有效计算大量/不精确数据量的统计数据的方法

时间:2013-08-20 18:18:52

标签: python performance statistics memory-efficient

我有超过6500万个数值存储在文本文件中。我需要计算最大值,最小值,平均值,标准差以及25%,50%和75%的百分位数。

通常我会使用附加代码,但我需要一种更有效的方法来计算这些指标,因为我无法将所有值p存储在列表中。如何在Python中更有效地计算这些值?

import numpy as np

np.average(obj)
np.min(mylist)
np.max(mylist)
np.std(mylist)
np.percentile(obj, 25)
np.percentile(obj, 50)
np.percentile(obj, 75)

maxx = float('-inf')
minx = float('+inf')
sumz = 0
for index, p in enumerate(open("foo.txt", "r")):
    maxx = max(maxx, float(p))
    minx = min(minx, float(p))
    sumz += float(p)
index += 1
my_max = maxx 
my_min = minx 
my_avg = sumz/index

5 个答案:

答案 0 :(得分:5)

使用二进制文件。然后,您可以使用numpy.memmap将其映射到内存,并可以执行各种算法,即使数据集大于RAM。

你甚至可以使用numpy.memmap创建一个内存映射数组,并从文本文件中读取你的数据...你可以使用它,当你完成后,你也有二进制格式的数据。

答案 1 :(得分:3)

我认为你是在正确的轨道上,通过迭代文件并跟踪最大值和最小值。要计算std,您应该在循环内保留一个平方和:sum_of_squares += z**2。然后,您可以在循环后计算std = sqrt(sum_of_squares / n - (sumz / n)**2),参见公式here(但此公式可能会遇到数值问题)。为了提高性能,您可能希望以适当大小的数据块迭代文件。

要以“连续”方式计算中位数和百分位数,您可以在循环内构建直方图。在循环之后,您可以通过将直方图转换为CDF来获得近似百分位数和中位数,错误将取决于容器的数量。

答案 2 :(得分:2)

正如Antti Haapala所说,最简单,最有效的方法是坚持使用numpy,只需使用memmap ped二进制文件而不是文本文件。是的,从一种格式转换到另一种格式需要一些时间 - 但它几乎肯定会节省更多时间而不是成本(因为你可以使用numpy矢量化操作而不是循环),它也会使你的代码变得很多简单。

如果你不能这样做,Python 3.4将附带一个statistics模块。在PEP最终确定后的某个时刻,希望可以提供2.6+的后退;目前我相信你只能获得它所基于的早期模块stats,这需要3.1+。不幸的是,虽然stats确实对迭代器执行了单程算法,但它没有任何方便的方法在同一个迭代器上并行运行多个算法,因此你对itertools.tee和{{{ 1}}强制它交错工作而不是将整个事物拉入记忆中。

当然,如果您search PyPI for "stats"和/或“统计”和/或“统计”,还有很多其他模块。

无论哪种方式,使用预先构建的模块意味着某人已经调试了您将要遇到的所有问题,并且他们可能还优化了代码(甚至可能将其移植到C)来启动。

答案 3 :(得分:1)

要获取百分位数,请使用命令行程序对文本文件进行排序。使用行数(程序中的index)查找百分位数的行号(index // 4等)。然后从文件中检索这些行。

答案 4 :(得分:1)

大多数这些操作都可以用简单的算术来表达。在这种情况下,使用awksed直接从Linux命令行处理简单统计数据实际上(令人惊讶地)非常有效。如在这篇文章中:< http://www.unixcl.com/2008/09/sum-of-and-group-by-using-awk.html>。

如果您需要推广到更高级的操作,例如加权百分位数,那么我建议使用Python Pandas(特别是HDFStore功能以便以后检索)。我之前使用Pandas的DataFrame超过2500万条记录(10列乘2500万条不同的行)。如果你有更多的内存限制,你可以读取数据块,计算每个块的部分贡献,并存储中间结果,然后通过加载中间结果完成计算,在序列化的map-reduce中一种框架。