[解決済み】「コントラストは2つ以上の水準を持つ要因にのみ適用できる」エラーのデバッグ方法とは?
質問
私が扱っているすべての変数がここにあります。
str(ad.train)
$ Date : Factor w/ 427 levels "2012-03-24","2012-03-29",..: 4 7 12 14 19 21 24 29 31 34 ...
$ Team : Factor w/ 18 levels "Adelaide","Brisbane Lions",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Season : int 2012 2012 2012 2012 2012 2012 2012 2012 2012 2012 ...
$ Round : Factor w/ 28 levels "EF","GF","PF",..: 5 16 21 22 23 24 25 26 27 6 ...
$ Score : int 137 82 84 96 110 99 122 124 49 111 ...
$ Margin : int 69 18 -56 46 19 5 50 69 -26 29 ...
$ WinLoss : Factor w/ 2 levels "0","1": 2 2 1 2 2 2 2 2 1 2 ...
$ Opposition : Factor w/ 18 levels "Adelaide","Brisbane Lions",..: 8 18 10 9 13 16 7 3 4 6 ...
$ Venue : Factor w/ 19 levels "Adelaide Oval",..: 4 7 10 7 7 13 7 6 7 15 ...
$ Disposals : int 406 360 304 370 359 362 365 345 324 351 ...
$ Kicks : int 252 215 170 225 221 218 224 230 205 215 ...
$ Marks : int 109 102 52 41 95 78 93 110 69 85 ...
$ Handballs : int 154 145 134 145 138 144 141 115 119 136 ...
$ Goals : int 19 11 12 13 16 15 19 19 6 17 ...
$ Behinds : int 19 14 9 16 11 6 7 9 12 6 ...
$ Hitouts : int 42 41 34 47 45 70 48 54 46 34 ...
$ Tackles : int 73 53 51 76 65 63 65 67 77 58 ...
$ Rebound50s : int 28 34 23 24 32 48 39 31 34 29 ...
$ Inside50s : int 73 49 49 56 61 45 47 50 49 48 ...
$ Clearances : int 39 33 38 52 37 43 43 48 37 52 ...
$ Clangers : int 47 38 44 62 49 46 32 24 31 41 ...
$ FreesFor : int 15 14 15 18 17 15 19 14 18 20 ...
$ ContendedPossessions: int 152 141 149 192 138 164 148 151 160 155 ...
$ ContestedMarks : int 10 16 11 3 12 12 17 14 15 11 ...
$ MarksInside50 : int 16 13 10 8 12 9 14 13 6 12 ...
$ OnePercenters : int 42 54 30 58 24 56 32 53 50 57 ...
$ Bounces : int 1 6 4 4 1 7 11 14 0 4 ...
$ GoalAssists : int 15 6 9 10 9 12 13 14 5 14 ...
以下は、私がフィットさせようとしているglmです。
ad.glm.all <- glm(WinLoss ~ factor(Team) + Season + Round + Score + Margin + Opposition + Venue + Disposals + Kicks + Marks + Handballs + Goals + Behinds + Hitouts + Tackles + Rebound50s + Inside50s+ Clearances+ Clangers+ FreesFor + ContendedPossessions + ContestedMarks + MarksInside50 + OnePercenters + Bounces+GoalAssists,
data = ad.train, family = binomial(logit))
変数の数が多いのは分かっています(前方変数選択で減らす予定です)。しかし、変数が多いといっても、それらはintかfactorのどちらかです。しかし、このモデルをフィットさせようとするたびに、次のような結果が得られます。
Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : contrasts can be applied only to factors with 2 or more levels
これは、Rが何らかの理由で私のファクター変数をファクター変数として扱っていないように見えるのですが?
というような単純なものでも
ad.glm.test <- glm(WinLoss ~ factor(Team), data = ad.train, family = binomial(logit))
は動作しません! (同じエラーメッセージ)
このようなところ。
ad.glm.test <- glm(WinLoss ~ Clearances, data = ad.train, family = binomial(logit))
動作します!
どなたか、何が起こっているのかご存じですか?なぜ、このFactor変数をglmに当てはめることができないのでしょうか?
ありがとうございました。
-トロイ
解決方法は?
はじめに
対照誤差とは何か、それはよく説明されています:水準が1つしかない(またはそれ以下の)因子があるとします。
. しかし、実際には、モデルフィッティングに実際に使われるデータが、渡したものと大きく異なることがあるため、この単純な事実が簡単に隠されてしまうことがあるのです。このようなことが起こるのは
NA
データをサブセット化した場合、因子が未使用のレベルである場合、変数を変換した場合などです。
NaN
のどこかにあるはずです。
から1レベルの因子を発見できるような、このような理想的な状況になることはほとんどありません。
str(your_data_frame)
を直接表示します。
このエラーに関するStackOverflowの多くの質問は再現性がないため、人による提案はうまくいくかもしれませんし、いかないかもしれません。そのため、現在では
118件の投稿
この問題に関して、ユーザーはまだ適応的な解決策を見つけることができないので、この質問は何度も提起されています。この回答は、この問題を解決するための私の試みであり、少なくとも合理的なガイドを提供するものです。
この回答は情報量が多いので、まず簡単にまとめておきます。
3つのヘルパー関数を定義しておきました。
debug_contr_error
,
debug_contr_error2
,
NA_preproc
.
といった使い方がおすすめです。
-
走る
NA_preproc
を実行すると、より完全なケースが得られます。 -
モデルを実行し、もし "コントラストエラー" が発生したら、次のようにします。
debug_contr_error2
をデバッグに使用します。
ほとんどの回答は、これらの関数がどのように定義されているか、そしてなぜ定義されているかを段階的に示しています。しかし、quot;再現性のあるケーススタディと議論"のセクションは飛ばさないようにしましょう。
修正後の回答
は
オリジナル回答
はOPに最適です。
そして
は、他の何人かを助けることに成功しました。
. しかし
他の場所で失敗した
適応力不足で の出力を見てください。
str(ad.train)
を質問しています。OPの変数は数値か因子であり、文字はありません。元々の回答はこのような状況を想定したものです。文字変数がある場合、変数中に係数に強制されますが
lm
と
glm
を適用した場合、それらは要因として提供されなかったので、コードによって報告されません。
is.factor
は見逃してしまいます。今回の拡張で、私は元の答えの両方をより適応的にするつもりです。
とする。
dat
に渡されるデータセットです。
lm
または
glm
. このようなデータフレームがなかなかない場合、つまり、すべての変数がグローバル環境に散らばっている場合は、それらをデータフレームに集める必要があります。以下の方法はベストな方法ではないかもしれませんが、うまくいきます。
## `form` is your model formula, here is an example
y <- x1 <- x2 <- x3 <- 1:4
x4 <- matrix(1:8, 4)
form <- y ~ bs(x1) + poly(x2) + I(1 / x3) + x4
## to gather variables `model.frame.default(form)` is the easiest way
## but it does too much: it drops `NA` and transforms variables
## we want something more primitive
## first get variable names
vn <- all.vars(form)
#[1] "y" "x1" "x2" "x3" "x4"
## `get_all_vars(form)` gets you a data frame
## but it is buggy for matrix variables so don't use it
## instead, first use `mget` to gather variables into a list
lst <- mget(vn)
## don't do `data.frame(lst)`; it is buggy with matrix variables
## need to first protect matrix variables by `I()` then do `data.frame`
lst_protect <- lapply(lst, function (x) if (is.matrix(x)) I(x) else x)
dat <- data.frame(lst_protect)
str(dat)
#'data.frame': 4 obs. of 5 variables:
# $ y : int 1 2 3 4
# $ x1: int 1 2 3 4
# $ x2: int 1 2 3 4
# $ x3: int 1 2 3 4
# $ x4: 'AsIs' int [1:4, 1:2] 1 2 3 4 5 6 7 8
## note the 'AsIs' for matrix variable `x4`
## in comparison, try the following buggy ones yourself
str(get_all_vars(form))
str(data.frame(lst))
ステップ0:明示的なサブセット
もし、あなたが
subset
の引数は
lm
または
glm
のように、明示的なサブセットで開始します。
## `subset_vec` is what you pass to `lm` via `subset` argument
## it can either be a logical vector of length `nrow(dat)`
## or a shorter positive integer vector giving position index
## note however, `base::subset` expects logical vector for `subset` argument
## so a rigorous check is necessary here
if (mode(subset_vec) == "logical") {
if (length(subset_vec) != nrow(dat)) {
stop("'logical' `subset_vec` provided but length does not match `nrow(dat)`")
}
subset_log_vec <- subset_vec
} else if (mode(subset_vec) == "numeric") {
## check range
ran <- range(subset_vec)
if (ran[1] < 1 || ran[2] > nrow(dat)) {
stop("'numeric' `subset_vec` provided but values are out of bound")
} else {
subset_log_vec <- logical(nrow(dat))
subset_log_vec[as.integer(subset_vec)] <- TRUE
}
} else {
stop("`subset_vec` must be either 'logical' or 'numeric'")
}
dat <- base::subset(dat, subset = subset_log_vec)
ステップ1: 不完全なケースの削除
dat <- na.omit(dat)
このステップは、ステップ0を経ていれば、スキップすることができます。
subset
不完全なケースを自動的に削除
.
ステップ2:モードチェックと変換
データフレームのカラムは通常、アトミックベクターで モード 論理値、数値、複素数、文字、生の中から選択します。回帰の場合、異なるモードの変数は異なる方法で処理されます。
"logical", it depends
"numeric", nothing to do
"complex", not allowed by `model.matrix`, though allowed by `model.frame`
"character", converted to "numeric" with "factor" class by `model.matrix`
"raw", not allowed by `model.matrix`, though allowed by `model.frame`
論理変数はやっかいです。ダミー変数として扱うこともできますし (
1
に対して
TRUE
;
0
について
FALSE
というわけで、quot;numeric"または2レベルファクターに強制されることがあります。それはすべて
model.matrix
は、モデル式の仕様から、"to-factor" の強制が必要であると考えます。単純化すると、常に因子に強制されるが、対比を適用した結果、直接ダミーとして扱った場合と同じモデル行列になる可能性がある、というように理解することができます。
なぜ "integer" が含まれていないのかと思われる方もいらっしゃるでしょう。のような整数ベクトルだからです。
1:4
は、quot;numeric" モードを持っています (試しに
mode(1:4)
).
データフレームの列は、"AsIs" クラスを持つ行列でも構いませんが、そのような行列は "numeric"モードを持たなければなりません。
私たちのチェックは、以下の場合にエラーを発生させることです。
- a "complex" または "raw" が見つかりました。
- 論理型または文字型の行列変数が見つかりました。
を、quot;logical" とquot;character" を、quot;factor" クラスの "numeric" に変換する処理を実行する必要があります。
## get mode of all vars
var_mode <- sapply(dat, mode)
## produce error if complex or raw is found
if (any(var_mode %in% c("complex", "raw"))) stop("complex or raw not allowed!")
## get class of all vars
var_class <- sapply(dat, class)
## produce error if an "AsIs" object has "logical" or "character" mode
if (any(var_mode[var_class == "AsIs"] %in% c("logical", "character"))) {
stop("matrix variables with 'AsIs' class must be 'numeric'")
}
## identify columns that needs be coerced to factors
ind1 <- which(var_mode %in% c("logical", "character"))
## coerce logical / character to factor with `as.factor`
dat[ind1] <- lapply(dat[ind1], as.factor)
データフレームのカラムが既に因子変数である場合、そのカラムは
ind1
因子変数はquot;数値モードを持つため、(試しに
mode(factor(letters[1:4]))
).
ステップ3: 未使用の因子レベルを削除する
ステップ2から変換された因子変数、すなわち、以下のようなインデックスを持つ因子変数については、未使用の因子レベルを持たないことにします。
ind1
. ただし、因子変数に
dat
は未使用のレベルを持つかもしれない(多くの場合、ステップ 0 とステップ 1 の結果として)。可能性のある未使用のレベルをそれらから削除する必要があります。
## index of factor columns
fctr <- which(sapply(dat, is.factor))
## factor variables that have skipped explicit conversion in step 2
## don't simply do `ind2 <- fctr[-ind1]`; buggy if `ind1` is `integer(0)`
ind2 <- if (length(ind1) > 0L) fctr[-ind1] else fctr
## drop unused levels
dat[ind2] <- lapply(dat[ind2], droplevels)
ステップ4:因子変数の要約
では、実際にどのような因子レベルがいくつ使用されているかを確認する準備が整いました。
lm
または
glm
:
## export factor levels actually used by `lm` and `glm`
lev <- lapply(dat[fctr], levels)
## count number of levels
nl <- lengths(lev)
これらのステップを関数にまとめると、より簡単になります。
debug_contr_error
.
入力してください。
-
dat
に渡されるデータフレームです。lm
またはglm
を介してdata
引数で指定します。 -
subset_vec
に渡されるインデックスベクタです。lm
またはglm
を介してsubset
引数で指定します。
出力します。 を持つリストです。
-
nlevels
(リスト)は、すべての因子変数の因子レベルの数を与える。 -
levels
(ベクトル) は、すべての因子変数の水準を与える。
この関数は、完全なケースがない場合、または要約する因子変数がない場合、警告を出します。
debug_contr_error <- function (dat, subset_vec = NULL) {
if (!is.null(subset_vec)) {
## step 0
if (mode(subset_vec) == "logical") {
if (length(subset_vec) != nrow(dat)) {
stop("'logical' `subset_vec` provided but length does not match `nrow(dat)`")
}
subset_log_vec <- subset_vec
} else if (mode(subset_vec) == "numeric") {
## check range
ran <- range(subset_vec)
if (ran[1] < 1 || ran[2] > nrow(dat)) {
stop("'numeric' `subset_vec` provided but values are out of bound")
} else {
subset_log_vec <- logical(nrow(dat))
subset_log_vec[as.integer(subset_vec)] <- TRUE
}
} else {
stop("`subset_vec` must be either 'logical' or 'numeric'")
}
dat <- base::subset(dat, subset = subset_log_vec)
} else {
## step 1
dat <- stats::na.omit(dat)
}
if (nrow(dat) == 0L) warning("no complete cases")
## step 2
var_mode <- sapply(dat, mode)
if (any(var_mode %in% c("complex", "raw"))) stop("complex or raw not allowed!")
var_class <- sapply(dat, class)
if (any(var_mode[var_class == "AsIs"] %in% c("logical", "character"))) {
stop("matrix variables with 'AsIs' class must be 'numeric'")
}
ind1 <- which(var_mode %in% c("logical", "character"))
dat[ind1] <- lapply(dat[ind1], as.factor)
## step 3
fctr <- which(sapply(dat, is.factor))
if (length(fctr) == 0L) warning("no factor variables to summary")
ind2 <- if (length(ind1) > 0L) fctr[-ind1] else fctr
dat[ind2] <- lapply(dat[ind2], base::droplevels.factor)
## step 4
lev <- lapply(dat[fctr], base::levels.default)
nl <- lengths(lev)
## return
list(nlevels = nl, levels = lev)
}
以下は、構築された小さな例です。
dat <- data.frame(y = 1:4,
x = c(1:3, NA),
f1 = gl(2, 2, labels = letters[1:2]),
f2 = c("A", "A", "A", "B"),
stringsAsFactors = FALSE)
# y x f1 f2
#1 1 1 a A
#2 2 2 a A
#3 3 3 b A
#4 4 NA b B
str(dat)
#'data.frame': 4 obs. of 4 variables:
# $ y : int 1 2 3 4
# $ x : int 1 2 3 NA
# $ f1: Factor w/ 2 levels "a","b": 1 1 2 2
# $ f2: chr "A" "A" "A" "B"
lm(y ~ x + f1 + f2, dat)
#Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
よかった、エラーが表示されました。では、私の
debug_contr_error
は、その
f2
は1つのレベルで終わります。
debug_contr_error(dat)
#$nlevels
#f1 f2
# 2 1
#
#$levels
#$levels$f1
#[1] "a" "b"
#
#$levels$f2
#[1] "A"
元のショートアンサーは、ここでは絶望的であることに注意してください。
f2
は、因子変数ではなく、文字変数として提供されています。
## old answer
tmp <- na.omit(dat)
fctr <- lapply(tmp[sapply(tmp, is.factor)], droplevels)
sapply(fctr, nlevels)
#f1
# 2
rm(tmp, fctr)
次に、マトリックス変数を使った例を見てみましょう。
x
.
dat <- data.frame(X = I(rbind(matrix(1:6, 3), NA)),
f = c("a", "a", "a", "b"),
y = 1:4)
dat
# X.1 X.2 f y
#1 1 4 a 1
#2 2 5 a 2
#3 3 6 a 3
#4 NA NA b 4
str(dat)
#'data.frame': 4 obs. of 3 variables:
# $ X: 'AsIs' int [1:4, 1:2] 1 2 3 NA 4 5 6 NA
# $ f: Factor w/ 2 levels "a","b": 1 1 1 2
# $ y: int 1 2 3 4
lm(y ~ X + f, data = dat)
#Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
debug_contr_error(dat)$nlevels
#f
#1
水準がない因子変数も、"contrasts error"を引き起こす可能性があることに注意してください。0レベルの因子がどのように可能なのか不思議に思うかもしれません。しかし、それは合法的なものです。
nlevels(factor(character(0)))
. ここで、完全なケースがない場合、0レベルの因子を持つことになります。
dat <- data.frame(y = 1:4,
x = rep(NA_real_, 4),
f1 = gl(2, 2, labels = letters[1:2]),
f2 = c("A", "A", "A", "B"),
stringsAsFactors = FALSE)
lm(y ~ x + f1 + f2, dat)
#Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
debug_contr_error(dat)$nlevels
#f1 f2
# 0 0 ## all values are 0
#Warning message:
#In debug_contr_error(dat) : no complete cases
最後に、もし
f2
は論理変数です。
dat <- data.frame(y = 1:4,
x = c(1:3, NA),
f1 = gl(2, 2, labels = letters[1:2]),
f2 = c(TRUE, TRUE, TRUE, FALSE))
dat
# y x f1 f2
#1 1 1 a TRUE
#2 2 2 a TRUE
#3 3 3 b TRUE
#4 4 NA b FALSE
str(dat)
#'data.frame': 4 obs. of 4 variables:
# $ y : int 1 2 3 4
# $ x : int 1 2 3 NA
# $ f1: Factor w/ 2 levels "a","b": 1 1 2 2
# $ f2: logi TRUE TRUE TRUE FALSE
デバッガは "Contrasts error" を予測しますが、本当にそうなるでしょうか?
debug_contr_error(dat)$nlevels
#f1 f2
# 2 1
いや、少なくともこれは失敗してませんよ(
その
NA
の係数は、モデルのランク不足によるものなので、気にしないでください。
):
lm(y ~ x + f1 + f2, data = dat)
#Coefficients:
#(Intercept) x f1b f2TRUE
# 0 1 0 NA
エラーになるような例はなかなか思いつきませんが、その必要もないでしょう。実際には、デバッガは予測のために使うのではなく、本当にエラーが発生したときに使うのです。
もしかしたら、論理変数もダミーと変わらないという意見もあるかもしれません。しかし、以下の簡単な例を試してみてください。
u <- c(TRUE, TRUE, FALSE, FALSE)
v <- c(1, 1, 0, 0) ## "numeric" dummy of `u`
model.matrix(~ u)
# (Intercept) uTRUE
#1 1 1
#2 1 1
#3 1 0
#4 1 0
model.matrix(~ v)
# (Intercept) v
#1 1 1
#2 1 1
#3 1 0
#4 1 0
model.matrix(~ u - 1)
# uFALSE uTRUE
#1 0 1
#2 0 1
#3 1 0
#4 1 0
model.matrix(~ v - 1)
# v
#1 1
#2 1
#3 0
#4 0
を使用したより柔軟な実装が可能です。
"model.frame"
メソッドの
lm
を経由することもお勧めします。
R: 線形モデルおよび予測のための "因子が新しいレベルを持っている" エラーをデバッグする方法
を説明しています。
lm
と
glm
は、データセットに対して水面下で行われます。上記のステップ0から4は、このような内部処理を模倣しようとしているに過ぎないことが理解できるだろう。覚えておいてください。
で渡したデータと、実際にモデルフィッティングに使われるデータが大きく異なる場合があります。
.
私たちのステップは、このような内部処理と完全に一致するものではありません。比較のために、内部処理の結果を取得するために
method = "model.frame"
で
lm
と
glm
. 先に作成した小さな例で試してみましょう
dat
ここで
f2
は文字変数である。
dat_internal <- lm(y ~ x + f1 + f2, dat, method = "model.frame")
dat_internal
# y x f1 f2
#1 1 1 a A
#2 2 2 a A
#3 3 3 b A
str(dat_internal)
#'data.frame': 3 obs. of 4 variables:
# $ y : int 1 2 3
# $ x : int 1 2 3
# $ f1: Factor w/ 2 levels "a","b": 1 1 2
# $ f2: chr "A" "A" "A"
## [.."terms" attribute is truncated..]
実際には
model.frame
は、ステップ0とステップ1しか実行しません。また、データセットで提供され、モデル式で提供されない変数も削除されます。そのため、モデルフレームの行や列の数は、あなたが入力したものよりも少なくなる可能性があります。
lm
と
glm
. ステップ 2 で行われたようなタイプ強制は、後の
model.matrix
ここで、quot;contrasts error"が発生することがあります。
まずこの内部モデルフレームを取得し、それを
debug_contr_error
(実質的にステップ2~4のみを実行するように)。
利点1:モデル式で使用されていない変数は無視される
## no variable `f1` in formula
dat_internal <- lm(y ~ x + f2, dat, method = "model.frame")
## compare the following
debug_contr_error(dat)$nlevels
#f1 f2
# 2 1
debug_contr_error(dat_internal)$nlevels
#f2
# 1
利点2:変換された変数に対応できる
モデル式で変数を変換することは有効であり
model.frame
は、元のものの代わりに変換されたものを記録します。なお、元の変数に
NA
変換されたものには、それが含まれることがあります。
dat <- data.frame(y = 1:4, x = c(1:3, -1), f = rep(letters[1:2], c(3, 1)))
# y x f
#1 1 1 a
#2 2 2 a
#3 3 3 a
#4 4 -1 b
lm(y ~ log(x) + f, data = dat)
#Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
#In addition: Warning message:
#In log(x) : NaNs produced
# directly using `debug_contr_error` is hopeless here
debug_contr_error(dat)$nlevels
#f
#2
## this works
dat_internal <- lm(y ~ log(x) + f, data = dat, method = "model.frame")
# y log(x) f
#1 1 0.0000000 a
#2 2 0.6931472 a
#3 3 1.0986123 a
debug_contr_error(dat_internal)$nlevels
#f
#1
このような利点があるので、私は別の関数で
model.frame
と
debug_contr_error
.
入力 :
-
form
はモデル式です。 -
dat
に渡されるデータセットです。lm
またはglm
を介してdata
引数で指定します。 -
subset_vec
に渡されるインデックスベクタです。lm
またはglm
を介してsubset
引数で指定します。
出力します。 を持つリストです。
-
mf
(データフレーム)は、("terms" 属性を削除した)モデルフレームを提供します。 -
nlevels
(リスト)は、すべての因子変数の因子レベルの数を与える。 -
levels
(ベクトル) は、すべての因子変数の水準を与える。
## note: this function relies on `debug_contr_error`
debug_contr_error2 <- function (form, dat, subset_vec = NULL) {
## step 0
if (!is.null(subset_vec)) {
if (mode(subset_vec) == "logical") {
if (length(subset_vec) != nrow(dat)) {
stop("'logical' `subset_vec` provided but length does not match `nrow(dat)`")
}
subset_log_vec <- subset_vec
} else if (mode(subset_vec) == "numeric") {
## check range
ran <- range(subset_vec)
if (ran[1] < 1 || ran[2] > nrow(dat)) {
stop("'numeric' `subset_vec` provided but values are out of bound")
} else {
subset_log_vec <- logical(nrow(dat))
subset_log_vec[as.integer(subset_vec)] <- TRUE
}
} else {
stop("`subset_vec` must be either 'logical' or 'numeric'")
}
dat <- base::subset(dat, subset = subset_log_vec)
}
## step 0 and 1
dat_internal <- stats::lm(form, data = dat, method = "model.frame")
attr(dat_internal, "terms") <- NULL
## rely on `debug_contr_error` for steps 2 to 4
c(list(mf = dat_internal), debug_contr_error(dat_internal, NULL))
}
前の
log
を変換する例です。
debug_contr_error2(y ~ log(x) + f, dat)
#$mf
# y log(x) f
#1 1 0.0000000 a
#2 2 0.6931472 a
#3 3 1.0986123 a
#
#$nlevels
#f
#1
#
#$levels
#$levels$f
#[1] "a"
#
#
#Warning message:
#In log(x) : NaNs produced
試す
subset_vec
も同様に。
## or: debug_contr_error2(y ~ log(x) + f, dat, c(T, F, T, T))
debug_contr_error2(y ~ log(x) + f, dat, c(1,3,4))
#$mf
# y log(x) f
#1 1 0.000000 a
#3 3 1.098612 a
#
#$nlevels
#f
#1
#
#$levels
#$levels$f
#[1] "a"
#
#
#Warning message:
#In log(x) : NaNs produced
グループごとのモデルフィッティング、NAを因子レベルとして
グループごとにモデルをフィットさせる場合、"contrasts error"が発生しやすくなります。 必要なのは
-
グループ化変数によってデータフレームを分割します (
?split.data.frame
); -
は、これらのデータフレームを1つずつ処理し、以下のように適用します。
debug_contr_error2
(lapply
関数を使用すると便利です)。
また、一部の方からは
na.omit
というのも、行数が少なすぎて、意味のあることができないからです。
これは緩和することができます。実際には
NA_integer_
と
NA_real_
は省略しなければならないが
NA_character_
を追加するだけで、保持することができます。
NA
を因子レベルとして使用します。これを達成するためには、データフレーム内の変数をループする必要があります。
-
もし変数が
x
が既に因子である場合 とanyNA(x)
はTRUE
するx <- addNA(x)
. この「"and"」が重要です。もしx
にはNA
,addNA(x)
を追加すると、未使用の<NA>
レベルになります。 -
もし変数が
x
が文字である場合、次のようにします。x <- factor(x, exclude = NULL)
を使って係数に強制することができます。exclude = NULL
を保持します。<NA>
をレベルとして設定します。 -
もし
x
は、quot;logical", "numeric", "raw" または "complex" で、何も変更する必要がない。NA
は単にNA
.
<NA>
によって要因レベルが低下することはありません。
droplevels
または
na.omit
であり,モデルマトリックスを構築する際に有効です.以下の例で確認してください。
## x is a factor with NA
x <- factor(c(letters[1:4], NA)) ## default: `exclude = NA`
#[1] a b c d <NA> ## there is an NA value
#Levels: a b c d ## but NA is not a level
na.omit(x) ## NA is gone
#[1] a b c d
#[.. attributes truncated..]
#Levels: a b c d
x <- addNA(x) ## now add NA into a valid level
#[1] a b c d <NA>
#Levels: a b c d <NA> ## it appears here
droplevels(x) ## it can not be dropped
#[1] a b c d <NA>
#Levels: a b c d <NA>
na.omit(x) ## it is not omitted
#[1] a b c d <NA>
#Levels: a b c d <NA>
model.matrix(~ x) ## and it is valid to be in a design matrix
# (Intercept) xb xc xd xNA
#1 1 0 0 0 0
#2 1 1 0 0 0
#3 1 0 1 0 0
#4 1 0 0 1 0
#5 1 0 0 0 1
## x is a character with NA
x <- c(letters[1:4], NA)
#[1] "a" "b" "c" "d" NA
as.factor(x) ## this calls `factor(x)` with default `exclude = NA`
#[1] a b c d <NA> ## there is an NA value
#Levels: a b c d ## but NA is not a level
factor(x, exclude = NULL) ## we want `exclude = NULL`
#[1] a b c d <NA>
#Levels: a b c d <NA> ## now NA is a level
を追加すると
NA
を要因/文字のレベルとして使用すると、データセットに突然、より完全なケースが追加されるかもしれません。そして、モデルを実行することができます。それでもまだ「対照エラー」("contrasts error")が出る場合は
debug_contr_error2
で何が起こったかを確認します。
便宜上、このための関数を書いておきます。
NA
の前処理を行います。
入力 :
-
dat
はあなたの フル データセットです。
出力します。
- 要因/文字のレベルとしてNAが追加されたデータフレーム。
NA_preproc <- function (dat) {
for (j in 1:ncol(dat)) {
x <- dat[[j]]
if (is.factor(x) && anyNA(x)) dat[[j]] <- base::addNA(x)
if (is.character(x)) dat[[j]] <- factor(x, exclude = NULL)
}
dat
}
再現性のあるケーススタディとディスカッション
ここで作成した3つのヘルパー関数で回答しただけなので、再現性のあるケーススタディに特選しています。
また、他のStackOverflowユーザーが解決した良質のスレッドもいくつかあります。
- map() を使用した lm で因子が認識されない。 (グループ別のモデルフィッティングについてです)
- Rで線形回帰をするとき、条件付きで因子のNA観測を落とすには? (前のリストのケース1と同じです。)
- 混合モデルにおける因子・水準誤差 (グループ別モデルフィッティングについての別記事)
この回答は、モデルフィッティング中の "contrastsエラー" をデバッグすることを目的としています。しかし、このエラーは
predict
を予測することができます。このような動作は
predict.lm
または
predict.glm
しかし、いくつかのパッケージから予測されるメソッドを使用しています。以下はStackOverflowの関連スレッドです。
- Rでの予測 - GLMM
- コントラスト(Contrasts)エラー
- 異なる因子レベルを持つデータフレームに対するSVM予測
- predict を svyglm で使用する
- RのSVMでは、データセットにすべての因子が含まれていなければならない
- 累積リンク混合モデルによる確率予測
- RのSVMでは、データセットにすべての因子が含まれていなければならない
また、この回答の理念は、以下のものに基づいていることに注意してください。
lm
と
glm
.
この2つの関数は、多くのモデルフィッティングルーチンのコーディングスタンダードとなっています。
しかし、すべてのモデルフィッティングルーチンが同じような動作をするわけではありません。例えば、次のような場合、私のヘルパー関数が実際に役に立つかどうか、私には透明に見えません。
- svychisqでのエラー - 'コントラストは2つ以上のレベルを持つ要因に適用できる'
- R packages effects & plm : "周辺効果をプロットしようとすると、contrasts" でエラーが発生します。
- コントラストを適用できるのは、因子
- R: lawstat::levene.test は失敗し、Fligner Killeen は動作し、car::leveneTest も動作する。
- R - geeglm エラー: コントラストは2つ以上のレベルを持つ要因にのみ適用できる。
少し話がそれますが、quot;contrasts エラー" が単に間違ったコードを書いたことに起因する場合もあることを知っておくと便利です。次の例では、OPは変数の値ではなく、変数の名前を
lm
. 名前は1値の文字なので、後で1レベルの因子に強要され、エラーが発生します。
- Error in `contrasts<-`(`*tmp*`, value = contr.funs[1 + isOF[nn]]) : contrasts can be applied only to factors with 2 or more levels.
- 関数で使用する文字ベクトルをループ処理する
デバッグ後にこのエラーを解決するにはどうすればよいですか?
実際には、統計的なレベル、あるいはプログラミングのレベルで、この問題を解決する方法を知りたいと思う人がいます。
もし完全なデータセットにモデルを当てはめるのであれば、欠損値をインプットするか、より多くのデータを収集しない限り、統計的な解決策はないでしょう。したがって、問題のある変数を削除するために、単純にコーディングの解決策に頼ることができます。
debug_contr_error2
リターン
nlevels
これは、それらの場所を簡単に特定するのに役立ちます。もしそれらを削除したくない場合は、それらを 1 のベクトルに置き換えます (詳細は
2つ以上の水準を持つ因子にしか対比を適用できない場合、GLMはどのように行うのですか?
とし
lm
または
glm
は、結果として生じるランク不足を処理する。
部分集合にモデルを当てはめるのであれば、統計的な解決方法があるはずです。
グループ別にモデルをフィットさせる場合、必ずしもデータセットをグループ別に分割し、独立したモデルをフィットさせる必要はない。大まかなイメージとしては以下のような感じでしょうか。
明示的にデータを分割すると、quot;contrasts error" が発生しやすいので、グループごとにモデル式を調整する必要があります(つまり、モデル式を動的に生成する必要があります)。よりシンプルな解決策は、このグループに対するモデルの構築をスキップすることです。
また、クロスバリデーションを行うために、データセットをトレーニングサブセットとテストサブセットに無作為に分割することもできます。 R: 線形モデルおよび予測のための "因子が新しいレベルを持っている" エラーをデバッグする方法 にはこのことが書かれていますが、学習部でのモデル推定とテスト部での予測の両方を成功させるためには、層別サンプリングを行った方がよいでしょう。
関連
-
[解決済み】xtsオブジェクトでエラー: "antempt to set 'colnames' on the object with less than two dimension "を克服する方法
-
[解決済み】rbind エラー。"名前が以前の名前と一致しない"
-
[解決済み】 colMeans(x, na.rm = TRUE) のエラー : KNN分類では 'x' は数値でなければならない
-
[解決済み】「'dimnames' [1]の長さが配列の範囲と等しくない」とはどういう意味ですか?
-
[解決済み】 lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) のエラー : 'y' の NA/NaN/Inf, あらゆる方法を試したが解決しなかった。
-
[解決済み】エラー - replacement has [x] rows, data has [y].
-
[解決済み】ggplot2でのプロット:「Error: カテゴリ軸のY軸に "Discrete value supplied to continuous scale "と表示される。
-
[解決済み】 .subset2(x, i, exact = exact)のエラー:Rの添え字が範囲外である。
-
[解決済み】randomForestの実行予測で「NA/NaN/Inf in foreign function call (arg 7)」をなくすには?
-
[解決済み】.External.graphics Rでエラーが発生しました。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] promise already under evaluation: recursive default argument reference or earlier problems?
-
[解決済み】'builtin'型のオブジェクトはsubsetableではない【重複
-
[解決済み】「arguments imply differing number of rows: x, y」というエラーは何を意味するのか?
-
[解決済み】model.frame.defaultでのエラー:変数の長さが異なる
-
[解決済み】数学関数への非数値引数
-
[解決済み】ggplotの線幅を変更するには?
-
[解決済み】GLM解析での警告
-
[解決済み】 boxplotに色を追加する - "離散的なスケールに連続的な値が供給される "エラー
-
[解決済み】Rで文字ベクトルから引用符を削除する
-
[解決済み】二項演算子への非数値引数【非公開