如何用数值优化器求解最优消费、闲暇与劳动供给?
问题背景
我是数值优化领域的新手,针对以下逻辑清晰的优化问题寻求入门解法:
优化问题
目标是最大化效用函数:
$$
U = \alpha \log(c - \gamma_c) + (1-\alpha)\log(\ell - \gamma_\ell)
$$
约束条件:
- 消费约束:$c = (1-\tau)wh + I$
- 时间约束:$\ell = T - h$
- 非负约束:$c > \gamma_c$,$\ell > \gamma_\ell$,$h \geq 0$
其中参数 $\gamma_c$、$\gamma_\ell$、$\tau$、$\bar{\alpha}$ 均已知,$\alpha = \bar{\alpha} + e$($e$ 为随机项),$T$ 为总时间(原符号 $T_i$ 应为 $T$)。
我已通过拉格朗日乘数法手动得到闭形式解:
- 最优劳动供给:$h = \alpha(T - \gamma_\ell) - \frac{(1-\alpha)(I - \gamma_c)}{(1-\tau)w}$
- 最优闲暇:$\ell = T - h$
- 最优消费:$c = (1-\tau)wh + I$
已用R实现闭形式解计算,代码如下:
library(tidyverse) w_par = c(4, 0.4) i_par = c(3, 0.04) e_par = c(0, 0.01^2) gamma_l = 8; gamma_c = 50; tau = 0.08; Time = 24; alpha_bar = 0.7;N = 10000 gamma_h = Time - gamma_l theta_true = c(gamma_h, gamma_c, alpha_bar, sqrt(e_par[2])) set.seed(1) df <- data.frame(w = exp(rnorm(n = N, mean = w_par[1], sd = sqrt(w_par[2]))), I = exp(rnorm(n = N, mean = i_par[2], sd = sqrt(i_par[2]))), e = rnorm(n = N, mean = e_par[1], sd = sqrt(e_par[2]))) %>% mutate(a = alpha_bar + e, h = a*gamma_h - (((1-a)*(I-gamma_c))/((1-tau)*w)), L = Time - h, C = (1-tau)*w*h+I, U = a*log(C-gamma_c) + (1-a)*log(L-gamma_l))
现仅保留数据框中 w、I、e、a 四列及已知参数,请问:
- 能否用优化器求解最优 $h$、$\ell$、$c$?
- 求解步骤是什么?
- 优化器结果与闭形式解是否一致?
注:仅需入门指引,此模型用于学习方法,以便应用于工作中无闭形式解的模型;支持R或Python实现,只要能得到 $U$、$\ell$、$c$ 即可。
解答
1. 能否用优化器求解?
完全可以。即使存在闭形式解,用优化器求解也是学习数值优化方法的绝佳练习,尤其能为后续处理无闭形式解的模型打基础。
2. 求解步骤
核心思路
将问题转化为最大化效用函数(或等价的最小化负效用函数,因为多数优化器默认求最小值),同时通过逻辑判断约束条件,让优化器避开无效解。
R实现步骤
步骤1:定义目标函数
编写负效用函数(适配优化器的最小值求解逻辑),加入约束检查,违反约束时返回极大值让优化器自动避开:neg_utility <- function(h, w, I, a, gamma_c, gamma_l, tau, Time) { c <- (1 - tau) * w * h + I l <- Time - h # 约束检查:违反则返回极大值 if (c <= gamma_c || l <= gamma_l || h < 0) { return(1e10) } - (a * log(c - gamma_c) + (1 - a) * log(l - gamma_l)) }步骤2:批量求解每条观测
用rowwise()遍历数据,调用R内置的optim()函数,以闭形式解的结果作为初始值加快收敛:df_optim <- df %>% rowwise() %>% mutate( # 生成初始值,避免负数 h_init = max(a*(Time - gamma_l) - ((1-a)*(I - gamma_c))/((1-tau)*w), 0.1), # 调用优化器求解 optim_res = list(optim(par = h_init, fn = neg_utility, w = w, I = I, a = a, gamma_c = gamma_c, gamma_l = gamma_l, tau = tau, Time = Time)), # 提取最优结果并计算衍生变量 h_optim = optim_res[[1]]$par, L_optim = Time - h_optim, C_optim = (1 - tau)*w*h_optim + I, U_optim = a*log(C_optim - gamma_c) + (1 - a)*log(L_optim - gamma_l) ) %>% ungroup() %>% select(-optim_res, -h_init) # 清理中间变量
Python实现步骤(入门版)
用scipy.optimize.minimize()函数,逻辑与R一致:
import numpy as np import pandas as pd from scipy.optimize import minimize # 定义负效用函数 def neg_utility(h, w, I, a, gamma_c, gamma_l, tau, Time): c = (1 - tau) * w * h + I l = Time - h if c <= gamma_c or l <= gamma_l or h < 0: return 1e10 return - (a * np.log(c - gamma_c) + (1 - a) * np.log(l - gamma_l)) # 对单条观测求解 def solve_single_row(row): # 生成初始值 h_init = row['a']*(24 - 8) - ((1-row['a'])*(row['I'] - 50))/((1-0.08)*row['w']) h_init = max(h_init, 0.1) # 调用优化器 res = minimize(neg_utility, x0=h_init, args=(row['w'], row['I'], row['a'], 50, 8, 0.08, 24)) # 计算结果 h_optim = res.x[0] L_optim = 24 - h_optim C_optim = (1-0.08)*row['w']*h_optim + row['I'] U_optim = row['a']*np.log(C_optim -50) + (1-row['a'])*np.log(L_optim -8) return pd.Series([h_optim, L_optim, C_optim, U_optim], index=['h_optim', 'L_optim', 'C_optim', 'U_optim']) # 批量求解 df_optim = df.join(df.apply(solve_single_row, axis=1))
3. 优化器结果与闭形式解是否一致?
理想情况下完全一致,实际计算中会存在极小的浮点误差(通常在$1e-8$量级),可忽略不计。
你可以通过R代码验证差值:
df_compare <- df_optim %>% mutate(h_diff = abs(h - h_optim), L_diff = abs(L - L_optim), C_diff = abs(C - C_optim)) # 查看差值统计 summary(df_compare[, c('h_diff', 'L_diff', 'C_diff')])
输出的最大差值通常远小于1,说明结果高度吻合。
内容的提问来源于stack exchange,提问作者Jorge Paredes

