When I run this program, I get the error message:
??? Index exceeds matrix dimensions.
Error in ==> if a(1,i)==0
could you tell me why??
a = randi(5,4,100)-ones(4,100);
[n m]=size(a);
for i=1:m
if a(1,i)==0
a(:,i)=[];
end
end
The reason is that you are removing columns from your matrix, so inside the for loop you are reducing its dimension. Then you try to access a column with an index which refers to the original matrix, before the columns were removed.
Try this instead:
a = randi(5,4,100)-1;
ind2remove = (a(1,:) == 0);
a(:,ind2remove) = [];
You get that error because during the execution of this for loop, you might remove some columns. Therefore the dimensions of the matrix will decrease and you will try to access elements that have been moved to a different place.
To do wht you want, you either have to write a while loop, keeping the indices in check manually. The other solution is to vectorize your solution as itamar Katz has shown. That solution is more MATLAB-esque than writig a while loop.
But I have noticed that allowing a random algorithm to emit vectors of random length can sometimes prove more difficult to handle than fixed-length vectors. So you might want to construct your vector in such a way that you don't even have to remove such entries, depending on your application this might be accomplished by generating the first row and other rows with different instructions.
Related
I am trying to sum in the second dimension a matrix QI in Matlab. The trick is, the columns contain a series of increasing numbers, but not all columns have the same number of elements (i.e. numel(QI(:,1)) ~= numel(QI(:,2)) and so on). For the sake of clarity, I attach a picture of it. Note that I padded the missing areas with 0, so the previous condition becomes nnz(QI(:,1)) ~= nnz(QI(:,2)).
One initial strategy that I thought of was to treat this as an image and construct a mask for each different gradient level, but that seems like a tedious job.
Anyone has a better idea on how to do this? I should also mention that I am able to freely modify how QI is generated, but I'd rather not if there is a solution for this problem.
EDIT:
Hopefully the new colored image should give a better understanding.
FYI, each column was previously stored in a cell array without the trailing zeros. Then I extracted the columns one by one and stored them in a matrix in order to perform the summation, padding the extra zeros whenever the length isn't the same.
Generally these column data should have the same number of rows, but sometimes that's not the case, and even worse, they do not allign properly.
I'm starting to think if it's better to rework the code that generate the cell arrays rather than this matrix. Thoughts?
Thank you,
edit: following you comment, I modified the answer. Be aware that your data cannot be really "aligned" because they have not the same number of value.
A way would be to use a cell as a storage for your measures.
valueMissing = 0; % here you can put the defauld value you want
% transform you matrix in a cell
QICell = arrayfun(#(x) QI(QI(:,x)!=valueMissing,x), 1:size(QI,2),'UniformOutput', false);
Now you can sum the last element of the vectors inside the cell
QIsum = sum(cellfun(#(x) x(end), QICell))
Or reorder the vectors so that your last element are "aligned"
QICellReordered = cellfun(#(x) x(end:-1:1),QICell, 'UniformOutput',false);
Then you can make all possible sums:
m = min(cellfun(#numel, QICellReordered));
QIsum = zeros(m,1);
for i=1:m
QIsum(i) = sum(cellfun(#(x) x(i), QICellReordered));
end
% reorder QISum to your original order
QIsum = QIsum(end:-1:1);
I hope this help !
I'm trying to finish a program and for some reason, the matrix I loaded into Matlab is messing with the ability to select the rows inside it. I'm trying to select all the rows in the matrix and see which values match the criteria for a Live setting. However I can select specific values/sections of the matrix in the command window without issue. Why is this happening? Any ideas?
It appears to only happen when in a for loop, I can do it just fine when it's on its own.
The syntax is: for x = start:stop. I think you are trying to do a for to the whole "A" matrix. You can split "A", according to its format (e.g. if is a table split in two variables).
bye
Richardd is right on; you're trying to iterate on a matrix, no good.
If I read you right, you're trying to run through your A matrix one column at a time, and see all the rows in that column? Assuming that is correct...
Your A matrix is 14x3, so you should go through your for loop 3 times, which is the size of your column dimension. Luckily, there is a function that MATLAB gives you to do just that. Try:
for iColumn = 1:size(A,2)
...
end
The size function returns the size of your array in a vector of [rows, columns, depth...] - it will go as many dimensions as your array. Calling size(A,2) returns only the size of your array in the column dimension. Now the for loop is iterating on columns.
Hi and thank you for viewing my question.
I have a large spreadsheet (over 650,000 rows) that I am trying to spit up into separate parts of a structure. I am trying to split it up by the values in one of the columns of which there is 1132 unique text values. The rest of the columns are numerical. I have created a matrix of the numerical values with 4 columns called 'SectionID_Matrix' and a cell array for the text column I want to split the data up by called 'ELR'. I am also trying to name the parts in the structure by the text value I have split them up by. My code is as follows:
ELR_list = unique (ELR);
[m,~]=size(ELR_list);
n = 1;
b = [];
for j = 1:m
x = strcmp(ELR_list(n), char(ELR));
b(:,1) = SectionID_Matrix(x(:,1),1);
b(:,2) = SectionID_Matrix(x(:,1),2);
b(:,3) = SectionID_Matrix(x(:,1),3);
b(:,4) = SectionID_Matrix(x(:,1),4);
t = char(ELR_list(n));
s.(t) = b;
n = n+1;
end
clearvars -except *ELR_list* *ELR* *SectionID_Matrix* *s*
When I run this code though I get an error saying 'Subscripted assignment dimension mismatch'. Error in Sorting_Out_Locations (line 10). b(:,1) = SectionID_Matrix(x(:,1),1);
This is confusing me because when I remove the for loop and manually change the value of n, it works perfectly fine giving me a matrix in the structure with all the rows that contain the nth text value with the name of the text value.
I understand the error is caused by attempting to assign more elements to a section of a matrix or vector than that section can hold but I don't understand where that is happening.
Is there an error in my code that is causing the for loop to fail? because from my limited understanding the loop should just keep going around increase n by 1 each time until it has gone through all of the unique ELR values.
This is my very first time on Matlab (so any pointer on my code are very appreciated) and have spend all afternoon trying to get this working but no amount of internet help or the matlab website is helping.
Thank you for any help
In your code, the first time it runs through the loop, the size of the b matrix is set according to the number of true values in x. The next time it runs through the loop, that may be a different size, so you get the mismatch.
You can just clear b at the end of each loop iteration with b = []
The error Subscripted assignment dimension mismatch appears when you try to insert a matrix of a certain size into a matrix of a different size. For your code, it means that in the line
b(:,1) = SectionID_Matrix(x(:,1),1);
there is an attempted insertion of mismatching sizes: the size of SectionID_Matrix(x(:,1),1) and the size of b(:,1) are not the same. This is most likely because you only take certain values of each column of SectionID_Matrix using the logical indexing of x. To fix this you need the same logical indexing in b:
b(x(:,1),1) = SectionID_Matrix(x(:,1),1);
I'm currently working on a cellular automata but i keep running into this problem. I have a matrix idxR which contains zero's and/or ones, depending on a probability process:
idxR = ((rRecr>rEmpty)&(rRecr>rAlgae)&(rRecr>rCoral));
Now i want to replace all ones in idxR with unique values and assign it to the variable colonies. I came up with the following:
colonies = idxR;
no = sum(colonies(:)==1)
maxvalue = max(colonies(:));
replace = [1:no]+maxvalue;
ret = reshape(replace,no,1);
colonies(colonies==1) = colonies(colonies==1).*ret;
When i output colonies it gives me a matrix with just ones and zeros and not a matrix where all ones have been replaced with incremental values. I tried this code in a new file and assigned a matrix with random ones and zeros to idxR and then it seems to work. So i guess to problem lies with the matrix idxR in my automata. It might be worth mentioning that idxR is contained in a for loop.
Can somebody tell me how to fix this?
You got the entire logic correct, except one minor flaw. You have idxR as a logical matrix. Hence colonies is a logical matrix too. Therefore, you get the expected output till the second-last line. Problem occurs on the last line, when you try to assign an array of numbers in which each number is greater than 1 (colonies(colonies==1).*ret;) to a logical matrix.
Elements greater than 1 are clipped to one and thus you see only zeros and ones. There is a simple workaround. Change the first line to
colonies = double(idxR);
P.S. The answer was right in front of you, you just didn't spot it. You had written:
I tried this code in a new file and assigned a matrix with random ones and zeros to idxR and then it seems to work.
The idxR matrix must have been of double datatype, if you used randi.
Parag got it right. You have the solution there.
You can use the following code if you are looking for a more "organized" way to get to 'colonies' -
colonies = double(idxR);
maxvalue = max(colonies(:));
ind1 = find(idxR==1);
colonies(ind1)=maxvalue + (1:numel(ind1));
I want to apply a function to all columns in a matrix with MATLAB. For example, I'd like to be able to call smooth on every column of a matrix, instead of having smooth treat the matrix as a vector (which is the default behaviour if you call smooth(matrix)).
I'm sure there must be a more idiomatic way to do this, but I can't find it, so I've defined a map_column function:
function result = map_column(m, func)
result = m;
for col = 1:size(m,2)
result(:,col) = func(m(:,col));
end
end
which I can call with:
smoothed = map_column(input, #(c) (smooth(c, 9)));
Is there anything wrong with this code? How could I improve it?
The MATLAB "for" statement actually loops over the columns of whatever's supplied - normally, this just results in a sequence of scalars since the vector passed into for (as in your example above) is a row vector. This means that you can rewrite the above code like this:
function result = map_column(m, func)
result = [];
for m_col = m
result = horzcat(result, func(m_col));
end
If func does not return a column vector, then you can add something like
f = func(m_col);
result = horzcat(result, f(:));
to force it into a column.
Your solution is fine.
Note that horizcat exacts a substantial performance penalty for large matrices. It makes the code be O(N^2) instead of O(N). For a 100x10,000 matrix, your implementation takes 2.6s on my machine, the horizcat one takes 64.5s. For a 100x5000 matrix, the horizcat implementation takes 15.7s.
If you wanted, you could generalize your function a little and make it be able to iterate over the final dimension or even over arbitrary dimensions (not just columns).
Maybe you could always transform the matrix with the ' operator and then transform the result back.
smoothed = smooth(input', 9)';
That at least works with the fft function.
A way to cause an implicit loop across the columns of a matrix is to use cellfun. That is, you must first convert the matrix to a cell array, each cell will hold one column. Then call cellfun. For example:
A = randn(10,5);
See that here I've computed the standard deviation for each column.
cellfun(#std,mat2cell(A,size(A,1),ones(1,size(A,2))))
ans =
0.78681 1.1473 0.89789 0.66635 1.3482
Of course, many functions in MATLAB are already set up to work on rows or columns of an array as the user indicates. This is true of std of course, but this is a convenient way to test that cellfun worked successfully.
std(A,[],1)
ans =
0.78681 1.1473 0.89789 0.66635 1.3482
Don't forget to preallocate the result matrix if you are dealing with large matrices. Otherwise your CPU will spend lots of cycles repeatedly re-allocating the matrix every time it adds a new row/column.
If this is a common use-case for your function, it would perhaps be a good idea to make the function iterate through the columns automatically if the input is not a vector.
This doesn't exactly solve your problem but it would simplify the functions' usage. In that case, the output should be a matrix, too.
You can also transform the matrix to one long column by using m(:,:) = m(:). However, it depends on your function if this would make sense.