Pandas中使用apply函数基于计算值同时更新多列的实现方法及性能疑问
Pandas中使用apply函数基于计算值同时更新多列的实现方法及性能疑问
嗨,我来帮你解决这个问题!首先咱们先搞定用apply同时更新多列的需求,之后再聊聊你关心的性能问题。
一、用apply同时生成多列的解决方案
你现在的calculate_time_diff函数只返回了时间差字符串,但其实可以让它返回元组,包含秒数和格式化后的字符串,之后直接把这个元组的结果拆解到两个列里就行。另外注意你代码里有个小笔误:str_event_time定义了,但用的时候写成了str_t_zero_time,这个得先修正;还有原时间字符串里的011应该是11的手误,我也一起调整了。
修正后的完整代码
from datetime import datetime import pandas as pd # 修正笔误:变量名统一、时间格式修正 str_event_time = '2025-01-24T11:55:00.000Z' event_time = datetime.strptime(str_event_time,'%Y-%m-%dT%H:%M:%S.%fZ') def calculate_time_diff(date_time): # 计算时间差秒数 time_diff_secs = (date_time - event_time).total_seconds() # 计算时分秒格式 m, s = divmod(abs(time_diff_secs), 60) h, m = divmod(m, 60) # 根据正负号处理小时部分 sign_h = h if time_diff_secs >= 0 else -h time_diff_string = 'T{:+03.0f}:{:02.0f}:{:05.2f}'.format(sign_h, m, s) # 返回元组:(秒数, 格式化字符串) return time_diff_secs, time_diff_string def main(): # 构造测试数据框 df = pd.DataFrame({ 'date_time': [ '2025-01-24 12:00:00.000', '2025-01-24 12:05:00.000', '2025-01-24 12:10:00.000' ] }) # 先把date_time转成datetime类型,不然没法做时间差计算 df['date_time'] = pd.to_datetime(df['date_time']) # 用apply返回元组,直接拆解到两列 df['time_diff_s'], df['time_delta'] = zip(*df['date_time'].apply(calculate_time_diff)) # 调整列顺序到你想要的样子 df = df[['time_diff_s', 'time_delta', 'date_time']] print(df) # 保存到Excel df.to_excel('time_diff_result.xlsx', index=False) if __name__ == '__main__': main()
关键说明
- 让函数返回包含两个值的元组,这样
apply会给每一行返回一个元组; - 用
zip(*...)把所有行的元组拆解成两个独立的序列,分别赋值给time_diff_s和time_delta列; - 必须先把
date_time列转成datetime类型,否则无法进行时间差计算。
二、关于apply和循环的性能对比
你提到疑惑apply和循环哪个更高效,其实得明确几点:
apply本质上还是逐行循环,只是把循环封装在了Pandas的接口里,性能和手动写for循环差别不大,甚至有时候还不如手动循环(因为有额外的函数调用开销);- Pandas最推荐的是向量化操作,完全避免逐行循环,利用底层的C语言实现,性能会比
apply/手动循环快很多倍,尤其当数据量很大的时候。
向量化实现的版本(更高效)
咱们可以不用apply,直接对整个列做向量化计算:
from datetime import datetime import pandas as pd def main(): str_event_time = '2025-01-24T11:55:00.000Z' event_time = datetime.strptime(str_event_time,'%Y-%m-%dT%H:%M:%S.%fZ') # 构造测试数据框并转换时间类型 df = pd.DataFrame({ 'date_time': [ '2025-01-24 12:00:00.000', '2025-01-24 12:05:00.000', '2025-01-24 12:10:00.000' ] }) df['date_time'] = pd.to_datetime(df['date_time']) # 向量化计算时间差秒数 df['time_diff_s'] = (df['date_time'] - event_time).dt.total_seconds() # 向量化计算时分秒各部分 abs_secs = df['time_diff_s'].abs() hours = abs_secs // 3600 minutes = (abs_secs % 3600) // 60 seconds = abs_secs % 60 # 处理符号并格式化字符串 sign = df['time_diff_s'].apply(lambda x: '+' if x >=0 else '-') df['time_delta'] = 'T' + sign + hours.astype(int).apply('{:02d}'.format) + ':' + \ minutes.astype(int).apply('{:02d}'.format) + ':' + \ seconds.apply('{:05.2f}'.format) # 调整列顺序 df = df[['time_diff_s', 'time_delta', 'date_time']] print(df) df.to_excel('time_diff_result.xlsx', index=False) if __name__ == '__main__': main()
这个版本里,核心的时间差计算都是向量化的,只有最后处理符号和格式化时用了两次轻量的apply,数据量越大,这个版本的性能优势越明显。
总结
- 如果只是小数据量,用
apply实现多列更新完全没问题,代码更直观易读; - 如果数据量较大,优先用向量化操作,性能会提升一个量级;
apply和手动循环的性能差异不大,不要误以为apply是“高效”的循环,它只是写法更简洁而已。
备注:内容来源于stack exchange,提问作者D Chase
相关产品推荐
相关产品推荐

