random --- تولید اعداد شبه‌تصادفی

کد منبع: Lib/random.py


این ماژول تولیدگرهای اعداد شبه‌تصادفی برای توزیع‌های مختلف را پیاده‌سازی می‌کند.

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

بر خط حقیقی، توابعی برای محاسبه توزیع‌های یکنواخت، نرمال (گاوسی)، لگ‌نرمال، نمایی منفی، گاما و بتا وجود دارد. برای تولید توزیع‌های زاویه‌ای، توزیع فون‌میزس (von Mises) در دسترس است.

تقریباً همه توابع ماژول به تابع پایه random() وابسته هستند، که یک عدد اعشاری تصادفی را به‌طور یکنواخت در بازه نیمه‌باز 0.0 <= X < 1.0 تولید می‌کند. پایتون از Mersenne Twister به‌عنوان تولیدگر اصلی استفاده می‌کند. این تولیدگر، اعداد اعشاری با دقت ۵۳ بیت تولید می‌کند و دوره تناوب آن 2**19937-1 است. پیاده‌سازی زیربنایی به زبان C، هم سریع و هم ایمن از نظر نخ‌ها (threadsafe) است. Mersenne Twister یکی از آزمایش‌شده‌ترین تولیدگرهای اعداد تصادفی موجود است. با این حال، به دلیل کاملاً قطعی بودن، برای همه مقاصد مناسب نیست و برای مقاصد رمزنگاری کاملاً نامناسب است.

توابع ارائه‌شده توسط این ماژول، در واقع متدهای مقید یک نمونه پنهان از کلاس random.Random هستند. شما می‌توانید نمونه‌های خودتان از Random را ایجاد کنید تا تولیدگرهایی داشته باشید که وضعیت مشترکی ندارند.

در صورتی که بخواهید از یک تولیدگر پایه‌ی متفاوتِ ساخت خودتان استفاده کنید، می‌توانید از کلاس Random نیز زیرکلاس بسازید: برای جزئیات بیشتر، مستندات آن کلاس را ببینید.

ماژول random همچنین کلاس SystemRandom را ارائه می‌دهد که از تابع سیستمی os.urandom() برای تولید اعداد تصادفی از منابع فراهم‌شده توسط سیستم‌عامل استفاده می‌کند.

هشدار

نباید از تولیدگرهای شبه‌تصادفی این ماژول برای اهداف امنیتی استفاده کنید. برای کاربردهای امنیتی یا رمزنگاری، ماژول secrets را ببینید.

همچنین ملاحظه نمائید

M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-dimensionally equidistributed uniform pseudorandom number generator", ACM Transactions on Modeling and Computer Simulation Vol. 8, No. 1, January pp.3--30 1998.

دستور پخت Complementary-Multiply-with-Carry برای یک تولیدگر اعداد تصادفی جایگزین سازگار، با دوره‌ی طولانی و عملیات به‌روزرسانی نسبتاً ساده.

توجه

تولیدگر اعداد تصادفی سراسری و نمونه‌های Random نخ‌ایمن هستند. با این حال، در ساخت نخ‌آزاد، فراخوانی‌های همزمان روی تولیدگر سراسری یا روی یک نمونه‌ی یکسان از Random ممکن است با رقابت و عملکرد ضعیف مواجه شوند. در عوض، استفاده از نمونه‌های جداگانه‌ی Random به ازای هر نخ را در نظر بگیرید.

توابع ثبت و نگهداری

random.seed(a=None, version=2)

تولیدگر اعداد تصادفی را مقداردهی اولیه کنید.

اگر a حذف شده باشد یا None باشد، از زمان جاری سیستم استفاده می‌شود. اگر منابع تصادفی توسط سیستم‌عامل فراهم شده باشند، از آن‌ها به‌جای زمان سیستم استفاده می‌شود (برای جزئیات در مورد در دسترس بودن، تابع os.urandom() را ببینید).

اگر a یک عدد صحیح باشد، قدر مطلق آن مستقیماً استفاده می‌شود.

در نسخه‌ی 2 (پیش‌فرض)، یک شیء str، bytes یا bytearray به یک int تبدیل می‌شود و از تمام بیت‌های آن استفاده می‌شود.

