array3 = array1.astype(float) # this copies the array by default.
array3[array1 != 0] = array2[array1[array1 != 0]-1, 2]
結果は次のとおりです:あなたは、高度なnumpyの配列インデックスと一緒にブールインデックスを使用することができます
array([[ 0, 62., 62., 88.],
[ 0, 73., 64., 95.],
[ 0, 59., 67., 65.]])
説明
あなたが最初の非ゼロのエントリがある場所を示すブール配列を作成:
>>> non_zero_mask = array1 != 0
array([[False, True, True, True],
[False, True, True, True],
[False, True, True, True]], dtype=bool)
これは、 d交換する。あなたのarray2
を注文し、我々は、交換価値のための適切な行を見つけるために、1を減算する必要が値1で開始しているので
>>> non_zero_values = array1[non_zero_mask]
array([7, 4, 1, 8, 5, 2, 9, 6, 3])
:
その後、あなたはこれらの要素の値を見つける必要があります。あなたのarray2
がソートされていない場合、あなたはそれを並べ替えたり、間に別のインデックス作成を行うために必要がある場合があります。
>>> replacement_rows = array2[non_zero_values-1]
array([[ 7., 7., 62.],
[ 4., 4., 62.],
[ 1., 1., 88.],
[ 8., 8., 73.],
[ 5., 5., 64.],
[ 2., 2., 95.],
[ 9., 9., 59.],
[ 6., 6., 67.],
[ 3., 3., 65.]])
>>> replacement_values = array2[non_zero_values-1, 2] # third element of that row!
array([ 62., 62., 88., 73., 64., 95., 59., 67., 65.])
してからちょうど元または新しい配列にこれらの値を割り当てる:
array3[non_zero_mask] = replacement_values
このアプローチには依存していますarray2
の順番になっていますので、より複雑な条件があれば壊れます。しかし、それは値とインデックスの間の関係を見つけて、それを単純な0の代わりに挿入するか、または別の中間のnp.where
/ブールインデックス作成の代わりに挿入する必要があります。
拡張
場合、あなたはソートarray2
を持っていないと、あなたが行うことができ、それを並べ替えることはできません。
>>> array3 = array1.astype(float)
>>> array3[array1 != 0] = array2[np.where(array2[:, 0][None, :] == array1[array1 != 0][:, None])[1], 2]
>>> array3
array([[ 0., 62., 62., 88.],
[ 0., 73., 64., 95.],
[ 0., 59., 67., 65.]])
を、これはあなたがよ互いに配列の放送で動作しますので、サイズがarray1.size * array1.size
の配列を作成します。だから、これはあまり記憶にはならないかもしれませんが、完全にベクトル化されています。あなたはネイティブnumpyのscipyのダウンロードやバージョンが存在しないため、遅くなる事をスピードアップしたい場合は
Numba(あなたはスピードが必要な場合は)
numbaは素晴らしいです。あなたがアナコンダやcondaをお持ちの場合はそれがすでにインストールされている、それは現実的な選択肢かもしれないので:特に大規模な配列のために
import numba as nb
import numpy as np
@nb.njit
def nb_replace_values(array, old_new_array):
res = np.zeros(array.shape, dtype=np.float64)
rows = array.shape[0]
columns = array.shape[1]
rows_replace_array = old_new_array.shape[0]
for row in range(rows):
for column in range(columns):
val = array[row, column]
# only replace values that are not zero
if val != 0:
# Find the value to replace the element with
for ind_replace in range(rows_replace_array):
if old_new_array[ind_replace, 0] == val:
# Match found. Replace and break the innermost loop
res[row, column] = old_new_array[ind_replace, 2]
break
return res
nb_replace_values(array1, array2)
array([[ 0., 62., 62., 88.],
[ 0., 73., 64., 95.],
[ 0., 59., 67., 65.]])
何の一時的な配列が作成されませんので、これは明らかに最速とメモリ効率的なソリューションとなります。ファンクションがオンザフライでコンパイルする必要があるため、最初の呼び出しは非常に遅くなります。
タイミング:
%timeit nb_replace_values(array1, array2)
100000ループ、3の最もよい:ループ当たり6.23マイクロ秒
%%timeit
array3 = array1.astype(float)
array3[array1 != 0] = array2[np.where(array2[:, 0][None, :] == array1[array1 != 0][:, None])[1], 2]
10000ループ、3の最もよい:ループ
あたり74.8マイクロ秒
# Solution provided by @PDRX
%%timeit
array3 = array1.astype(float)
for i in array2[:,0]:
i_arr1,j_arr1 = np.where(array1 == i)
i_arr2 = np.where(array2[:,0] == i)
array3[i_arr1,j_arr1] = array2[i_arr2,2]
の
1000のループ、3の最高:ループあたり689マイクロ秒
まあ、私は配列2が実際にソートされているが、一般的に、ランダムで、必ずしもソートされていない任意の配列を、ことになっている与えた例では、これらの数字が繰り返されない限り、一貫した順序で並べ替えることのできない数字です。その列をIDと見なします。あなたはそれに基づいてあなたの答えを改善できますか?私の例を更新します。 – Bella
@Bellaそれははるかに難しく、私はそれに多くの考えを入れていない。しかし、答えの最後の部分を見てください。これは非常に効率が悪く、これらの場合には 'pandas'やカスタマイズされた' numba'関数の使用をお勧めします。 – MSeifert
ああ、私は前にあなたの最終編集を見たことがなかった!私は他の答えを見たとき、すぐにそれを理解しました。それは素晴らしいものでした。あなたのものはもう少し入手が難しいですが、あなたが正しいです、私は速度とあなたのための両方のソリューションをテストしたが、より速いですが、大規模な配列のほんの一桁の速さです。今私はおそらく私はおそらく両方を保つので、受け入れる答えは未定です。 :/私はあなたが配列のサイズについて言及したものは得られませんでした - 私はarray1と同じサイズarray3と両方のソリューションgetsizeof私に同じサイズを与える見ることができますから。 – Bella