testing单个向量的所有元素之间的相等性

我试图testingvector的所有元素是否相等。 我提出的解决scheme似乎有些迂回,都涉及检查length()

 x <- c(1, 2, 3, 4, 5, 6, 1) # FALSE y <- rep(2, times = 7) # TRUE 

unique()

 length(unique(x)) == 1 length(unique(y)) == 1 

rle()

 length(rle(x)$values) == 1 length(rle(y)$values) == 1 

一个解决scheme可以让我包含一个评估元素之间“平等”的容忍值,是避免FAQ 7.31问题的理想之选。

是否有一个我完全忽略的testingtypes的内置函数? identical()all.equal()比较两个R对象,所以他们不会在这里工作。

编辑1

以下是一些基准testing结果。 使用代码:

 library(rbenchmark) John <- function() all( abs(x - mean(x)) < .Machine$double.eps ^ 0.5 ) DWin <- function() {diff(range(x)) < .Machine$double.eps ^ 0.5} zero_range <- function() { if (length(x) == 1) return(TRUE) x <- range(x) / mean(x) isTRUE(all.equal(x[1], x[2], tolerance = .Machine$double.eps ^ 0.5)) } x <- runif(500000); benchmark(John(), DWin(), zero_range(), columns=c("test", "replications", "elapsed", "relative"), order="relative", replications = 10000) 

结果如下:

  test replications elapsed relative 2 DWin() 10000 109.415 1.000000 3 zero_range() 10000 126.912 1.159914 1 John() 10000 208.463 1.905251 

所以它看起来像diff(range(x)) < .Machine$double.eps ^ 0.5是最快的。

我用这个方法比较了最小值和最大值,除以平均值:

 # Determine if range of vector is FP 0. zero_range <- function(x, tol = .Machine$double.eps ^ 0.5) { if (length(x) == 1) return(TRUE) x <- range(x) / mean(x) isTRUE(all.equal(x[1], x[2], tolerance = tol)) } 

如果你使用这个更严重,你可能想在计算范围和平均值之前删除缺失的值。

如果他们都是数值,那么如果tol是你的容忍,那么…

 all( abs(y - mean(y)) < tol ) 

是解决您的问题。

编辑:

在看了这个以及其他答案之后,并且对一些事情进行基准testing,结果如下,结果出来的速度是迪文答案的两倍。

 abs(max(x) - min(x)) < tol 

这比diff(range(x))有点令人惊讶地快,因为diff不应该和-和两个数字的abs差别太大。 要求范围应优化得到最小值和最大值。 diffrange都是原始函数。 但时间不是谎言。

 > isTRUE(all.equal( max(y) ,min(y)) ) [1] TRUE > isTRUE(all.equal( max(x) ,min(x)) ) [1] FALSE 

另一个沿着同样的路线:

 > diff(range(x)) < .Machine$double.eps ^ 0.5 [1] FALSE > diff(range(y)) < .Machine$double.eps ^ 0.5 [1] TRUE 

为什么不简单地使用方差:

 var(x) == 0 

如果x所有元素都相等,则会得到0的方差。

您可以通过比较第一个元素和其他所有元素来使用identical()all.equal() ,从而有效地扫描比较:

 R> compare <- function(v) all(sapply( as.list(v[-1]), + FUN=function(z) {identical(z, v[1])})) R> compare(x) [1] FALSE R> compare(y) [1] TRUE R> 

这样你可以根据需要添加任何epsilon到identical()

由于我一遍又一遍地回到这个问题,这里是一个Rcpp解决scheme,如果答案实际上是FALSE (因为它会在遇到不匹配的时候会停止),那么Rcpp解决scheme通常比任何R解决scheme都要快得多。如果答案为TRUE则与最快的R解决scheme速度相同。 例如,对于OP基准testing,使用此function, system.time精确值为0。

 library(inline) library(Rcpp) fast_equal = cxxfunction(signature(x = 'numeric', y = 'numeric'), ' NumericVector var(x); double precision = as<double>(y); for (int i = 0, size = var.size(); i < size; ++i) { if (var[i] - var[0] > precision || var[0] - var[i] > precision) return Rcpp::wrap(false); } return Rcpp::wrap(true); ', plugin = 'Rcpp') fast_equal(c(1,2,3), 0.1) #[1] FALSE fast_equal(c(1,2,3), 2) #[2] TRUE 

我专门为此写了一个函数,它不仅可以检查向量中的元素,还可以检查列表中的所有元素是否相同 。 当然,它也很好地处理字符向量和所有其他types的向量。 它也有适当的error handling。

 all_identical <- function(x) { if (length(x) == 1L) { warning("'x' has a length of only 1") return(TRUE) } else if (length(x) == 0L) { warning("'x' has a length of 0") return(logical(0)) } else { TF <- vapply(1:(length(x)-1), function(n) identical(x[[n]], x[[n+1]]), logical(1)) if (all(TF)) TRUE else FALSE } } 

现在尝试一些例子。

 x <- c(1, 1, 1, NA, 1, 1, 1) all_identical(x) ## Return FALSE all_identical(x[-4]) ## Return TRUE y <- list(fac1 = factor(c("A", "B")), fac2 = factor(c("A", "B"), levels = c("B", "A")) ) all_identical(y) ## Return FALSE as fac1 and fac2 have different level order 

你实际上并不需要使用min,mean或max。 根据John的回答:

 all(abs(x - x[[1]]) < tolerance) 

这里有一个使用min,max技巧的替代scheme,但是用于数据框架。 在示例中,我正在比较列,但来自apply的边距参数可以更改为1行。

 valid = sum(!apply(your_dataframe, 2, function(x) diff(c(min(x), max(x)))) == 0) 

如果valid == 0那么所有的元素是相同的