【问题标题】:How to cast this sapply use-case as a dplyr?如何将此 sapply 用例转换为 dplyr?
【发布时间】:2019-11-03 13:02:38
【问题描述】:

在使用 predict.knn3 时,我遇到了一个有趣的数据争吵用例。我不知道我可以使用参数 type="class" 调用 predict 来获得预测的水平,这正是我所需要的。因此,我制定了一个有点复杂的解决方案,从每个predict() 的结果行中选择概率最大的级别。问题是由于names 函数不能以矩阵的“矢量化”形式工作,而只能与向量一起工作。

为了说明在发现 type="class" 参数之前和之后的用例:

rm(list = ls())
library(caret)
library(tidyverse)
library(dslabs)

data("tissue_gene_expression")
x <- tissue_gene_expression$x
y <- tissue_gene_expression$y

set.seed(1)
test_index <- createDataPartition(y, times = 1, p = 0.5, list = FALSE)
test_x <- x[test_index,]
test_y <- y[test_index]
train_x <- x[-test_index,]
train_y <- y[-test_index]

# fit the model, predict without type="class" and use sapply to build the y_hat levels
fit <- knn3(train_x, train_y, k = 1)
pred <- predict(fit, test_x)
y_hat <- sapply(1:nrow(pred), function(i) as.factor(names(pred[i,which.max(pred[i,])])))

# compare it to the solution using predict with type="class"
identical(y_hat, as.factor(predict(fit, test_x, type="class")))
[1] TRUE

为了说明问题,我可以执行以下操作,请参阅对命名数字元素的向量进行操作的 names 函数会产生所需的结果,而使用矩阵将失败并输出 NULL:

names(pred[1, which.max(pred[1,])])
[1] "cerebellum"
names(pred[1:2, which.max(pred[1:2,])])
NULL

假设在predict.knn3 函数中不知道这个方便的type="class";有没有更简单的方法使用 tidyverse 和 dplyr 来替换这个 sapply?或者任何其他更简单的方法来实现这个用例?

y_hat <- sapply(1:nrow(pred), function(i) as.factor(names(pred[i, which.max(pred[i,])])))

我正在追求类似以下的东西,但它不起作用:

as_tibble(predict(fit, test_x)) %>% mutate(y_hat=names(which.max(.[row_number(),])))

【问题讨论】:

    标签: r dplyr tidyverse


    【解决方案1】:

    我发现使用dplyr 对行进行操作可能有点混乱。不过,这应该可以。猜测一下,这并不是计算效率最高的。

    solution <- as_tibble(predict(fit, test_x)) %>%
      rowwise() %>%
      do(as.data.frame(.) %>%
           mutate(., y_hat = names(.)[which.max(select(., everything()))])
      )
    
    solution %>%
      slice(18:22)
    
    # A tibble: 5 x 8
      cerebellum colon endometrium hippocampus kidney liver placenta y_hat     
           <dbl> <dbl>       <dbl>       <dbl>  <dbl> <dbl>    <dbl> <chr>     
    1          1     0           0           0      0     0        0 cerebellum
    2          1     0           0           0      0     0        0 cerebellum
    3          0     1           0           0      0     0        0 colon     
    4          0     1           0           0      0     0        0 colon     
    5          0     1           0           0      0     0        0 colon
    

    【讨论】:

      【解决方案2】:

      由于预测是一个矩阵,您可以直接将which.max 应用于每一行。

      pred <- predict(fit, test_x)
      labels <- colnames(pred)
      labels[apply(pred, 1, which.max)]
      

      【讨论】:

        【解决方案3】:

        见?max.col:

        colnames(pred)[max.col(pred)]
        
        #or dplyr
        
        library (dplyr)
        
        pred%>%
          as_tibble()%>%
          mutate(y_hat = names(.)[max.col(.)])
        

        【讨论】:

        • @SkyWalker 查看dplyr 方法的编辑。它应该很快,因为max.col 是矢量化的
        【解决方案4】:

        我必须使用 melt 将矩阵变成长格式:

        library(reshape2)
        melt(pred) %>% 
            group_by(Var1) %>% 
            top_n(1,wt=value) %>% pull(Var2)
        

        【讨论】:

        • 如果你这样做,我现在会使用tidyr 和pivot_longer()。根据 github 页面:“reshape2 已退役:只会进行必要的更改以将其保留在 CRAN 上。我们建议改用 tidyr。”
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-05-30
        • 2019-11-23
        • 2016-02-10
        • 2017-09-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多