删除R中一组行中的某些行

时间:2015-12-15 16:17:25

标签: 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组删除ProfitId列的零行 因此,对于某个Id,如果两个或更多连续行的salesprofit值为零,则这些行将被删除。所以这个数据集会变成这样。

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

如果SalesProfit的值为零,我可以删除所有行

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

但是如何在这种情况下仅通过Id

删除某些组中的行 P.S这个想法是删除这些产品的条目,如果它们在几个月后开始销售,或者在一年的周期中几个月后被废弃。

4 个答案:

答案 0 :(得分:5)

以下是使用来自" data.table"的rleid的方法:

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

答案 1 :(得分: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)

<强>更新 要使用这些条件筛选多个列,请按照以下步骤操作。在目前的情况下,结果是相同的,因为当销售额为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)

答案 2 :(得分: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

首先确定salesProfit均为0(x)的所有行。变量y对连续的TRUEFALSE值进行分组。 ave()函数根据后续输入变量(xdf$Id)拆分第一个输入变量(y),然后在组内应用该函数。由于函数为sum(),它会将TRUE中的所有x值相加,然后返回与x长度相同的向量,因此我们只需要保留结果小于2的所有行。

答案 3 :(得分: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