2017-03-24 8 views
1

大きな配列があります。それ以下の要素を持つ各要素を減算し、ループを使用せずに新しいリスト/配列に結果を格納する方法はありますか?Pythonで配列の要素を反復的に減算する

私が何を意味するかの簡単な例:

a = numpy.array([4,3,2,1]) 

result = [4-3, 4-2, 4-1, 3-2, 3-1, 2-1] = [1, 2, 3, 1, 2 ,1] 

私が働いている「本当の」配列は順番に番号が含まれていないことに注意してください。例を単純にするだけです。

結果が(n-1)である必要があります。ここで、nは配列のサイズです。

ループを使用せずにこれを行う方法はありますか?「スマート」な方法で配列を繰り返す方法はありますか?

ありがとうございます!

+0

なぜ(n-1)!要素?それは2を選択する必要があるように私に見える。 – user2357112

+0

はい、あなたは絶対に正しいです!それはnC2 –

答えて

2

は、ここで抽出後の放送減算用maskingベースのアプローチだとマスクの作成のために我々は再びので、電源が入っbroadcasting(ダブルbroadcastingを利用しています)話をする -

r = np.arange(a.size) 
out = (a[:, None] - a)[r[:,None] < r] 

ランタイムテスト

ベクトル化が近づい -

# @user2357112's solution 
def pairwise_diff_triu_indices_based(a): 
    return (a[:, None] - a)[np.triu_indices(len(a), k=1)] 

# Proposed in this post 
def pairwise_diff_masking_based(a): 
    r = np.arange(a.size) 
    return (a[:, None] - a)[r[:,None] < r] 

タイミング -

In [109]: a = np.arange(2000) 

In [110]: %timeit pairwise_diff_triu_indices_based(a) 
10 loops, best of 3: 36.1 ms per loop 

In [111]: %timeit pairwise_diff_masking_based(a) 
100 loops, best of 3: 11.8 ms per loop 

関与性能パラメータを詳しく見

のマスクベースのアプローチができますどのくらい勉強するために、この設定のタイミングにより深いビットを掘るしてみましょう。ここでは、比較のために、マスク作成とインデックスの作成、マスクベースのブールインデックスと整数ベースのインデックスの2つの部分があります。

どのくらいのマスク作成が役に立ちますか?インデックスの設定上にマスク作成上の5x改善について

In [37]: r = np.arange(a.size) 

In [38]: %timeit np.arange(a.size) 
1000000 loops, best of 3: 1.88 µs per loop 

In [39]: %timeit r[:,None] < r 
100 loops, best of 3: 3 ms per loop 

In [40]: %timeit np.triu_indices(len(a), k=1) 
100 loops, best of 3: 14.7 ms per loop 

整数インデックスにはどのくらいのブールインデックスが役立ちますか?ここ2.5x改善について

In [41]: mask = r[:,None] < r 

In [42]: idx = np.triu_indices(len(a), k=1) 

In [43]: subs = a[:, None] - a 

In [44]: %timeit subs[mask] 
100 loops, best of 3: 4.15 ms per loop 

In [45]: %timeit subs[idx] 
100 loops, best of 3: 10.9 ms per loop 

+1

それは上の三角形を抽出するはるかに速い方法です。 – user2357112

+0

@ user2357112よろしく!その上にちょっとした見た目を追加しました。 – Divakar

1
a = [4, 3, 2, 1] 
differences = ((x - y) for i, x in enumerate(a) for y in a[i+1:]) 
for diff in differences: 
    # do something with difference. 
    pass 
+0

はいですが、リストの理解はループを使用しています!私の配列が大きすぎます! –

+0

NumPyでは、「ループを使用しない」には、リストの補完と、Pythonで反復を実行するその他の構文が含まれています。目標は、ボックス化されていないデータに対してCループにすべての反復を適用することです。 – user2357112

+0

これを行うには、スマートな方法で配列を繰り返す方法がありますか?最終的には、配列から別の配列を引くだけです。 –

0

itertools.combinationsをチェックアウト:中

from itertools import combinations 

l = [4, 3, 2, 1] 

result = [] 
for n1, n2 in combinations(l, 2): 
    result.append(n1 - n2) 

print result 

結果:

[1, 2, 3, 1, 2, 1] 

combinationsジェネレータを返すので、これは非常に大規模なリストのために良いです:)

3
temp = a[:, None] - a 
result = temp[np.triu_indices(len(a), k=1)] 

すべてのペアを実行サブトラクションを使ってtempを生成します。それ自体から要素を減算し、後の要素から以前の要素を減算してから、triu_indicesを使用して、必要な結果を選択します。 (triu_indicesが遅く、アレイの上部の三角形を選択するためにインデックスを使用して遅いため)ランタイムのほぼすべて(a[:, None] adds an extra length-1 axis to a。)

tempからresultを構築費やされます。あなたが直接tempを使用することができた場合、あなたは多くの時間を節約することができます

In [13]: a = numpy.arange(2000) 

In [14]: %%timeit 
    ....: temp = a[:, None] - a 
    ....: 
100 loops, best of 3: 6.99 ms per loop 

In [15]: %%timeit 
    ....: temp = a[:, None] - a 
    ....: result = temp[numpy.triu_indices(len(a), k=1)] 
    ....: 
10 loops, best of 3: 51.7 ms per loop 
+0

エレガント!あなたが使っているこの 'a [:、None]'インデックスの参照を与えることができますか? –

+0

@SomeGuy:追加されました。 – user2357112

+0

これは素晴らしい作品です!ありがとう! –

関連する問題