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
相关产品推荐
相关产品推荐

