机器学习练习一:用Python实现线性回归

979 阅读5分钟

1.单变量线性回归

数据介绍:在本练习的这一部分中,您将使用一个变量实现线性回归,以预测餐厅的利润。假设你是一家连锁餐厅的首席执行官,正在考虑在不同的城市开设一家新餐厅,你可以得到城市的利润和人口数据。

1.1 画出原始数据图

import matplotlib.pyplot as plt
import pandas as pd
data = pd.read_csv('ex1data1.txt', names=['population', 'profit'])  # 读取数据并赋予列名

展示前5行数据

data.head()

画出原始数据图

data.plot(kind='scatter', x='population', y='profit', figsize=(12,8))
plt.show()

1.2 数据处理

插入一列特征x_0,其值均为1,目的为了在矩阵运算时匹配偏置{\theta}_0

# 插入全1列x0
data.insert(0, 'Ones', 1)

将特征值和目标值从数据中提取出来

# set X (training data) and y (target variable)
cols = data.shape[1]  # 特征值的数量n
X = data.iloc[:,0:cols-1]  # X是所有行,去掉最后一列
y = data.iloc[:,cols-1:cols]  # y是所有行,最后一列

将dataframe类型转换为np.matrix

# 构造矩阵和向量
X = np.matrix(X.values)
y = np.matrix(y.values)
# 初始化权重为0,1*2向量
theta = np.matrix(np.array([0,0]))

1.3 创建损失函数

损失函数数学模型(MSE)

创建损失函数

# 构建损失函数
def computeCost(X, y, theta):
    inner = np.power(((X * theta.T) - y), 2)  # J(θ)内部函数
    return np.sum(inner) / (2 * X.shape[0])  # X.shape[0]是样本数m

1.4 创建梯度下降函数

数学模型(批量梯度下降)

# 构造梯度下降函数
def gradientDescent(X, y, final_theta, alpha, iters):
    temp = np.matrix(np.zeros(theta.shape))
    # 特征数n
    featrue_num = int(theta.shape[1])
    # 用来保存损失值
    cost = np.zeros(iters)
    # 用来保存θ的值
    theta0_list = []  
    theta1_list = []
    
    for i in range(iters):
        # 梯度下降模型内部函数
        inner = (X * final_theta.T) - y
        # 分别迭代不同特征
        for j in range(featrue_num):
            term = np.multiply(inner, X[:,j])
            temp[0,j] = final_theta[0,j] - ((alpha / X.shape[0]) * np.sum(term))
            
        # 保存变量    
        theta0_list.append(temp[0,0])
        theta1_list.append(temp[0,1])
        final_theta = temp
        cost[i] = computeCost(X, y, final_theta)
        
        
    return final_theta, cost,theta0_list,theta1_list

1.5 进行训练并绘图

真实值和预测值的对比

# 进行梯度下降运算
g, cost, theta0, theta1 = gradientDescent(X, y, theta, alpha, iters)
# 绘制拟合图
x = np.linspace(df.population.min(), df.population.max(), 100)  # 返回在指定范围内的100个等间隔数
f = g[0, 0] + (g[0, 1] * x)  # 预测值
# 设置子画布
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(x, f, 'r', label='Prediction')
ax.scatter(df.population, df.profit, label='Traning Data')
ax.legend(loc=2)  # 设置标签
ax.set_xlabel('Population')
ax.set_ylabel('Profit')
ax.set_title('Predicted Profit vs. Population Size')
plt.show()

迭代次数和损失值的对比

# 绘制损失函数变化
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(iters), cost, 'r')  # np.arange():生成自然数组
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()

1.6 θ值和损失值的对比,3D图

python中3d图的绘制值得探讨,先贴代码

# 绘制3D图
from mpl_toolkits.mplot3d import Axes3D
# 创建对象
fig = plt.figure()
ax = Axes3D(fig)
# 指定值选取范围
axis=[min(theta0)-0.5, max(theta0)+0.5,min(theta1)-0.5, max(theta1)+0.5]
X0, X1 = np.meshgrid(
        # 随机两组数,起始值和密度由坐标轴的起始值决定
        np.linspace(axis[0], axis[1], int((axis[1] - axis[0]) * 200)).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3] - axis[2]) * 200)).reshape(-1, 1),
    )
# ravel()方法将高维数组降为一维数组,c_[]将两个数组以列的形式拼接起来,形成矩阵
X_grid_matrix = np.c_[X0.ravel(), X1.ravel()]

