MATLAB subtract every row of matrix by a given vector - matlab

Let
M = | 1 2 3 |
| 4 5 6 |
| 7 8 9 |
and
V = | 1 1 1 |
I want to subtract V from every row of M so that M should look like
M = | 0 1 2 |
| 3 4 5 |
| 6 7 8 |
How can I do that without using a for, is there any straightforward command?

You can also use bsxfun.
M = [1 2 3 ; 4 5 6 ; 7 8 9] ;
V = [1 1 1] ;
iwant = bsxfun(#minus,M,V)

>> M = [1 2 3; 4 5 6; 7 8 9];
>> V = [1 1 1];
>> MV = M-repmat(V,size(M,1),1)
MV =
0 1 2
3 4 5
6 7 8
The call to repmat repeats the vector V by the number of rows in M.
User beaker pointed out that an even simpler (though a bit obscure) syntax works in recent versions of MATLAB. If you subtract a vector from a matrix, MATLAB will extend the vector to match the size of the matrix as long as one dimension of vector matches the matrix dimensions. See Compatible Array Sizes for Basic Operations.
>> M-V
ans =
0 1 2
3 4 5
6 7 8
Of course, if you know that V will contain all 1s, the solution is even simpler:
>> MV = M-1
MV =
0 1 2
3 4 5
6 7 8

Related

Count repeating integers in an array

If I have this vector:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6]
I would like to get the position of each unique number according to itself.
y = [1 2 3 4 5 1 2 3 1 1 2 1 2 3 4]
At the moment I'm using:
y = sum(triu(x==x.')) % MATLAB 2016b and above
It's compact but obviously not memory efficient.
For the pure beauty of MATLAB programming I would avoid using a loop. Do you have a better simple implementation ?
Context:
My final goal is to sort the vector x but with the constraint that a number that appear N times has the priority over another number that has appeared more than N times:
[~,ind] = sort(y);
x_relative_sort = x(ind);
% x_relative_sort = 1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
Assuming x is sorted, here's one vectorized alternative using unique, diff, and cumsum:
[~, index] = unique(x);
y = ones(size(x));
y(index(2:end)) = y(index(2:end))-diff(index).';
y = cumsum(y);
And now you can apply your final sorting:
>> [~, ind] = sort(y);
>> x_relative_sort = x(ind)
x_relative_sort =
1 2 3 4 6 1 2 4 6 1 2 6 1 6 1
If you have positive integers you can use sparse matrix:
[y ,~] = find(sort(sparse(1:numel(x), x, true), 1, 'descend'));
Likewise x_relative_sort can directly be computed:
[x_relative_sort ,~] = find(sort(sparse(x ,1:numel(x),true), 2, 'descend'));
Just for variety, here's a solution based on accumarray. It works for x sorted and containing positive integers, as in the question:
y = cell2mat(accumarray(x(:), x(:), [], #(t){1:numel(t)}).');
You can be more memory efficient by only comparing to unique(x), so you don't have a large N*N matrix but rather N*M, where N=numel(x), M=numel(unique(x)).
I've used an anonymous function syntax to avoid declaring an intermediate matrix variable, needed as it's used twice - this can probably be improved.
f = #(X) sum(cumsum(X,2).*X); y = f(unique(x).'==x);
Here's my solution that doesn't require sorting:
x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
y = cell2mat( splitapply(#(v){cumsum(v)},x,cumsum(logical([1 diff(x)]))) ) ./ x;
Explanation:
% Turn each group new into a unique number:
t1 = cumsum(logical([1 diff(x)]));
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% Apply cumsum separately to each group:
t2 = cell2mat( splitapply(#(v){cumsum(v)},x,t1) );
% t1 = [1 1 1 1 1 2 2 2 3 4 4 5 5 5 5 6 6 6];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];
% Finally, divide by x to get the increasing values:
y = t2 ./ x;
% x = [1 1 1 1 1 2 2 2 3 4 4 6 6 6 6 1 1 1];
% t2 = [1 2 3 4 5 2 4 6 3 4 8 6 12 18 24 1 2 3];

Finding where a set of values lie within a matrix

I have two values (k and j) which I know are within an nx3 matrix (M). I know that they're and on the same row and that j is always to the right of k, so if k is in M(2,1), then j will be in M(2,2). I tested for this earlier in the function, but now I want to know which row that is for a given k and j. I need the row number of their location to proceed. There are no duplicate combinations of k and j in the matrix.
So if I have the matrix
M=
1 4 5
1 5 7
k j 5
4 5 6
2 3 1
Then I want to know that they're in row 3. None of the columns are ordered.
What I have tried:
I used the code below
[row,~] = find(M==k);
I'm not sure how to look for a combination of them. I want to avoid using the find function. I hope to potentially use logical indexing.
How do I go about doing this? I hope this question makes sense.
You can use bsxfun -
find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
Being a relational operation with bsxfun, according to this post on benchmarked results, this should be pretty efficient.
Sample runs
Case #1 :
A =
1 4 5
1 5 7
6 7 1
4 5 6
2 3 1
k =
6
j =
7
>> find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
ans =
3
Case #2 :
A =
1 4 5
1 5 7
1 6 7
4 5 6
2 3 1
k =
6
j =
7
>> find(all(bsxfun(#eq,A(:,1:2),[k,j]),2) | all(bsxfun(#eq,A(:,2:3),[k,j]),2))
ans =
3
Slightly different version on bsxfun. This one doesn't limit the matrix to three columns.
find(sum(((bsxfun(#eq,M,j) + bsxfun(#eq,M,k)) .* M).' ) == j+k >0)
Case 1:
M = [
1 4 5
1 5 7
6 7 1
4 5 6
2 3 1]
k=6;j=7;
ans = 3
Case 2:
M=[
1 4 5
1 5 7
1 6 7
4 5 6
2 3 1
];
k=6;j=7;
ans = 3
Use this:
row = find(((M(:,1) == k ) & ( M(:,2) == j)) | ((M(:,1) == k ) & ( M(:,3) == j)) | ((M(:,2) == k ) & ( M(:,3) == j)) )
Also, logical indexing can only give you a matrix with zeros at all other positions and one at your required position. But to get the index of that position, you will have to use find.

Find the rows of a matrix with conditions concerning the values of certain columns in matlab

As the title says, I want to find all rows in a Matlab matrix that in certain columns the values in the row are equal with the values in the previous row, or in general, equal in some row in the matrix. For example I have a matrix
1 2 3 4
1 2 8 10
4 5 7 9
2 3 6 4
1 2 4 7
and I want to find the following rows:
1 2 3 4
1 2 3 10
1 2 4 7
How do I do something like that and how do I do it generally for all the possible pairs in columns 1 and 2, and have equal values in previous rows, that exist in the matrix?
Here's a start to see if we're headed in the right direction:
>> M = [1 2 3 4;
1 2 8 10;
4 5 7 9;
2 3 6 4;
1 2 4 7];
>> N = M; %// copy M into a new matrix so we can modify it
>> idx = ismember(N(:,1:2), N(1,1:2), 'rows')
idx =
1
1
0
0
1
>> N(idx, :)
ans =
1 2 3 4
1 2 8 10
1 2 4 7
Then you can remove those rows from the original matrix and repeat.
>> N = N(~idx,:)
N =
4 5 7 9
2 3 6 4
this will give you the results
data1 =[1 2 3 4
1 2 8 10
4 5 7 9
2 3 6 4
1 2 4 7];
data2 = [1 2 3 4
1 2 3 10
1 2 4 7];
[exists,position] = ismember(data1,data2, 'rows')
where the exists vector tells you wheter the row is on the other matrix and position gives you the position...
a less elegant and simpler version would be
array_data1 = reshape (data1',[],1);
array_data2 = reshape (data2',[],1);
matchmatrix = zeros(size(data2,1),size(data1,1));
for irow1 = 1: size(data2,1)
for irow2 = 1: size(data1,1)
matchmatrix(irow1,irow2) = min(data2(irow1,:) == data1(irow2,:))~= 0;
end
end
the matchmatrix is to read as a connectivity matrix where value of 1 indicates which row of data1 matches with which row of data2

How to subtract each item of a matrix from each coressponding row of another matrix

A = [1 2 3; 7 6 5]
B = [3 7];
A-B = [1-3 2-3 3-3; 7-7 6-7 5-7];
ans =[-2 -1 0; 0 -1 -2]
This is the operation I want to have done. How could I do it by matrix functions other than the iterative solutions?
You do this most conveniently with bsxfun, which automatically expands the arrays to match in size (so that you don't need to use repmat). Note that I need to transpose B so that it's a 2-by-1 array.
A = [1 2 3; 7 6 5]
B = [3 7];
result = bsxfun(#minus,A,B')
result =
-2 -1 0
0 -1 -2
I think that Jonas answer is the best. But just for the record, here is the solution using an explicit repmat:
A = [1 2 3; 7 6 5];
B = [3 7];
sz = size(A);
C = A - repmat(B', [1 sz(2:end)]);
Not only is Jonas' answer simpler, it is actually faster by a factor of 2 for large matrices on my machine.
It's also interesting to note that in the case where A is an n-d array, both these solutions do something quite reasonable. The matrix C will have the following property:
C(k,:,...,:) == A(k,:,...,:) - B(k)
In fact, Jonas' answer will run, and very likely do what you want, in the case where B is m-d, as long as the initial dimensions of A and B' have the same size. You can change the repmat solution to mimic this ... at which point you are starting to reimplement bsxfun!
Normally you can't. Iterative solutions will be necessary, because the problem is poorly defined. Matrix addition/subtraction is only defined for matrices of the same dimensions.
ie:
A = | 1 2 3 |
| 7 6 5 |
B = | 3 7 |
It makes no sense to subtract a 1x2 matrix from a 2x3 matrix.
However, if you multiplied B by some intermediate matrix to make the result a 2x3 matrix, that would work, ie:
B' * Y = | 3 3 3 |
| 7 7 7 |
eg:
B' = diag(B)
= | 3 0 |
| 0 7 |
B' * Y = | 3 3 3 |
| 7 7 7 |
Y = | 1 1 1 |
| 1 1 1 |
Therefore, A-B'*Y gives a valid, non-iterative solution.
A-(B'*Y) = | 1 2 3 | - | 3 3 3 |
| 7 6 5 | | 7 7 7 |
= A - (diag(B) * Y )
The only "cheat" here is the use of the diag() function, which converts a vector to a strictly-diagonal-matrix. There is a way to manually decompose a set of matrix/vector multiplication operations to manually re-create the diag() function, but that would be more work than my solution above itself.
Good luck!

Matlab, struct to matrix form with matrices oriented the correct way

I have a struct called poseSets and it contains two things:
Pose
Time
So what I want to do is to get the poses (Pose is a 4x4 matrix) in to one big long (4xN_Poses) x 4 matrix.
So lets imagine that i have a list of structs that is 10 long. I can get almost my list by doing this:
[structList.Pose]
But this gives me a (4xN) x 4 matrix ie:
1 2 3 4 | 1 2 3 4 | 1 2 3 4 | ...
5 6 7 8 | 5 6 7 8 | 5 6 7 8 | ...
3 5 6 8 | 3 5 6 8 | 3 5 6 8 | ...
0 0 0 1 | 0 0 0 1 | 0 0 0 1 | ...
But what i really want is this:
1 2 3 4
5 6 7 8
3 5 6 8
0 0 0 1
_______
1 2 3 4
5 6 7 8
3 5 6 8
0 0 0 1
_______
1 2 3 4
5 6 7 8
3 5 6 8
0 0 0 1
_______
: : : :
Now i cant transpose it because each of the matrices would be individually transposed and would be the wrong way.
Now you can solve this with a for loop:
poseList = [];
for i = 1:length(PoseSets);
poseList = [poseList; PoseSets(i).Pose];
end
Note: poseList contains what i want.
But I personally believe that matlab is magic and you should be able to write what you want in english and matlab will deliver. Does anyone know a one liner or a better way to do this?
Yes, I also find this quite annoying...some things in Matlab do not seem consistent regarding row-majorness or column-majorness. This is one example where things are concatenated colum-wise (=row-major), while the vast majority of algorithms are column-major. linspace or generic ranges (e.g., x = 0:5:100) are another prime example of row-major matrix generation, while x(:) is then again column-major... ¯\(°_°)/¯
Anyway, the easiest way to resolve is to force column-major concatenation:
cat(1, structList.Pose)
try this: vertcat(structList.Pose)
It can be done, but is sure isn't a one-liner:
% generate some data
M = magic(4)
poseSets = struct('pose',M);
poseSets = repmat(poseSets,3,1)
poseList = cellfun(#transpose, {poseSets.pose}, 'UniformOutput', false);
poseList = [poseList{:}].'