#0 개요

    1. 사용 라이브러리

    numpy

    pandas

    seaborn

    matplotlib

    sklearn

    datetime, calendar

     

    [작성 위치]

    https://www.kaggle.com/code/imjh99/notebooka8aee6dae3/edit

    #1 해당 경진대회 개요 (p169)

    1. 서울시 따릉이와 비슷한 자전거 대여 시스템

     

    2. 플레이 그라운드 난이도 (낮음)

     

    3. 피처 (독립변수) 는 대여날짜, 시간, 요일, 계절, 날씨, 실제 온도, 체감 온도, 습도, 풍속, 회원 여부.

     

    4. 예측할 값이 범주형 데이터가 아니므로 본 대회는 회귀 문제에 속함.

    회귀란?

    자연현상이나 사회 현사에서 변수 사이에 관계가 있는 경우, 이를 추론하는 과정.

    독립 변수와 종속 변수 사이의 관계. 이때 종속 변수가 수치형 데이터야 관계를 측정할 수 있으니 수치형임

     

    회귀 평가 지표란?

    예측하는 모델을 만들었으면 얼마나 잘 예측했는지 측정을 해야함.

    회귀 평가지표 값이 작을수록 모델 성능이 좋음. (p111에 지표 수식)

     

    [+ 캐글 경진대회에서의 평가 지표] (p 173)

    경진 대회에 평가 지표가 어떤 식으로 이루어지는지 Evaluation 항목에 고지되어있을 수 있음.

     

    5. RMSLE 평가 지표란? (p173)

     

     

     

    6. 유사 용어

    피처 = 독립변수

    타깃값 = 종속변수 (p170)

     

     

    7. Data 탭에서 데이터에 대해서 설명하고, 어떤 피쳐로 어떤 타깃값을 예측해야하는지 설명을 해줌

     

    8. shake-up 이란? (178p)

    경진대회 진행 중, 점수를 보여주는 Leader board의 점수 측정 방식은, 주최측에서 준비한 일부 데이터만을 사용해 평가 점수를 산출하고 등수를 메긴다. 따라서 대회가 끝나고 테스트 데이터 전체를 기반으로 다시 점수를 측정하는데,

    이 때 두 점수의 차이가 크면 shake-up이 심하다고 함.

     

    #2 탐색적 데이터 분석 EDA(1) - 피처 엔지니어링

    0. 페이지 순서 고려하지 않고, 이 단계에서 진행한 분석 결과 나열

    1) 훈련 데이터에서 casual, registered 피처 제거 ( 이유: test 데이터에도 빠져 있었기 때문 )

    2) 분석 결과 datetime 피처 제거 ( 이유: id 값이기 때문 )

     

     

    1. p182 pandas로 데이터 불러보기

    import numpy as np
    import pandas as pd
    
    data_path = "/kaggle/input/bike-sharing-demand/"
    
    train = pd.read_csv(data_path + "train.csv")
    test = pd.read_csv(data_path + "test.csv")
    submission = pd.read_csv(data_path + "sampleSubmission.csv")
    
    train.head()

     

    feature 분석

    season - 1 봄, 2 여름, 3 가을, 4 겨울

    holiday - 0 공휴일 아님, 1 공휴일

    working day 0 근무일 아님, 1 근무일

    weather 날씨. 숫자가 클수록 안좋음 (1 맑음, 2 옅은 안개, 3약간의 눈 비, 4 폭우 천둥 눈 비)

     

    2. dataframe.info() 를 통해 각 컬럼의 데이터 타입이나 null 여부(결측값 여부) 등을 알 수 있다.

     

    3. date-time 데이터 타입을 object에서 date로.

    ! pandas에서 object 타입은 그냥 사실상 문자열 타입이라고 생각하면 됨.

     

    4. apply

    dataframe의 각 열에 인자로 전달되는 함수를 적용한다.

     

    5. 머신러닝 주의사항!

    머신러닝 모델은 숫자만 인식하므로 모델을 훈련할 때는 피처 값을 문자로 바꾸면 안됨.

     

    6. datetime.strptime(date_string, format)

    문자열 형식의 날짜와 시간을 datetime 객체로 변환해줌

     

    7. p189 일자 형변환 및 요일 출력

    print(train['date'][100])
    print(datetime.strptime(train['date'][100], "%Y-%m-%d"))
    
    #정수로 요일 반환
    print(datetime.strptime(train['date'][100], "%Y-%m-%d").weekday())
    
    #문자로 요일 반환
    print(calendar.day_name[datetime.strptime(train['date'][100], "%Y-%m-%d").weekday()])

     

    8. 숫자로 표현된 범주형 데이터의 경우 map을 사용해서 이름을 넣어주면 데이터를 보기 편해짐.

     

    9. 지나치게 세분화된 피처는 특징을 찾아 더 큰 분류로 묶으면 성능이 좋아지는 경우가 있음

    month 피처를 season 피처로 묶은 후 제거

     

    10. 최종적인 피쳐 엔지니어링

    import numpy as np
    import pandas as pd
    from datetime import datetime
    
    data_path = "/kaggle/input/bike-sharing-demand/"
    
    train = pd.read_csv(data_path + "train.csv")
    test = pd.read_csv(data_path + "test.csv")
    submission = pd.read_csv(data_path + "sampleSubmission.csv")
    
    #train.info()
    
    train["date"] = train["datetime"].apply(lambda x: x.split()[0])
    
    train["year"] = train['datetime'].apply(lambda x: x.split()[0].split("-")[0])
    train["day"] = train['datetime'].apply(lambda x: x.split()[0].split("-")[2])
    train["hour"] = train['datetime'].apply(lambda x: x.split()[1].split(":")[0])
    train["minute"] = train['datetime'].apply(lambda x: x.split()[1].split(":")[1])
    train["second"] = train['datetime'].apply(lambda x: x.split()[1].split(":")[2])
    
    train['weekday'] = train['date'].apply(
        lambda dateString:
        calendar.day_name[datetime.strptime(train['date'][100], "%Y-%m-%d").weekday()]
    )
    
    train['season'] = train['season'].map({1: 'Spring',
                                          2: 'Summer',
                                          3: 'Fall',
                                          4: 'Winter'})
    
    train['weather'] = train['weather'].map({1: 'Clear',
                                            2: 'Mist, Few clouds',
                                            3: 'Light Snow, Rain, Thunderstorm',
                                            4: 'Heavy Rain, Thunderstorm, Snow, Fog'})
    
    train = train.drop(columns=['date'])
    
    train.head()

     

     

    #3 탐색적 데이터 분석 EDA(2) - 데이터 시각화

    1.

    import matplotlib as mpl
    import matplotlib.pyplot as plt
    %matplotlib inline

    %matplotlib inline 는 주피터 노트북 사용시 matplotlib이 그린 그래프를 바로 출력하도록 만드는 구문이다.

     

    2. 회귀 모델이 좋은 성능을 내려면 데이터가 정규분포를 따라야 함.

    따라서 아래와 같은 그래프를 로그변환을 사용해서 변화시켜줘야 함.

    import seaborn as sns
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    %matplotlib inline
    
    #폰트 크기를 15
    mpl.rc('font', size=15)
    
    #무한대를 NaN으로 바꾸라는 경고문에 따른 코드
    #근데 추가해도 경고 안 사라짐
    train['count'] = train['count'].replace([np.inf, -np.inf], np.nan)
    
    #분포도 출력
    sns.displot(train['count'])

    sns.displot(np.log(train['count']))

    3. 로그 변환 추가.

    오른쪽으로 긴 꼬리 형태일 때 도움이 되는 로그변환.

    GPT야 도와줘

     

    따라서 위 코드를 조금 더 분해해보면 아래와 같다.

    1) 먼저 numpy의 로그 변환을 취하면 밑이 자연상수가 됨.

     

    2) train 데이터에 count가 0인 값이 존재하지 않음

    따라서 로그 변환시 0이 들어가서 -inf가 출력되는 오류가 발생하지 않음

    이러한 오류 때문에 np.log 대신

    np.log1p()

    를 사용하는 경우도 있음.

    자동적으로 로그의 내부값이 x면 x+1로 해주는 것. 그럼 x가 들어가도 변환시 0이된다.

     

    3) 그렇다면 오른쪽으로 치우쳐진 그래프는 왜?

    일단 변환 전 그래프의 막대를 잘게 쪼개고 확대해보면 앞은 이런 모양이다.

    즉 위와 같은 분포의 극단적으로 오른쪽으로 긴 꼬리형태.

     

    로그분포로 바꾸면 두가지 특징이 생긴다.

    특징1. y=0 이되는 x가 0에서 1이 될때까지의 범위는 오히려 늘어난다는 것.

    특징2. 변환 전 x값이 0에서 멀어지면 멀어질수록, 압축률이 올라간다는 것.

    따라서 그래프로 표현하게되면 상대적으로 표현되기 때문에 0에서 가까운 애들은 y값은 크지만 x가 적은 범위가 합쳐지고, 0에서 먼 애들은 y값은 작지만 x가 큰 범위가 합쳐진다는 것.

     

    예를 들어 밑이 10인 로그는 x가 0~1까지는 넓어지고

    1에서 10까지와

    10에서 100까지와

    100에서 1000까지가 합쳐져서 비교된다는 것.

    그림으로 표현하면 아래와 같다.

     

    4. 서브플롯 사이에 여백을 주는 코드 (p196)

    plt.tight_layout()

     

    5. 완성된 barplot

    mpl.rc('font', size = 14)
    mpl.rc('axes', titlesize = 15)
    figure, axes = plt.subplots(nrows=3, ncols=2)
    plt.tight_layout()
    figure.set_size_inches(10, 9)
    
    sns.barplot(x='year', y='count', data=train, ax=axes[0,0])
    sns.barplot(x='month', y='count', data=train, ax=axes[0,1])
    sns.barplot(x='day', y='count', data=train, ax=axes[1,0])
    sns.barplot(x='hour', y='count', data=train, ax=axes[1,1])
    sns.barplot(x='minute', y='count', data=train, ax=axes[2,0])
    sns.barplot(x='second', y='count', data=train, ax=axes[2,1])
    
    axes[1,0].tick_params(axis='x', labelrotation=90)
    axes[1,1].tick_params(axis='x', labelrotation=90)

     

    6. boxplot (201p)

    boxplot은 범주형 데이터에 따른 수치형 데이터의 정보를 나타내는 그래프 

    figure, axes = plt.subplots(nrows = 2, ncols = 2)
    plt.tight_layout()
    figure.set_size_inches(10, 10)
    
    sns.boxplot(x='season', y='count', data=train, ax=axes[0,0])
    sns.boxplot(x='weather', y='count', data=train, ax=axes[0,1])
    sns.boxplot(x='holiday', y='count', data=train, ax=axes[1,0])
    sns.boxplot(x='workingday', y='count', data=train, ax=axes[1,1])
    
    axes[0, 0].set(title='Box Plot On Count Across Season')
    #이하 제목 생략
    
    axes[0, 1].tick_params(axis='x', labelrotation=10)

     

     

    의문?

    season을 보고 봄이 가장 적다고 할 수 있나? 중위수가 낮다고 대여 수량이 낮은 것인가?

    그 이유 중 하나로 엄청 많은 상향 이상치.

    즉, 평균적으로 많이 빌리지는 않지만 또 빌릴때는 엄청 많이 빌린다는 소리 아닌가?

     

     

    7. 포인트 플롯

    범주형 데이터에 따른 수치형 데이터의 평균과 신뢰구간을 점과 선으로 표시함.

    hue 인자에 비교하고 싶은 데이터를 전달함.

    시계열에 따른 값 비교 가능

    mpl.rc('font', size=11)
    #n행 m열. 여기서는 5행 1열
    figure, axes = plt.subplots(nrows=5)
    figure.set_size_inches(12, 18)
    
    sns.pointplot(x='hour', y='count', data=train, hue='workingday', ax=axes[0])
    sns.pointplot(x='hour', y='count', data=train, hue='holiday', ax=axes[1])
    sns.pointplot(x='hour', y='count', data=train, hue='weekday', ax=axes[2])
    sns.pointplot(x='hour', y='count', data=train, hue='season', ax=axes[3])
    sns.pointplot(x='hour', y='count', data=train, hue='weather', ax=axes[4])

     

    weather == 4 인 이상치 데이터 제거하는게 좋겠다고 판단.

     

    8. 회귀선을 포함한 산점도 그래프

    mpl.rc('font', size=15)
    figure, axes = plt.subplots(nrows=2, ncols=2)
    plt.tight_layout()
    figure.set_size_inches(7,6)
    
    sns.regplot(x='temp', y='count', data=train, ax=axes[0,0],
               scatter_kws={'alpha':0.2}, line_kws={'color':'blue'})
    sns.regplot(x='atemp', y='count', data=train, ax=axes[0,1],
               scatter_kws={'alpha':0.2}, line_kws={'color':'blue'})
    sns.regplot(x='windspeed', y='count', data=train, ax=axes[1,0],
               scatter_kws={'alpha':0.2}, line_kws={'color':'blue'})
    sns.regplot(x='humidity', y='count', data=train, ax=axes[1,1],
               scatter_kws={'alpha':0.2}, line_kws={'color':'blue'})

    9. 히트맵 (208p)

    corrMat = train[['temp', 'atemp', 'humidity', 'windspeed', 'count']].corr()
    fig, ax = plt.subplots()
    fig.set_size_inches(10, 10)
    sns.heatmap(corrMat, annot=True)
    ax.set(title="Heatmap")

    • 네이버 블러그 공유하기
    • 네이버 밴드에 공유하기
    • 페이스북 공유하기
    • 카카오스토리 공유하기