私は次のMWEを持っています。ここでは、リスト内包表記を使用して、リストls
内に含まれている文字列を検索しますstrings
。
import numpy as np
strings = ["ASD", "DSA", "ABC", "ABQ"]
ls = np.asarray(["ASD", "DSA", "ASD", "ABC", "ABQ","ASD", "DSA", "ASD", "ABC", "ABQ","ASD", "DSA", "ASD", "ABC", "ABQ"])
for string in strings:
print(len(ls[[string in s for s in ls]]))
これは意図したとおりに機能しls
ますが、問題は、私のリストが非常に長く(10 ^ 9エントリ)、リストの理解にかなりの時間がかかることです。
上記のコードを最適化する方法はありますか?
編集:私は個々の発生、すなわち6、3、3、3を記録することを可能にする解決策を探しています
この投稿で提案されたアイデアを使用することをお勧めします; 最善のアプローチはを使用することcollections.Counter
です。
これにより、Counter
1回のビルドが行われ、カウントする個々の要素を簡単に検索できます。
これは次のようになります。
import collections
import numpy as np
import timeit
def _get_data(as_numpy):
data = []
for _ in range(10**6):
data.extend(["ASD", "DSA", "ASD", "ABC", "ABQ"])
if as_numpy:
data = np.asarray(data)
return data
def f1(data):
search_list = ["ASD", "DSA", "ABC", "ABQ"]
result_list = []
for search_str in search_list:
result_list.append(
len(data[[search_str in s for s in data]]))
return result_list
def f2(data):
search_list = ["ASD", "DSA", "ABC", "ABQ"]
result_list = []
c = collections.Counter(data)
for search_str in search_list:
result_list.append(
c[search_str])
return result_list
def f3(data):
search_list = ["ASD", "DSA", "ABC", "ABQ"]
result_list = []
c = collections.Counter(data)
for search_str in search_list:
result_list.append(
data.count(search_str))
return result_list
def f4(data):
# suggestion by user 'nixon' in another answer to this question
search_list = ["ASD", "DSA", "ABC", "ABQ"]
l, counts = np.unique(data, return_counts=True)
# 'l' and 'counts' are in different order than 'search_list'
result_list = [
counts[np.where(l == search_str)[0][0]]
for search_str in search_list]
return result_list
これらのアプローチで同じ結果が得られるようにするには、次のようにします。
data1 = _get_data(as_numpy=True)
data2 = _get_data(as_numpy=False)
assert f1(data1) == f2(data2) == f3(data2) == f4(data1)
そして、タイミングを比較すると、次のようになります。
print(timeit.timeit(
'f(data)',
'from __main__ import f1 as f, _get_data; data = _get_data(as_numpy=True)',
number=10))
print(timeit.timeit(
'f(data)',
'from __main__ import f2 as f, _get_data; data = _get_data(as_numpy=False)',
number=10))
print(timeit.timeit(
'f(data)',
'from __main__ import f3 as f, _get_data; data = _get_data(as_numpy=False)',
number=10))
print(timeit.timeit(
'f(data)',
'from __main__ import f4 as f, _get_data; data = _get_data(as_numpy=True)',
number=10))
# f1 48.2 sec
# f2 1.7 sec
# f3 3.8 sec
# f4 9.7 sec
ご覧のとおり、時差には大きさの順序があります。
それはあなたの場合にうまくいきますか?
編集:numpy.unique
この質問への別の回答で@nixonによって提案されたものと同様の、を使用したアプローチを追加しました。それでも、を使用するよりも遅いようcollections.Counter
です。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加