পাঠ ৫০ · ৫৭-এর মধ্যে · মডিউল ১১
Home / Courses / Engineering Economics / মন্টে কার্লো সিমুলেশন

রিস্ক অ্যানালাইসিসের জন্য মন্টে কার্লো সিমুলেশন

Monte Carlo simulation for risk analysis
১১ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • মন্টে কার্লো সিমুলেশন কী এবং কেন এটি সেন্সিটিভিটি অ্যানালাইসিসের চেয়ে বেশি বাস্তবসম্মত ঝুঁকি-চিত্র দেয়
  • ত্রিভুজাকার (triangular) বণ্টন থেকে র‍্যান্ডম স্যাম্পল করা এবং কেন random.seed(...) রিপ্রোডিউসিবিলিটির জন্য অপরিহার্য
  • Python দিয়ে ৩০০০ ট্রায়ালের একটি সম্পূর্ণ মন্টে কার্লো সিমুলেশন — একই সাথে ইনিশিয়াল কস্ট ও বার্ষিক রেভিনিউ অনিশ্চিত ধরে PW-এর বণ্টন তৈরি ও সারাংশ পরিসংখ্যান রিপোর্ট
  • $P(PW>0)$ ব্যাখ্যা করা — একটি একক সংখ্যা নয়, বরং একটি সম্ভাব্যতা যা প্রজেক্টের সাফল্যের সম্ভাবনা বোঝায়

১ · মন্টে কার্লো সিমুলেশন কী

সেন্সিটিভিটি অ্যানালাইসিস (L47) একবারে শুধু একটি ভেরিয়েবল বদলায়, বাকি সব স্থির রেখে। কিন্তু বাস্তবে প্রায়ই একাধিক ইনপুট একসাথে অনিশ্চিত থাকে — ইনিশিয়াল কস্টও ভিন্ন হতে পারে, রেভিনিউও ভিন্ন হতে পারে, দুটোই একসাথে। মন্টে কার্লো সিমুলেশনMonte Carlo Simulationএকাধিক অনিশ্চিত ইনপুট প্রতিটির নিজস্ব সম্ভাব্যতা-বণ্টন থেকে বারবার র‍্যান্ডম স্যাম্পল করে, প্রতি ট্রায়ালে ফলাফল গণনা করে সামগ্রিক ফলাফলের একটি বণ্টন তৈরির কৌশল। এই সমস্যার সমাধান — প্রতিটি অনিশ্চিত ইনপুটকে তার নিজস্ব সম্ভাব্যতা-বণ্টন থেকে স্বাধীনভাবে র‍্যান্ডম স্যাম্পল করা হয়, প্রতিটি সংমিশ্রণে PW/NPV গণনা করা হয়, এবং এটি হাজার হাজার বার পুনরাবৃত্তি করে ফলাফলের একটি সম্পূর্ণ বণ্টন (distribution) তৈরি করা হয় — শুধু একটি সংখ্যা নয়।

র‍্যান্ডম স্যাম্পলিং
প্রতিটি অনিশ্চিত ইনপুট তার নিজস্ব বণ্টন (যেমন ত্রিভুজাকার) থেকে প্রতি ট্রায়ালে ভিন্নভাবে স্যাম্পল করা হয়।
বহু ট্রায়াল
সাধারণত ২,০০০-৫,০০০ ট্রায়াল — প্রতিটিতে সব অনিশ্চিত ইনপুট একসাথে বদলায়, PW/NPV নতুন করে গণনা হয়।
ফিক্সড সিড
random.seed(n) স্যাম্পলিংয়ের আগে কল করলে ফলাফল বারবার চালালেও হুবহু একই থাকে — রিপ্রোডিউসিবিলিটি।

২ · কোড সেল — ৩০০০ ট্রায়ালের মন্টে কার্লো সিমুলেশন

বেস প্রজেক্ট আগের মতোই ৮ বছর লাইফ, MARR ১০%, কিন্তু এবার ইনিশিয়াল কস্ট এবং বার্ষিক রেভিনিউ — দুটোই একসাথে অনিশ্চিত ধরা হচ্ছে, ত্রিভুজাকার (triangular) বণ্টন থেকে স্যাম্পল করে — কস্ট: নিম্ন $\$90{,}000$, সর্বাধিক-সম্ভাব্য $\$100{,}000$, উচ্চ $\$120{,}000$; রেভিনিউ: নিম্ন $\$25{,}000$, সর্বাধিক-সম্ভাব্য $\$32{,}000$, উচ্চ $\$38{,}000$।

Python
import random

def pw_of_annuity_factor(i, n):
    return ((1 + i) ** n - 1) / (i * (1 + i) ** n)

def trial_pw(cost, revenue, n, i):
    pa = pw_of_annuity_factor(i, n)
    return -cost + revenue * pa

random.seed(42)   # ফিক্সড সিড -- রিপ্রোডিউসিবিলিটির জন্য, যেকোনো স্যাম্পলিংয়ের আগেই কল করা হচ্ছে

N_TRIALS = 3000
N_YEARS = 8
MARR = 0.10

pw_results = []
for _ in range(N_TRIALS):
    cost = random.triangular(low=90000, high=120000, mode=100000)
    revenue = random.triangular(low=25000, high=38000, mode=32000)
    pw = trial_pw(cost, revenue, N_YEARS, MARR)
    pw_results.append(pw)

mean_pw = sum(pw_results) / N_TRIALS
min_pw = min(pw_results)
max_pw = max(pw_results)
variance = sum((x - mean_pw) ** 2 for x in pw_results) / N_TRIALS
std_pw = variance ** 0.5
prob_positive = sum(1 for x in pw_results if x > 0) / N_TRIALS

print(f"ট্রায়াল সংখ্যা: {N_TRIALS}")
print(f"গড় PW (mean)      = ${mean_pw:,.2f}")
print(f"সর্বনিম্ন PW        = ${min_pw:,.2f}")
print(f"সর্বোচ্চ PW         = ${max_pw:,.2f}")
print(f"স্ট্যান্ডার্ড ডেভিয়েশন = ${std_pw:,.2f}")
print(f"P(PW > 0)         = {prob_positive:.1%}")

    
যেহেতু random.seed(42) সেলের একদম শুরুতে, যেকোনো random.triangular(...) কলের আগে, বসানো হয়েছে — এই সেলটি যতবারই রি-রান করা হোক না কেন, Python-এর ছদ্ম-র‍্যান্ডম জেনারেটর ঠিক একই ক্রমে সংখ্যা তৈরি করবে, ফলে mean_pw, std_pw, ও prob_positive সহ প্রতিটি পরিসংখ্যান প্রতিবার হুবহু পুনরুৎপাদনযোগ্য (reproducible) হবে — এটি ডিবাগিং ও ফলাফল যাচাইয়ের জন্য অপরিহার্য। লক্ষ্য করুন, প্রতিটি ট্রায়ালে কস্ট ও রেভিনিউ স্বাধীনভাবে ও একসাথে বদলাচ্ছে — এটিই সেন্সিটিভিটি অ্যানালাইসিসের "একবারে একটি ভেরিয়েবল" পদ্ধতি থেকে মৌলিক পার্থক্য।
মূল কথা · Key takeaway

মন্টে কার্লো সিমুলেশন একাধিক অনিশ্চিত ইনপুট একসাথে বিবেচনা করে PW/NPV-এর একটি সম্পূর্ণ সম্ভাব্য বণ্টন তৈরি করে — গড়, বিস্তার (min/max), স্ট্যান্ডার্ড ডেভিয়েশন, এবং $P(PW>0)$ সবকিছু একসাথে দেখে ব্যবস্থাপক একটি সমৃদ্ধ ঝুঁকি-প্রোফাইল পান, শুধু একটি বেস-কেস সংখ্যা নয়। ফিক্সড random.seed() ছাড়া এই সিমুলেশন প্রতিবার ভিন্ন ফলাফল দেবে, যা যাচাই ও ডিবাগিং অসম্ভব করে তোলে — তাই এটি এই ধরনের যেকোনো প্রোবাবিলিস্টিক কোডের একটি অলঙ্ঘনীয় নিয়ম।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ random.seed(42) লাইনটি বাদ দিলে বা সেলের মাঝখানে (কিছু স্যাম্পলিংয়ের পরে) বসালে কী সমস্যা হবে?

বাদ দিলে প্রতিবার সেল রি-রান করলে ভিন্ন ভিন্ন র‍্যান্ডম সংখ্যা তৈরি হবে, ফলে mean_pw, std_pw ইত্যাদি প্রতিবার সামান্য ভিন্ন হবে — ফলাফল যাচাইযোগ্য (verifiable) থাকবে না। স্যাম্পলিং শুরু হওয়ার পরে সিড বসালে ততক্ষণে কিছু র‍্যান্ডম সংখ্যা ইতিমধ্যে ব্যবহৃত হয়ে গেছে, তাই সিড শুধু বাকি অংশের ক্রম নিয়ন্ত্রণ করবে — সম্পূর্ণ রিপ্রোডিউসিবিলিটি পাওয়া যাবে না। তাই সিড অবশ্যই যেকোনো স্যাম্পলিংয়ের আগে, একবারই, কল করতে হয়।

