-
Notifications
You must be signed in to change notification settings - Fork 0
/
3-Chapter_2.qmd
1754 lines (1411 loc) · 49 KB
/
3-Chapter_2.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# 第2章
第2章では2元表の連関モデルが紹介されている.制約のかけかたは少し複雑なのでプログラムとテキストをみながら手順を確認して欲しい.
パッケージは`tidyverse`(データセットの処理のため),`DescTools`(記述統計を求めるため),`vcd`パッケージ(カテゴリカルデータの分析のため),`broom`(回帰係数の整理),`gnm`(連関分析の処理のため),`logmult`(連関モデルのため)を使用する.
```{r, message = FALSE}
library(tidyverse)
library(broom)
library(gnm)
library(vcd)
library(DescTools)
library(logmult)
library(knitr)
```
## 対比について
回帰モデルにおけるカテゴリカル変数の係数を解釈する上では対比
(contrasts)が重要である.まずはモデルを推定できるようになることのほうが重要なので,
ひとまずとばして次の @sec-tab2_1 から読みすすめてもよい.
まず,デフォルト(標準の状態)での`contrasts`を確認したい.`factor`変数については`contr.treatment`,`ordered`変数については`contr.poly`という対比が用いられている.`contr.treatment`は基準となっている水準とそれぞれの水準を対比する.これはダミーコーディングと呼ばれる.
`contr.poly`は直交多項式(orthogonal polynomials)に基づいた対比を行う(気にしなくてよい).
```{r}
# デフォルトのcontrastsを確認
options("contrasts")
```
```{r}
# defaultのcontrastsの設定(ここでは特に意味はない.constrastをいじった後にデフォルトに戻す)
options(contrasts = c(factor = "contr.treatment",
ordered = "contr.poly"))
```
具体的に何をしているのかを以下のプログラムで確認する.
ダミーコーディングの`contr.treatment`以外にも効果コーディングの`contr.sum`がある.まずは両者を比較してみたい.
```{r}
# データの作成
x <- c("A","B","C","D","E")
# 確認
x
# 基準カテゴリが0となるような対比
contr.treatment(x)
# 合計が0となるような対比
contr.sum(x)
```
実際に回帰分析を例に`contr.treatment`と`contr.sum`の違いを確認する.データは`forcats`パッケージ(`tidyverse`に含まれる)の`gss_cat`(A sample of categorical variables from the General Social survey)である.従属変数は`tvhours`(hours per day watching tv)であり,独立変数は`marital`(marital status)とする.
```{r}
# class別のtvhoursの平均値
gss_cat |>
dplyr::summarise(n = sum(!is.na(tvhours)),
Mean = mean(tvhours, na.rm = TRUE),
.by = marital) |>
mutate(Diff_1 = Mean - Mean[marital == "Never married"],
Diff_2 = Mean - mean(Mean))
```
水準は`levels`関数で確認できる.1つ目の水準は`No answer`であり,最後の水準は`Married`である.
```{r}
# 水準の確認
gss_cat$marital |> levels()
```
まずダミーコーディング(dummy coding)の結果を確認する.
```{r}
# 回帰分析の例(contr.treatmentを使用)
options(contrasts = c(factor = "contr.treatment",
ordered = "contr.poly"))
# 回帰分析
fit_ct <- lm(tvhours ~ marital, data = gss_cat)
# 回帰分析の結果
summary(fit_ct)
# 回帰分析の係数をtidyで表示
tidy(fit_ct, conf.int = TRUE)
# モデルマトリックス
model.matrix(fit_ct) |> unique()
```
出力される係数は5つである.`marital`は`factor`によって水準が設定されているわけではないので,`No answer`が基準カテゴリとなっており,出力からは省略されている.つまり,`No answer`の係数は0であり,`(Intercept) `の値は`No answer`の平均値を示している.
次に効果コーディングの結果を確認する.
```{r}
# 回帰分析の例(contr.sumを使用)
options(contrasts = c(factor = "contr.sum",
ordered = "contr.poly"))
# 回帰分析
fit_cs <- lm(tvhours ~ marital, data = gss_cat)
# 回帰分析の結果
summary(fit_cs)
# 回帰分析の係数をtidyで表示
tidy(fit_cs, conf.int = TRUE)
# モデルマトリックス
model.matrix(fit_cs) |> unique()
```
ここでも出力される係数は5つであるが,ここでは最後のカテゴリである`Married`が省略されている.しかし,最後のカテゴリである`Married`の係数は0ではない.すべての係数の和が0になるという制約を与えているので,`Married`の係数は他の係数の値の和を0から引いたものとなる.
```{r}
# classという文字が含まれる係数を取り出し,係数の番号を調べる(2から6)
pickCoef(fit_cs, "marital")
# 係数の2から6までを取り出し,その和を求める.
fit_cs$coefficients[2:6] |> sum()
# 直接次のようにしても良い.
fit_cs$coefficients[pickCoef(fit_cs, "marital")] |> sum()
# 和を0から引く
0 - (fit_cs$coefficients[2:6] |> sum())
```
したがって,`Married`の係数は`r 0 - (fit_cs$coefficients[2:6] |> sum())`となる.
`contrasts`の設定を変更して分析を終えたら必ずもとに戻しておく.
```{r}
# デフォルトに戻す
options(contrasts = c(factor = "contr.treatment", ordered = "contr.poly"))
# contrastsを確認
options("contrasts")
```
`lm`ではモデルの中で`contrasts`を指定することもできる.2つの方法で係数を比較してみる.
```{r}
# 回帰分析
fit_cs2_1 <- lm(tvhours ~ marital, data = gss_cat)
# 回帰分析の結果
summary(fit_cs2_1)
# 回帰分析の係数をtidyで表示
tidy(fit_cs2_1, conf.int = TRUE)
# 回帰分析
fit_cs2_2 <- lm(tvhours ~ marital, data = gss_cat,
contrasts = list(marital = "contr.sum"))
# 回帰分析の結果
summary(fit_cs2_2)
# 回帰分析の係数をtidyで表示
tidy(fit_cs2_2)
```
では結果を図にしてみる.
```{r}
# termのカテゴリ名を変換し,最後に`No answer`の行を加える.
est_ct <- fit_ct |>
tidy(conf.int = TRUE) |> # 回帰分析の係数をtidyで表示し,信頼区間もつける
mutate(term = case_when(
grepl("Never", term) ~ "Never married",
grepl("Separated", term) ~ "Separated",
grepl("Divorced", term) ~ "Divorced",
grepl("Widowed", term) ~ "Widowed",
grepl("Married", term) ~ "Married",
.default = term
)) |>
add_row(term = "No answer", estimate = 0)
est_ct
# 結果を図示する.
fig_ct <- est_ct |>
ggplot(aes(x = term,
y = estimate,
ymin = conf.low,
ymax = conf.high)) +
geom_pointrange() +
theme_minimal()
fig_ct
# termのカテゴリ名を変換し,最後に`Married`の行を加える.
est_cs <- fit_cs |>
tidy(conf.int = TRUE) |>
mutate(term = case_match(term,
"marital1" ~ "No answer",
"marital2" ~ "Never married",
"marital3" ~ "Separated",
"marital4" ~ "Divorced",
"marital5" ~ "Widowed",
"marital6" ~ "Married",
.default = term)) |>
add_row(term = "Married",
estimate = 0 - (fit_cs$coefficients[2:6] |> sum()))
# 結果を図示する.
fit_cs <- est_cs |>
ggplot(aes(x = term,
y = estimate,
ymin = conf.low,
ymax = conf.high)) +
geom_pointrange() +
theme_minimal()
fit_cs
# 図を並べる
ggpubr::ggarrange(fig_ct, fit_cs, nrow = 2)
```
## 表2.1 (p.11) {#sec-tab2_1}
まずp.11の表2.1を再現する.クロス表に周辺度数を追加する場合は,`addmargins`を用いる.
```{r}
# 度数
Freq <- c( 40, 250,
160,3000)
Freq
```
ベクトルを表にする.ここでは`as.table`でクラスを`table`としている.
```{r}
# 行列を作成し,表とする.
tab_2.1 <- matrix(
Freq,
nrow = 2,
ncol = 2,
byrow = TRUE,
dimnames = c(list(
Member = c("Member", "Nonmember"),
Position = c("Have subordinates",
"No subordinates")
))
) |> as.table()
tab_2.1
```
周辺分布とモザイクプロットも確認する.本書で指摘されている関係性が図からも見て取れる.
```{r}
# 周辺分布の表示
Margins(tab_2.1)
# モザイクプロット
vcd::mosaic(tab_2.1, shade = TRUE, keep_aspect_ratio = FALSE)
```
::: {.callout-tip collapse="true"}
## ggplotでモザイクプロット
図はすべて`ggplot()`を使用して描きたいという場合は,`ggmosaic`パッケージを用いる.
その前に集計データを`vcdExtra::expand.dft()`によって個票データに変換し,`ggmosaic::geom_mosaic`を使用する.
```{r}
# パッケージの呼び出し
library(ggmosaic)
library(vcdExtra)
# データの変換
df_tab_2.1 <- vcdExtra::expand.dft(data.frame(tab_2.1), dreq = "Freq") |> tibble()
df_tab_2.1
# ggplotでモザイクプロット
df_tab_2.1 |>
ggplot() +
ggmosaic::geom_mosaic(aes(x = product(Position, Member), fill = Position)) +
scale_fill_viridis_d() +
coord_flip() # mosaicと表示をあわせる
```
:::
表に`addmargins()`で周辺度数を追加する.
```{r}
# A. 度数(周辺度数の追加)
tab_2.1 |> addmargins()
```
表の数字を用いてオッズ比を計算する.
```{r}
# B. Odds
x <- tab_2.1
# 1行1列と1行2列
x[1,1]/x[1,2]
# 2行1列と2行2列
x[2,1]/x[2,2]
# C. Odds ratio
OR <- (x[1,1]/x[1,2]) / (x[2,1]/x[2,2])
OR
```
(対数)オッズ比の信頼区間をもとめる.
```{r}
# 対数オッズの標準誤差を求める
SD <- sqrt(1/x[1,1] + 1/x[1,2] + 1/x[2,1] + 1/x[2,2])
# 対数オッズ比の信頼区間を求める
CI_log_OR <- log(OR) + qnorm(c(0.025, 0.975)) * SD
CI_log_OR
# オッズ比の信頼区間を求める
exp(CI_log_OR)
```
`DescTools`パッケージの`OddsRatio`関数を用いてオッズ比を求める.`conf.level = 0.95`とすることで信頼区間を求めることもできる.
先程計算したものと値が一致している.
```{r}
# OddsRatio関数を用いる
OddsRatio(tab_2.1, conf.level = 0.95)
```
::: {.callout-tip}
## 関数の中身を確認する.
`OddsRatio()`がどのような処理をしているのかについては`OddsRatio`と入力し,関数の中身をみることで確認できる.ただし,`UseMethod("OddsRatio")`となっており,詳細が分からないことがある.その場合は,`methods()`を用いる.そして,`OddsRatio.default*`のように`*`がついているものについて`DescTools:::OddsRatio.default`のように入力することで中身を確認することができる.`getAnywhere(OddsRatio.default)`としてもよい.
```{r}
#| eval: false
# OddsRatio関数の中身を確認
OddsRatio
# methods関数を用いてどこにアクセスすればよいかを確認する
methods(OddsRatio)
# DescTools関数のOddsRatio.defaultの中身を確認する
DescTools:::OddsRatio.default
# getAnywhereを利用する
getAnywhere(OddsRatio.default)
```
::::
さらに詳細な結果をみたければ`DescTools`パッケージの`Desc`を用いる.
```{r}
# 詳細なクロス表の分析
Desc(tab_2.1)
```
次にセルの組み合わせを単位とした集計データを作成し,`gnm`を適用することでオッズ比を求めてみたい.`gl()`は`n`個の水準のある因子を作成する.`k`は各水準を何度繰り返すのかを指定する.`length`でベクトルの長さを設定することで,その長さになるまで因子の作成が繰り返される.
```{r}
# 度数のベクトル
Freq
# 行変数 1,2の水準のそれぞれを2回くりかえす
COMM <- gl(n = 2, k = 2) # rep(c(1, 2), each = 2) |> factor()
COMM
# 列変数 1,2の水準を大きさが4となるまでそれぞれを1回くりかえす
SUP <- gl(n = 2, k = 1, length = 4) # rep(c(1, 2), times = 2) |> factor()
SUP
# 度数,行変数,列変数からなるデータを作成
freq_tab_2.1 <- tibble(COMM, SUP, Freq)
# データの確認
freq_tab_2.1
```
分析には通常は`glm`を用いるが,後の分析とあわせて`gnm`によって推定する.結果は異ならない.`family = poisson`という指定を忘れないようにすること.何も指定しないと`family = gaussian`となり,エラーなどを出さずに通常の線形回帰分析を行ってしまうので注意する.
```{r}
# gnmで推定
fit <- freq_tab_2.1 |>
gnm(Freq ~ COMM + SUP + COMM:SUP, data = _, family = poisson)
# 結果
summary(fit)
tidy(fit, conf.int = TRUE)
```
`COMM2:SUP2`の係数は1.0986である.これは対数オッズなので,指数関数`exp`を適用してオッズ比を求める.
```{r}
# Odds ratios fit$coefficientsのCOMM2:SUP2の要素のみを取り出し,指数関数expを適用
fit$coefficients["COMM2:SUP2"] |> exp()
fit |> confint("COMM2:SUP2") |> exp()
```
次のようにしてもよい.
```{r}
# 係数の"COMM2:SUP2"の部分のみを取り出し,expを使用
coef(fit)["COMM2:SUP2"] |> exp()
# 信頼区間の行が"COMM2:SUP2"の部分のみを取り出し,expを使用
confint(fit)["COMM2:SUP2",] |> exp()
```
他の係数についてもまとめて示したければ`tidy`関数を用いる.
```{r}
# 係数をtidyを用いて表示し,expを適用した新たな変数を作成する.
tidy(fit, conf.int = TRUE) |>
mutate(odds_ratio = exp(estimate),
or_conf.high = exp(conf.high),
or_conf.low = exp(conf.low))
```
## 表2.3A (p.32)
まずは表2.3Aを作成する.値をベクトルの形式で入力する.
```{r}
# 表2.3Aの値を入力
Freq <- c( 39, 50, 18, 4,
140, 178, 85, 23,
108, 195, 97, 23,
238, 598, 363, 111,
78, 250, 150, 55,
50, 200, 208, 74,
8, 29, 46, 21)
```
ベクトルのデータを`matrix`で行列にし,最終的には`as.table`でtable形式にする.
```{r}
# データを表形式に変換
tab_2.3A <- matrix(
Freq,
nrow = 7,
ncol = 4,
byrow = TRUE,
dimnames = c(list(
polviews = c(
"Strongly liberal",
"Liberal",
"Slightly liberal",
"Moderate",
"Slightly conservative",
"Conservative",
"Strongly conservative"),
fefam = c("Strongly Disagree",
"Disagree",
"Agree",
"Strongly agree")
))) |> as.table()
tab_2.3A
```
```{r}
# 度数,行変数,列変数からなる集計データを作成
polviews <- gl(n = 7, k = 4) # 1-7までの各数字について4つ値を出す
fefam <- gl(n = 4, k = 1, length = 28) # 1-4までの数字の列を長さが28になるまで繰り返す
# Freq, polviews, fefamからなるデータを作成
freq_tab_2.3A <- tibble(Freq, polviews, fefam)
freq_tab_2.3A
```
- なお`tab_2.3A`に対して,data.frameを適用しても集計データは作成される.tableの行変数と列変数が指定されていないと,行変数は`Var1`,列変数は`Var2`となるので,必要に応じて名前を`rename`で修正する.
```{r}
# 表データにdata.frameを適用し,tibble形式で表示
data.frame(tab_2.3A) |> tibble()
```
以下では複数のモデルの適合度を比較する.そこで,モデル適合度を表示するための関数を作成する.モデルはすべて`gnm`によって推定されることを前提としている.`glm`の場合はエラーが出るので注意すること.
```{r}
# 引数となるobjはgnmの結果
model.summary <- function(obj, Model = NULL){
if (sum(class(obj) == "gnm") != 1)
stop("estimate with gnm")
aic <- obj$deviance - obj$df * 2 # AIC(L2)
bic <- obj$deviance - obj$df * log(sum(obj$y)) #BIC(L2)
delta <- 100 * sum(abs(obj$y - obj$fitted.values)) / (2 * sum(obj$y))
p <- pchisq(obj$deviance, obj$df, lower.tail = FALSE) #p<-ifelse(p<0.001,"<0.001",p)
result <- matrix(0, 1, 7)
if (is.null(Model)){
Model <- deparse(substitute(obj))
}
result <- tibble(
"Model Description" = Model,
"df" = obj$df,
"L2" = obj$deviance,
#"AIC(L2)" = aic,
"BIC" = bic,
"Delta" = delta,
"p" = p
)
return(result)
}
```
コントラストがデフォルトの`factor = "contr.treatment"`と`ordered = "contr.poly"`になっているのかを確認する.
```{r}
# デフォルトのcontrasts
options("contrasts")
# defaultのcontrastsの設定(ここでは特に意味はない.constrastをいじった後にデフォルトに戻す)
options(contrasts = c(factor = "contr.treatment",
ordered = "contr.poly"))
```
行スコアと列スコアを用いるので,まず`as.integer`を用いて行スコア(`Rscore`)と列スコア(`Cscore`)の変数を作成する.
```{r}
# 行変数と列変数の整数値を作成
freq_tab_2.3A <- freq_tab_2.3A |>
mutate(Rscore = as.integer(polviews),
Rscore = Rscore - mean(Rscore),
Cscore = as.integer(fefam),
Cscore = Cscore - mean(Cscore))
freq_tab_2.3A
```
### 独立モデル
独立モデルは次のようになる.
```{r}
# 1. O: Independence/Null Association Model
O <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam,
family = poisson,
data = _,
tolerance = 1e-12
)
# 結果
summary(O)
tidy(O)
glance(O)
```
先ほど作成した適合度の関数を用いる.2つめの引数はモデルの名前の詳細を記述可能だが,これは省略してもよい.省略するとモデルをフィットさせた結果のオブジェクトの名前が表示される.
```{r}
# モデル適合度
model.summary(O, "O:Independent")
```
テキストの表2.4と同じ結果になっているのかを確認してみる.期待度数は様々な方法でとりだすことができる.ここでは元の観測度数の値も表示される`broom`パッケージの`augment`関数を用いる.
```{r}
# broomのaugmentで期待度数を求め,それをもとにL2とBICを計算
broom::augment(O, newdata = freq_tab_2.3A, type.predict = "response") |>
dplyr::summarise(L2 = sum(Freq * log(Freq / .fitted)) * 2,
BIC = L2 - summary(O)$df.residual * log(sum(Freq)))
# predict関数で期待度数を求める
predict(O, newdata = freq_tab_2.3A, type = "response")
# 結果から期待度数を取り出す.
O$fitted.values
```
### 一様連関モデル
一様連関モデルでは先ほど作成した行変数と列変数の整数スコアの積である`Rscore:Cscore`を加える.`Rscore*Cscore`あるいは`I(Rscore*Cscore)`でもよい.
```{r}
# 2. U: Uniform Association Model
U <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Rscore:Cscore,
family = poisson,
data = _,
tolerance = 1e-12)
```
```{r}
# 結果
summary(U)
# 信頼区間もあわせてtidyで表示
tidy(U, conf.int = TRUE)
```
表2.4Aと同じ結果になっているのかを確認する.
```{r}
# モデル適合度
model.summary(U, "U:Uniform")
```
モデル行列を確認するのもよいだろう.
```{r}
# model.matrixを適用し,ユニークな値だけを表示
model.matrix(U) |> unique()
```
### 行効果モデル
contrastを修正し,polviewsの係数のすべてを足すと0になるように効果コーディングを行ってる.なお行変数と列スコアの積については`Cscore*polviews`とし,`Cscore:polviews`としない.
```{r}
# contrastを修正している.
options(contrasts = c(factor = "contr.sum",
ordered = "contr.treatment"))
options("contrasts")
# 3. R: Row Effect Model
R <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Cscore*polviews,
family = poisson,
data = _,
tolerance = 1e-12)
# 結果
summary(R)
# 信頼区間もあわせてtidyで表示
tidy(R, conf.int = TRUE)
# モデル適合度
model.summary(R, "R:Row effect")
# モデル行列の確認
model.matrix(R) |> unique()
```
表2.4の適合度を確認しよう.また,パラメータ推定値については,表2.5のBから確認する.
Rの結果では,polviews1からpolviews6までの結果が表示されているが,polviews7は示されていない.パラメータのすべての値を足すと0となることから($\sum \tau_i^A=0$),polviews7の係数は`0-(-0.6721737)=0.6721737`となる.これをRで計算するためには係数を取り出し,それらを足したものを0から引けばよい.
```{r}
# R
# 取り出す係数を探す
pickCoef(R, ":Cscore")
# 12から17番目の係数を取り出し,足す
R$coefficients[12:17] |> sum()
# 次のようにもできる
R$coefficients[pickCoef(R, ":Cscore")] |> sum()
# 0から足したものを引く
0 - (R$coefficients[pickCoef(R, ":Cscore")] |> sum())
```
contrastsをもとに戻して同様の分析を行う.
今度は`polviews1:Cscore`の係数が省略されているが,この値は0である($\tau_1^A=0$).
```{r}
# alternative (default)
options(contrasts = c(factor = "contr.treatment",
ordered = "contr.poly"))
Ralt <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Cscore*polviews,
family = poisson,
data = _,
tolerance = 1e-12)
```
結果は表2.5Bの「他の正規化」の行を確認して欲しい.
```{r}
# 結果
summary(Ralt)
# 信頼区間もあわせてtidyで表示
tidy(Ralt, conf.int = TRUE)
```
モデルの適合度は全く同じであることがわかる.
```{r}
# モデル適合度
model.summary(R, "R: Row effect (effect coding)")
model.summary(Ralt, "R: Row effect (dummy coding)")
```
```{r}
# モデル行列の確認
model.matrix(Ralt) |> unique()
```
## 列効果モデル
列効果モデルは行効果モデルと同様の方法で推定すればよい.まずは効果コーディングで推定し,その後にダミーコーディングで推定する.
```{r}
# contrast
options(contrasts = c(factor = "contr.sum",
ordered = "contr.treatment"))
# 4. C: Column Effect Model
C <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Rscore*fefam, family = poisson,
data = _,
tolerance = 1e-12)
# 結果
summary(C)
# 信頼区間もあわせてtidyで表示
tidy(C, conf.int = TRUE)
# モデル適合度
model.summary(C, "C:Column effect")
# モデル行列の確認
model.matrix(C) |> unique()
```
すべてを足すと0となることから($\sum \tau_j^B=0$),polviews7の係数は`0-(-0.2496118)=0.2496118`となる
```{r}
pickCoef(C, ":Rscore")
C$coefficients[pickCoef(C, ":Rscore")] |> sum()
0 - (C$coefficients[pickCoef(C, ":Rscore")] |> sum())
```
以下はダミーコーディングを用いている.
```{r}
# alternative (default)
options(contrasts = c(factor = "contr.treatment",
ordered = "contr.poly"))
# 4. C: Column Effect Model (default)
Calt <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Rscore*fefam,
family = poisson,
data = _,
tolerance = 1e-12)
```
推定値は表2.5Cを確認せよ.
```{r}
# 結果
summary(Calt)
# 信頼区間もあわせてtidyで表示
tidy(Calt, conf.int = TRUE)
```
適合度は効果コーディングとダミーコーディングで変化しない.
```{r}
# モデル適合度
model.summary(C, "C:Column effect (effect coding)")
model.summary(Calt, "C:Column effect (dummy coding)")
```
```{r}
# モデル行列の確認
model.matrix(Calt) |> unique()
```
## 行・列効果モデル($R+C$)
普通に推定しても収束しない.
```{r}
# コントラスト
options(contrasts = c(factor = "contr.treatment",
ordered = "contr.treatment"))
# 5. R+C: Row and Column Effect Model
# 収束しない
RplusCno <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Cscore:polviews + Rscore:fefam,
family = poisson,
data = _,
tolerance = 1e-12)
```
係数を確認する.この場合,制約は3つ必要であるが2つしかNAとなっていない.テキストや表2.5Dを参照し,どのような制約を課すのかをきめる.ここでは表2.5Dのような制約を課す.
```{r}
RplusCno
pickCoef(RplusCno, ":Cscore") # 行効果
pickCoef(RplusCno, ":Rscore") # 列効果
```
あるいは次のように一覧にしてもよい.
```{r}
# 変数と係数と係数の順番を表示
data.frame(var = names(RplusCno$coefficients),
estimate = RplusCno$coefficients) |>
mutate(estimate = estimate,
number = row_number())
```
制約を課すのは11番目,17番目,18番目の係数であり,これらを0にする.対象となる係数は`constrain = c(11,17,18)`で指定し,制約は`constrainTo = c(0, 0, 0)`とする.あとは同じである.
```{r}
# polviews1:Cscore(11) = polviews7:Cscore(17) = fefam1:Rscore(18) = 0
RplusC <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Cscore:polviews + Rscore:fefam,
constrain = c(11, 17, 18),
constrainTo = c(0, 0, 0),
family = poisson,
data = _,
tolerance = 1e-12)
# 結果
summary(RplusC)
# モデル適合度
model.summary(RplusC)
```
11番目,18番目,21番目の係数を0にして推定する.
```{r}
# polviews1:Cscore(11) = polviews7:Cscore(17) = fefam1:Rscore(18) = 0
RplusC_2 <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Cscore:polviews + Rscore:fefam,
constrain = c(11, 18, 21),
constrainTo = c(0, 0, 0),
family = poisson,
data = _,
tolerance = 1e-12)
# 結果
summary(RplusC_2)
# モデル適合度
model.summary(RplusC_2)
```
`Rscore:Cscore`を含めて推定すれば,制約は自動的に課されており(`polviews`の1番目と7番目,`fefam`の1 番目と4番目),特に指定する必要はない.
```{r}
# 5. R+C: Row and Column Effect Model (Alternative)
RplusCalt <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Rscore:Cscore + Cscore:polviews + Rscore:fefam,
family = poisson,
data = _,
tolerance = 1e-12)
# 結果
summary(RplusCalt)
# モデル適合度
model.summary(RplusCalt)
```
## 行・列効果モデル($RC(1)$)
RC(1)については`Mult(1,polviews,fefam)`を含んだモデルで推定する.結果をみると係数は表示されているものの,標準誤差はNAとなっている.
```{r}
# 6. RC: RC(1) model
RC.un <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Mult(1,polviews,fefam),
family = poisson,
data = _,
tolerance = 1e-12)
# 結果
summary(RC.un)
# モデル適合度
model.summary(RC.un)
```
まずは「重みづけのないまたは単位標準化した解」を求める.`scaleWeights = "unit"`とする.`RC.un`から`.polviews`のある変数を`pickCoef(RC.un, "[.]polviews")`によって取り出す.
```{r}
# mu[i], i = 1 to 7
mu <- getContrasts(RC.un, pickCoef(RC.un,
"[.]polviews"),
ref = "mean",
scaleRef = "mean",
scaleWeights = "unit")
# 値の方向を揃える
if (mu$qvframe[1,1] > 0 ) {
mu$qvframe[,1] <- -1 * mu$qvframe[,1]
}
# 合計が0,2乗和が1となっていること確認する.
list("和" = sum(mu$qvframe[,1]),
"2乗和" = sum(mu$qvframe[,1]^2))
# nu[j], j = 1 to 4
nu <- getContrasts(RC.un, pickCoef(RC.un, "[.]fefam"),
ref = "mean",
scaleRef = "mean",
scaleWeights = "unit")
# 値の方向を揃える
if (nu$qvframe[1,1] > 0 ) {
nu$qvframe[,1] <- -1 * nu$qvframe[,1]
}
# 合計が0,2乗和が1となっていること確認する.
list("和" = sum(nu$qvframe[,1]),
"2乗和" = sum(nu$qvframe[,1]^2))
# muの1番目と7番目,nuの1番目と4番目の値を取り出し保存する.
con <- c(mu$qvframe[,1][c(1,7)],
nu$qvframe[,1][c(1,4)])
```
```{r}
#保存した値で制約を課した上で,再推定する.
set.seed(1234)
RC <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Mult(1,polviews,fefam),
constrain = c(12,18,19,22),
constrainTo = con,
family = poisson,
data = _,
tolerance = 1e-12)
```
`Deviance is not finite 警告メッセージ: Algorithm failed - no model could be estimated `と表示されたらもう一度推定する.`set.seed`の値をいくつか変えて実行するのがよい.
表2.5Eの値と一致しているのかを確認する.
```{r}
# 結果
summary(RC)
```
先ほどの単位標準化した解と推定の結果が一致しているのかを確認する.
```{r}
# 指定したmuとnuの値と結果が一致しているかを確認
list(mu = mu, nu = nu)
```
和が0,2乗和が1となっていることを確認
```{r}
sum(mu$qvframe[,1])
sum(mu$qvframe[,1]^2)
sum(nu$qvframe[,1])
sum(nu$qvframe[,1]^2)
```
適合度は変化していない.
```{r}
# モデル適合度
model.summary(RC.un)
model.summary(RC)
```
## 周辺重みづけ
```{r}
# 行の周辺確率
rp <- prop.table(apply(tab_2.3A, 1, sum, na.rm = TRUE))
rp
sum(rp)
# 列の周辺確率
cp <- prop.table(apply(tab_2.3A, 2, sum, na.rm = TRUE))
cp
sum(cp)
# mu[i], i = 1 to 7
mu <- getContrasts(RC.un, pickCoef(RC.un,
"[.]polviews"),
ref = rp,
scaleRef = rp,
scaleWeights = rp)
# 値の方向を揃える
if (mu$qvframe[1,1] > 0 ) {
mu$qvframe[,1] <- -1 * mu$qvframe[,1]
}
# nu[j], j = 1 to 4
nu <- getContrasts(RC.un, pickCoef(RC.un, "[.]fefam"),
ref = cp,
scaleRef = cp,
scaleWeights = cp)
# 値の方向を揃える
if (nu$qvframe[1,1] > 0 ) {
nu$qvframe[,1] <- -1 * nu$qvframe[,1]
}
# muの1番目と7番目,nuの1番目と4番目の値を取り出し保存する.
con <- c(mu$qvframe[,1][c(1,7)],
nu$qvframe[,1][c(1,4)])
```
```{r}
#保存した値で制約を課した上で,再推定する.
set.seed(1234)
RC_mw <- freq_tab_2.3A |>
gnm(Freq ~ polviews + fefam + Mult(1,polviews,fefam),
constrain = c(12,18,19,22),
constrainTo = con,
family = poisson,
data = _,
tolerance = 1e-12)
```
```{r}
# 結果
summary(RC_mw)
```
内的連関パラメータ$\phi$が0.25673となっている.場合によっては符号が逆となる.
適合度は変化していない.
```{r}
# モデル適合度
model.summary(RC.un)
model.summary(RC)
model.summary(RC_mw)
```