如何通过简单的电源自动化来计划无限制的电源 BI 数据集刷新
来自 Unsplash.com 的斯蒂芬·菲利普-Hostreviews.co.uk
如何在不到五分钟的时间内设置自动刷新而无需直接查询
为什么您不能总是对您的 PowerBI 使用直接查询
通常,数据工程师会建议您在 Power BI 报告中使用直接查询。这种解决方案(可能)是最用户友好的,因为它使用户能够通过一次点击来刷新数据和视觉效果。然而,有许多技术原因为什么直接查询可能是不可能的。最常见的问题可能是这个:你的数据有不止一个来源。
Power BI 的直接查询选项仅在您的 BI 数据集基于单一来源时有效。目前,您的报告需要两个或更多来源,不再支持直接查询。虽然这对于拥有发达的 IT 基础设施和训练有素的数据工程团队的组织来说可能不是问题,但对于其他组织来说却是一个巨大的挑战。许多组织使用 Power BI,因为内置的数据建模工具使得在不应用全面的 ETL 过程的情况下组合不同的数据源变得容易。如果您想不出适用的场景,请考虑以下商业案例:
您的销售团队使用 Salesforce 跟踪他们的销售线索并维护客户信息。然而,财务部使用一种小型会计软件,这种软件是根据您所在地区的要求量身定制的。
财务部门现在希望将客户、渠道和财务数据整合到一份报告中。在大公司中,数据工程团队会将不同的系统连接到一个仓库,并创建一个包含所有需要的信息的表。
但是,您的公司很小,而且您没有数据工程团队。您的会计软件太不知名,不提供 Salesforce 的标准连接器。
因为您希望避免在外部程序员身上花钱,所以您将不同的源连接到您的 Power BI,并通过数据建模器自己进行映射。因此,直接查询选项被禁用,您的用户无法再通过报告的刷新选项更新数据和图像。
以下是你解决这个问题的方法…
如果不能使用直接查询,用户必须手动刷新数据集。虽然这不仅耗时,而且几乎不可能。大多数情况下,最终用户无法访问报表的基础数据集。换句话说,他们必须向报告管理员请求手动刷新…浪费更多的时间。
你们中的一个会跳起来说:为什么不在 Power BI Pro 中简单地安排刷新?这是个好主意,但是你每天只能刷新 8 次。
那还有什么?正确!**我们可以升级到高级,这样我们每天最多可以安排 48 次刷新。**虽然对于大多数用例来说这可能已经足够了,但这只能让您每 30 分钟刷新一次数据集。如果你想达到接近实时,这是不够的。通过 Power BI cloud 界面设置 48 个日程安排也是一项痛苦的手动工作。相信我,我尽力了。
…您应该这样做!
你需要的东西
在您开始实现您的 Power Automate 流程之前,您需要进行一些采购。给你自己买以下两件东西(不,我不会因此得到任何会员奖金):
如何实现它
首先,将您的报告发布到您的高级工作区或用户。您可以识别用户或工作区是否是高级的,如果它有一点💎名字旁边的。但是,您只能在 web 界面中看到这一点。因此,我建议您在发布报告之前检查一下。
现在,登录到您的 Power Automate web 界面,点击“我的流程”。之后,点击“新建流量”并选择“预定云流量”选项。
新的预定云流量选项。图片作者。
然后会要求您提供名称、开始时间和流程间隔。随意输入,点击创建。
预定云流量选项。图片作者。
您已经成功创建了流程,并将看到一个新页面。在这里,单击“+New step”选项,并在搜索栏中键入“刷新数据集”。然后点击 Power BI 动作“刷新数据集”。
相应的操作将作为下一步成功添加。**现在,您可以在相应的字段中选择您的工作空间或用户以及您的目标数据集。**然而,根据您的系统设置,Power Automate 会要求您首先登录 Power Bi。提供您的凭据,然后单击“保存”。
刷新数据集操作。图片作者。
恭喜你!您已经成功设计了一个 Power Automate,它将在指定的循环中刷新目标数据集,而无需任何额外的手动工作。
如果您不确定计划的刷新是否真正起作用,您可以在最后一步检查您的流的运行历史。您可以通过点击流的名称并向下滚动来实现。在这里,您将看到已执行运行的历史记录。如果运行成功,状态将为绿色。
流程运行历史记录。图片作者。
对于所有多疑的人来说:你也可以在 Power BI web 界面上查看。只需单击您的工作区或用户(您发布报告的地方),并查看相应的数据集列。**你会看到“刷新”下的条目会显示与你的工作流程大致相同的时间。**由于刷新本身可能会出现时差,所以不必担心。这是完全正常的。
Power BI web 界面中刷新的数据集和报告。图片作者。
如何用 Python 熊猫刮 HTML 表格
数据收集
一个现成的代码,它利用了 Python 熊猫库的 read_html()函数
几乎所有在 Python 工作的数据科学家都知道 Pandas 库,几乎所有人都知道read_csv()
函数。但是,他们中只有很少人知道read_html()
的功能。
read_html()
函数允许快速提取 HTML 页面中包含的表格。这个函数的基本版本提取 HTML 页面中包含的所有表格,而使用一些特定的参数可以提取非常特定的表格。
在本教程中,我将重点放在以下 HTML 页面上,其中包含 2020 年欧洲杯的各组比赛:
作者图片
每个表格都具有以下 HTML 结构:
<table class="table"> <thead>
<tr>
<th title="Field #1"></th>
<th title="Field #2">P</th>
<th title="Field #3">+/-</th>
<th title="Field #4">Pts</th>
</tr>
</thead> <tbody>
<tr>
<td><span>1</span> </span>ITA</span> <span>Italy</span></td
<td>3</td>
<td>7</td>
<td>9</td>
</tr>
<tr>
...
</tr>
<tr>
...
</tr>
<tr>
...
</tr>
</tbody>
</table>
提取所有表格
欧足联网站包含 6 张表格,每组一张(A-F)。我可以简单地通过将路径传递给read_html()
函数来提取所有的表
import pandas as pddf_list = pd.read_html("source/euro2020_groups.html")
该函数返回一个包含 6 个数据帧的列表,每组一个。例如,df_list[0]
包含第一个数据帧:
作者图片
所有的数据帧都有相同的结构。我注意到第一列Unnamed: 0
没有被正确识别。因此,它需要一个清洁过程。
将所有提取的表组合成一个表
现在,我将所有提取的表组合成一个表。为了保持表之间的差异,我需要添加一个新列,存储每条记录所属的组。
我定义了一个包含所有组(A-F)的列表:
import stringN = len(df_list)
groups_names = list(string.ascii_uppercase[0:N])
groups_names
变量包含以下值:
['A', 'B', 'C', 'D', 'E', 'F']
现在我通过append()
函数将所有数据帧分组。首先我定义了一个空的数据帧,然后我将包含在df_list
变量中的所有数据帧添加到它上面。根据上下文,我还添加了Group
列,它指定了每条记录所属的组:
df = pd.DataFrame()
for i in range(0,N):
group_col = [groups_names[i]] * len(df_list[i])
df_list[i]['Group'] = group_col
df = df.append(df_list[i])
现在数据帧df
如下表所示:
作者图片
清洁数据框
数据帧df
看起来有点脏:事实上,列Unnamed: 0
是不正确的。首先,我把它改名为Team
:
df.rename(columns={"Unnamed: 0": "Team"}, inplace=True)
然后我扩展了Team
列,将它分成许多列:
df_new = df['Team'].str.split(' ',expand=True)
df_new
数据帧如下所示:
作者图片
唯一有趣的列是 0、1 和 2。因此,我选择 then,并将其分配给原始数据帧中的新列df
:
df[['N', 'ID', 'Country']] = df_new[[0,1,2]]
我可以删除原来的Team
列:
df.drop(['Team'], axis=1, inplace=True)
df
数据帧如下所示:
作者图片
表格是正确的,但是列的顺序是错误的。我需要首先移动组,然后是 N,ID,Country,最后是剩余的列。我可以通过reindex()
函数对列进行重新排序,该函数接收精确的列顺序作为输入:
df = df.reindex(columns=['Group','N', 'ID', 'Country', 'P', '+/-', 'Pts'])
df
数据帧如下所示:
作者图片
保存数据帧
现在,我可以将数据帧保存为 CSV 文件:
df.to_csv('euro_2020_groups.csv')
摘要
在本教程中,我用 Python Pandas 演示了一个从 HTML 页面中提取表格的简单机制。这可以通过read_html()
函数来实现,非常简单快捷。在大多数情况下,报废的桌子需要一些清理过程。
read_html()
函数还提供了一个有趣的输入参数,称为match
,可以用来提取复杂 HTML 页面中非常具体的表格。想深化这个参数敬请期待:)
本文中解释的所有代码都可以作为 Jupyter 笔记本从 my Github repository 下载。
如果你想了解我的研究和其他活动的最新情况,你可以在 Twitter 、 Youtube 和 Github 上关注我。
相关文章
[## 用 Python Selenium 从嵌套的 HTML 页面中抓取数据
towardsdatascience.com](/scraping-data-from-nested-html-pages-with-python-selenium-c5f23065841f) [## 如何用 Python 加载 Google 文档的内容
towardsdatascience.com](/how-to-load-the-content-of-a-google-document-in-python-1d23fd8d8e52)
如何使用 Kaggle API 搜索和下载数据?
使用命令行工具与 Kaggle 交互
图片由穆罕默德·哈桑拍摄,来自 Pixabay ,使用 Pixlr 编辑
aggle 是世界上最大的数据科学社区,拥有强大的工具、数据集和其他资源来帮助您实现数据科学目标。Kaggle 包含大量用于教育目的的免费数据集。它还举办比赛,并免费提供笔记本电脑,以探索和运行数据科学和机器学习模型。
要使用 Kaggle 资源并参加 Kaggle 比赛,您需要登录 Kaggle 网站并进行相应的搜索。要从 Kaggle 下载数据集,需要搜索数据集并手动下载,然后移动到所需的文件夹进行进一步探索。
所有与 Kaggle 的交互都可以通过用 Python 实现的命令行工具(CLI) 使用 Kaggle API 来完成。
安装:
使用 pip 安装 Kaggle 库:
**pip install kaggle**
认证:
要使用 Kaggle 公开可用的 API 与 Kaggle 资源交互,首先您需要使用 API 令牌进行认证。按照以下步骤将新的身份验证令牌下载到您的计算机上,以完成身份验证:
- 点击您的个人资料图片和点击下拉菜单中的账户。
- 向下滚动到 API 章节。
- 点击**“创建新的 API 令牌”**按钮,以 JSON 文件的形式下载一个新的令牌,该文件包含用户名和 API 密钥。
- 将 JSON 文件复制到
**~/.kaggle/**
目录下。在 windows 系统中,进入根目录,然后进入**.kaggle**
文件夹,将下载的文件复制到该目录。
如果您直接使用 Kaggle API,那么只要您能够在运行时提供凭证,令牌放在哪里并不重要。
您可以使用 Kaggle API 进行交互,以便在不登录其网站的情况下使用其资源,以下是通过命令行语句使用 API 的可用交互列表:
- 搜索数据集
- 下载数据集
- 创建和维护数据集
- 搜索已发布的笔记本
- 下载已发布的笔记本
- 创建和运行笔记本
- 与比赛互动
- 提交参赛作品
1.搜索数据集:
使用 CLI 参数,您可以搜索任何关键字来查找相应的数据集。使用 search 语句获取数据集列表的 CLI 语句:
**kaggle datasets list -s [KEYWORD]**
(图片由作者提供),使用“titanic”关键字搜索数据集的结果
2.下载数据集:
在您使用用于搜索的 CLI 参数搜索了适当的数据集之后,这个 API 提供了一个优势,可以将任何数据集从 Kaggle 下载到您的本地机器。使用 CLI 下载与数据集关联的文件的命令:
**kaggle datasets download -d [DATASET]**
3.创建和维护数据集:
Kaggle API 可用于使用 CLI 参数上传新数据集和数据集版本。这可以简化 Kaggle 上数据集和项目的共享。
要创建新的数据集,请遵循以下步骤:
- 将数据集文件组装到一个文件夹中,然后上传到 Kaggle 上。
- 要生成元数据,请运行:
**kaggle datasets init -p /path/to/dataset**
- 将元数据添加到生成的文件:
**datapackage.json**
- 为了最终创建数据集,运行:
**kaggle datasets create -p /path/to/dataset**
为了上传现有数据集的新版本遵循以下步骤:
- 要生成元数据,运行:
**kaggle datasets init -p /path/to/dataset**
- 确保元数据文件
**datapackage.json**
中的**id**
字段指向您的数据集。 - 要最终创建数据集,运行:
**kaggle datasets version -p /path/to/dataset -m "MESSAGE"**
4.搜索已发布的笔记本:
使用 Kaggle API,您可以使用关键字进行搜索,找到相应的已发布笔记本。它支持搜索已发布的笔记本及其元数据,以及用于创建和运行笔记本的工作流。
使用搜索关键字获取已发布笔记本列表的 CLI 语句:
**kaggle kernels list -s [KEYWORD]**
(图片由作者提供),使用“titanic”关键字搜索笔记本的结果
5.下载已发布的笔记本:
Kaggle API 提供了从 Kaggle 下载任何发布的笔记本到你的本地机器的优势。使用 CLI 下载与笔记本相关的文件的命令:
**kaggle kernels pull -k [KERNEL] -p /path/to/download -m**
6.创建和运行笔记本:
Kaggle API 可用于上传新笔记本,并使用 CLI 参数维护笔记本版本。这可以方便在 Kaggle 上共享笔记本和项目。
要创建新笔记本,请遵循以下步骤:
- 将代码文件(笔记本)放在一个文件夹中上传到 Kaggle。
- 要生成元数据,请运行:
**kaggle kernels init -p /path/to/kernel**
- 将元数据添加到生成的文件:
**kernel-metadata.json**
- 为了最终创建数据集,运行:
**kaggle kernels push -p /path/to/kernel**
为了上传现有数据集的新版本遵循以下步骤:
- 将笔记本的最新版本和相应的元数据下载到本地机器:
**kaggle kernels pull -k [KERNEL] -p /path/to/download -m**
- 确保元数据文件
**kernel-metadata.json**
中的**id**
字段指向您的笔记本。 - 要最后推送新版笔记本运行:
**kaggle kernels version -p /path/to/kernel**
7.与竞争对手互动:
Kaggle API 工具提供了一种与 Kaggle 上举办的比赛进行互动的简单方式。要接受任何比赛的规则,您需要登录到比赛网站并接受规则以下载数据集并提交。你需要访问 Kaggle 网站并接受那里的规则,因为通过 API 是不可能的。
与 Kaggle 上举办的竞赛互动的命令:
- 所有正在进行的比赛列表:
**kaggle competitions list**
- 下载比赛相关文件:
**kaggle competitions download -c [COMPETITION]**
8.提交竞赛:
只有在您通过访问 Kaggle 竞赛网站页面接受提交规则后,才能提交任何竞赛。
- 提交给竞争对手并获得分数的 CLI 参数:
**kaggle competitions submit -c [COMPETITION NAME] -f [FILE PATH]**
- 要列出所有之前提交的竞赛运行:
**kaggle competitions submissions -c [COMPETITION NAME]**
结论:
在本文中,我们讨论了如何使用 Kaggle API 通过 CLI 参数使用 Kaggle 资源。使用 CLI 命令,我们可以与数据集、笔记本电脑或任何竞赛互动。
为了探索更多的 CLI 参数,您可以在任何调用之后添加***-h***
来查看该命令的帮助菜单。
参考资料:
[1] Kaggle API 文档:https://www.kaggle.com/docs/api
[2] Kaggle API GitHub 回购:【https://github.com/Kaggle/kaggle-api
感谢您的阅读
如何分割胰腺 CT
腹部增强 CT 发现和追踪胰腺指南
特别感谢我的好朋友梅根·恩格斯博士帮助我写这篇文章。
简介—什么是细分?
CT 扫描包含丰富的信息,可以帮助我们了解患者的健康状况。作为数据科学家,我们的角色是提取信息,以便可以测量或量化。
分析 CT 或 MRI 扫描的第一步通常是分割。这里,我指的是追踪——从背景中分割出重要的结构。从分割中,我们提取重要的特征,如器官体积、表面积、亮度和纹理模式,告诉我们疾病的各个方面。
细分可能是一个耗时的过程,也是我们试图使用深度学习实现自动化的首批任务之一。例如,我们实验室开发了一个 U-Net 模型,从腹部 CT ( 纸 ) 中分割出三十四个独特的器官。
在本教程中,我将演示如何从腹部 CT 分割胰腺。我将重点使用 ITK 快照,这是一个简单的,免费的工具,你可以使用开始。我将介绍一些解剖学基础,但如果你打算开始自己的研究项目,我强烈建议你联系临床专家,如放射科医生,以了解你的任务的具体需求。
TCIA 数据集
对于这个演示,我使用的是 癌症成像档案 (TCIA)数据集,这是一个由 NIH 提供的公开可用的医学图像数据集。完整的数据集包含来自健康患者的 85 次扫描。数据集还提供分段,尽管我将向您展示如何从头开始追踪。
ITK 快照
有许多工具可以查看和注释 DICOM 图像(有关 DICOM 文件格式的背景,请参见 我的另一篇文章 )。快速入门的方法是使用 ITK 快照 ,它很容易下载和使用。它非常适合较小的数据集。
快速插入——对于更复杂的项目(例如,涉及多个示踪剂或重复扫描的项目),我们在梅奥诊所的团队开发了我们自己的开源软件工具【RIL 轮廓 。RIL 轮廓有先进的功能,使分割更快,更准确,甚至数据版本,这有助于质量控制时,你有多个个人工作在同一个项目。
查看图像
ITK 快照支持 NIFTI 和 DICOM 格式的图像。图 1 显示了导入文件后 ITK 快照界面的样子。
**图一。**将文件导入 ITK 快照
这是一个 3D 扫描,以 3 个视图显示——轴向(也称为“横向”)(左上)、矢状(右上)和冠状(右下)。你会注意到每个视图都标有前视图(A),后视图§,上视图(S),下视图(I),右视图®和左视图(L)。
对读者来说,右和左可能是向后的——这是从面对我们的病人的角度给出的。
您可以在任何平面上进行分割,但是通常在轴向平面上进行大部分分割。这是因为 CT 中的切片厚度通常在轴向平面上更大(3-5 毫米,而不是 0.5-0.8 毫米),所以您最终必须跟踪更少的切片。
开窗术
开始之前,我们需要调整扫描的对比度。这叫做“开窗”。CT 对比度是以 Hounsfield 单位测量的,它被标准化为空气(HU = -1000)和水(HU = 0)。要在 ITK 快照中调整窗口,请转到工具 > 图像对比度 > 对比度调整。有一个滑动条,但是直接输入数字会更准确。对于腹部软组织,级别为 50,窗口为 400,这意味着图像像素被裁剪在-350 到+450 之间。
图二。 CT 腹部开窗前(左)和开窗后(右)。设置为级别=50,窗口=400。
这些 CT 是对比增强的,这意味着碘造影剂被注射到血流中。这将使血管看起来比周围的组织更亮。此外,患者有钡剂吞咽形式的消化对比,这使得胃和小肠的内容物也显得明亮。
腹部解剖学
在我们找到胰腺之前,了解一点腹部解剖学是有帮助的。我在下面的扫描中标记了一些地标。如果你查阅解剖学教科书,你会看到胰腺藏在肝脏下面,胃的后面,通常靠近脊柱。
**图 3。**腹部冠状面(左)和轴面(右)解剖
胰腺解剖学
就像其他器官一样,胰腺的位置、大小和形状有相当大的差异,这使得它很难分割。胰腺可能特别难以分割,原因有几个—
- 它比其他固体器官附着少,而且容易移动
- 它直接连接其他周围器官(尤其是肠壁)
- 即使在健康的病人身上,它也有不均匀的外观。
下面,我从维基百科上复制了一幅漫画。胰腺器官分为三个区域,头部、身体和尾部。胰腺具有柔软的叶状外观,并围绕中央胰管组织,中央胰管将胰腺分泌的消化液运送到小肠。
**图 4。**胰腺图,来自维基百科
在 CT 上,这种分叶状的外观表现为一种柔软的块状结构。胰管可以是可见的,也可以是不可见的(年轻患者胰管不太可见)。要知道胰腺可能含有囊肿— 有人估计 把这个数字高达 50%。肥胖还会影响胰腺的外观,导致脂肪沉积,使胰腺看起来更黑。最后,胰腺萎缩在老年人中也很常见;这可能是疾病的迹象,或者只是老年人的正常变异。
**图 5。**轴面胰腺特写。关键的标志包括柔软的叶状结构和黑色的胰管。
一步一步地追踪胰腺
我通常认为最容易找到胰腺体,因为它的纹理和位置与众不同。我先追踪这个结构,然后上下追踪。
胰腺往往包裹在几个血管周围,包括主动脉、腔静脉和肾动脉/静脉。这些血管通常在对比增强 CT 上显示为明亮的圆形结构(非对比 CT 这些区别几乎不可见,并且更难分割)。务必避免在分割中意外包含血管,这会给测量带来偏差。
最后,当胰腺的头部和尾部接触附近的器官时,很难将它们分开。我喜欢使用的一个技巧是在冠状面上分割 4-5 个明显的切片,然后以此作为轴向分割的指导。这使得找到胰腺器官的“角落”变得容易。
完成后,一定要再次检查你的工作。我最常犯的错误是不小心跳过了一两片。
**图 6。**在轴面(左)、矢状面(中)和冠状面(右)完成胰腺分割。使用 ITK 快照,这个分割花了我大约 20 分钟
结论
像其他事情一样,细分是一个学习过程(有点像艺术形式)。在 我们的论文 *,*中,我们发现当多个示踪剂勾画出同一个胰腺时,它们的一致性只有 80%左右,所以可以预料你的工作可能并不完美。
我喜欢告诉学生的一件事是,当你不确定的时候,就做你最好的猜测。你可能比你意识到的更准确!
如何选择数据拆分方法
不同数据拆分方法的优缺点及其背后的原因。
班农·莫里西在 Unsplash 拍摄的照片
S 分离你现有的数据是有效训练和评估你的模型的一项重要任务。在这里,我将讨论 scikit-learn 中不同的数据分离技术,选择特定的方法,以及一些常见的陷阱。
本文包含供您使用的易用代码块和供参考的快速摘要。 **** 请随意将这篇文章加入书签以备后用。****
当你第一次学习数据科学时,拆分你的数据是一项次要的任务。
为什么您应该只使用部分数据?让我的模型学习更多的数据不是会产生更好的结果吗?
虽然人们普遍认为,在构建预测模型时,更多的数据会带来更好的模型,但考虑如何使用您的模型也很重要。
在将模型投入使用之前,测试模型在开发过程中是必不可少的。不过,你必须只处理可用的数据,这意味着留出一些数据作为你的“真实”数据。
但是调查你真实的“现实生活”数据是至关重要的。这个问题的答案决定了您应该如何分离您的数据。
列车试分裂
在最简单的数据分离形式中,您随机抽取一部分数据,将其放在一边供以后测试。
很简单,但是停下来想想这些假设。
- 该方法假设数据来自同一分布。例如,假设您有逐年变化的数据。假设您主要从最近一年的数据中取样(甚至可能是由于随机选择而偶然取样)。在这种情况下,您的模型可能无法有效处理今年的预测。
- **你有足够的数据使你的数据集具有代表性。**如果您有来自相同分布的数据,但只有 100 个实例,选择 10%的数据作为测试集可能会提供不准确的结果。如果这 10 个数据点来自数据中最异常的区域,那么模型的性能会更差。当您有更多的数据实例时,这种情况不太可能发生。
- **对于分类问题,是否需要考虑每个类的份额?**假设您有一个高度倾斜的分类问题(根据我的经验,通常都是这样)。在这种情况下,您可能需要考虑对数据集进行分层。这一点几乎落入前一点,测试集可能太小,但在这种情况下,它对于您试图预测的一个类来说太小了。
如果您想要执行内部交叉验证,这种拆分方法是完美的。将数据分为训练和测试,并在训练模型时应用交叉验证方法。对于来自同一分布的足够数据,这种方法是可行的
对中大型数据集使用 train_test_split,数据来自同一个分布
import numpy as np
from sklearn.model_selection import train_test_split# Update with your data
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
y = np.array([1, 2, 3, 4, 5])X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=10)###########################################
#### Add the code for your model here #####
###########################################
训练测试分割的一个缺点是,当您进行分割时,有一个决定,即您的测试集中的数据将始终是您的测试数据。
这有几个缺点。
- 在训练时,你从不在你的模型中包含测试数据。在您的测试数据中可能有一些实例会使您的模型更加健壮。
- **测试数据是固定的。**最后,还有一个微妙的问题,就是过度适应这个测试集。虽然这不像过度训练神经网络来完美地学习数据那样明确,但这种过度拟合仍然是一个问题。一旦这些数据固定下来,您所执行的实验将根据这个测试集进行重复测试。你要寻找在这个场景中表现最好的模型。但是考虑一下预测建模的原始问题。你不知道未来的数据会怎样。通过对固定的测试集进行重复测试,您正在做一些在真实场景中不可能完成的事情。
KFold
作为训练-测试分割的替代方法,K-fold 提供了一种机制,可以将数据集中的所有数据点同时用作训练数据和测试数据。
Kfolds 将数据集分成多组零重叠的索引,从数据集中随机抽取数据集。
这种方法优于以前的训练测试分割,因为每个数据点都可以是模型的一部分和测试集中的一部分。
然而,这意味着一些事情。
- 您将在每个训练数据集上构建多个模型,并在每个测试数据集上进行测试。虽然这对于小数据集来说没问题,但是当模型很大,数据集很大时,事情很快变得昂贵。
- 测试之间的性能有所不同。这种性能上的变化是一件好事。您可以计算关于您的表现的统计数据(即,您可以从多次评估中获得标准偏差和平均值)。您还可以更好地了解您的模型在不同场景下的行为。
- 通常,当使用这种类型的数据分段时,每个测试的平均值给出了一个模型在真实环境中如何表现的更加可靠的解释。外部交叉验证以这种方式创建多个模型,报告所有折叠的平均性能,然后基于所有数据制作最后一个模型。这个最终模型得益于所有数据的使用。但是,在有额外数据之前,无法对其进行测试。因此,在这种情况下,模型性能的平均值被用作该模型的性能。
当您的数据来自同一个分布 时,将 KFold 用于中小型数据集
import numpy as np
from sklearn.model_selection import KFold# Update with your data
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
y = np.array([1, 2, 3, 4, 5])KF = KFold(n_splits=5)
for train_index, test_index in KF.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index] ###########################################
#### Add the code for your model here #####
###########################################
时间序列分割
前面的两种方法都认为你所拥有的数据是可以随机抽样的。**然而,在时间序列数据中,你不能随机抽样数据。**最重要的原因是,没有现实生活中的场景可以用未来的数据训练一个模型来预测过去。
相反,你可以通过时间来分离数据。例如,获取一个数据点之前的所有数据,然后在下一个数据点上测试它,可以确保没有数据泄漏。从这个意义上说,漏损就是用未来的数据来预测以前的数据。
这种分割方法是三种方法中唯一一种考虑分布随时间变化的方法。因此,当您有随时间变化的数据时,可以使用它。
对于时间序列数据或数据分布随时间变化时,使用 TimeSeriesSplit。
import numpy as np
from sklearn.model_selection import TimeSeriesSplit# Update with your data
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
y = np.array([1, 2, 3, 4, 5])time_series_cv = TimeSeriesSplit(gap=0, max_train_size=None, n_splits=5, test_size=None)for train_index, test_index in time_series_cv.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]###########################################
#### Add the code for your model here #####
###########################################
总结
建立模型很有趣。但是,试图提高模型的性能可能是一项无止境的任务。虽然您可能在一组数据上有出色的表现,但考虑如何在现实世界中使用您的模型是否至关重要。不同的拆分方式服务于不同的目的,所以要相应选择。
记住关注目标问题,而不仅仅是某个测试集的最高性能。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
如何为您的数据科学问题选择初始模型
为自己节省一些时间和麻烦,从简单开始。
塞萨尔·卡利瓦里诺·阿拉贡在 Unsplash 上拍照
这篇文章是为那些试图决定用什么模型来解决问题的新的或者有抱负的数据科学家而写的。
这篇文章不会讨论数据争论。希望这是数据科学家的主要工作。我假设你已经准备好了一些数据,你想看看如何做一些预测。
简单模型
有许多型号可供选择,而且似乎有无穷无尽的变种。
将回归模型转换成分类模型通常只需要很小的改动,反之亦然。幸运的是,标准的 python 监督学习包已经为您完成了这项工作。所以你只需要选择你想要的选项。
有许多型号可供选择:
- 决策树
- 支持向量机(SVM)
- 朴素贝叶斯
- k-最近邻
- 神经网络
- 梯度推进
- 随机森林
这个清单可以一直列下去,但是可以考虑从两个中的一个开始。
线性回归&逻辑回归
照片由 iMattSmart 在 Unsplash 上拍摄
是的,像 xgboost,BERT 和 GPT-3 这样的花哨模型是存在的,但从这两个开始。
注 : logistic 回归有一个不太合适的名字。该模型用于分类,但由于历史原因,该名称仍然存在。
我建议将名称改为线性分类这样简单的名称,以消除这种混淆。但是,我在这个行业还没有那样的影响力。
线性回归
**from** **sklearn.linear_model** **import** LinearRegression
**import** **numpy** **as** **np**X = np.array([[2, 3], [5, 6], [8,9], [10, 11]])
y = np.dot(X, np.array([1, 2])) + 1
reg = LinearRegression().fit(X, y)
reg.score(X, y)
逻辑回归
**from** **sklearn.linear_model** **import** LogisticRegression
**from** **sklearn.datasets** **import** load_breast_cancer
X, y = load_breast_cancer(return_X_y=**True**)
clf = LogisticRegression(solver='liblinear', random_state=10).fit(X, y)
clf.score(X,y)
为什么是这些型号?
为什么要从这些简单的模型开始呢?因为有可能,你的问题不需要什么花哨。
打破一些深度学习模型,花费数百美元在 AWS 费用上,只获得轻微的准确性提升,这是不值得的。
这两个模型已经被研究了几十年,是机器学习中最广为人知的模型之一。
它们很容易解释。两个模型都是线性的,所以它们的输入转化为输出的方式可以用手工计算。
给自己省点头疼。
即使你是一个经验丰富的数据科学家,你也应该知道这些模型在你的问题上的表现,主要是因为它们实现和测试是如此的不费力。
我为此感到内疚。我以前曾一头扎进去,建立过复杂的模型。考虑到我正在使用的 xgboost 型号总体上更胜一筹,所以它应该是我的起始型号。却发现线性回归模型的表现只有几个百分点。使用线性回归是因为它更简单,更容易理解。
这里有自我的因素在起作用。
你可能想表明你理解这些复杂的模型以及如何使用它们。但有时设置、培训和维护它们并不实际。一个模型可以用,并不意味着就应该用这个模型。
不要浪费你的时间。足够好并被使用的东西总是比复杂但没人使用或理解的东西更好。
所以希望,现在你从简单的开始,从这些模型中的一个开始。
第一个问题
我的问题是分类问题还是回归问题?
你的问题是回归问题吗?
你想预测一个连续的输出吗?
线性回归(作者供图)
像房子、产品或股票的价格?回归。
某样东西会持续多久,比如飞行持续时间、制造时间,或者用户在你博客上停留的时间?回归。
从线性回归开始。画出你的线性回归图并评估这个模型。
在这里保存性能。如果对你的问题来说已经足够好了,那就继续吧。否则,现在你可以开始尝试其他模式。
你的问题是分类问题吗?
您是在尝试预测二进制输出还是多个唯一且离散的输出?
逻辑回归(作者照片)
你是想确定某人是否会从你的商店买东西或者赢得一场游戏吗?分类。
一个是或否回答了你的问题吗?分类。
从逻辑回归开始,绘制你的数据或数据子集的散点图,并给类着色。也许已经有了明确的模式。
同样,评估这个模型,如果你仍然需要改进你的表现,把它作为你的基线。但是从这里开始。
结论
很可能,那些读过这篇文章的人会发现自己处于类似的情况,选择使用什么模型。然后从你读过的一篇论文中决定你的问题对于这个新模型是完美的。结果,花费数小时对这个复杂的模型进行微调,最终只有一个更简单的模型胜出。
不一定是性能,而是因为它们简单易懂。
给自己留点时间和精力。就从线性回归和逻辑回归开始吧。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
如何在不同的升压算法之间进行选择
AdaBoost、梯度增强、XGBoost、Light Gbm、CatBoost
几年前我第一次听说 boosting 算法。当时我还在学校读本科,使用线性回归/逻辑回归作为机器学习的主要算法。那时候,boosting 听起来像是一个非常困难和复杂的算法,这让我害怕!
这些年来,我逐渐学会了不同的 boosting 算法。我意识到这其实并不是一个很难学习和应用的概念。当然,如果你想对算法的数学和编码了如指掌,这将是困难和巨大的努力。但是,如果你只是想用算法,知道什么时候用,我们只需要知道特点,了解不同 boosting 算法的区别。
本文将重点介绍不同升压算法的概述。我将向您展示主要思想、示例代码、如何使用它们以及每种 boosting 方法的优缺点。然而,我不会深入讨论每一种提升算法的细节。
Boosting 是一种顺序集成学习技术,其中不同的模型被迭代添加,以提高整体模型性能。
作者图片:Boosting 算法的演变
如上图所示,我将按照发布时间的顺序介绍 5 种提升方法。Light Gbm 和 CatBoost 是在相似的时间推出的,所以我们不能说一个是另一个的改进版本。
我们正在使用的数据
这次我将使用来自 UCI 的成人工资预测数据集进行演示。该数据集的主要目标是预测此人的年收入是否超过 5 万英镑。这是一个分类问题,它包含相当多的分类变量,如教育背景、婚姻状况和职业。
我将在 salary 数据集上展示每个 boosting 算法的示例代码。对于前 4 种方法,我已经使用标签编码将文本列转换成整数。标签编码将文本类别转换为 0,1,2,3…我使用这种方法是因为一个热编码(转换为 0/1)会创建太多的列。我将使用最后一个方法 CatBoost 的原始文本列,因为这是算法内置功能的一部分。
此外,为了查看运行时性能,我将所有算法标准化为运行 100 次迭代来比较运行时。
adaboost 算法
AdaBoost 是自适应增强的简称。我们称之为自适应,因为该算法利用了来自先前模型的未分类案例,并创建了一个新的加权数据样本**,其中未分类案例具有更大的权重。这样,新添加的模型在解决先前模型的“错误”时应该更具适应性。**
AdaBoost 是最早开发的 boosting 算法之一。现在很少使用它,但它是大多数 boosting 算法的基础。
由西拉科恩——自己的作品,CC BY-SA 4.0,https://commons.wikimedia.org/w/index.php?curid=85888769
from sklearn.ensemble import AdaBoostClassifier
clf = AdaBoostClassifier(n_estimators=100,random_state=1)
clf.fit(X_train, Y_train)
predicted=clf.predict(X_test)
print('Accuracy of the result is:')
print(np.mean(predicted==Y_test))#Accuracy: 0.8659023441498618
#Runtime: 0.9506289958953857
梯度推进
与 AdaBoost 相比,梯度提升不惩罚漏分类情况,而是使用损失函数。损失函数可以是回归的平均误差或分类问题的对数损失。此外,梯度提升算法使用梯度下降法来不断最小化损失函数,以找到最优点。
梯度提升方法理论上比 AdaBoost 执行得更好。然而,它更容易出现过拟合问题,并且梯度增强的运行时间更长。可以设置早期停止条件,以减轻过拟合并减少运行时间。
通过使用 R 的动手机器学习进行梯度提升
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier(n_estimators=100,random_state=0)
clf.fit(X_train, Y_train)
predicted=clf.predict(X_test)
print('Accuracy of the result is:')
print(np.mean(predicted==Y_test))#Accuracy: 0.8646739686764254
#Runtime: 1.6930928230285645
XGBoost
XGBoost 代表极限梯度提升,它指的是工程师们推动梯度提升方法的计算资源极限的目标。
XGBoost 是梯度增强方法的增强版本。首先,它通过使用正则化改进过拟合。其次,通过使用并行运行优化排序**,提高了运行速度。最后,使用决策树的最大深度作为参数来修剪该树,这显著减少了运行时间。**
from xgboost import XGBClassifier
clf = XGBClassifier(n_estimators=100,random_state=0)
clf.fit(X_train, Y_train)
predicted=clf.predict(X_test)
print('Accuracy of the result is:')
print(np.mean(predicted==Y_test))#Accuracy: 0.8710205752891801
#Runtime: 0.7643740177154541
轻型 GBM
顾名思义, Light Gbm 进一步通过让计算工作量‘轻’来提高程序的运行时间。但是,与其他算法相比,它仍然可以保持相同或更高的模型性能。
Light Gbm 主要通过两种方式优化运行速度和准确性。
- 它采用基于直方图的算法,将连续变量拆分到不同的桶中(而不是单独排序)。这大大提高了运行时间。
- 它使用逐叶树生长方法,而不是逐层树生长方法(被大多数其他基于决策树的方法使用)。从下面的图片可以看出,它允许损失较高的叶片部分继续生长(最佳拟合切割),从而将整体损失函数降至最低。
来自轻型 gbm 文档的水平方向树生长与叶方向树生长
import lightgbm as lgb
clf = lgb.LGBMClassifier()
clf.fit(X=X_train, y=Y_train,feature_name=list(X_train.columns),categorical_feature=list(df_cat.columns))
predicted=clf.predict(X_test)
print('Accuracy of the result is:')
print(np.mean(predicted==Y_test))#Accuracy: 0.871839492271471
#Runtime: 0.15074729919433594
使用 Light Gbm 的另一个好处是,它有 100 多个参数可以根据数据集和问题进行调优和调整。这里一个非常有用的特性是,您可以在 fit 函数中定义分类特性列表(您需要先将类别转换为整数)。
CatBoost
最后,CatBoost 代表分类推进。它有一个很大的特点就是自动处理分类变量,而不需要将它们转换成数字。
CatBoost 是 5 种 boosting 算法中最新开发的,但非常接近轻型 Gbm。分类变量越多,性能越好。
from catboost import CatBoostClassifier
clf=CatBoostClassifier(iterations=100)
clf.fit(X_train, Y_train,cat_features=list(df_cat.columns))
predicted=clf.predict(X_test)
print('Accuracy of the result is:')
print(np.mean(predicted==Y_test))#Accuracy: 0.8731702323676938
#Runtime: 0.5496680736541748
整体性能比较
结果对照表
不同的增强方法在准确性方面的表现相当一致。CatBoost 具有最高的精度,但差异领先是最小的。就运行时性能而言,Light Gbm 具有最快的执行速度和最高的准确率。
梯度增强在运行时间方面表现不佳,并且它具有最低的精度(略低于 AdaBoost)。从这次演习来看,轻型 Gbm 似乎是冠军。
建议
就个人而言,我会推荐使用轻型 GBM 和 CatBoost ,因为它们的性能/速度优势以及大量用于模型调整的参数。
当预测器中有许多分类变量时,CatBoost 表现更好。分类变量包括文本、音频和图像。它还为您节省了转换分类变量的工作量。
轻型 GBM 的模型训练速度比 CatBoost 快。同时也不牺牲精度水平。当您有一个大型数据集和相对较少的分类预测器时,您可以选择使用 LightGBM
潜在的未来工作
- 比较是在 30k 行数据上进行的。数据集可以有偏差,大小也不是很大。您可以通过使用 make_classification 包来尝试更大的分类数据集
- 这个练习只是为了分类,你也可以尝试回归的一面
- 在评估模型性能方面,仅使用准确性和运行时间,其他分类评估如 ROC 评分、F1 评分、召回率、精确度也可用于查看全貌。
- 建模最耗时的部分是超参数调整。当前的练习或比较不包括超参数调整部分。我会有一篇新的文章,请继续关注。
最后
这是对不同类型的升压方法的非常基本的概述。你可以阅读每种方法的更多内容,也许可以在几个数据集上尝试模型以进一步理解它。
另外,boosting 只是集成学习算法中的一种。如果你有兴趣了解更多关于 ensembled learning 的内容,可以参考我下面的文章:
感谢阅读!希望这篇文章能帮到你。
如果你对你想让我介绍的某个特定的助推方法或主题感兴趣,请在评论中提出来!
如何根据列值从 Pandas 数据框架中选择行
探索如何根据 pandas 数据框架中的条件选择行
Teslariu Mihai 在 Unsplash 上拍摄的照片
介绍
从数据帧中选择行可能是使用 pandas 最常见的任务之一。在今天的文章中,我们将讨论如何对列值为:
- 等于标量/字符串
- 不等于标量/字符串
- 大于或小于一个标量
- 包含特定(子)字符串
- 可迭代的成员(例如列表)
此外,我们将讨论如何将多个条件组合在一起。
在开始讨论从 pandas 数据帧中选择行的不同方法之前,首先让我们创建一个示例数据帧来演示一些概念,该示例数据帧将贯穿本文。
import numpy as npdf = pd.DataFrame(
[
(73, 15, 55, 33, 'foo'),
(63, 64, 11, 11, 'bar'),
(56, 72, 57, 55, 'foo'),
],
columns=['A', 'B', 'C', 'D', 'E'],
)print(df)# A B C D E
# 0 73 15 55 33 foo
# 1 63 64 11 11 bar
# 2 56 72 57 55 foo
在熊猫中选择行
在下面几节中,我们将讨论并展示如何基于各种可能的条件从数据帧中选择特定的行。
选择列值等于标量或字符串的行
假设我们只想选择特定列中有一个特定值的行。我们可以通过简单地使用loc[]
属性来做到这一点:
>>> df.loc[df['B'] == 64]
A B C D E
1 63 64 11 11 bar
我们甚至可以省略loc
并在索引熊猫数据帧时提供布尔条件,如下所示:
>>> df[df['B'] == 64]
A B C D E
1 63 64 11 11 bar
注意,除了df['B']
,您还可以使用df.B
来引用列B
。例如,下面的语句与上面的等价。
>>> df[df.B == 64]
在 Python 的上下文中,将这样的布尔条件命名为mask
是一种常见的做法,然后我们在索引 DataFrame 时将它传递给 data frame。
>>> mask = df.B == 64
>>> df[mask]
A B C D E
1 63 64 11 11 bar
在介绍了几种基于列值等于标量来选择行的可能方法之后,我们应该强调的是loc[]
才是正确的选择。这仅仅是因为**df[mask]**
总是会分派到 **df.loc[mask]**
,这意味着直接使用 **loc**
会稍微快一点。
选择列值不等于标量的行
接下来,您可能希望只选择特定列中的值不等于标量的行的子集。为此,我们只需遵循与之前相同的约定:
>>> df.loc[df['B'] != 64]
A B C D E
0 73 15 55 33 foo
2 56 72 57 55 foo
选择行显示大于或小于标量的列值
这是一个与前一个非常相似的用例。在这种情况下,我们只需要使用所需的操作符来执行比较。举个例子,
>>> df.loc[df['B'] >= 64]
A B C D E
1 63 64 11 11 bar
2 56 72 57 55 foo
选择列值包含字符串的行
最常见的一个用例是,当您需要过滤数据帧时,只保留特定列中包含特定(子)字符串的行。
和前面的用例一样,我们可以使用loc
来实现:
>>> df.loc[df['E'].str.contains('oo')]
A B C D E
0 73 15 55 33 foo
2 56 72 57 55 foo
选择列值在可迭代中的行
现在让我们假设我们只想选择那些特定列中的值包含在列表中的行。为此,我们只需使用如下所示的isin()
。
>>> df.loc[df['B'].isin([64, 15])]
A B C D E
0 73 15 55 33 foo
1 63 64 11 11 bar
选择列值不在 iterable 中的行
现在,如果你想选择值不在可迭代的行(例如,一个列表),那么你可以简单地使用否定字符~
:
>>> df.loc[~df['B'].isin([64, 15])]
A B C D E
2 56 72 57 55 foo
多重条件
当从 pandas 数据框架中选择行时,您可能希望或必须将多个条件组合在一起。
为此,我们需要使用&
操作符
>>> df.loc[(df['A'] >= 59) & (df['E'].isin(['foo', 'boo']))]
A B C D E
0 73 15 55 33 foo
最后的想法
在今天的文章中,我们讨论了如何对 pandas 数据帧执行行选择,并展示了具体的用例及示例。
在大部分章节中,我们基本上使用了标签索引,这是通过loc
实现的。请注意,pandas 有一个名为iloc
的附加属性,通常用于执行位置索引。理解这两者之间的区别是很重要的,我建议你阅读下面的文章,它详细解释了每一个的作用。
[## 熊猫中的 loc 与 iloc
towardsdatascience.com](/loc-vs-iloc-in-pandas-92fc125ed8eb)
如何使用 Python 发送和接收自动电子邮件
使用令人眼花缭乱的仪表板创建自动化的电子邮件管道
斯蒂芬·菲利普斯-Hostreviews.co.uk 在 Unsplash 上的照片
介绍
在我们的公司和非公司生活中,我们每天都会收发大量的电子邮件。说实话,这些交易中的很大一部分确实可以自动化。也许我们都经历过人生中具有里程碑意义的时刻,那就是我们一天中的大部分时间都在给许多人发送差不多相同的电子邮件。嗯,不一定非要那样。使用 Python,您实际上可以设置和部署一个自动化的电子邮件管道来接收电子邮件,然后根据前者的内容发送电子邮件。换句话说,当你在工作或家里处理更有影响力的任务时,你可以让自动化发挥作用。
完全没有必要精通技术,我们要做的事情很简单,我们每个人都可以在短时间内完成。在本教程之后,您将学习如何自动接收电子邮件,使用内容和附件生成图表,然后最终向许多收件人发送带有令人眼花缭乱的仪表板的电子邮件。
具体来说,在本教程中,我们将自动执行以下操作:
- 接收电子邮件
- 解析电子邮件内容和附件
- 生成数据可视化
- 向多个收件人发送电子邮件
接收电子邮件
虽然本教程中使用的技术可以应用于任何使用标准 IMAP 协议的电子邮件服务器,但一些服务器(如 Gmail)的使用可能会有所不同。如果您确实在使用 Gmail,请确保您在 Google 帐户中启用了不太安全的应用程序选项,如下所示:
Gmail 不太安全的应用程序授权-作者图片。
继续启动 Anaconda 或您选择的任何其他 Python IDE,并运行下面的代码片段来连接到您的电子邮件帐户并下载您收件箱中的所有内容。
此外,请注意,存储您的用户凭证的更安全的方法是将它们保存在一个配置文件中,然后在您的代码中将它们作为参数调用。
解析电子邮件内容和附件
现在让我们假设您正在等待一封带有 Microsoft Excel 附件的电子邮件,其中包含许多学生的考试结果。您的目标是使用“考试结果”主题自动搜索该电子邮件。一旦找到它,您将需要提取文件并保存到您的本地目录。
请注意,如果您想要搜索特定的发件人而不是电子邮件主题,请将上面代码片段的第 7 行替换为以下内容:
if 'sender_email@gmail.com' in email_content['From']:
生成数据可视化
现在您已经下载了电子邮件附件,您将希望根据附件的内容生成文本和图表。因为在我们的例子中,文件是一个 Excel 电子表格,我们将使用 Pandas 将其转换成一个数据框。
电子邮件附件数据框-作者图片。
我们现在的目标是找到每次考试的班级平均分,然后创建一个图表,单独显示每个学生的分数。为此,我们将使用如下所示的 Plotly 来生成包含考试结果的自定义折线图、条形图和直方图。在继续下一步之前,请确保您可以通过在 Anaconda 提示符下键入以下命令,使用‘python-kaleido’库将图表保存为图像:
conda install -c plotly python-kaleido
上面的片段将为每个学生创建以下三个图表:
考试成绩图表-作者图片。
向多个收件人发送电子邮件
现在我们已经生成了定制的图表,下一步是将相应的图表和考试结果发送给每个学生。下面的代码片段是前面代码片段中 for 循环的延续。
结果
这就是你自己的电子邮件仪表板,通过自动化管道毫不费力地发送给许多收件人。这只是这种方法的扩展功能的一个小演示,实际上您可以通过发送更丰富的内容来扩展它,包括但不限于文本、图像、音频和其他 HTML 内容。
电子邮件仪表板—按作者分类的图像。
如果您想了解更多关于数据可视化和 Python 的知识,请随时查看以下(附属链接)课程:
使用 Streamlit 开发 Web 应用程序:
使用 Python 实现数据可视化:
面向所有人的 Python 专业化:
GitHub 资源库:
https://github.com/mkhorasani/python_automated_email
☕喜欢这个教程?这里有空给我捐一杯咖啡。
新到中?您可以在此订阅并解锁无限文章。
如何使用 Python 发送电子邮件
向您展示使用 Python 与人交流的多种方式
来源:https://unsplash.com/photos/3Mhgvrk4tjM
在本教程中,我将向您展示使用 Python 发送电子邮件的多种方式。这在许多项目或情况下非常有用,在这些项目或情况下,您需要以快速、简单和安全的方式与不同的人共享任何类型的信息。
传统方式:SMTPLIB
当使用 Python 发送电子邮件时,这个库是最受欢迎的。它创建了一个简单邮件传输协议(SMTP)会话对象,可用于向任何 internet 机器发送邮件。
在使用此模块发送电子邮件之前,您需要更改电子邮件帐户的设置。事实上,你需要在作为发件人的电子邮件中“启用对不太安全的应用程序的访问”。更多信息请点击这里:https://support . Google . com/accounts/answer/6010255 # zippy = % 2c if-less-secure-app-access-on-for-your-account
一旦这样做了,这里的代码将允许你立刻发送一封非常简单的电子邮件。
这传递了一个非常简单的信息。当然,您可以添加主题、附件等。但是我将要展示的另一种方法也可以用更简单的方式实现。
另一种选择:Yagmail
Yagmail 是一个 gmail 客户端,旨在使发送电子邮件变得更加简单。
我个人喜欢它,因为它非常容易给邮件添加内容(附件、主题、链接等)。)而我发现在使用 SMTPLIB 时并不那么直接。
下面是发送包含主题和附加图像的电子邮件的代码。还是那句话,超级简单!
在第 7 行中,‘test’
实际上是邮件的主题,而在内容中,您可以添加消息和附件(图像、word 文档、音频文件等)。)超级轻松。
更具伸缩性的方式:使用 API
电子邮件服务现在已经存在,它可以用很少几行代码帮你发送尽可能多的电子邮件。
使用服务的好处是,它允许您跟踪您发送的内容。你可以很容易地知道是否收到电子邮件,何时何地发送了多少封。这种类型的信息并不总是必要的,但是随着项目的发展,您对这种类型的信息的需求也会增加。
这种服务可以是免费的。例如,如果你使用 Mailgun(https://www.mailgun.com/),你每月可以免费发送多达 5000 封电子邮件。
此类服务的唯一问题是,你需要创建一个账户,如果你打算发送大量电子邮件,你最终可能需要花钱。
一旦你有了一个帐户,这里是你如何使用 Mailgun 和 Python 发送电子邮件。您自己的个人功能(具有正确的凭证)将很容易在您的帐户中使用。
我希望这能对你正在做的任何项目有所帮助,如果你有任何问题,请不要犹豫。
谢谢!
如何测序人类基因组
实践教程
通过阅读《三只小猪》和穿越一座城市
人类基因组包含超过 30 亿个碱基对。从上下文来看,如果你每秒钟检测一个碱基对,你需要花 94 年来检测它们。因此,毫不奇怪,1990 年,人类基因组计划就是为了完成这一任务而创立的,也就是说,对整个人类基因组进行测序。
像科学中的许多事情一样,这个项目变成了一场竞赛。在这种情况下,在 Celera Genomics 和 IHGSC 之间。
DNA 基因分型和测序。信用:国家癌症研究所(Unsplash)
也许有些令人不满意,两个团队在 2001 年同时发表了完整的基因组。这两个阵营采用的方法各不相同,在本文中,我们将重点介绍 Celera 的三步法:
- 将整个基因组切割成大约 150,000 个碱基对长的更易管理的片段。
- 将这些片段分别插入克隆的人造细菌染色体中,然后通过“指纹”向科学家展示它们重叠的地方。
- 然后,这些重叠被用作向导,向科学家展示顺序,然后从那里,整个基因组被重建。
前两步非常简单,事实上,DNA 的分离和转染是工业上经常做的事情,例如在重组蛋白生产中。第三步要复杂得多,乍一看,可能会让人不知所措。
这种做事方式几乎就像你拿了很多本三只小猪(或者任何一个词汇相当局限于一小组单词的故事),把它们放进一个碎纸机,把纸屑像绳子一样混合在一起,然后试图重建至少一个完美的三只小猪的副本。
信用:马蒂厄·佩蒂亚尔(Unsplash)
除非你对拼图游戏有秘密的嗜好,否则这看起来非常没有希望,事实上也确实如此(特别是当你的《三只小猪》有 30 亿个字符长的时候)。
但是,人类无法有效完成的机械任务,计算机肯定可以。这就是生物信息学的用武之地。生物信息学就像生物学和计算机的私生子。它利用计算机以逻辑方式处理大量数据的能力来解决生物学问题。人类基因组测序可以被视为一个非同寻常的生物学问题,几乎从定义上来说,它包含了大量的数据,这使得使用生物信息学方法来解决它变得非常完美。
回到*三只小猪的比喻,*因为粉碎的过程是随机的,所以不可能有很多碎片看起来完全一样。例如,在一个副本中,句子“我会一鼓作气,吹倒你的房子”可能会被砍成
“我会吹气,我会吹气,我会吹倒你的房子”。
但是,在另一个副本中,它可能是
“我会发怒,我会砰的一声,我会把你的房子夷为平地”。
如果我们对英语没有任何概念,如果呈现给我们第一批片段,我们就不知道该按什么顺序排列,因为就我们所知,一个顺序看起来和下一个一样好。我们会很容易地把第一组纸条拼凑成正确的措辞“我会吹,我会吹你,我会吹倒我们的房子”。
话虽如此,如果有第二套,我们可能会注意到有一些重叠之间的“我会 huff an”和“我会 huff,我会 pu”和一些更多的重叠之间的“我会 huff,我会 pu”和“d 我会 puff,我会吹你”。因此,我们可能会得出这样的结论:“我会发脾气”和“我会吹气,我会吹你”紧挨着,提供句子“我会发脾气,我会吹气,我会吹你”,这是朝着正确方向迈出的一步。
这个过程似乎有些矫枉过正。为什么你要收集一架子的三只小猪,把每一只都放进碎纸机里,当你可以读其中一只的时候,还要煞费苦心地寻找重叠之处?当谈到基因组时,生物信息学家没有能力像阅读一本书那样从左到右阅读。因此,他们不得不
- 将基因组的多个副本分割成更小的“读数”,这不可避免地会变得杂乱无章。
- 找到这些读数重叠的地方,并利用这些信息构建整个基因组。
我们先考虑一个理想情况。比方说,我们有一个“天文”这个词,它可以很方便地分成一堆三个字母:“ast”、“str”、“tro”、“ron”、“ono”、“omi”、“mic”、“ica”、“cal”。因为每对连续的三聚体共有 2 个字符(即一个三聚体的“后缀”等于紧随其后的三聚体的“前缀”)。
因此,我们可以从第一个三聚体开始,添加每个后续三聚体的最后一个字符,得到“ast-r-o-n-o-m-i-c-a-l”。如果我们使用四聚体,这将是正确的:
" astr" + “stro” + "tron “,” rono “+” onom “+” nomi “+” omic “+” mica “+” ical " = " astr-o-n-o-m-I-c-a-l "。
或五聚体
" astro “+” stron “+” trono “+” ronom “+” onomi “+” nomic “+” omica “+” mical " = " astro-n-o-m-I-c-a-l "。
这其中的两个主要问题是
- 它假设所有的读取都是按照正确的顺序进行的。例如,如果我们有“astro”、“trono”、“nomic”、“onomi”、“omica”、“stron”、“mical”、“ronom”,这就不太好了。
- 它假设完美覆盖——即每一个可能的 k-mer 都被转换成 k-mer。如果 k-mer 的“ronom”被省略,我们从“trono”到“onomi”,我们就会有一个缺口。
我们将讨论所有这些要点,但首先让我们考虑一个基本操作,即获取一个字符串并尝试将其分解为它的 k-mer 组合——即组成它的 k-mer 集合(例如。《天文》的三聚体构成是" ast “、” str “、” tro “、” ron “、” ono “、” omi “、” mic “、” ica “、” cal "。
def StringComposition(Text, k):
for i in range(len(Text)-k+1):
print(Text[i:i+k])
但是,我们也希望能够做相反的事情。也就是说,给定一个 k-mer 组合,恢复它对应的字符串。因为这仍然是一种理想化的情况,我们可以进行上面的观察,并意识到每个 k-mer 都在其之前的 k-mer 中添加一个新字母。
def StringFromGenomePath(Genome):
k = len(Genome[0])
string = ""
string += Genome[0][0:k-1]
for i in range(0, len(Genome)):
string += Genome[i][k-1]
return string
假设 1:所有的阅读顺序都是正确的。
现在,我们陷入疯狂和不确定之中!但在我们全面开始之前,值得注意的是,这很大程度上是基于 Pavel Pevzner 和 Philip Compeau 的 MOOC 生物信息学 II。为了更多地实践这里概述的概念,我强烈建议你去看看!
正如我们之前建立的那样,k-mers 可能不会按照你想要的顺序出现。所以我们转向重叠图的概念。所有的图都是由节点和边组成的。你可以把它想象成一个城市,各个目的地是节点,边是街道
鸣谢:Hanson Lu (Unsplash)
在这种情况下,我们的图将有条有向边,这意味着你只能沿着边所指的方向从一个节点到下一个节点,即单行道。
我们将制作所有的 k-mers 节点,并在共享前缀和后缀的节点之间绘制边。例如,如果我们有三聚体 TAATGGGATGCCATGTT,那么节点 TAA 有一条指向 AAT 的边,它有一条指向 ATG 的边…等等。因为边缘在共享的前缀和后缀之间,所以穿过它们就像穿过两个 k-mers 之间的重叠部分。
基本字符串重建路径。鸣谢:作者
但问题是,我们实际上并不知道事情是以这种特定的顺序联系在一起的,例如,ATG 目前指向 TGC 的气泡,但从技术上来说也可能指向 TGG。
重建 k-mer 就像试图在这个重叠图中找到一条路径/找到一条访问城市中每一个目的地的方法。但不是任何路径:一条哈密尔顿路径,它恰好访问每个节点一次。因为它是沿着有向边(所有的重叠)来做的,所以我们知道所有的 k-mers 都是正确的顺序。
但是,从算法上来说,很难找到哈密顿路径。这就是为什么我们也考虑德布鲁因图的原因。在这个图中,边是 k-mers,节点是构成前缀和后缀的 k-1mers。特别地,对于给定的边,它来自的节点将是前缀,它去往的节点将是后缀。因此,例如在上面的 k-mer TAATGGGATGCCATGTT 中,边 TAA 将从 TA 指向 AA,边 GAT 将从 GA 指向 AT。
为了简化事情,我们可以将具有相同 k-1 mer 的节点“粘合”在一起,合并进入和离开它们的边。
德布鲁金图。鸣谢:作者
def DeBruijn(k, Text):
mers = {}
for i in range(len(Text)-k+1):
if Text[i:i+k-1] in mers:
mers[Text[i:i+k-1]].append(Text[i+1:i+k])
else:
mers[Text[i:i+k-1]] = [Text[i+1:i+k]]
for item in mers:
print("{} -> {}".format(item, ', '.join(mers[item])))
我们想在这个图中找到一条路径,这条路径恰好访问每条边一次(所以每个 k-mer 都被访问一次)。我们知道,如果我们沿着正确的方向沿着边走,那么所有这些 k-mers 的顺序都是正确的,因为它们必须紧挨着与它们重叠的 k-mers(由于共享前缀和后缀的节点)。这样的路径被称为欧拉路径。
欧拉循环非常类似于欧拉路径,只是它在同一个节点开始和结束。对于一个有欧拉圈的图,它必须是
- **强连接。**即可以从每个其他节点到达每个节点。例如,如果我们的“城市”基本上是一系列没有桥梁连接的岛屿,那么它就不会是强连接的。
**2。平衡。**进入节点的边数(入度)必须等于离开节点的边数(出度)。换句话说,能让你到达目的地的单行道数量等于能让你离开目的地的节点数量。
在这种情况下,第一个要求几乎是隐含在这种情况下,如果你有一个字符串,你将显然能够从字符串中的一个 k-mer 到另一个。第二个也是,但是如果一个图有两个以上的节点,其中入度不是出度,那么在访问每个点之前,您将不可避免地停留在一个这样的位置。
但是一个人如何找到这样一条路呢?让我们假设你被随机放在一个欧拉图上,任务是计算出一个欧拉圈。如果事先不知道这个图表是什么样子,你的第一反应可能是开始随机地四处游荡,直到有事情发生。
将会发生的“某件事”是你到达一个节点,却无处可去,因为你已经用完了离开那个节点的所有边。但这不会在任何节点发生,因为结果是,你唯一可能被卡住的节点是你从开始的节点。在这种情况下,如果你已经沿着其他每一条边走了,那么很好——你找到了一个欧拉周期。但是,如果仍有一些未使用的边,则必须执行以下操作:
- 回溯到一个节点(n ),它有一些未使用的边。
- 从那里开始遍历图,直到你再次卡在节点 n。
- 沿着原始路径从节点 n 继续前进。
您可以将这种方法视为为您的循环建立一个“主干”,即最初的遍历,然后在图的其他部分不断“循环”到这个主干中。
def EulerCycleSolver(graph):
path = []
key = random.choice(list(graph))
path.append(key)while len(graph[key]) != 0:
value = random.choice(graph[key])
graph[key].remove(value)
key = value
path.append(key)
for key in path:
if len(graph[key]) != 0:
x = len(path) - path.index(key) - 1
while len(graph[key]) != 0:
value = random.choice(graph[key])
graph[key].remove(value)
key = value
path.insert(-x, key)
#path.pop() #- if want to minus last connection
return path
然后从这一点,找到一个欧拉路径只是必须忽略最后一个连接。这是可行的,因为所有有欧拉圈的图都必须有一条欧拉路径。但是,如果一个图没有欧拉圈呢?这并不一定意味着图形没有欧拉路径(有点像所有的正方形都是矩形,但不是所有的矩形都是正方形)。
在那些小的子集情况下,图必须是“接近平衡的”。这意味着,有一个节点的进箭头比出箭头多一个,另一个节点的出箭头比进箭头多一个。
具有额外出度的那个将是起点,具有额外入度的那个将是终点。这是因为每次你进入一个节点,你需要能够离开它,但如果你有一个更多的边缘进来,你最终会卡在那个节点,这是好的,如果这是你的最后一个节点。一种相反的直觉适用于起始节点。
通过找到这两个节点,在 then 和 then 之间添加一条边,然后使用之前建立的欧拉循环算法,我们可以很容易地将此图转换为具有欧拉循环的图。
德布鲁金图中的欧拉圈。鸣谢:作者
然后将该序列拟合到字符串重构问题算法中,将返回原始字符串。但是事实证明并不是所有时候。例如,假设您有一个字符串 TAATGGGATGCCat GTT,它的三个成员是 TAA、ATT、ATG、TGG、GGG、GGA、GAT、ATG、TGC、GCC、CCA、CAT、ATG、TGT 和 GTT。虽然欧拉循环算法可以按照这个顺序将它们组合在一起,但它也可以很容易地切换 GG 和 CC,并返回 TAATGCCATGGGat gtt,因为它的三聚体组成是相同的,只是顺序略有不同——TGG、GGG、GGA 将与 TGC、GCC、CCA 进行切换。
因为这些更小的片段可以互换,我们需要考虑它们的顺序,这可以从它周围的三聚体推断出来。而不仅仅是直接围绕着它,因为正如我们所看到的,它们也被转换了。我们需要前面至少有 k 个字符的 k-mers。
这启发了成对的 De Brujin 图采用(k,d)-mers 而不是 k-mers。(k,d) mer 是一对由 d 字符分隔的两个 k-mer。例如,在上面的字符串中,第一个(3,2)将是(TAA|GGA)。条形表示两个 k-mers 之间已删除的所有内容。
就像我们可以有一个 k-mer 组合的字符串,我们也可以有一个(k,d)-mer 组合的字符串。对于上面的字符串,(3,2) mer 组成将是(TAA|GGA),(AAT|GAT),(ATG|ATG),(TGG|TGC),(GGG|GCC),(GGA|CCA),(GAT|CAT),(ATG|ATG),(TGC|TGT),(GCC|GTT)。
成对的德布鲁金图。鸣谢:作者
def PairedDeBruijn(k, Text):
mers = {}
for i in range(len(Text)):
if Text[i][0:k-1] + "|" + Text[i][k+1:2*k] in mers:
mers[Text[i][0:k-1] + "|" + Text[i][k+1:2*k]].append(Text[i][1:k] + "|" + Text[i][k+2:2*k+1])
else:
mers[Text[i][0:k-1] + "|" + Text[i][k+1:2*k]] = [Text[i][1:k] + "|" + Text[i][k+2:2*k+1]]
for item in mers:
return mers
当我们得到一个有序的(k,k-mer 集时,我们可以像上面一样重建字符串,但是将第一个字符添加到第一个 k-mer 的末尾,然后根据 d 的值补充最后几个第二个 k-mer。
假设 2:完美覆盖
尝试处理这种假设比克服之前的事实要容易得多,即并非所有的 k 线图都是按照理想的顺序排列的。正如我们之前看到的,完美覆盖的概念是我们拥有我们想要重建的字符串中出现的每个 k-mer。
这就是为什么生物信息学家经常求助于使用“重叠群”,这是德布鲁金图中最长的可能片段,没有任何不确定性。基本上,如果你要尝试扩展这样一条道路,你需要选择 k-mer 将会带来什么。即使我们的 k-mers 具有完美的覆盖,也使用这种做法,因为有时重复会阻止存在唯一的欧拉路径(即一个图可以翻译成许多字符串)。
生成 MaximalNonBranching 路径/重叠群。鸣谢:作者
def MaximalNonBranchingPaths(graph):
#print(graph)
ins = {}
for i in graph:
for x in graph[i]:
if x in ins:
ins[x] += 1
else:
ins[x] = 1
rejects = {}
for x in graph:
if x in ins and len(graph[x]) == 1 and ins[x] == 1:
rejects[x] = graph[x]
dones = []
collections = []
for x in graph:
if x not in rejects:
for y in graph[x]:
path = [x, y]
while y in rejects:
dones.append(y)
path.append(graph[y][0])
y = graph[y][0]
collections.append(path)
for y in dones:
del rejects[y]
while len(rejects) != 0:
forgotten = []
key = random.choice(list(rejects))
forgotten.append(key)
while key in rejects:
value = rejects[key][0]
forgotten.append(value)
del rejects[key]
key = value
collections.append(forgotten)
return collections
好了,让我们回顾一下我们是如何从残忍地撕毁一堆三只小猪到能够重建整个基因组的。
- 在罕见的理想情况下,我们以正确的顺序覆盖所有节点,我们可以只使用字符串重建。
- 否则,我们可以用节点作为 k-mers 的前缀/后缀来构造一个 DeBrujin 图。我们想在这个图中找到一个欧拉圈或欧拉路径,然后对其应用字符串重构。
- 为了更准确,我们可以使用成对的德布鲁金图,它考虑了 k-mers 之间的空间,并在这周围找到类似的欧拉回路/路径。
- 因为我们不能假设完美的覆盖,科学家们经常求助于寻找“重叠群”,这是德布鲁金图中最长的可能片段,没有不确定性。
现在你有了,你应该完全有能力对整个人类基因组进行测序;).
如何使用 Python Web 应用服务于大规模计算?
克服 Python 的局限性,并通过 web 请求将其用于繁重的数据分析和机器学习。
米格尔·Á拍摄的照片。来自佩克斯的帕德里纳
在的上一篇文章中,我写了使用 Python web 应用进行分析项目的局限性。其中一些观点点燃了读者的好奇心,并激励我写另一个故事来补充它。
这篇文章的中心问题是,“如果 Python 因为其同步行为而存在严重缺陷,那么 Instagram 和 Spotify 等平台如何使用它来服务全球数百万人?”
虽然我没有来自这些平台(或类似平台)的官方信息,但根据我的经验,我对处理如此大规模的请求有一些见解。
在本文中,我准备了一个演示来展示基础知识。现实生活中的项目可能有其他几种技术;我没有把它们都包括在内。但是我在这个故事中暗示了一些我最喜欢的,并尽可能提供了参考资料的链接。
让我们再次从讨论同步-异步问题开始。
Python 的同步行为和服务 web 请求的成本。
拥有一个精益技术栈是一个很好的选择。数据科学社区在这方面有 Python 的天赋。因为 python 是一种通用语言,所以可以用它来构建数据管道、机器学习、web 应用等等。
使用 Python web 框架时需要注意的一点是它的同步行为。也就是说,Pyhton 在每个线程中一次处理一个任务。在请求完成之前,其他人必须排队等候。如果您需要服务更多的并发请求,您必须增加内核和实例的数量。
如果你的网络应用只为有限数量的用户服务,这不是一件事。此外,如果您不按需执行繁重的计算,您仍然可以。但是当你增长和计算更多的时候,你的 hello world 类型的网络应用可能会引起严重的问题。
即使是选择节点 app 也是如此。Node 是基于 JavaScript 的,异步运行是这种语言的本性。关键是,在使用 Python 框架时,成本更高(如果未处理的话)。
所以,我们来处理吧。
将计算从请求-响应周期中分离出来。
想象一下,在 Instagram 上;你会看到一只巨大的蓝鲸。被它的美丽所震撼,你双击并喜欢上了这张图片。你希望你能看到更多。但这是你第一次在站台上遇到如此雄伟的照片。
你一直向下滚动;下面几张图片是旧的数据科学迷因之类的东西。
过一会儿,你会再次访问 Instagram。太棒了!你会看到更多巨大的蓝鲸在游泳,和它们的幼崽玩耍。它让你着迷。
这是大多数平台向用户推荐内容的方式。不需要立即学习。它们甚至可能导致假阳性。
处理这个问题的一个聪明方法是将计算从请求-响应周期中分离出来。使用关于用户的先验知识来服务即时请求。积累更多的数据,以便以后更好的学习和表现。这就是我们如何通过继续向下滚动看到旧的数据科学迷因,并在下一次访问中看到更多蓝鲸。
在大规模应用中,我们将用户的每一个动作都收集在一个专用的数据库中。像 Cassandra 这样的数据存储是实现这一目的的绝佳选择。根据应用程序的性质,定期任务用新数据更新模型,或者系统使用触发器来做同样的事情。如果它们发生在你下一次访问平台之前,你很幸运得到了一个最新的模型。
这就足够说明问题了;是时候把手弄脏了。
在 web 请求之外执行繁重的计算。
为了简单起见,我将使用 Flask。但是这种技术同样适用于任何其他 Python 框架。我们使用芹菜来处理请求-响应周期之外的繁重计算。最后,我们将使用一个数据库来收集用户操作。
在这个演示中,我们使用请求本身作为触发器,并立即开始计算。但是它可能会根据您的应用程序的性质而有所不同。通常,您可能还必须使用单独的管道。在这种情况下,你可能需要像阿帕奇气流或者提督这样的技术。
安装消息代理— Redis。
消息代理顾名思义。您可以向代理发送一条消息,代理同时将该消息传递给它的所有订阅者。尽管这个定义看起来很简单,但是对于工程师来说,在消息代理出现之前的生活是很困难的。
这里我们将安装 Redis,一个著名的消息代理软件。相反,你也可以使用 RabbitMQ、亚马逊 SQS 和许多其他芹菜经纪人。
Redis 官方网站有所有操作系统的说明。一种与平台无关的方法是使用他们的官方 docker 映像。
**$** docker run --name redis-server -p 6379:6379 -d redis
安装芹菜和烧瓶
这两个模块的安装非常简单。就像许多其他 Python 包一样,您可以使用 PyPI。
**$** pip install celery Flask
Flask 的目的是通过 HTTP 服务 web 请求。这是一个极简主义的框架,其广受欢迎的替代方案 Django 是满足许多需求的一站式解决方案。我将要分享的技术将在这些方面发挥作用。
芹菜是 Flask(或 Django)和消息代理之间的桥梁。它将您的 Python 对象解析成代理软件可以理解的消息。更广泛的应用还包括任务调度和定期执行。
去耦 hello world 示例。
现在,我们已经安装了芹菜和烧瓶,我们的 Redis 服务正在运行。让我们尝试创建我们的第一个解耦应用程序。
创建一个名为 app.py 的文件,并添加以下内容。
来自作者的代码片段。
上面的代码有四个部分。第一个是将返回芹菜对象的函数(make_celery)。
第二个是 Flask 应用程序创建。如果你有使用 Flask 的经验,你可能对这部分比较熟悉。我们传递额外的配置来通知 Flask 应用程序和 Celery 关于 Redis 服务器的信息。
在第三部分中,我们使用 make_celery 函数创建芹菜应用程序。我们传入 Flask 应用程序实例,它包含 Redis 配置信息。
有了这个设置,我们现在可以创建异步任务。这意味着它们的执行不会中断主线程的常规操作。这里的示例任务 massive _ computation 将返回“你好”,不是立即返回,而是在五秒钟后返回。
为了测试这一点,首先,我们需要启动芹菜服务器。这是一个解耦的过程,将运行您的大规模计算。下面的这个命令会做到这一点。
**$** celery -A app.celery worker -E
在另一个终端中,运行下面录音中显示的命令。
这从 app 模块中导入了我们的 massive _ computation 函数,并调用它。请注意用于调用该函数的独特延迟方法。@celery.task 装饰器添加了这个额外的方法。
一旦调用了函数并将它的值存储在变量中,就可以使用 result 属性来访问它的值。
正如您在录音中看到的,result 属性在最初的几次调用中没有值。几秒钟后,屏幕上出现了“Hello Thuwarakesh”。
在函数返回值之前,您可以在同一个线程中执行其他活动。这不是使用同步语言(如 Python)开发的应用程序的典型行为。
通过 web 请求服务于大量计算。
我们已经安装了我们需要的技术,并创建了一个与应用程序线程并行运行的基本应用程序。现在,我们已经完成了最后一个部分 web 请求处理。
现在用下面的代码替换 massive _ computation 函数和下面的所有内容。
来自作者的代码片段。
我们创建了 Redis 数据库的一个实例来存储我们分离的计算结果。
我们在这里执行的计算是斐波那契计算。massive _ computation 函数接受一个数字,计算斐波那契数,并将其存储在数据库中。
我们还创建了两个 web API 端点。第一个将设置上次计算的值,另一个将读取当前值。
为了测试这个应用程序,我们需要在已经运行的芹菜服务旁边运行一个 Flask 应用程序。您可以使用以下命令在不同的终端中启动 Flask 应用程序。
**$** flask run
现在,我们已经做好了使用 Python web 应用测试大规模计算的一切准备。让我们试一试。
你可以使用你的浏览器或者 CURL 来完成这项工作。我将在终端窗口中使用 curl。
上面的录音清楚地解释了用法。当我们查询“/current”端点时,它给出初始值 0。
然后,我们通过“/set”端点指定一个新值,即第 40 个斐波那契数。计算这个数字需要一些时间。然而,系统立即给出了回应,“新的斐波纳契数将很快分配。”这方便地通知用户关于后端任务的信息。
对“/current”终结点的立即查询再次得到 0。这是因为计算尚未完成,数据库中的值仍为 0。
然而,过了一会儿,同一个端点返回第 40 个斐波那契数列的值。后端计算已经完成,芹菜任务更新了数据库中的值。
计算斐波那契数并不是你在现实生活中看到的大量计算。但这只是对它们可能样子的一个合理估计。你可以触发机器学习模型的再训练,而不是斐波那契。
最后的想法
你可能想知道大规模计算在哪里。然而,这篇文章不是关于计算本身。我们专注于如何为大规模计算服务。为了公平起见,我们使用了斐波那契数计算器。
我们已经将计算从 web 服务器的请求-响应周期中分离出来。这允许我们在不中断网络服务器的情况下执行计算。
在本文中,我们使用芹菜来处理这种分离的任务。虽然芹菜能够在生产中运行,但现代替代品提供了更多功能。阿帕奇气流和提督是这方面的一些伟大的技术。
Python 本质上是一种同步语言。试图使它异步会带来很多开销和缺点。使用芹菜进行繁重的计算是处理这个问题的一种优雅的方式。
然而,这并不意味着异步语言可以摆脱它。大规模计算不应该通过请求-响应循环来完成。它们通常服务于不同的目的,而不是即时的、有意义的反应。因此这种方法在任何情况下都是有用的。
感谢阅读,朋友!看来你和我有许多共同的兴趣。我很乐意通过 LinkedIn、T2、Twitter 和 Medium 与你联系
还不是中等会员?请使用此链接 成为 会员。你可以享受成千上万的有见地的文章,并支持我,因为我赚了一点佣金介绍你。
如何设定学习数据科学的套路
如何充分利用你拥有的时间
Malvestida 杂志在 Unsplash 上拍摄的照片
如果你通过正式的全日制教育学习数据科学,你通常可以投入几个小时的时间来学习,并且创建一个学习例程相对容易。然而,如果你像许多人一样,适合围绕全职工作的要求或在照顾家庭的同时学习数据科学护理,可能很难找到时间。
我个人过渡到了数据科学的职业生涯,同时兼顾全职工作和照顾我的两个年幼的孩子。时间对我来说已经很紧张了,我经常因为找不到时间来学习而感到沮丧。然而,随着时间的推移,我学会了一些有用的技巧,来帮助我在我的其他承诺周围划出时间来适应我的学习。
在这篇文章中,我想分享一些我用来创建和坚持学习数据科学的技巧和技术,使我能够成功地过渡到这一新的职业。
你的学习预算是多少?
你需要确定的第一件事是你能花多少时间来学习。能够留出适当的时间进行强化学习是很重要的。理想情况下,这些时间应该至少有两个小时,我建议每周至少留出五个小时。
为了坚持包含一致时间段的学习时间表,它需要是现实的,并且需要适合你的其他承诺。
为了确定你实际上有多少时间可以用于这些紧张的学习时间,我建议首先拿起笔和纸,写下你在典型的一天中已经拥有的时间承诺,包括周末。假设你必须工作 8 小时,你需要睡眠(8 小时),然后你需要时间锻炼、吃饭、做家务和与家人在一起。假设这些还需要 2 -3 个小时。这可能会让你每天的学习预算只有 3-4 个小时。
“关键不在于花费时间,而在于投资时间.”,斯蒂芬·R·科维
这 3 到 4 个小时的时间,或者你个人学习预算中剩余的任何时间,都是你专门学习的时间。这段时间应该用于紧张、集中的学习或动手实践应用,如从事副业项目。
优先安排你的学习时间是非常重要的。做到这一点的最好方法是做出承诺并坚持下去。将你每天的学习时间作为一个循环事件添加到你的日历中。
利用空闲时间
死区时间是你日常生活的一部分,在这段时间里你不能进行任何高强度的学习,但对于更轻量级的学习来说是理想的。这可能是坐在火车上作为你早晨通勤的一部分,在工作会议前的 5-10 分钟,没有时间开始新的任务或等待你的孩子完成足球练习。
当我最小的儿子还是个婴儿的时候,没有我安静地坐在他旁边,他无法入睡。所以我每天晚上至少花 30 分钟坐在他床边的地板上。过了一段时间,我开始利用这段时间进行一些安静的学习。这是我看书或听播客的理想时间。通过这样做,我既能给我儿子提供他所需要的舒适,同时也给了我自己学习和成长的时间。
"失去的时间一去不复返。"本杰明·富兰克林
所以我的建议是尽量利用你一天中的任何空闲时间进行某种学习。这不是深度强化学习的时间,但通常是花时间阅读论文、补上博客帖子或视频讲座的绝佳机会。
通过利用这些空闲时间,你可以最大限度地利用学习预算中的可用时间。
也要安排休息时间
大多数运动员在日常锻炼中安排有规律的休息日。这些休息日是必要的,让身体有时间从高强度训练的压力中恢复过来。人们早就认识到,与完全不休息相比,通过休息,运动员的表现实际上有所提高。
“工作中有美德,休息中也有美德。两者并用,不可偏废。”,
艾伦·科恩
我相信对于像学习这样的脑力劳动来说,安排休息日也同样重要。在设计你的学习计划时,确保你每周至少有 1 到 2 天的休息时间。这可能是周末休假或者在一周中的某些晚上不学习。找到适合自己的平衡点很重要。
除了休息日之外,在你的日常生活中安排不太密集的学习也是一个好主意。这类似于运动员的积极休息日,在艰苦训练后的第二天进行温和的锻炼。学习数据科学的积极休息日可能是阅读一本书,在 Youtube 上赶上一些讲座,或者与你的导师喝杯咖啡。
在这段时间里,你仍然会学习,但是你会避免精疲力尽,最终从长远来看,你会学得更快。
我写了很多关于如何使用免费或低价资源学习数据科学,而不必花费数千美元接受更正规的教育。然而,能够负担得起你需要学习的材料是一回事,找到你需要学习的时间是另一回事。尤其是如果你有其他的承诺,比如一份全职工作。
为了找到学习数据科学的现实路线,并且可以长期坚持,我建议采取以下步骤:
- 设定一个切实可行的时间表,每周至少包括 5 次强化学习。每节课至少要两个小时。
- 利用空闲时间进行不太紧张的学习,最大化你的整体学习预算。
- 确保你能及时安排休息日,以避免精疲力竭。
除了时间,你还需要学习资源和足够的动力。关于如何找到免费资源和学习动机的指导,请参见我之前的文章。
感谢阅读!
我每月都会发一份简讯,如果你想加入,请点击此链接注册。期待成为您学习旅程的一部分
如何为企业设置技术指标数据科学项目
技术 KPI 是数据科学项目中的必备要素
弗洛里安·伯杰在 Unsplash 上拍摄的照片
数据科学家是受雇使用数据产品解决业务问题的人。然而,数据科学课程的趋势集中在技术方面,而不是业务角度。老实说,如果数据科学家先学习业务而不是技术,他们被聘用的机会会增加。
数据科学家工作的重点之一是技术指标,如准确度、精确度、召回率等。许多数据科学家专注于获得尽可能高的指标,但是多高的指标才算是好的呢?。你可能想在竞争中取得最好的成绩,但做生意不同,很多时候你没有时间这样做。那么,如何为企业设定合理的技术指标呢?本文将通过一个示例帮助您理解如何做到这一点。
本文将从我设置满足业务需求的技术指标的经验中探索一个具体的例子。它可能不适用于您的特定业务,但总体思路应该是相似的。带着那个音符,让我们开始吧。
商业和数据科学
数据科学家懂业务是否必不可少?是的,我会为这种说法辩护。优秀的数据科学家和伟大的数据科学家的区别在于解决业务问题。一个优秀的数据科学家可以开发出最好的模型,但是一个伟大的数据科学家可以开发出满足业务需求的好模型。
在下面的文章中,我就为什么一个伟大的数据科学家是懂业务的人这一问题提出了自己的观点。
每个数据科学家都知道的一个知识是将业务问题模拟成技术需求。每个业务项目都将从业务用户希望数据科学家解决的业务问题开始。我们需要讨论我们的项目将触及的每个业务方面的情况。为什么?因为我们的模式会受到每个商业选择的影响。
例如,业务用户需要一个模型来预测客户购买产品的兴趣。许多人最初会通过开发一个分类模型来进行预测。然而,我认为您应该知道的是业务流程如何向客户销售产品。
最佳模型是在业务流程中使用的模型。想象一下,你已经花了几个月的时间来完善这个模型,却发现你的模型无法使用——因为你使用的特性或者不好的标记。这就是为什么你需要知道业务流程。
了解业务会让你成为伟大的数据科学家,因为你会选择适合问题的特性和模型。此外,您可以为您的数据科学项目设定技术要求。为了帮助您理解技术指标的业务概念,让我们使用一个示例数据集。
设定技术要求的业务模拟
对于这种情况,我会利用我在开发机器学习模型方面的经验来预测交叉销售保险客户。数据集来自 Kaggle 。让我们阅读培训和测试数据,以了解数据集和业务问题。
import pandas as pdtrain = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')train.info()
作者图片
训练数据包含具有 381109 行的 12 个特征。因变量(目标)是响应变量。测试数据包括 127037 个具有相似特征的行,但不包括响应。我们来看看目标变量分布。
import seaborn as sns#Target exploration
sns.countplot(train['Response'])
作者图片
我们的数据中有一个不平衡案例;只有 12%的人对培训数据中的交叉销售感兴趣。
我不会在这里展示我所有的数据探索结果,因为要花很长时间来解释它,但我稍后会将我的笔记本附加到我的 GitHub 上。我将描述业务中的特性含义,以及如何从业务角度对待训练/测试(当前数据)。
现在,在现实世界中选择数据之前,我们需要首先考虑业务流程。然而,在这种情况下,让我们反过来;根据我们拥有的数据集,我们需要考虑使用数据集的业务流程和含义。
比如功能 Driving _ License 是客户有没有驾照的一个特征。如果此功能可以帮助您预测交叉销售的客户,您认为您会使用它吗?也许你会说是,但我会说不是。为什么?从商业的角度来看,尤其是保险,向没有驾驶执照的客户提供保险是不合理的(以我的经验来看)。我会说这个特性变成了一个过滤器,而不是训练数据。
我可以说 Policy_Sales_Channel 特性和 Region_Code 特性也可能产生偏见。一些渠道和地区可能比其他地区销售更多;你能把它介绍给模特吗?我之所以说不,是因为它间接导致了一些渠道和地区被排除在外。
让我们进入本文的要点,建立业务的技术需求。我前面解释的所有业务理解都是理解业务流程所需要的。你需要知道这个行业来自哪里,以及你所使用的每个特性的含义。
业务模拟
在继续机器学习开发之前,我们需要在部署这个模型时考虑业务方面。怎么做呢?通过业务模拟,我们可以计划我们的技术需求目标。首先,我们来考虑一下我们为什么要开发这个机器学习模型?我们希望构建模型,帮助企业产生交叉销售可能性更高的销售线索,以避免致电不感兴趣的客户。
遗憾的是,没有关于代理商数量和联系客户费用的信息。为什么这个信息很重要?因为如果联系客户没有相关的成本,而模型做出了错误的预测,那么为什么不直接给他们打电话,而不是依赖机器学习模型呢?。此外,我们需要考虑项目时间表和能够执行销售线索的代理数量,因为这也会影响业务目标。
此外,我们为什么要考虑项目时间表?想象一下,该模型预测 50000 名客户将进行交叉销售。代理会在一天内执行所有 50000 个客户吗?显然,不是(除非每个客户有 50000 个代理),并且代理会优先考虑他们要呼叫的客户。也许你会认为我们可以让代理在任何时候找到销售线索,只要我们预测到他们会交叉销售;问题是客户的生活会随着时间的推移而改变,在这种情况下预测可能不成立(数据漂移)。这就是项目时间表影响业务和技术方面的原因。
让我们试着概述一下我们需要考虑的业务变量:
1.业务目标(从这个项目来看,要跟踪的业务目标是什么;
常为销售数或换算数)2。接洽/拜访成本(与拜访相关的所有成本、运营成本、代理小费等。)
3。代理编号
4。时间线
5。成功转化收入(成功交叉销售对 ANP 的贡献有多大)
6。销售线索数量(在时间表中会有多少销售线索)
7。模型度量
我们仍然可以想到许多变量,但是让我们首先坚持最简单的一个。那么如何处理这些变量呢?我们需要基于业务流程用这个变量构建一个模拟。这个过程可以是任何事情,因为我不知道这个特定公司的过程是怎样的,但是我可以根据我的经验来模拟它。我的目标是模拟我们能否实现目标。
业务目标(BT)是我们需要在时间线(T)内实现或超越的最终目标。在该项目中,在收到预测后,我们会给代理(A) 一定数量的线索(L) 在时间表内处理。假设每个代理只需要调用转换,那么我们需要关心调用© 的成本。每个电话都会受到代理数量和项目时间表的影响,代理数量多和时间表短都会增加成本,反之亦然。最后,成功转换收入是每个成功呼叫的系数。总收入将受到模型指标(M)** 和销售线索数(销售线索数中有多少成功呼叫转化为收入)的影响。为什么还要对度量进行建模?因为不是所有的电话都会 100%成功。**
业务流程将只有预测感兴趣的销售线索才是被呼叫的销售线索。
如果我们把它变成一个线性方程,我们就把它写成:
BT <= (S * (L * M)) — (L*(C * (A/T))
这个等式并不完美,但我们需要用一个合理的数字来填充它。
我们已经建立了变量和方程。现在,我们只需要把它装满。成本是一个企业的固定数字,我们可以调整,但成功转换收入在每次成功中都是不同的(除非你想说产品总是产生固定收入/ANP)。在这种情况下,我们可以使用来自客户 ANP 的历史数据,例如平均值或中值。对于我们的情况,让我们以列车数据的年保费平均值为例。
#Rounding the ANP Average per cases
round(train['Annual_Premium'].mean())
结果将是 30564 印度卢比。接下来,让我们为模拟操作定义一个函数。
def business_target_simulation(S, L, M, C, A, T):
revenue = (S*(L * M)) - (L * (C * (A/T)))
return revenue
让我们定义一些变量(因为这是模拟,所以您可以更改),我们有:
- 业务目标(BT);假设今年我们希望通过交叉销售计划获得 10.000.000 印度卢比
- 时间线(T)将是一年,这意味着 12 个月
- 每次通话费用©假设 5000 印度卢比
- 代理数量(A),假设为 100
- 成功收入将是 30564 英镑
- 销售线索的数量(L)将与现有人口相关,因为它是交叉销售计划。测试数据包含 127037 人。从培训数据中,我们看到大约 12%的人对销售感兴趣。如果我们将其余数据的 12%作为线索(假设预测模型可能遵循相同的概率分布),我们将有 15244 个客户作为线索。
- 对于模型度量(M ),让我们假设我们使用精度,因为我们需要根据预测的购买兴趣来计算真实的正例。因为业务流程只会调用预测的感兴趣的线索,所以我们需要最大化类 1(感兴趣)的精确度。为什么?因为误报太高(精度低),打了太多电话没有成功收入;sans,成本更高。我们的成本与阳性病例相关(对或错)。
我们要定义我们的技术 KPI,所以让我们模拟各种精度数字。我将创建一个简单的函数来绘制要实现或超越的业务目标的结果。
def simulation_plot(metric_range, S, L, C, A, T, BT):
result = []
for score in metric_range:
result.append(business_target_simulation(S=S, L=L, M = score, C=C, A=A, T=T))
plt.figure(figsize = (8,8))
img = plt.plot(metric_range, result, marker = 'o')
plt.axhline(BT, color = 'red')
return img
让我们输入所有的假设变量,用这个函数来画出函数。
simulation_plot(metric_range = np.arange(0.7, 1.01, 0.01), S = 30564, L = 15244, C = 3000, A = 100, T =12, BT = 10000000)
作者图片
我们的业务目标是 10.000.000 印度卢比,根据我们的模拟,我们需要至少达到 82% 的精度,我们的模型才能对业务产生影响。这个数字相对较高,但肯定是可能的。考虑到这一点,当我们建立模型和 MLOps 时,我们需要确保精度始终高于 82%。你可以随时改变衡量标准,比如准确性、召回率等。然而;如果我们这样做,我们需要调整等式。
当然,这种模拟是基于线性假设,没有考虑随机因素和误差。我们可以试着改变置信区间,但是让我们留待以后讨论。
您可以修改代码和变量,以更好地模拟业务需求。我建议你调整一下线性函数,因为我知道它并不完美。我愿意为这个功能的建议。
我想展示的是模拟的力量,它能够为业务建立技术要求。有了 82%的准确率,我们就能实现业务目标;少于这个数字是不可取的。
资源
这个模拟的所有代码都存储在我下面的 GitHub 页面上。
https://github.com/cornelliusyudhawijaya/Cross-Sell-Insurance-Business-Simulation
结论
伟大的数据科学家是理解业务流程的人。商业理解来自经验,但它肯定是我们可以学习的东西。
在本文中,我概述了如何为业务建立技术需求,尤其是使用业务模拟的能力。
希望有帮助!
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的 简讯。
如果您没有订阅为中等会员,请考虑通过 我的推荐 订阅。
如何设置 AB 测试中的最小可检测效应
(图片来自Unsplash.com)
业内笔记
揭秘最难以捉摸的 AB 测试参数
*“在这个测试中,我们应该使用多大的最小可检测效应?”*无论何时与产品团队建立 AB 测试,确定最小可检测效应(MDE)值都是最棘手的部分之一。关于这个术语的意思存在着许多混乱。以及对于特定的测试应该选择什么值。
在本文中,我想阐明 MDE 的含义,它对实验结果的影响,以及如何找到一个合适的值。
最小可检测效应是什么意思?
MDE 对于计算最小所需样本量是必要的,最小所需样本量是必须收集的观察值的数量。在达到该阈值之前,不得分析 AB 测试的结果。
通常,MDE 被误解为可以检测到的最小影响。这是可以理解的,因为这就是名字的含义。但是如果 AB 测试不能产生显著的结果,如果效应大小小于 MDE,这将意味着测试不能产生任何错误的结果。
MDE 不是 AB 测试中可以检测到的最小可能的影响。
AB 检验中总是存在不确定性因素,这可以通过各种参数来控制,如显著性水平。该参数决定了得出有显著影响的结论的概率,尽管没有影响。尽管没有影响,但总是有可能得到重要的结果,AB 测试总是可以提供重要的结果,尽管影响比 MDE 小。
另一个参数是权力水平,它决定了如果现实中存在积极影响,获得重大成果的可能性。该参数与显著性水平和 MDE 一起决定了实验所需的最小样本量。记住这一点,最小可检测效应的定义可以重新表述如下:
MDE 是应该以一定概率检测到的最小效应大小。
在文献中,术语最小可靠可检测效应被认为是更合适的术语,更符合上述定义。要明确的是,MDE 不是我们期望或想要的效果大小。
为什么 MDE 很重要
想象你站在传送带前,质量检查螺丝从旁边经过。如果你想证明正在生产的 50%的螺丝质量低于标准,在得出结论之前,你会检查多少螺丝?如果你想证明 2%的螺丝是低质量的,这可能会更少。
这个类比可以转移到 AB 测试的世界。我们感兴趣的效应越小,在得出任何结论之前,我们需要收集的样本就越多。所需样本量的增加要求我们进行更长时间的实验。
用 MDE 控制风险和成本
AB 测试是一种控制与特定变更相关的业务风险的机制。每个实验都有与时间相关的成本,比如向一部分用户展示糟糕体验的机会成本。我们进行测试的时间越长,成本就越高。
在某些情况下,拥有非常低的 MDE 会浪费金钱和时间。想象一个产品团队正在一个市场网站上测试一个非常有前途的 MVP。实现这种改变是有风险的,需要花费数月的开发工作,但可能会导致用户转化率的大幅增加。在这种情况下,团队需要至少 5%的转换率来证明成本的合理性。因此,对于根本原因而言,设置明显较低的 MDE 是不必要的,并且会不必要地延长测试时间(测试将超过)。
同时,我们需要确保 AB 测试有正确的统计设置来检测一个效应(如果存在的话)。让我们假设我们进行了一个实验,在这个实验中,我们改变了网站上“立即购买”按钮的内容,以提高转化率。我们的测试只能检测到转化率以一定的概率增加了至少 50%。在这种情况下,即使变化有积极的影响,测试也很可能不会产生任何显著的结果。我们可能会错误地得出结论,认为改变并没有什么不同,并决定继续使用旧的副本(在这种情况下,有人提到了动力不足测试)。
设置适当的 MDE
正如您所看到的,MDE 的正确值在很大程度上取决于用例。它必须了解与潜在实验相关的风险、成本和预期。
**你的最小 MDE 应该是能够证明正在测试的变更的实现是正确的最小效果。**当然,你总是可以战胜考试,从中学到更多。但是在这样做的时候,必须记住进行实验的风险和机会成本。
那么如何得出一个确切的数字呢?这归结为一个简单的 ROI 计算。考虑以下(非常简化的)情况:
- 一个团队正在验证一个 MVP,让用户在旅游网站的收银台购买旅游保险。
- 该网站每天登记 2000 个预订(每年 730.000)。
- 保险的估计净利润是每个用户 3 美元。
- 实现完整的功能将花费团队 ca。150 个开发人员小时,比方说每小时 500 美元,总计 75.000 美元(不考虑任何机会成本)。
以年为基础,该网站必须销售 25000 份保险才能达到收支平衡,相当于 3.42%的预订量加上保险。
由于保险转换率是实验的主要指标,3.42%将是一个合理的 MDE。任何低于这个值的值都不会引起团队的兴趣,并且会不必要地延长测试的持续时间。
摘要
对于大多数 AB 测试参数,从业者倾向于使用行业标准值。显著性水平通常选择为 95%,而 80%是测试功效的默认值。尽管不鼓励盲目使用这些默认值,但它们仍然为找到合理的值提供了一些指导。因为 MDE 没有这样的标准,所以每个 AB 测试都会出现一个合适值的问题。这使得所有团队成员了解这个参数的含义以及如何适当地设置它变得更加重要。
通常,测试持续时间首先是固定的,并且选择 MDE 来适应这个运行时间。可能有很好的理由只进行一周或特定时间的实验。但是这种实践通常会导致测试不足或测试过度,从而导致业务的更高风险或机会成本。因此,MDE 必须基于底层业务案例来选择。这个值决定了必要的样本大小,从而决定了测试的运行时间。
喜欢这篇文章吗?
那么你可能也会喜欢我的另一个关于 AB 测试的帖子:
参考资料和进一步阅读
在线 AB 测试中的统计方法 格奥尔吉·格奥尔杰夫
为成功建立有效的数据分析团队和项目生态系统
应用这些技术创建一个数据分析程序,提供令最终用户满意并满足其需求的解决方案
介绍
在软件开发、信息安全和数据分析的长期职业生涯中,我观察到大型、复杂和压倒性的项目有可能无法满足利益相关者的需求,除非它们管理得非常好。相比之下,我参与的大多数成功的数据分析项目在范围、规模、团队规模和时间上都很小。它们通常需要几天、几周或几个月的时间来完成,而不是几年,并且通常可以满足最终用户的需求。
健全的管理、敏捷的实践、熟练的从业者、强大的工具、标准和指南可以结合起来创建一个数据分析生态系统,从而缩短项目生命周期并提供有用的解决方案。以下部分描述了我的团队为取得成功而开发和利用的一些组织、项目和数据分析属性和技术。虽然我们在大型企业的风险管理和内部审计职能中构建了我们的数据分析计划,但是您也可以将其中的许多技术应用到您的工作环境中。
良好的管理和领导力
在我从事软件开发和数据分析的 34 年中,我观察到了许多管理和领导风格,有好有坏。我最近与一位经理一起工作,他创建了一个框架,并指导我们的团队在一家大型企业中建立了一个成功的部门数据分析程序。根据经验和观察,以下是他和其他模范领导者为帮助个人、团队和项目取得成功而采取的一些品质和行动:
- 为项目设定目标,并管理项目和团队实现目标。
- 确定所需的能力,并雇用和培训员工来实现这些能力。
- 与内部和外部组织合作,分享和学习最佳实践。
- 提供满足需求的强大软件工具。
- 作为高层管理人员的沟通渠道。
- 与团队合作,关心团队及其成员,但不要盛气凌人。
- 确保实施并遵循基本但充分的商定标准、指南和程序。
- 建立成长和成就的节奏。
- 尊重每个团队成员的时间和注意力。
雇佣并发展技能和知识
几年前,我参加了一个数据分析会议,会上一位演讲者描述了她作为数据科学家所需的一些技能。她说有效地完成她的工作需要 200 多种技能。事实上,创建成功的数据分析解决方案需要分析师具备多方面的才能。要聘用和培养具备所需技能和知识的分析师,您和您的管理层可以考虑以下步骤:
- 撰写引人注目的职位描述和公告 —撰写描述成功候选人必须具备的技能和知识的职位描述和公告。此外,列出员工在受雇期间必须发展的技能和知识。
- 聘用具有专业知识和良好潜力的数据分析师 —应用职位描述和职位发布来聘用具有所需技能和知识、资质和潜力的分析师,以开发额外的所需技能。
- 确定学习资源 —创建课程和教程列表,以帮助数据分析师发展在其职位上取得成功所需的技能和知识。
- 评估技能 —衡量团队及其成员的优势和劣势,确定发展和成长需求,根据每个数据分析师的工作描述和深入的能力列表评估他们的技能和知识。
- 培训分析师 —确保工作单位的预算和时间表允许资金和时间用于数据分析师完成培训,以发展所需的技能和知识。根据技能评估结果,确保分析师参加学习资源列表中定义的培训。
保持项目团队的小规模
除非熟练地管理,否则大型团队的复杂项目可能会陷入困境。尝试保持每个项目的规模和范围较小,并将团队规模限制为一至三个最终用户和一名首席数据分析师,可能有助于项目成功。团队可以将数据分析师添加到复杂的项目中,这将受益于分工或互补的技能。对于大型或复杂的项目,您可能希望指派一名项目经理与团队一起确定和管理任务、时间表、风险和问题。最后,在需要时,寻找项目业务领域的主题专家(SME)。
采用敏捷实践
项目团队,尤其是在软件开发中,经常将敏捷开发方法应用到他们的项目中,比如 Scrum 或看板,来组织任务和快速移动。我的团队有效地使用了在 Microsoft OneNote 中开发的看板,在频繁的站立会议上,在团队及其经理之间跟踪和交流任务。它在一页上由三列组成。每项任务在开始时从“准备工作”变为“工作中”,在完成时从“工作中”变为“完成”。
一个简单的看板可以用来管理项目任务。图片由作者提供。
定义简明的范围、目标和时间表
在整个项目生命周期中,与最终用户、团队成员和经理的对话对于建立和坚持一致同意的简明范围、目标和时间表至关重要。通过保持项目紧凑,我成功地完成了一周至三个月的项目。
如果一个项目很大很复杂,可以考虑把它分成更小的子项目,每个子项目都有一个有限的范围、目标和时间表。
将一组合理的竞争性项目和任务分配给数据分析师
一些研究人员发现,当同时处理多项任务时,人类的表现会受到影响。给个人分配大量的项目或任务可能会适得其反。此外,虽然技能和任务多样性是可以提高个人满意度和绩效的工作组成部分(参见工作特征理论),但分配给工人的项目或任务数量应该合理,以允许工人成功完成所有项目或任务。
平衡团队合作和自主性
在一个运转良好的团队中工作可以带来许多好处,例如:
- 队友可以互补彼此的技能。
- 队友之间可以互相鼓励和推动。
- 团队成员可以分享想法,集思广益,找出解决方案。
- 团队的生产力可能超过其各个部分的总和。
有效团队合作的好处是毋庸置疑的。另一方面,一些类型的工作,如数据分析、编程和写作,通常最好由半自主工作的个人来完成,通常需要团队成员的输入。他们的工作需要专注和有限的干扰。
采用并掌握强大而通用的工具和语言
数据分析师应该为自己配备功能强大、用途广泛的数据分析工具,以满足他们的需求。通过这种方法,分析师可以利用每种工具的功能,开发能力和最佳实践。以下部分描述了我当前团队在数据分析项目中使用的每个软件包。
Alteryx Designer——根据 Alteryx 的网站,Designer 可以用来“自动化分析的每一步,包括数据准备、混合、报告、预测分析和数据科学。”虽然单用户许可证需要数千美元,但它是一个强大的数据分析和数据科学工具。我的团队使用它来创建和运行输入数据、转换和准备数据以及以多种格式输出数据的工作流。分析师使用它来快速轻松地创建强大且快速运行的工作流。
Tableau — Tableau 软件创建了一个强大的、或许是最受欢迎的商业智能和数据可视化平台。我的团队使用 Tableau Desktop 连接数据源,开发可视化的工作表和仪表板。然后,我们将视觉效果发布到 Tableau 服务器,最终用户可以在那里观看并与之交互。
Python — Python 是一种用户友好且功能强大的编程语言,深受数据分析师和数据科学家的欢迎。与在数据科学家中也很流行的以统计为中心的 R 语言不同,Python 是一种通用语言。它是免费的,也很容易学。分析师可以用免费的库来扩展 Python 的功能,比如 NumPy 和 TensorFlow 。
Python 编程语言代码示例。图片由作者提供。
SQL —结构化查询语言(SQL)是用于实现、操作和查询存储在关系数据库管理系统(RDBMS)中的结构化数据的标准语言。它包括多种子语言。通过其数据查询语言(DQL),分析师可以从数据库表中查询和检索数据。RDMS 数据库存储了世界各地企业的大量数据集。
SQL(结构化查询语言)代码示例。图片由作者提供。
微软 SQL Server Management Studio(SSMS)—SSMS 是微软的集成开发环境(IDE),用于管理和查询在其 SQL Server RDBMS 中实现的数据库。免费且易于学习,我使用 SSMS 创建并运行 SQL 代码来查询包含所需数据的数据库。
SQL Server Management Studio (SSMS)用于管理 Microsoft SQL Server 数据库和 SQL 代码。图片由作者提供。
Rapid SQL — Rapid SQL 是一个类似于 SSMS 的 IDE,用于开发 SQL 查询以访问存储在 Oracle、SQL Server、DB2 和 SAP Sybase 数据库中的数据。我使用 Rapid SQL 从 DB2 或 Oracle 数据库获取数据。
微软 Visual Studio — Visual Studio 是微软的旗舰集成开发环境(IDE)。我使用 Visual Studio Professional 创建用 Python 和其他编程语言编写的应用程序。它的编辑器具有强大的颜色编码语法。Visual Studio Community 2019是一款免费版的 IDE,可能会满足你的需求。微软的 Visual Studio Code (VS Code)是另一个免费的 IDE,在程序员和数据分析师中很受欢迎。
Microsoft Visual Studio Professional 是用于编写程序和开发应用程序的集成开发环境(IDE)。图片由作者提供。
当然,Excel 是一个无处不在的、有用的、强大的、有时不可或缺的工具。我使用 Excel 工作簿作为项目数据源和输出来创建小型数据集,执行基本的数据清理和计算,等等。像 Excel 这样的电子表格应用程序是任何数据分析或数据科学商店中的重要工具。
电子表格应用程序,如 Microsoft Excel,是通用的数据分析工具。图片由作者提供。
制定基本标准、指南和程序
将简明的标准和指南应用到数据分析项目中,可以提高生产力,维护和共享工作产品。以下是指导我工作的标准和指南。
命名标准——标准化项目,例如文件夹、文件、数据库表、列和字段,使它们易于一致地命名,并在许多产品的集合中找到工作产品。
文件夹结构标准和模板 —对所有项目使用标准文件夹结构,可以轻松创建新项目和查找文件夹和文件。我的团队使用以下文件夹结构模板来组织和存储所有数据分析项目的工作产品:
- Project_name(将此值更改为项目的名称)
- alteryx _ 工作流
- 数据
- 证明文件
- python _ 程序
- sql _ 脚本
- tableau _ 工作簿
文件夹结构会根据每个项目的需求进行扩展和收缩。
编码标准 —编码标准适用于编程,就像语法适用于英语散文一样。它们帮助我们清晰一致地组织和传达思想。我工作过的数据分析和软件开发团队受益于文档化的编码约定。在项目中应用这些标准可以使每个代码模块更容易被最初的编码者编写,也更容易被任何团队成员阅读、理解、增强和维护。下面是我的团队用来指导工作的一些编码标准的描述。
- 类、变量和函数命名惯例 —为了可读性,我们决定用小写字母创建所有的类、函数和变量名称,每个单词或缩写用下划线(“_”)隔开。每个类和变量名描述了它存储的值的类型,而每个函数名描述了该函数用什么值或对象做什么。例如,存储人名的变量可能被称为 person_name 或 person_nm。从数据库中检索人名列表的函数可以称为 get_person_names()。
- 代码模块序言 —我们以文本开始每个模块,描述其用途。为了帮助其他可能维护该模块的编码人员,我们添加了额外的信息,例如作者的姓名、数据库连接字符串、文件位置信息和更改日志。
- 注释 —虽然有人说代码本身就是文档,但我相信恰当的注释可以帮助编码者组织他们的思想,并帮助其他需要维护或增强代码的人更快地理解它。例如,在它的开始,我描述了一个函数用什么数据做什么。我还在执行任务的每个代码逻辑分组前添加了一个简短的注释。
- 空白——为了让代码更容易阅读,我在每个函数、每组变量定义和执行特定任务的每个代码块之间插入了一个空行。
- 简洁的函数范围和可见的大小——和空白一样,我限制了每个函数的内容,以便更容易编码、理解、维护和增强。我努力保持每个函数简单,并试图保持其内容在编辑器中可见(例如 80 个字符宽,40 行长)。
可视化风格指南 —虽然编码标准可以帮助程序员理解、编写和维护代码,但可视化风格指南可以帮助数据分析师开发一致、有用和有意义的视觉效果。它们还可以通过提供一致、设计良好、易于理解和用户友好的视觉效果,使数据分析项目的最终用户受益。以下是我的团队采用的一些视觉风格指南。
- 品牌标准 —我们公司的品牌管理部门已经确定了一套一致的字体、颜色以及视觉设计风格和组件。我们将这些应用到我们的可视化指南中,以增加专业性和一致性,并帮助为最终用户提供熟悉的用户界面风格。
- 字体 —我们公司已经设计了一种字体,当它可供我们使用时,我们将使用它。否则,我们的数据分析产品将默认使用 Ariel 字体。
- 颜色 —我们公司的品牌标准包括一个小调色板。我们尽可能将这些颜色应用于图表、图形和仪表板。我们还试图将图表、图形或仪表板上使用的颜色数量限制在视觉上令人愉悦的范围内。
- 标题、页眉和标签 —我们的指南描述了应用于文本元素的标准位置、字体、大小和颜色,例如仪表板标题、图形和图表页眉、列、过滤器和图例。
- 可视组件的放置 —与文本一样,我们的指南描述了图表、图形、过滤器和图例等元素在仪表板上的标准位置。
摘要
建立一个有效的数据分析团队并不容易,该团队定期构建和交付数据分析解决方案,为最终用户提供见解并帮助他们做出决策。但是,应用我在长期的软件开发和数据分析职业生涯中学到、采纳和发展的一些经验和有效实践,可能会帮助你取得成功。
关于作者
Randy Runtsch 是一名数据分析师、软件开发人员、作家、摄影师、自行车手和冒险家。他和妻子住在美国明尼苏达州东南部。
关注 Randy 即将发表的关于公共数据集的文章,以推动数据分析解决方案、编程、数据分析、自行车旅行、啤酒等。
如何在 Pytorch 中建立深度学习项目
在 Pytorch 中建立深度学习项目的 3 个步骤
Graham Holtshausen 在 Unsplash 上拍摄的照片
在这篇文章中,我将解释如何在 PyTorch 中建立一个深度学习项目。
任何 PyTorch 深度学习项目通常由 3 个基本步骤组成:
- 设置数据集
- 创建数据加载器
- 创建培训、验证和测试循环
我不会讲述如何建立一个实际的模型,因为它相当简单,因任务而异,而且网上已经有很多资源可以学习如何做这件事。
1.设置数据集
为了创建可以与数据加载器一起工作的数据集,以创建可以发送到实际模型中的数据批,PyTorch 要求您为数据集创建一个特定的类,并覆盖它的两个函数:getitem()函数和 len()函数。
在大多数机器学习项目中,在数据实际发送到模型之前,通常需要对数据进行一些预处理。例如,在自然语言处理任务中,这可能涉及对文本进行标记并将其转换成数字格式。为此,我在同一个类中创建可以完成所有这些过程的函数,如 build_dataset()或 preprocess()函数,并将所有预处理数据存储在一个单独的文件中。
getitem 和 len 函数只是数据加载器用来构建小批量数据的函数。在下一节中,您将看到数据加载器如何使用和需要一个数据集对象/类,该数据集对象/类作为参数正确地覆盖了 getitem 和 len 函数,因此正确地实现这两个函数非常重要。
getitem 函数相当简单。想象您的数据集正在被索引。例如,如果您正在执行一项图像识别任务,并且正在处理图像,则每个图像都将从 0 到数据集大小/数据集中的图像数量进行索引。对于 getitem 函数,您所要做的就是,给定一个索引,返回存在于该特定索引的数据的 x,y 对(或输入输出对)。因此,重要的是要记住,您可能应该将数据存储在索引数据集中,如列表中,这样您就可以轻松地访问特定索引处的元素。len 函数只是一个返回数据集长度的函数。以前面将数据存储为列表的例子为例,您只需返回列表的长度。
class MyDataset:
def __getitem__(self, index):
return self.input[index], self.label[index]
def __len__(self):
return len(self.input)
需要注意的是,getitem 函数中的数据不一定是元组。您可以用任何类型的数据结构返回数据。如果您的模型有多个输入,您可以将数据作为字典返回。如果只有一个输入,可以将其作为元组返回。这真的没有关系,因为在训练循环中,您只需正确地从数据结构中检索输入。
class MyDataset:
def __getitem__(self, index):
return {"Input_1": self.input1[index],
"Input_2": self.input2[index],
"Input_3": self.input3[index],
"Label": self.label[index]}
def __len__(self):
return len(self.input1)
2.创建数据加载器
DataLoader 是 Pytorch 提供的一个工具,它使得创建批量数据并将其发送到模型中变得非常容易。它使用我们在上一部分中创建的 dataset 类,以及其他一些东西来创建批处理。下面是你如何编码它们:
from torch.utils.data import DataLoader
data = MyDataset(parameters here)
data.build_dataset()## A helper function to do the preprocessingdataloader = DataLoader(dataset = data, batch_size = batchsize, shuffle=True)
数据加载器提供的一个非常重要的功能是,它们允许我们在将每批数据发送到模型之前,对每批数据应用特定的函数。他们通过 collate 类来实现这一点。collate 是一个一次接收一批数据的类,可以修改该批数据并对数据执行任何特定于批的功能。它是这样工作的:
class MyCollate():
def __call__(self, batch):
## do whatever operations you want here
## return the new batch of data
为了正确地创建 collate 类,您必须重写 call()函数。调用函数将接收一批数据,并返回一批新的、修改过的数据。collate 中 call()函数的输入批处理只是一个通过多次调用数据集中的 getitem 函数构建的列表,这是由数据加载器完成的。列表中的每个项目都是数据集中的一个项目或 x,y 对,可以从数据集类中的 getitem()函数中检索到。批处理的输出必须以稍微不同的方式构建。当您将一批数据发送到模型中时,例如,如果您的批量大小为 16,则模型的输入张量将被构造为一个列表/张量中的 16 个单独的输入,而标签/输出张量将是 16 个单独的标签。因为我们覆盖了 collate 函数,所以我们必须手动完成这个过程。如果我们没有覆盖 collate 函数,那么 Dataloader 将通过默认的 collate 函数自动完成这项工作。
collate 函数的输入结构如下:
(input1, label1),
(input2, label2),
(input3, label3),
(input4, label4),
(input5, label5)
如果批量大小为 5。我们从 collate 函数返回的输出应该是这样的结构:
(input1, input2, input3, input4, input5),
(label1, label2, label3, label4, label5)
假设我正在做一个 NLP 任务。如果我试图将一批中的标记化句子填充到相同的长度(假设是该批中最长句子的长度),那么我会这样做:
class MyCollate():
def __call__(self, batch):
## find maximum length of a sentence
max_len = 0
for item in batch:
max_len = max(max_len, len(item[0]))
new_input = []
new_label = []
for item in batch:
## pad all items in batch to max_len
val = item[0]
val = pad(val, max_len)
##pad is the function you should create
new_input.append(val)
new_label.append(item[1])
new_input = torch.tensor(new_input)
new_label = torch.tensor(new_label)
return new_input, new_label
要将校对功能与您的数据加载器集成,只需执行以下操作:
data = MyDataSet(parameters here)
data.build_dataset()dataloader = DataLoader(dataset = data, batch_size = batchsize, shuffle=True, collate_fn = MyCollate())
shuffle=true 参数只是在创建批处理之前随机打乱数据集中的数据。通常的做法是混洗训练数据加载器的数据,而不是验证和测试数据加载器的数据。关于所有 PyTorch 机器学习项目,需要记住的一点是,模型只能接受张量形式的输入,这就是我在上面的代码片段中返回输入和标签列表之前,将它们都转换为张量的原因。
需要记住的重要一点是,用于在 getitem 函数和 collate 中存储数据的数据结构必须相同,并且它们的大小也必须相同。如果在 getitem 函数中返回一个包含 5 个键值对的字典,则必须在 collate 中返回相同的键。这些值会有所不同,因为您已经对该批数据做了一些预处理。正如我之前提到的,返回的批次的结构会有所不同。如果在 getitem 函数中使用了字典,调用函数的输入将是
{keys:values},
{keys:values},
{keys:values},
{keys:values},
{keys:values}
如果批量大小为 5。每批的密钥都是相同的。返回的输出结构将是
{key1: all values for key1},
{key2: all values for key2},
{key3: all values for key3},
{key4: all values for key4},
{key5: all values for key5}
在大多数机器学习项目中,您通常需要三个不同的数据加载器:一个用于训练循环、验证循环和测试循环。在 PyTorch 中实现这一点非常简单:
from torch.utils.data.dataset import random_splitdata = MyDataset()
data.build_dataset()train_len = int(0.7 * len(dataset))
test_len = len(dataset) - train_len
train_data, test_data = random_split(dataset, (train_len, test_len))
val_len = int(0.33 * len(test_data))
test_len = len(test_data) - val_len
test_data, val_data = random_split(test_data, (test_len, val_len))train_loader = DataLoader(dataset = train_data, batch_size = batchsize, shuffle = True, collate_fn = MyCollate())test_loader = DataLoader(dataset = test_data, batch_size = batchsize, shuffle = False, collate_fn = MyCollate())val_loader = DataLoader(dataset = val_data, batch_size = batchsize, shuffle = False, collate_fn = MyCollate())
您只需使用 PyTorch 提供的 random_split 函数将原始数据集分割成任意数量的部分。我将上面的数据集分成 70%的训练、20%的测试和 10%的验证。在创建每个数据集之后,您可以简单地将它们传递给自己的数据加载器,并定期使用它们。
3.创建培训、验证和测试循环
PyTorch 中的训练、验证和测试循环相当简单,也很相似。以下是创建训练循环的方法:
model = model.to(device)
model = model.train()
for index, batch in enumerate(train_loader):
x = batch[0].to(device)
y = batch[1].to(device)
optimizer.zero_grad()
output = model(x).to(device)
loss = criterion(output, y).to(device)
loss.backward()
optimizer.step()
下面是如何创建一个验证/测试循环(它们是同一个东西,但是有不同的数据加载器)。
model = model.to(device)
model = model.eval()with torch.no_grad():
for index, batch in enumerate(train_loader):
x = batch[0].to(device)
y = batch[1].to(device)
output = model(x).to(device)
loss = criterion(output, y).to(device)
优化器是你选择的优化器(我通常选择 Adam),准则是我通常给我的损失函数起的名字。您必须预先对它们进行初始化,以下是您的操作方法:
import torch.optim as optim
import torch.nn as nnlearning_rate = 1e-3optimizer = optim.Adam(model.parameters(), lr = learning_rate)
criterion = nn.BCEwithLogitsLoss()##you can use any loss function
我们必须在验证/测试循环中指定 with torch.no_grad(),以确保 PyTorch 不会计算反向传播的梯度,因为我们在这里不进行反向传播。如果你不包含这段代码,你的程序仍然可以工作,但是它将消耗更多的内存,因为 PyTorch 将计算和存储我们甚至不会使用的模型的梯度。
关于训练和测试循环,需要指出的一件重要的事情是,即使我将 x = batch[0]和 y = batch[1],您也不需要像这样明确地构造模型的输入(作为一个元组),特别是如果您使用了不同的数据结构。您只需要确保从在 collate 中的 getitem 函数和 call 函数中使用的数据结构中正确地检索数据。需要注意的一点是,某些损失函数需要输出的特定形状/尺寸和 y/标签,因此在从模型中获得输出后,请确保对其进行整形,然后将其发送到损失函数或我在上面命名的标准中。
还有一件重要的事情要记住,你需要把。除了优化器和训练循环中的损失。这将把你的张量和数据放到你指定的设备上。如果您不知道如何创建设备,以下是方法:
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
如果你有一个 GPU,那么设备将自动成为一个 GPU。不然就是 CPU 了。
完成 PyTorch 项目设置的最后一步是将前面的三个步骤结合起来。创建一个初始化所有需要的东西的函数,一个训练模型的函数,一个评估模型的函数。然后你只需要把所有的东西组合在一起,这相对来说比较简单。
您还应该记得将模型权重保存到文件中。除了将模型权重保存到文件中,我还保存了优化器权重。您可以像这样保存模型/优化器权重:
model = Model(parameters here
optimizer = optim.Adam(model.parameters(), lr = learning_rate)
save_dict = {'Optimizer_state_dict': optimizer.state_dict(),
'Model_state_dict': model.state_dict()}
torch.save(save_dict, file_path)
加载模型也非常容易。
load_dict = torch.load(file_path)
model.load_state_dict(load_dict['Model_state_dict'])
optimizer.load_state_dict(load_dict['Optimizer_state_dict'])
我希望你觉得这篇文章简单易懂,内容丰富。如果你有任何问题,请在下面的评论中提出。
如何建立法律合同审查的机器学习模型
行业笔记
深入研究新发布的自然语言处理数据集,以了解合同
合同审查是彻底阅读合同以理解签署合同的个人或公司的权利和义务并评估相关影响的过程。人们普遍认为这是初级律师事务所合伙人必须做的最重复、最乏味的工作之一。这也很昂贵,而且是对法律专业人员技能的低效利用。在这篇博文中,我展示了如何建立一个新发布的数据集和相关的机器学习模型来自动化合同审查。
合同评审需要什么?
谈到合同审查,律师的工作就是手动审查数百页的合同,以找到合同中规定的相关条款或义务。这是重复的,因为他们总是需要在任何给定的合同中识别相同的数据点:合同的生效日期是什么?续约条款是什么?谁参与了这个合同?
律师事务所面临着降低成本的巨大压力,尤其是在 COVID 时代期间和之后。随着自然语言处理(NLP)的最新进展,机器学习模型可以学习自动提取和识别合同中的关键条款,从而节省数百小时的人工劳动。
什么是 CUAD 数据集?
2021 年 3 月, Atticus 项目发布了合同理解 Atticus 数据集(CUAD),该数据集由 500 多份合同组成,每份合同都由法律专家仔细标记,以确定 41 种不同类型的重要条款,总共有 13,000 多条注释。除了数据集,他们还发布了几个经过数据集训练的最先进的变压器模型。你可以在他们的 GitHub repo 找到数据集和训练代码,微调后的模型可以从 Zenodo 下载。
在这篇文章中,我将带你一步一步地建立和运行微调后的模型,这样你就可以用它们来做你自己的预测。
数据准备
你应该可以在你自己的机器上运行这个例子,因为它不是很耗费资源,我们也不需要模型的毫秒级响应。我用的所有代码和笔记本都可以在我的 GitHub repo 里找到。
在第一个笔记本中,1 _ preparation . ipynb,我运行一组 shell 命令来下载数据、代码、模型和库。相反,您可以在终端中轻松运行这些命令。
出于这个博客的目的,我使用的是 roberta-base 模型,它是最小的,但也是表现第三好的模型。当然,你可以选择使用性能更好的 roberta-large 型号或 deberta-v2-xlarge 型号。无论选择哪种模型,加载模型和进行预测的指令都是相同的。所有型号均可在此下载。
运行这些命令后,您的主项目文件夹中应该有以下三个文件夹: cuad-data/ ,其中包含实际的 cuad 数据集*,cuad-models/* ,其中包含模型,和 cuad-training/ ,其中包含用于训练模型的 Python 脚本和 shell 脚本。
CUAD 演示的文件夹结构
加载模型
查看 cuad-training/train.py 中的训练代码,我们可以看到 cuad 模型基于 AutoModelForQuestionAnswering 类,该类是专门为问答任务训练的。这是有意义的,因为我们希望模型通过问它一个问题来识别合同的某些部分(例如,“合同的日期是什么?”).
有了这些知识,我们可以像这样加载模型和它的记号化器(为模型准备输入):
注意,我们将 use_fast 参数设置为 False 。原因是问答(Q & A)模型与具有更智能的溢出处理的快速标记化器不兼容。这完全符合我们的目的,我们只需要记住相应地设置参数。
既然我们已经加载了模型,我们可以用一个样本快速测试它。CUAD 团队提供 JSON 文件中的合同和相关查询数据。41 个查询的完整列表可在此处查看。现在,我们可以使用数据集中的一个契约和查询来测试刚刚加载的模型:
这段代码从 JSON 文件加载第三个查询,询问“合同的日期是什么?”,并显示该合同的前 100 个单词:
查询和签约。我强调了合同中的相关部分。
进行第一次测试预测
问答模型的工作方式是将问题和契约连接在一起(用一个特殊的标记分开),标记化(即准备输入以便模型可以理解),然后输入到模型中。然后,该模型将提供两个输出:开始逻辑和结束逻辑。
开始逻辑描述了字符串中每个单词成为问题答案开始的概率。类似地,结尾逻辑描述了每个单词成为答案结尾的概率。
为了从模型中获得最佳预测,我们现在要做的就是选择具有最高概率的开始和结束标记。
这一切听起来有点抽象,所以我包含了以下两个图表来澄清。第一个图表描述了契约中的每个标记成为答案的开始标记的概率,第二个图表描述了除结束标记之外的相同情况:
每个标记成为开始标记的概率
每个标记成为结束标记的概率
通过分别挑选具有最高概率的两个记号,我们检索总体上具有最高概率的模型预测:
模型预测法
完整代码可以在笔记本2 _ loading _ model . ipynb中找到。
摘要
在这篇博文中,我们介绍了自动化合同审查的挑战以及帮助应对这一挑战的 CUAD 数据集。我们已经下载了数据集并加载了相关的微调模型。然后,我们创建了第一个示例查询,以确保模型正确运行。我们已经查看了模型的输出,并确定了提取模型预测的简单方法。
后续步骤
我们在这里还没有完成:虽然我们现在已经建立并运行了模型,但是我们的方法对于在生产中实际使用来说有点太简单了。首先,您可能已经问过自己:“如果模型预测到一个结束标记在契约中的开始标记之前,该怎么办?”这是一个合理的问题,因为开始和结束标记是由模型独立预测的,所以我们必须实现一些逻辑来解决这个问题。
我们当前方法的另一个限制并不明显,但与问答模型的底层架构有关。这些模型中的大多数,包括这一个,只能接受 512 个令牌(大致相当于 512 个单词),这包括问题和契约的组合。但是这对于我们的用例来说是行不通的:大多数合同都比 512 个单词长得多,例如,特定合同评审查询的答案可能在合同的第 27 页。
在以后的博客文章中,我们将看看如何克服这些限制,以及如何为这个演示设置一个用户友好的 UI。
【2021 年 4 月 13 日编辑: 第二部 现已出版!】
如何为法律合同审查建立机器学习模型—第二部分
克服臭名昭著的 512 令牌限制
由 Raphael Schaller 在 Unsplash 拍摄的照片
这是怎么回事?
在之前的一篇博文中,我们看了如何开始使用新发布的 CUAD 数据集,它有助于自动化合同审查。我们加载了模型,并对一份合同的简短摘录(前 100 个单词)进行了第一次预测。正如文章中提到的,我们用于这项任务的 NLP 模型通常有 512 个单词的限制。这意味着我们建立的模型不能扫描整个合同的信息。相反,它只限于少于 512 个字的合同摘录。
在这篇博文中,我们将看看如何克服这一限制,以便该模型可以在整个合同中搜索律师感兴趣的关键信息。
边注:技术上来说,限制不是 512 个字,而是 512 个令牌。记号是自然语言的组成部分,因此也是 NLP 模型的组成部分。它们通常通过将单词分成子单词来表示:
单词“Highlight”的标记。第一个和最后一个标记是特殊的标记,用于标识文本的开始和结束。
出于我们的目的,这种技术上的区别在很大程度上是不相关的,我将在本文中互换使用术语令牌和单词。
我们试图解决的问题是什么?
上次我们在合同的前 100 个字内搜索了一条特定的信息(合同日期)。这很有效,因为我们在 512 字的限制之内。但是,如果我们试图在整个合同中查找这些信息,我们将会超出这个限制。在这种情况下,我们会收到如下所示的错误消息:
合同过长时的错误消息
错误消息通知我们,合同的令牌数(7,548)超过了该模型允许的最大长度 512。
对于许多类似的问答(Q&A)模型来说,这不是问题。这是因为这些问答对中的相关段落要么少于 512 个单词,要么这些段落被截断以符合单词限制,而不会丢失关键信息。这些类型的问答任务的示例可以在斯坦福问答数据集(SQUAD) 中找到。比如这些关于南加州的段落都短于 512 个字。
一份合同有多少字?
对于法律合同,情况就大不相同了。查看 CUAD 数据集中包含的合同,我们发现只有 3.1%的合同短于 512 个单词。
标识有多少合同短于 512 个字的代码。对于 CUAD 数据集,这将是 3.1%。
我们还可以看到,通过绘制合同长度直方图,我们将遇到大多数合同的 512 字限制:
按长度划分的合同
克服 512 字的限制
为了克服这个限制,合同必须被分成 512 个单词的几个部分。然后,该模型可以单独分析每个部分,并汇总结果以得出最终预测。幸运的是,当模型在 CUAD 数据集中的合同上训练时,程序员们必须克服同样的挑战。这意味着,通过识别训练代码中的相关代码段,我们可以对我们的预测任务使用相同的逻辑。我已经用一个 Python 脚本编译了相关的代码片段。在这一节中,我将介绍这个脚本的关键部分。
将问题和契约转换成模型接受的特性的函数是一个名为*squad _ convert _ examples _ to _ features()的函数。*它的文档和它的实现可以在 Huggingface 网站找到。正如我们从文档中看到的,该函数将一系列问题和合同转换为模型的特性:
将问题和合同转换为模型的特征
然后将生成的要素加载到数据加载器中,并批量输入到模型中。该模型预测开始和结束逻辑,就像我们在第一篇博文中看到的例子一样:
对合同块进行预测
由此产生的开始和结束逻辑适用于合同的各个部分,必须总结为一个最终的模型预测。为此,我们可以利用函数compute _ predictions _ logits():
为了最终的预测,把所有的东西集合在一起
结论
在这篇博文中,我们克服了合同评审 NLP 模型的 512 字限制。这很重要,因为律师在合同中寻找的关键信息可能在文件中的任何地方,正如我们所看到的,大多数合同都比 512 个字长得多。
克服这一限制的代码封装在这个脚本中。在本笔记本中可以找到一个示例,说明如何利用该脚本来回答关于样本合同的 CUAD 数据集的所有 41 个问题。该笔记本的输出包含所有 41 个问题和相应的模型预测。它相当长,所以我将模型预测保存在这个文本文件中,以便于查看。
前 5 个问题和模型预测
有了这些资源,你现在可以自己设计一个法律合同评审模型了。您可以上传一个文本格式的合同,然后运行模型来查找合同中的关键信息,就像我们在这里所做的一样。
在以后的博客文章中,我们将看看如何用 Streamlit 建立一个合同评审的演示网站。这将使得上传合同和使用易于使用的 web 界面运行模型变得更加容易,非常类似于这个例子。