机器学习(3)--正则化及python源码(附练习数据资源文件百度云)

吴恩达ML课程课后总结,以供复习、总结、温故知新,也欢迎诸位评论讨论分享,一起探讨一起进步:


上一篇:机器学习(3)--逻辑回归Python实现(附练习数据资源百度云)https://blog.csdn.net/qq_36187544/article/details/87916663

下一篇:机器学习(4)--前向神经网络及BP算法https://blog.csdn.net/qq_36187544/article/details/88180984


上数据资源与源代码

链接:https://pan.baidu.com/s/1eqr6f0Nd2-ZCMxfxC9zZJg 
提取码:krbt 

文件如下,xls文件是原始的所有数据,提取了部分数据写成credit_card_clients作为训练集,credit_card_test作为测试集

进行拟合时易产生过拟合现象,过拟合问题解决方案:
1,通过人工或者算法模型本身减少特征数量(比如专家系统,可以通过专家的分析减少特征)
2,正则化,保留所有特征,但减小量级

正则化代价函数:
参数加上惩罚项,让其尽可能的小从而得到二次函数等于简单函数,简化假设模型,函数会更平滑不易过拟合

思想较简单,在θj^2前加上惩罚项λ,因为目标是使代价函数J(θ)最小当惩罚项λ值较大时,函数倾向就偏于θj^2趋近于0。一般将θ0独立出来,不对θ0做惩罚


 对于使用而言,仅记住下式即可

θj也可用下式,是等价的,感觉来说下式更加简单


对于线性回归而言,如果不采用梯度下降,还可以采用正规方程的方法的方法求解:


接下来代码实现,代码部分其实很简单,将之前写过的LR算法改动一行即可,增加一个惩罚项,为了体现正则化的差异,利用测试集做了测试,增加了部分代码,测试结果如下:

可以发现正则化之后正确率相对更高了些,但是正确率仍旧不高,为什么?因为这里拟合的是线性,导致结果只能如此。源码如下:

import numpy as np

'''逻辑回归'''
# Hθ
def getH(θ, _x):
    θx = θ[0]
    for i in range(len(_x)):
        θx += θ[i+1]*_x[i]
    if θx >= 0:
        return 1.0 / (1 + np.exp(-θx))
    else:
        return np.exp(θx) / (1 + np.exp(θx))
    # return 1/(1+np.exp(-θx))  #这样直接返回结果会导致RuntimeWarning: overflow encountered in exp

# 不带正则化的逻辑回归
def lr(x,y, α):
    θ = [0]
    for i in range(len(x)):
        θ.append(0)

    m=len(x[0])
    for ii in range(100):
        sum = 0
        for j in range(m):
            _x = []
            for jj in range(len(x)):
                _x.append(x[jj][m-1])
            sum+=(getH(θ,_x)-y[j])
        θ[0] -= α*sum/m
        for i in range(len(x)):
            sum = 0
            for j in range(m):
                _x = []
                for jj in range(len(x)):
                    _x.append(x[jj][m-1])
                sum += ((getH(θ, _x) - y[j])*x[i][j])
            θ[i] -= α * sum/m
    return θ

# 带正则化的逻辑回归
def lr_r(x,y, α):
    θ = [0]
    for i in range(len(x)):
        θ.append(0)

    m=len(x[0])
    for ii in range(100):
        sum = 0
        for j in range(m):
            _x = []
            for jj in range(len(x)):
                _x.append(x[jj][m-1])
            sum+=(getH(θ,_x)-y[j])
        θ[0] -= α*sum/m
        for i in range(len(x)):
            sum = 0
            for j in range(m):
                _x = []
                for jj in range(len(x)):
                    _x.append(x[jj][m-1])
                sum += ((getH(θ, _x) - y[j])*x[i][j])
            θ[i] = θ[i]*(1-1000*α/m) - α * sum/m # 定义惩罚项λ=1000
    return θ

