logo

자전거 통행량과 그룹별 집계

실습 준비

import pandas as pd

자전거 카운터 데이터

  • 미국 시애틀 프레몬트 브리지(Fremont Bridge)의 자전거 카운터 데이터
  • 동쪽과 서쪽 보도를 지나는 자전거 통행량을 시간별로 기록

시애틀 프레몬트 브리지의 자전거 통행량 카운터와 자전거 이용자

data = pd.read_csv(
    'bicycle.csv',
    index_col='Date',  # Date 컬럼을 인덱스로 지정
    parse_dates=True)  # 인덱스를 날짜·시간 자료형으로 변환
data.head()
실행 결과
                     Fremont Bridge Total  Fremont Bridge East Sidewalk  \
Date                                                                      
2019-11-01 00:00:00                  12.0                           7.0   
2019-11-01 01:00:00                   7.0                           0.0   
2019-11-01 02:00:00                   1.0                           0.0   
2019-11-01 03:00:00                   6.0                           6.0   
2019-11-01 04:00:00                   6.0                           5.0   

                     Fremont Bridge West Sidewalk  
Date                                               
2019-11-01 00:00:00                           5.0  
2019-11-01 01:00:00                           7.0  
2019-11-01 02:00:00                           1.0  
2019-11-01 03:00:00                           0.0  
2019-11-01 04:00:00                           1.0  

시각화

  • 편의를 위해 컬럼 이름을 변경
    • Total: 전체 통행량
    • East: 동쪽 보도 통행량
    • West: 서쪽 보도 통행량
data.columns = ['Total', 'East', 'West']
  • 시간별 원자료 시각화
data.plot()
실행 결과
<Axes: xlabel='Date'>
<Figure size 640x480 with 1 Axes>

전체·동쪽·서쪽 보도의 시간별 자전거 통행량

  • 주 단위 합계 시각화
data.resample('W').sum().plot()
실행 결과
<Axes: xlabel='Date'>
<Figure size 640x480 with 1 Axes>

주 단위로 집계한 전체·동쪽·서쪽 보도의 자전거 통행량

이동 평균

  • 일 단위 합계를 계산한 뒤 30일 이동 평균을 계산
  • daily: 하루에 한 행이므로 30개 관측값은 30일에 해당
daily = data.resample('D').sum()
daily.rolling(30, center=True).mean().plot()  # 30일 평균을 구간 중심에 표시
실행 결과
<Axes: xlabel='Date'>
<Figure size 640x480 with 1 Axes>

일별 통행량 합계의 30일 이동 평균

가우스 가중 이동 합계

  • 중심에 가까운 날짜에 더 큰 가중치를 주고, 먼 날짜에 더 작은 가중치를 주는 방식
  • win_type='gaussian': 가우스 형태의 가중치
  • 구간 길이 50일, 가우스 가중치의 표준편차 10
  • sum(): 가중 이동 합계. 가중 이동 평균과 구별
roll = daily.rolling(50, center=True, win_type='gaussian')  # 50일 가중 구간
roll.sum(std=10).plot()  # 가중치의 표준편차 10
실행 결과
<Axes: xlabel='Date'>
<Figure size 640x480 with 1 Axes>

중심에서 먼 날짜에 작은 가중치를 적용한 50일 가우스 가중 이동 합계

시간대별 평균

  • data.index.time: 날짜를 제외한 시각
  • 같은 시각의 관측값을 groupby()로 모아 평균 계산
by_time = data.groupby(data.index.time).mean()
by_time.plot()
실행 결과
<Axes: xlabel='time'>
<Figure size 640x480 with 1 Axes>

여러 날짜의 같은 시각을 모아 계산한 시간대별 평균 통행량

가로 눈금을 4시간 간격으로

  • 시각 인덱스의 그래프에서 눈금 위치는 자정부터 경과한 초 단위
  • 4 * 60 * 60: 4시간을 초로 환산
  • np.arange(6): 0, 1, 2, 3, 4, 5
  • 눈금 시각: 00:00, 04:00, 08:00, 12:00, 16:00, 20:00
  • style: Total, East, West 순서대로 점선, 대시, 실선 지정
