회귀¶

  • 독립변수가 종속변수에 영향을 미치는지 알아보고자 할 때 사용
  • 연속형 변수들에 대해 두 변수 사이의 적합도를 측정
  • 단순회귀
    • 하나의 종속변수와 하나의 독립변수 사이의 관계 분석
  • 다중회귀
    • 하나의 종속변수와 여러 독립변수 사이의 관계 분석
No description has been provided for this image
In [ ]:
# 회귀란? 최적의 선을 찾는것...!!!
# 최적의 선이랑 예측 값의 선....
# 예측 값의 선으로 부터 결과 값들의 거리가 작을수록 좋은 예측이다

회귀 평가지표¶

  • MSE(Mean Squared Error)(평균 제곱 오차)
    • 예측값과 실제값의 차이에 대한 제곱에 대하여 평균을 낸 값
    • 회귀 문제에서 가장 많이 사용하는 성능 지표
    • 모델을 평가하는 평가 지표로 오차를 나타내는 식이므로 수치가 적을 수록 좋은 모델
    • 다른 모델과 비교해야만 성능이 좋은지 알 수 있다.
  • RMSE(Root Mean Squared Error)
    • 0에 가까울수록 좋은 모델
    • MSE에 ROOT를 쒸운 값
  • MAE(Mean Absolute Error, 평균 절대 오차)
    • 실제값 대비 예측값의 오차를 나타내는 것으로 값이 낮을 수록 좋다
    • 예측값과 실제값의 차이에 대한 절대값에 대하여 평균을 낸 값
  • MAPE(Mean Absolute Percentage Error, 평균 절대 비율 오차)
    • 실제값 대비 예측차이가 얼마나 있는지를 비율(%)로 측정
    • 퍼센트값을 가지며 0에 가까울수록 회귀모형의 성능이 좋다고 해석
  • r2(결정계수)
    • 0~1 사이의 값을 표현해 주며 r2의 값이 높을수록 좋다
    • 예측 모델과 실제 모델이 얼마나 강한 상관관계를 가지고 있는지

  • 타겟 데이터
    • 1978년 보스턴 주택 가격
    • 506개 타운의 주택 가격 중앙값(단위 1,000달러)
  • 특징 데이터
    • CRIM : 범죄율
    • ZM : 25,000평방 피트 당 주거용 토지의 비율
    • INDUS : 비소매상업지역 면적 비율
    • CHAS : 찰스강의 경계에 위치한 경우는 1, 아니면 0(통로가 하천을 향하면1, 아니면 0)
    • NOX : 일산화질소 농도(천만분의 1)
    • RM : 주택당 방수
    • AGE : 1940년 이전에 건축된 주택의 비율
    • DIS : 5개 주요 고용센터까지의 가중거리
    • RAD : 고속도로 접근성 지수
    • TAX : 재산세율
    • PTRATIO : 학생/교사 비율
    • B ; 인구 중 흑인 거주 비율
    • LSTAT : 인구 중 하위 계층 비율
    • MEDV : 본인 소유의 주택가격(중앙값) (단위: $1,000)
In [1]:
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
In [2]:
df = pd.read_csv("../data_set/6.회귀/HousingData.csv")
df.head()
Out[2]:
CRIM ZN INDUS CHAS NOX RM AGE DIS RAD TAX PTRATIO B LSTAT MEDV
0 0.00632 18.0 2.31 0.0 0.538 6.575 65.2 4.0900 1 296 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 0.0 0.469 6.421 78.9 4.9671 2 242 17.8 396.90 9.14 21.6
2 0.02729 0.0 7.07 0.0 0.469 7.185 61.1 4.9671 2 242 17.8 392.83 4.03 34.7
3 0.03237 0.0 2.18 0.0 0.458 6.998 45.8 6.0622 3 222 18.7 394.63 2.94 33.4
4 0.06905 0.0 2.18 0.0 0.458 7.147 54.2 6.0622 3 222 18.7 396.90 0.00 36.2
In [3]:
from sklearn.model_selection import train_test_split

y = df['MEDV']
X = df.drop(["MEDV"], axis=1)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
In [4]:
from sklearn.neighbors import KNeighborsRegressor