در نسخه 1 (که برای بازتولید دنباله‌های تصادفی از نسخه‌های قدیمی‌تر پایتون ارائه‌شده است)، الگوریتم برای str و bytes بازه باریک‌تری از بذرها را تولید می‌کند.

تغییر یافته در نسخه‌ی 3.2: به طرح‌واره نسخه‌ی 2 منتقل شد که از تمام بیت‌های یک بذر رشته‌ای استفاده می‌کند.

تغییر یافته در نسخه‌ی 3.11: seed باید یکی از انواع زیر باشد: None، int، float، str، bytes یا bytearray.

random.getstate()

شیءای را برمی‌گرداند که وضعیت داخلی فعلی تولیدگر را ثبت می‌کند. می‌توان این شیء را به setstate() ارسال کرد تا وضعیت بازیابی شود.

random.setstate(state)

state باید از فراخوانی پیشینِ getstate() به‌دست آمده باشد، و setstate() وضعیت داخلی تولیدگر را به آنچه در زمان فراخوانی getstate() بوده است بازمی‌گرداند.

توابعی برای bytes

random.randbytes(n)

تولید n بایت تصادفی.

این متد نباید برای تولید توکن‌های امنیتی استفاده شود. در عوض از secrets.token_bytes() استفاده کنید.

اضافه شده در نسخه‌ی 3.9.

توابع برای اعداد صحیح

random.randrange(stop)
random.randrange(start, stop[, step])

یک عنصر انتخاب‌شده به‌صورت تصادفی از range(start, stop, step) برمی‌گرداند.

این تقریباً معادل choice(range(start, stop, step)) است، اما از بازه‌های بسیار بزرگ پشتیبانی می‌کند و برای حالت‌های رایج بهینه‌سازی شده است.

الگوی آرگومان جایگاهی با تابع range() مطابقت دارد.

نباید از آرگومان‌های کلیدواژه‌ای استفاده شود، زیرا ممکن است به‌شکل‌های غیرمنتظره‌ای تفسیر شوند. برای مثال randrange(start=100) به‌صورت randrange(0, 100, 1) تفسیر می‌شود.

تغییر یافته در نسخه‌ی 3.2: randrange() برای تولید مقادیر با توزیع یکنواخت، پیشرفته‌تر عمل می‌کند. در گذشته از سبکی مانند int(random()*n) استفاده می‌کرد که می‌توانست توزیع‌های اندکی ناهموار تولید کند.

تغییر یافته در نسخه‌ی 3.12: تبدیل خودکار انواع غیر از عدد صحیح دیگر پشتیبانی نمی‌شود. فراخوانی‌هایی مانند randrange(10.0) و randrange(Fraction(10, 1)) اکنون استثنای TypeError را پرتاب می‌کنند.

random.randint(a, b)

یک عدد صحیح تصادفی N برمی‌گرداند به‌طوری که a <= N <= b. نام مستعاری برای randrange(a, b+1) است.

random.getrandbits(k)

یک عدد صحیح نامنفی پایتون با k بیت تصادفی برمی‌گرداند. این متد همراه با تولیدگر Mersenne Twister ارائه می‌شود و برخی تولیدگرهای دیگر نیز ممکن است آن را به‌عنوان بخشی اختیاری از API ارائه کنند. در صورت در دسترس بودن، getrandbits() به randrange() امکان می‌دهد محدوده‌هایی با بزرگی دلخواه را مدیریت کند.

تغییر یافته در نسخه‌ی 3.9: این متد اکنون مقدار صفر را برای k می‌پذیرد.

توابع برای دنباله‌ها

random.choice(seq)

یک عنصر تصادفی از دنباله‌ی غیرخالی seq برمی‌گرداند. اگر seq خالی باشد، IndexError را پرتاب می‌کند.

random.choices(population, weights=None, *, cum_weights=None, k=1)

بازگرداندن یک فهرست به اندازه‌ی k از عناصر انتخاب‌شده با جایگذاری از population. اگر population خالی باشد، IndexError پرتاب می‌شود.

