2016-03-28 26 views
8

Desidero chiarire in anticipo Sto cercando un modo per calcolare la deviazione standard utilizzando gli stream (attualmente ho un metodo di lavoro che calcola lo & restituisce SD ma senza utilizzare gli stream).Java Stream - Deviazione standard

Il set di dati sto lavorando con le corrispondenze da vicino come visto in Link. Come mostrato in questo link sono in grado di raggruppare i miei dati & ottenere la media, ma non in grado di capire come ottenere la SD.

Codice

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

Ho anche controllato Link su DoubleSummaryStatistics ma non sembra aiutare per SD.

risposta

9

È possibile utilizzare un raccoglitore personalizzato per questa attività che calcola una somma di quadrato. Il collezionista buis-in DoubleSummaryStatistics non ne tiene traccia. Questo è stato discusso dal gruppo di esperti in this thread ma alla fine non è stato implementato. La difficoltà nel calcolare la somma dei quadrati è il potenziale trabocco quando si quadrano i risultati intermedi.

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; 
    } 

} 

Quindi, è possibile utilizzare questa classe con

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() 
       ) 
      ) 
     )); 

Questo raccoglierà la lista di ingresso in una mappa in cui i valori corrisponde alla deviazione standard del high - low per la stessa chiave.

+0

grazie mille. Sono in grado di ottenere la SD. Ora sto controllando per vedere se riesco a raccogliere sia media Double e SD (come - car, averageHL, SD) nella stessa chiamata stream() invece di 2 flussi. – iCoder

+1

@iCoder Il 'DoubleStatistics' in questa risposta raccoglie SD e il sì medio. Potresti avere un 'Map ' con tutte le informazioni. – Tunaki

+2

Il fatto interessante riguardante l'overflow: a nessuno importa che "LongSummaryStatistics' superi effettivamente la somma, quindi' LongStream.of (Long.MAX_VALUE, Long.MAX_VALUE) .summaryStatistics(). GetAverage() 'è' -1.0'. Le probabilità di colpire questo overflow, secondo me sono più alte delle possibilità di colpire l'overflow della somma dei quadrati ... –