2015-12-15 2 views
6

Предположим, у меня есть этот набор данныхУдалить определенные строки в группе строк в 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 

Я хочу, чтобы удалить строки с нулями для Sales и Profit колонки Id группы Таким образом, для определенного Id, если два или более последовательные строки имеют нулевые значения для sales и profit, эти строки будут удалены. Таким образом, этот набор данных станет таким.

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 

можно удалить все строки, если они имеют нулевые значения для Sales и Profit с

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

Но как удалять строки только в определенной группе в этом случае Id

PS Идея заключается в удалении записей для этих продуктов, если они начали продаваться через несколько месяцев или были оставлены после нескольких месяцев в течение года.

+0

Напишите простую функцию, которая выполняет удаление и включает/исключает группы, которые вы хотите. Затем используйте любой из 'lapply'' 'for' loop,' data.table' или '(d) plyr' to split-apply-comb –

ответ

5

Вот подход, использующий rleid из «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

Ошибка в eval (expr, envir, enc): не удалось найти функцию " rleid " получил эту ошибку, я установил и загрузил пакет data.table. –

+0

@Jaykhan, какую версию «data.table» вы используете? На какой ОС вы работаете? – A5C1D2H2I1M1N2O1R2T1

+0

таблица данных 1.9.6 и с использованием OSX El Captain –

1

Я не могу сделать это в одной строке, но здесь она в трех:

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 

Это работает на первом отыскивая все строки, в которых sales и Profit являются как 0 (x). Переменная y групп последовательных TRUE и FALSE значений. Функция ave() разделяет первую входную переменную (x) в соответствии с последующими входными переменными (df$Id и y), затем применяет функцию внутри групп. Так как функция sum(), он будет сложить все TRUE значения в x, то он возвращает вектор той же длины, как x, так что мы просто должны держать все строки, в которых результат меньше, чем 2.

+0

Когда я попытался применить код к исходным данным из более чем 500 000 строк, он обрывается с ошибкой, что длинные векторы еще не поддерживаются: –

3

Вот как это сделать: dplyr. В основном, я поддерживаю только строки, которые не равны нулю или что предыдущие/следующие строки не равны нулю.

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 

данных

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) 

UPDATE Для фильтрации на более чем один столбец с этими критериями, вот как это сделать. В данном случае, результат будет тот же, потому что, когда продажи 0, прибыль также 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

Кстати, это не совсем то, чего хочет OP. Посмотрите на 8. строку желаемого результата. – DatamineR

+0

Я отредактировал свой ответ, чтобы исправить это. –

+0

@ Заменить его удаление на основе одной переменной Sales, не так ли? Я хочу удалить строки с нулем на основе 2 или более значений переменных. Как это сделать? –

1

Вот мое решение :

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

Когда я попытался применить код к исходным данным более 500 000 строк, он обрывается с ошибкой, что длинные векторы еще не поддерживаются: –

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