CS/Python

파이썬의 Pandas 라이브러리에 대해 알아보기

munsik22 2026. 8. 6. 11:15

🧩 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