단일 벡터의 모든 요소가 같은지 테스트


101

벡터의 모든 요소가 서로 같은지 테스트하려고합니다. 내가 생각해 낸 솔루션은 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가장 빠른 것 같습니다 .

답변:


37

평균으로 나눈 후 최소값과 최대 값을 비교하는이 방법을 사용합니다.

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

이것을 더 심각하게 사용한다면 범위와 평균을 계산하기 전에 누락 된 값을 제거하고 싶을 것입니다.


나는 Dirk보다 빠르기 때문에 이것을 선택했습니다. 수백만 개의 요소가 없지만 이것은 나를 위해 조금 더 빨리 실행될 것입니다.
kmm 2011 년

@Kevin : John의 솔루션은 어떻습니까? Hadley보다 ~ 10 배 빠르며 허용 오차를 설정할 수 있습니다. 다른 방식으로 부족합니까?
Joshua Ulrich

몇 가지 벤치마킹을 제공하십시오. 방금 내 것이 백만 개의 유니폼 벡터에 대해 거의 동일한 지 확인했습니다.
hadley

@hadley : 나는 달리고 있었는데, OP에서 온 system.time(for(i in 1:1e4) zero_range(x))x이었습니다. 요한의 솔루션 ~ 10 배이다 x빨라 ~ 3 배 y약간 느린을위한 runif(1e6).
Joshua Ulrich

0.00023 초와 0.000023 초 사이의 차이를 볼 때 10 배의 차이는 그다지 중요하지 않습니다. DWin은 아마도 지정된 허용 오차 수준과 동일하다고 주장 할 것입니다.)
hadley

46

단순히 분산을 사용하지 않는 이유 :

var(x) == 0

의 모든 요소 x가 같으면의 분산을 얻습니다 0.


17
length(unique(x))=1결국 약 두 배 빠르지 만 var간결합니다.
AdamO

YohanBadia, 배열 c (-5.532456e-09, 1.695298e-09)가 있고 John test: TRUE ; DWin test: TRUE ; zero-range test: TRUE ; variance test: FALSE다른 모든 테스트가 R에서 값이 동일하다는 것을 인식한다는 의미를 얻 습니다. 그 맥락에서 분산 테스트를 어떻게 사용할 수 있습니까?
mjs

배열의 두 값이 동일하지 않습니다. 테스트가 반환되기를 원하는 이유는 무엇 TRUE입니까? John의 답변의 경우 차이가 특정 임계 값을 초과하는지 확인합니다. 귀하의 경우 두 값의 차이가 매우 낮기 때문에 정의한 임계 값 아래로 떨어질 수 있습니다.
Yohan Obadia

41

모두 숫자 값이면 tol이 허용 오차이면 ...

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

귀하의 문제에 대한 해결책입니다.

편집하다:

이것과 다른 답변을 살펴보고 몇 가지를 벤치마킹 한 후 DWin 답변보다 두 배 빠른 속도로 다음이 나옵니다.

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

이것은 조금 놀라 울 정도로 빠르게보다 diff(range(x))이후 diff보다 훨씬 다른 안 -abs두 개의 번호. 범위를 요청하면 최소값과 최대 값을 최적화해야합니다. diff및 둘 다 range기본 함수입니다. 하지만 타이밍은 거짓말이 아닙니다.


평균을 뺀 것과 평균을 뺀 것의 상대적인 장점에 대해 말씀해 주시겠습니까?
hadley 2011 년

계산적으로 더 간단합니다. 시스템 및 R이 컴파일되고 벡터화되는 방식에 따라 더 적은 전력 소비로 더 빠르게 수행됩니다. 또한 평균으로 나눌 때 테스트 결과는 1에 상대적인 반면 뺄셈을 사용하면 0이됩니다. 또한 허용 오차는보다 직접적인 해석이 있습니다.

1
그러나 범위를 추출하는 데 필요한 검색 및 정렬이 단순한 빼기보다 계산 비용이 훨씬 많이 들기 때문에 나누기가 복잡하지는 않습니다. 나는 그것을 테스트했고 위의 코드는 zero_range 함수 Hadley보다 약 10 배 더 빠릅니다 (그리고 여기에서 가장 빠른 정답입니다). Dirk의 비교 기능은 엄청나게 느립니다. 이것이 가장 빠른 대답입니다.

방금 귀하의 답변에서 Josh의 타이밍 댓글을 보았습니다. Hadley ... 나는 zero_range가 더 빠른 상황을 얻지 못했습니다. 이 답변의 경우 불일치는 약간 더 빠름 (아마도 20 %)에서 항상 10 배 사이입니다. 여러 가지 방법을 시도했습니다.

