| title:機械学習 |
| output: 田中ツヨキ |
| date: “2023-12-08” |
d0 <- read.csv(file = 'https://stats.dip.jp/01_ds/data/titanic_data_jp.csv')
library(DT)
datatable(d0)
d0$生死 <- ifelse (d0$生死== '生存',1 ,0 )
summary(d0)
## 乗船番号 生死 客室等級 名前
## Length:714 Min. :0.0000 Length:714 Length:714
## Class :character 1st Qu.:0.0000 Class :character Class :character
## Mode :character Median :0.0000 Mode :character Mode :character
## Mean :0.4062
## 3rd Qu.:1.0000
## Max. :1.0000
## 性別 年齢 兄弟配偶者数 親子数
## Length:714 Min. : 0.42 Min. :0.0000 Min. :0.0000
## Class :character 1st Qu.:20.12 1st Qu.:0.0000 1st Qu.:0.0000
## Mode :character Median :28.00 Median :0.0000 Median :0.0000
## Mean :29.70 Mean :0.5126 Mean :0.4314
## 3rd Qu.:38.00 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. :80.00 Max. :5.0000 Max. :6.0000
## 運賃 乗船地
## Min. : 0.00 Length:714
## 1st Qu.: 8.05 Class :character
## Median : 15.74 Mode :character
## Mean : 34.69
## 3rd Qu.: 33.38
## Max. :512.33
head(d0)
## 乗船番号 生死 客室等級 名前 性別 年齢 兄弟配偶者数 親子数 運賃 乗船地
## 1 No.1 0 3等 Braund 男性 22 1 0 7.2500 S
## 2 No.2 1 1等 Cumings 女性 38 1 0 71.2833 C
## 3 No.3 1 3等 Heikkinen 女性 26 0 0 7.9250 S
## 4 No.4 1 1等 Futrelle 女性 35 1 0 53.1000 S
## 5 No.5 0 3等 Allen 男性 35 0 0 8.0500 S
## 6 No.7 0 1等 McCarthy 男性 54 0 0 51.8625 S
tail(d0)
## 乗船番号 生死 客室等級 名前 性別 年齢 兄弟配偶者数 親子数 運賃 乗船地
## 709 No.885 0 3等 Sutehall 男性 25 0 0 7.050 S
## 710 No.886 0 3等 Rice 女性 39 0 5 29.125 Q
## 711 No.887 0 2等 Montvila 男性 27 0 0 13.000 S
## 712 No.888 1 1等 Graham 女性 19 0 0 30.000 S
## 713 No.890 1 1等 Behr 男性 26 0 0 30.000 C
## 714 No.891 0 3等 Dooley 男性 32 0 0 7.750 Q
(n <- nrow(d0))
## [1] 714
set.seed(5)
ii <- sample(x = 1:n, size = floor(0.8 * n))
d.tr <- d0[ ii, ]
d.te <- d0[-ii, ]
(n.tr <- nrow(d.tr))
## [1] 571
(n.te <- nrow(d.te))
## [1] 143
fit.all <- glm(生死~客室等級+ 性別+ 年齢+ 兄弟配偶者数+ 親子数+ 運賃+ 乗船地, data = d.tr, family = 'binomial')
summary(fit.all)
##
## Call:
## glm(formula = 生死 ~ 客室等級 + 性別 + 年齢 + 兄弟配偶者数 +
## 親子数 + 運賃 + 乗船地, family = "binomial", data = d.tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.6437 -0.6306 -0.3804 0.6662 2.4121
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 17.215715 605.555989 0.028 0.9773
## 客室等級2等 -1.540699 0.381403 -4.040 5.36e-05 ***
## 客室等級3等 -2.721618 0.398577 -6.828 8.59e-12 ***
## 性別男性 -2.512823 0.245347 -10.242 < 2e-16 ***
## 年齢 -0.046152 0.009290 -4.968 6.76e-07 ***
## 兄弟配偶者数 -0.353650 0.138036 -2.562 0.0104 *
## 親子数 -0.044062 0.139460 -0.316 0.7520
## 運賃 -0.003207 0.003342 -0.960 0.3372
## 乗船地C -12.272960 605.555797 -0.020 0.9838
## 乗船地Q -13.069235 605.556026 -0.022 0.9828
## 乗船地S -12.731745 605.555772 -0.021 0.9832
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 774.32 on 570 degrees of freedom
## Residual deviance: 519.84 on 560 degrees of freedom
## AIC: 541.84
##
## Number of Fisher Scoring iterations: 13
fit <- glm(生死 ~ 客室等級 + 性別 + 年齢 + 兄弟配偶者数, data = d.tr, family = 'binomial')
summary(fit)
##
## Call:
## glm(formula = 生死 ~ 客室等級 + 性別 + 年齢 + 兄弟配偶者数,
## family = "binomial", data = d.tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.7973 -0.6277 -0.3904 0.6724 2.3959
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 4.389219 0.504021 8.708 < 2e-16 ***
## 客室等級2等 -1.508696 0.318108 -4.743 2.11e-06 ***
## 客室等級3等 -2.651199 0.313919 -8.445 < 2e-16 ***
## 性別男性 -2.480583 0.235670 -10.526 < 2e-16 ***
## 年齢 -0.045982 0.009104 -5.051 4.40e-07 ***
## 兄弟配偶者数 -0.405085 0.129990 -3.116 0.00183 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 774.32 on 570 degrees of freedom
## Residual deviance: 523.85 on 565 degrees of freedom
## AIC: 535.85
##
## Number of Fisher Scoring iterations: 5
fit <- glm(生死 ~ 客室等級 + 性別 + 年齢, data = d.tr, family = 'binomial')
summary(fit)
##
## Call:
## glm(formula = 生死 ~ 客室等級 + 性別 + 年齢, family = "binomial",
## data = d.tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.7089 -0.6917 -0.4177 0.7013 2.4047
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.716434 0.437531 8.494 < 2e-16 ***
## 客室等級2等 -1.360400 0.307460 -4.425 9.66e-06 ***
## 客室等級3等 -2.557113 0.307238 -8.323 < 2e-16 ***
## 性別男性 -2.347847 0.225497 -10.412 < 2e-16 ***
## 年齢 -0.036569 0.008345 -4.382 1.18e-05 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 774.32 on 570 degrees of freedom
## Residual deviance: 534.59 on 566 degrees of freedom
## AIC: 544.59
##
## Number of Fisher Scoring iterations: 4
d.new <- data.frame(客室等級 = '2等', 年齢 = 45, 性別 = '女性')
p.hat <- predict(fit, type = 'response', newdata = d.new)
sprintf('生存確率:%2.1f%', p.hat * 100)
## [1] "生存確率:67.0%"
p.hat <- predict(fit, type = 'response', newdata = d.te)
threshold <- 0.5
is.pred <- p.hat > threshold
is.ref <- d.te$生死 == 1
table(予測値 = is.pred, 真値 = is.ref)
## 真値
## 予測値 FALSE TRUE
## FALSE 77 9
## TRUE 12 45
is.ok <- is.pred == is.ref
n.ok <- sum(is.ok)
sprintf('生存予測精度:%2.1f%', n.ok / nrow(d.te) * 100)
## [1] "生存予測精度:85.3%"
library(caret)
## 要求されたパッケージ ggplot2 をロード中です
## 要求されたパッケージ lattice をロード中です
confusionMatrix(data = as.factor(is.pred),
reference = as.factor(is.ref))
## Confusion Matrix and Statistics
##
## Reference
## Prediction FALSE TRUE
## FALSE 77 9
## TRUE 12 45
##
## Accuracy : 0.8531
## 95% CI : (0.7843, 0.9067)
## No Information Rate : 0.6224
## P-Value [Acc > NIR] : 1.037e-09
##
## Kappa : 0.691
##
## Mcnemar's Test P-Value : 0.6625
##
## Sensitivity : 0.8652
## Specificity : 0.8333
## Pos Pred Value : 0.8953
## Neg Pred Value : 0.7895
## Prevalence : 0.6224
## Detection Rate : 0.5385
## Detection Prevalence : 0.6014
## Balanced Accuracy : 0.8493
##
## 'Positive' Class : FALSE
##
library(pROC)
## Type 'citation("pROC")' for a citation.
##
## 次のパッケージを付け加えます: 'pROC'
## 以下のオブジェクトは 'package:stats' からマスクされています:
##
## cov, smooth, var
roc1 <- roc(response = d.te$生死, predict = p.hat,
plot = T, print.auc = T, grid = T, ci = T, auc.polygon=T)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases

