使用np.where()创建DataFrame新列时遇格式错误的解决咨询
解决DataFrame基于条件创建新列时的np.where筛选失效问题
需求说明
要在DataFrame中生成名为New的新列,规则如下:
- 当
MinDate列值为空时,直接取Start_Date列的数据 - 当
MinDate列值不为空时,将该列日期转为字符串后与Time列的时间字符串拼接,再转回datetime格式
原代码及错误信息
原实现代码:
import pandas as pd import numpy as np from datetime import date, datetime fffg = pd.DataFrame({'N': [1, 2, 3], 'MinDate': [date(2023,1,2), None, date(2022,1,7)], 'Time': [datetime.time(8, 48, 0), datetime.time(8, 48, 0), datetime.time(8, 48, 0)], 'Start_Date': [datetime(2022,4,1,15,10), datetime(2023,4,1,15,10), datetime(2022,5,1,15,10)]}) fffg['MinDate'] = pd.to_datetime(fffg['MinDate']) fffg['New'] = np.where(pd.notnull(fffg['MinDate']), pd.to_datetime(fffg['MinDate'].astype(str)+' '+fffg['Time'].astype(str)), fffg['Start_Date'] ) fffg
运行后报错:
ValueError: time data "NaT 08:48:00" doesn't match format "%Y-%m-%d %H:%M:%S", at position 1. You might want to try: - passing `format` if your strings have a consistent format; - passing `format='ISO8601'` if your strings are all ISO8601 but not necessarily in exactly the same format; - passing `format='mixed'`, and the format will be inferred for each element individually. You might want to use `dayfirst` alongside this.
问题原因
np.where的执行逻辑是先完整计算两个分支的所有元素,再根据条件选择对应结果。即使MinDate为NaT(空值),对应的行仍会执行字符串拼接操作,生成"NaT 08:48:00"这种无法被pd.to_datetime解析的无效时间字符串,最终触发报错。
解决方案
方案1:使用apply逐行处理
逐行判断条件,仅对符合要求的行执行拼接转换,避免无效计算:
import pandas as pd from datetime import date, datetime fffg = pd.DataFrame({'N': [1, 2, 3], 'MinDate': [date(2023,1,2), None, date(2022,1,7)], 'Time': [datetime.time(8, 48, 0), datetime.time(8, 48, 0), datetime.time(8, 48, 0)], 'Start_Date': [datetime(2022,4,1,15,10), datetime(2023,4,1,15,10), datetime(2022,5,1,15,10)]}) fffg['MinDate'] = pd.to_datetime(fffg['MinDate']) def create_new_col(row): if pd.notnull(row['MinDate']): return pd.to_datetime(f"{row['MinDate'].date()} {row['Time']}") return row['Start_Date'] fffg['New'] = fffg.apply(create_new_col, axis=1) print(fffg)
方案2:分步处理(适合大数据集,性能更优)
先初始化新列为Start_Date,再筛选出MinDate非空的行执行拼接转换,利用pandas向量化操作提升性能:
import pandas as pd from datetime import date, datetime fffg = pd.DataFrame({'N': [1, 2, 3], 'MinDate': [date(2023,1,2), None, date(2022,1,7)], 'Time': [datetime.time(8, 48, 0), datetime.time(8, 48, 0), datetime.time(8, 48, 0)], 'Start_Date': [datetime(2022,4,1,15,10), datetime(2023,4,1,15,10), datetime(2022,5,1,15,10)]}) fffg['MinDate'] = pd.to_datetime(fffg['MinDate']) # 初始化New列为Start_Date fffg['New'] = fffg['Start_Date'] # 筛选MinDate非空的行,执行拼接转换 valid_mask = pd.notnull(fffg['MinDate']) fffg.loc[valid_mask, 'New'] = pd.to_datetime( fffg.loc[valid_mask, 'MinDate'].astype(str) + ' ' + fffg.loc[valid_mask, 'Time'].astype(str) ) print(fffg)
补充说明
方案2通过掩码筛选只处理需要转换的行,避免了对全列执行无效操作,在处理大型数据集时性能远优于逐行循环的apply方法。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

