এলোমেলো সংখ্যার একটি তালিকা তৈরি করা হচ্ছে, সমষ্টি 1 করে


84

আমি কীভাবে এন (100 বলুন) এলোমেলো সংখ্যার একটি তালিকা তৈরি করব, যাতে তাদের যোগফল 1 হয়?

আমি এলোমেলো সংখ্যার সাথে একটি তালিকা তৈরি করতে পারি

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

আমি এটি কীভাবে সংশোধন করব যাতে তালিকাটি 1 এর সমষ্টি হয় (এটি সম্ভাব্যতা সিমুলেশনের জন্য)।


4
যদি তাদের যোগফল 1 হয় তবে তারা সম্পূর্ণ এলোমেলো নয়।
ফিজারি

20
তালিকার প্রতিটি সংখ্যাকে তালিকার সমষ্টি অনুসারে ভাগ করুন
আরগায়ার

4
@ বোগদান এটি আসলে কোনও সমস্যা নয়।
টম কেলি

4
পছন্দ করেছেন এগুলি এলোমেলো, তবে এক ডিগ্রি স্বাধীনতা সীমাবদ্ধতার দ্বারা ব্যবহৃত হয়।
pjs

4
@pjs, যার অর্থ (সর্বোত্তমভাবে) এর মধ্যে 99 টি এলোমেলো এবং 1 টি নয়। অন্য কথায়, "পুরোপুরি এলোমেলো নয়"।
ফিজরি

উত্তর:


155

সহজ সমাধানটি হ'ল এন এলোমেলো মান গ্রহণ করে যোগফলকে ভাগ করে।

আরও জেনেরিক সমাধান হ'ল ডাইরিচলেট বিতরণ http://en.wikedia.org/wiki/Dirichlet_dist वितरण যা অদ্ভুতভাবে উপলব্ধ use

বিতরণের প্যারামিটারগুলি পরিবর্তন করে আপনি স্বতন্ত্র সংখ্যার "এলোমেলো" পরিবর্তন করতে পারেন

>>> 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 হবে, বা এই সম্ভাবনার মধ্যে কিছু দেবে।

সম্পাদনা (মূল উত্তরের 5 বছর পরে): ডিরিচলেট বিতরণ সম্পর্কে আরেকটি দরকারী তথ্য হ'ল আপনি স্বভাবতই তা পেয়ে যান, যদি আপনি এলোমেলো ভেরিয়েবলের গামা-বিতরিত সেট তৈরি করেন এবং তারপরে তাদের যোগফল দিয়ে ভাগ করেন।


4
+1 শুধুমাত্র ডিরিচলেট বিতরণ উল্লেখ করার জন্য। এই উত্তর হওয়া উচিত।
টিমোথি শিল্ডস

4
আমি এইটির কাছে আমার গ্রহণযোগ্য উত্তরটি পরিবর্তন করেছি, কারণ স্কেলিং অগত্যা অভিন্ন বিতরণ দেয় না।
টম কেলি

4
@Tom, আমি আপনার পছন্দ ব্যাপারে অসন্তুষ্ট হওয়া না থাকে, এবং এই উত্তরটি সুন্দর, কিন্তু আমি স্পষ্ট কিছু করতে চাই: স্কেলিং করে অগত্যা একটি অভিন্ন বন্টন (ওভার দিতে [0,1/s))। এটি যে অনাবৃত বিহীন বিতরণ দিয়ে আপনি শুরু করেছিলেন ঠিক তেমনই অভিন্ন হবে, কারণ স্কেলিং বিতরণ পরিবর্তন করে না, তবে কেবল এটি সংকুচিত করে। এই উত্তরটি বিভিন্ন বিতরণ দেয়, যার মধ্যে একটি অভিন্ন। যদি এটি আপনার কাছে বোঝায় না, উদাহরণগুলি চালনা করুন এবং এটি পরিষ্কার করার জন্য কয়েকটি হিস্টোগ্রাম দেখুন ogra গাউসীয় বিতরণ ( np.random.normal) দিয়েও একই জিনিস ব্যবহার করে দেখুন ।
জিজ্ঞাসাবাদ

