2010-08-02 2 views
22

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

Попытка

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

выдает ошибку

ValueError: setting an array element with a sequence. 

ответ

17

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

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

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

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

12

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

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

Мы уже почти 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])] 
+0

Проблема в том, что вы все еще не можете использовать d.mean(), d.flatten() и т. Д. – episodeyang

1

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

cells_flat = numpy.array([0, 1, 2, 3, 2, 3, 4]) 
# One of these is required, it's 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]) 
Смежные вопросы