텍스트마이닝

비교분석 #2 오즈비

yul_S2 2022. 12. 18. 11:27
반응형

오즈비

상대적으로 중요한 단어 비교하기

 

(1) Long from Wide form 으로 변환하기

여러 텍스트 비교하기 편하게 데이터 구조 바꾸기

 

# 1 Long from

df_long <- frequency %>%
  group_by(president) %>%
  slice_max(n, n = 10) %>%
  filter(word %in% c("국민", "우리", "정치", "행복"))

df_long

## # A tibble: 6 x 3
## # Groups: president [2]
## president word n
## <chr> <chr> <int>
## 1 moon 국민 21
## 2 moon 우리 17
## 3 moon 정치 12
## 4 park 국민 72
## 5 park 행복 23
## 6 park 우리 10 

frequency : president가 "moon"인 행과 "park"인 행이 세로로 길게 나열

 

< Long form 데이터 >

  • 같은 단어가 범주별로 다른 행을 구성
  • 범주별 빈도 비교 어려움
  • 빈도를 활용해 연산하기 불편

 

< wide form 데이터 > 가로로 넓은 형태의 데이터

  • 범주별로 단어 빈도 비교하기 편함
  • 변수간 연산하기 편함

 

# 2 Wide form

library(tidyr)
df_wide <- df_long %>%
  pivot_wider(names_from = president,
              values_from = n)

df_wide

## # A tibble: 4 x 3
## word moon park
##
## 1 국민 21 72
## 2 우리 17 10
## 3 정치 12 NA
## 4 행복 NA 23

tidyr::pivot_wider() : long form을 wide form으로 변환

names_from : 변수명으로 만들 값이 들어 있는 변수

values_from : 변수에 채워넣을 값이 들어 있는 변수

 

 

 

(2)  NA를 0으로 바꾸기

어떤 단어가 둘 중 한 범주에만 있으면 NA

오즈비 계산하기 위해 0으로 변환해야 함

df_wide <- df_long %>%
  pivot_wider(names_from = president,
              values_from = n,
              values_fill = list(n = 0))

df_wide
## # A tibble: 4 x 3
## word moon park
## <chr> <int> <int>
## 1 국민 21 72
## 2 우리 17 10
## 3 정치 12 0
## 4 행복 0 23

df_long
## # A tibble: 6 x 3
## # Groups: president [2]
## president word n
## <chr> <chr> <int>
## 1 moon 국민 21
## 2 moon 우리 17
## 3 moon 정치 12
## 4 park 국민 72
## 5 park 행복 23
## 6 park 우리 10

 

 

 

(3) 연설문 단어 빈도를 Wide form 으로 변환하기

 

frequency_wide <- frequency %>%
  pivot_wider(names_from = president,
              values_from = n,
              values_fill = list(n = 0))

frequency_wide

 

 

 

(4) 오즈비 구하기

어떤 사건이 A 조건에서 발생할 확률이 B 조건에서 발생할 확률에 비해 얼마나 더 큰지를 나타냄
단어가 두 텍스트 중 어디에 등장할 확률이 높은지, 상대적인 중요도를 알 수 있음
# n : 각단어의 빈도
# total : 전체 단어 빈도

 


# 1. 단어의 비중을 나타낸 변수 추가하기

  • 각 단어가 두 연설문에서 차지하는 비중을 나타낸 변수
  •  연설문별로 '각 단어의 빈도'를 '모든 단어 빈도의 합'으로 나눔
frequency_wide <- frequency_wide %>%
  mutate(ratio_moon = ((moon)/(sum(moon))),                    # moon 에서 단어의 비중
         ratio_park = ((park)/(sum(park))))                              # park 에서 단어의 비중

frequency_wide


# # A tibble: 950 x 5
# word      moon  park ratio_moon ratio_park
#                  
#   1 가동         1     0   0.000755    0      
# 2 가사         1     0   0.000755    0      
# 3 가슴         2     1   0.00151     0.00117
# 4 가족         1     1   0.000755    0.00117
# 5 가족구조     1     0   0.000755    0      
# 6 가지         4     0   0.00302     0      
# 7 가치         3     1   0.00226     0.00117
# 8 각종         1     0   0.000755    0      
# 9 감당         1     0   0.000755    0      
# 10 강력         3     0   0.00226     0      
# # ... with 940 more rows
# # i Use `print(n = ...)` to see more rows

 

  • 어떤 단어가 한 연설문에 전혀 사용되지 않으면 빈도 0, 오즈비 0, 단어 비중 비교 불가
  •  빈도가 0보다 큰 값이 되도록 모든 값에 +1
frequency_wide <- frequency_wide %>%
  mutate(ratio_moon = ((moon + 1)/(sum(moon + 1))),          # moon에서 단어의 비중
         ratio_park = ((park + 1)/(sum(park + 1))))                     # park에서 단어의 비중