coords(roc1, 'best')
## threshold specificity sensitivity
## 1 0.4505387 0.8539326 0.8518519
c <- coords(roc1)
library(DT)
datatable(round(c, 3))
d <- read.csv(file = 'https://stats.dip.jp/01_ds/data/univ_exam_data.csv')
library(DT)
datatable(d, caption = '勉強時間と大学合否')
fit <- glm(合格 ~ 勉強時間, data = d, family = 'binomial')
#summary(fit)
library(sjPlot)
tab_model(fit, show.aic = T)
|
|
合格
|
|
Predictors
|
Odds Ratios
|
CI
|
p
|
|
(Intercept)
|
0.06
|
0.00 – 0.51
|
0.029
|
|
勉強時間
|
1.94
|
1.25 – 3.86
|
0.015
|
|
Observations
|
20
|
|
R2 Tjur
|
0.446
|
|
AIC
|
21.662
|
x <- d$勉強時間
y <- d$合格
matplot(x = x, y = y, pch = 1,
ylim = c(0, 1.1), xlim = c(0, 10),
main = 'ロジスティック回帰分析',
xlab = '平均勉強時間',
ylab = '合格(1),不合格(0)')
grid()
xp <- seq(0, 10, 0.1)
yp <- predict(fit, type = 'response', newdata = data.frame(勉強時間 = xp))
matlines(x = xp, y = yp, lty = 1, col = 2, lwd = 2)
library(latex2exp)
text(x = 3.8, y = 0.4, adj = 0,
TeX('$\\leftarrow \\hat{p}=\\frac{1}{1+exp\\{-(b_0 + b_1 x)\\}}$'))
legend('topleft', pch = c(1, NA), lty = c(NA, 1), col = c(1, 2),legend = c('合格(1),不合格(0)', 'ロジスティック回帰モデル'))

yp <- predict(fit, type = 'response', newdata = data.frame(勉強時間 = 5.5))
sprintf('合格確率:%2.1f%', yp * 100)
## [1] "合格確率:70.9%"
d <- read.csv(file = 'https://stats.dip.jp/01_ds/data/gender.csv')
library(DT)
datatable(d, caption = '性別データ')
d$性別 <- ifelse(d$性別 == '男性', 1, 0)
set.seed(1) # 乱数シード
n <- 100000 # データサイズ
# 正常値
rv <- runif(n = n, min = 0, max = 1) # 一様乱数
# 異常値1(負の値)
size <- 3 # ランダムサンプルサイズ
ii <- sample(n, size) # インデックスランダムサンプル
rv[ii] <- runif(n = size, min = -1, max = 0)
# 異常値2(とても大きな/小さな値)
rv[39] <- 22
rv[52] <- -21
rv[91] <- 11
# 小数点第2位に丸め行列(列数:100)に変換
m <- matrix(round(rv, 2), ncol = 100)
write.csv(as.data.frame(m),
file = 'data_cleansing2_dirty_data.csv', row.names = F, quote = F)
boxplot(m)

any(m < 0)
## [1] TRUE
any(abs(m) > 3*sd(m))
## [1] TRUE
jj <- 36:46
boxplot(m[, jj])

j <- 37
y <- m[, j]
barplot(height = y, # 棒グラフの高さ
names.arg = 1:nrow(m)) # 横軸名

ii <- 140:231
y <- m[ii, j]
barplot(height = y, # 棒グラフの高さ
cex.names = 0.4, # 横軸ラベルの大きさ
names.arg = paste(ii, '\n(', y, ')')) # 横軸名 \nで改行して値も()内に表示

