Created
January 17, 2015 09:34
-
-
Save neoneo40/6294bac4655f44aad81a to your computer and use it in GitHub Desktop.
kaggle_weather
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Kaggle.com | |
# Competition | |
# < Bike Sharing Demand > | |
# 세미나 시간 2시간 | |
# 일자 : 1월 17일 토요일 갱남. | |
# 문제푸는 시간. 캐글 소개, 문제 설명, 데이터 주고, 도전 | |
# 중간중간 미리 준비한 코드 보여주며 잡아주기. 전체 프로세스 경험 | |
# 1. 상황 파악하기(데이터셋 불러오기) | |
sample_submission = read.csv("sampleSubmission.csv", header = TRUE) | |
test = read.csv("test.csv", header = TRUE) | |
train = read.csv("train.csv", header = TRUE) | |
head(sample_submission, 20) # 제출 형식을 확인해봅시다. | |
head(train, 20) # 모델 생성 데이터셋을 확인해봅시다. | |
head(test, 20) # 검증 데이터셋을 확인해봅시다. | |
summary(train) | |
summary(test) | |
summary(sample_submission) | |
# 2. 목표 정하기 | |
# 우리가 예측해야 할 변수는? | |
head(sample_submission) | |
# count 입니다. | |
# 각 변수에 대한 이해! | |
# join $ -> take -> ride -> return | |
# datetime - hourly date + timestamp | |
# season - 1 = spring, 2 = summer, 3 = fall, 4 = winter | |
# holiday - whether the day is considered a holiday | |
# workingday - whether the day is neither a weekend nor holiday | |
# weather - 1: Clear, Few clouds, Partly cloudy | |
# 2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist | |
# 3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds | |
# 4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog | |
# temp - temperature in Celsius | |
# atemp - "feels like" temperature in Celsius | |
# humidity - relative humidity | |
# windspeed - wind speed | |
# casual - number of non-registered user rentals initiated | |
# registered - number of registered user rentals initiated | |
# count - number of total rentals | |
# 좀 더 알아보자 | |
sub_date = as.data.frame(substr(train[,"datetime"], 1, 10)) | |
sub_unique_date = unique(sub_date) | |
start_end = c(as.character(sub_unique_date[1,]), as.character(sub_unique_date[nrow(sub_unique_date),])) | |
start_end # 시작일, 종료일 확인 | |
difftime(sub_unique_date[nrow(sub_unique_date),1], sub_unique_date[1,1]) | |
nrow(sub_unique_date) # 시작과 끝의 차이는 718일, 보유 데이터 456일. 약 40%정도의 데이터가 없다. | |
nchar(as.character(train[1,1])) # 몇 글자로 시간이 표현되었는지 확인해봅시다. | |
train_sub_date = as.data.frame(substr(train[,1], 1, 10)) # 날짜 | |
train_sub_year = as.data.frame(as.numeric(substr(train[,1], 1, 4))) # 년도 | |
train_sub_month = as.data.frame(as.numeric(substr(train[,1], 6, 7))) # 월 | |
train_sub_day = as.data.frame(as.numeric(substr(train[,1], 9, 10))) # 일 | |
train_sub_hour = as.data.frame(as.numeric(substr(train[,1], 12, 13))) # 시간 | |
head(train_sub_date) # 시간 확인 ㄱㄱ | |
train_sub = cbind(train_sub_date, train_sub_year, train_sub_month, train_sub_day, train_sub_hour, train[,2:ncol(train)]) | |
head(train_sub) | |
colnames(train_sub) = c("date", "year", "month", "day", "hour", colnames(train_sub)[6:ncol(train_sub)]) # 이름 바꿔주기 | |
head(train_sub) | |
# 결측값에 대한 이해! | |
summary(train_sub) # 결측치(NA)가 없다. | |
year_unique = unique(train_sub$year) | |
month_unique = unique(train_sub$month) | |
year_unique | |
month_unique | |
table(train_sub$hour) # 시간 별로 숫자가 다름 -> 데이터가 조금씩 없음. | |
max(table(train_sub$hour)) # 최대값 = 456. 결측치가 없는 경우의 데이터 수량이 456일 수 있다. | |
# 데이터셋[ 열 번호 , 행 번호] | |
train_sub[1:24 , 1:4] | |
train_sub[25:35 , 1:4] # 다섯시의 데이터가 없다!! | |
# Calendar 붙이기 | |
# 2011년, 2012년 달력을 불러온다. | |
calendar = read.csv("2011_2012_calendar.csv", header = TRUE) | |
head(calendar) | |
calendar_2 = as.data.frame(matrix(NA, nrow=nrow(calendar)*24, ncol=ncol(calendar)+1)) | |
head(calendar_2) | |
# 0시 부터 23시 까지 숫자를 넣으면서 24배로 늘여야 한다. | |
matrix_hour = matrix(c(seq(0,23,1)), nrow=24, ncol=1) | |
for(n in 1:nrow(calendar)) | |
{ | |
if(n == 1) | |
{ | |
calendar_2[1:24,1:10] = calendar[1,] | |
calendar_2[1:24,11] = matrix_hour | |
} else { | |
calendar_2[(24*(n-1)+1):(24*n), 1:10] = calendar[n,] | |
calendar_2[(24*(n-1)+1):(24*n), 11] = matrix_hour | |
} | |
} | |
head(calendar_2) | |
fix(calendar_2) | |
colnames(calendar_2) = c("year", "month", "day", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", "hour") | |
head(calendar_2) | |
calendar_3 = calendar_2[,c(1,2,3,11,seq(4,10,1))] # 끝에 있던 "hour" column을 "day" 변수 뒤로 옮겨줍시다. | |
head(calendar_3) | |
# 데이터셋을 결합해봅시다. | |
# install.packages("plyr") | |
library("plyr") | |
head(train_sub) | |
head(calendar_3) # 공통되는 column을 확인. | |
train_calendar_join = join(calendar_3, train_sub, type = "left") | |
head(train_calendar_join, 50) # 30번째 row에 결측치(NA) 확인 가능 | |
fix(train_calendar_join) # 전체를 살펴보면서 다시 확인 | |
write.csv(train_calendar_join, "train_calendar_join.csv", row.names = FALSE) | |
# 이제 비어있는 결측치를 채워 넣어보자. | |
# Data Interpolation (Linear Interpolation) - sample | |
I_data = as.data.frame(matrix(c(1,2,3,4,5,6,3,NA,NA,10,2,NA,5,9,20), nrow = 5, ncol = 3)) | |
colnames(I_data) = c("obs", "trend", "sales") | |
head(I_data) | |
for(col_no in 2:ncol(I_data)) | |
{ | |
NA_count = 0 | |
for(row_no in 2:nrow(I_data)) | |
{ | |
value_check = I_data[row_no, col_no] | |
if(is.na(value_check)) | |
{ | |
NA_count = NA_count + 1 | |
if(NA_count == 1) | |
{ | |
value_prior = I_data[row_no-1, col_no] | |
} | |
} | |
value_later = value_check | |
if((is.na(I_data[row_no-1,col_no]) & (is.na(value_later) == FALSE))) | |
{ | |
print("====Doing Interpolation====") | |
print(paste0("row number : ", (row_no-NA_count), "~", (row_no-1), " column number : ", col_no)) | |
flush.console() | |
value_multi = (value_later - value_prior)/(NA_count+1) | |
for(Inter in 1:NA_count) | |
{ | |
I_data[(row_no-NA_count+Inter-1), col_no] = value_prior + value_multi*Inter | |
} | |
} | |
} | |
} | |
head(I_data) | |
# 이제 주어진 데이터에 대한 Interpolation을 수행하자. | |
########################################## | |
head(train_calendar_join) | |
# 변수명 : season | |
# 이 변수는 월별로 고정적인 값을 가질 수 있다. | |
# ex. 봄 3~5월 / 여름 6~8월 등 | |
# | |
# 특정 계절이 어떤 달이 포함되는지 알아보자. | |
# ※ 단순히 여름이 7~8월 언저리라고 단정하면 안되는 이유는, 이 데이터가 남반구의 것일 수 있다. | |
season_check = train_calendar_join[,c("month", "season")] | |
head(season_check) | |
table(season_check) # WOW! | |
# 이 경우는 위의 Interpolation 식을 사용 할 필요 없이 단순히 값을 대입해주면 된다. | |
test = train_calendar_join # 실수로 원 파일을 잘못 다룰 경우 앞의 코드를 다시 실행시켜야 되니 버퍼를 두자. | |
head(test) | |
table(test$season) # season = 1 의 개수를 잘 보자. | |
test[test$month == 3, "season"] = 1 | |
table(test$season) # season = 1 의 개수가 증가 하였는가!? | |
fix(test) # 스크롤을 내려보면서 확인해 보자. | |
# 이제 위 코드를 train_calendar_join에 적용해보자! | |
table(season_check) # 다시 확인. | |
for(month in 1:12) | |
{ | |
test[test$month == month, "season"] = ceiling(month/3) # 비슷한 함수 : round, floor | |
} | |
season_check_2 = test[,c("month", "season")] | |
table(season_check_2) | |
summary(season_check) | |
summary(season_check_2) # NA 개수 확인! | |
########################################## | |
head(train) | |
# 변수명 : holiday, workingday | |
# 공휴일에는 보통 일을 하지 않음으로 두 변수를 합칠 수 있을지도 모른다. | |
# ex. holiday = 1, workingday = 0 | |
# 일단 분포를 보자. | |
holi_work_sub = train_calendar_join[,c("holiday", "workingday")] | |
head(holi_work_sub) | |
summary(holi_work_sub) # 결측치 6000개 이상... | |
table(holi_work_sub) | |
# 여기서 결측치를 어찌 처리할까? | |
# holiday와 workingday는 1일(24시간) 단위로 정해지는 숫자이다. | |
head(train_calendar_join) | |
sub_mode = train_calendar_join[,c("date", "holiday", "workingday")] | |
head(sub_mode) | |
summary(sub_mode) | |
# install.packages("doBy") | |
library("doBy") | |
summary_days = summaryBy(holiday + workingday ~ date, data = sub_mode, FUN = c(max), na.rm = TRUE) | |
summary_days[(nrow(summary_days)-4):nrow(summary_days),] | |
summary_days = summary_days[1:(nrow(summary_days)-1),] | |
head(summary_days) | |
fix(summary_days) | |
summary_days = cbind(as.numeric(substr(summary_days$date, 1, 4)), as.numeric(substr(summary_days$date, 6, 7)), as.numeric(substr(summary_days$date, 9, 10)), summary_days[,2:3]) | |
colnames(summary_days) = c("year", "month", "day", "holiday_2", "workingday_2") | |
head(summary_days) | |
train_calendar_join = read.csv("train_calendar_join.csv", header = TRUE) | |
date_sub = train_calendar_join[,1:3] | |
head(date_sub) | |
date_days = join(date_sub, summary_days, type = "left") | |
head(date_days) | |
train_calendar_join[,c("holiday", "workingday")] = date_days[,4:5] | |
fix(train_calendar_join) | |
train_2 = train_calendar_join | |
train_2 = train_2[,-12] | |
head(train_2) | |
write.csv(train_2, "train_2.csv", row.names = FALSE) | |
############################################# | |
# 더 진행하기 전에 하루가 통째로 결측(NA)인 날은 날려버리자. | |
train_2 = train_2[is.na(train_2$holiday) == 0,] | |
fix(train_2) | |
########################################## | |
head(train_2) | |
# 변수명 : weather, temp, atemp | |
# Interpolation 수행, round 함수 사용 | |
# 추가작업 : 그래프 그려보기 | |
# Data Interpolation (Linear Interpolation) - weather, temp, atemp | |
colnames(train_2) | |
for(col_no in 15:17) | |
{ | |
NA_count = 0 | |
for(row_no in 2:nrow(train_2)) | |
{ | |
value_check = train_2[row_no, col_no] | |
if(is.na(value_check)) | |
{ | |
NA_count = NA_count + 1 | |
if(NA_count == 1) | |
{ | |
value_prior = train_2[row_no-1, col_no] | |
} | |
} | |
value_later = value_check | |
if((is.na(train_2[row_no-1,col_no]) & (is.na(value_later) == FALSE))) | |
{ | |
print("====Doing Interpolation====") | |
print(paste0("row number : ", (row_no-NA_count), "~", (row_no-1), " column number : ", col_no)) | |
flush.console() | |
value_multi = (value_later - value_prior)/(NA_count+1) | |
for(Inter in 1:NA_count) | |
{ | |
train_2[(row_no-NA_count+Inter-1), col_no] = value_prior + value_multi*Inter | |
} | |
} | |
} | |
} | |
head(train_2) | |
summary(train_2[15:19]) | |
train_3 = train_2[is.na(train_2$casual) == 0,] | |
plot(train_3$month, train_3$temp) | |
# 파생변수를 만들어보자! | |
# 습도가 높아도 바람이 많이 불면 나름 쾌적함 ㅇㅇ. 근데 겨울엔 좀 아님. | |
# 온도, 습도, 풍속을 고려하여 새로운 변수를 만들어보자. (1번) | |
# 사람들의 활동 시간대를 고려해보자. | |
# 0시부터 23시 까지 각각의 시각에 자전거를 많이 탈 것 같은 시간에 따라 | |
# 점수를 1점에서 10점까지 매겨봄. 식사시간, 운동시간 등등 고려하여 점수 부여. (2번) | |
########################################## | |
# 파생변수명 : factor_x | |
# 온도, 습도, 풍속을 고려하여 만드는 새로운 변수 | |
# 추가작업 : 그래프 그려보기 | |
ncol(train_3) | |
train_3[,23] = round(train_3$temp * (train_3$humidity*0.01) * train_3$windspeed, 3) | |
colnames(train_3) = c(colnames(train_3)[1:22], "factor_x") | |
head(train_3) | |
plot(train_3$hour, train_3$factor_x) | |
plot(train_3$month, train_3$factor_x) | |
plot(1:nrow(train_3), train_3$factor_x) | |
########################################## | |
# 파생변수명 : h_score | |
# 온도, 습도, 풍속을 고려하여 만드는 새로운 변수 | |
# 추가작업 : 그래프 그려보기 | |
# hour_score = as.data.frame(matrix(c(seq(0,23,1), c( 시간별 점수를 넣어주세요 )),nrow = 24, ncol = 2)) | |
# hour_score = as.data.frame(matrix(c(seq(0,23,1), c( ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, ■, )),nrow = 24, ncol = 2)) | |
hour_score = as.data.frame(matrix(c(seq(0,23,1), c( 1, 1, 1, 1, 3, 2, 4, 5, 2, 6, 7, 8, 3, 8, 9, 8, 7, 6, 3, 4, 5, 8, 4, 2)),nrow = 24, ncol = 2)) | |
colnames(hour_score) = c("hour", "h_score") | |
head(hour_score) | |
train_3_score_join = join(train_3, hour_score, by = "hour", type = "left") | |
head(train_3_score_join) | |
fix(train_3_score_join) | |
#install.packages("car") | |
library("car") | |
###################################### | |
# 회귀회귀 | |
lm_train = lm(count ~ season +holiday +workingday +weather +temp +atemp +humidity +windspeed +factor_x +h_score, data = train_3_score_join) | |
summary(lm_train) | |
vif(lm_train) | |
lm_train = lm(count ~ season +holiday +workingday +weather +temp +humidity +windspeed +factor_x +h_score, data = train_3_score_join) | |
summary(lm_train) | |
vif(lm_train) | |
###################################### | |
# 알고리즘에 의한 변수 제거 | |
step(lm_train, direction = "both") | |
lm_train_4 = lm(count ~ season + weather + temp + humidity + windspeed + factor_x + h_score, data = train_3_score_join) # <-- 수식을 입력하세요! | |
summary(lm_train_4) | |
vif(lm_train_4) | |
###################################### | |
# 회귀식으로 예측하기. | |
# train 데이터로 만든 회귀식으로 test 데이터의 결과를 예측 | |
# test = read.csv("test.csv", header = TRUE) | |
head(test) | |
summary(test) | |
test[,(ncol(test)+1)] = as.numeric(substr(test$date, 12,13)) | |
test[,(ncol(test)+1)] = test$temp * (test$humidity*0.01) * test$windspeed | |
colnames(test) | |
colnames(test) = c(colnames(test)[1:9], "hour", "factor_x") | |
colnames(test) | |
test_score_join = join(test, hour_score, by = "hour", type = "left") | |
head(test_score_join) | |
prediction = predict(lm_train_4, test_score_join) | |
head(prediction) | |
prediction = round(prediction,0) | |
head(prediction) | |
prediction_cbind = cbind(test$datetime, as.data.frame(prediction)) | |
head(prediction_cbind) | |
head(sample_submission) | |
colnames(prediction_cbind) = c("datetime", "count") | |
head(prediction_cbind) | |
###################################### | |
# 대망의 제출 파일 만들기!!! | |
write.csv(prediction_cbind, "submission.csv", row.names = FALSE) | |
# 제출!!! | |
# 그리고.. 끝없는 반복... | |
# 사실 개인적으로 제대로 분석을 한다면? | |
# 두 개의 모델을 합칠 것. | |
# | |
# casual - number of non-registered user rentals initiated | |
# registered - number of registered user rentals initiated | |
# count - number of total rentals | |
# | |
# count = casual + registered | |
# | |
# 즉, casual 값을 예측하기 위한 모델과 registered 값을 예측하기 위한 모델을 따로 만들어서 | |
# 그 결과 값을 더하여 submission 파일을 만들 것. | |
# 참고 | |
# assign(), get() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment