【问题标题】:R, how to add an unlist (and other) function inside an apply function?R,如何在 apply 函数中添加一个 unlist (和其他)函数?
【发布时间】:2016-07-19 14:44:07
【问题描述】:

背景:我正在研究基因和本体,但我的问题涉及 R 脚本编写。

我想用从数据库中提取的相应术语替换我的数据框中的 GO:ID。

所以,这是我的源数据框。它是一个基因列表 (v1) 和相关的 GO:ID (v2):

>gene_list_and_Go_ID

         V1                                                V2
2563  Gene1    GO:0003871, GO:0008270, GO:0008652, GO:0009086
2580  Gene2    GO:0003871, GO:0008270, GO:0008652, GO:0009086
12686 Gene3    GO:0003871, GO:0008270, GO:0008652, GO:0009086
14523 Gene4                GO:0004489, GO:0006555, GO:0055114

对数据库的请求看起来很简单:

>select(GO.db, my_Go_id, "TERM", "GOID")

我尝试了以下几行手动寻址数据库,效果很好:

>my_Go_id = unlist(strsplit("GO:0008270, GO:0008652, GO:0009086", split=", "))
>select(GO.db, my_Go_id, "TERM", "GOID")

    GOID                                     TERM
1 GO:0008270                         zinc ion binding
2 GO:0008652 cellular amino acid biosynthetic process
3 GO:0009086          methionine biosynthetic process

我的问题:我不能让这个过程自动化! 准确地说,对于每一行,我需要将每个字符串从我的数据框中的第 n°2 列转换为一个向量,以便质疑数据库。 然后我需要将数据框中的 GO:ID 替换为请求的结果。

1/ 首先,我尝试将“unlist”函数放在“apply”函数中到我的数据框:

apply(gene_list_and_Go_ID,1,unlist(strsplit(gene_list_and_Go_ID[,2], split=", ")))

我明白了:

Error in strsplit(ok, split = ", ") : non-character argument

2/ 那么,我可以在apply函数中也将请求添加到数据库中吗?

3/ 最后,我不知道如何将第 2 列替换为数据库请求的结果。

这是一个例外的“理想”结果示例:

         V1                                                              V2
2563  Gene1        GOID                                                TERM
                   1 GO:0008270                            zinc ion binding
                   2 GO:0008652    cellular amino acid biosynthetic process
                   3 GO:0009086             methionine biosynthetic process

感谢您的帮助。

