def learning_curve(X, y, Xval, yval, ilambda):
    """ 计算学习曲线所需的参数, 返回训练误差, 交叉验证误差"""

    # 随机选择训练样本以及验证样本, 重复50次取误差的平均值
    num_items = 50

    # 训练集大小
    m = X.shape[0]

    # 训练误差以及交叉验证误差
    error_train = np.zeros((m, 1))
    error_val = np.zeros((m, 1))

    for i in range(m):
        # 建立线性回归模型
        my_lr = LR(X[0:i + 1, :], y[0:i + 1])
        my_lr.gradient_descent_reg(0.001, ilambda, 5000)
        theta = my_lr.theta
        error_train[i:], _ = my_lr.compute_cost_reg(theta,
                                                    0,
                                                    X=X[:i + 1, :],
                                                    y=y[:i + 1])
        error_val[i:], _ = my_lr.compute_cost_reg(theta, 0, X=Xval, y=yval)

    # ~ for i in range(m):
    # ~ print("样本 {}".format(i+1))

    # ~ for t in range(num_items):
    # ~ # 随机获取训练以及交叉验证样本
    # ~ rand_indices = np.arange(m)			# 随机获取样本的100行, 进行可视化
    # ~ np.random.shuffle(rand_indices)		# shuffle返回None 就地打乱
    # ~ sel_1 = rand_indices[:i+1]

    # ~ np.random.shuffle(rand_indices)
    # ~ sel_2 = rand_indices[:i+1]

    # ~ # 建立线性回归模型
    # ~ my_lr = LR(X[sel_1, :], y[sel_1])

    # ~ # 使用不用的训练样本进行参数学习 -> 进行验证
    # ~ my_lr.gradient_descent_reg(0.001, ilambda, 5000)
    # ~ theta = my_lr.theta

    # ~ # 使用不同训练样本计算训练误差, lambda=0
    # ~ cost_train, _ = my_lr.compute_cost_reg(theta, 0, X=X[sel_1, :], y=y[sel_1])
    # ~ error_train[i:] += cost_train
    # ~ # 使用全部交叉验证样本计算交叉验证误差, lambda=0
    # ~ cost_val, _ = my_lr.compute_cost_reg(theta, 0, X=Xval[sel_2, :], y=yval[sel_2])
    # ~ error_val[i:] += cost_val

    # ~ # 计算误差平均值
    # ~ error_train /= num_items
    # ~ error_val /= num_items

    return error_train, error_val
def validation_curve(X, y, Xval, yval):
    """ 自动选择lambda """
    lambda_vec = np.array([0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10])
    lambda_vec = lambda_vec.reshape(lambda_vec.size, 1)

    error_train = np.zeros((lambda_vec.shape[0], 1))
    error_val = np.zeros((lambda_vec.shape[0], 1))

    for i in range(lambda_vec.size):
        # 遍历lambda, 计算每一个的训练以及验证误差
        ilambda = lambda_vec[i]

        #建立模型, 获得参数, 计算误差
        my_lr = LR(X, y)
        my_lr.gradient_descent_reg(0.001, ilambda, 5000)
        theta = my_lr.theta
        error_train[i:], _ = my_lr.compute_cost_reg(theta, 0, X=X, y=y)
        error_val[i:], _ = my_lr.compute_cost_reg(theta, 0, X=Xval, y=yval)

    return lambda_vec, error_train, error_val
# 显示训练集
# ~ plt.plot(X, y, 'rx', markersize=8, linewidth=1.5)
# ~ plt.xlabel('Change in water level (x)')
# ~ plt.ylabel('Water flowing out of the dam (y)')
# ~ plt.show()

# =========== Part 2: 计算正则线性回归代价与梯度 =============
#

theta = np.ones((2, 1))
ilambda = 1  # 使用iambda控制是否正则化

# 创建模型
my_lr = LR(np.hstack((np.ones((m, 1)), X)), y)
# 计算代价值与梯度
cost, grad = my_lr.compute_cost_reg(theta, ilambda)

print('在 theta = [1; 1] 时, 代价值为: {:.6f} '
      '\n(这个值大约是 303.993192)\n'.format(float(cost)))
print('在 theta = [1; 1] 时, 梯度分别为: [{:.6f}; {:.6f}] '
      '\n(这个值大约是 [-15.303016; 598.250744])\n'.format(float(grad[0]),
                                                     float(grad[1])))

## =========== Part 3: 训练线性回归模型 =============
#

ilambda = 0
alpha = 0.001
num_iters = 5000

# 使用梯度下降进行训练