仅标记列值第一次按 R 中的 id 按行更改

Flag only the first time a column value changes rowwise per id in R

我开门见山。我在 Whosebug 上找到了一些部分有效的代码。

df1 <- read.table(text = "
ID  V1    V2
A   X     SBI123
A   Y     SBI123
A   Y     SBI133
B   A     SBI888
B   A     SBI999
B   B     SBI999
", header = TRUE)

# Rowwise comparison per column
setDT(df1)[, flag_V1 := 0][V1!="", flag_V1 := 1*(rleid(V1)-1 > 0), by = ID]
setDT(df1)[, flag_V2 := 0][V2!="", flag_V2 := 1*(rleid(V2)-1 > 0), by = ID]
df1

# Output
   ID V1     V2 flag_V1 flag_V2
1:  A  X SBI123       0       0
2:  A  Y SBI123       1       0
3:  A  Y SBI133       1       1
4:  B  A SBI888       0       0
5:  B  A SBI999       0       1
6:  B  B SBI999       1       1

因此 ID 'A' 的 V1 值第一次更改时 'flag_V1' 是 1,这是正确的。我想要的是第三行为 0。我知道代码将所有列值与第一行进行比较,这使得该代码正确,但我只希望第一次标记值更改。 期望的输出:

# Desired output
   ID V1     V2 flag_V1 flag_V2
1:  A  X SBI123       0       0
2:  A  Y SBI123       1       0
3:  A  Y SBI133       0       1
4:  B  A SBI888       0       0
5:  B  A SBI999       0       1
6:  B  B SBI999       1       0

dplyr中,您可以使用acrosslag。基本上,当前一个值与实际值不同时,该值为 1,否则为 0。

library(dplyr)

df1 %>% 
  group_by(ID) %>% 
  mutate(across(V1:V2, ~ +(lag(.x, default = first(.x)) != .x), .names = "flag_{col}"))

# A tibble: 6 × 5
# Groups:   ID [2]
  ID    V1    V2     flag_V1 flag_V2
  <chr> <chr> <chr>    <int>   <int>
1 A     X     SBI123       0       0
2 A     Y     SBI123       1       0
3 A     Y     SBI133       0       1
4 B     A     SBI888       0       0
5 B     A     SBI999       0       1
6 B     B     SBI999       1       0

您可以将重复项转换为 0,即 V1

library(data.table)

setDT(df1)[, flag_V1 := 0][
           V1!="", flag_V1 := 1*(rleid(V1)-1 > 0), by = ID][, 
                   lapply(.SD, function(i) replace(i, duplicated(i), 0)), by = .(ID, V1)][]

   ID V1     V2 flag_V1
1:  A  X SBI123       0
2:  A  Y SBI123       1
3:  A  Y SBI133       0
4:  B  A SBI888       0
5:  B  A SBI999       0
6:  B  B SBI999       1