word2vecでテキストモードで出力した結果を、binaryモードでの出力結果にPythonで変換したい


word2vecというC言語のプログラムで単語情報を多次元ベクトル化する際に出力されたテキストファイルが手元にあります。
次のコードの`else`の文章で出力されたものです。

[code]

    for (a = 0; a < vocab_size; a++) {
        fprintf(fo, "%s ", vocab[a].word);
        if (binary) for (b = 0; b < layer1_size; b++) fwrite(&syn0[a * layer1_size + b], sizeof(real), 1, fo);
        else for (b = 0; b < layer1_size; b++) fprintf(fo, "%lf ", syn0[a * layer1_size + b]);
        fprintf(fo, "\n");
    } 
    
[/code]

[ソース](https://code.google.com/p/word2vec/source/browse/trunk/word2vec.c?r=41#562)

`if(binary)`の`else`の方で出力されたベクトルファイルが手元にありますが、その後`if(binary)`の方で出力されたファイルが必要になりました。
ファイルの中身は以下のようになっています。

<単語><スペース><数値><スペース><数値><スペース>

今書いているコードは次のようです。

* * *
[code]

    # -*- coding: utf-8 -*-
    import sys
    import struct
    #テキストベクトルデータの読み込み
    title = sys.argv[1:]
    i = 0
    fp = open('binaryVec.bin','wb')
    odata = ''
    
    for line in open(title[0]):
        chars = list(map(hex, map(ord, line)))
        print line
        print chars
        odata += struct.pack('s',chars)
    fp.write(odata)
    fp.close()
    
[/code]

* * *

データが大きいため効率のよい変換プログラムがあると良いです。

よろしくお願いします。

文字コードはテキストもpythonプログラムもutf-8を使用しています。 テキストベクトルの一部を載せます。

* * *
[code]

    多い 0.205392 -0.245325 0.240983 0.533283 0.087030 -0.198588 0.395930 0.331363 -0.212541 0.383991 0.391010 0.140275 0.178444 -0.331018 -0.303288 -0.168199 0.227571 -0.133808 -0.583108 -0.004697 -0.068092 -0.057790 0.199027 -0.443492 0.006436 -0.098054 0.221261 -0.413350 -0.274608 -0.266688 0.198686 -0.347939 -0.272542 -0.005835 0.195161 0.255993 -0.435598 0.083113 -0.061061 -0.602378 0.244479 -0.090220 0.053294 0.225144 0.084010 0.150409 -0.078552 0.184509 0.068329 -0.045706 -0.037543 -0.347720 0.363027 -0.251563 -0.293957 0.201196 -0.062295 -0.102561 -0.093551 -0.212615 -0.000832 -0.071720 -0.404002 0.124075 0.283026 0.108321 -0.177551 -0.681601 0.051641 0.324483 0.078215 -0.282532 0.313095 -0.250052 -0.872598 0.035464 -0.266010 -0.389549 -0.120772 0.243341 -0.255850 0.044791 -0.151454 0.159697 -0.320580 -0.663053 0.167484 0.361221 0.185417 0.342295 0.889678 -0.302563 0.289107 -0.102576 0.263508 -0.012531 0.298031 -0.515175 -0.127688 -0.260832 
    可能 0.108951 -0.258674 0.629972 0.311664 -0.077146 -0.124886 -0.096122 0.011065 -0.309206 0.867305 0.633274 0.006818 0.267469 -0.119733 0.521135 -0.064882 -0.018288 -0.010180 -0.729432 -0.028794 -0.299309 -0.141295 0.623287 -0.417451 0.007524 0.092700 0.215297 -0.506577 -0.271396 -0.184997 -0.198890 -0.349385 -0.178141 0.230034 0.141386 0.193577 0.223477 0.341060 -0.165425 -0.397568 0.020117 0.154478 0.313013 0.013119 0.172535 0.277345 -0.347708 0.686350 -0.181311 0.344334 -0.119619 -0.433781 0.426598 -0.588145 -0.155892 0.060375 0.023153 0.062405 0.193624 -0.262037 0.259582 0.140148 -0.697635 -0.071356 0.526129 -0.122136 -0.622095 -0.284502 0.130523 0.427264 0.295688 -0.340023 0.310286 -0.043206 -0.201572 -0.319277 0.377619 0.101276 -0.208789 0.099027 0.056171 -0.081605 -0.523134 0.181316 -0.018701 -0.517925 -0.108934 0.514148 0.504512 0.430822 0.481150 -0.165199 0.472695 0.080885 -0.141376 0.324130 0.128912 -0.219854 -0.160605 -0.224664 
    
[/code]




Pythonで数値をバイナリに吐き出す方法を2つ説明したいと思います。
まず、何らかの方法でデータを得て、以下のような形でfloatのリストで持っているとします。

[code]

    data = [0.1, 0.2, 0.3]
    
[/code]

## struct.pack を使う方法

[code]

    import struct
    with open('binaryVec.bin', 'wb') as f:
        for x in data:
            four_bytes = struct.pack('f', x)
            f.write(four_bytes)
    
[/code]

  * [packのformat characterの種類と意味](http://docs.python.org/2/library/struct.html#format-characters)

## numpy arrray の tofile メソッドを使う方法

上記の方法はforループを使うので、スピードが遅いです。 tofileメッソッドを使うと一気にバイナリファイルに書き出すことができます。

[code]

    import numpy as np
    X = np.array(data, dtype='float32')
    X.tofile('binaryVec.bin')
    
[/code]

今の場合、この2つの方法で作られた`binaryVec.bin`ファイルは全く同じものになります。 (32bit floatで保存されている)

* * *

補足: テキストファイルの読み出しについて

`Vec.txt`が以下のような形式で与えられているとします。(エントリがスペースで区切られている)

[code]

    日本語 0.1 0.2 0.3 
    
[/code]

このファイルをparseする1つの簡単な方法としては、`csv.reader`を使うことです。

[code]

    import csv
    with open('Vec.txt', 'rt') as g:
        for row in csv.reader(g, delimiter=' '):  # 入力ファイルは一行しか無いので、これでrowに全データが入る。
            pass
    data = map(float, row[1:])  # これで、data = [0.1, 0.2, 0.3] になる。
    
[/code]

