2016-03-28 71 views
8

我想先澄清我正在尋找一種方法來計算標準偏差使用流(我有一個工作方法,目前計算&返回SD但不使用流)。Java Streams - Standard Deviation

我正在使用的數據集緊密匹配,如Link所示。如此鏈接所示,我可以將我的數據分組&獲得平均值,但無法弄清楚如何獲得標清。

代碼

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

我還檢查Link上DoubleSummaryStatistics但它似乎並沒有幫助的SD。

回答

9

您可以使用自定義收集器執行此任務,計算平方和。插座DoubleSummaryStatistics收集器不會跟蹤它。專家組in this thread對此進行了討論,但最終沒有實施。計算平方和時的困難是平方中間結果時可能發生的溢出。

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

} 

然後,你可以使用這個類

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

這將收集輸入列表進入地圖,數值相當於high - low對於同一個密鑰的標準偏差。

+0

非常感謝。我能夠獲得SD。我正在檢查是否可以在同一個stream()調用中,而不是2個流中同時收集平均Double&SD(如 - car,averageHL,SD)。 – iCoder

+1

@iCoder這個答案中的'DoubleStatistics'收集SD和平均值yes。你可以有一個包含所有信息的Map 。 – Tunaki

+2

有關溢出的有趣事實:沒有人在意LongSummaryStatistics實際上溢出了總和,所以LongStream.of(Long.MAX_VALUE,Long.MAX_VALUE).summaryStatistics()。getAverage()是'-1.0'。碰到這種溢出的機會,我認爲高於碰撞總和溢出的機率... –