[R] 7. 데이터 형태 변환

반응형

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

set.seed(2021)

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

temp
## # A tibble: 100 x 6
##    user_id user_age user_gender song_id streaming_count song_class_flag
##      <int>    <dbl> <chr>       <chr>             <int> <chr>          
##  1   10000       49 여성        i                    19 비인기곡       
##  2   10001       49 여성        m                    28 비인기곡       
##  3   10002       26 여성        f                    21 인기곡         
##  4   10003       48 남성        e                    14 인기곡         
##  5   10004       49 여성        o                    17 비인기곡       
##  6   10005       37 여성        h                    22 비인기곡       
##  7   10006       48 여성        n                    15 비인기곡       
##  8   10007       43 남성        g                    22 비인기곡       
##  9   10008       22 남성        m                    28 비인기곡       
## 10   10009       34 여성        g                    18 비인기곡       
## # … with 90 more rows





1. 데이터 형태

  • 데이터의 형태를 크게 두 가지로 구분한다면 테이블 자체가 긴 형태(long format)와 옆으로 넓은 형태(wide format)으로 구분지을 수 있습니다.
  • tidyverse를 적극 잘 활용하시려면 이 두 가지 데이터 형태에 대해 가볍게라도 어떤 형태인지 인지할 필요가 있습니다.
  • 이해를 쉽게하지 위해 우리가 흔히 보는 데이터를 행렬 형태(matrix format)로 빗대어 표현했을 때 아래와 같이 이해하셔도 됩니다.
    • long format: rows > columns
    • wide format: rows < columns

 

  • 우리는 아래 user_gender, song_id별 sum(streaming_count) 값을 가지고 데이터 형태를 변환하도록 하겠습니다.
temp2 <- temp %>% 
  group_by(user_gender, song_id) %>% 
  summarise(total_streaming_count = sum(streaming_count)) %>% 
  ungroup()
## `summarise()` has grouped output by 'user_gender'. You can override using the `.groups` argument.
temp2
## # A tibble: 30 x 3
##    user_gender song_id total_streaming_count
##    <chr>       <chr>                   <int>
##  1 남성        a                          43
##  2 남성        b                         127
##  3 남성        c                          33
##  4 남성        d                          65
##  5 남성        e                          44
##  6 남성        f                          98
##  7 남성        g                         146
##  8 남성        h                          50
##  9 남성        i                          48
## 10 남성        j                          45
## # … with 20 more rows





2. spread(): long format ~> wide format

  • spread() 함수는 long format을 wide format으로 변환해주는 함수이며 포맷은 아래와 같습니다.
spread(
  data = 데이터,
  key = "넓은 형태로 나열하게 될 변수",
  value = "key 변수에 대한 값"
)

data %>% 
  spread(
    key = "넓은 형태로 나열하게 될 변수",
    value = "key 변수에 대한 값"
  )
# song_id를 기준으로 wide formatting
temp2_spread <- temp2 %>% 
  spread(key = "song_id", value = "total_streaming_count")

temp2_spread
## # A tibble: 2 x 16
##   user_gender     a     b     c     d     e     f     g     h     i     j     k
##   <chr>       <int> <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
## 1 남성           43   127    33    65    44    98   146    50    48    45    24
## 2 여성          104    21    37    35    74    63   100    69    19    82    42
## # … with 4 more variables: l <int>, m <int>, n <int>, o <int>
  • key나 value 파라미터로 받지 않은 변수들은 기존 형태를 유지하되,
    key를 파라미터로 받은 변수는 옆으로 나열하게 되고, value를 파라미터로 받은 변수는 key 변수 값으로 매칭됩니다.





3. gather(): wide format ~> long format

  • gather() 함수는 wide format을 long format으로 변환해주는 함수이며 포맷은 아래와 같습니다.
gather(
  data = 데이터,
  key = "긴 형태로 나열하게 될 변수명",
  value = "key 변수에 대한 값 변수명",
  -var1, -var2, ... # 고려하지 않는 변수
)

data %>% 
  gather(
    key = "긴 형태로 나열하게 될 변수명",
    value = "key 변수에 대한 값 변수명",
    -var1, -var2, ... # 고려하지 않는 변수
  )
# 위에서 살펴본 wide format 데이터를 다시 long format으로 변환
temp2_gather <- temp2_spread %>% 
  gather(key = "song_id", value = "streaming_value", -user_gender)

