How can I set a matrix with different, repeating patterns in every column? - arrays

I'm trying to set an nx3 matrix in GNU Octave to scatter plot and compare it to a fitted surface which I already solved for and plotted. However this matrix has repeating patterns in columns 1 and 2; I could set them by hand, but the number of rows is somewhat big and the only row I currently have is the non-repeating one (row 3).
For example:
A=|1 5 z|
|2 5 z|
|3 5 z|
|4 5 z|
|1 10 z|
|2 10 z|
...
And so on. Where z are the values that I already have as a column vector, which I can simply punch into the matrix with:
A(:,3)=z
However, I've tried doing
A(2:4:n)=2;A(3:4:n)=3;A(4:4:n)=4
Which actually worked, for the first column, but had no luck with the second one (and I don't think is the cleanest way to do it). Any ideas?

It seems to me that the pattern in the first two columns correspond to a grid of coordinates, where x=1:4 and y=5:5:20 (or some other end value).
You can generate these coordinates using meshgrid:
[y, x] = meshgrid(5:5:20, 1:4);
(Note how x and y are reversed, don't ask). Next, you can put these into a matrix together with the z values you already have as follows:
A = [x(:), y(:), z];
Alternatively, you can do
A(:,1) = x(:);
A(:,2) = y(:);

Each of the column is repeating in a different way so you can generate each in different ways:
octave:1> col1 = repmat ([1:4].', [3 1]); # repeat matrix
octave:2> col2 = ([5 5 5 5].' .* [1 2 3])(:); # automatic broadcasting
octave:3> col3(1:12, 1) = 42; # on the fly by assignment
octave:4> A = [col1 col2 col3]
A =
1 5 42
2 5 42
3 5 42
4 5 42
1 10 42
2 10 42
3 10 42
4 10 42
1 15 42
2 15 42
3 15 42
4 15 42

Related

How to find minimum value of a column imported from Excel using MATLAB

I have a set of values in the following pattern.
A B C D
1 5 6 11
2 6 5 21
3 7 3 42
4 3 7 22
1 2 3 54
2 3 2 43
3 4 3 27
4 3 2 14
I exported the every column into MATLAB workspace as follows.
A = xlsread('F:\R.xlsx','Complete Data','A2:A43');
B = xlsread('F:\R.xlsx','Complete Data','B2:B43');
C = xlsread('F:\R.xlsx','Complete Data','C2:C43');
D = xlsread('F:\R.xlsx','Complete Data','D2:D43');
I need help with code where the it has to check the Column A, find the lowest D value and output the corresponding B and C values. I need the output to look like.
1 5 6 11
2 6 5 21
3 4 3 27
4 3 2 14
I read through related questions and understand that I need to make it a matrix and sort it based on the element on the 4th column using
sortrows
and get indices of the sorted elements. But I am stuck here. Please Guide me.
You can export those columns in one go as:
ABCD = xlsread('F:\R.xlsx','Complete Data','A2:D43');
Now use sortrows to sort the rows according to the first and the fourth column.
req = sortrows(ABCD, [1 4]);
☆ If all elements of the first column exist twice then:
req = req(1:2:end,:);
☆ If it is not necessary that all elements of the first column will exist twice then:
[~, ind] = unique(req(:,1));
req = req(ind,:);

Automatic test for the equality of columns between two matrices

I have two matrices:
X =
1 2 3
4 5 6
7 8 9
`Y` =
1 10 11
4 12 13
7 14 15
I know that if I want to find the index of a specific element in X or Y, I can use the function find. For example:
index_3 = find(X==3)
What I want is to find or search in a very automatic way if a column in X is also present in Y. In other terms, I want a function which can tell me if a column in X is equal to a column in Y. In fact to to try this, one can use the function ismember which indeed has an optional flag to compare rows:
rowsX = ismember(X, Y, 'rows');
So a simple way to get columns is just by taking the transpose of both matrices:
rowsX = ismember(X.', Y.', 'rows')
rowsX =
1
0
0
But how can I do that in other manner?
Any help will be very appreciated!
You can do that with bsxfun and permute:
rowsX = any(all(bsxfun(#eq, X, permute(Y, [1 3 2])), 1), 3);
With
X = [ 1 2 3
4 5 6
7 8 9 ];
Y = [ 1 10 11
4 12 13
7 14 15 ];
this gives
rowsX =
1 0 0
How it works
permute "turns Y 90 degrees" along a vertical axis, so columns of Y are kept aligned with columns of X, but rows of Y are moved to the third dimension. Testing for equality with bsxfun and applying all(...,1) gives a matrix that tells which columns of X equal which columns of Y. Then any(...,3) produces the desired result: true if a column of X equals any column of Y.

Rowwise 2 dimensional matrix intersection in Matlab

I will try to explain what I need through an example.
Suppose you have a matrix x as follows:
1 2 3
4 5 6
And another matrix y as follows:
1 4 5
7 4 8
What I need is (without looping over the rows) to perform an intersection between each 2 corresponding rows in x & y. So I wish to get a matrix z as follows:
1
4
The 1st rows in x and y only have 1 as the common value. The 2nd rows have 4 as the common value.
EDIT:
I forgot to add that in my case, it is guaranteed that the intersection results will have the same length and the length is always 1 actually.
I am thinking bsxfun -
y(squeeze(any(bsxfun(#eq,x,permute(y,[1 3 2])),2)))
Sample runs -
Run #1:
>> x
x =
1 2 3
4 5 6
>> y
y =
1 4 5
7 4 8
>> y(squeeze(any(bsxfun(#eq,x,permute(y,[1 3 2])),2)))
ans =
1
4
Run #2:
>> x
x =
3 5 7 9
2 7 9 0
>> y
y =
6 4 3
6 0 2
>> y(squeeze(any(bsxfun(#eq,x,permute(y,[1 3 2])),2)))
ans =
0
3
2
The idea is to put the matrices together and to look for duplicates in the rows. One idea to find duplicated numeric values is to diff them; the duplicates will be marked by the value 0 in result.
Which leads to:
%'Initial data'
A = [1 2 3; 8 5 6];
B = [1 4 5; 7 4 8];
%'Look in merged data'
V = sort([A,B],2); %'Sort matrix values in rows'
R = V(diff(V,1,2)==0); %'Find duplicates in rows'
This should work with any number of matrices that can be concatenated horizontally. It will detect all the duplicates, but it will return a column the same size as the number of rows only if there is one and only one duplicate per row in the matrices.

Matlab: Reshaping grid points from ndgrid into N x m matrix [duplicate]

This question pops up quite often in one form or another (see for example here or here). So I thought I'd present it in a general form, and provide an answer which might serve for future reference.
Given an arbitrary number n of vectors of possibly different sizes, generate an n-column matrix whose rows describe all combinations of elements taken from those vectors (Cartesian product) .
For example,
vectors = { [1 2], [3 6 9], [10 20] }
should give
combs = [ 1 3 10
1 3 20
1 6 10
1 6 20
1 9 10
1 9 20
2 3 10
2 3 20
2 6 10
2 6 20
2 9 10
2 9 20 ]
The ndgrid function almost gives the answer, but has one caveat: n output variables must be explicitly defined to call it. Since n is arbitrary, the best way is to use a comma-separated list (generated from a cell array with ncells) to serve as output. The resulting n matrices are then concatenated into the desired n-column matrix:
vectors = { [1 2], [3 6 9], [10 20] }; %// input data: cell array of vectors
n = numel(vectors); %// number of vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n); %// reshape to obtain desired matrix
A little bit simpler ... if you have the Neural Network toolbox you can simply use combvec:
vectors = {[1 2], [3 6 9], [10 20]};
combs = combvec(vectors{:}).' % Use cells as arguments
which returns a matrix in a slightly different order:
combs =
1 3 10
2 3 10
1 6 10
2 6 10
1 9 10
2 9 10
1 3 20
2 3 20
1 6 20
2 6 20
1 9 20
2 9 20
If you want the matrix that is in the question, you can use sortrows:
combs = sortrows(combvec(vectors{:}).')
% Or equivalently as per #LuisMendo in the comments:
% combs = fliplr(combvec(vectors{end:-1:1}).')
which gives
combs =
1 3 10
1 3 20
1 6 10
1 6 20
1 9 10
1 9 20
2 3 10
2 3 20
2 6 10
2 6 20
2 9 10
2 9 20
If you look at the internals of combvec (type edit combvec in the command window), you'll see that it uses different code than #LuisMendo's answer. I can't say which is more efficient overall.
If you happen to have a matrix whose rows are akin to the earlier cell array you can use:
vectors = [1 2;3 6;10 20];
vectors = num2cell(vectors,2);
combs = sortrows(combvec(vectors{:}).')
I've done some benchmarking on the two proposed solutions. The benchmarking code is based on the timeit function, and is included at the end of this post.
I consider two cases: three vectors of size n, and three vectors of sizes n/10, n and n*10 respectively (both cases give the same number of combinations). n is varied up to a maximum of 240 (I choose this value to avoid the use of virtual memory in my laptop computer).
The results are given in the following figure. The ndgrid-based solution is seen to consistently take less time than combvec. It's also interesting to note that the time taken by combvec varies a little less regularly in the different-size case.
Benchmarking code
Function for ndgrid-based solution:
function combs = f1(vectors)
n = numel(vectors); %// number of vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(vectors{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n);
Function for combvec solution:
function combs = f2(vectors)
combs = combvec(vectors{:}).';
Script to measure time by calling timeit on these functions:
nn = 20:20:240;
t1 = [];
t2 = [];
for n = nn;
%//vectors = {1:n, 1:n, 1:n};
vectors = {1:n/10, 1:n, 1:n*10};
t = timeit(#() f1(vectors));
t1 = [t1; t];
t = timeit(#() f2(vectors));
t2 = [t2; t];
end
Here's a do-it-yourself method that made me giggle with delight, using nchoosek, although it's not better than #Luis Mendo's accepted solution.
For the example given, after 1,000 runs this solution took my machine on average 0.00065935 s, versus the accepted solution 0.00012877 s. For larger vectors, following #Luis Mendo's benchmarking post, this solution is consistently slower than the accepted answer. Nevertheless, I decided to post it in hopes that maybe you'll find something useful about it:
Code:
tic;
v = {[1 2], [3 6 9], [10 20]};
L = [0 cumsum(cellfun(#length,v))];
V = cell2mat(v);
J = nchoosek(1:L(end),length(v));
J(any(J>repmat(L(2:end),[size(J,1) 1]),2) | ...
any(J<=repmat(L(1:end-1),[size(J,1) 1]),2),:) = [];
V(J)
toc
gives
ans =
1 3 10
1 3 20
1 6 10
1 6 20
1 9 10
1 9 20
2 3 10
2 3 20
2 6 10
2 6 20
2 9 10
2 9 20
Elapsed time is 0.018434 seconds.
Explanation:
L gets the lengths of each vector using cellfun. Although cellfun is basically a loop, it's efficient here considering your number of vectors will have to be relatively low for this problem to even be practical.
V concatenates all the vectors for easy access later (this assumes you entered all your vectors as rows. v' would work for column vectors.)
nchoosek gets all the ways to pick n=length(v) elements from the total number of elements L(end). There will be more combinations here than what we need.
J =
1 2 3
1 2 4
1 2 5
1 2 6
1 2 7
1 3 4
1 3 5
1 3 6
1 3 7
1 4 5
1 4 6
1 4 7
1 5 6
1 5 7
1 6 7
2 3 4
2 3 5
2 3 6
2 3 7
2 4 5
2 4 6
2 4 7
2 5 6
2 5 7
2 6 7
3 4 5
3 4 6
3 4 7
3 5 6
3 5 7
3 6 7
4 5 6
4 5 7
4 6 7
5 6 7
Since there are only two elements in v(1), we need to throw out any rows where J(:,1)>2. Similarly, where J(:,2)<3, J(:,2)>5, etc... Using L and repmat we can determine whether each element of J is in its appropriate range, and then use any to discard rows that have any bad element.
Finally, these aren't the actual values from v, just indices. V(J) will return the desired matrix.

Associating / linking an array column with another column in the array

I have an array that has some calcultations done on the second column. I would like the values from the third column to follow/be linked to the second column.
Test Code:
a1= [1,10,-11;
2,70,232;
3,33.2,-33;
4,40,44;]
a2calc=abs(a1(:,2)-max(a1(:,2))) %calculation
a2=[a1(:,1),a2calc,a1(:,3)] %new array
Example:
original a1 Array
1 10 -11
2 70 232
3 33.2 -33
4 40 44
a2 Array after column 2 calculations looks like this
1 60 -11
2 0 232
3 36.8 -33
4 30 44
I'm trying to get the final array to look like this (column 3 values follow / are linked to the second column)
1 60 232
2 0 -11
3 36.8 44
4 30 -33
What I'm having problems with is I'm not sure if I should use the index values of column 2 and if so how I can get it to look like the final output array I included in the question.
I might be wrong here, but it looks to me like the logic is:
After calculating the second column, change the order of the third column so that the third column is sorted the same way as the second. To see what I mean:
This represents the two columns, numbered from highest to lowest:
A = 1 1
4 3
2 2
3 4
If I understand it right, you want the resulting matrix to be
A = 1 1
4 4
2 2
3 3
If this is the right logic then you should check out sort with two outputs. You can use the second output to index the third column.
[~, idx] = sort(A(:, 2));
sorted_3 = sort(A(:, 3));
A(idx, 3) = sorted_3;
The output from this is:
A =
1.00000 60.00000 232.00000
2.00000 0.00000 -33.00000
3.00000 36.80000 44.00000
4.00000 30.00000 -11.00000
Good luck!

Resources