Pandas: как использовать эквивалент np.where()
Вы можете использовать функцию NumPy where() для быстрого обновления значений в массиве NumPy, используя логику if-else.
Например, в следующем коде показано, как обновить значения в массиве NumPy, соответствующие определенному условию:
import numpy as np #create NumPy array of values x = np.array([1, 3, 3, 6, 7, 9]) #update valuesin array based on condition x = np.where ((x < 5) | (x >8), x/2, x) #view updated array x array([0.5, 1.5, 1.5, 6. , 7. , 4.5])
Если заданное значение в массиве было меньше 5 или больше 8, мы делили значение на 2.
В противном случае мы оставили значение без изменений.
Мы можем выполнить аналогичную операцию в pandas DataFrame, используя функцию pandas where() , но синтаксис немного отличается.
Вот основной синтаксис с использованием функции NumPy where():
x = np.where (condition, value_if_true, value_if_false)
А вот основной синтаксис с использованием функции pandas where():
df['col'] = (value_if_false). where (condition, value_if_true)
В следующем примере показано, как использовать функцию where() в pandas на практике.
Пример: эквивалент np.where() в Pandas
Предположим, у нас есть следующие Pandas DataFrame:
import pandas as pd #create DataFrame df = pd.DataFrame() #view DataFrame print(df) A B 0 18 5 1 22 7 2 19 7 3 14 9 4 14 12 5 11 9 6 20 9 7 28 4
Мы можем использовать следующую функцию панд where() для обновления значений в столбце A на основе определенного условия:
#update values in column A based on condition df['A'] =(df['A'] / 2). where(df['A'] < 20, df['A'] \* 2) #view updated DataFrame print(df) A B 0 9.0 5 1 44.0 7 2 9.5 7 3 7.0 9 4 7.0 12 5 5.5 9 6 40.0 9 7 56.0 4
Если заданное значение в столбце А было меньше 20, мы умножали это значение на 2.
В противном случае мы разделили значение на 2.
Дополнительные ресурсы
В следующих руководствах объясняется, как выполнять другие распространенные операции в pandas:
Фильтрация значений и вырезание — Python: Numpy-массивы
При работе с данными часто возникает необходимость найти элементы по определенному условию. С точки зрения поиска ошибок в данных критерии поиска могут быть разными, например:
- Отрицательные значения в графе «Количество продаж»
- Буквы вместо цифр в графе «Номер телефона»
- Нереалистично большие числа в графе «Сумма сделки»
В стандартном Python искать и фильтровать значения можно с помощью функции filter() . В Numpy есть схожая функциональность, которую мы рассмотрим в этом уроке. Вы узнаете, как получить элементы по заданному условию при работе с массивами numpy.ndarray .
Как создать булеву маску
Для фильтрации значений массива numpy.ndarray по определенному условию используют булевы маски — массивы значений True и False . Каждый элемент проходит фильтрацию через булеву маску и распределяется в зависимости от значения маски:
- Если на той же позиции в маске стоит значение True , элемент добавляется в итоговый массив
- Если на позиции стоит значение False , то элемент не будет включен в итоговый массив
Существует три способа работы с булевой маской:
- Создать массив значений True и False вручную
- Использовать операторы сравнения над элементами исходного массива
- Применить логическое отрицание к текущей маске — поменять True на False и наоборот
Так все три способа выглядят в коде:
import numpy as np # Исходный массив base_array = np.array([0, 1, 2, 3, 4, 5, 6, 7,]) print(base_array) # => [0 1 2 3 4 5 6 7] # Ручное создание маски handmade_mask = [True, True, True, False, False, False, False, False,] print(handmade_mask) # => [True, True, True, False, False, False, False, False] # Создание маски по условию compare_mask = base_array 3 print(compare_mask) # => [ True True True False False False False False] # Создание маски по логическому отрицанию условия opposite_compare_mask = ~(base_array >= 3) print(opposite_compare_mask) # => [ True True True False False False False False]
Первый способ на практике встречается редко, потому что на ручное создание маски уходит слишком много времени, особенно при большом размере массива:
Как применять маску
Чтобы применить булеву маску к исходному массиву, достаточно подставить ее в качестве индекса:
print(base_array[handmade_mask]) # => [0 1 2] print(base_array[compare_mask]) # => [0 1 2] print(base_array[opposite_compare_mask]) # => [0 1 2]
Как мы говорили выше, в Python реализована функция filter() , которая применяется для итеративной фильтрации значений списка по условию:
# Фильтрация значений с использованием filter filtered_list = list( filter( lambda x: x 3, [0, 1, 2, 3, 4, 5, 6, 7,] ) ) print(filtered_list) # => [0 1 2]
Для итеративной фильтрации элементов массива numpy.ndarray используется другой способ — метод numpy.fromiter() :
# Итеративное создание нового массива с использованием fromiter, тип массива задается аргументом dtype filtered_array = np.fromiter( (base_array_element for base_array_element in base_array if base_array_element 3), dtype = base_array.dtype ) print(filtered_array) # => [0 1 2]
На практике часто требуется не только убирать значения из исходного массива, но и заменять их. Для этого используется метод numpy.where() :
# Заменяем отфильтрованные элементы на 0 print(np.where(base_array 3, base_array, 0)) # => [0 1 2 0 0 0 0 0]
Если для фильтрации мы используем составное условие, лучше инициализировать маску отдельно. Это упрощает поддержку и делает код более читабельным:
# Заменяем отфильтрованные элементы на 0 с использованием маски compare_masks = (base_array > 5) | (base_array 3) print(np.where(compare_masks, base_array, 0)) # => [0 1 2 0 0 0 6 7]
В реальных данных регулярно возникают пропущенные значения. Это может происходить из-за человеческого фактора, сбоя в работе сервисов или ошибки при записи в базу данных. Для таких случаев в Numpy существует отдельный тип данных numpy.nan (not a number):
# Массив с пропущенными значениями raw_array = np.array([0, 1, None, 3, 4, None, 6, 7,], dtype=np.float64) print(raw_array) # => [ 0. 1. nan 3. 4. nan 6. 7.]
Для корректной работы программ необходимо обнаруживать пропуски, чистить данные от них или заменять на значение по умолчанию.
Рассмотрим на примере. Сначала нужно обнаружить пропуски:
# Маска для поиска пропусков nan_mask = np.isnan(raw_array) print(nan_mask) # => [False False True False False True False False]
Затем чистим данные от пропусков:
# Маска для фильтрации пропущенных значений not_nan_mask = ~nan_mask print(raw_array[not_nan_mask]) # => [0. 1. 3. 4. 6. 7.]
Теперь заменяем пропуски на некоторое значение:
# Заменяем пропуски на 0 print(np.where(nan_mask, 0, raw_array)) # => [0. 1. 0. 3. 4. 0. 6. 7.]
Как применять маску с двумерными массивами
Выше мы рассмотрели фильтрацию значений на примере одномерного массива. Те же принципы применимы и в работе с двумерными массивами. Рассмотрим пример задачи — подготовим сырые данные продаж магазина ноутбуков по следующим шагам:
- Сначала обнаружим выбросы двух типов — значения выше 200 и отрицательные значения. Число 200 выбрано потому, что именно столько ноутбуков хранится на складе. Менеджер магазина знает, что в день не бывает более 200 продаж
- Затем заменим выбросы и пропуски на среднее значение продаж
Мы проводим эти операции, чтобы подготовить сырые данные к более глубокому анализу с применением методов статистики и машинного обучения:
# Создаем список списков продаж четырех магазинов orders_values = [ [7, 1, -7, None], [1000, 2, 4, None], [3, None, 503, 3], [8, 12, 8, 7], [15, 11, None, 9], [None, 18, 17, -21], [252, 16, 25, 17] ] # Конвертируем в Numpy-массив orders = np.array(orders_values, dtype=np.float64) print(orders) # => [[ 7. 1. -7. nan] # [1000. 2. 4. nan] # [ 3. nan 503. 3.] # [ 8. 12. 8. 7.] # [ 15. 11. nan 9.] # [ nan 18. 17. -21.] # [ 252. 16. 25. 17.]]
Чтобы отфильтровать значения, нужно создать маски:
# Маска для отрицательных значений negative_values = orders 0 print(orders[negative_values]) # => [ -7. -21.] # Маска для больших значений big_values = orders > 200 print(orders[big_values]) # => [1000. 503. 252.] # Маска для пропущенных значений и подсчета их количества nan_values = np.isnan(orders) print(sum(sum(nan_values))) # => 5
Чтобы найти средние значения, нужно оставить только стандартные значения продаж. Сделать это можно маской, объединяющей логические отрицания сформированных масок:
# Маска стандартных значений normal_mask = ~negative_values & ~big_values & ~nan_values # Стандартные значения заказов normal_values = orders[normal_mask] # Среднее значение для стандартных заказов normal_mean = normal_values.mean() normal_mean = int(normal_mean) print(normal_mean) # => 10
Далее остается только заменить нестандартные значения на величину среднего:
# Массив, в котором нестандартные значения заменены на среднее prepared_orders = np.where(normal_mask, orders, normal_mean) print(prepared_orders) # => [[ 7. 1. 10. 10.] # [10. 2. 4. 10.] # [ 3. 10. 10. 3.] # [ 8. 12. 8. 7.] # [15. 11. 10. 9.] # [10. 18. 17. 10.] # [10. 16. 25. 17.]]
Выводы
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях:
Numpy Where передать строку как переменную
Ищу в Pandas DataFrame координаты ячейки содержащей нужный мне текст. Для этого использую Numpy where.
rows, cols = np.where(df == 'Нужный мне текст')
Когда пытаюсь сравнивать с переменной содержащей текст, то ничего не находит:
text_to_find='Нужный мне текст' rows, cols = np.where(df == text_to_find)
Подскажите пожалуйста, как в Numpy Where искать текст, содержащийся в переменной.
Отслеживать
17.9k 11 11 золотых знаков 25 25 серебряных знаков 58 58 бронзовых знаков
задан 21 мар 2023 в 8:54
31 4 4 бронзовых знака
Я попробовал, вообще-то работает одинаково. Что-то вы не то делаете. А текст вы на полное совпадение именно проверяете?
21 мар 2023 в 9:16
Действительно все работает, ошибка была у меня, в DataFrame были слова с буквой ё, а искал я без нее.
21 мар 2023 в 10:37
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Согласно документации where возвращает не rows и cols а ndarray
Создадим простой датафрейм
>>> d = >>> df = pd.DataFrame(data=d) >>> print(df) col1 col2 0 1 3 1 2 4
А теперь попробуем найти 1 в нашем датафрейме.
>>> np.where(df == 1, df, -1)
Первым аргументом передаем условие, вторым сам датафрейм, а третьим то чем следует заполнить данные которые не будут совпадать с данным условием, например -1
Таким образом в качестве результата получаем массив:
array([[ 1, -1], [-1, -1]])
Если вместо -1 будем использовать 0 получим:
array([[1, 0], [0, 0]])
Теперь как мы можем получить все таки колонку и строку — отбрасыванием
>>> df.where(df == 1).dropna(how='all') # отбрасываем строки
А тут мы отбрасываем и строки и колонки
>>> res = df.where(df == 1).dropna(how='all').dropna(axis=1)
В итоге получается такой результат
col1 0 1.0
Получить строку мы можем таким образом
>>> res.index Int64Index([0], dtype='int64')
Получить колонку таким образом
>>> res.columns Index(['col1'], dtype='object')
Но это может быть не совсем удобно, что если нам нужны tuples в виде (row, col)?
Тогда мы можем сгенерировать их массив таким образом:
[(df[col][df[col]==1].index[i], df.columns.get_loc(col)) for col in df.columns for i in range(len(df[col][df[col]==1].index))] [(0, 0)] # массив туплов (row, col)
Вместо выражения df[col]==1 можно использовать функциональный эквивалент df[col].eq(1) — дело вкуса.
Как использовать NumPy, где() с несколькими условиями
Вы можете использовать следующие методы для использования функции NumPy where() с несколькими условиями:
Способ 1: используйте where() с ИЛИ
#select values less than five *or* greater than 20 x[np.where ((x < 5) | (x >20))]
Способ 2: используйте where() с AND
#select values greater than five *and* less than 20 x[np.where ((x > 5) & (x < 20))]
В следующем примере показано, как использовать каждый метод на практике.
Способ 1: используйте where() с ИЛИ
В следующем коде показано, как выбрать каждое значение в массиве NumPy, которое меньше 5 или больше 20:
import numpy as np #define NumPy array of values x = np.array([1, 3, 3, 6, 7, 9, 12, 13, 15, 18, 20, 22]) #select values that meet one of two conditions x[np.where ((x < 5) | (x >20))] array([ 1, 3, 3, 22])
Обратите внимание, что четыре значения в массиве NumPy были меньше 5 или больше 20.
Вы также можете использовать функцию размера , чтобы просто найти, сколько значений соответствует одному из условий:
#find number of values that are less than 5 or greater than 20 (x[np.where ((x < 5) | (x >20))]). size 4
Способ 2: используйте where() с AND
В следующем коде показано, как выбрать каждое значение в массиве NumPy, которое больше 5 и меньше 20:
import numpy as np #define NumPy array of values x = np.array([1, 3, 3, 6, 7, 9, 12, 13, 15, 18, 20, 22]) #select values that meet two conditions x[np.where ((x > 5) & (x < 20))] array([6, 7, 9, 12, 13, 15, 18])
Выходной массив показывает семь значений в исходном массиве NumPy, которые были больше 5 и меньше 20.
Еще раз, вы можете использовать функцию размера , чтобы найти, сколько значений удовлетворяет обоим условиям:
#find number of values that are greater than 5 and less than 20 (x[np.where ((x > 5) & (x < 20))]). size 7
Дополнительные ресурсы
В следующих руководствах объясняется, как выполнять другие распространенные операции в NumPy: