В чем преимущество представления или копирования данных
Я видел много вопросов о печально известной SettingWithCopy
предупреждение. Я даже рискнул ответить на некоторые из них. Недавно я составил ответ на эту тему, и я хотел представить преимущества представления данных. Мне не удалось создать ощутимую демонстрацию того, почему это хорошая идея - создать представление для фрейма данных или что-то, что генерирует SettingWithCopy
Рассматривать df
df = pd.DataFrame([[1, 2], [3, 4]], list('ab'), list('AB'))
df
A B
x 1 2
y 3 4
а также dfv
которая является копией df
dfv = df[['A']]
print(dfv.is_copy)
<weakref at 0000000010916E08; to 'DataFrame' at 000000000EBF95C0>
print(bool(dfv.is_copy))
True
Я могу генерировать SettingWithCopy
dfv.iloc[0, 0] = 0
Тем не мение, dfv
изменился
print(dfv)
A
a 0
b 3
df
не имеет
print(df)
A B
x 1 2
y 3 4
а также dfv
все еще копия
print(bool(dfv.is_copy))
True
Если я изменю df
df.iloc[0, 0] = 7
print(df)
A B
x 7 2
y 3 4
Но dfv
не изменился. Тем не менее, я могу сослаться df
от dfv
print(dfv.is_copy())
A B
x 7 2
y 3 4
Вопрос
Если dfv
поддерживает свои собственные данные (то есть фактически не сохраняет память) и присваивает значения с помощью операций присваивания, несмотря на предупреждения, тогда зачем нам вообще сохранять ссылки и генерировать SettingWithCopyWarning
совсем?
В чем ощутимая выгода?
1 ответ
Существует множество дискуссий по этому вопросу, см. Здесь, например, попытки PR. Стоит также отметить, что истинное копирование при записи для представлений рассматривается как часть рефакторинга "pandas 2.0", см. Здесь.
Причина, по которой ссылка поддерживается в вашем примере, заключается именно в том, что это не представление, поэтому, если кто-то попробует это, он получит предупреждение.
df[['A']].iloc[0, 0] = 1
Редактировать:
С точки зрения "зачем вообще использовать представления", это из соображений производительности / памяти. Рассмотрим базовую индексацию (выбор столбца), потому что эта операция выполняется в режиме просмотра, она почти мгновенная.
df = pd.DataFrame(np.random.randn(1000000, 2), columns=['a','b'])
%timeit df['a']
100000 loops, best of 3: 2.13 µs per loop
Принимая во внимание, что взятие копии имеет нетривиальную стоимость.
%timeit df['a'].copy()
100 loops, best of 3: 4.28 ms per loop
Эта стоимость производительности будет отображаться во многих операциях, например, при добавлении двух Series
все вместе.
%timeit df['a'] + df['b']
100 loops, best of 3: 4.31 ms per loop
%timeit df['a'].copy() + df['b'].copy()
100 loops, best of 3: 13.3 ms per loop