所以我怀疑是不是我对SCAD惩罚函数的理解有错误,总之我今天又谷歌,搜索到了http://vlambda.com/wz_wRtUGSimSJ.html。这篇文章,里面的SCAD惩罚函数又和第一个链接看到的不一样,我已经迷糊了
我的意思是,现在我搞不清楚SCAD是不是函数表达式弄错了,但不论是否弄错,我发现我不能理解SCAD如何把参数估计为0。参数估计为0就会将某段的回归全部系数估计为0,从而能直接告知这个分段不需要,这是第二个链接论文告诉我的。。。但反正,现在门槛 c 值就不对。。。门槛自变量的数据最大也才1W出头,而估计出的C竟然数倍于它们
以下是代码,其中pay_data_x为189*9的矩阵自变量数据,pay_data_y为因变量。M_c是分段,这里分了2段,先分别用pay_data_x的第2列数据的标准差和均值做分段门槛值的初始值(即第2列数据为门槛变量)
另外就是,是否有可能我对门槛值c的求导有错误??
- # 定义损失函数:光滑SCAD正则,参考《门槛回归模型中门槛值和回归参数的估计》
- def loss_SCAD(beta_matrix, M_c):
- first_M_MSE = np.dot(pay_data_x, beta_matrix[:lt]) - pay_data_y.values.reshape((-1, 1))
- z = pay_data_x.iloc[:, 1].values.reshape((-1, 1))
- other_M_MSE = 0
- scad = 0
- for idx, c in enumerate(M_c):
- nor_distri_x = (z - c) / h
- nor_distri_CDF = st.norm.cdf(nor_distri_x) # 光滑示性函数
- other_M_MSE += np.dot(pay_data_x, beta_matrix[lt * (idx + 1):lt * (idx + 2)]) * nor_distri_CDF
- for beta_param in beta_matrix[lt * (idx + 1):lt * (idx + 2)]:
- if abs(beta_param) < lam:
- scad += lam ** 2 - (abs(beta_param) - lam) ** 2
- else:
- scad += lam ** 2
- MSE = 0.5 * np.average((first_M_MSE + other_M_MSE) ** 2) + scad
- return MSE
- # 更新梯度
- def loss_derivative(beta_matrix, M_c):
- deriv_list = []
- other_M_MSE = 0
- nor_distri_CDF = 0
- first_M_MSE = np.dot(pay_data_x, beta_matrix[:lt]) - pay_data_y.values.reshape((-1, 1))
- z = pay_data_x.iloc[:, 1].values.reshape((-1, 1))
- for idx, c in enumerate(M_c):
- nor_distri_x = (z - c) / h
- nor_distri_CDF = st.norm.cdf(nor_distri_x) # 光滑示性函数
- other_M_MSE += np.dot(pay_data_x, beta_matrix[lt * (idx + 1):lt * (idx + 2)]) * nor_distri_CDF
- square_part = first_M_MSE + other_M_MSE
- for idx, beta_param in enumerate(beta_matrix[:lt]): # 更新梯度:第一段
- deriv_list.append(np.average(square_part * pay_data_x.iloc[:, idx].values.reshape((-1, 1))))
- for idx, c in enumerate(M_c):
- for i, beta_param in enumerate(beta_matrix[lt * (idx + 1):lt * (idx + 2)]): # 更新梯度:分段
- if abs(beta_param) > lam: # 更新梯度:SCAD函数
- if a * lam > beta_param:
- scad = (lam + (a * lam - beta_param) / ((a - 1) * lam))
- else:
- scad = 0
- else:
- scad = lam
- deriv_list.append(np.average(square_part * pay_data_x.iloc[:, i].values.reshape((-1, 1)) * nor_distri_CDF) + scad)
- for idx, c in enumerate(M_c): # 更新梯度:门槛参数
- nor_distri_PDF = st.norm.pdf((z - c) / h)
- deriv_list.append(np.average(square_part * np.dot(pay_data_x, beta_matrix[lt * (idx + 1):lt * (idx + 2)]) * nor_distri_PDF / -h))
- return np.array(deriv_list).reshape((-1, 1))
- # DFP迭代
- def DFP(M_c, t=0.5, epsilon=1e-5, max_iter=1000, sigma=0.4):
- c = np.array(M_c).reshape((-1, 1))
- tmp_beta = np.ones((pay_data_x.shape[1] * (len(M_c) + 1), 1))
- H = np.eye(pay_data_x.shape[1] * (len(M_c) + 1) + len(M_c)) # 初始化伪黑塞矩阵的逆
- beta_c_last = np.concatenate((tmp_beta, c))
- iter = 1
- tmp_beta_idx = tmp_beta.shape[0]
- while iter < max_iter:
- iter += 1
- beta_last = beta_c_last[:tmp_beta_idx]
- c_last = beta_c_last[tmp_beta_idx:]
- deriv_last = loss_derivative(beta_last, c_last)
- if np.linalg.norm(deriv_last) <= epsilon or iter >= max_iter:
- return beta_last.reshape((-1, len(M_c) + 1)), c_last, iter, loss_SCAD(beta_last, c_last)
- dk = -np.dot(H, deriv_last)
- m, mk = 0, 0
- loss_Armijo_1 = loss_SCAD(beta_last, c_last)
- while m < 20: # 搜索最佳学习率
- if loss_SCAD(beta_last + t ** m * dk[:tmp_beta_idx], c_last + t ** m * dk[tmp_beta_idx:]) \
- < loss_Armijo_1 + sigma * t ** m * np.dot(deriv_last.T, dk):
- mk = m
- break
- m += 1
- beta_c_new = beta_c_last + t ** mk * dk
- beta_new = beta_c_new[:tmp_beta_idx]
- c_new = beta_c_new[tmp_beta_idx:]
- deriv_new = loss_derivative(beta_new, c_new)
- s = beta_c_new - np.concatenate((beta_last, c_last)) # 参数一阶差分
- y = deriv_new - deriv_last # 梯度一阶差分
- h_y = np.dot(H, y)
- H += np.dot(s, s.T) / np.dot(s.T, y) - np.dot(h_y, h_y.T) / np.dot(np.dot(y.T, H), y) # 更新伪黑塞矩阵的逆
- beta_c_last = beta_c_new
- s = DFP(M_c=(pay_data_y.std(), pay_data_y.mean()))
- print(s[0], s[1], s[2], s[3], sep='\n')
分3段,故有9*3=27个参数,可以看到第2和第3段参数估计一模一样
[[ 2.21651758e+02 1.24799988e+04 1.24799988e+04]
[-2.70472227e-02 1.26663922e+08 1.26663922e+08]
[ 2.84548849e-02 3.16436052e+07 3.16436052e+07]
[ 3.82476892e-02 3.05133523e+07 3.05133523e+07]
[ 1.13002044e-02 2.92317240e+07 2.92317240e+07]
[ 8.44805488e-02 3.13574382e+07 3.13574382e+07]
[-1.01630661e-01 2.93887077e+07 2.93887077e+07]
[ 3.42105205e-02 3.08086230e+07 3.08086230e+07]
[ 7.84099476e+00 2.79222208e+07 2.79222208e+07]]
门槛值c:[[ 26632.39914284], [113303.41470849]]


雷达卡




京公网安备 11010802022788号







