如果我有一个像这样的数字列表:
10,9,8,8,9,7,6,5,4,6,7,8,11,10,12,14,16,20,30,29,28,29,27,25,20,18,15,10,8,5,4,1
我想获得以下数字(符合此示例):10,4,30,1
是否可以编写一个能够获得这些极端值的函数?
这些数字是图表的值,我希望获得图表的峰值。
答案 0 :(得分:5)
我没有测试过这么多,并且它不适用于少于3点的任何东西,但这应该给你一个很好的起点。
<?php
$array = array(10,9,8,8,9,7,6,5,4,6,7,8,11,10,12,14,16,20,30,29,28,29,27,25,20,18,15,10,8,5,4,1);
$extremes = array();
$last = null;
$num = count($array);
for($i=0;$i<$num - 1;$i++) {
$curr = $array[$i];
if($last === null) {
$extremes[] = $curr;
$last = $curr;
continue;
}
//min
if($last > $curr && $curr < $array[$i + 1]) {
$extremes[] = $curr;
}
//maxes
else if ($last < $curr && $curr > $array[$i + 1]) {
$extremes[] = $curr;
}
if($last != $curr && $curr != $array[$i + 1]) {
$last = $curr;
}
}
//add last point
$extremes[] = $array[$num - 1];
print_r($extremes);
给你结果(你错过了列表中的一对):
Array
(
[0] => 10
[1] => 8
[2] => 9
[3] => 4
[4] => 11
[5] => 10
[6] => 30
[7] => 28
[8] => 29
[9] => 1
)
如果你想让它与列表完全一样,你必须对数据应用一些平滑处理,或者对检测采用一些容差。
答案 1 :(得分:3)
用于识别局部极值的一阶导数检验的变体,识别δ从一个间隔到下一个间隔交替标记的点。如果delta从正变为负,这些点将是最大值,如果delta从负变为正,则这些点将是最小值,但对于您的使用似乎并不重要。此外,抛出终点因为此测试的间隔被认为是开放的,您似乎希望将它们包括在内。
<?php
define('MSB_MASK', (int)(PHP_INT_MAX + 1));
$points = array(0, 0, 1, 0, -1, -2, -2, -3, -4, -3, 0, 1);
$extrema = getExtrema($points);
function getExtrema($points) {
$extrema = array($points[0]);
$limit= count($points)-2;
for ($i = 0; $i < $limit; ++$i) {
$deltai = $points[$i+1]-$points[$i];
$deltaiplus1 = $points[$i+2]-$points[$i+1];
if (($deltai ^ $deltaiplus1) & MSB_MASK)
$extrema[] = $points[$i+1];
}
$extrema[] = $points[$limit+1];
return $extrema;
}
?>
注意:我在ideone.com上测试了一下,它有效,但它可能有未被发现的问题。这个 也适用于浮点数。
信用:这是每个微积分I教科书的第一个衍生测试,仅适用于离散数学。我们将每个点都视为关键点,因为我们不知道图的功能。
编辑:在查看wolframalpha上的数据图之后,我想也许您只是在关闭的时间间隔内寻找全局最大值和最小值,加上结束点?如果是这样,只需使用简单的内容,例如max($points)
和min($points)
。
编辑:我以前从未有过使用xor的好机会!
答案 2 :(得分:2)
我的类似于jprofitt's
但是我把它们分成了山峰和山谷,所以我可以用它做更多的东西。
我认为他的循环比我的循环要干净得多,但我只是想为自己测试一下 不要判断我 ee ee e
这个脚本只是绘制出点并选择峰和谷,分别给它们分别为绿色和红色。将其视为视觉辅助。 :P
<?php
$plot = array(10,9,8,8,9,7,6,5,4,6,7,8,11,10,12,14,16,20,30,29,28,29,27,25,20,18,15,10,8,5,4,1);
$res = local_extremes($plot);
function local_extremes(array $array){
$peaks = array();
$valleys = array();
$peak_keys = array();
$valley_keys = array();
for($i = 0; $i < count($array); $i++){
$more_than_last = $array[$i] > $array[$i-1];
$more_than_next = $array[$i] > $array[$i+1];
$next_is_equal = $array[$i] == $array[$i+1];
if($next_is_equal) continue;
if($i == 0){
if($more_than_next){
$peaks[] = $array[$i];
$peak_keys[] = $i;
}else{
$valleys[] = $array[$i];
$valley_keys[] = $i;
}
}elseif($i == (count($array)-1)){
if($more_than_last){
$peaks[] = $array[$i];
$peak_keys[] = $i;
}else{
$valleys[] = $array[$i];
$valley_keys[] = $i;
}
}else{
if($more_than_last && $more_than_next){
$peaks[] = $array[$i];
$peak_keys[] = $i;
}elseif(!$more_than_last && !$more_than_next){
$valleys[] = $array[$i];
$valley_keys[] = $i;
}
}
}
return array("peaks" => $peaks, "valleys" => $valleys, "peak_keys" => $peak_keys, "valley_keys" => $valley_keys);
}
?>
<style type="text/css">
.container{
position: absolute;
}
.point{
position: absolute;
width: 4px;
height: 4px;
background: black;
}
.extreme{
position: absolute;
top: 5px;
}
.extr_low{
background: red;
}
.extr_high{
background: green;
}
</style>
<?php
//Plot
echo "<div class='container'>";
foreach($plot as $key => $point){
$left = ($key*10);
$top = 400 - ($point*10);
if(in_array($key, $res['peak_keys']) || in_array($key, $res['valley_keys'])){
$extreme = "<div class='extreme'>$point</div>";
}else{
$extreme = "";
}
if(in_array($key, $res['peak_keys'])){
$xc = "extr_high";
}elseif(in_array($key, $res['valley_keys'])){
$xc = "extr_low";
}else{
$xc = "";
}
echo "<div class='point $xc' style='left: ".$left."px; top: ".$top."px;'>$extreme</div>";
}
echo "</div>";
?>
<table>
<tr>
<th> </th>
<th>Valley</th>
<th>Peak</th>
</tr>
<tr>
<th>Lowest</th>
<td><?php echo min($res['valleys']); ?></td>
<td><?php echo min($res['peaks']); ?></td>
</tr>
<tr>
<th>Highest</th>
<td><?php echo max($res['valleys']); ?></td>
<td><?php echo max($res['peaks']); ?></td>
</tr>
</table>
答案 3 :(得分:1)
是的,对于行中的每个数字,您将它与边数进行比较,然后得到它(您需要的数字小于数字之前和之后)。然后添加数字的第一个和最后一个数字,它是完整的。
我希望它是一些排序数组。
答案 4 :(得分:1)
这是执行此操作的伪代码
输入:listOfNumbers
//Handle exceptional cases
if listOfNumbers.length == 0
return []
if listOfNumbers.length == 1
return [listOfNumbers[0]]
//Pre-condition listOfNumbers.length > 1
extremes = emptyList
lastNumber = listOfNumbers[0]
isIncreasing = listOfNumbers[0] < listOfNumbers[1]
extremes.push(listOfNumbers[0])
foreach number in listOfNumbers[1...listOfNumbers.length]
if(isIncreasing AND lastNumber > number)
extremes.push(lastNumber)
isIncreasing = false
if(NOT isIncreasing AND lastNumber < number)
extremes.push(lastNumber)
isIncreasing = true
extremes.push(listOfNumbers.length-1)
return extremes
我认为这样做会有,尽管我没有对此进行过测试。
答案 5 :(得分:0)
从数字数组中获取第一个和最后一个数字,然后对数组进行排序,并获取与您的上一个结果不同的第一个和最后一个数字。你将得到一个像你的例子的结果。