27_Pandas按星期,月份,季度和年份的天计算时间序列数据的总计和平均值

27_Pandas按星期,月份,季度和年份的天计算时间序列数据的总计和平均值

将pandas.DataFrame的索引设置为DatetimeIndex对于处理具有日期和时间信息(例如日期和时间)的时间序列数据很有用。

由于DatetimeIndex可以获取诸如星期几,月份,季度和年份之类的信息作为属性,因此可以使用它们来计算每个时间序列数据的总和或平均值。此外,通过组合它们,例如可以计算每个季度的一周中的每一天的总计。

这里,将描述以下内容。

  • 通过resample()汇总任何期间
  • 星期几:weekday, dayofweek, day_name()
    • 通过指定星期几来提取行
    • 计算一周中每一天的总数和平均值
  • 其他属性
    • 年: year
    • 季度:quarter
    • 月:month, month_name()
    • 周:week, weekofyear
  • 通过组合多个属性(星期几,月份,季度,年份等)进行处理

有关如何将索引设置为datetime64 [ns]类型的DatetimeIndex,请参考以下文章。

使用以下csv数据作为示例

import pandas as pd

df = pd.read_csv('./data/27/sample_date.csv', index_col=0, parse_dates=True)
print(df)
#             val_1  val_2
# date
# 2017-11-01     65     76
# 2017-11-07     26     66
# 2017-11-18     47     47
# 2017-11-27     20     38
# 2017-12-05     65     85
# 2017-12-12      4     29
# 2017-12-22     31     54
# 2017-12-29     21      8
# 2018-01-03     98     76
# 2018-01-08     48     64
# 2018-01-19     18     48
# 2018-01-23     86     70

print(type(df.index))
# <class 'pandas.core.indexes.datetimes.DatetimeIndex'>

通过resample()汇总任何期间

首先,显示了通过使用resample()而不是DatetimeIndex的属性对任意时间段进行总计(求和,平均值等)的方法。

在第一个参数中指定频率代码,例如W(星期),M(月),Q(季度),Y(年),并调用诸如sum()的方法。

print(df.resample('W').sum())
#             val_1  val_2
# date                    
# 2017-11-05     65     76
# 2017-11-12     26     66
# 2017-11-19     47     47
# 2017-11-26      0      0
# 2017-12-03     20     38
# 2017-12-10     65     85
# 2017-12-17      4     29
# 2017-12-24     31     54
# 2017-12-31     21      8
# 2018-01-07     98     76
# 2018-01-14     48     64
# 2018-01-21     18     48
# 2018-01-28     86     70

print(df.resample('M').sum())
#             val_1  val_2
# date                    
# 2017-11-30    158    227
# 2017-12-31    121    176
# 2018-01-31    250    258

print(df.resample('Q').sum())
#             val_1  val_2
# date                    
# 2017-12-31    279    403
# 2018-03-31    250    258

print(df.resample('Y').sum())
#             val_1  val_2
# date                    
# 2017-12-31    279    403
# 2018-12-31    250    258

还可以通过组合数字来指定时间段,例如10D(10天)和3W(3周).

print(df.resample('10D').sum())
#             val_1  val_2
# date                    
# 2017-11-01     91    142
# 2017-11-11     47     47
# 2017-11-21     20     38
# 2017-12-01     65     85
# 2017-12-11      4     29
# 2017-12-21     52     62
# 2017-12-31    146    140
# 2018-01-10     18     48
# 2018-01-20     86     70

print(df.resample('3W').sum())
#             val_1  val_2
# date                    
# 2017-11-05     65     76
# 2017-11-26     73    113
# 2017-12-17     89    152
# 2018-01-07    150    138
# 2018-01-28    152    182

除了sum()之外,还可以使用诸如mean()之类的方法。还可以使用agg()同时应用多种方法。

print(df.resample('Y').mean())
#              val_1   val_2
# date                      
# 2017-12-31  34.875  50.375
# 2018-12-31  62.500  64.500

print(df.resample('Y').agg(['sum', 'mean', 'max', 'min']))
#            val_1                 val_2                
#              sum    mean max min   sum    mean max min
# date                                                  
# 2017-12-31   279  34.875  65   4   403  50.375  85   8
# 2018-12-31   250  62.500  98  18   258  64.500  76  48

请注意,如果索引的值为D,则将是该期间的开始日期和时间,而W,M,Q,Y将是结束日期和时间。

星期几:weekday, dayofweek, day_name()

从这里开始,将说明使用DatetimeIndex属性和多索引进行总计的方法。

使用DatetimeIndex的weekday或dayofweek属性,可以获取星期几信息,该信息是整数,其中星期一为0,星期日为6。两者是相同的。

