从 xts 对象中删除连续的重复行

Remove sequential repeating rows from xts object

假设我有以下包含出价和要价数据的 XTS 对象:

   Time     Bid    Ask
   00:01    10     11
   00:02    10     11
   00:03    11     12
   00:04    12     13
   00:05    10     11
   00:06    10     11
   00:07    10     11

   00:08    9      12
   00:09    2      10
   00:10    4      5

我想获得以下输出:

   Time     Bid    Ask
   00:01    10     11
   00:03    11     12
   00:04    12     13
   00:05    10     11

   00:08    9      12
   00:09    2      10
   00:10    4      5

仅当行与上一个条目相同时才应删除行。如果出价或要价发生变化,则不会删除任何内容,因此简单地删除重复项是行不通的。

这应该是相当简单的,因为我以前做过,但我就是不记得怎么做,也找不到。

更新: 我在我的初始数据和预期输出中添加了一些额外的条目。

Joshua 的 swearer 很聪明,但它依赖于 rowSums 等函数给出不同的结果,但它与 9 12 不符。 我使用了 matrixStats 包中的 rowProds 函数,该函数有效,但显然我的最后两行失败了。此外,我的示例中第一列中的值小于第二列中的值。虽然这是有道理的,但它不是必须的,因此如果 Ask 小于 Bid,则 rowSums 和 rowProds 都将失败时,该函数应该可以工作。 是否有更好的行函数,如果有任何不同,例如可能是行哈希,总是会给出不同的结果?

您可以通过对每行的总和使用 rle() 来完成此操作。

x <- structure(
  c(10L, 10L, 11L, 12L, 10L, 10L, 10L, 11L, 11L, 12L, 13L, 11L, 11L, 11L),
  .Dim = c(7L, 2L), .Dimnames = list(NULL, c("Bid", "Ask")),
  index = structure(1:7, tzone = "", tclass = c("POSIXct", "POSIXt")),
  .indexCLASS = c("POSIXct", "POSIXt"), .indexTZ = "",
  tclass = c("POSIXct", "POSIXt"), tzone = "", class = c("xts", "zoo"))
r <- rle(rowSums(x))

如果你想在每个组中最后观察,你可以在子集时使用cumsum(r$lengths)作为行索引。

R> x[cumsum(r$lengths),]
                    Bid Ask
1969-12-31 18:00:02  10  11
1969-12-31 18:00:03  11  12
1969-12-31 18:00:04  12  13
1969-12-31 18:00:07  10  11

因为你想要每个组的第一个观察值,你需要在 r$lengths 向量前面加上一个 1 (你总是想要第一个观察值)然后删除 [= 的最后一个元素16=]。然后对结果调用 cumsum()

R> x[cumsum(c(1, head(r$lengths, -1))),]
                    Bid Ask
1969-12-31 18:00:01  10  11
1969-12-31 18:00:03  11  12
1969-12-31 18:00:04  12  13
1969-12-31 18:00:05  10  11

很好地理解了 rowSums() 的限制。一个可靠的解决方案是 diff() 出价和要价以及 select 两者都不为零的行。

d <- diff(x) != 0           # rows with price changes
d[1,] <- TRUE               # always select first observation
g <- cumsum(d$Bid | d$Ask)  # groups of repeats
r <- rle(as.numeric(g))     # run length encoding on groups

# now use the solution above
x[cumsum(c(1, head(r$lengths, -1))),]