यादृच्छिक संख्याओं की एक सूची बनाना, 1 तक संक्षेप


84

मैं N (100 नंबर) को यादृच्छिक संख्याओं की सूची कैसे बनाऊंगा, ताकि उनकी राशि 1 हो?

मैं के साथ यादृच्छिक संख्याओं की एक सूची बना सकता हूं

r = [ran.random() for i in range(1,100)]

मैं इसे कैसे संशोधित करूंगा ताकि यह सूची 1 पर आ जाए (यह प्रायिकता सिमुलेशन के लिए है)।


5
यदि उनकी राशि 1 है, तो वे पूरी तरह से यादृच्छिक नहीं हैं।
फजर्री

19
सूची में प्रत्येक संख्या को सूची के योग से विभाजित करें
aragaer

1
@ बोगदान वास्तव में एक मुद्दा नहीं है।
टॉम केली

2
@ बोगदान सही नहीं है। वे यादृच्छिक हैं, लेकिन स्वतंत्रता की एक डिग्री बाधा द्वारा उपयोग की जाती है।
PJs

2
@ पीजे, जिसका अर्थ है कि (सबसे अच्छे रूप में) उनमें से 99 यादृच्छिक हैं और 1 नहीं है। दूसरे शब्दों में, "पूरी तरह से यादृच्छिक नहीं"।
फ़जर्री

जवाबों:


151

सबसे सरल उपाय वास्तव में एन यादृच्छिक मूल्यों को लेना और योग द्वारा विभाजित करना है।

एक और अधिक सामान्य समाधान है ड्यूरिचलेट डिस्ट्रीब्यूशन http://en.wikipedia.org/wiki/Dirichlet_distribution का उपयोग करना जो कि खसखस ​​में उपलब्ध है।

वितरण के मापदंडों को बदलकर आप व्यक्तिगत संख्याओं की "यादृच्छिकता" को बदल सकते हैं

>>> import numpy as np, numpy.random
>>> print np.random.dirichlet(np.ones(10),size=1)
[[ 0.01779975  0.14165316  0.01029262  0.168136    0.03061161  0.09046587
   0.19987289  0.13398581  0.03119906  0.17598322]]

>>> print np.random.dirichlet(np.ones(10)/1000.,size=1)
[[  2.63435230e-115   4.31961290e-209   1.41369771e-212   1.42417285e-188
    0.00000000e+000   5.79841280e-143   0.00000000e+000   9.85329725e-005
    9.99901467e-001   8.37460207e-246]]

>>> print np.random.dirichlet(np.ones(10)*1000.,size=1)
[[ 0.09967689  0.10151585  0.10077575  0.09875282  0.09935606  0.10093678
   0.09517132  0.09891358  0.10206595  0.10283501]]

मुख्य पैरामीटर के आधार पर ड्यूरिचलेट वितरण या तो वैक्टर देगा जहां सभी मान 1./N के करीब होंगे जहां एन वेक्टर की लंबाई है, या वेक्टर देते हैं जहां वैक्टर के अधिकांश मान ~ 0 होंगे, और वहां एक एकल 1 होगा, या उन संभावनाओं के बीच में कुछ देगा।

EDIT (मूल उत्तर के 5 साल बाद): डिरिचलेट वितरण के बारे में एक और उपयोगी तथ्य यह है कि आप स्वाभाविक रूप से इसे प्राप्त करते हैं, यदि आप यादृच्छिक चर का एक गामा-वितरित सेट उत्पन्न करते हैं और फिर उन्हें उनके योग से विभाजित करते हैं।


4
डिरिचलेट वितरण का उल्लेख करने के लिए केवल 1 ही है। इसका उत्तर होना चाहिए।
टिमोथी शील्ड

2
मैंने अपना स्वीकृत उत्तर इस एक में बदल दिया है, क्योंकि स्केलिंग अनिवार्य रूप से एक समान वितरण नहीं देता है।
टॉम कीली

1
@Tom, मैं अपनी पसंद नापसंद करते हैं, और इस जवाब अच्छा है, लेकिन मैं स्पष्ट कुछ बनाना चाहते: स्केलिंग है जरूरी एक समान वितरण (अधिक देना [0,1/s))। यह आपके द्वारा शुरू किए गए बिना वितरण के समान ही समान होगा, क्योंकि स्केलिंग से वितरण में बदलाव नहीं होता है, लेकिन यह इसे संकुचित करता है। यह उत्तर कई प्रकार के वितरण देता है, जिनमें से केवल एक समान है। यदि इससे आपको कोई मतलब नहीं है, तो उदाहरणों को चलाएं और इसे स्पष्ट करने के लिए कुछ हिस्टोग्राम देखें। गॉसियन डिस्ट्रीब्यूशन ( np.random.normal) के साथ भी यही कोशिश करें ।
आस्कवेचन

