【问题标题】:Summarise over all columns汇总所有列
【发布时间】:2015-03-21 15:26:30
【问题描述】:

我有以下格式的数据:

gen = function () sample.int(10, replace = TRUE)
x = data.frame(A = gen(), C = gen(), G = gen(), T = gen())

我现在想将行中所有元素的总和附加到每一行(我的实际函数更复杂,但sum 说明了问题)。

没有 dplyr,我会写

cbind(x, Sum = apply(x, 1, sum))

导致:

   A C  G T Sum
1  3 1  6 9  19
2  3 4  3 3  13
3  3 1 10 5  19
4  7 2  1 6  16
…

但是用 dplyr 来做这件事似乎非常困难。

我试过了

x %>% rowwise() %>% mutate(Sum = sum(A : T))

但结果不是每一行的列的总和,这是出乎意料的,(对我来说)莫名其妙。

我也试过

x %>% rowwise() %>% mutate(Sum = sum(.))

但在这里,. 只是整个 x 的占位符。不出所料,提供 no 参数也不起作用(结果都是0)。不用说,如果没有 rowwise(),这些变体都无法工作。

(实际上没有任何理由必须在 dplyr 中执行此操作,但是 (a) 我希望我的代码尽可能统一,并且在不同 API 之间跳转没有帮助;并且 (b) 我'我希望有一天能在 dplyr 中自动和免费地并行化此类命令。)

【问题讨论】:

  • 如果 sum 只是为了说明,它可能是一个糟糕的选择,因为有一个特殊的功能,如下面的答案所示。对于其他功能,收集您感兴趣的列,计算您感兴趣的值然后传播(例如使用 tidyr)可能更像 dplyr。至少这是我的解释..
  • 我想知道像 library(data.table) ; setDT(x)[, Sum := Reduce("+", .SD)][] 这样的人是否有用...
  • @DavidArenburg,很好的方法,它与 dplyr 的工作方式相同。您将如何将它与不同的功能一起使用,例如我的答案中的那个? (我认为不同之处在于+ 是一个二进制函数,接受2 个输入,然后可以多次应用/减少,而我的答案中的f 一次接受整个向量..)
  • @docendodiscimus,这就是我在 cmets 中发布此内容的原因。我们没有 Konrads 真正的功能,因此它也可能与 Reduce 一起使用。会等着看他说什么。
  • @DavidArenburg,当然 - 了解更多有关函数输入/输出设计的信息肯定会很有趣。

标签: r dplyr summarization


【解决方案1】:

这是你想要的吗?

Data %>%
   mutate(SumVar=rowSums(.))

【讨论】:

  • 它可能会,但我使用的实际函数不是矢量化的。
【解决方案2】:

我将尝试展示我在评论中所写内容的示例。假设您有一个自定义函数f

f <- function(vec) sum(vec)^2

并且您想将此函数应用于 data.frame x 的每一行。基本 R 中的一种选择是使用apply,正如您在问题中所显示的那样:

> transform(x, z = apply(x, 1, f))
#   A  C  G T   z
#1  5  7 10 7 841
#2  1  9  5 9 576
#3  7 10  2 4 529
#4  1  4 10 1 256
#5  4  4  5 2 225
#6  9  1  6 8 576
#7  9  3  7 1 400
#8  5  2  7 5 361
#9  6  3 10 4 529
#10 5 10  1 6 484

这里的小缺点是,因为您在 data.frame 上使用apply,所以首先将整个 data.frame 转换为 matrix,这当然意味着所有列都转换为相同的类型。

使用 dplyr(和 tidyr),您可以解决之后收集/熔化和散布/铸造的问题。

library(dplyr)
library(tidyr)
x %>% 
  mutate(n = row_number()) %>%    # add row numbers for grouping 
  gather(key, value, A:T) %>%
  group_by(n) %>% 
  mutate(z = f(value)) %>%
  ungroup() %>%
  spread(key, value) %>%
  select(-n)

#Source: local data frame [10 x 5]
#
#     z A  C  G T
#1  841 5  7 10 7
#2  576 1  9  5 9
#3  529 7 10  2 4
#4  256 1  4 10 1
#5  225 4  4  5 2
#6  576 9  1  6 8
#7  400 9  3  7 1
#8  361 5  2  7 5
#9  529 6  3 10 4
#10 484 5 10  1 6

这显然比使用apply 的代码要长得多,但是一旦数据变得更大,我希望这会比任何apply 在data.frame 的行上快得多。

或者,如果您手动指定列,则可以使用 rowwise

x %>%
  rowwise %>%
  mutate(z = f(c(A,C,G,T)))  # manual column specification

#Source: local data frame [10 x 5]
#Groups: <by row>
# 
#  A  C  G T   z
#1  5  7 10 7 841
#2  1  9  5 9 576
#3  7 10  2 4 529
#4  1  4 10 1 256
#5  4  4  5 2 225
#6  9  1  6 8 576
#7  9  3  7 1 400
#8  5  2  7 5 361
#9  6  3 10 4 529
#10 5 10  1 6 484

我还没有弄清楚,是否可以更改 rowwise 解决方案,以便它可以与列名的字符输入一起使用 - 也许以某种方式使用lazyeval。

数据:

set.seed(16457)
gen = function () sample.int(10, replace = TRUE)
x = data.frame(A = gen(), C = gen(), G = gen(), T = gen())

【讨论】:

  • 老实说,熔化解决方案看起来非常低效:熔化和扩散不是免费的,它涉及大量(在这种情况下)无偿复制。在我的情况下手动指定列也不可行,因为我的实际数据有 61 列,而不是 4 列(好吧,我显然可以使用 mutate_ 来解决这个问题)。我的印象是这是 dplyr 中缺少的动词……也就是说,感谢您的详尽回答。
  • @KonradRudolph,您对效率问题的看法是正确的(我做了一个小基准测试)。也许有人会想出一个更清洁、更高效的替代方案——我也有兴趣了解这一点
【解决方案3】:

我曾经做过类似的事情,到那时我最终得到了:

x %>%
  rowwise() %>%
  do(data.frame(., res = sum(unlist(.))))
#    A  C G  T res
# 1  3  2 8  6  19
# 2  6  1 7 10  24
# 3  4  8 6  7  25
# 4  6  4 7  8  25
# 5  6 10 7  2  25
# 6  7  1 2  2  12
# 7  5  4 8  5  22
# 8  9  2 3  2  16
# 9  3  4 7  6  20
# 10 7  5 3  9  24

也许你的更复杂的函数在没有unlist 的情况下也能正常工作,但对于sum 来说似乎是必要的。因为. 指的是“当前组”,所以我最初认为. 用于例如rowwise 机器中的第一行将对应x[1, ],这是一个列表,sumdo 之外愉快地吞下它

is.list((x[1, ]))
# [1] TRUE

sum(x[1, ])
# [1] 19 

但是,如果在 do 中没有 unlist,则会生成错误,我不知道为什么:

x %>%
  rowwise() %>%
  do(data.frame(., res = sum(.)))
# Error in sum(.) : invalid 'type' (list) of argument

【讨论】:

  • 更好更简洁的方法! (+1) OTOH,我认为为每一行调用 dodata.frame 可能也很昂贵(也许使用 data_frame 会更有效?)
  • 感谢您的反馈!对于我最初的用途,我不需要计算微秒,它最终可以工作就足够了......是的,我已经尝试过data_frame,但它没有返回所需的结果。
  • 嗯。这行得通。所以.do(= 当前组/行)而不是mutate(= 整个表)。惊人的。在我的情况下,我也不需要unlist,但是,我的函数也接受单行 data.frame,所以这可能就是原因。是的,在我的情况下它很慢,但apply 方法也是如此,my actual function 效率极低,根本没有优化。
  • @KonradRudolph 除了?do?rowwise 中的内容之外,我还试图找到有关. 使用的官方文本。也许@hadley here 的评论(“代词由 %>% 或 do() 提供,因此它不会与任意 dplyr 函数一起使用。”)表明 .do 一起最开心?虽然版本之间发生了很多事情,所以我不确定.的朋友和敌人的当前状态@
猜你喜欢
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多