graph_collective_inteligence_stock

4718 days ago by takepwave

Hiroshi TAKEMOTO (take@pwv.co.jp)

Sageで再現してみよう:集合知プログラミング第10章株価

今回は、集合知プログラミング の第10章にでてきます株価の因子分析を取り上げます。

あらかじめ読み込んでおくライブラリ

NMFの計算を行うnnmf.pyを読み込んでいます。

また、銘柄コードと銘柄名をプリントするために、_plist関数を定義します。

import urllib2 attach(DATA + 'nnmf.py') attach(DATA + 'RUtil.py') attach(DATA+'clusters.py') 
       
# 日本語を含むリストを一行でプリントする import json def _plist(obj): if isinstance(obj, list): sys.stdout.write("[") for i in range(len(obj)): if i != 0: sys.stdout.write(", ") orig = json.dumps(obj[i], indent=4) sys.stdout.write(eval("u'''%s'''" % orig).encode('utf-8')) sys.stdout.write("]\n") 
       

銘柄一覧の作成

10章では、Yahoo!ファイナンスを利用していましたが、日本の市場には対応していないみたいです。 そこで、フリーで株情報を公開化している株価データ ダウンロードサイト を利用することにします。

個別銘柄 株価時系列データから上位50個の銘柄を取り出して、銘柄コードリストtickersと銘柄辞書namesを作成します。

stocks = ["7751-T キヤノン", "8306-T 三菱UFJ", "7201-T 日産自", "3632-T グリー", "2432-T DENA", "6753-T シャープ", "7203-T トヨタ", "9984-T ソフトバンク", "6502-T 東芝", "6857-T アドバンテ", "8316-T 三井住友", "6301-T コマツ", "6752-T パナソニック", "6758-T ソニー", "5411-T JFEHD", "8604-T 野村HD", "6954-T ファナック", "7267-T ホンダ", "6501-T 日立", "6762-T TDK", "8411-T みずほ", "4503-T アステラス薬", "7974-O 任天堂", "4063-T 信越化", "8031-T 三井物", "5401-T 新日鉄", "8058-T 三菱商", "9202-T ANA", "2914-T JT", "9432-T NTT", "8802-T 菱地所", "8801-T 三井不", "9503-T 関西電", "4689-T ヤフー", "9437-T NTTドコモ", "8035-T 東エレク", "8766-T 東京海上", "8830-T 住友不", "7731-T ニコン", "9983-T ファーストリテイ", "4502-T 武田", "9433-T KDDI", "8591-T オリックス", "7733-T オリンパス", "6594-O 日電産", "5214-T 日電硝", "3382-T 7&I-HD", "4452-T 花王", "7752-T リコー", "9831-T ヤマダ電"] tickers = [s.split(' ')[0] for s in stocks] names = {} for s in stocks: nt = s.split(' ') names[nt[0]] = nt[1] 
       

株価データの取得

urlの部分を修正して、株価データのcsvファイルをダウンロードし、日付、出来高を取り出し、 pricesとdatesにセットします。

shortest=250 prices = {} dates = None 
       
for t in tickers: # urlをオープン url = 'http://k-db.com/site/jikeiretsu.aspx?c=%s&year=0&download=csv'%t rows = urllib2.urlopen(url).readlines() # 各行の取引量のフィールドを抽出 prices[t] = [float(r.split(',')[5]) for r in rows[2:] if r.strip() != ''] if len(prices[t]) < shortest: shortest = len(prices[t]) # 日付をセット if not dates: dates = [r.split(',')[0] for r in rows[2:] if r.strip() != ''] 
       

因子分析

データが揃ったので、NMFを使って因子分析をします。

因子分析によって、銘柄の特徴ベクトルと日付の特徴ベクトルが求まります。

# 解析用データをセットアップ l1 = [[ prices[tickers[i]][j] for i in range(len(tickers)) ] for j in range(shortest)] 
       
w, h = factorize(matrix(l1), pc=10, iter=200) 
       
6.0597757814e+18
2.98595935813e+17
2.26123310135e+17
1.82914414094e+17
1.58774016733e+17
1.42327700527e+17
1.29312900217e+17
1.18216924728e+17
1.07471473865e+17
9.67831467802e+16
8.75826491354e+16
8.04946434703e+16
7.49706463128e+16
7.06535234912e+16
6.70519184709e+16
6.39110958831e+16
6.11406092507e+16
5.87051880091e+16
5.65939019309e+16
5.47945196125e+16
6.0597757814e+18
2.98595935813e+17
2.26123310135e+17
1.82914414094e+17
1.58774016733e+17
1.42327700527e+17
1.29312900217e+17
1.18216924728e+17
1.07471473865e+17
9.67831467802e+16
8.75826491354e+16
8.04946434703e+16
7.49706463128e+16
7.06535234912e+16
6.70519184709e+16
6.39110958831e+16
6.11406092507e+16
5.87051880091e+16
5.65939019309e+16
5.47945196125e+16
# print h # print w 
       

結果の表示

特徴ベクトルの値大きな順にソートし、上位6個の銘柄と日付の上位3個の銘柄を表示します。

特徴ベクトルの上位銘柄の内、トップの値が他の値と比べて突出している場合には、 トップの企業のスキャンダルや特別なイベントによって出来高が大きく変動したことを表し、 逆に値が揃っている場合には、株価の出来高に関するグループの候補になると考えられます。

Feature 8を例にとると、2011-11-10にオリンパスの粉飾決算で「オリンパス」が管理銘柄になり、 その翌日の2011-11-11に大量の売りがでたことに起因していると思われます。

株価の情報については、 日々の日経平均株価を記録するブログを参考にさせて頂きました。 このブログは、日々の株価の情報をきちんと記録してあるので、今回のような結果の検証にはとても助かりました。

# Loop over all the features for i in range(shape(h)[0]): print "Feature %d" %i # Get the top stocks for this feature ol=[(h[i,j],names[tickers[j]]) for j in range(shape(h)[1])] ol.sort() ol.reverse() for j in range(6): _plist(list(ol[j])) print # Show the top dates for this feature porder=[(w[d,i],d) for d in range(shortest)] porder.sort() porder.reverse() print [(p[0],dates[p[1]]) for p in porder[0:3]] print 
       
Feature 0
[24503731.495503131, "三菱UFJ"]
[21942496.698866684, "みずほ"]
[14722168.773796422, "新日鉄"]
[4157687.7315523904, "シャープ"]
[1898085.0597432754, "パナソニック"]
[1864064.8616137055, "野村HD"]

[(2.4626644727394149, '2012-03-09'), (2.2899306285400796, '2012-02-15'),
(2.2480437009410785, '2012-02-24')]

Feature 1
[27168040.032120727, "みずほ"]
[23570501.275139578, "東芝"]
[8793882.8523550984, "三菱UFJ"]
[4133037.6287319614, "日産自"]
[3385558.7033507898, "新日鉄"]
[3063942.0314624044, "グリー"]

[(2.966388973066596, '2011-09-06'), (2.2940302794241605, '2011-08-09'),
(1.7605915944996444, '2012-07-25')]

Feature 2
[22483374.16913221, "シャープ"]
[5764920.5972688748, "パナソニック"]
[4718719.9261009339, "ANA"]
[3826031.4570076745, "三菱UFJ"]
[3599392.8615424554, "東芝"]
[2796578.285746316, "ソニー"]

[(4.2656715705249884, '2012-03-29'), (3.5237681491909547, '2012-07-24'),
(3.4763963315000774, '2012-03-14')]

Feature 3
[22327268.744900949, "オリンパス"]
[6783618.1721497104, "東芝"]
[4011381.1874279948, "日立"]
[3763030.3278834787, "野村HD"]
[2500871.7967263251, "三井物"]
[2157992.1389836962, "三菱商"]

[(3.6596980348316972, '2011-11-11'), (3.3883959893234081, '2011-10-18'),
(3.0622136678156338, '2011-10-27')]

Feature 4
[21030298.841478363, "ANA"]
[19145619.39827688, "みずほ"]
[15550734.471063728, "三菱UFJ"]
[3650608.8318609749, "東芝"]
[2627728.1886605611, "日立"]
[2072028.4862695236, "日産自"]

[(4.7411283281746117, '2012-07-03'), (3.1571797568669742, '2012-07-04'),
(2.6690379044978814, '2012-07-26')]

Feature 5
[37460566.537939727, "みずほ"]
[16967989.879439618, "三菱UFJ"]
[8752997.1270286962, "日産自"]
[6027004.8152939938, "パナソニック"]
[5534338.7011789205, "野村HD"]
[3604628.406140069, "ソフトバンク"]

[(2.2981950415763723, '2012-02-06'), (1.9427348447695754, '2011-08-25'),
(1.9342830658758026, '2012-02-02')]

Feature 6
[37426842.155204937, "野村HD"]
[19645415.770484798, "みずほ"]
[6695366.2084121471, "三菱UFJ"]
[2101482.3396030832, "新日鉄"]
[1633950.8291756455, "三井住友"]
[1581154.0772207044, "DENA"]

[(5.100719302072334, '2011-11-08'), (4.2140124094117493, '2011-11-09'),
(2.7067470001117937, '2012-03-22')]

