【问题标题】:Pandas : if value in a dataframe contains string from another dataframe, append columnsPandas:如果数据框中的值包含来自另一个数据框的字符串,则追加列
【发布时间】:2017-03-10 04:12:04
【问题描述】:

假设我有两个数据框 df1 和 df2。 如果 df1 的特定列的值包含 df2 的特定列中的字符串,我想将 df2 的某些列附加到 df1,否则为 NaN。

一个小例子:

import pandas as pd
df1 = pd.DataFrame({'col': ['abc', 'def', 'abg', 'xyz']})
df2 = pd.DataFrame({'col1': ['ab', 'ef'], 'col2': ['match1', 'match2'], 'col3': [1, 2]})

df1:
   col
0  abc
1  def
2  abg
3  xyz

df2:

  col1    col2    col3
0   ab  match1       1
1   ef  match2       2

我想要:

   col   col2_match   col3_match
0  abc       match1            1
1  def       match2            2
2  abg       match1            1
3  xyz          NaN          NaN

我设法以一种肮脏且低效的方式做到了这一点,但在我的情况下,df1 包含大约 100K 行并且它需要永远......

提前致谢!

编辑

有点脏,但可以相对较快地完成工作(但我仍然认为存在最聪明的方法......):

import pandas as pd
import numpy as np


df1 = pd.DataFrame({'col': ['abc', 'def', 'abg']})
df2 = pd.DataFrame({'col1': ['ab', 'ef'],
                    'col2': ['match1', 'match2'],
                    'col3': [1, 2]})


def return_nan(tup):
    return(np.nan if len(tup[0]) == 0 else tup[0][0])


def get_indexes_match(l1, l2):
    return([return_nan(np.where([x in e for x in l2])) for e in l1])


def merge(df1, df2, left_on, right_on):
    df1.loc[:, 'idx'] = get_indexes_match(df1[left_on].values,
                                          df2[right_on].values)
    df2.loc[:, 'idx'] = np.arange(len(df2))
    return(pd.merge(df1, df2, how='left', on='idx'))


merge(df1, df2, left_on='col', right_on='col1')

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    你可以像这样使用 python difflib 模块进行模糊匹配

    import difflib 
    difflib.get_close_matches
    df1.col = df1.col.map(lambda x: difflib.get_close_matches(x, df2.col1)[0])
    

    所以现在你的 df1 是

        col
    0   ab
    1   ef
    2   ab
    

    如果您希望保持 df1 不变,可以将其命名为 df3。

    现在可以合并了

    merged = df1.merge(df2, left_on = 'col', right_on = 'col1', how = 'outer').drop('col1', axis = 1)
    

    合并后的数据框看起来像

        col col2    col3
    0   ab  match1  1
    1   ab  match1  1
    2   ef  match2  2
    

    编辑: 如果没有像给出的新示例那样匹配,您只需在 lambda 中放置一个条件

    df1.col = df1.col.map(lambda x: difflib.get_close_matches(x, df2.col1)[0] if difflib.get_close_matches(x, df2.col1) else x)
    

    现在你得到合并后

        col col2    col3
    0   ab  match1  1
    1   ab  match1  1
    2   ef  match2  2
    3   xyz NaN     NaN
    

    【讨论】:

    • 感谢您的帮助!问题是我不能冒险做出错误的匹配,我编辑了我的问题以分配 NaN 如果没有准确找到。
    猜你喜欢
    • 2020-05-22
    • 1970-01-01
    • 2019-07-18
    • 2020-08-04
    • 2018-01-21
    • 2021-12-31
    • 2022-10-24
    • 2022-10-15
    • 2020-08-06
    相关资源
    最近更新 更多