【问题标题】:Using dplyr/purrr instead of for loops to mask multiple columns and/or expand rows使用 dplyr/purrr 而不是 for 循环来屏蔽多列和/或扩展行
【发布时间】:2019-06-29 05:29:31
【问题描述】:

本质上是关于对数据表/帧使用位掩码/二进制列和面向行的操作:首先,从选定列的组合中构造一个逻辑向量,该列可用于屏蔽字符向量以表示“什么”列被标记。其次,行扩展——给定一列中的计数,生成一个数据表,其中包含复制该次数的原始行数据。

为了使用逐行位掩码总结标志,它使用 purrr:reduce 连接行表示的标志,我找不到在 %>% 链而不是单独的 for 循环中执行此操作的简洁方法。我怀疑 purrr::map 是必需的,但我无法正确理解它/语法。

对于行扩展,嵌套的 for 循环具有令人震惊的性能,我找不到 dplyr/purrr 逐行复制该行给定次数的方法。地图和其他功能需要生成和附加多行,我认为地图无法做到。

以下代码产生所需的输出 - 但是,除了性能问题(尤其是关于行扩展)之外,我希望能够将其作为矢量化操作来完成。

library(tidyverse)
library(data.table)
dt <- data.table(C1=c(0,0,1,0,1,0),
         C2=c(1,0,0,0,0,1),
         C3=c(0,1,0,0,1,0),
         C4=c(0,1,1,0,0,0),
         C5=c(0,0,0,0,1,1),
         N=c(5,2,6,8,1,3),
         Spurious = '')
flags <- c("Scratching Head","Screaming",
       "Breaking Keyboard","Coffee Break",
       "Giving up")

# Summarise states
flagSummary <- function(dt){
    interim <- dt %>%
            dplyr::mutate_at(vars(C1:C5),.funs=as.logical) %>%
    dplyr::mutate(States=c(""))

    for(i in 1:nrow(interim)){
        interim$States[i] <-
        flags[as.logical(interim[i,1:5])] %>%
        purrr::reduce(~ paste(.x, .y, sep = ","),.init="") %>%
        stringr::str_replace("^[,]","") }
      dplyr::select(interim,States,N) }

summary <- flagSummary(dt)
View(summary)

# Expand states
expandStates <- function(dt){
    interim <- dt %>%
    dplyr::mutate_at(vars(C1:C5), .funs=as.logical) %>%
    dplyr::select_at(vars(C1:C5,N)) %>%
    data.table::setnames(.,append(flags,"Count"))

    expansion <- interim[0,1:5]
    for(i in 1:nrow(interim)){
        for(j in 1:interim$Count[i]){
        expansion <- bind_rows(expansion, interim[i,1:5]) } }
      expansion }

expansion <- expandStates(dt)
View(expansion)

如上所述,代码产生了预期的结果。我“希望”在不诉诸 for 循环的情况下看到相同的结果,同时能够将函数链接到初始的 mutate/selects 中。

【问题讨论】:

    标签: r dplyr purrr collapse


    【解决方案1】:

    至于expandStates函数的行扩展,答案在这里Replicate each row of data.frame and specify the number of replications for each row?由A5C1D2H2I1M1N2O1R2T1提供。

    本质上,嵌套的for循环被替换为

    interim[rep(rownames(interim[,1:5]),interim$Count),][1:5]
    

    根据我的“实际”数据,这会将用户系统时间从 28.64 秒减少到 0.06 秒,从而产生大约 26000 行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-27
      • 2018-08-07
      • 2018-07-15
      • 1970-01-01
      • 2020-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多