서울시 공공자전거 데이터를 활용한 수요 분석 및 예측
2025. 5. 10. 17:37ㆍ프로젝트
github link : https://github.com/Thingjae98/bike_data/tree/main
GitHub - Thingjae98/bike_data
Contribute to Thingjae98/bike_data development by creating an account on GitHub.
github.com
🔍 프로젝트 개요
서울시 공공자전거 '따릉이' 데이터를 활용해 자전거 이용 패턴을 분석하고, 날씨 및 시간 정보를 기반으로 수요를 예측하는 프로젝트를 진행했습니다.
이 글에서는 데이터 수집, 전처리, 시각화, 모델링 및 결과 분석까지의 전체 흐름을 Python 기반으로 소개합니다.
🛠 사용 기술 스택
구분도구 및 기술
언어 | Python 3 |
데이터 처리 | pandas, numpy |
시각화 | matplotlib, seaborn, folium |
머신러닝 | scikit-learn, XGBoost |
환경 관리 | requirements.txt |
파일 관리 | CSV 데이터 (자전거 이용 + 기상청 날씨), 병합 및 전처리 |
📁 데이터 소개
1. 자전거 이용 데이터
- 대여일시(24년 12월), 대여소명, 성별, 연령대, 운동량, 탄소량, 이동거리, 이용시간 등 포함
- 시간대, 요일, 계절 등의 파생변수 추가
2. 기상청 날씨 데이터 (서울)
- 기온, 강수량, 풍속, 습도, 지면온도, 적설량 등
- 기상청 기후통계 Open API를 통해 수집하거나 csv로 다운로드 가능
📝 두 데이터는 대여일시 기준으로 병합하여 df_merged에 저장
📊 주요 분석 내용
✅ 요일 및 시간대별 이용량 분석
📌 분석 인사이트:
- 평일(특히 월요일·화요일) 7, 19시는 출퇴근 시간대에 이용량이 집중되었습니다.
- 주말은 오후 13~17시 사이에 이용이 많았으며, 레저 목적의 사용이 많은 것으로 보입니다.
# 히트맵: 요일 vs 시간대
pivot = df_merged.groupby(['요일', '시간대']).size().unstack().fillna(0)
order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
pivot = pivot.reindex(order)
plt.figure(figsize=(12,6))
sns.heatmap(pivot, cmap='YlGnBu')
plt.title('요일/시간대별 이용량')
✅ 인기 대여소 분석 (Top 10)

📌 분석 인사이트:
- 상위 대여소는 주요 지하철역에 집중되어 있었습니다.
- 마곡나루역, 영등포구청역 등 유동 인구가 많은 지역이 대여 중심 허브 역할을 하고 있습니다.
# 대여 기준 인기 대여소 Top 10
top_stations = df_merged["대여소명"].value_counts().head(10)
print("🚲 대여 기준 Top 10 대여소:")
print(top_stations)
# 시각화
import matplotlib.pyplot as plt
top_stations.plot(kind="barh", figsize=(8, 5), color="teal")
plt.gca().invert_yaxis()
plt.title("Top 10 인기 대여소")
plt.xlabel("대여 횟수")
plt.tight_layout()
✅ 날씨와의 상관관계 분석

📌 분석 인사이트:
- 기온이 올라갈수록 이용건수도 증가하는 경향이 있었으며,
- 반대로 강수량과 풍속이 높을수록 이용이 감소하는 음의 상관관계를 보였습니다.
- 이는 날씨 정보가 수요 예측에 중요한 피처임을 의미합니다.
# 대여일시에서 날짜별 대여건수 집계
df_bike['날짜'] = pd.to_datetime(df_bike['날짜시간']).dt.date # 대여일시에서 날짜 추출
daily_bike = df_bike.groupby('날짜').size().reset_index(name='대여건수')
# 날씨 데이터의 날짜 형식 변환
df_weather['날짜시간'] = pd.to_datetime(df_weather['날짜시간']).dt.date
# 날별 이용량과 날씨 데이터 병합
merged = pd.merge(daily_bike, df_weather, left_on='날짜', right_on='날짜시간', how='inner')
# 상관관계 확인
correlation = merged.corr(numeric_only=True)
print(correlation)
✅ 성별 연령대별 이용건수
📌 분석 인사이트:
- 나이대별 이용건수는 20~40대에 집중되어 있었습니다.
- 성별의 경우 여성보다는 남성 사용자가 더 많은것으로 보입니다.
# 성별-연령대별 이용건수 합계
pivot = df_merged.groupby(['연령대코드', '성별'])['이용건수'].sum().unstack()
pivot.plot(kind='bar', stacked=False, figsize=(8, 5), title='성별/연령대별 이용건수')
plt.ylabel("이용건수")
plt.xticks(rotation=0)
✅ 대여 유형별 이용 비율, 시간
📌 분석 인사이트:
- 대부분의 사용자는 정기권에 구독중에 있었습니다.
- 오히려 사용시간은 정기권이 반복되는 사용으로 간결하게 사용하고, 일일권이나 비회원으로 사용하는 사람의 시간이 길었습니다.
# 대여구분코드별 이용건수 합계
usage_by_type = df_merged.groupby("대여구분코드")["이용건수"].sum().sort_values(ascending=False)
🤖 예측 모델링 (XGBoost 회귀)
# 특성 및 목표 변수 선택
X = df[['기온(°C)', '강수량(mm)', '시간대', '풍속(m/s)']]
y = df['이용건수']
# 훈련/테스트 데이터 분리
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# XGBoost 모델 학습
model = xgb.XGBRegressor(random_state=42)
model.fit(X_train, y_train)
# 예측
y_pred = model.predict(X_test)
# 성능 평가 (MAE)
mae = mean_absolute_error(y_test, y_pred)
📌 결과 해석:
- MAE가 약 0.1327로, 예측값과 실제값의 차이가 평균적으로 0.13건밖에 되지 않음 → 모델 성능 우수
- 날씨와 시간대만으로도 상당히 정확한 수요 예측이 가능함을 확인
🤖 클러스터링
# 필요한 컬럼 선택
df_cluster = df[['대여소명', '시간대', '요일']]
df_cluster['요일'] = df_cluster['요일'].astype('category').cat.codes # 요일을 숫자로 변환
# 군집화 (KMeans)
kmeans = KMeans(n_clusters=3, random_state=42) # 출퇴근, 관광 등 3개의 군집
df_cluster['cluster'] = kmeans.fit_predict(df_cluster[['시간대', '요일']])
📌 결과 해석:
- 오히려 요일, 시간대로 군집화에는 실패했는데 이용건수가 해당 사용자의 이용건수라서 군집화에 오류를 발생시킨것으로 보임.
📌 결론 및 다음 단계
- 시간대, 날씨, 요일 등을 활용한 예측 모델은 수요 예측에 효과적
- 대여소 위경도와 함께 분석 시 출퇴근/관광 패턴까지 파악 가능
- 향후 Google Mobility 데이터, 교통량 등 외부 데이터와 결합도 고려
- 군집화(클러스터링)와 추천시스템을 통한 서비스 최적화도 가능성 있음
'프로젝트' 카테고리의 다른 글
안양 부림동 공기질 분석 및 예측 프로젝트 (1) | 2025.05.15 |
---|---|
전기차 커뮤니티 데이터 분석 프로젝트 (0) | 2025.05.08 |
COVID-19 확진자 예측: 전통적 모델 vs 딥러닝 (0) | 2025.05.08 |
Tableau 실력향상 프로젝트 (0) | 2025.03.30 |
Olist 데이터 분석 프로젝트 (1) | 2025.03.30 |