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

如何计算满足三类约束条件的每日权重(Python实现)

如何计算满足三类约束条件的每日权重(Python实现)

我明白你的需求啦——要找到一组严格递减、和为7的每日权重,还要恰好让10个用户里的7个加权平均低于11。前两个约束你已经用指数衰减+归一化搞定了,但第三个约束确实需要结合起来处理,下面我给你两种可行的Python实现思路:

方法一:约束优化法(基于Scipy)

这个方法把问题转化为带约束的优化问题,通过变量替换把单调性约束转化为变量边界,再用目标函数逼近“恰好7个用户达标”的要求。

步骤1:准备数据

首先先把你的数据集固定下来(加随机种子方便复现):

import pandas as pd
import numpy as np
from scipy.optimize import minimize

# 固定随机种子,复现你的数据集
np.random.seed(42)
df = pd.DataFrame(np.random.randint(8, 15, size=(10, 7)))
df.columns = ['day_0', 'day_-1', 'day_-2', 'day_-3', 'day_-4', 'day_-5', 'day_-6']
df.index.name = 'id'
df = df.reset_index()
# 提取用户消费数据(去掉id列)
X = df.drop('id', axis=1).values

步骤2:变量替换处理单调性约束

为了方便处理w0 > w1 > ... > w6 >0的约束,我们做个变量替换:

  • 令s6 = w6(最小的权重,正数)
  • s5 = w5 - w6(正数,保证w5>w6)
  • s4 = w4 -w5(正数,保证w4>w5)
  • ...以此类推,直到s0 =w0 -w1(正数)

这样所有s0~s6都是正数,且权重和为7的约束可以转化为:s0 +2s1 +3s2 +4s3 +5s4 +6s5 +7s6 =7。接下来写个转换函数把s转成最终的权重w:

def s_to_w(s):
    s0, s1, s2, s3, s4, s5, s6 = s
    w6 = s6
    w5 = s5 + w6
    w4 = s4 + w5
    w3 = s3 + w4
    w2 = s2 + w3
    w1 = s1 + w2
    w0 = s0 + w1
    return np.array([w0, w1, w2, w3, w4, w5, w6])

步骤3:定义目标函数与约束

目标函数要让“加权平均低于11的用户数”尽可能接近7,同时可以加个小惩罚项避免加权和刚好卡在阈值上:

def objective(s):
    w = s_to_w(s)
    # 加权平均 <11 等价于 加权和 < 11*7=77(因为权重和为7)
    weighted_sums = X @ w
    # 统计达标用户数
    cnt_less = np.sum(weighted_sums < 77)
    # 目标:让达标数尽可能接近7,平方差最小化
    # 加边界惩罚项,避免加权和刚好卡在77附近
    boundary_penalty = np.sum(np.exp(-(weighted_sums - 77)**2 / 10))
    return (cnt_less -7)**2 + 0.1 * boundary_penalty

然后定义约束条件和变量边界:

# 权重和为7的等式约束
cons = ({'type': 'eq', 'fun': lambda s: s[0] + 2*s[1] + 3*s[2] + 4*s[3] + 5*s[4] + 6*s[5] +7*s[6] -7})
# 所有s变量必须为正(用1e-6避免数值问题)
bounds = [(1e-6, None) for _ in range(7)]

步骤4:运行优化并验证结果

# 初始化变量(可以用随机值或指数衰减权重转化的s)
s_init = np.ones(7) * 0.1
# 用SLSQP算法求解带约束的优化问题
result = minimize(objective, x0=s_init, method='SLSQP', bounds=bounds, constraints=cons)

# 提取最优权重
w_opt = s_to_w(result.x)
# 验证结果
weighted_sums = X @ w_opt
cnt_less = np.sum(weighted_sums <77)

print("=== 优化结果 ===")
print(f"满足加权平均<11的用户数:{cnt_less}")
print(f"权重:{np.round(w_opt,4)}")
print(f"权重严格递减:{all(w_opt[i] > w_opt[i+1]+1e-6 for i in range(6))}")
print(f"权重和:{np.sum(w_opt):.4f}")

如果一次优化没得到恰好7个用户的结果,可以多试几次不同的初始值,因为目标函数是离散的,可能会陷入局部最优。


方法二:随机搜索法(简单易上手)

如果觉得优化算法太复杂,也可以用“生成符合前两个约束的权重→验证第三个约束”的随机搜索法,虽然笨但有效:

实现代码

def generate_valid_weights():
    """生成满足w0>w1>...>w6>0且sum(w)=7的权重"""
    while True:
        # 生成7个随机正数,降序排序后归一化到和为7
        w = np.random.rand(7)
        w = -np.sort(-w)  # 降序排序
        w = w / np.sum(w) *7
        # 检查严格单调性(避免相等的情况)
        if all(w[i] > w[i+1]+1e-6 for i in range(6)) and w[-1]>1e-6:
            return w

# 搜索符合条件的权重
target_cnt =7
found = False
print("正在随机搜索符合条件的权重...")
while not found:
    w = generate_valid_weights()
    weighted_sums = X @w
    cnt_less = np.sum(weighted_sums <77)
    if cnt_less == target_cnt:
        found = True
        print("\n=== 找到符合条件的权重 ===")
        print(f"满足加权平均<11的用户数:{cnt_less}")
        print(f"权重:{np.round(w,4)}")
        print(f"权重严格递减:{all(w[i] > w[i+1]+1e-6 for i in range(6))}")
        print(f"权重和:{np.sum(w):.4f}")

这种方法的好处是不需要理解复杂的优化理论,代码简单,而且对于7维的情况,搜索速度其实挺快的,一般几秒内就能找到符合条件的权重。


备注:内容来源于stack exchange,提问作者quant

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 18:05:26