简体   繁体   中英

R - Resize a 3D array by removing all-zeros 2D matrices of the x, y, and z dimensions

Is there any function in R, Python, Lua, Java, Matlab or any programming language that can reduce the size of the 3D input_array from c(6, 6, 6) to c(4, 4, 4) by deleting all-zero matrices on the periphery of the 3 dimensions?

## Create an empty array with all zeros
input_array <- array(data = c(0), dim = c(6, 6, 6)) 

## Populate the central locations of the array with 1
input_array[, ,2:5] <- matrix(c(0, 0, 0, 0, 0, 0, 
                                0, 1, 1, 1, 1, 0,  
                                0, 1, 1, 1, 1, 0, 
                                0, 1, 1, 1, 1, 0, 
                                0, 1, 1, 1, 1, 0, 
                                0, 0, 0, 0, 0, 0), 
                                nrow = 6, ncol = 6) 

## Show the input_array
input_array 

## The target output
output_array <- array(data = c(1), dim = c(4, 4, 4)) 

So, in other words, I am looking for a function that takes the input_array as an input and spits the output_array as an output. I want to maintain the 3D nature of the array throughout the conversion. The reason I am looking into this, is that I have very large 3D arrays with lots of zeros around the periphery and by removing all-zeros matrices out of the three dimensions, I can achieve considerable reduction in the sizes of these arrays and hence allow for more efficient processing.

In case there is no function out there, what could be a logic to write a new function so as to get this done? Use whatever language you prefer if you have anything to share, any feedback or help is very much appreciated.

You can do reasonably well in R with the help of the abind package, which is handy for dealing with arrays:

abind::asub(input_array,    # take this and subset
            lapply(1:3, function(d){    # iterate over its dimensions
                apply(input_array != 0, d, any)    # look for any non-zero elements
            }))
## , , 1
## 
##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    1
## [2,]    1    1    1    1
## [3,]    1    1    1    1
## [4,]    1    1    1    1
## 
## , , 2
## 
##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    1
## [2,]    1    1    1    1
## [3,]    1    1    1    1
## [4,]    1    1    1    1
## 
## , , 3
## 
##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    1
## [2,]    1    1    1    1
## [3,]    1    1    1    1
## [4,]    1    1    1    1
## 
## , , 4
## 
##      [,1] [,2] [,3] [,4]
## [1,]    1    1    1    1
## [2,]    1    1    1    1
## [3,]    1    1    1    1
## [4,]    1    1    1    1

Thanks for all of those who shared their thoughts or cited other similar posts. I reached this through your answers:

## Create an empty array with all zeros
input_array <- array(data = c(0), dim = c(6, 6, 6)) 

## Populate the central locations of the array with 1
input_array[, ,2:5] <- matrix(c(0, 0, 0, 0, 0, 0, 
                                0, 1, 1, 1, 1, 0,  
                                0, 1, 1, 1, 1, 0, 
                                0, 1, 1, 1, 1, 0, 
                                0, 1, 1, 1, 1, 0, 
                                0, 0, 0, 0, 0, 0), 
                                nrow = 6, ncol = 6) 

## Show the input_array
input_array 

## The target output
(output_array <- input_array[apply(input_array != 0, 3, any),
                             apply(input_array != 0, 2, any),
                             apply(input_array != 0, 1, any)])  

I haven't tested it with different inputs, so further testing for different inputs may need to be performed.

Here's one option ( python / numpy ):

xcrit = np.where(np.any(input, axis=(0,1)))[0]
ycrit = np.where(np.any(input, axis=(0,2)))[0]
zcrit = np.where(np.any(input, axis=(1,2)))[0]
output = input[zcrit[0]:zcrit[-1]+1,ycrit[0]:ycrit[-1]+1,xcrit[0]:xcrit[-1]+1]

explanation np.any returns True if along the dimensions passed at least one cell is True. it returns a boolean array shaped like the remaining dimensions

np.where finds the indices of the True cells of its argument. in this example we use it to find the indices of the first and last not-all-zero slice along each coordinate

Sample run:

>>> input = np.zeros((6,6,6))
>>> input[1:-2,1:-2,2:-1] = 1
>>> xcrit = np.where(np.any(input, axis=(0,1)))[0]
>>> ycrit = np.where(np.any(input, axis=(0,2)))[0]
>>> zcrit = np.where(np.any(input, axis=(1,2)))[0]
>>> output = input[zcrit[0]:zcrit[-1]+1,ycrit[0]:ycrit[-1]+1,xcrit[0]:xcrit[-1]+1]
>>> # verify
... input.sum(), output.sum(), output.size
(27.0, 27.0, 27)

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