Как создать массив numpy списков?

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

Я посмотрел на google и вот на переполнение стека уже, но, похоже, его не найти.

Основная проблема заключается в том, что numpy предполагает, что ваш список должен стать массивом, но это не то, что я ищу.

Ответ 1

Как вы обнаружили, np.array пытается создать массив 2d, когда ему присваивается что-то вроде

 A = np.array([[1,2],[3,4]],dtype=object)

Вы применяете некоторые трюки, чтобы обойти это поведение по умолчанию.

Один из них состоит в том, чтобы сделать сублисты переменной длины. Он не может сделать из них 2d-массив, поэтому он обращается к массиву объектов:

In [43]: A=np.array([[1,2],[],[1,2,3,4]])
In [44]: A
Out[44]: array([[1, 2], [], [1, 2, 3, 4]], dtype=object)

И вы можете добавить значения в каждый из этих списков:

In [45]: for i in A: i.append(34)
In [46]: A
Out[46]: array([[1, 2, 34], [34], [1, 2, 3, 4, 34]], dtype=object)

np.empty также создает массив объектов:

In [47]: A=np.empty((3,),dtype=object)
In [48]: A
Out[48]: array([None, None, None], dtype=object)

Но тогда вам нужно быть осторожным, как вы меняете элементы в списках. np.fill заманчиво, но имеет проблемы:

In [49]: A.fill([])
In [50]: A
Out[50]: array([[], [], []], dtype=object)
In [51]: for i in A: i.append(34)
In [52]: A
Out[52]: array([[34, 34, 34], [34, 34, 34], [34, 34, 34]], dtype=object)

Оказывается, что fill помещает один и тот же список во все слоты, поэтому изменение одного изменяет все остальные. Вы можете получить ту же проблему со списком списков:

In [53]: B=[[]]*3
In [54]: B
Out[54]: [[], [], []]
In [55]: for i in B: i.append(34)
In [56]: B
Out[56]: [[34, 34, 34], [34, 34, 34], [34, 34, 34]]

Правильный способ инициализации empty A - с итерацией, например

In [65]: A=np.empty((3,),dtype=object)
In [66]: for i,v in enumerate(A): A[i]=[v,i]
In [67]: A
Out[67]: array([[None, 0], [None, 1], [None, 2]], dtype=object)
In [68]: for v in A: v.append(34)
In [69]: A
Out[69]: array([[None, 0, 34], [None, 1, 34], [None, 2, 34]], dtype=object)

Немного непонятно из вопроса и комментариев, хотите ли вы добавить в списки или добавить списки в массив. Я только что продемонстрировал добавление списков.

Существует функция np.append, которую новые пользователи часто неправильно используют. Это не замена списка. Это передний конец np.concatenate. Это не операция на месте; он возвращает новый массив.

Также определение списка для добавления с ним может быть сложным:

In [72]: np.append(A,[[1,23]])
Out[72]: array([[None, 0, 34], [None, 1, 34], [None, 2, 34], 1, 23],     dtype=object)

Вам нужно построить еще один массив объектов для конкатенации оригиналу, например

In [76]: np.append(A,np.empty((1,),dtype=object))
Out[76]: array([[None, 0, 34], [None, 1, 34], [None, 2, 34], None], dtype=object)

Во всем этом массив списков сложнее построить, чем список списков, а не проще и быстрее манипулировать. Вы должны сделать это 2d массивом списков, чтобы получить некоторую выгоду.

In [78]: A[:,None]
Out[78]: 
array([[[None, 0, 34]],
       [[None, 1, 34]],
       [[None, 2, 34]]], dtype=object)

Вы можете преобразовать, транспонировать и т.д. массив объектов, где сложнее создавать и обрабатывать список списков списков.

In [79]: A[:,None].tolist()
Out[79]: [[[None, 0, 34]], [[None, 1, 34]], [[None, 2, 34]]]

Ответ 2

Если вам действительно нужен массив из 1-го списка, вам придется обернуть свои списки в свой собственный класс, так как numpy всегда будет пытаться преобразовать ваши списки в массивы внутри массива (что более эффективно, но, очевидно, требует постоянного размера -элементы), например, через

class mylist:

    def __init__(self, l):
        self.l=l

    def __repr__(self): 
        return repr(self.l)

    def append(self, x):
        self.l.append(x)

а затем вы можете изменить любой элемент, не изменяя размерность других.

>>> x = mylist([1,2,3])
>>> y = mylist([1,2,3])
>>> import numpy as np
>>> data = np.array([x,y])
>>> data
array([[1,2,3], [1,2,3]], dtype=object)
>>> data[0].append(2)
>>> data
array([[1,2,3,2], [1,2,3]], dtype=object)

Update

Как было предложено ali_m, на самом деле существует способ заставить numpy просто создать 1-й массив для ссылок, а затем передать их фактическим спискам

>>> data = np.empty(2, dtype=np.object)
>>> data[:] = [1, 2, 3], [1, 2, 3]
>>> data
array([[1, 2, 3], [1, 2, 3]], dtype=object)
>>> data[0].append(4)
>>> data
array([[1, 2, 3, 4], [1, 2, 3]], dtype=object)

Ответ 3

data = np.empty(20, dtype=np.object)
for i in range(data.shape[0]):
    data[i] = []
    data[i].append(i)
print(data)

Результатом будет:

[список ([0]) список ([1]) список ([2]) список ([3]) список ([4]) список ([5]) список ([6]) список ([7]) список ([8]) список ([9]) список ([10]) список ([11]) список ([12]) список ([13]) список ([14]) список ([15]) список ([ 16]) список ([17]) список ([18]) список ([19])]