WeniVooks

검색

essentials-numpy-pandas

시간 데이터 처리

1. 시간 데이터 생성 및 변환

시간 데이터는 데이터 분석에서 매우 중요한 역할을 합니다. 특히 금융, 기상, 웹 로그 분석 등 많은 분야에서 시간에 따른 데이터의 변화를 추적하고 분석하는 것이 핵심입니다. 판다스(Pandas)는 이러한 시간 데이터를 효과적으로 다룰 수 있는 다양한 도구를 제공합니다. 이 장에서는 시간 데이터를 생성하고 변환하는 기본적인 방법에 대해 알아보겠습니다.

1.2 datetime 객체 이해하기

datetime 객체는 Python에서 날짜와 시간을 표현하는 기본적인 방법으로, 연도, 월, 일(필수), 시, 분, 초, 마이크로초(선택) 등의 정보를 포함하여 다양한 시간 관련 연산과 비교를 가능하게 합니다. 예를 들어, 2026년 7월 19일 오후 3시 30분은 datetime(2026, 7, 19, 15, 30, 0)과 같이 생성할 수 있습니다.

from datetime import datetime # datetime 객체 생성 dt = datetime(2026, 7, 19, 15, 30, 0) print(dt) # datetime 객체의 속성 접근 print(dt.year) print(dt.month) print(dt.day) print(dt.hour) print(dt.minute) print(dt.weekday()) # 0은 월요일, 6은 일요일
1.3 to_datetime() 함수 사용하기

판다스의 to_datetime() 함수는 다양한 형식의 날짜와 시간 데이터를 datetime 객체로 유연하게 변환하는 도구로, 문자열, 숫자, 리스트, 시리즈 등 다양한 입력 형태를 처리할 수 있습니다. 이 함수는 여러 일반적인 날짜 형식을 자동으로 인식하며, 단일 값뿐만 아니라 여러 날짜/시간 데이터를 한 번에 변환할 수 있어 다양한 데이터 소스와 대량의 시계열 데이터 처리에 특히 유용합니다.

import pandas as pd # 문자열을 datetime으로 변환 date_string = '2026-07-19' date = pd.to_datetime(date_string) date
# 다양한 형식의 날짜 변환 dates = ['7/19/2026', '20260719', '2026.07.19'] date_series = pd.to_datetime(dates) date_series
# 시간을 포함한 문자열 변환 datetime_string = '2026-07-19 15:30:00' dt = pd.to_datetime(datetime_string) print(dt)
1.4 다양한 형식의 날짜/시간 문자열 변환

to_datetime() 함수의 'format' 파라미터는 표준화되지 않은 다양한 날짜/시간 문자열을 정확하게 변환할 수 있게 해줍니다. strftime 형식을 사용하여 %Y-%m-%d%d/%m/%Y 등의 특정 형식을 지정할 수 있으며, 시간을 포함한 형식도 가능합니다. 이 기능은 비표준 형식이나 특정 국가, 조직의 독특한 날짜 형식을 다룰 때 특히 유용하여 정확한 데이터 변환을 가능하게 합니다.

# 특정 형식 지정 custom_date = '19-07-2026' dt = pd.to_datetime(custom_date, format='%d-%m-%Y') print(dt) # 시간을 포함한 형식 datetime_string = '2026-07-19 15:30:00' dt = pd.to_datetime(datetime_string, format='%Y-%m-%d %H:%M:%S') print(dt) # 비표준 형식 odd_format = '19_07_2026_153000' dt = pd.to_datetime(odd_format, format='%d_%m_%Y_%H%M%S') print(dt)
1.5 에러 처리

to_datetime() 함수는 'errors' 파라미터를 통해 잘못된 날짜 형식이나 존재하지 않는 날짜를 유연하게 처리할 수 있습니다. 'coerce' 옵션은 변환 불가능한 값을 NaT(Not a Time)로 처리하여 결측치로 표시하고, 'ignore' 옵션은 이러한 값을 원래 형태로 유지합니다. 이러한 에러 처리 옵션을 사용하면 대규모 데이터 분석 시 발생할 수 있는 문제를 효과적으로 관리하고, 전체 분석 프로세스의 안정성을 높일 수 있습니다.

# 잘못된 날짜 처리 wrong_dates = ['2026-07-19', '2026-13-45', '2026-07-20'] # 에러 발생 try: pd.to_datetime(wrong_dates) except ValueError as e: print("ValueError 발생:", e) # 에러 무시 (NaT 반환) result = pd.to_datetime(wrong_dates, errors='coerce') print(result) # 변환 불가능한 값 유지 result = pd.to_datetime(wrong_dates, errors='ignore') print(result)

2. 날짜 범위 생성 및 활용

2.1 date_range() 함수 사용하기

date_range() 함수는 판다스에서 날짜 범위를 만듭니다. 시작일부터 종료일까지, 또는 원하는 기간 동안의 날짜들을 쉽게 생성할 수 있습니다. 이 함수는 주로 시작일, 종료일, 또는 기간을 지정해서 사용합니다. 만들어진 날짜 범위는 DatetimeIndex 객체로 반환되는데, 이걸 시계열 데이터의 인덱스로 활용하면 데이터 분석과 시각화에 정말 유용합니다.

import pandas as pd # 시작일과 종료일 지정 date_range = pd.date_range(start='2026-01-01', end='2026-01-31') print(date_range) # 시작일과 기간 지정 date_range = pd.date_range(start='2026-01-01', periods=31) print(date_range) # 종료일과 기간 지정 date_range = pd.date_range(end='2026-01-31', periods=31) print(date_range)
2.2 다양한 주기의 날짜 생성

date_range() 함수는 pandas의 핵심 도구로, 시계열 분석에 필요한 날짜 범위를 생성합니다. 시작일, 종료일, 또는 기간을 지정하여 날짜 시퀀스를 만들 수 있으며, 결과로 반환되는 DatetimeIndex 객체는 시계열 데이터의 인덱스로 활용되어 데이터 분석과 시각화에 유용합니다.

# 주별 날짜 생성 weekly_dates = pd.date_range(start='2026-01-01', end='2026-12-31', freq='W') print(weekly_dates) # 월별 날짜 생성 monthly_dates = pd.date_range(start='2026-01-01', end='2026-12-31', freq='M') print(monthly_dates) # 연도별 날짜 생성 yearly_dates = pd.date_range(start='2026-01-01', end='2033-01-01', freq='Y') print(yearly_dates) # 2일 간격으로 날짜 생성 two_day_dates = pd.date_range(start='2026-01-01', end='2026-01-31', freq='2D') print(two_day_dates)
2.3 비즈니스 날짜 다루기

비즈니스 날짜는 주말을 제외한 평일만을 포함하며, 금융 데이터 분석이나 업무 일정 관리에 유용합니다. date_range() 함수에서 'B(비지니스 데이)' 주기를 사용하여 비즈니스 날짜를 생성할 수 있으며, 'C' 옵션으로 사용자 정의 달력을 적용해 공휴일 등을 제외할 수 있습니다. 이렇게 생성된 비즈니스 날짜 범위는 실제 업무일을 기준으로 데이터 분석이나 금융 모델링에 활용됩니다.

import pandas as pd # 1월의 영업일 생성 business_days_january = pd.date_range(start='2026-01-01', end='2026-01-31', freq='B') print(business_days_january) # 사용자 정의 달력 적용 cal = USFederalHolidayCalendar() holidays = cal.holidays(start='2026-01-01', end='2026-12-31') custom_bday = pd.offsets.CustomBusinessDay(holidays=holidays) # 2026년의 영업일 생성 business_days_2026 = pd.date_range(start='2026-01-01', end='2026-12-31', freq=custom_bday) print(business_days_2026)

3. 시계열 데이터 분석 기초

