PySpark에서 NULL이 많을 때 filter가 안 먹히는 이유

2025. 4. 24. 15:30·Data Engineer
728x90

 

며칠 전, 실시간 로그 데이터를 정제하는 작업을 하던 중 이상한 결과를 마주했습니다.
status != 'deleted' 조건을 주고 필터링을 했는데, 결과 데이터가 너무 적었습니다.
“뭐지? deleted가 아닌 데이터만 남긴 건데, 왜 이렇게 많이 빠졌지?”

처음엔 단순히 삭제 상태가 많았겠거니 하고 넘어가려다, 궁금해서 groupBy("status").count()를 찍어봤습니다.
그 순간, 충격적인 결과가 나왔습니다. 생각보다 NULL이 굉장히 많았던 것이죠.
그리고 깨달았습니다. 아, 이건 단순히 조건식이 잘못된 문제가 아니라, Spark의 NULL 처리 방식에 대한 이해 부족이었다는 걸요.


PySpark의 삼진 논리(Tri-valued logic)

우리는 보통 이런 식으로 조건을 걸죠:

df.filter(col("status") != "deleted")

 

자연스럽게 “삭제 상태가 아닌 것”만 남겠지? 라고 생각합니다.
하지만 PySpark의 조건식은 SQL의 삼진 논리를 따릅니다.
즉, Boolean 평가 시 true, false, unknown(NULL) 이렇게 세 가지 결과가 존재합니다.

 

status 값 status != "deleted" 평가 필터 통과 여부
'active' true ✅ 포함됨
'deleted' false ❌ 제외됨
NULL unknown ❌ 제외됨

 

여기서 포인트는 NULL이 'false'가 아니라는 것입니다.
조건을 만족하지 않는 것이 아니라, 애초에 조건 평가가 안 되는 겁니다.
그래서 filter는 이 NULL 값들을 모두 제거해버립니다.

우리는 필터를 썼지만, 의도한 결과가 나오지 않은 거죠.


이 오류 하나로 인해 생각보다 큰 문제가 파생됐습니다.

1. 통계 수치 왜곡

분명히 전체 데이터는 1000만 건이 넘었는데, status != 'deleted' 조건 이후 남은 건 절반도 안 됐습니다.
나중에 확인해보니 status가 NULL인 데이터가 전체의 40% 이상이었습니다.

2. 모델 학습 데이터 편향

모델링 단계에서 "status != 'deleted'"로 데이터 필터 후 학습을 진행했는데,
status가 NULL인 데이터를 모두 제거하면서 특정 클래스가 과소 대표되는 문제가 발생했습니다.

3. 사용자 리포트 누락

운영 리포트 상에서 특정 상태가 통계에 아예 안 잡히는 문제가 생겼고,
원인은 status NULL인데 필터에서 빠졌기 때문이었습니다.


NULL을 배제하지 말고, 직접 다뤄야 한다

1. isNotNull()과 AND 조건 사용

from pyspark.sql.functions import col

filtered_df = df.filter(
    (col("status").isNotNull()) & (col("status") != "deleted")
)

 

이렇게 명시적으로 NULL 값을 제외하는 조건을 추가하면, 우리가 원하는 정확한 행만 남길 수 있습니다.

 

2. 사전 분포 확인 (groupBy 필수)

df.groupBy("status").count().show()

 

조건 필터링 전에 값 분포를 확인하는 건 실무에서 정말 좋은 습관입니다.
NULL이 많은 컬럼일수록 더더욱 필요하죠.

 

3. NULL을 대체해서 정규화 처리 (분석/시각화 목적)

from pyspark.sql.functions import coalesce, lit

df = df.withColumn("status", coalesce(col("status"), lit("unknown")))

 

이렇게 하면 NULL이 아닌 "unknown"이라는 명확한 값으로 대체되기 때문에
분석이나 리포트에서 값 누락 없이 분포를 정확히 파악할 수 있습니다.


  • 삼진 논리에서는 NULL은 != 조건에도 포함되지 않는다 → 명시적 예외 처리가 필요합니다.
  • isNotNull()을 함께 쓰면 조건식이 true/false로 명확히 판단됩니다.
  • NULL을 "unknown"으로 치환하면 필터 외에도 groupBy, 집계 등에서 의도치 않은 누락을 방지할 수 있습니다.
  • groupBy로 분포를 미리 확인하는 습관은 실무에서 오류를 미연에 방지하는 강력한 방법입니다.
상황 잘못된 코드 실제 문제
기본 필터 df.filter(col("status") != "deleted") NULL 포함 데이터 누락
조인 키 전 필터 status가 NULL인데 필터로 걸러져 조인 누락 일부 조인 실패
시각화 집계 NULL 빠진 상태로 시각화 리포트 불완전

 

방지 패턴

if "status" in df.columns:
    df = df.filter(
        (col("status").isNotNull()) & (col("status") != "deleted")
    )
else:
    raise ValueError("status 컬럼이 존재하지 않습니다.")

요약

  • PySpark의 filter에서 != 조건은 NULL을 고려하지 않으면 의도와 다르게 동작합니다.
  • NULL은 false가 아니라 unknown → 명시적 .isNotNull() 또는 치환 필요
  • 정제, 분석, 모델링 단계 모두에서 NULL은 사라지거나 무시되기 쉽지만,
    그만큼 정확한 대응이 필요합니다.
  • “값이 없다”는 사실 자체를 정보로 바꿔주는 과정이 실력이라고 생각합니다.

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Data Engineer' 카테고리의 다른 글

'정규화(Normalization)'를 과도하게 적용하면 Spark 성능이 저하될까?  (0) 2025.04.24
PySpark vs. Scala Spark 어떤 언어를 선택해야할까?  (0) 2025.04.02
Airflow XCom 태스크 간 데이터 전달  (0) 2025.03.28
Airflow로 데이터 품질 테스트  (0) 2025.03.28
Apache Spark vs Apace Flink  (0) 2025.03.26
'Data Engineer' 카테고리의 다른 글
  • '정규화(Normalization)'를 과도하게 적용하면 Spark 성능이 저하될까?
  • PySpark vs. Scala Spark 어떤 언어를 선택해야할까?
  • Airflow XCom 태스크 간 데이터 전달
  • Airflow로 데이터 품질 테스트
Balang
Balang
음악 전공생의 개발일지
  • Balang
    Balang
    Balang
  • 전체
    오늘
    어제
  • 반응형
    • All Post (146)
      • python (45)
        • selenium (4)
        • algorithm (9)
        • Django (6)
        • Pandas | Numpy (22)
      • SQL (9)
      • Data Engineer (29)
      • Data Scientist (3)
      • Data Analysis (9)
      • Computer Science (35)
      • Why? (15)
      • 마음가짐 (1)
  • 인기 글

  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
Balang
PySpark에서 NULL이 많을 때 filter가 안 먹히는 이유
상단으로

티스토리툴바