从 R 中 data.table 中的列中删除序列号



>我有一个数据表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已更改。现在,objc3的第一个和最后一个元素已成为"异常值"。第一个元素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

最新更新