1

リストまたは numpy 配列にロードする非常に大きなデータ .dat ファイルがあります。ファイルには値の列が含まれており、最後の列は値を配列にロードする回数の乗数です。したがって、それをロードするときは、それを考慮して 2 番目のサブループを実行する必要があります。これは、場合によっては 1Gb をはるかに超えていたため、ファイルの合計サイズを小さくするために行われました。

numpy の事前に割り当てられたゼロ配列と単純なリストへの追加を使用していくつかのテストを行ったところ、追加の方が高速であることがわかりました。ただし、多数の投稿では、これは当てはまりません。ボトルネックはどこ?

    if True:
            startTime1 = time.clock()
            ## Numpy way to load up the data
            dataAry = np.zeros(TotalSamples)
            multiColAry = np.loadtxt(filename,skiprows=2,                           usecols=(columNum,lastColLoc))
            latestLoc = 0               
            for i in range(0,multiColAry.shape[0]):
                curData = multiColAry[i][0]
                timesBeenHere = int(multiColAry[i][2])
                for j in range(0,timesBeenHere):
                    dataAry[latestLoc] = curData                        
                    latestLoc+=1
            endTime1 = time.clock()
            totalTime = (endTime1-startTime1) # in seconds
            totalTimeString = timeString(totalTime)

        if True:
            #Old string parsing directly version
            startTime1 = time.clock()
            totalAccepted = 0
            f = open(filename,'r')
            dataAry = []
            line = 'asdf'
            while line!='':
                line = f.readline()
                if line!='':
                    dataLineCols = line.split()
                    dataValue = float(dataLineCols[columNum])
                    timesBeenHere = float(dataLineCols[-1])
                    for j in range(0,int(timesBeenHere)):
                        totalAccepted+=1
                        dataAry.append(dataValue)

            f.close()
            endTime1 = time.clock()
            totalTime = (endTime1-startTime1) # in seconds
            totalTimeString = timeString(totalTime)

コメント/提案をありがとう。

4

2 に答える 2

3

大きなゼロ配列を割り当てるには、大量のメモリをクリアする必要があるため、np.zeros で十分な大きさの配列を割り当てると、ページングが開始され、その呼び出しだけでプロセッサ キャッシュが確実にクリアされます。引数を使用して配列を割り当てても、配列ndarray(shape=(TotalSamples))は初期化されません。

次に、コードの最初のバージョンは、2 番目のバージョンがオンザフライで破棄するデータを追跡します。入力ファイルは明らかに数値のテキスト テーブルであり、最初の実装では列 0 と 2 が読み取られ、2 番目の実装では列 columnNum と -1 が読み取られます。これは、最初のバージョンが multiColAry が存在する限りメモリに保持する少なくとも 1 つの列を示しますが、2 番目のバージョンは次の行に移動するときにそれを破棄します。を使えば回避できますloadtxt(filename, usecols=(0,2))

ちなみに、ファイルが iterableであることをご存知でしたか? あなたのトリッキーな組み合わせ usingf.readline()と空の文字列のテストは、に置き換えることができますfor line in f:(空の文字列は false の場合、空の文字列と比較する必要はありません)。

また、numpy を使用している間はfor j in range(0,timesBeenHere):、Python のように内部ループを記述しないことをお勧めします。dataAry[latestLoc:latestLoc+timesBeenHere].fill(curData)またはを使用して再構築できますdataAry.append(multiEntries)。multiEntries の作成はそれ自体が 1 つの章であり、np.ones(timesBeenHere)*dataValue(伝統的ですが、キャッシュに収まらない場合はコストがかかります) またはnp.linspace(dataValue,dataValue,timesBeenHere). ndarray.put()も参照してください。

... 2 番目のバージョンが配列ではなくリストを作成することに今まで気づきませんでした。これは、データが後でどのように使用されるかという問題を思い起こさせます。今のところ、目に見えないコードで numpy 配列に変換されていると仮定します。

最終的には、次のようなものがおそらく最も便利になると思います。

dataAry = np.empty(TotalSamples)
i=0
for line in open(filename):
  words=line.split()
  repeats=int(words[2])
  value=float(words[0])
  np.copyto(dataAry[i:i+repeats],value)
  i+=repeats

numpy を使用してインデックスを計算する方法もあるはずですが、このように手動で解析し、loadtxt を使用して完全なテーブル (興味深い列) をロードするのにどちらがコストがかかるかはわかりません。

于 2013-08-19T07:14:18.650 に答える
1

for ループを に置き換えることができると思いますnumpy.repeat(multiColAry[:, 0], multiColAry[:, 2])。これはかなり大きな違いになるはずです。

また、numpy 配列は通常、array[i, j, k]ではなくインデックスですarray[i][j][k]。この場合、結果は同じになるはずですが、場合によっては、後者が実際に間違った結果をもたらすことがあります。どちらの場合も、前者の方が高速です。

最後に、numpy でプログラミングする場合、要素単位の操作と for ループは推奨されません。代わりに、配列単位の、または「ベクトル化された」コードが推奨されます。このパラダイムでは、プログラムを配列の要素に対する操作ではなく、配列の操作として表現します。Numpy は、この種のプログラミング用に最適化されています。これは、C や Java などの低レベル言語からやってきた人にはなじみのないものですが、Matlab や IDL などの他の科学プログラミング言語と似ています。

于 2013-08-19T06:29:29.590 に答える