What is a good way of perfoming operations on specified columns of a table with many columns
myTable = Array[Subscript[a, Row[{##}]] &, {5, 10}];
MatrixForm @ myTable
functions = {foo, bar};
columns = {2, 5};
1. Part
assignment:
myTable[[All, columns]] = {foo@#, bar@#2} & @@@ myTable[[All, columns]];
myTable // MatrixForm
2. MapAt
myTable = Array[Subscript[a, Row[{##}]] &, {5, 10}];
myTable = Fold[MapAt[First@#2, #, {All, Last@#2}] &, myTable,
Transpose[{functions, columns}]];
myTable // MatrixForm
3. ReplacePart
myTable = Array[Subscript[a, Row[{##}]] &, {5, 10}];
myTable = ReplacePart[myTable,
MapThread[{i_, #} :> #2[myTable[[i, #]]] &, {columns, functions}]];
myTable // MatrixForm
4. MapIndexed
+ Association
myTable = Array[Subscript[a, Row[{##}]] &, {5, 10}];
asso = AssociationThread[columns, functions];
myTable = MapIndexed[asso[#2[[2]]]@# /. Missing[__] -> Identity &, myTable, {2}];
myTable // MatrixForm
5. Dataset
myTable = Array[Subscript[a, Row[{##}]] &, {5, 10}];
myTable = Normal @ Dataset[myTable][All, Thread[columns -> functions]];
myTable // MatrixForm
A little too long for a comment, and I have marked this as 'Community Wiki' (not an original contribution). In addtion, I think the Query
method should not be 'buried' in a comment.
Query
Sjoerd Smit has posted a neat method for applying a function to a matrix column using Query
.
Query[All, {1 -> (#+1/137&),3->(2 Pi# + 42&)}]@myTable2//TeXForm
$$ \left( \begin{array}{cccc} a_{11}+\frac{1}{137} & a_{12} & 2 \pi a_{13}+42 & a_{14} \\ a_{21}+\frac{1}{137} & a_{22} & 2 \pi a_{23}+42 & a_{24} \\ a_{31}+\frac{1}{137} & a_{32} & 2 \pi a_{33}+42 & a_{34} \\ a_{41}+\frac{1}{137} & a_{42} & 2 \pi a_{43}+42 & a_{44} \\ a_{51}+\frac{1}{137} & a_{52} & 2 \pi a_{53}+42 & a_{54} \\ a_{61}+\frac{1}{137} & a_{62} & 2 \pi a_{63}+42 & a_{64} \\ a_{71}+\frac{1}{137} & a_{72} & 2 \pi a_{73}+42 & a_{74} \\ a_{81}+\frac{1}{137} & a_{82} & 2 \pi a_{83}+42 & a_{84} \\ a_{91}+\frac{1}{137} & a_{92} & 2 \pi a_{93}+42 & a_{94} \\ a_{101}+\frac{1}{137} & a_{102} & 2 \pi a_{103}+42 & a_{104} \\ \end{array} \right) $$
Query[All, {1 -> foo, 3 -> bar, 6-> Sqrt}]@myTable//TeXForm
$$ \left( \begin{array}{cccccc} \text{foo}\left[a_{11}\right] & a_{12} & \text{bar}\left[a_{13}\right] & a_{14} & a_{15} & \sqrt{a_{16}} \\ \text{foo}\left[a_{21}\right] & a_{22} & \text{bar}\left[a_{23}\right] & a_{24} & a_{25} & \sqrt{a_{26}} \\ \text{foo}\left[a_{31}\right] & a_{32} & \text{bar}\left[a_{33}\right] & a_{34} & a_{35} & \sqrt{a_{36}} \\ \text{foo}\left[a_{41}\right] & a_{42} & \text{bar}\left[a_{43}\right] & a_{44} & a_{45} & \sqrt{a_{46}} \\ \text{foo}\left[a_{51}\right] & a_{52} & \text{bar}\left[a_{53}\right] & a_{54} & a_{55} & \sqrt{a_{56}} \\ \end{array} \right) $$
Query
(in this case) seems to be based on MapAt
'under the hood'
In[7]:=Query[All, {1 -> (#+ 137&),3->(2 Pi# + 42&)}]@myTable2x
Out[7]= MapAt[#1 + 137 & , {All, 1}][MapAt[2 Pi #1 + 42 & , {All, 3}][myTable2x]]
And for the lazy, the following doesn't seem too bad either:
myTable//MapAt[2 Pi # + 42 & , {All, 3}]// MapAt[# + 137 & , {All, 1}]
$$ \left( \begin{array}{cccccc} a_{11}+137 & a_{12} & 2 \pi a_{13}+42 & a_{14} & a_{15} & a_{16} \\ a_{21}+137 & a_{22} & 2 \pi a_{23}+42 & a_{24} & a_{25} & a_{26} \\ a_{31}+137 & a_{32} & 2 \pi a_{33}+42 & a_{34} & a_{35} & a_{36} \\ a_{41}+137 & a_{42} & 2 \pi a_{43}+42 & a_{44} & a_{45} & a_{46} \\ a_{51}+137 & a_{52} & 2 \pi a_{53}+42 & a_{54} & a_{55} & a_{56} \\ \end{array} \right) $$
Inner
Inner
is another possibility (see here)
myTable//Inner[Times,#,ConstantArray[1,Length@#[[1]]],{#1+1/137,#2,#3, 2 Pi #4+42, ##5}&]&//TeXForm
$$ \left( \begin{array}{cccccc} a_{11}+\frac{1}{137} & a_{12} & a_{13} & 2 \pi a_{14}+42 & a_{15} & a_{16} \\ a_{21}+\frac{1}{137} & a_{22} & a_{23} & 2 \pi a_{24}+42 & a_{25} & a_{26} \\ a_{31}+\frac{1}{137} & a_{32} & a_{33} & 2 \pi a_{34}+42 & a_{35} & a_{36} \\ a_{41}+\frac{1}{137} & a_{42} & a_{43} & 2 \pi a_{44}+42 & a_{45} & a_{46} \\ a_{51}+\frac{1}{137} & a_{52} & a_{53} & 2 \pi a_{54}+42 & a_{55} & a_{56} \\ \end{array} \right) $$
Related
Applying a function to every item in a column of a matrix
Matrices
myTable = Array[Subscript[a, Row[{##}]] &, {5, 6}];
myTable2 = Array[Subscript[a, Row[{##}]] &, {10, 4}];
kglr's ReplacePart
method is completely general, but I think in many situations writing the rules explicitly is easier and gives more readable code. So I would write:
data = Array[f, {4, 4}];
ReplacePart[data, {{r_, 1} :> data[[r, 1]] + 137, {r_, 3} :> 2 π data[[r, 3]]}]
{{137 + f[1, 1], f[1, 2], 2 π f[1, 3], f[1, 4]}, {137 + f[2, 1], f[2, 2], 2 π f[2, 3], f[2, 4]}, {137 + f[3, 1], f[3, 2], 2 π f[3, 3], f[3, 4]}, {137 + f[4, 1], f[4, 2], 2 π f[4, 3], f[4, 4]}}
I can see what my code does at a glance, but I can't do the with kglr's code. Of course, you may consider this more a reflection on my smarts than a valid critique of kglr's coding style.
Update
The following is added to address concerns raised by the Craig Carter in a comment to this answer.
It's pretty simple. Just change the column specs to the appropriate row specs. Like so:
ReplacePart[data, {{1, c_} :> data[[1, c]] + 137, {3, c_} :> 2 π data[[3, c]]}
{{137 + f[1, 1], 137 + f[1, 2], 137 + f[1, 3], 137 + f[1, 4]}, {f[2, 1], f[2, 2], f[2, 3], f[2, 4]}, {2 π f[3, 1], 2 π f[3, 2], 2 π f[3, 3], 2 π f[3, 4]}, {f[4, 1], f[4, 2], f[4, 3], f[4, 4]}}