I'm working in Matlab and I have the following problem:
I have a 2x4 matrix A
A = 0 0 0 0
0 0 0 0
and index matrix
index = 1 2
2 3
each row of index matrix indicates the location I want to assign in A. What should I do to make A be
A = 1 1 0 0
0 1 1 0
Another Example: if index is
index = 1 3
2 4
then
A = 1 0 1 0
0 1 0 1
Thanks!
You can do this using linear indexing and implicit expansion:
A((index-1).*size(A,1)+(1:size(index,1)).') = 1;
Related
I have a logical vector in which I would like to iterate over every n-elements. If in any given window at least 50% are 1's, then I change every element to 1, else I keep as is and move to the next window. For example.
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
output = func(input,4);
output = [0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1];
This function is trivial to implement but is it possible to apply a vectorized implementation using logical indexing?. I am trying to build up the intuition of applying this technique.
here's a one liner (that works for your input):
func = #(input,n) input | kron(sum(reshape(input ,n,[]))>=n/2,ones(1,n));
of course, there are cases to solve that this doesnt answer, what if the size of the input is not commensurate in n? etc...
i'm not sure if that's what you meant by vectorization, and I didnt benchmark it vs a for loop...
Here is one way of doing it. Once understood you can compact it in less lines but I'll details the intermediate steps for the sake of clarity.
%% The inputs
n = 4;
input = [0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 1 0 0 0 1];
1) Split your input into blocks of size n (note that your final function will have to check that the number of elements in input is a integer multiple of n)
c = reshape(input,n,[]) ;
Gives you a matrix with your blocks organized in columns:
c =
0 0 0 0 0
0 1 0 1 0
0 1 0 0 0
1 0 1 1 1
2) Perform your test condition on each of the block. For this we'll take advantage that Matlab is working column wise for the sum function:
>> cr = sum(c) >= (n/2)
cr =
0 1 0 1 0
Now you have a logical vector cr containing as many elements as initial blocks. Each value is the result of the test condition over the block. The 0 blocks will be left unchanged, the 1 blocks will be forced to value 1.
3) Force 1 columns/block to value 1:
>> c(:,cr) = 1
c =
0 1 0 1 0
0 1 0 1 0
0 1 0 1 0
1 1 1 1 1
4) Now all is left is to unfold your matrix. You can do it several ways:
res = c(:) ; %% will give you a column vector
OR
>> res = reshape(c,1,[]) %% will give you a line vector
res =
0 0 0 1 1 1 1 1 0 0 0 1 1 1 1 1 0 0 0 1
Say I have a vector A of item IDs:
A=[50936
332680
107430
167940
185820
99732
198490
201250
27626
69375];
And I have a matrix B whose rows contains values of 8 parameters for each of the items in vector A:
B=[0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 1 0 1 1 1
1 0 1 0 0 1 0 1 1 1
0 0 1 0 0 0 0 1 0 1
0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1];
So, column 1 in matrix B represents data of item in row 1 of vector A, column 2 in matrix B represents data of item in row 2 of vector A, and so on. However, I want matrix B to contain the information in a different order of items stored in vector A2:
A2=[185820
198490
69375
167940
99732
332680
27626
107430
50936
201250];
How do I sort them, so that column 1 of matrix B contains data for item in row 1 of vector A2, column 2 of matrix B contains data for item in row 2 of vector A2, and so on?
My extremely crude solution to do this is the following:
A=A'; A2=A2';
for i=1:size(A,2)
A(2:size(B,1)+1,i)=B(:,i);
end
A2(2:size(B,1)+1,:)=zeros(size(B,1),size(B,2));
for i=size(A2,2)
for j=size(A,2)
if A2(1,i)==A(1,j)
A2(2:end,i)=A(2:end,j);
end
end
end
B2 = A2(2:end,:);
But I would like to know a cleaner, more elegant and less time consuming method to do this.
A possible solution
You can use second output of ismember function.
[~ ,idx] = ismember(A2,A);
B2 = B(:,idx);
Update:I tested both my solution and another proposed by hbaderts
disp('-----ISMEMBER:-------')
tic
[~,idx]=ismember(A2,A);
toc
disp('-----SORT:-----------')
tic
[~,idx1] = sort(A);
[~,idx2] = sort(A2);
map = zeros(1,size(idx2));
map(idx2) = idx1;
toc
Here is the result in Octave:
-----ISMEMBER:-------
Elapsed time is 0.00157714 seconds.
-----SORT:-----------
Elapsed time is 4.41074e-05 seconds.
Conclusion: the sort method is more efficient!
As both A and A2 contain the exact same elements, just sorted differently, we can create a mapping from the A-sorting to the A2-sorting. For that, we run the sort function on both and save indexes (which are the second output).
[~,idx1] = sort(A);
[~,idx2] = sort(A2);
Now, the first element in idx1 corresponds to the first element in idx2, so A(idx1(1)) is the same as A2(idx2(1)) (which is 27626). To create a mapping idx1 -> idx2, we use matrix indexing as follows
map = zeros(size(idx2));
map(idx2) = idx1;
To sort B accordingly, all we need to do is
B2 = B(:, map);
[A2, sort_order] = sort(A);
B2 = B(:, sort_order)
MATLAB's sort function returns the order in which the items in A are sorted. You can use this to order the columns in B.
Transpose B so you can concatenate it with A:
C = [A B']
Now you have
C = [ 50936 0 0 1 1 0 0 0 0;
332680 0 0 0 0 0 0 0 0;
107430 0 0 1 1 1 0 0 0;
167940 0 0 0 0 0 0 0 0;
185820 0 0 0 0 0 0 0 0;
99732 0 0 1 1 0 0 0 0;
198490 0 0 0 0 0 0 0 0;
201250 0 0 1 1 1 1 0 0;
27626 0 0 1 1 0 0 0 0;
69375 0 0 1 1 1 0 0 1];
You can now sort the rows of the matrix however you want. For example, to sort by ID in ascending order, use sortrows:
C = sortrows(C)
To just swap rows around, use a permutation of 1:length(A):
C = C(perm, :)
where perm could be something like [4 5 6 3 2 1 8 7 9 10].
This way, your information is all contained in one structure and the data is always correctly matched to the proper ID.
I am trying to select all BUT certain index pairs in a multi-dimensional array. i.e. I have a set of paired indices (e.g. [1,2] and [4,5]). I want to set all BUT those indexed pairs to 0.
The closest I have come to this is:
A(setdiff(1:length(A(:,1)),lon),setdiff(1:length(A(1,:)),lat)) = 0;
, where A is the matrix and lon and lat are the index pairs I want to keep. However, that also leaves all the intersecting rows and columns of those pairs.
Any ideas?
Here is some example code:
A = ones([5,5])
A =
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
lon = [1];
lat = [4];
A(setdiff(1:length(A(:,1)),lon),setdiff(1:length(A(1,:)),lat)) = 0
A =
1 1 1 1 1
0 0 0 1 0
0 0 0 1 0
0 0 0 1 0
0 0 0 1 0
What I want is:
A =
0 0 0 1 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
The easiest thing to do is actually the opposite of what you have tried. First you want to start with a matrix of zeros and then only fill in those pairs that you have stored in lat and lon. Also because you have paired subscripts, you will want to convert those to a linear index using sub2ind
%// Convert subscripts to a linear index
inds = sub2ind(size(A), lon, lat);
%// Start off with a matrix of zeros
B = zeros(size(A));
%// Fill in the values at the specified lat/lon from A
B(inds) = A(inds);
I have a 64-by-1 vector which contains 27 non-zero values. I want to create N copies from that vector such that each copy contains only 4 non-zero values (in that case the first 6 copies will have 4 non-zero values and the last copy will contain only 3 non-zero values) using MATLAB.
For example:
orig_vector = [0 0 0 0 1 0 0 0 0 5 0 0 0 2 0 1 0 2 3 1 1 ];
first_copy = [0 0 0 0 1 0 0 0 0 5 0 0 0 2 0 1 0 0 0 0 0 ];
second_copy = [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 3 1 1 ];
How can this be done?
Perhaps something like:
non_zero_indices = find(orig_vector); % get array indices of non-zero elements
n_non_zero = length(non_zero_indices);
n_copies = ceil(n_non_zero / 4); % eg. with 6 non-zero elements we will have 2 copies
new_vectors = zeros(n_copies, length(orig_vector)); % matrix of new vectors where vectors go in rows
for i=0:n_copies - 2
idx = non_zero_indices(1+i*4:4+i*4);
new_vectors(i+1, idx) = orig_vector(idx);
end
idx = non_zero_indices(1+(n_copies-1)*4:end); % handle end which may have fewer than 4 elements
new_vectors(n_copies, idx) = orig_vector(idx);
Im using matlab and am having some difficulty. I am trying to swap the columns of one matrix (A) with the column of another matrix (B). For Example:
A =
4 6 5
7 8 4
6 5 9
1 0 0
0 1 0
0 0 1
B =
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
0 0 0 -1 0 0
0 0 0 0 -1 0
0 0 0 0 0 -1
Is there a way to tell Matlab to switch, for instance, column 1 in A with column 3 in B?
You can actually perform this column swap in one line and without the need for dummy variables using the function DEAL:
[A(:,1),B(:,3)] = deal(B(:,3),A(:,1));
tmp = A(:,1);
A(:,1) = B(:,3);
B(:,3) = tmp;
Use
A(:,1) = B(:,3);
Or to actually swap them, you can use:
dummy = A(:,1);
A(:,1) = B(:,3);
B(:,3) = dummy;