我正在尝试计算1000个组内的多个整数数据点。
假设我们在0..999999范围内有10,000个数据点:
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组中计算的数据点数?
“更好”可能意味着以下之一(请详细说明):
变式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中做得更好! : - )
答案 0 :(得分:3)
如果您正在尝试计算事物,那么最Pythonic的答案是Counter
,一种专门用于计算的dict
。
from collections import Counter
Counter(n // 1000 for n in numbers)
结果如下:
Counter({0: 87,
1: 113,
2: 117,
3: 99,
4: 114,
...
其中键是每个键中的数千个" band"或小组。因此,键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()
函数/生成器通常返回的半开放范围相比有点微不足道但却截然不同。