Ich versuche, eine Liste von Transaktionsdaten zu einem 2d-Numpy-Array zusammenzufassen. Meine Daten sehen wie folgt aus:

person, product, date, val
A, x, 1/1/2013, 10
A, x, 1/10/2013, 10
B, x, 1/2/2013, 20
B, y, 1/4/2013, 15
A, y, 1/8/2013, 20
C, z, 2/12/2013, 40

Ich muss die Ausgabe in ein 2D-Array bringen, mit jeder Person als Zeile und dem Produkt als Spalten. Das Datum wird gelöscht und die Werte werden summiert.

Die Ausgabe sieht folgendermaßen aus:

[[20, 20, 0],[20, 15, 0],[0, 0, 40]]

Ich habe folgende Funktionen, aber sie sind sehr langsam (ich habe 110.000.000 Datensätze):

import numpy as np
from collections import defaultdict
from sklearn.feature_extraction import DictVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
import pandas as pd
from scipy import sparse
import os
import assoc


#read in data to a dict object - sums scripts by tuple (doc, drug)
dictObj = {}
rawData = 'subset.txt'
with open(rawData) as infile:
for line in infile:
    parts = line.split(',')
    key = (parts[0],parts[1])
    val = float(parts[3])
    if key in dictObj:
        dictObj[key] += val
    else:
        dictObj[key] = val
infile.close()

print "stage 1 done"
#get the number of doctors and the number of drugs
keys =  dictObj.keys()
docs = list(set([x[0] for x in keys]))
drugs = sorted(list(set([x[1] for x in keys])))

#read through the dict and build out a 2d numpy array 
docC = 0
mat = np.empty([len(docs),len(drugs)])
for doc in docs:
drugC = 0
for drug in drugs:
    key = (doc,drug)
    if key in dictObj:
        mat[(docC,drugC)] = dictObj[(key)]
            else:
        mat[(docC,drugC)] = 0
    drugC += 1
docC+=1

Ich hatte zuvor einen ähnlichen Thread gepostet (hier - Umwandlung von Transaktionen in ein numpy-Array ) und alle antworteten, dass Pandas der richtige Weg sei, aber ich kann die Pandas-Ausgabe für mein ganzes Leben nicht in das richtige Format bringen. Ich kann keinen Pandas-Datenrahmen an die von mir verwendeten kmeans- oder apriori-Algorithmen übergeben, und unabhängig davon, wie ich den Datenrahmen anordne, bringt mich der df.values zu einer MultiIndex-Reihe (die bis zu einem langen Array vereinfacht!). Alle Hinweise wäre sehr dankbar!

1
flyingmeatball 25 Nov. 2013 im 08:11

4 Antworten

Beste Antwort

Ich könnte so etwas tun

>>> df = pd.read_csv("trans.csv", skipinitialspace=True)
>>> w = df.groupby(["person", "product"])["val"].sum().reset_index()
>>> w
  person product  val
0      A       x   20
1      A       y   20
2      B       x   20
3      B       y   15
4      C       z   40
>>> w.pivot("person", "product").fillna(0)
         val        
product    x   y   z
person              
A         20  20   0
B         20  15   0
C          0   0  40
>>> w.pivot("person", "product").fillna(0).values
array([[ 20.,  20.,   0.],
       [ 20.,  15.,   0.],
       [  0.,   0.,  40.]])

Welches IIUC ist das 2-D-Array, nach dem Sie suchen? Beachten Sie, dass Sie nicht die gesamte Datei auf einmal in den Speicher lesen müssen, sondern den Parameter chunksize verwenden können (siehe die Dokumente hier) und sammeln Sie Ihre Tabelle Stück für Stück.

4
DSM 25 Nov. 2013 im 05:48

Basierend auf dem Ende Ihres Problems scheint es, dass Sie nur einen Pandas DataFrame zu einem Numpy array bringen müssen. So machen Sie das:

#df is your DataFrame
data = np.asarray(df)

Jetzt sollten Sie also kein Problem mit Pandas haben!

0
Ryan Saxe 25 Nov. 2013 im 04:29

Wenn ich mir Ihren Code und die Größe Ihrer Daten anschaue, sollte ich denken, dass es sich um sehr langsame 110.000.000 Datensätze handelt, die vermutlich aus einer Zeichenfolge (Arzt), einer langen Zeichenfolge (Droge), einem Datum (gelöscht) und einem Wert bestehen, der a ist Float-Wert. Nehmen wir an, 20 Zeichen für den Arzt (möglicherweise nicht genug) und 30 für das Medikament (wahrscheinlich nicht genug), 4 Bytes für einen Wert von 5,5 Gi vor Overheads. Dann duplizieren Sie ihn in a 2D-Matrix.

Sofern Sie nicht auf einem Mainframe oder einem Cluster ausgeführt werden, würde ich dringend empfehlen, die Umstrukturierung entweder beim Lesen oder beim Einlesen von Stufe 1 in eine Datenbank vorzunehmen.

Sie können auch die Möglichkeit prüfen, pytables zu verwenden, wenn Pandas nicht für Sie arbeitet.

0
Steve Barnes 25 Nov. 2013 im 05:12

recfromcsv (oder recfromtxt) lädt Ihre Daten in ein Datensatzarray

data=np.recfromcsv('stack20179393.txt')

rec.array([('A', ' x', ' 1/1/2013', 10), ('A', ' x', ' 1/10/2013', 10),
       ('B', ' x', ' 1/2/2013', 20), ('B', ' y', ' 1/4/2013', 15),
       ('A', ' y', ' 1/8/2013', 20), ('C', ' z', ' 2/12/2013', 40)], 
      dtype=[('person', 'S1'), ('product', 'S2'), ('date', 'S10'), ('val', '<i4')])

data.person
# chararray((['A', 'A', 'B', 'B', 'A', 'C'], dtype='|S1')

data.val
# array([10, 10, 20, 15, 20, 40])

Da person in beliebiger Reihenfolge und mit unterschiedlicher Frequenz (3A, 2B, 1C) auftreten kann, können Sie dies nicht ohne weiteres in ein 2D-Array umwandeln. Daher müssen Sie möglicherweise noch die Datensätze durchlaufen und Werte in einem Wörterbuch sammeln. Ich würde ein collections.defaultdict empfehlen. itertools.groupby ist auch ein praktisches Werkzeug zum Sammeln von Werten in Gruppen. Es würde jedoch das Sortieren Ihrer Datensätze erfordern.

Mit einem defaultdict

from collections import defaultdict
dd = defaultdict(list)
for row in data:
    dd[row[0]].append(row[-1])
print dd
# defaultdict(<type 'list'>, {'A': [10, 10, 20], 'C': [40], 'B': [20, 15]})
d = {}
for k,v in dd.items(): d[k] = sum(v)
print d
# {'A': 40, 'B': 35, 'C': 40}

Oder

dd = defaultdict(float)
for row in data:
    dd[row[0]].append(row[-1])
print dd
defaultdict(<type 'float'>, {'A': 40.0, 'C': 40.0, 'B': 35.0})

Ein spärlicher Ansatz nutzt die Art und Weise, wie csr_matrix wiederholte Indizes summiert

from scipy import sparse  
row=np.array([ord(a) for a in data.person])-65
col=np.zeros(row.shape)
sparse.csr_matrix((data.val,(row,col))).T.A
# array([[40, 35, 40]])
1
hpaulj 25 Nov. 2013 im 06:08