Erstellen einer neuen Spalte unter bestimmten Bedingungen basierend auf den vorherigen n Zeilen

9

Ich habe einen Datenrahmen wie folgt eingerichtet:

 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

Ich versuche im Grunde, ein binäres Flag zu erstellen, in dem sich ein Ort in einer vorherigen Begegnung für jede ID-Gruppe befindet. So würde es aussehen:

    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

Ich habe versucht herauszufinden, wie man eine if-Anweisung wie folgt macht:

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

Dies hat jedoch das Problem, dass Zeile 9 fälschlicherweise eine 1 zugewiesen wird, und es gibt Fälle mit mehr als 15 Begegnungen in den tatsächlichen Daten, sodass dies ziemlich umständlich wird. Ich hatte gehofft, einen Weg zu finden, so etwas zu tun

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

Aber ich weiß lag(), dass eine ganze Zahl für k benötigt wird, damit ein bestimmter Befehl nicht funktioniert.

Dalton K.
quelle
Willkommen bei Stack Overflow! Nur weil Sie nach Erkenntnissen über SO-Routinen gefragt haben, möchten Sie möglicherweise lesen, was zu tun ist, wenn jemand Ihre Frage beantwortet . Abgesehen davon ist es keine schlechte Idee, an der Tour teilzunehmen und zu lesen, wie man fragt (Ihre Frage ist großartig, aber Sie erhalten ein Abzeichen). Ich hoffe, wir sehen uns öfter hier. Prost.
M--

Antworten:

6

Eine Option mit 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
quelle
4

In Basis R können wir avegruppiert nach idund verwenden Locationund alle Werte aus der zweiten Zeile der Gruppe auf 1 setzen.

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

Mit dplyrwäre das

library(dplyr)

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

Verwenden von data.table:

library(data.table)

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

Daten:

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
quelle
4

Eine allgemeinere data.tableLösung wäre .Noder rowid:

library(data.table)

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

oder

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--
quelle
0

Sie können dies auch verwenden:

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