要解释这是一项复杂的任务,但是我试图逐行查看几列,以搜索连续出现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
中以一种优雅的方式完成此操作,但是我只是找不到这种方法。非常感谢您的帮助
答案 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)
使用tidyverse
,data.table
和zoo
的另一种方法:
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
,并且TRUE
中rle_mat
的值为0,因此第二次通话中的不平等。