Индекс последовательных дубликатов в векторе - PullRequest
7 голосов
/ 24 июня 2019

Каков оптимальный способ получить индекс всех элементов, которые повторяются # раз?Я хочу идентифицировать элементы, которые дублируются более 2 раз.rle() и rleid() оба намекают на нужные мне значения, но ни один метод напрямую не дает мне индексы.

Я придумал этот код:

t1 <- c(1, 10, 10, 10, 14, 37, 3, 14, 8, 8, 8, 8, 39, 12)

t2 <- lag(t1,1)
t2[is.na(t2)] <- 0
t3 <- ifelse(t1 - t2 == 0, 1, 0)
t4 <- rep(0, length(t3))
for (i in 2:length(t3)) t4[i] <- ifelse(t3[i] > 0, t3[i - 1] + t3[i], 0)

which(t4 > 1)

возвращает:

[1]  4 11 12 

и это те значения, которые мне нужны.

Существуют ли более подходящие R-функции?

Бен

Ответы [ 4 ]

9 голосов
/ 24 июня 2019

Один вариант с данными. Нет реальной причины использовать это вместо lag / shift при n = 2, но для больших n это избавит вас от создания большого числа новых векторов с задержкой.

library(data.table)

which(rowid(rleid(t1)) > 2)
# [1]  4 11 12

Пояснение:

rleid будет генерировать уникальное значение для каждого "прогона" равных значений, а rowid будет отмечать, сколько элементов "в" прогоне каждого элемента. То, что вы хотите, это элементы больше, чем на 2 "в" пробег.

data.table(
  t1,
  rleid(t1),
  rowid(t1))

#     t1 V2 V3
#  1:  1  1  1
#  2: 10  2  1
#  3: 10  2  2
#  4: 10  2  3
#  5: 14  3  1
#  6: 37  4  1
#  7:  3  5  1
#  8: 14  6  2
#  9:  8  7  1
# 10:  8  7  2
# 11:  8  7  3
# 12:  8  7  4
# 13: 39  8  1
# 14: 12  9  1

Редактировать: Если, как в примере, поставленном этим вопросом, никакие два прогона (даже "прогоны" длины-1) не имеют одинакового значения (или если вам все равно, находятся ли дубликаты рядом друг с другом), вместо этого вы можете использовать which(rowid(t1) > 2). (Это отмечает Фрэнк в комментариях)

Надеюсь, этот пример прояснит различия

a <- c(1, 1, 1, 2, 2, 1)
which(rowid(a) > 2)
# [1] 3 6
which(rowid(rleid(a)) > 2)
# [1] 3
6 голосов
/ 24 июня 2019

Вы можете использовать dplyr::lag или data.table::shift (обратите внимание, что для shift по умолчанию используется задержка, поэтому shift(t1, 1) равно shift(t1, 1, type = "lag"):

which(t1 == lag(t1, 1) & lag(t1, 1) == lag(t1, 2))
[1]  4 11 12
# Or
which(t1 == shift(t1, 1) & shift(t1, 1) == shift(t1, 2))
[1]  4 11 12

Если вам нужноДля масштабирования нескольких дубликатов вы можете сделать следующее (спасибо за подсказку @IceCreamToucan):

n <- 2
df1 <- sapply(0:n, function(x) shift(t1, x))
which(rowMeans(df1 == df1[,1]) == 1)
[1]  4 11 12
2 голосов
/ 24 июня 2019

Другая возможность с участием rle() может быть:

pseudo_rleid <- with(rle(t1), rep(seq_along(values), lengths))
which(ave(t1, pseudo_rleid, FUN = function(x) seq_along(x) > 2) != 0)

[1]  4 11 12
2 голосов
/ 24 июня 2019

Это обычно тот случай, когда rle полезен, то есть

v1 <- rle(t1)
i1 <- seq_along(t1)[t1 %in% v1$values[v1$lengths > 2]]
i2 <- t1[t1 %in% v1$values[v1$lengths > 2]]
tapply(i1, i2, function(i) tail(i, -2))
#$`8`
#[1] 11 12

#$`10`
#[1] 4

Вы можете удалить и получить его как вектор,

unlist(tapply(i1, i2, function(i) tail(i, -2)))
#81 82 10 
#11 12  4

Существует также функция, которая называетсяrleid в data.table упаковке, которую мы можем использовать,

unlist(lapply(Filter(function(i) length(i) > 2, split(seq_along(t1), data.table::rleid(t1))),
                                                                    function(i) tail(i, -2)))
 #2 71 72 
 #4 11 12 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...