Pandas все еще получает SettingWithCopyWarning даже после использования .loc

Сначала я попытался написать код, который выглядел бы так:

import numpy as np
import pandas as pd
np.random.seed(2016)
train = pd.DataFrame(np.random.choice([np.nan, 1, 2], size=(10, 3)), 
                     columns=['Age', 'SibSp', 'Parch'])

complete = train.dropna()    
complete['AgeGt15'] = complete['Age'] > 15

Получив SettingWithCopyWarning, я попытался использовать .loc:

complete.loc[:, 'AgeGt15'] = complete['Age'] > 15
complete.loc[:, 'WithFamily'] = complete['SibSp'] + complete['Parch'] > 0

Однако я все равно получаю такое же предупреждение. Что дает?

Ответ 1

Примечание. Начиная с версии 0.24 для панд is_copy устарела и будет удалена в следующей версии. Хотя закрытый атрибут _is_copy существует, подчеркивание указывает, что этот атрибут не является частью общедоступного API и поэтому не должен зависеть от него. Поэтому, в дальнейшем, кажется, что единственный правильный способ заставить замолчать SettingWithCopyWarning - сделать это глобально:

pd.options.mode.chained_assignment = None

При complete = train.dropna() выполняются, dropna может вернуть копию, так что из - за излишнюю осторожность, Панды устанавливают complete.is_copy к Truthy значения:

In [220]: complete.is_copy
Out[220]: <weakref at 0x7f7f0b295b38; to 'DataFrame' at 0x7f7eee6fe668>

Это позволяет Pandas предупреждать вас позже, когда будет complete['AgeGt15'] = complete['Age'] > 15 что вы можете изменять копию, которая не будет влиять на train. Для начинающих это может быть полезным предупреждением. В вашем случае, похоже, у вас нет намерения изменять train опосредованно путем изменения complete. Поэтому предупреждение - это просто бессмысленное раздражение в вашем случае.

Вы можете отключить предупреждение, установив,

complete.is_copy = False       # deprecated as of version 0.24

Это быстрее, чем создание фактической копии, и SettingWithCopyWarning в зародыше (в точке, где _check_setitem_copy):

def _check_setitem_copy(self, stacklevel=4, t='setting', force=False):
    if force or self.is_copy:
        ...

Если вы действительно уверены, что знаете, что делаете, вы можете отключить SettingWithCopyWarning глобально с помощью

pd.options.mode.chained_assignment = None # None|'warn'|'raise'

Альтернативный способ заставить предупреждение замолчать - сделать новую копию:

complete = complete.copy()

Тем не менее, вы можете не захотеть делать это, если размер DataFrame велик, поскольку копирование может занимать значительное количество времени и памяти, и это совершенно бессмысленно (за исключением того, чтобы заставить замолчать предупреждение), если вы знаете, что complete - это уже копия,

Ответ 2

Я разрешаю это, создавая копию dataframe:

complete = train.copy()