如何用groupby()与for loop统计满足日期条件的空值记录数
需求实现:按月份统计符合条件的记录数
数据生成代码
import pandas as pd import numpy as np from datetime import timedelta import random # 补充原代码遗漏的导入 random.seed(365) # 生成数据 start_date = pd.date_range(start="2015-01-09", end="2022-09-11", freq="6D") end_date = [date + timedelta(days=np.random.exponential(scale=100)) for date in start_date] df = pd.DataFrame( {"start_date": start_date, "end_date": end_date} ) # 随机移除部分end_date值 df["end_date"] = df["end_date"].sample(frac=0.7).reset_index(drop=True) df["end_date"] = df["end_date"].dt.date.astype("datetime64[ns]")
生成月份第一天序列
dates = pd.Series(df["start_date"].dt.to_period("M").sort_values(ascending=True).unique()).dt.start_time
需求说明
统计每个月份第一天对应的df记录数,需同时满足两个条件:
df["start_date"]小于该月份第一天df["end_date"]为NaT(空值)
要求用**for loop结合groupby()**实现,输出格式参考:
| month_start | count |
|---|---|
| 2015-01-01 | 5 |
| 2015-02-01 | 10 |
| 2015-03-01 | 35 |
错误尝试代码
df.groupby(by=dates)[["start_date", "end_date"]].apply( lambda x: [x["start_date"] < date for date in dates] & x["end_date"].isnull == True )
正确实现方法
方式1:显式for loop遍历统计
先筛选出end_date为空的记录,再逐个遍历月份第一天统计符合条件的数量:
# 先筛选出end_date为空的子集 null_end_df = df[df["end_date"].isnull()] # 初始化结果存储列表 result_list = [] # 遍历每个月份第一天 for month_start in dates: # 统计满足start_date < 当前月份第一天的记录数 count = null_end_df[null_end_df["start_date"] < month_start].shape[0] result_list.append({"month_start": month_start, "count": count}) # 转换为DataFrame并格式化日期 result_df = pd.DataFrame(result_list) result_df["month_start"] = result_df["month_start"].dt.date.astype("datetime64[ns]") print(result_df)
输出示例(根据实际数据生成)
| month_start | count |
|---|---|
| 2015-01-01 | 0 |
| 2015-02-01 | 5 |
| 2015-03-01 | 9 |
| ... | ... |
方式2:groupby结合匹配逻辑(简化循环)
如果想减少显式循环,可通过给空值记录匹配对应月份区间,再分组统计:
null_end_df = df[df["end_date"].isnull()] # 给每个start_date匹配大于它的最小月份第一天 null_end_df["month_start"] = null_end_df["start_date"].apply( lambda x: dates[dates > x].min() if (dates > x).any() else None ) # 按月份分组统计,补全所有月份(包括count为0的) result_df = null_end_df.groupby("month_start").size().reindex(dates, fill_value=0).reset_index(name="count")
内容的提问来源于stack exchange,提问作者JoMcGee
相关产品推荐
相关产品推荐

