2015-06-27 16 views
11

C'è un modo per convertire da un pandas.SparseDataFrame a scipy.sparse.csr_matrix, senza generare una matrice densa in memoria?Pandas sparse dataFrame alla matrice sparsa, senza generare una matrice densa in memoria

scipy.sparse.csr_matrix(df.values) 

non funziona in quanto genera una matrice densa che viene gettato al csr_matrix.

Grazie in anticipo!

+0

Esegui questo al contrario? http://stackoverflow.com/questions/17818783/populate-a-pandas-sparsedataframe-from-a-scipy-sparse-matrix – JohnE

risposta

0

Pandas docs parla di una conversione sperimentale per SciPy sparse, SparseSeries.to_coo:

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

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

modifica - questa è una funzione speciale da un multiindice, non da un frame di dati. Vedi le altre risposte per quello. Notare la differenza di date.

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

Al 0.20.0, c'è un sdf.to_coo() e multiindex ss.to_coo(). Poiché una matrice sparsa è intrinsecamente 2d, ha senso richiedere il multiindice per il dataseries (efficace) 1d. Mentre il dataframe può rappresentare una tabella o un array 2d.

Quando ho risposto per la prima volta a questa domanda, questa spettrale funzione dataframe/serie era sperimentale (giugno 2015).

+0

Questo è solo per 'MultiIndex' -ed' SparseSeries', non per un DataFrame. –

+0

Come @eleanora ha menzionato, [questo in realtà funziona ora] (http://pandas-docs.github.io/pandas-docs-travis/generated/pandas.SparseDataFrame.to_coo.html#pandas.SparseDataFrame.to_coo) (come della versione 0.20.0, rilasciata il 5 maggio 2017). 'sparse.csr_matrix (df.to_coo())' è l'one-liner che farà il trucco. Forse dovresti modificare la tua risposta per renderla chiara? –

+0

Forse dovremmo chiudere l'argomento come datato? – hpaulj

0

Ecco una soluzione che riempie la colonna di matrice sparsa per colonna (si presuppone che sia possibile inserire almeno una colonna nella memoria).

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

La risposta di @Marigold fa il trucco, ma è lento a causa di accesso a tutti gli elementi in ciascuna colonna, inclusi gli zeri. Partendo da questo, ho scritto il seguente codice rapido e sporco, che gira circa 50 volte più velocemente su una matrice 1000x1000 con una densità di circa l'1%. Il mio codice gestisce anche le colonne dense in modo appropriato.

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+:

Come di panda versione 0.20.0, rilasciata 5 Maggio 2017, v'è un one-liner per questo:

from scipy import sparse 


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

Questo utilizza la nuovo to_coo() method.

versioni precedenti:

edificio sulla risposta di Victor maggio, ecco un'implementazione leggermente più veloce, ma funziona solo se l'intera SparseDataFrame è sparsa con tutto BlockIndex (nota: se è stato creato con get_dummies, questo sarà il Astuccio).

Modifica: Ho modificato questo in modo che funzioni con un valore di riempimento diverso da zero. La CSR non ha un valore di riempimento nativo diverso da zero, quindi dovrai registrarlo esternamente.

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

Che ne dici di usare 'series.to_coo()' per convertire ogni colonna, e 'sparse.bmat()' per unirli a una matrice? – hpaulj

+0

@hpaulj Sembra una risposta distinta: dovresti scriverlo! –

+0

Scavando ulteriormente, vedo che la mappatura Multiindex è molto diversa dai semplici vettori di colonne che avevo in mente. È più simile alla matrice di funzioni che piace a persone che usano sklearn. – hpaulj

-1

EDIT: Questo metodo è in realtà avere una rappresentazione densa a un certo punto, in modo che non risolve la questione.

Si dovrebbe essere in grado di utilizzare il metodo sperimentale .to_coo() in pandi [1] nel modo seguente:

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

Questo metodo, invece di prendere un DataFrame (righe/colonne) richiede un Series con righe e le colonne in un MultiIndex (questo è il motivo per cui è necessario il metodo .stack()). Questo Series con MultiIndex deve essere un SparseSeries e anche se l'input è un SparseDataFrame, .stack() restituisce un normale Series. Quindi, è necessario utilizzare il metodo .to_sparse() prima di chiamare .to_coo().

Il Series restituito da .stack(), anche se non è un SparseSeries contiene solo gli elementi non nulli, quindi non dovrebbe prendere più memoria rispetto alla versione sparse (almeno con np.nan quando il tipo è np.float).

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

Questo metodo sembra utilizzare un'enorme quantità di memoria tristemente. – eleanora

+0

Hai ragione @eleanora, non sono sicuro di come l'ho provato prima, ma sembra che internamente questo metodo abbia una densa rappresentazione interna dell'array, quindi è inutile per la domanda. Ci scusiamo per la risposta sbagliata. –

+0

Sembra che funzioni ora. 'dataset = sparse.csr_matrix (df.to_coo())' – eleanora

Problemi correlati