1

csv ファイルとして保存された特徴ベクトルの巨大なファイル (1.2GB) があります。行を確認するために、一度に 1 バッチずつ、巨大なファイルからメモリに行のバッチをロードする Python クラスを作成しました。

このクラスが、batch_size の完全な行 (batch_size=10,000 とします) のバッチを取得するためにファイルのどこを正確に読み取るかを知るために、巨大なファイルを初めて使用するときに、このクラスはファイル全体を 1 回調べ、登録します。各行のオフセットを取得し、これらのオフセットを補助ファイルに保存して、後で「file.seek(starting_offset); batch = file.read(num_bytes)」で行の次のバッチを読み取ることができるようにします。

まず、次の方法でライン オフセットの登録を実装しました。

    offset = 0;
    line_offsets = [];
    for line in self.fid:
        line_offsets.append(offset);
        offset += len(line); 

そして、giant_file1でうまくいきました。

しかし、その後、作成したこのクラスの助けを借りて、これらの機能を処理し、giant_file2 (正規化された機能を使用) を作成しました。次に、giant_file2 から行のバッチを読み込もうとしたときに、読み取ったバッチ文字列が適切な場所になかったため、失敗しました (たとえば、"-00\n15.467e-04 のようなものを読み取っています... " の代わりに "15.467e-04,...\n")。

そこで、ラインオフセット計算部分を次のように変更してみました。

    offset = 0;
    line_offsets = [];
    while True:
        line = self.fid.readline();

        if (len(line) <= 0):
            break;

        line_offsets.append(offset);
        offset = self.fid.tell();

主な変更点は、オフセット I レジスタが行の累積長ではなく、fid.tell() の結果から取得されることです。

このバージョンは、giant_file2 ではうまく機能しましたが、giant_file1 では失敗しました。

さらに調べてみると、関数 seek()、tell()、および read() が互いに矛盾していると感じました。例えば:

fid = file('giant_file1.csv');
fid.readline();
>>>'0.089,169.039,10.375,-30.838,59.171,-50.867,13.968,1.599,-26.718,0.507,-8.967,-8.736,\n'
fid.tell();
>>>67L
fid.readline();
>>>'15.375,91.43,15.754,-147.691,54.234,54.478,-0.435,32.364,4.64,29.479,4.835,-16.697,\n'
fid.seek(67);
fid.tell();
>>>67L
fid.readline();
>>>'507,-8.967,-8.736,\n'

ここにはいくつかの矛盾があります: 私が (fid.tell() に従って) バイト 67 に配置されたとき、一度読み取られた行は 1 つのことであり、2 回目には (再び fid.tell() が私がバイトに配置されていると報告したとき) 67) 読み取られる行が異なります。

tell() と seek() を信頼して、目的の行の先頭から読み取る目的の場所に移動することはできません。一方、(giant_file1 を使用して)文字列の長さを seek() の参照として使用すると、正しい位置が得られます。

fid.seek(0);
line = fid.readline();
fid.tell();
>>>87L
len(line);
>>>86
fid.seek(86);
fid.readline();
>>>'15.375,91.43,15.754,-147.691,54.234,54.478,-0.435,32.364,4.64,29.479,4.835,-16.697,\n'

それで、何が起こっているのですか?

私が考えることができる Giant_file1 と Giant_file2 の唯一の違いは、giant_file1 では値が 10 進数のドット (例: -0.435) で書き込まれ、giant_file2 では値がすべて科学形式 (例: -4.350e-01) であるということです。それらのいずれもがユニコードでコーディングされているとは思いません (単純な file.read() で読み取った文字列は読み取り可能なように見えるため、そう思います。どうすれば確認できますか?)。

説明、原因のアイデア、考えられる解決策 (または回避策) とともに、ご協力をお願いいたします。

よなたん、ありがとう。

4

2 に答える 2

2

改行の問題があると思います。Giant_file1.csv の行が \n または \r で終わっているかどうかを確認します\n ファイルをテキスト モードで開くと、ファイルは \n で終わる行のみを返し、冗長な \r を破棄します。したがって、返された行の長さを見ると、実際のファイル位置から 1 ずれています (\n だけでなく、\r\n も消費しています)。もちろん、これらのエラーは、より多くの行を読むにつれて蓄積されます。

解決策は、代わりにバイナリ モードでファイルを開くことです。このモードでは、\r\n -> \n の削減はないため、行の長さの集計は、ファイルの tell( ) クエリと一貫したままになります。

簡単に修正できるので、これで解決することを願っています。:) あなたのプロジェクトと幸せなコーディングで頑張ってください!

于 2012-06-14T16:19:17.253 に答える
0

私は過去に同様のことをしなければならず、linecacheと呼ばれる標準ライブラリの何かに出くわしました。あなたもそれを調べたいと思うかもしれません。

http://docs.python.org/library/linecache.html

于 2012-06-14T16:14:22.623 に答える