개요
데이터 전처리 작업을 하다 보면 DataFrame 안의 음수 값을, 해당 위치보다 앞에 있는 가장 최근의 양수 값으로 대체해야 하는 경우가 있습니다. 만약 앞쪽에 양수 값이 하나도 존재하지 않는다면, 그 값은 0으로 처리하는 것이 조건입니다. 이 글에서는 Pandas의 mask(), ffill(), fillna() 메서드를 조합해 이 문제를 반복문 없이 한 줄의 코드로 해결하는 방법을 소개합니다.
핵심 아이디어
해결 과정은 크게 세 단계로 나눌 수 있습니다.
- 마스킹(masking) –
df.mask(df.lt(0))를 사용해 음수 값을 모두NaN으로 변경합니다. - 전방 채우기(forward fill) –
ffill()로NaN을 바로 앞의 유효한 값, 즉 이전 양수 값으로 채웁니다. - 남은 결측값 처리 – 앞에 양수 값이 없어 여전히
NaN으로 남아 있는 값은fillna(0)으로 0으로 채운 뒤,astype('int32')로 정수형을 유지합니다.
예제 코드
먼저 음수와 양수가 섞여 있는 DataFrame을 생성합니다.
import pandas as pd
# pandas DataFrame 생성
df = pd.DataFrame({'One': [-3, 7, 4, 0], 'two': [-6, -1, 2, -8]})
# 원본 DataFrame 출력
print("DataFrame:\n", df)
# 음수 마스킹 → forward fill → 남은 NaN은 0으로 대체
df = df.mask(df.lt(0)).ffill().fillna(0).astype('int32')
# 변경된 DataFrame 출력
print("\nUpdated DataFrame:\n", df)
실행 결과
DataFrame: One two 0 -3 -6 1 7 -1 2 4 2 3 0 -8 Updated DataFrame: One two 0 0 0 1 7 0 2 4 2 3 0 2
결과 해설
One 열 (-3, 7, 4, 0)
첫 번째 값 -3은 그 앞에 양수 값이 존재하지 않으므로 조건에 따라 0으로 대체됩니다. 나머지 값(7, 4, 0)은 음수가 아니기 때문에 원래 값이 그대로 유지됩니다.
two 열 (-6, -1, 2, -8)
-6과 -1 역시 앞에 양수 값이 없으므로 0으로 채워집니다. 반면 마지막 값 -8은 바로 앞에 있는 양수 값 2로 대체되는 것을 확인할 수 있습니다.
마무리
이처럼 mask() → ffill() → fillna()를 메서드 체이닝으로 연결하면, 복잡한 반복문이나 조건문 없이도 음수 값을 이전 양수 값으로 깔끔하게 치환할 수 있습니다. 시계열 데이터나 센서 로그처럼 비정상 값(음수)을 직전 정상 값으로 되돌려야 하는 상황에서 특히 유용하게 활용할 수 있는 패턴이니 꼭 기억해 두시기 바랍니다.