AssertionError:平方偏差的负和

时间:2016-08-03 13:10:28

标签: python python-3.x dictionary statistics standard-deviation

作为一个更大的项目的一部分,我正在编写一个函数,它接受一个intt的字典,并返回一个字典,每个"外部"密钥链接到该子字典的平均值和标准偏差的元组(即(mean(dict[key1]), stdev(dict[key1])))。我正在操作一个大型数据集(源文件是一个2.8 GB的csv文件),并在计算其中一个子字节的标准偏差时得到一个断言错误。

虽然我(并且目前正在)追踪导致下面错误的子字典,但我很好奇一般情况可能导致它如此,所以如果它进一步发生在我的数据集中,我可以尝试避免它。

我收到的错误消息是:

AssertionError: negative sum of square deviations: -3734262324235.697754

来自代码:

import statistics as stat

try: #Check for single value error
    std = stat.stdev(val)
except stat.StatisticsError:
    std = 0

3 个答案:

答案 0 :(得分:2)

statiscs.py中的代码是纯Python - 在处理内部" quares之和statistics._ss函数时,您似乎是Fraction类中奇怪的溢出错误的受害者。

我认为你现在可以做的最好的事情就是使用" if"来构建_ss文件本身中的statistics.py函数。并调用pdb.set_trace以交互方式查找导致错误的数据(代码中有一条注释,表明此部分存在舍入错误)。它计算一个shuld为零的分数 - 但是对于舍入误差,以及该分数的平方。但是在平方时,已经很大的分母本身就是平方 - 这可能会引发Python的Fraction中的一个错误,并且当它应该接近于零时返回一个非常大的值。

这样的"如果"子句可以允许您(1)绕过错误条件并将代码运行到最后,在找到错误时强制该值为零; (2)记下导致错误的值,并将其报告为Python语言本身的错误。

答案 1 :(得分:0)

这是@jsbueno提到的statistics.py文件问题。我也遇到了同样的错误,并通过将statistics.stdev替换为numpy.std而不是对源代码进行更改来解决了该问题。

答案 2 :(得分:0)

我遇到了一个很小的问题。 sum(x²)的精确计算得出的结果为零(Fraction(0,1)),而sum(x)的精确计算给出了一个很小的正分数,表示取整误差和精度的损失。从数据中得出平均值。

statistics.py中的代码指示total2应该为零,但实际上可以是任何小数,正数或负数。 total2的平方始终是一个小的正分数。

def _ss(data, c=None):
    """Return sum of square deviations of sequence data.

    If ``c`` is None, the mean is calculated in one pass, and the deviations
    from the mean are calculated in a second pass. Otherwise, deviations are
    calculated from ``c`` as given. Use the second case with care, as it can
    lead to garbage results.
    """
    if c is None:
        c = mean(data)
    T, total, count = _sum((x-c)**2 for x in data)
    # The following sum should mathematically equal zero, but due to rounding
    # error may not.
    U, total2, count2 = _sum((x-c) for x in data)
    assert T == U and count == count2
    total -=  total2**2/len(data)
    assert not total < 0, 'negative sum of square deviations: %f' % total
    return (T, total)

因此,恰恰在失败的断言之前,总方差可以变成负值。

根本原因是在第一个_sum函数调用中将每个值取平方时会发生精度损失。 float或np.float64值通过浮点运算在列表推导中平方。

一种可能的更正方法是在平方之前将total2转换为类型T。它更改了语义,因为_ss返回类型T的值而不是精确的分数。另一种更准确的方法是,在首次调用_sum之前,将x-c一次全部转换为小数。在这两种情况下,计算都将更快。

最合适的校正并非微不足道,因为_sum还会汇总来自对_coerce的连续调用的类型。较早地将数据转换为分数也将结果的类型更改为分数。