跨行搜索r中的一系列值

时间:2018-10-12 12:05:34

标签: r

要解释这是一项复杂的任务,但是我试图逐行查看几列,以搜索连续出现FALSE的3个或更多模式,但前提是先于此TRUE的至少一个实例。

找到此模式的地方,我想添加一个新列date_lost,以显示发生这种情况的日期(日期取自列标题-我知道这不是最好的命名方式列,但这是设置数据框的方式)

一个简单的数据框可能如下所示:

library(tidyverse)

df <- 
  tribble(
    ~id, ~`01/01/18`, ~`02/01/18`, ~`03/01/18`, ~`04/01/18`, ~`05/01/18`,
    1,        NA,        NA,      TRUE,      TRUE,     FALSE,
    2,      TRUE,      TRUE,     FALSE,     FALSE,     FALSE,
    3,      TRUE,     FALSE,     FALSE,     FALSE,      TRUE,
    4,     FALSE,      TRUE,     FALSE,      TRUE,     FALSE,
    5,      TRUE,     FALSE,     FALSE,      TRUE,      TRUE,
    6,     FALSE,     FALSE,     FALSE,      TRUE,     FALSE,
    7, NA, NA, NA, NA, NA
  )

> df
# A tibble: 7 x 6
     id `01/01/18` `02/01/18` `03/01/18` `04/01/18` `05/01/18`
  <dbl> <lgl>      <lgl>      <lgl>      <lgl>      <lgl>     
1     1 NA         NA         TRUE       TRUE       FALSE     
2     2 TRUE       TRUE       FALSE      FALSE      FALSE     
3     3 TRUE       FALSE      FALSE      FALSE      TRUE      
4     4 FALSE      TRUE       FALSE      TRUE       FALSE     
5     5 TRUE       FALSE      FALSE      TRUE       TRUE      
6     6 FALSE      FALSE      FALSE      TRUE       FALSE     
7     7 NA         NA         NA         NA         NA     

该函数将标识在第二行和第三行中找到此模式,并在新列date_lost中添加日期(第二行添加05/01/18,第二行添加04/01/18 3)。如果找不到此模式,则其他行可能有NA,如下所示:

# A tibble: 7 x 7
     id `01/01/18` `02/01/18` `03/01/18` `04/01/18` `05/01/18` date_lost
  <dbl> <lgl>      <lgl>      <lgl>      <lgl>      <lgl>      <chr>    
1     1 NA         NA         TRUE       TRUE       FALSE      NA       
2     2 TRUE       TRUE       FALSE      FALSE      FALSE      05/01/18 
3     3 TRUE       FALSE      FALSE      FALSE      TRUE       04/01/18 
4     4 FALSE      TRUE       FALSE      TRUE       FALSE      NA       
5     5 TRUE       FALSE      FALSE      TRUE       TRUE       NA       
6     6 FALSE      FALSE      FALSE      TRUE       FALSE      NA       
7     7 NA         NA         NA         NA         NA         NA    

我确定可以在r中以一种优雅的方式完成此操作,但是我只是找不到这种方法。非常感谢您的帮助

3 个答案:

答案 0 :(得分:3)

这是一个解决方案,该方法使用一些重塑(使用列而不使用行)和一些分组以发现(3 +)连续的(1+)FALSE情况在他们之前为真。

library(tidyverse)
library(data.table)

df <- 
  tribble(
    ~id, ~`01/01/18`, ~`02/01/18`, ~`03/01/18`, ~`04/01/18`, ~`05/01/18`,
    1,        NA,        NA,      TRUE,      TRUE,     FALSE,
    2,      TRUE,      TRUE,     FALSE,     FALSE,     FALSE,
    3,      TRUE,     FALSE,     FALSE,     FALSE,      TRUE,
    4,     FALSE,      TRUE,     FALSE,      TRUE,     FALSE,
    5,      TRUE,     FALSE,     FALSE,      TRUE,      TRUE,
    6,     FALSE,     FALSE,     FALSE,      TRUE,     FALSE,
    7, NA, NA, NA, NA, NA
  )