Feature 7
[49855887.587955639, "みずほ"]
[7166732.1649423679, "日立"]
[6697903.567755457, "新日鉄"]
[4766056.4778533829, "東芝"]
[2615196.6310248198, "日産自"]
[1957292.7358615058, "三井物"]

[(3.9887861874876833, '2011-08-05'), (2.5066276529575675, '2011-10-27'),
(2.1986428591943463, '2011-10-28')]

Feature 8
[12972593.094876677, "東芝"]
[12057143.922293084, "三菱UFJ"]
[11887162.858139826, "日立"]
[11291908.875963112, "新日鉄"]
[9194990.09504476, "日産自"]
[6759443.0396503471, "野村HD"]

[(2.3414746977026435, '2012-06-04'), (2.2856907325104263, '2011-08-24'),
(2.2798007880572251, '2012-05-18')]

Feature 9
[22395069.877191965, "日立"]
[16660786.457563112, "みずほ"]
[9252762.5902375858, "三菱UFJ"]
[6525456.9038422294, "野村HD"]
[1581587.2629734608, "東芝"]
[1348317.4375840703, "ソニー"]

[(2.5858682521484515, '2011-08-04'), (2.5551325002251453, '2012-02-03'),
(2.2971193641440077, '2012-04-19')]
Feature 0
[24503731.495503131, "三菱UFJ"]
[21942496.698866684, "みずほ"]
[14722168.773796422, "新日鉄"]
[4157687.7315523904, "シャープ"]
[1898085.0597432754, "パナソニック"]
[1864064.8616137055, "野村HD"]

[(2.4626644727394149, '2012-03-09'), (2.2899306285400796, '2012-02-15'), (2.2480437009410785, '2012-02-24')]

Feature 1
[27168040.032120727, "みずほ"]
[23570501.275139578, "東芝"]
[8793882.8523550984, "三菱UFJ"]
[4133037.6287319614, "日産自"]
[3385558.7033507898, "新日鉄"]
[3063942.0314624044, "グリー"]

[(2.966388973066596, '2011-09-06'), (2.2940302794241605, '2011-08-09'), (1.7605915944996444, '2012-07-25')]

Feature 2
[22483374.16913221, "シャープ"]
[5764920.5972688748, "パナソニック"]
[4718719.9261009339, "ANA"]
[3826031.4570076745, "三菱UFJ"]
[3599392.8615424554, "東芝"]
[2796578.285746316, "ソニー"]

[(4.2656715705249884, '2012-03-29'), (3.5237681491909547, '2012-07-24'), (3.4763963315000774, '2012-03-14')]

Feature 3
[22327268.744900949, "オリンパス"]
[6783618.1721497104, "東芝"]
[4011381.1874279948, "日立"]
[3763030.3278834787, "野村HD"]
[2500871.7967263251, "三井物"]
[2157992.1389836962, "三菱商"]

[(3.6596980348316972, '2011-11-11'), (3.3883959893234081, '2011-10-18'), (3.0622136678156338, '2011-10-27')]

Feature 4
[21030298.841478363, "ANA"]
[19145619.39827688, "みずほ"]
[15550734.471063728, "三菱UFJ"]
[3650608.8318609749, "東芝"]
[2627728.1886605611, "日立"]
[2072028.4862695236, "日産自"]

[(4.7411283281746117, '2012-07-03'), (3.1571797568669742, '2012-07-04'), (2.6690379044978814, '2012-07-26')]

Feature 5
[37460566.537939727, "みずほ"]
[16967989.879439618, "三菱UFJ"]
[8752997.1270286962, "日産自"]
[6027004.8152939938, "パナソニック"]
[5534338.7011789205, "野村HD"]
[3604628.406140069, "ソフトバンク"]

[(2.2981950415763723, '2012-02-06'), (1.9427348447695754, '2011-08-25'), (1.9342830658758026, '2012-02-02')]

Feature 6
[37426842.155204937, "野村HD"]
[19645415.770484798, "みずほ"]
[6695366.2084121471, "三菱UFJ"]
[2101482.3396030832, "新日鉄"]
[1633950.8291756455, "三井住友"]
[1581154.0772207044, "DENA"]

[(5.100719302072334, '2011-11-08'), (4.2140124094117493, '2011-11-09'), (2.7067470001117937, '2012-03-22')]

Feature 7
[49855887.587955639, "みずほ"]
[7166732.1649423679, "日立"]
[6697903.567755457, "新日鉄"]
[4766056.4778533829, "東芝"]
[2615196.6310248198, "日産自"]
[1957292.7358615058, "三井物"]

[(3.9887861874876833, '2011-08-05'), (2.5066276529575675, '2011-10-27'), (2.1986428591943463, '2011-10-28')]

Feature 8
[12972593.094876677, "東芝"]
[12057143.922293084, "三菱UFJ"]
[11887162.858139826, "日立"]
[11291908.875963112, "新日鉄"]
[9194990.09504476, "日産自"]
[6759443.0396503471, "野村HD"]

[(2.3414746977026435, '2012-06-04'), (2.2856907325104263, '2011-08-24'), (2.2798007880572251, '2012-05-18')]

Feature 9
[22395069.877191965, "日立"]
[16660786.457563112, "みずほ"]
[9252762.5902375858, "三菱UFJ"]
[6525456.9038422294, "野村HD"]
[1581587.2629734608, "東芝"]
[1348317.4375840703, "ソニー"]

[(2.5858682521484515, '2011-08-04'), (2.5551325002251453, '2012-02-03'), (2.2971193641440077, '2012-04-19')]

株価チャートの表示

ここで、オリンパスの株価チャートがどのように変換しているか、RのRFinanceYJパッケージを使って表示してみましょう。

RFinanceYJ、quantmodがインストールされていない場合には、コメントを外して実行してください。 RFinanceYJのインストールには、libxml2-devが必要となります。

#r('install.packages("RFinanceYJ")') #r('install.packages("quantmod")') r('library(RFinanceYJ)') r('library(quantmod)') r('library(xts)') 
       
 [1] "quantmod"   "TTR"        "Defaults"   "RFinanceYJ" "xts"       
"zoo"        "XML"       
 [8] "stats"      "graphics"   "grDevices"  "utils"      "datasets"  
"methods"    "base"      
 [1] "quantmod"   "TTR"        "Defaults"   "RFinanceYJ" "xts"        "zoo"        "XML"       
 [8] "stats"      "graphics"   "grDevices"  "utils"      "datasets"   "methods"    "base"      
graph = preGraph('olympus.pdf') r('olympus <- quoteStockTsData("7733.t", "2011-11-01")') r('names(olympus)<-c("Date","Open","High","Low","Close","Volume")') r('olympus<-read.zoo(olympus,tz="")') r('candleChart(olympus)') postGraph(graph) 
       

特徴的な銘柄の比較

NMF分析で抽出した特徴的な銘柄の株価と出来高をプロットしてみます。 ここでは、野村HD、三菱UFJ、グリー、DENAを例とします。

# Feature 0の確認 graph = preGraph('Nomura.pdf') r('Nomura <- quoteStockTsData("8604.t", "2011-11-01")') r('names(Nomura)<-c("Date","Open","High","Low","Close","Volume")') r('Nomura<-read.zoo(Nomura,tz="")') r('candleChart(Nomura)') offGraph() graph = preGraph('UFJ.pdf') r('UFJ <- quoteStockTsData("8306.t", "2011-11-01")') r('names(UFJ)<-c("Date","Open","High","Low","Close","Volume")') r('UFJ<-read.zoo(UFJ,tz="")') r('candleChart(UFJ)') offGraph() graph = preGraph('DENA.pdf') r('DENA <- quoteStockTsData("2432.t", "2011-11-01")') r('names(DENA)<-c("Date","Open","High","Low","Close","Volume")') r('DENA<-read.zoo(DENA,tz="")') r('candleChart(DENA)') offGraph() graph = preGraph('Gree.pdf') r('Gree <- quoteStockTsData("3632.t", "2011-11-01")') r('names(Gree)<-c("Date","Open","High","Low","Close","Volume")') r('Gree<-read.zoo(Gree,tz="")') r('candleChart(Gree)') offGraph() 
       
html.table([[getGraph('Nomura.pdf', 0.5), getGraph('UFJ.pdf', 0.5)], [getGraph('DENA.pdf', 0.5), getGraph('Gree.pdf', 0.5)]]) 
       

銘柄の特徴ベクトルによるクラスタリング

最後に、銘柄の特徴ベクトル(計算では$h^T$)を使って株の銘柄の クラスタリングを行います。

グリーとDENA、三井物と三菱商、パナソニックとソニー等きれいに分類できています。

株の出来高をNMFで因子分析するだけで、銘柄のクラスタリングや関連づけができることに 正直驚きました。

# デンドログラムで日本語を表示するための修正 from PIL import Image,ImageDraw,ImageFont font = ImageFont.truetype('/usr/local/share/Fonts/MS Mincho.ttf', 14) 
       
# データのセットアップ data = h.transpose() (ii, jj) = shape(data) v = [[data[i, j] for j in range(jj)] for i in range(ii)] namelist = [names[t] for t in tickers] # 株価のクラスタリング clust=hcluster(v) drawdendrogram(clust,namelist,png=DATA + 'stockclust.png') showPNG('stockclust.png', fac=1)