【问题标题】:Replace comma-separated values in a dataframe with values from another dataframe将数据框中的逗号分隔值替换为另一个数据框中的值
【发布时间】:2020-04-24 06:53:25
【问题描述】:

这是我在 StackOverflow 上的第一个问题,如果我不够清楚,请见谅。我通常在这里找到我的答案,但这次我没有运气。也许我太密集了,但我们开始吧。

我有两个 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)   |
+--------+--------------+

基本上,df2 中的 Ref_ID 包含构成 df1References 字段中包含的字符串的 ID /p>

我想做的是替换 df1References 字段中的值,使其看起来像这样:

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

到目前为止,我必须处理具有 1-1 关系的列和 ID,这非常有效 Pandas - Replacing Values by Looking Up in an Another Dataframe

但我无法解决这个略有不同的问题。我能想到的唯一解决方案是重新迭代一个 for 和 if 循环,将 df1 的每个字符串与 df2 进行比较并进行替换。

恐怕这会很慢,因为我有 ca。 2000 个唯一的 Ref_ID,我必须在类似于 References 的几列中重复此操作。

有人愿意为我指明正确的方向吗?

非常感谢。

【问题讨论】:

  • 编辑:感谢您的提示,我正在尝试。我现在正在努力解决的一件事是“参考”中的某些单元格是空的。

标签: python python-3.x pandas python-2.7 dataframe


【解决方案1】:

让我们试试这个:

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)

【讨论】:

  • 一个陷阱...正在检查 df1 Reference 和 df2 Reference 之间的 dtypes。
  • 似乎没有 OP 想要 [...] 围绕引用,有没有办法摆脱它?
  • df['Reference2'] = df["References"].str.split(",").explode().astype(int).map( df2.set_index("Ref_ID")["ShortRef"] ).groupby(level=0).agg(';'.join) 我想整理一下 dtypes ;)
  • 此解决方案完美运行!非常感谢您,我将在我的代码中添加到此页面的 pingback。
  • 实施该解决方案后,我注意到在某些情况下值放错了位置。例如。在上述情况下,我不仅找到了与参考 ID 3 相关的“John (2014)”,还找到了“Smith (2006)”。但这仅发生在特定记录中,例如参考 ID = 3 的其他行可以替换。奇怪的行为...
【解决方案2】:

你可以使用一些列表理解和字典查找,我认为这不会太慢

首先,为 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])

这个有用还是太慢了?

【讨论】:

  • 这很好,但您可以使用explodestr.split 来减少代码行数。
  • 如果速度是一个问题,这可能会更快
【解决方案3】:

另一种解决方案是使用str.get_dummiesdot

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)

【讨论】:

  • 这个也可以,我上面提到的错误也不会出现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-09
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多