質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Q&A

解決済

2回答

760閲覧

再帰を用いた無作為抽出標本の生成のコード

macuserdesu

総合スコア8

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

0グッド

0クリップ

投稿2020/04/30 06:07

MITのアルゴリズムイントロダクション第3版の5章の練習問題5.3-7の質問です。
この問題は無作為抽出標本を生成することを証明する問題です。
下の擬似コードが{1,2,3,.....,n}から0<=m<=nであるm部分集合Sを無作為抽出することの証明です。
イメージ説明
具体的な数字を当てはめて動きを追うことはできるのですが、感覚的に無作為抽出になることも理解できず、もちろんループ不変式を用いた帰納的な証明もできません。
再帰のサイクルの途中段階では最終的なループより小さい集合から抽出しているし、特に6行目は理解できません。
後もしこのテキストの解答が閲覧できるサイトがあれば教えていただければ幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2020/04/30 06:24

RANDOM(1, n)というのは、1以上n以下の整数をランダムに得るということで合っていますか?
episteme

2020/04/30 06:48

↑それとも1以上n"未満"?
macuserdesu

2020/04/30 06:50

1以上n以下です。nも含みます!
guest

回答2

0

ベストアンサー

無作為抽出した場合、このm部分集合に特定の要素が属する確率を数学的に求めるとm/n(※)なので、すべての要素に対して、部分集合に属する確率がm/nであれば証明ができることになります。

(※)全パターンはnCm、特定の要素(xとする)が属するパターンは、xを除いた(n-1)個から、xとともに属する(m-1)個を選ぶ組み合わせに等しいので、(n-1)C(m-1)=(m/n)×nCm。よって確率は{(m/n)×nCm}/nCm = m/n

再帰の繰り返しにより、(0, n-m)に到達し、これは空集合を返します。そして(1, n-m+1)から要素の選定が始まります。これから、n-m+1以下の要素aについては、RANDOMでaが1回でも選ばれれば部分集合に入ります。この確率を直に求めるのは難しいので、「aが1回も選ばれない」確率を求めます。
(1, n-m+1)の時、aが選ばれない確率は(n-m)/(n-m+1)
(2, n-m+2)の時、aが選ばれない確率は(n-m+1)/(n-m+2)
(3, n-m+3)の時、aが選ばれない確率は(n-m+2)/(n-m+3)

(m-1, n-1)の時、aが選ばれない確率は(n-2)/(n-1)
(m, n)の時、aが選ばれない確率は(n-1)/n
ここで再帰が終了します。aが1回も選ばれない確率は、これらの確率をすべて掛けて(n-m)/nとなります。
したがって、aが1回以上選ばれる確率は、1-(n-m)/n = m/nとなります。

n-m+2以上の要素bについては、b=n-m+1+iとしたとき、(i, b-1)までに選ばれることはありませんが、(i+1, b)のときだけは、RANDOMでb自身が選ばれるときだけではなく、それまでに選んだi個の要素のいずれかが選ばれたときに、部分集合に入ります。したがって、先ほどと同様にbが1回も選ばれない確率を考えると、
(i+1, b)の時、bが選ばれない確率は(b-i-1)/b
(i+2, b+1)の時、bが選ばれない確率はb/(b+1)
(i+3, b+2)の時、bが選ばれない確率は(b+1)/(b+2)

(m-1, n-1)の時、bが選ばれない確率は(n-2)/(n-1)
(m, n)の時、bが選ばれない確率は(n-1)/n
ここで再帰が終了します。bが1回も選ばれない確率は、これらの確率をすべて掛けて(b-i-1)/nとなります。b=n-m+1+iなので、この確率は(n-m)/nです。
したがって、bが部分集合に入る確率は、1-(n-m)/n = m/nとなります。

以上より、どの要素も部分集合に入る確率がm/nであることが示せました。

直感的には、番号が後の方は最初に選ばれるチャンスがない代わりに、あとで大きなチャンスがあるために釣り合っている、といった感じでしょうか。

投稿2020/04/30 07:04

編集2020/04/30 07:06
swordone

総合スコア20669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2020/04/30 07:07

そか、無作為抽出になってることを証明するんだから、 どれも同確率で現れることを証明せにゃならんのか。
swordone

2020/04/30 07:21

まあ、明らかにフィッシャー・イェーツのアルゴリズムを応用すれば簡単だと思うんだけど…
episteme

2020/04/30 07:47

n個の玉の入った袋からm個取り出すだけですからねー
guest

0

  1. S = RANDOM_SAMPLE(m-1, n-1) は n を含まない。
  2. i = RANDOM(1, n) が既に S に含まれていたら n を追加する。(1.より重複しない)
  3. i が S に含まれていないなら i を追加する。(当然重複しない)

...だから S には m個の 1~n が重複なく現れる。

[追記] とんでもなく勘違いしてました。そっと閉じてください orz

で、書いてみた.

C++

1#include <iostream> 2#include <set> 3#include <random> 4 5std::set<int> random_sample(int m, int n) { 6 if ( m == 0 ) { 7 return std::set<int>(); 8 } else { 9 std::set<int> S = random_sample(m-1, n-1); 10 std::random_device rnd; 11 std::uniform_int_distribution<> dist(1,n); 12 int i = dist(rnd); 13 if ( S.find(i) != S.end() ) { 14 S.insert(n); 15 } else { 16 S.insert(i); 17 } 18 return S; 19 } 20} 21 22int main() { 23 int hist[10]; 24 std::fill_n(hist, 10, 0); 25 for ( int i = 0; i < 10000; ++i ) { 26 for ( int item : random_sample(3, 10)) { ++hist[item-1]; } 27 } 28 for ( int item : hist ) { 29 std::cout << item << ' '; 30 } 31 std::cout << std::endl; 32}

投稿2020/04/30 07:01

編集2020/04/30 07:44
episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

swordone

2020/04/30 07:08

「無作為抽出」である、つまり各要素が確率的な偏りなく抽出される、という点が疑問なのだと思います。
episteme

2020/04/30 07:21

面目ねぇ... お詫びの実装を追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問