문제

디음 plot의 회귀선에 평행한 라벨을 붙이는 방법을 알아보겠습니다.

require(ggplot2)
ggplot(data=iris,aes(x=Sepal.Length,y=Sepal.Width,color=Species))+stat_smooth(method="lm",se=FALSE)

회귀모형에서 회귀식 추출

먼저 iris데이터에서 Sepal.Width를 반응변수로, Sepal.Length와 Species를 설명변수로 하는 회귀모형을 만듭니다. 이때 설명변수 간의 상호작용이 있어야 하므로 Sepal.Length*Species로 사용합니다

fit=lm(Sepal.Width~Sepal.Length*Species,data=iris)
summary(fit)

Call:
lm(formula = Sepal.Width ~ Sepal.Length * Species, data = iris)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.72394 -0.16327 -0.00289  0.16457  0.60954 

Coefficients:
                               Estimate Std. Error t value Pr(>|t|)    
(Intercept)                     -0.5694     0.5539  -1.028 0.305622    
Sepal.Length                     0.7985     0.1104   7.235 2.55e-11 ***
Speciesversicolor                1.4416     0.7130   2.022 0.045056 *  
Speciesvirginica                 2.0157     0.6861   2.938 0.003848 ** 
Sepal.Length:Speciesversicolor  -0.4788     0.1337  -3.582 0.000465 ***
Sepal.Length:Speciesvirginica   -0.5666     0.1262  -4.490 1.45e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.2723 on 144 degrees of freedom
Multiple R-squared:  0.6227,    Adjusted R-squared:  0.6096 
F-statistic: 47.53 on 5 and 144 DF,  p-value: < 2.2e-16

이 회귀모형에서 Species에 따른 회귀식의 slope와 intercept를 추출합니다. 이를 이용하여 label을 만듭니다.

Species=levels(iris$Species)
intercept=c(fit$coef[1],fit$coef[1]+fit$coef[3],fit$coef[1]+fit$coef[4])
slope=c(fit$coef[2],fit$coef[2]+fit$coef[5],fit$coef[2]+fit$coef[6])
df=data.frame(Species,intercept,slope)
df$label=paste0("italic(y)==",round(df$intercept,2),"+",round(df$slope,2),"*italic(x)")
df
     Species  intercept     slope                          label
1     setosa -0.5694327 0.7985283 italic(y)==-0.57+0.8*italic(x)
2 versicolor  0.8721460 0.3197193 italic(y)==0.87+0.32*italic(x)
3  virginica  1.4463054 0.2318905 italic(y)==1.45+0.23*italic(x)

직선의 slope는 직선의 가지는 각도의 arctan 값입니다. R에서는 atan()합수로 계산됩니다. 단 이렇게 계산한 각도는 radian이라 ggplot에서 쓰려면 degree로 바꾸어주어야 합니다.

df$radian=atan(df$slope)
df$angle=df$radian*180/pi
df
     Species  intercept     slope                          label    radian
1     setosa -0.5694327 0.7985283 italic(y)==-0.57+0.8*italic(x) 0.6738429
2 versicolor  0.8721460 0.3197193 italic(y)==0.87+0.32*italic(x) 0.3094483
3  virginica  1.4463054 0.2318905 italic(y)==1.45+0.23*italic(x) 0.2278632
     angle
1 38.60836
2 17.73008
3 13.05560

또한 라벨을 붙일 x좌표와 y좌표를 계산합니다. 편의상 x축의 5,6,7.2 위치에 라벨을 붙이기 위해 다음과 같은 함수를 만들고 좌표를 계산합니다.

fun=list()
fun[[1]]=function(x){fit$coef[1]+fit$coef[2]*x}
fun[[2]]=function(x){fit$coef[1]+fit$coef[3]+(fit$coef[2]+fit$coef[5])*x}
fun[[3]]=function(x){fit$coef[1]+fit$coef[4]+(fit$coef[2]+fit$coef[6])*x}

df$x=c(5,6,7.2)
df$y=unlist(lapply(1:3,function(i){fun[[i]](df$x[i])}))
df
     Species  intercept     slope                          label    radian
1     setosa -0.5694327 0.7985283 italic(y)==-0.57+0.8*italic(x) 0.6738429
2 versicolor  0.8721460 0.3197193 italic(y)==0.87+0.32*italic(x) 0.3094483
3  virginica  1.4463054 0.2318905 italic(y)==1.45+0.23*italic(x) 0.2278632
     angle   x        y
1 38.60836 5.0 3.423209
2 17.73008 6.0 2.790462
3 13.05560 7.2 3.115917

회귀선 확인

먼저 회귀선이 이 그림과 일치하는지 plot에 직선을 추가해 선이 일치하는지 알아봅니다.

p <-ggplot(data=iris,aes(x=Sepal.Length,y=Sepal.Width,color=Species))+
    stat_smooth(method="lm",se=FALSE)
p+  stat_function(fun=fun[[1]],lty=2)+
    stat_function(fun=fun[[2]],lty=2)+
    stat_function(fun=fun[[3]],lty=2)

당연히 선이 일치합니다. 이제 우리가 계산한 각도로 라벨을 붙여봅니다.

p+ geom_text(data=df,aes(x=x,y=y,label=label,angle=angle,color=Species),parse=TRUE)