※ 이 포스팅은 저자 'Kirthi Raman'의 도서 <Mastering Python Data Visualization> 을 공부하며 정리한 글입니다.
Chapter 05. Financial and Statistical Models (금융과 통계 모형)
확률론적 모형 (Stochastic Model)
지금까지는 임의성(Randomness)을 고려하지 않은 결정론적 모형을 살펴보았다. 지금부터는 임의성을 고려한 모형을 생각해보자.
#. 몬테카를로 시뮬레이션 (Monte Carlo Simulation)
확률 시뮬레이션으로도 불리며, 어느 예측 모형에든 위험성이나 불확실성의 영향을 활용하는 방법(기술)이다.
예측 모형에는 임의성에 대한 가정들이 포함되어 있다. 이는 포트폴리오상의 투자 수익률, 또는 작업 수행 시간에 대한 가정일 수 있다.
이렇게 임의성에 대해 모형을 세우고 미래에 투영함으로써 기대값(Expected Value)을 예측하는 것이다.
몬테카를로 시뮬레이션은 난수(Random Value)들을 입력하여 결정론적(Deterministic) 모형을 반복적(보통 100,000 ~ 수백 만 회 이상)으로 평가하는 방법이다.
모형이 복잡하고, 비선형적(Non-linear)이며 불확실한 모수(Parameter)가 하나 이상 포함하는 경우에 자주 사용된다.
결정론적 모형과의 차이점을 살펴보자. 결정론적 모형은 일관된 결과를 도출하지만,
확률론적 모형은 확률밀도함수에서 비롯되며 도출되는 결과 또한 확률적이다.
위의 그림을 설명하면 이렇다. 우선 랜덤 입력 x1~x3에 대한 모형의 함수 f(x1,x2,x3)을 설정한 후, 여러개의 무작위 집합 {x1, x2, x3}을 생성한다.
각 입력값을 모형에 적용한 후, 평가하는 과정을 모든 값(가령 1만 개면 1만 개 까지)에 적용한다.
결과값들을 분석하고, 마지막으로 가장 가능성이 높은 것을 고른다. 몬테카를로 시뮬레이션은 난수 생성에 매우 크게 의존한다.
예를 들어, A 라는 농구 팀이 이길 확률을 알고 싶다면, 농구라는 상황에 대한 확률론적 가정 아래 수 많은 무작위 입력값들을 생성하는 몬테카를로 시뮬레이션을 통해 추정해볼 수 있겠다.
이와 같이 몬테카를로 시뮬레이션은 대다수의 현실 상황에 적용하여 문제를 해결할 수 있습니다.
#. 몬테카를로 시뮤레이션 예시 1 - 재고 관리 모형 (An Inventory Model for Monte Carlo Simulation)
한 과일 소매 판매상은 과일을 팔고 매일 주문한다.
매 단위의 매출 당 $0.6의 이익이 발생하고, 그 날 안에 팔리지 않으면 단위당 $0.4의 손실이 발생한다.
수요 D는 [80, 140] 범위에서 균등하게 분포한다고 가정하자.
이 때, 소매상의 수익을 최대로 하기 위해서는 얼마나 주문해야 좋을까?
수익을 P, 판매량을 s, 수요를 d라고 한다면 다음과 같이 수식을 세울 수 있다.
* 만약 수요가 재고보다 많으면 수요량 만큼만 판매되며, 수요량이 재고에 못미치면 폐기된다는 전제를 하고 있는 것 같습니다.
* 즉, 의사결정의 주체인 소매상은 주문량을 결정할 수 있지만 수요량은 임의성(Randomness)이 존재함을 적용한 것입니다.
이를 바탕으로 파이썬을 통해 다음과 같이 시뮬레이션하면, 최대 기대 수익과 최적의 주문량을 구할 수 있다.
(제가 임의로 수정한 것으로, 책의 예제 코드와 다소 상이할 수 있습니다.)
import numpy as np
import matplotlib.pyplot as plt
# 수익식
def generateProfit(d):
global s
if d >= s:
return 0.6*s
else:
return 0.6*d - 0.4*(s-d)
# 시뮬레이션 시작
x = []
y = []
# 주문량 10 ~ 200 까지 시행
for s in range(10, 200):
profit = []
# n = 1,000 회 시뮬레이션 시행 // 횟수가 많을 수록 정밀해지나 거의 비슷하다.
for i in range(1, 1000):
# 균등분포(Uniform distribution)으로 정수의 수요량 난수를 생성한다.
d = np.random.randint(low = 80, high = 140)
# 이 수요량 난수 d에 대한 수익 계산
profit.append(generateProfit(d))
# x 축을 따라 그려질 s(주문량) 저장
x.append(s)
# y 축을 따라 그려질 평균 수익 저장
y.append(np.mean(profit))
plt.grid(True)
plt.xlabel('Volume of Orders')
plt.ylabel('Average Profits')
plt.plot(x,y)
print 'Max Average Profit:', max(y)
print 'Optimal Volume of Orders:', x[y.index(max(y))]
Max Average Profit: 58.8266266266
Optimal Volume of Orders: 112
실제 계산을 통해서 시뮬레이션이 얼마나 합리적인지 확인해보자.
시뮬레이션 결과는 112로, 실제 계산값인 116과 매우 흡사하다. 난수 개수를 늘리면 더더욱 실제 계산값과 가까워진다.
* 더 복잡한 상황들과 가정을 적용했을 때, 계산보다 시뮬레이션이 용이할 수 있습니다.
#. 몬테카를로 시뮬레이션 예시 3 - 농구 게임 (A Basketball Game Model for Monte Carlo Simulation)
Khan Academy에서 Lebron James의 질문을 해결해보자.
" 3점을 뒤지고 있는 상태에서 단 30초가 남았을 때, 어려운 3점 슛을 시도하는 것이 나은가 아니면 쉬운 2점 슛과 추가 점유를 시도하는 것이 나은가? "
여기에 필요한 몇 가지 파라미터들을 다음과 같이 (쉽게 풀이하기 위해 간단히) 정의한다.
우리팀 : threePtPercent , twoPtPercent
상대팀 : oppTwoPtPercent , oppFtPercent (프리드로우 전력 퍼센티지)
상대 팀의 프리드로우 퍼센티지(oppFtPercent)가 높을 수록, 3포인트 슛이 유리하다.
반대로 oppFtPercent 값이 낮아지면? 이를 시뮬레이션해보자.
import numpy as np
import matplotlib.pyplot as plt
colors = [(31, 119, 180), (174, 199, 232), (255, 127, 14),
(255, 187, 120), (44, 160, 44), (214, 39, 40), (148,103,189),
(152, 223, 138), (255,152,150), (197, 176, 213), (140, 86, 75),
(196, 156, 148), (227,119,194), (247, 182, 210), (127,127,127),
(199, 199, 199),(188,189, 34),(219, 219, 141), (23, 190,207),
(158, 218, 229),(217,217,217)]
# RGB 값들을 matplotlib이 받을 수 있는 [0, 1] 범위로 스케일
for i in range(len(colors)) :
r, g, b = colors[i]
colors[i] = (r / 255., g / 255., b / 255.)
# 3점 시도
def attemptThree() :
if np.random.randint(0, high=100) < threePtPercent :
if np.random.randint(0, high=100) < overtimePercent :
return True # 게임 승리
return False # 3점에 실패하거나 시간 초과로 게임 패배
# 2점 시도
def attemptTwo() :
havePossession = True
pointsDown = 3
timeLeft = 30
while (timeLeft > 0) :
# 점유권을 가지고 있다면?
if (havePossession) :
# 우리가 3점 이상 뒤지고 있다면, 2점을 빠르게
# 우리가 2점 이하로 뒤지고 있다면, 우리는 먼저 시간을 끌어야
if (pointsDown >= 3) :
timeLeft -= timeToShoot2
else :
timeLeft = 0
# 슈팅을 해야 할까?
if (np.random.randint(0, high=100) < twoPtPercent) :
pointsDown -= 2
havePossession = False
else :
# 상대팀이 리바운드를 한다면? 우리는 점유권을 잃는다
# 그러나 우리가 시간을 끌게 되면, 이것은 문제가 되지 않는다.
if (np.random.randint(0, high=100) >= offenseReboundPercent) :
havePossession = False
else : # 우리가 점유권을 갖지 않는 경우
if (pointsDown > 0) : # 점유권을 되찾기 위해 파울
# 파울을 위한 시간
timeLeft -= timeToFoul
# 상대 팀이 두 개의 프리드로우 획득
if (np.random.randint(0, high=100) < oppFtPercent) :
pointsDown += 1
if (np.random.randint(0, high=100) < oppFtPercent) :
pointsDown += 1
havePossession = True
else :
if (np.random.randint(0, high=100) >= ftReboundPercent) :
havePossession = True
else :
# 동점 또는 이기고 있어 파울을 원하지 않음.
# 상대팀이 시간 끄는 것을 가정
if (np.random.randint(0, high=100) < oppTwoPtPercent) :
pointsDown += 2 # 상대팀이 2점 기록
timeLeft = 0
if (pointsDown > 0) :
return False
else :
if (pointsDown < 0) :
return True
else :
if (np.random.randint(0, high=100) < overtimePercent) :
return True
else :
return False
# 시각화
plt.figure(figsize=(14,14))
names=['Lebron James', 'Kyrie Irving', 'Steph Curry', 'Kyle Krover', 'Dirk Nowitzki']
threePercents = [35.4, 46.8, 44.3, 49.2, 38.0]
twoPercents = [53.6, 49.1, 52.8, 47.0, 48.6]
colind=0
for i in range(5) : # 각각 수행할 수 있음
x=[]
y1=[]
y2=[]
trials = 400 # 시뮬레이션 실행 시도 수
threePtPercent = threePercents[i] # 3점 슛 만들 기회 %
twoPtPercent = twoPercents[i] # 2점 슛 만들 기회 %
oppTwoPtPercent = 40 # 상대팀이 2점 슛 만들 기회 %
oppFtPercent = 70 # 상대팀의 프리드로우 %
timeToShoot2 = 5 # 2점 슛을 위해 경과된 초
timeToFoul = 5 # 상대팀을 파울하는 데 경과된 초
offenseReboundPercent = 25 # 공격 리바운드 %
ftReboundPercent = 15 # FT를 놓친 후 공격 리바운드 %
overtimePercent = 50 # 연장선에서 우승 확률 %
winsTakingThree = 0
lossTakingThree = 0
winsTakingTwo = 0
lossTakingTwo = 0
curTrial = 1
while curTrial < trials :
# 3점 획득 시도 실행
if (attemptThree()) :
winsTakingThree += 1
else :
lossTakingThree += 1
# 2점 획득 시도 실행
if attemptTwo() == True :
winsTakingTwo += 1
else :
lossTakingTwo += 1
x.append(curTrial)
y1.append(winsTakingThree)
y2.append(winsTakingTwo)
curTrial += 1
plt.plot(x, y1, color=colors[colind], label=names[i]+" Wins Taking Three Point", linewidth=2)
plt.plot(x, y2, color=colors[20], label=names[i]+" Wins Taking Two Point", linewidth=1.2)
colind += 2
legend = plt.legend(loc='upper left', shadow=True,)
for legobj in legend.legendHandles :
legobj.set_linewidth(2.6)
plt.show()
모든 경우에서 상대 팀의 프리드로우 비율이 높기 때문에(70%), 모든 선수들에 대해 몬테카를로 시뮬레이션은 3점 득점을 제안하고 있다.
#. 변동성 그래프 (The Volatility Plot)
표준편차는 평균 주위에서의 변화량 또는 흩어짐 정도를 측정하는 통계 용어로 변동성의 척도이다.
이처럼 정의에 의해, 흩어짐의 정도란 실제 값과 평균 값 사이의 차이이다.
가까운 값들을 바탕으로 변동성을 그래프로 살펴보기 위해 주어진 시작 일로부터 어떻게 볼 수 있는지,
어떻게 특정 주식에 대해 수행하는지 예제(IBM, 2005.10.01. ~)로 살펴보자.
import pandas_datareader as stockdata
import numpy as np
ibmquotes = stockdata.DataReader(name='IBM', data_source='yahoo', start='2005-10-01')
ibmquotes['Volatility'] = np.log(ibmquotes['Close'] / ibmquotes['Close'].shift(1))
ibmquotes[['Close', 'Volatility']].plot(figsize=(12,10),subplots=True)
주가 변동성은 다양한 특징적 피크점을 가질 수 있는 가격의 변동이다.
지수(exponential) 함수는 시간에 따른 성장을 보여주고,
로그(log, 지수의 역) 함수는 성장에 이르기 위한 시간을 측정할 수 있게 한다.
'데이터 과학 > Mastering Python Data Visualization' 카테고리의 다른 글
Chapter 06. Statistical and Machine Learning (통계 및 머신러닝) (0) | 2017.10.29 |
---|---|
Chapter 05-3. An Overview of Statistical and Machine Learning (통계 및 머신러닝 개요) (0) | 2017.10.18 |
Chapter 05-1. Deterministic Model (결정론적 모형) (0) | 2017.06.18 |
Chapter 04-2. Interactive Plotting (반응형 시각화) (0) | 2017.06.18 |
Chapter 04-1. Numerical Computing (수치 연산) (0) | 2017.06.16 |