How to convert Binary matrix to Decimal matrix in matlab? - matlab

In mat-lab I have Binary 10x10 matrix
I want to convert this into a 10x10 decimal matrix. How I can do that ?
Edit: r is 10x10 binary matrix.

According to your snapshot, we can infer that you have a double type matrix contains only "1" and "0" as value.
Therefore, I reproduce and solve your case like this:
>> r = [11111010, 11111111; 1010101, 101]
result = cellfun(#(x) bin2dec(num2str(x)), num2cell(r))
r =
11111010 11111111
1010101 101
result =
250 255
85 5
Or, you don't have to use cellfun(), you can just use arrayfun() without converting array/matrix to cell array, like this:
>> r = [11111010, 11111111; 1010101, 101]
result = arrayfun(#(x) bin2dec(num2str(x)), r)
Or, if we assumed you have binary type (logical) cell array, this could be a solution:
r = {[1 1 1 1 1 0 1 0], [1 1 1 1 1 1 1 1]; [1 0 1 0 1 0 1], [1 0 1]}; %// Double type binary valued cell array
r = cellfun(#(x) logical(x), r, 'UniformOutput', false); %// You asserted binary type cell array is given
result = cell2mat(cellfun(#(x)( sum(pow2(length(x)-1:-1:0) .* x) ), r, 'UniformOutput', false));
Used built-in functions: cellfun(), bin2dec(), num2str(), num2cell(), arrayfun() and cell2mat().

Related

Permuting columns of a matrix in MATLAB

Say I have an n by d matrix A and I want to permute the entries of some columns. To do this, I compute permutations of 1 ... n as
idx1 = randperm(n)'
idx2 = randperm(n)'
Then I could do:
A(:,1) = A(idx1,1)
A(:,2) = A(idx2,2)
However, I dont want to do this using a for-loop, as it'll be slow. Say I have an n by d matrix A and an n by d index matrix IDX that specifies the permutations, is there a quicker equivalent of the following for-loop:
for i = 1:d
A(:,i) = A(IDX(:,i),i);
end
Using linear-indexing with the help of bsxfun -
[n,m] = size(A);
newA = A(bsxfun(#plus,IDX,[0:m-1]*n))
I guess another rather stupid way to do it is with cellfun, stupid because you have to convert it into a cell and then convert it back, but it is there anyways.
N=ones(d,1)*n; %//create a vector of d length with each element = n
M=num2cell(N); %//convert it into a cell
P=cellfun(#randperm, M,'uni',0); %//cellfun applys randperm to each cell
res = cell2mat(P); %//Convert result back into a matrix (since results are numeric).
This also allows randperm of type Char and String, but the cell2mat will not work for those cases, results are in Cell Array format instead.
for d = 5, n = 3:
>> res =
1 3 2
1 2 3
2 3 1
3 1 2
3 2 1

How to zero out the centre k by k matrix in an input matrix with odd number of columns and rows

I am trying to solve this problem:
Write a function called cancel_middle that takes A, an n-by-m
matrix, as an input where both n and m are odd numbers and k, a positive
odd integer that is smaller than both m and n (the function does not have to
check the input). The function returns the input matrix with its center k-by-k
matrix zeroed out.
Check out the following run:
>> cancel_middle(ones(5),3)
ans =
1 1 1 1 1
1 0 0 0 1
1 0 0 0 1
1 0 0 0 1
1 1 1 1 1
My code works only when k=3. How can I generalize it for all odd values of k? Here's what I have so far:
function test(n,m,k)
A = ones(n,m);
B = zeros(k);
A((end+1)/2,(end+1)/2)=B((end+1)/2,(end+1)/2);
A(((end+1)/2)-1,((end+1)/2)-1)= B(1,1);
A(((end+1)/2)-1,((end+1)/2))= B(1,2);
A(((end+1)/2)-1,((end+1)/2)+1)= B(1,3);
A(((end+1)/2),((end+1)/2)-1)= B(2,1);
A(((end+1)/2),((end+1)/2)+1)= B(2,3);
A(((end+1)/2)+1,((end+1)/2)-1)= B(3,1);
A(((end+1)/2)+1,((end+1)/2))= B(3,2);
A((end+1)/2+1,(end+1)/2+1)=B(3,3)
end
You can simplify your code. Please have a look at
Matrix Indexing in MATLAB. "one or both of the row and column subscripts can be vectors", i.e. you can define a submatrix. Then you simply need to do the indexing correct: as you have odd numbers just subtract m-k and n-k and you have the number of elements left from your old matrix A. If you divide it by 2 you get the padding on the left/right, top/bottom. And another +1/-1 because of Matlab indexing.
% Generate test data
n = 13;
m = 11;
A = reshape( 1:m*n, n, m )
k = 3;
% Do the calculations
start_row = (n-k)/2 + 1
start_col = (m-k)/2 + 1
A( start_row:start_row+k-1, start_col:start_col+k-1 ) = zeros( k )
function b = cancel_middle(a,k)
[n,m] = size(a);
start_row = (n-k)/2 + 1;
start_column = (m-k)/2 + 1;
end_row = (n-k)/2 + k;
end_column = (m-k)/2 + k;
a(start_row:end_row,start_column:end_column) = 0;
b = a;
end
I have made a function in an m file called cancel_middle and it basically converts the central k by k matrix as a zero matrix with the same dimensions i.e. k by k.
the rest of the matrix remains the same. It is a general function and you'll need to give 2 inputs i.e the matrix you want to convert and the order of submatrix, which is k.

fill gaps specified as "0" in 2D matrix not taking into account NaN

I'm working with a 2D matrix (global soiltype grid) that I want to fill up to fit a new mask. For that, my idea is to fill the blanks using an interpolation by nearest neighbor. I don't see how can I apply that interpolation just to the zeros, and not considering NaNs (which represent the sea). I was thinking about filling those blanks by hand as there aren't too many of them, but I thought that it's interesting to know how to do this anyway. I'd like grid cells representing islands in the middle of the ocean to consider the closest coast as nearest neighbor, if that makes sense. I know that's not realistic, but for my purposes is good enough.
Thank you in advance for any ideas. I don't play with Matlab very often and this kind of things are too much of a challenge timewise.
I advice you to use the function isnan() of matlab.
Here's un example:
A = [1 0 4, 0 3 NaN, NaN 4 5, 0 0 0, NaN 1 NaN]
A =
1 0 4
0 3 NaN
NaN 4 5
0 0 0
NaN 1 NaN
By using isnan(A) will return you a matrix with 1's where there are NaN's and 0 elsewhere.
isnan(A)
ans =
0 0 0
0 0 1
1 0 0
0 0 0
1 0 1
Then you can use the returned matrix (same size as A) as a mask for something else and/or replace the NaN's with whatever you want.
Hope this helps!
This is what I came up with.
function result = nonNanNearestNeighbor(A)
[gridX, gridY] = meshgrid(1:size(A,2), 1:size(A,1));
%if you don't want periodic BCs change function below
t = PeriodicBC(gridY - 1, size(A,1));
b = PeriodicBC(gridY + 1, size(A,1));
l = PeriodicBC(gridX - 1, size(A,2));
r = PeriodicBC(gridX + 1, size(A,2));
%Convert from rc notation to index notation
T = sub2ind(size(A), t, gridX);
B = sub2ind(size(A), b, gridX);
L = sub2ind(size(A), gridY, l);
R = sub2ind(size(A), gridY, r);
%Shift the stencils until they're not nans
while any(isnan(A(T(:))))
[tNaN, gX] = ind2sub(size(A), T(isnan(A(T))));
T(isnan(A(T))) = sub2ind(size(A), PeriodicBC(tNaN - 1, size(A,1)), gX);
end
while any(isnan(A(B(:))))
[bNaN, gX] = ind2sub(size(A), B(isnan(A(B))));
B(isnan(A(B))) = sub2ind(size(A), PeriodicBC(bNaN + 1, size(A,1)), gX);
end
while any(isnan(A(L(:))))
[gY, lNaN] = ind2sub(size(A), L(isnan(A(L))));
L(isnan(A(L))) = sub2ind(size(A), gY, PeriodicBC(lNaN - 1, size(A,2)));
end
while any(isnan(A(R(:))))
[gY, rNaN] = ind2sub(size(A), R(isnan(A(R))));
R(isnan(A(R))) = sub2ind(size(A), gY, PeriodicBC(rNaN + 1, size(A,2)));
end
result = (A(T) + A(B) + A(L) + A(R)) / 4;
end
function shifted = PeriodicBC(shifted, value)
shifted(shifted <= 0) = value - shifted(shifted <= 0);
shifted(shifted > value) = shifted(shifted > value) - value;
if any((shifted(:) <= 0) | (shifted(:) > value))
shifted = PeriodicBC(shifted, value);
end
end

Matlab convert columnar data into ndarray

Is there a simple (ideally without multiple for loops) way to group a vector of values according to a set of categories in Matlab?
I have data matrix in the form
CATEG_A CATEG_B CATEG_C ... VALUE
1 1 1 ... 0.64
1 2 1 ... 0.86
1 1 1 ... 0.74
1 1 2 ... 0.56
...
etc.
and what I want is an N-dimensional array
all_VALUE( CATEG_A, CATEG_B, CATEG_C, ..., index ) = VALUE_i
of course there may be any number of values with the same category combination, so size(end) would be the number of value in the biggest category -- and the remaining items would be padded with nan.
Alternatively I'd be happy with
all_VALUE { CATEG_A, CATEG_B, CATEG_C, ... } ( index )
i.e. a cell array of vectors. I suppose it's a bit like creating a pivot table, but with n-dimensions, and not computing the mean.
I found this function in the help
A = accumarray(subs,val,[],#(x) {x})
but I couldn't fathom how to make it do what I wanted!
This is also a mess, but works. It goes the ND-array way.
X = [1 1 1 0.64
1 2 1 0.86
1 1 1 0.74
1 1 2 0.56]; %// data
N = size(X,1); %// number of values
[~, ~, label] = unique(X(:,1:end-1),'rows'); %// unique labels for indices
cumLabel = cumsum(sparse(1:N, label, 1),1); %// used for generating a cumulative count
%// for each label. The trick here is to separate each label in a different column
lastInd = full(cumLabel((1:N).'+(label-1)*N)); %'// pick appropriate values from
%// cumLabel to generate the cumulative count, which will be used as last index
%// for the result array
sizeY = [max(X(:,1:end-1),[],1) max(lastInd)]; %// size of result
Y = NaN(sizeY); %// initiallize result with NaNs
ind = mat2cell([X(:,1:end-1) lastInd], ones(1,N)); %// needed for comma-separated list
Y(sub2ind(sizeY, ind{:})) = X(:,end); %// linear indexing of values into Y
The result in your example is the following 4D array:
>> Y
Y(:,:,1,1) =
0.6400 0.8600
Y(:,:,2,1) =
0.5600 NaN
Y(:,:,1,2) =
0.7400 NaN
Y(:,:,2,2) =
NaN NaN
It's a mess but here is one solution
[U,~,subs] = unique(X(:,1:end-1),'rows');
sz = max(U);
Uc = mat2cell(U, size(U,1), ones(1,size(U,2)));
%// Uc is converted to cell matrices so that we can take advantage of the {:} notation which returns a comma-separated-list which allows us to pass a dynamic number of arguments to functions like sub2ind
I = sub2ind(sz, Uc{:});
G = accumarray(subs, X(:,end),[],#(x){x});
A{prod(max(U))} = []; %// Pre-assign the correct number of cells to A so we can reshape later
A(I) = G;
reshape(A, sz)
On your example data (ignoring the ...s) this returns:
A(:,:,1) =
[2x1 double] [0.8600]
A(:,:,2) =
[0.5600] []
where A(1,1,1) is [0.74; 0.64]

Find part of vector in another vector matlab

I would like to know if there is an easy way to find the indices of a vector in another vector in matlab:
a = [1 2 3 5 7 10 2 3 6 8 7 5 2 4 7 2 3]
b = [2 3]
So how to get the indices of a when comparing it with b (index of first element is needed)
In this case:
ans = [2 7 16]
Thanks in advance
find(a(1:end-1) == b(1) & a(2:end) == b(2) == 1)
You can re-purpose strfind by converting the elements of both vectors to byte arrays (uint8) with typecast:
bytesPerEl = numel(typecast(a(1),'uint8'));
byteLocs = strfind(char(typecast(a,'uint8')),char(typecast(b,'uint8')));
locsb = (byteLocs-1)/bytesPerEl + 1
locsb =
2 7 16
Just make sure a and b are of the same type. Also note that this works for 1D vectors, not matrixes or higher dimensional arrays.
General approach with length of b arbitrary (not necessarily 2 as in the example), and avoiding the use of strings:
match1 = bsxfun(#eq, a(:), b(:).'); %'// now we just need to make the diagonals
%// horizontal (in order to apply "all" row-wise). For that we'll use indices
%// ind, ind1, ind2
ind = reshape(1:numel(match1), numel(a), numel(b));
ind1 = nonzeros(tril(ind)); %// source indices
ind2 = sort(nonzeros(tril(flipud(ind)))); %// destination indices
match2 = zeros(size(match1));
match2(ind2) = match1(ind1); %// diagonals have become horizontal
result = find(all(match2.'));