I tried looking this up, but don't really know what to look for...
I need to "table-join" N vectors, meaning,
to create a matrix in which every input vector has a row, and every possible entry has a column.
Also it would be nice to have a translation vector to has easy access to which column is responsible for which entry
for example
a = [3, 2, 4, 9]
b = [3, 1, 5, 9]
c = [2, 4, 9, 6]
then
join(a, b, c) =
[
3; 2; nan; 4; nan; 9; nan,
3; nan; 1; nan; 5; 9; nan,
nan; 2; nan; 4; nan; 9; 6,
]
with a translation vector
[3,2,1,4,5,9,6]
so if I find out something about the i'th column, I can easily know what that column represents.
I prefer the join operation to be able to take in n vectors (they can be of the same length), but 2 is also ok.
Also, on a second glance, this data representation seems a bit redundant at some points. Perhaps there is a better way to even represent the "join-matrix"
Thanks
Basically you want to construct your translation vector using all the possible unique inputs in the order that they were received. To do this, we can concatenate all of the inputs together than find the unique values.
values = cat(1, [3, 2, 4, 9], [3, 1, 5, 9], [2, 4, 9, 6])
%// 3 2 4 9
%// 3 1 5 9
%// 2 4 9 6
translationVector = unique(values, 'stable')
%// 3 2 1 4 5 9 6
Then we want to use ismember to return a logical array for any given input to specify which values of our translation vector are present in the input argument.
columns = ismember(translationVector, [3 2 4 9])
%// 1 1 0 1 0 1 0
We then want to set just those columns in the output matrix.
output(1, columns) = [3 2 4 9];
%// 3 2 NaN 4 NaN 9 NaN
%// NaN NaN NaN NaN NaN NaN NaN
%// NaN NaN NaN NaN NaN NaN NaN
We then repeat this for all of your input arrays.
Implementation
Here is some code that accomplishes that.
function [out, translationVector] = yourjoin(varargin)
%// Make sure all inputs are row vectors
varargin = cellfun(#(x)x(:).', varargin, 'uni', 0); %'
%// compute the translation vector
translationVector = unique(cat(1, varargin{:}), 'stable');
%// Pre-allocate your matrix of NaNs
out = nan(numel(varargin), numel(translationVector));
%// Fill in each row using each input argument
for k = 1:numel(varargin)
%// Identify columns that we have
toreplace = ismember(translationVector, varargin{k});
%// Set the values of those columns to the input values
out(k,toreplace) = varargin{k};
end
end
And then as a test:
a = [3 2 4 9];
b = [3 1 5 9];
c = [2 4 9 6];
D = yourjoin(a,b,c)
3 2 NaN 4 NaN 9 NaN
3 NaN 1 NaN 5 9 NaN
NaN 2 NaN 4 NaN 9 6
Related
I have a matrix1 like that:
matrix1 = [4 2 NaN 3
8 4 1 3
7 7 NaN 2
5 NaN NaN 1];
I take from the user the row index which will be used. I need indexes of columns without NaN elements of this row. Then, these indexes should be assigned to a vector.
This is my code:
rowindex = input('Which row do you choose?: ');
vector1 = find(matrix1(rowindex,setdiff(1:end,find(isnan(matrix1(rowindex,:))))));
For example, when rowindex = 3, vector1 should be [1 2 4] but the result is [1 2 3]. What should I do to correct my code?
You should write:
vector1 = find(~isnan(matrix1(rowindex,:)))
I have a matrix A and B as the following:
A = [1 NaN 3 4 5 NaN NaN 8 9 10];
B = [2 6 7];
Matrix B has the same size as there are NaN values in matrix A (so 3x1 in this case).
I would like to replace the NaN values in the same order as the values appear in B. So the output should look like:
C = [1 2 3 4 5 6 7 8 9 10];
I can replace the NaN, if both matrices have the same size. For T = 10 and N = 1, I would use:
for t=1:T
for i=1:N
if A == NaN
C(t,i) = B;
else
C(t,i) = A(t,i);
end
end
end
However, I would like to know whether I could compare these matrices and replace the values even if the matrices are of different size? Saying differently, if A = NaN take the first value of B. For the next A = NaN take the second value in B.
You can simply do:
A(find(isnan(A))) = B; % store the result of find(...) to keep track of NaN indices
isnan() is the proper way of determining whether a value is NaN (since NaN ~= NaN), while find() returns the indices of A where an element is NaN in this case.
As per #Adiel's suggestion, you can use logical indexing instead to more compactly achieve the same result, provided you don't need the indices of NaN elements later on:
A(isnan(A)) = B;
I have the 4x2 matrix A:
A = [2 NaN 5 8; 14 NaN 23 NaN]';
I want to replace the non-NaN values with their associated indices within each column in A. The output looks like this:
out = [1 NaN 3 4; 1 NaN 3 NaN]';
I know how to do it for each column manually, but I would like an automatic solution, as I have much larger matrices to handle. Anyone has any idea?
out = bsxfun(#times, A-A+1, (1:size(A,1)).');
How it works:
A-A+1 replaces actual numbers in A by 1, and keeps NaN as NaN
(1:size(A,1)).' is a column vector of row indices
bsxfun(#times, ...) multiplies both of the above with singleton expansion.
As pointed out by #thewaywewalk, in Matlab R2016 onwards bsxfun(#times...) can be replaced by .*, as singleton expansion is enabled by default:
out = (A-A+1) .* (1:size(A,1)).';
An alternative suggested by #Dev-Il is
out = bsxfun(#plus, A*0, (1:size(A,1)).');
This works because multiplying by 0 replaces actual numbers by 0, and keeps NaN as is.
Applying ind2sub to a mask created with isnan will do.
mask = find(~isnan(A));
[rows,~] = ind2sub(size(A),mask)
A(mask) = rows;
Note that the second output of ind2sub needs to be requested (but neglected with ~) as well [rows,~] to indicate you want the output for a 2D-matrix.
A =
1 1
NaN NaN
3 3
4 NaN
A.' =
1 NaN 3 4
1 NaN 3 NaN
Also be careful the with the two different transpose operators ' and .'.
Alternative
[n,m] = size(A);
B = ndgrid(1:n,1:m);
B(isnan(A)) = NaN;
or even (with a little inspiration by Luis Mendo)
[n,m] = size(A);
B = A-A + ndgrid(1:n,1:m)
or in one line
B = A-A + ndgrid(1:size(A,1),1:size(A,2))
This can be done using repmat and isnan as follows:
A = [ 2 NaN 5 8;
14 NaN 23 NaN];
out=repmat([1:size(A,2)],size(A,1),1); % out contains indexes of all the values
out(isnan(A))= NaN % Replacing the indexes where NaN exists with NaN
Output:
1 NaN 3 4
1 NaN 3 NaN
You can take the transpose if you want.
I'm adding another answer for a couple of reasons:
Because overkill (*ahem* kron *ahem*) is fun.
To demonstrate that A*0 does the same as A-A.
A = [2 NaN 5 8; 14 NaN 23 NaN].';
out = A*0 + kron((1:size(A,1)).', ones(1,size(A,2)))
out =
1 1
NaN NaN
3 3
4 NaN
So, I have a cell-array of 1xN vectors of different lengths. I want to append them into a matrix so I can display them with imagesc. Obviously the matrix must be the width of the largest vector. My current code for this is below:
tcell = {[1,2,3], [1,2,3,4,5], [1,2,3,4,5,6], [1], []};
lens = cellfun('length', tcell);
rmat = NaN(length(tcell), max(lens));
for i = 1:length(tcell)
rmat(i, 1:lens(i)) = tcell{i};
end
Does anyone know a vectorized solution for this type of problem? I'm not really worried about the speed of this loop because of MATLAB's JIT. I'm just trying to expand my knowledge and this is a case that I come across quite often in my programming.
Here's one solution that uses cellfun with an anonymous function to first pad each cell with NaN values, then vertcat to put the cell contents into a matrix:
tcell = {[1 2 3], [1 2 3 4 5], [1 2 3 4 5 6], [1], []}; % Sample cell array
maxSize = max(cellfun(#numel, tcell)); % Get the maximum vector size
fcn = #(x) [x nan(1, maxSize-numel(x))]; % Create an anonymous function
rmat = cellfun(fcn, tcell, 'UniformOutput', false); % Pad each cell with NaNs
rmat = vertcat(rmat{:}); % Vertically concatenate cells
And the output:
rmat =
1 2 3 NaN NaN NaN
1 2 3 4 5 NaN
1 2 3 4 5 6
1 NaN NaN NaN NaN NaN
NaN NaN NaN NaN NaN NaN
There is one NaN element per row, I want to remove it.
A=[NaN 1 2;
3 NaN 4;
NaN 5 6];
The desired output is:
[1 2;
3 4;
5 6]
A = [NaN 1 2 ; 3 NaN 4; NaN 5 6]
sz = size(A);
B = reshape(A', size(A,1)*size(A,2), 1);
B(isnan(B)) = [];
B = reshape(B, sz(2)-1, sz(1))'
I thought it could be done in one line, but I was wrong. See solution below:
Given (added row helps me debug my indexing below):
>> A = [NaN 1 2 ; 3 NaN 4; NaN 5 6; 7 8 NaN]
A =
NaN 1 2
3 NaN 4
NaN 5 6
7 8 NaN
Then:
>> Atrans = A';
>> B = reshape( Atrans(~isnan(Atrans)) ,[],size(Atrans,2))'
B =
1 2
3 4
5 6
7 8
Incidentally, the Matlab idiom of performing a simple logical check on an array within an logical indexing operation is very common and incredibly useful. The archetypical example is:
>> x(x>0) %This returns a 1D column vector of all values of x
%which are greater than 0, regardless of the initial
%size of x. Multidimensional inputs are unwrapped
%column-first
Everything else above is size and dimension handling.
Here it is - please note that the code is not robust. It assumes that indeed in every row there is a NaN element.
While it is not a vectorized solution, it has other advantages - like a clear code.
for i=1:size(A,1)
x = A(i,:);
x(isnan(x)) = [];
B(i,:) = x;
end
B
B =
1 2
3 4
5 6