我的任务是计算第 1 和 2 个元素、第 3 和 4 个元素、第 5 和 6 个元素等的平均值。在 Python 中有什么简单的方法可以做到这一点?[2.34, 3.45, 4.56, 1.23, 2.34, 7.89, ...]
我的任务是计算第 1 和 2 个元素、第 3 和 4 个元素、第 5 和 6 个元素等的平均值。在 Python 中有什么简单的方法可以做到这一点?[2.34, 3.45, 4.56, 1.23, 2.34, 7.89, ...]
data = [2.34, 3.45, 4.56, 1.23, 2.34, 7.89]
print [(a + b) / 2 for a, b in zip(data[::2], data[1::2])]
解释:
data[::2]
是元素 2.34, 4.56, 2.34
data[1::2]
是元素 3.45, 1.23, 7.89
zip
将它们组合成二元组: (2.34, 3.45), (4.56, 1.23), (2.34, 7.89)
zip
和列表推导式!使计算变得简洁高效。 - Joëlrange
、for循环等等。... - TheEagle[(a + b) / 2 for a, b in zip(data[:-1], data[1::])]
让我困惑的是一个需要3个地址,而另一个只需要2个地址。元组的第一个表示除了最后一个元素以外的整个列表,而第二个元组则要求从第二个元素开始的列表中的每个成员。 - brosenheim如果列表长度不太长,Paul Draper的回答非常简单。如果它真的很长,您可能需要考虑另外两个选项之一。
首先,使用迭代器,您可以避免复制大型临时列表:
avgs = [(a + b) / 2 for a, b in zip(*[iter(data)]*2)]
这实际上是相同的操作,但是惰性地执行,这意味着它只需要在内存中存储一个值(好吧,三个值——a、b和平均值),而不是所有值。
iter(data)
创建一个对数据进行惰性迭代的迭代器。[iter(data)]*2
创建一个包含两个指向同一迭代器的引用的列表,因此当一个迭代器推进时,另一个也会被推进。zip
和列表解析。 (在Python 2.x中,与3.x不同,zip
不是惰性的,因此您要使用itertools.izip
而不是zip
。)如果您实际上不需要结果列表,而只需要可以迭代的东西,请将外部方括号更改为括号,它就会变成生成器表达式,这意味着它给您一个迭代器而不是列表,您根本没有存储任何内容。
请注意,itertools
文档提供了一个名为grouper
的技巧(您还可以在第三方模块more-itertools
中找到它),因此您可以只需编写grouper(data,2)
而不是zip(*[iter(data)]*2)
,如果经常这样做,这显然更容易阅读。 如果需要更多解释,请参见How grouper works。
或者,您可以使用NumPy数组代替列表:
data_array = np.array(data)
然后你只需要这样做:
avg_array = (data_array[::2] + data_array[1::2]) / 2
这不仅更简单(无需显式循环),而且速度大约快10倍,使用的内存量也只有原来的四分之一。
如果你想将此推广至任意长度的组……
对于迭代器解决方案,这很简单:
[sum(group) / size for group in zip(*[iter(data)]*size)]
对于NumPy解决方案,要稍微复杂一些。您需要动态创建一个迭代器以遍历data[::size]
、data[1::size]
、…、data[size-1::size]
,就像这样:
sum(data[x::size] for x in range(size)) / size
NumPy还有其他方法可以实现这个,但只要size
不太大,这种方法就可以了,并且它的优点是完全相同的技巧也适用于Paul Draper的解决方案:
[sum(group) / size for group in zip(*(data[x::size] for x in range(size)))]
avgs = [sum(vals, 0.0) / size for vals in zip(*[iter(data)]*size)]
或类似的方式。 - Jon Clementssum
而不是+
)……除非我认为你的评论已经说了所有必要的内容。 - abarnertnp.array([1, 2, 3, 4, 5, 6]).reshape(3, 2).mean(axis=1)
? - Jon Clementss= [2.34, 3.45, 4.56, 1.23, 2.34, 7.89, ...]
res= [(s[i]+s[i+1])/2 for i in range(0, len(s)-1, 2)]
data=np.array([1,2,3,4,5,6])
k=2 #In your case
data1=np.mean(data.reshape(-1, k), axis=1)
只需使用索引来完成任务。
举个简单的例子,
avg = []
list1 = [2.34, 3.45, 4.56, 1.23, 2.34, 7.89]
for i in range(len(list1)):
if(i+1 < len(list1):
avg.append( (list1[i] + list1[i+1]) / 2.0 )
avg2 = []
avg2 = [j for j in avg[::2]]
你需要的是avg2。这可能很容易理解。
zip
是惰性的,但你的代码显然是Python 2,因为它使用print
作为语句。同时,你是对的,你不会创建2N个新浮点数,但你仍然会创建3N个列表插槽(在CPython术语中,只有2个额外的PyFloatObject
,但是有3*N个额外的指针)。无论如何,你可以通过使用itertools.islice
而不是列表切片来解决这个问题,但我认为在那时你最好还是首先按迭代器分组(就像我的答案一样)。 - abarnert