ii <- 194:206
y <- m[ii, j]
barplot(height = y, # 棒グラフの高さ
cex.names = 0.4, # 横軸ラベルの大きさ
names.arg = paste(ii, '\n(', y, ')')) # 横軸名 \nで改行して値も表示

m[200, j]
## [1] -0.78
m[m < 0]
## [1] -21.00 -0.78 -0.99 -0.68
sigma <- sd(m) # 標準偏差
#m[abs(m) > 3*sigma] # 数が多いためコメントアウトした。
# 4シグマ(標準偏差の4倍)を超える値
m[abs(m) > 4*sigma]
## [1] 22 -21 11
m.a <- NULL # 結果格納用の空のオブジェクトを作成
for (i in 1:nrow(m))
{
for (j in 1:ncol(m))
{
if ( m[i, j] < 0 | m[i, j] > 4*sigma)
{
cat('Row:', i, ', Col:', j, ', Value: ', m[i, j], fill = T)
m.a <- rbind(m.a, t(c(i, j, m[i, j]))) # rbind:行ベクトルを追加
}
}
}
## Row: 39 , Col: 1 , Value: 22
## Row: 52 , Col: 1 , Value: -21
## Row: 91 , Col: 1 , Value: 11
## Row: 200 , Col: 37 , Value: -0.78
## Row: 242 , Col: 100 , Value: -0.68
## Row: 521 , Col: 59 , Value: -0.99
colnames(m.a) <- c('Row', 'Col', 'Value')
m.a
## Row Col Value
## [1,] 39 1 22.00
## [2,] 52 1 -21.00
## [3,] 91 1 11.00
## [4,] 200 37 -0.78
## [5,] 242 100 -0.68
## [6,] 521 59 -0.99
d <- read.csv(file = 'https://stats.dip.jp/01_ds/data/data_cleansing2_dirty_data_exercise.csv')
library(DT)
datatable(d)
options(digits = 2) # 表示の有効桁数2桁に設定
d0 <- read.csv(file = 'https://stats.dip.jp/01_ds/data/car_data_jp.csv')
summary(d0)
## お客様番号 性別 年齢 年収 購入判断
## Min. : 1 Length:1000 Min. :18 Min. : 15000 Min. :0.0
## 1st Qu.: 251 Class :character 1st Qu.:32 1st Qu.: 46375 1st Qu.:0.0
## Median : 500 Mode :character Median :40 Median : 72000 Median :0.0
## Mean : 500 Mean :40 Mean : 72689 Mean :0.4
## 3rd Qu.: 750 3rd Qu.:48 3rd Qu.: 90000 3rd Qu.:1.0
## Max. :1000 Max. :63 Max. :152500 Max. :1.0
head(d0)
## お客様番号 性別 年齢 年収 購入判断
## 1 385 男性 35 20000 0
## 2 681 男性 40 43500 0
## 3 353 男性 49 74000 0
## 4 895 男性 40 107500 1
## 5 661 男性 25 79000 0
## 6 846 女性 47 33500 1
tail(d0)
## お客様番号 性別 年齢 年収 購入判断
## 995 951 女性 53 104000 1
## 996 863 男性 38 59000 0
## 997 800 女性 47 23500 0
## 998 407 女性 28 138500 1
## 999 299 女性 48 134000 1
## 1000 687 女性 44 73500 0
(n <- nrow(d0)) # 全レコード数
## [1] 1000
# 乱数シード(乱数の種):
# 無作為標本抽出でプログラム実行のたびに同じ標本が抽出される。
# 数字を変えると異なる組み合わせで毎回同じ標本が抽出される。
set.seed(5)
## インデックス番号1~n(1000)をサイズ900で無作為標本抽出
#ii <- sample(x = 1:n, size = 900)
# インデックス番号1~nを全体の80%のサイズで無作為標本抽出
ii <- sample(x = 1:n, size = floor(0.8 * n))
# 抽出されたインデックス番号行のレコードを訓練データ
# 抽出されなかったインデックス番号行のレコードをテストデータとする。
d.tr <- d0[ ii, ] # 訓練データ
d.te <- d0[-ii, ] # テストデータ
(n.tr <- nrow(d.tr)) # 訓練データのレコード数
## [1] 800
(n.te <- nrow(d.te)) # テストデータのレコード数
## [1] 200
fit.all <- glm(購入判断 ~ ., data = d.tr, family = 'binomial')
summary(fit.all)
##
## Call:
## glm(formula = 購入判断 ~ ., family = "binomial", data = d.tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.931 -0.590 -0.138 0.475 2.446
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.22e+01 9.22e-01 -13.3 <2e-16 ***
## お客様番号 2.16e-04 3.60e-04 0.6 0.55
## 性別男性 1.67e-01 2.08e-01 0.8 0.42
## 年齢 2.19e-01 1.68e-02 13.0 <2e-16 ***
## 年収 3.38e-05 3.67e-06 9.2 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1076.00 on 799 degrees of freedom
## Residual deviance: 589.56 on 795 degrees of freedom
## AIC: 599.6
##
## Number of Fisher Scoring iterations: 6
fit <- glm(購入判断 ~ 年齢 + 年収, data = d.tr, family = 'binomial')
summary(fit)
##
## Call:
## glm(formula = 購入判断 ~ 年齢 + 年収, family = "binomial",
## data = d.tr)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.948 -0.595 -0.140 0.476 2.421
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -1.19e+01 8.63e-01 -13.85 <2e-16 ***
## 年齢 2.17e-01 1.66e-02 13.05 <2e-16 ***
## 年収 3.35e-05 3.65e-06 9.18 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 1076.00 on 799 degrees of freedom
## Residual deviance: 590.54 on 797 degrees of freedom
## AIC: 596.5
##
## Number of Fisher Scoring iterations: 6
d.new <- data.frame(年齢 = 45, 年収 = 80000)
p.hat <- predict(fit, type = 'response', newdata = d.new)
sprintf('新車購入確率:%2.1f%', p.hat * 100)
## [1] "新車購入確率:62.0%"
p.hat <- predict(fit, type = 'response', newdata = d.te)
threshold <- 0.5 # 閾値(しきいち),カットオフ値(cut-off)とも呼ばれる。
is.pred <- p.hat > threshold
is.ref <- d.te$購入判断 == 1
table(予測値 = is.pred, 真値 = is.ref)
## 真値
## 予測値 FALSE TRUE
## FALSE 102 27
## TRUE 15 56
is.ok <- is.pred == is.ref
n.ok <- sum(is.ok)
sprintf('新車購入予測精度:%2.1f%', n.ok / nrow(d.te) * 100)
## [1] "新車購入予測精度:79.0%"
library(caret)
confusionMatrix(data = as.factor(is.pred),
reference = as.factor(is.ref))
## Confusion Matrix and Statistics
##
## Reference
## Prediction FALSE TRUE
## FALSE 102 27
## TRUE 15 56
##
## Accuracy : 0.79
## 95% CI : (0.727, 0.844)
## No Information Rate : 0.585
## P-Value [Acc > NIR] : 7.05e-10
##
## Kappa : 0.558
##
## Mcnemar's Test P-Value : 0.0896
##
## Sensitivity : 0.872
## Specificity : 0.675
## Pos Pred Value : 0.791
## Neg Pred Value : 0.789
## Prevalence : 0.585
## Detection Rate : 0.510
## Detection Prevalence : 0.645
## Balanced Accuracy : 0.773
##
## 'Positive' Class : FALSE
##
library(pROC)
roc1 <- roc(response = d.te$購入判断, predict = p.hat,
plot = T, print.auc = T, grid = T, ci = T, auc.polygon=T)
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases

