matrices - ¿Qué tipo de matriz de Python sería esto? ¿Ya existe en Python?
numpy array que es (4)
Tengo una matriz numpy:
m = array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
Las 4 columnas de m están etiquetadas:
c = array([ 10, 20, 30, 40])
Quiero poder cortar un objeto o
tal que:
o.vals[0,:] = array([4, 9])
o.vals[1,:] = array([7,])
o.vals[2,:] = array([])
o.vals[3,:] = array([5])
o.cols[0,:] = array([10, 30] )# the non-zero column labels from row 0
o.cols[1,:] = array([20,])
o.cols[2,:] = array([])
o.cols[3,:] = array([40])
¿Existe un objeto Python existente que me permita hacer esto?
He analizado Scipy Sparse Matrices , pero no es exactamente lo que estoy buscando.
UNA ACTUALIZACIÓN el 17 de agosto de 2015: He tenido algunas ideas y se me ocurrió esto, que es casi lo mismo que describí la semana pasada:
Podría usar pandas
( http://pandas.pydata.org/ ). (dado que probé scipy/numpy
que no son paquetes de biblioteca estándar de Python, supongo que está bien sugerir otro paquete).
Un DataFrame
es un objeto que le permite realizar todas sus operaciones, y muchas más.
import numpy as np
import pandas as pd
m = array([[4, 0, 9, 0], [0, 7, 0, 0], [0, 0, 0, 0], [0, 0, 0, 5]])
# create a dataframe
df = pd.DataFrame(m, columns=[10,20,30,40])
# replace 0 with NaN (to make use of pandas `dropna`)
df.replace(0, np.NaN, inplace=True)
# values per row
df.irow(0).dropna().as_matrix()
array([ 4., 9.])
df.irow(1).dropna().as_matrix()
array([ 7.])
df2.irow(2).dropna().as_matrix()
array([], dtype=float64)
# column labels (as list)
df.irow(1).dropna().index.tolist()
[10, 30]
# or non-zero values per column?
df.icol(0).dropna().as_matrix()
array([ 4.])
# ...
También puede combinar la etiqueta y el valor de la columna, ya que el retorno normal del dropna
es un DataFrame.
non_zero_1 = df.irow(0).dropna()
labels_1 = non_zero_1.index
Int64Index([10, 30], dtype=''int64'')
Lo mejor es probar Pandas y ver si se ajusta a tus necesidades. Y también eche un vistazo a la gran introducción ( http://pandas.pydata.org/pandas-docs/stable/10min.html ).
Puede acercarse a lo que desea con una matriz dispersa de CSR:
import scipy.sparse as sps
m_csr = sps.csr_matrix(m)
Ahora puede implementar funciones similares a lo que está buscando de esta manera:
def vals(sps_mat, row):
row_slice = slice(sps_mat.indptr[row], sps_mat.indptr[row+1])
return sps_mat.data[row_slice]
def cols(sps_mat, col_labels, row):
col_labels = np.asarray(col_labels)
row_slice = slice(sps_mat.indptr[row], sps_mat.indptr[row+1])
return col_labels[sps_mat.indices[row_slice]]
Usando estas funciones obtenemos:
>>> for row in range(m_csr.shape[0]):
... print vals(m_csr, row)
...
[4 9]
[7]
[]
[5]
>>> for row in range(m_csr.shape[0]):
... print cols(m_csr, [10, 20, 30, 40], row)
...
[10 30]
[20]
[]
[40]
Esto será muy eficiente en matrices grandes, aunque la sintaxis no es exactamente lo que usted quería.
Puede acercarse a lo que desea definiendo una clase que contenga m
y c
:
import numpy as np
class O(object):
def __init__(self, m, c):
self.m, self.c = m, c
def vals(self, i):
return self.m[i][self.m[i]!=0]
def cols(self, i):
return self.c[self.m[i]!=0]
m = np.array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
c = np.array([ 10, 20, 30, 40])
o = O(m, c)
for i in range(4):
print ''o.vals({0:d}) = {1}''.format(i, o.vals(i))
for i in range(4):
print ''o.cols({0:d}) = {1}''.format(i, o.cols(i))
Devoluciones:
o.vals(0) = [4 9]
o.vals(1) = [7]
o.vals(2) = []
o.vals(3) = [5]
o.cols(0) = [10 30]
o.cols(1) = [20]
o.cols(2) = []
o.cols(3) = [40]
(Sin embargo, podría ser más fácil usar la indexación, m[i][m[i]!=0
c[m[i]!=0]
directamente).
Puede usar una clase anidada y sobrecargar el atributo __getitem__
de sus objetos:
import numpy as np
class indexer:
def __init__(self,arr):
self.arr=arr
self.d=self.caldict(self.arr)
self.vals=self.values(self.arr,self.d)
self.cols=self.columns(self.d)
def caldict(self,arr,dd={}):
inds=np.array(np.nonzero(arr)).T
for i,j in inds:
dd.setdefault(i,[]).append(j)
return dd
class values:
def __init__(self,arr,d):
self.arr=arr
self.d=d
def __getitem__(self,index):
try:
return self.arr.take(index,axis=0)[self.d[index]]
except KeyError:
return []
class columns:
def __init__(self,d):
self.d=d
self.c=np.array([ 10, 20, 30, 40])
def __getitem__(self,index):
try:
return self.c.take(self.d[index])
except KeyError:
return []
Manifestación:
m=np.array([[4, 0, 9, 0],
[0, 7, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 5]])
o=indexer(m)
print o.vals[0],''/n'',o.vals[1],''/n'',o.vals[2],''/n'',o.vals[3]
print ''------------------''
print o.cols[0],''/n'',o.cols[1],''/n'',o.cols[2],''/n'',o.cols[3]
[4 9]
[7]
[]
[5]
------------------
[10 30]
[20]
[]
[40]