Construct matrix according to the arrangement in another matrix - matlab

I have a matrix 'eff_tot' with dimension (m x n) which I want to rearrange according to a matrix called 'matches' (e.g. [n2 n3; n4 n5]) and put all the collumns not specified in 'matches' at the end.
That is, I want to have [eff_tot(:,n2) eff_tot(:,n3) ; eff_tot(:,n4) eff_tot(:,n5) ; eff_tot(:,n1)].
That's all folks!
Taking the example in the first answer, what I would like to have is:
eff_tot =
81 15 45 15 24
44 86 11 14 42
92 63 97 87 5
19 36 1 58 91
27 52 78 55 95
82 41 0 0 0
87 8 0 0 0
9 24 0 0 0
40 13 0 0 0
26 19 0 0 0
Regards.

Create a vector listing the indices of all the columns in eff_tot and then use SETDIFF to determine which columns do not occur in [n2 n3 n4 n5]. These columns are the unmatched ones. Now concatenate the matched and unmatched column indices to create your column-reordered eff_tot matrix.
>> eff_tot = randi(100, 5, 7)
eff_tot =
45 82 81 15 15 41 24
11 87 44 14 86 8 42
97 9 92 87 63 24 5
1 40 19 58 36 13 91
78 26 27 55 52 19 95
>> n2 = 3; n3 = 5; n4 = 2; n5 = 6;
>> missingColumn = setdiff(1:size(eff_tot, 2), [n2 n3 n4 n5])
missingColumn =
1 4 7
>> eff_tot = [eff_tot(:,n2) eff_tot(:,n3) eff_tot(:,missingIndex); eff_tot(:,n4) eff_tot(:,n5) zeros(size(eff_tot, 1), length(missingIndex))];
eff_tot =
81 15 45 15 24
44 86 11 14 42
92 63 97 87 5
19 36 1 58 91
27 52 78 55 95
82 41 0 0 0
87 8 0 0 0
9 24 0 0 0
40 13 0 0 0
26 19 0 0 0

Related

MatLab Group by Non-Descending Order

