dplyr总结:从命名向量创建变量

时间:2015-05-25 15:14:14

标签: r dplyr

这是我的问题:

我正在使用一个返回命名向量的函数。这是一个玩具示例:

toy_fn <- function(x) {
    y <- c(mean(x), sum(x), median(x), sd(x))
    names(y) <- c("Right", "Wrong", "Unanswered", "Invalid")
    y
}

我在dplyr中使用group_by为每个组应用此功能(典型的split-apply-combine)。所以,这是我的玩具数据。框架:

set.seed(1234567)
toy_df <- data.frame(id = 1:1000, 
                     group = sample(letters, 1000, replace = TRUE), 
                     value = runif(1000))

以下是我的目标:

toy_summary <- 
    toy_df %>% 
    group_by(group) %>% 
    summarize(Right = toy_fn(value)["Right"], 
              Wrong = toy_fn(value)["Wrong"], 
              Unanswered = toy_fn(value)["Unanswered"], 
              Invalid = toy_fn(value)["Invalid"])

> toy_summary
Source: local data frame [26 x 5]

   group     Right    Wrong Unanswered   Invalid
1      a 0.5038394 20.15358  0.5905526 0.2846468
2      b 0.5048040 15.64892  0.5163702 0.2994544
3      c 0.5029442 21.62660  0.5072733 0.2465612
4      d 0.5124601 14.86134  0.5382463 0.2681955
5      e 0.4649483 17.66804  0.4426197 0.3075080
6      f 0.5622644 12.36982  0.6330269 0.2850609
7      g 0.4675324 14.96104  0.4692404 0.2746589

有效!但是调用四次相同的功能并不酷。我宁愿喜欢dplyr来获取命名向量并为向量中的每个元素创建一个新变量。像这样:

toy_summary <- 
    toy_df %>% 
    group_by(group) %>% 
    summarize(toy_fn(value))

遗憾的是,这不起作用,因为&#34;错误:期待单个值&#34;。

我想,好吧,让我们使用data.frame将矢量转换为data.frame(as.list(x))。但这也不起作用。我尝试了很多东西,但是我无法欺骗dplyr认为它实际上接收了4个不同变量的单个值(观察)。有没有办法帮助dplyr意识到这一点?。

5 个答案:

答案 0 :(得分:6)

一种可能的解决方案是使用Size SE功能。例如,设置您的功能如下

dplyr

然后,您可以使用dots <- setNames(list( ~ mean(value), ~ sum(value), ~ median(value), ~ sd(value)), c("Right", "Wrong", "Unanswered", "Invalid")) (带summarize_),如下所示

_

虽然它看起来不错,但这里有一个很大的问题。在设置函数时,您必须知道要以先验(toy_df %>% group_by(group) %>% summarize_(.dots = dots) # Source: local data table [26 x 5] # # group Right Wrong Unanswered Invalid # 1 o 0.4490776 17.51403 0.4012057 0.2749956 # 2 s 0.5079569 15.23871 0.4663852 0.2555774 # 3 x 0.4620649 14.78608 0.4475117 0.2894502 # 4 a 0.5038394 20.15358 0.5905526 0.2846468 # 5 t 0.5041168 24.19761 0.5330790 0.3171022 # 6 m 0.4806628 21.14917 0.4805273 0.2825026 # 7 c 0.5029442 21.62660 0.5072733 0.2465612 # 8 w 0.4932484 17.75694 0.4891746 0.3309680 # 9 q 0.5350707 22.47297 0.5608505 0.2749941 # 10 g 0.4675324 14.96104 0.4692404 0.2746589 # .. ... ... ... ... ... )运行的列,因此如果您不设置{{1},它将无法用于其他列名称正确。

作为奖励,这是使用value使用原始功能的简单解决方案

dots

答案 1 :(得分:3)

这不是一个dplyr解决方案,但如果你喜欢管道:

library(magrittr)

toy_summary <-
  toy_df %>% 
  split(.$group) %>% 
  lapply( function(x) toy_fn(x$value) ) %>% 
  do.call(rbind, .)

# > head(toy_summary)
#         Right    Wrong Unanswered   Invalid
#   a 0.5038394 20.15358  0.5905526 0.2846468
#   b 0.5048040 15.64892  0.5163702 0.2994544
#   c 0.5029442 21.62660  0.5072733 0.2465612
#   d 0.5124601 14.86134  0.5382463 0.2681955
#   e 0.4649483 17.66804  0.4426197 0.3075080
#   f 0.5622644 12.36982  0.6330269 0.2850609      

答案 2 :(得分:3)

使用median时显然存在问题(不确定那里发生了什么)但除此之外,您通常可以使用summarise_each之类的方法来应用多个功能。请注意,您可以使用命名向量作为funs_()的输入来指定结果列的名称:

x <- c(Right = "mean", Wrong = "sd", Unanswered = "sum")

toy_df %>% 
  group_by(group) %>% 
  summarise_each(funs_(x), value)

#Source: local data frame [26 x 4]
#
#   group     Right     Wrong Unanswered
#1      a 0.5038394 0.2846468   20.15358
#2      b 0.5048040 0.2994544   15.64892
#3      c 0.5029442 0.2465612   21.62660
#4      d 0.5124601 0.2681955   14.86134
#5      e 0.4649483 0.3075080   17.66804
#6      f 0.5622644 0.2850609   12.36982
#7      g 0.4675324 0.2746589   14.96104
#8      h 0.4921506 0.2879830   21.16248
#9      i 0.5443600 0.2945428   22.31876
#10     j 0.5276048 0.3236814   20.57659
#..   ...       ...       ...        ...

答案 3 :(得分:3)

您也可以使用do()

尝试此操作
toy_df %>%
  group_by(group) %>%
  do(res = toy_fn(.$value))

答案 4 :(得分:1)

使用来自list(as_tibble(as.list(...))的{​​{1}}后跟unnest的序列来解决问题

tidyr