添加像计数器这样的Numpy数组

时间:2017-07-10 20:33:51

标签: python arrays numpy multidimensional-array counter

由于collections.Counter非常慢,我在Python 2.7中寻求一种更快的求和映射值的方法。这似乎是一个简单的概念,我对内置的Counter方法感到很失望。

基本上,我需要能够采用这样的数组:

array([[ 0.,  2.],
       [ 2.,  2.],
       [ 3.,  1.]])

array([[ 0.,  3.],
       [ 1.,  1.],
       [ 2.,  5.]])

然后“添加”它们,使它们看起来像这样:

array([[ 0.,  5.],
       [ 1.,  1.],
       [ 2.,  7.],
       [ 3.,  1.]])

如果没有一个好的方法可以快速有效地做到这一点,我会接受任何其他的想法,这些想法将允许我做类似的事情,而且我对Numpy以外的模块持开放态度。

谢谢!

编辑:准备进行一些速度测试? 英特尔赢得64位机器。以下所有值均以秒为单位; 20000循环。

  

collections.Counter结果:   2.131000,2.125000,2.125000

     

Divakar的union1d +掩蔽结果:   1.641000,1.633000,1.625000

     

Divakar的union1d +索引结果:   0.625000,0.625000,0.641000

     

直方图结果:   1.844000,1.938000,1.858000

     

熊猫结果:   16.659000,16.686000,16.885000

结论:union1d +索引获胜,数组大小太小,Pandas无法生效,而直方图方法让我的思维简单,但我猜它需要花费太多的开销来创建。不过,我收到的所有回复都非常好。 This is what I used to get the numbers.再次感谢!

编辑:应该提到的是,尽管做同样的事情(65.671000秒),使用Counter1.update(Counter2.elements())仍然很糟糕。

后来编辑:我一直在考虑这个问题,而且我已经意识到,使用Numpy,用零填充每个数组可能会更有效因为我们可以只使用索引,所以甚至不需要列,这也使得将多个数组添加到一起以及执行其他功能变得更加容易。另外,Pandas比Numpy更有意义,因为不需要0填充,并且对于大型数据集肯定会更有效(但是,Numpy具有在更多平台上兼容的优势,如GAE,如果重要的话在所有)。最后,我检查的答案肯定是我问的确切问题的最佳答案 - 以我展示的方式添加两个数组 - 但我认为我需要的是透视变化。

5 个答案:

答案 0 :(得分:2)

以下是np.union1dmasking -

的一种方法
def app1(a,b):
    c0 = np.union1d(a[:,0],b[:,0])

    out = np.zeros((len(c0),2))
    out[:,0] = c0

    mask1 = np.in1d(c0,a[:,0])
    out[mask1,1] = a[:,1]

    mask2 = np.in1d(c0,b[:,0])
    out[mask2,1] += b[:,1]
    return out

示例运行 -

In [174]: a
Out[174]: 
array([[  0.,   2.],
       [ 12.,   2.],
       [ 23.,   1.]])

In [175]: b
Out[175]: 
array([[  0.,   3.],
       [  1.,   1.],
       [ 12.,   5.]])

In [176]: app1(a,b)
Out[176]: 
array([[  0.,   5.],
       [  1.,   1.],
       [ 12.,   7.],
       [ 23.,   1.]])

这是另一个np.union1dindexing -

def app2(a,b):
    n = np.maximum(a[:,0].max(), b[:,0].max())+1
    c0 = np.union1d(a[:,0],b[:,0])
    out0 = np.zeros((int(n), 2))
    out0[a[:,0].astype(int),1] = a[:,1]

    out0[b[:,0].astype(int),1] += b[:,1]

    out = out0[c0.astype(int)]
    out[:,0] = c0
    return out

对于ab中的第一列值涵盖所有索引的情况 -

def app2_specific(a,b):
    c0 = np.union1d(a[:,0],b[:,0])
    n = c0[-1]+1
    out0 = np.zeros((int(n), 2))
    out0[a[:,0].astype(int),1] = a[:,1]        
    out0[b[:,0].astype(int),1] += b[:,1]
    out0[:,0] = c0
    return out0

示例运行 -

In [234]: a
Out[234]: 
array([[ 0.,  2.],
       [ 2.,  2.],
       [ 3.,  1.]])

In [235]: b
Out[235]: 
array([[ 0.,  3.],
       [ 1.,  1.],
       [ 2.,  5.]])

In [236]: app2_specific(a,b)
Out[236]: 
array([[ 0.,  5.],
       [ 1.,  1.],
       [ 2.,  7.],
       [ 3.,  1.]])

答案 1 :(得分:1)

如果您知道字段数,请使用np.bincount

c = np.vstack([a, b])
counts = np.bincount(c[:, 0], weights = c[:, 1], minlength = numFields)
out = np.vstack([np.arange(numFields), counts]).T

如果您一次获取所有数据,则此功能正常。列出您的数组并vstack。如果您按顺序获取数据块,则可以使用np.add.at执行相同的操作。

out = np.zeros(2, numFields)
out[:, 0] = np.arange(numFields)
np.add.at(out[:, 1], a[:, 0], a[:, 1])
np.add.at(out[:, 1], b[:, 0], b[:, 1])

答案 2 :(得分:1)

您可以使用基本直方图this will deal with gaps, too。如果需要,您可以过滤掉零计数条目。

import numpy as np

x = np.array([[ 0.,  2.],
              [ 2.,  2.],
              [ 3.,  1.]])

y = np.array([[ 0.,  3.],
              [ 1.,  1.],
              [ 2.,  5.],
              [ 5.,  3.]])

c, w = np.vstack((x,y)).T
h, b = np.histogram(c, weights=w, 
                    bins=np.arange(c.min(),c.max()+2))
r = np.vstack((b[:-1], h)).T
print(r)
# [[ 0.  5.]
#  [ 1.  1.]
#  [ 2.  7.]
#  [ 3.  1.]
#  [ 4.  0.]
#  [ 5.  3.]]
r_nonzero = r[r[:,1]!=0]

答案 3 :(得分:0)

Pandas有一些功能完全符合您的意图

import pandas as pd
pda = pd.DataFrame(a).set_index(0)
pdb = pd.DataFrame(b).set_index(0)
result = pd.concat([pda, pdb], axis=1).fillna(0).sum(axis=1)

编辑:如果您确实需要以numpy格式返回数据,只需执行

array_res = result.reset_index(name=1).values

答案 4 :(得分:0)

这是一个典型的分组问题,numpy_indexed(免责声明:我是它的作者)是为了优雅而有效地解决而创建的:

import numpy_indexed as npi
C = np.concatenate([A, B], axis=0)
labels, sums = npi.group_by(C[:, 0]).sum(C[:, 1])

注意:将标签数组维护为单独的int数组更清晰;浮标在标记事物时是挑剔的,正面和负面的零点,以及打印值不会传递所有二元状态。最好使用整数。