How can I vectorize the following piece of code in Matlab? - matlab

y is 5000 x 1 vector containing numbers 1 to 10. I can convert y to Y (5000 x 10 matrix) such that
Y = zeros(5000,10);
for i = 1:5000
Y(i,y(i))=1;
end
Can I achieve the same result without using for loop?

A solution using implicit expansion:
Y = y == 1:10;
It creates a logical matrix. If you need a double matrix you can write:
Y = double(y == 1:10);

You can use sparse for that:
y = [8 5 7 4 2 6 4]; % example y. Arbitrary size
M = 10; % maximum possible value in y
Y = full(sparse(1:numel(y), y, 1, numel(y), M));
Equivalently, it can be done with accumarray:
Y = accumarray([(1:numel(y)).' y(:)], 1, [numel(y) M]);

In addition to #LuisMendo answer, you can also use sub2ind:
Y = zeros(5,10); % Y preallocation, zeros(numel(y),max_column)
y = [8 5 7 4 2]; % Example y
Y(sub2ind(size(Y),1:numel(y),y)) = 1 % Linear indexation
Noticed that this method is slightly different than accumarray and sparse if there are duplicate pairs of [row,column] index:
% The linear index assigns the last value:
Y = zeros(2,2);
Y(sub2ind(size(Y),[1 1],[1,1])) = [3,4] % 4 overwrite 3
Result:
Y =
4 0
0 0
VS
% Sparse sum the values:
Y = full(sparse([1 1],[1,1], [3,4], 2, 2)) % 3+4
Result:
Y =
7 0
0 0

Related

Plotting a 3d figure in Matlab given a table

The table I have is like this:
An image of the table
X↓ Y->
Y = 0
Y = 1
Y = 2
Y = 3
X = 3
PXY = 4/54
PXY = 3/54
PXY = 2/54
PXY = 1/54
X = 5
PXY = 6/54
PXY = 5/54
PXY = 4/54
PXY = 3/54
X = 7
PXY = 8/54
PXY = 7/54
PXY = 6/54
PXY = 5/54
PXY is given by (x - y + 1)/54
How should I go about graphing this on MATLAB? I wish to draw a 3d histogram, something like this:
.
Most of my attempts have ended in errors usually because the X and Y vectors are not the same length.
If there's ways to do this Python as well, then please let me know, that works too.
In Matlab, you can use histogram2 specifying the edges of the bins in the x and y direction and the bin count.
% Your data
x = [3; 5; 7];
y = [0, 1, 2, 3];
p = (x - y + 1)/54;
% since x is a column vector and y a row vector, as of Matlab R2016b this results in a length(x)*length(y) matrix, equivalent to:
% p = zeros(length(x), length(y));
% for ix = 1:length(x)
% for iy = 1:length(y)
% p(ix, iy) = (x(ix) - y(iy) + 1)/54;
% end
% end
% Plot the histogram
histogram2('XBinEdges', [x; 9], ...
'YBinEdges', [y, 4], ...
'BinCounts', p);
xlabel('X')
ylabel('Y')
zlabel('P_{xy}')
Since you need 3 bins for x (4 bins for y), you need to provide 4 edges (5 edges for y), hence the additional points in the histogram2 call.
EDIT: on second thought, you probably want the bins centered on the x and y points that you provide, so perhaps you might want to use xEdges = [x - 1; x(end) + 1] and yEdges = [y - 0.5, y(end) + 0.5] as bin edges instead.

How can I find the value of a matrix that minimize a least square cost function in MATLAB?

Given the value of S1 which is a vector of size (1,K), I want to find the value of matrix B of size (N,M) that can minimize the following least square cost function:
sum(S2 - S1).^2
Subject to:
S2(i)>=S1(i) \forall i \in {1, .., K}
Where S2 is a vector of size (1,K) and is a function of matrix B.
S2 can be calculated after optimizing matrix B using the following system parameters and equations:
clc;
clear;
% Given system parameters:
N = 2;
K = 4;
M = 2;
C_l = 4;
H = [0.1185 0.2811; 0.3550 0.8224; 0.3260 0.9644; 0.5333 0.6083]; % 4*2 matrix
A = [-2 1; -1 1]; % 2*2 matrix
C = [7 -3; 7 -3; -2 1; -2 1]; % 4*2 matrix
P = [25000000 0; 0 25000000]; % 4*4 matrix
S1 = [3.1683 3.1686 1.8716 1.8898]; % 1*4 vector
S2 = zeros(1,K); % intial value
B = zeros(N,M); % intial value
% How can we optimize the value of the B matrix to achieve our goal?
%calculate S2 from B and the other given inputs
for j=1:1:N
d(j) = (B(j,:)*P*B(j,:)')/((2^(2*C_l))-(norm(A(:,j))^2));
end
D_d = diag(d);
for i=1:1:K
V_d(i)=C(i,:)*P*B'*H(i,:)'*inv(1+H(i,:)*(A'*D_d*A+B*P*B')*H(i,:)');
sigma_d(i)=norm((V_d(i)*H(i,:)*B-C(i,:))*(P^(1/2)))^2+(V_d(i)^2)*(1+H(i,:)*A'*D_d*A*H(i,:)');
S2(i)=0.5*log2((P(1,1))/sigma_d(:,i));
end

pick random numbers in certain range from vector

how would you use randperm to randomly pick three numbers out of a range of 5 in a vector?
i have a vector like this:
A = [1 2 3 4 5 6 7 8 9 10]
now from every 5 consecutive values i want to randomly pick 3 of them:
A_result = [1 3 5 6 7 9]
any help is appreciated!
This one uses different random indices in every 5-group.
A = [1 2 3 4 5 6 7 8 9 10]
B = reshape(A,5,[]) % (5 x 2)
ind = cell2mat(arrayfun(#(x)sort(randperm(5,3))',1:size(B,2),'UniformOutput',false)) % (3 x 2), row indices into B
ind = bsxfun(#plus,ind,size(B,1)*(0:size(B,2)-1)) % (3 x 2), linear indices into B
C = B(ind) % (3 x 2) result
C(:)' % result vector
Every sort(randperm(5,3))' call generates a random column vector with 3 ascending numbers from 1 to 5, like [1;3;4] or [2;4;5]. arrayfun with the dummy argument x calls this 2 times in this example, because A consists of 2 sub-vectors of length 5. With the argument 'Uniform output' set to false, it generates a cell array of these random vectors, and cell2mat converts it to the (3 x 2)-matrix ind. The bsxfun call converts the values in the matrix ind to a matrix of linear indices into matrix B or A.
For your (900 x 25)-matrix, do
A = rand(900,25); % (900 x 25)
B = A'; % (25 x 900)
ind = cell2mat(arrayfun(#(x)sort(randperm(25,17))',1:size(B,2),'UniformOutput',false)); % (17 x 900), row indices into B
ind = bsxfun(#plus,ind,size(B,1)*(0:size(B,2)-1)); % (17 x 900), linear indices into B
C = B(ind); % (17 x 900), result
You can use reshape and randsample
rA = reshape( A, 5, [] ); % groups of 5 in a a row
A_result = rA( randsample( 5, 3, false ), : );
A_result = reshape( A_result, 1, [] );
You can pre-generate all possible picking patterns, and then randomly select one such pattern for each group. This approach is suitable for small group sizes, otherwise it may use a lot of memory.
A = 1:10; %// example data
n = 5; %// group size. Assumed to divide numel(A)
k = 3; %// how many to pick from each group
S = numel(A);
patterns = nchoosek(1:n, k); %// all possible picking patterns
K = size(patterns, 1);
p = randi(K, S/n, 1); %// generate random indices for patterns
pick = bsxfun(#plus, patterns(p,:).', (0:n:S-1)); %'// to linear indices
A_result = A(pick(:));

How to zero pad a matlab array?

What is the easiest way to (zero) pad a matlab array?
i.e. given [1,2,3,4] and length 6 return [1,2,3,4,0,0]
Background
I have a data array which I would like to apply a windowing function to before running fft on the data.
I use to pass data directly to fft which would zero pad to the next power of 2, but now I need it zero padding before the fft so I can multiply by the window function.
fs = 100; % Sample frequency (Hz)
t = 0:1/fs:10-1/fs; % 10 sec sample
x = (1.3)*sin(2*pi*15*t) ... % 15 Hz component
+ (1.7)*sin(2*pi*40*(t-2)) ... % 40 Hz component
+ (2.5)*randn(size(t)); % Gaussian noise;
m = length(x); % Window length
n = pow2(nextpow2(m)); % Transform length
w = barthannwin( n ); % FFT Window
y = fft(data, n); % DFT
windowed_data = x*w ; % Dimensions do not match as x not padded
y = fft(windowed_data, n); % DFT
I am aware of padarray as part of the Image Processing Toolbox, which I do not have.
EDIT
This method is probably even better for vectors as it does not break when they are transposed, note that it will change the original vector which may not be desirable:
myVec = 1:7;
myVec(end+3)=0
Alternately you can just concatenate zeros and the vector that you have and create a new variable with it.
myVec = 1:7;
requiredpadding = 10-7;
myVecPadded=[myVec zeros(1,requiredpadding)]
There is no built in function to do padding, but here is a little function to pad vector x given a minimum length n.
function y = pad(x, n)
y = x;
if length(x) < n
y(n) = 0;
end
this should pad it with zeros to the nearest power of 2 for an array a:
a(2^ceil(log2(length(a))))=0;
The image-processing toolbox of Matlab has a built-in function to pad arrays padarray(A,dim,value
For your example:
A = [1, 2, 3, 4];
dimension = [0 1]; % pad with extra columns
size = 2; % how much to pad
B = padarray(A,size*dimension,'post') % 'post' says to pad at the end
% just for demonstration, let's pre-pad the first dimension (rows)
dimension = [1 0];
C = padarray(A,dimension,'pre') % just as an example
% or pad in both directions
dimension = [1 2];
D = padarray(A,dimension) % by default, it will pad both pre and post
returns
B =
1 2 3 4 0 0
C =
0 0 0 0
1 2 3 4
D =
0 0 0 0 0 0 0 0
0 0 1 2 3 4 0 0
0 0 0 0 0 0 0 0
You can also use this for multi-dimensional arrays, the dimension vector just needs to be extended correspondingly, i.e. dimension = [0 0 1] will extend in the 3rd dimension.

Convert vector into logical matrix?

I have a vector y of length n. y(i) is an integer in 1..m. Is there a simpler way to convert y into an n x m logical matrix yy, where yy(i, j) = 1 if y(i) = j, but 0 otherwise? Here's how I've been doing it:
% If m is known (m = 3 here), you could write it out all at once
yy = [y == 1; y== 2; y == 3];
yy = reshape(yy, n, 3);
or
% if m is not known ahead of time
yy = [ y == 1 ];
for i = 2:m;
yy = [ yy; y == i ];
end
yy = reshape(yy, n, m);
You can use bsxfun for this
yy = bsxfun(#eq,y(:),[1,2,3])
y is transformed (if necessary) to a column-vector, while the other vector is a row vector. bsxfun implicitly expands the m-by-1 and 1-by-n arrays so that the result becomes m-by-n.
If n*m is sufficiently large (and m is, by itself, sufficiently large), it is a good idea to create yy as a sparse matrix. Your y vector is really a special type of sparse matrix format, but we can translate it into the built-in sparse matrix format by doing the following.
yy = sparse(1:length(y), y, 1);
This will keep your storage to O(n). It is not going to be doing you a lot of favors if you are using yy for a lot of indexing. If that is the case you are better off using your original sparse structure (i.e., y).
A slight modification to your method:
% A n-dimensional vector y, with values in some range 1..m
m = 4;
n = 7;
y = randi([1 m], n, 1);
% Preallocating a n by m matrix of zeros
nXm = zeros(n, m);
% In each pass of this loop a single column of nXm is updated, where
% for each column index j in nXm, if y(i) = j then nXm(i,j) = 1
for j = 1:m;
nXm(:,j) = (y == j);
end
From Machine Learning on Coursera:
yy = eye(m)(y, :)
This requires that the list be a range 1:m (as OP stated). For an irregular list, like [2 3 5], do this
yy = eye(m)(:, [2 3 5])(y, :)
Note: not tested on MATLAB.
In octave you can write:
yy = y' == (1:m); % or y == (1:m)' for transposed
[1 2 1 3 2] == [1 2 3]' % = [1 0 1 0 0; 0 1 0 0 1; 0 0 0 1 0]