Matriz de partición en N trozos con Numpy

5 minutos de lectura

avatar de usuario
Eiyrioü von Kauyf

Existe esto ¿Cómo se divide una lista en partes de tamaño uniforme? para dividir una matriz en fragmentos. ¿Hay alguna forma de hacer esto de manera más eficiente para matrices gigantes que usan Numpy?

  • Defina eficiente. Proporcione algunos datos de muestra, su método actual, qué tan rápido es y qué tan rápido necesita que sea.

    – Prashant Kumar

    31 de diciembre de 2013 a las 18:19

  • ¿Se supone que debemos interpretar la entrada a esta pregunta como una matriz nativa de Pythono un numpy ndarray? La primera oración parece implicar lo primero. La segunda oración implica que está pidiendo una comparación entre el primero y el segundo. Solo bidimensional, presumiblemente. Y cuando decimos “eficientemente… para arreglos gigantes”, ¿estamos más preocupados por la escalabilidad para N asintóticamente grande, sin importar si es más lento para N pequeño?

    – smci

    9 de noviembre de 2020 a las 23:24


avatar de usuario
Prashant Kumar

Probar numpy.array_split.

De la documentación:

>>> x = np.arange(8.0)
>>> np.array_split(x, 3)
    [array([ 0.,  1.,  2.]), array([ 3.,  4.,  5.]), array([ 6.,  7.])]

Idéntico a numpy.splitpero no generará una excepción si los grupos no tienen la misma longitud.

Si el número de fragmentos> len (matriz), obtiene matrices en blanco anidadas dentro, para abordar eso, si su matriz dividida se guarda en aentonces puede eliminar matrices vacías de la siguiente manera:

[x for x in a if x.size > 0]

Solo guárdalo de nuevo en a si lo desea.

  • ¿Cómo puedes eliminar las listas vacías?

    – Eiyrioü von Kauyf

    18/01/2013 a las 20:42

  • ¿Puedes dar un pequeño ejemplo?

    – Prashant Kumar

    28 de enero de 2013 a las 22:48

  • si # chunks > len(matriz) obtiene matrices en blanco anidadas dentro.

    – Eiyrioü von Kauyf

    29 de enero de 2013 a las 7:50

  • sí, eso era lo que estaba usando … pero de todos modos, ¿hacer eso con numpy? Las listas de comprensión en python son lentas.

    – Eiyrioü von Kauyf

    29 de enero de 2013 a las 18:45

  • @EiyrioüvonKauyf, para hacerlo con numpy, simplemente limite la cantidad de elementos a la longitud de la matriz: np.array_split(x, min(len(x), 3)) donde 3 es el número predeterminado de grupos que desea.

    – David Kaftan

    8 mayo 2021 a las 14:50

avatar de usuario
tzelleké

Solo algunos ejemplos sobre el uso de array_split, split, hsplit y vsplit:

n [9]: a = np.random.randint(0,10,[4,4])

In [10]: a
Out[10]: 
array([[2, 2, 7, 1],
       [5, 0, 3, 1],
       [2, 9, 8, 8],
       [5, 7, 7, 6]])

Algunos ejemplos sobre el uso array_split:
Si proporciona una matriz o una lista como segundo argumento, básicamente proporciona los índices (antes) que ‘cortar’

# split rows into 0|1 2|3
In [4]: np.array_split(a, [1,3])
Out[4]:                                                                                                                       
[array([[2, 2, 7, 1]]),                                                                                                       
 array([[5, 0, 3, 1],                                                                                                         
       [2, 9, 8, 8]]),                                                                                                        
 array([[5, 7, 7, 6]])]

# split columns into 0| 1 2 3
In [5]: np.array_split(a, [1], axis=1)                                                                                           
Out[5]:                                                                                                                       
[array([[2],                                                                                                                  
       [5],                                                                                                                   
       [2],                                                                                                                   
       [5]]),                                                                                                                 
 array([[2, 7, 1],                                                                                                            
       [0, 3, 1],
       [9, 8, 8],
       [7, 7, 6]])]

Un entero como segundo argumento. especifica el número de igual trozos:

In [6]: np.array_split(a, 2, axis=1)
Out[6]: 
[array([[2, 2],
       [5, 0],
       [2, 9],
       [5, 7]]),
 array([[7, 1],
       [3, 1],
       [8, 8],
       [7, 6]])]