اگر یک دنباله weights مشخص شده باشد، انتخاب‌ها بر اساس وزن‌های نسبی انجام می‌شوند. به‌عنوان جایگزین، اگر یک دنباله cum_weights داده شده باشد، انتخاب‌ها بر اساس وزن‌های تجمعی انجام می‌شوند (که ممکن است با استفاده از itertools.accumulate() محاسبه شده باشند). برای مثال، وزن‌های نسبی [10, 5, 30, 5] معادل وزن‌های تجمعی [10, 15, 45, 50] هستند. به‌صورت داخلی، وزن‌های نسبی پیش از انجام انتخاب‌ها به وزن‌های تجمعی تبدیل می‌شوند، بنابراین ارائه وزن‌های تجمعی باعث صرفه‌جویی در کار می‌شود.

اگر هیچ‌کدام از weights یا cum_weights تعیین نشده باشد، انتخاب‌ها با احتمال برابر انجام می‌شوند. اگر دنباله‌ای از وزن‌ها ارائه شود، باید هم‌طول با دنباله‌ی population باشد. تعیین همزمان weights و cum_weights باعث TypeError می‌شود.

برای weights یا cum_weights می‌توان از هر نوع عددی استفاده کرد که با مقادیر float برگردانده‌شده توسط random() قابل تعامل باشد (این شامل اعداد صحیح، شناورها و کسرها می‌شود، اما اعداد اعشاری (decimals) را شامل نمی‌شود). فرض می‌شود وزن‌ها نامنفی و متناهی باشند. اگر همه وزن‌ها صفر باشند، یک ValueError پرتاب می‌شود.

برای یک بذر مشخص، تابع choices() با وزن‌دهی برابر معمولاً دنباله‌ای متفاوت از فراخوانی‌های مکرر choice() تولید می‌کند. الگوریتم استفاده‌شده در choices() از حساب ممیز شناور برای سازگاری داخلی و سرعت استفاده می‌کند. الگوریتم استفاده‌شده در choice() به‌طور پیش‌فرض از حساب عدد صحیح با انتخاب‌های مکرر استفاده می‌کند تا از انحراف‌های جزئی ناشی از خطای گرد کردن اجتناب کند.

اضافه شده در نسخه‌ی 3.6.

تغییر یافته در نسخه‌ی 3.9: اگر همه وزن‌ها صفر باشند، یک ValueError پرتاب می‌شود.

random.shuffle(x)

دنباله‌ی x را به‌صورت درجا درهم می‌ریزد.

برای درهم‌ریختن یک دنباله تغییرناپذیر و برگرداندن یک فهرست درهم‌ریخته جدید، به‌جای آن از sample(x, k=len(x)) استفاده کنید.

توجه داشته باشید که حتی برای len(x) کوچک، تعداد کل جایگشت‌های x می‌تواند به‌سرعت از دوره‌ی بیشتر تولیدگرهای اعداد تصادفی بزرگ‌تر شود. این بدان معناست که بیشتر جایگشت‌های یک دنباله‌ی طولانی هرگز نمی‌توانند تولید شوند. برای مثال، دنباله‌ای به طول ۲۰۸۰ بزرگ‌ترین دنباله‌ای است که می‌تواند در دوره‌ی تولیدگر اعداد تصادفی Mersenne Twister جای گیرد.

تغییر یافته در نسخه‌ی 3.11: پارامتر اختیاری random حذف شد.

random.sample(population, k, *, counts=None)

فهرستی به طول k از عناصر یکتا انتخاب‌شده از دنباله‌ی جمعیت برمی‌گرداند. برای نمونه‌گیری تصادفی بدون جایگزینی استفاده می‌شود.

فهرست جدیدی شامل عناصری از جامعه برمی‌گرداند، در حالی که جامعه اصلی را بدون تغییر باقی می‌گذارد. فهرست حاصل به ترتیب انتخاب است، به‌طوری که همه زیراسلایس‌ها نیز نمونه‌های تصادفی معتبر خواهند بود. این امکان را فراهم می‌کند که برندگان قرعه‌کشی (نمونه) به برندگان جایزه بزرگ و برندگان مقام دوم (زیراسلایس‌ها) تقسیم شوند.

لازم نیست اعضای جمعیت، hashable یا یکتا باشند. اگر جمعیت دارای تکراری باشد، هر رخداد یک انتخاب ممکن در نمونه است.

