机器学习

特征工程

特征提取 sklearn.features_extraction

  • 字典特征提取

    1
    2
    from sklearn.features_extraction import DictVectorizer	
    features = DictVectorizer().fit_transform(datas)
  • 文本特征提取

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    from sklearn.feature_extraction.text import CountVectorizer
    features = CountVectorizer().fit_transform(datas)

    # 中文分词使用 jieba 库
    import jieba
    def cut(text):
    return " ".join(jieba.cut(text))

    print(cut("我爱北京天安门"));

    # Tfidf
    from sklearn.features_extraction.text import TfidfVectorizer
    features = TfidfVectorizer().fit_transform(datas)
  • 无量纲化

    1. 归一化 MinMaxScaler
    2. 标准化 StanderScaler
  • 独热编码

  • 降维

    1.低方差过滤

    1
    2
    3
    4
    from sklearn.feature_selection import VarianceThreshold
    features = VarianceThreshold().fit_transform(datas)
    # VarianceThreshold(threshold= x)
    # x为整数,删除方差≤x的特征

    2.主成分分析

    1
    2
    3
    from sklearn.decomposition import PCA
    features = PCA().fit_transform(datas)
    # x为整数时,则减少到x个特征, 如果为小数,则保留百分比数据

机器学习

转换器和估计器

  • 转换器(transformer) - 特征工程的父类
  • 估计器(estimator) - 机器学习算法的实现

模型选择与调优

  • 交叉验证 (cross validation):将训练数据,分为训练和验证集。以下图为例:将数据分为4份,其中一份作为验证集,经过4次(组)的测试,每次更换不同的验证集,即得到4组模型的结果,取平均值作为最终结果,又称4折交叉验证

    交叉验证
  • 超参数搜索-网格搜索 (Grid Search):通常情况下,有很多参数需要手动指定 (如KNN),这种叫超参数。手动过程繁杂,所以需要对模型预设几种超参数组合。每组超参数都采用交叉验证来进行评估。最终选出最优参数组合建立模型

  • API

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from sklearn.model_selection import GridSearchCV
    # GridSearchCV中包含三个参数, estimator, param_grid, cv
    # estimator 为估计器
    # param_grid 为估计器参数,如(dict){"n_neighbors":[1, 3, 5]}
    # cv 指定几折交叉验证
    # 详细例子请看下文 KNN算法样例
    # tips: 网格搜索每次都会进行标准化,如果之前标准化过,就会导致数据泄露,影响正确性
    # estimator = Pipeline([('scaler', StanderScaler()), ('sgd', SGDRegressor(fit_intercept= True))])
    # param_dict = {"sgd__eta0": [1e-2, 1e-3, 1e-4]}
    # estimator = GridSearchCV(estimator= estimator, param_dict, cv= 4)

