【问题标题】:Python: Return Pandas DataFrame from FuzzyWuzzy ExtractOne()Python:从 FuzzyWuzzy ExtractOne() 返回 Pandas DataFrame
【发布时间】:2019-08-29 07:58:58
【问题描述】:

我有两个 Pandas DataFrames(人名),一个很小(200+ 行),另一个非常大(100k+ 行)。它们都有相似的标题,但大的也有一个唯一的 ID,如下所示:

Small: LST_NM, FRST_NM, CITY
Big: LST_NM, FRST_NM, CITY, UNIQUE_ID

小号:df2 = pd.DataFrame([['Doe','John','New York'], ['Obama', 'Barack', 'New York']], columns = ['FRST_NM', 'LST_NM', 'CITY_NM'])

大:df = pd.DataFrame([['Doe','John','New York', 'N1'], ['Obama', 'Barack Hussein', 'New York', 'N2'], ['Obama', 'Michelle', 'Chicago', 'N3'], ['Trump', 'Donald', 'New York', 'N4']], columns = ['FRST_NM', 'LST_NM', 'CITY_NM', 'UNIQUE_ID'])

我使用下面的代码:

import itertools
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
import time
import pandas as pd
import multiprocessing as mp
from unidecode import unidecode
import re

#read the CSV files;
df = pd.read_csv("BIG.csv", encoding="utf-8")
df2 = pd.read_csv("SMALL.csv", encoding="utf-8")

#create function to clean the columns
def clean_column(column):
    column = unidecode(column)
    column = re.sub('\n', ' ', column)
    column = re.sub('-', ' ', column)
    column = re.sub('/', ' ', column)
    column = re.sub("'", '', column)
    column = re.sub(",", '', column)
    column = re.sub(":", ' ', column)
    column = re.sub('  +', ' ', column)
    column = column.strip().strip('"').strip("'").lower().strip()
    if not column :
        column = None
    return column

#Normalize, create FULL_NM by combining FRST_NM / LST_NM and then create MIN_CITY as the first three chars from CITY_NM:
df['FULL_NM'] = (df['LST_NM'] + ' ' + df['FRST_NM']).apply(lambda x: fuzz._process_and_sort(clean_column(x), True, True))
df['MIN_CITY'] = (df['CITY_NM']).astype(str).apply(lambda x: clean_column(x[:3]))

df2['FULL_NM'] = (df2['LST_NM'] + ' ' + df2['FRST_NM']).apply(lambda x: fuzz._process_and_sort(clean_column(x), True, True))
df2['MIN_CITY'] = (df2['CITY_NM']).astype(str).apply(lambda x: clean_column(x[:3]))

#create match1 function; it uses the FULL_NM as lookup field
def match1(x, choices, scorer, cutoff):
        match = process.extractOne(x['FULL_NM'], choices=choices.loc[choices['MIN_CITY'] == x['MIN_CITY'],'FULL_NM'], 
                                   scorer=scorer, 
                                   score_cutoff=cutoff)
        if match:
            return match[0]

#and finally... create the MATCH_NM column by applying match1 function as following:
df2['MATCH_NAME'] = df2.apply(match1, args=(df, fuzz.token_set_ratio, 80), axis=1)

我想从大的到小的查找信息,带上 UNIQUE_ID。为了加快这个过程,我创建了更小的块(使用城市的前三个字母)。这个新列(在两个 DataFrame 中创建)被命名为 MIN_CITY。

上面的代码运行良好,但它只带来了匹配的名称 (MATCH_NAME)。我不想反转(从小到大然后过滤)。如何从 process.ExtractOne() 中获取 UNIQUE_ID?我需要提一下,我对 Python / Pandas / FuzzyWuzzy 非常陌生。

【问题讨论】:

  • 嗨@c_c。你能提供一个minimal, complete, and verifiable example吗?
  • 完成!抱歉,我是 StackOverflow 的新手!感谢您的提示,我会牢记这一点!
  • 当然。请检查答案。还将推荐使用 MVC 作为代码而不是图片。喜欢:df2 = pd.DataFrame([['Doe','John','New York'], ['Obama', 'Barack', 'New York']], columns = ['FRST_NM', 'LST_NM', 'CITY_NM'])

标签: python pandas fuzzywuzzy


【解决方案1】:

请查看fuzzymatcher:

from fuzzymatcher import link_table, fuzzy_left_join

left_on = ['FULL_NM']
right_on = ['FULL_NM']

fuzzy_left_join(df2, df, left_on, right_on)

给出一个表格:

best_match_score    __id_left   __id_right  FRST_NM_left    LST_NM_left CITY_NM_left    FULL_NM_left    MIN_CITY_left   MATCH_NAME  FRST_NM_right   LST_NM_right    CITY_NM_right   UNIQUE_ID   FULL_NM_right   MIN_CITY_right
0   0.167755    0_left  0_right Doe John    New York    doe john    new doe john    Doe John    New York    N1  doe john    new
1   0.081166    1_left  1_right Obama   Barack  New York    barack obama    new barack hussein obama    Obama   Barack Hussein  New York    N2  barack hussein obama    new

这里有一些examples

如果你非要坚持使用fuzzy_wuzzy.process.extractOne,你可以匹配并从匹配的名称中找到unique_id,如:

def match1(x, choices, scorer, cutoff):
        match = process.extractOne(x['FULL_NM'], choices=choices.loc[choices['MIN_CITY'] == x['MIN_CITY'],'FULL_NM'], 
                                   scorer=scorer, 
                                   score_cutoff=cutoff)
        if match:
            return choices[choices['FULL_NM'] == 'doe john'].UNIQUE_ID[0]

【讨论】:

  • 谢谢,尼哈尔!效果很好。你知道,也许,我可以在哪里找到这个图书馆的更多信息?它缺乏文档。例如,我想更改记分器并添加自定义数据预处理器。我找不到例子...
猜你喜欢
  • 2023-03-15
  • 2017-09-11
  • 2018-02-23
  • 1970-01-01
  • 2020-03-30
  • 2021-03-16
  • 1970-01-01
  • 2012-05-31
  • 2018-01-01
相关资源
最近更新 更多