Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using All in MapAt in Mathematica

I often have a list of pairs, as

data = {{0,0.0},{1,12.4},{2,14.6},{3,25.1}}

and I want to do something, for instance Rescale, to all of the second elements without touching the first elements. The neatest way I know is:

Transpose[MapAt[Rescale, Transpose[data], 2]]

There must be a way to do this without so much Transposeing. My wish is for something like this to work:

MapAt[Rescale, data, {All, 2}]

But my understanding is that MapAt takes Position-style specifications instead of Part-style specifications. What's the proper solution?

To clarify,

I'm seeking a solution where I don't have to repeat myself, so lacking double Transpose or double [[All,2]], because I consider repetition a signal I'm not doing something the easiest way. However, if eliminating the repetition requires the introduction of intermediate variables or a named function or other additional complexity, maybe the transpose/untranspose solution is already correct.

like image 430
ArgentoSapiens Avatar asked Dec 20 '11 18:12

ArgentoSapiens


People also ask

What does $Failed mean in Mathematica?

$Failed. Cell[BoxData["$Failed"], "Input", CellTags -> "$Failed_templates"] is a special symbol returned by certain functions when they cannot do what they were asked to do.

How do you write greater than or equal to in Mathematica?

x≥y can be entered as x >= y or x \[GreaterEqual]y. GreaterEqual gives True or False when its arguments are real numbers. GreaterEqual does some simplification when its arguments are not numbers. For exact numeric quantities, GreaterEqual internally uses numerical approximations to establish numerical ordering.

What is flatten in Mathematica?

Details. Flatten "unravels" lists, effectively just deleting inner braces. Flatten[list,n] effectively flattens the top level in list n times.


2 Answers

Use Part:

data = {{0, 0.0}, {1, 12.4}, {2, 14.6}, {3, 25.1}}

data[[All, 2]] = Rescale @ data[[All, 2]];

data

Create a copy first if you need to. (data2 = data then data2[[All, 2]] etc.)


Amending my answer to keep up with ruebenko's, this can be made into a function also:

partReplace[dat_, func_, spec__] :=
  Module[{a = dat},
    a[[spec]] = func @ a[[spec]];
    a
  ]

partReplace[data, Rescale, All, 2]

This is quite general is design.

like image 111
Mr.Wizard Avatar answered Oct 18 '22 17:10

Mr.Wizard


I am coming late to the party, and what I will describe will differ very little with what @Mr. Wizard has, so it is best to consider this answer as a complementary to his solution. My partial excuses are that first, the function below packages things a bit differently and closer to the syntax of MapAt itself, second, it is a bit more general and has an option to use with Listable function, and third, I am reproducing my solution from the past Mathgroup thread for exactly this question, which is more than 2 years old, so I am not plagiarizing :)

So, here is the function:

ClearAll[mapAt,MappedListable]; 
Protect[MappedListable]; 
Options[mapAt] = {MappedListable -> False}; 
mapAt[f_, expr_, {pseq : (All | _Integer) ..}, OptionsPattern[]] := 
  Module[{copy = expr}, 
    copy[[pseq]] = 
      If[TrueQ[OptionValue[MappedListable]] && Head[expr] === List, 
        f[copy[[pseq]]], 
        f /@ copy[[pseq]] 
      ]; 
    copy]; 
mapAt[f_, expr_, poslist_List] := MapAt[f, expr, poslist]; 

This is the same idea as what @Mr. Wizard used, with these differences: 1. In case when the spec is not of the prescribed form, regular MapAt will be used automatically 2. Not all functions are Listable. The solution of @Mr.Wizard assumes that either a function is Listable or we want to apply it to the entire list. In the above code, you can specify this by the MappedListable option.

I will also borrow a few examples from my answer in the above-mentioned thread:

In[18]:= mat=ConstantArray[1,{5,3}];

In[19]:= mapAt[#/10&,mat,{All,3}]
Out[19]= {{1,1,1/10},{1,1,1/10},{1,1,1/10},{1,1,1/10},{1,1,1/10}}

In[20]:= mapAt[#/10&,mat,{3,All}]
Out[20]= {{1,1,1},{1,1,1},{1/10,1/10,1/10},{1,1,1},{1,1,1}}

Testing on large lists shows that using Listability improves the performance, although not so dramatically here:

In[28]:= largemat=ConstantArray[1,{150000,15}];

In[29]:= mapAt[#/10&,largemat,{All,3}];//Timing
Out[29]= {0.203,Null}

In[30]:= mapAt[#/10&,largemat,{All,3},MappedListable->True];//Timing
Out[30]= {0.094,Null}

This is likely because for the above function (#/10&), Map (which is used internally in mapAt for the MappedListable->False (default) setting, was able to auto-compile. In the example below, the difference is more substantial:

ClearAll[f];
f[x_] := 2 x - 1;

In[54]:= mapAt[f,largemat,{All,3}];//Timing
Out[54]= {0.219,Null}

In[55]:= mapAt[f,largemat,{All,3},MappedListable->True];//Timing
Out[55]= {0.031,Null}

The point is that, while f was not declared Listable, we know that its body is built out of Listable functions, and thus it can be applied to the entire list - but OTOH it can not be auto-compiled by Map. Note that adding Listable attribute to f would have been completely wrong here and would destroy the purpose, leading to mapAt being slow in both cases.

like image 22
Leonid Shifrin Avatar answered Oct 18 '22 16:10

Leonid Shifrin