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

Pandas更新后问卷脚本无法保留受访者得分及全部响应问题

问题描述

现有一款问卷脚本,规则如下:

  • 为最快作答的受访者发放积分奖励
  • 对规定时间内答对的受访者额外加1分

升级至最新Pandas库后,规定时间内答对加1分的功能失效;将原代码中的append方法替换为concat方法后,脚本可运行但无法保留全部响应。


得分处理代码片段

if len(repHolder) > 0:

    repHolder.columns = ['name', 'points', 'time']

    repHolder = repHolder.sort_values('time').reset_index(drop=True)
    repHolder.loc[:, 'time'] = repHolder.loc[:, 'time'].apply(
        lambda x: (datetime.utcfromtimestamp(x) + timedelta(hours=-4)).strftime("%I:%M:%S %p"))

    # 保留每位参与者的首次响应
    minDate = repHolder.groupby('name').min()['time'].reset_index()
    repHolder = repHolder.merge(minDate)

    # 同分情况下按时间而非姓名排序计分
    timeHolder = repHolder.loc[repHolder['points'], ['time']].drop_duplicates().reset_index(drop=True)
    timeHolder['points'] = 0

    corHolder = 0
    for idx3, row in enumerate(timeHolder.iterrows()):
        if corHolder == 0:
            timeHolder.loc[idx3, 'points'] = 1
            corHolder = 1
        elif corHolder == 1:
            timeHolder.loc[idx3, 'points'] = 1
            corHolder = 2
        elif corHolder == 2:
            timeHolder.loc[idx3, 'points'] = 1
            corHolder = 3
        else:
            timeHolder.loc[idx3, 'points'] = 1

    repHolder = repHolder.merge(timeHolder, on='time', how='left')
    repHolder['points'] = (repHolder['points_x'] * repHolder['points_y'])
    repHolder.loc[repHolder['points'].isnull(), 'points'] = 0

    print('scored winners')

    repHolder = repHolder.sort_values('points', ascending=False)

    repHolder['qTime'] = (datetime.utcfromtimestamp(qCom.created_utc) + timedelta(hours=-4)).strftime(
        "%I:%M:%S %p")
    repHolder['deltaTime'] = pd.to_datetime(repHolder['time']) - pd.to_datetime(repHolder['qTime'])

    repHolder['points'] = repHolder['points'] + repHolder[['deltaTime', 'points']]. \
        apply(lambda x: 1 if (x['deltaTime'].seconds <= 30) and (x['points'] == 1) else 0, axis=1)

    print(repHolder)

    winHolder = pd.concat([winHolder, repHolder])

代码更新对比

原代码(使用append)

if not reply.author == None and not reply.banned_by:
    repTab = pd.DataFrame([[reply.author.name, gottem, reply.created_utc]])
    repHolder = repHolder.append(repTab)

更新后代码(替换为concat)

if not reply.author == None and not reply.banned_by:
    repTab = pd.DataFrame([[reply.author.name, gottem, reply.created_utc]])
    repHolder = pd.concat([repTab])

问题分析与修复方案

1. concat替换append后丢失响应的问题

原代码中repHolder.append(repTab)是将新数据追加到已有数据集后,但更新后的pd.concat([repTab])仅保留当前的repTab,完全覆盖了历史的repHolder数据,导致之前的响应全部丢失。

修复代码:

if not reply.author == None and not reply.banned_by:
    repTab = pd.DataFrame([[reply.author.name, gottem, reply.created_utc]])
    # 同时传入原数据集和新数据,实现追加效果
    repHolder = pd.concat([repHolder, repTab], ignore_index=True)
  • 必须将原repHolder和新repTab同时放入concat的列表参数中
  • 添加ignore_index=True避免索引冲突

2. 规定时间内答对加1分功能失效的问题

原代码存在两个核心问题:

  • 提前将time转换为字符串格式,后续用pd.to_datetime解析计算时间差时,可能出现格式或时区解析错误
  • 加1分的逻辑中,apply函数引用了正在更新的points字段,存在循环依赖

修复后的得分处理代码片段:

if len(repHolder) > 0:

    repHolder.columns = ['name', 'points', 'time']

    # 先保留时间戳数值,延迟转换为字符串
    repHolder = repHolder.sort_values('time').reset_index(drop=True)

    # 保留每位参与者的首次响应
    minDate = repHolder.groupby('name').min()['time'].reset_index()
    repHolder = repHolder.merge(minDate)

    # 同分情况下按时间而非姓名排序计分(简化循环逻辑)
    timeHolder = repHolder.loc[repHolder['points'], ['time']].drop_duplicates().reset_index(drop=True)
    timeHolder['points'] = 1  # 所有符合条件的时间节点都计1分,无需循环判断

    repHolder = repHolder.merge(timeHolder, on='time', how='left')
    repHolder['points'] = (repHolder['points_x'] * repHolder['points_y'])
    repHolder.loc[repHolder['points'].isnull(), 'points'] = 0

    print('scored winners')

    repHolder = repHolder.sort_values('points', ascending=False)

    # 统一处理问卷发布时间的时区转换
    qTime_dt = datetime.utcfromtimestamp(qCom.created_utc) + timedelta(hours=-4)
    repHolder['qTime'] = qTime_dt.strftime("%I:%M:%S %p")
    
    # 直接用时间戳计算时间差,避免字符串解析错误
    repHolder['deltaTime'] = (datetime.utcfromtimestamp(repHolder['time']) + timedelta(hours=-4)) - qTime_dt

    # 保存基础积分,避免循环引用
    repHolder['base_points'] = repHolder['points']
    repHolder['points'] = repHolder['base_points'] + repHolder.apply(
        lambda x: 1 if (x['deltaTime'].seconds <= 30) and (x['base_points'] == 1) else 0, axis=1
    )
    repHolder.drop('base_points', axis=1, inplace=True)

    # 最后将时间戳转换为字符串格式
    repHolder['time'] = repHolder['time'].apply(
        lambda x: (datetime.utcfromtimestamp(x) + timedelta(hours=-4)).strftime("%I:%M:%S %p")
    )

    print(repHolder)

    winHolder = pd.concat([winHolder, repHolder], ignore_index=True)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 17:33:23