Confusion re: pandas копия фрагмента предупреждения о кадре данных

Я просмотрел множество вопросов и ответов, связанных с этой проблемой, но я все еще нахожу, что получаю эту копию предупреждения о срезе в местах, где я этого не ожидаю. Кроме того, он появился в коде, который работал для меня раньше, что заставило меня задаться вопросом, может ли быть виной какого-либо обновления.

Например, это набор кода, где все, что я делаю, - это чтение в файле Excel в pandas DataFrame и сокращение набора столбцов, включенных в синтаксис df[[]].

 izmir = pd.read_excel(filepath)
 izmir_lim = izmir[['Gender','Age','MC_OLD_M>=60','MC_OLD_F>=60','MC_OLD_M>18','MC_OLD_F>18','MC_OLD_18>M>5','MC_OLD_18>F>5',
               'MC_OLD_M_Child<5','MC_OLD_F_Child<5','MC_OLD_M>0<=1','MC_OLD_F>0<=1','Date to Delivery','Date to insert','Date of Entery']]

Теперь любые дальнейшие изменения, которые я делаю в этом файле izmir_lim поднимут копию предупреждения о срезе.

izmir_lim['Age'] = izmir_lim.Age.fillna(0)
izmir_lim['Age'] = izmir_lim.Age.astype(int)

/Users/samlilienfeld/anaconda/lib/python3.5/site-packages/ipykernel/main.py: 2: SettingWithCopyWarning: значение пытается установить на копии среза из DataFrame. Попробуйте вместо этого использовать.loc [row_indexer, col_indexer] = значение

Я смущен, потому что я думал, что подстрока столбца df[[]] вернула копию по умолчанию. Единственный способ, которым я нашел подавление ошибок, - это явно добавить df[[]].copy(). Я мог бы поклясться, что в прошлом мне не приходилось это делать и не поднимал копию ошибки среза.

Аналогично, у меня есть другой код, который выполняет функцию на фреймворке данных, чтобы фильтровать его определенным образом:

def lim(df):
if (geography == "All"):
    df_geo = df
else:
    df_geo = df[df.center_JO == geography]

df_date = df_geo[(df_geo.date_survey >= start_date) & (df_geo.date_survey <= end_date)]

return df_date

df_lim = lim(df)

С этого момента любые изменения, которые я делаю для любого из значений df_lim создают копию ошибки среза. Единственный способ, которым я нашел, - это изменить вызов функции:

df_lim = lim(df).copy()

Это кажется мне неправильным. Что мне не хватает? Кажется, что эти случаи использования должны возвращать копии по умолчанию, и я мог бы поклясться, что в последний раз, когда я запускал эти сценарии, я не сталкивался с этими ошибками.
Нужно ли просто начинать добавлять .copy() повсюду? Похоже, что должен быть более чистый способ сделать это. Любое понимание или помощь очень ценятся.

Ответ 1

 izmir = pd.read_excel(filepath)
 izmir_lim = izmir[['Gender','Age','MC_OLD_M>=60','MC_OLD_F>=60',
                    'MC_OLD_M>18','MC_OLD_F>18','MC_OLD_18>M>5',
                    'MC_OLD_18>F>5','MC_OLD_M_Child<5','MC_OLD_F_Child<5',
                    'MC_OLD_M>0<=1','MC_OLD_F>0<=1','Date to Delivery',
                    'Date to insert','Date of Entery']]

izmir_lim - это вид/копия izmir. Затем вы пытаетесь назначить ему. Это то, что бросает ошибку. Используйте это вместо этого:

 izmir_lim = izmir[['Gender','Age','MC_OLD_M>=60','MC_OLD_F>=60',
                    'MC_OLD_M>18','MC_OLD_F>18','MC_OLD_18>M>5',
                    'MC_OLD_18>F>5','MC_OLD_M_Child<5','MC_OLD_F_Child<5',
                    'MC_OLD_M>0<=1','MC_OLD_F>0<=1','Date to Delivery',
                    'Date to insert','Date of Entery']].copy()

Всякий раз, когда вы "создаете" новую структуру данных из другого, следующим образом:

new_df = old_df[list_of_columns_names]

new_df будет иметь правдивое значение в is_copy. Когда вы SettingWithCopyWarning назначить ему, pandas выдает команду SettingWithCopyWarning.

new_df.iloc[0, 0] = 1  # Should throw an error

Вы можете преодолеть это несколькими способами.

Опция 1

new_df = old_df[list_of_columns_names].copy()

Вариант № 2 (как @ayhan, предложенный в комментариях)

new_df = old_df[list_of_columns_names]
new_df.is_copy = None

Вариант № 3

new_df = old_df.loc[:, list_of_columns_names]