dplyr group_by()

dplyr를 활용한 그룹 별 계산
dplyr
R
Published

February 1, 2023

group_by() 란?

group_by()는 특정 집단의 범주별로 어떤 값들을 요약하거나 계산할 때 많이 활용되는 함수입니다.

library(dplyr)
starwars |> 
  group_by(species, sex) |> 
  select(height, mass) |> 
  summarise(
    height = mean(height, na.rm = TRUE),
    mass = mean(mass, na.rm = TRUE)
  )
by_species <- starwars |> group_by(species)
by_sex_gender <- starwars |> group_by(sex,gender)

출력했을 때, 데이터가 그룹으로 묶인 것을 알 수 있습니다.

by_species
by_sex_gender

tally() 또는 count()를 이용해 그룹별 n수를 파악할 수도 있습니다.

sort 인자를 통해서 그룹 수가 많은 순서대로 정렬할 수 있습니다.

by_species |> tally()
by_sex_gender |> 
  tally(sort=T)

또한 group_by() 안에서 새로운 변수를 만들어 그 변수에 따른 계산을 할 수도 있습니다.

starwars |> 
  group_by(bmi_cat = cut(mass/(height/100)^2, breaks = c(0,18,23,25,30,Inf))) |> 
  tally()

그룹 변수 정보 확인

그룹 변수를 지정해준 경우, group_keys() 를 통해 그룹 변수의 범주(종류)를 확인할 수 있습니다.

by_species |> group_keys()

한편 group_vars()group_by() 에 사용된 변수의 이름을 확인할 때 사용할 수 있습니다.

by_sex_gender |> group_vars()
[1] "sex"    "gender"

그룹 변수 변경 및 추가

기존의 그룹처리 되어있는 데이터에 group_by() 를 진행할 시, 새로운 그룹 변수로 덮어씌워집니다.

by_species는 앞서 group_by(species)를 통해 species별로 묶은 데이터죠. 여기서 group_by(homeworld)를 추가한다면 기존의 species에서 homeworld를 기준으로 그룹이 묶이게 됩니다.

by_species |> 
  group_by(homeworld) |> 
  tally()

만약 기존의 그룹을 대체하는 것이 아니라 추가를 할 수도 있을텐데요. group_by().add=T 인자를 추가할 경우, 기존에 있던 그룹 변수에 새로운 그룹 변수를 추가할 수도 있습니다.

by_species |> 
  group_by(homeworld, .add=T) |> 
  tally()

그룹 변수 제거

그룹 처리된 데이터를 제거하고 싶은 경우, ungroup() 을 사용합니다.

by_species |> 
  ungroup() |> 
  tally()

물론 특정 그룹 변수만 제외할 수도 있습니다. by_sex_gender에서 sexgender로 묶여있던 것을 ungroup()을 통해 sex만 제거하여 gender만 그룹으로 남아있게 되었습니다.

by_sex_gender |> 
  ungroup(sex) |> 
  tally()

group_by()와 함께 쓰는 동사

다음으로 dplyr에서 group_by()와 자주 쓰이는 함수들을 알아보겠습니다.

1. summarise(), summarize()

summarise()group_by()가 함께 사용될 경우, 그룹별로 요약 계산을 수행합니다. 평균, 표준편차, 중앙값, 최소, 최대값과 같은 값을 출력할 수 있습니다.

by_species |> 
  summarise(
    n=n(),
    mean_height = mean(height,na.rm=T)
  )

.groups인자는 출력되는 결과의 그룹 구조를 다루는 인자입니다. keep은 그룹으로 묶인 상태를 유지하는 반면, drop은 그룹으로 묶인 상태를 해제합니다.

by_sex_gender |> 
  summarise(n=n(), .groups = 'keep')
by_sex_gender |> 
  summarise(n=n(), .groups = 'drop')

2. select(), rename(), relocate()

rename()relocate()group_by()와 관계없이 동일한 작업을 수행합니다. 각각 열의 이름과 위치에만 영향을 미치게 때문입니다.

select()group_by()와 함께 쓰이면 그룹 변수가 항상 함께 선택됩니다.

by_species |> select(mass)

그룹 변수가 함께 선택되는 것을 원치 않는다면 ungroup()을 먼저 사용해야 합니다.

by_species |> ungroup() |> select(mass)

3. arrange()

arrange()group_by()와 함께 쓰일 경우, 그냥 사용하게 되면 group_by() 가 없을 때와 동일합니다. 그러나 .by_group=T 인자를 통해 그룹 변수를 기준으로 정렬되어 결과가 출력됩니다.

by_species |> 
  arrange(desc(mass)) |> 
  relocate(species, mass)
by_species |> 
  arrange(desc(mass), .by_group = T) |> 
  relocate(species, mass)

4. mutate(), transmute()

group_by()와 함께 새로운 변수를 생성할 경우, 그룹 별로 동일한 값이 들어가게 됩니다.

starwars |> 
  group_by(species) |> 
  mutate(mean_height = mean(height, na.rm=T)) |> 
  arrange(desc(species)) |> 
  select(species, height, mean_height)

5. filter()

filter()group_by()를 함께 사용하여, 특정 그룹의 수를 기준으로 선택할 때 사용할 수 있습니다.

아래의 예시에서는 그룹 별 수가 1인 경우를 모두 제외하고 선택한 결과입니다.

by_species |> 
  filter(n()!=1) |> 
  tally()

6. slice()

slice()slice() 계열 함수들이 group_by() 와 함께 사용될 경우, 그룹별로 해당되는 값이 출력됩니다.

# 그룹별 첫번째 값 
by_species |> 
  slice(1) 
by_species |>
  filter(!is.na(height)) |> 
  slice_min(height,n=2)

Update: dplyr 1.1.0

dplyr 1.1.0 업데이트 이후에는 group_by()를 사용하지 않아도 다른 함수들에서 그룹 별 계산을 수행할 수 있습니다. 바로 .by 인자를 통해서 말이죠.

starwars |> 
  mutate(bmi = mass/(height/100)^2) |> 
  summarise(mean_bmi = mean(bmi, na.rm=T),.by=species)
Back to top