ループ内のエラー(ある場合)をスキップして、次の反復を続けたいと思います。 {0、1、2}からランダムにサンプリングされた要素を持つ2行2列の行列の100個の逆行列を計算したい。特異行列を持つことが可能です(たとえば、
1 0
2 0
ここに私のコードがあります
set.seed(1)
count <- 1
inverses <- vector(mode = "list", 100)
repeat {
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
inverses[[count]] <- solve(x)
count <- count + 1
if (count > 100) break
}
3回目の反復で、行列は特異であり、コードはエラーメッセージで実行を停止します。実際には、このエラーをバイパスして次のループに進みたいと思います。 try
またはtryCatch
関数を使用する必要があることは知っていますが、使用方法はわかりません。ここでも同様の質問が出されましたが、それらはすべて本当に複雑であり、答えは私の理解をはるかに超えています。誰かがこの質問に特化した完全なコードを提供してくれれば、本当に感謝しています。
これは、特異行列のNULL
sをinverses
に入れます:
_inverses[[count]] <- tryCatch(solve(x), error=function(e) NULL)
_
tryCatch
の呼び出しの最初の式でエラーが発生した場合、error
引数に指定された関数の値を実行して返します。 error
argに提供される関数は、エラー自体を引数としてとる必要があります(ここではe
と呼びます)が、何もする必要はありません。
その後、inverses[! is.null(inverses)]
でNULL
エントリを削除できます。
または、下位レベルtry
を使用できます。選択は本当に好みの問題です。
_count <- 0
repeat {
if (count == 100) break
count <- count + 1
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
x.inv <- try(solve(x), silent=TRUE)
if ('try-error' %in% class(x.inv)) next
else inverses[[count]] <- x.inv
}
_
式がエラーを生成する場合、try
はクラス_try-error
_のオブジェクトを返します。 _silent=FALSE
_の場合、メッセージを画面に出力します。この場合、_x.inv
_がクラス_try-error
_を持っている場合、next
を呼び出して現在の反復の実行を停止し、次の反復に移動します。それ以外の場合は_x.inv
_を追加しますinverses
。
repeat
およびreplicate
でlapply
ループを使用することを避けることができます。
_matrices <- replicate(100, matrix(sample(0:2, 4, replace=T), 2, 2), simplify=FALSE)
inverses <- lapply(matrices, function(mat) if (det(mat) != 0) solve(mat))
_
replicate
の2番目の引数はexpression
として扱われることに注意してください。これは、レプリケートごとに新たに実行されることを意味します。つまり、replicate
を使用して、同じ式から生成される任意の数のランダムオブジェクトのlist
を作成できます。
tryCatch
を使用する代わりに、関数det
を使用して行列の行列式を単純に計算できます。行列式は、行列式がゼロの場合にのみ特異です。
したがって、行列式がゼロと異なるかどうかをテストし、テストが正の場合にのみ逆行列を計算できます。
set.seed(1)
count <- 1
inverses <- vector(mode = "list", 100)
repeat {
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
# if (det(x)) inverses[[count]] <- solve(x)
# a more robust replacement for the above line (see comment):
if (is.finite(determinant(x)$modulus)) inverses[[count]] <- solve(x)
count <- count + 1
if (count > 100) break
}
更新:
ただし、特異行列の生成を回避することは可能です。 2行2列の行列mat
の行列式は、mat[1] * mat[4] - mat[3] * mat[2]
。この知識を使用して、乱数をサンプリングできます。特異行列を生成する数値をサンプリングしないでください。もちろん、これは以前にサンプリングされた数値に依存します。
set.seed(1)
count <- 1
inverses <- vector(mode = "list", 100)
set <- 0:2 # the set of numbers to sample from
repeat {
# sample the first value
x <- sample(set, 1)
# if the first value is zero, the second and third one are not allowed to be zero.
new_set <- ifelse(x == 0, setdiff(set, 0), set)
# sample the second and third value
x <- c(x, sample(new_set, 2, replace = T))
# calculate which 4th number would result in a singular matrix
not_allowed <- abs(-x[3] * x[2] / x[1])
# remove this number from the set
new_set <- setdiff(0:2, not_allowed)
# sample the fourth value and build the matrix
x <- matrix(c(x, sample(new_set, 1)), 2, 2)
inverses[[count]] <- solve(x)
count <- count + 1
if (count > 100) break
}
この手順は、生成されたすべての行列に逆行列があることを保証します。
try
は、単にR
に伝える方法です。「次の括弧内でエラーをコミットした場合は、スキップして先に進みます。」
そのため、x <- matrix(sample(0:2, 4, replace = T), 2, 2)
がエラーを与えるのではないかと心配している場合、あなたがしなければならないことは次のとおりです。
_try(x <- matrix(sample(0:2, 4, replace = T), 2, 2))
_
ただし、これを行うとx
が未定義になり、答えを計算できなくなることに注意してください。 solve(x)
に到達すると問題が発生する可能性があります。そのため、x
の前にtry
を定義するか、すべてを「試す」ことができます。
_try(
{
x <- matrix(sample(0:2, 4, replace = T), 2, 2)
inverses[[count]] <- solve(x)
}
)
_
tryのドキュメント はあなたの問題をかなりよく説明しています。完全に経験することをお勧めします。
Edit:
ドキュメンテーションの例は非常に簡単で、opの質問と非常によく似ていました。提案をありがとう。ドキュメントページの例に続く答えを次に示します。
# `idx` is used as a dummy variable here just to illustrate that
# all 100 entries are indeed calculated. You can remove it.
set.seed(1)
mat_inv <- function(idx) {
print(idx)
x <- matrix(sample(0:2, 4, replace = T), nrow = 2)
solve(x)
}
inverses <- lapply(1:100, function(idx) try(mat_inv(idx), TRUE))