web-dev-qa-db-fra.com

rouleau de python numpy avec rembourrage

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

32
marshall.ward

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]]
27
Hooked

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.

14
Justin Peel

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
4
Ken Arnold
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.

2
NanoBennett

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]]
2
heltonbiker

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]
0
HerrIvan

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. 

0
mac389