2013-03-27 19 views
9

Supponiamo che io ho una matrice composta da una lista di liste in questo modo:Sub matrice di una lista di liste (senza NumPy)

>>> LoL=[list(range(10)) for i in range(10)] 
>>> LoL 
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]] 

assumere, anche, che ho una matrice NumPy della stessa struttura chiamata LoLa:

>>> LoLa=np.array(LoL) 

Utilizzando NumPy, ho potuto ottenere una sottomatrice di questa matrice simili:

>>> LoLa[1:4,2:5] 
array([[2, 3, 4], 
     [2, 3, 4], 
     [2, 3, 4]]) 

posso replic mangiato la fetta NumPy matrice in puro Python in questo modo:

>>> r=(1,4) 
>>> s=(2,5) 
>>> [LoL[i][s[0]:s[1]] for i in range(len(LoL))][r[0]:r[1]] 
[[2, 3, 4], [2, 3, 4], [2, 3, 4]] 

che non è la cosa più facile del mondo per leggere, né il più efficace :-)

Domanda: C'è un modo più semplice (in puro Python) per tagliare una matrice arbitraria come sottotabella?

risposta

11
In [74]: [row[2:5] for row in LoL[1:4]] 
Out[74]: [[2, 3, 4], [2, 3, 4], [2, 3, 4]] 

Si potrebbe sintassi anche mimica del NumPy definendo una sottoclasse di list:

class LoL(list): 
    def __init__(self, *args): 
     list.__init__(self, *args) 
    def __getitem__(self, item): 
     try: 
      return list.__getitem__(self, item) 
     except TypeError: 
      rows, cols = item 
      return [row[cols] for row in self[rows]] 

lol = LoL([list(range(10)) for i in range(10)]) 
print(lol[1:4, 2:5]) 

produce anche

[[2, 3, 4], [2, 3, 4], [2, 3, 4]] 

Utilizzando la LoL sottoclasse non vincerà alcun test di velocità :

In [85]: %timeit [row[2:5] for row in x[1:4]] 
1000000 loops, best of 3: 538 ns per loop 
In [82]: %timeit lol[1:4, 2:5] 
100000 loops, best of 3: 3.07 us per loop 

ma la velocità non è tutto - a volte la leggibilità è più importante.

+0

La seconda parte * totalmente * ha rubato la mia risposta! :-)) +1 – dawg

+1

Cheers, @drewk; il prossimo è tutto tuo :) – unutbu

5

Per uno, è possibile utilizzare slice oggetti direttamente, che aiuta un po 'con sia la leggibilità e le prestazioni:

r = slice(1,4) 
s = slice(2,5) 
[LoL[i][s] for i in range(len(LoL))[r]] 

E se si iterare le liste list-of-direttamente, si può scrivere che come:

[row[s] for row in LoL[r]] 
0

Non so se la sua più facile, ma mi permetta di gettare un'idea alla tabella:

from itertools import product 
r = (1+1, 4+1) 
s = (2+1, 5+1) 
array = [LoL[i][j] for i,j in product(range(*r), range(*s))] 

Questa è una versione appiattita del submatrix che si desidera.

1

Fate questo,

submat = [[mat [i] [j] per j nella gamma (index1, indice2)] for i in range (index3, index4)]

il submat sarà il pezzo rettangolare (quadrato se index3 == index1 e index2 == index4) della tua matrice grande originale.