Замените разделенные запятыми значения в кадре данных значениями из другого кадра данных - PullRequest
3 голосов
/ 06 января 2020

это мой первый вопрос по StackOverflow, поэтому прошу прощения, если я не достаточно ясен. Я обычно нахожу здесь свои ответы, но на этот раз мне не повезло. Может быть, я плотный, но здесь у нас go.

У меня есть два pandas кадра данных, отформатированных следующим образом

df1

+------------+-------------+
| References | Description |
+------------+-------------+
| 1,2        | Descr 1     |
| 3          | Descr 2     |
| 2,3,5      | Descr 3     |
+------------+-------------+

df2

+--------+--------------+
| Ref_ID |   ShortRef   |
+--------+--------------+
|      1 | Smith (2006) |
|      2 | Mike (2009)  |
|      3 | John (2014)  |
|      4 | Cole (2007)  |
|      5 | Jill (2019)  |
|      6 | Tom (2007)   |
+--------+--------------+

В основном Ref_ID в df2 содержит идентификаторы, которые образуют строку, содержащуюся в поле Ссылки в df1

Я хотел бы заменить значения в поле References на df1 , чтобы оно выглядело так:

+-------------------------------------+-------------+
|             References              | Description |
+-------------------------------------+-------------+
| Smith (2006); Mike (2009)           | Descr 1     |
| John (2014)                         | Descr 2     |
| Mike (2009);John (2014);Jill (2019) | Descr 3     |
+-------------------------------------+-------------+

До сих пор мне приходилось иметь дело со столбцами и идентификаторами с отношением 1-1, и это прекрасно работает Pandas - Замена значений путем поиска в другом кадре данных

Но я не могу разобраться с этой немного другой проблемой. Единственное решение, о котором я могу подумать, - это повторить циклы for и if, которые сравнивают каждую строку df1 с df2 и производят замену.

Это будет, я боюсь, очень медленно, так как у меня ок. 2000 уникальных Ref_ID s, и я должен повторить эту операцию в нескольких столбцах, аналогичных References one.

Кто-нибудь желает указать мне правильное направление?

Заранее большое спасибо.

Ответы [ 3 ]

3 голосов
/ 06 января 2020

Вы можете использовать некоторое понимание списка и поиск в диктовке, и я не думаю, что это будет слишком медленно

Во-первых, сделаем быстрое отображение доступа к id для short_ref

mapping_dict = df2.set_index('Ref_ID')['ShortRef'].to_dict()

Затем, давайте разделим ссылки запятыми

df1_values = [v.split(',') for v in df1['References']]

Наконец, мы можем выполнить итерацию и выполнить поиск по словарю, прежде чем конкатенироваться обратно в строки

df1['References'] = pd.Series([';'.join([mapping_dict[v] for v in values]) for values in df1_values])

Это можно использовать или это слишком медленно?

2 голосов
/ 06 января 2020

Давайте попробуем это:

df1 = pd.DataFrame({'Reference':['1,2','3','1,3,5'], 'Description':['Descr 1', 'Descr 2', 'Descr 3']})
df2 = pd.DataFrame({'Ref_ID':[1,2,3,4,5,6], 'ShortRef':['Smith (2006)',
                                                       'Mike (2009)',
                                                       'John (2014)',
                                                       'Cole (2007)',
                                                       'Jill (2019)',
                                                       'Tom (2007)']})

df1['Reference2'] = (df1['Reference'].str.split(',')
                                     .explode()
                                     .map(df2.assign(Ref_ID=df2.Ref_ID.astype(str))
                                             .set_index('Ref_ID')['ShortRef'])
                                     .groupby(level=0).agg(list))

Вывод:

  Reference Description                                Reference2
0       1,2     Descr 1               [Smith (2006), Mike (2009)]
1         3     Descr 2                             [John (2014)]
2     1,3,5     Descr 3  [Smith (2006), John (2014), Jill (2019)]

@ Datanovice спасибо за обновление.

df1['Reference2'] = (df1['Reference'].str.split(',')
                                     .explode()
                                     .map(df2.assign(Ref_ID=df2.Ref_ID.astype(str))
                                             .set_index('Ref_ID')['ShortRef'])
                                     .groupby(level=0).agg(';'.join))

Вывод:

  Reference Description                            Reference2
0       1,2     Descr 1              Smith (2006);Mike (2009)
1         3     Descr 2                           John (2014)
2     1,3,5     Descr 3  Smith (2006);John (2014);Jill (2019)
0 голосов
/ 06 января 2020

Другое решение использует str.get_dummies и dot

df3 = (df1.set_index('Description').Reference.str.get_dummies(',')
          .reindex(columns=df2.Ref_ID.astype(str).values, fill_value=0))
df_final = (df3.dot(df2.ShortRef.values+';').str.strip(';').rename('References')
               .reset_index())

Out[462]:
  Description                           References
0     Descr 1             Smith (2006);Mike (2009)
1     Descr 2                          John (2014)
2     Descr 3  Mike (2009);John (2014);Jill (2019)
...