How to repeat and split this vector in MATLAB? [duplicate] - matlab

This question already has answers here:
Repeat elements of vector [duplicate]
(3 answers)
Closed 8 years ago.
I have 2 data vectors d1 = [1 2 1 3 4] and d2 = [3 1 2 1], and 2 references howMany1= [3 2 2 1 2] and howMany2 = [2 1 2 2]. The elements of d1 and d2 are to be repeated according to the elements of howMany1 and howMany2: so d1(1) i.e. the first element of d1 should repeat 3 times,d1(2) should repeat 2 times and so on.. and the final result should be d1_repeated = [1 1 1 2 2 1 1 3 4 4] and d2_repeated = [3 3 1 2 2 1 1]
How could I do that in MATLAB? I reviewed the a similar post in which one vector is being repeated, so I tried to do the same and made a for loop. Here is my code:
clear all
close all
clc
% data
d1 = [1 2 1 3 4];
d2 = [3 1 2 1];
howMany1 = [3 2 2 1 2]; % Determines how many times each index in IDX1 should be repeated.
howMany2 = [2 1 2 2];
d = {d1 d2}
howMany = {howMany1 howMany2}
Anew = cell(1,2)
for k = 1:2 % 2 data vectors
Anew{1,k} = arrayfun(#(x) repmat(d{k}(x), howMany{k}(x), 1), 1:numel(d{k}), 'uni', 0);
Anew = vertcat(Anew{:});
end
but I receive the following error:
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
Then I tried to change the vert cat to horzcat, but I receive the repetitions as group of doubles:
Anew =
Columns 1 through 7
[3x1 double] [2x1 double] [1] [2x1 double] [2x1 double] [2x1 double] [3]
Column 8
[2x1 double]
Im wondering what is the problem here? Thank you for taking the time.

This can be done by combining ismember and cumsum:
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
Breakdown:
Compare 1:sum(howMany1) with the cumulative sum of howMany1. This is a vector with 1 and 0 that shows the position of where the next value from d1 should start.
ismember(1:sum(howMany1),cumsum([1 howMany1]))
ans =
1 0 0 1 0 1 0 1 1 0
The cumulative sum of this gives a vector that looks like:
cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1])))
ans =
1 1 1 2 2 3 3 4 5 5
Now, this can be used as indices to d1 when creating the d1_repeated.
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
ans =
1 1 1 2 2 1 1 3 4 4

Related

How to creat a four dimentional (from a vector) matrix and reset it's 'lower triangle'

