실기
연습 화면을 불러오는 중…
연습 화면을 불러오는 중…
Python으로 준비하는 실기
코딩이 처음이라면 한 줄 실행부터.
설명 옆에서 직접 써 보고, 결과를 확인하며 배웁니다.
설치·가입 없이 이 화면에서 실행
코드를 실행해 안녕하세요를 출력해요.
처음 보는 코드를 읽고, 오류 메시지를 읽고, 짧은 코드를 스스로 고칠 수 있다.
표에서 원하는 숫자 하나를 뽑아내는 길을 스스로 찾을 수 있다.
전처리 조건을 그대로 코드로 옮겨, 문제가 요구한 자리수로 값을 낼 수 있다.
학습 데이터로 모델을 만들고 평가 데이터의 예측을 규격에 맞는 CSV 로 낼 수 있다.
검정통계량과 p-value 를 구하고 그 결과를 과장 없이 문장으로 옮길 수 있다.
도움말과 파일을 확인하며 혼자 문제를 풀고 제출할 수 있다.
배운 내용을 실전으로
train.csv 는 한 시간에 한 줄인 자전거 대여 기록 3,000건과 그 시간의 비회원 대여 건수 casual 이고, test.csv 는 casual 이 없는 800건이다.
season·month·hour·holiday·weekday·workingday·weather 는 범주와 시각을 나타내는 정수이고, temp_c·feel_c·humidity·windspeed 는 실제 단위로 바꾼 측정값이다. 결측은 없다.
casual 은 한산한 새벽에 0 이고 붐비는 오후에는 300 을 넘는다. 평가 자료 800건 중 72건이 0 이다.
test.csv 의 각 행에 대해 casual 을 예측하고, pred 열 하나만 가진 result.csv 로 현재 폴더에 저장한다. 행은 test.csv 와 같은 순서로 800개이며, 자동 생성되는 index 열이 있으면 안 된다.
제출하면 앱이 형식을 검사한 뒤 RMSLE 를 계산한다. 낮을수록 좋은 지표이고, 절대 오차가 아니라 대략의 비율을 잰다.
예측 대상이 대여 건수이므로 이 문항은 0 이상의 값만 받는다. 음수를 0 으로 고쳐 주지 않고 몇 번째 행인지와 함께 형식 오류로 돌려보낸다.
train['casual'].describe() 로 최솟값·중앙값·최댓값의 차이를 본다. 0 과 300 이 한 열에 있으면 절대 오차를 재는 RMSE 는 붐비는 시간대의 오차에 눌려 한산한 시간대를 거의 보지 않는다.np.log1p(train['casual']) 로 학습한다. 평가가 로그 눈금에서 이뤄지므로 학습도 같은 눈금에서 하면 모형이 줄이려는 것과 채점이 재는 것이 일치한다.id 는 행에 붙인 번호다. 넣으면 모형이 그 번호와 정답 사이의 우연한 관계를 외워, 학습 자료에서만 좋아 보인다.np.expm1 은 log1p 의 정확한 역함수다. 되돌리지 않고 제출하면 로그 값을 건수라고 낸 것이라 지표가 크게 나빠진다 — 형식은 통과하므로 숫자를 보기 전까지 모른다.pred.min() 을 한 번 찍어 본다. 이 문항은 건수를 예측하므로 0 이상만 받고, 음수가 하나라도 있으면 앱이 그 행 번호와 함께 돌려보낸다. 저장은 pd.DataFrame({'pred': pred}).to_csv('result.csv', index=False) 이고 행 순서가 평가 자료와 같아야 한다.import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
features = [column for column in test.columns if column != 'id']
# RMSLE 는 log1p 위에서 재는 지표다. 타깃도 같은 눈금으로 옮겨 학습하면
# 모형이 "몇 건 틀렸나" 가 아니라 "몇 배 틀렸나" 를 줄이게 된다.
model = RandomForestRegressor(n_estimators=200, random_state=42)
model.fit(train[features], np.log1p(train['casual']))
# expm1 은 log1p 의 정확한 역함수다. 되돌리지 않으면 로그 값을 건수라고 낸 셈이 된다.
pred = np.expm1(model.predict(test[features]))
pd.DataFrame({'pred': pred}).to_csv('result.csv', index=False)RMSLE 는 sqrt(mean((log1p(정답) - log1p(예측))²)) 이다 — scikit-learn 의 root_mean_squared_log_error 와 같은 식이고, 그 함수도 root_mean_squared_error(log1p(y), log1p(ŷ)) 로 구현돼 있다. 로그를 씌우면 대략의 비율을 재게 된다. 큰 값에서 난 오차 하나가 한산한 시간대의 오차를 덮지 않으므로, 0 이 섞이고 크기가 수백 배 차이 나는 이 자료에 맞다. "비율" 은 근사다 — +1 때문에 3건을 6건으로 틀린 벌점(ln(7/4) = 0.5596)과 300건을 600건으로 틀린 벌점(ln(601/301) = 0.6915)이 정확히 같지는 않고, 값이 커질수록 진짜 비율에 가까워진다. 타깃에 log1p 를 씌워 학습하고 expm1 로 되돌리는 것이 이 지표를 겨냥한 풀이다 — 이 기준 풀이의 RMSLE 는 약 0.5562 이고, 같은 모형을 원 타깃으로 학습하면 0.6077 로 나빠진다. log1p 는 log(1 + x) 를 정확하게 계산하는 함수이고 log1p(0) = 0 이라, 0 인 시간대를 버리거나 1 을 더해 얼버무리지 않아도 된다. 선형회귀처럼 음수를 낼 수 있는 모형을 쓰면 형식 검사에서 막힌다. 지표가 음수를 계산하지 못해서가 아니라 — RMSLE 자체는 -1 초과 구간에서 계산된다 — 이 문항이 예측하는 것이 건수라서 0 미만은 답이 될 수 없기 때문이다. 앱은 음수를 0 으로 고쳐 주지 않는다.
-1 초과 구간에서는 값이 나온다. 걸리는 이유는 이 문항이 건수를 묻기 때문이다. 앱은 음수를 0 으로 고쳐 주지 않는다 — 고쳐 주면 모형이 음수를 낸다는 사실이 가려지고, 시험장에서 같은 제출을 또 내게 된다.