轻松制作 Matplotlib 图形动画
原文:https://towardsdatascience.com/easily-animate-your-matplotlib-graphs-99b62db63697
让 Matplotlib 动画更容易理解
将数据可视化制作成动画可以增加可视化的整体深度。例如,下面的示例将时间维度添加到数据可视化中。你可以很容易地看到不同年龄组的人口随着时间的推移是如何变化的。通过动画可视化,我们可以很容易地看到趋势随时间的变化,在详细的组。
考虑到 Matplotlib 中可用选项的广度,学习如何制作图形动画似乎是一项艰巨的任务。本教程旨在解决这个问题!
请看下图,看看我们今天要创造什么:
你将学会创造什么(来源:Nik Piepenbreier)
激动吗?让我们开始吧!
你可以在这里下载数据集。它基于加拿大统计局免费提供的数据,描述了加拿大人口按年份、年龄组和性别的细分。
创建基础可视化
Matplotlib 动画通过不同的可视化效果循环工作。因此,我们可以设置一个基本的可视化,然后创建一个 for 循环,根据数据变化修改可视化。
让我们先创建一个我们满意的基础可视化:
创建我们的基础可视化
代码太多了!让我们来分析一下我们在这里做了什么:
- 我们导入了项目所需的库
- 我们使用
read_csv()
函数读入数据 - 我们应用了一些数据清理来使我们的数据达到最佳状态。我们向前填充缺失的年龄类别,将我们的人口数转换为整数,并将我们的女性人口数乘以-1,这样她们就出现在我们视觉的左侧
- 然后,我们创建了一个图形和轴对象来保存我们的可视化
- 然后,我们过滤我们的数据,使之可视化
- 然后,我们使用
barh()
函数创建两个相互叠加的可视化效果,并添加我们的值作为标签 - 最后,我们通过移除脊柱等来自定义我们的可视化。最后,我们设置一个标题来表示年份。
这将返回以下可视化结果:
您将创建的基本图像(来源:Nik Piepenbreier)
现在我们已经建立了基础,让我们创建我们的动画!
创建可视化
为了动画化我们的可视化,我们将使用FuncAnimation
类。顾名思义,这个类使用函数来创建动画。在我们进一步讨论之前,让我们看一下类的定义:
了解 FuncAnimation 类
从上面的代码块中我们可以看到,我们需要传入三个关键参数:
- 要使用的数字
- 修改图形的功能
- 对于每个帧,将什么数据传递到函数中
您已经做了大量定义图形外观的艰苦工作。很容易把它转换成一个函数!让我们看看如何做到这一点:
创建我们的动画功能
我们在上面的代码中所做的只是简单地将之前的代码转换成一个函数。该函数接受一个参数,即年份,稍后我们将使用我们的frames=
参数填充它。
这里需要注意的是,我们还在函数中添加了第一行。ax.clear()
调用清除了我们的 axes 对象,并允许我们使用函数重新创建它。
把所有的放在一起
让我们看看现在如何把这些放在一起。我们可以通过用我们的轴、函数和一组框架实例化它来创建一个FuncAnimation
对象。
我们可以通过创建一个捕捉最小值和最大值的范围,使我们的框架对数据是动态的:
加入我们的动画(终于!)
在上面的代码中,我们首先创建我们的动画对象。然后,我们使用PillowWriter
类将我们的动画保存为 GIF 文件。这允许我们自定义动画运行的速度。在上面的代码中,我们将其设置为每秒 5 帧。
结论
厉害!您已经创建了您的动画!创建动画数据可视化可让您以全新的方式浏览数据。在这种情况下,我们能够看到人口如何随着时间的推移而变化。添加动画并不总是一个好主意,但确实可以使数据交流更容易。
轻松自动化您的文档,再也不用碰它了
原文:https://towardsdatascience.com/easily-automate-and-never-touch-your-documentation-again-a98c91ce1b95
使用 MkDocs 的完全自动化的 Python 文档过程
作为开发人员,每个人最喜欢的方面是:维护文档化的代码,并在 GitHub 上为他们的开发伙伴托管文档。
当然,我是在开玩笑。文档常常是一项被忽视的任务,这使得新成员接管过时的代码库成为一项浪费且痛苦的任务。我们都经历过——在我之前的开发者在这里做什么?还有……这到底是怎么回事?
不会了。在 Mkdocs 、 Mkgendocs 、我写的一个自定义脚本和 GitHub 动作的帮助下,我们可以自动维护像这样的华丽文档!
第一步——确保你的代码库有谷歌风格的 python 文档串
自动化的第一步只是将 google 风格的文档字符串添加到 python 文件中。对于 atom 文本编辑器用户,我推荐使用 docblock atom 扩展来自动完成这项工作!
这一步并不是绝对必要的,但是以这种方式添加的任何文档字符串都将在接下来的步骤中被删除并添加到我们的站点中!这一步也可以在闲暇时逐步完成。您添加的文档越多,您的自动文档就越有成效!
步骤 2—安装必要的软件包
安装这两个包就这么简单!
mkgendocs==0.9.0
mkdocs==1.2.3
步骤 3——下载启动代码并将其添加到您的项目根目录中
点击下载启动代码。这提供了三个有助于自动化的文件!
mkgendocs.yaml 该文件是 python 文件(例如 main.py)到其关联的文档文件输出(例如 docs/modules/main.md)。它还包含了我们希望包含在文档中的所有类和文件的列表。我们将自动创建这个映射,以及降价文件本身。
这个文件获取我们的文档文件(例如 docs/modules/main.md),并将它们组织到站点文件夹中,以便创建站点地图。这也将由我们的脚本自动完成。
automate _ mkdocs . py——这个脚本受 Louis de Brujin 的工作的启发,但我自己针对更多情况进行了进一步的扩展和优化,填充了 mkgendocs.yaml 和 mkdocs.yaml 文件。将包括所有存在且不包含语法错误的文件。目录结构的样式将反映您的软件包文件夹的设置方式。
花点时间填写 mkgendocs.yaml 和 mkdocs.yaml 的顶部,让它们成为您的项目所独有的!
第 4 步—立即创建文档!
运行以下命令:
python automate_mkdocs.py
这将自动填充 mkdocs.yaml 和 mkgendocs.yaml 文件。
gendocs --config mkgendocs.yml
这个命令获取我们的 mkgendocs 文件,并生成我们的 markdown 文件!注意:您可能需要在根目录下创建 docs 文件夹。
我们现在可以使用以下工具测试和查看我们的文档:
mkdocs serve
当您对它在本地的外观感到满意时,我们可以用
mkdocs gh-deploy
就是这么简单!刚刚创建了一个新的分支来保存您的文档和自动生成的站点地图!如果您喜欢在每次更改文档时都运行这些命令,那么到此结束就好了,但是,我们还可以做一个进一步的优化,那就是设置 Github 操作,以便在每次我们推送到我们的主(或任何)分支时更新和部署我们的文档!
步骤 5——使用 GitHub 动作自动部署文档
如果你以前从未使用过 GitHub actions,我推荐你先熟悉一下这里的!并创建基本 yaml 文件。从那里,我们将添加命令到:
- 设置我们的 python 版本并检查我们的代码
- 安装需求并更新 mkdocs 和 mkgendocs
- 建立或更新我们的降价文件
- 部署我们的网站
- 提交可能已经发生的任何更改
- 将这些更改推送到关联的分支
这可能看起来很多,但一旦做到了,它会让生活变得容易得多!
注意:你的 GitHub actions 文件很可能是相似的,但是会根据你使用的 python 版本,选择的主题,以及你是否有额外的需求比如自定义站点或者 GitHub 推送限制而有所不同!
设置我们的 Python 版本并检查我们的代码。这相当简单!
- name: Checkout
uses: actions/checkout@v1- name: Set up Python python-version
uses: actions/setup-python@v1
with:
python-version: 3.7
安装需求并更新 mkdocs 和 mkgendocs——requirements . txt 文件应该包含项目的所有文件,包括在步骤 2 中安装的文件。
- name: Autogenerate new documentation
continue-on-error: true
run: |
pip install -r requirements.txt
python automate_mkdocs.py
git add .
构建或更新降价文件——我为安装添加了一些额外的 pip 文件,尽管这些文件可能会被排除!我个人对 jinja2 包有问题。
- name: Update and Build GH Pages
run: |
python -m pip install --upgrade pip
pip install mkdocs==1.2.3
pip install mkgendocs==0.9.0
pip install jinja2==2.11
gendocs --config mkgendocs.yml
部署我们的站点——它使用了一个非常酷的自定义 GitHub 动作,并且有大量可选参数,包括设置自定义域!
- name: deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
#CUSTOM_DOMAIN: optionaldomain.com
CONFIG_FILE: mkdocs.yml
EXTRA_PACKAGES: build-base
# GITHUB_DOMAIN: github.myenterprise.com
# REQUIREMENTS: docs/docs_requirements.txt, separate requirements file to install any themes you may want on your site
提交任何更改—我们使用“出错时继续”,因此如果没有更改,它不会失败!
- name: Commit any changes to docs
continue-on-error: true
run: |
git config --local user.name "github-actions[bot]"
git add ./docs
git commit -m "Auto-updating the docs"
推送我们的更改—注意:您可以选择将这些更改推送至哪个分支
- name: Push the changes to master
continue-on-error: true
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: master
force: true
仅此而已!一旦您解决了任何部署难题,您现在就有了一个完全自动化的文档工作流!如果这真的对你有帮助,这里有一个链接指向 mkgendocs 捐赠页面的创建者。我给他寄了一笔小小的捐款,以表达我对制作这个包裹的感激之情!
我希望这篇文章对您的文档之旅有所帮助!这篇文章是我最喜欢写的文章之一。如果您认为需要回来参考,请务必保存/标记该故事!如果你喜欢这篇文章,请随意关注我,阅读我写的更多内容,或者将我作为推荐人,这样我就可以继续制作我喜欢的内容。
轻松采用时间序列的 Theta 模型
原文:https://towardsdatascience.com/easily-employ-a-theta-model-for-time-series-b94465099a00
M4 竞赛中的最佳基准模型使用 Python 轻松训练、调整和测试
作者图片
与 ARIMA 等经典技术相比,Theta 不太为人所知,它是一种时间序列模型,可以产生准确的结果,并且易于理解和应用。如果你是时间序列从业者和预测者,这是一个很好的工具。
它的工作原理是从潜在的时间序列中提取两条“θ线”。第一条线是时间序列的线性趋势,可以通过对使用时间趋势作为输入的数据运行简单的线性回归来提取。这条θ线可以非常简单地通过无限期地继续其线性趋势而推断出未来。
第二条θ线可以看作是级数的曲率。它是系列的第二个差值乘以一个因子,默认情况下为 2。小于 1 的值抑制曲率并强调长期趋势,大于 1 的值强调曲率并强调短期趋势。通过使用指数平滑向前外推第二条θ线。
这两条θ线然后在加法或乘法过程中结合。为了说明季节性,在提取 theta 线之前,该模型还使用乘法或加法季节性分解方法对数据进行去季节性处理。在θ线合并后,这种季节性会重新应用到预测数据中。
提出这种方法的论文还提到,进一步的研究可能包括提取两条以上的θ线,但据我所知,没有这样的模型发现任何有前途的东西,但思考起来很有趣(Assimakopoulos & Nikolopoulos,2000)。
很简单吧?让我们看看如何使用 Python 来实现它。
Python 应用程序
飞镖游戏
Darts 是一个用户友好的时间序列包,它使用了一个名为 FourTheta 的 Theta 模型的实现,这是上面解释的思想的衍生物,可以对第一条 theta 线应用指数变换(而不是使用简单的线性趋势)。这款衍生车型是 2020 年 M4 竞赛中表现最佳的基准车型。
要安装省道:
pip install darts
这里有一个链接到 darts 中的模型文档。
规模预测
Scalecast 将 darts 的 theta 模型移植到一个通用的时间序列框架中,该框架易于实施,并可与其他几种经典的时间序列方法、scikit-learn 的机器学习模型以及其他技术进行比较。我将演示 theta 模型的 scalecast 实现,因为我是 scalecast 的作者,并且希望展示这个框架如何能够非常容易地为任何用户实现。也就是说,如果你想直接使用 darts 的模型,它也提供了一个用户友好和舒适的框架。
要安装 scalecast:
pip install scalecast
你可以在这里找到本文中使用的完整笔记本。数据来自 M4 竞赛的开放访问,可在 GitHub 上获得。我们将使用 H7 每小时时间序列。
代码实现
在代码中应用这个模型非常简单。我们首先将数据加载到预测器对象:
train **=** pd**.**read_csv('Hourly-train.csv',index_col**=**0)
y **=** train**.**loc['H7']**.**to_list()
current_dates **=** pd**.**date_range(
start**=**'2015-01-07 12:00',
freq**=**'H',
periods**=**len(y)
)**.**to_list()
f **=** Forecaster(y**=**y,current_dates**=**current_dates)
我们可以绘制这个系列,以便更好地了解我们在做什么:
f**.**plot()
plt**.**show()
作者图片
让我们留出 25%的数据进行测试,并预测未来的 48 个时间段:
f**.**set_test_length(.25)
f**.**generate_future_dates(48)
现在,我们可以指定一个超参数网格来找到调优该模型的最佳方式。这个网格在大多数情况下都能找到一个很好的模型,但是你也可以考虑给它增加更多的θ值。
fromdarts.utils.utils import (
SeasonalityMode,
TrendMode,
ModelMode
)theta_grid **=** {
'theta':[0.5,1,1.5,2,2.5,3],
'model_mode':[
ModelMode**.**ADDITIVE,
ModelMode**.**MULTIPLICATIVE
],
'season_mode':[
SeasonalityMode**.**MULTIPLICATIVE,
SeasonalityMode**.**ADDITIVE
],
'trend_mode':[
TrendMode**.**EXPONENTIAL,
TrendMode**.**LINEAR
],
}
现在,让我们使用三重时间序列交叉验证来寻找最佳的超参数组合。这将基于我们的训练集创建 3 个数据段,其中每个验证集的长度为 131 个观察值,并且具有所有上述超参数组合的模型根据每个验证集之前的数据进行训练。基于哪个模型返回所有褶皱的最佳平均 MAPE 值来选择最终模型。
f**.**set_validation_metric('mape')
f**.**set_estimator('theta')
f**.**ingest_grid(theta_grid)
f**.**cross_validate(k**=**3)
从交叉验证中选择的最佳参数是:
>>> f**.**best_params
{'theta': 1,
'model_mode': <ModelMode.ADDITIVE: 'additive'>,
'season_mode': <SeasonalityMode.MULTIPLICATIVE: 'multiplicative'>,
'trend_mode': <TrendMode.EXPONENTIAL: 'exponential'>}
然后,我们使用选择的模型预测我们的测试集和 48 期预测范围:
f**.**auto_forecast()
我们现在可以看到可视化的测试结果:
f**.**plot_test_set(ci**=**True)
plt**.**show()
作者图片
以及预测结果:
f**.**plot(ci**=**True)
plt**.**show()
作者图片
这返回了 5.5%的测试集 MAPE 结果。交叉验证过程中的平均验证 MAPE 为 7.5%。验证 MAPE 稍微差一点是有道理的,因为它在每次验证迭代中要学习的训练集更少。
假设一段时间过去了,我们现在有一些新的数据要引入到这个模型中,我们可以衡量它在 48 期预测中的表现。让我们看看效果如何。
test = pd.read_csv('Hourly-test.csv',index_col=0)
y_test = test.loc['H7'].to_list()
future_dates = pd.date_range(
start=max(current_dates) + pd.Timedelta(hours=1),
freq='H',
periods=len(y_test),
).to_list()fcst = f.export('lvl_fcsts')
mape = np.mean(
[np.abs((f - a) / a) for f, a in zip(fcst['theta'],y_test)]
)
这返回了 6%的值,正好在我们的测试集和验证度量之间,这正是我们所期望的!
结论
theta 模型是时间序列分析师的强大工具,概念简单,易于调整,易于评估。希望你觉得这个教程有用!如果是的话,请考虑以后使用 scalecast,为其成长做点贡献!
https://github.com/mikekeith52/scalecast
参考
动词 (verb 的缩写)Assimakopoulos,K. Nikolopoulos,theta 模型:预测的分解方法,国际预测杂志,第 16 卷,2000 年第 4 期,第 521-530 页,ISSN 0169-2070,https://doi . org/10.1016/s 0169-2070(00)00066-2。
(https://www . science direct . com/science/article/pii/s 0169207000000662)
使用 SentenceTransformers 轻松获得高质量的嵌入!
介绍向量表示的概念,并比较 TF-IDF 向量和 SentenceTransformers 向量!
图片作者。
背景
在我加入 HK01 之前,它的数据团队已经利用大量的文本数据建立了几个数据项目。虽然能够将 NLP(自然语言处理)技术应用于真实世界的数据以对业务产生影响是件好事,但我注意到这些数据项目都在使用 TF-IDF 来学习 HK01 上发布的内容的嵌入(向量表示)。这些嵌入是这些数据项目的核心,因为它们在机器学习模型中用于进行预测。这种方法有几个问题:
- 性能欠佳 虽然 TF-IDF 做得很好,但它是一种相对较老的计算文本嵌入的方法。最近有很多关于 NLP 的研究,现在变形金刚模型(例如伯特、罗伯塔、 GPT-3 )是 NLP 任务的最新模型。
- 难以维护
升级或调试效率低下,我们需要对这些项目中的每一个都进行更改。 - 高成本
由于这些数据项目中的每一个都是独立计算嵌入,因此其成本远远高于由一个集中式服务来计算全部嵌入。
我们为什么要关心这些嵌入呢?
嵌入只是一些东西的表示,可以是文本、图像,甚至是语音,通常是矢量形式。计算文本嵌入的最简单方法是使用单词袋(BOW)表示法。
假设你有很多关于你在网上销售的产品的用户评论。要获得 BOW 表示或用户评论,您需要做的就是将这些评论分解成单词。然后创建一个表格(或者更像一个矩阵),它的列是注释中的单词。索引将是用户评论的 id。该值是该单词是否出现在用户评论中。看起来是这样的:
现在每一行都是一个注释的向量表示,所以注释 ID 1 的嵌入向量是[1, 0, 1, 1, 0, ...]
。由于第一行在单词“好”、“爱”和“令人惊叹”中的值为 1,我们已经可以看出这个评论在情感方面是积极的。所以嵌入向量告诉我们注释的上下文含义。
一旦我们有了所有用户评论的嵌入,我们就可以做许多不同的事情。例如:
- 我们可以训练一个分类器来预测每个评论的情绪。
- 我们可以通过计算余弦相似度或欧氏距离来找到上下文相似的评论。
- 我们可以将评论分组,然后找到这些组中出现的最常见的单词。例如,我们可能会在聚类中找到像
'fast', 'delivery'
或'overpriced'
这样的词。这有助于我们了解需要改进什么。
想象一下,如果我们对 HK01 上发表的文章这样做,我们就可以做一些事情,比如主题建模(类似于第 3 点),推荐用户读过的类似文章(类似于第 2 点),等等!
旁注
在实践中,我们会将停用词(例如’ the ‘,’ a ‘,’ and ‘)和词干词放入它们的基本形式(例如’ flying ‘到’ fly ‘,’ cars ‘到’ car ‘,’ am ‘到’ be ')。这里不解释涉及的许多数据预处理技术。
为什么弓不够好?
在这一点上,你可能会意识到我们的向量的维数很高,这是因为用户评论中可能出现的单词数量非常大。所以每个向量在维度上可以是1x10000
甚至是1x100000
。当我们使用这些向量时,这会降低计算速度!
此外,BOW(单词袋)表示法可能不是一个很好的表示法。如果我们有两个注释,例如Exactly what I wanted! 5 stars!
和Absolutely amazed by the product! great price!
。虽然我们可以知道它们都是正面的评论,但是这两个评论的 BOW 表示没有相似之处,因为没有重叠的单词。这就是为什么我们需要更好的东西!
句子变压器
SentenceTransformers 是一个 Python 框架,用于最先进的句子、文本和图像嵌入。它的 API 使用起来非常简单:
就这么简单,这就是我们需要编码来获得任何文本的嵌入的全部内容!
[-5.09571552e-01 6.48085847e-02 7.05999061e-02 -1.10023748e-02
-2.93584824e-01 -6.55062944e-02 7.86340162e-02 1.02539763e-01
-3.80028449e-02 1.71354219e-01 1.69140086e-01 -9.65721607e-02
2.04715624e-01 3.12998295e-01 -1.77713439e-01 1.53584480e-02
9.74370390e-02 2.11779386e-01 1.24351427e-01 -1.38820678e-01
4.35955316e-01 -1.17388457e-01 -3.58339213e-02 -1.36476666e-01
... # hidden by me as it's too long :)(1, 384)
与使用 BOW 得到的 1 和 0 不同,我们得到了浮点值和固定尺寸(本例中为 1 x 384)。这是因为嵌入是从变压器模型中的隐藏层提取的,维度与该隐藏层的神经元数量相同。因为嵌入是由 transformer 模型学习的,所以前一节中的两个示例注释现在是相似的。在这篇博文中,我不打算详细讨论这个问题。现在,只需要知道转换器是一个神经网络,它的本质是可以将高维数据压缩到低维。
它在幕后做什么?
为 SentenceTransformers 做出贡献的人们在 HuggingFace 模型中心上托管许多不同的预训练的变形金刚模型。托管预训练模型已经在大量数据(100 多万甚至 1B+训练对)上进行训练,因此被称为“预训练”模型。模型看到的数据样本量如此之大,以至于我们可以简单地使用它开箱即用来获得高质量的嵌入。当 API 被调用时,它从 HuggingFace Model Hub 下载所选择的预训练模型(或者如果给定了本地路径,则下载 load)。然后,它对你的输入句子进行标记,并将它们放入模型中计算它们的嵌入。
API 极大地简化了这个过程,以至于我们不再需要为标记化编写代码,改变 PyTorch 模型类中定义的predict()
等等。如果你使用了 HuggingFace 甚至纯 PyTorch 来做这件事,你就会知道这种痛苦了。现在,它变成了一行代码!
embeddings = model.encode(sentences) # very simple, isn't it?
我的文字超级长怎么办?
考虑 SentenceTransformers 上可用的每个预训练模型的最大长度很重要。例如,paraphrase-multilingual-mpnet-base-v2
型号的最大序列长度为 128。这意味着对于任何超过 128 个标记的输入句子,都将被修剪,即只有前 128 个标记将被放入模型。想象一下,如果我们在 HK01 上发表了一篇包含数千个汉字的文章。如果我们把它放到 API 中,我们将只能得到代表前几个句子的嵌入!
克服这一点的一个简单技巧是将文章分成一系列句子,然后取句子嵌入的平均值作为文章嵌入。像这样:
虽然这听起来可能太简单,但我们发现它工作得很好。让我们在下一节看看它的表现。
旁注
正如你所看到的,理解它是如何工作的非常重要。这正是为什么即使训练机器学习模型的 API 已经简化了这么多,公司仍然需要数据科学家和机器学习工程师的原因:)!
与 TF-IDF 相比,它的性能如何?
为了了解它如何优于 TF-IDF 矢量表示,我们:
- 随机抽样 10,000 篇发表在 HK01 上的文章。
- 使用句子变形器(
paraphrase-multilingual-MiniLM-L12-v2
和平均句子嵌入)和 TF-IDF 计算它们的嵌入。对于 TF-IDF,我使用sklearn.feature_extraction.text.TfidfVectorizer
和TfidfVectorizer(analyzer='word', min_df=0.001, ngram_range=(1, 3)
来更好地捕捉汉字。 - 通过运行 t-SNE 将嵌入维数减少到 2, t-SNE 是一种降维算法,以防你不知道。
- 将文章类别映射到数据,并将结果可视化。
以下是可视化效果,您可以通过单击图例与图表进行交互以放大和过滤数据:
请注意,由于有太多不同的类别,一些不同的类别使用相同的颜色。
我们可以看到,在顶部(红色的)和底部(紫色的)周围只有一些小簇。这个中心根本没有清晰的星团。想象一下,如果我们完全没有类别,我们很难对同一主题的文章进行分组。现在让我们来看看句子变形器生成的嵌入:
请注意,由于有太多不同的类别,一些不同的类别使用相同的颜色。
At first glance, you can already see data points with the same category are sticking closer together. Not only that, categories that are somewhat related (e.g. movie (電影), games & anime (遊戲動漫) and entertainment (即時娛樂)) are also closer together at the bottom right.
想象一下,如果我们有一篇关于喜剧电影的文章,那么我们可以使用上述嵌入来找到最近的 N 个数据点,并将它们列在 HK01 上作为相关文章,最近的 N 个数据点也将与“电影”、“喜剧”或至少“娱乐”相关。
摘要
现在,我们已经看到 SentenceTransformers 非常容易使用,并且它生成高质量的嵌入。
为了克服 HK01 的问题,我们正在创建一个新项目,目的是使用 SentenceTransformers 计算 HK01 上发布的任何内容的嵌入。目前,我们正在将每一个数据源集成到这个新项目中,以建立一个 cronjob 来计算新内容或编辑内容的嵌入。我们期待看到我们的推荐系统和下游数据项目的改进!
如果你喜欢这篇博文,请点击下面按钮并鼓掌!👏🏻也在 Github 上关注我吧!
参考
- 变形金刚—https://www.sbert.net/index.html#
- TF-IDF—https://en.wikipedia.org/wiki/Tf%E2%80%93idf
- 鞠躬—https://en.wikipedia.org/wiki/Bag-of-words_model
在 pandas 和 parallel-pandas 中轻松并行计算
介绍
Pandas 是最受欢迎的数据科学图书馆之一。来自官方文档:
pandas 是一个快速、强大、灵活且易于使用的开源数据分析和操作工具,构建于 Python 编程语言之上
而每一个熟悉熊猫的人都会很有信心地证实这些话。与此同时,他们管道中的许多人面临着这样一个事实,即 pandas 没有充分利用 CPU 的能力。换句话说,pandas 方法不支持并发。
考虑一个简单的例子:
synchronous describe time took: 37.6 s.
(图片由作者提供)
从上图中可以看出,100%时只使用了一个内核。其余的无所事事。但是如果你使用所有的处理器内核呢?你能多快得到同样的结果,最重要的是——如何实现?
所以我们先想想 describe()是怎么工作的?它处理这些列,并为每个列计算一些统计数据。我们有一个包含 1000 列的数据框架。沿着第一个轴(沿着列)将我们的数据帧分成几个更小的部分,分别计算每个部分的 describe,然后将结果组合回一个公共数据帧,怎么样?让我们看看如何沿着指定的轴将数据帧分割成多个部分。这可以通过**numpy**
模块的array_split
功能轻松完成。让我们看一个简单的例子:
[ cat dog
0 0 0
1 1 1
2 2 2,
cat dog
3 3 3
4 4 4
5 5 5,
cat dog
6 6 6
7 7 7,
cat dog
8 8 8
9 9 9]
并按列拆分
[ cat
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9,
dog
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9]
因此,我们有了一个算法,可以将一个大的数据帧沿着我们需要的轴分割成更小的部分。下一步是什么?如何让我们 CPU 的所有核心都工作起来?众所周知,pandas under the hood 使用[**numpy**](https://numpy.org/doc/stable/user/whatisnumpy.html)
数组和方法来处理它们,这通常会移除全局解释器锁(GIL)。因此,我们可以使用线程池来并行计算。让我们转向[**concurrent.futures**](https://docs.python.org/3/library/concurrent.futures.html#module-concurrent.futures)
模块的ThreadPoolExecutor
类的map
方法:
map ( func , *iterables , timeout=None , chunksize=1 )
类似于[map(func, *iterables)](https://docs.python.org/3/library/functions.html#map)
除了:
1。立即收集可重复项而不是延迟收集;
2。 func 异步执行,可以并发调用几次 func 。
在我们的例子中,describe()
方法是函数,iterable 对象是数据帧列表。下面给出了实现管道的完整代码。
parallel desribe time took: 15.0 s.
(图片由作者提供)
所以我们将pandas.DataFrame.describe()
方法的速度提高了两倍!类似地,您可以并行化其他的pandas
方法。
平行熊猫简介
[**parallel-pandas**](https://pypi.org/project/parallel-pandas/)
库在本地实现了上述pandas
方法的并行化。首先,使用pip
软件包管理器安装parallel-pandas
:
pip install --upgrade parallel-pandas
只要两行就够入门了!
synchronous time took: 3.7 s.
parallel time took: 0.688 s.
如你所见,p_quantile
方法比快 5 倍!
一旦parallel-pandas
被初始化,你继续照常使用熊猫。pandas
方法的并行模拟以来自单词 parallel 的p_
为前缀。此外,parallel-pandas
允许您查看并行计算的进度。为此,在初始化期间指定disable_pr_bar=False
就足够了。
带有进度条并行描述方法
如您所见,parallel-pandas
负责将原始数据帧分割成块,并行化并为您聚合最终结果。
更复杂的计算可以以类似的方式并行化。例如,让我们对数据帧的列进行 z 规范化。同样,为了比较,我们用daskdata frame 实现 z 归一化:
synchronous z-score normalization time took: 21.7 s.
parallel z-score normalization time took: 11.7 s.
dask parallel z-score normalization time took: 12.5 s.
注意内存消耗。parallel-pandas
和dask
使用的 RAM 几乎是pandas
的一半
RAM 使用
对于某些方法,parallel-pandas 比 dask DataFrame 更快:
dask nunique time took:42.5 s.
dask rolling window mean time took: 19.8 s.
paralle-pandas nunique time took:12.5 s.
parallel-pandas rolling window mean time took: 11.8 s.
parallel-pandas
实现了许多熊猫方法。完整列表可在文档中找到。
总结一下:
- 在本文中,我们简要回顾了并行化
pandas
方法的思想,并以describe
方法为例实现了它 - 我们还熟悉了
parallel-pandas
库,它使得基本pandas
方法的并行化变得容易。 - 我们还使用几个例子将
parallel-pandas
的工作与另一个著名的分布式计算库dask
进行了比较。
希望这篇文章对你有帮助,祝你好运!
用内乌顿自动语言实现简单的机器学习
原文:https://towardsdatascience.com/easy-machine-learning-with-neuton-automl-881437a09061
内乌顿汽车公司房价数据的探索性数据分析。作者创造的形象。
在过去十年中,机器学习(ML)领域在应用科学、社会科学、商业和经济学的不同领域中的应用蓬勃发展。ML 是困难的,找到最佳算法需要用户大量的经验、精力和直觉。
由于多种因素导致 ML 的复杂性增加,在过去几年中,出现了自动 ML 的激增。自动 ML 的目标是尽可能简化用户与底层 ML 算法的交互。仅举一个例子,Tableau、Power BI 等几个 BI 应用。在许多情况下,通过最大限度地减少用户输入,只需很少的点击即可执行 ML 算法。
即使 Tableau 或者 PowerBI 可以进行回归、分类等 ML 算法。它们不是执行复杂 ML 算法的最佳选择。现在很多 ML 算法通常都是用 Mathematica,Python,Matlab,Octave 等来做的。当一个人必须执行复杂的 ML 算法时,这些软件通常是最好的选择。
然而,随着技术和人工智能的进步,商业领域的许多公司可能没有预算(或想省钱)来负担员工执行 BI ML 算法。在这方面,这种类型的公司可能会寻求能够通过最大限度地减少用户与底层 ML 算法的交互来几乎不用代码执行 ML 的软件。这个软件之一是内乌顿-AutoML 。在这篇文章中,我讨论了内乌顿-AutoML 的最重要的方面,以及为什么它在许多方面对那些不太了解 ML 但却不得不在业务中使用的大公司非常有用。
什么是内乌顿汽车公司,它做什么?
内乌顿是一个使用 ML 的神经网络框架,无需从用户端编写代码。它不是基于一个预先存在的框架,而是利用 TinyML 来解决用户可能遇到的不同的 ML 问题。
许多最大似然算法的一个关键问题是,由于它们的复杂性和在训练过程中使用的大量数据,这些算法在计算机云上运行并消耗大量能量。由于这个原因,在过去的几年里, TinyML 领域有了显著的发展。ML 的这一新领域的目标是在微控制器上使用 ML 算法,以尽可能减少执行算法时使用的能量。
内乌顿是一个获得专利的神经网络框架,不是基于预先存在的算法。它有四个主要特征,使得修剪、量化和提取变得不必要,也不需要最终的模型压缩。这四个主要特征是:
- 专利优化算法 *。*内乌顿算法使平台的计算不基于误差的反向传播和随机梯度下降。这使得遇到局部最小值的可能性最小化。
- 无需用户手动搜索神经网络参数。 该功能使用户无需随机搜索参数,如层数、批量、学习率。
- 逐神经元结构生长。 该功能可以从一般特征到最具体的特征进行学习,并选择解决问题所需的几乎任何模型精度和尺寸。
- 有选择地接近选中的特征。 内乌顿的这一特性有助于在创建模型时只建立必要的神经元连接,不允许结构随机增长。
内乌顿的实际方面
要使用内乌顿,你只需在内乌顿的官方网站注册。我将不描述这个过程的必要步骤。我在这篇文章中的重点是内乌顿的实践和技术方面。
与任何 ML 过程一样,第一步是获取数据集并清理它。在这方面,内乌顿对数据集的类型及其要素数量有一些限制。训练数据必须满足的一些数据集特征如下:
- 数据集必须是使用 UTF 8 或 ISO-8859–1 编码的 CSV 文件。
- 数据集必须至少有 2 列或 2 行。
- 数据集不能有任何空列。
- 注意重复行:在预处理阶段,将从训练集中删除重复行,这可能导致与数据集最小大小和样本数要求不一致。
- 数据集中的第一行必须包含列名,并且必须使用逗号、分号、竖线、插入符号或制表符作为分隔符。CRLF 或 LF 应该用作行字符的结尾。数据集中的分隔符和行尾字符应该一致。
- 所有列名必须是唯一的,并且只能包含字母(a-z、A-Z)、数字(0–9)、连字符(-)或下划线(_)。
- 所有空值都必须从目标变量中排除。
- 对于回归任务类型,目标变量必须只有数值。
- 对于分类任务类型,必须为每类目标变量提供至少十个样本。
其他细节可以在内乌顿的用户指南文件中找到。一个关键的方面是数据集文件必须是 CVS 格式。类似的信息可以在测试数据集中找到。
一旦选择了数据集,接下来的内乌顿最大似然算法步骤如下:
- 选择数据进行训练
- 训练选中的模型
- 做出预测
为了帮助您更清楚地了解内乌顿汽车公司是如何工作的,我将展示几幅房屋数据集训练测试程序的图像。注册内乌顿网站后,点击“添加新解决方案”按钮,将出现以下窗口:
图一。“新建解决方案”对话框。作者创造的形象
点击“下一步”后,您将看到一个新的对话窗口。通过单击预加载数据集选项卡,您将看到以下窗口:
图二。训练数据集选项。在本文中,我使用预先加载的房价数据集。
在图 2 中,我勾选了房价(回归)选项,然后单击 OK 继续。之后,出现以下对话框:
图 3。作者创造的形象。
点击“确定”按钮,将出现以下对话框:
图 4。选项来选择目标变量。作者创造的形象。
在图 4 中,可以选择将哪个特征用作目标变量 y 。在这个例子中,我选择 SalePrice 变量作为目标变量。单击“下一步”按钮,您将看到以下窗口:
图 5。开始训练程序
在图 5 中,对话窗口给予用户选择任务类型的可能性,例如回归、分类等。,以及度量的类型。在这种情况下,软件默认选择 RMSLE。这是因为在这个训练程序中,我使用了基本模式,这是新用户的默认计划,并且是免费的。详情可在内乌顿用户指南中找到。
培训结果
一旦在基础模式下开始训练,内乌顿默认获取训练数据集(由内乌顿或用户预加载)并将数据拆分成训练数据集和验证数据集。如果用户选择高级模式计划,则可以选择加载验证数据集,而无需对原始数据集进行训练测试分割。
在培训过程结束时,内乌顿将为基本模式用户显示以下窗口
图 6。培训过程结束。作者创造的形象。
从图 6 中可以看出,在训练过程结束时,内乌顿向用户提供了所获得结果的详细信息。例如,训练模型大约需要 8 分 7 秒。如果点击图 6 中的“日志”按钮选项,将显示以下信息
图 7。内乌顿在培训过程中采取的步骤。作者创造的形象。
从图 7 中可以看出,内乌顿基本上是从创建一个虚拟机开始的,然后是预处理数据,然后是特征工程,等等。如果用户单击“Metrics”按钮,则会显示以下信息
图 8。培训过程的模型质量和度量指标。作者创造的形象。
在图 8 中,有训练测试分割过程的度量指标的总结。结果是通过将学习的函数应用于验证测试而获得的。可以看出,MSE 误差相当大,正如人们对房价数据集的预期。内乌顿默认选择非常小的 RMSLE 误差,RMSLE = 0.139326。
要查看模型是否运行良好,还可以使用决定系数 R =0.88,这是一个非常好的输出结果。所有这些指标给出不同的结果,这完全取决于用户使用哪一个以及如何解释它。
在图 8 所示的训练测试结果之后,可以使用训练模型来对训练测试过程中未使用的看不见的数据进行预测,如下图 9 所示
图 9。模型预测选项选项卡。作者创造的形象。
结论
在这篇文章中,我讨论了最重要的特点,内乌顿汽车用于 ML。作为一个例子,我使用了 房价 数据集来说明内乌顿如何在给定的数据集上执行 ML。
你或你的公司应该使用内乌顿汽车吗?这个问题的答案取决于几个因素,但从技术和实用的角度来看,我强烈推荐。正如我在本文开始时已经提到的,内乌顿 AutoML 的主要目标之一是尽可能地减少编写代码的用户算法。在这方面,内乌顿做得非常出色,因为几乎所有的 ML 流程都是自动化的,如上图所示。
有了内乌顿,人们根本不需要执行 EDA。唯一的要求是那些必须在 CSV 等格式的训练数据集。正如我上面讨论的。尽管执行 ML 解决方案不需要任何代码,但决定使用内乌顿的个人或公司需要了解一些基本的 ML。事实上,他们需要知道什么是特征变量,什么是输出。他们还需要知道如何解释图 8 所示的输出结果,以评估模型的准确性。
内乌顿在当前阶段需要改进的一点是,让用户不仅可以使用 CSV 格式的数据集,还可以使用其他格式的数据集。此外,我认为支持库不应该依赖 维基百科 链接来指引用户到特定的定义。事实上,维基百科是一个公共百科全书,不时会有关于 ML 度量等的定义。,可能会发生变化,可能与其他 ML 学习材料不一致。
如果你喜欢我的文章,请与你可能对这个话题感兴趣的朋友分享,并在你的研究中引用/参考我的文章。不要忘记订阅将来会发布的其他相关主题。
简单拼花教程和最佳实践
原文:https://towardsdatascience.com/easy-parquet-tutorial-best-practices-237955e46cb7
开始学习拼花地板的实践教程
Parquet file 是一个文件存储系统,它改变了任何与几个数据用户之间的日常数据操作有关的人的生活,例如数据工程师、数据科学家、分析工程师以及其他技术角色。
拼花的原理在于其面向列的存储,以及数据沿着列比沿着行更加同质的事实,提供了数据的优化压缩,从而导致更小的存储大小和增加的处理速度。
在本教程中,我们将概述一些最佳实践,让你开始学习镶木地板。
加载数据
首先,我们将使用一个公开的信用卡应用数据集。数据集可在 Kaggle 上获得:信用卡审批预测| Kaggle 。
获取这些数据最简单的方法是在您的环境中安装Kaggle API,提取数据并将归档文件解压到您的工作文件夹中:
pip install kaggle
kaggle datasets download -d rikdifos/credit-card-approval-prediction
unzip credit-card-approval-prediction.zip
让我们加载教程所需的包。6.0.0 以上的 pyarrow 任何版本都可以。
import pandas as pd
import numpy as np
import pyarrow as pa
在 zip 存档中,您将拥有 credit_record.csv (关于客户每月信用状况的数据集)和 application_record.csv (关于客户的信息)。为了简单起见,我们只对 zip 存档中的应用程序记录. csv 文件感兴趣。
为了让事情变得有趣,我们将复制数据 10 次并重置 id,使数据帧大约有400 万行和 18 列。
applications = pd.read_csv('application_record.csv')
applications = pd.concat(10*[applications]).reset_index().drop(columns=['ID','index']).reset_index().rename(columns={'index':'ID'})
以下是数据帧前 5 行的概述(面向列):
applications.head(5).T
我们注意到名为 FLAG_X 的变量不共享相同的输出类型,将它们规范化为布尔值应该是一个合理的选择。
首先,让我们构建一些简单的功能,即家庭收入和申请人年龄的月度版本:
applications['MONTH_INCOME_TOTAL'] = applications['AMT_INCOME_TOTAL']/12
applications['AGE'] = - np.floor(applications['DAYS_BIRTH']/365)
现在,我们希望与其他数据用户共享这些数据。为此,我们将以 CSV 和 parquet 格式将数据保存到其他用户可以访问的一些路径中。但在此之前,我们先来看看模式的概念。
模式
对于 parquet 文件,一个非常有价值的实践是定义数据集的模式。原因是,这将显著提高您正在共享的数据的一致性和健壮性,在用户之间传输数据时,列上不会出现任何类型的模糊性。
要获得 pandas DataFrame 的模式,只需使用 pyarrow 的 from_pandas 。模式。在内部,该函数将 DataFrame 列的类型与 pyarrow 能够理解的类型进行匹配,以用于 Parquet 文件。
my_schema = pa.Schema.from_pandas(applications)
my_schema
从上面的模式中,我们注意到我们最好做两个操作:
flags 变量实际上是布尔值 (1/0),这样存储它们除了避免任何类型模糊性之外,还会节省我们的存储空间。
- 出生天数与年龄重复,可以删除。
Schema 可以轻松完成这两种操作(类型转换和变量过滤)。该方法集用于用第二个参数更新第个 列,该参数应该是一个 pyarrow.field 对象。
my_schema = my_schema.set(12, pa.field('FLAG_MOBIL', 'bool'))
my_schema = my_schema.set(13, pa.field('FLAG_WORK_PHONE', 'bool'))
my_schema = my_schema.set(14, pa.field('FLAG_PHONE', 'bool'))
my_schema = my_schema.set(15, pa.field('FLAG_EMAIL', 'bool'))
my_schema = my_schema.remove(10)
现在让我们比较一下保存拼花和 CSV 文件的执行时间:
%%time
applications.to_parquet('applications_processed.parquet', schema = my_schema)
%%time
applications.to_csv('applications_processed.csv')
以 CSV 格式存储不允许任何类型声明,与拼花模式不同,并且在执行时间上有显著差异,以拼花格式存储比以 CSV 格式存储快 5-6 倍。
您刚刚见证了由拼花文件提供的处理速度。
为了减少存储大小,在本例中,拼花文件的存储差几乎是 20 乘以便宜(CSV 为 636MB,拼花为 39MB)。
总的来说,处理速度和存储减少是 Parquet 文件的主要优势,但不是唯一的优势。
创建分区
另外,关于 Parquet 非常有趣的一点是,您可以通过分区来分割数据,这意味着将与分区名称上的相同值相关的信息组合在一起。
您可以将数据分区视为将图书馆中相同类型的书籍排列在一起。就像整理书籍一样,它有许多优点:
- 数据的用户可以访问指定的一组数据,显著提高了加载速度,降低了 RAM 消耗
- 数据的生产者可以并行化处理,允许数据大小的可伸缩性和运行时间的可伸缩性减少
下面我将向您展示如何产生 Parquet 分区数据。
从列 *NAME_INCOME_TYPE,*中,我们观察到只有 5 个不同的值涉及客户的职业活动类别。
现在假设,我们作为数据的制作者,想要保存到拼花文件,但是在这个列上分区,因为数据的用户有兴趣分别查看那些专业活动:
applications.to_parquet('APPLICATIONS_PROCESSED', schema = my_schema, partition_cols=['NAME_INCOME_TYPE'])
注意,当我们保存到具有一个或多个分区列的 Parquet 时,我们必须提供一个文件夹路径而不是一个 Parquet 文件路径,因为方法 to_parquet 将创建关于 partition_cols 所需的所有子文件夹和 Parquet 文件。
生成的 APPLICATIONS_PROCESSED 文件夹现在根据信用申请人的 NAME_INCOME_TYPE 为每个信用申请人类别包含一个文件夹。
现在,对特定专业类别进行分析或决策选择感兴趣的最终用户,如*【国家公务员】*可以以很快的速度加载数据,并且只针对这群信贷申请人。
读取分区
我们将数据创建为分区的 Parquet 文件。
但是用户如何访问它们呢?这是我们从数据的用户的角度将要看到的。
有几种方法可以读取拼花文件。
如果它是由生成器生成的,没有分区列,并且假设我们,作为一个用户,对是“*工薪阶层”*的候选人感兴趣,我们必须写:
%%time
test = pd.read_parquet('applications_processed.parquet')
test[test.NAME_INCOME_TYPE=='Working']
这个操作花了将近 5 秒,仍然比在 CSV 中读取要好,但不是最佳的,因为用户正在加载所有数据并在那之后过滤它们。这意味着我们在浪费宝贵的内存和计算时间。
我们刚刚看到了分区的存在,一个熟练的数据工程师生成了由 NAME_INCOME_TYPE 分区的数据,这样我们就可以通过简单地加载感兴趣的分区来加快读取时间并减少 RAM 消耗。
有两种方法可以在相似的执行时间内完成:
- 我们可以直接将 NAME_INCOME_TYPE 的分区路径读作“Working”
- 或者我们可以使用 filters list 参数以同样的方式到达分区。过滤器选项会查看文件夹中的所有分区,并选择符合您条件的分区,这里是NAME _ INCOME _ TYPE**=**‘正在工作’,而不是直接进入路径。
下面列出了两种可能性:
%%time
pd.read_parquet('APPLICATIONS_PROCESSED/NAME_INCOME_TYPE=Working/')
# OR (the run-time below corresponds to either one of way of reading)
pd.read_parquet('APPLICATIONS_PROCESSED', filters=[('NAME_INCOME_TYPE', '=', 'Working')])
你看到速度增加了吗?速度快了 3 倍,而且你不必加载全部数据,节省了你机器上的大量内存。
这两种读取分区数据的方法有一个区别,但在我们的例子中几乎察觉不到:使用过滤器读取数据取决于内部分区的数量。实际上,这里我们在 NAME_INCOME_TYPE,上只有 5 个分区,所以读取数据的路径和过滤器方法之间的运行时是相同的。然而,如果我们有 1000 个分区,运行时的差异将会很大,因为 Apache Parquet 必须发现所有的分区,并返回与您的过滤器匹配的分区。
然而,我强调这样一个事实,用过滤器读取在灵活性和容量方面要强大得多,如果运行时的权衡可以接受的话,我强烈建议您尝试一下。
一个简单的例子是,如果您想专门读取两个或更多的分区(但不是所有的分区),那么您无法使用路径读取有效地做到这一点,但是使用过滤器,您可以做到。
例如,如果我们不仅对标准的*【工作】申请人感兴趣,而且对【国家公务员】*申请人也感兴趣:
filters = [('NAME_INCOME_TYPE', 'in', ['Working', 'State servant'])]
pd.read_parquet('APPLICATIONS_PROCESSED', filters=filters)
您也可以通过给出文件夹路径 : 来加载整个数据,即使它是在 NAME_INCOME_TYPE 上分区的
pd.read_parquet('APPLICATIONS_PROCESSED')
请注意,在生成的数据帧上,列 NAME_INCOME_TYPE 是存在的,而如果您正在读取 NAME_INCOME_TYPE 的分区,则它是隐藏的。
这是正常的行为:通过简单地读取分区,分区数据上的Apache**Parquet假设您已经知道这个列是针对这个特定的已过滤分区值而存在的(因为您告诉他根据 NAME_INCOME_TYPE 进行过滤),所以它不会在输出数据帧中重复该列,因为它只是一个具有唯一值的 NAME_INCOME_TYPE 的列。
总之,我们概述了使用 Parquet 的最佳实践,包括定义一个模式和划分数据。我们还强调了使用拼花文件在处理速度和存储效率方面的优势(在硬盘和 RAM 上)。此外,我们还考虑了数据用户的观点以及使用 Parquet 文件的相关性和简单性。
用我的其他文章继续学习拼花地板:
https://pub.towardsai.net/parquet-best-practices-the-art-of-filtering-d729357e441d
无需额外费用,您可以通过我的推荐链接订阅 Medium。
https://medium.com/@arli94/membership
或者你可以在收件箱里收到我所有的帖子。做到这里 !
可解释的助推机器:弥合 ML 和可解释性之间的鸿沟
原文:https://towardsdatascience.com/ebm-bridging-the-gap-between-ml-and-explainability-9c58953deb33
什么是可解释性,为什么它很重要?
安德烈·德·森蒂斯峰在 Unsplash 上拍摄的照片
什么是可解释性,为什么它很重要?
人工智能在过去几十年中不断发展,已经在各个领域找到了应用,包括医疗保健、军事、银行和自动驾驶汽车等关键系统。然而,很多时候,许多机器学习模型的黑盒性质阻碍了它们的采用。例如,在商业中,机器学习的应用将是预测未来销售、预测客户流失、锁定客户等。黑箱模型或许能够准确预测未来的销售或客户流失,但它无法解释不同的因素如何影响产出。这在银行业等行业尤其重要,因为这些行业受到监管机构的监管,这些机构要求其模型透明、结构公正。此外,对模型决策的理解有助于企业理解不同因素如何影响其业务,更好地为不确定的未来做准备,并做出更好的战略决策。这是通过可解释的或玻璃盒子的 ML 模型提供给他们的。
机器学习中的可解释性指的是模型或建模技术解开模型内关系的能力。根据算法提供的可解释性水平,机器学习模型可以大致分为两类:玻璃盒模型和黑盒模型。本文探讨了什么是玻璃盒模型和黑盒模型,是什么赋予了玻璃盒模型的可解释性,以及一种称为可解释助推机(EBM)的玻璃盒模型。
玻璃盒型号:
这些都是固有解释的模型。属于这一类的两个最简单的模型是线性回归和逻辑回归。以逻辑回归为例,它将概率预测为一个或多个独立变量的线性组合的函数。这个模型的等式可以写成:
作者图片
其中 p 是事件发生的概率,log(p/(1-p))是事件的对数概率。这种将对数概率表示为独立变量的线性组合的能力使得该模型具有可解释性。对于这个逻辑回归模型,可以说变量 x1 的单位变化改变了事件的对数概率β1。注意,为了便于解释,因变量不需要与自变量具有线性关系。例如,即使是以下形式的“广义加性模型”
作者图片
是可以解释的,因为你可以估计任何变量 x 的变化是如何影响目标 y 的
黑盒模型:
在这些模型中,自变量和因变量之间的关系并不明显。诸如随机森林、梯度增强树和神经网络之类的算法是一些黑盒模型。
为了进一步说明黑盒的概念,考虑一个简单回归树的例子,它具有以下数学形式:
作者图片
其中,ki 是常数,I(。)是一个指示函数,如果其参数为真,则返回 1,否则返回 0。
和 Di 是训练数据的不相交分区。下面的例子说明了这个等式:
作者图片
使用上述等式的更简洁的表示,我们得到:
作者图片
然而,玻璃盒模型虽然可以解释,但与黑盒模型相比往往不够准确。EBM 试图通过提供一个与一些黑盒模型一样准确同时又保持相当可解释性的解决方案来弥合这一差距。
可解释增压机
什么是循证医学?
EBM 是一个广义的加法模型,它使用梯度推进和浅回归树的集合[1]。因此,简单地说,循证医学是以下形式的广义函数
作者图片
其中 g(。)是一个链接函数(类似于广义线性模型)。该模型使用非常低的学习率在“循环周期”中一次训练一个特征,因此特征顺序无关紧要[1]。
因此,在迭代 1 中:
作者图片
在迭代 2 中:
作者图片
这一直持续到迭代 r。每个特征的最终函数是通过将该特征的所有函数相加而获得的,即
作者图片
诸如此类。
对于每一个特征,EBM 计算一个 f(xi)对 xi 表,用它来产生得分对 xi 图,帮助理解 xi 和易之间的关系以及每一个特征对易预测的贡献。然而,循证医学并不止于此。它还包括变量之间的二维相互作用。由于二维交互仍然可以在二维平面上呈现为热图,因此包含二维交互的模型仍然是可解释的。因此,EBM 的最终形式可以表示为:
作者图片
传统上,确定交互项在所需的计算能力方面是复杂的,尤其是对于具有大量变量的大型数据集。EBM 通过提出两阶段构建方法和使用 FAST 有效地对成对交互进行排序来解决这个问题。这种方法的两个阶段是:
1.在第一阶段,仅使用一维组件构建最佳的附加模型。
2.在阶段 2 中,固定一维函数并为残差上的成对相互作用构建模型,即,使用 FAST 选择前 K 个相互作用对,并使用残差 R 上的对来拟合模型,其中 K 是根据计算能力选择的。[2]
由于 EBM 通过将每个特征的贡献相加来计算最终输出,因此很容易可视化和理解各个特征和交互项的贡献。然而,由于预测的这种模块化,EBM 必须支付额外的训练成本,这使得它比类似的方法要慢一些。但是这并没有使它在预测过程中变慢,因为进行预测涉及到简单的加法和特征函数内部的查找。事实上,这使得 EBMs 成为预测中执行速度最快的模型之一[1]。
循证医学实例:
在下面的例子中,我使用了来自 Kaggle [3]的信用卡欺诈检测数据集。根据 ODC ODBL 许可协议,该数据集可供用户自由共享、修改和使用。
数据集描述:
该数据集包含欧洲持卡人在 2013 年 9 月的信用卡交易。数据集高度不平衡,正类(欺诈)占所有交易的 0.172%。它包含从 V1 到 V28 的特征,这些特征是在 PCA 之后获得的。不使用 PCA 进行转换的唯一特征是时间(数据集中第一次和每次交易之间经过的秒数)、数量(每次交易中使用的数量)和类别(目标变量)[3]。
循证医学模式:
由于数据已经被处理,我们将直接进入建模部分。
作者图片
一旦我们有了模型,让我们看看模型是如何表现的。循证医学提供了两种解释:全局和局部。
全局解释:
全局解释有助于我们理解特性对模型的整体贡献,以及每个特性与模型的关系。
- 了解特征对模型的整体贡献
作者图片
还可以通过使用 ebm.feature_importances_ 和 ebm.feature_names 来获取特征和特征重要性
特征(x) v/s 目标(y)关系:
作者图片
局部解释:
局部解释有助于我们理解在每次预测中,即在局部水平上发生了什么。
作者图片
作者图片
从 EBM 获得预测:
由于数据集非常不平衡,我们使用“精确召回曲线下的面积”这一指标来测试模型。
作者图片
让我们比较一下 EBM 和 xg-boost 的竞争情况:
作者图片
很接近吧!
参考资料:
[1]https://interpret.ml/docs/ebm.html
[2]尹娄,丰富卡鲁阿纳,约翰内斯·盖尔克,和贾尔斯·胡克。具有成对交互的精确可理解模型。第 19 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集,623–631。2013.
[3]https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud
计量经济学是原始的数据科学
原文:https://towardsdatascience.com/econometrics-is-the-original-data-science-6725d3f0d843
这就是你应该多了解它的原因
米克·豪普特在 Unsplash 上的照片
我记得开始我的第一门机器学习在线课程时,我意识到我已经知道了大部分内容。
我将在这篇文章的开头说,我是一个受过训练的、杂志发表的计量经济学家——我有偏见。你知道谁也有偏见吗?约书亚·安格里斯特——一位 2021 年诺贝尔奖获得者,我在为这篇文章做研究时发现他的视频说了同样的话。
如果你正在读这篇文章,我假设你对数据科学有些兴趣——你可以从计量经济学中学到很多东西,所以请系好安全带,认真听讲。
有什么区别?
总的来说,它们是一个硬币的两面。
数据科学和计量经济学的大部分课程都是从同一个地方开始的。计量经济学线性回归与数据科学线性回归完全相同。然而,你可能会学到不同的东西。例如,在计量经济学课程中,有相当多的关于“正规方程”的提及,这是一个代数方程,允许你解析地求解最优参数。从下面可以看出:
由作者创建— θ是参数权重的向量,X 和 y 分别是你的观测值和目标的矩阵。
我一直认为这是一个非常漂亮的等式,但在数据科学中经常被忽略。我认为原因是法线方程在处理少量数据时表现良好,不需要特征缩放,而梯度下降则相反。随着大数据的兴起,在数据科学课程中坚持梯度下降是有意义的。
你会注意到一些符号是不同的,这让我觉得非常讨厌。
计量经济学和数据科学都会教你很多相同的东西,因为两者都需要对统计学有很强的理解。然而,在讨论了线性和逻辑回归之后,课程往往会在最后有所不同,数据科学将继续谈论神经网络,而计量经济学将深入研究工具变量和回归不连续设计的主题。
它们的目标和结果确实不同
不过,这两者的不同之处在于它们创建的模型的结果和用途。计量经济学家和数据科学家可以制作完全相同的模型,并撰写非常不同的讨论论文。
我注意到,大多数数据科学家似乎只对他们的模型感到满意,如果它获得了高准确率的话。我们都知道这个问题——尤其是在试图预测罕见事件的模型中。计量经济学倾向于更深入地研究模型,并试图推断因果关系。
虽然数据科学只关注预测,但计量经济学试图实现高准确性,同时也寻求找到因果关系。然而,寻找因果关系是一种约束,这往往会损害你的准确性。
计量经济学用准确性换取理解。
数据科学用数据找关系,计量经济学用数据证明关系。计量经济学从一个理论开始,然后用一个模型来检验它的假设。
因此,根据项目的不同,您可能经常希望理解多于准确。我稍后会解释原因。
数据科学遗漏了什么?
计量经济学课程让学生更好地理解基本面
在我个人看来,计量经济学的课程提供了对基本面更好的理解,尤其是在回归这样的领域。有多少数据科学家知道并理解高斯-马尔科夫定理?我相信很多人都有,但我很少在课程中看到他们被提及。高斯马尔可夫定理告诉我们,如果满足某组假设,回归系数的普通最小二乘估计会给出可能的最佳线性无偏估计(蓝色)。像 Josh Angrist 一样,我觉得花时间在课堂上证明它是浪费时间,但对我来说,它肯定回答了很多关于我们为什么在回归中做某些事情的问题。在现实中,这些假设永远不会得到完美的满足,但它们肯定有助于作为基准来改进您的模型。这就引出了我的下一点。
因果关系
计量经济学家如此关心正确地描述他们的模型,有时为了做到这一点而放弃准确性的原因是,他们主要关心的是因果关系。
让我们忽略亚里士多德和休谟,采取实际意义上的因果关系。让我们看看维基百科的定义:
因果关系(也称为因果关系,或因果关系)是一个事件,过程,状态,或对象(一个原因)促成另一个事件,过程,状态,或对象(一个效果)的产生的影响,其中原因部分地对结果负责,结果部分地依赖于原因。一般来说,一个过程有很多原因,也可以说是这个过程的原因,都在于它的过去。一个效应可以反过来成为许多其他效应的原因或因果因素,这些都在于它的未来。
实际上,因果关系是一个物体对另一个物体的影响。
然而,因果关系不能与相关性相混淆。在计量经济学中,第一课是——“相关性并不意味着因果关系”。关于计量经济学因果关系的精彩阅读,请试试这个。
强烈的相关性可能表明因果关系,但它可能存在许多其他原因。这很可能是出于偶然——为了好玩,请看下面来自网站的一个例子。
https://www.tylervigen.com/spurious-correlations——https://creativecommons.org/licenses/by/4.0/
或者它很容易来自另一个我们没有包括在分析中的秘密变量。例如,想象你看到皮肤癌和锻炼之间有很强的相关性。你会很快得出结论,锻炼不会导致皮肤癌,但锻炼越多的人往往越活跃,因此更多地外出。
所以这是计量经济学真正试图解决的问题。作为一名数据科学家,我可以向墙壁扔东西,看看有什么粘在一起,但作为一名计量经济学家,我真的必须考虑我在扔什么(以及我没有扔什么)。
那么如何推导因果关系呢?
通过实验和传统数据科学技术的巧妙结合。
我不会详细介绍计量经济学家的所有不同技术,但这里有一个很好的例子——工具变量。
以线性回归为例,如果真实模型被认为在解释变量和误差项之间没有协方差(来自高斯-马尔可夫假设),那么由于任何原因,这是不真实的(例如,有一个被忽略的变量影响因变量和自变量),那么 OLS 将不会产生 X 对 y 的因果影响
基本上,除非模型是完美的,否则我们有将相关性视为因果关系的风险。
如果你担心错误指定的模型,工具变量是推断因果关系的一个很好的方法,特别是在随机对照试验不适合的领域。
工具变量是第三个变量,Z,当您有内生变量或不确定模型是否指定错误或缺少关键变量时,在回归分析中使用。
例如,让我们以一种降低血压的药物为例。我们想知道,假设这种药物是免费的,任何人都可以购买,这种药物是否有效(我们无法进行随机对照试验)。其他变量如锻炼和饮食也将发挥作用,我们不知道是锻炼越多的人服用药物的可能性越小,还是我们只是忽略了一些变量。
因此,我们必须找到一个仅通过服药途径影响血压的变量。一个我们确信对血压绝对没有影响的变量,但由于与服用药物相关,可能显示出一些相关性。
常用的例子是靠近药房。你离药店有多近绝对不会对你的血压产生影响,除非是因为你更有可能服药。因此,我们可以通过第三个变量来分离药物和血压之间的因果关系。
由作者创建。
然后你可以通过两阶段回归 /OLS 来解释结果。
通过这种实验和统计操作的巧妙结合,我们可以对药物的能力更有信心。
这只是计量经济学可以用来确定因果关系的许多技术之一。作为我最喜欢的另一个例子,这是我写的另一篇关于回归不连续设计的文章。
你为什么要在乎?
这篇文章的要点是因果关系很重要——大公司也知道这一点。正如乔希·安格里斯特所说,对于受过计量经济学培训的人来说,私营部门有一个非常大的市场。
他们在寻找能做一些统计的人,但这些公司感兴趣的很多问题都是因果问题。例如,改变价格的后果会是什么。’
在就业市场上,有能力确定因果关系是一个巨大的优势。
计量经济学也可以从数据科学中学到很多东西。
为了完善这一点,并确保我没有试图侮辱数据科学家——我就是其中之一——这里有几点我认为计量经济学可以从数据科学中吸取的。
探索性分析
通过学习许多数据科学课程,我也学到了许多可以应用于计量经济学的东西。
计量经济学家在探索性研究方面很糟糕,绝对糟糕。
显然,这并不适用于每个计量经济学家,但就教科书和课程而言,绝对没有强调理解你的数据。如果你只是绘制一些数据,你可以节省很多时间来决定在你的模型中放入什么。
准确(性)
当我学习计量经济学的时候,曾经困扰我的是对 p 值的依赖,以及对模型整体准确性的缺乏关注。对我来说,如果模型只解释了 4%的方差,那么吹嘘一个变量有多重要就没什么意义了。是的,这个变量可能是有趣的,但当我们只解释和理解图片的一部分时,这并不重要。
结论
归根结底,计量经济学可以从数据科学中学到很多东西,数据科学也可以从计量经济学中学到很多东西。两者之间的鸿沟当然也在缩小。
对因果影响的理解确实是所有数据科学家都应该具备的技能。
只要记住‘所有的模型都是错的,但有些是有用的。有时候理解一个更差的模型比不理解一个稍微好一点的模型更有用。
干杯,
詹姆斯
感谢阅读,我希望这能帮助你。
If I’ve inspired you to join medium I would be really grateful if you did it through this [link](https://jamesasher4994.medium.com/membership) — it will help to support me to write better content in the future.If you want to learn more about data science, become a certified data scientist, or land a job in data science, then checkout [365 data science](https://365datascience.pxf.io/c/3458822/791349/11148) through my [affiliate link.](https://365datascience.pxf.io/c/3458822/791349/11148)
这是我写的其他一些东西:
EDA 与 Tableau: 2021 年 NYPD 停下来搜身的人口统计
使用公共数据时制作可访问仪表板的案例—
(longislandwins的《无声行进到终点》被 2.0 的 CC 授权。)
上面这张照片是在一次结束截停搜身和种族歧视的无声游行中拍摄的,拍摄于 2012 年 6 月 17 日,在截停搜身被视为违宪的一年前。探索 NYPD 的拦截搜身数据符合公众的既得利益。去年在纽约,有将近 9000 次停车。
但是什么是拦截搜身呢?
NYPD 拦截搜身概述:
Dictionary.com 将 stop-and-frisk 定义为*短暂拦截某人以搜查其武器或违禁物品的警察行为*
NYPD 从去年开始称他们的项目为“拦截、询问和搜身”,以反映市长亚当对拦截和搜身的态度,亚当是前 NYPD 队长。
“我不断被追问我对被称为‘拦截搜身’的警务程序的立场——这在执法中实际上被称为‘拦截、询问和搜身’——以及为什么我相信,如果使用得当,它可以在不侵犯个人自由和人权的情况下减少犯罪,”—亚当斯市长【1】**
为什么这对纽约市的治安历史如此重要,是因为如果你在谷歌上搜索“停下来搜身+违宪”,你首先会看到以下内容,来自维基百科:
纽约市警察局在 NYPD 的拦截搜身计划上立场明确。[4]
来自纽约市警察局:
年度拦截搜身数字:
NYCLU 的一项分析显示,自 2002 年以来,无辜的纽约人遭到警察拦截和街头审讯超过 500 万次,黑人和拉丁裔社区仍然是这些策略的主要目标。在 2011 年彭博政府时期的截停搜身高峰期,超过 685,000 人被截停。几乎 90%被拦截搜身的纽约人是完全无辜的。
…在 2021 年,记录了 8947 次停车。
5422 人是无辜的(61%)。5404 人是黑人(60%)。2457 人是拉丁裔(27%)。732 人是白人(8%)。192 人是亚洲/太平洋岛民(2%)
71 人是中东/西南亚人(1%)
然而,有一个问题阻止了大多数纽约人接近拦截搜身数据。正如我在关于 NYPD 拦截搜身数据的上一篇文章中提到的,这些信息对公众开放,但公众无法获取。NYPD 公布的文件仅以原始形式存在,它们没有被总结或汇总。文件的每一行代表一个站点的一个记录,查看原始文件有点像这样:
(视频由作者提供。youtube 上的视频片段链接如下:https://www.youtube.com/watch?v=illObkP3TLQ
对于需要公众访问的数据,Tableau Public 这样的工具是绝佳的匹配。它的点击式图形用户界面对于熟悉数据的人和数据新手来说都很直观。通过将 Tableau Public 用于我的 EDA,交互式可视化的好处有助于我自己对数据的理解,但更重要的是,我可能为普通纽约人构建了一些易于理解的东西,以理解去年的“拦截搜身”。
让我们看看我能做什么。然后,我将向后展示我的方法,这样您就可以理解我是如何构建这个仪表板并将其用于 EDA 的。
我的 EDA 将专注于理解人口统计学(种族、年龄和性别)与警察辖区之间的关系,在这些区域发生了拦截搜身,并阻止了涉嫌犯罪的人。我还会调查是否使用了任何形式的暴力,以及停车是否导致了逮捕。
结果:
这是我制作的一张仪表盘的静态图片,因为 Medium 不支持嵌入 Tableau 公共仪表盘。
(图片由作者提供)
数据:
NYPD 将其所有可用数据发布到纽约市开放数据网站,这是他们的拦截、询问和搜身数据。
纽约市在“学校、警察、健康和消防”【3】下面有 NYPD 分局的 geojson 档案。
代码:
我的 Github Repo 在这里清理了数据,并为聚合做好了准备。我不会回顾我所做的每一步,而是概述我所做的选择。
- 我将
STOP_FRISK_DATE
和STOP_FRISK_TIME
制作成每一站的日期时间列,并将文件重新保存为 csv.gz 文件以节省一些空间:
(图片由作者提供)
2.我分离出感兴趣的列,只保留那些:
(图片由作者提供)
3.我用完整的措辞替换了一些更复杂的犯罪描述:
(图片由作者提供)
4.我尽可能地将一些种族描述改为更微妙的语言。(Business Insider 很好地解释了为什么“中东”是过时的语言。[ 4 ]在SUSPECT_RACE_DESCRIPTION
中将类似MALE
和(null)
的值更改为UNKNOWN
非常简单。我不想改变太多的这些价值观,因为我发现保持警察如何对人们进行种族侧写的精确性是相关的。
然而,可以将BLACK HISPANIC
与BLACK
和WHITE HISPANIC
与WHITE
合并,或者将HISPANIC
或LATINX
单独归为一类。将ASIAN / PACIFIC ISLANDER
更改为E. ASIAN
是唯一一个我失去了一些细微差别的类别,以换取一个更简单易用的名称对象,这是我在 Tableau 中使用别名时解决的问题。
(图片由作者提供)
5.在关于使用体力的栏中,我将Y
替换为1
,将UNKNOWN
替换为0
。当我合计时,这将把所有的Y
加在一起。
(图片由作者提供)
6.出于汇总和描述性统计的目的,我还制作了一个列,记录了一次遭遇中使用的所有物理力量(行。)
(图片由作者提供)
它返回给我们下表:
(图片由作者提供)
值得注意的是,在该数据代表的 8,947 行中,只有不到 100 行使用了UNKNOWN
数量的体力。该数据集中的所有其他停止都有一个已知的因素,即至少使用了某种物理力的一个计数。当我们得到描述性统计数据时,我们将回到这个问题上来。
7.我做了一个布尔列来捕捉是否使用了任何形式的物理力量。请注意,当我在 Tableau 中为该列添加别名时,FALSE
变成了UNKNOWN
:
(图片由作者提供)
8.我将 DateTime 列转换为索引,并将STOP_LOCATION_PRECICNT
列更改为 string 数据类型,因为它是分类信息,我们不想计算这些值。
(图片由作者提供)
9.我在做了一个data['SUSPECT_REPORTED_AGE'].value_counts()
之后,发现了一些像 0 岁、120 岁这样不合逻辑的年龄值,就把SUSPECT_REPORTED_AGE
中一些没有意义的值改成了UNKNOWN
。
(图片由作者提供。)
10.我从数据中切掉年龄是已知值的行,并将这些值转换成整数,这样我们就可以计算它们了。
(图片由作者提供)
我这样做是因为我想基于年龄的四分位数范围创建一个AGE_CATEGORY
分类列。通过按四分位数范围划分年龄,我知道我可以在数据分布的地方最平均地划分数据。
(图片由作者提供)
这段代码向我们返回了与年龄层位置相关的数字。
(图片由作者提供)
11.所以我做了一个垃圾桶来捕捉 20 岁以下,21-28 岁,28-38 岁和 38 岁以上的人:
这段代码返回到我们的SUSPECT_REPORTED_AGE
列,与我们刚刚创建的AGE_CATEGORY
列进行比较。让我们看看它是否有效。
成功了!我可以说它工作了,因为我们的第一行,索引在2021-01-01 01:50:00
被列为40
岁,在Thirtyeight-Above
类别等等。
从那里,我想把我们的年龄未知数混合回数据中,他们的年龄类别为UNKNOWN
:
(图片由作者提供)
它返回以下内容:
(图片由作者提供)
好像花了!从那里,我想了解一下AGE_CATEGORY
中年龄的总体分布情况
它返回了以下内容:
(图片由作者提供)
看起来我们的分位数成功地捕捉到了均匀分布,我们的UNKNOWN
年龄类别比其他类别的一半要小。
11.当我查看像这样的SUSPECT_SEX
发行版时:
(图片由作者提供)
它返回了以下内容:
(图片由作者提供)
使FEMALE
成为这个数据集中的少数。让大多数人是一种性别没有太大意义。我决定将UNKNOWN
改为MALE
,因为我知道可能会有一些既不是女性也不是男性的人通过这种方式处理数据时会经历数据擦除。
(图片由作者提供)
12.我制作了一个列,仅仅是为了汇总任何给定类别中的停靠点总数。我会在 Tableau 中大量使用这个专栏。
(图片由作者提供)
13.我使SUSPECT_ARRESTED_FLAG
列适合聚合,并使它的对应列SUSPECT_NOT_ARRESTED_FLAG
显示相反的值,这样我就可以同时使用这两个列。
(图片由作者提供)
因此,如果有人被捕,它将显示值为SUSPECT_ARRESTED_FLAG
的1
和值为SUSPECT_NOT_ARRESTED_FLAG
的0
,这将在可视化过程中帮助我。
14.我使用data.describe()
查看了描述性统计数据,以下是我的发现:
(图片由作者提供)
- 总的平均比率是 37%被捕与 62%未被捕,平均标准偏差约为 50%,这意味着可变性高于实际被捕率。
- 在停车期间,平均枪支收缴率不到 6%。
- 在停车期间,大约有 20%的时间会强制使用手铐。
(图片由作者提供)
- 根据数据,2021 年停车期间没有使用 OC 喷雾。
- 在停车期间,大约 3%的时间使用体力“其他”。
- 在停车期间,只有不到 3%的时间使用了约束。
- 90%的时间都在使用体力口头指令,这使它成为大多数停车的常规部分。
(图片由作者提供)
- 几乎没有使用过武器的记录。
- 体力总量,也许是这组统计数据中最有趣的指标,约为 1.25%,这意味着如果我们将所有使用的各种体力计数相加,使用的体力计数比停止的多大约四分之一。这是一个非常有趣的统计数据。标准偏差约为 0.5 或所用物理力的一半,这意味着平均经验是物理力被用于止损,物理力的大小通常变化半个计数。
从这里开始,我使用data.to_csv('2021_data.csv')
保存数据,并继续使用 Tableau 公开仪表板。
仪表板:
这是我第一次使用 Tableau Public,我花了一分钟才适应。这里是我的一般步骤,但对于更多细节,我鼓励您下载仪表板本身并开始使用它。
- 将
precincts.json
文件添加为Spacial
文件,将2021_data.csv
文件添加为文本文件,并将它们之间的关系定义为Precicnt1
=
STOP_LOCATION_PRECICNT
(图片由作者提供)
2.通过将Geometry
拖到空白页上制作分区结果图,使Stop Location Precicnt
成为一个维度细节(不是按总和),允许我滚动每个分区并弹出该分区。从那以后,问题就变成了我想在选区展示什么。我选择显示该辖区内的总停靠次数,并选择显示我创建的名为Not-Arrested Rate
的计算字段,有关我如何计算该字段的详细信息,请参见此处:
(图片由作者提供)
3.对于涉嫌犯罪被阻止的情节,我把Total Stops
拖到列上,确定它正在取和。然后,我将Suspected Crime
药丸拖到几排。
(图片由作者提供)
我决定将“大麻的销售”与“大麻的销售”混为一谈,因为我想消除说西班牙语的人的污名。更多来自 NPR 的消息。]
让数字在栏旁边弹出也很简单,只需将SUM(Total Stops)
拖到文本框中,如下所示:
(图片由作者提供)
4.随着时间的推移制作种族差异剧情分两步走。首先,我将时间索引拖到列上,并选择了Month
而不是Year.
,然后我将Total Stops
拖到行上,并确保它得到了总和。
(图片由作者提供)
然后我把Suspect Race Description
药丸拖到 Marks,并使它成为一个彩色细节。
(图片由作者提供)
5.制作年龄图是类似的,我将Age Category
拖到列上,将Total Stops
拖到行上,确保它得到总和。
(图片由作者提供)
然后我同样将Suspect Race Description
拖到颜色标记处。
(图片由作者提供。)
6.将所有这些都放在一个仪表板上,使每个情节相互作用,并设置所有的过滤器,这是一个有趣的过程。要看到我的整个过程,最简单的事情就是从 Tableau Public 下载仪表板,然后自己去找。Tableau 社区文档中有丰富的更多资源:https://help . Tableau . com/current/pro/desktop/en-us/filtering . htm[6]
注意:这个仪表板仍然可以看到一些变化或改进。举例来说,我还没有尝试使用集合功能将同一个区的所有选区组合在一起。我也没有连接一种方法来显示使用了两种或两种以上物理力的停止,这在分离出 PHYSICAL_FORCE_
时可能是相关的。
为什么这比用 python 做我所有的 EDA 要好?
- 我可以用连珠炮似的问题来处理数据,而不会因为制作大量的静态表格和图表而慢下来。
- 我可以非常容易地与公众和我的利益相关者分享我的发现。
例如,如果我只想得到未逮捕率最高的统计数据的明细,该怎么办?在地图上,我可以很容易地将 75 区(东纽约)标记为最暗的红色,当我单击它时,我可以看到该区内涉嫌犯罪的分布明细,其中绝大多数是持枪犯罪。从这里我还可以看到按种族划分的年龄分布,以及按种族划分的被捕时间。一次点击为我节省了很多很多行代码!
(图片由作者提供)
当我们使用这些描述性统计数据深入了解该辖区时,我们可以了解到,平均而言,75 号辖区拦截的乘客年龄远低于所有车站的平均年龄(28 岁)。)我们还了解到,75 区的未逮捕率远高于全市平均水平,分别为 83%和 67%。如果我们看一下时间线,我会想到问“4 月份开始发生了什么来阻止止损,特别是当阻止黑人时?”
(图片由作者提供)
当我们使用Outcome
过滤器比较我们的图表时,我们可以看到,去年在 75 区因涉嫌非法持有武器而被拦下的 330 人中,有 278 人没有被逮捕。
进一步的发现:
涉嫌非法持有武器并不导致逮捕:
在今年进行的 8,947 次拦截中,有 2,471 次是涉嫌非法持有武器,并没有导致逮捕。这仅占所有停靠站的 27%。通过查看年龄图,我们可以看到超过四分之一的停靠点都是 20 岁以下的人,或者他们的年龄没有被列出。我们也可以看到大多数黑人弥补这些停止。当我们查看种族差异随时间变化的图表时,我们可以看到一波从 9 月开始,在 11 月达到高峰,停留次数是 9 月的两倍多。这就引出了一个问题,9 月份开始发生了什么,为什么警方会阻止涉嫌非法持有武器的年轻黑人?
(图片由作者提供)
斯塔滕岛站:
当我们查看仅发生在斯塔滕岛的停靠点时,我们会得到不同的数据。我们看到了更多针对年轻人停车的证据,(但没有列出年龄的趋势),黑人年轻人占了 20 岁及以下类别停车的一半。
(图片由作者提供。)
最值得注意的是,在斯塔滕岛发生的停车事件中,绝大多数都使用了暴力。这两张照片显示了发生在斯塔顿岛的所有停靠站,然后我只分离出使用某种物理力量的停靠站。这两张照片几乎一模一样。
(图片由作者提供)
那是因为去年在斯塔滕岛只有 5 次停车,没有证实是否使用了某种暴力。其余的停留都涉及到体力。在未来,我想进行假设检验,看看斯塔滕岛的数据与纽约市其他地方的数据有多大差异,因为我们之前发现,去年全市 90%的车站中至少有一次使用了物理力量。
14 区的车站和妇女:
只要看看那些被拦下的人被列为女性的车站(记住,虽然大多数女性都自称为女性,但这是一种过于简单化的说法),我们就可以看到曼哈顿下城的一个区,那里的不逮捕率特别高(暗红色。)
(图片由作者提供)
在进一步调查中,我们可以看到这是 14 区,去年有 60 个由妇女组成的站点,其中 90%没有被逮捕。与我们全市所有车站 67%的不逮捕率相比,这是一个相当高的比率。
(图片由作者提供。)
在这 60 次拦截中,40 次(67%或三分之二)涉嫌非法持有武器。当我们查看她们的年龄时,我们可以发现超过一半的女性年龄在 28 岁以下,而大多数没有列出年龄的女性是东亚或太平洋裔。当我们查看我们的种族差异随时间变化的图表时,我们可以看到这些停止在 10 月和 11 月之间有一个很大的峰值。
当我们更仔细地观察时,我们可以看到这些拦截中的大多数并没有导致逮捕。通过比较这两张快照,我们可以看到,随着时间的推移,种族差异主要是由黑人女性构成的。重要的是,大多数导致这些黑人女性被捕的停车点并不是在 10 月至 11 月停车高峰时发生的。
通过使用 Tableau,我可以与更多的观众分享这些发现,并且我能够轻松地对数据快速提问。事实证明,Tableau 在帮助我探索数据以及找到我想要进一步查询数据的位置方面非常有用。
最后,我将把 Tableau 整合到我的 EDA 过程中,我鼓励你也考虑这样做。它节省了你询问数据问题的时间,你的利益相关者会感谢你能够理解数据并与数据本身互动。
[1] E. Adams,A. Wehenkel 和 G. Louppe,我们如何使纽约市变得安全:当选市长 Eric Adams 解释了我们为什么需要拦截搜身和积极主动的治安 (2021),纽约每日新闻
[2] NYPD,拦住、盘问和搜身的数据 (2021)
[3]纽约市,政治和行政区—下载和元数据 (2021)
[4]纽约市警察局,拦截搜身数据 (2021 年),纽约市警察局
EDN-GTM:具有用于单一图像去雾的引导传输图的编码器-解码器网络
当传统的计算机视觉和深度学习结合时。
由 Unsplash 上的 drmakete 实验室拍摄的照片
图像去雾
增强从自然场景捕获的数字图像的可见性的目的在许多现实世界应用中变得非常必要,因此图像去雾(或去雾)在几十年前已经成为计算机视觉和图像处理中的重要任务。
如果你想知道这个话题有多热,我想让你知道何,深度学习中各种经典理论如残差网络、更快 R-CNN、空间金字塔池、特征金字塔网络等的发明者在他的博士研究期间研究了这个主题,并在他的论文和IEEE Transactions on Pattern Analysis and Machine Intelligence中提出了之前的暗通道(DCP)。
去雾算法有两种范式:传统方法和基于深度学习的方法。许多传统方法已经使用纯计算机视觉技术将手工制作的图形模型应用于去雾(例如,DCP),而基于深度学习的方法已经采用卷积神经网络(CNN)来解决去雾问题。然而,这些方法仍然有它们的缺点,并且总是有改进的空间。
这篇文章回顾了使用导向传输图(EDN-GTM)实现有效的单幅图像去雾的编码器-解码器网络。EDN-GTM 是一种新的方案,它利用传统计算机视觉技术和现代深度学习算法的能力来执行图像去雾。具体地,利用通过采用暗通道先验估计的透射图作为 CNN 模型的指南来执行去雾。论文全文可在 arXiv (预印本)或Procedia Computer Science 204(已发表论文)上找到。
作为 CNN 指南的传输图
暗通道先验(DCP)的去雾结果:(a)输入模糊图像,(b)通过 DCP 的去雾图像,©地面真实图像,(d)通过 DCP 的反转透射图。(纸张中的图像)
DCP 是基于无薄雾的室外图像的统计而提出的,因此,它在室内场景中不太有效,并且当薄雾图像包含看起来类似于空气光的大区域时可能无效。在上图中可以看到一个例子,当 DCP 试图在看起来像空气光和薄雾的墙壁场景区域中去雾时,从而提出了比地面真实图像更暗的输出图像。
然而,当重新思考由 DCP 产生的倒置透射图时,它们可以被认为是一种注意力图,其中较亮的区域指示密集雾度的区域,而较暗的区域指示不太雾度的区域(除了墙壁场景区域)。现在的问题是如何找到墙景区域?
哦,CNN 刚刚举手了!由于具有提取和分析图像特征的能力,CNN 可能是一个潜在的候选者。
有了这些强有力的证据,由 DCP 和 CNN 模型获得的透射图可以被统一以形成有效的霾去除系统。传输图“告诉”CNN 关注哪里。从这些建议区域,CNN 可以通过监督学习知道它应该更加关注哪些区域(例如,在输入和输出图像中墙壁场景区域没有太大不同,但是模糊区域不同)。
网络架构
图表和网络架构:(a)EDN-GTM 方案的图表,(b) EGN-GTM 设计,以及©鉴别器设计。(纸张中的图像)
上图显示了 EDN-GTM 方案以及发生器和鉴别器的网络架构。
发电机设计(EDN-GTM)
作为语义分割和图像恢复中最流行和最强大的网络之一,U-Net 被选为 EDN-GTM 方案的基础网络。为了获得 EDN-GTM 的架构设计,作者进一步将以下主要修改添加到网络中:
- 输入通道:传输图与图像的深度信息有着密切的关系,在去雾方案中起着重要的作用,然后它被用作网络输入的附加通道(与传统的 RGB 图像一起)。
- 瓶颈:通过使用一组具有不同内核大小的池操作,空间金字塔池(SPP)模块能够分离出最重要的功能,它被插入到基础网络的瓶颈中(就像它在 YOLOv4 object detector 的颈部使用的方式)。
- 激活:ReLU 在最近的 CNN 模型中逐渐变得过时,因此,ReLU 被 Swish 函数所取代,该函数已经被证明在现代深度网络中始终优于 ReLU。
- 感受野:去雾网络的感受野应该足够大,这是由于在模糊图像中霾(或雾)的扩散分布,因此在基本网络的每个卷积级中增加一个 3×3 conv 层。
鉴别器的设计
该方案选择 U-Net 的编码器部分作为鉴别器的结构。鉴别器设计的这种选择可以帮助两个网络(发生器和鉴别器)具有提取和分析输入图像特征的竞争能力,从而两个网络可以相互“战斗”以获得它们的性能。
损失函数
EDN-GTM 应用积分损失函数,该函数是对抗性损失、MSE 损失和感知损失的加权和。
对抗性损失
其中 B 是批量,z 是模糊图像,G 是发生器,D 是鉴别器。
MSE 损失
其中 N 是输入(输出)图像中的像素数,I 是干净的图像。
知觉丧失
其中 M 是预训练 VGG16 模型的层 Conv3_3 的特征图φ中的元素数量。
整体损失
积分损失是上述所有相关损失函数的加权和。
基准测试的结果
提供了去雾任务的四个基准数据集上的实验结果,包括 I-HAZE、O-HAZE、Dense-HAZE 和 NH-HAZE。下图显示了各种方法的典型视觉去雾性能。EDN-GTM 已被证明在可见度方面始终优于其他现代去雾方法。
视觉去雾的结果是:(a) I 雾度,(b) O 雾度,©致密雾度,和(d) NH 雾度。(图片来自论文)
下表显示了 EDN-GTM 和其他最新去雾方法的定量结果(红色和蓝色数字分别表示最佳和次佳性能)
来自纸张的图像
应用于对象检测
EDN-GTM 作为预处理工具应用于目标检测任务。比较了有雾和去雾图像的检测性能。实验中使用的数据集是 WAYMO 数据集。WAYMO 数据集不提供模糊图像数据,因此,通过应用本文帖子中描述的方法合成模糊图像。
合成模糊 WAYMO 数据集上的视觉去雾结果。(图片来自论文)
在两组模糊和去雾图像上的对象检测性能(红色:地面实况框,绿色:预测框,蓝色:放大区域)。(图片来自论文)
图片来自纸张。
结论
在这篇文章中,我简要回顾了 EDN-GTM,一种新颖的单幅图像去雾方案。EDN-GTM 利用纯计算机视觉和深度学习方法来形成一个统一的网络,以实现最先进的去雾性能。EDN-GTM 利用 U-Net 作为基础网络,并对网络进行各种修改,以便能够实现最佳去雾性能。EDN-GTM 的有效性已经在基准去雾数据集上得到验证。论文全文可以在 arXiv (预印本)或Procedia Computer Science 204(发表的论文)上找到。
欢迎读者访问我的脸书粉丝页面分享关于机器学习的事情:投入机器学习。我的其他著名帖子也可以在这里找到:
感谢您抽出时间!
教育是巴西人类发展的驱动力
原文:https://towardsdatascience.com/education-as-the-driver-of-human-development-in-brazil-e95f9f0124fe
巴西人口普查数据分析
图片: Freepik
T2010 年的上一次人口普查更新了衡量巴西各城市(MHDI)人类发展指数的数据。该国本应在 2020 年进行随后的人口普查,但主要是因为疫情,数据收集推迟了两年。疫情和经济危机的影响使人们对 2000 年和 2010 年人口普查中观察到的改善感到关切。虽然不可能与该国的现状进行比较,但如何从冰冷的数字和图形的视觉感受中更详细地了解过去的演变呢?
以下段落,尤其是下面的图片,对 1991 年至 2010 年间的变化进行了简要总结。这里我先做了 1991 年和 2000 年的比较,然后是 2000 年和 2010 年的比较。这个想法是通过 聚类 技术显示 MHDI 的变化之间的比较形成了哪三组城市,然后从组成 MHDI 的各种变量的变化中显示影响这三组城市框架的主要因素是什么。
1991 年和 2000 年的比较
下图显示了该算法如何在 1991 年至 2000 年间将巴西城市分布在 MHDI 的三个不同等级中。
MHDI 变差的分类。图片由作者提供。
在图表中,每个点都是一个自治市。在低变化等级中,紫色部分是 2167 个城市,它们的 MHDI 变化在 5.9%到 34.8%之间。浅绿色表示中等变化等级,集中了 2107 个 MHDI 在 34.81%和 53.7%之间变化的地点,在最后一个用黄色表示的类别中,其余 991 个城市的变化范围在 53.71%和 207%之间。
下面,我们可以看到 MHDI 三个不同等级的城市分布情况。
1991 年和 2000 年之间的地图和 HMDI 变化。图片由作者提供。
应用于地图的图例表明,自治市点的颜色越蓝,MHDI 越高,越红,值越低。颜色范围的变化发生在 0.5 的测量中,对应于我们开始考虑中等发展的 HDI 的值。
对地图的观察表明,MHDI 地区差异较小,同时 MHDI 值最高的城市集中在南部和东南部地区。另一方面,变化大的城市在 1991 年与非常低的 MHDI 联系在一起。2000 年,总的来说,这一阶层有所改善,一些城市甚至超过了中等发展人类发展指数点(人类发展指数> 5)。通过这种方式,可以看到一些带有蓝色阴影的城镇,这在 1991 年并没有出现。
MHDI 由 200 多个变量综合而成。一些因素可能对每个城市的指标演变产生了较大影响,而另一些因素则影响较小。因此,我使用了一个被称为 决策树 的程序,试图找出最相关的特征来确定上面显示的三组城市。
该算法指出了八个重要变量,它们都与教育有关。第一个是年轻人口的入学率。根据所使用的方法,这一变量比第二重要的变量,即 5 至 6 岁儿童的入学率,重要 2.28 倍。让我们来看图表。
年轻人口的入学率
使用四个指标来计算青年人口的入学率:5 至 6 岁儿童的入学率、11 至 13 岁儿童在小学最后几年的入学率、15 至 17 岁儿童完成小学教育的百分比以及 18 至 20 岁儿童完成高中教育的百分比。见下文该指标如何划分 1991 年至 2000 年 MHDI 的三类变化。
1991 年至 2000 年 MHDI 入学率变化的影响。作者图片
在上图中,我们可以看到,在参考年份 1991 年,三组的三种颜色在它们的位置上得到了很好的巩固。在他们的 MHDI 里,移动最少的城市,用紫色的点标出,在另外两个班级里,有着比其他城市高得多的入学率。更相关的是,运动最显著的城市,用黄色画的,占据了低 MHDI 和低入学率的空间。
另一方面,当我们看到 2000 年发生的情况时,黄色和浅绿色的点更接近紫色的点,从而表明这些群体中的城市在入学率指数方面取得了多大进展,以及这种进展对 MHDI 的改善产生了多大影响。
另一种观察这种运动的方式是通过下图。
1991 年至 2000 年 MHDI 入学率变化的影响。作者图片
人们可以在 1991 年观察到,黄点集中在一个象限,其特点是 MHDI 非常低,入学率很低。实际上,几乎没有一个城市的 MHDI 高于 0.4,学校出勤率高于 0.25。另一方面,在 2000 年,黄点很快出现在入学率高于 0.5 和 MHDI 高于 0.4 的象限中。还值得注意的是,在以高入学率和低 MHDI 率为标志的象限中,没有一个班级是他们的代表,这加强了这一组成部分在 MHDI 整体改善中的重要性。
5 至 6 岁在校人口
如前所述,衡量 5 至 6 岁儿童上学的百分比是青少年上学指标的一部分。根据我们的算法,这是通过 MHDI 的变化形成组的第二个最重要的变量。那么,让我们来看一个与这个指标相关的数字。
1991-2000 年间 MHDI 5-6 岁学生变化的影响。作者图片
很容易看到市政当局向右移动,特别是对于 MHDI 中高变化的城市。然而,我们也注意到,这种迁移对 MHDI 的改善并没有像青年人口频率指数那样产生强烈的影响。人们可以看到,所有群体都存在中等和高中入学率以及中等和低 MHDI 的城市。
2000 年和 2010 年的比较
十多年的文明进程改进带来了更多的蓝点和更少的关注点。但是,更重要的是,在 2000 年和 2010 年之间 MHDI 的变化所形成的群体中有一个区域性的重点。
2000 年和 2010 年之间的地图和 HMDI 变化。图片由作者提供。
上图显示,2010 年几乎没有 MHDI 点被归类为低发展。南部和东南部地区集中在两次人口普查之间差异较小的城市。最有可能的原因是,这些地区已经出现中高 MHDI 的频率更高,因此不会有更大的增长空间。另一方面,东北地区集中了 MHDI 变化最大的城市。
这种大约 20 年的转变促使我们将 1991 年与 2010 年进行比较,使颜色之间的对比更加强烈。我们会做这个比较,因为我们有数据。
1991 年至 2010 年间的地图和 HMDI 变化。图片由作者提供。
但是,2000 年到 2010 年之间的变化的重要变量是什么呢?同样,所有重要的因素都与教育有关。同样,年轻人口的入学率是最重要的,其次是 11 至 13 岁小学生的比率。让我们来看图表。
年轻人的入学率——第二部分
看看下面的点和颜色告诉我们什么。
2000 年至 2010 年 MHDI 入学率变化的影响。作者图片
不出所料,所有阶层的起点都远高于前十年的对比。我们再一次看到了所有不同班级的出勤率和 MHDI 之间高度相关的视觉亮点。
小学 11 至 13 岁学生的比例
同样,构成年轻人入学率的一个指标在人类发展指数变化组的定义中排在第二位。让我们看一下图表。
2000 年至 2010 年 MHDI 11-13 岁学生的影响变化。作者图片
当将 2000 年与 2010 年进行比较时,中低变化等级被压缩,对于中变化城市,可以清楚地看到 MHDI 向上移动。另一方面,对于高度变化的城市,点向右的位移与向上的位移一样大。这显示了适龄儿童接受初等教育对改善 2010 年观察到的 MHDI 的重要性。
该分析中使用的算法有助于发现构成 MHDI 数据库的近 17000 行和 230 列中的隐藏模式。这里我们只强调文本中最重要的变量的一个子集。
年轻人在学校的存在与年龄和学校阶段之间一致性的重要性之间高度相关的模式变得很明显。此外,在 2000 年和 2010 年的比较中,根据人类发展指数的变化划分的市镇群体的明显的区域成分也很突出。
总的来说,这些进步与其他几个变量有关。例如,一个更细心的研究人员可能想解释婴儿死亡率的大幅下降、收入的提高等等。仍有大量数据有待探索。恢复人口普查之前的这一时刻似乎是恢复巴西在 2010 年之前取得的进步并将其与极不稳定情况下的预期进行对比的大好时机。
如果对 MHDI 的数据感兴趣,非政府组织 Base dos Dados 可以从这个地址轻松获取这些数据。另一方面,如果你有兴趣知道我是如何使用算法或构建图形的,R 语言的代码可以在我的 GitHub 上找到。
使用 OpenBCI Ultracortex 的脑电图 101
原文:https://towardsdatascience.com/eeg-101-using-openbci-ultracortex-fbeb0202d0c5
使用open BCI—ultra cortex Mark IV EEG 耳机演示 EEG(脑电图)信号中的数据采集、数据滤波和去噪技术的教程。
图:1 (A)直接从 Ultracortex Mark EEG 耳机收集的未滤波 EEG 数据(B)带通滤波器(> 1Hz 和<50 Hz) ( C)Denoising with Fast Fourier Transform(FFT).
Modus Operandi
I have recorded live EEG※ from my own scalp using an Ultracortex Mark IV EEG 耳机 😃 Ultracortex 耳机共有 16 个通道,但在本教程中,我们将仅使用 8 个通道(图 2)。电极按照国际 10–20 系统放置,这使我们能够测量大脑皮层中潜在的电活动。
E 电极放置: Fp1 和 Fp2,测量额叶前部皮层的活动, C3 和 C4 ,来自顶叶的 P7 / T5 和 P8 / T6 ,颞侧的 O1 和 O2
图 2:使用基于国际 10–20 系统的 Cyton 板(8 通道)收集 EEG 数据。
Ultracortex Mark IV※可用于湿电极和干电极。它也可以被配置成作为有源电极或无源电极工作。但是对于这个实验的范围,我使用了干电极和无源电极的组合以及 Cyton 生物传感板 ※以 *250 赫兹(采样频率)*采样信号。
数据收集
在 *Python (Python 3.8.0: CPython 实现)*中,我们将使用 BrainFlow 用户 API ※ (BoardShim 类)进行数据收集,使用 Scipy(信号类)进行数据过滤和去噪技术。这两个软件包都可以通过 pip 安装在终端中,如下所示:
pip install brainflowpip install scipy
让我们开始编码吧!!( Github: collection.py )
- 库导入
import time
import argparse
import numpy as np
import pandas as pdfrom brainflow.board_shim import BoardShim, BrainFlowInputParams
2.串行端口和板 ID 配置
parser = argparse.ArgumentParser()parser.add_argument('--serial-port', type=str,
help='serial port', required=False, default='/dev/ttyUSB0')parser.add_argument('--board-id', type=int,
help='board id, check docs to get a list of supported
boards', required=False, default=0) ## Cyton board ID = 0)args = parser.parse_args()
3.用于加载配置的 BrainflowInput 参数 API
params = BrainFlowInputParams()
params.serial_port = args.serial_port
board = BoardShim(args.board_id, params)
4.记录实时脑电图数据流(时间间隔= 1 秒)
board.prepare_session()
board.start_stream()
time.sleep(1)
data = board.get_board_data(250*1) ## (250 Hz @ 1sec) ##
board.stop_stream()
board.release_session()
N 注意:get_board_data()
方法获取最新的板卡数据,并从环形缓冲区中删除这些数据。其他方法如**get_current_board_data()**
如果没有足够的数据,则获取指定数量或更少的数据,并且不从环形缓冲区中移除数据。
5.获取 Cyton 板所有活动 EEG 通道的列表
eeg_channels = BoardShim.get_eeg_channels(args.board_id)
eeg_names = BoardShim.get_eeg_names(args.board_id)
注:Cyton 板有 24 个通道来捕捉所有生物传感活动(体温、心跳等)。但在我们目前的设置中,我们使用的是 8 通道 EEG 配置:Fp1、Fp2、C1、C2、P7、P8、O1 和 O2。
6.将脑电图数据存储到 CSV 文件中
df = pd.DataFrame(np.transpose(data[:,1:]))
df_eeg = df[eeg_channels]
df_eeg.columns = eeg_namesdf_eeg.to_csv('data.csv', sep=',', index = False)
图 3:熊猫数据框架的前 10 行数据。
数据分解
EEG 信号可以分解成多个频段,每个频段都有独特的功能特征,如图 4 所示。这些子带的范围从被称为以 0.1 赫兹振荡的德尔塔波的极低频到被称为以 40 赫兹振荡的伽马波的高频。我们过滤掉其余的频率。※
图 4:脑电图中感兴趣的频谱(频域)。
在本教程中,我们将使用带通滤波器对数据进行滤波,这也是信号处理中最常用的滤波器。重要的是要注意,在应用滤波器后,信号会被衰减,即当频率成分被移除时,信号强度会有强度降低。人们可以在图 1 中观察到同样的情况;原始 EEG 和带通数据之间的幅度差异(V)。
N 注:为了简化计算,我们将只对其中一个通道进行预处理,即使用带通滤波器对 Fp2(前额叶皮层—右侧)进行预处理,并将其分解为各种其他子带。
让我们开始编码吧!!( Github: bands.py )
- 库导入
import pandas as pd
import matplotlib.pyplot as pltfrom scipy.signal import butter, lfilter, lfilter_zi
2.定义带通滤波方法
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype='band')
return b, adef butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
b, a = butter_bandpass(lowcut, highcut, fs, order=order)
zi = lfilter_zi(b, a) * data[0]
y, _ = lfilter(b, a, data, zi=zi)
return y
3.分解频带(α、β、δ、θ、γ)
sampling_frequency = 250df = pd.read_csv('data.csv')delta = butter_bandpass_filter(data = df.Fp2, lowcut = 0.1, highcut
= 4 , fs = sampling_frequency, order = 3)theta = butter_bandpass_filter(data = df.Fp2, lowcut = 4, highcut
= 8, fs = sampling_frequency, order = 3)alpha = butter_bandpass_filter(data = df.Fp2, lowcut = 8, highcut
= 13, fs = sampling_frequency, order = 3)beta = butter_bandpass_filter(data = df.Fp2, lowcut = 13, highcut
= 32, fs = sampling_frequency, order = 3)gamma = butter_bandpass_filter(data = df.Fp2, lowcut = 32, highcut
= 50, fs = sampling_frequency, order = 3)
4.数据可视化(图 5:脑电波分解)
fig = plt.figure(1)plt.subplot(6,1,1)
plt.plot(df.Fp2, linewidth=2)plt.subplot(6,1,2)
plt.plot(delta, linewidth=2)plt.subplot(6,1,3)
plt.plot(theta, linewidth=2)plt.subplot(6,1,4)
plt.plot(alpha, linewidth=2)plt.subplot(6,1,5)
plt.plot(beta, linewidth=2)plt.subplot(6,1,6)
plt.plot(gamma, linewidth=2)plt.show()
图 5:单个波形在不同频率下进行滤波,以展示其频率构成。
N 注:随着滤波器阶数的增加,滚降也会降低,从而大幅削减阻带频率,但更高的阶数也会在滤波数据中引入延迟。与当前值(即 3)相比,通过将上述代码中的顺序更改为 1,可以看到相同的情况。
用 FFT 对数据去噪
FFT 是信号处理中最受欢迎的算法之一,是数字通信、音频和图像压缩以及卫星电视中的一个重要组成部分。在本教程中,我们将利用快速傅立叶变换(FFT)算法从 EEG 数据的原始结构中提取噪声数据。
在收集 EEG 时,有许多假象频率被引入到波形中,这些假象频率不是由人脑活动直接产生的,因此降低了数据结构的锐度。FFT 帮助我们从草地(原始脑电图波形)中去除杂草(噪声)。由于数字(CPU、GPU)或生理假象(呼吸、脉搏和眨眼),这些微弱的频率很可能是在收集 EEG 时被拾取的。
F 人们也可以将 FFT 理解为信号从时域到频域的变换。
我们将通过 FFT 算法传递上一步过滤后的 EEG(带通滤波器),并希望找到 EEG 中最显著的频率成分。稍后,我们将过滤掉功率较低的频率(或“弱”频率)。我们将使用频率的功率谱密度(PSD)度量特定频率在给定 EEG 波形中对其形状的贡献有多重要。
让我们开始编码吧!!(Github:noise . py)
- 库导入
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.signal import iirnotch, freqz, filtfilt
2.使用带通滤波器(包括陷波滤波器)
df = pd.read_csv('data.csv')
band_pass_eeg = butter_bandpass_filter(data = df.Fp2, lowcut = 1,
highcut = 50, fs = 250, order = 3)b_notch, a_notch = iirnotch(w0=59.9250936329588, Q=20, fs=250)
filtered_eeg = filtfilt(b_notch, a_notch, band_pass_eeg)
3.计算傅立叶系数(复数值):
number_of_points = len(filtered_eeg)fhat = np.fft.fft(filtered_eeg, number_of_points)
PSD = fhat * np.conj(fhat) / number_of_points
freq = (1/(0.004*number_of_points))*np.arange(number_of_points)
L = np.arange(1,np.floor(number_of_points/2),dtype='int')
4.用 PSD 滤除噪声
indices = PSD > 150
PSDclean = PSD * indices
fhat = indices * fhat
ffilt = np.fft.ifft(fhat)
5.数据可视化(图 6:降噪和噪声数据的功率密度)
fig,axs = plt.subplots(3,1)data_points = np.arange(number_of_points)plt.sca(axs[0])
plt.plot(data_points,band_pass_eeg, color='k',linewidth=1.5,
label='Bandpass filter')
plt.xlim(data_points[0],data_points[-1])
plt.legend()plt.sca(axs[1])
plt.plot(data_points,ffilt,color='b',linewidth=2,
label='FFT Filtered')
plt.xlim(data_points[0],data_points[-1])
plt.legend()plt.sca(axs[2])
plt.plot(freq[L][3:75],PSD[L[3:75],color= 'r',linewidth=2,
label='Noisy')plt.plot(freq[L][3:75],PSDclean[L][3:75],color='b',linewidth=1.5,
label='Filtered')
plt.legend()
plt.xticks(freq[L][3:75:5])
图 6 —(A)来自带通滤波器的数据,( B)通过 FFT 后的数据,( C)噪声和干净数据的 PSD。
尽管我们有嘈杂的数据,但在θ、α和β光谱中有一些清晰的峰值,这是显而易见的,因为我在收集我的大脑数据时处于完全警觉状态:)(图 6 — ©)。
我们选择功率的截止值为 150,因此强度小于 150 的所有频率都将从信号中截止。去除噪底后,信号更加清晰锐利。
F 最后注意:预处理 EEG 数据时需要小心,因为它可能会改变事件相关电位的时间结构,可能无法绘制出准确的大脑反应。过滤会改变你的数据,因此,根据一般经验,过滤越少越好。
我想衷心感谢 Titiksha Bhardwaj 在本教程中设计了以上所有的视觉效果。没有她,这样有见地的插图是不可能的。谢谢:)
※参考文献:
- 定义脑电图(维基)
- 10–20 脑电图采集国际系统(维基)
- OpenBCI — UltraCortex 耳机设置
- OpenBCI Cyton 生物传感板
- 人才流动—用户应用编程接口
- 脑电信号的频谱信息(EURASIP-信号处理进展杂志)
- 用 Python 去噪 (databook.uw — Steve Brunton —华盛顿大学)
Eeny Meeny Miny Moe,最好了解哪个数据科学平台?
研究不同的数据科学平台和 ide 以及何时学习它们
图片来自 Pixabay,作者 geralt
选择正确的平台来专注于您的数据科学教育是一项挑战,因为当今进行数据科学的平台无处不在。但情况并非总是如此。不久前,唯一可用于测试数据科学的是 IPython 或交互式 Python。命令行 shell 为不同的代码块提供即时反馈。
使用命令行进行数据科学的问题在于,数据科学活动需要能够看到输出,无论是数据本身、正在创建的变量还是分析结果。尽管 Python 作为一种编程语言很有用,但它还没有达到适用于典型数据科学家的可用性。
Python 作为一种编程语言诞生于 80 年代末,在 90 年代初开始普及,并随着 2000 年 Python 2.0 的发布开始被后端数据开发人员所采用。直到 2009 年,随着 Anaconda 和面向数据科学的“集成开发环境”(IDE) Spyder 的出现,Python 才真正开始成为数据科学的“语言”。
在短短的 12 年里,IDE 和数据科学平台的数量激增,以至于学习该领域的人很难知道应该关注哪个 IDE 或平台。在本文的剩余部分,我将回顾 IDE 和平台之间的区别,介绍不同的产品,并解释我认为每种产品在开发数据科学家的教育旅程中都属于什么位置。
它是一个平台还是仅仅是一个 IDE?
数据科学家花大量时间研究数据。在许多情况下,这些研究活动的结果会成为可交付成果(如幻灯片)的基础。因此,数据科学家要求他们的开发环境在视觉上对满足这些目标有用。
Spyder 是第一个在编程和视觉上都非常有用的 IDE。Spyder 是由科学家为科学家开发的,并成为与 Anaconda 打包在一起的默认 IDE(下面将详细介绍这个数据科学平台)。
但是 Spyder 等 ide 都不是平台。它们是图形用户界面(GUI ),帮助程序员和数据科学家开发解决 Python 代码问题的解决方案。
另一方面,平台是将多种服务集成到一个框架中的产品,该框架通过抽象或自动化用户可能需要的一些技术要求来处理复杂的任务,从而使用户能够实现这些不同的服务。
在数据科学中,最受欢迎的 ide 包括 Jupyter Notebooks、Spyder、PyCharm 和 Sublime Text(但在这里可以看到更多)。平台致力于与这些 ide 集成,以支持额外的数据科学需求,如包依赖性管理、计算资源、安全性和模型部署。例如,Anaconda 可以被认为是一个数据科学平台,因为它有助于管理包的依赖关系,提供了多种 ide 用于开发,并且包括对它们自己的包存储库的访问。
一些最大、最受欢迎的数据科学商业平台包括 DataBricks、Amazon Sagemaker、Dataiku 和 IBM 的用于数据的 CloudPak。
在接下来的几节中,我将典型的数据科学学生的学习之旅分为 3 个简化的关键时期,并讨论应该重点关注哪些 ide 和平台,以成功克服这个关键点并提高数据科学技能。
关键期#1:学习数据科学基础知识(Python,数据角力,&模型训练)
对大多数人来说,成为数据科学家的第一步需要学习如何使用代码来访问和操作数据。因为 Python 已经成为行业中最受欢迎的数据科学编码语言,并且代表了满足最大数量的职位空缺的一种技能,所以现阶段的重点应该是创造一个允许个人在数据环境中学习 Python 基础知识的环境。
最简单的平台是 Anaconda,它允许从您的笔记本电脑上最快速地访问 Python,包括公共数据科学库,并且包括基于 GUI 和基于浏览器的 ide。Anaconda 对个人使用也是免费的,因此对于学习数据科学的初级阶段来说,它是最容易访问的数据科学平台。我只希望在我刚开始的时候有人告诉我这些😉
为什么是 Anaconda 而不仅仅是 Python 的基础实现?
当我刚开始学习数据科学时,Anaconda 是全新的,人们对它的全部功能知之甚少。因此,我不得不遵循需要下载 Python 解释器的教程和建议,它也有自己的 IDE,名为 IDLE 。从命令行在 IDLE 和 Python 解释器之间工作很麻烦,经常导致包依赖冲突,并且很少提供可视化体验来快速观察我的代码如何影响我试图处理的数据。
Anaconda 通过帮助执行环境扫描来处理所有这些问题,环境扫描增加了包不冲突的可能性,并且提供了一个虚拟环境库,以防我们需要访问与主环境中安装的现有库冲突的包。尽管虚拟环境超出了本文的范围,但是要了解为什么虚拟环境有用的更多信息,请参阅这里、这里和这里。
此外,Anaconda 还附带了 Spyder 和 Jupyter IDEs。Spyder 对我来说更熟悉,我在学术界使用 SPSS 和 SAS,Jupyter 提供了更丰富的视觉体验,因为它是基于浏览器的,可以利用互联网浏览器的交互功能。
此外,Jupyter 也是最受欢迎的 ide 之一,它与 Sagemaker 和 DataBricks 等企业级数据科学平台相集成。
要点:Anaconda 是开始学习数据科学的最佳环境。我强烈建议学习 Jupyter 和像 Spyder 这样的 ide 的优点,因为它们提供的优点略有不同,正如我提到的,Jupyter 是主要企业数据科学平台的主要 IDE。
最后,Anaconda 预装了几个非常有用和常用的数据科学库,如 Pandas、Scikit-Learn、NLTK 和 Numpy。因此,作为一个学习平台,Anaconda 代表了从您的笔记本电脑开始学习数据科学基础知识的最佳场所之一。
关键时期#2:扩大计算资源以训练“更大”的模型
随着数据科学家学习数据访问、争论和模型训练的基础知识,下一步通常是希望用需要更多计算资源或 GPU 等新计算资源的数据来训练模型,这是用图像或文本训练深度学习模型时经常出现的情况。正是在这一点上,数据科学家认识到 Anaconda 的本地安装受限于他们本地笔记本电脑的处理资源。因此,提升我们的数据科学技能通常也意味着提升我们的计算需求。
正是在这一点上,世界变得更加复杂,可能也更加昂贵,尽管我将分享一些方法来将您的数据科学平台预算保持在最低水平。当然,您可以选择购买一台新的、功能更强大的笔记本电脑,但也有更便宜的替代方案,并且可以学习新技能,这些新技能通常与业务环境中的数据科学需求相重叠。
有几种解决方案允许数据科学家访问比大多数个人笔记本电脑计算能力更强的环境。例如,Google CoLab 提供对基于 Jupyter 笔记本的云环境的免费访问。免费层功能强大,用户可以访问 12 GB 的 RAM 和一个 GPU。在本文发布时,您可以分别以 9.99 美元和 49.99 美元的价格订阅 CoLab Pro 或 Pro+来提升计算能力。
CoLab 的一些限制包括非持久性磁盘,这意味着一旦笔记本电脑关机,数据就会被删除,有限的运行时间取决于订阅级别,以及当重新启动笔记本电脑时,任何新安装的库都需要重新安装。
用于扩展计算资源的其他基于平台的选项包括 AWS Sagemaker、微软 Azure 的 DataBricks 或 IBM 的 Watson Studio。但是请注意,其中每一项都与一些成本相关联,包括租赁虚拟机的成本、利用数据科学平台的成本、将数据存储在 it 可访问的位置的成本,或者以上所有成本。例如,对于 Sagemaker 平台,AWS Sagemaker 没有成本,但是如果您在计算量超过空闲层的虚拟机上启动该服务,您将会产生成本。根据分配给虚拟机的磁盘大小,您还会产生数据存储成本。或者,DataBricks 收取平台使用费,外加租用运行您正在使用的 DataBricks 机器的虚拟机的 Azure 成本。因此,管理实际成本对你来说是一个挑战。
到目前为止,我们一直专注于支持更多计算的平台,但我们注意到,每个平台都抽象出一些用于支持开发人员需求的服务,这对您理解成本带来了一些挑战。
但是平台不一定是你在这个阶段的唯一选择。
出于上述许多原因,我在自己的工作中经常使用的一种替代方法是从云提供商那里租赁自己的虚拟机,并启用远程桌面连接,这样我就可以像在自己的桌面环境中一样在该虚拟机上工作。虽然设置不像上面的平台提供的那样简单,但这确实意味着我的成本更加透明,我可以完全访问 VM 的操作系统,因此可以添加其他有用的软件来满足不同的开发需求,并且我可以学习一些关于网络的知识。
设置好之后,我就可以再次利用 Anaconda 来满足我的大部分开发需求,并且可以控制服务器的大小以及维护它的成本。例如,在 GCP,我可以以 0.067006 美元/小时的价格租用一台带有 2 个虚拟 CPU 和 8GB 内存的虚拟机。如果我选择使用现货虚拟机,成本是价格的 1/3。只要我不忘记在不使用时关闭虚拟机,我就能够控制成本,同时最大限度地访问强大的计算资源。我唯一需要支付的是我的数据的谷歌云存储费用。请注意,云平台也对数据传输收费,每个云提供商对收费有不同的规定,因此请确保监控您的数据传输需求。
如果您有兴趣了解更多关于使用云虚拟机设置自己的数据科学环境的信息,请查看我在这里整理的指南。
总之,使用云提供商构建您自己的虚拟机,同时学习云服务的工作方式,可以为您的数据科学知识增加显著优势,并最终使您对潜在雇主更具吸引力。简而言之,您将获得理解不同服务使用的成本后果的第一手经验。
关键点#3:获得数据科学工作并实现模型需要部署
假设您已经在上述 ide 和平台上进行了最大限度的实验,现在对您的数据科学技能非常有信心,并准备开始申请工作。或者你甚至找到了一份工作。当谈到数据科学的业务应用时,与数据科学平台相关的下一个考虑因素是什么?
在商业环境中,数据科学要产生影响,通常需要“生产化”我在这里的意思是,您的数据科学代码需要从研究和模型实验/培训阶段进入使用模型对新业务数据进行评分的阶段。换句话说,我们需要找出吸收和准备数据的部署选项,然后用我们的模型对数据进行评分,最终将这些结果公开给使用模型结果的下游流程。
正是在这种背景下,我们遇到了快速增长的 MLOps 领域,这是一种 DevOps,但特别适合数据科学任务和模型管理。这也是大多数年轻数据科学家经验最少的领域。这也是数据科学平台具有真正商业价值的地方,因为它们帮助数据科学和 MLOps 团队跟踪他们的实验,并将模型管道部署为计划任务或可按需调用的 API 服务。
无论是哪种情况,Sagemaker 和 DataBricks 等数据科学平台都提供了支持模型管道代码部署的简单工具。但是,每个平台在实现部署方面都有自己的细微差别,并且每个平台都有不同的相关成本。因此,选择一个来学习是不太有用的,除非你为已经使用该平台的公司工作。
如果您发现自己正处于数据科学学习之旅的这一阶段,我强烈建议您更多地关注学习 MLOps 的一些基础知识,例如构建逻辑有序、模块化、遵循良好编码实践并可通过 Github 共享的代码项目。
结论
总之,有几种不同的数据科学平台和 ide 可供年轻的学习数据科学家使用,知道将注意力集中在哪里可能是一个巨大的挑战,因为许多平台甚至提供“免费”的试用版本。请小心,即使平台可能是免费的,平台使用的虚拟机和存储也可能不是免费的。因此,我强烈建议专注于使用 Anaconda 平台构建您的基础,确保同时使用笔记本和 ide 进行实验。这样做可以让你为你可能接触到的平台做好准备,因为你的数据科学爱好会变成数据科学职业。
比如参与学习数据科学、职业发展或糟糕的商业决策?加入我。
机器学习的有效测试(第三部分)
原文:https://towardsdatascience.com/effective-testing-for-machine-learning-part-iii-7bdb557711ab
测试 ML 系列
机器学习的有效测试(第三部分)
用于开发健壮的 ML 项目的渐进的、逐步的框架
图片作者。
在前两部分(第一部分和第二部分,我们描述了一个框架,通过逐步增加更全面的测试来增加我们项目的健壮性。从冒烟测试到集成测试,我们从一个基本项目过渡到一个确保生成高质量模型的项目。
这最后一部分总结了这个系列,有三个目标:
- 定义一个策略来决定每当我们遇到问题时添加什么测试。
- 描述加速测试执行的策略。
- 为选择开发可测试 ML 管道的工具提供建议。
测试的分类
让我们回顾一下我们在前两部分中介绍的测试类型:
1。集成(数据质量)测试
1.1.检查数据属性(即age
列中没有NULL
值)。
1.2.分布变化(即,确保我们的目标变量的分布不会发生剧烈变化)。
1.3.模型质量(即检测模型性能的突然下降/上升)。
2。单元测试
2.1 检查训练和服务管道之间的一致性(又名训练-服务偏斜测试)。
2.2 检查数据转换的正确性(给定一些有代表性的输入,测试数据转换的输出)。
2.3.检查模型文件和推理管道的兼容性。
工作流摘要
我们希望我们的测试快速失败,所以我们将首先运行单元测试(训练服务偏斜和数据转换)。如果它们通过了,我们继续运行带有数据样本的管道(集成测试);如果成功,我们使用生成的模型文件,并检查与推理管道的兼容性;我们在下图中描述了完整的流程:
图片作者。
请注意,我们建议每晚对整个数据集重复相同的过程;但是,时间间隔越短越好。
集成与单元测试
一个关键的区别是集成测试依赖于训练数据,因为它们评估其质量。相反,单元测试不会,因为它们评估我们代码的正确性。因此,我们可以用几个有代表性的例子来检验它们。
这种对训练数据的依赖对定义我们的测试策略有影响。理想情况下,我们希望我们的集成测试检查我们的整个数据集。然而,这是不可行的,所以我们求助于随机抽样(比如 1%)来快速测试数据质量。虽然有效,但这种随机抽样方法只是我们在整个数据集上测试所得的近似值。
另一方面,由于单元测试不依赖于我们的训练数据,我们可以使用一些有代表性的输入进行测试;因此,预期的运行时间应该很短(不超过几分钟)。此外,由于单元测试运行速度很快,它们应该是您测试的第一件事,所以如果单元测试有问题,您不必运行昂贵的集成测试。
因此,总的来说,我们应该把测试套件(带有随机样本的集成测试和单元测试)的运行时间控制在 20 分钟以内。
现在让我们描述一个策略,当我们遇到一个错误的时候,决定执行什么测试。
未来测试的策略
我们的策略取决于具体情况;让我们来看看每一个:
当集成测试崩溃时
数据属性
假设数据属性失败(例如,一列突然有了NULL
值)。在这种情况下,有两个选择:更新您的代码以过滤掉违规的记录(这将导致测试通过),或者放松测试(例如,删除测试以允许NULL
值,或者允许某个百分比)。决定将取决于你的用例:也许你决定做数据插补,所以你决定允许一些NULL
值;另一方面,您可能确定您不能估算数据,在这种情况下,更新代码以过滤掉违规记录。
分布变化
如果数据分布发生变化,您必须确定这种差异是由于数据生成过程中的实际变化,还是由于某些数据接收或数据转换错误。例如,假设您发现了age
列中的差异:中位数age
是 25,现在是 40。可能是目标人群变老了,你现在必须更新你的参考值。另一方面,也可能是上游数据转换发生了变化,它传递了您不应该使用的记录;如果是这种情况,您可能需要检查上游流程,以过滤掉改变数据分布的新记录。
模型质量
一旦你在生产中有了第一个模型,改进通常是小幅度的。因此,每当模型质量出现显著下降或上升时,调查它是很重要的。正如本系列的第二部分所提到的,您需要一个基准模型来评估当前模型的质量;这通常是生产中的当前模型。
性能的突然下降意味着丢失了一些集成测试(因为集成测试应该在进入模型训练任务之前检测低质量的数据)。相比之下,性能的突然显著提升可能表明存在泄漏等问题。
如果您的模型性能比基准差得多,请比较用于训练当前模型和基准的代码,以确定发生了什么变化(例如,删除了某个特征,更改了超参数)。另一方面,如果模型的性能比基准测试好得多,检查代码变更并确保没有任何问题,比如泄漏。如果您没有发现任何问题,那么恭喜您,您刚刚使您的模型变得更好了!接受变更并更新基准指标。
如果您在调查后发现培训管道有问题,请将其转化为集成测试。例如,如果您的模型变得更差,因为您在具有NULL
值的列上对其进行了训练,那么为其添加一个集成测试。添加测试后,修复管道,并确保更改修复了性能问题。
请注意,我们建议使用数据样本在每个git push
上测试您的管道,以使其切实可行;然而,这意味着输出训练集将变得更小,使得评估性能变得更具挑战性。如果可能的话,根据在相同样本大小上训练的基准模型,评估在数据样本上训练的模型的性能。然而,如果这样做很有挑战性(例如,不同实验之间的性能差异太大),您可能会决定只在夜间运行模型质量测试。
当单元测试失败时
训练-发球偏斜
如果您的训练-服务偏斜测试失败,比较您的训练和服务管道的输出,直到您发现结果不同的第一步。一旦您发现了问题,修复它并继续运行测试,直到它通过所有的样本输入。这种一步一步的调试过程是我们需要构建模块化管道的原因:如果我们在单个笔记本/脚本中编写整个项目,将很难发现这些问题。
例如,下图显示了以不同方式处理输入的管道(它们生成不同的特征向量)。因此,一旦您检测到问题,请向后检查输出,直到您发现差异为止;在这种情况下,问题在于Process input A
步骤,因为它在训练(2
)和发球时间(10
)产生不同的结果。
图片作者。
数据转换
如果一个数据转换(通常是一个单一的函数)测试失败了,那一定是由于转换的源代码发生了变化。有时,我们在优化一个转换时会犯错误(例如,为了更有效地利用内存),单元测试允许我们检测它们。然而,其他时候,我们可能会改变转换的行为。因此,单元测试中的输入样本将不再具有代表性。在任何情况下,都要确保确定哪种场景适合您,并修复源代码或更改示例输入。
请记住,您的单元测试应该是不断发展的。因此,每当您发现一个边缘案例时,确保您添加了一个新的输入测试案例:单元测试应该覆盖您的转换应该考虑的所有代表性的输入案例。
模型文件和推理管道
您的推理管道捕获将原始数据转换为模型用作输入的特征向量所需的预处理逻辑;这两个元素可能会不同步。例如,你可能有一个特征训练的模型文件[A, B, C]
(按此顺序)。尽管如此,如果您最近更新了您的推理逻辑,它可能会以不同的顺序生成要素(比如说,[C, B, A]
),这会中断您的推理过程。您通常可以通过使用相同的 git 提交生成模型文件来修复模型文件和推理管道之间的不兼容性;然而,有必要运行这个测试,以确保您不会部署不兼容的工件。
加速测试
单元测试应该运行得很快(几分钟),因为它们是用几个有代表性的输入运行的。然而,快速运行集成测试是具有挑战性的,因为它们依赖于训练数据。为了有助于这一点,我们用随机样本运行训练管道;但是,这可能无法检测出整个数据集中存在的问题。
例如,如果我们测试数据属性,比如没有NULL
值,如果我们用 1%的数据对整个数据集进行测试,测试结果可能会改变。分发也受到影响;用较小的样本进行测试会增加假阳性的变化(在没有差异的情况下检测到差异)。此外,用数据样本评估模型性能几乎肯定会给出一个度量更差的模型。
为了平衡运行时间和测试健壮性,我建议如下:用最广泛的数据样本运行集成测试,这仍然给你一个合理的测试运行时间(我认为不超过 20 分钟)。最重要的是,尽可能频繁地安排完整数据集的运行。例如,如果使用整个数据集端到端地运行培训管道需要 2-3 个小时,则可以在夜间运行。
最重要的是,您可以利用增量构建:假设您已经计算并存储了来自管道的所有结果;如果只改变最后一步,就不需要从头重新运行一切。因此,相反,只执行自上次运行以来源代码已经更改的步骤。不幸的是,并不是所有的管道框架都支持这一点(但是 Ploomber 支持!).然而,增量构建极大地加快了开发和测试的速度。
处理昂贵的培训程序
在某些情况下,训练过程可能需要很长时间才能完成(例如,深度神经网络)。如果是这种情况,您可以使用代理模型进行测试(例如,如果您的神经网络有十个隐藏层,则使用其中三个的代理模型)。如果你的训练数据有问题,很有可能代理模型也会表现出较低的性能。
选择正确的工具
当测试我的 ML 项目时,我发现最大的挑战之一是缺少合适的工具。我们设计了 Ploomber 来支持这个测试工作流程(所以我们强烈建议您尝试一下!),但是这里有一些选择框架时的一般建议。
本地执行
通常,被设计成分布式运行的框架(例如,在 Kubernetes 上)没有在单节点环境中执行管道的简单方法;依赖外部基础设施使测试变得复杂。因此,最好使用允许您在单节点环境中运行代码的框架。测试应该像启动一台机器并调用:
可输入管道
测试需要一些配置和准备;例如,您可能需要创建一个临时目录来运行带有示例的管道。像 pytest 这样的测试框架允许你这么做。测试的典型结构是这样的:
要使用测试框架,您应该能够使用 Python 导入和运行您的管道,因此确保您将使用的库允许您这样做。测试可能是这样的:
参数化
您的培训管道必须公开参数,以允许您使用不同的配置运行它们。测试时,您希望使用数据样本运行测试,并将任何结果存储在单独的文件夹中,以防止覆盖您的结果,因此请确保您使用的框架允许您对管道进行参数化:
最后的想法
测试 ML 管道是一项艰巨的任务:大型数据集和长训练周期为确保测试在合理的时间内运行带来了巨大的挑战。然而,简单的测试策略,比如冒烟测试和用小的随机样本进行测试是有回报的,所以确保你实现了那些基本的策略,并且随着你的项目的成熟而转向更高级的策略。
开发可测试项目的一个基本要求是模块化您的工作。在单个文件中包含整个数据处理逻辑的单块笔记本是测试和维护的噩梦,所以请确保您使用的框架允许您将逻辑分解为小步骤,以便您可以单独测试每个步骤。
我作为数据科学家的经历启发了这些指南;然而,这是一个不断发展的领域,所以如果你有任何问题或者想聊聊关于 ML 测试的所有事情,加入我们的社区!
发现错误?点击这里让我们知道。
最初发布于ploomber . io。
有效平衡客户和数据科学家之间的产品需求
意见
共同管理如何帮助您的项目
照片由 Unsplash 上的 Aziz Acharki 拍摄
在项目管理中,有一个被称为合作经理模型的概念,它为客户和技术团队提供了管理项目的同等权力和责任。这意味着技术产品经理必须愿意与客户产品经理分担项目的责任。有了这些,花点时间思考一下,如果我的团队是数据科学/技术产品团队,那么谁是我的客户端产品团队?
在之前的一个角色中,我在一个客户的技术团队中工作,该客户了解如何进行数据分析,但需要一个技术团队来开发机器学习和分析,以推动他们的仪表板。为了管理这种约定,在运行项目时,在技术联合经理和客户联合经理之间形成平衡变得至关重要。我们的最终目标是为设备运行状况管理制作仪表盘,显示哪些设备存在高问题风险,哪些设备与可接受的设备相比需要关注。
为了处理这两个团队之间的联系,每周,我们都通过电话讨论项目状态、后续步骤和演示。开始时,会议双方关系紧张。客户觉得他们没有从产品中得到他们期望的东西,而技术团队觉得他们达到了他们的目标。当团队要求对正在完成的工作进行反馈时,这种冲突导致缺乏充分的参与。在认识到这些问题的几个月内,我们授权客户的产品经理在项目中承担更多的责任,并开始根据他们的业务案例和他们期望的结果做出决策。
我们通过分解我们的技术工作和术语方面的挑战来做到这一点,这些术语可能与客户的设备健康监控有关。本质上,我们遵循了可解释人工智能的四个原则:
知识 限制:系统仅在其设计条件下运行,或者当系统对其输出达到足够的置信度时运行。
我们创建的控制面板仅适用于特定的设备子集,分析师正在研究这些设备的运行状况管理。这缩小了项目范围,允许我们在已知的条件下操作来创建我们的模型。这项工作是事先商定的;我们只需要对客户所要求的这些条件进行解释。
解释:系统为所有输出提供附带的证据或理由。
我们创建了仪表板,显示关于模型如何到达的足够多的细节,以得出设备是否健康的结论。我们允许分析师向下点击底层数据,以查看维护活动用于达成模型的决策。通过允许分析师向下点击底层数据,他们得到了支持模型输出所需的证据。这些数据为他们看到的输出提供了解释。
有意义的:系统提供个人用户可以理解的解释。
允许分析师看到基础数据以及模型对健康状况好坏的预测是好的,但它需要对客户有意义。结合起来,不同屏幕的 UI 易于导航,每个级别都以分析师的术语向他们提供了详细的解释,说明分析是如何形成的,以及他们如何理解该输出以做出关于设备分组的决策。
说明 精度:说明正确反映了系统产生输出的过程。
伴随着解释和意义而来的是对准确性的需求。一旦我们产生了这些输出,我们就在每周的电话中演示结果。正是在这些演示中,客户反馈变得很重要。通过他们的领域专业知识和我们的模型,我们可以评估结果的准确性,并根据客户对他们所见的反应做出改变。此外,我们将他们的手动分析重新创建为可解释的机器学习模型,以提高生产率。他们对我们的建模理解得越多,反馈就变得越好,因为他们可以根据他们的领域知识提供特性请求和改进。此外,它允许团队之间更好的协作,以提高仪表板输出的整体可解释性。
在合同进行到一半时,我们的客户更好地理解了所展示的仪表板演示,以及它们背后的算法是如何做出决策的。通过更好的解释和沟通,我们可以使用客户的语言建立一个开放和诚实的沟通渠道。这种变化意味着客户对项目的方向承担了更多的责任,并提供了有价值的反馈,告诉他们什么工作符合他们的预期,什么工作不符合他们的预期。既然客户理解了我们所展示的内容,他们就可以根据他们的行业领域知识和经验提供意见。这个反馈允许我们产生一个实用的解决方案,为使用仪表板的分析师创造预期的业务价值。这种变化也使团队能够积极地参与所有的决策和需求变更,以实现这些目标。
最终想法
数据科学家经常与业务分析师和客户密切合作,他们需要了解他们的工作以及工作对他们的影响。有了这个,团队需要确保客户处于最佳位置,以创建有益于项目的有意义和及时的决策。通过用客户的语言解释您的数据科学流程,并确保他们理解您的算法如何预测事件,可以促进这些行动。通过提供所有这些信息,您可以帮助您的客户做出决策,并拥有他们所支持的产品。此外,它为两个团队创建了一定程度的所有权,并允许他们感觉他们为路线图的成功做出了贡献。
感谢阅读!我希望你喜欢阅读我所学到的东西。如果你愿意,你可以通过这个链接成为一名灵媒来支持我的写作。