繁体   English   中英

如何合并字符串包含的熊猫?

[英]How to merge pandas on string contains?

我有 2 个数据框,我想在一个公共列上合并。 但是,我要合并的列不是同一个字符串,而是一个字符串包含在另一个字符串中,如下所示:

import pandas as pd
df1 = pd.DataFrame({'column_a':['John','Michael','Dan','George', 'Adam'], 'column_common':['code','other','ome','no match','word']})

df2 = pd.DataFrame({'column_b':['Smith','Cohen','Moore','K', 'Faber'], 'column_common':['some string','other string','some code','this code','word']})

我想从d1.merge(d2, ...)得到的结果如下:

column_a  |  column_b
----------------------
John      |  Moore    <- merged on 'code' contained in 'some code' 
Michael   |  Cohen    <- merged on 'other' contained in 'other string'  
Dan       |  Smith    <- merged on 'ome' contained in 'some string'  
George    |  n/a
Adam      |  Faber    <- merged on 'word' contained in 'word'  

新答案

这是一种基于 pandas/numpy 的方法。

rhs = (df1.column_common
          .apply(lambda x: df2[df2.column_common.str.find(x).ge(0)]['column_b'])
          .bfill(axis=1)
          .iloc[:, 0])

(pd.concat([df1.column_a, rhs], axis=1, ignore_index=True)
 .rename(columns={0: 'column_a', 1: 'column_b'}))

  column_a column_b
0     John    Moore
1  Michael    Cohen
2      Dan    Smith
3   George      NaN
4     Adam    Faber

旧答案

这是左连接行为的解决方案,因为它不会保留与任何column_b值不匹配的column_a值。 这比上面的 numpy/pandas 解决方案要慢,因为它使用两个嵌套的iterrows循环来构建一个 python 列表。

tups = [(a1, a2) for i, (a1, b1) in df1.iterrows() 
                 for j, (a2, b2) in df2.iterrows()
        if b1 in b2]

(pd.DataFrame(tups, columns=['column_a', 'column_b'])
   .drop_duplicates('column_a')
   .reset_index(drop=True))

  column_a column_b
0     John    Moore
1  Michael    Cohen
2      Dan    Smith
3     Adam    Faber

我的解决方案涉及将函数应用于公共列。 我无法想象当 df2 很大时它会保持良好状态,但也许有人比我建议改进的知识更丰富。

def strmerge(strcolumn):
    for i in df2['column_common']:
        if strcolumn in i:
            return df2[df2['column_common'] == i]['column_b'].values[0]

df1['column_b'] = df1['column_common'].apply(strmerge)

df1
    column_a    column_common   column_b
0   John        code            Moore
1   Michael     other           Cohen
2   Dan         ome             Smith
3   George      no match        None
4   Adam        word            Faber

一种简单、可读且纯矢量化的方法可能是进行cross连接,然后过滤其中一个列的column_common是另一个的子字符串:

df = df1.merge(df2, how='cross')
df.loc[df.column_common_x.eq('no match'),'column_b'] = pd.NA
df.loc[df.apply(lambda x:x.column_common_y.__contains__(x.column_common_x) or x.column_common_x == 'no match', axis=1), 
       ['column_a', 'column_b']].drop_duplicates(subset=['column_a'])

输出:

column_a column_b
约翰 摩尔
迈克尔 科恩
史密斯
乔治
亚当 费伯

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM