【问题标题】:Efficient way of computing statistics for large/imprecise amount of data为大量/不精确的数据计算统计数据的有效方法
【发布时间】:2013-08-20 18:18:52
【问题描述】:

我在一个文本文件中存储了超过 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

【问题讨论】:

  • 但是问题是什么?
  • 我认为不使用内存很难计算百分位数...
  • “6500000 百万点” - 不太可能。您没有多 TB 的数据文件。
  • “数值”的范围和精度是多少?
  • 传感器必须有最大有效位数。如果是这样,您可以将它们规范化为整数并使用像 collections.Counter 这样的东西,它可能比 65M 浮点数列表更有效。精度超过 5 或 6 位有效数字的传感器很少见。

标签: python performance statistics memory-efficient


【解决方案1】:

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

您甚至可以使用 numpy.memmap 创建一个内存映射数组,并从文本文件中读取您的数据...您可以对其进行处理,完成后,您还可以获得二进制格式的数据。

【讨论】:

  • 感谢 Antii。我以文本文件的形式从传感器接收文件,但无法修改文件类型。
  • @Gianni:您可以将其从一种格式转换为另一种格式,然后将其处理为 memmap 的二进制文件。
【解决方案2】:

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

要以“连续”方式计算中位数和百分位数,您可以在循环内构建直方图。循环结束后,可以通过将直方图转换为CDF得到近似的百分位数和中位数,误差取决于分箱数。

【讨论】:

    【解决方案3】:

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

    如果你不能这样做,Python 3.4 将附带一个statistics 模块。在 PEP 最终确定后,有望在某个时候提供到 2.6+ 的反向移植;目前我相信你只能得到stats,它基于的较早的模块,需要3.1+。不幸的是,虽然stats 确实在迭代器上执行单通道算法,但它没有任何方便的方法在同一个迭代器上并行运行多个算法,所以你必须巧妙地使用itertools.teezip 来强制它交错工作,而不是将整个事情拖入记忆中。

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

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 但是,如果您以后想推广到加权百分位数怎么办?
      • 对文本文件进行排序,您需要将其保存在内存中,或者对临时文件使用多通道合并排序;二进制文件可以从磁盘“有效”地排序。
      • GNU/Linux 有sort 命令:gnu.org/software/coreutils/manual/html_node/… 它在对大型文本文件进行排序时非常有效,并带有许多选项(选择列、字母/数字、日期、不区分大小写和还有更多)。
      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-19
        • 2023-04-06
        • 2011-09-27
        • 2017-03-26
        • 1970-01-01
        • 1970-01-01
        • 2012-08-02
        • 1970-01-01
        相关资源
        最近更新 更多