🧩 Pandas란?
Pandas는 파이썬 프로그래밍 언어를 기반으로 구축된 빠르고 강력하며 유연하고 사용하기 쉬운 오픈소스 데이터 분석 및 조작 도구다. (Pandas 공식 웹사이트 발췌)
Pandas는 표 형태의 데이터를 다루기 위한 파이썬 라이브러리다. NumPy가 숫자 배열을 빠르게 계산하는 도구라면, Pandas는 열 이름이 있는 표 데이터를 편하게 다루는 도구라고 보면 된다. 보통 엑셀이나 CSV 등에서 읽어 온 데이터를 정리하고 분석하는 데 많이 사용된다.
핵심 자료구조
| 자료구조 | 설명 | 비유 |
Series |
한 줄(열)의 데이터 | 엑셀의 한 열 |
DataFrame |
행과 열로 이루어진 표 | 엑셀 시트 전체 |

Series (한 줄짜리 데이터)
Series는 값과 인덱스를 함께 가진 1차원 데이터이다.
- 아래 코드에서 0, 1, 2는 인덱스이고, 오른쪽이 실제 값이다.
import pandas as pd
s = pd.Series([10, 20, 30])
print(s)
'''
0 10
1 20
2 30
dtype: int64
'''
- 직접 인덱스 지정하기: 값에 이름을 붙일 수 있다.
import pandas as pd
scores = pd.Series(
[85, 92, 78],
index=["민수", "지영", "철수"]
)
print(scores)
'''
민수 85
지영 92
철수 78
dtype: int64
'''
print(scores["지영"]) # 92
DataFrame (행과 열로 이루어진 표 전체)
DataFrame은 여러 Series를 모은 2차원 테이블이다.
import pandas as pd
df = pd.DataFrame({
"이름": ["민수", "지영", "철수"],
"나이": [20, 22, 21],
"점수": [85, 92, 78]
})
print(df)
'''
이름 나이 점수
0 민수 20 85
1 지영 22 92
2 철수 21 78
'''
- 각 열: 이름, 나이, 점수
- 각 행: 한 사람의 데이터
- 기본 행 인덱스: 0, 1, 2
CSV 파일 읽기
import pandas as pd
df = pd.read_csv("students.csv")
print(df)
'''
이름 나이 점수
0 수만 20 85
1 진영 22 92
2 현석 21 78
3 시혁 24 89
4 재용 25 99
5 태원 27 72
6 창섭 21 88
'''
# pd.read_csv("data.csv")
# pd.read_excel("data.xlsx")
# pd.read_json("data.json")
# pd.read_sql(...)
데이터 기본 정보 확인
head()/tail(): 처음/마지막 N개 행 (기본값 5개)
print(df.head()) # 처음 5개 행
'''
이름 나이 점수
0 수만 20 85
1 진영 22 92
2 현석 21 78
3 시혁 24 89
4 재용 25 99
'''
print(df.tail()) # 마지막 5개 행
'''
이름 나이 점수
2 현석 21 78
3 시혁 24 89
4 재용 25 99
5 태원 27 72
6 창섭 21 88
'''
shape: 행과 열의 개수
print(df.shape) # (7, 3)
columns: 열 이름 목록
print(df.columns)
# Index(['이름', '나이', '점수'], dtype='object')
info(): 열별 자료형, 결측치 개수 등
print(df.info())
'''
<class 'pandas.DataFrame'>
RangeIndex: 7 entries, 0 to 6
Data columns (total 3 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 이름 7 non-null str
1 나이 7 non-null int64
2 점수 7 non-null int64
dtypes: int64(2), str(1)
memory usage: 300.0 bytes
None
'''
describe(): 숫자에 대한 기초 통계
print(df.describe())
'''
나이 점수
count 7.000000 7.000000
mean 22.857143 86.142857
std 2.544836 8.933618
min 20.000000 72.000000
25% 21.000000 81.500000
50% 22.000000 88.000000
75% 24.500000 90.500000
max 27.000000 99.000000
'''
열 선택하기
- 하나의 열 선택:
Series반환
print(df["이름"])
'''
0 수만
1 진영
2 현석
3 시혁
4 재용
5 태원
6 창섭
Name: 이름, dtype: str
'''
print(type(df["이름"]))
# <class 'pandas.Series'>
- 여러 열 선택:
DataFrame반환
print(df[["이름", "점수"]])
'''
이름 점수
0 수만 85
1 진영 92
2 현석 78
3 시혁 89
4 재용 99
5 태원 72
6 창섭 88
'''
행 선택하기
loc: 이름 기준 선택 (인덱스 이름 및 열 이름으로 선택)
import pandas as pd
# df = pd.read_csv("students.csv")
# print(df.loc["재용"])
# KeyError: '재용'
df = pd.DataFrame(
{
"나이": [25, 27, 21],
"점수": [99, 72, 88]
},
index=["재용", "태원", "창섭"]
)
print(df.loc["재용"])
'''
나이 25
점수 99
Name: 재용, dtype: int64
'''
print(df.loc["재용", "점수"])
# 99
print(df.loc[["재용", "태원"], ["나이", "점수"]])
'''
나이 점수
재용 25 99
태원 27 72
'''
iloc: 정수 위치 기준 선택 (행 번호로 선택)
df = pd.read_csv("students.csv")
print(df.iloc[0]) # 1번째 행 가져옴
'''
이름 수만
나이 20
점수 85
Name: 0, dtype: object
'''
print(df.iloc[0:2]) # 0~1번째 행 가져옴
'''
이름 나이 점수
0 수만 20 85
1 진영 22 92
'''
print(df.iloc[0, 2]) # 0행 2열의 데이터 가져옴
# 85
당연히 df = pd.read_csv(...)에서도 .loc는 당연히 사용할 수 있다. 다만 보통은 loc가 찾는 "인덱스 이름"과 실제 DataFrame의 인덱스가 다르기 때문에 선택이 안 된다.
import pandas as pd
df = pd.read_csv("students.csv")
print(df)
'''
이름 나이 점수
0 수만 20 85
1 진영 22 92
2 현석 21 78
(이하 생략)
'''
여기서 인덱스는 0, 1, 2, ...이고 "이름"은 그냥 일반 열이다.
print(df.index)
# RangeIndex(start=0, stop=7, step=1)
그래서 인덱스 번호로 접근하는 것은 가능하지만 이름으로 접근하는 것은 불가능하다. ('수만'은 인덱스가 아니라 이름 열의 값이기 떄문)
print(df.loc[0])
'''
이름 수만
나이 20
점수 85
Name: 0, dtype: object
'''
이름 열을 기준으로 찾고 싶다면?
- 조건 필터링
print(df[df["이름"] == "수만"])
'''
이름 나이 점수
0 수만 20 85
'''
print(df.loc[df["이름"] == "수만", "점수"])
'''
0 85
Name: 점수, dtype: int64
'''
set_index()로 열을 인덱스로 바꾸기
df = df.set_index("이름")
print(df)
'''
나이 점수
이름
수만 20 85
진영 22 92
현석 21 78
(이하 생략)
'''
print(df.loc["수만"])
'''
나이 20
점수 85
Name: 수만, dtype: int64
'''
- CSV를 읽을 때부터 인덱스로 지정하기
df = pd.read_csv("students.csv", index_col="이름")
print(df)
'''
나이 점수
이름
수만 20 85
진영 22 92
현석 21 78
(이하 생략)
'''
df.loc["수만", "점수"] # 85
조건으로 데이터 필터링하기
- 점수가 90점 이상인 사람 필터링
result = df[df["점수"] >= 90]
print(result)
'''
이름 나이 점수
1 진영 22 92
4 재용 25 99
'''
- 조건식 자체는 True, False로 이뤄진 Series를 만든다.
print(df["점수"] >= 90)
'''
0 False
1 True
2 False
(이하 생략)
Name: 점수, dtype: bool
'''
- 다중 조건 필터링
# 나이가 22 이상이고 점수가 80 이상인 사람 찾기
result = df[(df["나이"] >= 22) & (df["점수"] >= 80)]
print(result)
'''
이름 나이 점수
1 진영 22 92
3 시혁 24 89
4 재용 25 99
'''
- isin: 특정 값에 포함되는지 확인
print(df[df["이름"].isin(["재용", "창섭"])])
'''
이름 나이 점수
4 재용 25 99
6 창섭 21 88
'''
열 추가와 수정
- 새 열 추가하기
df["합격"] = df["점수"] >= 80
print(df)
'''
이름 나이 점수 합격
0 수만 20 85 True
1 진영 22 92 True
2 현석 21 78 False
3 시혁 24 89 True
4 재용 25 99 True
5 태원 27 72 False
6 창섭 21 88 True
'''
- 계산 결과를 새 열로 저장
df["점수_2배"] = df["점수"] * 2
print(df)
'''
이름 나이 점수 점수_2배
0 수만 20 85 170
1 진영 22 92 184
2 현석 21 78 156
3 시혁 24 89 178
4 재용 25 99 198
5 태원 27 72 144
6 창섭 21 88 176
'''
df["등급"] = "일반"
df.loc[df["점수"] >= 90, "등급"] = "우수"
df.loc[df["점수"] < 80, "등급"] = "과락"
print(df)
'''
이름 나이 점수 등급
0 수만 20 85 일반
1 진영 22 92 우수
2 현석 21 78 과락
3 시혁 24 89 일반
4 재용 25 99 우수
5 태원 27 72 과락
6 창섭 21 88 일반
'''
정렬하기
# 점수 기준 오름차순 정렬
print(df.sort_values("점수"))
'''
이름 나이 점수
5 태원 27 72
2 현석 21 78
0 수만 20 85
6 창섭 21 88
3 시혁 24 89
1 진영 22 92
4 재용 25 99
'''
# 점수 기준 내림차순 정렬
print(df.sort_values("점수", ascending=False))
'''
이름 나이 점수
4 재용 25 99
1 진영 22 92
3 시혁 24 89
6 창섭 21 88
0 수만 20 85
2 현석 21 78
5 태원 27 72
'''
# 나이 기준 오름차순, 나이가 같으면 점수 기준 내림차순
df = df.sort_values(
by=["나이", "점수"],
ascending=[True, False]
)
print(df)
'''
이름 나이 점수
0 수만 20 85
6 창섭 21 88
2 현석 21 78
1 진영 22 92
3 시혁 24 89
4 재용 25 99
5 태원 27 72
'''
결측치 다루기
numpy.nan: NaN(Not a Number)로 결측치를 표현
import numpy as np
import pandas as pd
df = pd.DataFrame({
"이름": ["민수", "지영", "철수"],
"나이": [20, np.nan, 21],
"점수": [85, 92, np.nan]
})
print(df)
'''
이름 나이 점수
0 민수 20.0 85.0
1 지영 NaN 92.0
2 철수 21.0 NaN
'''
- isna(): 결측치 확인
print(df.isna())
'''
이름 나이 점수
0 False False False
1 False True False
2 False False True
'''
print(df.isna().sum())
'''
이름 0
나이 1
점수 1
dtype: int64
'''
dropna(): 결측치가 있는 행 제거
print(df.dropna())
'''
이름 나이 점수
0 민수 20.0 85.0
'''
fillna(): 결측치를 측정 값으로 채움
df["나이"] = df["나이"].fillna(df["나이"].mean()) # 나이 결측치를 평균 나이로 채움
df["점수"] = df["점수"].fillna(0) # 점수 결측치를 0으로 채움
print(df)
'''
이름 나이 점수
0 민수 20.0 85.0
1 지영 20.5 92.0
2 철수 21.0 0.0
'''
groupby: 그룹별 집계
df = pd.DataFrame({
"이름": ["민수", "지영", "철수", "수진", "영희"],
"반": ["A", "A", "B", "B", "A"],
"점수": [85, 92, 78, 95, 88]
})
print(df)
'''
이름 반 점수
0 민수 A 85
1 지영 A 92
2 철수 B 78
3 수진 B 95
4 영희 A 88
'''
# 반별 평균 점수
print(df.groupby("반")["점수"].mean())
'''
반
A 88.333333
B 86.500000
Name: 점수, dtype: float64
'''
# 반별 점수 합계
print(df.groupby("반")["점수"].sum())
'''
반
A 265
B 173
Name: 점수, dtype: int64
'''
# 반별 학생 수
print(df.groupby("반")["이름"].count())
'''
반
A 3
B 2
Name: 이름, dtype: int64
'''
# 반별 점수 다중 집계
print(df.groupby("반")["점수"].agg(["count", "mean", "min", "max", "sum"]))
'''
count mean min max sum
반
A 3 88.333333 85 92 265
B 2 86.500000 78 95 173
'''
merge: 여러 테이블 합치기
students = pd.DataFrame({
"학생번호": [1, 2, 3, 4, 5],
"이름": ["현준", "상혁", "수환", "민석", "지훈"]
})
scores = pd.DataFrame({
"학생번호": [1, 2, 3, 4, 6],
"점수": [78, 92, 85, 72, 67]
})
# inner join (양쪽에 모두 있는 데이터만)
print(pd.merge(students, scores, on="학생번호"))
'''
학생번호 이름 점수
0 1 현준 78
1 2 상혁 92
2 3 수환 85
3 4 민석 72
'''
# left join (왼쪽 테이블은 모두 유지)
print(pd.merge(students, scores, on="학생번호", how="left"))
'''
학생번호 이름 점수
0 1 현준 78.0
1 2 상혁 92.0
2 3 수환 85.0
3 4 민석 72.0
4 5 지훈 NaN
'''
# right join (오른쪽 테이블은 모두 유지)
print(pd.merge(students, scores, on="학생번호", how="right"))
'''
학생번호 이름 점수
0 1 현준 78
1 2 상혁 92
2 3 수환 85
3 4 민석 72
4 6 NaN 67
'''
# outer join (양쪽 데이터를 모두 유지)
print(pd.merge(students, scores, on="학생번호", how="outer"))
'''
학생번호 이름 점수
0 1 현준 78.0
1 2 상혁 92.0
2 3 수환 85.0
3 4 민석 72.0
4 5 지훈 NaN
5 6 NaN 67.0
'''
concat: 행 방향으로 붙이기
merge가 공통 열을 기준으로 옆으로 합치는 기능이라면, concat은 표를 상하 또는 좌우로 이어 붙이는 기능이다.
df1 = pd.DataFrame({
"이름": ["우제", "진혁"],
"점수": [85, 92]
})
df2 = pd.DataFrame({
"이름": ["건우", "민형", "환중"],
"점수": [78, 95, 72]
})
# ignore_index: 기존 인덱스를 무시하고 새로 0부터 붙임
result = pd.concat([df1, df2], ignore_index=True)
print(result)
'''
이름 점수
0 우제 85
1 진혁 92
2 건우 78
3 민형 95
4 환중 72
'''
str: 문자열 데이터 다루기
df = pd.DataFrame({
"이름": ["Doran", "Oner", "Faker"]
})
# 모두 소문자로
print(df["이름"].str.lower())
'''
0 doran
1 oner
2 faker
Name: 이름, dtype: str
'''
# 특정 문자열 포함 여부
print(df["이름"].str.contains("er"))
'''
0 False
1 True
2 True
Name: 이름, dtype: bool
'''
# 길이
print(df["이름"].str.len())
'''
0 5
1 4
2 5
Name: 이름, dtype: int64
'''
# 특정 문자 기준 분리
print(df["이름"].str.split("r"))
'''
0 [Do, an]
1 [One, ]
2 [Fake, ]
Name: 이름, dtype: object
'''
날짜 데이터 다루기
df = pd.DataFrame({
"날짜": ["2026-06-05", "2026-07-05", "2026-08-05"],
"매출": [100, 200, 150]
})
# 날짜형으로 변환
df["날짜"] = pd.to_datetime(df["날짜"])
# 연도, 연, 요일 추출
df["연도"] = df["날짜"].dt.year
df["월"] = df["날짜"].dt.month
df["요일"] = df["날짜"].dt.day_name()
print(df)
'''
날짜 매출 연도 월 요일
0 2026-06-05 100 2026 6 Friday
1 2026-07-05 200 2026 7 Sunday
2 2026-08-05 150 2026 8 Wednesday
'''
# 월별 매출 합계
print(df.groupby("월")["매출"].sum())
'''
월
6 100
7 200
8 150
Name: 매출, dtype: int64
'''
apply: 사용자 정의 함수 적용
df = pd.DataFrame({
"점수": [85, 92, 78]
})
def grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
return "C"
df["등급"] = df["점수"].apply(grade)
print(df)
'''
점수 등급
0 85 B
1 92 A
2 78 C
'''
- 람다식, 벡터 연산 또는
np.where()도 사용 가능
df["점수_2배"] = df["점수"].apply(lambda x: x * 2)
df["점수_2배"] = df["점수"] * 2
df["합격"] = np.where(df["점수"] >= 80, "합격", "불합격")
실제 데이터 분석 흐름 예시
import pandas as pd
# 1. 파일 읽기
df = pd.read_csv("data.csv")
# 2. 구조 확인
print(df.head())
print(df.info())
print(df.isna().sum())
# 3. 필요한 열만 선택
df = df[["이름", "나이", "점수"]]
# 4. 결측치 처리
df = df.dropna()
# 5. 조건 필터링
df = df[df["점수"] >= 80]
# 6. 새 열 생성
df["등급"] = "일반"
df.loc[df["점수"] >= 90, "등급"] = "우수"
# 7. 그룹별 통계
result = df.groupby("등급")["점수"].mean()
# 8. 정렬
result = result.sort_values(ascending=False)
print(result)
주요 핵심 문법 정리
df = pd.read_csv("data.csv") # 파일 읽기
df.head() # 앞부분 보기
df.info() # 구조 확인
df["열이름"] # 한 열 선택
df[["열1", "열2"]] # 여러 열 선택
df[df["점수"] >= 90] # 조건 필터링
df.loc[df["점수"] >= 90, "등급"] = "A" # 조건에 따라 값 수정
df.sort_values("점수") # 정렬
df.isna().sum() # 결측치 개수
df.dropna() # 결측치 제거
df.fillna(0) # 결측치 채우기
df.groupby("반")["점수"].mean() # 그룹별 평균
pd.merge(df1, df2, on="id") # 표 합치기
🧩 NumPy와 Pandas의 관계
Pandas는 내부적으로 NumPy를 많이 활용한다.
| 구분 | NumPy | Pandas |
| 주 목적 | 수치 배열 연산 | 표 데이터 처리 |
| 주요 객체 | ndarray |
Series, DataFrame |
| 열 이름 | ❌ | ⭕ |
| 행 인덱스 | 단순 위치 중심 | 이름 기반 인덱스 가능 |
| 결측치 처리 | 상대적으로 불편 | 강력함 |
| CSV 처리 | 직접 구현 필요 | 매우 편리함 |
| 그룹별 집계 | 직접 구현 필요 | groupby 제공 |
[ 참고자료 ]
- Pandas API Reference 문서
API reference — pandas 3.0.5 documentation
This page gives an overview of all public pandas objects, functions and methods. All classes and functions exposed in pandas.* namespace are public. The following subpackages are public. In addition, public functions in pandas.io, pandas.tseries, pandas.ut
pandas.pydata.org
'CS > Python' 카테고리의 다른 글
| 파이썬으로 데이터 전처리 찍먹하기 (0) | 2026.08.07 |
|---|---|
| 파이썬으로 데이터 시각화 찍먹하기 (0) | 2026.08.06 |
| 파이썬의 NumPy 라이브러리에 대해 알아보기 (0) | 2026.08.05 |
| 파이썬으로 플로이드-워셜 알고리즘 구현하기 (0) | 2025.04.01 |
| 파이썬으로 MST 알고리즘 구현하기 (0) | 2025.04.01 |