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

如何用Pandas无循环统计用户每日新增BookId数量

无循环实现用户每日新增图书统计

原始数据

UserIdDateBookId
12022-07-1510
12022-07-1611
12022-07-1612
12022-07-1712

需求说明

统计每个用户在连续日期中每日的新增BookId数量:

  • 2022-07-16新增2本(11、12均未在之前出现)
  • 2022-07-17新增0本(12已在前一天出现)

期望结果:

UserId2022-07-162022-07-17
120

现有循环实现代码

df = studentAnswers.groupby('StudentId')
df.apply(findObjDiff)

def findObjDiff(df):
    print(df.StudentId.head(3))
    dataDict = {}
    dates = list(df.Date)
    dates.sort()
    for d in dates:
        ixNext = dates.index(d) + 1
        if(ixNext > len(dates)):
            break
        dateNext = dates[ixNext]
        objListPrev = set(df[df.Date == d].ObjectiveId)
        objListNext = set(df[df.Date == dateNext].ObjectiveId)
        dataDict[df.StudentId] = {dateNext : {'Different': len(objListPrev - objListNext)}}

    return dataDict

无循环简洁实现方案

可以利用Pandas的分组、去重、累积集合操作实现无循环统计,以下是两种简洁写法:

写法一:分步清晰实现

import pandas as pd

# 构造原始数据(实际使用时替换为你的数据源)
df = pd.DataFrame({
    'UserId': [1,1,1,1],
    'Date': ['2022-07-15','2022-07-16','2022-07-16','2022-07-17'],
    'BookId': [10,11,12,12]
})

# 1. 去重:确保每个用户每日的同一BookId只计数一次
df_unique = df.drop_duplicates(subset=['UserId', 'Date', 'BookId'])

# 2. 按用户分组,按日期排序,生成每日图书集合
df_grouped = df_unique.groupby('UserId').apply(
    lambda x: x.sort_values('Date').assign(
        daily_books=lambda y: y.groupby('Date')['BookId'].apply(set)
    )
).reset_index(drop=True)

# 3. 计算每个用户每日新增数量
def calc_new(user_df):
    read_books = set()
    new_counts = []
    for _, row in user_df.iterrows():
        # 新增数 = 当日图书 - 已读图书的数量
        new_num = len(row['daily_books'] - read_books)
        new_counts.append(new_num)
        read_books.update(row['daily_books'])
    user_df['new_books'] = new_counts
    # 排除第一天(需求只统计后续日期的新增)
    return user_df[user_df['Date'] != user_df['Date'].min()][['Date', 'new_books']]

result = df_grouped.groupby('UserId').apply(calc_new).reset_index()

# 4. 转换为宽表格式,补全0值
final_result = result.pivot(index='UserId', columns='Date', values='new_books')\
                     .fillna(0).astype(int).reset_index()
final_result.columns.name = None

print(final_result)

写法二:利用expanding简化累积集合

import pandas as pd

df = pd.DataFrame({
    'UserId': [1,1,1,1],
    'Date': ['2022-07-15','2022-07-16','2022-07-16','2022-07-17'],
    'BookId': [10,11,12,12]
})

df['Date'] = pd.to_datetime(df['Date'])
df_unique = df.drop_duplicates(['UserId', 'Date', 'BookId'])

# 按用户分组,生成每日图书集合和累积图书集合
df_grouped = df_unique.groupby('UserId').apply(
    lambda x: x.sort_values('Date').assign(
        daily_set=lambda y: y.groupby('Date')['BookId'].apply(set),
        cumulative_set=lambda y: y['daily_set'].expanding().apply(lambda s: set.union(*s))
    )
).reset_index(drop=True)

# 计算新增数量:当日集合减去前一天的累积集合
df_grouped['new_books'] = df_grouped.apply(
    lambda row: len(row['daily_set'] - (row['cumulative_set'] - row['daily_set'])),
    axis=1
)

# 过滤第一天并转换为目标格式
final_result = df_grouped[df_grouped['Date'] != df_grouped.groupby('UserId')['Date'].transform('min')] \
    .pivot(index='UserId', columns='Date', values='new_books') \
    .fillna(0).astype(int).reset_index()
final_result.columns = final_result.columns.astype(str)
final_result.columns.name = None

print(final_result)

两种写法运行后均输出:

UserId  2022-07-16  2022-07-17
0       1           2           0

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 19:20:08