scipy UnivariateSpline在绘制时始终返回线性样条

时间:2018-07-12 23:20:53

标签: python matplotlib scipy spline timeserieschart

我有以下一组数据(pandas.DataFrame),我想使用它们来填充scipy.interpolate.UnivariateSpline。我们将数据称为data

Date
2018-04-02 09:00:00     16249
2018-04-02 10:00:00     45473
2018-04-02 11:00:00     32050
2018-04-02 12:00:00     35898
2018-04-02 13:00:00     21577
2018-04-02 14:00:00     30545
2018-04-02 15:00:00     60925
2018-04-02 16:00:00     47124
2018-04-03 09:00:00     18534
2018-04-03 10:00:00     36064
2018-04-03 11:00:00     32387
2018-04-03 12:00:00     15903
2018-04-03 13:00:00     22291
2018-04-03 14:00:00     26367
2018-04-03 15:00:00     66269
2018-04-03 16:00:00     38478
2018-04-04 09:00:00     15803
2018-04-04 10:00:00     22511
2018-04-04 11:00:00     33123
2018-04-04 12:00:00     21000
2018-04-04 13:00:00     23132
2018-04-04 14:00:00     39270
2018-04-04 15:00:00    102544
2018-04-04 16:00:00    143421
2018-04-04 17:00:00       200
2018-04-05 09:00:00     23377
2018-04-05 10:00:00     52089
2018-04-05 11:00:00     99298
2018-04-05 12:00:00     24627
2018-04-05 13:00:00     33467
2018-04-05 14:00:00     26498
2018-04-05 15:00:00    114794
2018-04-05 16:00:00     44904
2018-04-06 09:00:00     12180
2018-04-06 10:00:00     41658
2018-04-06 11:00:00     64066
2018-04-06 12:00:00     12517
2018-04-06 13:00:00     12610
2018-04-06 14:00:00     43544
2018-04-06 15:00:00     65533
2018-04-06 16:00:00    123885
2018-04-09 09:00:00     13425
2018-04-09 10:00:00     38354
2018-04-09 11:00:00     59491
2018-04-09 12:00:00     21402
2018-04-09 13:00:00     24550
2018-04-09 14:00:00     25189
2018-04-09 15:00:00     67751
2018-04-09 16:00:00     16071
2018-04-10 09:00:00     35587
2018-04-10 10:00:00     58667
2018-04-10 11:00:00     41831
2018-04-10 12:00:00     35196
2018-04-10 13:00:00     22611
2018-04-10 14:00:00     23070
2018-04-10 15:00:00     40819
2018-04-10 16:00:00     20337
2018-04-11 09:00:00      7962
2018-04-11 10:00:00     23982
2018-04-11 11:00:00     21794
2018-04-11 12:00:00     16835
2018-04-11 13:00:00     16821
2018-04-11 14:00:00     13270
2018-04-11 15:00:00     34954
2018-04-11 16:00:00     15772
2018-04-12 09:00:00      8587
2018-04-12 10:00:00     47950
2018-04-12 11:00:00     24742
2018-04-12 12:00:00     16743
2018-04-12 13:00:00     21917
2018-04-12 14:00:00     43272
2018-04-12 15:00:00     50630
2018-04-12 16:00:00    104656
2018-04-13 09:00:00     15282
2018-04-13 10:00:00     30304
2018-04-13 11:00:00     65737
2018-04-13 12:00:00     17467
2018-04-13 13:00:00     10439
2018-04-13 14:00:00     19836
2018-04-13 15:00:00     52051
2018-04-13 16:00:00     99462

到目前为止,我所做的是:

import matplotlib.pyplot as plt
import numpy as np
import scipy.interpolate as interp

x = [i for i in range(1, data.size+1)]  # this gives x as an array from 1 to 82.

spl = interp.UnivariateSpline(x, data.values, s=0.5)
xx = np.linspace(min(x), max(x), 1000)  # 1000 is an arbitrary number here.
plt.plot(x, data.values, 'bo')
plt.plot(xx, spl(xx), 'r')
plt.show()

# the plot is below and it seems to be very linear and does not look like a cubic spline at all. Cubic Spline is the default.

enter image description here

当我对spl运行x时,其他的保持不变,即:

plt.plot(x, spl(x), 'r')

我得到以下消息:

唯一的不同是y轴最高为14,000,这似乎意味着先前的图显示了一定程度的曲率。 (还是没有?)

