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】:

将数据放入一个形状为 (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 = 数据被划分和平均的块大小。【参考方案2】:

这是一种方法

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])

【讨论】:

【参考方案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 计算滚动/移动平均值?

Python NumPy 学习记录冒泡排序和List中sort方法计算时间对比

Python | Numpy:详解计算矩阵的均值和标准差

Python | Numpy:详解计算矩阵的均值和标准差

如何计算无符号字符数组中元素的平均值?

如何计算数组中元素的总和和平均值?