Pandas快速提取历史数据技巧
时间:2025-11-06 22:33:34 280浏览 收藏
在数据分析领域,尤其是时间序列分析中,经常需要对比当前数据与历史同期数据,以洞察趋势和评估绩效。本文针对 Pandas 库在直接获取历史同期值并计算变化量方面的局限性,提供了一个通用的解决方案。通过结合 `pd.DateOffset` 进行日期偏移,以及 `df.merge` 进行数据合并,可以灵活高效地提取任意指定月份前的历史数据,并计算绝对变化量和百分比变化量。该方法避免了手动处理的复杂性和潜在错误,为时间序列分析提供了强大的数据准备能力,适用于需要对比“去年同期”或“上上个月”具体数值的场景。通过本文提供的代码示例,读者可以轻松实现对 DataFrame 历史数据的提取和分析,从而更有效地进行时间序列数据的挖掘和利用。

本教程详细介绍了如何利用 Pandas 库高效地从 DataFrame 中提取指定历史同期的数据,并计算相应的绝对变化量和百分比变化量。通过结合 `pd.DateOffset` 进行日期偏移和 `df.merge` 进行数据合并,我们能够灵活地获取任意前推月份的历史数据,为时间序列分析提供强大的数据准备能力,避免了手动处理带来的复杂性和错误。
引言
在数据分析领域,尤其是进行时间序列数据分析时,经常需要将当前数据与历史同期数据进行比较,例如与上个月、上季度或去年同期的数据进行对比,以洞察趋势、评估绩效或识别异常。Pandas 库提供了强大的数据处理能力,但直接获取精确的历史同期值并计算其变化量,对于初学者而言可能会遇到挑战。本文将提供一个通用的解决方案,通过自定义函数和 Pandas 的核心功能,实现灵活、高效的历史同期数据提取与分析。
挑战与 Pandas .pct_change() 的局限性
Pandas 内置的 .pct_change() 方法可以方便地计算相邻时间点之间的百分比变化。然而,它的主要局限在于只能计算紧邻的或基于固定周期(如 periods=1)的变化,而无法直接获取任意指定月份(如 3 个月前、12 个月前)的精确原始值进行比较。当我们需要获取的是“去年同期”或“上上个月”的具体数值,而非仅仅是其变化率时,就需要更精细的数据处理方法。
核心思路:日期偏移与数据合并
解决此问题的核心策略是:
- 日期偏移: 为 DataFrame 中的每个日期计算出其对应的历史同期日期(例如,当前日期减去 N 个月)。
- 数据合并: 将原始 DataFrame 与其自身进行合并,通过将当前日期的“历史同期日期”与原始 DataFrame 的“实际日期”进行匹配,从而将历史同期的数据引入到当前行。
实施步骤与代码示例
我们将通过一个具体的 Python 脚本来演示如何实现这一功能。假设我们有一个包含 URL、关键词、流量和日期的数据集,目标是为每个数据点添加其 1 个月前和 12 个月前的关键词和流量数据。
1. 数据准备
首先,我们需要导入必要的库,并加载示例数据。数据加载后,关键步骤是将日期列转换为 Pandas 的日期时间格式,并按日期降序排序,这有助于后续的理解和处理,尽管对于 merge 操作并非严格要求排序。
import pandas as pd
import io
# 示例输入数据
INPUT_CSV = """
URL,Organic Keywords,Organic Traffic,Date
https://www.example-url.com/,1315,11345,20231115
https://www.example-url.com/,1183,5646,20231015
https://www.example-url.com/,869,5095,20230915
https://www.example-url/,925,4574,20230815
https://www.example-url/,899,4580,20230715
https://www.example-url/,1382,5720,20230615
https://www.example-url/,1171,5544,20230515
https://www.example-url/,1079,5041,20230415
https://www.example-url/,734,3855,20230315
https://www.example-url/,853,3455,20230215
https://www.example-url/,840,2343,20230115
https://www.example-url/,325,2318,20221215
https://www.example-url/,156,1981,20221115
https://www.example-url/,166,2059,20221015
https://www.example-url/,124,1977,20220915
https://www.example-url/,98,1919,20220815
https://www.example-url/,167,1796,20220715
https://www.example-url/,140,1596,20220615
https://www.example-url/,168,1493,20220515
https://www.example-url/,171,1058,20220415
https://www.example-url/,141,1735,20220315
https://www.example-url/,129,1836,20220215
https://www.example-url/,141,746,20220115
https://www.example-url/,129,1076,20211215
"""
# 定义常量
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] # 需要计算的历史同期周期(月)
# 读取CSV数据
df = pd.read_csv(io.StringIO(INPUT_CSV))
# 重新排序列,确保关键列在前
df = df[INITIAL_COL_REORDER]
# 将日期列转换为datetime对象
df[DATE_COL] = pd.to_datetime(df[DATE_COL], format='%Y%m%d')
# 按日期降序排序
df = df.sort_values(by=DATE_COL, ascending=False)
print("原始数据(前5行):")
print(df.head())2. 构建 get_last_period_values 辅助函数
这个函数是实现核心逻辑的关键。它接收 DataFrame、要回溯的月份数、指标列、维度列和日期列作为参数。
def get_last_period_values(df, months_prior, metric_cols, dimension_cols, date_col):
df_copy = df.copy() # 创建副本以避免修改原始DataFrame
# 1. 计算历史同期日期
# 使用 pd.DateOffset(months=months_prior) 从当前日期减去指定月份
df_copy[f'{date_col}_Prior'] = df_copy[date_col] - pd.DateOffset(months=months_prior)
# 2. 将原始DataFrame与自身合并
# left_on: 当前DataFrame中的计算出的历史同期日期
# right_on: 原始DataFrame中的实际日期
# 此外,我们还通过 'URL' (dimension_cols) 进行匹配,确保比较的是同一URL的数据
# suffixes: 用于区分合并后同名列(当前值和历史值)的后缀
df_copy = df_copy.merge(
df_copy[[date_col] + dimension_cols + metric_cols], # 右侧DataFrame选择的列
left_on=[f'{date_col}_Prior'] + dimension_cols, # 左侧合并键
right_on=[date_col] + dimension_cols, # 右侧合并键
how='left', # 使用左连接,保留所有当前数据,没有历史数据则填充NaN
suffixes=('', f'_{months_prior}mo_Prior') # 左侧列无后缀,右侧列添加后缀
)
# 3. 清理辅助列
# 移除用于合并的临时历史日期列以及合并时产生的维度列(因为原始维度列已存在)
df_copy = df_copy.drop(columns=[f'{date_col}_Prior'] + [col + f'_{months_prior}mo_Prior' for col in dimension_cols])
# 4. 计算绝对变化量和百分比变化量
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_copymerge 操作详解:
- left_on=[f'{date_col}_Prior'] + dimension_cols: 这是左侧(当前 DataFrame)用于匹配的键。它包括了我们计算出的历史同期日期和维度列(如 'URL')。
- right_on=[date_col] + dimension_cols: 这是右侧(原始 DataFrame)用于匹配的键。它包括了原始日期列和维度列。
- how='left': 确保所有当前数据行都被保留。如果某个日期的历史同期数据不存在,则对应的历史值列将填充 NaN。
- suffixes=('', f'_{months_prior}mo_Prior'): 当合并导致列名冲突时,Pandas 会自动添加后缀。这里我们指定左侧(当前数据)列名不变,右侧(历史数据)列名添加 _Xmo_Prior 后缀。例如,Organic Keywords 变成 Organic Keywords_1mo_Prior。需要注意的是,如果 date_col 也被选入右侧的列中,且与左侧的 date_col 冲突,它也会被加上后缀,即生成 Date_Xmo_Prior。
3. 整合多个周期计算的函数
为了方便地计算多个历史同期周期的数据,我们可以再封装一个函数。
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_copy4. 主脚本执行
现在,我们可以将所有部分组合起来,执行主脚本。
if __name__ == '__main__':
# 已经完成了数据加载和预处理
# df = pd.read_csv(io.StringIO(INPUT_CSV))
# 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)
# 调用整合函数计算所有指定周期的历史数据
df_final = get_period_values(df, PERIODS, METRIC_COLS, DIMENSION_COLS, DATE_COL)
# 显示最终结果
print("\n最终结果DataFrame(前5行):")
print(df_final.head())
# 打印所有列,检查输出
print("\n最终结果DataFrame所有列:")
print(df_final.columns.tolist())运行上述代码,你将得到一个包含原始数据、1个月前、3个月前、12个月前的关键词和流量数据,以及它们对应的绝对变化和百分比变化的完整 DataFrame。
示例输出(部分)
最终结果DataFrame(前5行):
URL Date Organic Keywords Organic Traffic \
0 https://www.example-url/ 2023-11-15 1315 11345
1 https://www.example-url/ 2023-10-15 1183 5646
2 https://www.example-url/ 2023-09-15 869 5095
3 https://www.example-url/ 2023-08-15 925 4574
4 https://www.example-url/ 2023-07-15 899 4580
Date_1mo_Prior Organic Keywords_1mo_Prior Organic Traffic_1mo_Prior \
0 2023-10-15 1183.0 5646.0
1 2023-09-15 869.0 5095.0
2 2023-08-15 925.0 4574.0
3 2023-07-15 899.0 4580.0
4 2023-06-15 1382.0 5720.0
Organic Keywords_1mo_Abs_Change Organic Keywords_1mo_Pct_Change \
0 132.0 0.11
1 314.0 0.36
2 -56.0 -0.06
3 26.0 0.00
4 -483.0 -0.35
Organic Traffic_1mo_Abs_Change Organic Traffic_1mo_Pct_Change \
0 5699.0 1.01
1 551.0 0.11
2 521.0 0.11
3 -6.0 0.00
4 -1140.0 -0.20
Date_3mo_Prior Organic Keywords_3mo_Prior Organic Traffic_3mo_Prior \
0 2023-08-15 925.0 4574.0
1 2023-07-15 899.0 4580.0
2 2023-06-15 1382.0 5720.0
3 2023-05-15 1171.0 5544.0
4 2023-04-15 1079.0 5041.0
Organic Keywords_3mo_Abs_Change Organic Keywords_3mo_Pct_Change \
0 390.0 0.42
1 284.0 0.32
2 -513.0 -0.37
3 -246.0 -0.21
4 -180.0 -0.17
Organic今天关于《Pandas快速提取历史数据技巧》的内容就介绍到这里了,是不是学起来一目了然!想要了解更多关于的内容请关注golang学习网公众号!
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
142 收藏
-
259 收藏
-
113 收藏
-
327 收藏
-
358 收藏
-
340 收藏
-
365 收藏
-
391 收藏
-
392 收藏
-
105 收藏
-
442 收藏
-
291 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习