簡體   English   中英

如何創建L個n個非零隨機小數的列表,每個列表的總和為1.0?

[英]How to create L lists of n non-zero random decimals where each list sums to 1.0?

尋找一種快速的方法來創建L個數量的列表,這些列表的n個小數的數量之和為1。每個數字應> = 0.01

所需輸出:

其中L = 200,n = 6

[0.20, 0.22, 0.10, 0.06, 0.04, 0.38]
[0.32, 0.23, 0.18, 0.07, 0.05, 0.15]
...
# There are 200 of these

其中L = 200,n = 3

[0.90, 0.10, 0.10]
[0.35, 0.25, 0.30]
...
# There are also 200 of these

我想不出切實可行的解決方案的棘手部分是確保每個列表中都沒有零。 n達到大數時,這尤其困難。 您如何相應地分割值1的片段?

這應該非常快,因為它使用numpy。

如果得到任何0.0,它將自動重復隨機化,但這不太可能。 在OP將非零要求調整為高於0.01之前,編寫了while循環。 要解決此問題,您可以修改while塊以包括整個后續代碼,並以類似於檢測零的方式顯示最終計算違反任何所需約束的次數。 但是,與違反約束的可能性相比,當L大時,這可能會變慢。 從某種意義上講,最容易滿足>0.0的原始要求。

在while循環之后,L xn矩陣的每個元素均勻分布在(0.0,1.0)上,沒有任何0或1s。 將每一行相加並用於形成比例矩陣,然后將該矩陣乘以隨機矩陣以獲得自動求和為1.0的行

 import numpy as np
 def random_proportions(L,n):
      zeros = 1
      while zeros>0:
          x = np.random.random(size=(L,n))
          zeros = np.sum(x==0.0)
      sums = x.sum(axis=1)
      scale = np.diag(1.0/sums)
      return np.dot(scale, x)

編輯:上面產生一個LxL矩陣的規模,這是內存效率低下。 L = 10 ** 6之前將OOM。 我們可以使用此答案建議的廣播歸一化程序來解決此問題

import numpy as np
def random_proportions(L,n):
      zeros = 1
      while zeros>0:
          x = np.random.random(size=(L,n))
          zeros = np.sum(x==0.0)
      sums = x.sum(axis=1).reshape(L,1) # reshape for "broadcasting" effect
      return x/sums

在具有16GB內存的AMD FX-8150上,此第二版將在大約1/3秒內計算100萬個大小為10的列表:

%timeit l = random_proportions(1000000,10)
1 loops, best of 3: 347 ms per loop

這是獲得n加起來為1的數字的方法:在您選擇的任意范圍內(例如1到10)選擇n隨機數,然后將它們全部除以它們的和。

這應該可以解決問題:

import random


def floatPartition(n, total):
    answer = []
    for _ in range(n-1):
        num = random.uniform(0, total)
        answer.append(num)
        total -= num
    answer.append(total)
    return answer


def paritions(n,L):
    return [floatPartition(n, 1) for _ in range(L)]


if __name__ == "__main__":
    answer = paritions(6,200)

我沒有檢查其他速度,但是此算法會在20秒內生成1,000,000個長度為10的列表,其中元素0.01-0.99的增量為0.01:

import random
def rand_list(n):

    sub_list = []
    max_val  = 100 - n + 1  # max needs to be n-1 less than 100

    for repetition in xrange(n-1):

        sub_list += [random.randrange(1, max_val)]
        max_val  -= (sub_list[-1] - 1)  # decrease the range by the latest element added - 1

    sub_list += [max_val]  # use the remainder for the last value, this way it adds to 100

    return [round(x/100.0, 2) for x in sub_list]  # convert to 0.01 - 0.99 with list comprehension

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM