sklearn——线性回归与逻辑回归

1. 线性回归

1.1 数据生成

线性回归是机器学习算法的一个敲门砖,为了能够更方便直观地带大家入门,这里使用人工生成的简单的数据。生成数据的思路是设定一个二维的函数(维度高了没办法在平面上画出来),根据这个函数生成一些离散的数据点,对每个数据点我们可以适当的加一点波动,也就是噪声,最后看看我们算法的拟合或者说回归效果。

import numpy as np
import matplotlib.pyplot as plt 

def true_fun(X): # 这是我们设定的真实函数,即ground truth的模型
    return 1.5*X + 0.2

np.random.seed(0) # 设置随机种子
n_samples = 30 # 设置采样数据点的个数

'''生成随机数据作为训练集,并且加一些噪声'''
X_train = np.sort(np.random.rand(n_samples)) 
y_train = (true_fun(X_train) + np.random.randn(n_samples) * 0.05).reshape(n_samples,1)

1.2 定义模型

生成数据之后,我们可以定义我们的算法模型,直接从sklearn库中导入类LinearRegression即可,由于线性回归比较简单,所以这个类的输入参数也比较少,不需要多加设置。 定义好模型之后直接训练,就能得到我们拟合的一些参数。

from sklearn.linear_model import LinearRegression # 导入线性回归模型
model = LinearRegression() # 定义模型
model.fit(X_train[:,np.newaxis], y_train) # 训练模型
print("输出参数w:",model.coef_) # 输出模型参数w
print("输出参数b:",model.intercept_) # 输出参数b

输出参数w: [[1.4474774]]
输出参数b: [0.22557542]

1.3 模型测试与比较

可以看到线性回归拟合的参数是1.44和0.22,很接近实际的1.5和0.2,说明我们的算法性能还不错。 下面我们直接选取一批数据测试,然后通过画图看看算法模型与实际模型的差距。

X_test = np.linspace(0, 1, 100)
plt.plot(X_test, model.predict(X_test[:, np.newaxis]), label="Model")
plt.plot(X_test, true_fun(X_test), label="True function")
plt.scatter(X_train,y_train) # 画出训练集的点
plt.legend(loc="best")
plt.show()

sklearn——线性回归与逻辑回归_第1张图片

由于我们的数据比较简单,所以从图中也可以看出,我们的算法拟合曲线与实际的很接近。对于更复杂以及高维的情况,线性回归不能满足我们回归的需求,这时候我们需要用到更为高级一些的多项式回归了。

2. 多项式回归

多项式回归的思路一般是将
次多项式方程转化为线性回归方程,即将转换为(令

即可),然后使用线性回归的方法求出相应的参数。 一般实际的算法也是如此,我们将多项式特征分析器和线性回归串联,算出线性回归的参数之后倒推过去就行。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures # 导入能够计算多项式特征的类
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score

def true_fun(X): # 这是我们设定的真实函数,即ground truth的模型
    return np.cos(1.5 * np.pi * X)
np.random.seed(0)
n_samples = 30 # 设置随机种子

X = np.sort(np.random.rand(n_samples)) 
y = true_fun(X) + np.random.randn(n_samples) * 0.1

degrees = [1, 4, 15] # 多项式最高次
plt.figure(figsize=(14, 5))
for i in range(len(degrees)):
    ax = plt.subplot(1, len(degrees), i + 1)
    plt.setp(ax, xticks=(), yticks=())
    polynomial_features = PolynomialFeatures(degree=degrees[i],
                                             include_bias=False)
    linear_regression = LinearRegression()
    pipeline = Pipeline([("polynomial_features", polynomial_features),
                         ("linear_regression", linear_regression)]) # 使用pipline串联模型
    pipeline.fit(X[:, np.newaxis], y)
    
    scores = cross_val_score(pipeline, X[:, np.newaxis], y,scoring="neg_mean_squared_error", cv=10) # 使用交叉验证
    X_test = np.linspace(0, 1, 100)
    plt.plot(X_test, pipeline.predict(X_test[:, np.newaxis]), label="Model")
    plt.plot(X_test, true_fun(X_test), label="True function")
    plt.scatter(X, y, edgecolor='b', s=20, label="Samples")
    plt.xlabel("x")
    plt.ylabel("y")
    plt.xlim((0, 1))
    plt.ylim((-2, 2))
    plt.legend(loc="best")
    plt.title("Degree {}\nMSE = {:.2e}(+/- {:.2e})".format(
        degrees[i], -scores.mean(), scores.std()))
plt.show()

sklearn——线性回归与逻辑回归_第2张图片

2.1 交叉验证

