Основываясь на этом вопросе, мне удалось использовать метод запроса:
import pandas as pd
df = pd.DataFrame({"genre":[['comedy', 'sci-fi'], ['action', 'romance', 'comedy'], ['documentary'], ['crime','horror'], []]})
df.query("(genre.str.contains('comedy', na=False, regex=False))", engine = "python")
Теперь я хотел бы иметь запрос, возвращающий строки с пустым списком для жанра. я попробую
df.query("~(genre.str.contains('\\w*', na=False, regex=True))", engine = "python")
и многие другие варианты, но безуспешно…
IIUC, вы хотите вернуть строки, в которых список в столбце жанра пуст. Ты можешь сделать:
print(df)
genre
0 [comedy, sci-fi]
1 [action, romance, comedy]
2 [documentary]
3 [crime, horror]
4 []
out = df.loc[df['genre'].str.len() == 0]
print(out)
genre
4 []
Что это за колдовство? Есть ли какая-либо документация, почему str.len()
(с использованием аксессора .str
) будет рассматривать элементы серии как списки, а не строки?
Кстати, можешь пропустить .loc
: print(df[df.genre.str.len() == 0])
Если подумать, имеет смысл, если панды слепо вызывают len
на каждом объекте, очевидно, что и str
, и list
реализуют __len__
. Если это так, то к этому ответу следует относиться с недоверием, поскольку он может или не может сломаться в будущей версии pandas.
@DeepSpace См. Строковые методы: «... методы, которые упрощают работу с каждым элементом массива». Обратите внимание, что здесь не написано «каждая строка». Затем позже: «Предупреждение: вообще говоря, метод доступа .str
предназначен для работы только со строками. За очень немногими исключениями, другие варианты использования не поддерживаются и могут быть отключены позже».
@wjandrea Это именно моя точка зрения. Спасибо, что отвез его домой :)
Спасибо, но, как уже упоминалось, мне бы хотелось query
, чтобы поиграть с различными фильтрами.
Вы можете использовать pandas взорвать, проверить, какая строка имеет значение na, и после этого использовать groupby Any, чтобы воссоздать исходный индекс.
m = df['genre'].explode().isna().groupby(level=0).any()
print(df[m])
Другой пример с использованием вашего условия:
m = (df['genre'].explode()
.str.contains('\\w*', na=False, regex=True)
.groupby(level=0).any()
)
print(df[~m])
Результат:
genre
4 []
Спасибо, но, как уже упоминалось, мне бы хотелось query
, чтобы поиграть с различными фильтрами.
Вы можете фильтровать, используя тот же код. Я отредактирую, чтобы использовать то же условие
Вы можете использовать apply
для фильтрации кадра данных:
# option 1
df[df["genre"].apply(len) == 0]
# option 2
df[df["genre"].apply(lambda x: len(x) == 0)]
Вы можете сделать нечто подобное, используя query
, ссылаясь на встроенную функцию len
с локальной переменной и @
:
len = len
df.query("genre.apply(@len) == 0")
Все печати:
genre
4 []
Спасибо, но, как уже упоминалось, мне бы хотелось query
, чтобы поиграть с различными фильтрами.
@NBur Я обновил ответ возможным решением, используя query
.
Вы можете проверить .str.len()
:
df.query('genre.str.len() == 0')
Выход:
genre
4 []
Вы можете использовать ==
, но для списка операция преобразуется в .isin
, поэтому удвойте скобки:
>>> df.query('genre == [[]]')
genre
4 []
Действительно, эквивалентно df[df['genre'].isin([[]])]
.
Тем временем я успешно попробовал
df.query("genre.astype('str') == '[]'")
, но нахожу это уродливым хаком — преобразование в строку…