You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用pandas.Series.apply()与lambda函数按条件统计DataFrame列值

问题:统计每月初满足时间区间条件的记录数

这是此前相关帖子的后续内容。

数据集

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 = [s + timedelta(days=np.random.exponential(scale=100)) for s 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]")

已准备的每月初日期序列

先生成了数据全周期内每个月第一天的Series:

dates = pd.Series(df["start_date"].dt.to_period("M").sort_values(ascending=True).unique()).dt.start_time

需求

统计DataFrame中同时满足以下两个条件的行数:

  • df["start_date"] 小于dates中每个月的第一天
  • df["end_date"] 大于该月的第一天

尝试的代码

我尝试用apply结合lambda或np.logical_and实现,但写法存在问题:

# 筛选出有end_date的记录
inactives = df[df["end_date"].isnull() == False]

# 写法1
dates.apply(
    lambda x: (inactives[inactives["start_date"] < x] & inactives[inactives["cancel_date"] > x]).count()
)

# 写法2
dates.apply(
    lambda x: np.logical_and(
        inactives[inactives["start_date"] < x,
        inactives[inactives["cancel_date"] > x]]
    ).sum())

期望输出

month_firstcount
2015-01-0110
2015-02-0125
2015-03-0145

解决方法

你的尝试存在两处问题:一是误写了列名cancel_date(数据集实际列名为end_date),二是布尔索引的拼接逻辑错误。以下是两种可行的实现方式:

方法1:优化apply写法

# 筛选出有有效end_date的记录
inactives = df.dropna(subset=["end_date"])

# 对每个月初日期统计符合条件的记录数
count_result = dates.apply(lambda x: inactives[(inactives["start_date"] < x) & (inactives["end_date"] > x)].shape[0])

# 整理为期望的DataFrame格式
result_df = count_result.reset_index(drop=True).to_frame(name="count")
result_df.insert(0, "month_first", dates.dt.date)

方法2:向量化操作(大数据量更高效)

如果数据集规模较大,apply的循环效率偏低,可以用向量化广播实现:

inactives = df.dropna(subset=["end_date"])

# 将日期转为可广播的数组,批量比较
start_mask = inactives["start_date"].values[:, None] < dates.values
end_mask = inactives["end_date"].values[:, None] > dates.values

# 统计每个月初对应的符合条件的记录数
counts = (start_mask & end_mask).sum(axis=0)

# 生成结果DataFrame
result_df = pd.DataFrame({"month_first": dates.dt.date, "count": counts})

运行后即可得到符合预期格式的输出。


内容的提问来源于stack exchange,提问作者JoMcGee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:25:23