Groupby并在Python中的两列中查找相似或相同的项

Groupby并在Python中的两列中查找相似或相同的项,python,pandas,dataframe,Python,Pandas,Dataframe,对于如下数据帧,如果name2中的字符串与name1中的字符串在类型的每组中大致相似或相同,则返回Y,否则返回N id type name1 name2 0 1 A James B. James 1 2 A Keras Steven 2 3 A NaN Keras 3 4 B Jack Lucy 4 5 B Lucy Jack 5

对于如下数据帧,如果
name2
中的字符串与
name1
中的字符串在
类型的每组中大致相似或相同,则返回
Y
,否则返回
N

   id type     name1      name2
0   1    A  James B.      James
1   2    A     Keras     Steven
2   3    A       NaN      Keras
3   4    B      Jack       Lucy
4   5    B      Lucy       Jack
5   6    C    Jasica     Hoverd
6   7    C    Steven     Jasica
7   8    C       NaN  Steven L.
   id type     name1      name2 result
0   1    A  James B.      James      Y
1   2    A     Keras     Steven      N
2   3    A       NaN      Keras      Y
3   4    B      Jack       Lucy      Y
4   5    B      Lucy       Jack      Y
5   6    C    Jasica     Hoverd      N
6   7    C    Steven     Jasica      Y
7   8    C       NaN  Steven L.      Y
预期的结果是这样的,例如,在
type
A
中,来自
name2
James
具有相似的值
James B.
name1
中,
Keras
name2
name1
中具有相同的值,因此它们在
结果中都返回
Y
。虽然
Steven
name1
中不存在,所以返回
N

   id type     name1      name2
0   1    A  James B.      James
1   2    A     Keras     Steven
2   3    A       NaN      Keras
3   4    B      Jack       Lucy
4   5    B      Lucy       Jack
5   6    C    Jasica     Hoverd
6   7    C    Steven     Jasica
7   8    C       NaN  Steven L.
   id type     name1      name2 result
0   1    A  James B.      James      Y
1   2    A     Keras     Steven      N
2   3    A       NaN      Keras      Y
3   4    B      Jack       Lucy      Y
4   5    B      Lucy       Jack      Y
5   6    C    Jasica     Hoverd      N
6   7    C    Steven     Jasica      Y
7   8    C       NaN  Steven L.      Y
有人能帮忙吗?多谢各位


如果查找相似值太复杂而无法实现,则只查找相同的值并返回
Y
就可以了。

如果没有相似性,则更简单:

mask = df.groupby('type', group_keys=False).apply(lambda x: x['name2'].isin(x['name1']))
df['new'] = np.where(mask, 'Y','N')
print (df)
   id type     name1      name2 new
0   1    A  James B.      James   N
1   2    A     Keras     Steven   N
2   3    A       NaN      Keras   Y
3   4    B      Jack       Lucy   Y
4   5    B      Lucy       Jack   Y
5   6    C    Jasica     Hoverd   N
6   7    C    Steven     Jasica   Y
7   8    C       NaN  Steven L.   N
与split基本相似:

mask = (df.assign(name1 = df['name1'].fillna('|').astype(str).str.split().str[0],
                  name2 = df['name2'].astype(str).str.split().str[0])
          .groupby('type', group_keys=False)
          .apply(lambda x: x['name2'].isin(x['name1'])))
df['new'] = np.where(mask, 'Y','N')
print (df)

   id type     name1      name2 new
0   1    A  James B.      James   Y
1   2    A     Keras     Steven   N
2   3    A       NaN      Keras   Y
3   4    B      Jack       Lucy   Y
4   5    B      Lucy       Jack   Y
5   6    C    Jasica     Hoverd   N
6   7    C    Steven     Jasica   Y
7   8    C       NaN  Steven L.   Y
为了更好地匹配相似性,可以使用
SequenceMatcher
进行比率匹配,并通过treshold进行过滤,例如,此处通过
0.5

from difflib import SequenceMatcher

def f(x):
    comp = [any(SequenceMatcher(None, a, b).ratio() > .5 
                                   for a in x['name1'].fillna('_')) 
                                   for b in x['name2']]
    return pd.Series(comp, index=x.index)

mask = df.groupby('type', group_keys=False).apply(f)
df['new'] = np.where(mask, 'Y','N')
print (df)
   id type       name1      name2 new
0   1    A    James B.      James   Y
1   2    A       Keras     Steven   N
2   3    A         NaN      Keras   Y
3   4    B        Jack       Lucy   Y
4   5    B        Lucy       Jack   Y
5   6    C      Jasica     Hoverd   N
6   7    C  Steven LA.     Jasica   Y
7   8    C         NaN  Steven L.   Y

如果没有相似性,则更为简单:

mask = df.groupby('type', group_keys=False).apply(lambda x: x['name2'].isin(x['name1']))
df['new'] = np.where(mask, 'Y','N')
print (df)
   id type     name1      name2 new
