我有两个df和两个字符串列,如下所示:
Df1:原始df有2000行名称
Id Name
1 Paper
2 Paper
3 Scissors
4 Mat
5 Cat
6 Cat
第二个Df:原始Df有1000+项目名称
Item_ID Item_Name
1 Paper Bag
2 wallpaper
3 paper
4 cat cage
我需要位于Item_Name列的Name
列中的字符串
第一种方法:使用str.contains
:
如果字符串是一列和两个字符串,我知道如何匹配,如下所示:
df[df['Name'].str.contains("paper|cat", na=False)]
但是当有两列字符串(名称和项目名称(要匹配时该怎么办?
第二种方法:Fuzzywuzzy
matched = []
for row in df1.index:
name = df1.get_value(row,"Name")
for columns in df2.index:
item_name=df2.get_value(columns,"Item_Name")
matched_token=fuzz.token_sort_ratio(name,item_name)
if matched_token> 80:
matched.append([name,item_name,matched_token])
问题是,它会很慢,而且我想要的输出比我从fuzzywuzzy得到的要多一点。输出看起来像:
Id Name Item_ID
1 Paper 1,2,3
2 Paper 1,2,3
3 Scissors NA
4 Mat NA
5 Cat 4
6 Cat 4
总结:
- 如果它们是两个具有不同列名的df,如何执行str.contains
- 如何转换df以获得上述预期输出
您可以将pd.Series.apply
与自定义函数一起使用:
def matcher(x):
res = df2.loc[df2['Item_Name'].str.contains(x, regex=False, case=False), 'Item_ID']
return ','.join(res.astype(str))
df1['Item_ID'] = df1['Name'].apply(matcher)
print(df1)
Id Name Item_ID
0 1 Paper 1,2,3
1 2 Paper 1,2,3
2 3 Scissors
3 4 Mat
4 5 Cat 4
5 6 Cat 4
有一些方法可以提高效率:
- 仅处理
df1['Name']
:apply
中的唯一项是行循环 - 使用列表综合而不是
pd.Series.apply
。两者都是Python级别的循环,但列表理解通常优于Pandasstr
方法
但以上并不能提高算法的复杂性。为了获得数量级的更好改进,您应该考虑基于trie的算法,例如使用Aho–Corasick算法的这个答案。
您可以在此处使用df.apply
def get_vals(df):
return ','.join(map(str, df2.loc[df2['Item_Name'].str.contains(df['Name'], case=False),]['Item_ID'].tolist()))
df1['Item_ID'] = df1.apply(get_vals, axis=1)
输出:
Id Name Item_ID
1 Paper 1,2,3
2 Paper 1,2,3
3 Scissors
4 Mat
5 Cat 4
6 Cat 4
相信这会给你想要的结果
df=pd.DataFrame({'ID':[1,2,3,4,5,6],'Name':['paper','paper','scissors','mat','cat','cat']})
df1=pd.DataFrame({'ID':[1,2,3,4],'Name':['paper bag','wallpaper','paper','cat cage']})
import numpy as np
def lookup_prod(ip):
lst=[]
for idx,row in df1.iterrows():
if ip in row['Name']:
lst.append(row['ID'])
if not lst:
return np.NaN
return lst
df['Item_ID'] = df['Name'].apply(lookup_prod)
输出:
ID Name Item_ID
0 1 paper [1, 2, 3]
1 2 paper [1, 2, 3]
2 3 scissors NaN
3 4 mat NaN
4 5 cat [4]
5 6 cat [4]