시계열 데이터 분석은 시간에 따라 변하는 데이터를 다루는 중요한 분야입니다. pandas에서는 이런 데이터를 쉽게 다룰 수 있는 다양한 도구를 제공합니다.

3.1 시계열 데이터 인덱싱과 슬라이싱

시계열 데이터를 다룰 때는 날짜나 시간을 기준으로 데이터를 선택하는 일이 많습니다. pandas에서는 이런 작업을 아주 쉽게 할 수 있습니다.

import pandas as pd import numpy as np # 예시 데이터 생성 dates = pd.date_range('2026-01-01', periods=365, freq='D') df = pd.DataFrame({'value': np.random.randn(365)}, index=dates) df
# 특정 기간 선택 jan_data = df['2026-01-01':'2026-01-31'] print("1월 데이터:") jan_data.head()
# 특정 연도 선택 year_2026 = df['2026'] print("2026년 데이터:") year_2026.head()
# 특정 월 선택 march_data = df['2026-03'] print("3월 데이터:") march_data.head()
# 특정 요일 선택 (예: 모든 월요일) mondays = df[df.index.dayofweek == 0] print("월요일 데이터:") mondays.head()
3.2 시계열 데이터의 기본 통계량 계산

시계열 데이터를 분석할 때 기본 통계량을 계산하는 것은 매우 중요합니다. Pandas에서는 여러 함수를 사용하여 쉽게 통계량을 계산할 수 있습니다. 이런 방식으로 다양한 시간 단위와 통계량을 조합하여 데이터의 특성을 파악할 수 있습니다. 특히 resample() 함수는 시계열 데이터를 다룰 때 매우 유용합니다.

# 월별 평균 계산 monthly_mean = df.resample('M').mean() print("월별 평균:") monthly_mean.head()
# 연도별 합계 계산 yearly_sum = df.resample('Y').sum() print("연도별 합계:") yearly_sum.head()
# 주별 최댓값과 최솟값 계산 weekly_max_min = df.resample('W').agg(['max', 'min']) print("주별 최댓값, 최솟값:") weekly_max_min.head()
# 전체 기간의 기본 통계량 계산 basic_stats = df.describe() print("기본 통계량:") basic_stats
# 월별 중앙값과 표준편차 계산 monthly_median_std = df.resample('M').agg(['median', 'std']) print("월별 중앙값, 표준편차:") monthly_median_std.head()
3.3 시계열 데이터의 이동 평균 계산

이동 평균은 시계열 데이터의 추세를 파악하는 데 많이 사용됩니다. Pandas에서는 rolling() 함수를 사용하여 이동 평균을 쉽게 계산할 수 있습니다. 이동 평균을 사용하면 데이터의 단기적인 변동을 줄이고 장기적인 추세를 더 잘 파악할 수 있습니다.

# 7일 이동 평균 계산 df['7D_MA'] = df['value'].rolling(window=7).mean() print("7일 이동 평균:") df[['value', '7D_MA']].head(10)
# 30일 이동 평균 계산 df['30D_MA'] = df['value'].rolling(window=30).mean() print("30일 이동 평균:") df[['value', '30D_MA']].head(10)
# 이동 평균과 원본 데이터의 차이 계산 df['7D_MA_diff'] = df['value'] - df['7D_MA'] print("7일 이동 평균과 원본 데이터의 차이:") df[['value', '7D_MA', '7D_MA_diff']].head(10)
# 가중 이동 평균 계산 (최근 데이터에 더 높은 가중치 부여) weights = np.arange(1, 8) df['7D_WMA'] = df['value'].rolling(window=7).apply(lambda x: np.dot(x, weights)/weights.sum()) print("7일 가중 이동 평균:") df[['value', '7D_WMA']].head(10)
3.4 시계열 데이터의 시프트와 라그

데이터를 특정 기간만큼 앞뒤로 이동시켜 분석할 수 있습니다. 이는 이전 기간과의 관계를 분석할 때 유용합니다. 시프트(shift)와 라그(lag) 기능을 사용하면 데이터의 변화량이나 증가율을 쉽게 계산할 수 있습니다. 시프트는 데이터 전체를 일정 기간만큼 앞이나 뒤로 이동시키는 기능이며, 라그는 특정 시점의 데이터와 이전 시점의 데이터를 비교할 때 사용합니다.

