基于Python的机器学习笔记

机器学习步骤概述

加载数据库:

sklearn.datasets模块提供多个函数加载和生成数据库,常用的数据库的加载函数如:

  • load_iris() 加载鸢尾花数据集,这是一个常用的多类分类数据集
  • load_digits() 加载手写数字数据集,每个实例都是一张8*8的数字图像
  • load_boston() 加载波士顿房价数据库,这是一个回归问题的数据集
  • load_diabets() 加载糖尿病数据集,这是一个可用于回归分析的数据集
  • datasets.fetch_<dataset_name>:比较大的数据集,主要用于测试解决实际问题,支持在线下载
  • make_classification()、make_regression()等 这是一系列的数据库创建函数,根据用户指定的参数可以生成可用于指定任务的数据集

这些函数执行后将返回datasets.base.Bunch(继承自字典),该数据结构具有键data(特征值),target(目标值),target_names(目标值名称列表),DESCR(对样本数据的描述)等,可通过.或[]查看键值

导包说明

  • from xxx import yyy 使用此种方法导入时 不需要在使用导入元素的前面加上模块或包名
  • import xxx 使用此种方法导入时 如果需要使用xxx中的元素 需要加上xxx

获取数据

from sklearn.datasets import load_iris

irisData = load_iris()
print("该数据集中的目标值为",irisData.target_names)
该数据集中的目标值为 ['setosa' 'versicolor' 'virginica']

数据处理

# 函数   train_test_split(data,target,test_size,random_state) 特征值数据,目标值数据,测试集占比,随机分割种子
# 返回值 训练集特征值,测试集特征值,训练集目标值,测试集目标值

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(irisData.data, irisData.target, test_size=0.2, random_state=22)

特征工程

特征提取

说明
特征提取是将输入的文本信息、图像信息转化为机器学习用到的数字信息的过程

字典数据的特征提取
from sklearn.feature_extraction import DictVectorizer

# 0、数据准备
data = [{'city': '北京','temperature':100}, {'city': '上海','temperature':60}, {'city': '深圳','temperature':30}]

# 1、实例化一个转换器类
# sparse = True 返回稀疏矩阵 否则返回独热模型矩阵  推荐True,利于节省空间,提高效率
transfer = DictVectorizer(sparse=False)

# 2、调用fit_transform()
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
print("特征名字:\n", transfer.get_feature_names_out())  # 用于获取特征提取后每列数据对应的特征名称的列表

data_new:
 [[  0.   1.   0. 100.]
 [  1.   0.   0.  60.]
 [  0.   0.   1.  30.]]
特征名字:
 ['city=上海' 'city=北京' 'city=深圳' 'temperature']
文本数据的特征提取

说明:
特征提取时对文本进行分词时使用的是" " , " ,"等标点符号,这对英文体系下的文本适用,但是中文体系下一个句子之间无空格等符号进行分割。
若直接使用转换器进行特征提取分词,那么其将认为一个句子为一个词,这不利于机器学习的算法,因此需要额外进行分词。

方法 1 特征提取结果为词频,词频高的对语义的影响大

# 方法 1 根据词频(EN)
from sklearn.feature_extraction.text import CountVectorizer

# 0、数据准备
dataEN = ["life is short,i like like python", "life is too long,i dislike python"]

# 1、实例化一个转换器类
transfer = CountVectorizer(stop_words=["is", "too"]) # stop_words停用词即对语句理解无用的词 转换器将跳过这些词而不进行特征提取

# 2、调用fit_transform
data_new = transfer.fit_transform(dataEN)
print("data_new:\n", data_new.toarray())  # sparse矩阵通过 sparseObject.toarray()可以转为独热模型矩阵
print("特征名字:\n", transfer.get_feature_names_out())
data_new:
 [[0 1 2 0 1 1]
 [1 1 0 1 1 0]]
特征名字:
 ['dislike' 'life' 'like' 'long' 'python' 'short']
# 方法 1 词频矩阵(CH)
from sklearn.feature_extraction.text import CountVectorizer
import jieba

def cut_word(text):
    """
    进行中文分词:"我爱北京天安门" --> "我 爱 北京 天安门"
    """
    return " ".join(list(jieba.cut(text)))

# 0、数据准备
dataCH =["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
        "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
        "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]

data_new = []
for sent in dataCH:
    data_new.append(cut_word(sent))

# 1、实例化一个转换器类
transfer = CountVectorizer(stop_words=["一种", "所以"])

# 2、调用fit_transform
data_final = transfer.fit_transform(data_new)
print("data_new:\n", data_final.toarray())
print("特征名字:\n", transfer.get_feature_names_out())
data_new:
 [[0 1 0 0 0 2 0 0 0 0 0 1 0 1 0 0 0 0 1 0 2 0 1 0 2 1 0 0 0 1 1 0 0 1 0]
 [0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 1 3 0 0 0 1 0 0 0 0 2 0 0 0 0 0 1 0 1]
 [1 0 0 4 3 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 0 0 1 0 0 0 2 1 0 0 1 0 0 0]]
特征名字:
 ['不会' '不要' '之前' '了解' '事物' '今天' '光是在' '几百万年' '发出' '取决于' '只用' '后天' '含义'
 '大部分' '如何' '如果' '宇宙' '我们' '放弃' '方式' '明天' '星系' '晚上' '某样' '残酷' '每个' '看到'
 '真正' '秘密' '绝对' '美好' '联系' '过去' '还是' '这样']

方法 2 TF-IDF 关键词(在其他文章出现较少,而在样本中出现多的词语)对语义的影响更大

from sklearn.feature_extraction.text import TfidfVectorizer
import jieba
data = ["一种还是一种今天很残酷,明天更残酷,后天很美好,但绝对大部分是死在明天晚上,所以每个人不要放弃今天。",
            "我们看到的从很远星系来的光是在几百万年之前发出的,这样当我们看到宇宙时,我们是在看它的过去。",
            "如果只用一种方式了解某样事物,你就不会真正了解它。了解事物真正含义的秘密取决于如何将其与我们所了解的事物相联系。"]

data_new = []
for sent in data:
    data_new.append(cut_word(sent))
# print(data_new)
# 1、实例化一个转换器类
transfer = TfidfVectorizer(stop_words=["一种", "所以"])

# 2、调用fit_transform
data_final = transfer.fit_transform(data_new)
print("data_new:\n", data_final.toarray())  # 值越大表示其重要性越大
print("特征名字:\n", transfer.get_feature_names_out())
data_new:
 [[0.         0.21821789 0.         0.         0.         0.43643578
  0.         0.         0.         0.         0.         0.21821789
  0.         0.21821789 0.         0.         0.         0.
  0.21821789 0.         0.43643578 0.         0.21821789 0.
  0.43643578 0.21821789 0.         0.         0.         0.21821789
  0.21821789 0.         0.         0.21821789 0.        ]
 [0.         0.         0.2410822  0.         0.         0.
  0.2410822  0.2410822  0.2410822  0.         0.         0.
  0.         0.         0.         0.         0.2410822  0.55004769
  0.         0.         0.         0.2410822  0.         0.
  0.         0.         0.48216441 0.         0.         0.
  0.         0.         0.2410822  0.         0.2410822 ]
 [0.15895379 0.         0.         0.63581516 0.47686137 0.
  0.         0.         0.         0.15895379 0.15895379 0.
  0.15895379 0.         0.15895379 0.15895379 0.         0.12088845
  0.         0.15895379 0.         0.         0.         0.15895379
  0.         0.         0.         0.31790758 0.15895379 0.
  0.         0.15895379 0.         0.         0.        ]]
特征名字:
 ['不会' '不要' '之前' '了解' '事物' '今天' '光是在' '几百万年' '发出' '取决于' '只用' '后天' '含义'
 '大部分' '如何' '如果' '宇宙' '我们' '放弃' '方式' '明天' '星系' '晚上' '某样' '残酷' '每个' '看到'
 '真正' '秘密' '绝对' '美好' '联系' '过去' '还是' '这样']

特征预处理

说明:
特征预处理是将特征提取到的数据信息进一步处理为更加符合机器学习算法的过程,主要包括归一化/标准化。

归一化

归一化根据最大最小值进行处理

from sklearn.preprocessing import MinMaxScaler
import pandas as pd
# 1、获取数据
data = pd.read_csv("./data/dating.txt")
data.head()
milageLitersConsumtimetarget
0409208.3269760.9539523
1144887.1534691.6739042
2260521.4418710.8051241
37513613.1473940.4289641
4383441.6697880.1342961
# 1、读取数据(接上)
data = data.iloc[:, :3] # 归一化/标准化仅需对特征值处理

# 2、实例化一个转换器类
transfer = MinMaxScaler(feature_range=(2,3))  # 设置归一化后各特征值所处的范围 默认 feature_range = (0,1)

# 3、调用fit_transform
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
data_new:
 [[2.44832535 2.39805139 2.56233353]
 [2.15873259 2.34195467 2.98724416]
 [2.28542943 2.06892523 2.47449629]
 ...
 [2.29115949 2.50910294 2.51079493]
 [2.52711097 2.43665451 2.4290048 ]
 [2.47940793 2.3768091  2.78571804]]
标准化

标准化根据平均值和标准差进行计算 避免了最大最小值为异常值时的归一化的鲁棒性

from sklearn.preprocessing import StandardScaler

# 1、获取数据
data = pd.read_csv("./data/dating.txt")
data.head()
data = data.iloc[:, :3] # 归一化/标准化仅需对特征值处理

# 2、实例化一个转换器类
transfer = StandardScaler() # 将数据转化为 均值为 0 标准差为 1 的范围内

# 3、调用fit_transform
data_new = transfer.fit_transform(data)  
print("data_new:\n", data_new)
data_new:
 [[ 0.33193158  0.41660188  0.24523407]
 [-0.87247784  0.13992897  1.69385734]
 [-0.34554872 -1.20667094 -0.05422437]
 ...
 [-0.32171752  0.96431572  0.06952649]
 [ 0.65959911  0.60699509 -0.20931587]
 [ 0.46120328  0.31183342  1.00680598]]

特征降维

说明:
特征降维是指在某些限定的情况下,降低随机变量(特征变量)的个数,得到一组不相关的主要变量的过程,主要方法为 特征选择以及主成分分析

特征选择
# 1、获取数据( 接上 )
data = data.iloc[:, 1:-2]  # 选取有价值的信息

# 2、实例化一个转换器类
transfer = VarianceThreshold(threshold=10) # 将删除所有方差低于threshold的随机变量

# 3、调用fit_transform
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new, data_new.shape)

# 计算某两个变量之间的相关系数
r1 = pearsonr(data["pe_ratio"], data["pb_ratio"])
print("相关系数:\n", r1)
r2 = pearsonr(data['revenue'], data['total_expense'])
print("revenue与total_expense之间的相关性:\n", r2)


data_new:
 [[ 5.95720000e+00  8.52525509e+10  8.00800000e-01 ...  1.21144486e+12
   2.07014010e+10  1.08825400e+10]
 [ 7.02890000e+00  8.41133582e+10  1.64630000e+00 ...  3.00252062e+11
   2.93083692e+10  2.37834769e+10]
 [-2.62746100e+02  5.17045520e+08 -5.67800000e-01 ...  7.70517753e+08
   1.16798290e+07  1.20300800e+07]
 ...
 [ 3.95523000e+01  1.70243430e+10  3.34400000e+00 ...  2.42081699e+10
   1.78908166e+10  1.74929478e+10]
 [ 5.25408000e+01  3.28790988e+10  2.74440000e+00 ...  3.88380258e+10
   6.46539204e+09  6.00900728e+09]
 [ 1.42203000e+01  5.91108572e+10  2.03830000e+00 ...  2.02066110e+11
   4.50987171e+10  4.13284212e+10]] (2318, 7)
相关系数:
 PearsonRResult(statistic=-0.004389322779936285, pvalue=0.8327205496590723)
revenue与total_expense之间的相关性:
 PearsonRResult(statistic=0.99584504131361, pvalue=0.0)
主成分分析PCA
from sklearn.decomposition import PCA
data = [[2,8,4,5], [6,3,0,8], [5,4,9,1]]

# 1、实例化一个转换器类
transfer = PCA(n_components=0.95) # n_components传入的值为小数时表示保留百分之多少的信息  当传入值为整数时表示减少到多少的特征

# 2、调用fit_transform
data_new = transfer.fit_transform(data)
print("data_new:\n", data_new)
data_new:
 [[ 1.28620952e-15  3.82970843e+00]
 [ 5.74456265e+00 -1.91485422e+00]
 [-5.74456265e+00 -1.91485422e+00]]

分类算法–监督学习

转换器与估计器

**转换器:**转换器(Transformer)是一种用于数据转换和预处理的对象或类。它接受输入数据,并对其进行某种形式的变换。常见的转换器包括

  • 数据缩放器(如StandardScaler、MinMaxScaler)
  • 特征选择器(如SelectKBest、PCA)
  • 特征提取器(如CountVectorizer、TF-IDFVectorizer)

估计器: 估计器(Estimator)是实现机器学习算法的对象或类。常见的估计器包括

  • 分类器(classifier)
  • 回归器(regresser)
  • 聚类器(clusterer)
  • 估计器的使用步骤:
    • 初始化 :先实例化一个estimator
    • 模型生成:调用 estimator.fit(x_train,y_train) 进行模型训练
    • 模型评估:调用 estimator.score(x_test,y_test) 评估模型准确性

KNN(K-邻近)算法

算法介绍:

预测一个新样本的类别时,算法预测其属于距离其最近的 K 个样本点属于同一个类别个数最多的类别。

距离的计算方式:欧氏距离、曼哈顿距离、闵可夫斯基距离

以鸢尾花分类为背景运用KNN算法分类

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier

# 1获取数据
iris = load_iris()

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)

# 3特征工程:标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)  # 训练集fit,测试集不fit,是因为实际我们不知道要分类的未知数据,所以标准化的平均值和标准差只能用测试集的

# 4KNN算法预估器
estimator = KNeighborsClassifier(n_neighbors=3,p=2) # p=2为欧氏距离 p=1为曼哈顿距离
estimator.fit(x_train, y_train)

# 5模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)

# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)

y_predict:
 [0 2 1 2 1 1 1 2 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 2 0 2 2 2 2 0 0 1 1 1 0 0
 0]
直接比对真实值和预测值:
 [ True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True False  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True]
准确率为:
 0.9736842105263158

模型选择与调优

k折交叉验证
  • 将训练集进一步进行划分,分为k份,其中一份作为验证集,其他k-1份仍作为训练集
  • 用训练集训练模型,然后使用验证集进行验证,得到这种情况下的模型准确率
  • 然后从上一轮训练集中选择一份为新一轮的验证集,上一轮的验证集加入本轮的测试集,再次重复以上操作,直至所有训练集都被作为过验证集(共k次验证)
  • 取k次验证的准确率平均值作为最终的模型准确率

通过交叉验证,能够使得模型更加准确可靠

超参数搜索

**超参数:**机器学习模型中有些参数需要手动指定,而无法通过模型自行决定的参数(如KNN算法中的K值)

网格搜索(Grid-Search)

from sklearn.model_selection import GridSearchCV

网格搜索交叉验证

GridSearchCV(estimator, param_grid=param_dict, cv)

  • estimator : 实例化的还没调试参数的估计器
  • param_grid : 估计器参数(dict字典数据类型)
  • cv : 经过几折交叉验证
  • return :返回一个特殊估计器,该估计器除了具有原估计器的功能属性外,还可以查看最佳参数、最佳结果、最佳估计器以及交叉验证结果。

以以鸢尾花分类为背景模型调优后的KNN算法

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV

# 1获取数据
iris = load_iris()

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)

