【123】TensorFlow 多个特征值线性回归,并且使用训练集、验证集和测试集的例子

我使用加利福尼亚州房价数据来作例子。训练集和验证集用到的CSV文件在这里:https://download.csdn.net/download/zhangchao19890805/10584496

测试集用到的CSV文件在这里: https://download.csdn.net/download/zhangchao19890805/10631336

我们的目标是构建数学模型来预测房价。通常情况下,会有多个因素影响房价,因此使用多个特征值做线性回归。数学上,每个特征值视为一个自变量,相当与构建一个包含多个自变量的函数。
1.png

我写了两个 python 文件,一个是用来训练模型,并使用验证集验证模型。另一个是用测试集测试我的数学模型。

在程序中,使用到的特征值是这些:latitude、 longitude、
housing_median_age、total_rooms、 total_bedrooms、population、 households、 median_income 和 rooms_per_person

训练模型的文件:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import math
from sklearn import metrics

# 从CSV文件中读取数据,返回DataFrame类型的数据集合。
def zc_func_read_csv():
    zc_var_dataframe = pd.read_csv("http://114.115.223.20/california_housing_train.csv", sep=",")
    # 打乱数据集合的顺序。有时候数据文件有可能是根据某种顺序排列的,会影响到我们对数据的处理。
    zc_var_dataframe = zc_var_dataframe.reindex(np.random.permutation(zc_var_dataframe.index))
    return zc_var_dataframe

# 预处理特征值
def preprocess_features(california_housing_dataframe):
    selected_features = california_housing_dataframe[
        ["latitude",
         "longitude",
         "housing_median_age",
         "total_rooms",
         "total_bedrooms",
         "population",
         "households",
         "median_income"]
    ]
    processed_features = selected_features.copy()
    # 增加一个新属性:人均房屋数量。
    processed_features["rooms_per_person"] = (
        california_housing_dataframe["total_rooms"] /
        california_housing_dataframe["population"])
    return processed_features

# 预处理标签
def preprocess_targets(california_housing_dataframe):
    output_targets = pd.DataFrame()
    # Scale the target to be in units of thousands of dollars.
    output_targets["median_house_value"] = (
        california_housing_dataframe["median_house_value"] / 1000.0)
    return output_targets

def zc_func_yhat_eval(zc_param_yhat):
    r = []
    for ele in zc_param_yhat:
        r.append(ele[0])
    return r

# 根据数学模型计算预测值。公式是 y = w0 + w1 * x1 + w2 * x2 .... + w9 * x9
def zc_func_predict(zc_param_dataframe, zc_param_weight_arr):
    zc_var_result = []
    for var_row_index in zc_param_dataframe.index:
        y = zc_param_weight_arr[0]
        y = y + zc_param_weight_arr[1] * zc_param_dataframe.loc[var_row_index].values[0]
        y = y + zc_param_weight_arr[2] * zc_param_dataframe.loc[var_row_index].values[1]
        y = y + zc_param_weight_arr[3] * zc_param_dataframe.loc[var_row_index].values[2]
        y = y + zc_param_weight_arr[4] * zc_param_dataframe.loc[var_row_index].values[3]
        y = y + zc_param_weight_arr[5] * zc_param_dataframe.loc[var_row_index].values[4]
        y = y + zc_param_weight_arr[6] * zc_param_dataframe.loc[var_row_index].values[5]
        y = y + zc_param_weight_arr[7] * zc_param_dataframe.loc[var_row_index].values[6]
        y = y + zc_param_weight_arr[8] * zc_param_dataframe.loc[var_row_index].values[7]
        y = y + zc_param_weight_arr[9] * zc_param_dataframe.loc[var_row_index].values[8]
        zc_var_result.append(y)
    return zc_var_result



# 训练形如 y = w0 + w1 * x1 + w2 * x2 + ...  的直线模型。x1 x2 ...是自变量,
# w0 是常数项,w1 w2 ... 是对应自变量的权重。
# feature_arr 特征值的矩阵。每一行是 [1.0, x1_data, x2_data, ...] 
# label_arr 标签的数组。相当于 y = kx + b 中的y。
# training_steps 训练的步数。即训练的迭代次数。
# period         误差报告粒度
# learning_rate 在梯度下降算法中,控制梯度步长的大小。
def zc_fn_train_line(feature_arr, label_arr, validate_feature_arr, validate_label_arr, training_steps, periods, learning_rate):
    feature_tf_arr = feature_arr
    label_tf_arr = np.array([[e] for e in label_arr]).astype(np.float32)
    # 整个训练分成若干段,即误差报告粒度,用periods表示。
    # steps_per_period 表示平均每段有多少次训练
    steps_per_period = training_steps / periods
    # 存放 L2 损失的数组
    loss_arr = []
    weight_arr_length = len(feature_arr[0])
    # 开启TF会话,在TF 会话的上下文中进行 TF 的操作。
    with tf.Session() as sess:
        # 训练集的均方根误差RMSE。这是保存误差报告的数组。
        train_rmse_arr = []
        # 验证集的均方根误差RMSE。
        validate_rmse_arr = []

        # 设置 tf 张量(tensor)。注意:TF会话中的注释里面提到的常量和变量是针对TF设置而言,不是python语法。

        # 因为在TF运算过程中,x作为特征值,y作为标签
        # 是不会改变的,所以分别设置成input 和 target 两个常量。
        # 这是 x 取值的张量。设一共有m条数据,可以把input理解成是一个m行2列的矩阵。矩阵第一列都是1,第二列是x取值。
        input = tf.constant(feature_tf_arr)
        # 设置 y 取值的张量。target可以被理解成是一个m行1列的矩阵。 有些文章称target为标签。
        target = tf.constant(label_tf_arr)

        # 设置权重变量。因为在每次训练中,都要改变权重,来寻找L2损失最小的权重,所以权重是变量。
        # 可以把权重理解成一个多行1列的矩阵。初始值是随机的。行数就是权重数。
        weights = tf.Variable(tf.random_normal([weight_arr_length, 1], 0, 0.1))

        # 初始化上面所有的 TF 常量和变量。
        tf.global_variables_initializer().run()
        # input 作为特征值和权重做矩阵乘法。m行2列矩阵乘以2行1列矩阵,得到m行1列矩阵。
        # yhat是新矩阵,yhat中的每个数 yhat' = w0 * 1 + w1 * x1 + w2 * x2 ...。 
        # yhat是预测值,随着每次TF调整权重,yhat都会变化。
        yhat = tf.matmul(input, weights)
        # tf.subtract计算两个张量相减,当然两个张量必须形状一样。 即 yhat - target。
        yerror = tf.subtract(yhat, target)
        # 计算L2损失,也就是方差。
        loss = tf.nn.l2_loss(yerror)
        # 梯度下降算法。
        zc_optimizer = tf.train.GradientDescentOptimizer(learning_rate)
        # 注意:为了安全起见,我们还会通过 clip_gradients_by_norm 将梯度裁剪应用到我们的优化器。
        # 梯度裁剪可确保梯度大小在训练期间不会变得过大,梯度过大会导致梯度下降法失败。
        zc_optimizer = tf.contrib.estimator.clip_gradients_by_norm(zc_optimizer, 5.0)
        zc_optimizer = zc_optimizer.minimize(loss)
        for _ in range(periods):
            for _ in range(steps_per_period):
                # 重复执行梯度下降算法,更新权重数值,找到最合适的权重数值。
                sess.run(zc_optimizer)
                # 每次循环都记录下损失loss的值,并放到数组loss_arr中。
                loss_arr.append(loss.eval())
            v_tmp_weight_arr = weights.eval()
            train_rmse_arr.append(math.sqrt(
                    metrics.mean_squared_error(zc_func_yhat_eval(yhat.eval()), label_tf_arr)))
            validate_rmse_arr.append(math.sqrt(
                    metrics.mean_squared_error(zc_func_predict(validate_feature_arr, v_tmp_weight_arr), validate_label_arr)))
        zc_weight_arr = weights.eval()
        zc_yhat = yhat.eval()
    return (zc_weight_arr, zc_yhat, loss_arr, train_rmse_arr, validate_rmse_arr)
