我正在尝试将多个条件应用于data.frame的多个列,其中条件i应该应用于列i,即应用条件取决于我所在的列。我有一个工作解决方案,但它有两个主要缺点是,它在大数据上可能会变慢,因为它使用for循环并且它需要两个输入向量"列将条件应用于"和"要应用的条件"以相同的顺序。我设想了一种利用快速数据纠缠包功能的解决方案,例如dplyr,data.table,并且在参数向量元素的顺序方面更灵活。一个例子应该说清楚(这里条件只是一个阈值测试,但在更大的问题中,它可能是一个涉及数据集变量的更复杂的布尔表达式。)
t <- structure(list(a = c(2L, 10L, 10L, 10L, 3L),
b = c(5L, 10L, 20L, 20L, 20L),
c = c(100L, 100L, 100L, 100L, 100L)),
.Names = c("a", "b", "c"),
class = "data.frame",
row.names = c(NA, -5L))
foo_threshold <-
function(data, cols, thresholds, condition_name){
df <- data.frame(matrix(ncol = length(cols), nrow = nrow(data)))
colnames(df) <- paste0(cols, "_", condition_name)
for (i in 1:length(cols)){
df[,i] <- ifelse(data[,i] > thresholds[i],T,F)
}
return(df)
}
foo_threshold(data = t, cols = c("a", "b"), thresholds = c(5, 18),
condition_name = "bigger_threshold")
我试图在dplyr链中解决它但是我无法正确传递参数向量,即如何明确表示他应该将条件i应用于列i。下面是我要去的插图。它没有工作,它错过了一些观点,但我认为它说明了我想要实现的目标。请注意,这里假设条件位于data.frame中,其中列变量保存col名称,并且通过查找(dplyr filer + select chain)提取阈值。
foo_threshold <- function(data, cols, thresholds, cond_name) {
require(dplyr)
# fun to evaluate boolean condition
foo <- function(x) {
threshold <- thresholds %>% filter(variable==x) %>% select(threshold)
temp <- ifelse(x > threshold, T, F)
return(temp)
}
vars <- setNames(cols, paste0(cols,"_",cond_name))
df_out <-
data %>%
select_(.dots = cols) %>%
mutate_(funs(foo(.)), vars) %>%
select_(.dots = names(vars))
return(df_out)
}
# create threshold table
temp <-
data.frame(variable = c("a", "b"),
threshold = c(5, 18),
stringsAsFactors = F)
# call function (doesn't work)
foo_threshold(data = t, thresholds = temp, cond_name = "bigger_threshold")
编辑:条件的@thepule data.frame可能如下所示,其中x是列。因此,对每个条件的相应列的每一行进行评估。
conditions <-
data.frame(variable = c("a", "b"),
condition = c("x > 5 and x < 10", "!x %in% c("o", "p")"),
stringsAsFactors = F)
答案 0 :(得分:2)
使用扫描代替mapply进行了另一次尝试。离开之前的答案,因为我觉得它增加了显示效率低下的价值。 这个新的答案似乎比OP快两倍。我认为它比当前最好的答案要慢一点,但代码稍微简洁一些。
如果您愿意接受结果作为矩阵而不是data.frame,它运行得更快。
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath){
switch (indexPath.row) {
case 0:
self.performSegueWithIdentifier("box", sender: self)
case 1:
self.performSegueWithIdentifier("box1", sender: self)
default:
break
}
}
答案 1 :(得分:1)
试试这个:
library(dplyr)
foo_threshold <-
function(data, cols, thresholds, condition_name){
temp <- rbind(data[,cols], thresholds) %>%
lapply(function(x) x[1:length(x)-1] > last(x)) %>% data.frame()
colnames(temp) <- paste0(cols, "_", condition_name)
return(temp)
}
foo_threshold(data = t, cols = c("a", "b"), thresholds = c(5, 18),
condition_name = "bigger_threshold")
为了测试哪个更快:
test <- data.frame(a = runif(10000000), b = runif(10000000), stringsAsFactors = F)
lapply(list(foo_threshold_original, foo_threshold),
function(x) system.time(x(data = test, cols = c("a", "b"), thresholds = c(0.5, 0.8),
condition_name = "bigger_threshold")))
其中foo_threshold_original是您的初始版本。 结果是:
[[1]]
user system elapsed
3.95 0.64 4.58
[[2]]
user system elapsed
1.73 0.24 1.96
因此新版本在更大的数据帧上实际上更快。
答案 2 :(得分:1)
最后尝试回答。试图使代码更通用,以便它可以接受任意函数。很好,它似乎比我之前的任何答案都要快得多。如果我犯了一个愚蠢的错误,我也很累。
temp <- structure(list(a = c(2L, 10L, 10L, 10L, 3L),
b = c(5L, 10L, 20L, 20L, 20L),
c = c(100L, 100L, 100L, 100L, 100L)),
.Names = c("a", "b", "c"),
class = "data.frame",
row.names = c(NA, -5L))
condition <- c(function(x) x> 5 ,
function(x) x > 18 )
foo_threshold <- function ( data , cols , threshold , condition_name ) {
dat <- data[0]
for ( i in 1:length(condition)) dat[cols[i]] <- condition[[i]]( data[[cols[i]]] )
names(dat) <- paste0( cols , "_" , condition_name)
return(dat)
}
foo_threshold(data = temp, cols = c("a", "b"), threshold = condition ,
condition_name = "bigger_threshold")
答案 3 :(得分:0)
这个怎么样?不使用dplyr(我加载它无论如何使用管道)
library(dplyr)
foo_threshold <- function( data , cols , thresholds , condition_name){
dat <- mapply( function(x , val) x > val , data[cols] , thresholds ) %>% as.data.frame
names(dat) <- paste0(names(dat) , "_" , condition_name)
return(dat)
}
编辑:简化