Ответ 1
numpy.take
в режиме 'wrap'
будет использовать ваши индексы по модулю длины массива.
indices = range(i-2,i+3)
neighbourhood = A.take(indices, mode='wrap')
Подробнее см. документацию numpy.take
У меня есть массив numpy, и я хочу получить "окрестности" i-й точки. Обычно массивы, которые я использую, являются двумерными, но следующий пример 1D иллюстрирует то, что я ищу. Если
A = numpy.array([0,10,20,30,40,50,60,70,80,90])
Тогда окрестность элемента (размер 5) элемента 4 равна [20,30,40,50,60]
, и это легко получить, выполняя A[i-2:i+3]
.
Однако мне также нужны окрестности для "обертывания" краев массива, так что окрестность элемента 0 равна [80,90,0,10,20]
, а окрестность элемента 9 равна [70,80,90,0,10]
. Кажется, я не могу найти элегантный способ сделать это, поэтому в конечном итоге мне приходится использовать сложную, раздражающую логику каждый раз, когда это появляется (что очень часто для меня). В двумерном случае окрестность точки будет прямоугольным массивом.
Итак, мой вопрос: есть ли опрятный способ выражения этой операции "округление окрестности" в numpy? Я бы предпочел что-то, что возвращает фрагмент, а не копию, но читаемость и скорость являются наиболее важными соображениями.
numpy.take
в режиме 'wrap'
будет использовать ваши индексы по модулю длины массива.
indices = range(i-2,i+3)
neighbourhood = A.take(indices, mode='wrap')
Подробнее см. документацию numpy.take
вы можете использовать аргумент axis=0
для numpy.take
для массива n-d.
A = zip(range(0,101,10),range(0,11)) #create 2-d list
A = numpy.array(A) #create 2-d array
indices = range(i-2,i+3)
neightbourhood = A.take(indices,axis=0,mode='wrap')
Тот же axis=0
будет работать для измерений n * m...
Я знаю, что этот вопрос старый, но следует упомянуть scipy.ndimage.filter.generic_filter.
Он имеет параметр mode='wrap'
, плюс он обрабатывает приложение соседней функции.
import scipy.ndimage as nd
A = np.array([0,10,20,30,40,50,60,70,80,90])
Скажите, что у вас есть соседняя функция:
def nbf(arr):
return sum(arr)
Чтобы применить соседнюю функцию к каждому 5, с обернутыми значениями по краям:
C = nd.generic_filter(A, nbf, 5, mode='wrap')
print(C)
[200 150 100 150 200 250 300 350 300 250]
Примечание. В случаях, когда ваши соседи не требуют обертывания, numpy.take
работает медленнее, чем просто взять срез A[i-2:i+3]
. Вы можете обернуть функцию соседей с помощью некоторых условных операторов:
def neighbors(a,i,n):
N = a.shape[0]
if i - n < 0 and i + n > 0:
indices = range(i-n,i+n+1)
nbrs = a.take(indices, mode='wrap')
elif i-n < N - 1 and i+n > N - 1:
indices = range(i-n,i+n+1)
nbrs = a.take(indices, mode='wrap')
else:
nbrs = a[i-n:i+n+1]
return nbrs
Если вы обнаружите, что принимаете соседей при повторении через массив, например, в центрированной скользящей средней, вы обнаружите, что для этого требуется меньше времени, особенно для более длинных массивов:
Вот скользящая средняя функция, которую я использовал:
def moving_average(a,n=1):
N = a.shape[0]
ma = np.empty(N)
for i in range(N):
if n*2+1 > N:
ma[i] = a.mean()
else:
ma[i] = neighbors(a,i,n).mean()
return ma
Я уверен, что эти функции могут быть улучшены. Я открыт для предложений.
Вы можете использовать процедуру np.pad следующим образом:
A = np.array([0,10,20,30,40,50,60,70,80,90])
A = np.pad(A, 2, 'wrap')
print(A)
[80, 90, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 0, 10]
Скажите, что у вас есть соседняя функция:
def nbf(arr):
return sum(arr)
Чтобы применить соседнюю функцию к каждому 5, вам нужно быть осторожным относительно ваших начальных и конечных индексов (в команде диапазона (...)) и относительного фрагмента, который вы берете из A.
B = [nbf(A[i-2:i+3]) for i in range(2,12)]
print(B)
[200, 150, 100, 150, 200, 250, 300, 350, 300, 250]
numpy.roll может смещать массив таким образом, чтобы весь срез находился в начале массива. Затем возьмите свой срез в начале и numpy.roll еще раз, чтобы вернуть массив обратно в исходное положение.
# modify array at index i and nearest two
# locations on each side of i, wrapping
# around the edges
A = np.array([0,10,20,30,40,50,60,70,80,90])
i = 9
neighbors = 2
A=np.roll(A, -i+neighbors)
A[:5] += 1
A=np.roll(A, i-neighbors)
array([ 1, 11, 20, 30, 40, 50, 60, 71, 81, 91])
numpy.roll не работает хорошо для меня на больших массивах.