2

タブで区切られたdoubleの配列を含む最大100万のテキストファイルを生成しています(これらは研究用のシミュレーションです)。以下の出力例。100万個のテキストファイルごとに最大5TBになると予想されますが、これは許容できません。だから私は圧縮する必要があります。

ただし、私のデータ分析はすべてmatlabで行われます。そして、すべてのmatlabスクリプトは、これらの数百万のテキストファイルすべてにアクセスする必要があります。HDスペースが不足しているため、C++を使用して100万個全体を解凍してからmatlabスクリプトを実行することはできません。だから私の質問は、C ++で圧縮を記述してmatlabで読み取ることができるように、テキストファイルのサイズを縮小する非常にシンプルで実装が簡単なアルゴリズムやその他の方法はありますか?

サンプルテキストファイル

0.0220874   0.00297818  0.000285954 1.70E-05    1.52E-07
0.0542912   0.00880725  0.000892849 6.94E-05    4.51E-06
0.0848582   0.0159799   0.00185915  0.000136578 7.16E-06
0.100415    0.0220033   0.00288016  0.000250445 1.38E-05
0.101889    0.0250725   0.00353148  0.000297856 2.34E-05
0.0942061   0.0256  0.00393893  0.000387219 3.01E-05
0.0812377   0.0238492   0.00392418  0.000418365 4.09E-05
0.0645259   0.0206528   0.00372185  0.000419891 3.23E-05
0.0487525   0.017065    0.00313825  0.00037539  3.68E-05

重要な場合は、完全なテキストファイルは同時確率質量関数を表すため、合計は1になります。可逆圧縮が必要です。

更新これは、C ++でバイナリを記述してMatlabで読み取るための、非常に基本的な説明を含むIDIOTSガイドです。

小さな配列をバイナリファイルに書き込むためのC++コード。

