熊猫可以在不尝试将索引转换为周期的情况下绘制时间序列吗?

Posted

技术标签:

【中文标题】熊猫可以在不尝试将索引转换为周期的情况下绘制时间序列吗?【英文标题】:Can pandas plot a time-series without trying to convert the index to Periods? 【发布时间】:2014-02-07 00:32:53 【问题描述】:

在绘制时间序列时,我观察到异常行为,最终导致无法格式化绘图的 xticks。 似乎 pandas 在内部尝试将索引转换为 PeriodIndex,但显然只有在时间戳值等间距时才会成功。如果它们间隔不均匀(或者 - 奇怪的是 - 如果它们间隔均匀但时区感知),则索引仍然是 DatetimeIndex。 后一种情况按预期工作。我可以设置 DateFormatter 和 Locators。但是,如果在绘图之前将索引内部转换为 PeriodIndex,则生成的绘图的 x 轴似乎是混乱的。

这是一个重现问题的示例。

from pandas import Series, DataFrame
import pandas as pd
from datetime import datetime
import pytz
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

idx1 = np.array([datetime(2014, 1, 16, 0),
                 datetime(2014, 1, 16, 5),
                 datetime(2014, 1, 16, 10),
                 datetime(2014, 1, 16, 15), 
                 datetime(2014, 1, 16, 20), 
                 datetime(2014, 1, 17, 1)])
idx2 = np.array([datetime(2014, 1, 16, 0),
                 datetime(2014, 1, 16, 5),
                 datetime(2014, 1, 16, 10),
                 datetime(2014, 1, 16, 15),
                 datetime(2014, 1, 16, 20),
                 datetime(2014, 1, 16, 23)])
y = [0, 2, np.nan, 5, 2, 1]
tz = pytz.timezone('Europe/Berlin')

fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(15,4))

# index convertible to period index
s1 = Series(y, index=idx1)
s1.plot(ax=ax1)
print ax1.get_xticks()
print ax1.xaxis.get_major_locator()
print ax1.xaxis.get_major_formatter()
#ax1.xaxis.set_major_formatter(mpl.dates.DateFormatter('%H'))
#ax1.xaxis.set_major_locator(mpl.ticker.MultipleLocator(0.25))

# index not convertible to period index
s2 = Series(y, index=idx2)
s2.plot(ax=ax2)
print ax2.get_xticks()
#ax2.xaxis.set_major_formatter(mpl.dates.DateFormatter('%H'))
#ax2.xaxis.set_major_locator(mpl.ticker.MultipleLocator(0.25))

# index convertible to period index but tz-aware
s3 = Series(y, index=idx1)
s3 = s3.tz_localize(tz)
s3.plot(ax=ax3)
print ax3.get_xticks()
#ax2.xaxis.set_major_formatter(mpl.dates.DateFormatter('%H'))
#ax2.xaxis.set_major_locator(mpl.ticker.MultipleLocator(0.25))

fig.autofmt_xdate()  # just temporarily

plt.tight_layout()
plt.show(block=False)

有没有办法告诉 pandas 将索引保持其原始格式而不是将其转换为句点?任何如何处理这个问题的想法都非常感谢!

我使用 pandas 0.13 和 matplotlib 1.3.1

作为旁注: 如果时区没有全部转换为 UTC,那当然会很棒。但是我意识到这个问题可能还会持续一段时间。但是,如果有人有解决方法的提示,我会很高兴听到(我尝试将 tz 直接传递给 DateFormatter。这可行,但定位器似乎不太喜欢它)。

【问题讨论】:

好的,对于旁注,我想出了一个解决方法: 1. ax3.xaxis.set_major_formatter(mpl.dates.DateFormatter('%H %Z', tz=tz)) 2. l = mpl.dates.HourLocator((0,6,12,18), tz=tz) 这意味着问题只剩下如何处理 tz-naive 等距时间序列了... This issue 实际上涉及到known bug。 【参考方案1】:

解决这个问题的一种方法是不使用 pandas plot 方法,而是直接使用 matplotlib 的 plot 函数。 s1.plot(ax=ax1) 会变成:

ax1.plot(s1.index, s1)

如果您随后打印ax1.get_xticks(),您会得到与不规则时间序列相同的结果,因为日期时间值不会转换为期间。这样做的一个缺点是你失去了 pandas 更智能的日期轴格式(但你想适应这个,我想这不是问题)。

据我所知,您无法在 pandas 公共 api 中指定这一点(除了故意使您的时间序列不规则或添加时区的丑陋黑客行为)

【讨论】:

感谢分享;我已经为这个问题苦苦挣扎了好几个小时。这有点烦人,因为它是一个不容易调试的 pandas “幕后”机制。【参考方案2】:

处理从UTC到本地时间的转换

import time
import pytz
import matplotlib.dates
…
# Get the time zone.
tz = pytz.timezone(time.tzname[0])
…
ax1.xaxis.set_major_locator(matplotlib.dates.HourLocator(interval=1, tz=tz))
ax1.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('%H', tz=tz))

【讨论】:

以上是关于熊猫可以在不尝试将索引转换为周期的情况下绘制时间序列吗?的主要内容,如果未能解决你的问题,请参考以下文章

将索引转换为日期时间对象后,MatplotLib 无法正确绘制熊猫时间序列 1 分钟数据

PySpark DataFrames - 在不转换为 Pandas 的情况下进行枚举的方法?

PySpark DataFrames - 在不转换为 Pandas 的情况下进行枚举的方法?

如何在不改变坐标的情况下转换(旋转)svg文本元素?

按值加入两个熊猫系列[重复]

我正在使用熊猫数据框,我需要在不使用循环的情况下将一整列纪元时间戳转换为人类时间