delete elements from a matrix and calculate mean - matlab

I have an N-by-M-Matrix as input called GR wich consists of the following numbers: -3,0,2,4,7,10,12
And I have to return a vector. If M=1, then it should just return the input.
If M>1 It should remove the lowest number from the matrix and then calculate the mean of the remaining numbers.
However, if one of the numbers in the row is -3, it should return the value -3 in the output.
My thoughts of the problem:
Is it possible to make a for loop?
for i=1:length(GR(:,1))
If length(GR(1,:))==1
GR=GR
end
If length(GR(1,:))>1
x=min(GR(i,:))=[] % for removing the lowest number in the row
GR=sum(x)/length(x(i,:))
I just don't have any Idea of how to detect if any of the numbers in the row is -3 and then return that value instead of calculating the mean and when I tried to delete the lowest number in the matrix using x=min(GR(i,:)) matlab gave me this error massage 'Deletion requires an existing variable.'

I put in a break function. As soon as it detects a -3 value it breaks from the loop. Same goes for the other function.
Note that it is an i,j (M*N) matrix. So you might need to change your loop.
for i=1:length(GR(:,1))
if GR(i,1)==-3
GR=-3
break
end
If length(GR(1,:))==1
GR=GR
break
end
If length(GR(1,:))>1
x=min(GR(i,:))=[] % for removing the lowest number in the row
GR=sum(x)/length(x(i,:))
end
end

