2015-05-15 8 views
15

Я хотел бы исключить все дублированные строки. Однако это должно быть правдой, только когда они являются последующими строками. Следит типичный пример:Исключить последующие дублированные строки

Мой вход 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) 

ответ

14

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 
10

Есть, вероятно, много способов решения этого, я хотел бы попробовать rleid/unique комбинацию из data.tabledevel version

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)), ] 
8

Как об этом:

> 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] находит пары последовательных строк, которые содержат разные значения, а остальная часть кода извлекает их из фрейма данных.

2

Я наткнулся на эту хорошей функции некоторое время назад, какие флаги строк, будучи первым на основании указанной переменной:

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 

You может затем сделать вывод в первом столбце, чтобы получить ожидаемый результат.

Я нашел это очень полезным в прошлом, особенно исходя из фона SAS, где это было очень легко сделать.

4

Я хотел бы использовать решение, похожее на @NPE «s

df[c(TRUE,abs(diff(df$VALUE))>1e-6),] 

Конечно, вы можете использовать любой другой уровень толерантности (кроме 1e-6).

2

Многие хорошие ответы уже здесь dplyr версия:

filter(df,VALUE!=lag(VALUE,default=df$VALUE[1]+1)) 

 Смежные вопросы

  • Нет связанных вопросов^_^