大熊猫绘制时间序列,间隙最小化

时间:2016-07-25 16:02:50

标签: python pandas matplotlib plot

我最近开始探索大熊猫的深度,并希望可视化一些包含空白的时间序列数据,其中一些数据相当大。示例mydf

             timestamp       val
0  2016-07-25 00:00:00  0.740442
1  2016-07-25 01:00:00  0.842911
2  2016-07-25 02:00:00 -0.873992
3  2016-07-25 07:00:00 -0.474993
4  2016-07-25 08:00:00 -0.983963
5  2016-07-25 09:00:00  0.597011
6  2016-07-25 10:00:00 -2.043023
7  2016-07-25 12:00:00  0.304668
8  2016-07-25 13:00:00  1.185997
9  2016-07-25 14:00:00  0.920850
10 2016-07-25 15:00:00  0.201423
11 2016-07-25 16:00:00  0.842970
12 2016-07-25 21:00:00  1.061207
13 2016-07-25 22:00:00  0.232180
14 2016-07-25 23:00:00  0.453964

现在我可以通过df1.plot(x='timestamp').get_figure().show()绘制我的DataFrame,并且可以插入沿x轴的数据(显示为一行): plot0

我想要的是:

  • 带有数据的部分之间的可见间隙
  • 不同间隙的一致间隙宽度 - legths
  • 轴上可能有某种形式的标记,这有助于澄清一些时间跳跃的事实。

在这件事上研究我遇到了

通常接近我之后的情况,但前一种方法只会使绘制的数字中的空隙脱离而后者会产生我希望避免的大间隙(想想可能存在的差距)跨越几天。

因为第二种方法可能更接近我试图通过以下方式使用我的timestamp-column作为索引:

mydf2 = pd.DataFrame(data=list(mydf['val']), index=mydf[0])

允许我通过重新索引填补NaN的空白(想知道是否有更简单的解决方案来实现这一点)

mydf3 = mydf2.reindex(pd.date_range('25/7/2016', periods=24, freq='H'))

导致:

                          val
2016-07-25 00:00:00  0.740442
2016-07-25 01:00:00  0.842911
2016-07-25 02:00:00 -0.873992
2016-07-25 03:00:00       NaN
2016-07-25 04:00:00       NaN
2016-07-25 05:00:00       NaN
2016-07-25 06:00:00       NaN
2016-07-25 07:00:00 -0.474993
2016-07-25 08:00:00 -0.983963
2016-07-25 09:00:00  0.597011
2016-07-25 10:00:00 -2.043023
2016-07-25 11:00:00       NaN
2016-07-25 12:00:00  0.304668
2016-07-25 13:00:00  1.185997
2016-07-25 14:00:00  0.920850
2016-07-25 15:00:00  0.201423
2016-07-25 16:00:00  0.842970
2016-07-25 17:00:00       NaN
2016-07-25 18:00:00       NaN
2016-07-25 19:00:00       NaN
2016-07-25 20:00:00       NaN
2016-07-25 21:00:00  1.061207
2016-07-25 22:00:00  0.232180
2016-07-25 23:00:00  0.453964

从这里开始我可能需要减少超过某个限制的连续条目,并将数据丢失到一个修正数(代表我的间隙宽度)并对这些条目的索引值做一些事情,这样它们的绘制方式不同但我得到了迷失在这里,我想我不知道如何实现这样的目标。

在修补时,我想知道是否可能有一种更直接和更优雅的方法,如果有人知道更多关于这一点的话可能会指出我朝着正确的方向发展。

提前感谢任何提示和反馈!

### ADDENDUM ###

在发布我的问题后,我发现另一个有趣的idea postend by Andy Hayden似乎很有帮助。他使用一列来保存差异与时间差值的比较结果。在对布尔结果的int表示执行cumsum()之后,他使用groupby()将每个无空位系列的条目聚类为DataFrameGroupBy - 对象。

