2016-09-11 4 views
3

numpyでは、私はadxn配列Aと長さnのリストLを持っています。ここでは、Aの各列が行列Bになる場所を記述しています。考え方は、行列Bの列iはLの対応する値がiであるAの全列の和。私はループでこれを行うことができます。リストに従ってナンディ崩壊列

A = np.arange(15).reshape(3,5) 
L = [0,1,2,1,1] 
n_cols = 3 
B = np.zeros((len(A), n_cols)) 
# assume I know the desired number of columns, 
# which is also one more than the maximum value of L 
for i, a in enumerate(A.T): 
    B[:, L[i]] += a 

配列A(またはいくつかそうでないベクトル化の方法で)をスライスしてこれを行う方法はありますか?

+0

完全な例を投稿できると思いますか? (つまり、[mcve])このコードの小さな行列への影響やリストの例を見ることができれば助けになります。 – Praveen

+0

@Praveen私は例をもう少し書きました。 –

答えて

3

。また、L要素の一意性に基づいて出力配列の列を更新しています。行数がCOLSの数と同程度になると

In [129]: def org_app(A,n_cols): 
    ...:  B = np.zeros((len(A), n_cols)) 
    ...:  for i, a in enumerate(A.T): 
    ...:   B[:, L[i]] += a 
    ...:  return B 
    ...: 
    ...: def vectorized_app(A,n_cols): 
    ...:  sidx = L.argsort() 
    ...:  col_idx, grp_start_idx = np.unique(L[sidx],return_index=True) 
    ...:  B_out = np.zeros((len(A), n_cols)) 
    ...:  B_out[:,col_idx] = np.add.reduceat(A[:,sidx],grp_start_idx,axis=1) 
    ...:  return B_out 
    ...: 

In [130]: # Setup inputs with an appreciable no. of cols & lesser rows 
    ...: # so as that memory bandwidth to work with huge number of 
    ...: # row elems doesn't become the bottleneck 
    ...: d,n_cols = 10,5000 
    ...: A = np.random.rand(d,n_cols) 
    ...: L = np.random.randint(0,n_cols,(n_cols,)) 
    ...: 

In [131]: np.allclose(org_app(A,n_cols),vectorized_app(A,n_cols)) 
Out[131]: True 

In [132]: %timeit org_app(A,n_cols) 
10 loops, best of 3: 33.3 ms per loop 

In [133]: %timeit vectorized_app(A,n_cols) 
100 loops, best of 3: 1.87 ms per loop 

-

sidx = L.argsort() 
col_idx, grp_start_idx = np.unique(L[sidx],return_index=True) 
B_out = np.zeros((len(A), n_cols)) 
B_out[:,col_idx] = np.add.reduceat(A[:,sidx],grp_start_idx,axis=1) 

ランタイムテスト -

したがって、あなたはそうのようなベクトル化ソリューションのためのnp.add.reduceatを使用することができますAでは、ベクトル化手法のメモリ帯域幅要件が高いため、それに比べて目に見える高速化が相殺されます。

1

`` B`のこの繰り返しは同じです(テストされていません)?

for I in range(B.shape[1]): 
     B[:, I] = A[:, L==I].sum(axis=1) 

数字ループは少なくなります。しかしもっと重要なことは、他のベクトル化の洞察を与えるかもしれないということです。

(編集)テストでは、これは動作しますが、はるかに遅くなります。

+ ========

scipy.sparseものの行列と行列積と列合計を行います。ここで同じことをすることはできますか?右の列

def my2(A,L): 
    n_cols = L.shape[0] 
    C = np.zeros((n_cols,n_cols),int) 
    C[np.arange(n_cols), L] = 1 
    return A.dot(C) 

これは、より速く、あなたのループよりも7倍であり、わずかに速くより@Divakarsreduceatコードで1秒とC配列を作成します。あなたが和縮小/それらの列を選択するためのLを使用してAオフ列を崩壊さ

==========

In [126]: timeit vectorized_app(A,L) 
The slowest run took 8.16 times longer than the fastest. This could mean that an intermediate result is being cached. 
10000 loops, best of 3: 99.7 µs per loop 
In [127]: timeit val2 = my2(A,L) 
The slowest run took 10.46 times longer than the fastest. This could mean that an intermediate result is being cached. 
10000 loops, best of 3: 81.6 µs per loop 
In [128]: timeit org1(A,n_cols) 
1000 loops, best of 3: 623 µs per loop 
In [129]: d,n_cols 
Out[129]: (10, 100) 
関連する問題