kn = KNeighborsRegressor()
kn.fit(X_train, y_train)
Out[4]:
KNeighborsRegressor()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KNeighborsRegressor()
In [20]:
pred = kn.predict( X_test )
pred
Out[20]:
array([23.46, 15.06, 23.38, 25.44, 22.14, 16.52, 20.02, 28.02, 23.52,
       21.5 , 41.54, 16.52, 23.9 , 29.94, 23.56, 17.32, 21.46, 24.3 ,
       14.84, 28.64, 23.46, 24.78, 17.92, 29.26, 18.62, 20.6 , 20.56,
       20.64, 18.32, 15.54, 11.68, 18.32, 28.72, 39.32, 38.  , 20.16,
       27.36, 20.98, 23.94, 24.06, 30.38,  9.96, 16.64, 34.9 , 28.76,
       15.4 , 30.02, 23.82, 13.26, 10.56, 28.02, 33.18, 20.88, 22.62,
       28.36, 24.56, 23.16, 21.64, 26.14, 11.14, 28.06, 15.2 , 21.5 ,
       13.26, 12.88, 13.34, 25.38, 12.3 , 13.28, 26.44, 23.96, 28.22,
       31.48, 18.24, 15.4 , 28.42, 24.46, 23.9 , 21.72, 34.34, 16.84,
        8.2 , 28.02, 23.36, 20.7 , 32.32, 12.34, 28.26, 15.4 , 29.  ,
       20.9 , 29.86, 23.  , 21.5 , 21.5 , 22.08, 20.96, 20.76, 28.06,
       13.1 , 17.96, 19.58, 14.76, 18.62, 11.92, 11.46, 18.14, 36.86,
       29.04, 22.48, 29.82, 25.52, 24.82, 14.68, 29.96, 28.02, 21.12,
       10.8 , 22.68, 20.7 , 30.34, 10.04, 21.64, 41.54, 12.32, 21.58,
       19.94, 31.92, 22.12, 11.82, 24.78, 19.26, 25.38, 36.18, 29.66,
       16.74, 22.38, 20.12, 41.54, 11.94, 22.42, 12.18, 17.76, 25.48,
       17.58, 27.02, 22.48, 24.66, 35.24, 27.82, 22.68, 40.16])
In [6]:
y_test
Out[6]:
63     25.0
417    10.4
339    19.0
84     23.9
215    25.0
       ... 
294    21.7
232    41.7
150    21.5
172    23.1
94     20.6
Name: MEDV, Length: 152, dtype: float64
In [21]:
from sklearn.metrics import mean_squared_error, r2_score

mse = mean_squared_error(y_test, pred)
r2 = r2_score(y_test, pred)

print("mse : ", mse)
print("r2 : ", r2)
print("score : ", kn.score(X_train, y_train))
print("score : ", kn.score(X_test, y_test))

# mse 는 0과 가까울 수록 좋은 결과
# r2, score 는 높을 수록 좋은 결과
mse :  43.82906578947368
r2 :  0.5349249633916936
score :  0.6057676219071229
score :  0.5349249633916936
In [ ]:
 
In [ ]:
 
In [17]:
from sklearn.ensemble import RandomForestRegressor

rfr = RandomForestRegressor()

rfr.fit(X_train, y_train)
Out[17]:
RandomForestRegressor()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
RandomForestRegressor()
In [19]:
pred = rfr.predict( X_test )
mse = mean_squared_error(y_test, pred)
r2 = r2_score(y_test, pred)

print("mse : ", mse)
print("r2 : ", r2)
print("score : ", rfr.score(X_train, y_train))
print("score : ", rfr.score(X_test, y_test))
mse :  13.420632730263165
r2 :  0.857592190344317
score :  0.9701950979154201
score :  0.857592190344317
In [ ]:
 
In [ ]:
 

자전거 수요 예측¶

  • 자전거 수요를 파악하여 효율적으로 자전거 대여수를 예측하고자 한다
  • 월, 일, 시 별로 언제 자전거를 많이 대여하는지를 파악한다
  • 컬럼
    • datetime : 대여 날짜
    • season : 1(봄), 2(여름), 3(가을), 4(겨울)
    • holiday : 1(토,일 주말을 제외한 국경일 등의 휴일), 0(휴일이 아닌 날)
    • workingday : 1(토, 일 주말 및 휴일이 아닌 주중), 0(주말 및 휴일)
    • weather : 1(맑음), 2(흐림), 3(가벼운 눈, 비), 4(심한 눈, 비)
    • temp : 온도(섭씨)
    • atemp : 체감온도(섭씨)
    • humidity : 습도
    • windspeed : 풍속
    • casual : 비등록 대여 횟수
    • registered : 등록 대여 횟수
    • count : 총 대여 횟수
