Membuat kolom baru secara kondisional berdasarkan pada n baris sebelumnya


9

Saya memiliki kerangka data yang diatur seperti berikut:

 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

Saya pada dasarnya mencoba membuat bendera biner lokasi di Encounter sebelumnya untuk setiap grup id. Jadi akan terlihat seperti:

    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

Saya mencoba mencari cara untuk melakukan pernyataan if seperti:

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

Tapi ini memiliki masalah di mana Baris 9 mendapatkan salah ditempatkan 1, dan ada kasus dengan 15+ pertemuan dalam data aktual sehingga ini menjadi cukup rumit. Saya berharap menemukan cara untuk melakukan sesuatu seperti

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

Tapi saya tahu lag()perlu integer untuk k, sehingga perintah tertentu tidak akan berfungsi.


Selamat Datang di Stack Overflow! Hanya karena Anda meminta wawasan tentang rutinitas SO, Anda mungkin ingin membaca ini tentang apa yang harus dilakukan ketika seseorang menjawab pertanyaan Anda . Selain itu, bukan ide yang buruk untuk mengikuti tur dan membaca Bagaimana cara bertanya (pertanyaan Anda bagus, tetapi itu akan memberi Anda lencana). Berharap untuk melihat Anda di sini, lebih sering. Bersulang.
M

Jawaban:


6

Opsi dengan 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

Di basis R, kita bisa menggunakan yang avedikelompokkan oleh iddan Locationdan mengubah semua nilai dari baris kedua grup ke 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

Menggunakan dplyr, itu akan menjadi

library(dplyr)

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

4

Menggunakan data.table:

library(data.table)

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

Data:

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

Solusi yang lebih umum data.tableakan menggunakan .Natau rowid:

library(data.table)

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

atau

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

Anda juga dapat menggunakan ini:

library(data.table)
setDT(df)[,flag:=ifelse(1:.N>1,1,0),by=.(id,Location)] 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.