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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

4回答

391閲覧

Pythonで違う要素数の複数の配列から同じ確率で値をランダムに取り出す方法

taisei12232

総合スコア23

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2022/05/19 09:50

編集2022/05/21 00:03

Pythonで、

[ { a:[1,2,3] }, { a:[4,5,6,7,8] } ]

のような配列があったとして、
2つ以上の複数のaの配列からランダムに同じ確率で値を取り出したいのですが、どうすれば良いでしょうか?
実際の配列はかなり長いので、新しく配列を作り直すのは出来ればやりたくないです。
現在はrandom.choice()を2回使用していますが、これだと要素数が少ない配列の方が、が選出率が高くなってしまいます。
実際に使用している配列は要素数がもっと多いです。

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

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

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

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

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

TakaiY

2022/05/19 09:58 編集

「同じ確率で」というのはどういう意味ですか? 「新しく配列を作り直すのは出来ればやりたくない」というのも、どうしてそういうことになるのかわかりません。
taisei12232

2022/05/19 10:00

現在random.choice()を2回使用しているのですが、これだと要素数が少ない配列が選出率が高くなってしまうので、 例の場合は1~8を同じ確率で取り出したいという意図で質問させて頂きました。
taisei12232

2022/05/19 10:02

中身を1つの配列に纏めてからであれば同じ確率で値を取り出すことが出来ますが、実行に時間がかかってしまうためです。
TakaiY

2022/05/19 10:16

回答はここに書かっずに、質問を編集したほうが、見てくれた人に伝わりやすくなります。
guest

回答4

0

ベストアンサー

既に、回答がでてますが配列が3つ以上のケースです。
処理速度を上げるために、配列へのインデックスを作成しています。
v = arr[i]['a'][j]
のvが乱数rから取得した配列内の数値です。
不明点は補足してください。

python3

1import random 2arr = [ { 'a':[1,2,3]},{ 'a':[4,5,6,7,8]},{ 'a':[9,10,11,12]},{ 'a':[13] },{ 'a':[14,15,16,17,18,19,20]}] 3 4len_all = 0 5lens = [] 6for i in range(len(arr)): 7 len_all += len(arr[i]['a']) 8 lens.append(len_all) 9 10ctr = [ 0 ] * (len_all+1) 11ix = [ None ] * len_all 12 13for i in range(len_all): 14 for j in range(len(lens)): 15 if i < lens[j]: 16 ix[i] = j 17 break 18 19for x in range(200000): 20 r = random.randrange(len_all) 21 i = ix[r] 22 if i == 0: 23 j = r 24 else: 25 j = r - lens[i-1] 26 v = arr[i]['a'][j] 27 ctr[v] += 1 28 29print(ctr) 30

実行結果
[0, 9870, 10064, 10062, 9836, 10012, 10093, 10025, 9954, 10062, 10138, 10047, 10010, 10038, 9996, 9854, 9953, 9985, 10064, 9982, 9955]

投稿2022/05/21 00:15

tatsu99

総合スコア5438

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

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

0

python

1import random 2from collections import defaultdict 3 4lst = [{'a': [1, 2, 3]}, {'a': [4, 5, 6, 7, 8]}] 5N = 800000 6counts = defaultdict(int) 7weights = [len(d['a']) for d in lst] 8 9for _ in range(N): 10 i = random.choice(random.choices(lst, weights)[0]['a']) 11 counts[i] += 1 12 13print(dict(sorted(counts.items()))) 14 15# 16{1: 99954, 2: 99716, 3: 100201, 4: 99556, 5: 100484, 6: 99676, 7: 100434, 8: 99979}

投稿2022/05/19 15:32

編集2022/05/19 16:04
melian

総合スコア19791

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

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

0

TakaiYさんのアルゴリズムを実装してみました。
0番目の配列の要素数は3
0番目の配列の要素数は5、したがって、合計=8
0~7の乱数を発生させる
乱数の値が3未満なら、配列0番の[乱数]の値を取得
乱数の値が3以上なら、配列1番の[乱数-3]の値を取得

上記を80000回実行し、取得した値の回数をカウントする。
1から8の数が取得されるが、各々の値が10000回になれば、均一に取り出されていると判断して良い。
結果は、各々の値は、ほぼ10000の値に近いので、ほぼ均一に取り出されていると判断して良い。

import random arr = [ { 'a':[1,2,3]},{ 'a':[4,5,6,7,8]}] len0 = len(arr[0]['a']) lenA = len(arr[0]['a']) + len(arr[1]['a']) ctr = [0,0,0,0,0,0,0,0,0] for x in range(80000): r = random.randrange(lenA) if r < len0: i = 0 j = r else: i = 1 j = r - len0 v = arr[i]['a'][j] #print(v) ctr[v] += 1 print(ctr)

実行結果
[0, 10035, 9985, 9927, 10151, 9974, 9999, 9956, 9973]

投稿2022/05/19 13:53

tatsu99

総合スコア5438

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

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

taisei12232

2022/05/19 14:56

とてもわかりやすい解説ありがとうございます。 しかし、これは自分の書き方が悪かったのですが、実際は配列は2つ以上あるんです。 すみません。
tatsu99

2022/05/21 00:17 編集

配列が3つ以上のケースを回答にアップしました。考え方は基本的には2つのケースと同じです。
guest

0

配列の合計数で乱数を発生させて、振り分ければよいのではないかと思います。
10000と20000 で、12700 であればあ、 12700 > 10000なので、というような具合。

投稿2022/05/19 10:19

TakaiY

総合スコア12765

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

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

taisei12232

2022/05/19 10:21

すみません。数字の意味がよく分かりません。 簡単なコードを書いていただくことは可能でしょうか?
TakaiY

2022/05/19 10:42

質問の例であれば index = random.randrange(0, 3 + 5) index が 2であれば、 最初の配列の3番目、 3であれば2つめの配列の0番目 という具合ですね。
taisei12232

2022/05/19 13:04

やり方が分かりません。
TakaiY

2022/05/19 15:30

ここはプログラムを作ってもらう場所ではありませんので、あとはご自分でお考えください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問