19

私はたくさんのcsvデータセットを持っており、それぞれのサイズは約10Gbです。それらの列からヒストグラムを生成したいと思います。しかし、numpyでこれを行う唯一の方法は、最初に列全体をnumpy配列にロードしてから、numpy.histogramその配列を呼び出すことだと思われます。これにより、不要な量のメモリが消費されます。

numpyはオンラインビニングをサポートしていますか?csvを1行ずつ繰り返し、値を読み取るときに値をビン化するものを期待しています。このようにして、一度に最大1行がメモリに保存されます。

私自身を転がすのは難しいことではないでしょうが、誰かがすでにこのホイールを発明したかどうか疑問に思います。

4

4 に答える 4

13

あなたが言ったように、あなた自身を転がすのはそれほど難しいことではありません。自分でビンを設定し、ファイルを反復処理するときにそれらを再利用する必要があります。以下はまともな出発点であるべきです:

import numpy as np
datamin = -5
datamax = 5
numbins = 20
mybins = np.linspace(datamin, datamax, numbins)
myhist = np.zeros(numbins-1, dtype='int32')
for i in range(100):
    d = np.random.randn(1000,1)
    htemp, jnk = np.histogram(d, mybins)
    myhist += htemp

このような大きなファイルではパフォーマンスが問題になると思います。また、各行でヒストグラムを呼び出すオーバーヘッドが遅すぎる可能性があります。 @dougのジェネレーターの提案は、その問題に対処するための良い方法のようです。

于 2010-03-17T19:43:20.737 に答える
6

値を直接ビニングする方法は次のとおりです。

import numpy as NP

column_of_values = NP.random.randint(10, 99, 10)

# set the bin values:
bins = NP.array([0.0, 20.0, 50.0, 75.0])

binned_values = NP.digitize(column_of_values, bins)

'binned_values'は、column_of_valuesの各値が属するビンのインデックスを含むインデックス配列です。

'bincount'は、(明らかに)ビンカウントを提供します。

NP.bincount(binned_values)

データセットのサイズを考えると、Numpyの「loadtxt」を使用してジェネレーターを構築すると便利な場合があります。

data_array = NP.loadtxt(data_file.txt, delimiter=",")
def fnx() :
  for i in range(0, data_array.shape[1]) :
    yield dx[:,i]
于 2010-03-17T18:53:27.930 に答える
5

フェニックツリーによるビニング (非常に大きなデータセット、パーセンタイル境界が必要)

このアプローチは非常に異なり、さまざまな問題に対処しているため、同じ質問に対する2番目の回答を投稿します。

非常に大きなデータセット(数十億のサンプル)があり、ビンの境界がどこにあるべきかを事前に知らない場合はどうなりますか?たとえば、四分位数または十分位数に物事をまとめたい場合があります。

小さなデータセットの場合、答えは簡単です。データを配列にロードし、並べ替えてから、配列の途中のインデックスにジャンプして、任意のパーセンタイルの値を読み取ります。

配列を保持するためのメモリサイズが実用的でない(ソートする時間は言うまでもなく)大規模なデータセットの場合...次に、「バイナリインデックスツリー」とも呼ばれるフェニックツリーの使用を検討してください。

これらは正の整数データに対してのみ機能すると思います。したがって、フェンウィックツリーでデータを集計する前に、少なくともデータセットについて十分に理解してデータをシフト(および場合によってはスケーリング)する必要があります。

私はこれを使用して、妥当な時間と非常に快適なメモリ制限で、1,000億のサンプルデータセットの中央値を見つけました。(私の他の答えのように、ジェネレーターを使用してファイルを開いて読み取ることを検討してください。それでも便利です。)

フェニックの木の詳細:

于 2013-12-29T15:43:14.127 に答える
2

ジェネレーターによるビニング大きなデータセット、固定幅のビン、フロートデータ

必要なビンの幅が事前にわかっている場合(バケットが数百または数千ある場合でも)、独自のソリューションのローリングは高速であると思います(書き込みと実行の両方)。ファイルから次の値を提供するイテレータがあることを前提としたPythonを次に示します。

from math import floor
binwidth = 20
counts = dict()
filename = "mydata.csv"
for val in next_value_from_file(filename):
   binname = int(floor(val/binwidth)*binwidth)
   if binname not in counts:
      counts[binname] = 0
   counts[binname] += 1
print counts

値はfloatにすることができますが、これは整数のbinwidthを使用することを前提としています。フロート値のbinwidthを使用する場合は、これを少し調整する必要があります。

については、前述のように、 iter()メソッドnext_value_from_file()を使用してカスタムジェネレーターまたはオブジェクトを作成することをお勧めします。これを効率的に実行します。このようなジェネレータの擬似コードは次のようになります。

def next_value_from_file(filename):
  f = open(filename)
  for line in f:
     # parse out from the line the value or values you need
     val = parse_the_value_from_the_line(line)
     yield val

特定の行に複数の値がある場合はparse_the_value_from_the_line()、リストを返すか、それ自体をジェネレーターにして、次の擬似コードを使用します。

def next_value_from_file(filename):
  f = open(filename)
  for line in f:
     for val in parse_the_values_from_the_line(line):
       yield val
于 2013-12-29T14:55:13.910 に答える