В поисках более быстрого способа нечеткого сопоставления строк - PullRequest
1 голос
/ 27 мая 2019

Я использую fuzzywuzzy в python для нечеткого соответствия строк. У меня есть набор имен в списке с именем HKCP_list, который я итеративно сопоставляю со столбцом панд, чтобы получить наилучшее возможное совпадение. Ниже приведен код для этого

import fuzzywuzzy
from fuzzywuzzy import fuzz,process

def search_func(row):
    chk = process.extract(row,HKCP_list,scorer=fuzz_token_sort_ratio)[0]
    return chk

wc_df['match']=wc_df['concat_name'].map(search_func)

Фрейм данных wc_df содержит столбец 'concat_name', который должен соответствовать каждому имени в списке HKCP_list. Приведенному выше коду потребовалось около 2 часов для работы с 6K-именами в списке и 11K-именами в столбце «concat_name».

Я должен повторить это на другом наборе данных, где 89K имен в списке и 120K имен в столбце. Чтобы ускорить процесс, у меня появилась идея в следующем вопросе о Stackoverflow

Векторизация или ускорение нечеткого соответствия строк в столбце PANDAS

В одном из комментариев в ответе выше было рекомендовано сравнить имена с одинаковыми 1-ыми буквами. Столбец 'concat_name', с которым я сравниваю, является производным столбцом, полученным путем объединения столбцов 'first_name' и 'last_name' в кадре данных. Следовательно, я использую следующую функцию для сопоставления с 1-й буквой (так как это оценка сортировки токена, которую я рассматриваю, я сравниваю 1-ю букву и first_name, и last_name с элементами в списке). Ниже приведен код:

wc_df['first_name_1stletter'] = wc_df['first_name'].str[0]
wc_df['last_name_1stletter'] = wc_df['last_name'].str[0]

import time
start_time=time.time()
def match_func(row):
    CP_subset=[x for x in HKCP_list if x[0]==row['first_name_1stletter'] or x[0]==row['last_name_1stletter']]
    return CP_subset
wc_df['list_to_match']=wc_df.apply(match_func,axis=1)
end_time=time.time()
print(end_time-start_time)

Вышеуказанный шаг занял 1600 секунд с данными 6K X 11K. Столбец list_to_match содержит список имен для сравнения для каждого concat_name. Теперь здесь я должен снова взять элемент list_to_match и передать отдельные элементы в списке и выполнить нечеткое сопоставление строк с помощью метода process.extract. Есть ли более элегантный и быстрый способ сделать это на том же шаге, что и выше?

PS: изменив это, добавьте пример того, как выглядит список и столбец данных.

HKCp_list=['jeff bezs','michael blomberg','bill gtes','tim coook','elon musk'] 
concat_name=['jeff bezos','michael bloomberg','bill gates','tim cook','elon musk','donald trump','kim jong un', 'narendra modi','michael phelps']
first_name=['jeff','michael','bill','tim','elon','donald','kim','narendra','michael']
last_name=['bezos','bloomberg','gates','cook','musk','trump','jong un', 'modi','phelps']
import pandas as pd
df=pd.DataFrame({'first_name':first_name,'last_name':last_name,'concat_name':concat_name})

Каждая строка 'concat_name' в df должна сравниваться с элементами HKcp_list.

PS: редактирование сегодня, чтобы отразить ":" и строку во 2-м фрагменте кода, который я пропустил вчера

С уважением, Nirvik

Ответы [ 2 ]

0 голосов
/ 28 мая 2019

Ниже приведен код, который я использовал для динамического сравнения списка для каждого экземпляра:

import fuzzywuzzy
from fuzzywuzzy import fuzz,process

wc_df['first_name_1stletter'] = wc_df['first_name'].str[0]
wc_df['last_name_1stletter'] = wc_df['last_name'].str[0]

import time
start_time=time.time()
def match_func(row):

    CP_subset=[x for x in HKCP_list if x[0]==row['first_name_1stletter'] or x[0]==row['last_name_1stletter']]
    if len(CP_subset)>0:
        chk=process.extract(row['concat_name'],CP_subset,scorer=fuzz.token_sort_ratio)[0]
    else:
        chk = "No item to match"

    return chk

wc_df['match']=wc_df.apply(match_func,axis=1)

end_time=time.time()
print(end_time-start_time)

Приведенный выше код для сравнения 6K X 11K занял около 2600 секунд вместо 7000 секунд, какза 1-й фрагмент кода, размещенного в вопросе.

0 голосов
/ 27 мая 2019

Вы можете попробовать эту функцию Я написал в другом ответе, не на 100% уверенный, как она справляется с точки зрения скорости, вы можете попробовать сами:

from fuzzywuzzy import fuzz
from fuzzywuzzy import process

# Make dataframe out of list
HKCp = pd.DataFrame({'names':HKCp_list})

# Use fuzzy_merge function
fuzzy_merge(df, HKCp, 'concat_name', 'names')

Выходные данные

  first_name  last_name        concat_name           matches
0       jeff      bezos         jeff bezos         jeff bezs
1    michael  bloomberg  michael bloomberg  michael blomberg
2       bill      gates         bill gates         bill gtes
3        tim       cook           tim cook         tim coook
4       elon       musk          elon musk         elon musk
5     donald      trump       donald trump                  
6        kim    jong un        kim jong un                  
7   narendra       modi      narendra modi                  
8    michael     phelps     michael phelps                  

Примечание Вы можете играть с аргументом treshold, чтобы получить менее точные совпадения

...