I have a cell array called output. Each cell within output contains a 1024 x 1024 matrix. I would like to threshold each matrix so that elements below a given value are set to NaN.
I tried using:
output(output < 100000) = NaN;
However, I feel that this is the wrong approach. Intuitively, I want to use a for loop, however, I don't think that will be the most efficient method possible.
Thoughts? Suggestions?
Thanks :)
it can be done with cellfun function!cell fun can implement a function on every cell (it's like for loop) Assume below example
first consider you have a variable named a in cell form.
a{1,1} =
1 2
3 4
a{2,1} =
1 2
5 5
a{1,2} =
4 5
1 2
a{2,2} =
5 5
5 5
in this cell i want to substitute entries with NaN if entry lower than 3
So I write below function for this purpose
function out = main_func()
%% define a
a{1,1}=[1 2;3 4];
a{1,2}=[4 5;1 2];
a{2,1}=[1 2;5 5];
a{2,2}=[5 5;5 5];
out=cellfun(#(T) cell_f(T),a,'uniformOutput',false); % using cell fun function
function x = cell_f(x)
x(x<3)=nan; % if entries lower that 3 then substitute with Nan
the output will be like below
ans{1,1} =
NaN NaN
3 4
ans{2,1} =
NaN NaN
5 5
ans{1,2} =
4 5
NaN NaN
ans{2,2} =
5 5
5 5
Related
How do I create a function (e.g. here, an anonymous one but I don't mind any) to get x elements from vec that are most centered (i.e. around the median)? In essence I want a function with same syntax as Matlab's randsample(n,k), but for non-random, with elements spanning around the center.
cntr=#(vec,x) vec(round(end*.5)+(-floor(x/2):floor(x/2))); %this function in question
cntr(1:10,3) % outputs 3 values around median 5.5 => [4 5 6];
cntr(1:11,5) % outputs => [4 5 6 7 8]
Note that vec is always sorted.
One part that I struggle with is not to output more than the limits of vec. For example, cntr(1:10, 10) should not throw an error.
edit: sorry to answer-ers for many updates of question
It's not a one-line anonymous function, but you can do this pretty simply with a couple calls to sort:
function vec = cntr(vec, x)
[~, index] = sort(abs(vec-median(vec)));
vec = vec(sort(index(1:min(x, end))));
end
The upside: it will still return the same set of values even if vec isn't sorted. Some examples:
>> cntr(1:10, 3)
ans =
4 5 6
>> cntr(1:11, 5)
ans =
4 5 6 7 8
>> cntr(1:10, 10) % No indexing errors
ans =
1 2 3 4 5 6 7 8 9 10
>> cntr([3 10 2 4 1 6 5 8 11 7 9], 5) % Unsorted version of example 2
ans =
4 6 5 8 7 % Same values, in their original order in vec
OLD ANSWER
NOTE: This applied to an earlier version of the question where a range of x values below and x values above the median were desired as output. Leaving it for posterity...
I broke it down into these steps (starting with a sorted vec):
Find the values in vec less than the median, get the last x indices of these, then take the first (smallest) of them. This is the starting index.
Find the values in vec greater than the median, get the first x indices of these, then take the last (largest) of them. This is the ending index.
Use the starting and ending indices to select the center portion of vec.
Here's the implementation of the above, using the functions find, min, and max:
cntr = #(vec, x) vec(min(find(vec < median(vec), x, 'last')):max(find(vec > median(vec), x)));
And a few tests:
>> cntr(1:10, 3) % 3 above and 3 below 5.5
ans =
3 4 5 6 7 8
>> cntr(1:11, 5) % 5 above and 5 below 6 (i.e. all of vec)
ans =
1 2 3 4 5 6 7 8 9 10 11
>> cntr(1:10, 10) % 10 above and 10 below 5.5 (i.e. all of vec, no indexing errors)
ans =
1 2 3 4 5 6 7 8 9 10
median requires sorting the array elements. Might as well sort manually, and pick out the middle block (edit: OP's comment indicates elements are already sorted, more justification for keeping it simple):
function data = cntr(data,x)
x = min(x,numel(data)); % don't pick more elements than exist
data = sort(data);
start = floor((numel(data)-x)/2) + 1;
data = data(start:start+x-1);
You could stick this into a single-line anonymous function with some tricks, but that just makes the code ugly. :)
Note that in the case of an uneven division (when we don't leave an even number of elements out), here we prioritize an element on the left. Here is what I mean:
0 0 0 0 0 0 0 0 0 0 0 => 11 elements, x=4
\_____/
picking these 4 values
This choice could be made more complex, for example shifting the interval left or right depending on which of those values is closest to the mean.
Given data (i.e. vec) is already sorted, the indexing operation can be kept to a single line:
cntr = #(data,x) data( floor((numel(data)-x)/2) + (1:x) );
The thing that is missing in that line is x = min(x,numel(data)), which we need to add twice becuase we can't change a variable in an anonymous function:
cntr = #(data,x) data( floor((numel(data)-min(x,numel(data)))/2) + (1:min(x,numel(data))) );
This we can simplify to:
cntr = #(data,x) data( floor(max(numel(data)-x,0)/2) + (1:min(x,numel(data))) );
So, I have a cell-array of 1xN vectors of different lengths. I want to append them into a matrix so I can display them with imagesc. Obviously the matrix must be the width of the largest vector. My current code for this is below:
tcell = {[1,2,3], [1,2,3,4,5], [1,2,3,4,5,6], [1], []};
lens = cellfun('length', tcell);
rmat = NaN(length(tcell), max(lens));
for i = 1:length(tcell)
rmat(i, 1:lens(i)) = tcell{i};
end
Does anyone know a vectorized solution for this type of problem? I'm not really worried about the speed of this loop because of MATLAB's JIT. I'm just trying to expand my knowledge and this is a case that I come across quite often in my programming.
Here's one solution that uses cellfun with an anonymous function to first pad each cell with NaN values, then vertcat to put the cell contents into a matrix:
tcell = {[1 2 3], [1 2 3 4 5], [1 2 3 4 5 6], [1], []}; % Sample cell array
maxSize = max(cellfun(#numel, tcell)); % Get the maximum vector size
fcn = #(x) [x nan(1, maxSize-numel(x))]; % Create an anonymous function
rmat = cellfun(fcn, tcell, 'UniformOutput', false); % Pad each cell with NaNs
rmat = vertcat(rmat{:}); % Vertically concatenate cells
And the output:
rmat =
1 2 3 NaN NaN NaN
1 2 3 4 5 NaN
1 2 3 4 5 6
1 NaN NaN NaN NaN NaN
NaN NaN NaN NaN NaN NaN
I have an array 2549x13 double (M).
Example lines:
-7.8095 -4.4135 -0.0881 2.5159 6.3142 6.9519 4.9788 2.9109 0.6623 -0.9269 0.3172 1.2445 -0.0730
4.5819 6.2371 5.8721 6.1824 5.2074 4.8656 5.0269 5.3340 3.6919 1.3608 -0.5443 0.2871 -1.2070
-6.2273 -3.7767 1.1829 2.8522 3.2428 0.5261 -3.5535 -7.7743 -8.4391 -9.8188 -6.0503 -5.8805 -7.7700
-2.2157 -3.2100 -4.4400 -3.5898 -0.8901 3.4061 6.5631 7.2028 4.3082 -0.7742 -5.0963 -3.1837 0.4372
5.5682 5.5393 3.4691 0.6789 1.7320 4.4472 3.7622 1.0194 -0.5362 -3.1721 -6.1281 -6.3959 -6.1932
0.9707 -0.2701 -3.8883 -8.8974 -7.0375 -1.5085 5.4171 6.0831 2.9852 -2.3474 -4.5637 -3.7378 1.3236
-2.811 0.0164 2.7208 5.7862 7.3344 8.3504 9.0635 8.4271 2.7669 -2.1403 -2.2003 -0.9940 0.7729
4.2382 3.3532 3.5475 7.9209 11.7933 14.3181 13.6289 12.9553 13.7464 14.1331 14.3814 16.7949 15.9003
-0.0539 -2.7059 -3.8141 -2.7531 -1.7465 0.9190 2.2220 0.7268 1.5436 1.0426 2.3535 3.0269 6.4798
I also have the indices of some values I need, 2549x5 double(inde).
Example lines:
4 5 6 7 8
0 1 2 3 4
3 4 5 6 7
6 7 8 9 10
-1 0 1 2 3
6 7 8 9 10
5 6 7 8 9
10 11 12 13 14
11 12 13 14 15
I want now to create a new array/matrix with the actual values. So, to find in the array M the values corresponding to the indices inde.
However, if the index (in inde) is equal to zero, I would like to take the values corresponding to the indeces 1,2,3,4 of that row.
If the index is -1 or 15, I would like to insert an NaN in the new array/matrix.
If the index is 14, I would like to take the values corresponding to 10,11,12,13.
So I would like to obtain:
2.5159 6.3142 6.9519 4.9788 2.9109
NaN 4.5819 6.2371 5.8721 6.1824
1.1829 2.8522 3.2428 0.5261 -3.5535
3.4061 6.5631 7.2028 4.3082 -0.7742
NaN
-1.5085 5.4171 6.0831 2.9852 -2.3474
7.3344 8.3504 9.0635 8.4271 2.7669
14.1331 14.3814 16.7949 15.9003 NaN
NaN
Very grateful to anyone who could help with this.
This will give you the desired array:
rows = size(M, 1); % number of rows in M and inde
cols = size(inde, 2); % number of columns in inde
N = [nan(rows, 2) M nan(rows, 2)]; % pad M with 2 columns of NaN values
% on left and right
inde = inde + 2; % change indices to account for padding
P = zeros(rows, cols); % preallocate result matrix
nanrow = nan(1, cols); % make a row of all NaN values
for row_num = 1:rows
P(row_num,:) = N(row_num, inde(row_num,:)); % get values from N
if sum(isnan(P(row_num,:))) > 1 % if 2 NaN values, original index was -1 or 15
P(row_num,:) = nanrow; % so make it all NaN's
end
end
(I dislike leaving that stray 2 in there when padding, but I was unsure what the expected result was for different numbers of columns of inde, if that's even a concern. Perhaps floor(cols/2)?)
Since MATLAB won't allow you to have matrices with rows of unequal length, for rows in which there are indices of -1 or 15, I've inserted a row of all NaN values. This can obviously be changed to whatever you prefer by modifying the line inside the if clause.
Results using M and inde from your example:
P =
2.51590 6.31420 6.95190 4.97880 2.91090
NaN 4.58190 6.23710 5.87210 6.18240
1.18290 2.85220 3.24280 0.52610 -3.55350
3.40610 6.56310 7.20280 4.30820 -0.77420
NaN NaN NaN NaN NaN
-1.50850 5.41710 6.08310 2.98520 -2.34740
7.33440 8.35040 9.06350 8.42710 2.76690
14.13310 14.38140 16.79490 15.90030 NaN
NaN NaN NaN NaN NaN
EDIT
I suggest not to mix numbers and characters in your matrix since it would become a cell-structure which is harder to handle.
So I assume for the rest of my answer that you want to put zeros (or any error value, -999 for instance is sometimes used) where you want to modify your data. Assuming A is your data matrix and i your indexes' matrix :
B=zeros(size(i));
for j=1:size(i,1)
if (prod(i(j,:))==0)
k=find(i(j,:)==0);
B(j,k+1:end)= A(j,i(j,k+1:end));
m=find(i(j,:)<0);
if (~isempty(m))
B(j,:)= 0;
end
else
B(j,:)= A(j,i(j,:));
end
end
I get :
2.5159 6.3142 6.9519 4.9788 2.9109
0 4.5819 6.2372 5.8722 6.1824
1.1830 2.8522 3.2429 0.5261 -3.5535
3.4061 6.5632 7.2028 4.3083 -0.7742
0 0 0 0 0
-1.5086 5.4171 6.0831 2.9853 -2.3475
7.3344 8.3505 9.0635 8.4271 2.7670
I am trying to remove array values whose difference is a member of that array in MATLAB. For example, if I have an array defined as
x = [1 2 4 3 7];
I would like to remove 2, because it can be achieved from 4 - 2. I would also like to remove 4 because it can be achieved from 7 - 3. I would then like to store these values (2 and 4, respectively) into a matrix. The latter is easy. I just have a hard time doing this checker for summation.
I know you can use
ismember(*any 2 differences*),x(:))
to check if the differences are in the array. However, I don't know how to code my function to try out all the combinations of element subtraction.
Seemed like a good setup to use bsxfun -
abs_diffs = abs(bsxfun(#minus,x(:),x(:).')) %//'
unq_abs_diffs = unique(abs_diffs)
out = x(~any(bsxfun(#eq,unq_abs_diffs(:),x(:).'),1)) %//'
%// OR x(~ismember(x,unq_abs_diffs))
Sample run -
>> x
x =
1 2 4 3 7
>> abs_diffs = abs(bsxfun(#minus,x(:),x(:).'))
abs_diffs =
0 1 3 2 6
1 0 2 1 5
3 2 0 1 3
2 1 1 0 4
6 5 3 4 0
>> unq_abs_diffs = unique(abs_diffs)
unq_abs_diffs =
0
1
2
3
4
5
6
>> out = x(~any(bsxfun(#eq,unq_abs_diffs(:),x(:).'),1))
out =
7
So, in [1 2 4 3 7], only 7 seemed like the one that could not be removed.
You could do it like this:
n = length(a);
differences = meshgrid(a,a) - meshgrid(a,a)'; % get differences between elements
differences(1:n+1:n*n) = []; % remove diagonal
a(ismember(a,differences)) = []; % remove elements in differences
I'm assuming that you only want differences between unique elements. If you want to allow the difference between an element of a and itself, then remove the 3rd line.
I have the following variables:
x = [0 1 2 2 3 4 5 6 7 8 9];
y = [0 1 2 nan 3 4 5 6 7 8 9];
I would like to pass 'y' through an equation to give 'y2', for example:
y2 = y.*2;
Note this is just an example. The real equation I have is more complicated. The 'real' equation does not allow nans to be within the vector (as one value depends on the last).
If I can't have nans passing through the equation, however, I can type
y2 = y(~isnan(y)).*2;
y2 =
0 2 4 6 8 10 12 14 16 18
This removes the nan and then performs the calculation.
How can I make 'y2' to be back to the same length as 'x' i.e. with a nan as the fourth value?
Something like:
y2 =
0 2 4 NaN 6 8 10 12 14 16 18
The reason I'm doing this is that I want to plot 'y2' against 'x' and thus they must be the same size.
I realize that I can do
x2 = x(~isnan(y))
and then just plot 'x2' against 'y2' but I would like to find a way of doing it the way I specify above.
Store the NaN indices somewhere and then use those to input the new values into the right places and then plug back in the NaN values too.
Code
%%// Define function
func1 = #(x)x*2;
%%// Input data - y
y = [0 1 2 nan 3 4 5 6 7 8 9];
%%// Store NaN indices
nan_ind = isnan(y)
%%// Process data on the function
y2(~nan_ind) = func1(y(~nan_ind))
y2(nan_ind) = NaN