Как фильтровать DataFrame Pandas с помощью 'in' и 'not in', как в SQL
Как мне добиться эквивалентов SQL-запросов IN
и NOT IN
в Pandas?
У меня есть список с необходимыми значениями. Вот сценарий:
df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']})
countries_to_keep = ['UK', 'China']
псевдокод:
df[df['country'] not in countries_to_keep]
Мой текущий способ выполнения этого выглядит следующим образом:
df = pd.DataFrame({'country': ['US', 'UK', 'Germany', 'China']})
df2 = pd.DataFrame({'country': ['UK', 'China'], 'matched': True})
IN
df.merge(df2, how='inner', on='country')
NOT IN
not_in = df.merge(df2, how='left', on='country')
not_in = not_in[pd.isnull(not_in['matched'])]
Но это кажется ужасным обходным решением. Можете ли вы предложить улучшение?
5 ответ(ов)
Вам нужно фильтровать строки в DataFrame, используя условие, при котором значение в столбце 'countries' отсутствует в перечисленных странах. Ваш код уже почти правильный, однако можно немного улучшить его для более понятного выполнения. Вы можете использовать метод .isin()
для этого, чтобы сделать код более лаконичным. Вот как это можно реализовать:
not_in = df[~df['countries'].isin(countries)]
Здесь ~
- это оператор логического отрицания, который будет исключать строки, где значения в столбце 'countries' присутствуют в списке countries
. Таким образом, вы получите DataFrame not_in
, который будет содержать только те строки, где значение 'countries' не входит в указанный список.
Для решения задачи по фильтрации данных в pandas:
Для фильтрации с использованием IN:
df[df['A'].isin([3, 6])]
Для фильтрации с использованием NOT IN можно использовать несколько подходов:
Использовать отрицание с помощью минуса:
df[-df["A"].isin([3, 6])]
Использовать оператор ~ (логическое отрицание):
df[~df["A"].isin([3, 6])]
Использовать сравнение с False:
df[df["A"].isin([3, 6]) == False]
Использовать функцию
np.logical_not
из библиотеки NumPy:df[np.logical_not(df["A"].isin([3, 6]))]
Эти методы позволят вам эффективно отфильтровать данные в вашем DataFrame в зависимости от необходимости включения или исключения определенных значений.
На вопрос о том, почему никто не обсуждает производительность различных методов фильтрации данных, следует отметить, что эта тема действительно часто поднимается на форумах, включая StackOverflow. Я провел собственные тесты производительности на большом наборе данных, и результаты получились довольно интересными и познавательными.
Я создал DataFrame с 10 миллионами записей, где один столбец содержит животных, а другой — случайно сгенерированные числа. Ниже приведены результаты тестов производительности для различных методов фильтрации по одному столбцу:
Метод
.isin()
:%%timeit conditions = ['cat', 'dog'] df[df.animals.isin(conditions)]
367 ms ± 2.34 ms на цикл (среднее ± стандартное отклонение из 7 запусков)
Метод
.query()
:%%timeit conditions = ['cat', 'dog'] df.query('animals in @conditions')
395 ms ± 3.9 ms на цикл
Метод
.loc[]
:%%timeit df.loc[(df.animals=='cat')|(df.animals=='dog')]
987 ms ± 5.17 ms на цикл
Метод с использованием
apply()
:%%timeit df[df.apply(lambda x: x['animals'] in ['cat', 'dog'], axis=1)]
41.9 s ± 490 ms на цикл
Создание индекса и фильтрация:
%%timeit new_df = df.set_index('animals') new_df.loc[['cat', 'dog'], :]
3.64 s ± 62.5 ms на цикл
Индекс и метод
.isin()
:%%timeit new_df = df.set_index('animals') new_df[new_df.index.isin(['cat', 'dog'])]
469 ms ± 8.98 ms на цикл
Слияние через
merge()
:%%timeit s = pd.Series(['cat', 'dog'], name='animals') df.merge(s, on='animals', how='inner')
796 ms ± 30.9 ms на цикл
Таким образом, метод isin
оказался самым быстрым, тогда как использование apply()
продемонстрировало наименьшую производительность, что не вызывает удивления. Эти результаты подчеркивают важность выбора правильного метода в зависимости от задач и объема данных, что может существенно повлиять на производительность вашей работы с DataFrame.
Чтобы отфильтровать строки в DataFrame dfbc
, у которых значение столбца BUSINESS_ID
также присутствует в столбце BUSINESS_ID
DataFrame dfProfilesBusIds
, вы можете использовать метод isin()
в сочетании с отрицательной индексацией. Ваш код выглядит верно:
dfbc = dfbc[~dfbc['BUSINESS_ID'].isin(dfProfilesBusIds['BUSINESS_ID'])]
Таким образом, ~
(логическое "НЕ") используется для исключения всех строк из dfbc
, где BUSINESS_ID
также содержится в dfProfilesBusIds
. Это позволит вам оставить только те строки, которые не имеют соответствующих идентификаторов в другом DataFrame. Если у вас возникнут дополнительные вопросы или понадобится помощь с другим кодом, не стесняйтесь спрашивать!
Для того чтобы отфильтровать строки в DataFrame, которые содержат только определённые страны, вы можете использовать метод isin()
. В представленном вами коде, например, вы можете извлечь строки для стран, входящих в список countries
:
import pandas as pd
df = pd.DataFrame({'countries': ['US', 'UK', 'Germany', 'China']})
countries = ['UK', 'China']
# Фильтр для стран, входящих в список
result_in = df[df.countries.isin(countries)]
print(result_in)
Это вернёт строки с 'UK' и 'China'.
Чтобы отфильтровать все строки, которые содержат страны, не указанные в списке countries
, вы можете использовать следующий код. Он создает новый список стран, не входящих в countries
, а затем применяет фильтр:
import numpy as np
# Фильтр для стран, которые не входят в список
result_not_in = df[df.countries.isin([x for x in np.unique(df.countries) if x not in countries])]
print(result_not_in)
Этот код вернёт строки с 'US' и 'Germany'.
Таким образом, вы можете легко использовать isin()
для фильтрации значений в DataFrame как для включения, так и для исключения определенных значений.
Неоднозначное значение истинности Series. Используйте a.empty, a.bool(), a.item(), a.any() или a.all()
Переименование названий столбцов в Pandas
"Красивая печать всей Series / DataFrame в Pandas"
Преобразование списка словарей в DataFrame pandas
Объединение двух столбцов текста в DataFrame pandas