데이터 전처리 작업 중 pandas를 쓸 일이 있었다. 조건처리를 해야 하는데 python 문법으로 삼항연산자를 썼다가 오류를 만났다.
문제 상황 - 실패한 코드 예시
import pandas as pd
df = pd.DataFrame({
"측정일시": pd.to_datetime([
"2024-01-10 00:00", "2024-01-10 01:00", "2024-01-10 02:00", "2024-01-12 09:00"
]),
"측정값": [2.0, 3.5, 3.5, 1.0],
})
df["시간간격(h)"] = df["측정일시"].diff() / pd.Timedelta(hours=1)
df["diff"] = df["측정값"].diff()
# 실패 케이스: if/elif/else 감각으로 짠 삼항연산자
df["1시간 증가분"] = df["측정값"] if df["시간간격(h)"].isnull() or df["시간간격(h)"] > 24 else df["diff"]
시간간격이 null이거나 24시간 초과인 경우는 1시간 증가분을 원본 측정값 컬럼으로 두고, 아닐 경우 diff로 두는 로직을 짰다. 하지만 다음과 같이 에러가 떴다.
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
and, or가 피연산자를 bool 하나로 뭉뜽그려 참/거짓을 판단해서 여러 값이 있는 Series에서 오류가 난다길래 or을 |으로 바꿔서 시도했다.
interval = df["시간간격(h)"]
cond = interval.isnull() | (interval > 24)
df["1시간 증가분"] = df["측정값"] if cond else df["diff"] # 그래도 실패
그러나 같은 에러를 마주했다.
삼항연산자에서 if 안의 조건은 bool 타입을 요구하는데 위 코드에서 cond은 Series이다. 실제로 값을 출력해보면 다음과 같이 나온다.
0 True
1 False
2 False
3 True
값이 True, False 여러 개가 있기 때문에 하나로 정할 수 없어서 오류가 난 것이었다.
Series.where() : 조건이 2개일 때
Series.where(cond, other=<no_default>, *, inplace=False, axis=None, level=None)
cond:True인 자리는 원본 값 유지,False인 자리만 other로 교체할 조건 Seriesother:cond가 False인 자리에 채워 넣을 값 (기본값: NaN)inplace:True면 원본 자체를 수정,False(기본)면 새 Series를 반환axis: 축이 여러 개인 DataFrame에서 정렬 기준 축 지정용level: MultiIndex일 때 정렬 기준 레벨 지정용
Series의 where은 조건이 False인 행을 다른 지정 값(other)으로 바꾼다.
에러가 난 코드를 다음과 같이 수정했다.
df["diff"] = df["측정값"].diff()
interval = df["시간간격(h)"]
is_reset = interval.isnull() | (interval > 24)
df["증가분"] = df["diff"].where(~is_reset, df["측정값"])
np.select() : 조건이 3개 이상일 때
조건이 3개 이상인 경우 numpy의 select 함수를 쓰면 된다.
numpy.select(condlist, choicelist, default=0)
condlist: 조건(Series/배열) 목록choicelist: 조건과 1:1로 대응하는 값 목록default: 아무 조건도 안 맞을 때 쓸 값
df["상태"] = np.select(
[interval.isnull(), interval > 24, interval > 1],
["첫 측정", "리셋구간", "공백포함"],
default="정상관측",
)
numpy의 select는 리스트의 순서대로 검사해서 맨 처음 True인 조건을 채택한다. python의 elif 문법과 동일한 원리이다.
참고
hanul.dev
데이터와 일상을 기록합니다
댓글 0
아직 댓글이 없습니다.