用于分类的估计器 (目标是类型)

  1. KNN算法(K-近邻算法):

    1. 核心思想:根据邻居来分类

    2. 定义:如果一个样本在特征空间中的k个最相似(即特征空间中最临近)的样本中大多数属于某一个类别,则该样本也属于这个类别

    3. 距离:确定邻居可以使用欧氏距离(或曼哈顿距离,明可夫斯基距离)

    4. 确定 k 的大小:过小的 k 受异常值影响大, 过大的 k 会受到样本不均衡的影响

    5. API:

      1
      2
      3
      4
      from sklearn.neighbors import KNeighborsClassifier
      model = KNeighborsClassifier(n_neighbors= 5, algorithm= "auto"
      # n_neighbors: int,默认为5 表示上文的 k
      # algorithm: {'auto', 'ball_tree', 'kd_tree', 'brute'}
    6. 总结:优点:简单,易于理解,易于实现 缺点 :计算量大,内存开销大,k 的选择影响大

    7. 使用场景:小数据场景,几千到几万的样本

    8. 样例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      import pandas as pd
      from sklearn.model_selection import train_test_split
      from sklearn.datasets import load_iris
      from sklearn.neighbors import KNeighborsClassifier
      from sklearn.preprocessing import StandardScaler
      from sklearn.model_selection import GridSearchCV

      iris = load_iris()
      x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size= 0.25, random_state= 6)
      transfer = StandardScaler()
      x_train = transfer.fit_transform(x_train)
      x_test = transfer.transform(x_test)

      estimator = KNeighborsClassifier()

      # 网格搜索 + 交叉验证 注意数据泄露问题
      # param_dict = {"n_neighbors": [1, 3, 5, 7, 9, 11]}
      # GridSearchCV(estimator, param_grid= param_dict, cv= 10)

      estimator.fit(x_train, y_train)
      y_pred = estimator.predict(x_test)
      print(f"Score: {estimator.score(x_test, y_test)}")
  2. 朴素贝叶斯算法:

    1. 朴素:假设特征与特征之间是相互独立的

    2. 核心思想:基于朴素的贝叶斯算法

    3. 拉普拉斯平滑系数:避免概率为0 $P(F1|C)=\frac{N_i+\alpha}{N+\alpha m}$ 其中 α 为系数,一般为1m 为文档统计出的特征词个数

    4. API:

      1
      2
      3
      from sklearn.naive_bayes import MultinomialNB
      # MultinomialNB(alpha= 1.0)
      # 参数解释同上
    5. 总结:优点:发源于古典数学理论,有稳定的分类效率,对缺失不太敏感,算法简单,常用于文本分类,分类准确度高,速度快 缺点:使用了样本属性独立性的假设,特征属性有关联时效果不好

    6. 应用场景:文本分类

    7. 样例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      import pandas as pd
      from sklearn.model_selection import train_test_split
      from sklearn.feature_extraction.text import TfidfVectorizer
      from sklearn.datasets import fetch_20newsgroups
      from sklearn.naive_bayes import MultinomialNB

      news = fetch_20newsgroups(subset= "all")

      x_train, x_test, y_train, y_test = train_test_split(news.data, news.target, test_size= 0.2, random_state= 42)
      transfer = TfidfVectorizer()
      x_train = transfer.fit_transform(x_train)
      x_test = transfer.transform(x_test)

      estimator = MultinomialNB()
      estimator.fit(x_train, y_train)

      print(f"准确率: {estimator.score(x_test, y_test)}")
      # 准确率: 0.8474801061007957
  3. 决策树:例如银行决定是否给一个人贷款时,可以有如下决策树

    决策树

    1. 原理:信息熵,信息增益等

    2. 信息熵的定义:H(X) =  − Σi = 1nP(xi)log p(xi),单位:比特

    3. 决策树的划分依据之一 —— 信息增益:特征 A 对训练集 D 的信息增益 g(D, A),定义为集合 D 的信息熵 H(D) 与特征 A 给定条件下 D 的信息条件熵 H(D|A) 之差,公式为: g(D, A) = H(D) − H(D|A)

    4. 决策树的划分依据还有:ID3,C4.5,CART

    5. API:

      1
      2
      3
      4
      5
      from sklearn.tree import DecisionTreeClassifier
      DecisionTreeClassifier(criterion= "gini", max_depth= None, random_state= None)
      # criterion 划分依据,默认是 gini,也可以选择信息增益的熵 entropy
      # max_depth 树的深度大小 tips: 过大的树会导致 过拟合
      # random_state 随机数种子
    6. 决策树的可视化:

      1
      2
      from sklearn.tree import export_graphviz
      export_graphviz(decision_tree= estimator, out_file= "./tree.dot", feature_names= ['',''])

      借助网站 http://webgraphviz.com 来查看

    7. 总结:优点:简单的理解和解释,树可视化,可解释性强 缺点: 可能创建不能很好地推广数据的过于复杂的树,引起过拟合 改进:剪枝cart算法,随机森林

    8. 案例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      import pandas as pd
      from sklearn.feature_extraction import DictVectorizer
      from sklearn.model_selection import train_test_split
      from sklearn.tree import DecisionTreeClassifier, export_graphviz

      datas = pd.read_csv("https://hbiostat.org/data/repo/titanic.txt")

      features = datas[['pclass', 'age', 'sex']]
      targets = datas['survived']

      features['age'] = features['age'].fillna(features['age'].mean())
      features = features.to_dict(orient= "records")

      x_train, x_test, y_train, y_test = train_test_split(features, targets, test_size= 0.2, random_state= 24)

      transfer = DictVectorizer()
      x_train = transfer.fit_transform(x_train)
      x_test = transfer.transform(x_test)

      # 此处可以使用网格搜索来限制深度,从而达到更好的结果
      estimator = DecisionTreeClassifier(criterion= "entropy")
      estimator.fit(x_train, y_train)

      print(estimator.score(x_test, y_test))
      # 0.8022813688212928

      export_graphviz(estimator, out_file= "titanic.dot", feature_names= transfer.get_feature_names_out())
  4. 随机森林(集成学习方法):

    1. 定义:随机森林是一个包含多个决策树的分类器,输出的类别是由个别树输出的类别的众数而定

    2. 建造树的方法:

      • 训练集随机 —— 从 N 个样本中随机有放回的抽样 N
        • bootstarp 随机有放回抽样
        • 例如:[1, 2, 3, 4 ,5] -> [2, 2, 3, 1, 5]
      • 特征随机 —— 从 M 个特征中随机抽取 m 个特征
        • M >  > m 降维,防止过拟合
    3. API:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      from sklearn.ensemble import RandomForestClassifier
      RandomForestClassifier(n_estimators= 10, criterion= "gini", max_depth= None, bootstrap= True, random_state= 24, min_samples_split= 2)
      # 部分参数和决策树相同
      # n_estimators 森林里树的数量
      # max_features 每个决策树的最大特征数量,默认为 'auto'
      # 'sqrt'(auto) / 'log2' / 'None'
      # bootstrap 解释同上文
      # min_sample_split 节点划分最少样本数
      # min_sample_leaf 叶子节点最小样本数
      # 超参数: n_estimators, max_depth, min_sample_split, min_sample_leaf
    4. 总结:在当前所有算法中,具有较好的准确率。能有效运行在大数据集上,处理具有高维特征的输入样本,而且不需要降维。能够评估各个特征在分类问题上的重要性

