我正在使用一系列变量的expand.grid,但是有些特殊情况可以排除。 搜索显示expand.grid无法做到这一点,但是可以添加过滤器,因此这是我的尝试。
a = 1:5
b = 1:5
c = 0:3
d = 1:5
e = 1:3
df = expand.grid(a,b,c,d,e)
colnames(df)[c(1:5)] <- c("a","b","c","d","e");
df$d = ifelse(df$c == 0, d[[1]], df$d);
df$e = ifelse(df$c == 0, d[[1]], df$e);
df = unique(df)
在这种情况下,如果c为0,则不使用变量d和e,因此我使用ifelse将d和e设置为d和e的第一个值(如果c = 0),然后删除具有唯一性的重复行。
上面的代码确实有效,所以出了什么问题。太具体了。
我不喜欢针对特定变量的2条ifelse语句。如果我有100个条件变量,该怎么办。如何压缩语句,并可能仅在一行中写出依赖于任一条件的所有条件或变量。
我也欢迎任何其他优化以复杂场景的最少编码来完成所需任务。谢谢。
更新
到目前为止,在运行时之前我根本不知道变量的数量。我的例子是一个非常基本的例子。通常,我会得到很好的解决方案,但这些解决方案仅适用于特定示例,而并非真正的问题。
我没有从头到尾的集合,或者直到运行时才知道有多少集合或集合的大小。 a可能是文件夹列表,b是子文件夹列表,c文件。但是如果文件很小或者是空的,我就不需要做e和f了。
理想的解决方案不考虑任何静态值,例如:
expand.grid(变量列表,键变量=键值,依赖列表)
是的,这超出了此问题的范围,但是我只是想说解决方案需要处理编码时未知的数据集。
希望这可以解决一些问题,而不仅仅是提出更多问题。
答案 0 :(得分:2)
我们可以使用crossing
library(tidyr)
library(dplyr)
crossing(a, b, c, d, e) %>%
mutate_at(vars(d, e), ~ replace(., c == 0, first(.))) %>%
distinct
答案 1 :(得分:1)
这是另一种基本的R方式。它使用逻辑索引来修改列d
和e
,其余代码与问题类似。下面的测试表明这是最快的选择。
f1 <- function(a, b, c, d, e){
X <- expand.grid(a, b, c, d, e)
names(X) <- c("a","b","c","d","e")
X$d <- ifelse(X$c == 0, X$d[1], X$d)
X$e <- ifelse(X$c == 0, X$d[1], X$e)
unique(X)
}
f2 <- function(a, b, c, d, e){
X <- expand.grid(a, b, c, d, e)
names(X) <- c("a","b","c","d","e")
i <- X$c == 0
X$d[i] <- X$d[1]
X$e[i] <- X$e[1]
unique(X)
}
library(tidyr)
library(dplyr)
f3 <- function(a, b, c, d, e){
crossing(a, b, c, d, e) %>%
mutate_at(vars(d, e), ~ replace(., c == 0, first(.))) %>%
distinct
}
a = 1:5
b = 1:5
c = 0:3
d = 1:5
e = 1:3
library(microbenchmark)
mb <- microbenchmark(
op = f1(a,b,c,d,e),
rui = f2(a,b,c,d,e),
akrun = f3(a,b,c,d,e)
)
print(mb, unit = "relative", order = "median")
#Unit: relative
# expr min lq mean median uq max neval cld
# rui 1.0000000 1.000000 1.000000 1.000000 1.000000 1.000000 100 a
# op 0.8147996 1.035322 1.018649 1.026295 1.038269 1.096384 100 a
# akrun 1.7580304 1.815582 1.836061 1.827887 1.872767 1.107545 100 b