Как изменять значение в ячейке с использованием значения из другого DataFrame как регулярного выражения?
У меня есть 2 DataFrame.
df1 - это таблица фактов:
Луговая ТЦ (25 ВЛД) Джинсы Черный 99
Луговая ТЦ (25 ВЛД) Свитер Голубой 48
8 Марта (66 ЕКБ) Джинсы Черный None
8 Марта (66 ЕКБ) Юбка Белый 34
8 Марта 66 ЕКБ Юбка черный 34
Москва 77 Жакет белый 45
Алтуфьево ТЦ (77 МСК) Свитер красный 7
Алтуфьево ТЦ (77 МСК) Джинсы синий 87
Екатеринбург 66 Юбка зеленый 10
Луговая ТЦ 25 ВЛД Свитер Голубой 48
Санкт-Петербург 78 Свитер красный 7
Мегамол 59 ПРМ Свитер белый 4
Пермь 59 Юбка зеленый 8
df2 - второй DataFrame - справочные данные:
77 МСК Москва 77
50 Мытищи Москва 77
78 СПб Санкт-Петербург 78
25 ВЛД Владивосток 25
66 ЕКБ Екатеринбург 66
23 КРД Краснодар 23
Мне надо сделать так, чтобы осуществлялась проверка:
Если значения в 1-ом столбце df1 != значению во 2-м столбце df2, то нужно найти какое из значений 1-го столбца df2 содержится в 1-м столбце df1. Затем полностью заменить значение ячейки в 1-м столбце df1 на соответствующее значение 2-го столбца df2.
Если значения в 1-ом столбце df1 = значению 2-м столбце df2, то пропустить.
Результат в df1 должен быть следующий:
Владивосток 25 Джинсы Черный 99
Владивосток 25 Свитер Голубой 48
Екатеринбург 66 Джинсы Черный None
Екатеринбург 66 Юбка Белый 34
Екатеринбург 66 Юбка черный 34
Москва 77 Жакет белый 45
Москва 77 Свитер красный 7
Москва 77 Джинсы синий 87
Екатеринбург 66 Юбка зеленый 10
Владивосток 25 Свитер Голубой 48
Санкт-Петербург 78 Свитер красный 7
NaN Свитер белый 4
NaN Юбка зеленый 8
Можно ли как-то сделать, чтобы значения из df2 использовались, как регулярное выражение?
Может эту операцию вообще лучше в openpyxl сделать?
PS Работаю с pandas 1.0.3, python 3.8.
Ответы (2 шт):
Сначала дадим имена столбцам фреймов:
df1.columns = ["mix_addr", "name", "color", "val"]
df2.columns = ["code", "addr"]
решение:
res = (df1
.assign(code=df1["mix_addr"].str.extract(r"\(([^)]*)\)"))
.merge(df2, how="left"))
результат:
In [21]: res
Out[21]:
mix_addr name color val code addr
0 Луговая ТЦ (25 ВЛД) Джинсы Черный 99 25 ВЛД Владивосток 25
1 Луговая ТЦ (25 ВЛД) Свитер Голубой 48 25 ВЛД Владивосток 25
2 8 Марта (66 ЕКБ) Джинсы Черный None 66 ЕКБ Екатеринбург 66
3 8 Марта (66 ЕКБ) Юбка Макси 34 66 ЕКБ Екатеринбург 66
4 Алтуфьево ТЦ (77 МСК) Свитер красный 7 77 МСК Москва 77
5 Алтуфьево ТЦ (77 МСК) Джинсы синий 87 77 МСК Москва 77
Если второй фрейм достаточно маленький, то можно из него создать регулярное выражение для поиска:
mask = df1["mix_addr"].isin(df2["addr"])
pat = r"\b({})\b".format(df2["code"].str.cat(sep="|"))
df1["new"] = df1["mix_addr"].str.extract(pat)[0].map(df2.set_index("code")["addr"])
df1.loc[mask, "new"] = df1.loc[mask, "mix_addr"]
регулярное выражение для вычленения кодов:
In [98]: pat
Out[98]: '\\b(77 МСК|50 Мытищи|78 СПб|25 ВЛД|66 ЕКБ|23 КРД)\\b'
результат:
In [96]: df1
Out[96]:
mix_addr name color val new
0 Луговая ТЦ (25 ВЛД) Джинсы Черный 99 Владивосток 25
1 Луговая ТЦ (25 ВЛД) Свитер Голубой 48 Владивосток 25
2 8 Марта (66 ЕКБ) Джинсы Черный None Екатеринбург 66
3 8 Марта (66 ЕКБ) Юбка Белый 34 Екатеринбург 66
4 8 Марта 66 ЕКБ Юбка черный 34 Екатеринбург 66
5 Москва 77 Жакет белый 45 Москва 77
6 Алтуфьево ТЦ (77 МСК) Свитер красный 7 Москва 77
7 Алтуфьево ТЦ (77 МСК) Джинсы синий 87 Москва 77
8 Екатеринбург 66 Юбка зеленый 10 Екатеринбург 66
9 Луговая ТЦ 25 ВЛД Свитер Голубой 48 Владивосток 25
10 Санкт-Петербург 78 Свитер красный 7 Санкт-Петербург 78
11 Мегамол 59 ПРМ Свитер белый 4 NaN
12 Пермь 59 Юбка зеленый 8 NaN