使用Pandas高效统计多列日期数据在指定范围内的行数

DDD
发布: 2025-12-05 13:03:19
原创
650人浏览过

使用pandas高效统计多列日期数据在指定范围内的行数

本教程旨在解决如何高效、准确地统计Pandas DataFrame中多列日期数据在特定时间范围内的行数,这在分析多阶段流程数据时尤为常见。文章将深入探讨常见的错误做法及其原因,并提供一个基于Pandas向量化操作的优化解决方案,以实现精准的日期范围筛选和计数,最终构建出适用于漏斗分析等场景的汇总表格。

背景与问题描述

在业务流程分析中,我们经常会遇到跟踪一个记录(例如客户、订单)在不同阶段进入时间的需求。数据通常以DataFrame的形式存储,其中每一列代表一个流程阶段,每个单元格记录了该记录进入该阶段的日期。我们的目标是统计在给定日期范围内,每个阶段有多少条记录的日期落入此范围,以便进行漏斗分析,比较不同阶段的转化或流失情况。

例如,给定以下DataFrame,它展示了三条记录在三个阶段的进入日期:

stage 1 stage 2 stage 3
row 1 1/3/2023 4/3/2023 5/7/2023
row 2 2/5/2023 2/6/2023 3/4/2023
row 3 1/15/2023 6/3/2023 7/8/2023

我们希望得到一个汇总表,显示不同日期范围内每个阶段的计数,例如:

stage 1 stage 2 stage 3
1/1/2023 - 4/1/2023 2 1 1
4/1/2023 - 7/1/2023 0 2 1
7/1/2023 - 10/1/2023 0 1 1

常见误区与低效方法

初学者在处理这类问题时,常会尝试使用any(axis=1)结合日期范围筛选。例如:

import pandas as pd

# 示例数据
data = {
    'stage 1': ['1/3/2023', '2/5/2023', '1/15/2023'],
    'stage 2': ['4/3/2023', '2/6/2023', '6/3/2023'],
    'stage 3': ['5/7/2023', '3/4/2023', '7/8/2023']
}
df = pd.DataFrame(data, index=[f'row {i+1}' for i in range(3)])
df = df.apply(pd.to_datetime) # 确保日期格式正确

start = pd.to_datetime('2023-1-1')
end = pd.to_datetime('2023-3-30')
stage_cols = ['stage 1', 'stage 2', 'stage 3']

# 错误示例
# (df[stage_cols] >= start).any(axis=1) 会检查任何列是否大于等于start
# (df[stage_cols] <= end).any(axis=1) 会检查任何列是否小于等于end
# 这种方法会错误地将满足任一条件的行全部纳入计数
filtered_df_incorrect = df[(df[stage_cols] >= start).any(axis=1) & (df[stage_cols] <= end).any(axis=1)]
print("错误筛选结果的行数:\n", filtered_df_incorrect.shape[0])
# 这种筛选方式可能导致行3被计数,即使其stage 2和stage 3的日期超出了范围,
# 因为stage 1的日期满足条件,且stage 2的日期可能满足另一个条件。
# 并且,最终我们想要的是每个阶段的独立计数,而不是基于行的整体筛选。
登录后复制

这种方法的问题在于,它首先在行级别进行聚合(any(axis=1)),然后才进行逻辑与操作。这意味着只要一行中的任何一个阶段日期满足起始条件,且任何一个阶段日期满足结束条件,该行就会被选中。这无法实现对每个阶段日期进行独立的范围检查和计数。例如,对于row 3,stage 1的日期在范围内,但stage 2和stage 3的日期不在范围内。如果使用上述逻辑,row 3仍可能被错误地包含在计数中。

此外,用户可能会编写一个循环函数来逐个日期范围、逐列地进行计数,如问题中提到的funnel_by_time函数。虽然这种方法能够得到正确结果,但由于使用了Python循环,在大规模数据集上性能会比较低下,不符合Pandas的向量化操作最佳实践。

优化方案:向量化日期范围筛选与计数

Pandas提供了强大的向量化操作能力,可以高效地处理这类问题。核心思想是:先对DataFrame中的每个日期进行独立的范围检查,生成布尔矩阵,然后对该布尔矩阵按列求和。

步骤1:确保日期列为datetime类型

这是进行日期比较的前提。

import pandas as pd

data = {
    'stage 1': ['1/3/2023', '2/5/2023', '1/15/2023'],
    'stage 2': ['4/3/2023', '2/6/2023', '6/3/2023'],
    'stage 3': ['5/7/2023', '3/4/2023', '7/8/2023']
}
df = pd.DataFrame(data, index=[f'row {i+1}' for i in range(3)])

# 将所有日期列转换为datetime对象
tmp_df = df.apply(pd.to_datetime)
print("转换后的DataFrame (tmp_df):\n", tmp_df)
登录后复制

输出:

转换后的DataFrame (tmp_df):
             stage 1    stage 2    stage 3
row 1 2023-01-03 00:00:00 2023-04-03 00:00:00 2023-05-07 00:00:00
row 2 2023-02-05 00:00:00 2023-02-06 00:00:00 2023-03-04 00:00:00
row 3 2023-01-15 00:00:00 2023-06-03 00:00:00 2023-07-08 00:00:00
登录后复制

步骤2:定义日期范围并进行元素级比较

畅图
畅图

AI可视化工具

畅图 179
查看详情 畅图

定义起始日期和结束日期,然后使用Pandas的ge()(大于等于)和le()(小于等于)方法进行元素级的布尔比较。

