I am getting frustrated with MATLAB when I tried to get the data back in matrix format. But every time i only get back the answer in a single column format. I will illustrate my question:
For example,
A = [1 -3 2;5 4 7;-8 1 3];
L = logical(mod(A,2))
L =
1 1 0
1 0 1
0 1 1
now I have another set of matrix sample called B, C is the output I would like to see
B = [100 300 200;500 400 700;800 100 300];
C = B(L)
C =
100
500
300
100
700
300
I don't want it to remain as a single column. I wonder what I can do to make C returned to me in this matrix format?
C =
100 300 0
500 0 700
0 100 300
Thanks a lot, guys!!!
Logical indexing will select only the elements from the matrix for which the logical matrix is true. Obviously this means it can't retain it's original shape, since the number of elements will change. There are a few ways of doing what you want to do; the most efficient is probably:
C = B;
C(~L) = 0;
This sets C to B, then sets every element of the matrix for which L is false to zero.
Or you could start with a blank matrix and set the desired elements:
C = NaN(size(B),'like',B); % or zeros(size(B),'like',B)
C(L) = B(L);
Related
Let's assume my matrix A is the output of comparison function i.e. logical matrix having values 0 and 1's only. For a small matrix of size 3*4, we might have something like:
A =
1 1 0 0
0 0 1 0
0 0 1 1
Now, I am generating another matrix B which is of the same size as A, but its rows are filled with indexes of A and any leftover values in each row are set to zero.
B =
1 2 0 0
3 0 0 0
3 4 0 0
Currently, I am using find function on each row of A to get matrix B. Complete code can be written as:
A=[1,1,0,0;0,0,1,0;0,0,1,1];
[rows,columns]=size(A);
B=zeros(rows,columns);
for i=1:rows
currRow=find(A(i,:));
B(i,1:length(currRow))=currRow;
end
For large martixes, "find" function is taking time in the calculation as per Matlab Profiler. Is there any way to generate matrix B faster?
Note:
Matrix A is having more than 1000 columns in each row but non-zero elements are never more than 50. Here, I am taking Matrix B as the same size as A but Matrix B can be of much smaller size column-wise.
I would suggest using parfor, but the overhead is too much here, and there are more issues with it, so it is not a good solution.
rows = 5e5;
cols = 1000;
A = rand(rows, cols) < 0.050;
I = uint16(1:cols);
B = zeros(size(A), 'uint16');
% [r,c] = find(A);
tic
for i=1:rows
% currRow = find(A(i,:));
currRow = I(A(i,:));
B(i,1:length(currRow)) = currRow;
end
toc
#Cris suggests replacing find with an indexing operation. It increases the performance by about 10%.
Apparently, there is not a better optimization unless B is required to be in that specific form you tell. I suggest using [r,c] = find(A); if the indexes are not required in a matrix form.
I have to multiply 2 matrices (scalar multiplication) that have different sizes. For instance, the 1st has size n-by-m and the 2nd n+1-by-m+1. The fact is that it is not always the case. I mean, sometimes the first has size n+1-by-m+1 and the 2nd n-by-m or n+2-by-m+2 etc...
Example:
a = [ 1 2 3;
4 5 6];
b = [ 1 2 3;
4 5 6;
7 8 9]
I would like Matlab to check the size of each matrix, then multiply them using the smallest size available between the 2 i.e. ignoring the last rows and columns of the bigger matrix (or similarly, adding rows and columns of 0 to the smaller matrix).
With the example inputs I would like to obtain:
c = [1 4 9;
16 25 36]
or
c = [1 4 9;
16 25 36;
0 0 0]
How can I write this?
Find the number of rows and columns of your final matrix:
n = min(size(a,1), size(b,1));
m = min(size(a,2), size(b,2));
Then extract only the relevant sections of a and b (using the : operator) for your multiplication:
c = a(1:n,1:m).*b(1:n,1:m)
If you only consider dot product, it means that size(a) must equal size(b), which allows to simply restrain the size of b, you can use a simple if statement if you like. For example:
if all(size(b) == size(a))
answer = a.*b
else
minsize(:,1) = min(size(a,1),size(b,1));
minsize(:,2) = min(size(a,2),size(b,2));
answer = a(1:minsize(:,1),1:minsize(:,2)).*a(1:minsize(:,1),1:minsize(:,2));
end
I don't think this is easiest way to do it, but it is simple to understand :)
I am not always sure which one of the matrix is bigger, then I thought to use:
if size (a) > size (b)
a = a(1:size(b,1),1:size(b,2));
elseif size (a) < size (b)
b = b (1: size (a,1),1:size(a,2));
end
It seems to work like this.
I'm working in Matlab and I have the next problem:
I have a B matrix of nx2 elements, which contains indexes for the assignment of a big sparse matrix A (almost 500,000x80,000). For each row of B, the first column is the column index of A that has to contain a 1, and the second column is the column index of A that has to contain -1.
For example:
B= 1 3
2 5
1 5
4 1
5 2
For this B matrix, The Corresponding A matrix has to be like this:
A= 1 0 -1 0 0
0 1 0 0 -1
1 0 0 0 -1
-1 0 0 1 0
0 -1 0 0 1
So, for the row i of B, the corresponding row i of A must be full of zeros except on A(i,B(i,1))=1 and A(i,B(i,2))=-1
This is very easy with a for loop over all the rows of B, but it's extremely slow. I also tried the next formulation:
A(:,B(:,1))=1
A(:,B(:,2))=-1
But matlab gave me an "Out of Memory Error". If anybody knows a more efficient way to achieve this, please let me know.
Thanks in advance!
You can use the sparse function:
m = size(B,1); %// number of rows of A. Or choose larger if needed
n = max(B(:)); %// number of columns of A. Or choose larger if needed
s = size(B,1);
A = sparse(1:s, B(:,1), 1, m, n) + sparse(1:s, B(:,2), -1, m, n);
I think you should be able to do this using the sub2ind function. This function converts matrix subscripts to linear indices. You should be able to do it like so:
pind = sub2ind(size(A),1:n,B(:,1)); % positive indices
nind = sub2ind(size(A),1:n,B(:,2)); % negative indices
A(pind) = 1;
A(nind) = -1;
EDIT: I (wrongly, I think) assumed the sparse matrix A already existed. If it doesn't exist, then this method wouldn't be the best option.
I'd like to accumulate indexed elements in a matrix, like table and tapply function in R.
I found sparse(i,j,s,m,n) fit my need perfectly,
As the document says:"Any elements of s that have duplicate values of i and j are added together."
But I have to convert the obtained sparse matrix to a full one using full():
a = a + full(sparse(i,j,s,m,n));
Is this a efficient way to do so?
By the way, is there anything like below, no matter whether adding duplicated i,j pairs?
a = setelements(a, i,j,s);
and
vector = getelement(a,i,j);
where i&j take meanings in sparse() function.
And what if a is a multidimensional array? sparse() only deal with matrix.
Do I have to set the entries page by page with outer loops?
Take a look at accumaray. For example,
ii = [1 2 2 3 3];
jj = [3 2 2 2 2];
s = [10 20 30 40 50];
a = accumarray([ii(:) jj(:)],s(:));
gives
a =
0 0 10
0 50 0
0 90 0
Note that each row of the first argument ([ii(:) jj(:)]) defines an N-dimensional index into the output array (N is 2 in this example).
accumarray is very flexible. It works for N-dimensional arrays, lets you specify size of the result (it may be larger than inferred from the supplied indices), and can even apply an arbitrary function (different from sum) to each set of values defined by the same index.
As a more general example, with the above data,
a = accumarray([ii(:) jj(:)],s(:),[4 4],#max)
gives
a =
0 0 10 0
0 30 0 0
0 50 0 0
0 0 0 0
Say I have matrices A and B. I want to create a third matrix C where
A = [1,0,0,1]
B = [1,0,1,0]
C = [11, 00, 01, 10]
Is there such a function in Matlab? If not how would I go about creating a function that does this?
Edit: C is not literal numbers. They are concatenated values of A,B element-wise.
Edit2: The actual problem I am dealing with is I have 10 large matrices of the size [x,y] where x,y > 1000. The elements in these matrices all have 0s and 1s. No other number. What I need to accomplish is have the element [x1,y1] in matrix 1 to be appended to the element in [x1,y1] of matrix 2. and then that value to be appended to [x1,y1] of matrix 3.
Another example:
A = [1,1,1,1;
0,0,0,0]
B = [0,0,0,0;
1,1,1,1]
C = [1,0,1,0;
0,1,0,1]
And I need a matrix D where
D = [101, 100, 101, 101; 010, 011, 010, 011]
I recommend that you avoid manipulating binary numbers as strings where possible. It seems tempting, and there are cases where matlab provides a more elegant solution if you treat a binary number as a string, but you cannot perform binary arithmetic on strings. You can always work with integers as if they were binary (they are stored as bits in your machine after all), and then just display them as binary numbers using dec2bin when necessary.
A = [1,0,0,1]
B = [1,0,1,0]
C = bitshift(A,1)+B;
display(dec2bin(C));
In the other case you show in your question you could use:
A = [1,1,1,1; 0,0,0,0];
B = [0,0,0,0; 1,1,1,1];
C = [1,0,1,0; 0,1,0,1];
D = bitshift(A,2) + bitshift(B,1) + C;
You can also convert an arbitrary length row vector of zeros and ones into its decimal equivalent by defining this simple function:
mat2dec = #(x) x*2.^(size(x,2)-1:-1:0)';
This will also work for matrices too. For example
>> M = [0 0 1; 0 1 1; 0 1 0; 1 1 0; 1 1 1; 1 1 0; 1 0 0];
>> dec2bin(mat2dec(M))
ans =
001
011
010
110
111
110
100
In my experience, treating binary numbers as strings obfuscates your code and is not very flexible. For example, try adding two binary "strings" together. You have to use bin2dec every time, so why not just leave the numbers as numbers until you want to display them? You have already run into some of the issues caused by strings of different lengths too. You will be amazed how one simple change can break everything when treating numbers as strings. The worst part is that an algorithm may work great for one set of data and not for another. If all I test with is two-bit binary numbers and a three-bit number somehow sneaks its way in, I may not see an error, but my results will be inexplicably incorrect. I realize that this is a very subjective issue, and I think that I definitely stand in the minority on StackOverflow, so take it for what it's worth.
It depends how you want the output formatted. You could apply bitshift to the numerical values and convert to binary:
>> b = dec2bin(bitshift(A,1)+B)
b =
11
00
01
10
For a general matrix Digits:
>> Digits
Digits =
1 0 0 0
0 1 0 0
1 0 1 1
1 1 0 0
1 0 0 0
1 0 1 1
1 1 0 0
1 0 1 0
0 1 1 1
0 1 1 1
>> Ddec = D*(2.^(size(D,2)-1:-1:0))'; % dot product
>> dec2bin(Ddec)
ans =
1000
0100
1011
1100
1000
1011
1100
1010
0111
0111
Another way to write that is dec2bin(sum(D .* repmat(2.^(size(D,2)-1:-1:0),size(D,1),1),2)).
For your larger problem, with 10 large matrixes (say M1, M2, ..., M10), you can build the starting Digits matrix by:
Digits = [M1(:) M2(:) M3(:) M4(:) M5(:) M6(:) M7(:) M8(:) M9(:) M10(:)];
If that is reverse the order of the digits, just do Digits = fliplr(Digits);.
If you would rather not reshape anything you can compute the matrix decimal values from the matrices of digits as follows:
M = cat(3,A,B,C);
Ddec = sum(bsxfun(#times,M,permute(2.^(size(M,3)-1:-1:0),[1 3 2])),3)
I see some quite extensive answers so perhaps this is thinking too simple, but how about just this assuming you have vectors of ones and zeros representing your binary numbers:
A = [1,0,0,1];
B = [1,0,1,0];
C = 10*A + B
This should give you the numbers you want, you may want to add leading zeros. Of course this method can easily be expanded to append multiple matrices, you just need to make sure there is a factor (base) 10 between them before adding.