【问题标题】:How to subtract specific elements in a list using functional programming in Mathematica?如何使用 Mathematica 中的函数式编程减去列表中的特定元素?
【发布时间】:2010-06-24 00:29:19
【问题描述】:

我有一个日期和值的列表,格式为:

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

对于那些好奇的人,这是从FRED database 中提取的美元与加元值的列表。

我想简单地从值 2 中减去 value1,然后创建一个新列表,其中包含以下形式的数据:

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

(其中 change1 为 value2-value1)

我知道必须有一种相对简单的方法来使用函数式编程来完成此操作,而不是使用索引变量和计数以及所有废话的 Do 或 While。我试图完成的方法必须相对稳健,因为我会自动从具有相同格式但不同时间间隔的源中提取数据集。如果我不必指定 ListPlot 日期间隔(如果我从列表中删除 dateInfo 会发生这种情况),那么重新绘制会容易得多。

我熟悉文档中心和非编程 Mathematica 功能。我一直在使用 Mathematica 学习编程,并且真的很想将这种能力扩展到函数式编程中,但是发现有关该主题的大多数资源都太难了。我觉得我正处于学习曲线的那个高峰,它即将点击到位,但现在我正在挣扎。至少,如果您有很好的函数式编程资源,我会非常乐意研究这些!任何帮助深表感谢!抱歉,如果是 TMI,但我相信你们中的许多人都有同样的感受。

【问题讨论】:

  • 您可能已经注意到,当您尝试保持前导 0 时,所有提供的解决方案都会有点尴尬,这在 AFAICT 数学上毫无意义。我认为宇宙正试图在那里告诉你一些事情......
  • 我知道前导 0 在数学上没有多大意义,但就表示而言,它更有意义。例如,如果在分析中使用 1971 作为基准年,那么从 1 月到 2 月的变化应该是 2 月到 1 月。如果该值显示为 2 月的变化,则演示文稿会更合乎逻辑,特别是因为我将绘制数据。

标签: list date functional-programming wolfram-mathematica


【解决方案1】:

您有一个 {date,value} 对列表,因此如果您 Transpose 您将有一个包含两个列表的列表——第一个是日期列表,第二个是对应值的列表。 然后,您可以取值中的Differences 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}}

将其封装成一个函数,感谢Janus 的想法:

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@@listApply[f, list] 的简写:

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

所以上面定义的taildiffs只是这个的一个简洁(也许是神秘的)版本:

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

【讨论】:

  • 所以,为了确保我在理解函数式表示法方面取得进展,sing 函数的工作方式如下:1) 数据被转置到两个列表中,#1 和#2。 2) 这两个列表以下列方式应用; #1 被单独留下,#2 被差分并以 0 开头。 3) #1 和修改后的 #2 然后转置回单个列表。对吗?
  • 没错。说得好。您应该更一般地知道,例如, foo[#2,#1]& 是两个参数的纯函数,它在这两个参数上调用 foo(以相反的顺序)。其他花哨的语法还有@ 和@@。让我在答案中附加一些内容来解释这些......
【解决方案2】:

除了你想要初始的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}}

【讨论】:

    【解决方案3】:

    我建议为此使用ReapSow

    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 的输出如果你不熟悉的话会有点复杂,但是ReapSow 基本上给了你一种将东西“播种”到列表中然后在之后“收获”它们的方法评估。例如,ReapSow 比将 AppendTo 与列表一起使用要高效得多。

    HTH!

    【讨论】:

      【解决方案4】:
      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}
      

      确实不适合序列,因此您可以手动将其添加到列表中

      【讨论】:

        【解决方案5】:

        这个操作也可以用PartSet来完成:

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

        【讨论】:

          猜你喜欢
          • 2021-10-18
          • 2022-01-14
          • 1970-01-01
          • 2019-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多