[R] 9. 기술통계분석

반응형

0. 예시로 쓰일 데이터 예제

set.seed(2021)

# 임의로 데이터를 생성한다. (100명의 유저가 특정 곡을 스트리밍한 이력)
temp <- tibble(
  user_id = c(10000:10149),
  user_age = sample(x = round(runif(n = 50, min = 18, max = 50), 0), size = 150, replace = TRUE),
  user_gender = sample(x = c("남성", "여성"), size = 150, prob = c(0.5, 0.5), replace = TRUE),
  song_id = sample(x = letters[1:15], size = 150, replace = TRUE),
  streaming_count = rpois(n = 150, lambda = 20),
  download_count = rpois(n = 150, lambda = 5)
) %>% 
  mutate(
    song_class_flag = case_when(
      song_id %in% c("d", "e", "f") ~ "인기곡",
      TRUE ~ "비인기곡"
    )
  )

temp
## # A tibble: 150 x 7
##    user_id user_age user_gender song_id streaming_count download_count
##      <int>    <dbl> <chr>       <chr>             <int>          <int>
##  1   10000       44 여성        e                    20              6
##  2   10001       47 남성        f                    21              6
##  3   10002       49 남성        k                    14              3
##  4   10003       44 남성        j                     8              4
##  5   10004       26 여성        f                    20              5
##  6   10005       44 여성        j                    17              2
##  7   10006       20 여성        j                    24              3
##  8   10007       27 남성        l                    24              1
##  9   10008       34 여성        f                    20              5
## 10   10009       26 남성        d                    27              6
## # … with 140 more rows, and 1 more variable: song_class_flag <chr>





1. 들어가며..

  • 우선 기술통계치를 계산하기 위한 함수들로는 count() 함수와 summarise_*() 함수 등을 언급할 수 있습니다.
    • summarise(): 개별 함수에만 적용되는 함수
    • summarise_if(): 특정 조건을 만족하는 변수에만 적용되는 함수
    • summarise_at(): 지정된 변수명이나 위치에 있는 변수에만 적용되는 함수
    • summarise_all(): 모든 변수들에 적용되는 함수
  • 이와 더불어 기술통계분석 결과를 시각화할 수 있는 라이브러리로는 대표적으로 ggplot2가 있습니다.
    (tidyverse의 부속 라이브러리에는 ggplot2가 내포되어 있습니다)
  • 시각화도 같이 설명하면 좋겠지만, ggplot2에 대한 설명은 따로 포스팅하도록 하겠습니다.





2. 단순 빈도분석

  • 단순히 로그의 수를 세기에는 count() 함수를 사용할 수 있습니다.
# 단순히 count() 함수만 사용하여 song_id 카운팅
temp %>% 
  count(song_id)
## # A tibble: 15 x 2
##    song_id     n
##    <chr>   <int>
##  1 a           9
##  2 b           9
##  3 c           8
##  4 d          12
##  5 e           5
##  6 f          14
##  7 g           8
##  8 h           6
##  9 i          15
## 10 j          13
## 11 k           8
## 12 l          15
## 13 m           9
## 14 n           9
## 15 o          10
# group_by() + summarise() + n() 사용
temp %>% 
  group_by(song_id) %>% 
  summarise(n = n())
## # A tibble: 15 x 2
##    song_id     n
##    <chr>   <int>
##  1 a           9
##  2 b           9
##  3 c           8
##  4 d          12
##  5 e           5
##  6 f          14
##  7 g           8
##  8 h           6
##  9 i          15
## 10 j          13
## 11 k           8
## 12 l          15
## 13 m           9
## 14 n           9
## 15 o          10

 

  • 때로는 유니크 집계값이 필요할 수도 있습니다.
  • 유니크 집계가 필요한 경우는 summarise() 함수 안에서 n_distinct() 함수를 사용할 수 있습니다.
temp %>% 
  group_by(song_id) %>% 
  summarise(user_count = n_distinct(user_id))
