回帰分析をRで実施する。Bostonデータセットを使って実践。
その後、train、validation、testセットに分けて、MSEを計算する。
/**
* jQuery Plugin: Sticky Tabs
*
* @author Aidan Lister
* adapted by Ruben Arslan to activate parent tabs too
* http://www.aidanlister.com/2014/03/persisting-the-tab-state-in-bootstrap/
*/
(function($) {
"use strict";
$.fn.rmarkdownStickyTabs = function() {
var context = this;
// Show the tab corresponding with the hash in the URL, or the first tab
var showStuffFromHash = function() {
var hash = window.location.hash;
var selector = hash ? 'a[href="' + hash + '"]' : 'li.active > a';
var $selector = $(selector, context);
if($selector.data('toggle') === "tab") {
$selector.tab('show');
// walk up the ancestors of this element, show any hidden tabs
$selector.parents('.section.tabset').each(function(i, elm) {
var link = $('a[href="#' + $(elm).attr('id') + '"]');
if(link.data('toggle') === "tab") {
link.tab("show");
}
});
}
};
// Set the correct tab when the page loads
showStuffFromHash(context);
// Set the correct tab when a user uses their back/forward button
$(window).on('hashchange', function() {
showStuffFromHash(context);
});
// Change the URL when tabs are clicked
$('a', context).on('click', function(e) {
history.pushState(null, null, this.href);
showStuffFromHash(context);
});
return this;
};
}(jQuery));
window.buildTabsets = function(tocID) {
// build a tabset from a section div with the .tabset class
function buildTabset(tabset) {
// check for fade and pills options
var fade = tabset.hasClass("tabset-fade");
var pills = tabset.hasClass("tabset-pills");
var navClass = pills ? "nav-pills" : "nav-tabs";
// determine the heading level of the tabset and tabs
var match = tabset.attr('class').match(/level(\d) /);
if (match === null)
return;
var tabsetLevel = Number(match[1]);
var tabLevel = tabsetLevel + 1;
// find all subheadings immediately below
var tabs = tabset.find("div.section.level" + tabLevel);
if (!tabs.length)
return;
// create tablist and tab-content elements
var tabList = $('
');
$(tabs[0]).before(tabList);
var tabContent = $('
');
$(tabs[0]).before(tabContent);
// build the tabset
var activeTab = 0;
tabs.each(function(i) {
// get the tab div
var tab = $(tabs[i]);
// get the id then sanitize it for use with bootstrap tabs
var id = tab.attr('id');
// see if this is marked as the active tab
if (tab.hasClass('active'))
activeTab = i;
// remove any table of contents entries associated with
// this ID (since we'll be removing the heading element)
$("div#" + tocID + " li a[href='#" + id + "']").parent().remove();
// sanitize the id for use with bootstrap tabs
id = id.replace(/[.\/?&!#<>]/g, '').replace(/\s/g, '_');
tab.attr('id', id);
// get the heading element within it, grab it's text, then remove it
var heading = tab.find('h' + tabLevel + ':first');
var headingText = heading.html();
heading.remove();
// build and append the tab list item
var a = $('' + headingText + '');
a.attr('href', '#' + id);
a.attr('aria-controls', id);
var li = $('
');
li.append(a);
tabList.append(li);
// set it's attributes
tab.attr('role', 'tabpanel');
tab.addClass('tab-pane');
tab.addClass('tabbed-pane');
if (fade)
tab.addClass('fade');
// move it into the tab content div
tab.detach().appendTo(tabContent);
});
// set active tab
$(tabList.children('li')[activeTab]).addClass('active');
var active = $(tabContent.children('div.section')[activeTab]);
active.addClass('active');
if (fade)
active.addClass('in');
if (tabset.hasClass("tabset-sticky"))
tabset.rmarkdownStickyTabs();
}
// convert section divs with the .tabset class to tabsets
var tabsets = $("div.section.tabset");
tabsets.each(function(i) {
buildTabset($(tabsets[i]));
});
};
library(MASS) # Boston データセットを使う
library(tidyverse) # ggplot2とdiplyrを使う
線形回帰分析 Regression 重回帰・単回帰
以下の形で、回帰分析のオブジェクトを作る。
mylm <- lm(data=データフレーム, outcome ~ predictor_1 + predictor_2)
outcomeは目的変数y、predictor_1は説明変数1、predictor_2は説明変数2とする。
今回は、MASSの中にあるBostonデータセットを使用する。Bostonの中には、変数medv(median value of owner-occupied homes in $1000s)と変数lstat(lower status of the population (percent).)がある。
medvをyとして、lstatをxとして式を定義する。このときに、Boston\(medv ~ Boston\)lstat とすると、うまくいかない。
mylm <- lm(data=Boston, medv ~ lstat)
coef()を使うと、Interceptとcoefficientsを得ることができる。
coef(mylm)
## (Intercept) lstat
## 34.5538409 -0.9500494
summary() を使うと、Multiple R-squared、Adjusted R-squared、Intercept、coefficients等など、様々な情報を得ることができる。
summary(mylm)
##
## Call:
## lm(formula = medv ~ lstat, data = Boston)
##
## Residuals:
## Min 1Q Median 3Q Max
## -15.168 -3.990 -1.318 2.034 24.500
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 34.55384 0.56263 61.41 <2e-16 ***
## lstat -0.95005 0.03873 -24.53 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.216 on 504 degrees of freedom
## Multiple R-squared: 0.5441, Adjusted R-squared: 0.5432
## F-statistic: 601.6 on 1 and 504 DF, p-value: < 2.2e-16
predict()を使うと、さきほどの回帰分析のモデルを使って目的変数を予測することできる。
predict(回帰モデル,説明変数)
これで得られるものは、目的変数を予想したもの。 特に意味はないが、得られた回帰モデルを使って、説明変数から目的変数を予測してみる。
predicted_value <- predict(mylm,Boston[,13,drop=F])
head(predicted_value)
## 1 2 3 4 5 6
## 29.82260 25.87039 30.72514 31.76070 29.49008 29.60408
以下のように説明変数にdrop=Fが必要なのは、説明変数がデータフレームである必要があるから。 Boston$lstatだと、ベクターになってしまう。
新たな説明変数を使って、予測してみたい。列の名前は、モデルの説明変数の名前と同じにしなければならない。
pred_dat <- data.frame(seq(1, 40, length=1000))
names(pred_dat) <- "lstat"
y_pred_new <- predict(mylm, pred_dat)
head(y_pred_new)
## 1 2 3 4 5 6
## 33.60379 33.56670 33.52961 33.49252 33.45544 33.41835
95%信頼区間を得る方法。
y_pred_95 <- predict(mylm, newdata = pred_dat[,1,drop=F], interval = 'confidence')
head(y_pred_95)
## fit lwr upr
## 1 33.60379 32.56402 34.64356
## 2 33.56670 32.52947 34.60394
## 3 33.52961 32.49491 34.56432
## 4 33.49252 32.46035 34.52470
## 5 33.45544 32.42578 34.48509
## 6 33.41835 32.39122 34.44547
グラフにしたいので、説明変数の列を加える。
y_pred_95 <- predict(mylm, newdata = pred_dat[,1,drop=F], interval = 'confidence')
y_pred_95 <- data.frame(y_pred_95,pred_dat[,1,drop=F])
head(y_pred_95)
## fit lwr upr lstat
## 1 33.60379 32.56402 34.64356 1.000000
## 2 33.56670 32.52947 34.60394 1.039039
## 3 33.52961 32.49491 34.56432 1.078078
## 4 33.49252 32.46035 34.52470 1.117117
## 5 33.45544 32.42578 34.48509 1.156156
## 6 33.41835 32.39122 34.44547 1.195195
分かりやすいように名前を変える
names(y_pred_95) <- c("medv","lwr","upr","lstat")
ggplot() +
geom_ribbon(data=y_pred_95,aes(x=lstat,ymin=lwr,ymax=upr),color="blue",fill="blue") +
geom_point(data=Boston,aes(x=lstat,y=medv)) +
geom_line(data=y_pred_95,aes(x=lstat,y=medv),color="green") +
theme_classic()
MSE(Mean Squared Error)の関数を自作する。これは、予測値と実際の数値の違いを足し合わせたもの。
mse <- function(y_true, y_pred) {
vec_length = length(y_true)
mse_value =0
for (i in 1:vec_length){
mse_value = mse_value + (y_true[i]-y_pred[i])^2
}
mse_value = mse_value/vec_length
return(mse_value)
}
さきほど予測したmedvの値と、実際のmedvの値についてMSEを求める。
mse(Boston$medv,predicted_value)
## 1
## 38.48297
Bostonのデータセット502行を、 train データセット(5割)と、validationデータセット(3割)と、testデータセット(2割)に分別する。
splits <- c(rep("train",253),rep("validation",152),rep("test",101))
head(splits)
## [1] "train" "train" "train" "train" "train" "train"
Bostonのデータセットに、上で作った1列を追加する。名前は、boston_masterとする。
boston_master <- Boston %>%
mutate(splits=sample(splits))
boson_masterから、train,validation,test に分ける。
boston_train <- boston_master %>% filter(splits=="train")
boston_valid <- boston_master %>% filter(splits=="validation")
boston_test <- boston_master %>% filter(splits=="test")
trainセットのみで、regressionを学習させる。
model_1 <- lm(data=boston_train, medv~lstat)
summary(model_1)
##
## Call:
## lm(formula = medv ~ lstat, data = boston_train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -10.137 -4.350 -1.369 1.784 23.615
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 36.12775 0.81584 44.28 <2e-16 ***
## lstat -1.09719 0.05916 -18.55 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.363 on 251 degrees of freedom
## Multiple R-squared: 0.5781, Adjusted R-squared: 0.5765
## F-statistic: 344 on 1 and 251 DF, p-value: < 2.2e-16
train内のMSEを計算する。
pred_train <- predict(model_1,boston_train[,13,drop=F])
model_1_mse_train <- mse(boston_train$medv,pred_train)
model_1_mse_train
## 1
## 40.16525
trainで学習させたモデルを使って、validationを予測する。そして、MSEを計算する。
pred_valid <- predict(model_1, boston_valid[,13,drop=F])
model_1_mse_valid <- mse(boston_valid$medv,pred_valid)
model_1_mse_valid
## 1
## 33.58956
他の数式を使って、regressionを学習させる。
model_2 <- lm(data=boston_train, medv~age+tax)
pred_train2 <- predict(model_2,boston_train[,c(7,10),drop=F])
model_2_mse_train <- mse(boston_train$medv,pred_train2)
print(paste("model_2_mse_train:",as.character(model_2_mse_train)))
## [1] "model_2_mse_train: 75.5125419055823"
pred_valid2 <- predict(model_2,boston_valid[,c(7,10),drop=F])
model_2_mse_valid <- mse(boston_valid$medv,pred_valid2)
print(paste("model_2_mse_valid:",as.character(model_2_mse_valid)))
## [1] "model_2_mse_valid: 40.5666012367619"
数式によるMSEの比較してみる。
print(paste("model_1_mse_train:",as.character(model_1_mse_train)))
## [1] "model_1_mse_train: 40.1652537382155"
print(paste("model_1_mse_valid:",as.character(model_1_mse_valid)))
## [1] "model_1_mse_valid: 33.5895601321273"
print(paste("model_2_mse_train:",as.character(model_2_mse_train)))
## [1] "model_2_mse_train: 75.5125419055823"
print(paste("model_2_mse_valid:",as.character(model_2_mse_valid)))
## [1] "model_2_mse_valid: 40.5666012367619"
MSEはモデル1の方がモデル2よりも低かったので、モデル1を選択する。
今度は、最終的にtestセットでMSEを計算する。
pred_test <- predict(model_1,boston_test[,13,drop=F])
model_1_mse_test <- mse(boston_test$medv,pred_test)
print(paste("model_1_mse_test:",as.character(model_1_mse_test)))
## [1] "model_1_mse_test: 47.5681944974811"
K-fold cross validationをRで実装する。
kfold_validate <- function(formula,dataset,k){
if (k>1){
d_length <- nrow(dataset)
indexs <- rep(1:k, length.out = d_length)
indexs <- data.frame(indexs)
names(indexs) <- "indexs"
outcome <- all.vars(formula)[1]
predictors <- all.vars(formula)[-1]
MSE_value = 0
for (i in 1:k){
new_data <- cbind(dataset,indexs)
dataset_train <- new_data %>% filter(indexs != i)
dataset_valid <- new_data %>% filter(indexs == i)
mylm <- lm(data = dataset_train,formula)
pred <- predict(mylm,dataset_valid[,predictors])
MSE_value = MSE_value + mse(dataset_valid[,outcome],pred)
}
}else{
print("k should be higher 1")
}
return(MSE_value/k)
}
解説 outcome <- all.vars(formula)[1] predictors <- all.vars(formula)[-1]
は、以下の式から左辺と右辺をとりだしている。 formula <- outcome ~ predictor_1 + predictor_2
dataset_valid[,outcome] は、上記の左辺と同じ列を取り出している。
dataset_valid[,predictors] は、上記の右辺と同じ列を取り出している。
試しに、9-fold cross validationを実行してみる。下のように、2つのモデルを比べてみる。 medv ~ lstat + age + tax medv ~ lstat + I(lstat^2) + age + tax
boston_train_validation <- boston_master %>% filter(splits=="train"|splits=="validation")
formula1 <- medv ~ lstat +age +tax
results1 <- kfold_validate(formula1,boston_train_validation,9)
print(paste("MSE_k-fold cross-validation by formula1:",results1))
## [1] "MSE_k-fold cross-validation by formula1: 36.4827657175701"
mylm <- lm(data = boston_test,formula1)
pred <- predict(mylm,boston_test[,c("lstat","age","tax")])
print(paste("MSE test set by formula1:",mse(boston_test[,"medv"],pred)))
## [1] "MSE test set by formula1: 40.4491711116041"
formula2 <- medv ~ lstat + I(lstat^2) + age + tax
results2 <- kfold_validate(formula2,boston_train_validation,9)
print(paste("MSE_k-fold cross-validation by formula2:",results2))
## [1] "MSE_k-fold cross-validation by formula2: 28.1007057996556"
mylm <- lm(data = boston_test,formula2)
pred <- predict(mylm,boston_test[,c("lstat","age","tax")])
print(paste("MSE test set by formula2:",mse(boston_test[,"medv"],pred)))
## [1] "MSE test set by formula2: 26.3088757875499"
Formula 2 のほうがMSE的にいいスコアを出した。
// add bootstrap table styles to pandoc tables
function bootstrapStylePandocTables() {
$('tr.odd').parent('tbody').parent('table').addClass('table table-condensed');
}
$(document).ready(function () {
bootstrapStylePandocTables();
});