AI/데이터 분석

[DACON] 따릉이 데이터 분석 EDA

HHB 2022. 11. 29. 19:54

환경 : Colab

from google.colab import drive
drive.mount('/content/drive')

!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf

구글 드라이브를 통해 파일을 업로드 할 것이다.

그리고 코랩에서의 그래프에서 한글이 깨지는 것을 방지하기 위해 위 폰트들을 설치한 후 런타임 재실행한다.

 

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import warnings
warnings.filterwarnings(action='ignore')

palette = sns.color_palette('Dark2')
plt.rc('font', family='NanumBarunGothic') 

train = pd.read_csv('train 경로')
test = pd.read_csv('test 경로')
submission = pd.read_csv('submission 경로')

print(train.shape, train.columns)
print(test.shape, test.columns)
print(submission.shape, submission.columns)
  1. 필요한 라이브러리를 불러오고
  2. 경고 메시지 제거, 그래프 색상 지정, 폰트 지정을 했다.
  3. 그리고 구글 드라이브에 있는 파일을 read_csv로 읽어왔다.
  4. 각 데이터 프레임의 모양과 컬럼명을 확인했다.
train.info()
#<class 'pandas.core.frame.DataFrame'>
#RangeIndex: 1459 entries, 0 to 1458
#Data columns (total 11 columns):
# #   Column                  Non-Null Count  Dtype  
#---  ------                  --------------  -----  
# 0   id                      1459 non-null   int64  
# 1   hour                    1459 non-null   int64  
# 2   hour_bef_temperature    1457 non-null   float64
# 3   hour_bef_precipitation  1457 non-null   float64
# 4   hour_bef_windspeed      1450 non-null   float64
# 5   hour_bef_humidity       1457 non-null   float64
# 6   hour_bef_visibility     1457 non-null   float64
# 7   hour_bef_ozone          1383 non-null   float64
# 8   hour_bef_pm10           1369 non-null   float64
# 9   hour_bef_pm2.5          1342 non-null   float64
# 10  count                   1459 non-null   float64
#dtypes: float64(9), int64(2)
#memory usage: 125.5 KB
#[4]
#0초

일단 훈련 데이터의 정보를 봤을 때 몇몇 컬럼에서 결측값이 있는 것을 확인했다. 

각 컬럼별 결측값이 직관적으로 다가오지 않아 시각화를 했다.

plt.title("결측값 확인 그래프")
train.isnull().sum().plot.barh(color=palette)

결측값 확인 그래프

위 그래프를 봤을 때 미세먼지, 오존 데이터에 결측값이 많다는 것을 확인했다.

각 결측값을 채우기 위해 어떻게 해야 할지 조사했다.

sns.heatmap(train.corr(), annot=True, fmt = '.2f', linewidths=.5)

상관계수 시각화

위 그래프를 보면 id 값이 없는걸 확인할 수 있는데 id 는 각 row을 식별하는 고유의 값이기 때문에 분석에 도움되지 않아 drop했다.

train.drop('id', inplace=True, axis=1)

다시 상관계수 그래프를 보면 상관관계가 있는 값들이 보인다.

hour, temperature는 count와 상대적으로 강한 양의 상관관계를 가지고 있다.

그리고 시간 / 온도, 풍속, 오존은 약한 양의 상관관계를 , 습도는 음의 상관관계를 가지고 있다.

 

따라서 시간에 따라 온도, 풍속, 오존, 습도의 결측값을 대체하기로 했다.

hour_null_col = ['hour_bef_temperature', 'hour_bef_windspeed', 'hour_bef_humidity', 'hour_bef_ozone']
for col in hour_null_col:
    index = train[train[col].isnull()][col].index
    print(col)
    for i in index:
        hour = train.iloc[i, :]['hour']
        
        train[col][i] = groupby_hour.iloc[int(hour), :][col]

그리고 나머지 결측값들은 각 컬럼의 평균값으로 대체하기로 했다.

train['hour_bef_precipitation'].fillna(train['hour_bef_precipitation'].mean(), inplace=True)
train['hour_bef_visibility'].fillna(train['hour_bef_visibility'].mean(), inplace=True)
train['hour_bef_ozone'].fillna(train['hour_bef_ozone'].mean(), inplace=True)
train['hour_bef_pm10'].fillna(train['hour_bef_pm10'].mean(), inplace=True)
train['hour_bef_pm2.5'].fillna(train['hour_bef_pm2.5'].mean(), inplace=True)

 

시각화

train['AMPM'] = np.where(train['hour'] >= 12, "PM", "AM")

plt.title("오전 / 오후 사용량 비교")
train.groupby("AMPM").sum()['count'].plot.pie(colors = palette, autopct='%.1f%%')

오전 / 오후 사용량 비교

오전보다 오후에 3배가량 사용량이 많다.

figure, axs = plt.subplots(figsize=(15, 15), nrows=3, ncols=4)
axs = axs.flatten()
for i in range(1, len(train.columns)):
    sns.boxplot(train['hour'], train.iloc[:, i], ax=axs[i])

시간별 각 컬럼 boxplot

데이터가 전체적으로 연속 변수이기 때문에 boxplot으로 이상값과 데이터의 분포를 확인했다.

이상값이 매우 많다는 것을 알 수 있었다.

 

gubun = []
for pm in train['hour_bef_pm2.5']:
    if pm <= 15:
        gubun.append("좋음")
    elif pm <= 50:
        gubun.append("보통")
    elif pm <= 100:
        gubun.append("나쁨")
    else:
        gubun.append("매우나쁨")

train["초미세먼지"] = pd.Series(gubun)
train.head()
gubun = []
for pm in train['hour_bef_pm10']:
    if pm <= 30:
        gubun.append("좋음")
    elif pm <= 80:
        gubun.append("보통")
    elif pm <= 150:
        gubun.append("나쁨")
    else:
        gubun.append("매우나쁨")

train["미세먼지"] = pd.Series(gubun)
train.head()

미세먼지, 초미세먼지 나눈 기준 : https://misebig.tistory.com/6

 

미세빅이 PM2.5, PM10, NO2의 4단계를 6단계로 개편한 이야기

US AQI와 WHO Air Quality Guidelines을 참고하여 초미세먼지, 미세먼지, 이산화질소의 4단계를 6단계로 개선 이번 겨울 초미세먼지 농도가 100~200 μg/m3나 되던 적이 있었죠, 농도가 51 μg/m3 이든 200 μg/m3 이

misebig.tistory.com

plt.figure(figsize=(9, 6))
plt.subplot(1, 2, 1)
plt.title("초미세먼지")
train.groupby("초미세먼지").sum()['count'].plot.bar(color=palette)
plt.subplot(1, 2, 2)
plt.title("미세먼지")
train.groupby("미세먼지").sum()['count'].plot.bar(color=palette)

초미세먼지, 미세먼지별 이용량

미세먼지, 초미세먼지가 보통일 때 이용량이 가장 많았고 좋음, 나쁨 순이다.

미세먼지, 초미세먼지가 좋음이라고 해서 사용량이 늘어나진 않는 것 같다.

train['hour_bef_precipitation'] = train['hour_bef_precipitation'].map(lambda x : round(x))

비가 내렸는지 내리지 않았는지에 따라 분석하기 전 강수 유무 값에 이상값이 있어 0, 1로만 만들어줬다.

plt.title("비 내림 유무에 따른 사용량")
train.groupby("hour_bef_precipitation").sum()['count'].plot.bar(color=palette)

비 내림 유무에 따른 사용량

비가 내릴 땐 사용량이 급격히 준다.

plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title("풍속에 따른 사용량")
train.groupby('hour_bef_windspeed').sum()['count'].plot(color=palette[0])
plt.subplot(1, 2, 2)
plt.title("습도에 따른 사용량")
train.groupby("hour_bef_humidity").sum()['count'].plot(color=palette[2])

그렇다면 풍속과 습도에 따른 사용량은 어떨까

풍속 / 습도에 따른 사용량

마지막으로 시간에 따른 사용량이다.

plt.title("시간에 따른 사용량")
train.groupby('hour').sum()['count'].plot.bar(color=palette)

시간에 따른 사용량

위 그래프를 보면 오전엔 8시, 오후엔 6시가 각 피크이다.

왜 그럴까 생각을 해보면 오전엔 출근?을 할 때 사용하는 것 같고 오후엔 퇴근 및 산책에 이용되는게 아닐까 싶다.

 

 

다음은 지금까지 분석한 내용을 바탕으로 사용량을 예측해보겠다.

728x90
반응형
LIST

'AI > 데이터 분석' 카테고리의 다른 글

Bag of Words (BoW)란 ?  (0) 2024.02.24
왁물원 카페 크롤링 및 우왁굳즈 워드클라우드  (0) 2022.12.21