Python 通过部分字符串匹配合并两个数据帧

Python 通过部分字符串匹配合并两个数据帧,python,r,Python,R,我正在尝试基于部分字符串匹配合并两个不同大小的相当大的数据帧 df1$代码包含所有12位代码,而df2$代码包含10-12位代码的混合,其中一些较短的代码是与df1$代码中的12位代码相匹配的子字符串 因此,我需要合并两个数据帧之间的所有12位匹配,还需要合并df2中具有10-11位代码的记录,这些记录是与df1的子字符串匹配 数据帧示例: df1 <- data.frame(code_1 = c('123456789012', '210987654321', '567890543211'

我正在尝试基于部分字符串匹配合并两个不同大小的相当大的数据帧

df1$代码包含所有12位代码,而df2$代码包含10-12位代码的混合,其中一些较短的代码是与df1$代码中的12位代码相匹配的子字符串

因此,我需要合并两个数据帧之间的所有12位匹配,还需要合并df2中具有10-11位代码的记录,这些记录是与df1的子字符串匹配

数据帧示例:

df1 <- data.frame(code_1 = c('123456789012', '210987654321', '567890543211', '987656789001', '123456654321', '678905432156', '768927461037', '780125634701', '673940175372', '167438501473'),
              name = c('bob','joe','sally','john','lucy','alan', 'fred','stephanie','greg','tom'))

df2 <- data.frame(code_2 = c('123456789012','2109876543','7890543211','98765678900','12345665432','678905432156'),
              color = c('blue', 'red', 'green', 'purple', 'orange', 'brown'))

df3 (merged)

code_1         code_2         name  color
123456789012   123456789012   bob   blue
210987654321   2109876543     joe   red
567890543211   7890543211     sally green
987656789001   98765678900    john  purple
123456654321   12345665432    lucy  orange
678905432156   678905432156   alan  brown

在python/pandas中,您可以执行以下操作:

from pandas import DataFrame, Series
df1 = DataFrame(dict(
        code1 = ('123456789012', '210987654321', '567890543211', '987656789001', '123456654321', '678905432156', '768927461037', '780125634701', '673940175372', '167438501473'),
        name = ('bob','joe','sally','john','lucy','alan', 'fred','stephanie','greg','tom')))

df2 = DataFrame(dict(
        code2 = ('123456789012','2109876543','7890543211','98765678900','12345665432','678905432156'),
        color = ('blue', 'red', 'green', 'purple', 'orange', 'brown')))

matches = [df1[df1['code1'].str.contains(x)].index[0] for x in df2['code2']]

print(
    df1.assign(subcode=Series(data=df2['code2'], index=matches))
       .merge(df2, left_on='subcode', right_on='code2')
       .drop('subcode', axis='columns')
)
这倒是:

          code1   name         code2   color
0  123456789012    bob  123456789012    blue
1  210987654321    joe    2109876543     red
2  567890543211  sally    7890543211   green
3  987656789001   john   98765678900  purple
4  123456654321   lucy   12345665432  orange
5  678905432156   alan  678905432156   brown

注意:我讨厌在数据帧中使用循环,但我想这是可行的。

根据新信息更新。这应该起作用:

df2$New <- lapply(df2$code_2, grep, df1$code_1,value=T)

combined <- merge(df1,df2, by.x="code_1", by.y="New")

        code_1  name       code_2  color
1 123456654321  lucy  12345665432 orange
2 123456789012   bob 123456789012   blue
3 210987654321   joe   2109876543    red
4 567890543211 sally   7890543211  green
5 678905432156  alan 678905432156  brown
6 987656789001  john  98765678900 purple
df2$New尝试此SQL连接

library(sqldf)

sqldf("select a.code_1, b.code_2, a.name, b.color 
       from df2 b left join df1 a on a.code_1 like '%' || b.code_2 || '%'")
给予:

        code_1       code_2  name  color
1 123456789012 123456789012   bob   blue
2 210987654321   2109876543   joe    red
3 567890543211   7890543211 sally  green
4 987656789001  98765678900  john purple
5 123456654321  12345665432  lucy orange
6 678905432156 678905432156  alan  brown

更新:更新答案以反映问题中的更改,以便(1)子字符串可以位于目标字符串中的任何位置,以及(2)代码列的名称已更改为
code\u 1
code\u 2

我们可以使用
grep
+
sapply
df2$code
中为每个
df1$code
提取匹配索引,并从中创建
matchID
。接下来,我们在
matchID
上进行
merge
以获得所需的输出:

df1$matchID = row.names(df1)
df2$matchID = sapply(df2$code, function(x) grep(x, df1$code))

df_merge = merge(df1, df2, by = "matchID")[-1]
请注意,如果
df1$code
与任何
df2$code
不匹配,
df2$matchID
将为空,因此不会与
df1$matchID
合并

结果:

> df2
          code  color matchID
1 123456789012   blue       1
2   2109876543    red       2
3   7890543211  green       3
4  98765678900 purple       4
5  12345665432 orange       5
6 678905432156  brown       6
7  14124124124  black        

> df_merge
        code.x  name       code.y  color
1 123456789012   bob 123456789012   blue
2 210987654321   joe   2109876543    red
3 567890543211 sally   7890543211  green
4 987656789001  john  98765678900 purple
5 123456654321  lucy  12345665432 orange
6 678905432156  alan 678905432156  brown
df1 <- data.frame(code = c('123456789012', '210987654321', '567890543211', '987656789001', '123456654321', '678905432156', '768927461037', '780125634701', '673940175372', '167438501473'),
                  name = c('bob','joe','sally','john','lucy','alan', 'fred','stephanie','greg','tom'),
                  stringsAsFactors = FALSE)

df2 <- data.frame(code = c('123456789012','2109876543','7890543211','98765678900','12345665432','678905432156', '14124124124'),
                  color = c('blue', 'red', 'green', 'purple', 'orange', 'brown', 'black'),
                  stringsAsFactors = FALSE)
数据(添加不匹配项以获得更好的演示):

> df2
          code  color matchID
1 123456789012   blue       1
2   2109876543    red       2
3   7890543211  green       3
4  98765678900 purple       4
5  12345665432 orange       5
6 678905432156  brown       6
7  14124124124  black        

> df_merge
        code.x  name       code.y  color
1 123456789012   bob 123456789012   blue
2 210987654321   joe   2109876543    red
3 567890543211 sally   7890543211  green
4 987656789001  john  98765678900 purple
5 123456654321  lucy  12345665432 orange
6 678905432156  alan 678905432156  brown
df1 <- data.frame(code = c('123456789012', '210987654321', '567890543211', '987656789001', '123456654321', '678905432156', '768927461037', '780125634701', '673940175372', '167438501473'),
                  name = c('bob','joe','sally','john','lucy','alan', 'fred','stephanie','greg','tom'),
                  stringsAsFactors = FALSE)

df2 <- data.frame(code = c('123456789012','2109876543','7890543211','98765678900','12345665432','678905432156', '14124124124'),
                  color = c('blue', 'red', 'green', 'purple', 'orange', 'brown', 'black'),
                  stringsAsFactors = FALSE)

df1我们是否可以简单地将每个代码的长度截断为10位,然后进行匹配?您也想要python解决方案吗?在其他人编辑python标记之前,您最初包含了该标记。是否应该将其与
'7890543211'
匹配
'567890543211'
?或者您只关心出现在12位数字开头的子字符串吗?@useR如果您的示例是所需的结果,您可以使用
sapply(df1$code,agrep,df2$code,value=TRUE)
获取匹配值。我不知道如何从列表返回到加入。抱歉,更正了字段。我不能截短到10位,因为有些从开头到结尾都缺少数字(有些从开头到结尾都缺少一个数字)。我可以使用R或Python答案。谢谢他要了一张支票solution@Mako212问题并没有那么明确。考虑到OP包含了一个python标记,而其他人删除了它,我觉得这仍然是一个有效的答案。@Mako212可能值得删除这些注释,因为OP现在已经明确表示python解决方案也在使用sought@PaulH.嗨,我正在尝试使用您的代码在我的数据集上执行此操作,但我得到以下错误:Indexer错误:索引0超出大小为0的轴0的界限。知道为什么吗?谢谢@基本上是句子。两列都有段落,其中一列有另一列句子的子集(两列大小不同)。让我们假设dataframe 1中的第1列有“Hello,今天真是美好的一天!”和“You Do Azing job”这样的值,另一列是这些句子的子集,如“Hello,today”或“You Do an”,我希望第2列中的所有内容(也称为子集)都与它们的适当子集相关联。这有意义吗?我认为这不起作用,因为并不是
df2
中的所有10位代码都与
df1
@中的前10位匹配。用户更正,如果子字符串从数字内的某个地方开始,它就不起作用,但看看OPs示例,他只返回了5个匹配项,这是前10位数字匹配的地方。请注意,在我更新后,上面的注释不再是问题。我尝试了这一点,但对于完整的数据帧(一个210K+行和另一个30K+行),它不断崩溃。将201K+数据帧拆分为四个数据块在第一个数据块上产生以下错误:顺序错误(列表(“899349002062”),“793573098023”、“815036020027”、“857638004289”:在“orderVector1”中未实现类型“list”