[Pandas] SettingWithCopyWarning
SettingWithCopyWarning, Pandas copy view, Pandas chained indexing 1.
2. 명시적
Q.
정의
SettingWithCopyWarning 은 pandas 가 가장 자주 던지는 경고. chained indexing 으로 view 인지 copy 인지 모호한 상태에 값을 할당 할 때 발생.
sub = df[df['age'] > 30]
sub['new'] = 1 # ⚠️ SettingWithCopyWarning
# sub 가 view 인지 copy 인지 pandas 가 모름
# 원본 df 가 영향받을 수도, 안 받을 수도
왜 위험한가
sub가 copy 면 →sub['new'] = 1은 sub 만 변경, 원본 df 는 안 바뀜sub가 view 면 → 원본 df 도 변경 (의도일 수도, 아닐 수도)
pandas 는 결과를 보장 못 하므로 경고.
4 가지 해결 패턴
1. .loc[] 한 줄에 통합 (가장 권장)
# ❌
df[df['age'] > 30]['salary'] = 0
# ✓
df.loc[df['age'] > 30, 'salary'] = 0
행 / 열을 한 번의 indexer 로.
2. 명시적 .copy()
sub = df[df['age'] > 30].copy() # 명시적 copy
sub['new'] = 1 # sub 만 변경
원본 보존 의도가 명확.
3. 결과를 새 변수에 할당
df = df.assign(salary=lambda d: d['salary'].where(d['age'] > 30, 0))
method chain 안에서 처리.
4. inplace 메서드
df.loc[df['age'] > 30, 'salary'] = 0
# 위와 같음, 가장 흔한 패턴
흔한 함정 패턴
chained indexing
df[df['age'] > 30]['salary'] = 0
# df.__getitem__(mask).__setitem__('salary', 0)
# 두 번의 indexing, 첫 번째 결과가 view/copy 불확실
slice 후 수정
sub = df[5:10] # slice 는 view (대부분)
sub['x'] = 1 # 원본 df 의 5-10 행이 영향받을 수 있음
loc + chained
df.loc[df['age'] > 30]['salary'] = 0
# .loc 가 있어도 두 번의 indexing 이라 같은 문제
df.loc[df['age'] > 30, 'salary'] = 0 # ✓
view vs copy 판별 (정확하지 않음)
pandas 의 내부 동작이 복잡하고 버전마다 다르다. 확신할 수 없으면 항상 .copy() 또는 한 줄 .loc[행, 열].
df._is_view # 비공식, 의존하지 마라
pandas 3.0 의 변화 (Copy-on-Write)
pandas 2.0+ 부터 pd.options.mode.copy_on_write = True 옵션. pandas 3.0 부터 기본화 예정.
pd.options.mode.copy_on_write = True
# 모든 슬라이싱이 copy 처럼 동작
# 더 이상 SettingWithCopyWarning 안 뜸
향후 이 동작이 표준이 되면 경고가 사라진다.
자주 묻는 질문
Q. 경고를 무시해도 되나?
A. 무시하지 마라. 경고는 의도와 다른 결과를 낳을 수 있다는 신호.
Q. inplace=True 가 해결인가?
A. 별 도움 안 됨. inplace 자체도 deprecation 방향. 명시적 할당 권장.
Q. .copy() 가 항상 안전한가?
A. ✓. 단, 큰 DataFrame 에서 메모리 / 시간 비용. 의도적으로 view 가 필요하면 한 줄 .loc[].
함정
1. groupby 결과 수정
g = df.groupby('city').get_group('Seoul')
g['new'] = 1 # ⚠️
g = df.groupby('city').get_group('Seoul').copy()
g['new'] = 1 # ✓
2. boolean mask + 컬럼 추가
sub = df[df['age'] > 30]
sub.loc[:, 'flag'] = True # ⚠️ 여전히 경고
sub = df[df['age'] > 30].copy()
sub['flag'] = True # ✓
3. 경고 출처가 다른 줄
경고 메시지의 라인 정보가 정확하지 않을 수 있음. 한 단계 앞에서 발생한 chained indexing 이 진짜 원인.
참고
이 글의 용어 (3개)
- [Pandas] .loc / .ilocpandas
- 정의 - : 라벨 기반 인덱싱 (index/column 이름) - : 정수 위치 기반 인덱싱 (0-based) 이 두 indexer 가 pandas 선택의 표준. 만으로는 헷갈리…
- [Pandas] Boolean Indexingpandas
- 정의 Boolean Indexing 은 True/False 의 Series 를 인덱서로 전달 해 행을 선택하는 패턴. pandas 의 가장 흔한 필터링 방법. 기본 <CodeWi…
- [Pandas] pipe / method chainingpandas
- 정의 는 DataFrame 자체를 함수의 첫 인자로 넘겨 method chaining 을 확장. functional style Pandas. 문제: 중간 변수 남발 가독성 나쁘고…
💬 댓글