Как бороться с SettingWithCopyWarning у панд?
фон
Я только что обновил свои панды с 0.11 до 0.13. 0rc1. Теперь, приложение выскакивает много новых предупреждений. Один из них такой:
E:FinReporterFM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
Я хочу знать, что именно это означает? Нужно ли мне что-то менять?
как я должен приостановить предупреждение, если я настаиваю на использовании quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE?
функция, которая дает ошибки
def _decode_stock_quote(list_of_150_stk_str):
"""decode the webpage and return dataframe"""
from cStringIO import StringIO
str_of_all = "".join(list_of_150_stk_str)
quote_df = pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
quote_df.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
quote_df['TClose'] = quote_df['TPrice']
quote_df['RT'] = 100 * (quote_df['TPrice']/quote_df['TPCLOSE'] - 1)
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
quote_df['TAmt'] = quote_df['TAmt']/TAMT_SCALE
quote_df['STK_ID'] = quote_df['STK'].str.slice(13,19)
quote_df['STK_Name'] = quote_df['STK'].str.slice(21,30)#.decode('gb2312')
quote_df['TDate'] = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
return quote_df
больше сообщений об ошибках
E:FinReporterFM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
E:FinReporterFM_EXT.py:450: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TAmt'] = quote_df['TAmt']/TAMT_SCALE
E:FinReporterFM_EXT.py:453: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TDate'] = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
4 ответов:
The
SettingWithCopyWarningбыл создан, чтобы отметить потенциально запутанные" цепные " назначения, такие как следующие, которые не всегда работают должным образом, особенно когда первый выбор возвращает скопировать. [см.GH5390 и GH5597 для общего обсуждения.]df[df['A'] > 2]['B'] = new_val # new_val not set in dfпредупреждение предлагает переписать следующим образом:
df.loc[df['A'] > 2, 'B'] = new_valоднако это не соответствует вашему использованию, что эквивалентно к:
df = df[df['A'] > 2] df['B'] = new_valхотя ясно, что вы не заботитесь о том, чтобы записи возвращались к исходному кадру (поскольку вы переписали ссылку на него), к сожалению, этот шаблон не может быть отличен от первого примера цепного назначения, следовательно, (ложноположительное) предупреждение. Потенциал ложных срабатываний рассматривается в документы по индексации, если вы хотите, читать далее. Вы можете безопасно отключить это новое предупреждение следующим образом назначение.
pd.options.mode.chained_assignment = None # default='warn'
в общем суть
SettingWithCopyWarningэто показать пользователям (и особенно новым пользователям), что они мая работать на копии, а не оригинал, как они думают. Там are ложные срабатывания (я знаю, что вы делаете, так что это ОК). Одна из возможностей-просто отключить (по умолчанию предупредить) предупреждение ,как @ Garrett предложить.вот nother, за вариант.
In [1]: df = DataFrame(np.random.randn(5,2),columns=list('AB')) In [2]: dfa = df.ix[:,[1,0]] In [3]: dfa.is_copy Out[3]: True In [4]: dfa['A'] /= 2 /usr/local/bin/ipython:1: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead #!/usr/local/bin/pythonвы можете установить
is_copyфлаг toFalse, что позволит эффективно отключить проверку, *для этого объекта"In [5]: dfa.is_copy = False In [6]: dfa['A'] /= 2если вы явно копируете, то вы знай, что ты делаешь, так что больше никаких предупреждений не будет.
In [7]: dfa = df.ix[:,[1,0]].copy() In [8]: dfa['A'] /= 2код, который OP показывает выше, в то время как законный, и, вероятно, что-то я делаю, технически является случаем для этого предупреждения, а не ложным положительным. Еще один способ не имейте предупреждение было бы сделать операцию выбора через
reindex, например,quote_df = quote_df.reindex(columns=['STK',.......])или
quote_df = quote_df.reindex(['STK',.......], axis=1) # v.0.21
Pandas dataframe copy warning
когда вы идете и делаете что-то вроде этого:
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
pandas.ixв этом случае возвращает новый, автономный фрейм данных.любые значения, которые вы решили изменить в этом фрейме данных, не изменят исходный фрейм данных.
это то, о чем панды пытаются предупредить вас.
почему
.ix- это плохая идеяThe
чтобы устранить любые сомнения, мое решение состояло в том, чтобы сделать глубокую копию среза вместо обычной копии. Это может быть неприменимо в зависимости от вашего контекста (ограничения памяти / размер среза, потенциал для снижения производительности - особенно если копия происходит в цикле, как это было для меня, и т. д...)
чтобы быть ясным, вот предупреждение, которое я получил:
/opt/anaconda3/lib/python3.6/site-packages/ipykernel/__main__.py:54: 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: удаление столбца на оригинале влияет на копию
мы это уже знали, но это здоровое напоминание. Это не что предупреждение об этом.
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]} >> df1 = pd.DataFrame(data1) >> df1 A B 0 111 121 1 112 122 2 113 123 >> df2 = df1 >> df2 A B 0 111 121 1 112 122 2 113 123 # Dropping a column on df1 affects df2 >> df1.drop('A', axis=1, inplace=True) >> df2 B 0 121 1 122 2 123можно избежать изменений, внесенных в df1, чтобы повлиять на df2
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]} >> df1 = pd.DataFrame(data1) >> df1 A B 0 111 121 1 112 122 2 113 123 >> import copy >> df2 = copy.deepcopy(df1) >> df2 A B 0 111 121 1 112 122 2 113 123 # Dropping a column on df1 does not affect df2 >> df1.drop('A', axis=1, inplace=True) >> df2 A B 0 111 121 1 112 122 2 113 123Пример 2: Удаление столбца на копии может повлиять на оригинал
Это на самом деле иллюстрирует предупреждение.
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]} >> df1 = pd.DataFrame(data1) >> df1 A B 0 111 121 1 112 122 2 113 123 >> df2 = df1 >> df2 A B 0 111 121 1 112 122 2 113 123 # Dropping a column on df2 can affect df1 # No slice involved here, but I believe the principle remains the same? # Let me know if not >> df2.drop('A', axis=1, inplace=True) >> df1 B 0 121 1 122 2 123можно избежать изменений, внесенных в df2, чтобы повлиять на df1
>> data1 = {'A': [111, 112, 113], 'B':[121, 122, 123]} >> df1 = pd.DataFrame(data1) >> df1 A B 0 111 121 1 112 122 2 113 123 >> import copy >> df2 = copy.deepcopy(df1) >> df2 A B 0 111 121 1 112 122 2 113 123 >> df2.drop('A', axis=1, inplace=True) >> df1 A B 0 111 121 1 112 122 2 113 123Ура!
Comments