Matrix as input and output of Matlab function - matlab

For example I want to have a function which let me delete rows of my matrix where the highest value is 1. Thus I wrote:
% A is an input matrix
% pict2 suppose to be output cleared matrix
function pict2 = clear_(A)
B=A
n = size(A,1)
for i=1:n
if(max(B(i,:))==1)
B(i,:)=[]
end
end
But after I call:
pict2=clear_(pict) the Matlab resposes:
"warning: clear_: some elements in list of return values are undefined
warning: called from
clear_ at line 5 column 1 pict2 = "
I'm not sure which elements were left undefined?

The variable name of your output argument must match the variable that you want to be returned. So you'll want to change the first line to the following so that your modifications to B are saved and returned.
function B = clear_(A)
As far as your algorithm is concerned, it's not going to work because you are modifying B while trying to loop through it. Instead, you can replace your entire function with the following expression which computes the maximum value of each row, then determines if this value is equal to 1 and removes the rows where this is the case.
B(max(B, [], 2) == 1, :) == [];

I believe that, alternatively to the suggestions you already recieved, you might want to try the following. Using logicals is probably one of the best options for such a problem, since you don't need to use for-loops:
function out = clear_matr(A)
% ind is true for all the rows of A, where the highest value is not equal to 1
ind = ~(max(A, [], 2) == 1);
% filter A accordingly
out = A(ind, :);
end

Related

MATLAB - Check matrix to see if two consecutive numbers = 0

I have a matrix being created in MATLAB but need to check if any two consecutive numbers (by row) = 0 and if it does output with a yes or no without showing the answers. Ive put my code below my final loop is returning errors and im not too sure how to go about this.
%%Input positive integer
n=input('Give a positive integer greater than 1: ');
%%Error for below 1
if n<=1
error('The value given is less than or equal to 1')
end
%%loop for vector v
for i=1:n
v(i)=2^i*3;
end
%display vector
v
A=randi([-5,5],n,n);
A
x = 1;
consecutive = false;
for i = 1:25
if (A(x) + A(x+1) = 0);
consecutive = true;
end
end
There's a lot wrong with the code of your final loop:
You set x to 1 and use it as an index into A, but never change it from 1.
As Amit points out, you are using = (used for assignment) when you should be using == (the equality operator).
As Gondrian points out, you are testing if a sum is equal to zero, but from your description it sounds like you should be testing if each value is zero.
Your loop iterates 25 times (i = 1:25), but it's not clear why, since your matrix A is of size n-by-n.
Instead of using a for loop, it's possible to do this with indexing instead. Since you are checking for consecutive zeroes by row, this is what it would look like:
zeroPairs = (A(:, 1:(n-1)) == 0) & (A(:, 2:n) == 0);
consecutive = any(zeroPairs(:));
The term A(:, 1:(n-1)) gets all of the "left" values in each pairwise comparison and the term A(:, 2:n) gets all of the "right" value. These are compared to 0, then combined. This creates an n-by-(n-1) matrix zeroPairs where a value of true indicates where a pair of consecutive zeroes occurs. This matrix is reshaped into a column vector and any is used to check if a value of true is present anywhere.
You will need to change your if block as follows.
if (A(x) + A(x+1) == 0);
consecutive = true;
end
Notice the == instead of just =. The first one is for comparison and the second one is for assignment. This will get rid of the error that you are currently getting. There may be other issues in the algorithm of your code but I did not examine or try to fix that.
btw:
'if any two consecutive numbers (by row) = 0'
If I understand you right, you should try 'if A(x) == 0 && A(x+1) == 0';
because '(A(x) + A(x+1) == 0)' would be true for -5 and 5, as it equals to 0. But -5 and 5 are not two consecutive zeros.
(or even look at the 'diff' function. It will return a 0 if two following numbers are the same)
To show a vectorized, more Matlab-like approach:
v = 0; % sought value
C = 2; % desired number of consecutive values in a row
consecutive = nnz(conv2(double(A==v), ones(1,C))==C)>0;
This compares each entry of A with the value v, and then applies 2D convolution with a row vector of C ones. Any C horizontally-consecutive entries of A with value v will produce an entry equal to C in the convolution result. So we check if the number of such entries is positive.

