在 tibble 中的嵌套级别之间移动:如何引用存储在嵌套层次结构上层的数据
Traveling between nesting levels in a tibble: how to refer to data stored in upper levels of nesting hierarchy
我有一个包含 list-column 数据帧的 tibble。在这个最小的例子中,这样的小标题只有 1 行:
library(tibble)
df_meta <-
tibble(my_base_number = 5,
my_data = list(mtcars))
df_meta
#> # A tibble: 1 x 2
#> my_base_number my_data
#> <dbl> <list>
#> 1 5 <df [32 x 11]>
我想修改 table 里面的 my_data
并在其中改变一个新列。这是 mtcars 数据,我想改变一个新列,该列记录了 mpg
列。
虽然我可以做到:
library(dplyr)
library(purrr)
df_meta %>%
mutate(my_data_with_log_col = map(.x = my_data, .f = ~ .x %>%
mutate(log_mpg = map(.x = mpg, .f = ~log(.x, base = 5)))
)
)
#> # A tibble: 1 x 3
#> my_base_number my_data my_data_with_log_col
#> <dbl> <list> <list>
#> 1 5 <df [32 x 11]> <df [32 x 12]>
我真正想要的是在内部 map()
中调用 log()
会将值传递给 df_meta$my_base_number
的 base
参数,而不是 hard-coded 5
在我的例子中。
虽然在这个 1 行示例中这很简单:
df_meta %>%
mutate(my_data_with_log_col = map(.x = my_data, .f = ~ .x %>%
mutate(log_mpg = map(.x = mpg, .f = ~log(.x, base = df_meta$my_base_number)))
)
)
考虑一个更复杂的管道过程,它不再起作用:
tibble(my_data = rep(list(mtcars), 3)) %>%
add_column(base_number = 1:3) %>%
mutate(my_data_with_log_col = map(.x = my_data, .f = ~ .x %>%
mutate(log_mpg = map(.x = mpg, .f = ~log(.x, base = # <- ???
)))
)
)
所以我正在寻找的是一个程序,当我引用存储在“meta-table".
现在,随着我对 map()
的深入研究,为了处理嵌套 table,我无法引用存储在 upper 上的数据。如果您愿意,我正在寻找类似于 cd ../../..
使用终端导航时的内容。
这不是您要的答案。
我想分享它作为一个选项!
您可以使用 unnest
和 nest
的组合四处旅行:
library(dplyr)
library(tidyr)
df_meta %>%
unnest(cols = c(my_data)) %>%
mutate(log_mpg = log(mpg, my_base_number)) %>%
nest(my_data=mpg:log_mpg)
变异后的输出:
my_base_number mpg cyl disp hp drat wt qsec vs am gear carb log_mpg
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 5 21 6 160 110 3.9 2.62 16.5 0 1 4 4 1.89
2 5 21 6 160 110 3.9 2.88 17.0 0 1 4 4 1.89
3 5 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1 1.94
4 5 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1 1.90
5 5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2 1.82
6 5 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1 1.80
7 5 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4 1.65
8 5 24.4 4 147. 62 3.69 3.19 20 1 0 4 2 1.98
9 5 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2 1.94
10 5 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4 1.84
nest
后的最终输出:
my_base_number my_data
<dbl> <list>
1 5 <tibble [32 × 12]>
这是您要求的方法。但我实际上建议寻找不那么嵌套的方法,例如@TarJae 的回答。
library(tidyverse)
df_meta <-
tibble(my_data = rep(list(mtcars), 3),
my_base_number = 3:5)
add_log <- function(this_data, this_base){
this_data %>% mutate(log_mpg = log(mpg, this_base))
}
# check that it works properly:
mtcars %>% add_log(5)
# now apply to each row in df_meta
df_meta %>%
mutate(my_data_with_log_col = map2(my_data, my_base_number, add_log))
您会注意到我不需要在内部函数中使用 map
。但如果我这样做了,我会使用 map_dbl
而不是你使用的 map
,因为你实际上想要一个数字,而不是长度为 1 的向量列表。这也表明,也许您一开始就不需要双层地图。
此外,虽然匿名函数是可能的,但我认为对于像这样复杂的东西来说它是非常不可读的。这就是为什么我在 map2
.
之外定义函数的原因
purrr 中有一个函数叫做as_mapper
,您可以在其中使用公式语法来指定lambda 函数。您可以为 map
、..1
和 ..2
指定 n 个以 ..1
开头的参数,为 map2
和 ..1
..... ..3
.... ..n
对于 pmap
。这是一个例子:
library(tidyverse)
set.seed(111)
# create some data
df_meta <- tibble(my_base_number = sample(1:5, 5, replace = TRUE), my_data = rerun(5, mtcars))
mutate_log <- as_mapper(~ mutate(..1, log_mpg = log(mpg, ..2)))
df_meta %>%
mutate(my_data_with_log_col = map2(my_data, my_base_number, mutate_log))
#> # A tibble: 5 × 3
#> my_base_number my_data my_data_with_log_col
#> <int> <list> <list>
#> 1 3 <df [32 × 11]> <df [32 × 12]>
#> 2 4 <df [32 × 11]> <df [32 × 12]>
#> 3 3 <df [32 × 11]> <df [32 × 12]>
#> 4 1 <df [32 × 11]> <df [32 × 12]>
#> 5 3 <df [32 × 11]> <df [32 × 12]>
由 reprex package (v2.0.1)
于 2021-12-20 创建
编辑:将 pmap
与 as_mapper
结合使用:
library(tidyverse)
set.seed(111)
# create some data
df_meta <- tibble(
my_base_number = sample(1:5, 5, replace = TRUE),
my_col = sample(names(mtcars), 5, replace = TRUE),
my_data = rerun(5, mtcars)
)
mutate_log <- as_mapper(~ mutate(..1, "log_{..2}" := log(get(..2), ..3)))
#pmap takes two arguments, a list and a function.
data <- df_meta %>%
mutate(my_data_with_log_col = pmap(list(my_data, my_col, my_base_number), mutate_log))
#check the results
map(data[[4]], head)
#> [[1]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_drat
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 1.2388142
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 1.2388142
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 1.2270691
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 1.0239550
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 1.0444107
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 0.9241028
#>
#> [[2]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_disp
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 3.660964
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 3.660964
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 3.377444
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 4.005614
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 4.245927
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 3.906891
#>
#> [[3]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_vs
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 -Inf
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 -Inf
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 0
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 0
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 -Inf
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 0
#>
#> [[4]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_gear
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Inf
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Inf
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Inf
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Inf
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Inf
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 Inf
#>
#> [[5]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_mpg
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 2.771244
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 2.771244
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 2.846100
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 2.788419
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 2.665657
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 2.635973
由 reprex package (v2.0.1)
于 2021-12-20 创建
我有一个包含 list-column 数据帧的 tibble。在这个最小的例子中,这样的小标题只有 1 行:
library(tibble)
df_meta <-
tibble(my_base_number = 5,
my_data = list(mtcars))
df_meta
#> # A tibble: 1 x 2
#> my_base_number my_data
#> <dbl> <list>
#> 1 5 <df [32 x 11]>
我想修改 table 里面的 my_data
并在其中改变一个新列。这是 mtcars 数据,我想改变一个新列,该列记录了 mpg
列。
虽然我可以做到:
library(dplyr)
library(purrr)
df_meta %>%
mutate(my_data_with_log_col = map(.x = my_data, .f = ~ .x %>%
mutate(log_mpg = map(.x = mpg, .f = ~log(.x, base = 5)))
)
)
#> # A tibble: 1 x 3
#> my_base_number my_data my_data_with_log_col
#> <dbl> <list> <list>
#> 1 5 <df [32 x 11]> <df [32 x 12]>
我真正想要的是在内部 map()
中调用 log()
会将值传递给 df_meta$my_base_number
的 base
参数,而不是 hard-coded 5
在我的例子中。
虽然在这个 1 行示例中这很简单:
df_meta %>%
mutate(my_data_with_log_col = map(.x = my_data, .f = ~ .x %>%
mutate(log_mpg = map(.x = mpg, .f = ~log(.x, base = df_meta$my_base_number)))
)
)
考虑一个更复杂的管道过程,它不再起作用:
tibble(my_data = rep(list(mtcars), 3)) %>%
add_column(base_number = 1:3) %>%
mutate(my_data_with_log_col = map(.x = my_data, .f = ~ .x %>%
mutate(log_mpg = map(.x = mpg, .f = ~log(.x, base = # <- ???
)))
)
)
所以我正在寻找的是一个程序,当我引用存储在“meta-table".
现在,随着我对 map()
的深入研究,为了处理嵌套 table,我无法引用存储在 upper 上的数据。如果您愿意,我正在寻找类似于 cd ../../..
使用终端导航时的内容。
这不是您要的答案。 我想分享它作为一个选项!
您可以使用 unnest
和 nest
的组合四处旅行:
library(dplyr)
library(tidyr)
df_meta %>%
unnest(cols = c(my_data)) %>%
mutate(log_mpg = log(mpg, my_base_number)) %>%
nest(my_data=mpg:log_mpg)
变异后的输出:
my_base_number mpg cyl disp hp drat wt qsec vs am gear carb log_mpg
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 5 21 6 160 110 3.9 2.62 16.5 0 1 4 4 1.89
2 5 21 6 160 110 3.9 2.88 17.0 0 1 4 4 1.89
3 5 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1 1.94
4 5 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1 1.90
5 5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2 1.82
6 5 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1 1.80
7 5 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4 1.65
8 5 24.4 4 147. 62 3.69 3.19 20 1 0 4 2 1.98
9 5 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2 1.94
10 5 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4 1.84
nest
后的最终输出:
my_base_number my_data
<dbl> <list>
1 5 <tibble [32 × 12]>
这是您要求的方法。但我实际上建议寻找不那么嵌套的方法,例如@TarJae 的回答。
library(tidyverse)
df_meta <-
tibble(my_data = rep(list(mtcars), 3),
my_base_number = 3:5)
add_log <- function(this_data, this_base){
this_data %>% mutate(log_mpg = log(mpg, this_base))
}
# check that it works properly:
mtcars %>% add_log(5)
# now apply to each row in df_meta
df_meta %>%
mutate(my_data_with_log_col = map2(my_data, my_base_number, add_log))
您会注意到我不需要在内部函数中使用 map
。但如果我这样做了,我会使用 map_dbl
而不是你使用的 map
,因为你实际上想要一个数字,而不是长度为 1 的向量列表。这也表明,也许您一开始就不需要双层地图。
此外,虽然匿名函数是可能的,但我认为对于像这样复杂的东西来说它是非常不可读的。这就是为什么我在 map2
.
purrr 中有一个函数叫做as_mapper
,您可以在其中使用公式语法来指定lambda 函数。您可以为 map
、..1
和 ..2
指定 n 个以 ..1
开头的参数,为 map2
和 ..1
..... ..3
.... ..n
对于 pmap
。这是一个例子:
library(tidyverse)
set.seed(111)
# create some data
df_meta <- tibble(my_base_number = sample(1:5, 5, replace = TRUE), my_data = rerun(5, mtcars))
mutate_log <- as_mapper(~ mutate(..1, log_mpg = log(mpg, ..2)))
df_meta %>%
mutate(my_data_with_log_col = map2(my_data, my_base_number, mutate_log))
#> # A tibble: 5 × 3
#> my_base_number my_data my_data_with_log_col
#> <int> <list> <list>
#> 1 3 <df [32 × 11]> <df [32 × 12]>
#> 2 4 <df [32 × 11]> <df [32 × 12]>
#> 3 3 <df [32 × 11]> <df [32 × 12]>
#> 4 1 <df [32 × 11]> <df [32 × 12]>
#> 5 3 <df [32 × 11]> <df [32 × 12]>
由 reprex package (v2.0.1)
于 2021-12-20 创建编辑:将 pmap
与 as_mapper
结合使用:
library(tidyverse)
set.seed(111)
# create some data
df_meta <- tibble(
my_base_number = sample(1:5, 5, replace = TRUE),
my_col = sample(names(mtcars), 5, replace = TRUE),
my_data = rerun(5, mtcars)
)
mutate_log <- as_mapper(~ mutate(..1, "log_{..2}" := log(get(..2), ..3)))
#pmap takes two arguments, a list and a function.
data <- df_meta %>%
mutate(my_data_with_log_col = pmap(list(my_data, my_col, my_base_number), mutate_log))
#check the results
map(data[[4]], head)
#> [[1]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_drat
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 1.2388142
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 1.2388142
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 1.2270691
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 1.0239550
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 1.0444107
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 0.9241028
#>
#> [[2]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_disp
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 3.660964
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 3.660964
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 3.377444
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 4.005614
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 4.245927
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 3.906891
#>
#> [[3]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_vs
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 -Inf
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 -Inf
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 0
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 0
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 -Inf
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 0
#>
#> [[4]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_gear
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 Inf
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 Inf
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 Inf
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 Inf
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 Inf
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 Inf
#>
#> [[5]]
#> mpg cyl disp hp drat wt qsec vs am gear carb log_mpg
#> Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 2.771244
#> Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 2.771244
#> Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 2.846100
#> Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 2.788419
#> Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 2.665657
#> Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 2.635973
由 reprex package (v2.0.1)
于 2021-12-20 创建