Average Multiple Matrix Columns Based On Duplicate Entries In A Different ColumnVector

I have a column vector consisting of hundreds of unit64 values where duplicates appear and are always grouped together but groups appear only once. Each element of this vector corresponds to a row in a separate 2D matrix of double values. I would like to remove the duplicates from the row vector and then remove the corresponding rows in the matrix, replacing them with a single row where each column is average the removed elements in the column, while keeping the order stable. So with data like this:
1
1
2
A= 2
3
3
1 2 3
2 3 4
3 4 5
B = 4 5 6
5 6 7
6 7 8
I would want the output to be
1.5 2.5 3.5
C = 3.5 4.5 5.5
5.5 6.5 7.5
Some combination of unique and accumarray seems to be in order but I cannot figure out how to handle the multiple coulmn part of the problem.

 Respuesta aceptada

Guillaume
Guillaume el 13 de Jul. de 2018
Editada: Guillaume el 13 de Jul. de 2018
So if I understood correctly, the shape of B does not matter and it is to be considered a column vector.
[~, ~, subs] = unique(A, 'stable');
C = accumarray(subs, B(:), [], @mean)
Note that whether or not the groups appear only once does not matter for the above. All the values with the same corresponding A still get averaged.
Also note that if A is already integer values from 1 to n with no gap and in the right order, then the call to unique is unnecessary and you can just pass A instead of subs.

6 comentarios

No, the shape of B does matter. I've edited the example slightly to add a third row to B. With a third row, your solution gives an error:
"Error using accumarray Second input VAL must be a vector with one element for each row in SUBS, or a scalar."
A and B will always have the same number of rows. B will have more than one column. In any column of B, the values in the rows corresponding to the row indices of repeated values in A should be averaged and the end result should consist of a A with the duplicate rows removed and B with the rows corresponding to the duplicates in A replaced by a single row with the average.
I'm sorry I don't get it at all.
A and B will always have the same number of rows.
In your example, A has 6 rows, and B has 3.
the end result should consist of a A with the duplicate rows
That's easy to achieve:
unique(A, 'stable')
However, none of these values appear in your desired output.
and B with the rows corresponding to the duplicates in A replaced by a single row with the average
I don't understand that. I think you need to describe with an example all the steps leading to each value of C. What is C(1) the average of?
Yep. My first edit made it more confusing. I've made one more edit with the correct data. For the given data, the results should be each column of rows 1 and 2 in B are averaged and the result is row 1 in C. Columns of rows 3 and 4 in B are averaged and the result is row 2 in C and so on. Which rows are averaged are driven by the values in A.
Ok, got it now. This can be done awkwardly with accumarray but in this case, the newer splitapply is simpler. While we're at it we can use findgroups instead of unique:
g = findgroups(A);
C = splitapply(@mean, B, g)
This works great for my sample data above, but when I try it with my real data I am getting an error:
Error using vertcat
Dimensions of arrays being concatenated are not consistent.
Error in splitapply>localapply (line 257)
finalOut{curVar} = vertcat(funOut{:,curVar});
Error in splitapply (line 132)
varargout = localapply(fun,splitData,gdim,nargout);
My A vector is 1335 x 1 (unit64)
My B matrix is 1335 x 632 (double)
findgroups returns a 1335 x 1 (double) with indices from 1 to 516.
I'm not sure why splitapply would be having a problem with this.
C = splitapply(@(m) mean(m, 1), B, g);
should fix the problem. If a group only contain one row, the mean will be taken along the columns of the one row instead of across the rows as it happens for matrices. As a result, you'd get a scalar value instead of a row, hence the Dimensions of arrays being concatenated are not consistent. @(m) mean(m, 1) forces the mean to be taken across the rows regardless.

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Matrices and Arrays en Centro de ayuda y File Exchange.

Productos

Versión

R2018a

Etiquetas

Preguntada:

el 13 de Jul. de 2018

Editada:

el 16 de Jul. de 2018

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by