在下面的数据中,我想跟踪U
和Value
列。一旦列Value
的值在U
列中具有相同值的行发生更改,我想为U
列分配NA
。
有关如何有效处理此问题的任何建议?
输入数据
data <- read.table(header = TRUE, text="
U Value Debug
A 1 1231
A 1 41
A 2 -1149
A 2 -2339
B 3 -3529
B 4 -4719
C 5 -5909
C 5 -7099
C 5 -8289
C 6 -9479
C 6 -10669
C 6 -11859
D 7 -13049
D 7 -14239
D 8 -15429
D 8 -16619")
当前表输出
U Value Debug
A 1 1231
A 1 41
A 2 -1149
A 2 -2339
B 3 -3529
B 4 -4719
C 5 -5909
C 5 -7099
C 5 -8289
C 6 -9479
C 6 -10669
C 6 -11859
D 7 -13049
D 7 -14239
D 8 -15429
D 8 -16619
预期的表输出
U Value Debug
A 1 1231
A 1 41
NA 2 -1149
NA 2 -2339
B 3 -3529
NA 4 -4719
C 5 -5909
C 5 -7099
C 5 -8289
NA 6 -9479
NA 6 -10669
NA 6 -11859
D 7 -13049
D 7 -14239
NA 8 -15429
NA 8 -16619
我们可以使用data.table
。将data.frame
转换为data.table
(setDT(data)
),按U
分组,获取Value
列的运行长度id(基于值的变化,rleid
- 增量值),将其转换为带有mod运算符的二进制(%%
),通过否定(!
)转换为逻辑,使得0成为TRUE
和1的FALSE
,得到TRUE
值的行指数(.I
),提取该列($V1
)并使用它作为i
来指定(:=
)U
的值NA
library(data.table)
setDT(data)[data[, .I[!rleid(Value) %%2], U]$V1, U := NA]
data
# U Value Debug
# 1: A 1 1231
# 2: A 1 41
# 3: <NA> 2 -1149
# 4: <NA> 2 -2339
# 5: B 3 -3529
# 6: <NA> 4 -4719
# 7: C 5 -5909
# 8: C 5 -7099
# 9: C 5 -8289
#10: <NA> 6 -9479
#11: <NA> 6 -10669
#12: <NA> 6 -11859
#13: D 7 -13049
#14: D 7 -14239
#15: <NA> 8 -15429
#16: <NA> 8 -16619
根据与OP的讨论,我们需要指定NA'U',其中'Value'不是每个'U'的first
'Value'
setDT(data)[data[, .I[Value != first(Value)], .(U)]$V1, U := NA]
或者在dplyr
中使用相同的逻辑
library(dplyr)
data %>%
group_by(U1 = U) %>%
mutate(U = replace(U, Value != first(Value), NA)) %>%
ungroup %>%
select(-U1)
像这样的东西?
data %>%
group_by(U) %>%
mutate(
grp = cumsum(!(lag(Value, default = F) == Value)),
U.new = ifelse(grp == 1, as.character(U), NA))
## A tibble: 16 x 5
## Groups: U [4]
# U Value Debug grp U.new
# <fct> <int> <int> <int> <chr>
# 1 A 1 1231 1 A
# 2 A 1 41 1 A
# 3 A 2 -1149 2 NA
# 4 A 2 -2339 2 NA
# 5 B 3 -3529 1 B
# 6 B 4 -4719 2 NA
# 7 C 5 -5909 1 C
# 8 C 5 -7099 1 C
# 9 C 5 -8289 1 C
#10 C 6 -9479 2 NA
#11 C 6 -10669 2 NA
#12 C 6 -11859 2 NA
#13 D 7 -13049 1 D
#14 D 7 -14239 1 D
#15 D 8 -15429 2 NA
#16 D 8 -16619 2 NA
我正在这里创建一个新的列U.new
,因为我们正在由U
进行分组。
在回应你的评论时,你可以用U
取代U.new
data %>%
group_by(U) %>%
mutate(
grp = cumsum(!(lag(Value, default = F) == Value)),
U.new = if_else(grp == 1, as.character(U), "NA")) %>%
ungroup() %>%
select(U = U.new, Value, Debug)
## A tibble: 16 x 3
# U Value Debug
# <chr> <int> <int>
# 1 A 1 1231
# 2 A 1 41
# 3 NA 2 -1149
# 4 NA 2 -2339
# 5 B 3 -3529
# 6 NA 4 -4719
# 7 C 5 -5909
# 8 C 5 -7099
# 9 C 5 -8289
#10 NA 6 -9479
#11 NA 6 -10669
#12 NA 6 -11859
#13 D 7 -13049
#14 D 7 -14239
#15 NA 8 -15429
#16 NA 8 -16619
dplyr
的另一个选择是每个组(U
)找到Value
与前一个不同的第一行,然后将这些行更改为NA
。
library(dplyr)
data %>%
group_by(U) %>%
mutate(U1 = replace(U, row_number() > which.max(diff(Value) != 0), NA))
# U Value Debug U1
# <fct> <int> <int> <fct>
# 1 A 1 1231 A
# 2 A 1 41 A
# 3 A 2 -1149 NA
# 4 A 2 -2339 NA
# 5 B 3 -3529 B
# 6 B 4 -4719 NA
# 7 C 5 -5909 C
# 8 C 5 -7099 C
# 9 C 5 -8289 C
#10 C 6 -9479 NA
#11 C 6 -10669 NA
#12 C 6 -11859 NA
#13 D 7 -13049 D
#14 D 7 -14239 D
#15 D 8 -15429 NA
#16 D 8 -16619 NA
如果在Value
列中可能存在非数字值,我们可以使用lag
而不是diff
data %>%
group_by(U) %>%
mutate(U1 = replace(U, row_number() >= which.max(Value != lag(Value)), NA))