Python/NumPy 中计算均值的元素排列
Posted
技术标签:
【中文标题】Python/NumPy 中计算均值的元素排列【英文标题】:Elements Arrangement For Calculating Mean In Python/NumPy 【发布时间】:2015-10-08 06:12:57 【问题描述】:我有如下的一维列表:
data = [1,5,9,13,
2,6,10,14,
3,7,11,15,
4,8,12,16]
我想制作以下元组列表,并分别计算每个元组的平均值。
[(1,5,2,6), (3,7,4,8), (9,13,10,14), (11,15,12,16)]
预期的结果应该是:
[3.5, 5.5, 11.5, 13.5]
有什么更简单的方法?
【问题讨论】:
到目前为止你有没有尝试过?可能是搜索或任何代码? 【参考方案1】:这是一种方法
In [29]: a = np.array(data)
In [30]: a2 = a.reshape(4,4)
In [31]: a3 = np.vstack((a2[:, :2], a2[:, 2:]))
In [32]: a4 = a3.reshape(4,4)
In [33]: np.mean(a4, axis=1)
Out[33]: array([ 3.5, 5.5, 11.5, 13.5])
【讨论】:
【参考方案2】:将数据放入一个形状为 (2, 2, 2, 2) 的 4-d numpy 数组,然后在轴 1 和轴 3 上取该数组的平均值:
In [25]: data
Out[25]: [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]
In [26]: a = np.array(data).reshape(2, 2, 2, 2)
In [27]: a
Out[27]:
array([[[[ 1, 5],
[ 9, 13]],
[[ 2, 6],
[10, 14]]],
[[[ 3, 7],
[11, 15]],
[[ 4, 8],
[12, 16]]]])
In [28]: a.mean(axis=(1, 3))
Out[28]:
array([[ 3.5, 11.5],
[ 5.5, 13.5]])
如果您需要将最终结果作为一维数组,您可以使用ravel()
方法:
In [31]: a.mean(axis=(1, 3)).ravel()
Out[31]: array([ 3.5, 11.5, 5.5, 13.5])
请参阅How can I vectorize the averaging of 2x2 sub-arrays of numpy array? 了解类似问题。
【讨论】:
第一次看到axis=(1, 3),是什么意思? 如果我有一个大数组(比如 n = 2000)并且需要以类似的方式计算平均值怎么办? @Borys 我想应该是a = np.array(data).reshape(-1, N1, M2/N2, N2)
,其中M2
= 输入数据中的列或步长(如果您想这样称呼一维输入列表)和N1, N2
= 数据被划分和平均的块大小。【参考方案3】:
本文列出了一些解决方案建议-
def grouped_mean(data,M2,N1,N2):
# Paramters:
# M2 = Columns in input data
# N1, N2 = Blocksize into which data is to be divided and averaged
# Get grouped mean values; transpose and flatten for final output
grouped_mean = np.array(data).reshape(-1,N2).sum(1).reshape(-1,N1,M2/N2).sum(1)/(N1*N2)
# Return transposed and flattened version as output (as per OP)
return grouped_mean.T.ravel()
现在,grouped_mean
可以用np.einsum
来计算,而不是像这样使用np.sum
-
stage1_sum = np.einsum('ij->i',np.array(data).reshape(-1,N2))
grouped_mean = np.einsum('ijk->ik',stage1_sum.reshape(-1,N1,M2/N2))/(N1*N2)
或者,可以按照@Warren Weckesser's solution
中的建议将 2D 输入数组拆分为 4D 数组,然后像这样使用np.einsum
-
split_data = np.array(data).reshape(-1, N1, M2/N2, N2)
grouped_mean = np.einsum('ijkl->ik',split_data)/(N1*N2)
示例运行 -
In [182]: data = np.array([[1,5,9,13],
...: [2,6,10,14],
...: [3,7,11,15],
...: [4,8,12,16]])
In [183]: grouped_mean(data,4,2,2)
Out[183]: array([ 3.5, 5.5, 11.5, 13.5])
运行时测试
计算grouped_mean
似乎是代码中计算量最大的部分。所以,这里有一些运行时测试来用这三种方法计算它 -
In [174]: import numpy as np
...: # Setup parameters and input list
...: M2 = 4000
...: N1 = 2
...: N2 = 2
...: data = np.random.randint(0,9,(16000000)).tolist()
...:
In [175]: %timeit np.array(data).reshape(-1,N2).sum(1).reshape(-1,N1,M2/N2).sum(1)/(N1*N2)
...: %timeit np.einsum('ijk->ik',np.einsum('ij->i',np.array(data).reshape(-1,N2)).reshape(-1,N1,M2/N2))/(N1*N2)
...: %timeit np.einsum('ijkl->ik',np.array(data).reshape(-1, N1, M2/N2, N2))/(N1*N2)
...:
1 loops, best of 3: 2.2 s per loop
1 loops, best of 3: 2.12 s per loop
1 loops, best of 3: 2.1 s per loop
【讨论】:
以上是关于Python/NumPy 中计算均值的元素排列的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 python + NumPy / SciPy 计算滚动/移动平均值?