데이터 분석에서 날짜 데이터의 분포를 시각화하면 특정 기간에 데이터가 얼마나 집중되어 있는지 한눈에 파악할 수 있습니다. Matplotlib과 Pandas를 함께 사용하면 날짜 데이터를 커널 밀도 추정(KDE) 곡선으로 손쉽게 그릴 수 있는데, 이 글에서는 그 구현 과정을 단계별로 살펴보겠습니다.
핵심 개념: 왜 서수(Ordinal) 변환이 필요할까?
KDE 플롯은 수치형 데이터를 대상으로 연산하기 때문에 datetime 객체를 그대로 사용할 수 없습니다. 따라서 Python 내장 함수인 toordinal()로 날짜를 정수형 서수 값으로 먼저 변환한 뒤 밀도를 계산하고, 마지막에 x축 눈금 레이블을 다시 'YYYY-MM-DD' 형식의 날짜 문자열로 되돌리는 방식을 사용합니다.
구현 단계
- 그림(figure) 크기를 설정하고 서브플롯 주변 및 사이의 여백을 자동으로 조정합니다.
pd.date_range()로 날짜 범위를 생성한 후, 무작위로 추출한 100개의 날짜를 담은 Pandas 데이터프레임을 만듭니다.- 날짜 열을
toordinal()로 변환한 'ordinal' 열을 추가합니다. plot(kind='kde')를 호출하여 이름(name)별 커널 밀도 추정 곡선을 그립니다.set_xticklabels()메서드를 사용해 x축 눈금 레이블을 날짜 문자열로 설정합니다.plt.show()메서드로 최종 그래프를 화면에 표시합니다.
예제 코드
import pandas as pd
import numpy as np
import datetime
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True
dates = pd.date_range('2010-01-01', periods=31, freq='D')
df = pd.DataFrame(np.random.choice(dates, 100), columns=['dates'])
df['ordinal'] = [x.toordinal() for x in df.dates]
ax = df['ordinal'].plot(kind='kde')
x_ticks = ax.get_xticks()
ax.set_xticks(x_ticks[::2])
xlabels = [datetime.datetime.fromordinal(int(x))
.strftime('%Y-%m-%d') for x in x_ticks[::2]]
ax.set_xticklabels(xlabels)
plt.show()
실행 결과

코드 상세 설명
np.random.choice(dates, 100)는 2010년 1월 한 달간의 날짜 중 100개를 무작위로 샘플링하여 실제와 유사한 데이터 분포를 만듭니다. 이후 KDE 곡선을 그리면 어느 날짜 구간에 데이터가 몰려 있는지 부드러운 확률 밀도 곡선으로 확인할 수 있습니다.
x축 눈금이 너무 촘촘해지는 것을 방지하기 위해 x_ticks[::2] 슬라이싱으로 눈금을 절반씩 건너뛰며 표시했고, fromordinal()과 strftime()을 조합해 서수 값을 다시 사람이 읽기 쉬운 날짜 형식으로 변환했습니다. 이 패턴은 시계열 히스토그램, 분포 비교 등 다양한 시각화 작업에 그대로 응용할 수 있습니다.