【问题标题】:dplyr giving different results with the rowwise operator than looping that function over each rowdplyr 使用 rowwise 运算符给出不同的结果,而不是在每一行上循环该函数
【发布时间】:2017-12-02 00:33:13
【问题描述】:

我有一个分类变量数据框,看起来像这样(但更长)。

taxTest <- structure(list(Kingdom = structure(c(1L, 1L, 1L, 1L, 1L), .Label = "Bacteria", class = "factor"), 
Phylum = structure(c(2L, 1L, 1L, 1L, 1L), .Label = c("Bacteroidetes", 
"Proteobacteria"), class = "factor"), Class = structure(c(2L, 
1L, 1L, 1L, 1L), .Label = c("Bacteroidia", "Gammaproteobacteria"
), class = "factor"), Order = structure(c(2L, 1L, 1L, 1L, 
1L), .Label = c("Bacteroidales", "Enterobacteriales"), class = "factor"), 
Family = structure(c(2L, 1L, 3L, 1L, 3L), .Label = c("Bacteroidaceae", 
"Enterobacteriaceae", "Prevotellaceae"), class = "factor"), 
Genus = structure(c(2L, 1L, 3L, 1L, 3L), .Label = c("Bacteroides", 
"Escherichia/Shigella", "Prevotella"), class = "factor"), 
Genus.y = structure(c(NA, 1L, 2L, 1L, 2L), .Label = c("Bacteroides", 
"Prevotella"), class = "factor"), Species = structure(c(1L, 
4L, 2L, 5L, 3L), .Label = c("albertii/boydii/coli/coli,/dysenteriae/enterica/fergusonii/flexneri/sonnei/vulneris", 
"copri", "disiens", "dorei", "dorei/vulgatus"), class = "factor")), .Names = c("Kingdom", 
"Phylum", "Class", "Order", "Family", "Genus", "Genus.y", "Species"
), row.names = c("tax1", "tax2", "tax3", "tax4", "tax5"), class = "data.frame")

我想从这些数据中得出一个简短的分类名称,因此我运行了一个比这个稍微复杂的函数(它必须处理这些分类级别中的 NA 数据),但是以同样的方式失败。

library(dplyr)

tag_taxon <- function(tvdf){
    species <- tvdf %>% dplyr::select(Species) %>% unlist

    genus2 <- tvdf %>% dplyr::select(Genus, Genus.y) %>% unlist
    genus <- genus2 %>% na.omit %>% .[1]

    #genus <- tvdf %>% dplyr::select(Genus) %>% unlist

        out <- paste(genus, species)

out }

如果我对表格的每一行运行这个函数,我会得到一个我期待的答案,一个属名和种名。

for(i in 1:5){
    print(taxTest %>% .[i,] %>% tag_taxon)
}

[1] “埃希氏菌/阿尔伯氏志贺菌/boydii/coli/coli,/dysenteriae/enterica/fergusonii/flexneri/sonnei/vulneris”

[1]“拟杆菌”

[1]“普雷沃氏菌”

[1] "Bacteroides dorei/vulgatus"

[1]“普雷沃氏菌”

我觉得我应该能够使用 dplyr 将此函数应用于数据框的每一行。不幸的是,这会返回违反直觉的结果。

 taxTest %>% rowwise %>% tag_taxon

'Escherichia/Shigella albertii/boydii/coli/coli,/dysenteriae/enterica/fergusonii/flexneri/sonnei/vulneris' '大肠埃希氏菌/Shigella dorei' '大肠埃希氏菌/Shigella copri' 'Escherichia/Shigella dorei/vulgatus' 'Escherichia/Shigella disiens'

我想也许 apply 函数也可以在这里工作,但这完全失败并显示一个神秘的错误消息。

 apply(taxTest, 1, tag_taxon)

UseMethod("select_") 中的错误:'select_' 没有适用的方法 应用于“字符”类 Traceback 的对象:

  1. 申请(taxTest, 1, tag_taxon)
  2. FUN(newX[, i], ...)
  3. tvdf %>% dplyr::select(Species) %>% unlist # 在文件的第 4 行
  4. withVisible(eval(quote(_fseq(_lhs)), env, env))
  5. eval(quote(_fseq(_lhs)), env, env)
  6. eval(quote(_fseq(_lhs)), env, env)
  7. _fseq(_lhs)
  8. freduce(值, _function_list)
  9. function_list[i]
  10. dplyr::select(., Species)
  11. select.default(., Species)
  12. select_(.data, .dots = compat_as_lazy_dots(...))

