G-Research Crypto Competition(timestamp,Targetの抜け(コインごと))
timestampが全通貨で抜けているtimestampがあることを確認したけど、そういえばコインごとにみたときはtimestampってどれだけ抜けているの?と思って確認。
全コインで抜けているtimestampの要因は出題者がデータまとめた際のエラーや取引所自体が落ちたとか?かなと。一方、あるコインのみ抜けているtimestampはそのコインが対象の1分間取引されなかったのではないかと思う。後者は動いてないだけだから前の時点の値で補完してもよい気がする。
コインごとにどれだけ抜けているか確認
コインによってデータ取得開始期間が違うため、取得開始以降で全体の何%がNaNであったかをCloseとTargetそれぞれについて確認。
id2name = details.set_index("Asset_ID")["Asset_Name"].to_dict() adds = [] for k,v in id2name.items(): tmp = data[data.Asset_ID == k].copy() full_time = pd.DataFrame(pd.to_datetime(full_timestamp)).rename(columns= {0: "org_timestamp"}) tmp = pd.merge(full_time, tmp, left_on= "org_timestamp", right_on= "Time", how= "left") tmp.sort_values("org_timestamp", inplace= True) tmp["timestamp"] = tmp["timestamp"].fillna(method= "ffill") tmp.dropna(subset= ["timestamp"], inplace= True) first_time = tmp["org_timestamp"].iloc[0] agg_dict = { "org_timestamp": "count", # "Time": "first", "Close": "count", "Target": "count", } agg = tmp.agg(agg_dict) agg["Close%"] = 100. - (agg.Close / agg.org_timestamp) * 100. agg["Target%"] = 100. - (agg.Target / agg.org_timestamp) * 100. agg["first_time"] = first_time agg = pd.DataFrame(agg) agg["asset_name"] = v adds.append(agg) tmp = pd.concat(adds, axis= 0, sort= True)\ .reset_index()\ .rename(columns= {0: "value"}) pivot = tmp.pivot(index= "asset_name", columns= "index", values= "value") pivot = pd.merge(pivot, details.set_index("Asset_Name")["Weight"], left_index= True, right_index= True, how= "inner") pivot[["Weight", "first_time", "Close%", "Target%"]].sort_values("Weight", ascending= False)
当たり前だけど、CloseのNaN比率が低いとTargetのNaN比率も低い。CloseのNaN比率の低さはVolumeの変動の低さと相関してそう。ある程度のVolumeで安定していれば取引がつかないこともなくCloseがNaNとなることもなくなる的な。試しにコインごとのVolumeの標準偏差を出してみるとドージ・ステラは確かに大きい。Moneroは標準偏差は大きくないがそもそも平均がとても小さい。Volumeが関係している気が。。
agg_dict = { "Volume": ["mean","median","min", "max", "std"] } pivot = df_v.groupby("Asset_ID").agg(agg_dict) pivot.columns= ["_".join(i) for i in pivot.columns] pivot = pivot.rename(index= details.set_index("Asset_ID")["Asset_Name"].to_dict()) pivot = pd.merge(pivot, details.set_index("Asset_Name")["Weight"], left_index= True, right_index= True, how= "inner") pivot[["Weight", "Volume_mean", "Volume_max", "Volume_std"]].sort_values("Weight", ascending= False)
G-Research Crypto Competition(timestampの抜け)
Targetを作成しているnotebookをみつけたので、それをコピー。
ってか、Targetは加重平均に対する超過平均ではなくて、アルファみたいだな。
timestampに抜けがある
その中で気になったのが、trainデータに各月初日の最初の1分のデータがないという話。
要するに、毎月の最初の1分間が欠落しているので、その1分前と16分前のTargetsはリターンを計算するためのClose priceがないのでNaNになるはずなのに、それらの値が計算されているのです。つまり、これらの場合のTargetsは、私たちが見ることのできないデータに基づいて計算されているのか、それとも間違ったタイムスタンプに基づいて計算されているのでしょうか?
ほう。ということで「各月初日の最初の1分」以外にも抜けがあるのか含めて確認。まずは、そもそも何日間のデータがあるはずなのか確認。下の通り、1359日。
full_timestamp = crypto_df["timestamp"]\ .sort_values()\ .apply(lambda x: datetime.datetime.fromtimestamp(x))\ .unique() tmp = pd.DataFrame(pd.to_datetime(full_timestamp)).rename(columns= {0: "org_timestamp"}) dt_min = tmp["org_timestamp"].min() dt_max = tmp["org_timestamp"].max() dt_max - dt_min
Timedelta('1358 days 23:59:00')
今度はHHMM(時間:分)ごとに要素数をカウントして、やたら少ないHHMMがないか確認。雑だけど、たしかに00:00のところだけ要素数が少ない。
tmp["hhmm_timestamp"] = tmp["org_timestamp"].apply(lambda x: x.replace(year= 2000, month= 1, day= 1)) hhmm = tmp.groupby("hhmm_timestamp").count() sns.lineplot(data= hhmm) hhmm.head()
value_counts()するとこんな感じ。00:00以外は1つ抜けがあるかないか。
hhmm["org_timestamp"].value_counts()
00:00以外についてもなんか抜けがあっても1つだけというのは気持ち悪いな。ランダムなら2つ抜けるとかあってもよさそう。同じ日に連続して何時間か抜けたりしているのか??とりあえず以下の2通りの可能性を考えたけど、出題者が抜いている気が何となくする。前者ならすべて1つずつなんてきれいにならないだろうし、Bitcoinが1分間トレードされなかったという時間があるとはあんまり思えない。。
全通貨取引その1分間取引がなかった
出題者が意図的にデータ削除orデータ成形のミス
とりあえず、その抜けってある一日に集中しているのかそれとも分散しているのか確認。なぜかわからんが2019/10/16と2019/10/23の2日に抜けは集中している。あと毎月初日は1つ抜けているみたい(これが00:00か)。2019/10/16が抜けているのはなぜだ。。ビットコインの価格推移みてもそんなに動いた日ではないのに。。
tmp["yyyymmdd_timestamp"] = tmp["org_timestamp"].apply(lambda x: x.replace(hour= 0, minute= 0)) yyyymmdd = tmp.groupby("yyyymmdd_timestamp")["org_timestamp"].count() yyyymmdd.value_counts()
sns.lineplot(data= yyyymmdd.iloc[:-1]) yyyymmdd.sort_values().head(10)
ってか、この2019/10/16あたりってTargetはあるのか?
自分のPCで作成した関数をKaggleのNotebookで使用する方法
Pycharmとかで作成した関数を、Kaggleのノートブック上で読み込んで使用できたら楽だなあ、と思って始めました。
もっといい方法があると思うけど、いまの自分にはこれが限界だったので、その方法をとりえず備忘録として。
参考サイト:
【超入門】初心者のためのGitとGitHubの使い方 - RAKUS Developers Blog | ラクス エンジニアブログ
一回設定してしまえば、あとは「1-6. ローカルリポジトリにコミットする」以降でリモートレポジトリにプッシュすればよさそう。
2.それをzip形式でダウンロードする。
Github上でレポジトリ開いて緑のCodeボタンおせばzip形式でダウンロードできる
3.KaggleのDatasetにアップロードする。
画像の通りUpload datasetをクリック
適当な名前でさっきダウンロードしたzipファイルをドラッグ
ちなみに、githubから直接できそうだったのになんか無理だった。。理由がわからない。。
あとはNotebook上で以下の感じで読み込めばできた~!
data_folder = "../input/ttttest/Crypto-master/" !ls $data_folder # import module we'll need to import our custom module from shutil import copyfile # copy our file into the working directory (make sure it has .py suffix) test = "../input/ttttest/Crypto-master/esty.py" # copyfile(src = "../input/my_functions.py", dst = "../working/my_functions.py") copyfile(src = test, dst = "../working/my_functions.py") # import all our functions # from my_functions import * import my_functions as pytest
G-Research Crypto Forecasting(欠損値確認、コインごとの取引量)
やるといってもなにをしようかと。。。。EDAとかでデータ見せてくれてるものはあるけど、はあそうですか。。。って感じになってしまいがち。
予測するものは将来15分間の超過リターン(Target: Residual log-returns for the asset over a 15 minute horizon.)。具体的には下の画像。
これ見る感じ、とりあえず各通貨ごとに重みづけした指数を作成しないと始まらないのでは??特徴量つくるにしても、終値の推移より指数対比の推移をみないと発見はないだろうなと思ったので、まずは指数を作ることに。さーっと共有されているNotebookみてみたけど、この指数作成しているっぽいものを見つけられなかったので自分で作ろうかと。
単純に「通貨のリターン」ー「重みづけ指数」みたいな特徴量作ったらそれなりにいい特徴量になるのでは??
悩みポイント
timestampに抜けとかないのか??
df
全体に関して欠損値を確認。vwap以外はなし。ただ、timestampがすべてそろっているかは別問題。
df = crypto_df.copy(deep= True) df.columns = [str.lower(i) for i in df.columns] df.isnull().sum(axis= 0)
timestamp 0 asset_id 0 count 0 open 0 high 0 low 0 close 0 volume 0 vwap 9 target 750338 dtype: int64
ではtimestampの抜けは?Dogeのように最近できて昔のデータがそもそもないやつは除いて確認してみたりした(na_mid列)けど、それでも結構抜け漏れあり。抜けもれあると1日変化と3日変化の区別がつかないと思うので、これはさすがに補完した方がよさそう。前の値とかで補完したら同じ話になるので、線形補完で。
pivot = df.pivot(index= "timestamp", columns= "asset_id", values= "close") asset_id2name = asset_details.set_index("asset_id")["asset_name"].to_dict() fillna = pivot.rename(columns= asset_id2name).fillna(method= "ffill").isnull().sum(axis= 0) not_fillna = pivot.rename(columns= asset_id2name).isnull().sum(axis= 0) fillna = pd.DataFrame(fillna).rename(columns= {0: "fillna"}) not_fillna = pd.DataFrame(not_fillna).rename(columns= {0: "not_fillna"}) na_check = pd.merge(fillna, not_fillna, left_index= True, right_index= True) na_check["na_mid"] = na_check["not_fillna"] - na_check["fillna"]
- timestampの抜けを埋める。フルのtimestampを作成→それでreset_indexの方法で。
フルのtimestamp作成。すべて60(秒)間隔ではなかったけど、資産間でラグがあっていればいいかなと思ったのでよいことに。
full_timestamp = df.timestamp.unique() pd.Series(np.diff(np.sort(full_timestamp))).value_counts()
reset_indexかつ欠損値補完
・・・ここまでやって気づいたけど、欠損値ってもしやその1分でトレードがなかったときでは?????たしかに、夜中とかなくてもおかしくないか????
ということで、count(取引数)と一応Volume(取引量)の最小数を確認。せっかくなので最大と平均も。すると取引量最大のBitCoinでも最小は1ということは、欠損値は取引0=補完せずに欠損値であることに意味があるのでは。。線形補完は違うと思った。取引0=前の時点と変化なしなので終値などはfillnaでcountなどは0を入れればよい気が。
agg_dict = { "count": ["mean", "min", "max"], "volume": ["mean", "min", "max"], } group = df.groupby("asset_id", as_index= False).agg(agg_dict) group["asset_id"] = group["asset_id"].apply(lambda x: asset_id2name[x]) group.columns = ['_'.join(col) for col in group.columns]
というか、このデータはへえ、って感じだったのでちょっとグラフ書いてみることに。取引数は中央値>平均値なのでやっぱり取引数の波は激しくあるタイミングでみんな集中して取引するみたいですな。大きく動いた後あとなのか同時なのか、下落なのか上昇なのか(下落っぽいけど)など深堀りの余地はありそう。特にDogeは中央値と平均値の差が激しい気がする。激しい=投機的コインのようなイメージ受けるけどな。実際に平均/中央値だしてみたらDogeが圧倒的。さすが柴犬。
import matplotlib import matplotlib.pyplot as plt import seaborn as sns # col = "count_mean" col = [ "count_mean", "count_median" ] show = group.set_index("asset_id_")\ .loc[:, col]\ .stack()\ .reset_index()\ .rename(columns= {"level_1": "hue", 0: "value"}) fig = plt.figure() ax = fig.add_subplot() # sns.barplot(data= group, x= "asset_id_", y= col, ax= ax) sns.barplot(data= show, x= "asset_id_", y= "value", hue= "hue", ax= ax) ax.tick_params(axis= "x",rotation = 270) # ax.set_title(col) ax.set_title(col[0].split("_")[0])
平均/中央値
平均/中央値(柴犬除き)
あと1取引あたりのボリューム。大型のフローが入りやすいのか小型なのか。BitCoinは個人のすそ野広そうだし小型では??案の定Dogeあたりのマイナーコインのフローがでかい。まじでコインによって差がでた。
group["one_impact_mean"] = group.volume_mean / group.count_mean group["one_impact_median"] = group.volume_median / group.count_median col = [ "one_impact_mean", "one_impact_median", ] show = group.set_index("asset_id_")\ .loc[:, col]\ .stack()\ .reset_index()\ .rename(columns= {"level_1": "hue", 0: "value"}) fig = plt.figure() ax = fig.add_subplot() sns.barplot(data= show, x= "asset_id_", y= "value", hue= "hue", ax= ax) ax.tick_params(axis= "x",rotation = 270)
G-Research Crypto Forecasting(コードの提出方法)
ビットコインはちょっと気になるということで、これ!
予測の提出方法がよくわからない。。ファイルではなくコードを提出するのか??ということでとりあえず、コードの提出方法試したのでその備忘録。結論はファイル提出するときとそんなにかわんないっぽい。
- とりあえずコード作る。 今回は主催者が用意してるBasic Submission Templateをそのまま使用。右上Save Versionを押す。
- ノートブックを閉じて、下の画面のSubmit Predictionで提出。
- 補足メモ
test_df
にtimestampやcloseなどが入っているので、row_idをキーにsample_prediction_df
に予測したTargetを入れればよさそう。ただ、test_df
の中身をみたらtimestampが1つdatetime.datetime(2021, 6, 13, 0, 3)しかない。これは実際にはどんどん増やされていくということ??提出後の実際の市場データをもとに評価するらしいので、おそらく変わっていくのでしょう。
とりあえずコンペの紹介文を和訳。
暗号化予測チュートリアル G-Research暗号予測コンペティション G-Research Crypto forecasting competitionでは、参加者は主要な暗号通貨を束ねた価格リターンを予測する課題を持っています。このチュートリアルノートでは、参加者の皆様が参加しやすいように、暗号通貨予測に関連するいくつかのコンセプトについて説明します。 このノートブックでは、暗号予測への導入、データセットの構造と要素、関連する統計的特性、いくつかのMLベースラインモデルの構築、コード送信の例を説明しています。
暗号通貨市場 まず、暗号の世界について簡単に紹介します。暗号通貨は非常に人気のある不安定な市場となっており、投資家に大きなリターン(と同時に損失も)をもたらしています。ビットコイン(BTC)、イーサ(ETH)、ドージコイン(DOGE)など、多くの人が聞いたことのある主要な暗号通貨が数千種類も誕生しています。 暗号通貨は暗号取引所で広く取引されており、CryptoCompareによると、昨年1年間に毎日平均410億ドルが取引されています(2021年7月25日現在)。 異なる暗号通貨間の価格変動は、相互に大きく関連しています。例えば、ビットコインは歴史的に暗号通貨間の価格変動の主な要因となっていますが、他のコインも市場に影響を与えています。
リターンの予測 金融モデリングの基本的な作業は、近い将来の価格がどのように動くかを予測することである。過去の価格の時系列データを学習データとして、価格が上がるか下がるか、どの程度上がるか、すなわち資産リターンを予測したいのです。 このコンペティションでは、Kagglerは14種類の人気暗号通貨のリターンを予測する機械学習モデルを、数分から数時間の時間スケールで構築することが課題となっています。あなたは、数百万行の分単位の暗号通貨取引データにアクセスすることができ、それを使って14の資産すべてについて同時に予測モデルを設計することになります。あなたの予測は、コンペティション終了後の3ヶ月間の評価期間中に収集された実際の市場データとの相関関係によって評価されます。 暗号通貨のリターン予測は、オープンかつ非常に困難な予測タスクです。資産の極端な変動、データの非定常性、市場やミーム操作、資産間の相関、非常に速く変化する市場状況を考えると、これはMLコミュニティにとって魅力的な問題領域と言えます。私たちと同じように、皆さんもこの問題を魅力的だと感じてくれることを願っています。
- スケジュール
このコンペティションは、トレーニング期間と実際の市場データに対してモデルを実行する第2期間を設けた予測コンペティションです。 トレーニングのタイムライン 2021年11月2日~開始日
2022年1月25日 - エントリー締め切り。出場するためには、この日までに競技規則に同意する必要があります。
2022年1月25日 - チーム合併の締切。この日が、参加者がチームに参加したり、合併したりできる最終日です。
2022年2月1日 - 最終提出期限。
すべての締め切りは、特に断りのない限り、該当する日の午後11時59分(UTC)です。大会主催者は、必要と判断した場合、コンテストのスケジュールを更新する権利を有します。
予測タイムライン。 最終提出期限の後、選択されたノートブックに対して実行される市場データの更新を反映するために、リーダーボードに定期的な更新が行われます。更新はおよそ2週間おきに行われる予定です。
2022年5月3日 コンペティション終了日 - 入賞者発表
optiver-realized-volatility-prediction 3日目
目標がないと頑張れないので、今日の時点で銅メダルラインの0.1955を一旦に目標してみよう。方法はディスカッションやVote多いNotebookみてひたすらぱくる。
今日のまとめ
- スコア0.2192 -> 0.2134
今日の目標
前回うまくいったボラのラグを取る特徴量を他の値でも試す
クラスタリングしてその平均取るやつをやる。
前回うまくいったボラのラグを取る特徴量を他の値でも試す
realized_volを正しいtime_idに並べ替えて、そのラグをとったらスコア結構あがった。前回はラグ1しかとらなかったので、それを1,2,5...のように複数取るだけ。
クラスタリングしてその平均取るやつをやる。
time_idとstock_idで類似性が高いものをクラスタリングして、その平均取った値を特徴量にする。
サンプルコード
target_feature = 'book.log_return1.realized_volatility' n_max = 40 # make neighbors pivot = df.pivot('time_id', 'stock_id', 'price') pivot = pivot.fillna(pivot.mean()) pivot = pd.DataFrame(minmax_scale(pivot)) nn = NearestNeighbors(n_neighbors=n_max, p=1) nn.fit(pivot) neighbors = nn.kneighbors(pivot) # aggregate def make_nn_feature(df, neighbors, f_col, n=5, agg=np.mean, postfix=''): pivot_aggs = pd.DataFrame(agg(neighbors[1:n,:,:], axis=0), columns=feature_pivot.columns, index=feature_pivot.index) dst = pivot_aggs.unstack().reset_index() dst.columns = ['stock_id', 'time_id', f'{f_col}_cluster{n}{postfix}_{agg.__name__}'] return dst feature_pivot = df.pivot('time_id', 'stock_id', target_feature) feature_pivot = feature_pivot.fillna(feature_pivot.mean()) neighbor_features = np.zeros((n_max, *feature_pivot.shape)) for i in range(n): neighbor_features[i, :, :] += feature_pivot.values[neighbors[:, i], :] for n in [2, 3, 5, 10, 20, 40]: dst = make_nn_feature(df, neighbors, feature_pivot, n) df = pd.merge(df, dst, on=['stock_id', 'time_id'], how='left')
実装コード
中に入れ子で関数作ったりして、変数の受け渡しがめんどくさかったのでclassつかってみた。いまいちうまく使えているかわからん。。
from sklearn.neighbors import NearestNeighbors class NearestNeiborFeature: def __init__(self, f_nn, f_agg, type_): self.n_max = 40 self.feature_nn = f_nn self.feature_agg = f_agg self.type_ = type_ def nn_features(self, df): ''' 特徴量Xのminmax_scaleで近いもの同士(time_id, stock_id)を集めて、その平均を取る - time_idのとき time_idが近い=そのときfeature_nnのminmax水準が近い 各stockに対してtimeが近いn個のfeature_aggを抽出して、その平均取る ''' def make_nn_feature(df, neighbors, n, agg=np.mean): pivot_aggs = pd.DataFrame(agg(neighbors[1:n,:,:], axis=0), columns=df.columns, index=df.index) dst = pivot_aggs.stack().reset_index() dst.columns = ['time_id', 'stock_id', f'{self.type_}_cluster{n}_{agg.__name__}_{self.feature_nn}'] return dst # make neighbors pivot = df.pivot('time_id', 'stock_id', self.feature_nn) pivot = pivot.fillna(pivot.mean()) pivot = pd.DataFrame(minmax_scale(pivot)) if self.type_ == "stock": pivot = pivot.T # stockのときのみ転置 nn = NearestNeighbors(n_neighbors=self.n_max, p=1) ''' n_neibors: 近いとして持ってくる個数 p(int), default=2: 距離の出し方 Parameter for the Minkowski metric from sklearn.metrics.pairwise.pairwise_distances. When p = 1, this is equivalent to using manhattan_distance (l1), and euclidean_distance (l2) for p = 2. For arbitrary p, minkowski_distance (l_p) is used. ''' nn.fit(pivot) neighbors = nn.kneighbors(pivot) # tuple(0: distance, 1: index) # nnで近い順にn個取得、その平均 feature_pivot = df.pivot('time_id', 'stock_id', self.feature_agg) feature_pivot = feature_pivot.fillna(feature_pivot.mean()) if self.type_ == "stock": feature_pivot = feature_pivot.T # stockのときのみ転置 neighbor_features = np.zeros((self.n_max, *feature_pivot.shape)) for i in range(self.n_max): # 1d: nn, 2d: time_id, 3d: stock_id neighbor_features[i, :, :] += feature_pivot.values[neighbors[1][:, i], :] for n in [2, 3, 5, 10, 20, 40]: dst = make_nn_feature(feature_pivot, neighbor_features, n) df = pd.merge(df, dst, on=['stock_id', 'time_id'], how='left') return df
作成した特徴量
- stock_cluster5_mean_log_return_realized_volatility: クラスタリングしてその平均取ったりしたやつ
importance
地味にorder(時系列の順番)も結構効いている気が。
optiver-realized-volatility-prediction 2日目
目標がないと頑張れないので、今日の時点で銅メダルラインの0.1955を一旦に目標してみよう。方法はディスカッションやVote多いNotebookみてひたすらぱくる。
今日のまとめ
- スコア0.2344 -> 0.2192
- 時系列+元のpriceに復元したことでラグやtime_id間での変化率が取れるようになった。
- ラグは1だけにしたけど、もっと他の値でもとるか?
- あと、クラスタリングしてその平均取るやつもやってみる。結構スコア上がるらしい。
今日の目標
time_idを時系列に復元+priceをもとの値に戻す
time_idを時系列に復元
参考はこのDiscussion.Discussionでやられているのは「time_idの復元」「time_id,stock_idで似ているものクラスタリングしてその平均みたいな特徴量作成」の2つと理解。time_idが復元できたら「ラグ変数の作成」「Cross Variationを時系列で検証」ができるかなと。まずはtime_idの復元を。
Optiver Realized Volatility Prediction | Kaggle
サンプルコード
というかそもそもtime_idってランダムだったの?という。。要点まとめると、 1. 各stock_idのbid/ask priceをtick(最小値幅)で割ると元のpriceに戻る。
- priceをminmax scalingして、近い順に並べ替えると時系列順に復元可能。
前者は最初の値における最小単位は1とかですべて共通。しかし、そのsecondsにおける株価の平均などで割られているのでは?割った理由はseriesにおけるボラ(標準偏差)がpriceの水準によって変わることを修正したかったのかなと。x*100の標準偏差はxの標準偏差の100倍なので。
後者はstock_idとあるのでおそらくすべて株=相関高いからこそ可能な気が。それなら時系列順に戻す前でも相関は高そうではある。
import glob import numpy as np import pandas as pd from joblib import Parallel, delayed from sklearn.manifold import TSNE from sklearn.preprocessing import minmax_scale def calc_price_from_tick(df): tick = sorted(np.diff(sorted(np.unique(df.values.flatten()))))[0] return 0.01 / tick def calc_prices(r): df = pd.read_parquet(r.book_path, columns=[ 'time_id', 'ask_price1', 'ask_price2', 'bid_price1', 'bid_price2' ]) df = df.groupby('time_id') \ .apply(calc_price_from_tick).to_frame('price').reset_index() df['stock_id'] = r.stock_id return df def reconstruct_time_id_order(): paths = glob.glob('/kaggle/input/optiver-realized-volatility-prediction/book_train.parquet/**/*.parquet') df_files = pd.DataFrame( {'book_path': paths}) \ .eval('stock_id = book_path.str.extract("stock_id=(\d+)").astype("int")', engine='python') # build price matrix using tick-size df_prices = pd.concat( Parallel(n_jobs=4)( delayed(calc_prices)(r) for _, r in df_files.iterrows() ) ) df_prices = df_prices.pivot('time_id', 'stock_id', 'price') # t-SNE to recovering time-id order clf = TSNE( n_components=1, perplexity=400, random_state=0, n_iter=2000 ) compressed = clf.fit_transform( pd.DataFrame(minmax_scale(df_prices.fillna(df_prices.mean()))) ) order = np.argsort(compressed[:, 0]) ordered = df_prices.reindex(order).reset_index(drop=True) # correct direction of time-id order using known stock (id61 = AMZN) if ordered[61].iloc[0] > ordered[61].iloc[-1]: ordered = ordered.reindex(ordered.index[::-1])\ .reset_index(drop=True) return ordered[['time_id']]
作成した特徴量
price_change_timeid: 価格変化率 vol_lag1_timeid: time_id一つ前のrealized volatility vol_20med_timeid: 20日ロール中央値realized volatility
importance
20medが効いた。lag1も効いてる。pct_changeが効かなかったか。絶対値が大きければtargetも大きくなると思ったんだが。