@askewchan, आप यहां सही नहीं हैं। रैंडम नंबर लेने और योग से विभाजित करने पर समान वितरण नहीं होगा (यह बहुत बड़े एन के लिए वर्दी के करीब होगा, लेकिन कड़ाई से वर्दी और छोटे एन में बिल्कुल भी समान नहीं है)। Dirichlet वितरण समान वितरण नहीं देगा (क्योंकि समान वितरण और 1 का योग प्राप्त करना असंभव है)।
sega_sai

@sega_sai उस नस में, कोई सख्ती से समान वितरण नहीं है जो कि छद्म-यादृच्छिक रूप से उत्पन्न हो सकता है। मेरे कहने का मतलब यह है कि 'वर्दी' वितरण का नाम बदलने से यह कम समान नहीं हो जाता है। मैं टॉम की टिप्पणी का जवाब दे रहा था जिसने इस उत्तर को चुना क्योंकि वह एक समान वितरण चाहता था। जब तक मैं अधिक मौलिक रूप से गलत नहीं हूँ?
प्रश्नवचन

39

इसका सबसे अच्छा तरीका यह है कि आप जितनी चाहें उतनी संख्याओं की एक सूची बना लें, फिर उन सभी को राशि में विभाजित करें। वे इस तरह पूरी तरह से यादृच्छिक हैं।

r = [ran.random() for i in range(1,100)]
s = sum(r)
r = [ i/s for i in r ]

या, जैसा कि @TomKealy द्वारा सुझाया गया है, एक लूप में योग और निर्माण रखें:

rs = []
s = 0
for i in range(100):
    r = ran.random()
    s += r
    rs.append(r)

सबसे तेज़ प्रदर्शन के लिए, उपयोग करें numpy:

import numpy as np
a = np.random.random(100)
a /= a.sum()

और आप एक संभावित वितरण के लिए रैंडम नंबर किसी भी वितरण को दे सकते हैं,

a = np.random.normal(size=100)
a /= a.sum()

---- समय ----

In [52]: %%timeit
    ...: r = [ran.random() for i in range(1,100)]
    ...: s = sum(r)
    ...: r = [ i/s for i in r ]
   ....: 
1000 loops, best of 3: 231 µs per loop

In [53]: %%timeit
   ....: rs = []
   ....: s = 0
   ....: for i in range(100):
   ....:     r = ran.random()
   ....:     s += r
   ....:     rs.append(r)
   ....: 
10000 loops, best of 3: 39.9 µs per loop

In [54]: %%timeit
   ....: a = np.random.random(100)
   ....: a /= a.sum()
   ....: 
10000 loops, best of 3: 21.8 µs per loop

2
@ कोई चिंता नहीं, इन चीजों को बनाने की कोशिश करना आसान हो गया है क्योंकि वे इन चीजों को बहुत कठिन बना रहे हैं :) अब यह अगले व्यक्ति के लिए यहां है।
Askewchan

3
मुझे लगता है कि यह बीयर का समय है।
टॉम केली

1
यह एक अच्छा समाधान है, लेकिन ऐसा लगता है कि एक एकल पास में ऐसा करने का एक तरीका होना चाहिए जो सीमा के पार अच्छा वितरण प्राप्त करता है। बनाएँ, योग, संशोधित एक 3 पास ऑपरेशन है। यद्यपि आप कम से कम एक पास को पास से अनुकूलित कर सकते हैं जैसा कि आप उत्पन्न करते हैं।
सिलस रे

2
जरूरी नहीं कि स्केलिंग अच्छी हो। अधिक के लिए मेरा जवाब देखें। लक्ष्य स्थान पर [0,1) ^ n से कई संभावित मैपिंग हैं (x_i = 1 का योग) और वे सभी समान नहीं हो सकते हैं!
माइक हाउसकी

1
यह गलत है , कम से कम यदि आप वास्तविक वर्दी वितरण के बारे में परवाह करते हैं stackoverflow.com/a/8068956/2075003
n1000

7

