仅标记列值第一次按 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
中,您可以使用across
和lag
。基本上,当前一个值与实际值不同时,该值为 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
我开门见山。我在 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
中,您可以使用across
和lag
。基本上,当前一个值与实际值不同时,该值为 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