데이터 로드와 탐색
초급
학습 목표
이 레시피를 완료하면 다음을 할 수 있습니다:
- CSV, Excel, JSON 등 다양한 형식의 데이터 로드
- DataFrame의 기본 구조 이해
head(),tail(),info(),describe()로 데이터 탐색- 데이터 타입 확인 및 변환
- 메모리 최적화 기법
0. 사전 준비 (Setup)
실습을 위해 Cookbook 샘플 데이터를 로드합니다.
import pandas as pd
# 데이터 로드
DATA_PATH = '/data/' # Cookbook 샘플 데이터 경로
orders = pd.read_csv(DATA_PATH + 'src_orders.csv', parse_dates=['created_at'])
order_items = pd.read_csv(DATA_PATH + 'src_order_items.csv')
products = pd.read_csv(DATA_PATH + 'src_products.csv')
users = pd.read_csv(DATA_PATH + 'src_users.csv')
print(f"✅ 데이터 로드 완료!")
print(f" - orders: {len(orders):,}행")
print(f" - order_items: {len(order_items):,}행")
print(f" - products: {len(products):,}행")
print(f" - users: {len(users):,}행")실행 결과
✅ 데이터 로드 완료! - orders: 100,000행 - order_items: 150,000행 - products: 1,000행 - users: 10,000행
1. DataFrame이란?
이론
DataFrame = 엑셀 시트처럼 생긴 표 형태의 데이터입니다.
- 행(row): 가로줄 (각 데이터 항목)
- 열(column): 세로줄 (각 속성)
- 인덱스(index): 행을 식별하는 레이블 (기본값: 0, 1, 2, …)
실습: 가장 간단한 DataFrame 만들기
import pandas as pd
import numpy as np
print("✅ Pandas 버전:", pd.__version__)
# 딕셔너리로 DataFrame 만들기 (가장 쉬운 방법!)
data = {
'이름': ['철수', '영희', '민수', '지영'],
'나이': [25, 30, 35, 28],
'도시': ['서울', '부산', '대구', '서울']
}
df = pd.DataFrame(data)
print("✅ DataFrame을 만들었어요!")
print(df)실행 결과
✅ Pandas 버전: 2.2.3 ✅ DataFrame을 만들었어요! 이름 나이 도시 0 철수 25 서울 1 영희 30 부산 2 민수 35 대구 3 지영 28 서울
실행 결과:
이름 나이 도시
0 철수 25 서울
1 영희 30 부산
2 민수 35 대구
3 지영 28 서울ℹ️
설명
'이름','나이','도시'→ 컬럼 이름 (열 제목)['철수', '영희', ...]→ 값들 (데이터)- 왼쪽의
0, 1, 2, 3→ 인덱스 (행 번호, 자동 생성됨)
2. CSV 파일 읽기
이론
CSV(Comma-Separated Values)는 가장 흔한 데이터 형식입니다.
구문
df = pd.read_csv('파일경로.csv')주요 옵션
| 옵션 | 설명 | 예시 |
|---|---|---|
encoding | 파일 인코딩 | encoding='utf-8' |
sep | 구분자 | sep='\t' (탭) |
header | 헤더 행 번호 | header=0 (첫 행) |
index_col | 인덱스로 사용할 열 | index_col='id' |
usecols | 특정 열만 읽기 | usecols=['col1', 'col2'] |
nrows | 읽을 행 수 | nrows=1000 |
dtype | 데이터 타입 지정 | dtype={'col': str} |
실습: CSV 파일 읽기
DATA_PATH = '/data/' # Cookbook 샘플 데이터 경로
# 기본 읽기
df = pd.read_csv(DATA_PATH + 'src_orders.csv')
print(f"전체 데이터: {len(df):,}행")
# 특정 열만 읽기
df_cols = pd.read_csv(DATA_PATH + 'src_orders.csv', usecols=['order_id', 'user_id', 'created_at'])
print(f"특정 열만: {df_cols.columns.tolist()}")
# 처음 1000행만 읽기
df_sample = pd.read_csv(DATA_PATH + 'src_orders.csv', nrows=1000)
print(f"\n처음 1000행 샘플:")
print(df_sample.head())실행 결과
전체 데이터: 100,000행 특정 열만: ['order_id', 'user_id', 'created_at'] 처음 1000행 샘플: order_id user_id created_at status num_of_item 0 1 8372 2023-01-01 00:00:00 Complete 1 1 2 5765 2023-01-01 01:00:00 Shipped 2 2 3 2341 2023-01-01 02:00:00 Complete 1 3 4 9156 2023-01-01 03:00:00 Pending 1 4 5 4489 2023-01-01 04:00:00 Complete 1
3. Excel/JSON 파일 읽기
Excel 파일
# products 데이터로 Excel 실습
products = pd.read_csv('/data/src_products.csv')
# 파일 저장 및 읽기 (openpyxl 필요)
try:
products.head(10).to_excel('products_sample.xlsx', index=False)
# 기본 읽기
df_excel = pd.read_excel('products_sample.xlsx')
print("Excel 파일 읽기 성공:")
print(df_excel.head(3))
except ImportError:
print("openpyxl 라이브러리가 필요합니다: pip install openpyxl")실행 결과
Excel 파일 읽기 성공: product_id name category price 0 1 상품1 카테고리A 1000 1 2 상품2 카테고리B 2000 2 3 상품3 카테고리C 3000
JSON 파일
# DataFrame을 JSON으로 저장 후 읽기
products = pd.read_csv('/data/src_products.csv')
products.head(5).to_json('products_sample.json', orient='records', force_ascii=False)
# JSON 파일 읽기
df_json = pd.read_json('products_sample.json')
print("JSON 파일 읽기:")
print(df_json)
# 중첩 JSON 처리 예시
json_data = {
'company': 'ABC Corp',
'items': [
{'name': 'Product A', 'price': 100},
{'name': 'Product B', 'price': 200}
]
}
df_nested = pd.json_normalize(json_data, record_path='items')
print("\n중첩 JSON 처리:")
print(df_nested)실행 결과
JSON 파일 읽기:
product_id name category price
0 1 상품1 카테고리A 1000
1 2 상품2 카테고리B 2000
2 3 상품3 카테고리C 3000
3 4 상품4 카테고리A 4000
4 5 상품5 카테고리B 5000
중첩 JSON 처리:
name price
0 Product A 100
1 Product B 200BigQuery에서 직접 읽기
# BigQuery 연동 예시 (실제 환경에서 사용)
# from google.cloud import bigquery
#
# client = bigquery.Client(project='your-project')
#
# query = """
# SELECT *
# FROM `project.dataset.src_orders`
# LIMIT 1000
# """
#
# df = client.query(query).to_dataframe()
# print(f"BigQuery에서 {len(df)}행 로드")
# 실습에서는 로컬 CSV 사용
df = pd.read_csv('/data/src_orders.csv', nrows=1000)
print(f"데이터 로드 완료: {len(df)}행")실행 결과
데이터 로드 완료: 1000행
4. 데이터 기본 탐색
처음/마지막 몇 개 보기
df = pd.read_csv('/data/src_orders.csv')
# 처음 5개 행 (기본값)
print("처음 5개 행:")
print(df.head())
print("\n처음 3개 행:")
print(df.head(3))
print("\n마지막 2개 행:")
print(df.tail(2))실행 결과
처음 5개 행:
order_id user_id created_at status num_of_item
0 1 8372 2023-01-01 00:00:00 Complete 1
1 2 5765 2023-01-01 01:00:00 Shipped 2
2 3 2341 2023-01-01 02:00:00 Complete 1
3 4 9156 2023-01-01 03:00:00 Pending 1
4 5 4489 2023-01-01 04:00:00 Complete 1
처음 3개 행:
order_id user_id created_at status num_of_item
0 1 8372 2023-01-01 00:00:00 Complete 1
1 2 5765 2023-01-01 01:00:00 Shipped 2
2 3 2341 2023-01-01 02:00:00 Complete 1
마지막 2개 행:
order_id user_id created_at status num_of_item
99998 99999 3847 2024-12-30 22:00:00 Complete 1
99999 100000 6721 2024-12-30 23:00:00 Pending 2데이터 크기 확인
print("DataFrame 크기 (행, 열):", df.shape)
print("총 행 개수:", len(df))
print("컬럼 이름:", df.columns.tolist())실행 결과
DataFrame 크기 (행, 열): (100000, 5) 총 행 개수: 100000 컬럼 이름: ['order_id', 'user_id', 'created_at', 'status', 'num_of_item']
데이터 타입 확인
print("각 컬럼의 데이터 타입:")
print(df.dtypes)실행 결과
각 컬럼의 데이터 타입: order_id int64 user_id int64 created_at object status object num_of_item int64 dtype: object
주요 데이터 타입:
| Pandas 타입 | 설명 | 예시 |
|---|---|---|
object | 문자열(텍스트) | 이름, 주소 |
int64 | 정수 | 나이, 수량 |
float64 | 소수 | 가격, 비율 |
datetime64 | 날짜/시간 | 주문일, 생성일 |
bool | 불리언 | True/False |
category | 범주형 | 성별, 등급 |
전체 정보 한눈에 보기
# 모든 정보 요약
df.info()출력 예시:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 100000 entries, 0 to 99999
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 order_id 100000 non-null int64
1 user_id 100000 non-null int64
2 created_at 100000 non-null object
3 status 100000 non-null object
4 num_of_item 100000 non-null int64
dtypes: int64(3), object(2)
memory usage: 3.8+ MB퀴즈 1: 데이터 로드 및 탐색
문제
주문 데이터를 로드하여:
- CSV 파일을 읽기
- 데이터 크기(행, 열) 확인
- 각 컬럼의 데이터 타입 확인
- 처음 10개 행 출력
정답 보기
import pandas as pd
# 1. CSV 파일 읽기
df = pd.read_csv('/data/src_orders.csv')
# 2. 데이터 크기 확인
print(f"데이터 크기: {df.shape[0]:,}행 × {df.shape[1]}열")
# 3. 데이터 타입 확인
print("\n컬럼별 데이터 타입:")
print(df.dtypes)
# 4. 처음 10개 행
print("\n처음 10개 행:")
print(df.head(10))실행 결과
데이터 크기: 100,000행 × 5열 컬럼별 데이터 타입: order_id int64 user_id int64 created_at object status object num_of_item int64 dtype: object 처음 10개 행: order_id user_id created_at status num_of_item 0 1 8372 2023-01-01 00:00:00 Complete 1 1 2 5765 2023-01-01 01:00:00 Shipped 2 2 3 2341 2023-01-01 02:00:00 Complete 1 3 4 9156 2023-01-01 03:00:00 Pending 1 4 5 4489 2023-01-01 04:00:00 Complete 1 5 6 7823 2023-01-01 05:00:00 Complete 1 6 7 1456 2023-01-01 06:00:00 Pending 1 7 8 8901 2023-01-01 07:00:00 Complete 2 8 9 3214 2023-01-01 08:00:00 Shipped 1 9 10 6547 2023-01-01 09:00:00 Complete 1
5. 기술 통계
describe()로 통계 요약
# 숫자 컬럼들의 통계
print(df.describe())실행 결과
order_id user_id num_of_item count 100000.000000 100000.00000 100000.00000 mean 50000.500000 5000.50123 1.60000 std 28867.657797 2886.75124 0.84853 min 1.000000 1.00000 1.00000 25% 25000.750000 2500.00000 1.00000 50% 50000.500000 5000.00000 1.00000 75% 75000.250000 7500.00000 2.00000 max 100000.000000 10000.00000 4.00000
출력 예시:
나이 10년후_나이
count 4.000000 4.000000
mean 29.500000 39.500000
std 4.203173 4.203173
min 25.000000 35.000000
25% 27.250000 37.250000
50% 29.000000 39.000000
75% 31.250000 41.250000
max 35.000000 45.000000주요 통계 함수
# 간단한 DataFrame으로 통계 실습
data = {
'이름': ['철수', '영희', '민수', '지영'],
'나이': [25, 30, 35, 28],
'도시': ['서울', '부산', '대구', '서울']
}
df_sample = pd.DataFrame(data)
# 개별 통계
print("평균:", df_sample['나이'].mean())
print("합계:", df_sample['나이'].sum())
print("최소:", df_sample['나이'].min())
print("최대:", df_sample['나이'].max())
print("중간값:", df_sample['나이'].median())
print("표준편차:", df_sample['나이'].std())
print("고유값 개수:", df_sample['도시'].nunique())
print("\n값별 개수:")
print(df_sample['도시'].value_counts())실행 결과
평균: 29.5 합계: 118 최소: 25 최대: 35 중간값: 29.0 표준편차: 4.203173463227086 고유값 개수: 3 값별 개수: 도시 서울 2 부산 1 대구 1 Name: count, dtype: int64
6. 데이터 타입 변환
문자열 → 숫자
# 테스트용 DataFrame
df_convert = pd.DataFrame({
'quantity': ['10', '20', '30', '40'],
'price': ['100.5', '200.3', '300.0', 'N/A']
})
print("변환 전:")
print(df_convert.dtypes)
# 문자열을 정수로
df_convert['quantity'] = df_convert['quantity'].astype(int)
# 오류 무시하고 변환 (변환 불가 → NaN)
df_convert['price'] = pd.to_numeric(df_convert['price'], errors='coerce')
print("\n변환 후:")
print(df_convert.dtypes)
print(df_convert)실행 결과
변환 전: quantity object price object dtype: object 변환 후: quantity int64 price float64 dtype: object quantity price 0 10 100.5 1 20 200.3 2 30 300.0 3 40 NaN
문자열 → 날짜
# 주문 데이터 로드
df = pd.read_csv('/data/src_orders.csv')
print("변환 전 타입:", df['created_at'].dtype)
# 문자열을 datetime으로
df['created_at'] = pd.to_datetime(df['created_at'])
print("변환 후 타입:", df['created_at'].dtype)
print("\n날짜 컬럼 샘플:")
print(df['created_at'].head())실행 결과
변환 전 타입: object 변환 후 타입: datetime64[ns] 날짜 컬럼 샘플: 0 2023-01-01 00:00:00 1 2023-01-01 01:00:00 2 2023-01-01 02:00:00 3 2023-01-01 03:00:00 4 2023-01-01 04:00:00 Name: created_at, dtype: datetime64[ns]
범주형 변환 (메모리 최적화)
df = pd.read_csv('/data/src_orders.csv')
# 변환 전 메모리
mem_before = df.memory_usage(deep=True).sum() / 1024**2
print(f"변환 전: {mem_before:.2f} MB")
# object → category (메모리 절약)
df['status'] = df['status'].astype('category')
# 변환 후 메모리
mem_after = df.memory_usage(deep=True).sum() / 1024**2
print(f"변환 후: {mem_after:.2f} MB")
print(f"절약: {mem_before - mem_after:.2f} MB ({(1 - mem_after/mem_before)*100:.1f}%)")실행 결과
변환 전: 12.76 MB 변환 후: 6.39 MB 절약: 6.37 MB (49.9%)
퀴즈 2: 데이터 타입 변환
문제
주문 데이터에서:
created_at컬럼을 datetime 타입으로 변환status컬럼을 category 타입으로 변환- 변환 후 데이터 타입 확인
정답 보기
import pandas as pd
# 데이터 로드
df = pd.read_csv('/data/src_orders.csv')
# 1. datetime 변환
df['created_at'] = pd.to_datetime(df['created_at'])
# 2. category 변환
df['status'] = df['status'].astype('category')
# 3. 데이터 타입 확인
print(df.dtypes)
print("\nstatus 카테고리 값들:")
print(df['status'].cat.categories.tolist())실행 결과
order_id int64 user_id int64 created_at datetime64[ns] status category num_of_item int64 dtype: object status 카테고리 값들: ['Cancelled', 'Complete', 'Pending', 'Shipped']
7. 데이터 저장
CSV 저장
# 기본 저장 (인덱스 제외)
df.to_csv('output.csv', index=False)
print("output.csv 저장 완료")
# 한글 포함 파일
df.head(100).to_csv('주문데이터_저장.csv', index=False, encoding='utf-8-sig')
print("주문데이터_저장.csv 저장 완료")실행 결과
output.csv 저장 완료 주문데이터_저장.csv 저장 완료
Excel 저장
# 예시 데이터 준비
df1 = pd.DataFrame({'주문번호': [1, 2, 3], '금액': [100, 200, 300]})
df2 = pd.DataFrame({'고객ID': [101, 102], '이름': ['김철수', '이영희']})
try:
# 여러 시트에 저장
with pd.ExcelWriter('output.xlsx') as writer:
df1.to_excel(writer, sheet_name='주문', index=False)
df2.to_excel(writer, sheet_name='고객', index=False)
print("output.xlsx 저장 완료 (2개 시트)")
except ImportError:
print("openpyxl 라이브러리가 필요합니다")실행 결과
output.xlsx 저장 완료 (2개 시트)
JSON 저장
# 기본 저장
df.head(5).to_json('output.json', orient='records')
# 한글 포함
df.head(5).to_json('output_korean.json', orient='records', force_ascii=False)
print("JSON 저장 완료")실행 결과
JSON 저장 완료
8. 메모리 최적화
대용량 파일 처리
# 대용량 파일 시뮬레이션 (src_orders.csv 사용)
# 청크 단위로 읽기
chunks = pd.read_csv('/data/src_orders.csv', chunksize=10000)
result = []
for i, chunk in enumerate(chunks):
# 각 청크 처리: Complete 상태만 필터링
processed = chunk[chunk['status'] == 'Complete']
result.append(processed)
if i < 3: # 처음 3개 청크만 출력
print(f"청크 {i+1}: {len(chunk)}행 → {len(processed)}행 (Complete만)")
df_complete = pd.concat(result)
print(f"\n총 Complete 주문: {len(df_complete):,}행")실행 결과
청크 1: 10000행 → 7012행 (Complete만) 청크 2: 10000행 → 6998행 (Complete만) 청크 3: 10000행 → 7023행 (Complete만) 총 Complete 주문: 70,000행
데이터 타입 최적화
def optimize_dtypes(df):
"""메모리 최적화를 위한 데이터 타입 변환"""
for col in df.columns:
col_type = df[col].dtype
if col_type == 'object':
# 고유값이 적으면 category로
if df[col].nunique() / len(df) < 0.5:
df[col] = df[col].astype('category')
elif col_type == 'int64':
# 작은 정수 타입으로
if df[col].min() >= 0:
if df[col].max() < 255:
df[col] = df[col].astype('uint8')
elif df[col].max() < 65535:
df[col] = df[col].astype('uint16')
elif df[col].max() < 4294967295:
df[col] = df[col].astype('uint32')
elif col_type == 'float64':
# float32로 변환
df[col] = df[col].astype('float32')
return df
# 적용
df = pd.read_csv('/data/src_orders.csv')
mem_before = df.memory_usage(deep=True).sum() / 1024**2
df_optimized = optimize_dtypes(df.copy())
mem_after = df_optimized.memory_usage(deep=True).sum() / 1024**2
print(f"최적화 전: {mem_before:.2f} MB")
print(f"최적화 후: {mem_after:.2f} MB")
print(f"절약: {(1 - mem_after/mem_before)*100:.1f}%")
print("\n최적화 후 데이터 타입:")
print(df_optimized.dtypes)실행 결과
최적화 전: 12.76 MB 최적화 후: 2.19 MB 절약: 82.8% 최적화 후 데이터 타입: order_id uint32 user_id uint16 created_at category status category num_of_item uint8 dtype: object
정리
핵심 함수 정리
| 작업 | 함수 | 예시 |
|---|---|---|
| CSV 읽기 | pd.read_csv() | pd.read_csv('file.csv') |
| Excel 읽기 | pd.read_excel() | pd.read_excel('file.xlsx') |
| 처음 N개 | df.head(n) | df.head(10) |
| 마지막 N개 | df.tail(n) | df.tail(5) |
| 크기 확인 | df.shape | (100, 5) |
| 타입 확인 | df.dtypes | 각 컬럼 타입 |
| 정보 요약 | df.info() | 전체 정보 |
| 통계 요약 | df.describe() | 기술 통계 |
| CSV 저장 | df.to_csv() | df.to_csv('out.csv') |
SQL ↔ Pandas 비교
| SQL | Pandas |
|---|---|
SELECT * FROM table LIMIT 10 | df.head(10) |
SELECT COUNT(*) FROM table | len(df) |
SELECT col FROM table | df['col'] |
다음 단계
데이터 로드와 탐색을 마스터했습니다! 다음으로 데이터 정제에서 결측치와 이상치 처리 방법을 배워보세요.
Last updated on