はじめに
こんにちは。現在私はデータのカテゴライズに関する研究をやっております。
その際に、実験用データを学習用データと検証用データとに分ける処理を実装したので記載します。
実験用データはラベル (カテゴリー) 付きのものを想定しています。
詳細
分離の仕方は以下の二つの方法想定しました。
1, 学習用と検証用との比率をこちらで指定して分離する場合
-> この場合は指定された比率でカテゴリーごとに分離していくことになる
2, 完全にランダムに分離する場合
1 の方をわかりやすくするために例をあげる。
例えばこんな感じの実験用データがあったとする。
c1 data1
c1 data2
c1 data3
c1 data4
c2 data5
c2 data6
c2 data7
c2 data8
このデータを比率を 0.5 に指定して分離する。
結果:
学習用データ ->
c1 data1
c1 data2
c2 data5
c2 data7
検証用データ ->
c1 data3
c1 data4
c2 data6
c2 data8
こんなかんじにカテゴリーごとに綺麗に 1:1 で分離される。
実装
基本的にデータは tsv を想定している。
require "set"
# 重複のない数値配列を返す
def get_uniq_numbers(min, max, noa)
# min: 乱数の下限, max: 乱数の上限, noa: 必要な乱数の個数
# min < max でない場合は空配列を返す
return [] if min >= max
numbers = Set.new
i = 0
while i < noa
num = rand(min..max)
if !numbers.include?(num)
numbers.add(num)
i += 1
end
end
numbers.to_a
end
# 学習用データ (in_sample) と検証用データ (out_of_sample) とを分離するための module
module DataSeparator
# in_sample の比率を決めて分離する場合はこちらを使用する
# in_sample の比率の default は 0.5
def separate_per_category(data_set, in_sample_ratio=0.5)
# とりあえずカテゴリーごとにデータをまとめる
categories = Hash.new {|h, cat| h[cat] = []}
data_set.each do |data|
categories[data[:category]].push(data[:data])
end
# ## in_sample と out_of_sample とをビルドする
# こちらに分類したデータを入れていく
separated_data = {in_sample: [], out_of_sample: []}
categories.each do |category, data_array|
# 乱数の max
rand_max = data_array.length - 1
# インサンプルデータの数
in_sample_noa = (data_array.length * in_sample_ratio).round
# in_sample にするデータの index を取得
in_sample_indexes = get_uniq_numbers(0, rand_max, in_sample_noa)
# あとは振り分けていくだけ
data_array.each_with_index do |data, i|
obj = {category: category, data: data}
if in_sample_indexes.include?(i)
separated_data[:in_sample].push(obj)
else
separated_data[:out_of_sample].push(obj)
end
end
end
separated_data
end
module_function :separate_per_category
# 特に比率を決めないで分離する場合
def separate_randomly(data_set)
separated_data = {in_sample: [], out_of_sample: []}
data_set.each do |data|
# ランダムに 0 or 1 の乱数を発生させて、1 の場合は in_sample にする
if rand(0..1) == 1
separated_data[:in_sample].push(data)
else
separated_data[:out_of_sample].push(data)
end
end
separated_data
end
module_function :separate_randomly
end
実際にテストしてみる。
require_relative "data_separator.rb"
tsv_file = "./test_data.tsv"
# データセット作成
data_set = []
File.open(tsv_file) do |file|
file.each_line do |line|
array = line.split(/\t/)
data_set.push({category:array.first, data: array.last.chomp})
end
end
# カテゴリーごとに比率 0.7 で分離する
separated_per_category = DataSeparator.separate_per_category(data_set, 0.7)
p separated_per_category
print("\n")
# ランダムに分離する
separate_randomly = DataSeparator.separate_randomly(data_set)
p separate_randomly
実験用データが記載された test_data.tsv の中身はこんな感じ
python 機械学習でよく使用される言語です
python 広く使用されている汎用のプログラミング言語である。
python 小規模なプログラムから大規模なプログラムまで、さまざまなプログラムをクリアに書けるように、多くのコードが提供されている
python 標準ライブラリやサードパーティ製のライブラリも充実している。
python 理工学や統計解析のためのツールとしてなど、幅広い領域で使用されている。
ruby オープンソースの動的なプログラミング言語で、 シンプルさと高い生産性を備えています。
ruby まつもとゆきひろ(通称 Matz)により開発されたオブジェクト指向スクリプト言語であり、スクリプト言語が用いられてきた領域でのオブジェクト指向プログラミングを実現する。
ruby 機能として、クラス定義、ガベージコレクション、強力な正規表現処理、マルチスレッド、例外処理、イテレータ、クロージャ、Mixin、演算子オーバーロードなどがある。
ruby Perl を代替可能であることが初期の段階から重視されている。
ruby 可読性を重視した構文となっている。
終わりに
最初はカテゴリーごとに比率を指定していく仕様にしたんだけど、必要ないと思い一律にしました。機会があれば使ってみてください!