【问题标题】:Subset data based on sequence of characters across rows基于跨行字符序列的子集数据
【发布时间】:2018-08-17 17:46:13
【问题描述】:

如何通过连续字符行的模式对 df 进行子集化?在下面的示例中,我想对历史值连续为“TRUE”、“FALSE”、“TRUE”的数据进行子集化。下面的数据有点奇怪,但你明白了!

value <- c(1/1/16,1/2/16, 1/3/16, 1/4/16, 1/5/16, 1/6/16, 1/7/16, 1/8/16, 1/9/16, 1/10/16)

history <- c("TRUE", "FALSE", "TRUE", "TRUE", "FALSE", "TRUE", "TRUE", "TRUE", "FALSE", "TRUE")

df <- data.frame(value, history)
df

         value history  
1  0.062500000    TRUE  
2  0.031250000   FALSE  
3  0.020833333    TRUE  
4  0.015625000    TRUE  
5  0.012500000   FALSE  
6  0.010416667    TRUE  
7  0.008928571    TRUE  
8  0.007812500    TRUE  
9  0.006944444   FALSE  
10 0.006250000    TRUE  

我已经尝试过grepl,但这适用于字符串 - 而不是跨行连续的字符序列。

输出将与上面的 df 相同,但没有第 7 行,因为这不符合上述模式。

【问题讨论】:

    标签: r


    【解决方案1】:

    你可以...

    s = c("TRUE", "FALSE", "TRUE")
    
    library(data.table)
    w = as.data.table(embed(history, length(s)))[as.list(s), on=paste0("V", seq_along(s)), which=TRUE]
    
    df$v <- FALSE
    df$v[w + rep(seq_along(s)-1L, each=length(s))] <- TRUE
    
             value history     v
    1  0.062500000    TRUE  TRUE
    2  0.031250000   FALSE  TRUE
    3  0.020833333    TRUE  TRUE
    4  0.015625000    TRUE  TRUE
    5  0.012500000   FALSE  TRUE
    6  0.010416667    TRUE  TRUE
    7  0.008928571    TRUE FALSE
    8  0.007812500    TRUE  TRUE
    9  0.006944444   FALSE  TRUE
    10 0.006250000    TRUE  TRUE
    

    然后您可以像subset(df, v == TRUE) 一样过滤。


    这使用 data.table 连接,x[i, which=TRUE]x = embed(history, length(s)) 中查找 i = as.list(s) 并报告 x 的哪些行匹配:

    > as.data.table(as.list(s))
         V1    V2   V3
    1: TRUE FALSE TRUE
    
    > as.data.table(embed(history, length(s)))
          V1    V2    V3
    1:  TRUE FALSE  TRUE
    2:  TRUE  TRUE FALSE
    3: FALSE  TRUE  TRUE
    4:  TRUE FALSE  TRUE
    5:  TRUE  TRUE FALSE
    6:  TRUE  TRUE  TRUE
    7: FALSE  TRUE  TRUE
    8:  TRUE FALSE  TRUE
    

    w + rep(...) 与@GGrothendieck 的outer(...) 相同,只是这里的w 包含比赛开始的位置,而不是结束的位置。

    【讨论】:

    • embed 的不错选择
    【解决方案2】:

    问题中的数据看起来很奇怪,所以我们使用了最后 Note 中的数据。如果您确实有一个值为“TRUE”和“FALSE”的字符向量或因子,则可以使用以下方法轻松地将其转换为逻辑:

    df <- transform(df, history = history == "TRUE")
    

    1) rollapply 首先定义模式,然后使用带有rollapplyr 的移动窗口搜索它。这给出了一个逻辑向量,如果它是这种模式匹配的结尾,则该向量为 TRUE。找到 TRUE 的索引并包括前两个索引。最后执行子集。

    library(zoo)
    
    pattern <- c(TRUE, FALSE, TRUE)
    ix <- which(rollapplyr(df$history, length(pattern), identical, pattern, fill = FALSE))
    ix <- unique(sort(c(outer(ix, seq_along(pattern) - 1L, "-"))))
    df[ix, ]
    

    给予:

             value history
    1  0.062500000    TRUE
    2  0.031250000   FALSE
    3  0.020833333    TRUE
    4  0.015625000    TRUE
    5  0.012500000   FALSE
    6  0.010416667    TRUE
    8  0.007812500    TRUE
    9  0.006944444   FALSE
    10 0.006250000    TRUE
    

    1a) magrittr (1)中的这段代码可以用 magrittr 来表示。 (解决方案(2)也可以按照类似的想法使用 magrittr 来表达。)

    library(magrittr)
    library(zoo)
    
    df %>%
      extract(
       extract(.,, "history") %>%
       rollapplyr(length(pattern), identical, pattern, fill = FALSE) %>%
       which %>%
       outer(seq_along(pattern) - 1L, "-") %>%
       sort %>%
       unique, )
    

    2) gregexpr 使用上面定义的pattern,我们将其转换为0 和1 的字符串,并将df$history 转换为这样的字符串。然后我们可以使用 gregexpr 查找每个匹配项的第一个元素的索引,然后将其扩展到所有索引和子集。我们得到和以前一样的答案。此替代方案不使用任何包。

    collapse <- function(x) paste0(x + 0, collapse = "")
    ix <- gregexpr(collapse(pattern), collapse(df$history))[[1]]
    ix <- unique(sort(c(outer(ix, seq_along(pattern) - 1L, "+"))))
    df[ix, ]
    

    注意

    Lines <- "
             value history  
    1  0.062500000    TRUE  
    2  0.031250000   FALSE  
    3  0.020833333    TRUE  
    4  0.015625000    TRUE  
    5  0.012500000   FALSE  
    6  0.010416667    TRUE  
    7  0.008928571    TRUE  
    8  0.007812500    TRUE  
    9  0.006944444   FALSE  
    10 0.006250000    TRUE"
    df <- read.table(text = Lines)
    

    【讨论】:

      【解决方案3】:

      使用延迟的选项:

          df <- data.frame(value, history)
      
          n<- grepl("TRUE, FALSE, TRUE", paste(lag(lag(history)), (lag(history)), history, sep = ", "))[-(1:2)]
      
          cond <- n |lag(n)|lag(lag(n)) 
          cond <- c(cond, cond[length(history)-2], cond[length(history)-2])
          df[cond, ]
      

      【讨论】:

      • 如果使用基本 R 的 lag,则给出 0 行,但如果我们添加 library(dplyr),它将起作用。
      猜你喜欢
      • 2020-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-30
      • 2022-08-18
      • 2018-09-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多