누구나 따라 하는 금융 데이터 분석 - 주피터 노트북 기초 활용법

누구나 따라 하는 금융 데이터 분석 - 주피터 노트북 기초 활용법

2019, Jan 04    
Jupyter_Introduction

[누구나 따라 하는 금융 데이터 분석] - 주피터 노트북 기초 활용법

by JunPyo Park

Part of the Alpha Square Lecture Series:


앞으로 진행될 금융 데이터 분석 콘텐츠에서는 주피터 노트북(공식 홈페이지)을 활용합니다. 이번 콘텐츠에서는 주피터 노트북의 가장 기초적인 활용법들에 대해 정리해 보았습니다. 주피터 노트북 환경을 세팅하신 후 아래 내용을 천천히 따라 해 보신다면 쉽게 기본적인 명령어와 기능들에 익숙해질 수 있습니다. 주피터 노트북 환경이 갖추어지지 않으신 분은 아래의 링크를 통해 주피터 환경 구축이 가능합니다.

코드 셀 vs 텍스트 셀

각각의 셀들은 코드를 담거나 텍스트를 담을 수 있습니다. 셀을 클릭 후 m 을 누르면 텍스트 셀(Markdown)로 활용할 수 있고 y 를 누르면 코드 셀로 활용할 수 있습니다.

명령어 실행하기

코드 셀은 실행 버튼을 누르거나 셀에서 쉬프트 엔터를 누르면 실행됩니다. 코드 셀에 명령어를 입력한 뒤 실행하면 각 줄의 내용이 실행되어 지고 결괏값이 셀의 마지막줄 아래에 출력됩니다.

In [1]:
1 + 3
Out[1]:
4

출력값이 없는 셀도 있을 수 있습니다. 다음과 같이 변수에 값을 할당하는 경우 입니다.

In [2]:
X = 1

가장 마지막 줄에 있는 결괏값만 출력되어 집니다.

In [4]:
2 + 2
3 + 3
Out[4]:
6

마지막 줄이 아닌 곳의 값을 출력 하려면 print 명령어를 사용합니다.

In [5]:
print(2 + 2)
3 + 3
4
Out[5]:
6

셀이 동작하고 있을 경우

셀이 동작하고 있을 경우 [*] 기호가 왼쪽에 표시됩니다. 실행 되지 않은 셀의 경우 [] 기호가 표시됩니다. 실행된 셀은 [5] 와 같이 몇 번째 순서로 실행되었는지 그 숫자가 표기됩니다. 다음 셀을 실행 시키고 어떤 일이 벌어지는지 잘 관찰해 보세요.

In [6]:
# 시간이 걸리는 코드를 작성해 보았습니다.
c = 0
for i in range(10000000):
    c = c + i
c
Out[6]:
49999995000000

라이브러리 불러오기

대부분 작업의 경우 미리 만들어진 라이브러리에서 함수를 불러와 사용하게 됩니다. 아나콘다 환경에서는 기본적인 라이브러리들이 설치되어 있으며 설치되지 않은 라이브러리는 pip 명령어 등으로 설치하여 불러올 수 있습니다. 설치된 라이브러리는 import 명령어를 통해 불러올 수 있습니다.

In [1]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

라이브러리를 불러온 후 as 라는 명령어를 통해 이름을 재설정 할 수 있습니다. numpy 라이브러리에는 np 라는 이름을 pandas 라이브러리에는 pd 라는 이름을 지정하였습니다. 이는 대부분의 코드에서 보편적으로 사용하는 이름입니다. 이처럼 라이브러리를 자주 호출하는 경우 단순한 이름으로 재설정하여 쉽게 접근할 수 있습니다.

Tab 자동완성 기능

탭키를 누르면 주피터 노트북에서 다음에 쓸 명령어나 변수이름를 자동으로 추천하여 보여주거나 해당하는 값이 하나라면 자동으로 완성시켜 줍니다. 이는 코드를 작성할 때 많은 시간을 절약할 수 있도록 해줍니다. 이 기능을 활용하여 라이브러리에 어떤 함수들이 있는지 확인하는것도 가능합니다.

다음 셀에서 커서를 . 뒤에 두고 탭을 눌러보세요.

In [ ]:
np.random.

Documentation 도움말 보기

물음표를 함수 뒤에 입력하고 해당 셀을 실행하면 주피터가 해당 함수에 대한 documentation을 보여줍니다. 코드가 재실행 되는것을 방지하기 위해 새로운 셀에서 이런 도움말 기능을 실행하면 편리합니다.

In [2]:
np.random.normal?

Sampling 하기

numpy의 여러 함수들을 통해 랜덤한 데이터를 샘플링 할 수 있습니다.

In [10]:
# 평균이 0 이고 분산이 1 인 정규분포에서
# 100개의 데이터를 다음과 같이 추출할 수 있습니다.
X = np.random.normal(0, 1, 100)

Plotting 하기

이전에 불러온 plt 라이브러리를 통해 그래프를 그릴 수 있습니다.

In [11]:
plt.plot(X)
Out[11]:
[<matplotlib.lines.Line2D at 0x22bfe4bd710>]

Line Output 제거하기

위 출력결과를 보면 [<matplotlib.lines.Line2D at 0x160c22db240>] 와 같이 문구가 그래프와 같이 출력된것을 볼 수 있습니다. 이를 없애기 위해 다음과 같이 마지막에 세미콜론을 붙여줍니다.

In [12]:
plt.plot(X);

축에 이름 설정하기

plt.xlabel 또는 plt.ylabel 명령어를 통해 각각 x축, y축의 이름을 지정할 수 있습니다.

In [17]:
X = np.random.normal(0, 1, 100)
X2 = np.random.normal(0, 1, 100)

plt.plot(X);
plt.plot(X2);
plt.xlabel('Time') 
plt.ylabel('Returns')
plt.legend(['X', 'X2']);

통계량(statistics) 계산하기

numpy를 활용해서 간단한 통계량들을 쉽게 계산할 수 있습니다.

In [14]:
# 평균
np.mean(X)
Out[14]:
0.1230036394638333
In [18]:
# 표준편차
np.std(X)
Out[18]:
1.051931761394475

주가 데이터 불러오기

In [22]:
import pandas_datareader.data as web

data = web.DataReader('AAPL', 'robinhood')
In [24]:
data
Out[24]:
close_price high_price interpolated low_price open_price session volume
symbol begins_at
AAPL 2017-12-22 172.421400 172.829300 False 171.919000 172.096300 reg 16349444
2017-12-26 168.047100 168.933800 False 167.169300 168.273700 reg 33185536
2017-12-27 168.076600 168.254000 False 167.199800 167.584000 reg 21498213
2017-12-28 168.549500 169.308200 False 167.958400 168.470700 reg 16480187
2017-12-29 166.726900 168.066800 False 166.717100 167.997800 reg 25999922
2018-01-02 169.712100 169.751500 False 166.756500 167.643100 reg 25555934
2018-01-03 169.682500 171.968200 False 169.416500 169.978100 reg 29517899
2018-01-04 170.470700 170.904200 False 169.534700 169.987900 reg 22434597
2018-01-05 172.411600 172.776100 False 170.490400 170.874600 reg 23660018
2018-01-08 171.771200 173.012500 False 171.357400 171.771200 reg 20567766
2018-01-09 171.751500 172.470700 False 170.845100 171.968200 reg 21583997
2018-01-10 171.712100 171.721900 False 170.441100 170.598800 reg 23959895
2018-01-11 172.687400 172.892900 False 171.909100 172.007600 reg 18667729
2018-01-12 174.470600 174.736700 False 173.051900 173.574100 reg 25418080
2018-01-16 173.584000 176.736600 False 173.534700 175.268700 reg 29565947
2018-01-17 176.450900 176.598700 False 172.480500 173.544500 reg 34386836
2018-01-18 176.608500 177.436100 False 175.613500 176.716900 reg 31193352
2018-01-19 175.820400 176.923800 False 174.785900 175.968200 reg 32425067
2018-01-22 174.382000 175.150400 False 173.989500 174.677500 reg 27108551
2018-01-23 174.421400 176.785900 False 174.204600 174.677500 reg 32689146
2018-01-24 171.643100 174.677500 False 170.638200 174.628300 reg 51105090
2018-01-25 168.579100 172.362300 False 168.007700 171.923900 reg 41529004
2018-01-26 168.973200 169.455900 False 167.544600 169.455900 reg 39143011
2018-01-29 165.475700 167.643100 False 164.598900 167.643100 reg 50640406
2018-01-30 164.500300 164.894400 False 162.263900 163.076700 reg 46048185
2018-01-31 164.953500 165.950300 False 164.037300 164.401800 reg 32478930
2018-02-01 165.298400 166.125900 False 164.293400 164.692400 reg 47230787
2018-02-02 158.126000 164.332800 False 157.731900 163.544700 reg 86593825
2018-02-05 154.175300 161.456000 False 153.692600 156.746700 reg 72738522
2018-02-06 160.618600 161.298400 False 151.722200 152.539900 reg 68243838
... ... ... ... ... ... ... ...
2018-11-09 204.470000 206.010000 False 202.250000 205.550000 reg 34365750
2018-11-12 194.170000 199.850000 False 193.790000 199.000000 reg 51135518
2018-11-13 192.230000 197.180000 False 191.450100 191.630000 reg 46882936
2018-11-14 186.800000 194.480000 False 185.930000 193.900000 reg 60800957
2018-11-15 191.410000 191.970000 False 186.900000 188.390000 reg 46478801
2018-11-16 193.530000 194.969500 False 189.460000 190.500000 reg 36928253
2018-11-19 185.860000 190.700000 False 184.990000 190.000000 reg 41925292
2018-11-20 176.980000 181.470000 False 175.510000 178.370000 reg 67825247
2018-11-21 176.780000 180.270000 False 176.550000 179.730000 reg 31124210
2018-11-23 172.290000 176.595000 False 172.100000 174.940000 reg 23623972
2018-11-26 174.620000 174.950000 False 170.260000 174.240000 reg 44998520
2018-11-27 174.240000 174.770000 False 170.880000 171.510000 reg 41387377
2018-11-28 180.940000 181.290000 False 174.930000 176.730000 reg 46062539
2018-11-29 179.550000 182.800000 False 177.700000 182.660000 reg 41769992
2018-11-30 178.580000 180.330000 False 177.030000 180.290000 reg 39531549
2018-12-03 184.820000 184.940000 False 181.210000 184.460000 reg 40802482
2018-12-04 176.690000 182.389900 False 176.270000 180.950000 reg 41344282
2018-12-05 176.690000 176.690000 True 176.690000 176.690000 reg 0
2018-12-06 174.720000 174.780000 False 170.420000 171.760000 reg 43098410
2018-12-07 168.490000 174.490000 False 168.300000 173.490000 reg 42281631
2018-12-10 169.600000 170.090000 False 163.330000 165.000000 reg 62025994
2018-12-11 168.630000 171.790000 False 167.000000 171.660000 reg 47281665
2018-12-12 169.100000 171.920000 False 169.020000 170.400000 reg 35627674
2018-12-13 170.950000 172.570000 False 169.550000 170.490000 reg 31898647
2018-12-14 165.480000 169.080000 False 165.280000 169.000000 reg 40703710
2018-12-17 163.940000 168.350000 False 162.730000 165.450000 reg 44287922
2018-12-18 166.070000 167.530000 False 164.390000 165.380000 reg 33841518
2018-12-19 160.890000 167.450000 False 159.090000 166.000000 reg 49047297
2018-12-20 156.830000 162.110000 False 155.300000 160.400000 reg 64772960
2018-12-21 150.730000 158.160000 False 149.630000 156.860000 reg 95744584

