Он хорошо известен (и понятный), что поведение pandas по сути, непредсказуемо при назначении срезу. Но я привык к предупреждению об этом с помощью предупреждения SettingWithCopy
.
Почему предупреждение не генерируется ни в одном из следующих двух фрагментов кода, и какие методы могут уменьшить вероятность написания такого кода непреднамеренно?
# pandas 0.18.1, python 3.5.1
import pandas as pd
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data[['a', 'b']]
data = data['a']
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
data[0] == 1
True
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data['a']
data = data['a']
new_data.loc[0] = 100 # no warning, propagates to data
data[0] == 100
True
Я думал, что объяснение состоит в том, что pandas выводит предупреждение только тогда, когда родительский DataFrame по-прежнему доступен из текущего контекста. (Это было бы слабостью алгоритма обнаружения, как показывают мои предыдущие примеры.)
В следующем фрагменте AFAIK исходный двухстолбцовый DataFrame больше недоступен, но механизм предупреждения pandas управляет (к счастью):
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
new_data = data['a']
data = data[['a']]
new_data.loc[0] = 100 # warning, so we're safe
Edit:
При этом я нашел еще один случай отсутствия предупреждения:
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c']})
data = data.groupby('a')
new_data = data.filter(lambda g: len(g)==1)
new_data.loc[0, 'a'] = 100 # no warning, does not propagate to data
assert data.filter(lambda g: True).loc[0, 'a'] == 1
Даже если почти идентичный пример вызывает предупреждение:
data = pd.DataFrame({'a': [1, 2, 2], 'b': ['a', 'b', 'c']})
data = data.groupby('a')
new_data = data.filter(lambda g: len(g)==1)
new_data.loc[0, 'a'] = 100 # warning, does not propagate to data
assert data.filter(lambda g: True).loc[0, 'a'] == 1
Обновление: я отвечаю на ответ @firelynx здесь, потому что его трудно помещать в комментарий.
В ответе @firelynx говорит, что первый фрагмент кода не дает никаких предупреждений, потому что я беру весь файл данных. Но даже если я принимал участие в этом, я все равно не получаю предупреждение:
# pandas 0.18.1, python 3.5.1
import pandas as pd
data = pd.DataFrame({'a': [1, 2, 3], 'b': ['a', 'b', 'c'], c: range(3)})
new_data = data[['a', 'b']]
data = data['a']
new_data.loc[0, 'a'] = 100 # no warning, doesn't propagate to data
data[0] == 1
True