【问题标题】:Subtract rows of data frames column-wise preserving multiple factor column按列减去数据帧的行,保留多因子列
【发布时间】:2018-11-12 14:35:51
【问题描述】:

我有两个列数不等的数据框。我想从 df1 中减去 df2 行的强度值,按列(即按样本)。 我的条件是:

  1. 在 df1 中,每个基因 (gene_nm) 的肽序列 (pep_seq) 及其对应的每个样本的强度 (int_sam) 都有多行。同一个基因出现多次,即占据多行。
  2. 在 df2 中,基因(行)仅出现一次并具有相应的强度值
  3. 因此,df1 比 df2 长得多(例如,55000 行与 6000 行)
  4. 强度列 (int_samp) 的数量可以很多。在这个例子中我有 3 个

数据框 1

pep_seq = c("aaaaaaaaa", "ababababba", "dfsfsfsfds", "xbbcbcncncc", "fbbdsgffhhh", "dggdgdgegeggerr", 
        "dfgthrgfgf", "wegregegg", "egegegergewge", "sfngegebser", "qegqeefbew", "qegqetegqt", 
        "qwtqtewr", "etghsfrgf", "sfsdfbdfbergeagaegr", "wasfqertsdfaefwe")
int_samp_1 = c("2421432", "24242424", "NA", "4684757849", "NA", "10485040", "NA", 
          "6849400", "40300", "NA", "NA", "NA", "556456466", "4646456466", "246464266", "4564242646")
int_samp_2 = c("NA", "5342353", "14532556", "43566", "46367367", "768769769", "797899", "NA", "NA", "NA", 
          "686899", "7898979", "678568", "NA", "68886", "488")
int_samp_3 = c("11351", "NA", "NA", "NA", "1354151345", "1351351354", "314534", "1535", "3145354", "4353455", 
          "324535", "3543445", "34535", "34535534", "NA", "NA")
gene_nm = c("A", "A", "A", "A", "A", "A", "B", "B", "B", "C", "C", "C", "C", "C", "C", "C")
df_1 = cbind.data.frame(pep_seq, int_samp_1, int_samp_2, int_samp_3, gene_nm)

数据框 2

int_samp_1a = c("2421432", "24242424", "NA")
int_samp_2a = c("NA", "5342353", "14532556")
int_samp_3a = c("11351", "NA", "NA")
gene_nm.a = c("A", "B", "C")
df_2 = cbind.data.frame(gene_nm.a, int_samp_1a, int_samp_2a, int_samp_3a)

请提出建议。

【问题讨论】:

  • 您已经很好地描述了您的数据。现在在这种情况下您的预期输出是什么?
  • 你想如何对待NA?例如,如果df_2 中有NAdf_1 中没有,那么df_1 中的值是否应该保持不变,就好像我们在减零一样?如果df_2 中有一个值,但df_1 中有NA 怎么办?最终应该是一个负数,还是保持NA
  • 数据中真正奇怪的一点是,所有测量值都在factor 中定义。我认为最终需要对这些进行减法时不需要它。
  • @MKR............对不起,我没有提到我需要的输出。这可以是带有减去值的单独列,也可以是单独的数据框。两者都会很好。
  • @andrew_reece.. 我可以根据情况从数据帧中删除 NA。在这种情况下想将它们视为“0”。所以是的,你是对的。谢谢。

标签: r dataframe dplyr purrr


【解决方案1】:

IIUC,您在df_1df_2 中有同名的列(例如int_samp_X 表示某个整数X),并且您想获得匹配列名的差异,按gene_nm 分组(例如df_1[df_1$gene_nm == 'A', int_samp_1] - df_2[df_2$gene_nm == 'A', int_samp_1])。

我们可以使用tidyverse 系列包来解决这个问题,特别是dplyrpurrr

首先,将df_1df_2left_join 合并,以确保df_1 中的所有许多条目在与df_2 中的基因级条目匹配时都被保留:

library(tidyverse)

df_3 <- df_1 %>% left_join(df_2, by = "gene_nm")