回归和聚类算法

  1. 线性回归(Linear regression):

    1. 定义:利用回归方程(函数)对一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模的一种分析方式

    2. 特点:只有一个自变量的情况称为单变量回归,多于一个自变量的情况称为多元回归

    3. 通用公式:h(w) = w1x1 + w2x2 + ⋯ + b = wTx + b

    4. 线性关系一定是线性模型,线性模型不一定线性关系

    5. 损失函数(成本函数)优化:

      1. 正规方程: w = (XTX) − 1XTy 数学上的精确解
        1. 优点:可以直接求到最好的结果
        2. 缺点:当特征过多过复杂时,求解速度慢且得不到结果
        3. 数据量较小可以使用  < 100K
      2. 梯度下降 不标准化可能无法收敛
        1. 数据量较大可以使用  > 100K
        2. 优化方法:
          1. GD(Gradient Descent) 最原始的梯度下降算法
          2. SGD(Stochastic Gradient Descent) 随机梯度下降
            • 优点:高效,容易实现
            • 缺点:需要许多超参数,对特征标准化敏感
          3. SAG(Stochastic Average Gradient) 随机平均梯度法
        3. 使用网格搜索超参数时,务必使用pipeline进行标准化,否则会无法收敛
    6. API:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from sklearn.linear_model import LinearRegression
      LinearRegression(fit_intercept= True)
      # fit_intercept 是否计算偏置
      # LinearRegression.coef_ 回归系数
      # LinearRegression.intercept_ 偏置

      from sklearn.linear_model import SGDRegressor
      SGDRegressor(loss= "squared_loss", fit_intercept= True, learning_rate= "invscaling", eta0= 0.01)
      # SGDRegressor 采用随机梯度下降学习,支持不同loss函数和正则化惩罚来拟合
      # loss 损失函数 "squared_loss" 最小二乘法(默认)
      # learning_rate 学习率填充
      # 'constant': eta = eta()
      # 'optimal': eta = 1.0 / (alpha * (t + t0)) (默认)
      # 'invscaling': eta = eta0 / pow(t, power_t) power_t = 0.25 存在父类中
      # 同理也有回归系数和偏置项的api
    7. 模型评估:sklearn.metrics

      1. 均方误差(MSE): $MSE=\frac{1}{m}\sum_{i=1}^m(y_i-\bar y)^2$
      2. 平均绝对误差(MAE)
      3. 决定系数 (R2)
      4. 均方根误差 (RMSE)
  2. 过拟合与欠拟合

    1. 欠拟合:原因:学习到的特征过少 解决:增加数据特征数量

    2. 过拟合:原因:原始特征过多,存在一些嘈杂特征,模型过于复杂 解决:

      • 正则化类别

        • L2正则化(最常用)

          • 作用:可以使其中一些 w 变小,削弱某个特证影响
          • 优点:越小的参数说明模型越简单,越简单的模型越不容易出现过拟合现象
          • Ridge回归
          • 加入L2正则化后的损失函数:

          $$ J(w)=\frac{1}{2m}\sum_{i=1}^m(h_w(x_i)-y_i)^2+\lambda \sum_{j=1}^{n}w_j^2 $$

          • 其中 $\lambda \sum_{j=1}^n w_j^2$ 为惩罚项,m 为样本数, n 为特征数, λ 为步长,可以超参数
        • L1正则化

          • 和 L2正则化相似,都在损失函数后加入惩罚项
          • 惩罚项为:$\lambda \sum_{j=1}^n |w_j|$
          • 作用:可以使得其中的 w 直接变为 0,删除某个特征影响
          • LASSO回归
  3. 岭回归(Ridge):

    1. 带有L2正则化的线性回归

    2. API:

      1
      2
      3
      4
      5
      6
      from sklearn.linear_model import Ridge
      Ridge(alpha= 1.0, fit_intercept= True, solver= "auto")
      # alpha 正则化力度 即上文的 lambda 0~1, 1~10, 可超参数
      # solver 优化方法
      # 在大数据集的情况下采用 SAG
      # 同理也有回归系数和偏置项
    3. Ridge相当于SGD加上了L2正则化,但Ridge实现了SAG

    4. 正则化力度越大,权重系数越小,反之,正则化力度越小,权重系数越大

  4. 逻辑回归 (Logistic Regression): 解决二分类问题

    1. tips:虽然带有“回归”,但逻辑回归是一种分类算法,只是它与回归之间有一定联系

    2. 线性回归的输出就是逻辑回归的输入,即 h(w) = w1x1 + w2x2 + w3x3 + ⋯ + b 为输入

    3. 激活函数:

      • Sigmoid 函数: $g(\theta^Tx)=\frac{1}{1+e^{-\theta^Tx}}$ 将某个函数映射到 [0, 1] 区间内
    4. 损失:对数似然损失 $$ cost(h_\theta(x),y)= \begin{cases} -\log(h_\theta(x))\ \ \ \ \ &if\ \ y=1\\ -\log(1-h_\theta(x))\ \ \ \ &if\ \ y=0 \end{cases} $$

    5. 完整损失函数: $cost(h_\theta(x), y)=\sum_{i=1}^{m}-y_i\log(h_\theta(x))-(1-y_i)\log(1-h_\theta(x))$

    6. 损失优化:梯度下降

    7. API:

      1
      2
      3
      4
      5
      6
      7
      from sklearn.linear_model import LogisticRegression
      LogisticRegression(solver= "liblinear", penalty= "l2", C= 1.0)
      # solver 优化求解方式
      # liblinear 默认开源库,坐标轴下降法
      # sag 同上文
      # penalty 正则化
      # C 正则化力度
    8. 案例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      # 数据集下载链接https://archive.ics.uci.edu/dataset/15/breast+cancer+wisconsin+original
      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
      from sklearn.metrics import roc_auc_score

      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']
      datas = pd.read_csv("./breast-cancer-wisconsin.data", names= column_names)

      datas = datas.replace(to_replace= "?", value= np.nan)
      datas = datas.dropna()

      x_train, x_test, y_train, y_test = train_test_split(datas.iloc[:, :-1], datas['Class'], test_size= 0.2, random_state= 24)
      transfer = StandardScaler()
      x_train = transfer.fit_transform(x_train)
      x_test = transfer.transform(x_test)

      estimator = LogisticRegression(penalty= "l2")
      estimator.fit(x_train, y_train)

      print(estimator.score(x_test, y_test))
      # 0.9562043795620438

      # 模型评估,详见下文
      from sklearn.metrics import classification_report
      print(classification_report(y_test, estimator.predict(x_test), labels= [2, 4], target_names= ['良性', '恶性']))
      # precision recall f1-score support
      #
      # 良性 0.96 0.98 0.97 88
      # 恶性 0.96 0.92 0.94 49
      #
      # accuracy 0.96 137
      # macro avg 0.96 0.95 0.95 137
      # weighted avg 0.96 0.96 0.96 137

      # ROC,AUC 详见下文
      y_test = np.where(y_test > 3, 1, 0)
      print(roc_auc_score(y_test, y_pred))
      # 0.9478200371057514
    9. 模型评估:

      • 精确率和召回率

        • 混淆矩阵
        • 混淆矩阵
        • 精确率(Precision):预测结果为正例样本中真实为正例的比例 $P_1=\frac{TP}{TP+FP}$
        • 召回率(Recall):真实结果为正例的样本中预测结果为正例的比例 $P_2=\frac{TP}{TP+FN}$
        • F1-Score:反应了模型的稳健性 $F1=\frac{2TP}{2TP+FN+FP}=\frac{2\cdot P_1\cdot P_2}{P_1+P_2}$
      • API:

        1
        2
        from sklearn.metrics import classification_report
        classification_report(y_true, y_pred, labels= [], target_names= None)
    10. 样本不均衡情况下的评估 —— ROC曲线和AUC指标

      1. TPR与FPR

        • $TPR=\frac{TP}{TP+FN}$ 所有真实类别为 1 的样本中,预测类型为 1 的比例
        • $FPR=\frac{FP}{FP+TN}$ 所有真是类别为 0 的样本中,预测类型为 1 的比例
      2. ROC曲线

        1. 定义:ROC曲线横轴为 FPR , 纵轴为 TPR ,当二者相等时,对于不论真实类别是 1 还是 0 的样本,分类器预测为 1 的概率是相等的,此时的 AUC0.5ROC
      3. AUC指标

        1. AUC 的概率意义是随机取一对正负样本,正样本得分大于负样本的概率

        2. AUC 的值域一般在 [0.5, 1],数值越大越好

        3. AUC = 1 ,完美分类器,采用这个分类器时,不管设定什么阈值都能得到完美预测。绝大多数预测的场合,不存在完美分类器

        4. 0.5 < AUC < 1, 优于随机猜测,当这个分类器妥善设置阈值时,有预测价值

        5. 如果 AUC 指标小于 0.5,可以反过来看(模型的对立面)

        6. API:

          1
          2
          3
          4
          from sklearn.metrics import roc_auc_score
          roc_auc_score(y_true, y_score)
          # y_true 每个样本的真实类别
          # y_score 预测得分,可以是正类的估计概率,置信值或者分类器方法的返回值
        7. 总结: AUC 只能用来评价二分类,非常适合评价样本不均衡中的分类器性能

