drop, fillna, replace 등 python pandas 함수를 쓰면서 Inplace=True 옵션을 자주 사용하였는데, 이 옵션이 동작하지 않는 경우가 있어서 공유합니다. 우선 아래 예제를 보겠습니다.
1. Inplace=True 옵션이 동작하지 않는 경우
이 예제는 Age와 Income 열의 값이 0인 경우 각 컬럼의 평균값으로 대체하는 예제입니다.
import pandas as pd
# 샘플 데이터프레임 생성
data = {'Name': ['John', 'Alice', 'Bob', 'Emily'],
'Age': [25, 30, 35, 0],
'Income':[100,200,300,0],
'City': ['New York', 'Paris', 'London', 'Sydney'],
'Gender': ['Male', 'Female', 'Male', 'Female']}
df = pd.DataFrame(data)
# 변경할 열 선택
cols = ['Age','Income']
# 변경할 값을 지정
cols_mean=df[cols].mean()
# 일부 열의 값을 변경
df[cols].replace(0,cols_mean,inplace=True)
# 결과 출력
print(df)
Output:
Name Age Income City Gender
0 John 25 100 New York Male
1 Alice 30 200 Paris Female
2 Bob 35 300 London Male
3 Emily 0 0 Sydney Female
/opt/conda/lib/python3.7/site-packages/pandas/core/indexing.py:1773: 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
self._setitem_single_column(ilocs[0], value, pi)
코드상으로는 정상적으로 변경이 되어야 할 것 같은데, 결과를 보면 Age와 Income에 아무 변경이 없고, SettingWithCopyWarning 경고가 발생합니다. 이러한 경고 메시지는 DataFrame의 복사본에 값을 설정하려고 시도했을 때 발생한다고 합니다.
경고를 해결하기 위해. loc [row_indexer, col_indexer]를 사용하여 값을 설정하라는 안내에 따라 코드를 수정해 보았습니다.
df.loc[:,cols].replace(0,cols_mean,inplace=True)
경고메시지는 없어졌지만, 결과는 여전히 변경이 없습니다.
Name Age Income City Gender
0 John 25 100 New York Male
1 Alice 30 200 Paris Female
2 Bob 35 300 London Male
3 Emily 0 0 Sydney Female
2. 변경이 되지 않는 이유 - 데이터 원본(Original Data)과 뷰 (View) 그리고 복사본 (Copy)의 차이
아래 글에서 이유를 확인할 수 있었는데요. 데이터 원본(Original Data)과 뷰 (View) 그리고 복사본 (Copy)의 차이에 의해 변경이 되거나 안되거나 합니다.
https://stackoverflow.com/questions/68352823/inplace-true-doesnt-work-for-subset-data
inplace=True doesn't work for subset data
I am trying to fill missing values in subset of rows. I am using inplace=True in fillna(), but it is not working in jupyter notebook. You can see attached picture showing NaN in the first 2 rows in
stackoverflow.com
데이터 원본(Original Data)과 뷰 (View) 그리고 복사본 (Copy)에 대해 간단하게 알아보겠습니다.
- 데이터 원본 (Original Data)
: 데이터프레임을 처음에 생성한 원본 데이터입니다. - 뷰 (View)
: 뷰는 데이터프레임의 일부를 참조하는 것입니다. 뷰는 원본 데이터의 일부에 대한 참조를 유지하며, 원본 데이터와 동기화됩니다. 뷰를 수정하면 원본 데이터도 수정됩니다. 데이터프레임의 슬라이싱, 필터링, 특정 열 선택 등을 통해 생성될 수 있습니다. - 복사본 (Copy)
: 복사본은 데이터프레임의 별개인 독립된 사본입니다. 복사본은 원본 데이터와 독립적으로 존재하며, 원본 데이터의 변경에 영향을 받지 않습니다. 복사본을 수정해도 원본 데이터는 수정되지 않습니다. 데이터프레임의 copy() 메서드를 사용하거나 슬라이싱 연산으로 생성될 수 있습니다.
데이터 원본과 뷰는 동일한 메모리 공간을 차지하며, 복사본은 별도의 메모리 공간을 할당받습니다. 이에 따라 뷰에 대한 변경은 원본의 변경을 수반하지만, 복사본의 변경은 원본에 영향을 주지 않습니다. 그런데, 위 설명처럼 슬라이싱을 했을 때, 어떤 때는 뷰이고, 어떤 때는 복사본이 되어버리는데요. 어떨 때 가능한지 예제를 확인해 보겠습니다.
_is_view 속성을 보면 뷰인지 복사본인지 확인이 가능합니다.
print(df[cols]._is_view)
print(df.loc[:,cols]._is_view)
print(df.loc[:,'Age']._is_view)
Output:
False
False
True
단일 컬럼을 쓴 경우에는 View이지만, 그 외 슬라이싱 한 결과는 모두 View가 아닙니다. 따라서 위의 예제에서는 컬럼별로 replace를 하거나, inplace=True 옵션을 사용하지 않고 직접 할당해야 합니다.
수정한 코드:
# 일부 열의 값을 변경
# df[cols].replace(0,cols_mean,inplace=True) # 변경되지 않음
df[cols] = df[cols].replace(0,cols_mean)
# 결과 출력
print(df)
Output:
Name Age Income City Gender
0 John 25.0 100 New York Male
1 Alice 30.0 200 Paris Female
2 Bob 35.0 300 London Male
3 Emily 22.5 150 Sydney Female
보시는 것처럼 원하는 대로 변경이 된 것을 볼 수 있습니다.
이렇게 뷰인지 복사본인지 확인하는 것은 가능하지만, 어떤 경우에, 뷰가 되고 어떤 경우에 복사본이 되는지가 명시적으로 밝혀져있지 않습니다. 이름은 Inplace이지만, 실제로는 복사본을 생성하는 경우가 많으므로 가급적이면, "Inplace=True" 옵션 사용을 지양하는 것이 좋겠습니다.
'데이터분석과 AI > 데이터분석과 AI 문법(Python)' 카테고리의 다른 글
데이터분석 초보자가 자주하는 실수- 정확도, 정밀도, 재현율, F1-score 까지 모든 성능지표가 1인 경우 (0) | 2023.06.30 |
---|---|
[Python] 그래프에서 한글 깨질 때, 폰트 확인, 한글 폰트 설정, 마이너스 표기 방법 (0) | 2023.06.28 |
Label Encoidng 시 ValueError: y contains previously unseen labels:가 발생할 때 (0) | 2023.06.08 |
비지도학습의 앙상블 방법(iris) (0) | 2023.05.12 |
Python에서 DataFrame의 목록을 출력하는 방법 (0) | 2022.09.13 |
댓글