【问题标题】:Find the latest sequence of TRUEs with length equal or greater than n查找长度等于或大于 n 的最新 TRUE 序列
【发布时间】:2018-09-12 13:15:02
【问题描述】:

我有如下数据:

library(dplyr)
ex <- data.frame(bool = c(rep(FALSE, 2), rep(TRUE, 3), rep(FALSE, 2), rep(TRUE, 5), 
                      FALSE, FALSE, rep(TRUE, 6), FALSE, FALSE, FALSE)) %>%
  mutate(seq = data.table::rleid(bool)) %>% 
  group_by(seq) %>% 
  mutate(n = n()) %>% 
  ungroup() %>% 
  mutate(expected_output = c(4, 4, NA, NA, NA, 4, 4, rep(NA,5), 4, 4, rep(NA, 6), rep(6, 3)))

对于每个FALSE,我需要找到长度至少为4TRUE 的最新序列。但是如果之前没有这样的序列(比如行1:26:7),我们应该向前检查,即找到观察后出现的第一个长度为4或更多的序列。

ex 的最后一列包含预期的输出。我该怎么做(最好使用tidyverse)?

编辑

仍然非常感谢使用tidyverse 的解决方案。

【问题讨论】:

  • 如果没有直接前后的序列。你应该先看哪里?在前面或后面。最近的?如果 font 和 behind 是相同的 dist appart 怎么办?
  • expected_output 列中的 4 和 6 指的是什么?
  • @denis,来自seq 列的序列号
  • 10:11 旁边应该是什么? 45 ??? data.frame(bool = c(rep(TRUE, 4), rep(FALSE, 2), rep(TRUE, 3), rep(FALSE, 2), rep(TRUE, 5), FALSE, FALSE, rep(TRUE, 6), FALSE, FALSE, FALSE))
  • @jakes。我和 Aarons 的解决方案适用于新数据。你哪里有问题?错误/错误结果是什么?

标签: r dplyr tidyverse


【解决方案1】:

以下内容应该使用 base R.

function(col,min_seq =4)
{
    end = c(which(c(col[-1],NA)!=col),length(col))   
    num = diff(c(0,end))     
    start = end-num+1 
    seq_n = seq_along(start) 
    v=col[end]

    accept = num >= min_seq & v
    st = start[accept]
    sn = seq_n[accept]
    en = end[accept]
    en_ = en
    en_[1]=1
    place = rep(sn, diff(c(en_,length(col) + 1 )))      # If row with start of sequence is wanted instead of sequence number sn can be replaced with st
    place[col]=NA

    return(place)
}

【讨论】:

  • 您的解决方案似乎没有设置 seq 的最后一个值。
  • @Andre Elrico,我已经修好了。谢谢你让我知道,我真的应该检查一下。
  • 您的解决方案也启发了我采用函数方法。我认为您的解决方案非常好!它还“正确”处理了我所有的边境案件!
  • 您的解决方案看起来很简洁,但我很难理解 - 您能否评论一下您的步骤? endstart 的目标是什么?
  • @jakes 请逐行运行代码。对不清楚的地方提出具体问题。如果解决了您的问题,请将解决方案标记为答案。随意通过点赞您喜欢的答案来表示赞同。
【解决方案2】:

你可以这样做:

定义函数:(健壮且具有错误处理功能)

fun1<-
function(vec, min_rep = 4) {

    stopifnot(length(vec)>0, all(vec %in% 0:1))

    runL <- do.call(rbind,rle(vec))
    lngth<- ncol(runL)
    runL <- rbind(runL, seq = 1:lngth, seq2 = NA^runL[2,])

    runL[3,] <- ifelse(!runL[2,]|runL[1,]<min_rep, NA, runL[3,]) 

    cases <- na.omit(runL[3,])

    if(length(cases)>0) {

        for(i in rev(cases)) {
            runL[4,1:i][!is.na(runL[4,1:i])] <- i
        }

        for(i in cases) {
            runL[4,i:lngth][!is.na(runL[4,i:lngth])] <- i
        }
    } else { runL[4,] <- NA }

    return(rep(runL[4,],runL[1,]))
}

调用函数:

vec = c(rep(FALSE, 2), rep(TRUE, 3), rep(FALSE, 2), rep(TRUE, 5), 
        FALSE, FALSE, rep(TRUE, 6), FALSE, FALSE, FALSE)
cbind(vec,fun1(vec))

vec = rep(T,5)
cbind(vec,fun1(vec))

vec = rep(F,5)
cbind(vec,fun1(vec))

vec = c(rep(F,5),T)
cbind(vec,fun1(vec))

vec = c()
cbind(vec,fun1(vec))

vec = 1:3
cbind(vec,fun1(vec))

【讨论】:

    【解决方案3】:

    如果 OP 严格不想要 data.table 解决方案,我可以删除这篇文章。

    这是一种可能的data.table 方法:

    #aggregate the dataset by bool and rleid
    agg <- DT[, .(rn=.GRP, N=.N), by=.(bool, seq=rleid(bool))]
    
    #extract all the TRUE sequences with length >= 4
    true4s <- agg[(bool) & N >= 4L]
    
        #for rows that are FALSE
    agg[(!bool), expOut := {
            prev <- NA
    
            #find the previous sequence of TRUEs by using data.table non-equi join 
            #(a rolling join will work too here)
            #in addition, do the match in reverse so that we can fill NA with prev value
            ans <- true4s[.SD[order(-rn)], {
                if (.N > 0L) {
                    prev <- seq[.N] 
                } 
                prev
                  #for each row in i (see ?data.table for i argument and also ?.EACHI)
                              #non equi join where earlier row in x to be join with later row in i 
            }, by=.EACHI, on=.(rn<rn)]$V1
    
            #for the rolling version
            #}, by=.EACHI, on=.(rn), roll=Inf]$V1
    
            rev(ans)
        }]
    
    #add expected output to original dataset
    DT[, expected_output := inverse.rle(list(values=agg$expOut, lengths=agg$N))]
    

    输出:

         bool expected_output
     1: FALSE               4
     2: FALSE               4
     3:  TRUE              NA
     4:  TRUE              NA
     5:  TRUE              NA
     6: FALSE               4
     7: FALSE               4
     8:  TRUE              NA
     9:  TRUE              NA
    10:  TRUE              NA
    11:  TRUE              NA
    12:  TRUE              NA
    13: FALSE               4
    14: FALSE               4
    15:  TRUE              NA
    16:  TRUE              NA
    17:  TRUE              NA
    18:  TRUE              NA
    19:  TRUE              NA
    20:  TRUE              NA
    21: FALSE               6
    22: FALSE               6
    23: FALSE               6
         bool expected_output
    

    数据:

    library(data.table)
    DT <- data.table(bool = c(rep(FALSE, 2), rep(TRUE, 3), rep(FALSE, 2), rep(TRUE, 5), 
        FALSE, FALSE, rep(TRUE, 6), FALSE, FALSE, FALSE)) 
    

    【讨论】:

    • 感谢您的努力!并不是我不想 data.table 解决方案,我只是对 data.table 语法一无所知,我需要一个我能够理解的解决方案。但我认为它应该留给任何会从搜索中听到的人。
    猜你喜欢
    • 2022-01-23
    • 2011-09-03
    • 2021-06-09
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多