2015-08-11 19 views
7

Ho una matrice NumPy:Che tipo di array Python sarebbe? Esiste già in Python?

m = array([[4, 0, 9, 0], 
      [0, 7, 0, 0], 
      [0, 0, 0, 0], 
      [0, 0, 0, 5]]) 

Le 4 colonne di m sono etichettati:

c = array([ 10, 20, 30, 40]) 

voglio essere in grado di tagliare un oggetto o tale che:

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

Esiste un oggetto Python esistente che potrebbe permettermi di farlo?

Ho visto Scipy Sparse Matrices, ma non è proprio quello che sto cercando.

UN AGGIORNAMENTO il 17 agosto 2015: Ho avuto un gioco intorno con alcune idee e si avvicinò con questo, che è quasi lo stesso di quello che ho descritto la settimana scorsa:

risposta

3

È possibile avvicinarsi a ciò che si desidera, definendo un cl ass di contenere m e 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)) 

Returns:

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] 

(. Potrebbe essere più facile da usare l'indicizzazione, m[i][m[i]!=0 e c[m[i]!=0] direttamente, però)

2

Si potrebbe utilizzare pandas (http://pandas.pydata.org/). (Dal momento che hai provato scipy/numpy che non sono pacchetti di Python standard della libreria presumo che sia giusto suggerire un altro pacchetto).

A DataFrame è un oggetto che consente di eseguire tutte le operazioni e molte altre.

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.]) 

# ... 

Si potrebbe anche combinare etichetta di colonna e il valore, dal momento che il rendimento normale dal dropna è un dataframe.

non_zero_1 = df.irow(0).dropna() 
labels_1 = non_zero_1.index 

Int64Index([10, 30], dtype='int64') 

Meglio solo provare Panda e vedere se soddisfa le vostre esigenze. E anche dare un'occhiata alla grande introduzione (http://pandas.pydata.org/pandas-docs/stable/10min.html).

2

È possibile avvicinarsi a ciò che si desidera con un CSR matrice sparsa:

import scipy.sparse as sps 

m_csr = sps.csr_matrix(m) 

Si potrebbe ora implementare funzioni simili a quello che stai dopo in questo modo:

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]] 

Utilizzando questo funzioni noi get:

>>> 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] 

Questo sarà molto efficiente su matrici di grandi dimensioni, anche se il synta x non è proprio quello che volevi.

1

È possibile utilizzare una classe annidata e sovraccaricare l'attributo __getitem__ degli oggetti:

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 [] 

Demo:

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] 
Problemi correlati