在 pandas 中,按 DatetimeIndex 中的日期进行分组

Dro*_*ror 5 python pandas

考虑以下综合示例:

import pandas as pd
import numpy as np
np.random.seed(42)
ix = pd.date_range('2017-01-01', '2017-01-15', freq='1H')
df = pd.DataFrame(
    {
        'val': np.random.random(size=ix.shape[0]),
        'cat': np.random.choice(['foo', 'bar'], size=ix.shape[0])
    },
    index=ix
)
Run Code Online (Sandbox Code Playgroud)

这会产生以下形式的表:

                    cat val
2017-01-01 00:00:00 bar 0.374540
2017-01-01 01:00:00 foo 0.950714
2017-01-01 02:00:00 bar 0.731994
2017-01-01 03:00:00 bar 0.598658
2017-01-01 04:00:00 bar 0.156019
Run Code Online (Sandbox Code Playgroud)

现在,我想计算每个类别和日期的实例数量和平均值。

以下groupby,几乎是完美的:

df.groupby(['cat',df.index.date]).agg({'val': ['count', 'mean']})
Run Code Online (Sandbox Code Playgroud)

返回:

                val
                count   mean
cat         
bar 2017-01-01  16  0.437941
    2017-01-02  16  0.456361
    2017-01-03  9   0.514388...
Run Code Online (Sandbox Code Playgroud)

这个的问题是索引的第二层变成了字符串而不是date. 第一个问题:为什么会发生这种情况?我怎样才能避免它?

groupby接下来,我尝试了和的组合resample

df.groupby('cat').resample('1d').agg({'val': 'mean'})
Run Code Online (Sandbox Code Playgroud)

在这里,索引是正确的,但我无法同时运行meancount聚合。这是第二个问题:为什么

df.groupby('cat').resample('1d').agg({'val': ['mean', 'count']})
Run Code Online (Sandbox Code Playgroud)

不起作用?

最后一个问题是获取聚合(使用两个函数)视图date索引类型的干净方法是什么?

jez*_*ael 5

对于第一个问题,需要转换为datetimes ,没有时间,例如

\n\n
df1 = df.groupby([\'cat\',df.index.floor(\'d\')]).agg({\'val\': [\'count\', \'mean\']})\n#df1 = df.groupby([\'cat\',df.index.normalize()]).agg({\'val\': [\'count\', \'mean\']})\n\n#df1 = df.groupby([\'cat\',pd.to_datetime(df.index.date)]).agg({\'val\'\xe2\x80\x8c\xe2\x80\x8b: [\'count\', \'mean\']})\n\nprint (df1.index.get_level_values(1))\n\n\nDatetimeIndex([\'2017-01-01\', \'2017-01-02\', \'2017-01-03\', \'2017-01-04\',\n               \'2017-01-05\', \'2017-01-06\', \'2017-01-07\', \'2017-01-08\',\n               \'2017-01-09\', \'2017-01-10\', \'2017-01-11\', \'2017-01-12\',\n               \'2017-01-13\', \'2017-01-14\', \'2017-01-01\', \'2017-01-02\',\n               \'2017-01-03\', \'2017-01-04\', \'2017-01-05\', \'2017-01-06\',\n               \'2017-01-07\', \'2017-01-08\', \'2017-01-09\', \'2017-01-10\',\n               \'2017-01-11\', \'2017-01-12\', \'2017-01-13\', \'2017-01-14\',\n               \'2017-01-15\'],\n              dtype=\'datetime64[ns]\', freq=None)\n
Run Code Online (Sandbox Code Playgroud)\n\n

...因为dates 是 python 对象:

\n\n
df1 = df.groupby([\'cat\',df.index.date]).agg({\'val\': [\'count\', \'mean\']})\nprint (type(df1.index.get_level_values(1)[0]))\n<class \'datetime.date\'>\n
Run Code Online (Sandbox Code Playgroud)\n\n

第二个问题 - 在我看来这是错误或尚未实现,因为仅使用一个函数名称agg

\n\n
df2 = df.groupby(\'cat\').resample(\'1d\')[\'val\'].agg(\'mean\')\n#df2 = df.groupby(\'cat\').resample(\'1d\')[\'val\'].mean()\nprint (df2)\ncat            \nbar  2017-01-01    0.437941\n     2017-01-02    0.456361\n     2017-01-03    0.514388\n     2017-01-04    0.580295\n     2017-01-05    0.426841\n     2017-01-06    0.642465\n     2017-01-07    0.395970\n     2017-01-08    0.359940\n...\n... \n
Run Code Online (Sandbox Code Playgroud)\n\n

但以旧方式工作apply

\n\n
df2 = df.groupby(\'cat\').apply(lambda x: x.resample(\'1d\')[\'val\'].agg([\'mean\',\'count\']))\nprint (df2)\n                    mean  count\ncat                            \nbar 2017-01-01  0.437941     16\n    2017-01-02  0.456361     16\n    2017-01-03  0.514388      9\n    2017-01-04  0.580295     12\n    2017-01-05  0.426841     12\n    2017-01-06  0.642465      7\n    2017-01-07  0.395970     11\n    2017-01-08  0.359940      9\n    2017-01-09  0.564851     12\n    ...\n    ...\n
Run Code Online (Sandbox Code Playgroud)\n