Как сэмплировать огромный 2D-массив в Python, используя массивы 2x2 для создания словаря? (Алгоритм трафарета для Python)

Я новичок в программировании, поэтому прошу прощения, если это классический и тривиальный вопрос. У меня есть 100x100 2D-массив значений, который построен с помощью matplotlib. На этом изображении каждая ячейка имеет свое значение (от 0.0 до 1.0) и идентификатор (от 0 до 9999, начиная с левого верхнего угла). Я хочу сэмплировать матрицу, используя движущееся окно 2x2, которое создает два словаря:

  • 1-й словарь: ключ представляет собой пересечение 4 ячеек; значение представляет кортеж с идентификаторами 4 соседних ячеек (см. изображение ниже — пересечение представлено "N");
  • 2-й словарь: ключ представляет пересечение 4 ячеек; значение представляет собой среднее значение 4 соседних ячеек (см. изображение ниже).

В приведенном ниже примере (верхняя левая панель), где N имеет ID=0, первый словарь даст {'0': (0,1,100,101)}, поскольку ячейки пронумерованы от 0 до 99 справа и от 0 до 9900, step= 100, вниз. Второй словарь даст {'0': 0.775}, так как 0,775 — это среднее значение 4 соседних ячеек N. Конечно, эти словари должны иметь столько ключей, сколько «пересечений» у меня есть в 2D-массиве.

Как это можно сделать? И являются ли словари лучшим «инструментом» в этом случае? Спасибо, ребята!

введите здесь описание изображения

PS: я пробовал по-своему, но мой код неполный, неправильный, и я не могу понять его:

a=... #The 2D array which contains the cell values ranging 0.0 to 1.0
neigh=numpy.zeros(4)
mean_neigh=numpy.zeros(10000/4)
for k in range(len(neigh)):
    for i in a.shape[0]:
        for j in a.shape[1]:
            neigh[k]=a[i][j]
            ...

person FaCoffee    schedule 19.10.2015    source источник
comment
Я не знаю, может ли это помочь, но, по крайней мере, я могу сказать, что то, что вы описываете, широко известно как алгоритм трафарета, который представляет собой своего рода двумерный фильтр с конечной импульсной характеристикой. Если у вас есть S сэмплов и с учетом вашего шаблона, вам следует подумать о переходе матрицы от 1 до S (не от 0 до S) и применить любую операцию, которую вы описываете.   -  person Emilien    schedule 19.10.2015
comment
Это начало :) в любом случае спасибо!   -  person FaCoffee    schedule 19.10.2015


Ответы (2)


Что ж, словари действительно могут быть кстати в вашем случае.

Вы уверены, что используемый вами формат numpy.array верен? Я не нахожу форму массива ((int, int)) в API. тем не мение...

Что делать после объявления двумерного массива

Чтобы навести порядок, давайте сделаем две функции, которые будут работать с любым квадратным 2D-массивом, возвращая два нужных вам словаря:

#this is the one that returns the first dictionary
def dictionarize1(array):
    dict1 = {}
    count = 0
    for x in range(len(array[0]) - 1) :
        for y in range(len(array[0]) - 1):
            dict1[count] = [array[x][y], array[x][y+1], array[x+1][y], array[x + 1][y+1]]
            count = count + 1
    return dict1

def dictionarize2(array):
    dict2 = {}
    counter = 0
    for a in range(len(array[0]) - 1) :
        for b in range(len(array[0]) - 1):
            dict2[counter] = (array[a][b] + array[a][b+1] + array[a+1][b] + array[a + 1][b+1])/4
            counter = counter + 1
    return dict2

#here's a little trial code to see them working

eighties = [[2.0, 2.2, 2.6, 5.7, 4.7], [2.1, 2.3, 2.3, 5.8, 1.6], [2.0, 2.2, 2.6, 5.7, 4.7],[2.0, 2.2, 2.6, 5.7, 4.7],[2.0, 2.2, 2.6, 5.7, 4.7]]
print("Dictionarize1: \n")
print(dictionarize1(eighties))
print("\n\n")
print("Dictionarize2: \n")
print(dictionarize2(eighties))
print("\n\n")

По сравнению с первым кодом я предпочел использовать целое число в качестве ключа, потому что в этом случае python будет печатать отсортированный словарь (словари по определению не сортируются, но если у них есть ключи int, Python будет печатать их, отсортированные по ключу). Однако вы можете изменить его обратно на строку, просто используя str(count), как я делал раньше.

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