# 这一部分是计算cost损失值
inner = np.power(((X * X_grid_matrix.T) - y), 2)
inner = inner.sum(axis=0) / (2 * X.shape[0])
Z = inner.reshape(X0.shape)

# 设置标签
ax.set_xlabel("theta0")
ax.set_ylabel("theta1")
ax.set_zlabel("cost")

# 绘制3D曲面图
ax.plot_surface(X0, X1, Z, rstride=10, cstride=10, cmap='rainbow')
ax.view_init(30, 70)  # 改变视角
plt.show()

由此图可以直观的看出梯度下降的大致方向,其中:

引自:程序员说

  • np.meshgrid():该函数将随机出的两组数以坐标点的形式组合起来,其中X0为横坐标的组合,X1为纵坐标的组合

  • np.c_[]:将两个一维数组拼接起来,最终形成一个n * 2的矩阵,即每个点坐标的组合

另外,在计算损失值时用np.mat().sum(axis=0)的目的是将矩阵的每列求和,返回一个1 * n的矩阵。

2.用TensorFlow实现线性回归

数据介绍:在这一部分中,你将使用多元线性回归来预测房价。假设你要卖房子,你想知道一个好的市场价格是多少。一种方法是首先收集最近售出房屋的信息,并制作一个房价模型。 文件ex1data2.txt包含俄勒冈州波特兰市的房价培训集。第一栏是房子的大小(以平方英尺为单位),第二栏是卧室的数量,第三栏是房子的价格。

2.1 读取数据,特征归一化

因为数据的量纲相差较大,故需要进行特征归一化

# 读取数据
data = pd.read_csv('ex1data2.txt', header=None, names=['Size', 'Bedrooms', 'Price'])
# 特征归一化
data = (data - data.mean()) / data.std()
data.head()

2.2 提取数据

因为需要在tf设置float32类型的占位符,并且feed数据的时候不支持dataframe类型,所以将dataframe --> ndarray。

# add ones column
data.insert(0, 'Ones', 1)

# set X (training data) and y (target variable)
cols = data.shape[1]
X = data.iloc[:,0:cols-1]
y = data.iloc[:,cols-1:cols]
# 数据类型转换 dataframe --> ndarray
X = X.values.astype(np.float32)
y = y.values.astype(np.float32)

2.3 创建tf函数

函数返回损失值列表和最后的权重值

def linear_regression(X_data, y_data, alpha, epoch):
    # 设置占位符
    X = tf.placeholder(tf.float32, shape=X_data.shape)
    y = tf.placeholder(tf.float32, shape=y_data.shape)

    # 构造线性回归算法
    with tf.variable_scope('linear-regression'):
        W = tf.get_variable("weights",
                            (X_data.shape[1], 1),
                            initializer=tf.constant_initializer())  # 创建权重

        y_pred = tf.matmul(X, W)  # m*n @ n*1 -> m*1
        # 损失函数
        loss = 1 / (2 * X_data.shape[0]) * tf.matmul((y_pred - y), (y_pred - y), transpose_a=True)  # (m*1).T @ m*1 = 1*1
    
    # 梯度下降优化
    train_op = tf.train.GradientDescentOptimizer(alpha).minimize(loss)

    # run the session
    with tf.Session() as sess:
        # 变量初始化
        sess.run(tf.global_variables_initializer())
        loss_data = []

        for i in range(epoch):
            _, loss_val, W_val = sess.run([train_op, loss, W], feed_dict={X: X_data, y: y_data})
#             print(loss_val)
            loss_data.append(loss_val[0, 0])  # because every loss_val is 1*1 ndarray

            if len(loss_data) > 1 and np.abs(loss_data[-1] - loss_data[-2]) < 10 ** -9:  # early break when it's converged
                print('Converged at epoch {}'.format(i))
                break

    # clear the graph
    tf.reset_default_graph()
    return {'loss': loss_data, 'parameters': W_val}  # just want to return in row vector format

2.4 绘制迭代图

迭代次数和损失值的对比

result = linear_regression(X,y,0.1,1000)
# 绘制损失函数变化
fig, ax = plt.subplots(figsize=(12,8))
ax.plot(np.arange(152), result['loss'], 'r')  # np.arange():生成自然数组
ax.set_xlabel('Iterations')
ax.set_ylabel('Cost')
ax.set_title('Error vs. Training Epoch')
plt.show()