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

书籍名: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列不等于fold
	df_train = df[df.kfold != fold].reset_index(drop=True)
	# 选取df中kfold列等于fold
	df_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.py
	Fold=0, Accuracy=0.8680833333333333
	Fold=1, Accuracy=0.8685
	Fold=2, Accuracy=0.8674166666666666
	Fold=3, Accuracy=0.8703333333333333
	Fold=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).values
	y_train = df_train.label.values
	x_valid = df_valid.drop("label", axis=1).values
	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)
	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 0
	Fold=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).values
	y_train = df_train.label.values
	x_valid = df_valid.drop("label", axis=1).values
	y_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 ,并将它们导入到我的训练脚本中。请注意,我没有导入 * ,你也不应该导入。如果我导入了 * ,你就永远不会知道模型字典是从哪里来的。编写优秀、易懂的代码是一个人必须具备的基本素质,但许多数据科学家却忽视了这一点。如果你所做的项目能让其他人理解并使用,而无需咨询你的意见,那么你就节省了他们的时间和自己的时间,可以将这些时间投入到改进你的项目或开发新项目中去。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVA之异常详解

1. 异常的概念与体系结构 1.1 异常的概念 在Java中,将程序执行过程中发生的不正常行为称为异常 1. 算术异常 public class Test {public static void main(String[] args) {System.out.println(10/0);} } 因为 0 不能当被除数,所以报出了异常&#…

如何避免死锁

程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一波电子书籍资料,包含《Effective Java中文版 第2版》《深入JAVA虚拟机》,《重构改善既有代码设计》,《MySQL高性能-第3版》&…

【C++】IO流

文章目录 一、C语言的输入与输出二、流是什么?三、CIO流1. C标准IO流2. C文件IO流 四、stringstream简单介绍 一、C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是 scanf () 与 printf()。 scanf(): 从标准输入设备(键盘)读取数据,并将值…

xadmin后台在每一行记录增加一个复制链接按钮

xadmin后台在每一行记录增加一个复制链接按钮 1、效果 点击复制后,自动把url链接复制到粘贴板,按Ctrl+v即可显示复制内容。 2、实现代码 adminx.py # 用户管理 class UserWhiteListAdmin(object):search_fields = [name, mobile] # 检索字段list_display

Linux 基础-常用的命令和搭建 Java 部署环境

文章目录 目录相关查看目录中的内容查看目录当前的完整路径切换目录 文件相关创建文件查看文件内容写文件vim 基础 创建删除创建目录 移动和复制移动(剪切粘贴)复制(复制粘贴) 搭建 Java 部署环境1. 安装 jdk2. 安装 tomcat1). 我们在自己电脑上下好 tomcat2). 从官网下载的 .z…

spring本地事务与单/多线程

请直接看原文 原文链接:多线程与数据库事务以及数据库连接之间的关系 - 知乎 (zhihu.com) -------------------------------------------------------------------------------------------------------------------------------- 今天我们来梳理一下, 多线程、数…

HCIP-九、路由控制

九、路由控制 实验拓扑实验需求及解法1.企业生产网运行 OSPF,完成以下需求:2.数据中心运行 ISIS3.路由引入4.路由策略5.策略路由6.ISP 过滤私网路由 实验拓扑 实验需求及解法 1.企业生产网运行 OSPF,完成以下需求: 1.1 OSPF 进程…

JSP宾馆预定管理系统数据库设计过程ER图

**Hi**,今天给大家带来一款使用JSP和Servlet开发的宾馆预定管理系统的论文写作指导。需要使用本项目写文档的童鞋可以好好看看文末附项目的效果查看地址哦~ 一、项目功能 具体的功能看下面这张表,表里面只是截取了主要功能来说的。 员工角色管理员角色员…

CSS-长度单位篇

px:像素em:相对元素font-size的倍数rem:相对根字体大小,html标签就是根%:相对父元素计算 注意:CSS中设置长度,必须加单位,否则样式无效!