## # A tibble: 15 x 2
##    song_id user_count
##    <chr>        <int>
##  1 a                9
##  2 b                9
##  3 c                8
##  4 d               12
##  5 e                5
##  6 f               14
##  7 g                8
##  8 h                6
##  9 i               15
## 10 j               13
## 11 k                8
## 12 l               15
## 13 m                9
## 14 n                9
## 15 o               10

 

  • 이번에는 유저의 연령대를 10단위로 범주화하여 연령대별/성별 유저 수를 계산해보겠습니다.
# count() 함수만 사용
temp %>% 
  mutate(
    user_age_category = cut_width(user_age, width = 10),
    user_gender
  ) %>% 
  count(user_age_category, user_gender)
## # A tibble: 8 x 3
##   user_age_category user_gender     n
##   <fct>             <chr>       <int>
## 1 [15,25]           남성           12
## 2 [15,25]           여성           16
## 3 (25,35]           남성           17
## 4 (25,35]           여성           14
## 5 (35,45]           남성           21
## 6 (35,45]           여성           23
## 7 (45,55]           남성           28
## 8 (45,55]           여성           19
# group_by() + summarise() + n_distinct() 사용
temp %>% 
  group_by(
    user_age_category = cut_width(user_age, width = 10),
    user_gender
  ) %>% 
  summarise(user_count = n_distinct(user_id)) %>% 
  ungroup()
## # A tibble: 8 x 3
##   user_age_category user_gender user_count
##   <fct>             <chr>            <int>
## 1 [15,25]           남성                12
## 2 [15,25]           여성                16
## 3 (25,35]           남성                17
## 4 (25,35]           여성                14
## 5 (35,45]           남성                21
## 6 (35,45]           여성                23
## 7 (45,55]           남성                28
## 8 (45,55]           여성                19

 

  • 이렇게 집계한 데이터는 spread() 함수를 사용하여 교차표의 형태로도 만들 수 있습니다.
# 위 결과에 spread() 함수를 사용하여 교차분석표를 생성
temp %>% 
  group_by(
    user_age_category = cut_width(user_age, width = 10),
    user_gender
  ) %>% 
  summarise(user_count = n_distinct(user_id)) %>% 
  ungroup() %>% 
  spread(key = "user_age_category", value = "user_count")
## `summarise()` has grouped output by 'user_age_category'. You can override using the `.groups` argument.
## # A tibble: 2 x 5
##   user_gender `[15,25]` `(25,35]` `(35,45]` `(45,55]`
##   <chr>           <int>     <int>     <int>     <int>
## 1 남성               12        17        21        28
## 2 여성               16        14        23        19

 

  • mutate_if 함수를 적용하여 특정 조건을 만족하는 변수에 함수를 씌울 수도 있습니다.
temp %>% 
  group_by(
    user_age_category = cut_width(user_age, width = 10),
    user_gender
  ) %>% 
  summarise(user_count = n_distinct(user_id)) %>% 
  ungroup() %>% 
  mutate_if(
    is.integer,          # (1 )정수형(integer) 변수들을 대상으로
    funs((./sum(.))*100) # (2) 빈도를 백분율로 표시
  ) %>% 
  spread(key = "user_age_category", value = "user_count")
## # A tibble: 2 x 5
##   user_gender `[15,25]` `(25,35]` `(35,45]` `(45,55]`
##   <chr>           <dbl>     <dbl>     <dbl>     <dbl>
## 1 남성              8       11.3       14        18.7
## 2 여성             10.7      9.33      15.3      12.7





3. 기술통계량 계산

  • 한 개의 연속형 변수에 대해서 기술통계량을 구해볼 수 있습니다.
  • 아래 예시에 적용된 사례뿐만 아니라 베이스로 계산할 수 있는 계산들 대부분 다 적용이 가능합니다. (상관계수, 분위수 등)
# 평균 스트리밍 횟수 구하기
temp %>% 
  summarise(avg_streaming_count = mean(streaming_count, na.rm = TRUE))
## # A tibble: 1 x 1
##   avg_streaming_count
##                 <dbl>
## 1                19.9
# 스트리밍 횟수 중앙값 구하기
temp %>% 
  summarise(med_streaming_count = median(streaming_count, na.rm = TRUE))
