如何更优雅地在Pandas DataFrame中分类并比较日期时间列?
寻找更Pythonic的方式统计两个时间段的独立访问次数
我有一个包含VisitDate(日期时间列)和VisitID(访问ID列)的DataFrame,需要对比两个时间段内的独立访问次数。目前的实现代码能得到正确结果,但写法不够Pythonic,想了解更优的实现方式。
输入数据
| VisitID | 访问日期 |
|---|---|
| 1 | 1/1/2023 |
| 2 | 2/1/2023 |
| 4 | 3/1/2023 |
| 5 | 4/1/2023 |
| 6 | 5/1/2023 |
现有实现代码
import pandas as pd df = pd.DataFrame({"VisitID":['1', '2', '4', '5', '6'], "VisitDate": ['1/1/2023', '2/1/2023', '3/1/2023', '4/1/2023', '5/1/2023']}) df['VisitDate'] = pd.to_datetime(df['VisitDate']) # 划分3个日期分类 df["Categorize Date Range"] = pd.cut(df['VisitDate'], bins=[pd.Timestamp("1/1/2023"), pd.Timestamp("2/2/2023"), pd.Timestamp("3/31/2023"), pd.Timestamp("5/1/2023")], labels=['Dates: 1/1/2023 - 2/1/2023', 0, "Dates: 4/1/2023 - 5/1/2023"], include_lowest=True, right=True) # 过滤掉无关的日期分类 df = df[(df['Categorize Date Range'] != 0) & (df['Categorize Date Range'].notnull())].copy() # 统计每个分类的独立访问次数 df.groupby(['Categorize Date Range'])['VisitID'].nunique()
现有代码输出
| index | VisitID |
|---|---|
| Dates: 1/1/2023 - 2/1/2023 | 2 |
| Dates: 4/1/2023 - 5/1/2023 | 2 |
优化实现方式
方式一:用np.select生成分组标签并过滤
直接定义目标时间段的条件和对应标签,避免冗余的中间分类(比如原代码中的0标签),逻辑更清晰:
import pandas as pd import numpy as np df = pd.DataFrame({"VisitID":['1', '2', '4', '5', '6'], "VisitDate": ['1/1/2023', '2/1/2023', '3/1/2023', '4/1/2023', '5/1/2023']}) df['VisitDate'] = pd.to_datetime(df['VisitDate']) # 定义目标时间段条件与对应标签 conditions = [ df['VisitDate'].between('2023-01-01', '2023-02-01'), df['VisitDate'].between('2023-04-01', '2023-05-01') ] labels = ['Dates: 1/1/2023 - 2/1/2023', 'Dates: 4/1/2023 - 5/1/2023'] # 生成分组列,不符合条件的标记为NaN df['period'] = np.select(conditions, labels, default=np.nan) # 过滤无效行并统计独立访问数 result = df.dropna(subset=['period']).groupby('period')['VisitID'].nunique()
方式二:一步到位,无需新增中间列
如果不想在DataFrame中新增列,可以直接在groupby中使用np.select,代码更紧凑:
import pandas as pd import numpy as np df = pd.DataFrame({"VisitID":['1', '2', '4', '5', '6'], "VisitDate": ['1/1/2023', '2/1/2023', '3/1/2023', '4/1/2023', '5/1/2023']}) df['VisitDate'] = pd.to_datetime(df['VisitDate']) result = df.groupby( np.select( [ df['VisitDate'].between('2023-01-01', '2023-02-01'), df['VisitDate'].between('2023-04-01', '2023-05-01') ], ['Dates: 1/1/2023 - 2/1/2023', 'Dates: 4/1/2023 - 5/1/2023'], default=np.nan ) )['VisitID'].nunique().dropna()
优化说明
这两种方式都去掉了原代码中冗余的分类标签和后续过滤步骤,直接聚焦于需要统计的时间段,代码逻辑更直观,也更符合Pythonic的简洁风格。
内容的提问来源于stack exchange,提问作者Yisroel Len
相关产品推荐
相关产品推荐

