Pandas 개요
Pandas는 파이썬에서 데이터 조작 및 분석을 위해 널리 사용되는 고성능 라이브러리이다. 핵심적으로 2차원 데이터를 다루는 DataFrame 객체를 제공하며, DataFrame의 각 열을 구성하는 1차원 데이터 구조가 Series 객체이다.
Series 객체
Series는 1차원 배열과 유사하지만, 인덱스(Index)라는 명시적인 키(Key)를 가지고 있어 딕셔너리와 배열의 특징을 모두 갖춘 데이터 구조이다.
Series 생성 방법
리스트를 전달하여 Series를 생성하면 기본적으로 0부터 시작하는 정수 인덱스가 부여된다. index 파라미터를 사용하면 사용자 지정 인덱스를 설정할 수 있다.
# 기본 정수 인덱스를 갖는 Series 생성
import pandas as pd
s_data = pd.Series([10, 20, 30])
print(s_data)
# 0 10
# 1 20
# 2 30
# dtype: int64
# 사용자 정의 인덱스 지정
s_custom = pd.Series([10, 20, 30], index=['x', 'y', 'z'])
print(s_custom)
# x 10
# y 20
# z 30
# dtype: int64
# 딕셔너리를 활용한 Series 생성
s_dict = pd.Series({'alpha': 100, 'beta': 200})
Series 데이터 접근
Series의 요소에 접근할 때는 위치(정수)나 레이블(인덱스)을 사용할 수 있다. 단, 대괄호만 사용할 경우 인덱스가 정수일 때 의미가 모호해질 수 있으므로 loc(레이블 기반)과 iloc(위치 기반) 속성을 사용하는 것이 권장된다.
s_obj = pd.Series([15, 25, 35], index=['x', 'y', 'z'])
# 레이블로 접근
print(s_obj.loc['x']) # 15
# 위치로 접근
print(s_obj.iloc[0]) # 15
# 다중 값 선택 (이중 대괄호 사용)
print(s_obj.loc[['x', 'y']])
# x 15
# y 25
# dtype: int64
NumPy 배열처럼 불리언 인덱싱도 가능하다.
# 값이 20 초과인 요소 필터링
print(s_obj[s_obj > 20])
# y 25
# z 35
# dtype: int64
Series 슬라이싱
슬라이싱 시 iloc는 끝점을 포함하지 않지만(파이썬 표준 방식), loc는 끝점을 포함하는 차이가 있다.
# 위치 기반 슬라이싱 (인덱스 1부터 끝까지, 끝점 미포함)
print(s_obj.iloc[1:])
# y 25
# z 35
# 레이블 기반 슬라이싱 ('x'부터 'y'까지, 끝점 포함)
print(s_obj.loc['x':'y'])
# x 15
# y 25
Series 연산 및 결측치 처리
Series는 스칼라 값이나 다른 Series와 연산이 가능하다. 다른 Series와 연산할 때는 인덱스를 기준으로 자동 정렬(데이터 정렬)이 발생하며, 매칭되는 인덱스가 없으면 NaN(결측치)이 된다.
s1 = pd.Series([1, 2, 3], index=['x', 'y', 'z'])
s2 = pd.Series([10, 20, 30], index=['y', 'z', 'w'])
# 인덱스가 다른 Series 간의 연산
print(s1 + s2)
# w NaN
# x NaN
# y 12.0
# z 23.0
# dtype: float64
결측치는 dropna()로 제거하거나 fillna()로 대체할 수 있다.
result = s1 + s2
# 결측치 제거
print(result.dropna())
# y 12.0
# z 23.0
# 결측치를 평균값으로 대체
print(result.fillna(result.mean()))
DataFrame 객체
DataFrame은 2차원 표 형태의 데이터 구조로, 여러 개의 Series가 묶여 있는 형태이다.
DataFrame 생성
딕셔너리나 Series 객체를 사용하여 생성할 수 있다. 딕셔너리의 키는 열 이름이 되고, 값은 해당 열의 데이터가 된다.
# 딕셔너리로 DataFrame 생성
df = pd.DataFrame({'col_A': [1, 2, 3], 'col_B': [4, 5, 6]}, index=['row1', 'row2', 'row3'])
print(df)
# col_A col_B
# row1 1 4
# row2 2 5
# row3 3 6
파일 입출력
read_csv() 및 to_csv() 메서드를 통해 파일 쉽게 데이터를 읽고 쓸 수 있다.
# CSV 파일 읽기
df_csv = pd.read_csv("dataset.csv")
# 헤더가 없는 파일 읽기 및 컬럼명 지정
df_no_header = pd.read_csv('dataset.csv', header=None, names=['id', 'value', 'count'])
# 특정 열을 인덱스로 설정 및 날짜 파싱
df_time = pd.read_csv('dataset.csv', index_col='date', parse_dates=['date'])
# DataFrame을 CSV로 저장 (결측치는 'NA'로 표시, 구분자 세미콜론)
df.to_csv("output.csv", sep=";", na_rep="NA")
DataFrame 속성 및 통계
DataFrame은 행과 열의 인덱스, 값, 전치 등 다양한 속성을 제공한다.
print(df.index) # 행 인덱스 출력
print(df.columns) # 열 인덱스 출력
print(df.values) # 값만 2차원 배열로 출력
print(df.T) # 행과 열 전치
# 기술 통계 정보 (평균, 표준편차, 최소/최대값 등)
print(df.describe())
DataFrame 데이터 접근 및 연산
데이터에 접근할 때는 loc와 iloc를 사용하는 것이 안전하다.
# 'row1' 행의 'col_A' 열 값 접근
print(df.loc['row1', 'col_A'])
# 조건부 필터링 및 정렬
print(df.sort_values(by='col_A', ascending=False))
# 행 또는 열 단위 평균 계산
print(df.mean(axis=1)) # 행 기준 평균
DataFrame 결측치 처리
DataFrame에서 결측치를 다룰 때는 행 또는 열 단위로 제거 또는 대체를 수행할 수 있다.
df_na = pd.DataFrame({'A': [1, None, 3], 'B': [4, 5, None]})
# 결측치가 하나라도 있는 행 제거
print(df_na.dropna())
# 모든 값이 결측치인 행 제거
print(df_na.dropna(how='all'))
# 결측치가 있는 열 제거
print(df_na.dropna(axis=1))
# 결측치를 0으로 채우기
print(df_na.fillna(0))
시계열 데이터 처리
Pandas는 시계열 데이터 처리에 특화된 기능을 제공한다. to_datetime()으로 문자열을 날짜 객체로 변환하고, date_range()로 날짜 범위를 생성할 수 있다.
# 날짜 문자열을 datetime 객체로 변환
date_series = pd.Series(['2023/01/01', '2023/01/02'])
parsed_dates = pd.to_datetime(date_series)
# 날짜 범위 생성 (2주 간격, 5개)
range_dates = pd.date_range(start='2023-01-01', periods=5, freq='2W')
시계열 인덱스가 설정된 데이터는 연도나 월 단위로 슬라이싱하거나, resample()을 통해 시간 단위를 재그룹화할 수 있다.
# 시계열 인덱스를 갖는 Series 생성
time_data = pd.Series(range(50), index=pd.date_range('2023-01-01', periods=50))
# 2023년 1월 데이터만 선택
print(time_data['2023-01'])
# 주 단위로 재샘플링하여 합계 계산
print(time_data.resample('W').sum())
# 특정 날짜 이전 데이터 제거
print(time_data.truncate(before='2023-02-01'))