питон ролл с обивкой - PullRequest
32 голосов
/ 06 мая 2010

Я хотел бы бросить двумерный numpy в Python, за исключением того, что я хотел бы дополнить концы нулями, а не свернуть данные, как если бы они были периодическими.

В частности, следующий код

import numpy as np

x = np.array([[1, 2, 3], [4, 5, 6]])

np.roll(x, 1, axis=1)

возвращает

array([[3, 1, 2],[6, 4, 5]])

но я бы предпочел это

array([[0, 1, 2], [0, 4, 5]])

Я мог бы сделать это с помощью нескольких неловких касаний, но я надеюсь, что есть способсделать это с помощью быстрых встроенных команд.

Спасибо

Ответы [ 7 ]

28 голосов
/ 06 мая 2013

В версии 1.7.0 numpy.pad появилась новая функция numpy, которая может сделать это в одну строку. Пад кажется довольно мощным и может сделать гораздо больше, чем простой «крен». Кортеж ((0,0),(1,0)), использованный в этом ответе, указывает «сторону» матрицы, которую нужно дополнить.

import numpy as np
x = np.array([[1, 2, 3],[4, 5, 6]])

print np.pad(x,((0,0),(1,0)), mode='constant')[:, :-1]

Предоставление

[[0 1 2]
 [0 4 5]]
14 голосов
/ 06 мая 2010

Я не думаю, что вы найдете более простой способ сделать это встроенным. Мне кажется, что этот штрих довольно прост:

y = np.roll(x,1,axis=1)
y[:,0] = 0

Если вы хотите, чтобы это было более прямым, то, возможно, вы могли бы скопировать функцию прокрутки в новую функцию и изменить ее на то, что вы хотите. Функция roll () находится в файле site-packages\core\numeric.py.

4 голосов
/ 01 июля 2010

Я только что написал следующее. Его можно было бы оптимизировать, избегая zeros_like и просто вычисляя форму для 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
3 голосов
/ 18 февраля 2015
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

Эта функция будет работать с двумерными массивами и заменять полученные значения константой по вашему выбору.

2 голосов
/ 14 ноября 2012

Немного поздно, но похоже на быстрый способ сделать то, что вы хотите в одной строке. Возможно, будет лучше всего работать, если обернут в интеллектуальную функцию (пример ниже представлен только для горизонтальной оси):

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]]
0 голосов
/ 22 октября 2015

Разработка ответа Hooked (так как мне понадобилось несколько минут, чтобы понять его)

Код ниже сначала дополняет определенное количество нулей в полях вверх, вниз, влево и вправо, а затем выбирает исходную матрицу внутри дополняемой. Совершенно бесполезный код, но полезный для понимания 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)

теперь, чтобы сделать сдвиг вверх на 2 в сочетании со сдвигом вправо на 1 позицию, нужно сделать

print np.pad(x,((0,2),(1,0)), mode='constant')[2:0,0:-1]
0 голосов
/ 17 августа 2011

Вы также можете использовать триу numpy и циркулянт scipy.linalg. Сделайте циркулянтную версию своей матрицы. Затем выберите верхнюю треугольную часть, начиная с первой диагонали (опция по умолчанию в triu). Индекс строки будет соответствовать нужному количеству дополненных нулей.

Если у вас нет scipy, вы можете сгенерировать циркулянтную матрицу nXn, сделав (n-1) X (n-1) единичную матрицу и сложив строку [0 0 ... 1] поверх нее и столбец [1 0 ... 0] справа от него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...