量子振幅放大实用指南
格罗弗的搜索算法是第一个也是最突出的例子之一,展示了量子电路如何比经典算法快几个数量级
本帖是本书的一部分: 用 Python 动手做量子机器学习 。
在之前的文章中,我们对算法的工作原理有了一个概念性的理解。它遵循一个简单的程序。量子预言反转了被搜索状态的振幅。然后,扩散器翻转关于平均振幅的所有状态,因此,放大被搜索的状态。
作者弗兰克·齐克特的图片
我们了解到我们可以使用相位来放大振幅。如果我们应用一个 HZH 序列,它会把一个量子比特从|0⟩态变成|1⟩.态
作者弗兰克·齐克特的图片
但是一个 HIH 序列将一个量子位从|0⟩变成|+⟩,再回到|0⟩.
作者弗兰克·齐克特的图片
虽然电路的起点和终点保持不变,但我们可以通过翻转(HZH)或不翻转(HIH)的相位来控制量子位的最终振幅
在单量子位电路中,这些电路恒等式似乎相当琐碎。所以,现在让我们来看看,我们如何在实际中利用两个量子位和四个状态。
同样,我们从所有状态的相等叠加开始。对于四个状态,每个状态的幅度为 0.5,得到的测量概率为 0.25。
作者弗兰克·齐克特的图片
下一步,我们需要实现 oracle。其目的是翻转有利状态的振幅。假设它在|10⟩.记住,我们从右边(位置 0 的量子位)到左边(位置 1 的量子位)读取量子位。
作者弗兰克·齐克特的图片
如果控制量子位处于|1⟩.状态,受控 z 门(CZ,垂直连接的点)在目标量子位上应用 z 门因此,当两个量子位都处于|1⟩态和|11⟩.态时,这个门就产生了相移通过将受控的 z 门封装在我们应用于第一个量子位的非门中,我们选择了状态|10⟩而不是|11⟩.
下面的状态及其相位图证实了这种影响。我们翻转了|10⟩.的状态 CZ 门纠缠两个量子位。
作者弗兰克·齐克特的图片
现在,我们需要一个扩散器来放大振幅。它从在所有量子位上应用哈达玛门开始。在下图中,散流器从第二个垂直分离器的右侧开始。
作者弗兰克·齐克特的图片
这一系列的哈达玛门有相当有趣的效果。它切换|01⟩和|10⟩.的振幅
作者弗兰克·齐克特的图片
封装在非门中的受控 Z 门的下一序列具有简单的效果。它翻转了|00⟩.的振幅此外,受控制的 Z 闸再次解开两个量子位元的纠缠。
作者弗兰克·齐克特的图片
作者弗兰克·齐克特的图片
现在,|00⟩和|01⟩共享一个阶段,|10⟩和|11⟩共享一个阶段。换句话说,第一个量子位(符号的右边)在|+⟩状态,第二个量子位在|−⟩.状态
当我们在两个量子位上应用哈达玛门时,我们把来自|+⟩的第一个量子位转换成|0⟩,把来自|−⟩的第二个量子位转换成|1⟩.我们总是在|10⟩州测量系统——我们通过神谕标记的州。
作者弗兰克·齐克特的图片
下图描绘了完整的电路
作者弗兰克·齐克特的图片
这个电路包含相当多的相移,直到我们在最后应用哈达玛门,量子位产生了神谕所标记的期望状态。
这个电路中的大多数门都有技术用途。例如,CZ 门允许我们在多量子位系统中标记一个单一的状态。
如果我们把整个电路分成几个部分,从概念上看这些部分,我们可以发现一个熟悉的结构。我们在起点和终点都看到了哈达玛门。中心部分由神谕和扩散器组成,代表我们应用于第一个量子位的 Z 门和应用于第二个量子位的 I 门。
这个电路的整体模式类似于我们应用于第一个量子位的 HIH 序列和我们应用于第二个量子位的 HZH 序列。I-gate 不会改变量子位,而 Hadamard gate 会自行恢复。因此,第一个量子位元会回到它开始时的状态。那是|0⟩.HZH 门等同于非门,将第二个量子位从初始状态|0⟩变成|1⟩.
结论
格罗弗的电路遵循一个简单的想法。第一组哈达玛闸将量子位元带到相位重要的状态。神谕改变了被搜索状态的阶段。扩散器重新排列所有状态的相位,以便后面的哈达玛门将量子位带入标记状态。
这个电路的美妙之处在于,唯一改变的是标记被搜索状态的神谕。扩散器保持不变。
本帖是本书的一部分: 用 Python 动手做量子机器学习 。
在这里免费获得前三章。
使用 Scikit-Learn 分类的七个基本性能指标实用指南
入门
通过 Python 中的实例介绍了准确率、混淆矩阵、准确率、召回率、F1 值、ROC 曲线和 AUROC。
性能测量是任何机器学习项目中必不可少的过程。我们的机器学习过程可能不总是产生具有预期准确性的最佳模型。因此,这里需要性能测量来评估训练模型在预测中的有效性。
绩效测量中使用的指标种类繁多,但一般来说,它们可以根据模型类型进行分类,1)分类器或 2)回归器。在本文中,我们将通过介绍在分类项目中使用的七个常见的性能度量标准来关注分类器类型的度量。这七项指标如下:
- 准确度得分
- 混淆矩阵
- 精度
- 召回
- F1 得分
- ROC 曲线
- 奥罗克
虽然理解上述一些性能指标的基本概念可能需要一段时间,但好消息是,使用 Python 机器学习库Scikit-Learn,这些指标的实现从未如此简单。Scikit-Learn 可以用几行 Python 代码简化性能测量。
在下面的部分中,将通过基于经典威斯康星州乳腺癌数据集的简单二元分类项目来解释每个性能指标的概念。这种分类的目的是预测乳腺癌肿瘤是恶性还是良性。
为了确保您能够理解这些材料,建议您使用sci kit-learn 0.23 版或更高版本更新您的 Python 包。这里介绍的一些功能在 Scikit-learn 的早期版本中可能不受支持。
注:
完整的源代码可以从我的 Jupyter 笔记本格式的 Github 中获得。(如果您希望在阅读下面的材料时预览源代码,可以提前下载 Jupyter 笔记本)。
1.数据准备
1.1 数据加载
我们将使用威斯康星州乳腺癌数据集进行分类。为了获得数据,我们可以使用 Scikit-Learn 中的一个助手函数。
load_breast_cancer 是一个 Scikit-Learn 辅助函数,它使我们能够获取所需的乳腺癌数据集并将其加载到 Python 环境中。这里我们调用 helper 函数,并将加载的乳腺癌数据赋给一个变量, br_cancer 。
加载的数据集具有 Python 字典结构,其中包括:
- 一个" data" 键,包含一个数组,每个实例一行,每个特征一列
- 包含标签数组的“目标”键
- 包含数据集描述的“描述”键
1.2 数据探索
现在,让我们通过显示前三行记录来快速预览一下加载的数据集。
前三行记录(图片由作者准备)
记录显示乳腺癌数据集由 30 个数字特征组成(每列一个特征)。如果你有兴趣了解更多关于特性的细节,你可以参考这里的资源。
接下来,我们来看看前三个目标值。
前三个目标值(图片由作者准备)
前三个值是 0 ,表示一个“恶性类。还有另一个可能的值是 1,表示“良性类。
两个可能的类别(图片由作者准备)
现在,我们可以将特征值和目标值分别赋给变量 X 和 y,。
1.3 数据标准化
此时,您可能已经注意到 30 个特性的值范围不一致,这可能会影响我们模型预测的准确性。为了避免这个问题,我们可以使用 Scikit-Learn 标准缩放器将特征值重新缩放到其单位方差。
缩放后的特征值(图片由作者准备)
我们创建一个 StandardScaler 对象,并使用其 fit_transform 方法来重新缩放我们的 X 值,并将转换后的值赋给一个变量 X_scaled 。
1.4 将数据分为训练集和测试集
在训练分类器之前,我们需要将数据集分成训练集和测试集。为此,我们可以利用 Scikit-Learn 函数, train_test_split。
train_test_split 可以自动随机化我们的数据集,并根据我们分配的 test_size 将其分成训练集和测试集。在这种情况下,我们将 test_size 设置为 0.3,以便留出 30%的数据集作为测试集,其余的将用作训练集。训练集和测试集分别分配给变量 X_train 、 X_test 、 y_train 和 y_test 。
2.训练分类器
我们将分别基于 k-最近邻算法(KNN)、随机梯度下降(SGD)和逻辑回归来训练三个分类器。我们构建三个分类器的原因是,我们可以使用本文将要介绍的度量标准来比较它们的性能。
Scikit-Learn 为我们提供 KNN、SGD 和逻辑回归分类器。我们需要做的只是将这些分类器( KNeighboursClassifier、SGDClassifier 和 LogisticRegression )导入到我们的 Python 环境中。接下来,我们为每个分类器创建一个对象,然后使用拟合方法开始训练各自的分类器,使用相同的训练集(X _ train&y _ train)作为其输入。
(整个训练过程应该只需要几秒钟,因为我们正在处理一个非常小的数据集。)
现在,让我们通过使用模型内置方法预测来尝试使用我们训练的分类器进行预测。
我们将测试集取到预测方法中,每个分类器的预测结果分别存储在三个变量 y_pred_knn、 y_pred_sgd 和 y_pred_log 中。
3.性能测定
这是本文的主题。在这里,我们将通过深入研究分类器的基本概念及其使用 Scikit-Learn 的实现来涵盖分类器的七个性能指标。
先说最简单的一个,准确率评分。
3.1 准确度得分
3.1.1 概念
准确度分数可能是衡量分类器性能的最直接的指标。这是一个向我们展示正确预测的一部分的指标。公式如下:
准确度分数的公式(图片由作者准备)
假设在我们的测试集中有 100 条记录,并且我们的分类器成功地对其中的 92 条进行了准确的预测,那么准确性得分将是 0.92。
3 . 1 . 2 sci kit-Learn 中的实施
Scikit-Learn 提供了一个函数 accuracy_score ,它接受真实值和预测值作为其输入来计算模型的准确度分数。
首先,我们从 Scikit-Learn 的度量模块中导入 accuracy_score 函数。接下来,我们将 y_test 作为真值,将 y_pred_knn ,y _ pred _ SGD&y _ pred _ log作为预测值输入到 accuracy_score 函数中。将得到的准确度分数分配给三个变量,并打印分数。
三个分类器的结果准确度分数(图片由作者准备)
所得的准确度分数揭示了逻辑回归分类器在三个分类器中表现出最高的性能。然而,所有三个分类器通常都很高(> 95%的准确度),这给了我们一个粗略的想法,即这些分类器在识别恶性或良性肿瘤中是有效的。
3.2 混淆矩阵
3.2.1 概念
总的来说,准确度分数只给了我们正确预测的一小部分。如果我们想从以下几个方面了解我们的分类器,该怎么办:
- 我们的样本中有多少恶性肿瘤被正确和错误地预测了?
- 我们的样本中有多少良性肿瘤被正确和错误地预测了?
这些问题是至关重要的,因为没有一个病人会乐于接受错误报告的医疗结果。理想情况下,对恶性和良性类别的预测应该达到很高的准确度,以最小化错误报告。如果我们的分类器明显偏向恶性或良性类别,我们可能需要通过调整一些超参数或获取额外的数据到训练管道来重新训练我们的分类器。
因此,评估分类器性能的更好方法是使用混淆矩阵。混淆矩阵(也称为误差矩阵)是一个二维表格,允许分类器对正确标记和错误标记的实例进行可视化。
给定测试集中的 100 个实例的样本,其中每个实例属于正类或负类。分类器在该测试集上的性能可以表示为下面的混淆矩阵:
混淆矩阵的样本(图片由作者准备)
上面混淆矩阵中的每一列代表一个实际的类,而每一行代表一个预测的类。左上象限显示在测试集中有 44 个被准确预测的阳性实例,因为实际类(阳性)与预测类(阳性)相匹配。这种结果被称为真阳性(TP) 。另一方面,右上象限显示了被错误预测为阳性类别的 6 个阴性实例,这些实例被称为假阳性(FP) 。
在右下象限,有 48 个被正确预测的负实例,被称为真负(TN) 。最后,左下象限显示 2 个阳性实例,它们被错误地预测为阴性类别,这些实例被称为假阴性(FN) 。
从上面的样本混淆矩阵中,我们可以观察到,分类器在识别负类时表现出比正类稍好的性能。理想情况下,一个好的分类器应该具有尽可能少的假阳性和假阴性。这意味着混淆矩阵的主对角线中的非零数字越高,分类器的性能越好。
3.2.2 在 Scikit-Learn 中实现
虽然对混淆矩阵的解释可能听起来很冗长,但实现只需要几行代码(感谢 Scikit-Learn)。让我们尝试使用 Scikit-Learn 的混淆矩阵函数为我们的 KNN 分类器构建一个混淆矩阵表。
首先,我们将混淆矩阵函数导入到我们的 Python 环境中。通过向函数传递两个必需的参数,真值( y_test )和预测值( y_pred_knn ),将生成一个表示为 2D 数组的混淆矩阵,如下所示:
Scikit-Learn 生成的 2D 阵列(图片由作者准备)
为了减轻我们在乳腺癌预测中解释 2D 阵列的任务,我们可以通过将阳性类别称为恶性,将阴性类别称为良性,来尝试将 2D 阵列映射到我们之前的混淆矩阵表**。**
将 2D 阵列映射到 KNN 分类器的混淆矩阵表(图片由作者准备)
给定测试集中总共 171 个实例,混淆矩阵显示有 59 个恶性肿瘤被正确分类(真阳性),4 个良性肿瘤被错误分类为恶性(假阳性),105 个良性肿瘤被正确分类(真阴性),另外 3 个恶性肿瘤被错误分类为良性(假阴性)。
基本上,KNN 分类器展示了对恶性和良性肿瘤的良好预测工作。通过重复上述类似的步骤,我们还可以为我们的 SGD 分类器和逻辑回归分类器创建混淆矩阵,然后将它们与 KNN 分类器进行比较。
将 2D 阵列映射到 SGD 分类器的混淆矩阵表(图片由作者准备)
将 2D 阵列映射到 log reg 分类器的混淆矩阵表(图片由作者准备)
现在,让我们看看所有三个混淆矩阵,并在它们之间进行比较。
三种分类器混淆矩阵的比较(图片由作者准备)
从上面的结果中,我们可以观察到 SGD 分类器显示出稍高的假阴性数量,尽管它的总体准确度分数优于 KNN。如果我们只有两个分类器的选择,KNN 或 SGD,并且目标是更低的假阴性,KNN 可能是一个更好的选择,即使它的整体准确性分数略低于 SGD。
另一方面,很明显,逻辑回归分类器仍然是赢家,因为它在三个分类器中显示出最低数量的假阳性和假阴性。
3.3 精确度、召回率和 F1 分数
3.3.1 概念
混淆矩阵向我们显示了一个分类结果中真阳性、假阳性、真阴性和假阴性的确切数量。事实上,我们可以进一步从混淆矩阵中导出几个有用的度量。
首先,我们可能会问自己:真正肯定的积极预测的比例是多少?
阳性预测中真正阳性的比例(图片由作者准备)
为了解决这个问题,让我们通过一个简单的数学计算逻辑,如下所示。
精度计算(图片由作者准备)
真正阳性的数量与阳性总数之间的比率就是所谓的**精度。**精度公式如下:
精确公式(图片由作者准备)
精度给了我们一个量词来揭示预测的阳性实例中真正阳性的部分。上面的样本分类器达到了 0.88 的精度分数,这也意味着 88%的预测阳性是真阳性。
现在,让我们考虑另一个微妙的问题:被正确预测为阳性的阳性实例的比例是多少?
预测为阳性的阳性实例的比例(图片由作者准备)
我们将再次使用一个简单的数学逻辑来解决这个问题。
回忆的计算(图片由作者准备)
上面的计算得出真实阳性与阳性实例总数之间的比率,该比率称为召回。回忆也称为敏感度或真阳性率(TPR)。召回的公式如下所示:
回忆公式(图片由作者准备)
上面的样本分类器的召回分数为 0.957,高于其精确度。这意味着在所有 46 个阳性实例中,95.7%被正确预测为阳性。
精确度和召回率也可以合并成一个单一的指标,称为 F1 分数。F1 分数是精确度和召回率的调和平均值。
F1 分数公式(图片由作者准备)
初看起来,F1 分数公式似乎有点令人生畏,但它只是一个特定的平均值,给予低值更多的权重(与平等对待所有值的常规平均值相比)。高 F1 分数表示相似的精确度和召回率。例如,如果我们将 F1 分数公式应用于我们的样本分类器,我们将得到大约 0.917 的分数。这表明样本分类器的准确率和召回率都很高。
重要的是要知道精确度和召回率并不总是相似的,在某些情况下,我们更喜欢精确度高于召回率,反之亦然。例如,我们期望在医学使用案例(如癌症检测)中有更高的召回率。使我们的分类器能够准确地识别尽可能多的真正阳性癌症实例总是比忽略一些阳性实例更好。另一方面,银行分析师可能更喜欢他们的贷款分类器具有更高的精度,这样他们就不会意外拒绝潜在客户并失去业务。
不幸的是,我们不能总是调整我们的分类器来达到几乎同样高的精度和召回率。提高精确度会导致召回率的降低,反之亦然。这就是所谓的精度/召回权衡。
3 . 3 . 2 sci kit-Learn 中的实现
现在是时候再次动手使用 Scikit-Learn 实现我们在本节中涉及的指标了。使用 Sckit-Learn 提供的 classification_report 函数可以轻松获得精确度、召回率和 F1 分数指标。
像往常一样,我们将所需的 classification_report 函数导入到 Python 环境中。接下来,让我们尝试从数据集中提取目标名称(恶性和良性),并将其分配给一个变量 targets 。由 targets 变量保存的名称稍后将显示为最终结果的一部分。最后,我们将三个参数,真值( y_test )、预测值( y_pred_knn、y_pred_sgd & y_pred_log )和目标名称( targets )传递给 classification_report 函数并打印出结果,如下所示。
三个分类器的分类报告(图片由作者准备)
总的来说,三种分类器在准确率、召回率和 F1 值上没有明显的差异。逻辑回归仍然是明显的赢家,恶性和良性类别的 F1 值分别为 0.98 和 0.99。此外,其 0.98 的高召回率已经证明其本身是对恶性肿瘤进行可靠检测的可靠分类器。
3.4 ROC 曲线和 AUROC
3.4.1 概念
接收器工作特性(ROC)曲线为我们提供了一种可视化方法来检查我们训练过的分类器的性能。这是一条绘制分类器的真阳性率(TPR)与其假阳性率(FPR)的曲线。如前所述,TPR 也称为召回。另一方面,FPR 是被错误预测为阳性的阴性实例的比率。
ROC 曲线示例如下:
ROC 曲线(图片由作者准备)
TPR 和 FPR 之间有一个权衡,TPR 越高,分类器产生的 FPR 越多。中间的斜虚线代表随机分类器 ROC 曲线。
一个好的分类器的 ROC 曲线应该尽可能远离对角线,朝向左上角。基于这一基本原理,我们可以通过计算曲线下面积(AUC)来衡量和比较我们的分类器的性能,这将产生一个名为 AUROC ( 受试者操作特性**下的面积)**的分数。一个完美的 AUROC 应该有 1 分,而一个随机分类器应该有 0.5 分。
3 . 4 . 2 sci kit-Learn 中的实施
Scikit-Learn 提供了一个方便的函数, plot_roc_curve ,我们可以用它来创建 roc 曲线并计算 AUROC 分数。
plot_roc_curve 函数只需要三个参数,即分类器( knn_model )、测试集( X_test )和真值( y_test ),它将自动生成 roc 曲线并实时计算我们的 knn 分类器的 AUROC 分数。
KNN 分类器的 ROC 曲线和 AUROC 分数(图片由作者准备)
让我们为 SGD 和逻辑回归分类器重复类似的步骤。
SGD 分类器的 ROC 曲线和 AUROC 分数(图片由作者准备)
Log Reg 分类器的 ROC 曲线和 AUROC 分数(图片由作者准备)
我们的逻辑回归分类器的 AUROC 达到了满分 1。通过查看我们在这里讨论的所有指标的结果,我们可以得出结论,逻辑回归分类器是三者中表现最好的。该分类器被证明是预测乳腺癌肿瘤类型的最可靠的模型。
结论
在本文中,我们已经使用上面介绍的七个度量标准完成了测量三个分类器性能的步骤。使用 Scikit-Learn 可以很容易地实现它们。Scikit-Learn 在一些性能指标中封装了大量底层复杂逻辑,它提供了一个一致的编程接口来接受输入参数并即时生成所需的结果。我希望您能从这里提供的材料中受益,它能让您在学习分类器性能指标的同时接触 Scikit-Learn(如果您还不熟悉 Scikit-Learn)。
资源
完整的源代码可以从我的 Github 库获得。
参考
- Geron,A. (2019)。使用 Scikit-Learn、Keras & TensorFlow 进行机器学习。奥莱利媒体。
- https://en.wikipedia.org/wiki/Confusion_matrix
- 【https://en.wikipedia.org/wiki/Precision_and_recall
TFRecords 实践指南
关于处理图像、音频和文本数据的介绍
TensorFlow 的自定义数据格式 TFRecord 真的很有用。这些文件由速度极快的 tf.data API 提供本机支持,支持分布式数据集,并利用并行 I/O。但它们起初有些令人难以招架。这篇文章是一个实践性的介绍。
概观
在下文中,我们将使用人工数据来回顾 TFRecord 文件背后的概念。记住这一点,我们就可以继续研究图像;我们将使用小型和大型数据集。扩展我们的知识,然后我们处理音频数据。最后一个大的领域是文本领域,我们也会涉及到。为了将所有这些结合起来,我们创建了一个人工的多数据类型数据集,并且,您可能已经猜到了,也将它写入 TFRecords。
TFRecord 的布局
当我开始我的深度学习研究时,我天真地将我分散在磁盘上的数据存储起来。更糟糕的是,我用数千个小文件污染了我的目录,大约只有几 KB。我当时工作的集群并不觉得有趣。加载所有这些文件花了相当长的时间。
这就是 TFRecords(或大型 NumPy 数组,就此而言)派上用场的地方:我们不是存储分散的数据,而是迫使磁盘在块之间跳转,而是简单地将数据存储在一个顺序布局中。我们可以用以下方式来形象化这个概念:
作者创建的可视化
TFRecord 文件可以看作是所有单个数据样本的包装器。每一个数据样本都被称为一个示例,本质上是一个字典,存储着一个键和我们实际数据之间的映射。
现在,看似复杂的部分是这样的:当你想把数据写到 TFRecords 时,你首先必须把你的数据转换成一个特性。这些特征是一个示例的内部组件:
作者创建的可视化
到目前为止,一切顺利。但是现在将数据存储在压缩的 NumPy 数组或 pickle 文件中有什么区别呢?两件事:TFRecord 文件是顺序存储的,由于访问时间短,可以实现快速流式传输。其次,TFRecord 文件原生集成到 TensorFlows tf.data API 中,可以轻松实现批处理、混排、缓存等功能。
另外,如果您有机会和计算资源进行多工人培训,您可以将数据集分布在您的机器上。
在代码级别,特性创建是通过这些方便的方法进行的,我们将在后面讨论这些方法:
要将数据写入 TFRecord 文件,首先要创建一个字典,该字典表示
我想把这个数据点存储在这个键下
当从 TFRecord 文件中读取时,您可以通过创建一个字典来反转这个过程,该字典说
我有这个键,用存储在这个键上的值填充这个占位符
让我们看看这是如何运作的。
图像数据,小
一只小猫。在 Unsplash 上由 Kote Puerto 拍摄的照片
图像是深度学习中的一个常见领域,MNIST [1]和 ImageNet [2]是两个众所周知的数据集。将您的图像从磁盘放入模型的方法有很多:编写一个定制的生成器,使用 Keras 的内置工具,或者从 NumPy 数组加载它。为了高效地加载和解析图像数据,我们可以求助于 TFRecords 作为底层文件格式。
过程如下:我们首先创建一些随机图像——也就是说,使用 NumPy 随机填充给定图像形状的矩阵:宽度、高度和颜色通道:
输出符合预期;我们有 100 个形状为 250x250 的图像,每个图像有三个通道:
(100, 250, 250, 3)
我们也创造一些人为的标签:
因此,我们有一个形状为(100,1)的标签数组,每个图像存储一个标签。打印出前十个标签:
(100, 1)
[[2] [4] [3] [3] [2] [4] [2] [3] [3] [0]]
为了将这些{image,label}对放入 TFRecord 文件,我们编写了一个简短的方法,获取一个图像及其标签。使用上面定义的助手函数,我们创建一个字典,在键 height 、 width 和depth——w中存储我们图像的形状,我们需要这些信息在以后重建我们的图像。接下来,我们还将实际图像存储为 raw_image 。为此,我们首先序列化数组(考虑构建一个长列表),然后将其转换为一个 bytes_feature 。最后,我们存储图像的标签。
所有这些键:值映射构成了一个示例的特性,如上所述:
既然我们已经定义了如何从一对{image,label}创建一个示例,我们需要一个函数将我们的完整数据集写入 TFRecord 文件。
我们首先创建一个 TFRecordWriter ,随后使用它将示例写入磁盘。对于每个图像和相应的标签,我们使用上面的函数来创建这样一个对象。在写入磁盘之前,我们必须对其进行序列化。在我们使用完数据后,我们关闭我们的 writer 并打印我们刚刚解析的文件数:
这就是将图像写入 TFRecord 文件所需的全部内容:
输出与预期的一样,因为我们刚刚解析了 100 个{image,label}对:
Wrote 100 elements to TFRecord
有了这个文件在我们的磁盘上,我们以后可能也会有兴趣阅读它。这也是可能的,并且是相反的:
前面,我们定义了一个用于将内容写入磁盘的字典。我们现在使用类似的结构,但这次是为了读取数据。之前,我们说过键宽度包含 int 类型的数据。因此,当我们创建字典时,我们也分配一个 int 类型的占位符。因为我们正在处理固定长度的特性(我们大部分时间都在处理这些特性;稀疏张量很少使用),我们说:
给我我们存储在键“width”中的数据,并用它填充这个占位符
类似地,我们为其他存储的特性定义了 key:placeholder 映射。然后,我们通过用 parse_single_example 解析元素来填充占位符。假设我们处理的是一个字典,我们通常可以通过访问相应的键来提取所有的值。
在最后一步中,我们必须将图像从序列化形式解析回(高度、宽度、通道)布局。注意,我们希望 out_type 为 int16,这是必需的,因为我们也是用 int16 创建映像的:
为了从解析元素中创建数据集,我们只需利用 tf.data API。我们通过将 TFRecord 文件指向磁盘上的 TF record 文件来创建一个 TFRecordDataset ,然后将我们之前的解析函数应用于每个提取的示例。这会返回一个数据集:
我们可以通过获取单个数据点来探索数据集的内容:
输出是
(250, 250, 3)
()
第一行是一个图像的形状;第二条线是标量元素的形状,它没有维度。
这标志着小型数据集解析的结束。在下一节中,我们将研究如何解析一个更大的数据集,在解析过程中创建多个 TFRecord 文件。
图像数据,大
一只大猫。照片由蒂莫西·梅恩伯格在 Unsplash 上拍摄
在上一节中,我们向单个 TFRecord 文件中写入了一个相当小的数据集。对于更大的数据集,我们可以考虑将数据分割到多个这样的文件中。
首先,让我们创建一个随机图像数据集:
下一步将创建相应的标签:
由于我们现在正在处理一个更大的数据集,我们首先必须确定我们甚至需要多少个碎片。为了计算这一点,我们需要文件总数和希望存储在单个碎片中的元素数量。我们还必须考虑这样的情况,例如,每个分片有 64 个图像和 10 个文件。这将导致 6 个碎片(6x10 ),但会丢失最后 4 个样本。我们只是通过预先添加一个额外的碎片来避免这种情况,如果我们有 60 个文件,就删除它,因为 60//10 不会留下任何余数:
下一步,我们迭代分割/碎片。我们为每个分割创建一个新的文件和 writer,相应地更新文件名。命名遵循{输出目录} {当前碎片数} _ {碎片总数} {文件名}。
对于每一个碎片,我们创建一个临时计数来跟踪我们存储在其中的所有元素。通过计算split _ numberxmax _ files+current _ shard _ count来确定下一个{image,label}对。对于我们的第一个碎片,索引将从 0 到 9;对于第二个碎片,索引将从 10 到 19,依此类推。如果索引等于元素的数量,我们只需打破循环:
准备好索引后,我们可以从相应的数组中获取图像和标签。我们重用了之前编写的 parse_single_image 函数,因为我们只改变了数据集的维度,而没有改变布局。下一步,我们将返回的示例对象写入 TFRecord 文件。最后,我们增加当前和全局计数器;最后,关闭我们的 writer:
和前面一样,我们可以通过一个函数调用来创建 TFRecord 文件:
打印语句的输出是
Using 17 shard(s) for 500 files, with up to 30 samples per shard
100%|██████████| 17/17 [00:03<00:00, 5.07it/s]
Wrote 500 elements to TFRecord
类似于我们的小数据集,我们可以从磁盘中提取较大的文件。因为我们没有改变存储的键,所以我们重用了我们的 parse_tfr_element() 方法。唯一的区别是我们有多个 TFRecord 文件,而不是只有一个。我们可以通过获取符合某个模式的所有文件的列表来处理这个问题;我们简单地搜索所有包含字符串 large_images 的 TFRecord 文件:
我们可以用下面的代码获取一个数据集并查询一个元素:
输出是预期的,一个图像的形状是(400,750,3),标签是一个标量,没有形状:
(400, 750, 3)
()
这标志着将较大的图像数据集解析为多个 TFRecord 文件并获取数据的工作已经结束。在下一节中,我们将讨论存储音频数据。
音频数据
照片由 Alexey Ruban 在 Unsplash 上拍摄
音频是第二种常用的数据类型;有各种各样的大型数据集可用。Christopher Dossman 列出了超过 1 TB 的音频数据——这只是更大的公开数据中的一部分:
对于本节,我们不会从一开始就处理 TBs。相反,我们将关注一个更小的数据集。
让我们从创建它开始,我们需要 librosa 包来完成它。我们使用 librosa 提供的示例文件,并分配一些人工标签。对于每个样本,我们存储原始音频和采样速率:
正如我们之前所做的,我们编写了一个简短的方法来帮助我们将数据放入 TFRecord 文件。因为我们将音频数据和采样率打包到一个公共数组中,所以我们必须简单地查询条目:第一个条目是音频数据,第二个条目保存采样率。
有了这些,我们就可以创建并返回一个示例对象。这里没有什么完全新的东西;方法与之前类似:
前面的函数返回一个样本,准备写入 TFRecord。下一个函数遍历所有样本,并将它们写入磁盘:
然后我们简单地调用
将我们完整的音频数据集写入磁盘。
将它存储在一个文件中,我们可以像以前一样继续:我们编写一个函数,它与向 TFRecord 编写示例的过程相反,而是读取它。这与我们用来解析图像的函数非常相似;只有键有不同的名称:
和前面一样,要创建数据集,我们只需将这个解析函数应用于 TFRecord 文件中的每个元素:
为了查询我们的数据集,我们调用这个函数并检查第一个元素:
输出是
(117601,)
tf.Tensor(0, shape=(), dtype=int64)
第一个条目是音频文件的形状;第二个条目是相应的标签。
这标志着音频数据和 TFRecord 文件工作的结束。在下一节中,我们来看看如何处理文本数据。
文本数据
作为最后一个大域,我们有文本数据。考虑到 NLP 研究在过去三、四年中的成功——变形金刚[3]、GPT [4]、…这就不足为奇了。
我们首先创建一个虚拟数据集:
然后,我们创建数据集并查询前五个元素:
这给了我们
['Hey, this is a sample text. We can use many different symbols.',
'A point is exactly what the folks think of it; after Gauss.',
'Hey, this is a sample text. We can use many different symbols.',
'A point is exactly what the folks think of it; after Gauss.',
'Hey, this is a sample text. We can use many different symbols.']
现在我们编写一个函数,从文本数据中创建一个示例对象。过程和前面一样:我们将非标量数据存储为字节特征,将标签存储为标量。
使用下一个函数,我们迭代文本数据集和标签,并将它们写入单个 TFRecord 文件:
将我们的人工文本数据集放到磁盘上只需一个简单的调用:
在下一个函数中,我们反转这个过程,从 TFRecord 文件中获取数据。一个显著的区别是,我们希望我们的特征——文本数据——是字符串类型;因此,我们将 out_type 参数设置为 tf.string :
和以前一样,我们将每个元素都映射到这个函数:
然后我们得到一个数据集,并期待前两个元素:
输出是
b'Hey, this is a sample text. We can use many different symbols.'
tf.Tensor(0, shape=(), dtype=int64)
b'A point is exactly what the folks think of it; after Gauss.'
tf.Tensor(1, shape=(), dtype=int64)
这标志着在 TFRecord 文件的上下文中写入和读取音频数据的结束。在下一节中,我们将合并所有以前的域。
多种数据类型
到目前为止,我们已经检查了单个域。当然,没有什么反对合并多个域!对于以下内容,请考虑以下大纲:
我们有多个图像:
其次,我们对每幅图像都有一个简短的描述,描述图像显示的风景:
最后,我们还有对风景的听觉描述。我们重用上面的虚拟音频数据:
现在,让我们将它们合并到 TFRecord 文件中。我们编写一个函数,接受这些数据类型并返回一个示例对象。这是 TFRecord 格式的另一个好处:即使我们处理多种数据类型,我们也可以将所有内容一起存储在一个对象中:
如前所述,我们迭代所有数据样本并将它们写入磁盘:
创建 TFRecord 文件只是一个函数调用:
既然我们已经将这样一个例子写到磁盘上,我们通过提取特征来读回它。与上一节的主要区别在于,我们有多个特征—文本、图像和音频数据—因此我们必须分别解析它们:
获得组合数据集的代码非常简单:
让我们看看数据集中的第一个元素:
输出是
(<tf.Tensor: shape=(256, 256, 3), dtype=int16, numpy=
array([[[160, 224, 213],
...
[189, 253, 65]]], dtype=int16)>,
<tf.Tensor: shape=(), dtype=string, numpy=b'This image shows a house on a cliff. The house is painted in red and brown tones.'>,<tf.Tensor: shape=(), dtype=int64, numpy=3>,<tf.Tensor: shape=(117601,), dtype=float32, numpy=
array([-1.4068224e-03, -4.4607223e-04, -4.1098078e-04, ...,
7.9623060e-06, -3.0417003e-05, 1.2765067e-05], dtype=float32)>,<tf.Tensor: shape=(), dtype=int64, numpy=0>)
第一个元素是图像,第二个元素是图像的文本描述,第三个元素是文本的标签。最后两个元素是音频数据和音频数据的标签。
这标志着关于将多种数据类型写入 TFRecord 文件的部分到此结束。
摘要
我们讨论了将图像、音频和文本数据写入 TFRecord 文件。我们还讨论了读回这些数据。
不管实际内容如何,程序总是如下:
- 为存储在 TFRecord 文件中的数据定义字典
- 解析数据时,通过复制该字典来重建数据
- 将每个元素映射到解析函数
只有在处理大型数据集时,才需要稍加修改。在这种情况下,您必须将您的数据写入多个 TFRecord 文件,这一点我们在处理大型图像数据一节中已经介绍过。
这里有一个包含所有代码的 Colab 笔记本。
如果您有兴趣了解这种文件格式,您可以阅读我关于自定义音频数据分类的帖子。在那里,我使用 TFRecord 文件来存储我的数据集,并直接在其上训练神经网络:
文学
[1] Y. LeCun 等。,基于梯度的学习应用于文档识别 (1994),IEEE 会议录
[2] J. Deng 等,Imagenet: 大规模分层图像数据库 (2009),IEEE 计算机视觉与模式识别会议
[3] A .瓦斯瓦尼等,注意力是你所需要的全部 (2017),NIPS
[4] A .拉德福德等,通过生成性预训练提高语言理解 (2018),OpenAI
使用 QGIS 处理地理空间数据的实用指南:第 1 部分
在 Unsplash 上由 Brett Zeck 拍照
介绍
最近,我开始研究一个涉及分析地理空间数据的项目。要分析这样的数据,可视化是极其重要的一步。你可以很容易地在地图上看到几个图案。如果数据包含 100 个特征,如果我们可以绘制这些特征的地图,并查看数据是否直观地有意义,那就太好了。QGIS 是一个很好的应用程序,允许分析、编辑和可视化地理数据。在本教程的第 1 部分中,我们将学习如何使用 QGIS 来显示地图和分析地理空间数据。我们还将学习对数据进行一些基本的操作。在第 2 部分中,我将讨论一些复杂的操作以及如何使用 geopandas 来操作地理空间数据。
地理数据和 QGIS 简介
地理数据包含一个几何组件,为数据在地图上提供一个位置。几何可以是不同的类型,如点/多点、线/多线和多边形/多边形。
QGIS 是一个免费的地理信息系统应用程序,支持查看、编辑和分析地理空间数据。
你可以从这里下载 QGIS。
shapefiles 有不同的格式,如。shp,。kml,。kmz,。geojson 等。你可以在这里查看所有格式:https://gisgeography.com/gis-formats/
对于本教程,我将使用一个**。来自 SEDAC 网站的 shp** 格式 shapefile。
SEDAC 是社会经济数据和应用中心。它是美国国家航空航天局(NASA)地球观测系统数据和信息系统(EOSDIS)的分布式主动档案中心(DAACs)之一。SEDAC 专注于人类在环境中的互动。
我将使用印度北方邦的村级 shapefile。它包含村庄一级的社会经济特征。你可以从这里下载。
在 QGIS 上加载/显示数据
首先,打开 QGIS 应用程序。点击“新建空项目”。您可以选择:项目->-另存为选项来保存项目。
A.加载 Shapefile 数据
要加载 shapefile,请执行以下步骤:
- 图层->添加矢量图层。
- 选择。shp 文件或选择 shapefile 所在的目录。现在,点击添加。
现在,您可以查看 shapefile。
第一步
第二步
Shapefile 的视图
要查看有关 shapefile 的信息:
- 右键单击左窗格中的 shapefile 名称。
- 点击属性->信息。在这里你可以看到关于 shapefile 的所有细节。
Shapefile 信息
B .修复几何图形(可选)
有时,shapefile 包含无效的几何。当我们试图在 shapefile 上执行一些操作时,它会给出错误“无效几何图形”。要修复几何图形,请执行以下步骤:
- 从菜单栏中,转到处理->工具箱->修复几何。选择您的形状文件。
2.点击运行
3.现在,将创建一个新的 shapefile。如果某些几何图形无效,它将修复这些几何图形。
几何图形固定的 Shapefile
我们将继续我们在这个新的形状文件上的工作。如果旧的 shapefile 没有无效的几何图形,您也可以使用它。但是,我已经知道这个 shapefile 有一些无效的几何图形。而且,它会在以后产生一些问题。
C.查看数据属性
现在,shapefile 已加载。但是我们如何知道 shapefile 中有哪些变量/属性呢?要查看属性:
- 右键单击左窗格中的 shapefile 名称。
- 点击“打开属性表”。
现在,您可以看到数据中存在的所有属性。
第一步
属性表
D.在地图上显示数据属性
让我们在地图上显示 shapefile 中的特定属性。属性可以有两种类型:离散/分类变量或连续值。
以下是实现这一点的步骤:
- 右键单击左侧窗格中的 shapefile 名称。
- 点击属性。
- 现在,点击符号。
- 在顶部,单击下拉菜单。你会看到诸如单一符号、分类、分级等选项。
5.要显示分类属性,请单击分类。
6.在它下面,有一个名为“值”的选项来选择属性。
7.我们将选择“DID ”,这是唯一的地区 ID。
8.现在,在左下角,点击“分类”。按“确定”。
您将看到类似下图的内容。
在地图上显示分类属性
9.要显示连续值,请遵循上述相同的步骤。但是,点击“毕业”,而不是“分类”。
10.现在,在“值”中,选择属性“TOT_P ”,这是总人口。
11.现在,在左下角,有一个叫做“模式”的按钮。它使用特定的模式将连续变量划分为不同的区间,如等计数、等区间、对数标度、自然突变等。
12.我们将使用“自然休息”。Natural Breaks 试图找到数据的自然分组来创建类。
13.在右下角,有一个名为“Classes”的参数。它会将变量划分为用户指定数量的区间。我们将创建 15 个类。
14.现在,点击分类。
你会看到这样的东西。
在地图上显示分级/连续属性
使用 QGIS 操作数据
我们可以使用 QGIS 执行许多操作。例如:将多边形转换为质心,基于特定属性溶解边界等。我们将在这里看到一些操作。
A.按特定属性融合几何
shapefile 中的所有几何图形都使用多边形显示。此 shapefile 还包含村庄边界。但是,如果我们想要合并每个区内的所有边界,并且只保留区边界,该怎么办呢?“溶解”操作正是这样做的。它将融合区域内的所有边界/多边形,并从中创建一个单独的区域/多边形。以下是融合边界的步骤:
- 转到矢量->地理处理工具->融合
- 现在,有一个选项融合领域。我们希望分解一个区内的所有内容,而“DID”变量是唯一的区 ID。所以,我们将通过属性“DID”来溶解。
- 在溶解属性中选择“DID”后,点击“运行”。
你会看到这样的东西-
溶解的几何图形形状文件
B.将多边形转换为质心
也可以将多边形转换为质心。我们将把这个“溶解”的 shapefile 转换成质心。
- 转到矢量->几何工具->质心
- 选择文件“溶解”并点击“运行”。
您将看到类似这样的内容:
生成质心
在 shapefile 上显示街道地图
您也可以在“溶解”的 shapefile 上显示街道地图。
- 首先,在左窗格底部,点击“浏览器”。
- 现在,在众多选项中,双击“OpenStreetMap”。
- 现在,在左窗格底部,再次点击“层”。而且,你会看到一个新的层被称为“OpenStreetMap”
开放街道地图
4.为了将溶解的地图叠加在街道地图上,勾选两个图层。然后,拖动“溶解”层以上的“OpenStreetMap”层。
5.但是,我们看不到 shapefile 后面的地图。这是因为图层的不透明度默认为 100%。我们可以设置图层的不透明度为 50%。
6.现在,右键单击溶解层。
7.转到属性->不透明度。
8.设置不透明度为 50%,点击“确定”。
现在,我们可以看到两层。您也可以放大以获得更好的视图。“放大镜”选项位于底部中间。
查看打开的街道地图以及其他 shapefile
保存形状文件
现在,让我们保存质心文件。要保存 shapefile,请按照下列步骤操作。
- 在左侧窗格中,右键单击一个特定的文件(此处为“质心”)。
- 点击导出->功能另存为。
3.现在,编写所需的输出文件名。您也可以通过选中/取消选中属性旁边的框来选择要保存的属性。
4.最后,单击确定。并且,您的文件被保存。
结论
这是针对初学者的关于如何使用 QGIS 处理地理空间数据的基础教程。现在,您知道了如何将数据加载到 QGIS 中并进行分析。我们还对数据做了一些基本的处理。我希望它对你有帮助。
后续步骤
在本文的第 2 部分,我将尝试使用 QGIS 介绍一些复杂的操作。我将讨论如何使用 geopandas 和 python 来读取和操作 shapefiles。
我希望这篇文章对你有用。
让我知道,如果你有一些关于 QGIS 的其他问题,需要帮助。我将在以后的文章中尝试介绍它们。
**非常感谢您的阅读!🙂
参考
https://earthdata.nasa.gov/eosdis/daacs/sedac https://sedac.ciesin.columbia.edu/data/set/india-india-village-level-geospatial-socio-econ-1991-2001/data-download
9 种回归算法的实用介绍
有效使用不同回归算法的实践教程
线性回归通常是人们学习机器学习和数据科学的第一个算法。它简单易懂,但是,由于其功能有限,它不太可能是真实世界数据的最佳选择。最常见的是,线性回归被用作基线模型来评估和比较研究中的新方法。
在处理现实问题时,您应该知道并尝试许多其他回归算法。在本文中,您将通过使用 Scikit-learn 和 XGBoost 的实践来学习 9 种流行的回归算法。这篇文章的结构如下:
- 线性回归
- 多项式回归
- 简单向量回归
- 决策树回归
- 随机森林回归
- 套索回归
- 里脊回归
- 弹性网络回归
- XGBoost 回归
请查看笔记本获取源代码。更多教程可从 Github Repo 获得。
1.线性回归
线性回归通常是人们学习机器学习和数据科学的第一个算法。线性回归是一种线性模型,假设输入变量(X
)和单个输出变量(y
)之间存在线性关系。一般来说,有两种情况:
- 单变量线性回归:模拟一个 单输入变量(单特征变量)和一个单输出变量之间的关系。
- 多元线性回归(也称多元线性回归):模拟多输入变量(多特征变量)和单输出变量之间的关系。
这种算法非常常见,以至于 Scikit-learn 在LinearRegression()
中内置了这种功能。让我们创建一个LinearRegression
对象,并使其适合训练数据:
from sklearn.linear_model import LinearRegression# Creating and Training the Model
linear_regressor = **LinearRegression()**
linear_regressor**.fit(X, y)**
一旦训练完成,我们可以检查LinearRegression
在coef_
属性中找到的系数参数:
linear_regressor.**coef_**array([[-0.15784473]])
现在,用这个模型为训练数据拟合一条线
sci kit-学习线性回归(图片由作者提供)
关于线性回归的几个要点:
- 快速且易于建模
- 当要建模的关系不是非常复杂,并且您没有大量数据时,这尤其有用。
- 非常直观的理解和解读。
- 它对异常值非常敏感。
2.多项式回归
多项式回归是我们想要为非线性可分数据创建模型时最流行的选择之一。这就像线性回归,但使用变量X
和y
之间的关系来找到绘制符合数据点的曲线的最佳方式。
对于多项式回归,一些自变量的幂大于 1。例如,我们可以提出如下的二次模型:
二次模型(作者图片)
β_0
、β_1
和β_2
是系数x
是一个变量/特征ε
是偏见
Scikit-learn 在PolynomialFeatures
中内置了这个方法。首先,我们需要生成一个由指定次数的所有多项式特征组成的特征矩阵:
from sklearn.preprocessing import PolynomialFeatures# We are simply generating the matrix for a quadratic model
poly_reg = PolynomialFeatures(**degree = 2**)
**X_poly** = **poly_reg.fit_transform(X)**
接下来,让我们创建一个LinearRegression
对象,并将其与我们刚刚生成的特征矩阵X_poly
相匹配。
# polynomial regression model
poly_reg_model = LinearRegression()
poly_reg_model.fit(**X_poly**, y)
现在采用该模型,并为训练数据X_plot
拟合一条线,如下所示:
多项式回归(作者图片)
关于多项式回归的几个要点:
- 能够对非线性可分离数据建模;线性回归做不到这一点。一般来说,它更加灵活,可以模拟一些相当复杂的关系。
- 完全控制特征变量的建模(设置哪个指数)。
- 需要精心设计。需要一些数据知识,以便选择最佳指数。
- 如果指数选择不当,容易过度拟合。
3.支持向量回归
支持向量机在分类问题中是众所周知的。在回归中使用 SVM 被称为支持向量回归 (SVR)。 Scikit-learn 在SVR()
中内置了这个方法。
在拟合 SVR 模型之前,通常的最佳实践是执行特征缩放,以便每个特征具有相似的重要性。首先,让我们用StandardScaler()
进行特征缩放:
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler# Performing feature scaling
scaled_X = StandardScaler()
scaled_y = StandardScaler()scaled_X = scaled_X.fit_transform(X)
scaled_y = scaled_y.fit_transform(y)
接下来,我们创建一个SVR
对象,将内核设置为'rbf'
,将伽玛设置为'auto'
。在这之后,我们调用fit()
来使其符合缩放的训练数据:
svr_regressor = SVR(**kernel='rbf'**, **gamma='auto'**)
svr_regressor.fit(**scaled_X, scaled_y**.ravel())
现在采用该模型,并为训练数据scaled_X
拟合一条线,如下所示:
支持向量回归(图片由作者提供)
关于支持向量回归的几个要点
- 它对异常值是鲁棒的,并且在高维空间中是有效的
- 它具有出色的泛化能力(能够恰当地适应新的、以前看不见的数据)
- 如果特征的数量远大于样本的数量,则容易过度拟合
4.决策树回归
决策树(DTs) 是一种用于分类和回归的非参数监督学习方法[1]。目标是创建一个模型,通过学习从数据特征推断的简单决策规则来预测目标变量的值。一棵树可以被看作是一个分段常数近似。
决策树回归也很常见,以至于 Scikit-learn 内置了DecisionTreeRegressor
。无需特征缩放即可创建DecisionTreeRegressor
对象,如下所示:
from sklearn.tree import DecisionTreeRegressortree_regressor = DecisionTreeRegressor(random_state = 0)
tree_regressor.**fit(X, y)**
现在采用该模型,并使其符合训练数据:
决策树回归(图片作者提供)
关于决策树的几个要点:
- 易于理解和解释。树木可以被可视化。
- 适用于分类值和连续值
- 使用 DT(即预测数据)的成本是用于训练树的数据点数量的对数
- 决策树的预测既不平滑也不连续(显示为分段常数近似,如上图所示)
5.随机森林回归
基本上,随机森林回归与决策树回归非常相似。它是一种元估计器,可以在数据集的各种子样本上拟合许多决策树,并使用平均来提高预测准确性和控制过度拟合。
随机森林回归器在回归中的表现不一定比决策树好(虽然它通常在分类中表现更好),因为在树构造算法的本质中存在微妙的过拟合-欠拟合权衡。
随机森林回归非常普遍,以至于 Scikit-learn 将它内置于RandomForestRegressor
中。首先,我们需要创建一个具有指定数量估算器的RandomForestRegressor
对象,如下所示:
from sklearn.ensemble import **RandomForestRegressor**forest_regressor = RandomForestRegressor(
**n_estimators = 300**,
random_state = 0
)
forest_regressor.fit(X, y.ravel())
现在采用该模型,并使其符合训练数据:
随机森林回归(图片作者提供)
关于随机森林回归的几点:
- 减少决策树中的过度拟合并提高准确性
- 它也适用于分类值和连续值
- 需要大量的计算能力和资源,因为它适合多个决策树来组合它们的输出
6.套索回归
套索回归是使用收缩的线性回归的变体。收缩是数据值向中心点收缩为平均值的过程。这种类型的回归非常适合显示高度多重共线性(要素之间的高度相关性)的模型。
Scikit-learn 内置了LassoCV
。
from sklearn.linear_model import LassoCVlasso = LassoCV()
lasso.fit(X, y.ravel())
现在采用该模型,并使其符合训练数据:
拉索回归(图片由作者提供)
关于拉索回归的几点:
- 它最常用于消除自动化变量和选择特性。
- 它非常适合显示高度多重共线性(要素之间的高度相关性)的模型。
- 套索回归利用 L1 正则化
- LASSO 回归被认为比 Ridge 更好,因为它只选择一些要素,而将其他要素的系数降低到零。
7.里脊回归
岭回归与套索回归非常相似,因为两种技术都使用收缩。岭回归和套索回归都非常适合显示高度多重共线性(要素之间的高度相关性)的模型。它们之间的主要区别是 Ridge 使用 L2 正则化,这意味着没有一个系数会像 LASSO 回归中那样变为零(而是接近零)。
Scikit-learn 内置了RidgeCV
。
from sklearn.linear_model import RidgeCVridge = RidgeCV()
ridge.fit(X, y)
现在采用该模型,并使其符合训练数据:
岭回归(图片作者提供)
关于岭回归的几点:
- 它非常适合显示高度多重共线性(要素之间的高度相关性)的模型。
- 岭回归使用 L2 正则化。贡献较小的特征将具有接近零的系数。
- 由于 L2 正则化的性质,岭回归被认为比拉索差
8.弹性网络回归
ElasticNet 是另一个用 L1 和 L2 正则化训练的线性回归模型。它是套索和岭回归技术的混合,因此也非常适合显示严重多重共线性(要素之间的严重相关性)的模型。
在套索和脊之间进行权衡的一个实际优势是,它允许弹性网在旋转下继承脊的一些稳定性[2]。
Scikit-learn 内置了ElasticNetCV
。
from sklearn.linear_model import ElasticNetCV
elasticNet = ElasticNetCV()
elasticNet.fit(X, y.ravel())
现在采用该模型,并使其符合训练数据:
ElasticNet 回归(图片由作者提供)
关于 ElasticNet 回归的几个要点:
- ElasticNet 总是优于 LASSO 和 Ridge,因为它解决了这两种算法的缺点
- ElasticNet 带来了确定最优解的两个 lambda 值的额外开销。
9.XGBoost 回归
极限梯度提升 ( XGBoost )是梯度提升算法的一种高效且有效的实现。梯度提升是指一类集成机器学习算法,可用于分类或回归问题。
XGBoost 是一个开源库,最初由陈天琦在他 2016 年题为“ XGBoost:一个可扩展的树增强系统”的论文中开发。该算法被设计成计算效率高且高效。
如果尚未安装 XGBoost 库,第一步是安装它。
pip install xgboost
XGBoost 模型可以通过创建一个XGBRegressor
的实例来定义:
from xgboost import XGBRegressor
# create an xgboost regression model
model = **XGBRegressor(
n_estimators=1000,
max_depth=7,
eta=0.1,
subsample=0.7,
colsample_bytree=0.8,
)**model.fit(X, y)
**n_estimators**
:集合中的树的数量,经常增加直到看不到进一步的改进。**max_depth**
:每棵树的最大深度,通常取值在 1 到 10 之间。**eta**
:用于加权每个模型的学习率,通常设置为 0.3、0.1、0.01 或更小的小值。**subsample**
:每棵树使用的样本数,设置为 0-1 之间的值,通常为 1.0 表示使用所有样本。**colsample_bytree**
:每个树中使用的特征(列)的数量,设置为 0 到 1 之间的值,通常为 1.0 以使用所有特征。
现在采用该模型,并使其符合训练数据:
XGBoost 回归(图片由作者提供)
关于 XGBoost 的几点:
- XGBoost 在稀疏和非结构化数据上表现不佳。
- 该算法被设计为计算效率高且高效,但是对于大数据集来说,训练时间仍然相当长
- 它对异常值很敏感
结论
在本文中,我们通过使用 Scikit-learn 和 XGBoost 的实践,介绍了 9 种流行的回归算法。在您的工具箱中拥有它们是很好的,这样您就可以尝试不同的算法,并为现实世界的问题找到最佳的回归模型。
我希望你喜欢这篇文章,并学到一些新的有用的东西。
感谢阅读。请查看笔记本获取源代码,如果你对机器学习的实用方面感兴趣,请继续关注。更多教程可从 Github Repo 获得。
参考文献:
- [1]sci kit-学习决策树文档:https://scikit-learn.org/stable/modules/tree.html#tree
- [2] Scikit-Learn ElasticNet 文档:https://sci kit-Learn . org/stable/modules/linear _ model . html # elastic-net
网格搜索、随机搜索和贝叶斯搜索的实用介绍
在机器学习中有效使用超参数调整的实践教程
在机器学习中,超参数是指无法从数据中学习到,需要在训练前提供的参数。机器学习模型的性能在很大程度上依赖于找到最优的超参数集。
超参数调整基本上是指调整模型的超参数,这基本上是一个长度过程。在本文中,您将学习 3 种最流行的超参数调优技术:网格搜索、随机搜索和贝叶斯搜索。这篇文章的结构如下:
- 获取和准备数据
- 网格搜索
- 随机搜索
- 贝叶斯搜索
- 结论
请查看笔记本获取源代码。更多教程可以从 Github Repo 获得。
1.获取和准备数据
为了进行演示,我们将使用来自 Scikit Learn 的内置乳腺癌数据来训练一个支持向量分类器 (SVC)。我们可以用load_breast_cancer
函数得到数据:
from sklearn.datasets import **load_breast_cancer****cancer = load_breast_cancer()**
接下来,让我们为特性和目标标签创建df_X
和df_y
,如下所示:
# Features
df_X = pd.DataFrame(cancer['data'], columns=cancer['feature_names'])# Target label
df_y = pd.DataFrame(cancer['target'], columns=['Cancer'])
另外,如果你想了解更多关于数据集的信息,你可以运行print(cancer['DESCR'])
来打印出概要和特性信息。
之后,让我们使用training_test_split()
将数据集分成训练集(70%)和测试集(30%):
# Train test split
from sklearn.model_selection import train_test_split
import numpy as npX_train, X_test, y_train, y_test = train_test_split(df_X, np.ravel(df_y), test_size=0.3)
我们将训练一个支持向量分类器 (SVC)模型。正则化参数C
和核系数gamma
是 SVC 中两个最重要的超参数:
- 正则化参数
C
决定正则化的强度。 - 内核系数
gamma
控制内核的宽度。SVC 默认使用径向基函数(RBF) 核(也称为高斯核)。
我们将在下面的教程中调整这两个参数。
2.网格搜索
很难找到C
和gamma
的最佳值。最简单的解决方案是尝试多种组合,看看哪种效果最好。这种创建参数“网格”并尝试所有可能组合的想法被称为网格搜索。
网格搜索——尝试所有可能的组合(图片由作者提供)
这种方法很常见,Scikit-learn 在GridSearchCV
中内置了这种功能。CV 代表交叉验证,这是另一种评估和改进我们的机器学习模型的技术。
GridSearchCV
采用描述应该尝试的参数的字典和要训练的模型。参数网格被定义为一个字典,其中键是参数,值是要测试的设置。让我们首先定义我们的候选人C
和gamma
如下:
param_grid = {
'C': [0.1, 1, 10, 100, 1000],
'gamma': [1, 0.1, 0.01, 0.001, 0.0001]
}
接下来,让我们创建一个GridSearchCV
对象,并使其适合训练数据。
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVCgrid = **GridSearchCV(SVC(), param_grid, refit=True, verbose=3)**
grid.**fit(X_train,y_train)**
作者图片
一旦训练完成,我们可以检查GridSearchCV
在best_params_
属性中找到的最佳参数,以及best_estimator_
属性中的最佳估计器:
# Find the best paramters
>>> **grid.best_params_**{'C': 1, 'gamma': 0.0001}# Find the best estimator
>>> **grid.best_estimator_**SVC(C=1, gamma=0.0001)
现在,利用这个网格模型,使用测试集创建一些预测,并为它们创建分类报告和混淆矩阵。
3.随机搜索
网格搜索尝试超参数的所有组合,因此增加了计算的时间复杂度,并且可能导致不可行的计算成本。提供了一个更便宜的选择,随机搜索只测试你选择的元组。超参数值的选择是完全随机的。
随机搜索尝试随机组合(作者图片)
这种方法也很常见,Scikit-learn 在RandomizedSearchCV
中内置了这种功能。函数 API 和GridSearchCV
很像。
首先,让我们指定参数C
& gamma
和样本分布如下:
import scipy.stats as stats
from sklearn.utils.fixes import loguniform# Specify parameters and distributions to sample from
param_dist = {
'C': **stats.uniform(0.1, 1e4)**,
'gamma': **loguniform(1e-6, 1e+1)**,
}
接下来,让我们用参数n_iter_search
创建一个RandomizedSearchCV
对象,并使其适合训练数据。
**n_iter_search = 20**
random_search = **RandomizedSearchCV**(
SVC(),
param_distributions=param_dist,
**n_iter=n_iter_search,**
refit=True,
verbose=3
)
**random_search.fit(X_train, y_train)**
RandomizedSearchCV fit()输出示例(图片由作者提供)
类似地,一旦训练完成,我们可以检查由best_params_
属性中的RandomizedSearchCV
找到的最佳参数,以及在best_estimator_
属性中的最佳估计器:
>>> **random_search.best_params_**{'C': 559.3412579902997, 'gamma': 0.00022332416796205752}>>> **random_search.best_estimator_**SVC(C=559.3412579902997, gamma=0.00022332416796205752)
最后,我们采用随机搜索模型,使用测试集创建一些预测,并为它们创建分类报告和混淆矩阵。
预测随机搜索并创建报告(图片由作者提供)
4.贝叶斯搜索
贝叶斯搜索使用贝叶斯优化技术来模拟搜索空间,以尽快达到优化的参数值。它利用搜索空间的结构来优化搜索时间。贝叶斯搜索方法使用过去的评估结果对最有可能给出更好结果的新候选人进行采样(如下图所示)。
贝叶斯搜索(作者图片)
Scikit-Optimize 库附带 BayesSearchCV 实现。
首先,让我们如下指定参数C
& gamma
和样本分布:
from skopt import BayesSearchCV
# parameter ranges are specified by one of below
from skopt.space import Real, Categorical, Integersearch_spaces = {
'C': **Real(0.1, 1e+4)**,
'gamma': **Real(1e-6, 1e+1, 'log-uniform')**,
}
接下来,让我们用参数n_iter_search
创建一个BayesSearchCV
对象,并使其适合训练数据。
n_iter_search = 20
bayes_search = BayesSearchCV(
SVC(),
search_spaces,
n_iter=n_iter_search,
cv=5,
verbose=3
)
bayes_search.fit(X_train, y_train)
作者图片
类似地,一旦训练完成,我们可以检查BayesSearchCV
在best_params_
属性中找到的最佳参数,以及best_estimator_
属性中的最佳估计器:
>>> **bayes_search.best_params_**OrderedDict([('C', 0.25624177419852506), ('gamma', 0.00016576008531229226)])>>> **bayes_search.best_estimator_**SVC(C=0.25624177419852506, gamma=0.00016576008531229226)
最后,我们采用贝叶斯搜索模型,使用测试集创建一些预测,并为它们创建分类报告和混淆矩阵。
作者图片
5.结论
在本文中,我们讨论了 3 种最流行的超参数优化技术,这些技术用于获得优化的超参数集,从而训练一个健壮的机器学习模型。
一般来说,如果组合的数量足够有限,我们可以使用网格搜索技术。但是当组合的数量增加时,我们应该尝试随机搜索或贝叶斯搜索,因为它们计算量不大。
希望这篇文章能帮助你节省学习机器学习的时间。我建议你去看看他们的 APIs,2]并了解你可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。
参考文献:
- [1]sci kit-Learn docs:https://sci kit-Learn . org/stable/auto _ examples/model _ selection/plot _ randomized _ search . html
- [2]sci kit-Optimize docs:https://sci kit-Optimize . github . io/stable/modules/generated/skopt。BayesSearchCV.html
熊猫系列实用介绍
你所需要知道的熊猫系列——数据框架的基本构件。
熊猫系列实用介绍(作者使用canva.com图片)
数据帧和系列是 Pandas 中的两个核心数据结构。 DataFrame 是带有行和列的二维标签数据。它就像一个电子表格或 SQL 表。系列是一维标签数组。这有点像 Python 列表的更强大版本。理解序列非常重要,不仅因为它是核心数据结构之一,还因为它是数据帧的构建块。
在本文中,您将学习 Pandas 系列最常用的数据操作,并且应该可以帮助您开始使用 Pandas。这篇文章的结构如下:
- 创建系列
- 检索元素
- 属性(常用)
- 方法(常用)
- 使用 Python 内置函数
源代码请查看笔记本。
1.创建系列
1.1 来自 Python 列表
Python 列表可以传递给 Pandas Series()
函数来创建一个系列。
companies = ['Google', 'Microsoft', 'Facebook', 'Apple']pd.Series(companies)0 Google
1 Microsoft
2 Facebook
3 Apple
dtype: **object**
注意事项:
- 所有值的显示顺序与它们在原始 Python 列表中的显示顺序完全相同。
dtype
表示对象(是字符串的内部熊猫行话)。- 还有一个额外的列叫做索引。在这种情况下,它类似于 Python 列表中的索引。但是 Pandas 系列的一个主要优点是索引标签不必是数字,它们可以是任何数据类型。
我们可以使用参数index
来指定一个自定义索引:
# Pass number
pd.Series(companies,**index=[100,101,102,103]**)**100** Google
**101** Microsoft
**102** Facebook
**103** Apple
dtype: object # Pass string
pd.Series(companies,**index=['GOOGL','MSFT','FB','AAPL']**)
**GOOGL** Google
**MSFT** Microsoft
**FB** Facebook
**AAPL** Apple
dtype: object
1.2 来自字典
一个字典可以传递给熊猫Series()
函数。如果没有指定index
,字典键将按照排序的顺序构造索引。
companies = {
**'a': 'Google',
'b': 'Microsoft',
'c': 'Facebook',
'd': 'Apple'**
}
pd.Series(companies)**a Google
b Microsoft
c Facebook
d Apple**
dtype: object
如果指定了index
,则index
中标签对应的数据中的值将被取出。
pd.Series(
companies,
**index=['a', 'b', 'd']**
)**a** Google
**b** Microsoft
**d** Apple
dtype: object
1.3 从标量
如果输入是标量值,那么必须提供参数index
。该值将被重复以匹配index
的长度:
pd.Series(**10**, index=[100, 101, 102, 103])100 10
101 10
102 10
103 10
dtype: int64
1.4 来自熊猫的read_csv()
功能
默认情况下,Pandas read_csv()
函数将数据作为数据帧导入。它将整个数据集加载到内存中,当导入一个巨大的 CSV 文件时,这可能是一个内存和性能问题。
pd.read_csv('data.csv')
pd.read_csv(‘data.csv’)
结果(图片由作者提供)
如果我们想将数据导入到系列中,而不是数据帧,我们可以提供额外的参数usecols
和squeeze
。squeeze=True
将一列的数据帧转换成一个序列。
pd.read_csv('data.csv', **usecols=['product']**, **squeeze=True**)0 A
1 B
2 C
3 D
Name: product, dtype: object
请看看下面这篇关于熊猫的文章read_csv()
2.检索元素
2.1 带位置
传递索引以检索元素,例如,第一个元素。
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])s[**0**]
1
检索第一个*n*
元素,例如,前 3 个元素
s[**:3**]a 1
b 2
c 3
dtype: int64
检索最后一个n
元素。
s[**-3:**]c 3
d 4
e 5
dtype: int64
检索某个范围内的元素
s[**2:4**]c 3
d 4
dtype: int64
逐步检索元素
s[**::2**]a 1
c 3
e 5
dtype: int64
2.2 带索引标签
熊猫系列是一个一维标签数组,我们可以通过索引标签访问元素。
使用索引标签检索单个元素。
s = pd.Series([1,2,3,4,5],index = ['a','b','c','d','e'])s[**'a'**]
1
使用索引标签列表检索多个元素。
s[**['a','c','d']**]a 1
c 3
d 4
dtype: int64
3.属性
Python 中的对象有属性和方法。属性是一种我们可以用来查找信息的方式,而不需要操作或破坏任何东西。方法实际上对对象做了些什么。它可能是操纵它,或者添加值,或者用对象的值做一些计算。
熊猫系列只是 Python 对象的一种类型。在这一节中,我们将介绍熊猫系列中一些常用的属性。
我们先来创作一个熊猫系列。
companies = ['Google', 'Microsoft', 'Facebook', 'Apple']
s = pd.Series(companies)
3.1 值和索引
属性返回序列中所有值的数组。
s.**values**array(['Google', 'Microsoft', 'Facebook', 'Apple'], dtype=object)
属性返回一个RangeIndex
对象。我们可以看到它从 0 开始,到 4 结束。最后一部分叫做步长,它告诉我们它的增量是 1
s.**index**RangeIndex(start=0, stop=4, step=1)
**is_unique**
属性返回一个布尔值(True
或False
)。这是检查每个序列值是否唯一的一种非常方便的方法。
s.**is_unique**True
3.2 数据类型和大小
**dtype**
属性返回数据类型。它给了我们'O'
,它是 object 的缩写。
s.**dtype**dtype('O')
**size**
属性返回一个系列中的项目数。
s.**size**4
**shape**
属性根据元组中的列数返回行数
s.**shape**(4,)
我们还有**ndim**
属性,它是维数的缩写,一个序列总是一个一维对象
s.**ndim**1
4.方法
上面提到的方法实际上对对象做了一些事情。它可能是操纵它,或者添加值,或者用对象的值做一些计算。
4.1 显示行
head()
和tail()
方法分别返回第一行和最后一行*n*
。*n*
如果不给出任何值,默认为 5。它们对于快速验证数据很有用,例如在排序或追加行之后。
prices = [10, 5, 3, 2.5, 8, 11]
s = pd.Series(prices)s.**head()**0 10.0
1 5.0
2 3.0
3 2.5
4 8.0
dtype: float64s.**head(2)**0 10.0
1 5.0
dtype: float64s.**tail(2)**
4 8.0
5 11.0
dtype: float64
4.2 执行聚合
我们可以对mean()
、sum()
、product()
、max()
、min()
、median()
等系列进行聚合
s.**mean()**s.**sum()**s.**product()**
如果我们需要多个聚合,我们可以在一个列表中将它们传递给agg()
方法
s.**agg(['mean','sum','product'])**mean 6.583333
sum 39.500000
product 33000.000000
dtype: float64
4.3 计数值
unique()
和nunique()
方法分别返回唯一值和唯一值的数量。
s = pd.Series(['a','b','b','a','a'])**s.unique()**
array(['a', 'b'], dtype=object)**s.nunique()**
2
value_counts()
方法返回一个序列中每个唯一值出现的次数。了解数值分布的概况是很有用的。
**s.value_counts()**a 3
b 2
dtype: int64
4.4 按值或索引标签排序
sort_values()
方法根据某种标准对一个系列进行升序或降序排序。
# ascending by default
s.sort_values()# To sort it in descenting order
s.sort_values(**ascending=False**)# To modify the original series
s.sort_values(**inplace=True**)
sort_index()
方法通过索引标签对序列进行排序。它类似于sort_value()
。
# ascending by default
s.sort_index()# To sort it in descenting order
s.sort_index(**ascending=False**)# To modify the original series
s.sort_index(**inplace=True**)
4.5 处理缺失值
isna()
方法返回一个相同大小的布尔对象,指示值是否丢失。
s = pd.Series([1, 2, 3, np.nan, np.nan])
**s.isna()**0 False
1 False
2 False
3 True
4 True
dtype: bool
我们可以通过用sum()
方法链接结果来计算缺失值的数量。
**s.isna().sum()**
2
count()
方法返回序列中非缺失值的个数。
s.count()
3
4.6 搜索值
nlargest()
和nsmallest()
方法返回序列中的最大值和最小值。默认情况下,如果您不给出任何值,它将显示 5 个结果。
s.**nlargest()**s.**nlargest(2)**
有一些逻辑运算符方法:
gt()
:大于ge()
:大于等于eq()
:平等le()
:小于或等于lt()
:小于ne()
:不相等
它们分别相当于>
、>=
、=
、<=
、<
和!=
,但支持用fill_value
替换缺失值。
s.le(5, **fill_value=0**) s <= 5
5.使用 Python 内置函数
len()
和type()
是针对大小和数据类型的 Python 内置函数。
**len(s)**
6**type(s)**
pandas.core.series.Series
dir()
目录的简称。如果我们向它传递一个序列,它会给出所有可用属性和方法的输出。
**dir(s)**['T',
'_AXIS_LEN',
'_AXIS_NAMES',
'_AXIS_NUMBERS',
'_AXIS_ORDERS',
'_AXIS_REVERSED',
'_AXIS_TO_AXIS_NUMBER',
'_HANDLED_TYPES',
'__abs__',
....]
要浓缩一个系列,我们可以使用内置的list()
函数。我们传递一个列表给Series()
,这是一种完全相反的操作。
**list(s)**[10.0, 5.0, 3.0, 2.5, 8.0, 11.0]
类似地,dict()
是我们向Series()
传递字典时的反向操作
**dict(s)**{0: 10.0, 1: 5.0, 2: 3.0, 3: 2.5, 4: 8.0, 5: 11.0}
Python in
关键字返回一个布尔值,将您提供的值与列表中的值进行比较。如果它存在于这些值中,它将返回True
,如果不存在,它将返回False
。
2.5 **in s**False
2.5 in s
返回False
,因为默认情况下,Pandas 将在索引标签中查找,而不是在序列中查找实际值。只需确保添加额外的values
属性:
2.5 **in s.values**True
结论
Pandas 系列是 Pandas 中的核心数据结构,也是数据框架的基本构件。本文从 5 个方面介绍了 Pandas 系列常用的数据操作。
我希望这篇文章能帮助你节省学习熊猫的时间。当然,熊猫系列有更多的属性和方法可以使用。我建议你查看一下 API 文档并了解你可以做的其他事情。
感谢阅读。请查看笔记本获取源代码,如果您对机器学习的实用方面感兴趣,请继续关注。
你可能会对我的其他一些熊猫文章感兴趣:
- 使用熊猫方法链接提高代码可读性
- 如何对熊猫数据帧进行自定义排序
- 何时使用 Pandas transform()函数
- 你应该知道的熊猫串联()招数
- Pandas 中 apply()和 transform()的区别
- 所有熊猫合并()你应该知道
- 在 Pandas 数据帧中处理日期时间
- 熊猫阅读 _csv()你应该知道的招数
- 用 Pandas read_csv()解析日期列应该知道的 4 个技巧
更多教程可以在我的 Github 上找到
数据科学家模拟建模实用介绍
几十年来,模拟一直被用于改善物流、供应链管理和制造等领域的运营。然而,今天大多数数据科学家可能并不熟悉它。在本文中,我们将使用模拟改进操作,并使用建模软件 AnyLogic 解释统计输出。
Marcin Jozwiak 在 Unsplash 上拍摄的照片
但是首先,让我们介绍一下模拟建模的世界
仿真建模是一种研究方法,旨在模拟虚拟环境中的物理系统,并从中获取有用的输出统计数据。例如,一个系统可以是一个群体、一个机场或一个货运卡车运输队。
模拟建模也用于改进分析。这通常是通过对模拟系统进行修改来完成的,以在实际投入使用之前,看看是否可以在虚拟模型中进行改进。这使得它成为决策支持和风险缓解的强大工具。总之,模拟非常适用于描述和改进系统。
在模拟建模中,有三个主要框架:
- 离散事件模拟
- 系统动力学
- 基于主体的建模(ABM)
DES 的范围很窄,主要处理流程。典型的应用领域是制造、物流和运营规划。
SD 范围更广,处理更多的聚合系统。典型的应用是人口、流行病和经济。
ABM 的范围可以有所不同,旨在研究系统中的代理如何随时间改变状态。应用范围非常广泛,并且该框架与 DES 和 SD 结合使用效果良好。
如今有许多强大的模拟软件/软件包可供数据科学家使用。其中包括 AnyLogic 、 Arena 和 Simul8 以及 python 和 R 包 SimPy 和smell。当选择一个适合你的时候,要认真考虑你正在解决的问题。较重的商业软件非常适合包含动画和验证输出,但是它通常缺乏基于脚本的包所能实现的复杂性和灵活性。
让我们进入一个简短的案例研究,看看我们如何在 DES 框架内使用模拟来改进流程。
案例研究
考虑下图中装配工厂的两步流程:
从图中我们可以看到,货物每 5 天到达一次。之后,装运被装配,装配时间正态分布为 N(6,1)。最后,组装的装运以 N(5,1)的操作时间包装,并离开系统。
乍一看,我们可以看到装配时间平均比系统的到达率长。因此,我们应该看到在装配站有一些排队等候的人。
使用流程建模库在 AnyLogic 中对此进行建模,为我们提供了以下模型:
该模型的结构由 10 个模块组成。块源和接收器是系统的起点和终点。在源之后,我们有三个模块分配给组件,同样用于包装。这三个块被称为抓住、延迟和释放。这种结构保证了当装配工和打包机的产能闲置*时,新的出货可以进入运行。*它还确保如果一个进程繁忙,在操作之前形成一个队列。
为每个流程分配一个工人,并运行模拟 180 天,我们将得到以下带有固定种子的输出:
从模拟输出中,我们可以看到 36 个装运(源块)进入系统,只有 28 个装运(接收器块)离开系统。我们还可以看到,目前有 6 批货物正在等待组装,1 批正在组装,1 批正在包装。最后,我们还可以看到,装配工人 97%的时间在忙,包装工人 60%的时间在忙。显然,装配操作是限制生产量的瓶颈。
( NB :尽管我们应该理想地运行大约 1000+次模拟来获得这些数字的有效估计,但我们将保持简单,只运行一次模拟)
因此,作为一名数据科学家,你必须弄清楚的是:
- 我们怎样才能缩短排队的时间?
- 我们怎样才能提高系统的效率?
- 我们怎样才能防止装配工人累垮呢?
让我们考虑我们可以做出的三个决定:
- 再雇一个装配工人
- 使装配操作平均快 1 天
- 两样都做 1。第二。
1。雇用另一名装配工人的产量
这个决定似乎并没有给系统增加多少价值。生产量只增加了一个单位(从 28 个增加到 29 个),装配工人似乎仍然超负荷工作,利用率高达 93%。
2。装配作业平均快 1 天的产量
这一决定增加了系统的吞吐量,出货 4 次(从 28 次增加到 32 次),但是,在这种情况下,装配工人似乎也超负荷工作,利用率为 94%。
3。双管齐下的产出 1。第二。
现在的生产量相当稳定,为 34,装配工人不像以前那样超负荷工作,利用率为 50%。有趣的是,23%的瓶颈似乎转向了包装过程。积分利用率更高!
那么这项研究的结论是什么?我们要做决定 3 吗?
——不一定。为了给出更有把握的答案,应该收集额外的数据,例如雇佣额外工人的成本、提高操作速度的成本以及将货物排队等待的成本。时间单位
该模型可以进一步扩展,以提供更强大的决策支持,这就是模拟建模的魅力所在。诸如此类的决定可以在一个无风险环境中进行实验,随着问题的进展,可以对模型进行修改。
有关本文中使用的 AnyLogic PLE 和流程建模库的更多信息,请查看以下链接:
https://www.anylogic.com/
https://www . any logic . com/features/libraries/process-modeling-library/
13 个 Python 片段中的 Matplotlib 实用摘要
Python 中基本数据可视化的基本脚本
Matplotlib 是 Python 中数据可视化的基础。为了最大限度地利用它,人们需要练习它的多种特性和功能,以便能够随意定制情节。
在本文中,我将向您展示总结 Matplotlib 基础知识的 13 个脚本
[[2021 年更新]]
如果你愿意,你可以看看我在 Youtube 上关于这个话题的视频:
用图形和轴绘制基础
import matplotlib.pyplot as plt
import numpy as npfig,axs = plt.subplots(figsize=(15,7))
data1 = np.random.normal(0,1,100)
data2 = np.random.normal(0,1,100)
data3 = np.random.normal(0,1,100)
x_ax = np.arange(0,100,10)
y_ax = np.arange(-3,3,1)
axs.plot(data1,marker="o")
axs.plot(data2,marker="*")
axs.plot(data3,marker="^")
axs.set_xticks(x_ax)
axs.set_xticklabels(labels=x_ax,rotation=45)
axs.set_yticks(y_ax)
axs.set_yticklabels(labels=y_ax,rotation=45)
axs.set_xlabel("X label")
axs.set_ylabel("Y label")
axs.set_title("Title")
axs.grid("on")
面向对象(OO)风格与 Pyplot 风格
如文档中所述,使用 Matplotlib 主要有两种方式:
- OO 风格 :显式创建图形和轴,并对其调用方法
- Pyplot 式 :依靠 Pyplot 模块自动创建和管理图形和轴。
面向对象风格
import matplotlib.pyplot as plt
import numpy as np
x = np.cos(np.linspace(0, 2, 100)) # Create the data
# Note that even in the OO-style, we use `.pyplot.figure` to create the figure.
fig, ax = plt.subplots() # Create a figure and an axes with pyplot.subplots()
ax.plot(x, x, label='linear') # Plot some data on the axes.
ax.plot(x, x**2, label='quadratic') # Plot more data on the axes...
ax.plot(x, x**3, label='cubic') # ... and some more.
ax.set_xlabel('x label') # Add an x-label to the axes.
ax.set_ylabel('y label') # Add a y-label to the axes.
ax.set_title("Simple Plot") # Add a title to the axes.
ax.legend(); # Add a legend.
Pyplot 风格
import matplotlib.pyplot as plt
import numpy as npx = np.cos(np.linspace(0, 2, 100)) # Create the data
plt.plot(x, x, label='linear') # Plot some data on the (implicit) axes.
plt.plot(x, x**2, label='quadratic') # same pipeline but using pyplot.plot directly
plt.plot(x, x**3, label='cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend();
何时使用面向对象风格还是 pyplot 风格
Matplotlib 文档中的例子使用了这两种方法,但是强调最好选择其中一种并坚持使用。建议是 将 pyplot 限制为交互式绘图(例如,在 Jupyter 笔记本中),并且对于非交互式绘图 更喜欢 OO 风格。
Matplotlib 图的推荐函数签名
# source: https://matplotlib.org/stable/tutorials/introductory/usage.html#sphx-glr-tutorials-introductory-usage-pyimport matplotlib.pyplot as plt
import numpy as npdef my_plotter(ax, data1, data2, param_dict):
"""
A helper function to make a graph
Parameters
----------
ax : Axes
The axes to draw to
data1 : array
The x data
data2 : array
The y data
param_dict : dict
Dictionary of kwargs to pass to ax.plot
Returns
-------
out : list
list of artists added
"""
out = ax.plot(data1, data2, **param_dict)
return out
data1, data2, data3, data4 = np.random.randn(4, 100)
fig, ax = plt.subplots(1, 1)
my_plotter(ax, data1, data2, {'marker': 'x'})
# 2 sub-plots example
fig, (ax1, ax2) = plt.subplots(1, 2)
my_plotter(ax1, data1, data2, {'marker': 'x'})
my_plotter(ax2, data3, data4, {'marker': 'o'});
格式化您的绘图样式
import matplotlib.pyplot as plt
import numpy as np
t = np.sin(np.linspace(-3,3,50))
# red dashes, blue squares and green triangles
plt.plot(t, t, 'r--', color="red")
plt.plot(t, t**2, 'bs', color="blue")
plt.plot(t, t**3, 'g^', color="green")
plt.plot(t, t**4, "o", color="orange")
plt.plot(t, t**5, "o-", color="black")
plt.show()
查看更多信息
使用关键字字符串绘图(来自字典)
# source: https://matplotlib.org/stable/gallery/misc/keyword_plotting.htmlimport matplotlib.pyplot as plt
import numpy as npdata = {'a': np.arange(50),
'c': np.random.randint(0, 50, 50),
'd': np.random.randn(50)}
data['b'] = data['a'] + 10 * np.random.randn(50)
data['d'] = np.abs(data['d']) * 100
plt.scatter('a', 'b', c='c', s='d', data=data)
plt.xlabel('entry a')
plt.ylabel('entry b')
plt.show()
绘制分类变量
import matplotlib.pyplot as plt
import numpy as npnames = ['cats', 'dogs', 'dragons']
values = [5, 25, 125]
plt.figure(figsize=(15, 7))
plt.subplot(131)
plt.bar(names, values, color="red", label="bar chart")
plt.legend()
plt.subplot(132)
plt.scatter(names, values, color="orange", label="scatter plot")
plt.legend()
plt.subplot(133)
plt.plot(names, values, color="green", label="line plot")
plt.legend()
plt.suptitle('Categorical Plots')
plt.show()
使用多个图形
import matplotlib.pyplot as plt
import numpy as npdef f(t):
return np.exp(-t) * np.cos(2*np.pi*t)
t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.2)
plt.figure()
plt.subplot(2,2,1)
plt.plot(t1, f(t1), 'black')
plt.subplot(2,2,2)
plt.plot(t2, np.tan(2*np.pi*t2), 'r--')
plt.subplot(2,2,3)
plt.plot(t2, np.exp(t2), 'g^')
plt.subplot(2,2,4)
plt.plot(t2, np.cos(2*np.pi*t2), 'orange');
您可以使用图形编号来创建多个图形:
import matplotlib.pyplot as plt
import numpy as npplt.figure(1)
plt.subplot(121)
plt.plot([1, 2, 3])
plt.subplot(122)
plt.plot([4, 5, 6])
plt.figure(2)
plt.subplot(121)
plt.plot([1, 2, 3],color="red")
plt.subplot(122)
plt.plot([4, 5, 6],color="red")
plt.title('It is that simple');
查看更多信息:
使用文本
Matplotlib 允许您使用文本对象在绘图中轻松编写任意放置的文本。
#source: https://matplotlib.org/stable/tutorials/introductory/pyplot.html#sphx-glr-tutorials-introductory-pyplot-pymu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)
# the histogram of the data
n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75)
plt.xlabel('Smarts')
plt.ylabel('Probability')
plt.title('Histogram of IQ')
plt.text(60, .025, r'$\mu=100,\ \sigma=15$')
plt.axis([40, 160, 0, 0.03])
plt.grid(True)
plt.show()
所有的文本函数都返回一个文本对象实例。请注意,您可以在文本中使用数学表达式,就像上面取自 Matplotlib 文档的例子一样。想法是在文本字符串中插入 latex 语法:
plt.title(r'$\sigma_i=15$')Text(0.5, 1.0, '$\\sigma_i=15$')
更多信息,请访问:
文本注释
# source: https://matplotlib.org/stable/tutorials/text/annotations.html
ax = plt.subplot()
t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = plt.plot(t, s, lw=2)
plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
arrowprops=dict(facecolor='black', shrink=0.05),
)
plt.ylim(-2, 2)
plt.show()
更多信息,请访问:
使用其他轴秤
# adapted from: https://matplotlib.org/stable/tutorials/introductory/pyplot.html#sphx-glr-tutorials-introductory-pyplot-py
# make up some data in the open interval (0, 1)
y = np.random.normal(loc=0.5, scale=0.4, size=1000)
y = y[(y > 0) & (y < 1)]
y.sort()
x = np.arange(len(y))
# plot with various axes scales
plt.figure()
# linear
plt.subplot(221)
plt.plot(x, y, color="red")
plt.yscale('linear')
plt.title('linear',color="red")
plt.grid(True)
# log
plt.subplot(222)
plt.plot(x, y, color="green")
plt.yscale('log')
plt.title('log',color="green")
plt.grid(True)
# symmetric log
plt.subplot(223)
plt.plot(x, y - y.mean(),color="blue")
plt.yscale('symlog', linthresh=0.01)
plt.title('symlog',color="blue")
plt.grid(True)
# logit
plt.subplot(224)
plt.plot(x, y, color="orange")
plt.yscale('logit')
plt.title('logit',color="orange")
plt.grid(True)
# Adjust the subplot layout, because the logit one may take more space
# than usual, due to y-tick labels like "1 - 10^{-3}"
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25,
wspace=0.35)
plt.tight_layout()
plt.show()
更多信息,请访问:
数据可视化是一门手艺
这些只是 Matplotlib 背后图形可能性的几个例子。我鼓励您进一步阅读该文档,并研究掌握 Matplotlib 的正确做法。对于那些每天使用它的人来说,我保证这是一个值得追求的目标!
本文的笔记本源代码可以在这里找到。
如果您想了解更多关于 Python 和数据可视化的知识,请查看 Udemy 的这些课程:
这些是附属链接,如果你使用它们,我会得到一小笔佣金,干杯!😃
如果你喜欢这篇文章,请在 Twitter 、 LinkedIn 、 Instagram 上联系我,并在 Medium 上关注我。谢谢,下次再见!
参考
30 个 Python 片段中的熊猫实用摘要
理解 pandas 库中主要功能的基本脚本
Pandas 是数据科学和机器学习最重要的 Python 库之一。我几乎每天都使用它,但我总是觉得我错过了有用的功能,所以我决定写一个压缩的总结来帮助指导我的熊猫技能的进步。
在本文中,我将用 30 个 Python 片段来分享 pandas 库主要功能的实用摘要。
这些功能
我们将在此介绍的功能包括:
- 使用数据框架
- 读取和写入表格数据
- 过滤数据帧中的行
- 选择特定的行和列
- 创建地块
- 从现有列创建新列
- 计算汇总统计数据
- 对表中的值进行排序
- 组合多个表中的数据
- 处理时间序列数据
- 操作文本数据
我们开始吧!
使用数据框架
让我们从从字典创建一个基本数据帧开始:
import pandas as pd
data = {"Country": ["Portugal", "USA", "France"],
"Population": [10.31*10**6, 329.5*10**6, 67.39*10**6]
}
df = pd.DataFrame(data)
df
当您使用 Python 字典创建 pandas 数据帧时,字典中的键将是数据帧的列标题,相应的值将是列。您可以在同一数据帧中存储多种数据类型。
要从 pandas 数据框架中选择一列,我们需要:
df["Country"]# Output0 Portugal
1 USA
2 France
Name: Country, dtype: object
使用方括号“[]”,这将返回一个Series
对象。
如文档中所述:
pandas 系列没有列标签,因为它只是数据帧中的一列。系列确实有行标签。
我们还可以根据 pandas 的解释检查每一列的数据类型:
df.dtypesCountry object
Population float64
dtype: object
在这种情况下,数据类型是浮点(float64
)和字符串(object
)
读取和写入表格数据
Pandas 提供了read_csv()
功能,将存储为 csv 文件的数据读入 pandas 数据帧。Pandas 支持许多不同的文件格式或现成的数据源(csv、excel、sql、json、parquet)。
df = pd.read_csv("Advertising.csv")
df
如果您想查看数据的受控子集,您可以:
df.head(8)
这里我们只显示了数据帧的前 8 行。
如果我们想要可视化数据帧的最后 8 行,我们可以:
df.tail(8)
我们还可以用熊猫轻松读取 excel 文件:
df = pd.read_excel("Advertising.xlsx")
df
您可以从数据帧中获得技术总结:
df.info()# Output<class 'pandas.core.frame.DataFrame'>
RangeIndex: 200 entries, 0 to 199
Data columns (total 4 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 TV 200 non-null float64
1 radio 200 non-null float64
2 newspaper 200 non-null float64
3 sales 200 non-null float64
dtypes: float64(4)
memory usage: 6.4 KB
这将输出关于数据帧的技术信息,如条目数、数据类型、列数、空值数等。
过滤数据帧中的行
假设我对收视率大于 100.0 的电视节目感兴趣,我如何过滤我的数据帧以获得特定的子集?
df[df["TV"]>100]
我们还可以使用条件表达式来帮助过滤。例如,假设我们有 titanic 数据集(与 Pandas 文档中使用的相同):
df = pd.read_csv("titanic.csv")
df
我们希望从 35 岁以下的幸存者那里获得信息,然后我们会使用:
survived_under_35 = df[(df["Survived"]==1) & (df["Age"]<35)]
survived_under_35
在这里,我们使用括号内的条件表达式结合这里的and
操作符作为&
来组合两个过滤语句。
如果我们只想处理特定列中非空的值,我们可以使用条件函数notna()
,它返回True
每一行的值都不是空值。
df[df["Age"].notna()]
关于条件表达式和过滤的更多信息,请参见 pandas 文档的这一部分。
选择特定的行和列
假设我想要 40 岁以上乘客的名字。因为我想要行和列的子集,仅仅使用选择括号[]
已经不够了,所以我使用了loc/iloc
操作符:
df.loc[df["Age"]>40, "Name"]6 McCarthy, Mr. Timothy J
11 Bonnell, Miss. Elizabeth
15 Hewlett, Mrs. (Mary D Kingcome)
33 Wheadon, Mr. Edward H
35 Holverson, Mr. Alexander Oskar
...
862 Swift, Mrs. Frederick Joel (Margaret Welles Ba...
865 Bystrom, Mrs. (Karolina)
871 Beckwith, Mrs. Richard Leonard (Sallie Monypeny)
873 Vander Cruyssen, Mr. Victor
879 Potter, Mrs. Thomas Jr (Lily Alexenia Wilson)
Name: Name, Length: 150, dtype: object
如文档中所述:
使用 loc/iloc 时,逗号前的部分是您想要的行,逗号后的部分是您想要选择的列。
使用列名、行标签或条件表达式时,在选择括号[]
前使用 loc 运算符。
对于逗号前后的部分,可以使用单个标签、标签列表、标签片段、条件表达式或冒号。如果您使用冒号,这意味着您想要选择所有行或列。
当您的选择基于表上的位置时,例如使用iloc.
,假设您想要 23 到 42 行和 1 到 3 列:
df.iloc[22:42, 0:3]
当使用loc|iloc
选择特定的行和/或列时,新值可以分配给所选数据。例如,将名称 anonymous 分配给第三列的前三个元素。有关选择的更多信息,请参见此处。
创建地块
df = pd.read_csv("Advertising.csv")
如果您想快速可视化数据,您可以简单地调用.plot()
方法:
df.plot();
在这里,pandas 用数字数据为每一列创建了一个单线图。如果您想得到具体的数据,您可以选择所需的列,例如,假设您只想绘制销售额:
df["sales"].plot();
如果你想评估电视/广播/报纸收视率对销售额的影响,你可以将它们一个一个地对比:
df.plot.scatter(x="TV", y="sales", alpha=0.6);
df.plot.scatter(x="radio", y="sales", alpha=0.6);
df.plot.scatter(x="newspaper", y="sales", alpha=0.6);
pandas 中有许多绘图选项,我们可以使用 Python 中内置的 dir()函数来检查它们:
for method_name in dir(df.plot):
if not method_name.startswith("_"):
print(method_name)area
bar
barh
box
density
hexbin
hist
kde
line
pie
scatter
关于熊猫的更多绘图,查看熊猫文档的这一部分。
从现有列创建新列
在 pandas 中创建新的专栏很简单。只需使用括号[]
在左侧分配新的列名,在右侧分配该列的数据:
df["Date"] = pd.date_range("1965-01-01", periods=len(df))
df
注意:这里我还使用了另一个名为 *date_range*
的 cool pandas 方法,它以 *period*
参数指定的周期从一个起点生成一个日期值列表。
但是,如果我们想从一个现有的列创建一个新的列呢?例如,假设我们有熊猫文档使用的空气质量数据集:
df = pd.read_csv("air_quality_no2.csv")
df
假设您想要检查安特卫普与伦敦的值的比率,并将结果保存为新列:
df["ratio_antwerp_london"] = (df["station_antwerp"] / df["station_london"])
df
如果您想对一列应用一个更复杂的函数,并将结果保存为 dataframe 的一个新列,您可以使用.apply()
方法。
例如,让我们对来自伦敦站的 NO2 值应用条件,其中,如果它们大于阈值,则输出将为“高”,否则为“低”:
def highLow(temp):
if temp > 24.77:
return "High"
else:
return "Low"
df["station_london_high_low"] = df["station_london"].apply(highLow)
df
使用熊猫.rename()
重命名数据列:
data = {"Name": ["John", "Mary", "Paul"],
"Age": [20,25,30],
"Occupation": ["Software Engineer", "Artist", "Product Manager"]
}
df = pd.DataFrame(data)
df_renamed = df.rename(columns={"Name":"First Name",
"Occupation": "Job"})
df_renamed
注意,我不必重命名所有的列,因为Age
列保持不变。
计算汇总统计数据
计算熊猫的统计数据非常简单:
df = pd.read_csv("titanic.csv")
print(df["Age"].mean())
print(df["Age"].max())
print(df["Age"].min())
print(df["Age"].median())29.69911764705882
80.0
0.42
28.0df.describe()
您还可以计算给定列的聚合统计信息的特定组合:
df.agg(
{
"Age": ["min", "max", "mean"],
"Parch": ["min", "max", "mean"]
}
)
.describe()
方法可以方便地加快速度:
df.describe()
它提供了表格中数字数据的快速概览。您还可以通过一行代码按类别计算值/记录的数量:
df["Pclass"].value_counts()3 491
1 216
2 184
Name: Pclass, dtype: int64
你可以在这个部分看到更多细节。
对表中的值进行排序
假设你有一个姓名和年龄的数据集:
data = {
"Name": ["Lucas", "Beatriz", "Clara", "Sara"],
"Age": [30, 26, 20, 22]
}
df = pd.DataFrame(data)
df
你想按年龄分类:
df.sort_values(by="Age")
您也可以按降序排列:
df.sort_values(by="Age", ascending=False)
组合多个表中的数据
df1 = pd.DataFrame(
{
"Name": ["Lucas", "Beatriz", "Clara", "Sara"],
"Age": [30, 26, 20, 22]
}
)
df2 = pd.DataFrame(
{
"Name": ["John", "Mary"],
"Age": [45, 38]
}
)
df_names_ages = pd.concat([df1, df2], axis=0)
df_names_ages
也可以使用共享列合并两个数据帧。
df1 = pd.DataFrame(
{
"Name": ["Lucas", "Beatriz", "Clara", "Sara"],
"Age": [30, 26, 20, 22],
"City": ["Lisbon", "Barcelona", "London", "Paris"],
}
)
df2 = pd.DataFrame(
{
"City": ["Lisbon", "Barcelona", "London", "Paris"],
"Occupation": ["Machine Learning Enginner", "Scientist", "Writer","Teacher"]
}
)
df_merged = pd.merge(df1,df2,how="left", on="City")
df_merged
在这个部分你可以了解更多关于 pandas 中的连接和合并。
处理时间序列数据
import pandas as pd
import matplotlib.pyplot as plt
假设我们有这样一个数据集:
df = pd.read_csv("typingPerformance.csv")
df
这实际上是我创建的一个数据集,用来跟踪我的触摸打字性能,以显示我在键盘上打字的速度。
这里的一个问题是“日期”列的数据类型是一个string
。我希望它是一个datetime
对象,这样我就可以对它执行标准的日期操作。Pandas 提供了一种将列转换为 datetime 对象的简单方法:
df["date"] = pd.to_datetime(df["date"])
df
现在,我们可以检查数据类型以确保它是datetime
:
df.dtypesdate datetime64[ns]
wpm object
accuracy float64
dtype: object
完美!现在我们可以用简单的表达回答问题了。比如,我什么时候开始跟踪我的打字表现?
df["date"].min()Timestamp('2021-01-14 00:00:00')
我上次练习是什么时候?
df["date"].max()Timestamp('2021-10-01 00:00:00')
我追踪了多久?
df["date"].max() - df['date'].min()Timedelta('260 days 00:00:00')
现在,我可以创建一个新列,指定一些关于日期的信息,如创建该数据点的月份:
df["month"] = df["date"].dt.month
df
现在,我可以画出每个月的平均 wpm(每分钟字数)表现:
df_monthly_performance = df.groupby("month")["wpm"].mean()df_monthly_performance.plot()
plt.ylabel("wpm");
pandas 中有大量与日期相关的功能,我建议查看文档的这一部分,以了解更多信息!
操作文本数据
data = {"Full Name": ["Mark Harrison Junior", "Mary Elisabeth"],
"Age": [40, 50]}
df = pd.DataFrame(data)
df
我们可以使用.str()
方法来处理字符串列。例如,我们可以使给定列中的所有字符串都小写:
df["Full Name"].str.lower()0 mark harrison junior
1 mary elisabeth
Name: Full Name, dtype: object
或者基于给定列的文本操作创建另一列:
df["Last Name"] = df["Full Name"].str.split(" ").str.get(-1)
df
我们可以检查字符串列是否包含某个字符串:
df["Full Name"].str.contains("Junior")0 True
1 False
Name: Full Name, dtype: bool
您可以在本部分中了解更多关于文本操作的信息。
学习熊猫
Pandas 是数据科学家和机器学习工程师最常用的 Python 库之一。它具有惊人的功能,如果掌握得当,在处理数据和加快工作流程时会有很大的帮助。
花时间以正确的方式学习 pandas,阅读文档,练习每个项目中经常出现的单个功能,我保证结果会不言自明。
如果你想了解更多关于熊猫的知识,可以看看 Udemy 的这两门课程:
(这些是附属链接,如果你使用它们,我会得到一小笔佣金,干杯!😃)
如果你喜欢这篇文章,在媒体、上关注我,订阅我的时事通讯,或者加入媒体(如果你还没有的话:)。在 Twitter 、 LinkedIn 和 Instagram 上和我联系!谢谢,下次再见!😃