[책] How to Measure Anything 2부 – 몬테카를로 시뮬레이션을 통해 위험 측정하기

  • 위험은 그 자체가 일종의 측정의 결과입니다.하지만 이 것은 또 다른 중요한 측정의 기반이 됩니다.
  • 의사결정 내용을 좋게 느끼는 것과 실제로 좋은 의사결정을 내리는 것의 차이를 인식해야 합니다. 실제 의사결정과 예측 결과를 향상시킬 수 있는 증거들을 측정해야 합니다
  • 불확실성을 나타낼 때 비현실적인 정확한 값을 사용하는 것보다 현재의 불확실성을 포함하는 범위값을 사용하는 것은 도움이 됩니다.
  • 몬테카를로 시뮬레이션을 통해 대략적인 범위를 시뮬레이션을 통해서 파악할 수 있습니다.
  • 몬타카를로 시뮬레이션을 할 떄는 주요 변수들의 주요 정규 분포형태를 파악할 필요가 있습니다. 가장 많이 사용하는 분포는 정규분포입니다
  • 몬테카를로 시뮬레이션을 할 때는 분포, 그리고 변수간의 상관관계, Markov Property, Agent Based Modeling 등을 추가로 고려할 수 있습니다.
  • 스탠포드 대학교수인 샘 새비지는 경영분야에 있어 몬테카를로 시뮬레이션를 적극 권장하였습니다.

몬테카를로 시뮬레이션은 다음과 같이 할 수 있습니다. 책의 예를 그대로 들어보면 다음과 같습니다. 생산과정에서 새로운 기계를 임대한다고 할 때, 연간 임대비용은 40만불입니다. 이 때 절약할 수 있는 비용은 다음과 같이 정리한다고 할 때 대략 몇 퍼센트의 확률로 비용절감을 할 수 있을지 계산해볼수 있습니다.

변수는 다음과 같습니다.

  • Variables- Maintenance Savings(MS): 한 개당 $10~20
  • Labor Saving(LS): 한 개 당 $2~8
  • Raw material savings Saving(RMS) 한 개 당 $3~9
  • Production Level(PL): 연간 15,000 ~ 35,000개 생산 – 1,000 개 $\times$ 계약파기 가능성 $\times$ 남은 기간
  • 연간 임대비용: $400,000
  • 계약금액은 고정
  • 계약시 판매대수는 1,000개로 고정
  • 계약은 연중 어느 때나 파기 가능
  • 모두 정규분포를 따르는 것으로 가정
  • 변수의 상한, 하한은 90% 신뢰구간 – 양측검정 기준 신뢰구간 90%의 Z분포에서 값은 3.29

이렇게 하면 연감비용 절감은 다음과 같이 계산할 수 있습니다.

  • 연간 비용 절감: (MS+PL+RMS) $\times$ PL

이를 몬테카를로 시뮬레이션으로 적용해보면 다음과 같습니다.

import scipy.stats as stats
import random
import numpy as np
import pandas as pd

# Lower Bound, Mean(Median), Upper Bound 
MS = [10,15,20]
LS = [2,3,8]
RMS = [3,6,9]
contract_size = 1000
contract_loss_prob = 0.1
remaining_contract_month = [0,6,12]
PL = [15000,25000,35000]
scenario_count = 10000 # 몇번 돌려볼지
BEP = 400000
result = dict({"Scenario_no":[],"MS":[],"LS":[],"RMS":[],"Contract_size":[],"Contract_loss":[],"Remaining_contract_month":[],"Production_level":[],"Savings":[],"isBEP":[]})

# 돌리기
for i in range(1,scenario_count+1):

  _MS = stats.norm.ppf(random.random(), MS[1], (MS[2] - MS[0])/3.29 )
  _LS = stats.norm.ppf(random.random(), LS[1], (LS[2] - LS[0])/3.29 )
  _RMS = stats.norm.ppf(random.random(), RMS[1], (RMS[2] - RMS[0])/3.29 )
  _contract_loss = 1 if random.random() < 0.1 else 0
  try:
    production_level = stats.norm.ppf(random.random(), PL[1], (PL[2] - PL[0])/3.29 ) - (temp['contract_size'] * temp['contact_loss'] * temp['remaining_contract_month'])
  except Exception as e:
    production_level = stats.norm.ppf(random.random(), PL[1], (PL[2] - PL[0])/3.29 )
  _savings = (_MS+_LS+_RMS) *  production_level
  
  result['Scenario_no'].append(str(i))
  result['MS'].append(_MS)
  result['LS'].append(_LS)
  result['RMS'].append(_RMS)
  result['Contract_size'].append(contract_size)
  result['Contract_loss'].append(_contract_loss)
  result['Remaining_contract_month'].append(random.random() * (remaining_contract_month[2] - remaining_contract_month[0]) + remaining_contract_month[0] if _contract_loss == 1 else 0  )
  result['Production_level'].append(production_level)
  result['Savings'].append(_savings)
  result['isBEP'].append( 1 if _savings > BEP else 0 )

  if(i % 100 == 0):
    print(f"{i} times was run")

위와 같이 코드를 짜보면 BEP 여부를 “isBEP”로 간단하게 계산해볼 수 있습니다. 제경우 87%는 BEP를 넘길 것으로 계산되어서, 새로운 기기 임대는 해볼만하다고 판단하였습니다. 역으로 생각하면 13%의 위험 발생가능성이 있는 것도 알 수 있었습니다.

sum(result['isBEP']) / len(result['isBEP'])

다음과 같은 방식으로 모델을 통해서 위험도를 측정할 수 있습니다.