株も歩けば犬に当たる

ブラックSlerで働くSEが株やPythonや思ったことについて書いています。

第2回 データを整える 〜S◯I証券風のチャートを描いてみる〜 

今回は、Yahoo!ファイナンスのサイトからスクレイピングして、取得してきたデータを整えようと思います。

データを整えるとは??
データをコンピュータにも読み込める形にするということです。

データを取得したら、次はそれを使ってグラフを描いたり、計算したり・・・
いろいろできますよね!
でも、例えば、string型のデータを計算させることはできませんよね。
グラフとしてプロットするにも、int型などの然るべき型にしないといけません。

だから今回は、データを加工する前の必須工程である「データを整える」をやろうと思います。


前回は、Yahoo!ファイナンスからデータを取得するところまでやりました。

doz13189.hatenablog.com

じゃあ、前回集めたデータは何がいけないのかを見てみます。

f:id:doz13189:20160828171447p:plain

前回使ったソースコードで、Yahoo!ファイナンスから40日分の株価を取得しました。
問題点が2つあります。

1つは、インデックスがされてないことです。
左端の数字はインデックスなので、本来は0から順番に振られていないといけないのにも関わらず、0〜19でループしています。
これはデータの取得元のサイトのページ構造に原因があるので、こうなってしまうのは仕方がないことです。
なので、これは自分でインデックスを振りなおしてやる必要があります。

2つめは、日付が2016年8月1日となっていることです。
年とか月とは日は、コンピュータには読めません。
string型として入っているので、このままではグラフを作るさいに軸として使えません。
日付はx軸として使うので、なんとかしないとダメですね。


この2つの問題を解決するためのコードがこちらです。

import pandas
import datetime

def scraping_yahoo(code, start, end, term):
	base = "http://info.finance.yahoo.co.jp/history/?code={0}.T&{1}&{2}&tm={3}&p={4}"

	start = str(start)
	start = start.split("-")
	start = "sy={0}&sm={1}&sd={2}".format(start[0], start[1], start[2])
	end = str(end)
	end = end.split("-")
	end = "ey={0}&em={1}&ed={2}".format(end[0], end[1], end[2])
	page = 1

	result = []
	while True:
		url = base.format(code, start, end, term, page)
		df = pandas.read_html(url, header=0)
		if len(df[1]) == 0:
			break

		result.append(df[1])
		page += 1
	result = pandas.concat(result)
	result.columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Adj Close']

	return result


def generate(data):
	data_frame = data[["Date","Open","Close","High","Low",'Adj Close',"Volume",]]

	hiduke = pandas.DataFrame(data_frame["Date"])
	hiduke.columns = ["Hiduke"]

	dates = []
	for day in data_frame["Date"]:
		day = day.replace("年", "-")
		day = day.replace("月", "-")
		day = day.replace("日", "")
		time = datetime.datetime.strptime(day, '%Y-%m-%d')
		dates.append(time)

	data_frame["Date"] = dates
	tmp = data_frame["Date"].values.astype("datetime64[D]")
	d = tmp
	
	data_frame["Date"] = tmp.astype(float)

	index = len(data_frame["Date"])
	index_data = []
	for x in range(index):
		index_data.append(x)

	data_frame.index = index_data
	hiduke.index = index_data
	
	data_frame = pandas.concat([data_frame, hiduke], axis=1)

	return data_frame



if __name__ == "__main__":
	company = 4312

	EndDate = datetime.date.today()
	StartDate = EndDate - datetime.timedelta(days=60)#640

	data = scraping_yahoo(company, StartDate, EndDate, "d")
	print(data)
	generate_data = generate(data)
	print(generate_data)

前回のコードにプラスしているので、少し長くなっています。
新しくなっているコードはdef generate(data):の部分です。


このコードを実行することでデータがこうなります。


f:id:doz13189:20160828173030p:plain


インデックスが整っています。
日付であるDateが変換されていますね。
これは、Dateをdatetime64という形式にしてから、さらにfloatの型にはめ込んだためです。
なぜこの型なのかというと、私はこのあとにmatplotlib.financeというモジュールで、ローソク足をプロットします。
モジュールの関数が、この形だと扱いやすかったのでこうしました。

しかし、これだと本当の日付がわからないので、本来の年月日の日付もHidukeとして追加して、残しています。


ここからはコードを解説したいと思います。
もう一度、今回新しくなった部分のコードを貼りますね。

def generate(data):
	data_frame = data[["Date","Open","Close","High","Low",'Adj Close',"Volume",]]

	hiduke = pandas.DataFrame(data_frame["Date"])
	hiduke.columns = ["Hiduke"]

	dates = []
	for day in data_frame["Date"]:
		day = day.replace("年", "-")
		day = day.replace("月", "-")
		day = day.replace("日", "")
		time = datetime.datetime.strptime(day, '%Y-%m-%d')
		dates.append(time)

	data_frame["Date"] = dates
	tmp = data_frame["Date"].values.astype("datetime64[D]")
	d = tmp
	
	data_frame["Date"] = tmp.astype(float)

	index = len(data_frame["Date"])
	index_data = []
	for x in range(index):
		index_data.append(x)

	data_frame.index = index_data
	hiduke.index = index_data
	
	data_frame = pandas.concat([data_frame, hiduke], axis=1)

	return data_frame


まずはじめに、引数をdataにし、scraping_yahooのreturnを受け取っています。
受け取ったデータをそのまま、data_frameに入れています。

次に、hidukeという新しいデータフレームを作っています。
そして、その中には受け取ったデータであるdata_frameの["Date"]をそのまま入れています。
columnsの名前をHidukeにしました。
今から、日付の年月日をいじるのですが、元のデータも残しておきたいのです。
そのため、hidukeというデータフレームを作って避難させています。
下がそのコードです。

data_frame = data[["Date","Open","Close","High","Low",'Adj Close',"Volume",]]

hiduke = pandas.DataFrame(data_frame["Date"])
hiduke.columns = ["Hiduke"]


ここからdata_frameのDateの年月日をいじっていこうと思います。
2016年8月1日という形から、2016-8-1という形に変換しています。
この形だと、datetimeモジュールの形式に合うので、加工しやすくなります。
加工したデータは、リストであるdates = []に入っています。
そのため、そのままdata_frame["Date"] = datesで上書きしてやればOKです。

普通はここまでで良いかもしれません。
私の場合は、このデータをローソク足をプロットする際に使うため、もう少しデータの形式を変える必要があります。
ここからさらにdatetime64[D]という形式に変換しています。
そして、それをfloat型にしています。
日付の整形はこんなところです。
下がそのコードです。

dates = []
for day in data_frame["Date"]:
	day = day.replace("年", "-")
	day = day.replace("月", "-")
	day = day.replace("日", "")
	time = datetime.datetime.strptime(day, '%Y-%m-%d')
	dates.append(time)

data_frame["Date"] = dates
tmp = data_frame["Date"].values.astype("datetime64[D]")
d = tmp
	
data_frame["Date"] = tmp.astype(float)


次にインデックスです。
これは非常にシンプルで、len()でデータの数を調べます。
そして、データの数の分だけのリストを作ります。
それを.indexで上書きしてやるだけでOKです。
下がそのコードです。

index = len(data_frame["Date"])
index_data = []
for x in range(index):
	index_data.append(x)

data_frame.index = index_data
hiduke.index = index_data


最後に忘れていはいけないのが、hidukeをくっつける作業です。
pandas.concatで2つのデータフレームを合体させています。
下がそのコードです。

data_frame = pandas.concat([data_frame, hiduke], axis=1)

return data_frame


以上でデータが整いました。
今回はこんなところで終わろうと思います。

この作業は、少し面倒ですが必須工程です。
私の感覚からすると、この工程で一番時間がとられているようにも思います。
データが揃ってしまえば、あとの作業は楽しいですし、そもそもちゃんと使いやすいデータになっていれば作業が捗ります。
大変ですが、がんばりましょう笑

このデータで、私はローソク足を描いています。
ローソク足を書くにはもうひと頑張りいりますが、気になる方は見てみてください。
ちなみに続きはこちらです。

doz13189.hatenablog.com