[판다스 7화] 조건으로 데이터 추출하기: Boolean Indexing과 query 함수 활용법 | Python Pandas | 빅분기, 빅데이터분석기사 실기

데이터 분석 프로젝트를 진행하다 보면 전체 데이터셋에서 우리가 원하는 특정 조건에 부합하는 데이터만 선별하여 추출해야 하는 상황을 끊임없이 마주하게 됩니다. 예를 들어 “연령대가 30대이면서 구매 금액이 100만 원 이상인 우수 고객군”을 추출하거나, “특정 기간 동안 매출이 감소한 매장”을 필터링하는 작업 등입니다.

파이썬(Python) 판다스(Pandas) 라이브러리에서 이처럼 조건에 맞는 데이터를 필터링하는 대표적인 방법이 바로 불리언 인덱싱(Boolean Indexing)과 query() 함수입니다. 두 방법은 대용량 데이터 전처리와 탐색적 데이터 분석(EDA) 과정에서 매우 빈번하게 사용되며, 빅데이터분석기사(빅분기) 실기 시험에서도 필수로 출제되는 영역입니다. 이번 글에서는 두 기법의 개념과 세부 사용법, 그리고 실제 비즈니스 가상 데이터를 활용한 실전 예제를 상세히 정리해 보겠습니다.

1. 판다스 필터링의 표준: 불리언 인덱싱(Boolean Indexing)

1.1. 불리언 인덱싱의 기본 원리

불리언 인덱싱은 데이터프레임의 각 행에 대해 조건식의 결과가 참(True)인지 거짓(False)인지 판별하는 불리언 시리즈(Boolean Series)를 생성한 뒤, 이 중에서 True에 해당하는 행만 필터링하여 가져오는 방식입니다.

가장 흔하게 사용되는 대괄호(df[조건식]) 문법이나 앞선 6화에서 배운 df.loc[조건식] 형태로 주로 구현됩니다.

1.2. 비즈니스 예시로 이해하는 단일 조건 필터링

아래와 같이 가상의 이커머스 고객 데이터프레임을 생성하여 간단한 필터링을 수행해 보겠습니다.

import pandas as pd

# 가상 고객 데이터 생성
customer_df = pd.DataFrame({
    '고객ID': ['C01', 'C02', 'C03', 'C04', 'C05'],
    '나이': [24, 37, 29, 41, 35],
    '가입여부': ['Active', 'Inactive', 'Active', 'Active', 'Inactive'],
    '구매금액': [120000, 450000, 80000, 950000, 300000]
})

여기서 “구매금액이 30만 원 이상인 고객”을 불리언 인덱싱으로 추출해 보겠습니다.

# 1. 조건에 맞는 불리언 시리즈 생성
condition = customer_df['구매금액'] >= 300000

# 2. 대괄호 내부에 조건식을 전달하여 필터링 수행
high_spenders = customer_df[condition]
high_spenders

customer_df['구매금액'] >= 300000을 실행하면 판다스는 내부적으로 [False, True, False, True, True] 형태의 불리언 시리즈를 만듭니다. 이를 다시 데이터프레임의 인덱서(df[...])에 대입하면 True가 있는 1번, 3번, 4번 인덱스 행만 남기고 나머지는 제외된 결과가 반환됩니다.

1.3. 다중 조건 필터링: AND(&)와 OR(|) 연산

실무에서는 둘 이상의 조건을 결합하여 데이터를 찾아내야 하는 경우가 대다수입니다. 이때 판다스에서는 비트 연산자인 & (AND, 그리고)와 | (OR, 또는)를 사용합니다.

여기서 아주 중요한 파이썬 문법적 주의사항이 있습니다. 연산자 우선순위 문제를 방지하기 위해 각각의 독립된 조건식은 반드시 소괄호()로 감싸주어야 합니다.

# [AND 조건] 나이가 30대 이상이면서 가입여부가 'Active'인 고객 추출
active_30s = customer_df[(customer_df['나이'] >= 30) & (customer_df['가입여부'] == 'Active')]

# [OR 조건] 가입여부가 'Inactive'이거나 구매금액이 50만 원 이상인 고객 추출
target_group = customer_df[(customer_df['가입여부'] == 'Inactive') | (customer_df['구매금액'] >= 500000)]

오류 방지 팁: 파이썬 기본 조건문에서 쓰이는 andor 키워드를 판다스 불리언 인덱싱에 사용하면 ValueError가 발생하므로 반드시 기호인 &|를 사용해야 합니다.

2. 직관적인 가독성을 제공하는 query() 함수

2.1. query() 함수의 개념 정의

불리언 인덱싱은 안전하고 확실한 필터링 방법이지만, 다중 조건이 늘어날수록 df[...] 내부에 df['컬럼명']을 반복해서 적어야 하므로 코드가 길어지고 가독성이 저하될 우려가 있습니다. 이를 보완해 주는 도구가 바로 query() 함수입니다.

query() 함수는 SQL 쿼리문을 작성하듯이 조건식을 문자열 형태로 전달하여 데이터를 필터링하는 방식입니다.

2.2. query() 함수를 활용한 비즈니스 데이터 필터링

앞서 구현한 조건들을 query() 함수를 통해 재구성해 보겠습니다. 코드의 형태가 훨씬 직관적으로 변하는 것을 확인할 수 있습니다.

# 1. 단일 조건: 구매금액이 30만 원 이상인 고객
df_query1 = customer_df.query("구매금액 >= 300000")

