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

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

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

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

Python

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

Q&A

解決済

5回答

1547閲覧

Pythonで配列内の要素をを分割したい

ntsk2543

総合スコア4

アルゴリズム

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

Python

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

0グッド

0クリップ

投稿2021/12/01 06:38

編集2021/12/01 07:46

前提・実現したいこと

以下の様なアルゴリズムを実装したいです。

1.配列に01までのランダムな小数が入っている。
2.配列から要素を1つ持ってくる。
3.その要素が0
1をN等分したどこに入るかを分配する。
(例:取り出した要素=0.598,等分数=100の時、0.59<=要素<=0.6なので59番目)
4.新たな配列を用意し、3で決まった番号の回数を1個増やす
(例:先程0.598は59番目に入るのが分かったので、新たな配列の59番目を+1する。)
5.24を最初の要素数行う。
6.4,5で作成した配列の要素を持ってくる。
7.その要素数分だけ等分し、どこに入るかを考える。
(例:59番目の配列には5個の要素があるとすると、0.59
0.6の間を5等分し、0.58<=0.598<=0.6より、0.598はその中の5番目に入る)
8.7を分配後の要素の数だけ繰り返し、再等分された中に入っているかどうか割合を考える。それを更に新しい配列に順次追加する。
(例:5等分され、1,3,5番目に数が1個以上あり、2,4番目に入っていない場合,3/5となる。)
9.6~8を元々のN等分行う。

6以降の追記です。
5までで、59番目に入った配列の要素が5個、その内容を[0.5910,0.5930,0.5930,0.5960,0.5980]とします。
ここから、0.590.60に入っているこの5個の要素を更に細かく見ていくこととなります。
再等分数は、要素が5個の為0.59
0.60を5等分します。この5等分に先程の要素が入っているかを考えます。
0.5910=1番目
0.5930=2番目
0.5930=2番目
0.5960=3番目
0.5980=4番目
すると、各区間に入っている数は

区間要素が入っているかどうか
0.5900~0.5920
0.5921~0.5940
0.5941~0.5960
0.5961~0.5980
0.5981~0.6000×

となります。ここから、5等分された区間の中にどの区間数が入ってるかを考えます。
今回の場合、5区間中に4区間は要素が存在しているので、最終的な出力は4/5となります。
この4/5を新しい配列の59番目に挿入します。

試したこと

5までは自力でやってみましたが、6からが分かりません。
1の配列作成は省略しています。(orbitに入っています。)

Python

1 2import numpy as np 3import math 4 5 N=100 #N:等分数。 6 7 for i in range(len(orbit)): 8 temporary = 0 9 temporary = orbit[i] 10 temporary = abs(math.floor(temporary*N)) 11 pdcount[temporary] = pdcount[temporary]+1

3の補足ですが、取り出した点をN倍し、小数を切り落としすればそのまま分配先の番号になることを利用しています。
(例:0.598,N=100の時、0.598*100=59.8,つまり59となり、pdcount[59]の要素を+1している。)

補足情報(FW/ツールのバージョンなど)

Python 3.94

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

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

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

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

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

melian

2021/12/01 07:15

Numpy はお使いにならないのでしょうか?
ntsk2543

2021/12/01 07:21

Nmupyは使用しています。追記しておきます。
退会済みユーザー

退会済みユーザー

2021/12/01 07:22

最終的にどのような結果が欲しいのか分かりません。ダミーサンプルでかまわないので0.59~0.6の間に10個くらい値があるケースで説明してもらえませんか?
ntsk2543

2021/12/01 07:23

分かりました。追記しておきます。
melian

2021/12/01 07:56 編集

5 までの操作はいわゆるヒストグラムかと思いますので、 pdcount = np.histogram(orbit, bins=N, range=(0.0, 1.0))[0] かと。
退会済みユーザー

退会済みユーザー

2021/12/01 07:58

更新ありがとうございます。重要な部分なので細かい点を確認させてください。7の区間を分割する部分は 0.590以上~0.592未満、0.592以上~0.594未満… みたいな感じじゃなくていいんですか?現在の例だと 0.59201などがどこにも含まれないことになります。
ntsk2543

2021/12/01 08:10

区間の分割に関してはftlobwさんの言う通りです、あいまいな表現、失礼いたしました。 melianさんの質問ですが、記述の通りでした。ありがとうございました。
guest

回答5

0

こんなことでしょうか?

import numpy as np import random random.seed(110) orbit = np.asarray([random.uniform(0,1) for _ in range(10000000)]) print('start') N = 100 # 分割数 hist, bins = np.histogram(orbit, range=(0, 1), bins=N) print(hist) print(bins) results = [] for i in range(len(bins)-1): r_min = bins[i] r_max = bins[i+1] pick_elems = orbit[(r_min <= orbit) & (orbit < r_max)] # print(r_min, r_max) # print(pick_elems) m_hist, _ = np.histogram(pick_elems, range=(r_min, r_max), bins=len(pick_elems)) # print(m_hist) m_p = np.count_nonzero(m_hist)/len(m_hist) results.append(m_p) print(len(results)) print(results)

[補足]
少しpythonっぽくしてみました

!pip install more-itertools
import numpy as np import random import more_itertools random.seed(110) orbit = np.asarray([random.uniform(0,1) for _ in range(10000000)]) print('start') N = 100 hist, bins = np.histogram(orbit, range=(0, 1), bins=N) def get_ratio(r_min:float, r_max:float, arr:np.ndarray)->float: pick_elems = arr[(r_min <= arr) & (arr < r_max)] m_hist, _ = np.histogram(pick_elems, range=(r_min, r_max), bins=len(pick_elems)) return np.count_nonzero(m_hist)/len(m_hist) results = [get_ratio(r[0], r[1], orbit) for r in more_itertools.windowed(bins,2,step = 1)] print(len(results)) print(results)

