Как удалить/свернуть последовательные повторяющиеся значения в последовательности в R?
У меня есть следующий кадр данных
a a a b c c d e a a b b b e e d d
Требуемый результат должен быть
a b c d e a b e d
Таким образом, это означает, что никакие две последовательные строки не должны иметь одинаковое значение. Как это можно сделать без использования цикла.
Поскольку мой набор данных довольно большой, выполнение цикла занимает много времени.
Изменить:
Структура фрейма данных похожа на следующую
a 1
a 2
a 3
b 2
c 4
c 1
d 3
e 9
a 4
a 8
b 10
b 199
e 2
e 5
d 4
d 10
Результат:
a 1
b 2
c 4
d 3
e 9
a 4
b 10
e 2
d 4
Его следует удалить всю строку.
Ответы
Ответ 1
Один простой способ - использовать rle
:
Вот ваши примеры данных:
x <- scan(what = character(), text = "a a a b c c d e a a b b b e e d d")
# Read 17 items
rle
возвращает list
с двумя значениями: длина прогона ("lengths
") и значение, которое повторяется для этого прогона ("values
").
rle(x)$values
# [1] "a" "b" "c" "d" "e" "a" "b" "e" "d"
Обновление: для data.frame
Если вы работаете с data.frame
, попробуйте что-то вроде следующего:
## Sample data
mydf <- data.frame(
V1 = c("a", "a", "a", "b", "c", "c", "d", "e",
"a", "a", "b", "b", "e", "e", "d", "d"),
V2 = c(1, 2, 3, 2, 4, 1, 3, 9,
4, 8, 10, 199, 2, 5, 4, 10)
)
## Use rle, as before
X <- rle(mydf$V1)
## Identify the rows you want to keep
Y <- cumsum(c(1, X$lengths[-length(X$lengths)]))
Y
# [1] 1 4 5 7 8 9 11 13 15
mydf[Y, ]
# V1 V2
# 1 a 1
# 4 b 2
# 5 c 4
# 7 d 3
# 8 e 9
# 9 a 4
# 11 b 10
# 13 e 2
# 15 d 4
Обновление 2
В пакете "data.table" есть функция rleid
, которая позволяет вам сделать это довольно легко. Используя mydf
сверху, попробуйте:
library(data.table)
as.data.table(mydf)[, .SD[1], by = rleid(V1)]
# rleid V2
# 1: 1 1
# 2: 2 2
# 3: 3 4
# 4: 4 3
# 5: 5 9
# 6: 6 4
# 7: 7 10
# 8: 8 2
# 9: 9 4
Ответ 2
library(dplyr)
x <- c("a", "a", "a", "b", "c", "c", "d", "e", "a", "a", "b", "b", "b", "e", "e", "d", "d")
x[x!=lag(x, default=1)]
#[1] "a" "b" "c" "d" "e" "a" "b" "e" "d"
РЕДАКТИРОВАТЬ: для data.frame
mydf <- data.frame(
V1 = c("a", "a", "a", "b", "c", "c", "d", "e",
"a", "a", "b", "b", "e", "e", "d", "d"),
V2 = c(1, 2, 3, 2, 4, 1, 3, 9,
4, 8, 10, 199, 2, 5, 4, 10),
stringsAsFactors=FALSE)
Решение dplyr - это один вкладыш:
mydf %>% filter(V1!= lag(V1, default="1"))
# V1 V2
#1 a 1
#2 b 2
#3 c 4
#4 d 3
#5 e 9
#6 a 4
#7 b 10
#8 e 2
#9 d 4
опубликовать скриптум
lead(x,1)
, предложенный @Carl Witthoft, повторяется в обратном порядке.
leadit<-function(x) x!=lead(x, default="what")
rows <- leadit(mydf[ ,1])
mydf[rows, ]
# V1 V2
#3 a 3
#4 b 2
#6 c 1
#7 d 3
#8 e 9
#10 a 8
#12 b 199
#14 e 5
#16 d 10
Ответ 3
С базой R мне нравятся забавные алгоритмы:
x <- c("a", "a", "a", "b", "c", "c", "d", "e", "a", "a", "b", "b", "b", "e", "e", "d", "d")
x[x!=c(x[-1], FALSE)]
#[1] "a" "b" "c" "d" "e" "a" "b" "e" "d"
Ответ 4
Как бы я ни любил... ошибаться, любовь rle
, вот перестрелка:
ОБНОВЛЕНИЕ: Не могу понять, что именно с dplyr
, поэтому я использовал dplyr::lead
. Я на OSX, R3.1.2 и последней версии dplyr
от CRAN.
xlet<-sample(letters,1e5,rep=T)
rleit<-function(x) rle(x)$values
lagit<-function(x) x[x!=lead(x, default=1)]
tailit<-function(x) x[x!=c(tail(x,-1), tail(x,1))]
microbenchmark(rleit(xlet),lagit(xlet),tailit(xlet),times=20)
Unit: milliseconds
expr min lq median uq max neval
rleit(xlet) 27.43996 30.02569 30.20385 30.92817 37.10657 20
lagit(xlet) 12.44794 15.00687 15.14051 15.80254 46.66940 20
tailit(xlet) 12.48968 14.66588 14.78383 15.32276 55.59840 20