عناصر تکراری را می‌توان یکی‌یکی یا با پارامتر اختیاری فقط‌کلیدواژه‌ای counts مشخص کرد. برای مثال، sample(['red', 'blue'], counts=[4, 2], k=5) معادل sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5) است.

برای انتخاب یک نمونه از بازه‌ای از اعداد صحیح، از یک شیء range() به‌عنوان آرگومان استفاده کنید. این روش برای نمونه‌گیری از یک جامعه بزرگ به‌ویژه سریع و از نظر فضا کارآمد است: sample(range(10000000), k=60).

اگر اندازه نمونه از اندازه جامعه بزرگ‌تر باشد، یک ValueError پرتاب می‌شود.

تغییر یافته در نسخه‌ی 3.9: پارامتر counts اضافه شد.

تغییر یافته در نسخه‌ی 3.11: population باید یک دنباله باشد. تبدیل خودکار مجموعه‌ها به فهرست‌ها دیگر پشتیبانی نمی‌شود.

توزیع‌های گسسته

تابع زیر یک توزیع گسسته تولید می‌کند.

random.binomialvariate(n=1, p=0.5)

توزیع دوجمله‌ای. تعداد موفقیت‌ها را برای n آزمایش مستقل با احتمال موفقیت p در هر آزمایش برمی‌گرداند:

از نظر ریاضی معادل با:

sum(random() < p for i in range(n))

تعداد آزمایش‌ها n باید یک عدد صحیح نامنفی باشد. احتمال موفقیت p باید در بازه‌ی 0.0 <= p <= 1.0 باشد. نتیجه یک عدد صحیح در بازه‌ی 0 <= X <= n است.

اضافه شده در نسخه‌ی 3.12.

توزیع‌های با مقدار حقیقی

توابع زیر توزیع‌های حقیقی‌مقدار مشخصی را تولید می‌کنند. پارامترهای توابع مطابق روش رایج ریاضی، به نام متغیرهای متناظر در معادله‌ی توزیع نام‌گذاری شده‌اند؛ بیشتر این معادلات را می‌توان در هر متن آماری یافت.

random.random()

عدد ممیز شناور تصادفی بعدی را در بازه‌ی 0.0 <= X < 1.0 برمی‌گرداند

random.uniform(a, b)

یک عدد ممیز شناور تصادفی N برمی‌گرداند، به‌طوری‌که a <= N <= b به ازای a <= b و b <= N <= a به ازای b < a.

مقدار پایانه b ممکن است بسته به گرد کردن اعداد ممیز شناور در عبارت a + (b-a) * random()، در بازه قرار بگیرد یا نگیرد.

random.triangular(low, high, mode)

یک عدد اعشاری تصادفی N برمی‌گرداند، به‌طوری که low <= N <= high و mode مشخص‌شده بین آن کران‌ها قرار داشته باشد. مقدار پیش‌فرض کران‌های low و high صفر و یک است. مقدار پیش‌فرض آرگومان mode نقطه میانی بین کران‌ها است، که توزیع متقارن ایجاد می‌کند.

random.betavariate(alpha, beta)

توزیع بتا. شرایط پارامترها alpha > 0 و beta > 0 است. مقادیر برگردانده‌شده بین ۰ و ۱ هستند.

random.expovariate(lambd=1.0)

توزیع نمایی. lambd برابر با ۱٫۰ تقسیم بر میانگین موردنظر است. این مقدار باید غیرصفر باشد. (این پارامتر «lambda» نامیده می‌شد، اما این یک کلیدواژه رزروشده در پایتون است.) مقادیر بازگشتی، اگر lambd مثبت باشد، از ۰ تا بی‌نهایت مثبت و اگر lambd منفی باشد، از بی‌نهایت منفی تا ۰ هستند.

تغییر یافته در نسخه‌ی 3.12: مقدار پیش‌فرض برای lambd افزوده شد.

random.gammavariate(alpha, beta)

توزیع گاما. (نه تابع گاما!) پارامترهای شکل و مقیاس، alpha و beta، باید مقادیر مثبت داشته باشند. (قراردادهای فراخوانی متفاوت است و برخی منابع 'beta' را به‌عنوان معکوس مقیاس تعریف می‌کنند).

تابع توزیع احتمال به صورت زیر است:

          x ** (alpha - 1) * math.exp(-x / beta)
