Je voudrais rouler un numpy 2D en python, sauf que je voudrais compléter les extrémités par des zéros plutôt que de rouler les données comme si elles étaient périodiques.
Plus précisément, le code suivant
import numpy as np
x = np.array([[1, 2, 3], [4, 5, 6]])
np.roll(x, 1, axis=1)
résultats
array([[3, 1, 2],[6, 4, 5]])
mais ce que je préférerais, c'est
array([[0, 1, 2], [0, 4, 5]])
Je pourrais le faire avec quelques retouches maladroites, mais j'espère qu'il sera possible de le faire avec des commandes intégrées rapides.
Merci
Il existe une nouvelle fonction numpy dans la version 1.7.0 numpy.pad
that can faire ceci en une ligne. Pad semble être assez puissant et peut faire beaucoup plus qu'un simple "roulement". Le tuple ((0,0),(1,0))
utilisé dans cette réponse indique le "côté" de la matrice à remplir.
import numpy as np
x = np.array([[1, 2, 3],[4, 5, 6]])
print np.pad(x,((0,0),(1,0)), mode='constant')[:, :-1]
Donnant
[[0 1 2]
[0 4 5]]
Je ne pense pas que vous allez trouver un moyen plus facile de faire cela qui est intégré. La retouche me semble assez simple:
y = np.roll(x,1,axis=1)
y[:,0] = 0
Si vous voulez que cela soit plus direct, vous pourriez peut-être copier la fonction de rouleau dans une nouvelle fonction et la changer pour faire ce que vous voulez. La fonction roll () se trouve dans le fichier site-packages\core\numeric.py
.
Je viens d'écrire ce qui suit. Cela pourrait être plus optimisé en évitant zeros_like
et en calculant directement la forme pour zeros
.
import numpy as np
def roll_zeropad(a, shift, axis=None):
"""
Roll array elements along a given axis.
Elements off the end of the array are treated as zeros.
Parameters
----------
a : array_like
Input array.
shift : int
The number of places by which elements are shifted.
axis : int, optional
The axis along which elements are shifted. By default, the array
is flattened before shifting, after which the original
shape is restored.
Returns
-------
res : ndarray
Output array, with the same shape as `a`.
See Also
--------
roll : Elements that roll off one end come back on the other.
rollaxis : Roll the specified axis backwards, until it lies in a
given position.
Examples
--------
>>> x = np.arange(10)
>>> roll_zeropad(x, 2)
array([0, 0, 0, 1, 2, 3, 4, 5, 6, 7])
>>> roll_zeropad(x, -2)
array([2, 3, 4, 5, 6, 7, 8, 9, 0, 0])
>>> x2 = np.reshape(x, (2,5))
>>> x2
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
>>> roll_zeropad(x2, 1)
array([[0, 0, 1, 2, 3],
[4, 5, 6, 7, 8]])
>>> roll_zeropad(x2, -2)
array([[2, 3, 4, 5, 6],
[7, 8, 9, 0, 0]])
>>> roll_zeropad(x2, 1, axis=0)
array([[0, 0, 0, 0, 0],
[0, 1, 2, 3, 4]])
>>> roll_zeropad(x2, -1, axis=0)
array([[5, 6, 7, 8, 9],
[0, 0, 0, 0, 0]])
>>> roll_zeropad(x2, 1, axis=1)
array([[0, 0, 1, 2, 3],
[0, 5, 6, 7, 8]])
>>> roll_zeropad(x2, -2, axis=1)
array([[2, 3, 4, 0, 0],
[7, 8, 9, 0, 0]])
>>> roll_zeropad(x2, 50)
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
>>> roll_zeropad(x2, -50)
array([[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]])
>>> roll_zeropad(x2, 0)
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
"""
a = np.asanyarray(a)
if shift == 0: return a
if axis is None:
n = a.size
reshape = True
else:
n = a.shape[axis]
reshape = False
if np.abs(shift) > n:
res = np.zeros_like(a)
Elif shift < 0:
shift += n
zeros = np.zeros_like(a.take(np.arange(n-shift), axis))
res = np.concatenate((a.take(np.arange(n-shift,n), axis), zeros), axis)
else:
zeros = np.zeros_like(a.take(np.arange(n-shift,n), axis))
res = np.concatenate((zeros, a.take(np.arange(n-shift), axis)), axis)
if reshape:
return res.reshape(a.shape)
else:
return res
import numpy as np
def shift_2d_replace(data, dx, dy, constant=False):
"""
Shifts the array in two dimensions while setting rolled values to constant
:param data: The 2d numpy array to be shifted
:param dx: The shift in x
:param dy: The shift in y
:param constant: The constant to replace rolled values with
:return: The shifted array with "constant" where roll occurs
"""
shifted_data = np.roll(data, dx, axis=1)
if dx < 0:
shifted_data[:, dx:] = constant
Elif dx > 0:
shifted_data[:, 0:np.abs(dx)] = constant
shifted_data = np.roll(shifted_data, dy, axis=0)
if dy < 0:
shifted_data[dy:, :] = constant
Elif dy > 0:
shifted_data[0:np.abs(dy), :] = constant
return shifted_data
Cette fonction fonctionnerait sur des tableaux 2D et remplacerait les valeurs laminées par une constante de votre choix.
Un peu tard, mais cela semble être un moyen rapide de faire ce que vous voulez en une ligne. Cela fonctionnerait peut-être mieux s'il était intégré à une fonction intelligente (l'exemple ci-dessous est fourni uniquement pour l'axe horizontal):
import numpy
a = numpy.arange(1,10).reshape(3,3) # an example 2D array
print a
[[1 2 3]
[4 5 6]
[7 8 9]]
shift = 1
a = numpy.hstack((numpy.zeros((a.shape[0], shift)), a[:,:-shift]))
print a
[[0 1 2]
[0 4 5]
[0 7 8]]
Expliciter la réponse de Hooked (puisqu'il m'a fallu quelques minutes pour la comprendre)
Le code ci-dessous remplit d'abord un certain nombre de zéros dans les marges supérieure, inférieure, gauche et droite, puis sélectionne la matrice d'origine à l'intérieur de la première. Un code parfaitement inutile, mais bon pour comprendre np.pad
.
import numpy as np
x = np.array([[1, 2, 3],[4, 5, 6]])
y = np.pad(x,((1,3),(2,4)), mode='constant')[1:-3,2:-4]
print np.all(x==y)
maintenant pour faire un décalage vers le haut de 2 combiné avec un décalage vers la droite de 1 position on devrait faire
print np.pad(x,((0,2),(1,0)), mode='constant')[2:0,0:-1]
Vous pouvez également utiliser les circulants numu et triip et scipy.linalg. Faites une version circulante de votre matrice. Ensuite, sélectionnez la partie triangulaire supérieure en commençant par la première diagonale (option par défaut dans triu). L'index de ligne correspond au nombre de zéros remplis que vous souhaitez.
Si vous n'avez pas scipy, vous pouvez générer une matrice circulante nXn en créant une matrice d'identité (n-1) X (n-1) et en empilant une ligne [0 0 ... 1] et la colonne [ 1 0 ... 0] à droite de celui-ci.