In [23]:
df = pd.read_csv("../data_set/6.회귀/data.csv")
df.head()
Out[23]:
datetime season holiday workingday weather temp atemp humidity windspeed casual registered count
0 2011-01-01 00:00:00 1 0 0 1 9.84 14.395 81 0.0 3 13 16
1 2011-01-01 01:00:00 1 0 0 1 9.02 13.635 80 0.0 8 32 40
2 2011-01-01 02:00:00 1 0 0 1 9.02 13.635 80 0.0 5 27 32
3 2011-01-01 03:00:00 1 0 0 1 9.84 14.395 75 0.0 3 10 13
4 2011-01-01 04:00:00 1 0 0 1 9.84 14.395 75 0.0 0 1 1
In [24]:
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10886 entries, 0 to 10885
Data columns (total 12 columns):
 #   Column      Non-Null Count  Dtype  
---  ------      --------------  -----  
 0   datetime    10886 non-null  object 
 1   season      10886 non-null  int64  
 2   holiday     10886 non-null  int64  
 3   workingday  10886 non-null  int64  
 4   weather     10886 non-null  int64  
 5   temp        10886 non-null  float64
 6   atemp       10886 non-null  float64
 7   humidity    10886 non-null  int64  
 8   windspeed   10886 non-null  float64
 9   casual      10886 non-null  int64  
 10  registered  10886 non-null  int64  
 11  count       10886 non-null  int64  
dtypes: float64(3), int64(8), object(1)
memory usage: 1020.7+ KB
In [25]:
# 문자열(object) 형식으로 저장되어 있던 datetime 을
# datetime 자료형으로 변환
df['datetime'] = df['datetime'].apply(pd.to_datetime)

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10886 entries, 0 to 10885
Data columns (total 12 columns):
 #   Column      Non-Null Count  Dtype         
---  ------      --------------  -----         
 0   datetime    10886 non-null  datetime64[ns]
 1   season      10886 non-null  int64         
 2   holiday     10886 non-null  int64         
 3   workingday  10886 non-null  int64         
 4   weather     10886 non-null  int64         
 5   temp        10886 non-null  float64       
 6   atemp       10886 non-null  float64       
 7   humidity    10886 non-null  int64         
 8   windspeed   10886 non-null  float64       
 9   casual      10886 non-null  int64         
 10  registered  10886 non-null  int64         
 11  count       10886 non-null  int64         
dtypes: datetime64[ns](1), float64(3), int64(8)
memory usage: 1020.7 KB
In [29]:
# 년 / 월 / 일 / 시
# 컬럼으로 따로 분리
df['year'] = df['datetime'].dt.year
df['month'] = df['datetime'].dt.month
df['day'] = df['datetime'].dt.day
df['hour'] = df['datetime'].dt.hour
In [28]:
df.head()
Out[28]:
datetime season holiday workingday weather temp atemp humidity windspeed casual registered count year month day hour
0 2011-01-01 00:00:00 1 0 0 1 9.84 14.395 81 0.0 3 13 16 2011 1 1 0
1 2011-01-01 01:00:00 1 0 0 1 9.02 13.635 80 0.0 8 32 40 2011 1 1 1
2 2011-01-01 02:00:00 1 0 0 1 9.02 13.635 80 0.0 5 27 32 2011 1 1 2
3 2011-01-01 03:00:00 1 0 0 1 9.84 14.395 75 0.0 3 10 13 2011 1 1 3
4 2011-01-01 04:00:00 1 0 0 1 9.84 14.395 75 0.0 0 1 1 2011 1 1 4
In [31]:
# 시간 별로 빌린 자전거 댓수의 합
d = df.groupby('hour').agg({"count":sum}).reset_index()
d
Out[31]:
hour count
0 0 25088
1 1 15372
2 2 10259
3 3 5091
4 4 2832
5 5 8935
6 6 34698
7 7 96968
8 8 165060
9 9 100910
10 10 79667
11 11 95857
12 12 116968
13 13 117551
14 14 111010
15 15 115960
16 16 144266
17 17 213757
18 18 196472
19 19 143767
20 20 104204
21 21 79057
22 22 60911
23 23 40816
In [35]:
import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(7,5))
sns_result = sns.pointplot(data=d, x="hour", y="count")