投稿2021/12/01 08:37

編集2021/12/02 00:28
taront

総合スコア59

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

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

0

python

1import numpy as np 2from numpy.random import default_rng 3 4M = int(1e+7) 5N = 100 6num_range = (0.0, 1.0) 7 8rg = default_rng() 9orbit = rg.uniform(*num_range, M) 10 11orbit_org = orbit.copy() 12orbit.sort() 13pdcount, bin_edge = np.histogram(orbit, bins=N, range=num_range) 14bins = np.split(orbit, pdcount.cumsum()[:-1]) 15 16ratio = np.zeros(N) 17for i, data in enumerate(bins): 18 hist, _ = np.histogram(data, bins=pdcount[i], range=(bin_edge[i], bin_edge[i+1])) 19 ratio[i] = hist[hist>0].size/pdcount[i] 20 21print(ratio) 22# 23[0.63314754 0.63316065 0.6325016 0.63304742 0.6318326 0.63409262 24 0.6309113 0.6328047 0.63185449 0.63081087 0.63180382 0.63368009 25 0.63418594 0.63202644 0.630325 0.62935527 0.63230635 0.63173384 26 0.63192124 0.63125318 0.63181714 0.63249917 0.63271949 0.63248817 27 0.63252976 0.63157 0.63182343 0.63087606 0.63256839 0.6310312 28 : 29 :

以下の環境での実行時間は N = 1e+70.66±0.02 秒程度になりました(timeit モジュールを利用して計測)。

sh

1$ lscpu | grep -E '^(Architecture|Model name)' 2Architecture: x86_64 3 Model name: Intel(R) Core(TM) i5-8500T CPU @ 2.10GHz 4 5$ lsb_release -ir 6Distributor ID: Ubuntu 7Release: 21.04 8 9$ python3 --version 10Python 3.9.5 11 12$ python3 -c 'import numpy;print(numpy.__version__)' 131.21.4

投稿2021/12/01 14:33

編集2021/12/01 15:30
melian

総合スコア20655

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

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

0

ベストアンサー

処理を共通化してみました。

python

1import numpy as np 2 3N = 15 4 5def classify(amin, amax, a, n): 6 linspace = np.linspace(amin, amax, n+1) 7 return [(pmin, pmax, orbit[(orbit >= pmin) & (orbit <pmax)]) for pmin, pmax in zip(linspace, linspace[1:])] 8 9def ratio(amin, amax, a): 10 alist = np.array([len(a) for pmin, pmax, a in classify(amin, amax, a, len(a))]) 11 return len(alist[alist>0])/len(alist) 12 13result = [ratio(pmin, pmax, a) for pmin, pmax, a in classify(0, 1, orbit, N)]

実行例

python

1>>> orbit = np.random.random(1000) 2>>> result = [ratio(pmin, pmax, a) for pmin, pmax, a in classify(0, 1, orbit, N)] 3>>> print(result) 4[0.704225352112676, 0.6461538461538462, 0.6610169491525424, 0.6911764705882353, 0.6764705882352942, 0.6590909090909091, 0.6712328767123288, 0.5970149253731343, 0.5571428571428572, 0.5753424657534246, 0.6176470588235294, 0.6142857142857143, 0.59375, 0.6125, 0.6333333333333333]

投稿2021/12/01 08:53

ppaul

総合スコア24670

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

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

0

記載された手順をそのまま素直に組んでみました。答え合わせはしていません。
要素数1000万で一様分布、N=100~10000でも10秒程度で終わります。
C++などでやるともっとはやくなると思います。

Python

1import math 2import random 3 4random.seed(110) 5orbit = [random.uniform(0,1) for _ in range(10000000)] 6print('start') 7#print(orbit) 8 9N = 100 10 11# 各要素をクラス分け 12slots = {} 13for i, v in enumerate(orbit): 14 n = math.floor(v*N) 15 if n >= N: 16 n = N-1 17 if n not in slots: 18 slots[n] = [] 19 slots[n].append(i) # 要素位置を保持 20 21# 各クラスの計算 22results = [0.0 for _ in range(N)] # 要素のないクラスの初期値は0 23for n, lst in slots.items(): 24 exists = set() 25 SUB_N = len(lst) # クラス内の要素数 26 st = n / N # この区間の左端値 27 for i in lst: 28 v = (orbit[i]-st) * N # クラス内の値を0...1に正規化 29 sub_n = math.floor(v*SUB_N) 30 if sub_n >= SUB_N: 31 sub_n = SUB_N-1 32 exists.add(sub_n) 33 34 results[n] = len(exists)/SUB_N 35 36print(results)

投稿2021/12/01 08:07

編集2021/12/01 08:28
can110

総合スコア38341

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

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

can110

2021/12/01 08:37 編集

あ。クラス内の計算がおかしかった。これで合ってるかな?
guest

0

0~1 を N等分するんだから 配列: slot[N] を用意し、
与えられた各要素:x に対し i/N <= x < (i+1)/N なら x を slot[i] に追加する。

...でいいんですよね?

投稿2021/12/01 06:53

episteme

総合スコア16612

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

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

ntsk2543

2021/12/01 07:13

それが5までの内容になります。(質問がわかりずらくてすみません。) ただ、本来ならこの後2次元配列のバージョンもあり、pythonで回すと処理に時間がかかってしまいます。(明記するのを忘れていましたが元々の配列の要素数は10万~1000万程ある。) その為、各要素xを1回で振り分けることが可能になるようなアルゴリズムにしています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問