person Community    schedule 19.10.2015
comment
Вы абсолютно правы насчет формата массива. На самом деле я изменил свой блок кода, хотя он бесполезен, поскольку в нем не упоминаются слова... - person FaCoffee; 19.10.2015
comment
Я сделал последнее исправление, теперь пробный код тоже должен работать. В любом случае, если вы найдете способ объявить массив, который вы хотите, этот код должен работать. - person ; 19.10.2015
comment
На самом деле массив a происходит из строки numpy.genfromtxt(directoryPath, delimiter=","). Позже он преобразуется в список. - person FaCoffee; 19.10.2015
comment
Итак, вы бы поместили список в качестве ввода или массив? - person ; 19.10.2015
comment
Массив numpy преобразуется в list, и именно этот список будет обрабатываться. Я думал, что это лучший способ выполнить эту работу. Интересно, какова была бы скорость этих двух фрагментов кода с массивом 10201x1... - person FaCoffee; 19.10.2015
comment
Ммм... не могли бы вы оставить массив массивов (так работают 2D-массивы)? Это будет быстрее, чем списки, если я не ошибусь, и мой код будет работать с этим. Хотя это должно работать и со списком списков, так как способ доступа к их параметрам одинаков. - person ; 19.10.2015
comment
Попался. Два глупых вопроса: 1) Смогу ли я получить доступ к одному из списков, которые создает функция dictionarize1? Я надеюсь на это, но поскольку я совершенно не знаком с dictionaries, мне нужно понять; 2) Как вывод dictionarize1 может показать правильное количество ключей? У меня есть 10000 ключей и 10201 ячеек, поэтому какая строка указывает dict считать от 0 до 9999? - person FaCoffee; 19.10.2015
comment
Как вывод dictionarize1 может показать правильное количество ключей? У меня есть 10000 ключей и 10201 ячейка для сопоставления, так какая строка указывает dict считать от 0 до 9999? - person FaCoffee; 26.10.2015
comment
Все очень просто: словари — это просто списки, у которых в качестве ключа может быть что угодно, это значит, что вы можете, например, создать словарь, в котором в качестве ключей используются животные, а в качестве значения — количество их лап: dict = {} - person ; 03.11.2015
comment
Не знаю, почему нет отступа, надеюсь, вы понимаете то же самое: dict = {} dict['cat'] = 4 dict['bird'] = 2 dict['spider'] = 8 Итак, чтобы получить доступ к элементы словаря, которые создают функции dictionarize, вам просто нужно сказать (со ссылкой на пример кода, который я разместил выше): simba = dictionarize1(eighties) number = simba[x] Где x может быть любым числом от 0 до (rows - 1)*(столбцы - 1). - person ; 03.11.2015

Допустим, data — это исходное numpy.array с размерностью dr и dc для строк и столбцов.

dr = data.shape[0]
dc = data.shape[1]

Вы можете создать Keys как функцию, которая возвращает интересующие индексы, и Values как список с вычисленным средним значением 4 соседних ячеек. В этом случае Keys равно:

def Keys(x):
    xmod = x + (x+1)/dc  # dc is in scope
    return [xmod, xmod + 1, xmod + dc, xmod + 1 + dc]

Размерность Values равна dr-1 * dc-1, так как последняя строка и столбец не включены. Мы можем вычислить его как скользящее среднее и изменить форму на 1D позже (на основе ссылка):

Values = ((d[:-1,:-1] + d[1:,:-1] + d[:-1,1:] + d[1:,1:])/4).reshape((dr-1)*(dc-1))

Пример:

dr = 3
dc = 5

In: np.array(range(dc*dr)).reshape((dr, dc))  # data
Out: 
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])

In: [Keys(x) for x in range((dr-1)*(dc-1))]
Out: 
    [[0, 1, 5, 6],
     [1, 2, 6, 7],
     [2, 3, 7, 8],
     [3, 4, 8, 9],
     [5, 6, 10, 11],
     [6, 7, 11, 12],
     [7, 8, 12, 13],
     [8, 9, 13, 14]]

In: Values
Out: array([ 3,  4,  5,  6,  8,  9, 10, 11])
person toine    schedule 19.10.2015
comment
если ваш массив огромен, наличие Keys в качестве функции сэкономит вам много памяти, а использование numpy нарезки и векторизации сэкономит ваше время. - person toine; 19.10.2015
comment
Ну, это выглядит очень красиво, хотя и обеспечивает некоторую обертку, если я не ошибаюсь. Пятая строка вашего матричного вывода должна читаться как [5,6,10,11] вместо [4,5,9,10]. В моей модели не допускается обертывание. Извините, что не указал на это раньше. - person FaCoffee; 19.10.2015
comment
правильно, я изменил код - была ошибка целочисленного деления в функции Keys line 1 - person toine; 19.10.2015
comment
Мой исходный массив состоит из 10201 значений, поэтому он довольно большой. Но мне, новичку, эти строки кажутся немного сложными для понимания. Values не является частью функции Keys, верно? Кроме того, я хотел бы иметь словарь в качестве вывода, а не список. Это облегчит мне чтение результатов. - person FaCoffee; 19.10.2015
comment
для интересующей ячейки X вы получаете значение mean из Values[X] и индексы, из которых эта mean была построена из Keys(X). Это не словари, но я не думаю, что вам это нужно. - person toine; 19.10.2015
comment
Я вижу вашу точку зрения. В любом случае, есть и другие словари, связанные с более широкой картиной, и они полезны, поскольку: 1) они связывают окрестность [0,1,5,6] с идентификатором пересечения (в данном случае 0); 2) Каждый идентификатор пересечения связан со значением, полученным в результате другого вычисления, и я должен иметь возможность их связать; 3) будет создан другой словарь, сопоставляющий идентификатор пересечения со средним значением 4 соседних ячеек. Поэтому словари выглядят броско, так как работа с массивами наверняка запутает меня при анализе данных. - person FaCoffee; 19.10.2015
comment
Ключи как функция делают то же самое, как если бы это был словарь, с той лишь разницей, что вы вызываете ее с помощью (). Что касается значений, то он делает 3) и работает так же, как словарь. - person toine; 19.10.2015