252 rows × 7 columns

data 변수는 pandas.DataFrame 형태를 가지고 있습니다. 자세한 설명 보기.

In [38]:
X = data.loc['AAPL']['close_price'].astype('float')
In [41]:
plt.plot(X.index, X.values)
plt.ylabel('close')
plt.legend(['AAPL']);

실제 데이터에서 통계량을 계산할 수 있습니다.

In [42]:
np.mean(X)
Out[42]:
188.02081944444456
In [43]:
np.std(X)
Out[43]:
20.454761929633772

가격으로 부터 수익률 계산하기

pct_change(percent change) 라는 함수를 사용하여 일간 수익률을 쉽게 계산할 수 있습니다.

In [44]:
R = X.pct_change()
In [46]:
R.head()
Out[46]:
begins_at
2017-12-22         NaN
2017-12-26   -0.025370
2017-12-27    0.000176
2017-12-28    0.002814
2017-12-29   -0.010813
Name: close_price, dtype: float64

R 값을 확인해 보면 처음 데이터의 경우 기준이 되는 이전일의 데이터가 없기 때문에 NaN(Not a Number)라는 값이 저장되어 있습니다. 다음과 같은 조작을 통해 이 값을 없앨 수 있습니다.

In [47]:
R = X.pct_change()[1:]
In [48]:
R.head()
Out[48]:
begins_at
2017-12-26   -0.025370
2017-12-27    0.000176
2017-12-28    0.002814
2017-12-29   -0.010813
2018-01-02    0.017905
Name: close_price, dtype: float64

plt.hist 함수를 사용하여 일간 수익률 히스토그램을 그려보도록 하겠습니다.

In [49]:
# 구간의 범위를 몇 등분 할것인지 bins 개수를 통해 조절 가능합니다.
plt.hist(R, bins=20)
plt.xlabel('Return')
plt.ylabel('Frequency')
plt.legend(['AAPL Returns']);

통계량을 계산해 봅시다.

In [50]:
np.mean(R)
Out[50]:
-0.0003816818079786287
In [51]:
np.std(R)
Out[51]:
0.017506270274000497

위의 수익률 데이터로 부터 측정된 평균과 표준편차 값을 바탕으로 정규분포를 그려 보도록 하겠습니다. 그려진 정규분포와 실제 데이터의 수익률 분포 비교를 통해 실제 수익률이 정규분포를 따르는지 추정해 볼 수 있습니다.

In [52]:
plt.hist(np.random.normal(np.mean(R), np.std(R), 10000), bins=20)
plt.xlabel('Return')
plt.ylabel('Frequency')
plt.legend(['Normally Distributed Returns']);

유사한 형태를 보이지만 완전히 같다고는 보기 힘들다 생각됩니다. 일단 오늘은 이렇게 간단히 히스토그램을 그려 모양을 통해 추정해 보는것으로 글을 마치도록 하겠습니다. 실제데이터가 조금더 엄밀하게 정규분포를 따르는지 확인하려면 자크베라의 정규성 검정(Jacque-Bera Normality test)과 같은 방식을 활용해야 합니다. 이는 추후 가설 검정 부분 이후 소개하도록 하겠습니다.