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
.我认为可以使用Cases
和PatternSequence
提取这些信息,但这种尝试不起作用:
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}
.这里发生了什么?
失败尝试不起作用的原因之一是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)
你的"笨拙"解决方案相当快,因为它严重限制了所看到的内容.
这是一个例子.
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