scipy.interpolate.UnivariateSpline无论参数如何都不平滑

时间:2012-01-03 22:50:28

标签: python scipy splines

我无法获得scipy.interpolate.UnivariateSpline在插值时使用任何平滑。基于function's page以及一些previous posts,我认为它应该提供s参数的平滑。

这是我的代码:

# Imports
import scipy
import pylab

# Set up and plot actual data
x = [0, 5024.2059124920379, 7933.1645067836089, 7990.4664106277542, 9879.9717114947653, 13738.60563208926, 15113.277958924193]
y = [0.0, 3072.5653360000988, 5477.2689107965398, 5851.6866463790966, 6056.3852496014106, 7895.2332350173638, 9154.2956175610598]
pylab.plot(x, y, "o", label="Actual")

# Plot estimates using splines with a range of degrees
for k in range(1, 4):
    mySpline = scipy.interpolate.UnivariateSpline(x=x, y=y, k=k, s=2)
    xi = range(0, 15100, 20)
    yi = mySpline(xi)
    pylab.plot(xi, yi, label="Predicted k=%d" % k)

# Show the plot
pylab.grid(True)
pylab.xticks(rotation=45)
pylab.legend( loc="lower right" )
pylab.show()

结果如下:

Splines without smoothing

我尝试了一系列s值(0.01,0.1,1,2,5,50),以及显式权重,设置为相同的事物(1.0)或随机化。我仍然无法进行任何平滑,并且结的数量始终与数据点的数量相同。特别是,我正在寻找像第4点(7990.4664106277542,5851.6866463790966)那样的异常值来平滑。

是因为我没有足够的数据吗?如果是这样,是否有类似的样条函数或聚类技术可用于实现这几个数据点的平滑?

4 个答案:

答案 0 :(得分:11)

简短回答:您需要更仔细地选择s的值。

UnivariateSpline的文档指出:

Positive smoothing factor used to choose the number of knots. Number of 
knots will be increased until the     smoothing condition is satisfied:
sum((w[i]*(y[i]-s(x[i])))**2,axis=0) <= s

从这一点可以推断出,如果你没有传递明确的权重,平滑的“合理”值大约是s = m * v,其中m是数据点的数量,{{1}数据的方差。在这种情况下,v

编辑s_good ~ 5e7的合理值当然也取决于数据中的噪音水平。文档似乎建议在s范围内选择s,其中(m - sqrt(2*m)) * std**2 <= s <= (m + sqrt(2*m)) * std**2是与您想要平滑的“噪音”相关联的标准偏差。

答案 1 :(得分:2)

@ Zhenya在数据点之间手动设置节点的答案太粗糙,无法在噪声数据中提供良好的结果,而没有选择如何应用此技术。然而,受他/她的建议的启发,我在scikit-learn包中获得了Mean-Shift clustering的成功。它执行群集计数的自动确定,并且似乎做了相当好的平滑工作(实际上非​​常流畅)。

# Imports
import numpy
import pylab
import scipy
import sklearn.cluster

# Set up original data - note that it's monotonically increasing by X value!
data = {}
data['original'] = {}
data['original']['x'] = [0, 5024.2059124920379, 7933.1645067836089, 7990.4664106277542, 9879.9717114947653, 13738.60563208926, 15113.277958924193]
data['original']['y'] = [0.0, 3072.5653360000988, 5477.2689107965398, 5851.6866463790966, 6056.3852496014106, 7895.2332350173638, 9154.2956175610598]

# Cluster data, sort it and and save
inputNumpy = numpy.array([[data['original']['x'][i], data['original']['y'][i]] for i in range(0, len(data['original']['x']))])
meanShift = sklearn.cluster.MeanShift()
meanShift.fit(inputNumpy)
clusteredData = [[pair[0], pair[1]] for pair in meanShift.cluster_centers_]
clusteredData.sort(lambda pair1, pair2: cmp(pair1[0],pair2[0]))
data['clustered'] = {}
data['clustered']['x'] = [pair[0] for pair in clusteredData]
data['clustered']['y'] = [pair[1] for pair in clusteredData]

# Build a spline using the clustered data and predict
mySpline = scipy.interpolate.UnivariateSpline(x=data['clustered']['x'], y=data['clustered']['y'], k=1)
xi = range(0, round(max(data['original']['x']), -3) + 3000, 20)
yi = mySpline(xi)

# Plot the datapoints
pylab.plot(data['clustered']['x'], data['clustered']['y'], "D", label="Datapoints (%s)" % 'clustered')
pylab.plot(xi, yi, label="Predicted (%s)" %  'clustered')
pylab.plot(data['original']['x'], data['original']['y'], "o", label="Datapoints (%s)" % 'original')

# Show the plot
pylab.grid(True)
pylab.xticks(rotation=45)
pylab.legend( loc="lower right" )
pylab.show()

enter image description here

答案 2 :(得分:1)

虽然我不知道有任何库会为你做这件事,但我会尝试更多的DIY方法:我从制作带有原点数据点之间的节点的样条开始, xy。在你的特定例子中,在第4点和第5点之间有一个结点应该可以解决问题,因为它会删除x=8000附近的巨大导数。

答案 3 :(得分:0)

我无法运行BigChef的答案,这是一个适用于python 3.6的变体:

# Imports
import pylab
import scipy
import sklearn.cluster

# Set up original data - note that it's monotonically increasing by X value!
data = {}
data['original'] = {}
data['original']['x'] = [0, 5024.2059124920379, 7933.1645067836089, 7990.4664106277542, 9879.9717114947653, 13738.60563208926, 15113.277958924193]
data['original']['y'] = [0.0, 3072.5653360000988, 5477.2689107965398, 5851.6866463790966, 6056.3852496014106, 7895.2332350173638, 9154.2956175610598]

# Cluster data, sort it and and save
import numpy
inputNumpy = numpy.array([[data['original']['x'][i], data['original']['y'][i]] for i in range(0, len(data['original']['x']))])
meanShift = sklearn.cluster.MeanShift()
meanShift.fit(inputNumpy)
clusteredData = [[pair[0], pair[1]] for pair in meanShift.cluster_centers_]

clusteredData.sort(key=lambda li: li[0])
data['clustered'] = {}
data['clustered']['x'] = [pair[0] for pair in clusteredData]
data['clustered']['y'] = [pair[1] for pair in clusteredData]

# Build a spline using the clustered data and predict
mySpline = scipy.interpolate.UnivariateSpline(x=data['clustered']['x'], y=data['clustered']['y'], k=1)
xi = range(0, int(round(max(data['original']['x']), -3)) + 3000, 20)
yi = mySpline(xi)

# Plot the datapoints
pylab.plot(data['clustered']['x'], data['clustered']['y'], "D", label="Datapoints (%s)" % 'clustered')
pylab.plot(xi, yi, label="Predicted (%s)" %  'clustered')
pylab.plot(data['original']['x'], data['original']['y'], "o", label="Datapoints (%s)" % 'original')

# Show the plot
pylab.grid(True)
pylab.xticks(rotation=45)
pylab.show()