Ch 05. 데이터 변환 (mutate, case_when)
원본 데이터에는 없지만 분석에 꼭 필요한 변수가 있습니다. 연비를 킬로미터로 환산한 값, 나이를 구간으로 나눈 범주, 두 열을 조합해서 만든 점수. 이런 파생 변수를 만드는 것이 mutate()의 역할입니다.
mutate()로 새 열 만들기
mpg 데이터에서 도심 연비(cty)와 고속도로 연비(hwy)의 평균을 구해 새 열로 추가합니다.
library(tidyverse)
mpg %>%
mutate(avg_mpg = (cty + hwy) / 2) %>%
select(manufacturer, model, cty, hwy, avg_mpg)
# A tibble: 234 × 5
manufacturer model cty hwy avg_mpg
<chr> <chr> <int> <int> <dbl>
1 audi a4 18 29 23.5
2 audi a4 21 29 25
3 audi a4 20 31 25.5
...
mutate() 안에서 만든 열을 같은 mutate() 안에서 바로 참조할 수도 있습니다.
mpg %>%
mutate(
avg_mpg = (cty + hwy) / 2,
avg_kmpl = avg_mpg * 0.4251 # 미국 mpg → 한국 km/L 환산
) %>%
select(manufacturer, model, avg_mpg, avg_kmpl)
# A tibble: 234 × 4
manufacturer model avg_mpg avg_kmpl
<chr> <chr> <dbl> <dbl>
1 audi a4 23.5 9.99
2 audi a4 25 10.6
...
기존 열 변환
mutate()는 새 열을 추가할 뿐 아니라 기존 열을 덮어쓸 수도 있습니다.
# 배기량을 소수점 없이 반올림
mpg %>%
mutate(displ = round(displ, 0)) %>%
select(manufacturer, model, displ)
# 제조사 이름을 대문자로 변환
mpg %>%
mutate(manufacturer = toupper(manufacturer)) %>%
select(manufacturer, model)
transmute()로 선택하며 변환
transmute()는 mutate()와 달리 지정한 열만 남깁니다. mutate() 후 select()를 쓰는 것과 같습니다.
mpg %>%
transmute(
manufacturer,
model,
avg_kmpl = (cty + hwy) / 2 * 0.4251
)
# A tibble: 234 × 3
manufacturer model avg_kmpl
<chr> <chr> <dbl>
1 audi a4 9.99
2 audi a4 10.6
...
case_when()으로 조건 분기
case_when()은 여러 조건에 따라 다른 값을 할당합니다. if-else 체인을 깔끔하게 표현합니다.
mpg의 hwy 연비를 기준으로 등급을 매깁니다.
mpg %>%
mutate(
grade = case_when(
hwy >= 35 ~ "A",
hwy >= 28 ~ "B",
hwy >= 22 ~ "C",
TRUE ~ "D"
)
) %>%
select(manufacturer, model, hwy, grade)
# A tibble: 234 × 4
manufacturer model hwy grade
<chr> <chr> <int> <chr>
1 audi a4 29 B
2 audi a4 29 B
3 audi a4 31 B
4 audi a4 30 B
5 audi a4 26 C
...
case_when()의 구조는 조건 ~ 값 쌍을 순서대로 평가합니다. 위에서부터 처음으로 TRUE가 되는 조건의 값이 사용됩니다. 마지막 TRUE ~ "D"는 모든 조건에 해당하지 않을 때의 기본값입니다.
문자 조건도 자유롭게 쓸 수 있습니다.
mpg %>%
mutate(
origin = case_when(
manufacturer %in% c("audi", "volkswagen") ~ "독일",
manufacturer %in% c("toyota", "honda", "nissan") ~ "일본",
manufacturer %in% c("chevrolet", "ford", "dodge") ~ "미국",
TRUE ~ "기타"
)
) %>%
select(manufacturer, model, origin)
# A tibble: 234 × 3
manufacturer model origin
<chr> <chr> <chr>
1 audi a4 독일
2 audi a4 독일
...
across()로 여러 열에 동시 적용
같은 변환을 여러 열에 적용할 때 across()를 사용합니다.
# cty와 hwy를 동시에 km/L로 변환
mpg %>%
mutate(across(c(cty, hwy), ~ .x * 0.4251)) %>%
select(manufacturer, model, cty, hwy)
# A tibble: 234 × 4
manufacturer model cty hwy
<chr> <chr> <dbl> <dbl>
1 audi a4 7.65 12.3
2 audi a4 8.93 12.3
...
across()의 두 번째 인수는 함수입니다. .x는 현재 처리 중인 열을 가리킵니다. ~(tilde)로 시작하는 람다 함수 형식입니다.
열 이름 패턴으로 선택할 수도 있습니다.
# 숫자형 열 모두에 반올림 적용
mpg %>%
mutate(across(where(is.double), round, 1))
# starts_with로 선택
mpg %>%
mutate(across(starts_with("c"), ~ .x * 2))
실전 예제: 여러 변환 한 번에
starwars 데이터셋으로 종합 실습을 해봅니다. 스타워즈 캐릭터 데이터입니다.
starwars %>%
filter(!is.na(height), !is.na(mass)) %>%
mutate(
bmi = mass / (height / 100)^2,
bmi_grade = case_when(
bmi < 18.5 ~ "저체중",
bmi < 25 ~ "정상",
bmi < 30 ~ "과체중",
TRUE ~ "비만"
),
height_m = height / 100
) %>%
select(name, height_m, mass, bmi, bmi_grade) %>%
arrange(desc(bmi))
# A tibble: 59 × 5
name height_m mass bmi bmi_grade
<chr> <dbl> <dbl> <dbl> <chr>
1 Jabba Desilijic Tiure 1.75 1358 443. 비만
2 Dud Bolt 0.94 45 50.9 비만
3 Yoda 0.66 17 39.0 비만
...
키, 체중, BMI, BMI 등급이 한 파이프 안에서 순서대로 처리됩니다. 코드가 분석의 흐름을 그대로 표현합니다.
열을 만드는 방법을 익혔으니, 이제 그룹별로 요약하는 방법을 배웁니다. 데이터 분석에서 가장 자주 쓰는 패턴입니다.