2015-12-15 14 views
6

Supponiamo che io ho questo set di datiElimina alcune righe in un gruppo di righe in R

Id Name Price sales Profit Month Category Mode Supplier 
1 A  2  0  0  1  X K  John 
1 A  2  0  0  2  X K  John 
1 A  2  5  8  3  X K  John 
1 A  2  5  8  4  X L  Sam 
2 B  2  3  4  1  X L  Sam 
2 B  2  0  0  2  X L  Sam 
2 B  2  0  0  3  X M  John 
2 B  2  0  0  4  X L  John 
3 C  2  0  0  1  X K  John 
3 C  2  8  10  2  Y M  John 
3 C  2  8  10  3  Y K  John 
3 C  2  0  0  4  Y K  John 
5 E  2  0  0  1  Y M  Sam 
5 E  2  5  5  2  Y L  Sam 
5 E  2  5  9  3  Y M  Sam 
5 E  2  0  0  4  Z M  Kyle 
5 E  2  5  8  5  Z L  Kyle 
5 E  2  5  8  6  Z M  Kyle 

voglio eliminare le righe con zeri per Sales e Profit colonna Id gruppo Così per un certo Id se due o più le righe consecutive hanno zero valori per sales e profit quelle righe verranno eliminate. Quindi questo set di dati diventerà così.

Id Name Price sales Profit Month Category Mode Supplier 
1 A  2  5  8  3  X K  John 
1 A  2  5  8  4  X L  Sam 
2 B  2  3  4  1  X L  Sam 
3 C  2  0  0  1  X K  John 
3 C  2  8  10  2  Y M  John 
3 C  2  8  10  3  Y K  John 
3 C  2  0  0  4  Y K  John 
5 E  2  0  0  1  Y M  Sam 
5 E  2  5  5  2  Y L  Sam 
5 E  2  5  9  3  Y M  Sam 
5 E  2  0  0  4  Z M  Kyle 
5 E  2  5  8  5  Z L  Kyle 
5 E  2  5  8  6  Z M  Kyle 

posso rimuovere tutte le righe se hanno valori zero per Sales e Profit con

df1 = df[!(df$sales==0 & test$Profit==0),] 

Ma come eliminare solo le righe in certo gruppo in questo caso per Id

PS L'idea è quello di eliminare le voci per quei prodotti se hanno iniziato a vendere dopo pochi mesi o sono stati abbandonati dopo pochi mesi in un ciclo annuale.

+0

Scrivere una semplice funzione che esegue la cancellazione e include/esclude i gruppi desiderati. Quindi usa uno dei 'lapply' a' for' loop, 'data.table', o '(d) plyr' per split-apply-combine –

risposta

5

Ecco un approccio utilizzando rleid da "data.table":

library(data.table) 
as.data.table(mydf)[, N := .N, by = .(Id, rleid(sales == 0 & Profit == 0))][ 
    !(sales == 0 & Profit == 0 & N >= 2)] 
##  Id Name Price sales Profit Month Category Mode Supplier N 
## 1: 1 A  2  5  8  3  X K  John 2 
## 2: 1 A  2  5  8  4  X L  Sam 2 
## 3: 2 B  2  3  4  1  X L  Sam 1 
## 4: 3 C  2  0  0  1  X K  John 1 
## 5: 3 C  2  8  10  2  Y M  John 2 
## 6: 3 C  2  8  10  3  Y K  John 2 
## 7: 3 C  2  0  0  4  Y K  John 1 
## 8: 5 E  2  0  0  1  Y M  Sam 1 
## 9: 5 E  2  5  5  2  Y L  Sam 2 
## 10: 5 E  2  5  9  3  Y M  Sam 2 
## 11: 5 E  2  0  0  4  Z M  Kyle 1 
## 12: 5 E  2  5  8  5  Z L  Kyle 2 
## 13: 5 E  2  5  8  6  Z M  Kyle 2 
+0

Errore in eval (expr, envir, enclos): impossibile trovare la funzione " rleid " ottenuto questo errore, ho installato e caricato il pacchetto data.table. –

+0

@ Jaykhan, quale versione di "data.table" stai usando? Su quale sistema operativo sei? – A5C1D2H2I1M1N2O1R2T1

+0

data table di 1.9.6 e usando OSX El Captain –

1

Non posso farlo in una linea, ma qui è in tre:

x <- df$sales==0 & df$Profit==0 
y <- cumsum(c(1,head(x,-1)!=tail(x,-1))) 
df[ave(x,df$Id,y,FUN=sum)<2,] 

# Id Name Price sales Profit Month Category Mode Supplier 
# 3 1 A  2  5  8  3  X K  John 
# 4 1 A  2  5  8  4  X L  Sam 
# 5 2 B  2  3  4  1  X L  Sam 
# 9 3 C  2  0  0  1  X K  John 
# 10 3 C  2  8  10  2  Y M  John 
# 11 3 C  2  8  10  3  Y K  John 
# 12 3 C  2  0  0  4  Y K  John 
# 13 5 E  2  0  0  1  Y M  Sam 
# 14 5 E  2  5  5  2  Y L  Sam 
# 15 5 E  2  5  9  3  Y M  Sam 
# 16 5 E  2  0  0  4  Z M  Kyle 
# 17 5 E  2  5  8  5  Z L  Kyle 
# 18 5 E  2  5  8  6  Z M  Kyle 