plt.xticks(rotation=45)
plt.title("bicycle rental", fontsize=15, color="black")
plt.show()
No description has been provided for this image
In [44]:
# 휴일과 휴일이 아닌 날로 그룹화
d = df.groupby(['hour','workingday']).agg({"count":sum}).reset_index()
d.head()
Out[44]:
hour workingday count
0 0 0 13701
1 0 1 11387
2 1 0 10427
3 1 1 4945
4 2 0 7686
In [45]:
# 1 : 주중
# 0 : 휴일 ( 토, 일 )
sns.pointplot(data=d, x="hour", y="count", hue="workingday")
plt.show()
No description has been provided for this image
In [46]:
# 시간대 별, 월 별로 확인
d = df.groupby(['hour','month']).agg({"count":sum}).reset_index()
d.head()
Out[46]:
hour month count
0 0 1 852
1 0 2 1096
2 0 3 1249
3 0 4 1480
4 0 5 2441
In [47]:
sns.pointplot(data=d, x="hour", y="count", hue="month")
plt.show()
No description has been provided for this image
In [49]:
# 시간대 별, 날씨 별로 확인
# weather : 1(맑음), 2(흐림), 3(가벼운 눈, 비), 4(심한 눈, 비)
d = df.groupby(['hour','weather']).agg({"count":sum}).reset_index()
d.head()
sns.pointplot(data=d, x="hour", y="count", hue="weather")
plt.show()
No description has been provided for this image
In [50]:
df.columns
Out[50]:
Index(['datetime', 'season', 'holiday', 'workingday', 'weather', 'temp',
       'atemp', 'humidity', 'windspeed', 'casual', 'registered', 'count',
       'year', 'month', 'day', 'hour'],
      dtype='object')
In [51]:
f = ['season', 'holiday', 'workingday', 'weather', 'temp',
       'atemp', 'humidity', 'windspeed', 'year', 'month', 'day', 'hour']
l = 'count'
X, y = df[f], df[l]
In [52]:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
In [53]:
from sklearn.ensemble import RandomForestRegressor
rfr = RandomForestRegressor()
rfr.fit(X_train, y_train)
print("train : ", rfr.score(X_train, y_train))
print("test : ", rfr.score(X_test, y_test))
train :  0.9914114957469251
test :  0.9376778114053523
In [54]:
from sklearn.model_selection import GridSearchCV

params = {
    "n_estimators" : range(5, 100, 10), # 트리 갯수(알고리즘)
    "max_depth" : range(4, 11, 2), # 트리의 최대 깊이
    "min_samples_split" : range(4, 21, 4) # 립노드 조건 샘플 수
}

rfr = RandomForestRegressor()
grid_cv = GridSearchCV(rfr, param_grid=params, cv=3, n_jobs=-1)

grid_cv.fit(X_train, y_train)

print("최적의 파라미터 : ", grid_cv.best_params_)
print("train : ", grid_cv.score(X_train, y_train))
print("test : ", grid_cv.score(X_test, y_test))
최적의 파라미터 :  {'max_depth': 10, 'min_samples_split': 4, 'n_estimators': 75}
train :  0.9525772588841167
test :  0.9206851922918676
In [55]:
X.head(3)
Out[55]:
season holiday workingday weather temp atemp humidity windspeed year month day hour
0 1 0 0 1 9.84 14.395 81 0.0 2011 1 1 0
1 1 0 0 1 9.02 13.635 80 0.0 2011 1 1 1
2 1 0 0 1 9.02 13.635 80 0.0 2011 1 1 2
In [59]:
# 대략 아래와 같은 상황에서는 자전거가 20대가 필요하겠다....!!
# 아래와 같은 계절, 흄, 날씨, 온도 등등등.... 에서
re = grid_cv.predict([[1, 0, 0, 1, 9.84, 14.395, 81, 0.0, 2011, 1, 1, 0]])
re[0]
Out[59]:
20.63599993470582
In [58]:
int(re[0])
Out[58]:
20
In [ ]:
 
In [ ]:
 
In [60]:
# 예제 : 두 값을 비교하기 위함
df_result = pd.DataFrame({"y_test ": [11,12,13,14,15,16,17,18,19],
                    "line_test" : [10,11,12,13,14,15,16,17,18]})

sns.lineplot(data = df_result)
plt.legend(labels=["Legend_Day1","Legend_Day2"])
# 실제 정답과 예측 정답 두가지를 넣고 lineplot를 이용하여 그리면 된다
Out[60]:
<matplotlib.legend.Legend at 0x1b203e646d0>
No description has been provided for this image
In [61]:
grid_cv.predict(X_test)
Out[61]:
array([147.88696059, 272.60793329,  18.18288773, ..., 197.27226131,
       415.09046011, 419.37438723])
In [62]:
y_test
Out[62]:
7971     95
848     162
642      37
1023      1
6050    508
       ... 
5327     31
3742    121
4530    209
4375    209
8311    294
Name: count, Length: 3266, dtype: int64
In [69]:
range_start = 0
range_end = 30
line_test = grid_cv.predict(X_test)

y_test_reset = y_test[range_start : range_end].reset_index()
y_test_reset['pred_test'] = line_test[range_start : range_end]
y_test_reset['pred_test'] = y_test_reset['pred_test'].apply( int )

sns.lineplot( data = y_test_reset[['count', 'pred_test']])
plt.legend(labels = ['y_test', 'pred test'])
Out[69]:
<matplotlib.legend.Legend at 0x1b20aae5b10>
No description has been provided for this image