【问题讨论】:

    标签: r dataframe apply strsplit


    【解决方案1】:

    最近的问题是你不像你那样打电话给apply。您需要提供一个函数,该函数将通过其第一个参数依次将数组的每一行/列作为输入,而不是像您那样编写函数 call ,因此您想要类似(未测试,因为你不需要这个)

    apply(gene_list_and_Go_ID, 1,
          function(x) { unlist(strsplit(x[2], split=", "))})
    

    但是,请注意您不需要gene_list_and_Go_ID 的整个。您想要的是在gene_list_and_Go_IDV2 上工作。现在还要注意strsplit向量化的,这意味着如果你传递一个长度大于1 的向量,它将作用于该向量的每个元素,就好像你重复调用strsplit() on依次为向量的每个元素。

    考虑以下几点:

    df <- data.frame(V1 = paste0("Gene", 1:4),
                     V2 = c("GO:0003871, GO:0008270, GO:0008652, GO:0009086",
                            "GO:0003871, GO:0008270, GO:0008652, GO:0009086",
                            "GO:0003871, GO:0008270, GO:0008652, GO:0009086",
                            "GO:0004489, GO:0006555, GO:0055114"),
                     stringsAsFactors = FALSE)
    

    注意V2 必须是一个字符向量 --- 这里我使用stringsAsFactors = FALSE 来停止自动强制转换character -> factor,但你也可以只使用as.character(V2) 我有@ 987654334@在下面的代码中。

    要在V2 的每个元素上运行strsplit,我们可以使用:

    spl <- with(df, strsplit(V2, ", "))
    

    这得到了我们

    > spl
    [[1]]
    [1] "GO:0003871" "GO:0008270" "GO:0008652" "GO:0009086"
    
    [[2]]
    [1] "GO:0003871" "GO:0008270" "GO:0008652" "GO:0009086"
    
    [[3]]
    [1] "GO:0003871" "GO:0008270" "GO:0008652" "GO:0009086"
    
    [[4]]
    [1] "GO:0004489" "GO:0006555" "GO:0055114"
    

    select 调用的外观来看,这是一次性交易 - 您需要为df(您的gene_list_and_Go_ID)中的所有行调用它。如果是这样,只需遍历 strsplit() 返回的列表的元素:

    names(spl) <- with(df, as.character(V1))
    term <- lapply(spl, function(x, db) select(db, x, "TERM", "GOID"),
                   db = GO.db)
    

    这将返回一个列表,其中每个元素都是对select 的单个基因/df 行的调用的结果。

    你可能想要把它重新组合起来:

    out <- cbind.data.frame(Gene = rep(names(spl), each = lengths(spl)),
                            do.call("rbind", term))
    

    但我无法测试最后几部分,因为我不知道 select() 来自哪里,也不知道 GO.db 是什么创建的

    【讨论】:

    • 感谢您提供如此详细的答案和您的时间。很多东西对我来说都是全新的(paste0、with、c 和 rbind、rep、lengths……)。我将进一步了解所有这些功能,太好了! :-)
    【解决方案2】:

    好的,根据 Gavin 的回答和他的热心帮助,我得到了正确的脚本。但是有一个非常重要的步骤阻止了我:将我的“gene_list_and_Go_ID”数据框第二列从因子转换为字符。我这样做是为了跳过“strsplit”函数中的“非字符参数”错误。这篇文章帮助了我:LINK

    所以这是我的起始数据框:

    >gene_list_and_Go_ID
    
             V1                                                V2
    2563  Gene1    GO:0003871, GO:0008270, GO:0008652, GO:0009086
    2580  Gene2    GO:0003871, GO:0008270, GO:0008652, GO:0009086
    12686 Gene3    GO:0003871, GO:0008270, GO:0008652, GO:0009086
    14523 Gene4                GO:0004489, GO:0006555, GO:0055114
    

    接下来是脚本。 第一个新行看起来非常有用(将我的 df 从因子转换为字符):

    >gene_list_and_Go_ID <- data.frame(lapply(gene_list_and_Go_ID, as.character), stringsAsFactors=FALSE)
    

    下一个:

    >V_ID <- with(gene_list_and_Go_ID, strsplit(V2, ", "))
    >names(V_ID) <- with(gene_list_and_Go_ID, as.character(V1))
    >terms <- lapply(V_ID, function(x, db) select(db, x, "TERM", "GOID"), db = GO.db)
    

    最终的输出是完美的:-) :

    > terms
    $Gene1
            GOID                        TERM
    1 GO:0003871 S-methyltransferase activity
    2 GO:0008270 zinc ion binding
    3 GO:0008652 cellular amino acid biosynthetic process
    4 GO:0009086 methionine biosynthetic process
    
    $Gene2
    ... etc ...
    ... etc ...
    

    注意,我跳过了最后一个 Gavin 的建议:

    out <- cbind.data.frame(Gene = rep(names(spl), each = lengths(spl)),
                        do.call("rbind", term))
    

    这可能是一个非常优雅的脚本,但我很难理解它的所有功能,下面是它生成的内容:

    Error in data.frame(..., check.names = FALSE) : 
      arguments imply differing number of rows: 16, 15
    In addition: Warning message:
    In rep(names(V_ID), each = lengths(V_ID)) :
      first element used of 'each' argument
    

    谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-03-28
      • 1970-01-01
      • 2021-07-02
      • 1970-01-01
      • 1970-01-01
      • 2018-11-15
      相关资源
      最近更新 更多