功能分配以numpy

问题描述

| 假设我有两个数组
A = [ 6,4,5,7,9 ]
ind = [ 0,2,1,2 ]
和一个功能f。 我想建立一个新数组B,其大小为ind中与B [i]中in的不同元素的数量,f的结果为参数i由i索引的A子数组。 对于此示例,如果我取f =和,则
B = [10,14]
或f =最大值
B = [6,9]
有没有比numpy中的for循环更有效的方法? 谢谢     

解决方法

对于
f =  sum
的特殊情况:
In [32]: np.bincount(ind,A)
Out[32]: array([ 10.,7.,14.])
假设:
f
是ufunc 您有足够的内存来制作2D 形状为
len(A) x len(A)
的数组 您可以制作2D数组
B
B=np.zeros((len(A),max(ind)+1))
并在
B
的各个位置填充
A
的值,以使
B
的第一列仅在
ind == 0
时获得ѭ10gets的值,而
B
的第二列仅在
ind == 1
时获得
A
的值,等等:
B[zip(*enumerate(ind))]=A
你最终会得到一个像
[[ 6.  0.  0.]
 [ 4.  0.  0.]
 [ 0.  0.  5.]
 [ 0.  7.  0.]
 [ 0.  0.  9.]]
然后,您可以沿轴= 0应用
f
,以获得所需的结果。 这里使用第三个假设:
B
中的多余零不影响    预期的结果。 如果您可以忍受这些假设,那么:
import numpy as np

A = np.array([ 6,4,5,7,9 ])
ind = np.array([ 0,2,1,2 ])

N=100
M=10
A2 = np.array([np.random.randint(M) for i in range(N)])
ind2 = np.array([np.random.randint(M) for i in range(N)])

def use_extra_axis(A,ind,f):
    B=np.zeros((len(A),max(ind)+1))
    B[zip(*enumerate(ind))]=A
    return f(B)

def use_loop(A,f):
    n=max(ind)+1
    B=np.empty(n)
    for i in range(n):
        B[i]=f(A[ind==i])
    return B

def fmax(arr):
    return np.max(arr,axis=0)

if __name__==\'__main__\':
    print(use_extra_axis(A,fmax))
    print(use_loop(A,fmax))
对于某些值
M
N
(例如M = 10,N = 100),使用额外的轴可能比使用循环更快:
% python -mtimeit -s\'import test,numpy\' \'test.use_extra_axis(test.A2,test.ind2,test.fmax)\'
10000 loops,best of 3: 162 usec per loop

% python -mtimeit -s\'import test,numpy\' \'test.use_loop(test.A2,test.fmax)\'
1000 loops,best of 3: 222 usec per loop
但是,随着N变大(例如M = 10,N = 10000),使用循环可能会更快:
% python -mtimeit -s\'import test,test.fmax)\'
100 loops,best of 3: 13.9 msec per loop
% python -mtimeit -s\'import test,best of 3: 4.4 msec per loop
结合thouis使用稀疏矩阵的出色思想:
def use_sparse_extra_axis(A,f):
    B=scipy.sparse.coo_matrix((A,(range(len(A)),ind))).toarray()
    return f(B)

def use_sparse(A,f):
    return [f(v) for v in scipy.sparse.coo_matrix((A,(ind,range(len(A))))).tolil().data]
哪种实现最佳取决于参数
N
M
N=1000,M=100
·───────────────────────·────────────────────·
│ use_sparse_extra_axis │ 1.15 msec per loop │
│        use_extra_axis │ 2.79 msec per loop │
│              use_loop │ 3.47 msec per loop │
│            use_sparse │ 5.25 msec per loop │
·───────────────────────·────────────────────·

N=100000,M=10
·───────────────────────·────────────────────·
│ use_sparse_extra_axis │ 35.6 msec per loop │
│              use_loop │ 43.3 msec per loop │
│            use_sparse │ 91.5 msec per loop │
│        use_extra_axis │  150 msec per loop │
·───────────────────────·────────────────────·

N=100000,M=50
·───────────────────────·────────────────────·
│            use_sparse │ 94.1 msec per loop │
│              use_loop │  107 msec per loop │
│ use_sparse_extra_axis │  170 msec per loop │
│        use_extra_axis │  272 msec per loop │
·───────────────────────·────────────────────·

N=10000,M=50
·───────────────────────·────────────────────·
│              use_loop │ 10.9 msec per loop │
│            use_sparse │ 11.7 msec per loop │
│ use_sparse_extra_axis │ 15.1 msec per loop │
│        use_extra_axis │ 25.4 msec per loop │
·───────────────────────·────────────────────·
    ,我认为您无法摆脱循环,但是也许使用scipy的稀疏矩阵会更有效。
[f(v) for v in scipy.sparse.coo_matrix((A,range(len(A))))).tolil().data]
    ,另一种可能性
from operator import itemgetter
from itertools import groupby

A = [ 6,9 ]
ind = [ 0,2 ]

z = zip(ind,A)
z.sort()

fst,snd = itemgetter(0),itemgetter(1)
g = groupby(z,fst)

f = sum
# or 
# f = max

for i in g:
    print i[0],f(snd(j) for j in i[1])
    ,至少对于添加而言,这有效
import numpy as np

def op_at(f,vals):
    base = np.zeros(np.max(ind)+1)
    f.at(base,vals)
    return base

print op_at(np.add,[ 0,2],[ 6,9])

> [ 10.   7.  14.]
不幸的是,它似乎无法正常工作。     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...