Как написать функцию для получения значения через 2 кадра данных, используя итерацию в Python - PullRequest
0 голосов
/ 01 июня 2019

Я получил два фрейма данных, A длиной 2173 и B длиной 6135. A называется 'file_name', B называется 'crsp_name'

A.head()
                    file_name
0                       3M CO
1         ABBOTT LABORATORIES
2                     ABC INC
3            ALTRIA GROUP INC
4  AMERICAN ELECTRIC POWER CO
B.head()
0      A & E PLASTIK PAK INC
1    A & M FOOD SERVICES INC
2                 A A I CORP
3          A A IMPORTING INC
4                 A A R CORP
Name: comnam, dtype: object

Я пытался вычислить fuzz.token_set_ratioкаждого элемента в A с B и объединить их как один фрейм данных. Например, вычислите соотношение «3M CO» с каждым элементом в B и объедините «3M» и наибольшее соотношение в виде одной строки во фрейме данных.таким образом, я ожидал получить фрейм данных формы (2173,2)

Вот моя функция, я пытаюсь использовать 'apply' и мою 'fuzzratio' функцию для вычисления желаемого отношения.Но произошла ошибка, надеюсь, кто-нибудь может дать мне правильное решение.

def fuzzratio(x):
    global crsp_name
    ratio_list = list()
    name_list = list()
    for i in crsp_name:
        ratio = fuzz.token_set_ratio(x,i)
        if ratio > 80:
            name_list.append(x)
            ratio_list.append(ratio)
    name_list = pd.DataFrame(name_list)
    result = pd.merge(name_list,ratio_list).rename(columns = {'comnam','ratio'})
    return result

file_name.apply(fuzzratio)

ошибка:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/frame.py", line 6004, in apply
    return op.get_result()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/apply.py", line 318, in get_result
    return super(FrameRowApply, self).get_result()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/apply.py", line 142, in get_result
    return self.apply_standard()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/apply.py", line 248, in apply_standard
    self.apply_series_generator()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/apply.py", line 277, in apply_series_generator
    results[i] = self.f(v)
  File "<stdin>", line 11, in fuzzratio
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/reshape/merge.py", line 60, in merge
    validate=validate)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/reshape/merge.py", line 526, in __init__
    'type {right}'.format(right=type(right)))
ValueError: ("can not merge DataFrame with instance of type <class 'list'>", 'occurred at index file_name')

1 Ответ

1 голос
/ 01 июня 2019

Я создал тестовые данные следующим образом:

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 раза быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...