Python:根据属于特定范围内的项目数从列表创建分发

时间:2010-08-23 17:55:48

标签: python distribution poisson

我用poisson标记了这个问题,因为我不确定在这种情况下它是否有用。

我需要从数据列表中创建一个分发(可能最终格式化为图像)。

例如:

data = [1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 10, 10, 10, 22, 30, 30, 35, 46, 58, 59, 59]

这样数据可用于创建视觉分布。例如,在这种情况下,我可能会说范围是10,并且每个范围中至少需要有3个项目才能成为有效点。

通过这个示例数据,我希望结果类似于

ditribution = [1, 2, 4, 6]

因为我有> 0-9,10-19,30-39和50-59范围内的3个项目。使用该结果,我可以生成一个图像,该图像具有在我的最终分布中存在的分割出的部分(较暗的颜色)。我尝试创建的图像类型的示例可以在下面看到,并且将生成具有更多数据的图像。暂时忽略蓝线。

我知道如何使用强力方法迭代列表中的每个项目并进行我的计算。但是,我的数据集可能有数十万甚至数百万的数字。在现实世界的例子中,我的范围(10)和我所需的项目数(3)可能会大得多。

distribution image

感谢您的帮助。

3 个答案:

答案 0 :(得分:4)

如果始终对data进行排序,则紧凑的方法可能是:

import itertools as it

d = [k+1 for k, L in
         ((k, len(list(g))) for k, g in it.groupby(data,key=lambda x:x//10))
     if L>=3]

如果data未排序,或者您不知道,请使用sorted(data)作为itertools.groupby的第一个参数,而不只是data

如果您喜欢不那么密集/紧凑的方法,您当然可以扩展它,例如到:

def divby10(x): return x//10

distribution = []
for k, g in it.groupby(data, key=divby10):
    L = len(list(g))
    if L < 3: continue
    distribution.append(k+1)

在任何一种情况下,机制都是groupby首先将作为key=传递的可调用数应用于作为其第一个参数传递的iterable中的每个项,以获得每个项的“键”;对于具有相同“键”的每个连续项目组,groupby产生一个包含两个项目的元组:键的值,以及所述组中所有项目的可迭代项。

这里,通过将项目除以10(截断)获得密钥; len(list(g))是具有该“密钥”的连续项目的数量。由于这些项目必须是连续的,因此您需要对数据进行排序(并且,对它进行排序更简单,而不是“按值除以10并对其进行排序”; - )。

答案 1 :(得分:2)

由于data可能非常冗长,您可能需要考虑使用numpy。它为数值工作提供了许多有用的函数,它需要更少的内存来存储{n}数组中的data而不是Python列表[*],并且,由于许多numpy函数在引擎盖下调用C函数,你可能是能够获得一些速度提升:

import numpy as np

data = np.array([1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 10, 10, 10, 22, 30, 30, 35, 46, 58, 59, 59])

hist,bins=np.histogram(data,bins=np.linspace(0,60,7))
print(hist)
# [11  3  1  3  1  3]

distribution=np.where(hist>=3)[0]+1
print(distribution)
# [1 2 4 6]

[*] - 注意:在上面的代码中,在定义data的过程中形成了一个Python列表。因此,这里的最大内存需求实际上大于您刚刚使用Python列表时的内存需求。但是,如果没有对Python列表的其他引用,则应释放内存。或者,如果数据存储在磁盘上,则可以使用numpy.loadtxt将其直接读取到numpy数组中。

答案 2 :(得分:0)

这听起来像某种形式的直方图。为了实现这一目标,不需要预先分类。我讨论了使用存储桶排序的变体来对附近的元素here进行分组,但您需要调整此算法以适合您的目的。请注意,您不需要将数字本身存储在存储桶中以形成直方图