frequency_wide

# # A tibble: 950 x 5
# word      moon  park ratio_moon ratio_park
#                  
#   1 가동         1     0   0.000879   0.000555
# 2 가사         1     0   0.000879   0.000555
# 3 가슴         2     1   0.00132    0.00111 
# 4 가족         1     1   0.000879   0.00111 
# 5 가족구조     1     0   0.000879   0.000555
# 6 가지         4     0   0.00220    0.000555
# 7 가치         3     1   0.00176    0.00111 
# 8 각종         1     0   0.000879   0.000555
# 9 감당         1     0   0.000879   0.000555
# 10 강력         3     0   0.00176    0.000555
# # ... with 940 more rows
# # i Use `print(n = ...)` to see more rows

 

 

# 2 오즈비 변수 추가하기

  • 오즈비를 보면 단어가 어떤 텍스트에서 상대적으로 더 많이 사용됐는지 알 수 있음
  • "moon"에서 상대적인 비중 클수록 1보다 큰 값
  • "park"에서 상대적인 비중 클수록 1보다 작은 값
  • 두 연설문에서 단어 비중 같으면 1
frequency_wide <- frequency_wide %>%
  mutate(odds_ratio = ratio_moon/ratio_park)

frequency_wide

# # A tibble: 950 x 6
# word      moon  park ratio_moon ratio_park odds_ratio
# <chr>    <int> <int>      <dbl>      <dbl>      <dbl>
#   1 가동         1     0   0.000879   0.000555      1.59 
# 2 가사         1     0   0.000879   0.000555      1.59 
# 3 가슴         2     1   0.00132    0.00111       1.19 
# 4 가족         1     1   0.000879   0.00111       0.793
# 5 가족구조     1     0   0.000879   0.000555      1.59 
# 6 가지         4     0   0.00220    0.000555      3.96 
# 7 가치         3     1   0.00176    0.00111       1.59 
# 8 각종         1     0   0.000879   0.000555      1.59 
# 9 감당         1     0   0.000879   0.000555      1.59 
# 10 강력         3     0   0.00176    0.000555      3.17 
# # ... with 940 more rows

 

# "moon"에서 상대적인 비중 클수록 1보다 큰 값

frequency_wide %>%  arrange(-odds_ratio)

# # A tibble: 950 x 6
# word      moon  park ratio_moon ratio_park odds_ratio
# <chr>    <int> <int>      <dbl>      <dbl>      <dbl>
#   1 복지국가     8     0    0.00396   0.000555       7.13
# 2 세상         6     0    0.00308   0.000555       5.55
# 3 여성         6     0    0.00308   0.000555       5.55
# 4 정의         6     0    0.00308   0.000555       5.55
# 5 강자         5     0    0.00264   0.000555       4.76
# 6 공평         5     0    0.00264   0.000555       4.76
# 7 대통령의     5     0    0.00264   0.000555       4.76
# 8 보통         5     0    0.00264   0.000555       4.76
# 9 상생         5     0    0.00264   0.000555       4.76
# 10 지방         5     0    0.00264   0.000555       4.76
# # ... with 940 more rows

 

# "park"에서 상대적인 비중 클수록 1보다 작은 값

frequency_wide %>%  arrange(odds_ratio)

# # A tibble: 950 x 6
# word      moon  park ratio_moon ratio_park odds_ratio
# <chr>    <int> <int>      <dbl>      <dbl>      <dbl>
#   1 박근혜       0     8   0.000440    0.00499     0.0881
# 2 여러분       2    20   0.00132     0.0116      0.113 
# 3 행복         3    23   0.00176     0.0133      0.132 
# 4 실천         0     5   0.000440    0.00333     0.132 
# 5 정보         0     5   0.000440    0.00333     0.132 
# 6 투명         0     5   0.000440    0.00333     0.132 
# 7 과제         0     4   0.000440    0.00277     0.159 
# 8 국정운영     0     4   0.000440    0.00277     0.159 
# 9 시작         0     4   0.000440    0.00277     0.159 
# 10 지식         0     4   0.000440    0.00277     0.159 
# # ... with 940 more rows

 

# 두 연설문에서 단어 비중 같으면 1

frequency_wide %>%  arrange(abs(1 - odds_ratio))

# # A tibble: 950 x 6
# word    moon  park ratio_moon ratio_park odds_ratio
# <chr>  <int> <int>      <dbl>      <dbl>      <dbl>
#   1 때문       4     3    0.00220    0.00222      0.991
# 2 강화       3     2    0.00176    0.00166      1.06 
# 3 부담       3     2    0.00176    0.00166      1.06 
# 4 세계       3     2    0.00176    0.00166      1.06 
# 5 책임       3     2    0.00176    0.00166      1.06 
# 6 협력       3     2    0.00176    0.00166      1.06 
# 7 가슴       2     1    0.00132    0.00111      1.19 
# 8 거대       2     1    0.00132    0.00111      1.19 
# 9 교체       2     1    0.00132    0.00111      1.19 
# 10 근본적     2     1    0.00132    0.00111      1.19 
# # ... with 940 more rows

 

 

