2013-03-27 12 views
9

Załóżmy, że mam matrycę składającą się z listy list tak:Sub matryca wykazu list (bez 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]] 

Załóżmy również, że mam numpy matrycę tej samej struktury o nazwie LoLa:

>>> LoLa=np.array(LoL) 

Korzystanie numpy, mogę dostać podmatrycę tej macierzy tak:

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

mogę replic zjadł kawałek numpy matrycy w czystym Pythonie tak:

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

który nie jest najłatwiejszą rzeczą na świecie czytać ani najskuteczniejszy :-)

Pytanie: Czy istnieje prostszy sposób (w czystej Python), aby wyciąć dowolną macierz jako pod-macierz?

Odpowiedz

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

Można też naśladować NumPy Składnia definiując podklasę 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]) 

daje również

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

Używanie LoL podklasy nie zdobędzie żadnych testów prędkości :

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 

ale prędkość to nie wszystko - czasami ważniejsza jest czytelność.

+0

Druga część * całkowicie * ukradła moją odpowiedź! :-)) +1 – dawg

+1

Pozdrawiam, @drewk; następny jest cały twój :) – unutbu

5

Z jednej strony, można użyć slice obiektów bezpośrednio, co pomaga trochę z obu czytelności i wykonanie:

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

A jeśli po prostu iteracyjne nad lista-of-list bezpośrednio, można napisać, że jako:

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

nie wiem, czy jej łatwiej, ale pozwól mi rzucić pomysł do stołu:

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

To jest spłaszczona wersja submatrix, którą chcesz.

1

Do tego

submat = [[mata [b] [j] przez j w zakresie (index1, Index2)] dla i w zakresie (index3, index4)]

submat będzie prostokątna (kwadratowa, jeśli index3 == index1 i index2 == index4) fragment oryginalnej dużej macierzy.