#python #pandas
Вопрос:
Мне интересно, как убедиться, что все строки во фрейме данных содержат определенный набор значений.
Например:
VALUES = [1, 2]
df_no = pd.DataFrame(
{
"a": [1],
"b": [1],
}
)
df_yes = pd.DataFrame(
{
"a": [1],
"b": [2],
"c": [3],
}
)
Здесь df_no
не содержатся значения VALUES
в каждой из его строк, в то df_yes
время как это так.
Подход заключается в следующем:
# check df_no
all(
[
all(value in row for value in VALUES)
for row in df_no.apply(lambda x: x.unique(), axis=1)
]
)
# returns False
# check df_yes
all(
[
all(value in row for value in VALUES)
for row in df_yes.apply(lambda x: x.unique(), axis=1)
]
)
# returns True
Я чувствую, что подходы здесь могут быть настолько ясными, и что может быть более идиоматический способ действий.
Ответ №1:
Использование issubset
в понимании генератора:
s = set(VALUES)
print (all(s.issubset(x) for x in df_no.to_numpy()))
False
s = set(VALUES)
print (all(s.issubset(x) for x in df_yes.to_numpy()))
True
Что быстрее? Зависит от данных:
VALUES = [1, 2]
df = pd.DataFrame(
{
"a": [1,2,8],
"b": [2,8,2],
"c": [3,1,1],
}
)
#30k rows
df = pd.concat([df] * 10000, ignore_index=True)
print (df)
In [171]: %%timeit
...: s = set(VALUES)
...: all(s.issubset(x) for x in df.to_numpy())
...:
...:
55.9 ms ± 2.77 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [172]: %%timeit
...: vals = set(VALUES)
...: df.apply(vals.issubset, axis=1).all()
...:
...:
211 ms ± 1.38 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
#3k rows
df = pd.concat([df] * 1000, ignore_index=True)
print (df)
In [174]: %%timeit
...: s = set(VALUES)
...: all(s.issubset(x) for x in df.to_numpy())
...:
...:
5.46 ms ± 76.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [175]: %%timeit
...: vals = set(VALUES)
...: df.apply(vals.issubset, axis=1).all()
...:
...:
21.5 ms ± 107 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Комментарии:
1. @baxx — Это неправильный ответ 🙁 Работает над правильным.
2. @baxx — Он не тестировал каждую строку отдельно. Он проверил все данные вместе
3. ах, конечно, да, важно, чтобы это была каждая строка
4. предпочтительнее ли применять list comp? Я не уверен, есть ли какие-либо оптимизации (или медлительность) с применением, о которых я не знаю
5. теперь это более или менее похоже на мой ответ 🙁
Ответ №2:
Вы можете использовать наборы python и issubset
:
vals = set(VALUES)
df_yes.apply(lambda x: vals.issubset(set(x)), axis=1).all()
более короткая версия:
vals = set(VALUES)
df_yes.apply(vals.issubset, axis=1).all()