tabla - que es python pandas
¿Cree eficientemente tablas dinámicas dispersas en pandas? (3)
Estoy trabajando para convertir una lista de registros con dos columnas (A y B) en una representación matricial. He estado usando la función de pivote dentro de los pandas, pero el resultado termina siendo bastante grande. ¿Los pandas admiten el giro en un formato disperso? Sé que puedo girarlo y luego convertirlo en una especie de representación dispersa, pero no es tan elegante como me gustaría. Mi objetivo final es usarlo como entrada para un modelo predictivo.
Alternativamente, ¿hay algún tipo de capacidad de giro escasa fuera de los pandas?
edición: aquí hay un ejemplo de un pivote no disperso
import pandas as pd
frame=pd.DataFrame()
frame[''person'']=[''me'',''you'',''him'',''you'',''him'',''me'']
frame[''thing'']=[''a'',''a'',''b'',''c'',''d'',''d'']
frame[''count'']=[1,1,1,1,1,1]
frame
person thing count
0 me a 1
1 you a 1
2 him b 1
3 you c 1
4 him d 1
5 me d 1
frame.pivot(''person'',''thing'')
count
thing a b c d
person
him NaN 1 NaN 1
me 1 NaN NaN 1
you 1 NaN 1 NaN
Esto crea una matriz que podría contener todas las combinaciones posibles de personas y cosas, pero no es escasa.
http://docs.scipy.org/doc/scipy/reference/sparse.html
Las matrices dispersas ocupan menos espacio porque pueden implicar cosas como NaN o 0. Si tengo un conjunto de datos muy grande, esta función pivotante puede generar una matriz que debería ser dispersa debido a la gran cantidad de NaN o 0. Tenía la esperanza de poder ahorrar una gran cantidad de espacio / memoria generando algo que no estaba muy extendido en lugar de crear una matriz densa y luego convertirla en escasa.
Aquí hay un método que crea una matriz escasa basada en datos e índices de persona y cosa. person_u
y thing_u
son listas que representan las entradas únicas para sus filas y columnas de pivote que desea crear. Nota: esto supone que su columna de recuento ya tiene el valor que desea.
from scipy.sparse import csr_matrix
person_u = list(sort(frame.person.unique()))
thing_u = list(sort(frame.thing.unique()))
data = frame[''count''].tolist()
row = frame.person.astype(''category'', categories=person_u).cat.codes
col = frame.thing.astype(''category'', categories=thing_u).cat.codes
sparse_matrix = csr_matrix((data, (row, col)), shape=(len(person_u), len(thing_u)))
>>> sparse_matrix
<3x4 sparse matrix of type ''<type ''numpy.int64''>''
with 6 stored elements in Compressed Sparse Row format>
>>> sparse_matrix.todense()
matrix([[0, 1, 0, 1],
[1, 0, 0, 1],
[1, 0, 1, 0]])
Sobre la base de su pregunta original, la matriz dispersa debe ser suficiente para sus necesidades, pero si desea tener un marco de datos disperso, puede hacer lo siguiente:
dfs=pd.SparseDataFrame([ pd.SparseSeries(sparse_matrix[i].toarray().ravel(), fill_value=0)
for i in np.arange(sparse_matrix.shape[0]) ], index=person_u, columns=thing_u, default_fill_value=0)
>>> dfs
a b c d
him 0 1 0 1
me 1 0 0 1
you 1 0 1 0
>>> type(dfs)
pandas.sparse.frame.SparseDataFrame
La respuesta publicada anteriormente por @khammel fue útil, pero desafortunadamente ya no funciona debido a los cambios en pandas y Python. Lo siguiente debe producir el mismo resultado:
from scipy.sparse import csr_matrix
from pandas.api.types import CategoricalDtype
person_c = CategoricalDtype(sorted(frame.person.unique()), ordered=True)
thing_c = CategoricalDtype(sorted(frame.thing.unique()), ordered=True)
row = frame.person.astype(person_c).cat.codes
col = frame.thing.astype(thing_c).cat.codes
sparse_matrix = csr_matrix((frame["count"], (row, col)), /
shape=(person_c.categories.size, thing_c.categories.size))
>>> sparse_matrix
<3x4 sparse matrix of type ''<class ''numpy.int64''>''
with 6 stored elements in Compressed Sparse Row format>
>>> sparse_matrix.todense()
matrix([[0, 1, 0, 1],
[1, 0, 0, 1],
[1, 0, 1, 0]], dtype=int64)
dfs = pd.SparseDataFrame(sparse_matrix, /
index=person_u.categories, /
columns=thing_u.categories, /
default_fill_value=0)
>>> dfs
a b c d
him 0 1 0 1
me 1 0 0 1
you 1 0 1 0
Los principales cambios fueron:
-
.astype()
ya no acepta "categórico". Tienes que crear un objeto CategoricalDtype. -
sort()
ya no funciona
Otros cambios fueron más superficiales:
- Usar los tamaños de categoría en lugar de una longitud de los objetos de la serie sin formato, simplemente porque no quería hacer otro objeto innecesariamente
- La entrada de datos para
csr_matrix
(frame["count"]
) no necesita ser un objeto de lista - pandas
SparseDataFrame
acepta un objeto scipy.sparse directamente ahora
Tuve un problema similar y me tropecé con este post. La única diferencia fue que tenía dos columnas en el DataFrame
que definen la "dimensión de fila" ( i
) de la matriz de salida. Pensé que esto podría ser una generalización interesante, usé el grouper
:
# function
import pandas as pd
from scipy.sparse import csr_matrix
def df_to_sm(data, vars_i, vars_j):
grpr_i = data.groupby(vars_i).grouper
idx_i = grpr_i.group_info[0]
grpr_j = data.groupby(vars_j).grouper
idx_j = grpr_j.group_info[0]
data_sm = csr_matrix((data[''val''].values, (idx_i, idx_j)),
shape=(grpr_i.ngroups, grpr_j.ngroups))
return data_sm, grpr_i, grpr_j
# example
data = pd.DataFrame({''var_i_1'' : [''a1'', ''a1'', ''a1'', ''a2'', ''a2'', ''a3''],
''var_i_2'' : [''b2'', ''b1'', ''b1'', ''b1'', ''b1'', ''b4''],
''var_j_1'' : [''c2'', ''c3'', ''c2'', ''c1'', ''c2'', ''c3''],
''val'' : [1, 2, 3, 4, 5, 6]})
data_sm, _, _ = df_to_sm(data, [''var_i_1'', ''var_i_2''], [''var_j_1''])
data_sm.todense()