Использование All in MapAt в Mathematica

У меня часто есть список пар, поскольку

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

и я хочу сделать что-то, например Rescale, ко всем вторым элементам, не касаясь первых элементов. Самый простой способ, который я знаю, это:

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

Должен быть способ сделать это без большого количества Transpose ing. Мое желание состоит в том, чтобы что-то вроде этого работать:

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

Но я понимаю, что MapAt использует Position -стандартные спецификации вместо спецификаций Part. Какое правильное решение?

Чтобы уточнить,

Я ищу решение, в котором мне не нужно повторять себя, поэтому мне не хватает двойного Transpose или double [[All,2]], потому что я считаю повторение сигнала, что я не делаю что-то самым простым способом. Однако, если исключение повторения требует введения промежуточных переменных или именованной функции или другой дополнительной сложности, возможно, решение транспонирования/нетранслирования уже правильно.

Ответ 1

Используйте Part:

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

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

data

Создайте копию, если вам нужно. (data2 = data, затем data2[[All, 2]] и т.д.)


Внесение изменений в мой ответ, чтобы не отставать от ruebenko's, это также можно сделать в функцию:

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

partReplace[data, Rescale, All, 2]

Это довольно общий дизайн.

Ответ 2

Я опаздываю на вечеринку, и то, что я опишу, будет очень мало отличаться от того, что @Mr. У мастера есть, поэтому лучше всего рассматривать этот ответ как дополнение к его решению. Мои частичные оправдания состоят в том, что вначале функция ниже упаковывает вещи немного по-другому и ближе к синтаксису самого MapAt, во-вторых, она немного более общая и имеет возможность использовать с функцией Listable, а в-третьих, я Я воспроизводил свое решение из прошлой темы Mathgroup именно по этому вопросу, которому больше двух лет, поэтому я не плагирую:)

Итак, вот функция:

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]; 

Это та же идея, что и @Mr. Используется мастер с этими отличиями: 1. Если спецификация не соответствует установленной форме, обычный MapAt будет использоваться автоматически 2. Не все функции Listable. Решение @Mr.Wizard предполагает, что либо функция Listable, либо мы хотим применить ее ко всему списку. В приведенном выше коде вы можете указать это с помощью опции MappedListable.

Я также возьму несколько примеров из моего ответа в вышеупомянутом потоке:

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}}

Тестирование в больших списках показывает, что использование Listability повышает производительность, хотя и не так резко:

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}

Это, скорее всего, потому что для вышеуказанной функции (#/10&), Map (которая используется внутри MapAt для параметра MappedListable->False (по умолчанию), была способна автоматически компилироваться. В приведенном ниже примере, разница более существенна:

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}

Дело в том, что, хотя f не был объявлен Listable, мы знаем, что его тело построено из функций Listable, и поэтому оно может быть применено ко всему списку, но OTOH не может быть автоматически скомпилирован Map. Обратите внимание, что добавление атрибута Listable к f было бы совершенно неправильным здесь и уничтожило бы цель, в результате чего MapAt будет медленным в обоих случаях.

Ответ 3

Как насчет

Transpose[{#[[All, 1]], Rescale[#[[All, 2]]]} &@data]

который возвращает то, что вы хотите (т.е. не меняет data)

Если не разрешено Transpose,

Thread[Join[{#[[All, 1]], Rescale[#[[All, 2]]]} &@data]]

работает.

EDIT: "Самая короткая" теперь является целью, лучше всего от меня до сих пор:

data\[LeftDoubleBracket]All, 2\[RightDoubleBracket] = Rescale[data[[All, 2]]]

на 80 символов, что совпадает с Mr.Wizard's... Итак, проголосуйте за его ответ.

Ответ 4

Вот еще один подход:

op[data_List, fun_] := 
 Join[data[[All, {1}]], fun[data[[All, {2}]]], 2]

op[data, Rescale]

Изменить 1:

Расширение от Mr.Wizard, которое не копирует его.

SetAttributes[partReplace, HoldFirst]
partReplace[dat_, func_, spec__] := dat[[spec]] = func[dat[[spec]]];

используется как

partReplace[data, Rescale, All, 2]

Изменить 2: Или как это

ReplacePart[data, {All, 2} -> Rescale[data[[All, 2]]]]

Ответ 5

Это сработало для меня и друга

In[128]:= m = {{x, sss, x}, {y, sss, y}}
Out[128]= {{2, sss, 2}, {y, sss, y}}

In[129]:= function[ins1_] := ToUpperCase[ins1];
fatmap[ins2_] := MapAt[function, ins2, 2];

In[131]:= Map[fatmap, m]
Out[131]= {{2, ToUpperCase[sss], 2}, {y, ToUpperCase[sss], y}}