Как изменять значение в ячейке с использованием значения из другого 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 шт):

Автор решения: MaxU

Сначала дадим имена столбцам фреймов:

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
→ Ссылка
Автор решения: MaxU

Если второй фрейм достаточно маленький, то можно из него создать регулярное выражение для поиска:

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
→ Ссылка