Я мог бы выполнять фильтрацию массивов numpy через
a[np.where(a[:,0]==some_expression)]
или
a[a[:,0]==some_expression]
Каковы (не)преимущества каждой из этих версий, особенно в отношении производительности?
@LiorT - не уверен, что я следую вашему комментарию, вы имеете в виду, что a[:,0]==some_expression
- это ложь? a[a[:,0]==some_expression]
тоже работает в этом случае
@Mr_and_Mrs_D np.where похож на функцию excel if. вы можете попросить его дать вам один ответ для мест, где какое-то условие верно, и другое значение, если это не так. например, np.where(x==10,10,0) вернет массив из 10, а нули зависят от того, равен ли x 10 или нет. это может быть полезно иногда
О, я понимаю - но в этом вопросе это не должно иметь значения
К моему удивлению, первый работает немного лучше:
a = np.random.random_integers(100, size=(1000,1))
import timeit
repeat = 3
numbers = 1000
def time(statement, _setup=None):
print(min(
timeit.Timer(statement, setup=_setup or setup).repeat(repeat, numbers)))
setup = """from __main__ import np, a"""
time('a[np.where(a[:,0]==99)]')
time('a[(a[:,0]==99)]')
печатает (например):
0.017856399000000023
0.019185326999999974
Увеличение размера массива приводит к тому, что числа различаются еще больше.
Булева индексация внутри преобразуется в целочисленную. Это указано в документах:
In general if an index includes a Boolean array, the result will be identical to inserting
obj.nonzero()
into the same position and using the integer array indexing mechanism described above.
Таким образом, сложность двух подходов одинакова. Но np.where
более эффективен для больших массивов:
np.random.seed(0)
a = np.random.randint(0, 10, (10**7, 1))
%timeit a[np.where(a[:, 0] == 5)] # 50.1 ms per loop
%timeit a[a[:, 0] == 5] # 62.6 ms per loop
Теперь у np.where
есть и другие преимущества: расширенное целочисленное индексирование хорошо работает в нескольких измерениях. Пример, когда логическое индексирование в этом аспекте не интуитивно понятно, см. в Индексация NumPy: трансляция с булевыми массивами. Поскольку np.where
более эффективен, чем логическое индексирование, это просто дополнительная причина, по которой его следует предпочесть.
Но в документации np.where() говорится: «Если указано только условие, верните condition.nonzero()». Почему это не то же самое, что индексация по умолчанию с помощью логического значения, поскольку оба используют bool_array.nonzero()?
@Dusch, не уверен, я не смотрел исходный код. Скорее всего детали реализации. Мое основное мнение заключается в том, что np.where
быстрее и универсальнее, поэтому, если важна эффективность, стоит многословия.
С моей точки зрения, основное преимущество np.where заключается в том, что он также может давать вам результаты, когда выражение ложно. Это основной способ, которым я его использую. Вы также можете проверить, как это влияет на производительность, особенно на время выполнения.