Extracting neighbouring cells in a cell array

This is a follow up to this question. I have cell array and a list of cells of interests (given as a matrix, whose columns correspond to the indices of cells). I want to access and concatenate the entries of all cells located +/- 1 the cell of interest.
For example, as suggested in the accepted answer to the references question, I construct the cell array A as follows
B = [1,2,2,1,1; 2,1,2,1,2];
V = 1:size(B,2);
A = accumarray(B.',V(:),[],@(m){m.'})
A = 2x2 cell array
{[4]} {[1 5]} {[2]} {[ 3]}
Now I have the matrix C with the cells of interest
C=[1 2; 1 2]
C = 2x2
1 2 1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
I have 2 neighbourhoods that I want to explore
NbhInd1=[1 1 2; 1 2 1];
NbhInd2=[1 2 2; 2 2 1];
In the end, I want to be able to get two arrays of neighbourhoods (can be sorted or unsorted)
Nbh1=[4 1 5 2]
Nbh1 = 1x4
4 1 5 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
Nbh2=[1 5 3 2]
Nbh2 = 1x4
1 5 3 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
I have 3 problems:
  1. (Same as in the referenced question): I don't know how to convert an array into a proper index to refer to the correct cell of A. I.e. A{[1,1]} or A ([1,1]) is not the same as A{1,1}, and I need to the latter.
  2. How to automate the construction of indices of the neighbourhoods. In principle, I can use combinations() but it gives too many indices. Also, I'm not sure how to automatically easily convert [1,1] into table2array(combinations(1:2,1:2)), i.e. splitting an array into its coordinates and manipulating separately
  3. The true array A has high dimensionality (e.g. size(A)=repmat(9,[1,10])), so I'd like to minimize the number of loops.

3 Comments

Following the answers to the referenced question, problem 1 can be resolved by (so far referring to the specific cell, not its neighbourhood)
%Input
B = [1,2,2,1,1; 2,1,2,1,2];
V = 1:size(B,2);
A = accumarray(B.',V(:),[],@(m){m.'})
A = 2x2 cell array
{[4]} {[1 5]} {[2]} {[ 3]}
C=[1 2; 1 2];
%
k=1;
D = num2cell(C(:,k));
A{D{:}}
ans = 4
"I want to access and concatenate the entries of all cells located +/- 1 the cell of interest."
How many times do you need to perform this operation? With how many indices? Your data arrays are large, so if you want an efficient approach you might need to think outside the square, perhaps based on interpolation or convolution or something of that ilk. Another option might be to use some image processing tools.
@Stephen23 good question, thanks for raising this. The story is that I have a large set S of points (in principle, can be arbitrarily large, for now 10^6) and I have another set S' of points (~|S'|=1000) for which I want to study a certain property P, i.e. for each x in S', I want to know whether P(x)==true.
To compute P(x), I need to understand how x is positioned with respect to the its neighbours in S (e.g. all points in S that lie within some distance d from x). Which means that I need to select the neighbourhood of x in S. For now I am extracting the neighbourhoods using Euclidean distance, but this is pretty slow.
My hope is that by first putting S on a grid and then restricting the search space to the neighbouring cells instead of the entire S should speed up the process.

Sign in to comment.

 Accepted Answer