pdf(x) =  --------------------------------------
            math.gamma(alpha) * beta ** alpha
random.gauss(mu=0.0, sigma=1.0)

توزیع نرمال، که توزیع گاوسی نیز نامیده می‌شود. mu میانگین است و sigma انحراف معیار است. این تابع کمی سریع‌تر از تابع normalvariate() است که در ادامه تعریف شده است.

یادداشت چندنخی: هنگامی که دو نخ همزمان این تابع را فراخوانی کنند، ممکن است مقدار بازگشتی یکسانی دریافت کنند. می‌توان از این حالت به سه روش جلوگیری کرد. ۱) هر نخ از نمونه‌ای متفاوت از مولد اعداد تصادفی استفاده کند. ۲) اطراف همه فراخوانی‌ها قفل قرار دهید. ۳) در عوض، از تابع کندتر، اما ایمن برای نخ‌ها normalvariate() استفاده کنید.

تغییر یافته در نسخه‌ی 3.11: mu و sigma اکنون آرگومان‌های پیش‌فرض دارند.

random.lognormvariate(mu, sigma)

توزیع نرمال لگاریتمی. اگر لگاریتم طبیعی این توزیع را بگیرید، یک توزیع نرمال با میانگین mu و انحراف معیار sigma به دست می‌آورید. mu می‌تواند هر مقداری داشته باشد و sigma باید بزرگ‌تر از صفر باشد.

random.normalvariate(mu=0.0, sigma=1.0)

توزیع نرمال. mu میانگین است و sigma انحراف معیار است.

تغییر یافته در نسخه‌ی 3.11: mu و sigma اکنون آرگومان‌های پیش‌فرض دارند.

random.vonmisesvariate(mu, kappa)

mu زاویه میانگین است و بر حسب رادیان بین ۰ و ۲*pi بیان می‌شود، و kappa پارامتر تمرکز است، که باید بزرگ‌تر یا مساوی صفر باشد. اگر kappa مساوی صفر باشد، این توزیع به یک زاویه تصادفی یک‌نواخت در بازه ۰ تا ۲*pi تقلیل می‌یابد.

random.paretovariate(alpha)

توزیع پارتو. alpha پارامتر شکل است.

random.weibullvariate(alpha, beta)

توزیع وایبول. alpha پارامتر مقیاس و beta پارامتر شکل است.

تولیدگر جایگزین

class random.Random([seed])

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

تغییر یافته در نسخه‌ی 3.11: پیش‌تر seed می‌توانست هر شیء هش‌پذیر باشد. اکنون به این موارد محدود شده است: None، int، float، str، bytes یا bytearray.

زیرکلاس‌های Random باید در صورتی که بخواهند از یک تولیدگر پایه‌ی متفاوت استفاده کنند، متدهای زیر را بازنویسی کنند:

seed(a=None, version=2)

این متد را در زیرکلاس‌ها بازنویسی کنید تا رفتار seed() را برای نمونه‌های Random سفارشی کنید.

getstate()

این متد را در زیرکلاس‌ها بازتعریف کنید تا رفتار getstate() نمونه‌های Random سفارشی شود.

setstate(state)

این متد را در زیرکلاس‌ها بازنویسی کنید تا رفتار setstate() در نمونه‌های Random سفارشی شود.

random()

این متد را در زیرکلاس‌ها بازنویسی کنید تا رفتار random() نمونه‌های Random را سفارشی کنید.

به‌صورت اختیاری، یک زیرکلاس تولیدگر سفارشی می‌تواند متد زیر را نیز ارائه دهد:

getrandbits(k)

این متد را در زیرکلاس‌ها بازنویسی کنید تا رفتار getrandbits() در نمونه‌های Random سفارشی شود.

randbytes(n)

این متد را در زیرکلاس‌ها بازنویسی کنید تا رفتار randbytes() برای نمونه‌های Random سفارشی شود.

class random.SystemRandom([seed])

کلاسی که از تابع os.urandom() برای تولید اعداد تصادفی از منابع فراهم‌شده توسط سیستم‌عامل استفاده می‌کند. در همه‌ی سیستم‌ها در دسترس نیست. به وضعیت نرم‌افزار متکی نیست و دنباله‌ها قابل تولید مجدد نیستند. بر همین اساس، متد seed() هیچ اثری ندارد و نادیده گرفته می‌شود. متدهای getstate() و setstate() در صورت فراخوانی، استثنای NotImplementedError را پرتاب می‌کنند.

