Как вычесть конкретные элементы в списке с помощью функционального программирования в Mathematica?

у меня есть список дат и значений в формате:

{{{dateInfo1},value1},{{dateInfo2},value2},...,{{dateInfoN},valueN}}

С некоторыми фактическими датами и значениями:

{{{1971, 1, 31, 0, 0, 0.}, 1.0118}, {{1971, 2, 28, 0, 0, 0}, 1.0075},
 ..., {{2010, 5, 31, 0, 0, 0.}, 1.0403}}

для тех, кто любопытен, это список нас против значений CAD $, вытащенных из базе Фред.

Я хотел бы просто вычесть из значение1 значение 2, а затем создать новый список с данными в виде:

 {{{dateInfo1},0},{{dateInfo2},change1},...,{{dateInfoN},changeN-1}}

(С change1, являющимся value2-value1)

Я знаю должен быть относительно простой способ сделать это с помощью функционального программирования, а не делать или в то время как с индексными переменными и подсчетом и всей этой ерундой. Метод, который я пытаюсь выполнить, должен быть относительно надежным, потому что я автоматически вытягиваю наборы данных из источников с одинаковым форматированием, но разными временными интервалами. Реплоттинг тогда намного проще, если мне не нужно указывать интервалы дат ListPlot (что произойдет, если я удалю dateInfo из список.)

Я знаком с Центром документации и возможностями непрограммирования Mathematica. Я изучал программирование с Mathematica и действительно хочу расширить эту способность в функциональное программирование, но обнаружил, что большинство ресурсов по этой теме слишком сложно. Я чувствую, что нахожусь на том горбе в кривой обучения, где он собирается щелкнуть на месте, но прямо сейчас я борюсь. По крайней мере, если у вас есть хороший источник по функциональному программированию я я был бы более чем счастлив заглянуть в них! Любая помощь очень ценится! Извините, если это TMI, но я уверен, что многие из вас чувствовали то же самое.

5 ответов


у вас есть список пар {дата, значение}, поэтому, если вы транспонировать что у вас будет список из двух списков-первый список дат и второй список соответствующих значений. Затем вы можете взять различия ценностей, добавить 0, а затем транспонировать снова, чтобы вернуться к списку пар.

в коде

data = {{{1971,1,31,0,0,0}, 1.0118}, 
        {{1971,2,28,0,0,0}, 1.0075}, 
        {{2010,5,31,0,0,0}, 1.0403}}
{dates, values} = Transpose[data];
diffs = Prepend[Differences[values], 0];
answer = Transpose[{dates, diffs}]

возвращает:

{{{1971,1,31,0,0,0}, 0}, 
 {{1971,2,28,0,0,0}, -0.0043}, 
 {{2010,5,31,0,0,0}, 0.0328}}

чтобы обернуть это в одну функцию, с спасибо Янус идея:

taildiffs[data_]:= 
  Transpose @ {#1, Prepend[Differences[#2], 0]}& @@ Transpose@data  

отметим, что ... #1 ... #2 ... & конструкция является чистой функцией:

http://reference.wolfram.com/mathematica/ref/Function.html

на f@x синтаксис-это просто сокращение для f[x].

наконец, f@@list сокращенно от Apply[f, list]:

http://reference.wolfram.com/mathematica/ref/Apply.html

так taildiffs как определено выше это просто краткая (возможно, загадочная) версия этого:

Apply[Transpose[Function[{x,y}, {x, Prepend[Differences[y],0]}], Transpose[data]]

за исключением того, что вы хотите начальном 0, вы ищете Differences. Чтобы оставить даты в покое, перенесите и примените только ко второй части, например:

TailDifferences[data_]:=
  Transpose@Apply[{#1,{0}~Join~Differences[#2]}&,Transpose[data]]

применение этого к вашим данным дает что-то вроде этого:

data={{{dateInfo1},value1},{{dateInfo2},value2},{{dateInfo3},value3}};
TailDifferences[data]

{{{dateInfo1},0},{{dateInfo2},-value1+value2},{{dateInfo3},-value2+value3}}

я рекомендую использовать Reap и Sow для этого:

In[13]:= lis= {{{1971,1,31,0,0,0.},1.0118},{{1971,2,28,0,0,0},1.0075},{{2010,5,31,0,0,0.},1.0403}};

In[14]:= First@Last@Reap[
   (* set first previous to first value to get 0 *)
   Module[{prev = lis[[1, 2]]},
    Scan[
     (
       (* First[#] = date, Last[#] = value *)
       Sow[{First[#], Last[#] - prev}];
       (* set new previous to this value *)
       prev = Last[#]
       ) &,
     lis]]
   ]

Out[14]= {{{1971, 1, 31, 0, 0, 0.}, 0.},
  {{1971, 2, 28, 0, 0, 0}, -0.0043},
  {{2010, 5, 31, 0, 0, 0.}, 0.0328}}

выход Reap немного сложно, если вы не знакомы с ним, но Reap и Sow в основном дать вам способ "посеять" вещи в списки, а затем" пожинать " их после оценки. Reap и Sow намного эффективнее, чем использование AppendTo список, например.

HTH!


data = {{{dateInfo1}, value1}, {{dateInfo2}, value2}, {{dateInfo3}, value3}}

Map[{#[[2,1]], #[[2,2]] - #[[1,2]]}&, {Take[data, Length[data] - 1], Rest[data]}]

дает

{{{dateInfo2}, -value1 + value2}, {{dateInfo3}, -value2 + value3}}

этот первый элемент в вашем списке результатов

{{dateInfo1},0}

на самом деле не вписывается в последовательность, поэтому вы можете вручную добавить его в список


эта операция также может быть выполнена с Part и Set:

data = {{{1971,1,31,0,0,0}, 1.0118}, 
        {{1971,2,28,0,0,0}, 1.0075}, 
        {{2010,5,31,0,0,0}, 1.0403}};

Module[{a = data},
  a[[2 ;;, 2]] = Differences[a[[All, 2]]];
  a[[1, 2]] = 0;
  a
]
{{{1971, 1, 31, 0, 0, 0}, 0},
 {{1971, 2, 28, 0, 0, 0}, -0.0043},
 {{2010, 5, 31, 0, 0, 0}, 0.0328}}