coords(roc1, 'best') # 最適閾値 (optimal threshold)
## threshold specificity sensitivity
## 1 0.27 0.77 0.89
c <- coords(roc1) # 閾値 (threshold)ごとの値 (sensitivity, specificity)
library(DT)
datatable(round(c, 3))
d0 <- read.csv(file = 'https://stats.dip.jp/01_ds/data/titanic_data_jp.csv')
datatable(d0)
d0 <- read.csv(file = 'https://stats.dip.jp/01_ds/data/dirty_data1.csv')
summary(d0) # 要約統計値 NA's:1 (NAが1つ含まれている)
## 会社名 気温 湿度 風速
## Length:22 Min. :12 Min. :-50 Min. :-1.0
## Class :character 1st Qu.:20 1st Qu.: 30 1st Qu.: 1.0
## Mode :character Median :32 Median : 50 Median : 2.0
## Mean :28 Mean : 40 Mean : 2.1
## 3rd Qu.:34 3rd Qu.: 51 3rd Qu.: 4.0
## Max. :50 Max. : 60 Max. : 5.0
## NA's :1 NA's :1
library(DT)
datatable(d0)
d1 <- na.omit(d0)
summary(d1) # 要約統計値 NAがなくなった。
## 会社名 気温 湿度 風速
## Length:20 Min. :12 Min. :-50 Min. :-1.0
## Class :character 1st Qu.:18 1st Qu.: 28 1st Qu.: 0.8
## Mode :character Median :32 Median : 50 Median : 2.0
## Mean :28 Mean : 39 Mean : 2.1
## 3rd Qu.:34 3rd Qu.: 51 3rd Qu.: 4.0
## Max. :50 Max. : 60 Max. : 5.0
datatable(d1)
# 各気象変数の許容範囲に入っているか否かを示す論理式を作成
is.tp <- -20 <= d1$気温 & d1$気温 <= 50
is.hm <- 0 <= d1$湿度 & d1$湿度 <= 100
is.ws <- 0 <= d1$風速 & d1$風速 <= 70
summary(is.tp)
## Mode FALSE TRUE
## logical 2 18
summary(is.hm)
## Mode FALSE TRUE
## logical 1 19
summary(is.ws)
## Mode FALSE TRUE
## logical 1 19
d2 <- d1[is.tp & is.hm & is.ws, ]
datatable(d2)
d3 <- d2
d3$気温 <- round(d2$気温, 1)
d3$湿度 <- round(d2$湿度, 0)
d3$風速 <- round(d2$風速, 0)
datatable(d3)
d3$会社名
## [1] "ソニー" "Sony" "SONY" "sony"
## [5] "ソニー株式会社" "Sony(株)" "ソニー(株)" "sony"
## [9] "富士通" "Fujitsu" "Fujitu" "FUJITSU"
## [13] "富士通株式会社" "富士通(株)" "fujitsu" "FUJITSU"
LAB.SONY <- c("ソニー", "Sony(株)", "ソニー(株)", "Sony", "SONY", "sony")
# 富士通株式会社を意味する表記
LAB.FUJITSU <- c("富士通", "富士通(株)", "Fujitsu", "FUJITSU", "fujitsu", "Fujitu", "fujitu")
# %in%の記号は右辺の集合に含まれるか否かを示す論理記号
is.sony <- d3$会社名 %in% LAB.SONY
is.fujitsu <- d3$会社名 %in% LAB.FUJITSU
d4 <- d3
# 各メーカーの正式名称に統一
d4$会社名[is.sony] <- 'ソニー株式会社'
d4$会社名[is.fujitsu] <- '富士通株式会社'
d4$会社名
## [1] "ソニー株式会社" "ソニー株式会社" "ソニー株式会社" "ソニー株式会社"
## [5] "ソニー株式会社" "ソニー株式会社" "ソニー株式会社" "ソニー株式会社"
## [9] "富士通株式会社" "富士通株式会社" "富士通株式会社" "富士通株式会社"
## [13] "富士通株式会社" "富士通株式会社" "富士通株式会社" "富士通株式会社"
datatable(d4)
d <- read.csv(file = 'https://stats.dip.jp/01_ds/data/dirty_data2.csv')
datatable(d)
y <- c(AirPassengers) # 月間航空旅客数
n <- length(y) # 月数
n.tr <- 120 # 訓練月数
n.te <- n - n.tr # テスト月数
t <- 1:n # 月
ii.tr <- 1:120 # 訓練期間インデックス
ii.te <- 121:n # テスト期間インデックス
matplot(y, type = 'o', pch = 1, col = 2)

