본문 바로가기
데이터분석과 AI/데이터분석과 AI 문법(Python)

Inplace=True 옵션을 썼는데, 데이터 변경이 안되는 경우

by 우공80 2023. 6. 11.
728x90

Inplace=True 옵션을 썼는데, 데이터 변경이 안되는 경우

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" 옵션 사용을 지양하는 것이 좋겠습니다.

 

728x90

댓글