数値のリストが与えられた場合、すべての(i
)番目の要素とその(i+1
)番目の要素の違いをどのように見つけますか?
lambda
式を使用した方がいいですか、それともリスト内包を使用した方がいいですか?
例えば:
リストを考えるとt=[1,3,6,...]
、目標は、リストを見つけることですv=[2,3,...]
ので3-1=2
、6-3=3
など
数値のリストが与えられた場合、すべての(i
)番目の要素とその(i+1
)番目の要素の違いをどのように見つけますか?
lambda
式を使用した方がいいですか、それともリスト内包を使用した方がいいですか?
例えば:
リストを考えるとt=[1,3,6,...]
、目標は、リストを見つけることですv=[2,3,...]
ので3-1=2
、6-3=3
など
回答:
>>> t
[1, 3, 6]
>>> [j-i for i, j in zip(t[:-1], t[1:])] # or use itertools.izip in py2k
[2, 3]
list(itertools.starmap(operator.sub, zip(t[1:], t)))
インポート後)。itertools
operator
list(map(operator.sub, t[1:], t[:-1]))
行います。
他の答えは正しいですが、数値計算を行っている場合は、numpyを検討することをお勧めします。numpyを使用すると、答えは次のとおりです:
v = numpy.diff(t)
np.diff([2,4,9])
次のようになります[2,5]
zip
バージョンよりも効率的ですか?
を使用itertools.tee
しzip
て、結果を効率的に構築できます。
from itertools import tee
# python2 only:
#from itertools import izip as zip
def differences(seq):
iterable, copied = tee(seq)
next(copied)
for x, y in zip(iterable, copied):
yield y - x
またはitertools.islice
代わりに使用:
from itertools import islice
def differences(seq):
nexts = islice(seq, 1, None)
for x, y in zip(seq, nexts):
yield y - x
itertools
モジュールの使用を避けることもできます:
def differences(seq):
iterable = iter(seq)
prev = next(iterable)
for element in iterable:
yield element - prev
prev = element
すべての結果を保存して無限のイテラブルをサポートする必要がない場合、これらすべてのソリューションは一定の空間で機能します。
ソリューションのいくつかのマイクロベンチマークは次のとおりです。
In [12]: L = range(10**6)
In [13]: from collections import deque
In [15]: %timeit deque(differences_tee(L), maxlen=0)
10 loops, best of 3: 122 ms per loop
In [16]: %timeit deque(differences_islice(L), maxlen=0)
10 loops, best of 3: 127 ms per loop
In [17]: %timeit deque(differences_no_it(L), maxlen=0)
10 loops, best of 3: 89.9 ms per loop
そして他の提案された解決策:
In [18]: %timeit [x[1] - x[0] for x in zip(L[1:], L)]
10 loops, best of 3: 163 ms per loop
In [19]: %timeit [L[i+1]-L[i] for i in range(len(L)-1)]
1 loops, best of 3: 395 ms per loop
In [20]: import numpy as np
In [21]: %timeit np.diff(L)
1 loops, best of 3: 479 ms per loop
In [35]: %%timeit
...: res = []
...: for i in range(len(L) - 1):
...: res.append(L[i+1] - L[i])
...:
1 loops, best of 3: 234 ms per loop
ご了承ください:
zip(L[1:], L)
同等であるzip(L[1:], L[:-1])
ため、zip
すでに最短入力に終了し、しかし、それは全体のコピーを回避しますL
。numpy.diff
ある遅いそれは最初に変換する必要があるためlist
にndarray
。あなたがあれば明らかに起動してndarray
、それは次のようになりますずっと速いです。
In [22]: arr = np.array(L)
In [23]: %timeit np.diff(arr)
100 loops, best of 3: 3.02 ms per loop
islice(seq, 1, None)
代わりにislice(seq, 1, len(seq))
使い方:=
はPython 3.8+で利用可能なセイウチ演算子を:
>>> t = [1, 3, 6]
>>> prev = t[0]; [-prev + (prev := x) for x in t[1:]]
[2, 3]
私は使用をお勧めします
v = np.diff(t)
これはシンプルで読みやすいです。
しかし、あなたがしたい場合v
と同じ長さを持つことがt
、その後
v = np.diff([t[0]] + t) # for python 3.x
または
v = np.diff(t + [t[-1]])
参考:これはリストに対してのみ機能します。
numpy配列の場合
v = np.diff(np.append(t[0], t))
機能的アプローチ:
>>> import operator
>>> a = [1,3,5,7,11,13,17,21]
>>> map(operator.sub, a[1:], a[:-1])
[2, 2, 2, 4, 2, 4, 4]
ジェネレーターの使用:
>>> import operator, itertools
>>> g1,g2 = itertools.tee((x*x for x in xrange(5)),2)
>>> list(itertools.imap(operator.sub, itertools.islice(g1,1,None), g2))
[1, 3, 5, 7]
インデックスの使用:
>>> [a[i+1]-a[i] for i in xrange(len(a)-1)]
[2, 2, 2, 4, 2, 4, 4]
OK。私は適切な解決策を見つけたと思います:
v = [x[1]-x[0] for x in zip(t[1:],t[:-1])]
周期的な境界を持つソリューション
数値積分では、リストを周期的な境界条件で差分したい場合があります(最初の要素が最後の要素との差分を計算するためです。この場合、numpy.roll関数が役立ちます:
v-np.roll(v,1)
先頭がゼロのソリューション
numpy.ediff1d(v)
これはnumpy.diffとして機能しますが、ベクター上でのみ機能します(入力配列をフラット化します)。結果のベクトルに番号を付加または追加する機能を提供します。これは、気象変数(雨、潜熱など)のフラックスであることが多い累積フィールドを処理する場合に役立ちます。最初のエントリは変更せずに、入力変数と同じ長さの結果のリストが必要になるためです。
それからあなたは書くでしょう
np.ediff1d(v,to_begin=v[0])
もちろん、np.diffコマンドを使用してこれを行うこともできますが、この場合は、シリーズの先頭にprependキーワードを付けてゼロを追加する必要があります。
np.diff(v,prepend=0.0)
上記のすべてのソリューションは、入力と同じ長さのベクトルを返します。
私のやり方
>>>v = [1,2,3,4,5]
>>>[v[i] - v[i-1] for i, value in enumerate(v[1:], 1)]
[1, 1, 1, 1]
[abs(j-i) for i,j in zip(t, t[1:])]