نکاتی درباره بازتولیدپذیری

گاهی اوقات، توانایی بازتولید دنباله‌های ارائه‌شده توسط یک تولیدگر اعداد شبه‌تصادفی مفید است. با استفاده مجدد از یک مقدار بذر، تا زمانی که چندین نخ در حال اجرا نباشند، باید بتوان دنباله‌ی یکسانی را از یک اجرا تا اجرای دیگر بازتولید کرد.

بیشتر الگوریتم‌ها و توابع مقداردهی اولیه (seeding) ماژول random ممکن است در نسخه‌های مختلف پایتون تغییر کنند، اما تضمین شده است که دو جنبه تغییر نخواهند کرد:

  • اگر یک روش جدید بذردهی (seeding) اضافه شود، یک بذردهنده (seeder) سازگار با نسخه‌های پیشین ارائه خواهد شد.

  • متد random() تولیدگر، هنگامی که به بذردهنده‌ی سازگار (seeder) همان بذر داده شود، به تولید همان دنباله ادامه خواهد داد.

مثال‌ها

مثال‌های پایه:

>>> random()                          # Random float:  0.0 <= x < 1.0
0.37444887175646646

>>> uniform(2.5, 10.0)                # Random float:  2.5 <= x <= 10.0
3.1800146073117523

>>> expovariate(1 / 5)                # Interval between arrivals averaging 5 seconds
5.148957571865031

>>> randrange(10)                     # Integer from 0 to 9 inclusive
7

>>> randrange(0, 101, 2)              # Even integer from 0 to 100 inclusive
26

>>> choice(['win', 'lose', 'draw'])   # Single random element from a sequence
'draw'

>>> deck = 'ace two three four'.split()
>>> shuffle(deck)                     # Shuffle a list
>>> deck
['four', 'two', 'ace', 'three']

>>> sample([10, 20, 30, 40, 50], k=4) # Four samples without replacement
[40, 10, 50, 30]

شبیه‌سازی‌ها:

>>> # Six roulette wheel spins (weighted sampling with replacement)
>>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
['red', 'green', 'black', 'black', 'red', 'black']

>>> # Deal 20 cards without replacement from a deck
>>> # of 52 playing cards, and determine the proportion of cards
>>> # with a ten-value:  ten, jack, queen, or king.
>>> deal = sample(['tens', 'low cards'], counts=[16, 36], k=20)
>>> deal.count('tens') / 20
0.15

>>> # Estimate the probability of getting 5 or more heads from 7 spins
>>> # of a biased coin that settles on heads 60% of the time.
>>> sum(binomialvariate(n=7, p=0.6) >= 5 for i in range(10_000)) / 10_000
0.4169

>>> # Probability of the median of 5 samples being in middle two quartiles
>>> def trial():
...     return 2_500 <= sorted(choices(range(10_000), k=5))[2] < 7_500
...
>>> sum(trial() for i in range(10_000)) / 10_000
0.7958

مثالی از بوت‌استرپ آماری (statistical bootstrapping) با استفاده از نمونه‌گیری مجدد با جایگذاری برای برآورد بازه اطمینان میانگین یک نمونه:

# https://www.thoughtco.com/example-of-bootstrapping-3126155
from statistics import fmean as mean
from random import choices

data = [41, 50, 29, 37, 81, 30, 73, 63, 20, 35, 68, 22, 60, 31, 95]
means = sorted(mean(choices(data, k=len(data))) for i in range(100))
print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
      f'interval from {means[5]:.1f} to {means[94]:.1f}')

مثالی از یک آزمون جایگشتی بازنمونه‌گیری (resampling permutation test) برای تعیین معناداری آماری یا مقدار p یک تفاوت مشاهده‌شده میان اثرهای یک دارو در برابر دارونما:

# Example from "Statistics is Easy" by Dennis Shasha and Manda Wilson
from statistics import fmean as mean
from random import shuffle

drug = [54, 73, 53, 70, 73, 68, 52, 65, 65]
placebo = [54, 51, 58, 44, 55, 52, 42, 47, 58, 46]
observed_diff = mean(drug) - mean(placebo)

