Python 데이터 분석 입문: Pandas와 NumPy 완벽 가이드
Python을 활용한 데이터 분석의 기초를 Pandas, NumPy, Matplotlib를 중심으로 실전 예제와 함께 단계별로 학습합니다.
Python 데이터 분석 입문: Pandas와 NumPy 완벽 가이드
데이터 분석은 현대 IT 산업에서 가장 중요한 역량 중 하나로 자리잡았습니다. Python은 풍부한 라이브러리 생태계 덕분에 데이터 분석 분야에서 가장 널리 사용되는 프로그래밍 언어입니다. 이 글에서는 Python 데이터 분석의 핵심 라이브러리인 NumPy, Pandas, 그리고 Matplotlib을 활용하여 데이터를 다루는 방법을 체계적으로 알아보겠습니다.
환경 설정
데이터 분석을 시작하기 전에 필요한 라이브러리를 설치해야 합니다.
pip install numpy pandas matplotlib seaborn jupyter
Jupyter Notebook 환경에서 작업하면 코드 실행 결과를 바로 확인할 수 있어 데이터 분석에 매우 유용합니다.
jupyter notebook
NumPy 기초: 수치 연산의 핵심
NumPy(Numerical Python)는 Python에서 대규모 다차원 배열과 행렬 연산을 효율적으로 수행하기 위한 핵심 라이브러리입니다. Pandas와 Matplotlib 등 대부분의 데이터 분석 라이브러리가 NumPy를 기반으로 구축되어 있습니다.
배열 생성
import numpy as np
# 1차원 배열 생성
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1) # [1 2 3 4 5]
# 2차원 배열 생성
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)
# [[1 2 3]
# [4 5 6]]
# 특수 배열 생성
zeros = np.zeros((3, 4)) # 0으로 채운 3x4 배열
ones = np.ones((2, 3)) # 1로 채운 2x3 배열
eye = np.eye(3) # 3x3 단위 행렬
rand = np.random.rand(3, 3) # 0~1 난수로 채운 3x3 배열
arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0.0, 0.25, 0.5, 0.75, 1.0]
배열 연산
NumPy의 가장 큰 장점은 벡터화 연산(Vectorized Operations)입니다. 반복문 없이도 배열 전체에 대한 연산을 빠르게 수행할 수 있습니다.
a = np.array([1, 2, 3, 4, 5])
b = np.array([10, 20, 30, 40, 50])
# 기본 산술 연산
print(a + b) # [11 22 33 44 55]
print(a * b) # [10 40 90 160 250]
print(a ** 2) # [1 4 9 16 25]
# 통계 함수
print(np.mean(a)) # 3.0 (평균)
print(np.std(a)) # 1.4142... (표준편차)
print(np.median(a)) # 3.0 (중앙값)
print(np.max(a)) # 5 (최대값)
print(np.min(a)) # 1 (최소값)
print(np.sum(a)) # 15 (합계)
배열 인덱싱과 슬라이싱
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]])
# 인덱싱
print(arr[0, 2]) # 3 (0행 2열)
print(arr[1]) # [5 6 7 8] (1행 전체)
# 슬라이싱
print(arr[:2, 1:3]) # [[2 3] [6 7]]
# 조건부 인덱싱 (불리언 인덱싱)
print(arr[arr > 5]) # [6 7 8 9 10 11 12]
배열 변형
arr = np.arange(12)
print(arr) # [0 1 2 3 4 5 6 7 8 9 10 11]
# reshape: 형태 변경
reshaped = arr.reshape(3, 4)
print(reshaped)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 전치 (transpose)
print(reshaped.T)
# 배열 결합
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.concatenate([a, b])) # [1 2 3 4 5 6]
print(np.vstack([a, b])) # 수직 결합
print(np.hstack([a, b])) # 수평 결합
Pandas 기초: 데이터 분석의 핵심
Pandas는 구조화된 데이터를 효율적으로 처리하고 분석하기 위한 라이브러리입니다. Excel이나 SQL 테이블과 유사한 데이터 구조를 제공하며, 데이터 정제, 변환, 분석에 필요한 강력한 도구들을 갖추고 있습니다.
Series와 DataFrame
Pandas의 두 가지 핵심 데이터 구조는 Series(1차원)와 DataFrame(2차원)입니다.
import pandas as pd
# Series 생성
s = pd.Series([10, 20, 30, 40, 50], index=['a', 'b', 'c', 'd', 'e'])
print(s)
# a 10
# b 20
# c 30
# d 40
# e 50
# DataFrame 생성
data = {
'이름': ['김철수', '이영희', '박민수', '정수진', '홍길동'],
'나이': [25, 30, 28, 35, 22],
'도시': ['서울', '부산', '대구', '서울', '인천'],
'연봉': [3500, 4200, 3800, 5000, 3000]
}
df = pd.DataFrame(data)
print(df)
데이터 읽기와 저장
# CSV 파일 읽기
df = pd.read_csv('data.csv')
df = pd.read_csv('data.csv', encoding='utf-8-sig') # 한글 인코딩
# Excel 파일 읽기
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')
# JSON 파일 읽기
df = pd.read_json('data.json')
# 데이터 저장
df.to_csv('output.csv', index=False, encoding='utf-8-sig')
df.to_excel('output.xlsx', index=False)
데이터 탐색
데이터를 불러온 후 가장 먼저 해야 할 일은 데이터의 구조와 특성을 파악하는 것입니다.
# 기본 정보 확인
print(df.shape) # (행 수, 열 수)
print(df.dtypes) # 각 열의 데이터 타입
print(df.info()) # 전체 요약 정보
print(df.describe()) # 수치형 열의 통계 요약
# 데이터 미리보기
print(df.head()) # 상위 5행
print(df.tail(3)) # 하위 3행
print(df.sample(5)) # 랜덤 5행
# 고유값 확인
print(df['도시'].unique()) # 고유값 목록
print(df['도시'].nunique()) # 고유값 개수
print(df['도시'].value_counts()) # 값별 빈도수
데이터 선택과 필터링
# 열 선택
print(df['이름']) # 단일 열 (Series)
print(df[['이름', '나이']]) # 여러 열 (DataFrame)
# 행 선택
print(df.iloc[0]) # 인덱스 번호로 선택
print(df.iloc[0:3]) # 슬라이싱
print(df.loc[0]) # 라벨로 선택
# 조건부 필터링
print(df[df['나이'] > 25]) # 나이 25 초과
print(df[df['도시'] == '서울']) # 서울 거주자
print(df[(df['나이'] > 25) & (df['연봉'] > 4000)]) # 복합 조건
print(df[df['도시'].isin(['서울', '부산'])]) # 서울 또는 부산
데이터 전처리
실제 데이터는 결측값, 중복, 이상치 등의 문제를 포함하고 있습니다. 분석 전에 이러한 문제를 처리하는 것이 필수적입니다.
결측값 처리
# 결측값 확인
print(df.isnull().sum()) # 열별 결측값 개수
print(df.isnull().sum().sum()) # 전체 결측값 개수결측값 제거
df_dropped = df.dropna() # 결측값이 있는 행 제거 df_dropped = df.dropna(subset=['나이']) # 특정 열 기준으로 제거
결측값 채우기
df['나이'].fillna(df['나이'].mean(), inplace=True) # 평균값으로 채우기 df['도시'].fillna('미상', inplace=True) # 특정 값으로 채우기 df['연봉'].fillna(method='ffill', inplace=True) # 이전 값으로 채우기
### 데이터 타입 변환과 문자열 처리
타입 변환
df['나이'] = df['나이'].astype(int) df['날짜'] = pd.to_datetime(df['날짜'])
문자열 처리
df['이름'] = df['이름'].str.strip() # 공백 제거 df['이름'] = df['이름'].str.upper() # 대문자 변환 df['도시_포함'] = df['도시'].str.contains('서울') # 포함 여부
### 데이터 그룹화와 집계
그룹별 통계
print(df.groupby('도시')['연봉'].mean()) # 도시별 평균 연봉 print(df.groupby('도시')['나이'].agg(['mean', 'min', 'max']))
피벗 테이블
pivot = df.pivot_table( values='연봉', index='도시', aggfunc=['mean', 'count'] )
정렬
df_sorted = df.sort_values('연봉', ascending=False) df_sorted = df.sort_values(['도시', '나이'], ascending=[True, False])
### 데이터 병합
두 DataFrame 합치기
df1 = pd.DataFrame({'ID': [1, 2, 3], '이름': ['A', 'B', 'C']}) df2 = pd.DataFrame({'ID': [2, 3, 4], '점수': [85, 90, 78]})
merge (SQL JOIN과 유사)
merged = pd.merge(df1, df2, on='ID', how='inner') # 내부 조인 merged = pd.merge(df1, df2, on='ID', how='left') # 왼쪽 조인 merged = pd.merge(df1, df2, on='ID', how='outer') # 외부 조인
concat (단순 결합)
combined = pd.concat([df1, df2], axis=0) # 세로 결합 combined = pd.concat([df1, df2], axis=1) # 가로 결합
## 데이터 시각화: Matplotlib
데이터 분석에서 시각화는 패턴과 인사이트를 발견하는 핵심적인 과정입니다. Matplotlib은 Python의 대표적인 시각화 라이브러리입니다.
### 기본 그래프
import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams['font.family'] = 'Malgun Gothic' # 한글 폰트 설정 matplotlib.rcParams['axes.unicode_minus'] = False # 마이너스 기호 깨짐 방지
선 그래프 (Line Plot)
months = ['1월', '2월', '3월', '4월', '5월', '6월'] sales = [150, 180, 200, 220, 250, 280]
plt.figure(figsize=(10, 6)) plt.plot(months, sales, marker='o', color='blue', linewidth=2) plt.title('월별 매출 추이', fontsize=16) plt.xlabel('월', fontsize=12) plt.ylabel('매출 (만원)', fontsize=12) plt.grid(True, alpha=0.3) plt.show()
### 막대 그래프
막대 그래프 (Bar Chart)
categories = ['전자제품', '의류', '식품', '도서', '가구'] values = [450, 320, 280, 150, 200]
plt.figure(figsize=(10, 6)) bars = plt.bar(categories, values, color=['#3498db', '#2ecc71', '#e74c3c', '#f39c12', '#9b59b6']) plt.title('카테고리별 매출', fontsize=16) plt.ylabel('매출 (만원)', fontsize=12)
막대 위에 값 표시
for bar, value in zip(bars, values): plt.text(bar.get_x() + bar.get_width()/2., bar.get_height(), f'{value}만원', ha='center', va='bottom')
plt.show()
### 산점도와 히스토그램
산점도 (Scatter Plot)
np.random.seed(42) x = np.random.randn(100) y = 2 x + np.random.randn(100) 0.5
plt.figure(figsize=(8, 6)) plt.scatter(x, y, alpha=0.7, c='coral', edgecolors='black') plt.title('변수 간 상관관계', fontsize=16) plt.xlabel('X 변수', fontsize=12) plt.ylabel('Y 변수', fontsize=12) plt.show()
히스토그램 (Histogram)
data = np.random.normal(170, 10, 1000) # 평균 170, 표준편차 10
plt.figure(figsize=(8, 6)) plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7) plt.title('키 분포', fontsize=16) plt.xlabel('키 (cm)', fontsize=12) plt.ylabel('빈도', fontsize=12) plt.axvline(np.mean(data), color='red', linestyle='--', label=f'평균: {np.mean(data):.1f}cm') plt.legend() plt.show()
### 여러 그래프를 한 번에 그리기
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
왼쪽 상단: 선 그래프
axes[0, 0].plot(months, sales, 'bo-') axes[0, 0].set_title('월별 매출')
오른쪽 상단: 막대 그래프
axes[0, 1].bar(categories, values, color='coral') axes[0, 1].set_title('카테고리별 매출')
왼쪽 하단: 산점도
axes[1, 0].scatter(x, y, alpha=0.5) axes[1, 0].set_title('상관관계')
오른쪽 하단: 원형 그래프
axes[1, 1].pie(values, labels=categories, autopct='%1.1f%%') axes[1, 1].set_title('매출 비율')
plt.tight_layout() plt.show()
## 실전 데이터 분석 예제
실제 데이터를 분석하는 전체 과정을 살펴보겠습니다. 가상의 온라인 쇼핑몰 주문 데이터를 활용합니다.
import pandas as pd import numpy as np import matplotlib.pyplot as plt
가상 데이터 생성
np.random.seed(42) n = 1000
orders = pd.DataFrame({ '주문일': pd.date_range('2024-01-01', periods=n, freq='H'), '고객ID': np.random.randint(1, 200, n), '상품카테고리': np.random.choice(['전자제품', '의류', '식품', '도서', '가구'], n), '주문금액': np.random.randint(5000, 500000, n), '할인율': np.random.choice([0, 5, 10, 15, 20], n), '배송지역': np.random.choice(['서울', '경기', '부산', '대구', '광주'], n) })
1단계: 데이터 탐색
print("=== 데이터 기본 정보 ===") print(f"데이터 크기: {orders.shape}") print(f"\n데이터 타입:\n{orders.dtypes}") print(f"\n기초 통계:\n{orders.describe()}")
2단계: 파생 변수 생성
orders['실결제금액'] = orders['주문금액'] * (1 - orders['할인율'] / 100) orders['주문월'] = orders['주문일'].dt.month orders['요일'] = orders['주문일'].dt.day_name()
3단계: 분석
카테고리별 매출 분석
category_sales = orders.groupby('상품카테고리')['실결제금액'].agg(['sum', 'mean', 'count']) category_sales.columns = ['총매출', '평균주문금액', '주문건수'] category_sales = category_sales.sort_values('총매출', ascending=False) print(f"\n=== 카테고리별 매출 ===\n{category_sales}")
월별 매출 추이
monthly_sales = orders.groupby('주문월')['실결제금액'].sum() print(f"\n=== 월별 매출 ===\n{monthly_sales}")
지역별 분석
region_analysis = orders.groupby('배송지역').agg({ '실결제금액': ['sum', 'mean'], '고객ID': 'nunique' }).round(0) print(f"\n=== 지역별 분석 ===\n{region_analysis}")
이 예제에서는 데이터 생성부터 탐색, 전처리, 분석, 시각화까지 데이터 분석의 전 과정을 다루었습니다. 실제 업무에서도 이와 동일한 흐름으로 분석을 진행합니다.
## 추가 학습 라이브러리
기본기를 익힌 후에는 다음 라이브러리들도 함께 학습하면 데이터 분석 역량을 크게 향상시킬 수 있습니다.
- **Seaborn**: Matplotlib 기반의 통계 시각화 라이브러리로, 더 아름다운 그래프를 쉽게 생성할 수 있습니다.
- **Scikit-learn**: 머신러닝 모델을 쉽게 구현할 수 있는 라이브러리입니다.
- **Plotly**: 인터랙티브한 시각화를 만들 수 있습니다.
- **Statsmodels**: 통계 모델링과 가설 검정을 위한 라이브러리입니다.
## 마무리
Python 데이터 분석의 기초를 NumPy, Pandas, Matplotlib을 중심으로 살펴보았습니다. 데이터 분석은 이론만으로는 충분하지 않으며, 실제 데이터를 다루면서 경험을 쌓는 것이 중요합니다.
Kaggle(kaggle.com) 같은 플랫폼에서 다양한 데이터셋을 내려받아 직접 분석해보는 것을 추천합니다. 공공데이터포털(data.go.kr)에서도 흥미로운 한국 데이터를 많이 찾을 수 있습니다.
꾸준한 연습과 함께 점차 고급 분석 기법과 머신러닝으로 영역을 넓혀가시기 바랍니다. 데이터를 이해하고 의미 있는 인사이트를 도출하는 능력은 앞으로 더욱 중요해질 것입니다.