प्रत्येक संख्या को कुल से विभाजित करने पर आपको वह वितरण नहीं मिल सकता है जो आप चाहते हैं। उदाहरण के लिए, दो संख्याओं के साथ, युग्म x, y = random.random (), random.random () वर्ग 0 <= x <1, 0 <= y <1 पर समान रूप से एक बिंदु चुनता है। मूल "x", बिंदु (x, y) से रेखा पर x (y, 1) की रेखा से मूल (x, y) तक के योग से विभाजित करना। अंक (0.5,0.5) के पास (0.1,0.9) के पास अंक की तुलना में बहुत अधिक होने की संभावना होगी।

दो चर के लिए, फिर, x = random.random (), y = 1-x ज्यामितीय रेखा खंड के साथ एक समान वितरण देता है।

3 चर के साथ, आप एक घन में एक यादृच्छिक बिंदु उठा रहे हैं और प्रक्षेपित कर रहे हैं (मूल रूप से, मूल रूप से), लेकिन त्रिकोण के केंद्र के पास बिंदुओं के पास बिंदुओं की तुलना में अधिक संभावना होगी। परिणामी बिंदु x + y + z समतल में एक त्रिभुज पर हैं। यदि आपको उस त्रिकोण में अंक के निष्पक्ष विकल्प की आवश्यकता है, तो स्केलिंग अच्छा नहीं है।

समस्या एन-आयामों में जटिल हो जाती है, लेकिन आप कम सटीकता (लेकिन उच्च सटीकता, जो आप सभी प्रयोगशाला विज्ञान के प्रशंसकों के लिए प्राप्त कर सकते हैं!) का अनुमान है कि गैर-नकारात्मक पूर्णांक के सभी n-tuples के सेट से समान रूप से जोड़कर। एन, और फिर उनमें से प्रत्येक को एन द्वारा विभाजित करना।

मैं हाल ही में एक एल्गोरिथ्म के साथ आया था कि मामूली आकार के एन के लिए, एन। यह आपको 6-अंकों के रैंडम देने के लिए n = 100 और N = 1,000,000 के लिए काम करना चाहिए। मेरा जवाब यहां देखें:

विवश यादृच्छिक संख्याएँ बनाएँ?


आपको डिरिचलेट वितरण की जांच करनी चाहिए ।
जोनाथन एच।

6

0 और 1 से मिलकर एक सूची बनाएँ, फिर 99 यादृच्छिक संख्याएँ जोड़ें। सूची को क्रमबद्ध करें। क्रमिक अंतर अंतराल की लंबाई होगी जो 1 तक जोड़ता है।

मैं पाइथन में धाराप्रवाह नहीं हूं, इसलिए अगर ऐसा करने का अधिक पाइथोनिक तरीका है तो मुझे माफ कर दें। मुझे आशा है कि इरादा स्पष्ट है, हालांकि:

import random

values = [0.0, 1.0]
for i in range(99):
    values.append(random.random())
values.sort()
results = []
for i in range(1,101):
    results.append(values[i] - values[i-1])
print results

यहाँ पायथन 3 में एक अद्यतन कार्यान्वयन है:

import random

def sum_to_one(n):
    values = [0.0, 1.0] + [random.random() for _ in range(n - 1)]
    values.sort()
    return [values[i+1] - values[i] for i in range(n)]

print(sum_to_one(100))

3

@ पीजे के समाधान के अलावा हम एक फ़ंक्शन को दो मापदंडों के साथ भी परिभाषित कर सकते हैं।

import numpy as np

def sum_to_x(n, x):
    values = [0.0, x] + list(np.random.uniform(low=0.0,high=x,size=n-1))
    values.sort()
    return [values[i+1] - values[i] for i in range(n)]

sum_to_x(10, 0.6)
Out: 
[0.079058655684546,
 0.04168649034779022,
 0.09897491411670578,
 0.065152293196646,
 0.000544800901222664,
 0.12329662037166766,
 0.09562168167787738,
 0.01641359261155284,
 0.058273232428072474,
 0.020977718663918954]  

1

100 यादृच्छिक संख्याएँ उत्पन्न होती हैं, जो कि कोई सीमा नहीं है। उत्पन्न संख्याओं को जोड़ दें, प्रत्येक व्यक्ति को कुल से विभाजित करें।


1

यदि आप यादृच्छिक रूप से चुनी गई संख्याओं के लिए न्यूनतम सीमा रखना चाहते हैं (यानी, उत्पन्न संख्याएँ कम से कम होनी चाहिए min_thresh),

rand_prop = 1 - num_of_values * min_thresh
random_numbers = (np.random.dirichlet(np.ones(10),size=1)[0] * rand_prop) + min_thresh