0   1    A  James B.      James   N
1   2    A     Keras     Steven   N
2   3    A       NaN      Keras   Y
3   4    B      Jack       Lucy   Y
4   5    B      Lucy       Jack   Y
5   6    C    Jasica     Hoverd   N
6   7    C    Steven     Jasica   Y
7   8    C       NaN  Steven L.   N
与split基本相似:

mask = (df.assign(name1 = df['name1'].fillna('|').astype(str).str.split().str[0],
                  name2 = df['name2'].astype(str).str.split().str[0])
          .groupby('type', group_keys=False)
          .apply(lambda x: x['name2'].isin(x['name1'])))
df['new'] = np.where(mask, 'Y','N')
print (df)

   id type     name1      name2 new
0   1    A  James B.      James   Y
1   2    A     Keras     Steven   N
2   3    A       NaN      Keras   Y
3   4    B      Jack       Lucy   Y
4   5    B      Lucy       Jack   Y
5   6    C    Jasica     Hoverd   N
6   7    C    Steven     Jasica   Y
7   8    C       NaN  Steven L.   Y
为了更好地匹配相似性,可以使用
SequenceMatcher
进行比率匹配,并通过treshold进行过滤,例如,此处通过
0.5

from difflib import SequenceMatcher

def f(x):
    comp = [any(SequenceMatcher(None, a, b).ratio() > .5 
                                   for a in x['name1'].fillna('_')) 
                                   for b in x['name2']]
    return pd.Series(comp, index=x.index)

mask = df.groupby('type', group_keys=False).apply(f)
df['new'] = np.where(mask, 'Y','N')
print (df)
   id type       name1      name2 new
0   1    A    James B.      James   Y
1   2    A       Keras     Steven   N
2   3    A         NaN      Keras   Y
3   4    B        Jack       Lucy   Y
4   5    B        Lucy       Jack   Y
5   6    C      Jasica     Hoverd   N
6   7    C  Steven LA.     Jasica   Y
7   8    C         NaN  Steven L.   Y
输出

   id type     name1      name2 result
0   1    A  James B.      James      Y
1   2    A     Keras     Steven      N
2   3    A       NaN      Keras      Y
3   4    B      Jack       Lucy      Y
4   5    B      Lucy       Jack      Y
5   6    C    Jasica     Hoverd      N
6   7    C    Steven     Jasica      Y
7   8    C       NaN  Steven L.      Y
输出

   id type     name1      name2 result
0   1    A  James B.      James      Y
1   2    A     Keras     Steven      N
2   3    A       NaN      Keras      Y
3   4    B      Jack       Lucy      Y
4   5    B      Lucy       Jack      Y
5   6    C    Jasica     Hoverd      N
6   7    C    Steven     Jasica      Y
7   8    C       NaN  Steven L.      Y


您的解决方案与他的预期输出不匹配谢谢,但我得到了一个相同的错误:
AttributeError:只能使用带字符串值的.str访问器,它在pandas
@ahbon中使用np.object\dtype-问题是如果强制转换到字符串,然后将
nan
s与
nan
s匹配,因为字符串
'nan'='nan'
。因此,为了避免匹配,有必要将至少转换为其他内容,@ahbon-使用
SequenceMatcher
@ahbon-编辑另一个通用解决方案的答案-是的,因此另一个答案是关于拆分的,我的第二个答案是关于拆分的,因此无法使用。需要更一般的匹配相似性的最后一个答案,如果需要匹配,如
Steven L.到Steven LA。
Steven到Stevens
您的解决方案与他预期的输出不匹配谢谢,但我得到了一个相同的错误:
AttributeError:只能使用带字符串值的.str访问器,在pandas
@ahbon中使用np.object\dtype-问题是如果对字符串进行强制转换,则将
nan
s与
nan
s匹配,因为字符串
'nan'='nan'
。因此,为了避免匹配,有必要将至少转换为其他内容,@ahbon-使用
SequenceMatcher
@ahbon-编辑另一个通用解决方案的答案-是的,因此另一个答案是关于拆分的,我的第二个答案是关于拆分的,因此无法使用。需要更一般匹配相似性的最后一个答案,如果需要匹配,如
Steven L.到Steven LA.
Steven到Stevens
谢谢,但我的实际数据
AttributeError:只能使用带字符串值的.str访问器,在pandas
@iamklaus中使用np.object\dtype的-它匹配
NaN
s witn
NaNs
-无法转换both@jezrael怀疑是否会放弃它们,继续向str施法,然后进行分割。一次转换,另一次移除,检查我的回答谢谢,但是我的实际数据
AttributeError:只能使用带字符串值的.str访问器,它在pandas
@iamklaus中使用np.object\dtype-它匹配
NaN
s witn
NaNs
-无法转换both@jezrael怀疑是否会放弃它们,然后向str全部施放,然后进行分割。一个皈依者,另外,请检查我的答案