B = [1,2,2,1,1; 2,1,2,1,2];
V = 1:size(B,2);
A = accumarray(B.',V(:),[],@(m){m.'})
A = 2x2 cell array
{[4]} {[1 5]} {[2]} {[ 3]}
C=[1 2; 1 2]
C = 2x2
1 2 1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% construct NbhInd (a cell array of neighborhood index matrices) from C
N = size(C,2);
NbhInd = cell(1,N);
sizA = size(A);
NsA = numel(sizA);
assert(size(C,1) == NsA)
offsets = [zeros(1,NsA); eye(NsA); -eye(NsA)];
for ii = 1:N
NbhInd{ii} = unique(min(sizA,max(1,C(:,ii).'+offsets)),'rows').';
end
NbhInd{:}
ans = 2x3
1 1 2 1 2 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 2x3
1 2 2 2 1 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% take elements from A within each neighborhood
Nbh = cell(1,N);
for ii = 1:N
M = size(NbhInd{ii},2);
idx = num2cell(NbhInd{ii});
temp = cell(1,M);
for jj = 1:M
temp{jj} = A{idx{:,jj}};
end
Nbh{ii} = [temp{:}];
end
Nbh
Nbh = 1x2 cell array
{[4 1 5 2]} {[1 5 2 3]}

3 Comments

A higher-dimensional example:
A = num2cell(rand(3,4,5))
A = 3x4x5 cell array
A(:,:,1) = {[0.2026]} {[0.8070]} {[0.2340]} {[0.5565]} {[0.3429]} {[0.4575]} {[0.0680]} {[0.7258]} {[0.1143]} {[0.4171]} {[0.6360]} {[0.0947]} A(:,:,2) = {[0.6664]} {[0.0016]} {[0.6793]} {[0.9978]} {[0.4280]} {[0.2755]} {[0.4612]} {[0.5945]} {[0.8832]} {[0.3841]} {[0.7139]} {[0.7530]} A(:,:,3) = {[0.4360]} {[0.6815]} {[0.0069]} {[0.3654]} {[0.5671]} {[0.3924]} {[0.0300]} {[0.8141]} {[0.4582]} {[0.9913]} {[0.4975]} {[0.1185]} A(:,:,4) = {[0.5181]} {[0.7495]} {[0.6264]} {[0.2215]} {[0.8475]} {[0.0393]} {[0.5354]} {[0.3604]} {[0.1938]} {[0.6822]} {[0.2137]} {[0.1701]} A(:,:,5) = {[0.1957]} {[0.3457]} {[0.5664]} {[0.9837]} {[0.8453]} {[0.4789]} {[0.4812]} {[0.7150]} {[0.4127]} {[0.4667]} {[0.5036]} {[0.1855]}
C=[1 2 3 3 3; 1 2 1 2 4; 1 2 4 4 5]
C = 3x5
1 2 3 3 3 1 2 1 2 4 1 2 4 4 5
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% construct NbhInd (a cell array of neighborhood index matrices) from C
N = size(C,2);
NbhInd = cell(1,N);
sizA = size(A);
NsA = numel(sizA);
assert(size(C,1) == NsA)
offsets = [zeros(1,NsA); eye(NsA); -eye(NsA)];
for ii = 1:N
NbhInd{ii} = unique(min(sizA,max(1,C(:,ii).'+offsets)),'rows').';
end
NbhInd{:}
ans = 3x4
1 1 1 2 1 1 2 1 1 2 1 1
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 3x7
1 2 2 2 2 2 3 2 1 2 2 2 3 2 2 2 1 2 3 2 2
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 3x5
2 3 3 3 3 1 1 1 1 2 4 3 4 5 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 3x6
2 3 3 3 3 3 2 1 2 2 2 3 4 4 3 4 5 4
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 3x4
2 3 3 3 4 3 4 4 5 5 4 5
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
% take elements from A within each neighborhood
Nbh = cell(1,N);
for ii = 1:N
M = size(NbhInd{ii},2);
idx = num2cell(NbhInd{ii});
temp = cell(1,M);
for jj = 1:M
temp{jj} = A{idx{:,jj}};
end
Nbh{ii} = [temp{:}];
end
Nbh
Nbh = 1x5 cell array
{[0.2026 0.6664 0.8070 0.3429]} {1x7 double} {1x5 double} {1x6 double} {[0.7150 0.5036 0.1701 0.1855]}
Nbh{:}
ans = 1x4
0.2026 0.6664 0.8070 0.3429
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1x7
0.0016 0.4280 0.4575 0.2755 0.3924 0.4612 0.3841
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1x5
0.8475 0.4582 0.1938 0.4127 0.6822
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1x6
0.0393 0.1938 0.9913 0.6822 0.4667 0.2137
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1x4
0.7150 0.5036 0.1701 0.1855
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2023b

Asked:

OK
on 1 Jul 2024

Commented:

on 1 Jul 2024

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!