Логическое ИЛИ для подмножества столбцов в 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
Другие вопросы по тегам