R:在数据帧中按行选择具有最低值(在单独的键中)的字符串

时间:2017-11-21 18:57:33

标签: r apply

我在R中有一个包含SNP行的数据框,如下所示:

Column1 Column2 Column3 Column4
rs111   rs222   NA      NA
rs333   rs444   rs555   rs666
rs777   rs888   rs999   NA

和另一个数据框:

SNP    P value
RS111  0.21
RS222  0.02
RS333  0.80
RS444  0.55
RS555  0.10
RS666  0.07
RS777  0.99
RS888  0.33
RS999  0.45

我试图将第一个数据帧中每行的最低P值的SNP提取到新的列或列表中。实际数据框的尺寸为~15,000行×500列(包括大多数行中的大量NA)。我最初尝试用P值替换标签,使用apply for each row,然后尝试使用match函数替换P值的标签,但是无法获得类似的矩阵,并且我确定这不是最好的方法这样做。

有没有人知道如何做得更好?非常感谢你!

[R

2 个答案:

答案 0 :(得分:1)

您可以使用dplyr + tidyr

执行此操作
library(tidyr)
library(dplyr)

df1$Col_min = df1 %>%
  mutate(ID = row_number()) %>%
  gather(var, SNP, -ID) %>%
  left_join(df2 %>% mutate(SNP = tolower(SNP))) %>%
  group_by(ID) %>%
  slice(which.min(P_value)) %>%
  pull(SNP)

如果速度是一个问题,这是使用hashmap的另一个解决方案,这是非常快的。基本上,我将df2存储为哈希表,并通过索引哈希表查找返回的值,为P_value中的每一行提取具有最低df1的元素:

library(hashmap)

lookup = hashmap(df2$SNP, df2$P_value)

df1$Col_min = apply(df1, 1, function(x) x[which.min(lookup[[toupper(x)]])])

<强>结果:

  Column1 Column2 Column3 Column4 Col_min
1   rs111   rs222    <NA>    <NA>   rs222
2   rs333   rs444   rs555   rs666   rs666
3   rs777   rs888   rs999    <NA>   rs888

<强>基准:

hash_func = function(){
  apply(df1, 1, function(x) x[which.min(lookup[[toupper(x)]])])
}

dplyr_func = function(){
  df1 %>%
    mutate(ID = row_number()) %>%
    gather(var, SNP, -ID) %>%
    left_join(df2 %>% mutate(SNP = tolower(SNP))) %>%
    group_by(ID) %>%
    slice(which.min(P_value)) %>%
    pull(SNP)
}

library(microbenchmark)
microbenchmark(dplyr_func(), hash_func())

# Unit: microseconds
#         expr       min        lq       mean    median         uq      max neval
# dplyr_func() 16530.857 17780.660 20086.9777 19017.828 21500.2595 42734.06   100
#  hash_func()   153.561   177.641   311.2788   268.633   298.0425  5254.22   100

数据:

df1 = read.table(text = "Column1 Column2 Column3 Column4
rs111   rs222   NA      NA
rs333   rs444   rs555   rs666
rs777   rs888   rs999   NA", header = TRUE, stringsAsFactors = FALSE)

df2 = read.table(text = "SNP    P_value
RS111  0.21
                 RS222  0.02
                 RS333  0.80
                 RS444  0.55
                 RS555  0.10
                 RS666  0.07
                 RS777  0.99
                 RS888  0.33
                 RS999  0.45", header = TRUE, stringsAsFactors = FALSE)

答案 1 :(得分:0)

我不确定我的解决方案在内存和性能方面是否是最好的,但至少它应该起作用。意见和建议表示赞赏!

假设矩阵被称为mat,而data.frame被称为df。首先定义一个函数find_min

find_min <- function(v){
  temp <- filter(df, tolower(SNP) %in% v) %>% filter(P_value == min(P_value))
  return(temp$SNP)
}

然后你可以做

result <- apply(mat, 1, find_min)

这将为您提供一个具有最小P值的SNP列,在mat的每一行进行评估。

希望这有帮助。