Python Pandas : SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
DataFrame에 있는 특징 한 가지를 알아보겠습니다.
import pandas as pd
dict_test = {
'col1': [1, 2, 3, 4, 5],
'col2': [2, 3, 4, 5, 6],
}
df_test = pd.DataFrame(dict_test)
df_test_1 = df_test
df_test_1.loc[:, 'col3'] = 3
df_test를 생성하고 df_test_1 = df_test 처럼 df_test_1에 df_test를 할당하였습니다.
- df_test_1.loc[:, 'col3'] = 3
그리고 df_test_1에 col3를 추가하였습니다.
그러면 df_test_1에만 col3가 생길까요?
아니면 df_test에도 col3가 생길까요?
정답은 df_test에도 col3가 생깁니다.
import pandas as pd
dict_test = {
'col1': [1, 2, 3, 4, 5],
'col2': [2, 3, 4, 5, 6],
}
df_test = pd.DataFrame(dict_test)
df_test_1 = df_test
df_test_1.loc[:, 'col3'] = 3
print(df_test)
print(df_test_1)
-- Result
col1 col2 col3
0 1 2 3
1 2 3 3
2 3 4 3
3 4 5 3
4 5 6 3
col1 col2 col3
0 1 2 3
1 2 3 3
2 3 4 3
3 4 5 3
4 5 6 3
결과 출력을 해보면 df_test, df_test_1 모두에 col3가 생긴 것을 볼 수 있습니다.
DataFrame을 다른 변수에 할당하면 단순히 새로운 변수에만 DataFrame을 복사해서 넣는 것이 아니라 원본 DataFrame을 참조하는 형태로 DataFrame을 할당받게 됩니다.
import pandas as pd
dict_test = {
'col1': [1, 2, 3, 4, 5],
'col2': [2, 3, 4, 5, 6],
}
df_test = pd.DataFrame(dict_test)
df_test_1 = df_test.copy()
df_test_1.loc[:, 'col3'] = 3
print(df_test)
print(df_test_1)
-- Result
col1 col2
0 1 2
1 2 3
2 3 4
3 4 5
4 5 6
col1 col2 col3
0 1 2 3
1 2 3 3
2 3 4 3
3 4 5 3
4 5 6 3
이를 방지하기 위해선 copy() method를 사용할 수 있습니다.
- df_test_1 = df_test.copy()
copy() method는 DataFrame을 복사해서 df_test_1에 할당하게 됩니다.
따라서 df_test_1은 df_test를 참조하는 것이 아닌 독자적인 DataFrame이 되는 것이죠.
그래서 col3이 df_test_1에만 생긴 것을 알 수 있습니다.
이러한 특성 때문에 발생하는 에러가 하나 있습니다.
import pandas as pd
dict_test = {
'col1': [1, 2, 3, 4, 5],
'col2': [2, 3, 4, 5, 6],
}
df_test = pd.DataFrame(dict_test)
con = (df_test['col1'] <= 3)
df_test_1 = df_test.loc[con, :]
df_test_1.loc[:, 'col3'] = 3
위 코드를 실행하면 아래와 같은 에러가 뜹니다.
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
위 코드를 살펴봅시다.
con = (df_test['col1'] <= 3)
df_test_1 = df_test.loc[con, :]
위 코드에서는 df_test_1에 df_test를 할당할 때 그냥 df_test 자체를 할당하는게 아니라 어떠한 조건을 적용해서 특정 index의 row만을 할당했습니다.
df_test_1.loc[:, 'col3'] = 3
그리고 df_test_1에 col3를 추가했습니다.
이런 경우 df_test_1에 col3를 추가했으니 df_test에도 col3가 추가될까요?
정답은 아니오 입니다.
df_test_1에 할당된 DataFrame은 df_test의 일부이기 때문에 df_test_1에 할당된 DataFrame은 새로운 DataFrame입니다.
import pandas as pd
dict_test = {
'col1': [1, 2, 3, 4, 5],
'col2': [2, 3, 4, 5, 6],
}
df_test = pd.DataFrame(dict_test)
con = (df_test['col1'] <= 3)
df_test_1 = df_test.loc[con, :]
df_test_1.loc[:, 'col3'] = 3
print(df_test)
print(df_test_1)
-- Result
col1 col2
0 1 2
1 2 3
2 3 4
3 4 5
4 5 6
col1 col2 col3
0 1 2 3
1 2 3 3
2 3 4 3
그래서 결과를 출력해보면 위처럼 df_test_1에만 col3가 생긴 것을 알 수 있습니다.
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
따라서 위 에러는 이러한 상황을 주의하라고 출력되는 에러 메세지 입니다.
위같은 에러메세지를 방지하려면 코드를 아래와 같이 수정하면 됩니다.
import pandas as pd
dict_test = {
'col1': [1, 2, 3, 4, 5],
'col2': [2, 3, 4, 5, 6],
}
df_test = pd.DataFrame(dict_test)
con = (df_test['col1'] <= 3)
df_test_1 = df_test.loc[con, :].copy()
df_test_1.loc[:, 'col3'] = 3
print(df_test)
print(df_test_1)
-- Result
col1 col2
0 1 2
1 2 3
2 3 4
3 4 5
4 5 6
col1 col2 col3
0 1 2 3
1 2 3 3
2 3 4 3
- df_test_1 = df_test.loc[con, :].copy()
이렇게 copy() method를 이용해서 명확하게 DataFrame을 복사해주는 것입니다.
그러면 SettingWithCopyWarning 에러가 사라지게 됩니다.