Как вычесть конкретные элементы в списке с помощью функционального программирования в 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}}