#python #regex #pandas #dataframe
Вопрос:
У меня есть два df с серией терминов, которые представляют эмоцию (например, гнев, счастье), и мне нужно перебрать все строки другого df в поисках строк, содержащих некоторые термины в серии, и обменять их значение на имя эмоции, которое представляет термин, или добавить другое значение (например, Нет), если ни один из терминов не соответствует одному из двух df.
Я попытаюсь объяснить это на приведенных ниже примерах:
# Two df2 with target terms:
anger = pd.DataFrame({'anger': ['Angry','Acerbic', 'Aggressive', 'Bitter', 'Fiery', 'Outraged', 'Rebellious', 'Snide']})
happiness= pd.DataFrame({'happiness':['Happy','Cheerful','Bright', 'Celebratory', 'Effervescent', 'Gleeful', 'Humorous',
'Irreverent', 'Rambunctious', 'Raucous', 'Rollicking', 'Silly', 'Sweet', 'Whimsical', 'Witty', 'Joyous']
})
Цель Df:
настроения |
---|
Агрессивный, Грамотный, Бунтарский, Веселый |
Шумный, Яркий, Едкий, Глупый |
Ожидаемый df:
настроения |
---|
Злости, Никакой, Злости, Никакой |
Нет, Счастье, Гнев, Счастье |
Есть ли какой-нибудь способ сделать это?
Комментарии:
1. Довольно грубый способ, который я могу придумать, — это создать функцию для замены данного слова (глупо) соответствующим чувством (гнев), а затем использовать df.apply для применения этой функции ко всем строкам (можно использовать .split()) для разделения каждой строки на несколько слов. Но я не уверен, насколько эффективно это было бы
Ответ №1:
Вы можете использовать replace
:
# Create patterns
anger_pat = fr"b({'|'.join(anger['anger'])})b"
happiness_pat = fr"b({'|'.join(happiness['happiness'])})b"
# Replace patterns
df['moods'] = df['moods'].replace({anger_pat: 'Anger',
happiness_pat: 'Happiness',
r'b(?!Anger|Happinessb)w ': 'None'},
regex=True)
Поскольку replace
функция выполняется последовательно, предыдущие замены уже сделаны. Итак, последний шаблон означает: «если слово не «Гнев» или «Счастье», замените его «Нет».
Выход:
>>> df
moods
0 Anger, None, Anger, None
1 None, Happiness, Anger, Happiness
>>> print(anger_pat)
b(Angry|Acerbic|Aggressive|Bitter|Fiery|Outraged|Rebellious|Snide)b
>>> print(happiness_pat)
b(Happy|Cheerful|Bright|Celebratory|Effervescent|Gleeful|Humorous|Irreverent|Rambunctious|Raucous|Rollicking|Silly|Sweet|Whimsical|Witty|Joyous)b
Ответ №2:
Вы можете anger
объединить / happiness
фреймы данных вместе, .explode
целевой df и .merge
их. Затем .groupby
они возвращаются:
x = (
pd.concat([anger.stack(), happiness.stack()])
.to_frame(name="moods")
.droplevel(0)
.reset_index()
)
df["moods"] = df["moods"].str.split(", ")
df = df.explode("moods").reset_index()
print(
df.merge(x, on="moods", how="left")
.fillna("None")
.groupby("index_x")["index_y"]
.agg(", ".join)
.reset_index(drop=True)
.to_frame(name="moods")
)
С принтами:
moods
0 anger, None, anger, None
1 None, happiness, anger, happiness