3. 成本预测核心指标:CPI、SPI、EAC、ETC 的计算公式与业务含义

在挣值管理(EVM)体系中,成本绩效指数(CPI)、进度绩效指数(SPI)、完工估算(EAC)和完工尚需估算(ETC)是四个最核心的量化指标。它们将原始测量数据(PV、EV、AC)转化为可决策的预测信号,是成本偏差分析与纠偏的“仪表盘”。

3.1 核心绩效指数:CPI 与 SPI

CPI 和 SPI 是衡量项目当前“成本效率”和“进度效率”的无量纲比率,通常以周或月为周期滚动计算。

指标 计算公式 业务含义 临界值解读
CPI CPI = EV / AC 每实际花费 1 元,完成了多少预算价值的工作。 CPI > 1:成本节约;CPI = 1:按预算;CPI < 1:成本超支。
SPI SPI = EV / PV 按计划进度,实际完成了多少比例的工作。 SPI > 1:进度超前;SPI = 1:按计划;SPI < 1:进度滞后。
实战经验:CPI 和 SPI 应结合“趋势线”而非单点值判断。连续 3 个报告周期 CPI < 0.9 且 SPI < 0.9,通常触发项目预警,需启动纠偏计划。
CPI 与 SPI 物理意义与趋势判断 CPI / SPI 物理意义与趋势判断 CPI = EV / AC 每花 1 元,产出多少预算价值 CPI > 1 → 成本节约(效率高) CPI < 1 → 成本超支(效率低) SPI = EV / PV 按计划,实际完成了多少工作 SPI > 1 → 进度超前 SPI < 1 → 进度滞后 趋势判断规则(连续 3 周期) CPI < 0.9 且 SPI < 0.9 → 触发项目预警,启动纠偏 CPI > 1.1 且 SPI > 1.1 → 检查计划是否过于保守

3.2 完工估算(EAC)与完工尚需估算(ETC)

EAC 和 ETC 是项目成本预测的“终点线”指标。EAC 代表项目完工时的总成本预测,ETC 代表从当前时点开始还需要多少成本才能完成剩余工作。根据项目实际绩效与未来假设,EAC 有四种典型算法。

预测场景 EAC 公式 ETC 公式 适用条件
典型偏差(按当前 CPI 继续) EAC = BAC / CPI ETC = EAC - AC 成本偏差由普遍性效率问题导致,未来不会改善
非典型偏差(仅过去偏差,未来按计划) EAC = AC + (BAC - EV) ETC = BAC - EV 成本偏差由一次性事件导致,未来回归预算效率
同时考虑 CPI 和 SPI EAC = AC + (BAC - EV) / (CPI × SPI) ETC = (BAC - EV) / (CPI × SPI) 成本与进度均存在偏差,且相互影响
重估(自下而上估算) EAC = AC + 自下而上 ETC 重新估算剩余工作 项目发生重大变更或原始估算失效
关键决策点:选择哪种 EAC 公式,取决于项目经理对“未来绩效是否与过去一致”的判断。在实战中,典型偏差模型(EAC = BAC / CPI)是最常用的保守预测,因为它假设低效率将持续到项目结束。
EAC 与 ETC 四种预测路径 EAC / ETC 四种预测路径 当前状态 (EV, AC, PV) 典型偏差(按当前 CPI) EAC = BAC / CPI ETC = EAC - AC 非典型偏差(未来按计划) EAC = AC + (BAC - EV) ETC = BAC - EV CPI × SPI 综合影响 EAC = AC + (BAC - EV)/(CPI×SPI) ETC = (BAC - EV)/(CPI×SPI) 自下而上重估 EAC = AC + 自下而上 ETC 适用:重大变更或原始估算失效

3.3 指标联动与业务决策

四个指标不是孤立存在的,它们共同构成一个“测量 → 分析 → 预测 → 决策”的闭环。以下是一个典型的联动分析场景:

  1. 测量阶段:获取 PV、EV、AC 原始数据。
  2. 效率分析:计算 CPI 和 SPI,判断成本与进度偏差的性质(典型/非典型)。
  3. 预测阶段:根据偏差性质选择 EAC 公式,计算 EAC 和 ETC。
  4. 决策阶段:对比 EAC 与 BAC,计算完工偏差(VAC = BAC - EAC)。若 VAC 为负,说明预测超支,需启动纠偏。
常见误区:不要将 ETC 简单理解为“剩余预算”。ETC 是基于当前绩效的预测值,而剩余预算(BAC - EV)是理想值。当 CPI < 1 时,ETC 通常大于剩余预算,这才是真实的资金需求。

3.4 实战代码示例:Python 计算核心指标

以下代码演示如何根据 PV、EV、AC 和 BAC 批量计算 CPI、SPI、EAC 和 ETC,并输出预测报告。

import pandas as pd

def calculate_evm_metrics(pv, ev, ac, bac, scenario='typical'):
    """
    计算 EVM 核心指标
    :param pv: 计划价值
    :param ev: 挣值
    :param ac: 实际成本
    :param bac: 完工预算
    :param scenario: 预测场景 ('typical', 'atypical', 'composite')
    :return: 包含所有指标的字典
    """
    # 绩效指数
    cpi = ev / ac if ac != 0 else 0
    spi = ev / pv if pv != 0 else 0

    # 完工估算与完工尚需估算
    if scenario == 'typical':
        eac = bac / cpi if cpi != 0 else 0
        etc = eac - ac
    elif scenario == 'atypical':
        eac = ac + (bac - ev)
        etc = bac - ev
    elif scenario == 'composite':
        eac = ac + (bac - ev) / (cpi * spi) if (cpi * spi) != 0 else 0
        etc = (bac - ev) / (cpi * spi) if (cpi * spi) != 0 else 0
    else:
        raise ValueError("scenario must be 'typical', 'atypical', or 'composite'")

    # 完工偏差
    vac = bac - eac

    return {
        'CPI': round(cpi, 3),
        'SPI': round(spi, 3),
        'EAC': round(eac, 2),
        'ETC': round(etc, 2),
        'VAC': round(vac, 2)
    }

# 示例数据
data = {
    'PV': [1000, 2000, 3000, 4000],
    'EV': [900, 1800, 2800, 3500],
    'AC': [1100, 2100, 3200, 3800],
    'BAC': [5000, 5000, 5000, 5000]
}
df = pd.DataFrame(data)

# 批量计算(典型偏差场景)
results = df.apply(lambda row: calculate_evm_metrics(
    row['PV'], row['EV'], row['AC'], row['BAC'], scenario='typical'
), axis=1, result_type='expand')

df = pd.concat([df, results], axis=1)
print(df.to_string(index=False))

输出示例(第 4 周期):

  PV    EV    AC   BAC    CPI    SPI     EAC     ETC     VAC
1000   900  1100  5000  0.818  0.900  6111.11  5011.11 -1111.11
2000  1800  2100  5000  0.857  0.900  5833.33  3733.33  -833.33
3000  2800  3200  5000  0.875  0.933  5714.29  2514.29  -714.29
4000  3500  3800  5000  0.921  0.875  5428.57  1628.57  -428.57
解读:第 4 周期 CPI = 0.921,SPI = 0.875,成本超支且进度滞后。按典型偏差预测,EAC = 5428.57,超出 BAC 约 428.57 元(VAC 为负)。项目经理需立即分析超支原因,并考虑是否切换为“自下而上重估”场景。