Странное поведение при обновлении значений с использованием iloc в фрейме данных pandas

В идеале при копировании кадра данных pandas мы должны использовать .copy(), который по умолчанию является глубокой копией.

Мы также могли бы добиться того же, используя new_df = pd.Dataframe(old_df), который также интуитивно понятен (и является общим стилем для большинства языков программирования, поскольку в принципе мы называем конструктор копирования).

В обоих случаях они имеют разные идентификаторы памяти, как показано ниже. Но когда я меняю old_df с помощью .iloc, это меняет значение new_df. Это ожидаемое поведение? Я не мог понять это поведение, используя документы. Я упускаю что-то тривиальное?

# ! pip install smartprint

from smartprint import smartprint as sprint
import pandas as pd

data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
original_df = pd.DataFrame(data)

new_df = pd.DataFrame(original_df)
original_df['A'] = original_df['A'].apply(lambda x: x * 1000)

print ("============ Changing a column with pd.Dataframe(old_df); No change")
sprint(original_df)
sprint(new_df)
sprint (id(new_df), id(original_df))



data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
original_df = pd.DataFrame(data)
new_df = pd.DataFrame(original_df)

original_df.iloc[0,:] = 20

print ("============ Using .iloc with pd.Dataframe(old_df); Change")
sprint(original_df)
sprint(new_df)
sprint (id(new_df), id(original_df))



data = {'A': [1, 2, 3], 'B': [4, 5, 6]}
original_df = pd.DataFrame(data)
new_df = original_df.copy()

original_df.iloc[0,:] = 20

print ("============ Using .iloc with old_df.copy(); No change")
sprint(original_df)
sprint(new_df)
sprint (id(new_df), id(original_df))

Выход:

============ Changing a column with pd.Dataframe(old_df); No change
original_df :       A  B
0  1000  4
1  2000  5
2  3000  6
new_df :    A  B
0  1  4
1  2  5
2  3  6
id(new_df), id(original_df) : 140529132556544 140529514510944
============ Using .iloc with pd.Dataframe(old_df); Change
original_df :     A   B
0  20  20
1   2   5
2   3   6
new_df :     A   B
0  20  20
1   2   5
2   3   6
id(new_df), id(original_df) : 140528893052000 140528894065584
============ Using .iloc with old_df.copy(); No change
original_df :     A   B
0  20  20
1   2   5
2   3   6
new_df :    A  B
0  1  4
1  2  5
2  3  6
id(new_df), id(original_df) : 140529057828336 140528940223984

Мои версии Python и Pandas перечислены ниже:

import sys
sys.version
Out[16]: '3.8.17 (default, Jul  5 2023, 16:18:40) \n[Clang 14.0.6 ]'
pd.__version__
Out[17]: '1.4.3'
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это ожидаемое поведение DataFrame, это также происходит, когда вы передаете в качестве входных данных массив numpy:

a = np.array([[1,2],[3,4]])

df = pd.DataFrame(a)
a[0][0] = 9

print(df)
    0  1
0  99  2
1   3  4

На самом деле это хорошо описано в документации DataFrame:

копировать: bool или None, по умолчанию None

Скопируйте данные из входов. Для данных dict значение по умолчанию None ведет себя как copy=True. Для ввода DataFrame или 2d ndarray по умолчанию установлено значение «Нет». ведет себя как copy=False. Если данные представляют собой словарь, содержащий один или несколько Серии (возможно, разных типов), copy=False гарантирует, что эти входные данные не копируются.

a = np.array([[1,2],[3,4]])

df = pd.DataFrame(a, copy=True)
a[0][0] = 99

print(df)
   0  1
0  1  2
1  3  4

как насчет изменения всего столбца?

В этом случае вы не изменяете столбец, а перезаписываете его новым. Это означает, что базовые объекты теперь другие:

a = np.array([[1,2],[3,4]])
df = pd.DataFrame(a)

df[0] = 99

print(a)
[[1 2]
 [3 4]]

Теперь это имеет смысл, как вы это объясняете. Тем не менее, я нахожу это нелогичным, но это просто мысли бывшего Java-разработчика :), отмечающего как принятое.

lifezbeautiful 02.07.2024 09:25

Другие вопросы по теме