2015-06-27 15 views
11

Gibt es eine Möglichkeit, von pandas.SparseDataFrame in scipy.sparse.csr_matrix zu konvertieren, ohne eine dichte Matrix im Speicher zu erzeugen?Pandas sparse dataFrame in spärlicher Matrix, ohne eine dichte Matrix im Speicher zu erzeugen

scipy.sparse.csr_matrix(df.values) 

nicht funktioniert, da sie eine dichte Matrix erzeugt, die an die csr_matrix gegossen wird.

Vielen Dank im Voraus!

+0

dies Run umgekehrt? http://StackOverflow.com/questions/17818783/populate-a-pandas-sparsedataframe-from-a-scipy-sparse-matrix – JohnE

Antwort

0

Pandas docs spricht über eine experimentelle Umwandlung spärlich, SparseSeries.to_coo SciPy:

http://pandas-docs.github.io/pandas-docs-travis/sparse.html#interaction-with-scipy-sparse

================

bearbeiten - Dies ist eine spezielle Funktion aus einem Multiindex, kein Datenrahmen. Siehe dazu die anderen Antworten. Beachten Sie den Unterschied in den Daten.

============

Ab 0.20.0 gibt es einen sdf.to_coo() und ein Multiindex ss.to_coo(). Da eine dünn besetzte Matrix inhärent 2d ist, ist es sinnvoll, Multiindex für die (effektiv) 1d Datenspeicher zu verlangen. Während der Datenrahmen eine Tabelle oder ein 2D-Array darstellen kann.

Als ich zuerst auf diese Frage geantwortet habe, war dieses spärliche Datenrahmen-/Serienmerkmal experimentell (Juni 2015).

+0

Dies ist nur für 'MultiIndex'-ed' SparseSeries', nicht für einen DataFrame. –

+0

