I suggest you use the ideas proposed in this post; the best approach could be using collections.Counter
.
This builds the Counter
once, and then you can easily look up the individual elements you want the count for.
This could look like this:
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
To assure that these approaches get the same results:
data1 = _get_data(as_numpy=True)
data2 = _get_data(as_numpy=False)
assert f1(data1) == f2(data2) == f3(data2) == f4(data1)
And comparing the timings, I get:
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
As you can see, there is an order of magnitud in time difference.
Does that work for your case?
EDIT: added approach using numpy.unique
, similar to the one suggested by @nixon in another answer to this question; it still seems to be slower than using collections.Counter
.