회귀 진단
이상점
> house <- read.csv('house_sales.csv', sep='\t')
> zip_groups <- house %>%
+ mutate(resid = residuals(house_lm)) %>%
+ group_by(ZipCode) %>%
+ summarize(med_resid = median(resid),
+ cnt = n()) %>%
+ # sort the zip codes by the median residual
+ arrange(med_resid) %>%
+ mutate(cum_cnt = cumsum(cnt),
+ ZipGroup = factor(ntile(cum_cnt, 5)))
> house <- house %>%
+ left_join(select(zip_groups, ZipCode, ZipGroup), by='ZipCode')
> house_98105 <- house[house$ZipCode == 98105,]
> lm_98105 <- lm(AdjSalePrice ~ SqFtTotLiving + SqFtLot + Bathrooms + Bedrooms + BldgGrade, data=house_98105)
> lm_98105
Call:
lm(formula = AdjSalePrice ~ SqFtTotLiving + SqFtLot + Bathrooms +
Bedrooms + BldgGrade, data = house_98105)
Coefficients:
(Intercept) SqFtTotLiving SqFtLot Bathrooms Bedrooms BldgGrade
-772549.86 209.60 38.93 2282.26 -26320.27 130000.10
> sresid <- rstandard(lm_98105)
> idx <- order(sresid, decreasing=FALSE)
> sresid[idx[1]]
24333
-4.326732
> resid(lm_98105)[idx[1]]
24333
-757753.6
- 결과를 보면 표준오차의 4배 이상이나 회귀식과 차이가 남
- 이에 해당하는 추정값은 $757,753. 이 특잇값에 해당하는 레코드는 디음과 같음
> house_98105[idx[1], c('AdjSalePrice', 'SqFtTotLiving', 'SqFtLot', 'Bathrooms', 'Bedrooms', 'BldgGrade')]
AdjSalePrice SqFtTotLiving SqFtLot Bathrooms Bedrooms BldgGrade
24333 119748 2900 7276 3 6 7
- 빅데이터의 경우, 새로운 데이터를 예측하기 위한 회귀분석에서 이상점이 그렇게 문제가 되지 는 않는다.
- 그러나 이상점을 찾는 것이 주목적인 이상점 검출의 경우 이 값들이 매우 중요해진다.
- 이상점은 사기 사건이나 갑작스러운 사건 발생과도 관련이 있다.
- 따라서 이상점을 발견하는 것은 아주 중요한 사업 가치가 될 수 있다
영향값
- 주영향관측값(influential observation): 회귀모델에서 제외됐을 때중요한 변화를 가져오는 값
- 회귀분석에서, 잔차가 크다고 해서 모두 이런 값이 되지는 않는다.
> seed <- 11
> set.seed(seed)
> x <- rnorm(25)
> y <- -x/5 + rnorm(25)
> x[1] <- 8
> y[1] <- 8
> plot(x, y, xlab='', ylab='', pch=16)
> model <- lm(y~x)
> abline(a=model$coefficients[1], b=model$coefficients[2], col="blue", lwd=3)
> model <- lm(y[-1]~x[-1])
> abline(a=model$coefficients[1], b=model$coefficients[2], col="red", lwd=3, lty=2)
- 빨간색 점선은 오른쪽 위의 한 점을 제거했을 때의 회귀선
- 오른쪽 위의 데이터 값은 회귀 결과에 큰 영향을 주지만 큰 이상점으로 나타난 것은 아니다.
- 이 데이터 값은 회귀에 대한 높은 레버리지(leverage)를 가진 것으로 볼 수 있다
- 햇 값(hat-value): \(2(P=1)/n\) 이상의 값들은 레버리지가 높은 데이터로 판단
- 쿡 거리(Cook's distance): 레버리지와 잔차의 크기를 합쳐서 영향력을 판단하며 경험적으로 \(4/(n-P-1)\)보다 크면 영향력이 높다고 판단
- 영향력 그림(influence plot) 또는 거품그림(bubble plot): 표준화잔차와 햇 값, 쿡 거리를 모두 한번에 표현하는 그림
- 우편번호가 98105인 킹 카운티 주택 데이터에 대한 영향력 그림
> std_resid <- rstandard(lm_98105)
> cooks_D <- cooks.distance(lm_98105)
> hat_values <- hatvalues(lm_98105)
> plot(hat_values, std_resid, cex=10*sqrt(cooks_D))
> abline(h=c(-2.5, 2.5), lty=2)

- 회귀에서 몇몇 데이터 포인트가 정말로 큰 영향력을 보임을 알 수 있다.
- 쿡 거리는 cooks.distance 힘수를 사용해 계산하고 hatvalues 함수를 이용해 회귀 진단을 구할 수 있다.
- 햇 값은 \(x\)축, 잔차 정보는 \(y\)축에 위치하며, 쿡 거리에 해당하는 값은 원의 크기로 표현된다
- 전체 데이터를 모두 사용했을 때와 영향력이 가장 큰 데이터를 제거하고 구한 회귀 결과 비교
- Bathrooms 변수의 회귀계수가 크게 변한다
- 데이터의 규모가 작을 경우에만 영향력이 큰 관측 데이터를 확인하는 작업이 유용하며
- 빅데이터의 경우에는 어떤 한 값이 회귀식에 큰 변화를 주기란 쉽지 않기 때문이다
이분산성
- 데이터 과학자가 신경쓰는 것 한 가지는 잔차에 대한 가정을 기반으로 예상 값에 대한 신뢰구간을 계산하는 방법
- 이분산성(heteroskedasticity): 다양한 범위의 예측값에 따라 잔차의 분산이 일정하지 않은 것
- 어떤 일부분에서의 오차가 다른 곳보다 훨씬 크게 나타나는 것
- 우편번호가 98105인 킹 카운티 주택 회귀모델에서 절대잔차와 예측값의 관계
- 잔차의 분산은 고가의 주택일수록 증가하는 경향이 있다
- 이 회귀모델은 주택가격이 너무 높거나 너무 낮은 경우에는 예측을 잘하지 못하므로 모델이 다소 불완전하다
> df <- data.frame(resid = residuals(lm_98105), pred = predict(lm_98105))
> ggplot(df, aes(pred, abs(resid))) + geom_point() + geom_smooth()
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

- 정규분포보다 확연히 더 긴 꼬리를 가지며 , 더 큰 잔차에 대해 약간의 왜곡을 보인다.

편잔차그림과 비선형성
- 편잔차그림(partial residual plot): 예측모델이 예측변수와 결과변수 간의 관계를 얼마나 잘 설명하는지 시각화하는 방법
- 이상점의 검출과 함께 데이터 과학자들에게 가장 중요한 모델 진단 방법
- 하나의 예측변수와 응답변수 사이의 관계를 모든 다른 예측 변수로부터 분리하는 것
- 편잔차는 단일 예측변수를 기반으로 한 예측값과 전체를 고려한 회귀식의 실제 잔차를 결합하여 ‘만든 결과’
- 예측변수 \(X_i\)의 편잔치는 일반 잔차에 \(X_i\)와 연관된 회귀항을 더한 값
\begin{eqnarray} \textrm{partial residual} = \textrm{residual} + \hat{b}_iX_i\end{eqnarray}
- R의 predict 힘수를 이용해서 개별 회귀항 \(\hat{b}_iX_i\)를 얻을 수 있다.
> terms <- predict(lm_98105, type='terms')
> partial_resid <- resid(lm_98105) + terms
> partial_resid
SqFtTotLiving SqFtLot Bathrooms Bedrooms BldgGrade
1036 -9582.44883 -357174.9708 -450660.995 -524932.2009 -412036.63955
1769 -189558.76910 -78529.9327 -159020.193 -174374.6343 -114119.61053
1770 -98583.94036 11964.9452 -63853.317 -52887.4899 -148952.83461
1771 -130174.59786 -92384.0872 -187669.007 -176703.1797 -272768.52442
1783 306968.80331 48451.3706 -96567.562 -142236.2342 74339.15810
1784 -28140.43476 -121486.4246 -132131.685 -122877.5562 -88942.80121
1785 571952.99093 266306.1851 276268.714 284381.7110 448316.56574
- 편잔차그림에서 \(x\)축은 \(X_i\)를, \(y\)축은 편잔차를 의미
> df <- data.frame(SqFtTotLiving = house_98105[, 'SqFtTotLiving'], Terms = terms[, 'SqFtTotLiving'], PartialResid = partial_resid[, 'SqFtTotLiving'])
> ggplot(df, aes(SqFtTotLiving, PartialResid)) + geom_point(shape=1) + scale_shape(solid = FALSE) + geom_smooth(linetype=2) + geom_line(aes(SqFtTotLiving, Terms))
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
- 편잔차는 SqFtTotLiving 변수가 주택 가격에 얼마나 영향을 미치는지 보여준다.
- SqFtTotLiving 변수와 가격 사이의 관계는 분명히 비선형이다.
- 1,000제곱피트보다 작은 평수의 집에 대해서는 가격을 원래보다 낮게 추정
- 2,000∼3.000제곱피트 집에 대해서는 더 높게 추정
- 4 , 000제곱피트 이상에 관해서는 데이터 개수가 너무 적어 뭐라고 결론을 내릴 수가 없다.
