G_T*_*G_T 6 r dplyr tidyr purrr tidyverse
使用此示例数据:
library(tidyverse)
set.seed(123)
df <- data_frame(X1 = rep(LETTERS[1:4], 6),
X2 = sort(rep(1:6, 4)),
ref = sample(1:50, 24),
sampl1 = sample(1:50, 24),
var2 = sample(1:50, 24),
meas3 = sample(1:50, 24))
Run Code Online (Sandbox Code Playgroud)
我可以summarise_at()用来计算列子集中的值的数量:
df %>% summarise_at(vars(contains("2")), funs(sd_expr = n() ))
Run Code Online (Sandbox Code Playgroud)
这不是很令人兴奋,因为它与行数相同.但是,它在具有嵌套列的表中很有用,每个单元格包含一个数据帧,每个单元格中的行数不同.
例如,
df %>%
mutate_at(vars(-one_of(c("X1", "X2", "ref"))), funs(first = . - ref)) %>%
mutate_at(vars(contains("first")), funs(second = . *2 )) %>%
nest(-X1) %>%
mutate(mean = map(data,
~ summarise_at(.x, vars(contains("second")),
funs(mean_second = mean(.) ))),
n = map(data,
~ summarise_at(.x, vars(contains("second")),
funs(n_second = n() ))) ) %>%
unnest(mean, n)
Run Code Online (Sandbox Code Playgroud)
但是我得到错误:
mutate_impl(.data,dots)出错:评估错误:无法创建对不可调用对象的调用.
为什么mean()函数在这种情况下工作而n()不是?
现在几个可以解决的问题是:
n = map(data, ~ summarise_at(.x, vars(contains("second")),
funs(n_second = length(unique(.)) )))
Run Code Online (Sandbox Code Playgroud)
但是当在不同的行上存在相同的值或者可选地:
n = map(data, ~ nrow(.x) )
Run Code Online (Sandbox Code Playgroud)
但这不允许我构建更复杂的summarise_at()功能,这正是我真正的目标.最后我想做这样的事情来计算标准误差:
se = map(data, ~ summarise_at(.x, vars(contains("second")),
funs(se_second = sd(.)/sqrt(n()) )))
Run Code Online (Sandbox Code Playgroud)
为什么n()不做我认为在这种情况下应该做的事情?
我相信aosmith的评论是正确的,这是这个问题的一个例子:
#2080:在嵌套 mutate()/summarize() 调用中使用 n() 会产生意想不到的结果
原因是 dplyr 的混合评估,它将某些 R 函数识别为它知道如何在 C++ 代码中处理的东西,并替换它们。在这种情况下,更换过于激进。特别是,mutate将 替换n()为数字 4(因为嵌套后外部数据框中有 4 行,尽管嵌套数据框本身各有 6 行)。您可以通过运行以下命令来查看:
library(tidyverse)
set.seed(123)
df <- data_frame(X1 = rep(LETTERS[1:4], 6),
X2 = sort(rep(1:6, 4)),
ref = sample(1:50, 24),
sampl1 = sample(1:50, 24),
var2 = sample(1:50, 24),
meas3 = sample(1:50, 24))
df1 <- df %>%
mutate_at(vars(-one_of(c("X1", "X2", "ref"))), funs(first = . - ref)) %>%
mutate_at(vars(contains("first")), funs(second = . *2 )) %>% print %>%
nest(-X1)
debugonce(map)
df1 %>% mutate(n = map(data,
~ summarize_at(.x,
vars(contains("second")),
funs(n_second = n()))))
Run Code Online (Sandbox Code Playgroud)
在 dplyr 0.7.8 中,这会产生以下消息:
debugging in: map(data, ~summarize_at(.x, vars(contains("second")), funs(n_second = 4L)))
Run Code Online (Sandbox Code Playgroud)
当然funs(4)不会工作,因为4不可调用,所以你会得到错误。
也许更有害的是,如果您尝试通过执行以下操作来修复它:
df1 %>% mutate(n = map(data,
~ summarize_at(.x,
vars(contains("second")),
. %>% { n() }))) %>%
unnest(n)
Run Code Online (Sandbox Code Playgroud)
在 dplyr 0.7.8 中,运行没有错误,但给出了错误的答案:计数为 4 而不是 6,因为它使用外部数据框中的行数,而不是嵌套数据框中的行数。
幸运的是,由于以下更改,所有这些都应该在 dplyr 0.8.0 中得到修复:
通过这一更改,对 的调用mutate不会替换n(),因为它不知道如何替换包含该内容的完整表达式n()(正如我们所见,周围的表达式可以更改 的含义n())。
至于在以前版本的 dplyr 中工作的替代方案,在我看来,您感兴趣的计算可以在不嵌套的情况下通过使用来实现 group_by:
df %>%
mutate_at(vars(-one_of(c("X1", "X2", "ref"))), funs(first = . - ref)) %>%
mutate_at(vars(contains("first")), funs(second = . *2 )) %>%
group_by(X1) %>%
summarise_at(vars(contains("second")),
funs(mean_second = mean(.),
n_second = n(),
se_second = sd(.)/sqrt(n()) ))
Run Code Online (Sandbox Code Playgroud)