I am trying to get a 4 dimentional matrix out of a vector and then reset it's
'lower triangel'.
for example, if my original vector is two dimentional: A = [1 2]' then I would like my initial matrix to be:
C(:,:,1,1) = [1*1*1*1 1*1*1*2 ; 1*1*2*1 1*1*2*2] = [ 1 2 ; 2 4]
C(:,:,2,1) = [2*1*1*1 2*1*1*2 ; 2*1*2*1 2*1*2*2] = [ 2 4 ; 4 8]
C(:,:,1,2) = [1*2*1*1 1*2*1*2 ; 1*2*2*1 1*2*2*2] = [ 2 4 ; 4 8]
C(:,:,2,2) = [2*2*1*1 2*2*1*2 ; 2*2*2*1 2*2*2*2] = [ 4 8 ; 8 16]
So C is:
C(:,:,1,1) = [ 1 2 ; 2 4] C(:,:,2,1) = [ 2 4 ; 4 8]
C(:,:,1,2) = [ 2 4 ; 4 8] C(:,:,2,2) = [ 4 8 ; 8 16]
and after reset I would like it to be:
C(:,:,1,1) = [ 1 2 ; 2 4] C(:,:,2,1) = [ 0 0 ; 0 0]
C(:,:,1,2) = [ 0 0 ; 4 8] C(:,:,2,2) = [ 0 0 ; 8 16]
shotrly, I want no rows repetitions.
I tried the following code:
A = [1 2]';
C = bsxfun(#times, permute(C, [4 3 2 1]), C*C');
disp('C before reset is:');
disp(C);
for k = 2:size(C, 4)
C(1:k-1,:,k) = 0;
end
disp('C after reset is:');
disp(C);
disp('The size of C is:');
disp(size(C));
But the output is:
BB before reset is:
(:,:,1,1) =
1 2
2 4
(:,:,1,2) =
2 4
4 8
C after reset is:
(:,:,1,1) =
1 2
2 4
(:,:,1,2) =
0 0
4 8
The size of BB is:
2 2 1 2
What did I miss?
I think I don't understand what is behind the line:
C = bsxfun(#times, permute(C, [4 3 2 1]), C*C');
what is the meaning of each number in the row [4 3 2 1]?
Thanks!
edit note: The matrix represents correlations between neurons. I am trying to look at the correlation structure of groups of 4 neurons. So, each 4 neurons sould only be measuresd once. I think that he matrix before reset contains 4! times, every group of 4, because they apear in all orders. I could leave it like this but I am think it might slow the program..
Permute exchanges dimensions, so for example
C = [1:3;4:6];
permute(C, [2 1])
Computes a simple transpose by swapping rows and columns. The [2 1] argument means that the 2st and 1st dimension of C are mapped to the 1st and 2nd dimension in the result. Each 'new' dimension is specified in order. So [3 2 1] would take the 3rd, 2nd and 1st dimensions to be the new 1st, 2nd and 3rd dimensions.
permute(C, [3 2 1])
ans =
ans(:,:,1) =
1 2 3
ans(:,:,2) =
4 5 6
Elements of C with row = 1 are found in where the 3rd dimension = 1 in the result. Similarly, elements of C with row = 2 are found where the 3rd dimension = 2 in the result.
Elements of C with column = 1 are still found where column = 1 in the result (and so on) as the column dimension was mapped to itself.
The rows of the result is the interesting dimension, it is singleton (i.e. there is only one row) as a result of C having no 3rd dimension.
Addressing the first part of your problem, the correct output for C can be obtained by
A = [1 2]'*[1 2];
C = bsxfun(#times, permute(A, [4,3,1,2]), A);
I would need more information on what you want the final behaviour to be ('resetting the lower triangle') as it is unclear to me what you desire.
A function that might be useful to you is the triu function which extracts upper triangular components of a matrix.

Replace one element of a column in another

Let A and B be column vectors:
A = (1:6).'; %'// [1;2;3;4;5;6]
B = (7:12).'; %'// [7;8;9;10;11;12]
How do I construct a matrix such that one element of A is replaced each time by an element from B to get C as:
C = [...
7 1 1 1 1 1
2 8 2 2 2 2
3 3 9 3 3 3
4 4 4 10 4 4
5 5 5 5 11 5
6 6 6 6 6 12];
If C is to be indexed as index = [1 1 1 2 2 3 3]', how is it possible to produce
c1 = [...
1 7 1 1
1 2 8 2
1 3 3 9];
c2 = [...
2 10 4
2 5 11];
c3 = [3 6]; %// either this
c3 = [3 12]; %// or this
Problem #1:
C = bsxfun(#plus,A.',-diag(A)+diag(B));
gives:
7 2 3 4 5 6
1 8 3 4 5 6
1 2 9 4 5 6
1 2 3 10 5 6
1 2 3 4 11 6
1 2 3 4 5 12
Problem #2:
As far as I understand, you want to extract blocks out of the previously found C matrix, in the following fashion:
Where c1, c2, c3 are the green, red and blue blocks, repectively; and "missing" elements are replaced with NaN (in the initial version of your question).
index = [1 1 1 2 2 3 3]; %// Block definition
[blkSz,~] = histcounts(index,numel(unique(index))); %// Conversion...
paddedC = padarray(C,numel(index)-numel(diag(C))*[1 1],NaN,'post');
blocks = mat2cell(paddedC,blkSz,blkSz);
This results in a cell-array blocks with the following contents:
blocks =
[3x3 double] [3x2 double] [3x2 double]
[2x3 double] [2x2 double] [2x2 double]
[2x3 double] [2x2 double] [2x2 double]
Where for example blocks{1,1} is:
ans =
7 2 3
1 8 3
1 2 9
Then you can pad the array using the index of the loop, to get the c cell, like so:
c = cell(numel(blkSz),1); %// Preallocation
for ind1 = 1:numel(blkSz)
c{ind1} = padarray(blocks{ind1,ind1},1,ind1,'pre');
end
Note that c1 is found in c{1} etc.
Addition:
In the case when you don't want c1...c3 to be (possibly) padded with NaNs, the best way in my opinion would be trimming the index vector to the length of A or B ("length(C)"). This ensures you won't access blocks outside your square matrix. For example:
newIdx = index(1:numel(A));
Then just use newIdx instead of index in the rest of the code.

comparing rows of a logical matrix in matlab?

I have sentences cross words [4 cross 5] matrix as follows:
out=
0 1 1 0 1
1 1 1 0 0
0 0 1 1 0
1 1 0 1 1
I want to create a 1D cell array based upon above matrix which should tell in which two sentences same words appear with value = 1 i.e. let's take line 1 and line 2 in which at 2 points column 2 and column 3 the logical matrix has both 1's in row 1 and row 2 this information should be stored in 1D cell array.
suppose above example it's output would be as:
output{1,1} = []
output{1,2} = [2 3]
output{1,3} = [3]
.....
output{n,n} = [....]
where {1,1} tells sentence 1 relation with sentence 1 on the basis of value=1 of words, {1,2} tells sentence 1 relation with sentence 2 on the basis of value=1 of words and so on...
Try this:
x = [ 0 1 1 0 1
1 1 1 0 0
0 0 1 1 0
1 1 0 1 1];
[ii, jj] = ndgrid(1:size(x,1));
y = arrayfun(#(m,n) find(x(m,:) & x(n,:)), ii, jj, 'uniformoutput', 0);
Result:
y{1,1} =
2 3 5
y{2,1} =
2 3
y{3,1} =
3
y{4,1} =
2 5
[...]
If you want the diagonal elements to be empty:
y = arrayfun(#(m,n) find(x(m,:) & x(n,:) & m~=n), ii, jj, 'uniformoutput', 0)
Result:
y{1,1} =
[]
y{2,1} =
2 3
y{3,1} =
3
y{4,1} =
2 5
[...]
If you want something written quick... and since we are dealing with cell arrays, the easiest thing would be to have a pair of for loops. Assuming that you have your matrix defined in out:
out_cell = cell(size(out,1),size(out,1));
for idx = 1 : size(out,1)
for idx2 = 1 : idx
vals = find(out(idx,:) & out(idx2,:));
out_cell{idx,idx2} = vals;
out_cell{idx2,idx} = vals;
end
end
For each pair of rows, idx and idx2, we look to see if any columns match in terms of having a 1, then place the indices into its respective cell location in the 2D cell array. Note that because will encounter pairs of rows that are duplicates (i.e. checking row 3 and row 5, compared to row 5 and row 3), there is no need for the second for loop to iterate all over the other rows. We only need to check up to the current row that is described by the outer loop and we simply write the same values with the row indices swapped... so this is a "symmetric" matrix.
If you would like the diagonal elements to be empty, simply change the inner for loop so that it goes for idx2 = 1 : idx-1, instead of for idx2 = 1 : idx.
With your example, we get:
>> out_cell
out_cell =
[1x3 double] [1x2 double] [ 3] [1x2 double]
[1x2 double] [1x3 double] [ 3] [1x2 double]
[ 3] [ 3] [1x2 double] [ 4]
[1x2 double] [1x2 double] [ 4] [1x4 double]
>> celldisp(out_cell)
out_cell{1,1} =
2 3 5
out_cell{2,1} =
2 3
out_cell{3,1} =
3
out_cell{4,1} =
2 5
out_cell{1,2} =
2 3
out_cell{2,2} =
1 2 3
out_cell{3,2} =
3
out_cell{4,2} =
1 2
out_cell{1,3} =
3
out_cell{2,3} =
3
out_cell{3,3} =
3 4
out_cell{4,3} =
4
out_cell{1,4} =
2 5
out_cell{2,4} =
1 2
out_cell{3,4} =
4
out_cell{4,4} =
1 2 4 5

How to make elements of multiple vectors repeated by MATLAB? [duplicate]

This question already has answers here:
Repeat elements of vector [duplicate]
(3 answers)
Closed 8 years ago.
I have 2 data vectors d1 = [1 2 1 3 4] and d2 = [3 1 2 1], and 2 references howMany1= [3 2 2 1 2] and howMany2 = [2 1 2 2]. The elements of d1 and d2 are to be repeated according to the elements of howMany1 and howMany2: so d1(1) i.e. the first element of d1 should repeat 3 times,d1(2) should repeat 2 times and so on.. and the final result should be d1_repeated = [1 1 1 2 2 1 1 3 4 4] and d2_repeated = [3 3 1 2 2 1 1]
How could I do that in MATLAB? I reviewed the a similar post in which one vector is being repeated, so I tried to do the same and made a for loop. Here is my code:
clear all
close all
clc
% data
d1 = [1 2 1 3 4];
d2 = [3 1 2 1];
howMany1 = [3 2 2 1 2]; % Determines how many times each index in IDX1 should be repeated.
howMany2 = [2 1 2 2];
d = {d1 d2}
howMany = {howMany1 howMany2}
Anew = cell(1,2)
for k = 1:2 % 2 data vectors
Anew{1,k} = arrayfun(#(x) repmat(d{k}(x), howMany{k}(x), 1), 1:numel(d{k}), 'uni', 0);
Anew = vertcat(Anew{:});
end
but I receive the following error:
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
Then I tried to change the vert cat to horzcat, but I receive the repetitions as group of doubles:
Anew =
Columns 1 through 7
[3x1 double] [2x1 double] [1] [2x1 double] [2x1 double] [2x1 double] [3]
Column 8
[2x1 double]
Im wondering what is the problem here? Thank you for taking the time.
This can be done by combining ismember and cumsum:
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
Breakdown:
Compare 1:sum(howMany1) with the cumulative sum of howMany1. This is a vector with 1 and 0 that shows the position of where the next value from d1 should start.
ismember(1:sum(howMany1),cumsum([1 howMany1]))
ans =
1 0 0 1 0 1 0 1 1 0
The cumulative sum of this gives a vector that looks like:
cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1])))
ans =
1 1 1 2 2 3 3 4 5 5
Now, this can be used as indices to d1 when creating the d1_repeated.
d1(cumsum(ismember(1:sum(howMany1),cumsum([1 howMany1]))))
ans =
1 1 1 2 2 1 1 3 4 4

how to get the intersection of many different length cell vectors in matlab

I have n different length cell vectors, call it c{i}, i=1,2,...,n.
I wanna know if there any c{j} is the subset of c{i}, for example:
c{1}=[1 2 3 4 5 6]; c{2}=[1 3 5 7];c{3}=[2 4 6 8];
c{4}=[1 4 6];c{5}=[3 7];
then I hope I can find that c{4} is subset of c{1}, c{5} is subset of c{2}.
I used two for loops with intersect function can process it, but I hope I can use at most one loop to process it, is there any way can achieve it?
Building on the other answers, you can also use ismember:
sets = {[1 2 3 4 5 6], [1 3 5 7], [2 4 6 8], [1 4 6], [3 7]};
N = numel(sets); % number of sets
idx = nchoosek(1:N,2); % indices of combinations
subsets = false(N,N);
for i = 1:size(idx,1)
a = idx(i,1); b = idx(i,2);
% check that set A is a subset of B, and the other way around as well
subsets(a,b) = all(ismember(sets{a},sets{b}));
subsets(b,a) = all(ismember(sets{b},sets{a}));
end
We get a logical matrix:
>> subsets
subsets =
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 0 0 0 0
0 1 0 0 0
where non-zeros indicate subset relationship:
>> [i,j] = find(subsets)
i =
4
5
j =
1
2
i.e c{4} is a subset of c{1}, and c{5} is a subset of c{2}
Note: it is obvious that any set is a subset of itself, so the diagonals of subsets matrix should also be made 1. You could add that if you want using:
subsets(1:N+1:end) = true;
Here's a option using nchoosek – like cellfun it's also a loop in disguise of course:
c{1} = [1 2 3 4 5 6];
c{2} = [1 3 5 7];
c{3} = [2 4 6 8];
c{4} = [1 4 6];
c{5} = [3 7];
combs = nchoosek(1:numel(c),2);
subC = cell(size(combs,1),1);
for i = 1:size(combs,1)
subC{i} = intersect(c{combs(i,:)});
end
which results in the cell array
subC =
[1x3 double]
[1x3 double]
[1x3 double]
[ 3]
[1x0 double]
[ 1]
[1x2 double]
[1x2 double]
[1x0 double]
[1x0 double]
Each cell in subC corresponds to intersection of the cells indices in combs (a matrix form could easily be built within the loop if that is preferred).
EDIT: If you simply want to know if one vector is a subset of another then you can either use subC and combs from above to determine this or calculate it directly
combs = nchoosek(1:numel(c),2);
isSubC = logical(eye(numel(c)));
for i = 1:size(combs,1)
subC = intersect(c{combs(i,:)});
isSubC(combs(i,1),combs(i,2)) = isequal(subC,c{combs(i,2)});
isSubC(combs(i,2),combs(i,1)) = isequal(subC,c{combs(i,1)});
end
where isSubC(i,j) specifies if c{j} is a subset of c{i}.
You can by using cellfun, but as stated here, it is not a good idea.
For doing so, with one loop:
c{1}=[1 2 3 4 5 6]; c{2}=[1 3 5 7];c{3}=[2 4 6 8];
c{4}=[1 4 6];c{5}=[3 7];
cSize = numel( c);
isect=cell(1,cSize)
for k=1:cSize
isect{k}=cellfun(#(in) intersect(in,c{k}),c,'UniformOutput',false);
end
This procedure may be repeated to eliminate the other for:
c{1}=[1 2 3 4 5 6]; c{2}=[1 3 5 7];c{3}=[2 4 6 8];
c{4}=[1 4 6];c{5}=[3 7];
isect=cellfun(#(in) cellfun(#(in2) intersect(in,in2),c,'UniformOutput',false),c,'UniformOutput',false);
isect{i}{j} is the intersection from c{i} to {j}
Note: cellfun will do the loop internally over the cell value, so in fact, you are not removing the loops.
Although this was not the initial question, finding the subsets:
c{1}=[1 2 3 4 5 6]; c{2}=[1 3 5 7];c{3}=[2 4 6 8];
c{4}=[1 4 6];c{5}=[3 7];c{6}=[];
isSubset=cell2mat(cellfun(#(in) cellfun(#(in2) isequal(intersect(in,in2),in)|isempty(in),c),c,'UniformOutput',false)');
Results:
isSubset =
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
1 0 0 1 0 0
0 1 0 0 1 0
1 1 1 1 1 1
Which returns a boolean if k is a subset of m by doing isSubset(k,m).