как создать категориальное поле в фрейме данных на основе значений в другом фрейме данных - PullRequest
0 голосов
/ 08 февраля 2019

Мне нужно создать категориальную переменную на основе значения в другом фрейме данных.Рассмотрим таблицу 1, в которой есть посещения больниц и идентификаторы пациентов.Обратите внимание, что пациент может посещать больницу более одного раза:

+----------+------------+
| visit_id | patient_id |
+----------+------------+
|       10 |          1 |
|       20 |          1 |
|       50 |          2 |
|      100 |          3 |
|      110 |          3 |
+----------+------------+

Мне нужно добавить новое поле со значением 1 или 0, указывающим, получал ли пациент аспирин во время посещения больницы, что показано в таблице 2:

+----------+------------+---------------+
| visit_id | patient_id |  medication   |
+----------+------------+---------------+
|       10 |          1 | aspirin       |
|       10 |          1 | ibuprofin     |
|       20 |          1 | codine        |
|       50 |          2 | aspirin       |
|      100 |          3 | ibuprofin     |
|      110 |          3 | acetaminophin |
|      110 |          3 | vicodin       |
+----------+------------+---------------+

Вы можете снова увидеть несколько уровней - вы можете получить более одного лекарства от врача, верно?Это всего лишь пример, конечно.

Я пытался объединить таблицы (внутреннее объединение), что сработало ...

tab1 = pd.merge(tab1, tab2, on=['visit_id','patient_id'])

tab1['aspirin_index'] = np.where(tab1['medication'].str.contains('aspirin', 
       flags=re.IGNORECASE, regex=True, na=False),1,0)

... но затем я получил дубликаты для пациента 1, который получил аспирин и ибупрофен,Мне просто нужно знать, получали ли они аспирин хотя бы один раз.

+----------+------------+---------------+
| visit_id | patient_id | aspirin_index |
+----------+------------+---------------+
|       10 |          1 |             1 |
|       10 |          1 |             0 |
+----------+------------+---------------+

Мне нужно попасть сюда ... такой же формы, как в таблице 1, но только с новым индексом.

+----------+------------+---------------+
| visit_id | patient_id | aspirin_index |
+----------+------------+---------------+
|       10 |          1 |             1 |
|       20 |          1 |             0 |
|       50 |          2 |             1 |
|      100 |          3 |             0 |
|      110 |          3 |             0 |
+----------+------------+---------------+

1 Ответ

0 голосов
/ 08 февраля 2019

Сначала давайте настроим ваши образцы данных.

# setup tab1 & tab2
tab1 = pd.DataFrame([[10, 1], [20, 1], [50, 2], [100, 3], [110, 3]], columns=["visit_id","patient_id"])
tab2 = pd.DataFrame([[10, 1, "aspirin"], [10, 1, "ibuprofin"], [20, 1, "codine"], [50, 2, "aspirin"], [100, 3, "ibuprofin"], [110, 3, "acetominophin"], [110, 3, "vicodin"]], columns=["visit_id","patient_id", "medication"])

Есть много способов сделать это.Один из подходов может состоять в том, чтобы отфильтровать tab2 только до аспирина, присоединить его к tab1 с помощью «левого» соединения, а затем заполнить нулями 0.

# filter tab2 to aspirin only
# change column name
# change to 1/0 instead of text since it now only refers to aspirin
aspirin = tab2.loc[tab2.medication=="aspirin"].copy()
aspirin.columns = ["visit_id", "patient_id", "aspirin_index"]
aspirin["aspirin_index"] = 1

# left-outer merge and fill nulls
tab1 = pd.merge(tab1, aspirin, how="left", on=["visit_id","patient_id"])
tab1.aspirin_index.fillna(0, inplace=True)
tab1["aspirin_index"] = tab1.aspirin_index.astype("int")

#  visit_id  patient_id  aspirin_index
#        10           1              1
#        20           1              0
#        50           2              1
#       100           3              0
#       110           3              0

, что даст вам один столбец с «aspirin_index».Так что это достигает вашей цели.

Но как насчет того же упражнения одновременно со ВСЕМИ наркотиками ... включая аспирин?В sklearn есть несколько функций предварительной обработки, которые облегчают эту задачу.

from sklearn import preprocessing

le = preprocessing.LabelEncoder()
lb = preprocessing.LabelBinarizer()

# convert each drug into a column of 1's and 0's
all_drugs = pd.DataFrame(lb.fit_transform(le.fit_transform(tab2.medication)), columns=le.classes_)

# concat with source data, aggregate, and clean up
tab2 = pd.concat((tab2.loc[:,["visit_id", "patient_id"]].copy(), all_drugs), axis=1)
tab2 = tab2.groupby(["visit_id", "patient_id"]).agg(np.sum)
tab2.reset_index(inplace=True)

#  visit_id  patient_id  acetominophin  aspirin  codine  ibuprofin  vicodin
#        10           1              0        1       0          1        0
#        20           1              0        0       1          0        0
#        50           2              0        1       0          0        0
#       100           3              0        0       0          1        0
#       110           3              1        0       0          0        1

Это довольно распространенный подход для получения категориальных данных в виде столбцов двоичных объектов.Но это занимает много места.

Как насчет того, чтобы придерживаться одного столбца, в котором указаны все лекарства для этого посещения в списке?Это позволило бы вам выполнять поиск текста и не иметь плотных столбцов, состоящих в основном из 0, для редких лекарств.

# create tab1 with ALL meds taken on each visit
tab2 = tab2.groupby(["visit_id", "patient_id"]).agg({"medication": list})
tab1 = pd.merge(tab1, tab2, how="left", on=["visit_id","patient_id"])

#  visit_id  patient_id                medication
#        10           1      [aspirin, ibuprofin]
#        20           1                  [codine]
#        50           2                 [aspirin]
#       100           3               [ibuprofin]
#       110           3  [acetominophin, vicodin]

# helper function to extract records for ANY drug
def drug_finder(drug):
  idx = tab1.medication.apply(lambda drugs: drug in drugs)
  return tab1.loc[idx].copy()

# find aspirin
drug_finder("aspirin")

#  visit_id  patient_id            medication
#        10           1  [aspirin, ibuprofin]
#        50           2             [aspirin]

# find ibuprofin
drug_finder("ibuprofin")

#  visit_id  patient_id            medication
#        10           1  [aspirin, ibuprofin]
#       100           3           [ibuprofin]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...