通过窗口函数释放时间序列数据的力量。本指南涵盖了数据分析的基本概念、实践案例和高级技巧。
时间序列分析:掌握窗口函数以获取数据洞见
时间序列数据,以其顺序性和时间依赖性为特征,在各行各业中无处不在。从追踪股票价格、监控网站流量,到分析传感器读数和预测销售趋势,从时间序列数据中提取有意义的洞见对于做出明智决策至关重要。窗口函数提供了一套强大而灵活的工具集,用于对与当前行相关的一组行进行计算,使其成为时间序列分析中不可或缺的工具。
理解时间序列数据
时间序列数据是按时间顺序索引的一系列数据点。这些数据点可以代表各种指标,例如:
- 金融数据:股票价格、汇率、交易量
- 销售数据:各种产品的每日、每周或每月销售数据
- 传感器数据:温度读数、压力测量、湿度水平
- 网站流量数据:网站访问量、页面浏览量、跳出率
- 能源消耗数据:每小时或每日的电力使用量
分析时间序列数据涉及识别模式、趋势和季节性,这些可用于预测未来值、检测异常和优化业务流程。
窗口函数简介
窗口函数,也称为窗口聚合或分析函数,允许您对与当前行相关的一组行进行计算,而无需像传统的聚合函数(如 SUM, AVG, COUNT)那样将行分组为单个结果集。此功能对于时间序列分析特别有用,因为您经常需要计算移动平均、累积总和和其他基于时间的指标。
一个窗口函数通常由以下几个部分组成:
- 函数:要执行的计算(例如,AVG, SUM, RANK, LAG)。
- OVER 子句:定义用于计算的行窗口。
- PARTITION BY 子句(可选):将数据划分为分区,窗口函数独立应用于每个分区。
- ORDER BY 子句(可选):指定每个分区内行的顺序。
- ROWS/RANGE 子句(可选):定义窗口框架,即相对于当前行用于计算的一组行。
关键概念与语法
1. The OVER() Clause
OVER()
子句是窗口函数的核心。它定义了函数将要操作的行窗口。一个不带任何参数的简单 OVER()
子句会将整个结果集视为窗口。例如:
SQL 示例:
SELECT
date,
sales,
AVG(sales) OVER()
FROM
sales_data;
此查询计算了 sales_data
表中所有日期的平均销售额。
2. PARTITION BY
PARTITION BY
子句将数据划分为分区,窗口函数分别应用于每个分区。当您想为数据中的不同组计算指标时,这非常有用。
SQL 示例:
SELECT
date,
product_id,
sales,
AVG(sales) OVER (PARTITION BY product_id)
FROM
sales_data;
此查询分别计算每个产品的平均销售额。
3. ORDER BY
ORDER BY
子句指定每个分区内行的顺序。这对于计算运行总计、移动平均和其他基于时间的指标至关重要。
SQL 示例:
SELECT
date,
sales,
SUM(sales) OVER (ORDER BY date)
FROM
sales_data;
此查询计算了随时间变化的销售额的累积总和。
4. ROWS/RANGE
ROWS
和 RANGE
子句定义了窗口框架,即相对于当前行用于计算的一组行。ROWS
子句根据物理行号指定窗口框架,而 RANGE
子句则根据 ORDER BY
列的值指定窗口框架。
ROWS 示例:
SELECT
date,
sales,
AVG(sales) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
FROM
sales_data;
此查询计算了过去3天(包括当天)的销售移动平均值。
RANGE 示例:
SELECT
date,
sales,
AVG(sales) OVER (ORDER BY date RANGE BETWEEN INTERVAL '2' DAY PRECEDING AND CURRENT ROW)
FROM
sales_data;
此查询计算了过去2天(包括当天)的销售移动平均值。请注意,`RANGE` 需要一个数值或日期/时间数据类型的排序列。
时间序列分析中常用的窗口函数
1. 滚动/移动平均
滚动平均,也称为移动平均,是一种广泛使用的技术,用于平滑时间序列数据中的短期波动并突显长期趋势。它通过对指定时间窗口内的值求平均来计算。
SQL 示例:
SELECT
date,
sales,
AVG(sales) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_average_7_days
FROM
sales_data;
此查询计算了7天销售移动平均值。
Python 示例 (使用 Pandas):
import pandas as pd
# Assuming you have a Pandas DataFrame called 'sales_df' with 'date' and 'sales' columns
sales_df['moving_average_7_days'] = sales_df['sales'].rolling(window=7).mean()
全球应用示例:一家跨国零售商可以使用30天移动平均来平滑每日销售波动,并识别不同地区的潜在销售趋势。
2. 累积求和
累积求和,也称为运行总计,计算截至当前行的值的总和。它对于跟踪随时间累积的总价值非常有用。
SQL 示例:
SELECT
date,
sales,
SUM(sales) OVER (ORDER BY date) AS cumulative_sales
FROM
sales_data;
此查询计算了随时间变化的销售额的累积总和。
Python 示例 (使用 Pandas):
import pandas as pd
# Assuming you have a Pandas DataFrame called 'sales_df' with 'date' and 'sales' columns
sales_df['cumulative_sales'] = sales_df['sales'].cumsum()
全球应用示例:一家国际电子商务公司可以使用累积销售额来跟踪新产品在不同市场发布后产生的总收入。
3. Lead 和 Lag
LEAD
和 LAG
函数允许您分别访问后续行或前序行的数据。它们对于计算周期性变化、识别趋势以及比较不同时间段的值非常有用。
SQL 示例:
SELECT
date,
sales,
LAG(sales, 1, 0) OVER (ORDER BY date) AS previous_day_sales,
sales - LAG(sales, 1, 0) OVER (ORDER BY date) AS sales_difference
FROM
sales_data;
此查询计算了与前一天相比的销售差额。`LAG(sales, 1, 0)` 函数检索前一行的销售值(偏移量为1),如果没有前一行(例如第一行),则返回0(默认值)。
Python 示例 (使用 Pandas):
import pandas as pd
# Assuming you have a Pandas DataFrame called 'sales_df' with 'date' and 'sales' columns
sales_df['previous_day_sales'] = sales_df['sales'].shift(1)
sales_df['sales_difference'] = sales_df['sales'] - sales_df['previous_day_sales'].fillna(0)
全球应用示例:一家全球航空公司可以使用 lead 和 lag 函数来比较同一航线在不同周的机票销售情况,并识别潜在的需求波动。
4. Rank 和 Dense Rank
RANK()
和 DENSE_RANK()
函数根据指定的排序为分区内的每一行分配一个排名。RANK()
分配的排名有间隙(例如,1, 2, 2, 4),而 DENSE_RANK()
分配的排名没有间隙(例如,1, 2, 2, 3)。
SQL 示例:
SELECT
date,
sales,
RANK() OVER (ORDER BY sales DESC) AS sales_rank,
DENSE_RANK() OVER (ORDER BY sales DESC) AS sales_dense_rank
FROM
sales_data;
此查询按降序对销售值进行排名。
全球应用示例:一个全球在线市场可以使用排名函数来识别每个国家或地区的畅销产品。
高级技巧与应用
1. 组合窗口函数
可以组合窗口函数以执行更复杂的计算。例如,您可以计算累积总和的移动平均值。
SQL 示例:
SELECT
date,
sales,
AVG(cumulative_sales) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_average_cumulative_sales
FROM
(
SELECT
date,
sales,
SUM(sales) OVER (ORDER BY date) AS cumulative_sales
FROM
sales_data
) AS subquery;
2. 将窗口函数与条件聚合结合使用
您可以将窗口函数与条件聚合(例如,使用 CASE
语句)结合使用,以根据特定条件执行计算。
SQL 示例:
SELECT
date,
sales,
AVG(CASE WHEN sales > 100 THEN sales ELSE NULL END) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_average_high_sales
FROM
sales_data;
此查询仅计算销售额大于100的日子的销售移动平均值。
3. 时间序列分解
窗口函数可用于将时间序列分解为其趋势、季节性和残差部分。这涉及计算移动平均以估计趋势,识别季节性模式,然后减去趋势和季节性部分以获得残差。
4. 异常检测
窗口函数可通过计算移动平均和标准差来检测时间序列数据中的异常。落在某个范围之外的数据点(例如,与移动平均值相差+/- 3个标准差)可以被标记为异常。
跨行业实践案例
1. 金融
- 股价分析:计算股票价格的移动平均值以识别趋势和潜在的买卖信号。
- 风险管理:计算投资组合回报的滚动标准差以评估波动性和风险。
- 欺诈检测:通过将当前交易金额与历史平均值进行比较来识别异常交易模式。
2. 零售
- 销售预测:使用移动平均和累积销售数据来预测未来的销售趋势。
- 库存管理:通过分析过去的销售数据和识别季节性模式来优化库存水平。
- 客户细分:根据客户随时间的购买行为对其进行细分。
3. 制造业
- 预测性维护:使用设备的传感器数据来预测潜在故障并主动安排维护。
- 质量控制:监控生产过程并识别与预期性能的偏差。
- 流程优化:分析生产数据以识别瓶颈并优化制造流程。
4. 医疗保健
- 患者监测:随时间监测患者的生命体征并检测可能指示健康问题的异常。
- 疾病爆发检测:跟踪疾病的传播并识别潜在的爆发。
- 医疗资源分配:根据患者需求和历史需求模式分配资源。
选择合适的工具
窗口函数可用于各种数据处理工具和编程语言,包括:
- SQL:大多数现代关系数据库管理系统(RDBMS)都支持窗口函数,包括 PostgreSQL、MySQL(8.0+版本)、SQL Server、Oracle 和 Amazon Redshift。
- Python:Pandas 库通过
rolling()
和expanding()
方法为窗口函数提供了出色的支持。 - Spark:Apache Spark 的 SQL 和 DataFrame API 也支持窗口函数。
工具的选择取决于您的具体需求和技术专长。SQL 非常适合存储在关系数据库中的数据,而 Python 和 Spark 更灵活,适用于处理大型数据集和执行复杂分析。
最佳实践
- 理解数据:在应用窗口函数之前,要彻底了解您的时间序列数据的特性,包括其频率、季节性和潜在的异常值。
- 选择合适的窗口大小:窗口大小的选择取决于您正在执行的具体分析。较小的窗口大小对短期波动更敏感,而较大的窗口大小会平滑数据并突显长期趋势。
- 考虑边界情况:注意窗口函数如何处理边界情况,例如缺失数据或时间序列的开始和结束。使用适当的默认值或过滤技术来处理这些情况。
- 优化性能:窗口函数可能计算成本高昂,尤其是在处理大型数据集时。优化您的查询和代码以提高性能,例如使用适当的索引和分区策略。
- 记录您的代码:清晰地记录您的代码和查询,以解释窗口函数的目的和逻辑。这将使其他人更容易理解和维护您的代码。
结论
窗口函数是时间序列分析的强大工具,使您能够计算移动平均、累积总和、lead/lag 值以及其他基于时间的指标。通过掌握窗口函数,您可以从时间序列数据中解锁宝贵的洞见,并做出更明智的决策。无论您是在分析金融数据、销售数据、传感器数据还是网站流量数据,窗口函数都可以帮助您识别使用传统聚合技术难以检测的模式、趋势和异常。通过理解窗口函数的关键概念和语法并遵循最佳实践,您可以有效地利用它们来解决各个行业的各种实际问题。