Make vectors of unequal length equal in length by reducing the size of the largest ones - matlab

I am reading 5 columns from a .txt file to 5 vectors.
Sometimes some vectors are one element larger than others, so I need to check if they are all of equal length, and if not, I have to find which ones are the largest and delete their last element. I think I should be able to do this without loops. I was originally thinking of using find in combination with isequal but isequal only returns a logical, and does not provide any information on which vectors are the largest.
[Seconds,Sensor1VStatic,Sensor2VPulsed,TemperatureC,RelativeHumidity] = importfile(path);
Then depending on what vectors are longer by one element, I will do, for example
Seconds(end) = [];
Sensor1VStatic(end) = [];
If Seconds and Sensor1VStatic are longer than the other vectors by one element

Assume your vectors are in a cell array A:
A = {[1 2 3], [1 2 3 4], [1 2 3 4 5]};
You can get the size of each vector with
sz = cellfun(#(x)size(x,2), A);
Which will return (for the above example)
sz = [ 3 4 5]
Now you can find the shortest vector:
minLength = min(sz);
And finally, make all vectors this length:
B = cell2mat(cellfun(#(x)x(1:minLength), A, 'uniformoutput', false))';
There may be more elegant ways (and note that cellfun really is doing "implicit looping")
Applying this to your (now expanded) example, you could probably assign the output of importfile directly to the cell array - or you can do it as a separate line:
A = {Seconds,Sensor1VStatic,Sensor2VPulsed,TemperatureC,RelativeHumidity};
But it all becomes a lot of work. Instead you could do:
minLength = min(size(Seconds,1), size(Sensor1VStatic,1), size(Sensor2VPulsed,1), ...
Seconds = Seconds(1:minLength);
...
There is scope for some cleverness but it won't make things more readable, and it won't save time in the long run...

Related

Extracting a matrix from a cell vector in MATLAB

A sparse matrix is a large matrix with almost all elements of the same
value (typically zero). The normal representation of a sparse matrix
takes up lots of memory when the useful information can be captured
with much less. A possible way to represent a sparse matrix is with a
cell vector whose first element is a 2-element vector representing the
size of the sparse matrix. The second element is a scalar specifying
the default value of the sparse matrix. Each successive element of the
cell vector is a 3-element vector representing one element of the
sparse matrix that has a value other than the default. The three
elements are the row index, the column index and the actual value.
Write a function called "sparse2matrix" that takes a single input of a
cell vector as defined above and returns the output argument called
"matrix", the matrix in its traditional form. Consider the following
run:
cellvec = {[2 3], 0, [1 2 3], [2 2 -3]};
matrix = sparse2matrix(cellvec)
matrix =
0 3 0
0 -3 0
Good morning/afternoon/night, everyone
I was wondering if you could help me with this.
I am trying to complete this, but I am not sure how to deal with this. I understand that I am interested in the first part of the cell vector, but I am not sure about how to tell Matlab I need that. This is my code:
function matrix = sparse2matrix(x)
A = [2 3];
B = 0;
C = [1, 2, 3];
x = {A, 0, C};
matrix = cell2mat(x);
end
The result of this code is different from the result I showed above.
I am not getting the right answer and honestly I do not know what to do, so I would appreciate if you guide me a little bit.
Not the most elegant way of doing it but it gets the job done. Uses the cell2mat() function and indexing to grab the necessary values for each step. A for-loop is then used to obtain the 3-element vectors that is used to change the array values from the default values in the respective indices.
cellvec = {[2 3], 0, [1 2 3], [2 2 -3]};
[matrix] = sparse2matrix(cellvec)
function [matrix] = sparse2matrix(x)
Matrix_Size = cell2mat(x(1,1));
Matrix_Height = Matrix_Size(1);
Matrix_Width = Matrix_Size(2);
Default_Value = cell2mat(x(1,2));
matrix = Default_Value*ones(Matrix_Height,Matrix_Width);
Triplets = x(3:end);
Number_Of_Triplets = length(Triplets);
for Triplet_Index = 1: Number_Of_Triplets
Current_Triplet = cell2mat(Triplets(1,Triplet_Index));
Row = Current_Triplet(1,1);
Column = Current_Triplet(1,2);
Value = Current_Triplet(1,3);
matrix(Row,Column) = Value;
end
end
Explanation:
The first line in the local function sparse2matrix() indicates to retrieve row 1, column 1 of the cell array x and then convert it to a matrix. The conversion is done using the cell2mat() function.
Matrix_Size = cell2mat(x(1,1));
Results in:
Matrix_Size = [2 3]
The following line indicates to grab index 1 of the previous array Matrix_Size. This will be used to determine the height of the output array matrix. This is done in a similar fashion to evaluate the Matrix_Width using index 2.
Matrix_Height = Matrix_Size(1);
Results in:
Matrix_Height = 2
Ran using MATLAB R2019b

Windowed subtraction of vectors that are not same size and then finding the mean of results

Good day,
I have a question what I want to achieve without the loop if possible. As title says I need to do windowed subtraction of vectors that are not same size and then finding the mean of results.
As example, let say that we have vector a = [2 3 4 5 6] and vector b = [1 2].
Program will have to move window with smaller numbers of elements (in this example vector b) over bigger one (vector a) and make operations on that way so it starts in first two elements in vector a and make subtraction with vector b and then sum results and find mean.
In this example it will just make calculation of subtraction 2-1 = 1, 3-2 = 1, summing results 1+1=2 and divide them with 2 (because vector b is that size). Final result is 1.
Then we move window on second elements of vector a (value 3 and 4 there, or index 2 and 3) and repeat process to the last elements of vector a.
For final result we need to get vector c who consist of elements [1 2 3 4] for this example.
Is this possible to do without looping because I have data sets over 10k of size. Thanks in advance
I can solve it with only one loop, iterating through "b" (two loops in your example).
Declare vectors (as columns! This is needed for matlabs computations to work)
a = [2 3 4 5 6]';
b = [1 2]';
Declare matrix for computed results. Each column represents subtractions of elements in "a" with one of the elements in "b".
c = zeros(length(a)-length(b)+1,length(b));
for k = 1:length(b)
c(:,k) = a(k:length(a)-length(b)+k)-b(k);
end
Now just sum the elements in "c" row wise and divide by length of "b" to get the mean
result = sum(c,2)/length(b);
You can simplify this for your exact example, but this is a generic solution for any vetors "a" and "b", where "b" is the smaller vector.

Fastest way of finding repeated values in different cell arrays of different size

The problem is the following:
I have a cell array of the form indx{jj} where each jj is an array of 1xNjj, meaning they all have different size. In my case max(jj)==3, but lets consider a general case for the shake of it.
How would you find the value(s) repeated in all the jj i the fastest way?
I can guess how to do it with several for loops, but is there a "one (three?) liner"?
Simple example:
indx{1}=[ 1 3 5 7 9];
indx{2}=[ 2 3 4 1];
indx{3}=[ 1 2 5 3 3 5 4];
ans=[1 3];
One possibility is to use a for loop with intersect:
result = indx{1}; %// will be changed
for n = 2:numel(indx)
result = intersect(result, indx{n});
end
Almost no-loop approach (almost because cellfun essentially uses loop(s) inside it, but it's effect here is minimal as we are using it to find just the number of elements in each cell) -
lens = cellfun(#numel,indx);
val_ind = bsxfun(#ge,lens,[1:max(lens)]');
vals = horzcat(indx{:});
mat1(max(lens),numel(lens))=0;
mat1(val_ind) = vals;
unqvals = unique(vals);
out = unqvals(all(any(bsxfun(#eq,mat1,permute(unqvals,[1 3 2]))),2));
Another possibility that I could suggest, though Luis Mendo's answer is very good, is to take all of the vectors in your cell array and remove the duplicates. This can be done through cellfun, and specifying unique as the function to operate on. You'd have to set the UniformOutput flag to false as we are outputting a cell array at each index. You also have to be careful in that each cell array is assumed to be all row vectors, or all column vectors. You can't mix the way the arrays are shaped or this method won't work.
Once you do this, concatenate all of the vectors into a single array through cell2mat, then do a histogram through histc. You'd specify the edges to be all of the unique numbers in the single array created before. Note that you'd have to make an additional call to unique on the output single array before proceeding. Once you calculate the histogram, for any entries with a bin count equal to the total number of elements in your cell array (which is 3 in your case), then these are values that you see in all of your cells. As such:
A = cell2mat(cellfun(#unique, indx, 'uni', 0));
edge_values = unique(A);
h = histc(A, edge_values);
result = edge_values(h == numel(indx));
With the unique call for each cell array, if a number appears in every single cell, then the total number of times you see this number should equal the total number of cells you have.

MATLAB: Adding vectors to a matrix and counting the number of non zeros

I have the following problem:
A = [] % matrix
Q = [] % number on non zero in each row
for i=1:10
% I generate a path with name path
% add the path to the matrix A
end
% count number on non zero numbers in each row
How can I do that?
Here is an illustrative example:
If the path in first iteration was: path = [ 1 2 3 4 ]
In the second iteration: path = [ 4 5 6 ]
In third iteration: path = [ 7 2 ]
Then A should be like this:
A =
[1 2 3 4 ,
4 5 6 0 ,
7 2 0 0 ]
After, I would like a vector to show me the number of numbers different than zero in each row like so:
Q = [4 3 2]
Given your comments, this is what I would suggest that you do:
Because the actual paths are not known a priori, I would suggest that you store all of the paths in a cell array. Given your for loop condition, I'm assuming that there will be 10 paths. The actual paths we don't know, but we know there will be 10.
Write some code that will figure out the maximum length of path as this will dictate the size of our matrix A.
Create the matrix A then store of all the paths in, with zeroes appended at the end of each path should they not be the size of the maximum length of the path.
Using the matrix A, figure out how many non-zeroes there are.
Without any further ado, here is the code you are seeking. With each step, I will explain what I am doing to get the desired step.
Step #1
pathCellArray = cell(10, 1);
for i = 1 : 10
%// Insert path generation code here...
%// Assume that the variable is called
%// 'path' that stores this path
%//..
pathCellArray{i} = path;
end
This should be self-explanatory. For each path that you generate, store it in its corresponding cell. The reason why we are placing each path in a cell is because the length of each path is variable. We are also doing this so we can figure out how many columns we need to allocate for A. Also take note that I am creating a cell array of columns. The reason why is because when we do a reconstruction and solve for A, it will make things easier.
Step #2
%// Use cellfun that takes in a cell array and we will
%// generate an array as output that contains the
%// size of each path. We will find the maximum of
%// all of these that will dictate our size of A
lengthArray = cellfun(#length, pathCellArray);
numCols = max(lengthArray);
Now this is something cool. You probably have never seen cellfun before. How cellfun works is that we specify a custom function, and cellfun will apply this function to every element to this cell. For the output of cellfun the i'th position of the output is the output of the custom function for each i'th position of the input cell array. As such, what we are doing here is that we are generating a length array (stored as lengthArray) that goes through each cell and figures out how big the path is. lengthArray will thus store how long each path is. Once we do that, we figure out what the longest path is so we know how big A will be.
Step #3
pathCellArrayAppend = cellfun(#(x) [x zeros(1,numCols-length(x))], ...
pathCellArray, 'UniformOutput', false);
A = cell2mat(pathCellArrayAppend);
This code is probably the most complex out of all that you have dealt with. What I am basically doing here is taking that cell array of paths that I created, and generating a new cell array where each element in the cell (which is our path) gets appended with zeroes up until the length of the longest path. If you look, the custom function we have generated basically creates the array that first stores the path that we want, then zero-pads the rest of the array with zeroes. We have to specify UniformOutput to false as because the output of the the custom function is no longer a single value. It is an array as the output, which is why this flag is set to false. The output of this call to cellfun will generate 10 cell arrays where each element is a path and is zero-padded with zeroes. We then call cell2mat to convert this cell array back to matrix form, and A is your result.
Step #4
Q = cellfun(#(x) sum(x ~= 0), pathCellArrayAppend);
We thus call cellfun again. This time we take a look at our cell array that has all of the paths that are zero-padded. We go through each cell, and count how many non-zero entries there are. Q will store this result. Note that we don't need to set UniformOutput to false as the output of the custom function is a single number.
Using your example that you have provided, here is how the code will look with their corresponding outputs:
%// Step #1 - Simulated
p1 = [1 2 3 4];
p2 = [4 5 6];
p3 = [7 2];
pathCellArray = {p1; p2; p3};
%// Step #2
lengthArray = cellfun(#length, pathCellArray)
>> lengthArray =
4
3
2
numCols = max(lengthArray)
>> numCols =
4
%// Step #3
pathCellArrayAppend = cellfun(#(x) [x zeros(1,numCols-length(x))], ...
pathCellArray, 'UniformOutput', false);
A = cell2mat(pathCellArrayAppend)
>> A =
1 2 3 4
4 5 6 0
7 2 0 0
%// Step #4
Q = cellfun(#(x) sum(x ~= 0), pathCellArrayAppend)
>> Q =
4
3
2
NB: You could simply use Step #2 as your Q, provided that your paths are non-zero. If there are, then you need to go right to Step #4.

Combination of colon-operations in MATLAB

I have a question concerning the colon operator and expansion of vectors in MATLAB. My problem is to understand how the following line of code expands, to be able to use it for other sequences. The line of MATLAB code is:
a(1:2:5) = 1:-4:-7
Note that a is not defined before the expansion. This returns the vector
a = 1 0 3 0 -7
I know how the colon operator works with {start}:{step}:{stop}, my problem is to understand how and why the combination of a(1:2:5)and 1:-4:-7 returns a vector of five elements with zeros in position 2 and 5?
Whenever Matlab detects you're indecing to an element outside the current bounds of the matrix/array, it will automatically pad the missing elements with zeros:
>> clear b; b(10) = 5
b =
0 0 0 0 0 0 0 0 0 5
This feature is both very useful, and very dangerous. It is useful for the fact declarations can be made very easy, such as your own case. You can create a whole array of custom-made classes by issuing something like
myClassArray(500) = myClass(1, 2);
which is infinitely better than something like
% cannot pre-allocate (zeros() or ones() give double/uint8/..., not myClass)
for ii = 1:499
myClassArray(ii) = myClass; % so, growing array
end
myClassArray(500) = myClass(1,2);
But, growing arrays can be hard to spot:
a = zeros(10,1);
for ii = 1:10
a(ii+1) = rand;
end
which can make performance drop tremendously. Also, when you translate code prototyped in Matlab to a statically-typed language like C++, copying this code will result in buffer overflows and thus segfaults.
Now, going back to your case:
clear a; a(1:2:5) = 1:-4:-7
The 1:2:5 will expand to the array [1 3 5], and the 1:-4:-7 will give the values [1 -3 -7]. Since the variable a does not exist yet, Matlab will create a new one and fill the elements [1 3 5] with the values [1 -3 -7]. The indices that have been skipped in order to initialize variable a (namely, [2 4]) will then have been initialized automatically to zero.
If you're familiar with Python, it's a bit like the syntax to assign multiple values to multiple variables
x,y = 1,2
But in your Matlab case, these different variables are indices to a non-existent array, which requires "filling the holes with something" to make it a valid, consistent array.
Does this make things clear?
when you define a(1:2:5), it creates a size 5 vector (zero-valued), and selecting odd indexed(3 of them exists) cells. 1:-4:-7 creates three values (not five). Finally your selected three cells are filled with data of 3 values coming from 1:-4:-7