Frage

Ich habe eine Reihe von CSV-Datensätzen mit einer Größe von jeweils etwa 10 GB.Ich möchte aus ihren Spalten Histogramme erstellen.Aber es scheint, dass die einzige Möglichkeit, dies in Numpy zu tun, darin besteht, zuerst die gesamte Spalte in ein Numpy-Array zu laden und dann aufzurufen numpy.histogram auf diesem Array.Dies verbraucht unnötig viel Speicher.

Unterstützt Numpy Online-Binning?Ich hoffe auf etwas, das meine CSV-Datei Zeile für Zeile durchläuft und die Werte beim Lesen in Bins einordnet.Auf diese Weise befindet sich jeweils höchstens eine Zeile im Speicher.

Es wäre nicht schwer, mein eigenes Rad zu drehen, aber ich frage mich, ob jemand dieses Rad bereits erfunden hat.

War es hilfreich?

Lösung

Wie Sie sagten, ist es nicht so schwer, Ihre eigene Rolle. Hier finden Sie die Behälter selbst einrichten müssen und wieder zu verwenden, wie Sie Iterierte über die Datei. Im Folgenden soll ein anständiger Ausgangspunkt sein:

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

Ich vermute, Leistung wird ein Thema mit so großen Dateien, und der Overhead in jeder Zeile Histogramm Aufruf möglicherweise zu langsam. @ Dougs Vorschlag eines Generators scheint wie ein guter Weg, um Adresse, dass Problem dar.

Andere Tipps

Hier ist eine Möglichkeit, Ihre Werte direkt zu klassifizieren:

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“ ist ein Indexarray, das den Index des Bins enthält, zu dem jeder Wert in „column_of_values“ gehört.

'bincount' gibt Ihnen (offensichtlich) die Anzahl der Bins:

NP.bincount(binned_values)

Angesichts der Größe Ihres Datensatzes könnte es nützlich sein, Numpys „loadtxt“ zum Erstellen eines Generators zu verwenden:

data_array = NP.loadtxt(data_file.txt, delimiter=",")
def fnx() :
  for i in range(0, data_array.shape[1]) :
    yield dx[:,i]

Binning mit einem Fenwick Baum (sehr große Datenmenge; Perzentil Grenzen erforderlich)

Ich bin eine zweite Antwort auf die gleiche Frage veröffentlichen, da dieser Ansatz sehr unterschiedlich ist, und Adressen verschiedene Themen.

Was ist, wenn Sie eine sehr große Datenmenge (in Milliarden Samples) haben, und Sie nicht wissen, vor der Zeit, wo Ihre Grenzen sind sein sollen? Zum Beispiel, vielleicht wollen Sie sind Dinge in zu Quartile oder Dezil auf.

Für kleine Datensätze, die Antwort ist einfach: Laden Sie die Daten in ein Array, dann sortieren, dann Perzentil die Werte zu einem bestimmten abzulesen durch Springen auf den Index, dass Prozentsatz des Weges durch das Feld

.

Bei großen Datenmengen, wo die Speichergröße des Arrays zu halten, nicht praktikabel ist (nicht die Zeit zu sortieren ganz zu schweigen) ... dann einen Fenwick Baum zu prüfen, mit, auch bekannt als ein „Binary Indexed Tree“.

ich denke, diese nur Arbeit für positive Integer-Daten, so dass Sie zumindest Notwendigkeit genug über Ihr Datensatz Verschiebung kennen (und möglicherweise Skala) Ihre Daten, bevor Sie sie in Fenwick Baum tabellarisieren.

Ich habe dies den Median eines 100 Milliarden Beispieldatensatz, in angemessener Zeit und sehr komfortable Speichergrenzen zu finden verwendet. (Man denkt Generatoren, die Dateien zu öffnen und zu lesen, wie pro meiner anderen Antwort;., Die nach wie vor sinnvoll ist)

Mehr über Fenwick Bäume:

Binning mit Generatoren ( großer Datensatz; feste Breite bins; float Daten )

Wenn Sie die Breite des gewünschten Bins im Voraus wissen - auch wenn es Hunderte oder Tausende von Eimern sind - dann denke ich, Ihre eigene Lösung rollt schnell wäre (beide zu schreiben und zu laufen). Hier einige Python, dass vorausgesetzt, dass Sie einen Iterator, dass Sie den nächsten Wert aus der Datei gibt:

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

Die Werte können Schwimmer sein, aber das ist vorausgesetzt, Sie eine ganze Zahl binwidth verwenden; Sie benötigen diese ein wenig zwicken, wenn Sie einen binwidth einiger Float-Wert verwendet werden soll.

Wie bei next_value_from_file(), wie bereits erwähnt, werden Sie wahrscheinlich wollen einen benutzerdefinierten Generator oder ein Objekt mit einer schreiben iter () Methode, um dies effizient zu tun. Der Pseudo-Code für eine solche Generator wäre dies:

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

Wenn eine bestimmte Zeile mehrere Werte hat, dann parse_the_value_from_the_line() machen entweder eine Liste zurückkehren oder sich ein Generator sein, und verwenden Sie diese Pseudo-Code:

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
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top