最近、目を見張るような tips を見つけたのですがそこまで多用するかも微妙で、当面はすぐに忘れてしまいそうなので備忘録です。
R でたくさんのベクトルを、一定数に分けたいとします。
交差検証のシナリオが分かりやすいですね。
交差検証(交差確認)(こうさけんしょう、英: cross-validation)とは、統計学において標本データを分割し、その一部をまず解析して、残る部分でその解析のテストを行い、解析自身の妥当性の検証・確認に当てる手法を指す。
k 分割交差検証というのは、たとえばデータを 5 個 (k = 5) に分けて、
- 1 つめのセットを除いたデータで訓練したモデルを、1 つめのセットに適用して精度を測る
- 2 つめのセットを除いたデータで訓練したモデルを、2 つめのセットに適用して精度を測る
- 3 つめのセットを除いたデータで訓練したモデルを、3 つめのセットに適用して精度を測る
- 4 つめのセットを除いたデータで訓練したモデルを、4 つめのセットに適用して精度を測る
- 5 つめのセットを除いたデータで訓練したモデルを、5 つめのセットに適用して精度を測る
- 上記 5 つの精度の平均をとって、モデルそのもののパフォーマンスとする
という一連の検証アプローチです。
…自分の理解が正しければw
これを手動で実装する場合、元のデータセットを 5 分割する必要があります。
1,000 行のデータであれば 200 行ずつと分かりやすいですが、今試している SIGNATE の練習問題だと、訓練データが 16,280 行なので、え~と…3,256 行ずつにしないといけません。
さらに、これが 5 の倍数でない場合や、そもそも k の値をいろいろ変えてみたいとなった場合、端数になる最後のセットの扱いも加味する必要が出てきます。
30 行のデータを 4 分割したいとなったら、「8 + 8 + 8 + 6」に分ける必要があるわけですね。
その辺を簡潔なコードで柔軟に処理する方法を探していたところ、見つけました。
元ネタはこちら。
こちらはもともと、(最終セットの端数の処理を含めて) 「一定数ずつのセット」に分けるにはどうするかという質問に対して、
split() と seq_along() と ceiling() があればできるやん
という回答になっています。
d というベクトルを 20 ずつに分けるなら、
split(d, ceiling(seq_along(d) / 20))
とのこと。
今回の自分のニーズは「特定セット数」に分けること、なので、これを少々加工します。
この Q&A の例に沿うと、73 の長さを持つベクトル d を 5 セットに分けるとした場合、1 セットの基準サイズが 14 と導ければよいので、
split(d, ceiling(seq_along(d) / floor(length(d) / 5)))
ということになります。
これを実際の訓練データセットに当てはめる場合、ベクトルはデータセットの行番号か id 列 (あれば) になります。
自分は行番号を使っていて、ランダムに並べ替えた行番号を先頭から順番に区切っていくという手順を踏みます。
dataset を k 分割するとした場合、
idx <- sample(1:nrow(dataset))
cv <- split(idx, ceiling(seq_along(idx) / floor(length(idx) / k)))
となり、i を 1 から k までループまたはマップする中で
test_idx <- cvi
train_idx <- setdiff(idx, test_idx)train_set <- dataset[train_idx, ]
test_set <- dataset[test_idx, ]
とすれば、k 分割交差検証における訓練データセットと検証データセットが作れるわけです。
個人的にはこの「split() の中で seq_along(d) ÷ セット サイズを ceiling() する」ということの意味が腹落ちしきっていないんですが、結局はベクトルの要素に 1 から k までのファクタを割り当てて、それに基づいて split() するという動作のようです。
今後もうまく使っていきたいです。
…と、「かたてわざってバイクのブログじゃなかったの?」とお思いの方には意味不明な記事ですみません。
バイクは季節柄、首都高ランばかりですが、そろそろもう少し遠くまで足を伸ばし始めてもいいかなと思っています。