Как вычесть конкретные элементы в списке, используя функциональное программирование в Mathematica? - PullRequest
6 голосов
/ 24 июня 2010

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

{{{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 $, взятых из базы данных FRED .

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

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

(изменение1 является значением2-значением1)

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

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

Ответы [ 5 ]

7 голосов
/ 24 июня 2010

У вас есть список пар {date, value}, так что если вы Transpose , у вас будет список из двух списков - первый список дат, а второй список соответствующих значений,Затем вы можете взять Различия значений, Prepend 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]]
3 голосов
/ 24 июня 2010

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

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

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

2 голосов
/ 24 июня 2010

Я рекомендую использовать 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 со списком.

НТН!

2 голосов
/ 24 июня 2010
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}

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

1 голос
/ 24 декабря 2011

Эту операцию также можно выполнить с 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}}
...