Выполнить слияние на основе совпадения подстроки?
Хотя этот вопрос тесно связан с слиянием нечетких совпадений с пандами, этот вопрос конкретно касается только слияния (или подмножества, в данном случае), когда ключ в одном DataFrame
полное совпадение или подстрока ключа в другом DataFrame
, Чтобы проиллюстрировать мою точку зрения, вот 2 DataFrames
:
df1
id code
0 1 E282
1 2 O0080
2 3 R52
3 4 J0100
4 5 F99
df2
code val
0 V282 11
1 O008 12
2 J0101 13
3 F99 14
4 R55 15
Проблема с использованием difflib
в том, что я действительно не хочу сопоставлять ближайшую строку, и я не уверен, что смогу разделить совпадения как V282
в E282
, чего не должно случиться и подобного O008
в O0080
который должен слиться.
Ожидаемый результат должен быть
code1 id
0 O0080 2
1 F99 5
Я могу добраться до этого результата с
import numpy as np
df1[np.logical_or.reduce([df1['code'].str.contains(code) for code in df2.code.tolist()])]
но с тех пор df1
длиной 42M и df2
содержит ~4000 кодов, этот метод невероятно медленный. Это лучшее, что я собираюсь сделать? Просто кажется прискорбным, когда внутреннее объединение строки 21M df и строки 7M df для точных ключей занимает < 1 минуту.
1 ответ
Это сложная проблема. Может быть, рассмотреть подход Python? any
здесь будет короткое замыкание, поэтому вы должны сэкономить на некоторых циклах. Также, contains
не обязательно проверять с самого начала, поэтому использование startswith
вместо этого должен быть более эффективным.
df1[
any(
i.startswith(j) for j in df2.codes.tolist()
) for i in df1.codes.tolist()
]
Что о:
import pandas as pd
df1 = pd.DataFrame({'id':[1,2,3,4,5], 'code':['E282', 'O0080', 'R52', 'J0100', 'F99']})
df2 = pd.DataFrame({'code':['V282','O008','J0101','F99','R55'], 'val':[11,12, 13, 14, 15]})
pat = "|".join(df2['code'])
df1.insert(0, 'part_code', df1['code'].str.extract("(" + pat + ')', expand=False))
pd.merge(df1, df2, how='inner', left_on='part_code', right_on='code')[['code_y', 'id']]
На основе /questions/5098695/python-pandas-obedinenie-na-osnove-podstroki-v-stroke/5098698#5098698