5
A
回答
3
只是對dflemstr的答案擴大,您可以使用Control.Monad.Random這樣創造的加權值的無窮列表:
import Control.Monad.Random
import System.Random
weightedList :: RandomGen g => g -> [(a, Rational)] -> [a]
weightedList gen weights = evalRand m gen
where m = sequence . repeat . fromList $ weights
而且使用這樣的:
> let values = weightedList (mkStdGen 123) [(1, 2), (2, 5), (3, 10)]
> take 20 values
[2,1,3,2,1,2,2,3,3,3,3,3,3,2,3,3,2,2,2,3]
這並不需要IO monad,但您需要提供用於流的隨機數生成器。
5
Control.Monad.Random
提供在fromList
:: MonadRandom m => [(a, Rational)] -> m a
形式此功能可以在IO
單子與使用它:
import Control.Monad.Random
-- ...
someNums <- evalRandIO . sequence . repeat . fromList $ [(1, 0.3), (2, 0.2), (3, 0.5)]
print $ take 200 someNums
有運行Rand
單子的其他方式,你可以在包看。權重不必加起來1
編輯:Rand
比我想象的明顯懶惰,所以replicateM n
可以通過sequence . repeat
取代,如@shang建議。
11
正如人們指出Control.Monad.Random
中有一個函數,但它的複雜度相當差。下面是我今天上午寫的一些巧合的代碼。它使用美麗的Alias算法。
module Data.Random.Distribution.NonUniform(randomsDist) where
import Data.Array
import Data.List
import System.Random
genTable :: (Num a, Ord a) => [a] -> (Array Int a, Array Int Int)
genTable ps =
let n = length ps
n' = fromIntegral n
(small, large) = partition ((< 1) . snd) $ zip [0..] $ map (n' *) ps
loop ((l, pl):ls) ((g, pg):gs) probs aliases =
let prob = (l,pl)
alias = (l,g)
pg' = (pg + pl) - 1
gpg = (g, pg')
in if pg' < 1 then loop (gpg:ls) gs (prob:probs) (alias:aliases)
else loop ls (gpg:gs) (prob:probs) (alias:aliases)
loop ls gs probs aliases = loop' (ls ++ gs) probs aliases
loop' [] probs aliases = (array (0,n-1) probs, array (0,n-1) aliases)
loop' ((g,_):gs) probs aliases = loop' gs ((g,1):probs) ((g, -1):aliases)
in loop small large [] []
-- | Generate an infinite list of random values with the given distribution.
-- The probabilities are scaled so they do not have to add up to one.
--
-- Uses Vose's alias method for generating the values.
-- For /n/ values this has O(/n/) setup complexity and O(1) complexity for each
-- generated item.
randomsDist :: (RandomGen g, Random r, Fractional r, Ord r)
=> g -- | random number generator
-> [(a, r)] -- | list of values with the probabilities
-> [a]
randomsDist g xps =
let (xs, ps) = unzip xps
n = length xps
axs = listArray (0, n-1) xs
s = sum ps
(probs, aliases) = genTable $ map (/ s) ps
(g', g'') = split g
is = randomRs (0, n-1) g'
rs = randoms g''
ks = zipWith (\ i r -> if r <= probs!i then i else aliases!i) is rs
in map (axs!) ks
相關問題
- 1. 以固定概率生成隨機數
- 2. 生成隨機數與給定的概率
- 3. 以概率生成隨機數
- 4. 如何根據給定的概率生成隨機事件?
- 5. 用概率分佈生成範圍內的隨機整數
- 6. 帶概率的隨機圖生成
- 7. 生成具有一定概率的隨機數
- 8. 概率隨機數?
- 9. Matlab:從給定概率的正態分佈中生成隨機數
- 10. 概率隨機數發生器
- 11. 隨機數字的概率
- 12. 高概率數的隨機?
- 13. c#概率和隨機數
- 14. 概率和隨機數
- 15. 根據概率分佈函數生成隨機數
- 16. 在matlab中隨機生成概率的數字
- 17. 如何根據Java中的概率生成隨機數
- 18. 隨機生成的數字遊戲與概率和循環
- 19. 生成具有不同概率的隨機數
- 20. PHP隨機概率
- 21. 隨機概率PHP
- 22. 隨機函數,其與給定的概率
- 23. 從三維概率分佈生成隨機數
- 24. 基於概率隨機生成子集數據
- 25. Python - 如何用逐位概率生成隨機數?
- 26. Python numpy根據概率生成隨機二進制值數組
- 27. 如何將概率添加到隨機數生成器中
- 28. 從給定數字生成隨機數
- 29. 如何用特定的概率密度函數生成一個隨機數?
- 30. C++,給定概率如何隨機選擇數字
我只是想這個「總時間55.59s」對執行此:http://idontgetoutmuch.wordpress.com/2014/08/26/haskell-vectors-and-sampling-from-a-categorical分佈/「總時間11.09s」在兩種情況下采樣2 * 10^7個樣本。也許這不是一個公平的比較,因爲使用System.Random和其他System.Random.MWC。 – idontgetoutmuch 2014-08-28 06:57:35
是的,我會假設生成隨機數將主宰我的代碼。它還需要專業化,這可能會在-O2時自動發生。 – augustss 2014-08-28 07:46:13
使用不同的隨機數發生器,我得到了「總時間20.31s」,但仍然不如以前好。我還沒有嘗試過專業化。內存使用情況也不好。我希望兩個表中的每個條目都有4 + 8個字節,因此應該是2 * 12 * 10^7個字節,因此小於1G。我看到大約5G。我可能很天真。我還沒有讀完Devroye和Vose。誰會想到你可以用隨機數字獲得如此多的樂趣。 – idontgetoutmuch 2014-08-29 08:33:40