Почему мой код pandas вызывает предупреждения о назначении и работает медленно? - PullRequest
0 голосов
/ 18 марта 2020

Я делаю проект, в котором мне приходится справляться с множеством диагнозов. Независимо от цели, с точки зрения кодирования, я думаю, что приведенный ниже код верен, однако это занимает много времени (~ 1 час) и всегда показывает мне предупреждения. Есть ли что-то, что я не делаю правильно? Заранее спасибо

# The first 3 values are the only that matters
diagnoses_sec = df[['Diagnóstico 2', 'Diagnóstico 3', 'Diagnóstico 4', 'Diagnóstico 5', 'Diagnóstico 6',
          'Diagnóstico 7', 'Diagnóstico 8', 'Diagnóstico 9', 'Diagnóstico 10', 'Diagnóstico 11', 'Diagnóstico 12', 
          'Diagnóstico 13', 'Diagnóstico 14', 'Diagnóstico 15', 'Diagnóstico 16', 'Diagnóstico 17', 'Diagnóstico 18', 
          'Diagnóstico 19', 'Diagnóstico 20']]
for i in range(0, diagnoses_sec.shape[1]):
    diagnoses_sec.iloc[:,i].fillna("ZZZ", inplace = True)
    diagnoses_sec.iloc[:,i] = diagnoses_sec.iloc[:,i].str.slice(start=0, stop=3, step=1)

В этой части есть предупреждение, но я не могу понять, почему:

C:\Users\Asus\Anaconda3\lib\site-packages\pandas\core\indexing.py:630: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self.obj[item_labels[indexer[info_axis]]] = value

Вторая часть кода такова:

from bisect import bisect_left

diag_icd10_ranges = ["B99","D49","D89","E89","F99","G99","H59","H95",
          "I99","J99","K95", "L99", "M99", "N99","O9A","P96","Q99",
          "R99","T88","Y99","Z99","ZZZ"]

diag_icd10_dict = {0: 'infectious_icd10d', 1: 'neoplasms_icd10d', 2: 'blood_icd10d', 3: 'endocrine_icd10d',
                   4: 'mental_icd10d', 5: 'nervous_icd10d', 6: 'eye_icd10d', 7: 'ear_icd10d',
                   8: 'circulatory_icd10d', 9: 'respiratory_icd10d', 10: 'digestive_icd10d', 11: 'skin_icd10d', 
                  12: 'musculo_icd10d', 13: 'genitourinary_icd10d', 14: 'pregnancy_icd10d', 15: 'perinatalperiod_icd10d', 
                  16: 'congenital_icd10d',
                  17: 'abnormalfindings_icd10d', 18:'injury_icd10d', 19:'morbidity', 20:'healthstatus', 21:'Nan_Category'}

# function to categorize every patient
def icdGroup(code): return bisect_left(diag_icd10_ranges,code)

# loop for the categorisation of every patient in every diagnose
for i_diag_sec in range(0,diagnoses_sec.shape[1]):
    for i_within_diag_sec in range(0, len(diagnoses_sec)):
        diagnoses_sec.iloc[i_within_diag_sec,i_diag_sec] = icdGroup(diagnoses_sec.iloc[i_within_diag_sec,i_diag_sec])

И еще раз у меня есть еще одно предупреждение:

C:\Users\Asus\Anaconda3\lib\site-packages\ipykernel_launcher.py:20: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

1 Ответ

0 голосов
/ 18 марта 2020

Вы получаете эти SettingWithCopyWarning предупреждающие сообщения, поскольку diagnoses_sec является копией части df; установка значений в этой копии вызывает предупреждение, чтобы вы знали об этом - ваши изменения не будут распространяться обратно до df. Эти предупреждения исчезнут, если вы явно сделаете копию, используя метод copy, например:

diagnoses_sec = df[['Diagnóstico 2', 'Diagnóstico 3']].copy()

Относительно времени, затрачиваемого на выполнение вашего кода, итерации по pandas DataFrame s таким образом неэффективен, и вы должны стремиться использовать векторизованные операции, применяя функцию или операцию ко всему массиву.

Вы можете изменить свой первый пример, чтобы сделать это:

diagnoses_sec = df[['Diagnóstico 2', 'Diagnóstico 3', 'Diagnóstico 4', 'Diagnóstico 5', 'Diagnóstico 6',
          'Diagnóstico 7', 'Diagnóstico 8', 'Diagnóstico 9', 'Diagnóstico 10', 'Diagnóstico 11', 'Diagnóstico 12', 
          'Diagnóstico 13', 'Diagnóstico 14', 'Diagnóstico 15', 'Diagnóstico 16', 'Diagnóstico 17', 'Diagnóstico 18', 
          'Diagnóstico 19', 'Diagnóstico 20']].copy()
diagnoses_sec.fillna("ZZZ", inplace=True)
diagnoses_sec = diagnoses_sec.apply(lambda x: x.str.slice(start=0, stop=3, step=1))

Здесь fillna применяется ко всему DataFrame и заменяет каждое значение NA на "ZZZ". Во второй операции apply с помощью функции lambda выполнит операцию среза строки в каждом столбце (Series) вашего diagnoses_sec DataFrame.

Ваш второй случай аналогичен, хотя, поскольку ваша icdGroup функция не векторизована (она не работает с DataFrame или Series) и применяется к каждой ячейке вашего DataFrame, вы можете использовать applymap чтобы выполнить его для каждого значения:

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