>我有一个数据表dt,有三列nm,seqn和obj
> nm <- letters[1:22]
> seqn <- c(32,36, 86,45 , 47, 48, 49,
+ 52, 54, 59,
+ 66, 9, 69, 74, 81, 88, 90, 91, 93, 94, 95, 97)
> obj <- rep(c('c1', 'c2', 'c3'), c(7, 3, 12))
> dt <- data.table(nm, seqn, obj)
> dt
nm seqn obj
1: a 32 c1
2: b 36 c1
3: c 86 c1
4: d 45 c1
5: e 47 c1
6: f 48 c1
7: g 49 c1
8: h 52 c2
9: i 54 c2
10: j 59 c2
11: k 66 c3
12: l 9 c3
13: m 69 c3
14: n 74 c3
15: o 81 c3
16: p 88 c3
17: q 90 c3
18: r 91 c3
19: s 93 c3
20: t 94 c3
21: u 95 c3
22: v 97 c3
我想为每个"obj"组获取一个单调的"seqn"序列。我想在 obj"c1"的情况下删除像 86(记录 3)这样的非序列号(* 这里的 86 是一个大数字,而通常的小单调 seqn 数字系列),在 obj "c3" 的情况下,我想删除 seqn 9。(记录 12)(*这里9是大数的单调序列中的小数)。
我如何使用data.table/dataframe执行此操作。
这是另一个data.table
解决方案,它与本评论中建议的解决方案不同。
OP 要求为每个obj
组获取单调的seqn
序列。此外,OP详细说明,当数字之前和后面是较小的数字时,他需要删除较大的数字,并在数字之前和之后删除较小的数字。虽然没有明确说明,但从提供的数据中可以得出结论,OP指的是单调递增的序列。
library(data.table)
DT[-DT[, .I[which(xor(
shift(seqn) < shift(seqn, type = "lead"),
between(seqn, shift(seqn), shift(seqn, type = "lead"))
))], by = obj]$V1]
# nm seqn obj
# 1: a 32 c1
# 2: b 36 c1
# 3: d 45 c1
# 4: e 47 c1
# 5: f 48 c1
# 6: g 49 c1
# 7: h 52 c2
# 8: i 54 c2
# 9: j 59 c2
#10: k 66 c3
#11: m 69 c3
#12: n 74 c3
#13: o 81 c3
#14: p 88 c3
#15: q 90 c3
#16: r 91 c3
#17: s 93 c3
#18: t 94 c3
#19: u 95 c3
#20: v 97 c3
数据
library(data.table)
nm <- letters[1:22]
seqn <- c(32,36, 86,45 , 47, 48, 49, 52, 54, 59,
66, 9, 69, 74, 81, 88, 90, 91, 93, 94, 95, 97)
obj <- rep(c('c1', 'c2', 'c3'), c(7, 3, 12))
DT <- data.table(nm, seqn, obj)
违反每个序列开头和结尾的单调性
可以增强上述方法,以涵盖在每个序列的开头或结尾(即每个obj
组)违反单调性的边缘情况。
例如:
seqn <- c(32,36, 86, 45, 47, -48, 49, 52, 54, 59,
66, 9, 13, 74, 81, 88, 90, 91, 93, 94, 95, 11)
(DT <- data.table(nm, seqn, obj))
# nm seqn obj
# 1: a 32 c1
# 2: b 36 c1
# 3: c 86 c1
# 4: d 45 c1
# 5: e 47 c1
# 6: f 48 c1
# 7: g 49 c1
# 8: h 52 c2
# 9: i 54 c2
#10: j 59 c2
#11: k 66 c3
#12: l 9 c3
#13: m 13 c3
#14: n 74 c3
#15: o 81 c3
#16: p 88 c3
#17: q 90 c3
#18: r 91 c3
#19: s 93 c3
#20: t 94 c3
#21: u 95 c3
#22: v 11 c3
# nm seqn obj
请注意,第 13 行和第 22 行中的DT
已更改。现在,obj
组c3
的第一个和最后一个元素已成为"异常值"。第一个元素66大于接下来的两个元素9和13,最后一个元素11低于前面的元素95。因此,单调递增序列从 9 开始,以 95 结束,必须删除元素 66 和 11。
这是通过简单地用前导-Inf
和尾随+Inf
填充每个序列来实现的。不需要对代码进行其他更改,只是必须将结果移回以选择正确的行号:
DT[-DT[, {seqn <- c(-Inf, seqn, +Inf); .I[which(shift(xor(
shift(seqn) < shift(seqn, type = "lead"),
between(seqn, shift(seqn), shift(seqn, type = "lead"))
), type = "lead"))]}, by = obj]$V1]
# nm seqn obj
# 1: a 32 c1
# 2: b 36 c1
# 3: d 45 c1
# 4: e 47 c1
# 5: f 48 c1
# 6: g 49 c1
# 7: h 52 c2
# 8: i 54 c2
# 9: j 59 c2
#10: l 9 c3
#11: m 13 c3
#12: n 74 c3
#13: o 81 c3
#14: p 88 c3
#15: q 90 c3
#16: r 91 c3
#17: s 93 c3
#18: t 94 c3
#19: u 95 c3