I have this matrix A of size 100x100. Now I have another vector Z=(1,24,5,80...) which has 100 elements. it is a column vector with 100 elements. Now for each row of the matrix A, I want its A(i,j) element to be 1 where i is the row from 1:100 and j is the column which is given by Z
So the elements that should be 1 should be
1,1
2,24
3,5
4,80
and so on
I know I can do it using a loop. But is there a direct simple way I mean one liner?
A matrix that has 100 non-zero elements out of 10000 (so only 1% non-zero) in total is best stored as sparse. Use the capability of matlab.
A = sparse(1:100,Z,1,100,100);
This is a nice, clean one-linear, that results in a matrix that will be stored more efficiently that a full matrix. It can still be used for matrix multiplies, and will be more efficient at that too. For example...
Z = randperm(100);
A = sparse(1:100,Z,1,100,100);
whos A
Name Size Bytes Class Attributes
A 100x100 2408 double sparse
This is a reduction in memory of almost 40 to 1. And, while the matrix is actually rather small as these things go, it is still faster to use it as sparse.
B = rand(100);
timeit(#() B*A)
ans =
4.5717e-05
Af = full(A);
timeit(#() B*Af)
ans =
7.4452e-05
Had A been 1000x1000, the savings would have been even more significant.
If your goal is a full matrix, then you can use full to convert it to a full matrix, or accumarray is an option. And if you want to insert values into an existing array, then use sub2ind.
One way to do it is to convert the values in Z to absolute indices in A using sub2ind, and then use vector indexing:
idx = sub2ind(size(A), 1:numel(Z), Z);
A(idx) = 1;
or simply in a one-liner:
A(sub2ind(size(A), 1:numel(Z), Z)) = 1;
Related
How can I get a maximum of a three-dimensional matrix (which was previously two-dimensional and converted to a three-dimensional matrix by reshape) in MATLAB so that I can then get the position of that maximum value in the matrix?
I wrote the following code, but unfortunately the dimensions obtained for the maximum values are larger than the dimensions of the matrix.
mxshirin=max(max(frvrdin))
[X,Y,Z]=size(frvrdin)
[o,i]=find(frvrdin==mxshirin)
xo=size(o)
xi=size(i)
If frvrdin is 3D, max(max(frvrdin)) will be a 1x1x3 vector:
frvrdin = rand(3,3,3);
max(max(frvrdin))
ans(:,:,1) =
0.8235
ans(:,:,2) =
0.9502
ans(:,:,3) =
0.7547
Don't nest max() functions, simply use the 'all' switch to take the max of the entire matrix at once.
max(frvrdin,[],'all')
ans =
0.9340
If you're on an older MATLAB, use column flattening: max(frvrdin(:)).
You can't use the automated location output of max [val,idx]=max() on more than two dimensions, so use find and ind2sub:
frvrdin = rand(3,3,3);
val = max(frvrdin,[],'all'); % Find maximum over all dims
idx = find(abs(frvrdin-val)<1e-10); % Compare within tolerance
[row,col,page] = ind2sub(size(frvrdin),idx); % Get subscript indices
where row is the index into your first dimension, col into the second and finally page into the third.
I am using Matlab function round(rand(256)) to create a square matrix of size 256x256 with random distribution of 0s and 1s.
What I specifically want to do is that I want to somehow specify number of 1s that rand() (or any other relevant function for that matter) to generate and distribute throughout the matrix randomly
Magdrop’s answer is the most straight-forward method, it computes the percentile of the random values to determine the threshold.
Another two options involve randperm:
Randomly permute all indices into the matrix, then threshold:
sz = [256,256]; % matrix size
n = 256; % number of zeros
M = randperm(prod(sz)) <= n;
M = reshape(M,sz);
Randomly permute indices and select n as the locations of the ones:
indx = randperm(prod(sz),n);
M = zeros(sz);
M(indx) = 1;
You could also generate the random value the usual way, but before you round them, sort them as a vector. The number of 1s will the index in the sorted vector you want to cut for 1s or 0s. For example, let say we want 50 1s:
matrix = rand(256,256);
vec = sort(reshape(matrix,[],1));
thresh = vec(50);
matrix(matrix <= thresh) = 1;
matrix(matrix > thresh) = 0;
You could use the randi function to determine the locations of where to insert the ones, and then place those ones into your matrix. For example for n ones:
matrix = zeros(256,256);
onesIndices = randi([0 256*256],1,n);
matrix(onesIndices) = 1;
One problem with this approach is that randi can generate repeat values, though for this example, where the size of the matrix is large and the number of ones is low, this is pretty unlikely. You could test if this is the case and "reroll:" so if sum(sum(matrix)) is less than n you know you had a repeat value.
Edit: a better approach is to use randperm instead of randi and only take the first n elements. This should prevent there from being repeats and having to re-roll.
I am still wrapping my head around vectorization and I'm having a difficult time trying to resolve the following function I made...
for i = 1:size(X, 1)
min_n = inf;
for j=1:K
val = X(i,:)' - centroids(j,:)';
diff = val'*val;
if (diff < min_n)
idx(i) = j;
min_n = diff;
end
end
end
X is an array of (x,y) coordinates...
2 5
5 6
...
...
centroids in this example is limited to 3 rows. It is also in (x,y) format as shown above.
For every pair in X I am computing the closest pair of centroids. I then store the index of the centroid in idx.
So idx(i) = j means that I am storing the index j of the centroid at index i, where i corresponds to the index of X. This means the closest centroid to pair X(i, :) is at idx(i).
Can I possibly simplify this via vectorization? I struggle with just vectorizing the inner loop.
Here are three options. But please note that the disadvantage of vectorization, as compared to your double loops, is that it stores all the difference operation results at once, which means that if your matrices have many rows, you might run out of memory. On the other hand, the vectorized approach is probably much faster.
Option 1
If you have access to Statistics and Machine Learning Toolbox, you can use the function pdist2 to get all the pairwise distances between rows of two matrices. Then, the min function gives you the minimum of each column of the result. Its first returned value are the minimal values, and its second are the indices, which is what you need for idx:
diff = pdist2(centroids,X);
[~,idx] = min(diff);
Option 2
If you don't have access to the toolbox, you can use bsxfun. This will let you compute the difference operation between the two matrices even if their dimensions don't agree. All you need to do is to use shiftdim to reshape X' to have size [1,size(X,2),size(X,1)], and then reshapedX and and centroids are compatible with their dimensions (see documentation of bsxfun). This lets you take the difference between their values. The result is a three dimensional array, which you need to sum along the second dimension to get the norm of the differences between rows. At this point you can proceed as in option 1.
reshapedX = shiftdim(X',-1);
diff = bsxfun(#minus,centroids,reshapedX);
diff = squeeze(sum(diff.^2,2));
[~,idx] = min(diff);
Note: Starting in the Matlab version 2016b, the bsxfun is used implicitly and you do not need to call it anymore. So the line with bsxfun can be replaced with the simpler line diff = centroids-reshapedX.
Option 3
Use the function dsearchn, which performs exactly what you need:
idx = dsearchn(centroids,X);
it could be done using pdist2 - pairwise distances between rows of two matrices:
% random data
X = rand(500,2);
centroids = rand(3,2);
% pairwise distances
D = pdist2(X,centroids);
% closest centroid index for each X coordinates
[~,idx] = min(D,[],2)
% plot
scatter(centroids(:,1),centroids(:,2),300,(1:size(centroids,1))','filled');
hold on;
scatter(X(:,1),X(:,2),30,idx);
legend('Centroids','data');
In an attempt to create my own covariance function in MatLab I need to perform matrix multiplication on a row to create a matrix.
Given a matrix D where
D = [-2.2769 0.8746
0.6690 -0.4720
-1.0030 -0.9188
2.6111 0.5162]
Now for each row I need manufacture a matrix. For example the first row R = [-2.2770, 0.8746] I would want the matrix M to be returned where M = [5.1847, -1.9915; -1.9915, 0.7649].
Below is what I have written so far. I am asking for some advice to explain how to use matrix multiplication on a rows to produce matrices?
% Find matrices using matrix multiplication
for i=1:size(D, 1)
P1 = (D(i,:))
P2 = transpose(P1)
M = P1*P2
end
You are trying to compute the outer product of each row with itself stored as individual slices in a 3D matrix.
Your code almost works. What you're doing instead is computing the inner product or the dot product of each row with itself. As such it'll give you a single number instead of a matrix. You need to change the transpose operation so that it's done on P1 not P2 and P2 will now simply be P1. Also you are overwriting the matrix M at each iteration. I'm assuming you'd like to store these as individual slices in a 3D matrix. To do this, allocate a 3D matrix where each 2D slice has an equal number of rows and columns which is the number of columns in D while the total number of slices is equal to the total number of rows in D. Then just index into each slice and place the result accordingly:
M = zeros(size(D,2), size(D,2), size(D,1));
% Find matrices using matrix multiplication
for ii=1:size(D, 1)
P = D(ii,:);
M(:,:,ii) = P.'*P;
end
We get:
>> M
M(:,:,1) =
5.18427361 -1.99137674
-1.99137674 0.76492516
M(:,:,2) =
0.447561 -0.315768
-0.315768 0.222784
M(:,:,3) =
1.006009 0.9215564
0.9215564 0.84419344
M(:,:,4) =
6.81784321 1.34784982
1.34784982 0.26646244
Depending on your taste, I would recommend using bsxfun to help you perform the same operation but perhaps doing it faster:
M = bsxfun(#times, permute(D, [2 3 1]), permute(D, [3 2 1]));
In fact, this solution is related to a similar question I asked in the past: Efficiently compute a 3D matrix of outer products - MATLAB. The only difference is that the question wanted to find the outer product of columns instead of the rows.
The way the code works is that we shift the dimensions with permute of D so that we get two matrices of the sizes 2 x 1 x 4 and 1 x 2 x 4. By performing bsxfun and specifying the times function, this allows you to efficiently compute the matrix of outer products per slice simultaneously.
I have vector with 5 numbers in it, and a matrix of size 6000x20, so every row has 20 numbers. I want to count how many of the 6000 rows contain all values from the vector.
As the vector is a part of a matrix which has 80'000'000 rows, each containing unique combinations, I want a fast solution (which doesn't take more than 2 days).
Thanks
With the sizes you have, a bsxfun-based approach that builds an intermediate 6000x20x5 3D-array is affordable:
v = randi(9,1,5); %// example vector
M = randi(9,6000,20); %// example matrix
t = bsxfun(#eq, M, reshape(v,1,1,[]));
result = sum(all(any(t,2),3));