return a data.frame 函数的分组应用(没有for循环)
Grouped application of function that return a data.frame (without a for loop)
我需要应用一个 return 一个 data.frame 跨(分组)tibble
的函数
部分数据:
df <- data.frame(start=1:10,end=21:30,g=sample(LETTERS[1:2],10,replace=TRUE))
ff <- function(start,end,... ) {
out <- data.frame(T1=c(start,rev(start)),T2=c(end,rev(end)))
return(out)
}
然后我想做这样的事情
library(dplyr)
library(purrr)
df %>%
group_by(g) %>%
pmap_dfr( ff,.keep=TRUE)
产生小标题/data.frame像这样:
g start end
1 A 1 21
2 A 3 23
3 A 4 24
4 A 5 25
5 A 6 26
6 A 7 27
7 A 8 28
8 A 8 28
9 A 7 27
10 A 6 26
11 A 5 25
12 A 4 24
13 A 3 23
14 A 1 21
15 B 2 22
16 B 9 29
17 B 10 30
18 B 10 30
19 B 9 29
20 B 2 22
以便将输出连接在一起row-wise,并以某种方式标记它所属的组。
我想应用的函数需要从原始 data.frame 中的其他列获取参数(示例代码中的 df)所以我认为 pmap_dfr 是正确的函数.但我只是对输出感到困惑,所以我一定是用错了那个函数。
我将不胜感激能获得的所有帮助。
使用data.table和lapply可以达到预期的效果。
df <- data.frame(start=1:10,end=21:30,g=sample(LETTERS[1:2],10,replace=TRUE))
start end g
1: 1 21 B
2: 2 22 A
3: 3 23 A
4: 4 24 A
5: 5 25 A
6: 6 26 B
7: 7 27 A
8: 8 28 B
9: 9 29 B
10: 10 30 B
library(data.table)
setDT(df)
ff <- function(x) {
x <- c(x, rev(x))
return(x)
}
df[,lapply(.SD, ff), .SDcols = c('start', 'end'), by = .(g)]
g start end
1: B 1 21
2: B 6 26
3: B 8 28
4: B 9 29
5: B 10 30
6: B 10 30
7: B 9 29
8: B 8 28
9: B 6 26
10: B 1 21
11: A 2 22
12: A 3 23
13: A 4 24
14: A 5 25
15: A 7 27
16: A 7 27
17: A 5 25
18: A 4 24
19: A 3 23
20: A 2 22
一种选择是使用 dplyr::group_split()
和 purrr::map_dfr()
。
工作原理:group_split()
会根据您提供的分组变量(例如,g
).接下来,map_dfr()
可用于将函数应用于该列表的每个元素。因为您的自定义函数 ff()
returns a data.frame 没有您的分组变量 g
,您需要将该信息添加回 ff()
输出 - 这可以是使用 mutate()
完成,如下例所示:
library(dplyr)
library(purrr)
# set seed so that example is reproducible
set.seed(1)
# your example data and function
df <- data.frame(start=1:10,end=21:30,g=sample(LETTERS[1:2],10,replace=TRUE))
ff <- function(start,end,... ) {
out <- data.frame(T1=c(start,rev(start)),T2=c(end,rev(end)))
return(out)
}
# use group_split & map_dfr
df %>%
# divide df into a list of data.frames based on supplied grouping variables
group_split(g) %>%
# for each element in the list, apply this function
map_dfr(function(df.x) {
with(df.x,
# get the data.frame your function returns
ff(start, end) %>%
# add your grouping variables back-in (stripped by ff)
mutate(g = g[1]))
})
# a short-hand version of the above can be written as:
df %>%
group_split(g) %>%
map_dfr(~ff(.x$start, .x$end) %>% mutate(g = .x$g[1]))
可以这样使用dplyr::across()
:
library(tidyverse)
group_by(df, g) %>%
summarise(across(all_of(c("start", "end"))) %>%
{
ff(.[[1]], .[[2]])
})
#> `summarise()` has grouped output by 'g'. You can override using the `.groups` argument.
#> # A tibble: 20 × 3
#> # Groups: g [2]
#> g T1 T2
#> <chr> <int> <int>
#> 1 A 1 21
#> 2 A 3 23
#> 3 A 4 24
#> 4 A 9 29
#> 5 A 10 30
#> 6 A 10 30
#> 7 A 9 29
#> 8 A 4 24
#> 9 A 3 23
#> 10 A 1 21
#> 11 B 2 22
#> 12 B 5 25
#> 13 B 6 26
#> 14 B 7 27
#> 15 B 8 28
#> 16 B 8 28
#> 17 B 7 27
#> 18 B 6 26
#> 19 B 5 25
#> 20 B 2 22
由 reprex package (v2.0.1)
于 2021-12-21 创建
我需要应用一个 return 一个 data.frame 跨(分组)tibble
的函数部分数据:
df <- data.frame(start=1:10,end=21:30,g=sample(LETTERS[1:2],10,replace=TRUE))
ff <- function(start,end,... ) {
out <- data.frame(T1=c(start,rev(start)),T2=c(end,rev(end)))
return(out)
}
然后我想做这样的事情
library(dplyr)
library(purrr)
df %>%
group_by(g) %>%
pmap_dfr( ff,.keep=TRUE)
产生小标题/data.frame像这样:
g start end
1 A 1 21
2 A 3 23
3 A 4 24
4 A 5 25
5 A 6 26
6 A 7 27
7 A 8 28
8 A 8 28
9 A 7 27
10 A 6 26
11 A 5 25
12 A 4 24
13 A 3 23
14 A 1 21
15 B 2 22
16 B 9 29
17 B 10 30
18 B 10 30
19 B 9 29
20 B 2 22
以便将输出连接在一起row-wise,并以某种方式标记它所属的组。
我想应用的函数需要从原始 data.frame 中的其他列获取参数(示例代码中的 df)所以我认为 pmap_dfr 是正确的函数.但我只是对输出感到困惑,所以我一定是用错了那个函数。
我将不胜感激能获得的所有帮助。
使用data.table和lapply可以达到预期的效果。
df <- data.frame(start=1:10,end=21:30,g=sample(LETTERS[1:2],10,replace=TRUE))
start end g
1: 1 21 B
2: 2 22 A
3: 3 23 A
4: 4 24 A
5: 5 25 A
6: 6 26 B
7: 7 27 A
8: 8 28 B
9: 9 29 B
10: 10 30 B
library(data.table)
setDT(df)
ff <- function(x) {
x <- c(x, rev(x))
return(x)
}
df[,lapply(.SD, ff), .SDcols = c('start', 'end'), by = .(g)]
g start end
1: B 1 21
2: B 6 26
3: B 8 28
4: B 9 29
5: B 10 30
6: B 10 30
7: B 9 29
8: B 8 28
9: B 6 26
10: B 1 21
11: A 2 22
12: A 3 23
13: A 4 24
14: A 5 25
15: A 7 27
16: A 7 27
17: A 5 25
18: A 4 24
19: A 3 23
20: A 2 22
一种选择是使用 dplyr::group_split()
和 purrr::map_dfr()
。
工作原理:group_split()
会根据您提供的分组变量(例如,g
).接下来,map_dfr()
可用于将函数应用于该列表的每个元素。因为您的自定义函数 ff()
returns a data.frame 没有您的分组变量 g
,您需要将该信息添加回 ff()
输出 - 这可以是使用 mutate()
完成,如下例所示:
library(dplyr)
library(purrr)
# set seed so that example is reproducible
set.seed(1)
# your example data and function
df <- data.frame(start=1:10,end=21:30,g=sample(LETTERS[1:2],10,replace=TRUE))
ff <- function(start,end,... ) {
out <- data.frame(T1=c(start,rev(start)),T2=c(end,rev(end)))
return(out)
}
# use group_split & map_dfr
df %>%
# divide df into a list of data.frames based on supplied grouping variables
group_split(g) %>%
# for each element in the list, apply this function
map_dfr(function(df.x) {
with(df.x,
# get the data.frame your function returns
ff(start, end) %>%
# add your grouping variables back-in (stripped by ff)
mutate(g = g[1]))
})
# a short-hand version of the above can be written as:
df %>%
group_split(g) %>%
map_dfr(~ff(.x$start, .x$end) %>% mutate(g = .x$g[1]))
可以这样使用dplyr::across()
:
library(tidyverse)
group_by(df, g) %>%
summarise(across(all_of(c("start", "end"))) %>%
{
ff(.[[1]], .[[2]])
})
#> `summarise()` has grouped output by 'g'. You can override using the `.groups` argument.
#> # A tibble: 20 × 3
#> # Groups: g [2]
#> g T1 T2
#> <chr> <int> <int>
#> 1 A 1 21
#> 2 A 3 23
#> 3 A 4 24
#> 4 A 9 29
#> 5 A 10 30
#> 6 A 10 30
#> 7 A 9 29
#> 8 A 4 24
#> 9 A 3 23
#> 10 A 1 21
#> 11 B 2 22
#> 12 B 5 25
#> 13 B 6 26
#> 14 B 7 27
#> 15 B 8 28
#> 16 B 8 28
#> 17 B 7 27
#> 18 B 6 26
#> 19 B 5 25
#> 20 B 2 22
由 reprex package (v2.0.1)
于 2021-12-21 创建