n = 10_000
count = 0
combined = drug + placebo
for i in range(n):
    shuffle(combined)
    new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):])
    count += (new_diff >= observed_diff)

print(f'{n} label reshufflings produced only {count} instances with a difference')
print(f'at least as extreme as the observed difference of {observed_diff:.1f}.')
print(f'The one-sided p-value of {count / n:.4f} leads us to reject the null')
print(f'hypothesis that there is no difference between the drug and the placebo.')

شبیه‌سازی زمان‌های ورود و ارائه خدمات برای یک صف چندکارگزاره:

from heapq import heapify, heapreplace
from random import expovariate, gauss
from statistics import mean, quantiles

average_arrival_interval = 5.6
average_service_time = 15.0
stdev_service_time = 3.5
num_servers = 3

waits = []
arrival_time = 0.0
servers = [0.0] * num_servers  # time when each server becomes available
heapify(servers)
for i in range(1_000_000):
    arrival_time += expovariate(1.0 / average_arrival_interval)
    next_server_available = servers[0]
    wait = max(0.0, next_server_available - arrival_time)
    waits.append(wait)
    service_duration = max(0.0, gauss(average_service_time, stdev_service_time))
    service_completed = arrival_time + wait + service_duration
    heapreplace(servers, service_completed)

print(f'Mean wait: {mean(waits):.1f}   Max wait: {max(waits):.1f}')
print('Quartiles:', [round(q, 1) for q in quantiles(waits)])

همچنین ملاحظه نمائید

Statistics for Hackers یک آموزش ویدیویی از Jake Vanderplas درباره‌ی تحلیل آماری با استفاده از تنها چند مفهوم بنیادی از جمله شبیه‌سازی، نمونه‌گیری، بر زدن و اعتبارسنجی متقابل.

شبیه‌سازی اقتصاد شبیه‌سازی از بازار توسط پیتر نورویگ است که استفاده‌ی مؤثر از بسیاری از ابزارها و توزیع‌های ارائه‌شده توسط این ماژول (gauss، uniform، sample، betavariate، choice، triangular و randrange) را نشان می‌دهد.

A Concrete Introduction to Probability (using Python) آموزشی از Peter Norvig که مبانی نظریه احتمال، نحوه نوشتن شبیه‌سازی‌ها و نحوه انجام تحلیل داده با استفاده از پایتون را پوشش می‌دهد.

دستورهای عملی

این دستورهای پخت نشان می‌دهند که چگونه می‌توان به‌شکل کارآمد از پیمایش‌گرهای ترکیبیاتی در ماژول itertools انتخاب‌های تصادفی انجام داد:

import random

def random_product(*iterables, repeat=1):
    "Random selection from itertools.product(*iterables, repeat=repeat)"
    pools = tuple(map(tuple, iterables)) * repeat
    return tuple(map(random.choice, pools))

def random_permutation(iterable, r=None):
    "Random selection from itertools.permutations(iterable, r)"
    pool = tuple(iterable)
    r = len(pool) if r is None else r
    return tuple(random.sample(pool, r))

def random_combination(iterable, r):
    "Random selection from itertools.combinations(iterable, r)"
    pool = tuple(iterable)
    n = len(pool)
    indices = sorted(random.sample(range(n), r))
    return tuple(pool[i] for i in indices)

def random_combination_with_replacement(iterable, r):
    "Choose r elements with replacement.  Order the result to match the iterable."
    # Result will be in set(itertools.combinations_with_replacement(iterable, r)).
    pool = tuple(iterable)
    n = len(pool)
    indices = sorted(random.choices(range(n), k=r))
    return tuple(pool[i] for i in indices)

def random_derangement(iterable):
    "Choose a permutation where no element stays in its original position."
    seq = tuple(iterable)
    if len(seq) < 2:
        if not seq:
            return ()
        raise IndexError('No derangments to choose from')
    perm = list(range(len(seq)))
    start = tuple(perm)
    while True:
        random.shuffle(perm)
        if all(p != q for p, q in zip(start, perm)):
            return tuple([seq[i] for i in perm])

