[R] 4. select(), filter(), group_by(), summarise(), arrange(), rename()
반응형
0. 예시로 쓰일 데이터 예제
set.seed(2021)
# 임의로 데이터를 생성한다. (100명의 유저가 특정 곡을 스트리밍한 이력)
temp <- tibble(
user_id = c(10000:10099),
user_age = round(runif(n = 100, min = 18, max = 50), 0),
song_id = sample(x = letters[1:15], size = 100, replace = TRUE),
streaming_count = rpois(n = 100, lambda = 20)
)
# 임의로 유저의 연령값에 결측값을 섞는다.
temp[round(runif(n = 5, min = 0, max = 100)), "user_age"] <- NA
temp
## # A tibble: 100 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10000 32 f 17
## 2 10001 43 l 14
## 3 10002 41 f 19
## 4 10003 30 f 29
## 5 10004 38 h 14
## 6 10005 40 k 23
## 7 10006 38 l 20
## 8 10007 27 m 29
## 9 10008 44 a 11
## 10 10009 49 n 20
## # … with 90 more rows
1. select()
select()
함수를 통해 데이터에서 필요한 변수를 선택하여 조회할 수 있습니다.
# user_id와 user_age 컬럼만 조회
temp %>%
select(user_id, user_age)
## # A tibble: 100 x 2
## user_id user_age
## <int> <dbl>
## 1 10000 32
## 2 10001 43
## 3 10002 41
## 4 10003 30
## 5 10004 38
## 6 10005 40
## 7 10006 38
## 8 10007 27
## 9 10008 44
## 10 10009 49
## # … with 90 more rows
- 비슷한 방식으로 필요하지 않은 변수들을 직접 선택하여
-
를 붙여 선택할 수도 있습니다.
# song_id와 streaming_count 컬럼은 조회에서 제외
temp %>%
select(-song_id, -streaming_count)
## # A tibble: 100 x 2
## user_id user_age
## <int> <dbl>
## 1 10000 32
## 2 10001 43
## 3 10002 41
## 4 10003 30
## 5 10004 38
## 6 10005 40
## 7 10006 38
## 8 10007 27
## 9 10008 44
## 10 10009 49
## # … with 90 more rows
- 데이터 분석을 위해 전처리를 하는 작업을 거치다보면서 변수명에
_id
와 같이 특정 변수명 규칙을 발견할 수 있습니다. - 이를 알면 데이터 전처리 또한 매우 쉽게 처리하실 수 있습니다.
ends_with()
함수는 특정 표현으로 끝나는 변수명을 선택할 수 있는 함수입니다.
# 컬럼이 _id로 끝나는 컬럼들 모두 조회
temp %>%
select(ends_with("_id"))
## # A tibble: 100 x 2
## user_id song_id
## <int> <chr>
## 1 10000 f
## 2 10001 l
## 3 10002 f
## 4 10003 f
## 5 10004 h
## 6 10005 k
## 7 10006 l
## 8 10007 m
## 9 10008 a
## 10 10009 n
## # … with 90 more rows
- 비슷한 방식으로
starts_with()
특정 표현으로 시작하는 변수명을 선택할 수도 있습니다.
# 컬럼이 user_로 시작하는 컬럼들 모두 조회
temp %>%
select(starts_with("user_"))
## # A tibble: 100 x 2
## user_id user_age
## <int> <dbl>
## 1 10000 32
## 2 10001 43
## 3 10002 41
## 4 10003 30
## 5 10004 38
## 6 10005 40
## 7 10006 38
## 8 10007 27
## 9 10008 44
## 10 10009 49
## # … with 90 more rows
- 특정 표현이 포함된 변수명을 선택하는 경우에는
contains()
함수를 활용할 수 있습니다.
# 컬럼에 id라는 문자열에 포함된 컬럼들 모두 조회
temp %>%
select(contains("id"))
## # A tibble: 100 x 2
## user_id song_id
## <int> <chr>
## 1 10000 f
## 2 10001 l
## 3 10002 f
## 4 10003 f
## 5 10004 h
## 6 10005 k
## 7 10006 l
## 8 10007 m
## 9 10008 a
## 10 10009 n
## # … with 90 more rows
a:b
표현을 활용하여 a에서부터 b까지 변수명을 모두 출력할 수도 있습니다.
# user_id ~ song_id 까지 조회
temp %>%
select(user_id:song_id)
## # A tibble: 100 x 3
## user_id user_age song_id
## <int> <dbl> <chr>
## 1 10000 32 f
## 2 10001 43 l
## 3 10002 41 f
## 4 10003 30 f
## 5 10004 38 h
## 6 10005 40 k
## 7 10006 38 l
## 8 10007 27 m
## 9 10008 44 a
## 10 10009 49 n
## # … with 90 more rows
# 두 번째 컬럼부터 네 번째 컬럼까지 조회
temp %>%
select(2:4)
## # A tibble: 100 x 3
## user_age song_id streaming_count
## <dbl> <chr> <int>
## 1 32 f 17
## 2 43 l 14
## 3 41 f 19
## 4 30 f 29
## 5 38 h 14
## 6 40 k 23
## 7 38 l 20
## 8 27 m 29
## 9 44 a 11
## 10 49 n 20
## # … with 90 more rows
2. filter()
- SQL에서 SELECT 함수를 통해 변수를 선택하고 WHERE 절을 통해 데이터에서의 조건을 부여 합니다.
- 마찬가지로 R에서 WHERE절의 역할을 하는 함수는
filter()
함수 입니다. 함수 이름 그대로 설정된 조건을 필터링 하는 기능을 합니다.- R에서 ’같다’의 의미는
==
, ’다르다’의 의미는!=
로 쓰입니다.
- R에서 ’같다’의 의미는
# a라는 곡을 들은 유저만 조회
temp %>%
filter(song_id == "a")
## # A tibble: 9 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10008 44 a 11
## 2 10025 47 a 16
## 3 10028 48 a 18
## 4 10033 47 a 17
## 5 10037 26 a 32
## 6 10058 46 a 28
## 7 10064 45 a 26
## 8 10067 NA a 20
## 9 10087 44 a 20
- ‘AND’ 조건은
&
, ‘OR’ 조건은|
표현을 사용합니다. filter()
함수에 조건절을 컴마(,
)로 구분하는 경우 ‘AND’ 조건으로 인식합니다.
# a라는 곡을 들었으면서 나이는 30세 이하인 유저
temp %>%
filter(song_id == "a" & user_age <= 30)
## # A tibble: 1 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10037 26 a 32
# a라는 곡을 들은 유저들 또는 c라는 곡을 들은 유저들
temp %>%
filter(song_id == "a" | song_id == "c")
## # A tibble: 17 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10008 44 a 11
## 2 10011 45 c 10
## 3 10025 47 a 16
## 4 10026 48 c 17
## 5 10028 48 a 18
## 6 10032 48 c 26
## 7 10033 47 a 17
## 8 10037 26 a 32
## 9 10044 NA c 18
## 10 10053 35 c 18
## 11 10058 46 a 28
## 12 10064 45 a 26
## 13 10065 22 c 21
## 14 10067 NA a 20
## 15 10084 30 c 19
## 16 10085 25 c 17
## 17 10087 44 a 20
- 결측값을 여부를 TRUE 또는 FALSE로 표현해주는 함수는
is.na()
함수가 있습니다.
(TRUE == 1, FALSE == 0으로 인식)
x <- c(NA, 3, 5, NA, 10)
# is.na() 함수를 이용하여 결측값에 해당하는 부분에는 TRUE를 결측값이 아니면 FALSE를 할당
is.na(x)
## [1] TRUE FALSE FALSE TRUE FALSE
# TRUE는 숫자로 1을, FALSE는 0에 해당하는 값임
sum(is.na(x))
## [1] 2
filter()
함수와is.na()
함수를 활용하여 데이터 결측 여부를 확인할 수 있습니다.
# user_age 컬럼에 결측이 있는 값들만 조회
temp %>%
filter(is.na(user_age) == TRUE)
## # A tibble: 5 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10044 NA c 18
## 2 10051 NA g 17
## 3 10067 NA a 20
## 4 10093 NA k 15
## 5 10097 NA m 22
# drop_na() 함수를 이용하여 결측값이 존재하지 않는 관측값만을 추출
temp %>%
drop_na()
## # A tibble: 95 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10000 32 f 17
## 2 10001 43 l 14
## 3 10002 41 f 19
## 4 10003 30 f 29
## 5 10004 38 h 14
## 6 10005 40 k 23
## 7 10006 38 l 20
## 8 10007 27 m 29
## 9 10008 44 a 11
## 10 10009 49 n 20
## # … with 85 more rows
3. group_by()
- 위에서
filter()
함수를 이용하여 특정한 값을 갖는 관측값들을 선별하는 사례를 살펴보았다면, 데이터 전처리 과정에서 특정한 조건에 따라 구분해야 하는 경우도 발생할 수 있습니다. - 이 떄 이용하는 함수는
group_by()
함수로 SQL에서 GROUP BY와 같은 역할을 수행합니다. - 아래 코드는
group_by()
함수를 이용하여 변수 수준 단위로 그룹화하는 작업입니다.
# 곡 별 기준으로 그룹화
temp %>%
select(user_id, song_id, streaming_count) %>%
group_by(song_id)
## # A tibble: 100 x 3
## # Groups: song_id [15]
## user_id song_id streaming_count
## <int> <chr> <int>
## 1 10000 f 17
## 2 10001 l 14
## 3 10002 f 19
## 4 10003 f 29
## 5 10004 h 14
## 6 10005 k 23
## 7 10006 l 20
## 8 10007 m 29
## 9 10008 a 11
## 10 10009 n 20
## # … with 90 more rows
- song_id 변수를 기준으로 묵였다고 표시되는 것(“Groups: song_id”)을 확인할 수 있습니다.
- 그룹화는 한 개 이상 변수를 그룹화 시킬 수 있습니다.
- 이렇게 그룹화 된 데이터를
summarise()
함수를 이용하여 연산을 수행할 수 있습니다.- 합계
sum()
, 평균mean()
, 표준편차sd()
, 카운트n()
, 유니크 카운트n_distinct()
등이 있습니다.
- 합계
temp %>%
drop_na() %>%
group_by(song_id) %>%
summarise(
total_streaming_count = sum(streaming_count),
avg_user_age = mean(user_age),
unique_user_count = n_distinct(user_id)
)
## # A tibble: 15 x 4
## song_id total_streaming_count avg_user_age unique_user_count
## <chr> <int> <dbl> <int>
## 1 a 168 43.4 8
## 2 b 46 35 2
## 3 c 128 36.1 7
## 4 d 77 27.5 4
## 5 e 224 35.3 12
## 6 f 167 32.5 8
## 7 g 150 36.9 7
## 8 h 63 42.2 4
## 9 i 89 38 5
## 10 j 68 32.7 3
## 11 k 187 35.1 9
## 12 l 73 42 4
## 13 m 203 34.2 11
## 14 n 171 30 9
## 15 o 41 39 2
- 만일 먼저 데이터를 집단의 수준별로 구분한 후 특정 변수와 특정 변수(들)의 관계를 살펴보는 경우에는 R에서 기본적으로 제공하는
split()
함수와purrr
라이브러리의map()
함수를 같이 이용하면 매우 유용합니다. split()
함수는tidyverse
라이브러리의group_by()
함수와 차이점이 있다면 괄호 안의 변수 수준을 구분할 때 사용되는 변수를 투입하는 방식에서 차이가 있습니다. 아래 코드에서 보듯split()
함수의 괄호 안에 투입되는 변수는.$변수
형태로 마침표로 시작하게 됩니다.- 여기서 마침표는 코드 앞에서 제시된 데이터를 의미하며 따라서
.$변수
는 앞서 제시된 데이터에 포함된 변수를 의미하게 됩니다.
# song_id별 데이터를 리스트 형태로 분리 (song_id는 a, c만 대상)
temp %>%
drop_na() %>%
filter(song_id %in% c("a", "c")) %>%
split(.$song_id)
## $a
## # A tibble: 8 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10008 44 a 11
## 2 10025 47 a 16
## 3 10028 48 a 18
## 4 10033 47 a 17
## 5 10037 26 a 32
## 6 10058 46 a 28
## 7 10064 45 a 26
## 8 10087 44 a 20
##
## $c
## # A tibble: 7 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10011 45 c 10
## 2 10026 48 c 17
## 3 10032 48 c 26
## 4 10053 35 c 18
## 5 10065 22 c 21
## 6 10084 30 c 19
## 7 10085 25 c 17
- 위의 결과에서 보면 각 song_id별로 streaming_count를 보실 수 있습니다.
- 이를 가지고 각 song_id별 streaming_count와 user_age간 상관계수를 확인하고 싶다면 아래와 같이
magrittr
라이브러리를 불러온 후map()
함수를 이용하시면 됩니다. map()
함수는 벡터의 각 요인별로 특정 함수를 적용하는 함수로map(~ fun, data = .x)
의 형태로 코딩하시면 됩니다.
library(magrittr)
# song_id별 데이터를 리스트로 분리 후 map() 함수를 적용. streaming_count, user_age간의 상관분석
temp %>%
drop_na() %>%
filter(song_id %in% c("a", "c")) %>%
split(.$song_id) %>%
map(~ cor.test(~ streaming_count + user_age, data = .x))
## $a
##
## Pearson's product-moment correlation
##
## data: streaming_count and user_age
## t = -1.9245, df = 6, p-value = 0.1026
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.9213593 0.1538638
## sample estimates:
## cor
## -0.6177925
##
##
## $c
##
## Pearson's product-moment correlation
##
## data: streaming_count and user_age
## t = -0.17867, df = 5, p-value = 0.8652
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.7855868 0.7163783
## sample estimates:
## cor
## -0.07964767
- 만일 위와 같은 결과에서 상관계수만 추정하여 저장하고 싶다면?
map("estimate")
함수를 이용하여 저장할 수 있습니다.
temp %>%
drop_na() %>%
filter(song_id %in% c("a", "c")) %>%
split(.$song_id) %>%
map(~ cor.test(~ streaming_count + user_age, data = .x)) %>%
map("estimate") %>%
as_tibble()
## # A tibble: 1 x 2
## a c
## <dbl> <dbl>
## 1 -0.618 -0.0796
4. arrange()
arrange()
함수는 SQL에서 ORDER BY와 같은 역할을 하는 함수로 데이터를 오름차순 또는 내림차순 정렬할 때 쓰입니다.- 디폴트는 오름차순이며, 내림차순은
desc()
함수를 이용합니다.
# streaming_count 기준 오름차순
temp %>%
arrange(streaming_count) %>%
head()
## # A tibble: 6 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10011 45 c 10
## 2 10019 35 f 10
## 3 10082 49 h 10
## 4 10008 44 a 11
## 5 10047 19 m 12
## 6 10010 19 e 13
# streaming_count 기준 내림차순
temp %>%
arrange(desc(streaming_count)) %>%
head()
## # A tibble: 6 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10037 26 a 32
## 2 10015 26 k 30
## 3 10003 30 f 29
## 4 10007 27 m 29
## 5 10048 20 g 29
## 6 10058 46 a 28
group_by()
함수와 마찬가지로 두 가지 이상의 변수를 정렬할 수 있습니다.
temp %>%
arrange(desc(streaming_count), user_age) %>%
head()
## # A tibble: 6 x 4
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10037 26 a 32
## 2 10015 26 k 30
## 3 10048 20 g 29
## 4 10007 27 m 29
## 5 10003 30 f 29
## 6 10098 42 f 28
- 그룹으로 구분된 데이터를 정렬하는 경우라면
arrange()
함수 내에.by_group = TRUE
옵션을 추가하시면 됩니다.
# POC코드별 스트리밍 횟수 내림차순 정렬
temp %>%
group_by(song_id) %>%
arrange(desc(streaming_count), .by_group = TRUE)
## # A tibble: 100 x 4
## # Groups: song_id [15]
## user_id user_age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10037 26 a 32
## 2 10058 46 a 28
## 3 10064 45 a 26
## 4 10067 NA a 20
## 5 10087 44 a 20
## 6 10028 48 a 18
## 7 10033 47 a 17
## 8 10025 47 a 16
## 9 10008 44 a 11
## 10 10089 31 b 25
## # … with 90 more rows
5. rename()
- 변수의 이름을 분석가가 원하는 이름으로 바꾸고자 할 떄 방법은 크게 두 가지가 있습니다.
- 첫 번째로
tidyverse
패키지에서 제공하는rename()
함수를 이용하는 것이고,
두 번째로 티블 데이터에names()
함수를 적용한 결과를 텍스트 형태의 범주형 변수로 취급하여 원하는 표현을 일괄적으로 바꾸는 방법 입니다. - 두 방법 모두 직관적이며 매우 간단하고 이해하기 쉽습니다. 아래 예제 코드를 통해 살펴보겠습니다.
# 영어로 된 변수명을 rename() 함수를 적용하여 한글로 변경
temp %>%
rename(
`유저 아이디` = user_id,
`유저 나이` = user_age,
`곡 아이디` = song_id,
`스트리밍 횟수` = streaming_count
)
## # A tibble: 100 x 4
## `유저 아이디` `유저 나이` `곡 아이디` `스트리밍 횟수`
## <int> <dbl> <chr> <int>
## 1 10000 32 f 17
## 2 10001 43 l 14
## 3 10002 41 f 19
## 4 10003 30 f 29
## 5 10004 38 h 14
## 6 10005 40 k 23
## 7 10006 38 l 20
## 8 10007 27 m 29
## 9 10008 44 a 11
## 10 10009 49 n 20
## # … with 90 more rows
# names() 함수를 이용하여 데이터의 변수명을 직접 변경
var_name = c("유저 아이디", "유저 나이", "곡 아이디", "스트리밍 횟수")
temp2 <- temp
names(temp2) = var_name
temp2
## # A tibble: 100 x 4
## `유저 아이디` `유저 나이` `곡 아이디` `스트리밍 횟수`
## <int> <dbl> <chr> <int>
## 1 10000 32 f 17
## 2 10001 43 l 14
## 3 10002 41 f 19
## 4 10003 30 f 29
## 5 10004 38 h 14
## 6 10005 40 k 23
## 7 10006 38 l 20
## 8 10007 27 m 29
## 9 10008 44 a 11
## 10 10009 49 n 20
## # … with 90 more rows
names()
함수를 이용하여 일괄적 변경하는 방법은 조금 더 체계적으로 함수를 적용할 수 있습니다.- 예를 들면 user라는 이름이 들어가는 것을 유저라는 표현으로 바꾸는 경우
str_replace()
함수를 이용할 수 있고, 코드는 아래와 같습니다.
# str_replace() 함수를 이용하여 특정 조건에 해당하는 부분을 변경하여 변수명 수정
temp3 <- temp
names(temp3) = str_replace(names(temp3), "user", "유저_")
temp3
## # A tibble: 100 x 4
## 유저__id 유저__age song_id streaming_count
## <int> <dbl> <chr> <int>
## 1 10000 32 f 17
## 2 10001 43 l 14
## 3 10002 41 f 19
## 4 10003 30 f 29
## 5 10004 38 h 14
## 6 10005 40 k 23
## 7 10006 38 l 20
## 8 10007 27 m 29
## 9 10008 44 a 11
## 10 10009 49 n 20
## # … with 90 more rows
# 특정 위치의 변수이름만 변경
names(temp3)[3] = "곡 아이디"
temp3
## # A tibble: 100 x 4
## 유저__id 유저__age `곡 아이디` streaming_count
## <int> <dbl> <chr> <int>
## 1 10000 32 f 17
## 2 10001 43 l 14
## 3 10002 41 f 19
## 4 10003 30 f 29
## 5 10004 38 h 14
## 6 10005 40 k 23
## 7 10006 38 l 20
## 8 10007 27 m 29
## 9 10008 44 a 11
## 10 10009 49 n 20
## # … with 90 more rows
반응형
'tidyverse' 카테고리의 다른 글
[R] 6. 날짜 및 시간 변수 (lubridate) (3) | 2021.07.05 |
---|---|
[R] 5. mutate() (0) | 2021.07.05 |
[R] 3. 파이프 오퍼레이터 (%>%) (0) | 2021.07.05 |
[R] 2. tibble 데이터 (0) | 2021.07.05 |
[R] 1. tidyverse 라이브러리와 tidy data (0) | 2021.07.05 |
TAGS.