تص

تصادفی در Python

{one: "۱ تمرین", other: "%{count} تمرین"}

درباره‌ی تصادفی

بسیاری از برنامه‌ها برای شبیه‌سازی رویدادهای دنیای واقعی به مقادیر تصادفی (به ظاهر تصادفی) نیاز دارند.

نمونه‌های رایج و آشنای آن عبارت‌اند از:

  • انداختن سکه: مقداری تصادفی از ('Heads', 'Tails').
  • انداختن تاس: عددی صحیح و تصادفی از ۱ تا ۶.
  • بُر زدن دسته‌ای ورق: ترتیبی تصادفی از فهرست ورق‌ها.

تولید مقادیر واقعاً تصادفی با رایانه چالشی فنی و به‌طرز غافلگیرکننده‌ای دشوار است، به همین دلیل ممکن است ببینید به این نتایج «شبه‌تصادفی» می‌گویند.

در عمل، یک کتابخانه‌ی خوش‌طراحی مانند ماژول random در کتابخانه‌ی استاندارد Python سریع، انعطاف‌پذیر است و نتایجی می‌دهد که برای بیشتر کاربردها در مدل‌سازی، شبیه‌سازی و بازی‌ها کاملاً کافی است.

بقیه‌ی این صفحه چند مورد از رایج‌ترین توابع random را فهرست می‌کند. شما را تشویق می‌کنیم که مستندات کامل random را کاوش کنید، چون گزینه‌های بسیار بیشتری از آنچه اینجا پوشش می‌دهیم وجود دارد.

Caution

ماژول random نباید برای کاربردهای امنیتی یا رمزنگاری استفاده شود.

در عوض، Python ماژول secrets را ارائه می‌دهد. این ماژول به‌طور ویژه برای امنیت رمزنگاری بهینه شده است. برخی از مشکلات پیشین و دلایل ساخت ماژول secrets را می‌توانید در PEP 506 پیدا کنید.

وارد کردن ماژول

پیش از آنکه بتوانید از ابزارهای ماژول random استفاده کنید، ابتدا باید آن را وارد کنید:

>>> import random

# Choose random integer from a range
>>> random.randrange(1000)
360

>>> random.randrange(-1, 500)
228

>>> random.randrange(-10, 11, 2)
-8

# Choose random integer between two values (inclusive)
>>> random.randint(5, 25)
22

برای اینکه مجبور نباشید اسم ماژول را تایپ کنید، می‌توانید توابع مشخصی را با اسم وارد کنید:

>>> from random import choice, choices

# Using choice() to pick Heads or Tails 10 times
>>> tosses = []
... for side in range(10):
...    tosses.append(choice(['H', 'T']))    

>>> print(tosses)
['H', 'H', 'H', 'H', 'H', 'H', 'H', 'T', 'T', 'H']


# Using choices() to pick Heads or Tails 8 times
>>> picks = []
... picks.extend(choices(['H', 'T'], k=8))
... print(picks)
['T', 'H', 'H', 'T', 'H', 'H', 'T', 'T']

ساختن اعداد صحیح تصادفی

تابع randrange() سه شکل دارد و در هر شکل مقداری تصادفی را از range(start, stop, step) انتخاب می‌کند:

  1. randrange(stop) عدد صحیحی مانند n می‌دهد به‌طوری که 0 <= n < stop
  2. randrange(start, stop) عدد صحیحی مانند n می‌دهد به‌طوری که start <= n < stop
  3. randrange(start, stop, step) عدد صحیحی مانند n می‌دهد به‌طوری که start <= n < stop و n در دنباله‌ی start, start + step, start + 2*step... قرار دارد

برای حالت رایجی که step == 1 باشد، تابع randint(a, b) ممکن است راحت‌تر و خواناتر باشد. نتایج ممکن randint() کران بالا را هم در بر می‌گیرد، بنابراین randint(a, b) همان استفاده از randrange(a, b+1) است:

>>> import random

# Select one number at random from the range 0, 499
>>> random.randrange(500)
219

# Select 10 numbers at random between 0 and 9 two steps apart.
>>> numbers = []
... for integer in range(10):
...    numbers.append(random.randrange(0, 10, 2))

>>> print(numbers)
[2, 8, 4, 0, 4, 2, 6, 6, 8, 8]

# roll a die
>>> random.randint(1, 6)  
4

کار با دنباله‌ها

توابع این بخش فرض می‌کنند که از یک دنباله یا ظرف دیگری شروع می‌کنید.

این معمولاً یک list است، یا با برخی محدودیت‌ها، یک tuple یا یک set (یک tuple تغییرناپذیر است و set بدون ترتیب).

choice() و choices()

تابع choice() یک عضو را به‌صورت تصادفی از دنباله‌ی داده‌شده برمی‌گرداند. در ساده‌ترین حالت، این می‌تواند انداختن یک سکه باشد:

# This will pick one of the two values in the list at random 5 separate times 
>>> [random.choice(['H', 'T']) for _ in range(5)]
['T', 'H', 'H', 'T', 'H']

می‌توانیم تقریباً همین کار را با تابع choices() انجام دهیم و یک آرگومان کلیدواژه‌ای با طول فهرست به آن بدهیم:

>>> random.choices(['H', 'T'], k=5)
['T', 'H', 'T', 'H', 'H']

در مثال‌های بالا فرض کردیم سکه‌ی سالمی داریم که احتمال شیر یا خط در آن برابر است، اما وزن‌ها را هم می‌توان مشخص کرد. برای مثال، اگر کیسه‌ای ۱۰ توپ قرمز و ۱۵ توپ سبز داشته باشد و بخواهیم یکی را به‌صورت تصادفی بیرون بکشیم:

