Преобразование последовательности 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)
- Добавление нового столбца / массива в массив Numpy
- Невозможно разбить многострочную строку на массив строк
- Почему NumPy массивы над стандартными библиотечными массивами?
- Создание списка отдельных элементов списка, умноженных n раз
- Эффективное определение того, имеет ли большой сортированный массив numpy только уникальные значения
Вы можете использовать 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)
- Фильтровать структурированный массив numpy на основе нескольких значений
- Интерполяция 3d-массива в Python расширена
- Режимы Numpy действуют по-разному на скопированных и неопубликованных массивах
- TypeError: недопустимые размеры для данных изображения при построении массива с imshow ()
- Np.cross производит неправильные результаты, ищет рабочую альтернативу
- Как передать список Python в функцию C с помощью Cython
- Python – пересечение 2D массивов Numpy
- Данные массива XYZ для тепловой карты
- Выбор и итерация определенных подмассивов в многомерных массивах в Python