Creazione di una nuova colonna in modo condizionale basata su n righe precedenti


9

Ho un frame di dati impostato come il seguente:

 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

Sto fondamentalmente cercando di creare un flag binario, una posizione è in un incontro precedente per ogni gruppo di ID. Quindi sembrerebbe:

    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

Stavo cercando di capire come fare un'istruzione if come:

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

Ma questo ha il problema per cui a Row 9 viene assegnato erroneamente un 1 e ci sono casi con oltre 15 incontri nei dati effettivi, quindi questo diventa piuttosto ingombrante. Speravo di trovare un modo per fare qualcosa del genere

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

Ma so che ha lag()bisogno di un numero intero per k, quindi quel comando specifico non funzionerebbe.


Benvenuto in Stack Overflow! Solo perché hai chiesto approfondimenti sulle routine SO, potresti voler leggere questo su cosa fare quando qualcuno risponde alla tua domanda . Oltre a ciò, non è una cattiva idea fare il tour e leggere Come chiedere (la tua domanda è fantastica, ma ti darà un badge). Spero di vederti da queste parti, più spesso. Saluti.
M--

Risposte:


6

Un'opzione con 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

4

Nella base R, possiamo usare averaggruppati per ide Locatione trasformare tutti i valori dalla seconda riga del gruppo su 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

Usando dplyr, sarebbe

library(dplyr)

df %>%  group_by(id, Location) %>%  mutate(Flag = as.integer(row_number() > 1))

4

Utilizzando data.table:

library(data.table)

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

Dati:

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))

4

Una data.tablesoluzione più generica sarebbe utilizzare .No rowid:

library(data.table)

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

o

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

0

Puoi anche usare questo:

library(data.table)
setDT(df)[,flag:=ifelse(1:.N>1,1,0),by=.(id,Location)] 
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.