Выберите строки в кадре данных на основе шаблона, образованного последовательными значениями в столбце - PullRequest
0 голосов
/ 18 февраля 2019

Я в среднем на R, и мне нужна помощь со следующей операцией.

Допустим, у меня есть следующий фрейм данных:

    >df
    ID   Label
    P1   M
    P1   S
    P2   M
    P2   M
    P2   S
    P3   M
    P3   S
    P3   M
    P4   S
    P4   M
    P5   M
    P5   M
    P5   S

Я хочу иметь возможностьвыберите строки, которые встречаются в определенной последовательности переменной Label относительно каждого идентификатора.

Для шаблона "MS" ожидаемый результат будет

    ID   Label
    P1   M
    P1   S
    P2   M
    P2   S
    P3   M
    P3   S

и дляшаблон "MMS", ожидаемый результат будет

    ID   Label
    P2   M
    P2   M
    P2   S
    P5   M
    P5   M
    P5   S

, а для шаблона "SM" ожидаемый результат:

    ID   Label
    P3   S
    P3   M
    P4   S
    P4   M

Пожалуйста, примите во внимание тот факт, что данные, с которыми я работаюУ on есть много строк, и решение, которое мне нужно построить, должно работать для шаблонов произвольной длины.(напр. "MSS", "SM", "MMSSMS" и т. д.).Я скромно прошу вашей помощи.

Редактировать: я обновил этот вопрос (пример кадра данных и пример вывода шаблона "MMS". Я хочу добавить, что я хочу, чтобы сопоставление с шаблоном происходило после группировки данныхиспользуя переменную ID, чтобы шаблоны можно было найти в группах данных, сгруппированных по ID. Извините, что не удалось очистить в первый раз.

Окончательное редактирование: ответы от @akrun, @boski и @У меня работают tmfmnk. Решения @ boski и @ akrun были быстрее по времени выполнения (~ 2-10 секунд на 400k строк данных) по сравнению с решением @ tmfmnk (~ 29 секунд на 400k строк данных). Я советую читателю:см. все три из этих решений.

Ответы [ 3 ]

0 голосов
/ 18 февраля 2019

Вы можете попробовать использовать gregexpr().Сначала вставьте все метки и найдите начальную позицию искомого шаблона.

> df
   ID Label
1  P1     M
2  P1     S
3  P2     M
4  P2     M
5  P2     S
6  P3     M
7  P3     S
8  P3     S
9  P4     S
10 P4     M
11 P5     M
12 P5     M
13 P5     S

Редактировать

В моем предыдущем решении не удалось получить весь шаблон (простоначало).

pattern="SM"
starts=gregexpr(pattern=pattern,paste(df$Label,collapse=""))[[1]]
positions=as.vector(sapply(starts,function(x){ 
  s=seq(x,x+nchar(pattern)-1)
  if (all(df$ID[s]==df$ID[x])){
    return(s)
  } else {return(rep(NA,nchar(pattern)))}
  }))
positions=positions[which(!is.na(positions))]

df[positions,]
df[positions,]
   ID Label
1  P1     M
2  P1     S
4  P2     M
5  P2     S
6  P3     M
7  P3     S
12 P5     M
13 P5     S

pattern="MMS"
   ID Label
3  P2     M
4  P2     M
5  P2     S
11 P5     M
12 P5     M
13 P5     S

pattern="SM"
   ID Label
9  P4     S
10 P4     M
0 голосов
/ 18 февраля 2019

Одно базовое решение для исходного вопроса может быть:

nchar <- nchar("MS")
x <- grepRaw("MS", paste(df$Label, collapse = ""), all = TRUE)
y <- rep(x, each = nchar) + 0:(nchar - 1)

df[1:nrow(df) %in% y, ]

  ID Label
1 P1     M
2 P1     S
4 P2     M
5 P2     S
6 P3     M
7 P3     S

nchar <- nchar("SM")
x <- grepRaw("SM", paste(df$Label, collapse = ""), all = TRUE)
y <- rep(x, each = nchar) + 0:(nchar - 1)

df[1:nrow(df) %in% y, ]

   ID Label
2  P1     S
3  P2     M
5  P2     S
6  P3     M
9  P4     S
10 P4     M

Или записано в форме dplyr:

nchar <- nchar("MS")
df %>%
 filter(row_number() %in% c(rep(grepRaw("MS", paste(Label, collapse = ""), all = TRUE), 
            each = nchar) + 0:(nchar - 1)))

   ID Label
1  P1     M
2  P1     S
3  P2     M
4  P2     S
5  P3     M
6  P3     S
7  P3     M
8  P4     S
9  P5     M
10 P5     S

Также обращаясь к редактированию вопроса:

nchar <- nchar("MS")
df %>%
 group_by(ID) %>%
 filter(row_number() %in% c(rep(grepRaw("MS", paste(Label, collapse = ""), all = TRUE), 
            each = nchar) + 0:(nchar - 1)))

  ID    Label
  <fct> <fct>
1 P1    M    
2 P1    S    
3 P2    M    
4 P2    S    
5 P3    M    
6 P3    S    
7 P5    M    
8 P5    S  
0 голосов
/ 18 февраля 2019

Одним из вариантов будет сравнение значений lead и получение индекса, сгруппированного по 'ID'

library(data.table)
i1 <- unique(setDT(df)[, lapply(which(Reduce(`&`, 
  Map(`==`, shift(Label, n = 0:2, type = "lead"), c("M", "M", "S")))), 
       function(i) .I[i:(i+2)]) , by = ID]$V1)
df[i1]
#    ID Label
#1: P2     M
#2: P2     M
#3: P2     S
#4: P5     M
#5: P5     M
#6: P5     S

data

df <- structure(list(ID = c("P1", "P1", "P2", "P2", "P2", "P3", "P3", 
"P3", "P4", "P4", "P5", "P5", "P5"), Label = c("M", "S", "M", 
"M", "S", "M", "S", "M", "S", "M", "M", "M", "S")), 
class = "data.frame", row.names = c(NA, -13L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...