R回帰分析における「特異性のために定義されていない」問題の解決
統計学や数学を専攻しているなら、大まかに原因を把握し現在直面している問題を解決するだけでなく、数理的証明まで理解することを強く推奨する。
エラー
診断
Coefficients: (1 not defined because of singularities)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.5723 0.1064 5.381 4.98e-05 ***
최고기온 -0.3528 0.1490 -2.368 0.030 *
최저기온 0.2982 0.1955 1.525 0.146
일교차 NA NA NA NA
Rで回帰分析を行う際、回帰係数でnot defined because of singularities
というメッセージと共に係数推定がされない問題である。
原因
- デザインマトリックス $X$ がフルランクを持たないため、$X^{T} X$の逆行列が存在しない状態で最小二乗解を求める際に問題が発生する。それがエラーメッセージに
singularities
が言及されている理由だ。 - 簡単に言えば、多重共線性があるということだ。
- もっと簡単に言えば、独立変数同士が独立ではないということだ。
$X^T X$の逆行列が存在するための必要十分条件: $m \ge n$のとき、行列 $X \in \mathbb{R}^{m \times n}$ の逆行列が存在するための必要十分条件は$X$がフルランクを持つことだ。 $$ \exists \left( X^{T} X \right)^{-1} \iff \text{rank} X = n $$
これは、教科書的に初心者が犯しやすい間違いで、例で示されているように、何かを考えて派生変数を作る過程で初めて遭遇する問題だ。理由を聞けば数学的には当たり前だが、統計学的直感がまだ芽生え始めた学生にとっては、当然犯しうる間違いだ。
あなただけが犯した間違いではなく、これらの人々も犯したし、私も犯した。重要なのは、この問題を解決した後、数学―特に行列代数や線形代数が重要であるという事実に共感し、徹底した理論学習の動機とすることだ。
典型的な状況は、以下の例で想像することができる。
> data = as.data.frame(matrix(runif(60),20,3))
> names(data) <- c("감기확률", "최고기온", "최저기온")
> lm(감기확률 ~ 최고기온 + 최저기온, data = data)
Call:
lm(formula = 감기확률 ~ 최고기온 + 최저기온, data = data)
Coefficients:
(Intercept) 최고기온 최저기온
0.5723 -0.3528 0.2982
例えば、風邪を引く確率を説明するデータとして、気温に関するデータがあるとしよう。
> data$일교차 <- (data$최고기온 - data$최저기온)
> out <- lm(감기확률 ~ 최고기온 + 최저기온 + 일교차, data = data)
그러나 상식으로써 널리 알려져있듯 감기가 유행하는 시기는 단순히 기온이 낮은 것보다 일교차가 클 때와 더 관련이 있다. 그래서 위와 같이 파생변수로써 일교차를 넣어주면 다음의 결과를 얻는다.
> summary(out)
Call:
lm(formula = 감기확률 ~ 최고기온 + 최저기온 + 일교차, data = data)
Residuals:
Min 1Q Median 3Q Max
-0.41562 -0.03316 0.00506 0.10834 0.35714
Coefficients: (1 not defined because of singularities)
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.5723 0.1064 5.381 4.98e-05 ***
최고기온 -0.3528 0.1490 -2.368 0.030 *
최저기온 0.2982 0.1955 1.525 0.146
일교차 NA NA NA NA
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.1988 on 17 degrees of freedom
Multiple R-squared: 0.2779, Adjusted R-squared: 0.193
F-statistic: 3.271 on 2 and 17 DF, p-value: 0.06281
해결법
가능하면 새로운 파생변수를 빼고, 정 남기고 싶다면 그 파생변수를 만들 때 사용했던 원래의 독립변수를 제거해야한다. 직관적으로 말이 된다면 비선형 함수를 취하는 등 파생변수를 만드는 방법 자체를 바꿔보는 것도 가능하다.
코드
data = as.data.frame(matrix(runif(60),20,3))
names(data) <- c("감기확률", "최고기온", "최저기온")
lm(감기확률 ~ 최고기온 + 최저기온, data = data)
data$일교차 <- (data$최고기온 - data$최저기온)
out <- lm(감기확률 ~ 최고기온 + 최저기온 + 일교차, data = data)
summary(out)
環境
- OS: Windows 11
- julia: v4.1.1