5.1每日一题(无穷级数敛散性的判断:莱布尼兹准则、p级数、绝对收敛、条件收敛、比较法/比较法的极限形式)

莱布尼兹准则&#xff1a;&#xff08;1&#xff09;单调递减&#xff1b;&#xff08;2&#xff09;极限 -> 0 绝对收敛&#xff1a;级数的绝对值收敛 条件收敛&#xff1a;级数的绝对值发散 p级数的次幂 <1 时发散 &#xff1b;>1时收敛

Vue框架学习笔记——事件修饰符

文章目录 前文提要事件修饰符prevent&#xff08;常用&#xff09;stop&#xff08;不常用&#xff09;事件冒泡stop使用方法三层嵌套下的stop三层嵌套看出的stop&#xff1a; once&#xff08;常用&#xff09;capture&#xff08;不常用&#xff09;self&#xff08;不常用&a…

vue开发中遇到的问题记录

文章目录 前言1、css 即时使用了scoped子组件依然会生效2、路由配置如果出现重复name&#xff0c;只会生效最后一个&#xff0c;且前端的路由无效3、组件之间事件传递回调需要先定义emits: []&#xff0c;不然会警告提示总结如有启发&#xff0c;可点赞收藏哟~ 前言 1、css 即…

共享模型之内存

JMM JMM&#xff1a;Java内存模型。定义了主存&#xff08;所有线程共享的数据&#xff09;、工作内存&#xff08;每个线程对应的私有数据&#xff09;的抽象概念。 JMM存在以下几个特征 原子性&#xff1a;保证指令不会受到线程上下文切换所影响。可见性&#xff1a;保证指…

【数据集】全网最全的常见已公开医学影像数据集

目录 一&#xff0c;极市医学数据集汇总 1.CT 医学图像 ​编辑 2.恶性与良性皮肤癌 3.白内障数据集 4.胸部 X 光图像&#xff08;肺炎&#xff09; 5.用于图像增强的内窥镜真实合成曝光过度和曝光不足帧 6.医学家 7.乳房组织病理学图像 8.皮肤癌 MNIST&#xff1a;HA…

elementPlus之home页面布局

可以根据自己喜欢的格式选择 现在 header 部分 Aside 部分 Main部分 加上背景色以及命名 <template><div class="common-layout"><el-container><el-header class="homeHeader"><div class="headerTitle">Dev…

【Flutter】设置顶部状态栏的显示、隐藏、半透明灰色显示

【Flutter】设置顶部状态栏的显示、隐藏、半透明灰色显示 设置方法&#xff1a; // 这种模式不现实状态栏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); // 这种模式显示状态栏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); // 修…

Yakit工具篇:WebFuzzer模块之热加载技术

简介 官方定义&#xff1a; 什么是热加载&#xff1f; 广义上来说&#xff0c;热加载是一种允许在不停止或重启应用程序的情况下&#xff0c;动态加载或更新特定组件或模块的功能。这种技术常用于开发过程中&#xff0c;提高开发效率和用户体验。 在Yakit 的Web Fuzzer中&…

C#调用ffmpeg从视频提取图片

微信公众号“CSharp编程大全”的文章《C#从视频提取图片&#xff1f;》介绍了基于Microsoft.DirectX.AudioVideoPlayback.Video类实现从视频提取图片的方式&#xff0c;本来是想学习并测试该类的用法&#xff0c;但实际测试过程中却没有测通。百度从视频提取图片&#xff0c;网…

Kotlin学习——kt里面的函数,高阶函数 函数式编程 扩展函数和属性

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…

如何使用Python在3dMax控制网格对象?

我们以一个在3dMax中使用Python脚本在网格对象对象上创建水波变形作为例子。 首先&#xff0c;在3dmax创建两个对象&#xff0c;一个“box”对象&#xff0c;将长宽方向的分段设置的多一些&#xff08;目的是为了后面的水波变形&#xff09;&#xff0c;一个“点”帮助对象&am…