প্র ০২ মন্টে কার্লো সিমুলেশন সেন্সিটিভিটি অ্যানালাইসিসের (L47) চেয়ে কীভাবে বেশি বাস্তবসম্মত?

সেন্সিটিভিটি অ্যানালাইসিস একবারে একটি ভেরিয়েবল বদলায়, বাকি সব বেস-কেসে স্থির রেখে — কিন্তু বাস্তবে সব ভেরিয়েবলই একসাথে অনিশ্চিত থাকে, এবং তারা একসাথে ভালো বা একসাথে খারাপ দিকেও যেতে পারে। মন্টে কার্লো প্রতিটি ট্রায়ালে সব অনিশ্চিত ইনপুট একসাথে স্বাধীনভাবে স্যাম্পল করে, তাই এটি "সব একসাথে খারাপ হলে কী হয়" বা "সব একসাথে ভালো হলে কী হয়" — এই সম্মিলিত ঝুঁকি সরাসরি ধরতে পারে, যা এক-ভেরিয়েবল সেন্সিটিভিটি অ্যানালাইসিস পারে না।

প্র ০৩ $P(PW>0)$ যদি ৯৫% আসে, এর ব্যবহারিক অর্থ কী — এবং এটি কি প্রজেক্ট গ্রহণের নিশ্চয়তা দেয়?

$P(PW>0)=95\%$ মানে ৩০০০টি সিমুলেটেড ট্রায়ালের মধ্যে ৯৫% ক্ষেত্রেই প্রজেক্ট লাভজনক হয়েছে, অর্থাৎ কস্ট ও রেভিনিউর অনিশ্চয়তা মাথায় রেখেও প্রজেক্ট লাভজনক হওয়ার সম্ভাবনা বেশি। কিন্তু এটি নিশ্চয়তা দেয় না — বাকি ৫% ক্ষেত্রে (উচ্চ কস্ট ও নিম্ন রেভিনিউর সংমিশ্রণে) প্রজেক্ট লোকসানে যেতে পারে। সিদ্ধান্ত এখনো ব্যবস্থাপকের ঝুঁকি-সহনশীলতার উপর নির্ভর করে — ৯৫% উচ্চ হলেও শূন্য নয়।

অনুশীলন

  1. চিন্তা করুন: যদি ট্রায়াল সংখ্যা ৩০০০ থেকে কমিয়ে মাত্র ১০ করা হয় (সিড একই রেখে), ফলাফলের পরিসংখ্যান (mean, std dev) কি একই নির্ভরযোগ্যতায় থাকবে? কেন বা কেন নয়?

    না — মাত্র ১০টি ট্রায়াল থেকে গণনা করা mean ও std dev পরিসংখ্যানগতভাবে অনেক বেশি অস্থির (উচ্চ স্যাম্পলিং এরর), কারণ এত কম ট্রায়াল ত্রিভুজাকার বণ্টনের প্রকৃত আকৃতি ভালোভাবে ধরতে পারে না। ৩০০০ (বা তার বেশি) ট্রায়াল লার্জ-নাম্বার-এর সূত্র অনুযায়ী প্রকৃত বণ্টনের অনেক কাছাকাছি, নির্ভরযোগ্য সারাংশ পরিসংখ্যান দেয়।

  2. পরীক্ষা করুন: উপরের কোড সেলে random.seed(42)-কে random.seed(7)-এ বদলে Run চেপে দেখুন — mean_pw ও prob_positive কি বদলায়? তারপর আবার random.seed(42)-এ ফিরিয়ে Run চাপলে কী হয়?

    সিড 7-এ বদলালে ভিন্ন র‍্যান্ডম সিকোয়েন্স তৈরি হবে, তাই mean_pw ও prob_positive সামান্য ভিন্ন সংখ্যা দেবে (যদিও একই ত্রিভুজাকার বণ্টন থেকে আসায় বড় পরিসরে কাছাকাছিই থাকবে)। কিন্তু random.seed(42)-এ ফিরিয়ে আবার Run করলে ঠিক আগের মতোই হুবহু একই সংখ্যাগুলো ফিরে আসবে — এটিই সিড-নির্ধারিত রিপ্রোডিউসিবিলিটির মূল প্রমাণ।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
এক্সপেক্টেড ভ্যালু ও প্রোবাবিলিস্টিক অ্যানালাইসিস