Taking averages of data based on logical filter - arrays

we have two columns ('A' and 'B') as follows.
A = [10 5 6 6 10 2 3 2 1 3 2 3 3 7 9 8 6 8 8 12]
B = [10 5 6 6 2 2 3 2 1 3 2 3 3 7 2 2 3 3 8 12]
logicalFilter= ~(B<=3 & B>1)
Now I need to take averages of data points in A corresponding to logicalFilter == 1 for three different blocks of logicalFilter == 1 separately and also ignoring first two points (for example) in A when logicalFilter == 1 in each block for the calculation of averages. How this can be done?

My mentalist skills leading me to this answer:
%// input
A = [10 5 6 6 10 2 3 2 1 3 2 3 3 7 9 8 6 8 8 12]
B = [10 5 6 6 2 2 3 2 1 3 2 3 3 7 2 2 3 3 8 12]
mask = (B<=3 & B>1)
%// get subs and vals for accumarray
C = cumsum(~mask) + 1
[~,~,subs] = unique(C(mask))
val = A(mask)
%// calculate mean starting with 3rd value of group
out = accumarray(subs(:),val(:),[],#(x) mean(x(3:end)) )
out =
2.5000 3.0000 7.0000

Related

How can I count number of occurrences of unique row in MATLAB ?

I have a matrix like following,
A =
1 2 3
4 5 6
7 8 9
10 11 12
4 5 6
7 8 9
4 5 6
1 2 3
I could extract unique rows in this matrix using command A_unique = unique(A,'rows') and result as follows
A_unique =
1 2 3
4 5 6
7 8 9
10 11 12
I need to find number of times each rows exists in the main matrix A
Some thing like following
A_unique_count =
2
3
2
1
How can I find count of unique rows? Can anyone help? Thanks in Advance
Manu
The third output of unique gives you the index of the unique row in the original array. You can use this with accumarray to count the number of occurrences.
For example:
A = [1 2 3
4 5 6
7 8 9
10 11 12
4 5 6
7 8 9
4 5 6
1 2 3];
[uniquerow, ~, rowidx] = unique(A, 'rows');
noccurrences = accumarray(rowidx, 1)
Returns:
noccurrences =
2
3
2
1
As expected
I would recommend #excaza's approach. But just for variety:
A_unique_count = diff([0; find([any(diff(sortrows(A), [], 1), 2); 1])]);

From ndgrid grid-representing matrices to grid points

By using ndgrid, we can obtain the matrices representing the grid:
[Y, X, Z]=ndgrid(1:2,3:4,5:6)
Y(:,:,1) =
1 1
2 2
Y(:,:,2) =
1 1
2 2
X(:,:,1) =
3 4
3 4
X(:,:,2) =
3 4
3 4
Z(:,:,1) =
5 5
5 5
Z(:,:,2) =
6 6
6 6
However, there are actually 8 grid "points"
(3,1,5), (3,1,6), (3,2,5), (3,2,6), (4,1,5), (4,1,6), (4,2,5), (4,2,6)
How can I create a matrix of these 8 vectors (using ndgrid or not in the process)? That is,
3 1 5
3 1 6
3 2 5
3 2 6
4 1 5
4 1 6
4 2 5
4 2 6
I've seen this related question, but it uses meshgrid, which only works for two dimensions.
Easy. Just linearize the output from ndgrid:
[Y, X, Z]=ndgrid(1:2,3:4,5:6);
out = [X(:) Y(:) Z(:)]
If you want the same ordering as in your question, use sortrows:
out = sortrows([X(:) Y(:) Z(:)])
You just need to straighten these 3D vectors:
>> vertices = [X(:),Y(:),Z(:)]
vertices =
3 1 5
3 2 5
4 1 5
4 2 5
3 1 6
3 2 6
4 1 6
4 2 6

How to concatenate submatrix into a bigger matrix in Octave

I'm trying to solve the following issue: I have an 3x3x4 array like this:
A(:,:,1) = A(:,:,2) = A(:,:,3) = A(:,:,4) =
1 1 1 2 2 2 3 3 3 4 4 4
1 1 1 2 2 2 3 3 3 4 4 4
1 1 1 2 2 2 3 3 3 4 4 4
I would like to produce a 6x6 matrix like the following:
B =
1 1 1 3 3 3
1 1 1 3 3 3
1 1 1 3 3 3
2 2 2 4 4 4
2 2 2 4 4 4
2 2 2 4 4 4
My first thought was to use something like the reshape function, but since it operates columnwise, the result is not what I want.
Do you have any ideas to perform it efficiently?
Thanks in advance
This is for a general case of converting a 3D array into such a 2D array -
m = 2; %// number of 3D slices to be vertically concatenated to form the rows
m1 = size(A,1)*m;
m2 = size(A,3)/m;
B = reshape(permute(reshape(permute(A,[1 3 2]),m1,m2,[]),[1 3 2]),m1,[])
Sample run -
A(:,:,1) =
1 1 7
1 9 1
1 7 2
A(:,:,2) =
3 9 2
9 4 7
9 3 7
A(:,:,3) =
2 6 8
4 8 4
1 8 4
A(:,:,4) =
1 1 7
8 3 4
1 9 8
A(:,:,5) =
7 9 2
6 8 5
4 1 6
A(:,:,6) =
3 2 8
4 9 1
4 4 4
B =
1 1 7 2 6 8 7 9 2
1 9 1 4 8 4 6 8 5
1 7 2 1 8 4 4 1 6
3 9 2 1 1 7 3 2 8
9 4 7 8 3 4 4 9 1
9 3 7 1 9 8 4 4 4
Since your sub-matrices are all of the same size you can assign them directly into B:
clear
B = zeros(6);
A(:,:,1) = ones(3);
A(:,:,2) = 2*ones(3);
A(:,:,3) = 3*ones(3);
A(:,:,4) = 4*ones(3);
B = [A(:,:,1) A(:,:,3); A(:,:,2) A(:,:,4)]
B =
1 1 1 3 3 3
1 1 1 3 3 3
1 1 1 3 3 3
2 2 2 4 4 4
2 2 2 4 4 4
2 2 2 4 4 4
This might prove cumbersome if you have many more sub-matrices though but that could be automated.
permute is much more efficient (à la Divakar) or manually slicing into a 2D array (à la Benoit), but I'll add something to the mix for future readers. One way I can suggest is to take each plane and place it into a 1D cell array, reshape the cell array into a 2 x 2 grid, then convert the 2 x 2 grid into a final matrix. Something like:
B = arrayfun(#(x) A(:,:,x), 1:4, 'uni', 0);
B = reshape(B, 2, 2);
B = cell2mat(B)
B =
1 1 1 3 3 3
1 1 1 3 3 3
1 1 1 3 3 3
2 2 2 4 4 4
2 2 2 4 4 4
2 2 2 4 4 4

Complete set of combinations combining 3 set

I need to generate the complete set of combinations obtained combining three different subset:
Set 1: choosing any 4 numbers from a vector of 13 elements.
Set 2: choosing any 2 numbers from a vector of 3 elements.
Set 3: choosing any 2 numbers from a vector of 9 elements.
Example: sample 3 from vector of 4 (H=3 and L=4) for the Set A, H=2 L=3 for the Set B and H=2 L=4 for the Set B:
4 4 4
3 4 4
3 3 4
3 3 3
2 4 4
2 3 4
2 3 3
2 2 4
Set A = 2 2 3
2 2 2
1 4 4
1 3 4
1 3 3
1 2 4
1 2 3
1 2 2
1 1 4
1 1 3
1 1 2
1 1 1
3 3
2 3
Set B = 2 2
1 3
1 2
1 1
4 4
3 4
3 3
2 4
Set C = 2 3
2 2
1 4
1 3
1 2
1 1
[Set A] = [20 x 3], [Set B] = [6 x 2], [Set C] = [10 x 2]. Then I need to obtain all possible combinations from these three sets: AllComb = [Set A] x [Set B] x [Set C] = [1200 x 8]. The AllComb matrix will be like this:
4 4 4 | 3 3 | 4 4
4 4 4 | 3 3 | 3 4
4 4 4 | 3 3 | 3 3
4 4 4 | 3 3 | 2 4
4 4 4 | 3 3 | 2 3
4 4 4 | 3 3 | 2 2
4 4 4 | 3 3 | 1 4
4 4 4 | 3 3 | 1 3
4 4 4 | 3 3 | 1 2
4 4 4 | 3 3 | 1 1
4 4 4 | 2 3 | 4 4
4 4 4 | 2 3 | 3 4
4 4 4 | 2 3 | 3 3
4 4 4 | 2 3 | 2 4
4 4 4 | 2 3 | 2 3
.
.
.
1 1 1 | 1 1 | 1 1
Unfortunately I can not use the same number for the sets since I need to substitute the numbers like that:
For Set A: 1 = 10, 2 = 25, 3 = 30 and 4 = 45
For Set B: 1 = 5, 2 = 20 and 3 = 35
For Set C: 1 = 10, 2 = 20, 3 = 30 and 4 = 50
Any ideas? Real case sets will often lead to an AllComb matrix ~[491 400 x 8] so vectorized solutions will be gladly accepted.
Note: Each set is obtained with the following code:
a = combnk(1:H+L-1, H);
b = cumsum([a(:,1) diff(a,[],2) - 1],2);
What is H and L?
H are the hoppers of a MultiheadWeigher (MHW) machines. I have a MHW with H=8 and I need to deliver in each of these hoppers some materials. If I need to deliver just one type of material all possibile combinations are (L+H-1)!/(H!(L-1)!) and i compute them with the code write above (a and b). Now, suppose to have 3 different product then we have 4 hoppers for product A, 2 for B and 2 for C. Product A in the first 4 hoppers can assume values 10:10:130, Product B 10:10:30 and c 10:10:90. Then the number of steps are for A L=13, B L=3 and C L=9
You basically need to find
Combinations with repetition for each set;
"Multi-variations" (I don't know the correct name for this) of the results of stage 1.
Both stages can be solved with more or less the same logic, taken from here.
%// Stage 1, set A
LA = 4;
HA = 3;
SetA = cell(1,HA);
[SetA{:}] = ndgrid(1:LA);
SetA = cat(HA+1, SetA{:});
SetA = reshape(SetA,[],HA);
SetA = unique(sort(SetA(:,1:HA),2),'rows');
%// Stage 1, set B
LB = 3;
HB = 2;
SetB = cell(1,HB);
[SetB{:}] = ndgrid(1:LB);
SetB = cat(HB+1, SetB{:});
SetB = reshape(SetB,[],HB);
SetB = unique(sort(SetB(:,1:HB),2),'rows');
%// Stage 1, set C
LC = 4;
HC = 2;
SetC = cell(1,HC);
[SetC{:}] = ndgrid(1:LC);
SetC = cat(HC+1, SetC{:});
SetC = reshape(SetC,[],HC);
SetC = unique(sort(SetC(:,1:HC),2),'rows');
%// Stage 2
L = 3; %// number of sets
result = cell(1,L);
[result{:}] = ndgrid(1:size(SetA,1),1:size(SetB,1),1:size(SetC,1));
result = cat(L+1, result{:});
result = reshape(result,[],L);
result = [ SetA(result(:,1),:) SetB(result(:,2),:) SetC(result(:,3),:) ];
result = flipud(sortrows(result)); %// put into desired order
This gives
result =
4 4 4 3 3 4 4
4 4 4 3 3 3 4
4 4 4 3 3 3 3
4 4 4 3 3 2 4
4 4 4 3 3 2 3
4 4 4 3 3 2 2
4 4 4 3 3 1 4
4 4 4 3 3 1 3
4 4 4 3 3 1 2
4 4 4 3 3 1 1
4 4 4 2 3 4 4
4 4 4 2 3 3 4
4 4 4 2 3 3 3
4 4 4 2 3 2 4
4 4 4 2 3 2 3
4 4 4 2 3 2 2
4 4 4 2 3 1 4
4 4 4 2 3 1 3
4 4 4 2 3 1 2
...
I guess this could be further optimized but this generates you AllComb:
H=3;
L=4;
a = combnk(1:H+L-1, H);
b = cumsum([a(:,1) diff(a,[],2) - 1],2);
H=2;
L=3;
c = combnk(1:H+L-1, H);
d = cumsum([c(:,1) diff(c,[],2) - 1],2);
H=2;
L=4;
e = combnk(1:H+L-1, H);
f = cumsum([e(:,1) diff(e,[],2) - 1],2);
u=[];
for k=1:10
u=vertcat(u,d);
end
u=sortrows(u,[1 2]);
v=[];
for k=1:6
v= vertcat(v,f);
end
w= [u,v];
v=[];
for k=1:20
v= vertcat(v,w);
end
u=[];
for k=1:60
u = vertcat(u,b);
end
u=sortrows(u,[1 2 3]);
AllComb= [u,v];
Here b,d and f are your 3 sets. Then i loop over the numbers of permutation in d and f and replicate them so that all possibilities are constructed. One of them is sorted and then i write them in a new matrix w. THis process is repeated with Set A (b) and this new constructed matrix. Resulting in the end in AllComb.

Reshape acast() remove missing values

I have this dataframe:
df <- data.frame(subject = c(rep("one", 20), c(rep("two", 20))),
score1 = sample(1:3, 40, replace=T),
score2 = sample(1:6, 40, replace=T),
score3 = sample(1:3, 40, replace=T),
score4 = sample(1:4, 40, replace=T))
subject score1 score2 score3 score4
1 one 2 4 2 2
2 one 3 3 1 2
3 one 1 2 1 3
4 one 3 4 1 2
5 one 1 2 2 3
6 one 1 5 2 4
7 one 2 5 3 2
8 one 1 5 1 3
9 one 3 5 2 2
10 one 2 3 3 4
11 one 3 2 1 3
12 one 2 5 2 1
13 one 2 4 1 4
14 one 2 2 1 3
15 one 1 3 1 4
16 one 1 6 1 3
17 one 3 4 2 2
18 one 3 2 1 3
19 one 2 5 3 1
20 one 3 6 2 1
21 two 1 6 3 4
22 two 1 2 1 2
23 two 3 2 1 2
24 two 1 2 2 1
25 two 2 3 1 3
26 two 1 5 3 3
27 two 2 4 1 4
28 two 2 6 2 4
29 two 1 6 2 2
30 two 1 5 1 4
31 two 2 1 2 4
32 two 3 6 1 1
33 two 1 1 3 1
34 two 2 4 2 3
35 two 2 1 3 2
36 two 2 3 1 3
37 two 1 2 3 4
38 two 3 5 2 2
39 two 2 1 3 4
40 two 2 1 1 3
Note that the scores have different ranges of values. Score 1 ranges from 1-3, score 2 from -6, score 3 from 1-3, score 4 from 1-4
I'm trying to reshape data like this:
library(reshape2)
dfMelt <- melt(df, id.vars="subject")
acast(dfMelt, subject ~ value ~ variable)
Aggregation function missing: defaulting to length
, , score1
1 2 3 4 5 6
one 6 7 7 0 0 0
two 8 9 3 0 0 0
, , score2
1 2 3 4 5 6
one 0 5 3 4 6 2
two 5 4 2 2 3 4
, , score3
1 2 3 4 5 6
one 10 7 3 0 0 0
two 8 6 6 0 0 0
, , score4
1 2 3 4 5 6
one 3 6 7 4 0 0
two 3 5 5 7 0 0
Note that the output array includes scores as "0" if they are missing. Is there any way to stop these missing scores being outputted by acast?
In this case, you might do better sticking to base R's table feature. I'm not sure that you can have an irregular array like you are looking for.
For example:
> lapply(df[-1], function(x) table(df[[1]], x))
$score1
x
1 2 3
one 9 6 5
two 11 4 5
$score2
x
1 2 3 4 5 6
one 2 5 4 3 3 3
two 4 2 2 3 4 5
$score3
x
1 2 3
one 9 5 6
two 4 11 5
$score4
x
1 2 3 4
one 4 4 8 4
two 2 6 5 7
Or, using your "long" data:
with(dfMelt, by(dfMelt, variable,
FUN = function(x) table(x[["subject"]], x[["value"]])))
Since each "score" subset is going to have a different shape, you will not be able to preserve the array structure. One option is to use lists of two-dim arrays or data.frames. eg:
# your original acast call
res <- acast(dfMelt, subject ~ value ~ variable)
# remove any columns that are all zero
apply(res, 3, function(x) x[, apply(x, 2, sum)!=0] )
Which gives:
$score1
1 2 3
one 7 8 5
two 6 8 6
$score2
1 2 3 4 5 6
one 4 2 6 4 1 3
two 2 5 3 4 3 3
$score3
1 2 3
one 5 10 5
two 5 11 4
$score4
1 2 3 4
one 5 4 4 7
two 4 6 6 4

Resources