print(df.index.weekday)
# Int64Index([2, 1, 5, 0, 1, 1, 4, 4, 2, 0, 4, 1], dtype='int64', name='date')

print(df.index.dayofweek)
# Int64Index([2, 1, 5, 0, 1, 1, 4, 4, 2, 0, 4, 1], dtype='int64', name='date')

可以用英语获取ay_name()。请注意,这是一种方法,而不是属性。此外,在版本0.22之前,可以使用weekday_name属性获取星期几的名称,但是在0.23中已将其废除,并添加了新的day_name()。

print(df.index.day_name())
# Index(['Wednesday', 'Tuesday', 'Saturday', 'Monday', 'Tuesday', 'Tuesday',
#        'Friday', 'Friday', 'Wednesday', 'Monday', 'Friday', 'Tuesday'],
#       dtype='object', name='date')

通过指定星期几来提取行

例如,如果要提取星期一(0)的行,请执行以下操作。

print(df[df.index.weekday == 0])
#             val_1  val_2
# date                    
# 2017-11-27     20     38
# 2018-01-08     48     64

计算一周中每一天的总数和平均值

可以使用sum()和mean()方法来计算统计数据,例如在一周的指定天中提取的数据的总和和平均值。也可以通过agg()一次全部应用。

print(df[df.index.weekday == 0].sum())
# val_1     68
# val_2    102
# dtype: int64

print(df[df.index.weekday == 0].mean())
# val_1    34.0
# val_2    51.0
# dtype: float64

print(df[df.index.weekday == 0].agg(['sum', 'mean']))
#       val_1  val_2
# sum    68.0  102.0
# mean   34.0   51.0

当要计算所有天的总和或平均值而不仅仅是特定日期时,多索引机制很有用。

如果使用set_index()将多个列指定为索引,则它将成为多索引。有关set_index()的信息,请参见以下文章。

df_w = df.set_index([df.index.weekday, df.index])
print(df_w)
#                  val_1  val_2
# date date                    
# 2    2017-11-01     65     76
# 1    2017-11-07     26     66
# 5    2017-11-18     47     47
# 0    2017-11-27     20     38
# 1    2017-12-05     65     85
#      2017-12-12      4     29
# 4    2017-12-22     31     54
#      2017-12-29     21      8
# 2    2018-01-03     98     76
# 0    2018-01-08     48     64
# 4    2018-01-19     18     48
# 1    2018-01-23     86     70

由于索引列的名称照原样重复,因此请重写index.names属性。

df_w.index.names = ['weekday', 'date']
print(df_w)
#                     val_1  val_2
# weekday date                    
# 2       2017-11-01     65     76
# 1       2017-11-07     26     66
# 5       2017-11-18     47     47
# 0       2017-11-27     20     38
# 1       2017-12-05     65     85
#         2017-12-12      4     29
# 4       2017-12-22     31     54
#         2017-12-29     21      8
# 2       2018-01-03     98     76
# 0       2018-01-08     48     64
# 4       2018-01-19     18     48
# 1       2018-01-23     86     70

さらに、sort_index()でソート。

df_w.sort_index(inplace=True)
print(df_w)
#                     val_1  val_2
# weekday date                    
# 0       2017-11-27     20     38
#         2018-01-08     48     64
# 1       2017-11-07     26     66
#         2017-12-05     65     85
#         2017-12-12      4     29
#         2018-01-23     86     70
# 2       2017-11-01     65     76
#         2018-01-03     98     76
# 4       2017-12-22     31     54
#         2017-12-29     21      8
#         2018-01-19     18     48
# 5       2017-11-18     47     47

如果按原样使用sum(),则将计算总和,但是如果在参数级别中指定索引列的名称,则将计算每个索引的总数(在这种情况下,将计算一周中每一天的总数)。

print(df_w.sum())
# val_1    529
# val_2    661
# dtype: int64

print(df_w.sum(level='weekday'))
#          val_1  val_2
# weekday              
# 0           68    102
# 1          181    250
# 2          163    152
# 4           70    110
# 5           47     47

其他方法(例如mean())也是如此。

print(df_w.mean(level='weekday'))
#              val_1      val_2
# weekday                      
# 0        34.000000  51.000000
# 1        45.250000  62.500000
# 2        81.500000  76.000000
# 4        23.333333  36.666667
# 5        47.000000  47.000000

如果是agg(),请将其与groupby()一起使用。

print(df_w.groupby(level='weekday').agg(['sum', 'mean']))
#         val_1            val_2           
#           sum       mean   sum       mean
# weekday                                  
# 0          68  34.000000   102  51.000000
# 1         181  45.250000   250  62.500000
# 2         163  81.500000   152  76.000000
# 4          70  23.333333   110  36.666667
# 5          47  47.000000    47  47.000000

其他属性

年: year

