

Numpyで、n次元のランダムベクトルvを作りたいのですが、  
ベクトルの要素の総和がNになるようにしたいです。

例えば、  
n=4で、N=1ならば、`v = np.array([0.1, 0.3, 0.2, 0.4])`  
あるいは、  
n=6で、N=3ならば、`v = np.array([0.3, 0.1, 1.2, 0.6, 0.5, 0.3])`  
というような感じです。

このようなことをNumpyで実現するにはどうすれば良いでしょうか？


CC BY-SA 3.0
2018-01-04T06:30:54.137
40711
2018-01-05T19:02:56.560
2018-01-04T06:50:50.787
19110
25649
question
python numpy
Numpyで、要素数の総和がNとなる制約の下、n次元のランダムベクトルを生成したい。


多少の誤差を気にしないのであれば、ひとまず `n` 個のランダムな数を生成した後、正規化すれば良いです。

[code]

    >>> import numpy as np
    >>> n = 7
    >>> N = 3
    >>> random_numbers = np.random.rand(n)
    >>> print(random_numbers)
    [ 0.61444461  0.44538832  0.80188737  0.57265561  0.05225624  0.07613083
      0.55669533]
    >>> print(np.sum(random_numbers))
    3.11945832298
    >>> answer = N * random_numbers / np.sum(random_numbers)
    >>> print(answer)
    [ 0.59091472  0.42833237  0.77117943  0.55072601  0.05025511  0.07321543
      0.53537692]
    >>> print(np.sum(answer))
    3.0
    
[/code]


CC BY-SA 3.0
2018-01-04T06:50:33.653
40712
2018-01-04T06:50:33.653
19110
40711
answer


他にもやり方がありそうですが、求めたい総和を乱数の範囲として、乱数をその範囲の上限と下限を除いたものの中から、n-2個出して、上限と下限を含むものに加えて小さい数から大きい数へソートした後、numpy.arrayに入っている小さい方から隣り合った項の差を加えていくと求めたい値が出るはずです。

[code]

    import numpy as np, numpy.random
    // N = 3 総和を3とする、つまり以下では乱数が出る範囲を3とする. 
     以下では下限が0.0、上限が3.0。np.random.uniformは上限の値は出力しないはず。
    // n = 6 要素の数を 6つとする。
    values = numpy.array([0.0, N]);
    x = np.random.uniform(0.0, N,size= n-2);
    values = numpy.append(x, values);
    values.sort();
    print(values) 
    // [ 0.  0.83087151  1.27426042  1.47701249  2.83517723  3. ] 0., 3.は0.0, 3.0のはず。repl.itによる。
    results = numpy.array([]);
    for i in range(1, 6):
         results = numpy.append(results, values[i] - values[i-1]);
    print(np.sum(results));
    // 3.0
    
[/code]


CC BY-SA 3.0
2018-01-04T08:02:03.487
40714
2018-01-04T09:16:53.930
2018-01-04T09:16:53.930
25766
25766
40711
answer


[SO英語版に同じ質問](https://stackoverflow.com/questions/18659858/generating-a-list-
of-random-numbers-summing-to-1/18662466#18662466)がありました。

[code]

    import numpy as np
    
    n = 7
    N = 3
    
    answer = np.random.dirichlet(np.ones(n)) * N
    
    print("n =", answer.size)
    print("N =", answer.sum())
    print(answer)
    
[/code]

### 実行結果

[code]

    n = 7
    N = 3.0
    [ 0.23253049  1.45542211  0.36459806  0.39199048  0.31374561  0.20020738
      0.04150587]
    
[/code]

np.ones(n)に係数を掛けると乱数の分布を変えることもできるみたいです。詳しくは英語版をご覧ください。


CC BY-SA 3.0
2018-01-05T18:39:10.817
40760
2018-01-05T19:02:56.560
2018-01-05T19:02:56.560
7837
7837
40711
answer