使用日期时间绘制切片熊猫数据框时出现 KeyError

Posted

技术标签:

【中文标题】使用日期时间绘制切片熊猫数据框时出现 KeyError【英文标题】:KeyError when plotting a sliced pandas dataframe with datetimes 【发布时间】:2012-09-06 12:50:34 【问题描述】:

当我尝试绘制带有日期时间的 pandas DataFrame 列的切片时,我得到一个 KeyError。有人知道是什么原因造成的吗?

我设法在一个独立的小示例中重现了该错误(您也可以在此处查看:http://nbviewer.ipython.org/3714142/):

import numpy as np
from pandas import DataFrame
import datetime
from pylab import *

test = DataFrame('x' : [datetime.datetime(2012,9,10) + datetime.timedelta(n) for n in range(10)], 
                  'y' : range(10))

现在如果我绘制:

plot(test['x'][0:5])

没有问题,但是当我绘制时:

plot(test['x'][5:10])

我得到下面的 KeyError(并且错误消息对我不是很有帮助)。这只发生在 datetime 列上,而不是其他列(据我所知)。例如。 plot(test['y'][5:10]) 不是问题。

其他错误信息:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-aa076e3fc4e0> in <module>()
----> 1 plot(test['x'][5:10])

C:\Python27\lib\site-packages\matplotlib\pyplot.pyc in plot(*args, **kwargs)
   2456         ax.hold(hold)
   2457     try:
-> 2458         ret = ax.plot(*args, **kwargs)
   2459         draw_if_interactive()
   2460     finally:

C:\Python27\lib\site-packages\matplotlib\axes.pyc in plot(self, *args, **kwargs)
   3846         lines = []
   3847 
-> 3848         for line in self._get_lines(*args, **kwargs):
   3849             self.add_line(line)
   3850             lines.append(line)

C:\Python27\lib\site-packages\matplotlib\axes.pyc in _grab_next_args(self, *args, **kwargs)
    321                 return
    322             if len(remaining) <= 3:
--> 323                 for seg in self._plot_args(remaining, kwargs):
    324                     yield seg
    325                 return

C:\Python27\lib\site-packages\matplotlib\axes.pyc in _plot_args(self, tup, kwargs)
    298             x = np.arange(y.shape[0], dtype=float)
    299 
--> 300         x, y = self._xy_from_xy(x, y)
    301 
    302         if self.command == 'plot':

C:\Python27\lib\site-packages\matplotlib\axes.pyc in _xy_from_xy(self, x, y)
    215         if self.axes.xaxis is not None and self.axes.yaxis is not None:
    216             bx = self.axes.xaxis.update_units(x)
--> 217             by = self.axes.yaxis.update_units(y)
    218 
    219             if self.command!='plot':

C:\Python27\lib\site-packages\matplotlib\axis.pyc in update_units(self, data)
   1277         neednew = self.converter!=converter
   1278         self.converter = converter
-> 1279         default = self.converter.default_units(data, self)
   1280         #print 'update units: default=%s, units=%s'%(default, self.units)
   1281         if default is not None and self.units is None:

C:\Python27\lib\site-packages\matplotlib\dates.pyc in default_units(x, axis)
   1153         'Return the tzinfo instance of *x* or of its first element, or None'
   1154         try:
-> 1155             x = x[0]
   1156         except (TypeError, IndexError):
   1157             pass

C:\Python27\lib\site-packages\pandas\core\series.pyc in __getitem__(self, key)
    374     def __getitem__(self, key):
    375         try:
--> 376             return self.index.get_value(self, key)
    377         except InvalidIndexError:
    378             pass

C:\Python27\lib\site-packages\pandas\core\index.pyc in get_value(self, series, key)
    529         """
    530         try:
--> 531             return self._engine.get_value(series, key)
    532         except KeyError, e1:
    533             if len(self) > 0 and self.inferred_type == 'integer':

C:\Python27\lib\site-packages\pandas\_engines.pyd in pandas._engines.IndexEngine.get_value (pandas\src\engines.c:1479)()

C:\Python27\lib\site-packages\pandas\_engines.pyd in pandas._engines.IndexEngine.get_value (pandas\src\engines.c:1374)()

C:\Python27\lib\site-packages\pandas\_engines.pyd in pandas._engines.DictIndexEngine.get_loc (pandas\src\engines.c:2498)()

C:\Python27\lib\site-packages\pandas\_engines.pyd in pandas._engines.DictIndexEngine.get_loc (pandas\src\engines.c:2460)()

KeyError: 0

【问题讨论】:

Pandas bug report #4493 和 #6127 似乎是关于这个问题的。 【参考方案1】:

你可以调用Series对象的plot方法,而不是调用plot(test["x"][5:10])

test["x"][5:10].plot()

原因:test["x"][5:10] 是一个 Series 对象,其索引为 5 到 10。plot() 尝试获取它的索引 0,会导致错误。

【讨论】:

好的,谢谢。如果我想绘制 x, y 数据怎么办?像 plot(test['x'], test['y']) 一样切片。 我看到最新的熊猫(0.8.1)有'x'和'y'关键字来做到这一点(0.7.3,我正在使用,据我所知还没有) .但是如果我想使用旧的原生 matplotlib 函数而不是 pandas 方法,除了在绘图之前先调用 np.asarray 之外别无他法?【参考方案2】:

我在 Pandas 0.14.0 中使用 pd.groupby 遇到了这个错误,并使用 df = df[df['col']!= 0].reset_index() 解决了它

【讨论】:

【参考方案3】:

HYRY 解释了您收到 KeyError 的原因。 要使用 matplotlib 绘制切片,您可以这样做:

In [157]: plot(test['x'][5:10].values)
Out[157]: [<matplotlib.lines.Line2D at 0xc38348c>]

In [158]: plot(test['x'][5:10].reset_index(drop=True))
Out[158]: [<matplotlib.lines.Line2D at 0xc37e3cc>]

x,y 以 0.7.3 一次性绘制

In [161]: test[5:10].set_index('x')['y'].plot()
Out[161]: <matplotlib.axes.AxesSubplot at 0xc48b1cc>

【讨论】:

谢谢!但是,仍然存在两个问题:1)为什么只有日期列有问题(plot(test['y'][5:10]) 不是问题)?虽然test['y'][5:10][0] 也不起作用,至于'x'。 2) 我知道,对于整数索引,您无法使用标准索引工具根据位置进行索引(这引起了我的困惑,但在此解释:pandas.pydata.org/pandas-docs/dev/…),但是否有更少的标准工具可以使这成为可能(类似于属性.ix,但基于位置,例如.ix_loc)? 在日期列的情况下步进跟踪,表明 matplotlib 尝试在日期上执行 x[0] 以检索 tz 信息,这会引发 KeyError。这不是在 y 列上完成的。 Pandas 有基于位置的索引工具,但 matplotlib 内部不使用它们。 啊,好的,我明白了。什么是基于位置的索引工具(用于整数标签)?我无法直接在文档中找到它们。 我看到这是最近的更改 (pandas.pydata.org/pandas-docs/dev/…)。与此同时,我已经学会使用日期作为索引,所以我不再有问题了,但是,整数索引的一个烦人(但我想是不可避免的)结果(并且很难看到你做了什么)作为新手是错误的)。再次感谢!

以上是关于使用日期时间绘制切片熊猫数据框时出现 KeyError的主要内容,如果未能解决你的问题,请参考以下文章

使用熊猫数据框时出现 KeyError

将熊猫数据框可视化为热图时出现类型错误

对唯一顺序索引的多索引熊猫数据框进行切片和赋值

在 Python Pandas 中使用 DatetimeIndex 切片 MultIndex 帧时出现 1.1.0 以上的 InvalidIndexError

比较熊猫数据框列中的值时出现类型错误

与熊猫外部合并时出现重复问题