Dans Numpy, je peux concaténer deux tableaux de bout en bout avec np.append
ou np.concatenate
:
>>> X = np.array([[1,2,3]])
>>> Y = np.array([[-1,-2,-3],[4,5,6]])
>>> Z = np.append(X, Y, axis=0)
>>> Z
array([[ 1, 2, 3],
[-1, -2, -3],
[ 4, 5, 6]])
Mais ceux-ci font des copies de leurs tableaux d'entrée:
>>> Z[0,:] = 0
>>> Z
array([[ 0, 0, 0],
[-1, -2, -3],
[ 4, 5, 6]])
>>> X
array([[1, 2, 3]])
Y at-il un moyen de concaténer deux tableaux dans une vue , c’est-à-dire sans copier? Cela nécessiterait-il une sous-classe np.ndarray
?
La mémoire appartenant à un tableau Numpy doit être contiguë. Si vous allouez les tableaux séparément, ils sont dispersés de manière aléatoire dans la mémoire et il n’ya aucun moyen de les représenter sous forme de tableau Numpy.
Si vous connaissez à l'avance le nombre de tableaux dont vous avez besoin, vous pouvez commencer avec un grand tableau que vous avez alloué auparavant et que chacun des petits tableaux soit une vue du grand tableau (obtenu par exemple par découpage).
Il suffit d’initialiser le tableau avant de le remplir avec des données. Si vous le souhaitez, vous pouvez allouer plus d’espace que nécessaire et cela ne prendra pas plus de RAM en raison du fonctionnement de numpy.
A = np.zeros(R,C)
A[row] = [data]
La mémoire n'est utilisée qu'une fois les données placées dans le tableau. Créer un nouveau tableau à partir de la concaténation de deux ne se terminera jamais sur un jeu de données de toute taille, c'est-à-dire> 1 Go ou plus.
Pas vraiment élégant du tout, mais vous pouvez vous rapprocher de ce que vous voulez en utilisant un Tuple pour stocker des pointeurs sur les tableaux. Maintenant, je n'ai aucune idée de la façon dont je l'utiliserais dans le cas mais j'ai déjà fait des choses comme ça auparavant.
>>> X = np.array([[1,2,3]])
>>> Y = np.array([[-1,-2,-3],[4,5,6]])
>>> z = (X, Y)
>>> z[0][:] = 0
>>> z
(array([[0, 0, 0]]), array([[-1, -2, -3],
[ 4, 5, 6]]))
>>> X
array([[0, 0, 0]])
J'ai eu le même problème et j'ai fini par l'inverser, après avoir concaténé normalement (avec copie), j'ai réassigné les tableaux d'origine pour qu'ils deviennent des vues sur le tableau concaténé:
import numpy as np
def concat_no_copy(arrays):
""" Concats the arrays and returns the concatenated array
in addition to the original arrays as views of the concatenated one.
Parameters:
-----------
arrays: list
the list of arrays to concatenate
"""
con = np.concatenate(arrays)
viewarrays = []
for i, arr in enumerate(arrays):
arrnew = con[sum(len(a) for a in arrays[:i]):
sum(len(a) for a in arrays[:i + 1])]
viewarrays.append(arrnew)
assert all(arr == arrnew)
# return the view arrays, replace the old ones with these
return con, viewarrays
Vous pouvez le tester comme suit:
def test_concat_no_copy():
arr1 = np.array([0, 1, 2, 3, 4])
arr2 = np.array([5, 6, 7, 8, 9])
arr3 = np.array([10, 11, 12, 13, 14])
arraylist = [arr1, arr2, arr3]
con, newarraylist = concat_no_copy(arraylist)
assert all(con == np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14]))
for old, new in Zip(arraylist, newarraylist):
assert all(old == new)
La réponse est basée sur mon autre réponse dans Référence aux lignes ndarray dans ndarray
X = np.array([[1,2,3]])
Y = np.array([[-1,-2,-3],[4,5,6]])
Z = np.array([None, None, None])
Z[0] = X[0]
Z[1] = Y[0]
Z[2] = Y[1]
Z[0][0] = 5 # X would be changed as well
print(X)
Output:
array([[5, 2, 3]])
# Let's make it a function!
def concat(X, Y, copy=True):
"""Return an array of references if copy=False"""
if copy is True: # deep copy
return np.append(X, Y, axis=0)
len_x, len_y = len(X), len(Y)
ret = np.array([None for _ in range(len_x + len_y)])
for i in range(len_x):
ret[i] = X[i]
for j in range(len_y):
ret[len_x + j] = Y[j]
return ret
Vous pouvez créer un tableau de tableaux, comme:
>>> from numpy import *
>>> a = array([1.0, 2.0, 3.0])
>>> b = array([4.0, 5.0])
>>> c = array([a, b])
>>> c
array([[ 1. 2. 3.], [ 4. 5.]], dtype=object)
>>> a[0] = 100.0
>>> a
array([ 100., 2., 3.])
>>> c
array([[ 100. 2. 3.], [ 4. 5.]], dtype=object)
>>> c[0][1] = 200.0
>>> a
array([ 100., 200., 3.])
>>> c
array([[ 100. 200. 3.], [ 4. 5.]], dtype=object)
>>> c *= 1000
>>> c
array([[ 100000. 200000. 3000.], [ 4000. 5000.]], dtype=object)
>>> a
array([ 100., 200., 3.])
>>> # Oops! Copies were made...
Le problème est que cela crée des copies sur les opérations de diffusion (cela ressemble à un bogue).