解决几乎任何机器学习问题 -- 学习笔记(组织机器学习项目)

书籍名:Approaching (Almost) Any Machine Learning Problem-解决几乎任何机器学习问题
此专栏记录学习过程,内容包含对这本书的翻译和理解过程

我们首先来看看文件的结构。对于你正在做的任何项目,都要创建一个新文件夹。在本例中,我
将项目命名为 “project” 。

项目文件夹内部应该如下所示。

  • input
    • train.csv
    • test.csv
  • src
    • create_folds.py
    • train.py
    • inference.py
    • models.py
    • config.py
    • model_dispatcher.py
  • models
    • model_rf.bin
    • model_et.bin
  • notebooks
    • exploration.ipynb
    • check_data.ipynb
  • README.md
  • LICENSE

让我们来看看这些文件夹和文件的内容。

**input/ **该文件夹包含机器学习项目的所有输入文件和数据。如果您正在开发 NLP 项目,您可以将 embeddings 放在这里。如果是图像项目,所有图像都放在该文件夹下的子文件夹中。
**scr/**我们将在这里保存与项目相关的所有 python 脚本。如果我说的是一个 python 脚本,即任何 *.py 文件,它都存储在 src 文件夹中。
** models/ **该文件夹保存所有训练过的模型。
**notebook/ **所有 jupyter notebook (即任何 *.ipynb 文件)都存储在笔记本 文件夹中。
**README.md **这是一个标记符文件,您可以在其中描述您的项目,并写明如何训练模型或在生产环境中使用。
**LICENSE **这是一个简单的文本文件,包含项目的许可证,如 MIT 、 Apache 等。关于许可证的详细介绍超出了本书的范围。

假设你正在建立一个模型来对 MNIST 数据集(几乎每本机器学习书籍都会用到的数据集)进行分类。如果你还记得,我们在交叉检验一章中也提到过 MNIST 数据集。网上有许多不同格式的 MNIST 数据集,但我们将使用 CSV 格式的数据集。

在这种格式的数据集中, CSV 的每一行都包含图像的标签和 784 个像素值,像素值范围从 0 到255 。数据集包含 60000 张这种格式的图像。

我们可以使用 pandas 轻松读取这种数据格式。

请注意,尽管图 1 显示所有像素值均为零,但事实并非如此。

在这里插入图片描述
图 1 : CSV 格式的 MNIST 数据集
在这里插入图片描述
我们不需要对这个数据集进行更多的探索。我们已经知道了我们所拥有的数据,没有必要再对不同的像素值进行绘图。从图 2 中可以清楚地看出,标签的分布相当均匀。因此,我们可以使用准确率 /F1 作为衡量标准。这就是处理机器学习问题的第一步:确定衡量标准!

现在,我们可以编写一些代码了。我们需要创建 src/ 文件夹和一些 python 脚本。

请注意,训练 CSV 文件位于 input/ 文件夹中,名为 mnist_train.csv 。

首先要创建的脚本是 create_folds.py 。

这将在 input/ 文件夹中创建一个名为 mnist_train_folds.csv 的新文件,与 mnist_train.csv 相同。唯一不同的是,这个 CSV 文件经过了随机排序,并新增了一列名为 kfold 的内容。一旦我们决定了要使用哪种评估指标并创建了折叠,就可以开始创建基本模型了。这可以在train.py 中完成。

import joblib
import pandas as pd
from sklearn import metrics
from sklearn import tree
def run(fold):# 读取数据文件df = pd.read_csv("../input/mnist_train_folds.csv")# 选取df中kfold列不等于folddf_train = df[df.kfold != fold].reset_index(drop=True)# 选取df中kfold列等于folddf_valid = df[df.kfold == fold].reset_index(drop=True)# 训练集输入,删除label列x_train = df_train.drop("label", axis=1).values# 训练集输出,取label列y_train = df_train.label.values# 验证集输入,删除label列x_valid = df_valid.drop("label", axis=1).values# 验证集输出,取label列y_valid = df_valid.label.values# 实例化决策树模型clf = tree.DecisionTreeClassifier()# 使用训练集训练模型clf.fit(x_train, y_train)# 使用验证集输入得到预测结果preds = clf.predict(x_valid)# 计算验证集准确率accuracy = metrics.accuracy_score(y_valid, preds)# 打印fold信息和准确率print(f"Fold={fold}, Accuracy={accuracy}")# 保存模型joblib.dump(clf, f"../models/dt_{fold}.bin")
if __name__ == "__main__":# 运行每个折叠run(fold=0)run(fold=1)run(fold=2)run(fold=3)run(fold=4)

您可以在控制台调用 python train.py 运行该脚本。

❯ python train.pyFold=0, Accuracy=0.8680833333333333Fold=1, Accuracy=0.8685Fold=2, Accuracy=0.8674166666666666Fold=3, Accuracy=0.8703333333333333Fold=4, Accuracy=0.8699166666666667

查看训练脚本时,您会发现还有一些内容是硬编码的,例如折叠数、训练文件和输出文件夹。

因此,我们可以创建一个包含所有这些信息的配置文件: config.py 。

TRAINING_FILE = "../input/mnist_train_folds.csv"
MODEL_OUTPUT = "../models/"

我们还对训练脚本进行了一些修改。训练文件现在使用配置文件。这样,更改数据或模型输出就更容易了。

import os
import config
import joblib
import pandas as pd
from sklearn import metrics
from sklearn import tree
def run(fold):# 使用config中的路径读取数据df = pd.read_csv(config.TRAINING_FILE)df_train = df[df.kfold != fold].reset_index(drop=True)df_valid = df[df.kfold == fold].reset_index(drop=True)x_train = df_train.drop("label", axis=1).valuesy_train = df_train.label.valuesx_valid = df_valid.drop("label", axis=1).valuesy_valid = df_valid.label.valuesclf = tree.DecisionTreeClassifier()clf.fit(x_train, y_train)preds = clf.predict(x_valid)accuracy = metrics.accuracy_score(y_valid, preds)print(f"Fold={fold}, Accuracy={accuracy}")joblib.dump(clf,os.path.join(config.MODEL_OUTPUT, f"dt_{fold}.bin") )
if __name__ == "__main__":# 运行每个折叠run(fold=0)run(fold=1)run(fold=2)run(fold=3)run(fold=4)

请注意,我并没有展示这个培训脚本与之前脚本的区别。请仔细阅读这两个脚本,自己找出不同之处。区别并不多。

与训练脚本相关的还有一点可以改进。正如你所看到的,我们为每个折叠多次调用运行函数。有时,在同一个脚本中运行多个折叠并不可取,因为内存消耗可能会不断增加,程序可能会崩溃。为了解决这个问题,我们可以向训练脚本传递参数。我喜欢使用 argparse 。

import argparse
if __name__ == "__main__":# 实例化参数环境parser = argparse.ArgumentParser()# fold参数parser.add_argument( "--fold", type=int)# 读取参数args = parser.parse_args()run(fold=args.fold)

现在,我们可以再次运行 python 脚本,但仅限于给定的折叠。

❯ python train.py --fold 0Fold=0, Accuracy=0.8656666666666667

仔细观察,我们的第 0 折得分与之前有些不同。这是因为模型中存在随机性。我们将在后面的章节中讨论如何处理随机性。

现在,如果你愿意,可以创建一个 shell 脚本,针对不同的折叠使用不同的命令,然后一起运行,如下图所示。

python train.py --fold 0
python train.py --fold 1
python train.py --fold 2
python train.py --fold 3
python train.py --fold 4

您可以通过以下命令运行它。

❯ sh run.sh
Fold=0, Accuracy=0.8675
Fold=1, Accuracy=0.8693333333333333
Fold=2, Accuracy=0.8683333333333333
Fold=3, Accuracy=0.8704166666666666
Fold=4, Accuracy=0.8685

我们现在已经取得了一些进展,但如果我们看一下我们的训练脚本,我们仍然受到一些东西的限制,例如模型。模型是硬编码在训练脚本中的,只有修改脚本才能改变它。因此,我们将创建一个新的 python 脚本,名为 model_dispatcher.py 。model_dispatcher.py ,顾名思义,将调度我们的模型到训练脚本中。

from sklearn import tree
models = {# 以gini系数度量的决策树"decision_tree_gini": tree.DecisionTreeClassifier(criterion="gini"),# 以entropy系数度量的决策树"decision_tree_entropy": tree.DecisionTreeClassifier(criterion="entropy"),
}

model_dispatcher.py从 scikit-learn 中导入了 tree ,并定义了一个字典,其中键是模型的名称,值是模型本身。在这里,我们定义了两种不同的决策树,一种使用基尼标准,另一种使用熵标准。要使用 py ,我们需要对训练脚本做一些修改。

import argparse
import os
import joblib
import pandas as pd
from sklearn import metrics
import config
import model_dispatcher
def run(fold, model):df = pd.read_csv(config.TRAINING_FILE)df_train = df[df.kfold != fold].reset_index(drop=True)df_valid = df[df.kfold == fold].reset_index(drop=True)x_train = df_train.drop("label", axis=1).valuesy_train = df_train.label.valuesx_valid = df_valid.drop("label", axis=1).valuesy_valid = df_valid.label.values# 根据model参数选择模型clf = model_dispatcher.models[model]clf.fit(x_train, y_train)preds = clf.predict(x_valid)accuracy = metrics.accuracy_score(y_valid, preds)print(f"Fold={fold}, Accuracy={accuracy}")joblib.dump( clf,os.path.join(config.MODEL_OUTPUT, f"dt_{fold}.bin"))if __name__ == "__main__":parser = argparse.ArgumentParser()# fold参数parser.add_argument("--fold", type=int)# model参数parser.add_argument("--model", type=str)args = parser.parse_args()run(fold=args.fold, model=args.model)

train.py有几处重大改动:

  • 导入 model_dispatcher
  • 为 ArgumentParser 添加 --model 参数
  • 为 run() 函数添加 model 参数
  • 使用调度程序获取指定名称的模型

现在,我们可以使用以下命令运行脚本:

❯ python train.py --fold 0 --model decision_tree_gini
Fold=0, Accuracy=0.8665833333333334

或执行以下命令

❯ python train.py --fold 0 --model decision_tree_entropy
Fold=0, Accuracy=0.8705833333333334

现在,如果要添加新模型,只需修改 model_dispatcher.py 。让我们尝试添加随机森林,看看准
确率会有什么变化。

from sklearn import ensemble
from sklearn import tree
models = {"decision_tree_gini": tree.DecisionTreeClassifier(criterion="gini"),"decision_tree_entropy": tree.DecisionTreeClassifier(criterion="entropy"),# 随机森林模型"rf": ensemble.RandomForestClassifier(),
}

让我们运行这段代码。

❯ python train.py --fold 0 --model rf
Fold=0, Accuracy=0.9670833333333333

一个简单的改动就能让分数有如此大的提升!现在,让我们使用 run.sh 脚本运行 5 个折叠!

python train.py --fold 0 --model rf
python train.py --fold 1 --model rf
python train.py --fold 2 --model rf
python train.py --fold 3 --model rf
python train.py --fold 4 --model rf

得分情况如下

❯ sh run.sh
Fold=0, Accuracy=0.9674166666666667
Fold=1, Accuracy=0.9698333333333333
Fold=2, Accuracy=0.96575
Fold=3, Accuracy=0.9684166666666667
Fold=4, Accuracy=0.9666666666666667

示如何为你正在做的或计划在不久的将来做的几乎所有机器学习项目编写一个基本框架。有许多不同的方法可以改进这个 MNIST 模型和这个框架,我们将在以后的章节中看到。

我使用了一些脚本,如 model_dispatcher.py 和 config.py ,并将它们导入到我的训练脚本中。请注意,我没有导入 * ,你也不应该导入。如果我导入了 * ,你就永远不会知道模型字典是从哪里来的。编写优秀、易懂的代码是一个人必须具备的基本素质,但许多数据科学家却忽视了这一点。如果你所做的项目能让其他人理解并使用,而无需咨询你的意见,那么你就节省了他们的时间和自己的时间,可以将这些时间投入到改进你的项目或开发新项目中去。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/216192.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字图像处理(实践篇)二 画出图像中目标的轮廓

目录 一 涉及的OpenCV函数 二 代码 三 效果图 一 涉及的OpenCV函数 contours, hierarchy cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]]) image:源图像。mode:轮廓的检索方式。cv2.RETR_EXTERNAL(只检测…

uni-app,nvue中text标签文本超出宽度不换行问题解决

复现:思路: 将text标签换为rich-text,并给rich-text增加换行的样式class类名解决:

Ubuntu中安装搜狗输入法教程(详细图文教程)

习惯了使用搜狗输入法,这里总结了Ubuntu系统下安装搜狗输入法的详细教程,每个步骤都很详细,耐心安装。 搜狗输入法是一款功能强大、使用方便的输入法,能够有效提升用户在Ubuntu系统中的输入体验。 目录 一、下载搜狗安装包1.1 搜…

STM32_7(ADC)

一、ADC ADC(Analog-Digital Converter)模拟-数字转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁12位逐次逼近型ADC,1us转换时间输入电压范围:0~3.3V,…

分享一个软件模拟USB,支持HID

文章目录 一、特性二、相对于替代解决方案的优势(1) 为什么不选择内置USB硬件的微控制器呢?(2) 与带 USB 硬件的微控制器相比的优势(3) 与单独的 USB 外设相比的优势(4) 与其他纯固件实现相比的优势 三、链接 一、特性 完全符合 USB 1.1 标准的低速设备&#xff0c…

【汉诺塔 —— (经典分治递归)】

汉诺塔 —— (经典分治递归) 一.汉诺塔介绍二.分治算法解决汉诺塔问题三.汉诺塔问题的代码实现四.主函数测试展示 一.汉诺塔介绍 汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一…

前端vue导出PPT,使用pptxgen.js

前言 公司新需求需要导出ppt给业务用,查阅资料后发现也挺简单的,记录一下。 如有不懂的可以留言!!! 1.安装包 npm install pptxgenjs --save2.引入包 在需要使用的文件中引入 import Pptxgenfrom "pptxgenjs&…

【计算机网络】(网络层)定长掩码和变长掩码

目录 1、IPV4地址的应用规划 2、例题分析 2.1、定长的子网掩码 2.2、变长的子网掩码 1、IPV4地址的应用规划 定长的子网掩码(FLSM): 使用同一个子网掩码划分子网,每个子网所分配的IP地址数量相同,造成IP地址的浪费…

小辰的智慧树(差分+前缀和)

登录—专业IT笔试面试备考平台_牛客网 1.考虑总长度之和不能超过m,2考虑限制每棵树高度不能低于ci,如果用二分最短输能截到的高度,还要另外去判断,是否每棵树mid都能严格大于ci ,这样容易超时,换个角度&…

DFS序和欧拉序的降维打击

1. DFS 序和时间戳 1.1 DFS 序 定义:树的每一个节点在深度优先遍历中进、出栈的时间序列。 如下树的 dfs 序就是[1,2,8,8,5,5,2,4,3,9,9,3,6,6,4,7,7,1]。 下图为生成DFS的过程。对于一棵树进行DFS序,除了进入当前节点时对此节点进行记录,…

Chem. Eng. J | 掌控基于ESIPT的AIE效应设计具有单组分白光发射的光学材料

今天为大家介绍一篇近期发表在Chemical Engineering Journal上的论文:Controlling ESIPT-based AIE effects for designing optical materials with single-component white-light emission。论文通讯作者为中南大学董界副教授和曾文彬教授,论文第一作者…

使用new Vue()的时候发生了什么?

前言 Vue.js是一个流行的JavaScript前端框架,用于构建单页面应用(SPA)和用户界面。当我们使用new Vue()来创建一个Vue实例时,Vue会执行一系列的初始化过程,将数据变成响应式,编译模板,挂载实例…