# 1일 전의 데이터와 비교 df['prev_day'] = df['value'].shift(1) df['diff'] = df['value'] - df['prev_day'] print("1일 전 데이터와 차이:") df[['value', 'prev_day', 'diff']].head(10)
# 7일 후의 데이터와 비교 df['next_week'] = df['value'].shift(-7) df['diff_next_week'] = df['value'] - df['next_week'] print("7일 후 데이터와 차이:") df[['value', 'next_week', 'diff_next_week']].head(10)
# 전월 대비 증가율 계산 df['monthly_return'] = df['value'].pct_change(periods=30) print("전월 대비 증가율:") df['monthly_return'].head(10)
# 3일 이동 평균의 1일 전 데이터와 비교 df['3D_MA'] = df['value'].rolling(window=3).mean() df['3D_MA_prev'] = df['3D_MA'].shift(1) df['3D_MA_diff'] = df['3D_MA'] d- df['3D_MA_prev'] print("3일 이동 평균과 1일 전 데이터와 차이:") df[['value', '3D_MA', '3D_MA_prev', '3D_MA_diff']].head(10)
3.5 시계열 데이터의 계절성 분석

데이터에 주기적인 패턴이 존재하는지 확인하고 이를 분석할 수 있습니다. 시계열 데이터의 계절성을 분석하는 다양한 방법이 존재합니다. 월별, 요일별, 시간대별 패턴을 확인하는 것은 기본적인 방법이며, 더 복잡한 계절성 분해 기법을 사용하는 방법도 있습니다.

# 월별 평균을 계산하여 계절성 확인 monthly_avg = df.groupby(df.index.month).mean() print("월별 평균:", monthly_avg) # 요일별 평균을 계산하여 주간 패턴 확인 weekday_avg = df.groupby(df.index.dayofweek).mean() print("요일별 평균:", weekday_avg)

아래 코드는 statsmodels 라이브러리를 사용하여 계절성 분해를 수행하는 예제입니다. 이 예제는 위니북스에서는 실행되지 않습니다.

# 계절성 분해 (statsmodels 라이브러리 사용)
from statsmodels.tsa.seasonal import seasonal_decompose
result = seasonal_decompose(df['value'], model='additive', period=30)
print("계절성 분해 결과:")
print(result.seasonal.head())
print(result.trend.head())
print(result.resid.head())
# 계절성 분해 (statsmodels 라이브러리 사용)
from statsmodels.tsa.seasonal import seasonal_decompose
result = seasonal_decompose(df['value'], model='additive', period=30)
print("계절성 분해 결과:")
print(result.seasonal.head())
print(result.trend.head())
print(result.resid.head())

4. 시간 데이터 리샘플링

리샘플링은 시계열 데이터의 빈도를 변경하는 과정입니다. 이 기술은 데이터 분석, 시각화, 모델링 등 다양한 상황에서 유용하게 사용됩니다.

4.1 업샘플링 (Upsampling)

업샘플링은 데이터의 빈도를 높이는 과정으로, 새로 생성되는 데이터 포인트를 어떻게 채울지가 중요합니다. 이를 위해 이전 값을 그대로 사용하는 ffill, 다음 값을 사용하는 bfill, 선형 보간을 사용하는 linear interpolation, 그리고 다항식 보간을 사용하는 polynomial interpolation 방법이 있습니다.

