Какой самый эффективный способ проверить, существует ли значение в массиве NumPy?
У меня очень большой массив NumPy
1 40 3
4 50 4
5 60 7
5 49 6
6 70 8
8 80 9
8 72 1
9 90 7
....
Я хочу проверить, существует ли значение в 1-м столбце массива. У меня есть куча доморощенных способов (например, итерации по каждой строке и проверка), но, учитывая размер массива, я бы хотел найти наиболее эффективный метод.
Спасибо!
9 ответов
Как насчет
if value in my_array[:, col_num]:
do_whatever
Редактировать: я думаю __contains__
реализован таким образом, что это то же самое, что и версия @detly
Наиболее очевидным для меня будет:
np.any(my_array[:, 0] == value)
Чтобы проверить несколько значений, вы можете использовать numpy.in1d (), который представляет собой поэлементную версию функции ключевого слова python. Если ваши данные отсортированы, вы можете использовать numpy.searchsorted():
import numpy as np
data = np.array([1,4,5,5,6,8,8,9])
values = [2,3,4,6,7]
print np.in1d(values, data)
index = np.searchsorted(data, values)
print data[index] == values
Захватывающий. Мне нужно было повысить скорость серии циклов, которые должны выполнять сопоставление индекса таким же образом. Поэтому я решил примерить здесь все решения вместе с некоторыми риффами.
Вот мои тесты скорости для Python 2.7.10:
import timeit
timeit.timeit('N.any(N.in1d(sids, val))', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')
+18,86137104034424
timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = [20010401010101+x for x in range(1000)]')
+15,061666011810303
timeit.timeit('N.in1d(sids, val)', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')
+11,613027095794678
timeit.timeit('N.any(val == sids)', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')
+7,670552015304565
timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')
+5,610057830810547
timeit.timeit('val == sids', setup = 'import numpy as N; val = 20010401020091; sids = N.array([20010401010101+x for x in range(1000)])')
1,6632978916168213
timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = set([20010401010101+x for x in range(1000)])')
0,0548710823059082
timeit.timeit('val in sids', setup = 'import numpy as N; val = 20010401020091; sids = dict(zip([20010401010101+x for x in range(1000)],[True,]*1000))')
+0,054754018783569336
Очень удивительно! Разница в порядках!
Подводя итог, если вы просто хотите узнать, есть ли что-то в одномерном списке или нет:
- 19s N.any(N.in1d (массив numpy))
- 15 с х в (список)
- 8s N.any (x == массив numpy)
- 6s x in (массив numpy)
- .1s x in (набор или словарь)
Если вы хотите знать, где что-то есть в списке (порядок важен):
- 12s N.in1d (x, массив numpy)
- 2s x == (массив numpy)
Добавление ответа @HYRY in1d кажется самым быстрым для numpy. Это использует numpy 1.8 и python 2.7.6.
В этом тесте in1d был самым быстрым:
a = arange(0,99999,3)
%timeit 10 in a
%timeit in1d(a, 10)
10000 loops, best of 3: 150 µs per loop
10000 loops, best of 3: 61.9 µs per loop
Использование набора Python кажется самым быстрым:
s = set(range(0, 99999, 3))
%timeit 10 in s
10000000 loops, best of 3: 47 ns per loop
Я рекомендую использовать np.isin.
Руководство предлагает эту функцию для маскировки значений, но вы можете просто вызватьany
илиall
по этим маскам самостоятельно проверить членство. Рекомендую проверить скорость с помощьюtimeit
как предложено выше.
Не используйте циклы for, это в первую очередь противоречит идее использования numpy.
Вы можете либо проверить, находится ли какой-либо элемент списка в массиве, поместив массив первым, либо поместить массив вторым, чтобы проверить, охватывает ли он все элементы списка.
import numpy
a = np.arange(9).reshape((3,3))
any_lookup = [2,6,10,10002,34543,45]
all_lookup = [2,3,4,5]
none_lookup = [-10,435344,-255,557755]
res_any = np.isin(a,any_lookup)
res_all = np.isin(a,all_lookup)
res_none = np.isin(a,none_lookup)
print(res_any)
print(res_all)
print(res_none)
print(res_any.any())
print(res_all.any())
print(res_none.any())
print(np.isin(any_lookup,a).all())
print(np.isin(all_lookup,a).all())
Полученные результаты:
[[False False True]
[False False False]
[ True False False]]
[[False False True]
[ True True True]
[False False False]]
[[False False False]
[False False False]
[False False False]]
True
True
False
False
True
Если вы ищете список целых чисел, вы можете использовать индексацию для выполнения работы. Это также работает с nd-массивами, но кажется медленнее. Возможно, будет лучше, если вы сделаете это более одного раза.
def valuesInArray(values, array):
values = np.asanyarray(values)
array = np.asanyarray(array)
assert array.dtype == np.int and values.dtype == np.int
matches = np.zeros(array.max()+1, dtype=np.bool_)
matches[values] = True
res = matches[array]
return np.any(res), res
array = np.random.randint(0, 1000, (10000,3))
values = np.array((1,6,23,543,222))
matched, matches = valuesInArray(values, array)
Используя numba и njit, я мог получить ускорение на ~x10.
На мой взгляд, наиболее удобный способ:
(Val in X[:, col_num])
где Val - значение, которое вы хотите проверить, а X - массив. В вашем примере предположим, что вы хотите проверить, существует ли значение 8 в третьем столбце. Просто пиши
(8 in X[:, 2])
Это вернет True, если 8 находится в третьем столбце, иначе False.
Если вы хотите проверить, есть ли список a
находится в массиве NumPy b
затем используйте следующий синтаксис:
np.any(np.equal(a, b).all(axis=1))
Ввод axis = 1
учитывая, что массив NumPy имеет форму n*2