데이터 불러오기 !
저자가 걸어둔 링크를 통해서 데이터를 바로 다운 받을 수 있다.
https://drive.google.com/file/d/1pko9oRmCllAxipZoa3aoztGZfPAD2iwj/view?usp=sharing
import pandas as pd
features = pd.read_csv('temps.csv')
#설명에 따르기 위해 필요한 컬럼만 가져온다.
features = features[['year','month','day','week','temp_2','temp_1','average','actual','friend']]
features[:5]
year | month | day | week | temp_2 | temp_1 | average | actual | friend | |
---|---|---|---|---|---|---|---|---|---|
0 | 2016 | 1 | 1 | Fri | 45 | 45 | 45.6 | 45 | 29 |
1 | 2016 | 1 | 2 | Sat | 44 | 45 | 45.7 | 44 | 61 |
2 | 2016 | 1 | 3 | Sun | 45 | 44 | 45.8 | 41 | 56 |
3 | 2016 | 1 | 4 | Mon | 44 | 41 | 45.9 | 40 | 53 |
4 | 2016 | 1 | 5 | Tues | 41 | 40 | 46.0 | 44 | 41 |
- 각 행은 하나의 관측치를 나타내고, 열에 변수 값이 있는 깔끔한 데이터 형식이다.
year: 모든 데이터는 2016임.
month: 월
day: 일
week: 날짜이며, 문자(str) 형식이다.
temp_2: 이틀전 최고 온도.
temp_1: 하루전 최고 온도.
average: 과거 평균 최대 온도.
actual: 측정된 최대 온도.
friend: your friend’s prediction, a random number between 20 below the average and 20 above the average
#데이터 프레임의 사이즈.
features.shape
(348, 9)
- 이상 징후를 신속하게 파악하기 위해 요약 통계를 사용할 수 있다.
features.describe()
year | month | day | temp_2 | temp_1 | average | actual | friend | |
---|---|---|---|---|---|---|---|---|
count | 348.0 | 348.000000 | 348.000000 | 348.000000 | 348.000000 | 348.000000 | 348.000000 | 348.000000 |
mean | 2016.0 | 6.477011 | 15.514368 | 62.652299 | 62.701149 | 59.760632 | 62.543103 | 60.034483 |
std | 0.0 | 3.498380 | 8.772982 | 12.165398 | 12.120542 | 10.527306 | 11.794146 | 15.626179 |
min | 2016.0 | 1.000000 | 1.000000 | 35.000000 | 35.000000 | 45.100000 | 35.000000 | 28.000000 |
25% | 2016.0 | 3.000000 | 8.000000 | 54.000000 | 54.000000 | 49.975000 | 54.000000 | 47.750000 |
50% | 2016.0 | 6.000000 | 15.000000 | 62.500000 | 62.500000 | 58.200000 | 62.500000 | 60.000000 |
75% | 2016.0 | 10.000000 | 23.000000 | 71.000000 | 71.000000 | 69.025000 | 71.000000 | 71.000000 |
max | 2016.0 | 12.000000 | 31.000000 | 117.000000 | 117.000000 | 77.400000 | 92.000000 | 95.000000 |
- one-hot-encoding을 통해서 명목변수들을 나눠준다. a.k.a 더미변수.
features = pd.get_dummies(features)
features[:5]
year | month | day | temp_2 | temp_1 | average | actual | friend | week_Fri | week_Mon | week_Sat | week_Sun | week_Thurs | week_Tues | week_Wed | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2016 | 1 | 1 | 45 | 45 | 45.6 | 45 | 29 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 2016 | 1 | 2 | 44 | 45 | 45.7 | 44 | 61 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
2 | 2016 | 1 | 3 | 45 | 44 | 45.8 | 41 | 56 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
3 | 2016 | 1 | 4 | 44 | 41 | 45.9 | 40 | 53 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
4 | 2016 | 1 | 5 | 41 | 40 | 46.0 | 44 | 41 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
feature 와 target으로 나누어 array 만들기
actual 이라고 해서 실제 관측된 최대 온도가 우리가 예측하고자 하는 컬럼이다.
# array로 바꾸기 위해 numpy 불러오기.
import numpy as np
# 예측하고자 하는 라벨(타겟변수)
labels = np.array(features['actual'])
# features로 부터 label 컬럼 제거.
# axis 1 는 열을 의미. 'axis=0'은 행.
features= features.drop('actual', axis = 1)
# 나중에 사용하기 위해 features 이름 저장하기.
feature_list = list(features.columns)
# numpy array로 변환하기
features = np.array(features)
features
array([[2.016e+03, 1.000e+00, 1.000e+00, ..., 0.000e+00, 0.000e+00,
0.000e+00],
[2.016e+03, 1.000e+00, 2.000e+00, ..., 0.000e+00, 0.000e+00,
0.000e+00],
[2.016e+03, 1.000e+00, 3.000e+00, ..., 0.000e+00, 0.000e+00,
0.000e+00],
...,
[2.016e+03, 1.200e+01, 2.900e+01, ..., 1.000e+00, 0.000e+00,
0.000e+00],
[2.016e+03, 1.200e+01, 3.000e+01, ..., 0.000e+00, 0.000e+00,
0.000e+00],
[2.016e+03, 1.200e+01, 3.100e+01, ..., 0.000e+00, 0.000e+00,
0.000e+00]])
데이터 준비의 마지막 단계인 훈련&검증 셋으로 분할하는 작업
훈련을 하는 동안 모델이 정답을 보고 학습을하게 했으며, 이 예제와 같은 경우에는 실제 온도를 보고 학습하게 하여 features로 부터 온도를 예측해내는 방법을 갖게 할 수 있다.
모든 features와 label값 사이에는 어느정도 관계가 있을 것으로 예상하고, 모델은 훈련중에 이 관계에 대해 학습하는 것이다.
그런 다음 모델을 평가할 때가 되면, label값이 없게 만들어 놓은 검증 데이터 셋에서 예측을 하도록 요청하게 된다.
우리는 실제 답을 알고 있기 때문에 모델이 얼마나 정확한지 판단할 수 있다.
우리는 훈련/검증 셋은 랜덤으로 설정한다.
Skicit-learn을 사용해서 훈련데이터와 검증데이터셋으로 나눈다.
train_test_split를 사용하는데 여기서 순서대로 features와 label array를 입력해주고, test_size는 검증데이터의 비율이고, random_state는 랜덤을 42번 돌리겠다는 뜻이다.
from sklearn.model_selection import train_test_split
# 훈련/검증 셋으로 나누기
train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size = 0.25, random_state = 42)
열의 수가 일치하는지 확인한다.
print('Training Features Shape:', train_features.shape)
print('Training Labels Shape:', train_labels.shape)
print('Testing Features Shape:', test_features.shape)
print('Testing Labels Shape:', test_labels.shape)
Training Features Shape: (261, 14)
Training Labels Shape: (261,)
Testing Features Shape: (87, 14)
Testing Labels Shape: (87,)
train_features.shape
(261, 14)
test_features.shape
(87, 14)
정리
- 범주형 변수를 더미화 한다.(수치예측일 경우.)
- 데이터를 features와 label로 나누기.
- array로 변환 시키기.
- 훈련데이터와 검증데이터 셋으로 나누기.
초기 데이터셋에 따라 결측값을 상쇄할수도 있고, 특잇값을 제거할수도 있다. 시간 변수를 주기적인 표현으로 나타낼 수도 있다.
pd.DataFrame(test_features)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2016.0 | 9.0 | 29.0 | 69.0 | 68.0 | 66.1 | 57.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
1 | 2016.0 | 4.0 | 27.0 | 59.0 | 60.0 | 60.7 | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
2 | 2016.0 | 11.0 | 28.0 | 53.0 | 48.0 | 48.0 | 44.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
3 | 2016.0 | 10.0 | 12.0 | 60.0 | 62.0 | 61.0 | 52.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
4 | 2016.0 | 6.0 | 19.0 | 67.0 | 65.0 | 70.4 | 58.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
82 | 2016.0 | 6.0 | 4.0 | 71.0 | 80.0 | 67.9 | 76.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 |
83 | 2016.0 | 6.0 | 17.0 | 67.0 | 71.0 | 70.0 | 54.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
84 | 2016.0 | 10.0 | 5.0 | 61.0 | 63.0 | 63.7 | 48.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 |
85 | 2016.0 | 3.0 | 4.0 | 55.0 | 59.0 | 51.9 | 45.0 | 1.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
86 | 2016.0 | 12.0 | 22.0 | 51.0 | 49.0 | 45.1 | 38.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | 0.0 |
87 rows × 14 columns
feature_list.index('average')
5
baseline 확립하기.
명확하게 이해가 가는 건아니지만 이 파트를 하는 이유는 과거 온도 평균과 실제 값들에 대한 차이의 평균을 통해서 차이를 확인하고, 이를 개선할 수 있는 기준선을 만드는 정도로 이해하였다. 결과로는 5.06이 나왔기 때문에 우리가 후에 예측한게 이보다는 나아야한다...는 기준을 만든 것이라고 생각한다.
글쓴이도 평균 5도의 오차를 이기자는 식으로 말하고 있다. - -a
# The baseline predictions are the historical averages
baseline_preds = test_features[:, feature_list.index('average')]
# Baseline errors, and display average baseline error
baseline_errors = abs(baseline_preds - test_labels)
print('Average baseline error: ', round(np.mean(baseline_errors), 2))
Average baseline error: 5.06
모델 훈련하기
데이터 준비, 모델 생성, 훈련의 모든 작업이 끝나면 그 이후는 매우 간단하다.
skicit-learn에서 랜덤 포레스트 모델을 가져와서 모델을 인스턴스화하고 훈련데이터에 모델을 적합시킨다.
이 모든 과정은 단 3줄의 scikit-learn 으로 가능하다 !!
# 사용할 랜덤포레스트 모델을 불러오기.
from sklearn.ensemble import RandomForestRegressor
# 1000개의 결정트리를 가진 모델을 인스턴스화하기.
rf = RandomForestRegressor(n_estimators = 1000, random_state = 42)
# 트레이닝 데이터로 훈련시키기.
rf.fit(train_features, train_labels);
검증셋으로 예측값 만들기
# 검증 데이터를 만든 모델을 사용해서 예측하기.
predictions = rf.predict(test_features)
# 절대오차를 계산하기.
errors = abs(predictions - test_labels)
# Mean absolute error(MAE) 계산하기.
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
Mean Absolute Error: 3.83 degrees.
우리가 예측에 대한 평균 추정치는 3.83으로 약 1도의 MAE를 줄여버렸다 !
성능 매트릭스 선정하기
백분율로 정확도를 나타내보자 !
# Mean Absolut Percentage Error 계산하기.
mape = 100 * (errors / test_labels)
# 정확도를 구하고 나타내기.
accuracy = 100 - np.mean(mape)
print('Accuracy:', round(accuracy, 2), '%.')
Accuracy: 93.98 %.
94%의 정확도로 시애틀의 다음 날 최대 온도를 예측하는 방법을 배웠다.ㅎ
변수 중요도
모든 변수의 유의미한 정도를 상대적으로 비교한다. Skicit-learn을 계속 사용한다.
# 연속형 features의 중요도를 구하기.
importances = list(rf.feature_importances_)
# feature와 중요도를 튜플에 넣고 리스트에 넣음.
feature_importances = [(feature, round(importance, 2)) for feature, importance in zip(feature_list, importances)]
# 중요도 순으로 teature를 정렬.Sort the feature importances by most important first
feature_importances = sorted(feature_importances, key = lambda x: x[1], reverse = True)
# 중요도와 feature를 출력.
[print('Variable: {:20} Importance: {}'.format(*pair)) for pair in feature_importances];
Variable: temp_1 Importance: 0.69
Variable: average Importance: 0.2
Variable: day Importance: 0.03
Variable: friend Importance: 0.03
Variable: temp_2 Importance: 0.02
Variable: month Importance: 0.01
Variable: year Importance: 0.0
Variable: week_Fri Importance: 0.0
Variable: week_Mon Importance: 0.0
Variable: week_Sat Importance: 0.0
Variable: week_Sun Importance: 0.0
Variable: week_Thurs Importance: 0.0
Variable: week_Tues Importance: 0.0
Variable: week_Wed Importance: 0.0
가장 좋은 예측 변수로는 temp_1로 전날의 최대온도라는 것을 알 수 있다. 두번째는 과거 평균 최대 온도 이다. 친구는 주,일,연도,월,이틀전 기온과 함께 별로 도움이 되지 않는 것으로 밝혀졌다.
이러한 중요성은 month, year, day, week 는 날씨와 관계가 없기 때문에 이치에 맞다고 할 수 있다.
게다가 year의 경우 모든 데이터에 대해 연도가 같아서 예측할만한 정보를 제공하지도 못한다.
향후 모델 구현시, 중요하지 않고 성능이 저하되지 않는 변수들을 제거할 수 있다.
가장 중요한 변수로 확인된 temp_1과 average 변수를 사용하여 랜덤포레스트를 다시 만들어 보자.
# 두 중요 변수로 새로운 랜덤 포레스트 만들기.
rf_most_important = RandomForestRegressor(n_estimators= 1000, random_state=42)
# 중요 변수 두개 추출해오기.
important_indices = [feature_list.index('temp_1'), feature_list.index('average')]
train_important = train_features[:, important_indices]
test_important = test_features[:, important_indices]
# 랜덤포레스트 훈련.
rf_most_important.fit(train_important, train_labels)
# 예측하고 오차 구하기.
predictions = rf_most_important.predict(test_important)
errors = abs(predictions - test_labels)
# 성능측정
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
mape = np.mean(100 * (errors / test_labels))
accuracy = 100 - mape
print('Accuracy:', round(accuracy, 2), '%.')
Mean Absolute Error: 3.92 degrees.
Accuracy: 93.76 %.
이로써 정확한 예측을 위해 수집한 데이터 모두가 실제로는 필요하지 않다는 것을 말해준다 !. 이 모델을 계속 사용하게 되면 두 변수만 수집하고도 거의 같은 성능을 얻을 수 있을 것이다.
실제 환경에서 우리는 더 많은 정보를 얻기 위해 필요한 추가 시간과 정확도의 감소를 따져볼 필요가 있을 것이다. 성능과 비용 사이의 적절한 균형을 찾는 방법을 아는 것은 기계학습 엔지니어에게 필수적인 기술이며 궁극적으로 그 문제에 의존할 것이다.
reference:https://towardsdatascience.com/random-forest-in-python-24d0893d51c0
[
Random Forest in Python
A Practical End-to-End Machine Learning Example
towardsdatascience.com
](https://towardsdatascience.com/random-forest-in-python-24d0893d51c0)
'머신러닝' 카테고리의 다른 글
Nonparametric Method (0) | 2020.10.15 |
---|---|
회귀분석 with python (0) | 2020.03.21 |
엔트로피(Entropy) (0) | 2020.01.06 |
지니불순도(Gini impurity) (0) | 2020.01.06 |
군집분석 (0) | 2019.12.31 |
댓글