Pandas — сопоставление значений из столбца в одном фрейме данных с несколькими столбцами в другом фрейме данных и создание новых столбцов из исходного фрейма данных

#python #pandas

#python #pandas

Вопрос:

У меня есть два фрейма данных, которые нельзя объединить ни по каким значениям, но в первом фрейме данных есть столбец значений ( dfA ), который может совпадать или не совпадать со значениями в нескольких столбцах второго фрейма данных ( dfB ). Столбец ‘text_bod’ содержит особенно большие значения со средней длиной строки ~ 1500 символов.

В столбцах value1 и value2 в dfB не всегда записывается значение, даже если значение существует, но если значение существует, оно почти всегда будет найдено где-то в тексте text_bod столбца. Я пытаюсь выяснить, dfA существуют ли в dfB значения в.

Если значение из dfA существует в dfB , я хочу добавить некоторую информацию из dfA в новые столбцы в фрейме данных, где найдено значение. Например, ниже я хочу добавить столбцы ‘name’, ‘color’ и ‘animal’ в dfB , а затем добавить соответствующие имена, цвета и животных для найденных значений.

Это то, что я придумал до сих пор:

 def extract(t):
    s = ('|').join(dfA['value'])
    return re.search(s, t)

tqdm.pandas()

dfB['value'] = dfB['text_bod'].progress_map(extract)
  

Я хотел бы услышать любые предложения о том, как 1) оптимизировать этот поиск и 2) добавить информацию, соответствующую значениям, в новые столбцы в dfB .

dfA (~ 200 000 строк)

     value   name     color         animal
0  es9bum  name1       red        dolphin
1    qgl8  name2  cerulean   mountaingoat
2   klkwv  name3  platinum   mantisshrimp
3   tokgs  name4   fuchsia      tarantula
4 cnwsaq5  name5     frost  gentoopenguin   
  

dfB (~ 1 500 000 строк)

    value1 value2              text_bod           
0    null  tokgs   here are some tokgs        
1    null   null      something es9bum 
2   klkwv   null     blahblahblahklkwv 
3    null   null    boop: qgl8. moreamp;amp; 
4    null   null              hi it me
5    null   null   here are more words           
6   y2kbc   null       words and stuff
7    null   null          so much text
8    null   null   have a nice cnwsaq5 
9    null   null                  null
  

Это то, что я хотел бы вывести:

dfB (~ 1 500 000 строк)

    value1 value2              text_bod    name    color        animal         
0    null  tokgs   here are some tokgs   name4  fuchsia     tarantula
1    null   null      something es9bum   name1      red       dolphin
2   klkwv   null     blahblahblahklkwv   name3 platinum  mantisshrimp
3    null   null    boop: qgl8. moreamp;amp;   name2 cerulean  mountaingoat
4    null   null              hi it me     NaN      NaN           NaN
5    null   null   here are more words     NaN      NaN           NaN 
6   y2kbc   null       words and stuff  name99     onyx      direwolf
7    null   null          so much text     NaN      NaN           NaN
8    null   null   have a nice cnwsaq5   name5    frost gentoopenguin
9    null   null                  null     NaN      NaN           NaN
  

Ответ №1:

Мы можем использовать str.extract для поиска слов в вашем text_bod столбце и извлечения их. После этого мы используем эти извлеченные слова as key to merge df1 с dfA , чтобы собрать нужные столбцы вместе.

 s = ('|').join(dfA['value'])

df1['value'] = df1['text_bod'].str.extract('({})'.format(s))

df1 = df1.merge(dfA, on='value', how='left').drop('value', axis=1)

print(df1)
  value1 value2             text_bod   name     color        animal
0    NaN  tokgs  here are some tokgs  name4   fuchsia     tarantula
1    NaN    NaN     something es9bum  name1       red       dolphin
2  klkwv    NaN    blahblahblahklkwv  name3  platinum  mantisshrimp
3    NaN    NaN   boop: qgl8. moreamp;amp;  name2  cerulean  mountaingoat
4    NaN    NaN             hi it me    NaN       NaN           NaN
  

Если у вас Python версии 3.6 или выше
Мы можем использовать f-strings в третьей строке, что делает наш код немного чище:

 df1['value'] = df1['text_bod'].str.extract(f'({s})')
  

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

1. Спасибо Erfan! Я собираюсь попробовать это. Выполнение второй строки займет действительно много времени. Чтобы проверить ход выполнения кода, сработает ли использование счетчика в цикле for ( for idx in range(cases['communication_body'].size ) или вы знаете способ получше?