enter image description here

我不确定我在这里缺少什么,但我显然错过了一些东西。我一般对spline适应python还是很陌生。

您能告诉我如何正确地使样条曲线适合上面的时间序列吗?

编辑

根据您的评论,我想补充一点情节,以期对自己有所解释。我并不是真的说它是线性的,但我找不到更好的词。为了说明,

xxx = [10,20,40,60,80]
plt(x, data.values, 'bo')
plt(xx, sp(xx), 'r')

plt.show()

在我看来,下面的情节看起来相当线性。我猜想,也许我的问题应该是scipy.UnivariateSpline到底如何运作?

它仅显示在我们提供的点上评估的值的曲线图(例如,对于该曲线图是xxx)?

enter image description here

我期望曲线更加平滑,并显示出不错的曲率。 this问题的答案显示了我所期望的情节;它看起来更像是分段三次函数生成的图,而对我而言,我的图看起来是线性的(如果更合适,则为一阶)。

1 个答案:

答案 0 :(得分:1)

您拥有的数据集看起来更像Rexthor, the dog-bearer,而不是平滑曲线可以遵循的数据集。您对SciPy没问题;您的数据有问题。

通过增加参数s,您可以得到越来越平滑的图,这些图与数据的距离越来越远,最终接近三次多项式,即最适合数据的“最小二乘”。但是这里“最好”的意思是“非常糟糕,可能毫无价值”。平滑曲线对于显示数据已经遵循的模式可能很有用。如果数据不遵循平滑模式,则不应为了绘制而绘制曲线。第一张图上的数据点应按原样显示,没有任何连接或近似曲线。

数据来自从9:00到16:00的每小时读数(其中一个杂散的17:00值与它混合-丢弃)。此结构很重要。不要假装星期二9:00是星期一16:00之后一小时发生的情况。

可以通过每日总计有意义地总结数据

Day         Total
2018-04-02  289841
2018-04-03  256293
2018-04-04  401004
2018-04-05  419054
2018-04-06  375993
2018-04-09  266233
2018-04-10  278118
2018-04-11  151390
2018-04-12  318497
2018-04-13  310578

以及每小时平均值(每天9:00的平均事件数,等等)

Hour        Average
9:00:00     16698.6
10:00:00    39705.2
11:00:00    47451.9
12:00:00    21758.8
13:00:00    20941.5
14:00:00    29086.1
15:00:00    65627
16:00:00    65411

在这些情况下,我们也许可以观察到某种模式。这是每小时的一小时:

hourly_averages = np.array([16698.6, 39705.2, 47451.9, 21758.8, 20941.5, 29086.1, 65627, 65411])
hours = np.arange(9, 17)
hourly_s = 0.1*np.diff(hourly_averages).max()**2
hourly_spline = interp.UnivariateSpline(hours, hourly_averages, s=hourly_s)
xx = np.linspace(min(hours), max(hours), 1000)  # 1000 is an arbitrary number here.
plt.plot(hours, hourly_averages, 'bo')
plt.plot(xx, hourly_spline(xx), 'r')
plt.show()

hours

曲线显示了午休时间和一天中的高峰时间。我选择s作为0.1*np.diff(hourly_averages).max()**2并不规范,但它认识到s缩放为残差平方的事实。 (Documentation)。我将对每日平均值使用相同的选择:

daily_totals = np.array([289841, 256293, 401004, 419054, 375993, 266233, 278118, 151390, 318497, 310578])
days = np.arange(len(daily_totals))
daily_s = 0.1*np.diff(daily_totals).max()**2
daily_spline = interp.UnivariateSpline(days, daily_totals, s=daily_s)
xx = np.linspace(min(days), max(days), 1000)  # 1000 is an arbitrary number here.
plt.plot(days, daily_totals, 'bo')
plt.plot(xx, daily_spline(xx), 'r')
plt.show()

daily

这不太有用。也许我们需要更长的观察时间。也许我们不应该假装星期一在星期五之后。也许应该在一周的每一天取平均值,以发现每周模式,但是仅用两周就不够了。


技术细节:方法UnivariateSpline选择的结数越少越好,以使与数据的平方偏差的某个加权总和最大为s。对于大s,这意味着很少的结,直到没有结为止,并且我们得到了一个三次多项式。 s所需的大小取决于垂直方向上的振荡量,在此示例中,振荡量极高。