Parfois, il est utile de "cloner" un vecteur ligne ou colonne sur une matrice. Par clonage, je veux dire convertir un vecteur de rangée tel que
[1,2,3]
Dans une matrice
[[1,2,3]
[1,2,3]
[1,2,3]
]
ou un vecteur de colonne tel que
[1
2
3
]
dans
[[1,1,1]
[2,2,2]
[3,3,3]
]
En matlab ou octave, cela se fait assez facilement:
x = [1,2,3]
a = ones(3,1) * x
a =
1 2 3
1 2 3
1 2 3
b = (x') * ones(1,3)
b =
1 1 1
2 2 2
3 3 3
Je veux répéter ceci numpy, mais sans succès
In [14]: x = array([1,2,3])
In [14]: ones((3,1)) * x
Out[14]:
array([[ 1., 2., 3.],
[ 1., 2., 3.],
[ 1., 2., 3.]])
# so far so good
In [16]: x.transpose() * ones((1,3))
Out[16]: array([[ 1., 2., 3.]])
# DAMN
# I end up with
In [17]: (ones((3,1)) * x).transpose()
Out[17]:
array([[ 1., 1., 1.],
[ 2., 2., 2.],
[ 3., 3., 3.]])
Pourquoi la première méthode (In [16]) ne fonctionnait-elle pas? Existe-t-il un moyen de réaliser cette tâche dans python de manière plus élégante?
Voici une manière élégante et pythonique de le faire:
>>> array([[1,2,3],]*3)
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
>>> array([[1,2,3],]*3).transpose()
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
le problème avec [16]
semble être que la transposition n'a aucun effet sur un tableau. vous voulez probablement une matrice à la place:
>>> x = array([1,2,3])
>>> x
array([1, 2, 3])
>>> x.transpose()
array([1, 2, 3])
>>> matrix([1,2,3])
matrix([[1, 2, 3]])
>>> matrix([1,2,3]).transpose()
matrix([[1],
[2],
[3]])
Utilisation numpy.tile
:
>>> tile(array([1,2,3]), (3, 1))
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
ou pour répéter des colonnes:
>>> tile(array([[1,2,3]]).transpose(), (1, 3))
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
Notez tout d'abord qu'avec les opérations de numpy's broadcast, il n'est généralement pas nécessaire de dupliquer des lignes et des colonnes. Voir this et this pour les descriptions.
Mais pour ce faire, ( répétez et newaxis sont probablement le meilleur moyen
In [12]: x = array([1,2,3])
In [13]: repeat(x[:,newaxis], 3, 1)
Out[13]:
array([[1, 1, 1],
[2, 2, 2],
[3, 3, 3]])
In [14]: repeat(x[newaxis,:], 3, 0)
Out[14]:
array([[1, 2, 3],
[1, 2, 3],
[1, 2, 3]])
Cet exemple concerne un vecteur ligne, mais son application à un vecteur colonne est, espérons-le, évidente. La répétition semble bien épeler, mais vous pouvez aussi le faire par multiplication comme dans votre exemple
In [15]: x = array([[1, 2, 3]]) # note the double brackets
In [16]: (ones((3,1))*x).transpose()
Out[16]:
array([[ 1., 1., 1.],
[ 2., 2., 2.],
[ 3., 3., 3.]])
Je pense que l'utilisation de la diffusion numpy est la meilleure solution, et plus rapide
J'ai fait une comparaison comme suit
import numpy as np
b = np.random.randn(1000)
In [105]: %timeit c = np.tile(b[:, newaxis], (1,100))
1000 loops, best of 3: 354 µs per loop
In [106]: %timeit c = np.repeat(b[:, newaxis], 100, axis=1)
1000 loops, best of 3: 347 µs per loop
In [107]: %timeit c = np.array([b,]*100).transpose()
100 loops, best of 3: 5.56 ms per loop
environ 15 fois plus rapide en utilisant la diffusion
np.broadcast_to
est encore plus rapide que np.tile
:
x = np.arange(9)
%timeit np.broadcast_to(x, (6,9))
100000 loops, best of 3: 3.6 µs per loop
%timeit np.tile(x, (6,1))
100000 loops, best of 3: 8.4 µs per loop
Mais le plus rapide est la méthode de @ tom10:
%timeit np.repeat(x[np.newaxis, :], 6, axis=0)
100000 loops, best of 3: 3.15 µs per loop
Vous pouvez utiliser
np.tile(x,3).reshape((4,3))
la tuile générera les représentants du vecteur
et remodeler donnera la forme que vous voulez
Une solution simple consiste à utiliser la fonction de produit externe de NumPy avec un vecteur de ceux-ci:
np.outer(np.ones(n), x)
donne n
répétant les lignes. Changer l'ordre des arguments pour obtenir des colonnes répétitives. Pour obtenir un nombre égal de lignes et de colonnes, vous pouvez le faire
np.outer(np.ones_like(x), x)
import numpy as np
x=np.array([1,2,3])
y=np.multiply(np.ones((len(x),len(x))),x).T
print(y)
rendements:
[[ 1. 1. 1.]
[ 2. 2. 2.]
[ 3. 3. 3.]]