所有唯一行对应的所有行的平均值

4

我有一个包含两列的numpy数组:

A = [[1,1,1,2,3,1,2,3],[0.1,0.2,0.2,0.1,0.3,0.2,0.2,0.1]]

针对第一列中的所有唯一值,我希望得到相应数值的平均值。例如:

B = [[1,2,3], [0.175, 0.15, 0.2]]

有没有一种Pythonic的方法来做这件事?


2
0.233 应该改为 0.175,因为 (0.1+0.2+0.2+0.2)/4 == 0.175 - halex
5个回答

4
我认为以下是这种计算的标准numpy方法。如果A [0]的条目是小整数,则可以跳过对np.unique的调用,但这使整个操作更加健壮且独立于实际数据。
>>> A = [[1,1,1,2,3,1,2,3],[0.1,0.2,0.2,0.1,0.3,0.2,0.2,0.1]]
>>> unq, unq_idx = np.unique(A[0], return_inverse=True)
>>> unq_sum = np.bincount(unq_idx, weights=A[1])
>>> unq_counts = np.bincount(unq_idx)
>>> unq_avg = unq_sum / unq_counts
>>> unq
array([1, 2, 3])
>>> unq_avg
array([ 0.175,  0.15 ,  0.2  ])

当然,您可以将两个数组堆叠在一起,但这会将unq转换为浮点dtype:

>>> np.vstack((unq, unq_avg))
array([[ 1.   ,  2.   ,  3.   ],
       [ 0.175,  0.15 ,  0.2  ]])

这只适用于numpy bincount中的权重为整数的情况?如果我提供非整数权重,它会抛出一个错误:TypeError:无法将数组安全地转换为所需类型。 - Abhishek Thakur
np.bincount 要求权重可转换为 np.double 类型。它不能处理复数。但整数和浮点数都应该可以使用。 - Jaime

1
一种可能的解决方案是:

In [37]: a=np.array([[1,1,1,2,3,1,2,3],[0.1,0.2,0.2,0.1,0.3,0.2,0.2,0.1]])
In [38]: np.array([list(set(a[0])), [np.average(np.compress(a[0]==i, a[1])) for i in set(a[0])]])
Out[38]:
array([[ 1.   ,  2.   ,  3.  ],
       [ 0.175,  0.15 ,  0.2 ]]) 

1
您可以通过使用np.histogram更有效地完成此操作,首先获取与A [1]中每个唯一索引对应的值的总和,然后获取每个唯一索引的出现总次数。

例如:

import numpy as np

A = np.array([[1,1,1,2,3,1,2,3],[0.1,0.2,0.2,0.1,0.3,0.2,0.2,0.1]])

# NB for n unique values in A[0] we want (n + 1) bin edges, such that
# A[0].max() < bin_edges[-1]
bin_edges = np.arange(A[0].min(), A[0].max()+2, dtype=np.int)

# the `weights` parameter means that the count for each bin is weighted
# by the corresponding value in A[1]
weighted_sums,_ = np.histogram(A[0], bins=bin_edges, weights=A[1])

# by calling `np.histogram` again without the `weights` parameter, we get
# the total number of occurrences of each unique index
index_counts,_ = np.histogram(A[0], bins=bin_edges)

# now just divide the weighted sums by the total occurrences
urow_avg = weighted_sums / index_counts

print urow_avg
# [ 0.175  0.15   0.2  ]

1

另一个高效的仅使用NumPy的解决方案,使用reduceat

A=np.array(zip(*[[1,1,1,2,3,1,2,3],[0.1,0.2,0.2,0.1,0.3,0.2,0.2,0.1]]),
        dtype=[('id','int64'),('value','float64')])
A.sort(order='id')
unique_ids,idxs = np.unique(A['id'],return_index=True)
avgs = np.add.reduceat(A['value'],idxs)
#divide by the number of samples to obtain the actual averages.
avgs[:-1]/=np.diff(idxs)
avgs[-1]/=A.size-idxs[-1]

0
您可以按照以下方式进行:
values = {}

# get all values for each index
for index, value in zip(*A):
    if index not in values:
        values[index] = []
    values[index].append(value)

# create average for each index
for index in values:
    values[index] = sum(values[index]) / float(len(values[index]))

B = np.array(zip(*values.items()))

对于你的例子,这给我带来了:
>>> B
array([[ 1.   ,  2.   ,  3.   ],
       [ 0.175,  0.15 ,  0.2  ]])

你可以稍微简化一下,使用 collections.defaultdict
from collections import defaultdict

values = defaultdict(list)

for index, value in zip(*A):
    values[index].append(value)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接