#python #pandas #dataframe
#python #pandas #фрейм данных
Вопрос:
У меня есть столбец, в котором много специальностей врачей. Я хочу ее очистить и создал функцию ниже:
def specialty(x):
if x.str.contains('Urolog'):
return 'Urology'
elif x.str.contains('Nurse'):
return 'Nurse Practioner'
elif x.str.contains('Oncology'):
return 'Oncology'
elif x.str.contains('Physician'):
return 'Physician Assistant'
elif x.str.contains('Family Medicine'):
return 'Family Medicine'
elif x.str.contains('Anesthes'):
return 'Anesthesiology'
else:
return 'Other'
df['desc_clean'] = df['desc'].apply(specialty)
Однако я получаю сообщение об ошибке TypeError: 'function' object is not subscriptable
Слишком много значений для использования ручного сопоставления, поэтому я хотел использовать str.contains. Есть ли способ сделать это лучше?
РЕДАКТИРОВАТЬ: пример DF
{'person_id': {39063: 33081476009,
50538: 33033519093,
56075: 33170508793,
36593: 33061707789,
51656: 33047685345,
95512: 33022026049,
40286: 33038034707,
3887: 33076466195,
40161: 33052807819,
52905: 33190526939,
35418: 33008425164,
35934: 33015737122,
3389: 33055125864,
136: 33139641318,
105460: 33113871389,
52568: 33075745388,
24725: 33052090907,
34838: 33205449839,
31908: 33183672635,
36115: 33006692696},
'final_desc': {39063: 'None',
50538: 'Urology',
56075: 'Anesthesiology',
36593: 'None',
51656: 'Urology',
95512: 'None',
40286: 'Anesthesiology',
3887: 'Specialist',
40161: 'None',
52905: 'Anesthesiology',
35418: 'Urology',
35934: 'None',
3389: 'Ophthalmology',
136: 'Rheumatology',
105460: 'None',
52568: 'Urology',
24725: 'Family Medicine',
34838: 'None',
31908: 'Nurse Practitioner',
36115: 'None'}}
Комментарии:
1. можете ли вы предоставить образец вашего фрейма данных?
2. может быть, df.sample(n = 20).to_dict() или что-то в этом роде
3. добавлено! Спасибо
4. это похоже на вывод — как насчет входного текста / столбца?
5. добавлено решение для нечеткого сопоставления, которое может вас заинтересовать.
Ответ №1:
Для этого мы можем определить сопоставление между совпадениями, затем выполнить итерацию по ним и установить значение столбца, отслеживая столбцы, которые мы изменили. В конце все столбцы, которые мы никогда не сопоставляли, будут установлены 'Other'
.
mapping = {'Urolog': 'Urology',
'Nurse': 'Nurse Practioner',
'Oncology': 'Oncology',
'Physician': 'Physician Assistant',
'Family Medicine': 'Family Medicine',
'Anesthes': 'Anesthesiology'}
def specialty(column):
column = column.copy()
matches = pd.Series(False, index=column.index)
for k,v in mapping.items():
match = column.str.contains(k)
column[match] = v
matches[match] = True
column[~matches] = 'Other'
return column
specialty(df['final_desc'])
39063 Other
50538 Urology
56075 Anesthesiology
36593 Other
51656 Urology
95512 Other
40286 Anesthesiology
3887 Other
40161 Other
52905 Anesthesiology
35418 Urology
35934 Other
3389 Other
136 Other
105460 Other
52568 Urology
24725 Family Medicine
34838 Other
31908 Nurse Practioner
36115 Other
Name: final_desc, dtype: object
Ответ №2:
x, полученный специальной функцией, является самой строкой. Итак, нет x.str, и поскольку это строка, вы можете использовать ‘in’ для проверки, как показано ниже. Изменил некоторые данные, чтобы увидеть результат Совет: вы должны использовать словарь или список, а не использовать цепочку elif.
Код:
import pandas as pd
import numpy as np
def specialty(x):
print(x)
if x in 'Urolog':
return 'Urology'
elif x in 'Nurse':
return 'Nurse Practioner'
elif x in 'Oncology':
return 'Oncology'
elif x in 'Physician':
return 'Physician Assistant'
elif x in 'Family Medicine':
return 'Family Medicine'
elif x in 'Anesthes':
return 'Anesthesiology'
else:
return 'Other'
df = pd.DataFrame(data={'person_id': {39063: 33081476009, 50538: 33033519093, 56075: 33170508793, 36593: 33061707789, 51656: 33047685345, 95512: 33022026049, 40286: 33038034707, 3887: 33076466195, 40161: 33052807819, 52905: 33190526939, 35418: 33008425164, 35934: 33015737122, 3389: 33055125864, 136: 33139641318, 105460: 33113871389, 52568: 33075745388, 24725: 33052090907, 34838: 33205449839, 31908: 33183672635, 36115: 33006692696},
'final_desc': {39063: 'None', 50538: 'Urolog', 56075: 'Anesthes', 36593: 'None', 51656: 'Urology', 95512: 'None', 40286: 'Anesthes', 3887: 'Specialist', 40161: 'None', 52905: 'Anesthesiology', 35418: 'Urology', 35934: 'None', 3389: 'Ophthalmology', 136: 'Rheumatology', 105460: 'None', 52568: 'Urology', 24725: 'Family Medicine', 34838: 'None', 31908: 'Nurse', 36115: 'None'}})
df['desc_clean'] = df['final_desc'].apply(specialty)
print(df)
Вывод:
person_id final_desc desc_clean
39063 33081476009 None Other
50538 33033519093 Urolog Urology
56075 33170508793 Anesthes Anesthesiology
36593 33061707789 None Other
51656 33047685345 Urology Other
95512 33022026049 None Other
40286 33038034707 Anesthes Anesthesiology
3887 33076466195 Specialist Other
40161 33052807819 None Other
52905 33190526939 Anesthesiology Other
35418 33008425164 Urology Other
35934 33015737122 None Other
3389 33055125864 Ophthalmology Other
136 33139641318 Rheumatology Other
105460 33113871389 None Other
52568 33075745388 Urology Other
24725 33052090907 Family Medicine Family Medicine
34838 33205449839 None Other
31908 33183672635 Nurse Nurse Practioner
36115 33006692696 None Other
Ответ №3:
Вы можете использовать библиотеку, например fuzzywuzzy
, для сопоставления нечетких строк. Преимущество этого подхода в том, что он более гибкий, чем некоторый набор правил, как показано ниже.
Это решение генерирует максимальное количество подстрок и категорий кандидатов, возвращая ту, которая соответствует наилучшим образом. Если значение ниже порогового значения, оно вернет значение по умолчанию («None»):
from fuzzywuzzy import fuzz
CATEGORIES = [
'Urology',
'Nurse Practioner',
'Oncology',
'Physician Assistant',
'Family Medicine',
'Anesthesiology',
'Specialist',
]
def best_match(
text,
categories=CATEGORIES,
default="None",
threshold=65
):
matches = {fuzz.partial_ratio(cat, text): cat for cat in categories}
best_score = max(matches)
best_match = matches[best_score]
if best_score >= threshold:
return best_match
else:
return default
df["final_desc"] = df.desc.apply(best_match)
Результат:
person_id final_desc desc
52568 33075745388 Urology urologist
36593 33061707789 Nurse Practioner nruse practition
136 33139641318 Specialist oncology specialist
50538 33033519093 Physician Assistant physicians assistant
3389 33055125864 Family Medicine fam. medicine
51656 33047685345 Anesthesiology anesthesiology
35418 33008425164 Anesthesiology anesthesiologist
52905 33190526939 Nurse Practioner Nurses practitioner
36115 33006692696 Specialist Occupational specialist
31908 33183672635 Oncology Oncologist
Ответ №4:
Вы можете выполнить итерацию напрямую, используя индекс :
ix = df[df.desc.str.contains('Urolog')].index
df.loc[ix, 'desc_clean'] = "Urology"
Таким образом, итерация будет выглядеть примерно так :
dict_specialties = {"Urolog":"Urology",}
for key, val in dict_specialties.items():
ix = df[df.desc.str.contains(key)].index
df.loc[ix, 'desc_clean'] = val