合并两个numpy数组的和,一个作为键,另一个作为值 基准化

问题描述

有什么功能可以对numpy数组进行分组求和?

可能与tutorial重复

x = np.array([[1.2,10],[2.3,20],[1.2,30],7]
            ])

想要的输出

x = np.array([[1.2,40],27]            
            ])

更新:

实际上,我数据的第一列总是四舍五入到两位小数。因此x可以写成:

x = np.array([[120,[230,[120,7]
            ])

解决方法

我不会说这是重复的,但是您提到的相关问题是一个很好的起点。链接的大多数答案都需要对数组进行排序,从组开始的位置提取索引,然后在其上调用np.split。这里不是这种情况,因为它将返回大小不平衡的组的列表。

您可以使用np.bincount方法。它计算每个加权值的出现次数,它实际上与groupby sum相同,只是输出中没有group key。

def group_by_sum(x):
    u,idx = np.unique(x[:,0],return_inverse=True)
    s = np.bincount(idx,weights = x[:,1])
    return np.c_[u,s]

奖金。 实际上,它是numpy_indexed软件包中的一个衬套:

np.transpose(npi.group_by(x[:,0]).sum(x[:,1]))

基准化

import numpy as np
import perfplot
import matplotlib.pyplot as plt

def bincount(x):
    u,s]

def reduceat(x):
    x = x[np.argsort(x[:,0])]
    i = np.flatnonzero(np.diff(x[:,0]))
    i = np.r_[0,i + 1]
    s = np.add.reduceat(x[:,1],i)
    return np.stack((x[i,s),axis=-1)

def setup(N,s):
    x = np.linspace(0,1,N+1)[np.random.randint(N,size = s)]
    return np.c_[x,(x**2)%1]

def build_args(k):
    return {'setup': lambda x: setup(k,x),'kernels': [bincount,reduceat],'n_range': [2**k for k in range(1,20)],'title': f'Testing for x samples in [0,1] with no more than {k} groups','show_progress': True,'equality_check': False}

outs = [perfplot.bench(**build_args(n)) for n in (10,100,1000,10000)]
fig = plt.figure(figsize=(20,20))
for i in range(len(outs)):
    ax = fig.add_subplot(2,2,i + 1)
    ax.grid(True,which="both")
    outs[i].plot()
plt.show()

enter image description here

,

这是一种使用唯一值对每个元素进行重复计数并将其乘以其值以计算分组总和的解决方案(您可以通过实现O(n)的哈希图来实现此目的,该哈希图仅计算重复和唯一值):

编辑,因为原始问题已编辑:

keys2,idx,count = np.unique(x[:,return_counts=True,return_index=True)
values2 = x[:,1][idx]*count

另一种方法是使用pandas groupby:

df = pd.DataFrame({'keys':x[:,'values':x[:,1]})
df2 = df.groupby(keys)['values'].agg('sum')
keys2,values2 = df2.index.to_numpy(),df2.values

输出:

[1.2 2.3] 
[20 30]
,

Numpy提供了无需显式循环即可执行此操作的工具。

首先对行进行排序:

a = a[np.argsort(a[:,0])]

然后找到值更改的索引:

i = np.flatnonzero(np.diff(a[:,0]))
i = np.r_[0,i + 1]

然后添加元素:

s = np.add.reduceat(a[:,i)

索引只是每次运行中a的第一个元素,因此结果为

result = np.stack((a[i,axis=-1)
,

这是一种方法

d = {}
for k,v in x:
    d[k] = d.get(k,0) + v

x = np.array(list(d.items()))

请记住,这是在测试浮点数是否相等...您可能不应该这样做