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
差别太大。 要求范围应优化得到最小值和最大值。 diff
和range
都是原始函数。 但时间不是谎言。
> 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
那么所有的元素是相同的