24
> 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

나는 이것이 아주 작은 숫자에 대해 그렇게 잘 작동하지 않는다고 생각합니다 :x <- seq(1, 10) / 1e10
hadley

2
@Hadley : OP는 허용 오차를 지정할 수있는 솔루션을 요청했습니다. 아마도 그는 아주 작은 차이를 신경 쓰지 않았기 때문일 것입니다. all.equal은 다른 공차와 함께 사용할 수 있으며 OP는 이것을 이해하는 것으로 보입니다.
IRTFM 2011 년

2
나는 내 자신을 매우 명확하게 표현하지 않았습니다. 내 예에서는 가장 큰 숫자와 가장 작은 숫자 사이에 10 배의 상대적 차이가 있습니다. 그것은 아마도 당신이 주목하고 싶은 것입니다! 수치 공차는 데이터의 범위를 기준으로 계산해야한다고 생각합니다. 과거에이 작업을 수행 한 적이 없으며 문제가 발생했습니다.
hadley

2
나는 내가 당신을 가장 슬프게 오해했다고 생각하지 않습니다. 나는 단지 질문자가 사실상 0 인 숫자에 대해 10 배의 상대적 차이를 무시하는 해결책을 요구하고 있다고 생각했습니다. 나는 그가 1e-11과 1e-13의 차이를 무시할 해결책을 요구한다고 들었다.
IRTFM 2011 년

5
나는 사람들에게 그들이 원하는 것이 아니라 필요한 것을 제공하려고 노력하고 있습니다.
hadley

16

첫 번째 요소를 다른 모든 요소 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> 

이렇게하면 identical()필요에 따라 엡실론을 추가 할 수 있습니다 .


2
무시 무시하게 비효율적하지만 ... (내 컴퓨터에 백만 숫자 십초 정도 걸립니다)
해들리

2
의심 할 여지가 없습니다. 그러나 OP는 이것이 전혀 행해질 수 있는지 의문이었다 . 잘하는 것은 두 번째 단계입니다. 그리고 당신은 ;-) ... 내가 루프가 어디에 서 있는지 알
더크 Eddelbuettel

10
그 루프는 굉장합니까? ;)
hadley 2011 년

4
이 접근 방식에 대해 내가 좋아하는 점은 숫자가 아닌 개체와 함께 사용할 수 있다는 것입니다.
Luciano Selzer 2013 년

compare <-function (v) all (sapply (as.list (v [-1]), FUN = function (z) {isTRUE (all.equal (z, v [1])}))
N. McA .

16

그냥 확인할 수 있습니다 all(v==v[1])


이것은 문자열과 함께 작동하는 훌륭한 BC입니다! 감사합니다
arvi1000

이 작품, 당신은하지 않는 NA당신의 벡터에 : x <- c(1,1,NA); all(x == x[1])반환 NA하지 FALSE. 이러한 경우 length(unique(x)) == 1작동합니다.
HBat

11

이 질문에 계속해서 계속 돌아 오므로 대답이 실제로 (불일치가 발생하는 순간 멈출 것이기 때문에) 동일한 속도를 가질 경우 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

1
이것은 속도면에서 좋고 +1이지만 모든 요소를 ​​첫 번째 요소와 비교하는 것이 옳다고 확신하지 못합니다. 벡터는이 테스트를 통과 할 수 있지만 max (x)와 min (x)의 차이는 정밀도보다 큽니다. 예를 들어fast_equal(c(2,1,3), 1.5)
dww

@dww 당신이 지적하는 것은 정밀도 문제가있을 때 비교가 전 이적이지 않다는 것입니다. 즉 a == b, 부동 소수점 비교를 수행 b == c하는 a == c경우 반드시 암시하는 것은 아닙니다 . 이 문제를 피하기 위해 정밀도를 요소 수로 나누거나 알고리즘을 수정하여 계산 min하고 max중지 조건으로 사용할 수 있습니다.
eddi

10

나는 벡터의 요소뿐만 아니라 목록의 모든 요소가 동일한 지 확인할 수있는 함수를 특별히 작성했습니다 . 물론 문자형 벡터와 다른 모든 유형의 벡터도 잘 처리합니다. 또한 적절한 오류 처리 기능이 있습니다.

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

4

실제로 최소, 평균 또는 최대를 사용할 필요는 없습니다. John의 대답에 따라 :

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

3

여기에 최소, 최대 트릭을 사용하지만 데이터 프레임에 대한 대안이 있습니다. 이 예에서는 열을 비교하고 있지만 행의 여백 매개 변수 apply를 1로 변경할 수 있습니다.

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

그렇다면 valid == 0모든 요소가 동일 하다면

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.