前提・実現したいこと
大量(3,574個程度)のcsvファイルを高速に読み込みたいです。
Pythonの勉強も兼ねて,現在過去10年程度の期間において、自分の作った株取引ルールが機能するかを検証するためのプログラムを作成中です。そのためにcsvで保存されたデータをなるべく早く読み込みたいです。
現在は xarrayを用いて3次元データとして扱おうとしておりますがより高速な方法がありましたら教えていただけたら幸いです。
使用しているデータは株価データ集 for 日本株時系列データ 2000年-2017年6月30日です。
発生している問題・エラーメッセージ
Ipythonで%time , %run -p で動作時間を計測した結果
570秒~1500秒もの時間がかかっており,xarray.concat()だけで40秒程度かかっております。
一例
8383269 function calls (8141048 primitive calls) in 905.298 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
25 384.667 15.387 384.667 15.387 {built-in method numpy.core.multiarray.concatenate}
1 244.721 244.721 711.806 711.806 combine.py:286(_dataarray_concat)
24 130.215 5.426 130.215 5.426 {method 'acquire' of '_thread.lock' objects}
1 55.747 55.747 904.727 904.727 read_data.py:3(<module>)
1 13.966 13.966 13.966 13.966 {built-in method pandas._libs.lib.infer_datetimelike_array}
3960 7.479 0.002 8.485 0.002 indexing.py:480(__setitem__)
11878 6.137 0.001 6.137 0.001 {built-in method pandas._libs.lib.array_equivalent_object}
該当のソースコード
import os
import numpy as np
import xarray as xr
import pandas as pd
from multiprocessing import Pool
import numba
_path = os.path.abspath(os.path.dirname(__file__)) + '/st-jp-2000-2017.6/dd_full'
_ref = pd.read_csv(os.path.abspath(os.path.dirname(__file__)) + '/st-jp-2000-2017.6/dd/1301.CSV',
index_col=0, parse_dates=True,
names=["Open", "High", "Low", "Close", "Volume", "margin selling", "margin debt"])
@numba.jit
def in_parallel():
global _path
files = os.listdir(_path)
p = Pool()
stock_db = (p.map(csv_to_xarray, files))
p.close()
p.join()
print("loading complete")
return stock_db
def in_serial():
global _path
files = os.listdir(_path)
stock_db = [csv_to_xarray(file) for file in files]
print("loading complete")
return stock_db
@numba.jit
def csv_to_xarray(file):
"""
:type file: str
:rtype: DataArray
"""
global _ref
global _path
data = pd.read_csv(_path + '/' + file, index_col=0, parse_dates=True,
names=["Open", "High", "Low", "Close", "Volume", "margin selling", "margin debt"])
data = adjust_index_length(data, _ref)
da = xr.DataArray(data.values.reshape(len(data.index), 1, len(data.columns)),
coords=[data.index, [file[0:4]],
["Open", "High", "Low", "Close", "Volume", "margin selling", "margin debt"]],
dims=["date", "code", "values"])
return da
@numba.jit
def adjust_index_length(data, ref):
"""
:type ref: DataFrame
:type data: DataFrame
:rtype: DataFrame
"""
time_diff = set(ref.index) - set(data.index)
if len(time_diff) == 0:
data.drop(set(data.index) - set(ref.index), inplace=True)
return data.sort_index()
else:
df = pd.DataFrame(index=time_diff, columns=["Open", "High", "Low", "Close", "Volume",
"margin selling", "margin debt"])
df = df.append(data)
return df.sort_index()
if __name__ == '__main__': # ここで この処理を行わないとサブプロセスが再帰的に生成される?(Winだけ?)
__spec__ = "ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>)"
print(xr.concat(in_parallel(), dim='code'))
#print(xr.concat(in_serial(), dim='code'))
試したこと
multiprocessingを用いて並列に走らせてみて,ディスク使用率は常時100%になっていることを確認しました。また,numbaの使用を検討中であります。
そもそもpythonだけですべて行わず,元データの選別等をC等で行うことも検討しております。
補足情報(言語/FW/ツール等のバージョンなど)
現在の動作環境は以下の通りです。
core i3-6100T 3.2GHz
Ram ddr3 8GB
Windows 10
Anaconda
Python 3.6
今後 core i7 ないし Ryzen 7を積んだpcに乗り換える予定があります。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+7
自分の作った株取引ルールが機能するかを検証するためのプログラムを作成中です。
使用しているデータは株価データ集 for 日本株時系列データ 2000年-2017年6月30日です。
わざわざ低速なフォーマットを採用するメリットは一つもありません。
CSVを採用するケースなんて、非エンジニアの上司や顧客がExcelで見ないとやだやだって駄々こねたときだけです。
この馬鹿げた処理速度の原因の殆どは読み込みとソートに終始しているので、SQLiteに任せたほうが間違いなく速いです。
ローカルでソート処理等を書いてはいけません。
CSVファイル -> SQLite等の高速なフォーマットに一度移しておき、SQL文をつかって絞込やソートを行いましょう。
検証フェイズが終わった後本番で使う時の事を考えた場合、
株価は毎日のように更新されますが、SQLiteに変換するプログラムを用意してまわしておけば良いでしょう。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.10%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2017/10/30 11:30 編集
別件ですが
元々ソートされているものに対して set()で集合にして取った差をインデックスにDataFrameを作ると何故ソートされてない状態になってしまうのかというのが現在ちょっと引っかかっています。
2017/10/30 11:45
Pythonに関しては詳しくないのでブログ記事の引用で失礼します。
setは順番の概念を持たないので、おもちゃ箱のような空間に無造作に放り込まれるのでしょうね。
その後重複チェック処理にかけられますので、メモリ空間上に設置されたアイテムはこねくり回されてぐちゃぐちゃになるのだろうと「完全に憶測」ですが想像してます。
ソート済みの要素を重複排除の為だけにsetを使うのはやめたほうが良さそうですね。
2017/10/30 22:00