Mar 02, 2008
split
機械学習器をJavaで実装しているところなのだが、ファイル読み込みのところがやたら遅くなってしまっていて、どうしたものかと悩んでいる。
機械学習器と言っても様々であるが、構造学習をしない場合、 以下のようなフォーマットが用いられることが多い。
label1 feat1 feat2 feat3 ... label2 feat3 feat5 feat6 ... ...
このファイルの読み込みの処理を、当初以下のように一行ずつ読み込んでStringオブジェクトのsplitを呼び出して要素ごとに分割するという処理をしていた。
BufferedReader reader = new BufferedReader(new FileReader(file));
...
while((line = reader.readline()) != null) {
String[] elements = line.split(" ");
...
}
しかし、これで走らせてみると、非常に遅い。
Stringクラスのsplitは、内部ではパターンをコンパイルして、そのパターンを用いてsplitしている。以下はStringクラスのsplit。
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
}
これだとsplitする度に毎回パターンをコンパイルしていることになるので、事前にPattern.compile(" ")しておいて、このコンパイルしたパターンを使ってsplitするようにした。 しかし、気持ち程度しか速くならなかった。
次に、splitを使うのをやめて、文字単位にlineを見ていき、スペースを見つけたら、間の部分文字列をsubstringするようにしたところ、splitと比較して半分程度の処理時間になった。以下、その部分のコード。
int offset = 0;
int start = offset;
while(line.charAt(offset) != ' ')
offset++;
int end = offset;
String target = line.substring(start, end);
ArrayList features = new ArrayList();
while(true) {
start = ++offset;
if (offset >= line.length())
break;
while(offset < line.length() && line.charAt(offset) != ' ')
offset++;
end = offset;
features.add(line.substring(start,end));
}
これでもまだ結構遅いのだが、 ここで時間を費やすわけにもいかないので、これで我慢することに。

