2016-03-28 49 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'。碰到这种溢出的机会,我认为高于碰撞总和溢出的几率... –