将R中的idential()与多个向量一起使用
假设我有五个向量:将R中的idential()与多个向量一起使用,r,R,假设我有五个向量: A<-1:10 B<-1:10 C<-1:10 D<-1:10 E<-1:12 但是我想一次测试所有这些,看看是否有不同于其他的。有没有一种简单的方法可以做到这一点?首先要做的是对向量列表执行唯一的,并检查长度。如果存在两个或多个不同的向量,则结果列表的长度将大于1 length(unique(list(A,B,C,D))) == 1 [1] TRUE length(unique(list(A,B,C,D,E))) == 1 [1] FALS
A<-1:10
B<-1:10
C<-1:10
D<-1:10
E<-1:12
但是我想一次测试所有这些,看看是否有不同于其他的。有没有一种简单的方法可以做到这一点?首先要做的是对向量列表执行
唯一的,并检查长度。如果存在两个或多个不同的向量,则结果列表的长度将大于1
length(unique(list(A,B,C,D))) == 1
[1] TRUE
length(unique(list(A,B,C,D,E))) == 1
[1] FALSE
我只会选择一个,比如说A
,然后用它进行所有的成对比较
all(sapply(list(B, C, D, E), FUN = identical, A))
# [1] FALSE
移除all()
以查看不相同的
idential
应该是可传递的,因此如果A
与C
和D
相同,那么C
应该与D
相同
(感谢@docendo discimus简化了语法。)另一个选择,只是为了好玩:
Vectorize(identical, 'x')(list(A, B, C, D, E), C)
这是很明显的,但是:如果有很多元素并且很有可能失败,那么您将希望能够缩短比较。下面是一个循环,并举例说明:
A = sample(1e3)
Alist <- replicate(1e6,A,simplify=FALSE)
Alist[[2]][1e3] <- 0
system.time({brkres <- {
ok=TRUE
for (i in seq_along(Alist)) if( !identical(Alist[[1]],Alist[[i]]) ){
ok=FALSE
break
}
ok
}})
# user system elapsed
# 0 0 0
system.time({allres <- all(sapply(Alist[-1], FUN = identical, Alist[[1]]))})
# user system elapsed
# 1.66 0.03 1.68
A=样本(1e3)
Alist我也有同样的问题,但决定实施一个基于Reduce
和基于双for
循环的解决方案
职能:
all_elements_the_same = function(list) {
#func to compare with
comparison_func = function(x, y) {
if (!identical(x, y)) stop() #stop function if it finds a non-identical pair
y #return second element
}
#run comparisons
trial = try({
Reduce(f = comparison_func, x = list, init = list[[1]])
}, silent = T)
#return
if (class(trial) == "try-error") return(F)
T
}
all_elements_the_same2 = function(list, ignore_names = F) {
#double loop solution
for (i in seq_along(list)) {
for (j in seq_along(list)) {
#skip if comparing to self or if comparison already done
if (i >= j) next
#check
if (!identical(list[[i]], list[[j]])) return(F)
}
}
T
}
测试对象:
l_testlist_ok = list(1:3, 1:3, 1:3, 1:3, 1:3, 1:3)
l_testlist_bad = list(1:3, 1:3, 1:4, 1:3, 1:3, 1:3)
l_testlist_bad2 = list(1:3, 1:3, 1:4, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3, 1:3)
测试功能:
> all_elements_the_same(l_testlist_ok)
[1] TRUE
> all_elements_the_same(l_testlist_bad)
[1] FALSE
> all_elements_the_same(l_testlist_bad2)
[1] FALSE
> all_elements_the_same2(l_testlist_ok)
[1] TRUE
> all_elements_the_same2(l_testlist_bad)
[1] FALSE
> all_elements_the_same2(l_testlist_bad2)
[1] FALSE
测试时间使用:
> library(microbenchmark)
> microbenchmark(all_elements_the_same(l_testlist_ok),
+ all_elements_the_same(l_testlist_bad),
+ all_elements_the_same(l_testlist_bad2),
+ all_elements_the_same2(l_testlist_ok),
+ all_elements_the_same2(l_testlist_bad),
+ all_elements_the_same2(l_testlist_bad2), times = 1e4)
Unit: microseconds
expr min lq mean median uq max neval
all_elements_the_same(l_testlist_ok) 19.310 25.454 28.309016 26.917 28.380 1003.228 10000
all_elements_the_same(l_testlist_bad) 93.624 100.938 108.890823 103.863 106.497 3130.807 10000
all_elements_the_same(l_testlist_bad2) 93.331 100.938 107.963741 103.863 106.497 1181.404 10000
all_elements_the_same2(l_testlist_ok) 48.275 53.541 57.334095 55.881 57.930 926.866 10000
all_elements_the_same2(l_testlist_bad) 6.144 7.315 8.437603 7.900 8.778 998.839 10000
all_elements_the_same2(l_testlist_bad2) 6.144 7.315 8.564780 8.192 8.778 1323.594 10000
显然,try
部分大大降低了速度。如果对象非常大,使用Reduce
变量仍然可以节省时间,但是对于较小的对象,使用双for
循环似乎是一种可行的方法。使用Rcpp
的最快、最简单的解决方案:
#包括
使用名称空间Rcpp;
内联布尔相同(SEXP a,SEXP b){
返回R_compute_idential(a,b,0);
}
//[[Rcpp::导出]]
布尔完全相同(列表x){
std::size_t n=x.size();
对于(标准::尺寸i=1;i identical2我很喜欢这个答案的优雅,但我要把@Gregor的评为最好的。@Andy,这是一个更好的答案,因为它仍然使用idential
。我应该想到传递性比较:PA的一个小小改进是在sapply()前面使用all()函数,以便它返回一个true/false。
> all_elements_the_same(l_testlist_ok)
[1] TRUE
> all_elements_the_same(l_testlist_bad)
[1] FALSE
> all_elements_the_same(l_testlist_bad2)
[1] FALSE
> all_elements_the_same2(l_testlist_ok)
[1] TRUE
> all_elements_the_same2(l_testlist_bad)
[1] FALSE
> all_elements_the_same2(l_testlist_bad2)
[1] FALSE
> library(microbenchmark)
> microbenchmark(all_elements_the_same(l_testlist_ok),
+ all_elements_the_same(l_testlist_bad),
+ all_elements_the_same(l_testlist_bad2),
+ all_elements_the_same2(l_testlist_ok),
+ all_elements_the_same2(l_testlist_bad),
+ all_elements_the_same2(l_testlist_bad2), times = 1e4)
Unit: microseconds
expr min lq mean median uq max neval
all_elements_the_same(l_testlist_ok) 19.310 25.454 28.309016 26.917 28.380 1003.228 10000
all_elements_the_same(l_testlist_bad) 93.624 100.938 108.890823 103.863 106.497 3130.807 10000
all_elements_the_same(l_testlist_bad2) 93.331 100.938 107.963741 103.863 106.497 1181.404 10000
all_elements_the_same2(l_testlist_ok) 48.275 53.541 57.334095 55.881 57.930 926.866 10000
all_elements_the_same2(l_testlist_bad) 6.144 7.315 8.437603 7.900 8.778 998.839 10000
all_elements_the_same2(l_testlist_bad2) 6.144 7.315 8.564780 8.192 8.778 1323.594 10000
Unit: microseconds
expr min lq mean median uq max neval cld
identical2(A, B, C, D, E) 3.401 4.3065 5.32136 5.1245 5.5420 21.529 100 a
identical3(A, B, C, D, E) 6.480 7.8675 9.20970 8.3875 9.0175 26.739 100 b
identical4(A, B, C, D, E) 12.233 13.5680 15.48014 14.7755 15.5455 48.333 100 c
identical5(A, B, C, D, E) 90.177 93.1480 98.79570 95.2685 103.2765 178.657 100 e
identical6(A, B, C, D, E) 10.683 12.0650 13.43184 12.6820 13.4060 22.314 100 c
identical7(A, B, C, D, E) 28.202 31.0800 34.97819 32.4630 39.4960 68.902 100 d