Подтвердить что ты не робот

Как создать многомерный массив numpy с переменным размером строки?

Я хотел бы создать двухмерный массив numpy массивов, который имеет различное количество элементов в каждой строке.

Попытка

cells = numpy.array([[0,1,2,3], [2,3,4]])

дает ошибку

ValueError: setting an array element with a sequence.
4b9b3361

Ответ 1

В то время как Numpy знает о массивах произвольных объектов, он оптимизирован для однородных массивов чисел с фиксированными размерами. Если вам действительно нужны массивы массивов, лучше использовать вложенный список. Но в зависимости от предполагаемого использования ваших данных различные структуры данных могут быть еще лучше, например. Маскированный массив, если у вас есть некоторые недопустимые точки данных.

Если вам действительно нужны гибкие массивы Numpy, используйте что-то вроде этого:

numpy.array([[0,1,2,3], [2,3,4]], dtype=object)

Однако это создаст одномерный массив, в котором хранятся ссылки на списки, а это означает, что вы потеряете большую часть преимуществ Numpy (векторная обработка, локальность, нарезка и т.д.).

Ответ 2

Это не очень хорошо поддерживается в Numpy (по определению, почти везде "двумерный массив" имеет все строки равной длины). Список Python массивов Numpy может быть хорошим решением для вас, так как вы получите преимущества Numpy, где вы можете их использовать:

cells = [numpy.array(a) for a in [[0,1,2,3], [2,3,4]]]

Ответ 3

Мы сейчас почти через 7 лет после того, как задан вопрос, и ваш код

cells = numpy.array([[0,1,2,3], [2,3,4]])

выполняемый в numpy 1.12.0, python 3.5, не вызывает ошибок и cells содержит:

array([[0, 1, 2, 3], [2, 3, 4]], dtype=object)

Вы получаете доступ к вашим элементам cells как cells[0][2] # (=2).

Альтернативой решению tom10, если вы хотите создать свой список массивов numpy на лету, поскольку новые элементы (то есть массивы) становятся доступными, это использовать append:

d = []                 # initialize an empty list
a = np.arange(3)       # array([0, 1, 2])
d.append(a)            # [array([0, 1, 2])]
b = np.arange(3,-1,-1) #array([3, 2, 1, 0])
d.append(b)            #[array([0, 1, 2]), array([3, 2, 1, 0])]

Ответ 4

Другой вариант - хранить массивы как один непрерывный массив, а также хранить их размеры или смещения. Это требует немного более концептуальной мысли о том, как работать с вашими массивами, но можно сделать удивительно большое количество операций для работы, как если бы у вас был двухмерный массив разных размеров. В тех случаях, когда они не могут, тогда np.split можно использовать для создания списка, который рекомендует calocedrus. Простейшими операциями являются ufunc, потому что они практически не требуют изменений. Вот несколько примеров:

cells_flat = numpy.array([0, 1, 2, 3, 2, 3, 4])
# One of these is required, it pretty easy to convert between them,
# but having both makes the examples easy
cell_lengths = numpy.array([4, 3])
cell_starts = numpy.insert(cell_lengths[:-1].cumsum(), 0, 0)
cell_lengths2 = numpy.diff(numpy.append(cell_starts, cells_flat.size))
assert np.all(cell_lengths == cell_lengths2)

# Copy prevents shared memory
cells = numpy.split(cells_flat.copy(), cell_starts[1:])
# [array([0, 1, 2, 3]), array([2, 3, 4])]

numpy.array([x.sum() for x in cells])
# array([6, 9])
numpy.add.reduceat(cells_flat, cell_starts)
# array([6, 9])

[a + v for a, v in zip(cells, [1, 3])]
# [array([1, 2, 3, 4]), array([5, 6, 7])]
cells_flat + numpy.repeat([1, 3], cell_lengths)
# array([1, 2, 3, 4, 5, 6, 7])

[a.astype(float) / a.sum() for a in cells]
# [array([ 0.        ,  0.16666667,  0.33333333,  0.5       ]),
#  array([ 0.22222222,  0.33333333,  0.44444444])]
cells_flat.astype(float) / np.add.reduceat(cells_flat, cell_starts).repeat(cell_lengths)
# array([ 0.        ,  0.16666667,  0.33333333,  0.5       ,  0.22222222,
#         0.33333333,  0.44444444])

def complex_modify(array):
    """Some complicated function that modifies array

    pretend this is more complex than it is"""
    array *= 3

for arr in cells:
    complex_modify(arr)
cells
# [array([0, 3, 6, 9]), array([ 6,  9, 12])]
for arr in numpy.split(cells_flat, cell_starts[1:]):
    complex_modify(arr)
cells_flat
# array([ 0,  3,  6,  9,  6,  9, 12])