@ এসকিউচান, আপনি এখানে সঠিক নন। এলোমেলো সংখ্যা নেওয়া এবং যোগফলের মাধ্যমে বিভাজন অভিন্ন বিতরণ দেয় না (এটি খুব বড় এন এর জন্য ইউনিফর্মের কাছাকাছি হবে, তবে কখনও কঠোরভাবে ইউনিফর্ম হবে না এবং ছোট এন এ মোটেও অভিন্ন হবে না)। ডিরিচলেট বিতরণ অভিন্ন বিতরণও দেবে না (কারণ অভিন্ন বিতরণ এবং 1 এর যোগফল পাওয়া অসম্ভব)।
sega_sai

@ সেগা_সাই সেই শিরাতে, এমন কোনও কঠোরভাবে অভিন্ন বিতরণ নেই যা ছদ্ম-এলোমেলোভাবে উত্পন্ন করা যায়। আমার অর্থ হ'ল 'ইউনিফর্ম' বিতরণকে নতুন করে তৈরি করা এটিকে কোনও কম ইউনিফর্ম করে না। আমি টমের মন্তব্যে জবাব দিচ্ছিলাম যা বোঝায় যে এই উত্তরটি নির্বাচন করা হয়েছিল কারণ তিনি অভিন্ন বিতরণ চেয়েছিলেন। যদি না আমি আরও মৌলিকভাবে ভুল করি?
askewchan

39

এটি করার সর্বোত্তম উপায় হ'ল আপনার ইচ্ছামতো সংখ্যার একটি তালিকা তৈরি করা, তারপরে সমস্তগুলি যোগফল দিয়ে ভাগ করুন। তারা পুরোপুরি এলোমেলোভাবে।

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

বা, @ টমকিলির পরামর্শ অনুসারে, যোগফল এবং সৃষ্টিটিকে একটি লুপে রাখুন:

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

4
@ টম কোনও উদ্বেগ নয়, এই জিনিসগুলিকে তাদের চেয়ে আরও শক্ত করার চেষ্টা করে আটকা পড়ে যাওয়া সহজ: এখন এটি পরবর্তী ব্যক্তির জন্য এখানে।
জিজ্ঞাসা

4
আমি মনে করি এটি বিয়ারের সময় হয়েছে।
টম ক্যালি

4
এটি একটি ভাল সমাধান, তবে মনে হচ্ছে এটি একক পাসে করার একটি উপায় থাকা উচিত যা পরিসীমা জুড়ে একটি ভাল বিতরণ পায়। তৈরি করুন, যোগ করুন, সংশোধন করুন একটি 3 পাস অপারেশন। যদিও আপনি জেনারেট করে সংখ্যার মাধ্যমে কমপক্ষে একটি পাসকে অপ্টিমাইজ করতে পারেন।
সিলাস রায়

4
স্কেলিং অগত্যা ভাল নয়। আরও উত্তর জন্য আমার উত্তর দেখুন। [0,1) থেকে অনেকগুলি সম্ভাব্য ম্যাপিং রয়েছে space n লক্ষ্য স্থানে (x_i = 1 এর যোগফল) এবং সেগুলি সমস্ত অভিন্ন হতে পারে না!
মাইক হাউস্কি

4
এই ভুল , কেস অন্তত আপনার সম্পর্কে প্রকৃত অভিন্ন ডিস্ট্রিবিউশন পরোয়া stackoverflow.com/a/8068956/2075003
n1000

7

মোট প্রতিটি সংখ্যা ভাগ করে নেওয়া আপনার পছন্দসই বিতরণ দিতে পারে না। উদাহরণস্বরূপ, দুটি সংখ্যার সাথে, জোড়া, এক্স = y = এলোমেলো। (X, y) থেকে (x, y) লাইন ধরে (x, y) থেকে শুরু করে মূল পর্যন্ত রেখাটিতে যে বিন্দুতে (x, y) যোগফলকে "প্রজেক্ট" দিয়ে ভাগ করা হচ্ছে। (০.০,০.৫) এর নিকটবর্তী পয়েন্টগুলি (0.1,0.9) এর কাছাকাছি পয়েন্টগুলির তুলনায় অনেক বেশি সম্ভাবনা রয়েছে।

