我有一个数据框:
df = pd.DataFrame({'names': ['Mohit', 'Mimansa', 'Viseshini', 'Manoj', 'Manojj', 'Mohith', 'Mimi', 'Visesheni']})
df
names
0 Mohit
1 Mimansa
2 Viseshini
3 Manoj
4 Manojj
5 Mohith
6 Mimi
7 Visesheni
我正在尝试将每个字符串与其他列中的其余字符串进行比较
我有一个函数partial_ratio,该函数使用两个字符串并返回相似百分比:
from fuzzywuzzy import fuzz
fuzz.partial_ratio('Mohit', 'Moht Motwani')
>>80
我想要的是字符串匹配至少为80%的行的索引。
我已经尝试过了:
ratios = []
for row in df['names']:
vals = df['names'].apply(lambda x: fuzz.partial_ratio(x, row))
ratios.append(np.where(vals>80))
ratios
[(array([0, 5], dtype=int64),),
(array([1], dtype=int64),),
(array([2, 7], dtype=int64),),
(array([3, 4], dtype=int64),),
(array([3, 4], dtype=int64),),
(array([0, 5], dtype=int64),),
(array([6], dtype=int64),),
(array([2, 7], dtype=int64),)]
有两个问题:
1)我正在使用for循环,因此对于较大的数据集,这会使操作非常缓慢。使用一个系列的apply函数将每个字符串相互比较,然后返回另一个系列。使用np.where
检索匹配度至少为80%的索引。
2)当我使用apply函数时,字符串也将与其自身进行比较。
有没有熊猫函数/方法或更好的方法来实现这一目标?
names matches
0 Mohit [5]
1 Mimansa []
2 Viseshini [7]
3 Manoj [4]
4 Manojj [3]
5 Moht Motwani [0]
6 Mimi []
7 Visesheni [2]
答案 0 :(得分:1)
您可以循环并从列表理解列表中转换为numpy array
,因此可以使用numpy.where
进行filterinf,然后使用布尔索引过滤掉相同的索引,索引由enumerate
创建:>
from fuzzywuzzy import fuzz
ratios = []
for i, x in enumerate(df['names']):
a = np.array([fuzz.partial_ratio(x, row) for row in df['names']])
a = np.where(a > 80)[0]
ratios.append(a[a != i])
df['rat'] = ratios
print (df)
names rat
0 Mohit [5]
1 Mimansa []
2 Viseshini [7]
3 Manoj [4]
4 Manojj [3]
5 Mohith [0]
6 Mimi []
7 Visesheni [2]
答案 1 :(得分:1)
使用下面的代码块,所以只需为所需的输出做一堆东西,它可能不可读,但仍然可以按预期工作,一堆apply
和时髦的代码:-):
from fuzzywuzzy import fuzz
import pandas as pd
import random,ast
df = pd.DataFrame({'names': ['Mohit', 'Mimansa', 'Viseshini', 'Manoj', 'Manojj', 'Mohith', 'Mimi', 'Visesheni']})
it=iter(range(len(df['names'])))
df['matches']=df['names'].apply(lambda x: [i for i,v in enumerate(df['names']) if fuzz.partial_ratio(v,x)>80] if len([i for i,v in enumerate(df['names']) if fuzz.partial_ratio(v,x)>80])>1 else [])
df['matches']=df['matches'].astype(str)
df['count'] = df.groupby('matches').cumcount() + 1
df['matches']=df['matches'].map(ast.literal_eval)
df['matches']=df.apply(lambda x: ([x['matches'][-1]] if x['count']==1 else [x['matches'][0]]) if x['matches']!=[] else x['matches'],axis=1)
print(df)
输出:
names matches count
0 Mohit [5] 1
1 Mimansa [] 1
2 Viseshini [7] 1
3 Manoj [4] 1
4 Manojj [3] 2
5 Mohith [0] 2
6 Mimi [] 2
7 Visesheni [2] 2
说明:
创建一个apply
语句以按预期获取索引
使用groupby
来获取值的计数,每个值都会一直计数到该值存在的行
然后做很多事情来更新'matches'
列,并消除重复的问题