无监督学习——K-means算法

  • 没有目标值->无监督学习

  • 包含:聚类(K-means),降维(PCA)

  • 原理:

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

  • API:

    1
    2
    3
    4
    from sklearn.cluster import KMeans
    KMeans(n_clusters= 8, init= "k-means++")
    # n_clusters 同上文 k
    # init 初始化方法 默认为 k-means
  • 模型评估:

    • 轮廓系数:bii 到其他族群的所有样本的距离最小值,aii 到本身簇的距离平均值 $$ SC_i=\frac{b_i-a_i}{max(b_i,a_i)} $$

    • “高内聚,低耦合”

      轮廓系数
    • 轮廓系数的值越接近 1 效果越好, 越接近 -1 效果越不好

    • API:

      1
      2
      3
      4
      from sklearn.metrics import silhouette_score
      silhouette_score(X, labels)
      # X 特征值
      # labels 目标值
  • 总结:特点分析:采用迭代式算法,直观易懂且实用 缺点:容易收敛到局部最优解(多次聚类)

模型的保存与加载

  1. API:

    1
    2
    3
    import joblib
    joblib.dump(estimator, 'test.pkl')
    # estimator = joblib.load('test.pkl')

机器学习
http://example.com/2025/11/22/ml/
作者
Suzuran
发布于
2025年11月22日
许可协议