【问题标题】:scipy UnivariateSpline always return linear-ish spline when plottingscipy UnivariateSpline 在绘图时总是返回线性样条曲线
【发布时间】:2018-07-12 23:20:52
【问题描述】:

我有以下一组数据 (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.

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

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

我得到以下信息:

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

我不确定我在这里错过了什么,但我显然错过了一些东西。我对spline 仍然很陌生,通常适合 python。

你能告诉我如何正确地拟合上面的时间序列吗?

编辑

根据您的评论,我想添加另一个情节,希望能更好地解释自己。我并不是说它是线性的,但我找不到更好的词。为了说明,

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

plt.show()

我认为下面的情节在我的意义上看起来相当线性。我猜,可能我的问题应该是,scipy.UnivariateSpline 到底是如何工作的?

它是否只显示在我们提供的点处评估的值的图(例如,对于这个图,它是xxx)?

我期待一个更平滑的情节,并展示出不错的曲率。 this 问题的答案显示了我期望的情节;它看起来更像是一个分段三次函数会生成的图,而我的看起来,对我来说,与那个图相比,它是线性的(或者如果更合适的话,它是一阶的。)

【问题讨论】:

  • 为什么说情节看起来是线性的?在第一个图中,放大区间 [20
  • 样条拟合看起来正确并且执行正确。我不太明白它的问题。所以当你说“我显然错过了什么”时,你是什么意思?情节有什么问题,您希望它看起来如何?
  • @WarrenWeckesser 对不准确之处深表歉意。我并不是真的打算说“线性”。我添加了另一个情节来帮助解释我的问题。
  • @ImportanceOfBeingErnest 感谢您抽出宝贵时间。我可能期待来自UnivariateSpline 的错误信息。我添加了一个链接到一个更像我想要的情节的链接。当我在 r 中使用 gam 做样条时,我通常使用 r 作为样条,它看起来正确,也是我所期望的。

标签: python matplotlib scipy spline timeserieschart


【解决方案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()

曲线显示午休和下班高峰。我将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()

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


技术细节:UnivariateSpline 方法选择尽可能少的节点,以便与数据的某个加权平方偏差之和最多为s。对于大的s,这意味着很少有结,直到没有剩余,我们得到一个三次多项式。 s 需要多大取决于垂直方向的振荡量,在这个例子中是非常高的。

【讨论】:

  • 感谢您的回答。我实际上已经尝试将s 增加到一些荒谬的数字。例如s=100s=500。我想我必须放大才能看到实际的平滑效果。
  • 我添加的最后一个情节怎么样?看起来像 UnivariateSpline 只评估提供的那些点的值,并简单地画一条直线将它们全部连接起来。
  • hmm.. 当我读到this answer 时,UnivariateSpline 只获得了 14 分,但情节看起来还不错吧?唯一不同的是我使用的是pyplot.plot,答案是pylab.plot
  • 只是为了确保每个人都在同一页面上:如果您有 7 个点并绘制正弦曲线,x=np.array([0,1,2,3,4,5,6]); y=np.sin(x); plot(x,y)does not look smooth,仅仅是因为您只用 7 个点对正弦进行采样。如果你使用 1000 个点来采样正弦,x = np.linspace(0,6,1000),你当然会得到a smooth result
  • @ImportanceOfBeingErnest 所以它看起来确实是我应该更多地使用的绘图。我很快就会再试几次。非常感谢!
猜你喜欢
  • 2014-01-06
  • 2021-09-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多