4. 加权和法详解:原理、权重选择、优缺点分析、Python代码实现

加权和法,说白了就是多目标优化里最朴素、最直接的一种思路。你想想看,我们面对一堆互相打架的目标——比如又要成本低,又要性能高,还要寿命长——怎么办?最简单的办法就是给每个目标打个分,然后按重要性加权求和,变成一个单目标问题来解。

我刚开始做工业项目时,第一个接触的就是这个方法。当时觉得它太简单了,甚至有点瞧不上。后来踩过几次坑才发现,简单不等于没用。很多实际问题,用加权和法反而比那些花里胡哨的算法更靠谱。

4.1 原理:把多目标变成单目标

加权和法的数学表达其实就一行公式:

min F(x) = w₁·f₁(x) + w₂·f₂(x) + ... + wₘ·fₘ(x)

其中 wᵢ 是第 i 个目标的权重,fᵢ(x) 是第 i 个目标函数。权重之和通常归一化为 1,即 ∑wᵢ = 1。

说白了,就是把多个目标函数线性组合成一个综合指标。然后你只需要用单目标优化的方法去求解就行了——梯度下降、遗传算法、粒子群,随便你。

核心思想:通过调整权重 wᵢ,你可以让优化器偏向不同的目标。权重越大,对应的目标就越被重视。

这里有个关键点:加权和法只能找到帕累托前沿上的凸部分。如果帕累托前沿是非凸的,那有些最优解你永远找不到。嗯,这个坑我后面会细说。

4.2 权重选择:没有银弹,但有经验

权重怎么选?这是加权和法最让人头疼的地方。我见过不少新手,上来就拍脑袋给个 0.5、0.3、0.2,结果跑出来的结果根本不能用。

我个人习惯用以下几种方法:

4.2.1 等权重法

最简单,所有目标权重一样。适合你对目标重要性完全没概念的时候。但说实话,实际项目中很少这么干——因为不同目标的量纲和数值范围往往差很多。

4.2.2 目标归一化 + 权重

先对每个目标做归一化处理,再乘以权重。这样能避免数值大的目标主导优化过程。公式如下:

f'_i(x) = (f_i(x) - f_i_min) / (f_i_max - f_i_min)

我在做汽车轻量化设计时,就吃过这个亏。当时车身重量是几百公斤,碰撞能量是几千焦耳,直接加权求和,重量目标完全被淹没了。后来做了归一化,结果才合理。

4.2.3 层次分析法

如果你有多个决策者,或者目标重要性需要主观判断,可以用 AHP。它通过两两比较构建判断矩阵,然后计算特征向量得到权重。我个人觉得这方法有点繁琐,但确实能给出相对合理的权重。

4.2.4 自适应权重

在优化过程中动态调整权重。比如一开始均匀探索,后期逐渐聚焦到某个区域。这个方法我在做多目标进化算法时用过,效果不错,但实现起来稍微复杂点。

我的建议:如果你刚开始用加权和法,先试试等权重 + 归一化。跑几轮看看结果,再根据实际情况调整。别一上来就搞复杂的权重策略。

4.3 优缺点分析:别被它的简单骗了

优点 缺点
实现简单,代码量少 只能找到凸帕累托前沿上的解
计算效率高,适合大规模问题 权重选择主观性强,影响结果
容易理解,非专业人士也能看懂 不同目标量纲不一致时需要归一化
可以灵活调整权重来探索不同偏好 无法处理非凸、不连续的帕累托前沿
与大多数单目标优化器兼容 权重变化与解的变化不一定线性

我曾经在一个项目中,用加权和法去优化一个非凸问题。跑了上百次,换了各种权重组合,始终找不到某个区域的解。后来换成 NSGA-II,一下子就找到了。嗯,这就是加权和法的局限性——它只擅长凸问题。

避坑指南:如果你的问题帕累托前沿可能是非凸的,别只用加权和法。可以先用加权和法快速探索,再用其他方法精细搜索。我曾经因为只用加权和法,差点错过一个关键的设计方案。

4.4 Python代码实现:从零开始写一个加权和优化器

下面我给出一个完整的 Python 实现。这个例子解决一个简单的双目标优化问题:

  • 目标1:最小化 f₁(x) = x²
  • 目标2:最小化 f₂(x) = (x-2)²

我们用加权和法,配合 scipy 的优化器来求解。

import numpy as np
from scipy.optimize import minimize

def weighted_sum_objective(x, weights, objectives):
    """
    加权和目标函数
    x: 决策变量
    weights: 权重向量,如 [0.5, 0.5]
    objectives: 目标函数列表,如 [f1, f2]
    """
    # 计算每个目标的值
    f_values = [obj(x) for obj in objectives]
    
    # 加权求和
    total = sum(w * f for w, f in zip(weights, f_values))
    
    return total

# 定义两个目标函数
def f1(x):
    return x[0]**2

def f2(x):
    return (x[0] - 2)**2

# 目标函数列表
objectives = [f1, f2]

# 不同的权重组合
weight_sets = [
    [1.0, 0.0],  # 只优化目标1
    [0.8, 0.2],
    [0.6, 0.4],
    [0.5, 0.5],  # 等权重
    [0.4, 0.6],
    [0.2, 0.8],
    [0.0, 1.0]   # 只优化目标2
]

# 存储结果
results = []

for weights in weight_sets:
    # 定义当前权重下的目标函数
    def obj_func(x):
        return weighted_sum_objective(x, weights, objectives)
    
    # 使用SCIPY优化
    res = minimize(obj_func, x0=[0.0], method='BFGS')
    
    x_opt = res.x[0]
    f1_opt = f1([x_opt])
    f2_opt = f2([x_opt])
    
    results.append({
        'weights': weights,
        'x': x_opt,
        'f1': f1_opt,
        'f2': f2_opt
    })
    
    print(f"权重 [{weights[0]:.1f}, {weights[1]:.1f}] -> "
          f"x={x_opt:.4f}, f1={f1_opt:.4f}, f2={f2_opt:.4f}")

# 输出结果
print("\n=== 帕累托解集 ===")
for r in results:
    print(f"f1={r['f1']:.4f}, f2={r['f2']:.4f}")

运行这段代码,你会看到不同权重下得到的解。当权重偏向 f1 时,x 接近 0;偏向 f2 时,x 接近 2。等权重时,x 在 1 附近——这是两个目标的折中方案。

实战技巧:在实际项目中,我通常不会只跑一组权重。我会生成 10-20 组均匀分布的权重,跑出对应的解集,然后让决策者从中挑选。这样既利用了加权和法的效率,又保留了多目标优化的灵活性。

4.5 知识体系结构图

下面我用一张 SVG 图来展示加权和法的核心逻辑和知识体系:

加权和法知识体系 加权和法 原理 权重选择 优缺点分析 线性组合:F = Σ wᵢ·fᵢ 权重归一化:Σ wᵢ = 1 凸帕累托前沿假设 等权重法 目标归一化 + 权重 层次分析法 (AHP) 自适应权重 优点:简单、高效、易理解 缺点:非凸问题失效 权重主观性强 Python代码实现

这张图把加权和法的四个核心模块串起来了。从原理出发,到权重选择策略,再到优缺点分析,最后落地到代码实现。你可以在实际项目中对照这个框架来使用。


好了,关于加权和法就聊这么多。它虽然简单,但确实是多目标优化工具箱里的一把好手。记住它的适用场景和局限性,你就能在项目中用好它。

公众号:蓝海资料掘金营,微信deep3321