通过字符串和子字符串连接匹配的数据帧

2024-06-07 02:59:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我想通过部分字符串匹配合并两个数据帧。 我有两个数据帧要合并。第一个df1由130000行组成,如下所示:

id    text                        xc1       xc2
1     adidas men shoes            52465     220
2     vakko men suits             49220     224
3     burberry men shirt          78248     289
4     prada women shoes           45780     789
5     lcwaikiki men sunglasses    34788     745

第二个df2由8000行组成,如下所示:

id    keyword               abc1     abc2
1     men shoes             1000     11
2     men suits             2000     12
3     men shirt             3000     13
4     women socks           4000     14
5     men sunglasses        5000     15

在匹配关键字文本后,输出应如下所示:

id    text                        xc1       xc2   keyword         abc1  abc2
1     adidas men shoes            52465     220   men shoes       1000  11
2     vakko men suits             49220     224   men suits       2000  12
3     burberry men shirt          78248     289   men shirt       3000  13
4     lcwaikiki men sunglasses    34788     745   men sunglasses  5000  15

Tags: 数据textidshirtmenwomenshoessuits
2条回答

让我们通过交叉连接2个数据帧,然后通过将字符串与子字符串匹配来进行过滤,如下所示:

df3 = df1.merge(df2, how='cross')    # for Pandas version >= 1.2.0 (released in Dec 2020)

import re
mask = df3.apply(lambda x: (re.search(rf"\b{x['keyword']}\b", str(x['text']))) != None, axis=1)
df_out = df3.loc[mask]

如果您的Pandas版本早于1.2.0(于2020年12月发布),并且不支持与how='cross'合并,则可以将merge语句替换为:

# For Pandas version < 1.2.0
df3 = df1.assign(key=1).merge(df2.assign(key=1), on='key').drop('key', axis=1)   

在交叉连接之后,我们创建了一个布尔掩码,通过使用.apply()中的re.search来过滤在text中找到keyword的情况

我们必须使用re.search而不是像StackOverflow中大多数类似答案中的stringA in stringB这样的简单Python子字符串测试。这种类型的测试将失败,因为它返回True进行'men suits' in 'women suits'测试,因此keyword中的'men suits''women suits'中的'women suits'错误匹配

我们使用regex,在{}(regex模式:{})周围使用一对单词边界{}元字符,以确保只匹配{}中{}的整个单词匹配,即{}中的{}不会与{}中的{}匹配,因为单词{}在字母之间没有单词边界和{}

结果:

print(df_out)


    id_x                      text    xc1  xc2  id_y         keyword  abc1  abc2
0      1          adidas men shoes  52465  220     1       men shoes  1000    11
6      2           vakko men suits  49220  224     2       men suits  2000    12
12     3        burberry men shirt  78248  289     3       men shirt  3000    13
24     5  lcwaikiki men sunglasses  34788  745     5  men sunglasses  5000    15

这里,列id_xid_y分别是df1df2中的原始id列。从注释中可以看出,这些只是数据帧的行号,您可能并不关心。然后,我们可以删除这两列并重置索引以清理布局:

df_out = df_out.drop(['id_x', 'id_y'], axis=1).reset_index(drop=True)

最终结果

print(df_out)


                       text    xc1  xc2         keyword  abc1  abc2
0          adidas men shoes  52465  220       men shoes  1000    11
1           vakko men suits  49220  224       men suits  2000    12
2        burberry men shirt  78248  289       men shirt  3000    13
3  lcwaikiki men sunglasses  34788  745  men sunglasses  5000    15

让我们首先对关键词进行排序,以便“女士套装”与“男士套装”之前的“匹配”

lkeys = df2.keyword.reindex(df2.keyword.str.len().sort_values(ascending=False).index)

现在定义一个匹配函数;df1中的每个text值将作为s传递以查找匹配关键字:

def is_match(arr, s):
    for a in arr:
        if a in s:
            return a
    return None

现在我们可以从df1中的每个text中提取关键字,并将其添加到新列中:

df1['keyword'] = df1['text'].apply(lambda x: is_match(lkeys, x))

我们现在拥有标准合并所需的一切:

pd.merge(df1, df2, on='keyword')

相关问题 更多 >