Преобразование последовательности Python в массив NumPy, заполнение отсутствующих значений

Неявное преобразование последовательности Python списков переменной длины в массив NumPy приводит к тому, что массив будет иметь объект типа.

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

Попытка принудительного использования другого типа вызовет исключение:

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

Каков наиболее эффективный способ получить плотный массив NumPy типа int32, заполнив «отсутствующие» значения данным заполнителем?

Из моей выборки v , я хотел бы получить что-то вроде этого, если 0 является заполнителем

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

Вы можете использовать itertools.zip_longest :

 import itertools np.array(list(itertools.zip_longest(*v, fillvalue=0))).T Out: array([[1, 0], [1, 2]]) 

Примечание. Для Python 2 это itertools.izip_longest .

Pandas и его DataFrame прекрасно DataFrame с отсутствующими данными.

 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) 

Вот почти * векторный подход, основанный на булевом индексировании, который я использовал в нескольких других сообщениях –

 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 

Прогон образца

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

* Обратите внимание, что это придумано как почти векторизованное, потому что единственный цикл, выполняемый здесь, находится в начале, где мы получаем длины элементов списка. Но эта часть, не требующая вычислительных требований, должна иметь минимальный эффект на общую продолжительность работы.

Тест времени выполнения

В этом разделе я DataFrame-based solution by @Alberto Garcia-Raboso , itertools-based solution by @ayhan поскольку они, похоже, хорошо itertools-based solution by @ayhan а itertools-based solution by @ayhan индексация основана на этом сообщении для относительно более крупного набора данных с тремя уровнями размера изменение элементов списка.

Случай №1: изменение размера

 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 

Вариант № 2: Малый размер

 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 

Случай №3: большее количество элементов (100 макс.) Для элемента списка

 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 

Для меня, похоже, itertools.izip_longest работает очень хорошо! нет явного победителя, но его нужно будет принимать в каждом конкретном случае!

 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 

Вот общий способ:

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