我是purrr的新手,Hadley有前途的函数式编程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
的工作原理吗?或者有更好的方式来考虑这个问题吗?
答案 0 :(得分:10)
我不完全理解预期的结果,但这可能是一个答案的起点。来自map()
的{{1}}在公式参数中使用purrr
。
这是完成我认为你只想.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))
跳过purrr
。
dplyr:::summarise()
如果嵌套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)))
- ty答案。我希望purrr
的使用不会过于混乱。
pipeR
答案 1 :(得分:6)
特别是在处理需要多个输入的管道时(我们这里没有Haskell的箭头),我发现首先通过类型/签名更容易推理,然后将逻辑封装在函数中(你可以单元测试),然后写一个简洁的链。
在这种情况下,你想要比较所有可能的向量对,所以我会设定一个目标,即编写一个带有一对(即2个列表)向量的函数,并返回它们的双向t.test
一旦你完成了这个,你只需要一些胶水。所以计划是:
在编写任何代码之前制定此计划非常重要。由于R不是强类型的事实,事情在某种程度上被混淆了,但这种方式你推理"类型"首先,实施第二。
t.test需要点数,因此我们使用purrr:lift
来获取列表。由于我们不想匹配列表元素的名称,因此我们使用.unnamed = TRUE
。此外,我们更清楚地说明我们使用t.test
函数,其中arity为2(尽管代码不需要执行此额外步骤)。
t.test2 <- function(x, y) t.test(x, y)
liftedTT <- lift(t.test2, .unnamed = TRUE)
将我们在第1步中获得的功能包装到一个简单配对的功能链中(这里我使用索引,应该很容易使用cyl factor级别,但我没有时间去弄清楚)
doTT <- function(pair) {
mtcars %>%
split(as.character(.$cyl)) %>%
map(~ select(., mpg)) %>%
extract(pair) %>%
liftedTT %>%
broom::tidy
}
既然我们准备好了所有的乐高乐曲,那么乐曲很简单。
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
这里有相当多的清理工作,主要是使用因子级别并在输出中保留它们(而不是在第二个函数中使用全局变量),但我认为你想要的核心就在这里。根据我的经验,不要迷失的诀窍就是从内到外工作。
答案 2 :(得分:2)
要执行两个样本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))