Я хотел бы объединить 2 фрейма данных по приблизительному названию страны с помощью слияния по состоянию на но я получаю следующую ошибку:
TypeError: объект «NoneType» не может быть вызван
См. иллюстративный код ниже:
cl = {'Country' : ["Brazil", "US", "Russia"], 'BL?':['No', 'No','Yes']}
clist = pd.DataFrame.from_dict(cl)
cd = {'Country' : ["Braizl", "us", "Rusia"]}
cdata = pd.DataFrame.from_dict(cd)
clist = clist.sort_values('Country')
cdata = cdata.sort_values('Country')
cdata = pd.merge_asof(cdata,clist,on='Country')
Ожидаемый результат объединит две df, а cdata df будет иметь 'BL?' столбец со значениями ДА/НЕТ.
Заранее спасибо!
Правда, я получаю, что объект nonetype теперь не вызывается после удаления на месте
я отредактировал код
Я думаю, что merge_asof работает только с целыми числами. Если вы не хотите найти ближайшую строку к другой, вы можете использовать расстояние Левенштейна, но я не знаю о какой-либо его реализации в библиотеке Pandas.
Как бы я применил это к 2 диктовкам?
см. это: stackoverflow.com/questions/13636848/…
Это не работает для этого, я уже видел это






Учитывая ваш пример, я пришел к решению. Это не очень pythonic, но это работает! (при условии, что у вас есть совпадающее название страны в clist для каждой страны с ошибкой cdata)
def get_closest(x, column):
tmp = 1000
for i2, r2 in clist.iterrows():
levenshtein = editdistance.eval(x,r2['Country'])
if levenshtein <= tmp:
tmp = levenshtein
res = r2
return res['BL?']
cdata['BL'] = cdata['Country'].apply(lambda x: get_closest(x, clist))
Вывод :
Country BL
0 Braizl No
1 us No
2 Rusia Yes
Я использую библиотеку изменить расстояние для вычисления расстояния Левенштейна. Вы можете установить его с помощью pip :
pip install editdistance
Ну должно быть два. Можете ли вы опубликовать, как выглядит ваш код?
Это должно приблизить вас, но это не будет на 100% точным. Вы можете использовать пушистый. fuzzywuzzy использует расстояние Левенштейна для вычисления разницы между двумя строками:
from fuzzywuzzy import process
# create a choice list
choices = clist['Country'].values.tolist()
# apply fuzzywuzzy to each row using lambda expression
cdata['Close Country'] = cdata['Country'].apply(lambda x: process.extractOne(x, choices)[0])
# merge
cdata.merge(clist, left_on='Close Country', right_on='Country')
Country_x Close Country Country_y BL?
0 Braizl Brazil Brazil No
1 Rusia Russia Russia Yes
2 us US US No
Вы даже можете вернуть процентное совпадение и сохранить только значения > n, если вы хотите сохранить только совпадения, скажем, больше 85%
from fuzzywuzzy import process
# create a choice list
choices = clist['Country'].values.tolist()
# apply fuzzywuzzy to each row using lambda expression
cdata['Close Country'] = cdata['Country'].apply(lambda x: process.extractOne(x, choices))
# add percent match wiht apply
cdata[['Close Country', 'Percent Match']] = cdata['Close Country'].apply(pd.Series)
# merge
cdata.merge(clist, left_on='Close Country', right_on='Country')
Country_x Close Country Percent Match Country_y BL?
0 Braizl Brazil 83 Brazil No
1 Rusia Russia 91 Russia Yes
2 us US 100 US No
вы можете выполнить логическое индексирование либо перед слиянием, чтобы удалить плохое совпадение, либо слить:
cdata[['Close Country', 'Percent Match']] = cdata['Close Country'].apply(pd.Series)
cdata = cdata[cdata['Percent Match']>85]
или вы можете сделать это после слияния:
merge = cdata.merge(clist, left_on='Close Country', right_on='Country')
merge[merge['Percent Match'] > 85]
fuzzywuzzy возвращает процент совпадения как часть функции process. В первом примере я удалил его, вызвав первый элемент кортежа: process.extractOne(x, choices)[0]
Браво! Большое тебе спасибо!
Как я могу вернуть совпадение%?
@TPguru Вы хотите, чтобы это была новая колонка?
Да, это было бы отлично
Попробуйте заменить from fuzzywuzzy import process на from rapidfuzz import process. Вы увидите резкое улучшение времени выполнения с теми же результатами.
inplace=Trueзаставляет sort_values возвращатьNone, потому что вы указываете метод, чтобы сделать это на месте