1학년 / 2학기 / AI-R-PY / 4강

보충: Pandas 기본기능 총정리 (생성·필터·정렬·삭제·병합)

이번 강의에서 배울 것

  • DataFrame, Series, Index의 관계를 설명할 수 있다.
  • dict와 list of dict, 파일에서 DataFrame을 만들고 읽은 직후 점검할 수 있다.
  • 열 선택, 조건 필터, query, loc·iloc을 구분해 쓸 수 있다.
  • sort_values, drop, rename, assign으로 표를 정돈할 수 있다.
  • concat과 merge의 차이, merge의 how 옵션 네 가지를 설명할 수 있다.
  • groupby와 agg로 그룹별 요약표를 만들고 병합 결과를 검증할 수 있다.

학습 경로

이전: 4주차 · 파일 입출력과 Pandas · 다음: 5주차 · NumPy

범위: 보충 자료 pandas_basic_functions_visual_lecture.pdf 1–17쪽. 4주차에서 배운 불러오기·선택·필터를 한 흐름으로 다시 묶고, 정렬·삭제·병합·groupby를 더한다. 6·7주차 실습에서 쓰는 concat, apply, fillna의 바탕이 된다.

단원 도입

구간핵심 질문대표 코드
생성표를 어떻게 만들까?pd.DataFrame, pd.read_csv
필터필요한 행만 어떻게 남길까?df[조건], df.query()
정렬·삭제표를 어떻게 정돈할까?sort_values, drop
병합여러 표를 어떻게 연결할까?merge, concat
요약그룹별로 어떻게 묶어 볼까?groupby().agg()

목표: DataFrame을 표처럼 보고, 코드로 조작하는 감각을 만든다.

형광펜 읽는 법: 노랑 핵심 정의·결론 · 빨강 헷갈리기 쉬운 구분·함정 · 파랑 외워야 할 순서·목록

기본 단위: Series · DataFrame · Index

3쪽

Indexnamedeptscore
0KimA92
1LeeB83
2ParkA77
3ChoiC88

시작 템플릿과 데이터 점검 순서

4쪽

import pandas as pd
 
df = pd.read_csv("sales.csv")
print(df.shape)    # (행 수, 열 수)
print(df.head())   # 앞 5행
df.info()          # 자료형과 결측치
메서드의미확인할 것
df.shape크기행 수가 예상과 같은가
df.head()앞부분열 이름과 값이 정상인가
df.info()구조자료형과 null 여부
df.describe()요약통계이상치와 범위

생성 ① dict와 list of dict

5쪽

data = {
    "name": ["Kim", "Lee", "Park"],
    "dept": ["A", "B", "A"],
    "sales": [120, 95, 180],
}
df = pd.DataFrame(data)
#   name dept  sales
# 0  Kim    A    120
# 1  Lee    B     95
# 2 Park    A    180
 
rows = [{"name": "Kim", "sales": 120}, {"name": "Lee", "sales": 95}]
df2 = pd.DataFrame(rows)   # 한 행 = 딕셔너리 하나
방식생각하는 단위어울리는 데이터
dict of list열 중심: “열 이름: 값 목록”직접 만드는 작은 예제
list of dict행 중심: “한 행 = dict 하나”JSON, 웹 API, XML 파싱 결과 (6주차)

생성 ② 파일에서 읽기

6쪽

df_csv  = pd.read_csv("sales.csv")
df_xlsx = pd.read_excel("sales.xlsx", sheet_name="2026")
 
pd.read_csv("sales.csv", encoding="utf-8-sig")       # 한글이 깨질 때
pd.read_csv("sales.csv", parse_dates=["date"])       # 날짜 열을 날짜형으로
pd.read_csv("sales.csv", usecols=["id", "sales"])    # 필요한 열만
함수입력주요 옵션
read_csvcsv, txtencoding, sep, parse_dates, na_values(7주차)
read_excelxlsxsheet_name, usecols
read_jsonjsonorient, lines
read_sqlDB쿼리, 연결 객체

선택: 열과 행을 정확히 집기

7쪽

idxnamedeptsalescost
0KimA12070
1LeeB9560
2ParkA180100
3ChoiC8852
df["sales"]                       # 한 열 → Series
df[["name", "sales"]]             # 여러 열 → DataFrame (대괄호 두 겹)
df.loc[0:2, ["name", "sales"]]    # 이름 기준 → 행 0, 1, 2 (끝 포함) × 열 2개
df.iloc[0:2, 1:3]                 # 위치 기준 → 행 0, 1 × 열 1, 2 (끝 미포함)

필터 ① 조건식 → 마스크 → 남기기

