Я обожаю pandas и использую его в течение многих лет и чувствую себя довольно уверенно. Я хорошо разбираюсь в том, как подмножать данные и правильно обрабатывать представления и копии (хотя я использую много утверждений, чтобы быть уверенным). Я также знаю, что было много вопросов о SettingWithCopyWarning, например. Как работать с SettingWithCopyWarning в Pandas? и некоторые великие недавние руководства по обертыванию головы вокруг, когда это происходит, например. Общие сведения о настройкеWithCopyWarning в pandas.
Но я также знаю конкретные вещи, такие как цитата из этого ответа, больше не находятся в последних документах (0.22.0
) и что многие вещи устарели годы (приводящие к некоторым неправильным старым SO-ответам), и что вещи продолжают меняться.
Недавно после обучения pandas для новичков с очень базовым общим знанием Python о таких вещах, как избегание цепочечного индексирования (и с использованием .iloc
/.loc
), я все еще изо всех сил пытался предоставить общие правила, чтобы знать когда важно обратить внимание на SettingWithCopyWarning
(например, когда это безопасно игнорировать).
Я лично обнаружил, что конкретный шаблон подмножества данных в соответствии с таким правилом (например, разрезание или логическая операция), а затем изменение этого подмножества, независимо от исходного фрейма, является гораздо более распространенной операцией, чем предлагают документы. В этой ситуации мы хотим изменить копию, а не оригинал, и предупреждение запутывает/страшно для новичков.
Я знаю, что это не тривиально знать заранее, когда возвращается представление против копии, например,
Какие правила использует pandas для создания представления или копии?
Проверка, является ли кадр данных копией или просмотром в pandas
Итак, вместо этого я ищу ответ на более общий (начинающий) вопрос: , когда выполнение операции над подмножеством данных влияет на исходный dataframe, из которого он был создан, и когда они независимы?.
Я создал несколько случаев ниже, которые, как мне кажется, кажутся разумными, но я не уверен, есть ли у меня "gotcha", или нет ли более простой способ подумать/проверить это. Я надеялся, что кто-то сможет подтвердить, что мои интуиции о следующих случаях использования верны, поскольку они относятся к моему вопросу выше.
import pandas as pd
df1 = pd.DataFrame({'A':[2,4,6,8,10],'B':[1,3,5,7,9],'C':[10,20,30,40,50]})
1) Предупреждение: Нет Оригинал изменен: No
# df1 will be unaffected because we use .copy() method explicitly
df2 = df1.copy()
#
# Reference: docs
df2.iloc[0,1] = 100
2) Предупреждение: Да (я действительно не понял почему)
Оригинал изменен: No
# df1 will be unaffected because .query() always returns a copy
#
# Reference:
# https://stackoverflow.com/a/23296545/8022335
df2 = df1.query('A < 10')
df2.iloc[0,1] = 100
3) Предупреждение: Да Оригинал изменен: No
# df1 will be unaffected because boolean indexing with .loc
# always returns a copy
#
# Reference:
# /info/37847/pandas-subindexing-dataframes-copies-vs-views/275168#275168
df2 = df1.loc[df1['A'] < 10,:]
df2.iloc[0,1] = 100
4) Предупреждение: Нет Оригинал изменен: No
# df1 will be unaffected because list indexing with .loc (or .iloc)
# always returns a copy
#
# Reference:
# Same as 4)
df2 = df1.loc[[0,3,4],:]
df2.iloc[0,1] = 100
5) Предупреждение: Нет
Оригинал изменен: Да (смущает новичков, но имеет смысл)
# df1 will be affected because scalar/slice indexing with .iloc/.loc
# always references the original dataframe, but may sometimes
# provide a view and sometimes provide a copy
#
# Reference: docs
df2 = df1.loc[:10,:]
df2.iloc[0,1] = 100
TL;DR
При создании нового фрейма данных из оригинала изменение нового фреймворка данных:
Изменит оригинал, когда индексирование скалярного/среза с использованием .loc/.iloc используется для создания нового фрейма данных.
Не будет изменен исходный код, если булево индексирование с использованием .loc, .query()
или .copy()
используется для создания нового фрейма данных