you can use Nan's, nanmean, any, and dim argument in these functions:
% generate random matrix
M = randi(3);
N = randi(3);
nums = [-3,0,2,4,7,10,12];
GR = reshape(randsample(nums,N*M,true),[N M]);
% computation:
% find if GR has only one column
if size(GR,2) == 1
res = GR;
else
% find indexes of rows with -3 in them
idxs3 = any(GR == -3,2);
% the (column) index of the min. value in each row
[~,minCol] = min(GR,[],2);
% convert [row,col] index pair into linear index
minInd = sub2ind(size(GR),1:size(GR,1),minCol');
% set minimum value in each row to nan - to ignore it on averaging
GR(minInd) = nan;
% averaging each rows (except for the Nans)
res = nanmean(GR,2);
% set each row with (-3) in it to (-3)
res(idxs3) = -3;
end
disp(res)

Related

Is there a way to use "for loop" in creating a matrix

I'm a total beginner when it comes to MATLAB, so I have a question for this. How am I supposed to write this code out and if by any chance, can someone be kind enough to write out the code because I've been struggling with this. Use loops to create 3 x 5 matrix in which the value of each element is half of its row number plus three times its column number. for instance, the value of element (2,5) is: 1/22+35
The nested loops control the indexing of the matrix. The outer for-loop traverses through the rows of the matrix and the inner for-loop traverses through the columns of the matrix.
The second part of this question requires using a combination of the looping/scanning variables Row and Column to set the value of the matrix:
Matrix Value = (Row ÷ 2) + (3 × Column)
Number_Of_Rows = 3;
Number_Of_Columns = 5;
Matrix = zeros(Number_Of_Rows,Number_Of_Columns);
%Running through the array indices using two loops%
for Row = 1: Number_Of_Rows
for Column = 1: Number_Of_Columns
%Evaluating the value based on the current row and column index%
Matrix(Row,Column) = (Row/2) + (3*Column);
end
end
Matrix
Result:
Looping Methodology:
Variable Matrix Opened In Workspace:
Here's an intuitive way to do this:
% Initialize row num and column num
row = 3;
column = 5;
% H is the matrix of desire
% Initialize it as a 3*5 zero matrix
H = zeros(3,5);
% Outer loop, over column index
% Remember Matlab's index start with 1 not 0
for c = 1:column
% Inner Loop, over row index
for r = 1:row
% The algorithm of each element in the matrix
H(r,c) = 0.5*r+3*c;
end
end

Columnwise removal of first ones from binary matrix. MATLAB

I have some binary matrix. I want to remove all first ones from each column, but keep one if this value is alone in column. I have some code, which produces correct result, but it looks ugly- I should iterate through all columns.
Could You give me a piece of advice how to improve my code?
Non-vectorised code:
% Dummy matrix for SE
M = 10^3;
N = 10^2;
ExampleMatrix = (rand(M,N)>0.9);
ExampleMatrix1=ExampleMatrix;
% Iterate columns
for iColumn = 1:size(ExampleMatrix,2)
idx = find(ExampleMatrix(:,iColumn)); % all nonzeroes elements
if numel(idx) > 1
% remove all ones except first
ExampleMatrix(idx(1),iColumn) = 0;
end
end
I think this does what you want:
ind_col = find(sum(ExampleMatrix, 1)>1); % index of relevant columns
[~, ind_row] = max(ExampleMatrix(:,ind_col), [], 1); % index of first max of each column
ExampleMatrix(ind_row + (ind_col-1)*size(ExampleMatrix,1)) = 0; % linear indexing
The code uses:
the fact that the second output of max gives the index of the first maximum value. In this case max is applied along the first dimension, to find the first maximum of each column;
linear indexing.

Matlab: construct a binary matrix satisfying horizontal and vertical constraints

I want to initiate a mxn binary matrix. The summation of each column of the matrix equals to a given value s(j), for j=1..n. In addition, the summation of each row of the matrix should be within the range of given bounds: lhs is dl(i) and rhs is du(i), for i=1..m.
Now I can only randomly generate binary columns, in each of which the sum of ones equals to s(j) of that column, such as the following codes.
xij = zeros(m,n);
for j=1:n
randRows=randperm(m); %a row vector containing a random permutation of the integers from 1 to m inclusive.
rowsWithOne=randRows(1:sj(j)); %row indices having 1, and sum up to sj
xij(rowsWithOne,j)=1;
end
However, xij usually doesn't satisfy the horizontal constraints. I was thinking I should create a matrix first meets the row constraints lhs (lower bound) dl(i), then, column constraint s(j), and finally fill the offsets to meet rhs du(i), but I don't know how to implement it in Matlab. Is there any ideas to create xij?
Thanks in advance.
There are a couple things to first take into account, mainly if the problem can even be solved with the given constraints. First, you must check that the sum of s(j), sum(s) is greater than the sum of the lower bound constraints, sum(dl), and also less than the sum of the upper bound constraints, sum(du).
A simple if statement should be able to check this. After this has been done, the following code should be one solution to the problem, but given the nature of the problem, there will probably not be a unique solution.
%initialize counters
x = 1;
y = 1;
%make sure the lower bounds are first satisfied
for k = 1:nrows
while (dl(k) > 0)
if (s(y) > 0)
xij(k,y) = 1;
dl(k) = dl(k)-1;
du(k) = du(k)-1;
s(y) = s(y)-1;
end
y = y+1;
end
y = 1;
end
%make sure the columns all add to their specified values
for k = 1:ncols
while (s(k) > 0)
if (xij(x,k) == 0 && du(x) > 0)
xij(x,k) = 1;
du(x) = du(x)-1;
s(k) = s(k)-1;
end
x = x+1;
end
x = 1;
end
The first for loop adds 1s along the rows such that each row satisfies the minimum constraint. The next for loop adds 1s along the columns such that each column adds up to the desired value. The if statement in the first for loop ensures that a 1 isn't added if that column has already reached its desired value, and the if statement in the second for loop ensures that a 1 isn't added to a row that would put it over the maximum value of the row.
In order to keep track of the amount of ones, the du is lowered by 1 every time a 1 is added to the corresponding row, and likewise the desired value s(j) is subtracted by 1 every time a 1 is added to that column of the xij matrix.
%Create an initial xij matrix, each column of which consists of a random binary xij sequence, but sum of ones in each column equals to sj
Init_xij = zeros(nShift,nCombo);
for j=1:nCombo
randRows=randperm(nShift); %a row vector containing a random permutation of the integers from 1 to nShift inclusive.
rowsWithOne=randRows(1:sj(j)); %row indices having 1, and sum up to sj
Init_xij(rowsWithOne,j)=1;
end
%Adjust the initial xij matrix to make it feasible, satisfying horizontal
%LHS (dli) and RHS (dui) constraints
Init_xij_Feasible=Init_xij;
k=1;
while k
RowSum=sum(Init_xij_Feasible,2); %create a column vector containing the sum of each row
CheckLB=lt(RowSum,dli); %if RowSum <dli, true
CheckUB=gt(RowSum,dui); %if RowSum >dui, true
if ~any(CheckLB)&&~any(CheckUB) %if any element in CheckLB and CheckUB is zero
break,
else
[~,RowIdxMin]=min(RowSum);
[~,RowIdxMax]=max(RowSum);
ColIdx=find(Init_xij_Feasible(RowIdxMax,:) & ~Init_xij_Feasible(RowIdxMin,:),1); % returns the first 1 column index corresponding to the nonzero elements in row RowIdxMax and zero elements in row RowIdxMin.
%swap the min and max elements
[Init_xij_Feasible(RowIdxMin,ColIdx),Init_xij_Feasible(RowIdxMax,ColIdx)]=deal(Init_xij_Feasible(RowIdxMax,ColIdx),Init_xij_Feasible(RowIdxMin,ColIdx));
end
k=k+1;
end

Find the consecutive positive and negative elements for the entire array using matlab

I have a channel from which I take around 1 million samples now it contains both positive and negative values in it. My intention is to find the consecutive positive and negative integers(doesn't have to be same) and once the value is found I can then perform some operations on it. I have given my code below. chA is my channel from where i derive my inputs as values. The code is only giving me a value of 43.2600, which ideally should have given an array of numbers as there are lots of samples which are consecutive positive and negative.
consider the array as [0,1,-3,4,5,6,7,8,9,-19]
for i = 1:1000000 % loops strats from 1 and ends at 1000000
if (chA(i)<0) && (chA((i+1) >0)) % if i = 1, i+1 = -3 <it satisfy the condition>
tan = ((chA(i+1))- chA(i)); %calculate it
deltaOfTime = tan/i; %store the value here in the vector deltaOfTime
end
now in the next iteration it should be able to find out the next consecutive positive and negative value which is 9,-19
I think this is what you are trying to do...
origVec=[0,1,-3,4,5,6,7,8,9,-19];
yTemp=origVec(:); %make a column vector
yTemp = [NaN; yTemp; NaN]; %NaN pad
iTemp = (1:numel(yTemp)).'; %Get index array
% keep only the first of any adjacent pairs of equal values (including NaN).
yFinite = ~isnan(yTemp);
iNeq = [true;((yTemp(1:end-1) ~= yTemp(2:end)) & ...
(yFinite(1:end-1) | yFinite(2:end)))];
iTemp = iTemp(iNeq);
% take the sign of the first sample derivative
s = sign(diff(yTemp(iTemp)));
% find local maxima
iMax = [false;diff(s)<0];
iPk = iTemp(iMax)-1;
pksAndFollowingIdx = [iPk.';iPk.'+1]; %get neighbouring +ve and -ve values
deltaOfTime = diff(origVec(pksAndFollowingIdx))./iPk.'; %take difference between consecutive positive and negative values
That is, if your original code was supposed to be something more like:
for i = 1:10-1 % loop through array???
if (origVec(i)>0) && (origVec(i+1) <0) % check neighbouring +ve THEN -ve values???
tan12 = ((origVec(i+1))- origVec(i)); %calculate difference???
deltaOfTime(i) = tan12/i % deltaOfTime, not sure how this is "delta of time"???
end
end
You should save each of the value you calculate rather than overwrite it each loop:
deltaOfTime = zeros(1,1000000);
for i = 1:1000000 % loops strats from 1 and ends at 1000000
if (chA(i)<0) && (chA((i+1) >0)) % if i = 1, i+1 = -3 <it satisfy the condition>
tan = ((chA(i+1))- chA(i)); %calculate it
deltaOfTime(i) = tan/i; %store the value here in the vector deltaOfTime
end
However there are are better way to calculate the transitions and you would not need to loop through your signal, or pre-allocate large vector deltaOfTime.
This is a way to not pre-allocate values, However it might be slower as the array changes within the loop:
for i = 1:1000000 % loops strats from 1 and ends at 1000000
if (chA(i)<0) && (chA((i+1) >0)) % if i = 1, i+1 = -3 <it satisfy the condition>
tan = ((chA(i+1))- chA(i)); %calculate it
deltaOfTime = cat(2,deltaOfTime,tan/i); %store the value here in the vector deltaOfTime
end
Another try to correct all the bugs in the code:
for i = 1:length(chA)-1
if (chA(i)<0) && (chA((i+1) >0))
temp = ((chA(i+1))- chA(i));
deltaOfTime = cat(2,deltaOfTime,temp/i);
end
end
Fixed the if-statement, as well a the looping condition which will give you an error if you array is exactly 1million long.
Note: avoid using variable names of existing function e.g. tan.
Note2: Are you sure that you do not want both the definition of tan and deltaOfTime to be inside the if-statement?

Indices of constant consecutive values in a matrix, and number of constant values

I have a matrix with constant consecutive values randomly distributed throughout the matrix. I want the indices of the consecutive values, and further, I want a matrix of the same size as the original matrix, where the number of consecutive values are stored in the indices of the consecutive values. For Example
original_matrix = [1 1 1;2 2 3; 1 2 3];
output_matrix = [3 3 3;2 2 0;0 0 0];
I have struggled mightily to find a solution to this problem. It has relevance for meteorological data quality control. For example, if I have a matrix of temperature data from a number of sensors, and I want to know what days had constant consecutive values, and how many days were constant, so I can then flag the data as possibly faulty.
temperature matrix is number of days x number of stations and I want an output matrix that is also number of days x number of stations, where the consecutive values are flagged as described above.
If you have a solution to that, please provide! Thank you.
For this kind of problems, I made my own utility function runlength:
function RL = runlength(M)
% calculates length of runs of consecutive equal items along columns of M
% work along columns, so that you can use linear indexing
% find locations where items change along column
jumps = diff(M) ~= 0;
% add implicit jumps at start and end
ncol = size(jumps, 2);
jumps = [true(1, ncol); jumps; true(1, ncol)];
% find linear indices of starts and stops of runs
ijump = find(jumps);
nrow = size(jumps, 1);
istart = ijump(rem(ijump, nrow) ~= 0); % remove fake starts in last row
istop = ijump(rem(ijump, nrow) ~= 1); % remove fake stops in first row
rl = istop - istart;
assert(sum(rl) == numel(M))
% make matrix of 'derivative' of runlength
% don't need last row, but needs same size as jumps for indices to be valid
dRL = zeros(size(jumps));
dRL(istart) = rl;
dRL(istop) = dRL(istop) - rl;
% remove last row and 'integrate' to get runlength
RL = cumsum(dRL(1:end-1,:));
It only works along columns since it uses linear indexing. Since you want do something similar along rows, you need to transpose back and forth, so you could use it for your case like so:
>> original = [1 1 1;2 2 3; 1 2 3];
>> original = original.'; % transpose, since runlength works along columns
>> output = runlength(original);
>> output = output.'; % transpose back
>> output(output == 1) = 0; % see hitzg's comment
>> output
output =
3 3 3
2 2 0
0 0 0