我有一个Pandas数据帧df1,它包含一列名称和相关的数据列。我有另一个df2,它有一列来自不同来源的名称。两者在格式上存在差异。在这个例子中,df2去掉后缀,使用昵称而不是正式名称(但我不知道数据集中可能存在其他格式差异(:
df1 = pd.DataFrame([('Jordan Smith Jr.', 25, 180),
('Andrew Johnson', 34, 200),
('Anthony Tipton III', 42, 175),
('Chris Black', 24, 160)],
columns=('name', 'age', 'weight'))
df2 = pd.DataFrame([('Jordan Smith'),
('Drew Johnson'),
('Anthony Tipton')],
columns=('name'))
我想过滤并返回df1中存在于df2中的人员的行。df1包含df2,因此唯一的布尔比较失败将是由于格式差异。我想收集df2中比较不好的一组名称,这样我就可以检查它们并进行相应的处理。我可以这样过滤df1:
df1 = df1[df1['name'].str.contains('|'.join(df2['name'])]
这处理了后缀差异,并以我感到满意的方式减少了比较失败的次数,但有没有一种简单的方法可以收集df2中比较不好的成员?我可以用循环迭代,但我觉得可能有一种更优雅的方法
---------------编辑------------------
上面的代码返回了我想要的一半,我不寻求帮助(除非有更好的、完全不同的方法(:
>>>df1
[('Jordan Smith Jr.', 25, 180),
('Anthony Tipton III', 42, 175)]
我正在寻找一种方法来撤销df2中的名称,这些名称在评估此检查时没有被解析为df1中任何"名称"的"True":
df1['name'].str.contains('|'.join(df2['name'])
我可以用类似的东西来实现这一点:
for name in df2:
temp = df1['name'].str.contains(name)
if temp.any():
*append name to collection list/dataframe/etc.*
但我觉得还有更好的办法。
IIUC,您想在df2中识别在df1中从未匹配的名称吗?
您可以在extractall
:上使用设置操作
set(df2['name']).difference(df1['name'].str.extractall(f"({'|'.join(df2['name'])})")[0])
输出:{'Drew Johnson'}
中级,所有匹配的术语:
df1['name'].str.extractall(f"({'|'.join(df2['name'])})")[0]
match
0 0 Jordan Smith
2 0 Anthony Tipton
Name: 0, dtype: object
由于两个数据帧中没有一个名称完全匹配,我将添加一个来说明:
In[1]: df1 = pd.DataFrame([('Jordan Smith Jr.', 25, 180),
('Andrew Johnson', 34, 200),
('Anthony Tipton III', 42, 175),
('Chris Black', 24, 160)],
columns=('name', 'age', 'weight'))
In[2]: df2 = pd.DataFrame([('Jordan Smith'),
('Drew Johnson'),
('Anthony Tipton'),
('Chris Black')], # <-- added one here
columns=['name']) # had to put it into square brackets to work
然后,您可以通过在两组名称之间找到.intersection()
来找到那些完全相交的名称:
In[1]: name_intersection = list(set(df1['name']).intersection(set(df2['name'])))
In[2]: name_intersection
Out[2]: ['Chris Black'] # shows fully intersecting names only
然后,您可以在条件之前使用~
从df1
中筛选出匹配的名称
In[1]: df_unmatched = df1[~df1.name.isin(name_intersection)]
In[2]: df_unmatched
Out[2]: name age weight
0 Jordan Smith Jr. 25 180
1 Andrew Johnson 34 200
2 Anthony Tipton III 42 175
如果您的问题是查找不完全相同的名称,这将起作用。你可以进一步使用你的方法来过滤掉名字,但如果没有额外的例子,我无法为你提供一个通用的方法,因此"Andrew"是"Drew",但可能有"Joseph"是"Joe",或者其他模式。