Логическое ИЛИ для подмножества столбцов в DataFrame
Я хочу получить все строки, где (по крайней мере) один из столбцов в df[mylist] содержит True.
В настоящее время я делаю:
df = df[ df[mylist[0]] | df[mylist[1]] | df[mylist[2]] ]
где mylist
это список строк, относящихся к столбцам df
, Но я хотел бы сделать это для любой длины mylist
,
Единственный способ, которым я могу придумать, это зациклить mylist
и создайте новый фрейм данных для каждого его элемента и объедините /concat или что-то еще после них. Но это не выглядит очень умным для меня.
Есть ли способ лучше?
2 ответа
Опираясь на ответ LondonRob, вы можете использовать
df.loc[df[mylist].any(axis=1)]
Вызов DataFrame any
метод будет работать лучше, чем при использовании apply
вызвать Python встроенный any
функция один раз в строке.
Или вы могли бы использовать np.logical_or.reduce
:
df.loc[np.logical_or.reduce(df[mylist], axis=1)]
Для больших DataFrames, используя np.logical_or
может быть быстрее:
In [30]: df = pd.DataFrame(np.random.binomial(1, 0.1, size=(100,300)).astype(bool))
In [31]: %timeit df.loc[np.logical_or.reduce(df, axis=1)]
1000 loops, best of 3: 261 µs per loop
In [32]: %timeit df.loc[df.any(axis=1)]
1000 loops, best of 3: 636 µs per loop
In [33]: %timeit df[df.apply(any, axis=1)]
100 loops, best of 3: 2.13 ms per loop
Обратите внимание, что df.any
имеет дополнительные функции, такие как возможность пропустить NaNs. В этом случае, если столбцы имеют логическое значение, тогда не может быть никаких NaN (поскольку NaN являются значениями с плавающей запятой). Так np.logical_or.reduce
быстрее
import numpy as np
import pandas as pd
np.random.seed(2014)
df = pd.DataFrame(np.random.binomial(1, 0.1, size=(10,3)).astype(bool),
columns=list('ABC'))
print(df)
# A B C
# 0 False False False
# 1 True False False
# 2 False False False
# 3 True False False
# 4 False False False
# 5 False False False
# 6 False True False
# 7 False False False
# 8 False False False
# 9 False False False
mylist = list('ABC')
print(df[ df[mylist[0]] | df[mylist[1]] | df[mylist[2]] ])
print(df.loc[df[mylist].any(axis=1)])
print(df.loc[np.logical_or.reduce(df[mylist], axis=1)])
возвращает строки, где хотя бы один из столбцов равен True:
A B C
1 True False False
3 True False False
6 False True False
Существует гораздо более простой способ сделать это с помощью встроенного в Python any
функция:
In []: mylist
Out[]: ['A', 'B']
In []: df
Out[]:
A B C
0 False False False
1 True False False
2 False False False
3 True False False
4 False False False
5 False False False
6 False True False
7 False False False
8 False False False
9 False False False
Вы можете apply
функция any
вдоль рядов df
используя axis=1
, В этом случае я буду применять только any
к подмножеству столбцов:
In []: df[mylist].apply(any, axis=1)
Out[]:
0 False
1 True
2 False
3 True
4 False
5 False
6 True
7 False
8 False
9 False
dtype: bool
Это дает нам идеальный способ выбора наших строк:
In []: df[df[mylist].apply(any, axis=1)]
Out[]:
A B C
1 True False False
3 True False False
6 False True False