在这个算法训练过程中,我们使用了一个技巧,就是交叉验证,类似的方法还有holdout检验以及自助法(交叉验证的升级版,即每次又放回去的选取数据)。 交叉验证法的作用就是尝试利用不同的训练集/测试集划分来对模型做多组不同的训练/测试,来应对测试结果过于片面以及训练数据不足的问题。

2.2 过拟合与欠拟合

我们知道多项式回归根据最高次数的不同,其回归的效果对于同一数据可能也不会不同,高次的多项式能够产生更多的弯曲从而拟合更多非线性规则的数据,低次的则贴近线性回归。 但在这过程中,也会产生一个过拟合与欠拟合的问题。

https://github.com/datawhalechina/machine-learning-toy-code/tree/main/ml-with-sklearn/LinearRegression

2. 逻辑回归

# 添加目录到系统路径方便导入模块,该项目的根目录为".../machine-learning-toy-code"
import sys
from pathlib import Path
curr_path = str(Path().absolute())
parent_path = str(Path().absolute().parent)
p_parent_path = str(Path().absolute().parent.parent)
sys.path.append(p_parent_path) 
print(f"主目录为:{p_parent_path}")


from torch.utils.data import DataLoader
from torchvision import datasets
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report
import numpy as np

train_dataset = datasets.MNIST(root = p_parent_path+'/datasets/', train = True,transform = transforms.ToTensor(), download = False)
test_dataset = datasets.MNIST(root = p_parent_path+'/datasets/', train = False, 
                               transform = transforms.ToTensor(), download = False)

batch_size = len(train_dataset)
train_loader = DataLoader(dataset=train_dataset, batch_size=100, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=100, shuffle=True)
X_train,y_train = next(iter(train_loader))
X_test,y_test = next(iter(train_loader))
# 打印前100张图片
images, labels= X_train[:100], y_train[:100] 
# 使用images生成宽度为10张图的网格大小
img = torchvision.utils.make_grid(images, nrow=10)
# cv2.imshow()的格式是(size1,size1,channels),而img的格式是(channels,size1,size1),
# 所以需要使用.transpose()转换,将颜色通道数放至第三维
img = img.numpy().transpose(1,2,0)
X_train,y_train = X_train.cpu().numpy(),y_train.cpu().numpy() # tensor转为array形式)
X_test,y_test = X_test.cpu().numpy(),y_test.cpu().numpy() # tensor转为array形式)

X_train = X_train.reshape(X_train.shape[0],784)
X_test = X_test.reshape(X_test.shape[0],784)

# solver:即使用的优化器,lbfgs:拟牛顿法, sag:随机梯度下降
model = LogisticRegression(solver='lbfgs', max_iter=400) # lbfgs:拟牛顿法
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred)) # 打印报告
          precision    recall  f1-score   support

       0       0.50      0.75      0.60         4
       1       0.71      1.00      0.83        10
       2       0.79      0.85      0.81        13
       3       0.79      0.69      0.73        16
       4       0.83      0.91      0.87        11
       5       0.60      0.23      0.33        13
       6       1.00      1.00      1.00         5
       7       0.88      1.00      0.93         7
       8       0.67      0.83      0.74        12
       9       0.71      0.56      0.63         9
  accuracy                         0.75       100
  macro avg    0.75      0.78      0.75       100
 weighted avg  0.74      0.75      0.73       100
ones_col=[[1] for i in range(len(X_train))] # 生成全为1的二维嵌套列表,即[[1],[1],...,[1]]
X_train = np.append(X_train,ones_col,axis=1)
x_train = np.mat(X_train)
X_test = np.append(X_test,ones_col,axis=1)
x_test = np.mat(X_test)
# Mnsit有0-9十个标记,由于是二分类任务,所以可以将标记0的作为1,其余为0用于识别是否为0的任务
y_train=np.array([1 if y_train[i]==1 else 0 for i in range(len(y_train))])
y_test=np.array([1 if y_test[i]==1 else 0 for i in range(len(y_test))])

# solver:即使用的优化器,lbfgs:拟牛顿法, sag:随机梯度下降
model = LogisticRegression(solver='lbfgs', max_iter=100) # lbfgs:拟牛顿法
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred)) # 打印报告
          precision    recall  f1-score   support

       0       1.00      0.98      0.99        90
       1       0.83      1.00      0.91        10
  accuracy                         0.98       100
  macro avg    0.92      0.99      0.95       100
  weighted avg 0.98      0.98      0.98       100

https://github.com/datawhalechina/machine-learning-toy-code/tree/main/ml-with-sklearn/LogisticRegression

你可能感兴趣的:(机器学习,python,回归)