이 장에서는 많은 양의 모델을 쉽게 작업할 수 있도록 하는 세 가지 아이디어에 대해 학습할 것이다.
간단한 모델을 여러 개 사용하여 복잡한 데이터셋을 잘 이해 한다.
-리스트-열(리스트 형식의 열)을 사용하여 임의의 데이터 구조를 데이터프레임에 저장한다. 예를 들어 리스트-열 선형 모델을 포함하는 열을 가질 수 있다.
library(modelr)
library(tidyverse)
library(gapminder)
gapminder
## # A tibble: 1,704 x 6
## country continent year lifeExp pop gdpPercap
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afghanistan Asia 1952 28.8 8425333 779.
## 2 Afghanistan Asia 1957 30.3 9240934 821.
## 3 Afghanistan Asia 1962 32.0 10267083 853.
## 4 Afghanistan Asia 1967 34.0 11537966 836.
## 5 Afghanistan Asia 1972 36.1 13079460 740.
## 6 Afghanistan Asia 1977 38.4 14880372 786.
## 7 Afghanistan Asia 1982 39.9 12881816 978.
## 8 Afghanistan Asia 1987 40.8 13867957 852.
## 9 Afghanistan Asia 1992 41.7 16317921 649.
## 10 Afghanistan Asia 1997 41.8 22227415 635.
## # ... with 1,694 more rows
이 사례 연구에서는 ’각 국가(country)별 기대 수명(lifeEXP)은 시간(year)에 따라 어떻게 변하는가’라는 질문에 대답하기 위해 세 가지 변수에 초점을 맞출 것이다.
gapminder %>%
ggplot(aes(year, lifeExp, group = country)) +
geom_line(alpha = 1/3)
nz <- filter(gapminder, country == "New Zealand")
nz %>%
ggplot(aes(year,lifeExp)) +
geom_line() +
ggtitle("Full data = ")
nz_mod <- lm(lifeExp ~ year, data = nz)
nz %>%
add_predictions(nz_mod) %>%
ggplot(aes(year, pred)) +
geom_line() +
ggtitle("Linear trend + ")
nz %>%
add_residuals(nz_mod) %>%
ggplot(aes(year, resid)) +
geom_hline(yintercept = 0, color = "white",
size = 3) +
geom_line() +
ggtitle("Remaining pattern")
by_country <- gapminder %>%
group_by(country, continent) %>%
nest()
by_country %>% head
## # A tibble: 6 x 3
## # Groups: country, continent [6]
## country continent data
## <fct> <fct> <list>
## 1 Afghanistan Asia <tibble [12 x 4]>
## 2 Albania Europe <tibble [12 x 4]>
## 3 Algeria Africa <tibble [12 x 4]>
## 4 Angola Africa <tibble [12 x 4]>
## 5 Argentina Americas <tibble [12 x 4]>
## 6 Australia Oceania <tibble [12 x 4]>
-(여기서는 continent와 country를 그룹화는 약간의 편법을 사용한다. country에 대해 continent는 고정되므로 더 이상의 그붑은 추가하지 않으면거 추가 변수를 가져갈 수 있는 쉬운방법이다.)
by_country$data[[1]]
## # A tibble: 12 x 4
## year lifeExp pop gdpPercap
## <int> <dbl> <int> <dbl>
## 1 1952 28.8 8425333 779.
## 2 1957 30.3 9240934 821.
## 3 1962 32.0 10267083 853.
## 4 1967 34.0 11537966 836.
## 5 1972 36.1 13079460 740.
## 6 1977 38.4 14880372 786.
## 7 1982 39.9 12881816 978.
## 8 1987 40.8 13867957 852.
## 9 1992 41.7 16317921 649.
## 10 1997 41.8 22227415 635.
## 11 2002 42.1 25268405 727.
## 12 2007 43.8 31889923 975.
country_model <- function(df) {
lm(lifeExp ~ year, data = df)
}
-또한 함수를 모든 데이터프레임에 적용하려고 한다. - 데이터프레임이 리스트 안에 있으므로 Purr::map()을 사용하여 각 요소에 대해 country_model 함수를 적용할 수 있다.
models <- map(by_country$data, country_model)
by_country <- by_country %>%
mutate(model = map(data, country_model))
by_country
## # A tibble: 142 x 4
## # Groups: country, continent [142]
## country continent data model
## <fct> <fct> <list> <list>
## 1 Afghanistan Asia <tibble [12 x 4]> <lm>
## 2 Albania Europe <tibble [12 x 4]> <lm>
## 3 Algeria Africa <tibble [12 x 4]> <lm>
## 4 Angola Africa <tibble [12 x 4]> <lm>
## 5 Argentina Americas <tibble [12 x 4]> <lm>
## 6 Australia Oceania <tibble [12 x 4]> <lm>
## 7 Austria Europe <tibble [12 x 4]> <lm>
## 8 Bahrain Asia <tibble [12 x 4]> <lm>
## 9 Bangladesh Asia <tibble [12 x 4]> <lm>
## 10 Belgium Europe <tibble [12 x 4]> <lm>
## # ... with 132 more rows
by_country %>%
filter(continent == "Europe")
## # A tibble: 30 x 4
## # Groups: country, continent [30]
## country continent data model
## <fct> <fct> <list> <list>
## 1 Albania Europe <tibble [12 x 4]> <lm>
## 2 Austria Europe <tibble [12 x 4]> <lm>
## 3 Belgium Europe <tibble [12 x 4]> <lm>
## 4 Bosnia and Herzegovina Europe <tibble [12 x 4]> <lm>
## 5 Bulgaria Europe <tibble [12 x 4]> <lm>
## 6 Croatia Europe <tibble [12 x 4]> <lm>
## 7 Czech Republic Europe <tibble [12 x 4]> <lm>
## 8 Denmark Europe <tibble [12 x 4]> <lm>
## 9 Finland Europe <tibble [12 x 4]> <lm>
## 10 France Europe <tibble [12 x 4]> <lm>
## # ... with 20 more rows
by_country %>%
arrange(continent, country)
## # A tibble: 142 x 4
## # Groups: country, continent [142]
## country continent data model
## <fct> <fct> <list> <list>
## 1 Algeria Africa <tibble [12 x 4]> <lm>
## 2 Angola Africa <tibble [12 x 4]> <lm>
## 3 Benin Africa <tibble [12 x 4]> <lm>
## 4 Botswana Africa <tibble [12 x 4]> <lm>
## 5 Burkina Faso Africa <tibble [12 x 4]> <lm>
## 6 Burundi Africa <tibble [12 x 4]> <lm>
## 7 Cameroon Africa <tibble [12 x 4]> <lm>
## 8 Central African Republic Africa <tibble [12 x 4]> <lm>
## 9 Chad Africa <tibble [12 x 4]> <lm>
## 10 Comoros Africa <tibble [12 x 4]> <lm>
## # ... with 132 more rows
-데이터프레임의 리스트와 모델의 리스트가 분리된 객체인 경우, 하나의 백터를 재 정렬하거나 하위 집합으로 만들 때마다 동기화하기 위해 다른 모든것을 재정렬 하거나 하위 집합으로 만들어야 한다.
by_country <- by_country %>%
mutate(
resids = map2(data, model, add_residuals))
by_country %>% head()
## # A tibble: 6 x 5
## # Groups: country, continent [6]
## country continent data model resids
## <fct> <fct> <list> <list> <list>
## 1 Afghanistan Asia <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 2 Albania Europe <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 3 Algeria Africa <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 4 Angola Africa <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 5 Argentina Americas <tibble [12 x 4]> <lm> <tibble [12 x 5]>
## 6 Australia Oceania <tibble [12 x 4]> <lm> <tibble [12 x 5]>
resids <- unnest(by_country , resids)
resids
## # A tibble: 1,704 x 9
## # Groups: country, continent [142]
## country continent data model year lifeExp pop gdpPercap resid
## <fct> <fct> <list> <list> <int> <dbl> <int> <dbl> <dbl>
## 1 Afghanis~ Asia <tibble [1~ <lm> 1952 28.8 8.43e6 779. -1.11
## 2 Afghanis~ Asia <tibble [1~ <lm> 1957 30.3 9.24e6 821. -0.952
## 3 Afghanis~ Asia <tibble [1~ <lm> 1962 32.0 1.03e7 853. -0.664
## 4 Afghanis~ Asia <tibble [1~ <lm> 1967 34.0 1.15e7 836. -0.0172
## 5 Afghanis~ Asia <tibble [1~ <lm> 1972 36.1 1.31e7 740. 0.674
## 6 Afghanis~ Asia <tibble [1~ <lm> 1977 38.4 1.49e7 786. 1.65
## 7 Afghanis~ Asia <tibble [1~ <lm> 1982 39.9 1.29e7 978. 1.69
## 8 Afghanis~ Asia <tibble [1~ <lm> 1987 40.8 1.39e7 852. 1.28
## 9 Afghanis~ Asia <tibble [1~ <lm> 1992 41.7 1.63e7 649. 0.754
## 10 Afghanis~ Asia <tibble [1~ <lm> 1997 41.8 2.22e7 635. -0.534
## # ... with 1,694 more rows
resids %>%
ggplot(aes(year, resid)) +
geom_line(aes(group = country ), alpha = 1/3) +
geom_smooth(se = FALSE)
-플롯을 대륙으로 면분할하면 더 잘 나타난다.
resids %>%
ggplot(aes(year, resid, group = country )) +
geom_line(alpha = 1/3) +
facet_wrap(~ continent)
-플롯을 보면 가벼운 패턴은 포착하지 못한 것 처럼 보인다.
broom::glance(nz_mod)
## # A tibble: 1 x 12
## r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 0.954 0.949 0.804 205. 5.41e-8 1 -13.3 32.6 34.1
## # ... with 3 more variables: deviance <dbl>, df.residual <int>, nobs <int>
-mutate()와 unnest()를 사용하여 국가별로 하나의 행이 존재하는 데이터프레임을 만들수있다.
library(dplyr)
by_country %>%
mutate(glance = map(model, broom::glance)) %>%
unnest(glance)
## # A tibble: 142 x 17
## # Groups: country, continent [142]
## country continent data model resids r.squared adj.r.squared sigma statistic
## <fct> <fct> <lis> <lis> <list> <dbl> <dbl> <dbl> <dbl>
## 1 Afghan~ Asia <tib~ <lm> <tibb~ 0.948 0.942 1.22 181.
## 2 Albania Europe <tib~ <lm> <tibb~ 0.911 0.902 1.98 102.
## 3 Algeria Africa <tib~ <lm> <tibb~ 0.985 0.984 1.32 662.
## 4 Angola Africa <tib~ <lm> <tibb~ 0.888 0.877 1.41 79.1
## 5 Argent~ Americas <tib~ <lm> <tibb~ 0.996 0.995 0.292 2246.
## 6 Austra~ Oceania <tib~ <lm> <tibb~ 0.980 0.978 0.621 481.
## 7 Austria Europe <tib~ <lm> <tibb~ 0.992 0.991 0.407 1261.
## 8 Bahrain Asia <tib~ <lm> <tibb~ 0.967 0.963 1.64 291.
## 9 Bangla~ Asia <tib~ <lm> <tibb~ 0.989 0.988 0.977 930.
## 10 Belgium Europe <tib~ <lm> <tibb~ 0.995 0.994 0.293 1822.
## # ... with 132 more rows, and 8 more variables: p.value <dbl>, df <dbl>,
## # logLik <dbl>, AIC <dbl>, BIC <dbl>, deviance <dbl>, df.residual <int>,
## # nobs <int>
-그렇지만 여전히 모든 리스트-열을 포함하고 있으므로 이는 우리가 원하는 결과물이 아니다.
glance <- by_country %>%
mutate(glance = map(model, broom :: glance)) %>%
unnest(glance, drop = TRUE)
glance
## # A tibble: 142 x 18
## # Groups: country, continent [142]
## country continent data model resids r.squared adj.r.squared sigma statistic
## <fct> <fct> <lis> <lis> <list> <dbl> <dbl> <dbl> <dbl>
## 1 Afghan~ Asia <tib~ <lm> <tibb~ 0.948 0.942 1.22 181.
## 2 Albania Europe <tib~ <lm> <tibb~ 0.911 0.902 1.98 102.
## 3 Algeria Africa <tib~ <lm> <tibb~ 0.985 0.984 1.32 662.
## 4 Angola Africa <tib~ <lm> <tibb~ 0.888 0.877 1.41 79.1
## 5 Argent~ Americas <tib~ <lm> <tibb~ 0.996 0.995 0.292 2246.
## 6 Austra~ Oceania <tib~ <lm> <tibb~ 0.980 0.978 0.621 481.
## 7 Austria Europe <tib~ <lm> <tibb~ 0.992 0.991 0.407 1261.
## 8 Bahrain Asia <tib~ <lm> <tibb~ 0.967 0.963 1.64 291.
## 9 Bangla~ Asia <tib~ <lm> <tibb~ 0.989 0.988 0.977 930.
## 10 Belgium Europe <tib~ <lm> <tibb~ 0.995 0.994 0.293 1822.
## # ... with 132 more rows, and 9 more variables: p.value <dbl>, df <dbl>,
## # logLik <dbl>, AIC <dbl>, BIC <dbl>, deviance <dbl>, df.residual <int>,
## # nobs <int>, drop <lgl>
glance %>%
arrange(r.squared)
## # A tibble: 142 x 18
## # Groups: country, continent [142]
## country continent data model resids r.squared adj.r.squared sigma statistic
## <fct> <fct> <lis> <lis> <list> <dbl> <dbl> <dbl> <dbl>
## 1 Rwanda Africa <tib~ <lm> <tibb~ 0.0172 -0.0811 6.56 0.175
## 2 Botswa~ Africa <tib~ <lm> <tibb~ 0.0340 -0.0626 6.11 0.352
## 3 Zimbab~ Africa <tib~ <lm> <tibb~ 0.0562 -0.0381 7.21 0.596
## 4 Zambia Africa <tib~ <lm> <tibb~ 0.0598 -0.0342 4.53 0.636
## 5 Swazil~ Africa <tib~ <lm> <tibb~ 0.0682 -0.0250 6.64 0.732
## 6 Lesotho Africa <tib~ <lm> <tibb~ 0.0849 -0.00666 5.93 0.927
## 7 Cote d~ Africa <tib~ <lm> <tibb~ 0.283 0.212 3.93 3.95
## 8 South ~ Africa <tib~ <lm> <tibb~ 0.312 0.244 4.74 4.54
## 9 Uganda Africa <tib~ <lm> <tibb~ 0.342 0.276 3.19 5.20
## 10 Congo,~ Africa <tib~ <lm> <tibb~ 0.348 0.283 2.43 5.34
## # ... with 132 more rows, and 9 more variables: p.value <dbl>, df <dbl>,
## # logLik <dbl>, AIC <dbl>, BIC <dbl>, deviance <dbl>, df.residual <int>,
## # nobs <int>, drop <lgl>
glance %>%
ggplot(aes(continent, r.squared)) +
geom_jitter(width = 0.5)
bad_fit <- filter(glance, r.squared < 0.25)
gapminder %>%
semi_join(bad_fit, by = "country") %>%
ggplot(aes(year, lifeExp, color = country)) +
geom_line()
-여기서는 HIV/AIDS 전염병과 르완다 집단 학살의 비극이라는 두 가지 주요 효과를 확인할 수 있다.
선형 주세는 전체적인 추세에 비해 너무 단수해 보인다. 이를 2차 다향식으로 개선할 수 있는가? 2차 식의 계수는 어떻게 해석할 수 있는가? (힌트: year를 평균이 0이 되도록 변환할 수 있다.)
대륙별 R의 분포를 시각화하는 다른 방법을 탐색해보자. jitter와 같이 점들 이 겹처지는 것을 피하면서 결정론적 방법을 사용하는 ggbeeWarm 패키지를 사용해 볼 수 있다.
(가장 좋지 않는 모델이 생성된 국가의 데이터를 나타내는) 마지막 플롯을 생성하기 위해 두 가지 단계가 필요하다. 먼저 국가마다 한 행의 데이터프레임을 생성한 후, 원 데이터셋에 내부 조인하다. unnest(.drop = true) 대신에 unnest() 를 사용하면 이 조인을 피할수 있다. 이를 어떻게 할 수 있는가?
data.frame(x = list(1:3,3:5))
## x.1.3 x.3.5
## 1 1 3
## 2 2 4
## 3 3 5
data.frame (
x = I(list(1:3, 3:5)),
y = c("1, 2", "3, 4, 5")
)
## x y
## 1 1, 2, 3 1, 2
## 2 3, 4, 5 3, 4, 5
-tibble()은 입력값을 수정하지 않고도 더 나온 출력 방법을 제공하여 이 문제를 해결할 수 있다.
library(tibble)
tibble(
x = I(list(1:3, 3:5)),
y = c("1, 2", "3, 4, 5")
)
## # A tibble: 2 x 2
## x y
## <I<list>> <chr>
## 1 <int [3]> 1, 2
## 2 <int [3]> 3, 4, 5
-tibble()은 필요한 리스트를 자동으로 생성할 수 있는 더 간단한 방법이다.
tribble(
~x, ~y,
1:3, "1, 2", 3:5, "3, 4, 5"
)
## # A tibble: 2 x 2
## x y
## <list> <chr>
## 1 <int [3]> 1, 2
## 2 <int [3]> 3, 4, 5
-리스트-열은 중급 데이터 구조로 가장 유용하다. 대부분의 R 함수가 원자 백터 또는 데이터프레임에서 동작하기 때문에 리스트-열로 직접 작업하기는 어렵다.
기존의 리스트-열을 map(), map()2 또는 pmap()으로 변형하여 다른 중간 리스트 -열을 만든다. 예를 들어 이전 사례에서 데이터프레임의 리스트-열을 변형하여 모델의 리스트-열을 생성하였다.
399쪽의 ’리스트-열 단순화하기’의 내용과 같이 리스트-열을 데이터프레임 또는 원자 백터로 다시 단순화한다.
tidyr::nest()를 사용하여 그룹화된 데이터프레임을 데이터프레임의 리스트-열을 포함하는 중첩된 데이터로 변환한다.
리스트를 반환하는 mutate()와 백터화 함수를 사용한다.
여러 결과를 반환하는 summarize()와 요약 함수를 사용한다.
-또는 tibble::enframe()를 사용하여 명명된 리스트에서 생성할 수도 있다.
-nest()함수는 중첩된 데이터프레임(즉, 데이터프레임의 리스트-열로 이루어진 데이터프레임)을 생성한다.
gapminder %>%
group_by(country, continent) %>%
nest()
## # A tibble: 142 x 3
## # Groups: country, continent [142]
## country continent data
## <fct> <fct> <list>
## 1 Afghanistan Asia <tibble [12 x 4]>
## 2 Albania Europe <tibble [12 x 4]>
## 3 Algeria Africa <tibble [12 x 4]>
## 4 Angola Africa <tibble [12 x 4]>
## 5 Argentina Americas <tibble [12 x 4]>
## 6 Australia Oceania <tibble [12 x 4]>
## 7 Austria Europe <tibble [12 x 4]>
## 8 Bahrain Asia <tibble [12 x 4]>
## 9 Bangladesh Asia <tibble [12 x 4]>
## 10 Belgium Europe <tibble [12 x 4]>
## # ... with 132 more rows
gapminder %>%
nest(year: gdpPercap)
## # A tibble: 142 x 3
## country continent data
## <fct> <fct> <list>
## 1 Afghanistan Asia <tibble [12 x 4]>
## 2 Albania Europe <tibble [12 x 4]>
## 3 Algeria Africa <tibble [12 x 4]>
## 4 Angola Africa <tibble [12 x 4]>
## 5 Argentina Americas <tibble [12 x 4]>
## 6 Australia Oceania <tibble [12 x 4]>
## 7 Austria Europe <tibble [12 x 4]>
## 8 Bahrain Asia <tibble [12 x 4]>
## 9 Bangladesh Asia <tibble [12 x 4]>
## 10 Belgium Europe <tibble [12 x 4]>
## # ... with 132 more rows
몇 가지 유용한 함수는 원자 백터를 입력하여 리스트를 반환한다.
예를 들어 11 장에서는 문자형 백터를 사용하여 백터의 리스트를 반환하는 stringr:: str_split()에 대해 배웠다.
mutate 함수 안에서 이를 사용하여 리스트-열을 얻을 수 있다.
df <- tribble(
~x1, "a,b,c",
"d,e,f,g"
)
df %>%
mutate(x2 = stringr::str_split(x1, "."))
## # A tibble: 2 x 2
## x1 x2
## <chr> <list>
## 1 a,b,c <chr [6]>
## 2 d,e,f,g <chr [8]>
library(unnest)
df %>%
mutate(x2 = stringr::str_split(x1,".")) %>%
unnest()
## x1 x1.2 x2.1 x2.1.2 x2.1.3 x2.1.4 x2.1.5 x2.1.6 x2.2 x2.2.2 x2.2.3
## 1 a,b,c d,e,f,g
## x2.2.4 x2.2.5 x2.2.6 x2.2.7 x2.2.8
## 1
(이 패턴을 많이 사용하는 경우에 공통 패턴을 포함하는 tidyr:separate_rows() 를 반드시 확인한다.)
이 패턴의 또 다른 예제는 purr의 map(), map2(), pmap() 함수를 사용하는 것이다.
예를 들어 319쪽의 ’다른 함수 불러오기’의 마지막 예제를 활용하여 mutate() 함수를 사용하도록 다시 작성해 볼 수 있다.
sim <- tribble(
~f, ~params,
"runif", list(min = -1, max = -1),
"rnorm", list(sd = 5),
"rpois", list(lambda = 10)
)
sim %>%
mutate(sims = invoke_map(f, params, n = 10))
## # A tibble: 3 x 3
## f params sims
## <chr> <list> <list>
## 1 runif <named list [2]> <dbl [10]>
## 2 rnorm <named list [1]> <dbl [10]>
## 3 rpois <named list [1]> <int [10]>
mtcars %>%
group_by(cyl) %>%
summarize(q = quantile(mpg))
## # A tibble: 15 x 2
## # Groups: cyl [3]
## cyl q
## <dbl> <dbl>
## 1 4 21.4
## 2 4 22.8
## 3 4 26
## 4 4 30.4
## 5 4 33.9
## 6 6 17.8
## 7 6 18.6
## 8 6 19.7
## 9 6 21
## 10 6 21.4
## 11 8 10.4
## 12 8 14.4
## 13 8 15.2
## 14 8 16.2
## 15 8 19.2
mtcars %>%
group_by(cyl) %>%
summarize(q = list(quantile(mpg)))
## # A tibble: 3 x 2
## cyl q
## <dbl> <list>
## 1 4 <dbl [5]>
## 2 6 <dbl [5]>
## 3 8 <dbl [5]>
probs <- c(0.01, 0.25, 0.5, 0.75, 0.99)
mtcars %>%
group_by(cyl) %>%
summarize(p = list(probs), q = list(quantile(mpg, probs))) %>%
unnest()
## cyl cyl.2 cyl.3 p.1 p.1.2 p.1.3 p.1.4 p.1.5 p.2 p.2.2 p.2.3 p.2.4 p.2.5
## 1 4 6 8 0.01 0.25 0.5 0.75 0.99 0.01 0.25 0.5 0.75 0.99
## p.3 p.3.2 p.3.3 p.3.4 p.3.5 q.1 q.1.2 q.1.3 q.1.4 q.1.5 q.2 q.2.2 q.2.3
## 1 0.01 0.25 0.5 0.75 0.99 21.41 22.8 26 30.4 33.75 17.818 18.65 19.7
## q.2.4 q.2.5 q.3 q.3.2 q.3.3 q.3.4 q.3.5
## 1 21 21.376 10.4 14.4 15.2 16.25 19.135
x <- list(
a=1:5,
b=3:4,
c=5:6)
df <- enframe(x)
df
## # A tibble: 3 x 2
## name value
## <chr> <list>
## 1 a <int [5]>
## 2 b <int [2]>
## 3 c <int [2]>
이 구조의 장점은 간단한 방법으로 일반화한다는 것이다. 메타 데이터에 문자형 백터가 있는 경우 이름(name)에는 유용하지만 다른 유형의 데이터 또는 여러 백터가 있는 경우 유용하지 않는다.
이제 이름(name)과 값(value)을 동시에 반복하고자 한다면 map2()를 사용할 수 있다.
df %>%
mutate(
smry = map2_chr(
name,
value,
~ stringr::str_c(.x, ": ", .y[1])
)
)
## # A tibble: 3 x 3
## name value smry
## <chr> <list> <chr>
## 1 a <int [5]> a: 1
## 2 b <int [2]> b: 3
## 3 c <int [2]> c: 5
원자 백터를 입력하여 리스트르 반환하는 모든 함수를 나열해보자.
quantitle()처럼 여러 개의 값을 반환하는 유용한 요약 함수를 생각해보자.
다음의 데이터프레임에는 무엇이 누락되었는가? quantitle()은 누락된 부분을 어떻게 반환하는가? 왜 그것은 도움이 되지 않는가?
mtcars %>%
group_by(cyl) %>%
summarize(q = list(quantile(mpg))) %>%
unnest()
## cyl cyl.2 cyl.3 q.1 q.1.2 q.1.3 q.1.4 q.1.5 q.2 q.2.2 q.2.3 q.2.4 q.2.5
## 1 4 6 8 21.4 22.8 26 30.4 33.9 17.8 18.65 19.7 21 21.4
## q.3 q.3.2 q.3.3 q.3.4 q.3.5
## 1 10.4 14.4 15.2 16.25 19.2
mtcars %>%
group_by(cyl) %>%
summarize_each(funs(list))
## # A tibble: 3 x 11
## cyl mpg disp hp drat wt qsec vs am gear carb
## <dbl> <list> <list> <list> <list> <list> <list> <list> <list> <list> <list>
## 1 4 <dbl [~ <dbl [~ <dbl [~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~
## 2 6 <dbl [~ <dbl [~ <dbl [~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~
## 3 8 <dbl [~ <dbl [~ <dbl [~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~ <dbl ~
이 책에서 배운 데이터 처리 및 시각화 기술을 적용하기 위해서는 리스트-열을 일반 열(원자 백터) 또는 열의 집합으로 다시 단순화해야 한다.
단일 값을 원하는 경우 map_lgl(), map_int(), map_dbl(), map_chr()에 mutate() 를 사용하여 원자 백터를 생성한다.
많은 값을 원하는 경우 unnest()를 사용하여 리스트-열을 일반 열로 다시 변환 하고 필요한 만큼 행을 반복한다. 자세한 내용은 다음 절에서 설명할 것이다.
-리스트 열을 원자 벡터로 줄일 수 있다면 리스트 열은 일반 열이 될 것이다. 예를 들어 타입과 길이를 가진 객체는 항상 요약할 수 있으므로 다음 코드는 리스트 열의 종류에 관계없이 작동할 것이다.
df <- tribble(
~x,
letters[1:5],
1:3,
runif(5)
)
df %>% mutate(
type = map_chr(x, typeof),
length = map_int(x, length)
)
## # A tibble: 3 x 3
## x type length
## <list> <chr> <int>
## 1 <chr [5]> character 5
## 2 <int [3]> integer 3
## 3 <dbl [5]> double 5
이는 기본 tbl print 방법에서 얻은 것과 같은 기본 정보지만, 여기에서는 필터링 용도로 사용할 수 있다. 다차원적인 리스트에 대해서 작동하지 않은 부분을 필터링 하고자 할 때 유용한 기법이다.
map_*() 단축어를 기억하자. 예를 들어 map_chr(x, “apple”)를 사용하여 x의 각 요소에 대해 apple 저장된 문자열을 추출할 수 있다.
df <- tribble(
~x,
list(a=1,b=2),
list(a=2,c=4)
)
df %>% mutate(
a = map_dbl(x,"a"),
b = map_dbl(x, "b", .null = NA_real_)
)
## # A tibble: 2 x 3
## x a b
## <list> <dbl> <dbl>
## 1 <named list [2]> 1 2
## 2 <named list [2]> 2 NA
library(tibble)
library(dplyr)
library(unnest)
tibble(x = 1:2, y = list(1:4, 1)) %>% unnest(y)
## Error in unnest(., y): 객체 'y'를 찾을 수 없습니다
모든 행에 대해서 y와 z는 같은 수의 요소를 포함하므로 동작한다.
df1 <- tribble(
~x, ~y, ~z,
1, c("a","b"), 1:2,
2, "c", 3
)
df1
## # A tibble: 2 x 3
## x y z
## <dbl> <list> <list>
## 1 1 <chr [2]> <int [2]>
## 2 2 <chr [1]> <dbl [1]>
df1 %>% unnest(y, z)
## Error in unnest(., y, z): 객체 'y'를 찾을 수 없습니다
y와 Z가 가진 요소의 개수가 다르므로 동작하지 않는다.
df2 <- tribble(
~x, ~y, ~z,
1, "a", 1:2,
2, c("a","b","c"), 3
)
df2
## # A tibble: 2 x 3
## x y z
## <dbl> <list> <list>
## 1 1 <chr [1]> <int [2]>
## 2 2 <chr [3]> <dbl [1]>
df2 %>% unnest(y,z)
## Error in unnest(., y, z): 객체 'y'를 찾을 수 없습니다
리스트-열에서 원자 벡터 열을 만들때 lengths() 함수가 유용한 이유는 무엇인가?
데이터프레임에서 발견되는 가장 일반적인 유형의 벡터를 나열해보자. 어떤 점이 이 리스트를 다르게 만드는가?
broom 패키지는 모텔을 타이디 데이터프레임으로 변환할 수 있는 세 가지의 일 반적인 도구를 제공한다.
broom::glance(model)은 각 모델에 대한 행을 반환한다. 각 열에는 모델 요약 (모델 성능 척도 또는 복잡성 또는 둘의 조합)이 표시된다.
broom::glance(model)은 모델의 각 계수에 대한 행을 반환한다. 각 열은 추청값 또는 변동성에 대한 정보를 제공한다.
broom:augment(model,data)는 data의 각 행에 잔차와 같은 영향 통계량을 추가 하여 반환한다.
-Broom은 가장 인기 있는 모델링 패키지로 생성한 다양한 종류의 모델을 다룬다.