DataFrame 가공 — 필터, 정렬, 그룹
이 토픽을 마치면
pandas DataFrame에서 조건으로 데이터를 추출하고, 정렬하고, 그룹별로 집계할 수 있습니다.
데이터 준비
import pandas as pd
df = pd.DataFrame({ "이름": ["김훈", "이수", "박진", "최영", "정민"], "부서": ["개발", "마케팅", "개발", "마케팅", "개발"], "나이": [30, 25, 35, 28, 32], "연봉": [5000, 3500, 6000, 4000, 5500]})이 5행짜리 테이블로 핵심 기법을 모두 익힐 수 있습니다.
열 선택
# 단일 열 — Series 반환df["이름"]
# 여러 열 — DataFrame 반환df[["이름", "연봉"]]
# 새 열 추가df["세후연봉"] = df["연봉"] * 0.85
# 열 삭제df = df.drop(columns=["세후연봉"])대괄호 하나(df["이름"])와 이중 대괄호(df[["이름", "연봉"]])의 차이를 주의합니다. 하나면 Series, 둘이면 DataFrame입니다.
필터링 — 조건으로 행 추출
# 단일 조건df[df["나이"] >= 30]# 이름 부서 나이 연봉# 0 김훈 개발 30 5000# 2 박진 개발 35 6000# 4 정민 개발 32 5500
# 복합 조건 — & (AND), | (OR)df[(df["부서"] == "개발") & (df["연봉"] >= 5500)]# 이름 부서 나이 연봉# 2 박진 개발 35 6000# 4 정민 개발 32 5500
# 문자열 포함 검색df[df["이름"].str.contains("김")]
# 값 목록 중 하나에 해당df[df["부서"].isin(["개발", "기획"])]조건을 ()로 감싸고 &나 |로 연결합니다. Python의 and/or와 다릅니다 — DataFrame 필터링에서는 반드시 &/|를 씁니다.
정렬
# 단일 열 기준df.sort_values("연봉") # 오름차순 (낮은→높은)df.sort_values("연봉", ascending=False) # 내림차순
# 다중 열 기준df.sort_values(["부서", "연봉"], ascending=[True, False])# 부서 오름차순 → 같은 부서 내에서 연봉 내림차순
# 인덱스 리셋 (정렬 후 인덱스가 뒤섞이므로)df_sorted = df.sort_values("연봉").reset_index(drop=True)reset_index(drop=True)를 넣지 않으면 원래 인덱스가 그대로 남아서 0, 3, 1, 4, 2 같은 순서가 됩니다.
그룹 집계 — groupby
데이터 분석의 가장 강력한 도구입니다. "부서별 평균 연봉은?" 같은 질문에 한 줄로 답합니다.
# 기본 — 부서별 평균df.groupby("부서")["연봉"].mean()# 개발 5500.0# 마케팅 3750.0
# 여러 집계 함수df.groupby("부서")["연봉"].agg(["mean", "min", "max", "count"])# mean min max count# 개발 5500 5000 6000 3# 마케팅 3750 3500 4000 2
# 여러 열 집계df.groupby("부서").agg({ "연봉": "mean", "나이": "max"})# 연봉 나이# 개발 5500 35# 마케팅 3750 28groupby는 SQL의 GROUP BY와 같은 개념입니다. 분리(split) → 적용(apply) → 결합(combine) 패턴으로 작동합니다.
실전 패턴 — 종합 가공
# "개발 부서에서 연봉 5000 이상인 사람을 연봉 내림차순으로"result = ( df[df["부서"] == "개발"] .query("연봉 >= 5000") .sort_values("연봉", ascending=False) .reset_index(drop=True))
# 부서별 인원 수와 평균 연봉을 한 번에summary = ( df.groupby("부서") .agg( 인원수=("이름", "count"), 평균연봉=("연봉", "mean"), 최고연봉=("연봉", "max") ) .sort_values("평균연봉", ascending=False)).query()는 문자열로 조건을 쓰는 방식입니다. 복잡한 조건에서 df[(df["a"] > 1) & (df["b"] < 5)]보다 가독성이 좋습니다.
자주 쓰는 메서드 정리
| 작업 | 메서드 | 예시 |
|---|---|---|
| 조건 필터 | df[조건] | df[df["age"] > 30] |
| 열 선택 | df[["a", "b"]] | df[["이름", "연봉"]] |
| 정렬 | sort_values() | df.sort_values("연봉") |
| 그룹 집계 | groupby().agg() | df.groupby("부서")["연봉"].mean() |
| 상위 N개 | nlargest() / nsmallest() | df.nlargest(3, "연봉") |
| 고유값 | unique() / nunique() | df["부서"].nunique() |
| 값 분포 | value_counts() | df["부서"].value_counts() |
핵심 정리
DataFrame 가공은 "무엇을 보고 싶은가"를 코드로 표현하는 과정입니다. 필터(어떤 행?), 정렬(어떤 순서?), 그룹(어떤 기준으로 묶어서?), 집계(무엇을 계산?) — 이 네 가지 동사만으로 대부분의 데이터 질문에 답할 수 있습니다. SQL을 알고 있다면 SELECT ... WHERE ... GROUP BY ... ORDER BY와 1:1 대응된다고 생각하면 됩니다.