dplyr:按组逐组减去符合给定条件的值

3

我现在正在使用'dplyr'来重构一个基于“base”的R脚本。

基本上,我想按Gene分组,并按条件匹配的组逐个进行值的减法。在这种情况下,我希望将Gene == 'C'的值从所有其他值中减去。

简化数据如下:

x <- data.frame('gene' = c('A','A','A','B','B','B','C','C','C'),
                'sample' = rep_len(c('wt','mut1','mut2'),3),
                'value' = c(32.3,31,30.5,25,25.3,22.1,20.5,21.2,19.8))

  gene sample value
1    A     wt  32.3
2    A   mut1  31.0
3    A   mut2  30.5
4    B     wt  25.0
5    B   mut1  25.3
6    B   mut2  22.1
7    C     wt  20.5
8    C   mut1  21.2
9    C   mut2  19.8

期望的输出结果:

  gene sample value deltaC
1    A     wt  32.3   11.8
2    A   mut1  31.0    9.8
3    A   mut2  30.5   10.7
4    B     wt  25.0    4.5
5    B   mut1  25.3    4.1
6    B   mut2  22.1    2.3
7    C     wt  20.5    0.0
8    C   mut1  21.2    0.0
9    C   mut2  19.8    0.0

我明白,您需要将以下内容翻译为中文:

我基于它,这并不是什么大问题,但我想知道是否有一种简单的解决方案使用dplyr。

"伪代码":

df %>%
    group_by(Gene) %>%
    mutate(deltaC = Value - Value(where Gene == 'C'))

有没有一种函数可以让我只访问Gene == 'C'的值?当然,我也可以在之前进行子集操作,但我想一步完成 :)

2个回答

8

你已经基本掌握了!你可以在mutate调用中根据任何条件对数据帧进行子集操作:

df <- data.frame('gene' = c('A','A','A','B','B','B','C','C','C'),
                 'sample' = rep_len(c('wt','mut1','mut2'),3),
                 'value' = c(32.3,31,30.5,25,25.3,22.1,20.5,21.2,19.8))

Nicholas Hassan 指出了这个答案的原始版本存在问题。虽然你可以按"gene"分组,然后使用原始数据框的经过筛选的版本进行变异,但你最可能想做的是按"sample"分组,然后在样本组内根据"gene"进行子集筛选:

df %>%
    group_by(sample) %>%
    mutate(deltaC = value - value[gene == 'C'])

# A tibble: 9 x 4
# Groups:   sample [3]
  gene  sample value deltaC
  <fct> <fct>  <dbl>  <dbl>
1 A     wt      32.3   11.8
2 A     mut1    31      9.8
3 A     mut2    30.5   10.7
4 B     wt      25      4.5
5 B     mut1    25.3    4.1
6 B     mut2    22.1    2.3
7 C     wt      20.5    0  
8 C     mut1    21.2    0  
9 C     mut2    19.8    0  

在分组数据框中,mutate会将每个组视为自己的小型数据框,在该组中,您可以将value向量子集仅限于gene == 'C'的行,并从该组中的整个value变量中减去该值,以形成deltaC


但是是否也有一种不使用“base”为基础的括号/美元符号表示法的方法?例如,针对dplyr的特定方法? :) - interrobang
当然,你可以使用 filter 来基本上做同样的事情。 - divibisan
太好了!非常感谢你! - interrobang
@divibisan 谢谢您的回复!您能解释一下 group_by 在 gene 上是如何工作的吗?当我尝试使用它时,我认为您需要在 sample 上进行分组。如果以 gene 为分组依据,它是如何知道基于它们都是 wt,将第 1 行和第 4 行(以及第 7 行)减去第 7 行的呢? - Nicholas Hassan
@NicholasHassan 你说得完全正确。OP说他们想要按“gene”分组,减法之所以能够正确运行是因为每个组都按照相同的方式在“sample”上排序,但如果它们没有按照相同的方式排序,那么你将会得到错误的结果。按“sample”分组,然后在mutate中对变量进行子集操作绝对是更好的方法。感谢你指出这一点! - divibisan

3

如果你想完全避免使用 $,可以使用 dplyr::pull,如下:

df %>%
  group_by(gene) %>%
  mutate(deltaC = value - filter(., gene == 'C') %>% pull(value))

dplyr::pull基本上只是管道友好型的dplyr版本的df$valuedf$[["value"]]

此外,在过滤语句中使用.代表被传递到变异语句中的数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接