2015-05-15 21 views
15

Vorrei escludere tutte le righe duplicate. Tuttavia, deve essere vero solo quando sono righe successive. Segue un esempio rappresentativo:Escludi righe duplicate successive

mio ingresso 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) 

mio previsto 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) 

risposta

14

rle() è una bella funzione che identifica le esecuzioni di valori identici, ma può essere una sorta di sofferenza per combattere l'output in una forma utilizzabile. Ecco un relativamente incantesimo indolore che funziona nel tuo caso.

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

Probabilmente ci sono molti modi di risolvere questo, vorrei provare rleid/unique combinazione dal 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 

O da ottimi consigli dai commenti:

utilizzando solo il nuovo shift funzione di

setDT(df)[VALUE != shift(VALUE, fill = TRUE)] 

o utilizzando duplicated combinato con rleid

setDT(df)[!duplicated(rleid(VALUE)), ] 
8

ne dite di questo:

> 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 

Qui, df[-nrow(df),-1] != df[-1,-1] trova coppie di righe consecutive che contengono valori diversi e il resto del codice le estrae dal dataframe.

2

mi sono imbattuto in questa bella funzione di qualche tempo fa, che le bandiere righe come in fase di prima sulla base di una variabile specificata:

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 
    } 

applicandolo alle dati dà:

> 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 

È può quindi deduplicare sulla prima colonna per ottenere l'output previsto.

Ho trovato questo molto utile in passato, soprattutto proveniente da uno sfondo SAS in cui questo è stato molto facile da fare.

4

vorrei usare una soluzione simile a @NPE s'

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

Naturalmente è possibile utilizzare qualsiasi altro livello di tolleranza (diverso da 1e-6).

2

Molte buone risposte già, ecco dplyr versione:

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