fq <- 12
library(MASS)
bc <- boxcox(y ~ t, data = data.frame(y = y[ii.tr], t = t[ii.tr]))

lambda <- round(bc$x[which.max(bc$y)], 1)
lambda
## [1] 0
library(forecast)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
y.bc <- BoxCox(y[ii.tr], lambda)
matplot(y.bc, type = 'o', pch = 1, col = 2, ylab = 'y')

d <- 1
dy <- diff(y.bc, diff = d)
matplot(dy, type = 'o', pch = 1, col = 2, ylab = 'y')

ys <- ts(10 * sin(2 * pi * t / 10) + rnorm(n))
dir.create('acf_lag', showWarnings = F)
for (k in 1:25)
{
png(paste0('acf_lag/acf_lag', k, '.png'))
ys.lag <- lag(ys, k = -k)
ts2 <- cbind(ys, ys.lag)
par(mfrow = c(3, 1), mar = c(2, 4, 1, 1))
matplot(ts2, type = 'o', pch = 1, col = c(1, 4),
xlab = '', ylab = '', xlim = c(0, 120))
abline(v = c(0, k), col = 2)
arrows( 0, 0, k, 0, length = 0.1, col = 2)
mtext(paste(k), side = 1, at = k, line = 1, col = 2)
legend('topright', col = c(1, 4), bg = 'white', lty = 1,
legend = c('原系列(周期10の正弦波+ノイズ)', paste0(k, '次ラグ系列')))
grid()
acf(ys, lag.max = k, xlim = c(0, 120), ylim = c(-1, 1), main = '')
pacf(ys, lag.max = k, xlim = c(0, 120), ylim = c(-1, 1), main = '')
dev.off()
}
#system('bash -c 'convert -delay 100 -loop 0 ./acf_lag/acf_lag{1..25}.png ./acf_lag/acf_lag.gif'')
a <- acf(dy, lag.max = 50) # MA(q)
grid()
abline(v = fq, col = 3, lty = 3)

q <- 12
pa <- pacf(dy, lag.max = 50) # AR(p)【注意】acfと違いグラフが1次ラグから始まる。
grid()
abline(v = fq, col = 3, lty = 3)

p <- 12
fit.arima <- Arima(ts(y[ii.tr], frequency = fq), lambda = 'auto',
order = c(p, d, q),
seasonal = c(1, 1, 0)) # SARIMA
# c.f.
#fit.arima <- auto.arima(ts(y[ii.tr], frequency = fq), lambda = 'auto')
fit.arima
## Series: ts(y[ii.tr], frequency = fq)
## ARIMA(12,1,12)(1,1,0)[12]
## Box Cox transformation: lambda= -0.31
##
## Coefficients:
## ar1 ar2 ar3 ar4 ar5 ar6 ar7 ar8 ar9 ar10
## -0.25 0.094 -0.054 0.057 -0.059 -0.03 0.11 -0.003 0.14 0.073
## s.e. 0.14 0.144 0.137 0.135 0.133 0.13 0.14 0.133 0.13 0.131
## ar11 ar12 ma1 ma2 ma3 ma4 ma5 ma6 ma7 ma8
## -0.26 -0.28 -0.074 -0.14 -0.096 -0.22 0.19 0.21 -0.18 -0.037
## s.e. 0.13 0.18 0.147 0.14 0.126 0.15 0.15 0.15 0.16 0.139
## ma9 ma10 ma11 ma12 sar1
## -0.14 0.01 0.36 -0.63 0.12
## s.e. 0.14 0.15 0.15 0.15 0.23
##
## sigma^2 = 5.45e-05: log likelihood = 381
## AIC=-711 AICc=-693 BIC=-641
checkresiduals(fit.arima) # 残差分析グラフ

##
## Ljung-Box test
##
## data: Residuals from ARIMA(12,1,12)(1,1,0)[12]
## Q* = 6, df = 3, p-value = 0.1
##
## Model df: 25. Total lags used: 28
pred <- forecast(fit.arima, h = n.te, level = 95)
matplot(t, y, type = 'o', pch = 16, col = 2, main = pred$method)
grid()
abline(v = n.tr + 1, lty = 3, col = 3)
matlines(t[ii.tr], fit.arima$fitted, type = 'o', pch = 16, lty = 2, col = 4)
matlines(t[ii.te], pred$mean, type = 'o', pch = 1, lty = 2, col = 4)
matlines(t[ii.te], pred$lower, lty = 3, col = 'gray')
matlines(t[ii.te], pred$upper, lty = 3, col = 'gray')
legend('topleft', bg = 'white', lty = c(1, 2, 2, 3),
col = c(2, 4, 4, 'gray'), pch = c(16, 16, 1, NA),
legend = c('原系列', '1期先予測値', '予測値', '95%予測区間'))

get.accuracy <- function(yhat, y)
{
data.frame(MBE = mean(yhat - y),
MAE = mean(abs(yhat - y)),
MAPE = mean(abs((yhat - y) / y)) * 100,
RMSE = sqrt(mean((yhat - y)^2))
)
}
get.accuracy(yhat = pred$mean, y = y[ii.te])
## MBE MAE MAPE RMSE
## 1 -14 15 3.4 17
n <- 24*7*2 # 時間数
t <- 1:n # 時間
n.tr <- floor(n * 0.8) # 訓練期間数
n.te <- n - n.tr # テスト期間数
ii.tr <- 1:n.tr # 訓練期間インデックス
ii.te <- (n.tr+1):n # テスト期間インデックス
set.seed(5)
y <- 100 + 0.1 * t + 0.02 * t^2 + 100 * sin(2 * pi * t / 24) + rnorm(n, sd = 5)
matplot(y, type = 'o', pch = 1, col = 2)

