이제 사이킷런 패키지의 선형 회귀를 수행해봅시다.
👨🏫 모듈을 불러옴. 패키지들을 이용해서 선형회귀 가능.
from sklearn.model_selection import train_test_split
# train_data와 test_data를 나누기 위한 함수.
# 어떤 데이터가 하나의 파일에 몰려있으면 train과 test 데이터 나누기
from sklearn.linear_model import LinearRegression
# linear_model은 선형회귀를 학습하기 위한 함수.
👨🏫이전까지는 bike_df라는 이름으로 불러와서 저장했었으나,
이번에는 데이터를 train 이라는 이름으로 불러오겠습니다. 그리고 parse_dates=["datetime"] 이라고 해주시면, 자동으로 데이터에서 날짜 부분을 datetime 타입으로 변환해줍니다. (자료형으로 바꿔줘야만 년월일시 각각 열을 바로바로 만들수 있다.)
굳이 apply(pd.to_datetime) 이런 함수를 쓰지않아도, 바로 변환해서 불러온다는 것이죠!
데이터 불러오기
# 데이터 불러오기
train = pd.read_csv('https://raw.githubusercontent.com/jesford/bike-sharing/master/train.csv', parse_dates=["datetime"])
새로 불러왔으니, year, month, day, hour 열을 다시 만들어줍시다!
# year, month, day, hour 생성
train["year"] = train["datetime"].dt.year
train["month"] = train["datetime"].dt.month
train["day"] = train["datetime"].dt.day
train["hour"] = train["datetime"].dt.hour
- 그리고 이미 datetime 열에 있는 것은 나누어서 year, month, day, hour 로 담아놓았으니, 굳이 남겨둘 필요없이 삭제해줍시다.
- 그리고 casual, registered 는 더하면 count 값이 바로 나오기 때문에, 해당 열을 사용하게 되면 그건 예측이 아니겠죠? 그럼 해당 열들도 삭제해줍시다.
# 필요없는 열 삭제에는 .drop 사용, axis는 이 3개의 열들을 삭제하겠다는 것.
drop_columns = ['datetime', 'casual', 'registered']
train.drop(drop_columns, axis=1, inplace=True)
👨🏫
inplace=True는 train 자체를 변형시키는 것. 이것이 없으면,drop한 거를 어딘가에 변수에 저장해야만 반영되는 것이고, 이게 있으면 굳이 어떤 변수에 저장하지 않아도 그냥 train 자체에서 바로 드롭된다.
그 후 훈련 데이터와 레이블(예측 대상 값)을 분리하는 작업을 수행합니다.
y_target = train['count']
x_features = train.drop(['count'], axis=1, inplace=False)
👨🏫 예측을 하기 위한 값들에는
count대여량은 필요없으니깐 train data에서 삭제한다. 대여량을 제외한 나머지 값들을 이용해서 예측하는 것이기 때문에drop하는 것이다.
훈련 데이터를 테스트 데이터로 7:3으로 분리합니다. 이는 사이킷런에서 제공하는 train_test_split() 함수를 통해 가능합니다. test_size = .3을 기재하면 테스트 데이터를 전체 데이터에서 30%로 분리합니다.
random_state 는 데이터를 섞어주는 역할을 합니다!
x_train, x_test, y_train, y_test = train_test_split(x_features, y_target, test_size = .3, random_state=777)
👨🏫 섞어주는 이유, 섞어주지 않으면 데이터가 있는 순서대로 훈련데이터와 테스트 데이터를 나누는데,
만약에 순서를 딱 봤는데 앞 순서에는 대여량이 엄청 낮은 데이터들만 몰려있으면 정확한 예측이 안된다. 섞어서 순서상으로 데이터들이 골고루 분포되게random_state를 쓴다.
선형 회귀를 학습하고, 모델을 평가합니다.
lr = LinearRegression()
lr.fit(x_train, y_train)
pred = lr.predict(x_test)
calculate_model_score(y_test, pred)
>>>>> 결과 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
RMSLE: 1.157, RMSE: 143.207
👨🏫
- 객체를 선언해 주고, 객체안에 있는 함수인
fit()이라는 학습을 시키기 위한 함수를 사용해서train_data를 넣어주면, 이 데이터를 토대로가중치도 찾고,편향도 찾을 것임.- 그 값들을 찾아서 저장해놓고, predict()를 쓰면 위 두줄의 이 학습하면서 구한 가중치와 편향을 이용해서
x_test들어간 값에 대한 예측치를 출력해준다. 저장을 하는 것.pred라는 값에.- 그 뒤에는 우리가 가지고 있는 실제 이 데이터
y_test와 그 예측값pred를 넣어주면, 이것을 토대로RMSLE와RMSE를 구할 수 있다. = 오차값을 구할 수 있다.
RMSLE는 1.157, RMSE의 경우 143.207이 나왔습니다. 이 두 값이 더 낮을 수록 더 좋은 모델입니다. 저 두 값을 낮추기 위해서 몇 가지 트릭을 추가로 사용해봅시다.
👨🏫 어떻게 보면 최대한 이 값을 낮출수있을때까지 낮추는 것이 모델을 만드는 사람의 역할이다.
앞서 예측 대상이 되는 값의 경우에는 정규 분포를 가지도록 하는 것이 좋다고 언급한 바 있습니다. 탐색적 데이터 분석 과정에서 했었던 전처리를 적용하여 모델을 재학습시켜봅시다.
np.log1p 을 써서 정규분포화# 이를 적용하여 다시 학습 후 평가 필요
y_log_transform = np.log1p(y_target)
# 데이터가 바뀌었으므로 훈련 데이터와 테스트 데이터를 다시 분리
x_train, x_test, y_train, y_test = train_test_split(x_features, y_log_transform,
test_size = .3,
random_state = 777)
👨🏫
- train,test data는 원래 기존에 우리가 사용하고자하는 데이터가 바뀌었으면 그때그때마다 나눠줘야 되는 거다. 그래서 데이터를 분리해줬고, 그 아래에서 마찬가지로 선형 회귀를 씀.
lr안에 있는 함수를 이용해서 학습시켜주고, 여기서predict()를 쓰면 예측값 구할수 있다. 그래서 test data에 대한 예측값을pred라는 이름으로 저장해놓음.- y를 다 로그화해놨는데 오차를 계산할 꺼면 실제 y랑 예측한 y를 이용해서 오차를 구하는 건데. 이미 로그화를 되어있는 것을 토대로 구해버리면 당연히 그 오차는 엄청 작아진다.
- 원래 값으로 되돌린 상태에서 오차를 구해야 정확한 평가지표가 되기때문에 y값을 평가하기 위해
expm1을 이용함.
선형 회귀를 학습합니다.
lr = LinearRegression()
lr.fit(x_train, y_train)
pred = lr.predict(x_test)
주의할 점은 타겟값을 로그를 씌워줬던 것은 다시 점수를 계산해주기 전에 돌려놔야 한다는 것입니다.
# 로그 변환 된건 다시 expm1 이용
y_test_exp = np.expm1(y_test)
pred_exp = np.expm1(pred)
calculate_model_score(y_test_exp, pred_exp)
>>>>>>>>>>>>> 실행 >>>>>>>>>>>>>>
```python
RMSLE: 1.011, RMSE: 162.942
타겟값에 대해서 정규화를 해주었더니 RMSLE 값은 감소한 반면, RMSE 값은 오히려 증가하였습니다. 사실 아직 모델을 위해 해야할 일들이 남아있습니다. 그 중 하나는 범주형 변수에 대한 전처리입니다.
여기서 어떻게 하면 더 줄일지 다음시간에 배우기
[코드스니펫] RMSLE, RMSE 둘 다 계산하는 함수
from sklearn.metrics import mean_squared_error
def rmsle(y, pred):
# y : 전체 데이터의 실제값의 리스트 ex) [1, 2, 3, 4]
# pred : 전체 데이터의 예측값의 리스트 ex) [0.97, 1.85, 2.99, 3.87]
# np.log1p : 입력값에 +1을 한 후 log를 씌운다.
log_y = np.log1p(y)
log_pred = np.log1p(pred)
# 실제값과 예측값의의 차이의 제곱
squared_error = (log_y - log_pred) ** 2
# 모든 데이터에 대해 평균을 구한 후(np.mean())
# 루트를 씌워준다(np.sqrt())
rmsle = np.sqrt(np.mean(squared_error))
return rmsle
def rmse(y, pred):
# 평균 제곱 오차, MSE에 루트를 씌운다.
return np.sqrt(mean_squared_error(y, pred))
# RMSLE, RMSE 계산
def calculate_model_score(y, pred):
rmsle_value = rmsle(y, pred)
rmse_value = rmse(y, pred)
print(f'RMSLE: {rmsle_value:.3f}, RMSE: {rmse_value:.3f}')