Consider a relational table derived from survey data, where each column ("001-01" ...) represents a responder and each row ("MDQ1"...) a survey question.
To help intuition, response data is represented graphically by color-scaled disks, but the underlying data matrix is just a table of integers and bordered by the aforementioned string metadata in the first row and column.

A small submatrix is given here:
data = {{"ID", "MDQ1", "MDQ2", "MDQ3"}, {"001-01", 3, 2, 5}, {"002-01", 4, 1, 5}, {"003-01", 2, 2, 5}} Further, define a variable for the headers
ids = {"ID", "MDQ1", "MDQ2", "MDQ3"} To clean this data, the response values for a subset of questions, for example {"MDQ1", "MDQ3"} must be transformed, for example, by the function (6-#)&
(Note: in the figure I highlighted "MDQ1" and "MDQ5" - that's just for illustration)
I would prefer to use ReplacePart but afaik, pattern matching can only be applied to position index and not to the data values - but in this case the metadata (headers) is part of the data.
The alternative for this task is MapAt, but it requires the intermediate generation of the positional index and barely readable code:
MapAt[If[NumericQ[#], 6 - #, #] &, data, Flatten[Table[{i, First@First@Position[ids, #]}, {i, 2, Length@data}] & /@ {"MDQ1", "MDQ3"}, 1]] Is there a way to close the semantic gap between MapAt and ReplacePart and achieve more terse, more readable code?