10

我有以下格式的数据:

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. 不出所料,不提供任何参数也行不通(结果都是0)。不用说,这些变体都没有rowwise().

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

4

3 回答 3

5

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

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, ],这是一个列表,它sum在外面愉快地吞下do

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

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

但是,没有生成错误unlistdo我不确定为什么:

x %>%
  rowwise() %>%
  do(data.frame(., res = sum(.)))
# Error in sum(.) : invalid 'type' (list) of argument
于 2015-01-22T22:00:31.703 回答
3

这会做你想要的吗?

Data %>%
   mutate(SumVar=rowSums(.))
于 2015-01-22T18:01:30.533 回答
1

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

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

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

> 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

这里的小缺点是,因为您apply在 data.frame 上使用,整个 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但是一旦数据变大一点,我希望这比applydata.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())
于 2015-01-22T18:56:30.067 回答