#include <iostream>
using namespace std;
int main()
{
    float writefloat;
    const int rows=2;
    const int cols=3;
    float JPDF[rows][cols];
    JPDF[0][0]=.19493;
    JPDF[0][1]=.111593;
    JPDF[0][2]=.78135;
    JPDF[1][0]=.33333;
    JPDF[1][1]=.151535;
    JPDF[1][2]=.591355;

JPDFは、6つの値を保存するfloat型の配列です。これは2x3アレイです。

    FILE * out_file;
    out_file = fopen ( "test.bin" , "wb" );

正直なところ、最初の行が何をしているのかよくわかりません。out_fileという名前のFILE型のポインタを作成しているようです。2行目のfopenは、書き込み用の新しいファイル(2番目のパラメーターの「w」)を作成し、それをバイナリファイル(wbの「b」)にすることを示しています。

    fwrite(&rows,sizeof(int),1,out_file);
    fwrite(&cols,sizeof(int),1,out_file);

ここでは、配列のサイズ(#行、#列)をエンコードします。変数自体ではなく、変数の行と列への参照をfwriteすることに注意してください(&はrefによるものです)。2番目のパラメーターは、書き込むバイト数を示します。行と列はどちらもintなので、sizeof(int)を使用します。「1」はこれを1回行うと言います。おもう。そして、out_fileは、書き込み先のファイルへのポインターです。

    for (int i=0; i<3; i++)
    {
        for (int j=0; j<2; j++)
        {
            writefloat=JPDF[j][i];
            fwrite (&writefloat , sizeof(float), 1, out_file);
        }
    }
    fclose (out_file);

return 0;
}

次に、配列を反復処理し、各値をバイト単位でファイルに書き込みます。インデックス付けは、内側のループの列全体ではなく、各列を繰り返し処理しているという点で、少し後ろ向きです。その理由はすぐにわかります。繰り返しになりますが、writefloatへの参照を記述しています。これは、各反復で現在の配列要素の値を取ります。各配列要素はfloatであるため、ここではsizeof(int)の代わりにsizeof(float)を使用しています。

信じられないほど、ばかげて明確にするために、これが私が今作成したファイルについてどう思うかを示す図です。

[4 bytes: rows][4 bytes: cols][4 bytes: JPDF[0][0]][4 bytes: JPDF[1][0]] ...
[4 bytes: JPDF[1][2]]

..バイトの各チャンクはバイナリ(0と1)で書き込まれます。

MATLABで解釈するには:

FID=fopen('test.bin');
sizes=fread(FID,2,'int')

FIDは、ここではポインタのように機能します。密かに、それはおそらくポインタです。次に、C++フレッドと非常によく似た動作をするフレッドを使用します。FIDは、ファイルへの「ポインタ」です。'int'は、各チャンクに含まれるバイト数を関数に通知します。つまりsizes=fread(FID,2,'int')、'FIDをバイナリで開き、サイズINTバイトの2つのチャンクを読み取り、2つの要素をベクトル形式で返します。ここで、sizes(1)= rows、sizes(2)=colsです。

s=fread(FID,[sizes(1) sizes(2)],'float')

次の部分は元々私には完全には明確ではありませんでした。行/列情報を含むバイナリの「ヘッダー」をスキップするようにfreadに指示する必要があると思いました。ただし、中断した場所へのポインタを密かに保持します。そこで、配列の次元がわかっているという事実を利用して、残りのバイナリファイルを空にします。2番目のパラメーター[M、N]は[rows、cols]ですが、freadは「列順」で読み取るため、配列データを列順で書き込んだことに注意してください。

1つ*は、C ++プログラムのアーキテクチャがmatlabと一致している場合(たとえば、両方が64ビット、または両方が32ビット)にのみ、matlabコード'int'および'float'を使用できると思います。しかし、これについてはよくわかりません。

出力は次のとおりです。

sizes =

     2
     3

s =

         0.194930002093315         0.111593000590801         0.781350016593933
         0.333330005407333         0.151535004377365          0.59135502576828
4

3 に答える 3

3

数値あたり4バイトよりも優れた処理を行うには、これらの数値が必要な精度を決定する必要があります。それらは確率であるため、すべて[0,1]にあります。精度を2の累乗として指定できる必要があります。たとえば、実際の2n以内の各確率を知る必要があります。次に、各確率に2 nを掛けて、最も近い整数に丸め、その整数にnビットだけを格納できます。

最悪の場合、確率ごとに6桁を超える数字が表示されないことがわかります。したがって、小数点を超える一定の固定精度を想定して、20ビットでコーディングできます。各確率に220(1048576)を掛け、丸めて、ファイルに20ビットを書き込みます。各確率は2.5バイトかかります。これは、float値の4バイトよりも小さいです。

また、どちらの方法も、サンプルファイルの値あたりの平均11.3バイトよりもはるかに小さくなります。

データ内の既知のパターンを利用できる場合でも、それよりも優れた圧縮を得ることができます。あると仮定します。あなたの例では、各行で値が各ステップで何らかの係数で下がっています。それが実際のものであり、例の生成のアーティファクトだけではない場合は、各サンプルに対して連続して使用するビット数を減らすことができます。また、最初のサンプルが実際には常に1/8未満である場合、それらのビットは常にゼロになるため、上位3ビットをそのサンプルから削除できます。2番目の列が常に1/32未満の場合は、最初の5ビットをそれらすべてから削除できます。等々。例の大きさがすべてのデータセットで最大であると仮定し(明らかに真実ではありませんが、これを例として使用します)、小数点以下6桁が必要であると仮定します。

そして、圧縮の最後のsmidgenについては、値が1に加算されるため、最後の値を格納する必要はありません。

于 2012-09-11T04:44:27.087 に答える
2

Matlabはバイナリファイルを読み取ることができます。ファイルをテキストではなくバイナリとして保存してみませんか?

各数値をとして保存するfloatと、必要なのは4バイトだけです(32ビットLinuxを実行している場合)。doubleを使用できますが、完全なdouble解像度を使用していないようです。現在のスキームでは、各桁のすべての数値が1バイトのスペースを消費します。すべての数字は簡単に4文字以上の長さで、10文字にもなるものもあります。この変更を実装すると、ファイルサイズが50%以上削減されます。

さらに、圧縮サポートし、matlabでサポートされているHDF5 (詳細はこちら)のようなより洗練されたデータ形式の使用を検討することもできます。

更新

C++でバイナリファイルを書く方法のはたくさんあります。グーグルで検索してください。さらに、Matlabでバイナリファイルを読み込むには、freadを使用するだけです。

数値をASCIIと2進数で表すことの違いは、実に単純です。すべてのファイルはバイナリを使用して書き込まれますが、違いはその情報の解釈方法にあります。テキストファイルは通常ASCIIを使用して読み取られます。これにより、8ビットの単語と文字の間の適切なマッピングが提供されます。あなたが持っているような文字列を見るとき"255"、各バイトが配列内の文字をエンコードするバイトの配列です。ただし、数値を格納する場合、異なるバイトを使用して各桁を格納するのは非常に無駄です。1バイトには、0〜255の値を格納できます。"255"では、1バイトを使用して値を格納できるのに、なぜ3バイトを使用して文字列を格納するのでしょうか255

于 2012-09-10T20:00:46.097 に答える
0

zlibなどの標準ライブラリを使用して、いつでも先に進んですべてを圧縮できます。その後、管理可能なチャンクにデータを解凍するC++で記述されたカスタムdllを使用できます。つまり、基本的に:データ-> Zip-> Dll(LoadLibraryを介してMatlabによってロードされます)-> Matlab

于 2012-09-10T20:02:14.167 に答える