start_date = pd.to_datetime('2023-1-1')
end_date = pd.to_datetime('2023-3-30')

# 检查每个日期是否大于等于起始日期
ge_mask = tmp_df.ge(start_date)
print("\n大于等于起始日期的布尔矩阵 (ge_mask):\n", ge_mask)

# 检查每个日期是否小于等于结束日期
le_mask = tmp_df.le(end_date)
print("\n小于等于结束日期的布尔矩阵 (le_mask):\n", le_mask)
登录后复制

输出:

大于等于起始日期的布尔矩阵 (ge_mask):
       stage 1  stage 2  stage 3
row 1     True     True     True
row 2     True     True     True
row 3     True     True     True

小于等于结束日期的布尔矩阵 (le_mask):
       stage 1  stage 2  stage 3
row 1     True    False    False
row 2     True     True     True
row 3     True    False    False
登录后复制

步骤3:结合布尔矩阵并按列求和

将两个布尔矩阵通过逻辑与操作符&结合,生成最终的布尔矩阵,其中True表示该日期在该范围内。然后,对这个最终的布尔矩阵按列求和,即可得到每个阶段在指定日期范围内的计数。

# 结合两个布尔矩阵
final_mask = ge_mask & le_mask
print("\n最终布尔矩阵 (final_mask):\n", final_mask)

# 按列求和得到每个阶段的计数
counts = final_mask.sum()
print("\n单个日期范围内的计数结果:\n", counts)
登录后复制

输出:

最终布尔矩阵 (final_mask):
       stage 1  stage 2  stage 3
row 1     True    False    False
row 2     True     True     True
row 3     True    False    False

单个日期范围内的计数结果:
 stage 1    3
stage 2    1
stage 3    1
dtype: int64
登录后复制

通过这种方法,我们可以看到stage 1有3个日期在范围内,stage 2有1个,stage 3有1个。这与预期结果一致。

构建多日期范围的汇总表

为了生成漏斗分析所需的汇总表,我们需要对多个日期范围重复上述过程,并将结果收集到一个新的DataFrame中。

import pandas as pd

# 原始数据
data = {
    'stage 1': ['1/3/2023', '2/5/2023', '1/15/2023'],
    'stage 2': ['4/3/2023', '2/6/2023', '6/3/2023'],
    'stage 3': ['5/7/2023', '3/4/2023', '7/8/2023']
}
df = pd.DataFrame(data, index=[f'row {i+1}' for i in range(3)])
tmp_df = df.apply(pd.to_datetime) # 确保日期格式正确

# 定义日期范围列表
date_ranges = [
    (pd.to_datetime('2023-1-1'), pd.to_datetime('2023-4-1')),
    (pd.to_datetime('2023-4-1'), pd.to_datetime('2023-7-1')),
    (pd.to_datetime('2023-7-1'), pd.to_datetime('2023-10-1'))
]

results = {}
for start_date, end_date in date_ranges:
    # 执行向量化筛选和计数
    ge_mask = tmp_df.ge(start_date)
    le_mask = tmp_df.lt(end_date) # 注意:这里使用lt (<) 而不是 le (<=),以确保区间不重叠且符合常规统计习惯
                                  # 如果包含结束日期,则使用le
    final_mask = ge_mask & le_mask
    counts = final_mask.sum()

    range_label = f"{start_date.strftime('%m/%d/%Y')} - {end_date.strftime('%m/%d/%Y')}"
    results[range_label] = counts.tolist() # 将Series转换为列表

# 构建最终的汇总DataFrame
output_df = pd.DataFrame.from_dict(results, orient='index', columns=tmp_df.columns)
print("\n最终漏斗分析汇总表:\n", output_df)
登录后复制

输出:

最终漏斗分析汇总表:
                        stage 1  stage 2  stage 3
01/01/2023 - 04/01/2023        2        1        1
04/01/2023 - 07/01/2023        0        2        1
07/01/2023 - 10/01/2023        0        1        1
登录后复制

请注意,在定义日期范围时,通常会使用半开区间[start, end),即包含起始日期但不包含结束日期,以避免区间重叠导致重复计数。因此,在上述代码中,我们将le_mask = tmp_df.le(end_date)改为了le_mask = tmp_df.lt(end_date)。如果业务需求是包含结束日期,则应使用le()。

注意事项与最佳实践

  1. 数据类型统一: 始终确保DataFrame中的日期列已经正确转换为Pandas的datetime类型。否则,比较操作将无法正确执行。
  2. 向量化操作: 尽可能利用Pandas的向量化操作(如apply、ge、le、sum等),避免使用Python原生的循环,以获得最佳性能。
  3. 区间定义: 明确日期范围是闭区间[start, end]、开区间(start, end)还是半开区间[start, end),并相应地选择ge/gt和le/lt进行比较。
  4. 可读性: 将复杂的逻辑分解为几个清晰的步骤(如生成布尔掩码、组合掩码、求和),可以提高代码的可读性和可维护性。
  5. 后续分析: 生成的汇总表可以直接用于可视化,例如绘制漏斗图,直观展示不同阶段的转化率。

总结

通过本教程,我们学习了如何利用Pandas的向量化能力,高效且准确地统计DataFrame中多列日期数据在指定时间范围内的行数。关键在于理解并正确应用元素级的布尔比较和列求和操作,避免了常见的筛选误区和低效的循环方法。掌握这种技术,能够有效地支持多阶段流程的性能分析和可视化需求。

以上就是使用Pandas高效统计多列日期数据在指定范围内的行数的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号