# 2. 다중 조건(AND): 나이가 30세 이상이면서 가입여부가 'Active'인 고객
# 문자열 내부에서 비교하는 대상 문자열은 따옴표 구분을 해주어야 합니다.
df_query2 = customer_df.query("나이 >= 30 and 가입여부 == 'Active'")

# 3. 다중 조건(OR): 가입여부가 'Inactive'이거나 구매금액이 50만 원 이상인 고객
df_query3 = customer_df.query("가입여부 == 'Inactive' or 구매금액 >= 500000")

query() 함수에서는 and, or, not과 같은 논리 연산자를 사용할 수 있으며, 필요에 따라 &, | 연산자도 사용할 수 있습니다.

2.3. query() 함수에서 외부 변수 참조하기

만약 코드 상단에 선언해 둔 특정 변수 값을 query() 식 내부로 가져와 비교하고 싶다면, 변수명 앞에 골뱅이 기호(@)를 붙여서 연동할 수 있습니다.

# 외부 변수 정의
limit_age = 30

# query 함수에서 외부 변수 사용하기
young_customers = customer_df.query("나이 < @limit_age")

이 방식은 전처리 과정을 함수나 루프문으로 추상화하여 동적인 임계값을 적용할 때 유용하게 쓰입니다.

3. Boolean Indexing vs query() 함수 어떤 것을 사용해야 할까?

두 도구 모두 동일한 필터링 결과를 도출하기 때문에 어떤 상황에서 어떤 방식을 채택하는 것이 효율적인지 가이드라인을 세우는 것이 좋습니다.

비교 기준불리언 인덱싱 (Boolean Indexing)query() 함수
코드 가독성대괄호와 df['컬럼']이 중첩되어 다중 조건 시 복잡함SQL과 유사하게 한 줄의 직관적인 문자열로 작성 가능
성능 (대용량 데이터)소규모 데이터 및 보편적인 연산에서 처리 속도가 빠른 경향이 있음단순한 수치 연산 조건에서는 numexpr를 활용해 성능상 이점을 얻을 수 있는 경우가 있음
컬럼명 특수 제약컬럼 이름에 공백이나 특수문자가 포함되어 있어도 정상 작동함컬럼 이름에 공백이나 마침표(.)가 있으면 백틱(`)으로 감싸야 하는 등 제약이 있음
개발 도구 연동IDE 자동완성과 정적 분석 기능을 활용하기 쉬움문자열 형식이므로 자동완성 및 문법 검사 지원이 다소 제한됨

따라서 실무 개발 환경이나 협업 시에는 다음과 같은 기준으로 접근하는 편이 효율적입니다.

  • 컬럼명에 공백이 없고, 문자열 기반의 직관적인 쿼리 표현을 선호하며, 대용량 데이터를 다룰 때는 query() 함수가 유용합니다.
  • 파이썬 개발 도구(IDE)의 자동완성 지원을 온전히 받으며 안전하게 디버깅하고 싶거나, 컬럼명에 공백이나 특수문자가 포함되어 있다면 불리언 인덱싱을 사용하는 것이 구조적으로 안정적일 수 있습니다.

4. 빅데이터분석기사 실기 시험 환경에서의 실전 활용 포인트

빅데이터분석기사 실기(작업형 제1유형)에서는 특정 조건에 부합하는 서브셋 데이터를 걸러낸 뒤 평균, 표준편차, 합계 등의 요약 통계량을 구하는 문제가 빈번하게 출제됩니다.

예를 들어 “고객 등급이 Active인 그룹의 평균 구매금액과 Inactive인 그룹의 평균 구매금액의 차이의 절댓값을 계산하시오”라는 문제가 있다면 아래와 같이 설계할 수 있습니다.

Python

# 1. Active 그룹 구매금액 평균
mean_active = customer_df.loc[customer_df['가입여부'] == 'Active', '구매금액'].mean()

# 2. Inactive 그룹 구매금액 평균
mean_inactive = customer_df.loc[customer_df['가입여부'] == 'Inactive', '구매금액'].mean()

# 3. 차이의 절댓값 계산 (절댓값 함수 abs 사용)
result = abs(mean_active - mean_inactive)
print(result)

이와 같이 불리언 인덱싱과 결합된 .loc 속성은 필터링 조건을 만족하는 행에 대해 특정 컬럼(‘구매금액’)만 한 단계에 가져올 수 있어, 시험장 환경에서 코드 라인 수를 줄이고 메모리 낭비를 줄이는 직관적인 방법이 됩니다.

5. 요약 및 다음 화 안내

  • 불리언 인덱싱: 각 행별 참/거짓 판별 결과에 기반해 필터링하는 방식으로, 다중 조건 시에는 각 조건들을 소괄호()로 묶고 &| 연산자를 활용해야 합니다.
  • query() 함수: SQL과 유사한 문자열 형태로 조건식을 작성하여 데이터를 필터링합니다. 외부 변수를 대입할 때는 @ 기호를 앞에 붙여 호출합니다.
  • 시험 및 실무: 가독성이 요구되는 환경과 컬럼 특성 등에 알맞게 두 필터링 도구를 적절히 병행 선택하는 것이 합리적입니다.

다음 [판다스 8화]에서는 수집 및 필터링을 마친 데이터에 새로운 가치를 부여하는 작업으로, 컬럼 추가·수정·삭제하기: assign과 drop 실무 활용법에 대해 자세하게 학습해 보겠습니다. 데이터의 차원을 조절하고 열 단위 파생변수를 가공하는 효율적인 테크닉을 함께 다뤄봅시다.

댓글 남기기