Подтвердить что ты не робот

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

Я обожаю 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() используется для создания нового фрейма данных

4b9b3361

Ответ 1

У меня такое же сомнение, я искал этот ответ в прошлом без успеха. Итак, теперь я просто подтверждаю, что оригинал не меняется и использует этот код кода для запуска программы, чтобы удалить предупреждения:

 import pandas as pd
 pd.options.mode.chained_assignment = None  # default='warn'