【问题标题】:Plotting with GroupBy in Pandas/Python在 Pandas/Python 中使用 GroupBy 绘图
【发布时间】:2014-01-04 01:45:57
【问题描述】:

虽然在 pandas 中绘制 groupby 对象是直接且容易的,但我想知道从 groupby 对象中获取唯一组的最 Pythonic(pandastic?)方法是什么。例如: 我正在处理大气数据,并试图绘制几天或更长时间内的昼夜趋势。以下是包含多天数据的 DataFrame,其中时间戳为索引:

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 10909 entries, 2013-08-04 12:01:00 to 2013-08-13 17:43:00
Data columns (total 17 columns):
Date     10909  non-null values
Flags    10909  non-null values
Time     10909  non-null values
convt    10909  non-null values
hino     10909  non-null values
hinox    10909  non-null values
intt     10909  non-null values
no       10909  non-null values
nox      10909  non-null values
ozonf    10909  non-null values
pmtt     10909  non-null values
pmtv     10909  non-null values
pres     10909  non-null values
rctt     10909  non-null values
smplf    10909  non-null values
stamp    10909  non-null values
no2      10909  non-null values
dtypes: datetime64[ns](1), float64(11), int64(2), object(3)

为了能够对几天内每分钟的数据进行平均(并获取其他统计数据),我对数据框进行了分组: data = no.groupby('Time')

然后我可以轻松绘制平均 NO 浓度以及四分位数:

ax = figure(figsize=(12,8)).add_subplot(111)
title('Diurnal Profile for NO, NO2, and NOx: East St. Louis Air Quality Study')
ylabel('Concentration [ppb]')
data.no.mean().plot(ax=ax, style='b', label='Mean')
data.no.apply(lambda x: percentile(x, 25)).plot(ax=ax, style='r', label='25%')
data.no.apply(lambda x: percentile(x, 75)).plot(ax=ax, style='r', label='75%')

引发我的问题的问题是,为了绘制更有趣的东西,例如使用 fill_between() 之类的绘图,有必要根据文档了解 x 轴信息

fill_between(x, y1, y2=0, where=None, interpolate=False, hold=None, **kwargs)

在我的一生中,我无法找出实现这一目标的最佳方法。我试过了:

  1. 遍历 groupby 对象并创建组数组
  2. 从原始 DataFrame 中获取所有唯一的 Time 条目

我可以完成这些工作,但我知道有更好的方法。 Python 太漂亮了。有什么想法/提示吗?

更新: 可以使用unstack() 将统计信息转储到新的数据帧中,例如

no_new = no.groupby('Time')['no'].describe().unstack()
no_new.info()
<class 'pandas.core.frame.DataFrame'>
Index: 1440 entries, 00:00 to 23:59
Data columns (total 8 columns):
count    1440  non-null values
mean     1440  non-null values
std      1440  non-null values
min      1440  non-null values
25%      1440  non-null values
50%      1440  non-null values
75%      1440  non-null values
max      1440  non-null values
dtypes: float64(8)

虽然我应该能够使用no_new.indexfill_between() 进行绘图,但我收到了TypeError

当前的情节代码和TypeError

ax = figure(figzise=(12,8)).add_subplot(111)
ax.plot(no_new['mean'])
ax.fill_between(no_new.index, no_new['mean'], no_new['75%'], alpha=.5, facecolor='green')

类型错误:

TypeError                                 Traceback (most recent call last)
<ipython-input-6-47493de920f1> in <module>()
      2 ax = figure(figsize=(12,8)).add_subplot(111)
      3 ax.plot(no_new['mean'])
----> 4 ax.fill_between(no_new.index, no_new['mean'], no_new['75%'], alpha=.5,     facecolor='green')
      5 #title('Diurnal Profile for NO, NO2, and NOx: East St. Louis Air Quality Study')
      6 #ylabel('Concentration [ppb]')

C:\Users\David\AppData\Local\Enthought\Canopy\User\lib\site-packages\matplotlib\axes.pyc in fill_between(self, x, y1, y2, where, interpolate, **kwargs)
   6986 
   6987         # Convert the arrays so we can work with them
-> 6988         x = ma.masked_invalid(self.convert_xunits(x))
   6989         y1 = ma.masked_invalid(self.convert_yunits(y1))
   6990         y2 = ma.masked_invalid(self.convert_yunits(y2))

C:\Users\David\AppData\Local\Enthought\Canopy\User\lib\site-packages\numpy\ma\core.pyc in masked_invalid(a, copy)
   2237         cls = type(a)
   2238     else:
-> 2239         condition = ~(np.isfinite(a))
   2240         cls = MaskedArray
   2241     result = a.view(cls)

TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

目前的情节是这样的:

【问题讨论】:

  • 哎呀,这对我来说看起来不错...啊,现在我想我明白了,您需要将图形对象分配给一个变量,然后您才能获取轴...

标签: python matplotlib pandas


【解决方案1】:

将 groupby 统计信息(平均值/25/75)存储为新数据框中的列,然后将新数据框的 index 作为 plt.fill_between()x 参数传递给我(使用 matplotlib 1.3.1 测试) .例如,

gdf = df.groupby('Time')[col].describe().unstack()
plt.fill_between(gdf.index, gdf['25%'], gdf['75%'], alpha=.5)

gdf.info() 应该是这样的:

<class 'pandas.core.frame.DataFrame'>
Index: 12 entries, 00:00:00 to 22:00:00
Data columns (total 8 columns):
count    12 non-null float64
mean     12 non-null float64
std      12 non-null float64
min      12 non-null float64
25%      12 non-null float64
50%      12 non-null float64
75%      12 non-null float64
max      12 non-null float64
dtypes: float64(8)

更新:为了解决TypeError: ufunc 'isfinite' not supported异常,首先需要将Time列从一系列“HH:MM”格式的字符串对象转换为一系列datetime.time对象,可以做到如下:

df['Time'] = df.Time.map(lambda x: pd.datetools.parse(x).time())

【讨论】:

  • 太棒了!这是一个很好的开始。尝试填充之间()时,我不断收到类型错误。看起来在转换 x 轴值时遇到问题?一个快速的谷歌发现这是 matplotlib v. 1.3.0 中的一个错误,所以我升级到 1.3.1 但没有骰子。有任何想法吗?确切的错误是:TypeError: ufunc 'isfinite' not supported for the input types, and the input could not be safe to force to any supported types based on the cast rule ''safe''
  • 您使用的是哪个版本的熊猫?我想我在 0.12 和 master 上测试过
  • 统计数据:Pandas (0.12.0)、Numpy (1.8.0)、Python (2.7.3 64bit)
  • 我似乎无法重现该异常。你能用一个可重现的例子来更新这个问题吗?
  • 试试:no['Time'] = no.Time.map(lambda x: pd.datetools.parse(x).time())
猜你喜欢
  • 2021-09-11
  • 2019-02-02
  • 2020-12-25
  • 2019-02-13
  • 2017-01-28
  • 1970-01-01
  • 1970-01-01
  • 2018-06-27
  • 2013-03-06
相关资源
最近更新 更多