
本文详细阐述了如何利用pandas库高效地计算dataframe中指定指标的历史同期值,并进一步分析其绝对变化量和百分比变化率。通过构建可复用的函数,我们能够灵活地获取任意前n个月的数据,并将其与当前数据进行合并,为时间序列分析提供强大的数据支持。
引言
在数据分析领域,特别是对时间序列数据进行分析时,经常需要将当前数据与历史同期数据进行比较,以评估增长、下降趋势或季节性影响。例如,我们可能需要将本月销售额与上月或去年同月销售额进行对比。Pandas的pct_change()方法虽然可以计算百分比变化,但它通常用于计算连续周期(如上一行)的变化,且直接获取精确的历史同期值并不直接。本教程将介绍一种基于pd.DateOffset和merge操作的通用方法,以精确获取任意历史周期的值及其变化。
核心思路
解决此问题的核心在于以下两步:
计算目标历史日期:对于DataFrame中的每一行,根据当前日期和所需回溯的月份数,计算出对应的历史日期。这可以通过pd.DateOffset轻松实现。合并历史数据:将原始DataFrame与自身进行合并(自连接),使用当前日期的历史目标日期作为连接键,将历史数据(如指标值)引入当前行的上下文。
数据准备
首先,我们需要一个包含日期和相关指标的DataFrame。以下是一个示例数据集,我们将用它来演示。
import pandas as pdimport io# 示例输入数据INPUT_CSV = """URL,Organic Keywords,Organic Traffic,Datehttps://www.example-url.com/,1315,11345,20231115https://www.example-url.com/,1183,5646,20231015https://www.example-url.com/,869,5095,20230915https://www.example-url.com/,925,4574,20230815https://www.example-url.com/,899,4580,20230715https://www.example-url.com/,1382,5720,20230615https://www.example-url.com/,1171,5544,20230515https://www.example-url.com/,1079,5041,20230415https://www.example-url.com/,734,3855,20230315https://www.example-url.com/,853,3455,20230215https://www.example-url.com/,840,2343,20230115https://www.example-url.com/,325,2318,20221215https://www.example-url.com/,156,1981,20221115https://www.example-url.com/,166,2059,20221015https://www.example-url.com/,124,1977,20220915https://www.example-url.com/,98,1919,20220815https://www.example-url.com/,167,1796,20220715https://www.example-url.com/,140,1596,20220615https://www.example-url.com/,168,1493,20220515https://www.example-url.com/,171,1058,20220415https://www.example-url.com/,141,1735,20220315https://www.example-url.com/,129,1836,20220215https://www.example-url.com/,141,746,20220115https://www.example-url.com/,129,1076,20211215"""# 读取CSV数据df = pd.read_csv(io.StringIO(INPUT_CSV))# 定义常量,方便管理INITIAL_COL_REORDER = ['URL', 'Date', 'Organic Keywords', 'Organic Traffic']METRIC_COLS = ['Organic Keywords', 'Organic Traffic']DIMENSION_COLS = ['URL'] # 如果有多个维度,可以添加DATE_COL = 'Date'# 预处理:重排、转换日期格式、按日期降序排序df = df[INITIAL_COL_REORDER]df[DATE_COL] = pd.to_datetime(df[DATE_COL], format='%Y%m%d')df = df.sort_values(by=DATE_COL, ascending=False)print("原始数据(部分):")print(df.head())
实现 get_last_period_values 函数
这个函数是核心,它接收DataFrame、回溯月份数以及指标和维度列,并返回一个包含历史同期值的新DataFrame。
def get_last_period_values(df, months_prior, metric_cols, dimension_cols, date_col): df_copy = df.copy() # 避免修改原始DataFrame # 1. 计算目标历史日期 # 为当前日期创建一个对应的历史日期列 df_copy[f'{date_col}_Prior'] = df_copy[date_col] - pd.DateOffset(months=months_prior) # 2. 合并历史数据 # 将原始DataFrame与自身进行左连接,根据计算出的历史日期和维度列进行匹配 # suffixes 参数用于区分合并后的同名列,例如 'Organic Keywords' 会变成 'Organic Keywords_1mo_Prior' df_copy = df_copy.merge( df_copy[[date_col] + dimension_cols + metric_cols], left_on=[f'{date_col}_Prior'] + dimension_cols, # 连接键:历史日期 + 维度列 right_on=[date_col] + dimension_cols, how='left', # 左连接保留所有当前行,没有匹配的历史数据则为NaN suffixes=('', f'_{months_prior}mo_Prior') ) # 清理:删除临时创建的历史日期列和合并时产生的多余维度列 df_copy = df_copy.drop(columns=[f'{date_col}_Prior'] + [col + f'_{months_prior}mo_Prior' for col in dimension_cols]) # 3. 计算绝对变化量和百分比变化率 for metric in metric_cols: # 绝对变化 = 当前值 - 历史值 df_copy[f'{metric}_{months_prior}mo_Abs_Change'] = df_copy[metric] - df_copy[f'{metric}_{months_prior}mo_Prior'] # 百分比变化 = (当前值 / 历史值) - 1 df_copy[f'{metric}_{months_prior}mo_Pct_Change'] = df_copy[metric] / df_copy[f'{metric}_{months_prior}mo_Prior'] - 1 # 对百分比变化进行四舍五入 df_copy[f'{metric}_{months_prior}mo_Pct_Change'] = df_copy[f'{metric}_{months_prior}mo_Pct_Change'].round(2) return df_copy
函数详解:
df_copy = df.copy():进行操作前,创建一个DataFrame的副本,以避免对原始数据造成意外修改。df_copy[f'{date_col}_Prior’] = df_copy[date_col] – pd.DateOffset(months=months_prior):这一行是关键。pd.DateOffset(months=months_prior)会从date_col中的每个日期减去指定的月份数,得到对应的历史日期。merge()操作:left_on 和 right_on:指定了连接的键。left_on使用当前DataFrame的{date_col}_Prior和dimension_cols,而right_on使用原始DataFrame的date_col和dimension_cols。这样可以确保我们找到的是同一维度(例如URL)在指定历史日期的指标值。how=’left’:这是一个左连接,意味着DataFrame中的所有当前行都会被保留。如果某个历史日期没有匹配的数据,则相应的历史指标列会填充NaN。suffixes=(”, f’_{months_prior}mo_Prior’):这个参数非常重要,它用于处理合并后出现的同名列。原始DataFrame的列保持不变,而从右侧(历史数据)合并过来的列会加上指定的后缀,例如_1mo_Prior。清理:合并完成后,{date_col}_Prior列和合并时产生的历史维度列(如URL_1mo_Prior)已经完成了它们的使命,可以安全地删除,保持DataFrame的整洁。计算变化率:最后,我们遍历所有指标列,计算其与历史同期值的绝对变化和百分比变化。百分比变化率通常会进行四舍五入以提高可读性。
泛化到多个周期
为了方便地计算多个历史周期的值,我们可以再封装一个函数 get_period_values。
def get_period_values(df, periods, metric_cols, dimension_cols, date_col): df_copy = df.copy() for period in periods: df_copy = get_last_period_values(df_copy, period, metric_cols, dimension_cols, date_col) return df_copy
这个函数接收一个periods列表(例如[1, 3, 12]),然后循环调用get_last_period_values函数,将不同历史周期的数据逐步添加到DataFrame中。
完整脚本示例
将上述所有部分整合,形成一个完整的、可运行的Python脚本。
import pandas as pdimport io## 常量定义INITIAL_COL_REORDER = ['URL', 'Date', 'Organic Keywords', 'Organic Traffic']METRIC_COLS = ['Organic Keywords', 'Organic Traffic']DIMENSION_COLS = ['URL']DATE_COL = 'Date'PERIODS = [1, 3, 12] # 需要计算的历史周期(月)INPUT_CSV = """URL,Organic Keywords,Organic Traffic,Datehttps://www.example-url.com/,1315,11345,20231115https://www.example-url.com/,1183,5646,20231015https://www.example-url.com/,869,5095,20230915https://www.example-url.com/,925,4574,20230815https://www.example-url.com/,899,4580,20230715https://www.example-url.com/,1382,5720,20230615https://www.example-url.com/,1171,5544,20230515https://www.example-url.com/,1079,5041,20230415https://www.example-url.com/,734,3855,20230315https://www.example-url.com/,853,3455,20230215https://www.example-url.com/,840,2343,20230115https://www.example-url.com/,325,2318,20221215https://www.example-url.com/,156,1981,20221115https://www.example-url.com/,166,2059,20221015https://www.example-url.com/,124,1977,20220915https://www.example-url.com/,98,1919,20220815https://www.example-url.com/,167,1796,20220715https://www.example-url.com/,140,1596,20220615https://www.example-url.com/,168,1493,20220515https://www.example-url.com/,171,1058,20220415https://www.example-url.com/,141,1735,20220315https://www.example-url.com/,129,1836,20220215https://www.example-url.com/,141,746,20220115https://www.example-url.com/,129,1076,20211215"""## 辅助函数 - 获取指定历史周期的值及其变化def get_last_period_values(df, months_prior, metric_cols, dimension_cols, date_col): df_copy = df.copy() df_copy[f'{date_col}_Prior'] = df_copy[date_col] - pd.DateOffset(months=months_prior) df_copy = df_copy.merge( df_copy[[date_col] + dimension_cols + metric_cols], left_on=[f'{date_col}_Prior'] + dimension_cols, right_on=[date_col] + dimension_cols, how='left', suffixes=('', f'_{months_prior}mo_Prior') ) df_copy = df_copy.drop(columns=[f'{date_col}_Prior'] + [col + f'_{months_prior}mo_Prior' for col in dimension_cols]) for metric in metric_cols: df_copy[f'{metric}_{months_prior}mo_Abs_Change'] = df_copy[metric] - df_copy[f'{metric}_{months_prior}mo_Prior'] df_copy[f'{metric}_{months_prior}mo_Pct_Change'] = df_copy[metric] / df_copy[f'{metric}_{months_prior}mo_Prior'] - 1 df_copy[f'{metric}_{months_prior}mo_Pct_Change'] = df_copy[f'{metric}_{months_prior}mo_Pct_Change'].round(2) return df_copy## 辅助函数 - 迭代计算多个历史周期的值def get_period_values(df, periods, metric_cols, dimension_cols, date_col): df_copy = df.copy() for period in periods: df_copy = get_last_period_values(df_copy, period, metric_cols, dimension_cols, date_col) return df_copy## 主脚本if __name__ == '__main__': # 1. 读取数据 df = pd.read_csv(io.StringIO(INPUT_CSV)) # 2. 数据预处理 df = df[INITIAL_COL_REORDER] df[DATE_COL] = pd.to_datetime(df[DATE_COL], format='%Y%m%d') df = df.sort_values(by=DATE_COL, ascending=False) # 按日期降序排序 # 3. 计算历史同期值及变化 df_final = get_period_values(df, PERIODS, METRIC_COLS, DIMENSION_COLS, DATE_COL) # 4. 显示结果 print("n最终结果 DataFrame:") print(df_final.to_string()) # 使用 to_string() 避免截断显示
输出示例(部分):
最终结果 DataFrame: URL Date Organic Keywords Organic Traffic Organic Keywords_1mo_Prior Organic Traffic_1mo_Prior Organic Keywords_1mo_Abs_Change Organic Traffic_1mo_Abs_Change Organic Keywords_1mo_Pct_Change Organic Traffic_1mo_Pct_Change Organic Keywords_3mo_Prior Organic Traffic_3mo_Prior Organic Keywords_3mo_Abs_Change Organic Traffic_3mo_Abs_Change Organic Keywords_3mo_Pct_Change Organic Traffic_3mo_Pct_Change Organic Keywords_12mo_Prior Organic Traffic_12mo_Prior Organic Keywords_12mo_Abs_Change Organic Traffic_12mo_Abs_Change Organic Keywords_12mo_Pct_Change Organic Traffic_12mo_Pct_Change0 https://www.example-url.com/ 2023-11-15 1315 11345 1183 5646 132 5699 0.11 1.01 869 5095 446 6250 0.51 1.23 156 1981 1159 9364 7.43 4.731 https://www.example-url.com/ 2023-10-15 1183 5646 869 5095 314 551 0.36 0.11 925 4574 258 1072 0.28 0.23 166 2059 1017 3587 6.13 1.74...22 https://www.example-url.com/ 2022-01-15 141 746 129 1076 12 -330 0.09 -0.31 NaN NaN NaN NaN NaN NaN 141 746 0 0 0.00 0.0023 https://www.example-url.com/ 2021-12-15 129 1076 NaN NaN NaN NaN NaN
以上就是使用Pandas计算历史同期值及变化率的通用方法的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1377425.html
微信扫一扫
支付宝扫一扫