【问题标题】:subset of data frame on based on multiple conditions基于多个条件的数据框子集
【发布时间】:2016-03-19 21:09:02
【问题描述】:

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

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>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)

不幸的是,我在使用子集时遇到了一个错误,因为它无法解析我的字符串语句中的条件。我该怎么办?

【问题讨论】:

  • 问题会比这个大,还是只检查a和b?
  • 是的,问题比这还大,但我想简化它并推广给其他人。有错吗?
  • 我只是在检查。你完全没有错(你是对的),所以一个解决方案应该可以推广到任意数量的规则。
  • 最大的问题是子集步骤。添加更多规则只会在 subdf[i] 中添加其他列

标签: r if-statement dataframe subset


【解决方案1】:

您的问题是您创建了子集:子集命令需要一个布尔值,而您给了它一个字符串。 ('查看')。所以这里最简单的解决方案是添加一个“解析”。我觉得有一种更优雅的方法来解决这个问题,我希望有人能来做,但是你可以用下面的方法修复你的代码的最后部分

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

我添加了 parse/eval 部分以生成布尔向量以仅对“TRUE”情况进行子集化,并添加了对是否可以添加 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

【讨论】:

  • 正是我要找的东西!!!也是无行子集的控制。我真的不知道该怎么感谢你!那么是的,如果解析命令有更优雅的解决方案,那就太好了,但到目前为止已经足够了。我只需在循环中添加finaldf &lt;- data.frame(x=c(),A=c(),B=c(),C=c()) 并在if 语句中将subdf[[i]]&lt;-mysubset 替换为finaldf &lt;- rbind(finaldf,mysubset)
  • 我有一个更优雅的解决方案的想法,将在今天晚些时候进行处理
  • @Stefano done,在 for 循环中创建规则的更高效版本。
  • 非常感谢!!听起来超级优雅!并且出于我的技能... :) 我会适应我的真实情况。再次感谢
  • @Stefano 不客气。尝试使这些事情变得优雅/不易出错,因为您不使用 for 循环并更自动地生成事物是提高技能并让您能够解决不同问题的快速方法。我猜我的解决方案适用于数百个条件,这将很难在您的循环中编程。
猜你喜欢
  • 2018-12-06
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-01
  • 2020-09-26
  • 1970-01-01
相关资源
最近更新 更多