Pandas 데이터프레임 사용할 때 주의할 점 (Chained Assignment)

Jae Chan·2024년 6월 19일
1

TIL

목록 보기
10/10
post-thumbnail

문제 발생

최근에 회사에서 디버깅 도중 아래와 같은 로그를 발견했었다.

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

해석:
`데이터프레임의 슬라이스로부터 만들어진 복사본에 값을 설정하려고 합니다.
해당 방법으로 시도하세요. Try using .loc[row_indexer,col_indexer] = value instead`

무엇이 문제이길래 이러한 경고문을 띄우는걸까?
아래의 예시에서는 음료 자판기에서 소다의 가격을 1100원에서 1500원으로 바꾸려고 한다.

import pandas as pd

자판기 = pd.DataFrame({
    '음료수': ['Coke', 'Soda', 'Dr.Pepper', 'Fanta'],
    '가격': [1000 , 1100 , 1200, 1500]
})

# "Soda"의 가격을 1100원에서 1500원으로 바꾸기.
자판기[자판기['음료수'] == 'Soda']['가격'] = 1500
print(자판기)

결과는 어떻게 되었을까?

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
  자판기[자판기['음료수'] == 'Soda']['가격'] = 1500
  
         음료수    가격
0       Coke  1000
1       Soda  1100 <--- 가격이 그대로다 😫
2  Dr.Pepper  1200
3      Fanta  1500

엥?? 내가 의도한대로 변경되지 않았다.
이는 우리가 기대했던 대로 동작 하지 않을 가능성이 있다는 뜻이다.

왜 문제가 될까

공식문서에 의하면 chained assignment 를 데이터 프레임에 적용할 경우 원본이 아닌 복사본에 값이 변경될 수 있어 정상적인 리턴 값을 보장할 수 없다고 한다.

그럼 어떻게 할까요

값을 변경하고자 할 경우 두 가지의 방법을 이용하라고 한다.

1. .loc 사용하기

.loc 의 경우 데이터프레임에 직접 인덱싱 및 접근하여 값을 변경해준다고 한다.

import pandas as pd

자판기 = pd.DataFrame({
    '음료수': ['Coke', 'Soda', 'Dr.Pepper', 'Fanta'],
    '가격': [1000 , 1100 , 1200, 1500]
})

자판기.loc[자판기['음료수'] == 'Soda', '가격'] = 1500
print(자판기)

"""
결과 :
     음료수    가격
0       Coke  1000
1       Soda  1500 <-- 변경 됨!
2  Dr.Pepper  1200
3      Fanta  1500
"""

2. copy() 이용하기

슬라이싱한 데이터프레임을 원본 데이터프레임과 독립적인 복사본으로 사용하고자 할 경우 다음과 같이 사용 가능하다.

나는_복제_자판기 = 자판기.loc[자판기['음료수'] == 'Dr.Pepper'].copy()
나는_복제_자판기['가격'] = 2200
print(나는_복제_자판기)

"""
결과 :
2  Dr.Pepper  2200
"""

이렇게 사용하면 원본 데이터프레임에 영향을 끼치지 않고 값 변경이 가능하다.

요약

pandas의 데이터프레임을 핸들링 할 때 필터링과 값 변경을 동시에 하고자 할 경우 loc 또는 copy()를 이용하면 된다.

이를 무시하고 변경하고자 하면 값 변경의 보장을 못한다.

0개의 댓글