[英]pandas plot time-series with minimized gaps
我最近开始探索大熊猫的深度,并希望可视化一些包含间隙的时间序列数据,其中一些相当大。 一个例子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。get_figure df1.plot(x='timestamp').get_figure().show()
和x轴上的数据将被内插(显示为一行):
我想要的是:
研究这个问题我遇到过
这通常接近我所追求的,但是前一种方法只会使绘制的数字中的空隙脱离而后者会产生我希望避免的大间隙(想想可能跨越几天的空隙) 。
因为第二种方法可能更接近我试图使用我的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 ###
在发布我的问题之后,我发现Andy Hayden提出的另一个有趣的想法似乎很有帮助。 他正在使用一列来保存差异与时间增量的比较结果。 在对布尔结果的int表示执行cumsum()
,他使用groupby()
将每个无DataFrameGroupBy
系列的条目聚类到DataFrameGroupBy
。
正如timedelta
写的那样,大熊猫现在返回timedelta
-objects所以比较应该用另一个timedelta
来完成(基于上面的mydf
或者在通过mydf2['timestamp'] = mydf2.index
将索引复制到now列之后重新索引的df2
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的答案已经导致一个非常有用的结果,唯一的缺点是沿时间轴的更引人注目的视觉反馈,两个值之间出现间隙/时间跳跃。
也许对于分组的部分,间隙表示的宽度可以更加可配置?
我建立了一个新的系列并绘制它。 这不是超级优雅! 但我相信能得到你想要的东西。
这样做是为了达到你的起点
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])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.