import numpy as np
hourly_ticks = 4 * 60 * 60 * np.arange(6)  # 0시부터 20시까지 4시간 간격, 초 단위
by_time.plot(xticks=hourly_ticks, style=[':', '--', '-'])
실행 결과
<Axes: xlabel='time'>
<Figure size 640x480 with 1 Axes>

4시간 간격의 눈금과 서로 다른 선 모양으로 표시한 시간대별 평균 통행량

요일별 평균

  • data.index.dayofweek: 월요일 0부터 일요일 6까지의 요일 번호
  • 같은 요일의 시간별 관측값을 모아 평균 계산
by_weekday = data.groupby(data.index.dayofweek).mean()
by_weekday.index = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
by_weekday.plot()
실행 결과
<Axes: >
<Figure size 640x480 with 1 Axes>

월요일부터 일요일까지의 요일별 평균 통행량

  • 이 평균은 요일별 하루 총통행량이 아니라 해당 요일의 시간별 관측값 평균

주중과 주말의 비교

  • 요일 번호가 5보다 작으면 주중, 나머지는 주말로 구분
  • 주중·주말과 시각을 함께 기준으로 삼아 평균 계산
weekend = np.where(data.index.weekday < 5, 'Weekday', 'Weekend')  # 월~금과 토~일 구분
by_time = data.groupby([weekend, data.index.time]).mean()
  • by_time.loc['Weekday']: 주중의 시간대별 평균
by_time.loc['Weekday'].plot(xticks=hourly_ticks)
실행 결과
<Axes: xlabel='time'>
<Figure size 640x480 with 1 Axes>

오전과 오후에 봉우리가 나타나는 주중의 시간대별 평균 통행량

  • by_time.loc['Weekend']: 주말의 시간대별 평균
by_time.loc['Weekend'].plot(xticks=hourly_ticks)
실행 결과
<Axes: xlabel='time'>
<Figure size 640x480 with 1 Axes>

낮 시간대에 넓은 봉우리가 나타나는 주말의 시간대별 평균 통행량

하나의 그림에 합쳐 그리기

  • plt.subplots(1, 2): 한 행에 두 개의 그래프 배치
  • ax[0]: 왼쪽 그래프에 주중 평균 표시
  • ax[1]: 오른쪽 그래프에 주말 평균 표시
  • 하나의 셀에서 실행
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 2, figsize=(14, 5))  # 한 행, 두 열로 비교
by_time.loc['Weekday'].plot(ax=ax[0], title='Weekdays', xticks=hourly_ticks)
by_time.loc['Weekend'].plot(ax=ax[1], title='Weekends', xticks=hourly_ticks)
실행 결과
<Axes: title={'center': 'Weekends'}, xlabel='time'>
<Figure size 1400x500 with 2 Axes>

한 그림의 두 패널에 배치한 주중과 주말의 시간대별 평균 통행량

  • 주중: 오전과 오후에 두 개의 뚜렷한 봉우리
  • 주말: 낮 시간대에 하나의 넓은 봉우리
  • 두 패널의 세로축 범위가 다르므로 통행량은 눈금의 수치로 비교

퀴즈

문제 1 / 6맞음: 0힌트: 0틀림: 0채점중: 0남음: 6

data.resample('W').sum()의 결과는 무엇인가요?

  • ○주마다 시간별 관측값의 평균을 계산한 통행량
  • ○주 단위로 시간별 관측값을 합한 통행량
  • ○각 주의 마지막 관측값만 선택한 통행량
  • ○매일 이전 7개 관측값의 평균을 계산한 통행량

퀴즈를 풀려면 대화형 기능을 불러와야 합니다.

Previous
pandas에서 날짜/시간 다루기
Next
상관