# 3特征工程:标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 4KNN算法预估器
estimator = KNeighborsClassifier()

# 加入网格搜索与交叉验证
# 参数准备
param_dict = {"n_neighbors": [1, 3, 5, 7, 9, 11]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=10)
estimator.fit(x_train, y_train)

# 5模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)

# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)

# 最佳参数:best_params_
print("最佳参数:\n", estimator.best_params_)
# 最佳结果:best_score_
print("最佳结果:\n", estimator.best_score_)
# 最佳估计器:best_estimator_
print("最佳估计器:\n", estimator.best_estimator_)
# 交叉验证结果:cv_results_
print("交叉验证结果:\n", estimator.cv_results_)
y_predict:
 [0 2 1 2 1 1 1 2 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 2 0 2 2 2 2 0 0 1 1 1 0 0
 0]
直接比对真实值和预测值:
 [ True  True  True  True  True  True  True  True  True  True  True  True
  True  True  True  True  True  True False  True  True  True  True  True
  True  True  True  True  True  True  True  True  True  True  True  True
  True  True]
准确率为:
 0.9736842105263158
最佳参数:
 {'n_neighbors': 3}
最佳结果:
 0.9553030303030303
最佳估计器:
 KNeighborsClassifier(n_neighbors=3)
交叉验证结果:
 {'mean_fit_time': array([0.00080001, 0.00070019, 0.00050042, 0.00040014, 0.00010006,
       0.00099998]), 'std_fit_time': array([4.00006955e-04, 4.58380572e-04, 5.00417612e-04, 4.90066882e-04,
       3.00192833e-04, 3.16297988e-07]), 'mean_score_time': array([0.00160048, 0.00130033, 0.00129993, 0.00130029, 0.00180039,
       0.0010004 ]), 'std_score_time': array([1.49690505e-03, 4.58411861e-04, 4.58625936e-04, 4.58287295e-04,
       3.99995202e-04, 2.82100667e-07]), 'param_n_neighbors': masked_array(data=[1, 3, 5, 7, 9, 11],
             mask=[False, False, False, False, False, False],
       fill_value='?',
            dtype=object), 'params': [{'n_neighbors': 1}, {'n_neighbors': 3}, {'n_neighbors': 5}, {'n_neighbors': 7}, {'n_neighbors': 9}, {'n_neighbors': 11}], 'split0_test_score': array([0.91666667, 0.91666667, 1.        , 1.        , 0.91666667,
       0.91666667]), 'split1_test_score': array([1., 1., 1., 1., 1., 1.]), 'split2_test_score': array([0.90909091, 0.90909091, 0.90909091, 0.90909091, 0.90909091,
       0.90909091]), 'split3_test_score': array([0.90909091, 1.        , 0.90909091, 0.90909091, 0.90909091,
       1.        ]), 'split4_test_score': array([1., 1., 1., 1., 1., 1.]), 'split5_test_score': array([0.90909091, 0.90909091, 0.90909091, 0.90909091, 0.90909091,
       0.90909091]), 'split6_test_score': array([0.90909091, 0.90909091, 0.90909091, 1.        , 1.        ,
       1.        ]), 'split7_test_score': array([0.90909091, 0.90909091, 0.81818182, 0.81818182, 0.81818182,
       0.81818182]), 'split8_test_score': array([1., 1., 1., 1., 1., 1.]), 'split9_test_score': array([1., 1., 1., 1., 1., 1.]), 'mean_test_score': array([0.94621212, 0.95530303, 0.94545455, 0.95454545, 0.94621212,
       0.95530303]), 'std_test_score': array([0.04397204, 0.0447483 , 0.06030227, 0.06098367, 0.05988683,
       0.0604591 ]), 'rank_test_score': array([4, 1, 6, 3, 4, 1])}

朴素贝叶斯算法

拉普拉斯平滑系数

在计算概率时,可能出现概率为0的情况,这一般是由于训练集过小导致的数据集不均衡问题,为了避免0对计算的干扰,我们采用拉普拉斯平滑系数计算概率,公式为:

P( F | C )= (Nf + α) / (N + M)

  • Nf:F事件在C事件条件下出现的次数(训练文档中某特征词出现的次数)
  • N:C事件下包含F事件的其他事件出现的总次数(训练文档中特征词出现的总次数)
  • α:拉普拉斯平滑系数 一般取值为1
  • M:与F事件属于同一类事件的其他事件的种数(训练文档中统计出来的特征词种数)

算法介绍:

朴素贝叶斯算法的前提假设是:各个特征值直接相互独立

朴素贝叶斯即在各特征之间相互独立的情况下,运用贝叶斯公式计算概率

朴素贝叶斯常用于文本分类

优点:

  • 分类速度快,算法简单
  • 对缺失值不敏感

缺点:

  • 由于假定了特征之间相互独立,如果样本数据中特征之间存在关联时其效果不佳

以新闻分类为背景运用朴素贝叶斯算法

from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer

# 1获取数据
news = fetch_20newsgroups(subset="all")

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(news.data, news.target)

# 3特征工程:文本特征抽取-tfidf
transfer = TfidfVectorizer()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 4朴素贝叶斯算法预估器流程
estimator = MultinomialNB()
estimator.fit(x_train, y_train)

# 5模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)

# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)

决策树

算法介绍:

根据if-else来进行文本分类,其重点在于如何设置高效的决策顺序(先判断哪个特征后判断哪个特征)

