使用PatternSequence和Mathematica中的Case来查找峰值

Arg*_*ens 5 design-patterns wolfram-mathematica

给定坐标对

data = {{1, 0}, {2, 0}, {3, 1}, {4, 2}, {5, 1}, 
        {6, 2}, {7, 3}, {8, 4}, {9, 3}, {10, 2}}
Run Code Online (Sandbox Code Playgroud)

我想提取山峰和山谷,因此:

{{4, 2}, {5, 1}, {8, 4}}
Run Code Online (Sandbox Code Playgroud)

我目前的解决方案是这种笨拙:

Cases[
 Partition[data, 3, 1],
 {{ta_, a_}, {tb_, b_}, {tc_, c_}} /; Or[a < b > c, a > b < c] :> {tb, b}
]
Run Code Online (Sandbox Code Playgroud)

您可以看到,通过使用三倍大小的数据集开始Partition.我认为可以使用CasesPatternSequence提取这些信息,但这种尝试不起作用:

Cases[
 data,
 ({___, PatternSequence[{_, a_}, {t_, b_}, {_, c_}], ___} 
         /; Or[a < b > c, a > b < c]) :> {t, b}
]
Run Code Online (Sandbox Code Playgroud)

产量{}.

我不认为该模式有什么问题,因为它适用于ReplaceAll:

data /. ({___, PatternSequence[{_, a_}, {t_, b_}, {_, c_}], ___} 
             /; Or[a < b > c, a > b < c]) :> {t, b}
Run Code Online (Sandbox Code Playgroud)

这给出了正确的第一个峰值{4, 2}.这里发生了什么?

Hei*_*ike 6

失败尝试不起作用的原因之一是Cases默认情况下会在表达式的第1级上查找匹配项.由于你在0级寻找比赛,你需要做类似的事情

Cases[
 data,
 {___, {_, a_}, {t_, b_}, {_, c_}, ___} /; Or[a < b > c, a > b < c] :> {t, b}, 
 {0}
]
Run Code Online (Sandbox Code Playgroud)

但是,这仅{4,2}作为解决方案返回,因此它仍然不是您正在寻找的.要查找所有匹配而不进行分区,您可以执行类似的操作

ReplaceList[data, ({___, {_, a_}, {t_, b_}, {_, c_}, ___} /; 
    Or[a < b > c, a > b < c]) :> {t, b}]
Run Code Online (Sandbox Code Playgroud)

返回

{{4, 2}, {5, 1}, {8, 4}}
Run Code Online (Sandbox Code Playgroud)


Dan*_*lau 5

你的"笨拙"解决方案相当快,因为​​它严重限制了所看到的内容.

这是一个例子.

m = 10^4;
n = 10^6;

ll = Transpose[{Range[n], RandomInteger[m, n]}];

In[266]:= 
Timing[extrema = 
    Cases[Partition[ll, 3, 
      1], {{ta_, a_}, {tb_, b_}, {tc_, c_}} /; 
       Or[a < b > c, a > b < c] :> {tb, b}];][[1]]

Out[266]= 3.88

In[267]:= Length[extrema]

Out[267]= 666463
Run Code Online (Sandbox Code Playgroud)

这似乎比使用替换规则更快.

更快的是创建差异产品的标志表.然后选择不在列表末端对应于符号产品1的条目.

In[268]:= Timing[ordinates = ll[[All, 2]];
  signs = 
   Table[Sign[(ordinates[[j + 1]] - 
        ordinates[[j]])*(ordinates[[j - 1]] - ordinates[[j]])], {j, 2,
      Length[ll] - 1}];
  extrema2 = Pick[ll[[2 ;; -2]], signs, 1];][[1]]

Out[268]= 0.23

In[269]:= extrema2 === extrema

Out[269]= True
Run Code Online (Sandbox Code Playgroud)

在这些方法中不考虑处理连续的等宽坐标.这样做需要更多的工作,因为必须考虑大于三个连续元素的邻域.(我的拼写检查员要我在"邻居"的中间音节添加"你".我的拼写检查员必须认为我们在加拿大.)

Daniel Lichtblau