## # A tibble: 1 x 1
##   med_streaming_count
##                 <dbl>
## 1                  20
# 스트리밍 횟수 최소값 구하기
temp %>% 
  summarise(min_streaming_count = min(streaming_count, na.rm = TRUE))
## # A tibble: 1 x 1
##   min_streaming_count
##                 <int>
## 1                   6
# 스트리밍 횟수 최대값 구하기
temp %>% 
  summarise(max_streaming_count = max(streaming_count, na.rm = TRUE))
## # A tibble: 1 x 1
##   max_streaming_count
##                 <int>
## 1                  37
# 스트리밍 횟수 표준편차 구하기
temp %>% 
  summarise(std_streaming_count = sd(streaming_count, na.rm = TRUE))
## # A tibble: 1 x 1
##   std_streaming_count
##                 <dbl>
## 1                5.14

 

  • 여러 번수들의 통계량 또한 구할 수 있습니다.
  • 이 떄에는 summarise_at() 함수를 사용하며 vars() 파라미터에는 변수명 또는 변수의 위치(몇번째)값을 입력합니다.
# 유저의 연령대, 스트리밍 횟수, 다운로드 횟수의 평균값
temp %>% 
  summarise_at(
    vars("user_age", "streaming_count", "download_count"),
    funs(mean(., na.rm = TRUE))
  )
## # A tibble: 1 x 3
##   user_age streaming_count download_count
##      <dbl>           <dbl>          <dbl>
## 1     37.3            19.9           5.22
temp %>% 
  summarise_at(
    vars(c(2, 5, 6)),
    funs(mean(., na.rm = TRUE))
  )
## # A tibble: 1 x 3
##   user_age streaming_count download_count
##      <dbl>           <dbl>          <dbl>
## 1     37.3            19.9           5.22

 

  • 위 결과를 그룹별로도 확인해볼 수 있습니다.
  • 이 때에는 group_by() 함수를 통해 그룹화시킬 변수를 정의해줍니다.
# 남성/여성 유저별 유저의 연령대, 스트리밍 횟수, 다운로드 횟수의 평균값
temp %>% 
  group_by(user_gender) %>% 
  summarise_at(
    vars("user_age", "streaming_count", "download_count"),
    funs(mean(., na.rm = TRUE))
  )
## # A tibble: 2 x 4
##   user_gender user_age streaming_count download_count
##   <chr>          <dbl>           <dbl>          <dbl>
## 1 남성            37.9            19.8           5.26
## 2 여성            36.8            20.1           5.18

 

  • 커스텀 함수를 정의하여 동일하게 적용할 수 있습니다. 아래는 예시입니다.
# 99% 신뢰구간을 구하는 함수를 정의
cal_ci <- function(vals){
  avg = mean(vals, na.rm = TRUE)
  std = sd(vals, na.rm = TRUE)
  n = length(vals)
  lower = round(avg - 2.58*std/sqrt(n), 2)
  upper = round(avg + 2.58*std/sqrt(n), 2)
  
  result = paste0(
    round(avg, 2), " (", lower, ", ", upper, ")"
  )
  
  result
}

# 위에서 정의한 커스텀 함수를 summarise_at() 함수에 적용
temp %>% 
  group_by(user_gender) %>% 
  summarise_at(
    vars("streaming_count", "download_count"),
    funs(cal_ci)
  )
## # A tibble: 2 x 3
##   user_gender streaming_count      download_count  
##   <chr>       <chr>                <chr>           
## 1 남성        19.77 (18.45, 21.09) 5.26 (4.5, 6.01)
## 2 여성        20.14 (18.39, 21.89) 5.18 (4.3, 6.06)
반응형

'tidyverse' 카테고리의 다른 글

[R] 11. t-Test  (0) 2021.07.13
[R] 10. 피어슨 상관계수(Pearson's Corrleation)  (0) 2021.07.06
[R] 8. 데이터 합치기 (join)  (0) 2021.07.05
[R] 7. 데이터 형태 변환  (0) 2021.07.05
[R] 6. 날짜 및 시간 변수 (lubridate)  (3) 2021.07.05
TAGS.

Comments