仅当它们直接连续复制时才删除 R 中的行

Removing rows in R only if they are duplicated in direct succession

我有一个 data.table 指示动物的位置,看起来像这样:

    Date       TimeStamp             Transponder Units
 1: 2021-08-15 2021-08-15 14:11:13    DA2C614E    M2
 2: 2021-08-15 2021-08-15 14:11:14    DA2C614E    M2
 3: 2021-08-15 2021-08-15 14:11:14    DA2C614E    M2
 4: 2021-08-15 2021-08-15 14:11:15    DA2C614E    M2
 5: 2021-08-15 2021-08-15 14:11:15    DA2C614E    M2
 6: 2021-08-15 2021-08-15 14:11:16    DA2C614E    M2
 7: 2021-08-15 2021-08-15 14:12:40    DA2C614E   HM2
 8: 2021-08-15 2021-08-15 14:12:40    DA2C614E   HM2
 9: 2021-08-15 2021-08-15 14:12:49    DA2C614E    H2
10: 2021-08-15 2021-08-15 14:18:02    DA2C614E    H1
11: 2021-08-15 2021-08-15 14:18:04    DA2C614E    H1
12: 2021-08-15 2021-08-15 14:19:19    DA2C614E    H1
13: 2021-08-15 2021-08-15 14:25:29    DA2C614E   HM2

T运行sponder表示个人和Units的位置。我想通过删除重复的行来创建此数据集的更稀疏版本,但 那些连续的行。本质上,因为连续的重复只是意味着没有移动。这意味着我希望我的最终结果是:

      Date       TimeStamp             Transponder Units
   1: 2021-08-15 2021-08-15 14:11:13    DA2C614E    M2
   2: 2021-08-15 2021-08-15 14:12:40    DA2C614E   HM2
   3: 2021-08-15 2021-08-15 14:12:49    DA2C614E    H2
   4: 2021-08-15 2021-08-15 14:18:02    DA2C614E    H1
   5: 2021-08-15 2021-08-15 14:25:29    DA2C614E   HM2

我曾尝试使用 duplicated(),但问题是此函数会删除 所有 重复项,例如后来重复的 HM2 条目。 (我 运行 在 Date、T运行sponder 和 Units 的子集上复制):

> sample[!duplicated(sample[, c(1,3,4)]),]
         Date           TimeStamp Transponder Units
1: 2021-08-15 2021-08-15 14:11:13    DA2C614E    M2
2: 2021-08-15 2021-08-15 14:12:40    DA2C614E   HM2
3: 2021-08-15 2021-08-15 14:12:49    DA2C614E    H2
4: 2021-08-15 2021-08-15 14:18:02    DA2C614E    H1

关于如何“优雅地”解决这个问题,即无需循环解决这个问题,有什么想法吗?

Filtering out duplicated/non-unique rows in data.table

我认为如果您的数据是 时间索引,这将适用于您的代码:

unique(sample, by = "Date")

示例:

dt <- data.table(V1 = LETTERS[c(1,1,1,2,2,2)], V2 = c(1,1,1,2,2,2))

   V1 V2
1:  A  1
2:  A  1
3:  A  1
4:  B  2
5:  B  2
6:  B  2
unique(dt, by = "V1")

   V1 V2
1:  A  1
2:  B  2

我们使用 data.table 中的 rleid 创建一个 dummy-grouping 变量,并使用 dplyr 中的 distinct 删除重复项。在您的数据中,您可能希望在 rleid 函数中包含 Transponder,如果它在您的真实数据中确实有所不同。

library(tidyverse)
library(data.table)

df %>% 
  mutate(dummy = rleid(Units)) %>% 
  distinct(dummy, .keep_all = T) %>% 
  select(-dummy)

        Date           TimeStamp Transponder Units
1 2021-08-15 2021-08-15-14:11:13    DA2C614E    M2
2 2021-08-15 2021-08-15-14:12:40    DA2C614E   HM2
3 2021-08-15 2021-08-15-14:12:49    DA2C614E    H2
4 2021-08-15 2021-08-15-14:18:02    DA2C614E    H1
5 2021-08-15 2021-08-15-14:25:29    DA2C614E   HM2

仅使用 data.table 而没有临时变量,您可以执行以下操作:dt[!duplicated(rleid(Units)),],基于评论。

我想尝试使用 data.table,正如您所说,您正在使用它,大概是因为您的数据很大,所以这应该比建议的 dplyr 方法更快。我对 data.table 没有太多经验,所以我想尝试一下,这似乎有效:

# Cols to subset
cols <- c("Date", "Transponder", "Units")
lagcols <- paste0(cols, "_lag")

# Create lag
sample[, (lagcols) := shift(.SD, n = 1, fill = NA, type = "lag"), .SDcols = cols]

# Create boolean mask if row == previous row in selected columns
sample[, equals_previous := Date == Date_lag & Transponder == Transponder_lag & Units == Units_lag]

# Delete lag columns
sample[, (lagcols) := NULL]

# Subset only rows where they are not equal to the previous row
sample[(!equals_previous)]

data.table 中可能有更优雅的方法来执行此操作,但如果您的数据量很大,这至少应该比转换为 data.frame 并使用 [=12] 更快=].