2016-02-23 7 views
5

Ich habe eine SQL-Tabelle, die ich als Pandas Datenrahmen lesen kann, das die folgende Struktur aufweist:Wie kann ein SparseDataFrame effizient aus einer langen Tabelle erstellt werden?

user_id value 
1   100 
1   200 
2   100 
4   200 

Es ist eine Darstellung einer Matrix, für die alle Werte sind 1 oder 0. Die dichte Darstellung dieser Matrix würde wie folgt aussehen:

100 200 
1 1 1 
2 1 0 
4 0 1 

Normalerweise diese Umwandlung tun Sie schwenken können, aber in meinem Fall mit Dutzenden oder Hunderten von Millionen von Zeilen in der ersten Tabelle erhält man eine große dichte Matrix voll von Nullen, die teuer ist, um herumzuziehen. Sie können es in Sparse konvertieren, aber so weit zu kommen erfordert eine Menge Ressourcen.

Momentan arbeite ich an einer Lösung, um jeder user_id Zeilennummern zuzuordnen, sie zu sortieren und dann die 'value'-Spalte in SparseSeries aufzuteilen, bevor sie zu einem SparseDataFrame zusammengefügt werden. Gibt es einen besseren Weg?

+0

Ich habe nicht viel Diskussion über SparseSeries auf SO gesehen. Ich habe ein paar Fragen zum Hin- und Hertransfer zwischen diesen und den 'scipy'' spärlichen' Matrizen beantwortet. Mein Eindruck ist, dass die "spärliche" Struktur der Pandas noch in Entwicklung ist. – hpaulj

+0

Ich habe ein paar gefunden, wie Ihre Antwort hier http://stackoverflow.com/questions/34181494/populate-a-pandas-sparsedatareframe-from-a-scipy-sparse-coo-matrix Das Problem ist, dass es nicht scheint nicht zu skalieren. Im Moment versuche ich, eine CSC-Matrix von 40.000 x 15.000 zu konvertieren, die mehr als 30 Minuten läuft. –

Antwort

1

Ich kam zu einer Lösung, wenn auch eine etwas unvollkommene.

Man kann aus den Spalten eine Reihe von Pandas SparseSeries manuell erstellen, sie zu einem dict kombinieren und dann dieses dict in einen DataFrame (kein SparseDataFrame) umwandeln. Casting als SparseDataFrame trifft derzeit auf einen unausgereiften Konstruktor, der das gesamte Objekt unabhängig von der Eingabe in eine dichte und dann in eine spärliche Form dekonstruiert. Der Aufbau von SparseSeries zu einem herkömmlichen DataFrame führt jedoch zu geringer Speicherdichte, erzeugt jedoch ein brauchbares und ansonsten vollständiges DataFrame-Objekt.

Hier ist eine Demonstration, wie es gemacht wird, geschrieben mehr für die Klarheit als für die Leistung. Ein Unterschied zu meiner eigenen Implementierung ist, dass ich das Diktat spärlicher Vektoren als ein Diktatverständnis anstelle einer Schleife erstelle.

import pandas 
import numpy 

df = pandas.DataFrame({'user_id':[1,2,1,4],'value':[100,100,200,200]}) 

# Get unique users and unique features 
num_rows = len(df['user_id'].unique()) 
num_features = len(df['value'].unique()) 
unique_users = df['user_id'].unique().copy() 
unique_features = df['value'].unique().copy() 
unique_users.sort() 
unique_features.sort() 


# assign each user_id to a row_number 
user_lookup = pandas.DataFrame({'uid':range(num_rows), 'user_id':unique_users}) 


vec_dict = {} 

# Create a sparse vector for each feature 
for i in range(num_features): 
    users_with_feature = df[df['value']==unique_features[i]]['user_id'] 

    uid_rows = user_lookup[user_lookup['user_id'].isin(users_with_feature)]['uid'] 

    vec = numpy.zeros(num_rows) 
    vec[uid_rows] = 1 

    sparse_vec = pandas.Series(vec).to_sparse(fill_value=0) 

    vec_dict[unique_features[i]] = sparse_vec 


my_pandas_frame = pandas.DataFrame(vec_dict)  
my_pandas_frame = my_pandas_frame.set_index(user_lookup['user_id']) 

Die Ergebnisse:

>>> my_pandas_frame 
     100 200 
user_id   
1   1 1 
2   1 0 
4   0 1 

>>> type(my_pandas_frame) 
<class 'pandas.core.frame.DataFrame'> 

>>> type(my_pandas_frame[100]) 
<class 'pandas.sparse.series.SparseSeries'> 

Complete, aber immer noch spärlich. Es gibt ein paar Vorbehalte, wenn Sie eine einfache Kopie oder Teilmenge nicht-in-Place machen, dann wird es sich selbst vergessen und versuchen, um zu dichten, aber für meine Zwecke bin ich ziemlich glücklich damit.

Verwandte Themen