x, y = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]],[]
for sample in open("credit_card_clients.txt", "r"):
    aaa,_x1, _x2, _x3, _x4, _x5, _x6,  _x7, _x8, _x9, _x10, _x11, _x12,_x13,_x14,_x15,_x16,_x17,_x18,_x19,_x20,_x21,_x22,_x23,_y = sample.split("	")
    x[0].append(int(_x1))
    x[1].append(int(_x2))
    x[2].append(int(_x3))
    x[3].append(int(_x4))
    x[4].append(int(_x5))
    x[5].append(int(_x6))
    x[6].append(int(_x7))
    x[7].append(int(_x8))
    x[8].append(int(_x9))
    x[9].append(int(_x10))
    x[10].append(int(_x11))
    x[11].append(int(_x12))
    x[12].append(int(_x13))
    x[13].append(int(_x14))
    x[14].append(int(_x15))
    x[15].append(int(_x16))
    x[16].append(int(_x17))
    x[17].append(int(_x18))
    x[18].append(int(_x19))
    x[19].append(int(_x20))
    x[20].append(int(_x21))
    x[21].append(int(_x22))
    x[22].append(int(_x23))
    y.append(int(_y))

x[0], x[1], x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15],x[16],x[17],x[18],x[19],x[20],x[21],x[22],y = np.array(x[0]), np.array(x[1]), np.array(x[2]), np.array(x[3]), np.array(x[4]), np.array(x[5]), np.array(x[6]), np.array(x[7]), np.array(x[8]), np.array(x[9]), np.array(x[10]),  np.array(x[11]), np.array(x[12]), np.array(x[13]), np.array(x[14]), np.array(x[15]), np.array(x[16]), np.array(x[17]), np.array(x[18]), np.array(x[19]), np.array(x[20]), np.array(x[21]), np.array(x[22]),np.array(y) # 转化为Numpy数组待处理
# 记录下标准值供测试使用
mean ,std= [],[]
for i in range(len(x)):
    mean.append(x[i].mean())
    std.append(x[i].std())
x[0] = (x[0] - x[0].mean()) / x[0].std()  # 标准化,Mean表示取均值,std()为标准差,var()是方差
x[1] = (x[1] - x[1].mean()) / x[1].std()
x[2] = (x[2] - x[2].mean()) / x[2].std()
x[3] = (x[3] - x[3].mean()) / x[3].std()
x[4] = (x[4] - x[4].mean()) / x[4].std()
x[5] = (x[5] - x[5].mean()) / x[5].std()
x[6] = (x[6] - x[6].mean()) / x[6].std()
x[7] = (x[7] - x[7].mean()) / x[7].std()
x[8] = (x[8] - x[8].mean()) / x[8].std()
x[9] = (x[9] - x[9].mean()) / x[9].std()
x[10] = (x[10] - x[10].mean()) / x[10].std()
x[11] = (x[11] - x[11].mean()) / x[11].std()
x[12] = (x[12] - x[12].mean()) / x[12].std()
x[13] = (x[13] - x[13].mean()) / x[13].std()
x[14] = (x[14] - x[14].mean()) / x[14].std()
x[15] = (x[15] - x[15].mean()) / x[15].std()
x[16] = (x[16] - x[16].mean()) / x[16].std()
x[17] = (x[17] - x[17].mean()) / x[17].std()
x[18] = (x[18] - x[18].mean()) / x[18].std()
x[19] = (x[19] - x[19].mean()) / x[19].std()
x[20] = (x[20] - x[20].mean()) / x[20].std()
x[21] = (x[21] - x[21].mean()) / x[21].std()
x[22] = (x[22] - x[22].mean()) / x[22].std()

θ=[1.0838212187817922, -0.045955968961057296, 0.2900506418097455, -0.3127799856789351, 0.137783064865873, 2.4100461504016066, 1.7189506195292905, 1.582471758324859, 1.4126993687049045, 1.3885654177918474, 1.119129407787314, -0.060791017217695656, -0.05068254473086228, -0.037071324667241855, 0.0264489989904585, -0.005852121886165663, 0.014332012489780702, -0.7075552647477504, -0.6615940786053858, -0.2321243465015359, -0.5072334204862982, -0.27004565251264956, -0.34783918371064676, 0]
# lr(x,y,0.2)  #本来应当调用这一行计算不带正则化的逻辑回归的结果,但是为了加快运算速度,之前计算过该值,且这部分程序没变化的情况下直接调用List运行更快
θ1= lr_r(x,y,0.2)

