purrr 将 t.test 映射到拆分 df
purrr map a t.test onto a split df
我是 purrr 的新手,Hadley's promising functional programming R library。我正在尝试对一个变量进行分组和拆分数据框和 运行 的 t 检验。使用示例数据集的示例可能如下所示。
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
split(.$cyl) %>%
map(~ t.test(.$`4`$mpg, .$`6`$mpg))
这会导致以下错误:
Error in var(x) : 'x' is NULL
In addition: Warning messages:
1: In is.na(x) : is.na() applied to non-(list or vector) of type 'NULL'
2: In mean.default(x) : argument is not numeric or logical: returning NA
我是不是误解了 map
的工作原理?或者有更好的方法来考虑这个问题吗?
我不完全理解预期的结果,但这可能是一个答案的起点。 purrr
中的 map()
在公式参数中使用 .x
。
这里有一种方法可以完成我认为你正在尝试做的事情 purrr
。
mtcars %>%
split(as.character(.$cyl)) %>%
map(~t.test(.x$mpg))
但是,purrr::by_slice()
与 dplyr::group_by()
搭配得很好。
library(purrr)
library(dplyr)
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
by_slice(~ t.test(.x$mpg))
或者,您可以使用 dplyr:::summarise()
.
完全跳过 purrr
library(purrr)
library(dplyr)
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
summarise(t_test = data_frame(t.test(.$mpg)))
如果嵌套的 data.frame
令人困惑,broom
可以帮助我们得到一个简单的 data.frame
结果摘要。
purrr
+ broom
+ tidyr
library(broom)
library(tidyr)
mtcars %>%
group_by(as.character(cyl)) %>%
by_slice(~tidy(t.test(.x$mpg))) %>%
unnest()
dplyr
+ broom
library(broom)
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
do(tidy(t.test(.$mpg)))
已编辑以包括对评论的回复
有了管道,我们很快就会忘乎所以。我认为 Walt 的回答做得很好,但我想确保我提供了 purrr
-ty 答案。我希望 pipeR
的使用不会过于混乱。
library(purrr)
library(dplyr)
library(broom)
library(tidyr)
library(pipeR)
mtcars %>>%
(split(.,.$cyl)) %>>%
(split_cyl~
names(split_cyl) %>>%
(
cross_d(
list(against=.,tested=.),
.filter = `==`
)
) %>>%
by_row(
~tidy(t.test(split_cyl[[.x$tested]]$mpg,split_cyl[[.x$against]]$mpg))
)
) %>>%
unnest()
要执行两个样本 t 检验,您必须创建气缸数的组合。我看不到您可以使用 purrr
函数创建组合。然而,仅使用 purrr
和基本 R 函数的方法是
library(purrr)
t_test2 <- mtcars %>% split(.$cyl) %>%
transpose() %>%
.[["mpg"]] %>%
(function(x) combn(names(x), m=2, function(y) t.test(flatten_dbl(x[y[1]]), flatten_dbl(x[y[2]])) , simplify=FALSE))
虽然这看起来有点做作。
仅使用具有链接的基本 R 函数的类似方法是
t_test <- mtcars %>% split(.$cyl) %>%
(function(x) combn(names(x), m=2, function(y) x[y], simplify=FALSE)) %>%
lapply( function(x) t.test(x[[1]]$mpg, x[[2]]$mpg))
尤其是处理需要多路输入的管道时(我们这里没有Haskell的Arrows),我觉得先用types/signatures推理比较容易,再把逻辑封装在函数中(你可以单元测试),然后写一个简洁的链。
在这种情况下,您想比较所有可能的向量对,因此我将设定一个目标,即编写一个函数,该函数接受一对(即 2 个向量的列表)和 returns 2-其中 t.test 个。
完成此操作后,您只需要一些胶水。所以计划是:
- 编写接受向量列表并执行 2 路 t 检验的函数。
- 写一个 function/pipe 从 mtcars 获取向量(简单)。
- 将上面的内容映射到对列表上。
在编写任何代码之前制定此计划很重要。由于 R 不是强类型的,所以事情在某种程度上被混淆了,但这样你就可以首先推理 "types",其次实现。
第 1 步
t.test 取点,所以我们使用 purrr:lift
让它取一个列表。因为我们不想匹配列表元素的名称,所以我们使用 .unnamed = TRUE
。此外,我们还明确表示我们正在使用元数为 2 的 t.test
函数(尽管代码运行不需要这个额外的步骤)。
t.test2 <- function(x, y) t.test(x, y)
liftedTT <- lift(t.test2, .unnamed = TRUE)
第 2 步
将我们在步骤1中得到的函数包装成一个函数链,它采用一个简单的对(这里我使用索引,使用cyl factor levels应该很容易,但我没有时间去弄清楚) .
doTT <- function(pair) {
mtcars %>%
split(as.character(.$cyl)) %>%
map(~ select(., mpg)) %>%
extract(pair) %>%
liftedTT %>%
broom::tidy
}
步骤 3
既然我们已经准备好了所有的乐高积木,构图就很简单了。
1:length(unique(mtcars$cyl)) %>%
combn(2) %>%
as.data.frame %>%
as.list %>%
map(~ doTT(.))
$V1
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
1 6.920779 26.66364 19.74286 4.719059 0.0004048495 12.95598 3.751376 10.09018
$V2
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
1 11.56364 26.66364 15.1 7.596664 1.641348e-06 14.96675 8.318518 14.80876
$V3
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
1 4.642857 19.74286 15.1 5.291135 4.540355e-05 18.50248 2.802925 6.482789
这里有很多东西需要清理,主要是使用因子级别并将它们保留在输出中(而不是在第二个函数中使用全局变量),但我认为你想要的核心就在这里。根据我的经验,不迷路的诀窍是从内到外工作。
我是 purrr 的新手,Hadley's promising functional programming R library。我正在尝试对一个变量进行分组和拆分数据框和 运行 的 t 检验。使用示例数据集的示例可能如下所示。
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
split(.$cyl) %>%
map(~ t.test(.$`4`$mpg, .$`6`$mpg))
这会导致以下错误:
Error in var(x) : 'x' is NULL
In addition: Warning messages:
1: In is.na(x) : is.na() applied to non-(list or vector) of type 'NULL'
2: In mean.default(x) : argument is not numeric or logical: returning NA
我是不是误解了 map
的工作原理?或者有更好的方法来考虑这个问题吗?
我不完全理解预期的结果,但这可能是一个答案的起点。 purrr
中的 map()
在公式参数中使用 .x
。
这里有一种方法可以完成我认为你正在尝试做的事情 purrr
。
mtcars %>%
split(as.character(.$cyl)) %>%
map(~t.test(.x$mpg))
但是,purrr::by_slice()
与 dplyr::group_by()
搭配得很好。
library(purrr)
library(dplyr)
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
by_slice(~ t.test(.x$mpg))
或者,您可以使用 dplyr:::summarise()
.
purrr
library(purrr)
library(dplyr)
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
summarise(t_test = data_frame(t.test(.$mpg)))
如果嵌套的 data.frame
令人困惑,broom
可以帮助我们得到一个简单的 data.frame
结果摘要。
purrr
+ broom
+ tidyr
library(broom)
library(tidyr)
mtcars %>%
group_by(as.character(cyl)) %>%
by_slice(~tidy(t.test(.x$mpg))) %>%
unnest()
dplyr
+ broom
library(broom)
mtcars %>%
dplyr::select(cyl, mpg) %>%
group_by(as.character(cyl)) %>%
do(tidy(t.test(.$mpg)))
已编辑以包括对评论的回复
有了管道,我们很快就会忘乎所以。我认为 Walt 的回答做得很好,但我想确保我提供了 purrr
-ty 答案。我希望 pipeR
的使用不会过于混乱。
library(purrr)
library(dplyr)
library(broom)
library(tidyr)
library(pipeR)
mtcars %>>%
(split(.,.$cyl)) %>>%
(split_cyl~
names(split_cyl) %>>%
(
cross_d(
list(against=.,tested=.),
.filter = `==`
)
) %>>%
by_row(
~tidy(t.test(split_cyl[[.x$tested]]$mpg,split_cyl[[.x$against]]$mpg))
)
) %>>%
unnest()
要执行两个样本 t 检验,您必须创建气缸数的组合。我看不到您可以使用 purrr
函数创建组合。然而,仅使用 purrr
和基本 R 函数的方法是
library(purrr)
t_test2 <- mtcars %>% split(.$cyl) %>%
transpose() %>%
.[["mpg"]] %>%
(function(x) combn(names(x), m=2, function(y) t.test(flatten_dbl(x[y[1]]), flatten_dbl(x[y[2]])) , simplify=FALSE))
虽然这看起来有点做作。
仅使用具有链接的基本 R 函数的类似方法是
t_test <- mtcars %>% split(.$cyl) %>%
(function(x) combn(names(x), m=2, function(y) x[y], simplify=FALSE)) %>%
lapply( function(x) t.test(x[[1]]$mpg, x[[2]]$mpg))
尤其是处理需要多路输入的管道时(我们这里没有Haskell的Arrows),我觉得先用types/signatures推理比较容易,再把逻辑封装在函数中(你可以单元测试),然后写一个简洁的链。
在这种情况下,您想比较所有可能的向量对,因此我将设定一个目标,即编写一个函数,该函数接受一对(即 2 个向量的列表)和 returns 2-其中 t.test 个。
完成此操作后,您只需要一些胶水。所以计划是:
- 编写接受向量列表并执行 2 路 t 检验的函数。
- 写一个 function/pipe 从 mtcars 获取向量(简单)。
- 将上面的内容映射到对列表上。
在编写任何代码之前制定此计划很重要。由于 R 不是强类型的,所以事情在某种程度上被混淆了,但这样你就可以首先推理 "types",其次实现。
第 1 步
t.test 取点,所以我们使用 purrr:lift
让它取一个列表。因为我们不想匹配列表元素的名称,所以我们使用 .unnamed = TRUE
。此外,我们还明确表示我们正在使用元数为 2 的 t.test
函数(尽管代码运行不需要这个额外的步骤)。
t.test2 <- function(x, y) t.test(x, y)
liftedTT <- lift(t.test2, .unnamed = TRUE)
第 2 步
将我们在步骤1中得到的函数包装成一个函数链,它采用一个简单的对(这里我使用索引,使用cyl factor levels应该很容易,但我没有时间去弄清楚) .
doTT <- function(pair) {
mtcars %>%
split(as.character(.$cyl)) %>%
map(~ select(., mpg)) %>%
extract(pair) %>%
liftedTT %>%
broom::tidy
}
步骤 3
既然我们已经准备好了所有的乐高积木,构图就很简单了。
1:length(unique(mtcars$cyl)) %>%
combn(2) %>%
as.data.frame %>%
as.list %>%
map(~ doTT(.))
$V1
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
1 6.920779 26.66364 19.74286 4.719059 0.0004048495 12.95598 3.751376 10.09018
$V2
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
1 11.56364 26.66364 15.1 7.596664 1.641348e-06 14.96675 8.318518 14.80876
$V3
estimate estimate1 estimate2 statistic p.value parameter conf.low conf.high
1 4.642857 19.74286 15.1 5.291135 4.540355e-05 18.50248 2.802925 6.482789
这里有很多东西需要清理,主要是使用因子级别并将它们保留在输出中(而不是在第二个函数中使用全局变量),但我认为你想要的核心就在这里。根据我的经验,不迷路的诀窍是从内到外工作。