8쪽

idxnamesalessales >= 100
0Kim120True
1Lee95False
2Park180True
3Choi88False
cond = df["sales"] >= 100     # True/False로 된 Series = 마스크(mask)
df2 = df[cond]                # True인 행(0, 2)만 남음
 
df2 = df[df["sales"] >= 100]  # 한 줄로도 가능

필터 ② 여러 조건 결합하기

9쪽

df[(df["dept"] == "A") & (df["sales"] >= 100)]       # A 부서이면서 매출 100 이상 → Kim, Park
df[df["dept"].isin(["A", "B"])]                      # A 또는 B 부서 → Kim, Lee, Park
df[df["name"].str.contains("Kim", na=False)]         # 이름에 Kim 포함
df[df["sales"].between(88, 120)]                     # 88 이상 120 이하 → Kim, Lee, Choi
df.query("dept == 'A' and sales >= 100")             # query 방식 → Kim, Park
목적문법주의
AND&각 조건을 괄호로 묶기
OR|파이프 기호
NOT~조건 앞에 붙임
목록 포함isin([...])여러 값 비교
범위between(a, b)양 끝 포함

정렬: sort_values와 sort_index

10쪽

df.sort_values("sales")                                     # 오름차순: Choi 88, Lee 95, Kim 120, Park 180
df.sort_values("sales", ascending=False)                    # 내림차순: Park, Kim, Lee, Choi
df.sort_values(["dept", "sales"], ascending=[True, False])  # 부서 오름차순 → 같은 부서 안에서 매출 내림차순
df.sort_index()                                             # 행 인덱스 순서로 되돌리기

삭제·수정: drop, rename, assign

11쪽

df2 = df.drop(columns=["cost"])                    # 열 삭제
df2 = df.drop(index=[0, 2])                        # 행 삭제 → Lee, Choi
df2 = df.rename(columns={"sales": "revenue"})      # 열 이름 변경
df2 = df.assign(profit=df["sales"] - df["cost"])   # 새 열 → 50, 35, 80, 36
namesalescostprofit
Kim1207050
Lee956035
Park18010080

병합 ① concat과 merge의 차이

12쪽

pd.concat([df1, df2], axis=0)                 # 위아래로 (행이 늘어남)
pd.concat([df1, df2], axis=1)                 # 좌우로 (열이 늘어남)
pd.merge(left, right, on="id", how="left")    # id를 기준으로 연결
concat (위아래)merge (key = id)
id 1, 2 + id 3, 4→ id 1, 2, 3, 4id, sales + id, dept→ id, sales, dept

병합 ② how 옵션: inner · left · right · outer

13쪽

left  = pd.DataFrame({"id": [1, 2, 3], "sales": [120, 95, 180]})
right = pd.DataFrame({"id": [2, 3, 4], "grade": ["B", "A", "C"]})
 
pd.merge(left, right, on="id", how="inner")   # id 2, 3
pd.merge(left, right, on="id", how="left")    # id 1, 2, 3   (id 1의 grade는 NaN)
pd.merge(left, right, on="id", how="right")   # id 2, 3, 4   (id 4의 sales는 NaN)
pd.merge(left, right, on="id", how="outer")   # id 1, 2, 3, 4
how남기는 행결과 id
inner (기본값)양쪽 모두 있는 key만2, 3
left왼쪽 표는 모두 유지1, 2, 3
right오른쪽 표는 모두 유지2, 3, 4
outer한쪽에만 있어도 유지1, 2, 3, 4

groupby로 요약표 만들기

14쪽

summary = (
    df.groupby("dept", as_index=False)
      .agg(sum_sales=("sales", "sum"),
           avg_sales=("sales", "mean"),
           n=("sales", "count"))
)
#   dept  sum_sales  avg_sales  n
# 0    A        300      150.0  2
# 1    B         95       95.0  1
# 2    C         88       88.0  1

미니 프로젝트: 매출 데이터 정리 파이프라인

15쪽

orders = pd.DataFrame({
    "order_id": ["o1", "o2", "o3"],
    "customer_id": ["c1", "c2", "c1"],
    "amount": [120, 95, 180],
})
customers = pd.DataFrame({
    "customer_id": ["c1", "c2", "c3"],
    "region": ["Seoul", "Busan", "Daegu"],
})
 
result = (
    orders.merge(customers, on="customer_id", how="left")   # ① 주문에 지역 붙이기
          .query("amount >= 100")                           # ② 100 이상만
          .sort_values("amount", ascending=False)           # ③ 큰 순서로
          .groupby("region", as_index=False)["amount"].sum()  # ④ 지역별 합계
)
#   region  amount
# 0  Seoul     300

