236 votes

"Clonage" de vecteurs lignes ou colonnes

Il est parfois utile de "cloner" un vecteur ligne ou colonne en une matrice. Par clonage, j'entends la conversion d'un vecteur ligne tel que

[1, 2, 3]

Dans une matrice

[[1, 2, 3],
 [1, 2, 3],
 [1, 2, 3]]

ou un vecteur colonne tel que

[[1],
 [2],
 [3]]

en

[[1, 1, 1]
 [2, 2, 2]
 [3, 3, 3]]

Dans 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 cela en 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] ) fonctionne ? Existe-t-il un moyen de réaliser cette tâche en python de manière plus élégante ?

7 votes

Dans Matlab, notez qu'il est beaucoup plus rapide d'utiliser repmat : repmat([1 2 3],3,1) ou repmat([1 2 3].',1,3)

0 votes

Octave a également repmat .

0 votes

Pour ceux qui souhaitent faire la même chose avec un dataframe pandas, consultez la page tile_df lien ici

5voto

Jon Deaton Points 829

Une solution propre consiste à utiliser la fonction de produit extérieur de NumPy avec un vecteur de uns :

np.outer(np.ones(n), x)

donne n les rangs répétitifs. Inversez l'ordre des arguments pour obtenir des colonnes répétitives. Pour obtenir un nombre égal de lignes et de colonnes, vous pouvez faire

np.outer(np.ones_like(x), x)

4voto

thebeancounter Points 705

Vous pouvez utiliser

np.tile(x,3).reshape((4,3))

générera les reps du vecteur

et le remodelage lui donnera la forme souhaitée

4voto

Alex Fedotov Points 139

Pour en revenir à la question initiale

Dans MATLAB ou octave, cela se fait assez facilement :

x = [1, 2, 3]

a = ones(3, 1) * x ...

En numpy, c'est à peu près la même chose (et facile à mémoriser) :

x = [1, 2, 3]
a = np.tile(x, (3, 1))

sortie

array([[1, 2, 3],
       [1, 2, 3],
       [1, 2, 3]])

1voto

The Unfun Cat Points 1646

Si vous avez un dataframe pandas et que vous voulez préserver les dtypes, même les catégoriques, c'est un moyen rapide de le faire :

import numpy as np
import pandas as pd
df = pd.DataFrame({1: [1, 2, 3], 2: [4, 5, 6]})
number_repeats = 50
new_df = df.reindex(np.tile(df.index, number_repeats))

1voto

Dugas Points 83

Une autre solution

>> x = np.array([1,2,3])
>> y = x[None, :] * np.ones((3,))[:, None]
>> y
array([[ 1.,  2.,  3.],
       [ 1.,  2.,  3.],
       [ 1.,  2.,  3.]])

Pourquoi ? Bien sûr, la répétition et le carrelage sont la bonne façon de procéder. Mais l'indexation None est un outil puissant qui m'a souvent permis de vectoriser rapidement une opération (bien qu'elle puisse rapidement être très coûteuse en mémoire !).

Un exemple tiré de mon propre code :

# trajectory is a sequence of xy coordinates [n_points, 2]
# xy_obstacles is a list of obstacles' xy coordinates [n_obstacles, 2]
# to compute dx, dy distance between every obstacle and every pose in the trajectory
deltas = trajectory[:, None, :2] - xy_obstacles[None, :, :2]
# we can easily convert x-y distance to a norm
distances = np.linalg.norm(deltas, axis=-1)
# distances is now [timesteps, obstacles]. Now we can for example find the closest obstacle at every point in the trajectory by doing
closest_obstacles = np.argmin(distances, axis=1)
# we could also find how safe the trajectory is, by finding the smallest distance over the entire trajectory
danger = np.min(distances)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X