rule-based element selection from a matrixu V MmPGgzl
For simplicity, I give a (3,3) matrix below, though my matrix is of a larger dimension. My objective is, after some matrix manipulations, to select Maximum element(s) in a row and a column, and place zero all the cells except the maximum elements.
mat = {{1, 4, 5}, {1, 2, 4}, {4, 1, 2}};
one = {1, 1, 1};
colTot = one.mat;
rowTot = mat.one;
colStd = Table[matColStd[i, j] = mat[[i, j]]/colTot[[j]],
{i,3}, {j,3}]//N
rowStd = Table[matRowStd[i, j] = mat[[j, i]]/rowTot[[j]],
{j,3}, {i,3}] // N
solColMat = {{0,0.5714,0.4545}, {0,0, 0}, {0.6666,0,0}};
solRowMat ={{0,0,0.5}, {0,0,0.5714},{0.5714,0,0}};
The above Code column-wise standardizes mat, denoted by colStd. Using the same matrix mat I also introduce a row-standardization rowStd. The standardization of the Code works just fine.
My purpose is to create two new matrices solColMat and solRowMat, which respectively select maximum element(s) from each column and from each row. Non-maximum elements are converted to zeros. The final matrices, solColMat and solRowMat, are given above for clarification purposes.
I would like to have your help.
Thanks.
2 Answers
rowStd = Normalize[#, Total] & /@ mat
{{1/10, 2/5, 1/2}, {1/7, 2/7, 4/7}, {4/7, 1/7, 2/7}}
colStd = Transpose[Normalize[#, Total] & /@ Transpose[mat]]
{{1/6, 4/7, 5/11}, {1/6, 2/7, 4/11}, {2/3, 1/7, 2/11}}
maxSelect = Map[Clip[#, {Max @ #, ∞}, {0, 0}] &];
solRowMat = maxSelect @ rowStd
{{0, 0, 1/2}, {0, 0, 4/7}, {4/7, 0, 0}}
solColMat = Transpose @ maxSelect @ Transpose @ colStd
{{0, 4/7, 5/11}, {0, 0, 0}, {2/3, 0, 0}}
Alternative ways to select the maximum from each row:
maxSelect2 = Map[# UnitStep[# - Max @ #]&];
maxSelect3 = Map[Threshold[#, {"LargestValues", 1}]&];
The last one is more flexible in that you can change 1 to k to take the largest k elements in each row and set the rest to 0.
-
$\\begingroup$ In the case of a matrix, say (100,100), I may have to choose not the maximum only but the largest two or three elements in each matrix. Would it be feasible in your
Codeto do so? $\\endgroup$ – Tugrul Temel 9 hours ago -
$\\begingroup$ Sorry that my explanation was missing an important piece of information, which is to exclude the numbers in the diagonal elements of
mat. The selection should only consider the off-diagonal elements inmat. $\\endgroup$ – Tugrul Temel 9 hours ago -
1$\\begingroup$ @Tugrul, for largest
kelements you can trymaxSelect3replacing1withk. $\\endgroup$ – kglr 9 hours ago -
1$\\begingroup$ You can multiply
rowStdwith1- IdentityMatrix[3]or subtract fromrowStat-Max[mat] IdentityMatrix[3]before usingmaxSelect(Similarly forcolStd.) $\\endgroup$ – kglr 9 hours ago -
$\\begingroup$ @kglr the
Thresholdthing is pretty handy, never used it before. So many functions are there to get used to :) By the way +1. $\\endgroup$ – PlatoManiac 9 hours ago
I will do something like this. Unitize is pretty useful here.
With[{max = Max@#}, max Unitize[#, max]] & /@ rowStd
{{0., 0., 0.5}, {0., 0., 0.571429}, {0.571429, 0., 0.}}
For the colums first Transpose to get to rows and then transpose back.
With[{max = Max@#}, max Unitize[#, max]] & /@ (Transpose@colStd) // Transpose
{{0., 0.571429, 0.454545}, {0., 0., 0.}, {0.666667, 0., 0.}}
Note
This works when the maximum entry (in each row or column) is positive. However the methods given by @kglr explore more general options and UnitStep will probably give speed benefits for large matrices.