df %>%
  gather(date, value, -id) %>%                      # reshape data
  arrange(id) %>%                                   # arrange data by id
  group_by(id2 = rleid(id, value)) %>%              # create a new grouping (to spot consequtive FALSE cases)
  mutate(value = ifelse(is.na(as.character(value)), 
                        ".", 
                        as.character(value)),       # update value variable (NAs will break the grouping, so we replace them with ".")
         false_in_row = sum(value == "FALSE")) %>%  # count how many FALSE in a row
  group_by(id) %>%                                  # group by id column
  mutate(flag = cumsum(value == "TRUE")) %>%        # create a flag to spot if you had TRUE before FALSE cases
  filter(flag >= 1 & false_in_row >= 3) %>%         # keep only conditions you specified
  summarise(date_lost = nth(date, 3)) %>%             # get date the matches your conditions
  right_join(df, by="id")                           # join original dataset

# # A tibble: 7 x 7
#      id date_lost `01/01/18` `02/01/18` `03/01/18` `04/01/18` `05/01/18`
#   <dbl> <chr>     <lgl>      <lgl>      <lgl>      <lgl>      <lgl>     
# 1     1 NA        NA         NA         TRUE       TRUE       FALSE     
# 2     2 05/01/18  TRUE       TRUE       FALSE      FALSE      FALSE     
# 3     3 04/01/18  TRUE       FALSE      FALSE      FALSE      TRUE      
# 4     4 NA        FALSE      TRUE       FALSE      TRUE       FALSE     
# 5     5 NA        TRUE       FALSE      FALSE      TRUE       TRUE      
# 6     6 NA        FALSE      FALSE      FALSE      TRUE       FALSE     
# 7     7 NA        NA         NA         NA         NA         NA 

答案 1 :(得分:1)

使用tidyversedata.tablezoo的另一种方法:

df %>%
  gather(var, val, -c(1)) %>%
  arrange(id) %>%
  group_by(temp1 = rleid(val)) %>%
  mutate(temp2 = seq_along(temp1)) %>%
  ungroup %>%
  group_by(id) %>%
  mutate(date_lost = ifelse(lag(val, 3) == TRUE & val == FALSE & temp2 == 3, var, NA)) %>%
  summarise(date_lost = ifelse(all(is.na(date_lost)) == TRUE, NA_character_, na.locf(date_lost))) %>%
  right_join(df, by = "id")

答案 2 :(得分:1)

这是使用rle的基本R解决方案:

rle_mat <- t(apply(df[-1],1,function(x) sequence(rle(x)$length))) *!df[-1]
df$date_lost <- apply(rle_mat,1,function(x) {
  which_3 <-which(x==3)[1]
  cond    <- which_3 > which(x==0)[1]
  if(isTRUE(cond[[1]])) names(x)[which_3] else NA
})
df
# # A tibble: 7 x 7
#      id `01/01/18` `02/01/18` `03/01/18` `04/01/18` `05/01/18` date_lost
#   <dbl> <lgl>      <lgl>      <lgl>      <lgl>      <lgl>      <chr>    
# 1     1 NA         NA         TRUE       TRUE       FALSE      <NA>     
# 2     2 TRUE       TRUE       FALSE      FALSE      FALSE      05/01/18 
# 3     3 TRUE       FALSE      FALSE      FALSE      TRUE       04/01/18 
# 4     4 FALSE      TRUE       FALSE      TRUE       FALSE      <NA>     
# 5     5 TRUE       FALSE      FALSE      TRUE       TRUE       <NA>     
# 6     6 FALSE      FALSE      FALSE      TRUE       FALSE      <NA>     
# 7     7 NA         NA         NA         NA         NA         <NA>     

x在第一次出现FALSE时达到3,但必须首先为TRUE,并且TRUErle_mat的值为0,因此第二次通话中的不平等。