(5) 상대적으로 중요한 단어 추출하기

오즈비가 가장 높거나 가장 낮은 단어 추출하기

top10 <- frequency_wide %>%
  filter(rank(odds_ratio) <= 10 | rank(-odds_ratio) <= 10)

top10 %>% arrange(-odds_ratio)

# # A tibble: 20 x 6
# word      moon  park ratio_moon ratio_park odds_ratio
#                        
#   1 복지국가     8     0   0.00396    0.000555     7.13  
# 2 세상         6     0   0.00308    0.000555     5.55  
# 3 여성         6     0   0.00308    0.000555     5.55  
# 4 정의         6     0   0.00308    0.000555     5.55  
# 5 강자         5     0   0.00264    0.000555     4.76  
# 6 공평         5     0   0.00264    0.000555     4.76  
# 7 대통령의     5     0   0.00264    0.000555     4.76  
# 8 보통         5     0   0.00264    0.000555     4.76  
# 9 상생         5     0   0.00264    0.000555     4.76  
# 10 지방         5     0   0.00264    0.000555     4.76  
# 11 과제         0     4   0.000440   0.00277      0.159 
# 12 국정운영     0     4   0.000440   0.00277      0.159 
# 13 시작         0     4   0.000440   0.00277      0.159 
# 14 지식         0     4   0.000440   0.00277      0.159 
# 15 행복         3    23   0.00176    0.0133       0.132 
# 16 실천         0     5   0.000440   0.00333      0.132 
# 17 정보         0     5   0.000440   0.00333      0.132 
# 18 투명         0     5   0.000440   0.00333      0.132 
# 19 여러분       2    20   0.00132    0.0116       0.113 
# 20 박근혜       0     8   0.000440   0.00499      0.0881

상위 10개: "moon"에서 더 자주 사용되어 odds_ratio가 높은 단어

하위 10개: "park"에서 더 자주 사용되어 odds_ratio가 낮은 단어

 

 

 

(6) 막대 그래프 그리기

#1 비중이 큰 연설문을 나타낸 변수 추가하기

top10 <- top10 %>%
  mutate(president = ifelse(odds_ratio > 1, "moon", "park"),
         n = ifelse(odds_ratio > 1, moon, park))

top10


 

 

#2 막대 그래프 만들기

ggplot(top10, aes(x = reorder_within(word, n, president),
                  y = n,
                  fill = president)) +
  geom_col() +
  coord_flip() +
  facet_wrap(~ president, scales = "free_y") +
  scale_x_reordered()

 

 

 

 

#3 그래프별로 축 설정하기

범주별로 단어 비중 알 수 있도록 x축 크기 각각 정하기

ggplot(top10, aes(x = reorder_within(word, n, president),
                  y = n,
                  fill = president)) +
  geom_col() +
  coord_flip() +
  facet_wrap(~ president, scales = "free") +
  scale_x_reordered() +
  labs(x = NULL) +                                                               # x축 삭제
  theme(text = element_text(family = "nanumgothic"))        # 폰트
  •  x축 크기가 그래프마다 다르므로 해석 조심
  •  막대 길이 같아도 단어 빈도 다름
  •  두 텍스트 단어 빈도 비교 X
  •  각 텍스트에서 상대적으로 중요한 단어가 무엇인지 중심으로 해석

 

 

 

 

(7) 주요 단어가 사용된 문장 보기

speeches_sentence <- bind_speeches %>%
  as_tibble() %>%
  unnest_tokens(input = value,
                output = sentence,
                token = "sentences")

speeches_sentence

head(speeches_sentence)
## # A tibble: 6 x 2
## president sentence
## <chr> <chr>
## 1 moon "정권교체 하겠습니다!"
## 2 moon "정치교체 하겠습니다!"
## 3 moon "시대교체 하겠습니다!"
## 4 moon ""
## 5 moon "‘불비불명(不飛不鳴)’이라는 고사가 있습니다."…
## 6 moon "남쪽 언덕 나뭇가지에 앉아, 3년 동안 날지도 …

tail(speeches_sentence)
## # A tibble: 6 x 2
## president sentence
##
## 1 park 국민 여러분의 행복이 곧 저의 행복입니다.…
## 2 park 사랑하는 조국 대한민국과 국민 여러분을 위해, 앞…
## 3 park 그 길을 함께 해주시길 부탁드립니다.…
## 4 park 감사합니다.
## 5 park 2012년 7월 10일
## 6 park 새누리당 예비후보 박근혜

 