자주 나는 오류와 디버깅 순서

16쪽

오류·증상주요 원인확인 코드
KeyError열 이름 오타·공백df.columns
빈 결과조건식과 실제 값 불일치df["열"].unique()
정렬 이상숫자가 문자열df.dtypes
merge 후 행 폭증key 중복value_counts()
SettingWithCopyWarning필터한 부분 복사본을 수정.loc 사용
print(df.columns)                      # 1. 열 이름
print(df.dtypes)                       # 2. 자료형
print(df.isna().sum())                 # 3. 결측치
print(df["id"].value_counts().head())  # 4. key 중복

핵심 문법 요약

17쪽

구간문법
생성pd.DataFrame(data), pd.read_csv("file.csv")
확인df.head(), df.info(), df.shape
선택df["col"], df[["a", "b"]], df.loc[rows, cols]
필터df[df["x"] >= 10], df.query("x >= 10")
정렬df.sort_values("x"), df.sort_index()
삭제·수정df.drop(columns=["x"]), df.rename(columns={"a": "b"})
병합pd.concat([a, b]), a.merge(b, on="id", how="left")
요약df.groupby("g").agg(...), df.value_counts()

정답과 해설

1. df[["name"]]은 열이 하나인 DataFrame, df["name"]은 Series다. 대괄호를 두 겹 쓰면 “열 목록”으로 고른 것이라 표 모양이 유지된다.

2. 4행(id 1, 2, 3, 4). 한쪽에만 있는 id도 모두 남는다.

3. 예시 답안:

result = (
    orders.merge(customers, on="customer_id", how="left")
          .query("order_date.dt.year == 2026")
          .groupby("customer_id", as_index=False)["amount"].sum()
          .sort_values("amount", ascending=False)
)

정렬은 합계를 구한 뒤에 해야 “고객별 합계의 내림차순”이 된다. query 대신 [lambda d: d["order_date"].dt.year == 2026]나, 미리 만든 마스크로 걸러도 된다. 날짜가 문자열이면 먼저 pd.to_datetime()으로 바꾼다.

플래시카드

보충 Pandas — DataFrame, Series, Index의 관계는?

DataFrame은 표 전체, Series는 한 열(한 줄), Index는 행의 주소(행 이름)다.

보충 Pandas — 데이터를 읽은 직후 점검하는 3단계는?

① 열 이름(공백·대소문자·오타) ② 자료형(숫자·날짜가 문자열인지) ③ 결측치. 코드로는 df.columns, df.dtypes/info(), df.isna().sum().

보충 Pandas — df["a"], df[["a", "b"]], df[조건]의 차이는?

열 하나(Series), 열 여러 개(DataFrame), 조건이 True인 행만 남긴 행 필터.

보충 Pandas — 여러 조건 필터에서 가장 흔한 실수는?

비교식마다 괄호를 빼먹는 것. (df.a == 1) & (df.b >= 2)처럼 괄호로 묶고, and/or/not 대신 &, |, ~를 쓴다.

보충 Pandas — concat과 merge의 차이는?

concat은 같은 구조의 표를 위아래·좌우로 단순히 붙이고, merge는 공통 key 열을 기준으로 서로 다른 정보를 짝지어 연결한다.

보충 Pandas — merge의 how 네 가지는?

inner(양쪽 모두 있는 key만, 기본값), left(왼쪽 모두 유지), right(오른쪽 모두 유지), outer(한쪽에만 있어도 유지). 짝 없는 칸은 NaN.

보충 Pandas — groupby의 Split-Apply-Combine이란?

같은 값끼리 나누고(split), 그룹마다 계산하고(apply), 결과를 한 표로 합친다(combine).

보충 Pandas — merge 후 행 수가 갑자기 늘었다면?

key 중복을 의심한다. 병합 전후 행 수와 value_counts()로 key별 건수를 확인한다.

핵심 점검

  • DataFrame에서 한 열을 꺼내면 가 된다.
  • 필터는 조건식 → True/False → True인 행만 남기는 흐름이다.
  • between(a, b)는 양 끝을 한다.
  • sort_values(..., ascending=False)는 정렬이다.
  • 공통 key로 두 표를 연결하는 함수는 , 단순히 붙이는 함수는 이다.
  • how를 생략한 merge는 조인이다.
  • merge 후 행이 늘면 을 의심한다.
오늘도 한 걸음 앞으로.

내용을 이해했다면 학습 완료를 체크해 주세요.

학습 기록은 현재 브라우저에 저장됩니다.
HJS / STUDY한지석