Création conditionnelle d'une nouvelle colonne sur la base des n lignes précédentes

9

J'ai une trame de données configurée comme suit:

 df <- data.frame("id" = c(111,111,111,222,222,222,222,333,333,333,333), 
                  "Location" = c("A","B","A","A","C","B","A","B","A","A","A"), 
                  "Encounter" = c(1,2,3,1,2,3,4,1,2,3,4))

      id Location Encounter
1  111        A         1
2  111        B         2
3  111        A         3
4  222        A         1
5  222        C         2
6  222        B         3
7  222        A         4
8  333        B         1
9  333        A         2
10 333        B         3
11 333        A         4

J'essaie essentiellement de créer un indicateur binaire, un emplacement est dans une rencontre précédente pour chaque groupe d'ID. Cela ressemblerait donc à:

    id Location Encounter Flag
1  111        A         1    0
2  111        B         2    0
3  111        A         3    1
4  222        A         1    0
5  222        C         2    0
6  222        B         3    0
7  222        A         4    1
8  333        B         1    0
9  333        A         2    0
10 333        B         3    1
11 333        A         4    1

J'essayais de comprendre comment faire une instruction if comme:

library(dplyr)

df$Flag <- case_when((df$id - lag(df$id)) == 0 ~ 
                case_when(df$Location == lag(df$Location, 1) | 
                          df$Location == lag(df$Location, 2) | 
                          df$Location == lag(df$Location, 3) ~ 1, T ~ 0), T ~ 0)

    id Location Flag
1  111        A    0
2  111        B    0
3  111        A    1
4  222        A    0
5  222        C    0
6  222        B    0
7  222        A    1
8  333        B    0
9  333        A    1
10 333        B    1
11 333        A    1

Mais cela a le problème où la ligne 9 obtient un 1 incorrectement attribué, et il y a des cas avec plus de 15 rencontres dans les données réelles, donc cela devient assez lourd. J'espérais trouver un moyen de faire quelque chose comme

lag(df$Location, 1:df$Encounter)

Mais je sais qu'il a lag()besoin d'un entier pour k, afin que cette commande spécifique ne fonctionne pas.

Dalton K
la source
Bienvenue dans Stack Overflow! Tout simplement parce que vous avez demandé des informations sur les routines SO, vous voudrez peut-être lire ceci sur ce qu'il faut faire lorsque quelqu'un répond à votre question . En plus de cela, ce n'est pas une mauvaise idée de faire le tour et de lire Comment demander (votre question est excellente, mais elle vous donnera un badge). Au plaisir de vous voir ici, plus souvent. À votre santé.
M--

Réponses:

6

Une option avec duplicated

library(dplyr)
df %>% 
  group_by(id) %>% 
  mutate(Flag = +(duplicated(Location)))
# A tibble: 11 x 4
# Groups:   id [3]
#      id Location Encounter  Flag
#   <dbl> <fct>        <dbl> <int>
# 1   111 A                1     0
# 2   111 B                2     0
# 3   111 A                3     1
# 4   222 A                1     0
# 5   222 C                2     0
# 6   222 B                3     0
# 7   222 A                4     1
# 8   333 B                1     0
# 9   333 A                2     0
#10   333 A                3     1
#11   333 A                4     1
akrun
la source
4

Dans la base R, nous pouvons utiliser avegroupé par idet Locationet tourner toutes les valeurs de la deuxième ligne du groupe à 1.

df$Flag <- as.integer(with(df, ave(Encounter, id, Location, FUN = seq_along) > 1))
df

#    id Location Encounter Flag
#1  111        A         1    0
#2  111        B         2    0
#3  111        A         3    1
#4  222        A         1    0
#5  222        C         2    0
#6  222        B         3    0
#7  222        A         4    1
#8  333        B         1    0
#9  333        A         2    0
#10 333        A         3    1
#11 333        A         4    1

En utilisant dplyr, ce serait

library(dplyr)

df %>%  group_by(id, Location) %>%  mutate(Flag = as.integer(row_number() > 1))
Ronak Shah
la source
4

En utilisant data.table:

library(data.table)

dt[, flag:=1]
dt[, flag:=cumsum(flag), by=.(id,Location)]
dt[, flag:=ifelse(flag>1,1,0)]

Les données:

dt <- data.table("id" = c(111,111,111,222,222,222,222,333,333,333,333), 
                 "Location" = c("A","B","A","A","C","B","A","B","A","A","A"),
                 "Encounter" = c(1,2,3,1,2,3,4,1,2,3,4))
LocoGris
la source
4

Une data.tablesolution plus générique utiliserait .Nou rowid:

library(data.table)

setDT(dt)[, Flag := +(rowid(id, Location)>1)][]

ou

setDT(df)[, Flag := +(seq_len(.N)>1), .(id, Location)][]
#>      id Location  Encounter Flag
#> 1:  111        A         1    0
#> 2:  111        B         2    0
#> 3:  111        A         3    1
#> 4:  222        A         1    0
#> 5:  222        C         2    0
#> 6:  222        B         3    0
#> 7:  222        A         4    1
#> 8:  333        B         1    0
#> 9:  333        A         2    0
#> 10: 333        A         3    1
#> 11: 333        A         4    1
M--
la source
0

Vous pouvez également utiliser ceci:

library(data.table)
setDT(df)[,flag:=ifelse(1:.N>1,1,0),by=.(id,Location)] 
Rushabh Patel
la source