Remove columns from matrix by logical array: Matlab - matlab

I have a matrix in Matlab and I want to remove some columns from it. I have also a vector with the indices that I want to remove. How exactly I can do so?
train_data % My input matrix with size 1500x773
toremove % 1x773 logical vector values (0,1), 1 at 40 indices
How can I apply toremove to the train_data to remove the desired indices?
output = train_data(toremove) % I want the output to be a matrix with size 1500x733

If your array is truly logical (true/false) you can use it directly for indexing, it sounds like it's binary though (0/1), so you can use logical(toremove) to convert it to logical, then it's simple:
train_data = train_data(:,~logical(toremove));
% or equivalently
train_data(:, logical(toremove)) = [];
Avoiding a call to the find function will increase speed.

If you wish to delete columns in 2d matrix based off 1d column matrix:
output = train_data(:,find(toremove<1));
If it's rows that need deleting instead, based off 1d row matrix:
output = train_data(find(toremove<1),:);
Might do the job if I understand this correctly.

Related

Reshape a 3D matrix to 4D matrix in MATLAB [duplicate]

I want to reshape pixel intensity by imagesize*1(column vector).
Imvect = reshape(I,imsize,1);
But why these error comes?
Error using reshape
To RESHAPE the number of elements must not change.
Let's start with the syntax used in the documentation:
B = reshape(A,sz1,...,szN)
What reshape does is to take the matrix A, straightens it out, and gives it a new size, that's determined by the 2nd, 3rd to the Nth argument. For this to be possible, you need to have the same number of elements in the input matrix as you have in the output matrix. You can't make a 1x5 vector turn into a 2x3 vector, as one element would be missing. The number of elements in the output matrix will be proportional to the product of sz1, sz2, ..., szN. Now, if you know you want N rows, but don't know exactly how many columns you have, you might use the [] syntax, that tells MATLAB to use as many columns as necessary to make the number of elements be equal.
So reshape(A, 2, [], 3) will become a 2xNx3 matrix, where, for a matrix with 24 elements, N will be 4.
Now, in your case this is not the case. numel(I) ~= imsize. If mod(numel(I), imsize) ~= 0 then your imsize is definitely incorrect. However, if mod(numel(I), imsize) == 0, then your error might be that you want imsize number of rows, and a number of columns that makes this possible. If it's the latter, then this should work:
Imvect = reshape(I,imsize, []);
If you simply want to make you matrix I a vector of size (numel(I), 1), then you should use the colon operator :, as such:
Imvect = I(:);
An alternative, if you really want to use reshape, is to specify that you want a single column, and let MATLAB select the number of rows, as such:
Imvect = reshape(I, [], 1);

Creating Multi Dimesnional Array from 1D array in Matlab?

