#python-3.x #pandas
#python-3.x #pandas
Вопрос:
Начнем с примера…
In [1]: import pandas as pd
In [2]: from sklearn.datasets import load_iris
In [3]: iris = load_iris()
In [4]: X = pd.DataFrame(data=iris.data, columns=iris.feature_names)
In [5]: output_df = pd.DataFrame(X)
In [6]: X is output_df
Out[6]: False
In [7]: list(X.columns)
Out[7]:
['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)']
In [8]: output_df['y'] = iris.target
In [9]: list(X.columns)
Out[9]:
['sepal length (cm)',
'sepal width (cm)',
'petal length (cm)',
'petal width (cm)',
'y']
[6]
говорит, что это X is output_df
есть False
, что означает, что они не являются одним и тем же объектом. Если они не являются одним и тем же объектом, то добавление столбца к одному из них не должно влиять на другой.
Однако [9]
это говорит нам о том, что добавление столбца в output_df
определенно добавило тот же столбец в X
, что подразумевает, что они на самом деле являются одним и тем же объектом.
Почему здесь происходит отключение?
( pd.__version__ == 0.24.1
и python --version = Python 3.7.1
, если это имеет значение)
Ответ №1:
Существует некоторая развязка между a DataFrame
и его базовыми данными, которые хранятся в its BlockManager
. В вашем примере базовые BlockManager
данные те же, поэтому их изменение в одном из них DataFrame
повлияет на другое:
In [1]: import pandas as pd; pd.__version__
Out[1]: '0.24.1'
In [2]: df = pd.DataFrame({'A': list('abc'), 'B': [10, 20, 30]})
In [3]: df2 = pd.DataFrame(df)
In [4]: df is df2
Out[4]: False
In [5]: df._data is df2._data
Out[5]: True
In [6]: df._data
Out[6]:
BlockManager
Items: Index(['A', 'B'], dtype='object')
Axis 1: RangeIndex(start=0, stop=3, step=1)
IntBlock: slice(1, 2, 1), 1 x 3, dtype: int64
ObjectBlock: slice(0, 1, 1), 1 x 3, dtype: object
По сути, DataFrame
служит оболочкой для базовых данных, так что на самом деле это разные объекты, просто некоторые их компоненты являются общими. В качестве базового примера вы можете добавить фиктивные атрибуты к одному, не влияя на другой:
In [7]: df.foo = 'bar'
In [8]: df.foo
Out[8]: 'bar'
In [9]: df2.foo
---------------------------------------------------------------------------
AttributeError: 'DataFrame' object has no attribute 'foo'
Чтобы обойти проблему общих базовых данных, вам нужно явно указать DataFrame
конструктору копировать входные данные через copy
параметр:
In [10]: df2 = pd.DataFrame(df, copy=True)
In [11]: df._data is df2._data
Out[11]: False
In [12]: df['C'] = [1.1, 2.2, 3.3]
In [13]: df
Out[13]:
A B C
0 a 10 1.1
1 b 20 2.2
2 c 30 3.3
In [14]: df2
Out[14]:
A B
0 a 10
1 b 20
2 c 30