df_3
               pep_seq int_samp_1.x int_samp_2.x int_samp_3.x gene_nm int_samp_1.y int_samp_2.y int_samp_3.y
1            aaaaaaaaa      2421432           NA        11351       A      2421432           NA        11351
2           ababababba     24242424      5342353           NA       A      2421432           NA        11351
3           dfsfsfsfds           NA     14532556           NA       A      2421432           NA        11351
4          xbbcbcncncc   4684757849        43566           NA       A      2421432           NA        11351
5          fbbdsgffhhh           NA     46367367   1354151345       A      2421432           NA        11351
6      dggdgdgegeggerr     10485040    768769769   1351351354       A      2421432           NA        11351
7           dfgthrgfgf           NA       797899       314534       B     24242424      5342353           NA
8            wegregegg      6849400           NA         1535       B     24242424      5342353           NA
9        egegegergewge        40300           NA      3145354       B     24242424      5342353           NA
10         sfngegebser           NA           NA      4353455       C           NA     14532556           NA
11          qegqeefbew           NA       686899       324535       C           NA     14532556           NA
12          qegqetegqt           NA      7898979      3543445       C           NA     14532556           NA
13            qwtqtewr    556456466       678568        34535       C           NA     14532556           NA
14           etghsfrgf   4646456466           NA     34535534       C           NA     14532556           NA
15 sfsdfbdfbergeagaegr    246464266        68886           NA       C           NA     14532556           NA
16    wasfqertsdfaefwe   4564242646          488           NA       C           NA     14532556           NA

然后map 覆盖感兴趣的列名,获取每个列对的差异。 (请注意,您需要先将 int_samp 列从 factor 转换为 numeric。)

更新(每个 OP cmets): 要在计算差异之前将NA 转换为0,我们可以使用mutate_if()replace(),将以下内容添加到方法链中:

mutate_if(is.numeric,  funs(replace(., is.na(.), 0)))

最后,joindf_1

var_names <- df_1 %>% select(starts_with("int_samp")) %>% names()

var_names # [1] "int_samp_1" "int_samp_2" "int_samp_3"

var_names %>%
  map_dfc(~df_3 %>%
            mutate_at(vars(matches(.x)), funs(as.numeric(as.character(.)))) %>%
            mutate_if(is.numeric,  funs(replace(., is.na(.), 0))) %>%
            select(matches(.x)) %>%
            reduce(`-`)) %>%
  set_names(paste0(var_names, "_diff")) %>%
  bind_cols(df_1)

输出:

   int_samp_1_diff int_samp_2_diff int_samp_3_diff pep_seq             int_samp_1 int_samp_2 int_samp_3 gene_nm
             <dbl>           <dbl>           <dbl> <fct>               <fct>      <fct>      <fct>      <fct>  
 1              0.              0.              0. aaaaaaaaa           2421432    NA         11351      A      
 2       21820992.        5342353.         -11351. ababababba          24242424   5342353    NA         A      
 3       -2421432.       14532556.         -11351. dfsfsfsfds          NA         14532556   NA         A      
 4     4682336417.          43566.         -11351. xbbcbcncncc         4684757849 43566      NA         A      
 5       -2421432.       46367367.     1354139994. fbbdsgffhhh         NA         46367367   1354151345 A      
 6        8063608.      768769769.     1351340003. dggdgdgegeggerr     10485040   768769769  1351351354 A      
 7      -24242424.       -4544454.         314534. dfgthrgfgf          NA         797899     314534     B      
 8      -17393024.       -5342353.           1535. wegregegg           6849400    NA         1535       B      
 9      -24202124.       -5342353.        3145354. egegegergewge       40300      NA         3145354    B      
10              0.      -14532556.        4353455. sfngegebser         NA         NA         4353455    C      
11              0.      -13845657.         324535. qegqeefbew          NA         686899     324535     C      
12              0.       -6633577.        3543445. qegqetegqt          NA         7898979    3543445    C      
13      556456466.      -13853988.          34535. qwtqtewr            556456466  678568     34535      C      
14     4646456466.      -14532556.       34535534. etghsfrgf           4646456466 NA         34535534   C      
15      246464266.      -14463670.              0. sfsdfbdfbergeagaegr 246464266  68886      NA         C      
16     4564242646.      -14532068.              0. wasfqertsdfaefwe    4564242646 488        NA         C  

