본문 바로가기
컴퓨터쟁이/Python

pyhton Error :SettingWithCopyWarning 해결 방법

by 빙글빙글이 2022. 3. 31.
728x90
반응형

python dataframe에 있는 값을로 연산을 하는데 

자꾸 아래와 같은 오류가 떠서 신경쓰여서 찾아보았었다. 

 

<ipython-input-434-09caeaeba2c4>:2: SettingWithCopyWarning:

A value is trying to be set on a copy of a slice from a DataFrame See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

 

Indexing and selecting data — pandas 1.4.1 documentation

Another common operation is the use of boolean vectors to filter the data. The operators are: | for or, & for and, and ~ for not. These must be grouped by using parentheses, since by default Python will evaluate an expression such as df['A'] > 2 & df['B']

pandas.pydata.org

 

이러한 오류가 나는 이유에 대해서 정리해보았다. 

1. 오류가 나고 실행이 아예 안되는 경우

Dataframe에서 값을 조건부로 가져다 쓸 경우

그건 dataframe의 한 부분이기때문에,

그 이후에 df에 새로운 컬럼을 만들어 값을 넣어도,

이미 조건부로 필터를 했기에,

Dataframe에 NULL 값이 존재한다.

 

따라서, Dataframe에서 조건부로 가져올 경우에는

copy()해서 구조도 그대로 가져오는 방법을 사용한다. 

(아래 코드 참고)

# with SettingWithCopyWarning
df_positive = df[df.NUM >= 0]
df_positive['SQUARED'] = df_positive.NUM ** 2
# 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: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

# without SettingWithCopyWarning
df_positive = df[df.NUM >= 0].copy()
df_positive['SQUARED'] = df_positive.NUM ** 2

print(df_positive)
#    NUM  SQUARED
# 2    5       25
# 3    9       81
# 4    7       49
# 7    4       16
# 9    6       36

 

2. 전체를 다 연산으로 사용하여 결과 값은 나오는데, 에러가 뜨는 경우

내가 이 글을 쓰게 된 주된 이유이기도 하다. 

이런 경우에는 dataframe의 부분만 가져온 것이 아니라 그냥 연산만 하는거여서,

실행은 되는데 내가 원하는 값이 제대로 안나와서 뭐가 문제인지 고민하고 있었다. 

for i in range(len(df['prediction'])):
    df['diff_x'][i] = df['answer_x'][i] - df['prediction_x'][i]
    df['diff_y'][i] = df['answer_y'][i] - df['prediction_y'][i]
    df['diff_z'][i] = df['answer_z'][i] - df['prediction_z'][i]
    
##결과 
# <ipython-input-434-09caeaeba2c4>:2: SettingWithCopyWarning: 
# A value is trying to be set on a copy of a slice from a DataFrame

# See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
#   df['diff_x'][i] = df['answer_x'][i] - df['prediction_x'][i]
# <ipython-input-434-09caeaeba2c4>:3: SettingWithCopyWarning: 
# A value is trying to be set on a copy of a slice from a DataFrame

# See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
#   df['diff_y'][i] = df['answer_y'][i] - df['prediction_y'][i]
# <ipython-input-434-09caeaeba2c4>:4: SettingWithCopyWarning: 
# A value is trying to be set on a copy of a slice from a DataFrame

# See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
#   df['diff_z'][i] = df['answer_z'][i] - df['prediction_z'][i]

이럴 때는 결과값을 봐보자.

왜 연산이 제대로 안되었는지 확인을 하려면

DataFrame의 각 컬럼의 type을 확인해봐야한다. 

df.dtypes 로 확인 가능하다. 

 

나 같은 경우는, float형이 아니라 int형으로 되어 있어서 값이 제대로 출력이 안되었던 것이였다. 

따라서 astype을 이용해서 해당 컬럼의 type을 바꿔주었다. 

분명 소숫점까지 있는 float형들의 단순연산인데 값이 왜 다 0으로 뜨나 엄청 고민했었다. 

이런건 분명 기본적인 부분인데, 아직도 이런 실수를 하는 것을 보면

좀 더 주의깊게 코드를 살펴볼 필요가 있다. 

 

참고로 1번의 문제사항은 해당 error를 구글에 검색하면서 찾은 이유였다. 

코드를 잘 짜는 사람들은 최대한 저런 오류가 안뜨도록 주의해서 짠다고한다. 

하지만, 나는 그냥 단순 연산인데 왜 저렇게 뜨는 것인지는 아직도 잘 모르겠다....ㅎㅎㅎ

그치만 연산의 문제는 type을 꼭 확인해야한다는 사실을 알게 되었다. 

 

참고 : https://emilkwak.github.io/pandas-dataframe-settingwithcopywarning

 

Pandas의 DataFrame 사용 중 SettingWithCopyWarning 발생할 때

Python, Pandas를 Excel보다 사랑하는 직장인을 위한 블로그

emilkwak.github.io

 

728x90
반응형