Python 데이터 분석 기초 : Pandas 핵심 정리
Python으로 데이터 분석을 할 때 가장 많이 사용하는 라이브러리 중 하나가 바로 Pandas다. NumPy가 숫자 배열 연산에 강점을 가진다면, Pandas는 엑셀처럼 행과 열로 구성된 테이블 데이터를 다루는 데 강점을 가진다.
이번 글에서는 Pandas의 기본 개념부터 Series와 DataFrame, 데이터 불러오기, 기본 탐색, 속성과 메서드, 데이터 선택, 컬럼 생성, 정렬, 그리고 Tips 데이터셋을 활용한 간단한 실습까지 해봤다.
Pandas는 Python에서 테이블 형태의 데이터를 다루기 위한 핵심 라이브러리다. 데이터 불러오기, 결측치 확인, 컬럼 선택, 조건 필터링, 새로운 변수 생성, 정렬, 그룹 분석 등 데이터 전처리와 탐색 분석의 중심 역할을 한다.
1. Pandas란?
1-1. Pandas 라이브러리 소개
Pandas는 Python Data Analysis Library의 의미를 가진 라이브러리로, 파이썬에서 데이터 조작과 분석을 위한 가장 핵심적인 도구 중 하나다. 엑셀의 스프레드시트처럼 행과 열로 이루어진 테이블 형태의 데이터를 다룰 수 있으며, 데이터 전처리와 탐색 분석 과정에서 매우 자주 사용된다.
- 엑셀의 스프레드시트와 비슷한 테이블 형태의 데이터를 다룰 수 있음
- 결측치 처리, 데이터 변환, 집계 등 전처리 작업에 활용
- 시각화와 머신러닝으로 연결되는 데이터 파이프라인의 중심 역할
실제 데이터 분석에서는 모델링보다 데이터를 불러오고, 정리하고, 필요한 형태로 변환하는 시간이 더 오래 걸리는 경우가 많다. Pandas는 이 전처리 과정을 효율적으로 처리하기 위한 핵심 도구다.
1-2. Pandas 설치 및 import
먼저 터미널이나 명령 프롬프트에서 Pandas를 설치한다.
pip install pandas
Jupyter Notebook이나 Python 파일에서는 일반적으로 아래와 같이 Pandas를 불러온다.
import pandas as pd
pandas를 pd로 줄여서 import하는 것은 전 세계 데이터 분석가들이 사용하는 관례다. 코드를 간결하게 만들고, 다른 사람이 코드를 읽기 쉽게 해준다. 설치된 Pandas 버전은 다음과 같이 확인할 수 있다.
print(f"Pandas 버전: {pd.__version__}") # 출력 결과는 설치 환경에 따라 다르다.
Pandas 버전: 2.2.3
2. 데이터 구조 이해하기
2-1. Series와 DataFrame의 개념
Pandas에는 두 가지 핵심 데이터 구조가 있다. 하나는 Series, 다른 하나는 DataFrame이다.
- Series: 하나의 컬럼으로 이루어진 1차원 데이터 구조다. 인덱스와 값으로 구성되며, 리스트나 배열과 비슷하지만 더 다양한 기능을 제공한다.
- DataFrame: 여러 개의 컬럼으로 이루어진 2차원 테이블 구조다. 행과 열로 구성된 엑셀 시트와 유사하며, 여러 개의 Series가 모여 만들어진 구조라고 볼 수 있다.
2-2. Series 생성 및 확인
먼저 리스트를 이용해 간단한 Series를 생성해본다.
ages = pd.Series([25, 30, 35, 28, 32])
print("Series 예제:")
print(ages)
Series 예제:
0 25
1 30
2 35
3 28
4 32
dtype: int64
생성된 객체의 타입도 확인할 수 있다.
print(f"타입: {type(ages)}")
타입: <class 'pandas.core.series.Series'>
2-3. DataFrame 생성 및 확인
DataFrame은 딕셔너리 형태의 데이터를 이용해 쉽게 만들 수 있다. 각 key는 컬럼명이 되고, 각 value는 컬럼의 값이 된다.
df = pd.DataFrame({
'name': ['김철수', '이영희', '박민수', '최지은', '정대한'],
'age': [25, 30, 35, 28, 45],
'city': ['서울', '부산', '대구', '인천', '광주'],
'salary': [3500, 4200, 3800, 4100, 5200]
})
print(df)
name age city salary
0 김철수 25 서울 3500
1 이영희 30 부산 4200
2 박민수 35 대구 3800
3 최지은 28 인천 4100
4 정대한 45 광주 5200
DataFrame의 타입은 다음과 같이 확인할 수 있다.
print(f"타입: {type(df)}")
타입: <class 'pandas.core.frame.DataFrame'>
2-4. 기본 속성 활용하기
DataFrame을 만든 뒤에는 데이터의 크기, 컬럼명, 인덱스, 데이터 타입을 확인할 수 있다.
print(f"데이터 크기: {df.shape}")
print(f"컬럼명: {df.columns}")
print(f"인덱스: {df.index}")
print("데이터 타입:")
print(df.dtypes)
데이터 크기: (5, 4)
컬럼명: Index(['name', 'age', 'city', 'salary'], dtype='object')
인덱스: RangeIndex(start=0, stop=5, step=1)
데이터 타입:
name object
age int64
city object
salary int64
dtype: object
컬럼명은 전체를 한 번에 변경할 수도 있고, 특정 컬럼만 선택해서 변경할 수도 있다.
df.columns = ['이름', '나이', '도시', '연봉']
print("변경된 컬럼명:")
print(df.columns.tolist())
df.rename(columns={'연봉': '급여'}, inplace=True)
print("일부 컬럼명 변경:")
print(df.columns.tolist())
변경된 컬럼명:
['이름', '나이', '도시', '연봉']
일부 컬럼명 변경:
['이름', '나이', '도시', '급여']
3. 데이터 불러오기 및 기본 탐색
3-1. CSV 파일 불러오기
Pandas에서 가장 많이 사용하는 데이터 입력 방식은 CSV 파일을 불러오는 것이다. CSV 파일은 쉼표로 구분된 텍스트 파일로, 데이터 분석에서 가장 자주 사용되는 파일 형식 중 하나다.
df = pd.read_csv('파일경로/파일명.csv')
파일 경로에는 절대경로와 상대경로가 있다.
- 절대경로: 내 PC 기준으로 해당 파일이 어느 위치에 있는지 전체 경로를 지정하는 방식
- 상대경로: 현재 Python 파일이 실행되는 폴더를 기준으로 파일 위치를 지정하는 방식
CSV 파일을 읽을 때는 인코딩, 인덱스, 헤더, 구분자, 결측치 처리 옵션을 함께 지정할 수 있다.
df = pd.read_csv(
'data.csv',
encoding='utf-8',
index_col=0,
header=0,
sep=',',
na_values=['N/A', '']
)
3-2. Excel 파일 불러오기
Excel 파일도 Pandas로 간단하게 불러올 수 있다.
df = pd.read_excel('파일경로/파일명.xlsx')
특정 시트만 읽고 싶을 때는 sheet_name 옵션을 사용한다.
df = pd.read_excel('파일명.xlsx', sheet_name='Sheet1')
3-3. 온라인 데이터와 클립보드 데이터 불러오기
Pandas는 로컬 파일뿐 아니라 URL에 있는 CSV 파일도 직접 불러올 수 있다.
userdb1_url = "https://s3.ap-northeast-2.amazonaws.com/materials.spartacodingclub.kr/data/week4/user_db1.csv"
df = pd.read_csv(userdb1_url)
df
웹페이지나 엑셀에서 복사한 표 데이터는 클립보드에서 바로 읽어올 수도 있다.
df = pd.read_clipboard()
df
3-4. 타이타닉 데이터셋 탐색
실제 데이터셋을 사용해 Pandas의 기본 탐색 방법을 연습할 수 있다. 여기서는 온라인에 공개된 타이타닉 데이터셋을 불러온다.
url = "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
titanic = pd.read_csv(url)
print("데이터 불러오기 성공!")
print(f"데이터 크기: {titanic.shape}")
데이터 불러오기 성공!
데이터 크기: (891, 12)
데이터의 처음 몇 행을 확인하려면 head()를 사용한다.
print("처음 5행:")
titanic.head()
마지막 몇 행은 tail()로 확인할 수 있다.
print("마지막 5행:")
titanic.tail()
원하는 행 수만큼 확인하고 싶다면 숫자를 지정한다.
print("처음 10행:")
print(titanic.head(10))
데이터의 전체 구조는 info()를 사용해 확인한다.
print("데이터 정보:")
titanic.info()
info() 결과를 통해 총 행 수, 컬럼 수, 데이터 타입, 결측치 개수, 메모리 사용량을 확인할 수 있다.
숫자형 데이터의 기본 통계 정보는 describe()로 확인한다.
print("기본 통계:")
print(titanic.describe())
데이터를 처음 불러온 뒤에는
shape → head() → info() → describe() 순서로 확인하면 데이터의 전체 구조를 빠르게 파악할 수 있다.4. 속성과 메서드
4-1. 속성과 메서드 개념 이해
Pandas를 사용할 때 속성(Attribute)과 메서드(Method)의 차이를 이해하는 것이 중요하다. 둘은 비슷해 보이지만 사용하는 방식이 다르다.
- 속성: 객체가 가지고 있는 정보나 특성을 나타낸다. 괄호
()없이 사용한다. - 메서드: 객체가 수행할 수 있는 동작이나 기능을 나타낸다. 괄호
()와 함께 사용한다.
| 구분 | 의미 | 예시 |
|---|---|---|
| 속성 | 데이터의 상태나 정보를 확인 | shape, columns, index, dtypes |
| 메서드 | 데이터에 대해 특정 작업 수행 | head(), tail(), info(), describe() |
대표적인 속성은 다음과 같다.
index: 인덱스 정보columns: 컬럼명values: NumPy array 형식의 데이터 값dtypes: 컬럼별 데이터 타입T: DataFrame 전치shape: 데이터의 행과 열 개수
대표적인 메서드는 다음과 같다.
- 조회 및 탐색:
head(),tail(),describe(),info() - 데이터 선택 및 필터링:
loc[],iloc[],query(),filter() - 데이터 조작 및 변형:
drop(),rename(),melt(),pivot() - 정렬 및 그룹화:
sort_values(),sort_index(),groupby() - 결합 및 병합:
concat(),merge(),join() - 결측치 처리:
isnull(),notnull(),fillna(),dropna() - 통계 및 계산:
mean(),median(),sum(),std(),corr()
4-2. 데이터 선택하기 - 열 선택
DataFrame에서 하나의 컬럼을 선택하면 Series가 반환된다.
names = titanic['Name']
print("선택된 데이터 타입:", type(names))
print("처음 5개 이름:")
print(names.head())
여러 컬럼을 선택하면 DataFrame이 반환된다.
basic_info = titanic[['Name', 'Age', 'Sex']]
print("선택된 데이터 타입:", type(basic_info))
print("기본 정보:")
print(basic_info.head())
원하는 순서로 컬럼을 재배치할 수도 있다.
reordered = titanic[['Sex', 'Age', 'Name']]
print("순서가 바뀐 데이터:")
print(reordered.head())
4-3. 데이터 선택하기 - 행 선택과 조건 필터링
loc는 라벨 기반으로 행과 열을 선택하고, iloc는 정수 위치 기반으로 행과 열을 선택한다.
print("0번 인덱스 행:")
print(titanic.loc[0])
print("0부터 4번까지 행:")
print(titanic.loc[0:4])
print("첫 번째 행:")
print(titanic.iloc[0])
print("0부터 4번까지 행, 3~5번째 컬럼:")
print(titanic.iloc[0:5, [3, 4, 5]])
조건에 맞는 데이터만 선택할 수도 있다.
females = titanic[titanic['Sex'] == 'female']
print(f"여성 승객 수: {len(females)}")
여성 승객 수: 314
복합 조건을 사용할 때는 각 조건을 괄호로 묶고, & 또는 | 연산자를 사용한다.
young_females = titanic[(titanic['Sex'] == 'female') & (titanic['Age'] < 30)]
print(f"30세 미만 여성 승객 수: {len(young_females)}")
30세 미만 여성 승객 수: 147
조건이 많아질수록 아래처럼 조건을 변수로 나누면 가독성이 좋아진다.
female = titanic['Sex'] == 'female'
age_30 = titanic['Age'] < 30
young_females = titanic[female & age_30]
여러 값 중 하나와 일치하는 데이터를 선택할 때는 isin()을 사용한다.
first_second_class = titanic[titanic['Pclass'].isin([1, 2])]
print(f"1, 2등석 승객 수: {len(first_second_class)}")
1, 2등석 승객 수: 400
결측치가 아닌 데이터만 선택할 때는 notna()를 사용한다.
age_not_null = titanic[titanic['Age'].notna()]
print(f"나이 정보가 있는 승객 수: {len(age_not_null)}")
나이 정보가 있는 승객 수: 714
notna()는 결측치가 아닌 데이터만 선택하고, isna()는 결측치인 데이터만 선택한다. 조건이 복잡해지면 조건식을 변수로 나누어 작성하는 것이 좋다.4-4. 인덱스 관리
조건 필터링을 수행하면 기존 인덱스가 그대로 유지된다. 인덱스를 다시 0부터 정리하고 싶을 때는 reset_index()를 사용한다.
female = titanic['Sex'] == 'female'
age_30 = titanic['Age'] < 30
young_females = titanic[female & age_30]
young_females_reset = young_females.reset_index()
young_females_reset.head()
특정 컬럼을 인덱스로 설정하고 싶을 때는 set_index()를 사용한다.
df_indexed = titanic.set_index('PassengerId')
print("Passenger ID가 인덱스가 된 데이터:")
df_indexed.head()
5. 데이터 변경 및 생성
5-1. 새로운 컬럼 생성
Pandas에서는 기존 컬럼을 활용해 새로운 컬럼을 쉽게 만들 수 있다. 예를 들어 타이타닉 데이터에서 가족 크기는 형제자매 수, 부모/자녀 수, 본인을 더해 계산할 수 있다.
titanic['Family_Size'] = titanic['SibSp'] + titanic['Parch'] + 1
print("가족 크기 컬럼 생성 결과:")
print(titanic[['Name', 'SibSp', 'Parch', 'Family_Size']].head())
np.where()를 사용하면 조건에 따라 다른 값을 넣는 컬럼을 만들 수 있다.
import numpy as np
titanic['Is_Adult'] = np.where(titanic['Age'] >= 18, 'Adult', 'Child')
print("성인/아동 분포:")
print(titanic['Is_Adult'].value_counts())
여러 조건을 조합해 더 구체적인 카테고리 컬럼을 만들 수도 있다.
titanic['Passenger_Category'] = np.where(
(titanic['Pclass'] == 1) & (titanic['Age'] >= 18),
'First_Class_Adult',
'Other'
)
print("승객 카테고리 분포:")
print(titanic['Passenger_Category'].value_counts())
5-2. 데이터 정렬
데이터를 특정 컬럼 기준으로 정렬할 때는 sort_values()를 사용하고, 기본적으로 오름차순이다.
age_sorted = titanic.sort_values('Age')
print("나이순 정렬, 어린 순:")
print(age_sorted[['Name', 'Age']].head())
내림차순으로 정렬하려면 ascending=False를 지정한다.
age_desc = titanic.sort_values('Age', ascending=False)
print("나이순 정렬, 나이 많은 순:")
print(age_desc[['Name', 'Age']].head())
여러 컬럼을 기준으로 정렬할 수도 있다.
multi_sorted = titanic.sort_values(
['Pclass', 'Age'],
ascending=[True, False]
)
print("등급순, 나이 내림차순:")
print(multi_sorted[['Name', 'Pclass', 'Age']].head())
새로운 컬럼 생성은 기존 데이터를 분석 목적에 맞게 확장하는 과정이고, 정렬은 데이터의 우선순위와 패턴을 빠르게 확인하기 위한 기본 탐색 방법이다.
6. 실습 : 우리 가게 팁 분석하기
이번에는 Seaborn에서 제공하는 tips 데이터셋을 사용해 간단한 Pandas 실습을 진행해봤다. 식당 매니저가 되어 "언제 손님이 가장 많은지", "어떤 손님이 팁을 후하게 주는지" 데이터를 통해 확인해보는 상황을 가정한다.
Tips 데이터셋을 활용해 데이터 확인, 조건 필터링, 파생 변수 생성, 그룹 분석, apply 함수 적용을 연습한다.
0. 데이터 준비하기
별도의 파일 다운로드 없이 Seaborn의 예제 데이터를 바로 불러온다.
import seaborn as sns
df = sns.load_dataset('tips')
df.head()
| index | total_bill | tip | sex | smoker | day | time | size |
|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
total_bill: 총 계산 금액tip: 팁 금액sex: 성별smoker: 흡연 여부day: 요일time: 시간size: 인원 수
1. 데이터 훑어보기
print(df.shape)
df.info()
df.describe()
출력 결과를 통해 행과 열 개수, 결측치, 데이터 타입, 숫자형 변수의 기본 통계를 확인할 수 있다.
(244, 7)
<class 'pandas.DataFrame'>
RangeIndex: 244 entries, 0 to 243
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 total_bill 244 non-null float64
1 tip 244 non-null float64
2 sex 244 non-null category
3 smoker 244 non-null category
4 day 244 non-null category
5 time 244 non-null category
6 size 244 non-null int64
dtypes: category(4), float64(2), int64(1)
memory usage: 7.4 KB
describe()로 확인한 숫자형 변수의 기본 통계 결과는 다음과 같다.
| 구분 | total_bill | tip | size |
|---|---|---|---|
| count | 244.000000 | 244.000000 | 244.000000 |
| mean | 19.785943 | 2.998279 | 2.569672 |
| std | 8.902412 | 1.383638 | 0.951100 |
| min | 3.070000 | 1.000000 | 1.000000 |
| 25% | 13.347500 | 2.000000 | 2.000000 |
| 50% | 17.795000 | 2.900000 | 2.000000 |
| 75% | 24.127500 | 3.562500 | 3.000000 |
| max | 50.810000 | 10.000000 | 6.000000 |
2. 데이터 필터링
흡연하지 않는 손님만 따로 보고 싶다면 다음과 같이 조건 필터링을 사용한다.
non_smoker = df[df['smoker'] == 'No']
non_smoker.head()
| index | total_bill | tip | sex | smoker | day | time | size |
|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
저녁 시간이면서 팁을 5달러 이상 준 테이블을 찾고 싶다면 복합 조건을 사용한다.
vip_dinner = df[(df['time'] == 'Dinner') & (df['tip'] >= 5)]
vip_dinner.head()
| index | total_bill | tip | sex | smoker | day | time | size |
|---|---|---|---|---|---|---|---|
| 11 | 35.26 | 5.00 | Female | No | Sun | Dinner | 4 |
| 23 | 39.42 | 7.58 | Male | No | Sat | Dinner | 4 |
| 39 | 31.27 | 5.00 | Male | No | Sat | Dinner | 3 |
| 44 | 30.40 | 5.60 | Male | No | Sun | Dinner | 4 |
| 46 | 22.23 | 5.00 | Male | No | Sun | Dinner | 2 |
3. 파생 변수 만들기
총 금액 대비 팁을 몇 퍼센트나 줬는지 확인하기 위해 tip_rate 컬럼을 만든다.
df['tip_rate'] = (df['tip'] / df['total_bill']) * 100
df.head()
| index | total_bill | tip | sex | smoker | day | time | size | tip_rate |
|---|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 | 5.944673 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 | 16.054159 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 | 16.658734 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 | 13.978041 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 | 14.680765 |
4. 그룹 분석
groupby()를 사용하면 요일별, 시간대별 평균을 쉽게 계산할 수 있다.
print(df.groupby('day')['tip'].mean())
print(df.groupby('time')['tip_rate'].mean())
출력 결과를 통해 요일별 평균 팁과 점심·저녁 시간대별 평균 팁 비율을 비교할 수 있다.
day
Thur 2.771452
Fri 2.734737
Sat 2.993103
Sun 3.255132
Name: tip, dtype: float64
time
Lunch 16.412793
Dinner 15.951779
Name: tip_rate, dtype: float64
결과를 보면 요일별 평균 팁은 Sun이 가장 높고, 시간대별 평균 팁 비율은 Lunch가 Dinner보다 약간 높게 나타난다.
시간대별 평균 팁 비율은 Lunch가 Dinner보다 약간 높게 나타난다.
5. apply로 직접 분류하기
인원수에 따라 단체 손님 여부를 구분해볼 수 있다. 여기서는 4명 이상이면 Large, 아니면 Small로 분류한다.
def get_size_type(size):
if size >= 4:
return 'Large'
else:
return 'Small'
df['table_type'] = df['size'].apply(get_size_type)
print(df.groupby('table_type')['tip'].mean())
출력 결과를 통해 단체 손님과 소규모 손님의 평균 팁 차이를 확인할 수 있다.
table_type
Large 4.218478
Small 2.714798
Name: tip, dtype: float64
결과를 보면 4명 이상인 Large 테이블의 평균 팁이 Small 테이블보다 높게 나타난다.
Tips 데이터셋 실습에서는 데이터 불러오기, 기본 탐색, 조건 필터링, 파생 변수 생성, 그룹 분석, apply 함수 적용까지 Pandas의 핵심 흐름을 한 번에 연습할 수 있다.
최종 정리
이번 글에서는 Pandas의 기본 개념과 핵심 사용법을 정리했다. Pandas는 행과 열로 이루어진 테이블 데이터를 다루는 데 최적화된 라이브러리이며, 데이터 분석에서 전처리와 탐색 분석의 중심 역할을 한다.
Series와 DataFrame의 구조를 이해하고, 데이터를 불러온 뒤 head(), info(), describe()로 기본 구조를 확인하는 것이 Pandas 분석의 시작이다. 이후 컬럼 선택, 행 선택, 조건 필터링, 새로운 컬럼 생성, 정렬, 그룹 분석을 익히면 실제 데이터 분석에 필요한 기본 흐름을 구성할 수 있다.
Pandas는 데이터를 불러오고, 정리하고, 분석 가능한 형태로 바꾸는 Python 데이터 분석의 가장 기본적인 도구다.
출처
KDT 빅데이터 기반 품질 관리(QA/QC) 양성 과정 6회차
'TIL > Python' 카테고리의 다른 글
| Python 기초 문법 정리 (0) | 2026.07.14 |
|---|---|
| Python 분석 환경 조성하기 (0) | 2026.06.05 |
| Python 데이터 시각화 확장하기 (0) | 2026.06.04 |
| 데이터를 쉽게 보는 matplotlib 기초 (0) | 2026.06.02 |
| Python 분석을 위한 데이터 전처리 기초 (0) | 2026.06.01 |
