# Binning a 2D array

Hi,

I am trying to apply my understanding of image binning in Julia (which at its heart is an operation that needs to be performed on a 2D array) . To that end I created a toy array

``````julia> a = rand(range(0,1,step=1),10,10)
10×10 Array{Int64,2}:
0  1  0  1  1  0  0  0  1  0
1  0  1  0  1  0  1  1  0  0
0  1  0  0  1  1  0  1  0  0
0  0  0  0  0  1  0  1  1  0
1  1  1  0  0  0  1  0  1  0
0  0  1  0  0  1  0  0  0  1
0  0  1  1  0  1  0  0  1  1
0  1  0  0  1  0  0  0  1  1
0  1  1  0  0  0  0  1  0  1
1  0  1  0  1  1  0  1  1  0
``````

Now lets say, that I want to bin the data by 2 which in this case, would be a 2x2 kernel to that end I could grasp the logic as follows:

``````b=[]
julia> append!(b,a[1]+a[1,1]+a[2]+a[1,2])/2
1-element Array{Float64,1}:
1.0
julia> b
1-element Array{Any,1}:
2
``````

I guess, where I am stuck is coding a loop that will raster the kernel along a height and width of an input array and return a new array that is a fraction of the input size which in this case would be a 5x5 array.

is there a specific question you wanna ask?

Yes, i think the specific question is, how do you raster along the dimensions of an array such that the resultatnt array is a fraction of its size. eg. a 10x10 array is now a 5x5 array because each element in the smaller array is an average of a 2x2 kernel.

https://juliaimages.org/latest/pkgs/transformations/#Examples there’s existing library that can do this.

To continue where you were originally doing, you want to make a `b` that is `5x5` and then, for each `b[i,j]` you want to look at the corresponding `2x2` in `a`, so, if `i=1, j=1`, you want to look at `a[1:2, 1:2]`; `i=2, j=3` <= `a[3:4, 5:6]` etc…

3 Likes

This should work for arbitrary dimensions, and also if the axis length is not divisible by the bin size:

``````import Statistics: mean
map( (axes(a) .|> x->Iterators.partition(x,2)) |> x->Iterators.product(x...) ) do idx
mean(a[idx...])
end
``````

Thanks! I wanted to try this without libs because I wanted to gain a fundamental understanding of the operation.

1 Like

Thanks for introducing a new Lib (for me) AndiMD!

1 Like

My suggestion is to use `CartesianIndices` to iterate over `a`. Note that you can create ranges of `CartesianIndex`es, e.g.

``````julia> CartesianIndex(1, 1):CartesianIndex(2, 2)
2×2 CartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
CartesianIndex(1, 1)  CartesianIndex(1, 2)
CartesianIndex(2, 1)  CartesianIndex(2, 2)
``````

which will probably get you pretty far. As an added tip, arithmetic woks on `CartesianIndex` as though it were a scalar, as do functions like `one`, `zero`, etc, which you may find yourself needing.

2 Likes

If you always want a power-of-2 bin, repeated application of this works:

``````bin2(a) = a[1:2:end-1, 1:2:end-1] .+ a[2:2:end, 1:2:end-1] .+ a[1:2:end-1, 2:2:end] .+ a[2:2:end, 2:2:end]
``````