[R] 선형 회귀 분석(Linear Regression) - Dataset : Linear Regression(@Kaggle)

이 글은 Kaggle에서 좋은 평가를 받은 kernel을 따라하며 학습한 내용입니다.

선형 회귀 분석은 한 개 이상의 입력 변수(X)들을 기반으로 하나의 반응 변수(Y)를 예측하는데 활용됩니다.
입력 변수와 반응 변수의 선형 관계(수학적 공식) 수립의 목적은 입력 변수(X)들을 알고 있을 때, 공식을 이용하여 반응 변수(Y)를 추정하는데 있습니다.

1. 패키지 및 데이터 불러오기

분석을 시작하기 앞서, 데이터를 불러오고 분석에 필요한 패키지를 로드하는 단계입니다.
데이터는 아래 첨부된 링크에서 받으실 수 있습니다.

# ggplot2 패키지 불러오기
library(ggplot2)

# 데이터셋 불러오기
# https://www.kaggle.com/andonians/random-linear-regression
trainingSet = read.csv('../input/train.csv')

2. 결측치(NA) 확인

결측치(NA)를 확인하고 해당 행(row)를 삭제하는 단계입니다.

  • numberOfNA : trainingSet변수에 있는 결측치(NA) 개수 출력
  • complete.cases() : 결측값(NA)이 포함되지 않은 행만 리턴해주는 함수
# NA 결측값 확인
# is.na 함수를 이용하여 결측값(NA)을 확인하고 총 개수 출력
numberOfNA = length(which(is.na(trainingSet)==T))
# complete.cases 함수를 이용하여 결측값(NA)이 포함된 row 삭제
if(numberOfNA > 0) {
  cat('Number of missing values found: ', numberOfNA)
  cat('\nRemoving missing values...')
  trainingSet = trainingSet[complete.cases(trainingSet), ]
}
## Number of missing values found:  1
## Removing missing values...

3. 이상치(Outliers) 확인

변수별 이상치를 확인하는 단계입니다. 특정 함수를 이용하여 추출할 수 있으나, 해당 kernel에서는 시각화(boxplot)를 활용해 확인합니다.

# 이상값(Outliers) 확인
# 그래프를 2열로 분리
par(mfrow = c(1, 2))

# Boxplot for X
boxplot(trainingSet$x, main='X', sub=paste('Outliers: ', boxplot.stats(trainingSet$x)$out))
# Boxplot for Y
boxplot(trainingSet$y, main='Y', sub=paste('Outliers: ', boxplot.stats(trainingSet$y)$out))

시각화를 통해 XY 모두 편향(skewed)되지 않았고, 이상값(Outliers)이 없음을 확인하였습니다.

4. 연관성(Correlation)

연관성은 두 변수(XY) 쌍(pair)에서 발생하는 선형적인 의존성 수준을 나타내는 통계 값입니다.

연관성 정도는 -1 에서 1 사이 값으로 나타나며,

  1. 값이 0 이상 일 경우, 양의 상관 관계를 가진다고 하며 XY정비례한다.
  2. 값이 0 이하 인 경우, 음의 상관 관계를 가진다고 하며 XY반비례한다.
  3. 값이 0 인 경우, 약한 상관 관계를 가진다고 한다.
cor(trainingSet$x, trainingSet$y)
## 0.995339907721253
## 0.99 shows a very strong relation.

상관관계 분석결과는 약 0.99534로 나타났으며, 이는 강한 양의 상관 관계가 있다고 볼 수 있습니다.

5. 단순 선형 회귀(Simple Linear Regression)

  • lm() : 선형 회귀 분석 시 사용되는 함수
  • summary() : 변수의 통계정보를 나타내는 함수로 분석 모델에 대한 결과 확인도 가능
# 단순 선형 회귀 적합하기
# .은 모든 독립 변수들을 입력 변수로 사용한다.

regressor = lm(formula = y ~.,
               data = trainingSet)

# 단순 선형 회귀 모델 확인
summary(regressor)
## Call:
##   lm(formula = y ~ ., data = trainingSet)
## 
## Residuals:
##   Min      1Q  Median      3Q     Max 
## -9.1523 -2.0179  0.0325  1.8573  8.9132 
## 
## Coefficients:
##   Estimate Std. Error t value Pr(>|t|)    
## (Intercept) -0.107265   0.212170  -0.506    0.613    
## x            1.000656   0.003672 272.510   <2e-16 ***
##   ---
##   Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## 
## Residual standard error: 2.809 on 697 degrees of freedom
## Multiple R-squared:  0.9907,    Adjusted R-squared:  0.9907 
## F-statistic: 7.426e+04 on 1 and 697 DF,  p-value: < 2.2e-16

