- 텍스트 데이터를 분석하는 대표적인 방법
- 대상 데이터에서 단어를 추출하고 단어들의 출현 빈도수를 계산하여 시각화하는 기능을 함
- JRE 필요
- 텍스트 파일은 마지막에 줄바꿈 후 저장해야 함
- UTF-로 저장
필요 패키지
- wordcloud
- RcppMeCab (KoNLP에서 대체)
- RColorBrewer
library(wordcloud)
library(RColorBrewer)
library(RmecabKo)
text <- readLines("mis_document.txt",encoding="UTF-8") # 파일 읽기
pal2 <- brewer.pal(8, "Dark2") # 팔레트 생성
noun <- sapply(text, nouns, USE.NAMES=F) # 명사 추출
print(noun)
> noun <- sapply(text, nouns, USE.NAMES=F)
> noun
$`1. (여성가족부) 불법촬영 등 디지털 성범죄로부터 안전한 사회를 만들기 위해 국민들께 드리는 말씀`
[1] "여성" "가족" "부" "불법" "촬영" "등" "디지털" "성범죄" "안전" "사회"
[11] "국민" "말씀"
[[2]]
NULL
$`존경하는 국민 여러분!`
[1] "존경" "국민" "여러분"
$...
[1] "여성" "가족" "부" "장관" "정현백" "우리" "사회" "들불" "미투" "운동"
[11] "계기" "일상" "폭력" "차별" "여성" "외침" "연대" "이" "성" "평등"
[21] "세상" "우리" "사회" "무엇" "추동" "일상" "성" "평등" "뿌리" "문제"
[31] "우리" "앞" "불법" "촬영" "촬영" "물" "유포" "포함" "디지털" "성범죄"
[[5]]
NULL
$...
[1] "디지털" "성범죄" "피해" "고통" "분" "나" "자신" "범죄" "대상" "불안감"
[11] "호소" "국민" "앞" "저" "마음" "순간" "여성" "몸" "상품" "불법"
[21] "영상물" "광범위" "소비" "이" "누군가" "경제" "이득" "저" "자리" "정부"
[31] "대표" "정부" "디지털" "성범죄" "피해" "현안" "중대" "인식" "각오" "정책"
[41] "추진" "말씀"
...
위와 같이 명사를 추출해낸 것을 확인할 수 있다.
noun2 <- unlist(noun) # 추출된 명사 통합
wordcount <- table(noun2) # 단어 빈도수 계산
temp <- sort(wordcount, decreasing=T)[1:10] # 상위 10개 추출
temp
barplot(temp,
names.arg=names(temp), # 막대 이름을 단어로 표시시
col = "lightblue",
main="빈도수 높은 단어", ylab="단어 빈도수")
> temp
noun2
불법 등 여성 수사 촬영 디지털 성범죄 유포 경찰청 카메라
29 27 24 23 22 12 11 11 10 10
추가
- 여기서는 명사에 공백같은 의미 없는 것이 잡히지 않았지만 만약 잡혔다면 제거하고 그래프를 그려야 함
wordcloud(names(wordcount), # 단어들
freq=wordcount, # 단어들의 빈도
scale=c(6,0.7), # 단어의 폰트 크기 (최대, 최소)
min.freq=3, # 단어의 최소 빈도수
random.order=F, # 단어의 출력 위치, F는 빈도수가 높을 수록 중앙
rot.per=.1, # 90도 회전 단어 비율
colors=pal2) # 단어의 색색
- '수', '앞', '저', '등'과 같이 의미 없는 단어들도 포함되어 있음
- 중요한 단어이지만 사전에 없어서 생략된 단어도 있을 수 있음
noun <- sapply(text, nouns, USE.NAMES=F)
noun2 <- unlist(noun)
# 무의미한 단어 제거
noun2 <- noun2[nchar(noun2)>1] # 1글자 단어 제거
noun2 <- gsub("경우","",noun2) # '경우' 제거
noun2 <- gsub("하지","",noun2) # '하지' 제거
noun2 <- gsub("때문","",noun2) # '때문' 제거거
wordcount <- table(noun2)
wordcloud(names(wordcount),
freq=wordcount,
scale=c(6,0.7),
min.freq=3,
random.order=F,
rot.per=.1,
colors=pal2)
- 독립변수 (설명변수)
- 종속변수 (반응변수)
- 예측모델
- 독립변수와 종속변수에 해당하는 자료를 모아 관계를 분석하고 예측에 사용할 수 있는 통계적 방법으로 정리한 것
- 회귀분석
- 회귀 이론을 기초로 독립변수가 종속변수에 미치는 영향을 파악하여 예측모델을 도출하는 통계적 방법
- 회귀식
- 회귀모델에서 독립변수와 종속변수 사이의 관계를 수학식 형태로 표현한 것
- 단순 회귀
- 독립변수의 수가 하나인 경우
- 다중 회귀
- 독립 변수의 수가 두 개 이상인 경우
단순선형 회귀
- 독립변수(x)와 종속변수(y) 사이의 선형 관계를 파악하고 이를 예측에 활용하는 통계적 방법
- 단순선형 회귀식은 1차식의 형태를 가짐
y = Wx + b (W, b는 상수)
목표
- 위 식에서 상수인 W와 b를 찾는 것
head(cars)
plot(dist~speed, data=cars) # 산점도를 통한 선형 관계 확인
model <- lm(dist~speed, cars) # 회귀모델 구하기
model
abline(model) # 회귀선을 산점도 위에 표시
coef(model)[1] # b 값 출력
coef(model)[2] # W 값 출력
> head(cars)
speed dist
1 4 2
2 4 10
3 7 4
4 7 22
5 8 16
6 9 10
> model <- lm(dist~speed, cars) # 회귀모델 구하기
> model
Call:
lm(formula = dist ~ speed, data = cars)
Coefficients:
(Intercept) speed
-17.579 3.932
> coef(model)[1] # b 값 출력
(Intercept)
-17.57909
> coef(model)[2] # W 값 출력
speed
3.932409
회귀식
dist = 3.932 * speed - 17.579
b <- coef(model)[1]
W <- coef(model)[2]
speed <- 30
dist <- W*speed + b
dist
speed <- 35
dist <- W*speed + b
dist
speed <- 40
dist <- W*speed + b
dist
> b <- coef(model)[1]
> W <- coef(model)[2]
> speed <- 30
> dist <- W*speed + b
> dist
speed
100.3932
> speed <- 35
> dist <- W*speed + b
> dist
speed
120.0552
> speed <- 40
> dist <- W*speed + b
> dist
speed
139.7173
추가
- 단순선형 회귀모델을 예측에 활용할 때 예측한 값이 실제값과 오차가 있을 수 있다는 것을 인지해야 함
speed <- cars[,1]
pred <- W*speed + b
pred
compare <- data.frame(pred, cars[,2],pred-cars[,2])
colnames(compare) <- c('예상','실제','오차')
head(compare)
> speed <- cars[,1]
> pred <- W*speed + b
> pred
[1] -1.849460 -1.849460 9.947766 9.947766 13.880175 17.812584 21.744993 21.744993 21.744993 25.677401
[11] 25.677401 29.609810 29.609810 29.609810 29.609810 33.542219 33.542219 33.542219 33.542219 37.474628
[21] 37.474628 37.474628 37.474628 41.407036 41.407036 41.407036 45.339445 45.339445 49.271854 49.271854
[31] 49.271854 53.204263 53.204263 53.204263 53.204263 57.136672 57.136672 57.136672 61.069080 61.069080
[41] 61.069080 61.069080 61.069080 68.933898 72.866307 76.798715 76.798715 76.798715 76.798715 80.731124
> compare <- data.frame(pred, cars[,2],pred-cars[,2])
> colnames(compare) <- c('예상','실제','오차')
> head(compare)
예상 실제 오차
1 -1.849460 2 -3.849460
2 -1.849460 10 -11.849460
3 9.947766 4 5.947766
4 9.947766 22 -12.052234
5 13.880175 16 -2.119825
6 17.812584 10 7.812584
예시
- 키와 몸무게를 이용해 혈당 수치를 예측하는 문제
- 키와 몸무게가 독립변수 x1, x2
- 혈당 수치가 종속변수 y
독립변수가 n개인 다중선형 회귀모델
y = β0 + β1x1 + β2x2 + ... + βnxn
library(car)
head(Prestige)
newdata <- Prestige[,c(1:4)] # 회귀식 작성을 위한 데이터 준비
plot(newdata, pch=16, col="blue", # 산점도를 통해 변수 간 관계 확인
main="Matrix Scatterplot")
mod1 <- lm(income~education + prestige + # 회귀식 도출
women, data=newdata)
summary(mod1)
> library(car)
> head(Prestige)
education income women prestige census type
gov.administrators 13.11 12351 11.16 68.8 1113 prof
general.managers 12.26 25879 4.02 69.1 1130 prof
accountants 12.77 9271 15.70 63.4 1171 prof
purchasing.officers 11.42 8865 9.11 56.8 1175 prof
chemists 14.62 8403 11.68 73.5 2111 prof
physicists 15.64 11030 5.13 77.6 2113 prof
> newdata <- Prestige[,c(1:4)] # 회귀식 작성을 위한 데이터 준비
> plot(newdata, pch=16, col="blue", # 산점도를 통해 변수 간 관계 확인
+ main="Matrix Scatterplot")
> mod1 <- lm(income~education + prestige + # 회귀식 도출
+ women, data=newdata)
> summary(mod1)
Call:
lm(formula = income ~ education + prestige + women, data = newdata)
Residuals:
Min 1Q Median 3Q Max
-7715.3 -929.7 -231.2 689.7 14391.8
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -253.850 1086.157 -0.234 0.816
education 177.199 187.632 0.944 0.347
prestige 141.435 29.910 4.729 7.58e-06 ***
women -50.896 8.556 -5.948 4.19e-08 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2575 on 98 degrees of freedom
Multiple R-squared: 0.6432, Adjusted R-squared: 0.6323
F-statistic: 58.89 on 3 and 98 DF, p-value: < 2.2e-16
Prestige 데이터셋
- 행의 이름은 직군
- 열의 이름
- education: 교육연수(독립변수)
- income: 연봉(종속변수)
- women: 여성의 비율(독립변수)
- prestige: 직군에 대한 평판도(독립변수)
산점도 분석
- education과 prestige는 income과 양의 상관 관계를 보임
- women은 income과 음의 상관 관계를 보임
lm()
- ~앞이 종속변수, 뒤가 독립변수
- 독립변수가 여러 개면 +로 연결
회귀모델
income = (-253.850)+(177.199*education)+(141.435*prestige)-(50.896*women)
summary()
- Pr(>|t|) 옆의 '*'는 해당 변수가 종속변수를 설명하는 데 얼마나 중요한 변수인가를 나타냄, 많을수록 통계적으로 중요하다는 의미
- p-value(유의수준) 값은 구한 회귀모델이 의미 있는 모델인지, 혹은 신뢰할 수 있는 모델인지를 나타냄, 작을수록 의미 있는 모델
- Adjusted R-squared 값은 모델의 설명력을 나타냄, 0~1 사이의 값을 갖고 클수록 회귀모델이 현실을 잘 설명할 수 있다는 의미
- 모든 독립변수가 종속변수를 설명하는 데 동일하게 기여하는 것은 아님
library(MASS)
newdata2 <- Prestige[,c(1:5)]
head(newdata2)
mod2 <- lm(income~education + prestige + women + census, data=newdata2)
mod3 <- stepAIC(mod2) # 변수 선택 진행
mod3 # 변수 선택 후 결과 확인
summary(mod3) # 회귀모델 상세 내용 확인인
> head(newdata2)
education income women prestige census
gov.administrators 13.11 12351 11.16 68.8 1113
general.managers 12.26 25879 4.02 69.1 1130
accountants 12.77 9271 15.70 63.4 1171
purchasing.officers 11.42 8865 9.11 56.8 1175
chemists 14.62 8403 11.68 73.5 2111
physicists 15.64 11030 5.13 77.6 2113
> mod3 <- stepAIC(mod2) # 변수 선택 진행
Start: AIC=1607.93
income ~ education + prestige + women + census
Df Sum of Sq RSS AIC
- census 1 639658 649654265 1606.0
- education 1 5558323 654572930 1606.8
<none> 649014607 1607.9
- prestige 1 143207106 792221712 1626.3
- women 1 212639294 861653901 1634.8
Step: AIC=1606.03
income ~ education + prestige + women
Df Sum of Sq RSS AIC
- education 1 5912400 655566665 1605.0
<none> 649654265 1606.0
- prestige 1 148234959 797889223 1625.0
- women 1 234562232 884216497 1635.5
Step: AIC=1604.96
income ~ prestige + women
Df Sum of Sq RSS AIC
<none> 655566665 1605.0
- women 1 234647032 890213697 1634.2
- prestige 1 811037947 1466604612 1685.1
> mod3 # 변수 선택 후 결과 확인
Call:
lm(formula = income ~ prestige + women, data = newdata2)
Coefficients:
(Intercept) prestige women
431.57 165.87 -48.38
> summary(mod3) # 회귀모델 상세 내용 확인인
Call:
lm(formula = income ~ prestige + women, data = newdata2)
Residuals:
Min 1Q Median 3Q Max
-7620.9 -1008.7 -240.4 873.1 14180.0
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 431.574 807.630 0.534 0.594
prestige 165.875 14.988 11.067 < 2e-16 ***
women -48.385 8.128 -5.953 4.02e-08 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2573 on 99 degrees of freedom
Multiple R-squared: 0.64, Adjusted R-squared: 0.6327
F-statistic: 87.98 on 2 and 99 DF, p-value: < 2.2e-16
추가
- lm()에서
income~education + prestige + women + census
는income~.
으로 줄일 수 있는데 이때 '.'은 income을 제외한 나머지가 모두 독립변수라는 의미 - stepAIC()는 매개변수로 받은 모델에서 불필요한 변수를 제거해 나가는 방식으로 작업
- 그에 따라 마지막에는 prestige와 women만이 남은 것을 확인할 수 있음
- 회귀식은
income = 431.57 + (165.87*prestige) - (48.38*women)
- Adjusted R-squared 값이 mod3는 변수 2개에 0.6327, 앞의 mod1은 변수 3개에 0.6323으로 설명력은 거의 동일하지만 mod3가 더 단순하기 때문에 mod3가 더 나은 모델
Logistic regression
- 로지스틱 회귀
- 회귀모델에서 종속변수의 값의 형태가 연속형 숫자가 아닌 범주형 값인 경우를 다루기 위해서 만들어진 통계적 방법
분류
- 주어진 데이터로부터 어떤 범주를 예측하는 분야
- 로지스틱 회귀도 기본적으로 회귀 기법이기 때문에 종속변수가 숫자로 표현되어야 함
iris.new <- iris
iris.new$Species <- as.integer(iris.new$Species) # 범주형 자료를 정수로 변환
head(iris.new)
mod.iris <- glm(Species~., data=iris.new) # 로지스틱 회귀모델 도출
summary(mod.iris)
> head(iris.new)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 1
2 4.9 3.0 1.4 0.2 1
3 4.7 3.2 1.3 0.2 1
4 4.6 3.1 1.5 0.2 1
5 5.0 3.6 1.4 0.2 1
6 5.4 3.9 1.7 0.4 1
> mod.iris <- glm(Species~., data=iris.new) # 로지스틱 회귀모델 도출
> summary(mod.iris)
Call:
glm(formula = Species ~ ., data = iris.new)
Deviance Residuals:
Min 1Q Median 3Q Max
-0.59215 -0.15368 0.01268 0.11089 0.55077
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.18650 0.20484 5.792 4.15e-08 ***
Sepal.Length -0.11191 0.05765 -1.941 0.0542 .
Sepal.Width -0.04008 0.05969 -0.671 0.5030
Petal.Length 0.22865 0.05685 4.022 9.26e-05 ***
Petal.Width 0.60925 0.09446 6.450 1.56e-09 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for gaussian family taken to be 0.04800419)
Null deviance: 100.0000 on 149 degrees of freedom
Residual deviance: 6.9606 on 145 degrees of freedom
AIC: -22.874
Number of Fisher Scoring iterations: 2
# 예측 대상 데이터 생성(데이터프레임)
unknown <- data.frame(rbind(c(5.1, 3.5, 1.4, 0.2)))
names(unknown) <- names(iris)[1:4]
unknown
pred <- predict(mod.iris, unknown) # 품종 예측
pred
round(pred, 0)
# 실제 품종명 알아보기
pred <- round(pred, 0)
pred
levels(iris$Species)
levels(iris$Species)[pred]
> # 예측 대상 데이터 생성(데이터프레임)
> unknown <- data.frame(rbind(c(5.1, 3.5, 1.4, 0.2)))
> names(unknown) <- names(iris)[1:4]
> unknown
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.1 3.5 1.4 0.2
> pred <- predict(mod.iris, unknown) # 품종 예측
> pred
1
0.9174506
> round(pred, 0)
1
1
> # 실제 품종명 알아보기
> pred <- round(pred, 0)
> pred
1
1
> levels(iris$Species)
[1] "setosa" "versicolor" "virginica"
> levels(iris$Species)[pred]
[1] "setosa"
test <- iris[,1:4]
pred <- predict(mod.iris, test) # 모델을 이용한 예측
pred <- round(pred, 0)
pred
answer <- as.integer(iris$Species) # 실제 품종 정보
pred == answer # 예측 품종과 실제 품종이 같은지 비교
acc <- mean(pred == answer) # 예측 정확도 계산
acc
> pred
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
3 3 3 3 3 3 3 3 3 3 3 2 3 3 3 3 3 3 3 3 3 3 3 3 3 2 3
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
> answer <- as.integer(iris$Species) # 실제 품종 정보
> pred == answer # 예측 품종과 실제 품종이 같은지 비교
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
TRUE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
145 146 147 148 149 150
TRUE TRUE TRUE TRUE TRUE TRUE
> acc <- mean(pred == answer) # 예측 정확도 계산
> acc
[1] 0.9733333