2016-03-28 14 views
8

Chciałbym wyjaśnić z góry, szukam sposobu obliczenia odchylenia standardowego za pomocą strumieni (mam obecnie działającą metodę, która oblicza & zwraca SD, ale bez korzystania z strumieni).Strumienie Java - odchylenie standardowe

Zestaw danych, w którym pracuję, jest ściśle dopasowany do tego, co widać w artykule Link. Jak pokazano w tym linku jestem w stanie pogrupować moje dane, aby uzyskać średnią, ale nie jestem w stanie dowiedzieć się, jak uzyskać SD.

Kod

outPut.stream() 
      .collect(Collectors.groupingBy(e -> e.getCar(), 
        Collectors.averagingDouble(e -> (e.getHigh() - e.getLow())))) 
      .forEach((car,avgHLDifference) -> System.out.println(car+ "\t" + avgHLDifference)); 

Ja również sprawdzone Link na DoubleSummaryStatistics ale nie wydaje się, aby pomóc SD.

Odpowiedz

9

Do wykonania tego zadania można użyć niestandardowego kolektora, który oblicza sumę kwadratów. Kolekcjoner DoubleSummaryStatistics nie śledzi tego. Zostało to omówione przez grupę ekspertów in this thread, ale ostatecznie nie wdrożono. Trudność przy obliczaniu sumy kwadratów jest potencjalnym przepełnieniem przy podnoszeniu do kwadratu wyników pośrednich.

static class DoubleStatistics extends DoubleSummaryStatistics { 

    private double sumOfSquare = 0.0d; 
    private double sumOfSquareCompensation; // Low order bits of sum 
    private double simpleSumOfSquare; // Used to compute right sum for non-finite inputs 

    @Override 
    public void accept(double value) { 
     super.accept(value); 
     double squareValue = value * value; 
     simpleSumOfSquare += squareValue; 
     sumOfSquareWithCompensation(squareValue); 
    } 

    public DoubleStatistics combine(DoubleStatistics other) { 
     super.combine(other); 
     simpleSumOfSquare += other.simpleSumOfSquare; 
     sumOfSquareWithCompensation(other.sumOfSquare); 
     sumOfSquareWithCompensation(other.sumOfSquareCompensation); 
     return this; 
    } 

    private void sumOfSquareWithCompensation(double value) { 
     double tmp = value - sumOfSquareCompensation; 
     double velvel = sumOfSquare + tmp; // Little wolf of rounding error 
     sumOfSquareCompensation = (velvel - sumOfSquare) - tmp; 
     sumOfSquare = velvel; 
    } 

    public double getSumOfSquare() { 
     double tmp = sumOfSquare + sumOfSquareCompensation; 
     if (Double.isNaN(tmp) && Double.isInfinite(simpleSumOfSquare)) { 
      return simpleSumOfSquare; 
     } 
     return tmp; 
    } 

    public final double getStandardDeviation() { 
     return getCount() > 0 ? Math.sqrt((getSumOfSquare()/getCount()) - Math.pow(getAverage(), 2)) : 0.0d; 
    } 

} 

Następnie można użyć tej klasy z

Map<String, Double> standardDeviationMap = 
    list.stream() 
     .collect(Collectors.groupingBy(
      e -> e.getCar(), 
      Collectors.mapping(
       e -> e.getHigh() - e.getLow(), 
       Collector.of(
        DoubleStatistics::new, 
        DoubleStatistics::accept, 
        DoubleStatistics::combine, 
        d -> d.getStandardDeviation() 
       ) 
      ) 
     )); 

to będzie zbierać listę wejściowy na mapie gdzie wartości odpowiada odchyleniu standardowym high - low dla tego samego klucza.

+0

dziękuję bardzo. Jestem w stanie uzyskać SD. Teraz sprawdzam, czy mogę zebrać oba uśredniające podwójne i SD (np. - samochód, średniaHL, SD) w tym samym wywołaniu strumienia() zamiast 2 strumieni. – iCoder

+1

@iCoder "DoubleStatistics" w tej odpowiedzi zbiera SD i średnią tak. Możesz mieć 'Map ' z wszystkimi informacjami. – Tunaki

+2

Interesujący fakt dotyczący przepełnienia: nikt nie dba o to, że 'LongSummaryStatistics' faktycznie przepełnia sumę, więc' LongStream.of (Long.MAX_VALUE, Long.MAX_VALUE) .summaryStatistics(). GetAverage() 'to' -1.0'. Szanse na trafienie tego przelewu, według mnie są wyższe niż szanse trafienia przepełnienia sumy kwadratów ... –