# end def train_line


# 构建用于训练的特征值。
# zc_var_dataframe 原来数据的 Dataframe
# 本质上是用二维数组构建一个矩阵。里面的每个一维数组都是矩阵的一行,形状类似下面这种形式:
#    1.0, x1[0], x2[0], x3[0], ...
#    1.0, x1[1], x2[1], x3[1], ...
#    .........................
# 其中x1, x2, x3 表示数据的某个维度,比如:"latitude","longitude","housing_median_age"。
# 也可以看作是公式中的多个自变量。
def zc_func_construct_tf_feature_arr(zc_var_dataframe):
    zc_var_result = []
    # dataframe中每列的名称。
    zc_var_col_name_arr = [e for e in zc_var_dataframe]
    # 遍历dataframe中的每行。
    for row_index in zc_var_dataframe.index:
        zc_var_tf_row = [1.0]
        for i in range(len(zc_var_col_name_arr)):
            zc_var_tf_row.append(zc_var_dataframe.loc[row_index].values[i])
        zc_var_result.append(zc_var_tf_row)
    return zc_var_result

# 画损失的变化图。
# ax  Axes
# zc_param_learning_steps 训练次数。
# zc_param_loss_arr 每次训练,损失变化的记录
def zc_func_paint_loss(ax, arr_train_rmse, arr_validate_rmse):
    ax.plot(range(0, len(arr_train_rmse)), arr_train_rmse, label="training", color="blue")
    ax.plot(range(0, len(arr_validate_rmse)), arr_validate_rmse, label="validate", color="orange")

# 主函数 
def zc_func_main():

    california_housing_dataframe = zc_func_read_csv()
    # 对于训练集,我们从共 17000 个样本中选择前 12000 个样本。
    training_examples = preprocess_features(california_housing_dataframe.head(12000))
    training_targets = preprocess_targets(california_housing_dataframe.head(12000))
    # 对于验证集,我们从共 17000 个样本中选择后 5000 个样本。
    validation_examples = preprocess_features(california_housing_dataframe.tail(5000))
    validation_targets = preprocess_targets(california_housing_dataframe.tail(5000))

    fig = plt.figure()
    fig.set_size_inches(5,5)


    zc_var_train_feature_arr = zc_func_construct_tf_feature_arr(training_examples)
    zc_var_leaning_step_num = 500
    (zc_weight_arr, zc_yhat, loss_arr, train_rmse_arr, validate_rmse_arr) = zc_fn_train_line(zc_var_train_feature_arr, 
                    training_targets["median_house_value"], validation_examples, 
                    validation_targets["median_house_value"], zc_var_leaning_step_num, 20, 0.002)
    # 画损失变化图。
    zc_func_paint_loss(fig.add_subplot(1,1,1), train_rmse_arr, validate_rmse_arr)
    plt.show()

    print("Training RMSE " + str(train_rmse_arr[len(train_rmse_arr) - 1]) + " Validate RMSE: " + 
          str(validate_rmse_arr[len(validate_rmse_arr) - 1]))

    print("wieghts:", zc_weight_arr)



zc_func_main()

运行结果如下

1.png

然后我们用测试集来测试模型:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import math
from sklearn import metrics


# 从CSV文件中读取数据,返回DataFrame类型的数据集合。
def zc_func_read_csv(zc_param_csv_url):
#     zc_var_dataframe = pd.read_csv("http://49.4.2.82/california_housing_train.csv", sep=",")
    zc_var_dataframe = pd.read_csv(zc_param_csv_url, sep=",")
    # 打乱数据集合的顺序。有时候数据文件有可能是根据某种顺序排列的,会影响到我们对数据的处理。
    zc_var_dataframe = zc_var_dataframe.reindex(np.random.permutation(zc_var_dataframe.index))
    return zc_var_dataframe

# 预处理特征值
def preprocess_features(california_housing_dataframe):
    selected_features = california_housing_dataframe[
        ["latitude",
         "longitude",
         "housing_median_age",
         "total_rooms",
         "total_bedrooms",
         "population",
         "households",
         "median_income"]
    ]
    processed_features = selected_features.copy()
    # 增加一个新属性:人均房屋数量。
    processed_features["rooms_per_person"] = (
        california_housing_dataframe["total_rooms"] /
        california_housing_dataframe["population"])
    return processed_features

