Я создал тестовые данные следующим образом:
dat_A="""file_name
3M CO
ABBOTT LABORATORIES
ABC INC
ALTRIA GROUP INC
AMERICAN ELECTRIC POWER CO"""
dat_B="""crsp_name
A & E PLASTIK PAK INC
A & M FOOD SERVICES INC
A A I CORP
A A IMPORTING INC
A A R CORP
ABBOTT
ABBOTT LABS
ALTRIA
ALTRIA GROUP"""
df_A = pd.read_csv(pd.compat.StringIO(dat_A))
df_B = pd.read_csv(pd.compat.StringIO(dat_B))
Поскольку с df_B используется только столбец crsp_name , для эффективности
причина, по которой я извлек ее в переменную crsp :
crsp = df_B.crsp_name
Для облегчения работы с порогом отношения я сохранил его как другую переменную:
ratio_threshold = 50
Для целей теста я взял меньшее значение, чтобы получить любое "непустое"
результаты, но для ваших данных установите значение 80 (значение, которое вы определили).
Затем мы определяем функцию, которая будет применяться в ближайшее время:
def fn(t1):
ratios = crsp.apply(lambda t2: fuzz.token_set_ratio(t1, t2))
iMax = ratios.idxmax()
rMax = ratios[iMax]
return crsp.loc[iMax] if rMax > ratio_threshold else f'{iMax}_{rMax}'
Эта функция будет применяться к каждой строке из df_A.file_name ,
поэтому t1 является текущим значением ( имя_файла ).
Функция запускается с вычисления соотношений токенов, установленных между текущими
имя_файла и каждое имя_списка (сохраняется в отношениях ).
Затем iMax вычисляется как индекс максимального отношения, а rMax -
Максимальное соотношение само по себе.
Если максимальное отношение выше нашего порога, функция возвращает
соответствующее crsp_name .
В противном случае функция возвращает «диагностическое сообщение» - x_y (2 цифры)
где x - индекс, где было найдено максимальное соотношение, и
y - само соотношение. В финальной версии программы изменения
это либо np.nan , либо пустая строка.
И единственное, что нужно сделать, это применить эту функцию и добавить результат
как новый столбец для df_A :
df_A['crsp_name'] = df_A.file_name.apply(fn)
Для вышеуказанных тестовых данных (и порога == 50) я получил:
file_name crsp_name
0 3M CO 2_46
1 ABBOTT LABORATORIES ABBOTT
2 ABC INC A & E PLASTIK PAK INC
3 ALTRIA GROUP INC ALTRIA
4 AMERICAN ELECTRIC POWER CO 1_43
Как видите, есть еще 2 случая, когда нет позиции
в crsp_name дали соотношение более 50, но причина в том, что
исходные данные очень ограничены.
Второй раствор
Когда задача состоит в том, чтобы найти соответствие с списком кандидатов ,
Лучшее (более быстрое) решение - использовать process.extractOne .
Поскольку он принимает список в качестве второго аргумента, я извлек значения
из crsp в другую переменную:
crspVals = crsp.values
Функция для сопоставления (возвращает только лучшее совпадение):
def fn3(t1):
res = process.extractOne(t1, crspVals, scorer=fuzz.token_set_ratio,
score_cutoff=ratio_threshold)
return res[0] if res else ''
process.extractOne
возвращает кортеж (наилучшее совпадение, соотношение), но если
совпадений выше порогового не найдено, результат нет ,
поэтому я решил отказаться от лучшего соотношения ниже порога и вернуть
только лучшее совпадение или пустая строка.
Чтобы применить эту функцию, запустите:
df_A['crsp_name'] = df_A.file_name.apply(fn3)
По сравнению с первым решением (модифицирован для возврата только crsp_name )
он работает почти в 2 раза быстрее.