options(digits = 2)
year <- 2011:2017
sales <- c(1, 3, 2, 7, 3, 8, 7)
n <- length(year)
d <- data.frame(year, sales)
library(kableExtra)
kable(d,caption = 'ロボット販売', col.names = c('会計年', '台数'))%>%
kable_classic('striped', full_width = F)
ロボット販売
|
会計年
|
台数
|
|
2011
|
1
|
|
2012
|
3
|
|
2013
|
2
|
|
2014
|
7
|
|
2015
|
3
|
|
2016
|
8
|
|
2017
|
7
|
matplot(x = year, y = sales, type = 'o', pch = 1,
main = 'ロボット販売',
xlab = '会計年',
ylab = '台数')
grid()

d$ma3 <- NA # 値がNAの移動平均のカラム(ma3)を追加
for (i in 2:(n-1))
{
d$ma3[i] <- (sales[i-1] + sales[i] + sales[i+1]) / 3
}
ma3 <- stats::filter(sales, rep(1/3, 3))
ma3
## Time Series:
## Start = 1
## End = 7
## Frequency = 1
## [1] NA 2 4 4 6 6 NA
library(quantmod)
## 要求されたパッケージ xts をロード中です
## 要求されたパッケージ zoo をロード中です
##
## 次のパッケージを付け加えます: 'zoo'
## 以下のオブジェクトは 'package:base' からマスクされています:
##
## as.Date, as.Date.numeric
## 要求されたパッケージ TTR をロード中です
ma3 <- rollmean(sales, 3, na.pad = T)
ma3
## [1] NA 2 4 4 6 6 NA
d$ma4 <- NA # 値がNAの移動平均のカラム(ma4)を追加
for (i in 3:(n-2))
{
d$ma4[i] <-
(0.5 * sales[i-2] + sales[i-1] + sales[i] + sales[i+1] + 0.5 * sales[i+2]) / 4
}
ma4 <- stats::filter(sales, c(0.5/4, 1/4, 1/4, 1/4, 0.5/4))
ma4
## Time Series:
## Start = 1
## End = 7
## Frequency = 1
## [1] NA NA 3.5 4.4 5.6 NA NA
ma4 <- rollmean(sales, k = 4, na.pad = T)
ma4
## [1] NA 3.2 3.8 5.0 6.2 NA NA
kable(d, caption = 'ロボット販売',
col.names = c('会計年', '台数', '3項移動平均', '4項移動平均'))%>%
kable_classic('striped', full_width = F)
ロボット販売
|
会計年
|
台数
|
3項移動平均
|
4項移動平均
|
|
2011
|
1
|
NA
|
NA
|
|
2012
|
3
|
2
|
NA
|
|
2013
|
2
|
4
|
3.5
|
|
2014
|
7
|
4
|
4.4
|
|
2015
|
3
|
6
|
5.6
|
|
2016
|
8
|
6
|
NA
|
|
2017
|
7
|
NA
|
NA
|
matplot(x = year, y = sales, type = 'o', pch = 1,
main = 'ロボット販売', xlab = '会計年', ylab = '台数')
grid()
matlines(x = year, y = d$ma3, type = 'o', pch = 2, col = 2)
matlines(x = year, y = d$ma4, type = 'o', pch = 4, col = 4)
legend('topleft', col = c(1, 2, 4), pch = c(1, 2, 4), lty = 1,
legend = c('台数', '3項移動平均', '4項移動平均'))

library(quantmod)
z <- getSymbols('9984', src='yahooj',
from = '2022-01-01',
to = '2022-12-31',
auto.assign = F)
# データの保存
write.zoo(z, file = 'softbank.csv', sep = ',', quote = F)
x <- as.POSIXct(index(z), format = '%Y-%m-%d')
y <- z[, 'YJ9984.Close']
# 1日分データをずらすことで当日の日付の株価が1日前のものになる。
ylag1 <- lag(y, k = 1)
# align = 'right'で右寄せ移動平均となる。
yhat5 <- rollmean(ylag1, 5, fill = NA, align = 'right')
yhat25 <- rollmean(ylag1, 25, fill = NA, align = 'right')
yhat25c <- rollmean(y, 25, fill = NA) # 参考(通常の移動平均:中心化移動平均)
matplot(x, y, type = 'l', col = 3,
main = 'ソフトバンク(9984)', xlab = '日', ylab = '円')
matlines(x, yhat5, col = 2)
matlines(x, yhat25, col = 4)
matlines(x, yhat25c, col = 1)
grid()
legend('topleft', col = c(3, 2, 4, 1), lty = 1,
legend = c('株価',
'5日移動平均',
'25日移動平均',
'25日中心化移動平均(参考)'))

chartSeries(z, TA = c(addBBands(), addMACD()), type='bar',
subset='2022-06-01/2022-12-31')

x <- seq_along(y)
fit10 <- loess(y ~ x, data = data.frame(x, y), span = 0.1) # 10%
fit30 <- loess(y ~ x, data = data.frame(x, y), span = 0.3) # 30%
matplot(x, y = y, type = 'l', col = 3,
main = 'ソフトバンク(9984)', xlab = '日', ylab = '円')
matlines(x, fit10$fitted, col = 1, lwd = 2)
matlines(x, fit30$fitted, col = 2, lwd = 2)
grid()
legend('topleft', col = c(3, 1, 2), lty = 1,
legend = c('株価',
'LOESS(平滑化窓幅10%)',
'LOESS(平滑化窓幅30%)'))

n <- 100 # 全時間
x <- 1:n # 時刻
t <- 2 * x # トレンド(係数:2)
e <- rnorm(n, mean = 0, sd = 10) # 不規則変動
y <- t + e # 合成変動
matplot(x, y, type = 'o', pch = 16, col = 2)