random() پیش‌فرض مضرب‌هایی از 2⁻⁵³ را در بازه‌ی 0.0 ≤ x < 1.0 برمی‌گرداند. همه‌ی این اعداد به‌طور یکنواخت فاصله دارند و دقیقاً به‌صورت اعداد اعشاری پایتون قابل نمایش هستند. با این حال، بسیاری دیگر از اعداد اعشاری قابل نمایش در آن بازه، انتخاب‌های ممکن نیستند. برای مثال، 0.05954861408025609 مضرب عدد صحیحی از 2⁻⁵³ نیست.

دستور زیر رویکرد متفاوتی در پیش می‌گیرد. تمام اعداد اعشاری در بازه، انتخاب‌های ممکن هستند. مانتیس از توزیع یکنواخت اعداد صحیح در بازه‌ی 2⁵² ≤ mantissa < 2⁵³ به دست می‌آید. توان از توزیع هندسی به دست می‌آید که در آن توان‌های کوچک‌تر از -53 با نصف فراوانی توان بزرگ‌تر بعدی رخ می‌دهند.

from random import Random
from math import ldexp

class FullRandom(Random):

    def random(self):
        mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
        exponent = -53
        x = 0
        while not x:
            x = self.getrandbits(32)
            exponent += x.bit_length() - 32
        return ldexp(mantissa, exponent)

همه‌ی توزیع‌های با مقدار حقیقی در کلاس از متد جدید استفاده خواهند کرد:

>>> fr = FullRandom()
>>> fr.random()
0.05954861408025609
>>> fr.expovariate(0.25)
8.87925541791544

این روش از نظر مفهومی معادل الگوریتمی است که از میان همه‌ی مضارب 2⁻¹⁰⁷⁴ در بازه‌ی 0.0 ≤ x < 1.0 انتخاب می‌کند. همه‌ی این اعداد فاصله‌های برابر دارند، اما بیشتر آن‌ها باید به نزدیک‌ترین شناور پایتون قابل بازنمایی به پایین گرد شوند. (مقدار 2⁻¹⁰⁷⁴ کوچک‌ترین شناور مثبت نرمال‌نشده است و با math.ulp(0.0) برابر است.)

همچنین ملاحظه نمائید

Generating Pseudo-random Floating-Point Values مقاله‌ای از Allen B. Downey که روش‌هایی برای تولید مقادیر ممیز شناور ریزدانه‌تر از آنچه به‌طور معمول توسط random() تولید می‌شود، توصیف می‌کند.

استفاده از خط فرمان

اضافه شده در نسخه‌ی 3.13.

ماژول random را می‌توان از خط فرمان اجرا کرد.

python -m random [-h] [-c CHOICE [CHOICE ...] | -i N | -f N] [input ...]

گزینه‌های زیر پذیرفته می‌شوند:

-h, --help

نمایش پیام راهنما و خروج.

-c CHOICE [CHOICE ...]
--choice CHOICE [CHOICE ...]

یک انتخاب تصادفی را با استفاده از choice() چاپ کنید.

-i <N>
--integer <N>

یک عدد صحیح تصادفی بین ۱ تا N (شامل هر دو) را با استفاده از randint() چاپ کنید.

-f <N>
--float <N>

یک عدد ممیز شناور تصادفی بین ۰ تا N (شامل هر دو) را با استفاده از uniform() چاپ کنید.

اگر هیچ گزینه‌ای داده نشود، خروجی به ورودی بستگی دارد:

  • رشته یا چندتایی: همانند --choice.

  • عدد صحیح: معادل --integer.

  • شناور: همانند --float.

مثال خط فرمان

در اینجا چند نمونه از رابط خط فرمان random آمده است:

$ # Choose one at random
$ python -m random egg bacon sausage spam "Lobster Thermidor aux crevettes with a Mornay sauce"
Lobster Thermidor aux crevettes with a Mornay sauce

$ # Random integer
$ python -m random 6
6

$ # Random floating-point number
$ python -m random 1.8
1.7080016272295635

$ # With explicit arguments
$ python  -m random --choice egg bacon sausage spam "Lobster Thermidor aux crevettes with a Mornay sauce"
egg

$ python -m random --integer 6
3

$ python -m random --float 1.8
1.5666339105010318

$ python -m random --integer 6
5

$ python -m random --float 6
3.1942323316565915