Wie @eleanora erwähnt, [das funktioniert jetzt tatsächlich] (http://pandas-docs.github.io/pandas-docs-travis/generated/pandas.SparseDataFrame.to_coo.html#pandas.SparseDataFrame.to_coo) (als der Version 0.20.0, veröffentlicht am 5. Mai 2017). 'sparse.csr_matrix (df.to_coo())' ist der Einzeiler, der den Trick macht. Vielleicht solltest du deine Antwort bearbeiten, um das klarzustellen? –

+0

Vielleicht sollten wir zum Thema als datiert schließen? – hpaulj

0

Hier ist eine Lösung, die die dünn besetzte Matrix Spalte für Spalte füllt (vorausgesetzt, Sie können mindestens eine Spalte in den Speicher passen).

import pandas as pd 
import numpy as np 
from scipy.sparse import lil_matrix 

def sparse_df_to_array(df): 
    """ Convert sparse dataframe to sparse array csr_matrix used by 
    scikit learn. """ 
    arr = lil_matrix(df.shape, dtype=np.float32) 
    for i, col in enumerate(df.columns): 
     ix = df[col] != 0 
     arr[np.where(ix), i] = df.ix[ix, col] 

    return arr.tocsr() 
3

Die Antwort von @Marigold funktioniert der Trick, aber es ist langsam durch alle Elemente in jeder Spalte zugreifen, einschließlich der Nullen. Darauf aufbauend habe ich den folgenden schnellen und schmutzigen Code geschrieben, der auf einer 1000x1000 Matrix mit einer Dichte von etwa 1% etwa 50x schneller läuft. Mein Code behandelt auch dichte Spalten entsprechend.

def sparse_df_to_array(df): 
    num_rows = df.shape[0] 

    data = [] 
    row = [] 
    col = [] 

    for i, col_name in enumerate(df.columns): 
     if isinstance(df[col_name], pd.SparseSeries): 
      column_index = df[col_name].sp_index 
      if isinstance(column_index, BlockIndex): 
       column_index = column_index.to_int_index() 

      ix = column_index.indices 
      data.append(df[col_name].sp_values) 
      row.append(ix) 
      col.append(len(df[col_name].sp_values) * [i]) 
     else: 
      data.append(df[col_name].values) 
      row.append(np.array(range(0, num_rows))) 
      col.append(np.array(num_rows * [i])) 

    data_f = np.concatenate(data) 
    row_f = np.concatenate(row) 
    col_f = np.concatenate(col) 

    arr = coo_matrix((data_f, (row_f, col_f)), df.shape, dtype=np.float64) 
    return arr.tocsr() 
6

Pandas 0.20.0+:

Ab Pandas Version 0.20.0, den 5. Mai veröffentlicht 2017, ist es ein Einzeiler dafür:

from scipy import sparse 


def sparse_df_to_csr(df): 
    return sparse.csr_matrix(df.to_coo()) 

Dies nutzt die neu to_coo() method.

früheren Versionen:

Aufbauend auf Victor Mays Antwort, hier ist eine etwas schnellere Implementierung, aber es funktioniert nur, wenn die gesamte SparseDataFrame mit allen BlockIndex (Anmerkung spärlich ist: wenn es mit get_dummies erstellt wurde, das wird die Fall).

Bearbeiten: Ich habe dies geändert, so dass es mit einem Füllwert ungleich Null arbeiten wird. CSR hat keinen nativen Nicht-Null-Füllwert, daher müssen Sie ihn extern aufzeichnen.

import numpy as np 
import pandas as pd 
from scipy import sparse 

def sparse_BlockIndex_df_to_csr(df): 
    columns=df.columns 
    zipped_data = zip(*[(df[col].sp_values - df[col].fill_value, 
         df[col].sp_index.to_int_index().indices) 
         for col in columns]) 
    data, rows=map(list, zipped_data) 
    cols=[np.ones_like(a)*i for (i,a) in enumerate(data)] 
    data_f = np.concatenate(data) 
    rows_f = np.concatenate(rows) 
    cols_f = np.concatenate(cols) 
    arr = sparse.coo_matrix((data_f, (rows_f, cols_f)), 
          df.shape, dtype=np.float64) 
    return arr.tocsr() 
+0

Wie wäre es, 'series.to_coo()' zu verwenden, um jede Spalte zu konvertieren, und 'sparse.bmat()', um diese zu einer Matrix zusammenzufassen? – hpaulj

+0

@hpaulj Das klingt nach einer eindeutigen Antwort - Sie sollten es aufschreiben! –

+0

Ich sehe weiter, dass das Multiindex-Mapping sich sehr von den einfachen Spaltenvektoren unterscheidet, die ich im Sinn hatte. Es ist mehr wie die Feature-Matrix, die Leute "sklearn" mögen. – hpaulj

-1

EDIT: Diese Methode ist eigentlich irgendwann eine dichte Darstellung ist, so dass es nicht die Frage lösen.

Sie sollten die experimentellen .to_coo() Methode in Pandas [1] in der folgenden Art und Weise nutzen können:

df, idx_rows, idx_cols = df.stack().to_sparse().to_coo() 
df = df.tocsr() 

Diese Methode, anstatt sich ein DataFrame (Zeilen/Spalten) dauert es eine Series mit Reihen und Spalten in einer MultiIndex (deshalb benötigen Sie die .stack() Methode). Diese Series mit der MultiIndex muss eine SparseSeries sein, und selbst wenn Ihre Eingabe eine SparseDataFrame ist, gibt .stack() eine reguläre Series zurück. So müssen Sie die .to_sparse() Methode vor dem Aufruf .to_coo() verwenden.

Die Series zurück von .stack(), auch wenn es nur nicht ein SparseSeries ist, die Elemente enthält, die nicht null sind, so sollte es nicht mehr Speicher benötigt als die spärliche Version (zumindest mit np.nan, wenn der Typ np.float ist).

  1. http://pandas.pydata.org/pandas-docs/stable/sparse.html#interaction-with-scipy-sparse
+0

Diese Methode scheint eine große Menge an Speicher leider zu verwenden. – eleanora

+0

Sie haben Recht @eleanora, nicht sicher, wie ich es vorher getestet habe, aber es sieht aus wie intern diese Methode eine dichte interne Darstellung des Arrays hat, so ist es sinnlos für die Frage. Entschuldigung für die falsche Antwort. –

+0

Es scheint, dass das jetzt funktioniert. 'dataset = sparse.csr_matrix (df.to_coo())' – eleanora

Verwandte Themen