बस यह सुनिश्चित करें कि आपके पास num_of_values ​​(उत्पन्न होने वाले मूल्यों की संख्या) ऐसी है कि आवश्यक संख्याओं को उत्पन्न करने के लिए संभव है num_values <= 1/min_thesh)

इसलिए मूल रूप से, हम न्यूनतम दहलीज के लिए 1 के कुछ हिस्से को ठीक कर रहे हैं, फिर हम दूसरे हिस्से में यादृच्छिक संख्या बनाते हैं। हम min_theshयोग पाने के लिए सभी संख्याओं को जोड़ते हैं । उदाहरण के लिए: मान लें कि आप 3 संख्याएँ उत्पन्न करना चाहते हैं, जिसमें min_thresh = 0.2 है। हम यादृच्छिक संख्याओं द्वारा भरने के लिए एक भाग बनाते हैं [1 - (0.2x3) = 0.4]। हम उस हिस्से को भरते हैं और सभी मूल्यों में 0.2 जोड़ते हैं, इसलिए हम 0.6 को भी भर सकते हैं।

यह रैंडम नंबर जनरेशन थ्योरी में इस्तेमाल होने वाला स्टैंडर्ड स्केलिंग और शिफ्टिंग है। इसका श्रेय मेरे दोस्त जील वैष्णव (मुझे यकीन नहीं है कि अगर एसओ प्रोफाइल है) और @sega_sai को जाता है।


0

आप आसानी से कर सकते हैं:

r.append(1 - sum(r))

1
अंतिम संख्या फिर पहले N-1नंबरों के साथ सहसंबद्ध है ।
Askewchan

0

"सूची के योग द्वारा प्रत्येक तत्व को सूची में विभाजित करें" की भावना में, यह परिभाषा PLACES (या कोई नहीं) में गोल किए गए प्रत्येक तत्व के साथ लंबाई की यादृच्छिक संख्या = PARTS, sum = TOTAL बनाएगी।

import random
import time

PARTS       = 5
TOTAL       = 10
PLACES      = 3

def random_sum_split(parts, total, places):

    a = []
    for n in range(parts):
        a.append(random.random())
    b = sum(a)
    c = [x/b for x in a]    
    d = sum(c)
    e = c
    if places != None:
        e = [round(x*total, places) for x in c]
    f = e[-(parts-1):]
    g = total - sum(f)
    if places != None:
        g = round(g, places)
    f.insert(0, g)

    log(a)
    log(b)
    log(c)
    log(d)
    log(e)
    log(f)
    log(g)

    return f   

def tick():

    if info.tick == 1:

        start = time.time()

        alpha = random_sum_split(PARTS, TOTAL, PLACES)

        log('********************')
        log('***** RESULTS ******')
        log('alpha: %s' % alpha)
        log('total: %.7f' % sum(alpha))
        log('parts: %s' % PARTS)
        log('places: %s' % PLACES)

        end = time.time()  

        log('elapsed: %.7f' % (end-start))

परिणाम:

Waiting...
Saved successfully.
[2014-06-13 00:01:00] [0.33561018369775897, 0.4904215932650632, 0.20264927800402832, 0.118862130636748, 0.03107818050878819]
[2014-06-13 00:01:00] 1.17862136611
[2014-06-13 00:01:00] [0.28474809073311597, 0.41609766067850096, 0.17193755673414868, 0.10084844382959707, 0.02636824802463724]
[2014-06-13 00:01:00] 1.0
[2014-06-13 00:01:00] [2.847, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] [2.848, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] 2.848
[2014-06-13 00:01:00] ********************
[2014-06-13 00:01:00] ***** RESULTS ******
[2014-06-13 00:01:00] alpha: [2.848, 4.161, 1.719, 1.008, 0.264]
[2014-06-13 00:01:00] total: 10.0000000
[2014-06-13 00:01:00] parts: 5
[2014-06-13 00:01:00] places: 3
[2014-06-13 00:01:00] elapsed: 0.0054131

0

पीजे की विधि की भावना में:

a = [0, total] + [random.random()*total for i in range(parts-1)]
a.sort()
b = [(a[i] - a[i-1]) for i in range(1, (parts+1))]

यदि आप उन्हें दशमलव स्थानों पर गोल करना चाहते हैं:

if places == None:
    return b
else:    
    b.pop()
    c = [round(x, places) for x in b]  
    c.append(round(total-sum(c), places))
    return c
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.