দুটি ভেরিয়েবলের জন্য, তারপরে, x = random.random (), y = 1-x জ্যামিতিক লাইন বিভাগের সাথে অভিন্ন বিতরণ দেয়।

৩ টি ভেরিয়েবলের সাহায্যে আপনি একটি ঘনককে এলোমেলো পয়েন্টটি তুলছেন এবং প্রজেক্টিং করছেন (রেডিয়ালি, অরিজিনের মধ্য দিয়ে) তবে ত্রিভুজের কেন্দ্রের নিকটে অবস্থিত পয়েন্টগুলি উল্লম্বের কাছাকাছি পয়েন্টগুলির চেয়ে বেশি সম্ভবত হবে। ফলাফলগুলি পয়েন্টগুলি x + y + z বিমানের একটি ত্রিভুজগুলিতে রয়েছে। আপনার যদি সেই ত্রিভুজের বিন্দুযুক্ত পয়েন্টের প্রয়োজন হয় তবে স্কেলিং ভাল নয়।

সমস্যাটি এন-ডাইমেনশনগুলিতে জটিল হয়ে ওঠে, তবে আপনি অ-নেতিবাচক পূর্ণসংখ্যার সমস্ত এন-টিপলস সেট থেকে সমানভাবে বাছাই করে একটি স্বল্প-নির্ভুলতা (তবে উচ্চতর নির্ভুলতা, আপনার সমস্ত পরীক্ষাগার বিজ্ঞানের ভক্তদের জন্য) পেতে পারেন এন, এবং তারপরে এন দ্বারা তাদের প্রত্যেককে ভাগ করে নিন।

আমি সম্প্রতি পরিমিত আকারের এন, এন এর জন্য একটি অ্যালগরিদম নিয়ে এসেছি you ডিজিটের র্যান্ডম দেওয়ার জন্য এটি এন = 100 এবং এন = 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_values <= 1/min_thesh)

সুতরাং মূলত, আমরা ন্যূনতম প্রান্তিকের জন্য 1 এর কিছু অংশ ঠিক করছি, তারপরে আমরা অন্যান্য অংশে এলোমেলো সংখ্যা তৈরি করব। min_theshযোগফল 1 এর জন্য আমরা সমস্ত সংখ্যায় যুক্ত করি eg উদাহরণস্বরূপ: ধরুন আপনি min_thresh = 0.2 দিয়ে 3 নম্বর উত্পন্ন করতে চান। আমরা এলোমেলো সংখ্যা দ্বারা পূরণ করার জন্য একটি অংশ তৈরি করি [1 - (0.2x3) = 0.4]। আমরা সেই অংশটি পূরণ করি এবং সমস্ত মানগুলিতে 0.2 যোগ করি, সুতরাং আমরা 0.6 ভরাও পেতে পারি।

এটি স্ট্যান্ডার্ড স্কেলিং এবং স্থানান্তর যা এলোমেলো সংখ্যার প্রজন্মের তত্ত্বে ব্যবহৃত হয়। ক্রেডিট আমার বন্ধু জিল বৈষ্ণব (এসও প্রোফাইল আছে কিনা তা আমি নিশ্চিত নই) এবং @ সেগা_সাই এর কাছে যায়।



0

"তালিকার প্রতিটি সংখ্যাকে তালিকার সমষ্টি অনুসারে ভাগ করুন" এর চেতনায় এই সংজ্ঞাটি প্রতিটি উপাদানকে প্লাস (বা কোনও নয়) এর সাথে বৃত্তাকারে দৈর্ঘ্য = পার্টস, যোগফল = মোটের একটি তালিকা তৈরি করবে:

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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.