Рулон python numpy с отступом
Я хотел бы свернуть двумерный 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]])
Я мог бы сделать это с помощью нескольких неудобных прикосновений, но я надеюсь, что есть способ сделать это с помощью быстрых встроенных команд.
Спасибо
Ответы
Ответ 1
В версии 1.7.0 есть новая функция numpy numpy.pad
, которая может сделать это в одной строке. Пад кажется довольно мощным и может делать гораздо больше, чем простой "рулон". Кортеж ((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]]
Ответ 2
Я не думаю, что вы найдете более простой способ сделать это, встроенный. Прикосновение кажется мне довольно простым:
y = np.roll(x,1,axis=1)
y[:,0] = 0
Если вы хотите, чтобы это было более прямым, возможно, вы могли бы скопировать функцию roll на новую функцию и изменить ее, чтобы делать то, что вы хотите. Функция roll() находится в файле site-packages\core\numeric.py
.
Ответ 3
Я просто написал следующее. Его можно было бы оптимизировать, избегая 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
Ответ 4
Немного поздно, но он чувствует себя как бы быстрый способ сделать то, что вы хотите в одной строке. Возможно, это было бы лучше всего, если бы оно было включено в интеллектуальную функцию (пример ниже представлен только для горизонтальной оси):
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]]
Ответ 5
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
Эта функция будет работать на 2D-массивах и заменять свернутые значения постоянной по вашему выбору.
Ответ 6
Вы также можете использовать numpy triu и scipy.linalg circulant. Сделайте циркулярную версию вашей матрицы. Затем выберите верхнюю треугольную часть, начинающуюся с первой диагонали (опция по умолчанию в трио). Индекс строки будет соответствовать количеству нужных нулей.
Если у вас нет scipy, вы можете создать матрицу циркуляции nXn, создав (n-1) X (n-1) единичную матрицу и уложив в нее строку [0 0... 1] и столбец [1 0... 0] справа от него.
Ответ 7
Разрабатывая ответ на 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]