購入したばかりの曲を積極的に再生するための確率設定 -2

# 購入したばかりの曲を積極的に再生するための確率設定 -2
[前回の記事](https://qiita.com/ikuo0/items/86e1b4c1bfcd6d4ba1c4)
音楽プレイヤーのランダム再生機能を作ることを考え、購入したばかりの曲は再生頻度を高く、購入から日数の経過した曲は再生頻度を下げるといった再生をします、前回の記事では確率設定だけして実際の選曲部分を実装しなかったので今回は選曲部分を実装します

# 素直に確率を使用してランダムに選曲する場合
確率配列をｎまで足し込んだ配列を作成します

``` python
    psums = []
    for i, p in enumerate(prob):
        psums.append(np.sum(prob[0:i]))
    psums = np.array(psums)
```

random.random で ０－１ の乱数を生成し psums の中でそれ以下の配列を検索し、検索結果の最後の要素を選曲対象とします

``` python
    for i in range(10):
        r = random.random()
        pidxs = np.where(psums <= r)
        idx = idxs[pidxs[0][-1]]
        print(music_list[idx][0])
```

pidxs, idxs を使用しインデックスから更にインデックスを参照するという処理がかなり見づらいですね
どこかでまとめてソートし直してしまったほうが楽だったかもしれません


# 事前にプレイリストを作成しシャッフルする
最低確率の曲を最低１回は再生されるようにしたいので
確率 ／ 確率の最小値　を切り上げた数字を曲数として設定
各曲をいくつにするかを設定していきます

``` python
    pmin = np.min(prob)
    counts = []
    for p in prob:
        counts.append(math.ceil(p / pmin))
```

設定した数だけ曲を増やしてリスト化、さらにそれらをつなげてリスト化します、プログラムではひとつずつ追加しています

``` python
    for i, idx in enumerate(idxs):
        for j in range(counts[i]):
            music_list2.append(music_list[idx][0])
    random.shuffle(music_list2)
    print("\n".join(music_list2[:10]))
```

i と idx を使い分けているのがプログラムを分かりづらくしていますね…
関数化して頑張ればもっと見やすく作れたような気もします


# 出力結果

```
# 素直に確率で10曲選択する
ふざけてないぜ
こんがらがった
北上のススメ
北上のススメ
北上のススメ
君はいなせなガール
君はいなせなガール
北上のススメ
北上のススメ
北上のススメ

# 事前にプレイリストを作成しシャッフル、先頭から10曲を選択する
ふざけてないぜ
bloom
今日はカレーの日
ふざけてないぜ
北上のススメ
君はいなせなガール
北上のススメ
こんがらがった
北上のススメ
北上のススメ
```

購入から日数経過の短い物が高頻度で出ているのが分かります


# ソースコード全体
``` python

import matplotlib.pyplot as pyplot
import math
import numpy as np
import random
import sys

def coff_function(x, xmax, ymin):
    y = 1 - x / xmax
    if y < ymin:
        y = ymin
    return y

def test_plot():
    xmax = 1000
    ymin = 1 / xmax
    x = []
    y = []
    for ix in range(xmax + 1000):
        x.append(ix)
        y.append(coff_function(ix, xmax, ymin))
    
    pyplot.plot(x, y)
    pyplot.savefig("test_plot.png")

def test1():
    # 曲名, 購入日からの経過日数
    music_list = [
        ["bloom", 7],
        ["ふざけてないぜ", 1],
        ["優しくなれたなら", 6],
        ["今日はカレーの日", 5],
        ["北上のススメ", 0],
        ["こんがらがった", 6],
        ["君はいなせなガール", 3],
    ]
    
    #music_list = music_list * 10
    
    xmax = len(music_list)
    ymin = 1 / xmax
    names = []
    x = []
    y = []
    for v in music_list:
        ix = v[1]
        names.append(v[0])
        x.append(ix)
        y.append(coff_function(ix, xmax, ymin))
    
    names = np.array(names)
    x = np.array(x)
    y = np.array(y)
    idxs = np.argsort(y)
    idxs = np.flip(idxs) # 確率の高い順番に並べたいので逆転する
    
    names = names[idxs]
    x = x[idxs]
    y = y[idxs]
    
    ysum = np.sum(y)
    prob = y / ysum
    
    #print(names)
    #print(x)
    #print(y)
    #print(prob)
    #print(np.sum(prob))
    
    X = np.c_[names, prob * 100]
    for ix in X:
        print("{}\t{:.2f}%".format(ix[0], float(ix[1])))
    
    # 素直に確率で10曲選択する
    print("# 素直に確率で10曲選択する")
    psums = []
    for i, p in enumerate(prob):
        psums.append(np.sum(prob[0:i]))
    psums = np.array(psums)
    #print(psums)
    
    for i in range(10):
        r = random.random()
        pidxs = np.where(psums <= r)
        idx = idxs[pidxs[0][-1]]
        print(music_list[idx][0])
    
    # 事前にプレイリストを作成しシャッフル、先頭から10曲を選択する
    print()
    print("# 事前にプレイリストを作成しシャッフル、先頭から10曲を選択する")
    pmin = np.min(prob)
    counts = []
    for p in prob:
        counts.append(math.ceil(p / pmin))
    music_list2 = []
    for i, idx in enumerate(idxs):
        for j in range(counts[i]):
            music_list2.append(music_list[idx][0])
    random.shuffle(music_list2)
    print("\n".join(music_list2[:10]))
    

def main():
    #test_plot()
    test1()

if __name__ == "__main__":
    main()

```


以上です