фрейм данных pandas: замена (автономной) подстроки в ячейке на основе dict

#python #regex #pandas #dictionary

#питон #регулярное выражение #панды #словарь #python #pandas

Вопрос:

Мне интересно, мог бы кто-нибудь в сообществе помочь со следующим:

Стремитесь к замене подстрок регулярным выражением в фрейме данных pandas (на основе словаря, который я передаю в качестве аргумента). Хотя замена ключа: значения должна выполняться только в том случае, если ключ dict найден как отдельная подстрока (не как часть слова). Под автономной подстрокой я подразумеваю, что она начинается после пробела

e.x:

 mapping = {

   "sweatshirt":"sweat_shirt",
   "sweat shirt":"sweat_shirt",
   "shirt":"shirts"

}

df = pd.DataFrame([
         ["men sweatshirt"]
         ["men sweat shirt"]
         ["yellow shirt"]
       ])

df = df.replace(mapping,regex=True)

  

ожидаемый результат:
подстрока «рубашка» в свитшоте НЕ должна заменяться на «рубашки», поскольку значение является частью другой строки, не являющейся автономным значением ( b)

ПРИМЕЧАНИЕ: словарь, который я передаю, довольно длинный, поэтому в идеале есть способ передать автономное требование ( b) как часть dict, на который я передаю df.replace(dict, regex=True)

Заранее спасибо

Комментарии:

1. Помимо включения пробелов в сопоставление используйте df = df.apply(лямбда x: ‘ ‘ x, ось =1).заменить (сопоставление, регулярное выражение = True).ID.str.strip()

Ответ №1:

Вы можете использовать

 df[0].str.replace(fr"b(?:{'|'.join([x for x in mapping])})b", lambda x: mapping[x.group()])
  

Регулярное выражение будет выглядеть как b(?:sweatshirt|shirt)b , оно будет соответствовать sweatshirt или shirt как целые слова. Совпадение будет передано в лямбда-выражение, и соответствующее значение будет извлечено с помощью mapping[x.group()] .

Обновление условия поиска из нескольких слов

Поскольку у вас могут быть многословные термины для поиска в mapping ключах, вы должны убедиться, что самые длинные условия поиска идут первыми в группе чередования. То есть, b(?:abc def|abc)b и не b(?:abc|abc def)b .

 import pandas as pd

mapping = {
   "sweat shirt": "sweat_shirt",
   "shirt": "shirts"
}

df = pd.DataFrame([
         ["men sweatshirt"],
         ["men sweat shirt"]
       ])
rx = fr"b(?:{'|'.join(sorted([x for x in mapping],key=len,reverse=True))})b"
df[0].str.replace(rx, lambda x: mapping[x.group()])
  

Вывод:

 0     men sweatshirt
1    men sweat_shirt
Name: 0, dtype: object
  

Комментарии:

1. интересно, учитывает ли ваш приведенный выше код также подстроки, которые находятся в самом начале значения ячейки, например, ^ рубашка 123? Спасибо

2. @Mirko Да, b , когда за ним следует символ «word» (цифра, буква или _ ), также совпадает в начале строки.

3. есть последний вопрос (извините, что беспокою Виктора). было несколько крайних случаев, когда repl. не работал. придерживаться ex. Я дал в первоначальном сообщении. допустим, идентификатор имеет df со значением men sweat shirt и следующим отображением "sweat shirt: "sweat_shirt", "shirt": "shirts" . Я не уверен, действительно ли вступят в силу key1: value1 или key2: value2. кажется, в 9/10 случаях key1:value1 заменяется, но не всегда. вы можете определить, обрабатывается ли dict, используемый в сопоставлении, сверху вниз, чтобы я мог добавить эти ключи с пробелом перед этими ключами без? есть другие идеи?

Ответ №2:

Включите пробел в свой шаблон! 🙂

 mapping = {

   " sweatshirt":" sweat_shirt",
   " shirt":" shirts"

}

df = ([
         ["men sweatshirt"]
       ])

df = df.replace(mapping,regex=True)
  

Комментарии:

1. Это не заменит строку, если строка для замены находится в начале.

Ответ №3:

Попробуйте этот код-

 mapping = {

   " sweatshirt":" sweat_shirt",
   " shirt":" shirts"
}

import pandas as pd
df = pd.DataFrame ({'ID':["men sweatshirt", "black shirt"]}
       )

df = df.apply(lambda x: ' ' x, axis=1).replace(mapping,regex=True).ID.str.strip()
print(df)