在R中的列向量中检测模式并对其进行子集

时间:2019-07-19 16:59:07

标签: r dplyr tidyverse

作为this post中问题的扩展,我希望在按> UserID分组的列向量中的值模式上标记实例和子集。模式为“ 0,1,0”。还有两个方面需要考虑:

1)如下面的示例数据所示,我需要应对NA值。 NA值是实质性的,需要保持。

2)在模式为0,1,0,1,0的情况下,我想将两个实例都计为0,1,0(即,允许中间的零在两个实例中都计数)。 / p>

我尝试了链接文章中提供的方法的变体。我无法解决的问题是,在这些实例中,一旦标记了UserID,它将在该UserID的其余观察中进行检查。我只想标记0,1,0的实例。

示例数据:

df <- data.frame(UserID = rep(c("A", "B", "C"), each = 9L),
                  Job = as.integer(c(NA,0,1,0,NA,1,0,1,0,
                                    1,0,1,0,1,0,NA,1,0,
                                    NA,0,1,NA,0,1,0,1,NA)))

使用的代码:

library(tidyverse)
df %>%
   group_by(UserID)%>%
   mutate(Pattern=str_count(accumulate(Job,str_c,collapse=""),"010"))

代码结果:

  UserID   Job Pattern
   <fct>  <int>   <int>
 1 A         NA      NA
 2 A          0      NA
 3 A          1      NA
 4 A          0      NA
 5 A         NA      NA
 6 A          1      NA
 7 A          0      NA
 8 A          1      NA
 9 A          0      NA
10 B          1       0
11 B          0       0
12 B          1       0
13 B          0       1
14 B          1       1
15 B          0       1
16 B         NA      NA
17 B          1      NA
18 B          0      NA
19 C         NA      NA
20 C          0      NA
21 C          1      NA
22 C         NA      NA
23 C          0      NA
24 C          1      NA
25 C          0      NA
26 C          1      NA
27 C         NA      NA

预期结果:

  UserID   Job   Pattern
   <fct>  <int>   <int>
 1 A         NA      0
 2 A          0      1
 3 A          1      1
 4 A          0      1
 5 A         NA      0
 6 A          1      0
 7 A          0      1
 8 A          1      1
 9 A          0      1
10 B          1      1
11 B          0      1
12 B          1      1
13 B          0      1
14 B          1      1
15 B          0      1
16 B         NA      0
17 B          1      0
18 B          0      0
19 C         NA      0
20 C          0      0
21 C          1      0
22 C         NA      0
23 C          0      1
24 C          1      1
25 C          0      1
26 C          1      0
27 C         NA      0

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:0)

这是一种解决方案。因为您的模式相对较短,所以我只是将其硬编码到条件语句中。

search_results <- data.frame(
  V1 = c(1881, 1457, 1907, 1442, 1433, 1402, 1968, 1785, 1992),
  V2 = c(1470, 1893, 1444, 1443, 1918, 1949, 1969, 1786, 1993),
  V3 = c(1880, 1894, 1906, 1908, 1432, 1401, 1967, 1784, 1991)
) %>%
  dplyr::mutate(
    ordered = reduce(., ~ifelse(.x >= lag(.x, default = 0), .x, .y))
  )

with(search_results, any(ordered < lag(ordered, default = 0)))
#> [1] TRUE

答案 1 :(得分:0)

这是另一种方法(效率不高),其中我用Job折叠了paste并使用正则表达式搜索模式。然后将其拆分为向量的元素:

library(dplyr)
library(stringr)

df %>%
  mutate(Pattern = paste(Job, collapse = '-') %>%
           str_replace_all('(0(?=-1-0)|(?<=0-)1(?=-0)|(?<=0-1-)0)', '2') %>%
           str_split(pattern = '-') %>% .[[1]] %>%
           {if_else(. == '2', 1, 0)})

使用基本R:

string <- paste(df$Job, collapse = '-')
pattern <- strsplit(gsub('(0(?=-1-0)|(?<=0-)1(?=-0)|(?<=0-1-)0)', '2', 
                         string, perl = TRUE), split = '-')[[1]]
df$Pattern <- ifelse(pattern == '2', 1, 0)

输出:

   UserID Job Pattern
1       A  NA       0
2       A   0       1
3       A   1       1
4       A   0       1
5       A  NA       0
6       A   1       0
7       A   0       1
8       A   1       1
9       A   0       1
10      B   1       1
11      B   0       1
12      B   1       1
13      B   0       1
14      B   1       1
15      B   0       1
16      B  NA       0
17      B   1       0
18      B   0       0
19      C  NA       0
20      C   0       0
21      C   1       0
22      C  NA       0
23      C   0       1
24      C   1       1
25      C   0       1
26      C   1       0
27      C  NA       0