У меня есть df со столбцами product_id
и keyword
. Я повторяю идентификатор продукта для group_name, group in s.groupby('product_id')
, и на этом этапе я хочу сохранить группы, содержащие все элементы из списка поиска.
Например:
и мой список поиска = ['land', 'cruiser']
поэтому на выходе я хочу это:
я пробовал это
data[data["keywords"].isin(search_words)]
но этот метод сохраняет все группы, если он содержит хотя бы один элемент из списка, в то время как I группы должны содержать все элементы в списке поиска.
Если у вас есть приведенные ниже данные, хотите ли вы, чтобы группа 1 включала «сарай»? df = pd.DataFrame({"product_id": [1,1, 2, 3, 1, 2, 3], "keywords": ["land", "barn", "land", "land", "cruiser", "barn", "cruiser"]})
Для другого ответа (в одну строку!):
import pandas as pd
s = pd.DataFrame({'product_id': [1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 4],
'keywords': ["land", "cruiser", "land", "cruiser", "land",
"land", "land", "cruiser", "cruiser", "land", "cruiser"]})
search_words = ['land', 'cruiser']
s[[(all(p in x for p in search_words)) \
for x in s.merge(s.groupby("product_id").apply(
lambda x: list(set(x["keywords"]))).to_frame(). \
rename(columns = {0: "grouped"}), left_on = "product_id",
right_index=True)["grouped"]]]
#Out:
# product_id keywords
#0 1 land
#1 1 cruiser
#2 1 land
#3 1 cruiser
#4 1 land
#9 4 land
#10 4 cruiser
Я только что использовал pandas групповая фильтрация и понял, что было бы гораздо проще использовать это здесь. Возвращенный фрейм данных точно такой же, как и выше, но использует намного меньше кода!
s.groupby("product_id").filter(lambda x: all(p in list(set(x["keywords"])) for p in search_words))
Основная логика здесь взята из Ответ С. Роусона.
Вместо одной строки я создаю несколько вспомогательных переменных — я создаю ряд product_id и все связанные с ними условия поиска (product_keywords). Затем я делаю серию (хранителей) всех product_id, у которых есть все ключевые слова. Наконец, я использую метод isin(), чтобы проверить, есть ли в строках данных product_id в этом списке.
Это сохраняет все термины, которые находятся в группах, содержащих все искомые термины; поэтому, если в группе 1 есть «земля» и «крейсер», а также другие слова, это получает все термины.
df = pd.DataFrame({"product_id": [1,1, 2, 3, 1, 2, 3],
"keywords": ["land", "barn", "land", "land", "cruiser", "barn", "cruiser"]})
search_list = set(['land', 'cruiser'])
product_keywords = df.groupby("product_id").apply(lambda x: list(set(x["keywords"])))
product_keywords
# product_id
# 1 [barn, cruiser, land]
# 2 [barn, land]
# 3 [cruiser, land]
keepers = product_keywords[product_keywords.apply(lambda found_terms: all(search_term in found_terms for search_term in search_list))]
keepers
# product_id
# 1 [barn, cruiser, land]
# 3 [cruiser, land]
df.loc[df['product_id'].isin(keepers.index)]
# product_id keywords
# 0 1 land
# 1 1 barn
# 3 3 land
# 4 1 cruiser
# 6 3 cruiser
Конечно, легче следить за кодом, разбитым на части!
Я только что наткнулся на фильтрацию панд и сделал для этого гораздо меньшую и более простую строку кода в редактировании моего ответа (на случай, если вы сами с этим не сталкивались).
С. Роусон. Нет, я не знал, что вы можете фильтровать объект DataFrameGroupBy, спасибо. Интересно, «опускает» ли он фильтр и вообще избегает включения строк в группы. dir(df.groupby('product_id'))
также показывает много других атрибутов для изучения.
Ух ты! Это полезный кусок кода, спасибо!
Не могли бы вы включить свои данные в виде текста, чтобы мы могли их использовать?