web-dev-qa-db-ja.com

Rでの数値比較の難しさ

Ifステートメントの条件の一部として、Rの2つの数値を比較しようとしています。

_(a-b) >= 0.5_

この特定の例では、a = 0.58およびb = 0.08 ...であり、_(a-b) >= 0.5_はfalseです。私は正確な数値比較に_==_を使用することの危険性を認識しています、そしてこれは関連しているようです:

_(a - b) == 0.5)_はfalseですが、

all.equal((a - b), 0.5)はtrueです。

私が考えることができる唯一の解決策は、2つの条件があることです:_(a-b) > 0.5 | all.equal((a-b), 0.5)_。これは機能しますが、それが本当に唯一の解決策ですか?比較演算子の_=_ファミリーを永遠に誓うべきですか?

明確にするために編集:これは浮動小数点の問題であることを知っています。より根本的に、私が求めていることは、それについて何をすべきかということです。 _>=_は本当に信頼できないため、Rでの大なりまたは等しい比較を処理するための賢明な方法は何ですか?

45
Matt Parker

私はそのようなことをall.equalのファンにしたことがありません。耐性が神秘的な方法で時々働くように思えます。 0.05未満の許容誤差よりも大きい値をチェックしないのはなぜですか

tol = 1e-5

(a-b) >= (0.05-tol)

一般的に、丸めなしで、従来のロジックだけを使用すると、ストレートロジックがすべてよりも優れていることがわかります。

x == yの場合はx-y == 0。おそらくx-yは正確に0ではないので、そのような場合は私が使用します

abs(x-y) <= tol

とにかくall.equalの許容値を設定する必要があります。これはall.equalよりもコンパクトで簡単です。

41
John

このアプローチを頻繁に使用したい場合は、これを別の演算子として作成するか、元の> =関数を上書きする(おそらくお勧めできません)。

# using a tolerance
epsilon <- 1e-10 # set this as a global setting
`%>=%` <- function(x, y) (x + epsilon > y)

# as a new operator with the original approach
`%>=%` <- function(x, y) (all.equal(x, y)==TRUE | (x > y))

# overwriting R's version (not advised)
`>=` <- function(x, y) (isTRUE(all.equal(x, y)) | (x > y))

> (a-b) >= 0.5
[1] TRUE
> c(1,3,5) >= 2:4
[1] FALSE FALSE  TRUE
14
Shane

完全を期すために、特定の状況では、小数点以下数桁に丸めることができることを指摘しておきます(これは、以前に投稿されたより優れたソリューションと比較すると、不完全なソリューションの一種です)。

round(0.58 - 0.08, 2) == 0.5
11
icio

許容レベルを選択します。

epsilon <- 1e-10

次に使用します

(a-b+epsilon) >= 0.5
5
Rob Hyndman

もう一つコメント。 all.equalは総称です。数値の場合、all.equal.numeric。この関数を調べると、.Machine$double.eps^0.5、 どこ .Machine$double.eps と定義されている

double.eps: the smallest positive floating-point number ‘x’ such that
          ‘1 + x != 1’.  It equals ‘double.base ^ ulp.digits’ if either
          ‘double.base’ is 2 or ‘double.rounding’ is 0; otherwise, it
          is ‘(double.base ^ double.ulp.digits) / 2’.  Normally
          ‘2.220446e-16’.

(.Machineマニュアルページ)。

言い換えれば、それはあなたの許容範囲にとって許容できる選択です:

myeq <- function(a, b, tol=.Machine$double.eps^0.5)
      abs(a - b) <= tol
5
January

しかし、とにかく許容誤差を使用している場合、なぜa-b == .5(実際には)が評価されないことを気にするのですか?とにかく許容差を使用している場合、私はエンドポイントを正確に気にしないと言っています。

If((a-b)> = .5)if((a-b)<.5)は、trueです。

それらの1つは、常にdoubleのすべてのペアでtrueと評価されます。 1つを使用するコードは、少なくとも他の1つに対してno操作を暗黙的に定義します。最初に実際の.5を含めるために許容誤差を使用しても、問題が継続的なドメインで定義されている場合は、あまり達成できません。根本的な問題に連続値が含まれるほとんどの問題では、任意に.5を超える値は常に期待どおりに評価されるため、そのことにはほとんど意味がありません。任意に0.5に近い値は「間違った」フロー制御になりますが、重要ではない適切な精度を使用している継続的な問題では。

許容値が意味を持つ唯一の時間は、タイプif((a-b)== c)if((a-b)!= c)の問題を処理しているときです。

ここでは、「適切な精度」の量はあなたを助けることができません。その理由は、手動でa-bのビットを非常に低いレベルに設定しない限り、2番目の値が常にtrueに評価されるように準備する必要があるためです。

3
Jer

<=および>=浮動小数点数の数値の難易度が上がる場合、比較は言語固有ではありません。

IsSmallerOrEqual <- function(a,b) {   # To check a <= b
# Check whether "Mean relative difference..." exist in all.equal's result; 
# If exists, it results in character, not logical
if (   class(all.equal(a, b)) == "logical" && (a<b | all.equal(a, b))) { return(TRUE)
 } else if (a < b) { return(TRUE)
     } else { return(FALSE) }
}

IsSmallerOrEqual(abs(-2-(-2.2)), 0.2) # TRUE; To check |-2-(-2.2)| <= 0.2
IsSmallerOrEqual(abs(-2-(-2.2)), 0.3) # TRUE
IsSmallerOrEqual(abs(-2-(-2.2)), 0.1) # FALSE

IsBiggerOrEqual  <- function(a,b) {   # To check a >= b
# Check whether "Mean relative difference..." exist in all.equal's result; 
# If exists, it results in character, not logical
if (   class(all.equal(a, b)) == "logical" && (a>b | all.equal(a, b))) { return(TRUE)
 } else if (a > b) { return(TRUE)
     } else { return(FALSE) }
}
IsBiggerOrEqual(3,3) # TRUE
IsBiggerOrEqual(4,3) # TRUE
IsBiggerOrEqual(3,4) # FALSE
IsBiggerOrEqual(0.58 - 0.08,0.5)  # TRUE

all.equalは処理されません。エラーが発生する可能性があります。

以下は必須ではありませんが、役立ちます。

abs(-2-(-2.2)) # 0.2

sprintf("%.54f",abs(-2-(-2.2)))  # "0.200000000000000177635683940025046467781066894531250000"
sprintf("%.54f",0.2)             # "0.200000000000000011102230246251565404236316680908203125"

all.equal(abs(-2-(-2.2)), 0.2)  # TRUE; check nearly equivalence of floating point numbers
identical(abs(-2-(-2.2)), 0.2)  # FALSE; check exact equivalence of floating point numbers
2
Erdogan CEVHER