合并Numpy结构化数组中的记录

时间:2015-08-14 10:49:46

标签: python arrays numpy

我有一个Numpy结构化数组,按第一列排序:

x = array([(2, 3), (2, 8), (4, 1)], dtype=[('recod', '<u8'), ('count', '<u4')])

我需要合并记录(总结第二列的值)

x[n][0] == x[n + 1][0]

在这种情况下,所需的输出为:

x = array([(2, 11), (4, 1)], dtype=[('recod', '<u8'), ('count', '<u4')])

实现这一目标的最佳途径是什么?

4 个答案:

答案 0 :(得分:3)

您可以使用np.unique为第一列中的每个元素获取ID数组,然后使用np.bincount根据ID在第二列元素上执行 accum积累 -

In [140]: A
Out[140]: 
array([[25,  1],
       [37,  3],
       [37,  2],
       [47,  1],
       [59,  2]])

In [141]: unqA,idx = np.unique(A[:,0],return_inverse=True)

In [142]: np.column_stack((unqA,np.bincount(idx,A[:,1])))
Out[142]: 
array([[ 25.,   1.],
       [ 37.,   5.],
       [ 47.,   1.],
       [ 59.,   2.]])

您可以通过np.diffnp.cumsum的组合避免使用np.unique,这可能会有所帮助,因为np.unique也会在内部进行排序,在这种情况下不需要作为输入数据已经排序。实现看起来像这样 -

In [201]: A
Out[201]: 
array([[25,  1],
       [37,  3],
       [37,  2],
       [47,  1],
       [59,  2]])

In [202]: unq1 = np.append(True,np.diff(A[:,0])!=0)

In [203]: np.column_stack((A[:,0][unq1],np.bincount(unq1.cumsum()-1,A[:,1])))
Out[203]: 
array([[ 25.,   1.],
       [ 37.,   5.],
       [ 47.,   1.],
       [ 59.,   2.]])

答案 1 :(得分:2)

pandas使这种类型的"group-by" operation变得微不足道:

In [285]: import pandas as pd

In [286]: x = [(25, 1), (37, 3), (37, 2), (47, 1), (59, 2)]

In [287]: df = pd.DataFrame(x)

In [288]: df
Out[288]: 
    0  1
0  25  1
1  37  3
2  37  2
3  47  1
4  59  2

In [289]: df.groupby(0).sum()
Out[289]: 
    1
0    
25  1
37  5
47  1
59  2

如果这是您需要的唯一操作,您可能不会想要对pandas的依赖,但是一旦开始,您可能会在库中找到其他有用的位。

答案 2 :(得分:2)

Dicakar's以结构化数组形式回答:

In [500]: x=np.array([(25, 1), (37, 3), (37, 2), (47, 1), (59, 2)], dtype=[('recod', '<u8'), ('count', '<u4')])

查找唯一值并计算重复项:

In [501]: unqA, idx=np.unique(x['recod'], return_inverse=True)    
In [502]: cnt = np.bincount(idx, x['count'])

制作一个新的结构化数组并填写字段:

In [503]: x1 = np.empty(unqA.shape, dtype=x.dtype)
In [504]: x1['recod'] = unqA
In [505]: x1['count'] = cnt

In [506]: x1
Out[506]: 
array([(25, 1), (37, 5), (47, 1), (59, 2)], 
      dtype=[('recod', '<u8'), ('count', '<u4')])

有一个recarray函数可以从数组列表中构建一个数组:

In [507]: np.rec.fromarrays([unqA,cnt],dtype=x.dtype)
Out[507]: 
rec.array([(25, 1), (37, 5), (47, 1), (59, 2)], 
      dtype=[('recod', '<u8'), ('count', '<u4')])

在内部它做同样的事情 - 构建一个正确大小和dtype的空数组,然后遍历dtype字段。重新排列只是专用数组子类包装器中的结构化数组。

有两种填充结构化数组的方法(特别是使用不同的dtype) - 使用x和逐字段的元组列表。

答案 3 :(得分:1)

您可以使用np.reduceat。您只需要填充x[:, 0]更改的位置,这些更改相当于将np.diff(x[:,0])的非零索引移位一加上初始索引0:

>>> i = np.r_[0, 1 + np.nonzero(np.diff(x[:,0]))[0]]
>>> a, b = x[i, 0], np.add.reduceat(x[:, 1], i)
>>> np.vstack((a, b)).T
array([[25,  1],
       [37,  5],
       [47,  1],
       [59,  2]])