对这里发生的事情有任何想法吗?我可以用 for 循环完全解决这个问题,但如果可以的话,我宁愿使用 dplyr。

谢谢!

编辑:还有一件事!我忘了在我原来的帖子中提到,如果一个人取消了#genus &lt;- tvdf %&gt;% dplyr::select(Genus) %&gt;% unlist 行(也就是说,我不尝试将物种信息附加到属信息),那么 plyr 函数会给出预期的结果。

【问题讨论】:

  • 你可以用taxTest %&gt;% select(Species) %&gt;% unlist代替taxTest %&gt;% pull(Species)
  • 另外,由于您已经加载了dplyr,因此无需使用dplyr::select 而只是select

标签: r dplyr apply


【解决方案1】:

paste 是矢量化的,因此不需要单独的函数来按行操作。下面的代码要求GenusGenus.y是字符而不是因子,所以我在运行代码之前已经完成了转换。

taxTest[,c("Genus","Genus.y")] = lapply(taxTest[,c("Genus","Genus.y")] , as.character)

taxTest %>% 
  mutate(tag = gsub("NA ", "", paste(Genus, ifelse(Genus.y==Genus, NA, Genus.y), Species)))

gsub 是去掉NA 加上它后面的空格。 tag 列如下所示:

  tag
1 Escherichia/Shigella albertii/boydii/coli/coli,/dysenteriae/enterica/fergusonii/flexneri/sonnei/vulneris
2                                                                                        Bacteroides dorei
3                                                                                         Prevotella copri
4                                                                               Bacteroides dorei/vulgatus
5                                                                                       Prevotella disiens

要查看您的原始代码发生了什么,我们可以在tag_taxon 中添加一些cat 语句。

tag_taxon <- function(tvdf){
  species <- tvdf %>% dplyr::select(Species) %>% unlist

  genus2 <- tvdf %>% dplyr::select(Genus, Genus.y) %>% unlist

  cat("genus2 = ", genus2,"\n")

  genus <- genus2 %>% na.omit %>% .[1]

  cat("genus = ", genus,"\n")

  #genus <- tvdf %>% dplyr::select(Genus) %>% unlist

  out <- paste(genus, species)

  out }

for(i in 1:5){
  print(taxTest %>% .[i,] %>% tag_taxon)
}
genus2 =  Escherichia/Shigella NA 
genus =  Escherichia/Shigella
[1] "Escherichia/Shigella albertii/boydii/coli/coli,/dysenteriae/enterica/fergusonii/flexneri/sonnei/vulneris"
genus2 =  Bacteroides Bacteroides 
genus =  Bacteroides 
[1] "Bacteroides dorei"
genus2 =  Prevotella Prevotella 
genus =  Prevotella 
[1] "Prevotella copri"
genus2 =  Bacteroides Bacteroides 
genus =  Bacteroides 
[1] "Bacteroides dorei/vulgatus"
genus2 =  Prevotella Prevotella 
genus =  Prevotella 
[1] "Prevotella disiens"

好的,for 循环正在做我们期望的事情。现在为dplyr::rowwise

taxTest %>% rowwise %>% tag_taxon
genus2 =  Escherichia/Shigella Bacteroides Prevotella Bacteroides Prevotella NA Bacteroides Prevotella Bacteroides Prevotella 
genus =  Escherichia/Shigella 
[1] "Escherichia/Shigella albertii/boydii/coli/coli,/dysenteriae/enterica/fergusonii/flexneri/sonnei/vulneris"
[2] "Escherichia/Shigella dorei"                                                                              
[3] "Escherichia/Shigella copri"                                                                              
[4] "Escherichia/Shigella dorei/vulgatus"                                                                     
[5] "Escherichia/Shigella disiens"

所以dplyrgenus2 的形式返回一个包含GenusGenus.y 中所有值的向量(NA 值除外)。然后genus 只保留第一个值并一遍又一遍地使用它。这可能与dplyr 进行非标准评估的方式有关,但我并不肯定。

如果你想使用你的函数,它会以你期望的方式工作,来自purrrlyr 包中的by_row

library(purrrlyr)

taxTest %>% by_row(tag_taxon)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多