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

kmm*_*kmm 88 equality r vector

我正在尝试测试向量的所有元素是否彼此相等.我提出的解决方案似乎有点迂回,都涉及检查length().

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

unique():

length(unique(x)) == 1
length(unique(y)) == 1
Run Code Online (Sandbox Code Playgroud)

rle():

length(rle(x)$values) == 1
length(rle(y)$values) == 1
Run Code Online (Sandbox Code Playgroud)

一个允许我包含容差值的解决方案,用于评估元素之间的"平等",这是避免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)
Run Code Online (Sandbox Code Playgroud)

结果如下:

          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
Run Code Online (Sandbox Code Playgroud)

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

Joh*_*ohn 39

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

all( abs(y - mean(y)) < tol ) 
Run Code Online (Sandbox Code Playgroud)

是你的问题的解决方案.

编辑:

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

abs(max(x) - min(x)) < tol
Run Code Online (Sandbox Code Playgroud)

这是一个令人惊讶的一点速度比diff(range(x)),因为diff不应该是远远不同-,并abs用两个数字.请求范围应优化获得最小值和最大值.这两个diffrange是原始的功能.但时间不是谎言.


Yoh*_*dia 35

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

var(x) == 0
Run Code Online (Sandbox Code Playgroud)

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

  • `length(unique(x))= 1`最终大约快两倍,但`var`是简洁的,这很好. (11认同)

had*_*ley 34

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

# 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))
}
Run Code Online (Sandbox Code Playgroud)

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


May*_*evy 24

你可以检查 all(v==v[1])

  • 除非你的向量中有“NA”,否则这种方法有效:“x &lt;- c(1,1,NA);” all(x == x[1])` 返回“NA”,而不是“FALSE”。在这种情况下,“length(unique(x)) == 1”有效。 (2认同)

42-*_*42- 21

> isTRUE(all.equal( max(y) ,min(y)) )
[1] TRUE
> isTRUE(all.equal( max(x) ,min(x)) )
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

另一条沿着同样的路线:

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

  • 我试着给人们他们需要的东西,而不是他们想要的东西;)但是要点了. (5认同)
  • @哈德利:OP要求一个允许指定容差的解决方案,大概是因为他不关心非常小的差异.all.equal可以与其他公差一起使用,OP似乎理解这一点. (2认同)
  • 我没有非常清楚地表达自己 - 在我的例子中,最大和最小数字之间存在十倍的相对差异.这可能是你想要注意的事情!我认为数值公差需要相对于数据范围来计算 - 我过去没有这样做,而且它已经引起了问题. (2认同)
  • 我不认为我在最狭隘的时候误解了你.我只是觉得提问者要求的解决方案会忽略实际为零的数字的十倍相对差异.我听到他要求一个可以忽略1e-11和1e-13之间差异的解决方案. (2认同)

Dir*_*tel 14

您可以使用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> 
Run Code Online (Sandbox Code Playgroud)

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

  • 那个循环很棒?;) (9认同)
  • 我喜欢这个应用程序的是它可以与非数字对象一起使用. (4认同)
  • 但是效率却非常低......(在我的电脑上,一百万个数字大约需要10秒钟) (2认同)
  • 毫无疑问.然而,OP正在质疑这是否可以*完全*.做得好是第二步.你知道我站在哪里循环... ;-) (2认同)

edd*_*ddi 10

由于我一遍又一遍地回到这个问题,这里的Rcpp解决方案通常会比任何R解决方案快得多,如果答案是实际的FALSE(因为它会在遇到不匹配的那一刻停止)并具有相同的速度作为答案最快的R解决方案TRUE.例如,对于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
Run Code Online (Sandbox Code Playgroud)


Law*_*Lee 8

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

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
  }
}
Run Code Online (Sandbox Code Playgroud)

现在尝试一些例子.

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
Run Code Online (Sandbox Code Playgroud)


小智 5

您实际上并不需要使用 min、mean 或 max。基于约翰的回答:

all(abs(x - x[[1]]) < tolerance)
Run Code Online (Sandbox Code Playgroud)