n.tr <- n * 0.8 # 訓練時間(80%)
n.te <- n - n.tr # テスト時間(20%)
ii.tr <- 1:n.tr
ii.te <- (n.tr + 1):n
fit <- lm(y ~ x, data = data.frame(x = x[ii.tr], y = y[ii.tr]))
#summary(fit)
pred <- predict(fit, newdata = data.frame(x = x[ii.te]), interval = 'prediction')
myplot <- function(x, y, pred)
{
matplot(x, y, type = 'o', pch = 16, col = 2, cex = 0.5)
abline(v = n.tr+1, col = 3, lty = 2)
matlines(x[ii.te], pred[, 'fit'], type = 'o', pch = 1, lty = 2, col = 4)
matlines(x[ii.te], pred[, 'lwr'], lty = 3, col = 'lightgray')
matlines(x[ii.te], pred[, 'upr'], lty = 3, col = 'lightgray')
legend('topleft', bg = 0,
lty = c(1, 2, 3), pch = c(16, 1, NA), col = c(2, 4, 'lightgray'),
legend = c('原系列', '予測値', '95%予測区間'))
}
myplot(x, y, pred)

t <- 0.05 * x^2 - 2 * x # 2次のトレンド
e <- rnorm(n, mean = 0, sd = 10) # 不規則変動
y <- t + e # 合成変動
fit <- lm(y ~ poly(x, 2, raw = T), data = data.frame(x = x[ii.tr], y = y[ii.tr]))
#summary(fit)
pred <- predict(fit, newdata = data.frame(x = x[ii.te]), interval = 'prediction')
myplot(x, y, pred)

T <- 10 # 周期
c <- 30 * sin(2 * pi * x / T) # 周期変動(振幅:30,周期:10)
t <- 2 * x # トレンド(係数:2)
e <- rnorm(n, mean = 0, sd = 10) # 不規則変動
y <- t + c + e # 合成変動
fit <- lm(y ~ poly(x, 2, raw = T), data = data.frame(x = x[ii.tr], y = y[ii.tr]))
#summary(fit)
pred <- predict(fit, newdata = data.frame(x = x[ii.te]), interval = 'prediction')
myplot(x, y, pred)

dir.create('./ts_reg_periodic', showWarnings = F)
yhat <- rep(NA, n)
for (j in 1:T)
{
# j <- 1
ii <- seq(j, n.tr, T)
ii.pred <- ii[length(ii)] + seq(T, T*2, T)
fit <- lm(y ~ x, data = data.frame(x = x[ii], y = y[ii]))
pred <- predict(fit, newdata = data.frame(x = x[ii.pred]), interval = 'prediction')
yhat[ii.pred] <- pred[, 'fit']
png(paste0('./ts_reg_periodic/ts_reg_periodic', j, '.png'))
matplot(x, y, type = 'o', pch = 16, col = 2, cex = 0.5, ylim = c(0, 250))
abline(v = n.tr+1, col = 3, lty = 2)
matlines(x[ii], y[ii], type = 'o', pch = 1, col = 1, cex = 1.5)
matlines(x, yhat, type = 'o', pch = 1, col = 4)
matpoints(x[ii.pred], yhat[ii.pred], pch = 1, col = 1)
dev.off()
#Sys.sleep(2)
}
#system('bash -c "convert -delay 100 -loop 0 ./ts_reg_periodic/ts_reg_periodic{1..10}.png ./ts_reg_periodic/ts_reg_periodic.gif"')
d0 <- read.csv('https://stats.dip.jp/01_ds/data/load_amedas_y2017-2022_tokyo.csv')
head(d0)
## date datetime dow name event md gr year month
## 1 2017-01-01 2017-01-01 00:00:00 日 祝日:元日 年末年始 01-01 6 2017 1
## 2 2017-01-01 2017-01-01 01:00:00 日 祝日:元日 年末年始 01-01 6 2017 1
## 3 2017-01-01 2017-01-01 02:00:00 日 祝日:元日 年末年始 01-01 6 2017 1
## 4 2017-01-01 2017-01-01 03:00:00 日 祝日:元日 年末年始 01-01 6 2017 1
## 5 2017-01-01 2017-01-01 04:00:00 日 祝日:元日 年末年始 01-01 6 2017 1
## 6 2017-01-01 2017-01-01 05:00:00 日 祝日:元日 年末年始 01-01 6 2017 1
## day su mo tu we th fr sa wd ho bw af sp ab mw time hr mi hm rm ws tp
## 1 1 1 0 0 0 0 0 0 0 1 0 0 1 0 27830 00:00:00 0 0 77 0 2.3 4.9
## 2 1 1 0 0 0 0 0 0 0 1 0 0 1 0 26340 01:00:00 1 0 71 0 2.5 4.5
## 3 1 1 0 0 0 0 0 0 0 1 0 0 1 0 25200 02:00:00 2 0 69 0 1.5 4.1
## 4 1 1 0 0 0 0 0 0 0 1 0 0 1 0 24380 03:00:00 3 0 71 0 1.4 3.9
## 5 1 1 0 0 0 0 0 0 0 1 0 0 1 0 23890 04:00:00 4 0 75 0 2.0 3.2
## 6 1 1 0 0 0 0 0 0 0 1 0 0 1 0 23940 05:00:00 5 0 74 0 2.2 3.1
## tp3h tp5h tp3d tp7d
## 1 5.3 5.5 5.5 6.7
## 2 5.0 5.2 5.5 6.7
## 3 4.5 4.9 5.5 6.7
## 4 4.2 4.6 5.6 6.7
## 5 3.7 4.1 5.6 6.7
## 6 3.4 3.8 5.6 6.7
d0$px <- as.POSIXct(d0$datetime)
d0$gw <- d0$mw / 1000 # 測定値 (単位変換:MW -> GW)
d0$gwfit <- NA
d0$gwlwr <- NA
d0$gwupr <- NA
# Suffixとしてtr: training term, te: test term, al: all term を使用する。
# 訓練データの取得期間フラグ(ここでは予測日の前後1ヶ月間をとった)
is.67 <- '06-01' <= d0$md & d0$md <= '07-31'
# 訓練期間フラグ
is.tr <- '2017-06-01' <= d0$date & d0$date <= '2022-06-30'
# テスト期間フラグ
is.te <- '2022-07-01' <= d0$date & d0$date <= '2022-07-03'
# グラフ表示期間フラグ
is.plot <- '2022-06-28' <= d0$date & d0$date <= '2022-07-03'
d.plot <- d0[is.plot, ] # グラフ表用データ
matplot(d0$px, d0$gw,
main = '電力需要',
xlab = '年', ylab = '電力需要[GW]',
type = 'l', col = 2, ylim = c(20, 70))

