Исключить последующие повторяющиеся строки
Я хотел бы исключить все повторяющиеся строки. Однако это должно быть верно только тогда, когда они являются последующими строками. Следует репрезентативный пример:
вход df
:
df <- "NAME VALUE
Prb1 0.05
Prb2 0.05
Prb3 0.05
Prb4 0.06
Prb5 0.06
Prb6 0.01
Prb7 0.10
Prb8 0.05"
df <- read.table(text=df, header=T)
мой ожидаемый outdf
:
outdf <- "NAME VALUE
Prb1 0.05
Prb4 0.06
Prb6 0.01
Prb7 0.10
Prb8 0.05"
outdf <- read.table(text=df, header=T)
6 ответов
rle()
- хорошая функция, которая идентифицирует прогоны одинаковых значений, но это может быть своего рода боль, чтобы бороться с ее выходом в полезную форму. Вот относительно безболезненное заклинание, которое работает в вашем случае.
df[sequence(rle(df$VALUE)$lengths) == 1, ]
# NAME VALUE
# 1 Prb1 0.05
# 4 Prb4 0.06
# 6 Prb6 0.01
# 7 Prb7 0.10
# 8 Prb8 0.05
вероятно, есть много способов решить эту проблему, я бы попробовал rleid/unique
комбинация с data.table
версия devel
library(data.table) ## v >= 1.9.5
unique(setDT(df)[, indx := rleid(VALUE)], by = "indx")
# NAME VALUE indx
# 1: Prb1 0.05 1
# 2: Prb4 0.06 2
# 3: Prb6 0.01 3
# 4: Prb7 0.10 4
# 5: Prb8 0.05 5
или из некоторых замечательных предложений из комментариев:
используя только новые shift
функции
setDT(df)[VALUE != shift(VALUE, fill = TRUE)]
или через duplicated
в сочетании с rleid
setDT(df)[!duplicated(rleid(VALUE)), ]
Как насчет этого:
> df[c(T, df[-nrow(df),-1] != df[-1,-1]), ]
NAME VALUE
1 Prb1 0.05
4 Prb4 0.06
6 Prb6 0.01
7 Prb7 0.10
8 Prb8 0.05
здесь df[-nrow(df),-1] != df[-1,-1]
находит пары последовательных строк, содержащих разные значения, а остальная часть кода извлекает их из фрейма данных.
Я бы использовал решение, подобное @NPE ' s
df[c(TRUE,abs(diff(df$VALUE))>1e-6),]
конечно, вы можете использовать любой другой уровень толерантности (кроме 1e-6
).
я столкнулся с этой хорошей функцией некоторое время назад, которая помечает строки как первые на основе указанной переменной:
isFirst <- function(x,...) {
lengthX <- length(x)
if (lengthX == 0) return(logical(0))
retVal <- c(TRUE, x[-1]!=x[-lengthX])
for(arg in list(...)) {
stopifnot(lengthX == length(arg))
retVal <- retVal | c(TRUE, arg[-1]!=arg[-lengthX])
}
if (any(missing<-is.na(retVal))) # match rle: NA!=NA
retVal[missing] <- TRUE
retVal
}
применяя его к вашим данным дает:
> df$first <- isFirst(df$VALUE)
> df
NAME VALUE first
1 Prb1 0.05 TRUE
2 Prb2 0.05 FALSE
3 Prb3 0.05 FALSE
4 Prb4 0.06 TRUE
5 Prb5 0.06 FALSE
6 Prb6 0.01 TRUE
7 Prb7 0.10 TRUE
8 Prb8 0.05 TRUE
затем вы можете dedup в первом столбце, чтобы получить ожидаемый результат.
Я нашел это очень полезным в прошлом, особенно исходя из фона SAS, где это было очень легко сделать.