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

时间:2011-01-20 20:34:39

标签: r vector equality

我正在尝试测试向量的所有元素是否彼此相等。我提出的解决方案似乎有点迂回,都涉及检查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

允许我在评估元素之间“平等”时使用容差值的解决方案是避免FAQ 7.31问题的理想选择。

我完全忽略了测试类型的内置函数吗? identical()all.equal()比较两个R对象,因此它们无法在此处运行。

修改1

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

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最快。

11 个答案:

答案 0 :(得分:34)

如果它们都是数值,那么如果tol是你的容差那么......

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

是您问题的解决方案。

修改

在查看了这个以及其他答案并对一些事情进行基准测试后,以下内容的速度是DWin答案的两倍。

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

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

答案 1 :(得分:31)

我使用这种方法,在除以平均值后比较最小值和最大值:

# 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))
}

如果你更认真地使用它,你可能想要在计算范围和平均值之前删除缺失值。

答案 2 :(得分:29)

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

var(x) == 0

如果x的所有元素相等,您将得到0的差异。

答案 3 :(得分:20)

> 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

答案 4 :(得分:11)

您可以通过将第一个元素与所有其他元素进行比较来使用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()

答案 5 :(得分:10)

由于我一遍又一遍地回到这个问题,这里的Rcpp解决方案通常会比任何R解决方案快得多,如果答案实际上是FALSE (因为它会在遇到不匹配时停止)并且如果答案是TRUE,则速度与最快的R解决方案相同。例如,对于OP基准测试,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

答案 6 :(得分:6)

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

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

答案 7 :(得分:3)

您实际上不需要使用min,mean或max。 根据约翰的回答:

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

答案 8 :(得分:2)

这里有一个替代方法,使用min,max技巧但是对于数据帧。在示例中,我正在比较列,但apply的margin参数可以更改为1。

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

如果valid == 0则所有元素都相同

答案 9 :(得分:2)

您只需检查all(v==v[1])

答案 10 :(得分:0)

另一种使用 data.table 包、兼容字符串和 NA 的解决方案是 uniqueN(x) == 1