简体   繁体   中英

How to sample a huge 2D array in Python using 2x2 arrays to create a dictionary? (Stencil Algorithm for Python)

I am rather new to programming, so I apologise if this is a classic and trivial question. I have a 100x100 2D array of values which is plotted by means of matplotlib . In this image, each cell has its value (ranging 0.0 to 1.0 ) and ID (ranging 0 to 9999 starting from the upper left corner). I want to sample the matrix by using a 2x2 moving window which produces two dictionaries :

  • 1st dictionary: the key represents the intersection of 4 cells; the value represents the tuple with the IDs of the 4 neighboring cells (see image below - the intersection is represented by "N" );
  • 2nd dictionary: the key represents the intersection of 4 cells; the value represents the mean value of the 4 neighboring cells (see image below).

In the example below ( upper left panel ), where N has ID=0, the 1st dictionary would yield {'0': (0,1,100,101)} since the cells are numbered 0 to 99 toward the right hand side and 0 to 9900, step=100, downward. The 2nd dictionary would yield {'0': 0.775} , as 0.775 is the average value of the 4 neighboring cells of N. Of course, these dictionaries must have as many keys as "intersections" I have on the 2D array.

How can this be accomplished? And are dictionaries the best "tool" in this case? Thank you guys!

在此处输入图片说明

PS: I tried my own way but my code is incomplete, wrong, and I cannot get my head around it:

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]
            ...

Well, dictionaries may in fact be the way in your case.

Are you sure that the numpy.array format you're using is correct? I don't find any array((int, int)) form in the API. anyway...

What to do once you have your 2D array declared

To make things ordered, let's make two functions that will work with any square 2D array, returning the two dictionaries that you need:

#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")

Compared to the first code, i prefered using an integer as a key cause python will print the dictionary sorted in that case (dictionaries are by definition unsorted, but if they have int keys Python will print them out sorted by key). However, you can change it back to a string just using str(count) as I did before.

I hope this will help, now I'm not very practical with math libraries, but the code that I wrote should work well with any 2D square array that you may want to put as an input!

Let's say data is the original numpy.array with dimension dr and dc for rows and columns.

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

You could produce Keys as a function that return indices of interest and Values as a list with computed mean of 4 neighbouring cells. In that case, Keys is equal to:

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

The dimension of Values is equal to dr-1 * dc-1 since the last row and column is not included. We can compute it as a moving average and reshape to 1D later, (inspiration from link ):

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

Example:

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])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM