[Data Science With R] 2. 데이터 변형 (202405)

2023. 3. 29. 21:21·Data Science/Manipulation

1-1. filter( )로 조건에 맞는 행 선택

  • 설명 : 조건을 만족하는 모든 행을 남기는 데이터 프레임 서브셋팅(Subsetting) 함수
  • 조건의 결과가 TRUE인 모든 행을 남기며, FALSE나 NA를 반환 시에는 해당 행은 출력하지 않는다.
  • dot-dot-dot (...)에 (논리)조건이 들어가며 여러 개의 조건이 들어가면 & 연산으로 묶여서 계산
  • [advanced] Lazy Evaluation을 지원하므로 결과를 필요로 하기 전까지 필터링 조건을 평가하지 않음

  • 유용한 필터링 함수 
    • 논리연산자 : &(and), |(or), !(not), xor
    • between(x, a, b) : [a, b]에 포함되는 x는 TRUE 반환
    • x %in% y : x가 y에 포함되는지 반환하는 논리함수
    • near(x, y, tol) : 부등소수점 비교시 유용
    • is.na(x) : x의 값이 NA인지 확인하는 논리함수
    • str_detect : 문자열에 정규표현식(Regex)가 포함되어 있는지 확인하는 함수

  • [참고] Grouping 연산 지원하므로 grouped data / ungrouped data에 따라 결과가 다를 수 있다.
test <- tibble(name = rep(letters[1:3], each=3), num = 1:9)
test |> filter(num >= mean(num))
test |> group_by(name) %>% filter(num >= mean(num))

  • [코드설명] 그룹화 되지 않은 경우에는 전체 평균(1~9의 평균인 5)보다 같거나 큰 값들이 출력
  • [코드설명] 그룹화 된 경우에는 각 그룹(a, b, c)에서의 평균을 구하여(2, 5, 8) 각 그룹의 원소가 그룹의 평균보다 큰 경우에 출력 

 

[참고-advanced] 다양한 테이블에 동일한 조건 필터링을 해야하는 경우 expr함수와 !!를 사용할 수 있다.
expr함수를 사용해 코드를 실행시키지 않고 표현식을 반환하고 추후에 필요한 부분에 평가하여(!!) 다양한 테이블에 동일한 연산을 수행할 수 있도록 한다.

my_condition <- rlang::expr(Sepal.Length > 3 & Species %in% c("setosa", "virginica"))
iris |> filter(!!my_condition)

 

 

