首页
友情链接
点点滴滴
关于本站
秋码记录
一个游离于山间之上的Java爱好者 | A Java lover living in the mountains
累计撰写
163
篇文章
累计创建
356
个标签
累计创建
47
个分类
栏目
首页
友情链接
点点滴滴
关于本站
搜索
使用 golang 以及 Gin 框架,将上传的图片在不保存至本地的情况下添加水印,并上传至阿里云 OSS
正如标题所述,使用golang对上传图片添加水印,以及将图片上传到阿里云OSS,网上一搜索,便有你想要的结果了,可是,他们却先将上传图片添加水印后保存在本地,而后再将添加了水印的图片上传到阿里云OSS。 这无疑是暂时占用了你电脑的磁盘空间(这里说是暂时,因为你可以通过程序对上传到阿里云OSS成功的图片进行删除),即便是这样,它也是消耗了磁盘读写操作,虽然人类是察觉不到这么细微的变化。 然而,作为技术人员的我们(不介意我这么称呼自己吧!),使能够Review出这段程序的问题。很显然,本地图片是要通过程序处理,添加水印,而后最终储存到阿里云OSS中,而不是又要在本地多存了一张比原图多了些水印的图片。 图像处理库 既然我们的目的明确了,那么就卷起柚子加油干吧! 虽然,使用golang对上传图片添加水印,以及如何将图片上传到阿里云OSS中,是两个独立分开的。但是,这两步看似分而食之的程序,其实是可以合二为一的!(我想,正在浏览本文的你,也是这么想的!) 这是可行的方案,毕竟先前的秋码记录 就是这么做的(那是使用Java构建的那些年!当然现在的 秋码记录 改用 ```Hugo·``搭建了)。 既然,java能实现对上传图片添加水印,而不暂时保存在本地,立马即可上传到阿里云OSS中。想必,golang也是可以完成的! 然而,网上相关的资料有限,才能铸就本文的诞生! 首先,我是用golang的版本是1.19,虽然不是最新的,但却不妨碍我们继续对本文的讲解。 虽然,人类总是对新鲜事物充满好奇,从而萌生了猎奇心。但也只有在旧事物的烘衬下,人们才能对新事物寄以最大的希望!这就好比,老婆总是别人的好看(当然,别人的老婆也有没有自己老婆好看的),这才造就了黄脸婆这一全国男人在没有老婆在身旁统一叹息声! 你得在你电脑任一磁盘下,新建一空文件夹,随后打开黑窗口(Terminal),输入以下命令,说明是modules进行管理的(毕竟我使用的是golang 1.19): go mod init qiucode.cn/uploadImage 对于以上这行命令,就是初始化golang模块(module),在golang的世界是```万物皆可模块``(我说的如果不对,那么说出你的想法)。 初始化项目后,我们会发现文件夹下多了个go.mod文件(这个就是用来管理第三方依赖库的管理文件,不需要操作!),在该同级目录下新建main.go文件。 既然本文是探讨如何实现图片添加水印的,那么引入图像库那是必不可少的! go get github.com/fogleman/gg 本文不会对这个图像库进行深层次的讲解!毕竟本文的核心内容是介绍如何对图片添加水印,而不是避重就轻、本末倒置讲起了本该一笔带过的东西,却花了浓墨重彩去着重的描绘刻画它,到头来,却失了初心,乱了本文的主旨,实属不该。(实在不清楚的,可以去查看其文档) 很显然,将图片上传到阿里云OSS上,引入其SDK,那是必不可少的(关于这一点,应该不需要我多费口舌了吧) go get github.com/aliyun/aliyun-oss-go-sdk/oss 接下来的这个依赖库,并不是必须的(那就是可选的),毕竟,有它没有它,本文都可以实现! go get github.com/gin-gonic/gin 是啊!都说了,不引入它,本文也可以实现,那么我为什么还引入了呢?(关于这一点,欢迎你能在评论中留下你的只言片语,请不要吝啬你的文字!) 用代码实现标题的需求 前提准备工作就绪,我们该正式进入编码环节了。到了这里,正处于屏幕前的你,想必早就迫不及待了吧!毕竟,你就是与我有同样的需求,才会浏览本文的(当然也有那种,鼠标不小心点到了,但那种几率是很小的,我相信你不是属于那一类的) 首先,我们使用VS Code(你也可以使用其他你平时常用的IDE,不必非要使用与我一样的VS Code,然而,作为一款开源免费的IDE,你还有什么理由不去使用它呢?哦,差点忘记了,都说了,使用IDE是个人的自由,可我这么一说,倒有了让你使用VS Code之嫌。虽然,或许你比较喜欢使用收费软件,但你都是找的破解方法来破解软件,从而使用它们) 打开刚刚新建的main.go文件,开始逐步实现标题的需求。 package main import ( "bytes" "image" "image/png" // "image/jepg" //用于对 jpg 格式的图片进行处理 本文暂时不对 jpg 图片做处理 "github.com/gin-gonic/gin" //web 框架 "github.com/fogleman/gg" // 图像处理哭 "github.com/aliyun/aliyun-oss-go-sdk/oss" //阿里云OSS SDK ) 随后,我们在main函数中实现标题中的需求。
2024-03-30
[golang gin]
绘制特征曲线-ROC(Machine Learning 研习十七)
接收者操作特征曲线(ROC)是二元分类器的另一个常用工具。它与精确度/召回率曲线非常相似,但 ROC 曲线不是绘制精确度与召回率的关系曲线,而是绘制真阳性率(召回率的另一个名称)与假阳性率(FPR)的关系曲线。FPR(也称 “下降率”)是阴性实例被错误归类为阳性实例的比率。它等于 1 - 真阴性率 (TNR),即正确分类为阴性的阴性实例的比率。TNR 也称为特异性。因此,ROC 曲线是灵敏度(召回率)与 1 - 特异性的关系图 要绘制 ROC 曲线,首先要使用 roc_curve() 函数计算不同阈值的 TPR 和 FPR: from sklearn.metrics import roc_curve fpr, tpr, thresholds = roc_curve(y_train_5, y_scores) 然后可以使用 Matplotlib 绘制 FPR 与 TPR 的对比图。下面的代码可以绘制出 见下图 所示的图形。要找到与 90% 精度相对应的点,我们需要查找所需阈值的索引。由于在这种情况下阈值是按递减顺序排列的,因此我们在第一行使用 <= 而不是 >=: idx_for_threshold_at_90 = (thresholds <= threshold_for_90_precision).argmax() tpr_90, fpr_90 = tpr[idx_for_threshold_at_90], fpr[idx_for_threshold_at_90] plt.plot(fpr, tpr, linewidth=2, label="ROC curve") plt.plot([0, 1], [0, 1], 'k:', label="Random classifier's ROC curve") plt.plot([fpr_90], [tpr_90], "ko", label="Threshold for 90% precision") [.
2024-03-29
[Machine Learning 人工智能]
网站引入 Prism,使得代码高亮显示,并一键复制代码块
曾几何时,苦恼如何将本地写好的博文,更好的展示读者屏幕前?若只是简简单单的文章,其实还是很好的解决它的!可是,像我们这样写技术文章(有点牵强)的,在文章内容嵌入部分代码是在所难免的。 然而,由于没能将代码与文本区分开来,致使两者混在一起,分不出彼此。由此给读者带来了视觉上得不适,它并没有很好的像代码编辑器那样高亮。 下载 Prism 虽然市面上能让代码块高亮显示,远不止Prism这一款,而我又为什么选择这一款呢?这的确是个好问题,然而我只能回答您的是,它功能比较强大吧!(或许您还不能信服),这就好比是情人眼里出西施,您的老婆/老公或女朋友/男朋友长得不是那么美/那么帅(或许您在某一瞬间也是这么觉得),但是,您不还是选择了她/他吗?即便是,您和伴侣在逛街时,迎面走来一位身材高挑的美女/帅哥,想必您的伴侣是在您不经意间,偷瞄了一眼。 进入prism官网下载: https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript 随后,我们在项目中引入Prism.css样式文件。 <link href="themes/prism.css" rel="stylesheet" /> 以及Prism.js文件。 <script src="prism.js"></script> 当然咯,您的代码块是需要使用<pre>和<code class="language-*"标签。 <pre><code class="language-html"> <link href="themes/prism.css" rel="stylesheet" /> </code></pre> 添加 clipboard 复制代码按钮 若是有一点按钮就可以复制这段代码,想必应该是没有人会再去用鼠标去滑动选择代码,然后右键,选择复制选项,或者直接按住键盘上的Ctrl + C。 首先,想要在项目中添加clipboard功能,那么,就显得下载它,这是毋庸置疑的! 当然,我们还是到Prism官网下载它, 在项目中引入: <script src="plugins/clipboard.js"></script> Hugo-theme-kiwi 中引入 Prism 首先,我们在Hugo-theme-kiwi主题的head.html文件引入blackmac.css样式文件。 <link rel="stylesheet" href="{{ .Site.BaseURL }}css/blackmac.css"> blackmac.css文件内容如下: code[class*="language-"],pre[class*="language-"]{color:#f8f8f2;background:#313238;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:2;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;}pre[class*="language-"]{padding:.5em;margin:.5em 0;overflow:auto;}:not(pre)>code[class*="language-"],pre[class*="language-"]{background:#21252a}:not(pre)>code[class*="language-"]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#999;}.token.punctuation{color:#ccc;}.token.tag,.token.attr-name,.token.namespace,.token.deleted{color:#e2777a;}.token.function-name{color:#6196cc;}.token.boolean,.token.number,.token.function{color:#f08d49;}.token.property,.token.class-name,.token.constant,.token.symbol{color:#f8c555;}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin{color:#cc99cd;}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable{color:#7ec699;}.token.operator,.token.entity,.token.url{color:#67cdcc;}.token.important,.token.bold{font-weight:bold;}.token.italic{font-style:italic;}.token.entity{cursor:help;}.token.inserted{color:green;}pre.line-numbers{padding-bottom:.8em;padding-left:3.3em;counter-reset:linenumber}pre.line-numbers>code{white-space:inherit font-size:15px}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:3em;font-size:100%;left:-0.1em;width:3em;letter-spacing:-1px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.9em;text-align:right;background:#272c33}div.code-toolbar{font-size:100%;border-radius:4px;position:relative;box-shadow:0 0 20px 5px rgba(0,0,0,.4);padding-top:30px;background-color:#161616;margin:20px 0 20px 0}.code-toolbar:before{content:" ";position:absolute;-webkit-border-radius:50%;border-radius:50%;background:#fc625d;width:11px;height:11px;left:10px;top:10px;-webkit-box-shadow:20px 0 #fdbc40,40px 0 #35cd4b;box-shadow:20px 0 #fdbc40,40px 0 #35cd4b;z-index:2}div.code-toolbar>.toolbar{padding-right:.4em;position:absolute;top:.09em;right:.2em;width:100%;text-align:center;}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar>.toolbar .
2024-03-23
[前端]
精确率(召回率)的权衡(Machine Learning 研习十六)
精确率(召回率)的权衡 为了理解这种权衡,让我们看看 SGDClassifier 如何做出分类决策。 对于每个实例,它根据决策函数计算分数。 如果该分数大于阈值,则将该实例分配给正类; 否则它会将其分配给负类。 图 3-4 显示了从左侧最低分数到右侧最高分数的几个数字。 假设决策阈值位于中心箭头(两个 5 之间):您会在该阈值右侧发现 4 个真阳性(实际为 5),以及 1 个假阳性(实际上为 6)。 因此,使用该阈值,精度为 80%(5 分之 4)。 但在 6 个实际的 5 中,分类器仅检测到 4 个,因此召回率为 67%(6 中的 4)。 如果提高阈值(将其移动到右侧的箭头),假阳性(6)会变成真阴性,从而提高精度(在本例中高达 100%),但一个真阳性会变成假阴性 ,将召回率降低至 50%。 相反,降低阈值会增加召回率并降低精确度。 Scikit-Learn 不允许您直接设置阈值,但它允许您访问它用于进行预测的决策分数。 您可以调用其decision_function()方法,而不是调用分类器的predict()方法,该方法返回每个实例的分数,然后使用您想要根据这些分数进行预测的任何阈值: SGDClassifier 使用等于 0 的阈值,因此前面的代码返回与 Predict() 方法相同的结果(即 True)。 让我们提高门槛: 这证实了提高阈值会降低召回率。 该图像实际上代表的是 5,当阈值为 0 时分类器会检测到它,但当阈值增加到 3,000 时分类器会错过它。 y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3, method="decision_function") 有了这些分数,使用 precision_recall_curve() 函数计算所有可能阈值的精度和召回率(该函数添加最后精度 0 和最后召回率 1,对应于无限阈值): from sklearn.
2024-03-21
[Machine Learning 人工智能]
对模型性能进行评估(Machine Learning 研习十五)
在上一篇我们已然训练了一个用于对数字图像识别的模型,但我们目前还不知道该模型在识别数字图像效率如何?所以,本文将对该模型进行评估。 使用交叉验证衡量准确性 评估模型的一个好方法是使用交叉验证,让我们使用cross_val_score()函数来评估我们的 SGDClassifier 模型,使用三折的 k 折交叉验证。k-fold 交叉验证意味着将训练集分成 k 个折叠(在本例中是三个),然后训练模型 k 次,每次取出一个不同的折叠进行评估: 当您看到这组数字,是不是感到很兴奋?毕竟所有交叉验证折叠的准确率(预测准确率)均超过了 95%。然而,在您兴奋于这组数字前,还是让我们来看看一个假分类器,它只是将每张图片归入最常见的类别,在本例中就是负类别(即非 5): from sklearn.dummy import DummyClassifier dummy_clf = DummyClassifier() dummy_clf.fit(X_train, y_train_5) print(any(dummy_clf.predict(X_train))) # prints False: no 5s detected 您能猜出这个模型的准确度吗?让我们一探究竟: 没错,它的准确率超过 90%!这只是因为只有大约 10% 的图片是 5,所以如果你总是猜测图片不是 5,你就会有大约 90% 的时间是正确的。比诺斯特拉达穆斯还准。 这说明了为什么准确率通常不是分类器的首选性能指标,尤其是在处理偏斜 数据集时(即某些类别的出现频率远高于其他类别)。评估分类器性能的更好方法是查看混淆矩阵(CM)。 实施交叉验证 与 Scikit-Learn 现成提供的功能相比,您有时需要对交叉验证过程进行更多控制。在这种情况下,你可以自己实现交叉验证。下面的代码与 Scikit-Learn 的 cross_val_score() 函数做了大致相同的事情,并会打印出相同的结果: from sklearn.model_selection import StratifiedKFold from sklearn.base import clone skfolds = StratifiedKFold(n_splits=3) # add shuffle=True if the dataset is # not already shuffled for train_index, test_index in skfolds.
2024-03-15
[Machine Learning 人工智能]
图像识别之入门案例之数字识别(Machine Learning 研习十四)
在前面的文章中,我们曾提到最为常见的监督学习任务是回归(预测价值)和分类(预测类别)。我们使用线性回归、决策树和随机森林等各种算法探讨了回归任务,即预测房屋价值。现在,我们将把注意力转向分类系统。 MNIST数据集 我们将使用 MNIST 数据集,这是一组由人类手写的 70,000 张小数字图像。每张图片都标注了所代表的数字。人们对这个数据集的研究非常深入,以至于它经常被称为机器学习的 “hello world”:每当人们提出一种新的分类算法时,他们都会好奇地想看看这种算法在 MNIST 上的表现如何,而且任何学习机器学习的人迟早都会用到这个数据集。 Scikit-Learn 提供了许多下载流行数据集的辅助函数。MNIST 就是其中之一。以下代码从 OpenML.org 获取 MNIST 数据集: from sklearn.datasets import fetch_openml mnist = fetch_openml('mnist_784', as_frame=False) sklearn.datasets 包主要包含三种类型的函数:fetch_* 函数(如 fetch_openml())用于下载现实生活中的数据集;load_* 函数用于加载 Scikit-Learn捆绑的小型玩具数据集(因此无需通过互联网下载);make_* 函数用于生成假数据集,对测试非常有用。生成的数据集通常以 (X, y) 元组的形式返回,其中包含输入数据和目标数据,两者都是 NumPy 数组。其他数据集以 sklearn.utils.Bunch 对象的形式返回,这是一个字典,其条目也可以作为属性访问。它们通常包含以下条目: “DESCR” 数据集描述 “data” 输入数据,通常为Numpy二维数组 “target” 标签,通常为Numpy一维数组 fetch_openml() 函数有点不寻常,因为默认情况下,它以 Pandas DataFrame 的形式返回输入,以 Pandas Series 的形式返回标签(除非数据集很稀疏)。但 MNIST 数据集包含图像,而 DataFrame 并不适合图像,因此最好设置 as_frame=False,以 NumPy 数组的形式获取数据。让我们来看看这些数组: 共有 70,000 幅图像,每幅图像有 784 个特征。这是因为每幅图像都是 28 × 28 像素,每个特征只代表一个像素的强度,从 0(白色)到 255(黑色)。让我们来看看数据集中的一个数字(图 3-1)。我们需要做的就是抓取一个实例的特征向量,将其重塑为 28 × 28 数组,然后使用 Matplotlib 的 imshow() 函数显示出来。我们使用 cmap="binary" 来获取灰度颜色图,其中 0 代表白色,255 代表黑色:
2024-03-15
[Machine Learning 人工智能]
微调模型——续(Machine Learning 研习之十三)
集成方法 微调系统的另一种方法是尝试组合性能最佳的模型。 群体(或“整体”)通常会比最好的单个模型表现得更好,就像随机森林比它们所依赖的单个决策树表现更好一样,特别是当各个模型犯下不同类型的错误时。 例如,您可以训练和微调 k 最近邻模型,然后创建一个仅预测随机森林预测和该模型预测的平均值的集成模型。 分析最佳模型及其错误 通过检查最佳模型,您通常会获得对问题的深入见解。 例如,RandomForestRegressor可以指示每个属性对于做出准确预测的相对重要性: 让我们按降序对这些重要性分数进行排序,并将它们显示在相应的属性名称旁边: 有了这些信息,您可能想尝试删除一些不太有用的功能(例如,显然只有一个ocean_proximity类别真正有用,因此您可以尝试删除其他功能)。 您还应该查看系统所犯的具体错误,然后尝试了解为什么会犯这些错误,以及如何解决问题:添加额外的功能或删除无信息的功能,清理异常值等。 现在也是一个好时机,可以确保您的模型不仅平均运行良好,而且适用于所有类别的地区,无论是农村还是城市、富裕还是贫穷、北部还是南部、少数民族还是非少数民族等。 每个类别的验证集需要一些工作,但这很重要:如果您的模型在整个地区类别上表现不佳,那么在问题解决之前可能不应该部署它,或者至少不应该使用它 对该类别进行预测,因为它可能弊大于利。 在测试集上评估您的系统 对模型进行一段时间的调整后,您最终会得到一个性能足够好的系统。 您已准备好在测试集上评估最终模型。 这个过程没有什么特别的; 只需从测试集中获取预测变量和标签并运行Final_model来转换数据并进行预测,然后评估这些预测: X_test = strat_test_set.drop("median_house_value", axis=1) y_test = strat_test_set["median_house_value"].copy() final_predictions = final_model.predict(X_test) final_rmse = mean_squared_error(y_test, final_predictions, squared=False) print(final_rmse) # prints 41424.40026462184 在某些情况下,这样的泛化误差点估计不足以说服您启动:如果它只比当前生产的模型好 0.1% 怎么办? 您可能想了解这个估计的精确度。 为此,您可以使用 scipy.stats.t.interval() 计算泛化误差的 95% 置信区间。 您会得到从 39,275 到 43,467 的相当大的区间,而您之前的点估计值 41,424 大致位于中间: 如果您进行了大量的超参数调整,性能通常会比使用交叉验证测量的性能稍差。 这是因为您的系统最终经过微调以在验证数据上表现良好,但在未知数据集上可能表现不佳。 本示例中的情况并非如此,因为测试 RMSE低于验证 RMSE,但当发生这种情况时,您必须抵制调整超参数以使数字在测试集上看起来不错的诱惑; 这些改进不太可能推广到新数据。 现在是项目预启动阶段:您需要展示您的解决方案(突出显示您所学到的内容、有效的内容和无效的内容、做出的假设以及系统的局限性),记录所有内容,并使用以下内容创建精美的演示文稿: 清晰的可视化和易于记忆的陈述(例如,“收入中位数是房价的第一预测指标”)。 在这个加州住房示例中,系统的最终性能并不比专家的价格估计好多少,专家的价格估计通常会下降 30%,但启动它可能仍然是一个好主意,特别是如果这样可以释放更多资金 给专家一些时间,以便他们可以从事更有趣、更有成效的任务。 启动、监控和维护您的系统 您现在需要准备好用于生产的解决方案(例如,完善代码、编写文档和测试等)。 然后您可以将模型部署到生产环境。 最基本的方法就是保存您训练的最佳模型,将文件传输到您的生产环境并加载它。 要保存模型,您可以使用 joblib 库,如下所示:
2024-03-09
[Machine Learning 人工智能]
微调模型(Machine Learning 研习之十二)
现在正处于百模乱战的时期,对于模型微调,想必您是有所了解了,毕竟国外的大语言模型一开源,国内便纷纷基于该模型进行微调,从而开始宣称领先于某某、超越了谁。可到头来,却让人发现他们套壳了国外大语言模型对外开放的API。 好了,我们不说国内各种大模型宣称超过了谁,毕竟,嘴巴长在别人脸上,我们管不了,也管不着,吹牛终将是会露馅的! 当我们需要对开源大模型进行微调时,看看有几种方法可以做到这一点的! 网格搜索 手动调整超参数,直到找到超参数值的完美组合。 这将是一项非常乏味的工作,而且您可能没有时间去探索多种组合。 相反,您可以使用 Scikit-Learn 的 GridSearchCV 类来搜索您。 您需要做的就是告诉它您希望它试验哪些超参数以及要尝试哪些值,它将使用交叉验证来评估超参数值的所有可能组合。 例如,以下代码搜索 RandomForestRegressor 的最佳超参数值组合: from sklearn.model_selection import GridSearchCV full_pipeline = Pipeline([ ("preprocessing", preprocessing), ("random_forest", RandomForestRegressor(random_state=42)), ]) param_grid = [{'preprocessing__geo__n_clusters': [5, 8, 10], 'random_forest__max_features': [4, 6, 8]}, {'preprocessing__geo__n_clusters': [10, 15], 'random_forest__max_features': [6, 8, 10]}, ] grid_search = GridSearchCV(full_pipeline, param_grid, cv=3, scoring='neg_root_mean_squared_error') grid_search.fit(housing, housing_labels) 请注意,您可以引用管道中任何估计器的任何超参数,即使该估计器嵌套在多个管道和列转换器的深处。 例如,当 Scikit-Learn 看到“preprocessing__geo__n_clusters”时,它会在双下划线处分割该字符串,然后在管道中查找名为“preprocessing”的估计器并找到预处理 ColumnTransformer。 接下来,它在此 ColumnTransformer 中查找名为“geo”的转换器,并找到我们在纬度和经度属性上使用的 ClusterSimilarity 转换器。 然后它找到该变压器的n_clusters超参数。 同样,random_forest__max_features指的是名为“random_forest”的估计器的max_features超参数,这当然是RandomForest模型。 这个param_grid中有两个字典,因此GridSearchCV将首先评估第一个字典中指定的n_clusters和max_features超参数值的所有3×3=9个组合,然后它将尝试第一个字典中指定的所有2×3=6个超参数值组合 第二个字典。 因此,网格搜索总共将探索 9 + 6 = 15 种超参数值组合,并且每个组合都会对管道进行 3 次训练,因为我们使用的是 3 折交叉验证。 这意味着总共将有 15 × 3 = 45 轮训练! 这可能需要一段时间,但是完成后您可以获得如下参数的最佳组合:
2024-03-09
[Machine Learning 人工智能]
解决 github.com port 443: Timed out 的问题
国内访问github.com总是那么不竟如人意,时而无法加载网页,时而等我们抽完了一根烟后,它还处于转圈的状态。 虽然国内有gitee.com等诸多的代码托管平台,但却鲜有国人愿意去呢?其中的缘由,想必也不用我多说,大伙也都心知肚明了吧! 即便github.com在国内访问慢,或是加载不出来,我们也宁愿等它慢慢地加载出来,却不愿将代码托管于境内的平台。 github.com 托管了 qiucode.cn 站点 由于将 秋码记录 托管于 github.com上后,写些文章就得push上去,然而当我push上去时,却十有八九都会出现 github.com port 443: Timed out的错误,代码显然是无法push上去的了! 难道在国内,现在push或是pull github.com,都是要靠运气吗?偶尔可以,大多数都是报错。 可是,“运气”总不能实时来关顾我们,要是那样的话,我早去买彩票了,虽然有运气,买了彩票,它也不一定中奖,毕竟古话早就有言:朝里有人好当官。 然而,有没有一劳永逸的解决之道呢?答案那是肯定有的,要不然,也就不会有这么一篇文章了,您也就不会花费您宝贵的时间来浏览本文,寻求与我遇到同样问题的解决方案了。 当我们想要clone github.com上的一个项目时,出现以下错误,那都是家常便饭了。 从报错信息来看,很显然这是https请求超时,这是毋庸置疑的,毕竟我们访问github.com都是是好是坏的!您在terminal端不还是一样的请求超时嘛! 解决国内 push/pull github.com 项目出现 Timed out 的问题 毕竟,秋码记录 是托管于 github.com上,总不可能写了一篇文章,想要push到 github.com,这次出现Timed out的错误,就不push,而是等到下次再写文章时,再push,这显然不是我要的,毕竟,技术文章(在这里,我也就王婆卖瓜,自卖自夸咯)是有时效性的!说是这么说,但并不妨碍的。 能出现Timed out的问题,我们第一想到便是网络问题(有些事我们自己心里清楚就好了),其次才是本地git配置问题。 那么,我们暂且略过网络问题这一客观事实不谈,来说说本地git的配置是哪里出现问题,而导致了出现Timed out的问题呢? 我们还是回到 terminal,输入以下命令测试ssh是否成功? ssh -T git@github.com 如果,您也出现了上图的结果,那显然是配置的问题了。 我们再次测试下port 443是否也出现超时的问题? ssh -T -p 443 git@ssh.github.com 可以看出,端口 443 请求是没问题,那么,为什么clone项目时,却报出了port 443请求超时的错误呢? 我们大致从上面的ssh测试报错便可以得出结论了,那便是ssh连接超时了。 而要想解决ssh请求超时的问题,那就要从配置着手了,还是一样的在terminal输入以下命令。 vim ~/.ssh/config 而后在进入编辑状态,填写以下内容 # Add section below to it Host github.com Hostname ssh.
2024-01-27
[github]
选择和训练模型(Machine Learning 研习之十一)
当您看到本文标题时,不禁感叹,总算是到了训练模型这一节了。 是啊,在之前的文章中,我们对数据进行了探索,以及对一个训练集和一个测试集进行了采样,也编写了一个预处理管道来自动清理,准备您的数据用于机器学习算法,然而现在,我们可以选择并训练模型了。 训练集的训练与评估 我们从一个最基本的线性回归模型开始: from sklearn.linear_model import LinearRegression lin_reg = make_pipeline(preprocessing, LinearRegression()) lin_reg.fit(housing, housing_labels) 很好,至此,我们现在算是有了一个有效的线性回归模型,可以在训练集上试用它,查看前五个预测,并将它们与标签进行比较:: 第一个预测偏差很大(超过200,000美元!),而其他预测则更好,两个预测偏差约25%,还有两个预测 偏差不到10%。请记住,您选择使用RMSE作为性能测度,因此您希望使用Scikit-Learn的mean_squared_error()函数在整个训练集上测量该回归模型的RMSE,并将平方参数设置为False。 这总比没有好,但显然不是一个很好的分数,大多数地区的房屋价值中位数在120,000美元和26.5万美元之间,所以一个典型的68628美元的预测误差真的不是很令人满意。这是一个模型拟合训练数据不足的示例。当这种情况发生时,可能意味着这些特征没有提供足够的信息来做出好的预测,或者模型不够强大。 正如我们在上一章中看到的,修复欠拟合的主要方法是选择一个更强大的模型,为训练算法提供更好的特征,或者减少对模型的约束。这个模型没有正规化,这就排除了最后一个选项。您可以尝试添加更多功能,但首先您要尝试更复杂的模型,看看它是如何工作的。 您决定尝试DecisionTreeRegressor,因为这是一个相当强大的模型,能够在数据中找到复杂的非线性关系(后续篇章将更详细地介绍决策树): from sklearn.tree import DecisionTreeRegressor tree_reg = make_pipeline(preprocessing, DecisionTreeRegressor(random_state=42)) tree_reg.fit(housing, housing_labels) 现在模型已训练完毕,您可以在训练集中对其进行评估: 等等,难道这个模型真的很完美吗?当然咯,更有可能的是模型严重地过度拟合了数据。您怎么能确定正如你前面看到的,在您准备好启动一个您有信心的模型之前,您不想碰测试集,所以您需要使用一部分训练集进行训练,另一部分用于模型验证。 使用交叉验证进行更好的评估 评估决策树模型的一种方法是使用train_test_split()函数将训练集拆分为较小的训练集和验证集,然后针对较小的训练集训练您的模型,并针对验证集对其进行评估。这是一点努力,但没有太难,它会工作得相当不错。 一个很好的替代方法是使用Scikit-Learn的k_-fold交叉验证特性。下面的代码随机地将训练集分成10个不重叠的子集,称为fold,然后训练和评估决策树模型10次,每次选择不同的fold进行评估,并使用其他9个fold进行训练。结果是一个包含10个评价分数的数组: from sklearn.model_selection import cross_val_score tree_rmses = -cross_val_score(tree_reg, housing, housing_labels, scoring="neg_root_mean_squared_error", cv=10) ```Scikit-Learn```的交叉验证功能期望的是效用函数(越大越好)而不是成本函数(越低越好),所以评分函数实际上是RMSE的反面。它是一个负值,所以您需要切换输出的符号来获得RMSE分数。 让我们来看看结果吧: 现在决策树看起来不像以前那么好了。事实上,它的表现几乎和线性回归模型一样差!请注意,交叉验证不仅允许您获得模型性能的估计值,还允许您测量该估计值的精确度(即其标准差)。决策树的均方根误差约为66,868,标准差约为2,061。如果只使用一个验证集,则不会有此信息。但是交叉验证是以多次训练模型为代价的,所以它并不总是可行的。 如果您为线性回归模型计算相同的度量,您将发现平均RMSE为69,858,标准差为4,182。因此,决策树模型的性能似乎比线性模型稍微好一点,但由于严重的过拟合,差异很小。我们知道存在过拟合 问题,因为训练误差很低(实际上为零),而验证误差很高。 现在让我们尝试最后一个模型:随机森林调节器,随机森林的工作原理是在特征的随机子集上训练许多决策树,然后平均出它们的预测值。这样的模型组成的许多其他模型被称为合奏:他们能够提高性能基础模型(在本例中为决策树)。代码与前面的代码大同小异: from sklearn.ensemble import RandomForestRegressor forest_reg = make_pipeline(preprocessing, RandomForestRegressor(random_state=42)) forest_rmses = -cross_val_score(forest_reg, housing, housing_labels, scoring="neg_root_mean_squared_error", cv=10) 随机森林真的看起来非常有前途的任务!但是,如果您训练一个RandomForest并测量训练集上的RMSE,您将发现大约17,474:这要低得多,这意味着仍然存在大量的过度拟合。可能的解决方案是 简化模型,约束它(即,规则化它),或得到更多的训练数据。但是,在深入研究随机森林之前,您应该尝试来自各种类别机器学习算法的许多其他模型(例如,具有不同内核的多个支持向量机,可能还有一个神经网络),而无需花费太多时间调整超参数。目标是列出几个(两到五个)有前途的模型。
2024-01-14
[Machine Learning 人工智能]
回望这风雨飘摇的一年过后,我们终将要整束行囊继续前行
2023 这一年 时间倏忽而过,纵有再多的不甘,2023 这一年的日历终要翻过去了。这一年,或许还对很多事保持着一种执念,然而,随着 2023 年如东逝水一去不复返,也该放下那份执着,让我们挥手告别那处于风雨飘摇的 2023 年,毕竟,未来还很长,我们还得背上行囊踏上那远方的路,否则,赶不上停靠在路边的二路汽车了都! 2023 年年初为这一年预先设定的规划,实现了吗?然而,回答我们自己,是那无声的摇头。年初预定的规划,大抵也只有到了年末,我们对这一年复盘时,方觉得年初列出的计划清单,还是有那么多没有完成,更有甚者,清单上一项都没能实现,或许,此刻,我们会对自己发出一声苦笑,长吁责问自己,“一年的时间,竟然空不出一点时间来完成那年初既定的规划!” 无论是长吁短叹,还是责怪自己,我们总得为未来、新的一年起一份未来规划列表,顺带 2023 年还未完成的计划。 风雨过后,总能遇见太阳,只是自然界的现象,当然,也有例外,太阳有时让那厚实的云朵遮蔽了,日光便无法照耀大地,那阴郁之气却布满了上空,使这座城市处于压抑的一天,但我们相信,云朵总是会散开的,迟来的阳光,也会照射这片土地,用那光芒的温度去蒸发昨日的阴郁之气。 或许,用【风雨飘摇】这个成语来形容 2023 这一年,总觉得还不是那么恰当,因为 2023 这一年,并不像【风雨飘摇】这个词轻描淡写、一词带过,这四个字并不足以恰如其分地述说 2023 这一年。 这一年,承载着太多人的不甘;这一年,也让大部分撤离了那份职业;这一年,也让很大一部分人彻夜逃离了大城市,终将回到了可以安放灵魂的故乡。 然而,在 2023 这一年所积攒下来的诸多不甘、不忿、怨愤等阴郁之气,我们希望能借未来之光芒来吹散、蒸发那股消极、惨淡、压抑之气,在我们寄托于未来之光的时刻,我们也必须时刻充实自己,也只有这样,未来之光方能光顾到我们自己。 2023 年的既定计划 说来忏愧,2023 年年初既定要完成的计划,用这一年的时间,本是完成那份计划清单,绰绰有余,然而,一年到头了,回首这一年,却发觉,计划清单上竟然还有那么多未能实现的。或许,我们会长叹一声,“时间都去哪儿了?” 时间并没有去哪里游玩,而是一直傍我们左右,只是我们生活节奏快了,顺带也把时间扯上了。那一声,“时间都去哪儿了?”的感慨,是没来由的长吁短叹! 2023 年既定的计划: 编写一套具有 秋码记录 风格的 Wordpress主题 编写一套具有 秋码记录 风格的Typecho主题 更新基于Vue.js 2.X的开源 UI组件库 qiucode-ui 组件库 编写一套基于 React的开源UI组件库 让 秋码记录 全站使用自己开源的UI组件库 然而,到了 2023 年年末,回望计划清单时,发觉虽但没能全部完成,却在意料之外增添一项计划,实属难料的惊喜: 开源了一套由 Hugo驱动的 hugo-theme-kiwi主题 一套由 Hugo 驱动的博客主题 hugo-theme-kiwi 开源啦 实践多个Web3项目 研习人工智能领域 2023 年所欠下的计划,我们也只能将它们寄托于新的一年,希冀未来能够逐一地实现它们,以不负昨日之约。 我们将 2023 年所搁浅的计划,整理好,装进背囊,踏上远方之路,让未来之光吹散因在 2023 年所沾满了满身泄气、不甘、愤懑地压抑之气。 展望未来 昨日之事,已成定局,断然不可挽回,该是放下那份执念,去迎接明日的阳光。
2023-12-30
[生活情感]
机器学习中的 Transformation Pipelines(Machine Learning 研习之十)
Transformation Pipelines 有许多数据转换步骤需要以正确的顺序执行。幸运的是,Scikit-Learn提供了Pipeline类来帮助处理这样的转换序列。下面是一个用于数值属性的小管道,它首先对输入特性进行归并,然后对输入特性进行缩放: from sklearn.pipeline import Pipeline num_pipeline = Pipeline([ ("impute", SimpleImputer(strategy="median")), ("standardize", StandardScaler()), ]) Pipeline构造函数采用名称/估算器对(2元组)的列表,定义了一系列步骤。名称可以是您喜欢的任何名称,只要它们是唯一的,并且不包含双下划线(__)。以后我们讨论超参数调优时,它们会很有用。估计器必须都是转换器(即,它们必须有一个fit_transform()方法),除了最后一个,它可以是任何东西:转换器、预测器或任何其他类型的估计器。 如果你不想命名transformers你可以使用 make_pipeline() 函数; 它将transformers作为位置参数,并使用transformers类的名称(小写且不带下划线)创建管道(例如,“simpleimputer”): from sklearn.pipeline import make_pipeline num_pipeline = make_pipeline(SimpleImputer(strategy="median"), StandardScaler()) 如果多个transformers具有相同的名称,则会在其名称后附加索引(例如“foo-1”、“foo-2”等)。 当您调用管道的 fit() 方法时,它会在所有transformers上顺序调用 fit_transform(),将每个调用的输出作为参数传递给下一个调用,直到到达最终估计器,为此它只调用 fit() 方法。 该管道公开与最终估计器相同的方法。 在此示例中,最后一个估计器是 StandardScaler,它是一个transformers,因此管道也充当transformers。 如果您调用管道的transform()方法,它将按顺序将所有转换应用于数据。 如果最后一个估计器是预测器而不是变换器,那么管道将具有 Predict() 方法而不是 Transform() 方法。 调用它会按顺序将所有转换应用于数据并将结果传递给预测器的 Predict()方法 让我们调用管道的 fit_transform() 方法并查看输出的前两行,四舍五入到小数点后两位: 如前所述,如果要恢复一个漂亮的DataFrame,可以使用管道的get_feature_names_ out()方法: df_housing_num_prepared = pd.DataFrame( housing_num_prepared, columns=num_pipeline.get_feature_names_out(), index=housing_num.index) 管道支持索引;例如,管道[1]返回管道中的第二个估计值,管道[:-1]返回一个包含除最后一个估计值以外的所有估计值的管道对象。您还可以通过steps属性(它是名称/估算器对的列表)或named_steps字典属性(它将名称映射到估算器)访问估算器。例如,num_line[“ simpleimputer”]返回名为“simpleimputer”的估计器。 到目前为止,我们已经分别处理了分类列和数值列。如果有一个能够处理所有列的转换器,将适当的转换应用到每一列,那会更方便。为此,您可以使用olumnTransformer。例如,下面的ColumnTransformer将把num_pipeline(我们刚刚定义的那个)应用于数字属性,把cat_pipeline应用于类别属性: from sklearn.compose import ColumnTransformer num_attribs = ["longitude", "latitude", "housing_median_age", "total_rooms", "total_bedrooms", "population", "households", "median_income"] cat_attribs = ["ocean_proximity"] cat_pipeline = make_pipeline( SimpleImputer(strategy="most_frequent"), OneHotEncoder(handle_unknown="ignore")) preprocessing = ColumnTransformer([ ("num", num_pipeline, num_attribs), ("cat", cat_pipeline, cat_attribs), ]) 首先导入ColumnTransformer类,然后定义数字和分类列名的列表,并为分类属性构造一个简单的管道。最后,我们构造了一个列变换器。它的构造函数需要一个三元组(3-tuple)列表,每个三元组包含一个名称(必须是唯一的且不包含双下划线)、一个转换器和一个应该应用转换器的列的名称(或索引)列表。
2023-12-11
[Machine Learning 人工智能]
特征缩放和转换以及自定义Transformers(Machine Learning 研习之九)
特征缩放和转换 您需要应用于数据的最重要的转换之一是功能扩展。除了少数例外,机器学习算法在输入数值属性具有非常不同的尺度时表现不佳。住房数据就是这种情况:房间总数约为6至39320间,而收入中位数仅为0至15间。如果没有任何缩放,大多数模型将倾向于忽略收入中位数,而更多地关注房间数。 有两种常见的方法使所有属性具有相同的尺度:最小-最大尺度和标准化。 与所有估计器一样,重要的是仅将标量拟合到训练数据:永远不要对训练集以外的任何对象使用fit()或fit_transform()。一旦你有了一个训练好的定标器,你就可以用它来变换()任何其他的集合,包括验证集、测试集和新的数据。请注意,虽然培训集值将始终缩放到指定的范围,但如果新的数据包含异常值,则这些值最终可能会缩放到该范围之外。如果要避免这种情况,只需将剪辑超参数设置为True即可。 最小-最大缩放(许多人称之为标准化)是最简单的:对于每个属性,值被移位和重新缩放,以便它们最终的范围从0到1。这是通过减去最小值并除以最小值和最大值之间的差来实现的。Scikit-Learn为此提供了一个名为MinMaxScaler的转换器。它有一个feature_range超参数,如果出于某种原因,不希望0-1(例如,神经网络在零均值输入下工作得最好,所以最好在-1到1的范围内工作)。是相当好用的: from sklearn.preprocessing import MinMaxScaler min_max_scaler = MinMaxScaler(feature_range=(-1, 1)) housing_num_min_max_scaled = min_max_scaler.fit_transform(housing_num) 标准化是不同的:首先它减去平均值(所以标准化值有一个零均值),然后它除以标准差(所以标准-化值的标准差等于1)。不像最小最大缩放,标准化化不会将值限制在特定的范围内。然而,标准化受到离群值的影响要小得多。例如,假设一个地区的收入中位数等于100(误打误撞),而不是通常的0-15。将最小最大值缩放到0-1范围会将这个离群值映射到1并将所有其他值压缩到0-0.15,而标准化不会受到太大影响。Scikit-Learn提供了一个名为StandardScaler的转换器用于标准化: from sklearn.preprocessing import StandardScaler std_scaler = StandardScaler() housing_num_std_scaled = std_scaler.fit_transform(housing_num) 如果你想缩放一个稀疏矩阵而不首先将其转换为稠密矩阵,你可以使用一个标准缩放器,它的with_mean超参数设置为False它只会除以标准差,而不会减去均值(因为这会破坏稀疏性 当特征的分布具有重尾时(即,当远离平均值的值不是指数罕见时),最小-最大缩放和标准化都会将大多数值压缩到一个小范围内。 机器学习模型通常根本不喜欢这种情况,因此,在缩放特征之前,您应该首先对其进行变换以缩小重尾,并且如果可能的话,使分布大致对称。 例如,对于右侧有重尾部的正特征,执行此操作的常见方法是用其平方根替换特征(或将特征提高到 0 到 1 之间的幂)。 如果该特征具有非常长且重的尾部,例如幂律分布,则用其对数替换该特征可能会有所帮助。 例如,人口特征大致遵循幂律:拥有 10,000 名居民的地区的出现频率仅比拥有 1,000 名居民的地区低 10 倍,而不是呈指数级下降。 下图 显示了当你计算它的对数时这个特征看起来有多好:它非常接近高斯分布(即钟形)。 另一种处理重尾特征的方法是对特征进行反向转换。这意味着将其分布切割成大致相等大小的桶,并将每个特征值替换为它所属的桶的索引,就像我们创建收入猫特征一样(尽管我们只在分层抽样时使用它)。例如,您可以将每个值替换为其百分位数。使用相同大小的bucket处理会产生一个几乎均匀分布的特性,因此不需要进一步的缩放,或者您可以只除以bucket的数目来强制值到0-1的范围。 当一个特征具有多峰分布(即,有两个或两个以上清晰的峰值,称为模式)时,例housing_median_age特征,对它进行bucket ization也是有帮助的,但这次将bucket ID作为类别处理,而不是作为数值。这意味着必须对桶索引进行编码,例如使用OneHotEncoder(所以你通常不想用太多桶)。这种方法将允许回归模型更容易地为该特征值的不同范围学习不同的规则。例如,也许35年前建造的房子有一种独特的风格,已经过时了,因此它们比它们的年龄更便宜。 转换多峰分布的另一种方法是为每个模式(至少是主要模式)添加一个特征,表示住房中位年龄和该特定模式之间的相似性。相似性度量通常使用径向基函数(RBF)来计算–任何只依赖于输入值与不动点之间距离的函数。最常用的RBF是高斯RBF,其输出值随着输入值远离固定点而呈指数衰减。例如,高斯RBF相似度与房龄x和35由方程exp (-y (x-35)2)给出。超参数y(gamma)确定当x远离35时相似性度量衰减的速度。使用Scikit-Learn的rbf_kernel()函数,您可以创建一个新的高斯RBF特征来测量房屋中位年龄和35: from sklearn.metrics.pairwise import rbf_kernel age_simil_35 = rbf_kernel(housing[["housing_median_age"]], [[35]], gamma=0.1) 下图显示了这一新特征作为住房中位数年龄的函数(实线)。它还显示了如果使用较小的gamma值,该功能将是什么样子。如图所示,新的年龄相似性特征在35岁时达到峰值,正好在住房中位年龄分布的峰值附近:如果这个特定的年龄组与较低的价格有很好的相关性,那么这个新特征将有很好的机会发挥作用。 到目前为止,我们只看了输入特性,但是目标值可能也需要转换。例如,若目标分布具有较重的尾部,您可以选择将目标替换为其对数。但是,如果你这样做,回归模型现在将预测的房屋价值中位数的对数,而不是房屋价值中位数本身。如果您想要预测的房屋中值,则需要计算模型预测的指数值。 幸运的是,大多数Scikit-Learn的转换器都有一个inverse_transform()方法,这使得计算转换的逆运算变得很容易。例如,下面的代码示例显示了如何使用StandardScaler缩放标签(就像我们对输入所做的那样),然后在缩放后的标签上训练一个简单的线性回归模型,并使用它对一些新数据进行预测,然后使用经过训练的缩放器的inverse_transform()方法将这些数据转换回原始尺度。请注意,我们将标签从Pandas Series转换为DataFrame,因为标准Scaler期望2D输入。此外,为了简单起见,在本示例中,我们仅使用单个原始输入特征(中值收入)对模型进行训练: from sklearn.linear_model import LinearRegression target_scaler = StandardScaler() scaled_labels = target_scaler.
2023-11-18
[Machine Learning 人工智能]
为机器学习算法准备数据(Machine Learning 研习之八)
本文还是同样建立在前两篇的基础之上的! 属性组合实验 希望前面的部分能让您了解探索数据并获得洞察力的几种方法。您发现了一些数据怪癖,您可能希望在将数据提供给机器学习算法之前对其进行清理,并且发现了属性之间有趣的相关性,特别是与目标属性 之间的相关性。您还注意到一些属性具有向右倾斜的分布,因此您可能需要转换它们(例如,通过计算它们的对数或平方根)。当然,你的里程会因每个项目而有很大的不同,但大致的想法是相似的。 在为机器学习算法准备数据之前,您可能需要做的最后一件事是尝试各种属性组合。例如,如果你不知道一个地区有多少住户,那么这个地区的房间总数就不是很有用。你真正想要的是每个家庭的房间数量。同样,卧室总数本身也不是很有用:你可能想对比一下房间的数量。每个家庭的人口似乎也是一个有趣的属性组合。创建这些新属性如下: housing["rooms_per_house"] = housing["total_rooms"] / housing["households"] housing["bedrooms_ratio"] = housing["total_bedrooms"] / housing["total_rooms"] housing["people_per_house"] = housing["population"] / housing["households"] 然后你再看一遍相关矩阵: !新的bedrooms_ratio属性与房屋中值的相关性要比与房间或卧室总数的相关性大得多。显然,卧室/房间比率较低的房子往往更贵。每个家庭的房间数量也比一个地区的房间总数更能说明问题-很明显,房 子越大,就越贵。 这一轮的探索不需要绝对彻底;关键是从正确的角度出发,并迅速获得见解,这将帮助您获得第一个相当好的原型。但是这是一个迭代的过程:一旦你建立并运行了一个原型,你就可以分析它的输出以获得更多的见解,然后再回到这个探索步骤。 为机器学习算法准备数据 是时候为您的机器学习算法准备数据了。你应该为此编写函数,而不是手工操作,这有几个很好的理由: 这将允许您在任何数据集上轻松重现这些转换(例如,下次获得新数据集时)。 您将逐步构建一个转换函数库,以便在未来的项目中重用。 您可以在实时系统中使用这些函数来转换新数据,然后再将其输入到您的算法中。 这将使您能够轻松地尝试各种转换,并查看哪种转换组合效果最好。 但首先,恢复到一个干净的训练集(通过再次复制strat_train_set)。您还应该将预测变量和标签分开,因为您不一定希望对预测变量和目标值应用相同的转换(请注意,drop()创建数据的副本,并且不影响strat_train_set): housing = strat_train_set.drop("median_house_value", axis=1) housing_labels = strat_train_set["median_house_value"].copy() 清除数据 大多数机器学习算法无法处理缺失的功能,因此您需要处理这些功能。例如,您之前注意到total_bedrooms属性有一些缺失值。你有三个选项可以解决这个问题: 去掉相应的区。 去掉整个属性。 将缺失值设置为某个值(零、均值、中位数等)。这就是所谓的归罪。 您可以使用PandasDataFrame的dropna () 、drop () 和fillna ()方法轻松完成这些任务: housing.dropna(subset=["total_bedrooms"], inplace=True) # option 1 housing.drop("total_bedrooms", axis=1) # option 2 median = housing["total_bedrooms"].median() # option 3 housing["total_bedrooms"].fillna(median, inplace=True) 您决定使用选项3,因为它的破坏性最小,但是您将使用一个方便的Scikit-Learn类:Simplelmputer,而不是前面的代码。这样做的好处是,它将存储每个特征的中值:这将使得它不仅可以估算训练集上的缺失值,还可以估算验证集、测试集和输入到模型的任何新数据上的缺失值。要使用它,首先需要创建一个Simplelmputer实例,指定要将每个属性的缺失值替换为该属性的中位数: from sklearn.
2023-11-05
[Machine Learning 人工智能]
端到端的机器学习项目之探索数据(Machine Learning 研习之七)
本篇其实是承接上一篇内容,之所以没在上一篇将它写完,那是有原因的,毕竟,本着学习的态度,篇幅不应过长,方能使你有学习的欲望! 探索数据 首先,确保你已经把测试放在一边,你只是在探索训练集。此外,如果训练集非常大,您可能希望对探索进行采样设置,使操作在勘探阶段变得容易和快速。在这种情况下,培训集非常小,所以您可以直接处理完整集。由于你要试验完整训练集的各种变换,你应该制作一份原始的所以你可以在之后恢复它: housing = strat_train_set.copy() 可视化地理数据 因为数据集包括地理信息(纬度和经度),所以创建一个所有地区的散点图来可视化数据是一个好主意(见下图): housing.plot(kind="scatter", x="longitude", y="latitude", grid=True) plt.show() 这看起来很像加州,但除此之外,很难看到任何特别的模式。将alpha选项设置为0.2可以更容易地显示数据点密度高的位置(见下图): housing.plot(kind="scatter", x="longitude", y="latitude", grid=True, alpha=0.2) plt.show() 现在的情况要好得多:你可以清楚地看到高密度地区,即海湾地区、洛杉矶和圣地亚哥周围,再加上中央山谷(特别是萨克拉门托和弗雷斯诺)的一长排高密度地区。 我们的大脑非常善于发现图片中的模式,但你可能需要玩弄可视化参数,使模式脱颖而出。 接下来,你再看看房价(见下图)。每个圆圈的半径代表该地区的人口(选项s),颜色代表价格(选项c)。这里使用了一个名为jet的预定义颜色映射(选项cmap),其范围从蓝色(低值)到红色(高价):s housing.plot(kind="scatter", x="longitude", y="latitude", grid=True, s=housing["population"] / 100, label="population", c="median_house_value", cmap="jet", colorbar=True, legend=True, sharex=False, figsize=(10, 7)) plt.show() 这张图告诉你,房价与地理位置(例如,靠近大海)和人口密度密切相关,你可能已经知道了。聚类算法对于检测主集群和添加测量与集群中心的邻近性的新特性应该是有用的。海洋邻近属性也可能是有用的,尽管在北加州沿海地区的房价不是太高,所以这不是一个简单的规则。 寻找相关性 由于数据集不是太大,你可以很容易地使用corr()方法计算每对属性之间的标准相关系数(也称为皮尔逊相关系数): corr_matrix = housing.corr() 现在您可以查看每个属性与房屋中值的相关性: 相关系数从-1到1。当它接近1时,意味着有很强的正相关关系,例如,当收入中位数上升时,房屋价值中位数往往会上升。当系数接近-1时,意味着有很强的负相关性;你可以看到纬度和房屋价值中间值之间有一个很小的负相关性(即往北走,房价有轻微的下降趋势)。最后,系数接近0意味着不存在线性相关关系。 检查属性之间相关性的另一种方法是使用Pandas scatter_matrix ()函数,该函数将每个数值属性与其他每个数值属性进行绘图。由于现在有11个数字属性,您将得到112=121幅不适合页面的地块,所以您决定将重点放在一些看起来与住房中值最相关的有前途的属性上(见下图): 如果Pandas将每个变量相对于自身绘制,那么主对角线将充满直线,这将不是很有用。因此,Pandas显示每个属性的直方图(其他选项可用;请参阅Pandas文档以获取更多详细信息)。 查看相关散点图,似乎最有希望预测房屋价值中位数的属性是收入中位数,所以你放大他们的散点图(见下图): housing.plot(kind="scatter", x="median_income", y="median_house_value", alpha=0.1, grid=True) plt.show() 这个情节揭示了一些事情。首先,相关性确实很强;你可以清楚地看到上升的趋势,而且点也不太分散。第二,你之前注意到的价格上限在500,000美元的水平线上明显可见。但这个情节也揭示了其他不那么明显的直线:一条水平线在45万美元左右,另一条大约35万美元左右,也许还有一条大约28万美元,还有几条低于这一点。您可能希望尝试删除相应的区域,以防止您的算法学习重现这些数据怪癖。 警告: 相关系数只测量线性相关性(“当x上升时,y通常上升/下降”)。它可能会完全忽略非线性关系(例如,“当x接近0时,y通常会上升”)。图2-16显示了各种数据集及其相关系数。请注意,尽管它们的轴线显然不是独立的,但底部行的所有图都具有等于0的相关系数:这些都是非线性关系的例子。另外,第二行显示了相关系数等于1或-1的示例;注意,这与斜率无关。例如,以英寸为单位的身高与以英尺或纳米为单位的身高的相关系数为1。
2023-10-24
[Machine Learning 人工智能]
1
...
3
4
5
...
11