Сначала мы импортируем pandas и numpy, а затем создаем pd.DataFrame размером 5000 строк x 10 столбцов под названием 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).
Подробнее здесь: https://stackoverflow.com/questions/791 ... nsistently