在熊猫中与其自身比较列

时间:2018-12-21 09:05:50

标签: python python-3.x pandas

我有一个数据框:

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]

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'列,并消除重复的问题