正如前面写的那样,pandas现在返回timedelta - 对象,所以比较应该与另一个timedelta - 对象一样(基于上面的mydf或者通过df2将其索引复制到now列后重新编制索引mydf2['timestamp'] = mydf2.index

from datetime import timedelta
myTD = timedelta(minutes=60)
mydf['nogap'] = mydf['timestamp'].diff() > myTD
mydf['nogap'] = mydf['nogap'].apply(lambda x: 1 if x else 0).cumsum() 
## btw.: why not "... .apply(lambda x: int(x)) ..."?
dfg = mydf.groupby('nogap')

我们现在可以遍历DataFrameGroup获取无空位系列并使用它们执行某些内容。我的pandas / mathplot技能太不成熟了,但我们可以将组元素绘制成子图吗?也许这样,沿着时间轴的不连续性可以用某种方式表示(以中断的轴线等形式)?

piRSquared的答案已经导致一个非常有用的结果,唯一的缺点是沿时间轴的更引人注目的视觉反馈,两个值之间出现间隙/时间跳跃。

也许对于分组的部分,间隙表示的宽度可以更加可配置?

1 个答案:

答案 0 :(得分:1)

我制作了一个新系列并绘制了它。这不是超级优雅!但我相信能得到你想要的东西。

设置

这样做是为了达到起点

from StringIO import StringIO
import pandas as pd

text = """          timestamp       val
2016-07-25 00:00:00   0.740442
2016-07-25 01:00:00   0.842911
2016-07-25 02:00:00  -0.873992
2016-07-25 07:00:00  -0.474993
2016-07-25 08:00:00  -0.983963
2016-07-25 09:00:00   0.597011
2016-07-25 10:00:00  -2.043023
2016-07-25 12:00:00   0.304668
2016-07-25 13:00:00   1.185997
2016-07-25 14:00:00   0.920850
2016-07-25 15:00:00   0.201423
2016-07-25 16:00:00   0.842970
2016-07-25 21:00:00   1.061207
2016-07-25 22:00:00   0.232180
2016-07-25 23:00:00   0.453964"""

s1 = pd.read_csv(StringIO(text),
                 index_col=0,
                 parse_dates=[0],
                 engine='python',
                 sep='\s{2,}').squeeze()

s1

timestamp
2016-07-25 00:00:00    0.740442
2016-07-25 01:00:00    0.842911
2016-07-25 02:00:00   -0.873992
2016-07-25 07:00:00   -0.474993
2016-07-25 08:00:00   -0.983963
2016-07-25 09:00:00    0.597011
2016-07-25 10:00:00   -2.043023
2016-07-25 12:00:00    0.304668
2016-07-25 13:00:00    1.185997
2016-07-25 14:00:00    0.920850
2016-07-25 15:00:00    0.201423
2016-07-25 16:00:00    0.842970
2016-07-25 21:00:00    1.061207
2016-07-25 22:00:00    0.232180
2016-07-25 23:00:00    0.453964
Name: val, dtype: float64

每小时重新采样。 resample是一个延迟方法,这意味着它希望您之后传递另一个方法,以便它知道该怎么做。我用了mean。就你的例子而言,这并不重要,因为我们正在以更高的频率进行采样。如果你在意,请查一查。

s2 = s1.resample('H').mean()

s2

timestamp
2016-07-25 00:00:00    0.740442
2016-07-25 01:00:00    0.842911
2016-07-25 02:00:00   -0.873992
2016-07-25 03:00:00         NaN
2016-07-25 04:00:00         NaN
2016-07-25 05:00:00         NaN
2016-07-25 06:00:00         NaN
2016-07-25 07:00:00   -0.474993
2016-07-25 08:00:00   -0.983963
2016-07-25 09:00:00    0.597011
2016-07-25 10:00:00   -2.043023
2016-07-25 11:00:00         NaN
2016-07-25 12:00:00    0.304668
2016-07-25 13:00:00    1.185997
2016-07-25 14:00:00    0.920850
2016-07-25 15:00:00    0.201423
2016-07-25 16:00:00    0.842970
2016-07-25 17:00:00         NaN
2016-07-25 18:00:00         NaN
2016-07-25 19:00:00         NaN
2016-07-25 20:00:00         NaN
2016-07-25 21:00:00    1.061207
2016-07-25 22:00:00    0.232180
2016-07-25 23:00:00    0.453964
Freq: H, Name: val, dtype: float64

好的,所以你也想要同样大小的差距。这有点棘手。我使用ffill(limit=1)只填充每个间隙的一个空格。然后我拿了s2的切片,这个向前填充的东西不是空的。对于每个间隙,这给了我一个空值。

s3 = s2[s2.ffill(limit=1).notnull()]

s3

timestamp
2016-07-25 00:00:00    0.740442
2016-07-25 01:00:00    0.842911
2016-07-25 02:00:00   -0.873992
2016-07-25 03:00:00         NaN
2016-07-25 07:00:00   -0.474993
2016-07-25 08:00:00   -0.983963
2016-07-25 09:00:00    0.597011
2016-07-25 10:00:00   -2.043023
2016-07-25 11:00:00         NaN
2016-07-25 12:00:00    0.304668
2016-07-25 13:00:00    1.185997
2016-07-25 14:00:00    0.920850
2016-07-25 15:00:00    0.201423
2016-07-25 16:00:00    0.842970
2016-07-25 17:00:00         NaN
2016-07-25 21:00:00    1.061207
2016-07-25 22:00:00    0.232180
2016-07-25 23:00:00    0.453964
Name: val, dtype: float64

最后,如果我绘制了这个,我仍然会有不规则的差距。我需要str个索引,以便matplotlib不会尝试扩展我的日期。

s3.reindex(s3.index.strftime('%H:%M'))

timestamp
00:00    0.740442
01:00    0.842911
02:00   -0.873992
03:00         NaN
07:00   -0.474993
08:00   -0.983963
09:00    0.597011
10:00   -2.043023
11:00         NaN
12:00    0.304668
13:00    1.185997
14:00    0.920850
15:00    0.201423
16:00    0.842970
17:00         NaN
21:00    1.061207
22:00    0.232180
23:00    0.453964
Name: val, dtype: float64

我会把它们联系在一起,这样我们才能看出它们之间的区别。

f, a = plt.subplots(2, 1, sharey=True, figsize=(10, 5))
s2.plot(ax=a[0])
s3.reindex(s3.index.strftime('%H:%M')).plot(ax=a[1])

enter image description here