temp2_gather
## # A tibble: 30 x 3
##    user_gender song_id streaming_value
##    <chr>       <chr>             <int>
##  1 남성        a                    43
##  2 여성        a                   104
##  3 남성        b                   127
##  4 여성        b                    21
##  5 남성        c                    33
##  6 여성        c                    37
##  7 남성        d                    65
##  8 여성        d                    35
##  9 남성        e                    44
## 10 여성        e                    74
## # … with 20 more rows
  • 위 코드에서도 보였듯, spread()와 차이가 있다면, 고려하지 않는 변수는 -변수명을 따로 입력해주는 구조입니다.
  • 즉, wide format에서 user_gender를 제외하고 나머지들을 다시 long format으로 변환하되
    key 변수명은 song_id, 그 key 값에 대한 변수명은 streaming_value로 재정의한 것과 같습니다.





4. 두 가지 이상 교차 변수의 spread(), gather()

  • 두 가지 이상 변수를 unite() 함수를 사용하요 교차한 후 wide format 변환도 가능합니다.
    • unite() 함수는 여러 개의 변수 값을 하나로 뭉쳐주는 함수입니다.
temp3 <- temp %>% 
  unite(col = song, c("song_class_flag", "song_id"), sep = "_") %>% 
  spread(key = "song", value = "streaming_count")

temp3
## # A tibble: 100 x 18
##    user_id user_age user_gender 비인기곡_a 비인기곡_b 비인기곡_c 비인기곡_g
##      <int>    <dbl> <chr>            <int>      <int>      <int>      <int>
##  1   10000       49 여성                NA         NA         NA         NA
##  2   10001       49 여성                NA         NA         NA         NA
##  3   10002       26 여성                NA         NA         NA         NA
##  4   10003       48 남성                NA         NA         NA         NA
##  5   10004       49 여성                NA         NA         NA         NA
##  6   10005       37 여성                NA         NA         NA         NA
##  7   10006       48 여성                NA         NA         NA         NA
##  8   10007       43 남성                NA         NA         NA         22
##  9   10008       22 남성                NA         NA         NA         NA
## 10   10009       34 여성                NA         NA         NA         18
## # … with 90 more rows, and 11 more variables: 비인기곡_h <int>,
## #   비인기곡_i <int>, 비인기곡_j <int>, 비인기곡_k <int>, 비인기곡_l <int>,
## #   비인기곡_m <int>, 비인기곡_n <int>, 비인기곡_o <int>, 인기곡_d <int>,
## #   인기곡_e <int>, 인기곡_f <int>



  • 위에서 나왔던 결과를 반대로 separate() 함수를 사용하여 재변환도 가능합니다.
    • separate() 함수는 unite()와 반대로 여러 개의 변수 값 또는 특정 값이나 구분자로 되어 있는 데이터를 분리하는 역할을 합니다.
temp4 <- temp3 %>% 
  gather(key = "song", value = "streaming_count", -user_id, -user_age, -user_gender, na.rm = TRUE) %>% 
  separate(col = song, c("song_class_flag", "song_id"), sep = "_")

temp4
## # A tibble: 100 x 6
##    user_id user_age user_gender song_class_flag song_id streaming_count
##      <int>    <dbl> <chr>       <chr>           <chr>             <int>
##  1   10019       19 여성        비인기곡        a                    12
##  2   10025       21 남성        비인기곡        a                    19
##  3   10035       49 여성        비인기곡        a                    24
##  4   10036       33 여성        비인기곡        a                    19
##  5   10047       31 여성        비인기곡        a                     8
##  6   10058       20 여성        비인기곡        a                    25
##  7   10086       19 남성        비인기곡        a                    24
##  8   10092       48 여성        비인기곡        a                    16
##  9   10018       43 남성        비인기곡        b                    18
## 10   10022       32 남성        비인기곡        b                    11
## # … with 90 more rows
  • 위 코드를 보시면 아시다시피 gather() 함수에 key, value 값 외에 na.rm = TRUE 옵션이 있습니다.
  • 해당 옵션을 붙이면 넓은 형태의 데이터를 긴 형태의 데이터로 변환하는 과정에서 결측값을 제거한 후 데이터를 변환시킵니다.
반응형
TAGS.

Comments