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

Python中DataFrame多条件自定义函数应用报错排查与优化

错误原因分析

1. Cannot convert type '<class 'list'>' to date.

创建德国假日对象时,holidays.DE(years=[])传入了空列表,holidays库无法识别空年份列表,导致后续判断date in german_holidays时无法正确转换日期类型,抛出类型转换错误。需要指定数据对应的年份(比如你的数据是2019年,应改为holidays.DE(years=2019))。

2. The truth value of a Series is ambiguous...

  • 日期类型问题:如果df['date']列是字符串类型而非datetime64类型,在进行date + pd.Timedelta(days=1)或日期判断时会隐式转换失败,导致返回Series而非单个布尔值,触发模糊真值错误。
  • weekday调用错误:date.weekday是方法而非属性,正确写法应为date.weekday(),直接使用属性会拿到方法对象,无法和数字(5、6等)做比较,导致逻辑判断异常。
修正后的基础实现

先解决上述错误,调整代码如下:

import pandas as pd
import holidays

# 1. 正确初始化德国假日,指定年份
german_holidays = holidays.DE(years=2019)
# 2. 确保date列是datetime类型
df['date'] = pd.to_datetime(df['date'])

def eighteen(date):
    if date in german_holidays:
        return 120
    elif (date + pd.Timedelta(days=1)) in german_holidays:
        return 1320
    elif date.weekday() == 5:  # 改为调用weekday()方法
        return 1080
    elif date.weekday() == 6:
        return 120
    else:
        return 1440

def fifteenone(date):
    if date in german_holidays:
        return 120
    elif (date + pd.Timedelta(days=1)) in german_holidays:
        return 1320
    elif date.weekday() == 4:
        return 1320
    elif date.weekday() == 5:
        return 0
    elif date.weekday() == 6:
        return 120
    else:
        return 1440

def fifteentwo(date):
    if date in german_holidays:
        return 120
    elif (date + pd.Timedelta(days=1)) in german_holidays:
        return 1320
    elif date.weekday() == 4:
        return 1320
    elif date.weekday() == 5:
        return 0
    elif date.weekday() == 6:
        return 0
    elif date.weekday() == 0:
        return 1080
    else:
        return 1440

def twelve(date):
    if date in german_holidays:
        return 0
    elif date.weekday() == 5:
        return 0
    elif date.weekday() == 6:
        return 0
    else:
        return 960

def WT(shift, date):
    if shift == "18-sh":
        return eighteen(date)
    elif shift == "15.1-sh":
        return fifteenone(date)
    elif shift == "15.2-sh":
        return fifteentwo(date)
    elif shift == "12-sh":
        return twelve(date)

df['WT'] = df.apply(lambda row: WT(row['shift'], row['date']), axis=1)
更优的向量化实现方案

apply是逐行遍历,数据量大时效率极低,建议用向量化操作代替,步骤如下:

  1. 预处理衍生列:
df['date'] = pd.to_datetime(df['date'])
# 标记当日是否为德国假日
df['is_holiday'] = df['date'].isin(german_holidays)
# 标记次日是否为德国假日
df['next_day_holiday'] = df['date'].shift(-1).isin(german_holidays)
# 获取星期几(0=周一,6=周日)
df['weekday'] = df['date'].dt.weekday
  1. 针对不同班次定义规则,用np.select批量计算:
import numpy as np

# 定义18-sh的规则和结果
rules_18sh = [
    df['is_holiday'],
    df['next_day_holiday'],
    df['weekday'] == 5,
    df['weekday'] == 6
]
results_18sh = [120, 1320, 1080, 120]

# 定义15.1-sh的规则和结果
rules_151sh = [
    df['is_holiday'],
    df['next_day_holiday'],
    df['weekday'] == 4,
    df['weekday'] == 5,
    df['weekday'] == 6
]
results_151sh = [120, 1320, 1320, 0, 120]

# 定义15.2-sh的规则和结果
rules_152sh = [
    df['is_holiday'],
    df['next_day_holiday'],
    df['weekday'] == 4,
    df['weekday'] == 5,
    df['weekday'] == 6,
    df['weekday'] == 0
]
results_152sh = [120, 1320, 1320, 0, 0, 1080]

# 定义12-sh的规则和结果
rules_12sh = [
    df['is_holiday'],
    df['weekday'] == 5,
    df['weekday'] == 6
]
results_12sh = [0, 0, 0]

# 按班次批量计算WT
df['WT'] = np.where(df['shift'] == '18-sh',
                   np.select(rules_18sh, results_18sh, default=1440),
                   np.where(df['shift'] == '15.1-sh',
                            np.select(rules_151sh, results_151sh, default=1440),
                            np.where(df['shift'] == '15.2-sh',
                                     np.select(rules_152sh, results_152sh, default=1440),
                                     np.select(rules_12sh, results_12sh, default=960))))

这种方式完全利用pandas和numpy的向量化运算,避免逐行遍历,效率提升显著,且规则更清晰易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:20:41