In MatLab 2016b, is there a way to group the values of the below vector by non-descending order?
values = [1 1 1 7 17 74 89 91 96 1 5 32 43 78 84 95 98 100 0 0 15 31 69 88 94 97 100 100 100 0 2 12 42 66 78 83 89 94 97 1 6 34 63 65 75 89 93 98]
so I will get the following groups:
group A) 1 1 1 7 17 74 89 91 96
group B) 1 5 32 43 78 84 95 98 100
group C) 0 0 15 31 69 88 94 97 100 100 100
group D) 0 2 12 42 66 78 83 89 94 97
group E) 1 6 34 63 65 75 89 93 98
The following code should give you what you are looking for:
% Define the values...
values = [1 1 1 7 17 74 89 91 96 1 5 32 43 78 84 95 98 100 0 0 15 31 69 88 94 97 100 100 100 0 2 12 42 66 78 83 89 94 97 1 6 34 63 65 75 89 93 98];
% Define the linear indices...
subs = 1:numel(values);
% Define the grouping indices...
idx = [0 subs(diff(values) < 0) subs(end)];
% Split the values into multiple arrays...
result = arrayfun(#(k)values(idx(k-1)+1:idx(k)),2:numel(idx),'UniformOutput',false);
Here is the final output:
>> result{:}
ans =
1 1 1 7 17 74 89 91 96
ans =
1 5 32 43 78 84 95 98 100
ans =
0 0 15 31 69 88 94 97 100 100 100
ans =
0 2 12 42 66 78 83 89 94 97
ans =
1 6 34 63 65 75 89 93 98
diff(values)
returns a vector with the difference between each element of values and the following element. We can use this in a comparison to give a logical vector:
diff(values) < 0
returns a vector containing true, or 1, whenever the corresponding element of values is less than the following element. To finish the job we can use the cumsum function which returns a vector containing the running total of the elements in the input vector:
groups = cumsum([1, diff(values) < 0])
Just one wrinkle: we have to prepend an extra element at the front of the diff vector, because it has one fewer element than values did. Now we have a vector groups containing 1 for each element of values that should be in the first group, 2 for each element that should be in the second group, and so on.
You can access the individual groups using logical indexing:
values(groups == n) % returns a vector of the values in group n
If you want the groups as separate vectors you could use arrayfun:
groupArray = arrayfun(#(x) values(groups == x), 1:max(groups), 'UniformOutput', false)
This returns a cell array where groupArray{1} is the first group, groupArray{2} is the second group, etc.

Matlab replace value with zero from matrix

I matrix
A = [123 123 123 99 99 99 32 32 32 40
40 40 22 22 34 34 34 152 152 152
92 92 92 91 91 91 146 146 146 119
3 3 96 96 96 136 136 136 68 68
]
B = [40 68 119]
How can I replace with zero value from A that have same value with B. required result:
C = [123 123 123 99 99 99 32 32 32 0
0 0 22 22 34 34 34 152 152 152
92 92 92 91 91 91 146 146 146 0
3 3 96 96 96 136 136 136 0 0
]
thank you...
Use ismember to obtain a logical mask of values of A that are in B, and then use that as a logical index to make those entries zero:
C = A; % define C equal to A
C(ismember(A,B)) = 0; % make elements from B equal to 0
Or, in a single line: multiply A by a mask that equals 1 for elements not in B and 0 for elements in B:
C = A.*~ismember(A,B); % multiply A by a mask to make elements from B equal to 0
I'd start down this road:
C = A;
for i = 1:numel(B)
C(C == B(i)) = 0;
end
The third line uses logical indexing - C == 20 is a logical matrix, true where the element is 20, false otherwise, and C(C == 20) = 0 sets the true elements to 0.

how to smartly extract elements from 3 D array and put it into one array?

lets say
g(:,:,1) = [ 1; 4; 7]
g(:,:,2) = [11; 44; 77]
g(:,:,3) = [111; 444; 777] .
Lets say a = [2; 3; 1] and b = [1; 3; 2]. I want the output like this
[4;777;11]. first element is g(2,:,1) , second element is g(3,:,3) and third element is g(1,:,2).
It's as simple as this -
[m,n,r] = size(g)
out = g(a + (b-1)*m*n)
For a generic case, when you want to specify the column number as well -
out = g(a + (col_num-1)*m + (b-1)*m*n)
For a more generic case, when you want to specify more than just one column -
g(bsxfun(#plus,(col_nums-1)*m,a(:)+(b(:)-1)*m*n))
For even more generic cases, you have to ask harder questions.
Sample run -
>> g
g(:,:,1) =
11 81 26 19 87
96 87 80 27 58
1 9 43 15 55
77 40 91 14 15
g(:,:,2) =
85 40 19 90 34
62 8 24 94 90
35 24 42 49 37
51 13 5 49 12
g(:,:,3) =
78 10 57 82 65
39 14 6 2 73
24 94 24 5 65
40 95 35 17 45
>> [m,n,r] = size(g);
>> a = [2,3,1]; b = [1,3,2];
>> col_nums = [1 3];
>> g(bsxfun(#plus,(col_nums-1)*m,a(:)+(b(:)-1)*m*n))
ans =
96 80
24 24
85 19

Matlab: sum column elements with restrictions

We have a MxN matrix and a constrain cstrn = 100;.
The constrain is the summarize limit of column's elements (per column):
sum(matrix(:,:))<=cstrn.
For a given example as the following:
Columns 1 to 5:
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41
I want to find the max number of element per column who fulfill this constrain.
How can i summarize every column element with the others elements in same column and find which sum combinations uses the max number of elements per column?
In the given example solution is:
4 3 5 2 5
where
column 1: 15 + 50 + 31 +7 +(-2)
column 2: 18 +(-15) + 52 or 63 etc.
Thank you in advance.
Since it is always easier to fit small elements into a sum, you can do a sort, followed by the cumulative sum:
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
cs = cumsum(sort(m))
cs =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
Now you easily identify at which element you cross the threshold cnstrn (thanks, #sevenless)!
out = sum(cs <= cnstrn)
out =
4 3 5 2 5
I'd add to Jonas's answer, that you can impose your constraint in a way that outputs a logical matrix then sum over the 1's and 0's of that matrix like so:
cstrn = 100
m= [
15 18 -5 22 19
50 98 -15 39 -8
70 -15 80 45 38
31 52 9 80 72
-2 63 52 71 6
7 99 32 58 41];
val_matrix = cumsum(sort(m))
logical_matrix = val_matrix<=cstrn
output = sum(logical_matrix)
Giving output:
cstrn =
100
val_matrix =
-2 -15 -15 22 -8
5 3 -20 61 -2
20 55 -11 106 17
51 118 21 164 55
101 216 73 235 96
171 315 153 315 168
logical_matrix =
1 1 1 1 1
1 1 1 1 1
1 1 1 0 1
1 0 1 0 1
0 0 1 0 1
0 0 0 0 0
output =
4 3 5 2 5
Here is a logic, on mobile so can't give a code.
Check this out. Go to a column, sort it ascending order, loop to sum, break when hits <=100. Get counter. Refer back to original column, get the indices of elements matching the elements you just summed up :-)

sum over a matrix with condition in matlab

assume I have a 10x10 matrix M
M=[64 36 50 87 22 45 37 23 68 88;
33 23 87 49 54 25 35 98 78 52;
12 54 76 43 24 87 54 98 45 34;
77 87 23 45 34 65 23 76 12 76;
12 34 55 44 76 98 93 23 54 67;
22 55 78 90 88 56 34 23 12 76;
99 23 67 89 34 23 12 87 45 23;
22 54 76 89 65 23 45 12 93 12;
44 56 23 88 67 14 15 67 34 12;
11 44 77 99 34 23 78 34 12 79];
I want to first find out the local maximum in the matrix
and then according to the maximum position do a sum over a 3x3 region over M
For the first step, the code I used is local_max=imregionalmax(M). to find out the local maximum position, but how can I go further to use this coordination to sum over a 3x3 matrix over M?
Thanks for the help.
You can calculate the sum for the whole matrix and then only keep the values that you're interested in. This should work:
local_max=imregionalmax(M)
sums = imfilter(M, ones(3));
local_max_sums = sums(local_max);
And if what you want is a matrix with non-zero entries where the local maxima are located:
local_max_sums = sums .* local_max;
You seem to be looking for the matrix subset functionality of Matlab.
Basically, for
M = [ 1 2 3 4 5 6;
4 5 6 7 8 9;
7 8 9 0 1 2;
0 1 2 3 4 5;
3 4 5 6 7 8;
6 7 8 9 0 1];
If you have a max at (3,3), you can use M(2:4, 2:4) to get
N = [ 5 6 7;
8 9 0;
1 2 3];
Summing that matrix is all that remains - as simple as
total = sum(N(:));
This is kind of brute force for Matlab, but I think it works.
bw = imregionalmax(M);
[x,y] = find(bw);
s = [];
for i = 1:length(x)
startX = x(i)-2;
if(startX < 1)
startX = 1;
end
endX = x(i)+2;
if endX > 10
endX = 10;
end
startY = y(i)-2;
if startY < 1
startY = 1;
end
endY = y(i)+2;
if endY > 10
endY = 10;
end
s(i) = sum2(M(startX:endX, startY:endY));
end