# 预处理标签
def preprocess_targets(california_housing_dataframe):
    output_targets = pd.DataFrame()
    # Scale the target to be in units of thousands of dollars.
    output_targets["median_house_value"] = (
        california_housing_dataframe["median_house_value"] / 1000.0)
    return output_targets


# 根据数学模型计算预测值。公式是 y = w0 + w1 * x1 + w2 * x2 .... + w9 * x9
def zc_func_predict(zc_param_dataframe, zc_param_weight_arr):
    zc_var_result = []
    for var_row_index in zc_param_dataframe.index:
        y = zc_param_weight_arr[0]
        y = y + zc_param_weight_arr[1] * zc_param_dataframe.loc[var_row_index].values[0]
        y = y + zc_param_weight_arr[2] * zc_param_dataframe.loc[var_row_index].values[1]
        y = y + zc_param_weight_arr[3] * zc_param_dataframe.loc[var_row_index].values[2]
        y = y + zc_param_weight_arr[4] * zc_param_dataframe.loc[var_row_index].values[3]
        y = y + zc_param_weight_arr[5] * zc_param_dataframe.loc[var_row_index].values[4]
        y = y + zc_param_weight_arr[6] * zc_param_dataframe.loc[var_row_index].values[5]
        y = y + zc_param_weight_arr[7] * zc_param_dataframe.loc[var_row_index].values[6]
        y = y + zc_param_weight_arr[8] * zc_param_dataframe.loc[var_row_index].values[7]
        y = y + zc_param_weight_arr[9] * zc_param_dataframe.loc[var_row_index].values[8]
        zc_var_result.append(y)

    return zc_var_result


def zc_func_main():
    california_housing_dataframe = zc_func_read_csv("http://114.115.223.20/california_housing_train.csv")
    # 对于验证集,我们从共 17000 个样本中选择后 5000 个样本。
    validation_examples = preprocess_features(california_housing_dataframe.tail(5000))
    #print(validation_examples.describe())
    validation_targets = preprocess_targets(california_housing_dataframe.tail(5000))
    # 通过训练得到的模型权重
    zc_param_weight_arr = [-0.19103946,0.37296584,-0.7998271,0.25258455,0.03940793,-0.13476478,
                           -0.04755316,0.20973271,0.00714895,0.02928887]
    # 根据已经训练得到的模型系数,计算预验证集的测值。
    zc_var_validate_predict_arr = zc_func_predict(validation_examples, zc_param_weight_arr)
    # 计算验证集的预测值和标签之间的均方根误差。
    validation_root_mean_squared_error = math.sqrt(
        metrics.mean_squared_error(zc_var_validate_predict_arr, validation_targets["median_house_value"]))
    print("validation RMSE:", validation_root_mean_squared_error)


    # 基于测试集数据进行评估
    test_dataframe = zc_func_read_csv("http://114.115.223.20/california_housing_test.csv")
    # 测试集的样本
    test_examples = preprocess_features(test_dataframe)
    test_targets = preprocess_targets(test_dataframe)
    # 计算测试集的预测值
    zc_var_test_predict_arr = zc_func_predict(test_examples, zc_param_weight_arr)
    # 计算测试集的预测值和标签之间的均方根误差。
    test_root_mean_squared_error = math.sqrt(
        metrics.mean_squared_error(zc_var_test_predict_arr, test_targets["median_house_value"]))
    print("test RMSE:", test_root_mean_squared_error)

zc_func_main()

运行结果:

('validation RMSE:', 120.00240785178423)
('test RMSE:', 116.6171534701997)
  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 首先,我们需要将数据集分为训练集验证集测试集训练集用于训练模型,验证集用于验证模型的表现,测试集用于测试模型的泛化性能。 接下来,我们可以使用Lasso回归模型来进行回归分析。Lasso回归是一种线性回归模型,它在目标函数中加入了L1正则化项,可以有效地缩小特征的权重,从而避免过拟合。 最后,我们可以计算模型在训练集验证集测试集上的得分以及RMSE来评估模型的表现。 具体实现代码如下: ```python from sklearn.linear_model import Lasso from sklearn.model_selection import train_test_split from sklearn.metrics import r2_score, mean_squared_error # 假设数据集为 X 和 y # 将数据集分为训练集验证集测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=42) # 训练Lasso回归模型 lasso = Lasso(alpha=0.1) lasso.fit(X_train, y_train) # 在训练集上评估模型表现 train_score = lasso.score(X_train, y_train) train_rmse = mean_squared_error(y_train, lasso.predict(X_train), squared=False) # 在验证集上评估模型表现 val_score = lasso.score(X_val, y_val) val_rmse = mean_squared_error(y_val, lasso.predict(X_val), squared=False) # 在测试集上评估模型表现 test_score = lasso.score(X_test, y_test) test_rmse = mean_squared_error(y_test, lasso.predict(X_test), squared=False) print("Train score: {:.2f}, Train RMSE: {:.2f}".format(train_score, train_rmse)) print("Validation score: {:.2f}, Validation RMSE: {:.2f}".format(val_score, val_rmse)) print("Test score: {:.2f}, Test RMSE: {:.2f}".format(test_score, test_rmse)) ``` 其中,alpha参数控制L1正则化项的强度。我们可以根据实际情况调整alpha的值。 ### 回答2: 回归问题的目标是根据给定的特征数据预测连续数值的输出。为了评估模型的表现和确定模型的稳定性,常将数据集分为训练集测试集验证集。Lasso是一种常见的用于回归问题的正则化方法,用于减少模型的复杂度。 将数据集划分为训练集测试集验证集的目的是通过训练集进行模型的训练和参数调整,然后用测试集进行模型的评估,最后使用验证集验证模型的泛化能力。 下面给出一个回归问题使用Lasso进行建模,并给出三个数据集的得分和RMSE值的例子: 假设我们有一个回归问题的数据集,包含1000个样本和10个特征。我们按照70%的比例将数据集划分为训练集(700个样本)和测试集(300个样本),然后再从训练集中按照80%的比例划分为训练集(560个样本)和验证集(140个样本)。 首先,我们使用训练集进行Lasso回归模型的训练和参数调整。 接下来,我们使用测试集评估训练得到的模型的性能。假设我们得到了测试集上的R平方得分为0.8,RMSE为10。 最后,我们使用验证集验证已训练好的模型的泛化能力,得到了验证集上的R平方得分为0.75,RMSE为11。 通过以上的例子,我们可以看出,训练集上的得分并不能完全代表模型在其他数据集上的表现。因此,测试集验证集的评分和RMSE指标是更重要的度量标准,可以更好地评估模型的性能和泛化能力。 ### 回答3: 对于回归问题,常常会将数据集分为训练集测试集验证集。其中训练集用于模型的训练,测试集用于评估模型的泛化能力,验证集用于调整模型的超参数。 Lasso回归是一种常用的线性回归方法,它使用L1正则化项可以有效的进行特征选择,避免过拟合问题。下面给出了使用Lasso回归进行回归时,三个数据集的得分和均方根误差(RMSE)。 首先,将数据集划分为训练集测试集验证集,具体的划分比例可以根据实际情况进行调整。 然后,使用训练集进行模型的训练,得到模型参数。 接下来,使用训练好的模型对测试集进行预测,并计算预测结果的得分和RMSE。得分可以使用R平方值(R-squared)来衡量模型的拟合程度,RMSE则表示预测结果与真实值的平均误差。 最后,使用训练好的模型对验证集进行预测,并计算预测结果的得分和RMSE。这一步的目的是进一步评估模型的泛化能力,确保模型能够在新数据上表现良好。 完成以上步骤后,我们可以得到三个数据集上的得分和RMSE。根据得分和RMSE的大小,我们可以判断模型的性能如何。得分越接近1表示模型的拟合越好,RMSE越小表示模型的预测误差越小。 需要注意的是,以上的解释是基于使用Lasso回归进行回归问题的划分和评估的一般性描述,具体的结果会根据数据集和模型的具体情况而有所不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值