由于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,如果重要的话在所有)。最后,我检查的答案肯定是我问的确切问题的最佳答案 - 以我展示的方式添加两个数组 - 但我认为我需要的是透视变化。
答案 0 :(得分:2)
以下是np.union1d
和masking
-
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.union1d
和indexing
-
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
对于a
和b
中的第一列值涵盖所有索引的情况 -
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数组更清晰;浮标在标记事物时是挑剔的,正面和负面的零点,以及打印值不会传递所有二元状态。最好使用整数。