В чем преимущество представления или копирования данных

Я видел много вопросов о печально известной 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
Другие вопросы по тегам