**信息:**信息是用来消除随机不确定性的东西 - 香农

**信息熵 ( H ) :**也叫信息量

  • 公式: H ( X ) = − ∑ i = 1 n P ( x i ) log ⁡ b P ( x i ) H(X) = -\sum_{i=1}^{n} P(x_i) \log_b P(x_i) H(X)=i=1nP(xi)logbP(xi)

信息增益::用于衡量某条消息消除的不确定性的程度

  • 公式:G( D,a ) = H( D ) - H( D | a)
    • H(D | a )条件熵
      • 公式:H( D | a ) = ∑ x ∈ X P ( x ) H ( D ∣ X = a ) \sum_{x \in X} P(x) H(D|X=a) xXP(x)H(DX=a)

优点:

  • 算法易理解,树木可视化,可解释性强

缺点:

  • 创建的决策树容易出现过拟合问题

改进:

  • 剪枝算法
  • 随机森林

以鸢尾花进行分类为背景运用决策树

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier, export_graphviz # 决策树估计器,决策树可视化


# 1获取数据集
iris = load_iris()

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=22)

# 3决策树预估器
# criterion:特征选择标准,默认是gini(基尼不纯度),可以设置为entropy(信息增益)
# maxdepth: 决策树深度,默认为深度较深,尽量拟合训练集,但是这种情况容易出现过拟合现象,因此需要设置一个合适的深度(此处由于数据样本简单,不用考虑此点)
estimator = DecisionTreeClassifier(criterion="entropy",maxdepth=None) 
estimator.fit(x_train, y_train)

# 4模型评估
#方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)

#方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)

# 可视化决策树
export_graphviz(estimator, out_file="iris_tree.dot", feature_names=iris.feature_names)

y_predict:
 [0 2 1 2 1 1 1 1 1 0 2 1 2 2 0 2 1 1 1 1 0 2 0 1 2 0 1 2 2 1 0 0 1 1 1 0 0
 0]
直接比对真实值和预测值:
 [ True  True  True  True  True  True  True False  True  True  True  True
  True  True  True  True  True  True False  True  True  True  True  True
  True  True False  True  True False  True  True  True  True  True  True
  True  True]
准确率为:
 0.8947368421052632

决策树可视化生成决策树可视化文件后可以复制dot文件中的内容,打开可视化网站,在网站中输入dot文件内容即可进行可视化

https://dreampuf.github.io/GraphvizOnline

随机森林–决策树的改进

集成学习方法:
该方法通过建立多个模型,各自独立的学习和作出预测,最后结合成组合预测,通过多模型来解决单一分类问题,因此其优于任何一个单分类模型做出的预测。

算法介绍:

  • 森林:是一个包含多个决策树的分类器,其输出的类别是由各树输出的类别的众数决定的,
  • 随机:训练集随机(随机有放回抽样bootstrap)、特征随机(从样本中M个特征中随机抽出m个特征,且M >> m)
以泰坦尼克号乘客生存预测为背景运用随机森林
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV,train_test_split
from sklearn.feature_extraction import DictVectorizer

import pandas as pd
import numpy as np

# 获取数据
path = './data/titanic/'
data= pd.read_csv(path+"train.csv")

# 数据处理
x = data[['Pclass','Age','Sex']]
y = data['survived']

## 缺失值处理
x['Age'].fillna(x['Age'].mean(),inplace=True)

## 转字典
x = x.to_dict(orient='records')

## 划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y)


# 特征工程
transfer = DictVectorizer()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 实例化 
estimator = RandomForestClassifier(n_estimators=1200,max_depth=8)
estimator.fit(x_train,y_train)

'''
# 加入网格搜索与交叉验证
# 参数准备
param_dict = {"n_estimators": [120,200,300,500,800,1200],'max_depth':[5,8,15,25,30]}
estimator = GridSearchCV(estimator, param_grid=param_dict, cv=3)
estimator.fit(x_train, y_train)
'''
# 5模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)

# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)

'''
# 最佳参数:best_params_
print("最佳参数:\n", estimator.best_params_)
# 最佳结果:best_score_
print("最佳结果:\n", estimator.best_score_)
# 最佳估计器:best_estimator_
print("最佳估计器:\n", estimator.best_estimator_)
# 交叉验证结果:cv_results_
print("交叉验证结果:\n", estimator.cv_results_)
'''
C:\Users\NUDTer\AppData\Local\Temp\ipykernel_8624\4278225424.py:17: FutureWarning: A value is trying to be set on a copy of a DataFrame or Series through chained assignment using an inplace method.
The behavior will change in pandas 3.0. This inplace method will never work because the intermediate object on which we are setting values always behaves as a copy.

For example, when doing 'df[col].method(value, inplace=True)', try using 'df.method({col: value}, inplace=True)' or df[col] = df[col].method(value) instead, to perform the operation inplace on the original object.


  x['Age'].fillna(x['Age'].mean(),inplace=True)
C:\Users\NUDTer\AppData\Local\Temp\ipykernel_8624\4278225424.py:17: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  x['Age'].fillna(x['Age'].mean(),inplace=True)


