単一のベクトルのすべての要素が等しいかどうかをテストする


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の問題を回避するのに理想的です。

私が完全に見落としたタイプのテスト用の組み込み関数はありますか?2つのRオブジェクトidentical()all.equal()比較するため、ここでは機能しません。

編集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))
}

これをより真剣に使用している場合は、範囲と平均を計算する前に欠損値を削除することをお勧めします。


ダークより速いのでこれを選びました。何百万もの要素はありませんが、これは少し速く実行されるはずです。
kmm 2011年

@ケビン:ジョンの解決策はどうですか?Hadleyの最大10倍の速さで、許容誤差を設定できます。他の方法で不足していますか?
Joshua Ulrich

いくつかのベンチマークを提供してください-私がチェックしたのは、100万のユニフォームのベクトルでほぼ同じであることを確認しました。
ハドリー2011年

@hadley:私は走っていたsystem.time(for(i in 1:1e4) zero_range(x))、どこxからOPから。Johnのソリューションは、〜の場合は〜10倍、の場合は〜3倍x高速y、わずかに低速ですrunif(1e6)
ジョシュアウルリッヒ

0.00023秒と0.000023秒の違いを見ている場合、10倍の違いはそれほど重要ではありません。DWinはおそらく、それらが指定された許容範囲と同じであると主張します;)
hadley

46

なぜ単に分散を使用しないのですか?

var(x) == 0

のすべての要素xが等しい場合、分散はになり0ます。


17
length(unique(x))=1最終的にvarは約2倍の速度になりますが、簡潔でいいです。
AdamO 2017

YohanBadia、配列c(-5.532456e-09、1.695298e-09)があり、John test: TRUE ; DWin test: TRUE ; zero-range test: TRUE ; variance test: FALSE他のすべてのテストはRで値が同一であることを認識していることを意味します。そのコンテキストで分散テストをどのように使用できますか?
mjs

配列の2つの値は同一ではありません。なぜテストに戻りたいのTRUEですか?Johnの回答の場合、その差が特定のしきい値を超えているかどうかを確認します。あなたの場合、2つの値の差は非常に小さいため、定義したしきい値を下回る可能性があります。
Yohan Obadia

41

それらがすべて数値の場合、tolが許容範囲であれば...

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

あなたの問題の解決策です。

編集:

これと他の答えを見て、いくつかのことをベンチマークした後、以下はDWinの答えの2倍の速さで出てきます。

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

これは、2つの数値とほとんど変わらないはずなのでdiff(range(x))、これよりも少し驚くほど高速です。範囲を要求すると、最小値と最大値の取得が最適化されます。とはどちらもプリミティブ関数です。しかし、タイミングはありません。diff-absdiffrange


平均で除算するのと比較して平均を差し引くことの相対的なメリットについてコメントできますか?
ハドリー、2011年

計算が簡単です。システム、およびRのコンパイルとベクトル化の方法に応じて、より少ない消費電力でより高速に実行されます。また、平均で除算すると、テスト結果は1に対して相対的ですが、減算では0になります。また、許容誤差の解釈はより簡単です。
John

1
ただし、範囲を抽出するために必要な検索と並べ替えは、単純な減算よりもはるかに計算コストがかかるため、除算が複雑になるほどで​​はありません。私はそれをテストしました、そして上記のコードはzero_range関数Hadleyよりも約10倍高速です(そしてあなたのものがここで最も速い正しい答えについてです)。ダークの比較機能は、非常に遅いです。これがここで最も速い答えです。
John

回答のHadleyでJoshのタイミングコメントを見ただけです... zero_rangeの方が速い状況はありません。この答えの場合、差異はわずかに速い(おそらく20%)から10倍の間です。それはいくつかの方法を試しました。
John

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
ハドレー

2
@Hadley:OPは、おそらく非常に小さな違いを気にしていないため、公差の指定を可能にするソリューションを求めました。all.equalは他の許容範囲で使用でき、OPはこれを理解しているようです。
IRTFM、2011年

2
私は自分をはっきりと表現していませんでした。私の例では、最大数と最小数の間に10倍の相対差があります。それはおそらくあなたが気づきたいものです!データの範囲を基準にして数値許容誤差を計算する必要があると思います。これまでこれを実行したことがなく、問題が発生しました。
ハドリー、2011年

2
ずる賢いあなたを誤解したとは思いません。私は、質問者が事実上ゼロである数値の10倍の相対差を無視するソリューションを求めていると思っただけです。私は彼が1e-11と1e-13の違いを無視する解決策を求めているのを聞いた。
IRTFM、2011年

5
私は人々に彼らが望むものではなく、彼らが必要とするものを与えようとします;)しかし、要点を述べました。
ハドリー、2011年

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
恐ろしく非効率的ですが...(私のコンピューターでは、100万の数値の場合、約10秒かかります)
ハドリー、2011年

2
間違いない。しかし、OPはこれがまったく可能かどうか疑問視していました。それをうまく行うことは、2番目のステップです。そして、あなたは私がループで立っているところを知っています... ;-)
Dirk Eddelbuettel

10
そのループは素晴らしいですか?;)
ハドリー、2011年

4
このアプローチについて私が好きなのは、非数値オブジェクトで使用できることです。
Luciano

比較<-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])返します。そのような場合は機能します。NAFALSElength(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 2017

@dww指摘しているのは、精度の問題がある場合、比較は推移的ではないということです。つまりa == b、浮動小数点比較を行っている場合、b == c必ずしもそうではありませんa == c。精度を要素数で除算してこの問題を回避するか、アルゴリズムを変更して計算しminmaxそれを停止条件として使用することができます。
eddi 2017

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

実際には、min、mean、maxを使用する必要はありません。ジョンの答えに基づいて:

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

3

ここでは、min、maxトリックを使用した代替方法ですが、データフレームです。この例では列を比較していますが、行のマージンパラメータ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.