注意:这个答案很大程度上是从 akrun 的答案here 推导出来的。

【讨论】:

  • 我只是想知道为什么我们的结果不匹配。逻辑非常相似。匹配的值也很少。
  • 结果不匹配。我试图理解为什么会这样?
  • @andrew_reece 我正在寻找int_samp_1_diff 专栏。 3rd, 4th and 5th 行不匹配。也许,因为如果 df_1 中的值是 NA,我将值保留为 NA。这表明我们的解决方案是一致的。 :-)
  • @IndranilPaul 也许这些答案会对您有所帮助。如果是这样,您可以接受答案,最好查看此链接stackoverflow.com/help/someone-answers
  • 感谢你们俩。你们真棒!我接受andrew_reece的解决方案,主要是我比较容易理解。
【解决方案2】:

一种选择是使用dplyr 连接df_1df_2,然后执行简单的矩阵减法。

注意:数据帧的强度读数是因子。我认为当您希望执行减法时,将测量因素考虑在内并不是一个好主意。因此我将它们转换为integer

library(dplyr)

# The NA values from df_2 has been changed to 0 since keeping those NA, will
# turn values in df_A NA for no reason. 
mod <- df_1 %>% left_join(df_2, by= c("gene_nm" = "gene_nm.a")) %>% # join on gene
  mutate_at(vars(starts_with("int_samp")), funs(as.integer(as.character(.)))) %>%
  mutate_at(vars(ends_with("a")), funs(ifelse(is.na(.),0L,.))) #Values are converted

# The modified data.frame got columns from both df_1 and df_2
mod[,grepl("^int_samp_\\d+$", names(mod))] <- 
                mod[,grepl("^int_samp_\\d+$", names(mod))] -  
                mod[,grepl("^int_samp_\\d+[a-z]+$", names(mod))]

# Take columns from df_1. 
mod[names(df_1)]
#                pep_seq int_samp_1 int_samp_2 int_samp_3 gene_nm
# 1            aaaaaaaaa          0         NA          0       A
# 2           ababababba   21820992    5342353         NA       A
# 3           dfsfsfsfds         NA   14532556         NA       A
# 4          xbbcbcncncc         NA      43566         NA       A
# 5          fbbdsgffhhh         NA   46367367 1354139994       A
# 6      dggdgdgegeggerr    8063608  768769769 1351340003       A
# 7           dfgthrgfgf         NA   -4544454     314534       B
# 8            wegregegg  -17393024         NA       1535       B
# 9        egegegergewge  -24202124         NA    3145354       B
# 10         sfngegebser         NA         NA    4353455       C
# 11          qegqeefbew         NA  -13845657     324535       C
# 12          qegqetegqt         NA   -6633577    3543445       C
# 13            qwtqtewr  556456466  -13853988      34535       C
# 14           etghsfrgf         NA         NA   34535534       C
# 15 sfsdfbdfbergeagaegr  246464266  -14463670         NA       C
# 16    wasfqertsdfaefwe         NA  -14532068         NA       C

【讨论】:

  • 我收到以下错误。 (function (classes, fdef, mtable) 中的错误:无法为签名“numeric”的函数“funs”找到继承的方法。两种解决方案都出现相同的错误。
  • 你能检查一下你在哪一行得到错误吗?您最多可以选择%&gt;% 之前的位置并执行。您可以通过这种方式找到您遇到错误的行。
  • 谢谢。似乎问题出在funs( 上。我可以从代码中删除funs(ifelse(is.na(.),0L,.))。我可以在外面的数据框上做这个操作
  • @ip2018 我认为这些列应该首先在df2_2 中转换为Numeric
  • 让我看看。我会在大约几个小时后回来。
猜你喜欢
  • 1970-01-01
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多