logo

R 회귀분석에서 not defined because of singularities 해결 📂통계적분석

R 회귀분석에서 not defined because of singularities 해결

당신이 통계나 수학 전공자라면 원인을 대강 파악하고 직면한 문제를 해결하는 것에서 그치지 않고, 수리적인 증명까지 이해하는 것을 강하게 권한다.

에러

진단

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^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