Pandas:按年/月进行DataFrame分组,并返回新的DatetimeIndex

10

我需要在 Pandas DateFrame 对象中按年或月分组,并返回一个带有新索引的新 DateFrame 对象。

这是我到目前为止的代码。 groupby 工作正常。

从 .csv 文件加载数据,将“Date”解析为日期格式(来自 finance.yahoo.com 的历史股票行情)。

In [23]: import pandas as pd
         file = pd.read_csv("sdf.de.csv", parse_dates=['Date'])
         file.head(2)

Out[23]:
    Date        Open    High    Low     Close   Volume  Adj Close
0   2016-02-16  18.650  18.70   17.940  18.16   1720800 17.0600
1   2016-02-15  18.295  18.64   18.065  18.50   1463500 17.3794

按照“日期”升序排序文件,并将索引设置为Date

In [24]: daily = file.sort_values(by='Date').set_index('Date')
         daily.head()

Out[24]:
            Open    High    Low     Close   Volume  Adj Close
Date                        
2000-01-03  14.20   14.50   14.15   14.40   277400  2.7916
2000-01-04  14.29   14.30   13.90   14.15   109200  2.7431

按月分组

我会对这些分组进行额外的apply()操作,用于压缩特定分组的数据,例如查找年/月中最高的High值或对Volume值进行sum()运算。此示例中省略了此步骤。

In [39]: monthly = daily.groupby(lambda x: (x.year, x.month))
         monthly.first()

Out[39]:
            Open    High    Low     Close   Volume  Adj Close
(2000, 1)   14.200  14.500  14.150  14.400  277400  2.7916
(2000, 2)   13.900  14.390  13.900  14.250  287200  2.7625
... ... ... ... ... ... ...
(2016, 1)   23.620  23.620  23.620  23.620  0       22.1893
(2016, 2)   19.575  19.630  19.140  19.450  1783000 18.2719

这个方法能够运行,但是它会返回一个以元组为索引的 DateFrame 对象。

如果要按月份分组,期望得到的结果应该是一个全新的 DataFrame 对象,但是其 Date 索引应该是一个新的 DatetimeIndex,格式可以是 %Y-%m 或者根据年份分组时只是 %Y

Out[39]:
        Open    High    Low     Close   Volume  Adj Close
Date
2000-01 14.200  14.500  14.150  14.400  277400  2.7916
2000-02 13.900  14.390  13.900  14.250  287200  2.7625
... ... ... ... ... ... ...
2016-01 23.620  23.620  23.620  23.620  0       22.1893
2016-02 19.575  19.630  19.140  19.450  1783000 18.2719

我感谢任何方向。


欢迎来到 Stack Overflow。您可以查看 tour - jezrael
谢谢,但为什么?我的问题有问题吗? - dirk
不,问题非常好。没有问题。 - jezrael
啊,好的。我会去做,但是还没有测试建议的解决方案。 - dirk
2个回答

11
你可以使用 groupby 方法并将参数设为 daily.index.year, daily.index.month,或者将 index 转换为时间段类型(to_period)再以 index 作为参数调用 groupby 方法。
print daily
              Open   High    Low  Close   Volume  Adj Close
Date                                                       
2000-01-01  14.200  14.50  14.15  14.40   277400     2.7916
2000-02-01  13.900  14.39  13.90  14.25   287200     2.7625
2016-01-01  23.620  23.62  23.62  23.62        0    22.1893
2016-02-01  19.575  19.63  19.14  19.45  1783000    18.2719

print daily.groupby([daily.index.year, daily.index.month]).first()
          Open   High    Low  Close   Volume  Adj Close
2000 1  14.200  14.50  14.15  14.40   277400     2.7916
     2  13.900  14.39  13.90  14.25   287200     2.7625
2016 1  23.620  23.62  23.62  23.62        0    22.1893
     2  19.575  19.63  19.14  19.45  1783000    18.2719

daily.index = daily.index.to_period('M')
print daily.groupby(daily.index).first()
           Open   High    Low  Close   Volume  Adj Close
Date                                                    
2000-01  14.200  14.50  14.15  14.40   277400     2.7916
2000-02  13.900  14.39  13.90  14.25   287200     2.7625
2016-01  23.620  23.62  23.62  23.62        0    22.1893
2016-02  19.575  19.63  19.14  19.45  1783000    18.2719

谢谢,最后一个例子完美地运行了。但奇怪的是,如果我重新运行这个单元格,我会得到一个属性错误----> 4 daily.index = daily.index.to_period('M') 5 monthly = daily.groupby(daily.index).first() 6 print (monthly) AttributeError: 'PeriodIndex' object has no attribute 'to_period' 我必须重新运行所有单元格才能使其正常工作。 - dirk
如果我理解正确,您只需要一次设置PeriodIndex,然后使用其他代码即可。尝试测试:print dailydaily.index = daily.index.to_period('M')print daily - jezrael
但它会永久地更改 dailyPeriodIndex。如果我想将其更改回每天的 daily.index = daily.index.to_period('D') 或进一步使用 daily.index = daily.index.to_period('A') 进行年份的处理,则会出现 AttributeError。 - dirk
那么也许最好使用列而不是索引,例如:daily['m'] = daily.index.to_period('M')monthly = daily.groupby('m').first(),然后 daily['d'] = daily.index.to_period('D')daily1 = daily.groupby('d').first() - jezrael
或者你可以像这样将 index 赋值给列名:df['i'] = df.index,然后使用 groupby - jezrael
谢谢你的帮助。我想尝试将索引保留为整数,然后设置“Month”和“Year”列。然后使用“monthly = daily.groupby(['Month'])”进行分组。 - dirk

2
你可以使用列表推导式从时间戳中访问年份和月份的访问器变量,然后在这些变量上进行分组。
>>> df.groupby([[d.year for d in df.Date], [d.month for d in df.Date]]).first()
             Date    Open   High    Low  Close   Volume  Adj_Close
2000 1 2000-01-01  14.200  14.50  14.15  14.40   277400     2.7916
     2 2000-02-01  13.900  14.39  13.90  14.25   287200     2.7625
2016 1 2016-01-01  23.620  23.62  23.62  23.62        0    22.1893
     2 2016-02-01  19.575  19.63  19.14  19.45  1783000    18.2719

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接