可以使用DatetimeIndex属性year来获取年份。

print(df.index.year)
# Int64Index([2017, 2017, 2017, 2017, 2017, 2017, 2017, 2017, 2018, 2018, 2018,
#             2018],
#            dtype='int64', name='date')

可以采用与上述每周几天相同的方式来计算每年的总计和平均值。

df_y = df.set_index([df.index.year, df.index])
df_y.index.names = ['year', 'date']
print(df_y)
#                  val_1  val_2
# year date                    
# 2017 2017-11-01     65     76
#      2017-11-07     26     66
#      2017-11-18     47     47
#      2017-11-27     20     38
#      2017-12-05     65     85
#      2017-12-12      4     29
#      2017-12-22     31     54
#      2017-12-29     21      8
# 2018 2018-01-03     98     76
#      2018-01-08     48     64
#      2018-01-19     18     48
#      2018-01-23     86     70

print(df_y.sum(level='year'))
#       val_1  val_2
# year              
# 2017    279    403
# 2018    250    258

季度:quarter

可以按日期时间索引的季度属性获得季度的数目。

df_q = df.set_index([df.index.quarter, df.index])
df_q.index.names = ['quarter', 'date']
print(df_q)
#                     val_1  val_2
# quarter date                    
# 4       2017-11-01     65     76
#         2017-11-07     26     66
#         2017-11-18     47     47
#         2017-11-27     20     38
#         2017-12-05     65     85
#         2017-12-12      4     29
#         2017-12-22     31     54
#         2017-12-29     21      8
# 1       2018-01-03     98     76
#         2018-01-08     48     64
#         2018-01-19     18     48
#         2018-01-23     86     70

print(df_q.sum(level='quarter'))
#          val_1  val_2
# quarter              
# 4          279    403
# 1          250    258

月:month, month_name()

可以使用DatetimeIndex属性month获得月份。

df_m = df.set_index([df.index.month, df.index])
df_m.index.names = ['month', 'date']
print(df_m)
#                   val_1  val_2
# month date                    
# 11    2017-11-01     65     76
#       2017-11-07     26     66
#       2017-11-18     47     47
#       2017-11-27     20     38
# 12    2017-12-05     65     85
#       2017-12-12      4     29
#       2017-12-22     31     54
#       2017-12-29     21      8
# 1     2018-01-03     98     76
#       2018-01-08     48     64
#       2018-01-19     18     48
#       2018-01-23     86     70

print(df_m.sum(level='month'))
#        val_1  val_2
# month              
# 11       158    227
# 12       121    176
# 1        250    258

还有month_name()返回月份的名称

print(df.index.month_name())
# Index(['November', 'November', 'November', 'November', 'December', 'December',
#        'December', 'December', 'January', 'January', 'January', 'January'],
#       dtype='object', name='date')

周:week, weekofyear

可以使用DatetimeIndex的week或weekofyear属性获取星期数。

df_w2 = df.set_index([df.index.week, df.index])
df_w2.index.names = ['week', 'date']
print(df_w2)
#                  val_1  val_2
# week date                    
# 44   2017-11-01     65     76
# 45   2017-11-07     26     66
# 46   2017-11-18     47     47
# 48   2017-11-27     20     38
# 49   2017-12-05     65     85
# 50   2017-12-12      4     29
# 51   2017-12-22     31     54
# 52   2017-12-29     21      8
# 1    2018-01-03     98     76
# 2    2018-01-08     48     64
# 3    2018-01-19     18     48
# 4    2018-01-23     86     70

print(df_w2.sum(level='week'))
#       val_1  val_2
# week              
# 44       65     76
# 45       26     66
# 46       47     47
# 48       20     38
# 49       65     85
# 50        4     29
# 51       31     54
# 52       21      8
# 1        98     76
# 2        48     64
# 3        18     48
# 4        86     70

print(pd.date_range('2017-01-01', '2017-01-07').week)
# Int64Index([52, 1, 1, 1, 1, 1, 1], dtype='int64')

print(pd.date_range('2017-01-01', '2017-01-07').day_name())
# Index(['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
#        'Saturday'],
#       dtype='object')

通过组合多个属性(星期几,月份,季度,年份等)进行处理

通过增加多索引中的列数,可以组合和处理多个属性(星期几,月份,季度,年份等)。

Resample()易于进行简单的年度和月度处理,但是使用包含多个属性的多索引进行处理很方便。

例如,按年份和星期几排序。

