数据点计数/分组:forloop还是list?

2024-10-03 02:39:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我在计算1000个组中的整数数据点。你知道吗

假设有10000个数据点,范围为0..999999:

import random
random.seed(123456) # generate a reproducable sequence

# make 10000 numbers in range 0..99999
maxn = 99999
numbers = [random.randint(0,maxn) for i in range(10000)]

现在,哪种变体是生成一个列表的“更好”方法,该列表包含1000个组中已计数的数据点的数量?你知道吗

“更好”可以是指下列情况之一(请详细说明):

  • 更好的性能
  • 更像Python
  • 6个月后可读性更好

变体1:

# generate a zero-initialized "array" to hold the counts per 1000's block
blocks1 = [0 for i in range(maxn/1000 +1)] # init 1D "array"

for num in numbers:
    blocks1[num / 1000] += 1 # int divide by 1000 gives index

print blocks1[1] # show how many in range 1000..1999

变体2:

# Use a really wild list comprehension:
blocks2 = [len(filter(lambda num: num/1000 == i, numbers))
    for i in range(maxn/1000+1)]

print blocks2[1] # show how many in range 1000..1999

谢谢你帮我把Python做得更好!:-)


Tags: 数据in列表forshowrangerandom变体
1条回答
网友
1楼 · 发布于 2024-10-03 02:39:47

如果你想数数东西,最有吸引力的答案是Counter,一种专门用来数数的dict。你知道吗

from collections import Counter

Counter(n // 1000 for n in numbers)

结果如下:

Counter({0: 87,
         1: 113,
         2: 117,
         3: 99,
         4: 114,
         ...

其中键是每个“乐队”或组中的数千个数字。所以键0记录值0-999,1从1000-1999,依此类推。你知道吗

但你也可以做得更整洁。首先定义一个函数(在本例中为单行lambda函数),将值映射到带名称中。然后跨通用生成器表达式构造Counter

bandof = lambda x, b=1000: '{}-{}'.format(x//b*b, (x//b+1)*b-1)
Counter(bandof(n) for n in numbers)

结果是:

Counter({'0-999': 87,
         '1000-1999': 113,
         '10000-10999': 102,
         '11000-11999': 114,
         '12000-12999': 113,
         ...

键的顺序是不同的,键更具符号性,直接说明它们所代表的范围,而不是让您将索引转换为您头脑中的值范围。你知道吗

像这样概括的一个好处是,任何时候你想要改变波段大小,这都是微不足道的。例如,对于波段尺寸2000:

Counter(bandof(n, 2000) for n in numbers)

收益率:

Counter({'0-1999': 200,
         '10000-11999': 216,
         '12000-13999': 235,
         '14000-15999': 186,
         '16000-17999': 188,
         ...

选择100、250、500、1000、5000或任何你喜欢的乐队。也不局限于漂亮的整数。如果你想要一个391的乐队,那也行。你知道吗

最后一个窍门:虽然字符串键对于打印目的很有吸引力,但它们对于排序和其他类型的进一步处理可能不太方便。因此,使用tuple来代替将组名格式化为字符串通常是很方便的:

bandtuple = lambda x, b=1000: (x//b*b, (x//b+1)*b-1)

像以前一样调用这个分类程序函数。让我们狂野疯狂,用不寻常的乐队尺寸:

Counter(bandtuple(n, 3924) for n in numbers)

结果是:

Counter({(0, 3923): 411,
         (3924, 7847): 386,
         (7848, 11771): 403,
         (11772, 15695): 417,
         (15696, 19619): 396,
         ...

现在波段开始和停止值仍然很清楚,但它们也可以立即用作数据。你知道吗

:此处给出的波段开始和停止值为包含/闭合间隔。这对于很多用途来说都很有用,但与Python的range()函数/生成器通常返回的半开范围有着细微的差别。你知道吗

相关问题 更多 >