python pandas scipy sparse-matrix

python - Datos dispersos de pandas Marco de matriz dispersa, sin generar una matriz densa en la memoria



scipy sparse-matrix (5)

Pandas 0.20.0+:

A partir de la versión de pandas 0.20.0, lanzada el 5 de mayo de 2017, hay una frase para esto:

from scipy import sparse def sparse_df_to_csr(df): return sparse.csr_matrix(df.to_coo())

Esto usa el nuevo método to_coo() .

Versiones mas antiguas:

Basándose en la respuesta de Victor May, aquí hay una implementación un poco más rápida, pero solo funciona si todo el SparseDataFrame es escaso con todos los BlockIndex (nota: si fue creado con get_dummies , este será el caso).

Editar : modifiqué esto para que funcione con un valor de relleno distinto de cero. CSR no tiene un valor de relleno nativo distinto de cero, por lo que deberá registrarlo externamente.

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()

¿Hay alguna forma de convertir un pandas.SparseDataFrame a scipy.sparse.csr_matrix , sin generar una matriz densa en la memoria?

scipy.sparse.csr_matrix(df.values)

no funciona, ya que genera una matriz densa que se csr_matrix .

¡Gracias por adelantado!


Aquí hay una solución que llena la matriz dispersa columna por columna (se supone que puede ajustar al menos una columna en la 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()


La respuesta de @Marigold hace el truco, pero es lenta debido al acceso a todos los elementos en cada columna, incluidos los ceros. Sobre la base de esto, escribí el siguiente código rápido y sucio, que se ejecuta aproximadamente 50 veces más rápido en una matriz 1000x1000 con una densidad de aproximadamente 1%. Mi código también maneja columnas densas apropiadamente.

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()


Pandas docs habla sobre una conversión experimental a scipy sparse, SparseSeries.to_coo:

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

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

editar: esta es una función especial de un índice múltiple, no un marco de datos. Vea las otras respuestas para eso. Tenga en cuenta la diferencia en las fechas.

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

A partir de 0.20.0, hay un sdf.to_coo() y un ss.to_coo() . Dado que una matriz dispersa es intrínsecamente 2d, tiene sentido requerir un índice múltiple para las series de datos 1d (efectivamente). Mientras que el marco de datos puede representar una tabla o una matriz 2D.

Cuando respondí por primera vez a esta pregunta, esta característica de serie / marco de datos escasa fue experimental (junio de 2015).


EDITAR : Este método en realidad tiene una representación densa en alguna etapa, por lo que no resuelve la pregunta.

Debería poder utilizar el .to_coo() experimental .to_coo() en pandas [1] de la siguiente manera:

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

Este método, en lugar de tomar un DataFrame (filas / columnas), toma una Series con filas y columnas en un MultiIndex (es por eso que necesita el método .stack() ). Esta Series con el MultiIndex debe ser una SparseSeries , e incluso si su entrada es un SparseDataFrame , .stack() devuelve una Series normal. Por lo tanto, debe usar el método .to_sparse() antes de llamar a .to_coo() .

La Series devuelta por .stack() , incluso si no es una SparseSeries solo contiene los elementos que no son nulos, por lo que no debería ocupar más memoria que la versión dispersa (al menos con np.nan cuando el tipo es np.float )

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