find returns empty matrix

I have two vectors which are of length 200,000 approximately. They consist of dates in the datenum format.
%datenums
date_exp = datenum(data_exp(:,1:6));
date_sim = datenum(data_sim(:,1:6));
I want to find the dates in date_exp that exists in date_sim.
Then remove the values from date_exp
I have used the the ismember tool but ending up at i=38 find retunrs: Improper assignment with rectangular empty matrix.
Error in filter (line 18)
c(i)= find(ismember(date_sim(:),date_exp(i)),1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
c = zeros(length(date_sim),1);
for i=1:length(date_sim)
c(i)= find(ismember(date_sim(:),date_exp(i)),1);
if isempty(c(i)) == 1
c(i) = 0;
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
I would be really helpful if anyone could help me out here.
The issue is because date_exp(38) must not be within date_sim. When there are no 1's in the input, find returns an empty array ([]).
Your code does not handle this as you would expect though because of this line.
c(i) = find(...)
In this case, if there are no matches (find() == []), then you are essentially calling
c(i) = [];
This deletes the ith element of c element
Therefore the following line is never true!
if isempty(c(i)) == 1
Instead, you should probably do something to handle the empty value.
index = find(ismember(date_sim(:), date_exp(i)), 1);
%// Only assign the index if it isn't an empty array
if ~isempty(index)
c(i) = index;
end
You don't have to worry about assigning zeros because your initial matrix is already full of zeros.
A Better Option
All of that aside, it would likely be a much better approach to not loop at all and to instead use the second output of ismember (on the arrays before you pass them to datenum) to give you the same result in a much more efficient way.
[~, c] = ismember(date_exp(:,1:6), date_sim(:,1:6), 'rows');

expand matrix in matlab?

I would like to expand matrix row by row under a conditional statement without initializing the matrix. In C++, simply I use std::vector and push_back method without initializing the size of the vector in C++. However, I want to do same scenario in Matlab. This is my pseudo code
for i = 1:lengt(data)
if ( condition )
K = [data(1) data(2) i]
end
K
Let us assume some working code to resemble your pseudo-code.
%// Original code
for i = 1:10
if rand(1)>0.5
data1 = rand(2,1)
K = [data1(1) data1(2) i]
end
end
Changes for "pushing data without initialization/pre-allocation":
To save data at each iteration we keeping on "stacking" data along a chosen dimension. This could be thought of as pushing data. For a 2D case, use either a "row vector push" or a "column vector push". For this case we are assuming a former case.
We don't index into K using the original iterator, but use a custom one,
that only increments when the condition is satisfied.
The code below must make it clear.
%// Modified code
count = 1; %// Custom iterator; initialize it for the iteration when condition would be satisfied for the first time
for i = 1:10
if rand(1)>0.5
data1 = rand(2,1)
K(count,:) = [data1(1) data1(2) i] %// Row indexing to save data at each iteration
count = count +1; %// We need to manually increment our custom iterator
end
end
If we assume from the above that data is an Nx2 matrix, and that you only want to save the rows that satisfy some condition, then you almost have the correct code to update your K matrix without having to initialize it to some size:
K = []; % initialize to an empty matrix
for i=1:size(data,1) % iterate over the rows of data
if (condition)
% condition is satisfied so update K
K = [K ; data(i,:) i];
end
end
K % contains all rows of data and the row number (i) that satisfied condition
Note that to get all elements from a row, we use the colon to say get all column elements from row i.

Indexing must appear last in an index expression

I have a vector CD1 (120-by-1) and I separate CD1 into 6 parts. For example, the first part is extracted from row 1 to row 20 in CD1, and second part is extracted from row 21 to row 40 in CD1, etc. For each part, I need to compute the means of the absolute values of second differences of the data.
for PartNo = 1:6
% extract data
Y(PartNo) = CD1(1 + 20*(PartNo-1):20*(PartNo),:);
% find the second difference
Z(PartNo) = Y(PartNo)(3:end) - Y(PartNo)(1:end-2);
% mean of absolute value
MEAN_ABS_2ND_DIFF_RESULT(PartNo) = mean(abs(Z));
end
However, the commands above produce the error:
()-indexing must appear last in an index expression for Line:2
Any ideas to change the code to have it do what I want?
This error is often encountered when Y is a cell-array. For cell arrays,
Y{1}(1:3)
is legal. Curly braces ({}) mean data extraction, so this means you are extracting the array stored in location 1 in the cell array, and then referencing the elements 1 through 3 of that array.
The notation
Y(1)(1:3)
is different in that it does not extract data, but it references the cell's location 1. This means the first part (Y(1)) returns a cell-array which, in your case, contains a single array. So you won't have direct access to the regular array as before.
It is an infamous limitation in Matlab that you cannot do indirect or double-referencing, which is in effect what you are doing here.
Hence the error.
Now, to resolve: I suspect replacing a few normal braces with curly ones will do the trick:
Y{PartNo} = CD1(1+20*(PartNo-1):20*PartNo,:); % extract data
Z{PartNo} = Y{PartNo}(3:end)-Y{PartNo}(1:end-2); % find the second difference
MEAN_ABS_2ND_DIFF_RESULT{PartNo} = mean(abs(Z{PartNo})); % mean of absolute value
I might suggest a different approach
Y = reshape(CD1, 20, 6);
Z = diff(y(1:2:end,:));
MEAN_ABS_2ND_DIFF_RESULT = mean(abs(Z));
This is not a valid statement in matlab:
Y(PartNo)(3:end)
You should either make Y two-dimensional and use this indexing
Y(PartNo, 3:end)
or extract vector parts and use them directly, if you use a loop like you have shown
for PartNo = 1:6
% extract data
Y = CD1(1 + 20*(PartNo-1):20*(PartNo),:);
% find the second difference
Z = Y(3:end) - Y(1:end-2);
% mean of absolute value
MEAN_ABS_2ND_DIFF_RESULT(PartNo) = mean(abs(Z));
end
Also, since CD1 is a vector, you do not need to index the second dimension. Drop the :
Y = CD1(1 + 20*(PartNo-1):20*(PartNo));
Finally, you do not need a loop. You can reshape the CD1 vector to a two-dimensional array Y of size 20x6, in which the columns are your parts, and work directly on the resulting matrix:
Y = reshape(CD1, 20, 6);
Z = Y(3:end,:)-Y(1:end-1,:);
MEAN_ABS_2ND_DIFF_RESULT = mean(abs(Z));

Find index of all (non-unique) elements in a cell array as they appear in a second (sorted and unique) cell array

A = {'A'; 'E'; 'A'; 'F'};
B = {'A';'B';'C';'D';'E'; 'F'};
I am trying to get for each string in cell array A, the index that matches that string in cell array B. A will have repeated values, B will not.
find(ismember(B, A) == 1)
outputs
1
5
6
but I want to get
1
5
1
6
preferably in a one liner. I can't use strcmp instead of ismember either as the vectors are different sizes.
The vectors will actually contain date strings, and I need the index not a logical index matrix, I'm interested in the number not to use it for indexing.
How do I do it?
You flip the arguments to ismember, and you use the second output argument:
[~,loc]=ismember(A,B)
loc =
1
5
1
6
The second output tells you where the elements of A are in B.
If you are working with very strict limits to how many lines you can have in your code, and are in no position to fire the manager who imposed such limitations, you may want to access the second output of ismember directly. In order to do this, you can create the following helper function that allows to directly access the i-th output of a function
function out = accessIthOutput(fun,ii)
%ACCESSITHOUTPUT returns the i-th output variable of the function call fun
%
% define fun as anonymous function with no input, e.g.
% #()ismember(A,B)
% where A and B are defined in your workspace
%
% Using the above example, you'd access the second output argument
% of ismember by calling
% loc = accessIthOutput(#()ismember(A,B),2)
%# get the output
[output{1:ii}] = fun();
%# return the i-th element
out = output{ii};