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));
}

これでもまだ結構遅いのだが、 ここで時間を費やすわけにもいかないので、これで我慢することに。