Questo funziona identificando prima tutte le righe dove sales e Profit sono entrambi 0 (x). La variabile y raggruppa i valori TRUE e FALSE consecutivi. La funzione ave() divide la prima variabile di input (x) in base alle variabili di input successive (df$Id e), quindi applica la funzione all'interno di gruppi. Poiché la funzione è sum(), si sommano tutti i valori TRUE in x, quindi ritorna un vettore della stessa lunghezza come x, quindi abbiamo solo bisogno di mantenere tutte le righe in cui il risultato è inferiore a 2.

+0

Quando ho provato ad applicare il codice su dati originali di oltre 500.000 righe, si rompe con errore che i vettori lunghi non sono ancora supportati: –

3

Ecco come farlo con dplyr. Fondamentalmente, sto mantenendo solo le righe che non sono zero O che le righe precedenti/seguenti non sono zero.

table1 %>% 
group_by(Id) %>% 
mutate(Lag=lag(sales),Lead=lead(sales)) %>% 
rowwise() %>% 
mutate(Min=min(Lag,Lead,na.rm=TRUE)) %>% 
filter(sales>0|Min>0) %>% 
select(-Lead,-Lag,-Min) 

     Id Name Price sales Profit Month Category Mode Supplier 
    (int) (chr) (int) (int) (int) (int) (chr) (chr) (chr) 
1  1  A  2  5  8  3  X  K  John 
2  1  A  2  5  8  4  X  L  Sam 
3  2  B  2  3  4  1  X  L  Sam 
4  3  C  2  0  0  1  X  K  John 
5  3  C  2  8  10  2  Y  M  John 
6  3  C  2  8  10  3  Y  K  John 
7  3  C  2  0  0  4  Y  K  John 
8  5  E  2  0  0  1  Y  M  Sam 
9  5  E  2  5  5  2  Y  L  Sam 
10  5  E  2  5  9  3  Y  M  Sam 
11  5  E  2  0  0  4  Z  M  Kyle 
12  5  E  2  5  8  5  Z  L  Kyle 
13  5  E  2  5  8  6  Z  M  Kyle 

dati

table1 <-read.table(text=" 
Id,Name,Price,sales,Profit,Month,Category,Mode,Supplier 
1,A,2,0,0,1,X,K,John 
1,A,2,0,0,2,X,K,John 
1,A,2,5,8,3,X,K,John 
1,A,2,5,8,4,X,L,Sam 
2,B,2,3,4,1,X,L,Sam 
2,B,2,0,0,2,X,L,Sam 
2,B,2,0,0,3,X,M,John 
2,B,2,0,0,4,X,L,John 
3,C,2,0,0,1,X,K,John 
3,C,2,8,10,2,Y,M,John 
3,C,2,8,10,3,Y,K,John 
3,C,2,0,0,4,Y,K,John 
5,E,2,0,0,1,Y,M,Sam 
5,E,2,5,5,2,Y,L,Sam 
5,E,2,5,9,3,Y,M,Sam 
5,E,2,0,0,4,Z,M,Kyle 
5,E,2,5,8,5,Z,L,Kyle 
5,E,2,5,8,6,Z,M,Kyle 
",sep=",",stringsAsFactors =FALSE, header=TRUE) 

AGGIORNAMENTO Per filtrare su più di una colonna con questi criteri, ecco come fare. Nel caso di specie, il risultato è lo stesso, perché quando le vendite sono 0, i profitti sono anche 0.

library(dplyr) 
table1 %>% 
group_by(Id) %>% 
mutate(LagS=lag(sales),LeadS=lead(sales),LagP=lag(Profit),LeadP=lead(Profit)) %>% 
rowwise() %>% 
mutate(MinS=min(LagS,LeadS,na.rm=TRUE),MinP=min(LagP,LeadP,na.rm=TRUE)) %>% 
filter(sales>0|MinS>0|Profit>0|MinP>0) %>%   # "|" means OR 
select(-LeadS,-LagS,-MinS,-LeadP,-LagP,-MinP) 
+0

A proposito, questo non è esattamente ciò che l'OP vuole. Guarda 8. linea del risultato desiderato. – DatamineR

+0

Ho modificato la mia risposta per risolverlo. –

+0

@PLapointe l'eliminazione in base a una variabile Vendite, giusto? Voglio eliminare le righe con zero in base a 2 o più valori di variabili. Come farlo? –

1

Ecco la mia soluzione :

aux <- lapply(tapply(df$sales + df$Profit, df$Id, rle), function(x) 
     with(x, cbind(rep(values, lengths), rep(lengths, lengths)))) 

df[!(do.call(rbind, aux)[,1]==0 & do.call(rbind, aux)[,2] >= 2),] 

    Id Name Price sales Profit Month Category Mode Supplier 
3 1 A  2  5  8  3  X K  John 
4 1 A  2  5  8  4  X L  Sam 
5 2 B  2  3  4  1  X L  Sam 
9 3 C  2  0  0  1  X K  John 
10 3 C  2  8  10  2  Y M  John 
11 3 C  2  8  10  3  Y K  John 
12 3 C  2  0  0  4  Y K  John 
13 5 E  2  0  0  1  Y M  Sam 
14 5 E  2  5  5  2  Y L  Sam 
15 5 E  2  5  9  3  Y M  Sam 
16 5 E  2  0  0  4  Z M  Kyle 
17 5 E  2  5  8  5  Z L  Kyle 
18 5 E  2  5  8  6  Z M  Kyle 
+0

Quando ho provato ad applicare il codice su dati originali di oltre 500.000 righe, si rompe con errore che i vettori lunghi non sono ancora supportati: –