Создание флага с использованием нечеткого сопоставления между двумя наборами данных в Python

У меня есть два набора данных df1 и df2, оба имеют следующие столбцы:

|city   |state  |address_id |address             |postal_code
|A      |X      |10         |flat 123,abc lane   |400000

Я хочу создать двоичный флаг для каждого address_id в df1 в зависимости от того, присутствует ли аналогичный адрес в df2. Мои оригинальные наборы данных довольно большие (df1= 5 тыс. Строк, df2= 200 тыс. Строк). Я опробовал следующий набор кодов на небольших выборках данных:

for i in df1.index:
      v=[]
      for j in df2.index:
            vi = df1.get_value(i, 'address')
            vj = df2.get_value(j, 'address')
            v.append(max(fuzz.ratio(vi, vj),
               fuzz.partial_ratio(vi, vj),
               fuzz.token_sort_ratio(vi, vj),
               fuzz.token_set_ratio(vi, vj)))
      vmax=max(v)
      if vmax>=80:
           df1.loc[i,'flag']='Y'
      else:
           df1.loc[i,'flag']='N' 

Но это не сработает с большим набором данных. Есть ли способ оптимизировать это? postal_code может использоваться как условие при нечетком сопоставлении, чтобы уменьшить количество итераций. Также, возможно, я могу прекратить итерации, как только мы достигнем a v= 80.

for i in df1.index:
    v=1
    while v<=80:
        for j in df2.index:
            vi = df1.get_value(i, 'address')
            vj = df2.get_value(j, 'address')
            v= max(fuzz.ratio(vi, vj),
               fuzz.partial_ratio(vi, vj),
               fuzz.token_sort_ratio(vi, vj),
               fuzz.token_set_ratio(vi, vj))
        if v>=80:
           df1.loc[i,'flag']='Y'
        else:
           df1.loc[i,'flag']='N'

Только начал с питона, так что вроде застрял здесь. Пожалуйста помоги!

1 ответ

Решение

Я попробовал некоторые нечеткие сравнения для двух DF, и, насколько мне показалось, нет быстрого способа сделать это. Тот факт, что вы используете 4 fuzz методы замедляют ваш скрипт тоже. Одним из способов может быть использование 'process.extractOne()`и создание такой функции:

from fuzzywuzzy import process
def fw_process(row_df1):
    # Select the addresses from df2 with same postal_code
    df2_select_add = df2['address'][df2['postal_code'] == row_df1['postal_code']]
    ad_1 = row_df1['address']
    # Find the best match for ad_1 in df2_select_add and get the ratio with [1] 
    # for the name of df2_select_add , use [0]
    if process.extractOne(ad_1, df2_select_add)[1] >= 80:
        return 'Y'
    else:
        return 'N'

Затем создать свой флаг столбца в df1, ты сделаешь:

df1['flag'] = df1.apply(fw_process , axis=1)

ПРИМЕЧАНИЕ: имя df2 не вызывается как параметр функции, которая не является более чистым способом, но если она определена ранее в вашем коде с этим именем, она работает.

Если вы хотите сохранить 4 fuzz методы, то вы можете создать функцию по той же идее:

from fuzzywuzzy import fuzz
def fw_fuzz ( row_df1):
    # Select the addresses from df2 with same postal_code
    df2_select_add = df2['address'][df2['postal_code'] == row_df1['postal_code']]
    ad_1 = row_df1['address']
    # Get the max of the max of the 4 fuzz comparison between ad_1 and df2_select_add
    if max (df2_select_add.apply(lambda x: max(fuzz.ratio(ad_1, x), fuzz.partial_ratio(ad_1, x),
                                                fuzz.token_sort_ratio(ad_1, x),fuzz.token_set_ratio(ad_1, x)))) >= 80:
        return 'Y'
    else:
        return 'N'

а потом:

df1['flag'] = df1.apply(fw_fuzz, axis=1)
Другие вопросы по тегам