>>> random.choices(['red', 'green'], [10, 15])
['red']

sample()

مثال choices() بالا همان چیزی را در نظر می‌گیرد که آماردانان به آن «نمونه‌گیری با جایگذاری» می‌گویند. هر انتخاب هیچ تأثیری بر احتمال انتخاب‌های بعدی ندارد و توزیع انتخاب‌های بالقوه از یک انتخاب به انتخاب بعدی ثابت می‌ماند.

در مثال توپ‌های قرمز و سبز: بعد از هر انتخاب، توپ را به کیسه برمی‌گردانیم و پیش از انتخاب بعدی خوب تکان می‌دهیم. این در تقابل با وضعیتی است که یک توپ قرمز بیرون می‌کشیم و آن بیرون می‌ماند. برنگرداندن توپ یعنی الان توپ‌های قرمز کمتری در کیسه هست و انتخاب بعدی کمتر احتمال دارد قرمز باشد.

برای شبیه‌سازی این «نمونه‌گیری بدون جایگذاری»، ماژول random تابع sample() را فراهم می‌کند. نحوه‌ی نگارش sample() شبیه choices() است، با این تفاوت که یک پارامتر کلیدواژه‌ای counts اضافه می‌کند:

>>> random.sample(['red', 'green'], counts=[10, 15], k=10)
['green', 'green', 'green', 'green', 'green', 'red', 'red', 'red', 'red', 'green']

نمونه‌ها به همان ترتیبی که انتخاب شدند برگردانده می‌شوند.

shuffle()

هم choices() و هم sample() وقتی k > 1 باشد فهرست‌های جدیدی برمی‌گردانند. در مقابل، shuffle() ترتیب یک فهرست را در جا به‌هم می‌ریزد و ترتیب اصلی از دست می‌رود:

>>> my_list = [1, 2, 3, 4, 5]
>>> random.shuffle(my_list)
>>> my_list
[4, 1, 5, 2, 3]

کار با توزیع‌ها

تا اینجا روی حالت‌هایی تمرکز کرده‌ایم که همه‌ی نتیجه‌ها به یک اندازه محتمل‌اند. برای مثال، random.randrange(100) به یک اندازه احتمال دارد هر عدد صحیحی از ۰ تا ۹۹ را بدهد.

بسیاری از موقعیت‌های دنیای واقعی بسیار پیچیده‌تر از این هستند. در نتیجه، آماردانان گونه‌های متنوعی از distributions پدید آورده‌اند تا نتایج «دنیای واقعی» را به‌صورت ریاضی توصیف کنند.

توزیع‌های یکنواخت

برای اعداد صحیح، وقتی همه‌ی احتمال‌ها برابر باشند از randrange() و randint() استفاده می‌شود. به این، توزیع uniform می‌گویند.

معادل‌های اعشاری برای randrange() و randint() هم وجود دارند.

random() مقداری از نوع float مانند x می‌دهد به‌طوری که 0.0 <= x < 1.0.

uniform(a, b) مقدار x را طوری می‌دهد که a <= x <= b.

>>> [round(random.random(), 3) for _ in range(5)]
[0.876, 0.084, 0.483, 0.22, 0.863]

>>> [round(random.uniform(2, 5), 3) for _ in range(5)]
[2.798, 2.539, 3.779, 3.363, 4.33]

توزیع گاوسی

این توزیع که «نرمال» یا منحنی «زنگوله‌ای» هم نامیده می‌شود، روشی بسیار رایج برای توصیف عدم دقت در مقادیر اندازه‌گیری‌شده است.

برای مثال، فرض کنید کارخانه‌ای که در آن کار می‌کنید تازه ۱۰٬۰۰۰ پیچ خریداری کرده که باید یکسان باشند. می‌خواهید ربات کارخانه را برای جابه‌جایی آن‌ها تنظیم کنید، پس نمونه‌ای ۱۰۰تایی را وزن می‌کنید و می‌بینید میانگین (یا mean) وزن آن‌ها ۴٫۷۳۱ گرم است. این به‌احتمال بسیار زیاد به این معنا نیست که وزن همه‌ی آن‌ها دقیقاً ۴٫۷۳۱ گرم است. شاید ببینید مقادیر از ۴٫۶۲۷ تا ۴٫۷۹۴ گرم متغیرند اما حول ۴٫۷۳۱ گرم جمع شده‌اند.

این همان Gaussian distribution است که در آن احتمال‌ها در میانگین به اوج می‌رسند و در دو طرف به‌صورت متقارن کاهش می‌یابند (از همین رو «زنگوله‌ای»). برای شبیه‌سازی این در نرم‌افزار، به روشی نیاز داریم که پهنای منحنی را مشخص کند (معمولاً پیچ‌های گران‌قیمت حول میانگین متمرکزتر از پیچ‌های ارزان جمع می‌شوند!).

طبق قرارداد، این کار با standard deviation انجام می‌شود: مقادیر کوچک برای منحنی تیز و باریک، و مقادیر بزرگ برای منحنی پهن و کم‌ارتفاع. ریاضی‌دانان عاشق حروف یونانی‌اند، بنابراین از μ («مو») برای نمایش میانگین و از σ («سیگما») برای نمایش انحراف معیار استفاده می‌کنیم. بنابراین، اگر جایی بخوانید که «۹۵٪ مقادیر در فاصله‌ی ۲σ از μ قرار دارند» یا «بوزون هیگز با اطمینان ۵ سیگما شناسایی شده است»، این جمله‌ها به انحراف معیار مربوط می‌شوند.

>>> mu = 4.731
>>> sigma = 0.316
>>> [round(random.gauss(mu, sigma), 3) for _ in range(5)]
[4.72, 4.957, 4.64, 4.556, 4.968]
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود