Предположим, у меня есть массив:

from numpy import *
x = range(16)
x = reshape(x,(4,4))

print x
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]

И я хочу получить копию меньшего массива, который всегда центрирован в середине x, определяя размер этой матрицы (не индексы строки / столбца)

Например. если я хочу массив 2x2 из этого, он вернет:

[[5  6]
 [9 10]]

Для моих целей мой исходный массив больше (4096x4096), и я хочу взять копию массива среднего квадрата размеров (128x128), (256x256), (512x512), (1024x1024), (2048x2048).

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

Я думал об определении некоторых переменных, таких как (для случая 2x2):

rows_to_keep = [1,2]
cols_to_keep = [1,2]

А затем использовать

x[np.ix_(rows_to_keep, columns_to_keep)]

Но это становится непрактичным, когда мой rows_to_keep представляет собой список до 2048 номеров, например, Чтобы скопировать квадрат размером 128x128 из оригинала 4096x4096, я могу создать список индексов, который начинается со строки / столбца 1984 года и продолжается до 2112 года:

size_to_keep = 128
indices = np.linspace(0, size_to_keep, size_to_keep, endpoint=False)

rows_to_keep = [(4096/2)-(size_to_keep/2) + i for i in indices]
cols_to_keep = [(4096/2)-(size_to_keep/2) + i for i in indices]

copy_array = x[np.ix_(rows_to_keep, columns_to_keep)]    

Но опять это становится грязным / непрактичным. Я надеялся, что есть более питонический способ сделать это? заранее спасибо

1
rh1990 17 Сен 2018 в 17:11

2 ответа

Лучший ответ

Поскольку все ваши индексы непрерывны, вы можете просто использовать соответствующие slice. Очевидно, что вы не можете избежать вычисления экстремумов, но это все.

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

def get_center(arr, size):
    mask = tuple(
        slice(int(dim / 2 - size / 2), int(dim / 2 + size / 2))
        if 0 < size < dim else slice(None)
        for dim in arr.shape)
    return arr[mask].copy()

Который можно просто использовать как:

import numpy as np
dim = 4
x = np.arange(dim * dim).reshape((dim, dim))
y = get_center(x, 2)
# [[ 5,  6],
#  [ 9, 10]]

И работает как положено, но не занимая столько памяти.

Конечно, вы можете настроить свои экстремумы так, чтобы они справлялись со странными случаями так, как вам нравится (это не определено в вашем вопросе).

3
norok2 17 Сен 2018 в 14:58

Numpy работает с views , что означает, что когда вы делаете

extracted_middle_square = x[1:2,1:2]

Вы получаете представление о х (не копия, а х не изменяется). Если вы хотите создать новую переменную, то выполните

extracted_middle_square = x[1:2,1:2].copy()

Это должно решить вашу проблему.

2
Robin 17 Сен 2018 в 14:53