(8) 주요단어가 사용된 문장 추출 - str_detect()

speeches_sentence %>%
  filter(president == "moon" & str_detect(sentence, "복지국가"))

## # A tibble: 8 x 2
## president sentence
## <chr> <chr>
## 1 moon ‘강한 복지국가’를 향해 담대하게 나아가겠습니다.…
## 2 moon 2백 년 전 이와 같은 소득재분배, 복지국가의 사상을 가진 위정자가…
## 3 moon 이제 우리는 복지국가를 향해 담대하게 나아갈 때입니다.…
## 4 moon 부자감세, 4대강 사업 같은 시대착오적 과오를 청산하고, 하루빨리 …
## 5 moon 우리는 지금 복지국가로 가느냐, 양극화의 분열된 국가로 가느냐 하는…
## 6 moon 강한 복지국가일수록 국가 경쟁력도 더 높습니다.…
## 7 moon 결국 복지국가로 가는 길은 사람에 대한 투자, 일자리 창출, 자영업…
## 8 moon 우리는 과감히 강한 보편적 복지국가로 가야 합니다.…


speeches_sentence %>%
  filter(president == "park" & str_detect(sentence, "행복"))

## # A tibble: 19 x 2
## president sentence
## <chr> <chr>
## 1 park 저는 오늘, 국민 한 분 한 분의 꿈이 이루어지는 행복한 대한민국…
## 2 park 국가는 발전했고, 경제는 성장했다는데, 나의 삶은 나아지지 않았고…
## 3 park 과거에는 국가의 발전이 국민의 행복으로 이어졌습니다.…
## 4 park 개인의 창의력이 중요한 지식기반사회에서는 국민 한 사람, 한 사람…
## 5 park 이제 국정운영의 패러다임을 국가에서 국민으로, 개인의 삶과 행복 …
## 6 park 국민 개개인의 꿈을 향한 노력이 국가를 발전시키고 국가 발전이 국…
## 7 park 저는 ‘경제민주화 실현’, ‘일자리 창출’, 그리고 ‘한국형 복지…
## 8 park 국민행복의 길을 열어갈 첫 번째 과제로, 저는 경제민주화를 통해 …
## 9 park 국민행복의 길을 열어갈 두 번째 과제로, 저는 좋은 일자리 창출을…
## 10 park 국민행복의 길을 열어갈 세 번째 과제로, 우리의 실정에 맞으면서 …
## # … with 9 more rows

 

 

 

 

(9) 중요도가 비슷한 단어 살펴보기 

  • odds_ratio가 1에 가까운 단어 추출
  • 대부분 보편적인 의미를 지니는 단어
frequency_wide %>%
  arrange(abs(1 - odds_ratio)) %>%
  head(10)

## # A tibble: 10 x 6
## word moon park ratio_moon ratio_park odds_ratio
## <chr> <int> <int> <dbl> <dbl> <dbl>
## 1 때문 4 3 0.00218 0.00221 0.989
## 2 강화 3 2 0.00175 0.00165 1.06
## 3 부담 3 2 0.00175 0.00165 1.06
## 4 세계 3 2 0.00175 0.00165 1.06
## 5 책임 3 2 0.00175 0.00165 1.06
## 6 협력 3 2 0.00175 0.00165 1.06
## 7 거대 2 1 0.00131 0.00110 1.19
## 8 교체 2 1 0.00131 0.00110 1.19
## 9 근본적 2 1 0.00131 0.00110 1.19
## 10 기반 2 1 0.00131 0.00110 1.19

 

  • 중요도가 비슷하면서 빈도가 높은 단어: 두 텍스트에서 모두 강조한 단어
  frequency_wide %>%
    filter(moon >= 5 & park >= 5) %>%
    arrange(abs(1 - odds_ratio)) %>%
    head(10)

# # A tibble: 10 x 6
# word      moon  park ratio_moon ratio_park odds_ratio
# <chr>    <int> <int>      <dbl>      <dbl>      <dbl>
#   1 사회        14     9    0.00659    0.00555      1.19 
# 2 경제        15    15    0.00703    0.00887      0.793
# 3 사람         9     9    0.00440    0.00555      0.793
# 4 지원         5     5    0.00264    0.00333      0.793
# 5 불안         7     8    0.00352    0.00499      0.704
# 6 우리        17    10    0.00791    0.00610      1.30 
# 7 산업         9     5    0.00440    0.00333      1.32 
# 8 대한민국    11     6    0.00527    0.00388      1.36 
# 9 국가         7    10    0.00352    0.00610      0.576
# 10 교육         6     9    0.00308    0.00555      0.555

 

 

반응형