R data.table:按条件过滤多个变量中的行

时间:2018-11-20 18:22:24

标签: r data.table

我对以下data.table有一个过滤器问题,并真的希望有人可以帮助我。我不确定是否有简单的方法可以做到,并希望要求的不是太多。所以这是我的问题:

A   B   C   Area
aa  M+H 1   127427
aa  M+H 2   204051.5
aa  M+Na    1   6855539.48777
aa  M+Na    2   6469689
bb  M+H 1   15330650
bb  M+H 2   214221
bb  M+H 3   11357158
bb  M+K 1   2140221
bb  M+K 2   61715568

对于每个AB组(aa M + H,aa M + Na,bb M + H,bb M + K),如果其Area值大于行中的所有行,则应滤除C> 1的所有行具有相同的AB组合和C值1(每个ABC组合在表中仅存在一次)。在该步骤之后,应保留以下行:

A   B   C   Area
aa  M+H 1   127427
aa  M+Na    1   6855539.48777
aa  M+Na    2   6469689
bb  M+H 1   15330650
bb  M+H 2   214221
bb  M+H 3   11357158
bb  M+K 1   2140221

之后,我想过滤出同一AC组中的所有行(aa 1,aa 2,bb 1,bb2),但是Area值比带有“ M + H”的行中的行高作为B值。因此,应保留以下内容:

A   B   C   Area
aa  M+H 1   127427
aa  M+Na    2   6469689
bb  M+H 1   15330650
bb  M+H 2   214221
bb  M+H 3   11357158
bb  M+K 1   2140221

最后,将所有剩下的A B组(aa M + H,aa M + Na,bb M + H,bb M + K)除掉,剩下的C行中的值都不为1。因此应该只有:

A   B   C   Area
aa  M+H 1   127427
bb  M+H 1   15330650
bb  M+H 2   214221
bb  M+H 3   11357158
bb  M+K 1   2140221

我试图使用data.table完成它,但是如果有人告诉我dplyr更好,我也会为那里的解决方案感到高兴。无论如何,非常感谢您的时间和精力!

Yasel

2 个答案:

答案 0 :(得分:2)

欢迎您!

按照您的指示,我得到的结果与您的不同,但是您也许可以根据需要进行调整:

library(data.table)

DT <- data.table(stringsAsFactors=FALSE,
                 A = c("aa", "aa", "aa", "aa", "bb", "bb", "bb", "bb", "bb"),
                 B = c("M+H", "M+H", "M+Na", "M+Na", "M+H", "M+H", "M+H", "M+K",
                       "M+K"),
                 C = c(1L, 2L, 1L, 2L, 1L, 2L, 3L, 1L, 2L),
                 Area = c(127427, 204051.5, 6855539.48777, 6469689, 15330650, 214221,
                          11357158, 2140221, 61715568)
)

DT <- DT[DT[C==1], on=.(A, B)][i.Area-Area > 0 | C==1]
DT[, c("i.C", "i.Area") := NULL]

DT <- DT[DT[B=="M+H"], on=.(A, C)][i.Area-Area <= 0]
DT[, c("i.B", "i.Area") := NULL]

DT <- DT[DT[C==1], on=.(A, B)]
DT[, c("i.C", "i.Area") := NULL]

答案 1 :(得分:1)

这不是最吸引人的解决方案,但是它的某些变化可能会带您到达那里:

library(data.table)

A <- c(rep("aa",4),rep("bb",5))
B <- c(rep("M+H",2),rep("M+Na",2),rep("M+H",3),rep("M+K",2))
C <- c(1,2,1,2,1,2,3,1,2)
Area <- c(127427,204051.5,6855539.48777,6469689,15330650,214221,11357158,2140221,61715568)
DT <- as.data.table(cbind(A,B,C,Area))

DT <- setorder(DT,A,B)
DT$ABFilter <- sapply(1:nrow(DT), function(x) ifelse((C[x]==1 
      || (C[x]==2 && A[x]==A[x-1] && B[x]==B[x-1] && (Area[x] < Area[x-1]))
      || (C[x]==3 && A[x]==A[x-2] && B[x]==B[x-2] && (Area[x] < Area[x-2])))
      , "Keep", "Discard"))
DT <- DT[ABFilter=="Keep",]
DT$ABFilter <- NULL
DT

DT <- setorder(DT,A,C)
DT$ACFilter <- sapply(1:nrow(DT), function(x) ifelse((B[x]=="M+H" 
      || (B[x]!="M+H" && A[x]==A[x-1] && C[x]==C[x-1] && B[x-1]=="M+H" && (Area[x] < Area[x-1]))
      || (B[x]!="M+H" && A[x]==A[x-2] && C[x]==C[x-2] && B[x-2]=="M+H" && (Area[x] < Area[x-2])))
      , "Keep", "Discard"))
DT <- DT[ACFilter=="Keep",]
DT$ACFilter <- NULL
DT

DT <- setorder(DT,A,B,C)
DT$ABCFilter <- sapply(1:nrow(DT), function(x) ifelse(C[x]==1 
      || (C[x]==2 && A[x]==A[x-1] && B[x]==B[x-1] && C[x-1]==1) 
      || (C[x]==3 && A[x]==A[x-1] && B[x]==B[x-1] && C[x-1]==1) 
      || (C[x]==3 && A[x]==A[x-2] && B[x]==B[x-2] && C[x-2]==1)
      , "Keep", "Discard"))
DT <- DT[ABCFilter=="Keep",]
DT$ABCFilter <- NULL
DT

我对您使用的规则都不是很清楚。看起来应该保留Area = 11357158的行,因为它比C = 1的相应行小,而Area = 6855539.48777的行应该保留,因为它大于B = M + H的相应行:

    A    B C          Area
1: aa  M+H 1        127427
2: aa M+Na 1 6855539.48777
3: aa M+Na 2       6469689
4: bb  M+H 1      15330650
5: bb  M+H 2        214221
6: bb  M+H 3      11357158
7: bb  M+K 1       2140221