python - 如何在 x,y 点的二维数组中找到第一个极值?
问题描述
我有一组x_i, y_i
表示非双射映射的点(没有一对一的对应关系。见附图:
(不要注意第二行。它只是显示一个中心质量)。我试图找到它的第一个峰值(如您所见,它发现不正确)。代码如下。在这里,我按 Ox 轴对点进行排序,然后使用find_peaks
函数:
# sort points by X axis
aa = zip(x,y)
bb = sorted(aa, key=lambda x: (x[0], x[1]))
x,y = zip(*bb)
x = np.array(x)
y = np.array(y)
# find all peaks
peaks, props = find_peaks(y, prominence=0.01, height=0.4)
print('rmax candidates=', y[peaks])
rmax = y[peaks[0]] # first peak is not correct
我注意到这里的排序处理不正确。如果我只绘制y
数组,那么我会看到图片:
. 我们在哪里看到“带有非常锋利的牙齿的齿轮”。
因此,如何以最接近的方式对点进行排序(如果我可以设置起点)。对于人类来说,在图形上画一条线是一件容易的事,但是如何为计算机开发一种算法呢?我知道Online Digitizer中已经使用了类似的算法。可以很容易地从图形中提取点坐标。
也许你有更好的算法来找到第一个峰值?如果你有任何问题,请问我。
数据可以在这里找到:
解决方案
可以给出以下思路:
读取文件并将数据放入 2D NumPy 数组。
arr = []
with open(str(Path('example.csv'))) as csv_file:
reader = csv.reader(csv_file, delimiter=',')
for row in reader:
arr.append([float(row[0]),float(row[1])])
arr = np.array(arr)
由于数据是无序的,因此当我们随后连接点时,我们会观察到一个丑陋的图形。
fig0 = go.Figure(go.Scatter(x=arr[:,0],y=arr[:,1], mode='lines'))
fig0.show()
为了获得合适的图片,我们需要从某个起点对点进行排序,以便仅连接最近的点
arx, x0, xmin, xmax = sort_by_nearest(arr)
x = arx[:,0]
y = arx[:,1]
对数据进行排序后y
如下所示:
并且非双射行为消失了,我们可以使用函数轻松找到仅y
数据的第一个峰值。是从一个山峰到下一个山峰的最小下降和上升高度。因此,小的噪声峰值将被丢弃。负责一个参数,其中峰值将仅在以下区域中搜索find_peaks
prominence
height
y>height
peaks, props = find_peaks(y, prominence=0.01, height=0.4)
这里我们有几个候选人
print('rmax candidates=', y[peaks])
当然,我们拿第一个
rmax = y[peaks[0]]
x_rmax = x[peaks[0]] - x0
fig0 = go.Figure(go.Scatter(y=arx[:,1], mode='lines'))
fig0.show()
fig0 = go.Figure(go.Scatter(x=arx[:,0]-x0, y=arx[:,1], name='my_line', mode='lines'))
fig0.add_trace(go.Scatter(x=[x_rmax,x_rmax], y=[0,0.5], name='peak coord', mode='lines', line=dict(color='black', width=2, dash='dot')))
fig0.show()
让我们关注按邻居排序数据的算法。
import pandas as pd
import numpy as np
import plotly.graph_objects as go
import csv
from scipy.signal import find_peaks
import scipy.spatial.distance as ds
from pathlib import Path
搜索最近点的功能很棘手,我们需要以某种方式标记已经观察到的点以避免无限循环。我们只需通过大数字修改点坐标来完成数组的副本arr_full
def closest_point(arr_full, xi, yi, inds):
N = arr_full.shape[0]
arr_full[inds] = 1e+30
dist = (arr_full[:, 0] - xi)**2 + (arr_full[:, 1] - yi)**2
i_min = dist.argmin()
#returns an index of the nearest point and its coordinate
return i_min, arr_full[i_min][0], arr_full[i_min][1]
def sort_by_nearest(arr):
N = arr.shape[0]
nearest_point = [None]*N
#find initial point
xmin = min(arr[:,0])
xmax = max(arr[:,0])
# we copy the original array
arr_cut = np.copy(arr)
# the area in which we are 100% sure in absence of the starting point we flag by big value
arr_cut[arr[:,0] > 0.5*(xmin + xmax)] = 10e+30
iymin = arr_cut[:,1].argmin()
# the staring points are
x0, y0 = arr[iymin, 0], arr[iymin, 1]
# we initialize the sorted value nearest_point
nearest_point[0] = [arr[iymin,0],arr[iymin,1]]
print('Starting point:', x0, y0)
# we put in it the indices of visited points
observed = [iymin]
i_min = iymin
for i in range(1,N):
xi, yi = arr[i_min]
i_min, xip, yip = closest_point(arr, xi, yi, i_min)
nearest_point[i] = [xip, yip]
observed.append(i_min)
nearest_point = np.array(nearest_point)
return np.array(nearest_point), x0, xmin, xmax
推荐阅读
- javascript - 将 NaN 更改为 0
- javascript - 如何在重复条件渲染中优化代码?
- javascript - 加载 PDF base64 编码到 PDF.JS 的 viewer.js
- sql - 计算每个目的地的乘客
- kubernetes - 2 个共享 Redis 依赖的 Helm Charts
- c# - 为什么建议中间件在 ASP.NET Core 中异步?
- c# - 重复登录禁令问题(Selenium C#)
- reactjs - Redux 动作中的多种类型
- javascript - 在我的 Redux 应用程序中处理错误的代码中添加什么?
- popup - 如何使用 Leaflet 关闭多个弹出窗口?