단순 선형 회귀에서 가설(Hypothesis)는 아래와 같습니다.

  • 귀무가설(H_0) : X이 계수는 0이다
  • 대립가설(H_1) : X의 계수는 0이 아니다 ('독립 변수와 종속 변수는 연관성이 존재한다' 고 볼 수 있다)

결과해석

p-value에 별(*)이 3개가 있는 것은 x가 통계적으로 매우 유의하다는 것을 의미하며, 일반적으로 0.05 이하이면 통계적으로 유의하다고 볼 수 있습니다.
(P value is less than 0. Genraaly below 0.05 is considered good.)

R제곱(R^2)값은 이 모델에 의해 설명되고 있는 종속(반응) 변수의 변화 비율을 나타내며, R제곱(R^2)의 값이 0.99인 것은 종속 변수(Y)와 독립 변수(X)의 사이의 매우 좋은 변동을 나타냅니다.

6. 학습 데이터(training set) 분석 결과 시각화

학습 데이터(trainingSet)에 대한 분석 결과를 시각화(ggplot)하여 확인하는 단계입니다.

# Visualizing the training set results
ggplot() +
  geom_point(aes(x = trainingSet$x, y = trainingSet$y),
             colour = 'red') +
  geom_line(aes(x = trainingSet$x, y = predict(regressor, newdata = trainingSet)),
            colour = 'blue') +
  ggtitle('X vs Y (Training set)') +
  xlab('X') +
  ylab('Y')

그래프를 통해 모델이 매우 잘 적합되었음을 확인할 수 있습니다.

7. 정확도(accuracy) 계산

예측값(y_pred)와 실제값(testSet$x)을 비교하여 모델 정확도를 검증하는 단계입니다.
모델 생성에 적용되지 않은 새로운 데이터(testSet)를 불러와 모델 예측력을 검증하게 됩니다.

  • testSet : 모델 검증용 데이터 - 모델 생성 시 학습에 적용되지 않은 데이터
  • y_pred : testSet 데이터를 모델(regressor)로 예측한 결과
  • compare : 예측값(y_pred)와 실제값(testSet$x)을 담은 변수
# Importing test data
testSet = read.csv('../input/test.csv')
# Predicting the test results
y_pred = predict(regressor, newdata = testSet)

# Visualizing the test set results
ggplot() +
  geom_point(aes(x = testSet$x, y = testSet$y),
             colour = 'red') +
  geom_line(aes(x = trainingSet$x, y = predict(regressor, newdata = trainingSet)),
            colour = 'blue') +
  ggtitle('X vs Y (Test set)') +
  xlab('X') +
  ylab('Y')

그래프를 통해 모델이 매우 잘 적합되었음을 확인할 수 있습니다.

  • 정확도 확인
# Finding accuracy - kernel
compare <- cbind(actual=testSet$x, y_pred)  # 실제값과 예측값을 결합
mean(apply(compare, 1, min)/apply(compare, 1, max))
mean(0.9,0.9,0.9,0.9)
# -Inf
# 0.9

위 원문 코드의 정확도 계산 방식은 다음과 같습니다.

  1. 실제값과 예측값을 결합하여 리스트 생성
  2. 각 행별 (최소값/최대값)의 평균을 계산
  3. mean(0.9,0.9,0.9,0.9)의 의미는 파악을 못했습니다 :(

출력된 결과를 살펴보면 첫번째 결과가 -Inf 로 나타납니다. 이것은 예측값에 음수가 있어 발생한 결과로, 음수를 임의의 작은수(1e-10 = 0.0000000001)로 변경하여 계산한 코드로 수정하였습니다. 두번째 결과는 0.9로 4개의 0.9의 평균을 계산한 값인데 작성자의 의도를 파악 못했습니다.. :(

# accuracy 계산 : y_pred < 0이면 1e-10으로 변경
compare <- cbind(actual=testSet$x, y_pred)  # 실제값과 예측값을 결합
compare[,2] <- ifelse(compare[,2]<0, 1e-10, compare[,2])
mean(apply(compare, 1, min)/apply(compare, 1, max))
mean(0.9,0.9,0.9,0.9)
# 0.985664
# 0.9

위 결과로 모델의 예측 정확도(?)는 약 98.5664% 정도 되는 것을 확인할 수 있습니다.
검증에 사용된 accuracy 계산식에 대한 이해가 명확하지 않아 RMSE로 다시 계산하였으며 결과는 아래와 같습니다.

# calculating the RMSE
compare.rmse <- sqrt(mean((compare[,2]-compare[,1])^2))
compare.rmse 
## 0.137161

▶ 전체 코드 확인 : Github 링크