import pandas as pd import numpy as np # 월별 데이터 생성 monthly_data = pd.Series(np.random.randn(12), index=pd.date_range('2026-01-01', periods=12, freq='M')) print("원본 월별 데이터:", monthly_data) # 일별 데이터로 업샘플링 (forward fill 방식) daily_data_ffill = monthly_data.resample('D').ffill() print("업샘플링 결과 (ffill):", daily_data_ffill.head(15)) # 일별 데이터로 업샘플링 (backward fill 방식) daily_data_bfill = monthly_data.resample('D').bfill() print("업샘플링 결과 (bfill):", daily_data_bfill.head(15)) # 선형 보간법을 사용한 업샘플링 daily_data_interpolated = monthly_data.resample('D').interpolate(method='linear') print("업샘플링 결과 (linear interpolation):", daily_data_interpolated.head(15)) # 다항 보간법을 사용한 업샘플링 daily_data_poly = monthly_data.resample('D').interpolate(method='polynomial', order=2) print("업샘플링 결과 (polynomial interpolation):", daily_data_poly.head(15))
4.2 다운샘플링 (Downsampling)

다운샘플링은 데이터의 빈도를 낮추는 과정으로, 이 과정에서 여러 데이터 포인트를 어떻게 하나로 합칠지가 중요합니다. 다운샘플링 시에는 다양한 집계 함수를 사용할 수 있으며, 데이터의 특성과 분석 목적에 따라 적절한 함수를 선택하면 됩니다.

# 일별 데이터 생성 daily_data = pd.Series(np.random.randn(365), index=pd.date_range('2026-01-01', periods=365, freq='D')) print("원본 일별 데이터:", daily_data.head()) # 월별 평균으로 다운샘플링 monthly_mean = daily_data.resample('M').mean() print("다운샘플링 결과 (월별 평균):", monthly_mean) # 월별 중앙값으로 다운샘플링 monthly_median = daily_data.resample('M').median() print("다운샘플링 결과 (월별 중앙값):", monthly_median) # 월별 최대값, 최소값으로 다운샘플링 monthly_max_min = daily_data.resample('M').agg(['max', 'min']) print("다운샘플링 결과 (월별 최대값, 최소값):", monthly_max_min) # 주별 평균과 표준편차로 다운샘플링 weekly_stats = daily_data.resample('W').agg(['mean', 'std']) print("다운샘플링 결과 (주별 평균, 표준편차):", weekly_stats.head())
4.3 복잡한 리샘플링 예제

실제 데이터 분석에서는 더 복잡한 리샘플링이 필요할 수 있으며, 이를 통해 데이터의 다양한 패턴과 특성을 발견할 수 있습니다. 특정 시간대나 조건에 맞는 데이터만을 선택하여 분석함으로써 데이터의 세부적인 변화와 경향을 더 정확히 파악할 수 있습니다.

# 10분 단위 데이터 생성 (일주일치) ten_min_data = pd.DataFrame({ 'value': np.random.randn(1008), 'category': np.random.choice(['A', 'B', 'C'], 1008) }, index=pd.date_range('2026-01-01', periods=1008, freq='10T')) print("원본 10분 단위 데이터:", ten_min_data.head()) # 시간별 평균으로 다운샘플링 (카테고리별) hourly_mean = ten_min_data.groupby('category').resample('H').mean() print("카테고리별 시간당 평균:", hourly_mean.head(10)) # 일별 최대값과 최소값으로 다운샘플링 (전체) daily_max_min = ten_min_data['value'].resample('D').agg(['max', 'min']) print("일별 최대값과 최소값:", daily_max_min) # 특정 시간대만 선택하여 리샘플링 (예: 업무 시간 9AM-5PM) business_hours = ten_min_data.between_time('9:00', '17:00') business_hours_hourly = business_hours.resample('H').mean() print("업무 시간 동안의 시간별 평균:", business_hours_hourly.head(10)) # 주말과 주중을 구분하여 리샘플링 ten_min_data['is_weekend'] = ten_min_data.index.dayofweek.isin([5, 6]) weekend_vs_weekday = ten_min_data.groupby('is_weekend').resample('D').mean() print("주말과 주중의 일별 평균:", weekend_vs_weekday.head(10))
{"packages":["numpy","pandas","matplotlib","lxml"]}
5.1 데이터 분석 기법6장 Numpy & Pandas 연습