<h2>使用<code>numpy</code>的解决方案</h2>
<p>对于这个解决方案,我将使用<code>numpy</code>:</p>
<pre><code>import numpy as np
</code></pre>
<h2>数据集</h2>
<h3>创建数据集</h3>
<p>OP<a href="https://stackoverflow.com/users/10077730/phteven">Phteven</a>很好地提供了要处理的数据集,但是由于到数据集的链接趋于消失,我还创建了一个函数来生成类似的曲线。你知道吗</p>
<pre><code>def polyval_points(n):
"""Return random points generated from polyval."""
x = np.linspace(-20, 20, num=n)
coef = np.random.normal(-3, 3, size=(5))
y = np.polyval(coef, x) * np.sin(x)
return x, y
</code></pre>
<h3>加载数据集</h3>
<pre><code>def dataset_points():
"""Return points loaded from dataset."""
y = np.loadtxt("data.csv", delimiter=',')
x = np.linspace(0, 1, num=len(y))
return x, y
</code></pre>
<h2>阐述要点</h2>
<h3>斜率卷积</h3>
<p>因为这些点是离散的,所以我们必须<em>平均</em>斜率。其中一种方法是通过统一内核。你知道吗</p>
<pre><code>def convolute_slopes(y, k=3):
"""Return slopes convoluted with an uniform kernel of size k."""
d2y = np.gradient(np.gradient(y))
return np.convolve(d2y, np.ones(k)/k, mode="same")
</code></pre>
<h3>获得抛物面</h3>
<p>现在,我们可以计算卷积斜率,确定它在何处切换方向,并选择那些平均斜率大于绝对平均值乘以一个描述抛物面“斜率”的系数的间隔。你知道吗</p>
<pre><code>def get_paraboloids(x, y, c=0.2):
"""Return list of points (x,y) that are part of paraboloids in given set.
x: np.ndarray of floats
y: np.ndarray of floats
c: slopyness coefficient
"""
slopes = convolute_slopes(y)
mean = np.mean(np.abs(slopes))
w = np.where(np.diff(slopes > 0) > 0)[0] + 1
w = np.insert(w, [0, len(w)], [0, len(x)])
return [(x[lower:upper], y[lower:upper])
for lower, upper in zip(w[:-1], w[1:])
if np.mean(slopes[lower:upper]) > mean * c]
</code></pre>
<h2>如何使用这个和可视化</h2>
<p>首先,我们加载数据集并生成更多数据:</p>
<pre><code>datasets = [dataset_points(), polyval_points(10000), polyval_points(10000)]
</code></pre>
<p>然后,迭代每个数据集:</p>
<pre><code>from matplotlib import pyplot as plt
plt.figure(figsize=(10 * len(datasets), 10))
for i, points in enumerate(datasets):
x, y = points
plt.subplot(1, len(datasets), i + 1)
plt.plot(x, y, linewidth=1)
for gx, gy in get_paraboloids(x, y):
plt.plot(gx, gy, linewidth=3)
plt.show()
</code></pre>
<h3>结果</h3>
<p><a href="https://i.stack.imgur.com/xgkWZ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xgkWZ.png" alt="Paraboloids"/></a></p>