for (hr in 0:23)
{
# 予測時間
#hr <- 10
is.hr <- d0$hr == hr
# 訓練データ
d.tr <- d0[is.hr & is.67 & is.tr, ]
# テストデータ(予測区間の正解データとして精度評価に利用)
d.te <- d0[is.hr & is.te, ]
# フィッティング
# (ここでは,トレンドがなく気温の2次多項式と曜日ダミーのモデルとした)
fit <- lm(gw ~ tp + I(tp^2) + dow, data = d.tr)
summary(fit)
# 予測(予測区間付き)
pred <- predict(fit, newdata = d.te, interval = 'prediction')
# 毎時の予測値を保存
d0$gwfit[d0$px %in% d.te$px] <- pred[, 'fit']
d0$gwlwr[d0$px %in% d.te$px] <- pred[, 'lwr']
d0$gwupr[d0$px %in% d.te$px] <- pred[, 'upr']
# 時間別グラフ
dir.create('./load', showWarnings = F)
png(paste0('./load/load_at', hr, '.png'))
matplot(d0$px[is.hr & is.plot], d0$gw[is.hr & is.plot],
main = paste0(hr, '時の電力需要'),
xlab = format(d0$px[1], '%Y年'), ylab = '電力需要[GW]',
type = 'n', pch = 16, col = 2, xaxt = 'n',
xlim = range(d0$px[is.plot]), ylim = c(20, 70))
px.ax <- seq(d0$px[1], d0$px[nrow(d0)], by = 60*60*24)
abline(v = px.ax, col = 'lightgray', lty = 2)
abline(v = as.POSIXct('2022-07-01'), col = 3, lty = 2) # 予測開始線
axis(side = 1, at = px.ax, labels = format(px.ax, '%-m/%-d(%a)'))
matlines(d0$px[is.plot], d0$gw[is.plot], type = 'o', pch = 1, col = 'lightgray')
matlines(d.te$px, pred[, 'fit'], type = 'o', pch = 1, lty = 2, col = 4)
matlines(d.te$px, pred[, 'lwr'], lty = 3, col = 'lightgray')
matlines(d.te$px, pred[, 'upr'], lty = 3, col = 'lightgray')
matlines(d0$px[is.hr & is.plot], d0$gw[is.hr & is.plot], type = 'o', pch = 16, col = 2)
# 凡例
legend('topleft', bg = 0,
lty = c(1, 2, 3), pch = c(16, 1, NA), col = c(2, 4, 'lightgray'),
legend = c('原系列', '予測値', '95%予測区間'))
legend('topright', bg = 0,
legend = sprintf('MAPE: %2.1f%%',
mean(abs((pred[, 'fit'] - d.te$gw)/d.te$gw))*100))
dev.off()
}
#system('bash -c "convert -delay 100 -loop 0 ./load/load_at{0..23}.png ./load/load_at.gif"')
#cairo_pdf('load_0-23.pdf')
matplot(d0$px[is.plot], d0$gw[is.plot],
main = '電力需要',
xlab = format(d0$px[1], '%Y年'), ylab = '電力需要[GW]',
type = 'o', pch = 16, col = 2, xaxt = 'n',
xlim = range(d0$px[is.plot]), ylim = c(20, 70))
px.ax <- seq(d0$px[1], d0$px[nrow(d0)], by = 60*60*24)
axis(side = 1, at = px.ax, labels = format(px.ax, '%-m/%-d(%a)'))
abline(v = px.ax, col = 'lightgray', lty = 2)
abline(v = as.POSIXct('2022-07-01'), col = 3, lty = 2) # 予測開始線
matlines(d0$px[is.te], d0$gwlwr[is.te], lty = 3, col = 'lightgray')
matlines(d0$px[is.te], d0$gwupr[is.te], lty = 3, col = 'lightgray')
matlines(d0$px[is.te], d0$gwfit[is.te], type = 'o', pch = 1, lty = 2, col = 4)
# 凡例
legend('topleft', bg = 0,
lty = c(1, 2, 3), pch = c(16, 1, NA), col = c(2, 4, 'lightgray'),
legend = c('原系列', '予測値', '95%予測区間'))
legend('topright', bg = 0,
legend = sprintf('MAPE: %2.1f%%',
mean(abs((d0$gwfit[is.te] - d0$gw[is.te])/d0$gw[is.te]))*100))

d0 <- read.csv('https://stats.dip.jp/01_ds/data/e-stat_expenditure.csv', skip = 11)
# タイムスタンプと支出金額のカラムを探しデータを抽出
j.time <- grep('時間軸.月次..コード', colnames(d0))
j.ice <- grep('アイスクリーム', colnames(d0))
d1 <- d0[, c(j.time, j.ice)]
# 時間コード(10桁)からPOSIX準拠時間を作成
yyyy <- substr(paste(d1[, 1]), 1, 4)
mm <- substr(paste(d1[, 1]), 7, 8)
px <- as.POSIXct(paste(yyyy, mm, '01 12:00:00'), format = '%Y%m%d %H:%M:%S')
d <- data.frame(px, date = format(px, '%Y-%m-%d'), y = d1[, 2])
# 暦,気象とマージ
d <- merge(d, read.csv('https://stats.dip.jp/01_ds/data/calendar.csv'))
d <- merge(d, read.csv('https://stats.dip.jp/01_ds/data/amedas_tokyo.csv'))
#View(d)
# グラフ
MAIN <- 'アイスクリーム月間世帯支出'
matplot(d$px, d$y, type = 'o', pch = 16, lty =1, col = 2,
main = MAIN, xlab = '年', ylab = '円')

```