我需要为每个产品(例如A、B、C)找到最优的折扣,以便最大化总销售额。我已经为每个产品建立了现有的随机森林模型,这些模型将折扣和季节映射到销售额。我如何将这些模型结合起来,并将它们输入到优化器中,以找到每个产品的最佳折扣?
模型选择的原因:
- RF:它能够提供比线性模型更好的预测变量与响应变量(销售提升标准化)的关系。
- PSO:在许多白皮书中被推荐(可在researchgate/IEEE找到),并且在Python中也有可用的包,这里和这里。
输入数据:样本数据用于在产品级别构建模型。数据一览如下:
我采取的思路/步骤:
-
为每个产品构建RF模型
# 预处理数据 products_pre_processed_data = {key:pre_process_data(df, key) for key, df in df_basepack_dict.items()} # rf模型 products_rf_model = {key:rf_fit(df) for key, df in products_pre_processed_data .items()}
- 将模型传递给优化器
- 目标函数:最大化 sales_uplift_norm(RF模型的响应变量)
- 约束:
- 总支出(A + B + C的支出 <= 20),支出 = 产品总销售单位数 * 折扣百分比 * 产品市场参考价
- 产品(A、B、C)的下限:[0.0, 0.0, 0.0] # 折扣百分比下限
- 产品(A、B、C)的上限:[0.3, 0.4, 0.4] # 折扣百分比上限
伪/样本代码 # 因为我无法找到将产品模型传递给优化器的方法。
from pyswarm import psodef obj(x): model1 = products_rf_model.get('A') model2 = products_rf_model.get('B') model3 = products_rf_model.get('C') return -(model1 + model2 + model3) # -ve sign as to maximizedef con(x): x1 = x[0] x2 = x[1] x3 = x[2] return np.sum(units_A*x*mrp_A + units_B*x*mrp_B + units_C* x *spend_C)-20 # spend budgetlb = [0.0, 0.0, 0.0]ub = [0.3, 0.4, 0.4]xopt, fopt = pso(obj, lb, ub, f_ieqcons=con)
如何将 PSO优化器(或如果我选择的不是正确的优化器,则使用其他优化器)与RF一起使用?
添加用于模型的函数:
def pre_process_data(df,product): data = df.copy().reset_index() # print(data) bp = product print("----------product: {}----------".format(bp)) # 预处理步骤 print("pre process df.shape {}".format(df.shape)) #1. 响应变量转换 response = data.sales_uplift_norm # 已经转换 #2. 预测变量数值转换 numeric_vars = ['discount_percentage'] # 可能包括mrp, depth df_numeric = data[numeric_vars] df_norm = df_numeric.apply(lambda x: scale(x), axis = 0) # 中心化和缩放 #3. 字符字段虚拟化 #选择类别字段 cat_cols = data.select_dtypes('category').columns #选择字符串字段 str_to_cat_cols = data.drop(['product'], axis = 1).select_dtypes('object').astype('category').columns # 合并所有类别字段 all_cat_cols = [*cat_cols,*str_to_cat_cols]# print(all_cat_cols) #将类别转换为虚拟变量 df_dummies = pd.get_dummies(data[all_cat_cols]) #4. 合并数值和字符数据框 df_combined = pd.concat([df_dummies.reset_index(drop=True), df_norm.reset_index(drop=True)], axis=1) df_combined['sales_uplift_norm'] = response df_processed = df_combined.copy() print("post process df.shape {}".format(df_processed.shape))# print("model fields: {}".format(df_processed.columns)) return(df_processed)def rf_fit(df, random_state = 12): train_features = df.drop('sales_uplift_norm', axis = 1) train_labels = df['sales_uplift_norm'] # 随机森林回归器 rf = RandomForestRegressor(n_estimators = 500, random_state = random_state, bootstrap = True, oob_score=True) # RF模型 rf_fit = rf.fit(train_features, train_labels) return(rf_fit)
回答:
您可以在下方找到完整的解决方案!
与您的方法的根本区别如下:
- 由于随机森林模型以
season
特征作为输入,因此必须为每个季节计算最优折扣。 - 查阅pyswarm的文档,
con
函数的输出必须满足con(x) >= 0.0
。因此正确的约束是20 - sum(...)
,而不是相反的方式。此外,units
和mrp
变量没有给出;我只是假设其值为1,您可能需要更改这些值。
对您原始代码的其他修改包括:
- 使用
sklearn
的预处理和管道包装器,以简化预处理步骤。 - 最优参数存储在输出
.xlsx
文件中。 - PSO的
maxiter
参数已设置为5
以加速调试,您可能希望将其值设置为其他值(默认值为100
)。
因此,代码如下:
...