split funciona igual pero genera una excepción si no es posible una división equitativa

Además de array_split puedes usar atajos vsplit y hsplit.
vsplit y hsplit son bastante autoexplicativos:

In [11]: np.vsplit(a, 2)
Out[11]: 
[array([[2, 2, 7, 1],
       [5, 0, 3, 1]]),
 array([[2, 9, 8, 8],
       [5, 7, 7, 6]])]

In [12]: np.hsplit(a, 2)
Out[12]: 
[array([[2, 2],
       [5, 0],
       [2, 9],
       [5, 7]]),
 array([[7, 1],
       [3, 1],
       [8, 8],
       [7, 6]])]

  • mi problema con esto es que si chunks > len(array) entonces obtienes matrices anidadas en blanco… ¿cómo te deshaces de eso?

    – Eiyrioü von Kauyf

    29 de enero de 2013 a las 7:48

  • Buenos ejemplos, gracias. En tus np.array_split(a, [1], axis=1) ejemplo, ¿sabe cómo evitar que la primera matriz tenga todos los elementos anidados?

    – timgeb

    4 de enero de 2016 a las 8:11


creo que estas buscando numpy.split o posiblemente numpy.array_split si el número de secciones no necesita dividir el tamaño de la matriz correctamente.

  • misma pregunta que le hice a Prashant. ¿Cómo puede deshacerse de las matrices numpy vacías?

    – Eiyrioü von Kauyf

    18 de enero de 2013 a las 20:44

No es exactamente una respuesta, sino un comentario largo con un buen formato de código para las otras respuestas (correctas). Si intenta lo siguiente, verá que lo que obtiene son vistas de la matriz original, no copias, y ese no fue el caso de la respuesta aceptada en la pregunta que vincula. ¡Tenga en cuenta los posibles efectos secundarios!

>>> x = np.arange(9.0)
>>> a,b,c = np.split(x, 3)
>>> a
array([ 0.,  1.,  2.])
>>> a[1] = 8
>>> a
array([ 0.,  8.,  2.])
>>> x
array([ 0.,  8.,  2.,  3.,  4.,  5.,  6.,  7.,  8.])
>>> def chunks(l, n):
...     """ Yield successive n-sized chunks from l.
...     """
...     for i in xrange(0, len(l), n):
...         yield l[i:i+n]
... 
>>> l = range(9)
>>> a,b,c = chunks(l, 3)
>>> a
[0, 1, 2]
>>> a[1] = 8
>>> a
[0, 8, 2]
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8]

¿Qué tal esto? Aquí divide la matriz usando la longitud que desea tener.

a = np.random.randint(0,10,[4,4])

a
Out[27]: 
array([[1, 5, 8, 7],
       [3, 2, 4, 0],
       [7, 7, 6, 2],
       [7, 4, 3, 0]])

a[0:2,:]
Out[28]: 
array([[1, 5, 8, 7],
       [3, 2, 4, 0]])

a[2:4,:]
Out[29]: 
array([[7, 7, 6, 2],
       [7, 4, 3, 0]])

Esto se puede lograr usando as_strided de numpy. Le di un giro a la respuesta asumiendo que si el tamaño del fragmento no es un factor del número total de filas, entonces el resto de las filas en el último lote se llenarán con ceros.

from numpy.lib.stride_tricks import as_strided
def batch_data(test, chunk_count):
  m,n = test.shape
  S = test.itemsize
  if not chunk_count:
    chunk_count = 1
  batch_size = m//chunk_count
# Batches which can be covered fully
  test_batches = as_strided(test, shape=(chunk_count, batch_size, n), strides=(batch_size*n*S,n*S,S)).copy()
  covered = chunk_count*batch_size
  if covered < m:
    rest = test[covered:,:]
    rm, rn = rest.shape
    mismatch = batch_size - rm
    last_batch = np.vstack((rest,np.zeros((mismatch,rn)))).reshape(1,-1,n)
    return np.vstack((test_batches,last_batch))
  return test_batches

Esto se basa en mi respuesta https://stackoverflow.com/a/68238815/5462372.

¿Ha sido útil esta solución?