1-2. Slice( )로 위치에 따른 행 선택 

  • 행 선택, 행 제거, 행 중복 등 다양하게 활용할 수 있음 ( https://moogie.tistory.com/83 참고 )
  • dot-dot-dot (...)에 정수형 벡터를 지정할 수 있으며 양수인 경우는 해당 행을 출력, 음수인 경우에는 해당 행 제외한 결과 출력
  • Grouping 연산을 지원하므로 grouped data / ungrouped data에 따라 결과가 다를 수 있다.
  • 관련 함수 설명 
    • slice_head와 slice_tail은 각각 첫번째, 마지막부터 n개의 행을 선택 (prop 인자 제공시 nrow(data)*prop의 수만큼)
    • slice_sample은 행을 랜덤하게 선택 (argument : replace, weight_by)
    • slice_min, slice_max 함수는 주어진 변수(order_by)의 가장 작은/큰 행의 모든 열과 함께 보여준다. (with_ties로 동점 처리 설정) 

 

 

1-3. distinct( )로 중복되지 않은 행 선택

  • 각 데이터포인트(인스턴스)가 유일한 데이터 포인트만 반환하여 모든 변수의 값이 같은 행은 제거
  • unique.data.frame 함수와 동작 방식이 유사하며 distinct(df, col1, col2)는 unqiue(select(df, col1, col2))와 같다.
  • [참고] count(x, ...) 함수를 사용하여 1개 이상의 변수 값의 유일값의 개수 또는 각 그룹에서의 관측치 수를 반환하는 함수로
    count(df, a, b)는 group_by(df, a, b) |> summarise(n=n())와 같다. 
flights |> distinct() # remove duplicate rows
flights |> distinct(origin, dest)

 

 

1-4. arrange( )로 값의 크기에 따른 행 정렬

  • 열의 값을 기준으로 데이터 프레임의 행을 정렬하는 함수
  • Grouping 연산을 지원하지 않으므로 그룹화 연산을 원한다면 인자 .by_group = T를 사용해야 함 
iris_test <- iris |> group_by(Species) |> slice_sample(n=2)
iris_test |> arrange(Sepal.Width, Petal.Width)
iris_test |> arrange(Sepal.Width, Petal.Width, .by_group = T)

(좌) iris test 데이터 (중) 2번째 코드 (우) 3번째 코드

  • 기본적으로 오름차순으로 정렬하나 내림차순 정렬하려면 desc( ) 함수를 사용해야 함
  • 결측값 NA는 항상 마지막에 정렬되지만, desc함수와 is.na 함수를 활용해 처음에 나오도록 할 수 있다.
  • 데이터가 큰 경우에 여러 열을 기준으로 정렬하면 속도가 느릴 수 있으므로 data.table::setorder를 활용
# 5천만개의 데이터를 정렬하는 시간 비교
# dplyr::arrange --> 100회 평균 13초
# data.table::setorder --> 100회 평균 2초
bigdata <- diamonds |> slice(rep(1:50000, 1000))
microbenchmark::microbenchmark(
  "dplyr"=bigdata |> arrange(carat, price), 
  "data.table"=bigdata |> data.table::setorder(carat, price),
  times = 100)
  
#  Unit: seconds
#       expr      min        lq     mean    median        uq      max neval
#      dplyr 4.231359 12.185045 13.52448 12.856467 13.717012 39.87647   100
# data.table 1.633217  1.683112  2.07923  1.841243  1.990142 26.06883   100

 

  • Selection helper(선택도우미) 함수를 지원하지 않으므로 pick, across 함수와 활용하면 좋음
    • pick(...) : 데이터 마스킹을 지원하는 함수(mutate, arrange, summarise, group_by) 등에서 select 구문을 사용하여 주어진 데이터 열의 하위 집합을 쉽게 선택하는 함수
    • across(.cols, .fns, ...) : 데이터 마스킹을 지원하는 함수(mutate, arrange, summarise, group_by) 등에서 select 구문을 사용하여 다수의 열에 동일한 변환을 적용하는 함수
    • 두 함수 모두 select( ) 구문을 사용하므로 pick, across 함수 내부에서 선택도우미 함수 사용 가능
iris |> arrange(Sepal.Length, Sepal.Width)  # work!
iris |> arrange(starts_with("Sepal"))       # error
iris |> arrange(pick(starts_with("Sepal"))) # work!
# same results
iris |> arrange(across(starts_with("Sepal"), desc))
iris |> arrange(desc(Sepal.Length), desc(Sepal.Width))

 

 

 

2-1. select( )로 열 선택

  • 열의 이름이나 종류(type), 위치 등을 이용해서 열 출력을 유지하거나 드랍하는 함수
  • (열이름1:열이름2) 와 같이 사용하면 데이터 내 열이름1 ~ 열이름2 사이에 있는 열들이 자동으로 선택됨
  • -(열이름), !(열이름) 와 같이 사용하면 해당 열이름을 제외한 나머지 열들을 선택
  • rename(dataset, 변경할이름 = 기존변수명), select(dataset, 변경할변수명 = 기존변수명)
    (purrr::set_names에 unamed vector를 제공하여 일괄로 변경할 수 있음)
    (janitor::clean_names를 사용해 복잡한 변수 명을 문자와 숫자, _로 이루어진 유연한 변수 명으로 변환)
  • 동일한 열을 여러번 입력해도 한번만 출력되며, 열의 이름을 바꿀때 데이터프레임에 동일한 열이름이 있으면 에러 발생
  • Selection Helper Function (선택 도우미 함수)
starts_with("abc") "abc"로 시작하는 열과 매칭 everything( ) 모든 열과 매칭
ends_with("xyz") "xyz"로 끝나는 열과 매칭 last_col() 데이터의 마지막 열을 매칭
contains("ijk") "ijk"를 포함하는 열과 매칭 group_cols() 모든 그룹핑 변수 매칭
matches("regexp") 정규표현식을 포함하는 열과 매칭 all_of / any_of 문자형 벡터에 속한 이름의 열과 매칭
(https://moogie.tistory.com/75)
num_range("x", 1:3) "x1", "x2", "x3"에매칭 where 모든 열에 함수를 적용하여
TRUE를 반환하는  열과 매칭

 

 

2-2. Keep( ), Discard( ), Compact( )로 원하는 조건의 열 남기기

  • keep 함수는 논리함수의 결과 참인 열을 남기며, discard 함수는 논리함수의 결과가 참이 아닌 열을 남기는 함수
  • compact 함수는 NULL인 요소나 길이가 0인 요소를 제거한 결과를 출력하는 함수
  • predicate function을 나타내는 .p인자에는 일반함수, anonymous 함수, formula가 올 수 있다.


예시) mpg에서 문자형 열만 출력하기 위해 select / keep / discard 함수를 활용한 코드

mpg |> select(where(is_character))
mpg |> keep(is_character)
mpg |> discard(~!is_character(.))

 

 

2-3. Pull( )로 원하는 열 선택하기

  • subsetting operation "$"와 유사하나 pipe에서 보기 좋게 작동함
  • 추출하고자 하는 요소의 값을 var에 지정할 수 있으며 변수이름, 양의정수, 음의정수가 올 수 있다.

 

 

 

3. mutate( )로 새로운 변수 추가

  • 기존 변수에 다양한 함수를 적용하여 새로운 열을 추가하는 함수
  • Grouping 연산을 지원하므로 grouped data / ungrouped data에 따라 결과가 다를 수 있다.

  • [파라미터 설명] .before / .after : 기본적으로 새로운 열은 맨 오른쪽에 추가되나 .before, .after 인자를 사용해 신규 열의 위치를 조정할 수 있다.
  • [파라미터 설명] .keep : 새로운 열과 함께 반환할 기존 열을 지정하는 옵션으로 기본값으로는 all(모든값)이나 used(mutate에 사용된 변수만 남길때), unused(mutate에 사용되지 않은 변수만), none(변수를 남기지 않음) 옵션 존재
  • [파라미터 설명] .by : 새로운 열을 만들때, 특정 열의 값을 그룹으로 함수를 적용하는 경우 사용 (group_by 처럼 작동)


  • [참고] mutate(data, 삭제할열이름=NULL)로 설정시 열삭제(Column Drop) 가능 (단, 실제 data에 반영되지는 않음)
  • [참고] transmute( )는 새로운 변수만 남기는 함수로 mutate(.keep = "none")와 유사
  • [참고] 유용한 함수
함수 설명 함수 설명
min_rank 값이 같으면 공동 랭킹을 갖는 랭킹 함수로
rank(ties.method="min")와 동일하며
1, 2, 2, 4, ... 와 같이 진행한다
row_number 값이 같으면 관측이 빠른 값을 더 작은 랭킹 값으로
rank(ties.method="first")와 동일하며
1, 2, 3, 4, ... 와 같이 진행한다
dense_rank min_rank와 유사하나 랭킹간에 갭이 동일한 랭킹 함수 percent_rank min_rank를 [0, 1]로 리스케일링 한 랭킹 함수
cume_dist 해당 값의 누적 분포 함수 ntile 지정된 집단 수 n에 따라 랭킹을 매김
이때 각 집단의 수는 비슷하게 설정
lead(x) 벡터에서 다음값을 찾는 함수로 한칸씩 당겨온다
lead(1:5, 1) >> 2, 3, 4, 5, NA
lag(x) 벡터에서 이전값을 찾는 함수로 한칸씩 뒤로 민다.
lag(1:5, 1) >> NA, 1, 2, 3, 4
pmax /  pmin pmax(변수1, 변수2, 변수3)이면 변수1, 변수2, 변수3에서 제일 큰 값을 각 행마다 반환 first / last / nth 첫번째 / 마지막/ n번째 값을 추출한다.
cum* function cumsum, cummean, cummin, cummax na_if(x, y) x와 y의 값이 동일하면 해당 x의 값을 NA로 변환
coalesce missing value의 값을 특정 값으로 변환 replace_na NA를 특정 값으로 변환
case_match
(.x, ...)
switch 함수와 사용이 유사하며
여러 switch 구문의 벡터화가 허락된다.
이때 각 케이스는 two-sided formula로 작성
case_when
(...)
여러 if_else 구문의 벡터화를 제공하는 함수로
처음으로 조건(condition)에 일치하는 값을 
반환하므로 순서에 주의
case_when(
  x %in% c("a", "b") ~ 1,
  x %in% "c" ~ 2,
  x %in% c("d", "e") ~ 3
)

case_match(
  x,
  c("a", "b") ~ 1,
  "c" ~ 2,
  c("d", "e") ~ 3
)

 

아래 문제를 풀 때, 파이프 연산자를 사용해 댓글에 남겨주세요. 

 [Q] iris 데이터에서 모든 수치형 변수를 각 변수 내에서의 값의 순위(rank)로 변환하시오.

(좌) iris 데이터 (우) 변환된 결과

[Q] diamonds 데이터셋에서 각 관측값의 price와 해당 관측값이 속한 cut 그룹의 price 평균 간의 차이의 제곱을 구하시오.

 

 

4-1. group_by( )로 그룹화

  • 그룹화 된 데이터를 다루는 유용한 함수
    • group_data : 그룹화된 구조를 정의하는 데이터프레임을 반환 (각 그룹과 List-Column 형식으로 각 그룹별 데이터 위치 제공)
    • group_keys : 그룹화에 사용된 유일한 변수의 값을 데이터 프레임 형식으로 반환
    • group_rows : 각 그룹에 속한 데이터의 위치를 List 형식으로 반환
    • group_indices : 각 데이터가 속한 그룹의 고유번호 반환
    • group_vars : 그룹화에 사용된 변수의 이름을 문자형 벡터로 반환
    • group_size : 각 그룹의 원소 수를 반환
    • n_groups : 그룹의 수를 반환
  • ungroup 함수를 통해 그룹화 해제

  • purrr-style function (함수형 프로그래밍 함수)
    • group_map(.data, .f, ...) : 각 그룹별로 .f 함수를 적용하여 나온 결과를 리스트로 반환
    • group_modify(.data, .f, ...) : 각 그룹별로 .f 함수를 적용하여 나온 결과를 재구성해 데이터 프레임으로 반환
      (.f로 함수나 formula가 올 수 있는데, formula인 경우 "."(또는 ".x")은 각 그룹데이터를 나타내며, ".y"는 키를 나타내는 티블
  • 기타 유용한 함수
    • group_nest : grouping specification을 통한 중첩(nest) 티블 반환
    • group_split : 데이터 프레임을 각 그룹 기준으로 분리하는 함수로 리스트 반환
    • group_trim : 데이터에 존재하지 않는 그룹화 범주를 제거(Drop)하는 함수

      

 

4-2. summarise( )로 그룹화 요약

  • 새로운 데이터 프레임을 생성하며 그룹 변수의 각 조합별로 요약된 값을 반환한다. (그룹화된 데이터가 아닐시 전체 데이터 요약)
  • ...에는 이름과 요약을 수행할 함수가 지정되어야 하며 반환 값은 길이가 1인 벡터이거나 데이터 프레임이여야 함
  • [파라미터 설명] 그룹화 된 데이터 프레임에 summarise를 적용하는 경우 기본적으로 마지막 그룹화 변수를 벗겨내지만(peel off) .groups 옵션을 통해서 제어할 수 있다. (default = "drop_last", "drop"(그룹화 해제), "keep"(그룹화 유지))

  • summarise에 유용한 함수
    • n( ) : 그룹 내 관측수를 반환
    • n_distinct( ) : 그룹 내 유일값의 수를 반환

 

저작자표시 (새창열림)

'Data Science > Manipulation' 카테고리의 다른 글

[Data Science With R] 6. 파싱(Parsing) (202405)  (0) 2023.03.31
[Data Science With R] 5. readr로 파일 읽기 (202503)  (0) 2023.03.31
[Data Science With R] 4. 티블(Tibble) (202406)  (1) 2023.03.30
[Data Science With R] 3. 탐색적 데이터 분석 (Exploratory Data Analysis) (202405)  (0) 2023.03.29
[Data Science with R] 1. 데이터 시각화 (202405)  (1) 2023.03.29
'Data Science/Manipulation' 카테고리의 다른 글
  • [Data Science With R] 5. readr로 파일 읽기 (202503)
  • [Data Science With R] 4. 티블(Tibble) (202406)
  • [Data Science With R] 3. 탐색적 데이터 분석 (Exploratory Data Analysis) (202405)
  • [Data Science with R] 1. 데이터 시각화 (202405)
임파카
임파카
[ML & Statistics] 모바일 버전에서 수식 오류가 있어 PC 환경에서 접속하는 것을 권장합니다.
  • 임파카
    무기의 스탯(Stat)
    임파카
  • 전체
    오늘
    어제
    • Study (149)
      • Data Science (44)
        • Modeling (18)
        • Manipulation (21)
        • Visualization (4)
      • Statistics (59)
        • Mathmetical Statistics (53)
        • Categorical DA (1)
      • Web Programming (17)
      • AI (26)
        • Machine Learning (16)
        • Deep Learning (10)
      • 활동 및 프로젝트 (3)
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
임파카
[Data Science With R] 2. 데이터 변형 (202405)
상단으로

티스토리툴바