# 测试不带正则化的逻辑回归效果
def test(θ , test):
    sum = θ[0]
    for i in range(1, len(θ)):
        sum += θ[i]*(test[i-1]-mean[i-1])/std[i-1]
    if sum>0:return 1
    else:return 0

# 获取测试集
x, y = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]],[]
for sample in open("credit_card_test.txt", "r"):
    aaa,_x1, _x2, _x3, _x4, _x5, _x6,  _x7, _x8, _x9, _x10, _x11, _x12,_x13,_x14,_x15,_x16,_x17,_x18,_x19,_x20,_x21,_x22,_x23,_y = sample.split("	")
    x[0].append(int(_x1))
    x[1].append(int(_x2))
    x[2].append(int(_x3))
    x[3].append(int(_x4))
    x[4].append(int(_x5))
    x[5].append(int(_x6))
    x[6].append(int(_x7))
    x[7].append(int(_x8))
    x[8].append(int(_x9))
    x[9].append(int(_x10))
    x[10].append(int(_x11))
    x[11].append(int(_x12))
    x[12].append(int(_x13))
    x[13].append(int(_x14))
    x[14].append(int(_x15))
    x[15].append(int(_x16))
    x[16].append(int(_x17))
    x[17].append(int(_x18))
    x[18].append(int(_x19))
    x[19].append(int(_x20))
    x[20].append(int(_x21))
    x[21].append(int(_x22))
    x[22].append(int(_x23))
    y.append(int(_y))

# 测试集测试不带正则化的逻辑回归
y_equal_1_right = 0     # 正确值是y=1时正确的个数
y_equal_1_wrong = 0     # 正确值是y=1时错误的个数
y_equal_0_right = 0     # 正确值是y=0时正确的个数
y_equal_0_wrong = 0     # 正确值是y=0时错误的个数
for i in range(len(x[0])):
    lst = []
    for j in range(len(x)):
        lst.append(x[j][i])
    if y[i]==1:
        if test(θ,lst) == 1:y_equal_1_right+=1
        else:y_equal_1_wrong+=1
    elif y[i]==0:
        if test(θ,lst) == 0:y_equal_0_right+=1
        else:y_equal_0_wrong+=1

print("不带正则化的逻辑回归--正确答案y=1时,正确的个数:"+str(y_equal_1_right)+",错误的个数:"+str(y_equal_1_wrong)+"正确率:"+str(y_equal_1_right/(y_equal_1_right+y_equal_1_wrong)))
print("不带正则化的逻辑回归--正确答案y=0时,正确的个数:"+str(y_equal_0_right)+",错误的个数:"+str(y_equal_0_wrong)+"正确率:"+str(y_equal_0_right/(y_equal_0_right+y_equal_0_wrong)))

# 测试集测试带正则化的逻辑回归
y_equal_1_right = 0     # 正确值是y=1时正确的个数
y_equal_1_wrong = 0     # 正确值是y=1时错误的个数
y_equal_0_right = 0     # 正确值是y=0时正确的个数
y_equal_0_wrong = 0     # 正确值是y=0时错误的个数
for i in range(len(x[0])):
    lst = []
    for j in range(len(x)):
        lst.append(x[j][i])
    if y[i]==1:
        if test(θ1,lst) == 1:y_equal_1_right+=1
        else:y_equal_1_wrong+=1
    elif y[i]==0:
        if test(θ1,lst) == 0:y_equal_0_right+=1
        else:y_equal_0_wrong+=1

print("带正则化的逻辑回归--正确答案y=1时,正确的个数:"+str(y_equal_1_right)+",错误的个数:"+str(y_equal_1_wrong)+"正确率:"+str(y_equal_1_right/(y_equal_1_right+y_equal_1_wrong)))
print("带正则化的逻辑回归--正确答案y=0时,正确的个数:"+str(y_equal_0_right)+",错误的个数:"+str(y_equal_0_wrong)+"正确率:"+str(y_equal_0_right/(y_equal_0_right+y_equal_0_wrong)))

猜你喜欢

转载自blog.csdn.net/qq_36187544/article/details/88060700