基于多个条件的数据帧子集

时间:2015-12-14 11:40:18

标签: r if-statement dataframe subset

我实际上遇到了代码中特定任务的问题。我有一个数据框

n  <- 6
set.seed(123)
df <- data.frame(x=paste0("x",seq_along(1:n)), A=sample(c(-2:2),n,replace=TRUE), B=sample(c(-1:3),n,replace=TRUE))
#
#    x  A B
# 1 x1 -1 1
# 2 x2  1 3
# 3 x3  0 1
# 4 x4  2 1
# 5 x5  2 3
# 6 x6 -2 1

和决策树

A>0;Y;Y;N;N
B>1;Y;N;Y;N
C;1;2;2;1

我加载

dt <- read.csv2("tmp.csv", header=FALSE)

我想为(A> 0)和(B&gt; 1)的所有可能组合创建一个循环,并将C值设置为满足该条件的子集x列。所以,这就是我做的事情

nr <- 3
nc <- 5

cond <- dt[1:(nr-1),1,drop=FALSE]
rule <- dt[nr,1,drop=FALSE]

subdf <- vector(mode="list",2^(nr-1))

for (i in 2:nc) {
  check <- paste0("")
  for (j in 1:(nr-1)) {
    case <- paste0(dt[j,1])
    if (dt[j,i]=="N")
      case <- paste0("!",case)
    check <- paste0(check, "(", case, ")" )

    if (j<(nr-1))
      check <- paste0(check, "&")

  }

  subdf[i]   <- subset(df,check)
  subdf[i]$C <- dt[nr,i]

}
unlist(subdf)

不幸的是,我因此使用子集时出错,它无法解析我的字符串语句中的条件。我该怎么办?

1 个答案:

答案 0 :(得分:1)

你的问题是你创建的子集:子命令需要一个布尔值,你给它一个字符串。 (&#39;检查&#39)。所以这里最简单的解决方案是添加一个解析&#39;。我觉得有一种更优雅的方法可以解决这个问题,我希望有人能够一起来做,但你可以使用以下内容修复代码的最后部分

 mysubset  <- subset(df,with(df,eval(parse(text=check))))
  if(nrow(mysubset)>0){
    mysubset$C <-  dt[nr,i]
  } 
  subdf[[i]]<-mysubset

我添加了解析/评估部分以生成布尔值向量,仅对“&TRUE”字符进行子集化。 case,并添加了一个是否可以添加C的检查(如果没有行,将给出错误)。

基于之前的回答,我想出了一种更优雅/实用的方法来生成组合规则的向量,然后使用apply / lapply将它们全部应用于数据。

##create list of formatted rules

#format each 'building' block separately, 
#based on rows in 'dt'.
part_conditions <- apply(dt[-nrow(dt),],MARGIN=1,FUN=function(x){
  res <- sprintf("(%s%s)", ifelse(x[-1]=="Y","","!"), x[1])
})

# > part_conditions
# 1        2       
# [1,] "(A>0)"  "(B>1)" 
# [2,] "(A>0)"  "(!B>1)"
# [3,] "(!A>0)" "(B>1)" 
# [4,] "(!A>0)" "(!B>1)"

#combine to vector of conditions
conditions <- apply(part_conditions, MARGIN=1,FUN=paste, collapse="&")

# > conditions
# [1] "(A>0)&(B>1)"   "(A>0)&(!B>1)"  "(!A>0)&(B>1)"  "(!A>0)&(!B>1)"

#for each condition, test in data wheter condition is 'T'
temp <- sapply(conditions, function(rule){
  return(with(df, eval(parse(text=rule))))
}
)


rules <- as.numeric(t(dt[nrow(dt),-1]))

#then find which of the (in this case) four is 'T', and put the appropriate rule
#in df
df$C <- rules[apply(temp,1,which)]
> df
   x  A B C
1 x1 -1 1 1
2 x2  1 3 1
3 x3  0 1 1
4 x4  2 1 2
5 x5  2 3 1
6 x6 -2 1 1