y_predict:
 [0 1 1 0 0 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 1 1 1 1 1 0
 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 1 0 1 1 1 0 0 1
 0 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 0 1 0 1 1 0 0 0 0 0 1 1 1
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 0 1 1 0 0 1 0 0 0 1 1 0 1 0
 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 1 1 0 0 1 1 1 0 0 1 0 1 1 0 0 0 1 0 0
 1 1 1 1 0 0 1 0 0 0 0 1 1 0 1 0 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 0 0 0 1 0 0
 1]
直接比对真实值和预测值:
 787     True
498    False
712     True
569    False
757     True
       ...  
34      True
520     True
125    False
683     True
251    False
Name: survived, Length: 223, dtype: bool
准确率为:
 0.7713004484304933





'\n# 最佳参数:best_params_\nprint("最佳参数:\n", estimator.best_params_)\n# 最佳结果:best_score_\nprint("最佳结果:\n", estimator.best_score_)\n# 最佳估计器:best_estimator_\nprint("最佳估计器:\n", estimator.best_estimator_)\n# 交叉验证结果:cv_results_\nprint("交叉验证结果:\n", estimator.cv_results_)\n'

逻辑回归算法

算法说明:
逻辑回归是解决二分类问题的利器。
该分类算法之所以被叫做逻辑回归算法,是因为其输入是回归模型的输出,然后将输入传给激活函数(一般使用sigmoid激活函数),根据最终激活函数的输出值是否大于0.5来判断输入的分类情况。

  • sigmoid函数:
    • 公式: s i g m a ( x ) = 1 1 + e − x ​ sigma(x) = \frac{1}{1 + e^{-x}}​ sigma(x)=1+ex1
  • 损失函数:
    在这种方法下,传统的损失函数(如最小二乘法)已经不适用了,因为这类损失函数是根据具体的值计算误差,而在分类问题中,虽然有值但是该值最终会被转化为两种结果(是某种类别或不是某种类别),为此需要引入更适用的损失函数–对数似然损失
    • 公式: cost ( h ( x ) , y ) = { − log ⁡ ( h ( x ) ) , if  y = 1 − log ⁡ ( 1 − h ( x ) ) , if  y = 0 \text{cost}(h(x), y) = \begin{cases} -\log(h(x)), & \text{if } y = 1 \\ -\log(1 - h(x)), & \text{if } y = 0 \end{cases} cost(h(x),y)={log(h(x)),log(1h(x)),if y=1if y=0

以癌症分类预测为背景运用逻辑回归算法

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression



# 读取数据
## 此处由于数据只含值,未含特证名,因此还需要添加特征名
path = 'https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data'
column_names = ['Sample code number', 'Clump Thickness', 'Uniformity of Cell Size',
    'Uniformity of Cell Shape', 'Marginal Adhesion',
    'Single Epithelial Cell Size', 'Bare Nuclei', 'Bland Chromatin',
    'Normal Nucleoli', 'Mitoses', 'Class']
data = pd.read_csv(path,names=column_names)

# 缺失值处理
## 此处由于数据集中含有缺失值,且用?表示缺失值,因此需要先转化为NAN,再进行缺失值处理
data = data.replace(to_replace='?',value=np.nan)
data = data.dropna(how='any') # 删除含缺失值的样本数据

# 划分数据集
## 确定x,y
x = data.iloc[:,1:10]
y = data.iloc[:,10]

## 数据集划分
x_train,x_test,y_train,y_test = train_test_split(x,y)

# 特征工程
## 标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 模型训练
estimator = LogisticRegression()
estimator.fit(x_train,y_train)

# 模型评估
# 方法1:直接比对真实值和预测值
y_predict = estimator.predict(x_test)
print("y_predict:\n", y_predict)
print("直接比对真实值和预测值:\n", y_test == y_predict)

# 方法2:计算准确率
score = estimator.score(x_test, y_test)
print("准确率为:\n", score)
y_predict:
 [2 4 2 2 2 4 2 2 2 4 2 2 2 4 2 4 2 4 2 4 2 2 4 2 4 4 4 2 2 4 2 2 2 2 2 2 2
 4 2 2 2 2 2 2 2 2 2 4 2 2 4 4 2 4 4 2 4 2 4 2 4 2 2 2 2 4 4 2 4 2 4 4 2 2
 4 2 4 2 4 2 2 4 4 4 2 2 4 2 4 2 2 2 2 4 2 4 2 2 2 2 2 2 4 4 2 4 2 4 2 4 2
 2 4 2 2 2 2 4 2 2 2 2 2 2 2 4 4 4 2 4 2 2 2 2 2 2 4 4 2 2 2 2 2 4 4 2 2 4
 2 4 4 2 2 2 4 2 2 2 2 4 2 2 4 4 2 2 4 4 2 2 2]
直接比对真实值和预测值:
 682    True
123    True
470    True
332    True
508    True
       ... 
261    True
253    True
426    True
81     True
7      True
Name: Class, Length: 171, dtype: bool
准确率为:
 0.9649122807017544

分类算法评估方法

混淆矩阵

在这里插入图片描述

准确率

精确率Accuracy:
正例和假例中预测正确数量占总数量的比例

  • 公式: T P + T N T P + F N + F P + F N \frac{TP + TN}{TP + FN + FP + FN} TP+FN+FP+FNTP+TN

精确率与召回率

精确率Precision:
预测结果为正例样本中真实结果为正例的比例

  • 公式: T P T P + F P \frac{TP}{TP + FP} TP+FPTP

召回率Recall:
真实结果为正例的样本中预测结果为正例的比例

  • 公式: T P T P + F N \frac{TP}{TP + FN} TP+FNTP

F1-score

F1-score:
衡量模型的稳健性

  • 公式:F1-score =$ \frac{\text{2TP}}{ \quad \text{2TP} + \text{FN} + \text{FP}}$

ROC曲线与AUC指标

说明:
倘若样本集极度不均衡,可能出现模型全部预测为一种结果,但是精确率、准确率、召回率等指标均一切正常的情况,为了更全面的查看分类的能力,为此引入了衡量样本不均衡下的衡量模型的指标

召回率TPR:
所有真实结果为1的样本中,预测结果为1的比例,其也叫Recall

  • 公式: T P T P + F N \frac{TP}{TP + FN} TP+FNTP

误报率FPR:
所有真实结果为0的样本中,预测结果为1的比例

  • 公式: F P F P + T N \frac{FP}{FP + TN} FP+TNFP

ROC曲线:
下图中蓝线

AUC指标:
下图中蓝线与x轴围成的面积

  • 面积取值范围:0.5 <= AUC <= 1
  • 面积越接近0.5表示模型越不准确,越接近于1表示模型越精准,当AUC=0.5时表示模型预估的结果是随即猜测的

在这里插入图片描述

API

'''
Accuracy、Precision、Recall、F1-score
'''
from sklearn.metrics import classification_report
report = classification_report(y_test,y_predict,labels=[2,4],target_names=['良性','恶性'])
print(report)


''' 
ROC、AUC
'''
from sklearn.metrics import roc_auc_score
# score = roc_auc_score(y_true,y_predict)   要求y_true的值必须为0(反例)1(正例)
# 此方法仅能用于二分类问题
# 此方法运行后似乎会使得y_test的值被修改 需要重新运行癌症检测的逻辑回归算法得到原始数据
y_test = np.where(y_test>3,1,0)
score = roc_auc_score(y_test,y_predict)
print(score)
682    2
123    4
470    2
332    2
508    2
      ..
261    4
253    4
426    2
81     2
7      2
Name: Class, Length: 171, dtype: int64
              precision    recall  f1-score   support

          良性       0.98      0.96      0.97       113
          恶性       0.93      0.97      0.95        58

    accuracy                           0.96       171
   macro avg       0.96      0.97      0.96       171
weighted avg       0.97      0.96      0.97       171

682    2
123    4
470    2
332    2
508    2
      ..
261    4
253    4
426    2
81     2
7      2
Name: Class, Length: 171, dtype: int64
0.9650595056454074

回归算法–监督学习

线性回归

损失函数:
用来估量模型的预测值与真实值的不一致程度的函数

优化损失

损失函数的值代表了预测值与真实值之间的差别程度,为了使得模型的效果较好,需要让预测值尽可能接近真实值,因此损失函数的值也应趋近于0,为此需要不断修改线性回归各参数(权重、偏置值)使得损失函数值减小。常用的优化损失函数的方法有:

  • 正规方程
    • 说明:通过计算直接得到参数,逻辑简单,但当特征过多、复杂时将导致运算时间急剧增加而不能得到结果
    • 公式: W = ( X T X ) − 1 X T Y W = (X^T X)^{-1} X^T Y W=(XTX)1XTY
  • 梯度下降
    • 说明:不断尝试参数的修改方向,每次修改都沿着梯度方向修改,通过多次修改最终也能得到结果
    • 公式: θ n + 1 = θ n ​ − α ∇ J ( θ n ) θ n+1 =θn​ −α∇J(θ n ) θn+1=θnαJ(θn)

回归性能评估MSE

用于评估回归模型的预测能力

  • 公式:
    MSE ⁡ = 1 n ∑ i = 1 n ( Y i − Y ^ i ) 2 \operatorname{MSE} = \frac{1}{n} \sum_{i=1}^{n} (Y_i - \hat{Y}_i)^2 MSE=n1i=1n(YiY^i)2

欠拟合

  • 解释说明:在训练集和测试集中表现均不佳,体现为模型学习不充分
  • 出现原因:模型学习到的特征少
  • 解决方法:增加数据集的特征数量

过拟合

  • 解释说明:在训练集中表现良好,但在测试集中表现不佳
  • 出现原因:模型过于复杂,过度拟合训练集样本点
  • 解决方法:正则化
    • L1正则化(LASSO回归):能够使得某些特征的权重值直接等于0,使得模型更加简单,从而不易出现过拟合现象
      • 具体思路:L2正则化的损失函数后面加上了一个惩罚项,该惩罚项值为权重的平方之和,为了使得损失函数减小,势必会使得某些权重值降低,从而达到简化模型的目的,最终的损失函数为:

        J ( w ) = 1 2 m ∑ i = 1 m ( h w ( x i ) − y i ) 2 + λ ∑ j = 1 n ∣ w j ∣ J(w) = \frac{1}{2m} \sum_{i=1}^{m} (h_w(x_i) - y_i)^2 + {\lambda}{} \sum_{j=1}^{n} |w_j| J(w)=2m1i=1m(hw(xi)yi)2+λj=1nwj

    • L2正则化(Ridge岭回归):能够使得某些特征的权重值趋近于0,使得模型更加简单,从而不易出现过拟合现象
      • 具体思路:L2正则化的损失函数后面加上了一个惩罚项,该惩罚项值为权重的平方之和,为了使得损失函数减小,势必会使得某些权重值降低,从而达到简化模型的目的,最终的损失函数为:

        J ( w ) = 1 2 m ∑ i = 1 m ( h w ( x i ) − y i ) 2 + λ ∑ j = 1 n w j 2 J(w) = \frac{1}{2m} \sum_{i=1}^{m} (h_w(x_i) - y_i)^2 + {\lambda}{} \sum_{j=1}^{n} w_j^2 J(w)=2m1i=1m(hw(xi)yi)2+λj=1nwj2

常用的是L2正则化

以波斯顿房价预测为背景运用线性回归

正规方程(适用于数据量较小时)
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

"""
正规方程的优化方法对波士顿房价进行预测
"""

# 1获取数据
boston = load_boston() # `load_boston` has been removed from scikit-learn since version 1.2.[错误信息]

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(boston.data, boston.target, random_state=22)

# 3标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 4预估器
estimator = LinearRegression(fit_intercept = True) # fit_intercept 是否计算偏置,默认为True
estimator.fit(x_train, y_train)

# 5得出模型
print("正规方程-权重系数为:\n", estimator.coef_)
print("正规方程-偏置为:\n", estimator.intercept_)

# 6模型评估
y_predict = estimator.predict(x_test)
print("预测房价:\n", y_predict)
error = mean_squared_error(y_test, y_predict) # y_test真实值,y_predict预测值
print("正规方程-均方误差为:\n", error)

梯度下降(适用于数据量大时 100k以上)
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import SGDRegresso
from sklearn.metrics import mean_squared_error

"""
梯度下降的优化方法对波士顿房价进行预测
"""

# 1获取数据
boston = load_boston()

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(boston.data, boston.target, random_state=22)

# 3标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 4预估器
# loss : 损失类型    [Default] squared _loss 最小二乘法
# fit_intercept : 是否计算偏置    [Default]True
# earning_rate : 学习方式 [Default] invscaling(学习率逐渐降低)   constant(学习率保持不变)
# eta : 学习率
# max_iter : 最大迭代次数
# penalty : 
estimator = SGDRegressor(loss = "squared _loss",fit_intercept=True,earning_rate="constant", eta0=0.01, max_iter=10000, penalty="l1")
estimator.fit(x_train, y_train)

# 5得出模型
print("梯度下降-权重系数为:\n", estimator.coef_)
print("梯度下降-偏置为:\n", estimator.intercept_)

# 6模型评估
y_predict = estimator.predict(x_test)
print("预测房价:\n", y_predict)
error = mean_squared_error(y_test, y_predict) # y_test真实值,y_predict预测值
print("梯度下降-均方误差为:\n", error)

岭回归

**说明:**岭回归实际上就是带有L2正则化的线性回归

以波斯顿房价预测为背景运用岭回归

from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import  Ridge
from sklearn.metrics import mean_squared_error

"""
岭回归对波士顿房价进行预测
:return:
"""
# 1获取数据
boston = load_boston()
print("特征数量:\n", boston.data.shape)

# 2划分数据集
x_train, x_test, y_train, y_test = train_test_split(boston.data, boston.target, random_state=22)

# 3标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)

# 4预估器
estimator = Ridge(alpha=0.5, max_iter=10000) # alpha:正则化力度(即惩罚系数 λ ),优化选择方法slover=auto,是否进行标准化 normaliz
estimator.fit(x_train, y_train)


# 5得出模型
print("岭回归-权重系数为:\n", estimator.coef_)
print("岭回归-偏置为:\n", estimator.intercept_)

# 6模型评估
y_predict = estimator.predict(x_test)
print("预测房价:\n", y_predict)
error = mean_squared_error(y_test, y_predict)
print("岭回归-均方误差为:\n", error)

聚类算法–无监督学习

K-means算法

算法说明:

  • K-means聚类步骤
    • 1、随机设置K个特征空间内的点作为初始的聚类中心
    • 2、对于其他每个点计算到K个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别
    • 3、接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)
    • 4、如果计算得出的新中心点与原中心点一样,那么结束,否则重新进行第二步过程

在这里插入图片描述

import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# 创建数据集
# X为样本特征,Y为样本簇类别, 共1000个样本,每个样本2个特征,共4个簇,
# 簇中⼼在[-1,-1], [0,0],[1,1], [2,2], 簇⽅差分别为[0.4, 0.2, 0.2, 0.2]
X, y = make_blobs(n_samples=1000, n_features=2, centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
cluster_std=[0.4, 0.2, 0.2, 0.2],
random_state=9)

# 数据集可视化
plt.scatter(X[:, 0], X[:, 1], marker='o')
plt.show()

# 聚类算法
y_pred = KMeans(n_clusters=4, random_state=9).fit_predict(X)  # n_clusters:k值

# 评估模型
# 希望达到高内聚,低耦合
# 分别尝试n_cluses=2\3\4,然后查看聚类效果
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
# 查看轮廓系数[-1最差,1最佳]  
print(silhouette_score(X, y_pred))

原始数据可视化

聚类结果可视化

0.663699429101073

模型的保存与加载

from sklearn.externals import joblib
'''
保存模型应在estimator.fit() 得到模型之后

# 保存模型
# joblib.dump(estimator, "my_ridge.pkl") # 模型名.pkl
# 加载模型
estimator = joblib.load("my_ridge.pkl")
'''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NUDTer2026

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值