Сначала мы импортируем pandas и numpy, а затем создаем 5000 строк x 10 столбцов pd.DataFrame под названием df
Код: Выделить всё
import pandas as pd
import numpy as np
# Generate non-trivial df
data = np.random.rand(5000, 10)
column_names = [f'col_{i}' for i in range(10)]
df = pd.DataFrame(data, columns=column_names)
Затем мы берем df, выбираем 2 столбца и добавляем к ним новый столбец со статическим значением 10
Код: Выделить всё
foo = df
print(f"foo has type {type(foo)}\n")
bar = foo[["col_0", "col_1"]]
bar["new"] = 10
print(f"After modification bar has {type(bar)}\n\nbar is:\n{bar}")
Код: Выделить всё
foo has type
After modification bar has
bar is:
col_0 col_1 new
0 0.837911 0.715060 10
... ... ... ...
4999 0.684007 0.176949 10
[5000 rows x 3 columns]
C:\Users\vents\AppData\Local\Temp\ipykernel_5824\1295636698.py:5: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
bar["new"] = 10
Сделайте то же самое с другим df, но не получите SettingWithCopyWarning.
Теперь мы делаем то же самое, что и выше, но устанавливаем foo в тривиальную таблицу
Код: Выделить всё
foo = pd.DataFrame([["x",20.2,30], ["y",80,70]], columns=["col_0", "col_1", "col_2"])
print(f"foo has type {type(foo)}\n")
bar = foo[["col_0", "col_1"]]
bar["new"] = 10
print(f"After modification bar has {type(bar)}\n\nbar is:\n{bar}")
Код: Выделить всё
foo has type
After modification bar has
bar is:
col_0 col_1 new
0 x 20.2 10
1 y 80.0 10
Мое объяснение(?) и мысли
Насколько я понимаю, SettingWithCopyWarning означает, что существует неопределенность относительно того, является ли таблица копией или представлением. Так что, возможно, у pandas есть какая-то логика оптимизации: если таблица маленькая, она просто дает вам копию, потому что "о, какого черта, просто избавьте их от головной боли; их таблица крошечная, мы просто сделаем для них копию"??? Но тогда для большей таблицы он не хочет тратить оперативную память на копирование, поэтому требует от пользователей быть умнее?
Это мое лучшее предположение.
Мне просто не нравится общий совет: "О, просто используйте foo.loc[:, ["col_0", "col_1"] или foo[["col_0", "col_1"]].copy() и вы не получу ошибку", потому что я не уверен, что полностью понимаю проблему...
Например, какие другие части моего кода плохи, но мне (не)повезло, что я не получил предупреждение?
Из того, что я видел в Интернете, большинство настроек SettingWithCopyWarning часто выдаются, если вы берете подмножество данных, тип которых отличается от исходной таблицы, а затем пытаетесь сделать что-то к нему (например, foo[0]["col_0"], который сначала берет серию foo[0] а затем из нее дает столбец col_0).