Панды все еще получают 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

Тем не менее, я все еще получаю то же предупреждение. Что дает?

2 ответа

Решение

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

pd.options.mode.chained_assignment = None

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

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

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

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

complete.is_copy = False

Это быстрее, чем сделать реальную копию, и 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'

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

complete = train.copy()

Я думаю твой .loc решение сработало бы, если бы не np.nans в исходном фрейме данных. Вы могли либоcomplete = train.dropna().reset_index()или Pandas .assign() избегаетSettingWithCopyWarningи это рекомендуемый способ создания новых столбцов с возвратом нового объекта фрейма данных. Ваш пример:

complete = complete.assign(**{'AgeGt15': np.where(complete['Age'] > 15, True, False)})
Другие вопросы по тегам