2017-11-08 2 views
2

の間の重複を避ける:辞書に基づいてnumpyの配列の値を交換し、私はPythonで辞書を以下に基づいて、2D numpyの配列内の値を置換する新しい値とキー

code region 
334  0 
4  22 
8  31 
12  16 
16  17 
24  27 
28  18 
32  21 
36  1 

私はnumpyで細胞を見つけたいです2次元配列codeと一致し、region列の対応する値で置き換えます。問題は、code = 12region = 16に置き換え、次の行で16の値を持つすべてのセル(値が16に割り当てられたセルを含む)が17の値に置き換えられることです。それ?

+0

これまでに試したコードを投稿できますか? –

+1

'df ['your_col']。map(df2.set_index( 'code'))' –

答えて

3

ここでは、アレイ内のこれらのキーのそれぞれの位置をバックトレースするnp.searchsortedに基づいてベクトル化一つだし、次に置き換えると(ただし、それを助けることができなかった)、ここではほぼ性差別的関数名を言い訳してください -

def replace_with_dict(ar, dic): 
    # Extract out keys and values 
    k = np.array(list(dic.keys())) 
    v = np.array(list(dic.values())) 

    # Get argsort indices 
    sidx = k.argsort() 

    # Drop the magic bomb with searchsorted to get the corresponding 
    # places for a in keys (using sorter since a is not necessarily sorted). 
    # Then trace it back to original order with indexing into sidx 
    # Finally index into values for desired output. 
    return v[sidx[np.searchsorted(k,ar,sorter=sidx)]] 

サンプル実行 -

In [82]: dic ={334:0, 4:22, 8:31, 12:16, 16:17, 24:27, 28:18, 32:21, 36:1} 
    ...: 
    ...: np.random.seed(0) 
    ...: a = np.random.choice(dic.keys(), 20) 
    ...: 

In [83]: a 
Out[83]: 
array([ 28, 16, 32, 32, 334, 32, 28, 4, 8, 334, 12, 36, 36, 
     24, 12, 334, 334, 36, 24, 28]) 

In [84]: replace_with_dict(a, dic) 
Out[84]: 
array([18, 17, 21, 21, 0, 21, 18, 22, 31, 0, 16, 1, 1, 27, 16, 0, 0, 
     1, 27, 18]) 

改善

大きなアレイの

速い一方がソート値とキー配列であり、次いで、sorterなしsearchsortedを使用するように希望 -

def replace_with_dict2(ar, dic): 
    # Extract out keys and values 
    k = np.array(list(dic.keys())) 
    v = np.array(list(dic.values())) 

    # Get argsort indices 
    sidx = k.argsort() 

    ks = k[sidx] 
    vs = v[sidx] 
    return vs[np.searchsorted(ks,ar)] 

ランタイム試験 -

In [91]: dic ={334:0, 4:22, 8:31, 12:16, 16:17, 24:27, 28:18, 32:21, 36:1} 
    ...: 
    ...: np.random.seed(0) 
    ...: a = np.random.choice(dic.keys(), 20000) 

In [92]: out1 = replace_with_dict(a, dic) 
    ...: out2 = replace_with_dict2(a, dic) 
    ...: print np.allclose(out1, out2) 
True 

In [93]: %timeit replace_with_dict(a, dic) 
1000 loops, best of 3: 453 µs per loop 

In [95]: %timeit replace_with_dict2(a, dic) 
1000 loops, best of 3: 341 µs per loop 

汎用ケースすべての配列要素が辞書にない場合

入力配列のすべての要素が辞書に存在することが保証されていない場合、リストされているとおりにもう少し作業が必要です以下 -

def replace_with_dict2_generic(ar, dic, assume_all_present=True): 
    # Extract out keys and values 
    k = np.array(list(dic.keys())) 
    v = np.array(list(dic.values())) 

    # Get argsort indices 
    sidx = k.argsort() 

    ks = k[sidx] 
    vs = v[sidx] 
    idx = np.searchsorted(ks,ar) 

    if assume_all_present==0: 
     idx[idx==len(vs)] = 0 
     mask = ks[idx] == ar 
     return np.where(mask, vs[idx], ar) 
    else: 
     return vs[idx] 

サンプル実行 -

In [163]: dic ={334:0, 4:22, 8:31, 12:16, 16:17, 24:27, 28:18, 32:21, 36:1} 
    ...: 
    ...: np.random.seed(0) 
    ...: a = np.random.choice(dic.keys(), (20)) 
    ...: a[-1] = 400 

In [165]: a 
Out[165]: 
array([ 28, 16, 32, 32, 334, 32, 28, 4, 8, 334, 12, 36, 36, 
     24, 12, 334, 334, 36, 24, 400]) 

In [166]: replace_with_dict2_generic(a, dic, assume_all_present=False) 
Out[166]: 
array([ 18, 17, 21, 21, 0, 21, 18, 22, 31, 0, 16, 1, 1, 
     27, 16, 0, 0, 1, 27, 400]) 
+0

ありがとう@Divakar、これは本当に包括的な解決です! – user308827

0

私がやるだろうな方法これは2回のパスである:最初に、値を交換後、交換したい値に対応するインデックスを取得し、 。

arr = np.array([1,2,3,1,2,3]) 
code = np.array([1,2]) 
region = np.array([2,3]) 
index_list = [] 
for val in code: 
    index_list.append(np.where(arr == val)[0]) 
for indexes, replace_val in zip(index_list, region): 
    arr[indexes] = replace_val 
+0

なぜループ内でnp.whereを使用していますか? –

+0

良い方法がありますか?私は配列内の複数の値のインデックスを同時に取得するメソッドを見つけることができませんでした。 – Sebastian

+0

私はあなたが何をしようとしているのか見ていませんでしたが、一般的にnumpyメソッドのループを使用するのは反パターンです。 –

関連する問題