我有一组以表格形式提供的IF条件。例如。
rule_id number colour shape
1 1 200
2 2 100 triangle
3 3 NA red
4 4 NA ‘blue’,‘orange’ rectangle
5 5 NA green Not(‘triangle’,‘square’)
6 6 NA
需要按如下方式读取表格(伪代码):
如果number = 200
那么rule_id = 1
IFELSE number = 100 AND shape = triangle
然后rule_id = 2
IFELSE colour = red
然后rule_id = 3
.....
然后,我有兴趣根据这些规则对数据集中的行进行分类。例如。 (rule_id
是分类的结果)
number colour shape rule_id
1 100 red triangle 2
2 200 yellow none 1
3 300 blue none 6
4 200 none none 1
5 100 red square 3
6 500 green circle 5
7 400 green square 6
8 600 none none 6
为了做到这一点,我使用了一个遍历所有规则的FOR循环(我将所有满足条件rule_id = 1
的行分类,然后转到rule_id = 2
的下一次迭代)。遗憾的是,这似乎是一个非常缓慢的过程(我的规则表和我的数据集的尺寸都要大得多)。
有更好的方法吗?
而且,我如何才能最好地处理规则表中的Not
?
我使用的代码(可能不是美女......):
rules = data.frame(rule_id = 1:6,
number = c(200, 100, rep(NA,4)),
colour = c('', '', 'red', paste(sQuote('blue'), sQuote('orange'), sep = ','), 'green', ''),
shape = c('', 'triangle','','rectangle', paste(paste('Not(', sQuote('triangle'), sep = ''),
paste(sQuote('square'), ')', sep = ''), sep = ','), ''),
stringsAsFactors = FALSE)
data = data.frame(number = c(100, 200, 300, 200, 100, 500, 400, 600),
colour = c('red', 'yellow', 'blue', 'none', 'red', 'green', 'green', 'none'),
shape = c('triangle', 'none', 'none', 'none', 'square', 'circle', 'square', 'none'),
stringsAsFactors = FALSE)
data$rule_id = NA
nbrRules = nrow(rules)
for (j in 1:nbrRules){
data$rule_id[is.na(data$rule_id)
& (data$number == rules$number[j]
| is.na(rules$number[j]))
& ((apply(as.data.frame(data$colour),
1,
function(x) grepl(x, rules$colour[j]))
& (!grepl("Not", rules$colour[j])))
| (apply(as.data.frame(data$colour),
1,
function(x) !grepl(x, rules$colour[j]))
& (grepl("Not", rules$colour[j])))
| (rules$colour[j] == ""))
& ((apply(as.data.frame(data$shape),
1,
function(x) grepl(x, rules$shape[j]))
& (!grepl("Not", rules$shape[j])))
| (apply(as.data.frame(data$shape),
1,
function(x) !grepl(x, rules$shape[j]))
& (grepl("Not", rules$shape[j])))
| (rules$shape[j] == ""))] = rules$rule_id[j]
}
更新
我没有时间实施@alexis_laz他的建议,但他让我意识到,通过反向for (j in nbrRules:1)
而不是for (j in 1:nbrRules)
循环规则可能会获得一些时间。这允许我从
is.na(data$rule_id)
过滤器
data$rule_id[is.na(data$rule_id)
& (data$number == rules$number[j]
| is.na(rules$number[j]))
....
在我应用它的实际数据集上,它导致了一个小的增益(从3.978148分钟到3.972381分钟)。
我也意识到我的评论是错误的,@ Oliver Frost他的ifelse
建议不会导致更多的条件。然而,将代码更改为此导致程序更慢(在我的实际数据集上为4.079141分钟)
for (j in 1:nbrRules){
data$rule_id = ifelse(is.na(data$rule_id)
& (data$number == rules$number[j]
| is.na(rules$number[j]))
& ((apply(as.data.frame(data$colour),
1,
function(x) grepl(x, rules$colour[j]))
& (!grepl("Not", rules$colour[j])))
| (apply(as.data.frame(data$colour),
1,
function(x) !grepl(x, rules$colour[j]))
& (grepl("Not", rules$colour[j])))
| (rules$colour[j] == ""))
& ((apply(as.data.frame(data$shape),
1,
function(x) grepl(x, rules$shape[j]))
& (!grepl("Not", rules$shape[j])))
| (apply(as.data.frame(data$shape),
1,
function(x) !grepl(x, rules$shape[j]))
& (grepl("Not", rules$shape[j])))
| (rules$shape[j] == ""))
,rules$rule_id[j],
data$rule_id)
}