web-dev-qa-db-fra.com

Comment créer un tableau numpy multidimensionnel avec une taille de ligne variable?

Je voudrais créer un tableau numpy bidimensionnel de tableaux qui a un nombre différent d'éléments sur chaque ligne.

En essayant

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

donne une erreur

ValueError: setting an array element with a sequence.
39
dzhelil

Bien que Numpy connaisse les tableaux d'objets arbitraires, il est optimisé pour les tableaux homogènes de nombres avec des dimensions fixes. Si vous avez vraiment besoin de tableaux de tableaux, mieux vaut utiliser une liste imbriquée. Mais selon l'utilisation prévue de vos données, différentes structures de données peuvent être encore meilleures, par exemple un tableau masqué si vous avez des points de données non valides.

Si vous voulez vraiment des tableaux Numpy flexibles, utilisez quelque chose comme ceci:

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

Cependant, cela créera un tableau unidimensionnel qui stocke les références aux listes, ce qui signifie que vous perdrez la plupart des avantages de Numpy (traitement vectoriel, localité, découpage, etc.).

24
Philipp

Nous sommes maintenant près de 7 ans après que la question a été posée, et votre code

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

exécuté dans numpy 1.12.0, python 3.5, ne produit aucune erreur et cells contient:

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

Vous accédez à vos éléments cells en tant que cells[0][2] # (=2).

Une alternative à la solution de tom1 si vous voulez construire votre liste de tableaux numpy à la volée à mesure que de nouveaux éléments (c'est-à-dire des tableaux) deviennent disponibles est d'utiliser 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])]
24
calocedrus

Cela n'est pas bien pris en charge dans Numpy (par définition, presque partout, un "tableau à deux dimensions" a toutes les lignes de même longueur). Une liste Python de tableaux Numpy peut être une bonne solution pour vous, car de cette façon, vous obtiendrez les avantages de Numpy où vous pourrez les utiliser:

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

Une autre option serait de stocker vos tableaux en tant que tableau contigu et de stocker également leurs tailles ou décalages. Cela nécessite un peu plus de réflexion conceptuelle sur la façon d'opérer sur vos baies, mais un nombre étonnamment élevé d'opérations peut être fait pour fonctionner comme si vous aviez une baie bidimensionnelle de tailles différentes. Dans les cas où ils ne peuvent pas, alors np.split peut être utilisé pour créer la liste recommandée par calocedrus. Les opérations les plus simples sont les ufunc, car elles ne nécessitent presque aucune modification. Voici quelques exemples:

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

Dans numpy 1.14.3, en utilisant 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])]

ce que vous obtenez une liste de tableaux (qui peuvent être de différentes longueurs) et vous pouvez effectuer des opérations comme d[0].mean(). D'autre part,

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

résulte en un tableau de listes.

Vous voudrez peut-être faire ceci:

a1 = np.array([1,2,3])
a2 = np.array([3,4])
a3 = np.array([a1,a2])
a3 # array([array([1, 2, 3]), array([3, 4])], dtype=object)
type(a3) # numpy.ndarray
type(a2) # numpy.ndarray