df_yw = df.set_index([df.index.year, df.index.weekday, df.index])
df_yw.index.names = ['year', 'weekday', 'date']
df_yw.sort_index(inplace=True)
print(df_yw)
#                          val_1  val_2
# year weekday date                    
# 2017 0       2017-11-27     20     38
#      1       2017-11-07     26     66
#              2017-12-05     65     85
#              2017-12-12      4     29
#      2       2017-11-01     65     76
#      4       2017-12-22     31     54
#              2017-12-29     21      8
#      5       2017-11-18     47     47
# 2018 0       2018-01-08     48     64
#      1       2018-01-23     86     70
#      2       2018-01-03     98     76
#      4       2018-01-19     18     48

根据sum()或mean()的参数级别,可以汇总所有数据的星期几数据,也可以汇总每年的星期几数据。

print(df_yw.sum(level='weekday'))
#          val_1  val_2
# weekday              
# 0           68    102
# 1          181    250
# 2          163    152
# 4           70    110
# 5           47     47

print(df_yw.sum(level=['year', 'weekday']))
#               val_1  val_2
# year weekday              
# 2017 0           20     38
#      1           95    180
#      2           65     76
#      4           52     62
#      5           47     47
# 2018 0           48     64
#      1           86     70
#      2           98     76
#      4           18     48

在多索引的情况下,列选择和提取会有一些奇怪之处。有关详细信息,请参见以下文章。

这里有些例子。

print(df_yw.loc[(2017, 1), :])
#             val_1  val_2
# date                    
# 2017-11-07     26     66
# 2017-12-05     65     85
# 2017-12-12      4     29

print(df_yw.xs(1, level='weekday'))
#                  val_1  val_2
# year date                    
# 2017 2017-11-07     26     66
#      2017-12-05     65     85
#      2017-12-12      4     29
# 2018 2018-01-23     86     70

print(df_yw.loc[(2017, [0, 4]), :])
#                          val_1  val_2
# year weekday date                    
# 2017 0       2017-11-27     20     38
#      4       2017-12-22     31     54
#              2017-12-29     21      8

print(df_yw.loc[pd.IndexSlice[:, [0, 4]], :])
#                          val_1  val_2
# year weekday date                    
# 2017 0       2017-11-27     20     38
#      4       2017-12-22     31     54
#              2017-12-29     21      8
# 2018 0       2018-01-08     48     64
#      4       2018-01-19     18     48

如果原始时间序列数据的范围很广,则可以方便地首先设置大量的多索引列,以便可以从各个角度汇总数据。

df_yqmw = df.set_index([df.index.year, df.index.quarter, df.index.month, df.index.weekday, df.index])
df_yqmw.index.names = ['year', 'quarter', 'month', 'weekday', 'date']
df_yqmw.sort_index(inplace=True)
print(df_yqmw)
#                                        val_1  val_2
# year quarter month weekday date                    
# 2017 4       11    0       2017-11-27     20     38
#                    1       2017-11-07     26     66
#                    2       2017-11-01     65     76
#                    5       2017-11-18     47     47
#              12    1       2017-12-05     65     85
#                            2017-12-12      4     29
#                    4       2017-12-22     31     54
#                            2017-12-29     21      8
# 2018 1       1     0       2018-01-08     48     64
#                    1       2018-01-23     86     70
#                    2       2018-01-03     98     76
#                    4       2018-01-19     18     48

print(df_yqmw.sum(level='month'))
#        val_1  val_2
# month              
# 11       158    227
# 12       121    176
# 1        250    258

可以轻松地按每年的一天分析趋势,而按季度的一周的一天分析趋势。

print(df_yqmw.sum(level='weekday'))
#          val_1  val_2
# weekday              
# 0           68    102
# 1          181    250
# 2          163    152
# 5           47     47
# 4           70    110

print(df_yqmw.sum(level=['quarter', 'weekday']))
#                  val_1  val_2
# quarter weekday              
# 4       0           20     38
#         1           95    180
#         2           65     76
#         5           47     47
#         4           52     62
# 1       0           48     64
#         1           86     70
#         2           98     76
#         4           18     48

同样,由于在多索引情况下的列选择和提取有一些奇怪之处,请参阅以下文章以了解详细信息。

print(df_yqmw.xs(1, level='weekday'))
#                                val_1  val_2
# year quarter month date                    
# 2017 4       11    2017-11-07     26     66
#              12    2017-12-05     65     85
#                    2017-12-12      4     29
# 2018 1       1     2018-01-23     86     70

print(df_yqmw.xs((1, 2017), level=('weekday', 'year')))
#                           val_1  val_2
# quarter month date                    
# 4       11    2017-11-07     26     66
#         12    2017-12-05     65     85
#               2017-12-12      4     29

print(df_yqmw.loc[pd.IndexSlice[2017, :, :, [0, 4]], :])
#                                        val_1  val_2
# year quarter month weekday date                    
# 2017 4       11    0       2017-11-27     20     38
#              12    4       2017-12-22     31     54
#                            2017-12-29     21      8
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值