先说为什么
我为什么想通过Pandas实现日历表的计算。也许这跟做#数据仓库#,#BI#有关,日历表,在数据仓库和BI领域,更像是一个维度表,或者直白点,叫MappingTable。
通常情况下,一个设计好的日历表能够帮助数据团队在做多维数据模型的时候更好地对业务系统中的日期类型数据进行转换,并通过BI产品进行筛选和聚合,更加容易的实现如CalendarWeek数据的计算,如:
2022年第10周,销售额为******;2022年第4季度,利润为******;在当年的第几个自然日,2022年累计销量突破500万。Just a Pic
进入正文
通过前面几天的学习,逐步掌握了一些运用Pandas进行数据处理的方法。
今天我们主要了解一下如何通过Pandas处理日期类型的数据序列,并创建一个日历数据集合。
建议在实际应用过程中,直接通过函数获取对应的DataFrame结果,所有数据都在内存中进行缓存会提高程序的性能,文末通过to_excel另存为Excel文件主要是为了展示目的,让大家更加直观的看到所有的数据内容。
代码实现# -*- coding: utf-8 -*-"""Created on Fri Jan 7 14:20:38 2022@author: Derek Zhu@version: 1.0@content: a Calendar Table practice with Pandas"""import pandas as pdimport os# Return a fixed frequency DatetimeIndex.# ISO years always start with Monday# 定义函数,设置起始日期为参数def get_calendar(start_dt, end_dt): df = pd.DataFrame( {'date': pd.date_range(start_dt, end_dt)} ) # Index start from 0 df['date_id'] = df.index.values df['year'] = df.date.dt.year df['month'] = df.date.dt.month df['day_of_month'] = df.date.dt.day df['week_of_year'] = df.date.dt.isocalendar().week df['day_of_week'] = df.date.dt.weekday # Using apply&lambda for more readability: set Monday as 1 of week instead of 0 # df['day_of_week'] = df.date.dt.weekday.apply(lambda x: x + 1) df['day_of_year'] = df.date.dt.dayofyear df['quarter_of_year'] = df.date.dt.quarter df['day_name'] = df.date.dt.day_name() df['month_name'] = df.date.dt.month_name() # 判断是否为上下半年 df['year_half'] = df.month.apply(lambda x: 1 if x < 7 else 2) # 判断是否为闰年 df['is_leap_year'] = df.date.dt.is_leap_year return df# 提取2022年的日期记录df = get_calendar('2022-01-01', '2022-12-31')# 数据概况df.info()# =============================================================================# <class 'pandas.core.frame.DataFrame'># RangeIndex: 365 entries, 0 to 364# Data columns (total 13 columns):# # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 date 365 non-null datetime64[ns]# 1 date_id 365 non-null int64 # 2 year 365 non-null int64 # 3 month 365 non-null int64 # 4 day_of_month 365 non-null int64 # 5 week_of_year 365 non-null UInt32 # 6 day_of_week 365 non-null int64 # 7 day_of_year 365 non-null int64 # 8 quarter_of_year 365 non-null int64 # 9 day_name 365 non-null object # 10 month_name 365 non-null object # 11 year_half 365 non-null int64 # 12 is_leap_year 365 non-null bool # dtypes: UInt32(1), bool(1), datetime64[ns](1), int64(8), object(2)# memory usage: 33.6+ KB# # =============================================================================# 查看前5行记录df.head()# =============================================================================# Out[143]: # date date_id year ... month_name year_half is_leap_year# 0 2022-01-01 0 2022 ... January 1 False# 1 2022-01-02 1 2022 ... January 1 False# 2 2022-01-03 2 2022 ... January 1 False# 3 2022-01-04 3 2022 ... January 1 False# 4 2022-01-05 4 2022 ... January 1 False# =============================================================================# 查看后5行记录df.tail()# =============================================================================# Out[144]: # date date_id year ... month_name year_half is_leap_year# 360 2022-12-27 360 2022 ... December 2 False# 361 2022-12-28 361 2022 ... December 2 False# 362 2022-12-29 362 2022 ... December 2 False# 363 2022-12-30 363 2022 ... December 2 False# 364 2022-12-31 364 2022 ... December 2 False# =============================================================================# 找一条记录查看所有列的信息df.iloc[122, :]# =============================================================================# Out[145]: # date 2022-05-03 00:00:00# date_id 122# year 2022# month 5# day_of_month 3# week_of_year 18# day_of_week 1# day_of_year 123# quarter_of_year 2# day_name Tuesday# month_name May# year_half 1# is_leap_year False# Name: 122, dtype: object# =============================================================================# 调整计算每周的第几日的计算规则,使结果更符合人的理解,默认情况下从0开始。# 如,星期一为第一天,取值为1。# 对比上面的结果,2022年5月3日,是第18周的星期二,第二天。df.date.dt.weekday.apply(lambda x: x + 1).iloc[122]# =============================================================================# Out[147]: 2# =============================================================================# 输出Calendar结果到Excelos.chdir('D:/21_SuccessFactor/Python Training')df.to_excel('calendar_table.xlsx', 'calendar')数据结果如下图所示:
Excel 数据
总结本次练习主要用到下面的方法:
pd.Series.dt.year获取年份数值pd.Series.dt.month获取月份数值pd.Series.dt.day获取当月日数值pd.Series.dt.isocalendar().week获取自然周的数值pd.Series.dt.weekday获取当前日期在本周的天数(周一从数字0开始)pd.Series.dt.dayofyear获取当前日期在自然年的天数pd.Series.dt.quarter获取当前日期对应的季度数值pd.Series.dt.day_name()获取当前日期在本周的名称pd.Series.dt.month_name()获取当前日期对应的月名称pd.Series.dt.is_leay_year判断是否为闰年通过apply方法和lambda匿名函数判断上下半年特别注意
df.date.dt.weekofyear
<ipython-input-167-6f6ca36b1b62>:1: FutureWarning: Series.dt.weekofyear and Series.dt.week have been deprecated. Please use Series.dt.isocalendar().week instead.
pd.Series.dt.weekofyear,和pd.Series.dt.week两个方法已经过时,需要通过pd.Series.dt.isocalendar().week替换。
参考资料:
https://pandas.pydata.org/pandas-docs/stable/reference/series.html
接下来的安排
接下来,我将会通过PostgreSQL,SQLServer以及PowerBI分别实现生成Calendar日历表的过程,各位敬请期待。