Hello I am trying to create a simple array that contains a '10' 3x3 matrices. So I tried to create a 1D matrix that has 1 x 10 values. Then I tried assigning a 3x3 matrix in to each of the 10 slots in the 1D matrix. I am quite sure my syntax is wrong and matlab (I don't think allows this) but I couldn't find too much info to pre assign such array and I just started learning about matlab. Here is my attempt:
big_array = zeros(1,10) # creates 1x10 1d array
for i = 1:10
big_array(i) = zeros(3,3); #supposedly? assign 3x3 matrix in to each of the 10 slots
end
big_array # received an error
If you know that you want an array of 10 3x3 matrices, you would typically want to use a multidimensional array from the start.
big_array = zeros(10,3,3);
You can access the i'th matrix using big_array(i,:,:).
If you really do want a one-dimensional array of 3x3 matrices, you need to use a cell array.
big_array = {};
for i = 1:10
big_array{i} = zeros(3,3);
end
big_array
You can now access the i'th matrix using big_array{i}.
A small clarification - If all your slots must contain submatrices with the same size, then you can use very simple expression:
big_array = zeros(3,3,10) % (first dimension - rows, second dimension - columns, third dimension - bands or arrays)

How to loop through each value in a 3D matrix?

I have a matrix, 10x10x40, that is storing information of an image through time, where the the rows and columns indicate the spectral value at a specific point, and the third dimension is time. So in other words, a 10x10 image at 40 points in time. I would like to loop through each row, column and view that pixel history (1,1,:), (1,2,:)....(10,10,:).
Here's what I'm doing now:
val = [];
for i = 1:10;
for j = 1:10;
for k = 1:length(timevector)
val(k) = my_matrix(i,j,k);
end
end
end
Since I want to iterate through each pixel in time and then save that data, what would be the best way to store the new value/time vectors? I want to end up with 100 pixel history vectors, right now I end with one, and it's because val is written over within the loop. I know it's not advised to create variables within a loop, so what is the best alternative? Should I look into storing the output as a structure? I've been staring at this and I have over-complicated everything.
Depending on the structure you prefer, you can also use matlab's functions reshape and num2cell to get the output in the following form:
Alternative 1:
A = reshape(A,[],10);
This will return a matrix (100x40) where each row is a pixel's history.
Alternative 2:
A = num2cell( reshape(A,[],40), 2)
This will return a cell array (100x1) where each cell contains a vector (40x1) with each pixel's history.
Alternative 3:
A = squeeze( num2cell( permute(A, [3,1,2]), 1) );
This will return a cell array (10x10) where each cell contains a vector (40x1) with each pixel's history.
Depending on what you want to do with it, you don't need to store them in separate vectors. You can just get one of these pixel history vectors, like so,
pixel_history = squeeze(my_matrix(1,1,:));
squeeze will remove the singleton dimension from the slice, and make it into a 40-by-1 vector, instead of a 1-by-1-by-40 matrix.
To make the time dimension the first matrix dimension, you could also permute the matrix,
permute(my_matrix, [3 2 1]);
This will swap the 3rd and 1st dimensions, making the 1st dimension time.

How to sum 3d Matrix row by interval in Matlab?

I have a 36x256x2232 3d matrix in Matlab created by M = ones(36,256,2232) and I want to reduce the size of the matrix by sum rows by interval 3. The result matrix should be 12x256x2232 and each cell should have the value 3.
I tried using reshape and sum function but I get 1x256x2232 matrix.
How can I do this without using the for-loop ?
This should do it:
M = ones(36,256,2232)
reduced = reshape(sum(reshape(M, 3,[], 256,2232), 1),[], 256, 2232);
reshape makes a 4d matrix with the given intervals
sum reduce it
second reshape transform it to 3d again
you can use also squeeze, which removes singleton dimensions:
reduced = squeeze(sum(reshape(M, 3,[], 256,2232), 1));
You can use the new-ish splitapply function (which is similar to accumarray but can handle data with multiple dimensions). This approach works even if the number of rows is not a multiple of the group size:
M = ones(4,5,2); % example data
n = 3; % group size
result = splitapply(#(x)sum(x,1), M, floor((0:size(M,1)-1).'/n)+1);

Vectorizing by splitting matrix by rows unequally

I have X_test which is a matrix of size 967874 x 3 where the columns are: doc#, wordID, wordCount, and there's 7505 unique doc#'s (length(unique(X_test(:,1))) == length(Y_test) == 7505). The matrix rows are also already sorted according to the doc#'s column.
I also have a likelihoods matrix of size 61188 x 20 where the rows are all possible wordIDs, and the columns are different classes (length(unique(Y_test))==20)
The result I'm trying to obtain is a matrix of size 7505 x 20 where each row signifies a different document and contains, for each class (column), the sum of the wordCounts of the values in the likelihood matrix rows which correspond to the wordIDs for that document (trying to think of better phrasing...)
My first thought was to rearrange this 2D matrix into a 3D matrix according to doc#s, but the number of rows for each unique doc# are unequal. I also think making a cell array of 7505 matrices isn't a great idea, but may be wrong about that.
It's probably more explanatory if I just show the code I have that works, but is slow because it iterates through each of the 7505 documents:
probabilities = zeros(length(Y_test),nClasses); % 7505 x 20
for n=1:length(Y_test) % 7505 iterations
doc = X_test(X_test(:,1)==n,:);
result = bsxfun(#times, doc(:,3), log(likelihoods(doc(:,2),:)));
% result ends up size length(doc) x 20
probabilities(n,:) = sum(result);
end
for context, this is what I use the probabilities matrix for:
% MAP decision rule
probabilities = bsxfun(#plus, probabilities, logpriors'); % add priors
[~,predictions] = max(probabilities,[],2);
CCR = sum(predictions==Y_test)/length(Y_test); % correct classification rate
fprintf('Correct classification percentage: %0.2f%%\n\n', CCR*100);
edit: so I separated the matrix into a cell array according to doc#'s, but don't know how to apply bsxfun to all arrays in a cell at the same time.
counts = histc(X_test(:,1),unique(X_test(:,1)));
testdocs = mat2cell(X_test,counts);