【问题标题】:Dplyr syntax selecting columns and converting them to a single listDplyr 语法选择列并将它们转换为单个列表
【发布时间】:2021-07-08 01:07:19
【问题描述】:

我开始学习如何使用 dplyr 的管道 (%>%) 命令来操作数据帧。我喜欢它看起来更加精简。但是,我刚刚遇到了一个仅使用管道无法解决的问题。

我有一个数据框,其中包含如下所示的关系(网络)数据:

前两列表示哪些项目(基因)之间存在关系,第三列包含有关该关系的信息:

  a      b      c    
1 Gene_1 Gene_2 X    
2 Gene_2 Gene_3 R    
3 Gene_1 Gene_4 X    

我的目标是获取具有相同属性的独特基因列表。如果选择了 col 3 中的属性X,我会得到这个数据框:

  a      b      c    
1 Gene_1 Gene_2 X     
3 Gene_1 Gene_4 X   

我想以这个独特基因列表结束:

genes = c("Gene_1" "Gene_2" "Gene_4")

项目(基因)来自第一列还是第二列都没有关系,我只想要一个唯一的列表。我想出了这个解决方案:

library(tidyr)

net = tibble(a = c("Gene_1", "Gene_2", "Gene_1"),
       b = c("Gene_2", "Gene_3", "Gene_4"),
       c = c("X", "R", "X"))

df = net %>% 
  filter(c == "X") %>%
  select(c(1,2)) 

genes = unique(c(df$a, df$b))

但我并不满意,因为我无法在 dplyr 管道命令中完成所有操作。我必须在管道命令之外创建一个列表,然后在其上调用 unique。

有没有办法通过调用另一个管道来完成这项任务?我无论如何都找不到这样做。谢谢。

【问题讨论】:

    标签: r dplyr syntax


    【解决方案1】:

    虽然 OP 也提出并接受了许多有启发性的答案,但我只想补充一点,以防您希望同时为 c 中的所有值提供它,这样做

    library(tidyverse)
    
    net %>%
      group_split(c, .keep = F) %>%
      setNames(unique(net$c)) %>%
      map(~ (.x %>% unlist() %>% unique()))
    
    $X
    [1] "Gene_2" "Gene_3"
    
    $R
    [1] "Gene_1" "Gene_2" "Gene_4"
    

    【讨论】:

      【解决方案2】:

      1) 像这样使用{...}

      net %>% 
        filter(c == "X") %>%
        select(c(1,2)) %>%
        { unique(c(.$a, .$b)) }
      ## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
      

      2) 或使用 magrittr 的 %$% 管道:

      library(magrittr)
      
      net %>% 
        filter(c == "X") %>%
        select(c(1,2)) %$%
        unique(c(a, b))
      ## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
      

      3) 或使用with:

      net %>% 
        filter(c == "X") %>%
        select(c(1,2)) %>%
        with(unique(c(a, b)))
      ## [1] "Gene_1" "Gene_3" "Gene_2" "Gene_5"
      

      由于结果不是数据框最好不要调用它df

      【讨论】:

        【解决方案3】:
        library(tidyverse)
        
        net <- tibble(
          a = c("Gene_1", "Gene_1", "Gene_3"),
          b = c("Gene_2", "Gene_4", "Gene_5"),
          c = c("X", "R", "X")
        )
        
        df <- net %>%
          filter(c == "X") %>%
          select(a, b)
        df
        #> # A tibble: 2 x 2
        #>   a      b     
        #>   <chr>  <chr> 
        #> 1 Gene_1 Gene_2
        #> 2 Gene_3 Gene_5
        
        genes <- net %>%
          select(-c) %>%
          unlist() %>%
          unique()
        genes
        #> [1] "Gene_1" "Gene_3" "Gene_2" "Gene_4" "Gene_5"
        

        【讨论】:

          【解决方案4】:

          unlist() 函数可能正是您想要的。

          引用?unlist 的内置文档:“给定一个列表结构 x,unlist 将其简化为一个包含 x 中出现的所有原子组件的向量。”

          由于 R 数据帧(和 tibbles)被实现为长度相等的列向量列表,因此 unlist 函数将有效地将数据帧转换为向量。

          使用filterselect 对所需行和列进行子集,然后将结果通过unlist()unique() 进行管道传输。结果将是一个包含不同元素的向量。

          library(dplyr)
          
          # The example data
          tibble(a = c("Gene_1", "Gene_2", "Gene_1"),
                 b = c("Gene_2", "Gene_3", "Gene_4"),
                 c = c("X", "R", "X")) %>%
              
              # Subset data for desired feature
              filter(c == "X") %>%
              
              # Select identifier columns
              select(a, b) %>%
              
              # convert to a vector
              unlist() %>%
              
              # derive unique elements
              unique()
          

          结果

          [1] "Gene_1" "Gene_2" "Gene_4"
          

          【讨论】:

            【解决方案5】:

            我意识到这个问题有几个答案,但我会采取稍微不同的方式。也许它对某人有用?

            我也创建了一个数据集来演示。

            library(tidyverse) 
            library(stringi)    # only used in data generation
            
            # data set creation 100 rows
            a = paste0("Gene_",1:100)
            b = paste0("Gene_",round(runif(100, 10, 99),digits = 0))
            cC = paste0(stringi::stri_rand_strings(100, 1, '[A-Z]'))
            
            # put it together and strip the information    
            data.frame(a = a, b = b, cC = cC) %>% # collect the data
               filter(cC == "X") %>%              # filter for attribute
               select(-cC) %>%                    # remove attribute field
               unlist() %>%                       # collapse the data frame into a vector
               unique()                           # show me what's unique
            
            # output example
            # [1] "Gene_10" "Gene_12" "Gene_28" "Gene_77" "Gene_22" "Gene_41" "Gene_75"
            # [8] "Gene_19"
            

            【讨论】:

              【解决方案6】:

              我建议使用tidyr::pivot_longer 将多个潜在匹配列从两个不同的基因列重塑为一个值列(我们关心)和一个名称列(引用原始列名,我们不这样做' t关心并且可以忽略)。然后distinct得到唯一匹配,最后匹配到c列:

              net %>%
                pivot_longer(-c) %>%
                distinct(c, value) %>%
                filter(c == "X") 
              

              如果要将结果作为向量,可以添加%&gt;% pull(value)

              这种方法的一个好处是,我们已经为每一列 c 值计算了每组不同的基因,最后一个 filter 步骤只是将其缩小到一个示例 c 值。

              结果

                c     value 
                <chr> <chr> 
              1 X     Gene_1
              2 X     Gene_2
              3 X     Gene_4
              

              [注意:我制作了a = c("Gene_1", "Gene_2", "Gene_1")b = c("Gene_2", "Gene_3", "Gene_4") 来匹配示例。]

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-07-20
                • 2016-01-05
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多