python arrays numpy sequence variable-length-array

Convierta la secuencia de Python a la matriz NumPy, llenando los valores faltantes



arrays sequence (5)

Aquí hay un enfoque basado en la indexación booleana casi * vectorizado que he usado en varias otras publicaciones:

def boolean_indexing(v): lens = np.array([len(item) for item in v]) mask = lens[:,None] > np.arange(lens.max()) out = np.zeros(mask.shape,dtype=int) out[mask] = np.concatenate(v) return out

Ejecución de la muestra

In [27]: v Out[27]: [[1], [1, 2], [3, 6, 7, 8, 9], [4]] In [28]: out Out[28]: array([[1, 0, 0, 0, 0], [1, 2, 0, 0, 0], [3, 6, 7, 8, 9], [4, 0, 0, 0, 0]])

* Tenga en cuenta que esto se acuñó como casi vectorizado porque el único bucle realizado aquí es al principio, donde estamos obteniendo las longitudes de los elementos de la lista. Pero esa parte que no sea tan computacionalmente exigente debería tener un efecto mínimo en el tiempo de ejecución total.

Prueba de tiempo de ejecución

En esta sección, estoy cronometrando la DataFrame-based solution by @Alberto Garcia-Raboso , la itertools-based solution by @ayhan ya que parecen escalar bien y la indexación booleana basada en esta publicación para un conjunto de datos relativamente más grande con tres niveles de tamaño variación a través de los elementos de la lista.

Caso # 1: mayor variación de tamaño

In [44]: v = [[1], [1,2,4,8,4],[6,7,3,6,7,8,9,3,6,4,8,3,2,4,5,6,6,8,7,9,3,6,4]] In [45]: v = v*1000 In [46]: %timeit pd.DataFrame(v).fillna(0).values.astype(np.int32) 100 loops, best of 3: 9.82 ms per loop In [47]: %timeit np.array(list(itertools.izip_longest(*v, fillvalue=0))).T 100 loops, best of 3: 5.11 ms per loop In [48]: %timeit boolean_indexing(v) 100 loops, best of 3: 6.88 ms per loop

Caso # 2: variación de tamaño menor

In [49]: v = [[1], [1,2,4,8,4],[6,7,3,6,7,8]] In [50]: v = v*1000 In [51]: %timeit pd.DataFrame(v).fillna(0).values.astype(np.int32) 100 loops, best of 3: 3.12 ms per loop In [52]: %timeit np.array(list(itertools.izip_longest(*v, fillvalue=0))).T 1000 loops, best of 3: 1.55 ms per loop In [53]: %timeit boolean_indexing(v) 100 loops, best of 3: 5 ms per loop

Caso # 3: mayor número de elementos (100 máx.) Por elemento de lista

In [139]: # Setup inputs ...: N = 10000 # Number of elems in list ...: maxn = 100 # Max. size of a list element ...: lens = np.random.randint(0,maxn,(N)) ...: v = [list(np.random.randint(0,9,(L))) for L in lens] ...: In [140]: %timeit pd.DataFrame(v).fillna(0).values.astype(np.int32) 1 loops, best of 3: 292 ms per loop In [141]: %timeit np.array(list(itertools.izip_longest(*v, fillvalue=0))).T 1 loops, best of 3: 264 ms per loop In [142]: %timeit boolean_indexing(v) 10 loops, best of 3: 95.7 ms per loop

Para mí, parece que itertools.izip_longest está bastante bien. no hay un ganador claro, ¡pero tendría que tomarse caso por caso!

La conversión implícita de una secuencia de Python de listas de longitud variable en una matriz NumPy hace que la matriz sea de tipo objeto .

v = [[1], [1, 2]] np.array(v) >>> array([[1], [1, 2]], dtype=object)

Intentar forzar otro tipo causará una excepción:

np.array(v, dtype=np.int32) ValueError: setting an array element with a sequence.

¿Cuál es la forma más eficiente de obtener una matriz densa NumPy de tipo int32, rellenando los valores "faltantes" con un marcador de posición dado?

De mi secuencia de muestra v , me gustaría obtener algo como esto, si 0 es el marcador de posición

array([[1, 0], [1, 2]], dtype=int32)


Aquí hay una forma general:

>>> v = [[1], [2, 3, 4], [5, 6], [7, 8, 9, 10], [11, 12]] >>> max_len = np.argmax(v) >>> np.hstack(np.insert(v, range(1, len(v)+1),[[0]*(max_len-len(i)) for i in v])).astype(''int32'').reshape(len(v), max_len) array([[ 1, 0, 0, 0], [ 2, 3, 4, 0], [ 5, 6, 0, 0], [ 7, 8, 9, 10], [11, 12, 0, 0]], dtype=int32)


Pandas y su DataFrame tratan muy bien los datos faltantes.

import numpy as np import pandas as pd v = [[1], [1, 2]] print(pd.DataFrame(v).fillna(0).values.astype(np.int32)) # array([[1, 0], # [1, 2]], dtype=int32)



max_len = max(len(sub_list) for sub_list in v) result = np.array([sub_list + [0] * (max_len - len(sub_list)) for sub_list in v]) >>> result array([[1, 0], [1, 2]]) >>> type(result) numpy.ndarray