web-dev-qa-db-fra.com

"Clonage" vecteurs de lignes ou de colonnes

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?

127
Boris Gorelik

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]])
64
Peter

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]])
249
pv.

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.]])
33
tom10

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

8
smartkevin

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
6
Mateen Ulhaq

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

2
thebeancounter

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)
2
Jon Deaton
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.]]
0
kibitzforu