TowardsDataScience-博客中文翻译-2021-二十三-
TowardsDataScience 博客中文翻译 2021(二十三)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
挑战 cy thon——高性能计算的 Python 模块。
原文:https://towardsdatascience.com/challenging-cython-the-python-module-for-high-performance-computing-2e0f874311c0?source=collection_archive---------11-----------------------
现代的替代方案看起来很有希望,Python 可以以闪电般的速度运行。
来自 Pexels 的 Andrea Piacquadio 的照片
在最近的一篇文章中,我们讨论了如何运行 Python,比通常速度快 91 倍。在这篇文章中,我的目的是讨论上一篇文章中没有回答的问题。
与 Python 的传统性能修复技术——cy thon 相比,所提供的解决方案性能如何?
虽然 Python 是一种很棒的编程语言,但是它的性能是它的主要缺点。这种语法简单的优雅语言并不是为更快的计算而设计的。
多年来,Cython 一直在通过将 Python 代码转换为编译后的 C 程序来弥合这一差距。一系列科学计算包依靠 Cython 来加速计算。
让我们将它的性能与它的现代替代品进行比较。
我们将从使用普通 Python 计算质数开始。然后,我们再和它的 Cython 版本进行对比。我们将使用 Python 的多处理模块重复它们,以找出它的好处。
最后,我们将比较现代方法加速 Python 程序的性能。
Cython。vs Python 进行简单计算。
理解 Cython 优势的最直接方式是在基本计算中使用它。在这里,我们使用我在之前的基准测试中使用的相同的方法——计算一个数以下的质数的数量。
我们使用 cProfile 模块来测量每个计算的性能。cProfile 是众多测量代码运行时间的标准 Python 模块之一。
使用 Python 进行计算。
下面的代码将计算 35,000 以下的质数,并打印一份详细的性能报告。
代码片段由作者提供。
运行上面的 Python 代码片段时,输出可能如下所示。根据您的电脑规格,这些数字可能会有所不同。
作者截图。
因为可能有许多因素影响性能,所以明智的做法是多次进行实验,并使用平均值进行比较。在我的个人电脑上执行上述操作的平均时间是 18.721 秒。
使用 Cython 进行计算。
使用 Cython 不同于使用 Python。首先,我们需要将 Python 脚本转换成 c。
- 如果尚未安装 Cython,请安装它。
pip3 install --upgrade cython
2.用以下内容创建一个文件count_prime.pyx
。和以前一样。
代码片段由作者提供。
3.在同一个目录下创建另一个文件setup.py
,内容如下。它会把你的代码编译成 C 程序。
代码片段由作者提供。
4.现在,在终端窗口中运行下面的命令将创建我们的质数计数器函数的 C 版本。
python setup.py build_ext --inplace
5.另外,重命名(或移动)pyx 文件,否则可能会导致导入冲突。
mv count_prime.pyx count_prime_dep.pyx
6.最后,将函数导入到我们的主应用程序中,并像调用任何其他 python 函数一样运行它。
代码片段由作者提供。
运行这个程序的平均时间是 11.210 秒。这是我做的十个试验中的一个的样本报告。
作者截图。
从 18 秒减少到 11 秒是一个显著的进步。Cython 按照预期完成了工作。让我们重复多重处理场景的步骤。
Cython。多处理 vs Python。
Python 中的多处理模块是启动许多子流程的一种极好的方式。每个进程将运行您的代码的一个实例。如果处理器有空闲内核,它们也可以并行运行。
Python 多重处理。
下面的代码将在多个进程中计算 20K、25K、30K、35K 和 40K 以下的质数(如果可能的话,并行计算。)
代码片段由作者提供。
运行上述代码的平均时间为 29.7 秒。输出可能如下所示。
作者截图。
Cython 多重处理。
下面的代码将对我们之前编译的 C 版本重复同样的过程。
代码片段由作者提供。
这一过程的平均时间约为 18 秒,输出可能如下所示。
作者截图。
事实再次证明,Cython 在显著加快 python 处理时间方面是有效的。它将运行整个循环所需的时间减少了 37.9%。
使用 Tuplex 的高性能计算。
我们已经看到使用 Cython 取得了惊人的成功。在简单的质数计数和多重处理应用中,它大大减少了执行时间。
这能更快吗?我们在上一篇文章中讨论的 Tuplex 库比 Cython 版本的性能更好吗?
如果你在 Tuplex 上寻找一个详细的帖子,这里有一个。
单一进程的多路复用器。
Tuplex 将 Python 脚本转换成 LLVM bitecodes,并并行运行它们。结果是性能显著提高。这个新的库专注于数据管道,但它的应用不仅限于数据科学。
下面的代码将使用 Tuplex 运行一次计算。因为我们在并行化方法的 list 参数中只传递一个数字,所以 Tuplex 将在单线程中运行它。
由作者编写的代码片段。
tuplex 方法的平均结果为 9 秒。请注意,我们没有考虑 Tuplex 设置上下文所需的时间。
作者截图。
与 Cython 的 11 秒相比,这令人印象深刻。根据计算机的架构,结果也可能有所不同。但这个数字足够体面,足以表明 Cython 有一个值得尊敬的对手。
并行计算中的多路复用器。
最后一个比较还没有完成,这可能是 Tuplex 的核心目的——并行化。让我们用 Tuplex 计算同样的多重处理练习。调整 Tuplex 单进程示例的最后一行就可以达到这个目的。它应该是这样的。
代码片段由作者提供。
并行运行 Tuplex 代码的结果是惊人的平均 10 秒。完成同样的任务,Cython 用了 18 秒,plain Python 用了 29 秒。
作者截图。
结论
Cython 一直是 Python 程序员可用的主要(也是唯一的)性能补丁。图书馆经常做得很好;因此,许多其他科学计算软件包在内部使用 Cython。
然而,一个相对较新的图书馆 Tuplex 表现良好。在本文中,我们做了一个素数计数实验来比较 Tuplex 和 Cython 版本。执行时间似乎也大大减少了。
但是结果可能会因您的硬件、操作系统和系统状态而异。此外,由于 Tuplex 还不能用于生产,所以必须小心使用。另一方面,Cython 是稳定的,许多生产中的应用程序已经在使用它。
这种比较的全部意义不在于得出一个比另一个更好的结论。图普莱克斯要走到这一步还有很长的路要走。然而,如果 Cython 不适合你的项目,它不是一个死胡同。不再是了。
感谢阅读,朋友!看来你和我有许多共同的兴趣。我很乐意通过 LinkedIn、T2、Twitter 和 Medium 与你联系。
还不是中等会员?请使用此链接 成为 会员。你可以享受成千上万的有见地的文章,并支持我,因为我赚了一点佣金介绍你。
在 Pandas 中更改列数据类型
原文:https://towardsdatascience.com/change-column-data-type-in-pandas-954d7acdef1d?source=collection_archive---------11-----------------------
使用 PYTHON 进行动手数据分析
举例说明-。astype(),。convert_dtypes()和. to_numeric()
克里斯·劳顿在 Unsplash 上的照片
处理数据很少是直截了当的。大多数情况下,需要对导入的数据集执行各种转换,以便于分析。
在我的所有项目中,pandas 从来没有为导入的数据集的所有列检测到正确的数据类型。但同时,Pandas 提供了一系列方法来轻松转换列数据类型。
在这里,您将获得在 Pandas 中改变一个或多个列的数据类型的所有方法,当然还有它们之间的比较。
在整个阅读过程中,资源用📚,快捷方式用⚡️表示, 外卖 用表示📌。不要忘记查看一个有趣的💡在这篇文章的结尾。
您可以快速跟随本 笔记本 📌。
为了让您更容易理解,让我们创建一个简单的数据框架。
熊猫数据框|作者图片
使用这个例子,将更容易理解——如何在 Pandas 中更改列的数据类型。
熊猫。DataFrame.astype()
此方法用于将特定的数据类型分配给 DataFrame 列。
让我们将**int64**
指定为列Year
的数据类型。使用命令**.head()**
和**.info()**
,可以快速查看生成的数据帧。
df1 = df.copy()
df1["Year"] = df1["Year"].astype("int64")
df1.head()
df1.info()
按作者更改单列|图像的数据类型
类似地,可以将该列更改为 Python 中任何可用的数据类型。但是,如果数据类型不适合该列的值,默认情况下该方法会抛出一个**ValueError**
。
憎恨价值观错误???
熊猫有解决办法。此方法中的第二个可选参数μ. e .**errors**
让您可以自由处理错误。此选项默认为 raise,这意味着引发错误并且不返回任何输出。简单地说,将**‘ignore’**
赋给这个参数,忽略错误并返回原始值。
df1["Car"] = df1["Car"].astype("int64", errors='ignore')
❓ 想一次改变所有列的数据类型 ❓
⚡️只是将列名和数据类型对的字典传递给这个方法,问题就解决了。
df1 = df1.astype({"Year": "complex", "Rating": "float64",\
"Car": 'int32'}, errors='ignore')
更简单的是,通过在**astype()**
中直接传递数据类型,为所有列分配一个数据类型,就像下面的例子。
df1 = df1.astype("int64", errors='ignore')
df1.head()
df1.info()
一次更改所有列的数据类型|按作者排序的图像
如上图所示,Year
和Rating
列的**Dtype**
被修改为**int64**
,而其他非数字列的原始数据类型被返回而不抛出错误。
📚 熊猫。data frame . as type()
pandas.to_DataType()
好吧好吧,没有这样的方法叫做 pandas.to_DataType(),但是,如果把 DataType 这个词换成想要的数据类型,就可以得到下面 2 个方法。
pandas.to_numeric()
此方法用于将列的数据类型转换为数值类型。因此,根据列中的值,**float64**
或**int64**
将作为列的新数据类型返回。
df2 = df.copy()
df2["Rating"]=pd.to_numeric(df2["Rating"])
df2.info()
pandas.to_datetime()
在这里,列被转换为 DateTime 数据类型。该方法接受 10 个可选参数来帮助您决定如何解析日期。
df2 = df.copy()
df2["RealDate"] = pd.to_datetime(df2["Service"])
df2.info()
pandas.to_numeric()和 pandas.to_datetime() |作者图片
❓ 需要一次改变多列的数据类型 ❓
⚡ ️Use 的方法**.apply()**
df2[["Rating", "Year"]] = df2[["Rating",\
"Year"]].apply(pd.to_numeric)
类似于**pandas.DataFrame.astype()**
,方法**pandas.to_numeric()**
也给你处理错误的灵活性。
📚pandas . to _ numeric()
📚pandas . to _ datetime()
熊猫。DataFrame.convert_dtypes()
该方法将自动检测最适合给定列的数据类型。默认情况下,**Dtypes**
为**object**
的所有列都将被转换为字符串。
df3 = df.copy()
dfn = df3.convert_dtypes()
dfn.info()
熊猫。DataFrame.convert_dtypes() |作者图片
根据我的观察,这种方法对数据类型转换的控制很差
📚 **熊猫。data frame . convert _ dtypes()T22
总结一下,
在这篇快速阅读中,我演示了如何快速更改单个或多个列的数据类型。我经常使用**pandas.DataFrame.astype()**
方法,因为它对不同的数据类型提供了更好的控制,并且具有最少的可选参数。当然,基于分析需求,可以使用不同的方法,比如将数据类型转换为**datetime64(ns)**
方法**pandas.to_datetime()**
要简单得多。
如何看完所有的中篇文章?
今天就成为媒体会员&获得⚡ 无限制 ⚡访问所有媒体故事的权利。
在这里报名 和 加入我的电子邮件订阅
当你在这里注册并选择成为付费媒介会员,我会从你的会员费中获得一部分作为奖励。
💡项目创意!!
从一个新的 数据集 开始,通过实践 数据争论 技术来评估和清理它,并将其存储在 SQL 数据库 中,以最终在Power BI中可视化它,这可能是一个好主意。
此外,这个项目想法可以用其中给出的资源来实现。正如我常说的,我乐于接受建设性的反馈和通过 LinkedIn 分享知识。
感谢您的阅读和宝贵时间!
如何更改 PySpark 数据框架中的列类型
原文:https://towardsdatascience.com/change-column-type-pyspark-df-eecbe726fdbc?source=collection_archive---------7-----------------------
讨论如何转换 PySpark 数据帧中列的数据类型
Javier Allegue Barros 在 Unsplash 上拍摄的照片
介绍
PySpark 中一个相当常见的操作是类型转换,当我们需要更改数据帧中特定列的数据类型时,通常需要进行类型转换。例如,这很常见(而且是一种不好的做法!)将日期时间存储为字符串,甚至将整数和双精度数存储为StringType
。
在今天的简短指南中,我们将探讨如何在 PySpark 中更改某些 DataFrame 列的列类型。具体来说,我们将讨论如何使用
cast()
功能selectExpr()
功能- Spark SQL
首先,让我们创建一个示例数据框架,我们将在本文中引用它来演示一些概念。
from pyspark.sql import SparkSession# Create an instance of spark session
spark_session = SparkSession.builder \
.master('local[1]') \
.appName('Example') \
.getOrCreate()df = spark_session.createDataFrame(
[
(1, '10-01-2020', '1.0', '100'),
(2, '14-02-2021', '2.0', '200'),
(3, '15-06-2019', '3.0', '300'),
(4, '12-12-2020', '4.0', '400'),
(5, '01-09-2019', '5.0', '500'),
],
['colA', 'colB', 'colC', 'colD']
)
df.show()
*+----+----------+----+----+
|colA| colB|colC|colD|
+----+----------+----+----+
| 1|10-01-2020| 1.0| 100|
| 2|14-02-2021| 2.0| 200|
| 3|15-06-2019| 3.0| 300|
| 4|12-12-2020| 4.0| 400|
| 5|01-09-2019| 5.0| 500|
+----+----------+----+----+*df.printSchema()
*root
|-- colA: long (nullable = true)
|-- colB: string (nullable = true)
|-- colC: string (nullable = true)
|-- colD: string (nullable = true)*
在接下来的章节中,我们将展示如何将colB
、colC
和colD
列的类型分别更改为DateType
、DoubleType
和IntegerType
。
使用 cast()函数
转换数据类型的第一个选项是将输入列转换为指定数据类型的[pyspark.sql.Column.cast()](https://spark.apache.org/docs/3.1.1/api/python/reference/api/pyspark.sql.Column.cast.html)
函数。
from datetime import datetime
from pyspark.sql.functions import col, udf
from pyspark.sql.types import DoubleType, IntegerType, DateType # UDF to process the date column
func = udf(lambda x: datetime.strptime(x, '%d-%m-%Y'), DateType())**df = df \
.withColumn('colB', func(col('colB'))) \
.withColumn('colC', col('colC').cast(DoubleType())) \
.withColumn('colD', col('colD').cast(IntegerType()))** df.show()
*+----+----------+----+----+
|colA| colB|colC|colD|
+----+----------+----+----+
| 1|2020-01-10| 1.0| 100|
| 2|2021-02-14| 2.0| 200|
| 3|2019-06-15| 3.0| 300|
| 4|2020-12-12| 4.0| 400|
| 5|2019-09-01| 5.0| 500|
+----+----------+----+----+*df.printSchema()
*root
|-- colA: long (nullable = true)
* ***|-- colB: date (nullable = true)
|-- colC: double (nullable = true)
|-- colD: integer (nullable = true)***
注意,为了将字符串转换成DateType
,我们需要指定一个 UDF 来处理字符串日期的确切格式。
使用 selectExpr()函数
或者,您可以通过指定相应的 SQL 表达式来使用[pyspark.sql.DataFrame.selectExpr](https://spark.apache.org/docs/3.1.1/api/python/reference/api/pyspark.sql.DataFrame.selectExpr.html)
函数,该表达式可以转换所需列的数据类型,如下所示。
**df = df.selectExpr(
'colA',
'to_date(colB, \'dd-MM-yyyy\') colB',
'cast(colC as double) colC',
'cast(colD as int) colD',
)**df.show()
*+----+----------+----+----+
|colA| colB|colC|colD|
+----+----------+----+----+
| 1|2020-01-10| 1.0| 100|
| 2|2021-02-14| 2.0| 200|
| 3|2019-06-15| 3.0| 300|
| 4|2020-12-12| 4.0| 400|
| 5|2019-09-01| 5.0| 500|
+----+----------+----+----+*df.printSchema()
*root
|-- colA: long (nullable = true)
* ***|-- colB: date (nullable = true)
|-- colC: double (nullable = true)
|-- colD: integer (nullable = true)***
使用 Spark SQL
最后,您甚至可以使用 Spark SQL,以类似于我们使用selectExpr
函数的方式来转换所需的列。
# First we need to register the DF as a global temporary view
df.createGlobalTempView("df")**df = spark_session.sql(
"""
SELECT
colA,
to_date(colB, 'dd-MM-yyyy') colB,
cast(colC as double) colC,
cast(colD as int) colD
FROM global_temp.df
"""
)**df.show()
*+----+----------+----+----+
|colA| colB|colC|colD|
+----+----------+----+----+
| 1|2020-01-10| 1.0| 100|
| 2|2021-02-14| 2.0| 200|
| 3|2019-06-15| 3.0| 300|
| 4|2020-12-12| 4.0| 400|
| 5|2019-09-01| 5.0| 500|
+----+----------+----+----+*df.printSchema()
*root
|-- colA: long (nullable = true)
* ***|-- colB: date (nullable = true)
|-- colC: double (nullable = true)
|-- colD: integer (nullable = true)***
最后的想法
在今天的简短指南中,我们讨论了在 PySpark 中更改 DataFrame 列类型的几种不同方法。具体来说,我们探索了如何将withColumn()
函数与cast()
结合使用,以及如何使用更多类似 SQL 的方法,如selectExpr()
或 Spark SQL。
成为会员 阅读媒体上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
你可能也会喜欢
用于数据湖数据接收的变更数据捕获(CDC)
原文:https://towardsdatascience.com/change-data-capture-cdc-for-data-ingestion-ca81ff5934d2?source=collection_archive---------8-----------------------
意见
随着数据量持续爆炸式增长,业务用户越来越要求持续访问洞察,实时提取所有底层数据不再可行。相反,必须部署解决方案来识别和复制更改日志,以支持接近实时的分析应用程序。
适当的数据接收策略对于任何数据湖的成功都至关重要。这篇博文将提出一个案例,像 Oracle Golden Gate 、 Qlik Replicate 和 HVR 这样的变更数据捕获(CDC)工具最适合从频繁刷新的 RDBMS 数据源中提取数据。
图 1:数据湖的典型数据接收情况。作者图片
大量的数据传输时间限制了数据湖的采用
网络上的大量数据传输时间是限制数据湖采用的一个关键因素。如今,在典型的大型企业中,许多事务性数据源继续驻留在内部数据中心。同时,大多数分析平台已经迁移到云,以利用效用计算能力和云提供商的按需规模。对于大多数大型企业来说,连接到云提供商的冗余、专用 10 Gbps 网络链路非常常见,每月花费数万美元。虽然听起来不错,但在处理超过几 TB 的大型数据集时,10 Gbps 连接有很大的局限性。
图 2:大型数据集传输时间。图片由作者使用谷歌数据(参考下文)
上图描述的数据传输时间是乐观的估计。网络延迟、拥塞、跳数和服务器响应时间等其他因素可能会使真实世界的数据传输速度降低许多数量级。底线是满负荷复制对于大型数据集是不实际的。
自主开发的变更数据捕获(CDC)解决方案的局限性
许多数据工程团队开发自主开发的 CDC 解决方案。自主开发的 CDC 解决方案有两种主要模式:
- 使用时间戳的 CDC 计算 : 这种模式需要在源表上创建、更新和终止时间戳。任何插入、更新或删除行的进程也必须更新相应的时间戳列。不允许硬删除。一旦满足这些条件,计算变更日志就变得很简单了。然而,实施前面讨论的约束并不是一件小事。因此,实际上来说,典型数据库中很少一部分表具有这些时间戳或遵循这种模式。它还创建了源表和提取、转换&加载(ETL)代码之间的紧密耦合。
图 3:使用时间戳列的 CDC 计算。作者图片
- 使用减查询的 CDC 计算 : 这与其说是模式,不如说是反模式。然而,这似乎并没有阻止这种模式在许多生产系统的 CDC 计算中的扩散。在源数据库和目标数据库之间创建一个 DB 链接,并执行一个负 SQL 查询来计算 changelog。这种模式导致大量数据在源数据库和目标数据库之间流动。此外,这种模式只有在源数据库和目标数据库是同一类型的情况下才能工作,例如 Oracle 到 Oracle。
图 4:使用 minis 查询的 CDC 计算。作者图片
上面讨论的两种 CDC 方法都会给源数据库带来很大的负载。此外,减号查询模式也会导致显著的网络负载。
图 5:本土 CDC 计算对网络、CPU 和磁盘的不利影响。作者图片
CDC 工具如何计算 changelog?
CDC 工具通过为 changelog 计算挖掘数据库日志来最小化网络负载和源数据库。
每个支持事务的数据库在将任何更改(插入、更新和删除)写入数据库之前,都会先将其写入数据库日志。这样做是为了确保交易的完整性,避免意外事件,如电源故障等。,而交易仍在进行中。
数据库日志根据文件大小或时间间隔事件在活动日志(重做日志)和归档日志之间循环。根据目标数据库的数据延迟要求,CDC 工具可以访问源数据库的活动日志或归档日志。
图 6:典型 CDC 工具的基本架构。图片由作者提供,灵感来自 Qlik 博客。(参考下文)
由于 CDC 工具只从源数据库日志中读取数据,因此不会增加源数据库的负载。此外,变更日志通常比源表小很多数量级。这种更改日志在网络上的这种流动不会导致任何网络负载问题。
图 7: CDC 工具最小化源数据库和网络上的负载。作者图片
由于数据库日志只包含关于最近的插入、更新和删除的信息,所以 changelog 计算变得很简单。然而,由于有许多数据库供应商,每个供应商都有自己的(有时是专有的)日志格式,所以这种任务最好留给商业 CDC 工具供应商。
CDC 工具 ike Oracle Golden Gate 、 Qlik Replicate 和 HVR 允许以网络高效的方式将事务性数据源与分析数据库近乎实时地同步,同时最大限度地减少对源系统的影响,因此最适合从频繁刷新的 RDBMS 数据源获取数据。
商业 CDC 工具的其他优势
除了最大限度地减少对源系统和网络的影响,大多数商业 CDC 工具还提供其他优势,如:
- 企业级弹性
- 减少 ETL 计算占用空间
- 简化的 ETL 代码库
- 动态轻量级转换
- 失去源数据库和数据接收代码之间的耦合
那么为什么 CDC 工具没有更受欢迎呢?
CDC 工具未被更广泛采用的首要原因是成本。CDC 工具供应商在理解许多数据库的日志格式方面投入了大量资金,这些数据库本身可能会继续发展。这种对持续投资的要求将真正的 CDC 工具前景限制在少数几个关键参与者手中,允许他们为自己的产品收取溢价。
CDC 工具没有被广泛采用的第二个原因是,出于安全原因,源系统 DBA 不愿意向第三方 CDC 工具授予数据库日志级别的访问权限(特权访问)。
以上两种担忧都是有根据的,但是可以通过耐心和努力克服。您需要让 CDC 供应商参与价格谈判,以获得有利的定价条款。如果您还与您的 DBA 进行了详细的讨论,告知他们价值并解决他们的安全问题,那将会很有帮助。
通过实施 CDC 工具将数据吸收到数据湖中,可以释放出巨大的企业价值。我会鼓励你踏上那段旅程。CDC 工具是最好的解决方案之一,可以帮助管理爆炸式增长的数据量和业务用户对接近实时访问洞察的需求,至少在 RDBMS 源频繁刷新数据的情况下是如此。
图片鸣谢:图 2: 谷歌 ,图 6: Qlik 博客
免责声明:这是个人博文。此处表达的观点仅代表我个人的观点,并不代表我现任或前任雇主的观点。所有内容仅用于教育目的,不保证适用性。
如何在 Matplotlib 中改变图形的大小
原文:https://towardsdatascience.com/change-figure-size-matplotlib-11a409f39584?source=collection_archive---------3-----------------------
讨论如何在 Python 中调整用 matplotlib 创建的图形的大小
由 Deon Black 在 Unsplash 上拍照
介绍
在可视化数据时,调整通过 Python 中的matplotlib
生成的图形的大小是一项常见的任务。在今天的简短指南中,我们将讨论几种调整生成图大小的可能方法。
具体来说,我们将讨论如何做到这一点:
- 使用
matplotlib.pyplot.figure()
- 使用
set_size_inches()
- 通过修改
rcParams['figure.figsize']
此外,我们将讨论如何使用现有(默认)大小的因子/比率来调整图形的大小。
首先,让我们使用一些虚拟数据创建一个图表,我们将在本文中使用这些数据来演示几个概念。
import matplotlib.pyplot as pltx = y = range(1, 10)plt.plot(x, y)
plt.show()
下图是使用默认尺寸生成的,如rcParams['figure.figsize']
中所定义。
使用图形
您的第一个选择是调用[matplotlib.pyplot.figure](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.figure.html)
,它用于创建一个新图形或激活一个现有图形。该方法接受一个名为figsize
的参数,用于指定图形的宽度和高度(以英寸为单位)。此外,您甚至可以指定dpi
,它对应于以每英寸点数为单位的图形分辨率。
import matplotlib.pyplot as plt
**from matplotlib.pyplot import figure****figure(figsize=(3, 2), dpi=80)**x = y = range(1, 10)plt.plot(x, y)
plt.show()
使用set_size_inches
第二个选项是[matplotlib.figure.set_size_inches()](https://matplotlib.org/stable/api/figure_api.html?highlight=figure#matplotlib.figure.Figure.set_size_inches)
,用于设置图形的尺寸,单位为英寸。
import matplotlib.pyplot as pltx = y = range(1, 10)plt.plot(x, y)
**plt.gcf().set_size_inches(3, 2)** plt.show()
修改rcParams
如果您想在不使用图形环境的情况下修改图形的大小,那么您也可以更新matplotlib.rcParams
,它是用于处理默认 Matplotlib 值的[RcParams](https://matplotlib.org/stable/api/matplotlib_configuration_api.html#matplotlib.RcParams)
的一个实例。
import matplotlib.pyplot as plt**plt.rcParams['figure.figsize'] = (3, 2)**x = y = range(1, 10)plt.plot(x, y)
plt.show()
请注意,上述内容将对生成的每个图形产生影响,除非您为特定图形指定不同的大小。如果出于任何原因,您想要恢复该参数的默认值,您可以简单地使用如下所示的rcParamsDefault
plt.rcParams['figure.figsize']=plt.rcParamsDefault['figure.figsize']
使用系数调整图形大小
现在,如果您希望使用与另一个图形相关的硬编码因子或比率来调整图形的大小,那么您可以使用以下命令:
figure_size = plt.gcf().**get_size_inches**()
factor = 0.8plt.gcf().**set_size_inches**(factor * figure_size)
最后的想法
在今天的简短指南中,我们讨论了如何调整使用matplotlib
库生成的图形的大小。我们探讨了一些可能的选项,但您应该确保使用符合您需求的选项(例如,取决于您是想要指定所有图形和绘图的大小,还是仅指定一个特定的)。
成为会员 阅读介质上的每一个故事。你的会员费直接支持我和你看的其他作家。
你可能也会喜欢
[## 如何将 Python 包上传到 PyPI
towardsdatascience.com](/how-to-upload-your-python-package-to-pypi-de1b363a1b3)
如何更改 Matplotlib 图中的字体大小
原文:https://towardsdatascience.com/change-font-size-matplolib-480630e300b4?source=collection_archive---------7-----------------------
数据可视化
了解如何在 matplotlib 图形标题、轴标签和图例中更改字体大小
照片由马库斯·斯皮斯克在 Unsplash 拍摄
介绍
通常,你可能需要调整用matplotlib
创建的图形的默认字体大小,以确保所有的元素都被恰当地可视化并易于阅读。在今天的简短指南中,我们将讨论如何更改使用matplotlib
库生成的图中的字体大小。具体来说,我们将探索如何
- 全局更改字体大小(这意味着它将适用于所有生成的图)
- 更改单个组件的尺寸,如轴、图形标题、刻度标签等。
- 以及如何改变已经生成的特定绘图的字体大小
首先,让我们使用一些虚拟数据创建一个示例图,我们将在本文中使用它作为参考,以演示一些概念。
import matplotlib.pyplot as pltplt.plot([1, 3, 5, 7], color='red', label='1st Line')
plt.plot([2, 4, 6, 8], color='blue', label='2nd Line')plt.suptitle('Example Figure')
plt.xlabel('This is x-axis')
plt.ylabel('This is y-axis')plt.legend()
plt.show()
输出图如下所示:
这是我们的示例图—来源:作者
更改所有图和组件的字体大小
如果您想改变所有创建的图形的字体大小以及每个单独图形中显示的所有组件,包括标题、图例、轴标签等,那么您需要更新[rcParams](https://matplotlib.org/stable/api/matplotlib_configuration_api.html#matplotlib.RcParams)
中的相应参数,它是一个包含许多可定制属性的字典。
import matplotlib.pyplot as plt# Option 1
**plt.rcParams['font.size'] = 18**# Option 2
**plt.rcParams.update({'font.size': 18})**
更新font.size
参数后的输出图如下所示:
来源:作者
如前所述,这将产生全局影响,并且会影响图中所示的几乎所有组件,在大多数情况下,这可能不是您真正想要的。
更改单个组件的字体大小
有时候,你可能希望一些组件的字体大小不同于其他组件。例如,您可能需要不同地调整图形标题和图例的字体大小。在这种情况下,您必须通过修改相应的参数来指定每个组件的字体大小,如下所示。
import matplotlib.pyplot as plt# Set the default text font size
**plt.rc('font', size=16)**# Set the axes title font size
**plt.rc('axes', titlesize=16)**# Set the axes labels font size
**plt.rc('axes', labelsize=16)**# Set the font size for x tick labels
**plt.rc('xtick', labelsize=16)**# Set the font size for y tick labels
**plt.rc('ytick', labelsize=16)**# Set the legend font size
**plt.rc('legend', fontsize=18)**# Set the font size of the figure title
**plt.rc('figure', titlesize=20)**
更改特定绘图的字体大小
前面介绍的解决方案将适用于生成的每个图形。如果要调整已创建的单个图的字体大小,则可能需要为每个单独的组件指定字体大小。假设你已经创建了一个支线剧情,那么下面的代码应该可以完成这个任务:
import matplotlib.pyplot as pltax1 = plt.subplot(
111,
xlabel='This is x-axis',
ylabel='This is y-axis',
title='Example subplot'
)**ax1.title.set_fontsize(18)
ax1.xaxis.label.set_fontsize(18)
ax1.yaxis.label.set_fontsize(18)
map(lambda p: p.set_fontsize(18), ax1.get_xticklabels())
map(lambda p: p.set_fontsize(18), ax1.get_yticklabels())**plt.show()
最后的想法
在今天的简短指南中,我们讨论了几种改变用matplotlib
库生成的 Python 图中字体大小的方法。我们探讨了如何为创建的每个组件和绘图更改字体大小,以及如何仅为特定图形更改字体大小。
最后,我们还讨论了如何调整特定组件的字体大小。这通常在您希望图形标题和图例具有不同字体大小时很有用。
成为会员 阅读媒体上的每一个故事。你的会员费直接支持我和你看的其他作家。你也可以在媒体上看到所有的故事。
https://gmyrianthous.medium.com/membership
你可能也会喜欢
https://codecrunch.org/what-does-if-name-main-do-e357dd61be1a
改变您在 Power BI 中处理大型数据集的方法
原文:https://towardsdatascience.com/change-your-approach-with-large-datasets-in-power-bi-ca488a5b1066?source=collection_archive---------3-----------------------
由于内存的限制,当您试图在 Power BI Desktop 中加载具有数亿行的大型数据集时,您可能会遇到问题。让我们探索数据流来实现这一点。
布拉德·斯达克在 Unsplash 上的照片
出发点
我的一个客户的表有 1.26 亿行,并且还在增长。
他的问题是如何在只有 8gb RAM 的 Power BI 桌面中加载这些数据。
而且,他对数据源没有控制权。这种缺乏控制的情况意味着他不能创建带有过滤器的数据库视图,以减少 Power BI Desktop 初始加载的数据集。
至少可以说,这个挑战是有问题的。也许你在过去已经经历过这些。
我有了用 Power BI 数据流来解决这个问题的想法。
为此,我使用了放大的 Contoso 数据集:
图 1 —原始数据集(图片由作者提供)
首先,我将解释解决方案的外观。
然后,我向您展示设置解决方案的步骤。
解决办法
下图显示了该解决方案的体系结构:
图 2 —解决方案的架构(作者提供的图表)
如您所见,我设置了两个数据加载:
- 用数据流直接加载 Power BI 服务中的事实表
- 将所有维度表加载到 Power BI 桌面
这样做的目的是避免 Power BI Desktop 加载数百万行。
我在 Power BI Desktop 中使用了一个预览功能(在撰写本文时预览),它允许我将 Power BI 数据集的实时连接与来自另一个数据源的其他(导入的)表结合起来。
构建解决方案
第一步是分析源数据,并找出如何过滤数据。
目标是将数据量减少到最小,因为我必须将数据加载到 Power BI Desktop 一次。
在我的例子中,我可以简化两个事实表中的数据,以一种简单的方式只加载一年的数据:
图 3 —每个表格一年数据的行数(图片由作者提供)
接下来,我在 Power BI 服务上创建一个数据流。
在我的例子中,我使用了高级的每用户工作空间,以便能够使用大型数据集存储格式:
图 4 —在 Power BI 服务中创建一个新的数据流(图片由作者提供)
下一步是为数据流选择操作:
图 5 —为新数据流选择动作(图片由作者提供)
在我的例子中,我想添加新的表。
为了添加新表,我需要配置源服务器和数据库:
图 6 —新表的数据源(图片由作者提供)
我在我的 Azure 虚拟机上安装了本地数据网关。为了存储我的示例数据库,我在同一个虚拟机上安装了 SQL Server。首先,我必须在网关中配置服务器和数据库。其次,我必须在数据源连接中选择网关。
当您希望使用存储在网关连接中的凭据时,可以保留用户名和密码,也可以为数据源输入其他凭据。
现在,您可以使用一个看起来非常类似于 Power BI 中的 Power Query 编辑器的界面来选择所需的表,并根据需要向数据添加转换:
图 7 —数据流中的查询编辑器(图片由作者提供)
我可以添加一个过滤步骤来过滤数据,如上所述:
图 8 —在 Power Query 中过滤数据(图片由作者提供)
这种可能性是数据流的美妙之处:我可以像在 Power Query 中一样添加过滤器,而无需将数据下载到 Power BI Desktop。数据留在云中。
只要您按下保存并关闭,您就可以开始数据加载。这个过程花费的时间很少,因为我只加载了一小部分数据。
现在,数据集在我的工作区中可见:
图 9 —我的工作空间中的数据流(图片由作者提供)
前缀 DF_ stand 代表数据流,我需要一个惟一的名称,因为我将创建一个同名的数据集。但是我不能有两个同名的对象。
不幸的是,不可能在线创建数据集。
你可以在 idea.powerbi.com 上找到一个关于这个问题的条目:基于数据流的数据集服务
为此,我必须在 Power BI Desktop 中创建一个数据集。
我可以选择 Power BI 数据流作为源:
图 10—Power BI 桌面中作为源的数据流(图片由作者提供)
我将两个表都添加到数据集中,并将报表作为 ContosoRetailDW_Big_BigFacts 发布到服务。
但是这种方法有一个缺陷,正如我在构建结束时发现的那样。请读完,因为我留下它是为了说明这种特定方法的一个缺点。
下一步是编辑数据流,删除两个表上的过滤器并刷新数据。我需要刷新数据流和 Power BI 数据集中的数据。这意味着您必须将相同的数据存储两次。
目前,我不知道这个问题的解决方案。
但是您可以配置数据流和数据集的增量刷新,以减少刷新次数:Power BI 中数据集的增量刷新— Power BI | Microsoft Docs
为了创建最终的 Power BI 报告,我必须将带有两个事实表的数据集添加到新的 Power BI 报告中:
图 11 —从云中获取 Power BI 数据集(图片由作者提供)—名称错误
在右下角的状态栏中,我可以看到我正在使用实时连接:
图 12 —带有实时连接的状态栏(作者提供的图片)
我需要为下一步启用预览功能:
图 13-支持 PBI 数据集的直接查询(图片由作者提供)
单击“了解更多”链接,转到文档页面。在那里你可以找到关于这个特性的有价值的信息。
启用此功能并重启 Power BI Desktop 后,状态栏看起来如上图所示。
我一单击“转换数据”按钮,就会收到一条消息,提示实时连接将被更改为直接查询连接。这一更改允许我向数据模型添加额外的表。
现在,状态栏看起来像这样:
图 14 —直接查询模式下的数据模型(图片由作者提供)
下一步是将所有需要的维度表和表之间的所有关系添加到数据模型中。
当我试图将第二个事实表连接到日期表时,我得到了下面的错误消息:
图 15 —多重关系的错误消息(作者提供的图片)
似乎我必须创建两个数据集:每个事实表
一个,然后在直接查询模式下将两个数据集都添加到报告中。无论如何,我仍然能够使用一个数据流来准备我的数据。
这样,我的模型并不完美,但我可以用它作为原型展示给我的客户。
这个问题就是我在将两个事实表加载到一个数据集中时提到的小故障。
结论
当您开始比较两个 Power BI 文件时,这种方法最显著的效果是显而易见的。一个包含整个数据集,另一个包含复合模型,如本文所述:
图 16 —完整数据集和复合模型之间的大小比较(图片由作者提供)
复合模型的尺寸略大于原尺寸的 1/1000。
而且打开这个模型只需要几秒钟。维度表的数据刷新也需要很短的时间。
缺点是对数据流和带有事实表的数据集执行完全加载需要一个多小时。
但是在使用复合数据模型时,您需要理解所有可能的含义。
SQLBI 在 YouTube 上发布了一个关于这个主题的视频:
数据流和复合模型的结合为管理大型数据集打开了一个全新的世界。您可以在不同的报告中多次重用数据流或数据集的数据,而无需多次重新加载数据。
由 S Migaj 在 Unsplash 拍摄的照片
我希望你能从我的方法中得到新的想法。
市场危机的动态变化:对过去二十年国家、部门和股票行为的回顾
原文:https://towardsdatascience.com/changing-dynamics-of-market-crises-a-review-of-country-sector-and-equity-behaviours-over-the-1933e107fdc6?source=collection_archive---------34-----------------------
演化金融市场行为的数学研究
在本文中,我们研究了过去 20 年中国家金融指数、行业金融指数和股票的行为和相似性。首先,我们引入了一种新的方法来确定 20 个国家和 11 个部门在时间序列结构突变方面的相似性。我们引入了一个新的度量,可以量化任何两个候选集之间的距离,其中概率分布决定了各种元素位置周围的不确定性。接下来,我们转向美国股市,在这里我们进行了三个独立的实验。首先,我们分析了股票危机相关性随时间的演变,强调了近年来在市场恐慌时期股票相似性的增加。接下来,我们研究股票轨迹随时间变化的集体相似性,并证明在危机时期轨迹之间的距离更大。最后,我们通过时变主成分分析来探索我们的股票市场集合的动态。我们强调了在表现出同质行为的资产之间分散投资的当前困难领域,并提出了可能改善投资者多样化的方法。
本次研究的动机:
2020 年 3 月至 6 月,由于新冠肺炎危机,全球市场表现出极端行为。投资者在资产价格下跌和波动中挣扎,因为许多“传统的”多样化战略似乎并不有效。事实上,资产内部的相关性似乎特别高——即使相对于以前的市场危机。这引发了我们的好奇心,我们认为有必要进行彻底的调查。
尽管金融市场参与者可以获得大量数据,但许多投资者倾向于关注最近的过去。这是明智的。市场动态在不断变化,尽管历史可能会押韵,但它肯定不会重演,2020 年的金融市场行为不太可能与 2000 年的完全相同;因为在过去的二十年里,金融市场的许多方面都发生了巨大的变化。这篇论文是带着不同的目的写的。我们希望研究国家、行业和股票行为在过去 20 年中是如何演变的——尤其是在危机时期。我们引入新的方法来检查异常行为、轨迹和时变动态的变化。
我们将分析分为两部分。首先,我们研究国家和部门之间结构突变的相似性。这种分析对于任何希望根据国家或行业风险分散投资的资产配置者或投资者都是有用的。其次,我们研究标准普尔 500 股票,探索相关性、轨迹和时变动态的演变。这项工作的见解可以被任何对股票在过去 20 年中表现出的动态现象感兴趣的全球股票投资者所利用。
数据:
我们的国家和行业数据分别涵盖 2002 年 4 月 1 日至 2020 年 8 月 10 日和 2000 年 4 月 1 日至 2020 年 8 月 10 日,并且每天都进行测量。我们分析的国家包括:澳大利亚、巴西、加拿大、中国、法国、德国、印度、印度尼西亚、意大利、日本、韩国、荷兰、俄罗斯、沙特阿拉伯、西班牙、瑞士、土耳其、英国和美国。我们分析的行业包括:通信、非必需消费品、消费品、能源、金融、医疗保健、工业、信息技术、材料、房地产和公用事业。我们的股票数据涵盖 2000 年 3 月 1 日至 2020 年 8 月 10 日。我们研究了从开始到分析窗口结束的所有标准普尔 500 股票。我们还剩 347 只股票。我们所有的数据都来自彭博。
古怪行为建模:
在本节中,我们研究了 20 个国家指数和 11 个金融市场部门的异常行为的相似性。为了确定相似性,我们将变化点检测方法应用于每个时间序列,并生成变化点集。重要的是,我们使用一种基于功率谱变化检测变化点的方法。这缓解了许多变化点检测方法在面对相关数据时所面临的问题。先前的工作已经证明,本文中应用的方法能够恰当地检测分段自回归过程中的变化点,突出了该算法划分相关数据的能力。对于对所应用的方法感兴趣的人,请参见以下论文之一:
https://www . tandfonline . com/doi/ABS/10.1080/01621459 . 2012 . 716340
https://arxiv.org/pdf/2003.02367.pdf
由于相关性在金融时间序列中是常见的,我们使用上述技术。这种方法是在贝叶斯框架中实现的,并捕获候选变更点周围的不确定性。当测量集合之间的距离时,我们调整先前引入的半度量以考虑候选变化点周围的不确定性。
国家相似度:
国家金融指数的不规则行为集群结构表明,存在一个主要的国家集群,以及其他几个分散的集群。主要集群包括美国、韩国、土耳其、英国、法国、意大利、瑞士、荷兰、加拿大、澳大利亚、德国和沙特阿拉伯。离群国家包括:俄罗斯、巴西、西班牙和中国。这些集群成员和相关的变化点可能是由于这些国家的地理位置和政治关联非常相似,导致在英国退出欧盟等事件期间出现类似的市场行为。值得注意的是,西班牙决心要明显不如欧洲同行相似。集合中最不正常的国家是中国。这并不奇怪,因为许多与当地股票市场相关的特殊限制可能会提供与其他金融市场不同的动力。
扇区相似度:
扇区异常行为树状图由两个明显分开的簇组成。除了原材料和主要消费品之外,主要类别包括所有库存。有趣的是,公用事业、通信和 IT 行业在 2012 年至 2019 年期间没有出现结构性断裂。相比之下,在这个时间窗口期间,在材料部门时间序列中检测到几个变化点。在 2012 年至 2019 年期间,在主要集群(金融、非必需消费品等)的行业时间序列中也发现了变化点。).图 4 显示了通信、公用事业和材料行业的日志回报和检测到的变化点。人们可以看到 2012 年至 2019 年期间结构断裂传播的明显差异。
对比:
为了比较国家和部门之间的相似程度,我们计算了异常行为矩阵的矩阵规范,并根据矩阵中元素的数量对其进行归一化(因为在我们之前的实验中,国家/部门的数量不同)。国家异常距离矩阵标准高于部门异常距离矩阵标准。部门规范中的较小值表明,部门之间的异常行为比国家之间的异常行为更加相似。这可能表明,就国家而言(相对于部门而言),多样化对投资者的好处更大。
权益分析:
在本节中,我们研究了 347 只美国股票,时间跨度约为 20 年。我们将分析分为三个独立的部分。首先,我们检查在不同的离散(和不同的)时间周期内相关系数的行为。接下来,我们研究滚动股票轨迹的集体相似性。最后,我们探讨时变特征谱——作为突出“市场效应”最明显的时间段的一种手段(由领先特征值的大小表示)。
相关性:
在本节中,我们将分析窗口划分为 5 个时段:GFC、峰值 GFC、中期(GFC 和 COVID 之间的时段)、COVID 和峰值 COVID。每个时间分区的日期窗口如下:
- GFC:2007 年 1 月 1 日至 2010 年 5 月 31 日
- GFC 峰:2008 年 9 月 2 日至 2009 年 6 月 1 日
- 临时日期:2010 年 6 月 1 日至 2020 年 2 月 28 日
- COVID:2020 年 3 月 2 日–2020 年 8 月 31 日
- COVID 峰值:2020 年 3 月 2 日–2020 年 5 月 29 日。
在每个周期内,我们计算集合中所有股票的相关矩阵,并绘制相关系数的分布。
图 5 显示了两个发现。首先,在危机时期,股票的相关性明显增强。这在 GFC 和新冠肺炎市场的崩盘中都有所反映,但这种相关性的峰值在这两次崩盘的高峰期更加明显。也就是说,峰值 GFC 和峰值 COVID 分布分别比 GFC 和 COVID 分布更向右集中。其次,这种相关性的增加在最近变得更加明显。图 5 表明,在危机时期,股票行为变得更加相似。这一发现的含义令人震惊,并表明传统的马克维茨启发的投资组合多样化框架必须改变,至少在纯股票投资组合的背景下。
滚动轨迹分析:
在这一节中,我们研究股票轨迹的滚动相似性。为此,我们通过 L1 范数归一化所有轨迹,并在 45 天滚动的基础上计算所有候选轨迹之间的距离。图 6 表明,危机时期提供了最大的轨迹异质性。特别是,网络泡沫、GFC 和新冠肺炎市场危机都在滚动标准计算中显示峰值。
虽然在危机期间,轨迹距离矩阵规范有所增加,但轨迹的方向仍然基本一致。在危机期间,股市的主要方向是下跌。一致性在我们的相关分析中得到证实,其中相关系数更强地为正。这很有意思。
时变主元分析:
最后,我们实现了时变主成分分析,其中我们绘制了每个特征向量所表现出的解释方差的百分比。假设第一个特征向量代表市场的集体力量,当特征谱的第一个元素出现尖峰时,它表示集体市场行为的力量增加。
图 7 显示了互联网泡沫、GFC 和新冠肺炎市场危机期间特征谱第一元素的峰值。这证实了我们在相关性研究中的早期发现,表明在危机时期市场动态明显更加同质。
讨论和限制:
我们的异常行为模型突出了行为最相似和最不相似的部门和国家。在所分析的 20 个国家中,有一个主要由欧洲国家组成的集群。部门异常行为分析在分析的 11 个部门中发现 1 个主要集群。人们发现,原材料和主要消费品的反常行为与其他部门最不一样。我们的(标准化)矩阵规范分析表明,跨部门多元化可能比跨国家多元化更困难。国家不稳定距离矩阵标准的较大值突出了这一点。我们的相关性分析提供了两个见解。首先,股票相关性随着时间的推移而增加。其次,在市场危机期间,股票相关性飙升。我们的轨迹分析和滚动 PCA 表明,尽管在危机期间轨迹显示出最大的异质性,但在这些时期集体市场动态是最强的。这些发现可能会引起全球股票和国际投资者的兴趣,他们关心的是了解市场动态和分散投资组合。
为了便于理解,我将数学讨论/符号减到最少。对于那些对数学细节感兴趣的人,请随时给我发电子邮件,地址是 nickj@arowanaco.com
改变 Power BI 中的数据粒度
原文:https://towardsdatascience.com/changing-granularity-of-data-in-power-bi-3a2b81356990?source=collection_archive---------12-----------------------
有时,您需要以与数据不同的粒度创建报告。让我们看看如何在 Power BI 中解决这一挑战
由卢克·切瑟在 Unsplash 上拍摄的照片
问题是
我使用 Contoso 样本数据集,就像我以前的文章一样。你可以从微软这里免费下载 ContosoRetailDW 数据集。
Contoso 数据可以在 MIT 许可下自由使用,如这里的所述。
现在,让我们看看在线销售事实表(FactOnlineSales)。
当您查看下图时,可以看到每个订单都有一行或多行。每一行都有一个 SalesOrderLineNumber,每一行都有一个 ProductID。
图 1 —样本数据(图片由作者提供)
现在,我有以下问题之一:
- 数据太多—我的数据太多,我想减少数据量以节省空间和内存来提高性能
- 报告需求—我需要根据订单和产品类别创建报告。
- 我不需要最高的粒度,我想从我的数据中删除不必要的细节
因此,我希望将粒度从产品减少到产品子类别,从 OrderLineNumber 减少到 OrderNumber。由于这种减少,我必须连接 Product 表来映射 Product 子类别。
此聚合将数据集从 12'627'608 行减少到 3'432'947 行,同时保留 SalesOrderNumber、CustomerKey 和其他维度引用。
您可以使用三种方法之一来降低数据的粒度:
- 从源系统检索数据时更改它
- 在 Power Query 中的导入过程中更改它
- 在 Power BI 中加载数据后,在 DAX 中更改它
从这三个变体中,我最喜欢第一个。
我的口头禅是:“如果你需要改变你的数据,尽早去做”。
但是,让我们来详细看看这些变体中的每一个:
在源系统中
如果您的源系统是一个关系数据库,编写一个 SQL 查询来聚集您的数据。
聚合查询将如下所示:
SELECT [FOS].[DateKey], [FOS].[StoreKey], [FOS].[PromotionKey], [FOS].[CurrencyKey]
,[FOS].[CustomerKey], [P].[ProductSubcategoryKey], [FOS].[SalesOrderNumber]
,SUM([FOS].[SalesQuantity]) AS [SalesQuantity]
,SUM([FOS].[SalesAmount]) AS [SalesAmount]
,SUM([FOS].[ReturnQuantity]) AS [ReturnQuantity]
,SUM([FOS].[ReturnAmount]) AS [ReturnAmount]
,SUM([FOS].[DiscountQuantity]) AS [DiscountQuantity]
,SUM([FOS].[DiscountAmount]) AS [DiscountAmount]
,SUM([FOS].[TotalCost]) AS [TotalCost]
,SUM([FOS].[UnitCost]) AS [UnitCost]
,SUM([FOS].[UnitPrice]) AS [UnitPrice]
,[FOS].[UpdateDate], [FOS].[DueDate], [FOS].[ShipDate]
FROM [dbo].[FactOnlineSales] AS [FOS]
LEFT OUTER JOIN [dbo].[DimProduct] AS [P]
ON [P].[ProductKey] = [FOS].[ProductKey]
GROUP BY [FOS].[DateKey], [FOS].[StoreKey], [FOS].[PromotionKey], [FOS].[CurrencyKey]
, [FOS].[CustomerKey], [P].[ProductSubcategoryKey], [FOS].[SalesOrderNumber]
,[FOS].[UpdateDate], [FOS].[DueDate], [FOS].[ShipDate];
在分析数据后,我将所有的测量值相加。您需要仔细选择正确的聚合函数,因为简单的求和并不总是正确的选择。
有时,你不能简单地汇总你的数据。您可能需要对汇总的数据进行计算,以获得正确的结果。
如果源不是关系数据库,尽量在源系统中提前准备好数据,以减少 Power BI 中的转换工作。
一些应用程序允许您创建数据的聚合或报告视图,您可以在 Power BI 中使用这些视图。
如果这些都不可能,下一步就是 Power Query。
电源查询
您可以在 Power Query 中使用 Group By 函数来降低数据的粒度。
图 2 —强大查询中的分组依据(作者提供的图)
该特性计算 Power Query 中的分组和聚合,并将数据加载到 Power BI 中。
但是,这种方法的缺点是 Group By 函数不能将查询返回给 SQL Server。这意味着它必须在超级查询引擎中加载整个数据集。只有在所有数据都被加载后,它才能执行分组和聚合。
从 Power BI 的角度来看,在 Datasource 或 Power Query 中使用查询/视图没有区别。Power BI 仍然只能获得包含聚合数据的精简数据集。
当您需要两种粒度时该怎么办?
有时,您需要在更高和更低的粒度级别上进行计算。
在这种情况下,您需要两个表,并且您必须更改您的数据模型以适应所有需求。
在我的例子中,在为产品分类添加了聚合表和新表之后,我的 PBIX 文件需要大约 15%的额外空间。
但是,有时,这不是一个选项,因为您的事实表中可能有更多的数据,并且由于各种原因,您不能简单地向您的模型添加一个更大的表。
当你有大量数据集时,你可以阅读我上一篇关于这个主题的文章:
另一方面,如果您只有少量的数据,您可能希望只有一个事实表,并且您希望动态地更改度量中的粒度。
让我们来研究一下这种方法。
在一定程度上做这件事,让我们看看结果
不幸的是,在改变数据粒度的同时创建一个度量并不容易。有很多变数需要考虑。
我们来看下面这个问题:整体订单的平均销售金额是多少?
我想考虑整个订单,而不是每个订单行的销售额。因此,我必须合计每个订单号的销售总额。然后计算结果的平均值。
这项措施本身并不困难:
AvgSalesOverOrders =VAR SalesPerOrder = SUMMARIZE(‘Online Sales’
,’Online Sales’[Sales Order Number]
,”SalesAmountPerOrder”, SUMX(‘Online Sales’,
[SalesAmount])
)RETURN
AVERAGEX(SalesPerOrder
,[SalesAmountPerOrder])
我的第一种方法是对表变量 SalesPerOrder 使用 AVERAGE()。
不幸的是,AVERAGE 只能处理物化表,也可以是 DAX 表。
但是,我不想创建一个计算 DAX 表来解决这一挑战。我的目标是创建一个 DAX 度量,而不需要向我的数据模型添加更多的表。
在这种情况下,AVERAGEX()是解决方案。
但是结果正确吗?
嗯,看情况。
你可能在我的上一篇文章中读到过,有多种方法可以计算平均值:
在这种情况下,结果是否正确取决于数据的粒度。
我导入了聚合数据,这些数据是用上面描述的 Power 查询方法准备的,作为我的数据模型中一个名为“Online Sales Aggr”的新表。
请看下面的查询:
DEFINE
MEASURE ‘Online Sales’[AvgSalesOverOrders] =
VAR SalesPerOrder = SUMMARIZE(‘Online Sales’
,’Online Sales’[Sales Order Number]
,”SalesAmountPerOrder”
,SUMX(‘Online Sales’, [SalesAmount])
)
RETURN
AVERAGEX(SalesPerOrder
,[SalesAmountPerOrder])
MEASURE ‘Online Sales Aggr’[AvgSalesOverOrders_Aggr] =
AVERAGE(‘Online Sales Aggr’[SalesAmount])
EVALUATE
ROW( “AvgSalesOverOrders”, [AvgSalesOverOrders],
“AvgSalesOverOrders_Aggr”, [AvgSalesOverOrders_Aggr] )
这是结果:
图 3 —两个平均值的结果(图片由作者提供)
为什么会不一样?
第一个度量从最高粒度聚合数据,包括所有细节,直到每个订单号。
第二种使用预汇总数据。但是该表包含每个客户、商店、促销等的详细信息。因此,该表包含的详细信息比测量中生成的表多得多。
因此,预聚合数据在销售额列中的数字较小。这就是平均值较低的原因。
当我将第二个度量的粒度更改为相同的级别时,结果更加相似。
以下是完整的查询:
DEFINE
MEASURE ‘Online Sales’[AvgSalesOverOrders] =
VAR SalesPerOrder = SUMMARIZE(‘Online Sales’
,’Online Sales’[Sales Order Number]
,”SalesAmountPerOrder”
,SUMX(‘Online Sales’, [SalesAmount])
)
RETURN
AVERAGEX(SalesPerOrder
,[SalesAmountPerOrder])
MEASURE ‘Online Sales Aggr’[AvgSalesOverOrders_Aggr] =
AVERAGE(‘Online Sales Aggr’[SalesAmount])
MEASURE ‘Online Sales’[AvgSalesOverOrders_Aggr_2] =
VAR SalesPerOrder = SUMMARIZE(‘Online Sales Aggr’
,’Online Sales Aggr’[Sales Order Number]
,”SalesAmountPerOrder”
,SUMX(‘Online Sales Aggr’
[SalesAmount])
)
RETURN
AVERAGEX(SalesPerOrder
,[SalesAmountPerOrder])
EVALUATE
ROW( “AvgSalesOverOrders”, [AvgSalesOverOrders],
“AvgSalesOverOrders_Aggr”, [AvgSalesOverOrders_Aggr],
“AvgSalesOverOrders_Aggr_2”, [AvgSalesOverOrders_Aggr_2] )
这是结果:
图 4 —相似粒度的结果(图片由作者提供)
无论如何,由于基值不同,结果不可能相等。
每行的值如何影响结果只是众多变量中的一个。您需要验证结果,并相应地改变方法,以从计算中获得正确的结果。
结论
我已经向您展示了三种不同的方法:
- 准备源中的数据
- 在超级查询中操作数据
- 创建一个度量并在那里更改粒度
我更喜欢第一种选择,因为在大多数情况下,这是最有效的方法。
如果您的源是一个数据库,您可以向源传递一个查询,并用它来计算聚合。
第二种选择有一些限制。如上所述,Power Query 无法通过查询折叠将数据的分组和聚合传递给 SQL Server。
因此,Power Query 将始终读取整个数据集,并在 Power Query 中执行聚合,这需要时间和资源。
当您希望将数据保持在最低粒度时,您必须编写一个度量。
但要谨慎。这种方法可能是性能最低的解决方案。
上面显示的第一个度量用了将近两秒钟来计算结果,在查询中只显示结果的总数:
图 5 —对基础数据进行测量的时间(图片由作者提供)
但是在矩阵中使用它需要 15 秒钟以上:
图 6 —矩阵测量的时间(图片由作者提供)
在 Power BI 中,对聚合数据的简单测量需要 65 ms 才能完成:
图 7——对聚合数据进行简单测量的时间(图片由作者提供)
但是,最后一种方法与第一种方法一样计算平均值,只比第一种方法少花了大约 25%的时间:
这里来自查询:
图 8——聚合数据的测量时间(图片由作者提供)
在 Power BI 中,使用与上述相同的矩阵视觉效果:
图 9 —矩阵中聚合数据的测量时间(图片由作者提供)
正确的解决方案取决于用户的需求。如果这些不清楚,你需要向他们展示不同之处,并要求一个简洁的答案,哪个版本是正确的。
平均值只是计算的一个例子。但是您需要澄清基于聚合数据的所有计算的需求。
这同样适用于首先聚合数据的方法。
您可以加载数据两次。一次是所有细节,一次是汇总形式,以便于一些计算。
但是,要注意如何执行聚合。错误的方法会导致不好的结果。
Sascha Bosshard 在 Unsplash 上的照片
我希望我能够给你一些如何处理这种情况的启发。
更改笔记本电池的默认输出 Jupyter 笔记本生产力快速提示
原文:https://towardsdatascience.com/changing-the-cells-default-output-a-quick-jupyter-notebook-productivity-tip-a788c795884c?source=collection_archive---------15-----------------------
我打赌那是你会发现有用的东西
照片由 XPS 在 Unsplash 上拍摄
Jupyter Notebook 是一个友好的 Python 编辑器,适用于所有级别——初学者和有经验的 Python 用户会时不时或几乎每天都想使用它。对我来说,当我为实用程序模块编写脚本时,我喜欢使用 PyCharm。但是,当我处理数据时,我喜欢使用 Jupyter 笔记本。
Jupyter Notebook 对数据科学家的吸引力来自于它的交互性——你总是可以一步一步地检查数据是什么样子的。这是一些初级数据科学家没有意识到的事情——他们可能非常相信自己的编码技能,并认为一切都会很好。然而,如果不密切、持续地关注数据,您可能会得到一个完全错误的数据集。
默认输出行为
至此,我希望你已经养成了坚持检查数据的好习惯。您可能会做如下事情:
检查数据头(图片由作者提供)
在您读取数据集之后,您要做的是使用head
方法检查它的前五行。除了数据导入,有时您可能需要自己创建数据框架:
创建数据框架(图片由作者提供)
但是,正如您可能注意到的那样,DataFrame 在默认情况下没有输出。同样,您必须在数据帧上使用head
方法,或者简单地在另一个单元格中输入数据帧来检查数据。
检查数据帧(图片由作者提供)
当您一致地操作数据时,比如创建新列、设置数据框架的子集、与其他数据框架对象合并,通过调用单元格中的df.head
或df
来检查新的数据框架对象会变得很乏味。显示数据是因为单元格的默认输出行为是显示最后一个表达式的求值结果。
当单元格的最后一个操作是一个计算结果为 None 的语句或表达式时,您不会得到任何输出。例如,当我们创建 DataFrame another_df = pd.DataFrame(data_records)
时,我们没有任何输出,因为它是一个赋值语句,不输出任何东西。
有什么方法可以不用显式调用df.head
就能显示新创建的 DataFrame?
更改默认输出行为
如你所知,Jupyter Notebook 是建立在 IPython 库之上的,它提供了笔记本单元的基本功能。因此,通过快速的 Google 搜索,我意识到我可以通过运行下面的代码来改变默认的输出行为:
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last_expr_or_assign"
本质上,您改变了交互式 shell 在 IPython 中的工作方式,Jupyter Notebook 依赖于 IPython。代码所做的是显示最后一个表达式的计算结果或赋值语句中使用的值。运行上述代码后,让我们看看细胞现在的行为:
更新的输出行为(图片由作者提供)
如您所见,我们不再需要运行df.head
,所有创建的 DataFrame 对象都会自动显示,以便我们检查数据。
太方便了!
除了“last_expr_or_assign”
选项,你还可以尝试其他选项,如下图。对我来说,我觉得这个“last_expr_or_assign”
正是我想要的。
互动选项
“永久地”改变行为
当您使用完当前笔记本并创建另一个笔记本时,您可能会注意到您必须再次运行以下代码。否则,新笔记本的行为将和以前一样,只显示最后一个表达式的计算结果。
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "last_expr_or_assign"
在每一个笔记本里做是不是很繁琐?我不知道你的反应,但我发现它很乏味。
幸运的是,有一个解决方案—我们可以通过将此设置应用到配置文件来更改任何笔记本的默认行为。如果您使用的是 Mac (Windows 有类似的解决方案),您应该能够找到一个隐藏的目录(要显示隐藏的文件/文件夹,在 Finder 中,按下Shift + Cmd + .
)来进行 IPython 相关的设置:
/Users/your_username/.ipython/profile_default
在这个文件夹中,你创建一个名为ipython_config.py
的文件。在该文件中,添加以下代码。代码所做的是获取配置文件,并为任何新创建的笔记本将节点的交互性设置为“last_expr_or_assign”
。
c = get_config()c.InteractiveShell.ast_node_interactivity = "last_expr_or_assign"
创建这个文件后,您会看到它改变了新笔记本的默认单元格输出行为。超级酷吧?
抑制输出
就检查数据而言,更改默认显示行为很方便。但是,您的笔记本可能会变得很长,因为所有的 DataFrame 对象都会显示出来。当然,您可以在检查后删除单元的输出。另一个有用的方法是利用分号符号。请观察下面的截图。
抑制输出
如您所见,如果我们用分号结束我们的赋值,就不会显示更多的输出。如果没有分号,单元格将显示赋值中使用的值。
因此,通过使用分号,我们能够操纵单元格的输出行为,同时享受显示最后一个表达式或赋值的交互的笔记本级设置。
结论
在这篇文章中,我与你分享了一个简单的技巧,可以提高你的生产力与 Jupyter 笔记本。在许多情况下,我们希望在处理过程中不断检查我们的数据,为此,我们可能必须不断使用df.head
或df
,这很繁琐。
通过改变 IPython 中节点的交互模式,我们能够让单元格输出最后一个表达式或赋值,从而避免我们调用这些数据检查方法。此外,我们讨论了如何在不改变每个笔记本设置的情况下,在所有笔记本上一致地实施这种行为。我们还学习了如何在需要时使用分号来隐藏输出。
感谢阅读这篇文章。通过注册我的简讯保持联系。还不是中等会员?通过使用我的会员链接支持我的写作(对你没有额外的费用,但是你的一部分会费作为奖励由 Medium 重新分配给我)。
基因序列的混沌博弈表示
原文:https://towardsdatascience.com/chaos-game-representation-of-genetic-sequences-e0e6bdcfaf6c?source=collection_archive---------31-----------------------
为基因组序列的混沌游戏表示建立 GUI,为度量接近度和聚类算法的应用对 C.G.R 进行矢量化。
国家癌症研究所在 Unsplash 上拍摄的照片
在这篇文章中,我们将详细讨论 C.G.R 在生物信息学中的应用。然后,混沌矩阵将被转换成一个 N 维向量,用于测量接近度和聚类算法的应用。还将构建一个 GUI 来表示一系列序列的 C.G.R 图。
haos 游戏表示法是由 H J Jeffery 于 1990 年提出的一种新方法。这是一种将一维文本序列转换成可视二维矩阵的迭代方法,本质上是非随机输入在迭代函数系统中的应用。最初是为基因组序列引入的,现在它被用于任何包含从代码 32 到 126 的 ASCII 字符的任意符号或字母,这些字符由大写和小写字母以及标点符号组成。
基因组序列通常是通过 **A、T、G、**和 **C 表示的数千兆字节的文本排列。**多年来,已经开发了许多方法来比较序列,这对人眼来说是复杂的。C.G.R 提供了一个可视化的 2D 图,可以立即识别并与其他序列的 C.G.R 图进行比较。C.G.R 显示出基因组的显著模式特征。由于模式对基因组来说是独特的,这可以用来识别基因组片段或检测水平基因转移。此外,C.G.R 模式的定量分析可用于序列比较,用 C.G.R 进行无比对和基于比对的序列比较都是可能的
算法实现
在本节中,我们将深入探讨如何在 MATLAB 和 Python 中为任何给定的序列从头开始创建 C.G.R 图。我遇到了两种不同的迭代算法方法,这两种方法都可以用其中一种语言来实现。这两种算法的基础是相同的,
- 从二维坐标系的原点开始,通常为(0,0)
- 每个核苷酸都有其预定的位置:
A: (-1,1) — T: (1,-1) — G: (1,1) — C: (-1,-1)
- 对于每个核苷酸(以相反的顺序匹配 k-mer 表;即匹配正向马尔可夫链),移动并标记位于当前位置和核苷酸中间的新位置。例如,如果最后一个字母是 T,则位置从(0,0)移动到(1,-1)和(0,0)之间的中点,即(0.5,-0.5)
- 对所有核苷酸重复此程序
上述实现取决于所生成的 k-mers,并且将随着所选择的 k-mers 的长度而变化。
混沌游戏表征
用 k 值为 9 (k 值描述每个 k-mer 的长度)的人类β冠状病毒 fasta 文件测试的上述代码产生了这些图。
C.贝塔冠状病毒的 G.R 图
在 MATLAB 中完成的第二个实现不依赖于 k-mers,仅依赖于每个核苷酸。
黄泰荣、尹正昌、邱淑诗(2016)。DNA 序列的混沌游戏数字编码及其在相似性比较中的应用。基因组学,第 107 卷,2016 年,爱思唯尔公司理论生物学杂志
用人类贝塔冠状病毒 ' fasta' 文件测试的上述代码产生了这些图。
两个冠状病毒序列的混沌博弈图
GUI 实现
照片由西格蒙德在 Unsplash 上拍摄
实现的 python 文件将是 GUI 的框架。 Streamlit 是面向机器学习和数据科学团队的开源 app 框架。在数小时内而不是数周内创建漂亮的数据应用。全是纯 Python。
所用数据集的链接可在这里找到。
给定数据集由' xlsx' 格式的多个序列家族组成,每个家族由属于各自家族的多个序列组成。
窥视其中一个数据集。
GUI 允许用户从数据集中选择任意两个家族,并在这些家族中选择一个序列,该序列将被转换为 C.G.R 图。
两种不同的方法被用来寻找两个序列之间的相似性,向量相关和图像相似性方法。对于矢量相关,给定的 2D 混沌矩阵通过行的线性组合转换成 1D 矢量。这些载体通过 Spearman、Kendal 和 Pearson 的方法进行关联。
SSIM 和 PSNR 指数用于计算图像之间的相似性。计算出的 C . g . r . 2D 图将输入到这些方法中。SSIM 值的范围从 0 到 1,图像相似的分数越高。PSNR 值描述了信噪比,因此图像越近,该值越小。这些方法是进行的一系列实验的一部分,但是从观察来看,这些方法没有产生非常有用的结果。
python 中用于 SSIM 的包有:sc kit-ssim&SSIM-PIL****
实现的源代码可以在 这里找到 。
链接到 GUI:https://share . streamlit . io/rohith-2/chaos-game-representation _ BIOS eq/stream . py
建议的图形用户界面的最终结果
将 C.G.R 矩阵向量化成 N 维元组
在将 C.G.R 的应用扩展到尖端 ML 和深度学习模型的尝试中,可以利用在中公开的通过混沌游戏表示的 DNA 序列的数字编码以及在相似性比较中的应用 中的方法。目的是对属于同一家族的 N 维元组进行聚类,以找出任意两个序列之间的“距离”,并识别未知基因组序列的家族。
矢量器. m
通过选取 3 个基因组家族和这些家族中每个家族的 20 个序列来尝试所提出的想法。出于可视化的目的,元组维度被选择为 3。
********
3D 图的不同视图
未来工作:
这是 C.G.R 的一个基本实现,它没有针对速度或更高 k 值的更好描述进行优化。可以在更高维度更好的特征中使用矢量描述,这可以改进许多 ML 模型分类和基因组序列的模式匹配。
github:https://github . com/Rohith-2/Chaos-Game-Representation _ bio seq
本文使用的数据集来自 NCBI 。
合著者:阿尼鲁德·巴斯卡尔和斯里坎特·安卡姆
参考资料:
- 黄泰荣、尹正昌、邱淑诗(2016)。DNA 序列的混沌游戏数值编码及其在相似性比较中的应用。基因组学,2016 年第 107 卷,爱思唯尔公司理论生物学杂志。
- H.Joel Jeffrey,“基因结构的混沌游戏表示”,收录于核酸研究,第 18 卷,第 8 期,1990 年,第 2163–2170 页。**
混沌理论,侏罗纪公园,为混沌系统做机器学习
原文:https://towardsdatascience.com/chaos-theory-jurassic-park-and-doing-machine-learning-for-chaotic-systems-5ebed9cc72d1?source=collection_archive---------15-----------------------
受《侏罗纪公园》启发,分析混沌理论、机器学习和可预测性
作者图片
来自《侏罗纪公园》的灵感:
我第一次读 1990 年的《侏罗纪公园》小说时,看到了这一段有趣的内容,伊恩·马尔科姆博士解释了混沌理论,并声称通过计算机预测混沌系统是不可能的,同时谈到了预测天气的愿望,一个混沌系统,如何导致冯·诺依曼创造了现代(存储程序)计算机。混乱是侏罗纪世界系列的一个中心主题,也是对事情如何出错的解释。马尔科姆博士不断警告《侏罗纪公园》的创作者约翰·哈蒙德,由于混乱,这样的系统是无法控制和管理的。小说之前随机买了一本混沌理论的书。我不知道这是一本 1987 年的书,马尔科姆博士的角色实际上是受《混乱》的作者詹姆斯·格雷克的启发。意识到这一点后,我更感兴趣地读了那本书。
作为一名数据科学家和 JP fan,我决定做更多的研究和分析,评估在机器学习和计算领域取得最新进展后,这一说法现在如何成立,并分析混沌理论在过去几十年中如何应用和影响科学,特别是计算机科学和数据科学。混沌理论被认为是 20 世纪科学中发现的最重要的概念之一。这是一个有趣且有用的概念,但它很少在数据科学和人工智能领域被谈论,所以我写了这篇关于它的文章。
什么是混沌理论:
混沌理论是对复杂的,通常是非线性系统的研究,这些系统对初始条件和状态的改变高度敏感,并具有复杂的相互作用、混合、非周期性和反馈回路,从而导致快速演化的不规则和经常意外的行为,这是不可预测的。然而,在这种无序之下有潜在的秩序和模式,但据说是不可预测的。当你试图预测更远的未来时,预测会迅速变得更加困难。有时表面上简单的系统也会表现出混乱。
混沌理论创始人 Edward Lorenz 用一种有趣的方式总结:“当现在决定未来,但近似的现在并不近似地决定未来。”,意味着系统是确定性的,但初始条件的微小变化会导致非常不同的不可预测行为的演化。确定性行为似乎是随机的。
混沌理论是著名的蝴蝶效应的基础,这种效应在流行文化和电影中经常被提及。根据洛伦兹的说法:“今天在香港飞舞的蝴蝶可以改变下个月纽约的风暴系统。”
混沌理论的用途:
混沌是世界上普遍存在的现象,混沌理论的概念有着广泛的应用。它们不仅用于促进不同混沌系统的分析,断言考虑和限制,以及检测混沌。它们还被用于设计、生产和改进许多东西,有时是通过利用初始条件和混沌地图来制造混沌。除了物理学、化学和生物学等自然科学的核心领域,一些有趣的应用领域包括密码学、经济学、生态学、农业、天文学、政治学、人类学、生理学、心理学、气象学、地质学、最优化、机器人与控制、计算机科学、电气与电信工程、生殖艺术和纺织品设计。
伪随机数生成用于编程任何随机的东西,这在 AI 和 ML 中很常见。混沌过程及其对初始条件的敏感性被用来产生安全的伪随机数。它们也用于图像加密、制作密码和创建水印。
一些通信系统和电路使用混沌信号来实现安全通信。混沌过程也用于家用电器和消费电子产品。
在机器人学中,混沌动力学以混沌分析或混沌合成的形式使用。混沌合成就是产生混沌来完成任务。混沌分析是对混沌行为的观察和分析。混沌理论被用于群体智能&多智能体系统、双足机器人运动和移动机器人与环境交互的行为分析。它也用于一些运动规划算法。分形也被用于模块化机器人。
分形是复杂的,往往是美丽的视觉图案,源于混沌,在从细胞膜到太阳系的整个宇宙中普遍存在,使事物美丽而独特。它们也用于生成数字艺术和设计纺织品图案等。
混沌理论还用于基于元启发式的优化和进化计算,用于人工智能和机器人,以及许多工程和工业问题,如聚合物制造和电信。混沌被加入到粒子群优化和遗传算法的混沌版本中,以避免局部最优。基于主体的建模和仿真在某些情况下也利用混沌理论。
机器学习中有一些混沌启发的模型训练和优化方法。也有受混沌启发的神经网络架构,在实验中发现混沌神经网络处理信息快速高效。随机梯度下降(SGD)和神经网络训练的收敛性具有混沌行为,最近混沌理论被用来改善当前对神经网络优化的理解并解释为什么 SGD 工作良好。
混沌系统、预测分析和机器学习:
有很多混沌系统的例子,包括流行病、道路交通、密码和股票市场、经济、体育、人群、多智能体系统、自动驾驶、消费者行为、销售和社会,其中许多我也曾参与预测分析。
我相信,对于这样的系统,应该考虑并承认混沌的影响以及由此导致的预测中的限制和挑战,以避免在做出预测时不切实际的期望,特别是如果您没有仔细使用领域知识和专门方法的话。
现代计算能力、数据可用性和机器学习的进步,确实给了我们一种希望,可以在某种程度上预测混沌系统中的不可预测性,如果它们以某种方式了解了无序中的潜在秩序和模式。有预测分析做得很好的例子。这取决于数据和方法以及问题的复杂性和性质。
混沌系统对初始条件和测量精度很敏感,它们需要关于完整系统的详细信息。通常我们没有所需的或足够的数据,特征值是嘈杂的和不准确的。我们还没有在混沌系统中创造复杂的相互作用和变化的所有特征和状态表示。另一个挑战是,由于*“维数灾难”*,拥有更多功能会成倍增加所需的数据和计算。对反馈循环和突发行为的解释也使这个问题变得更加困难。
以下是一些方法和想法,它们被证明在减轻混沌的影响和在这样的混沌系统中进行适当的预测方面是很好的:
一个在机器学习中也很重要的简单想法是对模型和系统进行持续的训练、评估和监控。复杂进化系统的预测分析应该是一个迭代过程。混沌理论特别强调混沌系统在长期范围内的不可预测性,即在未来,因此在未来训练一个新系统是有帮助的。
在一些成功的尝试中,系综方法的使用已经被强调,这些成功的尝试是在具有混沌动力学的系统中进行良好的长期预测。在集成方法中,基于*【群体智慧】*,来自多个模型的预测被组合以获得更好的预测。总体而言,集成也是提高机器学习预测的一种有用和常见的方式。在具有混沌动力学的系统中,它们尤其有用,因为多个模型解决了系统对初始条件、状态变化和噪声测量的敏感性。
像卡尔曼滤波器集成这样的数据同化方法将新的观测结果与模型预报结合起来进行改进。当在混沌系统中进行数值模拟时,它们也用于改进预测,并且有时用于 ML 模型的输入。
反馈回路、序列动力学和跟踪状态是混沌理论和混沌动力学的固有部分。因此,递归神经网络(RNNs)似乎是处理这些问题的自然选择。长短期记忆是一种 RNNs。通过处理像消失梯度这样的问题,它们优于 RNNs。类似 LSTMs 的 rnn 在使用 ML 预测混沌的一些研究和实验中被有效地使用[1]。他们可以利用对过去状态的记忆和序列对未来进行连续的时间序列预测。一些解决方案使用简单的深度神经网络,有时将它们与自回归模型相结合。
相空间是在所有可能状态的 n 维空间中表示的系统状态。该系统遵循该空间中的轨迹,该轨迹是描述该系统的微分方程的解。混沌系统通常无法解决,但它们在相空间中运动的定性行为和风味可以估计。在相空间中有一个被称为吸引子的区域,它被所有的轨迹勾勒出来,它们似乎被吸引了。在奇异吸引子中,由于缺乏关于初始条件的完美信息,我们不知道系统在吸引子上的位置。洛伦兹吸引子是一种奇怪的吸引子,是洛伦兹在对流实验中发现的。它看起来像一个不断螺旋上升的蝴蝶形状,轨迹没有交叉,因为没有任何状态是重复的,显示出非周期性和混沌性。它革新了混沌理论,它的情节成为它的标志。
自动编码器以无人监督的方式学习数据的压缩表示。它们也用于混沌系统中的状态表示,有时与 RNNs 结合使用。他们也可以学习有效地表示混沌系统的吸引子。在实验[2]中,使用具有伪最近邻正则化的 LSTM-自动编码器通过无监督学习来编码和估计洛伦兹吸引子,并从该信息重建状态空间。这类似于使用非线性动力学中使用的延迟坐标编码进行状态估计,同时避免了其局限性。
卷积神经网络(CNN)也可以以时间 CNN 的形式用于顺序建模,时间 CNN 使用 1D 卷积。卷积从时间序列中执行复杂的特征提取。对于一些时间序列问题,它们被证明是 RNNs 的一个很好的替代品,有时也与 RNNs 结合使用。时间细胞神经网络也被应用于混沌系统的预测。一位研究人员[3]将自动编码器与 CNN 结合起来,使用 AE-CNN 对混沌的逐时气象数据进行中长期预测,并使用迁移学习对其进行进一步改进
也有机器学习的应用来控制和减少系统中的混沌,特别是使用强化学习。有时像小波这样的信号处理技术也用于此。
用于混沌系统预测的机器学习的一些最令人印象深刻和最新的应用利用了水库计算(RC)。RC 是基于 RNNs 背后的思想。这个框架对系统状态的演变进行数据驱动的预测。储层是随机连接的非线性单元的复杂网络,使用循环回路存储信息。贮存器通过使用那些递归连接来学习和表示系统的动态。输入是低维时间序列数据,使用储层输入(I/R)模块映射到储层中的高维时间相关向量。动态系统的演变输出状态由油藏-输出(R/O)模块[4]映射和预测。通过学习有限的输出参数来训练 RC 系统。在 RC 系统中,机器学习有助于填补状态信息缺失的空白。
在一些研究工作中,RC 已经被有效地应用于混沌系统预测,并且添加了不同的模块和改进以使它们更好地用于混沌系统。RC 系统[5,6]用于预测复杂和混沌的 Kuramoto-Sivashinsky 火焰传播系统。该系统在没有系统先验知识的情况下,对混沌时空系统进行了高度精确和非常长时间的预测。
在科学和工程中,使用基于模型的方法进行系统分析和预测是很常见的。如果一个好的系统模型是已知的,那么在许多情况下它会比使用 ML 做得更好。领域知识的使用非常有助于数据科学的直接利用,也有助于特征工程和 ML 的结合。所以它不应该总是被忽视。混沌系统中预测分析的几种方法是机器学习和系统模型的混合,或者将领域知识与 ML 算法相结合。
现代天气预报仍然使用气象系统模型和方程进行预报。他们通常使用来自不同模型的预测集合,以减轻信息和初始条件不完善的影响。天气的长期预测仍然不太好,研究表明,在 8 天后,这比使用该日期的历史平均值更糟糕[7]。然而,在使用最大似然法进行长期天气预测方面,一些很好的工作正在进行中,从事这项工作的专家声称非常乐观[8]。改进和大规模部署需要时间。有趣的是,尽管计算能力在过去几十年里有了惊人的增长,但制造现代计算机的主要目标仍未完全实现。
回到马尔科姆博士在《侏罗纪公园》中的主张,我想说,应该记住,在混沌系统中进行预测是具有挑战性的,也是不可靠的。然而,通过使用现代计算以及机器学习和深度学习的进步,在对混沌系统进行体面的预测分析方面取得了一些良好的进展。
参考文献:
[1] M. Modondo,T. Gibbons,“使用 LSTM 循环神经网络学习和模拟混沌”。2018 年多指标类集调查。
[2] Sigrid Keydana,《深度吸引子:深度学习遇到混沌的地方》,RStudio AI 博客,2020 年。
[3]辛,“基于混沌时间序列的 AE-CNN 与迁移学习的预测”,印度复杂性科学,2020 .
[4] H. Fan,J. Jiang,等,“用机器学习实现混沌系统的长期预测”,APS 物理评论研究,2020。
[5] Natalie Wolchover,“机器学习预测混沌的‘惊人’能力”,《量子》杂志,2018 年。
[6] J. Pathak,B. Hunt 等,“从数据中对大型时空混沌系统进行无模型预测:一种水库计算方法”,APS Physics,2018。
[7]马修·卡普奇,“研究表明'特定'天气预报不能提前 10 天以上做出”,华盛顿邮报,2019 年
[8]弗雷德·施穆德,“机器学习会让我们重新思考混沌理论吗?”,风暴地理,2021。
良好特性的特征
原文:https://towardsdatascience.com/characteristics-of-a-good-feature-4f1ac7a90a42?source=collection_archive---------9-----------------------
提示和技巧
为什么在选择模型特征时,预测能力不是一切
来源: flaticon , shutterstock
在保险业,过去的索赔行为对未来的索赔行为有很强的预测性。这可能是用于确定客户是否会提出索赔的唯一最具预测性的信息来源。然而,如果我们只使用索赔历史来构建模型,效果不会很好。通常,模型特征应该来自各种不同的信息源。您的特征选择方法应该旨在从每个不同的信息源中创建一个最具预测性的特征列表。
在本文中,我们将解释如何结合使用可变聚类和特性重要性来创建这样一个候选列表。我们还讨论了可能导致添加或删除功能的其他注意事项。这些包括数据质量和可用性、特征稳定性、可解释性和法律/道德。最后,我们将讨论所有这些因素是如何在一个特性选择框架中结合起来的。让我们从定义我们所说的特征选择的确切含义开始。
什么是特征选择?
在模型开发过程中,特征选择发生在特征工程之后和我们开始拟合模型之前。在特征工程中,我们将原始数据转换成模型特征列表。根据您的问题,此列表可能会很大(即超过 1000 个功能)。功能选择包括缩小到一个候选名单(即 20-40 个功能)。根据您的模型,可能会有另一个特征选择阶段,您可以在其中选择模型特征的最终列表(即 8-10 个特征)。在本文中,我们关注第一个阶段——创建候选名单。
图 1:特征工程和选择概述
我们创建入围名单有几个原因。在模型训练阶段,使用特征的完整列表在计算上是昂贵的。甚至在我们开始训练模型之前,我们将想要探索特征以理解它们与目标变量的关系。还有大量的工作要投入到特性的测试中。没有必要为他们都做这项工作。这是因为完整的列表将包含冗余/不相关的特征。
冗余功能
为了更好地理解这一点,假设您想要创建一个模型来预测某人是否会拖欠汽车贷款。让我们假设,对于每个客户,我们都可以访问月收入、违约和欠款历史、现有债务和一些个人信息。在要素工程过程中,您将在不同的时间段使用不同的聚合从每个来源创建许多要素。在图 2 中,您可以看到一些这样的例子。
图 2:特征工程示例
对于收入,我们预计上述 3 个特征非常相似。我们还可以预期它们会预测违约。然而,它们都捕捉到了收入和违约之间相同的潜在关系。这意味着,一旦我们的模型中有了收入特征,再增加一个也不会提高模型的准确性。我们说剩下的收入特征是多余的。我们希望从候选列表中排除多余的特征,即使它们是可预测的。
无关的特征
我们还希望删除任何不可预测的或由于其他原因不应考虑的特征(例如,在模型中使用该特征是非法的)。这些被称为不相关特征。例如,假设我们使用客户 20 年前的收入创建了一个特性。这些信息已经过时,不能告诉我们任何关于他们当前财务状况的信息。换句话说,这个特性不能帮助我们预测客户是否会拖欠汽车贷款。
图 3:冗余和不相关特性的总结
特征选择的目标是通过移除尽可能多的冗余和不相关的特征来缩小列表。为此,我们需要考虑单个特征的预测能力以及这些特征之间的差异(即预测变量)。这些是主要的考虑因素,我们将在下面深入讨论。
预测能力
我们可以粗略地将预测能力定义为一个特征预测目标变量的能力。实际上,我们需要使用一些度量/统计来估计这一点。一个常见的衡量标准是特征和目标变量之间的相关性。较大的正相关或负相关表明存在很强的关系,或者换句话说,该特征是预测性的。其他度量包括信息值、互信息和特征重要性分数。
不同的措施有各自的优缺点。重要的是,它们让我们能够比较特征,并优先考虑最具预测性的特征。然而,如果这是我们唯一考虑的事情,我们可能不会有一个很好的候选名单。继续我们的汽车贷款例子,假设我们已经创建了表 1 中的特性列表。这是我们所有的特性列表,我们已经根据特性的重要性对它们进行了排序。
表 1:潜在模型特征的完整列表
一般来说,我们可以看到基于违约历史的特征是最具预测性的。这是因为客户过去的违约历史会告诉我们很多关于他们未来是否会违约的信息。所以,假设我们只取了 20 个最有预测性的特征作为我们最终的候选名单。我们最终会得到许多默认的特性。换句话说,候选列表中会有许多多余的特征。
预测变量
这个问题把我们带到了我们应该考虑的第二个因素——预测变量。为了避免有很多冗余的特性,我们需要考虑这些特性彼此之间有多大的不同。为此,我们应该首先从完整列表中创建特征组。组的构建应使一个组中的要素彼此相似,而与其他组中的要素不同。现在,如果我们从每个组/子列表中选取最具预测性的特征,我们最终会得到更少的冗余特征。
可变聚类
问题是我们如何创建这些特征组。我们可以使用领域知识手工完成,或者可能已经有了一个固有的分组。对于我们的汽车贷款示例,我们可以创建 6 个组(5 个主要数据源和 1 个收入和债务组合)。例如,您可以在图 4 中看到默认组和收入组。在这两个组中,这些特征已经按照特征的重要性进行了排序。然后,我们可以从每组中选取 3/4 个最具预测性的特征,从而得到 18 到 24 个特征的候选列表。
图 4:默认和收入特性组
对于许多问题,可能很难手动对特征进行分组。您可能有太多的要素需要手动分组。底层数据源也可能更加复杂。即使以我们的汽车贷款为例,也不清楚这 6 个组是否是最佳分组。例如,个人组中的一个功能是“当前职业”。将这一点包括在收入特征中可能更好。
为了解决这些问题,我们需要一种统计方法来创建相似的组。这些被称为变量聚类方法。例如,您可以使用 Python 中的 VarClusHi 包。这种方法旨在对高度相关的变量进行分组。一个组内的变量应该高度相关,同时不与其他组中的变量相关。你也可以修改聚类方法,比如 K-means,这样它们就可以对变量而不是观察值进行聚类。
其他特征和考虑
使用可变聚类将帮助我们去除冗余特征。使用特征重要性将帮助我们去除不相关的特征,因为它们不具有预测性。在我们使用这些方法之前,我们可能首先想要移除由于其他原因而不相关的特征。同样,我们也有理由想要包含一些特征,即使它们不是可预测的。这些额外的原因总结在图 5 中,我们将在下面进行更详细的讨论。
图 5:一个好特性的特征
数据质量
如果某个特征的数据质量很差,则该特征可能被认为是不相关的。每当我们预期数据集中的记录值与真实值不同时,我们都应该小心。例如,数据可能丢失或输入不正确。通常,较差的数据质量意味着某个特征不具有预测性,并且无论如何都会被排除在外。情况并非总是如此,尤其是当错误是系统性的或者数据不是随机丢失的时候。
在某些情况下,数据可能会被用户或第三方公开处理。以我们的汽车贷款模型为例,用户可能会被要求提供自己的个人信息(例如,原籍国、职业)。用户可能会被诱惑提供给他们获得贷款的更好机会的信息。例如,他们可以谎称自己有一份高薪工作,比如医生或软件开发员。我们需要独立验证这些类型的特征是否正确。
数据可用性
模型通常是在开发环境中创建的。为了实际使用该模型,他们需要转移到生产环境中。由于各种技术问题和成本,某些功能可能在生产环境中不可用。换句话说,这些数据可用于训练模型,但不能用于模型的实时预测。为了有一个工作模型,我们需要排除这些特性。
即使这些特性被排除在最终的模型之外,我们仍然希望将它们包含在我们的候选列表中。这将允许我们继续探索这些特性。如果我们能证明它们是可预测的,这将有助于证明生产这些特征所涉及的工作和成本是合理的。它们可以用于未来的模型中。
稳定性(过去和未来的表现)
仅仅因为你的特征现在是可预测的,并不意味着它们将来也是可预测的。随着时间的推移,特征和目标变量之间的关系可能会发生变化,模型中捕获的关系可能会过时。这些变化是由各种内部和外部力量推动的。例如,COVID 疫情导致了客户行为的突然变化,影响了试图预测该行为的模型。
为了更好地理解这一点,让我们回到汽车贷款的例子。假设,在疫情之前,我们用过去 12 个月中 PERS7 - 的物理分行访问量建立一个模型。当时,倾向于更频繁去银行的客户不太可能拖欠汽车贷款。换句话说,较高的 PERS7 值与较低的违约概率相关。到了疫情,封锁意味着许多互动转移到了网上。这意味着更少的分支机构访问,我们将看到所有客户的 PERS7 值减少。
从我们模型的角度来看,个人债务的下降表明违约风险更高。尽管这些客户的违约风险不会改变,但该模型现在预测了更高的违约概率。组织内外还有许多其他潜在的变化会以这种方式影响你的模型。您需要尽最大努力考虑所有这些因素,并选择对这些变化具有鲁棒性的特性。
可解释性
到目前为止,我们已经讨论了使用平均值和最小值等简单聚合来创建要素。还有更复杂的特征工程技术,如主成分分析(PCA)。例如,从图 4 中,我们可以获得收入组中的所有特征,并计算 PCs。不严格地说,你可以把 PCs 看作是收入特征的总结。我们可以考虑将第一台电脑纳入我们的候选名单。
第一个 PC 可能比任何个人收入特征更具预测性。然而,我们可能仍然只包括收入的简单汇总。这是因为违约和总收入之间的关系比个人电脑更容易理解和解释。最终,我们可以优先考虑一些特性来提高模型的可解释性。如果你想了解为什么可解释性很重要,你可以阅读这篇文章:
法律与伦理
使用某些类型的信息构建模型可能是非法的。例如,为了避免借贷中的性别歧视,使用 PERS65 (客户性别)可能是非法的。即使法律目前没有涵盖这些类型的信息,你可能还是想避免它们。它们可能会导致不道德的后果和公众的反弹。
与直觉相反,你可能仍然想在你的候选名单中包含这些特征。这样就可以进行算法公平性评估。如果不将性别作为一个特征,您就无法确定您的模型是否偏向某一性别。这些类型的要素称为受保护的要素,不应用于构建模型。
具体问题
最后要考虑的是,模型通常会有很多分析。有时这种分析与模型构建没有直接关系,相反,我们想要回答特定的问题。比如,某些地区的客户违约率是否不同?还是倾向于网上互动的客户违约率比去分行的高?在你的候选名单中包含回答这类问题所需的任何特征会很方便。
特征选择框架
最终,以上所有的考虑都需要以某种方式形式化。这就是特性选择框架的用武之地。它将概述选择特征方法的技术细节,包括特征重要性的度量和可变聚类方法。它还可以定义您处理其他考虑事项的方法(例如,需要什么分析来确定一个特性是否稳定)。您可以在图 6 中看到这样一个框架的轮廓。
图 6:特性选择框架的概要
这个框架可能会成为一个更大的建模框架的一部分。与特征选择一起,这将定义特征工程的方法和使用的模型类型。建模框架可以再次成为更大的治理框架的一部分。这就是负责任的人工智能框架。我们将在下面的文章中讨论负责任的人工智能及其目标。
[## 什么是负责任的 AI?
towardsdatascience.com](/what-is-responsible-ai-548743369729)
成为推荐会员
如果你觉得这篇文章很有帮助并且想看更多,你可以成为我的 推荐会员 来支持我
图像来源
所有图片都是我自己的或从www.flaticon.com获得。在后者的情况下,我拥有他们的保费计划中定义的“完全许可”。
参考
名词(noun 的缩写)Siddiqi,信用风险记分卡:开发和实施智能信用评分 (2006)
J.Brownlee ,如何选择机器学习的特征选择方法(2020)https://machinelingmastery . com/Feature-Selection-with-real-and-category-data/
R Doucmentation,变量聚类(2021)http://math . Furman . edu/~ DCS/courses/math 47/R/library/Hmisc/html/var clus . html
打开风险手册,模型衰变(2021)https://www.openriskmanual.org/wiki/Model_Decay
用虚线绘制图表
原文:https://towardsdatascience.com/charting-with-plotly-dash-ee9334441c11?source=collection_archive---------20-----------------------
2:用于转换的单选项目
由马腾·范登赫维尔在 Unsplash 上拍摄的照片
生物燃料
生物燃料无疑是取代目前用于车辆推进的化石燃料的最有吸引力和最实用的选择。生物乙醇和生物柴油从富含糖类和淀粉的农作物中提取,具有减少二氧化碳排放和缓解气候变化不利影响的潜力。
阿根廷的生物燃料部门在过去十年中发展迅速,成为国民经济中一项非常活跃的活动,也是生产发展的一个有趣案例。
在阿根廷,生物柴油完全是以大豆为原料生产的,大豆油是制造这种生物燃料的主要原料。生物柴油的生产吸引了大量国内外投资,在阿根廷生产链中加入了一个新的环节,将生产分为国内市场和出口市场。
阿根廷的生物乙醇生产以糖蜜为基础,糖蜜是制糖的副产品,直接来自甘蔗(Sacharum officinarum L)和谷物,主要是玉米 ( 玉蜀黍)。液体生物燃料的产生对甘蔗转化链是一个有价值的补充。
仪表盘应用
在之前的一篇文章中,我们讨论了 Dash 的基本特性:一个开源的免费库,麻省理工学院许可的 python 框架,广泛用于创建基于 web 的、可定制的、交互式的、响应性强的仪表盘和 dataviz 应用程序。
Dash 主要基于 ReactJS,Flask,和 Plotly。Dash 建立在 ReactJS 的顶部作为前端;它使用 Flask 作为后端,Plotly 作为数据可视化工具。
如上一篇文章所述,Dash 包括三个主要的库:(1) dash_html_components ,它提供了多种 html 标签的 python 版本,可以在标题、段落、图形等应用中使用。;(2) dash_core_components ,提供下拉菜单、单选按钮、图表、滑块、按钮等多种元素;(3)*dash _ bootstrap _ components,*用于样式化用户界面。
本质上,Dash 应用程序( Dash Apps )由两部分组成:(1)描述应用程序外观的应用程序的“布局”和(2)允许应用程序交互的“回调”。
我们的仪表板外观(我们的布局)由以下内容组成:在左上角,一个条形图显示了阿根廷的生物乙醇总产量,另一个图表(转换)显示了甘蔗产量和玉米产量之间的比例。在右上角,一个条形图显示了阿根廷的生物柴油总产量,另一个图表(转换)显示了出口和国内市场产量之间的关系。在左下方,我们包括了一个堆积面积图,显示了 2015 年至 2020 年期间主要生物乙醇生产国的发展情况。最后,在我们布局的右下方,我们包括了一个面积图,显示了 2010 年至 2019 年期间世界生物柴油生产的发展。
我们的仪表板的转换是通过使用由 dash_core_components 库提供的组件 RadioItems 来实现的。功能 dcc。来自 Dash 库 dash_core_components 的 RadioItems() 允许我们呈现一组复选框。我们必须编写类似 dcc 的代码。放射性项目(选项=[..],value=) ,其中选项是带有键的字典列表,值是当前选择的值。
Dash App 的交互性是通过使用回调函数来实现的。在我们的仪表板中,我们必须创建一个回调函数来指示哪些图表显示在布局的顶部。如前一篇文章所述,回调函数有两个主要部分:(1)装饰器,使用 @app.callback() 初始化;(2)用 def 关键字初始化的函数。
带破折号的图表
我们与四个公共领域数据集 : (1)阿根廷,系列 Históricas,Indicadores del Sector energyético,Biocombustibles,Cuadro 3.1: 生物柴油; (2)阿根廷,Históricas 系列,能源部门指数,生物燃料,Cuadro 3.2: 生物乙醇;(3) 世界燃料乙醇年产量; (4) EIA,美国能源信息署,国际,生物燃料。
首先,我们将 Pandas 库导入为 pd,将 Plotly Express 导入为 px,将 plotly.graph_objects 导入为 go,并将我们的第一个 csv 文件转换为 dataframe:
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go# Step 1: Argentine bioethanol production (units in m3)
df_bioet = pd.read_csv(path + 'produccion_de_bioetanol.csv',
index_col = False, sep = ';',
engine = 'python',
header = 1, skiprows = 2, skipfooter = 3)
下面这张截图( df_bioet )展示了一个数据科学家最糟糕的噩梦:一个数据帧,有缺失数据、冗余数据、重复数据、缺失列名、列名不一致、奇怪字符等。
因此,我们必须努力将其转换为适合制图的数据框架:
df_bioet = df_bioet.drop(0)df_bioet.columns = ['Year','Period', 'Tot_Prod', 'Perc_Tot', 'Cane_Prod','Perc_SCT', 'Corn_Prod', 'Perc_Corn', 'Market', 'Perc_Mkt']cols_to_drop = ['Perc_Tot', 'Perc_SCT', 'Perc_Corn', 'Perc_Mkt']df_bioet = df_bioet.drop(cols_to_drop, axis = 1)
df_bioet['Year'] = df_bioet['Year'].str.replace('*', ' ')df_bioet['Tot_Prod'] = df_bioet['Tot_Prod'].str.replace(',', '')
df_bioet['Cane_Prod'] = df_bioet['Cane_Prod'].str.replace(',', ''
df_bioet['Corn_Prod'] = df_bioet['Corn_Prod'].str.replace(',', '')
df_bioet['Corn_Prod'] = df_bioet['Corn_Prod'].str.replace('-', '0')
df_bioet['Market'] = df_bioet['Market'].str.replace(',', '')
df_bioet['Market'] = df_bioet['Market'].str.replace('-', '0'
df_bioet.reset_index()f = df_bioet['Year'].notnull()
serie = df_bioet.loc[f, "Year"] = df_bioet['Year'].ffill()
df_bioet['Year'] = seriedf_bioet['Year'] = df_bioet['Year'].astype(int)
df_bioet['Tot_Prod'] = df_bioet['Tot_Prod'].astype(int)
df_bioet['Cane_Prod'] = df_bioet['Cane_Prod'].astype(int)
df_bioet['Corn_Prod'] = df_bioet['Corn_Prod'].astype(int)
df_bioet['Market'] = df_bioet['Market'].astype(int)
df_bioet['Period'] = df_bioet['Period'].apply(str)tipo1 = df_bioet.dtypespvt1 = pd.pivot_table(df_bioet, index = ['Year'],
values = ['Tot_Prod','Cane_Prod','Corn_Prod' ],
aggfunc = 'sum')
以下截图对应于名为 pvt1 的数据帧:
数据框架中仍有一些干预措施:将生产值减半(它们在原始文件中是重复的)并删除 2009 年和 2021 年的记录,因为这两个记录都不完整:
pvt2 = pvt1/2
pvt2 = pvt2[1:]
pvt2 = pvt2[:-1]pvt2.reset_index(level = 0, inplace = True)
现在我们为图表做好了准备。一个标准条形图是我们讲故事最符合逻辑的选择。
# First Figure: Total Argentine Bioethanol Production fig1 = go.Figure(data=[go.Bar(x=pvt2['Year'], y= pvt2['Tot_Prod'],
marker_color = 'DarkSlateGrey')])fig1.update_layout(title= {'text':"Argentine BioethanolProduction",
'font': {'size': 15}},
title_x = 0.5,
xaxis_title= 'Year',
yaxis_title = 'Production (m3)',
width = 700, height = 500)
图 1:阿根廷生物乙醇的生产。作者用 Plotly 制作的图表。
绘制阿根廷生物柴油生产图表的 ETL 过程与之前的过程完全相似,在初始数据库中存在相同的问题,并且增加了单位转换(从吨到立方米)。
# Step 2: Argentine biodiesel production (values in tons)df_biodsl = pd.read_csv(path + 'produccion_de_biodiesel.csv',
index_col = False, sep = ';',
engine = 'python',header = 1,
skiprows = 1, skipfooter = 4)df_biodsl = df_biodsl.drop(0)
df_biodsl.columns = ['Year','Period', 'Tot_Prod',
'Perc_Tot', 'Market',
'Perc_Mkt', 'Export', 'Perc_Exp']cols_to_drop = ['Perc_Tot', 'Perc_Mkt', 'Perc_Exp']df_biodsl = df_biodsl.drop(cols_to_drop, axis = 1)df_biodsl['Year'] = df_biodsl['Year'].str.replace('*', ' ')
df_biodsl['Tot_Prod']= df_biodsl['Tot_Prod'].str.replace(',', '')
df_biodsl['Export'] = df_biodsl['Export'].str.replace(',', '')
df_biodsl['Export'] = df_biodsl['Export'].str.replace('-', '0')
df_biodsl['Export'] = df_biodsl['Export'].str.replace('s', '0')
df_biodsl['Market'] = df_biodsl['Market'].str.replace(',', '')
df_biodsl['Market'] = df_biodsl['Market'].str.replace('-', '0')
df_biodsl.reset_index()f = df_biodsl['Year'].notnull()
serie = df_biodsl.loc[f, 'Year'] = df_biodsl['Year'].ffill()
df_biodsl['Year'] = seriedf_biodsl['Year'] = df_biodsl['Year'].astype(int)
df_biodsl['Tot_Prod'] = df_biodsl['Tot_Prod'].astype(int)
df_biodsl['Export'] = df_biodsl['Export'].astype(int)
df_biodsl['Market'] = df_biodsl['Market'].astype(int)
df_biodsl['Period'] = df_biodsl['Period'].apply(str)
tipo2 = df_biodsl.dtypespvt3 = pd.pivot_table(df_biodsl, index = ['Year'],
values = ['Tot_Prod','Export','Market' ],
aggfunc = 'sum')pvt4 = pvt3/2
pvt4 = pvt4[:-1]# From tons to cubic meters
pvt4[['Tot_Prod','Export','Market']]=
pvt4[['Tot_Prod','Export','Market']]* 1.1325
pvt4.reset_index(level = 0, inplace = True)
同样,标准条形图是我们讲故事的最合理选择:
# Third Figure: Total Argentine Biodiesel Productionfig3 = go.Figure(data=[go.Bar(x= pvt4['Year'], y= pvt4['Tot_Prod'],
marker_color = 'DarkSlateBlue')])fig3.update_layout(title={'text': "Argentine Biodiesel Production ",
'font': {'size': 15}},
title_x = 0.5,
xaxis_title = 'Year',
yaxis_title = 'Production (m3)',
width = 700, height = 500)
图 2:阿根廷生物柴油的生产。作者用 Plotly 制作的图表。
下图与世界乙醇产量有关。我们决定用堆积面积图来表示两个是主要生产国,占全球产量的 85%以上。
## Step 3: World Bioethanol production (values in Mgal)df_wrld_et = pd.read_csv(path + 'world_ethanol.csv',
index_col = False, sep = ';',
engine = 'python',
header = 0, skipfooter = 3)df_wrld_et_T = df_wrld_et.transpose()
df_wrld_et_T.columns = df_wrld_et_T.iloc[0]
df_wrld_et_T = df_wrld_et_T[1:]
df_wrld_et_T.index.names = ['Year']
df_wrld_et_T.reset_index(level = 0, inplace = True)# Sixth figure: stacked area chart for world bioethanol production
# 3785.4411 is the factor of conversion from Mgal to cubic meterfig6 = go.Figure()
fig6.add_trace(go.Scatter(x = df_wrld_et_T['Year'],
y = df_wrld_et_T['USA']*3785.4411,
name = 'USA',
mode = 'lines',
line=dict(width=0.5, color='orange'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x= df_wrld_et_T['Year'],
y= df_wrld_et_T['BRAZIL']*3785.4411,
name = 'BRAZIL',
mode = 'lines',
line=dict(width=0.5,color='darkgreen'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x=df_wrld_et_T['Year'],
y=df_wrld_et_T['EUROPEAN UNION']*3785.4411,
name = 'EUROPEAN UNION',
mode = 'lines',
line=dict(width=0.5, color='blue'),
stackgroup = 'one')fig6.add_trace(go.Scatter(x= df_wrld_et_T['Year'],
y=df_wrld_et_T['CANADA']*3785.4411,
name = 'CANADA',
mode = 'lines',
line=dict(width=0.5,color='crimson'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x=df_wrld_et_T['Year'],
y=df_wrld_et_T['THAILAND']*3785.4411,
name = 'THAILAND',
mode = 'lines',
line=dict(width=0.5,color='lightblue'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x = df_wrld_et_T['Year'],
y=df_wrld_et_T['CHINA']*3785.4411,
name = 'CHINA',
mode = 'lines',
line=dict(width=0.5, color='red'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x=df_wrld_et_T['Year'],
y=df_wrld_et_T['ARGENTINA']*3785.4411,
name = 'ARGENTINA',
mode = 'lines',
line=dict(width=0.5, color='yellow'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x = df_wrld_et_T['Year'],
y=df_wrld_et_T['INDIA']*3785.4411 ,
name = 'INDIA',
mode = 'lines',
line=dict(width=0.5, color='darkgrey'),
stackgroup = 'one'))fig6.add_trace(go.Scatter(x=df_wrld_et_T['Year'],
y=df_wrld_et_T['REST OF WORLD']*3785.4411,
name = 'REST OF WORLD',
mode = 'lines',
line=dict(width=0.5, color='darkred'),
stackgroup = 'one'))fig6.update_layout(template = 'plotly_dark',
title = dict(text = "World Bioethanol Production ",
x = 0.5, y = 0.95),
title_font= dict(family = 'Arial', size = 25),
font = dict(size = 10, family = 'Verdana'),
hovermode = False,
width = 700, height = 400)fig6.update_xaxes(title_text = 'Year',
title_font=dict(size =15, family='Verdana', color='white'),
tickfont=dict(family='Calibri', color='white', size=15))fig6.update_yaxes(title_text = "Production (m3)",
title_font=dict(size=15, family='Verdana', color='white'),
tickfont=dict(family='Calibri', color='white', size=15))
图 3:世界生物乙醇产量。作者用 Plotly 制作的图表。
最后,我们使用面积图展示了生物柴油的世界产量。同样,我们有 ETL 任务,包括列转置、列重命名和行删除。我们还必须将每天数百万桶原油转换成立方米。
## Step 4: World Biodiesel productiondf_wrld_di = pd.read_csv(path + 'world_biodiesel.csv',
index_col = False, sep = ';',
engine = 'python', header = 1)df_wrld_di = df_wrld_di.iloc[0:2]
df_wrld_di = (df_wrld_di.iloc[1: , : ]).set_index("API")
lista = df_wrld_di.columns.values.tolist()
df_wrld_di_T = df_wrld_di.transpose()
df_wrld_di_T['Year'] = lista
df_wrld_di_T = df_wrld_di_T.iloc[11:22]
df_wrld_di_T.rename(columns={'INTL.81-1-WORL-TBPD.A': 'DieselProd'}, inplace=True)# conversion from Mb/d to cubic meterdf_wrld_di_T['DieselProd']= df_wrld_di_T['DieselProd'].astype(float)df_wrld_di_T[['DieselProd']] = df_wrld_di_T[['DieselProd']]*365 * 0.158990df_wrld_di_T['DieselProd'] = df_wrld_di_T['DieselProd'].round(2)df_wrld_di_T.reset_index(drop = True, inplace = True)# Seventh figure: area chart for world biodiesel productionfig7 = px.area(df_wrld_di_T, x = 'Year', y = 'DieselProd')fig7.update_layout(template = 'plotly_dark',
title = dict(text = "World Biodiesel Production",
x = 0.5, y = 0.95),
title_font= dict(family = 'Arial', size = 25),
width = 700, height = 400)fig7.update_xaxes(title_text = 'Year',
title_font=dict(size=15, family='Verdana', color='white'),
tickfont=dict(family='Calibri', color='white', size=15))fig7.update_yaxes(title_text = "Production (Mm3)",
range = (0, 50000),
title_font=dict(size=15, family='Verdana', color='white'),
tickfont=dict(family='Calibri', color='white', size=15))
图 4:世界生物柴油产量。作者用 Plotly 制作的图表。
现在,是时候对仪表板进行编码了。
我们假设您安装了 Dash 如果没有,遵循这些指令。
首先需要导入一些库:dash,主库;*dash _ html _ components(*html)用于构建布局;dash _ core _ components(DCC)来呈现一组复选框和 plotly 图形;输出,输入函数来自模块 dash.dependencies 进行回调。
*import dash
from dash import html
from dash import dcc
from dash.dependencies import Output, Input*
dcc.graph 组件有三个参数:(1) id ,每个图的唯一标识符;(2) 图,每一个 plotly 图的具体名称;(3) style ,字典定义了图的某些方面如宽度和高度。
以下代码描述了该应用程序的外观。
*external_stylesheets= ['https://codepen.io/chriddyp/pen/bWLwgP.css']app = dash.Dash(__name__, external_stylesheets=external_stylesheets)app.layout = html.Div(children =[
html.Div([
html.H1(children = 'Biofuels',
style = {'textAlign':'center',
'color':'darkblue',
'fontSize' : '30px',
'fontWeight': 'bold'}
), html.Div([
dcc.RadioItems(id ='radio1',
options =
[{'label': 'Total Prod. ', 'value': 'figT'},
{'label': 'Composition', 'value': 'figC'},],
value ='figT',
labelStyle ={'display': 'inline-flex'} ), html.Div([
dcc.Graph(id = 'A-ethanol-graph', figure = fig1,
style={'width': '80vh', 'height': '40vh',
'display': 'inline-block'}),
], className = 'five columns'), html.Div([
dcc.Graph(id = 'A-biodiesel-graph', figure = fig3,
style={'width': '80vh',
'display': 'inline-block'}),
], className = 'six columns'), ],className='row'), html.Div([
html.Div([
dcc.Graph(id = 'W-ethanol-graph', figure = fig6,
style={'width': '80vh', 'height': '10vh',
'display': 'inline-block'}),
], className = 'six columns'), html.Div([
dcc.Graph(id = 'W-biodiesel-graph', figure = fig7,
style={'width': '80vh',
'display': 'inline-block'}),
], className = 'six columns'), ]),
]),
])*
现在,是回调的时候了。我们有一个输入:组件的值 dcc。放射性同位素;和两个输出:(1)生物乙醇和生物柴油总产量的标准柱状图(图 1 & 图 3 )。(2)一个分组柱状图 ( 图 2 )显示甘蔗和玉米的生物乙醇产量,另一个分组柱状图(图 4 )显示出口和国内市场的生物柴油产量。
*@app.callback(Output('A-ethanol-graph', 'figure'),
Output('A-biodiesel-graph','figure'),
[Input(component_id='radio1', component_property='value')]
)def build_graph(value):
if value == 'figT':
fig1 = go.Figure(data=[
go.Bar(x=pvt2['Year'], y= pvt2['Tot_Prod'],
marker_color = 'DarkSlateGrey')]) fig1.update_layout(title=
{'text': "Argentine Bioethanol Production",
'font': {'size': 15}},
title_x = 0.5,
xaxis_title = 'Year',
yaxis_title = ' Production (m3)',
width = 700, height = 350) fig3 = go.Figure(data=[
go.Bar(x= pvt4['Year'], y= pvt4['Tot_Prod'],
marker_color = 'DarkSlateBlue')]) fig3.update_layout(title =
{'text' : "Argentine Biodiesel Production ",
'font': {'size': 15}},
title_x = 0.5,
xaxis_title = 'Year',
yaxis_title = 'Production (m3)',
width = 700, height = 350) return fig1, fig3,else:
fig2 = go.Figure(data=[
go.Bar(name='Cane',
x=pvt2['Year'],y = pvt2['Cane_Prod'],
marker_color = 'goldenrod'),
go.Bar(name='Corn',
x=pvt2['Year'], y= pvt2['Corn_Prod'],
marker_color = 'lightslategray')]) fig2.update_layout(barmode='group') fig2.update_layout(title =
{'text' : "Argentine Bioethanol Production ",
'font': {'size': 15}},
title_x = 0.5,
xaxis_title = 'Year',
yaxis_title = 'Production (m3)',
legend=dict(orientation="h"),
width = 700, height = 350)## Fourth Figure: Biodiesel Production for Export or Internal Market fig4 = go.Figure(data=[
go.Bar(name='Market',
x=pvt4['Year'], y= pvt4['Market'],
marker_color = 'darkblue'),
go.Bar(name='Exports',
x=pvt4['Year'], y= pvt4['Export'],
marker_color = 'crimson')]) fig4.update_layout(barmode='group') fig4.update_layout(title =
{'text' : "Argentine Biodiesell Production ",
'font': {'size': 15}},
title_x = 0.5,
xaxis_title = 'Year',
yaxis_title = 'Production (m3)',
legend=dict(orientation="h"),
width = 700, height = 350) return fig2, fig4,*
运行服务器需要下面两行代码:
*if __name__ == '__main__':
app.run_server(debug = False, port = 8080)*
你的屏幕上会出现下面一行: Dash 正在http://127 . 0 . 0 . 1:8080/。将其复制到您的浏览器中,您将看到生物燃料仪表板。
图 5:生物燃料总产量。作者用 Dash 做的仪表盘。
点击单选按钮后,会出现“更改”屏幕:
图 6:转换屏幕。作者用 Dash 做的仪表盘。
总结一下:仪表板的概念是在一个屏幕上显示与研究目标最相关的信息。
在我们的仪表板上,我们在第一个屏幕上显示了阿根廷生物乙醇和生物柴油的总产量,以及这两种生物燃料的全球产量。可以看出,这两种生物燃料的本地产量都有惊人的增长,尤其是在 2016 年至 2019 年期间。我们也可以估计一下阿根廷在世界市场上的产量。
在转换屏幕中,我们区分了从甘蔗生产的生物乙醇和从玉米生产的生物乙醇。由于生物柴油是在阿根廷由单一原料(大豆)生产的,因此我们区分了国内市场生产和出口生产。由此可见,2012 年之前以零玉米为主的产量,是如何在短短两年内成为主要原料的。截至 2018 年,生物柴油出口和国内市场之间的趋势也发生了重大变化。
platform Dash 允许我们轻松地创建一个交互式 web 应用程序来显示这些重要的信息。
如果你对这篇文章感兴趣,请阅读我以前的(https://medium.com/@dar.wtz)
用虚线绘制图表
原文:https://towardsdatascience.com/charting-with-plotly-dash-fa96c171409b?source=collection_archive---------19-----------------------
1:损耗模式
图片来自 Unsplash
破折号
Dash 是位于加拿大蒙特利尔的技术计算公司 Plotly 创建的一个 python 框架。这是一个开源的、麻省理工学院许可的免费库,通过它你可以创建基于网络的、交互式的、可定制的、可响应的仪表盘和 dataviz 应用程序。
它的一个主要优势在于无需了解 HTML、CSS 或 Java 就可以创建 web 应用程序(尽管需要基础知识)。你不仅可以用 Python 创建 Dash 应用程序,还可以用 R、Julia 或. NET 创建 Dash 应用程序。Dash 非常简单,只需运行代码,dataviz 应用程序就会立即在 web 浏览器上显示出来。
带破折号的应用
首先,我们必须设计未来应用程序的基本结构(布局)。这是至关重要的一步,因为它决定了我们演示的视觉效果。
在布局中,我们放置应用程序的组件。为此,我们使用了两个库:dash _ core _ components和 *dash_html_components。*最后一个提供了 HTML 组件:用于为 HTML 元素创建标题、段落、图像或容器的 HTML 标签的 python 版本。另一方面, dash_core_components 提供了图形、 **下拉菜单、滑块、按钮、**等仪表盘常用组件。最后,我们必须配置一个样式属性,在这里我们定义一些 CSS 属性,比如字体大小、字体颜色、空白和其他与模板相关的方面。
还有一个名为 dash _ bootstrap _ components的库,用于设计用户界面的样式,其有用性和适用性将在以后的文章中讨论。
如果你的 Dash 应用有交互功能,你需要编写一个回调函数。回调函数有两个部分:
1.decorator,使用 @app.callback() 初始化;
2.-用 def 初始化的函数定义。
在装饰器中,我们指出了可以被用户修改的输入组件和显示应用程序对输入变化的反应的输出组件。在用 def 关键字初始化的函数中,我们编写了接受输入变化并返回相应输出的逻辑。
行动图表:损耗模式
损耗率(流失率,客户流失率)是客户停止与特定商业实体做生意的比率。这是一项业务指标,计算在给定时间内停止购买特定公司产品或服务的客户数量除以剩余客户总数。损耗率是许多公司最重要的 关键绩效指标(KPI)之一,因为它可以用来预测公司的增长或衰退。
跟踪流失率至关重要,但分析数据对于发现模式 解决造成流失的动机也非常重要。这些模式可能与人口统计学有关,也可能出于经济原因。****使这些模式可视化的仪表板将允许公司通过根据人口统计或群体划分现有客户来组织营销活动。这样,就有可能激活个性化消息或特定促销来降低流失率。
为了创建具有这些功能的仪表板,我们从 Kaggle 下载了一个数据集,该数据集由 10,000 名银行客户组成,显示了一个流失标志(现有客户与流失客户),人口统计数据:客户年龄;性别;教育水平;婚姻状况和财务数据:收入类别;卡片类别;与银行的关系期限、闲置月份等。
我们决定绘制四个图表来回答以下问题:
- 1)婚姻状况和减员情况有关系吗?
- 2)受教育程度与减员情况有关系吗?
- 3)客户的年龄和减员情况有关系吗?
- 4)帐户不活动与流失情况之间有什么关系吗?
让我们做一个仪表盘来回答这些问题。
带破折号的图表
Dash 库*dash_core_components*
中的函数*dcc.Graph()*
允许我们绘制图形。我们必须编写类似于*dcc.Graph(figure=fig*)
的代码,其中*figure*
是函数的参数, *fig*
是用Plotly Express***(Plotly 图形库)制作的图表。***
***首先,我们将 Pandas 库导入为 *pd,plot Express 为 px,并将我们的 csv 文件转换为 dataframe:
*import pandas as pd
import plotly.express as pxpath = 'your path'
df = pd.read_csv(path + 'CreditCardCustomersCols.csv',
index_col = False, header = 0, sep = ';',
engine='python')*
我们的第一个图表是一个 [100%堆积条形图](http://Stacked Bar Graphs, Why & How. Storytelling & Warnings | by Darío Weitz | Towards Data Science),根据客户的婚姻状况显示流失客户的百分比。我们选择列'Attrition_Flag'
和 'Marital_Status'
将数据集中的记录从长格式转换为宽格式。然后,我们使用函数*size(*)
和函数lambda
来计算相应的百分比。
*df_stack1 = df.groupby(['Attrition_Flag',
'Marital_Status']).size().reset_index()df_stack1['Percentage'] = df.groupby(['Attrition_Flag','Marital_Status']).size().groupby(level=1).apply(lambda x:100 * x/float(x.sum())).valuesdf_stack1.columns= ['Attrition_Flag', 'Marital_Status',
'Counts', 'Percentage']*
下面的屏幕截图显示了名为 df_stack1 的数据集的记录:
我们使用px.bar()
和barmode = 'stack'
生成了一个用 [Plotly 表示的 100%堆积条形图](http://Stacked Bar Charts with Plotly Express | by Darío Weitz | Towards Data Science)(图 1):
*fig1 = px.bar(df_stack1, x = 'Marital_Status', y = 'Percentage',
color = 'Attrition_Flag',
color_discrete_sequence=["crimson", "green"],
barmode = 'stack', text = 'Percentage')fig1.update_layout(title = "Marital Status Customers' Attrition",
xaxis_title = 'Marital Status',
yaxis_title = 'Percentage (%)',width = 800)fig1.update_traces(texttemplate='%{text:.2s}',textposition='inside')*
图 1:作者用 Plotly Express 制作的 100%百分比堆积条形图。
仪表板中的第二个图表(fig2
)是另一个 100%堆积条形图,根据客户的教育水平显示流失客户的百分比。代码是相同的,除了我们用原始数据帧中的 ‘Education Level’
列替换了‘Marital_Status’
列。
我们决定使用重叠直方图来回答问题 3 & 4。
因此,仪表板的第三个图表(fig3a
)是一个[图表,显示了现有客户和流失客户的年龄频率分布。](http://Histograms with Plotly Express. Themes & Templates | by Darío Weitz | Towards Data Science)
我们使用px.histogram()
和barmode = ‘overlay’
生成了 Plotly Express 重叠直方图(图 2):
*df3a = df[df['Attrition_Flag'] == 'Existing Customer']
df3b = df[df['Attrition_Flag'] == 'Attrited Customer']fig3a = px.histogram(df3a, x="Customer_Age",
nbins = 10, barmode = 'overlay',
template = 'seaborn', color = 'Attrition_Flag')fig3b = px.histogram(df3b, x="Customer_Age",
nbins = 10, barmode = 'overlay',
template = 'ggplot2', color = 'Attrition_Flag')fig3a.add_trace(fig3b.data[0])fig3a.update_layout(title = "Customers' Age Histogram",
title_font_size = 20,
xaxis_title = "Customers' Age",
yaxis_title = 'Count',
width = 800, height = 350)*
图 2:作者用 Plotly Express 制作的重叠直方图。
仪表板中的最后一个图表(fig4a
)是另一个重叠的直方图,比较了现有客户和流失客户的账户不活跃的月数。代码与前一个完全相同,只是我们使用了原始 dataframe 中的*'Months_Inactive_12_mon’*
列。
现在,该是仪表板的时候了。
我们假设您安装了 Dash 如果没有,请遵循这些说明。
首先,我们需要导入三个必要的库:dash
,主库;dash _ html _ components(html
)用于构建布局;dash_core_components ( dcc
)使用 *graph*
组件渲染 plotly 图形。
**import dashfrom dash import htmlfrom dash import dcc**
接下来,我们必须通过创建一个实例来初始化仪表板。由于 Dash 应用程序使用 CSS 在 web 浏览器中呈现,因此我们包含了一个外部样式表(‘https://codepen.io/chriddyp/pen/bWLwgP.css
’)
**external_stylesheets =['https://codepen.io/chriddyp/pen/bWLwgP.css']app = dash.Dash(__name__, external_stylesheets=external_stylesheets)**
然后我们必须定义我们的应用程序的布局,自然是用带有父组件html.Div
的app.layout
。前者是布局管理的关键字,后者是封装布局内多个组件的容器。
我们的计划是在顶部放置一个标题,然后放置 100%堆积条形图,在其下方放置重叠直方图。对应的 Dash 组件在容器 html.Div
的 children
属性中被表示为 a 列表。
dcc.graph
功能中的参数有:
- id: 每个图形的唯一标识符(字符串)
- **人物:一个情节性人物的名字
- style :定义(在我们的例子中)图形高度和宽度的字典
**app.layout = html.Div(children =
[html.Div([
html.Div([
html.H1(children = 'Attrition Data Analysis',
style = {'textAlign' : 'center',
'fontSize' : '30px',
'fontWeight': 'bold',
html.Div([
dcc.Graph(id = 'marit-graph',
figure = fig1,
style={'width': '90vh',
'height': '40vh'}),
], className = 'five columns'), html.Div([
dcc.Graph(id = 'educa-graph',
figure = fig2,
style={'width': '90vh',
'height': '40vh'}),
], className = 'six columns'), ],
className='row'), html.Div([html.Div([
html.H1(children = ''),
dcc.Graph(id = 'hisage-graph', figure = fig3a,
style={'width': '80vh',
'height': '10vh'}),
], className = 'six columns'), html.Div([html.Div([
html.H1(children = ''),
dcc.Graph(id = 'hisina-graph', figure = fig4a,
style={'width': '80vh',
'height': '10vh'}),
], className = 'six columns'), ]),
]),
])**
最后,我们添加以下两行代码来运行服务器:
**if __name__ == '__main__':
app.run_server(debug = True, port = 8080)**
debug=True
参数启用应用程序中的热重装选项。这是一个强烈推荐的选择,因为如果代码发生变化,应用程序会自动重新加载,而不需要重启服务器。
如果一切正常,应用程序运行,屏幕上将显示几行。我们真正感兴趣的行应该如下所示:
Dash 正在 http://127.0.0.1:8080/ 上运行
在您的网络浏览器中复制 url,您将看到图表仪表板。
图 3:作者用 Plotly Dash 制作的仪表盘。
可以看出,流失情况和银行客户的婚姻状况之间似乎没有明显的关系。客户年龄或账户闲置时间也没有显示出它们是流失的原因。
为了分析教育水平和损耗状况之间是否存在任何关系,我们使用ascending = True.
对相应的数据帧进行了排序。热重装选项允许我们立即获得以下仪表板:
图 4:作者用 Plotly Dash 制作的仪表盘。
似乎受教育程度较高的顾客比受教育程度较低的同行更不满意。然而,应该进行适当的统计研究来证实这一说法。
Dash 使我们能够轻松地生成一个应用程序,让我们能够搜索流失背后的原因。不幸的是,分析的变量似乎都不是我们要寻找的答案。在以后的文章中,我们将分析原始数据框架中包含的任何其他金融变量是否是答案。
如果你对这篇文章感兴趣,请阅读我之前的文章:(https://medium.com/@dar.wtz):
“平行坐标标绘有 Plotly,规范化还是标准化?
****
饼图和甜甜圈图,带有 Plotly,Why & How
****
Chartio 正在关闭:现在怎么办?
原文:https://towardsdatascience.com/chartio-is-shutting-down-what-now-209c8a28d5b4?source=collection_archive---------28-----------------------
这里有 3 个可供分析平台转换的选项
Chartio 已加入 Atlassian,并将关闭 Chartio 分析平台(图片由作者提供)
你可能听说了,Chartio 被 Atlassian 收购了。收购完成后,看起来他们将淘汰许多公司已经依赖的分析平台。
当前客户将有一年的时间过渡到新的供应商,以满足他们的分析需求。以下是他们在公告/迁移指南中所说的内容:
“如果你还没有看到我们的公告,Chartio 已经加入 Atlassian,该产品将于 2022 年 3 月 1 日关闭。虽然我们对未来的新篇章感到兴奋,但我们理解这可能对您产生的影响,我们希望确保您拥有顺利过渡到 Chartio 所需的一切。”
—摘自 Chartio 网站上的公告/迁移指南
如果您是 Chartio 的现有客户,并且在想“哦,不!我现在该怎么办?”别担心,这里有三个可靠的分析平台可供选择。
1.Knowi
Knowi 中的仪表板(图片由作者提供)
Knowi 在商业情报界是一个不太知名的名字。他们的重点一直是产品开发和吸引技术受众,直到最近他们才开始成为 Tableau 和 Chartio 等公司的真正竞争对手。
Knowi 的分析平台由三部分组成:HUB、EMBED 和他们的最新产品 ELEVATE。
对于 Chartio 用户来说, Knowi HUB 与他们所熟悉的最为相似。Knowi HUB 拥有您期望从一个健壮的 BI 工具中获得的所有仪表板和图表构建功能。
Knowi EMBED 是一个版本,面向希望在自己的产品中嵌入 Knowi 分析平台的用户。对于希望向客户提供高级分析功能而无需从头构建自己的分析引擎的公司来说,这正成为 BI 工具中更常见的用例。
Knowi EMBED 的一个例子,用于将 Knowi 分析引擎插入基于网络的应用程序(作者截图)
Knowi ELEVATE 是该公司的最新产品,旨在解决试图成为数据驱动的公司普遍存在的用户采用问题。
Knowi ELEVATE 产品发布会
这是一个首席信息官和首席数据官都非常熟悉的故事:他们引入了一个新的分析平台,花了大量的预算和精力来构建仪表板和分析以帮助团队,然后没有人真正看他们构建的仪表板。这一点在销售团队中尤为突出,他们仍然依赖 Salesforce 做任何事情,即使它提供的分析较差。
Knowi ELEVATE 旨在通过将数据洞察放在人们已经在工作的地方来解决这个问题:Slack 和 ms 团队内部。这些洞察力来到用户面前,而不是用户需要去寻找它们。然后,用户可以通过用简单的英语提问来跟进,并获得回答他们问题的数据和图表。
Knowi 数据分析平台的三个部分:ELEVATE、HUB 和 EMBED(作者截图)。
定价
Knowi 对其产品使用企业定价,因此使用 Knowi 的成本将与 Tableau 相当,但比 Power BI 贵。虽然值得注意的是,Knowi 确实为早期创业公司提供折扣。
2.功率 BI
Power BI 是微软知名的商业智能产品。在过去几年中,微软通过将 Power BI 捆绑为微软 Office 的一部分,并接近以前的铁杆 Excel 用户来帮助他们进行转换,从而获得了很多支持。
Power BI 示例仪表板(图片由作者提供)
以下是 Power BI 众所周知的一些特性:
- 简单的拖放界面。
- 无代码平台允许用户在 GUI 界面中做任何事情。
- 有桌面版和云版。
- 轻松集成到任何以 Microsoft/Windows 为中心的工作流中。
- 捆绑到 Office 365 中,因此您可能已经拥有许可证。
定价
如果你是 Chartio 的预算计划之一,这可能是你想看的地方,因为它是三个选项中最便宜的。合同可能有所不同,但据报道,Power BI 的成本约为每个用户每月 20 美元。
3.(舞台上由人扮的)静态画面
Tableau 于 2003 年在推出,自此成为商业智能中 800 磅重的大猩猩——本质上定义了这个类别。
Tableau 以其精美迷人的数据可视化和易于构建的拖放界面而闻名。Tableau 最初是一个桌面软件,你可以把它下载到你的电脑上,然后从那里运行(相对于基于云的软件)。此后,他们开发了 Tableau 的云版本,尽管他们的大多数用户仍然运行桌面版本。
显示图表的 Tableau 工作簿(图片由作者提供)
2019 年初,Salesforce 以价值超过 150 亿美元的纯股票交易收购了 Tableau。幸运的是,与 Chartio 目前的情况不同,Salesforce 似乎没有兴趣停止 Tableau analytics 产品。
在 Tableau 中按位置显示销售额(图片由作者提供)
包扎
这三个中的任何一个都可能是离开 Chartio 的好选择。如果您对价格敏感,Power BI 显然是最佳选择。如果你正在做老掉牙的分析过程,并且不介意潜在地使用桌面应用程序,Tableau 是一个不错的选择。如果您想要在团队中推动更高的参与度和采用率(Knowi ELEVATE),需要嵌入仪表板(Knowi EMBED),或者只是想要一个具有灵活本机集成的可靠的完全基于云的仪表板平台(Knowi HUB),Knowi 是一个不错的选择。
关于作者
嗨,我是肖恩。我写数据科学、禁欲主义、创业成长,偶尔也写政治。我拥有物理学和数据科学两个学位,我曾在粒子加速器、美国宇航局 JPL 研究核反应堆工作过,现在我正处于创业阶段。
在推特和 T2【Linkedin】上找到我。
聊天机器人:一个完整的 PyCharm 应用程序(第 2 部分,共 3 部分:距离度量)
原文:https://towardsdatascience.com/chatbot-a-complete-pycharm-app-part-2-of-3-distance-metric-46462a9ad4e4?source=collection_archive---------45-----------------------
Chatterbot、Django、Python 和 PyCharm 都统一在这个随时可用的聊天机器人应用程序中
聊天和距离度量(图片由作者提供)
动机:
在第一章中,我们已经在 PyCharm 中成功构建了一个聊天机器人。现在是时候训练我们的聊天机器人回答常见问题了(FAQ,不管这些是你公司的什么)。在这个故事中,我们将学习如何做到这一点(在这种情况下,培训实际上意味着什么?)我们将深入了解为什么我们的聊天机器人知道如何正确回答我们的问题。这样做的原因是,我们确实想尽可能创建最聪明的 FAQ 聊天机器人,所以现在让我们卷起袖子..
解决方案:
在基于检索的聊天机器人模型中,类似 Levenshtein 或余弦相似性的试探法用于从预定义的输入库中选择和输出**。这就构成了我们聊天机器人的识**。这听起来像是显式的“if-else”编码,所以你可能会问,Chatterbot 中的机器学习在哪里?好吧,如果只是显式编码,这将意味着我们的聊天机器人将无法给出正确的答案,每次问的问题都与库的编码略有不同。简单地说,如果我们告诉我们的聊天机器人“彩色鞋子重要吗?”传统的编码是“当然,颜色让世界变得明亮”,那么如果一个英国人问我们“彩色的鞋子重要吗?”我们的聊天机器人将无法给出正确的答案。
chats.txt 中的多语言问答映射
幸运的是,当我们使用 Chatterbot 时,我们不必硬编码数万亿条规则。但是我们使用 Chatterbot 的 Levenshtein 包来计算字符串之间的相似性(将用户的输入映射到我们的 FAQ 输入-输出 Chats.txt):
距离度量的 Levenshtein 和一般闲聊对话的语料库的导入。
我们的机器人将在 Chats.txt 文件和 Chatterbot 语料库上接受训练:
你可以在这里找到可用聊天机器人语料库的完整列表。
通过训练,我们确保机器人知道给出什么答案:
我们可以看到,由于 NLTK,甚至这个词的上下文都试图被理解。
所以当我们启动聊天机器人,问它一个问题:
..聊天机器人会努力思考:
..并给出与该问题最相关的答案,例如使用 Levenshtein。
作为一次短暂的旅行,让我们理解一下 Levenshtein 基本上是如何坚持我们简单的“彩色鞋子”Jupyter 笔记本例子的。我们只需要导入:
import Levenshtein
..能够使用莱弗施泰因的距离函数。两个相同句子的结果显然是距离为 0,正如我们在示例中看到的:
Levenshtein.distance(
‘Do colorful shoes matter’,
‘Do colorful shoes matter’)
Levenshtein 距离为 0,因为两个句子是一样的。
现在让我们稍微修改一下这句话,这次用英国的“颜色”一词:
Levenshtein.distance(
‘Do colorful shoes matter’,
‘Do colourful shoes matter’)
Levenshtein 距离现在是 1,因为唯一的变化是字符“u”的颜色。
最后,如果我们在句尾再输入五个单词(包括两个空格),我们得到的 Levenshtein 距离为 8:
Levenshtein.distance(
‘Do colorful shoes matter’,
‘Do colourful shoes matter at all’)
“u”和“根本”之差总共是 8。
Levenshtein(也称为编辑距离)对于比较单词或相似的句子非常有用。
相反,余弦相似度在比较差异更大的完整句子时有意义。如果我们在这些情况下坚持使用 Levenshtein ,Levenshtein 很可能会计算出一个相对较大的距离,尽管这两个句子传达了非常相似的关键信息:
Levenshtein.distance(
‘Do colorful shoes matter’,
‘At all, do colourful shoes really matter’)
尽管两个句子的上下文非常相似,但还是相对较远。
由于 Chatterbot 的机器学习分类器,我们的聊天机器人可以进一步使用对话的上下文从预定义的消息列表中选择希望的最佳响应。所以我们的聊天机器人不仅知道颜色和色彩很可能是相同的,而且机器人应该进一步知道鞋子和衣服密切相关(即使我们以前从未用衣服这个词训练过我们的聊天机器人)。这方面的理论背景超出了本文的范围,但我们可以理解,主要是由于 NLTK(自然语言工具包)和余弦相似性,我们的聊天机器人语料库理解了鞋子和衣服之间的联系。看看这个令人印象深刻的视觉化图像,了解一下高维单词向量空间的概念:
http://projector.tensorflow.org
“鞋”被理解为与“衣”、“衣”、“穿”、“穿”非常相似(截图来自projector.tensorflow.org)
简而言之,我们的聊天机器人会查看输入,并搜索它已经训练过的、最接近用户问题的输入。然后,机器人返回与该问题相关的答案。
为了调优这些参数,让我们查看 Views.py,看看我们的逻辑适配器设置。是适配器决定了 ChatterBot 如何选择对给定输入语句的响应的逻辑,并且有多种方式设置它们。我们在应用程序中使用了 BestMatch。BestMatch 将根据与输入(用户问题)最接近的已知响应返回一个响应。我们已经将两个语句之间的最大相似度设置为 90%,使用最大相似度来计算机器人的置信度:
如果聊天机器人估计不知道正确答案,它会问“请你用其他的话重复一下你的问题好吗?”
正如生活中经常出现的情况一样,对于如何设置这些参数的问题,没有绝对 100%的对错。这完全取决于你的 FAQ 背景,你想使用哪种逻辑。你的聊天机器人是不是应该只在绝对有把握给出正确答案的情况下才回应?或者它应该表现得更像一个话匣子,每次都给出答案,即使不一定总是最好的答案?我能给你的唯一诚实的建议是在你的数据上尝试一下(参考伟大的聊天机器人网站了解更多细节)。
恭喜,我们现在有一个完整的聊天机器人在运行,我们知道如何训练它来尽可能最好地回答我们的问题!我们仅仅关注基本的问答映射,但是上下文还可以包括特定对话流中的当前位置,或者之前保存的变量,如主题(例如,“您希望聊天机器人回答主题 a 或 b 中的问题吗?”).进行对话流对话将是另一篇文章的主题。
目前,非常感谢阅读!希望这篇文章对你有帮助。请随时在 LinkedIn 、 Twitter 或工作室与我联系。
https://jesko-rehberg.medium.com/membership
最初发表在我的网站 DAR-Analytics 。
聊天机器人:一个完整的 PyCharm 应用
原文:https://towardsdatascience.com/chatbot-complete-pycharm-app-3517b64075f2?source=collection_archive---------18-----------------------
Chatterbot、Django、Python 和 Pycharm 都统一在这个随时可用的聊天机器人应用程序中
作者图片
动机:
你正在寻找一个完全准备好的聊天机器人,它可以很容易地适应你的需求吗?如果你愿意结合使用 Python、Pycharm、Django 和 Chatterbot,就不用再看了。最重要的是,这个应用程序中甚至添加了一个 SQLite 数据库,所以你可以分析用户的输入和聊天机器人的输出。
这篇文章关注的是如何让一个 FAQ 聊天机器人运行起来,而不涉及 chatterbot 的理论背景,这将是另一篇相关文章的主题。
解决方案:
首先,请确保您安装了 PyCharm。如果没有,请现在就做:
去www.jetbrains.com安装免费社区版。
之后,在 PyCharm 开始新项目之前,请复制我的 Google Drive 文件夹中的所有文件:https://Drive . Google . com/Drive/folders/1 ixxjznr 8 pbgfsiypwj 92 fxnqx 35 ezoft?usp =共享
..并将其复制到您的 PyCharm 项目文件夹中(通常在您的用户文件夹中):
然后打开 PyCharm,点击“新建项目”:
选择 ChatbotProject 文件夹(您刚刚从我的 Google Cloud 下载的)作为您新的虚拟环境(virtualenv)项目的位置。还要确保 Python 解释器指向 Python 3.7:
确保文件夹“venv”是空的。如果没有,就删除该文件夹中的所有文件。
确认要从现有来源创建后:
下一步,添加配置:
..点击左上角的加号:
必须输入这些设置的位置:
从现在开始,您只需点击“运行”按钮即可启动 Manage.py:
..然后单击本地主机链接,这将在几秒钟后启动:
如果现在有导入错误弹出,类似于:
..您所要做的就是转到 settings 并在 Python 解释器部分导入必要的包:
请确保 Django 2.2 和 Chatterbot 1.0.2。已安装。这将确保我们的聊天机器人能够很好地与 Python 3.7 一起工作:
如果您现在再次运行“manage.py ”,您可能会在第一次启动 chatbot 时收到以下消息:
在这种情况下,请到您的终端并输入:
python manage.py migrate
现在再次运行 manage.py,您的聊天机器人应该可以在您的浏览器中工作了:
输入您的信息,然后点击下面的发布按钮。
你输入一个问题,我们的机器人有望给我们正确的答案:
你可以输入一个问题,你的聊天机器人会给你这个问题的答案。聊天机器人可能知道正确答案的原因是因为您的 chats.txt,您可以在这里修改它:
在我们的例子中,我们使用了英语和德语的输入输出映射。
如果您更喜欢 yaml 文件而不是 chats.txt,您也可以改编这些语料库文件:
请注意,除了 FAQ,其他都是 chatterbot 模块。这是我自己为了学习而创作的:
Chatterbot 是一个非常有趣的聊天机器人,它使用机器学习技术。如果你想了解更多关于 Chatterbot 的细节,请看看 chatterbot 网站。
还有什么要补充的吗?
现在一切都运转良好。但是,如果添加一个数据库连接,这样我们就可以分析 chatbot 的输出和用户的输入,岂不是很酷?
因此,我们必须再次进入设置,但这一次我们将安装在插件部分。搜索数据库导航器并安装插件:
然后输入新的数据库连接:
选择 SQLite 并添加 db.sqlite3 作为数据库文件:
单击测试连接,检查它是否正常工作。
在安装了 Database Navigator 之后,我们第一次运行 Chatbot 后,查看“statement”表,我们可以看到所有训练过的对话:
如果你想从零开始学习,删除这些文件就行了。
恭喜,我们有一个完整的聊天机器人运行!我们将在的另一篇文章中详细讨论聊天机器人的学习。
目前,非常感谢阅读!希望这篇文章对你有帮助。请随时在 LinkedIn 、 Twitter 或工作室与我联系。
https://jesko-rehberg.medium.com/membership
最初发布于我的网站 DAR-Analytics 。
QnA Maker 聊天机器人策略
原文:https://towardsdatascience.com/chatbot-strategy-with-qna-maker-9554e5bd7782?source=collection_archive---------27-----------------------
图片由皮克斯拜的默罕默德·哈桑拍摄
边学边学,不要丢脸
逐步实现聊天机器人不仅可以为您省去与聊天机器人相关的麻烦,还可以在此过程中为您的组织提供有价值的服务。开始这一旅程的一个极其简单的方法是使用 Microsoft QnA Maker。(本文不是微软赞助的,他们也没有任何编辑影响力。)
众所周知,聊天机器人服务于各行各业,尤其是客户服务。他们与客户“交谈”,这是聊天机器人的一个不错的自助用例,但也是一个“太多太快”的警示故事聊天机器人失败的例子有很多。
我提出了一条途径,让你在完成组织内的一个重要目标的同时,更容易地学习别人通过艰难的方式学到的东西,而没有风险;有效分享机构知识。
听起来好得难以置信。
很公平,但事实并非如此。QnA Maker 不太像聊天机器人,更像知识库,但是不要搞错,知识库是作为聊天机器人公开的。想想这意味着什么。想象一下,一个 SharePoint 搜索实际上是可行的,想象一下,在过早公开之前,在你自己的公司内部对它进行测试。
创建 QnA Maker 实例
我首先需要有一个 Azure 帐户。创建一个免费账户并不困难(而且你得到的不仅仅是 QnA Maker)。您可以导航到 https://www.qnamaker.ai 并在那里创建您的帐户,或者您也可以前往https://azure.portal.com。
创建新帐户后,我导航回 QnA Maker 主页,并选择创建知识库。
作者图片
注意,我在微软认知服务部门,这是 Azure 的一部分(这种联系很快就会变得更加明显)。创建知识库页面类似于向导,第一步是我连接 Azure 的地方。
选择创建 QnA 服务。(不要忘记我为什么这样做,这是为了 QnA Maker 实例——很容易忘记并认为你只是在做一些 Azure 的东西!)
瞧啊。我被弹出到 Azure Portal 来创建一个 QnA Maker 实例。以下是我对创建屏幕的选择:
- 我查了一下托管(预览)
- 我选择了我的订阅
- 我有一个我选择的测试资源组(如果您没有,创建一个)
- 我将我的实例命名为 medium-article-qna-maker (需要有命名约定)
- 我选择了*(美国)美国中南部*作为地点(尽可能选择离你近的地点)
- 我只能选择*标准 S0(免费预览,每分钟 600 笔交易)*定价层(我认为这就足够了)
- 对于 Azure 搜索位置,我保留了默认设置,( US) East US (再次选择地理位置离你近的地方)
- 对于 Azure 搜索定价层,我节俭地选择了免费的 F (3 个索引)
- 通过勾选“我确认…”复选框,我接受了法律条款
作者图片
然后我选择了屏幕底部的审查+创建(图中未显示),然后在下一个屏幕中选择创建。过了一段时间,我的 QnA Maker 实例就创建好了。
作者图片
这就是为什么记住我为什么这么做很重要。选择进入资源很有诱惑力,但是用海军上将贾尔·阿克巴的不朽名言来说,
这是个陷阱!
不,这真的不是陷阱,但这不是我接下来需要做的。接下来,我返回到创建 QnA Maker 向导并继续。步骤 2 从选择刷新按钮开始(因为有些值是基于刚刚在 Azure 中创建了资源而被填充的)。
我的 Active Directory ID 已被选中(它与我的新 Azure 帐户相关联)。我选择了我的订阅,我的新的 Azure QnA 服务(它被命名为medium-article-QnA-maker),以及英语作为语言。
在步骤 3 中,我输入了中型文章知识库作为知识库名称。(注意,微软没有给那个机器人命名为。我跳过步骤 4 (但创建或导入现有知识库是一个很酷的功能),直接进入步骤 5 并选择创建您的知识库。
作者图片
使用 QnA Maker
QnA Maker 是一个全功能的应用程序,并且“数据”(问题和答案对)耦合在自然语言处理中,以实现对话式人工智能。您可以按原样使用 QnA Maker,或者让它成为其他东西的基础(例如,网站的聊天机器人)。
知识库用户界面非常简单,它基于一个基本结构:问题和答案。我让启用丰富编辑器开关打开,并选择 +添加 QnA 对。
作者图片
没有比下一个屏幕更简单的了。我输入一个包含零到多个备选短语的问题以及问题的答案。
但是请注意,当我在输入一个带有备选措辞的问题后,将光标放在输入答案部分时会发生什么:
作者图片
这就是富编辑器的用武之地。答案可以被显著地修饰。在我的例子中,我想添加一个超链接。
作者图片
我输入我的文本以显示和 URL 。就这些了。如果我正在构建一个强大的知识库,我会输入许多 QnA 对,或者从某个来源(例如,网站—如 FAQ—Excel 电子表格、Word 文档)导入它们。一旦 QnA 对完成,我从顶部选择保存并训练。
作者图片
现在我将测试知识库,这是您看到的 QnA Maker 聊天界面。出现的是一个聊天窗口,您可以在其中输入任何文本。我逐字输入我的问题(因为如果它不能逐字做,它能做什么!?).
作者图片
好吧,这是可行的,但 SharePoint 或任何其他基于索引的搜索引擎可以做到这一点,对不对?我同意。我要尝试一些变化…
作者图片
我不得不努力让它失败。请注意,拼写错误甚至工作,直到我去所有的语音。SharePoint 不会这样做,它当然也不是对话式的。
这里微妙的一点是,你真的不需要明确地有许多不同的备选问题——QnA Maker 做了一件体面的工作,弄清楚被问的是什么。
下一步是什么?
随着您的聊天数据的工作,您可以轻松地将 QnA Maker 附加到实际的聊天机器人上,或者您可以(即使我不建议这样做)直接使用 QnA Maker。用户可以在 QnA Maker 中做很多正确的事情,特别是如果他们是知识库的内容创建者(例如,根据需要添加新的 QnA 对)
但是回到最初的观点——我的新知识库可以在我的庞大的 FranklyAI 帝国内使用(恰好一个人),以帮助员工理解政策和程序、fid 有用信息,或者部门和/或系统特定信息。这是一个低风险、高价值、低成本的提议,更重要的是,你可以在你自己的机器人的舒适环境中理解聊天机器人如何工作(和不工作)。
您可能没有想到其他的东西,但是实际内容可以(也应该)100%由最终用户维护。使用 QnA Maker 对任何计算机用户(即使是新手)来说都很简单。
但是还有什么呢?
QnA Maker 就像汽车的发动机,但它不一定是内饰。然而,为 QnA Maker 建立一个聊天界面非常容易,甚至更容易将其连接到现有的渠道,如微软团队(想象一个可以告诉你东西在哪里的团队机器人)、电子邮件、微软 Power 虚拟代理、API,等等。更何况每个渠道(网络、文字、邮件等。)共享同一个 KB 实例,因此 QnA Maker 中的更改会被填充到所有通道中。
作者图片
我将为您留下一些 QnA Maker 资源以供进一步研究。如果我的时间表允许的话,我会回来告诉你如何连接不同的频道(这些链接也会带你去那里)。
资源
[1]Microsoft.com。微软快速启动:创建、培训和发布你的 QnA Maker 知识库 (2020)。
[2]Microsoft.com。教程:添加你的知识库给虚拟代理 (2020)。
与 Geotab 数据和分析副总裁 Mike Branch 聊天
原文:https://towardsdatascience.com/chatting-with-the-vp-of-data-analytics-at-geotab-mike-branch-1ef04260c9f?source=collection_archive---------27-----------------------
与全球最大的远程信息处理行业领导者之一聊天
图片由 Mike Branch 提供
老实说,在决定我想在哪里发展职业生涯时,我是一个非常挑剔的人。也就是说,我非常幸运地在 6 个月前遇到了 Geotab。每天,我都和一群真正的数据迷一起工作,从事真正有趣的项目,并向一位不可思议的导师学习,他也是我的老板!
最重要的是,我有机会与 Geotab 数据和分析副总裁 Mike Branch 合作撰写一篇文章。迈克毫不犹豫地抓住这个机会,写了非常有思想的回应,我想每个人都可以从中学习。
如果你想了解更多关于 Geotab 的信息,了解是什么让这家世界上最大的远程信息处理公司如此成功,以及宝贵的职业建议,请留下来。
说到这里,我向大家介绍 Geotab 数据和分析副总裁 Mike Branch!
关于你
1.在你人生的哪个阶段,你意识到你想进入数据科学/数据分析领域,为什么?
我的职业生涯始于一名计算机工程师和软件开发人员,经营自己的软件开发业务刚刚超过 10 年。我一直对创建视觉上吸引人的软件有着着迷和热情,在这样做的过程中,战斗的一部分总是如何以一种对他们有意义和可操作的方式向我们的客户传达数据。
直到我卖掉公司,转到 Geotab,我才完全沉浸在数据科学领域,并立即爱上了它。这是 5 年前的事情,我之前做的一切都是由分析驱动的,而不是基于机器学习概念或任何与人工智能无关的东西。
我立即被机器学习的世界所吸引,因为它改变了我的思维模式(因为它与人们对传统软件开发的思考方式如此不同),并且它开辟了一个新的机会世界,以更简化的方式提供更高层次的洞察力。现在我可以用我的爱来创造视觉上吸引人的软件,并结合强大的 ML 驱动的洞察力。
2.你最喜欢的数据科学概念是什么,为什么?
强化学习(RL)领域对我来说非常有趣,因为这里有很多未开发的潜力,并且它不围绕着拥有大量标记数据,而这些数据是传统监督学习方法所必需的。过去,我们在很大程度上看到它应用于游戏和机器人,但随着基于云的 RL 平台开始通过提供必要的 RL 环境来进一步民主化这一领域,这对于这些利基用例之外的行业来说变得越来越令人兴奋。
3.我觉得这个疫情给了我们很多额外的时间。你在空闲时间喜欢做什么?
我不确定我是否同意这个疫情给我的“更多时间”)我和我的妻子在 3 月 15 日这个疫情开始的时候有了我们的第三个小孩(一个女孩)。我仍然记得走进医院对面的星巴克,看到所有的座位都被推到一边,还有新冠肺炎的警告标志。这是我们今天的标准,但在当时是令人震惊的。所以,我在疫情的生活围绕着我的两个儿子和一个刚出生的女儿(都是 5 岁或更小的:)的家庭时光。我的妻子应该在这里获得一枚奖章!
关于 Geotab
3.对于那些不知道什么是远程信息处理的人,你将如何向他们解释它,它与数据科学有什么联系?
非常广泛地说,远程信息处理领域捕获车辆运动和健康数据,并将其传输回基于云的环境,以便摄取到软件平台中。
我们在商业远程信息处理领域为规模从 1 到 100K 以上的车队提供服务。我们从全球超过 200 万辆商用车辆中获取数据,每天处理超过 400 亿条记录。然后,我们 80 人的数据科学团队从这些数据中产生洞察力,以帮助我们的客户。我们会回答这样的问题:从燃油经济性的角度来看,哪种车最适合我?我车上的电池什么时候会失效?我的哪些车辆没有得到充分利用?哪些车辆可以过渡到电动车?
Geotab 拥有世界上最丰富的车辆数据集,可以为我们的客户提供从位置数据到大量发动机诊断数据的价值,包括 RPM、挡风玻璃雨刷激活、电动汽车充电状态。对于希望有所作为的数据科学家来说,处理如此大量和多样的数据具有巨大的吸引力,正如我的一位同事所说→“他们为数据而来,但为文化而留。”
4.ABI 研究公司去年将 Geotab 列为第一名——从数据分析的角度来看,是什么使 Geotab 独一无二,从而成为世界上排名第一的远程信息处理公司?
我们的核心是数据驱动的文化。这一信息在我们的企业口号“通过测量进行管理”中非常明确,并由我们的首席执行官推动,他在如何运营组织和他所创造的文化中体现了数据驱动的含义。
我认为我们的不同之处在于我们处理数据问题的方式——我们专注于为客户创造价值,而不是货币化。这似乎是一个微小的差别,但如果你过度关注数据货币化,它可能会导致你创造出不符合客户长期利益的产品。我们还坚信利用数据做好事,并在我们的开放数据门户 Geotab Ignition 上提供了大量聚合数据集,供开发人员和数据科学家用来创建更安全驾驶和更安全城市的应用程序——从城市中的危险驾驶区到超局部降水(来自雨刷激活)。我们的团队还非常重视快速实验和创建基于数据的 MVP(最小可行产品),这真正促进了新想法的孵化,并进一步巩固了 Geotab 作为市场领导者的地位。
分享建议
5.你认为最重要的数据科学概念是什么,为什么?
将数据视为产品。我指的不仅仅是数据清理。在组织中,数据常常被视为另一个过程的副产品,人们必须认识到,数据是为人工智能提供动力的燃料,为了让我们拥有好的人工智能并做出好的预测,我们必须拥有好的数据。这从将数据视为组织中的产品开始。我指的是数据目录、数据沿袭、数据可发现性、使用策略、异常检测、监控、驻留、摄取管道、隐私等。有一大堆工作有时不那么光彩,但对于可持续的数据实践来说绝对是必不可少的,这些数据实践可以产生良好的模型,并推动更好的洞察力。
6.你认为人们忽略了什么技能,但应该在数据行业花更多的时间?
SQL。这可能看起来相对简单,但是数据科学家(在我看来)通常在 Python 和 R 方面有很好的造诣,但是 SQL 经验一般。对于 SQL,我不仅仅指编写 select 语句的能力,我还指复杂的连接、窗口、地理空间操作、在高效查询中处理大量数据等。有了像 Google BigQuery 和 Snowflake 这样的平台,我们越来越多地看到,仅仅利用 SQL,实际上可以做多少准备和预处理数据的工作。事实上,在许多情况下,您可以利用高级 SQL 语法来创建和训练基本模型(其中许多模型可以满足您 90%的业务需求)。
7.最后,你对那些刚刚开始数据科学/数据分析职业生涯的人有什么建议吗?
在我看来,我相信那些将软件工程实践融入其数据科学职业生涯的人处于最佳位置,因为他们知道如何将模型从初始阶段带到生产阶段,并且他们知道如何将模型扩展到整个生态系统。不仅如此,这些人还能够在他们新开发的模型周围包装一个软件或 API,并能够迅速向最终用户强调其优势,更快地实现采用。否则,模特们会冒着呆在实验室里看不到阳光的风险。
感谢阅读!
我希望你觉得这篇文章很有见地,很有趣!再次感谢迈克与我们分享你的经验和智慧。
如果这激起了你对 Geotab 的兴趣,我们发展得真的很快,我强烈建议你去 看看我们的 。如果您有任何问题,我也非常乐意在 LinkedIn 上与您联系!
不确定接下来要读什么?我为你挑选了另一篇文章:
还有一个:
特伦斯·申
- 如果你喜欢这个, 跟我上媒 了解更多
- 有兴趣合作吗?让我们连线上LinkedIn
- 报名我的邮箱列表 这里 !
检查熊猫数据帧列中的子字符串
原文:https://towardsdatascience.com/check-for-a-substring-in-a-pandas-dataframe-column-4b949f64852?source=collection_archive---------0-----------------------
大蟒
寻找字符串来减少用于分析和机器学习的数据集
马库斯·温克勒在 Unsplash 上的照片
熊猫图书馆是一个全面的工具,不仅用于处理数字,也用于处理文本数据。
对于许多数据分析应用和机器学习探索/预处理,您可能希望从文本数据中过滤或提取信息。为此,Pandas 提供了广泛的内置方法,您可以使用这些方法来添加、删除和编辑数据帧中的文本列。
在本文中,让我们具体看一下在 DataFrame 列中搜索子字符串。当您需要基于现有数据创建新类别时(例如在训练机器学习模型之前的特征工程期间),这可能会很方便。
如果你想继续,在这里下载数据集。
import pandas as pddf = pd.read_csv('vgsales.csv')
现在让我们开始吧!
注意:在这篇文章中我们会用到很多 *loc*
,所以如果你不熟悉这种方法,可以看看这篇文章底部的第一篇文章。
使用“包含”在熊猫数据帧中查找子串
Pandas 中的 contains 方法允许您在一列中搜索特定的子字符串。contains 方法返回系列的布尔值,如果原始系列值包含子字符串,则为 True,否则为 False。contains 的一个基本应用程序应该看起来像Series.str.contains("substring")
。但是,我们可以通过增加两项内容立即将此提升到下一个级别:
- 使用
case
参数指定是否匹配字符串大小写; - 使用返回的一系列布尔值作为掩码来获得数据帧的子集。
应用这两个应该是这样的:
pokemon_games = df.loc[df['Name'].str.contains("pokemon", case=False)]
使用loc
方法允许我们只获取 DataFrame 中包含字符串“pokemon”的值。我们简单地使用了contains
方法,根据“名称”列是否包含我们的子字符串来获取真值和假值,然后只返回真值。
在 Pandas 中使用 regex 和“contains”方法
除了匹配常规子串,我们还可以使用contains
匹配常规表达式。我们将使用与之前完全相同的格式,只是这次让我们使用一点 regex 来只查找基于故事的口袋妖怪游戏(即排除口袋妖怪弹球之类的游戏)。
pokemon_og_games = df.loc[df['Name'].str.contains("pokemon \w{1,}/", case=False)]
上面,我只是使用了一些简单的正则表达式来查找匹配“pokemon”+“一个或多个字符”+“/”模式的字符串。新面具的结果返回行包括“口袋妖怪红/口袋妖怪蓝”,“口袋妖怪金/口袋妖怪银”,等等。
接下来,让我们做另一个简单的例子,使用 regex 查找名称中带有“football”或“soccer”的所有体育游戏。首先,我们将使用一个简单的条件语句来过滤掉所有带有“sports”类别的行:
sports_games = df.loc[df['Genre'] == 'Sports']
您会注意到,上面并没有真正需要匹配子串或使用正则表达式,因为我们只是根据类别选择行。然而,当匹配行名时,我们需要在不同类型的字符串中搜索子字符串,这正是 regex 派上用场的地方。为此,我们将执行以下操作:
football_soccer_games = sports_games.loc[df['Name'].str.contains("soccer|football", case=False)]
现在,我们已经得到了一个数据框架,其中只包含名称包含“足球”或“橄榄球”的游戏。我们简单地使用了“|”regex“or”操作符,它允许您匹配包含一个或另一个子字符串的字符串。
因此,我们成功地得到了一个数据帧,它的名字包含“football”或“soccer ”,但我们实际上不知道它包含这两个字符串中的哪一个。如果我们想知道它包含两个中的哪一个,我们可以在 name 列上使用findall
方法,并将返回值赋给 DataFrame 中的一个新列。
findall
方法返回正则表达式模式的匹配,该模式是在调用它的序列的每个字符串中指定的。该格式与 contains 方法基本相同,除了您需要导入re
以不匹配字符串大小写。
import re
football_soccer_games['Football/Soccer'] = football_soccer_games['Name'].str.findall('football|soccer', flags=re.IGNORECASE)
您将在返回的数据帧的末尾看到一个包含“Soccer”或“Football”的新列,这取决于视频游戏名称包含两者中的哪一个。如果您需要基于现有列并使用这些列中的值来创建新列,这可能会很有帮助。
最后,为了快速排除字符串,只需在基本的contains
方法上增加一个操作符,让我们尝试得到所有名称中不包含“FIFA”的足球和英式足球游戏。
not_fifa = football_soccer_games.loc[~football_soccer_games['Name'].str.contains('FIFA')]
如你所见,我们简单地使用了~
操作符,它允许我们在loc
方法中获取掩码的所有假值。
仅此而已!
使用字符串可能有点棘手,但内置的 Pandas 方法是通用的,允许您以几乎任何需要的方式分割数据。contains
和findall
方法允许您做很多事情,特别是当您能够编写一些正则表达式来真正找到特定的子字符串时。
祝你好运!
**More by me:** - C[onditional Selection and Assignment With .loc in Pandas](/conditional-selection-and-assignment-with-loc-in-pandas-2a5d17c7765b?sk=e5672d859a3964c1453a1c09edca22cf)
- [Squeezing a New Trick Into Your Pandas Repertoire](/squeezing-a-new-trick-into-your-pandas-repertoire-d8ae3f338246?sk=a9d67d24b1ef469a88090b647f15ea50)
- [2 Easy Ways to Get Tables From a Website With Pandas](/2-easy-ways-to-get-tables-from-a-website-with-pandas-b92fc835e741?sk=9981ddaf0785a79be893b5a1dd3e03dd)
- [Top 4 Repositories on GitHub to Learn Pandas](/top-4-repositories-on-github-to-learn-pandas-1008cb769f77?source=friends_link&sk=d3acc38062490a86ecb46875342224e6)
- [Learning to Forecast With Tableau in 5 Minutes Or Less](/learning-to-forecast-effectively-with-tableau-in-6-minutes-or-less-3d77a55930a0?source=friends_link&sk=9abdfd7533ee9a31ab8a036413450059)
使用二进制扩展测试(BET)检查依赖性
原文:https://towardsdatascience.com/checking-for-dependency-using-binary-expansion-testing-bet-5234a818a18?source=collection_archive---------41-----------------------
统计独立性的一种新的非参数检验
夜空中的星星是均匀分布的吗?星系在宇宙中是均匀分布的吗?T 细胞是否为了杀死癌细胞而渗透到整个肿瘤?草原上的植被怎么样?在许多情况下,我们希望确定样本是否均匀地从感兴趣的空间中抽取。尽管这个问题听起来很简单,但是没有一个通用的解决方案可以满足所有的目的。最近,来自北卡罗来纳大学教堂山分校的张开为此引入了一个称为二进制扩展测试(BET)的优雅框架。这篇文章旨在为 BET 提供直观的解释。
让我们假设数据点分布在一个单位正方形内。然后每个点由两个随机变量 X 和 Y 指定。为了确定均匀性,有两个问题需要解决:1 . X 和 Y 是否遵循均匀分布?2. X 和 Y 在统计上是否独立?BET 是为问题 2 制定的,因此让我们先关注问题 2,然后再回到问题 1。
看一下实数 x= 0.375 *。*当然,按照通常的十进制形式写,
但是在二进制数字系统中,
一般来说,任何实数 x 使得 0≤x≤1 都可以表示为一个序列{ b ᵢ}与 b ᵢ=0 或 1。认识到ᵢ}可以被描绘成一系列二元决策是很重要的。第一项意味着区间[0,1]被划分成大小为 1/2 的 2 个仓,并且被询问 x 是位于左仓( b ₁=0)还是右仓( b ₁=1).)由于答案是“左”,第二项意味着区间[0,1/2]然后被进一步划分成大小为 1/4 的 2 个箱,并且被询问 x 是位于左箱( b ₂=0)还是右箱( b ₂=1).)这一次答案是“正确的”,它进入第三项,其中区间[1/4,1/2]被分成大小为 1/8 的两个箱,并且我们有另一个决策树 b ₃.
二进制展开可以被视为使用二进制变量划分单位区间的一种方式,而不是关注如何将实数映射到二进制数序列。一般来说, d 二元变量可以将单位区间分成 2 个ᵈ区间,每个长度为 d 的二元序列对应一个区间。给定从[0.1]中提取的随机变量 X ,我们可以通过 d 二进制随机变量来近似 X ,其中 d 确定面元大小,从而确定分辨率。很快就会清楚,用 aᵢ =2 bᵢ -1 代替 bᵢ 会更方便。换句话说,二进制变量取值为 1。
现在来看两个随机变量 X 和 Y 的相关性,这两个随机变量取自一个单位区间。我们选取某一深度的 d 并通过两个二进制随机变量序列来近似 X 和y{xᵢ}和{ Xⱼ }其中 i , j 从 1 运行到 *d,*和 Xᵢ 和 Xⱼ 取值回想一下 d 二元变量可以将单位区间划分为 2ᵈ箱,两组这样的变量将单位正方形划分为 2 个ᵈ小正方形,一个数据点 (X,Y) 将落在其中一个小正方形上。然而,BET 的关键不仅仅是将单个数据点分配给一个网格。BET 的目标是检查分布在网格上的数据点集合的均匀性。为了实现这一目标,BET 将网格一分为二,并计算每一半中的数据点数量。基于二进制变量的一个巧妙的技巧实现了对分。
为了说明这一点,让我们考虑一下情况 *d=2。*随机变量 X 和 Y 被映射到 4 个二元变量 X₁、X₂、Y₁、Y₂ 上,这些变量将单位正方形分成 4×4 的网格。有许多不同的方法可以将网格一分为二,例如,将网格分成左半部分和右半部分,或者分成上半部分和下半部分,或者分成棋盘。使用的关键观察:所有可能的二等分都可以被 X₁、X₂、Y₁、Y₂ 以及它们的组合捕获。例如,变量 X₁ 将网格分为左半部分( *X₁=-1,*蓝色)和右半部分( *X₁=+1,*白色);变量 Y₂ 将网格切割成水平带( *Y₁=-1,*蓝色; *Y₁=+1,*白色);并且棋盘可以通过组合 X₂Y₂= 1 来获得(这实际上是我们更喜欢值 1 到 1 或 0 的原因)。通过列举二元变量所有可能的选择,不难看出
这种二分法的例子如下所示。
二元函数对分(蓝色:-1,白色:+1)KKY 图像
列举了所有可能的二等分,一致性的推论是简单的。本质上,给定一个等分线,我们计算落在蓝色和白色区域的数据点的数量, n=nᵇ+nʷ 。由于蓝色和白色区域的面积相等,因此在 X 和 Y 之间缺少相关性将导致 nᵇ≈nʷ 。我们可以简单地用二项分布 B (n,p= 1/2 ) 作为空值,给观测值赋一个 P 值。由于二等分的数量呈指数级增长,p 值应针对多重假设检验进行调整,例如,乘以因子 2 ᵈ-1.
让我们看看张开手稿中的一个具体例子。他和他的同事已经在 R 包中实现了 BET。绝对值得一试。在下图中。红点表示天球上恒星的分布,其中 X 和 Y 是两个坐标参数。使用 d=2, BET 对所有等分线进行了测试,发现所示等分线呈现出一种具有最显著 q 值的不对称性。因此,BET 得出结论,恒星并不是均匀分布的,这当然是事实,因为恒星密集地分布在银河系的中心。
天空中星星的分布(数据来源:Ref 2,KKY 使用 Ref 生成的图。2)
到目前为止,我们已经概述了 BET 背后的直觉。一个问题不清楚: d 的值是多少?张开提出了一种迭代方法,在这种方法中,人们可以逐渐增加 T2 d T3。当然,根据数据点的数量, d 不能太大,否则会有很多面元是空的;还有,大的 d 会造成假设数量的爆炸,不对称不会很显著。最后,人们可能会注意到,BET 的目标是显示 X 和Y之间缺乏相关性。如果将 X 和 Y 视为空间坐标,则缺乏相关性意味着单位正方形内数据点的一致性。然而,反过来总是正确的吗?这两个概念是否相同很重要,因为 BET 所采用的宁滨和计数程序仅仅显示了一致性。我们将在下一篇文章中研究这些细微的差别以及 BET 解决它们的方法。
参考:
- 张开,赌独立(2019)。美国统计协会杂志
- 张莞,赵志根,迈克尔·拜奥奇,张开,BET:二进制扩展测试(2020),R 包版本 0.2.0
人工智能产品经理从设计冲刺中获得最大收益的清单
原文:https://towardsdatascience.com/checklist-for-ai-product-managers-to-get-the-most-from-the-design-sprints-d681456b1be9?source=collection_archive---------46-----------------------
不要让顾问愚弄你!
如何用一个伟大的产品满足所有利益相关者
插图来自上卷
将“数字化”、“创新”和“大数据”等流行词汇转化为有生命力且有利可图的产品非常困难。通常,失败的不是技术本身,而是所有者、管理者、客户、员工,有时还有社会之间的协调。对于人工智能产品来说,这甚至更难,因为这是一个相对较新的领域,其中有:
- 要么是通才顾问,他们可以在没有具体数字和下一步措施的情况下讲述光明的未来和经济影响;
- 或者是深度专家,他们知道这项技术的潜力和局限性,但是他们缺乏系统的商业和社会视野。
在这篇文章中,我想分享我们在神经元实验室与合作伙伴一起精心设计的方法,该方法融合了以用户为中心的算法、经济增长和社会影响,从而协调了产品生命周期中的所有利益相关者。它基本上是基于设计冲刺的想法,然而,主要步骤是从零开始重新构建,以符合行业的具体情况。
为 AI 设计冲刺?
经典设计冲刺的典型步骤,图片来自https://medium . com/I-want-to-be-a-product-manager-when-I-grow-up/the-design-sprint-92f 61 b 18 FB 72
原始设计冲刺的主要思想是快速验证想法:了解市场需求,头脑风暴解决问题的新方法,原型第一数字解决方案,并与客户一起测试。理想情况下,它甚至可以在 5 天内完成。此类活动的典型成果是:
- 来自头脑风暴的发现(用户故事、技术应用、优先新颖用例)
- 一个交互式的原型,它展示了用例并得到了涉众的验证
- 具有所需资源和风险的发展战略路线图
你可以在这里阅读更多关于这些短跑的历史和最佳实践。这些结果通常会满足所有重要的利益相关者,如传统数字产品的所有者、管理者和客户。在接下来的部分中,我将描述活动和实践,这些活动和实践将创建上述可交付成果,这些可交付成果将协调参与开发和使用以人工智能技术为核心的产品的每个人。
顾客想要什么
使用 Streamlit 可视化计算机视觉模型性能的实例。交互演示用户故事不是比演示 PowerPoint 演示或模板模型更好吗?插图来自流线型
引用蠢朋克的话,你的客户想要解决他们的问题:
更难、更好、更快、更强
人工智能相关技术确实可以让事情变得更准确、更快速,从我们的生活中删除常规或危险的任务。但是如何正式确定我们到底能为客户做些什么呢?我可以推荐谷歌使用的两个框架:
- 艾画布出自《预测机器》一书。它将帮助你将客户的想法转化为使用人工智能的用户故事
- 人+ AI 指导手册。它将有助于定义数据、度量、可解释性的需求,并支持上述用户情景的
你也想展示一些演示,并在几个小时内准备好,而不是几个星期,对吗?
- 轻松部署工具工具 ( BentoML 、烧瓶、 Streamlit
- No-code(asLobe)/managed解决方案(AWS、Azure、GCP 等)
- 开源 ML 模型zoo 为papers,代码, ModelZoo
因此,在这里,您将有一个按优先顺序排列的用例列表,并有几个小演示向用户展示它将会是什么样子。
企业想要什么
我们在神经元实验室准备的一个过程自动化项目的 PnL 计算样本,包括发布点、盈利起点和盈利转折点。作者图片
当然,以用户为中心的方法是核心,但从商业模式的角度来看,产品还必须是盈利的,并且在市场上具有竞争力。这在设计冲刺阶段通常会被忽略,从我的角度来看,这是一个可怕的疏忽。这部分是非常定制的,但是你想把它缩小到单个预测的单位经济学。使用上述“预测机器”中的人工智能画布,您可以计算使用人工智能功能的经济效果:
- 由于速度加快/质量提高/风险降低,每次预测你会节省多少钱?
- 您可以预期的精确度是多少,有多大把握?
您需要减去相关成本,包括但不限于:
- 开发成本(内部/顾问/外包)
- 维护,人力支持,以及云成本与风险
这个过程很棘手,我建议和那些在你的领域内已经交付了 10 多个项目的专家一起工作。因此,您将有一个业务模型草案,并根据经济情况重新确定用例的优先级——也许您最喜欢的用例从现在起 5 年后开始盈利,而您需要第二个更快上市的用例!
经理想要什么
克里斯普-DM,TDSP 和敏捷数据科学哲学插图。结构化方法和敏捷方法——哪个更适合你的项目?图片来自数据科学中心、微软和被烧毁的
好了,现在我们调整了用户和业务的需求,但是仍然会有人负责将这个交付给市场。他们应该如何监控发展?他们应该使用哪些指标?哪种资源燃烧速率可以接受,哪种不可以?如何管理 R & D 相关不确定性?如何以一种灵活敏捷的方式交付产品,让客户满意,同时又不增加额外的资本?
经典的 R&D 和数据科学流程,如 CRISP-DM 或 TDSP 考虑孤立的数据、建模和部署工作,而客户必须等待数月
"数据科学团队正在处理数据并训练模型,这是一个高度不可预测的过程"
听起来很像借口,对吧?备选的 敏捷数据科学 方法将每个最小的 R & D 阶段视为子产品(参见上图中的金字塔),可以为客户带来即时价值。我们可以开发什么样的用户故事和相关指标?
- **数据获取:**如果客户尚未收集任何数据,您需要定义数据收集和组织如何立即简化生活和一些流程(业务指标)
- **数据探索:**原始的统计洞察应该导致原始的预测决策和基于规则的系统,这些系统已经可以自动化一些工作!检查第一部分中基于客户端的指标
- **建模:**在制作越来越好的模型的同时,检查业务和基于客户的指标,您应该在这个阶段使用部署的模型达到盈利点
- **可操作的见解:**嗯,这是大家最后想要的:)
同事想要什么
插图来自突发事件
我们,管理者,喜欢透明和可预测的过程,但是必须有人在总体计划后面做实际的工作:)做有意义的工作有不同的动机,但是根据这个结构,它们是自主、掌握和目的。
- 自主性可以通过委派更多的责任和决策,从任务跟踪系统转换到结果跟踪系统来实现。分散的组织结构是你想要寻找的东西
- 精通来自基础知识和最先进的技能和技术。第二个可以通过使用像 PapersWithCode 和 AI Index 这样的门户网站来规划,在那里你可以找到大多数领域的最新发展
- 目的是一个有点敏感的问题,但通常,它与给予世界它需要的东西有关。下一部分是关于人工智能背景下的 it,你的商业策略和文化也必须负责任:)
这是一种在设计冲刺阶段考虑同事的非传统方法,然而,对于现代以人为中心的组织来说,这是必须的。
世界想要什么
图片来自https://www.uxai.design/design-strategy
人工智能是一种有缺点的技术——与人类智能一样,它可能会有偏见、模糊,并且容易受到外部攻击。我们可以做些什么来使人工智能的采用变得正确和有目的?在设计冲刺阶段,我们需要让利益相关者意识到这些问题,定义产品中的敏感时刻,并提供潜在的解决方案:
- **公平公正的人工智能:**我推荐使用 PAIR 的“假设工具”和一个更技术性的 Themis-ML 库来进行公平检验
- 可解释 AI: 对于解释 ML 预测,已经有多种策略和解决方案,如 TCAV 和 SHAP
- 受保护的 AI: 你肯定需要在基础设施层面上保护你的训练数据,并且,潜在地用联合学习 ( TF , PyTorch )。此外,机器学习模型可能会受到对抗性攻击,迫使模型做出错误的预测。检查这些 库作为潜在的解决方案。
外卖食品
在本文中,我们重新评估了基于人工智能的产品的经典设计 sprint 结构和可交付成果。作为主要思想,我们已经回顾了在开发和利用项目的过程中,每个项目涉众希望对项目满意的方面:
- **最终客户:**通过互动演示带来切实积极变化的解决方案
- **业务所有者:**具有单一预测单位经济性、燃烧率和相关风险的业务模型
- **管理者和员工:**前者有清晰的流程和衡量标准,后者有工作的实现
- **社会:**一个伟大的人工智能技术应用,它是公平的、透明的,并被保护免受误用
我没有提到在设计冲刺阶段有时会做的市场营销和竞争对手分析,因为我希望事先做广泛的竞争对手和市场分析。设计冲刺对于头脑风暴和测试技术产品的不同想法来说是很棒的,但是定义一个公司的总体愿景和战略是一个有点不同的话题。如果你有任何问题,或者你想分享你做这种设计冲刺的经验,请告诉我。祝你的人工智能产品好运!
附言
如果你觉得这个内容有用,有观点,可以在 Bitclout 上支持我。关注我还可以在脸书上看到太短的人工智能文章,在 Instagram 上看到个人资料,在 Linkedin 上看到!如果你想在设计冲刺或其他 ML 项目上合作,请联系我。
chef boost——基于树的模型的替代 Python 库
原文:https://towardsdatascience.com/chefboost-an-alternative-python-library-for-tree-based-models-f46af028a348?source=collection_archive---------14-----------------------
照片由张克帆·马塞多在 Unsplash 上拍摄
与 scikit-learn 的主要区别概述
我在我的 Twitter feed 中随机遇到了chefboost
,鉴于我以前从未听说过它,我决定快速浏览一下并测试一下。在本文中,我将简要介绍这个库,提到它与首选库scikit-learn
的主要区别,并展示一个实践中的chefboost
的快速示例。
chefboost 简介
我认为最好的描述是在库的 GitHub repo 中提供的:“chefboost 是 Python 的一个轻量级决策树框架,支持分类特性”。
与scikit-learn
相比,chefboost
有三个突出的特点:
- 支持分类特征,这意味着我们不需要使用例如一键编码对它们进行预处理。
- 使用
chefboost
训练的决策树被存储为专用 Python 文件中的 if-else 语句。通过这种方式,我们可以很容易地看到树做出了什么决定来达到一个给定的预测。 - 我们可以选择多种算法中的一种来训练决策树。
遵循最后一点,chefboost
为分类树(ID3、C4.5 和 CART)提供了三种算法,为回归树提供了一种算法。老实说,我并不完全确定哪一个是当前在scikit-learn
中实现的,所以我查看了文档(它也提供了算法的简明摘要)。原来scikit-learn
用的是优化版的 CART 算法,没有分类特征的支持。
在我们已经介绍的基础上,chefboost
还提供了一些更高级的基于树的方法,比如随机森林、梯度增强和 Adaboost。
Python 中的一个例子
和往常一样,我们从导入库开始。
对于这个例子,我们将使用成人数据集。你可能已经遇到过,但简单来说,目标是预测一个成年人的年收入是高于还是低于 5 万美元。为此,我们从 1994 年人口普查数据库中选择了一些数字和分类特征。你可以在这里找到原始数据集。
chefboost
中的一个怪癖是对目标变量的处理——它必须存储在与特征相同的数据帧中,它必须被称为Decision
,并且必须是数据帧的最后一列。很奇怪,但这可能是有原因的。
我们还将把数据分成训练集和测试集。然而,数据的非标准结构要求scikit-learn
的train_test_split
函数有一点不同的用法。即使数据集不是高度不平衡的,我们也使用了目标列的分层分割。
通常,我们也会将分类特征编码为布尔虚拟对象,但是chefboost
可以直接处理它们。这就是我们开始训练模型的原因。
为了训练模型,我们使用了fit
函数,并传递 dataframe(包含正确格式的数据)和config
字典作为参数。这一次,我们只表明我们想要使用 CART 算法。
假设我们的数据包含分类和数字特征,我们也可以使用 C4.5 算法,但不能使用 ID3,因为它不能处理数字特征。
培训完成后,我们得到了以下总结。
作者图片
很高兴看到这么多现成的指标,但最突出的是培训时间。这一棵树花了 10 多分钟来训练!可以通过在config
字典中设置enableParallelism
到True
来并行化训练。这样,树的分支被平行地训练。然而,这样做并没有带来实际的训练速度的提高,至少在我的机器上没有。
另外,与scikit-learn
的另一个区别是chefboost
主要使用函数而不是类。
训练模型导致创建一个新文件-> rules.py
。如简介中所述,它以嵌套的 if-elif-else 语句的形式包含了决策树的整个结构。
下面你可以看到脚本的一部分,整个脚本有 20.5 千行长。一方面,使用这样的嵌套结构,决策的逻辑非常清晰。但是另一方面,如果不限制树的最大深度(我认为这对于chefboost
中的决策树是不可能的),遵循决策路径根本不容易。
作者图片
训练好一个模型后,我们可以将它存储在 pickle 文件中,或者使用restoreTree
函数直接从rules.py
文件中加载它。
为了获得预测,我们使用了predict
函数。
您可能已经注意到,我们只向函数传递了一行数据。不幸的是,这是chefboost
做预测的唯一方法。我们可以自然地循环整个数据帧,但这不如scikit-learn
的 predict 方法方便。
我们可以做的是使用evaluate
函数运行评估。
我们得到了一个类似于我们从训练中得到的输出。但是我们不会花太多时间来分析树的性能,因为这不是本文的目的。
作者图片
该库提供的另一个特性是特性重要性分析。我就不赘述它是如何计算的了(你可以在这里找到它们)。为了获得重要性,我们需要使用feature_importance
函数并提供rules.py
文件的路径作为参数。
作者图片
结果表明,年龄是预测一个人年收入是否超过 5 万美元的最重要的特征。
作为最后一件事,我想比较一下chefboost
和scikit-learn
的速度。自然,后一个库中的决策树需要不同格式的数据,所以我们相应地准备了数据。
我们使用与之前相同的分割设置,以确保公平的比较。然后,我们使用%time
魔法来看看训练模型需要多长时间。
CPU times: user 1e+03 ns, sys: 0 ns, total: 1e+03 ns
Wall time: 3.1 µs
这是一个相当大的差异…我不确定是什么原因,我打赌会创建树的 if-else 表示。
外卖食品
chefboost
是用于训练基于树的模型的备选库,- 突出的主要特性是对分类特性的支持和以嵌套 if-else 语句形式的模型输出,
- 与
scikit-learn
相比,训练要慢得多,并且要调整的超参数的选择非常有限。
你可以在我的 GitHub 上找到本文使用的代码。此外,欢迎任何建设性的反馈。你可以在推特或评论中联系我。
如果您喜欢这篇文章,您可能还会对以下内容感兴趣:
三行代码的化学预测
原文:https://towardsdatascience.com/chemical-predictions-with-3-lines-of-code-c4c6a4ce7378?source=collection_archive---------17-----------------------
使用 Chemprop & graph 神经网络的最新结果
由宏向量设计—www.freepik.com
在这篇文章中,我们使用机器学习/人工智能来预测小分子的属性(这项任务被称为 QSAR )。这是通过使用来自开源库 Chemprop 的最先进的图形神经网络来完成的。
典型的药物以小分子的形式出现,可以调节我们体内的一些生物过程。不幸的是,在这个过程中可能会出现难以想象的问题;这些化合物可能是有毒的,从我们体内清除非常缓慢,与非预期的其他分子相互作用,等等。因此,我们希望在这些小分子被注射到人体之前,非常仔细地对它们进行检测。
在药物发现的早期阶段,通常在实验室规模的实验中测试小分子的许多不同变体的各种性质,例如溶解度、不同形式的毒性、结合亲和力等。这个过程可能非常费力,所以使用 ML 来根据已经完成的实验预测这些特性不是很好吗?这项任务在化学信息学中是众所周知的,近年来由于深度学习的进步而受到越来越多的关注。
有大量的库可以进行这种分析。在本文中,我们将使用名为 ChemProp 的开源库,该库由麻省理工学院的一个研究小组不断更新,它在广泛的基准数据集上取得了出色的结果,同时使用起来极其简单。
输入数据是什么?
预测化学性质传统上被称为定量结构-活性关系(QSAR)模型。这些模型的输入是分子的字符串表示,也称为“微笑”字符串。例如,这可能看起来像这样:
不同的微笑字符串可以代表同一个分子,但是每个微笑字符串只对应一个分子。作者图片
从本质上讲,我们的数据集由用微笑字符串表示的分子和我们想要预测的每个分子的一组属性组成。这可以看起来如下:属性是一个分子是否被 FDA 批准和是否通过毒性测试的二元变量。
每个样本都是一个分子,由它的微笑字符串和一个或多个属性表示——图片由作者提供。
这个 Chemprop 模型是什么?
Chemprop 模型于 2019 年在[1]发表,但此后一直在不断更新,并在一系列后来的出版物中显示出其价值,最引人注目的是在[2]中,他们用它来发现新的潜在抗生素化合物。
底层的 Chemprop 是在 Pytorch 中实现的消息传递神经网络,这意味着模型的输入是分子的图形表示。然而,除了直接在图表上工作之外,Chemprop 还自动使用更经典的衍生化学特征,这意味着它通常在小型和大型数据集上都表现良好(与其他模型相比)。要了解更多信息,我推荐阅读论文[1]。
Chemprop 可以从 PyPI: pip install chemprop.
安装
让我们开始吧:3 行代码
假设我们有一个如上所示的数据集,带有一些微笑字符串和两个我们希望预测的属性;FDA 是否批准了该化合物,以及它是否通过了临床试验期间的毒理学测试。
大量类似的数据集可以在网上找到,例如,查看这些基准。在 Chemprop 的典型使用中,我们将经历以下步骤:1)优化模型的超参数,2)训练模型,以及 3)对一组新的分子进行预测。
步骤 1:调整超参数。
Chemprop 有一些可调的超参数,可以调整这些参数以在给定数据集上获得最佳结果。安装 chemprop 后,我们可以运行 50 次 TPE 超参数调整迭代:
第二步:训练模型
有了在data/config.json
中识别和保存的理想超参数,我们就可以用这些参数训练模型:
这里有几个值得注意的有趣参数:
num_folds
:我们创建 5 个折叠(不同的训练/测试)分割,并在每个折叠上训练/评估模型。ensemble_size
:我们用不同的初始化创建了一个 3 个模型的集合,这将提高平均性能。请注意,这 3 个模型每个都有 5 个折叠,所以我们总共训练了 15 次模型!split_type
在创建我们的内部训练/测试分裂时,我们确保将相似的分子放入相同的折叠中,以获得更真实的泛化度量。
在我的训练运行中,我收到了下面的输出:Overall test AUC: 0.871 +/- 0.036
——即来自训练交叉验证的非常有希望的结果。
步骤 3:根据新数据评估模型。
既然我们已经训练了模型,下一步就是在测试数据集上评估它的性能。从交叉验证中我们已经知道,性能应该是大约 0.84 的 AUC,但是让我们看看:
这将生成一个文件predictions.csv
,其中包含我们测试数据集中化合物的预测。请注意,这些预测是上一步中训练的总共 15 个模型的平均值。将此与真实值进行对比,我们得到以下结果:
在测试数据集上评估已训练的 chemprop 模型。由作者策划。
非常适合最小的努力!👏
更进一步:解释
有时仅仅得到点预测是不够的;我们可能想知道为什么模型返回一个给定的预测。例如,如果预测该分子是有毒的,那么知道该分子的哪一部分引起所述毒性将是有价值的。通过从这里获取我的 Chemprop 分支,我们可以使用 BayesGrad 方法的变体创建这样的解释:
对于由interpret_local.py
脚本评估的每种化合物,算法将返回一个解释图,例如,在上面训练的溶解度模型的情况下,它将显示亲水原子(氧)如何增加分子的溶解度:
解释溶解度预测的热图。图片由作者提供。
简而言之,这里分子中给定原子或键的“重要性分数”被计算为预测目标相对于来自该原子或键的特征的梯度;即,归因于给定键/原子的梯度的绝对和越大,假定该键/原子对预测越重要。众所周知,以这种方式直接生成的灵敏度图噪声很大。因此,BayesGrad 建议使用 dropout 对网络参数 W 的后验分布 p(W|D) 进行采样,允许我们计算所有这些采样网络的梯度平均值,从而平滑结果。我们没有依赖 Chemprop 中包含的 dropout,而是通过简单地使用交叉验证折叠和集合模型中的权重 W 对 p(W|D) 进行采样,即,对于一组 20 个模型,我们计算每个原子和键的梯度的平均和。
结束语
能够预测化学性质是极其强大的;想象你有一组 100 个潜在的分子候选者。合成它们中的每一个都是一项艰巨的任务。如果我们可以根据它们满足各种特性的可能性来对它们进行排序,我们就可以首先综合出最有希望的候选者。此外,通过解释模型预测,我们可以了解更多关于分子工作或不工作的原因,因此甚至可以根据这些信息开发出更有前途的候选分子。
使用 3 个命令来训练和预测这些模型可能会给人一种这是一个已解决问题的印象。事实并非如此。我推荐阅读 Andreas Bender 的这篇文章,思考从这些模型中得出结论是多么的危险和困难。
[1] Kevin Yang 等, J. Chem .Inf。模型。 2019,59,8,3370–3388
[2]乔纳森·m·斯托克斯等,抗生素发现的深度学习方法(2020),细胞,180,4,P688–702。E13
胸部 x 光和肺炎:使用 TensorFlow 进行深度学习
原文:https://towardsdatascience.com/chest-x-ray-pneumonia-deep-learning-with-tensorflow-a58a9e6ade70?source=collection_archive---------24-----------------------
处理班级失衡并有效使用预先训练的模型
疾控中心在 Unsplash 拍的胸部 x 光照片
在过去的几年里,我们已经看到以各种形式使用深度学习进行医学诊断的快速增长,特别是在医学图像的分析中。这里我们将建立一个管道,对肺炎患者和非肺炎患者的胸部 x 光图像进行分类。在知识共享许可下,完整的数据集可以在 Kaggle 获得。在我们建立管道之前,让我们看看你能从这篇文章中学到什么
- 使用深度神经网络(DNN)进行二元分类。
- 使用 TensorFlow 数据集创建更快的数据分析管道。
- 更好的数据预处理技术(例如:标准化)。
- tensor flow 模型中的 lambda 层的扩充、重新缩放等。
- 阶层失衡与建筑自定义加权交叉熵损失。
不要耽搁,让我们开始吧!【这里用到的所有代码都可以在 Kaggle 笔记本中找到】。
熟悉数据结构:
因为我们将直接访问 Kaggle 输入目录中的数据,所以让我们来看看标签“正常”和“肺炎”在 Train、Validation 和 Test 文件夹中的分布。下面是我用来检查每个文件夹中文件数量的代码块
图 1: X 标签代表文件夹名称。训练、测试、验证,N 代表正常,P 代表肺炎。来源:作者笔记
首先,我们看到训练图像*是类别不平衡的,标记为“肺炎”的图像比“正常”的图像多得多。*此外,验证文件夹包含的示例非常少(准确地说是 8 个正常图像和 8 个肺炎图像)。
tot_normal_train = len(train_im_n) + len(valid_im_n)
tot_pneumonia_train = len(train_im_p) + len(valid_im_p)
print ('total normal xray images: ', tot_normal_train)
print ('total pneumonia xray images: ', tot_pneumonia_train)>>> total normal xray images: 1349
total pneumonia xray images: 3883
我们也可以想象一些正常和肺炎的图像,如下所示
“正常”X 射线图像:原始数据来源:在 Kaggle 中可用。
类似地,我们也可以查看“肺炎”图像—
肺炎的 x 光图像:原始数据来源:可在 Kaggle 获得。
在阅读了一些在线资源后,比如这个,我注意到发现肺炎的通常方法是搜索胸部 x 光片中的阴影。从上面的图片来看,与普通 x 射线相比,这些图像通常看起来不透明。但同样重要的是要记住,胸部 x 光检查可能不会一直告诉我们全部情况,有时视觉结果可能会产生误导。
预处理;标准化:
我们将调整图像数据,使数据的新平均值为零,数据的标准偏差为 1。稍后,我们将使用 TensorFlow 数据集,并定义一个函数,在该函数中,图像中的每个像素值都将替换为一个新值,该新值通过减去平均值并除以标准偏差(*x**μ)/σ计算得出。*让我们看看标准化如何帮助我们在一些随机示例中分配像素值——
对于一些随机图像,标准化(A)之前(B)之后(A)的像素强度分布。来源:作者笔记。
为了包括这种类型的标准化,我们创建了一个函数,该函数将在模型构建中用作 lambda 层。因此,GPU 的能力也将用于这个过程—
#### define a function that will be added as lambda layer later
def standardize_layer(tensor):
tensor_mean = tf.math.reduce_mean(tensor)
tensor_std = tf.math.reduce_std(tensor)
new_tensor = (tensor-tensor_mean)/tensor_std
return new_tensor
使用 TensorFlow 数据集构建输入管道:
在之前的一篇帖子中,我详细描述了如何使用 TensorFlow 数据集 API 构建包括增强在内的输入管道来加速 DNN 训练。我将遵循类似的步骤。由于图像数据存在于训练、测试和验证文件夹中,我们可以从[image_dataset_from_directory](https://keras.io/api/preprocessing/image/)
功能开始——
正如我们之前检查的,验证目录中只有 16 个文件,只使用 16 个图像进行验证并不是一个好主意。因此,我们需要添加训练和验证数据集,然后按照合理的百分比对它们进行拆分。首先,让我们检查“训练”和“有效”数据集中的元素数量。
num_elements = tf.data.experimental.cardinality(train_dir).numpy()
print (num_elements)
num_elements_val = tf.data.experimental.cardinality(val_dir).numpy()
print (num_elements_val)>>> 82
1
我们看到有 82 个训练批次和 1 个验证批次。为了增加验证批次,首先,让我们连接“训练”和“验证”数据集。然后,我们将总数据集的 20%分配给验证,并使用下面的代码块使用dataset.take
和dataset.skip
来创建新的数据集—
new_train_ds = train_dir.concatenate(val_dir)
print (new_train_ds, train_dir)
train_size = int(0.8 * 83) *# 83 is the elements in dataset (train + valid)*
val_size = int(0.2 * 83)
train_ds = new_train_ds.take(train_size)
val_ds = new_train_ds.skip(train_size).take(val_size)
*#### check the dataset size back again*
num_elements_train = tf.data.experimental.cardinality(train_ds).numpy()
print (num_elements_train)
num_elements_val_ds = tf.data.experimental.cardinality(val_ds).numpy()
print (num_elements_val_ds)>>> <ConcatenateDataset shapes: ((None, 300, 300, 1), (None, 1)), types: (tf.float32, tf.float32)> <BatchDataset shapes: ((None, 300, 300, 1), (None, 1)), types: (tf.float32, tf.float32)>
66
16
我已经描述了 【预取】技术 以及它比 ImageDataGenerator 快多少。让我们加上这个—
autotune = tf.data.AUTOTUNE ### most important function for speed up training
train_data_batches = train_ds.cache().prefetch(buffer_size=autotune)
valid_data_batches = val_ds.cache().prefetch(buffer_size=autotune)
test_data_batches = test_dir.cache().prefetch(buffer_size=autotune)
我还将添加一个重缩放层和一些增强层,这些都将作为 lambda 层包含在模型中。让我们把它们定义如下—
from tensorflow.keras import layers
rescale_layer = tf.keras.Sequential([layers.experimental.preprocessing.Rescaling(1./255)])
data_augmentation = tf.keras.Sequential([
layers.experimental.preprocessing.RandomFlip(),
layers.experimental.preprocessing.RandomRotation(10),
layers.experimental.preprocessing.RandomZoom(0.1) ])
加权二元交叉熵损失;
使用加权 BCE 损失背后的想法是,由于我们有比“正常”更多的“肺炎”x 射线图像,该模型对它们的错误分类进行了加权。因此,我们改变了这种偏见,并试图迫使模型对正常和肺炎图像进行同等加权。我们根据每个类别的图像数量除以图像总数来计算频率项。这些权重随后用于构建定制加权 BCE 损失函数。下面的代码块是用于给定问题的一个例子
建立一个 DNN 模型,包括扩展:
在定义了适当的定制损失函数之后,我们剩下的是构建一个包括作为 lambda 层的重新缩放和增强的模型。对于给定的工作,我使用了 InceptionResNetV2 预训练模型,你可以在这里检查 Keras 模块。在 Kaggle 比赛中,我们不允许使用互联网,所以我需要下载预先训练的重量,这解释了 InceptionResNetV2 函数中的weights
参数。在将图像批次馈送到模型之前,重新缩放、标准化&增强都作为 lambda 层添加。让我们看看下面的代码块—
编译后,包括一些“回调”,我们准备好训练模型。为了评估模型对测试数据的性能,我们可以绘制混淆矩阵和 ROC 曲线。
y_pred = model.predict(test_data_batches)
true_categories = tf.concat([y for x, y in test_data_batches], axis=0)
让我们设置一个 0.75 的阈值来分配标签“1”和任何低于标签“0”的值。
y_pred_th = (y_pred > 0.75).astype(np.float32)from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_pred_th, true_categories)class_names = train_dir.class_namesplt.figure(figsize=(8,8))
plt.title('CM for threshold 0.75')
sns_hmp = sns.heatmap(cm, annot=True, xticklabels = [class_names[i] for i in range(len(class_names))],
yticklabels = [class_names[i] for i in range(len(class_names))], fmt="d")
fig = sns_hmp.get_figure()
上面的代码块导致了下面的混乱矩阵—
二元分类的混淆矩阵。(来源:作者笔记)
类似地,我们也可以绘制 ROC 曲线,结果如下所示—
ROC 曲线为‘正常’和‘肺炎’图像分类。(来源:作者笔记)
最终注释:
上面使用的所有代码都可以在我的 GitHub 上找到,你也可以查看 Kaggle 笔记本。所使用的数据集在许可知识共享下的 Kaggle 中可用,因此我们可以自由使用和调整。最后,总结一下,我们经历了一个包括类不平衡数据集的数据分析管道,并学会了有效地使用 TensorFlow 数据集。
保持坚强,干杯!
卡方统计和卡方分布
原文:https://towardsdatascience.com/chi-square-statistic-chi-squared-distribution-2499084b5da8?source=collection_archive---------28-----------------------
在本文中,我将解释卡方统计量及其在假设检验中的作用,在假设检验中,数据集具有理论值,需要用实际数据集进行验证
约翰·莫塞斯·鲍恩在 Unsplash 上拍摄的照片
卡方统计是一个描述理论假设数据和实际数据之间关系的数字。它通常被认为是用实际数据集验证理论数据集并以数字形式给出结果的数字或统计值。
卡方统计公式
卡方统计的公式如上所示。这里,观测值是具有实际值的实际观测数据集,预期值是具有理论值的预期数据集。
关于卡方统计值得注意的一点是,该值始终为正值,因为当我们拥有数据集并评估统计时,即使数据集中有正值也可能有负值,这些值也是平方的。这将总是产生一个正值。
同样,卡方统计具有近似的卡方分布。
卡方分布是由 P 值( P )和自由度( DF )分布和分隔的一组值。
卡方分布可用于检查极端值或大于该值的结果的概率。
在这种情况下,我们通常会考虑一个显著性水平,例如我们在这里考虑的 P =10% (0.1)。因此,当我们获得卡方统计值时,我们通过特定的自由度(DF)检查分布中的值。如果分布中卡方统计值的概率( P )为 10%(0.1)及以上,我们无法拒绝零假设,否则我们拒绝它。
下表中的 P 是 p 值,它基本上是我们得到统计值时在分布表中检查的概率。
DF 是自由度,它取决于数据集中值的数量。如果在预期和观察列的数据集中有 N=4 个值,这 4 个值将应用于卡方统计公式。但是,如果我们注意到,当数据集中有 N=4 个值,并且我们对这 N 个值应用特定的公式时,我们基本上只需要前 3 个值来预测第 4 个值。所以这里的 DF 会是 3。 DF =N-1=3
让我们考虑一个例子,其中我们想知道学生在课堂上的出席情况。假设我们一个班有 5 个学生。因此,N = 5。因此,我们要求班主任告诉我们该班学生的大致出勤率。老师给我们提供了这样的数据:
Expected(%) : [50, 70, 75, 82, 86]
但是,接下来我们会用存储的学生出勤的实际数据来验证老师给出的数据。我们得到这样的结果:
Observed(%) : [55, 65, 73, 82, 80]
现在,我们可以看到两个数据集之间存在差异。所以,如果我们要拒绝或者不能拒绝这个假设(预期(%)),我们就要检验这个假设。
为此,我们将考虑两种可能性:
1st Probability : The teacher's distribution is correct
2nd Probability : The teacher's distribution is incorrect
我们将以 10%(0.1)的显著性进行假设检验。
如果根据预期和观察计算的卡方统计值在特定自由度( DF )内具有 10%或以上的 P ,则我们不会拒绝老师的假设,否则我们将拒绝该假设。
现在我们将计算卡方统计量:
卡方统计公式
现在,我们将这个公式应用于两个数据集:
如上所述,我们得到卡方统计值 1.32。
我们有以下数据:
现在,我们将检查自由度 DF = 4 内卡方分布表中统计值 1.32 的 P 值( P )。
卡方分布(来源)
这里,在 DF = 4 的范围内,我们看到统计值 5.989 的概率或 P 值(P)为 0.2,即 20%。所以,任何小于 5.989 的值都有超过 20%的概率。我们的统计值是 1.32。所以这个值也会有超过 20%的概率,相当高于我们的显著性水平(10%)。
因此,我们将无法拒绝老师的假设(零假设)。
结论
在本文中,我借助一个例子解释了卡方统计量的概念。我解释了卡方统计和卡方分布如何通过假设检验帮助我们评估理论数据集值及其实际值。我很高兴听到你对这篇文章的评论。请随时联系我,在 Linkedin 或评论中给我发消息。
独立性卡方检验
原文:https://towardsdatascience.com/chi-square-test-for-independence-cf2f5057cc35?source=collection_archive---------22-----------------------
使用 pingouin 库实现卡方分析
图片来自 unsplash
简介
数据科学家有时需要检查一个分类变量是否与同一人群中的另一个分类变量相关。如果数据是连续的,人们可以简单地计算变量之间的相关性,并根据相关系数确定这些变量是否高度相关。卡方检验是对分类变量进行分析的工具。例如,我们可能想检查性别是否在心脏病中起作用,或者教育是否与婚姻状况有关。在这种情况下,卡方检验是正确的分析工具。
背景
为了进行卡方检验,我想简单回顾一下相关术语的背景。python 中的分析和输出解释需要理解这些术语。
P 值、置信区间和显著性水平
p 值是两个值之间的差异偶然存在的概率。如果 p =值很小,观察到的数据偶然出现的概率很小,因此我们得出结论,观察到的数据和预期的数据之间存在统计上的显著差异。
置信区间是测试结果百分比的范围。如果置信区间设定为 95%,这并不意味着我们对测试结果有 95%的把握。可以认为,如果我们重复测试 100 次,测试结果将在 100 次中有 95 次落入该范围内。通常,CI 在大多数情况下设置为 95%。
另一个名为显著性水平(alpha)的术语是当假设事实上为真时拒绝零假设的概率。大多数情况下通常设定为 5%。
卡方检验
卡方检验有几种类型。一种类型的卡方检验被称为拟合优度检验,它检查一个分类变量是否很好地符合总体数据。另一种类型的检验检查一个分类变量相对于另一个分类变量的独立性,这被称为独立性卡方检验。在本文中,我将通过检验卡方统计量和 p 值来检验一个分类变量是否与另一个分类变量相关。
用 python 实现
让我们导入心脏病的数据。它显示了来自几个人的心脏相关变量的数据,如收缩压和舒张压、糖尿病、身体质量指数、心率葡萄糖水平、吸烟习惯等。
心脏病数据集
Python 有来自scipy.stats
的chi2_contingency
模块,我们需要在那里提供列联表。列联表是两个分类变量之间关系的总结。如果我们只提供数据,有一个名为 pingouin 的模块可以提供列联表。
根据我们的数据,假设我们想要检查冠心病(CHD)是否与性别分布有关。使用 pingouin,代码只有一行。
使用 pingouin 获得卡方统计数据
chi2_independence 返回三个表。期望表是列联表,显示了初始数据中两个感兴趣的分类变量之间的关系。
为了分析预期数据,我们首先需要获得初始数据中不同性别的比率。我们的数据显示,第 0 组和第 1 组之间的比例为 2420:1820 = 1.329,为了成为冠心病的不良预测因素,冠心病各组之间的性别比例应该相似。
当我们取第 0 组和第 1 组之间的比率时,我们在期望表中得到不同性别之间相同的 1.329:1 比率。例如,十年期第 0 组的性别比率为 2052.42/1543.56,相当于 1.329(近似值),另一组也是如此。
零假设表明我们期望观察到的表中有相同的比率。我们需要通过卡方统计来验证零假设,卡方统计根据自由度和显著性水平与卡方表中的特定卡方值进行比较。上面的观察值表显示了数据中实际观察到的性别类别和冠心病之间的关系。如果我们从观察到的表中计算性别比例,我们得到 2118.5/1477.5 = 1.433 和 342.5/301.5 = 1.136,这与预期的比例不同。接下来,我们需要从 stats 表中找出测试统计量和 p 值。
Ch 平方统计量和 p 值
皮尔逊残差的卡方统计量是最常见的统计量。皮尔逊残差被定义为通过期望值的平方根归一化的观察值和期望值之间的差。
皮尔逊残差=(观察值-期望值)/(sqrt(期望值))
对于这个单一自由度和 5%的显著性水平,卡方统计的临界值是 3.841,测试统计是在 32.618 获得的,这要高得多。该统计是对观察数据偏离预期值的程度的度量。我们还观察到一个非常小的 p 值,它基本上提供了反对零假设的证据。p 值越小,观察到的差异只是偶然出现的可能性就越低。因此,在这种情况下,我们有强有力的证据来拒绝零假设,并声明观察到的差异是真实的。本质上,我们可以得出结论,性别是冠心病的一个很好的预测因素。
A/B 测试的扩展
卡方检验可视为简单 A/B 检验的扩展版本,在两组之间进行,以检查两组之间是否存在任何观察到的差异。一组称为对照组,另一组称为治疗组。有时我们感兴趣的是一次检查多个治疗,卡方检验提供了各组与对照组偏离程度的信息。比如查看翻新网页多个版本的点击量,我们实质上可以做两个以上的组,提供给不同的用户组。应急表应反映新版本网页以及初始页面的点击次数或最终购买次数。
结论
在本文中,我描述了卡方测试的背景,并展示了它在 python 中的实现。卡方检验是检查分类变量独立性的简单统计检验。当需要多重处理来检查时,我们需要超越简单的 A/B 检验,进行卡方检验。
Github 页面
参考:
- pingouin 文档
- 心脏病数据
卡方检验,用 Python
原文:https://towardsdatascience.com/chi-square-test-with-python-d8ba98117626?source=collection_archive---------3-----------------------
执行卡方检验的完全初学者指南(带代码!)
卡伦·艾姆斯利在 Unsplash 上的照片
在本文中,我将介绍卡方检验(χ2)的基本原理,卡方检验是一种统计方法,用于推断一个变量的分布或判断总体中两个变量之间是否存在关系。推论依赖于χ2 分布曲线,取决于自由度的数量。
图 1:不同自由度的卡方分布[1]
χ2 分布曲线是右偏的,随着自由度的增加,χ2 曲线将更接近正态分布。
答:独立性的χ2 检验
它用于确定总体中两个变量之间是否存在关系。在分析两个分类变量的调查结果时很有用。
- H₀:这两个分类变量有没有关系
H₁:这两个分类变量之间有一种关系 - χ2 独立性检验统计量的自由度:
d.f. = (# rows -1) *(#columns-1)
表 1: rxc 两个分类变量的列联表
- 如果 H₀为真,上表中值的每个单元格将包含理论或预期频率 Eᵢⱼ ,而不是每个单元格的观测值 Oᵢⱼ 。
图 2:预期频率的推导
- 检验统计:比较 Oᵢⱼ & Eᵢⱼ 之间的差异得出χ2 统计,自由度为[(r-1) x (c-1)],其中
超过 rxc 列联表中的所有单元格
下表是一项出口民调,显示了对两个分类变量的联合回应:18-29 岁、30-44 岁、45-64 岁和 65 岁以上人群,以及他们的政治倾向,即“保守”、“社会主义”和“其他”。在 5%的显著性水平上,年龄组和他们的政治倾向之间有关系吗?
表 2:投票后调查[2]
按照假设检验的五步过程:
H₀:的年龄组与他们的政治倾向是否独立,即没有关系
H₁:的年龄组与他们的政治倾向是否有依赖关系,即∃的 a 关系
α = 0.05
遵循χ2 独立性检验统计:
结论:我们有足够的证据表明,在 5%的显著性水平上,年龄组和他们的政治倾向之间存在关联。
B: χ2 拟合优度检验
它用于推断变量的分布。
- H₀:变量有指定的分布,正态
H₁:变量没有指定的分布,不正态 - χ2 拟合优度检验统计的自由度数量:
d.f. = (# categories -1) - 它将样品的观察频率 O 与预期频率 E 进行比较。
E =事件的概率*总样本量
下表显示了 2013 年德国联邦大选超过 4400 万人的投票结果。41.5%的德国人投票给基督教民主联盟(CDU)25.7%投给社会民主党其余 32.8%投给其他。
假设研究者采取随机抽样的方法,选取了 123 名傅柏林的学生进行调查。其中 57 人投票给 CDU,26 人投票给社民党,40 人投票给其他人。这些数字对应于观察到的频率。
表 3: 2013 年德国联邦大选[3]
按照假设检验的五步流程:
H₀:变量具有规定的分布,即观测频率和期望频率大致相等
H₁:变量不具有规定的分布,不正态
α = 0.05
遵循χ2 拟合优度检验统计量:
结论:我们没有足够的证据证明观察到的和预期的频率在 5%的显著性水平上不相等。
推荐阅读
https://levelup.gitconnected.com/how-to-perform-one-sample-hypothesis-tests-with-python-308eae8789fc https://levelup.gitconnected.com/two-sample-hypothesis-tests-with-python-43e1b8c52306
参考
[1]《卡方检验 SOGA 地球科学系》【在线】。可用:https://www . geo . fu-Berlin . de/en/v/soga/Basics-of-statistics/Hypothesis-Tests/Chi-Square-Tests/index . html
[2]《卡方独立性检验 SOGA 地球科学系》【在线】。可用:https://www . geo . fu-Berlin . de/en/v/soga/Basics-of-statistics/Hypothesis-Tests/Chi-Square-Tests/Chi-Square-Independence-Test/index . html
[3]《卡方拟合优度检验 SOGA 地球科学系》【在线】。可用:https://www . geo . fu-Berlin . de/en/v/soga/Basics-of-statistics/Hypothesis-Tests/Chi-Square-Tests/Chi-Square-good-of-Fit-Test/index . html
卡方检验,用于比较两个机器学习模型,并确定它们是否是随机的
原文:https://towardsdatascience.com/chi-squared-tests-to-compare-two-machine-learning-models-and-determine-whether-they-are-random-2a405fc55181?source=collection_archive---------5-----------------------
在评估机器学习模型时,除了预测准确性/测试分数之外,您还应该考虑其他因素
一个具有挑战性的分类问题将你吸引到了你的屏幕上。你已经连续几个小时敲击键盘,分析数据,调试代码,执行算法。你的努力发展成两个机器学习模型。但是在你把显示器摔下来喝一口凉水之前,还有最后一个麻烦。你必须评估模型。通常,评估不仅仅是计算测试准确度。您可能想探究多个模型的性能是否不同。如果有变化,它们在统计上是显著的,还是由于随机性?所以让我们一起寻找这些答案。如果您熟悉概率分布(正态分布、二项式分布和卡方分布)、假设检验、假阳性和假阴性,我们就可以开始了。
卡方分布(图片由作者提供)
1.单一模型的卡方检验
1.1 我的模型是随机猜测的吗?:(
假设你的分类问题是预测一个人是否患有 covid。你构建的第一个模型,M1,给出了以下结果。
M1 观察表(图片由作者提供)
从概率上讲,一个数据实例有 65%的可能性是正面的,否则有 35%的可能性是负面的。一个重要的问题是,这个模型比随机猜测更有效吗?随机猜测意味着预测类和实际类是相互独立的。从本质上讲,这样的模型不会从数据中学习到任何有价值的东西,而仅仅是做出猜测。根据独立概率定律,可以得出:
(图片由作者提供)
在卡方检验中,我们将观察值与期望值进行对比。M1 将 69 例标为阳性。现在,如果这是一个随机的猜测,我们可以预计 35%的情况是假阳性。为什么?因为有 35%的可能性测试数据实例是负面的。这个结果也可以通过稍微修改一下问题从上面的等式推导出来。您认为 100 个实例中有多少个是误报?在这种情况下,我们找到 P(预测=+实际= —)。p(预测=+)= 69/100 = 0.69。
(图片由作者提供)
如果 M1 是一个随机的猜测者,总数据实例的 25.15%可能被分类为假阳性。因此,假阳性的数量= 100 的 24.15% = 24.15。同样,我们可以找到一个随机猜测者的所有预期预测。
随机猜测者期望表(RM 表)(图片由作者提供)
在上面两张表上运行卡方独立性测试将验证 M1 是否是一个随机猜测者。它通过计算卡方统计来实现。好吧,那是什么?
卡方统计方程
在下一节中,我将证明上面的等式是卡方的。测试的其余部分与任何其他假设测试一样。
H0(零假设):M1 是一个随机的猜测者
H1(替代假设):M1 不是一个随机的猜测者
M1 表列出了观察值,而随机猜测表列出了期望值。换句话说,对于我们的零假设,我们期望 M1 产生 RM 表中给出的结果。
为了找到卡方随机变量的值,我们还需要 DOF(自由度)。它是数据表中可以自由变化的值的数量。在计算实际类别和预测类别的概率时,我们固定了四个数字——实际阳性和阴性的数量,以及预测阳性和阴性的数量。
(图片由作者提供)
如果你现在观察上表,你会意识到,如果我给你集合 A,B,C,D 中的任何一个值,你可以找到剩下的变量。因此,数据集中的两个变量/值可以自由变化,因此 DOF=1。
从卡方统计量方程中,我们可以发现检验统计量是:
1.2 详述卡方检验
在继续之前,我想解释一下卡方检验的数学原理。如果你不是数学迷,请随意跳过。
(图片由作者提供)
如果你还在这一节,我相信你一定很想知道为什么上面的项是卡方变量。让我们重新表述这个问题。我们在寻找 M1 是否是随机猜测的证据。为了做到这一点,我们假设这是一个随机猜测,并列出期望值。M1 表中的值是我们观察到的,我们使用卡方检验来检验这两组值。
随机猜测表(图片由作者提供)
好的,现在观察随机猜猜表。想想每一面,预测(+)和预测(-),就像硬币。例如,预测(+)是一个硬币,正面表示正,反面表示负。因此,如果您投掷预测(+)硬币,且正面朝上,则该数据实例被归类为真正。否则,如果它落在尾部,数据实例被分类为假阳性。这让你想起了一个特定的概率分布吗?
将 T 作为随机变量,描述真正的正面实例的数量(硬币类比的头部)。不遵循 p=0.65(正概率)和 n=69(总数据实例)的二项式分布吗?当然了。我假设你知道二项式分布可以近似为正态分布,只要 np 和 n(1-p)都超过 10。相应地,我们得到一个正态变量 z~N(0,1)
(图片由作者提供)
我们可以利用上面的术语得到
(图片由作者提供)
就这样,我们挖掘出了隐藏的卡方项。记住 Z 遵循卡方分布。因此,RHS 是卡方分布的。在第一项中,T 是真阳性的数量,我们观察到它是 58,np=69 乘以 0.65=44.85。同样,在第二项中,n-T 是误报的次数,等于 11,n(1-p)等于 24.15。用这些值替换变量。
(图片由作者提供)
你现在可以把预测的(-)当作另一枚硬币,重复这项繁重的工作。否则,相信我,当我说你的麻烦会产生以下结果:
(图片由作者提供)
给你。两个 Z 项构成卡方统计量。
1.3 计算
您可以用 python 运行下面的代码来进行剩余的计算。我会讨论结果。
import numpy as np
import pandas as pd
from scipy.stats import chi2_contingency
data=[[58,7],[11,24]] #Model M1 table
#Chi square statistic,pvalue,DOF,expected table
stat, p, dof, expected = chi2_contingency(data)
print('Chi-square statistic=',stat)
print('Pvalue=',p)
alpha=0.05
if p < alpha:
print('Not a random guesser')
else:
print('Model is a random guesser')
结果:
Chi-square statistic= 32.884319981094166
Pvalue= 9.780899116984747e-09
(图片由作者提供)
从结果中,您可以观察到卡方统计量非常高。因此,与 alpha (0.05)相比,我们的零假设成立的概率(p 值)是微不足道的。因此,我们可以得出结论,M1 不是一个随机的猜测者。但是,请注意,最终决定完全取决于 alpha 值。但是由于我们通常将α取为 0.05,我们可以对我们的发现有信心。
2.使用卡方检验比较两个模型
好了,我们已经评估完你做的第一个模型了。让我们对第二个模型进行一些测试。
(图片由作者提供)
你也可以为这个模型进行一个单独的测试——“它是一个随机的猜测者吗?”。虽然,从上面的值可以明显看出,M2 比 M1 更准确。因此,M2 不可能是一个随机的猜测者。但它真的胜过 M1 吗,或者这种微小的进步源于随机的机遇吗?为了找到答案,我们必须修改我们的方法。
M1/M2 的正确/不正确矩阵(图片由作者提供)
上表显示了 M1 和 M2 正确和错误预测的分布。(我任意取了这些值。对于真正的问题,您可以通过执行几行代码轻松找到它们。).M1 和 M2 做出相同的预测(正确/不正确)没有什么令人信服的。我们对它们的差异很好奇,所以我们必须留意一个模型正确分类而另一个模型不正确分类的数据字段(B 和 C)。
如果 M1 和 M2 表现相似,B 值和 C 值应该不会相差太多。在这种情况下,两个模型的正确和错误预测比例几乎相等,因此表明同质性。
现在,通过将 B 和 C 想象成一枚硬币的两面,我们可以进行卡方检验来确定这两个值是否不同。我们已经确定上表的自由度是 1。卡方统计为:
(图片由作者提供)
同样,不要急于想为什么上面是一个卡方变量。可以通过重复我们上一节所做的来证明。如果你愿意,你可以试试。这种区分两种模型的特殊方法更广为人知的是麦克内马检验。现在让我们进行测试并建立假设。
H0: M1 和 M2 是一样的
H1: M1 和 M2 不一样
import numpy as np
import pandas as pd
from statsmodels.stats.contingency_tables import mcnemar
data=[[77,5],[10,8]]
res = mcnemar(data, exact=False)
alpha=0.05
print('Chi-square statistic:',res.statistic)
print('Pvalue:',res.pvalue)
if res.pvalue < alpha:
print('Models are different')
else:
print('Models are same')Chi-square statistic: 1.0666666666666667
Pvalue: 0.30169958247834494
在这里,P 值超过α,所以我们不能丢弃 H0。因此,尽管 M2 似乎比 M1 表现更好,但表现的差异很可能是随机的。我们应该从结果中进行推断,以避免仅仅通过分析分类精度得出任何结论。
结束语
在本文中,我只讨论了两种类型的评估。有统计程序来评估多个问题的众多模型。ROC 曲线在判断众多机器学习算法时极其俏皮。我给你链接了一些资源,让你对上面的解释有一个更全面的回顾。
https://en.wikipedia.org/wiki/McNemar%27s_test
https://en . Wikipedia . org/wiki/Chi-squared _ distribution #简介
https://www.youtube.com/watch?v=80ffqpZdKiA
芝加哥闯红灯摄像机和交通安全
原文:https://towardsdatascience.com/chicago-red-light-cameras-and-traffic-safety-a6c5f08e5c4?source=collection_archive---------37-----------------------
闯红灯摄像头会减少交通事故吗?
照片由加比在 Unsplash 上拍摄
我最近收到了芝加哥市一张 100 美元的红灯罚单。和罚单一起的还有一个链接,是我的车在红灯右转时没有完全停下来的照片和视频。我成了可怕的芝加哥红灯摄影机的受害者。一个朋友告诉我,一项研究显示闯红灯的摄像头让十字路口变得更加危险。作为一名数据科学家,我很感兴趣。这在芝加哥听起来像是一个可以回答的问题,所以我建立了一个项目试图回答这个问题。
我还创建了一个网络应用程序来配合这个项目。有了它,你可以探索详细的芝加哥红灯摄像头路口和碰撞数据。(点击下图)
点击图片访问链接https://chicago-rlc.herokuapp.com/
芝加哥红灯执法
2003 年,芝加哥开始用两个摄像头强制执行闯红灯。从那时起,该计划已经发展到在芝加哥 150 多个十字路口安装 350 多个摄像头。
摄像头强制交叉路口在所有方向都有清晰的标记
该计划受到丑闻的冲击,包括:贿赂计划,腐败指控,涉嫌针对服务不足的社区,以及软件修补以增加收入。许多芝加哥人认为闯红灯的摄像机不过是创收者,是居民的隐形税收。该计划自启动以来已经产生了惊人的 7.5 亿美元,其中几个著名的路口每年罚款数百万美元。
该计划的起源和目的(如他们的网站上所说)是“通过减少交叉路口最危险的交通事故来提高芝加哥街道的安全性”。虽然所有的碰撞都有潜在的危险,但红灯摄像机的设计是为了减少角度(或“丁字”)碰撞,因为它们对那些涉及的人来说极其危险。随着人们遵守交通信号,严重的车祸和伤害会大大减少。”
摄像头会提高安全性吗?
2018 年在凯斯西大学进行了一项关于红灯相机安全的国家研究。使用休斯顿及其周围的红灯摄像机,得出的结论是,红灯摄像机减少了危险角度碰撞的数量,但也可能增加追尾和其他类型的事故,因此不会提高整体安全性。这项研究和其他研究指出,摄像头实际上改变了交通模式:司机倾向于更猛烈、更突然地刹车,导致不同类型的事故,但并没有减少总数。
我决定看看芝加哥的数据,看看能否对我的城市得出结论;闯红灯摄像头真的能改善交通安全吗?
我的数据
自 2017 年 9 月 1 日起,芝加哥所有警区都在全市范围内强制实施统一的车祸报告。超过 50 万起事故报告可在芝加哥数据门户获得,并且每天更新。详细的事故报告包括事故类型、事故是否发生在红灯路口,以及每起事故的纬度/经度。
https://data.cityofchicago.org/Transportation/Traffic-Crashes-Crashes-Dashboard/8tdq-a5dp
数据门户还包含每个摄像机的每日闯红灯摄像机违规,并包括路口的名称和纬度/经度位置。
https://data.cityofchicago.org/Transportation/Red-Light-Camera-Violations/spqx-js37
在过滤我的数据,只包括 2017 年 9 月至 2021 年 1 月之间发生的撞车事故后,我剩下了超过 60,000 起与交叉路口相关的事故,这些事故发生在芝加哥 3000 多个红灯交叉路口中的一个。
通过使用纬度/经度,我指定了发生在红灯摄像头十字路口中心 30 米内的事故。超过 8000 起事故被标记为闯红灯,发生在一个闯红灯摄像头强制控制的十字路口。这是该项目的主要数据集。
事故类型
如上所述,芝加哥正在寻求减少角(“丁字”)型事故。下面的图表是只用芝加哥的红灯路口生成的。角型事故占所有事故的 16%,但造成 37%的死亡和 31%的受伤。转弯事故(也可以通过闯红灯摄像机减少)是最多的,也是仅次于角度碰撞的第二大红灯伤亡原因。
没有死亡的碰撞类型未显示。
休斯顿的研究显示,当摄像头被移除时,追尾事故会增加,虽然数量很多,但导致的伤亡却较少。如果更危险的碰撞类型相应减少,追尾事故的增加对一个城市来说是可以接受的。
方法学
休斯顿的研究使用了一项自然实验,该实验发生在该市的一次选民公投中,当时红灯摄像机被拆除。移除摄像头前后的碰撞数据可以进行比较,看看摄像头的存在是否对事故有影响。
我试图在芝加哥做同样的事情。自 2017 年以来,少数摄像头被打开/关闭,或被移至其他路口。这些删除和添加创建了一个类似于休斯顿研究的小规模(7 个交叉点)自然实验。此外,伊利诺伊州众议院的一项法案目前正在立法中,以消除芝加哥所有的红灯摄像机,这将创造一个难以置信的机会,以更大的规模评估这个实验。
七个兴趣点
不幸的是,我只能查看自 2017 年 9 月以来(车祸数据可用时)一直活跃的红灯摄像头路口。在此期间,七个路口要么被添加到闯红灯摄像头违规数据,要么被删除。安装/卸载前后都有崩溃数据。
在这段时间内,七个十字路口同时处于开启和关闭状态:
['FOSTER AND NORTHWEST HIGHWAY' 'FULLERTON AND NARRAGANSETT'
'HALSTED AND 103RD' 'LAKE AND UPPER WACKER' 'MICHIGAN AND JACKSON'
'MICHIGAN AND ONTARIO' 'MILWAUKEE AND CENTRAL']
我建立了一个数据集,包含我的每个十字路口的每日事故数量,并使用这些十字路口最早和最新的违规日期将人群分为“关闭摄像头”和“打开摄像头”(实验组和对照组)。
第八个交叉路口(富勒顿/纳拉甘西特)可能已被删除,但未包括在以下结果中
Dataset from 7 intersections of interestCameras OFF:
Cumulative days: 1733
Total crashes off: 69Cameras ON:
Cumulative days: 6786
Total crashes: 134
纠正不平衡
数据集是不平衡的,主要集中在 2017 年末和 2018 年初。通常情况下,这不会是一个问题,但是通过我的研究,很明显一些十字路口有更多的撞车,受伤,甚至特殊类型的事故。我不希望一个单独的交叉点(可能有明显的偏差)压倒其他的。为了平衡数据集,我对每台相机的过度代表组进行了随机采样,因此每台相机的开机和关机天数相同。尽管低于预期的检验功效,但有足够的数据进行可靠的 t 检验,将这两个群体与以下结果进行比较。
Balanced dataset hypothesis testing: Null hypothesis: red light cameras have no effect on the number of crashes.alpha: 0.05
Power: 0.62n (cam on): 628 days
n (cam off): 628 daysmean (cam on): 0.03185 crash/day
mean (cam off): 0.04777 crash/day
Actual crashes with cams off: 30
Expected crashes with cams off: 20
Standard deviation: 4.40
z score: 2.27
P value: 0.0115REJECT the null hypothesis
当真实总体平均值为 0.032 时,有 1.2%的概率观察到样本平均值为 0.048。我们拒绝零假设,并接受另一个假设,即红灯摄像头的存在减少了这七个路口的事故数量。
这些结果与休斯顿的研究相反,休斯顿的研究并没有得出相机减少整体事故的结论。
附加测试结果
用同样的技术和平衡的人群,我们可以调查受伤的人数。
Balanced dataset hypothesis testing:Null hypothesis: red light cameras have no effect on the number of injuries.alpha: 0.05
Power: 0.99n (cam on): 628 days
n (cam off): 628 daysmean (cam on): 0.00159 injuries/day
mean (cam off): 0.01752 injuries/day
Actual injuries with cams off: 11
Expected crashes with cams off: 1.0
Standard deviation: 1.00
z score: 10.01
P value: 7.030e-24REJECT the null hypothesis
当真实总体平均值为 0.00159 时,观察到样本平均值为 0.01752 的概率极小。我们拒绝零假设,并接受另一个假设,即红灯摄像机的存在减少了这七个路口的受伤人数。
当执行相同的平衡方法和事故类型过滤时,结果是混杂的和不确定的。测试功率太小,无法确定倾斜事故是否减少,或追尾事故是否增加。然而,当红灯摄像机出现时,所有七个十字路口的所有类型的事故相同或更少。
这项研究的缺点
与 Case Western 的国家研究相比,这项研究在规模和范围上相对有限。他们的研究使用了近 10 倍多的十字路口,还使用了这里没有考虑的关于驾驶员决策、心理方面和全市安全计算的假设。我严格依赖现有的有限数据。当更多的数据可用时,也许是今年,这些数据可能足以对不同的事故类型和整体安全性进行越来越可靠的测试。
由于使用的摄像机数量如此有限,除了红灯的存在之外,还有其他因素可能影响了结果。潜在的偏差可能是:施工日期、交通模式变化、交叉路口改造或少数群体的一年中的采样时间。这同样可以通过额外的数据和交叉点来改善。
结论
对于所研究的十字路口,我们接受这样的假设,即闯红灯摄像机的存在减少了这些十字路口的事故和伤害数量。
这支持了芝加哥市安装摄像头以提高安全性的理由。
首席数据科学家担任指挥
原文:https://towardsdatascience.com/chief-data-scientist-as-a-conductor-e2fba60a74d3?source=collection_archive---------64-----------------------
如何成为您的数据团队的世界级领导者
阿林达姆·马汉塔在 Unsplash 上拍摄的照片
C hief 数据科学家通常是从一群有才华的数据科学家中招募的。虽然从天才到首席的转变听起来是一个小而合理的步骤,但角色非常不同。
数据科学家在一线解决问题。他们每天都在磨砺自己的技术、编码、解决问题和沟通技能。一些人渴望成为首席数据科学家。当他们最终得到这个职位时,他们惊讶于这个新角色的与众不同。
就我个人而言,我整天都在与不建立模型、学习新技术、研究新方法和尝试新方法作斗争,每天都是。我觉得我错过了,整个行业都在前进,而我却停滞不前。简单地说,我习惯于处理——很多!
人们认为这是从专家角色到经理角色的标准、简单的转变。我认为,事实并非如此。你如何努力成为数据科学领导者?您如何为数据科学团队、企业及其客户增加价值?
受音乐启发
我喜欢音乐。主要是爵士乐和古典音乐。当我听管弦乐队演奏时,我对音乐家们的技术技巧印象深刻;我同样对许多数据科学家的技术能力印象深刻。
但是我被一个乐队在一起演奏时发出的强大、庄严和壮观的声音迷住了。
这完全是指挥的功劳,他为观众编织了激动人心的体验。
回到数据科学世界
这对首席数据科学家有什么影响?我相信从世界级的指挥家身上可以学到两点。
- 他们如何指挥管弦乐队
- 他们如何保持在自己的岗位上不断进步
许多书都写了关于领导团队的内容,指挥/乐队的角色并不新鲜。维基百科上写着:
指挥的主要职责是以反映乐谱中特定指示的方式解释乐谱,设定节奏,确保合奏成员的正确进入,并在适当的时候“塑造”乐句。
这清楚地描述了执行。步伐。领导一个团队。
如果你不知道我在说什么,就看下面的视频:
来源:https://www . ted . com/talks/Benjamin _ Zander _ the _ transformative _ power _ of _ classic _ music?language=en
但是维基百科也提到了(有我的重点):
指挥充当他们指挥的管弦乐队或合唱团的向导。他们选择要表演的作品,研究他们的分数,他们可以对这些分数进行一定的调整(例如速度、发音、乐句、段落的重复),做出他们的诠释,将他们的视觉传达给表演者。
这都是关于后台,指挥家工作中“看不见”的部分。我们在祖宾·梅塔的跳跃或者伦纳德·伯恩斯坦的舞蹈中体验到这种“隐形”。但是幕后到底发生了什么呢?
除了开一辆像赫伯特·冯·卡拉扬那样的定制保时捷(!),指挥选择要演奏的作品——研究、调整、诠释。
这也是首席数据科学家应该做的。
首席数据科学家应尽最大努力:
- 通过广泛阅读、追随思想领袖和与专家交流来了解任何值得探索的事物,跟上数据世界的新趋势
- 通过深入了解业务需求和仔细研究数据的可能性,设计并执行最能支持其业务的数据战略
- 选择要运行的项目,并根据业务情况调整它们
- 解释结果同时忠实于业务问题
- 将数据愿景传达给数据团队和整个企业,观察哪些可行,哪些不可行,并在需要时进行干预
至关重要的是,首席数据科学家需要确保数据团队像一个世界知名的、协调的、合拍的、流畅的管弦乐队一样工作!知道什么时候让人和项目发光,什么时候保持势头,什么时候拉回来。
对于首席数据科学家来说,认为自己是一名指挥而不是一名经理是一种解放(也相当令人愉快)。而且,一个人仍然可以密切关注激情的领域,就像一个指挥家仍然是一个音乐家一样。过渡到主增生:'和'或非'或'。
美国指挥家(钢琴家兼作曲家)麦可·提尔森·汤玛斯很好地推测了首席数据指挥:
作为一名指挥家是一种混合职业,因为从根本上来说,它是一名教练、培训师、编辑、导演……我的中心格言之一是,指挥家试图做的一个主要部分是让一大群人就“现在”的实际位置达成一致。
所以,找到你团队的“现在”并记住:你做音乐不是为了娱乐自己,而是为了取悦你的听众。
一如既往,我无限感激 切尔西·威尔金森 耐心地将我的想法塑造成可出版的格式。
感谢阅读!
欢迎在评论中分享你的想法或观点。
跟我上 中领英 和 推特 。
中国的人工智能雄心及其重要性
原文:https://towardsdatascience.com/chinas-ai-ambitions-and-why-they-matter-a7075ba993dc?source=collection_archive---------24-----------------------
播客
Jeffrey Ding 谈中国的人工智能大发展
苹果 | 谷歌 | SPOTIFY | 其他
编者按:这一集是我们关于数据科学和机器学习新兴问题的播客系列的一部分,由 Jeremie Harris 主持。除了主持播客,Jeremie 还帮助运营一家名为sharpes minds的数据科学导师初创公司。
有很多理由关注中国的人工智能举措。有些纯粹是技术性的:中国公司正在产生越来越高质量的人工智能研究,它们准备在未来几年成为人工智能领域更重要的参与者。例如,华为最近整合了他们自己版本的 OpenAI 大规模 GPT-3 语言模型——这一壮举利用了大规模计算,推动了当前系统的极限,要求深入的工程和技术知识。
但是中国的人工智能雄心在地缘政治上对 T21 也很重要。为了构建强大的人工智能系统,你需要强大的计算能力。为了实现这一点,你需要大量的计算机芯片,而众所周知,这些芯片很难制造。但是目前世界上大多数的计算机芯片都是在民主的台湾制造的,中国声称台湾是自己的领土。你可以看到这种事情会多么迅速地导致国际紧张局势。
尽管如此,美中人工智能的故事不仅仅是竞争和脱钩的故事,也是合作的故事——或者至少,这是我今天的嘉宾,中国人工智能专家和斯坦福大学研究员杰弗里·丁提出的案例。除了研究中国人工智能生态系统作为他日常工作的一部分,Jeff 还出版了非常受欢迎的中国人工智能通讯,提供了一系列关于人工智能的中文文章的翻译和分析。杰夫承认人工智能研究的竞争动态,但认为只关注人工智能的争议性应用——如面部识别和军事应用——会导致我们忽略或淡化真正可以合作的领域,如语言翻译。
以下是我在对话中最喜欢的一些观点:
- 西方的一种普遍说法是,中国在人工智能方面领先是因为他们的中央集权结构:这种说法是,中国中央政府可以以分散化的西方方法无法做到的方式推动人工智能的采用、开发和投资。然而,杰夫指出,中国存在一种镜像叙事,在中国,美国被广泛视为精通人工智能的国家和经济的终极典范。最终,分散的美国模式和集中的中国模式有着非常不同的优势和劣势,虽然还不清楚哪种模式更优越,但杰夫认为,即使面对中国的竞争,美国也有机会保持其历史优势。
- 半导体制造是人工智能供应链中的一个关键瓶颈。制造半导体在技术上非常具有挑战性,需要昂贵的设备和训练有素的团队。今天,世界上大多数半导体都是由一家公司(TSMC)在台湾制造的——尽管美国和中国都在加速减少对 TSMC 和台湾的依赖,但这一过程将是缓慢的,很可能在几年内都不会完成。
- 杰夫看到了中美在人工智能领域建立信任和合作的许多潜在途径——他希望这些措施能够减少危险对抗和有害竞争动态的可能性。特别是,他强调机器翻译和人工智能安全是美中两国利益一致的两个重要领域。
- 尽管有这些合作的机会和缓和国际紧张局势的潜在价值,杰夫强调了承认中国正在发生的侵犯人权行为的重要性,其中包括国家支持的对各种少数群体的迫害,如维吾尔穆斯林、轮丨子丨功练习者和基督徒。在决定如何与中国人工智能研究人员合作时,Jeff 认为重要的是要考虑任何特定合作可能出现的技术的潜在应用,以确保它最终不会被用来支持不道德和不道德的活动。
你可以在 Twitter 上关注杰夫,或者我在这里。
章节:
- 0:00 介绍
- 5:50 地缘政治人工智能进步的正负点数
- 9:00 硬件方面
- 13:10 中国在半导体方面的努力
- 中国 22:30 激励结构
- 26:30 半导体行业的脱钩
- 32:20 基本经济论点
- 38:50 中国对人工智能校准的理解
- 42:40 美中关系与人工智能研究
- 48:20 总结
用 CBG 聚类法进行墨西哥薄饼店选址——第一部分
原文:https://towardsdatascience.com/chipotle-site-selection-using-cbg-clustering-part-1-7ab8b76b79c5?source=collection_archive---------32-----------------------
地理空间数据可以帮助预测 Chipotle 将在哪里开设新的位置吗?
Emile Mbunzama 在 Unsplash 上拍摄的照片
本文中的所有分析都是使用 SafeGraph CBG 数据和模式数据完成的。请引用 SafeGraph 作为本文的参考。
本文是围绕人口普查区块组数据聚类的两篇系列文章中的第一篇。这个项目的目的是使用 CBG 聚类来预测 Chipotle 未来的选址。选址是像 Chipotle 这样寻求扩张到新地点的大公司特许经营的主要兴趣点。在 2020 年和 2021 年之间,Chipotle 在美国开设了 100 多个新地点,使其成为测试这种选址算法的理想候选人。本文将重点介绍如何使用美国人口普查局和 SafeGraph 的邻域模式数据首先创建聚类,然后将这些聚类与 Chipotle 位置进行匹配。
本文将主要使用 Sklearn 的 K-Means 聚类算法来产生聚类,并将这些聚类归属于美国各地的 Chipotle 位置。可以通过安全图访问 Chipotle 地点数据和美国人口普查区块组数据。SafeGraph 是一家数据提供商,为数百家企业和类别提供 POI 数据。它向学术界免费提供数据。对于这个项目,我选择使用 SafeGraph Places 数据来运行我的分析。地点数据的模式可以在这里找到:模式信息
CBG 数据选择:选择哪种人口统计学?
照片由vini cius“amnx”Amano在 Unsplash 上拍摄
以下代码片段允许我们从 SafeGraph 包中访问美国人口普查数据的字段描述:
!pip install -q --upgrade git+https://github.com/SafeGraphInc/safegraph_pyfrom safegraph_py_functions import safegraph_py_functions as sgpyfrom safegraph_py_functions import cbg_functions as sgpy_cbg df = sgpy_cbg.get_cbg_field_descriptions()df['field_level_1'].value_counts()df = df[df['field_level_1'] == 'Estimate']df.to_csv('census.csv')
字段描述用于提供实际人口普查数据集中的要素。由于该数据集提供了 7500 多个要素,因此使用该表可以更直接、更简单地选择分析所需的要素。需要注意的是,为了便于分析,我们将字段描述表限制为仅包含“估计”记录,而不是同时包含“估计”和“置信度”记录。“估计”记录是提供数值的记录,这些数值可以与给定人口普查区块组中特定人口统计的计数相关联。这是我们希望在分析中使用的信息。字段描述表如下所示:
虽然这个表有点晦涩难懂,但它本质上可以归结为这个表中的每条记录都对应于实际人口普查数据中的一个唯一列。有了这些信息,现在很明显,选择正确的人口统计对于这个项目生成的聚类的准确性是非常重要的。出于这个项目的目的,我们选择考虑与年龄、性别、收入和其他因素(如房屋所有权和工作时间)相关的特征。总的来说,我们研究了聚类算法的大约 70 个特性,其代码如下所示:
census_cols = sgpy_cbg.get_census_columns(['B01001e1','B01001e10','B01001e11','B01001e12','B01001e13','B01001e14','B01001e15','B01001e16','B01001e17','B01001e18','B01001e19','B01001e20','B01001e21','B01001e22','B01001e23','B01001e24','B01001e25','B01001e27','B01001e28','B01001e29','B01001e30','B01001e31','B01001e32','B01001e33','B01001e34','B01001e35','B01001e36','B01001e37','B01001e38','B01001e39','B01001e40','B01001e41','B01001e42','B02001e1','B02001e10','B02001e2','B09019e2','B09019e20','B09019e21','B09019e22','B09019e23','B09019e24','B09019e25','B09019e26','B09019e3','B09019e4','B09019e5','B09019e6','B09019e7','B09019e8','B09019e9','B19001e1','B19001e10','B19001e11','B19001e12','B19001e13','B19001e14','B19001e15','B19001e16','B19001e17','B19001e2','B19001e3','B19001e4','B19001e5','B19001e6','B19001e7','B19001e8','B19001e9'], 2019)
这些生成的要素的数据框架如下所示:
稍微清理数据(将所有数值转换为浮点数)后,我们可以将该数据追加到 SafeGraph 邻域模式数据中,这将为我们提供与特定人口普查区块组的原始访问者数量、这些访问者到达相关 CBG 的距离以及在相关 CBG 停留的平均时间相关的列。在邻域模式数据中,可能有更多有用的列,但为了简单起见,我们只使用这些列
patterns = patterns[['area', 'raw_stop_counts', 'raw_device_counts', 'distance_from_home', 'distance_from_primary_daytime_location', 'median_dwell']]patterns['census_block_group'] = patterns['area']patterns = patterns.drop(['area'], axis = 1)df = df.merge(patterns, on = 'census_block_group')
这导致两个数据帧合并在一起:
CBG 聚类:最后一步
在 Unsplash 上翻滚 926 拍照
该过程的第一步是对创建的数据集使用 K-means 聚类,并根据提供的特征对记录进行聚类。为了这个实验的目的,我们选择创建 50 个集群。下面的代码片段执行此操作。请注意,将大量记录聚集到少数几个分类中会导致运行时间过长:
model = KMeans(init="random",n_clusters=50,n_init=1000,max_iter=400,random_state=42)model.fit(df[1:])pred = model.predict(df)
要查看跨集群 id 的记录分布,可以使用下面的代码片段:
freq = {}for item in pred: if (item in freq): freq[item] += 1 else: freq[item] = 1
为了可视化这个分布,我们可以使用下面的代码片段来绘制它:
plt.bar(freq.keys(), freq.values())
从这个分布中我们可以看到,记录甚至不是在聚类之间分布的,这表明每个记录的特征变化导致 k-means 算法独立地做出决定来分配聚类 ID。
结论:
从这篇文章中,我们能够看到 SafeGraph 提供的人口普查区块数据、邻里模式数据和每月模式数据的多功能性。使用这三个数据集,我们能够得出一组超过 70 个特征,我们认为这些特征对于 Chipotle 特许经营店未来选址过程至关重要。这些人口统计数据包括年龄、性别、收入和其他因素,如房屋所有权和工作时间。然后,我们使用邻域模式数据将这些特征与其他一些特征相关联,例如特定人口普查区块组的原始访问者数量、这些访问者到达相关 CBG 的距离以及在相关 CBG 逗留的平均时间。使用这些数据,我们将 CBG 信息加入到 2020 年 Chipotle 的月度模式数据中。这个完整的数据然后被用于将数据聚类成 50 个独特的聚类。对于本项目的下一步和下一篇文章,我们将重点关注使用 2021 Chipotle 数据作为地面实况,并查看哪些集群接收新位置。
提问?
我邀请你在 SafeGraph 社区的 #help 频道问他们,这是一个面向数据爱好者的免费 Slack 社区。获得支持、共享您的工作或与 GIS 社区中的其他人联系。通过 SafeGraph 社区,学者们可以免费访问美国、英国和加拿大 700 多万家企业的数据。
基于可视化选择最佳的 ML 模型
原文:https://towardsdatascience.com/choose-best-ml-model-based-on-visualization-ed6398ac3005?source=collection_archive---------14-----------------------
使用 Combo 比较机器学习模型
来源:作者
比较不同的机器学习模型是一项艰巨的任务,因为我们需要创建不同的模型,拟合它们,然后评估它们。编写数百行代码,然后使用不同的可视化工具进行评估是一个耗时的过程。
如果我告诉您,您可以节省创建不同模型和评估它们的所有时间和精力,会怎么样?Combo 是一个开源 Python 库,用于创建数据可视化,有助于轻松轻松地评估不同的机器学习。
在本文中,我们将探索 Combo 并使用它创建一些可视化效果。
让我们开始吧…
安装所需的库
我们将从使用 pip 安装来安装 Combo 开始。下面给出的命令将使用 pip 安装 Combo。
pip install combo
导入所需的库
在这一步中,我们将导入创建模型和可视化这些模型所需的所有库。
import os
import sys
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname("__file__"), '..')))
import warnings
warnings.filterwarnings("ignore")
import numpy as np
from numpy import percentile
import matplotlib.pyplot as plt
import matplotlib.font_manager# Import all models
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifierfrom combo.models.classifier_comb import SimpleClassifierAggregator
from combo.models.classifier_stacking import Stacking
from combo.models.classifier_dcs import DCS_LA
from combo.models.classifier_des import DES_LA
创建数据集
对于本文,我们将使用 2 个类创建自己的数据集。在下面给出的代码中,您可以看到我们如何创建数据集。
# Define the number of class 0 and class 1
n_samples = 300
class1_fraction = 0.5
clusters_separation = [3]# Compare given detectors under given settings
# Initialize the data
xx, yy = np.meshgrid(np.linspace(-7, 7, 100), np.linspace(-7, 7, 100))
n_class0 = int((1\. - class1_fraction) * n_samples)
n_class1 = int(class1_fraction * n_samples)
ground_truth = np.zeros(n_samples, dtype=int)
ground_truth[-n_class1:] = 1# Show the statics of the data
print('Number of Class 0: %i' % n_class0)
print('Number of Class 1: %i' % n_class1)
print('Ground truth shape is {shape}.\n'.format(shape=ground_truth.shape))
print(ground_truth, '\n')
数据集(来源:作者)
创建用于比较的模型
在这里,我们将创建我们将比较的所有模型,然后,我们使用 Combo 来可视化模型。
random_state = np.random.RandomState(42)classifiers = [LogisticRegression(), GaussianNB(), SVC(probability=True),
KNeighborsClassifier()]# Define some combination methods to be compared
classifiers = {'Logistic Regression': LogisticRegression(),
'Gaussian NB': GaussianNB(),
'Support Vector Machine': SVC(probability=True),
'k Nearst Neighbors': KNeighborsClassifier(),
'Simple Average': SimpleClassifierAggregator(base_estimators=classifiers,
method='average'),
'Simple Maximization': SimpleClassifierAggregator(
base_estimators=classifiers, method='maximization'),
'Stacking': Stacking(base_estimators=classifiers, shuffle_data=True),
'Stacking_RF': Stacking(base_estimators=classifiers, shuffle_data=True,
meta_clf=RandomForestClassifier(
random_state=random_state)),
'DCS_LA': DCS_LA(base_estimators=classifiers),
'DEC_LA': DES_LA(base_estimators=classifiers)
}# Show all classifiers
for i, clf in enumerate(classifiers.keys()):
print('Model', i + 1, clf)# Fit the models with the generated data and
# compare model performances
for i, offset in enumerate(clusters_separation):
np.random.seed(42)
# Data generation
X1 = 0.3 * np.random.randn(n_class0 // 2, 2) - offset
X2 = 0.3 * np.random.randn(n_class0 // 2, 2) + offset
X = np.r_[X1, X2]
# Add class 1
X = np.r_[X, np.random.uniform(low=-6, high=6, size=(n_class1, 2))]# Fit the model
plt.figure(figsize=(15, 12))
for i, (clf_name, clf) in enumerate(classifiers.items()):
print(i + 1, 'fitting', clf_name)
# fit the data and tag class 1clf.fit(X, ground_truth)
scores_pred = clf.predict_proba(X)[:, 1] * -1y_pred = clf.predict(X)
threshold = percentile(scores_pred, 100 * class1_fraction)
n_errors = (y_pred != ground_truth).sum()
# plot the levels lines and the points
Z = clf.predict_proba(np.c_[xx.ravel(), yy.ravel()])[:, 1] * -1
Z = Z.reshape(xx.shape)
subplot = plt.subplot(3, 4, i + 1)
subplot.contourf(xx, yy, Z, levels=np.linspace(Z.min(), threshold, 7),
cmap=plt.cm.Blues_r)
a = subplot.contour(xx, yy, Z, levels=[threshold],
linewidths=2, colors='red')
subplot.contourf(xx, yy, Z, levels=[threshold, Z.max()],
colors='orange')
b = subplot.scatter(X[:-n_class1, 0], X[:-n_class1, 1], c='white',
s=20, edgecolor='k')
c = subplot.scatter(X[-n_class1:, 0], X[-n_class1:, 1], c='black',
s=20, edgecolor='k')
subplot.axis('tight')
subplot.legend(
[a.collections[0], b, c],
['learned boundary', 'class 0', 'class 1'],
prop=matplotlib.font_manager.FontProperties(size=10),
loc='lower right')
subplot.set_xlabel("%d. %s (errors: %d)" % (i + 1, clf_name, n_errors))
subplot.set_xlim((-7, 7))
subplot.set_ylim((-7, 7))
plt.subplots_adjust(0.04, 0.1, 0.96, 0.94, 0.1, 0.26)
plt.suptitle("Model Combination")
# plt.savefig('compare_selected_classifiers.png', dpi=300)
plt.show()
模型比较(来源:作者)
在这里,您可以清楚地看到我们使用 Combo 创建的不同图表和绘图。继续尝试不同的数据集,创建不同的可视化效果,并让我知道您在回复部分的评论。
本文是与 Piyush Ingale 合作完成的。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时联系我在 hmix13@gmail.com 或我的 LinkedIn 简介 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。
小心选择你的词语
原文:https://towardsdatascience.com/choose-your-words-carefully-3c8dba5b47e6?source=collection_archive---------28-----------------------
你的沟通方式最多会让你看起来缺乏经验,最糟糕的是让你看起来不善于沟通
照片由西格蒙德在 Unsplash 拍摄
行话是有时间和地点的。这可能是一个很好的语言捷径,或者让你说的话更加具体。但是当和你没有工作关系的人交谈时,它很容易被过度使用。
迈克尔·里维拉·🇵🇭在 Unsplash 上的照片
我特别谈论的是使用特定模型(ResNet、GPT-3、BERT 等)、算法(SMOTE、ADASYNC、SHAP 等)或技术(协同过滤、变分自动编码器等)的名称。还有大数据技术的字母汤(催生了“口袋妖怪或大数据”的趣味游戏)。如果你发现自己在概念层面描述项目时经常使用这些术语,你可能无法很好地解释你的项目。
事实是,所有这些技术术语要么是 1)特定概念的快捷术语,在这种情况下,用一些额外的词语用通俗的术语来解释这个想法比用行话来解释更好,要么是 2)指特定的工具,人们可能熟悉也可能不熟悉,因此最好再次从概念上解释这个工具在做什么,而不是用名称来指代它。
当与非技术观众交谈时,这尤其令人震惊,但即使是与另一位数据科学家交谈时,总是使用技术术语也不是一个好主意。数据科学是一个拥有不同专业知识的巨大领域-有人可能是伟大的数据科学家,但对特定的深度学习术语、数据库技术或推荐引擎一无所知。
为什么我们要使用行话
数据科学的一大优势是人们来自不同的背景。这也产生了两个问题:
- 很多数据科学家患有冒名顶替综合症。看到人们对你经验之外的概念有如此深刻的了解,肯定会引发许多冒名顶替综合症,而数据科学家的丰富经验意味着你肯定会遇到在你知之甚少的领域有深刻知识的人。
- 用于思考和交流技术概念的语言的多样性。与计算机科学家或社会科学家相比,拥有物理学背景的人将利用他们的背景来思考问题。
这两个问题都导致了一个共同的问题:过度使用技术术语。
那些感觉自己像骗子的人,要么是因为对这个领域不熟悉,要么是因为普遍缺乏信心,会寻求技术术语的安慰,让他们听起来像是知道自己在说什么。这导致了“知情者”术语的出现。
在光谱的另一端是那些使用技术术语的人,因为他们来自一个概念如此普遍的背景,它已经渗透到他们如何看待世界。我记不清有多少次,一位有物理学背景的数据科学家试图用熵来解释一些东西。这对我来说很难理解——不是因为我不知道熵是什么,而是因为我不太会这样想。
过度使用专业术语表明你要么不明白自己在说什么,要么不知道如何表达。
换句话说,依赖技术术语的人经常这样做,要么是因为他们是掩盖缺乏更深入理解的拐杖,要么是因为他们没有能力以更容易理解的方式进行交流。当这些术语被用来让你听起来像个专家时,它们通常会产生相反的效果,让你听起来好像你真的不知道自己在说什么。
显然,当与和你“在同一战壕”的同事交谈时,这些都不相关——对于那些和你一起使用这些工具的人来说,技术术语可能是一种简单的速记。但在许多其他情况下,即使是在与其他技术数据科学人士交谈时,省略行话也是有意义的。
用更笼统的术语交谈往往显示出更深刻的理解。
Osman Yunus Bekcan 在 Unsplash 上拍摄的照片
用一个一般的概念而不是一个具体的概念来说话,不仅让你说的话更容易理解,还表明你理解了一个概念——如果你能不用捷径来表达它,你就必须理解。
不要谈论具体的技术、模块或技术,尽量使用更通用的术语。不要使用协同过滤,而是说明你在使用相似用户的偏好。而不是伯特/巴特/罗伯塔/GPT-2 或任何最新风格的自然语言处理模型,只是说一个预先训练的自然语言处理网络。不使用 ADASYN 或 SMOTE,而是使用一种过采样技术。了解概念的技术人员会询问细节——如果只告诉他们概念,那些不了解的人会更好地理解。
同样,尽量避免特定领域的术语。许多数据科学家都有数学或物理背景。对某些人来说,谈论熵可能是自然的,但对大部分人来说肯定不是。这个词是一个概念的捷径——用一些额外的词来表达这个概念。
沟通是一项至关重要的技能——培养它
数据科学家最重要的技能之一是与其他技术人员和非技术利益相关者沟通的能力。值得你花时间和精力去思考如何与人交流,并确保你在用一种平易近人、清晰明了的方式交流。
使用 Python 选择婴儿名字
原文:https://towardsdatascience.com/choosing-a-baby-name-using-python-5c842f1e1a2f?source=collection_archive---------25-----------------------
实践教程
使用 Python 中的语音翻译器来比较英语和西班牙语中名和姓的发音。
键盘上的 Elisa。图片作者。
给孩子起个名字并不像人们想象的那么简单,至少对我和我妻子来说不是。我们到处为我们的宝贝女儿寻找名字,我们挑选一些选项。然而,我开始怀疑我们是否找对了地方,是否有一种方法来衡量哪个名字最适合我们的女儿。所以,我找到了三个数据库,里面有来自西班牙语和英语国家的名字,分析了趋势和最常出现的名字,并写下了所有可能名字的列表。最后,我开发了一个工具,它使用国际音标https://en.wikipedia.org/wiki/International_Phonetic_Alphabet来转换名字,并通过返回一个分数来衡量一个名字与另一个名字和/或姓氏在英语和西班牙语中的发音有多好,以便更容易地为婴儿找到可能的名字。
⭐️
介绍
在怀孕的最后五个月,当我们期待我们的第一个女婴时,我们在不同的来源上寻找名字的选择,如具有流行婴儿名字的网站和书籍,具有国际名字的网站,要求朋友之间的推荐,甚至写下电影和电视剧角色的名字。经过几个月的名字搜索,2021 年 4 月初,我们列出了我们最喜欢的女婴名字。我妻子的选择是: Elisa 和 Macarena 。在我这边,我有一个更大的名单:艾莎阿曼达卡琳娜****吉娜和维多利亚**。**
然而,我们没有同意给孩子取个名字。所以,我开始思考如何为我们的宝宝选择最好的名字?我们喜欢的名字有多流行?有没有一种方法可以衡量一个人的名字和他的姓结合起来有多好?
数据库
第一步是寻找名字。在我们的例子中,因为我们住在墨西哥,我们对西班牙语的名字感兴趣;然而,我们也对来自英语国家的名字持开放态度。
对于西班牙语的名字,我找到了西班牙🇪🇸国家统计研究所的数据,其中有最受欢迎的 100 个名字(2002 年至 2019 年),以及频率等于 20 人或更多的名字(2019 年)。另一方面,对于英语国家,我找到了几个流行婴儿名字的数据库,一个来自美国🇺🇸,由社会保障局(1880–2019)发布;另一份来自加拿大🇨🇦的不列颠哥伦比亚省,由公元前的政府分享(1920–2019)。
电子设计自动化(Electronic Design Automation)
当比较西班牙、美国和加拿大的常用地名数据库时,可以观察到不同数据库中不同地名的数量差异很大。这些差异可能可以用数据库的结构来解释,因为年份的范围及其特征:
不同数据库的描述。图片作者。
每个数据库中每个名称出现次数的增长。图片作者。
虽然美国和加拿大的人均姓名增长率稳定在 0%左右,但西班牙的情况并非如此,这可能是因为西班牙的数据库仅包含 100 个最受欢迎的姓名,而美国和加拿大的数据则包含大量姓名。
我们最喜欢的名字的描述性分析
西班牙🇪🇸
西班牙数据库中我们最喜欢的名字的出现频率。图片作者。
在我们最喜欢的名字中,在西班牙的数据库上,我发现使用最多的名字是维多利亚**,有 5.96 万人,其次是伊莉莎,有 3.63 万人,玛卡丽娜1.44 万人,阿曼达1.29 万人,吉娜 2.3 万人,艾莎 2.0 万人,卡琳娜只有 1.9 万人**
在来自西班牙的数据库中,我们还可以找到 2019 年出现频率最高的复合名称。因此,寻找包含我们最喜欢的七个名字之一的复合名字,我们可以找到 243 个复合名字,包括维多利亚**,82 个带 elisa ,31 个带玛卡丽娜,28 个带阿曼达,10 个带吉娜,3 个带艾莎,2 个带卡琳娜。该数据库还包括所有单名和复名的平均年龄。**
包含我们最喜欢的名字的复合名字的频率和平均年龄。图片作者。
包含我们最喜欢的名字之一的复合词的单词云。图片作者。
最后,单词 cloud plot 以等于 75 次或更多次观察的频率呈现西班牙的复合名称。虽然节点代表每个名称,但箭头显示名称之间的连接顺序,箭头越暗,名称之间的连接越强。
例如,玛丽亚和维多利亚这两个名字以两种方式连接起来,形成了复合名玛丽亚维多利亚和维多利亚玛丽亚**。**
美国🇺🇸
在美国,我们注意到,虽然维多利亚一直很受欢迎,但吉娜在 60 年代末成为最受欢迎的名字,阿曼达在 80 年代成为最受欢迎的名字。伊莉莎这个名字一直处于我们最喜欢的名字的中间范围,每年大约有 500 次,而艾莎的受欢迎程度从 60 年代的大约 10 次增加到 1000 次最后,卡丽娜和马卡瑞娜这两个名字是美国记录中最不受欢迎的****
在美国数据库中,我们最喜欢的名字出现的频率。图片作者。
加拿大🇨🇦不列颠哥伦比亚省
这张图展示了加拿大不列颠哥伦比亚省每年新生儿的趋势,这些新生儿都有我们最喜欢的名字。在这种情况下,数据库只有我们选择的七个名字中的五个名字的信息:维多利亚、伊莉莎、阿曼达、吉娜和艾莎**。**
与美国的情节相似,这里我们发现维多利亚一直很受欢迎阿曼达在八九十年代成为最受欢迎的名字吉娜的受欢迎程度随着时间的推移而下降。最后,伊莉莎和艾莎这两个名字的记录都很低。
在不列颠哥伦比亚(加拿大)数据库中,我们最喜欢的名字出现的频率。图片作者。
使用国际音标给名字打分
这一分析的最后一项工作是构建一个工具,在这种情况下是 Python 中的一个类,它测量名与中间名和/或姓的结合程度。为此,我使用国际音标将这些名字转换成西班牙语和英语的音标。
对于英语转换,使用了[eng_to_ipa](https://pypi.org/project/eng-to-ipa/)
库。在下面的代码块中有一个如何使用它的例子:
# call the eng_to_ip library
import eng_to_ipa as ipa# transform a text from English to IPA
ipa.convert("Maria")
### outcome: 'mərˈiə'
在西班牙语的情况下,[epitran](https://pypi.org/project/epitran/)
库对于转换名称很有用,可以如下使用:
# call the epitran library
import epitran# select an ISO 639-3 code of the language
epi = epitran.Epitran('spa-Latn')# transform a text from selected language to IPA
epi.transliterate("Maria")
### outcome: 'maɾja'
在将姓名转换为其语音符号后,一个自定义函数查找两个给定字符串(姓名和/或姓氏)之间的辅音和辅音韵脚,并比较每个姓名的最后一个元音、最后两个元音、最后一个音节和首字母,从每个比较中返回一个布尔值。对于每一种语言,该函数通过对最后两个元音和最后一个音节的比较赋予更大的权重并对结果进行标准化来获得分数。作为一个例子,这是一个从两个名字的西班牙语比较中得到分数的公式。
获得分数的公式。图片作者。
为了得到总分,该函数只对英语和西班牙语的最终分数进行平均。
最后,对于包含两个以上字符串的全名,另一个自定义函数将每个字符串与全名的其他字符串进行比较,并对每种分数类型的数量进行平均,返回全名的三个最终结果:英语、西班牙语和总分。
例如,在姓名玛丽亚维多利亚史密斯中,该函数获取(1) 玛丽亚与维多利亚、( 2) 玛丽亚与史密斯以及(3) 维多利亚与史密斯之间的比较分数。
⭐️点击这里 查看定制 Python 类的更多细节,以及它们的函数,开发这些函数是为了通过比较名字的押韵来获得这些分数。
😅 有趣的事实: 当我终于在 2021 年 4 月中旬到达这个分析点时,我的妻子已经为我们的宝贝女儿选择了一个名字: elisa 。从这一点上来说,我可以选择是给宝宝取一个复合名字,还是只给她一个名字。
几十首《伊莉莎·库斯皮涅拉·马丁内斯》。图片作者。
在包括 elisa 和我们的姓 cuspinera 和 martinez 的复合女性名字中(这是因为在墨西哥和拉丁美洲我们使用两个姓),得分较高的第二个可能的名字是:aisa、akira、alisa、ariza、corisa、delisa、elfrida、elissa、elvina、elyria、elysia、erisa、isa、jazeera、lisa、liza、louisa、luisa、 macarena
如你所知,其中一个名字是 macarena 。所以,就像在电影盗梦空间中一样,我觉得我的妻子向我灌输了这个名字的想法,在与 elisa 结合的化合物名称的首选中,这个是我最喜欢的,主要是因为它结合了 macarena 和 cuspinera 的发音。实际上 macarena cuspinera 西班牙语 0.5 分,英语 0.6667 分。
最后,我们决定给我们的女儿取名为伊莉莎·马卡雷纳·库斯皮内拉·马丁内斯**,这个名字比伊莉莎·库斯皮内拉·马丁内斯的分数还要高。**
“elisa macarena cuspinera martinez”的分数。图片作者。
最终意见
给孩子取名字可能不像人们想象的那么简单。这个项目的目的是建立一个工具来衡量一个完整的名字听起来有多好,并给它打分,以便更容易地为婴儿找到可能的名字。在这种情况下,定制函数可以是构建更健壮的模型的起点,该模型将其他特征考虑为声音的和谐。
另一方面,作为一种工具,这种模型只是拼图的一部分,可以(也应该)用其他定性变量来补充,例如,姓名的含义、地区习俗、家庭传统、趋势、个人偏好和/或未来父母的其他想法。
选择特色商店:盛宴 vs Hopsworks
原文:https://towardsdatascience.com/choosing-a-feature-store-feast-vs-hopsworks-143bc8bd84c?source=collection_archive---------10-----------------------
FEAST 是唯一一个独立的开源特性商店,但是你也有其他的选择
来源:作者
通过要素存储,您可以跟踪用于训练模型的要素。他们是一个相对较新的概念,但他们越来越受欢迎。
功能商店解决什么问题?
如果您在没有特征存储的情况下训练模型,您的设置可能如下所示:
如果您的模型直接从数据存储中提取数据,通常会有令人讨厌的重复。来源:作者
每个模型都必须访问数据,并进行一些转换,将其转换为模型用于训练的特征。
在这个过程中有很多重复的东西——许多型号使用许多相同的功能。
这种重复是功能存储可以解决的一个问题。每个要素都可以在要素库中进行存储、版本化和组织。这种预先准备的数据可以很容易地用于训练未来的其他模型。因此,您将避免重复计算数据集。您用于训练模型的数据也将可用,并且整个训练管道将更容易重现。
要素存储打破了模型和数据之间的耦合,从而减少了重复。来源:作者
直到最近,特征商店还主要用于内部机器学习平台,如优步的米开朗基罗。如果您想在大公司之外使用功能商店,您必须从头开始构建自己的商店。幸运的是,开源社区已经在改变这种情况。但是选择仍然有限。具体来说,您可以:
- 使用**宴、**或
- 使用 **Hopsworks 功能商店、**或
- 在类似 DVC 的东西上面滚动你自己的。
当我们构建我们的参考机器学习架构时,我们评估了所有这些选项,并选择了盛宴。这里有一个详细的比较来解释为什么,并帮助您评估自己项目的其他选项。
需要特色店吗?
如果你计划让你的机器学习项目达到中等规模,那么我们认为你应该有一个功能商店。也就是说,许多项目没有一个。如果您还没有遇到功能存储所解决的任何问题(例如,无法跟踪哪些功能正在使用,复制您的模型训练代码,或者花费大量时间等待 ETL 作业一次又一次地完成对相同数据的重新处理),那么您可能还不需要功能存储。
在以下情况下,您可以考虑而不是使用功能库:
- 你只训练了很少一部分模型。
- 您仍在构建概念验证;
- 你的团队很小。
随着你扩大机器学习团队和模型的规模,如果你不使用功能商店,你可能会遇到越来越多的问题**。您可能会注意到的第一个问题是重复和相应的工作浪费。当版本控制在项目中首次变得重要时,一个常见的解决方案是保留所有特性的时间索引快照。这可能意味着存储大量的重复数据:例如,我们合作的一个团队保存了他们所有 Apache Parquet 文件的每日快照。这不仅导致大量存储空间的浪费,还意味着如果某个特性发生变化,每个文件中的每一列都必须手动进行回溯更新。**
你在寻找一个包罗万象的机器学习解决方案吗?
有许多竞争工具和平台将帮助你管理端到端的机器学习生命周期。如果你刚刚起步,还没有确定任何特定的平台或框架,你可以找到一个适合你的需求。例如,Hopsworks 是一个数据科学平台,包括一个功能存储和许多其他功能,如模型服务和笔记本。
相比之下,FEAST 更加专门化:它只提供与存储和管理特性相关的功能。您可以使用他们的 CLI 或 Python SDK 将 FEAST 插入您的基础架构。
盛宴 vs. Hopsworks 特色店
Hopsworks 功能商店是更大的 Hopsworks 数据科学平台的一个组件,而 FEAST 是一个独立的功能商店。
如果您已经在使用更大的 Hopsworks 数据科学平台或对此持开放态度,请使用 Hopsworks 功能商店。Hopsworks 统一了其他几个平台,并添加了自己的功能库和文件系统(它被称为 HopsFS,但与 Hopsworks 的功能库是分开的)。
Hopsworks 统一了 Kafka、Airflow 等其他几个机器学习工具。来源:作者
如果你想要更小更专业的东西,可以集成到你现有的平台中,那么使用 FEAST 。乍一看,FEAST 似乎涵盖了与 Hopsworks 相似的一系列功能,但是需要注意的是,像模型训练和服务这样的事情发生在 FEAST 平台之外,但是发生在 Hopsworks 之内。
Feast 比 Hopsworks 更专业,将模型训练和模型服务留给外部组件。来源:作者
特色商店受欢迎程度
功能商店是一个相对较新的概念,但像 FEAST 和 Hopsworks 这样的开源解决方案正迅速变得越来越受欢迎。两者相比,就 GitHub 明星而言,FEAST 更受欢迎,增长也更快。
Feast 是最流行的开源特性商店,也是发展最快的。来源:作者
2020 年 11 月,FEAST 的创造者加入了企业和专有机器学习平台 Tecton.ai。虽然当开源项目的创造者“出卖”给企业时,这通常是一个不好的迹象,但在这种情况下,泰克顿已经承诺成为 FEAST 的核心贡献者,并资助和改进开源平台,因此 FEAST 可能会从这一变化中受益。
霍普斯沃克斯和盛宴 vs. DVC
DVC 是另一个跟踪大型数据集不同版本的工具——如果你已经在使用 DVC,你还需要一个功能商店吗?
DVC 并不完全等同于功能库,尽管正确的版本控制可以帮助解决一些相同的问题。
总的来说,与 FEAST 或 Hopsworks 相比,DVC 是一个更低级的解决方案——它有效地存储大数据的版本。这可能包括原始数据、特征,甚至最终模型文件。
DVC 保留所有不同版本的数据、特征和模型。来源:作者
因为 DVC 不是专门作为一个功能商店建立的,它缺少你在 FEAST 和 Hopsworks 等平台上发现的许多功能,特别是当涉及到流处理时。如果你看一下**批处理,**使用类似 git 的模型进行版本控制是很有意义的,但是对于摄取实时数据的机器学习系统(例如,考虑实时流量的路由系统,或者必须在毫秒内决定是否阻止特定交易的欺诈检测系统),跟踪一切可能会更棘手。
像 FEAST 这样的平台支持 online 和 offline 功能商店,当时间更重要时使用更快的基于键值的商店,而更慢、更结构化的离线商店用于跟踪多年来的历史数据。虽然你当然可以在 DVC 上实现类似的东西,但与使用专门的特性库相比,这需要大量的定制工程工作。
你需要帮助建立你理想的机器学习基础设施吗?
我们喜欢帮助团队决定正确的机器学习基础设施,我们也很乐意帮助您找到最适合您的设置。给我们打电话,告诉我们你的想法。
[ 注册获取更多关于 MLOps 的深入文章,并了解 FEAST 如何融入我们的内部参考架构。]
为图像处理选择和定制损失函数
原文:https://towardsdatascience.com/choosing-and-customizing-loss-functions-for-image-processing-a0e4bf665b0a?source=collection_archive---------14-----------------------
图片来源: Unsplash
**想象一下:**你站在一座能见度很低的高山上,你的目标是找到通往山下的路。你将如何实现这一点?一个可能的方法是四处寻找路径,拒绝那些向上的路径,因为它们会花费你太多的时间和精力,却发现它们不会帮助你实现你的目标,同时分析和选择那些会让你到达山中较低位置的路径。然后你选择一条向下的路,你认为这条路会用最少的时间和精力让你到达底部。然后你沿着这条路走下去,这条路会把你带到一个新的点,让你做出新的选择,并继续重复这个过程,直到你到达底部。
这是机器学习(ML)算法在训练期间所做的事情。更具体地说,优化器在这个山区类比中粗略地描述了随机梯度下降 (SGD)优化,它不断尝试新的权重和偏差,直到它达到为模型找到最佳值以进行准确预测的目标。但是优化器如何知道它是否在尝试好的值,以及当它在训练数据中前进时结果是否朝着正确的方向发展呢?这就是 损失函数 的用武之地。
输入损失函数
损失函数在训练(优化)ML 模型时起着关键作用。它主要计算模型使用一组给定的值(即权重和偏差)进行预测的能力。计算的输出是损失或误差,这是模型使用一组参数值做出的预测与实际地面实况之间的差异。
例如,如果使用神经网络对血细胞医学图像执行图像分类,则在训练期间使用损失函数来衡量模型能够将输入像素与网络隐藏层中不同级别的特征相关联的程度,并最终为每个分类设置正确的概率。在血细胞图像的例子中,较早的层可以表示基本图案(例如,弧线、曲线、形状等。),而随后的层可以开始表示医务人员感兴趣的血细胞的更高级特征。在这里,损失函数的作用是帮助优化器正确预测这些不同级别的特征——从基本模式到最终的血细胞。
术语损失函数(有时称为误差函数)经常与成本函数互换使用。然而,一般认为前者计算单个训练样本的损失,而后者计算所有训练数据的平均损失。总体目标是在所有训练样本中找到最小化平均成本的参数值(即,将成本降低到某个可接受的小值)。
成本函数接受模型的所有参数,并将成本作为单个标量输出。该函数由模型的优化器使用,该优化器试图找到一组理想的参数来最小化成本(也称为最小化函数)。
正如我们将在这篇博客中看到的,有许多你可以使用的成本函数,你甚至可以自定义自己的成本函数。因此,为您的用例选择正确的损失函数与拥有好的数据标签一样重要,以便将主题专业知识应用到模型中。换句话说,两者对于反映拥有一个正确的模型意味着什么以及针对什么进行优化都是至关重要的。然后,模型本身(即 DNN 操作)或多或少可以被认为只是一个保存和学习信息的媒介。
常见损失函数
损失函数通常来源于不同的数学领域,如统计分析、信息论等。,因此采用各种方程以不同的方式计算损失。因此,每个损失函数都有其优点和缺点也就不足为奇了,选择合适的损失函数取决于许多因素,包括用例、数据类型、优化方法等。
损失函数一般分为两类:分类和回归损失。分类寻求从有限的一组类别中预测一个值,而回归的目标是基于许多参数预测一个连续的值。
以下是一些常见的损失函数,您可以在 PerceptiLabs 中找到:
分类损失函数:
- 二次方(又名均方差或 MSE):对预测值和实际值之间的平方差进行平均,重点关注误差的平均大小,而不考虑方向。
- 交叉熵(也称为对数损失):计算预测的类别概率和基于对数标度的真实值之间的差异。适用于对象检测。
- 加权交叉熵:通过将权重添加到数据中表示不足的某些方面(例如,某些对象类)(例如,对象出现在较少的数据样本中),提高交叉熵的准确性。适用于不平衡数据集(例如,当图像的背景过度表现某些对象,而前景中感兴趣的对象表现不足时)。
- DICE :计算 Dice 系数,该系数测量预测样本和实际样本之间的重叠,结果 1 表示完全重叠。对图像分割有用。
回归损失函数:
- 均方误差/二次损失/L2 损失:对预测值和实际值之间的平方差进行平均,关注误差的平均大小,而不考虑方向。
- 平均绝对误差,L1 损失(由感知实验室的回归组件使用):对预测值和实际值之间的绝对差值求和,并求平均值。
损失函数用于各种用例中。下表显示了可能应用这些和其他损失函数的常见图像处理用例:
图片来源:感知器
损益损失
在感知器中配置损失函数非常容易,只需在模型的训练组件中选择所需的损失函数:
图像来源:感知器
然后,感知器将根据需要更新组件的底层 TensorFlow 代码,以集成该损失函数。例如,以下代码片段显示了配置有二次 (MSE)损失函数和 SGD 优化器的训练组件的代码:
# Defining loss function
loss_tensor = tf.reduce_mean(tf.square(output_tensor - target_tensor))...optimizer = tf.compat.v1.train.GradientDescentOptimizer(learning_rate=0.001)layer_weight_tensors = {}
layer_bias_tensors = {}
layer_gradient_tensors = {}
for node in graph.inner_nodes:
...compute gradientsupdate_weights = optimizer.minimize(loss_tensor, global_step=global_step)
您也可以通过修改培训组件的代码来轻松定制损失函数。只需配置并创建一个不同的损失函数,并将其传递给 optimizer。例如,以下代码创建了一个交叉熵损失函数:
# Defining loss function
n_classes = output_tensor.get_shape().as_list()[-1]
flat_pred = tf.reshape(output_tensor, [-1, n_classes])
flat_labels = tf.reshape(target_tensor, [-1, n_classes])
loss_tensor = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=flat_labels, logits=flat_pred))...update_weights = optimizer.minimize(loss_tensor, global_step=global_step)
当您在感知器中训练模型时,统计窗口上的损耗选项卡会向您显示一个时期内的计算损耗和所有时期的平均损耗,并且随着模型的训练,这些会实时更新。
图像来源:感知器 Labs
因为目标是最小化损失,所以您会希望看到所有时期的损失图逐渐减小,这意味着模型的预测在匹配基础事实方面正在逐渐改进。查看该用户界面是使用感知器的好处之一,因为您可以快速查看培训是否朝着正确的方向发展,或者您是否应该停止培训并调整您的超参数、更改您的损失函数或切换优化器。
结论
损失函数在训练模型时起着关键作用,并且是优化器的重要组成部分。虽然感知器的用户界面使得选择一个损失函数成为一个小细节,但是对于一个给定的用例和模型架构,知道选择哪个损失函数确实是一件大事。
有关损耗函数的更多信息,请阅读以下文章,这些文章很好地解释了其中一些损耗函数:
- 交叉熵损失函数
- 回归——为什么是均方误差?
- 训练深度学习神经网络时如何选择损失函数
对于那些刚刚开始学习 ML 或者需要复习损失函数的人,一定要看看梯度下降,神经网络如何学习。这是一个伟大的 YouTube 视频系列的第二部分,解释了神经网络如何工作,这一集涵盖了梯度下降中损失函数的作用。
关于神经网络的介绍或复习,看看这个优秀的 YouTube 视频系列。
https://towards data science . com/common-loss-functions-in-machine-learning-46 af 0 ffc 4d 23
https://arxiv.org/ftp/arxiv/papers/2006/2006.01413.pdf
用 Plotly 和 Python 实践 Choropleth 地图
原文:https://towardsdatascience.com/choropleth-maps-in-practice-with-plotly-and-python-672a5eef3a19?source=collection_archive---------23-----------------------
图 1—汉尼斯·沃尔夫在 Unsplash 上的照片
在一堆关于 choropleth 映射的理论之后,让我们看看如何轻松地为新的用例改编代码。在本教程中,我们将可视化法国医院在 covid 疫情期间的病床占用率。
介绍
Choropleth 地图是那些整个地区都被颜色覆盖的地图。来源于古希腊语: Choros 意为“*地区”,和 Plethos 意为“众多”。*这篇文章旨在展示使用 Plotly Python 库从头实现一个是多么容易。我们将用 covid 疫情公开数据来做这件事,放大法国的区域。
在继续讲下去之前,我想让你知道这个故事是对前一个故事的补充。如果你想要更多的信息或者想知道 choropleth 地图和 GeoJSON 的基本原理是什么,我强烈推荐你从这个故事开始,然后回来了解更多的细节🙃
话虽如此,今天的目的是:
- 了解使用新数据和新地理区域实现新的 choropleth 地图是多么容易
- 即使这意味着一些重构,看看当你已经做过一次的时候,做起来有多容易
- 了解 2020 年 11 月法国第二次全国封锁
动手🦠 🇫🇷 🛏
以前,我们使用全球数据集,呈现全球范围内的结果。今天,为了展示这个过程的可扩展性,我们将放大一个特定的国家:法国。
那么我们需要什么来绘制这张地图呢?
- 具有要在不同地理区域进行比较的 KPI 的数据集
- 一个 GeoJSON 文件,用于覆盖地图上要着色的地理区域
- 在它们之间建立联系
根据要求,您还需要一个安装了以下两个库的 python 开发:pandas
、plotly
。在脚本开始时安装和导入😉
import pandas as pd
import plotly.express as px
1.数据集
数据集来自 opendatasoft 。今天,我们将观察一个不同的 KPI,而不是通常的统计已确认、已康复或已死亡的人数。我们将跟踪医院的病床占用率。事实上,这是一个非常重要的指标,法国政府在宣布地区或全国宵禁和封锁之前就考虑到了这一点。
因此,首先,下载数据集并将其作为数据帧加载。作为处理的第一步,让我们重命名列,以便于处理。
步骤 1:加载数据集
由于数据集随着时间的推移跟踪大量信息,我们必须选择日期。实际上,choropleth 地图是给定情况的快照。在本例中,我们将选择 2020 年 10 月 15 日。
步骤 2:从特定日期选择数据并进行基本预处理—2020 年 10 月 15 日
如果我们浏览一下数据,df_dt
数据帧如下所示:
图 2-预处理数据集概述
你可能已经注意到一些有趣的事情:
- 一个
color
列的创建。事实上,我们希望色阶的值有限。由于整个数据集中的占用率在 0%和 250%之间变化,我随意决定除以 25。这不是强制性的,但它是我喜欢使用的一种颜色标准化,颜色值在 0 到 10 之间。 - 一个
title
栏目的创立。我们将把它用于悬停数据。它结合了部门代码、部门名称和相关比率。 - 前两条线有不同的
dept
值,但相同的bed_occupancy_rate
,这似乎有点幸运。它不是。事实上,在法国,有 18 个大区,分成 101 个省。这里一条线代表一个部门,数据按地区汇总。顺便说一下,你可以看到 Creuse 和 Vienne 都位于新阿基坦。这解释了相同的百分比值! - 数据集中已指定 GeoJSON 要素!真幸运!我们不必自己去寻找地理界限。但作为参考,它们也可以在单独部门的地理数据集中找到。例如,作为前面所说的参考,如果我们想要在地图上绘制区域而不是部门,我们可以从该区域的地理数据集加载 GeoJSON。我们必须使用
code_region
列来建立链接。事实上,这里的代码是管理代码,非常可靠。有点像国家的 ISO-A2 或 ISO-A3 标准化。 - 在脚本的末尾有一个断言测试,这样我们就可以确定部门代码是惟一的,这对进一步的处理很重要。一个部门必须对应我们 GeoJSON 的一个区域,反之亦然。
2.GeoJSON 文件
为了绘制地图,我们需要一个 GeoJSON 文件。希望地理数据已经存在于数据集中,并且由于有了 RFC 7946 规范,它们几乎已经可以使用了。
然而,Plotly 在数字信息和地理信息之间建立联系所需的步骤是在每个 GeoJSON 要素的键中有一个id
值,它与我们数据集的特定列相关。为了确保链接正确,后一列必须包含唯一的值。在我们的例子中,我们将使用部门代码作为唯一值
正如我们所看到的,在geoshape
一栏中,我们有部分需要的信息。然后我们只需要用json.loads
函数将它转换成一个字典。事实上,默认情况下,当加载pd.read_csv
函数时,它被定义为一个字符串。
所以我们开始吧!让我们从数据中构建自定义 GeoJSON 文件。
步骤 3:构建 GeoJSON 文件
这里没有什么特别要提的,代码非常简单!
3.绘制地图
所以我们来了!最关键的部分!密谋!
为此,我们将使用plotly.express.choropleth_mapbox
功能。Mapbox 是一家与 Plotly 合作的公司,因此他们可以提供非常酷的功能,如我们今天探索的 choropleth 地图。对于大多数地图绘制,您需要一个身份验证令牌,但是对于基本的 choropleth 地图来说就不是这样了😃
对于这个情节,我们必须说明几件事:
- 使用哪个数据帧
- 要使用哪个 GeoJSON 文件
- 数据帧的哪一列与 GeoJSON 的
id
值相匹配 - **【可选】**用于绘图的色标
- **【可选】【但强烈推荐】**色阶的最大值有哪些?**还记得之前的正常化吗?**这里我会设置
max_color=10
(意思是bed_occupancy_rate=25*10=250(%)
)。然后,无论所选日期的df_dt
中包含什么值,颜色都不适合这些精确的数据,而是之前选择的最大值。深红色将始终对应于历史最大值,如果在某些情况下,全国一天的最大值为 10%,所有彩色区域将非常亮。它允许保持几天的一致性。 - **【可选】**使用哪一列作为 hoverbox 的主要信息。这里我们将使用我们构建的包含所有必要信息的
title
列。 - **【可选】**在悬停框中将哪一列显示为次要信息。在这里,我们将把它们全部隐藏起来。
- 要使用的地图框样式。其中一些是免费的,其他一些则需要认证令牌。这里我们就用
carto-positron
这个很清醒。它可能会将国家数据作为证据。 - 使用哪个地图框缩放。
1
显示整个世界。这里我们将使用4
,它非常适合这个国家的大小。为了展示美国,我们选择了3
。 - 地图的中心位置。这是一个反复的过程。如果你有一个精确的地方可以选择,你可以使用谷歌地图😉
步骤 4:绘制地图
注意,使用 plotly
layout
,我们可以定制我们的颜色栏和标题属性!
所以现在我们可以看到这个图形了。是不是很奇妙?从无到有,我们只用了 75 行 gists!伴随着很多的描述和评论。实际上,就代码而言,它可以容纳不到 30 行。
让我们现在分析我们的地图🤓
结果
我绘制了从 7 月到 11 月底不同日期的图。这是我们根据数字得出的结果。
图 3-7 月至 11 月法国各地区 COVID 床位占用率的变化
- 我们注意到,在 7 月,也就是第一次法国全国封锁结束后的两个月,医院获得了喘息的机会,不再受到 COVID 患者的攻击。
- 然后一直到 10 月初,情况还是挺稳定的。
- 月中旬,我们开始观察到第二波污染,到 11 月初,多个地区的情况变得危急。
- 这种情况一直持续到 11 月 27 日。希望,如果你每天绘制所有的数据,你会看到在这个日期,高峰已经过去,医院的运营越来越好。
现在我们更好地理解了为什么马克龙总统决定第二次封锁的当前地图!
结论
今天,我们已经看到了如何在一个特定的用例中使用 Python 高效地绘制 choropleth 地图。多亏了 Plotly 库,我们只用了不到 30 行代码就做到了。很有效率,不是吗?
在结果部分,我们看到了进化的一部分,但不能用最后的图片来说是否已经过了顶峰。一个很好的解决方法是动画我们的地图。为此,我向您推荐下面的故事,在这个故事中,您将学习如何使用 Plotly 跟踪 KPI。
此外,如果我们今天专注于地图创建,Plotly 还提供了一个名为 Dash 的框架,它允许在易于使用的应用程序中集成地块和地图。如果你希望通过 Heroku 发现如何嵌入你的 choropleth 地图并在互联网上免费部署,我建议你阅读这篇文章
最后,要发现更多关于 GeoJSON 的信息,并获得更多关于今天的代码的信息,我只能建议你去了解激发这个故事的主要故事。
https://medium.com/@thibaud.lamothe2/how-to-create-outstanding-custom-choropleth-maps-with-plotly-and-dash-49ac918a5f05
希望你喜欢,希望不久能见到你🤠
流失预测模型
原文:https://towardsdatascience.com/churn-prediction-model-8a3f669cc760?source=collection_archive---------1-----------------------
思考一个伴随我十年的用例
照片由德鲁·法威尔在 Unsplash 拍摄
不公司喜欢失去有价值的客户。一开始,一家公司通常专注于获得新客户,然后通过向现有客户提供额外产品或试图让他们更多地使用他们的产品来增长。
如果一切进展顺利,当公司规模足够大时,它也必须选择一种稍微更具防御性的策略,并专注于留住现有客户。尽管用户体验最好,但总会有一批客户不满意,决定离开。
然后,公司面临如何尽可能有效地防止这些(自愿)离职的问题。这就是客户流失模型和其他模型的作用。
什么是流失模型?
这是一个预测模型,在单个客户的层面上估计他们必须离开的倾向(或易感性)。对于任何给定时间的每个客户,它告诉我们未来失去他们的风险有多高。
从技术上讲,它是一个二元分类器,将客户分为两组(类)——离开的和不离开的。除了将他们分配到两个组中的一个之外,它通常会给我们客户属于该组的概率。
需要注意的是,这是属于离开的客户群的概率。因此,这是离开的倾向,而不是离开的可能性。然而,通过客户流失模型来估计概率是可能的。
有什么用?
通过了解哪些客户离开的风险最高,我们可以更好地确定救援工作的目标。例如,我们可以通过营销活动联系这些客户,提醒他们已经有一段时间没有购买我们的产品了,甚至可以为他们提供优惠。
除了知道目标客户,我们还可以使用流失模型来计算仍然值得的最大收益价格。例如,如果我们知道特定客户离开的估计概率是 10%,他们的年收入是 100 美元,那么未来年收入的期望值是 90 美元。因此,对于这个客户来说,一个通常将离开的可能性降低到 5%的报价(收入的预期值是 95 美元)将是值得的,只要它的成本不超过 5 美元。
我们需要什么样的客户流失模型?
像任何有监督的机器学习模型一样,流失模型需要带有响应(目标)和解释变量(特征)的训练数据。基于这些训练数据,模型学习如何最好地捕捉特征和目标之间的关系。
通常,这是历史数据,我们知道哪些客户最终离开了,哪些没有。那些离开的人有一个积极的目标(是的,他们离开了)。其他人有一个消极的目标(不,他们没有离开)。而特征描述了在结果未知的时间点上的客户。
一个恰当定义的目标至关重要。在许多情况下,这很简单(例如,取消最后一个产品),有时不那么简单(例如,最近三个月没有交易)。然而,可以将流失模型应用于契约性(例如,银行)和非契约性(例如,电子商店)客户关系。
特征包括可以帮助识别流失客户的任何数据。这通常包括社会人口数据、所拥有产品的数据、历史交易、客户-公司互动、电子商务行为等等。
同样重要的是,要小心我们希望提前多长时间估计离职倾向。换句话说,从我们通过可用功能查看客户到我们知道他们是否已经离开之间的时间有多长?如果时间太短,我们就没有太多时间做出任何反应。另一方面,如果它太长,模型将会不太准确和不及时。
这样的模型是什么样子的?
现代客户流失模型通常基于机器学习;具体来说,就是上面提到的二元分类算法。这些算法有很多,需要测试哪一个最适合特定的情况(特定的训练数据、数据量等)。).无论是使用逻辑回归等简单模型,还是更复杂的随机森林或 GBM,或者冒险进入神经网络,都需要注意以下两点。
- 分类器有多种性能指标。由于大多数公司的客户流失率都很低,所以只看客户流失模型的准确性是不够的。例如,如果客户流失率为 10%,并且所有客户的流失率模型都表示他们不会离开,那么它的准确率为 90%。但这并没有用。因此,除了其他因素之外,您还需要考虑敏感度(实际离开的客户中有多少被模型检测到)和精确度(由模型识别的客户中有多少实际离开)。
- 此外,建议不要将生成的模型用作黑盒。相反,试着去理解决策所依据的参数。这不仅可以揭示模型或数据中的缺陷,而且对产品和营销团队来说也是非常有用的信息。例如,如果我们知道绝对折扣金额对客户流失的影响小于相对折扣金额,我们可以利用这一点来创建更有效的活动和定价策略。
接下来呢?
一旦你准备好了客户流失模型,你需要把它融入到公司的日常运营中。这包括在持续的基础上监控、评估和更新它(无论是简单地重新训练它还是添加新功能)。
因此,您可以开始自动检测倾向于增加离职倾向的事件,并尽快做出响应。
外部数据顾问可以在这两方面帮助你。但是请注意,流失模型(甚至比其他数据项目更重要)需要有经验的人参与,并对公司和行业的具体情况有感觉。
这篇文章最初是用捷克语写的,发表在 Bizztreat 博客 上。
一如既往,我无限感激 切尔西·威尔金森 耐心地将我的想法塑造成可出版的格式。
感谢阅读!
欢迎在评论中分享你的想法或观点。
跟我上 中领英 和 推特 。
Python 中的 CI/CD 示例
原文:https://towardsdatascience.com/ci-cd-by-example-in-python-46f1533cb09d?source=collection_archive---------5-----------------------
入门
用 Python 简单演示了 CI/CD,带有诗歌和预提交挂钩
由:爱德华·克鲁格和道格拉斯·富兰克林
昆腾·德格拉夫在 Unsplash 上拍摄的照片
我们将通过 Python 中的一个例子,将静态分析作为持续集成和持续交付(CI/CD)中的一个步骤。
CI/CD 管道允许快速和自动化的代码部署。他们尽可能多地自动化开发过程。CI/CD 管道可能包括格式化、强制执行良好的风格,以及提醒开发人员注意错误和运行测试。他们确保代码可以集成到代码库中,并最终将代码交付到产品中。
一些 CI/CD 任务可以通过静态分析来完成。静态分析通常通过预提交挂钩来完成。
什么是静态分析?
静态分析是一种确保代码质量的方法,它在不执行代码的情况下检查代码。静态分析工具的一些例子是格式化器、linters 和静态漏洞分析器。
格式化器自动对代码进行样式化,以提高可读性和一致性。他们主要是在空白区域进行修改;它们不会修改代码的执行方式。
作者:musicmoon@rogers.com
Linters 类似于书面文档的拼写检查器。他们寻找代码中的缺陷和错误。它们移除“无用的东西”,因此得名,比如未使用的导入和变量。Linters 也可以检测一些错误。例如,如果一个变量被使用但从未被定义,linter 将发出一个警告。Linters 还提供了风格和最佳实践的建议。
如果您使用的软件包版本存在已知的安全漏洞,静态漏洞分析工具会向您发出警告。这可以防止事后想起与安全相关的问题。例如,当 GitHub 警告您您的requirements.txt
包含一个已知安全漏洞的依赖项时。静态漏洞分析警告来自 CVE,一个致力于追踪这些漏洞的网站和公司。
Github 静态漏洞分析警报
静态分析工具有很多好处;一个是在 bug 发布到产品之前发现它们。静态分析的一个优点是它不需要执行你的代码,使得这个过程很快。
实现静态分析工具给开发人员带来如此小的开销,没有理由 不 使用它们。
静态分析可以很容易地用预提交钩子实现和完成。
什么是预提交挂钩?
预提交钩子是 Git 钩子的一种。Git-hooks 在 Git 存储库中出现命令时触发——比如提交或推送。当一个git commit
被执行时,一个“预提交钩子”运行。
预提交挂钩通常用于运行静态分析,因此代码在提交前会被链接和格式化。预提交挂钩可用于持续集成,为部署准备代码,帮助构建过程、依赖管理和测试。使用预提交钩子进行测试有好处也有坏处。好的一面是你永远不会得到测试失败的代码。不利的一面是,您可能会接受代码未能通过正在进行的工作的一些测试。大多数人不会将测试作为预提交挂钩,这些更高级的挂钩超出了本文的范围。
我们的 CI/CD 渠道
照片由 Florian wchter 在 Unsplash 上拍摄
我们在下面的存储库中使用了一个非常简单的“CI/CD 管道”。我们的预提交钩子做一些静态分析。你可以在.pre-commit-config.yaml
里观察它们。我们的定制预提交钩子create-requirements
确保我们的requirements.txt
与我们的诗歌 toml 和poety.lock
同步,也就是我们的本地虚拟环境。
https://github.com/edkrueger/poetry-template
这自动更新到requirements.txt
,所以我们需要更新的只是诗歌 toml。如果我们不能更新我们的requirements.txt
,任何改变或依赖都会导致我们的改变不出现,或者在最坏的情况下,使我们的应用崩溃。
这个定制钩子作为一个连续的交付工具,特别是因为我们已经从我们的 Github 主分支启用了自动部署。它的目的是在我们部署之前自动更新我们的requirements.txt
,以便 Heroku 可以从这个文件构建。
关于这个定制钩子或者如何用 Bash 编写自己的钩子的更多信息,请阅读下面的内容:
在某些情况下,应用程序崩溃几分钟可能会对企业、开发人员的声誉或两者都造成灾难性的影响。如果你的应用程序是一个简单的内部仪表盘来衡量 KPI,而你的老板决定在你破坏它时检查它的性能,这不是一个好的外观。对于面向客户的应用程序,崩溃的时间意味着失去客户和收入。
这些情况旨在强调使用简单工具来防止此类事情发生的重要性。有了良好的 CI/CD 管道,大多数错误都可以在投入生产之前被发现。
此外,虽然客户和老板可能不关心代码如何工作,但开发人员关心。这是使用静态分析工具和 CI/CD 管道的另一个原因。如果你的代码写得很差,它将很难测试和扩展。随着时间的推移,这些变化,无论植入得好或不好,都会或多或少地导致技术债务。
静态分析、CI/CD 和 Heroku 部署
如下图所示,我们选择了“启用自动部署”来开发我们的应用程序。通过在 Heroku 上选择这个选项,当新代码被推送到我们的 Git 存储库时,它会不断地被部署到我们的应用程序中。这意味着对主分支的每次推送都是对生产的推送。
正如按钮上方的警告所示,这就是为什么设置持续集成“服务”很重要。对我们来说,这个服务是我们的林挺和格式化预提交钩子以及我们的定制钩子,确保我们的requirements.txt
是最新的。
通过 Github 分支的自动部署实现持续交付
我们的库的pre-commit-config.yaml
、create-requirements
的 bash 代码以及在 Heroku 上实现自动部署,一起代表了我们简单的 CI/CD 管道。
这三个部分共同确保我们的代码被正确地格式化和标记,并且我们不会因为推送库requirements.txt
文件不支持的更改而使我们的应用崩溃。
结论
开发人员没有理由不使用简单的静态分析工具作为预提交挂钩就将代码推送到 GitHub。这有助于确保您的代码是干净的,有更少的错误,几乎没有开销。从事更重要的产品代码库的有先见之明的开发人员几乎总是使用 CI/CD 管道来自动化他们代码变更的林挺、格式化、测试和集成/交付。
从寻找工作的自学开发人员到在 GitHub 上发表作品的编程学者,一直到职业软件工程师,这些都是确保你不犯容易错误的重要工具。所以pip intstall pre-commit
和检查他们的文档和钩子开始吧!
如果配置太多,那就不要!使用 Ed 的模板回购。点击 GitHub 上的绿色按钮开始(见下图)。
使用此模板
CIFAR-100:图像识别任务预处理
原文:https://towardsdatascience.com/cifar-100-pre-processing-for-image-recognition-task-68015b43d658?source=collection_archive---------9-----------------------
常用图像数据集(CIFAR-100)的预处理或数据准备
在 Unsplash 上由 Bacila 拍摄的照片
图像识别对人类来说是一项简单的任务,因为我们很容易区分不同的特征。不知何故,我们的大脑在不知不觉中接受了不同或相似类型图像的训练,这些图像帮助我们在不投入太多精力的情况下区分特征(图像)。例如,在见过几只猫之后,我们几乎可以认出生活中遇到的每一种不同类型的猫。🐱然而,机器需要大量的特征提取训练,由于高计算成本、内存需求和处理能力,这成为一个挑战。
在本文中,我们将讨论这样一个用例的预处理。因此,让我们更深入地了解如何预处理图像数据集来构建卷积神经网络模型。🏊🏼
注:
- *我会尽量把大部分概念讲清楚,但是,本文假设对卷积神经网络(CNN)有一个基本的了解。*📖
- 我用 jupyter 笔记本来写我的代码。
卷积神经网络 (CNN) 是一类常用于分析图像的深度神经网络。可以构建卷积神经网络模型,以正确识别对象的彩色图像并将其分类到 CIFAR-100 数据集的 100 个可用类别之一。
那么,我们开始吧。🏃🏻
CIFAR-100 是什么?🤔
CIFAR-100 是 8000 万微小图像数据集的标记子集,其中 CIFAR 代表加拿大高级研究所。这些图片是由亚历克斯·克里热夫斯基、维诺德·奈尔和杰弗里·辛顿收集的。该数据集由 32 × 32 像素的 60000 幅彩色图像(50000 幅训练和 10000 幅测试)组成,分为 100 个类,分为 20 个超类。每个图像都有一个细标签(类)和一个粗标签(超类)。
如何获得 CIFAR-100 数据集?🙋
这个数据集的 Python 版本可以从多伦多计算机科学大学的网站上下载。下载的文件是使用 cPickle 生成的 Python 腌制对象。现在不要担心这个。我们将一起完成使用该数据集的每个步骤。
如何加载这个数据集?🚛
从网站下载数据集后,我们需要将它加载到我们的 jupyter 笔记本中。从网站上获取的文件都是 Python 腌制的对象。解压缩后的文件夹结构如下所示:
作者图片
我们可以看到,我们有单独的培训和测试文件,以及一个元文件。
Python Pickle 或 cPickle 模块可以用来序列化或反序列化 Python 中的对象。在这里,我用泡菜。Pickle 的 load()方法可以用来读取这些文件并分析它们的结构。阅读这篇了解更多关于腌制的知识。
Pickle 需要二进制数据,因此我们将以‘Rb’的形式打开文件,并使用 pickle load()方法和‘latin1’编码加载它。
让我们首先导入我们将在预处理中使用的库。
**import** pickle
**import** pandas **as** pd
**import** numpy **as** np
**import** matplotlib.pyplot **as** **plt**
**from** pylab **import** rcParams
%matplotlib inline
**import** keras **from** keras.utils **import** to_categorical
下面是读取这些文件的代码。
*#function to read files present in the Python version of the dataset*
**def** unpickle(file):
**with** open(file, 'rb') **as** fo:
myDict = pickle.load(fo, encoding='latin1')
**return** myDict
阅读这个就知道为什么我们大多使用‘latin1’作为编码。
现在让我们加载我们的训练集。
trainData = unpickle('train')#type of items in each file
**for** item **in** trainData:
**print**(item, type(trainData[item]))
输出如下所示:
filenames <class 'list'>
batch_label <class 'str'>
fine_labels <class 'list'>
coarse_labels <class 'list'>
data <class 'numpy.ndarray'>
培训文件中有上述项目。coarse_labels 和 fine_labels 是图像的标签(分别为 20、100),数据文件具有 NumPy 数组形式的图像数据,filenames 是说明文件名的列表,batch_label 是批次的标签。
让我们检查数据集的长度。
**print**(**len**(trainData['data']))
**print**(**len**(trainData['data'][0]))
输出如下所示:
50000
3072
因此,训练数据集中有 50,000 个图像,每个图像都是 3 通道 32 × 32 像素图像(32 × 32 × 3 = 3072)。
让我们来看看独特的精美标签。
**print**(**np.unique**(trainData['fine_labels']))
输出如下所示:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99]
因此,从 0 到 99 的图像有 100 个不同的精细标签。
现在让我们来看看独特的粗标签。
**print**(**np.unique**(trainData['coarse_labels']))
输出如下所示:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
因此,从 0 到 19 的图像有 20 个不同的粗略标签。
让我们检查一下 batch_label 文件中有什么。
**print**(trainData['batch_label'])
输出如下所示:
training batch 1 of 1
这里我们只有一个批处理,所以 batch_label 是一个字符串。
由于我们已经完成了对训练数据集中除数据文件本身以外的不同文件的研究,所以让我们首先解除对测试数据集和元数据文件的检查。
testData = **unpickle**('test')metaData = **unpickle**('meta')#metaData
**print**("Fine labels:", metaData['fine_label_names'], "\n")
**print**("Coarse labels:", metaData['coarse_label_names'])
元文件有一个精细标签和粗糙标签的字典。为了清楚起见,我将它们分开打印。这里是输出。
Fine labels: ['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm'] Coarse labels: ['aquatic_mammals', 'fish', 'flowers', 'food_containers', 'fruit_and_vegetables', 'household_electrical_devices', 'household_furniture', 'insects', 'large_carnivores', 'large_man-made_outdoor_things', 'large_natural_outdoor_scenes', 'large_omnivores_and_herbivores', 'medium_mammals', 'non-insect_invertebrates', 'people', 'reptiles', 'small_mammals', 'trees', 'vehicles_1', 'vehicles_2']
我们的任务将是识别图像,并为它们提供良好的标签。
现在让我们使用标签创建数据帧,这将有助于我们的可视化。
*#storing coarse labels along with its number code in a dataframe*
category = **pd.DataFrame**(metaData['coarse_label_names'], columns=['SuperClass'])*#storing fine labels along with its number code in a dataframe*
subCategory = **pd.DataFrame**(metaData['fine_label_names'], columns=['SubClass'])**print**(category)
**print**(subCategory)
两个数据帧的一瞥:
作者图片
作者图片
现在让我们看看我们的数据。
X_train = trainData['data']
X_train
输出是一个 NumPy 数组。
array([[255, 255, 255, ..., 10, 59, 79],
[255, 253, 253, ..., 253, 253, 255],
[250, 248, 247, ..., 194, 207, 228],
...,
[248, 240, 236, ..., 180, 174, 205],
[156, 151, 151, ..., 114, 107, 126],
[ 31, 30, 31, ..., 72, 69, 67]], dtype=uint8)
为了执行图像识别和分类的任务,必须建立卷积神经网络,该网络需要 4D 阵列作为输入。因此,必须对数据进行转换,以获得该形状。
例如,训练数据集有 50000 个形状为(50000,3072)的图像,因此我们需要使用 NumPy 数组的整形和转置操作来转换这些图像,以获得以下形状:
(实例数×宽×高×深)
宽度、高度和深度是图像的尺寸,其中深度只是图像中颜色通道的数量,在我们的例子中是 3,因为图像是 RGB。下图说明了卷积神经网络模型的 4D 输入形式。
作者图片
让我们为这种图像转换编写代码。
*#4D array input for building the CNN model using Keras*
X_train = X_train.**reshape**(**len**(X_train),3,32,32).**transpose**(0,2,3,1)
*#X_train*
我们现在已经完成了转型。让我们创建可视化来看这些图像。
可视化:
*#generating a random number to display a random image from the dataset along with the label's number and name*#setting the figure size
**rcParams**['figure.figsize'] = 2,2#generating a random number
imageId = **np.random.randint**(0, **len**(X_train))#showing the image at that id
**plt**.**imshow**(X_train[imageId])#setting display off for the image
**plt.axis**('off')#displaying the image id
**print**("Image number selected : **{}**".**format**(imageId))#displaying the shape of the image **print**("Shape of image : **{}**".**format**(X_train[imageId].**shape**))#displaying the category number **print**("Image category number: **{}**".**format**(trainData['coarse_labels'][imageId]))#displaying the category name
**print**("Image category name: **{}**".format(category.**iloc**[trainData['coarse_labels'][imageId]][0].**capitalize**()))#displaying the subcategory number
**print**("Image subcategory number: **{}**".**format**(trainData['fine_labels'][imageId]))#displaying the subcategory name
**print**("Image subcategory name: **{}**".format(subCategory.**iloc**[trainData['fine_labels'][imageId]][0].**capitalize**()))
输出如下所示:
作者图片
让我们展示更多的图像。
*#16 random images to display at a time along with their true labels*#setting the figure size
**rcParams**['figure.figsize'] = 8,8#number of columns and rows in which images needs to be displayed
num_row = 4
num_col = 4*#to get 4 * 4 = 16 images together*
imageId = **np.random.randint**(0, **len**(X_train), num_row * num_col)#creating subplots
fig, axes = **plt.subplots**(num_row, num_col)#main title of the plot **plt.suptitle**('Images with True Labels', fontsize=18)#displaying images as subplots
**for** i **in** **range**(0, num_row):
**for** j **in** **range**(0, num_col):
k = (i*num_col)+j
axes[i,j].**imshow**(X_train[imageId[k]])
axes[i,j].**set_title**(subCategory.**iloc**[trainData['fine_labels'][imageId[k]]][0].**capitalize**())
axes[i,j].**axis**('off')
作者图片
我们可以从可视化中看到,图像的质量很低,并且对象在图像中的位置变化很大。很难训练一个模型来识别和分类这样的图像。🙆🏻
现在让我们来处理测试数据集。
*#transforming the testing dataset*
X_test = testData['data']
X_test = X_test.**reshape**(**len**(X_test),3,32,32).**transpose**(0,2,3,1)y_train = trainData['fine_labels']
y_test = testData['fine_labels']
为了进行预测,图像的标签已经从现有的 1D NumPy 阵列结构转换成分类矩阵结构。
#number of classes in the dataset
n_classes = 100y_train = **to_categorical**(y_train, n_classes)
y_test = **to_categorical**(y_test, n_classes)
我们现在已经完成了预处理,我们将在的另一篇文章中研究如何为这个数据集构建卷积神经网络模型。
这里是到 GitHub 仓库的链接,里面有所有这些代码。请在您的工作中随意使用它来训练一个可以对图像进行分类的经典 CNN 模型。😊
相关文章:
谢谢大家阅读这篇文章。请分享您对这篇文章的宝贵反馈或建议!快乐阅读!📗 🖌
领英
CIFAR 100:使用 EfficientNet 进行迁移学习
原文:https://towardsdatascience.com/cifar-100-transfer-learning-using-efficientnet-ed3ed7b89af2?source=collection_archive---------3-----------------------
使用最先进的 EfficientNet-B0 进行迁移学习
玛丽娜·维塔莱在 Unsplash 上拍摄的照片
卷积神经网络 (CNN)是一类常用于分析图像的深度神经网络。在本文中,我们将一起构建一个 CNN 模型,该模型可以正确识别物体的彩色图像并将其分类到 CIFAR-100 数据集的 100 个可用类中的一个。特别是,我们将重用一个最先进的技术作为我们模型的起点。这种技术被称为迁移学习。➡️
我们先来了解一下什么是迁移学习。我不会讲太多细节,但会尝试分享一些知识。📝
迁移学习
如《机器学习应用研究手册》所述, 迁移学习 是通过从一个已经学习过的相关任务中迁移知识,在一个新任务中对学习的提高。
简单来说,迁移学习是一种机器学习技术,在一个任务上训练的模型被重新用于第二个相关的任务。深度学习网络是资源饥渴的,并且具有数百万个参数,计算成本很高。这些网络用大量数据进行训练,以避免过度拟合。因此,当一个最先进的模型被创造出来时,通常需要研究人员花费大量的时间进行培训。由于一个最先进的模型是在花费如此巨大的资源后训练出来的,研究者认为这种投资的收益应该是多次收获的,因此产生了迁移学习的概念。
迁移学习的最大好处是,我们可以重用整个模型或模型的某一部分。嗯,聪明!😎这样我们就不用训练整个模型了。特别是,迁移学习可以节省时间并提供更好的性能。例如,使用可以识别汽车的预训练模型到现在识别卡车。
现在让我们了解一下我们将在这里使用的最先进的模型。
EfficientNet-B0:最先进的模型
EfficientNet 是谷歌打造的 CNN 的一个家族。与其他最先进的模型相比,✌️these CNN 不仅提供了更好的准确性,而且通过减少参数数量提高了模型的效率。EfficientNet-B0 模型是一个简单的移动大小的基线架构,并在 ImageNet 数据集上进行训练。
在构建神经网络时,我们提高模型性能的基本方法是增加单元数或层数。然而,这种方法或策略并不总是奏效,或者我必须说,在某一点上没有帮助。例如,我为 CIFAR-100 数据集构建了一个 9 层卷积神经网络模型,并设法实现了仅 59%的准确率。不仅仅是随机的机会。😏我增加层数或单元数的尝试并没有进一步提高精度。☹️ ( 链接到代码)
**EfficientNet 的工作理念是,提供一种有效的复合缩放方法(缩放深度/宽度/分辨率的所有维度)来增加模型大小,可以帮助模型实现最大的精度增益。**下图来自原始论文,给出了一个很好的比例可视化。
【https://arxiv.org/pdf/1905.11946.pdf】来源:
注: EfficientNet 有很多变种。我用的是 EfficientNet-B0,因为它是个小型号。如果你愿意,你可以试试 EfficientNet 的其他变种。
所以,让我们用 EfficientNet-B0 建立一个图像识别模型。请注意,我只是在博文中训练模型。如果你想了解预处理部分,请参考这篇博文。
注: *我会尽量把大部分概念说清楚但还是,本文假设对卷积神经网络(CNN)有基本的了解。*📖
这项任务的代码可以在我的 Github 上找到。请放心使用它来构建更智能的图像识别系统。
使用迁移学习的模型训练
为了训练机器学习模型,我们需要一个训练集。一个好的做法是保留一个验证集来选择超参数,并保留一个测试集来根据看不见的数据测试模型。
让我们首先导入库。
**from** sklearn.model_selection **import** StratifiedShuffleSplit
**import** cv2
**import** albumentations **as** albu
**from** skimage.transform **import** resize
**import** numpy **as** np
**import** pandas **as** pd **import** matplotlib.pyplot **as** plt
%matplotlib inline
**from** pylab **import** rcParams
**from** sklearn.metrics **import** accuracy_score, confusion_matrix, classification_report
**from** keras.callbacks **import** Callback, EarlyStopping, ReduceLROnPlateau
**import** tensorflow **as** tf
**import** keras
**from** keras.models **import** Sequential, load_model
**from** keras.layers **import** Dropout, Dense, GlobalAveragePooling2D
**from** keras.optimizers **import** Adam
**import** efficientnet.keras **as** efn
我使用分层混洗分割将我的训练集分割为训练集和验证集,因为它将保留 100 个类中每个类的样本百分比。下面是执行分割的代码。
sss = StratifiedShuffleSplit(n_splits=2, test_size=0.2, random_state=123)
**for** train_index, val_index **in** sss.split(X_train, y_train):
X_train_data, X_val_data = X_train[train_index], X_train[val_index]
y_train_data, y_val_data = y_train[train_index], y_train[val_index]
**print**("Number of training samples: ", X_train_data.shape[0])
**print**("Number of validation samples: ", X_val_data.shape[0])
输出给出了每组中的样本数。
Number of training samples: 40000
Number of validation samples: 10000
根据 EfficientNet,我们不仅需要缩放模型的宽度和深度(这将由预训练的模型负责),还需要缩放图像的分辨率。EfficientNet-B0 模型架构要求映像的大小为(224,224)。因此,让我们将大小为(32,32)的图像调整到新的大小。
height = 224
width = 224
channels = 3input_shape = (height, width, channels)
下面的函数 resize_img 将图像和形状作为输入,并调整每个图像的大小。我使用了双三次插值法来放大图像。它考虑总共 16 个像素的已知像素的最近的 4x 4 邻域。这种方法产生明显更清晰的图像,被认为是处理时间和输出质量的理想组合。
**def** resize_img(img, shape):
**return** cv2.resize(img, (shape[1], shape[0]), interpolation=cv2.INTER_CUBIC)
我们都知道,深度学习模型的性能通常会随着更多数据的添加而提高,所以我计划进行图像增强,但内存始终是深度学习模型的一个大限制,因为它们有很多可训练的参数。所以,我选择了 python 的 相册 库,它有助于实时数据扩充。(如果你不了解这个库,我强烈推荐你去看看它的网站和 GitHub 页面。)
我使用 Keras 数据生成器类创建了自己的自定义数据生成器类。参数“水平翻转”、“垂直翻转”、“网格扭曲”和“弹性变换”被调整为扩展数据集(您也可以尝试其他参数)。
由于图像中特征值的分布可能彼此非常不同,因此通过将每个图像除以 255 来归一化图像,因为每个单独颜色的范围是[0,255]。因此,重新缩放的图像具有新范围[0,1]中的所有特征。
我分批完成了所有这些转换。此外,我只对训练数据集应用了增强,并保留了验证和测试数据集。
在编写自定义数据生成器类之前,让我们首先设置我们的常数。
n_classes = 100
epochs = 15
batch_size = 8
下面是自定义数据生成器类的代码。
**class** DataGenerator(keras.utils.Sequence):
**def** __init__(*self*, images, labels=**None**, mode='fit', batch_size=batch_size, dim=(height, width), channels=channels, n_classes=n_classes, shuffle=**True**, augment=**False**):
*#initializing the configuration of the generator*
*self*.images = images
*self*.labels = labels
*self*.mode = mode
*self*.batch_size = batch_size
*self*.dim = dim
*self*.channels = channels
*self*.n_classes = n_classes
*self*.shuffle = shuffle
*self*.augment = augment
*self*.on_epoch_end()
*#method to be called after every epoch*
**def** on_epoch_end(*self*):
self.indexes = np.arange(*self*.images.shape[0])
**if** *self*.shuffle == **True**:
np.random.shuffle(*self*.indexes)
*#return numbers of steps in an epoch using samples & batch size*
**def** __len__(*self*):
**return** int(np.floor(**len**(*self*.images) / *self*.batch_size))
*#this method is called with the batch number as an argument to #obtain a given batch of data*
**def** __getitem__(*self*, index):
*#generate one batch of data*
*#generate indexes of batch*
batch_indexes = *self*.indexes[index * *self*.batch_size:(index+1) * *self*.batch_size]
*#generate mini-batch of X*
X = np.empty((*self*.batch_size, **self*.dim, *self*.channels)) **for** i, ID **in** enumerate(batch_indexes):
*#generate pre-processed image*
img = *self*.images[ID]
*#image rescaling*
img = img.astype(np.float32)/255.
*#resizing as per new dimensions*
img = resize_img(img, *self*.dim)
X[i] = img
*#generate mini-batch of y*
**if** *self*.mode == 'fit':
y = *self*.labels[batch_indexes]
*#augmentation on the training dataset*
**if** *self*.augment == **True**:
X = *self*.__augment_batch(X)
**return** X, y
**elif** *self*.mode == 'predict':
**return** X
**else**:
**raise** **AttributeError**("The mode should be set to either 'fit' or 'predict'.")
*#augmentation for one image*
**def** __random_transform(*self*, img):
composition = albu.Compose([albu.HorizontalFlip(p=0.5),
albu.VerticalFlip(p=0.5),
albu.GridDistortion(p=0.2),
albu.ElasticTransform(p=0.2)])
**return** composition(image=img)['image']
*#augmentation for batch of images*
**def** __augment_batch(*self*, img_batch):
**for** i **in** range(img_batch.shape[0]):
img_batch[i] = *self*.__random_transform(img_batch[i])
**return** img_batch
让我们将数据生成器类应用于我们的训练集和验证集。
train_data_generator = DataGenerator(X_train_data, y_train_data, augment=**True**)
valid_data_generator = DataGenerator(X_val_data, y_val_data, augment=**False**)
Keras 中提供了 EfficientNet 类来帮助轻松转移学习。我使用了带有 ImageNet 权重的 EfficientNet-B0 类。因为我使用这个模型只是为了提取特征,所以我没有在网络的顶部包括完全连接的层,而是指定了输入形状和池。我还添加了自己的池和密集层。
下面是使用预先训练好的 EfficientNet-B0 模型的代码。
efnb0 = efn.EfficientNetB0(weights='imagenet', include_top=**False**, input_shape=input_shape, classes=n_classes)
model = Sequential()
model.add(efnb0)
model.add(GlobalAveragePooling2D())
model.add(Dropout(0.5))
model.add(Dense(n_classes, activation='softmax'))
model.summary()
这是输出。
作者图片
该模型有 4,135,648 个可训练参数。😳
optimizer = Adam(lr=0.0001)
*#early stopping to monitor the validation loss and avoid overfitting*
early_stop = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=10, restore_best_weights=**True**)
*#reducing learning rate on plateau*
rlrop = ReduceLROnPlateau(monitor='val_loss', mode='min', patience= 5, factor= 0.5, min_lr= 1e-6, verbose=1)*#model compiling*
model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])
在编译我们的模型之后,让我们将它放在我们的训练数据集上,并在验证数据集上验证它。
model_history = model.fit_generator(train_data_generator, validation_data = valid_data_generator, callbacks = [early_stop, rlrop],verbose = 1, epochs = epochs)
*#saving the trained model weights as data file in .h5 format*
model.save_weights("cifar_efficientnetb0_weights.h5")
以下是训练的片段。
作者提供的图片
我们可以看到,该模型在第 14 个时期调整了学习率,我们在训练集上获得了 84.82%的最终准确率,这是非常好的。但是等等,我们也需要看看测试的准确性。
视觉化有助于更好地看待事物。让我们画出精度和损耗图。
*#plot to visualize the loss and accuracy against number of epochs*
plt.figure(figsize=(18,8))
plt.suptitle('Loss and Accuracy Plots', fontsize=18)
plt.subplot(1,2,1)
plt.plot(model_history.history['loss'], label='Training Loss')
plt.plot(model_history.history['val_loss'], label='Validation Loss')
plt.legend()
plt.xlabel('Number of epochs', fontsize=15)
plt.ylabel('Loss', fontsize=15)
plt.subplot(1,2,2)
plt.plot(model_history.history['accuracy'], label='Train Accuracy')
plt.plot(model_history.history['val_accuracy'], label='Validation Accuracy')
plt.legend()
plt.xlabel('Number of epochs', fontsize=14)
plt.ylabel('Accuracy', fontsize=14)
plt.show()
作者图片
现在让我们评估一下我们的模型。
valid_loss, valid_accuracy = model.evaluate_generator(generator = valid_data_generator, verbose = 1)
**print**('Validation Accuracy: ', **round**((valid_accuracy * 100), 2), "%")
输出:
1250/1250 [==============================] - 85s 68ms/step Validation Accuracy: 82.3 %
现在,是时候看看测试数据集的准确性了。
y_pred = model.predict_generator(DataGenerator(X_test, mode='predict', augment=**False**, shuffle=**False**), verbose=1)
y_pred = np.argmax(y_pred, axis=1)
test_accuracy = accuracy_score(np.argmax(y_test, axis=1), y_pred)
**print**('Test Accuracy: ', **round**((test_accuracy * 100), 2), "%")
输出:
1250/1250 [==============================] - 78s 63ms/step
Test Accuracy: 81.79 %
培训的结果相当不错。我们在测试数据集上获得了 81.79%的准确率。💃
可以使用下面的代码为模型生成混淆矩阵和分类报告。
cm = confusion_matrix(np.argmax(y_test, axis=1), y_pred)
**print**(cm)target = ["Category **{}**".format(i) **for** i **in** range(n_classes)]
**print**(classification_report(np.argmax(y_test, axis=1), y_pred, target_names=target))
下面是前 11 个类的代码片段。
从分类报告中,我们可以看到一些类别被很好地预测,而一些被错误地预测。
如果您想可视化预测,这里是代码。
prediction = pd.DataFrame(y_pred)rcParams['figure.figsize'] = 12,15
num_row = 4
num_col = 4
imageId = np.random.randint(0, len(X_test), num_row * num_col)
fig, axes = plt.subplots(num_row, num_col)
**for** i **in** range(0, num_row):
**for** j **in** range(0, num_col):
k = (i*num_col)+j
axes[i,j].imshow(X_test[imageId[k]])
axes[i,j].set_title("True: " + **str**(subCategory.iloc[testData['fine_labels'][imageId[k]]][0]).capitalize() + "**\n**Predicted: " + **str**(subCategory.iloc[prediction.iloc[imageId[k]]]).split()[2].capitalize(), fontsize=14)
axes[i,j].axis('off')
fig.suptitle("Images with True and Predicted Labels", fontsize=18)
plt.show()
下面是输出的片段。
作者图片
你可以看到我们的模型混淆了摩托车和自行车。🙄但是,我们可以看到大多数预测是正确的。✅
深度学习就是实验。使用 EfficientNet 的其他最新版本,很有可能可以进一步提高该模型的性能。超参数调整也是深度学习的一个重要方面,可以帮助提高准确性。
我希望这个博客能帮助你理解如何进行迁移学习。请随意尝试更多以获得更好的性能。查看我的 GitHub 的完整代码和我的以前的文章的初始步骤。另外,我强烈推荐你阅读的原创论文。这是一本有趣的读物!
相关文章:
参考:
- 原文:https://arxiv.org/pdf/1905.11946.pdf
- 这个笔记本给了我如何进行迁移学习的指导。
谢谢大家阅读这篇文章。请分享您宝贵的反馈或建议。快乐阅读!📗🖌:我也很想知道你使用迁移学习在 CIFAR-100 上有没有更好的表现。
领英
城市、地图、仪表盘
原文:https://towardsdatascience.com/cities-maps-dashboards-792f247f8117?source=collection_archive---------29-----------------------
几个世纪以来,人类一直在记录和分析数据。例如,书写在公元前 3100 年左右的古代美索不达米亚得到发展,因为官僚们需要一种有效的工具来记录和追踪公民信息。自巴比伦帝国以来,各国政府一直在进行人口普查,以收集关于公民、牲畜和资源的大量数据,用于税收目的。将可用资源记录在案可以实现更有效的管理,并使国家的发展规模超过旧的城邦成为可能。反过来,更大的州开始覆盖更大的领土和更多样的资源,导致更大的人口普查数据。几个世纪以来,这种正反馈循环基本上没有中断过,为我们今天所承认的统计学埋下了种子。
统计这个词最终来源于现代拉丁语术语 statisticum collegium (“国务院”)和意大利语单词 statista (“政治家”或“政治家”)。由 Gottfried Achenwall (1749 年)首先引入的德语 Statistik ,最初指定了关于国家的数据分析,表示**“国家科学”**(当时英语中称为 政治算术 )
虽然统计科学自 18 世纪以来发生了变化,但我们用来存储记录的抽象结构却相对保持不变。众所周知的数据表示形式之一是由巴比伦人发明的表格结构,至今仍被广泛使用。在表格表示中,数据通常被组织成网格结构,显示条目的行和列之间的关系。这种结构在将数字条目相互联系起来时非常有效,但是对于古代的“国家科学”来说,这种枚举仅仅是达到目的的手段。仍然需要将数值关系与经验领域即三维空间联系起来。然而,当时表示空间关系的主要方法与表示数值关系的方法有很大不同。利用当时的几何知识,用当地地图(包括建筑图纸)定义空间关系。由于这种表现形式的差异,将普查数据与空间地图联系起来是通过编码和命名惯例来实现的,这些惯例将地域标签与相关数据联系起来。而空间的边界是用几何学在地图和图画上分别定义的。这种隔离空间和非空间信息的做法经受住了时间的考验,这主要归功于它的简单性,今天它可以在大量现代技术的基础上找到。
左上:数字关系右上:空间关系:Giambattista Nolli,来自罗马地图的片段(1748)。作者提供的图片
尽管今天表格和地图都有所发展,但它们背后的基本原则却变化甚微。发生巨大变化的是人类与信息互动的方式。早在 18 世纪,很明显,尽管表格结构对于存储信息很有效,但对于查看信息来说并不理想。数学家、政治经济学家和建筑师威廉·普莱费尔(William Playfair)在忙于瓦解法国国家货币时,也意识到了这一点,并开发了汇总和显示数据的方法。他的图表(条形图、饼状图)通常被誉为信息图表之父,几乎可以在互联网的每个角落找到,交付速度已经成为一个关键要求。
*商业和政治图册。*出版于 1786 年。威廉·普莱费尔的图片公共领域
他的图表让观众一眼就能洞察到潜在的数据。他们总结了主要趋势,并以一种许多人都能理解的方式更快地传递信息。
仪表板地图
带着这些问题和考虑,我开发了一个开源网络平台,收集、分析和可视化赫尔辛基大都市地区的城市数据。它利用 web 技术的交互性来关联空间和表格数据,同时以可访问的仪表板的形式呈现洞察力。
**Dashmap 布局概念草图。**图片作者
该平台试图解决现代开放数据生态系统中存在的一个基本问题。
**问题:**现代城市拥有丰富的开放数据生态系统,然而技术技能的缺乏经常阻止人们使用可用的数据。
普通公民每天会创建 160 千兆字节的数据。现代城市和企业在获取和分析这些数据方面已经变得非常高效。由于各种技术原因,公民产生的数据通常以复杂的文件格式提供,并通过复杂的 API 请求进行访问。这对机器来说很棒,但看着这些数据往往会让你的眼睛出血。 DashMap.io 通过可访问的交互式仪表盘提供对开放数据的访问,增强了非技术用户的能力。
图片由作者提供。
Dashmap.io 的布局以一个与交互式地图并列的仪表盘为特色。该地图可用于按邮政区域过滤数据,仪表盘根据地图上的选择进行更新。
Dashmap.io .作者图片。
该网站将数据分为 5 大类。
人口普查:
人口普查是对人口及其重要特征的全面统计。人口普查是通过系统地记录和汇总某一特定人口的数据而产生的。人口普查的目的是了解社会的基本结构,并确定新出现的模式和趋势。
房地产:
房地产是一种不动产,包括土地和任何附属于土地的永久性建筑物。包含的资源可以是人造的或天然的。它们可以包括水、树木、农作物、矿物质和建筑结构。房地产的价值通常是经济健康的关键指标之一。
服务
服务是一种没有实物商品从卖方转移到买方的交易。服务可以定义为服务提供者利用资源、技能、独创性或经验向客户提供价值的行为或表现。
流动性
地理流动性是衡量人口和商品如何随着时间的推移而移动的指标。人口流动对一个社会中的许多社会学因素有很大的影响,其影响范围从对当地经济增长的影响到住房市场和对区域服务的需求。
环境
环境是指人为和自然过程的副产品所创造的环境条件。它包括污染、噪音、风力模式和辐射水平等指标。
每个选项卡包含多个部分,提供基于更高粒度数据的见解。
开放源码
如前所述,DashMap 的目的是让个人和企业能够在决策过程中利用开放数据。因此,平台是开源的是至关重要的。Dashmap 背后的全部代码可以在这里找到:
https://github.com/Geometrein/dashmap.io
欢迎投稿和拉请求!
结论
开放数据生态系统将在未来继续发展。然而,开放数据应该惠及所有人,而不仅仅是将数据平台货币化的公司。因此,需要更多的平台,使个人和企业能够利用开放数据,而无需支付与应用开发相关的巨额前期成本。Dashmap 为赫尔辛基大都市区提供了这个平台。如果你想为你的城市做一个,请随意使用 Dashmap 作为启动平台。
开放数据应该让所有人受益!
城市尖塔
原文:https://towardsdatascience.com/cityspire-562abb2c3b11?source=collection_archive---------33-----------------------
—一个应用的故事,从想法到部署。
TLDR: 在远程跨学科团队做了 8 周(兼职)的数据科学家和机器学习工程师;帮助收集、清理和争论数据,以创建推荐模型;创建了一个 AWS RDS Postgres 数据库来存储数据,并通过使用 FastAPI 测试并使用 AWS Elastic Beanstalk 部署的端点将这些信息发送到前端。
迈克尔·迪森扎在 Unsplash 上的照片
我 简介:
Eeny,Meeny,Miny,Moe,你就是这样找到你的新家的吗?
**问题:**假设你想搬家,你如何决定哪个新城市适合你?应该问朋友吗?看看雅虎、谷歌或猫途鹰?搬家并不容易,这是一个重大的决定。哪里可以找到租赁价格等信息?这个地方的人口统计数据是什么,犯罪率,污染?你需要一辆车住在那里吗?还是那里适合步行?你将如何找到所有这些信息?你可以花几个小时谷歌不同的网站,或者你可以检查城市塔。
解决方案: CitySpire 的目标是成为用户接收最准确城市信息的一站式资源。我们通过以简单的格式为您提供数据驱动的推荐,让您不再为寻找理想的居住城市而烦恼。该应用程序分析来自城市的数据,如人口、生活成本、租赁率、犯罪率、公园(步行得分)以及许多其他社会和经济因素,这些因素对于决定某人想住在哪里很重要。这个应用程序在一个直观和易于理解的界面中呈现这些信息。
约束:
这是我迄今为止承担的最雄心勃勃的项目。我和我的团队在一个紧张的期限内工作,有几项新技术我们必须加快速度。
作为数据科学团队,我们的任务是寻找、清理和争论数据。然后,我们必须使用机器学习来创建一个推荐系统。最后,利用这些信息创建一个宜居指数,帮助用户做出明智的决定,决定他们想搬到哪个城市。我们还必须确保我们的前端工程师能够阅读这些信息。
虽然清理和争论数据可能看起来单调乏味或不成熟,但为了保持数据的连续性,我们不得不争论诸如城市名称应该如何出现之类的问题。另一个限制是在工作中学习新技术,因为我们的利益相关者期望部署 AWS,但是团队中的所有数据科学家只有 Heroku 的经验。
策划:
设计架构
项目的前几周完全用于规划:通读我们的产品文档,了解可用的数据(无论是作为数据集、API,还是如果我们必须进行网络搜集),促进数据科学会议以创建大纲和时间表,最重要的是:我们与团队领导和网络开发人员的日常会议,以保持彼此了解我们的规划,并确保我们的最终产品将准确符合我们的利益相关者的愿景。
为了确保我们都在同一页面上,我设计了我们的系统架构,以便我们有一个数据采集、存储、分析、机器学习、API 网关和数据反馈的可视化表示。这有助于我们从最终目标开始,而不是在试图跨越这座桥时试图去建造它。
从路线图到实施
由于我们的时间有限,而且项目的广度相当大,我们马上开始工作。使用产品文档,我们使用 Trello 创建了任务卡,这样我们就可以确保满足发布特性。
数据:
让美好时光滚滚来!
收集、评估和清洁
作为团队中的数据科学家,我们负责查找有关城市的信息,如犯罪、租金、污染等。我们花了很多时间收集数据,这些数据将提供利益相关者希望包含在他的应用程序中的信息。
清洁
哦,该打扫卫生了!
我们不得不争论信息,以确保命名惯例等事项在所有数据中是相同的,例如“圣路易斯”与“圣路易斯”,或者“布拉格堡”与“英尺。布拉格。我们知道,为了确保我们每个数据源之间的数据完整性和连续性,深入的数据清理是必要的。
例子
抬杠功能:
Wrangle 功能,用于清理 FBI 犯罪数据,并允许我将 50 个州合并到一个 csv 中。
使用管道
另一个注意事项是几个数据集有城市连字符,如奥尔巴尼-斯克内克塔迪-特洛伊,纽约。在这种情况下,我不仅必须对城市和州进行拆分,还必须创建一个用'-'分隔城市的函数,然后复制每个城市的行信息。
需要应用几个函数,所以我使用了一个叫做 pipe 的方法,将我的特定函数作为方法链中数据帧上的一个方法。这使得我的工程师同事可以很容易地跟踪我的过程。
使用。污染数据管道
评估:
将普查区域信息映射到城市
除了清理之外,该过程的另一个重要部分是评估数据,然后对数据以及如何使用数据做出一些假设或决策。我们获取信息的一个来源是人口普查局。此应用程序是一个基于城市的应用程序,但人口普查信息按区域或县进行格式化。作为一名数据科学家,我必须将区域信息转化为城市信息,为此我必须做出几个假设。我利用了 HUD中的一个文件,该文件将区域映射到邮政编码。有一个名为“res_ratio”的列,它映射了居住在特定 zip 范围内的地域人口的百分比。在与我的团队和利益相关者讨论后,我做出了假设,将这一比率用于人口统计、收入和就业数据等方面。
其他决定
另一个数据驱动的决策是确定如何总结某些信息以传播给用户。用户通常想要数据的快照或简洁表示,不带偏见地传达这些信息是很重要的。我为犯罪、污染和多样性创建了一个总结专栏。
每 1000 名居民犯罪率 : 为了总结犯罪数据,我使用了 FBI 每 1000 名居民的犯罪报告标准。这代表了每 1,000 名居民的指数犯罪数量。例如:一个拥有 513 项指数犯罪(谋杀、强奸、抢劫、严重人身攻击、入室盗窃、盗窃和机动车盗窃)的直辖市,其人口为 8,280 人,其犯罪率是多少?513(指数犯罪)÷ 8,280(人口)= .061957 x 1,000 = 62.0(每 1,000 名居民的犯罪率)。然后使用 pd.qcut 将其分为“高”、“中”和“低”。
**空气质量指数:**为了确定每个城市的整体空气质量,我使用了中值,然后创建了一个算法,根据美国空气质量指数将其分开。
多样性:为了总结多样性,我使用了辛普森多样性指数。
- n =每个种族的人数
- N =所有种族的总人数
- D 的值介于 0 和 1 之间
这些犯罪、污染、多样性的汇总数字,以及可步行性得分,被用来计算宜居性得分。
型号:
最近邻居
我们团队认为对用户有益的一个特性是创建一个推荐系统。在与我们的团队领导协商并获得批准后,我开始实现这个特性。
大多数人在考虑搬迁时,脑海中已经有了一个城市,但我们认为,获得类似城市的推荐将是一种打开用户可以搬到哪里的其他可能性的方式。
为了实现推荐系统,我使用了 sci-kit learn 库中名为 最近邻 的机器学习模型。在将我们收集的不同数据合并到一个数据框架中后,我对数据进行了缩放,这样诸如租金和人口等列的权重就不会超过百分比或小数。然后,名为“最近”的列被添加到数据帧中。然后使用 get_recommendations 端点返回该数据。
这是 get_recommendations 端点中使用的列
新技术:
开发这一产品令人兴奋的部分之一是获得新技术的经验。好在 FastAPI 和AWS(RDS Postgres, Elastic Beanstalk )都有很棒的文档。
这才是乐趣真正开始的地方!
FastAPI:
入门
和 Flask 一起工作过,有很多相似之处我可以带过去。这篇文章“针对 Flask 用户的 FASTAPI”非常有帮助。
为了开始,我们需要一个 main.py 文件,该文件在我们的存储库中提供,所以要测试它,只需运行以下一系列命令即可:
1.安装应用程序所需的所有依赖项
2.进入安装了正确依赖项的虚拟环境
3.这将部署您的 FastAPI 应用程序。
如果您运行服务器并转到端点http://127.0.0.1:8000/docs
,您将获得一个自动生成的 swagger 文档。FastAPI 易于使用,最好的部分是文档,它从您的文档字符串中获取。这使得显示如何使用端点变得容易,而不必去单独的文档,如 README.md(如果我使用 Flask,这将是我提供文档和链接的地方)。
AWS 弹性豆茎:
在创建和测试我们的基本端点之后,现在我们已经准备好将应用程序部署到 AWS Elastic Beanstalk。我们的团队领导为我们提供了一个 12 位数的帐户 ID(IAM)和一个 AWS 用户名和密码。在安装了awscli
和awsebcli
之后,我们能够运行下面的命令,并且我们开始工作了!
eb init --platform docker CHOOSE-YOUR-NAME --region us-east-1
eb create --region us-east-1 CHOOSE-YOUR-NAME
eb open
然后,在进行更改时,使用 git 提交您的更改,然后运行eb deploy
和eb open
来使用更改重新部署应用程序。
我们从惨痛的教训中学到的一件事是,当与前端连接时,我们需要确保配置正确的端口,以便可以从 HTTPS 流量接收信息。我们必须创建一个 443 监听端口,而默认设置只有一个端口 80,它只允许 HTTP 流量。
HTTP 和 HTTPS 流量所需的端口
AWS RDS Postgres:
用 AWS RDS 创建数据库非常简单。我登录 AWS 控制台并选择了该地区。然后,我执行了标准的创建操作,选择了一个 PostgreSQL,并且能够使用它们的默认设置创建数据库实例
在本地开发时,我使用 python-dotenv 加载一个.env
文件。(.env
文件在.gitignore
中列出。)这确保了我的用户名和密码受到保护。部署时,我们使用弹性 Beanstalk 控制台来配置环境变量。
包括数据库名称和 url —连接到 Elastic Beanstalk
API:
终点:
成功地建立了到数据库的连接并将基本 API 部署到 AWS 之后,接下来的步骤是构建 API 本身,包括路由(端点)、函数和使用文档。
数据科学终点
对于 DS 团队,我为最近邻模型和可视化端点创建了 API 端点。
最近邻 API 端点—从提取文档字符串。py 文件。显示成功响应和错误消息。
可视化:
一图抵千言 。
下面是我创建的交互式 plotly 可视化端点。这些端点使用户能够直观地查看数据点,并更深入地了解每项统计数据。使用图表或图形来可视化大量数据,使其更容易理解。
/API/demographics _ graph-显示每个种族类别的百分比
/API/employment _ graph-细分行业部门和就业类型
/API/aqi _ graph-更深入地了解每个城市的空气质量
最终想法:
参与这个项目既令人兴奋又有收获。我对在工作中学习感到兴奋,并且很高兴到目前为止,我的培训和教育为我成功地与 AWS 和 FastAPI 一起工作奠定了基础。我惊喜地发现 AWS 让部署和管理 web 应用变得如此容易,并对 FastAPI 及其内置功能印象深刻,这些功能使使用它创建 DS 端点变得轻而易举。
我从这个过程中学到的另一个重要的教训是,当与利益相关者和大型团队合作时,持续的沟通是关键。重要的是利用产品范围来确保我们在实现利益相关方对 CitySpire 的愿景方面步调一致,而不是我们的错误假设。此外,沟通对于确保每个团队成员都知道自己的职责非常重要。创建系统架构和 trello 板为我们提供了一个重要的路线图,并让我们负责任。
“城市塔”是我承担的最雄心勃勃的项目。我学到了很多东西,比如确定项目范围、沟通以及在工作中虚心学习。因此,这段经历提供了许多有价值的基础经验,我肯定会在我的整个职业生涯中一直保持这些经验。
潜在的改进:
到目前为止,在这个项目中,我们已经能够在 DS API 和前端网站上实现租赁价格估计、步行评分、犯罪、人口、污染和宜居性评分。一些可能的后续步骤是:
- 租金预测模型
- 人口预测模型
- 污染预测模型
- 整合每个城市的主流产业
- 整合其他数据点,如公共汽车和自行车分数
- 实现可视化 API
- 创建一个 NLP 推荐系统,用户可以在其中设置标准并接收基于其查询的结果。
团队概述:
我作为一名数据科学家和机器学习工程师在一个远程跨学科团队工作了 8 周(兼职),创建了 CitySpire。
城市塔——G 队
我和一个了不起的团队一起工作。这个团队包括我和其他三名数据科学家,三名网站开发人员,一名 UX 设计师,以及我们的项目负责人,他们让我们保持活力,确保我们朝着正确的方向前进。每个人都很勤奋,立即卷起袖子准备工作。(我们的团队做得非常好,在其他 8 个团队中,我们的存储库被选为未来团队的基础。)
角色: App 架构师、数据科学家、机器学习工程师、数据可视化
DS 技术栈: Python,FastAPI,AWS RDS Postgres,AWS Elastic Beanstalk,Docker
时间表: 8 周(兼职)
我们最终的 Github 库可以在这里找到。
演示:
CItySpire API 演示和 DS 架构
闪电对话:
在 8 周结束的时候,我做了一个关于使用文档作为交流的重要工具的简短演讲。
作为交流工具的文档
链接:
数据来源:
- 美国人口普查——https://www.census.gov/
- 联邦调查局犯罪数据—https://UCR . FBI . gov/Crime-in-the-u . s/2019/Crime-in-u . s-2019/tables/table-8/
- 污染数据—https://aqs.epa.gov/aqsweb/airdata
- 租房数据——https://www.huduser.gov/
- walk score——https://www.walkscore.com/
AWS 弹性豆茎应用程序
原文:https://towardsdatascience.com/cityspire-lambda-school-labs-project-b174ff7d877b?source=collection_archive---------36-----------------------
Lambda 学校实验室(Bloom Technology now)内的端到端数据科学项目,包括项目流程、团队工作和功能实现。
伊利诺伊州,芝加哥(图片来自 triplepundit.com
简单地
在一个由 web 开发人员和数据科学家组成的团队中为 inherited 项目工作了两个月,收集和清理新数据,执行数据分析和功能工程,使用机器学习建模技术为项目创建和添加新功能,通过 FastAPI 端点交付它们,并最终将应用程序部署到带有 AWS 关系数据库服务的 AWS Elastic Beanstalk。
需求、想法、规划和架构
CitySpire 是一款分析城市数据的应用程序,这些数据包括人口、生活成本、租金、犯罪率、公园(步行得分)以及许多其他社会和经济因素,这些因素对于决定人们喜欢住在哪里很重要。CitySpire 背后的理念是在一个地方为用户提供最准确的城市信息。该应用程序必须在非常直观和易于理解的界面呈现重要的城市数据。
作为数据科学家,我们的任务是收集和分析城市数据,如住房成本、天气状况、教育数据、工作列表和其他因素,对这些因素进行预测和预报,并重新计算新的宜居性得分。
继承的应用程序有一些 API 端点,如犯罪率、步行得分、污染、人口、租赁价格、空气质量、城市建议和宜居性得分。
第一步是在现有架构的基础上构建应用架构:
CitySpire 建筑图(图片由作者提供)
为了更好地了解整个 app 架构,包括该项目的 web 和 iOS,这里是异想天开网站的链接: 城市塔架构图 。
入门指南
由于我们项目的目标已经确定,下一步也是最重要的一步是找到我们需要在项目中使用的数据。我们必须获得每个城市和州的住房数据、天气数据、工作列表数据和学校数据,并开始清理和特征工程。一旦我们之间分配了任务,以便与我的同行数据科学家更有效地合作,我就负责找到每个城市的天气数据,用于进一步的预测和预报。其他团队成员负责传递房价、工作列表和学校教育数据。
探索性数据分析和特征工程
在网上查找任何数据是最耗时的一步,我前两周的大部分时间都在寻找和收集每个城市的天气数据,并将它们结合在一起:https://github.com/tigju/PT17_cityspire-b-ds/blob/main/notebooks/model/weather/combine_data.ipynb。下一步是清理数据,去掉丢失的值和特征工程。一些功能有超过 50%的丢失数据,我决定删除这些功能。其他特征有不到 20%的缺失值,所以我用平均值和中间值填充它们。另一个重要步骤是对分类值进行编码,并在将数据输入模型之前对所有数据进行缩放。对于编码,我使用了 OrdinalEncoder,对于缩放,我选择了 Sklearn 库中的 StandardScaler。探索性数据分析与特征工程流程在这里:GitHub**。****
数据建模
我决定制作两个功能,一个是天气温度预报,另一个是每年的天气状况(晴天、雨天、阴天、下雪天)。对于我的第一个特性,我执行了时间序列建模,对于第二个特性,我使用了聚合。
由于我需要执行多个时间序列建模,我决定使用脸书先知。这是一个提供自动预测的软件,可以手动调整。它最适用于非线性趋势,对缺失值和处理异常值非常稳健,这正是我的项目所需要的。这在实现上非常简单,唯一的要求是将目标列重命名为“y ”,将日期列重命名为“ds”。在下面的代码中,我按城市对数据进行了分组,这样我就可以分别对每个城市进行预测。然后,我对未来两年进行了每日预测,并将其保存到一个 csv 文件中。
(作者嵌入要点)
这是预测温度数据集的外观,其中“yhat”是预测平均温度,“yhat_lower”是最低预测温度,“yhat_upper”是最高预测温度:
FB Prophet 预测数据集(图片由作者提供)
为了检查我的模型的性能,我使用了 Sklearn 库中的平均绝对误差(MAE)和均方根误差(RMSE)性能指标。
加州萨克拉门托的结果相当不错:
绩效指标(图片由作者提供)
下面是可视化性能的图表。看起来,该模型可以预测平均温度,但有时它无法捕捉到极值。我会说,该型号的整体性能非常好。
加州萨克拉门托的天气预测和预报(图片由作者提供)
所有 FB 先知的工作流程都可以在这里找到: GitHub
综合天气条件
对于天气状况,我将这些值分为“晴天”、“多云”、“下雨”和“下雪”四个标签,并根据 4 年的历史天气状况汇总记录,然后用这些数据创建一个新的 csv 文件。NaN 值 I 用零填充,因为有些城市不具有仅在某些地区通用的特定条件。完整代码在这里:GitHub。
这个片段显示了我是如何计算每个城市的平均值并将结果串联起来的:
(作者嵌入要点)
汇总的天气状况数据如下所示:
天气状况数据集(图片由作者提供)
设置 FastAPI
因为我们已经继承了项目,所以建立 FastAPI 并不困难。以前的数据科学团队给我们留下了非常好的说明。我们只需要克隆 git 存储库并设置本地环境。它安装了项目所需的所有依赖项。
设置 FastAPI 环境(图片由作者提供)
AWS 弹性豆茎
为了部署到 Elastic Beanstalk,我必须首先在我的机器上安装 AWS CLI,方法是根据我的操作系统下载一个安装程序。安装 AWS CLI 后,我想用这个命令aws --version
测试安装是否正确,以确保我没有“command not found”错误,而不是版本号。第二步是安装 AWS Elastic Beanstalk CLI: pip install awsebcli
并通过检查其版本再次测试:eb --version
。
要使用新创建的端点将本地 FastAPI 部署到 AWS EB,我需要遵循以下步骤:
AWS EBS 部署(图片由作者提供)
然后,我必须运行aws configure
来配置 AWS CLI,并在出现提示时输入我的访问密钥。一旦完成,后续提交可以用eb deploy
和eb open
重新部署,以查看部署的变更。
AWS RDS Postgres
在 AWS 中建立数据库并不复杂。您只需登录 AWS 控制台并选择地区。之后,在 EC2 服务中创建一个安全组,并在入站规则中指定类型“PostgreSQL ”,源为“Anywhere ”,其余设置保持默认。然后在 RDS 服务中使用引擎 Postgres 创建标准数据库,在 VPC 安全组中标记“选择现有的”并选择您创建的安全组。
为了用新数据填充数据库,我使用 python-dotenv 从我们的.env
文件中获取数据库地址,并使用 SQLAlchemy 建立数据库连接。
SQLAlchemy 和 dotenv(图片由作者提供)
FastAPI 端点
由于我从事天气预报模型和天气条件聚合的工作,我还必须创建端点来检索这些数据。我添加了两个端点,分别是未来两年天气温度的日预报和月预报:/api/weather_daily_forecast
、/api/weather_monthly_forecast
,第三个端点是每年晴天、阴天、雨天、雪天的平均天数/api/weather_conditions
。其他端点由我的团队成员负责。一旦项目被部署到 Elastic Beanstalk,并且正确地建立了到 RDS 的连接,我们所有的端点(用红色方块标记的)都已经启动并运行了:
FastAPI 端点(图片由作者提供)
我还添加了两个端点来可视化每月天气温度预报/api/weather_forecast_graph
和每年天气状况/api/weather_conditions_graph
:
可视化终点(作者图片)
形象化
为了可视化未来两年的天气预报和天气状况,我使用了 Plotly 库。使用 Plotly,我创建了图形对象,并将其转换为 JSON 格式的 API 端点,可以使用plotly-react.js
库进行渲染,并以交互图形的形式发送到前端应用程序:
未来两年的每月天气预报图表(作者嵌入的图表)
每年的天气状况图表(作者嵌入图表)
还能做什么?
城市塔是思想的产物。可以添加许多功能来扩展它的功能。不幸的是,我们没有更多的时间来完成第二版,我们需要重新审视现有的宜居性评分,并与 DS 合作,看看我们是否可以通过添加新创建的功能来做出改变:房价、天气、工作和学校董事会。我们计划重新使用现有的功能,将我们的功能融入到宜居性评分中。此外,网络团队有一个想法,调整用户部分更重要的因素,根据用户偏好为它们添加权重,并计算得出宜居性得分。此外,我们可以创建标签,这样用户可以更直观地了解这个城市是否是他们的梦想之地。
未来还能增加哪些功能?在我的脑海里有几个:
- 展示社会经济因素,可以是财富、收入、职业、宗教、教育水平、家庭规模、购买习惯等。;
- 展示历史和文化因素,以及娱乐区,它可以是旅游场所,博物馆,纪念碑,公园等。可能是城市/州最好的 10 个地方;
- 最重要的因素之一是社会支持,包括儿童保育、医疗保健、社区安全和其他。
结论
实验室项目对我来说是一个与专业团队合作实现项目目标的绝佳机会。最重要的经历是与我的团队交流,如果需要的话互相帮助。我不得不经历一些艰苦的学习,特别是在设置和部署 AWS Elastic Beanstalk 和 RDS 方面,我确实从头到尾掌握了数据科学项目生命周期的扎实知识和理解。
数据来源:
- 天气: 天气数据
- 职位列表: 职位列表数据
- 房价: 房价数据
- 学校董事会: 学校董事会数据
在 GitHub 上查找我们的项目:
city spire 2.0
注意:
这个项目是为 Lambda 学校(Bloom Technology now)做的,作为Lambda Labs课程的一部分。**
Python 数据可视化库的冲突
原文:https://towardsdatascience.com/clash-of-python-data-visualization-libraries-c4f668a279f?source=collection_archive---------21-----------------------
Seaborn,Altair 和 Plotly
圣地亚哥·拉卡尔塔在 Unsplash 上拍摄的照片
数据可视化是数据科学的基本组成部分。它通过提供洞察力帮助我们更好地理解数据。我们还使用数据可视化来交付结果或发现。
Python 作为数据科学生态系统中编程语言的主要选择,提供了丰富的数据可视化库选择。在本文中,我们将对 3 种流行的方法进行实际比较。
我们将涉及的库是 Seaborn、Altair 和 Plotly。这些示例将包括 3 种基本的数据可视化类型,即散点图、直方图和线图。
我们将通过用所有 3 个库创建相同的可视化来进行比较。我们将使用 Kaggle 上的墨尔本房产数据集作为例子。
让我们从导入库和读取数据集开始。
# import the libraries
import numpy as np
import pandas as pd
import seaborn as sns
import altair as alt
import plotly.express as px# read the dataset
df = pd.read_csv("/content/melb_data.csv", parse_dates=['Date'])df.shape
(13580, 21)# remove outliers
df = df[(df.Price < 500000) & (df.Landsize < 5000)]
该数据集包含墨尔本 13580 所房屋的 21 个要素。我还删除了离群值,以免扭曲图的外观。
散点图
散点图是一种关系图。它通常用于可视化两个数值变量的值。我们可以观察它们之间是否有关联。
让我们生成一个价格和土地面积列的散点图,以研究它们之间的关系。
# Seaborn
sns.relplot(data=df, x="Price", y="Landsize", kind="scatter",
hue="Type", height = 5, aspect = 1.4)
(图片由作者提供)
将数据框传递给数据参数后,要绘制的列由 x 和 y 参数确定。色调参数为绘图增加了一条信息。我们可以根据类型列中的不同类别,大致了解价格和土地面积如何变化。最后,高度和纵横比参数调整地块的大小。
# Altair
alt.Chart(df).mark_circle(size=40).encode(
x='Price', y='Landsize', color="Type"
).properties(height=300, width=500)
(图片由作者提供)
Altair 语法从接受数据框的顶级图表对象开始。下一步是选择情节的类型。我们在编码函数中指定要绘制的列。
颜色参数与 Seaborn 的色调参数相同。最后,我们使用属性函数调整绘图的大小。
# plotly express
fig = px.scatter(df, x='Price', y='Landsize', color='Type',
height=450, width=700)fig.show()
(图片由作者提供)
我们使用了 plotly express,它是 plotly.py 库的高级 API。该语法与 Seaborn 语法非常相似。使用颜色参数代替色调参数。高度和宽度参数调整大小。
2.柱状图
直方图通常用于可视化连续变量的分布。连续变量的值的范围被分成离散的条块,每个条块中的数据点(或值)的数量用条形表示。
我们可以创建 price 列的直方图来检查房屋的价格分布。
# Seaborn
sns.displot(data=df, x="Price", kind="hist",
height=5, aspect=1.4)
(图片由作者提供)
我们使用 displot 函数,它允许创建不同的分布图。种类参数选择绘图类型。
# Altair
alt.Chart(df).mark_bar().encode(
alt.X('Price:Q', bin=True), y='count()'
).properties(height=300, width=500)
(图片由作者提供)
我们在 encode 函数中写的内容告诉 Altair 将 price 列中的值划分到 bin 中,然后计算每个 bin 中数据点(即行)的数量。
最后一个直方图将由 plotly express 库创建。直方图函数的使用如下。
# plotly express
fig = px.histogram(df, x='Price', height=450, width=600)
fig.show()
(图片由作者提供)
3.线形图
线形图显示了两个变量之间的关系。其中之一通常是时间,所以我们可以看到变量是如何随时间变化的。
我们可以生成一个线图来显示房价的日平均值。让我们首先计算每日平均值,并将其保存在另一个数据框中。
avg_daily_price = df.groupby('Date', as_index=False).agg(
avg_daily_price = ('Price', 'mean')
).round(1)avg_daily_price.head()
(图片由作者提供)
我们已经使用 Pandas groupby 函数来计算每天的平均房价。我们现在可以创建一个日平均价格和日期的折线图。
# Seaborn
sns.relplot(data=avg_daily_price, x="Date", y="avg_daily_price", kind="line", height=5, aspect=2)
(图片由作者提供)
与散点图一样,可以使用 Seaborn 的 relplot 函数创建折线图。
# Altair
alt.Chart(avg_daily_price).mark_line().encode(
alt.X("Date"),
alt.Y("avg_daily_price", scale=alt.Scale(zero=False))
).properties(height=300, width=600)
(图片由作者提供)
与前面的例子不同,我们使用了 Altair 的 X 和 Y 编码。原因是 Altair 默认从零开始轴值。它不会根据列的值范围来调整它们。我们需要明确地告诉 Altair 不要从零开始,如果大部分值都在零以上的话,我们的图就是这种情况。
Plotly express 提供了用于生成线图的直线功能。语法与前面的例子几乎相同。我们只改变函数的名字。
# plotly express
fig = px.line(avg_daily_price, x="Date", y="avg_daily_price",
height=400, width=700)
fig.show()
(图片由作者提供)
结论
我们已经用 3 个常用的 Python 数据可视化库介绍了 3 种基本的绘图类型。
使用哪一种取决于语法、用户偏好和风格。然而,在很大程度上,我们可以使用它们中的任何一种来生成漂亮的、信息丰富的可视化效果。
这篇文章中的情节可以认为是最基本的。这三个库能够创建更复杂的库。它们还提供了许多自定义地块的功能。
感谢您的阅读。如果您有任何反馈,请告诉我。
阶级不平衡
原文:https://towardsdatascience.com/class-imbalance-d90f985c681e?source=collection_archive---------19-----------------------
在这篇文章中,我们讨论了类不平衡的问题以及可能有助于提高模型性能的技术
(来源
介绍
当我开始学习机器学习及其各种子领域时,我参加了各种 MOOCs,阅读了各种文章、书籍等。我使用了各种免费的数据集并建立了模型,这些模型表现非常好。我当时的心态是,一切都依赖于我们使用的模型,数据只起次要作用。这种心态主要是因为数据是以干净、平衡的形式提供的,只需要很少的预处理。当我在一个研究所加入我的第一个机器学习角色时,这个信念遭受了重大挫折。该研究所专门从事医学研究,我的工作重点是超声图像。可用的数据不像公开可用的数据集那样清晰和结构化。以前我花大部分时间选择模型,现在我花大部分时间清理、构建和整理数据。此外,在公开可用的数据集中,类的分布几乎相似,如果不相似,每个类都有足够的代表性样本。但在现实世界中,尤其是在医疗领域,存在固有的阶级不平衡,因为患有特定疾病/病症的人与健康人相比要少得多。
当一个分类问题中一个或多个类别的可用示例数量远远少于其他类别时,类别不平衡就是问题所在。
样本数量多的类称为多数类,样本数量少的类称为少数类。在加入这个角色之前,我读到过关于类不平衡的问题,但从来没有机会处理不平衡的数据集,因为大多数在线可用的数据集都非常平衡,所有类都有几乎相同数量的样本。然而,我开始研究的第一批问题中有一个分布非常不均衡。这是一个二元分类问题,我应该检测给定的妇女是足月还是早产。早产是指妇女在怀孕不到 37 周时分娩,而足月是指妇女在怀孕超过 37 周时分娩。早产婴儿患有各种健康并发症,因为他们的器官没有正常发育,需要特殊护理才能存活。
据世卫组织称,每年有 1500 万婴儿早产,约 100 万婴儿死于早产引起的并发症。因此,检测早产是非常必要的,以便可以向婴儿提供足够的护理,并且可以挽救他/她的生命。
现有数据极不平衡,只有 300 名参与者分娩早产,而分娩足月分娩的妇女人数约为 3000 人。
这个问题很有挑战性,我开始研究阶级不平衡的话题和减轻它的技术。我发现网上大多数关于阶级不平衡的材料只提到了两种技术,即过采样和欠采样。在深入挖掘和阅读一些研究论文之后,我发现了一些其他不太为人所知的技术,我想在本文中与已知技术一起讨论这些技术。
注意:这篇文章中讨论的技术是从计算机视觉的角度来看的,但是由于核心概念保持不变,因此也可以应用到其他领域。
处理类别不平衡问题的技巧
处理类别不平衡的技术可以进一步分为两大类:
- 数据级方法
- 分类器级方法
数据级方法:
数据级方法是指我们在保持算法及其子部分(如损失函数、优化器)不变的同时,对训练集的分布进行更改。数据级方法旨在以某种方式改变数据集,使标准算法发挥作用。
有两种著名的数据级方法很容易应用于机器学习领域。
1.过采样:
过采样或者更准确地说,少数类过采样是一种非常简单且广为人知的技术,用于解决类不平衡的问题。在这种技术中,我们试图通过从所有类中采样相同数量的样本,从而从少数类中采样比多数类中更多的样本,来使小批量中所有类的分布相等。实际上,这是通过增加属于少数类的样本的采样概率,从而降低属于多数类的样本的采样概率来实现的。确定所有类别的抽样概率的最简单方法是取每个类别中样本数的倒数。这将增加样本属于少数类的概率,同时将降低样本属于多数类的概率。有些论文还用样本数平方根的倒数来衡量样本。
过采样的性能取决于原始数据集中代表性样本的数量,因为在过采样中,我们批量增加样本,但唯一样本的数量保持不变。
py torch 中实现少数类过采样的代码
图 1 :使用 Pytorch 加权采样器进行过采样的代码
图 2: 使用加权采样器进行过采样后的批量分配
2.欠采样:
用于解决类不平衡问题的另一种流行技术是欠采样,它与过采样相反。在这种情况下,我们从多数类中随机移除样本,直到所有类都具有相同数量的样本。这种技术有一个明显的缺点,因为它丢弃了可能导致数据集中代表性样本数量减少的数据。为了解决这个缺点,使用了各种方法,这些方法小心地去除冗余样本,从而保持数据集的可变性。
实现欠采样的一种简单方法是从多数类中随机抽取与少数类中样本数量相等的样本,同时保持少数类的分布不变。
为了在 Pytorch 中实现欠采样,可以使用 Pytorch 的 WeightedRandomSampler,其中多数类的权重应该减小,以便从多数类和少数类中采样几乎相同数量的样本。
例如:假设您有一个二元分类任务,其中多数类中的样本数为 2000,而少数类中的样本数为 1000。为了使用加权采样器进行欠采样,我们可以将属于少数类的所有示例的权重设为 1,即每个示例都有 100%的机会被采样,而对于属于多数类的示例,我们可以将权重设为 0.5(num _ samples _ minority/num _ samples _ majority),这意味着属于多数类的每个示例都有 50/50 的机会被采样。
py torch 中实现欠采样的代码:
图 3 :使用 Pytorch 加权取样器的欠采样代码
**图 4。**使用加权取样器进行欠采样后的批量分配
算法级方法:
算法级方法是处理类不平衡的一类方法,其目的是保持数据集不变,但改变训练或推理算法。
在这篇文章中,我将讨论我在处理不平衡数据集时常用的两种方法。
1.对成本敏感的学习:
在代价敏感学习中,基本思想是根据类的分布给类分配不同的代价。有各种实现成本敏感学习的方式,例如对属于多数类的例子使用比属于少数类的例子更高的学习率,或者使用类加权损失函数,该函数通过考虑类分布来计算损失,从而对来自少数类的例子的误分类比来自多数类的例子更加惩罚分类器。有各种类别的加权损失函数,但最广泛使用的两个是加权交叉熵和焦点损失。
**图五。**加权交叉熵损失方程
**图 6。**焦损失方程
WeightedCrossEntropy 使用经典的交叉熵损失,并加入了一个权重项,用于给特定类别(在类别不平衡问题中是少数类别)更多的权重。因此,当分类器错误分类属于少数类的例子时,交叉熵损失惩罚更多。
聚焦损失是由 FAIR 在他们的论文中首次介绍的,用于密集物体检测的聚焦损失被设计为以这样的方式执行两个任务来解决类别不平衡。
首先,与简单例子相比,它对困难例子的惩罚更多,并有助于算法更好地执行。难的例子是那些模型不自信并且以低概率预测事实真相的例子,而容易的例子是那些模型高度自信并且以高概率预测事实真相的例子。
例如,假设模型以 0.8 的概率错误地预测了某个类别,为简单起见,保持γ = 2,α = 1,log = log10,代入图 6 中给出的焦损方程中的值,我们得到
-(1–0.8)log(0.8)= 0.00387。
现在假设,模型以 0.2 的概率预测某个类别,保持上面我们得到的相同条件,
-(1–0.2)log(0.2)= 0.4473
如您所见,与模型过度自信的示例相比,模型不太自信的示例的焦点损失对模型的惩罚更大。
在类不平衡的情况下,由于少数类很少,模型很少看到它的例子,与拥有大量样本的多数类相比,模型在预测它时不太有信心(硬例子),而多数类反过来给模型更多的学习机会,因此模型在预测它时更有信心(简单例子)。
因此,焦点损失为少数类的实例提供了更大的权重,而为多数类提供了更小的权重,这反过来使得模型更加关注少数类,并提高了整体分类器的性能。
第二,类似于加权交叉熵,它在损失函数中有一个加权项。适当地设置权重项可以在错误分类少数类而不是多数类时对模型进行更多的惩罚。
焦点损失广泛用于对由于其上述两个属性而遭受类别不平衡问题的任务进行建模。
通过使用 Pytorch 中可用的交叉熵损失函数并指定权重项,可以在 Pytorch 中轻松实现 WeightedCrossEntropy,如下图 7 所示。
**图 7。**py torch 中的加权交叉熵损失码
要实现焦点损失,你可以参考文章从头开始实现,或者许多软件包为你实现,例如 Catalyst 、 Kornia 等。
2.一级分类:
顾名思义,一种类别分类是通过仅对少数类别的分布建模并将所有其他类别视为分布外/异常类别来处理类别不平衡的技术。使用这种技术,我们的目标是创建一个分类器,它可以检测属于少数类的例子,而不是区分少数类和多数类。这在实践中通过仅在属于少数类的实例上训练模型来完成,并且在测试时间期间使用属于所有类的实例来测试分类器正确识别属于少数类的实例的能力,同时标记属于其他类的实例。
一种类别分类技术以多种方式实现。计算机视觉应用中广泛使用的一种方法是使用自动编码器,我们在属于少数类的例子上训练自动编码器,并使其重新生成输入。现在,在测试时,我们传递属于所有类别的图像,并使用诸如 RMSE、MSE 等损失函数来测量模型的重建误差。如果图像属于少数类,则重建误差将会很低,因为模型已经熟悉其分布,并且对于属于除少数类之外的类的例子,重建误差将会很高。
现在你可能会想“但是我们怎么知道哪个误差低,哪个误差高呢?我们将使用什么阈值来决定给定图像是属于少数类还是异常?”。
在实践中,我们通过绘制差错率来确定阈值,差错率是通过传递属于所有类别的图像,然后选择能够清楚地区分少数和其他类别的值来获得的。
人们还取通过传递属于少数类的图像而获得的重建误差的均值 std。任何重建误差超过平均标准偏差的例子都被归类为异常。
经常使用使用神经网络和专门的单类分类器的混合方法。该方法包括两个阶段。在第一阶段,图像通过诸如 Resnet 的特征提取器,并且从模型的最后一层中提取特征。一旦要素被提取出来,它们就会被展平并传递给专门的 OCC 算法,例如一类 SVM 或隔离森林。分类器从特征中学习,并使用学习到的知识来分类一个例子是属于训练分布还是异常。
Sklearn 支持一些单类分类器,如 OneClassSVM 、 IsolationForest 等。应该使用交叉验证来调整这些模型的各种超参数,以获得更好的性能。
结论:
类别不平衡虽然在机器学习及其子领域中普遍存在,但却没有得到应有的重视,而且众所周知的技术是古老的,可能没有帮助。
因此,在这篇文章中,我试图解释一些我用来处理固有的职业不平衡的技巧。
然而,许多技巧在这篇文章中并未涉及,但对缓解班级失衡可能很重要。
如果你发现任何你认为有用的东西,并认为可能有助于改善这篇文章,我请求你在这里留言或通过我的 Linkedin 、 Twitter 与我联系。
我希望你喜欢这篇文章,并祝你有美好的一天:)
激励人心的名言:
“相信你能,你已经成功了一半”。
类别不平衡:带有不平衡学习的随机抽样和数据扩充
原文:https://towardsdatascience.com/class-imbalance-random-sampling-and-data-augmentation-with-imbalanced-learn-63f3a92ef04a?source=collection_archive---------3-----------------------
探讨了类别不平衡问题、准确性悖论以及利用不平衡学习库解决这一问题的一些技术。
图一。阶级失衡视觉描述|作者图片|图标取自维塔利-戈尔巴乔夫
开发用于分类的机器学习模型时出现的挑战之一是类别不平衡。大多数用于分类的机器学习算法是在假设类平衡的情况下开发的,然而,在现实生活中,拥有适当平衡的数据并不常见。由于这个原因,已经提出了各种替代方案来解决这个问题以及应用这些解决方案的工具。这就是不平衡学习 [ 1 ]的情况,这是一个 python 库,实现了最相关的算法来解决类不平衡的问题。
在这篇博客中,我们将看到什么是类不平衡,实现精度作为不平衡类的度量的问题,什么是随机欠采样和随机过采样,以及不平衡-学习作为一种替代工具,以适当的方式解决类不平衡问题。然后,博客将被划分如下:
- 什么是阶层失衡?
- 准确性悖论
- 欠采样和过采样
- 不平衡——在实践中学习
什么是阶层失衡?
当每个类别的样本不平衡时,类别不平衡的问题就出现了,也就是说,在类别的分布之间没有平衡的比率。这种不平衡可大可小。根据样本大小,从 1:2 到 1:10 的比率可以理解为轻微失衡,大于 1:10 的比率可以理解为强烈失衡。在这两种情况下,具有类别不平衡问题的数据必须用特殊技术处理,例如欠采样、过采样、成本敏感等等。稍后,我们将介绍欠采样和过采样以及它们与 imblearn [ 1 ]的实现。
准确性悖论
在处理分类问题中的不平衡数据时,要考虑的一个基本问题是要使用的度量标准。准确度通常被用作事实上的度量,但是对于类别不平衡问题,这不是一个好的选择,因为准确度可能会产生误导,这个问题更好地被称为 准确度悖论 。为了更好地理解 精度悖论 ,我们来看看图 2。
图二。准确性悖论|作者图片|图标取自 Freepik
当使用准确度作为衡量标准来评估用具有类别不平衡问题的数据集训练的机器学习模型时,结果可能会令人误解。正如我们所看到的,的准确度是 92%,这将使我们假设模型足够好。然而,如果我们仔细观察,我们可以看到模型学会了将所有东西分类为类 0,这产生了具有足够好的准确性的效果。在这些情况下,除了应用一些方法来修复类不平衡问题之外,建议引入其他评估指标,如精度、召回和 F1-Score。让我们看看图 3,以便更好地理解精度、回忆和F1-得分指标如何帮助我们更好地了解结果。
图 3。准确度、精确度、召回率和 F1 分数|作者图片
让我们看看刚刚发生了什么。准确性是一个衡量真阳性和真阴性之间平衡的指标,然而,当数据集呈现类不平衡问题时,模型将最有可能学习将所有东西都向主导类分类,在这种情况下向类 0 分类。因此,即使模型已经将 100%的数据分类为 0 类,考虑到真阴性的数量占主导地位,精确度也将足够好。这就是为什么当存在类别不平衡问题时,准确性度量经常会产生误导(准确性悖论)。
精度度量标准测量:“在所有被模型分类为阳性的元素中,有多少实际上是正确的”正如我们所观察到的,精度是完美的,这将使我们认为*“嗯,准确度和精度足够好了*”,然而这并不完全正确,因为在类别 1 的 10 个元素中,只有 2 个被正确分类,也就是说,8 个被错误分类,这可以在召回指标中观察到。
回忆度量标准:“被模型分类为正类的那些与被分类为负类但实际上是正的那些之间的平衡”。正如我们所看到的,召回值非常低,这给了我们一个信号,表明有些事情不对劲,也就是说,几个真正呈阳性的样本被归类为阴性。在一个真实的环境中,让我们想象阳性类别指的是"患有癌症",而阴性类别指的是"没有患有癌症",在这种环境中,我们会将许多真正患有癌症的人归类为没有患癌症的人,这将是一个灾难性的错误。
最后,为了概括精度和召回度量,我们实现了F1-分数度量,它被理解为精度和召回之间的调和平均值,换句话说,它提供了两个度量之间的比率。我们可以看到, F1-Score 值很低,这是另一个指标,表明有些事情不对劲(在我们的例子中,精度很完美但是召回很差)。
到目前为止,我们已经看到了什么是类不平衡问题,使用不平衡类的一些后果,以及在评估呈现类不平衡问题的模型时要考虑的一些指标。现在,让我们来看看可以用来调整类不平衡的一些替代方案,具体来说,让我们来看看应用基于欠采样和过采样的技术的效果。
欠采样和过采样
正如我们已经看到的,当等级分布之间没有平衡时,就会出现等级不平衡问题,也就是说,一个或多个等级相对于一个或多个剩余的等级可能是主导的。直观上,这个问题可以通过向少数类添加样本、从多数类移除样本或者两者的结合来解决。因此,从多数类中移除样本的过程称为欠采样,向少数类添加样本的过程称为过采样。
随机欠采样是指多数类的随机抽样。这一过程一直进行到少数群体达到平衡。虽然这种技术有助于在多数类和少数类之间建立平衡,但当从多数类中移除样本时,可能会丢失重要信息。
随机过抽样是指从少数类中随机复制样本。执行加法过程,直到相对于多数类达到平衡,然而,这种技术可能导致要训练的模型过度适合少数类。
随机欠采样和随机过采样可以理解为解决类不平衡问题的基本技术。今天,有更多有前途的技术试图改善基于随机的方法的缺点,如合成数据增强(SMOTE [ 2 ],ADASYN [3])或基于聚类的欠采样技术(ENN [ 4 ])。
好了,我们已经知道了基于欠采样和过采样的技术是什么,让我们看看如何在实践中实现它们吧!
不平衡——在实践中学习
不平衡学习是由 Guillaume lematre 等人 6 开发的开源 Python 库 5 ,它提供了一套处理类不平衡问题的算法。这样一套算法被组织成 4 组:欠采样、过采样、过采样和欠采样的组合和集成学习方法。出于我们的目的,此时我们将只使用欠采样和过采样扩展。
以下示例将使用一个不平衡数据集。将训练一个机器学习模型(决策树),并将评估度量准确度、精度、召回和f1-分数。随后,将应用下的和过采样算法,并且将再次评估前述度量,以在没有修复不平衡问题的情况下训练模型时获得的结果与应用欠采样和过采样时获得的结果之间进行比较。
所以我们先生成一个不平衡的玩具数据集:
代码片段 1。合成数据生成
生成的不平衡数据集将如图 4 所示:
图 4。不平衡数据集|作者图片
我们可以看到,生成的数据集呈现出类不平衡的问题,比例为 1:10。在应用欠采样和过采样算法之前,我们将定义一个能够用固定数据集训练决策树的函数。
代码片段 2。模型训练功能
正如我们已经观察到的,该函数实现了分层 K 折叠交叉验证技术,以保持每个折叠的类之间的平衡。
为了执行演示比较,我们将定义一组应用每种采样算法的函数(随机超过和下采样)、 SMOTE 以及 dummy 版本(该版本在不考虑类别不平衡问题的情况下训练决策树)。
代码片段 3。基于欠采样和过采样的技术
哑函数(第 6 行),用代码片段 1 中生成的数据训练一个决策树,而不考虑类不平衡问题。随机欠采样应用于第 10 行,随机过采样应用于第 17 行, SMOTE 应用于第 25 行。在图 5 中,我们可以看到当应用每种算法时,类平衡是如何转变的。
图 4。作者对随机抽样和 SMOTE | Image 的比较
如我们所见,欠采样算法从多数类中移除样本,使其与少数类对齐。另一方面,过采样算法复制了 minority 类的元素(您可以看到,该图类似于图 4 中的图)。最后 SMOTE (一种数据扩充技术),增加少数类的样本,直到它与多数类平衡。结果如图 6 所示。
图 6。结果
正如我们所看到的,当应用技术纠正职业平衡问题时,模型的有效性得到了提高。对于这个特殊的例子,基于合成数据扩充(SMOTE)的技术显示了更好的结果。归根结底,要实现的技术将完全取决于您正在处理的数据。值得一提的是不平衡学习提供了各种各样的算法来解决不平衡类的问题,值得看一看它的文档[ 1 ]。
结论
在这篇博客中,我们看到了类不平衡的问题,以及在处理不平衡数据集时必须考虑的指标。我们还看到了一个如何使用基于采样和数据扩充的算法来解决类不平衡问题的例子。我们还利用了不平衡学习库来扩展示例中使用的算法。
参考
[1]https://imbalanced-learn.org/stable/user_guide.html
[2] SMOTE:合成少数过采样技术
[3] ADASYN:用于不平衡学习的自适应合成采样方法
[4] 使用编辑数据的最近邻规则的随机属性
【https://github.com/scikit-learn-contrib/imbalanced-learn
[6] 不平衡学习:一个 Python 工具箱来解决机器学习中不平衡数据集的诅咒
分类损失的类别权重
原文:https://towardsdatascience.com/class-weights-for-categorical-loss-1a4c79818c2d?source=collection_archive---------16-----------------------
当数据集不平衡时,类权重通常用于分类问题。我们在引擎盖下看这个。
Suket Dedhia 的绘画作品
在寻找关于类权重的“确切”解释时,我不仅没有找到任何东西,对 tensorflow 和 PyTorch 中的实现进行逆向工程,我发现它们并不一致。因此,在这篇笔记中,我将以二进制分类问题为例来研究数学。之后,我还将很快讨论多类分类问题。
二元分类
不平衡数据集是指不同类别的数据点数量相差很大的数据集。有几种方法可以解决这个问题(欠采样、过采样、增加显式偏差和类别权重在张量流示例中讨论),这里我们将讨论类别权重。
让我们来看一个标签为 0 和 1 的二元分类问题。类权重的传统选择是
虽然最近讨论了一个更复杂的方法。
一个数据点的分类交叉熵损失函数为
其中,y=1,0 表示阳性和阴性标签,p 是阳性类别的概率,w1 和 w0 是阳性类别和阴性类别的类别权重。
对于 minibatch,PyTorch 和 Tensorflow 的实现有一个归一化的区别。PyTorch 有
而 Tensorflow 有
当批量较小时,这两者之间的差异很重要(对于较大的批量,大数法则抑制 PyTorch 实现中的批量相关波动)。
让我们看看最后一层的梯度下降。其余的使用简单的链式法则/反向传播。我们将重点关注一个数据点的损失。批次的结果是这些的平均值,并且取决于如上所述的特定实现。类别 1 的概率是
而类 0 的是 1-p。W 是权重向量,x 是前一层的输出。我忽略了对简单性的偏好。
简单的微积分表明,损失相对于重量的梯度为
这给出了对重量的修正
先看看这个没有类权重的例子,看看会发生什么。**如果样本为正类,即 y=1,则梯度指向 x 方向,向量长度与(1-p)成正比。概率离 1 越远,这个向量就越长。相反,如果样本属于负类,即 y=0,则梯度指向 x 的对面,向量的长度与 p 成比例。p 离 0 越远,向量越长。**想想这个,说服自己这是正确的行为。
现在,当我们打开级重量时,我们看到它们调整前述长度。我们取 p=0.5。在这种没有类权重的情况下,y=1 和 y=0 的梯度向量将分别沿着 x 和逆着 x 具有相等的长度。然而,如果 w1 > > w0,那么 y=1 的梯度向量将比 y=0 的梯度向量长得多。这将使前一种情况下对 w 的修正比后一种情况下大得多。w1 < < w0 时反之适用。
多类问题
为了完整性(你将看到额外的简单性),让我们也做多类问题。在这种情况下,交叉熵损失为
其中 alphas 是类权重(很抱歉切换通知,但是随着额外权重的继续,使用‘w’表示类权重会变得混乱)
softmax 下第 I 类的概率由下式给出
这很容易验证(如果看起来不容易,那么你应该实际计算并说服自己)
利用我们得到的链式法则
具体地看将是有启发性的,因此,不失一般性地,让我们假设真正的标签是 y0=1,而所有其他的 y 是 0。然后我们得到类的权重更新为正
正确类别的权重更新将权重与 x 对齐,并且如果强度与预测的偏离程度和正确类别的类别权重成比例,则强度与 x 对齐
而对负的类的权重更新是
不正确类别的权重更新使权重与 x 不对齐,并且强度再次与预测的偏离程度成比例,但是注意,它们与正确类别的权重成比例,而不是与不正确类别的权重成比例。如果人们盯着损失函数看一段时间,后一个事实就很明显了。
注意,校正的效果是使正确类的权重与 x 更加对齐,而不正确类的权重与 x 更加不对齐。
函数式编程中的“类”?
原文:https://towardsdatascience.com/classes-in-functional-programming-ee48a50b6235?source=collection_archive---------10-----------------------
小窍门
用 currying 模仿 Python 中的类的行为
作者:爱德华·克鲁格、斯蒂芬·莱西和道格拉斯·富兰克林。
照片由迈克尔·里维拉·🇵🇭在 Unsplash 上拍摄
Python 非常适合面向对象编程(OOP)。面向对象编程关注的是由属性和方法组成的对象。属性是数据,方法是作用于属性和其他数据的函数。类在 Python 中很常见。
一个类可以被认为是一个对象的蓝图。Python 程序员通过使用关键字“class”并添加定义它的属性和方法来创建类。一旦我们有了蓝图,我们就可以轻松地重用它们来创建一个实例。
因为 Python 是一种多范例语言,所以它不仅可以用于面向对象编程,还可以用于函数式编程!您可以编写一个使用其中一种范式甚至两种范式的 Python 程序。
面向对象编程将逻辑和数据结合成对象,而函数式编程将逻辑和数据分开。我们将说明这两种范例都可以用来获得相似的结果。
先说功能性的。程序员往往更熟悉 OOP。
什么是 currying,它如何表现得像一个类?
Currying 是将接受多个参数的函数简化为单参数函数的过程。
我们可以把班级想象成一个蓝图。让我们把 currying 想象成一个生产函数的工厂——在下面的例子中,是柑橘榨汁机。
咖喱和水果榨汁机
让我们用一个柑橘榨汁机厂的例子,他们生产的柑橘榨汁机和新鲜果汁来解释 currying。
照片由 Edgar Castrejon 在 Unsplash 上拍摄
柑橘榨汁机厂回一个柑橘榨汁机,是取水果,回果汁的功能。那么,我们怎样才能从一家生产榨汁机的工厂变成一杯新鲜的果汁呢?
我们追求功能。看看下面的代码。
注意我们如何与第 31 行及以下的函数交互。首先,我们使用citrus_press_factory
创建一个名为lemon_press
的新函数。然后我们通过“lemon”
和“lime”
到我们的lemon_press
去取一些新鲜的果汁,味道很好但是有点酸。
我们去喝点更甜的吧,橙汁。在第 34 行,我们试图传递一个“orange”
到我们的 lemon press 中,产生一个错误。看起来柠檬榨汁机只能用柠檬和酸橙!如果我们真的想做橙汁,我们就必须用我们的citrus_press_factory
来做一个橙子榨汁机!
试着用柠檬榨汁机榨橙汁
根据工厂规范,我们似乎可以做一个柚子压榨机来榨出一些柚子汁。但是当我们试图在第 36 行为此目的制作一个 pomelo press 时会发生什么呢?
试图在我们的柑橘工厂制造一台柚子压榨机
看起来我们又遇到了一个错误。要创建一个citrus_press
的实例,你必须使用citrus_press_factory.
中的一个有效值。类似地,要制作一些果汁,你向citrus_press
传递一个水果,它可以用它作为输入。
既然我们已经理解了 currying,那么让我们用一个 Python 类并把它重写为 currying 模式。
Python 类—口袋妖怪
在下面的例子中,我们创建了一个名为 Pokemon 的类。当我们在第 5 行使用带有参数self
和sound
的__init__
方法时,Pokemon 类被实例化。
要了解更多关于 Python 中的类的背景知识,请阅读由 Sadrach Pierre 博士撰写的文章
接下来,我们在 Pokemon 类中创建一个名为cry
的方法,该方法返回sound
。在这种情况下,sound
是数据,cry
是逻辑。注意类Pokemon
如何将数据存储为self.sound
。
既然 Pokemon 类已经创建好了,我们可以用它来创建一个对象。在第 23 行,我们创建了一个名为pikachu
的类实例,并传递了sound
“Pika”第 24 行显示pikachu.cry()
返回“Pika”
我们如何用数据和逻辑分离来创建这种行为?
“T21”怎么能产生类似的结果呢
如前所述,我们使用 currying 将多参数函数分解成连续的单参数函数。为此,我们首先在第 11 行创建一个名为make_pokemon
的函数,它接受参数sound
并返回cry
。函数cry
返回传递给make_pokemon
的sound
。
让我们调用这些函数来说明它们的行为。回想一下我们的果汁压榨机的例子!
通过将make_pokemon(“Pika”)
的结果存储为pickachu_cry
,我们创建了一个新函数,在被调用时返回“Pika”。
我们看到两者:
和
回报同样的叫声,“鼠兔。”
这表明创建一个类和使用固化可以产生相同的结果。在这两个例子中,我们都创建了可重用的代码。此外,这两个选项都允许程序员在程序中的单个位置对代码进行更改。
经典 Seq2Seq 模型与 Seq2Seq 模型对比注意
原文:https://towardsdatascience.com/classic-seq2seq-model-vs-seq2seq-model-with-attention-31527c77b28a?source=collection_archive---------20-----------------------
现在就来关注一下吧!
阿图尔·图马斯扬在 Unsplash 上的照片
“我需要关注。我喜欢这种关注。”—比尔弗利
介绍
在本文中,我们将分析一个经典序列对序列(Seq2Seq)模型的结构,并展示使用注意力解码器的优势。
这两个概念将为理解 论文中提出的变压器注意力是你所需要的全部。
Yoshua Bengio 分享了在人工智能中使用注意力机制来训练意识的价值。
目录:
- 什么是 Seq2Seq 模型?
- 经典的 Seq2Seq 模型是如何工作的?
- 注意
什么是 Seq2Seq 模型?
在 Seq2seq 模型中,神经机器翻译接收单词序列形式的输入,并生成单词序列作为输出。
从例子来看,“Cosa vorresti ordinare?”在意大利语中作为输入,变成“您想点什么?”作为英语输出。
或者,输入可以是一幅图像(图像字幕)或一长串单词(文本摘要)。
来源:图片由作者提供。
经典的 Seq2Seq 模型是如何工作的?
Seq2Seq 模型通常包括:
- 一个编码器
- 一个解码器
- 一个上下文 ( 向量)
请注意: 在神经机器翻译中,编码器和解码器都是 RNNs
编码器通过将所有输入转换成一个向量来处理它们,这个向量被称为上下文(通常长度为 256、512 或 1024)。上下文包含编码器能够从输入中检测到的所有信息(记住,在这种情况下,输入是要翻译的句子)。
最后,向量被发送到解码器,解码器形成输出序列。
神经机器翻译中的时间步骤
现在我们已经对序列到序列模型有了一个高层次的概述,让我们简要地分析一下输入是如何被处理的。
来源:图片由作者提供。
时间步骤#1: 意大利语单词“Stai”被发送到编码器
编码器根据其输入和先前输入更新其隐藏状态(h1)。
时间步骤#2: 字“attento”被发送到编码器
编码器基于其输入和先前输入更新其隐藏状态(h2)。
时间步骤#3: 单词“Thomas”被发送到编码器
编码器基于其输入和先前输入更新其隐藏状态(h3)。
时间步骤#4: 最后一个隐藏状态成为发送给解码器的上下文
解码器产生第一输出“Be”
时间步骤#5: 解码器产生第二输出“小心”
时间步骤#6: 解码器产生第三输出“托马斯”
编码器或解码器的每一步都是 RNN 处理其输入并生成该时间步的输出。
你可能注意到了,我们最后的隐藏状态( h3 ) 变成了发送给解码器的内容。在这个中存在经典序列对序列模型的限制;编码器“被迫”只发送一个向量,而不管我们的输入有多长,也就是说,我们的句子由多少个单词组成。
即使我们决定在编码器中使用大量的隐藏单元,目的是拥有更大的上下文,那么模型会过度拟合短序列,并且随着我们增加参数的数量,我们会受到性能的影响。
这就是注意力解决的问题!
注意力
至此,我们明白了要解决的问题在于上下文向量。这是因为,如果输入的是一个包含大量单词的句子,那么模型就会有问题。
bah danua 等人和 Loung 等人提出了解决方案。这两个出版物介绍并完善了“注意”的概念。这项技术通过关注输入序列的相关部分,使得机器翻译系统有了相当大的改进。
直觉 seq 2 seq 模型中的编码器与经典的编码器工作方式相似。这一次接收一个单词,并产生下一步使用的隐藏状态。
随后,与之前不同,不仅最后的隐藏状态(h3)将被传递到解码器,而且所有的隐藏状态都将被传递到解码器。
来源:图片由作者提供。
让我们更好地关注发生在编码器和注意力解码器内部的过程。
编码器
在到达编码器之前,我们的句子的每个单词都通过一个 嵌入过程 转换成一个向量(大小为 200,或 300)。
中的第一个字,在我们的例子中是“Stai”,一旦它转换成矢量就被发送到编码器。这里 RNN 的第一步产生了第一个隐藏状态。对于第二个的和第三个的字,同样的情况发生,总是考虑先前的隐藏状态。
一旦我们的句子的所有单词都被处理完毕,隐藏状态( h1,h2,h2 ) 将被传递给注意力解码器。
编码器。来源:图片由作者提供。
注意力解码器
首先,一个重要的过程发生在注意力解码器中:
- 每个隐藏状态被分配一个分数。
- 分数经过一个 softmax 函数。
- 隐藏状态和相关的 softmax 分数相互相乘
- 最后,将获得的隐藏状态相加以获得单个向量,即上下文向量。
这个过程允许我们放大序列中的重要部分,减少不相关的部分。
至此,我们要明白分数是如何分配给每个隐藏状态的。你还记得 Bahdanau 和 Luong 吗?嗯,为了更好地理解注意力解码器内部发生了什么以及分数是如何分配的,我们需要说一些关于倍增注意力的更多事情。
乘法注意力是通过开发先前为加法注意力所做的工作而发展起来的。
在论文《基于注意力的神经机器翻译的有效方法》中,Loung 引入了几个评分函数:
- 点积
- 一般产品
- 串联产品
从上到下:1) 点积,2) 一般积,3) 串联积。来源:图片由作者提供。
在本文中,我们将分析 g 一般产品注意事项(2) 。
这是因为,在我们的情况下,一旦确立了每种语言都倾向于有自己的嵌入空间,那么编码器和解码器就没有相同的嵌入空间。
多亏了这个产品,分数将由解码器的隐藏状态、权重矩阵和编码器的隐藏状态集合相乘得到。
现在我们知道了分数是如何计算的,让我们试着理解一下注意力解码器在 Seq2Seq 模型中是如何工作的。
在第一时间步,注意力解码器 RNN 接受 <结束> 令牌的嵌入,以及初始解码器隐藏状态。RNN 处理其输入,产生一个输出和一个新的 解码器隐藏状态向量(h4) 。输出被丢弃。
从这里开始注意步骤:
1-每个 编码器隐藏状态 被分配一个 分数 从 获得一般生产注意 。
一般产品注意事项。来源:图片由作者提供。
2-分数经过一个 softmax 函数。
Softmax。来源:图片由作者提供。
3- 编码器隐藏状态 与相关的of max 分数 相乘。将得到的隐藏状态相加,得到**【C4】**。
语境。来源:图片由作者提供。
4-上下文向量(c4)* 与 解码器隐藏状态(h4) 串接。
源自拼接的向量通过 完全连接的神经网络 ,其基本上乘以权重矩阵(Wc) 并应用双曲正切激活。
这个全连接层的输出将是我们在输出序列中的第一个输出单词(输入:“Stai”->输出:“Be”)。*
来源:图片由作者提供。
第二时间步从第一步的 输出【Be】开始,并随着 解码器产生隐藏状态(h5) 。接下来是上述的注意步骤*。
重复以下时间步骤所述的过程。*
注意解码器。图片由作者提供。
结论
如果你设法来到这里,恭喜你!非常感谢你花时间阅读这篇文章。
希望这篇文章已经让你对经典 Seq2Seq 模型*,以及 Seq2Seq 带注意模型有了很好的初步了解。
如果你注意到任何思维方式、公式或形象上的错误,请告诉我。最后但同样重要的是,如果你想深化所涉及的主题,我在下面给你留下了一些非常有用的资源:*
- C5W3L07 吴恩达注意力模型直觉
- chaud Hari 等人对注意力模型的仔细调查
- 杰伊·阿拉姆马的可视化神经机器翻译模型
- 深度学习 7。DeepMind 深度学习中的注意力和记忆
再次感谢您阅读我的文章。如有任何问题或信息,可在 LinkedIn 联系我,或在下方留言评论。
参考资料:
- Bahdanua 等人,“通过联合学习对齐和翻译的神经机器翻译”
- Loung 等人,“基于注意力的神经机器翻译的有效方法”
- 可视化神经机器翻译模型(Seq2seq 模型的机制,注意)Jay Alammar
分类决策树,容易解释
原文:https://towardsdatascience.com/classification-decision-trees-easily-explained-f1064dde175e?source=collection_archive---------22-----------------------
决策树是更高级的机器学习模型的构建模块之一。说到分类问题,它们到底是如何构建的?
照片由@ szmigieldesign@ unsplash.com 拍摄
不不管你在数据科学方面多么有经验,你可能听说过决策树。这种简单易懂的算法受到很多人的喜爱,是许多算法的基础,这些算法赢得了大量机器学习竞赛,并引导项目走向成功。
Random Forest、XGBoost 或 LightGBM 是一些基于 if-else 规则构建算法的简单而有效的算法。
决策树到底是怎么构建的?它如何选择组成规则的变量和阈值?如果你一直想了解这个算法是如何工作的,你来对地方了。
让我们从一个简单的角色扮演挑战开始。
我们有装有两枚鸵鸟蛋的盒子——我们需要将这些盒子海运到其他国家。我们已经做了一个实验,发送了 38 个盒子来测试两个鸡蛋是否安全到达目的地— 然后我们用散点图绘制两个鸡蛋的重量,试图了解这些变量与包装结果之间是否有任何关系:
鸡蛋的重量和包装的有效性
蓝点由安全抵达目的地的箱子组成。不幸的是,我们的一个或两个鸡蛋打破了,我们的包装被认为是无效的。
(还是救几只鸵鸟吧!)
来源:https://giphy . com/gifs/natgeowild-NAT-geo-wild-鸵鸟-国家地理-i3R0nglQHQipENYJkG
在与快递员核实后,您了解到,当您发送两个非常重的鸡蛋时,它们会相互挤压并可能破裂。当你送两个太轻的鸡蛋时,它们有太多的空间在盒子里移动,并折叠到它的边界。为了避免浪费大量的箱子,您希望构建一个算法来告诉您哪些箱子对于海外旅行应该是有效的。
对于一个人来说,执行某种 if-else 规则并在上面的例子中画出一些边界似乎很容易。类似这样的快速草图:
If-Else 规则用于区分有效和无效的包
这些象限产生以下 if-else 规则:
- 如果蛋 1 >的重量为 2.66 而蛋 2 >的重量为 1.95 ,则包装很有可能会破损。
- 如果蛋 1 的重量< 2.66 和蛋 2 的重量> 1.95 ,则包裹很有可能完好无损地到达。
- 如果蛋 1 <的重量为 2.66 而蛋 2 <的重量为 1.95 ,则包装很有可能会破损。
- 如果蛋 1 > 2.66 的重量和蛋 2 < 1.95 的重量,则包装很有可能完好无损地到达。
有了这些规则,我们可以很容易地建立一个系统,让我们决定是否应该把包裹送到海外。
基于这一系统,让我们将我们的分类形象化:
因此..如果人类可以在自己身上做到这一点,为什么要使用算法呢?主要问题是大多数数据集并不像我们上面看到的那样排列整齐(99.9%确定大多数真实生活中的数据集看起来不是这样的,我可以向你保证)——那么用 3 个以上的变量来绘制这些边界呢?疯狂的不可能!
这就是为什么我们需要机器来为我们做这些工作。
进入决策树!
决策树实际上非常简单,可以用一句“简单”的话来概括:“决策树是一种算法,它递归地在空间中搜索可能的最佳边界,直到我们无法这样做为止”。让我们去掉行话,从数学上把这句话分解一下。
想象一下,我们的第一次分割不是一个最佳分割——蛋 1 的重量超过或小于 1.5:
我们的树的次优分割—蛋 1 的重量≥ 1.5
这个决策界限并没有真正划分“盒子”或象限中的类。使用这个规则会给我们一个次优的分类,因为我们不能很好地将有效的和损坏的包分开。让我们画一棵真正的树,展开我们的论点,只是为了好玩:
鸡蛋 1 重量≥ 1.5 公斤的拆分生成的树(图标归属:Stockio.com)
在右边的分支中(我们一会儿会谈到树的解剖),我们有 19 个有效的包和 9 个破损的包。当蛋 1 的重量较高时,包装完好无损地到达的概率较高(19/28 或大约 68%)。另一方面,包裹到达时破损的概率是 9/28 。
如果你看左边的节点,包有效或破损的概率是完全一样的,5/10 或 50%。我们很难对低于 1.5 阈值的点进行分类,因为每个类别中的示例数量没有差异。
看起来这基本上是一个抛硬币的过程——用“树的语言”来说,这意味着这是一个真正不纯的节点。
理解这是否是一个好的分裂的关键是量化由这个分裂产生的两个节点的杂质。从正确的节点开始:
我们的分裂决策树的右节点——蛋 1 的权重≥ 1.5(图标归属:Stockio.com)
杂质始于概率,我们现在已经如下:
- 有效包的概率— 19/28 = 67.85%
- 包装破损的概率— 9/28 = 32.15%
我们现在引入一个非常重要的概念,称为基尼不纯度,这是一个让我们为每个分割赋值的概念,如果你研究过其他算法,这将类似于成本函数,我们希望选择具有最小 G ini 不纯度的分割。
为了对节点做出最终决定,我们需要计算分割中每个节点的部分杂质——对于该节点,部分基尼杂质为以下公式(其中我们插入有效包和破损包的概率):
这将产生 0.43622 的值。较低的部分杂质意味着更好地分离类别的节点。
好了,我们有了右节点的值——让我们计算左节点的部分杂质,从概率开始:
我们的决策树的左节点具有分裂-蛋 1 的权重< 1.5 (icon attribution: Stockio.com)
- Probability of valid package — 5/10 = 50%
- Probability of broken package — 5/10 = 50%
Now we can calculate the 左节点的部分杂质:
右节点的部分杂质是 0.5。注意它是如何变高的,因为当我们想要分开这些类的时候,我们有一个更困难的时间。
**我们如何将两部分杂质结合起来?**这是容易的部分!我们将根据每个节点的样本数量对杂质的平均值进行加权,逐步计算:
- 右节点 28 例;
- 左侧节点上的 10 个示例;
- 右节点部分杂质= 0.43622;
- 左节点的部分杂质= 0.5;
分裂整体的杂质是(鼓点!):
来源:https://giphy.com/gifs/GBvkxysAR8Svm
乌夫,终于!这种分裂的基尼系数是 0.4565——我们现在有一个单一的值可以附加到这个阈值上,并可以与其他潜在的候选值进行比较。
通过设计,我们将希望选择将实现最小杂质的分离,因为该分离将转化为更好的分类。
让我们测试另一个分裂!例如,鸡蛋 1 的重量> 2.3:
为我们的蛋重 1 ≥ 2.3 的树拆分。
这种分割会生成以下树:
蛋重 1 ≥ 2.3 生成的树。(图标归属:Stockio.com)
看来这根本就不是一个好的分裂!这两个类在两个叶节点中似乎是平衡的。“叶子是什么?” —你问。
在计算这种分割的基尼系数之前,有必要检查一下决策树的结构:
决策树的剖析(图标归属:Stockio.com)
- 根节点是我们的树的底部,在分裂之前,我们在那里有我们所有的鸡蛋盒子。
- 分支由应用 if-else 规则后盒子将采用的每条路径组成。
- 叶节点由盒子将结束的节点组成,取决于上面的分支。
- 如果树有不止一级的深度(我们马上就能到达那里!)然后叶节点变成内部节点。
让我们来分析一下这种分裂的数字,看看我们的基尼系数:
- 右节点的部分杂质是 0.4753
- 左节点的部分杂质是 0.455
鉴于此,我们对这种分裂的基尼不纯是(击鼓!):
来源:https://giphy.com/gifs/GBvkxysAR8Svm
这次分裂的基尼系数比我们测试的第一次分裂更差。这是有意义的,因为大多数类在两个节点中似乎是平衡的。
那么……我们如何找到最佳分割?
递归搜索整个空间的可能分裂可能是一个好主意!这实际上是决策算法在内部做的事情。
如果我们计算“鸡蛋 1 的重量”变量中所有可能分裂的基尼系数杂质,我们将得到一个如下图:
鸡蛋重量的所有可能阈值的基尼系数杂质的“成本函数”图 1
上面的图表明,当我们选择“鸡蛋重量≥ 1”作为阈值时,杂质在某处最小化——让我们检查一下这是否是真的,可视化我们的树与该分裂:
蛋的重量 1 ≥ 1 生成的树。(图标归属:Stockio.com)
- 右节点的部分杂质是 0 . 444;
- 左节点的部分杂质是 0.48;
这种分割的基尼系数可以用以下公式计算:
这与我们在递归搜索中实现的最小分割相匹配,应该是我们的第一次分割(应该吗?)!
...
记住我们有两个变量!如果蛋 1 的重量不是用来划分我们的类的最佳变量呢?
让我们检查鸡蛋 2 变量重量的每个分割的杂质图:
在鸡蛋重量的所有可能阈值上的基尼系数杂质的“成本函数”图 2
对于鸡蛋 2 的重量,我们可能有一个候选值——0.95 和 1 之间的区间可能是一个很好的第一次分割。
为了说明这一点,我们现在测试的是:
为我们的蛋重 2 ≥ 0.95 的树拆分。
卵重 2 ≥ 0.95 生成的树。(图标归属:Stockio.com)
- 右节点的部分杂质是 0 . 444;
- 左节点的部分杂质是 0.48;
这与我们看到的“鸡蛋 1 的重量”最佳分割模式完全相同!所以,我们最后的计算还是:
我们有了决策树的起点!根据您将用来使树适应数据的系统,可能会选择以下两种之一:
- 鸡蛋的重量 1 < 1 and Weight of Egg 1 ≥ 1
- Weight of Egg 2 < 0.95 and Weight of Egg 1 ≥ 0.95
为什么?因为这些是最小化基尼系数 的阈值——我们的例子中有一个平局,这在现实世界的数据集中并不常见。
但是..我们现在去哪里?
我们种植我们的树!
让我们关注一下左叶节点:
卵重 2 ≥ 0.95 生成的树。(图标归属:Stockio.com)
**左边的节点对应于所有低于阈值的例子。**如果我们只对这些例子进行递归搜索,我们将会发现一个完全纯粹的分割——注意新的垂直阈值,橙色:
蛋重 1 ≥ 2.9 的新阈值。
这对应于以下树:
用两级阈值生成的树(图标属性:Stockio.com)
作为分支“鸡蛋重量 2 < 0.95”的结果的叶节点现在是内部节点。为什么?因为它会让更多的树枝向前延伸!
新的叶节点是由分支使用“鸡蛋 1 的重量”生成的,您可以在内部节点的正下方看到它。
如果您进行计算,这些新节点将具有:
- 左节点有部分杂质=0。
- 右节点有部分杂质=0。
这个拆分的基尼杂质是什么?没错,0!
这意味着这是一个纯节点,因为它完美地划分了我们的类。过了这一点就不能分班了。
另一个分支呢?通过再次迭代我们的分类树,我们将达到一个新的阈值:
用两级阈值生成的树(图标属性:Stockio.com)
又一个纯节点!这种分裂的基尼系数的详细情况是:
- 偏杂左节点: 0
- 部分杂质右节点 : 0.4770408
- 基尼杂质 为拆分:0.4047619
现在,我们可以继续沿着我们的树往下,以产生更多的阈值,直到我们在所有的叶节点上达到节点纯度*。*
生成的最终阈值为:
请注意所有点是如何被分组到它们的小“盒子”中的。下面是我们今后如何对我们的观点进行分类:
如果我们收到一组新的盒子,我们会将它们放入这些方块中的一个,根据方块的颜色,我们将知道是否应该发送我们的鸡蛋— 我们已经建立了分类树算法!
一个挑战:你能自己画出由这些阈值生成的树吗?
最后的想法
- 达到节点纯度并不是阻止树生长的唯一(可能也不是最好的)标准。达到节点纯度很可能意味着您的模型只适合训练数据,而不能很好地适用于真实世界(这是每个预测模型的真正目标)。
- **与上面的论点相关,决策树确实容易过拟合。**您可以根据 if-else 规则隔离样本中的几乎所有示例,但这几乎肯定会导致算法过度拟合。
- 有时,输入的微小变化(从原始数据中选择特定的样本)可能会导致树的结果产生巨大的差异。
- **关于决策树,下一步要学习的是理解超参数调整和交叉验证的概念。**它们是保证你的决策树在未来使用新样本时足够健壮的关键——我们将在下一篇博文中探讨这些概念。
- 自从引入随机森林以来,决策树很少在生产中使用,因为随机森林更健壮,一般来说——我们还将在后续的博客文章中介绍随机森林。
- 基尼系数并不是决定最佳分割的唯一公式(例如,熵也可以用作一个标准)。
- **对于回归树,基本原理是相同的,**但是不使用基尼系数,而是使用回归的误差度量(通常为均方根误差)。
感谢你花时间阅读这篇文章!我希望你喜欢它,它帮助你最终理解了决策树背后的数学和逻辑。
想了解更多?在 Udemy 上查看我的 R 的数据科学课程,在这里我们将接触更多的算法,并深入研究数据科学概念。
本课程是你成为数据科学家的第一步,我们将慢慢地理解所有概念,并注意理解算法背后的基础和理论。本课程是你进入数据科学世界的无风险(30 天退款政策)机会,我非常希望你成为我的学生!
安全操作中的分类
原文:https://towardsdatascience.com/classification-in-security-operations-dc6f43adcae8?source=collection_archive---------36-----------------------
奇莫诺在 Pixabay 上的照片
网络安全行业的每个人都在争先恐后地获取必要的人工智能和机器学习,以领先于攻击者。虽然许多网络安全公司肯定只在一次次的流行推销中使用人工智能/人工智能,但大多数网络安全专业人士确实认为人工智能/人工智能在安全领域有其一席之地。
ML 或任何数据分析的基本问题是分类。安全运营中心不断解决一系列分类问题。给定一些输入数据集,安全分析师首先必须确定活动是恶意的还是非恶意的。因此,第一个问题是二元分类。在下图中,我将这个问题进一步分解。红点标记分类发生的位置,黄框标记分类的结果。
事件检测(作者图)
分类决策 1:这些数据对检测有用吗?
安全分析师喜欢他们的日志和 IDS 警报,但所有数据都需要持续仔细检查,以确定与事件检测的相关性。安全工程师不仅要考虑删除无用的事件检测源,还要考虑添加新的创新数据源。一般来说,人类不会操作循环的这一部分——SOC 尽可能从网络和日志中获取数据,并希望这些数据足以满足他们的工作需求。因此,AI/ML 自然适合这里。主机计算能力是主要的阻碍因素;因为如果主机必须智能地确定哪些数据可以帮助实时检测,它将使用计算开销来运行这样的算法。无论系统选择发送什么数据,都将传递给下一个分类决策。
分类决定 2:这是一个事件吗?
在决定将哪些数据传递给我们的入侵检测系统后,入侵检测系统必须决定这些数据是否属于恶意活动。这是一个二元分类问题,那么为什么上图是三种情况呢?机器学习工程师将开发一种算法,以根据输入的训练数据来确定系统数据是否表征了事故。该算法将返回事件发生的概率。因此,案例代表了这个返回概率的阈值。分析师必须确定适当的阈值以避免警报疲劳,并每天处理适当数量的警报。情况 1 的阈值将非常高。请注意,由于事件发生的频率较低,因此这可能不是一个接近 1 的阈值—情况 1 的阈值实际上可能非常接近于 0,仅比下一个阈值大。情况 2 的阈值仍然很高,但会生成几个警报。这将使分析师能够通读生成警报的数据,并决定如何对事件进行分类。SIEM 反馈决策点的循环代表了这个迭代过程。
事件调查和响应
NIST 网络安全框架将网络安全事件定义为“被确定会对组织产生影响,从而需要响应和恢复的网络安全事件”我从来不喜欢这个定义,这里我们需要一些更具体的东西。我更喜欢一个简单的定义:网络安全事件是分析师决定进一步调查的事件。这自然导致了 NIST 网络安全框架在响应分析中的第一项:“来自检测系统的通知被调查。”事件调查和响应也是分类问题。下图显示了三个二元分类问题,分析师必须解决这些问题才能在事件生成后关闭事件。
事件调查和响应(作者提供的数字)
分类决定 3:上下文数据的充分性
分类再次回到所提供数据的质量。决策点 2 根据决策点 1 的数据对事件进行分类,但这些数据侧重于检测而非调查。换句话说,我们只需要回答这个问题:这种反常的行为是我们应该调查的吗?现在我们需要回答:到底发生了什么,我们如何解决?为了回答这些问题,分析师可能需要查询额外的数据源。AI/ML 在这里可以提供重要的价值,因为它可以根据上下文数据快速确定哪些数据可能对分析师的调查有用,并自动将这些数据添加到事件案例对象(数据水合)中,供分析师进一步审查。
分类决定 4:真实事件
在收集额外的上下文数据的过程中,分析师将经常确定该事件是误报。在这种情况下,她会简单地关闭事件,而不会发现。这个错误总是会发生,因为上下文数据是集中的和大量的。将该判定点移回判定点 2,从而要求所有可能必要的上下文数据命中 IDS,这将使网络过载,并使事件检测成为计算上不可能的任务。两步事件确定使用分类,以减少计算和网络需求。因此,该步骤中的 AI/ML 算法需要适应分析师添加到上下文数据中的输入。算法可以在后台连续运行,或者在事故案例文件改变时运行,以改变在分类决策 2 中生成的事故可能性值。
分类决定 5:减缓成效
有一天,我们的人工智能霸主可能会基于上下文数据自动生成缓解措施。然而,现在分析师必须在调查完成后运用他们的最佳判断来制定缓解措施。分析师使用归纳推理和科学方法,而不是演绎推理。换句话说,他们必须利用自己的最佳判断来制定缓解措施,并通过测试来验证这些措施,而不是通过一系列关于事故的“如果-那么”陈述来得出一组正确的缓解措施。实际执行缓解后,如果缓解成功,分析师将关闭事件。分析师将开发自动测试,在开发缓解措施时验证他们实现的缓解措施。由于分析人员已经构建了这些测试,并且它们自然地从缓解开发中出现,AI/ML 在这个决策点上没有表现出显著的价值。
针对机器学习和分析问题
那些不熟悉安全操作的人可能认为单个 ML 算法可以帮助并最终取代安全分析师。虽然这样的超级机器可能有一天会存在,但上述五个决策点中的每一个都代表了一个具有不同数据源和所需分类结果的独特问题。事实上,上面的图片和将安全运营缩小到五个决策是对安全运营挑战的过度简化。这种简化的价值在于确定我们可以从哪里开始使用机器学习来提高安全运营的效率。机器学习工程师应该寻求在这五个决策点中的一些点上实现分类,以便帮助、缓解和关注安全操作员。
野外分类
原文:https://towardsdatascience.com/classification-in-the-wild-4787c4ffca38?source=collection_archive---------26-----------------------
让我们深入分类指标并讨论一些技巧,它们可以提高您的分类管道性能。
帕特里克·托马索在 Unsplash 上拍摄的照片
嗨,我是 Sergey,在过去的 5 年多时间里,我一直致力于基于 ML 的项目。在我的职业生涯中,我参与过不同的项目,创业公司,大公司,赢过几次比赛,写过几篇论文。我还启动了Catalyst——一个基于 PyTorch 的高级框架,以提高我作为深度学习实践者的生产力。有了这样一条路径,我最近决定写一系列关于深度学习“一般事情”的帖子。几个想法之后,我决定从 ML 评估技术和度量标准开始:如何理解它们?什么时候使用它们?在这种情况下,今天,我想深入研究深度学习中的分类指标,并讨论一些技巧,这些技巧可以提高你的分类管道性能。
你可以在 这个 colab 笔记本 下面找到所有的例子。
博文原文为 此处 。
实验 01:典型分类
分类任务对于任何深度学习实践者来说看起来都是众所周知的。长话短说,我们有一些以(some-data, label)
格式标记的数据,并想创建一个模型,它可以为我们将some-extra-data
转移到label
。例如,让我们回顾一下简单的 CIFAR10 分类:
典型的分类管道。
总结上面一个例子:
- 我们创建
resnet9
网络 - 在
CIFAR10
上训练它 10 个纪元 - 有
CE
损耗、Adam
优化器、MultiStep
调度器 - 和
accuracy
作为验证度量
这个例子看起来像一个非常普通的分类管道。我们能做得更好吗?我们去看看吧!
实验 02:焦点丢失
从一个简单的改进开始,让我们介绍一下FocalLoss
而不是CE
。长时间回顾,请阅读原始论文,短时间回顾:由于基于真实概率和预测概率之间的差异对每样本损失进行重新加权,FocalLoss
更好地处理了类别不平衡,重点关注难以区分的类别。因此,它为具有严重类别不平衡的分类任务提供了更好的性能(真实情况,而不是 CIFAR 情况)。更重要的是,它不会在您的管道中引入任何额外的复杂性。所以让我们来看看:
无焦点分类。
虽然我们还没有明显改善 CIFAR10 的结果,但FocalLoss
通常有助于更实际的案例。最后一个小技巧,我也想提一下——多准则用法:
多标准分类设置示例。
这种方法为您提供了一种平衡简单分类(使用CE
损失)和侧重不平衡分类(使用FocalLoss
)的方法。
实验 03:分类指标
好的,正如我们已经看到的,由于FocalLoss
,我们可以“提高”一下accuracy
的性能。但是有一些额外的分类标准可以更好地理解您的模型:
precision
-显示标签预测中的模型保证。例如,假设precision
为高,模型预测某个输入I
的某个标签L
。在那种情况下,I
实际上是L
的概率很大。recall
-显示模型在数据流中找到所有类实例的能力。当然,高的recall
并不意味着所有的模型预测都足够准确,但是它给了我们覆盖所有类实例的高概率。f-score
-是precision
和recall
之间的调和平均值。因此,它可以被视为理解模型在数据流中找到所有相关类(recall
)并正确标记它们(precision
)的能力的统一分数。此外,f-score
beta
参数允许我们在聚合时优先选择precision
或recall
。
此外,在模型训练和预测过程中,还有两件事需要检查:
support
-每个类只有简单数量的样本。这似乎是不经意的,但是你拥有的数据点越多,你就能找到自信的洞察力。有时,即使您有一个包含各种类的大型数据集,也可能有只有少数几个示例的类,从而导致训练和评估期间出现不可预测的结果。向您的管道中添加一个support
指标,为您提供了一种在训练期间“验证”数据集的简单方法。confusion matrix
-易于跟进你的分类模式简历区分不同类别的能力。虽然它明显地帮助您分析模型的正确性(混淆矩阵对角线),但它也让您对类的分布和标记有了重要的了解。在我的实践中,有几个案例是confusion matrix
在数据集更新期间帮助发现不正确的标记——仅仅是在confusion matrix
上检查类的交互异常。
让我们将它们添加到我们的管道中:
包含所有必备指标的分类示例。
对于这些指标,有一些关键的技巧需要注意。所有这些都可以通过类的*“每类”或“聚合”来计算。【Per-class】结果对于理解模型性能至关重要,因为在很多情况下,您的模型在最重要的类上可能表现“良好”,但“比以往任何时候都差”。例如,我们可以查看一些文本分类模型,这些模型对问候意图非常有效,但对有害意图的预测却失败了,从商业角度来看,这可能更有价值。【聚合】*如果你想快速查看几个数字的模型性能,结果是必不可少的。有三种最常见的聚合策略:
- 微:所有样本对最终平均度量的贡献相等,
- 宏:所有类对最终平均度量的贡献是相等的,
- 加权:在平均过程中,每个类的贡献根据其大小进行加权。
上述指标的另一个重要注意事项是,它们的所有结果都是基于数据集的,这意味着您不能简单地平均基于批处理的微指标来获得基于数据集的微统计数据。
张量板
由于我们有大量不同的指标,使用 tensorboard 来观察它们会容易得多:
tensorboard --logdir ./logs
上述管道的精度指标。(图片由作者提供)
推断&报告
此外,还有一种以用户友好的方式表示所有上述指标的方法,用于审查最终模型性能:
分类报告结果。(图片由作者提供)
有了这样的分类报告,断定模型的最终性能就容易多了。
阈值
我想在本教程中提到的最后一个关键步骤是阈值。虽然它们不是花哨的深度学习模型,但它们为您提供了一种无需任何额外学习即可针对您的生产案例调整这些模型的方法。因此,举例来说,你可以为一些贫穷的工人阶级设置一个阈值1.0
,以阻止模型预测它。只要这是生产深度学习中的基本实践,它也包含在催化剂中:
正如您所看到的,我们已经能够稍微改进我们的模型性能,即使是在像 CIFAR 这样简单的设置中(在 CIFAR 上学习模型非常容易)。当然,在基准测试期间会有数据泄漏,因为我们是在同一个test
集上调优和评估thresholds
,所以在现实世界的例子中,您必须将数据集分成train
、valid
和test
部分,以防止任何数据泄漏。然而,即使有如此严格的评估设置,thresholds
的使用通常会给你的兴趣指标带来关键的 2–8%的改善,这是巨大的。
结论
总而言之,这篇博文的主题是:
- 分类问题仍然是一个有待改进的领域(特别是在闭集和开集领域,但这是另一篇文章),
- 在你的下一个实验中尝试
FocalLoss
,如果你的数据中有一个类不平衡(一个很常见的情况), - 使用
PrecisionRecallF1Support
和ConfusionMatrix
分析您的模特在训练中的表现, - 使用
classification report
了解您的最终模型分类性能, - 在模型部署期间尝试使用
thresholds
,针对您的特殊情况调整模型,并提高最终性能。
如果您想更深入地了解这个分类示例,您可以:
- 用
CIFAR100
代替默认的CIFAR10
, - 查看我们的 CV 数据集,
- 尝试为 NLP 采用相同的管道( Albert 在 TPUs 上的培训示例),
或者针对您想要的任何分类问题进行调整;)
这些都是这篇博文分类的重要步骤。如果你想查看更多深度学习最佳实践——订阅[scitator](https://scitator.com/post/2110-classification/twitter.com/scitator)
& [catalyst-team](https://twitter.com/CatalystTeam)
。感谢您的阅读,敬请期待更多内容!
分类—让我们了解一下基础知识
原文:https://towardsdatascience.com/classification-lets-understand-the-basics-78baa6fbff48?source=collection_archive---------28-----------------------
机器学习(监督学习)
照片由 Reiseuhu 在 Unsplash 上拍摄
在我之前的博客中——机器学习的阴影——我们讨论了机器学习算法的两种主要类型。只是为了温习一下,我们有监督学习(其中目标已知/数据被标记,模型在此监督下工作)和无监督学习(其中目标未知/数据未被标记,因此算法没有任何监督)。
在这篇博客中,我们将只讨论分类。我们将讨论一些与分类相关的基本但重要的问题,例如— 分类到底意味着什么?什么样的数据可以分类,什么不能分类?有哪些分类算法?
分类的真正含义是什么?
在开始分类之前,让我们了解数据集的不同部分及其与算法的一般关系。
作者图片
我在上面的图片中创建了一个“假设”数据集,只是为了解释这个理论(吃披萨或可乐或蔬菜完全是你的选择,请不要让我为健康/不健康负责!:P)
- 数据集 —任何以行列形式排列的数据都适用于 ML。列分为两种类型—变量(可以是一列或多列)和目标(总是一列)。这些行是我们的数据点。
- 目标/标签 —是我们要预测的列。这是我们的结果列,我们想知道未来的数据。在这个数据集中,它的列“适合/不适合”用蓝色标记。我们的整个监督学习依赖于这一列,因为这是我们想要知道的。
- 变量/特征 —目标列以外的列。这些列帮助 ML 模型预测未来数据点的目标。在这个数据集中,变量是- >“吃比萨饼”、“喝可乐”、“吃蔬菜”和“锻炼”。
- 你可能会想什么样的栏目是“人物”。嗯,当我们在 ML 算法中输入数据时,有一些列我们不使用,因为我们不希望我们的模型“过拟合”或了解每个场景,相反,我们希望算法理解一般模式,并创建一个模型来预测同样的情况。我们将在以后的博客中讨论更多的过度拟合问题。
现在你已经熟悉了数据集和算法的关系,让我们回到分类上来。顾名思义,分类就是根据某些理由对数据进行分类。这是一种监督学习。在分类中,目标列应该是分类列。如果目标只有两个类别,如上面数据集中的类别(适合/不适合),则称为二元分类问题。当有两个以上的类别时,这是一个多类分类问题。“目标”列在分类问题中也称为“类”。
什么样的数据可以分类,什么不能分类?
为了对事物进行分类,我们需要有限的范畴。因此,我们需要一个数据集,其类别标签为— [0,1],[通过,失败],[适合,不适合],[好,更好,最好]等。如果我们在目标列中有这样类型的值,我们可以使用分类方法来解决这个问题。但是如果我们在目标列中有连续的数值,比如[100,23,44,46,44.7,24.8,…等等。],我们无法在这样的数据集上进行分类。在这种情况下,我们要么将该值转换为类值,例如— {values >50 将被视为 1,而以<50 is 0}, or we use other methods like regression to solve the problem which is out of the scope of this blog.
To understand this better, let’s take an example of the employee salary and other features dataset (below):
Data For Non-Classification Problem(Image By Author)
The above image consists of some data points, with Salary as our target variable. Now since Salary is a continuous number column (since salary is always numeric), we cannot treat this as a classification problem. But if we really want to treat this as a classification problem due to some reason, we can bin the target column into two categories **为例— Salary > 70,000 为高,Salary < 70,000 为低。**完成此操作后,数据集将如下所示:
将回归转换为分类问题(图片由作者提供)
所以现在我们的数据已经可以作为一个分类问题来处理了。当然,基于所使用的不同类型的算法,我们需要做其他的数据处理工作,但是我们现在至少有了一个分类的目标。
ML 算法或模型如何对数据进行分类?
既然我们知道了数据集如何与 ML 模型相关,以及哪些数据集可以用作分类问题,我们也应该知道如何解决它们,对吗?
世界上有很多算法正被用来解决分类问题,甚至每天都有更新的算法被推出。其中一些算法是— 决策树、 **【支持向量机】(SVM)、随机森林、梯度提升树(GBT)、K-最近邻(KNN)、**等。决策树是理解每个人分类的基本算法,也是理解树在机器学习中如何工作的基本算法。但是我喜欢保持我的博客简短,决策树应该有一个完整的博客,所以我会在这里停下来,并尝试尽快提出我的下一个关于决策树的博客!❤
同时,你可以按以下顺序查看我以前的博客,了解数据预处理和 ML 项目流程:
- 面向非数据科学家的数据科学
- 弥合业务差距&数据科学
- 数据科学—我该从哪里开始?
- 数据里面有什么!
- 理解数据中的模式
- 特征工程——保留什么,删除什么?
- 不同深浅的机器学习
我希望这个博客能帮助一些人理解他们之前没有得到的东西(并让他们继续提问)!:)
分类指标—混淆矩阵解释
原文:https://towardsdatascience.com/classification-metrics-confusion-matrix-explained-7c7abe4e9543?source=collection_archive---------30-----------------------
照片由陈伶俐·桑特兰在 Unsplash 上拍摄
我正在撰写一系列博客文章,旨在涵盖各种数据科学和机器学习概念的基础知识。我这么做主要是为了自己更好的理解这些概念。我希望在这个过程中,我也能帮助别人理解他们。好吧,我们开始吧!
在机器学习领域,混淆矩阵(也称为误差矩阵)是一个表格,允许我们可视化算法的性能。它仅用于分类任务。
这个名字来源于这样一个事实,即很容易看出一个算法是否混淆了两个或更多的类(即没有做出正确的预测)
二元(2 类)分类器示例
让我们从最简单的例子开始。想象一下,我们训练了一个机器学习模型来检测照片中是否有狗。这是一个二元分类任务,意味着只有两个类别(照片中的“狗”或“不是狗”)。如果照片中有狗,则用于训练过程的标签为 1,否则为 0。在二进制分类任务中,我们经常把这些类叫做正和负。当我们向模型传递一张新照片时,它会预测照片中是否有一只狗。
现在,假设我们要对 10 张新照片进行分类。我们可以使用我们的分类器对照片进行分类。每张照片都会收到一个包含标签(0 或 1)的预测,该标签代表两个类别(狗或非狗)。因此,对于每张照片,我们将有预测类和实际类。根据这些信息,我们可以为这 10 张照片生成一个混淆矩阵。稍后,我会给你一个链接,链接到一个很棒的绘制混淆矩阵的例子。现在,假设在我们通过了预测类和实际类之后,返回下面的混淆矩阵:
混淆矩阵—二元分类器 10 只狗
矩阵的每一列代表实际类中的实例,而每一行代表预测类的实例(反之亦然)。我们训练了一个模型来检测两个类,因此我们最终只有 4 个代表不同信息的单元格:
- т第一行第一列的单元格包含真实底片的数量(在我们的例子中,该单元格包含不包含狗的正确预测照片的数量)。模型真实预测这 3 张照片中没有狗。
- т第一行第二列的单元格包含假阳性的数量(在我们的例子中,该单元格包含预测为狗的照片的数量,但实际上照片不包含狗)。模型错误地预测这两张照片中有一只狗。
- т第二行第一列的单元格包含假阴性的数量(在我们的例子中,该单元格包含预测为不是狗的数量,但实际上照片包含一只狗)。模型错误地预测在这张照片中没有狗。
- т第二行第二列的单元格包含真阳性的数量(在我们的例子中,该单元格包含包含狗的正确预测照片的数量)。模型真实预测这 4 张照片中有一只狗。
我们可以很容易地看到,我们的模型正确预测了 10 张照片中的 7 张,并错误分类(混淆)了 3 张照片。从上面的观察,我们可以决定我们的分类器是否足够好,并继续对错误分类的照片进行额外的分析。
多类分类器示例
这是一个非常简单的例子。在某些情况下,我们需要训练一个模型来预测两个以上的类。让我们想象一下,我们想要训练一个模型来预测一张照片是否包含一只狗、猫或兔子。在这种情况下,类的数量将是 3。现在,假设我们传递 27 张照片进行分类(预测),我们得到以下混淆矩阵:
混淆矩阵-多类分类器 27 张照片
同样,矩阵的每一列代表实际类中的实例,而每一行代表预测类的实例。然而,这次我们有 9 个单元,因为我们有 3 个类。
请注意,我所说的真实的猫是指被归类为猫的照片,而且是真实的猫。另外,所谓的假猫,我指的是那些我们归类为猫但实际上不是猫的照片。对/错单词告诉我们预测是否正确,猫/狗/兔子单词告诉我们实际等级。
从这个混乱矩阵中可以得出一些见解:
- 模型只正确预测(分类)了全部 27 张照片中的 15 张。有 3 张正确预测的照片包含猫,4 张正确预测的照片包含狗,8 张正确预测的照片包含兔子。
- 从所有错误分类的照片中,我们有:2 张预测为狗但实际包含猫的照片,2 张预测为猫但实际包含狗的照片,1 张预测为兔但实际包含狗的照片,3 张预测为猫但实际包含兔的照片,以及 5 张预测为狗但实际包含兔的照片。
- 此外,我们可以看到,我们没有任何错误预测为兔子的照片,实际上包含一只猫。
现在你知道如何阅读一个混淆矩阵和它代表什么。这里有一个很好的例子,展示了如何使用 sklearn 软件包轻松生成漂亮的混淆矩阵。
摘要
混淆矩阵可以用来分析分类器的性能,并让我们了解应该朝哪个方向改进分类器。然而,我们只是看了两个由少量类别(2 和 3)训练的分类器生成的混淆矩阵。想象一下,我们要训练一个有 100 个类的分类器。在这种情况下,也许我们需要一些指标来聚集混淆矩阵提供的信息。请继续关注下一篇文章,我将向您展示我们如何使用准确度、精确度和召回指标,这些指标的定义只是使用矩阵值的公式。
好了,这就是所有的人!我希望你喜欢这篇博文。如果你对我有任何反馈,请告诉我。这里有一张图片总结了混淆矩阵的定义和例子。
如果你想在我发表新的博客文章时得到通知,你可以订阅我的简讯。这是我在 LinkedIn 上的简介,如果你想和我联系的话。我将很高兴与你联系在一起。
资源:
- https://en.wikipedia.org/wiki/Confusion_matrix
- https://sci kit-learn . org/stable/auto _ examples/model _ selection/plot _ confusion _ matrix . html
机器学习中的分类模型和阈值
原文:https://towardsdatascience.com/classification-models-and-thresholds-97821aa5760f?source=collection_archive---------16-----------------------
如何选择阈值以及它们为什么重要
Pawel Czerwinski 在 Unsplash 上的照片
分类模型是监督机器学习的子集。分类模型读取一些输入,并生成将输入分类到某个类别的输出。例如,一个模型可能会读取一封电子邮件,并将其分类为垃圾邮件或非垃圾邮件—二进制分类。或者,模型可以读取医学图像,比如乳房 x 光照片,并将其分类为良性或恶性。
像逻辑回归这样的分类算法会生成一个概率分数,为属于某个类别的输入分配一定的概率。假设分类是二进制的(恶性或良性,垃圾邮件或非垃圾邮件),这个概率然后被映射到二进制映射。在前面的垃圾邮件示例中,模型可能会读取一封电子邮件,并生成 92%的垃圾邮件概率得分,这意味着该电子邮件确实是垃圾邮件的可能性非常高。对于频谱两端的概率分数,映射非常明显。分数接近0 意味着该电子邮件很可能不是垃圾邮件,而接近 100 意味着该电子邮件很可能是垃圾邮件。然而,映射决策在许多情况下并不完全明显。考虑 58%的分数,这应该被归类为垃圾邮件吗?同样,32%的分数是否应该被归类为非垃圾邮件?
为了将逻辑回归或类似的概率分类模型的输出映射到二元分类类别中,您需要定义一个分类阈值。这个阈值代表决策边界。在前面的垃圾邮件分类器示例中,高于该阈值的值将被映射到垃圾邮件类别,而低于或等于该阈值的值将被映射到非垃圾邮件类别。问题是你如何选择这个门槛,这个选择意味着什么。
在我们能够回答这个问题之前,我们将需要稍微走一点弯路来理解如何度量模型。像我们这样将电子邮件分类为垃圾邮件或非垃圾邮件的模型可以通过这 4 种测量进行评估:真阳性、假阳性、真阴性和假阴性,这些都在下面的 2x2 中定义。绿色象限代表现实(真相)和模型(预测)之间的一致,而红色象限代表不一致。
作者图片
使用上述 4 个度量,我们可以导出另外两个度量,这两个度量有助于评估模型的性能以及最终如何选择阈值。
真阳性率(TPR): 这衡量模型能够正确预测阳性病例的程度。这是模型能够相对于被模型错误分类为阴性的真阳性和阳性病例的总和正确识别真阳性的功能;假阴性。更令人困惑的是,这种测量经常被称为敏感度或回忆
作者图片
真负率(TNR): 这是正例的逆例。它衡量模型能够正确识别真正负面案例的程度。这是相对于真阴性和模型错误分类为阳性的情况的总和的真阴性的函数;假阳性。这种测量也被称为特异性
作者图片
现在让我们用一个说明性的例子来展示这些测量。假设我们有一个模型,将 10 封电子邮件分类为垃圾邮件(正面)或非垃圾邮件(负面)。下表的第一行显示了这 10 封邮件的真相。在这 10 封邮件中,5 封是真正的垃圾邮件,5 封不是。该模型为每封输入的电子邮件生成一个概率分数,如下面第二行所示。最后五行使用 5 个不同的阈值将这个概率分数映射到一个二元决策——垃圾邮件还是非垃圾邮件。第一个阈值是 0.5,这意味着如果该模式的概率大于 50%,则该电子邮件将被分类为垃圾邮件,任何低于该分数的邮件都将被分类为非垃圾邮件。其他阈值为 0.3、0.8、0.0 (100%垃圾邮件)和 1.0 (100%无垃圾邮件)。后两个阈值是极端情况。最后,标为绿色的单元格表示真阳性和真阴性,而标为红色的单元格表示假阳性和假阴性。
作者图片
下表显示了之前定义的 4 个测量值,以及所用三个阈值中的每一个的 TPR 和 TNR。注意 TPR 和 TNR 是如何受阈值变化影响的。还要注意敏感性(TPR)和特异性(TNR)之间的反比关系。一个增加,另一个减少。找到正确的阈值是这两种测量之间的权衡。
作者图片
这很直观。阈值非常高(0.8)的模型会错误地将大多数电子邮件归类为非垃圾邮件。相反,阈值非常低(0.3)的模型会很快将大多数电子邮件分类为垃圾邮件。两者都是正确的,最终重要的是模型的预期用途和这些阈值的含义。
想象一下,如果实际部署了阈值为 0.3 的模型来过滤您的电子邮件提供商的垃圾邮件。该模型将非常积极地将大多数电子邮件归类为垃圾邮件。这种方法的后果将是你错过了非垃圾邮件,这些邮件最终会出现在你的垃圾邮件文件夹中..你必须定期检查你的垃圾邮件文件夹,看看它是否包含非垃圾邮件(误报)信息。这可能会导致糟糕的用户体验。或者,阈值非常高(0.8)的垃圾邮件过滤器可能会导致收件箱充满垃圾邮件。这也不是很好的用户体验。
在回答我们最初的问题之前,我们需要引入另一个概念:如何选择“正确的”阈值。这个概念就是接收算子曲线,简称 ROC。ROC 绘制了不同阈值下模型的灵敏度和特异性(实际上它绘制了1-特异性)。这类似于前面的例子,它显示了一个模型沿 5 个不同阈值的敏感性和特异性。下图显示了各种模型的示例性 ROC。每条曲线代表一个分类模型
图像由马丁·托马斯——自己的作品, CC0
该曲线有助于理解 TPR 和 FPR(对于不同阈值为 1-TNR)之间的权衡。此外,曲线下面积(AUC)提供了一个数字来概括模型的性能。完美模型的 ROC 为 1,而表现不佳的模型(随机分类器)的 ROC 为 0.5。ROC 是理解不同阈值之间权衡的有用诊断工具,AUC 提供了基于一般能力比较模型的有用数字。
快到了,我保证!
最佳阈值是最大化 TPR 和最小化 FRP 的点。我们可以在 TPR 约为 0.65 的蓝色曲线上大致了解一下。除了瞎猜,我们还可以选择使特异性和敏感性的几何平均值最大化的阈值。
作者图片
确定最佳阈值的几何平均法实际上可能不是您想要使用的最佳点(双关语)。简单地选择最大化 TPR 和最小化 FRP 的点可能会有一些不期望的结果。考虑一个模型的情况,该模型将罪犯分类为应该判死刑或不应该判死刑的人——我希望这样的模型永远不要被开发出来,但是请原谅我。您可能希望尽量减少假阳性,因为假阳性的后果是非常不利的:您的模型会让一个无辜的人走向死亡。您必须采取的平衡措施是选择一个阈值来减少误报,同时也产生一个合理的 TPR。下图描述了这一点。
作者图片
使用几何平均法将得出上面红点所示的阈值。这个阈值将导致大约 18%的 FPR。可选地,沿着 ROC 曲线(绿点)选择较低的阈值导致约 2%的 FPR。这里明显的权衡是通过选择绿点处的阈值,TPR 降低约 10%,但考虑到我们模型中假阳性的后果,这可能是一个很好的权衡。
因此,使用什么阈值的答案毕竟是“视情况而定”:)
最初发表于【https://karimfanous.substack.com】。
雷达回波的分类
原文:https://towardsdatascience.com/classification-of-radar-returns-c79fa1ce42eb?source=collection_archive---------29-----------------------
电离层数据集的案例研究
由 VM Quezada 在 Unsplash 上拍摄的照片
- 介绍
- 问题陈述
- 映射到 ML/DL 问题
- 理解数据
- 数据处理和探索性数据分析
- 结构
- 结论和未来工作
- 参考
1.介绍
电离层位于大气层和外层空间的地平线上。有趣的是,电离层探索属于太阳系探索的范畴。电离层是地球大气层从 48 公里到 965 公里的电离部分,包括热层和部分中间层和外逸层。[维基百科]
研究电离层的十个重要原因
- 它容纳了地球大气中所有的带电粒子。
- 它是地球大气层和太空的分界线。
- 在这个区域可以感觉到轨道阻力。
- 地球轨道卫星最喜欢去的地方。
- 它受到地球上天气条件波动的影响。
- 无线电和全球定位系统信号被电离层的辐射干扰。
- 受太空天气条件的影响。
- 空气辉光发生在原子和分子被太阳光的辐射激发而发光并释放多余能量的地方。
- 太空机构用不可见类型的光研究电离层
- 2019 年 10 月,美国宇航局加入了 GOLD,使用 ICON-电离层连接探测器研究电离层
2.问题陈述
在电离层研究中,我们需要将信号分为有用的(好的)或无用的(坏的)以供进一步分析。通常在这种分析中,手动干预是必要的,这是一项痛苦耗时的任务。约翰·霍普斯金应用物理实验室已经把从拉布拉多鹅湾雷达收集的数据存入了 UCI 机器学习知识库。
3.映射到 ML 问题
这个来自地球物理领域的问题可以映射成机器学习中的二分类问题。我们需要将数据分为好的(“g”)和坏的(“b”)。好的(‘g’)雷达显示了一些在电离层中返回的证据,而坏的(‘b’)雷达是那些不通过电离层的信号。
4。理解数据
“这些雷达数据是由拉布拉多鹅湾的一个系统收集的。该系统由 16 个高频天线的相控阵组成,总传输功率为 6.4 千瓦。目标是电离层中的自由电子。使用自相关函数处理接收的信号,自相关函数的自变量是脉冲的时间和脉冲数。鹅湾系统有 17 个脉冲数。该数据库中的实例由每个脉冲数的 2 个属性描述,对应于由复合电磁信号“[UCI 档案]产生的函数返回的复合值。
给定的数据集包含 351 行和 35 列。前 34 列是特征,最后一列包含“g”和“b”的分类标签。
5。数据预处理和探索性数据分析
给定的数据集包含 34 个特征。在深入研究特性的重要性之前,为了找出哪个特性更有用,哪个不是,先做一个随机数据分析。
我们将把数据集转换成 pandas 数据框,并执行进一步的处理。在转换成 pandas 数据框后,我们将删除数据集中任何重复的行。因此,最终的数据帧有 350 行和 34 列。
我们需要使用 MinMaxScaler 规范化数据集,然后对数据集执行初步的 EDA。概率密度函数图和累积密度函数如下所示。
PDF 绘图
CDF 图
由于特征值高度重叠,我们无法从上述图中推断出任何关于特征的重要信息。
我们现在将绘制具有相应标签的要素的热图,以检查是否可以进行任何重要的分析。
相关矩阵的热图
根据上面的热图,除了图中的要素高度重叠之外,无法推断出更多信息。
我们使用 sklearn 的选择测试功能来选择前 k 个重要特性。这在分类任务中使用。sklearn 的实现是用于分类的 ANOVA(分析均值之间的差异)。
计算最佳特性的代码
最重要的 5 个特征
降维
让我们使用一些降维技术,如主成分分析和 t-SNE,看看我们是否可以从我们的数据中获得任何其他见解。
主成分分析
我们使用主成分分析来找出数据集中的哪些成分解释了 80%以上的方差
代码和分析
从上图可以明显看出,1 到 10 之间的特征解释了最大方差。因此,“选择最佳”的输出和 PCA 的输出几乎匹配。
t-SNE: t 分布式随机邻域嵌入
让我们对数据集运行 t-SNE 算法,进行多次迭代并改变困惑分数,并检查是否有任何现象可以解释数据集中所有要素的高度重叠性质,从而使分析变得复杂。
基于 t-SNE 图,通过迭代= 50k 和不同的困惑分数,特征是不可区分的。因此,由于这些是电离层中的信号或辐射,它们由复数表示,因此它们需要更详细的机器学习模型来解释它们的行为。
6.结构
我们需要建立一个有监督的机器学习模型来解决这个二元分类问题。为了对好的和坏的回报进行分类,我们需要找到将两者平均分开的超平面。
我们可以使用 SVM 分类器来完成这项任务。使用 sklearn 的带 loss='hinge '的 SGDClassifier,可以得到 LinearSVM 模型。我们为模型评估选择的度量是 AUC。
具有所有 34 个特征的模型的训练和测试 AUC 被评估为 0.5。这意味着数据集本质上是高度随机的。因此,我们需要只选择最佳特征,并在这些特征上拟合模型,以获得所需的 AUC。
对数据集的前 5 个要素运行分析的代码如下。在这种情况下,获得的 AUC 从 0.5 提高到 0.7
为了进一步提高 AUC 和准确性,我们可以使用梯度推进决策树。梯度推进决策树在处理异构数据和相对少量的数据时非常有效。CatBoostClassifier 是 Yandex 公司的一个开源库。获得的 AUC 在训练数据集和测试数据集上提高到 0.85
在相同的上运行分类报告后,我们得到以下结果
分类报告
在将 GBDT 模型用于雷达回波的二元分类任务之后,在训练和测试数据集上的准确率分别提高到 85%和 89%。
根据应用物理实验室【3】的研究论文,深度学习神经网络模型,如简单的多层感知器,在特异性和敏感性方面超过了任何机器学习模型
我们已经实现了一个 MLP 模型与亚当优化。模型摘要和模型如下所示。关于代码实现,请参考文章末尾给出的 Github 链接。
多层感知器的自定义层实现在研究论文中给出的测试数据集上给出了更好的准确性。获得的测试准确度为 98%。完整的代码可以在下面参考资料部分提供的 GitHub 链接中找到。
7.结论和未来工作
对于给定的数据集,具有 5 个隐藏层和 Adam 优化器的多层感知器简单地优于其余的模型对应物
根据该研究论文,利用 MLFN 效应、非相干散射、雷达脉冲吸收和发射机干扰来分析不良回波的原因将是令人感兴趣的。我对研究这些方法感兴趣,并使用深度学习方法来实现和分析它们。
这些可以探索电离层研究的新的研究途径。
8。参考文献
- https://www.appliedaicourse.com/
- UCI 机器学习知识库:电离层数据 Se t
- https://www . jhuapl . edu/Content/tech digest/pdf/V10-N03/10-03-Sigillito _ class . pdf
- Github 源代码。
- 链接到我的 LinkedIn 个人资料
高光谱数据分类
原文:https://towardsdatascience.com/classification-on-hyperspectral-data-19c48c432b96?source=collection_archive---------25-----------------------
这是一个循序渐进的教程,介绍如何使用支持向量机执行特征约简,然后对高光谱数据进行分类
米卡·科霍宁的照片
简介
本教程的目标是将 PCA 应用于高光谱数据。(要了解 PCA,请阅读文章“高光谱数据的 PCA”。).在使用 PCA 降低数据的维度之后,通过应用支持向量机(SVM)对图像中的不同材料进行分类来对数据进行分类。
步伐
在本教程中,我们将使用高光谱 Gulfport 数据集。您可以从以下链接下载数据。
https://github.com/GatorSense/MUUFLGulfport
MUUFL Gulfport 数据包含基于像素的地面真实地图,该地图通过手动标注场景中的像素来提供。在场景树中标记了以下类别,主要是草地、地面、混合地面、泥土和沙子、道路、水、建筑物、建筑物的阴影、人行道、黄色路缘、布料面板(目标)和未标记的点。
步骤 1:导入库
步骤 2:加载数据
原始数据中有 65 个波段。
RGB 图像
步骤 3:去掉未标记的和一些类数据
移除未标记的数据点,并且将一些相似的类合并成一个。例如,水和建筑阴影合并成一类,因为它们具有相似的光谱。此外,布面板和黄色路缘类被忽略,因为他们的数量很少,因此,没有足够的培训。
因为地面真相标签从一开始。所以在最后一行,我从所有标签中减去 1,以确保它们从零开始。
步骤 4:将数据分为训练和测试
步骤 5:对原始数据应用 SVM 分类器
我对训练数据进行了 K 重交叉验证。
步骤 6:对 PCA 数据应用 SVM 分类器
我已经应用了 3 个模型的集合,并在训练数据上使用了 K-fold 交叉验证。
计算多数票后所有三个模型的最终预测。
步骤 7:绘制 PCA 后的最终图像
应用 PCA 后的图像
结论
PCA 前的数据维数为 65,PCA 后的数据维数为 3。主成分分析将数据的维数降低了近 21 倍。
从上面的结果我们可以得出结论,当我们将 SVM 应用于原始数据时,准确率在 88.7% 左右,而将 SVM 应用于主成分分析后,准确率在 88.9% 左右。所以在这两种情况下,我们得到了几乎相同的精度。
这就是为什么我们对减少的数据应用分类器。降低了时间和空间复杂度。根据问题的不同,与使用原始数据相比,PCA 的准确性可能更高。
感谢阅读!我希望这篇文章对你有用。如果你有任何问题,请随意提问。
参考
https://github.com/GatorSense/MUUFLGulfport https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html https://machinelearningmastery.com/k-fold-cross-validation/ https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html https://machinelearningmastery.com/standardscaler-and-minmaxscaler-transforms-in-python/
分类性能指标
原文:https://towardsdatascience.com/classification-performance-metrics-69c69ab03f17?source=collection_archive---------47-----------------------
探索各种性能测量方法,用具体的例子和插图来评估您的分类器。
分类性能指标包括照片。
评估一个分类器通常比评估一个回归量更困难,因为有许多可用的性能度量,并且不同类型的问题需要特定的度量。了解度量之间的差异以及何时使用它们仍然是解决任何分类问题的关键技能。
在本文中,我将从理解最重要的概念之一——混淆矩阵开始,然后进入其他度量,为您提供一种更简洁的方法来对分类器进行评分。
混淆矩阵
混淆矩阵是评估分类器性能的最佳方法之一。基本思想是计算一个类中的实例被正确分类或被错误分类为另一个类的次数。
混淆矩阵中的行代表实际类别,而每列代表预测类别。一个完美的分类器只会有真 正和真 负,这意味着它的混淆矩阵只会在其对角线上有非零值。
使用混淆矩阵计算准确度。
在混淆矩阵中,有两种类型的错误需要注意:假阳性或 I 型错误和假阴性或 II 型错误。这些术语来自统计学中的假设检验,并与分类问题互换使用。
从混淆矩阵中,你可以计算出各种不同的指标,包括最简单的一个准确度。准确度定义为正确分类的实例总数除以实例总数。在上面的例子中,我们计算的准确率为 86.11%!看起来不错,对吧?好吧,让我们来看一个虚拟分类器,它只是将每个实例分类为负类。
使用虚拟分类器计算准确度。
没错,虚拟分类器具有更好的准确性,这仅仅是因为正面分类器占总实例的 10%左右。这说明了为什么准确性通常不是首选的性能指标,尤其是当您处理不平衡的数据集时(例如,当一些类比其他类出现得更频繁时)。
精确度和召回率
混淆矩阵为您提供了有价值的信息,但有时您可能需要更简洁的度量。一种方法是计算被分类在正类中的所有实例的准确度。这叫做精度。由于 precision 只关注 I 类错误,所以它经常与另一个称为召回的指标(也称为灵敏度或真阳性率)一起使用。
计算精确度、召回率和 F1 分数。
这里我们看到,即使我们有超过 85%的准确率,我们的分类器只有 62.8%的时间是正确的。此外,它仅检测到 41.8%的阳性类别。将精确度和召回率结合成一个称为 F1 分数的指标通常是有帮助的。F1 分数被定义为精确度和召回率的调和平均值。它对较低的值赋予较重的权重,这意味着当这些值接近时,它将始终落在精度范围内,并回忆和偏好。
一种赋予精确度或召回率更大权重的方法是使用 Fβ分数,该分数赋予召回率β倍的重要性。因此,小于 1 的值有利于精度,大于 1 的值有利于召回。
精确度/召回率的权衡
有时你更关心精确度,有时你更关心回忆。例如,如果您训练一个分类器来检测欺诈性信用卡活动,如果您的分类器精度较低,只要它具有非常高的召回率(这意味着可能会有一些错误警报,但几乎所有的欺诈活动都会被检测到),这并不是什么大问题。
另一方面,假设你训练了一个分类器,它检测自然界中的蘑菇是否可以食用(无毒)。当预测蘑菇可食用(高精度)但将一些可食用蘑菇错误分类为有毒(低召回率)时,您可能更喜欢您可以信任的分类器,而不是将有毒蘑菇错误分类为可食用的分类器。
现在你可能已经知道,提高精确度会降低回忆,反之亦然。这被称为精度/召回权衡。
通过绘制精度/召回率与阈值的关系来解释精度召回率的权衡。
要理解精度/召回率的权衡,您必须理解分类器如何将实例分配给正类或负类。每个分类器都有一个决策函数,它计算得分/概率,如果得分/概率大于某个阈值,则该实例被分配给肯定类;否则,它被分配给负类。
通过改变这个阈值,您可以有效地改变假阳性的数量,而以您的假阴性为代价。提高阈值会提高精度,降低召回率。而降低阈值会增加召回率并降低精确度。
在某些情况下,召回曲线会比精确曲线更平滑。这是因为当您提高阈值使其看起来平滑时,召回率总是降低,但是尽管提高了阈值,精确度也可能降低。
我们也可以直接绘制精度与召回率的关系图,以帮助我们选择一个好的精度/召回率折衷方案。
精确/召回曲线及其应用。
精度/召回曲线允许您准确地看到在给定期望精度的情况下,您将获得什么样的召回。在上面的例子中,您可能希望在急剧下降之前选择 90%左右的精度。您可以通过搜索最低可能阈值来做到这一点,该阈值至少可以提供您想要的精度。
到目前为止,您可能已经知道,通过设置足够高的阈值,在分类器上实现您想要的任何精度是相当容易的。但是,一个具有高精度和低召回率的分类器不是很有用。了解业务问题将帮助您决定一个好的精度/召回权衡。
受试者工作特性曲线
接收器工作特性曲线是另一种用于分析二元分类器误差的工具。它与精确度/召回率曲线非常相似,但 ROC 曲线不是绘制精确度对召回率,而是绘制真阳性率 ( 召回)对假阳性率 ( 下降)。
通过测量曲线下的面积(AUC ),我们可以对分类器的性能进行评分。完美分类器的面积为 1,而随机分类器的面积为 0.5。我们用虚线对角线表示随机分类器。我们希望我们的分类器尽可能远离这条线(朝向左上角)。
受试者工作特性曲线及其应用。
现在,您可能想知道是否应该使用精确度/召回曲线或 ROC 曲线,因为它们非常相似。当数据集不平衡或者当您更关心假阳性而不是假阴性时,最好使用精度/召回曲线。否则,使用 ROC 曲线。
结论
希望这篇文章已经使您能够为您的问题选择一个合适的度量标准,找到一个好的精确度/召回率的折衷,并使用 ROC 曲线和 ROC AUC 分数来评估和比较各种模型。
一如既往地感谢您花时间阅读我的文章。我希望你从阅读中学到的和我从写作中学到的一样多。
本文中的所有插图都是我画的,我计划画更多像这样的文章。
如果你喜欢这里的内容,就给我一个关注吧!:-)
不平衡数据分类
原文:https://towardsdatascience.com/classification-with-imbalanced-data-f13ccb0496b3?source=collection_archive---------5-----------------------
使用各种重采样方法来改进机器学习模型
照片由 Unsplash 上的 Aziz Acharki 拍摄
在具有大量不平衡类别的数据上构建分类模型可能很困难。使用过采样、欠采样、重采样组合和自定义滤波等技术可以提高精度。
在本文中,我将介绍几种不同的方法来处理分类任务中的数据不平衡。
- 过采样
- 欠采样
- 组合过采样和欠采样
- 自定义过滤和采样
场景和数据概述
为了演示各种类别不平衡技术,将使用一个虚构的信用卡违约数据集。在我们的场景中,我们试图构建一个可解释的分类器,它接受两个输入(年龄和卡余额)并预测某人是否会错过即将到来的付款。
下面的图表显示了数据模型。您将看到数据中有一些随机的默认值(橙色点),但它们只占很小的百分比(374 个训练示例实例中的 24 个,约 6.4%)。这可能会使一些机器学习分类算法变得具有挑战性,并且我们可能希望在某些情况下限制我们潜在的模型选择集,以获得可解释性/监管因素。
在这种情况下,我们的目标是使用逻辑回归的准确率达到 90%以上,F1 分数达到 50%以上(精确度/召回率的调和平均值)。
按作者分类的数据概述、图像和数据
基线逻辑回归
对于用于比较的基线模型,我们将运行简单的 逻辑回归 并绘制决策界限,以及计算各种准确性指标。
基本逻辑回归符合我们 90%以上的准确性目标,但在精确度/召回率方面失败了。您将在下面看到为什么默认类的相对大小如此之小,模型只是将每个单个数据点预测为 未默认 (由决策边界图中的浅蓝色背景表示)。
基线逻辑回归-在任何重采样之前,按作者分类的图像
然而,在我们的数据的左上方有一个明显的部分(非常年轻的高余额年龄),似乎比随机违约更频繁。当引入重采样方法时,我们能做得更好吗?
过采样
处理这个问题的一种流行方法是使用 SMOTE 进行过采样。不平衡学习是一个 python 库,为不平衡类的分类任务提供了许多不同的方法。一种流行的过采样方法是 SMOTE 。
SMOTE 代表合成少数过采样技术。根据名称,您可能会直观地知道它是做什么的——用较少的数据点为类创建合成的附加数据点。它通过考虑其他特征来做到这一点——你几乎可以认为它是在我们必须添加新数据点的少数样本之间使用插值。
应用 SMOTE 很简单;我们只需传入我们的 x/y 训练数据,并取回所需的重采样数据。绘制这些新数据,我们现在显示了类的平均分布(350 个默认与 350 个非默认)。创建了许多新的默认类数据点,这应该允许我们的模型学习一个函数,该函数不仅仅预测每个数据点的相同结果。
SMOTE 调整后的训练数据,图片由作者提供
在这个重新采样的数据上拟合新的逻辑回归模型产生下面的决策边界。
您现在可以看到,不是蓝色背景代表整个图表的非默认决策(如我们的基线模型),而是根据 SMOTE 重采样数据训练的新模型预测左上角部分的默认决策(用浅橙色背景表示)。
SMOTE 决策界限,作者图像
对只有几个数据点的类进行过采样肯定会导致更高的默认预测百分比,但是我们达到目标了吗?准确率下降至约 76%,但 F1 分数上升至约 30%。还没有,让我们尝试一些额外的方法,看看是否可以改进。
欠采样
用较少的例子对类进行过采样的反面是用较多的例子对类进行欠采样。使用编辑最近邻的方法,我们可以战略性地对数据点进行欠采样。这样做将导致以下修改的训练数据——我们仍然有 24 个默认类数据点,但是在我们的新训练数据集中,多数类现在只有原始 350 个数据点中的 287 个数据点。
ENN 调整训练数据,图片由作者提供
这导致以下决策界限。该模型正确地将左上角作为最频繁违约的区域,但 F1 分数并不在我们需要的位置。当然,仍有一些数据点可以捕捉,以创建一个更理想的决策边界。
ENN 决定界限,图像由作者
欠采样+过采样
另一种流行的方法是结合这两种方法。我们可以使用 SMOTE 进行过采样,然后使用 ENN 清理数据点。这在 imblearn 中被称为 SMOTEENN 。
SMOTEENN 调整后的训练数据,图片由作者提供
我们的标签数更接近相等,但是我们的总数据点更少。这对我们的指标有什么影响?
SMOTEENN 决策界限,作者图片
这种方法导致了更多的极端决策边界,准确性进一步下降,F1 分数更低。
自定义采样+ Smote
对于我们的数据,SMOTE 似乎有所帮助,但也许我们可以更有针对性地选择想要过采样的数据点。我们可以采取的一种方法是使用一个简单的 K 最近邻分类器,只挑选那些邻居也属于我们默认的具有某种概率阈值的类的数据点。
有了这些,我们现在有了下面的一组数据——将我们默认的类从 24 个减少到 10 个(但是希望去掉 有噪声的 数据点,这些数据点可能会扰乱我们的 SMOTE 过程并创建过于激进的插值)。
KNN 过滤数据,作者图片
执行 SMOTE(使用与前面步骤中相同的代码)会产生以下训练数据集—从我们最初的 10 个样本中创建 350 个默认的类样本:
自定义采样+ SMOTE 调整后的训练数据,图片由作者提供
我们训练了另一个新的逻辑回归模型和 使用这个重新采样的数据,我们现在达到了我们的目标! 我们可以看到,在对我们调整后的数据进行训练后,决策边界现在考虑到了那部分违约。准确率仍然是 90%以上,F1 分数高于我们 50%的目标。
自定义采样+ SMOTE 决策界限,图片由作者提供
摘要
在建立机器学习模型时,有多种方法来处理不平衡的类。根据您的约束、目标和数据,有些可能比其他更适用。我们还可以提出一些创造性的重采样方法,以便构建一个分类器,正确地针对我们感兴趣的决策范围和场景,过滤掉数据中可能出现的噪声。
所有的例子和文件都可以在 Github 上找到。
原发布于https://data stud . dev。
分类器很简单,如果你认为贝叶斯
原文:https://towardsdatascience.com/classifiers-are-easy-if-you-think-bayes-d3da1afbec36?source=collection_archive---------23-----------------------
许多分类术语与贝叶斯概念直接对应:评估分类器变得容易多了
图片由塔纳西斯·帕帕萨恰里亚斯从皮克斯拜拍摄
评估分类器可能很棘手。首先,术语相当混乱,很难记住。有许多不同的评估指标可用,使用其中一个而不是另一个的原因可能很模糊。
但是这些概念不必混淆。事实上,一旦你以正确的方式构建分类问题,它们就变得相当直观。我最近说服自己,构建这个问题的正确方法是…贝叶斯方法!
在这篇文章中,我将解释很多分类术语是如何与贝叶斯概念一一对应的。这种关系很好理解,所以我在这里没有发现任何新的东西。尽管如此,它很少在教程和书籍中被提及。这很不幸,因为理解这种 1:1 的映射非常重要,原因有二:
- 贝叶斯思维非常直观,这意味着复杂的分类术语变得更加清晰和容易记忆;
- 评估分类器也变得更简单,因为每个评估指标的优点和缺点通过贝叶斯透镜变得直观。
我将从贝叶斯的快速回顾/介绍开始。我将在阐明分类器和贝叶斯术语之间 1:1 映射的同时做到这一点。最后,我将解释这种映射如何对您的分类器日常工作非常有用,尤其是对它们的评估。
开始吧!
(重新)定义分类问题
首先,我们需要一些符号。假设给你一个由特征向量 X 表示的数据点,你知道 X 可以属于两个可能的类之一:类 0 ( y =0)或类 1 ( y =1)。不幸的是,你不知道 X 属于哪一类,但是你得到了一个黑盒(分类器),它做了一个有趣的把戏:它获取特征向量 X ,它进行一些计算并最终输出关于 X 属于哪一类的猜测( g = 1 表示分类器正在猜测类 1, g = 0 类 0)。
根据 Bayes 的说法,这是一个分类器
猜测并不总是可靠的:你在许多测试特征向量上尝试分类器,你最终得到的是正确和错误预测的混合体。因此,自然的问题是:给定这些测试,我如何量化分类器的可靠性?
输入贝叶斯
为了形式化评估分类器的过程,我们将使用贝叶斯规则(或定理)的概率形式,如下所示:
其中 P(…)表示概率,P(…|…)表示条件概率, θ 、 θ 和 O 为随机变量。
简而言之,这条规则显示的是,在进行观察后,我们应该如何将我们之前对理论的信念(最右边的项, P(θ)/P( θ) )改变为新的、更新的信念(最左边的项, P(θ|O)/P( θ|O) ),该信念考虑了观察结果。Bayes 告诉我们,正确的方法是将之前的信念乘以一个乘法因子(中间的那个词, P(O|θ)/P(O| θ) ),我们懂点数学就能计算出来。
这是总的想法,但是为了了解这个公式如何帮助理解分类器,我们需要更详细地研究这个公式的每个组成部分。我们将看到,在我们的分类问题中,每个术语都对应一个等价的概念。
理论
θ和θ是关于世界的两种替代说法或 学说*;*
在我们的分类问题中,这些只是我们关于 X 来源的替代理论,即: θ = " X 属于第 1 类"( y=1 ), θ = " X 属于第 0 类"( y=0 )。我们不知道这两种理论哪一种是正确的,我们希望分类器能提供一些线索。
先前赔率
P(θ)/P( θ)是我们在对世界进行任何观察之前,对理论θ为真的置信度(用赔率表示)( 先验赔率*);*
在我们的分类问题中,这仅仅是 P(y=1)/P(y=0) 。我们应该给这个比率分配什么值?嗯,在询问分类器之前,我们对 X 一无所知,因此合理的做法是将 P(y=1)/P(y=0) 设置为等于这两个阶层在人口中的相对比例(例如,如果你衣柜中白/黑袜子的比例是 3/2,那么你分配给一只随机的白袜子的几率是 3/2)。因此,先验就是我们在分类设置中称之为 1 级的患病率。
小心小概率…(照片由迪伦·诺尔特在 Unsplash 上拍摄)
请注意,严重不平衡的数据集将导致先前的赔率非常高(因为分子 P(y=1) 接近 1,分母 P(y=0) 接近 0)或非常低( P(y=1) 接近 0, P(y=0) 接近 1)。
观察
O 是一个 观察 ,一个我们碰巧观察到的与理论θ和θ 有关的世界事实
在我们的分类问题中,当我们将特征向量 X 馈送给分类器时,观察值 O 是分类器的输出。换句话说,就是分类器对 X 的类的猜测。这是我们想要用来改变我们先前对 θ的信念的信号。
我们用二进制变量“ g ”来表示这个猜测。为了简单起见,我们假设分类器是猜测类 1,即 g = 1 。
一个拟人化的分类器正试图猜测(照片由莱曼·汉瑟·杰罗娜在 Unsplash 上拍摄)
似然比
P(O|θ)是理论θ赋予事实“O”发生的概率。它被称为θ的“似然函数”。同样,P(O| θ)是θ分配给“O”发生的概率。他们的比率 P(O|θ)/P(O| θ)被称为“ 【似然比 ”,它量化了理论θ在多大程度上给观察“O”比θ不同(更高或更低)的概率:如果差异很大(似然比非常高或非常低),那么这一项乘以先前的赔率将导致我们信念的强烈更新,这具有直观意义。
在我们的分类问题中, P(O|θ) = P(g =1|y=1) :这是分类器会猜测 X 属于第 1 类( g=1 )的概率,在 X 确实属于 1 ( y=1 )的场景下。如果你熟悉(令人困惑的)分类器术语,你会知道这只不过是分类器的真阳性率(TPR) !
而 P(O| θ) 呢?这就是 P(g =1|y=0) ,即当实际上 X 属于 0 类时,分类器会猜测 X 属于 1 类的概率。你认出它了吗?这个术语无非就是假阳性率(FPR) !
这两项都可以很容易地用你收集的关于测试特征向量的实验来计算。
现在,这两项在贝叶斯规则中以比率的形式出现, P(g =1|y=1)/P(g =1|y=0) 。我们刚刚展示了这可以重写为 TPR/FPR。
有印象吗?你知道任何比较 TPR 和 FPR 的分类标准吗?具体来说,TPR/FPR 的比率越高,度量就越高?是的, AUC !!这个非常常见的分类器的度量只是简单地描述了贝叶斯定理中的似然比!
计算 AUC 的 ROC 曲线示例( MartinThoma,CC0,通过 Wikimedia Commons )
后验概率
P(θ|O)/P( θ/O)是我们在观察事实 O ( 后验概率 )后对理论θ的确信程度(再次表示为赔率)。根据贝叶斯规则,它可以通过将先验概率乘以似然比来计算。
在我们的分类问题中,后验概率是 P(y=1|g=1)/P(y=0|g=1) 。
如果我们思考这个表达式的含义,我们会立即意识到分子 P(y=1|g=1) (当分类器预测时 X 真正属于第 1 类的概率)是分类器的精度!这是分类器的另一个流行的评估指标,通常被描述为 AUC 的替代。我们可以看到这两者是如何通过贝叶斯法则紧密联系在一起的。
顺便说一下,后验概率的分母 P(y=1|g=0) ,也是一个标准的分类指标——尽管在数据科学家中没有 precision 那么受欢迎——称为错误发现率。
分类器,重温
现在让我们欣赏贝叶斯框架给我们的关于分类器的新视角。为此,在这里重写贝叶斯规则是有用的,连同贝叶斯术语(公式的顶部)和相应的分类器概念(底部):
贝叶斯规则,分类器(底部)和贝叶斯术语(顶部)之间的对应关系(图片由作者提供)
我们发现 AUC(以及从中得出的 ROC 曲线)只不过是一种总结似然比的方法。如果我们再看看贝叶斯规则,我们认识到似然比是将先验信念转换为后验信念的乘法因子。因此AUC 真正量化的是使用分类器改变我们的先验概率的程度:如果乘法因子非常高或非常低,那么分类器的使用将显著改变我们关于 X 属于哪一类的信念,这是好的(AUC 将用接近 1 的值捕捉这一事实);如果乘法因子反而接近 1,那么它对先验的影响将是可忽略的,我们的先验信念不会改变太多,并且分类器是无用的(并且 AUC 将接近 0.5)。
这使得 AUC(以及总体 ROC 曲线)成为评估分类器的一个很好的默认选项。它有一个很好的特性,就是作为一个关于分类器的度量标准,而不是其他任何东西——特别是,它不是关于数据集的(数据集的属性,比如类之间的比例,是由先前的概率捕获的)。
然而,AUC 和似然比没有捕捉到的是使用分类器后我们将得到的关于 X 的绝对置信度……毕竟,似然比只是告诉我们,由于使用了分类器,先验信念发生了多大程度的变化。但是有些情况下,即使一个非常强大的贝叶斯更新也不会改变太多,在实践中,你对理论的信心 θ …
例如,如果在使用分类器之前,您认为 X 非常非常不可能属于类别 1(假设θ的先验概率为 1/1,000,000),那么即使使用强贝叶斯更新(假设可能性比为 100)也不会改变我们的情况(后验概率将为 100*1/1,000,000 = 1/10,000,这仍然是极小的概率)。正如我们所见,当目标样本严重失衡时,这些非常小的先验概率就会出现。
这就是精确度发挥作用的地方。当目标不平衡时,Precision 是更好的选择,因为在这种情况下,您希望在使用分类器后查看您的信念——也就是说,您希望查看后验概率。精度完全是 that⁴.
优秀的 AUC?在全押之前,你可能还是想检查一下你的后验概率(图片由 cottonbro 提供,来自 Pexels
后验概率(又名精度)的缺点是,因为它们考虑了似然比和先验概率,所以它们不仅仅是关于分类器的度量。相反,它们测量分类器的可靠性(似然比)和应用分类器的实际数据集(先验概率)之间的相互作用(实际上是乘积)。因此,尽管精度很有用,但它并不能告诉我们分类器本质上有多好,而且它会随着数据集的变化而变化(特别是,如果您在生产中获得的类的流行程度与训练集不同,它也会变化)。
不需要选择一个指标(如果你认为贝叶斯)
那么,哪个指标是最好的呢?像往常一样,没有明确的答案,这完全取决于你的特定问题和背景。标准的手册答案是,通常应该选择 ROC/AUC,除非目标严重失衡,在这种情况下,您希望使用 precision。
作为经验法则,这很好,但是我希望通过用贝叶斯术语来描述这个问题,你现在能够看到这个启发背后的原因。ROC/AUC 通常是一个很好的默认选择,因为可能性评估了分类器在分离两个类别时的内在性能,与类别 1 与类别 0 相比有多罕见的问题无关(编码在先前的优势中)。当目标不平衡时,Precision 是更好的选择,因为在这种情况下,即使是好的分类器也只能给我们很小的信心,在实践中,关于分类问题,你会意识到只看后验概率。
理想情况下,你希望看到两者的全貌。您既想知道分类器总体上有多好,又想知道它在实践中与数据集的交互有多好。如果你思考贝叶斯,你就能记住这两个方面,做出更好的决定。
[1]从技术上讲,AUC 是在分类器阈值的整个范围内总结 TPR/FPR 比率*,而在这个贝叶斯框架中,为了简单起见,我们保持阈值固定。*
[2]通常其形式是在分类器阈值的整个范围内取平均值,也称为平均精度。
[3]非常小的似然比实际上会转化为接近 0 而不是 1 的 AUC,但我们可以将这种情况视为以错误方式使用的良好分类器…
[4]通过贝叶斯框架,很明显整个“如果目标不平衡,不要使用 AUC”的建议只是为了避免基础利率谬误。
用自然语言处理对投诉进行分类
原文:https://towardsdatascience.com/classifying-complaints-with-natural-language-processing-e3b2765d525f?source=collection_archive---------21-----------------------
如何使用 NLP 模型对传入的消息进行排序
图片由作者提供,布鲁诺/德 / 皮克斯拜
消费者金融保护局 (CFPB),一个 2011 年才开始运作的联邦机构,在金融领域照顾消费者的利益。作为这一使命的一部分,当消费者觉得自己受到了征信机构、银行、信用卡公司或其他金融服务提供商的不公正对待时,他们可以提出投诉。
这些投诉可供数据科学家下载,作为一个数据集,它们为构建自然语言处理(NLP)分类系统提供了一个很好的切入点。
我创建了一个模型来分析投诉,并将其分为五类。这种模型或类似的模型有许多实际用途。它可以用于简化组织的传入消息的路由和处理,并可以简化消费者的投诉提交过程。
类别
除了投诉的叙述和关于他们自己的信息,在线表格还要求消费者将他们提交的材料分为九个产品类别中的一个。我的数据集包括一年的提交内容,经过清理后有 16 万条叙述。出于我的目的,我最终将产品类别分为五类:
- 信用报告
- 收债
- 信用卡(包括预付卡)
- 抵押贷款(包括助学贷款、车贷等。)
- 零售银行业务(包括储蓄和支票账户以及 Venmo 等在线服务)
对于大多数班级来说,特定的单词占主导地位。例如,该饼图显示术语“card”在信用卡类中出现 67.6%,但在抵押和贷款类中只出现 1.71%。
在我的探索性数据分析过程中,我还发现这些类是不平衡的。超过一半的提交属于信用报告类别,其他四个类别占提交的 8%到 14%。
阶级失衡
处理建模投诉
为了用数据训练一个机器学习模型,首先我必须把它转换成模型可以使用的形式。
- 我把每个故事都符号化了。换句话说,我将叙述拆分成一个(小写)单个字符串的列表:["my "、" bank "、" scammed "、" me"]。
- 从标记中,我删除了任何带有数字、标点符号或奇怪符号的字符串,如“xxxx ”, CFPB 在匿名化数据时将这些符号用作占位符。
- 我知道像“银行”和“信贷”这样的词可能对我的模型有用,而像“the”和“if”这样的词太常见了,没有什么帮助。所以,我去掉了这些所谓的停用词。
- 在语言学中,一个引理是字典中的关键词;这就是为什么“购买”、“购买”和“已购买”都出现在购买条目下。我对叙述的符号进行了符号化,将单词简化为它们的关键概念。
- 最后,我必须将单个令牌连接回更长的字符串,以便模型能够使用它们。
经过这些转换后,数据集中的第一个叙述现在以“采购订单日发货金额收到……”开始这种文本作为人类语言没有什么意义,但可以用于 NLP 模型。
建模管道
在建模之前,我必须再次通过矢量化来转换数据。换句话说,我使用工具给投诉语料库中的每个词分配一个数字频率。然后,我将语料库分为训练集(80%)和测试集(20%)。
我尝试了各种类型的模型,即多项朴素贝叶斯、随机森林、决策树、KNN、梯度推进和 XG 推进,或多或少使用了默认参数。我寻找那些有大量正确分类的文本,并且在训练集和测试集之间有相似结果的模型,这意味着模型不会过度拟合数据。
从我的前三个基线模型中,我试验了各种参数来改善结果。除了调整模型的参数,我还尝试了两种矢量化技术的不同参数,计数矢量化和 TF-IDF。
我的获胜者是一个计数矢量器,带有多项式朴素贝叶斯模型,这种组合将 86%的文本分类到正确的类别中。我使用了另一个模型,Gradient Boosting,它的性能与获胜的那个相差不远,来检查它发现的对投诉分类最重要的特征(在这种情况下是单词)。
为了再次检查我的管道,我从 CFPB 的 API 下载了 1000 个新提交的内容。我通过函数运行它们,以处理用于建模的投诉,对数据进行矢量化,并将其输入到训练好的模型中。我得到了类似的结果,模型对新投诉的正确分类率为 84%。本质上,一旦模型被训练,机构理论上可以使用它来实时分类收到的提交。
局限性和展望
我使用的数据的一个局限性是,产品类别是由消费者自己选择的。考虑到他们可能不太了解金融服务业务,他们可能选择了错误的类别。让 CFPB 的员工仔细检查记叙文的类别会很有趣,尤其是那些被模型错误分类的类别。
即使这些分类都是正确的,这 160,000 个故事仍然需要由人类来分类。尽管幸运的是,这些投诉被标记了产品类别,但是当文本没有被预先标记时,它可能是 NLP 建模的绊脚石。(见我的中帖可能解决这个问题。)
然而,我使用的过程可以被复制用于其他 NLP 分类任务,无论是将文本分类为问题、子主题还是情感。在有人可以选择将文本标记为我不知道的数据集中,数据科学家可以使用标记有确定内容的文本来重新处理我不知道。一般来说,NLP 技术非常有用和有效。
[ 项目的 GitHub 资源库
使用录音和 Python 对情绪进行分类
原文:https://towardsdatascience.com/classifying-emotions-using-audio-recordings-and-python-434e748a95eb?source=collection_archive---------5-----------------------
实践教程
声音和声学理论可以用于尖端的情感识别技术。下面是我们如何使用 Python 来应用它
在过去的几年中,情感识别技术已经被广泛应用于各种不同的应用中,并且在当今的行业中似乎变得更加流行。从心理学研究到客户需求的高级分析,这些技术的潜力似乎是无穷无尽的。然而,对于不具备音频帧和声波分析专家特权的普通数据科学家来说,这些方法仍然被认为是极其复杂和难以理解的。
在本文中,我们的目标是通过展示一个使用 python 和 Librosa 的情感识别分类器的例子,使这一过程尽可能地容易和简单——这是一个 python 包,使音频文件的分析变得非常简单和直接。我们将从理论和技术上解释这个过程的每一步。
首先,为了理解如何创建一个处理音频声音并理解其内在含义的算法,我们首先需要理解人类大脑是如何做完全相同的事情的。
声波等等
我们要讲的第一个术语是声波。声音可以定义为通过弹性材料介质(如空气)传播的机械扰动。它以纵波形式传播(因此称为“声波”),由交替的压缩和稀疏,或者高压区域和低压区域组成,以一定的速度移动。我们的身体能够产生声波的方式源于我们的声门脉冲,当我们说话时,声门脉冲操纵我们的声带。这显然对产生声音非常有帮助,但不足以真正理解它们,更不用说相互交流了。为了实现这一点,我们有自己的声道。
声道是一个描述我们口腔和咽喉中不同器官系统的术语,包括鼻腔、舌尖、牙齿、软腭等等。这个系统的目标是作为我们声门脉冲的过滤器,以某种方式理解我们产生的不同声音。为了让事情变得简单,我们可以说我们的语言是我们使用声道对我们的声门脉冲进行不同运动和操作的结果。稍后,我们将更多地讨论分析这些声波的方法,但现在,在我们深入这项任务的更务实部分时,让我们记住这些细节。
我们的数据集——探索声波
为了创建这个算法,我们结合了三个不同的数据集,其中包括语音记录和它们各自的标签——快乐、悲伤、愤怒、平静等。我们使用的数据集是拉夫德斯、苔丝和 SAVEE 。由于最终的数据集似乎在某些特征上非常不平衡(例如,我们的男性记录比女性记录少得多,与“消极”情绪相比,“积极”情绪的数量相对较少),我们决定首先从简化的模型开始——对男性和女性进行 3 个不同类别的分类(总共 6 个不同类别【1】):
mydf.head()
我们的数据集
mydf.info()
使用我们之前提到的 Librosa,我们成功绘制了一个声波的原始显示:
ind = np.random.randint(0,len(mydf))
data, sampling_rate = librosa.load(mydf['path'][ind], sr=44100)
emotion = mydf['emotion2'][ind]plt.title(f'Sound wave of- {emotion}')
librosa.display.waveplot(data, sampling_rate)
plt.show()
声波表示
然后,我们在时间-频率域中显示相同的信号,以便我们可以检查信号随时间变化的不同频率和幅度。这是通过对我们的数据执行傅立叶变换来实现的:
D = np.abs(librosa.stft(data))
librosa.display.specshow(D, sr=sampling_rate, x_axis='time', y_axis='linear');
plt.colorbar()
plt.show()
光谱的线性表示
上面的图显示了我们的频率随时间变化的线性表示,似乎没有给我们太多有价值的信息。原因是人类只能听到集中在非常小的频率和振幅范围内的声音(例如,不像狗)。为了解决这个问题,我们对频率和振幅都应用了对数标度。请注意,对数据应用对数标度后,我们不再以幅度为单位测量信号,而是以分贝为单位。
DB = librosa.amplitude_to_db(D, ref=np.max)
librosa.display.specshow(DB, sr=sampling_rate, x_axis='time', y_axis='log');
plt.colorbar(format='%+2.0f db')
plt.show()
声谱图
这个结果提供了更多的信息,因为我们可以看到不同频率的分贝数随时间的变化。这种表示的正式术语叫做声谱图。由于声谱图能够近似人类对声音的感知,因此声谱图本身也被证明在情绪分类方面非常有用。
深入声波中
既然我们已经了解了声谱图,让我们考虑一下声波的频谱;也就是说,在我们给定的时间范围内,分贝与频率的关系如下:
plt.magnitude_spectrum(data, scale='dB')
plt.show()
对数标度谱
对数标度谱是通过对我们的数据应用傅立叶变换,然后对结果进行对数标度变换而获得的。频谱图和对数标度频谱都是通过类似的数学运算实现的,它们之间的区别在于,前者显示的是频率和分贝随时间的变化,而后者显示的是分贝和频率之间的关系。一个细微但重要的区别。
回到我们对语音的定义,我们可以说我们的对数标度频谱是语音本身的非常准确的表示。正如我们前面提到的,语言可以被描述为声道和声门脉冲的结合。为了有效地分析我们的语音,我们需要从没有附加噪声的语音中提取声道,声道类似于滤波器,包含关于声音含义的完整信息。为了简化事情,我们需要从没有声门脉冲的语音中提取声道。
现在让我们考虑对数标度频谱的更平滑版本——频谱包络:
光谱包络
上面的图类似于我们的对数标度谱的主要和最重要的部分——我们可以检查主要的周期性、最大值点(用红色标记)以及总体趋势。这个频谱包络相当于我们所认为的声道,其最大值点称为“共振峰”。这些波峰包含了声音的主要“身份”,被认为是我们声波中最重要的部分。研究表明,我们的大脑可以通过共振峰来识别大部分讲话的意思。
MFCC 是这次任务的目标
既然我们认识到了我们的声道,我们需要找到一种方法从我们的讲话中提取它。为此,我们需要再进行一些数学运算。首先,我们需要将对数标度频谱转换为 Mel 标度【2】,然后对数据执行离散余弦变换。最后一个变换与我们之前使用的傅立叶变换相对相似,因为它也从我们当前的状态创建了一个光谱。所以基本上,我们在这里做的是在之前的光谱上创建一个光谱。我们的新频谱现在被称为倒谱,而我们的新频率被称为倒频。所有这些混乱的原因很简单——使用我们新的倒谱和倒频,我们可以很容易地区分我们的频谱包络(声道)和噪音(声门脉冲)。不仅如此,离散余弦变换已经产生了这个倒谱的主要和最重要的系数——梅尔频率倒谱系数,也称为 MFCC 系数!
幸运的是,Librosa 让这项工作变得非常简单,我们可以用一行简单的代码提取 MFCC 氏症,我们很快就会看到。
数据准备
要使用 MFCC 作为我们的特征,我们首先需要他们在一个同质的形状。由于我们的每一个信号波的长度都略有不同,这个过程也会导致 MFCC 波的长度不同,这对于为我们的数据创建模型没有太大的帮助。因此,我们首先使所有信号波的长度相同——比平均值短的信号被填充(使用中值),比平均值长的信号被截断(我们还事先去掉了极端长度的信号)。
然后,我们很容易地从每个信号波形中提取出 MFCC。我们从每个信号波中提取 20 个不同的系数,每个系数包含一个给定长度的向量。注意——传统的 MFCC 数通常是 12-13,Librosa 函数的默认值是 20。第一个系数通常是携带关于语音的大多数重要信息的系数,因此在大多数情况下,使用大量的 MFCC 不会改进模型。
mfccs = []
for i in tqdm(X):
mfcc = librosa.feature.mfcc(y=i, sr=44000, n_mfcc=20)
mfcc = mfcc.T
mfccs.append(mfcc)
正如我们所见,每个样本包括 20 个长度为 236 的 MFCC,每个长度为【3】。在此过程中,我们还丢弃了 3 个异常值。现在,我们终于为建模做好了准备。
建模
众所周知,RNN 网络非常适合语音识别任务。然而,有大量的研究证明,在很多情况下,CNN 网络可以胜过 RNN 网络。在这种情况下,我们决定使用 1 维卷积层和 1 维池层来构建 CNN 网络(因为我们的训练数据由 3 维组成)。
我们的 CNN 网络由两个模块组成,每个模块由 1 维卷积层、激活函数(“ReLu”)、1 维池层和 dropout 构成。这两个模块之后是两个完全连接的密集层和一个“SoftMax”激活功能,因为我们正在处理一个多类问题:
model = Sequential()model.add(layers.Conv1D(256, 5,padding='same',
input_shape=(236,40)))
model.add(layers.Activation('relu'))
model.add(layers.MaxPooling1D(pool_size=(8)))
model.add(layers.Dropout(0.2))model.add(layers.Conv1D(128, 5,padding='same'))
model.add(layers.Activation('relu'))
model.add(layers.MaxPooling1D(pool_size=(4)))
model.add(layers.Dropout(0.1))model.add(layers.Flatten())
model.add(layers.Dense(64))
model.add(layers.Dense(7))
model.add(layers.Activation('softmax'))
我们设法达到了相对较好的结果,达到了 90%的准确率。正如所料,男性录音的分数明显低于女性,因为我们的数据集中男性样本少得多:
我们第一个分类模型的指标
之后,我们瞄准了一个更复杂的模型——对不同的情绪进行分类:“恐惧”、“惊讶”、“悲伤”、“厌恶”、“快乐”、“愤怒”和“中性”【4】。样本的分布比前一次更平衡,所以我们期望这次的分类更平衡。
不同情绪的分布——我们第二个分类模型的目标
我们对数据进行了与之前相同的处理,并运行了完全相同的模型。这些是我们得到的结果:
我们第二个分类模型的指标
正如所料,这种分类看起来相对平衡,结果也相当不错。我们还可以观察混淆矩阵,它表明我们的绝大多数样本被正确分类:
有趣的是,有相当多被预测为‘中性’的样本结果是‘悲伤’(1.5%)。这也许可以用声音表达悲伤时的微妙特征来解释,这些特征很可能被误认为与中性情绪有关。
然后,我们想进一步检查这些类之间的关系,所以我们使用 PCA 和 KMeans 聚类进行降维,将数据分为 7 个聚类。我们的希望是找到 7 个独特的群体来对应我们的 7 种情绪。我们通过检查分类标签和类别预测之间的相关性并查看与不同标签相关的类别分布,来检查分类标签和类别预测之间的关系。最终我们得出了这个散点图:
我们可以清楚地检查 7 个不同的集群。我们注意到的第一件事是“愤怒”似乎相对独立于其他情绪。“中性”似乎位于中间,这当然是有意义的,而且它和“悲伤”之间也有一些接近,这可以解释我们之前关于两者之间联系的假设。“厌恶”也接近于“悲伤”,而“快乐”接近于“惊讶”——两者似乎都很直观。解释“恐惧”的位置有点困难,因为它最近的邻居是“快乐”,这没什么意义。在这种情况下,I t 与“惊喜”的接近似乎更直观。
总的来说,这些结果证明了即使使用一个简单的 CNN 网络,我们也可以以很高的可信度从音频记录中对情绪进行分类,甚至检查它们之间的关系。
最后的话
音频分类之所以如此有趣,是因为复杂的理论可以用普通的实用方法来表达。数学程序可以用来成功地实现这些概念的方式是不可思议的。幸运的是,大部分艰苦的工作都是由预制工具完成的。然而,了解这些工具背后的理论概念仍然是成功构建和使用这些模型的关键。
我们希望这篇文章有助于阐明这个迷人的主题,使它更容易理解,也希望更有用。
欲了解更多信息,请点击查看我们的项目。
参考
-https://www . Microsoft . com/en-us/research/WP-content/uploads/2016/02/CNN _ aslptrans 2-14 . pdf
-https://www . izotope . com/en/learn/understanding-spectrograms . html
——【https://arxiv.org/pdf/2007.11154.pdf
-https://arxiv.org/pdf/2012.14781.pdf
——https://saurabhgarg1996.github.io/files/6.pdf
-https://www.youtube.com/watch?v=4_SH2nfbQZ8&t = 1357s
- http://www . socsci . UCI . edu/~ JSP rouse/courses/S12/155/lectures/lectures 4
- https://librosa.org/doc/latest/index.html
【1】数据框中的列“情绪 2”是我们的第一个目标,列“情绪 3”是我们的第二个目标。本文稍后将对这两种方法进行更详细的描述。
【2】一种以更真实的方式模拟人类声谱的音阶,因为人耳无法轻易识别高于 500Hz 的频率变化。
【3】为了简单起见,我们调换了 MFCC 的形状。
注意,为了达到平衡的分类,我们使用了具有更多样本的情感。
使用多层感知器分类器(MLP)对手写数字进行分类
原文:https://towardsdatascience.com/classifying-handwritten-digits-using-a-multilayer-perceptron-classifier-mlp-bc8453655880?source=collection_archive---------10-----------------------
什么是多层感知器?MLP 的利与弊是什么?我们能用 MLP 分类器准确地分类手写数字吗?学来的重量是什么样的?
图 1:一个多层感知器网络(来源)。
1.简短介绍
1.1 什么是多层感知器(MLP)?
一个 MLP 是一个监督机器学习(ML)算法,属于前馈人工神经网络类[1]。该算法本质上是对数据进行训练,以便学习一个函数。给定一组特征和目标变量(例如标签),它学习用于分类或回归的非线性函数。在本文中,我们将只关注分类的情况。
1.2 MLP 和逻辑回归之间有什么相似之处吗?
有!逻辑回归只有两层,即输入和输出,然而,在 MLP 模型的情况下,唯一的区别是我们可以有额外的中间非线性层。这些被称为隐藏层。除了输入节点(属于输入层的节点),每个节点都是一个使用非线性 激活 函数【1】的神经元。由于这种非线性性质,MLP 可以学习复杂的非线性函数,从而区分不可线性分离的数据!参见下面的图 2 中带有一个隐藏层的 MLP 分类器的可视化表示。
如果你想在交互式路线图和活跃的学习社区的支持下自学数据科学,看看这个资源:https://aigents.co/learn
1.3 如何训练 MLP?
MLP 使用反向传播进行训练【1】。你可以看看这个网站这里的正式数学公式。
1.4 Main 的主要优势和劣势
优点
- 可以学习非线性函数从而分离不可线性分离的数据【2】。
缺点
- 隐藏层的损失函数导致一个非 - 凸优化问题,因此存在局部最小值。
- 由于上述问题,不同的权重初始化可能导致不同的输出/权重/结果。
- MLP 有一些超参数,例如隐藏神经元的数量,需要调整的层数(时间&功耗)[2]。
- MLP 可以是敏感的特征缩放【2】。
图 2:带有一个隐藏层和一个标量输出的 MLP。图片改编自 scikit-learn python 文档。
2.使用 scikit-learn 的 Python 实践示例
2.1 数据集
对于这个动手操作的例子,我们将使用 MNIST 数据集。MNIST 数据库是著名的手写数字数据库,用于训练几个 ML 模型[5]。有 10 个不同数字的手写图像,因此类别数为10
(参见图 3 )。
注:由于我们处理的是图像,这些用2D数组表示,数据的初始维数是每幅图像的**28** by **28**
(28x28 pixels
)。然后,2D 图像被 展平 ,并因此在最后由矢量表示。每个 2D 图像被转换成一个尺寸为[1, 28x28] = **[1, 784]**
的 1D 向量。最后,我们的数据集有***784***
特征/变量/列。
图 3:来自数据集的一些样本(来源)。
2.2 数据导入和准备
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_openml
from sklearn.neural_network import MLPClassifier
# Load data
X, y = fetch_openml("mnist_784", version=1, return_X_y=True)# Normalize intensity of images to make it in the range [0,1] since 255 is the max (white).
X = X / 255.0
记住每个 2D 图像现在被转换成一个 1D 向量与维度[1, 28x28] = **[1, 784]**
**。**现在我们来验证一下这个。
print(X.shape)
这返回:**(70000, 784)**
。我们有 70k 的展平图像(样本),每个包含 784 个像素(28*28=784)(变量/特征)。这样,输入 层 权重 矩阵将具有形状784 x #neurons_in_1st_hidden_layer.
输出层权重矩阵将具有形状 #neurons_in_3rd_hidden_layer x #number_of_classes.
2.3 模型培训
现在让我们建立模型,训练它并执行分类。我们将使用3
隐藏层,每个层分别带有50,20 and 10
神经元。此外,我们将最大迭代次数设置为100
,学习率设置为0.1
。这些就是我在介绍中提到的超参数。我们不会在这里对它们进行微调。
# Split the data into train/test sets
X_train, X_test = X[:60000], X[60000:]
y_train, y_test = y[:60000], y[60000:]
classifier = [MLPClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPClassifier.html#sklearn.neural_network.MLPClassifier)(
hidden_layer_sizes=(50,20,10),
max_iter=100,
alpha=1e-4,
solver="sgd",
verbose=10,
random_state=1,
learning_rate_init=0.1,
)# fit the model on the training data
classifier.fit(X_train, y_train)
2.4 模型评估
现在,让我们来评估这个模型。我们将估计训练和测试数据和标签的平均准确度。
print("Training set score: %f" % classifier.score(X_train, y_train))
print("Test set score: %f" % classifier.score(X_test, y_test))
训练集得分:
0.998633
测试集得分:0.970300
伟大的成果!
2.5 可视化成本函数演变
训练中损失减少的速度有多快?我们来编一个好看的剧情吧!
fig, axes = plt.subplots(1, 1)axes.plot(classifier.loss_curve_, 'o-')
axes.set_xlabel("number of iteration")
axes.set_ylabel("loss")
plt.show()
图 4:训练迭代中损失的演变。图由作者制作。
在这里,我们看到损失在训练期间下降得非常快,并且在40th
迭代之后饱和(记得我们将最大 100 次迭代定义为超参数)。
2.6 可视化学习到的重量
这里,我们首先需要了解权重(每层的学习模型参数)是如何存储的。
根据文档,属性classifier.coefs_
是权重数组的形状(n_layers-1, )
列表,其中索引 I 处的权重矩阵表示层i
和层i+1
之间的权重。在这个例子中,我们定义了 3 个隐藏层,我们还有输入层和**输出层。**因此,我们期望层间权重有 4 个权重数组(图 5 中的in-L1, L1-L2, L2-L3
和 L2-out
)。
类似地,classifier.intercepts_
是偏置向量的列表,其中索引i
处的向量表示添加到层i+1
的偏置值。
图 5:作者在 Notes (iOS)上的手工图。
让我们验证一下:
len(classifier.intercepts_) == len(classifier.coefs_) == 4
正确返回True
。
提醒:输入 层 权重 矩阵将具有形状784 x #neurons_in_1st_hidden_layer.
输出层权重矩阵将具有形状 #neurons_in_3rd_hidden_layer x #number_of_classes.
可视化输入层的学习权重
target_layer = 0 #0 is input, 1 is 1st hidden etcfig, axes = plt.subplots(1, 1, figsize=(15,6))
axes.imshow(np.transpose(classifier.coefs_[target_layer]), cmap=plt.get_cmap("gray"), aspect="auto")axes.set_xlabel(f"number of neurons in {target_layer}")
axes.set_ylabel("neurons in output layer")
plt.show()
图 6:输入和第一个隐藏层之间的神经元的学习权重的可视化。图由作者制作。
或者把它们重新塑造成 2D 的形象。
# choose layer to plot
target_layer = 0 #0 is input, 1 is 1st hidden etcfig, axes = [plt.subplots](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html#matplotlib.pyplot.subplots)(4, 4)
vmin, vmax = classifier.coefs_[0].min(), classifier.coefs_[target_layer].max()for coef, ax in zip(classifier.coefs_[0].T, axes.ravel()):
ax.matshow(coef.reshape(28, 28), cmap=plt.cm.gray, vmin=0.5 * vmin, vmax=0.5 * vmax)
ax.set_xticks(())
ax.set_yticks(())
[plt.show](https://matplotlib.org/api/_as_gen/matplotlib.pyplot.show.html#matplotlib.pyplot.show)()
3.摘要
MLP 分类器是一个非常强大的神经网络模型,能够学习复杂数据的非线性函数。该方法使用前向传播来构建权重,然后计算损失。接下来,使用反向传播来更新权重,从而减少损失。这是以迭代的方式完成的, 迭代的号 是一个输入超参数**,如我在介绍中所解释的。其他重要的超参数是每个隐层中** 神经元的数量 和总共的隐层数量**。这些都需要微调。**
那都是乡亲们!希望你喜欢这篇文章!
只需 5 秒钟就可以订阅我的邮件列表:https://seralouk.medium.com/subscribe
敬请关注并支持这一努力
如果你喜欢并发现这篇文章有用,请关注我!
有问题吗?把它们作为评论贴出来,我会尽快回复。
最新帖子
https://medium.com/mlearning-ai/how-to-use-python-sql-to-manipulate-data-in-1-min-bbf9ec17dc5d
参考
[1]https://en.wikipedia.org/wiki/Multilayer_perceptron
[2]https://sci kit-learn . org/stable/modules/neural _ networks _ supervised . html # MLP-tips
[3]https://scikit-learn . org/stable/modules/neural _ networks _ supervised . html # mathematical-formulation
https://en.wikipedia.org/wiki/Backpropagation
https://en.wikipedia.org/wiki/MNIST_database
和我联系
- 邮件列表:https://seralouk.medium.com/subscribe
- 领英:https://www.linkedin.com/in/serafeim-loukas/
- 研究之门:https://www.researchgate.net/profile/Serafeim_Loukas
使用 PCA +深度学习对 MNIST 数字进行分类
原文:https://towardsdatascience.com/classifying-mnist-digits-using-pca-deep-learning-852aeaff48a5?source=collection_archive---------15-----------------------
用 PCA 对 MNIST 数据进行预处理,建立更高效的 CNN 模型
由尼克·希利尔在 Unsplash 上拍摄
什么是主成分分析?
数据科学中的许多重要概念之一包括主成分分析(PCA),这是一种无监督的学习方法。它通常被用作大型数据集的降维方法或简化其复杂性,这是通过将一组大型变量转换为一组小型变量,同时保留数据集中的大部分变量来实现的。PCA 通过将数据几何投影到更低的维度上来减少数据,这些维度又被称为主成分(PC)。该方法的目标是通过使用最少的主成分找到我们数据的最佳摘要,通过选择我们的主成分,我们最小化原始数据与其在主成分上的投影值之间的距离。
什么是深度学习?
深度学习是机器学习的一个子集,受人脑结构的启发。深度学习算法试图通过不断分析具有给定逻辑结构的数据,得出与人类相似的结论。为了实现这一点,深度学习使用了一种多层结构的算法,称为神经网络。无论是 Alexa、Siri 还是 Cortana,深度学习都有助于他们理解语音和语言。深度学习使用不同类型的神经网络架构,如对象识别、图像和声音分类以及针对不同类型问题的对象检测。深度学习算法训练的数据越多,它就越准确。
MNIST 数据集
MNIST 数据集(修改后的国家标准与技术研究所数据库)是深度学习爱好者中更受欢迎的数据集之一。该数据集包含 42,000 个带标签的灰度图像(28 x 28 像素),这些图像是训练集中从 0 到 9 的手写数字,以及 28,000 个未带标签的测试图像。
在这篇博客中,我将演示如何使用 PCA 建立 CNN 模型来识别 MNIST 数据集中的手写数字,以实现高精度。
要遵循的步骤
- **导入库并加载数据集:**导入必要的库、包和 MNIST 数据集
- 数据预处理
- PCA 实施
- 创建 CNN 模型
- 训练和评估模型
1.导入库并加载数据集
我们首先导入训练数据所需的所有必要的库,然后加载我们的 MNIST 数据集,可以在这里找到—您也可以使用 keras.datasets 来导入 mnist 数据集!
# Import Libraries
%matplotlib inline
import pandas as pd
from sklearn.decomposition import PCA
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from keras.utils.np_utils import to_categorical
from sklearn.preprocessing import LabelEncoderfrom tensorflow.keras.layers import Input,InputLayer, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D
from tensorflow.keras.layers import AveragePooling2D, MaxPooling2D, Dropout
from tensorflow.keras.models import Sequential,Model
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.callbacks import ModelCheckpoint,LearningRateScheduler
import keras
from tensorflow.keras import backend as K
from sklearn.preprocessing import StandardScaler
from scipy.linalg import eigh# Load the Dataset
train = pd.read_csv("data/train.csv")
test = pd.read_csv("data/test.csv")
train.head()
作者图片
数据集的样本图像:
作者图片
2.预处理数据
首先,我们将数据集分成训练集和测试集
y_train = train['label']
X_train = train.drop(['label'], axis=1)
X_test = test
X_train.shape, y_train.shape, X_test.shape#Output
((42000, 784), (42000,), (28000, 784))X_train = X_train/255
X_test = X_test/255
注意,我们没有 y_test,因为测试集的标签没有给出。接下来,我们将标准化数据,这在 PCA 实施中很重要,因为它将原始数据投影到最大化方差的方向上。
3.PCA 实施
现在,我们将对我们的数据实施 PCA。首先,我们将标准化我们的数据,并计算我们的协方差矩阵。协方差可以认为是变量之间线性关系的方向。协方差矩阵是降维的第一步,因为它给出了强相关特征数量的概念,并且它通常是降维的第一步,因为它给出了强相关特征数量的概念,以便可以丢弃那些特征。
standardized_scalar = StandardScaler()
standardized_data = standardized_scalar.fit_transform(X_train)
standardized_data.shape# Output
(42000, 784)cov_matrix = np.matmul(standardized_data.T, standardized_data)
cov_matrix.shape# Output
(784,784)
接下来,我们将计算特征值和特征向量。协方差矩阵(或相关性)的特征向量和特征值描述了 PCA 的来源。特征向量(主成分)决定新属性空间的方向,特征值决定其大小。
# Calculate eigenvalues and eigenvectors
lambdas, vectors = eigh(cov_matrix, eigvals=(782, 783))
vectors.shape# Output
(784,2)vectors = vectors.T
vectors.shape
# (2, 784)
然后,我们将计算单位向量和它的新坐标。单位向量是大小为 1 的向量,我们试图找到使方差最大化的单位向量。
new_coordinates = np.matmul(vectors, standardized_data.T)
print(new_coordinates.shape)
new_coordinates = np.vstack((new_coordinates, y_train)).T# Output
(2, 42000)df_new = pd.DataFrame(new_coordinates, columns=["f1", "f2", "labels"])
df_new.head()
作者图片
让我们来看一下跨多个组件(784)保留的累积方差的可视化:
作者图片
4.创建 CNN 模型
在构建 CNN 模型之前,我们需要采取一些预处理步骤。这包括将训练集转换为一个数组,对输入数据进行整形以使其符合模型预期的形状,以及对图像标签进行编码。
X_train = np.array(X_train)
y_train = np.array(y_train)X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)
print(X_train.shape, y_train.shape)# Output
(42000, 28, 28, 1) (42000,)nclasses = y_train.max() - y_train.min() + 1
y_train = to_categorical(y_train, num_classes = nclasses)
print("Shape of ytrain after encoding: ", y_train.shape)# Output
Shape of ytrain after encoding: (42000, 10)
现在我们可以建立我们的 CNN 模型,我建立了一个 2D CNN 模型,有 3 层和 1 个完全连接的层。
input_shape = (28,28,1)
X_input = Input(input_shape)# layer 1
x = Conv2D(64,(3,3),strides=(1,1),name='layer_conv1',padding='same')(X_input)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling2D((2,2),name='maxPool1')(x)
# layer 2
x = Conv2D(32,(3,3),strides=(1,1),name='layer_conv2',padding='same')(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling2D((2,2),name='maxPool2')(x)
# layer 3
x = Conv2D(32,(3,3),strides=(1,1),name='conv3',padding='same')(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling2D((2,2), name='maxPool3')(x)
# fc
x = Flatten()(x)
x = Dense(64,activation ='relu',name='fc0')(x)
x = Dropout(0.25)(x)
x = Dense(32,activation ='relu',name='fc1')(x)
x = Dropout(0.25)(x)
x = Dense(10,activation ='softmax',name='fc2')(x)conv_model = Model(inputs=X_input, outputs=x, name='Predict')
conv_model.summary()
经过 40 个纪元,我们达到了 99.8%的准确率!
作者图片
摘要
从这篇文章中,我们使用神经网络对手写数字进行分类,并使用 PCA 对数据进行预处理。有关五氯苯甲醚及其用途的更多信息,请参见以下有用的文章。感谢您的阅读,所有代码都在我的 Github 上!:)
https://medium.com/towards-artificial-intelligence/principal-component-analysis-pca-with-python-examples-tutorial-67a917bae9aa https://medium.com/analytics-vidhya/a-deep-dive-into-principal-component-analysis-pca-4e8a6d5a6386
用神经网络对卫星图像中的船舶进行分类
原文:https://towardsdatascience.com/classifying-ships-in-satellite-imagery-with-neural-networks-944024879651?source=collection_archive---------22-----------------------
如何从零开始训练 CNN 的一课
内特·切尼在 Unsplash 上的照片
没有什么比谷歌地图更能说明卫星图像的无处不在。一项完全免费的服务为任何人提供互联网接入,获取整个地球的卫星图像。虽然谷歌地图是免费的,但也存在其他付费的替代品,它们可以更频繁地为商业用途拍摄地球表面的照片。世界各国政府也将其卫星用于许多国内用途。
由于卫星图像的可用性超过了人类手动浏览它们的能力,因此必须开发一种对它们进行分类的自动化方法。图像分类是计算机视觉中的一个基本问题,神经网络提供了一个有趣的解决方案。
对海湾中的船只进行分类
卫星图像数据集中的船只包含 4000 张船只和非船只的注释图像。取自星球 API 的 1000 张飞船图像统一为 80px x 80px,包含一艘处于不同方位的飞船,但总是在中心附近。
取自数据集的示例。CC-BY-SA 许可下的所有图像。
在 3000 幅非船只图像中,大约 1000 幅描绘了随机特征,如海洋或建筑物,大约 1000 幅描绘了船只的部分但不完整的图像,最后 1000 幅描绘了被其他机器学习模型错误标记的图像。
取自数据集的示例。CC-BY-SA 许可下的所有图像。
附带的 JSON 文件包括图像的 ID 和图像是否包含船只的标记,相应地用 1 或 0 表示。此外,它还包含每个图像的实际像素值。
排列为 19,200 个整数值,前三分之一包含红色通道中的所有像素值,接下来是绿色通道中的像素值,最后三分之一包含蓝色通道中的像素值。由于像素值是在数据集中明确说明的,实际的图像本身在技术上不需要下载,但它们是一个很好的参考。
为了对这些图像进行分类,将训练一个卷积神经网络(CNN)。作为一种人工神经网络,CNN 模仿大脑中的神经元,特别是那些用于视觉的神经元。网络中的每个神经元都开发了一个独特的特征图,可以识别图像中的特征。在浅层网络中,要素地图可能会识别垂直线或水平线。但是,随着图层被添加到网络中,要素地图可能会识别更复杂的结构,例如眼睛,或者在本例中是船只。
存在各种库来编写 CNN,但是本教程将使用 Keras 来介绍 TensorFlow。
Python 中的卷积神经网络
import tensorflow as tf
import pandas as pd
import numpy as np
在训练任何东西之前,使用基本导入。TensorFlow 是一个机器学习库,主要关注神经网络。Pandas 是一个电子表格类型的库,用于帮助解析数据。最后,NumPy 有助于快速有效地处理数字。
# Read the data
df = pd.read_json("shipsnet.json")
这一行只是导入 JSON 文件,并将其作为数据帧读取。
# Normalize and reshape the image data
df["normalized_data"] = df["data"].apply(lambda x: (np.array(x) / 255).reshape(80, 80, 3))
像素值存储在标题为“数据”的数据框的列中事实上,这些像素值还不能被 CNN 处理。相反,新数据被转换成一个 NumPy 数组,然后除以 255 来对值进行规范化。所有 19,200 个值现在应该是介于 0 和 1 之间的某个值。接下来,数据被整形为 80 x 80 x 3 的矩阵,这样它就被格式化为一张图片。
# Define X and Y
X = df["normalized_data"]
Y = df["labels"]# Split the data into training and testing sets. Use a 75/25 split
from sklearn.model_selection import train_test_split
(X_train, X_test, Y_train, Y_test) = train_test_split(X, Y, test_size=0.25, random_state=42)
定义了 X 和 Y 值。y 是标题为“标签”的列,包含 1 和 0 的数组,以定义图像是否包含船。X 是从像素值中提取的归一化图像数据。
定义了 X 和 Y 后,它们被分成 75/25 的训练集和测试集。因此,该模型将在 3000 幅图像上进行训练,并在 1000 幅其他图像上验证其结果。
# Transform the training and testing data into arrays
X_train = np.array([x for x in X_train])
X_test = np.array([x for x in X_test])
Y_train = np.array([y for y in Y_train])
Y_test = np.array([y for y in Y_test])
不幸的是,TensorFlow 不接受 Pandas 系列,因此训练和测试数据被转换为数组。
from tensorflow.keras import datasets, layers, models
from tensorflow.keras.layers import Activation# Starts the model with a sequential ANN
model = models.Sequential()
经过几次导入,真正的 CNN 已经准备好了。CNN 被初始化为一个序列模型%2C%20layers.),它确保每一层接收一个输入和一个输出。
# Adds the first convulsion layer and follows up with max pooling
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(80, 80, 3)))
model.add(layers.MaxPooling2D((2, 2)))
前两层被添加到模型中。第一层是卷积层,其使用“ ReLu ”激活函数,并期望 80×80×3 的输入张量,即训练图像的精确尺寸。32 表示图层输出的维度,而(3,3)表示卷积窗口的大小,在本例中为 3px x 3px。
添加的下一层用于最大池化,其池大小为 2 x 2。
# Add additional hidden layers
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
与前面的代码非常相似,这两行代码是网络的附加隐藏层。虽然输出大小发生了变化,但这些层遵循与前两层相同的基本模式。
# Flattens the input into a 1D tensor
model.add(layers.Flatten())# Makes the input more readable for classification
model.add(layers.Dense(64, activation='relu'))# Classifies - ensure the input in the number of classes, indexed
# at 0
model.add(layers.Dense(1))# Final activation function
model.add(Activation('sigmoid'))
第一行简单地将张量展平为一维,这将使处理更容易。下一行,第一个密集层,格式化结果输入。
下一个密集层与分类有关。因此,传递的唯一参数是类的数量,索引为 0。因为在这个例子中有两个类,ship 或者 not-ship,所以传递 1。
最后,添加一个激活层,告知是否激活神经元。
model.summary()
在继续下一步之前,花点时间用总结的方法回顾一下模型。输出应该如下所示:
模型总结。图由作者制作。
请注意每一行是如何描述 CNN 内置的一个层的,以及它的输出形状和参数数量。
# Compile the model
# Use binary_crossentropy because there are only 2 classes present
model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
这一行只是编译模型。如果添加图层时存在输入/输出维度问题,程序会在这一步通知您。
损失函数采用二元交叉熵,因为该模型仅使用两个类别。使用更多的类将需要一些不同的东西。损失函数的完整列表可在这里查看。优化器被当作 RMS prop 算法,但是其他的也是可用的这里。度量参数只是查看需要优化的内容,在本例中就是准确性。
# Train the model
gen_model = model.fit(X_train, Y_train, epochs=10, validation_data=(X_test, Y_test))
终于到了拟合模型的时候了。传递训练和测试数据非常简单。epochs 参数本质上是告诉模型要经历多少次迭代。
设定时代的回报边际递减。数字越大,通常精度越高,但是精度的每一次提高都会降低,直到接近数据集能够产生的最大精度。此外,更多的纪元将需要更长的时间来运行。对于这个数据集,10 将返回好的结果。
当模型训练时,每个历元的输出如下所示:
为模型定型的输出。作者制作的图
在返回样本数并给出训练历元的时间后,该行还将返回其自己的训练图像集的模型的损失和准确性,以及其验证集的损失和准确性。
在这种情况下,在第 10 个时期,该模型在其自己的训练图像上实现了 99.27%的准确性,在该模型从未见过的图像上实现了 98.5%的准确性。
估价
在过度庆祝之前,应该对结果进行更深入的分析。
# Evaluate the model
from sklearn.metrics import classification_report, confusion_matrix
predictions = model.predict(X_test)
print(classification_report(Y_test, predictions.round()))
print(confusion_matrix(Y_test, predictions.round()))
这些行导入一些函数来帮助评估模型的准确性,将模型应用到测试数据,并打印分类报告和混淆矩阵。
分类报告:
模型的分类报告。图由作者制作。
测试数据由 1000 幅图像组成,其中 733 幅是非舰船,267 幅是舰船。非船舶的精度为 99%,略高于船舶的精度 97%。本质上,对于所有被模型归类为船只的图像,97%都是真实的船只。该模型能够分别回忆起 99%的非船只图像和 98%的非船只图像。
总的来说,对于一个简单的 CNN 来说,这些都是很好的结果。
现在,看看混乱矩阵:
模型的混淆矩阵。图由作者制作。
在 733 幅非船只图像中,725 幅被正确识别,8 幅被误标为船只。这些都是误报。
在 267 张舰船图像中,262 张被正确识别,5 张被误标为非舰船。这些是假阴性。
保存和加载模型
如果每次需要的时候都需要训练,CNN 可能不会很有用。在这种情况下,训练时间只需要几分钟,但在更深的具有更多纪元的网络上,训练可能需要几个小时甚至几天。因此,有一个简单的方法可以调用来保存整个模型。
# Save the model for later use
model.save("ShipCNN.h5")
save 方法只接受路径名,将其保存为 H5 文件。
# Load a model
new_model = tf.keras.models.load_model("model.h5")
加载预先保存的文件也相当简单。调用 summary 方法来检查模型的架构是否符合预期也是一个好主意。
结论
使用卫星图像训练 CNN 提供了完美的数据集。所有的图像都是同样的大小,在基本相同的角度和距离拍摄,每艘船都保留了俯视图。虽然改变这些参数中的任何一个都会使分类问题变得更加困难,但船只图像展示了神经网络应用于计算机视觉问题的能力。
使用的 CNN 相对简单,但仍然只需要几分钟的训练就可以返回很高的准确度。接近人类水平的表现,1000 张图像中只有 13 张被错误标记。虽然应用程序是理想化的,但潜力是显而易见的。
借助模糊逻辑对简单配色服装进行分类
原文:https://towardsdatascience.com/classifying-simple-color-matching-outfits-with-the-help-of-fuzzy-logic-fc9733ce8346?source=collection_archive---------24-----------------------
实践教程
跟随我们创建一个智能助手,它将帮助我们决定一套服装是否有匹配的颜色
概观
在下面的文章中,我们将介绍一个概念验证项目的完整开发过程,它将帮助我们对由衬衫、下装和鞋子组成的简单配色进行分类。本文将分为以下几个部分:
- 了解问题(问题的起源)
- 快速回顾我们的主要工具‘模糊逻辑’
- HSV 颜色表示概述
- 建立模糊逻辑模型
- 添加装备规则过滤匹配的装备
- 最终结果和结论
了解问题
在 Covid 来到我们国家之前,大学里的一天,我和一些同事正在等老师开始讲课,突然出现了服装的话题。在谈话的某个时候,我们问我们的色盲朋友,他是如何选择每天穿的衣服的。他继续解释说,他过去常常依靠家人告诉他衣服是否相配,自从他搬出去开始独立生活后,他再也不能向他们求助了。他目前的方法要求他通过识别服装的品牌或图案来猜测或记住好的服装,这听起来非常适得其反。
我无法想象看不到完整色谱的概念及其对我日常生活的影响,这让我开始思考颜色和时尚之间的关系。那天晚些时候,我决定联系 Valeria,她是我的朋友,目前正在学习时尚和设计,希望获得一些知识,并找到解决我朋友问题的方法。我问她在选择服装配色方案时遵循的流程,在一次富有成效的长谈后,我发现自己在想,“难怪没有一个通用的解决方案,它比我想象的更加复杂和主观!”。我试图缩小指导方针的范围,这些是经常出现的规则:
- 中性色(白色、黑色、灰色、藏青色等。)可以适合任何装扮。
- 有暖色(红色)和冷色(蓝色)两种颜色,可以用不同的组合来搭配一套服装。
- 每种颜色都有不同的色调,搭配衣服时也要考虑到这一点。
当时我正在上机器学习的入门课。我天真地认为,很可能有一种简单的方法来训练一个模型来对匹配的衣服进行分类,并且这个模型会从所有输入的数据中推断出这些规则。最初的想法相对简单明了:
- -收集匹配和不匹配服装的数据并进行预处理
-用数据训练神经网络
-检查结果并进行调整
-使用模型将三种颜色的任意组合分类为匹配/不匹配
这个计划听起来可行,但是当我开始设计一个更具体的解决方案时,我发现有一些主要的细节我没有考虑进去。
我遇到的第一个障碍与颜色有关,这个话题我很快就会谈到。第二个障碍与训练模型和收集使其工作所需的大量数据有关。有很多关于时尚的数据库,但没有一个是以颜色为中心的。我想过自己收集数据,但这也带来了一些耗时的问题。
这一切都开始崩溃,看起来像一个太复杂而无法完成的项目,所以随着时间的推移,我失去了兴趣,并将其添加到“有趣但目前不可行”的项目列表中。直到我在计算机智能课程上听了一次特别的讲座,我才重新获得了继续这个项目的动力,这次脑子里有了一个新概念:模糊逻辑。
模糊逻辑概述
为了使这篇文章简短,我将用简单的术语总结我对模糊逻辑的理解,足以让你完成这个项目的其余部分。我绝不是这方面的专家,因为我自己刚刚才知道,所以如果你想要更深入地解释模糊逻辑,我建议你看看https://www.guru99.com/what-is-fuzzy-logic.html或电脑爱好者关于这个话题的视频。
我们首先需要回到“经典逻辑”。经典逻辑依赖于离散的、定义明确的值,如“真”或“假”。这些值之间没有混淆,它们可以完整地描述一种状态或结果,例如,如果加热器是“开”或“关”,则没有类似“稍微开”的中间值。另一方面,模糊逻辑可以使用没有严格定义的“中间”值。让我们来看一个最常见的例子:温度。
假设你想创建一个逻辑系统,当房间很热的时候关掉一会儿加热器,问题是,你如何定义“热”?热、暖、冷没有明确的界限;它似乎以连续的方式转变,并且在某一点上主观上变暖或变冷。模糊逻辑允许您定义没有明确界限的变量集,如['热'、'暖'、'冷'],并使用它们和一组规则来确定不同的结果。一个规则的例子可以是:如果房间“热”,关掉加热器“几分钟”。请记住,您需要指定这些模糊集及其隶属函数,这有助于模型计算某个值属于某个子集(模糊值)的程度。让我们看一个例子:
来源:https://commons . wikimedia . org/wiki/File:Fuzzy _ logic _ temperature _ en . SVG
这是“温度”隶属函数的图形表示。它解释了与温度变量相关的模糊集['冷','暖','冷']。给定一个明确的值,可以认为是变量的可测量值(在本例中是以摄氏度或华氏度为单位的温度),该函数将确定每个模糊元素描述该值的程度。在这个例子中,我们看到枢轴被放置成与“冷”和“暖”相交。我们可以推断,这个地方的温度并不完全冷,但也没有热到可以认为完全暖和。如果将其描述为 cold 更准确,它将给出与 cold 最匹配的模糊值。
在本例中,我们看到的是梯形隶属函数,但您可以使用不同的函数来映射每个变量,包括:三角形、高斯形、钟形等。
一旦我们模糊了温度的明确值,我们就可以使用一组以直观方式描述的规则来指定预期输出,例如:
- 如果温度“很高”,关闭加热器“几分钟”
- 如果温度“温暖”,关闭加热器“几分钟”
这些规则将被推理机用来计算输出。最后,我们可以通过将结果输出映射到一个描述分钟数['一些','几个',…]的隶属函数来消除其模糊性。这个反模糊值将给出数字结果,表明我们应该关闭加热器的精确分钟数。
理解数字颜色表示
鉴于我们的助手将生活在数字空间,我们所知道的颜色将需要用计算机能够处理的方式来表示。颜色有几种数字表示,最著名的是 RGB(红绿蓝)。
自然,我们可以开始考虑使用 RGB 作为模糊逻辑模型的清晰值,但是我们对 RGB 了解得越多,我们对使用它就越不乐观。RGB 允许超过 1600 万种不同的颜色,在一种颜色和另一种颜色之间没有直观的过渡/模式,除了一个人可能有更多的“红色”和更少的“蓝色”的想法。
这可能感觉像是一个巨大的挫折,但是如果你曾经使用过像 Photoshop 这样的照片编辑工具,并试图选择一种新的颜色,你可能会记得看到许多不同的选项来指定它。在这些选项中,我们可以看到 RGB、十六进制、CYM 和 HSV。如果我们对所有这些选项进行一些调查,并阅读它们之间的差异,我们可以观察到 HSV 具有一些值得探索的有用特征。
HSV 代表色调、饱和度和价值。每个组件在表示中都有特定的功能和一系列可能的值:
- 色调:代表感知的颜色,不考虑阴影。值从[0,360]
- 饱和度:表示颜色的丰富程度。饱和度越低,颜色就越淡,越灰。值从[0,100]
- 值:表示颜色的亮度,或发出的光量。值越低,颜色越深。值从[0,100]
这是 HSV 的视觉表示,我们可以看到每个维度如何以其独特的方式影响颜色。来源:https://es . m . Wikipedia . org/wiki/Archivo:HSV _ color _ solid _ cylinder . png
HSV 表示法的最大优点是:
- 颜色与色调/强度分离
- 色调成分对光线变化不太敏感
这里有一个例子,我们在不同的光线下有相同的颜色:
RGB (50,132,219)
HSV ( 211 ,77,86)
RGB (30,80,133)
HSV ( 211 ,77,52)
正如您所看到的,RGB 表示在每个维度上为两个元素提供了不同的值,而 HSV 保留了色调分量,只对值分量进行了调整。
这很有用,因为我们可以分离色调来确定一种颜色是“冷”还是“暖”温度,而无需考虑它的阴影/色调,然后使用饱和度和值来描述色调。
我们还可以通过同时检查饱和度和值来确定颜色是否为“中性”。低饱和度会产生接近灰色的褪色颜色。低值会产生暗(黑)色,高值会产生亮(白)色。所有这些都可以归类为“中性”颜色,可以在搭配服装时用作通配符。
改进的项目计划
现在我们对数据和问题有了更好的理解,我们可以制定一个新的计划,分两步来解决这个项目:
1.创建一个模糊逻辑模型,给定一种 HSV 格式的颜色,可以确定该颜色是“中性色”、“暖色”还是“冷色”,并指示其色调是“暗”还是“亮”。例如,给定 HSV 中的一种颜色,按照“暗暖色”或“亮冷色”2 返回一个描述。使用模型获得每件衣服的描述,然后使用时尚规则来确定服装是否匹配。《出埃及记》冬季服装应该包含所有“深色”,最好是“冷”色调。
模糊逻辑模型
第一步围绕着创建模糊逻辑模型,这将为我们提供颜色的描述。目标是以 HSV 格式输入一种颜色,并得到该颜色的描述性文本。
如果我们看一下在与 Valeria 交谈期间收集的笔记,我们会看到这些描述颜色的单词不断出现:“中性”、“暖色”、“冷色”、“暗色”、“亮色”,因此找到一种将 HSV 的颜色转换为类似颜色的方法可能会很有用。这些词主要用于表示一套服装的良好搭配。两种“暗冷”色和一种“亮冷”色,或者两种“中性色”和一种“亮暖色”。
HSV 将色调与其他成分分开,这样即使它们具有不同的色调,您也可以获得相同的色调。这将有助于我们对颜色的温度进行分类(“暖”或“冷”)。
(左)修改图片来自https://commons . wikimedia . org/wiki/File:RGB _ color _ wheel _ 360 . SVG——(右)图片作者
这是“温度”变量的隶属函数,由模糊集[“温暖”、“凉爽”]和范围从[0,360]的清晰值组成。正如在色轮中看到的,给定其圆形表示,色调在冷色、暖色和回到冷色之间过渡。有两种过渡色(绿色和棕色),其中“暖”和“冷”的概念变得非常主观。
作者提供的图片
这些隶属函数变得更加简单。
第一张图描述了颜色“值”的隶属函数,它可以帮助我们识别颜色从“黑”到“非常亮”的所有亮度。
第二个标识“饱和度”函数的成员,该函数可以基于饱和度值描述颜色是否完全“灰色”、“褪色”或不同程度的“饱和”。为了简单起见,这些都是均匀分割的高斯函数,但并不需要这样。
这两种成分的混合可以帮助我们识别不同的色调(“暗”或“亮”)和“中性”颜色,因为低饱和度导致灰色,低或高值分别导致黑色或白色。
我们需要添加规则来指导音调变量的计算。我们可以从一些简单的规则开始,例如:
- 1。饱和度被标识为“灰色”或“非常褪色”的颜色将被视为中性色
2。具有“黑色”值的颜色将被视为中性
3。“饱和”和“非常暗”的颜色将被视为深色
4。“褪色”和“深色”的颜色将被视为深色
5。“非常饱和”和“暗”的颜色将被视为暗
6。“褪色”和“非常亮”的颜色将被视为明亮的颜色
7。“饱和”和“明亮”的颜色将被视为明亮
8。“非常饱和”和“非常亮”的颜色将被视为明亮
如果我们要映射所有不同的值与饱和度的组合,我们将得到下面演示的表格。红色单元格表示在规则集(ej)中特别指定的结果值。“饱和”和“非常暗”导致“暗”色调)。白细胞不是显式编程的,但模型将根据前面的规则推断它们。如果这些结果不能正常工作,我们总是可以根据自己的喜好改变规则集。
有了这些规则,我们只需要为音调变量创建隶属函数,这样我们就可以将推理机的结果映射到其对应的类别。
作者图片
这是音调变量的隶属函数的图形表示。我们可以使用各种函数来帮助我们将推理机的结果映射到相应的模糊值。这些功能背后的直觉源于一个想法,即色调可以在暗色调和冷色调之间转换,但我们仍然必须考虑中性色。中性色可以被认为是那些足够暗或褪色到没有可感知的色调的颜色,这就是为什么我们看到中性色的映射接近深色。通常,我们会对推理机的结果进行去模糊化,以获得一个清晰的值,但对于这个特定的项目,我们感兴趣的是描述性的模糊值,如“明亮”。
下图显示了数据在清晰值和模糊值之间进行修改和转换的各个阶段,从 HSV 格式的数字颜色表示开始,并产生颜色的描述性文本。
作者图片
完成这些操作后,下一步将是将 HSV 值输入到它们各自的模糊化器中,并组合结果以获得由(TONE,TEMP)组成的描述。以下是一些测试结果:
作者图片
不错!这个过程似乎正在起作用。在某些情况下,我们可以用不同的方式来描述颜色,但这也可能是主观的。幸运的是,由于这是一个由规则引导的模糊逻辑模型,我们可以立即根据自己的喜好调整规则。现在我们已经有了描述,我们可以继续拼图的最后一块了。
*中性色包含了一个温度描述,因为在过程中还在单独计算色相,但是可以忽略。
重要的是要重申,我们可以增加模型的复杂性,使其更加准确,例如增加精确的色调集,或添加特殊的硬编码“中性”情况,如可能难以计算的棕色或米色。我们还可以添加一些偏差,这样冷色就有“暗”色调偏差,暖色就有“亮”色调偏差。为了完成这篇文章,我们将继续我们目前的结果。
添加匹配装备规则
我们可以遵循不同的服装配色方案,每一种都有自己的一套规则。我们能找到的最常见的是下面的*(在大多数这些‘中性’颜色中,它们可以用作通配符,因为它们基本上在任何地方都匹配)*:
- -中性色:只由中性色组成
-基本(safe-bet):任何颜色之间没有高对比度,不超过一个明亮的暖色
-对比度:两个深色和一个亮色,可以混合暖色和冷色。
-类比:不同色调下相同温度的颜色
-冬季:多为暗冷色
-夏季:多为暖色和一些对比鲜明的颜色
我们可以为备选服装配色方案创建不同的规则集,并将服装颜色描述传递给一个函数,该函数将验证规则并决定服装是否匹配特定的配色方案。
作者图片
有了这些规则,我们可以寻找一个特定的服装搭配,或者通过所有的方案运行颜色,并检查至少一个匹配的结果。
结果
为了尝试和测试这种算法,我们可以用谷歌图片快速搜索匹配和不匹配的服装。找到搭配的例子很容易,因为有很多关于搭配衣服的指南。我们可能很难找到不匹配的服装,因为这些服装并不公开。
来源:https://burst.shopify.com/photos/casual-urban-menswear?c =型号
如果所有颜色都是中性色,则按预期工作。“类比”分类在技术上是正确的,但更准确的描述应该是“单色”,因为颜色属于同一色调,但具有不同的色调。
来源:https://www . pexels . com/photo/woman-in-pink-turtle-weather-1649896/
按预期工作。
来源:https://stylishlyme.com/style/fur-coat-outfit/
由于这套服装主要由深色和冷色组成,因此效果与预期一致。
来源:https://www.freepik.com/photos/man—由 astock_productions 创作的人物照片
按预期工作。我们可以从这幅图中观察到一个潜在的问题。我们知道鞋子是白色的,但是照片的背景给了它们一些蓝色。分类仍然是准确的,但应该进行更多的测试来查看任何类似的问题。
来源:https://I . pinimg . com/736 x/0b/1c/c8/0 B1 cc 861706 edabe 86 c 089 da 600122 b 3 . jpg
按预期工作。这件衣服是在搜索“不匹配的衣服”时发现的。
来源:https://www.freepik.com/photos/people—由 lookstudio 创作的人物照片
按预期工作。这看起来像是一套色彩丰富但有风险的服装,所以它没有被归类为“基本款”。
最后的想法
总的来说,我们可以发现这些结果对于概念验证项目来说已经足够好了,但是可以进一步调整以提高准确性。有一些棘手的颜色,如紫色,棕色和绿色,应该进行更彻底的调查,并可能作为特例添加。
如果这个项目作为针对色盲的产品投入生产,它很可能只会考虑更安全的服装,如基本、中性、冬季风格,并避免一些高对比度的危险服装,如 Analogous 和 Summer。话又说回来,根据具体情况,一些危险的服装也可能成为时尚。
值得一提的是,搭配一套简单的衣服并不难,当衣服中加入更多的物品时,比如夹克、皮带、袜子等,搭配不当的可能性就会增加..此外,在选择服装时,还有一些其他细节需要考虑:
- -质地/图案也可能对服装有很大影响
-一件衣服的正式/优雅也应考虑在内。polo 衫(正式)与运动裤(非正式)
-肤色可能会影响整套服装的整体外观
至于模糊逻辑模型,我们总是可以增加它的复杂性,以获得更精确的描述,以及深入挖掘不同的隶属函数,可以与模糊变量一起使用,以获得更好的结果。
理想的最终产品将实现这一解决方案以及计算机视觉,以识别服装各自的颜色。此外,这可以开发为任何即将推出的 AR 眼镜的 AR 应用程序,以模拟实时服装助手,可以帮助色盲或任何想要时尚建议的人。
欢迎评论中的任何反馈或建设性的批评
github Repo:https://github . com/FCARRILLOM/ClassifyingColorMatchingOutfits
特别感谢:
瓦莱里娅,分享她的时尚知识。(在 Instagram @wtf.isfashion 上找到她的时尚简介)
朱安·迭戈,分享他色盲的经历。
蛋白质基准数据集分类
原文:https://towardsdatascience.com/classifying-the-proteins-benchmark-dataset-ec18e728a17a?source=collection_archive---------20-----------------------
实现图形卷积网络的两种方法
这是图论和图卷积网络系列的第四部分。
摄影在 Unsplash 上拍摄的照片
如果你一直在阅读这整个系列,那么你已经伴随我走过了这整个旅程——通过讨论什么是图论以及为什么它很重要,什么是图卷积网络甚至是和它们如何工作,现在我们在这里,到了有趣的部分——构建我们自己的 GCN。
如果你是这个系列的新手,那也完全没问题!不管是哪种情况,让我们开始编码吧!
在本教程中,我们将通过 GCNs 的两个实现来对蛋白质基准数据集进行分类。如果你想找到这些数据的归属或论文,或者自己下载看看,可以在“生物信息学”标题下 这里 *找到。*你也可以在这里看一看整个笔记本。代码的属性可以在这个项目的库中找到。
第一部分:带频谱的 GCNs
什么是光谱?根据他们的主页:
Spektral 是一个用于图形深度学习的 Python 库,基于 Keras API 和 TensorFlow 2。这个项目的主要目标是为创建图形神经网络(GNNs)提供一个简单而灵活的框架。
开始使用 Spektral 非常容易,因为对项目进行了预先考虑——如果你已经使用 Keras 或 Tensorflow 进行过建模,我想你会发现 Spektral 非常直观。
此外,Spektral 有许多内置的基准图数据集,这意味着您不必担心需要确保您的数据是使用 GNNs 建模的正确格式,并且可以很容易地开始实验。
无论您是在 Colab 中学习本教程,还是仅仅学习一本普通的笔记本,我们的第一步都是一样的。Spektral 不是 Colab 的内置库之一,所以我们需要安装它:
PROTEINS 是来自 TU Dortmund 的图形内核的基准数据集之一。您可以从TUDataset
类中访问这个数据集类,我们通过首先导入然后实例化它的一个对象来访问它,我们要访问的数据集的名称被传入:
当我们加载数据集时,我们可以看到它在n_graphs
属性中包含了多少个图。在这里,我们可以看到这个数据集有 1113 个图形。在这个数据集中,这些被分成两个不同的类。
Spektral 的GCNConv
层基于 Thomas N. Kipf 和 Max Welling 的论文:“使用图卷积网络的半监督分类”。这是完美的,因为这是我们一直在参考的论文,如果你一直在关注这个系列的话。如果您还没有,我建议您看看这篇论文以及我写的关于这些网络如何工作的文章,以便更好地了解 Spektral 在幕后为我们做了什么!
因为这是我们想要使用的层,我们将不得不执行一些预处理。Spektral 用他们的GCNFilter
类让这变得非常简单,该类只用两行代码就为我们执行了预处理步骤(在论文中有概述)。
首先,从spektral.transforms
导入GCNFilter
,然后在我们的数据集上调用.apply()
,传入GCNFilter
的实例:
在这个阶段,我们希望确保执行我们的训练/测试分割。在这个简单的例子中,我通过混排数据,然后取切片(分别约 80/20%)来实现,但是一旦您熟悉了这个实现,欢迎您进一步优化这个步骤!
现在,让我们导入我们的模型需要的层:
等一下——这些导入语句不是来自 Keras 吗?别担心——这不是偶然的。因为 Spektral 是建立在 Keras 之上的,所以我们可以很容易地使用 Keras functional API 来构建我们的模型,在我们处理图形结构数据时添加 Spektral 特定的层。
我们导入Dense
和Dropout
层— Dense
是典型的执行前向传播的密集神经网络层,而Dropout
以我们设定的速率将输入单元随机设置为 0。这里的直觉是,这一步可以帮助避免过度拟合*。
然后,我们导入我们之前介绍的GCNConv
层和GlobalSumPool
层。Spektral 为我们简明地定义了这一层:
全局汇总层。通过计算图的节点特征的总和来汇集图。
这就是全部了!让我们建立我们的模型:
这里,我们使用模型子类来定义我们的模型。当我们实例化模型进行训练时,我们将向模型传递n_hidden
:隐藏层数和n_labels
:标签(目标类)数。
然后,在__init__
中,我们将所有的层定义为属性。在call
中,我们定义了这个方法,通过按顺序调用我们的输入层来创建和返回我们想要的输出。
让我们为训练实例化我们的模型!
在这里,我们将初始化 32 个隐藏层和数据标签的数量。当我们读入时,Spektral 方便地在我们的TUDataset
上给了我们一个n_labels
属性。这样做的好处是,如果您想探索其他数据,您可以对任何其他光谱数据集使用相同的代码,无需修改!
上面,我们在我们的模型上调用.compile()
。如果你熟悉 Keras,你就会熟悉这个方法。我们将传递我们的优化器,adam
,并定义我们的损失函数,categorical crossentropy
。
现在我们遇到了一个障碍。你们中熟悉 Tensorflow 和 Keras 的人可能会尝试给model.fit()
打电话,然后就到此为止。然而,即使 Spektral 在 Keras 上无缝地构建 GNNs,我们也不能完全以同样的方式处理我们的数据。
因为我们使用的是图形结构的数据,所以需要创建批处理来填充我们的 Keras 模型。对于这项任务,Spektral 仍然通过提供装载机让我们的生活变得更加轻松。
现在我们已经处理了批处理,我们可以调用model.fit()
。我们不需要指定批处理,只需传入我们的加载器,因为它作为一个生成器工作。我们需要提供我们的steps_per_epoch
参数用于培训。
对于这个简单的例子,我们只选择了 10 个时期。为了验证,让我们为测试数据创建一个加载器:
我们将通过调用.load()
把它提供给我们的模型。
用 Spektral 构建 gcn 到此结束!我强烈建议您试着优化这个例子,或者深入到可以用 Spektral 构建的其他 gnn 中去。
第二部分:Pytorch 几何的 GCNs
尽管 Spektral 为我们提供了一个优秀的图形神经网络层、加载器、数据集等库,但有时我们可能需要更精细的控制,或者我们可能需要另一个工具来完成这项工作。
Pytorch-Geometric 还提供了基于 Kipf & Welling paper 以及基准数据集的 GCN 图层。PyTorch 的实现看起来略有不同,但仍然易于使用和理解。
我们开始吧!我们将从同一个笔记本开始,从标题“Pytorch 几何 GCN”的正下方开始。提供了此代码的归属。
像往常一样,我们的第一步是安装我们需要的包:
现在,让我们拿起数据集:
看看我们的数据:
这里,我们演示了 Pytorch-Geometric 在我们的 TUDataset 对象上提供的各种属性。这为我们提供了大量信息,我们可以使用这些信息在以后微调我们的方法,并深入了解我们的数据。
现在我们知道了数据的样子,我们将执行我们的训练/测试分割。对于这个例子,我也使用了一个简单的洗牌和切片方法,但是和往常一样,我鼓励你研究一下这个步骤的优化!
Pytorch 还为我们提供用于配料的DataLoaders
:
现在我们已经完成了这一步,我们可以构建我们的模型了。我们将使用类似的方法,但是记住现在我们使用 Pytorch 而不是 Keras。
我们将导入我们的功能层(类似于 Keras 的Dense
层)、我们的GCNConv
层和一个global_mean_pool
层。这执行了与 Spektral 的GlobalSumPool
类似的汇集操作,但是取平均值而不是相邻节点的和。
在构建我们的模型时,我们继承了 Pytorch 的GCN
模型,然后初始化三个卷积层。我们将在实例化模型时传递隐藏通道的数量。
然后,我们构建一个forward()
方法,它类似于我们之前在特定 GCN 中构建的call()
方法。这告诉我们的模型如何通过卷积层传播我们的输入。使用 Pytorch,我们显式地定义了我们的激活函数。在这个例子中,我们使用relu
。
在我们的最终分类之前,我们执行我们的池,然后设置我们的 dropout 并通过最终的线性层传递我们的输入。
虽然有很多机会来定制和微调我们的 Spektral 模型,但我喜欢我们用 Pytorch 明确定义我们的架构的方式。当谈到“哪种方法更好”时,像大多数事情一样,这取决于你的团队需要优先考虑什么(例如,解释能力比快速证明概念的效率更重要)。
让我们来看看由此产生的架构:
接下来,我们需要:
- 设置我们的优化器——我们也将在这个实现中使用
adam
- 定义我们的损失函数——同样,我们将保持
categorical crossentropy
- 定义训练和测试函数,然后在设定的时间段内调用它们。
我们在这个例子中使用了更多的纪元,因此,我们获得了更好的指标。除了我用来帮助构建模型和学习各个库的代码示例之外,没有什么内在的原因。此外,鉴于 Pytorch-Geometric 实现是我的最终实现,我比早期的实验更关注结果。一如既往地,我鼓励您尝试和优化代码,使它变得更好!
查看最近 20 个训练时期,我们看到我们实现了大约 71.34%的训练准确度和大约 62.67%的测试准确度。评估 186 年前后的测试数据的准确性,一个潜在的优化将是早期停止回调,这确保我们一旦达到收敛就停止训练,以避免过度拟合模型。
我们还可以进行更多的优化,但这是一篇很长的文章,所以我们就此打住,我将让您自己进行试验和优化!
注意事项:
- —要了解更多关于辍学或为什么辍学的信息,请查看这个来源。
将 Dash 和 Plotly 与 Docker 结合使用,为 AI/ML 应用提供简洁的架构
原文:https://towardsdatascience.com/clean-architecture-for-ai-ml-applications-using-dash-and-plotly-with-docker-42a3eeba6233?source=collection_archive---------2-----------------------
使用 Dash 和 Plotly 创建企业级仪表板,在 Dash 中了解最佳实践、项目结构、架构模式
由露丝·齐默曼在 Unsplash 上拍摄的照片
几乎每个数据科学项目都需要某种形式的可视化,如可视化输入数据、使用直方图或散点图的探索性数据分析、使用盒须图查找异常值或绘制统计数据、使用网络图可视化节点之间的关系、使用相关矩阵检查变量之间的关系、帮助理解高维数据集内的关系的可视化技术、可视化模型的性能或
此外,数据可视化可能成为任何演示文稿的重要补充,也是理解数据的最快途径。
正如你所看到的,数据可视化是任何数据科学项目的关键部分,但是创建一个仪表板并不是一项简单的任务。有很多库可以用来生成漂亮的图,但是在我看来,如果你正在使用 python,Dash 是最好的选择。
为什么 Dash
正如您在官方文档中看到的,Dash 是一个用于构建 web 分析应用程序的高效 Python 框架。Dash 是基于最流行的框架和库编写的**,比如 Flask、React 和 Plotly** ,它是构建数据可视化应用的理想选择。它很容易学习,因为 Dash 抽象了构建基于 web 的交互式应用程序所需的所有技术和协议。使用 Dash 你可以完全在 Python 中工作,后端,前端也可以用 Python 编写。
Dash 的优势
- 需要很少的样板文件就可以开始
- Dash 应用程序完全由 Python,甚至 HTML 和 JS 生成
- 它是“反应式”的,这意味着很容易推断出复杂的 ui 有多输入、多输出以及依赖于其他输入的输入
- Dash 应用程序本质上是多用户应用程序:多个用户可以查看应用程序并进行独立的会话
- Dash 应用程序可以有多个输入、多个输出以及依赖于其他输入的输入
- 因为 Dash 应用程序使用 Flask 作为后端,所以我们可以使用 Gunicorn 来运行它们,所以很容易通过增加工作进程的数量来扩展这些应用程序,以服务数百或数千个用户
- 使用 React.js 渲染组件,并包含一个插件系统,用于使用 React 创建您自己的 Dash 组件
- 因为它使用 Flask 作为服务器,所以您可以像部署 Flask 应用程序一样部署 Dash 应用程序
- 开源库,在许可的 MIT 许可下发布
- Dash 有很好的文档记录,并且在 Stack Overflow 和 Github 上有一个很好的响应社区
Dash 的缺点
- 反应图中没有中间值,对于中间数据,您必须添加一个隐藏的 div(正如 Plotly 所建议的)
- 您必须为每个输出编写单独的函数,这迫使您重新构建代码(有时这也是一种优势)
- 两个 Python 回调不可能更新同一个元素
- 不能有没有输入或没有输出的回调
每个框架或库也有缺点,但是在 Dash 的情况下,优点多于缺点,并且可以使用一些变通方法来解决缺点。
总的来说,如果你想为你的数据科学模型或算法创建一个企业级交互式仪表板,带有小样本的**,完全用 Python 编写(这样你就可以在后端和前端之间重用代码)Dash 是最好的选择。**
Dash 的干净建筑
注: 我们将在虚拟环境中工作。创建和激活虚拟环境参见 Python 虚拟环境 。
获得清晰架构的第一步是定义项目的文件结构**。任何严肃的 web 应用程序都有多个组件和多个页面。为了便于添加功能而不影响其他布局,并引入清晰的关注点分离,我推荐以下文件结构:**
作者图片
资产文件夹
如果您想要在项目中自动包含图像、样式表或 Javascript 文件,Dash 要求您将它们添加到 Assets 文件夹中。Dash 将自动处理该文件夹中包含的所有文件。参见仪表板外部资源。
组件文件夹
该文件夹将包含可重用的组件,如在多个页面上使用的按钮、可视化数据的表格、在多个页面上使用的标题等。
例如,它可以包含基于数据帧构建表的函数:
布局文件夹
web 应用程序将有一个始终可见的通用布局。通常,这是由侧边栏和/或菜单和内容页面组成的。在我们的例子中,我们有一个可折叠的侧边栏和内容页面。
作者图片
正如我们在上面的图片中看到的,作为一个常见的布局,我们有一个侧边栏(用绿色突出显示),它总是可以看到的(除非它是折叠的),以及内容,它会根据侧边栏中的页面选择而变化。
对于侧栏,我们有两个文件,一个用于定义视图(sidebar.py),另一个用于定义行为,以声明回调(sidebar_callbacks.py)。
内容是一个简单的 div,最终的通用布局由侧边栏、内容 Div 组成,它还包括破折号的位置组件,代表 web 浏览器中的位置或地址栏。通过它的 href 、路径名、搜索、和哈希属性,你可以访问加载应用的 URL 的不同部分,这对路由和导航非常有帮助。
页面文件夹
一个企业级的 web 应用程序通常由多个页面组成,我们将为每个页面创建一个新的文件夹。每个页面将由三个不同的文件组成,这样我们就可以将 MVC 架构模式也应用于 Dash。我们将在本教程的后面描述如何在 Dash 中使用 MVC。
实用程序文件夹
该文件夹将包含与特定页面或组件无关但可通用的通用和可重用功能。例如,我们可以在这里添加货币转换、十进制数字格式化或其他数学函数。
它还将包含全局使用的常量或指向外部资产的链接(指向样式表、图标、字体等的链接)。)
环境文件夹
因为不同的环境(开发、测试、试运行、生产前、生产或其他)将具有不同的配置文件和不同的环境变量,所以我们需要一种在这些配置文件之间进行选择的方法。该文件夹将包含不同的配置文件以及根据环境在这些文件之间进行选择的机制。
在我们的教程中,我们将有两个环境,开发和生产。
对于这两个环境,我们会有两个不同。环境文件。以便从中读取键值对。env 文件并将它们添加到环境变量中,我们使用【dotenv】库。
对于开发,我们将使用 .env.development 配置文件。
对于生产,我们将使用。env** 文件。**
主机必须是 0.0.0.0,因为在本教程的后面,我们将为我们的示例应用程序创建一个 Docker 容器,Docker 要求主机=0.0.0.0。
根据环境读取不同配置的逻辑可以在 settings.py 文件中找到。
在第 5 行,我们根据环境文件环境变量的值设置了正确配置文件的路径。对于开发,这将具有值 ".env.development" ,在生产环境中,我们将此变量设置为*"。env"* 。这样,我们将根据不同的环境拥有不同的配置。
要设置环境变量 ENVIRONMENT_FILE 的值,在 VS 代码中,我们可以使用下面的 launch.json 文件:
我们的生产环境将是 Docker,因此在 Docker 文件中,我们将使用 ENV ENVIRONMENT_FILE= "来设置这个环境变量。env" 命令。
缓存目录
这个文件夹是由 Dash 的所谓 记忆 能力自动生成的。由于 Dash 的回调本质上是功能性的(它们不包含任何状态),所以很容易添加内存化缓存。记忆化在函数被调用后存储它的结果,如果用相同的参数调用该函数,则重用该结果。
为了设置这种记忆能力,我们必须定义缓存类型。
代替本地文件系统,我们也可以使用一个 Redis 缓存。
设置 Redis 超出了本教程的范围,因此我们将使用文件系统来缓存和重用调用之间的数据。
仪表板中的 MVC
在 MVC(模型-视图-控制器)架构设计模式的情况下,每个相互连接的组件都是为承担开发过程中的特定任务而构建的。
使用这种模式有多重好处:****
- 快速并行开发——因为组件是解耦的,所以多人可以并行工作
- 单个模型的多个视图
- 稳定的业务逻辑 —很明显,我们对视图做了更多的修改(改变颜色、位置等)。)而不是在业务逻辑上,并且改变视图不会影响业务层
- 易于重复使用、维护和测试组件
- 它通过将应用程序分成独立的(MVC)单元来避免复杂性
- 它提供了一个清晰的关注点分离(SoC)。****
- ****逻辑分组将一个控制器上的相关动作组合在一起
MVC 模式最重要的缺点之一是,通常我们需要了解多种技术,因为视图和控制器+模型是使用不同的技术实现的(比如 React/Angular/Vue/等等)。为了风景和。net/Java/Python/Node/Go/等。用于后端)。如果您使用 Python 和 Dash,那么这个问题就解决了,您可以将 Python 用于视图和控制器+模型。
作者图片
正如你在上面的图片中看到的,在我们的项目中,每一页我们将有三个文件,我们有一个共同的布局**,正如我们在本文前面已经介绍过的。**
现在让我们看一个例子,我们如何创建一个使用 MVC 模式的页面。我们将创建一个示例页面,其中我们将根据 GDP 绘制不同国家的预期寿命图表。
型号示例
在上面的代码中,我们使用了 Dash 的内存化特性,因为我们不想多次读取相同的数据,所以我们缓存数据**,这种方式提高了我们应用程序的性能。**
模型不依赖于视图或控制器,它是解耦的,它的职责是处理数据,它不必处理用户界面或数据处理。
视图示例
视图的唯一职责是向用户显示数据。如您所见,它使用模型(dataframe)并定义 Html/Css/Js/其他标记语言元素来将数据呈现给用户。
正如您在上面的代码中看到的,我们的示例只使用了模型,并创建了表示元素**。它没有定义处理用户事件的逻辑,也不包含业务逻辑。**
控制器示例
控制器解释来自用户的鼠标和键盘输入,通知模型和视图适当地改变。
正如您在上面的例子中所看到的,update_figure 回调函数获取用户在滑块上选择的值作为输入(因此它处理用户事件),并基于从模型中读取的数据从视图中更新图形作为输出。因此,正如 MVC 模式所定义的,控制器是在我们从视图获得请求之后,在用我们的模型更新数据库之前,我们处理数据的部分。
按指定路线发送
为了在页面之间导航,我们需要定义路由规则。为此,在根文件夹中,我们创建了一个名为routes . py的文件。
正如我们在代码中看到的,我们定义了一个回调函数,它接受活动路径作为输入(当路径改变时,这个方法将被触发),输出将呈现在主布局的内容中(页面内容)。
为了呈现适当的页面,我们检查活动路径,并基于活动路径返回页面。
归档我们的 Dash 应用程序
第一步是定义 Dockerfile 。
为了减小图像的大小,我们使用了 slim 版本,我们还移除了缓存文件**(第 8 行)。**
该应用将由 Gunicorn 提供服务,因此我们必须为其定义配置(参见 gunicorn_config.py )。
在 docker 镜像中,主机必须是 0.0.0.0 否则无法访问。
Dash 实例在单独的 app.py 中定义,而运行 app 的入口点是 index.py 。这种分离是避免循环导入所必需的:包含回调定义的文件需要访问 Dash app 实例,然而,如果这是从 index.py 导入的,那么 index.py 的初始加载将最终要求它自己已经被导入,这是无法满足的。
对于 Gunicorn 来说,重要的是将服务器明确定义为 Falsk 应用**(第 12 行)。**
由于我们正在添加对 app.layout** 中不存在的元素的回调,Dash 将引发一个异常,警告我们可能做错了什么。我们可以通过设置suppress _ callback _ exceptions = True来忽略该异常(这在多页面应用上很正常)。**
注意,我们从环境中读取主机、端口、调试和 dev_tools_props_check 的值。****
对于 Gunicorn,我们还需要定义 Procfile 。
如您所见,我们从索引文件(index:server)运行服务器(这是我们在 app.py 中定义的 Falsk 应用程序)。
为了安装所有需要的依赖项,我们定义了 requirements.txt 文件。
我们还定义了一个 docker-compose.yml 文件,这样就很容易构建和运行我们的 docker 映像。
为了设置$VERSION 和$TARGET 变量,我们定义了一个。docker-compose.yml** 旁边的 env 文件(在同一个文件夹中)**
为了构建和运行我们的应用程序,我们运行docker-compose build**,然后运行docker-compose up-d命令(在根文件夹中)。**
结论
在本教程中,我们描述了组织 Dash 应用的一种可能方式,我们展示了如何应用架构设计模式来引入关注点分离并编写干净且可维护的代码**。我们还介绍了如何使用多页面,如何使用Dash 的内存化来缓存和重用数据,如何为不同的环境使用不同的配置,并且我们描述了一种干净的方式为您的 Dash 应用设置和创建 Docker 容器。**
我真的很喜欢咖啡,因为它给了我写更多文章的能量。
如果你喜欢这篇文章,那么你可以请我喝杯咖啡来表达你的欣赏和支持!
****成为媒介上的作家:【https://czakozoltan08.medium.com/membership】T2
后续步骤
在我们的 下一篇教程 中,我们将呈现 Dash 更高级的概念,比如在回调之间共享数据、持久性、使用 Redis 的内存化、动态创建回调以及使用模式匹配回调。****
代码
本教程的代码可以在 这个 git 资源库 中找到。(喜欢我的代码请留个✩)
最后的话
感谢您阅读这篇长文!
如果你想要一些【愚蠢简单】的解释**,请跟我上媒!**
有一个正在进行的《愚蠢简单的 AI》系列**。前两篇可以在这里找到: SVM 和内核 SVMKNN 在 Python 。**
如果想要一些关于 Kubernetes 的“愚蠢简单”的讲解和教程**,可以查看我的 愚蠢简单 Kubernetes 系列。**
谢谢大家!
面向数据科学家的干净代码
原文:https://towardsdatascience.com/clean-code-for-data-scientists-150ce920c39e?source=collection_archive---------34-----------------------
在 Unsplash 上 OCG 拯救海洋的照片
第 3 部分—团队合作
如果你是一个热爱干净代码的人(坦白地说,你怎么可能不是呢?)和你在一个团队工作,这就是你的位置。在团队中工作时,每个人对如何编写代码都有自己的想法,对什么是干净的代码以及我们是否需要它都有自己的想法(但是你知道正确的答案,对吗?).
当我们是团队的一部分时,我们通常共享我们的项目、我们的存储库、我们的助手功能和工具。此外,我们可能会使用其他人的代码,或者在团队成员请病假的当天处理他代码中的 bug。意思是——我们需要对我们团队的所有代码感到舒服,而不仅仅是我们自己的代码。帮助你理解你团队的代码并感到舒服的最好方法之一是确保你们都使用相同的语言——干净的代码。无论您是团队领导还是团队成员,您都可以开始干净代码革命!
传播干净的码字
我们如何让干净的代码成为我们团队核心价值的一部分?我们如何创建长期有效的编码标准?
1.分享为什么
第一步,有点像这个博客系列的第一部分,是确保你的队友理解为什么作为数据科学家写干净的代码如此重要。许多数据科学家并没有计算机科学背景(我也是,罪名成立),所以他们可能不熟悉这个话题,或者觉得这与他们的工作无关。
理解动机对于编写干净的代码至关重要(一般来说,作为数据科学家也是如此)。如果人们不理解其中的原因,他们不仅会缺乏动力,而且也不会写出最干净的代码。编写干净的代码需要你理解代码背后的逻辑——例如,我们编写有意义的名字,以使我们的代码可读,并在阅读时创建准确的预期。不了解动机,就无法判断自己是否写了干净的代码。
2.符合您的期望
在现实生活中,这些努力大多因实施困难而失败。您或您的团队成员可能至少有一次团队编写干净代码的失败尝试。
确保这些努力不会白费的最好方法之一就是设定期望值。确保你的团队成员和经理明白这是一个漫长的过程(几个月),它往往会有暂时的倒退(例如,在发布日期前后),它会在短期内减缓开发。这需要时间和耐心,直到所有团队成员都一致,代码会慢慢变得越来越好。
只有当每个人都认同这件事的重要性,并且我们在这个过程中设定了我们的期望,我们才能开始工作。
3.写下指导方针
安排一次与团队的会议,然后写下你自己团队编写代码的指导方针。作为干净代码的大使,建议你准备好一些建议。然后,与您的团队一起检查这些建议,讨论并决定您想要采纳哪些建议。一份书面的、简短的、保存的、共享的文件会让每个人都遵守这些指导方针,并使他们在需要提醒时能够回头阅读。另外,当一个新的团队成员加入进来时,这是一个添加到你的入职计划中的很好的文档。只要保证不要太长(不超过 5 页),分成有意义的主题,用项目符号写出来,就不会变得难读了。
4.建议循环编码会话
您可能会发现与您的团队的这个指导方针会议太短了,无法将您所想的所有干净代码实践都包含进去。或者你可能会发现你想讨论其他日常协议,比如使用 Git、模型版本控制、使用笔记本等等。这就是为什么我建议把这个会议变成一个定期的会议。不一定是一周一次,可以是隔周一次,也可以是一个月一次。但是有一个讨论代码协议的地方是你可以给你的团队的一份大礼。如果你碰巧没有话题了(不现实,我知道),你总是可以抓住一段旧的、杂乱的代码,作为一个团队一起重构它。你会惊讶于它有多有趣,而且它可以引出更多的问题来讨论。
5.代码审查
另一种确保你的团队编写出最整洁、最干净的代码的常见方法是代码评审。检查彼此的代码,确保它们遵循你心中的准则,并讨论任何不匹配的地方。这个过程对于确保你们仍然保持一致是至关重要的。这些代码审查还可能导致:
- 如有必要,更新指南文件
- 在你的一个循环代码会话中讨论经常出现的错误
并不是你写的每一段代码都需要经过代码评审过程(当然取决于你团队的政策)。如果你觉得,作为一个团队,代码评审占用了你太多的时间,你可以选择只对你的代码库的更重要的部分进行代码评审,而不是每次更新的时候。与其有一个强制性的、负担沉重的过程,不如执行更少的代码审查,让它们变得有意义(实际上从中学习)。
顺便说一句,如果你想确保你的代码是真正干净和可读的,建议只需将它发送给你的同事(使用拉请求或任何其他你希望的方法),而无需任何事先的对话。不要告诉他们去哪里看,你的代码做什么,你希望改进哪一部分——让他们来判断。这将使您的代码审查更加客观,并且符合它的目的——检查您的代码是否对任何人、任何时间都是可读的。
6.结对编程
“结对编程是一种开发技术,其中两个程序员在一个工作站一起工作。一个是驱动程序,编写代码,而另一个是观察者或导航者,在输入代码时检查每一行代码。这两个程序员经常交换角色”。(维基百科)
虽然结对编程乍看起来非常耗时(因为两个团队成员在一个任务上工作),但它也是提高您的编码技能的一个好方法。当你和身边的同事一起编码时,他们会不断提出你没有想到的问题,丰富你干净的编码思路。偶尔尝试将结对编程融入到工作流程中,你不会后悔的。
总而言之,如果干净的代码对你很重要,你应该让它成为你团队的日常习惯。解释的重要性,确定的指导方针,尝试安排一个定期会议,并确保你们团队有足够的代码评审。如果你有更多的想法,请与我分享,并让我知道它如何为您的团队工作。祝你好运!
面向数据科学家的干净代码
原文:https://towardsdatascience.com/clean-code-for-data-scientists-6fc90872398f?source=collection_archive---------12-----------------------
萨曼莎·加德斯在 Unsplash 上的照片
第 1 部分——动机
你好,如果你是一名数据科学家,并且关心你的代码,那么你来对地方了。这是为数据科学家撰写的干净代码系列文章的第一部分:
第一部分——这是你目前正在阅读的内容。在这一部分,我将分享为什么我认为把你的时间和精力投入到编写干净的代码中是很重要的。
第 2 部分——实施的实用技巧。
第 3 部分——作为数据科学团队如何实践干净的代码。
我将首先解释什么是干净的代码,以及为什么它对于数据科学家来说是至关重要的实践。
什么是干净代码?
干净的代码是人们可读的代码,而不仅仅是编译器可读的代码。很容易改变和维护。我发现描述干净代码的最好方式是度量——“每分钟 WTFs”。也就是说,当你阅读一段对你来说是新的代码时,你会有多少次对自己说“哇哦?”:
图片由 Glen Lipka 在 commadot 上拍摄
当我们想到干净的代码时,我们可能会想——嗯,这是软件工程师和架构师需要担心的事情。所以实际上没有。请继续关注,因为我将试图让您相信干净的代码对于您作为数据科学家的工作是至关重要的,并提供一些实用的工具和实现它的技巧。
干净代码对数据科学家的重要性
一般来说,干净的代码是可读的,所以更容易调试和重构。这种方便使得代码易于维护,因此添加或更改代码没什么大不了的。这意味着生产率不会随着时间和复杂性的增加而下降,也不会随着我们添加更多的代码而下降。另外,干净的代码对错误更免疫。
作为数据科学家,我们做研究,我们学习,我们计划,但最终— 我们需要编写代码来实现这一切。如果你的代码对别人(和你自己)来说是错误的或者不可读的,即使是最聪明的算法也一定会出错。我们的算法和我们的代码一样好。
作为数据科学家,我们有时单独工作,有时团队工作。在这两种情况下,编写干净的代码至关重要:
- 在团队中,这将使更容易理解和重构团队成员的代码(这可能是干净代码的第一条规则——剧透警告)。这也将使新团队成员的开始和入职更加顺利(说心里话——因为我最近刚开始一个新职位)。
- 当你独自工作,或者独自完成大部分项目时, cleaner code 将帮助你在项目之间跳转,并以最少的“我在这里做了什么?”阶段。
鲍勃叔叔说“花在阅读和写作上的时间比远远超过 10 比 1”。在编写新代码的过程中,我们不断地阅读旧代码。编写新的代码并不容易,更不用说当你试图在弄清楚之前有什么的时候。
举个例子,看看这个简短的函数,试着理解它的作用:
现在看看这个函数,做着完全相同的事情:
你只看名字就有这么多信息,每一行都讲述了一个故事。现在想象一下你的代码只由混乱的代码组成——难道不需要更长的时间来理解那里发生了什么吗?更别说重构了。事实是——我只花了大约半分钟的时间来编写更好的代码。
数据科学家的干净代码之争
你可能会达到这一点,并说——“是的!我想写更干净的代码,为什么我一直没有这么做?”。事实是你可能有很好的理由。首先,它需要知识、实践和渴望。作为数据科学家,保持我们的清单像我们希望的那样整洁并不总是容易的。
高风险代码编写
根据我的经验,第一个原因是我们工作的“高风险”性质。意思是,当我们在脚本中编写第一行代码时,我们通常不知道它会发生什么——它会工作吗?会量产吗?我们还会用它吗?它有价值吗?
我们最终可能会在高风险的概念验证或一次性数据探索上花费大量时间。在这种情况下,编写最简洁耗时的代码可能不是正确的方法。但是,我们以粗略的方式编写的这个 POC 变成了一个实际的项目,它甚至进入了生产阶段,而它的代码却是一团糟!听起来很熟悉?我以前经常遇到这种事。
耗时的
所有代码编写者的共同点是时间方面。写干净的代码首先要花费更多的时间因为你在写任何一行代码之前都需要三思。我们总是被督促或鼓励快速完成工作,这可能会以牺牲代码为代价。
请记住——在匆忙中快速完成工作,可能会在你每天处理 bug 的时候伤害到你。你花在编写干净代码上的时间肯定会在 bug 上节省的时间上得到回报。
韵律学
斗争的另一个原因是衡量我们的方式。作为数据科学家,我们的雇主正在寻找结果 —准确的预测、有见地的数据发现、最新的技术。但是通常,没有人会看着引擎盖下的东西,只有当我们的代码整洁时,才标记这个季度的任务是成功的。代码基础设施和条件是团队的内部目标,很难让其他人意识到。
一些基本原则
如果你已经做到了这一步,并且想让你的代码更整洁,这里有一些我最喜欢的指导方针:
让你的代码质量与草稿水平相匹配
高风险的概念验证或数据探索可以从草稿开始,随着您的进展,您的代码会变得更加整洁
遵循标准惯例
这包括变量、函数和类的有意义的名字;常数而不是硬编码的字符串和整数;格式一致。
让你的功能变得强大
每个功能应该只做一件事。他们应该是短期的,没有副作用。
少即是多
你的代码应该尽可能的短,不带注释(除非他们告诉你为什么,但从不告诉你怎么做)。另外,确保删除注释掉的代码,因为它只会造成混乱。
保持简单
越简单越好,所以尽量降低复杂度。
童子军规则——让露营地比你发现时更干净
在团队中工作时——不要害怕改变别人的代码。单独工作时——在重新审视代码时,修改自己的代码。
报纸文章原则
脚本的顶部应该是最顶层的函数,越往下越详细。
如果你想知道更多,欢迎你来查看我的教程 的第二部分 ,它解释了如何实施这些指导方针,并列出了更多值得关注的内容。
改变从现在开始
任何人在任何时间编写干净的代码都是可能的。不管你是新人还是有经验的人,所需要的只是一件简单的事情——想要它。改变从内部开始。
在瑜伽中,有一种想法是想做点什么,即使你不一定会成功。你的意图才是最重要的。
我发现写代码也很类似。我们不一定要遵循所有的协议或做得完美。只要把它放在我们的脑海中,想要它,并思考它,就一定会让我们的代码变得更好。当然,熟能生巧。如果你不相信我,你自己试试看吧!
面向数据科学家的干净代码
原文:https://towardsdatascience.com/clean-code-for-data-scientists-db1d88c42fab?source=collection_archive---------24-----------------------
JESHOOTS.COM在 Unsplash 上拍照
第 2 部分—方法
如果你在这里,这意味着你理解干净代码的重要性,并且你想掌握它。太神奇了。正如我在上一篇文章中提到的,你的意图和想法将会完成大部分工作。让我们添加一些实用的提示,你就可以开始了。
我想写干净的代码,但是怎么做呢?
如果你真的很认真,你想知道整个理论,我推荐阅读罗伯特·c·“鲍勃叔叔”马丁的**《干净代码:敏捷软件工艺手册》**。但是,如果您没有时间,或者您正在寻找更多面向数据科学的技巧,那也没关系。我将与你分享我的两分钱和我所学习和使用的东西。
但是,我必须警告你,从现在开始——这只是建议。没有对错之分(比如命名惯例),你只需要坚持某件事。另外,可能还有更多指导方针,我只是列出了最适合我的和我认为最方便的:
- 将您的代码质量与草稿级别相匹配
- 童子军规定——让露营地比你发现时更干净
- 保持简单
- 深思熟虑地命名变量、类和函数
- 确保你的函数很短,只做一件事,并且没有副作用
- 报纸文章——脚本的顶部应该是最顶层的函数,越往下越详细
- 少即是多——简短,无评论
将您的代码质量与草稿级别相匹配
正如我在上一篇文章中提到的,作为数据科学家,编写干净代码的挑战之一是,很多时候,我们开始一个项目(POC/数据探索),我们不确定它是否可行,以及我们是否会再次使用它。因此很难(当然也没有回报)投入很多时间为这些情况编写干净的代码。当它工作时,问题出现了,我们将它集成到我们的解决方案中,并在生产中发现这个写得很差的代码。
克服这个问题的方法——不要在探索性代码上投入太多,但要保持现实生活中的解决方案整洁,就是使代码质量与草稿水平相匹配。
我说的代码质量是什么意思?为了更好地定义代码质量,我把我的代码分成三个质量等级。
1.一团糟
想象一下你自己正在尝试一种你刚刚学到的新算法,检查它是否对你的数据有效,或者得到一个新的数据集并了解其中的内容。它将是快速而肮脏的——没有花哨的类,没有经过深思熟虑的变量名,您可能会将您的数据框命名为“df ”,而这一切都将被扔进一个脚本中,就像您在洗衣篮中的衣服一样。
2.相对可读的代码
这可能不是最棒的一段代码,但是其他人将能够理解发生了什么。变量名应该有意义,应该很好地划分成函数或类。它不会遵循所有的协议,可能不包括单元测试,但它是一个开始和重构的好地方。
3.最重要的是——代码的蒙娜丽莎
这是将授予你诺贝尔奖最伟大的代码工匠转变的代码。是的,我可能夸大了。这是生产级代码,所以它应该反映出你所得到的最好的东西,并且符合你希望遵循的所有准则,因为你会希望这段代码在未来尽可能地不受 bug 影响,并且最容易维护(无论是你自己还是你的团队成员)。
现在,考虑到这些质量水平,我根据任务及其成熟度匹配我的写作水平,并让它沿着这条路发展:
- 如果你正在编写一个低风险算法并且你对自己的方法有把握,那么从一个高水平的代码质量(介于 2 到 3 之间)开始。
- 如果您正在开始 POC、实施**高风险算法、**或进行可能是一次性的数据探索,从 1 开始,随着您的进步并了解什么可行,什么不可行,逐渐过渡到 2 。这样,你从低质量的代码开始,快速前进,尝试不同的方法、算法等。并在您开始看到潜力时改进您的代码。
- 出于任何其他目的,使用 2 并逐渐将其向上移动至 3 以准备释放。
- 最重要的规则是永远不要留下乱七八糟的代码!在进入之前,基本上进行重构,同时你还记得你试图实现什么以及如何实现。留下的杂乱代码在未来将是无用的,你可能不得不重写它。
一般准则
童子军规则
如果要我说出我的第一条规则,那就是童子军规则。童子军规定各州要保持营地比你发现时干净。或者在我们的例子中— 总是让代码比你发现的更好。这是什么意思?
- 在团队中工作时,不要害怕改变别人的代码。当你遇到一个写得不好的代码,不管是大的还是小的,需要改变的时候——改变它。你不需要请求许可或仔细考虑——这是你的职责。
- 独自工作时——重新审视自己的代码时修改它,不断重构和编辑以使它变得更好。
- 应用童子军规则将确保您的代码库始终处于最高水平。
- 当你在高质量测试和高测试覆盖率的代码上工作时,遵循童子军规则是最简单的。这样,你会感到安全,因为重构不会造成任何伤害。然而,缺乏测试不应该阻止你重构。你总是可以写一些测试来确保功能保持不变并进行重构。
保持简单
第二个重要的指导方针是“保持简单”。我曾经得到一个很好的建议— 写代码的时候,用一半的脑细胞去读代码。原因很明显——阅读代码要困难得多,所以我们在编写代码时应该以简单为目标。总是问自己——这能写得更简单吗?
命名规格
写代码就像讲故事,而你的名字选择是故事的一个重要部分。在编写代码时,确保你投入时间和精力在选择能透露尽可能多信息的名字上。
当你为你的函数/变量选择一个名字时,为了下一个阅读它的人(当然,可能是未来的你),这个名字创造了一个对那里将会有什么的期望。这些期望是两个因素的结果:
- 该名称的语义含义。我们期望函数“def load_training_set()”加载数据,但我们不会期望它过滤掉空值,对吗?我们期望变量“student”代表一个人,所以如果它是一个列表,那就令人困惑了。
- 格式——怎么写。如果标准约定是用大写字母书写常量值,并且您将数据框命名为“TRAINING_DATA ”,那么您的代码可读性更差,也更难解释。
当在代码中命名一个实例时,你应该总是考虑你创建的期望,并确保它匹配它的内容。如果不是,重命名它。
以下指南包含一般建议和具体约定。需要注意的是这种特殊的约定并不神圣,重要的是要有一个符合目的的一致约定——让你的代码更具可读性,符合读者的期望,并且有一个标准化的代码库。
通常,在整个代码中,请注意以下几点:
- 连贯的术语——每个概念使用一个术语(例如,不要同时使用“获取”和“取得”来描述同一个动作)。
- 避免将同一个词用于两个目的。
- 使用变量名作为一种方式来说明代码正在做什么。
常量变量
用常量变量代替硬编码的字符串或整数,写成全大写:
- 例如,使用“CLASSIFICATION_THRESHOLD=0.8”代替 0.8。
- 给它们一个描述性的名称。
- 将它们放在代码的顶部或外部设置文件中。
- 阅读、搜索、更改值和测试将变得更加容易。
变量名
您的变量名应该是:描述性的、可发音的、可搜索的、解释性的、揭示意图的:
- 比如不用“df”,用“train_set”。
- 对数组和列表使用复数,而不是命名它们的类型。例如,用“学生”代替“学生列表”。
- 使用单词,而不是缩写。比如用“learning_rate”代替“lr”。
- 长总比暧昧好。
类名
您的类名应该是:
- 名词或名词短语,如分类器、数据处理程序。
- 避免使用通用名称,如管理器、处理器。
功能名称
您的函数名应该:
- 说他们做什么。
- 包含动词或动词短语名称,如“evaluate_model”。
- 尽可能具体。比如用“load_training_data”代替“load”。
- 模仿你告诉你朋友这个函数是做什么的方式
- 如果它们仅供本课程内部使用,则以 _ 开头。比如“_load_training_data”。
功能
- 应该是小的——把一个大的功能分成几个小的。
- 应该比那个小。
- 经验法则——不要超过 20 行。当一个函数中有这么多行代码时,很难理解它做了什么。但是如果你把它分成更小的块,每个块都有一个有意义的名字,那就完全是另外一回事了。
- 如果你发现自己在函数中寻找几行代码——它们应该是自己的函数。
- 每个函数应该做一件事,而且只做一件事。它要么做点什么,要么回答点什么,而不是两者都做。
- 不要重复自己——这就是函数的作用。如果需要——将函数拆分成更小的方法,然后重用它们。
- 没有副作用——不要改变任何你不应该改变的东西。
- 当调用一个函数时,总是写下参数名和它们的值。这将使它更容易阅读和理解。
- 参数越少越好—尽量避免超过 3 个参数。
- 尽量用函数封装复杂的条件句。例如,不使用“if (timer.has_expired()和(timer.is_recurrent())”,而是使用“if should_be_deleted(timer)”
- 避免消极条件句。例如,不使用“if (not follow_up_needed())”,而是使用“if (follow_up_not_needed()”。
格式化
格式化是你设计代码的方式——它看起来不需要深入到名字和动作中。正确的格式有两个目的:
- 沟通——如果你的变量/函数名是口头沟通,那么格式化就是非口头部分。这说明了很多问题。如果您选择将两个函数一个接一个地放置,它可能会告诉读者它们是相关的,或者会一个接一个地运行。
- 专注——一旦格式化做得很好,代码看起来有条理,它释放你的思想去处理真正重要的东西——它的内容。看着视觉上混乱的代码会转移你对其含义的注意力。
以下是我尝试在代码中应用的一些格式准则:
- 概念之间的垂直开放性——每行代码只做一件事。
- 每一个空行都是一个视觉提示,可以识别一个新的独立的概念,所以要明智地使用它。
- 相关代码(和相关函数)应该垂直排列。
- 声明与其用法相近的变量。
报社负责人
我最喜欢的格式指南之一是报纸原则,它指出你的脚本应该从高级功能开始**,并向下滚动**深入细节。
- 源文件的最上面部分应该提供高级的概念和算法。
- 随着我们向下移动,细节应该增加,直到最后,我们在源文件中找到最低级别的函数和细节。
- 这就像读报纸一样——你从顶部的标题开始,然后是副标题,然后是全文和细节。
少即是多
尽量保持代码简洁:
- 简短简短——你的代码越短,你阅读和理解它的速度就越快。当然,不是以一团糟为代价。你仍然需要为每一个动作写一行,但是尽量避免不必要的动作。
- 删除注释掉的代码 —相信我,没有人会错过它。
争取零评论
你应该尽量在代码中没有注释——干净的代码不需要注释。
为什么?
- 代码应该在 90%以上的时间里自我解释——使用你的函数和变量名来解释,而不是注释。
- 我们经常在更新代码的时候忘记更新注释。
- 它增加了杂波。
如果您添加了评论:
- 不应该是关于你如何做某事,而应该是关于你为什么做这件事。
- 确保它是必要的,**非琐碎的,**而不是多余的。
- 使尽可能短。
- 随着代码的变化,删除过时的注释。
- 不要注释掉代码——只是删除它。
如果你想了解更多并看到一些真实的例子,我推荐这篇文章:
https://towards data science . com/python-clean-code-6-best-practices-to-make-your-python-functions-more-readable-7ea 4c 6171d 60
总而言之,只要记住作为一名数据科学家,你最好的算法只能和用写的代码一样好。写得好的算法将是(尽可能接近)防错的,并且易于维护。它所需要的只是你的良好意愿,一些实用的知识和技巧,这些你现在都有了。让我知道进展如何!
参考资料:
- “干净的代码:敏捷软件工艺手册”,作者罗伯特·c·“鲍勃叔叔”马丁。
- 7 2 个理由心理学将帮助你写出更好的代码作者莫兰·韦伯&乔纳森·阿维诺尔(演讲用希伯来语)
- 阿图罗·赫雷罗演讲中的干净代码幻灯片
使用 DataPrep 进行交互式清理、连接和可视化
原文:https://towardsdatascience.com/clean-connect-and-visualize-interactively-with-dataprep-9c4bcd071ea9?source=collection_archive---------16-----------------------
适用于您的数据分析过程的一体化软件包
照片由 UX 印尼在 Unsplash
数据准备是任何数据专业人员都要做的第一步。无论是要对数据进行分析,还是要对机器学习模型的数据进行预处理,都需要准备好数据。
准备数据意味着您需要收集、清理和探索数据。为了完成我提到的所有活动,开发了一个名为 DataPrep 的 Python 包。这个包裹对我们有什么帮助?让我们一起来探索一下。
数据准备
DataPrep 是为准备数据而开发的 Python 包。这个包包含三个主要的 API 供我们使用,它们是:
- 数据探索(
dataprep.eda
) - 数据清理(
dataprep.clean
) - 数据收集(
dataprep.connector
)
DataPrep 包被设计成具有快速的数据浏览,并且与 Pandas 和 Dask DataFrame 对象配合良好。为了探索 DataPrep 功能,我们需要首先安装这个包。
pip install -U dataprep
在我们安装完这个包之后,让我们使用 API 来准备我们的数据。
数据准备探索
DataPrep 让我们用一行代码创建一个交互式的概要报告。这个报告对象是一个 HTML 对象,从我们的笔记本中分离出来,有许多探索选项。让我们用示例数据来尝试一下 API。
from dataprep.datasets import load_dataset
from dataprep.eda import create_report
df = load_dataset("titanic")
df.head()
作者图片
我们将使用泰坦尼克号样本数据集作为我们的数据。加载完数据后,我们将使用create_report
函数来生成交互式报告。
create_report(df).show_browser()
作者 GIF
正如我们在上面的 GIF 中看到的,API 创建了一个很好的交互式报告供我们探索。让我们试着逐一剖析这些信息。
概览选项卡(按作者分类的图像)
从 overview 选项卡中,我们可以看到数据集的所有概述信息。我们可以获得的信息包括缺失数据数和百分比、重复数据、变量数据类型以及每个变量的详细信息。
变量选项卡(按作者分类的图像)
variables 选项卡为我们提供了数据集中每个变量的详细信息。几乎所有您需要的信息都是可用的,例如,唯一、缺失数据、分位数和描述性统计、分布和正态性。
交互选项卡(按作者分类的图片)
interactions 选项卡将从两个数字变量创建一个散点图。我们可以自己设置 X 轴和 Y 轴,这让我们可以控制如何可视化它。
相关性选项卡(按作者分类的图片)
“相关性”选项卡为我们提供了数值之间的统计相关性计算热图。目前,我们可以使用三种计算方法——Pearson、Spearman 和 KendallTau。
缺失值选项卡(按作者排序的图像)
“缺失值”选项卡为我们提供了关于选项卡中缺失值的所有详细信息。我们可以选择条形图、光谱图、热图和树状图来充分探索缺失值信息。
数据准备清洗
DataPrep 清理 API 集合提供了 140 多个 API 来清理和验证我们的数据帧。例如,我们可以使用的 API 有:
- 列标题
- 国名
- 日期和时间
- 重复值
- 电子邮件地址
还有很多。我们可以尝试的功能太多了,本文不可能涵盖所有的 API。如果你有兴趣,可以在这里查阅文档。
让我们以 Titanic 数据集为例,尝试一下列标题清理功能。
from dataprep.clean import clean_headers
clean_headers(df, case = 'const').head()
作者图片
使用“Const”的情况下,我们将结束所有大写的列名。如果我们把这个案例换成“骆驼”
clean_headers(df, case = 'camel').head()
作者图片
结果是除“sibSp”列之外的所有较低的列名,在“sibSp”列中,它们的列名中有两个单词。
如果你想要一个完整干净的数据框架,我们可以使用来自 DataPrep 的clean_df
API。这个 API 有两个输出—推断的数据类型和清理的数据帧。
from dataprep.clean import clean_df
inferred_dtypes, cleaned_df = clean_df(df)
作者图片
有许多参数可以在 API 中使用。我建议您阅读所有文档,看看哪些参数适合您的数据准备目的。
DataPrep 集合
DataPrep 收集 API 用于从数据库或 Web API 收集数据。如果我们可以访问数据库,比如 MySQL 或 PostgreSQL,您可以用 DataPrep API 连接它,但是也可以使用 DataPrep connect
API 访问公共 API。
如果您想从 web 上收集数据,仍然需要 API 代码,但是一切都被简化了。如果你想了解更多关于集合 API 的内容,你可以在这里阅读全部。
结论
DataPrep 是一个单行 Python 包,用于清理、连接和浏览您拥有的数据集。该功能包括:
- 数据探索(
dataprep.eda
) - 数据清理(
dataprep.clean
) - 数据收集(
dataprep.connector
)
希望有帮助!
在我的LinkedIn或 Twitter 上访问我。
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您不是作为中等会员认购,请考虑通过 我的推荐 进行认购。
清洁能源开发商需要兑现他们的数据
原文:https://towardsdatascience.com/clean-energy-developers-need-to-cash-in-their-data-63a2672147e8?source=collection_archive---------29-----------------------
不采用大数据工具将意味着能源行业的死亡
照片由 Unsplash 上的 Jp Valery
太阳能、风能和储能发电厂的公用事业规模开发商在一个利润微薄、资本支出极高且时间表漫长的行业中竞争。每一个新的发展都是一场赌博,只有在数年和数百万美元后才显示出它的可能性。鉴于该行业的历史性质,大多数用于评估这些发展的工具都是 20 世纪的人工制品。然而,“清洁技术”品牌吸引了大数据公司的注意,这些公司以强大的竞争优势进入了数据丰富的行业。如果保守的能源公司不采用最佳数据实践,他们高昂的开发成本将扼杀未来项目成功的任何希望。
是时候让开发公司意识到他们是大数据公司了。
数据驱动发展
开发的目标是通过最小化不确定性来最小化项目风险。一个完美开发的项目将确切地知道它将产生多少能量,确切地知道它的成本将是多少(以及被完全许可和准备建造)。为了降低风险,开发人员使用“数据驱动开发”它们会产生数量惊人的数据,从历史风速和辐照度等传统格式到工程报告或许可文件等组织性较差的格式。来自所有这些来源的数据在决策者的头脑中汇集,然后他们预测项目的经济效益。这种预测必须有足够的证据来支持它,以说服其他关键的利益相关者(如希望贷款给项目的金融家或希望购买项目的公用事业公司)。开发商通过以尽可能低的成本充分降低经济项目的风险而获得成功。
减少开发费用通常意味着产生更少的数据(因为你为更少的研究付费)。数据越少,项目的风险就越大。因此,开发公司削减项目成本的效率是有限的,他们必须寻求建筑、技术和性能方面的创新来获得优势。当然,除非你有办法在不需要获得更多数据的情况下,为关键涉众减少足够的项目不确定性。如果更少的数据并不意味着更高的项目风险呢?如果您可以从现有数据中获得更多见解,会怎么样?
大数据创新
在“大数据”的世界中,存在可以从我们生成的数据中提取出无数奇迹的工具,丰富的数据源就像等待数据科学“49 人组”挖掘的金矿很难找到比项目开发更丰富的未开发数据来源。然而,这些数据中的大部分都没有被传统的开发者使用。这里有一个例子:
示例开发
比方说,一家开发商正在考虑将其“Bertrand”太阳能发电场竞标到一些即将到来的提案请求中(RFP:当一家公司有兴趣从太阳能发电场购买电力时,要求开发商向他们发送项目以供选择)。为了决定是否支付投标这个项目的价格,以及如果有任何研究,它应该提前开始以进一步降低开发风险,开发商举行“思想会议”这些决策涉及许多因素,为了准备这次会议,公司的不同部门被要求总结他们对项目开发的每个关键部分的发现。
对于一个这样的组件,一名工程师阅读了一份初步的岩土工程研究,以评估该场地的土壤将大幅增加建筑成本的风险。这位工程师必须浏览几百页的文档,从中提取关键信息,然后将这些信息提交给她的经理,经理再将这些信息传递给她的经理,以此类推,直到在会议上提交。生成这份文件的研究花费了数十万美元,耗时数月才完成。所有这些时间和费用都转化为决策者在做出关于 RFP 的决定之前在许多其他要点中消化的一条知识。
如果你曾经有过认知偏差,或者你曾经玩过“电话”游戏,你知道在这个过程中做出的决定会受到很多“噪音”的影响,干扰了正确的“信号”。决策者无法对项目做出公正的决策,所提供的数据可能会遗漏它所保证的细微差别,而且整个过程既及时又昂贵。与此同时,这家开发公司拥有大量相关数据,但这些数据并没有在这个决策中使用。精通数据的公司面临所有这些问题。
更好的发展
为了降低这个项目的开发成本,公司可以引入附近项目已经生成的所有数据,以及相关的公开可用数据集。为了减少决策时的不确定性和偏见,机器学习模型可以提供数据驱动的建议。为了减少误解,项目的所有数据都可以在一个位置方便地访问和汇总。
下面的仪表板提供了一个排名系统,用于将一个项目与附近的其他开发项目进行比较,显示项目时间表和即将交付的成果,甚至估计该项目赢得即将到来的 RFP 的概率。决策者可以利用这些信息来了解应该启动哪些开发任务,以及应该投标或回避哪些 RFP。最重要的是,通过项目开发周期生成的每个数据点都被整合到影响整个开发组合的数据池中,减少了对未来研究的需求。
仪表板示例(按作者)
这个例子只是触及了大数据驱动的开发者所能获得的东西的表面。那些还运营发电厂的公司可以将运营和发展数据结合起来,以获得更大的洞察力,而参与电力市场竞标的独立发电商提供了另一个丰富的数据源。
结论
目前,有效的数据管理和分析为当前的公用事业规模开发商提供了巨大的竞争优势,但这将是短暂的,因为改进的数据平台的低成本和高收益迫切需要快速采用。迟早,适当的数据处理将成为行业的必需品。在已经成为 21 世纪能源行业标志的情况下,那些适应缓慢的公司将很快倒闭。
如果你是一家开发公司,是时候认识到你是一家大数据公司了。给自己提供成功所需的工具,培训能源专家,让他们的数据为自己服务。关于数据科学如何让您的团队受益的另一个例子,您可能有兴趣阅读这篇文章。你可以在这里找到提升你的团队的免费资源路线图。至少,和你的团队讨论一下如何更好地使用你的数据。你会对唾手可得的水果感到惊讶。
用 Python 中的傅里叶变换清除数据噪声
原文:https://towardsdatascience.com/clean-up-data-noise-with-fourier-transform-in-python-7480252fd9c9?source=collection_archive---------0-----------------------
用傅立叶变换清理时间序列数据用最短的 Python 代码
来自维基的约瑟夫·傅立叶
傅立叶变换是一种从完全不同的角度查看数据的强大方法:**从时域到频域。**但是这个强大的运算看起来很可怕,因为它的数学方程式。
将时域波转换到频域;
从时域到频域,也称为前向离散傅立叶变换或 DFT
下图很好地说明了傅立叶变换:将一个复杂的波分解成许多规则的正弦波。
图片来自维基
下面是完整的动画,解释了将时域波形数据转换到频域视图时会发生什么。
来自 wiki 的 Gif
我们可以很容易地操纵频域中的数据,例如:去除噪声波。之后,我们可以使用这个逆方程将频域数据转换回时域波:
从频域到时域的逆变换,也称为离散傅里叶逆变换或 IDFT
让我们暂时忽略 FT 方程的复杂性。假设我们已经完全理解了数学方程的含义,让我们使用傅立叶变换在 Python 中做一些实际的工作。
理解任何事物的最好方法是使用它,就像学习游泳的最好方法是潜入水中变湿。
将干净的数据与噪声混合
创建两个正弦波并将它们合并成一个正弦波,然后有目的地用从np.random.randn(len(t))
生成的数据污染干净的波。
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = [16,10]
plt.rcParams.update({'font.size':18})#Create a simple signal with two frequencies
data_step = 0.001
t = np.arange(*start*=0,*stop*=1,*step*=data_step)
**f_clean = np.sin(2*np.pi*50*t) + np.sin(2*np.pi*120*t)
f_noise = f_clean + 2.5*np.random.randn(len(t))**plt.plot(t,f_noise,*color*='c',*Linewidth*=1.5,*label*='Noisy')
plt.plot(t,f_clean,*color*='k',*Linewidth*=2,*label*='Clean')
plt.legend()
(将两个信号组合形成第三个信号也称为卷积或信号卷积。这是另一个有趣的主题,目前广泛用于神经网络模型中)
我们有带噪音的波浪,黑色是我们想要的波浪,绿色线条是噪音。
干净的海浪夹杂着噪音,作者安德鲁·朱
如果我隐藏图表中的颜色,我们几乎无法从干净的数据中分离出噪音。傅立叶变换在这里可以有所帮助,我们需要做的就是将数据转换到另一个角度,从时间视图(x 轴)到频率视图(x 轴将是波频率)。
从时域到频域的变换
可以用numpy.fft
或者scipy.fft
。我发现scipy.fft
非常方便,功能齐全。这里我将在本文中使用scipy.fft
,但是如果您想要使用其他模块,这是您的选择,或者您甚至可以基于我在开始时给出的公式构建一个您自己的模块(见后面的代码)。
from scipy.fft import rfft,rfftfreq
n = len(t)
yf = rfft(f_noise)
xf = rfftfreq(n,data_step)
plt.plot(xf,np.abs(yf))
- 在代码中,我使用了
rfft
而不是fft
。r 的意思是减少(我想)以便只计算正频率。所有负镜像频率将被忽略。而且速度也更快。更多讨论见此处。 - 来自
rfft
函数的yf
结果是一个复数,形式类似于a+bj
。np.abs()
函数将计算复数的√(a + b)。
这是我们原始波的神奇的频域视图。x 轴代表频率。
《频域数据》,作者 Andrew Zhu
在时域看起来复杂的东西现在被转换成非常简单的频域数据。两个峰值代表两个正弦波的频率。一波是 50 赫兹,另一波是 120 赫兹。再回头看看产生正弦波的代码。
f_clean = np.sin(2*np.pi***50***t) + np.sin(2*np.pi***120***t)
其他频率都是噪声,下一步会很容易去除。
去除噪声频率
在 Numpy 的帮助下,我们可以很容易地将这些频率数据设置为 0,除了 50Hz 和 120Hz。
yf_abs = np.abs(yf)
**indices = yf_abs>300 # filter out those value under 300**
**yf_clean = indices * yf # noise frequency will be set to 0**
plt.plot(xf,np.abs(yf_clean))
现在,所有的噪音都被消除了。
清理噪音,作者安德鲁·朱
逆回到时域数据
代码:
from scipy.fft import irfft
**new_f_clean = irfft(yf_clean)**
plt.plot(t,new_f_clean)
plt.ylim(-6,8)
结果表明,所有的噪声波都被消除了。
洁净的波浪,作者安德鲁·朱
转变是如何进行的
回到转换等式:
从时域到频域,也称为前向离散傅立叶变换或 DFT
原始时域信号由小写 x 表示。 x[n] 表示 n 位置(时间)的时域数据点。频域中的数据点由大写字母 X 表示。*X【k】*表示频率为 k 时的值
比方说,我们有 10 个数据点。
x = np.random.random(10)
N
应该是 10,所以n
的范围是 0 到 9,10 个数据点。k
代表频率#,其范围是 0 到 9,为什么?极端情况是每个数据点代表一个独立的正弦波。
n 和 k 的范围。
在传统的编程语言中,需要两个用于循环,一个用于k
,另一个用于n
。在 Python 中,对于循环,可以用 0 显式对操作进行矢量化(表达式 Python)。
而且 Python 对复数的原生支持也很牛逼。让我们建立傅立叶变换函数。
import numpy as np
from scipy.fft import fft
*def* DFT_slow(*x*):
*x* = np.asarray(*x*, *dtype*=float)# ensure the data type
N = *x*.shape[0] # get the x array length
n = np.arange(N) # 1d array
k = n.reshape((N, 1)) # 2d array, 10 x 1, aka column array
M = np.exp(-2*j* * np.pi * k * n / N)
return np.dot(M, *x*) # [a,b] . [c,d] = ac + bd, it is a sum
x = np.random.random(1024)
np.allclose(DFT_slow(x), fft(x))
与来自numpy
或scipy
的函数相比,这个函数相对较慢,但对于理解 FFT 函数如何工作已经足够了。为了更快地实现,请阅读杰克的理解 FFT 算法。
进一步的思考——不是总结
傅立叶变换所表达的思想是如此深刻。它提醒我,世界可能不是你看到的那样,你生活的世界可能有一个完全不同的新面貌,只有通过某种变换才能看到,比如傅立叶变换。
不仅可以转换声音数据,还可以转换图像、视频、电磁波,甚至股票交易数据( Kondratiev 波)。
傅立叶变换也可以用波生成圆来解释。
来自维基
大圈是我们的国家,我们的时代。我们作为一个个体是一个小小的核心圈子。没有那个驱动一切的大圈子,我们真的是做不到太多。
工业革命发生在英国而不是其他国家,不仅仅是因为采用了蒸汽机,还有许多其他原因。— 英国为什么先工业化。就是那个时候只存在于英格兰的大圈。
如果你很富有或者在某些时候、某些地方非常成功,这可能不全是因为你自己的优点,而很大程度上是因为你的国家、你周围的人或者你工作的好公司。没有那些驱使你前进的大圈子,你可能无法实现你现在所拥有的。
我对傅立叶变换了解得越多,我就越对约瑟夫·傅立叶感到惊讶,他在 1822 年提出了这个令人难以置信的方程。他永远也不会知道,在 21 世纪,他的作品现在到处都在使用。
附录—四种傅立叶变换
本文中提到的所有傅立叶变换都是指离散傅立叶变换。
《傅立叶变换的四种类型》,作者安德鲁·朱
当你坐在计算机前,试图用傅立叶变换做一些事情时,你只会使用 DFT——本文讨论的变换。如果你决定投身于数学沼泽,这里有两本推荐阅读的书:
- 频域和傅立叶变换。保罗·w·库夫的课本来自普林斯顿。
2.《数字信号处理》一书的第 8 章**——作者史蒂文·W·史密斯他们提供了在线链接: DSP Ch8**
参考
- 傅立叶变换互动指南:https://better explained . com/articles/an-Interactive-Guide-To-The-Fourier-Transform/
- 用 scipy.fft 进行傅立叶变换:Python 信号处理:https://realpython.com/python-scipy-fft/
- 了解 FFT 算法:http://jakevdp . github . io/blog/2013/08/28/understanding-the-FFT/
- 频域和傅立叶变换:https://www . Princeton . edu/~ cuff/ele 201/kulkarni _ text/frequency . pdf
- 用 FFT 去噪数据【Python】:https://www.youtube.com/watch?v=s2K1JfNR7Sc&ab _ channel = Steve brunton
- FFT 算法——简单的一步一步来:https://www.youtube.com/watch?v=htCj9exbGo0&ab _ channel = Simon Xu
如果你有任何问题,请留下评论,我会尽力回答,如果你发现了错误,不要犹豫,把它们标记出来。你们的阅读和支持是驱使我继续多写的大圈子。谢谢你。
带有匈牙利符号的更清晰的代码
原文:https://towardsdatascience.com/cleaner-code-with-hungarian-notation-49dfb1c88502?source=collection_archive---------13-----------------------
我最近开发的微生物组数据产品的 JSON 配置。记下文件名。
超越英语用语的限制,更好地组织和更快地解释你的工作。
前言
你还记得你什么时候学会了如何格式化日历日期进行字母数字排序吗?你或者有月首美国格式的日期,例如09–11–1991,或者有日首欧洲格式的日期,例如11–09–1991,并且你意识到排序不起作用。日期排序需要首先按年份进行,然后按月份进行,最后按月份进行,例如1991–09–11。
或者——您还记得您什么时候学习了更清晰的变量、方法和类命名的更好实践吗?也许当你看着别人的代码,却不知道变量 isOvrLn 是什么意思的时候,或者不知道名为 mkZro()的函数是什么意思的时候,就会发生这种情况;
哈!我本能地用分号结束了最后一句话。
无论如何,我在这里想说的是,从你认识到这些更好的编码实践的那一刻起,一切都变了。有时这个教训会产生如此大的影响,你不得不回去重构遗留代码,以帮助未来的读者和避免潜在的尴尬。
另一个类似的顿悟最近又发生在我身上——在我 20 年的编程生涯中。
匈牙利符号
这里有一个维基百科链接来复习一下——这是一个相对古老的概念,可以归结为你可能想用代码命名一个东西——例如变量、类、接口等等。—包括关于它是什么的信息,即它的类型。
匈牙利符号仍然有争议,所以在这篇文章中,我将关注我的一个特殊用例,以及为什么我认为它有效。
微生物组数据产品示例
在这里,我使用低代码 JSON 模板从源数据文件定义一个 Tag.bio 数据产品。您应该能够在不了解 Tag.bio 语法的情况下理解这些示例。
这个顶层文件 config.json 概述了创建数据模型所需的所有文件和函数。
注意我们是如何使用文件路径来引用嵌套代码的——包含表对象的文件以表 _ 为前缀,包含解析器对象的文件以解析器 _ 为前缀。
您可能会注意到,表目标文件已经位于一个名为表/ 的文件夹中,而解析器目标文件已经位于一个名为解析器/ 的文件夹中。那么,为什么会有冗余呢?
因为我并不总是通过文件的完整路径来查看文件。很多时候,我会在编辑器中将文件名单独作为一个标签来看。
这里,我们使用类型前缀来区分同一个gene familiesaspect的表目标文件和解析器目标文件。
此外,当查看我的 IDE 的资源管理器视图中列出的许多文件时,我希望直接从文件名中快速了解每个文件的用途,而不必通过视觉扫描来识别父文件夹。
为什么使用前缀和后缀?
这是它有助于远离英语的地方。在英语中,我们把形容词放在名词前面,例如大河。在许多其他语言中,形容词放在名词之后,例如西班牙语中的 el rio grande 。
鉴于本文中的代码——以及绝大多数已编写的代码——都是英文的,为什么我们决定将文件命名为table _ gene families . JSON而不是gene families _ table . JSON?这不是显而易见的。当我和我的同事谈到这些对象时,我们肯定会说“genefamilies 表”,而不是“genefamilies 表”。
我使用匈牙利符号前缀的理由——在这个特定的例子中是*——与 IDE 以及文件名如何组织、显示和排序有关。*
当您打开许多编辑器选项卡时,文件名通常会被截断。通过使用前缀,名称中最重要的部分——在本例中是类型——最后被删除。
在构建文件夹层次结构时,我们已经声明了每个对象的类型比方面更重要——即解析器被放入解析器/ 文件夹,而表被放入表/ 文件夹。
前缀不仅清楚地表明每个文件包含什么类型的对象,而且前缀的冗余性——在左侧水平对齐——也清楚地表明我正在查看哪个父文件夹。
确定我在解析器/ 文件夹中并查看解析器对象后,我可以沿着最右边的信息“列”垂直扫描,以确定我需要打开的特定文件——或者快速了解该文件夹中所有文件的范围。
值得注意的是,在 Tag.bio 中,我们已经为我们的 JSON 文件建立了一个约定,首先围绕类型,其次围绕方面进行组织。我们更喜欢嵌套更少的更宽的文件夹,并且在相同类型的文件之间有许多有用的代码复制/粘贴。开发人员更频繁地在多个表或多个解析器上工作,而在单个方面内工作的频率较低——例如 genefamilies 。
有时候后缀会更好
切换到一个不同的代码示例——因为我已经注意到在 Web 应用程序世界中,像 Angular 这样的框架已经迁移到代码主要由方面组织而不是由类型组织的惯例。
在这个来自 Tag.bio web 应用程序(Angular)代码库的示例中,我们围绕用户页面方面对文件进行分组,包括同一文件夹中不同类型的文件。在这里,带有后缀的匈牙利符号对于类型——即文件扩展名——是一个更好的选择。
Angular 社区意识到,开发人员经常处理与特定方面相关的文件,例如用户.组件,而较少处理与特定类型相关的文件,例如**。css** 。
仔细想想,文件扩展名可能是匈牙利符号中争议最小的形式。
这一切不是很明显吗?
那么,检查你的代码库,自己决定文件名是否足够清楚。另一个开发人员会仅仅通过阅读文件名来理解每个文件的用途吗?
感谢阅读!
用“看门人”包清理和探索数据
原文:https://towardsdatascience.com/cleaning-and-exploring-data-with-the-janitor-package-ee4a3edf085e?source=collection_archive---------17-----------------------
探索 clean_names()之外的功能
照片由 Pexels 的 Pixabay 拍摄
看门人包
《T2》看门人套装可在 CRAN 上下载,由山姆·菲尔克、比尔·丹尼、克里斯·海德、瑞安·奈特、马尔特·格罗塞和乔纳森·扎德拉创作。虽然可以说最出名的是它非常有用的 clean_names()函数(我将在本文的后面介绍),但是看门人包有大量的函数可以简化数据清理和探索。该软件包旨在与 tidyverse 兼容,因此可以无缝集成到大多数数据准备工作流中。我所参考的看门人软件包功能的有用概述可以在这里和这里找到。此外,以下引用的所有数据和代码都可以在GitHub repo中访问。
GNIS 数据
我们将在本教程中使用的数据来自地理名称信息系统(GNIS),这是一个由美国地名委员会创建的数据库。这个数据集出现在 Jeremy Singer-Vine 的 Data is Plural 时事通讯中,本质上是一个国内地名的可搜索目录。
为了下载数据,我们首先需要导航到查询表单:
我选择使用代表马萨诸塞州伯克郡地名的数据,这个地区包括我的家乡。为了创建该搜索,从州下拉菜单中选择“马萨诸塞州”,从县下拉菜单中选择“伯克希尔”。然后,点击“发送查询”按钮:
查询结果将如下所示。在结果表下方,单击“另存为管道”|“分隔文件”将数据保存到本地:
数据应该开始自动下载,并将出现在一个. csv 文件中,其特征由“|”分隔:
将这个 csv 文件保存到新 R 项目的“data”文件夹中。让我们将数据放入 R 中,将这些列分离出来,并执行一点修改,以便于我们的看门人包探索。首先,在一个新的 R Markdown 文件中加载 tidyverse 和看门人包。使用 read.csv()函数将数据作为“place_names”加载:
library(tidyverse)
library(janitor)place_names = read.csv("./data/GNIS Query Result.csv")
数据看起来应该和它在 Excel 中的样子差不多,一个巨大的列包含了我们所有的数据:
让我们来研究一下这个。首先,我们将名称“columns”分配给这个单独的列,以避免在代码中包含像默认列名称那样混乱和冗长的内容。接下来,我们使用 separate()函数将这一列分成它的所有组成部分。然后,我们将数据过滤到伯克希尔县,随着对数据的进一步检查,很明显,我们的伯克希尔县查询中包含了该县以外的一些条目。然后,我们在 mutate()步骤中稍微修改一下数据,以便以后整理它。str_replace()用于将 ID“598673”替换为数据集中已经存在的 ID 号“598712”,以便创建一个重复的 ID。最后,使用 NAs 在每行中创建了一个名为“extra_column”的额外列:
colnames(place_names) = "columns"place_names =
place_names %>%
separate(columns, c("Feature Name", "ID", "Class", "County", "State", "Latitude", "Longitude", "Ele(ft)", "Map", "BGN Date", "Entry Date"), sep = "[|]") %>%
filter(County == "Berkshire") %>%
mutate(
ID = str_replace(ID, "598673", "598712"),
extra_column = NA
)
在继续之前,让我们快速创建第二个名为“non_ma_names”的数据集,其中包含实际上并非来自伯克希尔县的条目。我们再次读入“GNIS 查询结果. csv”文件并分离出列名。然后,我们应用看门人包中的 clean_names()函数,这将在下一节中深入讨论。最后,我们在 mutate 步骤中使用 as.numeric()和 as.factor()将 ele_ft 变量转换为数字变量,将 map 变量转换为因子:
non_ma_names = read.csv("./data/GNIS Query Result.csv")colnames(non_ma_names) = "columns"non_ma_names =
non_ma_names %>%
separate(columns, c("Feature Name", "ID", "Class", "County", "State", "Latitude", "Longitude", "Ele(ft)", "Map", "BGN Date", "Entry Date"), sep = "[|]") %>%
filter(County != "Berkshire") %>%
clean_names() %>%
mutate(
ele_ft = as.numeric(ele_ft),
map = as.factor(map)
)
现在让我们看看看门人能做什么!
使用看门人
行名()
您可能已经收到了大量的数据文件,可能在。xlsx 表单,在实际数据开始之前,电子表格顶部有几行。这些行可以是空白的,也可以填充信息和公司徽标。当您将这些数据加载到 R 中时,这些前导行的内容可能会自动成为您的列标题和第一行。看门人包中的 row_to_names()函数允许您指出数据框中的哪一行包含实际的列名,并删除该行之前的所有内容。对我们来说很方便的是,GNIS 数据已经在正确的位置有了列名。不管怎样,让我们试一下,假设列名实际上在第三行。
我们使用 row_to_names()函数创建一个名为“test_names”的新数据帧。row_to_names()函数采用以下参数:数据源、列名应该来自的行号、是否应该从数据中删除该行以及是否应该从数据中删除上面的行:
test_names = row_to_names(place_names, 3, remove_row = TRUE, remove_rows_above = TRUE)
我们可以看到,第 3 行的信息现在构成了我们的列名。该行及其上方的行已从数据框中移除,我们可以看到数据现在从第 4 行开始:
虽然这个函数不是清理 GNIS 数据所必需的,但是它对于其他数据集来说肯定是很方便的!
清理名称()
这个函数是我几乎每次将新数据集加载到 r 中时都会用到的函数。如果您还没有使用这个函数,我强烈建议将它合并到您的工作流中。这是这个包中最受欢迎的功能,因为它非常有用!
tidyverse style guide 推荐对象名和列名使用 snake case(由下划线分隔的单词,如 this)。让我们花一点时间回顾一下我们的列名。有各种大写字母和空格(如“功能名称”、“BGN 日期”)以及符号(“Ele(ft)”)。clean_names()函数将把所有这些转换成 snake case。
使用 clean_names()非常简单,如下所示:
place_names = clean_names(place_names)ORplace_names =
place_names %>%
clean_names()
正如您在下面看到的,这个函数处理了数据集中出现的各种混乱的列名。现在一切看起来干净整洁:
移除 _empty()
remove_empty()函数,顾名思义,删除空的列。在准备数据时,我们在“place_names”数据框中创建了一个空列,因此我们知道至少有一列会受到此函数的影响。让我们试一试:
place_names =
place_names %>%
remove_empty()
如您所见,empty_column 已从我们的数据框中删除,只留下包含数据的列:
bgn_date 列看起来是空的,但是它没有被 remove_empty()删除的事实告诉我们,至少在一行中必须有数据。如果我们向下滚动,我们会看到事实就是这样:
移除常量()
remove_constant()函数删除所有行中具有相同值的列。我们的数据集目前有其中的两个,因为我们将数据过滤到了伯克希尔县,所有伯克希尔县都在马萨诸塞州内,所有行的 county = "Berkshire "和 state = "MA"。这些行保留在数据集中不是特别有用,因为它们不提供特定于行的信息。我们可以简单地使用 select()来删除这些列,但是 remove_constant()的好处是,这个函数可以对我们假设的所有条目都相同的情况进行双重检查。事实上,使用 remove_constant()是我第一次发现原始数据中 1968 个条目中有 38 个实际上不是来自伯克希尔郡!
像 remove_empty()一样,remove_constant()函数需要的所有信息都是它应该操作的数据集:
place_names =
place_names %>%
remove_constant()
正如您在下面看到的,县和州列已被删除:
compare_df_cols()
有没有试过使用 rbind()将两个数据帧堆叠在一起,却遇到意外错误?compare_df_cols()函数直接比较两个数据框中的列,对于解决这个问题非常有用。让我们通过将我们的“地名”数据框与我们创建的包含伯克郡以外条目的数据框“非马萨诸塞州名称”进行比较来尝试一下:
compare_df_cols(place_names, non_ma_names)
输出是一个比较两个数据帧的方便的表格。我们在地名中看到“NA”代表县和州,在非地名中看到“character”代表这些变量。这是因为我们用 remove_constant()从 place_names 中删除了这些列,但从未对 non_ma_names 中的默认字符变量做任何事情。在 non_ma_names 中,我们还将 ele_ft 视为数字,将 map 视为因子变量,这是我们在数据准备期间特别指定的。如果我们试图将这些数据框合并在一起,了解哪些列缺失以及哪些列在数据框中具有不一致的类型会很有用。在包含许多列的数据框中,compare_df_cols()可以显著减少进行这些比较所花费的时间。
get_dupes()
我经常从事具有唯一患者 id 的项目,您不希望在您的数据集中看到重复的 id。在很多其他情况下,您可能希望确保某个 ID 变量具有完全唯一的值,包括我们的 GNIS 数据。您应该还记得,我们在准备数据时创建了一个重复的 ID。让我们看看 get_dupes()是如何检测到这一点的。该函数只需要数据框的名称和作为标识符的列的名称:
get_dupes(place_names, id)
如下所示,数据框被过滤为 ID 列中有重复值的行,从而便于调查任何问题:
泰伯基()
tabyl()函数是 table()函数的 tidyverse 兼容替代函数。它还与 knitr 包兼容,对于数据探索非常有用。
让我们先用一个变量来试一下。假设我们对伯克郡的每个城镇有多少所学校感兴趣。我们首先将我们的类变量过滤为“School”,然后将 tabyl()函数用于我们的 map (location)变量。最后,我们将它输入到 knitter::kable()中,将输出格式化成一个漂亮的表格:
place_names %>%
filter(class %in% "School") %>%
tabyl(map) %>%
knitr::kable()
运行这个非常基本的代码块会产生下面的输出表:
当我们编织 Rmd 文件时,kable()函数将很好地格式化表格,如下所示。我们可以方便地得到每个城镇中学校的数量,以及该城镇中所有学校的百分比。很容易对这些数据进行观察,例如 29.5%的学校在皮茨菲尔德东部,那里有 41 所学校。或者这三个镇太小了,只有一所学校:
现在让我们试试两个变量的交叉列表。让我们看看每个城镇中有多少每种类型的地标:
place_names %>%
tabyl(map, class) %>%
knitr::kable()
我们的桌子的一部分(一旦编织)如下所示。对于每个城镇,我们可以清楚地看到每个地标类型在数据库中有多少:
虽然像这样简单的计数可能非常有用,但也许我们更关心列百分比。换句话说,每个城镇中每个地标类型的条目占多大比例?这很容易通过“装饰百分比()”函数用 tabyl()来研究:
place_names %>%
tabyl(map, class) %>%
adorn_percentages("col") %>%
knitr::kable()
现在我们看到的是这些列的百分比而不是计数,但是这个表很难阅读:
我们可以用 attear _ pct _ formatting()函数稍微清理一下,它允许用户指定输出中包含的小数位数。精度对于这个探索性的表不是特别重要,所以让我们使用 0 个小数位来使这个表更容易阅读:
place_names %>%
tabyl(map, class) %>%
adorn_percentages("col") %>%
adorn_pct_formatting(digits = 0) %>%
knitr::kable()
好多了!现在,阅读表格和理解我们的列百分比就容易多了:
使用 embody _ percentages()来查看行百分比(在我们的例子中,是属于每个地标类型的每个城镇的条目的百分比)同样简单:
place_names %>%
tabyl(map, class) %>%
adorn_percentages("row") %>%
adorn_pct_formatting(digits = 0) %>%
knitr::kable()
其他功能
在本文中,我描述了看门人包中的函数,我发现这些函数在我的日常工作中很有用。然而,这并不是看门人功能的详尽列表,我建议参考文档以获得关于这个包的更多信息。
也就是说,这里至少有几个其他函数值得注意:
- excel_numeric_to_date(): 该函数设计用于处理 excel 的许多日期格式,并将这些数字变量转换为日期变量。对于那些经常在 Excel 中处理数据的人来说,这似乎可以节省大量时间。作为一个不常使用 Excel 的用户,我非常依赖 lubridate 包来处理日期变量。
- round_to_fraction(): 此函数允许您将小数四舍五入为精确的分数分母。想要将所有值四舍五入到最接近的四分之一,还是使用小数来表示一小时中的分钟数?round_to_fraction()函数可能会对您有所帮助。
- top_levels(): 该函数生成一个频率表,将分类变量折叠成高、中、低三个级别。常见的用例包括简化李克特式秤。
结论
在这一点上,大多数数据分析师和数据科学家将大部分时间投入到数据清理和探索中,这是一个常识,因此,我总是发现新的包和函数可以使这些过程更加高效,这是一件令人兴奋的事情。
无论您以前是否使用过看门人包,我希望这篇文章已经向您介绍了一些函数,这些函数将被证明是对您的数据科学工具包的有用补充。
熊猫数据帧中 JSON 的清洗和提取
原文:https://towardsdatascience.com/cleaning-and-extracting-json-from-pandas-dataframes-f0c15f93cb38?source=collection_archive---------5-----------------------
包含 Github 回购
揭示 JSON 嵌入式专栏中隐藏的见解
照片由 Gerold Hinzen 在 Unsplash 上拍摄
我认识的一个人最近遇到了一个有趣的问题,我花了一分钟才弄明白。他们在 Kaggle 上发现了这些数据,其中包含嵌入了 JSON 的列。有多个这样的列,他们想从这些列中提取数据,并在同一个数据帧上表示它们。
让我们更详细地看看这个问题。这是一个数据的例子。
步骤 1:解码 JSON
JSON (JavaScript Object Notation)是大量信息在互联网上传输的方式。幸运的是,Python 标准库附带了一个名为json
的库。这意味着如果你已经安装了 Python,那么你就已经有了这个模块。如果您有兴趣了解更多信息,请查看文档!
通过导入json
包,我们可以将所有的 JSON 对象转换成它们各自的 Python 数据类型。Python 和 Pandas 不会明确地告诉你什么是 JSON,但是这通常很容易确定你是否在花括号({}
)中嵌套了数据,转换为str
类型。
下面是我写的将 JSON 解码成 Python 的代码:
步骤 2:跨多个列表示 JSON 数据
除非我们能从 JSON 中提取数据,否则我们所做的一切都没有用。为此,我创建了一个函数,它可以与熊猫 [apply](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html#pandas-dataframe-apply)
方法一起使用,并按行而不是按列应用(axis=1
)。
我的想法是对数据进行一次热编码,以保持一种整洁的格式。这意味着每行代表一个观察,每列代表观察的一个属性。
我为数据中看到的每个键和值创建了一个新列,如果在感兴趣的观察中看到了该键或值,则用1
表示,如果没有看到,则用0
代替。
代码如下:
让我们解释一下代码在做什么,首先我们循环遍历字典列表的长度,并创建一个列表来存储key:value
对。然后我们遍历每个字典,并使用[.items()](https://docs.python.org/3/library/stdtypes.html?highlight=dict%20items#dict.items)
提取key
和values
。.items()
将返回一个元组列表,其中第一个元素是key
,第二个元素是关联的value
。从这里开始,我们将把key
和value
加上一个下划线附加到我们的ls
对象上。
**# store values**
ls = []**# loop through the list of dictionaries**
for y in range(len(x[0])):**# Access each key and value in each dictionary**
for k, v in x[0][y].items():
# append column names to ls
ls.append(str(k)+ "_" +str(v))
接下来,我们将为在ls
对象中看到的key:value
对的每个组合创建一个新列。如果该列不存在,那么我们将创建一个具有关联名称的新列,并将所有值设置为0
,同时将当前观察值更改为1
。
**# create a new column or change 0 to 1 if keyword exists**
for z in range(len(ls)):**# If column not in the df columns then make a new column and assign zero values while changing the current row to 1**
if ls[z] not in df.columns:
df[ls[z]] = 0
df[ls[z]].iloc[x.name] = 1
else:
df[ls[z]].iloc[x.name] = 1
return
x.name
返回当前观察的指标。当axis=1
这将返回索引值,当axis=0
这将返回列名。在这里看文件。
步骤 3:应用函数
**# Loop over all columns and clean json and create new columns**
for x in json_cols:
df[[x]].apply(clean_json2, axis=1)print("New Shape", df.shape)
最后的想法
该代码返回一个超过 29,000 列的 DataFrame,需要很长时间来运行。在对所有数据进行测试之前,您可能希望对数据的子集进行测试。
在使用这段代码之前,您可以搜索每个 JSON 列,看看有多少惟一值。你总是可以将不太常见的值转换为“Other”来帮助加速运行。
现在你知道了,在 Pandas 中使用 JSON 数据并没有那么糟糕,只要有一点创造力,你就可以编写代码来实现你想要的任何东西。请随意调整代码,这样它就不会保存某些值或键。所提供的代码旨在作为您正在处理的任何 JSON 相关问题的样板。
在这里找到项目的代码。
在建模或分析之前,清理和准备 R 中的营销数据
原文:https://towardsdatascience.com/cleaning-and-preparing-marketing-data-in-r-prior-to-machine-learning-or-analysis-ec1a12079f1?source=collection_archive---------11-----------------------
实践教程
一个基本的、循序渐进的指南,帮助你清理 R 中典型的杂乱营销数据
照片由亚历山大·曾在 Unsplash 上拍摄
TLDR
本文着眼于在分析或输入 ML 模型之前处理 R 中杂乱数据的基本工作流程。具体来说,它将讨论:
- 正确导入 csv 数据
- 添加、删除和重命名列
- 识别独特性,处理重复的价值和 NAs
- 一致的大小写和格式
- 查找和替换字符串
- 处理不同的日期格式🙀!
- 将不同的数据集合并成一个
- 将每日数据转换为每周数据
- 将长数据转换为宽格式
我一直深入到基础,一步一步地帮助新的 R 用户一行一行地掌握 R。如果时间允许的话,我希望很快能把这变成一个关于营销组合建模的系列🤗!
挑战
在本练习中,我特意设置了以下挑战:
- 使用两个不同的数据集,这两个数据集都被认为是混乱的
- 尽可能坚持使用底座/默认 R
- 尽可能多地注释代码
让我们先解决这个问题:营销数据总是混乱的。
为什么?这是因为这些数据通常存放在多个平台上,有些在线,有些离线,全部由不同的团队、外部合作伙伴等管理。简直是遍地。
让我们举例说明:如果你是一名负责衡量数字营销活动有效性的分析师,你可能需要从 Google Analytics 收集网站表现数据,从 Search Ads 360 或 Tradedesk 收集广告表现数据,然后从 CRM 或 SQL 数据库检索客户数据及其订单。
接受会有不完整的数据。将会有 NAs 或许多丢失的值。将会有格式和结构问题。有些数据甚至可能不是你所想的那样(嘘!看到那个叫做“转换”的专栏了吗这不是收到的查询总数,实际上是衡量用户点击提交查询按钮的次数——查询是否成功是另一回事🙄。)
在我们可以在任何建模或分析中可行地使用这些数据之前,我们需要擦洗、清理和整理这些数据。我们开始吧!💪
与 R 中混乱的数据争论
数据集
在本练习中,我们将查看两个数据集:
- 一个是每日营销绩效数据,具有典型的指标,如日期、渠道、每日支出、展示、转化、点击等。我们可以假设这来自一个分析平台。
- 另一个是日常销售数据(订单 id、收入、税收、运输等)。我们可以假设这来自一个客户关系管理系统。
- 这两个数据集都可以被认为是杂乱的(你马上就会明白为什么!🤭)
👉你可以在这里访问 Kaggle 上的数据集。感谢 Firat,数据集所有者,感谢他让我在帖子中使用它!
使用基本/默认 R
我已经决定尽可能地坚持使用基地 R 。为什么?因为在使用尽可能少的 R 包时,我的目标是尽可能减少依赖。当你加载一个 R 包时,它有时也会在后台加载额外的库。这没有错,使用 R 的好处之一是我们可以在他人的工作基础上进行构建,并为社区做出贡献。然而,使用 base R,这里讨论的许多任务都可以简单地(有时同样快速地)完成。
也就是说,一些像 View()、str()、aggregate()、merge()这样的函数在技术上不是 base R,它们来自于已经默认加载的包(例如、等)。从这个意义上说,我们将把它们视为默认函数,并可以在这个挑战中使用它们。
另外,我真诚地认为,如果这是您第一次尝试使用 R,那么在直接进入 tidyverse 之前,学习 R 基础是很重要的。根据经验,我发现有 R 基础的基础非常有用。
尽可能多的评论
我将尽可能地对我的代码进行注释,一行一行地注释,以帮助新的 R 用户更容易了解这一点。注释代码也应该是很好的练习 btw!因为如果你要和你的团队共享代码模板,这有助于他们理解每个代码块或代码行的作用。
加载数据
我们有 2 个数据集。让我们下载这些 CSV,在 R 中加载它们,看看它们是什么样子的:
第一行主要使用 read.csv()函数读取文件,然后将其保存到名为 marketing_df 的数据帧中。
下一行中的 View() 函数(注意大写字母“V”)应该会打开 R 中的文件,这样您就可以查看它了:
呸!数据看起来乱糟糟的!CSV 文件可以用不同的分隔符保存。默认情况下,CSV 以逗号分隔(因此缩写为😉)但是这个是用分号隔开的,就像截图中的分号可以看到的。让我们再次加载数据,这次指定分隔符,如下所示:
好多了!我们现在可以看到每个值在各自的列中!
现在我们已经处理了营销数据,让我们获取订单数据并将其保存到名为 orders_df: 的数据帧中
很好,我们已经加载了两个数据集。显然,我们可以看到有工作要做,以清理他们。让我们首先处理营销数据集,然后我们将处理订单数据集。
清理营销数据
marketing_df 数据框架有许多有用的列。为了便于说明,假设我们只关心以下 3 列:
- 周期代码(第一列)
- 平台代码(第 4 列)
- 营销投资(第 7 列)。
我们将抓取这些列,并将它们保存到一个名为 marketing_df_clean 的新数据框架中。我们还想用更容易理解的名称来重命名这些列。
我们走吧:
所以我们把数据框从这里转了过来:
对此👇
我们将它保存到一个更小的数据框架中,名为 marketing_df_clean ,只有 3 列。查看数据,滚动并注意这些值是如何显示的。你会注意到几件事:
- 日期很奇怪。我的意思是,我们当然认识到它们是日期,但它们也可能被 R 解读为其他任何东西。我们需要将它们标准化成合适的日期格式。
- 通道列中的值有各种大小写。让我们将它们都强制转换为小写,以保持一致。
还有一些价值需要更新,这就是**领域知识派上用场的地方:**由于付费媒体已经被定义(如脸书、Adwords),那么“非付费”可以被视为“有机的”。“未跟踪”可能意味着“直接”,而“silverpop”是一个电子邮件平台,因此可以重命名为“电子邮件”。 - 如果您仔细查看支出列,您还会注意到值是用逗号分隔的。例如 20,29。
您可以通过运行以下代码行来检查 R 是如何读取这些值的:
str(marketing_df_clean)
这个 str() 函数向您展示了 R 如何查看 R 对象的内部结构,在本例中是一个包含 3 列的数据帧:
这个输出显示,R 错误地将日期列读取为整数,而不是格式日期。花被读作文字是不正确的!花费应该是数字。这可能是因为数字之间的逗号导致它被读为文本。
基于以上所述,我们知道我们需要做以下工作:
- 设置日期列的格式,以便将其正确识别为日期。不幸的是,日期格式化真的很麻烦😡。因此对于这一部分,我将使用奇妙的包将这些日期强制转换成正确的格式。公平地说,我认为这是我在这个练习中使用的唯一一个非基本/非默认包。我们将最后安排日期。
- 强制频道列中的所有文本值小写
- 一旦小写,检查通道列,查看所有可能的唯一值
- 选择我们想要重命名的频道
- 最后,确保花费一栏被识别为数字。
这是:
注意:是的,我经常使用 str()、View()和 head(),我建议你也这样做。它帮助我检查我没有在争论中损坏我的数据。
然后,用 StatQuest 的乔希·斯塔默的睿智的话来说:
嘭!!!💥
你可以在 r 中点击来排序你的表,你也可以过滤和搜索。
日期现在可以正确格式化并被识别。花费现在被正确地识别为数字。我们在做生意!!
呃,实际上不完全是。再次查看数据-似乎有重复的行(例如,同一个频道,同一天)。
还没有脱离险境
我们要确保每天只有一个渠道,支出是该渠道在这一天的总支出。回想一下,我们之前已经删除了不需要的其他列。这些列用于进一步细分数据(例如,按桌面或移动设备)。当我们删除这些列时,我们需要记住按渠道合计当天的支出。
aggregate() 函数很好地完成了这一任务:
marketing_df_clean <- aggregate(spend ~ date + channel, data = marketing_df_clean, sum)
这给了我们一张漂亮的桌子,像这样:
每天按渠道列出的总支出。没有重复。
耶!我们现在已经获得了每个频道每天花费的清晰数据集。
清除订单数据
现在,让我们执行与上面相同的步骤,但是这次使用的是订单数据。为了提醒我们自己, orders_df dataframe 看起来像这样:
在本练习中,我们只关心 createdAt(第 2)、platformCode(第 4)和 revenue(第 18)列。
还要注意,日期后面附加了这些时间戳。在使用将日期格式化为我们之前使用的一致的年-月-日格式之前,我们需要先去掉这些内容。
除此之外,我们可以对订单数据使用与营销数据相同的工作流程,如下所示:
这应该会产生这个干净的表:
r 还将日期列识别为日期格式,收入是数字。订单数据现在完成了!对营销和订单数据进行排序后,我们现在可以将它们转换成每周数据集。
将每日数据转换为每周数据
将每日数据集转换为每周数据集有很多原因。在营销组合建模和数字营销的一般预测中,通常使用每周数据,因为并非所有渠道都能在同一天对销售产生直接影响,转化可能发生在最初印象后的第二、第三或第四天。
我们可以在 r 中很容易地做到这一点
- 首先,我们将创建一个名为“week”的新列。这将表示日期所在的一年中的第几周。例如,2020 年 3 月 15 日是 2020 年的第 11 周。(我发现这个网站真的很有助于快速查周。)
- 然后我们将创建一个名为“monthyear”的新列。对于日期 2020–03–15,month year 将输出“03–2020”。
- 我们将对营销和订单数据都这样做👇
你现在应该有 2 个新的数据帧。
市场营销 _ df _ 周刊:
和 orders_df_weekly:
如您所见,这些值还没有按周进行聚合和求和。我们只是在每个数据帧中引入了 2 个新列来告诉我们每个特定日期属于哪一周。
接下来,我们将把营销和订单数据连接到一个数据框架中,我们称之为 weekly_df 。我们使用 merge() 函数来实现这一点:
weekly_df <- merge(marketing_df_weekly, orders_df_weekly)
View(weekly_df)
使用上面的代码行应该会得到这个结果👇—每天按渠道列出支出和收入的表格。“星期”和“月份”列显示了日期所属的星期数和月份。
现在,我们可以按周汇总支出和收入,如下所示:
- 按渠道合计每周所有支出。将其保存到名为 weekly_spend_df 的数据帧中
- 按渠道汇总每周所有收入。将其保存到名为 weekly_rev_df 的数据帧中
- 获取每周的第一天,将该列称为“weekdatestart”并保存到名为 weekly_df_dates 的数据帧中。移除任何重复的行。
- 将这 3 个数据帧合并成一个干净的每周聚合数据帧,称为 weekly_df_updated 。
太棒了。您现在应该会得到如下所示的数据帧:
坚持住!你注意到这有什么奇怪的吗🤔?
顾名思义,totalrevenuefortheweek 是该周的总收入,定义如下:
weekly_rev_df <- aggregate(revenue ~ week, data = weekly_df, sum)
然而, weeklyspend 指的是给定一周特定渠道的总支出*,定义如下:*
weekly_spend_df <- aggregate(spend ~ week + channel, data = weekly_df, sum)
从上表可以看出,从 2020 年 1 月 2 日开始的一周,在“adwords”上花费 70,326.29 英镑产生了 1,513,643 英镑的收入。在同一周内,在“heurekacz”频道上花费 262.32 英镑获得了另外 1,513,643 英镑的收入!诸如此类。
👎这当然是不正确的!
我们想要展示的是,在给定的一周内,在 adwords、电子邮件、rtbhouse 和其他渠道上的支出的综合表现,在该周总共产生了 1,513,643 英镑的收入。
为了正确理解这一点,我们需要将这种长数据格式转换为宽数据格式。
将长数据转换为宽数据
将长数据转换成宽数据非常简单,反之亦然!基本的 reshape() 函数让你在一行代码中就能做到,就像这样:
*weekly_reshaped_channel <- reshape(weekly_df_updated, idvar = c("weekdatestart","totalrevenueforweek"), timevar = "channel", direction = "wide")*
当您查看(weekly _ reshaved _ channel)时,您应该会看到下表:
这更有意义,因为您可以看到每周实现的总收入和该周每个渠道的支出!
处理 NAs
您可以使用 print() 查看控制台中的数据并检查 NA 值。或者,如果您喜欢像我们在本练习中所做的那样,以电子表格的方式查看它,只需使用 View()即可:
如果检测到 NAs,您可以使用 is.na() 将 NA 值替换为 0,如下所示:
*#view the data and check for NA or missing values
print(weekly_reshaped_channel)#if found, replace any NA with 0
weekly_reshaped_channel[is.na(weekly_reshaped_channel)] <- 0#check
str(weekly_reshaped_channel)
View(weekly_reshaped_channel)*
结束了
👏干得好,一直到最后!我们终于得到了我们需要的数据集,我们可以用它来执行以后的建模。
完整的 R 代码
👉从我的 Github repo 这里获取完整的 R 代码。
我希望这篇文章对你有所帮助。毫无疑问,有更快更好的方法来达到同样的最终结果,但这篇文章的目的是深入基础,帮助新的 R 用户掌握 R。如果你做过类似的练习,并找到了更好的方法,请在评论中分享🤗!
我还想在下一篇文章中继续使用同样的数据来制作营销组合模型。我们会看到的。TTFN!
通过构建 NLP 管道清理和预处理文本数据
原文:https://towardsdatascience.com/cleaning-preprocessing-text-data-by-building-nlp-pipeline-853148add68a?source=collection_archive---------6-----------------------
用 python 处理文本数据的完整演练
艾莉娜·格鲁布尼亚克在 Unsplash 上的照片
有一段时间,我在处理文本数据,我意识到在当今世界,有必要知道自然语言处理是如何工作的,以及为了从文本数据中获得洞察力需要涉及的主要步骤。
众所周知,为了从数字数据中获得洞察力,我们可以应用许多统计学和数学。
但是说到文本数据的繁琐形式,我们在很多地方都缺乏。
什么是 NLP 文本预处理?
NLP 文本预处理是一种清理文本的方法,目的是使文本可以提供给模型。文本中的噪音有多种形式,如表情符号、标点符号、不同的大小写。所有这些噪音对机器都没有用,因此需要清理。
为什么 NLP 文本预处理很重要?
重要性:
经过适当清理的数据将有助于我们进行良好的文本分析,并帮助我们对业务问题做出准确的决策。因此,机器学习的文本预处理是一个重要的步骤。
在我让你们了解 NLP 文本预处理的主要步骤之前,我想说的是,你们可以根据自己的数据和需求增加或删除一些步骤。
在本教程中,我几乎不会给你任何步骤的定义,因为互联网上有很多。相反,我将解释为什么您应该应用特定的步骤,如何使用 python 进行文本预处理,我在每个步骤中理解了什么,以及我的数据集的结果是什么。
好吧!!说够了。现在让我们深入研究代码。😄
库&所需的文本预处理工具:
*# Importing Libraries*
**import** **unidecode**
**import** **pandas** **as** **pd**
**import** **re** **import** **time**
**import** **nltk** **from** **nltk.corpus**
**import** stopwords
nltk.download('stopwords')
**from** **nltk.tokenize** **import** word_tokenize
**from** **nltk.stem** **import** WordNetLemmatizer
**from** **autocorrect** **import** Speller
**from** **bs4** **import** BeautifulSoup
**from** **nltk.corpus** **import** stopwords
**from** **nltk** **import** word_tokenize **import** **string**
读取数据集:
*# Read Dataset* Df = pd.read_csv('New Task.csv', encoding = 'latin-1')
*# Show Dataset*
Df.head()
以下是一些文本预处理步骤,您可以根据您拥有的数据集添加或删除这些步骤:
步骤 1:移除换行符&标签
您可能会在文本数据集和选项卡中无缘无故地遇到许多新行。因此,当您抓取数据时,网站上结构化内容所需的换行符和制表符在您的数据集中是不需要的,并且还会被转换为无用的字符,如\n,\t。因此,我编写了一个函数来删除所有这些无意义的内容。
步骤 2:剥离 HTML 标签
当您抓取数据时,如果您在抓取时没有处理它,您可能会在数据集的文本中看到 HTML 标记。因此,有必要在以后处理这些标签。在这个函数中,我删除了文本中所有匹配 HTML 标签的内容。
步骤 3:移除链接
这一步将删除所有与任何类型的超链接相似的内容。我在这里添加了这个函数,因为我已经在数据集上处理了它。
第四步:删除空白
如下所述,可以执行单行功能来移除额外的空白。在执行进一步的 NLP 任务之前,这一步至关重要。
自然语言处理文本预处理的主要步骤是什么?
下面列出的文本预处理步骤非常重要,我已经按顺序写了所有这些步骤。
第一步:删除重音字符
这是将所有类似重音字符的字符转换成机器可理解语言的关键一步。以便可以容易地实施进一步的步骤。重音字符是指字符上方有音调符号的字符,如“、”或“”。
步骤 2:案例转换
这是系列中真正重要的下一步,因为 case 是机器的两个不同的词。因此,您应该将文本的大小写转换为小写或大写才能继续。
步骤 3:减少重复字符和标点
这一步很重要,因为可能会出现字符重复过多的情况,这是拼写检查器无法检测到的。因此,在应用拼写检查功能之前,需要预先处理这种情况。我在工作中还会遇到另一种情况,也可能会出现重复的标点符号。所以也需要遇到他们。
当我们非常兴奋时,我们确实会覆盖那些让读者不知所措的东西。
示例:- Cheeeeeerrrrrrss!!!!!!
在上述正则表达式中使用某些符号的说明
\1 →相当于重新搜索(…)。组(1)。它指的是第一个捕获组。\1 匹配与第一个捕获组匹配的完全相同的文本。
{1,} →这意味着我们正在匹配出现不止一次的重复。
DOTALL - >它也匹配换行符,不像点运算符那样匹配给定文本中除换行符以外的所有内容。
sub() →此函数用于用另一个子字符串替换特定子字符串的出现。该函数将以下内容作为输入:要替换的子字符串。要替换的子字符串。
r'\1\1' →将所有重复限制在两个字以内。
r'\1' →将所有重复限制为仅一个字符。
{2,} →表示匹配出现两次以上的重复
第四步:扩张收缩
为了在下一步中删除停用词,首先处理缩写是至关重要的。缩写只不过是诸如“不要”、“不会”、“它是”等词的速记形式。宫缩是任何类似这些例子不要,不会,它的。
步骤 5:删除特殊字符
在这一步中,我们将学习如何删除特殊字符,为什么要删除它们,以及应该保留哪些特殊字符。
所以,我写了一个函数,它将删除一组指定的特殊字符,并保留一些重要的标点符号,如(,。?!)不包括括号。特殊字符应该被删除,因为当我们要对文本进行标记时,以后,标点符号不会以更大的权重出现。
从文本中删除数字:
您所需要做的就是修改给定的正则表达式
Formatted_Text = re.sub(r"[^a-zA-Z:$-,%.?!]+", ' ', text)
只需排除 0-9 范围,以便从文本中删除所有数字表示。我没有在我的数据集上执行这一特定步骤,因为这些数字对我的情况非常重要。
根据我的数据集,我正在考虑的标点符号很重要,因为我稍后必须执行文本摘要。
,。?! →这是一些经常出现的标点符号,需要保留下来,以便理解文本的上下文。
: →根据数据集,这个也很常见。保持是很重要的,因为每当出现像晚上 9:05 这样的时间时,它就有了意义
这个词也经常出现在许多文章中,更准确地讲述数据、事实和数字。
$ →这个用在很多考虑价格的文章里。因此,省略这个符号对那些只剩下一些数字的价格没有太大意义。
步骤 6:移除停用词
如果您正在执行标记化、文本摘要、文本分类或任何类似的任务,则应该删除停用词。如同没有停用字词一样,您可以理解呈现给您的文本数据的上下文。需要移除它们以减轻它们的重量。
你应该考虑这一步删除停用词,因为它不适合我的进一步分析。正如我在生成 n-gram 时发现的那样,有停用词的文件往往比没有停用词的文件给出更可靠的结果。
步骤 7:纠正拼写错误的单词
尝试这一步时,你应该非常小心。因为这个功能可能会改变单词的真正含义。所以你必须非常小心,试着看看在应用这个函数时事情是如何发展的。如果您正在处理一些特定于行业的数据集,那么您可能需要考虑关联字典,该字典明确地告诉该函数保持那些特定的单词不变。
步骤 8:词汇化/词干化
在这一步,我将准确地谈论两件事,词汇化和词干化。
人们对这两种技术感到困惑,比如哪一种更有效,该用什么。那么,让我告诉你我的经历,我喜欢什么,为什么?
因此,这两种技术实际上都将单词修整为其词根形式,就像 Planning 将被修整为 plan,但词干不会在单词“Better”的情况下工作,而如果您应用词汇化,它会将单词转换为其词根形式,即“good”。这是一个主要的区别,即 Lemmatization 工作效率高,我只在工作中使用过它。
虽然我已经写了这个函数,但是经过进一步的分析,我发现它的性能并不好,反而产生了噪音。因此,在对一些令牌进行位分析时,我意识到最好不要应用术语化。
例如:-有一个词“饲料”,这是频繁出现在所有的文章,这也是非常重要的。但是在词条化上,“饲料”→简化为→“饲料”。你可以看到它是如何改变了它的整个含义。
主要调查结果:
数据清理步骤完全取决于数据集的类型。根据数据,可以包括更多的步骤。必须删除多余的空间以减小文件大小。
结论:
这些是我在对文本数据进行预处理时一直考虑的一些重要步骤。如果您也必须处理文本数据,您可以利用共享的代码,或者不要忘记让我知道您是否尝试了其他方法来清理文本数据。这些步骤是特定于我所使用的数据集的,所以在方便的时候可以随意添加或删除它。
您还可以访问完整的 Github 资源库,其中包含一系列实现中的所有步骤,并附有简要说明。
https://github.com/techykajal/Data-Pre-processing/blob/main/Text_Preprocessing.ipynb
干杯!!你已经坚持到最后了。😉
所以,如果我的博客帖子对你有所帮助,而你此刻觉得很慷慨,请不要犹豫,请给我买杯咖啡。☕😍
是的,点击我。
And yes, buying me a coffee **(and lots of it if you are feeling extra generous)** goes a long way in ensuring that I keep producing content every day in the years to come.
您可以通过以下方式联系我:
- 订阅我的 YouTube 频道 视频内容即将上线 这里
- 跟我上 中
- 通过 LinkedIn 联系我
- 跟随我的博客之旅:-https://kajalyadav.com/
- 成为会员:https://techykajal.medium.com/membershipT21
也可以看看我的其他博客:
</8-ml-ai-projects-to-make-your-portfolio-stand-out-bfc5be94e063> </15-free-open-source-data-resources-for-your-next-data-science-project-6480edee9bc1>
清理 GitHub(用于数据科学)
原文:https://towardsdatascience.com/cleaning-up-github-for-data-science-d6b2dabca3cb?source=collection_archive---------16-----------------------
保持您的存储库数量易于管理
呀。图片作者。
你使用 GitHub 已经有一段时间了,也许你开始注意到你的存储库页面(pages???)比以前丰满了。也许,事实上,它变得如此之满,以至于它更像是一个代码转储,而不是一个有意义的代码集合。在写这篇文章的时候,我的 GitHub 明显属于前一类(是的,那就是我),感觉是时候改变这种情况了。
毕竟,在许多方面,你的 GitHub 是你向世界其他地方展示的编码面孔,因此,你希望它(如果不是通过 GitHub 的网站设计,而是通过对人类精神的设计)部分是作品集,部分是诗歌,部分是可视化,部分是对话——但完全整洁,记录良好,易于导航。
据我所见,有五种主要的方法来清理你的存储库:
- 删除旧的存储库
- 在 Github 上模仿一个目录式的架构:
- 子树/子模块
- 项目
- 组织
策略 1:删除旧的存储库
我们现在都已经读过《T2》了,对吗?浏览你的每一个储存库,问你自己,“这能激发快乐?”如果没有,就把它处理掉。
环顾网络,这是一个令人惊讶的受欢迎的选择。你一下午就完成的 Udemy 课程的知识库?摆脱它。你几个月或几年没做的事?摆脱它。我承认,这个选项可能会触发我的强迫症(“如果我以后需要这个生成猫的 GAN 怎么办?”),但这是你清除 GitHub 的第一站。也许浏览一下你所有的存储库,特别是如果它们和我的一样有数百个,问问你是否真的需要它们。也许你可以放走一些。
来自giphy.com
来自imgur.com
这种方法有一个潜在的缺点。嗯,两个。第一,代码不见了,第二,如果你删除了一个给定的库,那么在你的贡献图上显示的任何东西都会消失。如果这令人不安,考虑一些替代方法来重新填充你的贡献图
策略 2:模仿目录结构
Github,从它的概念来看,提供了相对简约的结构。它缺少真正的目录或文件结构。例如,我的 339 个知识库中的绝大多数来自 Flatiron School 的数据科学训练营,但我不能把它们都放在一个“Flatiron”文件夹中,因为 GitHub 天生就没有这种结构。虽然有许多模仿这种结构的选择,但工具的原始目的需要不同程度的低劣化。
子树(可能还有子模块)
出于清理存储库页面的目的,我认为 subtree 是两者中的赢家,但我肯定有人会更好地使用git submodule
。关于这两者区别的详细讨论,请阅读这里的、这里的和这里的,但主要区别是:
- 子模块在外部存储库内留下一个指针,指向内部存储库中的一个特定提交(它不会像我们想象文件在文件夹内移动那样将内部存储库移动到外部存储库内)并且在 git 中有一个明确的命令
git submodule
,这使得设置很容易,但之后很难维护; - 另一方面,子树实际上将内部回购的代码移动到外部回购中,就像将文件移动到文件夹中一样,但它在 git 中没有默认命令,这使得设置起来有点困难,但之后更容易维护。
如果试图在数百个回购中利用这两种方法的结构,它们会很快变得耗时,但你会得到你的贡献图。
项目
仅仅从名字上看,这一个听起来很有前途——当听到这个名字时,我的直觉是“我将多个存储库组合在一个项目下”——但是它有一个更接近于待办事项列表的功能,用于跟踪问题、拉请求和注释。尽管如此,我还是听说有人使用这个特性来组织存储库(每个项目最多 5 个 repos)。
组织
这个对我来说是赢家。您可以创建组织来对 repos 进行分组,它 1)从您的存储库页面中删除 repos,2)列出组织名称。因此,从这个重要的角度来看,这可以说是 GitHub 上最接近于模仿目录结构的了。看起来是这样的:
左下角用红色圈出的新组织。图片作者。
组织的悬停效应。图片作者。
将鼠标悬停在它上面,它会提供关于该组织的一些信息。在图中,它仍然显示我有大约 300 个存储库,但这是因为我还没有将其中的大部分转移到新的组织中。将存储库转移到组织中,即使是您拥有的组织,也会从您的个人资料页面上的存储库列表中删除该存储库,并从您的贡献图中删除对这些存储库所做的任何贡献。对我来说,这是一个很小的代价,可以让我有一个很好的地方把这 300 个存储库藏在一起,看不见,但我确信对一些人来说这是两个世界中最糟糕的:回购仍然存在,我失去了贡献图。
更好的例子,请看安德烈·乔阿拉的文章。
一旦你清理了你的 GitHub 档案,我认为考虑如何更好地构建你的 GitHub 是一个好主意。最好的方法之一就是看看其他人是如何组织他们的。你可以从这里开始,看看一些漂亮的数据科学投资组合的例子。我个人最喜欢的是汉娜·韩嫣的 GitHub 和个人网站。她将存储库的数量保持在 20 个以内(尽管她有更多的项目),并且由于智能回购名称和描述,很容易找到它们。
对于任何一个刚刚开始在 git 仓库之外运作的技术训练营的人来说,我的建议是只去那些你付出了原创努力的实验室(大约 10 秒,而不是 100 秒的回购),或者在 GitHub 上从一开始就建立一个组织来学习所有这些课程。
清晰存储:存储面部图像保留政策的伦理
原文:https://towardsdatascience.com/clear-storage-the-ethics-of-deletion-policies-for-stored-facial-images-a1748b0fe950?source=collection_archive---------18-----------------------
2021 年春天,华特·迪士尼世界测试了面部识别软件,旨在将客人的面部与他们的公园预订联系起来,引发了一场关于数据所有权的隐私辩论
由马库斯·斯皮斯克在 Unsplash 上拍摄的照片
虽然面部识别的话题令人不安,但听到它在一个与儿童般天真无邪相关的地方应用,对那些担心迪士尼公司侵犯他们隐私的人来说,尤其不和谐。应该指出的是,在迪士尼的案例中,对面部扫描仪感到不舒服的客人可以选择侵入性较小的门票扫描,并且没有关于该技术以非自愿方式实施的报告。
选择加入?
然而,并非所有公司都允许客户选择不收集面部数据。7 月,The Verge 报道称 Lowe's、Macy's 和 Ace Hardware 目前都在使用面部识别算法,而麦当劳、沃尔格林甚至 7–11 都在考虑未来使用面部识别。虽然这听起来很可怕,但这种做法并不违法,因为面部识别技术在美国和世界大部分地区都不受监管。虽然面部识别的立法被忽视了(目前),但有一个关于长期数据保留的更大的辩论正在激烈进行。当一起讨论时,很明显,动态或静态面部图像的长期存储对任何规模的组织都提出了道德和基础设施的困境。
数据常被比作石油;然而,与化石燃料不同,数据是一种可再生资源。它不需要被无限期地存储和访问才是无价的。
欧盟保留:被遗忘的权利
对于总部位于美国的公司来说,制定数据保护和保留政策目前是可选的,但加利福尼亚州除外,在加利福尼亚州,企业受加利福尼亚州消费者隐私法(CCPA)的约束,应用户的要求披露数据。对于在欧盟运营或影响欧盟用户的公司,数据透明是强制性的。《通用数据保护条例》( GDPR)没有规定公司被允许存储客户数据的时间期限。然而,它确实包括了具体的数据保留指南,并且是目前为止关于这个主题最全面的资源。几个亮点:
- 公司不得将个人数据保留超过他们需要的时间
- 公司必须能够证明他们为什么保存数据
- 公司需要建立保留期的政策
- 公司必须对他们如何使用数据进行定期审查
- 只有在符合公共利益的情况下,公司才能长期保留数据
最后,GDPR 向欧盟公民保证,他们对自己的数据拥有最终所有权,包括被遗忘的权利:
如果您不再需要数据,个人有权擦除数据——一般数据保护法规(GDPR)
斯蒂芬·菲利普斯-Hostreviews.co.uk 在 Unsplash 上拍摄的照片
图像和隐私无法扩展
然而,值得注意的是,这些定律通常应用于结构化的、基于文本的数据,而不是非结构化的图像数据。就基础设施而言,图像文件通常比文本文件大几十倍或几百倍,使用谷歌或亚马逊等公司提供的基于云的数据库来存储图像文件,公司每月将花费更多的成本,特别是因为谷歌按千兆字节收取活动存储费用。最重要的是,虽然存储方法可以用于较小的数据库,但扩展数百万图像文件的存储可能是一个基础架构挑战。
基础设施和成本可以预测和调整;决定存储一些可以收集的最私人的数据的道德性,一个人的脸,在服务器上多年,涉及数据相关领域内外的那些人。十年前,医学成像领域的研究人员在云计算出现之前就面临这些问题。甚至在谷歌云产品等基于云的服务器广泛使用之前,这些人就认识到了在将图像数据批量或流式传输到异地服务器之前存储和加密图像数据的挑战。
由托拜厄斯·图利乌斯在 Unsplash 拍摄的照片
建立一套清晰的道德准则可以帮助人工智能开发者和商业领袖确定如何以平衡他们收集数据的权利和消费者隐私权的方式构思、测试和部署面部识别。非营利组织隐私论坛的未来建议,利用面部识别的组织必须关注隐私原则,如同意、数据安全和透明度。然而,对于这些数据的长期存储,却没有明确的指导方针。因此,出现了许多伦理难题,特别是在从弱势群体中收集面部数据方面。
例如,这里有一个假设:公司应该有权收集、利用和无限期存储从未成年人那里收集的面部图像数据吗?
在一个父母对在社交媒体上发布他们年幼孩子的照片持谨慎态度的时代,公司可以捕捉并永久存储他们的面部图像这一事实是一种令人担忧的边缘反乌托邦思想。
被遗忘的辩论
有时候,似乎唯一与数据科学相关的伦理争论是负责任的人工智能设计和使用。当谈到面部识别时,对模型偏差和数据集缺乏多样性的担忧是可以理解的,也是认可的。坦率地说,这些都是相关的、有趣的讨论。诚然,数据保留并不是一个令人兴奋的话题。然而,随着越来越多的网站和应用程序兜售选择退出功能,技术公司和数据科学家将不得不应对的一个问题是:我们是否在道德上采购、处理和保护我们的数据?
照片由伯纳德·赫曼特在 Unsplash 上拍摄
慢慢地,我们开始看到公司,尤其是 FAANG 公司,解决这个问题。最近,谷歌更新了其 BigQuery 数据库产品以包括数据到期参数,以阻止用户保留数据超过合理的时间范围。谷歌本身正在带头努力改革数据保留政策。2020 年,谷歌宣布将在 18 个月后开始自动删除位置历史、网页历史和语音记录。谷歌在其新的数据保留政策中包括非结构化个人身份信息(PII)数据,如录音,这一事实应该为组织如何存储敏感的多媒体数据提供一些先例。
对于在数据行业工作的任何人,包括我自己,虽然我们没有任何希波克拉底誓言,但有一个隐含的责任是从道德上访问、操作和存储数据。限制存储能力或监管行业的想法不一定是可怕的想法。相反,对 PII 数据收集的监管,可以让企业建立、甚至在某些情况下重新赢得用户的信任,这些用户习惯于交出自己的信息,希望有人在后台考虑他们的最佳利益。
基于离散策略梯度算法的悬崖行走问题
原文:https://towardsdatascience.com/cliff-walking-problem-with-the-discrete-policy-gradient-algorithm-59d1900d80d8?source=collection_archive---------19-----------------------
用 Python 实现了一个完整的增强算法。手动执行这些步骤来说明该过程的内部工作原理。
詹妮弗·卡佩尔在 Unsplash 上的照片
教科书上的悬崖行走问题继续引人入胜。虽然非常简单,但它阐明了强化学习算法的许多有趣的方面。在处理了一些基于价值的实现(这里是 SARSA 和 Q-learning,这里是深度 Q-learning)之后,现在是时候转向基于策略的实现了。尽管现在有很多库,我们还是用 Python 手动实现了这个过程,来演示离散策略梯度算法背后的机制。最后,我们与 SARSA 进行了面对面的比较。
悬崖行走问题
先把问题勾勒出来。我们的世界是一个相当全面的网格,除了应该避免的致命悬崖。代理从悬崖的左手边开始,目标(代理不知道)在右手边等待。目标是找到到达目标的最短路径而不坠入悬崖,这直接结束了这一集。
悬崖世界[图片由作者提供]
存在各种强化学习解决方案。本文主要讨论策略梯度算法。简单地说,策略告诉代理在给定状态下做什么——比计算和利用对应于每个动作的值函数更直接。在此设置中,您可能倾向于将策略视为一个表格,其中列出了 48 个图块中每个图块的最佳操作。
不过这有点复杂,因为这种方法依赖于随机策略。策略不是简单地告诉我们最好的行动,而是提供了我们应该采取每个行动的概率。不涉及太多细节,随机政策通常在未知环境中是有意义的,并为探索提供了一种内置机制。不良行为的概率应该趋近于零。
离散策略— Softmax 函数
是时候正式制定政策了。我们使用一个 softmax 策略,它有效地将任何一系列真实值映射到一系列概率。作为输入,它需要一个特征向量和一个相应权重的向量。
作为特征向量 *ϕ(s,a,*我们定义了一个 48⋅4 向量,每四个元素代表任何给定瓷砖上的移动——本质上是一个查找表(或者可以使用后决策状态方法,只需要 48 个特征,但丢失了细节)。该向量是一位热编码的,这意味着我们有一个具有 191 个 0 和 1 个 1 的向量,对应于状态 s 中的动作 a 。如前所述, θ 是一个权重向量,每个 (s,a) 对一个。 ϕ(s,a) 和 θ 的点积捕捉了位于特定瓷砖上的值,与众所周知的 q 值相当。
现在,我们可以将 softmax 策略形式化如下:
Softmax 政策。
ϕ(s,a)^⊤ θ越大,a采取行动的概率越高。用正常的语言来说:我们很有可能采取措施,让我们更接近目标。但是在我们知道这些步骤之前,我们首先需要了解政策。
离散政策梯度
定义了策略本身之后,让我们来看看如何更新它。这就是政策梯度定理的用武之地。为了保持文章的范围,我们将自己限制在权重更新过程中:
策略梯度方法的更新功能
这里的 α 简单来说就是学习率。奖励函数 G_t 也很简单:
累积奖励函数
主要的挑战在于讨厌的 ∇_θ对数(π_θ(a|s)) — 也称为得分函数— 我们如何将它转化为可实施的规则?从数学上来说,这是相当多的工作(详细推导这里),所以让我们直接跳到最终结果:
离散政策梯度的得分函数。得分函数是所选动作的特征向量减去所有动作的加权特征向量。
在教科书中,最下面的方程通常是作为最终结果出现的,但实际上我发现其他方程更有用。
举个例子吧。处理一个 48 元素的向量有点不方便,所以假设我们有一个只有 4 个元素的特征向量。首先,我们的一键向量 ϕ(s,a) 可能看起来像[0 1 0 0]
——代表我们采取的行动。其次,我们计算我们的期望,它本质上是一个加权特征向量。假设我们有一个概率向量[0.2 0.5 0.1 0.2]
,每个动作将我们引向一个不同的瓦片(状态)。所有的动作都是一次性编码的,所以期望可以写成
weighted_phi: [1 0 0 0]*0.2 + [0 1 0 0]*0.5 + [0 0 1 0]*0.1 + [0 0 0 1]*0.2 = [0.2 0.5 0.1 0.2]
对,那和概率向量本身完全一样。事情并不总是这么简单——特征向量不一定是一个热门向量——但是你会明白的。现在,我们只需要从特征向量中减去期望值就可以得到
score function: [0 1 0 0] - [0.2 0.5 0.1 0.2] = [-0.2 0.5 -0.1 -0.2]
概括地说,我们采用了与我们选择的动作相对应的特征向量,然后减去所有动作的加权特征向量,从而获得该动作的得分。
为了执行权重更新δθ,我们将得分函数与奖励 G_t 和学习率 α 相乘。例如:
Weight update: Δθ = α * score_function * G_t = 0.01 *[-0.2 0.5 -0.1 -0.2]*10 = [-0.02 0.05 -0.01 -0.02]
直觉上,其中的含义是清楚的。如果我们把一个积极的分数(行动 2)乘以一个积极的回报,这个概率会增加,我们会在未来更频繁地采取行动。更微妙:奖励信号越强,更新越大。渐渐地,概率在最坏的情况下会收敛到局部最优,在最好的情况下会收敛到全局最优。
Python 实现
回到我们的悬崖漫步问题。最初,我们不知道什么行为是好的,因此相等地初始化概率是有意义的(简单地将所有的 θ 设置为 0)。我们的代理人会在一段时间内磕磕绊绊,但最终应该击中目标。这给了倒数第二块瓷砖一个强烈的奖励信号(增加向下移动的概率),从那里开始就是连锁反应。
请注意,尽管该方法是基于政策而不是基于价值的,但奖励轨迹隐含地保留了整个过程中的核心角色。更新只发生在一集的结尾,所以如果我们走了 20 步,我们执行 20 次更新,追溯完整的轨迹(即蒙特卡罗学习)。
完整的实现可以在我的 GitHub 上找到,在这里我将重点放在最相关的片段上(为了可读性做了一些清理)。
首先,让我们定义策略:
相应的 softmax 可以表示如下。实际的实现通常涉及缩放—指数可能会变得非常大。
使用相应的折扣,为存储的轨迹中的每个决策时刻 t 计算奖励函数 G_t 。通常,您还需要在这里执行一些奖励标准化。
最后,评分函数 ∇_θ log(π_θ(a|s)) ,需要执行更新*δθ=α⋅g_t⋅∇_θlog(π_θ(a | s))。*提醒一下,我们只是简单的从实际的特征向量(选择的动作)中减去加权的特征向量(所有动作)。
这就是我们所需要的。现在让我们运行它,使用 SARSA(另一个基于策略的方法,但是基于值)进行比较。
10,000 集的步骤数,使用策略梯度和 SARSA 进行培训。SARSA 更快地收敛到更好的解,并且经历更少的噪声。[图片由作者提供]
政策梯度和 SARSA 的培训路径。由于更高的探索,梯度剂走了更长的弯路。两者都不走最短路径,都是带有嵌入式探索的策略方法。[图片由作者提供]
显而易见,政策梯度更新比 SARSA 更新要混乱得多。这部分是随机策略所固有的(我们的 SARSA 代理只探索了 5%的时间,梯度方法探索了更多的时间)-即使在 10,000 次迭代之后,代理也要绕着悬崖走一大段路,以对抗随机移动的不利影响。
此外,SARSA 使用时间差异,而政策梯度使用完全回报轨迹——后者具有高得多的方差。因此,我们也需要较低的学习速率 α 来获得稳定的结果。
虽然政策梯度法在这里没有得到好评,但这并不意味着被驳回。像任何算法一样,对某些问题来说,这是一个很好的选择,但对其他问题来说,这是一个很差的选择。这些结果只是作为一个典型的强化行为的例子,可悲的是,它包含了高度的可变性和向局部最优的收敛。一如既往,适当的调整,奖励正常化,功能设计等。对提高性能大有帮助。
但是现在,让我们庆幸我们又一次勇敢地面对了悬崖。
完整的代码,包括其他针对悬崖行走问题的 RL 解决方案,可以在我的 GitHub 上找到:
https://github.com/woutervanheeswijk/cliff_walking_public
外卖食品
- 为了解决悬崖行走问题,我们可以采用离散策略,使用 softmax 策略选择动作。
- 更新依赖于得分函数,该函数是对应于所选动作的特征向量 ϕ(s,a) 减去所有动作的加权特征向量 ϕ(s,⋅) 。
- 逐渐地,策略收敛到每个状态的最佳动作的高概率(在这种情况下是平铺)。
- 由于奖励轨迹的高可变性和高探索性,在这种基本实现中,收敛比基于价值的方法慢。
Q-learning 和 SARSA 的实现:
深度 Q 学习的实现:
首先在离散政策梯度的基础上迎头赶上?查看我的文章最小工作实例和理论推导:
参考
Benderski,E. (2016 年)。soft max 函数及其导数。https://Eli . the green place . net/2016/the-soft max-function-and-its-derivative/
西格尔,E. (2029)。政策梯度。https://siegel.work/blog/PolicyGradient/
西尔弗博士(2020)。第七讲:政策梯度https://www . David silver . uk/WP-content/uploads/2020/03/pg . pdf
萨顿和巴尔托(2018 年)。强化学习:介绍。麻省理工出版社。
威廉姆斯,R. J. (1992)。连接主义强化学习的简单统计梯度跟踪算法。机器学习,8(3–4):229–256。
于,鄂(2017)。用 Python 从零开始的策略渐变。http://quant.am/cs/2017/08/07/policy-gradients/
气候变化:互动 Plotly Dash 发现我们的未来前景
原文:https://towardsdatascience.com/climate-change-interactive-plotly-dash-to-discover-our-future-prospective-d3d60d62cb86?source=collection_archive---------39-----------------------
数据科学,了解城市、国家和我们的世界正在发生什么,以及将会发生什么。
作者: 卡米拉·马西 ( 李 ) 西尔维娅·保鲁奇 ( 李 ) 唐塔雷利 ( 李)
*** 链接到app* * *
林丽安在 Unsplash 上的照片
在过去的几年里,一些机构提供的数据强调了我们星球的气温上升趋势。不幸的是,这种趋势没有任何积极的一面。
多年来,科学家们不断发出警告,让我们意识到尽可能降低气温的上升是多么重要。尽管在这个问题上达成了各种各样的协议,但事情并不完全像我们所希望的那样发展,并且后果是明显的。
大量研究表明,气候变化正在对动物和植物产生重大影响。气候条件是决定哪些动植物物种能够在特定地理区域生存、生长和繁殖的决定性因素。其中一些与它们已经适应的气候条件密切相关,温度的轻微上升、降雨量的少量减少或另一个参数的细微变化都会增加它们的脆弱性。
由于温度过高,两极的冰川不断融化。这导致生态系统发生重大变化,加速了生活在其中的动物的灭绝(例如:蜜蜂、北极熊、树袋熊、海豹和许多其他动物)以及海平面的上升。
安德里亚斯·韦思, CC BY-SA 4.0 ,通过维基共享
当然,不仅仅是地球上寒冷的地方显示了气候变化的后果。此外,非洲“包含世界上五分之一的已知植物、哺乳动物和鸟类物种,以及六分之一的两栖动物和爬行动物”(齐格弗里德 1989),正显示出一致的变化。这些变化包括候鸟和大型哺乳动物习性的改变、珊瑚礁的减少以及随之而来的生物多样性的丧失,而生物多样性是非洲人民的一种相关资源。
即使在意大利,我们也有气候变化影响的例子。例如,我们可以指出这样一个事实,即据估计,白云石(世界遗产)中最大的 Marmolada 冰川将在 15 年内消失,而且情况每年都在变得越来越糟。
SkiNick890 , CC BY-SA 4.0 ,通过维基共享
所以,我们认为提供我们的星球正在发生什么的证据是相关的,除非有所发现,否则我们将继续在这个星球上生活一辈子。为此,我们认为利用数据科学和数据分析的新技术开发一个 Python 仪表盘会很有意思,它将清楚明确地突出显示我们正在目睹的气候变化(我们是气候变化的原因)。
数据集
我们选择了由伯克利地球公司发布的开源数据集。这是一个美国非营利组织,它与各种机构一起进行了测量,其中美国宇航局是最突出的。
它包含了从 1750 年到 2013 年上半年的地球月平均温度、不同国家和一些特定城市的信息。其中一条信息是测量的不确定性。它在最初的几个世纪里太高了,所以这导致我们决定排除它们,因此只研究 1900 年到 2012 年之间的城市和城镇,以及 1900 年到 2015 年之间的地球。
阴谋地
我们所有的图表都使用了 Plotly ,这是一个免费的开源库。它实现了各种各样的图表,这些图表在视觉上非常吸引人,令人印象深刻。它还允许您添加不同类型的交互式内容,如动画、滑块等。
Pensrulerstape , CC BY-SA 4.0 ,通过维基共享
破折号
Dash 是一个用于构建 web 分析应用程序的高效 Python 框架,不需要 JavaScript,并且与 Plotly 紧密集成。Dash 是构建具有高度定制的用户界面的数据可视化应用程序的理想选择。通过几个简单的方案,Dash 抽象了构建基于 web 的交互式应用程序所需的所有技术和协议,使您可以将应用程序部署到服务器上,然后轻松地共享它们。此外,因为应用程序显示在 web 浏览器中,所以 Dash 本身就是跨平台的。
Heroku
Heroku 是一个云编程平台,旨在帮助构建和部署在线应用(PaaS)。它是首批出现在网络上的应用程序之一,允许用户开发、部署和管理在线应用程序,并支持包括 Python 在内的六种编程语言。
作为一个 PaaS,Heroku 的目的是为用户提供在各种平台(如脸书)上分发和运行基于网络的应用程序所需的计算资源。
Heroku , CC BY-SA 4.0 ,通过维基共享
应用
*** 链接到 app ***
这个应用程序是通过 Dash 和 Plotly 构建的,由三个选项卡组成:全球、国家和城市。每一个都是一个交互式仪表板,显示和报告从 1900 年到过去十年的前五年的各种图表和分析。
全球选项卡中收集的图表是最重要的:它们直接显示了上个世纪的全球变暖现象及其演变。
左侧的线形图显示了地球历年的平均温度趋势及其到 2050 年的预测。久而久之,增长的趋势越来越明显,预测证实了科学家们长期以来一直重复的话:如果我们不与这种趋势作斗争,气温将迅速上升,情况只会变得更糟。
全球气温趋势及预测
通过动画图表,还可以通过颜色与侧面的色标图例进行比较,直观地了解世界每个国家的气温变化。我们注意到,与 1900 年相比,几乎每个国家的气温都上升了,这可以从地图上的暖色调中看出。将鼠标悬停在不同的国家上,可以观察到不同年份的这种变化。
各国平均气温变化
国家选项卡按国家提供了对 温度变化的更深入分析:您可以使用顶部的下拉菜单将分析集中在特定国家和特定年份。
第一个图表显示了所选国家到 2042 年的平均气温趋势和预测。举个例子,我们关注我们的国家意大利:同样在这种情况下,随着地球温度的上升,很容易注意到一个毫无疑问的上升趋势,特别是自 80 年代以来,这导致了不间断的温度上升,导致自 1900 年以来气温上升超过 1 摄氏度。
国家平均气温趋势及预测’(意大利)
通过箱线图在右上角的图表中可以看到所选国家多年来平均气温的月分布。这样就可以知道一个国家一年中各月平均气温的最小值、第一个四分位数、中位数、第三个四分位数和最大值。此外,该图突出显示了异常值,与其他年份各月的平均温度记录相比,这些异常值代表了异常的炎热或寒冷月份。例如,如果您选择意大利,则可能会注意到六月和八月的异常值,这两个月份都对应于 2003 年记录的异常高温。事实上,在那年的夏天,一场强烈的热浪袭击了整个欧洲,在整个欧洲大陆造成了至少 3 万人死亡。
国家平均气温分布'(意大利)
在选项卡的底部,我们可以找到一个**直方图,显示了属于所选国家的不同城市的平均温度。水平段表示国家的平均温度,直方图的列表示城市的平均温度。**正如我们所料,选择意大利,最高的列对应于南部城市。
主要城市平均气温’(意大利— 2012 年)
转到城市选项卡,可以通过线性图表详细调查一个城市及其所在国家的平均温度。
到 2042 年所选城市的平均气温预测也以图表形式显示在该选项卡中。这一预测与全球气温的总体上升一致,这让我们想知道气候变化现象在未来可能会持续并恶化到什么程度。
城市平均气温趋势及预测’(意大利—安科纳)
国家和城市平均温度’(意大利—安科纳)
结论
总之,我们希望我们已经清楚地解释了气候变化和全球变暖的问题,并激发了你们对这个主题的兴趣。我们的目标是为理解我们的星球正在经历的突变以及气候变化和全球变暖对我们生活的影响提供定量支持。这不“仅仅”是两极冰川融化或荒漠化加剧的问题,因为这关系到我们所有人,因此我们必须应对气候变化。
我们所做的预测显示了一个明确的趋势。它导致不安全和令人担忧的前景延伸到 2050 年,这是世界主要领导人在最近的气候领导人峰会上设定的实现零排放的目标,但这些所谓的气候目标会实现吗?它们够用吗?还是会是惯常的“大言不惭,小动作”?
“我们知道世界是复杂的,许多人都在尽最大努力,需要的东西并不容易。但是我们不能满足[……]我们必须走得更远。我们必须相信我们能做到,因为我们能。当我们人类走到一起,决定完成某件事时,我们几乎可以完成任何事。我们将继续为一个安全的未来而奋斗。学位的每一分都很重要,而且将永远重要。需要做的事情和我们实际正在做的事情之间的差距每分钟都在扩大。所需的紧迫性与目前的认识和关注水平之间的差距越来越荒谬。我们所谓的气候目标和当前最有效的整体科学之间的差距不应再被忽视。”
格里塔·图恩伯格
作者: 卡米拉·马西 ( 领英 )
西尔维亚·保鲁奇 ( 领英 )
弗朗切斯科·通塔雷利 ( 领英)
利用 Pandas 和 Matplotlib 进行气候数据分析
原文:https://towardsdatascience.com/climate-data-analysis-with-pandas-and-matplotlib-ca75f18a0587?source=collection_archive---------27-----------------------
探索性数据分析揭示了加纳最热的日、月、年
照片由达维德·扎维亚在 Unsplash 上拍摄
基本原理
加纳气候数据的探索性数据分析(EDA)展示了我第一个数据科学项目组合。气候数据提供了一个时间序列的天气变量记录,按时间顺序排列,对 EDA 非常有用。其次,它可以免费公开获得,对我来说,只需点击几下鼠标,就可以从 https://www.ncdc.noaa.gov/cdo-web 的 T4 获得数据。
从美国国家海洋和大气管理局记录的最热月份项目中得到启示,该项目来自 https://www.ncdc.noaa.gov/sotc/global/201904。我使用 Pandas 和 Matplotlib 研究了加纳气候数据的 EDA,以了解趋势以及它如何与全球气候变化现象进行比较。就个人而言,从当地的角度把握气候变化的咒语。这篇文章介绍了该项目的成果和一点旅程。
旅程
在过去的几个月里,由于 Covid 19 疫情导致工作放缓,我陷入了学习 Python 编程的困境,以此来掩盖我的业余时间。互联网上许多免费的资源对我自学这个科目很有帮助。特别值得一提的是赫尔辛基大学提供的完整的地理 python 课程。这是为环境和自然资源领域的趋势学习者准备的。其他的包括科里·谢弗在 youtube 上的教程和 StackOverflow 上提供的一些有价值的建议。
有趣的是,在设置我的 Github 账户来托管这个项目时,我遇到了一个大惊喜。Github 通知我我的电子邮件帐户已经被占用了,真是一个惊喜!我成功地找回了密码。只有当我访问该帐户时,我才意识到,该帐户是 2014 年第一次设置的,哇!事实上,它已经来了很久。
结果
这些数据是从遍布加纳的 17 个站点/城镇获得的记录。它包含 70,068 条每日记录的 11 个变量。记录从 1973 年开始,到 2020 年,一段 47 年的气候数据。不同站点的独特记录的长度各不相同,这丝毫不影响数据的整体分析。最终只选择了四个主要变量进行分析。
总结和简要评论如下:
加纳的日平均气温为 27.6 摄氏度,即日平均气温。最热的一天,即 1977 年 4 月 22 日记录的最高日平均温度为 35.0 摄氏度。与全球 4 月最热月份记录一致。最高月平均温度 31.1 摄氏度,记录于 1983 年 4 月——最热的一个月。最高年平均温度 30.2 摄氏度,记录于 1983 年——最热的一年。这与 2020 年不同,根据美国宇航局的数据,2016 年是全球最热的一年。
加纳年平均温度
年平均温度图显示了总体上升和波动的温度,从 2015 年开始稳定在 28 摄氏度左右。这意味着更热的天气会带来严重的气候影响。1983 年,加纳经历了历史上最严重的干旱和森林大火,这些都被精确地记录在图片中。
在此期间,记录显示自 1973 年以来气温每十年上升 1.5 摄氏度。访问加纳的最佳时期是 6 月中旬到 9 月,那时气温会降到 26 摄氏度以下,这是我们最凉爽的月份。
加纳月平均气温
关于用 Pandas 编码,一个主要的收获是在任何切片操作之前对数据帧进行排序,否则,您可能会在分析中遇到挑战。也就是说,如果你的数据还没有排序。你不会想体验我作为切片新手所经历的麻烦。考虑到 17 个站点的数据集类型,该项目可以进行更多的分析、可视化和推断。去我的 Github 便携版玩玩吧。欢迎对这篇文章提出意见和问题。感谢阅读。
临床自然语言处理
原文:https://towardsdatascience.com/clinical-natural-language-processing-5c7b3d17e137?source=collection_archive---------11-----------------------
迁移学习和弱监督
由 Unsplash 上的 Hush Naidoo 拍摄的照片
在全国各地,医生每天都在给病人看病,并仔细地将他们的病情、健康的社会决定因素、病史等记录到电子健康记录(EHRs)中。这些文档繁重的工作流产生了丰富的数据存储,有可能从根本上改善患者护理。这些数据的大部分不是离散的字段,而是自由文本的临床笔记。传统的医疗保健分析主要依赖于离散数据字段,偶尔也依赖于自由文本数据的正则表达式,从而错过了大量的临床数据。
在疫情早期,在建立广泛的检测之前,关于新冠肺炎的症状信息(即发烧、咳嗽、气短)对于跟踪传播是有价值的。更好地了解疾病的进展并识别可能经历更差结果的患者仍然是有价值的。在离散数据字段中,无法可靠地捕获症状数据。临床进展记录,特别是在门诊环境中,提供了新冠肺炎感染的早期证据,使得能够预测即将到来的医院激增。在本文中,我们将研究 NLP 如何通过迁移学习和弱监督来实现这些见解。
照片由马丁·桑切斯在 Unsplash 拍摄
自然语言处理(NLP)可以从临床文本中提取编码数据,使以前的“黑暗数据”可用于分析和建模。随着最近算法的改进和工具的简化,NLP 比以往任何时候都更加强大和容易使用,然而,它也不是没有一些逻辑障碍。有用的 NLP 引擎需要大量带标签的数据来很好地“学习”一个数据域。临床文本的专业性质排除了人群来源标签,它需要专业知识,而具有专业知识的临床医生在更紧迫的事务中需求量很大——特别是在疫情期间。
那么,医疗系统如何在尊重临床医生时间的同时利用他们的自由文本数据呢?一个非常实用的方法是迁移学习和弱监督。
现代的 NLP 模型不再需要从头开始训练。许多最先进的语言模型已经在临床文本数据集上进行了预训练。对于新冠肺炎综合症的数据,我们从名为 huggingface 的 pytorch 框架中可用的Bio _ Discharge _ Summary _ BERT开始。如 ClinicalBERT 论文中所述,该模型在 MIMIC III 出院小结数据集上进行训练。我们使用来自 Bio_Discharge_Summary_BERT 的 transformer 单词嵌入作为迁移学习基础,并微调序列标记层,以使用我们的特定症状标签对实体进行分类。例如,我们对“气短”感兴趣,临床上有许多症状可以归入这一范畴(例如,“呼吸困难”、“气喘”、“呼吸急促”)。我们的分类问题限于大约 20 个症状标签,比一般的临床 NER 问题产生更高的性能结果。
然而,为了训练这个序列标记层,我们回到了数据问题。MIMIC III 和我们的内部临床文本数据集都是未标记的。少数公开可用的带标签的临床文本数据集(如 N2C2 2010)被标记为不同的使用案例。我们如何为我们的目标用例获得足够的数据标签,并负责任地进行采样以防止模型中的偏差?
我们的策略有三个步骤:注释的选择性抽样、弱监督和负责任的人工智能公平技术
我们使用选择性抽样来更有效地利用我们临床医生的时间。对于新冠肺炎症状,这意味着只向注释者提供可能包含症状信息的注释。产前预约记录或行为健康记录不太可能讨论发烧、咳嗽、流鼻涕或气短。战略性地限制我们发送给注释者的注释池增加了临床医生花费在每个注释小时上的标签。为了进行注释,我们为临床医生提供了一个名为 prodigy 的工具。用户界面易于使用,并且对于不同的注释策略是灵活的。
由作者创建
建立注释策略时的一个主要决策点是确定您希望您的注释器以什么粒度进行标记。选择太高的粒度,比如“症状”,不会给我们用例所需要的数据,但是过于具体,比如“非生产性咳嗽”对“生产性咳嗽”,对注释者来说是一个沉重的负担,对我们没有额外的好处。对于任何标注策略,平衡标注者的负担和标注数据集的可重用性是很重要的。我们回到井里的次数越少越好,但是如果一个临床医生花 2 个小时来注释一个临床笔记,我们也没有成功。对于我们的项目,注释的第一步只适用于 NER。我们后来通过了 NER 的情绪(即。存在、不存在、假设)。Prodigy 允许使用定制配方脚本制定有针对性的策略。
在从我们的临床医生那里收集了 Prodigy 注释后,我们创建了基于规则的标签模式,用于 SpaCy 中的弱监管。Prodigy 和 SpaCy 由同一个开发小组开发,这使得集成变得非常简单。弱监督是另一种注释策略,然而,它不是来自临床主题专家的“黄金标准”注释,而是使用一种算法来注释更大量的文本。理想情况下,由于使用算法而降低的准确性被可以处理的大量文档所抵消。使用基于以下标记模式的算法,我们能够生成一个非常大的训练数据集。
{"label":"SOB","pattern":[{"LOWER":{"IN":["short","shortness"]}},{"LOWER":"of","OP":"?"},{"LOWER":"breath"}]}
{"label":"SOB","pattern":[{"LOWER":"tachypnea"}]}
{"label":"SOB","pattern":[{"LOWER":"doe"}]}
{"label":"SOB","pattern":[{"LOWER":"winded"}]}{"label":"SOB","pattern":[{"LOWER":"breathless"}]}{"label":"SOB","pattern":[{"LOWER":"desaturations"}]}{"label":"SOB","pattern":[{"LOWER":"gasping"}]}{"LOWER":"enough"},{"LOWER":"air"}]}{"label":"SOB","pattern":[{"LOWER":"cannot"},{"LOWER":"get"},{"LOWER":"enough"},{"LOWER":"air"}]}{"label":"SOB","pattern":[{"LOWER":"out"},{"LOWER":"of"},{"LOWER":"breath"}]}
因为我们的选择性采样会使我们呈现给注释者的注释产生偏差,所以我们需要防止最终训练模型的弱监督数据集中的偏差。临床领域的机器学习需要更高程度的努力,以防止模型中的偏差。 负责任的人工智能技术 在所有行业都变得强制性,但由于平等和公正是生物医学伦理的基本原则,我们小心翼翼地开发了一种用于弱监管的无偏笔记采样方法。对于每个数据集,临床记录在种族和民族、地理位置、性别和年龄上以相同的数量进行采样。然后通过 SpaCy 将标签图案应用到纸币上。结果是 100,000 份临床记录的 IOB 格式的注释数据集。
def **pandas_parse**(x): with open(patterns_file) as f:
patterns = json.load(f) \
if patterns_file.lower().endswith("json") \
else [json.loads(s) for s in f]
for p in patterns:
p["id"] = json.dumps(p)
spacy.util.set_data_path("/dbfs/FileStore/spacy/data")
nlp = spacy.load(spacy_model, disable=["ner"])
ruler = EntityRuler(nlp, patterns=patterns)
nlp.add_pipe(ruler)
return x.apply(lambda i: parse_text(i,nlp))parse_pandas_udf = F.pandas_udf(pandas_parse,ArrayType(ArrayType(StringType())), F.PandasUDFType.SCALAR)#IOB output
def **parse_text**(text,nlp):
doc = nlp(text)
text = []
iob_tags = []
neg = []
for sent in doc.sents:
if len(sent) < 210 and len(sent.ents) > 0:
text = text + [e.text for e in sent]
iob_tags = iob_tags + [str(e.ent_iob_) + '-' \
+ str(e.ent_type_) if e.ent_iob_ else 'O' for e in sent]
return (pd.DataFrame( {'text': text,'iob_tags ': iob_tags
}).values.tolist())
由作者创建
此时,我们已经准备好训练我们的序列标签层。我们使用了一个叫做 Flair 的框架来从我们的 IOB 标签数据集创建一个语料库。然后,语料库被分成开发集、训练集和验证集,Flair 从那里开始。结果很有希望。
- F1-score (micro) 0.9964- F1-score (macro) 0.9783By class:ABDOMINAL_PAIN tp: 977 - fp: 6 - fn: 5 - precision: 0.9939 - recall: 0.9949 - f1-score: 0.9944ANXIETY tp: 1194 - fp: 8 - fn: 8 - precision: 0.9933 - recall: 0.9933 - f1-score: 0.9933CHILLS tp: 343 - fp: 1 - fn: 0 - precision: 0.9971 - recall: 1.0000 - f1-score: 0.9985CONGESTION tp: 1915 - fp: 21 - fn: 6 - precision: 0.9892 - recall: 0.9969 - f1-score: 0.9930COUGH tp: 3293 - fp: 6 - fn: 6 - precision: 0.9982 - recall: 0.9982 - f1-score: 0.9982COVID_EXPOSURE tp: 16 - fp: 1 - fn: 1 - precision: 0.9412 - recall: 0.9412 - f1-score: 0.9412DIARRHEA tp: 1493 - fp: 6 - fn: 0 - precision: 0.9960 - recall: 1.0000 - f1-score: 0.9980FATIGUE tp: 762 - fp: 2 - fn: 7 - precision: 0.9974 - recall: 0.9909 - f1-score: 0.9941FEVER tp: 3859 - fp: 7 - fn: 2 - precision: 0.9982 - recall: 0.9995 - f1-score: 0.9988HEADACHE tp: 1230 - fp: 4 - fn: 5 - precision: 0.9968 - recall: 0.9960 - f1-score: 0.9964MYALGIA tp: 478 - fp: 3 - fn: 1 - precision: 0.9938 - recall: 0.9979 - f1-score: 0.9958NAUSEA_VOMIT tp: 1925 - fp: 7 - fn: 12 - precision: 0.9964 - recall: 0.9938 - f1-score: 0.9951SOB tp: 1959 - fp: 10 - fn: 10 - precision: 0.9949 - recall: 0.9949 - f1-score: 0.9949SWEATS tp: 271 - fp: 0 - fn: 1 - precision: 1.0000 - recall: 0.9963 - f1-score: 0.9982TASTE_SMELL tp: 8 - fp: 0 - fn: 6 - precision: 1.0000 - recall: 0.5714 - f1-score: 0.7273THROAT tp: 1030 - fp: 11 - fn: 2 - precision: 0.9894 - recall: 0.9981 - f1-score: 0.9937WHEEZING tp: 3137 - fp: 6 - fn: 0 - precision: 0.9981 - recall: 1.0000 - f1-score: 0.9990
假设我们在弱监督的、基于规则的数据集上训练了一个 transformer 语言模型,人们可能会合理地问,“为什么不在生产中使用基于规则的方法?”然而,考虑到 transformer 语言模型(如 BERT)使用子词标记和上下文特定的向量,我们训练的模型可以识别基于规则的模式文件中未指定的症状,并且还可以正确识别我们感兴趣的实体的拼写错误版本(例如,它正确地将“cuogh”识别为[咳嗽])。
由于临床自由文本笔记中的丰富数据和临床笔记注释的逻辑挑战,医疗保健 NLP 的一个非常实用的方法是迁移学习和弱监督。
K-Means 类的亲密接触
原文:https://towardsdatascience.com/close-encounters-of-the-k-means-kind-4aff91b3d0ab?source=collection_archive---------18-----------------------
实践教程
用聚类算法分割史蒂芬·斯皮尔伯格的电影
📸—埃里克·维特索— Unspalsh
场景 1:为电影集群搭建舞台
“不管是成功还是失败,我都为自己执导的每一部电影感到骄傲。”
史蒂文·斯皮尔伯格
职业生涯跨越近 60 年;据《时代》杂志报道,电影制作人史蒂文·斯皮尔伯格凭借《大白鲨》一炮走红,使 1975 年成为“鲨鱼的夏天”。从那以后,他不断地将自己和观众推出舒适区,建立了一份无人能及的遗产。正如《滚石》杂志(Rolling Stone)的 Bilge Ebiri 所指出的,斯皮尔伯格“总是在大片和更严肃的作品之间徘徊”,他的电影跨越了多个流派。一路走来,他获得了 18 项奥斯卡提名,找到了一种赢得评论界和商业赞誉的方法,因为他的 30 多部电影在国内票房收入超过 100 亿美元(经通胀调整后)。他似乎也没有慢下来;快速浏览一下他的 IMDB 页面,暗示他可能正在努力导演下一部大片。
试图对这位可能是有史以来最著名的电影导演的电影作品进行分类或细分并不是一件简单的任务。但是让我们试一试。一个简单的时间顺序列表或类型分类就足够了,但如果我们采取一种更数据驱动的方法,通过评估多种电影属性,在斯皮尔伯格电影集中潜在地浮现潜在的模式或主题,会怎么样?
场景 2: K 均值聚类概述
无监督学习指的是当没有每个数据点的标签、类或类别的明确标识时,试图提取意义的模型。聚类是一种无监督的学习方法,它将未标记的数据分组,以帮助我们更好地理解数据集中的模式。聚类是广泛使用的推荐引擎的关键组成部分,这些引擎嵌入到亚马逊、网飞和许多其他人每天都在使用的产品中。虽然我们将在这里使用聚类作为非常简单的电影建议工具的构建块,但是其他应用包括:
个性化营销- 利用客户数据库中的人口统计数据,营销人员可以对不同类型的用户进行分组,并为他们提供更合适的产品或个性化活动。知道这个群体中的人喜欢“x”(而不是“y”),可以减少浪费的广告支出,同时提高活动转化率。
异常检测- 异常是数据集中偏离共同趋势或模式的数据点。结合 K-Means 聚类的视觉特性,可以设置预定的阈值或边界距离来帮助观察和隔离偏离包的离群值。
文件缩减/图像压缩 -数字图像由像素组成,每个像素的大小为 3 字节(RBG),每个字节的值从 0 到 255,导致每个像素有大量的颜色组合。K-Means 可应用于图像文件,将相似或相似的颜色分组,以创建文件大小减小但图像仍可解读的新版本。例如,代替包含 200 种颜色的狗的图像,K-均值聚类也许可以仅使用 10 种颜色来呈现图像,而不会显著降低图像的视觉特性。
存在多种聚类算法;您试图解决的问题以及您所掌握的数据通常会决定采用哪种方法。K-Means 聚类是最广泛使用的方法之一,它试图通过创建一定数量的聚类来对未标记的数据进行分类,如字母“k”所定义的。该算法确定适当的聚类,并根据每个数据点到质心的接近度(或相似度)将每个数据点分配给一个聚类,质心是聚类中心的别称。值得注意的是,K-Means 并不确保每个聚类都具有相同的大小,而是专注于识别最适合分离和分组的聚类。
K-Means 聚类通常被认为是一种“划分”技术,与其他聚类方法相比,它有几个优点。首先,这相当简单:告诉模型您想要多少个组,并将所有数据点分配给适当的组。这种简单性使它即使在非常大的数据集上也能快速运行。此外,它的流行导致了 Python 中大量的开源资源和相关库——我们将在后面探讨。
而 K-Means 聚类使用起来相对简单,并且可以很好地适应大型数据集;这种方法伴随着一些缺点。K-Means 聚类需要严格的数字数据,这可能需要根据可用的数据集准备一些数据。此外,该算法可能对异常值非常敏感。此外,K-Means 不能随着维数或变量的增加而很好地扩展;我们将看到两个甚至三个变量是如何很好地适用于这种技术的,但是超出这个范围会给解释带来困难。幸运的是,像主成分分析(PCA) 这样的降维技术与 K-Means 配合得很好。
解释是任何 K 均值聚类练习中最重要的步骤;正如道恩·雅各布奇在她的教科书 营销模型 中所写的,“一旦集群被衍生出来,我们必须理解它们。”对聚类输出的正确分析应揭示现有问题的答案,并产生关于数据集的新问题。聚类的大小、位置和数量都是潜在的有用线索,可以为下一步的分析提供信息。
场景 3:分解算法
K 均值聚类算法的过程可以分为几个步骤:
第一步(初始化)——首先,我们需要决定我们想要多少个簇(以及质心)。这一步既可以随机完成,也可以通过肘方法通知,这将在后面解释。我们将告诉模型选择“K”个随机点作为我们的初始质心。
第 2 步(分配)—算法然后将每个数据点分配到通过平方距离测量的最近质心。
步骤 3 (重新计算)——然后通过取当前分配给该聚类的所有数据点的平均值来重新计算或调整质心。
步骤 2 和 3 的迭代继续进行,直到不需要进行新的最佳重新分配,并且所有数据点都位于其数据与它们自己的数据最相似的聚类中。本质上,该算法寻求继续迭代,并最小化误差平方和(SSE)作为聚类性能的度量。这个迭代过程通过最小化簇内的可变性和最大化簇之间的可变性展示了“像数据点一样分组”的思想。
当在步骤 1 中随机选择质心位置时,K-Means 可以在算法的连续运行中返回不同的结果。为了克服这个限制,该算法可以运行多次,并最终提供基于 SSE 的最佳结果。
图:K-Means 收敛的 GIF(来源
场景 4:读入和浏览数据
虽然 R 对于这种类型的分析是完全合适的工具,但是我们将使用 Python,因为它可以访问有用的 K-Means 方法以及强大的绘图功能。在加载我们的数据来分析并最终推荐斯皮尔伯格电影之前,我们将导入 K-Means 所需的库以及其他一些用于后续绘制的库,同时也导入我们的数据集。
图:前五个观察值或我们数据集的“头”(图片由作者提供)
我综合了几个不同来源的数据——IMBD、烂番茄和数字——收集了一系列斯皮尔伯格担任导演的电影,以及每部电影的相关变量,如年份、片名、电影评分、国内票房表现(经通胀调整)和电影时长。如上所述,K-Means 聚类需要所有数值数据;幸运的是,这里就是这种情况,所以我们不需要转换数据集。(查看我的上一篇文章以了解关于数据清理和准备的价值的更多细节,以及本指南关于特定于集群的数据准备工作)。
配对图是快速探索数据集中分布和关系的有用工具。我们将使用。seaborn 库中的 pairplot 函数,只需一行代码,我们就可以了解数字变量(BoxOffice、TomatoMeter 和 Duration)之间的关系。不出所料,我们注意到票房和票房之间微弱但正相关,表明影评人和付费电影观众在谈到斯皮尔伯格电影时有一些共同的态度。
图:数据集的配对图(图片由作者提供)
可视化我们的数据有助于快速了解其形状、分布和对称性。除了散点图之外。pairplot 方法还提供了变量的直方图。displot 方法也可以用来实现这一点)。我们注意到两者都有一些尾部,电影票房呈左偏分布,票房略偏右。假设变量是正的,可以用对数变换来消除偏斜。出于本练习的目的,并且考虑到我们的数据集相对较小,偏斜度也相当小,我们将在本例中暂停运行该转换,但了解这一点还是有好处的。
最后,让我们使用图形库 plotly 来创建一个交互式散点图,显示根据我们感兴趣的两个变量(烂番茄和票房)绘制的电影。
图:通过 plotly 制作的数据集交互式散点图(图片由作者提供)
如上所述,K-Means 对数据集中的异常值非常敏感。在运行 K-Means 算法之前删除这些点是明智的,但是考虑到没有主要的异常值和相对较小的数据集,我们将跳过这一步。
场景 5: 确定聚类数
当基于数据的预定数量的聚类不明显时,我们求助于肘方法,这是一种帮助确定适当数量的聚类的统计方法。回想一下,聚类旨在定义聚类,以使总的类内变化(通过从点到质心的距离来测量,也称为 WCSS 或类内平方和)最小化。自然,群集数量的增加与误差成反比关系;更多的聚类为我们的数据中的观察提供了更多的选项,以找到相似的组来加入。然而,添加越来越多的集群会产生较小的增量增益,并可能导致“过拟合”的例子。肘方法帮助我们在过多和过少的集群之间找到适当的平衡。
肘法也为这一努力增加了视觉元素。肘形图将显示每个 K 值的 WCSS 值,代表聚类总数。我们开始看到收益递减的点,有时看起来像肘关节,可以被认为是 k 值的一个很好的候选点。
图:帮助确定适当集群数量的“肘方法”图(图片由作者提供)
看起来我们理想的集群数量是三个!在确定用于分析的聚类数量时,没有硬性规定;因此,诸如“这些集群是可解释的吗?”或者“它们被新数据复制的可能性有多大?”将有助于做出最终决定。肘方法的正确应用是一个很好的例子,说明数据分析需要艺术和科学的独特融合。
场景六:运用&解读 K-Means
虽然对数据的未缩放版本和缩放版本运行 K-Means 通常是最佳实践,但为了简单起见,我们将坚持在数据集的未缩放版本上运行该算法,同时保持变量及其相对缩放的可解释性。我们可以从 sci-kit learn 的集群模块中运行 k_means()函数,使得 K-Means 的实现相对简单。
图:K-Means 结果的第一个视图(图片由作者提供)
这是我们第一次看到我们的集群数据!但是我们的工作还远远没有结束。正如精彩的教材《Python for Marketing and Research Analytics》中提到的那样,“细分项目中最关键的问题是业务方面:结果对手头的目的有用吗?”
回想一下识别斯皮尔伯格导演的电影的独特分组的初衷,我们可以求助于 Python 来帮助我们识别与上述情节匹配的其他拼图(同时也使用一些简单的技巧来帮助增强图形本身)。例如,我们将使用。countplot 方法来了解每个集群的相对大小,同时将它们分配给数字分组。
图:结果。展示聚类大小的计数图方法(图片由作者提供)
不平衡的聚类通常表示远处的异常值或一组非常不相似的数据点,这将保证进一步的调查。通过浏览上面的图表,我们可以看到《第二集》确实因其相对较小的尺寸而显得突出——即使对于可以说是有史以来最伟大的导演来说,创作一部观众和评论家都非常崇拜的电影仍然很难做到!鉴于这一组中的三部电影取得了票房和关键成功的理想平衡,如果我们能够超越坐在导演椅上的人来识别这三部电影之间的相似之处,那当然值得一看。
计算质心的汇总统计数据有助于回答“是什么使这个星团独一无二?”我们将在这里添加回持续时间变量,看看是否可以帮助打开一些新的见解。
图:显示了所有三个集群中相关变量的平均值(图片由作者提供)
我们还将创建一个蛇形图,以便我们能够以一种更直观的方式查看每个集群中感兴趣的变量之间的变化。这将需要我们的数据集以及集群的规范化版本。熊猫。melt 方法将规范化的数据帧重新排列成适当的布局。
图:蛇情节结果(图片作者)
我们可以看到,该图提供了一个有用的可视化表示,显示了所生成的聚类在不同的感兴趣属性之间的差异。例如,这三个集群之间最明显的区别似乎是 BoxOffice 变量。让我们把上面的 K-Means 散点图带回来,用一些有用的注释把所有的东西放在一起。
图:带注释的 K-Means 结果的更新视图(图片由作者提供)
当组合在一起时,聚类平均值、蛇形图和 K-Means 可视化可以帮助启发一些合适的名称来帮助我们描绘我们的聚类。红色的簇 0 可能是“一个混合包”。虽然这些电影都没有打破票房纪录,但它包含了广泛的番茄米评级。绿色的集群 1 可能是“强有力的竞争者”集群,代表除了《侏罗纪公园 2》之外最受评论家喜欢的电影,并且在票房上表现相当好。最后,我们可以称较小的黄色星团 2 为“最好的”。如果你必须为你的电影爱好者朋友策划一个斯蒂芬·斯皮尔伯格入门包,这个小组将是一个很好的开始。
让我印象深刻的是斯皮尔伯格执导的高质量、高评价电影的惊人比例。考虑到 2019 年电影的平均评分为 59.3,斯皮尔伯格的电影平均得分高达 78。当我们看持续时间时,另一个有趣的收获出现了,这个变量包含在 snake 图和汇总统计图表中,但不在我们的 K-Means 算法中。时长和票房之间的反比和明显关系引发了一个问题,即删减一些场景或对白是否会给斯皮尔伯格的下一系列电影带来更大的商业成功。
请记住,考虑将聚类分析的输出结果与您试图回答的最终业务目标或问题联系起来是非常重要的。一天结束时,聚类输出只是数据点的组分配向量,由数据分析师来决定如何或是否讲述一个有见地的故事!
场景 7:限制、未来研究、额外资源和最终想法
正如我们上面提到的,我们在这里工作的数据集在观察数量和变量数量上都相对较小。编码电影相关的分类变量,如类型或美国电影协会评级,将是一种潜在的表面有趣的模式,并加强我们的电影建议的努力。此外,将我们的方法与时间序列分析结合起来,看看斯皮尔伯格电影这些年来是如何变化的,这是未来研究的另一条途径。在方法上;在这次讨论中,我们仅仅触及了集群技术的皮毛。其他方法,如层次聚类——以及称之为“树状图”的乐趣——有助于确定哪两个数据点最相似(或不相似)。虽然 k-means 方法在分析数据集的方法中具有全局性质,但分层可以根据我们所掌握的变量,得出关于哪些斯皮尔伯格电影最相似的有趣见解。
如果你想了解更多关于这个主题的内容,或者查看更多聚类算法的例子,我在下面列出了我在研究和撰写这篇文章的过程中遇到的一系列有用的 K-Means 聚类文章和教程:
- Ben Alex Keen—K-Means Python 中的聚类
- 阿曼达·多宾——数据科学专家
- 真正的 Python——Python 中的 K-Means 集群:实用指南
- 方差解释— K 均值聚类不是免费的午餐
- Oracle AI &数据科学博客—K 均值聚类简介
虽然我不认为我们非常简单的推荐模型会很快从网飞偷走订户,但希望 K-Means 聚类的高层次概述有助于展示 Python 及其相关功能的简单方面如何从数据集揭示独特的见解和模式,并帮助一些最广泛使用的推荐引擎。
点击查看原始代码。我忘记了什么或者你会做什么不同的事情?任何和所有的反馈都欢迎通过下面的评论,或者在 wmc342@gmail.com 给我留言。感谢你坚持这篇文章直到最后;喜欢这篇文章的人也喜欢…开玩笑而已;)
弥合人工智能价值差距第 2 部分:人工智能与自适应分析的共同创造
原文:https://towardsdatascience.com/closing-the-ai-value-gap-part-2-ai-co-creation-with-adaptive-analytics-3f144b42028f?source=collection_archive---------38-----------------------
让你的人工智能产品与人合作来实现他们的目标
图像来源:最大像素
在之前的一篇帖子中,我介绍了一个概念,即人工智能不会实现分析师预测的大规模财务影响。这是因为它预计“解决”(通过规定分析)的大多数问题本质上都很复杂,因此很难使用静态系统来解决。像强化学习这样的技术正在朝着构建适应不断变化的条件的系统取得进展(并且自从我发表关于这个主题的第一篇文章以来,已经取得了的进展),但是它们仍然需要问题的健壮模拟或者十亿用户规模的数据库。
幸运的是,另一个进步领域是增强人工智能或“人在回路中”人工智能。在这篇文章中,我将充实自适应分析的思想,它将重点放在每个过程中与人类一起学习,以便合作解决复杂的问题。
从接受人类会帮忙开始
构建人在回路中的自适应人工智能系统的过程将看起来不同于传统的人工智能开发过程。你的团队必须从设想一个未来的状态开始,在这个状态中,一个系统集成到业务或整个世界中来解决一个问题,在这个过程中真正地与人们协作。
当人工智能代理与人类合作者交互时,人工智能共同创造发生,人类合作者逐渐向代理提供更多信息。两者一起工作来发现和优化一个目标。
这增加了设计过程的复杂性,目标是在交付的结果中弥补这一点。我发现使用 Clayton Christensen 的 与运气 中介绍的技术,并在随后的待做的工作文献中进一步扩展,在这里是有帮助的。这涉及到一系列与规定性模型本身无关的问题:
图片作者。
今天谁参与了解决这个问题?他们扮演什么角色?
- 他们使用该系统的动机是什么?更广义地说?
- 这一过程中固有的社会制度是什么
- 你如何在不打断他们的情况下获得他们的反馈?
关于要做的工作,你有很多可以读的,在工作地图上有一个完整的框架。有了对系统中涉众的多方面目标的初步了解,您就可以开始开发一个与他们协作的系统。
接下来,使用体验设计技术来产生共鸣
适应性分析项目将从体验设计社区的技术开始。像 Ideo 的方法卡这样的技术在这里会很有帮助:
**学习:**活动分析,亲和图,流量分析
**看:**生活中的一天,墙上的苍蝇,延时录像
**提问:**叙述、认知图、五个为什么、调查&问卷
**尝试:**纸上原型,明年头条,角色扮演
反复了解利益相关者的目标
如果你只是简单地问利益相关者他们需要什么,最常见的回答是:“我不知道”。大多数人并不真正知道他们的确切目标,只是知道他们会随着时间的推移而明白。这意味着构建一个自适应的人工智能系统必须通过捕捉额外的信息,随着时间的推移不断地学习他们的目标。在上一篇文章中,我介绍了 4 种不同的反馈循环,可以发现和跟踪目标,使利益相关者的目标随着时间的推移而改变,这样你实际上仍然在帮助他们实现积极的结果。你追求的确切目标可能会有一点点变化,而你为实现目标所使用的方法肯定会改变。
构建适应能力:反馈回路
如果您接受最佳解决方案会随着时间的推移而改变,并且问题也可能会改变,那么您的系统必须衡量这些变化以真正优化。在您的系统中构建反馈回路,可以在多个层面上实现这种测量和调整。有了这些,让我们来详细看看 4 个反馈回路。
交互式循环
作者图片
中间最短的一个:交互循环。
你可以想象在本系列第 1 部分中描述的 Gong.io 系统询问为什么销售人员在电话中的某个特定点忽略或接受他们的建议(可能是建议改变语气或从介绍转到演示)。这种反应为他们提供了更多的信息,我可以在下一次互动中直接使用这些信息来帮助做出更好的推荐,或者至少是更个性化的推荐。像多臂盗匪这样的在线学习系统是代理从用户动作中学习的很好的例子。
自动循环
作者图片
移出一个,有一个自动循环,使新模型的再训练能够利用整个系统的所有交互。为了实现这个循环,应该在边缘收集所有的交互数据和尽可能多的上下文数据。然后需要对其进行聚合,并在数据湖中存储一个有代表性的集合。如果你有兴趣了解更多关于这个过程的信息,请看我关于雾计算架构的演讲。从那里,系统可以使用 MLOps 原则训练一组更好的全球模型。
分析回路
作者图片
下一个循环是对您正在获取的数据和/或向您的合作者提出建议的方式进行更改。
继续我们的销售代理支持示例:将净推销商得分调查数据与销售过程中了解到的细节联系起来,有助于了解客户对通话过程的感受。此外,如果销售人员提供反馈,说明他们不接受系统建议的原因是因为他们没有看到,系统开发团队可以改变向用户提供结果的方式。例如,如果视频聊天占据了电脑的整个屏幕,一种解决方案是将提醒推送到手机上,销售人员可以将手机放在屏幕旁边。
这个循环的关键是分析是离线进行的**,改进不仅限于模型本身,而是可以在整个系统中进行。**
补偿器
作者图片
**最后一个循环是关于扩展系统所覆盖的问题部分。这种情况通常通过传统的设计技术发生,人们在人工实验室环境中观察系统的使用。有了现在可用的技术,你可以捕捉一些同样的信息,但是要在大范围内进行。通过利用系统使用的视频记录,您最终能够扩展一些设计社区技术,而不需要手动合成数据。通过数字化这些过程,你可以改进你的系统的下一个版本。
循环过程如下:**
- 和你一起工作的合作者会告诉你一些事情,你会考虑这些数据并提出不同的建议。这个过程会重复很多次。
- 接下来,通过捕获数据并通过基于云的系统运行它来训练新的模型,你可以为你正在工作的每个人或小组制作正确的模型,并将这些模型推回到系统中。
- 在分析循环中,您与开发团队合作,自动执行不同类型的数据捕获,并让数据科学家探索和分析这些数据,以开发新的更好的模型,并将这些数据加入到现有的集合中。此外,团队开始改变用户体验,以最大化模型的每个合作者的有效性(就像你把消息推回给人们的方式)。
- 最后,最外层的扩展环包括手动捕获数据,这些数据可能永远不会直接包含在模型构建中,但旨在为人们提供所需的洞察力,以便调整正在解决的系统级问题。这使得麦肯锡在其文章中指出的业务层面财务指标得以优化。
所有 4 个循环必须协同工作,以消除 AI 值差距。图片作者。
没有这 4 个循环的协同工作,人工智能的价值差距将会持续。然而,根据我的经验,大多数数据团队都狭隘地关注交互式和自动化循环。实现更广阔的愿景需要跨数据、经验、产品设计和业务架构团队的协作。在下一篇文章中,我们将为刚刚开始开发自适应人工智能系统的组织提供一个框架和路线图。
本系列的更多内容:
- AI 值差距
- 缩小人工智能价值差距第三部分:自适应分析路线图
弥合人工智能价值差距第 3 部分:构建自适应分析的路线图
原文:https://towardsdatascience.com/closing-the-ai-value-gap-part-3-the-roadmap-to-build-adaptive-analytics-e70eaf076ce0?source=collection_archive---------36-----------------------
实现自适应分析解决方案需要建立信任,这对人工智能系统来说并不容易。这个路线图会有所帮助。
自适应人工智能系统的创建并不像将反馈回路放置到位那么简单。人类的复杂性是一个挑战。图片来源:维基媒体
在本系列的第 1 部分中,我介绍了我所谓的“人工智能价值差距”,即人工智能用例预测的价值生成与人工智能技术当前能力之间的脱节,并断言我们需要更广泛地考虑人工智能集成到的人在回路系统,从预测性&指令性转向适应性人工智能系统。
在第二部分中,我充实了实现自适应分析系统的 4 个反馈回路:交互、自动化、分析和扩展,以及它们如何共同工作来创建一个协作的人工智能,该人工智能适应每个人,并随着时间的推移不断改进以更好地解决问题。
然而,这些帖子只触及了创造自适应人工智能解决方案背后的理论,以及它们如何弥合复杂问题的人工智能价值差距。在本帖中,我将带您了解一种实用的方法,来构建为您的组织构建自适应分析产品的计划。
挑战:建立信任
自动化和分析性反馈之间的信任墙。图片作者。
当一个组织试图采用适应性分析时,他们不能简单地说“这些是反馈循环,开始!”并得到一个功能性的自适应 AI 系统。相反,他们必须小心地从最初的系统扩展,随着时间的推移,以赢得合作者信任的方式利用其他形式的反馈(即,在循环中的人,称他们为合作者有助于获得正确的心态)。当向合作者索取更多信息而不提供任何回报时,只注重改进功能系统的简单路径会很快碰壁。当从自动化进入分析反馈循环时,就会出现这种情况。
介绍自适应分析路线图
重新审视我们合作者的 JTBD 需求将使我们能够超越信任之墙。作者图片
为了避免这个问题,我们必须记住,建立信任需要认识到合作者是一个人,这带来了一系列的复杂性。换句话说,就像我在上一篇文章中提到的,我们必须支持合作者要完成的全部工作。为了建立一个使这成为可能的系统,我们必须随着时间的推移发展适应性人工智能系统,允许合作建立信任的基线。更具体地说,我们需要定义一系列计划来解决适应性人工智能系统合作者的功能、社会和情感需求。
一个自适应分析反馈框架,解决了合作者的全部 JTBD。图片作者。
在本帖中,我们将探讨上述自适应分析框架,该框架提供了一个建议的行动,以涵盖合作者在所有 4 个反馈循环中的功能、个人和社会需求。在该框架的指导下,一个组织将通过在反馈过程中扩展来解决个人和社会需求,从而绕过信任墙。你可能会发现这个框架看起来有点像棋盘游戏。在应用这个框架的过程中,我发现有一些“棋盘上的棋”可以走向成功。
开始功能:收集和利用反馈
自适应分析解决方案的主要功能是收集和分析反馈,以随着时间的推移改进系统(从而改进其交付的结果)。这个过程通常从在已部署的系统中建立交互式反馈开始,它可以是被动的(让合作者忽略您的推荐者提出的建议)或主动的(提供多个选择并让合作者选择)。当系统收集所采取的行动和这些行动的结果时,可以在自动反馈循环中利用它们来改进构成系统核心的预测和规定模型。然而,正如我们之前所讨论的,只有当合作者愿意与你分享更多信息时,从自动化到分析性反馈的步骤才是可能的,而这需要信任。
避开信任墙:通过提供配置转向个人
要继续,您必须与个人合作者建立信任。这最好在个人层面上实现,让他们感觉自己是合作者,而不是系统用户。我最近听了一个演讲,演讲人说得很好:**
不幸的是,相对于让人类为技术工作而言,并没有激励技术为人类工作。~Rohan D'Souza: 利用 Olive 改善人类的医疗保健体验
这意味着你必须开始了解你的系统内的合作者的更广泛的目标。最简单的方法是,当他们忽略系统动作时,通过提供直接反馈,允许他们指定自己的目标,但也有更微妙的方法来实现这一点。
首先,你可以让系统决定你的系统人工智能模型以前没有遇到的场景何时发生。通过使用异常检测技术或置信区间,系统可以基于当前上下文检测何时没有正常推荐会被强烈推荐。如果模型在某个时间点对任何推荐只有 30%的信心,那么你可能已经发现了一个新的场景,你的产品现在可能没有得到很好的服务。您可以更改这些场景的体验,以收集更多反馈。这将感觉更具协作性,因为系统已经交互地发现它需要更多信息,并协作地要求额外的上下文。在某种程度上,这类似于团队成员表现出的脆弱性对团队建设的影响。
在我们的销售支持系统示例中,这可能是检测到对话已经转移到几乎没有培训数据的主题(可能是解决当前产品组合中常见差距的路线图上的新产品)。如果没有这个自适应步骤,AI 可能会将此标记为不正确的信息,并警告销售主管。有了这个,系统可以将它标记为潜在的误导和潜在的新主题。如果系统随后提示讨论该主题的销售人员/销售主管提供更多信息,它可以帮助更快地将该主题添加到模型中。销售团队也会觉得自己有所贡献,未来会更愿意提供帮助,从而侵蚀信任墙。
第二,对于那些根据合作者的偏好有多种“正确的”方法来解决问题的场景,最好允许他们明确地选择一个建议而不是另一个。同样,这里最佳的信任建立体验将检测到合作者在特定的上下文中偏好特定的选择,并提示他们选择该选项作为默认选项(或者更好的是,将其设置为默认选项,并允许他们轻松撤销该设置)。一个很好的例子是 Waze 这样的驾驶应用程序检测到司机更喜欢一条更安全的路线,这条路线可能比那些让他们在繁忙的道路上左转的路线花费的时间略长。这项技术是对上述异常检测方法的补充,因为新发现的场景可能是原始建议的可配置替代方案。
一旦你创建了一个系统来学习更多关于合作者的目标,你将如何帮助那个人或团队实现他们的目标?通过改变合作者对建议的体验,这进入了个人层面的分析循环。在上一篇文章中,我提到改变推荐交付的设备或位置是这种技术的一个例子。另一个方法是改变正在使用的语言,潜在地采用一种多臂强盗的方法来为这个合作者学习最有效的语言。或者,你可以提供额外的背景信息,说明为什么推荐更容易获取。这个清单可以很容易地继续下去,因为有一整个领域的经验设计。虽然有许多方法可以实现 CX 建议,但是理解正确的方法需要每个合作者投入时间,这反过来需要信任。到目前为止,可能已经建立了足够的信任,但情况并非总是如此。迈出社会需求的最后一步会有所帮助。
社交:建立一个社区来培养合作精神
进入分析反馈循环的两条途径。图片作者。
下一层(我认为这一层真的被忽视了很多)是系统现在提供的社区建设方面。因为您正在寻找许多不同的方式来为不同的人个性化不同的模型,并且您还在捕捉他们与系统交互的方式以在个人层面上帮助他们,所以您可以通过发现行为相似的人群并将他们分组到社区来添加社交组件。
使用我们运行的例子,如果你有一组销售人员,你发现他们总是追求高接触的个人关系风格,而另一组则专注于展示他们销售的产品如何真正满足客户的业务目标。这是一个发现这些社区的分析反馈循环活动,因为分析并不用于直接改进模型本身。
一旦发现社区,您可以通过自动反馈循环返回,通过 collaborator 社区对您的模型培训进行细分来解决社交需求,collaborator 社区将培训单独的模型,以提出最符合社区风格的建议。您可以通过直接记录和建议同一社区中的合作者采取的新行动,利用在线学习方法来确定这些行动是否会带来更好的结果,从而进一步增加这种方法的交互性。
从协作者社区开始,通过分析循环中的个人需求往回移动,您可以设置由社区成员组成的焦点小组。他们将更愿意与分享他们经验的人分享见解,而不是与经验设计团队分享,从而打破最后的信任墙。然后,您可以使用这些见解来改善协作者体验,就像我们在引入社交需求层之前讨论的那样。
在这一点上,您的合作者很可能愿意分享更多的数据,使您能够更好地理解问题空间,并克服性能停滞。例如,通过让合作者的公司分享客户终身价值售后信息,您可以开始优化销售流程,以最大化长期回报,而不是二元销售/不销售指标。在我们的驾驶应用程序示例中,您可以访问合作者的日历,以建议优化他们的时间表,从而最大限度地减少驾驶时间。
利用社区检测来释放社会需求和分析反馈回路。图片作者。
进入体验式循环扩大了交付的价值
获取这些新信息为系统提供了扩展目标的第一次机会。系统可以尝试优化整个销售团队的绩效,而不仅仅是查看销售人员的绩效。根据与客户的最初几次互动,谁是该交易的最佳销售人员?可能会有更好的销售风格,因此系统可以向销售领导推荐理想的风格匹配,而不是仅仅试图帮助一个人。这给了我们进入体验式循环的第一步,从整体上改变了产品与合作者互动的方式。它还极大地提高了可能的优化水平,缩小了 AI 值的差距。
在个人层面,该系统可以通过构建 API 经济或插件模型扩展到一个生态系统中,在该模型中,您的合作者可以自己构建模块来补充该系统并针对其特定场景对其进行改进。这些可以在其他合作者之间重复使用,以在你的自适应人工智能系统之上创建一个产品生态系统。利用合作者的这些直接贡献可以扩大体验循环。
在社交层面,您必须了解协作者社区,以创建社区参与战略,将他们联系在一起,帮助他们互相帮助,提高他们对系统的使用。例如,如果合作者彼此离得很近,举办活动让这些人聚在一起谈论他们对产品的使用。通过添加这一层,您不仅投资于提高您的采用率,而且还帮助这些人相互协作。
指导自适应人工智能系统设计的自适应分析框架的完整步骤。图片作者。
从框架到路线图,快速入门
即使遵循本文中介绍的自适应分析框架,也可能感觉有很多复杂性。的确,这些是很难解决的问题,接受它们并不是出于真心。然而,我非常强烈地感觉到,任何一个团队,如果希望开始自适应分析,但不了解如何*,可以遵循一套规定的步骤开始旅程。这一系列步骤形成了一个路线图,走过曲折的道路,到达您的组织可以开始执行一系列计划以帮助缩小人工智能价值差距(并获得您的 1T+美元收益)的点。*
开始适应性分析并缩小人工智能价值差距的路线图。图片作者。
路线图中的阶段包括:
- 首先确定您想要追求的高价值适应性用例。对于这一点,我们可以从我在第一篇文章中用来量化 AI 价值差距的麦肯锡确定的行业用例开始。
- 下一步是为你的合作者确定真正的目标。在这里,您可以利用来自待完成工作、工作地图和设计思维的技术。你带来了真正的客户,并在你的组织内的一些必须一起工作的筒仓之间架起了桥梁,并帮助他们通过他们的合作者的观点来理解问题。
- 这将帮助我们确定每个初始反馈循环的具体形式。自适应的、自动化的、分析的和经验的循环将基于用例的细节看起来非常不同。
- 从那里,我们可以利用自适应分析框架来生成特定的计划和工作流,以构建系统的 MVP。
- 在这一点上,我们必须找到合适的技术来实现这一自适应分析愿景,以便我们能够分配资源、评估工作并开始实施。这将是本系列第四篇也是最后一篇文章的主题。
像往常一样,我把这些文章放在这里,激发一些想法,开始一场对话。请不要犹豫,直接联系我们或回复我们。感谢阅读!
用于对 NoSQL 的层次结构建模的闭包表模式
原文:https://towardsdatascience.com/closure-table-pattern-to-model-hierarchies-in-nosql-c1be6a87e05b?source=collection_archive---------33-----------------------
理解大数据,大数据建模模式
如何利用关系世界的最佳实践在 NoSQL 建立层级模型
介绍
有时我们会遇到这样的情况,当我们需要对不同复杂程度的层次结构进行建模时,却不确定如何以最有效、最可靠和最灵活的方式正确地完成这一任务。让我们回顾一下为我们提供一些答案的数据建模模式。
问题陈述
假设我们有一个深度参差不齐的层次结构,如下图所示:
作者图片
从功能的角度来看,我们需要涵盖以下主要情况:
查询层级:
- 查询一个子树,最好达到一定的深度级别,像直接下级以及达到一定级别的后代
- 查询该节点的所有祖先
修改层次结构:
- 添加/删除层次结构中的节点
- 更改层次结构的布局—将子树从一个位置移动到另一个位置(从一个父节点移动到另一个父节点)
物联网商业案例驱动的高级需求:
- 高效管理****森林—大量的树,每棵树的节点数和最大深度不一定很大,但树的数量可以增长到几十万甚至上百万
- 管理进入短期关系的树的节点。因此,有必要跟踪实际关系发生的时间段。
要使用的核心模式
我们也可以利用关系世界中的一些模式来研究 NoSQL。让我们考虑一下闭包表,它通常被低估,但却有很多优点,特别是:
- 高效的子树查询
- 管理短期关系的可能性
- 存储改变关系的历史
闭包表模式
根据闭包表模式,除了具有适当属性列表的主实体之外,我们还有一个附加实体,用于存储各个项目之间的层次关系。
例如,如果我们有一个雇员的从属层次结构,我们将有一个包含雇员信息的实体和一个专门存储从属关系的闭包表:
作者图片
该模式的主要构建块是一个额外的结构(表),用于保存树关系——从祖先到后代的每条路径的一组节点对,包括到自身的路径:
作者图片
基本结构可以扩展到有效地覆盖与子树选择的有限深度相关的更复杂的场景;找到所有的树叶;树根和有效时间范围:
作者图片
关于如何使用这种结构的更多细节包含在两篇好文章中。一个很好的例子就是这里的。
NoSQL 的闭包表实现
NoSQL 很大,让我们考虑两个 NoSQL 存储——Cassandra 和 MongoDB 作为 NoSQL 世界的两个很好的代表,它们是列族和面向文档的存储。
因为我们考虑 NoSQL,我们需要遵循它的建模哲学:有一个清晰和狭窄的用例,以更准确地使用模型。
物联网用例描述
输入:
- 有大量的边缘设备,产生遥测数据。
- 边缘设备在工作会话范围内工作;
- 在每次会议期间,他们形成一个关系层次
查询需求:
对于特定时间范围(特定会话 id)和特定边缘设备:
Q1 :读取设备子树(其下属设备列表以及它们之间的关系)
Q2 :读取设备的遥测数据以及所有下属设备的遥测数据
卡桑德拉溶液
为了实施上述物联网用例,提出了以下 Cassandra 数据模型(Chebotko 图):
作者图片
这里,边缘连接表起到了封闭表的作用,并存储了层次关系,而边缘遥测保存遥测数据本身。
边连接表可以用来有效地回答 Q1 查询。回答了 Q1 问题之后,我们就可以有效地回答 Q2 问题了。以便这两个查询都被这两个实体有效地覆盖。
看看链接后面的示例代码片段。
MongoDB 解决方案
使用同样的方法,我们可以在 Mongo 上创建一个平面集合。在这里,我们可以利用设备祖先 id、会话 id 和距离字段的复合索引,如下所示:
祖先查询注意事项
所描述的解决方案很好地涵盖了上述确切的物联网用例,但是如果我们想要查询特定节点的祖先列表而不是子树,我们将需要通过新对象来扩展模型:
- 对于 Cassandra,我们需要引入并正确维护另一个边连接(反转)表,该表具有相同的属性列表,但键的配置不同(交换了
device_ancestor_id
和device_descendant_id
) - 对于 MongoDB,我们需要另一个索引:
db.edge_connection.createIndex({device_descendant_id:1, session_id:1, distance:1})
修改层次结构
上面描述的方法展示了在 Cassandra 和 Mongo 上实现的数据模型如何满足查询树的主要需求。但是层次结构的修改呢?
嗯,首先,现有的层次结构修改是完全可能的,它只是需要一些逻辑来实现(超出了本文的范围,但你可以谷歌一下)。
另一方面,在我们的物联网用例中,我们假设不需要修改:一旦树在会话范围内形成,它的结构将在会话结束前保持不变。并且节点的新组合在新会话的范围内形成树。
结论
在文章中,描述了闭包表模式如何在 Cassandra 和 MongoDB 等 NoSQL 存储上有效地实现。
还有其他模式可以用来建模层次结构,它们将在下一篇博客文章中描述。敬请期待:)
浓缩咖啡用滤布
原文:https://towardsdatascience.com/cloth-filters-for-espresso-d5038f53605f?source=collection_archive---------30-----------------------
咖啡数据科学
超越纸过滤器;高级论文理论第四部分
在过去两年多的时间里,纸质过滤器一直是整个浓缩咖啡社区的一个有趣的实验。我记录了一些实验来帮助理解它们是如何运作的。这项特殊的工作开始比较漂白和未漂白的纸过滤器,但它把一个急转弯变成了布过滤器。
所有图片由作者提供
在试验纸质过滤器时,我最终试验了布料过滤器。我在一个视频中受到了詹姆斯·霍夫曼的影响,这个视频讲述了如何使用布料过滤器进行倾倒。今年夏天我的前几个实验没有引起我的注意,部分原因是因为其他一些变量无处不在。
左边:一个未切割的新布过滤器。右边:被切到一边用了十次之后。
然而这一次,一切都在掌控之中,我被吹走了。这一枪打得又快又准。最好的部分是布过滤器也更容易清洗!
我所有的镜头都是劈烤、断奏捣实镜头,中间是布滤片,底部是布或纸滤片。我也使用压力脉冲来拍摄我所有的照片。
镜头性能指标
我将这些定义放在这里,因为在这一节之后,我将使用这些指标评估不同数量的纸质过滤器。
我使用了两个指标来评估镜头之间的差异:最终得分和咖啡萃取。
最终得分是 7 个指标(强烈、浓郁、糖浆、甜味、酸味、苦味和余味)记分卡的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难,会影响最终得分。
使用折射仪测量总溶解固体(TDS ),该数字用于确定提取到杯中的咖啡的百分比,并结合一杯咖啡的输出重量和咖啡的输入重量,称为提取率(EY)。
漂白与未漂白纸过滤器
我从一个比较漂白和未漂白过滤器的实验开始。我瞄准了十对镜头,我看了一些度量标准。我看不出味道或提取率有什么不同。
我甚至观察了不同的烘焙方法,仍然没有明显的模式。
然而,当看拍摄时间时,有一个模式。T10 表示在量杯中达到 10 毫升所需的时间(通常一杯是 20 至 30 毫升的液体)。它受到我如何记录镜头的影响,但这不会从一个镜头到下一个镜头有太大的变化。漂白的 T10 时间比未漂白的长,总时间也比未漂白的长。因此,我更喜欢未漂白的。
我计算了所有的差异,我打算看看这些过滤器如何清洗,但我得到了布料过滤器的侧道。在 10 对样本中,我没有通过 t 检验计算 p 值。
拍摄后:
布与纸过滤器
关于布料过滤器,首先要知道的是它们会缩水。与极地特快中流浪汉使用的袜子过滤器不同,这种过滤器需要切割成篮子大小。我在使用之前洗了几次,最近,我把它放在一个空的咖啡篮里,在我用另一个篮子拍照之前,我把它洗了一遍。然后我让它变干,在切之前我会这样做几次。
这是底部有布过滤器和底部有纸过滤器的一个镜头的流程图。
典型的重量和流量剖面。布料的脉动要少得多,因为它流动得很快
我对比了几次布和纸,有一个清晰的图案。布过滤器产生了更好的味道和更高的提取率。
跨越不同的烘烤巩固了这一立场。
看看 T10 和总时间,布过滤器比纸过滤器跑得快。我很好奇这在多大程度上模拟了 2020 年初的工作,他们发现更粗的研磨但更快的拍摄产生了比他们想象的更高的提取率。
这里是更高的统计水平。我还包括 TCF 或时间覆盖过滤器。我发现这是一个度量标准,可以很好地指示预输注应该持续多长时间。在这些结果中,我试图将预输注保持为配对之间的常数。
选择哪种布料
我用两块布做了实验: [Hario](http://Hario Siphon Cloth Coffee Filter... https://www.amazon.com/dp/B000IGOTW6) 和 [Masukaze](http://Diguo Coffee Syphon Cloth... https://www.amazon.com/dp/B00M5SRPCG?ref=ppx_pop_mob_ap_share) (在帝国咖啡过滤器下)。后者稍微便宜一些。Hario 的味道得分稍微好一点,但提取率似乎很低。
就时间而言,Masukaze 过滤器比 Hario 过滤器运行得快得多。
再次,这里是更高的统计水平。
意式浓缩咖啡的粗糙层理论是,它让水流在整个过程中重新平衡。由于布过滤器的厚度,我认为它也在做类似的事情。我认为这也给了液体更多的空间,这样过滤孔的限制就不会引起沟流。
奇怪的是,一个布过滤器可以让子弹跑得更快,我想知道这是否是更高提取率的贡献者。
在重复使用方面,我非常喜欢重复使用,所以我也用布过滤器取代了我使用的中间过滤器。
我不知道布过滤器或纸是否可以在家庭咖啡师之外经常使用,但它们的功能可以用来改善过滤篮。没有理由过滤篮不能有允许它更类似于纸过滤器或布过滤器的结构。我原以为IMS superior会是这种情况,但是我没有注意到这样的改进。
如果你愿意,请在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡照片和浓缩咖啡相关的视频。你也可以在 LinkedIn 上找到我。也可以在中关注我。
我的进一步阅读:
浓缩咖啡系列文章
工作和学校故事集
个人故事和关注点
乐高故事首页
摄影启动页面
用纸质过滤器改进浓缩咖啡
纸质过滤器如何提高浓缩咖啡的流量
意式浓缩咖啡的金发滤纸
为浓缩咖啡重复使用纸质过滤器
有效切圆,为意式浓缩咖啡添加滤纸
基于 DeepFashion 数据集和 Fastai 的服装分类
原文:https://towardsdatascience.com/clothes-classification-with-the-deepfashion-dataset-and-fast-ai-1e174cbf0cdc?source=collection_archive---------6-----------------------
时尚 AI
一个关于我如何开始清理我的衣柜并最终训练一个神经网络的故事
图片由罗曼·桑波斯基根据 Shutterstock.com的许可使用
1 月 1 日是整理冬装的好时机。一个月前,当我走近我的衣柜时,我就是这么想的。叠毛衣、袜子和围巾的单调过程本质上是相当沉思的,并导致许多发现。我有三件同样款式的粉色衬衫。这一发现帮助我认识到,我不可避免地需要通过增加多样性和减少我拥有的物品的冗余来优化我的时装库存。自然,目标应该是将我的衣柜内容建模为一个图,该图将包含衣服项目、它们的类型(毛衣、裤子等)。)、属性(面料、款式、颜色等。),以及关系(两个项目是否可以组合在一个 look 中)。在这篇文章中,我写的是我创建数据集的方法,特别是如何识别随机物品的服装类型。
本文包含以下部分:
- 数据
- 模特培训
- 模型评估
- 如何将预训练的模型从 Fastai 加载到 PyTorch
- 摘要
即使我多年来一直在使用 Keras 进行深度学习,但这次我决定尝试一下 PyTorch 和 Fastai。文章中使用的完整代码可以在这里找到。
数据
为了对我衣柜里的物品进行分类,我需要一个经过训练的模型来完成这项任务,为了训练这样一个模型,我需要数据。在这个项目中,我使用了由香港中文大学多媒体实验室收集的 DeepFasion 数据集,这是一个用于服装类别和属性预测的大规模服装数据库。
深度时尚数据集
分类基准于 2016 年发布。它评估了 FashionNet 模型在预测 46 个类别和 1000 个服装属性方面的性能。原文请参考深度时尚:用丰富的注释支持健壮的服装识别和检索,CVPR 2016 。
DeepFashion 数据库包含几个数据集。在这个项目中,使用了类别和属性预测基准。该数据集包含来自 46 个不同类别的 289,222 幅不同的服装图像。
训练标签以下列格式存储在 train_labels.csv 中:
训练数据文件
训练数据文件包含图像和标签的位置。标签存储为字符串对象,每个图像一个标签。
我们可以使用 from_csv 方法将数据从 train_labels.csv 加载到 ImageDataLoaders 类。
我正在使用一种叫做预调整的 Fastai 数据增强策略。它首先将图像调整为较小的方形。由于正方形图像可以在 GPU 上处理,这使得接下来的所有放大操作都可以更快地进行。然后我们可以对每一批数据进行扩充。batch_tfms 顺序执行所有增强操作,如旋转和缩放,最后进行一次插值。这种增强策略将允许我们实现更好的增强图像质量,并由于在 GPU 上的处理而获得一些速度。
让我们看看数据集中的一些图像。
带标签的训练图像
我们还可以通过向上面的 show_batch 方法传递 unique=True 来检查增强图像的外观。
增强图像
正如我们所见,图像在增强后保持了质量。
模特培训
在这个项目中,我使用的是预先训练好的 ResNet34 模型。我尝试了更深层次的架构,但是它们并没有带来显著的改进。DeepFashion 数据集的主要挑战是标签的质量。例如,上图显示了两件商品:衬衫和短裤,但它只有一个“衬衫”标签。这样,模型将不可避免地受到噪声的影响。
为了使迁移学习起作用,我们需要用一个新的线性层替换网络的最后一层,该层包含与我们的数据集中的类的数量相同的激活数量。在我们的例子中,我们有 46 个服装类别,这意味着在我们的新层中有 46 个激活。新添加的层随机初始化权重。因此,我们的模型在被训练之前将具有随机输出,这并不意味着该模型完全是随机的。所有未改变的其他层将保持与原始模型相同的权重,并且将擅长识别一般的视觉概念,例如基本几何形状、梯度等。因此,当我们训练我们的模型能够识别衣服类型时,我们冻结了除最后一层之外的整个网络。这将允许我们优化最后一层的权重,而不改变更深层的权重。
当我们调用 learn.fine_tune()时,我们冻结整个网络,并为一个时期训练新创建的层的随机初始化的权重。然后我们解冻网络,按照我们指定的次数(在我们的例子中是两次)一起训练所有的层。这就是为什么我们在输出中看到了一个额外的纪元。
早期评估
早期评估允许我们检查早期阶段的学习进度,并在我们花费大量时间训练模型之前发现我们方法中的错误。有多种方法可以查看训练神经网络所产生的结果。为了快速获得印象,我们可以看看最常混淆的类:
正如我们所看到的,网络经常混淆“上衣”和“衬衫”,“连衫裤”和“连衣裙”,“t 恤”和“衬衫”。即使是人类也会犯这样的错误。这样我们就可以早期评估我们的网络是否学习到了正确的模式。
观察误差的另一种方法是画出最高亏损。
顶级损失。早期评估
如上所述,原始标签是有噪声的。我们的模型正确地分类了一件连体衣、两条裙子和一件连衣裙,而在原始数据集中,这些项目有错误的标签。
学习率探测器
现在,让我们浏览数据加载器中的数据,并逐渐增加每个小批量的学习率,以观察损失值如何随着学习率的变化而变化。我们的目标是找到最有效的学习速率,使网络更快地收敛。学习率在损失曲线的最陡斜率点处具有最佳值,因为这意味着损失下降得更快。极值点(最小值和最大值)和曲线的平坦部分对应于不允许网络学习的学习速率,因为这些点处的损失没有改善。
损失曲线
在我们的例子中,损失曲线的最陡点是学习率等于 0.005。这个学习率我们将用于进一步的培训。
在对模型进行 3 个时期的训练后,我们获得了 0.697 的准确度,这比默认学习率下的 0.694 有所提高。
区别学习率
在训练了网络的所有层之后,我们需要再次检查学习率,因为在几批训练之后,网络学习的速度变慢,并且我们冒着以高学习率超过损失函数的最小值的风险。因此,学习率需要降低。
当我们在三个时期的训练后绘制损失曲线时,我们可以看到它看起来不同,因为网络的权重不再是随机的。
三个时期后的损失曲线
我们没有观察到与权重从随机更新到减少损失的点相关联的这种急剧下降。曲线的形状看起来更平坦。在未来的训练中,我们将采用一系列的重量,从减少的点一直到损失再次开始增加的点。
如前所述,从预训练模型转移的层已经擅长识别基本的视觉概念,并且不需要太多训练。然而,负责识别特定于我们项目的复杂形状的更深层次将受益于更高的学习速率。因此,我们需要对第一层使用较小的学习速率,对最后一层使用较大的学习速率,以允许它们更快地进行微调。
我们可以清楚地看到我们的网络在学习上取得了进步。然而,很难说我们是否需要继续训练,或者停下来不要过度适应模型。绘制培训和验证损失图可以帮助我们评估是否需要继续。
培训与验证损失
我们可以看到,尽管培训损失仍在改善,但验证损失不再改善那么多。如果我们继续训练,我们将增加训练和验证损失之间的差距,这将意味着我们过度拟合我们的模型。因此,我们最好现在停止训练,进入下一步,评估。
模型评估
在前面的步骤中,我们能够在验证数据集上实现 70.4%的顶级准确性。如果我们绘制验证准确度,我们可以看到它是如何随着每个时期而提高的。
每个历元的最高验证精度
对训练数据集的评估
首先,我们将查看训练数据集上的预测,以估计我们是否仍有较高的偏差。
对训练数据的评估
训练数据集上的预测看起来不错。我们的模型捕捉到了主要概念。通过改进标签和清理数据,可以实现进一步的改进。
对测试数据集的评估
现在让我们加载测试数据,并检查模型在其上的表现。
测试数据的评估
模型 Top-1 测试精度为 70.4%。它错误地分类了一些对象,但仍然非常接近我们在验证集上得到的结果。
原始论文 DeepFashion:通过丰富的注释实现强大的服装识别和检索的作者,2016 年 CVPR使用前 3 名和前 5 名的准确度进行评估。
DeepFashion:通过丰富的注释实现强大的服装识别和检索,CVPR 2016
为了使我们的结果具有可比性,我将使用相同的指标。
我们模型的前三名准确率为 88.6%,比基准准确率高 6%,我们模型的前五名准确率为 **94.1%,**比基准准确率高 4%。这不应该令人惊讶,因为原始论文的作者使用了 VGG16 架构作为主干,这是一个功能较弱的模型。
对用户指定数据集的评估
最后,我们将检查模型如何处理我的图像。我用智能手机相机拍了 98 张自己衣服的照片。让我们加载图像,并检查模型是否可以正确地对它们进行分类。
该模型在用户指定数据上的 Top-1 准确率为 62.4% ,低于在 DeepFashion 数据集上的准确率。然而,对于 46 类分类模型来说,它仍然是好的。
用户数据集中的图像与最初训练模型时使用的图像完全不同。例如,用户图像只显示一件衣服,而 DeepFashion 数据集中的图像显示一个人穿着一件衣服,这使得缩放衣服更容易。用户数据集中几乎所有的裤子都被归类为短裤,因为模型很难估计其相对于人体的长度。尽管如此,该模型学会了主要概念,并可用于各种时尚背景。
如何将预训练的模型从 Fastai 加载到 PyTorch
训练完模型后,我们可能想要在没有 Fastai 安装的推理机器上运行它。为此,我们首先需要保存模型及其词汇表:
torch.save 保存预训练模型的权重。它使用 Python 的 pickle 实用程序进行序列化。要在 PyTorch 中运行模型,我们需要加载权重并重新定义模型:
将快速人工智能模型加载到 PyTorch
请注意,这一次我们需要在运行预测之前调整图像的大小并使其正常化。Fastai 库存储关于要在学习者中应用的变换的信息,但是当我们在 Fastai 之外运行模型时,我们需要首先变换图像。
之后,我们可以使用我们定义的类来运行预测:
摘要
在本教程中,我展示了如何使用 Fastai 库和 DeepFashion 数据集训练一个用于服装类型识别的 ResNet34 模型。我们已经看到,我们可以训练一个模型,对于前 3 名的准确性,它将超过当前基线 6%,对于前 5 名的准确性,它将超过当前基线 4%。我们对我自己的图像进行了评估,发现除了对比例敏感的项目(短裤或裤子问题)之外,该模型对项目进行了正确分类。模型性能可以受益于提高训练标签的质量和增加图像的多样性。
这只是我心目中时尚项目的开始。关于属性、图案和织物识别的文章将在后面。敬请期待!
感谢您阅读这篇文章!如有任何问题,请在下方留言或通过 LinkedIn 联系我。
如果你喜欢这篇文章,这里有一些你可能喜欢的其他文章:
Cloud Bigtable:它是什么,为什么有一天我们会需要它?
原文:https://towardsdatascience.com/cloud-bigtable-what-is-it-and-why-might-we-need-it-one-day-b9ec2a032854?source=collection_archive---------43-----------------------
全能的 NoSQL 数据库为移动网站提供实时分析,以改善客户体验
汤姆·霍尔姆斯在 Unsplash 上拍摄的照片
最初是谷歌的网络搜索索引存储系统。于 2015 年通过谷歌云平台作为公共服务提供,目前为 Spotify、谷歌地图和谷歌搜索等一些最著名的网络和移动应用程序提供支持。这就是云 Bigtable,它既不适合复杂的连接、即席交互查询,也不适合支持在线事务处理(OLTP)系统。
那么它是什么,为什么有一天我们可能需要像 Cloud Bigtable 这样的大规模数据库呢?
你会学到:
- 现实世界的挑战:网站速度和个性化客户参与
- 云 Bigtable 入门:定义、适合与不适合
- 云大表的关键概念
现实世界的挑战:网站速度和个性化的客户体验
在进入技术层面之前,我认为从业务背景入手,揭示客户的期望如何推动处理大量实时分析工作负载的需求是有益的。所以我们开始吧!
顾客对即时满足和个性的期望
很难不注意到我们的客户总是忙忙碌碌,没有什么耐心,不会满足于不那么令人惊叹的客户体验。以下是客户在访问任何移动网站或应用程序时所期望的两件事。
- 我现在就要
- 我希望它能根据我的品味和喜好个性化
根据德勤在 2020 年的一项研究,网站速度仅仅提高 0.1 秒,就可以产生 7%的潜在客户,增加近 10%的支出。
另一份 2019 市场研究报告称,63%的智能手机用户更有可能从那些移动网站或应用程序为他们提供相关推荐的公司购买他们可能感兴趣的产品。
简而言之,您的移动应用程序加载的速度和显示内容的个性化程度极大地影响了您的客户的参与度,以及他们是否决定在您的网站上购买。
处理大量实时分析工作负载的数据库功能
但是个性化对移动网站和应用程序意味着什么呢?
Spotify 音乐应用程序就是一个很好的例子。只要你打开 Spotify,主页就会显示个性化内容,如最近播放的歌曲和与你的用户档案相关的热门节目,并推荐每日混音和发现每周音乐,以帮助你根据以前听过的歌曲发现新音乐。
另一个常见的用例是电子商务网站。您可以轻松找到个性化的产品推荐,如“您可能喜欢的其他人”、“经常一起购买”和“为您推荐”。
这是棘手的部分:所有这些必须在几毫秒内自动发生。因为生命太短暂,不能让我们宝贵的客户等待,在这个即时满足的时代,哪怕一秒钟都感觉像是永远,我说的对吗?
但是,构建如此强大的移动网站或应用程序来自动处理大量实时分析工作负载,以实现个性化推荐,从来都不是一件容易的事情。
信不信由你,这一切都始于一个数据库,或者我敢说,一个非常特殊类型的数据库,看起来一点也不像我们太熟悉的关系数据库。以下是理想数据库必须提供的关键功能。
作者图片
当谈到提供所有 7 个关键功能的现有数据库时,两个最著名的例子包括 Amazon DynamoDB 和 Google Cloud Bigtable。今天我们来探索一下云 Bigtable,把 Amazon DynamoDB 留到以后再说。
十秒钟外卖
作为强大的 NoSQL 数据库家族中的一员,Cloud Bigtable 提供了强大的功能来支持移动网站或应用的个性化、速度和自动化。
云 Bigtable 入门
Cloud Bigtable 是一个稀疏填充的表,可以扩展到数十亿行和数千列,使您能够存储数 TB 甚至数 Pb 的数据。
—来自 谷歌云
首先,需要注意的是,Cloud Bigtable 不是一个关系数据库。它既不支持 ACID 事务,也不支持 SQL 查询。这使得云 Bigtable 不适合 OLTP 和 OLAP 系统。
此外,Cloud Bigtable 非常强大,有时甚至会大材小用,或者比小规模应用程序或玩具项目所需的成本更高。
如果你想知道你是否需要云 Bigtable,这里有一些我从 John J. Geewax 的书"Google Cloud Platform in Action"中总结的有用的考虑。
作者图片
十秒钟外卖
云 Bigtable 是一种大规模数据存储解决方案,以查询复杂性和成本为代价,提供了极高的速度和高吞吐量。
云大表的关键概念
作为一个为支持大规模分析工作负载而构建的 NoSQL 数据库,Cloud Bigtable 有许多独特的特征,使其有别于常见的关系数据库。
在所有特征中,这里有两个我们至少应该理解的关键概念。
使用 3D 地图结构优化数据处理
作者图片
看看上面的图片,你能看到什么?
该图展示了如何在云 Bigtable 表中以二维(行和列)存储数据。嗯,非常类似于关系数据库,对吗?
不要过早下结论。事情比看起来稍微复杂一些。所以让我解释一下这是怎么回事。
第一维:行
每个行由单个行关键字唯一标识或索引。简单地说,行键类似于关系数据库中的主键。存储在 Cloud Bigtable 中的数据自动按字母顺序按行键排序(也称为按字典顺序排序),这使得跨表搜索和扫描速度更快。
第二维:列
相关数据然后被分组到列族中。例如,用户的基本简档信息(例如姓名、电子邮件地址、移动电话号码)可以被分组到一个家族中,而用户的评论可以被分组到另一个家族中。其目的是将所有频繁检索的信息收集在同一位置,从而提高查找效率。
同一系列下的每一列都有一个唯一的列限定符。与行键类似,相同系列中的列也按照它们的列限定符按字母顺序排序,以提高查询速度。
关于云 Bigtable 列,有两点需要注意。
- 同一表中的两个柱族不应共享同一个族名。此外,同一系列中的任何两列都不应共享同一个列限定符。因此,每个列都由列族名和列限定符的组合唯一标识。
- 如果某一列在特定行中不包含任何数据,则它不会占用任何空间或存储空间。这就是为什么我们说云 Bigtable 表是稀疏的。
现在我们知道行和列是云 Bigtable 中 3D 地图结构的前两个维度。但是第三维度在哪里呢?让我们找出答案。
第三维度:细胞
作者图片
这可能需要一点想象力,但上面的图片可能会帮助你。如果我们通过特定的行键进行查找,并放大到特定的列,通常我们会期望找到单个值。
但是在 Cloud Bigtable 中,我们会在不同的时间点发现值的不同版本。每个有时间戳的版本被称为一个单元**,这是我们正在寻找的第三维。**
那么,为什么要有这个第三维度,让事情变得复杂呢?
请记住,存储在云 Bigtable 中的数据预计会随着时间的推移而快速变化。例如,客户可能会点击查看某个产品,然后迅速转到下一个产品。用户可能听了一首歌 10 秒钟,没有找到适合她心情的曲子,然后按下 Next。
但是我们希望很容易地看到连续数据的历史,比如客户从上周开始浏览了哪些产品,用户昨天听了哪些歌曲,客户的音乐类型是如何演变的。
有了第三个维度,企业可以有效地回到过去,提取相关的过去互动进行分析,并在几毫秒内显示个性化的内容或建议。这使得 Cloud Bigtable 成为强大的数据库,为移动网站或应用提供速度和个性化支持。
注意,云 Bigtable 的性能严重依赖于模式设计和行键的选择。如果您想了解更多关于在 Cloud Bigtable 中设计模式和选择合适的行键的最佳实践,请不要忘记查看这个 Google 文档。
利用分布式处理基础设施提高性能
实例、集群和节点
诚然,我花了一段时间才理解云大表基础设施是如何工作的。不要惊慌,因为我不会用太多的技术细节来烦你。为了让事情尽可能容易理解,以下是你最起码需要知道的。
云大表基础设施有 3 个关键组件:实例、集群和节点。
- 当我们说部署云 Bigtable 数据库时,它意味着创建一个实例。它是一个巨大的容器,容纳着数据库的所有部分。一个实例可以包含一个或多个集群。
- 每个簇表示存储数据的特定位置。在每个集群下,可能有一个或多个节点。
- 每个节点负责管理数据在数据库中的写入和查询。
性能&可用性影响
作者图片
场景 1: 1 个集群,1 个节点
场景 1 展示了最简单、最便宜的云 Bigtable 实例。您可以部署一个包含 1 个集群和 1 个节点的实例。但是等等!因为你能并不意味着你应该。
对于一些实验或(相当昂贵的)宠物项目来说,拥有一个集群和一个节点可能没问题。但是,如果前端应用程序生成和查询的数据太多,单个节点可能很容易过载,速度会大大降低。此外,只有一个集群就像把所有的鸡蛋放在一个篮子里。如果集群由于技术问题变得不可用,相关的应用程序也会失败。
场景二:1 个集群,N 个节点
简单地在同一个集群下添加更多的节点将把我们从场景 1 带到场景 2。有了这些额外的节点,您可以处理更多的数据读写请求,从而获得更好的性能。这对于扩大规模以应对不断增长的数据处理需求特别有用。
但是,拥有单个集群意味着所有数据仅在单个区域中可用。如果在该地理位置发生任何事故(例如停电),您的数据库和应用程序也会宕机。毫无疑问,这是一个需要考虑的关键风险,因为我们都希望我们的移动网站或应用程序能够连续运行而不出现故障,我说的对吗?
场景三:N 个集群,N 个节点
场景 3 是云 Bigtable 发挥其全部威力的地方。有了多个集群,对一个集群中的数据所做的任何更改都会在几秒钟或几分钟内复制到位于不同地带或区域的其他集群中。如果一个集群完全失败,其他集群中的数据随时可用。另一个群集可以快速承担工作负载,以便我们可以照常开展业务。这种情况的不利方面是钱!让多个集群并行运行当然需要一些巨额的日常开支。
十秒钟外卖
尽管云 Bigtable 非常强大,但它也有其独特之处,需要我们从不同的角度思考如何设计和管理数据库以提高性能和可用性。
离别的思绪
曾几何时,我们需要处理的数据只有千兆字节多一点,而且可以很好地放入闪存驱动器。仅在几年前,一个需要 1tb 存储的数据仓库就足以让人惊叹。然而,如今企业每天生成数十亿字节的数据非常普遍。毫不奇怪,我们的客户也开始期待企业将如此大量的数据转化为个性化内容,以获得更好的移动网站和应用体验。
顾名思义,云 Bigtable 旨在成为强大的数据库,为移动网站和应用程序提供大量实时分析工作负载。虽然这篇博客文章仅仅触及了云 Bigtable 的皮毛,但我希望我已经让您对这个独一无二的 NoSQL 数据库有了一两个新的认识。
如果你正在读这封信,感谢你抽出时间。请随时在 LinkedIn 和 T2 Twitter 上与我联系,并告诉我下次如何做得更好。保重,保持安全,继续牛逼!
原载于 2021 年 3 月 22 日 https://thedigitalskye.comhttp://thedigitalskye.com/2021/03/23/cloud-bigtable-what-is-it-and-why-might-we-need-it-one-day/。
云数据仓库:过去、现在和未来
原文:https://towardsdatascience.com/cloud-data-warehousing-the-past-present-and-future-2fad19ee64bf?source=collection_archive---------14-----------------------
意见
领先数据仓库提供商分析
本帖所有图片均由作者创作
那是 2013 年,我的工作是向印度最大的摩托车制造商销售车队管理解决方案,但只有当他们首先投资一个新的数据库系统,使我们的解决方案可行时,这笔交易才会成功。
我与一家合作伙伴供应商一起,将 SAP Hana 作为一款现代数据库解决方案进行推介,该解决方案非常适合事务性和分析性工作负载。
当时,大规模收集、存储和分析数据需要大量投资,并且只有预算为几十万美元和几个月人力资本的企业才可行。
快进到现在,对于一个认真构建数据文化的组织来说,投资数据仓库是一个赌注。毫不奇怪,这种转变是由市场上发生的创新推动的,这些创新带来了更好、更经济的数据仓库解决方案。
在探索云数据仓库工具市场之前,有必要了解一下为什么公司需要数据仓库以及导致其快速采用的因素。
数据仓库的需求和优势
由于专门构建的 SaaS 工具的激增,数据和数据源比以往任何时候都多。与此同时,大大小小的组织都认识到,提供由数据驱动的个性化体验是吸引和留住客户的唯一途径。
只有当团队能够分析和激活从每个客户接触点收集的数据时,这才成为可能,虽然有 SaaS 产品套件可以帮助实现这一点,但在仓库中存储一份数据副本可以打开更多的可能性。此外,不存储数据的副本会导致供应商锁定、效率低下,并让需要临时分析或特定数据集在他们所依赖的外部工具中可用的团队感到沮丧。
现在让我强调一下采用数据仓库的明显好处。
经济实惠且易于实施
基于使用的定价以及存储和计算的分离(详见下文)使得各种规模的企业采用数据仓库变得极其经济实惠,即使数据量有限且数据源很少。事实上,大多数数据仓库供应商为存储和分析提供试用和免费的月度配额。
就实现数据仓库而言,您可以在几个小时内(或者几分钟,如果您以前做过的话)完成一个数据仓库,而不需要编写任何代码。使用 ELT 工具,如 Fivetran 或 Airbyte ,您可以从几乎所有可以想象的数据源将数据接收到数据仓库中。不用说,我们必须编写 SQL 来对数据进行查询,或者构建可以在下游应用程序中使用的数据模型。但是作为一个非工程师来说,SQL 并不难,这里有一些学习 SQL 的好资源。
高性能和可扩展
云数据仓库的最大优势之一是,与它们的前辈不同,现代仓储工具建立在将计算与存储分离的架构之上。
这意味着存储数据的费用与对数据进行查询的费用是分开的。这不仅带来了成本优势,还使云数据仓库的性能更高,能够并发运行数百个查询。我推荐这篇快速阅读来了解更多关于云数据仓库中的并发性。
此外,随着存储成本日益降低,公司能够在其数据仓库中复制生产数据库,从而使数据仓库成为所有数据的真实来源。
数据仓库市场概述
让我们看看数据仓库解决方案市场在过去十年中是如何发展的,以及它的发展方向。
过去
在这篇文章的开头,我提到我试图达成的一笔交易依赖于买家对 SAP Hana 的投资,这在当时是一种内部解决方案,前期成本为几十万美元。因此,你可以想象,要让公司放弃这笔钱,需要的不仅仅是几次销售会议。
(如果你好奇的话,我的那笔交易陷入了几个月的循环,直到我停止跟进。)其他领先的仓储解决方案由甲骨文、T2、IBM 和 T4 Vertica 提供。这些部署在本地,并结合了事务(OLTP)和分析(OLAP)处理。IBM 的这篇短文在中解释了 OLTP 和 OLAP 之间的主要区别。
随着云的普及,所有这些供应商现在都提供云仓储解决方案;然而,当人们谈论现代云仓储工具时,它们并没有出现。
现在
现在是 2021 年,数据仓库市场正处于一个独特的转折点。由于上述原因,领先的云仓储解决方案提供商正在经历快速采用。与此同时,一家老牌数据公司和一家挑战者新贵正试图分一杯羹。
领头的马
Amazon Redshift、Google BigQuery 和 Snowflake 是目前在云仓库环境中谈论的三个最受欢迎的解决方案,其次是微软 Azure 所谓的仓库解决方案。
Redshift 于 2012 年推出,是云中的第一个 OLAP 数据库,启动起来既快又便宜。它也标志着我们今天所知的现代云数据仓库的开始。虽然 BigQuery 在 Redshift 之前上市,但直到 2016 年 6 月,即全面上市近 5 年后,谷歌才推出对标准 SQL 的支持,从而导致更广泛的采用。
然而,自 2014 年公开发布以来, Snowflake 是第一个提供将计算与存储分离的解决方案的,这种架构后来被其他提供商采用(尽管许多 Redshift 客户可能仍然没有在支持这种架构的集群上运行)。
如果你想更深入地挖掘并理解红移、BigQuery 和雪花之间的区别,我强烈推荐这个深入的比较。
如上所述,微软也有一匹马在竞争,我被告知它非常适合运行在 Azure 云上的公司。
同样值得一提的是,在确立了自己作为领先的数据仓库供应商的地位之后,Snowflake 现在将自己定位为一个端到端云数据平台,除了其他功能之外,现在还可以存储和处理非结构化数据。
一个玉米和一个挑战者
目前的仓储格局包括另外两家公司——价值 380 亿美元的 Databricks 和挑战者 Firebolt。如果不考虑这两家公司所能提供的东西,对数据仓库解决方案的任何评估都是不完整的。
Databricks 由 Apache Spark 的创始人创建,最初为 Spark 提供托管解决方案,Spark 是一个旨在处理大量数据的分析引擎,通常由大公司用来管理机器学习工作负载。
今天,Databricks 提供了一个名为 Lakehouse 的产品,它结合了数据 lake 和数据仓库 house 的功能。
从历史上看,数据湖一直用于存储没有直接用例的原始、非结构化数据。另一方面,数据仓库是为存储结构化数据而设计的,这些数据是为分析目的而准备或转换的。
然而,随着由仓储解决方案驱动的 ELT 相对于 ETL 的崛起,变得更加便宜和高效,数据湖和数据仓库之间的界限正在变得模糊。值得注意的是,Snowflake 和 Databricks 正在缓慢但肯定地融合——如果你想知道更多,我的朋友安妮卡在这种融合方面做了出色的工作。
接下来,Firebolt 已经成为该领域的一个挑战者,它提出了一些非常大胆的主张,并在解释它们是如何做到的方面做了很好的工作(强烈推荐观看这个产品演示)。
我很喜欢 Firebolt 如何迅速地将自己定位为一个由数十亿美元的巨头主导的市场中的一个重要竞争者,同时也享受着乐趣!
未来
目前的市场领导者不会很快被打乱,很可能在未来几年成为领导者。
Firebolt 无疑让我们看到了数据仓库的未来,随着它的发展势头,预计 Snowflake 和其他公司不会只是停下来盯着看。然而,有一些专门构建的分析数据库系统正在推动当前仓库解决方案所能达到的极限。
ClickHouse 、 Apache Druid 和 Apache Pinot 都是面向实时分析用例的开源 OLAP 数据库/数据存储/数据库管理系统。 Materialize 是另一家在实时分析领域大步前进的数据库初创公司。
这些不是通用的数据仓库解决方案,因为它们旨在仅满足实时用例,并且它们的架构不同,没有分离存储和计算,这是现代数据仓库工具的核心前提。
如果你在寻找 ClickHouse,Druid 和 Pinot 之间的超级详细的比较,这就是它。这些“数据库系统”绝不是数据仓库的替代品,但它们确实让我们看到了从能够存储大量数据用于分析的产品中可以期待什么。
作者图片:数据存储工具的演变。点击查看完整的基准测试
结论
现代数据仓库工具使得做两件事情变得非常容易和经济实惠——在云中存储大量数据,并使用 SQL 查询这些数据以进行分析和激活。
那些认真对待对数据的控制权和所有权,但却选择不投资数据仓库的公司,终究是不认真的。有些公司使用 PostgreSQL 数据库作为他们的数据仓库,虽然这在短期内是可以的,但随着数据仓库变得越来越便宜,性能越来越好,没有理由不尽早建立一个。
首发于蓖麻博客 。
使用 ArgoWorkflow 的云原生数据管道
原文:https://towardsdatascience.com/cloud-native-data-pipelines-using-argoworkflow-1e1fd8c03939?source=collection_archive---------20-----------------------
利用容器和 Kubernetes 扩展您的数据工程管道
背景
无论您是数据工程师、平台工程师、数据科学家还是 ML 工程师,在处理数据时,我们都面临着创建管道的挑战。尽管我们的数据处理目标之间存在折衷的差异,但有一点是不变的“我们需要创建和扩展 DAG 的能力”。在现代计算解决方案中,DAG 或有向无环图的概念是核心。简而言之,DAG 描述了复杂的非递归计算中的一系列执行步骤,定义可以在这里找到。实际上,我们将 DAG 定义为一组线性任务,这些任务共同作为一个逐步的过程运行。我们的简单目标是使开发和部署管道的过程尽可能自动化和可伸缩。
可以使用许多工具来构建管道。比较选项
Apache Airflow —基于 python 的编排平台,专为运营团队和数据科学打造。这个领域最好的用户界面之一
perfect—为开发人员使用而构建的程序编排平台。它是这一领域的新兴工具,正在获得越来越多的关注。
Luigi——另一个供开发者使用的开源解决方案
Ctrl-M—BMC 流行的企业工作流管理工具
DAG 已定义
为什么我们叫他们达戈?DAG 是一个有向非循环图,是管道的数学抽象。进一步说,图是顶点(或点)和边(或线)的集合,表示顶点之间的连接。有向图是一种图,其中的边指向从一个顶点到另一个顶点的方向。在这种情况下,同一对顶点之间可能存在两条边,但在这种情况下,它们将指向相反的方向。有向图通常被称为有向图。如果一个图包含一个或多个圈,则该图是循环的,其中循环被定义为沿着边的顶点之间的路径,该路径允许你沿着唯一的一组边返回到顶点。当一个图不包含圈时,它是无圈的。因此,有向无环图或 DAG 是没有圈的有向图。
Argo 工作流
Argo WorkFlows 是一个云原生计算基础项目,是一个开源的容器原生工作流引擎,用于编排 Kubernetes 中的作业,将工作流中的每个步骤作为一个容器来实现。Argo 使开发人员能够使用类似于传统 YAML 的自定义 DSL 启动多步管道。该框架提供了复杂的循环、条件、依赖管理和 DAG 等。这有助于增加部署应用程序堆栈的灵活性以及配置和依赖性的灵活性。使用 Argo,开发人员可以定义依赖关系,以编程方式构建复杂的工作流,将任何步骤的输出作为输入链接到后续步骤的工件管理,并在易于阅读的 UI 中监控计划的作业。Argo 是作为 Kubernetes CRD(自定义资源定义)实现的。因此,Argo 工作流可以使用 kubectl 进行管理,并与其他 Kubernetes 服务(如卷、秘密和 RBAC)进行本机集成,并提供完整的工作流功能,包括参数替换、工件、夹具、循环和递归工作流。
其他功能
- 可视化和管理工作流的用户界面
- 工作流模板用于存储集群中常用的工作流
- 计划的工作流
- 带有 REST API 的服务器接口
- 基于 DAG 或步骤的工作流声明
- 步骤级输入和输出(工件/参数)
- 参数化
- 条件式
- 重试(步骤和工作流级别)
- K8s 资源编排
- 调度(亲和力/容忍度/节点选择器)
- 卷(短期/现有)
- 平行度限制
- 魔鬼化的步骤
管道 API
为了简化环境和简化实施,我们的目标是利用我们在 Docker 和 Kubernetes 上的投资,同时使开发人员能够自动化所有语言和框架的云原生部署管道。
既然我们已经有了所有必要的材料;a)用于代码的容器 b)用于访问云资源的容器的编排 c)以编程方式构建复杂工作流(DAG)的能力,让我们仔细看看为什么我们开发了管道 API。
Argo 中的工作流自动化是由 YAML 模板驱动的(易于采用,因为 Kubernetes 主要使用相同的 DSL ),这些模板是使用 ADSL (Argo 领域特定语言)设计的。使用 ADSL 提供的每条指令都被视为一段代码,与 github 中的应用程序代码一起托管。Argo 提供/支持六种不同的 YAML 构造:
**容器模板:**根据需要创建单个容器和参数
**工作流模板:**定义作业,换句话说就是短时间运行的应用程序,它运行到完成。工作流中的步骤可以是容器
**策略模板:**用于触发/调用作业或通知的规则
**部署模板:**创建长时间运行的应用程序
**固定模板:**将 Argo
**项目模板之外的第三方资源粘合起来:**可以在 Argo 目录中访问的工作流定义。
这些模板提供了一组非常强大的特性,但也会给开发人员带来负担,特别是当它涉及到创建和维护复杂的 yaml 时。在多系列的这一部分中,我们将展示一个利用 Spark 的管道,这也是一个非常有趣的 K8 运营商,敬请关注关于该主题的未来文章。
项目配置
第一步是我们在您的项目中创建一个 config.yaml 文件,它包含所有关于图像/容器细节的底层细节。配置文件主要包含两个组件:
- 容器:包含预构建的容器图像
- 资源:可以包含任何需要实现的定制资源定义
下面是示例 yaml,它包含使用 pydeequ 运行示例数据分析器的jobprofilerclient
和使用 spark 操作符运行 Spark 作业的资源模板sparkk8sScala
现在,您可以使用下面的代码创建一个复杂的 DAG:
添加任务后,可以编译 DAG,我们还可以查看依赖关系,并将 DAG 提交到 Argo 工作流:
当提交到 ArgoWorkflow 时,此代码会生成如下所示的 DAG:
要查看工作代码,请查看 github repo,在这里我们将继续添加更多的管道 API 特性。请继续关注更多的用例,包括 ML 管道。
请联系!
如果您有任何问题,请联系我们。在这里找到我【https://www.linkedin.com/in/roberthheise/
你可以在 https://www.linkedin.com/in/gopalkrishna9/的[找到 Gopal](https://www.linkedin.com/in/gopalkrishna9/)
Tableau 中的聚类分析
原文:https://towardsdatascience.com/cluster-analysis-in-tableau-1f19acd0c647?source=collection_archive---------20-----------------------
了解如何轻松地在 Tableau 中对数据进行聚类
图片由尼基·❕❣️提供请保持安全❣️❕ 来自 Pixabay
考虑这样一种情况,您有一些属于您公司的销售数据。假设你想从消费者的消费能力中发现一种模式。如果您可以在数据中发现不同的群体或关联,您的公司就可以根据他们的偏好来定位不同的群体。这种直觉背后的基本思想被称为聚类,tableau 有一个固有的特性,可以根据某些属性自动对相似的数据点进行聚类。在本文中,我们将探索 Tableau 的这一功能,并了解如何将聚类方法应用于一些真实的数据集。
什么是集群?
聚类 又称聚类分析,是一种无监督的机器学习算法,倾向于根据某种相似性度量对更多相似的项目进行分组。
下面的图非常直观地展示了 K 均值算法的工作。在 K 均值聚类中,该算法将数据集分成 K 个聚类,其中每个聚类都有一个质心,质心计算为该聚类中所有点的平均值。在下图中,我们从随机定义 4 个质心点开始。然后,K 均值算法将每个数据点分配到其最近的聚类(交叉)。当所有数据点的平均值改变时,质心移动到新的位置,然后重复整个过程,直到质心位置不再有可观察到的变化。
可视化 K-Means 算法
Tableau 中的聚类
Tableau 还使用了 K 均值聚类下的算法。它使用 卡林斯基-哈拉巴斯 准则来评估聚类质量。下面是对卡林斯基-哈拉巴斯标准的数学解释:
来源:https://online help . tableau . com/v 10.0/pro/desktop/en-us/clustering _ how networks . html
这里 SSB 是总体的类间方差,SSW 是总体类内方差,k 是类的数量,N 是观察的数量。
这个比率给出了一个决定簇的内聚性的值。较高的值表明聚类之间的关联更紧密,聚类内距离较低,聚类间距离较高。
既然我们对什么是集群有了一个概念,那么是时候看看如何使用 tableau 来应用集群了。
使用聚类发现数据集中的模式
聚类有助于发现数据集中的模式。假设你是某个旅游公司的分析师。作为一家公司,了解人们旅行习惯的模式会很有用。你有兴趣知道哪个年龄段的人更喜欢旅行。你的工作是使用世界指标样本数据来确定哪些国家有足够多的合适的客户。
舞台环境
在本教程中,我们将使用 画面公开 **,**这是绝对免费的。从官网下载 Tableau 公版。按照安装说明进行操作,如果单击 tableau 图标时出现以下屏幕,就可以开始了。
Tableau 主屏幕|作者图片
连接到数据集
世界经济指标数据集包含推动世界各国经济发展的有用指标,如预期寿命、经商便利度、人口等。数据集是从联合国网站上获得的。数据集可以从这里的进入。
- 将数据集下载到您的系统中。
- 将数据从计算机导入 Tableau 工作空间。使用
Sheets
选项卡下的Data Interpreter
,校正并重新排列数据。
按作者连接到数据源|图像
格式化数据源
在工作表中,数据源中的列在数据窗格的左侧显示为字段。数据窗格包含由表格组织的各种字段。有许多功能可以归为一类。这也将有助于更好地表示所有数据字段。
- 选择
Business Tax Rate
、Days to Start Business
、Ease of Business
、Hours to do Tax
、Lending Interest
、>文件夹>创建文件夹
按作者分组文件夹|图像中的字段
- 将文件夹命名为 Business,,现在上述所有字段都包含在这个特定的文件夹中。
文件夹视图|按作者排序的图像
- 同样,创建三个新文件夹—
Development
、Health
和Population
,方法相同,如上图所示。分别添加以下字段。这是格式化后数据窗格的外观:
最终外观|作者图片
- 双击数据窗格中的
Country
。Tableau 创建一个地图视图,用一个实心圆代表每个国家。将标记类型改为地图,o 在标记卡片上,
按作者显示数据集|图像中的国家/地区
确定聚类的变量
聚类的下一步是确定将在聚类算法中使用的变量。在 tableau 中,变量类似于字段。对于能够给出理想集群的最佳变量,没有唯一的答案,但是您可以用几个变量进行实验,以查看期望的结果。在我们的例子中,让我们使用以下字段:
- 人口城市
城市人口是一个国家人口密度的良好指标。密度越高,商机就越多。
- 65 岁以上人口
65 岁以上的人口意味着老年人。许多老年人倾向于喜欢旅行,所以这可能是一个有用的指标。
- 女性预期寿命和男性预期寿命
预期寿命较高的国家意味着那里的人们寿命更长,对旅游更感兴趣。
- 人均旅游人数
该字段不存在,可以使用Tourism Outbound
和Population Total
字段创建为计算字段,如下所示:
Tourism Per Capita = SUM([Tourism Outbound])/SUM([Population Total])
人均旅游|作者图片
Tourism Outbound
代表人们每年花在国际旅行上的钱(以美元计)。为了得到平均值,我们需要将这个字段除以每个国家的人口
将选定字段添加到视图中
在继续之前,我们需要将默认聚合从SUM
更改为AVERAGE
。Tableau 使得聚集度量或维度成为可能,尽管聚集度量更常见。每当我们向视图中添加一个度量时,默认情况下会对该度量应用一个聚合。需要使用的聚合类型取决于视图的上下文。
将选定字段添加到视图|按作者排序的图像
更改所有选定字段的聚合,然后将它们拖到标记卡上的细节中,如下所示:
将汇总从总和变为平均值|按作者分类的图片
使聚集
Tableau 中的聚类是一个简单的拖放过程。以下步骤概述了群集过程:
- 点击
Analytics
窗格,拖动Cluster
到视图上,数据自动按 Tableau 聚类。就这么简单。
Tableau 中的聚类|按作者分类的图像
- 虽然 Tableau 可以自动决定要创建的聚类数,但我们也可以控制聚类数以及计算它的变量。将字段拖到框中以将其包括在聚类分析算法中,或者将其拖出以将其排除。
决定聚类数|按作者分类的图像
- 为了更好的分析,我们将使用 4 个集群和默认变量。注:一些国家不属于任何类别,被标记为非类别。
4 个群集和默认变量|作者图片
- 该集群被创建为一个新的药丸,可以在颜色架上看到。将此药丸拖到数据窗格上,保存为一个组。
聚类字段|图像 y 作者
在这里,我们根据所选的衡量标准对国家进行了分组。但是,我们如何理解这些结果,以及我们如何根据集群做出商业决策呢?下一节将解决这些问题。
描述集群
单击标记卡中的集群字段,然后单击描述集群选项。
描述各种集群|作者图片
这将显示一个包含集群详细描述的文档。文档中有两个选项卡— Summary
和Models
:
1.摘要
这给出了每个聚类的结果和每个变量的平均值的汇总。
结果摘要|作者图片
从上面的结果,我们可以推断集群 2 具有:
- 男性和女性的平均预期寿命最高
- 最高的人均旅游总量
- 最高平均城市人口
这意味着它拥有预期寿命更长的富裕城市人口,似乎是老年旅游业的良好市场。让我们看看这一组包括哪些国家。
分析第 2 组中的国家|作者图片
2.模型
models’
选项卡显示所有变量/字段平均值的各种统计值,并显示其统计显著性。你可以在这里阅读更多关于集群模型统计数据。
按作者分析模型选项卡|图像
因此,作为一名分析师,你可以向销售团队展示这份清单,让他们关注这些潜在客户。聚类为我们提供了一些很好的见解。从这里开始,您可以尝试不同的领域,设置人口或收入的阈值等。有许多方法可以对数据进行聚类,但基本原理是相同的。
结论
在本文中,我们学习了如何使用简单的拖放机制对 Tableau 中的给定数据集执行聚类分析。聚类是一个重要的工具,当与 Tableau 结合使用时,可以为分析师提供统计分析技术的力量。
参考文献和进一步研究
在数据中寻找聚类—Tableau 的自我指导,深入聚类分析的概念。
Plotly Express 的聚类和重叠条形图
原文:https://towardsdatascience.com/clustered-overlapped-bar-charts-with-plotly-express-c752d2925cf1?source=collection_archive---------14-----------------------
图片由 Ergyn Meshekran 从 Unsplash 提供
簇状&重叠条形图
聚类(分组)条形图显示主要类别和属于第二分类变量的子类别(子类别)之间的相对比例的数字信息。与堆积条形图、类似,它们应该用于比较和比例,但重点是组成。当一个整体被分成多个部分时,它们特别有效。它们能够在子类别之间进行比较**,而堆叠条形图在子类别内进行比较。**
簇状条形图由多组矩形条表示,这些矩形条可以水平或垂直定向。每个主要类别被分成代表第二分类变量的子类别的条簇和。每个子类别的数量由那些矩形条的长度或高度来表示,这些矩形条并排放置 形成一个簇,簇之间的间隙比单个标准条稍宽。
重叠(重叠)条形图 用于不同项目或类别之间的比较。他们只对单个图表中每个项目或类别的两个数字变量进行比较。数值变量必须密切相关,才能进行比较。它们也用于显示基于相似前提的长期趋势。它们不应用于关系或分布分析。概念上的想法是对比两个变量的数值,这两个变量一个重叠在另一个之上,允许用更大的阐释力描述信息。
簇状&重叠条形图,带有 Plotly Express
我们使用了从社区 Kaggle [1]下载的公共数据集。该数据集包含从 VzCharts 收集的与视频游戏销售和游戏评级数据相关的记录。我们特别选择了一个 csv 文件,其中有 422 条关于微软 Xbox One 主机上视频游戏销售的记录。我们想知道 2013 年至 2018 年期间全球不同地区的销售额分布情况。我们还想知道哪些是最畅销的类型。
首先,我们导入 Plotly Express 作为 *px,*模块 *plotly.graph_objects*
作为 go ,Pandas 库作为 pd ,并将我们的 csv 文件转换成数据帧:
import pandas as pdimport plotly.express as pximport plotly.graph_objects as godf = pd.read_csv(path + 'XboxOne_GameSales2.csv', index_col=False,
header = 0, sep = ';', engine='python')
下面的屏幕截图显示了数据集的前十条记录:
最初,我们删除了在年列中具有 N/A 值的行,然后删除了在全局列中具有 0 值的行,最后,我们根据年列对剩余的记录进行分组,并对每个组求和。
df.dropna(subset = ['Year'], inplace = True)df.drop(df[df['Global'] == 0.0].index, inplace = True)df_clust = df.groupby(['Year']).sum().reset_index()
完成这三行代码后,我们就可以绘制一个簇状条形图了。
对于本文中的聚类(分组)条形图,Plotly 函数是*go.Bar()*
,对应的参数是: x= 代表时间线的数据帧中的列名,而 y= 是代表特定区域的数据帧中的列名。此外,我们还设置了条形的宽度和图例的文本。
我们使用方法*fig.add_trace()*
添加新的轨迹(条)到图形对象*Figure()*
。我们重复这个过程四次,每个区域一次。
anchos = [0.2] * 6fig = go.Figure()fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['North America'],
width = anchos, name = 'North America'))fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['Europe'],
width = anchos, name = 'Europe'))fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['Japan'],
width = anchos, name = 'Japan'))fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['Rest of World'],
width = anchos, name = 'Rest of World'))
我们用*update.layout*
更新了图表:设置标题、字体大小以及图形的宽度和高度。
我们必须选择 barmode = 'group' 来绘制一个簇状条形图。记住,我们选择了*条形图=‘stack’*作为堆积条形图。
然后我们更新了 x 轴和 y 轴(文本、字体、tickfont)。我们将图表保存为静态的 png 文件,最后,我们使用默认模板( plotly )绘制图表。
fig.update_layout(title = "XboxOne World Sales (MM) ",
barmode = 'group', title_font_size = 40,
width = 1600, height = 1400)fig.update_xaxes(title_text = 'Year',
title_font=dict(size=30, family='Verdana', color='black'),
tickfont=dict(family='Calibri', color='darkred', size=25))fig.update_yaxes(title_text = "Sales",
title_font=dict(size=30, family='Verdana', color='black'),
tickfont=dict(family='Calibri', color='darkred', size=25))fig.write_image(path + "figclust1.png")fig.show()
图 1:一个簇状条形图。作者用 Plotly Express 制作的图表。
这是一个很好的图表,但我们无法清楚地确定哪些值对应于日本。此外,图例的大小不足以正确显示。
因此,我们在每个轨迹中加入了参数文本,以及对应于每个区域的数值。我们使用方法*update_traces()*
来设置这些数字注释的属性(模板、位置和字体特征)。最后,我们使用方法*update_layout(legend=go.layout.Legend()*
来建立屏幕上的位置( x,y )、图例项显示的顺序( traceorder ),最后是图例的族、大小和颜色。请注意, go.Legend
已被弃用,取而代之的是go.layout.Legend
。
anchos = [0.2] * 6fig = go.Figure()fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['North America'],
width = anchos, name = 'North America',
text = df_clust['North America']))fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['Europe'],
width = anchos, name = 'Europe',
text = df_clust['Europe']))fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['Japan'],
width = anchos, name = 'Japan',
text = df_clust['Japan']))fig.add_trace(go.Bar(x = df_clust['Year'],
y = df_clust['Rest of World'],
width = anchos, name = 'Rest of World',
text = df_clust['Rest of World']))fig.update_layout(title = "XboxOne World Sales (MM) ",
barmode = 'group',title_font_size = 40,
width = 1600, height = 1400)fig.update_layout(legend=go.layout.Legend(
x=1,y=1,
traceorder= normal",
font=dict(family="Verdana",size= 22, color = "black")))fig.update_traces(texttemplate='%{text:.2f}',textposition='outside',
textfont=dict(size=60, family='Verdana', color='black'))fig.update_xaxes(title_text = 'Year',
title_font=dict(size=30,family='Verdana',color='black'),
tickfont=dict(family='Calibri', color='darkred',size=25))fig.update_yaxes(title_text = "Sales",
title_font=dict(size=30,family='Verdana',color='black'),
tickfont=dict(family='Calibri', color='darkred',size=25)) fig.write_image(path + "figclust1.png")fig.show()
图 2:带注释的簇状条形图。作者用 Plotly Express 制作的图表。
现在我们可以做一个很好的比较,不仅是视觉上的,还有数字上的。
为了更好地讲述故事,我们决定在两个最畅销的地区按流派分析销售情况:
首先,我们按流派分组,并对北美和欧洲对应的列求和。正如我们从前面的图表中所知,北美是销量最高的地区,我们将列 [“北美”] 按降序排列。我们得到了 16 种不同的风格,太多了,难以形象化。因此,我们只筛选出那些在 2013 年至 2018 年期间销量超过 500 万册的书籍。
df_genre = df.groupby(['Genre'], as_index = False)
["North America", 'Europe'].sum()df_genre.sort_values(by=['North America'], inplace = True,
ascending = False)df_genre = df_genre[df_genre['North America'] > 5]
我们选择 bar mode =‘overlay’来得到一个重叠的条形图,因为我们每个类别只有两个数字变量。
anchos = 0.5fig = go.Figure()fig.add_trace(go.Bar(x = df_genre['Genre'],
y = df_genre['North America'],
width = anchos, name = 'North America',
text = df_genre['North America']))fig.add_trace(go.Bar(x = df_genre['Genre'],
y = df_genre['Europe'],
width = anchos, name = 'Europe',
text = df_genre['Europe']))fig.update_layout(title = "XboxOne Sales by Genre (MM)",
barmode = 'overlay',title_font_size = 40,
width = 1600, height = 1400)fig.update_layout(legend=go.layout.Legend(
x=1,y=1, traceorder= "normal",
font=dict(family="Verdana",size= 22, color = "black")))fig.update_xaxes(
title_text = 'Genre',
title_font=dict(size=30,family='Verdana',color='black'),
tickfont=dict(family='Calibri', color='darkred', size=25))fig.update_yaxes(
title_text = "Sales",
title_font=dict(size=30, family='Verdana', color='black'),
tickfont=dict(family='Calibri', color='darkred', size=25))fig.write_image(path + "figover1.png")fig.show()
图 3:重叠条形图。作者用 Plotly Express 制作的图表。
不出所料,射击游戏是北美人的最爱,销量是紧随其后的游戏的两倍。按比例来说,欧洲人只在赛车类型上与他们相匹配。
我们可以通过一个小的改动来改进图表:在第二个栏中将 offset 属性设置为 0.0005 。此属性移动绘制横条的位置(以位置轴为单位)。
fig.add_trace(go.Bar(x = df_genre['Genre'],
y = df_genre['Europe'],offset = 0.0005,
width = anchos, name = 'Europe',
text= df_genre['Europe']))
图 4:部分重叠的条形图。作者用 Plotly Express 制作的图表。
如图 4 所示的图表被称为部分重叠条形图。从概念上讲,当代表不同数据集的矩形开始重叠而不是并排放置时,它们相当于聚类(分组)条形图。重叠条意味着一个矩形在另一个矩形前面重叠 100%的极端情况。毫无疑问,观众会发现很难对三个或更多部分重叠的条进行比较。此外,重叠和部分重叠的条形图只有在较长的条形图总是在较短的条形图后面的情况下才能显示良好的信息。
总而言之:
当您想要对整体的各个部分进行直接比较时,可以使用簇状条形图。另一方面,重叠条形图能够很好地比较两个密切相关的数值变量。
如果你对这篇文章感兴趣,请阅读我以前的(【https://medium.com/@dar.wtz】):
带 Plotly Express、跟踪和布局的面积图
散点图,带有 Plotly Express、趋势线和分面
参考文献
[1]:https://www.kaggle.com/sidtwr/videogames-sales-dataset?select = Xbox one _ gamesales . CSV
客户细分的聚类算法
原文:https://towardsdatascience.com/clustering-algorithm-for-customer-segmentation-e2d79e28cbc3?source=collection_archive---------2-----------------------
K-均值聚类的逐步指南
聚类分析信息图(图片作者来自网站
什么是聚类算法?
**在商业环境中:**聚类算法是一种辅助客户细分的技术,客户细分是将相似的客户归类到同一细分市场的过程。聚类算法有助于从静态人口统计和动态行为两方面更好地了解客户。具有相似特征的客户通常以相似的方式与企业互动,因此企业可以通过为每个细分市场创建定制的营销策略来受益于这种技术。
**在数据科学上下文中:**聚类算法是一种无监督的机器学习算法,它发现密切相关的数据点组。监督算法和非监督算法之间的根本区别在于:
- 监督算法:它需要将数据集划分为训练集和测试集,算法基于训练数据集的输出/标签进行学习,并将其推广到未观察到的数据。例如,决策树、回归、神经网络。
- 无监督算法:当数据集中没有任何已定义的输出/标签时,它用于发现隐藏模式。例如,聚类、关联规则挖掘、降维。
在这里,我收集了各种 ML 算法的实用指南。
德斯坦贡
机器学习实用指南
View list10 stories
为聚类准备数据
在概述了什么是集群之后,让我们更深入地研究一个实际的客户数据示例。我用的是 Kaggle 数据集“商城客户细分数据”,数据集中有五个字段, ID,年龄,性别,收入,支出分数。商场最关心的是顾客的消费分数,因此本练习的目标是在领域消费分数中找到隐藏的聚类。
1.加载和预览数据
使用 describe()加载数据集并汇总列统计信息。
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from pandas.api.types import is_string_dtype, is_numeric_dtype df = pd.read_csv("../input/customer-segmentation-tutorial-in-python/Mall_Customers.csv")
描述数据集
检查每个字段的分布:对分类变量使用条形图,对数值变量使用直方图。
单变量分析(图片由作者提供)
数据分布(图片由作者提供)
如果您想了解更多关于数据可视化和 EDA 的细节,请查看这两篇文章。
2.数据预处理
既然我们已经定义了目标并对数据有了更好的理解,我们需要预处理数据以满足模型需求。在这个例子中,我选择 K 均值聚类作为主要算法,原因将在后面解释。
标准的 k 均值算法不能直接应用于分类数据。更具体地说,分类变量(例如,本例中的性别)的搜索空间是离散的(男性或女性),因此不能直接与连续空间组合并以相同方式测量距离。因此,我丢弃了“性别”字段和“客户 ID”字段。
由于 K 表示基于欧几里得距离解释数据点之间的接近程度,因此将所有维度协调到一个标准尺度中是很重要的。应该选择适当的数据转换类型,以便与数据的分布保持一致。来自 Google 的这篇文章提供了集群中数据转换的一般指南。
总而言之:
- 如果正态分布→归一化
- 如果幂律分布→对数变换
- 如果数据不符合任何分布→分位数
从前面的单变量分析中,我们可以看到这些变量既不符合正态分布也不符合法律分布。因此,我使用 MinMaxScaler 将数据范围缩小到 0 到 1 之间,同时保持分布形状。
数据转换(图片由作者提供)
3.电子设计自动化(Electronic Design Automation)
探索性数据分析提供了视觉线索,表明当将多个变量组合在一起时,是否有可能形成有洞察力的集群。这也是必不可少的一步,因为选择合适的聚类算法依赖于聚类的形状。一些基于中心的算法(例如 K 均值)更适用于球状簇,并且它们倾向于将线性簇分开。而基于密度的算法(例如 DBSCAN)更适合具有不规则形状和大量噪声的聚类。
我以下面的方式形象化了这三个领域。
2D 散点图
- 年龄与年收入
- 年收入与支出得分
- 年龄与支出收入
2D 散点图(图片由作者提供)
三维散点图:
- 年龄与年收入和支出得分
3D 散点图(图片由作者提供)
在这种情况下,很明显,“年收入与支出分数”的图表生成了一些基于中心的聚类。因此,我将使用 K 均值算法进行进一步的探索。
k 表示聚类
1.K 均值聚类是如何工作的?
k 表示聚类是一种基于中心的聚类算法,这意味着它根据接近度或距离将数据点分配给聚类,遵循以下程序:
- 指定星团的数量“K”。
- **初始化 K 个随机质心,给每个簇分配一个质心:**质心是每个簇的中心。开始时随机选择 k 个数据点作为质心,其他数据点的聚类标记随后相对于它们定义。因此,不同的初始质心分配可能导致不同的集群形成。
- **通过将数据点分配到最近的质心来形成 K 个聚类:**最近的质心通常由最小的欧几里德距离来定义,但根据使用情况,它也可以是相关或余弦。
- 重新计算每个聚类的质心:在所有数据点被分配到一个聚类后,对于每个聚类,我们重新计算属于该聚类的所有数据点的平均值,并将其定义为新的质心。
- **当质心不再变化时达到收敛:**重复步骤 2-4,直到达到停止准则,即质心不再变化或达到最大迭代次数。
该过程还确定了 K 均值算法具有将点聚类成具有相似大小的圆形的限制,并且它还严重依赖于预定义的数字 K
2.如何建立 K 均值聚类模型?
现在让我们仔细看看如何使用 python scikit learn 实现它。
首先,我定义了一个 KMeans_Algorithm 函数,它将数据集和聚类数作为参数传递。
定义 KMeans_Algorithm 函数(图片由作者提供)
该函数从 sklearn 库中调用 KMeans() 并指定一些关键参数:
- n_clusters: 集群的数量
- ***init:***它控制初始化技术,我选择了“k-means++”来以一种聪明的方式选择初始质心以加速收敛
- max_iter: 指定每次运行允许的最大迭代次数
- 算法 : 有几个选项可以选择,“auto”、“full”和“elkan”我选择“elkan”是因为它是一个 K Means 算法变体,使用三角形不等式使其更具时间效率。
- ****random _ state:**用一个整数来决定初始质心的随机生成
输出将生成以下属性和评估指标:
- ****cluster _ centres _:**返回一个形心位置的数组
- 惯性 _: 数据点到其最近质心的距离平方之和
- 标签 _: 将聚类标签分配给每个数据点
- ****silhouette _ score:**数据点到同一聚类中其他数据点之间的距离与最近邻聚类中的数据点进行比较
在这个例子中,我主要对关于“支出分数”的聚类的形成感兴趣。因此,我使用了数据集 X1,X2,X3,如下所述,作为模型的输入。
请注意,我们不再需要为无监督模型的训练和测试划分数据集。
年龄与支出得分
下面的代码使用了数据集 X1——按比例调整的年龄与按比例调整的支出分数,并直观地显示了随着分类数从 2 增加到 10,分类是如何变化的。
年龄与花费分数的 k 均值(图片由作者提供)
代码的第一部分遍历多个集群,并为每个集群生成一个散点图,红色方块表示质心。如下所示,当指定的“k”值改变时,聚类也改变。
X1 的聚类结果(图片由作者提供)
之后,我基于两个指标评估模型性能:惯性和轮廓系数。
由于聚类是一种无监督算法,我们不能根据预测结果和实际结果之间的差异直接评估模型质量。因此,评估应基于 最小化类内距离同时最大化类间距离的原则。基于这一原理,有两种评价方法可以确定最佳聚类数。
1)利用惯性的肘法:
惯性测量样本到其最近聚类质心的平方距离之和。对于相同数量的聚类,惯量越小表示聚类越好。肘方法通过查看下图的转折点(“肘”点)来确定最佳聚类数,在本例中为 6。
肘法(图片由作者提供)
2)轮廓系数:
下面是让它显得令人生畏的剪影系数公式:
*但是基本上它转化为最小化簇内距离,同时最大化簇间距离。 a(i) 是数据点 I 到**同一聚类中其他数据点的平均距离,和 b(i) 是数据点 I 到最近邻聚类中所有点的平均距离。*目标是最小化 a(i) 并最大化 b(i) ,因此当系数越接近 1,表示聚类越好。在本例中,2 和 6 都显示了分数的峰值。
轮廓系数(图片由作者提供)
基于这两个指标的结果,在绘制“年龄”与“支出分数”的对比图时,6 很可能是最佳的聚类数。然而,无论是从分数还是从视觉效果来看,说年龄和花费分数一起形成有洞察力的聚类仍然不足以令人信服。
年收入与支出得分
从 EDA 过程中,我们观察到图表中有几个不同的集群。现在,让我们仔细看看该模型是否能如预期的那样将客户划分为不同的细分市场。该代码与上面的代码类似,但只是将输入数据集更改为 X2-按比例缩放的年收入与按比例缩放的支出分数。
**
年收入与支出得分的平均值(图片由作者提供)
很明显,当聚类的数量等于 5 时,存在相当好的分割,并且在散点图中也清楚地示出了这一点。
年收入与支出分数,含 5 个聚类
年龄对比年收入对比支出得分
如果你感兴趣,我们还可以进一步研究这三个领域是如何相互作用的。
年龄、年收入和支出得分的平均值(图片由作者提供)
虽然,就可视化和度量值而言,没有形成任何突出的聚类的迹象,但无监督学习是关于发现和探索隐藏的努力。尽管如此,做进一步的调查还是值得的。
3.如何应用于客户细分?
毕竟,聚类模型的目标是为客户细分带来洞察力。在本练习中,根据两个方面将客户分为 5 类:支出分数与年收入,这最有利于制定量身定制的营销策略。
如下所示,客户可以分为五类:
- 高年收入(7 万美元以上)和高支出分数(60 分以上)
- 高年收入(7 万美元以上)和低支出分数(40 分以下)
- 低年收入(低于 4 万美元)和高支出分数(高于 60)
- 低年收入(低于 4 万美元)和低支出分数(低于 40)
- 平均年收入(介于 4 万美元和 7 万美元之间)和平均支出得分(介于 40 和 60 之间)
基于每个群体的不同特征,企业可以不同地接近每个客户群体。第一类和第三类客户产生的收入最多,他们需要使用营销策略来留住客户,如忠诚度计划或通过时事通讯提供折扣。另一方面,客户获取策略更适合第二组和第四组。这可以是根据他们的收入水平量身定制的营销活动,因为高收入群体和低收入群体对产品有不同的偏好。
更进一步
使用 K 均值聚类有几个局限性,值得注意。当集群的大小和密度不同时,或者如果有任何显著的异常值,它就不能很好地工作。因此,当遇到类似这样的情况时,我们需要考虑其他聚类算法。例如,DBSCAN 对噪声和异常值有更强的抵抗力,并且层次聚类不假设任何特定数量的聚类。如果你想了解更多关于与 DBSCAN 的比较,请查看我的 Kaggle 笔记本。
希望你喜欢我的文章:)。如果你想阅读更多我关于媒体的文章,请使用这个附属链接(【https://destingong.medium.com/membership】T2)注册媒体会员。
带回家的信息
本文介绍了聚类算法,特别是 K 表示聚类,以及我们如何在业务环境中应用它来帮助客户细分。一些关键要点:
- 为聚类分析准备数据:数据转换和探索性数据分析
- 使用 scikit learn 实现 k 均值聚类算法
- 使用惯性和轮廓分数的聚类算法评估
更多这样的文章
* https://medium.com/analytics-vidhya/top-15-websites-for-data-scientists-to-follow-in-2021-67352092c54d
原载于 2021 年 7 月 4 日 https://www.visual-design.nethttps://www.visual-design.net/post/semi-automated-exploratory-data-analysis-process-in-python。*
具有混合类别和数值特征的数据聚类算法
原文:https://towardsdatascience.com/clustering-algorithm-for-data-with-mixed-categorical-and-numerical-features-d4e3a48066a0?source=collection_archive---------4-----------------------
k-Modes 和 k-Prototype 算法直觉和用法
图片由穆罕默德·哈桑发自 Pixabay
聚类是一种无监督的机器学习技术,它以这样一种方式将群体分成几个聚类或组,即一个聚类中的数据点彼此相似,而不同聚类中的数据点不相似。k-Means 是一种流行的聚类算法,仅限于数字数据。
为什么 k-Means 不能用于分类特征?
k-Means 是一种流行的基于质心的聚类算法,它将整个群体的数据点分成 k 个聚类,每个聚类具有几乎相等数量的数据点。k-Means 聚类算法背后的思想是找到 k 个质心点,并且数据集中的每个点将属于具有最小欧几里德距离的 k 个集合中的任一个。
k-Means 算法不适用于分类数据,因为分类变量是离散的,没有任何自然来源。所以计算欧几里得距离对于这样的空间是没有意义的。
k-Means 算法有一种变体,称为 k-Modes,适用于具有分类特征的数据。k-Prototype 是 k-Modes 算法的扩展,适用于混合分类和数字特征。
什么是 k 模式和 k 原型算法:
k-Modes 是一种基于 k-Means 算法范例的算法,用于对分类数据进行聚类。k-modes 根据数据点之间的匹配类别定义聚类。k-Prototype 算法是对 k-modes 算法的扩展,它结合了 k-Modes 和 k-means 算法,能够对混合的数值和分类变量进行聚类。
安装:
k-modes 和 k-prototype 算法可以使用开源库**kmodes**
实现。可以使用以下命令从 PyPl 安装 kmodes 库:
**pip install kmodes**
用法:
如前所述,**kmodes**
算法仅用于分类变量的聚类。而人们可以使用**KPrototypes()**
函数来用一组混合的分类和数字特征对数据进行聚类。
用于演示的数据集包含分类特征和数字特征。
**from kmodes.kprototypes import KPrototypes****kproto = KPrototypes(n_clusters=2, verbose=2, max_iter=20)
kproto.fit(df_array, categorical=cat_idx)**
**KPrototypes**
函数用于将数据集聚类成给定的**n_clusters**
(聚类数)。在拟合训练数据集时,开发人员需要将分类特征的索引指定为参数。训练时**KPrototypes**
算法将使用 k-Modes 算法训练分类特征,剩余的数字特征将使用标准 k-Means 算法训练。
训练后,可以使用**cluster_centroids_()**
函数获得聚类的质心。
**print(kproto.cluster_centroids_)**
使用函数**predict()**
来预测聚类。
**clusters = kproto.predict(df_array, categorical=cat_idx)**
实施:
(作者代码)
结论:
在本文中,我们讨论了如何将聚类应用于具有混合的分类和数字特征集的数据集。KPrototypes 算法结合了 k-Modes 和 k-Means 算法的实现,为具有混合数据类型的数据创建分类。k-Modes 算法可以处理缺失值或 NaN 值,但建议估算这些值以获得更好的性能。
kModes 库的实现模仿了**scikit-learn**
中的集群算法,并具有相同的 API。
阅读下面提到的文章中的以获得对 k-Means、k-Means++和 k-Medoids 算法的更多理解。
参考资料:
[1] KModes 库 GitHub 库:https://github.com/nicodv/kmodes
感谢您的阅读
用于经济政策指导的聚类算法
原文:https://towardsdatascience.com/clustering-algorithms-for-economic-policy-guidance-45f469704815?source=collection_archive---------16-----------------------
行业笔记
在本教程中,我们将探索如何将数据科学方法应用于现实世界的经济政策挑战。
作者照片
T 创新的魔力总是产生于不同知识的融合。在那里,固执的学者们用新思想进行实验,以推进科学前沿。这无疑类似于知识领域像分子一样融合时释放的化学反应。当狡猾的技术和抽象的理论在点火和炼金术的地狱中结合在一起。
经济学和数据科学也是如此,这两个专业不仅有着共同的目标,而且都来自同一个知识宝库——统计学。在过去的几年里,他们变得越来越紧密。
Einav 和 Levin (2014) ,在一篇题为:大数据时代的经济学的论文中,将这种发展称为“实证转向”。在对未来的预测中,他们进一步指出,经济学将越来越多地采用机器学习学术社区中用于分析大数据的技术。事实上,Python 包的出现,如 EconML 、 DoWhy 和 DeepIV 证明了他们预测的准确性。
鉴于这些有趣的发展,本文的目的是说明聚类,一种无监督的学习方法,可以用来解决最优税收问题。
数据集
作者照片。
本文通过一个由 200 家索马里公司组成的小数据集,将重点放在寻找可能有助于设定适当税率的隐藏模式上。快速浏览数据集的信息表可以发现,我们既有丰富的地理信息,也有金融信息。总共有 14 列。
最重要的栏目是以美元计算的收入、连续活动的年数、增长潜力、公司经营的行业及其税收负担。地理位置当然也很重要。
如果您想对数据有所了解,或者您想亲自体验一下,您可以从下面的 Datapane 下载:
有趣的栏目:
- Growth _ Potential _ Index(0-100 的较高值,表示公司在中短期内可以快速增长)
- 月收入($) (公司月总收入)
- An_Revenue ($) (一年的月收入外推)
- 税收负担(可从总收入中扣除的官方税率)
- 税收 _ 收入(当地政府每年从公司获得的收入)
- 产业(相当明显)
- 地理信息(我们有经纬度,城市和省份)
该数据集可用于各种目的,但本文的目的是应用无监督学习算法对公司进行聚类,并确定它们是否被过度征税或征税不足。
但在我们探讨税收归宿的话题之前,让我们先对数据集进行一些探索性分析。
图 1:按城市/省份统计的价值。作者照片
图 1)显示,许多公司位于贝纳迪尔海岸和索马里首都摩加迪沙。其次是较大的城市,如博萨索、拜多阿和贝莱德文,其中第一个城市以其繁忙的港口和渔业闻名,后两个城市是该国南部的主要农业贸易中心。
图 2:按行业统计的价值和按增长潜力统计的税收。作者照片。
图 2)表明,我们数据集中的绝大多数公司都在金融服务领域运营,反映了索马里内战后时代(2000 年代和 2010 年代)的移动货币和汇款繁荣。第二个子图揭示了存在集群模式,其中企业是明显可区分的,因为一些企业产生高税收,而另一些企业产生较低的税收。这些公司的增长潜力也各不相同。
图 3:增长潜力、月收入和税收收入之间的成对网格图。作者照片。
可悲的是,图 3)几乎没有埋藏洞察力的宝藏。唯一值得注意和引人注目的模式似乎表明,现代企业需要支持,或许是减税以刺激增长和释放规模经济。因为其中一个散点图显示,有一群增长潜力低、月收入相对微薄的公司。也许这是一个逃税的例子,否定了我提出的用税收刺激经济增长的建议。
图 4:按部门划分的收入与税收归宿。作者照片。
图 4)无疑是迄今为止发现的最深刻的洞察力。我们可以清楚地看到——由于条形的颜色和大小形成对比——制造业和建筑业产生的税收收入占年收入的比例最高。与能源和电力、金融和资金转移等行业相比,农业和畜牧业的税率也不成比例。下图进一步证明了这一观察的可信度。
图 5:税负与增长潜力对比。作者照片。
在图 5)中,我们按降序比较了各个行业的增长潜力和税收负担。显而易见,制造业和建筑业以及农业和畜牧业在所有行业中的税负份额最高,尽管它们的增长潜力最大。一个可能的解释是,这两个部门都向摩加迪沙和博萨索的主要港口缴纳进出口税。因此,需要政府干预来减轻税收和运输成本的负担,这无疑会阻碍经济增长。此外,聚类算法可能有助于识别需要解决的隐藏模式。
k 均值聚类
众所周知,大多数机器学习模型分为三个不同的类别:1)监督学习,2)非监督学习,以及 3)强化学习。在第一类中,结果变量是已知的,无论是连续的数值变量还是必须预测的类。聚类属于第二类,没有明显的结果可以预测。主要目的是找到隐藏的模式,并简单地将杂乱无章的数据组织成组。
因此,聚类练习的起点总是一团数据点,我们的目标是使模型能够找到隐藏的模式,并根据列间的相似性将每个点分配到一个组(聚类)。聚类算法有许多应用,从生物遗传学到客户细分,再到内容推荐引擎。
图 6:月收入与增长潜力指数的散点图。作者照片。
从前面的图(图 6)中可以看出,我们总是首先检查最重要变量上的分散点。这项工作的目标是直观地衡量集群的最佳数量。给定情况下的最佳集群数是 5,这不是很明显吗?观察左上方和右上方的聚类,紧密聚类的数据点中间的斑点,以及两个方向上的底部两个。作为这种原始方法的替代,我们可以使用肘方法来计算惯性分数。
图 7:最佳聚类大小检测的肘形图。作者照片。
惯性分数表示聚类内平方和(WCSS ),它表示每个数据点与其所属聚类中心之间的距离。K-means 聚类寻求优化这个 WCSS,以便为可达到的最小距离找到尽可能少的聚类。因此,WCSS 越大,集群越松散,反之亦然。从图 7)中,我们可以发现 WCSS 和集群大小之间的最佳平衡是 5,其中折线图弯曲得像一个弯头。
图 8:惯性得分及其目标函数。作者照片。
检测到 5 是最佳的聚类大小后,我们现在可以开始实现 K-means 聚类模型。
结果向我们展示了五个清晰可辨的集群及其 id。
图 9:集群的散点图。作者照片。
结论
最后的任务通常是给集群命名,并将结果传达给决策者。在我们的例子中,下面的集群名称和随后的结论如下:
集群 0 (右下):收入高但增长潜力低 HL 。
集群 1 (左下):低收入和低增长潜力 LL 。
集群 2 (右上):高收入高增长潜力 HH 。
集群 3 (左上):低收入但高增长潜力 LH 。
集群 4 (中):收入中等,增长潜力中等 MM 。
就经济政策建议而言,我们可以从这项工作中得出以下结论:
- 能源和电力部门属于 LL 类组 1。该行业的企业税负较低,这一点应该保持不变。在当代索马里的社会经济环境中,这一部门进一步发展的可能性很大。
- 电信部门属于 HL 群组 0 类别。该部门的公司虽然收入最高,但税负较低。这一领域似乎监管不足。这些公司应该缴纳公平的税收份额,这将为帮助其他更不景气的行业提供更多的政策空间。
- HH 集群 2 无疑是制造业和建筑业,目前是税负最高的行业之一(约 38%)。我们早些时候已经指出这个部门是如何在主要港口遭受原材料进口税的。电信部门收入的增加可以允许当局这样做。
- LH 第 3 组可确定为农业和畜牧业,这是索马里经济的支柱。这些国家的大部分劳动力都在这个部门就业。除此之外,它在更好的粮食安全方面发挥着关键作用,因此必须得到培育和保护,免受港口和机场不合理的关税和税收。为了实现这些战略目标,必须降低目前接近 40%的高税负。
- 我们还没有讨论的最后一个扇区是 MM 星团 4。是我们政策指导制定剩下的最后一个行业。它可以被认为是金融和货币转移行业,正如我们所看到的,其税收负担非常低,约为 15%。为了更具战略重要性的产业,建议政策制定者提高这一比率。
在本文中,我们研究了如何将经济学和数据科学结合起来,以获得关于紧迫问题的新视角。我们探索了 K-means 聚类算法,经历了一次灵感引力之旅。当然,还有更多的聚类算法:比如 DBSCAN、Affinity Propagation、MeanShit 等等。但这是另一个帖子的故事。
在我的博客上订阅时事通讯,我正在那里为未来的出版物建立读者群。我的推特账号是 @warsame_words ,我欢迎反馈和建设性的批评——对于后者, LinkedIn 是一个受欢迎的渠道。谢谢你陪我走完这段旅程。在 Medium 上关注我,了解我的最新数据相关文章,例如:
[## 无处不在的假新闻:如何用 SOTA NLP 检测
towardsdatascience.com](/fake-news-everywhere-how-to-detect-it-with-sota-nlp-f2dc1e07247c)
新冠肺炎期间的聚集性和帕金森病人
原文:https://towardsdatascience.com/clustering-and-parkinsons-patients-during-covid-19-5552c005cfd9?source=collection_archive---------32-----------------------
变化数据,原因聚类
在新冠肺炎期间发现帕金森病患者的亚组,以对社区内的潜在亚组受疫情影响的方式进行详细分析。
图片来自 iStockPhoto
围绕新冠肺炎有许多挥之不去的问题;久而久之,我们揭示了疾病对不同人群的不同影响。试图理解由高层人口统计学分层的影响是本能的;然而,对遭受神经损伤的社区有什么影响?
在一个 3 人小组中,我们决定分析新冠肺炎影响帕金森氏病患者的方式。帕金森病是第二常见的神经退行性疾病;因此,了解 Covid 对帕金森病患者的影响是有益的。
我们的管道(图片由作者提供)
我们的数据
所使用的数据是围绕疫情和帕金森社区的最大和第一个数据集,由迈克尔·J·福克斯帕金森研究基金会提供。该系统包含 57 个不同的调查/数据集可供选择;我们小组决定合并以下调查:
- **关于你:**人口统计信息,29 列
- **新冠肺炎在 PD 社区的经历:**关于 PD 社区如何受到影响的信息,214 个专栏
- **你的心情:**心情得分,20 列
数据观察
- “情绪”、“Covid”和“关于”信息在单独的数据帧上
- 大量的空值
- 一些行包含“不愿回答”
- 无关列
- 许多二进制列
作者图片
数据预处理目标
- 加入情绪、covid 和关于日期和 id
- 删除包含空值的列
- 删除“不愿意回答”行
- 将情绪列一起编码到单独的类别中
- 由于我们使用聚类算法,我们将执行主成分分析
经过预处理后,我们绘制了解释方差对 PCA 成分的数量。
作者图片
作者图片
由于用 35 个主成分解释的方差比刚好低于 0.80,我们得出结论,35 个主成分将足以压缩 293 列。
k 均值聚类
在高层次上,机器学习的两个子集是监督学习和非监督学习。这两者之间的区别在于实例是否已经被预先标记(监督学习)或者没有被预先标记(非监督学习)。
给定预测值和它们相应的标签,训练监督学习算法,直到它能够区分预测值和它们的标签之间的关系。首要目标是根据新数据实现标签的准确预测。然而,对于无监督学习,目标是推断数据中以前未知或不清楚的关系和模式。
K-Means 是最常见的聚类技术之一,属于无监督学习方法的范畴。通过聚类技术解决的基本情况是当我们想要通过相似性推断数据的自然分组时。
选择‘k’
我们的算法需要输入聚类数 k,您可能想知道我们如何选择合适的聚类数。首先,在选择“k”时没有确定的答案或万无一失的方法。然而,有一些常见的做法来获得一些关于“k”的适当值的直觉。对于这个项目,我们选择了肘方法。
肘法是一个相对简单的想法。对于不同的 k 值,我们简单地评估数据点和它们指定的聚类质心之间的平方距离之和,并且我们选择平方距离之和开始以图形方式变平的 k 值。
作者图片
根据肘法,一个合适的“k”可能在 6 左右。下面,我们通过绘制主成分 1 与接下来的 5 个主成分来可视化具有 6 个聚类的聚类算法的性能。我们可以看到,该算法在识别独立的集群方面做得不错。
基于情感比较聚类
作者图片
虽然大多数集群都有相当积极的反应,但作为对立物脱颖而出的两组是第一和第二集群。
我们使用 Spark 重新运行数据,发现了类似的结果:
作者图片
一个自然的问题出现了:我们能找出是什么导致了两组人之间的差异吗?
收入
作者图片
通过对第 4 组的收入分析,我们发现该组的平均收入得分最低,收入“低于 2 万美元”的比例最高,收入“超过 10 万美元”的比例最低。随后,第 4 组在财务方面受 Covid 的影响最大。
Covid 的影响
作者图片
此外,与平均值相比,第 4 组的 Covid 症状恶化率更高。他们也被建议自我隔离。
收入人口统计
作者图片
第 4 组和第 5 组之间的收入统计数据的比较显示,第 4 组实际上没有退休的患者,而第 5 组有绝大多数退休的患者。
作者图片
由于年龄和退休之间的直接关系,年龄显然是一个需要探索的重要特征。所有患者的年龄分布显示,大多数患者年龄较大。第二个情节突出了第四组是迄今为止最年轻的一组,平均年龄只有 29 岁;这是之前直方图中的一个大的异常值。因为第四组是最不快乐的,我们决定分析这是否普遍。在最后一张图中,我们绘制了所有“快乐”分数与年龄的关系。我们可以看到有一个年龄随正分线性增长的总趋势。
对此的一个可能的解释是,想要社交的年轻人更容易受到 Covid 的社会影响,而更居家的老年人生活更正常。
摘要
- 尽管聚类仅基于欧几里德距离,但如果存在一些基本的差异组(对于正确数量的聚类),它也能准确地捕捉到这些差异组。
- 在这种情况下,聚类分析显示,在新冠肺炎期间,有明显的社会影响对年轻组比对老年组帕金森病人产生不利影响。
— — — — — — — —— — — — — — — — — — — — — — — — — — — — — — —
团队包括:克里斯塔贝尔·帕巴兰、维克多·纳兹鲁克汉扬和丹尼尔·卡雷拉
“Fox Insight 研究(FI)由迈克尔·J·福克斯帕金森研究基金会资助。我们要感谢帕金森社区参与这项研究,使这项研究成为可能。”
“本文准备过程中使用的数据于 2021 年 3 月 10 日从 Fox Insight 数据库(https://Fox Insight-info . michaeljfox . org/Insight/explore/Insight . JSP)获得。有关该研究的最新信息,请访问 https://fox insight-info . michaeljfox . org/insight/explore/insight . JSP。
不列颠哥伦比亚省温哥华的餐馆聚集区
原文:https://towardsdatascience.com/clustering-culinary-neighborhoods-in-vancouver-british-columbia-d8c712399874?source=collection_archive---------21-----------------------
我们可以在哪个集群中找到这家餐厅?让我们来了解一下!(照片由 Unsplash 上的 JP Holecka 拍摄)
通过 Python 中的主题建模和聚类算法,我展示了温哥华各个街区美食的地理模式。
作为一个自豪的温哥华人,我经常向在美国生活时遇到的人提起我来自哪里。除了搞不清楚温哥华位于哪个海岸之外,不熟悉的人通常会告诉我,他们访问这座城市只是为了乘船去阿拉斯加。然而,温哥华不仅仅是加拿大的西部港口。旅游指南宣称温哥华以其的自然美景、令人难忘的户外活动和多样化的社区而闻名。然而,如果不提到温哥华充满活力的美食,那么对温哥华的描述就不完整:
不要告诉这个国家的其他地方,温哥华是加拿大的外出就餐之都。放弃你的饮食,直接进入北美最好的亚洲美食,从闲聊的中国餐馆到越南的 banh mi 三明治店,或者释放你对新鲜捕获的当地海鲜的丰富自助餐的食欲,包括季节性斑点虾和多汁的野生鲑鱼。——孤独星球
但是如果没有旅游指南,我们还能如何找到描述温哥华美食之都的方法呢?答案当然在于数据。
动机:
我对透过温哥华众多“美食街区”的视角探索温哥华很感兴趣——毕竟,当人们说他们住在温哥华时,他们实际上是指他们在外出就餐的地方花了很多时间。和大多数城市一样,温哥华的餐馆往往聚集在客流量大的地区(对此的经济解释可以在这里找到)。
温哥华罗布森街的谷歌地图街景。我们仅在一个街区就有至少四家餐馆!(图像屏幕-由作者捕捉)
但考虑到温哥华可供就餐的美食种类繁多,我对特定类型的美食通常位于何处,以及餐馆聚集在一起的方式是否有任何模式变得更感兴趣。通过主题建模和聚类算法的应用,本博客旨在回答两个问题:
- 某些类型的菜肴在某些地区比在其他地区更有代表性吗?
- 我们可以根据温哥华最受欢迎的美食来划分区域吗?
旅行者在选择外出就餐的特定菜系时可以使用这种分析来识别感兴趣的区域,但也可以标记特定菜系的餐馆经营者的进入区域,该餐馆经营者希望避开可能已经被该菜系饱和的区域。
数据收集和准备:
为了回答这些问题,我使用了 Yelp 提供的数据,确定了位于温哥华本地边界内的约 4000 家餐馆类企业。我从 Yelp 餐厅数据中分析了三个主要特征:
- 地理位置
- 来自 Yelp 定义的餐厅标签的美食类型
- 平均星级的贝叶斯估计。这是 Yelp 确定的 5 星评级的一种修改措施,用于减少评论数量少的企业产生的噪音。我用来计算这个指标的公式可以在这个网站上找到
我的数据样本,如果我自己这么说的话,这是一个非常好的多汁猪肉饺子的地方……(图片由作者提供)
我们分析的第一步是为我们的餐馆数据确定标签,这些标签将餐馆分成人们会去并容易走进的区域。我称这些为“美食社区”我从温哥华市政府定义的 22 个社区中的餐馆位置开始:
(图片由作者提供)
餐馆往往聚集在一些可见的区域,但城市提供的街区边界在识别我们的美食街区时提出了两个问题:
- 我们看到出现在城市街区边界的餐馆集群会被任意分割。
(图片由作者提供)
- 我们还看到,像美景镇这样的较大的社区将大量的餐馆聚集在一起,而没有占据社区内较小的、更适合步行的区域。
(图片由作者提供)
我避免使用城市的标签来识别我的烹饪社区,而是使用 KMeans 聚类算法在餐馆的位置上生成标签。在我指定了我希望在我的数据中包含的标签数量(KMeans)之后,该算法的效果是根据它们的位置来标记餐馆。使用 scikit-learn 的轮廓分数作为优化我的标签质量的指标,我将我的数据分成 123 个烹饪社区。这产生了以下更新的餐厅图,用颜色表示我们烹饪社区的不同标签:
(图片由作者提供)
数据建模
现在我们已经确定了我们的烹饪社区,我们可以开始确定在这些社区中发现的烹饪类型的模式。我将我的数据建模过程概述如下。
- 首先,我将每个街区表示为不同菜系数量的向量。这给了我们一个初步的方法来量化我的邻居,并找出他们之间的差异。
- 为了纳入餐馆质量的信息,我进一步调整了每一种菜系的计数,这是基于该街区对该菜系相对于城市平均水平的平均评分。
- 我的数据显示有 332 种不同的烹饪类型,因此很难确定我们的数据中可能存在什么模式。因此,我对我的数据应用了一种 NMF 算法,将每个街区描述为一个美食群体的集合,而不是许多单独的美食类型——这一过程被称为主题建模(下文将详细介绍)。为了简单地描述这个过程,NMF 算法使用关于通常发生在邻近地区的烹饪类型的信息,并创建由各个烹饪类型的分布构成的烹饪组(主题);然后,该算法根据每个街区在每个烹饪组中的权重,生成每个街区的表示。
(图片由作者提供)
- 将每个邻域转换成烹饪组集合后,我应用另一个 KMeans 聚类算法,根据每个烹饪组的权重对邻域进行聚类。这将决定我们可能会在每个街区代表的烹饪群体中看到什么样的模式。
(图片由作者提供)
主题建模温哥华美食
在对我的数据尝试 NMF 算法的不同数字输入后,我决定对四个烹饪组进行建模。按照在每个烹饪组中的权重显示前 5 种烹饪类型揭示了一些非常独特的主题。
平均类别计数还显示了城市中每种烹饪类型的出现与其在每个烹饪组中的权重之间的一般相关性(图片由作者提供)
第 1 组(酒吧/西方)的主要特点是酒吧的出现,以及西方美食类型,如三明治、海鲜和来自加拿大和美国的美食。
对于第 2 组(中国/越南),我们看到中国美食和其他相关标签如点心和海鲜的权重很大。鉴于温哥华有大量的中国人口,这在温哥华作为一个烹饪团体并不令人惊讶。然而,我们也看到了相当大的重量为越南菜,这意味着这些美食一起出现在类似的地点。
第 3 组(日本/韩国)显示了类似的趋势,日本料理占很大比重,而韩国料理也占相当大的比重。
最后,我们有第 4 组(休闲/咖啡馆),它有咖啡和茶、咖啡馆、早午餐、比萨饼和三明治,是这个烹饪组的特色。
按烹饪类别对温哥华街区进行聚类
现在我们来看看我们的第二个 KMeans 聚类算法是如何基于烹饪组权重对我们的邻居进行聚类的。在这里,我选择 K = 5 是基于确定损失度量的最大减少,惯性(参见 scikit-learn 的聚类文档的第 2.3.2 节)。
下面,我提供了显示特定邻域分组的邻域具有的权重范围的箱线图。除了邻域标签#5 之外,这些邻域聚类中的每一个都表现出对我建模的四个烹饪组中的一个的强权重,如来自特定烹饪组的每个邻域的高权重所示。
(图片由作者提供)
结果
在所有这些建模之后,我们最终可以在温哥华的地图上绘制出我们得到的邻域标签,在那里我们可以找到针对特定烹饪群体的加权区域。每个邻域分组的图例如下:
- 绿色:偏向条形/西部
- 黄色:偏向中国人/越南人
- 紫色:偏向日语/韩语
- 红色:偏向休闲/咖啡馆
- 蓝色:不偏向任何一个烹饪类别
(图片由作者提供)
总的来说,温哥华的许多地区并不是由一个特定的烹饪团体主导的,直到你开始搬进住宅区或温哥华市中心。以下是我从这张地图中得到的一些亮点:
- 在橙色圆圈中,我们看到温哥华市中心被绿色的酒吧/西餐集团所占据,这是可以理解的,因为这与温哥华的夜生活有关。然而,我们也看到了一些标记为其他烹饪组的口袋,不仅显示了温哥华的餐饮选择是多么多样化,而且也显示了日本和中国烹饪组的密集区域。这些饱和区可以定位有意义的区域,如温哥华的唐人街,由市中心东侧的黄色集群表示。
- 金色圆圈代表我在查看数据时的一个发现。在我进行分析之前,我所知道的温哥华唯一充斥着日本或韩国餐馆的地区都位于市中心。然而,调查这个美食街区的标签,发现一个由日本餐馆主导的区域,我以前并不熟悉。我看了一下排名前三的日本餐馆,发现它们也有一些不错的评论!我在这里联系一下供参考: Saku 、 Uma 寿司、丸里路咖啡馆。
总结思路
我的项目揭示了温哥华的餐馆场景可以分为四大菜系,其中三个主要倾向于酒吧、中国和日本菜系。在地图上标出不同的菜系表明,在某些地区某些民族的菜系占主导地位,从而确定人们可以在城市的多个地区寻找特定的菜系。
我计划研究如何将温哥华的其他地理和人口特征结合起来,看看能否根据用户可能被吸引的区域创建一个餐馆推荐系统。
我对这些街区的最终标记似乎与我对这个城市的了解相吻合。它和你的一致吗?如果你同意或不同意,请在评论中告诉我!
聚类:如何利用惯性找到超参数
原文:https://towardsdatascience.com/clustering-how-to-find-hyperparameters-using-inertia-b0343c6fe819?source=collection_archive---------7-----------------------
Robynne Hu 在 Unsplash 上的照片
介绍
由于没有标签,聚类是非常强大的。获取标记数据通常既昂贵又耗时。聚类通常用于发现数据中的模式。然后,为了改进某个产品,经常使用找到的模式。一个著名的例子是客户聚类。在客户聚类中,可以找到相似的用户组。如果一个群体的顾客购买了某些产品,这个群体的其他顾客可能也会喜欢他们。因此,可以应用有针对性的广告来增加销售。另一个著名的例子是将网络活动分为欺诈行为和非欺诈行为。
有许多不同的聚类算法。K-Means 算法是一种非常简单而又强大的聚类算法。K-Means 算法要求用户首先定义聚类的数量,可能还需要定义聚类的初始化策略。但是如何找到这些参数呢?对于网络活动的群集,可以使用两个群集。一个用于欺诈活动,一个用于非欺诈活动。但是有多少个聚类用于客户聚类呢?在监督学习中,可以尝试不同的超参数和聚类数,并可以直接计算一些误差度量,如准确度。导致最高精确度的超参数集和聚类数然后可以用于最终模型。但是这对于无监督学习是不可能的,因为缺乏基础真值。那么,为了评估和比较不同的超参数和聚类数,可以为无监督学习做些什么呢?
一种可能性是计算群集内的平方和,也称为惯性。
在这篇短文中,介绍了惯性值。然后使用 Scikit-Learn 在小数据集上训练 K-Means 聚类算法。使用计算的惯性值和应用在惯性曲线上的肘方法找到最佳的聚类数。最后但同样重要的是,本文展示了如何使用惯性值找到最佳超参数。代码是用 Python 和 Jupyter 笔记本编写的。代码可以在我的 Github 页面找到。
惯性
惯性或组内平方和值给出了不同组的一致性的指示。等式 1 显示了计算惯性值的公式。
等式 1:惯性公式
n 是数据集内的样本数,C 是聚类的中心。因此,惯量简单地计算聚类中每个样本到其聚类中心的平方距离,并将它们相加。对该数据集中的每个聚类和所有样本进行该过程。惯性值越小,不同的聚类越一致。当添加的聚类数与数据集中的样本数一样多时,惯性值将为零。那么如何利用惯性值找到最优的聚类数呢?
为此,可以使用所谓的弯管法。但是让我们通过一个例子来看看这个方法。
最优聚类数的肘方法
通过直接应用于实例来学习总是更好的。为此,使用 Scikit-Learns make_blobs 函数创建一个具有二维特征的数据集。图 1 显示了创建这个数据集的代码,而图 2 显示了这个数据集的绘图。
图 1:创建集群数据集的代码(作者代码)。
图 2:数据集的绘图(图片由作者提供)。
这个数据集中有三个聚类,因此 K-Means 的最佳聚类数应该是三。但是让我们假设我们还不知道。
现在,让我们为不同数量的聚类训练 K 均值模型,并存储每个训练模型的惯性值。然后,可以绘制惯性曲线,以便使用肘方法来寻找最佳的聚类数。这些步骤的代码可以在图 3 中找到。图 4 显示了最终的惯性曲线。
图 3:用不同数量的聚类训练 K 均值模型并绘制惯性曲线的代码(作者编写的代码)。
图 4:惯性曲线(图片由作者提供)。
红色的 x 标记标记肘点。肘点给出了最佳的聚类数,这里是三个。这完全有意义,因为数据集是这样创建的,有三个不同的聚类。当添加更多的聚类时,惯性值减小,但是聚类中包含的信息也进一步减少。拥有多个集群会导致性能下降,并且也不会产生最佳的集群结果。让我们假设你做了一个客户聚类,你有许多小的聚类。当一个小客户群购买某样东西时,你只能向该产品的少数其他潜在买家推销。但是,当你有一个大的连贯集群,那么你可以直接解决更多的潜在买家。
因此,对于本例,最佳聚类数是 3。图 5 显示了三个不同集群的可视化。
图 5:三个聚类的 K-Means 结果的可视化(图片由作者提供)。
利用惯性值寻找最优超参数
惯性值也可以用于为无监督 K-均值算法寻找更好的超参数。一个潜在的超参数是初始化方法。在 Scikit-Learn 中,有两种不同的可能性。一个叫 k-means++ 一个叫 random 。但是应该使用哪种初始化呢?为了回答这个问题,可以为每个初始化策略训练一个 K 均值模型,并比较其惯性值。导致较小惯性值的策略可以用作最佳策略。图 6 显示了该评估的代码,图 7 显示了结果的数据框。
图 6:用于比较 K-Means 算法的不同初始化策略的代码(由作者编写)。
图 7:包含每个初始化策略的惯性值的数据框(图片由作者提供)。
可以看出,随机初始化实现了稍小的惯性值,并且在这里可以用作最佳初始化策略。
结论
聚类算法在发现数据模式方面非常有效。聚类算法通常只需要几个超参数,如聚类数或聚类的初始化策略。由于缺乏基础真值,寻找最优值不像监督学习那样简单。为了仍然能够找到最佳值,可以使用惯性值和弯头方法。
地理空间应用中的聚类—您应该使用哪种模型?
原文:https://towardsdatascience.com/clustering-in-geospatial-applications-which-model-should-you-use-59a039332c45?source=collection_archive---------8-----------------------
思想和理论
应用于城市网络的机器学习中的 KMeans、DBSCAN 和分层聚类模型之间的新比较
香港夜间交通| PxHere
T 看看 Python 中流行的机器学习工具箱,scikit-learn 关于不同聚类算法的页面——你会看到 10 种不同算法之间的比较。软件包开发人员在比较和可视化应用于不同玩具场景的不同聚类算法方面做得非常出色。这些可视化的优势在于你肯定知道基本事实——例如,3 个斑点应该是 3 个集群。然而,这并没有明确地告诉我们这些算法将如何处理地理空间数据,这可能是相当复杂的。地理空间聚类的一些重要应用包括减少大型位置数据集的大小,以及通过出租车出行聚类了解大规模移动模式,用于城市规划和交通。
在许多实际情况下,很难先验地知道有多少个聚类是正确的。在这种情况下,很难解释将数据分组到聚类中的聚类算法的结果。再加上其他 9 种算法,你可能会在每种算法中得到不同的结果,而且几乎不可能知道哪种算法最接近事实。在这里,我通过 3 个步骤对同一个曼哈顿城市街道网络数据集应用了 3 种代表性的聚类算法——k means、DBSCAN 和层次凝聚聚类:
- 使用逾渗理论的统计物理学中的相变标准,通过随机移除临界数量的节点,将曼哈顿街道网络分成 3 个大型集群
- 对数据集应用不同的聚类算法,并在此过程中发现一种在节点移除之前校准聚类算法的新方法
- 通过 Jaccard 相似性度量评估哪些聚类算法的性能优于其他算法。
好了,该行动了!
从 OSMnx 获得曼哈顿街道网络
import osmnx as ox
place=’Manhattan, New York City, New York, USA’
G = ox.graph_from_place(place)
ox.plot.plot_graph(G,edge_linewidth=0.1,edge_color='C0',node_size=0,bgcolor='w',save=True, filepath='Manhattan.png')
从 OSMnx 获得的曼哈顿街道网络
为了获得曼哈顿的街道网络,我们使用了 OSMnx,这是一个基于 python 的包,用于利用强大的协作地图项目 OpenStreetMap (OSM)对城市街道网络进行网络分析。网络包含表示交叉点的结点和表示交叉点之间双向道路的边。
来自逾渗理论的基本事实
为了获得地面真相,我们需要找到一种方法,通过适当地删除节点,将网络划分为少量的簇。这对于网络来说通常是困难的,因为仅仅移除几个节点就可能导致多个小集群,从单个大集群中分离出来,并且这变得难以通过聚类算法来检测。
相反,我们使用逾渗理论的统计物理学。许多论文(包括我们最近关于联网车辆遭受网络攻击后大规模网络中断的工作)表明,随机移除城市网络中的节点会导致渗透转变。在这个转变点,第二大簇具有最大的尺寸。这意味着在逾渗点,聚类算法最有可能从其余的噪声中区分出两个或三个大的聚类。
w = np.where(SG == np.max(SG))[0][0]G2 = G.copy()
G2.remove_nodes_from(nodes_G[0:int(w*100)])
conn = nx.weakly_connected_components(G2)
conn_list = list(conn)
conn_list = sorted(conn_list, key=len, reverse=True)
G3 = G2.copy()
for i in range(0, len(conn_list) — 3):
G3.remove_nodes_from(conn_list[i + 3])X_G3 = [[G3.nodes[node][‘y’], G3.nodes[node][‘x’]] for node in G3.nodes]
ids_G3 = [list(G3.nodes())[i] for i in range(0, len(list(G3.nodes())))]labels=np.zeros(len(ids_G3))for i in range(0,len(ids_G3)):
if(ids_G3[i] in conn_list[0]):
labels[i]=0if(ids_G3[i] in conn_list[1]):
labels[i]=1if(ids_G3[i] in conn_list[2]):
labels[i]=2nc_g,ns_g=plot1(G,ids_G3,labels,’ground_truth.png’)
逾渗转换法将城市网络分解成集群以备后续测试|塞犍陀·维韦克
3 个最大的集群|塞犍陀·维维克
3 个最大的聚类代表了与我将要介绍的各种聚类算法相比较的“基本事实”。
K 表示 K=3
k 均值的收敛| Chire
首先,让我们看看 vanilla KMeans 方法是如何工作的。KMeans 方法将数据划分为 K 个簇,通过迭代优化来减少簇内方差。每个可观察值属于具有最近平均值的组。显而易见的选择是 K=3,从地面真理。
#kmeans n_clusters=3
model = KMeans(n_clusters=3, random_state=0).fit(X_G3)
k3_labels = model.labels_
#kmeans_labels = np.unique(model_labels[model_labels >= 0])nc_k3,ns_k3=plot1(G, ids_G3, k3_labels,’kmeans_3.png’)
K 均值聚类结果,K=3 |塞犍陀·维韦克
结果表明,KMeans 将第一个聚类分成两个,而将第二个和第三个聚类合并为一个单独的聚类。这是由于 KMeans 对球状、线性可分数据的限制。请记住,在这种情况下,我们选择了 K=3 的值,因为我们从地面真相中知道应该是 3 个集群。然而,情况并非总是如此,大多数时候我们不知道有多少个集群存在,需要一个可靠的算法来告诉我们要寻找多少个集群。相反,让我们使用 elbow 方法来找到最佳的聚类数,然后使用最佳的聚类数来应用 KMeans。
肘法
#kmeans elbow methodmodel = KMeans()
visualizer = KElbowVisualizer(model, k=(4, 12))visualizer.fit(np.array(X_G3)) # Fit the data to the visualizer
model = KMeans(n_clusters=visualizer.elbow_value_, random_state=0).fit(X_G3)
ke_labels = model.labels_
#kmeans_labels = np.unique(model_labels[model_labels >= 0])nc_ke,ns_ke=plot1(G, ids_G3, ke_labels,’kmeans_elbow.png’)
使用肘方法,用 KMeans 对结果进行聚类;K=7 |塞犍陀·维维克
我们使用 yellow brick machine learning visualizer 软件包中的 KEllbowVisualizer,它实现了“肘”方法,通过用一系列 K 值拟合模型来选择最佳聚类数。肘方法给出了 K=7 的最佳值,但与选择 K=3 相比,它的表现尤其糟糕。
肘形法
DBSCAN 方法广泛用于地理空间聚类。该方法使用两个参数 MinPts 和 Eps 来拟合聚类。MinPts 是将一个点视为聚类核心的一部分所需的半径 Eps 内的最小数量,包括该点本身(下图中标为 A 的点)。如果一个点是从核心点可到达的,但是在半径 Eps 内不包含 MinPts,那么它被认为是该簇的非核心点(点 B & C)。最后,从核心点不可到达的点是噪声点(点 N)。
DBSCAN 聚类算法,MinPts=4| Chire
选择 Eps 和 MinPts 并不简单,但是有一些广泛使用的试探法。通常使用 min pts≥2 *维。我们使用 MinPts=5,因为曼哈顿很大程度上是一个网格。在一个网格中,每个交叉点都有 4 个相邻的交叉点,这使得 5 个交叉点包括它自己。要选择 Eps,我们用肘法
neigh = NearestNeighbors(n_neighbors=5)
nbrs = neigh.fit(np.radians(X_G3))
distances, indices = nbrs.kneighbors(np.radians(X_G3))
distances = distances[:, 1]
distances = np.sort(distances, axis=0)
fig=plt.figure()
plt.plot(distances)
plt.xlim(15000, 19000)
plt.ylim(.000001, .00002)plt.ylabel(‘5-NN Distance (Radians)’)
plt.xlabel(‘Points Sorted By Distance’)
plt.savefig(‘dbscan_elbow’,dpi=600)model = DBSCAN(eps=0.000005, min_samples=5, algorithm=’ball_tree’, metric=’haversine’).fit(np.radians(X_G3))dbe_labels = model.labels_
#db_labels = np.unique(model_labels[model_labels >= 0])
nc_dbe,ns_dbe=plot1(G, ids_G3, dbe_labels,’dbscan_elbow_G.png’)
寻找最佳 Eps 的 DBSCAN 肘法|塞犍陀·维韦克
塞犍陀·维韦克
这种方法效果很差。似乎 Eps=0.000005 被严重低估了,因为星团非常小。相反,如果我们在删除节点之前查看群集以进行校准,会怎么样?
校准的 DBSCAN
当曼哈顿街道网络中的节点未被移除时,理想的算法将给出 1 个大的连通聚类,而当节点被移除时,将给出 3 个聚类。让我们利用这些信息来校准 DBSCAN 算法的 Eps 值。
#dbscan calibration method# now figuring optimal epsilon for city
cs = np.zeros(16)
for i in range(0, 16):
db = DBSCAN(eps=np.linspace(0.000005, 0.000005 * 10, 16)[i], min_samples=5, algorithm=’ball_tree’, metric=’haversine’).fit(
np.radians(X_G))
cs[i] = len(np.unique(db.labels_))
# print(0.000005*(i+1))fig=plt.figure()
plt.loglog(np.linspace(0.000005, 0.000005 * 10, 16), cs)
plt.ylabel(‘Number Of Clusters’)
plt.xlabel(‘Eps Value (radians)’)
plt.savefig(‘dbscan_calib’,dpi=600)model = DBSCAN(eps=0.00003, min_samples=5, algorithm=’ball_tree’, metric=’haversine’).fit(np.radians(X_G3))dbc_labels = model.labels_
nc_dbc,ns_dbc=plot1(G, ids_G3, dbc_labels, ‘dbscan_calib_G.png’)
查找 Eps 的 DBSCAN 校准方法|塞犍陀·维韦克
DBSCAN 校准方法|塞犍陀·维韦克
我们选择在没有删除节点时给出一个集群的最小 Eps 值,得到 Eps=0.00003。这产生了一个更好的结果,并且直观地显示出 3 个集群。第一个似乎覆盖了地面实况组 1 和 2,第二个和第三个组分裂了第三个地面实况组。所以更好,但不完美。
校准的层次凝聚聚类
Iris 数据集 | Talgalili 的层次聚类树状图
最后,让我们看一个聚类算法,它构建了一个聚类的层次结构。层次凝聚聚类是一种自下而上的方法,其中每个可观察值从一个单独的聚类开始,随着一个聚类在层次中向上移动,聚类对被合并。一般来说,这是一个相当慢的方法,但有一个强大的优势,那就是可以可视化整个聚类树,称为树状图。
根据应用程序的不同,有一些不同的选项来查找集群的数量。与 KMeans 类似,可以选择集群的数量。或者,当聚类相距太远而无法合并时,使用距离标准来停止聚类,类似于 DBSCAN。
层次聚类的缺点在于选择聚类数量或距离标准的非直观性——相当于将上述的树状图可视化,并进行任意的截断。
相反,我做了一些类似于 DBSCAN 校准方法的事情——从完全连通的曼哈顿网络校准凝聚聚类距离标准,而不移除节点。
#hierarchical agglomerative clustering calibration method
n_l=np.zeros(10)
for i in range(0,10):
model = AgglomerativeClustering(distance_threshold=np.linspace(0.02,.2,10)[i], n_clusters=None)
model = model.fit(np.radians(X_G))
distances = model.distances_
n_l[i]=len(np.unique(model.labels_))
print(i)
plt.plot(np.linspace(0.02,.2,10),n_l)nc_ag,ns_ag=plot1(G, ids_G3, ag_labels, ‘hierarch_calib.png’)model = AgglomerativeClustering(distance_threshold=.2, n_clusters=None)
model = model.fit(np.radians(X_G3))
ag_labels = model.labels_
nc_ag,ns_ag=plot1(G, ids_G3, ag_labels, 'hierarch_calib_G.png')
分级凝聚聚类距离标准校准|塞犍陀·维韦克
类似于 DBSCAN,我选择对应于距离阈值的最小值的距离标准,当没有节点从曼哈顿的街道网络中移除时,该距离阈值给出 1 个聚类。凝聚聚类只给出一个大的聚类。
分层凝聚聚类结果|塞犍陀·维维克
当选择簇数= 3 时,看起来更好。
分层凝聚聚类结果,n_clusters=3 |塞犍陀·维韦克
地理空间应用的最佳算法是什么?
我们考虑了 3 种常用的空间聚类算法:KMeans、DBSCAN 和应用于曼哈顿街道网络的分层凝聚聚类。有趣的是,答案并不像我最初想的那样简单,它取决于最佳聚类数是否是先验已知的。
为了比较苹果和苹果,我在没有先验知识的情况下绘制了聚类算法的输出。从视觉上看,DBSCAN 似乎做得最好,证明了它在地理空间应用程序中的广泛使用。然而,如果我们事先知道聚类的数目,情况就不是这样了。
缺乏聚类数目先验知识时的聚类算法性能|塞犍陀·维韦克
为了量化每个算法的表现,我对非二进制类使用了 Jaccard 相似性度量。
评估地理空间聚类算法的 Jaccard 评分|塞犍陀·维韦克
表现最好的是凝聚聚类算法,使用 n_clusters=3 (ag_3),其 Jaccard 得分超过 0.65。在没有这些信息的情况下,通过校准(db_calib,ag_calib)的 DBSCAN 和凝聚聚类是并驾齐驱的。然而,我将把这一轮交给 DBSCAN,因为它识别单独的聚类,而凝聚聚类算法只找到单个聚类。
结论
如您所见,没有完美的空间聚类算法。在地理空间应用中尤其如此,其中网络节点和边不是均匀分布的,并且数据通常是有噪声的。获得的聚类算法结果可能是曼哈顿街道分布的一个特征,曼哈顿比其他城市更像网格-观察这些算法在其他城市网络中的表现可能会很有趣。我们知道,与新加坡、罗马和圣保罗等城市相比,芝加哥、迈阿密和曼哈顿等城市的街道网络更像网格。这里开发的方法通常可以应用于量化聚类方法在各种地理空间场景中的功效。如果您感兴趣,可以在 GitHub 上找到 python 代码。还有一个朱庇特笔记本:
https://github.com/skandavivek/Geospatial-Clustering
以下是 YouTube 上的教程链接:
参考文献:
- Geoff Boeing,“聚类减少空间数据集大小”,SocArxiv (2018)
- Dheeraj Kumar 等人,“通过出租车出行聚类了解城市移动性”,第 17 届 IEEE 移动数据管理国际会议(MDM) (2016)
- https://arxiv.org/abs/1903.00059塞犍陀·维韦克等人,“被黑客攻击的联网车辆的网络物理风险”,《物理评论》E (2019)
- Geoff Boeing,《城市空间秩序:街道网络定向、配置和熵》,应用网络科学(2019)
如果你喜欢这篇文章,请关注我。
如果你对科技和现代社会之间的相互联系有全面的看法,请订阅我的时事通讯。
*https://skandavivek.substack.com/ *
PyCaret 简化了集群
原文:https://towardsdatascience.com/clustering-made-easy-with-pycaret-656316c0b080?source=collection_archive---------3-----------------------
利用强大的 Python 库进行低代码机器学习
卢卡斯·霍布斯在 Unsplash 上的照片
这篇文章的内容最初发表在我的最新著作《用 PyCaret 简化机器学习》中。你可以点击这里了解更多。
无监督机器学习的基本任务之一是聚类。此任务的目标是根据给定数据集实例的共同特征,将它们分类到不同的群集中。聚类在各个领域有许多实际应用,包括市场研究、社会网络分析、生物信息学、医学等。在本文中,我们将通过使用 PyCaret 来检查一个聚类案例研究,PyCaret 是一个 Python 库,它支持所有基本的机器学习任务,如回归、分类、聚类和异常检测。PyCaret 通过遵循低代码方法简化了机器学习工作流,从而使其成为初学者以及希望快速原型化 ML 模型的专家的绝佳选择。
软件要求
本文中的代码应该可以在所有主要的操作系统上运行,比如微软的 Windows、Linux 和苹果的 macOS。你需要在你的电脑上安装 Python 3 和 JupyterLab。我建议你使用 Anaconda,这是一个机器学习和数据科学工具包,包括许多有用的库和软件包。Anaconda 可以在这个链接免费下载。或者,你可以使用像 Google Colab 这样的云服务来运行 Python 代码,而不用担心在你的机器上安装任何东西。你可以创建一个新的 Jupyter 笔记本并输入代码,或者从 Github 库下载。
正在安装 PyCaret
通过在 Anaconda 终端上执行以下命令,可以在本地安装 PyCaret 库。您还可以在 Google Colab 或类似的服务上执行相同的命令,将库安装到远程服务器上。
pip install pycaret[full]==2.3.4
执行该命令后,PyCaret 将被安装,您将能够运行本文的所有代码示例。建议通过包含[full]
说明符来安装可选的依赖项。此外,安装正确的包版本确保了最大的兼容性,因为我使用的是 PyCaret ver。2.3.4 撰写本文时。最后,为 PyCaret 创建一个 conda 环境被认为是最佳实践,因为它将帮助您避免与其他包的冲突,并确保您总是安装了正确的依赖项。
k 均值聚类
K-Means 聚类是最流行和最简单的聚类方法之一,易于理解并在代码中实现。它在下面的公式中定义。
K 是所有集群的数量,而 C 代表每个单独的集群。我们的目标是最小化 W ,这是集群内变化的度量。
定义类内变异有多种方法,但最常用的方法是平方欧几里德距离,如上式所示。这导致了以下形式的 K 均值聚类,其中 W 被欧几里德距离公式代替。
使用 PyCaret 进行聚类
K-Means 是一种广泛使用的方法,但还有许多其他可用的方法,如仿射传播、谱聚类、凝聚 Clustering⁴、均值漂移 Clustering⁵和基于密度的空间聚类(DBSCAN)⁶.我们现在将了解 PyCaret 聚类模块如何帮助我们轻松地训练模型并评估其性能。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
from pycaret.clustering import *
from sklearn.datasets import make_blobs
mpl.rcParams['figure.dpi'] = 300
我们首先导入一些标准的 Python 库,包括 NumPy、pandas、Matplotlib 和 Seaborn。我们还导入了 PyCaret 聚类函数,以及可用于生成数据集的make_blobs()
scikit-learn 函数。最后,我们将 Matplotlib 图形 DPI 设置为 300,这样我们就可以获得高分辨率的图形。没有必要启用此设置,所以如果需要,可以删除最后一行。
生成合成数据集
cols = ['column1', 'column2', 'column3',
'column4', 'column5']arr = make_blobs(n_samples = 1000, n_features = 5, random_state =20,
centers = 3, cluster_std = 1)data = pd.DataFrame(data = arr[0], columns = cols)
data.head()
作者图片
data.info()<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 5 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 column1 1000 non-null float64
1 column2 1000 non-null float64
2 column3 1000 non-null float64
3 column4 1000 non-null float64
4 column5 1000 non-null float64
dtypes: float64(5)
memory usage: 39.2 KB
我们将使用make_blobs()
scikit-learn 函数生成一个合成数据集,而不是加载真实世界的数据集。该函数生成适合于聚类模型的数据集,并且具有可以根据我们的需要修改的各种参数。在本例中,我们创建了一个包含 1000 个实例、5 个特征和 3 个不同聚类的数据集。使用合成数据集来测试我们的聚类模型有各种好处,主要是我们已经知道了实际的聚类数,因此我们可以轻松地评估模型性能。真实世界的数据通常更加复杂,也就是说,它们并不总是具有明显分离的聚类,但是使用简单的数据集可以让您熟悉工具和工作流。
探索性数据分析
data.hist(bins = 30, figsize = (12,10), grid = False)plt.show()
作者图片
hist()
pandas 函数让我们可以轻松地可视化每个变量的分布。我们可以看到,所有变量分布要么是双峰的,要么是多峰的,也就是说,它们有两个或更多的峰值。当数据集包含多个具有不同特征的组时,通常会发生这种情况。在这种情况下,数据集专门创建为包含 3 个不同的聚类,因此变量具有多峰分布是合理的。
plt.figure(figsize=(10, 8))
sns.heatmap(data.corr().round(decimals=2), annot=True)plt.show()
作者图片
我们使用了corr()
pandas 函数和heatmap()
Seaborn 函数来创建一个热图,可视化所有变量对的相关值。我们可以看到列 2 和列 3 有很强的线性关系,相关值为 0.93。第 3 列和第 4 列也是如此,相关值为 0.75。另一方面,列 1 与所有其他列反向相关,尤其是列 5,其值为-0.85。
plot_kws = {'scatter_kws': {'s': 2}, 'line_kws': {'color': 'red'}}
sns.pairplot(data, kind='reg', vars=data.columns[:-1], plot_kws=plot_kws)plt.show()
作者图片
我们使用pairplot()
Seaborn 函数为合成数据集创建散点图矩阵,对角线上有每个变量的直方图。数据集聚类在散点图中是可见的,这表明它们彼此明显分开。正如之前在关联热图中观察到的,我们可以看到一些变量对具有很强的线性关系,而其他变量对则具有相反的线性关系。通过将pairplot()
函数的kind
参数设置为reg
,每个散点图中包含的回归线突出显示了这一点。
正在初始化 PyCaret 环境
cluster = setup(data, session_id = 7652)
作者图片
在完成探索性数据分析(EDA)之后,我们现在将使用setup()
函数来初始化 PyCaret 环境。通过这样做,将创建一个为模型训练和部署准备数据的管道。在这种情况下,默认设置是可以接受的,所以我们不打算修改任何参数。不管怎样,这个强大的函数有许多数据预处理能力,所以你可以参考 PyCaret 集群模块的文档页面来阅读更多关于它的细节。
创建模型
model = create_model('kmeans')
作者图片
create_model()
函数让我们可以轻松地创建和评估我们偏好的聚类模型,比如 K-Means 算法。这个函数默认创建 4 个集群,所以我们可以简单地将num_clusters
参数设置为 3,因为这是正确的数字。相反,我们将遵循一种对真实世界数据集进行归纳的方法,其中聚类数通常是未知的。执行该功能后,将打印出许多绩效指标,包括 Silhouette⁷、Calinski-Harabasz⁸和 Davies-Bouldin⁹.我们将把重点放在轮廓系数上,它在下面的等式中定义。
- s(i) 是数据集实例 i 的剪影系数。
- a(i) 是 i 的平均类内距离。
- b(i) 是 i 的平均最近簇距离。
产生的度量值是所有实例的平均轮廓系数,范围在-1 和 1 之间。负值表示实例被分配到了错误的集群,而接近 0 的值表示集群重叠。另一方面,接近 1 的正值表示分配正确。在我们的示例中,该值为 0.5822,这表明可以通过为数据集找到最佳聚类数来提高模型性能。接下来,我们将看看如何通过使用肘方法来实现这一点。
plot_model(model, 'elbow')
作者图片
plot_model()
函数让我们为模型创建各种有用的图表。在这种情况下,我们创建了一个肘图,它将帮助我们找到 K-Means 模型的最佳聚类数。肘方法为一系列的 K 值训练聚类模型,并可视化每个⁰.的失真分数曲线上的拐点——即所谓的“肘”——表明了 K 的最佳值。正如所料,该图在 K = 3 处有一个拐点,用垂直虚线突出显示。
model = create_model('kmeans', num_clusters = 3)
作者图片
在使用肘方法找到最佳聚类数之后,我们再次训练 K-Means 模型。正如我们所看到的,平均轮廓系数增加到 0.7972,表明模型性能提高,每个数据集实例的聚类分配更好。
绘制模型
plot_model(model, 'cluster')
作者图片
如前所述,plot_model()
是一个有用的函数,可以用来为我们的聚类模型绘制各种图形。在这种情况下,我们为 K 均值模型创建了 2D 主成分分析(PCA)图。PCA 可用于将数据投影到低维空间,同时保留大部分方差,这种技术称为降维。在将 PCA 应用于合成数据集之后,原始的 5 个特征已经减少到 2 个主成分。此外,我们可以看到集群被清楚地分开,并且所有数据集实例都被分配到正确的集群。
保存和分配模型
save_model(model, 'clustering_model')results = assign_model(model)
results.head(10)
作者图片
save_model()
函数让我们将集群模型保存到本地磁盘,以备将来使用或作为应用程序部署。模型存储为 pickle 文件,可以使用补充的load_model()
功能加载。此外,assign_model()
函数返回合成数据集,并为分配给数据集实例的分类标签添加一列。
结论
希望我在本文中提供的案例研究能够帮助您掌握 PyCaret 集群模块。我还鼓励读者自己尝试其他数据集并实践上述技术。如果你想了解更多关于 PyCaret 的知识,你可以查看用 Pycaret 简化机器学习,这是我最近出版的一本关于图书馆的书。欢迎在评论中分享你的想法,或者关注我的 LinkedIn,我会定期在那里发布关于数据科学和其他主题的内容。
参考
[1]:斯坦利,道格拉斯。" K-均值聚类:半个世纪的综合."英国数学和统计心理学杂志 59.1(2006):1–34。
[2]:杜拉克,德尔伯特。相似性传播:通过传递消息来聚集数据。多伦多:多伦多大学,2009 年。
[3]:冯·卢克斯堡,乌尔里克。"关于谱聚类的教程."统计与计算 17.4(2007):395–416。
[4]:阿克曼,马塞尔 r 等,“凝聚式聚类分析”算法 69.1(2014):184–215。
[5]:德尔潘尼斯,康斯坦丁诺斯 g .“均值漂移聚类”课堂讲稿(2005): 32。
[6]:汗、卡姆兰等《DBSCAN:过去、现在和未来》第五届数字信息与网络技术应用国际会议(ICADIWT 2014)。IEEE,2014 年。
[7]: Rousseeuw,Peter J .“轮廓:聚类分析的解释和验证的图形辅助”计算与应用数学杂志 20(1987):53–65。
[8]:卡利翁斯基、塔德乌什和耶日·哈拉巴斯。"一种用于聚类分析的枝晶方法."统计学通讯-理论与方法 3.1(1974):1–27。
[9]:戴维斯、戴维 l 和唐纳德 w 波尔丁。"一种聚类分离方法."IEEE 模式分析和机器智能汇刊 2(1979):224–227。
[10]:袁、春晖、。" K-means 聚类算法中 K 值选择方法的研究."j 2.2(2019):226–235。
[11]:阿卜迪、埃尔韦和林恩·威廉斯。“主成分分析。”威利跨学科评论:计算统计学 2.4(2010):433–459。
基于命名实体的新闻文章聚类
原文:https://towardsdatascience.com/clustering-news-articles-based-on-named-entities-306a23d368e1?source=collection_archive---------17-----------------------
我如何实时处理西班牙语新闻,并可视化提到的人、地点和组织的分布
丹尼·米勒在 Unsplash 上的照片
在这篇文章中,我想和你分享我关于自然语言处理的硕士论文。尽管我在几年前就完成了它,但直到现在我才认为用英语写出来会很棒(我的硕士论文是用西班牙语完成的),并希望通过展示如何构建一个涵盖数据科学项目中许多阶段的系统来帮助一些有抱负的数据科学家或机器学习工程师。
介绍
可能由于我的多元文化经历,我一直对语言感兴趣。因此,在我攻读硕士学位期间,当我为论文选择主题时,我毫不犹豫;我想开发和研究自然语言处理。其中一个项目是基于文档相似性对新闻文章进行实时分类。我听说了教授指导这篇论文的一些很棒的事情,所以我全力以赴这个项目。
这个项目的目的是从新闻文章中识别相关信息,可视化它们的命名实体(人、组织和位置)的分布,找到文章之间的相似性,并最终根据它们的主题对新闻进行分组…并且都是实时的!
我知道对于一些人来说,数据科学和工程的广泛工具可能是令人生畏的,特别是对于那些没有软件背景的人。虽然这不是我的案例,但我只有纯软件开发的经验,所以我很高兴地接受了我的教授的建议,选择了这个堆栈:
- Apache Kafka 用于在处理前对实时文章进行排队,以及在处理后对命名实体进行排队(在不同的主题中)。
- Apache Spark (PySpark 流)用于实时处理新闻。
- Spacy Python NLP 库,用于在文章中查找命名实体。
- Brat 快速标注工具用于标注文章,用于语言模型的评估和训练。
- Elasticsearch 用于存储从每篇文章中提取的命名实体。
- 用于可视化不同类型命名实体的分布。
作者图片
数据
第一步是获取一些新闻文章。由于数据提取超出了这个项目的范围,我决定从 https://webhose.io/free-datasets/spanish-news-articles/的[下载一个包含西班牙旧新闻的数据集](https://webhose.io/free-datasets/spanish-news-articles/)
考虑到我们需要评估一些语言模型的性能,我们需要构建一个可信的测试集来比较预测。还有什么比我们自己手动标注文字更值得信赖呢?是的,这是一个漫长而乏味的过程,但作为回报,我们得到了一个非常有价值的黄金标准,我们可以继续用它来测试语言模型。为此,我们可以从主数据集中随机选取一组文章,并使用诸如 Brat 之类的注释工具用正确的命名实体来标记这些文章。
作者图片
需要注意的是,我将使用一个 Python 脚本来模拟新闻的接收,该脚本将来自我的本地数据源的文章注入到一个 Kafka 主题中,遵循每分钟 12 篇文章的泊松分布,而不是处理互联网上出现的当前新闻。
韵律学
您可以使用许多不同的指标来评估分类模型的性能。这里要考虑的一个重要方面是数据集是否平衡,即实体的类型是否平均分布?就我而言,我发现文章中提到的人数明显多于地点和组织的数量。因此,我决定追求精确度、召回率和 F1 分数(简介此处)。
Precision 表示检索到的实体中相关实体的百分比,而 recall 给出模型检索到的相关实体的比例。
检查分类模型准确性的一种直观方法是构建混淆矩阵,这可以用 Scikit-learn 轻松完成。当你有两个以上不同类型的实体时,你的混淆矩阵会变得非常有趣,因为你可以清楚地看到你的模型混合了哪些类或者混淆了,如果你想改进你的模型,它会提示你应该在哪里工作。
预训练语言模型评估
建议使用预先训练好的模型,然后在必要时用您的数据重新训练,而不是从头开始训练语言模型。Spacy 已经为不同的语言和环境提供了各种各样的预训练模型。注意模型的大小也很重要,因为数据集越大,模型就越精确,但处理和重新训练的工作量也越大。
幸运的是,我找到了一个西班牙的 NER(命名实体识别)模型,它用我的 3 种类型的实体进行训练:人、地点和组织。
正如你可能已经猜到的,由于在训练中花费较少的资源,非英语模型通常不如英语模型准确。因此,我们想知道这个初始模型有多精确,我们想通过在我们自己的数据上检查它的性能来做到这一点。这就是我们的黄金标准发挥作用的地方。
以下是根据我们的黄金标准评估西班牙语 Spacy 语言模型的结果。正如我们所看到的,它已经相当好地识别了地点和人,但它未能检测到大多数组织。还必须提及的是,该模型检测到一些实际上不是实体的地点、人员和组织(矩阵的最后一行)。
作者图片
判决?尽管考虑到我们使用的是非英语语言模型,结果并不差,但我们可以明确地说,我们离完美还很远,尤其是在识别组织方面。
那么我们能做些什么呢?
模特培训
如果我们使用了值得信赖的测试集,很明显,为了改进我们的语言模型,我们应该重新训练它。为了这个任务,我们需要更多的文章。实现这一点的一种方法是使用一种叫做的基于规则的匹配的技术对数据进行综合注释。
基本上,我们将下载一个实体(人、组织和地点)的大列表,并自动在另一组文章中找到它们。这将产生像黄金标准一样的带注释的文章子集。然而,我们将使用这组带注释的文章来重新训练模型。
当重新训练基于神经网络的模型时,要考虑的一个方面是灾难性遗忘,通过这种方式,我们用新数据重新训练模型越多,它就越有可能忘记以前的知识。这个问题的标准解决方案是所谓的假排练,它包括混合一些以前的预测作为训练数据,以不忘记它已经学会的东西。关于这个话题的更多技术细节可以在这里找到。
在 Spacy 中训练语言模型时,您需要考虑某些属性:
- 训练规模:训练集越大,模型学习的就越多,但是考虑你的计算资源和时间是很重要的。
- 历元数:已经完成了多少遍数据。
- 辍学率:让模型更难记住数据。
- 审查率:新的合成数据和原始模型预测之间的权衡(待审查的知识)。
来源:https://spacy.io/usage/training
优化的语言模型评估
现在是时候检查我们的重新培训是否对模型的性能产生了影响。我们可以用测试原始模型的相同方法,对照黄金标准来测试它,并比较结果。
正如下面的图所指出的,对于“组织”和“人”类型的实体有所改进,而对位置的检测稍差。
作者图片
混淆矩阵显示仍然有大量的假阳性(矩阵的最后一行)和假阴性(最右列)。
作者图片
总的来说,我们可以说该模型略有改进,但资源的缺乏使得用更大的数据集训练该模型变得复杂。
一旦你有了一个像样的模型,目标应该是把它投入生产,以便实时处理真实的数据。
实时自然语言处理
如前所述,由于新闻存储库是本地托管的,我们需要将新闻文件注入 Kafka 主题。Apache Kafka 的工作方式是拥有主题,其中生产者注入可以被消费者收集的数据。通过这种方式,我们可以在系统的不同组件之间实现松耦合,这意味着如果其中一个组件出现故障,所有组件都会继续正常运行。
想象一个有一群计算机的场景(超出了这个项目的范围,因为这只是独立的),我们可以在下面找到三个不同的 Kafka 主题。新闻生产者组件可以是我们的 Python 脚本,它生成文章并将它们排列在原始新闻主题中。与此同时,主处理模块( NER )正在使用火花流来消费和处理这些原始物品,用我们之前训练过的空间模型来检测命名实体。
作者图片
一旦用我们的模型处理了文章并提取了命名实体,我们需要考虑如何处理这些信息。让我们不要忘记这个项目的主要目标是根据他们的命名实体来聚集新闻。即使我们在本地使用静态的新闻库,我们也需要想象在现实世界中总会有更多的新闻出现。因此,在处理了一定数量的新闻后,只对新闻进行聚类是没有意义的。取而代之的是,我们希望能够随时对已经处理过的新闻进行可视化和分组。
那么我们该如何应对呢?首先,我们需要一个地方来存储我们从正在处理的文章中提取的相关信息。
已处理数据的存储
Elasticsearch 官方上是一个搜索引擎,但它也是一个强大的 NoSQL 数据库,它是 NoSQL,因为你不必为你的数据指定模式。因此,在我们的例子中,我们只是以 JSON 格式抛出一些数据(我们的文章和它们的命名实体),而 Elasticsearch 会发挥神奇的作用。
如果您回忆一下架构图,在文章被 NER 处理之后,管道分成两个分支。这种设计背后的理由基于两个原因:
- 我们需要能够通过命名实体查询文章,还需要获得实体的全球分布。
- Elasticsearch (v6.5.1)不支持嵌套对象上的聚合。技术细节此处。
因此,我们需要应用命名实体的反规范化,这导致 Elasticsearch 中的两个单独的索引:新闻索引存储每篇文章以及它们检测到的命名实体和时间戳,而实体索引存储所有命名实体,而不管它们属于哪篇文章。
现在,我们已经存储了一些相关信息,如果能够可视化所有这些信息以发现什么是趋势话题,岂不是很好?
(英)可视化(= visualization)
Elasticsearch 的一个关键优势是它与 Kibana 完全集成,后者是一个可视化工具,可以表示在任何给定时间在 Elasticsearch 中索引的数据,更重要的是,使用它您可以轻松创建实时仪表板来分析您的数据分布。
下面是一个例子,展示了在使用 Kibana 时,你可以对仪表盘做些什么。
作者图片
如果您还记得我们存储在新闻索引中的 JSON 字段,其中一个字段是时间戳。当你想知道“为什么我们需要一个时间戳”时,想想你想要分析多少新闻,或者更好地说,你想要回溯多远?你想看过去 5 分钟或前一天的热门话题吗?这时我们需要考虑一篇文章的年龄。在 Kibana 中,您可以通过时间窗口轻松过滤数据(JSON 文档)。
话虽如此,仪表板的结论可能会非常不同,这取决于您想要检查信息的时间,尽管有大量实体涉及政治家和政党。
所以下一个问题是,有了这些信息,我们如何找到一些模式来帮助我们将新闻分成不同的类别?
使聚集
一种可视化不同类别的方法是用一个图表,其中每个点代表一篇文章,点与点之间的距离,新闻有多相似。简单地说,我们可以使用每篇文章中的命名实体来计算它们的主题有多相似,从而计算每个点之间的距离。一旦我们有了用图表表示的文章,我们就可以很容易地想象文章的不同类别或社区。
这里的想法是按需生成这个图表,指定在 Elasticsearch 中索引的新闻的时间范围,例如,我们可以生成一个图表,表示上一小时处理的新闻。
要回答的一个关键问题是,我们如何根据它们的命名实体来衡量两篇文章有多相似(或不同)?人们可以想到一个简单的实现,要么是 Jaccard 指数 T1,要么是 T2 余弦相似度 T3(这里是比较 T4 T5)。然而,像“美国”和“美国”这样语义相关的实体呢?在我们的图表中,谈论这两个不同实体的新闻会不会离得很近呢?好消息……这个问题可以通过 单词嵌入 轻松解决,其中每个单词都用一个实值向量来表示其含义,因此相似的单词将有相似的向量或嵌入。
好的,那么我们如何使用单词嵌入来绘制正在 Elasticsearch 中处理、丰富和存储的新闻呢?第一步是获取这些新闻和实体,你可以用 Python 中的 elasticsearch-py 库来完成。现在我们可以将 Spacy 用于比较单词嵌入的能力(文档这里是)与 Scikit-learn 提供的多维标度结合起来。这将把 Spacy(或者更准确地说是 word2vec)给出的多维表示转换成可以用来绘制我们的图形的 2D 表示。
好了,一旦我们有了新闻的 2D 表示,最后一步就是找出有多少个集群或社区以及属于每个集群或社区的新闻。实现这一点的一种方法是通过卢万算法进行社区检测。即使数学细节可能相当复杂(见这里的),如果我们只是使用 python-louvain 库,我们真的不需要从头实现它。
根据用于绘制图表的 Python 库,结果可能如下所示,其中每个点代表一条新闻,颜色表示不同的主题。本例中的图例显示了每个主题中最常见的实体。据此,人们可以说,新闻已经分为西班牙和拉丁美洲、美国政治和西班牙政治。
作者图片
结论
正如您在本文中看到的,有如此多的开源工具可以用于几乎任何您能想到的 NLP 任务。还要记住,JSON 可能是在应用程序之间共享数据的最佳格式,因为它在开源社区得到了广泛的支持。最后,自从我完成这个项目以来,已经有很多关于数据可视化工具的工作,所以我建议你在选择满足你特定需求的工具之前去比较它们。
我只有有限的时间和资源来完成这个项目。几个肯定会带来巨大价值的扩展是:
- 抓取即时 RSS 提要,而不是处理新闻的静态存储库(一些相关的工作这里)。
- 使用云计算通过更大的带注释的数据集来重新训练模型。你可以和 Docker 竞争。这里有一篇关于整合所有这些工具的有趣文章。
如果你对源代码感兴趣,可以查看我的 GitHub repo (注意西班牙文写作)。
感谢您的阅读,并随时留下评论!
基于数字和类别特征的聚类。
原文:https://towardsdatascience.com/clustering-on-numerical-and-categorical-features-6e0ebcf1cbad?source=collection_archive---------0-----------------------
实践教程
在 Python 中使用高尔距离。
由蒙罗工作室在 Unsplash 拍摄的照片
介绍
去年,我一直在从事与客户体验(CX)相关的项目。在这些项目中,对客户数据进行机器学习(ML)和数据分析技术,以提高公司对客户的了解。最近,我集中精力寻找具有某些共同特征的不同客户群体,以便能够对他们采取特定的行动。
您可能已经猜到了,这个项目是通过执行**集群实现的。**对于那些不熟悉这一概念的人来说,聚类是根据一组对象或观察结果(例如,客户)的特征或属性(例如,性别、年龄、购买趋势)将它们分成不同的组(称为聚类)的任务。这种划分应该以这样的方式进行,即在同一个集群中的观测值应该尽可能地相似。此外,每个集群应该尽可能远离其他集群。[1]
一个主要的挑战是找到一种方法对既有分类变量又有数值变量的数据执行聚类算法。在现实世界中(尤其是在 CX),许多信息都存储在分类变量中。尽管 web 上有大量关于数字变量聚类的信息,但是很难找到关于混合数据类型的信息。
这是一项复杂的任务,对于将这种数据类型的混合与聚类算法结合使用是否合适存在很多争议。然而,我决定放手一搏,尽我所能。在这篇博客的剩余部分,我将分享我的个人经历和我所学到的东西。
在接下来的章节中,我们将会看到高尔距离是什么,使用哪种聚类算法比较方便,以及它在 Python 中的使用示例。
免责声明:我认为自己是一个数据科学新手,所以这篇帖子并不是要创造一个每个人都应该使用的单一而神奇的指南,而是分享我所获得的知识。我现在的主要兴趣是不断学习,所以我乐于接受批评和指正。欢迎在评论区分享你的想法!
高尔距离
既然我们理解了集群的含义,我想强调一下上面提到的下面这句话。
划分的方式应该是观测值 尽可能的相似 在同一个集群。
如何定义不同客户之间的相似度?在只有数字特征的情况下,解决方案看起来很直观,因为我们都知道 55 岁的客户更像 45 岁的人,而不是 25 岁的人。有许多方法可以测量这些距离,尽管这些信息超出了本文的范围。
但是,如果我们不仅知道他们的年龄,还知道他们的婚姻状况(例如,单身、已婚、离婚……)呢?这种分类特征可以通过使用诸如插补、标签编码、一键编码等技术转换成数字特征……然而,这些转换可能导致聚类算法误解这些特征并产生无意义的聚类。例如,如果我们在婚姻状况特征上使用标签编码技术,我们将获得以下编码特征:
应用于婚姻状况特征的标签编码技术
这种转换的问题是,聚类算法可能会认为一个单身值更类似于已婚 ( 已婚[2】–单身 [1]=1),而不是离异 ( 离异[3】–单身 [1]=2)。如图所示,转换特征可能不是最佳方法。
这就是高尔距离(衡量相似性或不相似性)发挥作用的地方。高尔相似性(GS) 最早是由 J. C .高尔在 1971 年定义的[2]。为了计算观察结果 i 和 j (例如,两个客户)之间的相似性,将 GS 计算为观察结果的 m 特征之间的部分相似性的平均值( ps )。
观察值 I 和 j 之间的相似性。每个观察值都有 m 个不同的特征,或者是数字的,或者是分类的,或者是混合的。
部分相似性的计算取决于被比较的特征的类型。
- 对于一个数字特征、**、**来说,两个个体 i 和 j 之间的部分相似性是一减去他们在特定特征中的值(绝对值)之间的差除以该特征的总范围。
当 f 是数值时,特征 f 中观察值 I 和 j 之间的相似性。
特征 f 的范围
- 对于一个分类特征,两个个体之间的部分相似性只有在两个观察值完全相同时才为 1。否则为零。
部分相似度的范围总是从 0 到 1。因此,当我们计算部分相似性的平均值来计算 GS 时,我们总是得到一个从 0 到 1 不等的结果。零表示观测值尽可能不同,一表示完全相等。
由于这些发现,当存在分类变量和数字变量的混合时,我们可以测量两个观察值之间的相似程度。然而,在进入细节之前,我们必须小心谨慎,并考虑到某些方面,这些方面可能会影响该距离与聚类算法的结合使用。
高尔距离的数学性质
关于交叉验证,我强烈推荐阅读两个问题:
- 高尔的相异指数
- 混合类型数据的层次聚类——使用什么距离/相似度?
两者都将高尔相似度 (GS) 定义为非欧几里得和非公制的。高尔相异度 (GD = 1 — GS)与 GS 有相同的局限性,所以它也是非欧非度。然而,定义为√GD 的高尔相异度实际上是一个欧几里德距离(因此是自动度量的),当没有使用特殊处理的序数变量时(如果你对此感兴趣,你应该看看 Podani 如何将高尔扩展到序数字符
这很重要,因为如果我们使用 GS 或 GD,我们使用的距离不符合欧几里德几何。因此,不得使用基于欧几里德距离的方法,因为一些聚类方法:
- k 均值
- 层次聚类的沃德法、形心法、中位数法
- …
编程语言中的高尔距离
R 或 Python 中的相关工作
现在,我们可以在 R 或 Python 中使用这个度量来执行聚类吗?关于 R,我发现了一系列非常有用的帖子,通过一个叫做 雏菊 : 的函数,教你如何使用这个距离度量
- 混合类型数据的聚类:一种使用 R 的建议方法。
- 使用高尔距离聚类分类和数值数据类型。
- R中分类数据的层次聚类(仅具有分类特征)。
但是,我还没有找到用 Python 实现它的具体指南。这就是为什么我决定写这个博客,并试图给社区带来一些新的东西。原谅我,如果目前有一个具体的博客,我错过了。
Python 中的高尔距离
首先,很重要的一点是,目前我们还不能在 scikit-learn 提供的聚类算法中包含这个距离度量。这是自 2015 年以来 scikit-learn 的 GitHub 上的一个开放问题。然而,自 2017 年以来,由 Marcelo Beckmann 领导的一组社区成员一直致力于高尔距离的实施。希望它能很快在图书馆内使用。
在这个过程中,另一位名叫 Michael Yan 的开发人员显然使用了 Marcelo Beckmann 的代码创建了一个名为gower的非 scikit-learn 包,该包已经可以使用,而无需等待 scikit-learn 社区昂贵且必要的验证过程。注意,这个实现使用了高尔相异度(GD)。
动手实施
数据
当我学习新的算法或方法时,我真的喜欢在非常小的数据集中看到结果,这样我就可以专注于细节。因此,对于实现,我们将使用一个小的合成数据集,其中包含关于杂货店客户的虚构信息。
创建熊猫数据帧的 Python 代码
创建的数据有 10 个客户和 6 个特征:
- 年龄:数字
- 性别:分类
- 公民身份:绝对身份
- 薪资:数字
- 客户有孩子吗?:二进制
- 购买者类型:分类
所有信息如下所示:
客户综合数据
高尔距离
现在,是时候使用之前提到的 高尔包 来计算不同客户之间的所有距离了。让我们手动做第一个,并且记住这个包正在计算高尔相异度(DS) 。所以计算的方式有点变化。
- 对于一个数字特征,两个客户 i 和 j 之间的部分相异度是它们在特定特征中的值(绝对值)的差除以该特征的总范围。工资的范围是 52000(70000–18000),而年龄的范围是 68(90–22)。注意在这些特性中没有异常值的重要性。一个非常大或非常小的错误值将直接影响范围,因此该特征的差异将变得不那么重要。
- 对于一个分类特征,当两个客户对此特征具有不同的值时,两个客户之间的部分不相似性为 1。否则为零。
按照这个过程,我们计算前两个客户的所有部分差异。
计算前两个客户的部分差异
两个客户之间的高尔相异度是沿着不同特征的部分相异度的平均值:(0.044118+0+0+0.096154+0+0)/6 = 0.023379。由于值接近于零,我们可以说这两个客户非常相似。
让我们使用 高尔包 来计算客户之间的所有差异。然后,将结果存储在一个矩阵中:
距离矩阵
我们可以这样解释这个矩阵。在第一列中,我们看到了第一个客户与所有其他客户的不同之处。由于 GD 较低,该客户与第二、第三和第六位客户相似。
对距离矩阵执行聚类
我们刚刚看到的矩阵可以用于几乎任何 scikit-learn 聚类算法。然而,我们必须记住高尔距离的局限性,因为它既不是欧几里得距离,也不是公制距离。
要在 scikit-learn 聚类算法中使用 Gower,我们必须在所选方法的文档中查找直接传递距离矩阵的选项。虽然参数的名称可以根据算法的不同而改变,但我们几乎总是应该将值预先计算好*,所以我建议去算法的文档中查找这个单词。*
在本文中,我们将使用 DBSCAN (带噪声应用的基于密度的空间聚类)算法。理解算法超出了本文的范围,因此我们不会深入讨论细节。我在这里留下了算法背后理论的链接,以及一个直观解释其基本功能的 gif。
这里我们有代码,在这里我们定义了集群算法,并对其进行配置,以使要使用的指标为“预计算”。拟合算法时,我们将引入已计算的距离矩阵,而不是将数据集与数据一起引入。此外,我们将集群的结果添加到原始数据中,以便能够解释结果。
最终结果如下:
如果我们分析不同的集群,我们会发现:
- ***集群 0(绿色):*工资在 18,000 至 27,000 英镑之间,没有孩子并且很少购买的客户。
- ***第 1 组(蓝色):*收入约 3.3 万英镑、经常购物的 40 多岁母亲。
- ***第 2 组(红色):*60 多岁的男性,中等购买量,无子女
- Cluster -1: 这不是集群本身,而是被算法识别为异常值的客户。它无法在任何集群中识别。
通过这些结果,我们可以了解客户所划分的不同群体。因此,我们可以对它们执行特定的动作,例如个性化的广告活动、针对特定群体的要约……的确,这个示例非常小,并且被设置为具有成功的集群,实际的项目要复杂得多并且花费时间来实现显著的结果。
结论
本文提出了一种在 Python 中使用 Gower 距离执行聚类的方法。它还暴露了距离度量本身的局限性,因此可以正确使用。最后,这个小例子证实了以这种方式开发的集群是有意义的,并且可以为我们提供大量信息。
我希望你能发现这种方法很有用,并且你会发现这篇文章很容易阅读。最重要的是,我很高兴收到任何形式的反馈。所以,请随意分享你的想法!
参考
[1]维基百科投稿人,聚类分析(2021),https://en.wikipedia.org/wiki/Cluster_analysis
[2] J. C. Gower,广义相似系数及其若干性质 (1971),生物统计学
集群:走出黑盒子
原文:https://towardsdatascience.com/clustering-out-of-the-black-box-5e8285220717?source=collection_archive---------6-----------------------
k-均值和高斯混合模型
米克·豪普特在 Unsplash 上的照片
作者:詹娜·琼斯和尼克·潘恩
介绍
最近,无监督学习受到了很多关注,因为它能够在没有任何训练的情况下发现数据中的模式。具体来说,聚类已被用于解决许多数据问题,包括客户细分、欺诈检测、推荐引擎以及最重要的足球运动员位置。本文讨论并比较了两种不同的数据点分组方法: K 均值和高斯混合模型(GMM) 。然后,我们使用这些方法中的每一种对相同的示例数据集进行聚类。
术语
与机器学习系统一样,需要一些特定的术语:
- 特征:可用于分析的可测量数据(如果我们有一个足球运动员的数据集,我们可以将身高作为一个特征,体重作为一个特征,大学作为一个特征)。
- 维数:数据集中特征的数量。在我们的例子中,将有两个维度:每个玩家的身高和体重。很容易想象二维空间(通常在数学课上看到),也有可能想象三维空间,但之后,更高维空间就不容易想象了。尽管如此,一个数据集中可以有无限数量的维度。
- 质心:计算出的一簇数据点的中心位置。对于 K-Means,这是每个维度的每个聚类中数据点的算术平均值。
- 聚类:由相似特征组合在一起的一组数据点。
- 距离度量:计算任意数据点距离每个聚类质心有多远的方法。
- 误差平方和:一旦数据被划分到给定数量的聚类中,该度量取每个数据点与其聚类中心之间的距离平方和,将分析中的所有数据点相加。它用于帮助评估数据中有多少个聚类。
例子
数据:我们使用了一组二维数据,显示了 NFL 橄榄球运动员的身高和体重,分为 AFC 和 NFC 南部赛区的跑卫、紧逼端和防守铲球。有 94 个数据点。
以二维形式显示数据的数据集摘录
该示例的目标是根据身高和体重将每个玩家正确分配到 K 个集群(位置)中的一个。请记住,该算法既没有看到标记数据,也没有经过任何训练——决策将完全基于二维数据做出。
下面是原始数据的图表,每个点代表一个玩家。你能想象出的最佳集群数量吗?
原始数据散点图
这对于计算机来说是一个相当棘手的问题,因为存在重叠的数据点和一些异常值。
视觉检查显示有两个不同的组:一个位于较高的重量范围,另一个跨越较低的重量范围,包括不同的高度。仅仅通过观察很难判断在第二组中是只有一个还是有许多集群。
我们想评估如何成功的 K-Means 和 GMM 可以分组的数据。在开始之前,让我们看一下实际的集群。
实际的集群
k 均值聚类
K-Means 由于其简单性很容易成为最流行的聚类算法。最终,它假设数据点彼此越接近,它们就越相似。流程如下:
- 选择集群的数量 K
- 随机建立每个质心的初始位置
- 使用距离测量将每个数据点分配到最近的质心
- 使用分配给每个聚类的数据点的平均值重置每个质心位置
- 返回步骤 3 并重复,直到没有单个数据点改变聚类
如何找到最优的聚类数, K ?
聚类中最困难的步骤之一是确定最佳聚类数, K,对数据进行分组,没有“正确”的答案。最常见的方法被称为“肘法”。本质上,它对整个数据集运行 K 均值聚类,得到不同的 K 值和,并计算每个和的误差平方和(SSE)
绘制结果是很重要的。该图类似于一只手臂,顾名思义,陡度变化最大(即肘部)的 K 的值被认为是最佳的聚类数。目标不是找到最小化总平方距离的 K ,而是找到当 K 增加时导致收益递减的 K 。
在我们的示例中,elbow 方法返回值 3 作为最佳聚类数(根据实际数据,我们知道这是正确的)。
什么是距离度量?
K-Means 算法使用欧几里德距离度量。这意味着每个聚类中心周围的距离度量是“圆形”的。不同地说,每个维度的重要性是相等的,因此有了术语‘圆形’。该距离可以定义为
其中 J 代表维数。
在我们的示例中,我们将该公式应用于两个维度:
如果我们计算 Derrick Henry (DH)的身高和体重与 RB 和 te 形心的身高和体重之间的距离,我们会发现到 TE 形心的距离要短得多,因此,他被归类为 TE。
如何重置每个质心位置?
将每个数据点分配到一个集群后,我们只需计算每个集群中每个维度的数据点的算术平均值(即每个位置的所有球员身高的平均值和所有球员体重的平均值)。这就是每个质心的新位置。均值的使用是该算法得名的原因:K-Means。
该算法直接在 sklearn.cluster.KMeans 包中实现。但是,我们将通过一个小示例来展示步骤 1(确定最佳集群数量)之后会发生什么。
首先,在步骤 2 中,每个质心被随机初始化。在第二幅图像的步骤 3 中,使用距离测量将数据点指定给最近的质心。
接下来,基于平均值重置每个质心位置。在第二幅图像中,数据点被重新分配给现在距离数据点最近的质心。
重复上述过程
该过程结束,因为没有数据点用新的质心位置改变聚类
我们用 Python 在数据集上运行了该算法,结果令人鼓舞。
K-Means 成功地将数据聚类成三组;然而,它错误地将三家 RBs 指定为 te。
结果:聚类对应于实际数据聚类,只有三个玩家被错误分类。因为我们已经知道每个玩家的位置,所以我们能够容易地评估集群。所有的 dt 都成功地聚集成一组,但这并不奇怪,因为我们可以用肉眼看到。令人印象深刻的是,尽管看起来是一组连续的数据,但大多数 RBs 和 TEs 都被正确地聚类。
特征标准化
当要素具有不同的比例(例如房价- 400,000 和平方英尺- 1,500)时,通过对数据进行标准化来预处理数据可能很重要,这样一个元素对距离的贡献与另一个元素相比不会过大,从而主导整个距离测量。为了更平均地分配要素之间的贡献,我们可以对数据进行标准化,以便整个数据集的每个维度的平均值分布是相同的。在我们的例子中,我们选择不标准化数据,因为我们相信运动员的体重自然比他们的身高更重要。然而,为了说明标准化的效果,我们展示了使用和不使用特征标准化的示例数据的分析结果。
从 K-均值和实际数据分组中交叉列表指定的聚类。集群 0 和 1 完全对应于 DT 和 RB 位置。群组 2 主要包括 te,并且错误地包括 3 个 Rb。
如上图所示的分配聚类的交叉列表,具有特征标准化
有了标准化的数据,错误分类的 RBs 就少了。然而,更多的运动员被错误分类,因为标准化挤压了体重范围,把两个 300 磅左右的运动员归入了运动员组。
特征标准化的 k-均值算法
正如我们所见,特征标准化的效果将取决于数据以及特征的结构和尺寸的构成。
K-Means 的优势:
- 简单易懂
- 非常快(所有正在计算的是每个点和聚类中心之间的距离)
- 易于实施
K-Means 的缺点:
- 必须手动选择 K
- 取决于初始质心位置
- 由于异常值,可能会歪曲质心位置
高斯混合模型
高斯混合模型是一种期望值最大化(EM)算法,其数据点假定具有高斯(正态)分布。它通常被描述为 K-Means 的一个更复杂的版本。它需要两个参数,均值和协方差,来描述每个聚类的位置和形状。
该模型基于多元高斯分布,即:
其中对于每个集群,
GMM 要求一个五步流程:
- 选择集群的数量, K
- 随机建立每个质心的初始参数(即平均值、协方差和权重)
- 使用当前参数计算数据集来自这组分类的可能性
- 通过更改参数(聚类比例、中心和围绕中心的分布)最大化可能性
- 返回到步骤 3 并重复,直到参数的变化小于预编程的量或者已经完成了固定次数的迭代
什么是期望值最大化算法?
EM 首先计算给定数据点来自高斯分布与当前参数集的混合的可能性。然后,它通过改变参数来最大化可能性。
可能性有多大,如何最大化?
似然函数基于数据点来自高斯聚类的加权集合的概率:
在哪里
当然,权重总和为 1。
然后,似然性是来自具有这些参数的聚类集的 N 个数据点的整个数据集的概率。
与许多似然最大化问题一样,取对数并最大化对数似然函数(它给出相同的最大值或最小值)更容易,因为当取对数时,似然函数中的乘积变成和。通过对每个参数(聚类加权、聚类均值和聚类协方差)进行微分,可以相当容易地获得用于更新每个参数的公式。确切的过程超出了本文的范围,但是下面给出了结果公式。
期望:在没有将数据点分配给单个聚类的情况下,我们计算每个聚类的参数产生每个数据点的概率。这意味着为每次迭代重新计算如上给出的新值 P(x) 。
最大化:我们需要使用以下公式分别更新每个聚类的权重、均值和协方差:
什么是距离度量?
GMM 不使用距离度量,而是应用围绕聚类中心的概率分布来计算数据点属于给定聚类的可能性。顾名思义,这是一个多元正态分布,变量的个数等于数据中的维数。
由于 GMM 正在寻找每个聚类的最佳参数,我们最终可能希望将每个数据点分配给一个聚类。这是通过选择离每个数据点“最近”的质心来实现的。为此,Python 的 Sklearn 包使用了一种称为 Mahalenobis 距离的距离度量,而不是 K-Means 中使用的欧几里德距离。这一措施被定义为:
很明显,该公式允许围绕质心的椭球形轮廓而不是圆形轮廓,并且其形式与多元高斯分布公式中使用的形式相同。
在我们的数据集上运行该算法给出了比 K-Means 稍好的结果。
GMM 成功地将数据分为三组;然而,它错误地分配了一个 RB 和一个 TE。
结果:所有的 DTs 再次成功聚类成一组,而 Derrick Henry 再次被误归类为紧端,紧端被误归类为跑锋。
来自 GMM 的指定分类和实际数据分组的交叉列表。集群 0 完全对应于 DT 位置。集群 1 和集群 2 大体上是正确的,但是不正确地包括 1 个玩家
GMM 的优势:
- 可以分析更复杂和混合的数据
- 可以更容易地处理异常值
GMM 的劣势:
- 更难直接解释结果
- 不直接将数据点分配给聚类
两种方法的比较与讨论
1:相似性
质心起点的选择
选择每个质心的起点非常重要,因为它对结果有很大的影响。
已经提出了各种方法来初始化聚类中心。常见的方法有:
- Forgy(随机选择 K 个数据点,并将其用作初始质心位置)
- 随机分区(为每个数据点随机分配一个聚类,然后基于该聚类计算质心——这通常会创建接近数据集中间的初始质心)
- K-Means++(选择彼此尽可能远离的初始质心,有效地围绕数据集的边缘)。
对于 GMM,通常将每个聚类的初始分布(方差)设置为总体方差,并相等地设置权重。
两个 Sklearn 软件包都提供了使用不同的起点运行多次分析的选项,并提供了最适合所有运行的结果。用户可以设置运行分析的不同尝试次数。
倾向于局部最小值而不是全局最小值
因为质心的初始化本质上是一种猜测,所以它们可以从远离数据中真正的聚类中心的地方开始。这两种方法总是趋于一致(意味着它们总会找到解决方案),但不一定是最佳方案。在途中,它们可能会陷入局部最小值并卡在那里。
具有两个局部最小值和一个全局最小值的函数的例子
当没有达到全局最小值时,结果将不是最佳的,并且将获得不同的聚类组。
结果显示该算法在左边达到全局最小值,在右边达到局部最小值。两者都是解决方案,但全局最小值是更好的数据聚类
2:差异
确定性与概率性方法
- K-Means:使用确定性方法并将每个数据点分配给一个唯一的聚类(例如:Derrick Henry = TE)。这被称为硬聚类方法。
- GMM:使用一种概率方法,给出每个数据点属于任何一个聚类的概率(例如:Derrick Henry = [0.63 TE,0.33 RB,. 04 DT]。这被称为软聚类方法。
参数
- K-Means:仅使用两个参数:聚类数 K 和质心位置
- GMM:使用三个参数:**:**聚类数 K ,均值和聚类协方差
更新质心
- K-Means:仅使用分配给每个特定聚类的数据点来更新质心平均值
- GMM:使用数据集中的所有数据点来更新质心权重、均值和协方差
特征标准化
- K-Means:如果一个或多个维度将主导计算,则质心周围的“圆形”距离测量可以使特征标准化成为必要
- GMM:通过计算和使用协方差矩阵,自动将问题考虑在内
计算机编程语言
Python 通过它的 Sklearn 包实现了这两种集群技术。这些软件包非常容易使用,并且保留了大量的数据信息。它们还允许许多用户选择,这些选择由您添加到语句中的超参数定义。
Python 代码的超参数
- 聚类数(n_clusters):将数据分组到的聚类数以及质心数
- 最大迭代次数(max_iter):算法有两种完成方式:一种是当数据点停止改变聚类时(如上图所示),另一种是为算法设置固定的循环次数(这将比收敛更快地结束算法)
- Number initial (n_init):整个算法运行的次数,质心的起始位置不同。由于算法对起点和很敏感,该软件包允许您选择多个不同的起点,以寻求最佳解决方案。
- Random State (random_state):初始化质心时为每次运行设置相同的位置
一旦有了一个只包含要素数据的数据框(在下面的代码中称为“数据”),就可以用很少的代码轻松运行 K-Means 和 GMM 聚类。
结论
我们已经使用 K-Means 和 GMM 对使用标准 Python 包的数据集进行了聚类。我们希望这篇文章能帮助你通过理解这些算法的工作原理来更好地分析你的数据。
您可能需要尝试多种不同的方法来获得最佳结果:使用不同的超参数、调整聚类的数量、应用不同的距离度量,并可能标准化您的数据。
在大多数实际情况下,聚类并不简单或明显,因此对这些工具、它们的使用方式以及数据科学家可用的选项的更深入了解将会带来更好的结果。
所有非参考图片均由作者创作。
参考
[1] Mahalanobis,P.C. (1936) 论统计学中的广义距离。印度国家科学研究所会议录,2,49–55。
**[2]希尔皮希,Y. (2019) 面向金融的 Python。奥莱利媒体公司
用 Python 对产品名称进行聚类—第 1 部分
原文:https://towardsdatascience.com/clustering-product-names-with-python-part-1-f9418f8705c8?source=collection_archive---------1-----------------------
使用自然语言处理(NLP)和 K-Means 聚类 Python 中的未标记文本
Billy Huynh 在 Unsplash 上拍摄的照片
介绍
自然语言处理(NLP)是指对人类语言(如文本和语音)的自动计算处理。
它对于分析大量未标记的文本以快速提取含义特别有用,而这正是对电子商务产品进行分类时的问题所在。产品要么被贴上不正确的类别标签,要么根本没有标签。手动分类效率不高,如果不是不可能的话。
今天我们将讨论我们如何使用 Python 中的 NLP 和 K-means 来自动聚类未标记的产品名称,以快速了解数据集中的产品种类。这种方法是无监督的(没有设置类别和类别数量),并且不同于有监督的分类,分类将产品名称分配给目标标签(已知类别)。
在本指南中,我将使用来自澳大利亚食物成分数据库的数据集,其中包含澳大利亚食物营养成分的数据。我将向您展示我是如何将 1,534 个具有许多独特性的食物名称聚集在一起的…
未标注的食物名称|作者图片
…获得数据集中所有食品类型的高效、高级视图,只需很少的人工输入。
相似食物聚类示例|作者图片
所有带标签的分类|按作者分类的图像
该方法包括以下步骤:
- 预处理****文本(食物名称)为干净的单词,这样我们就可以把它变成数字数据。
- ****矢量化是将单词转化为数字特征的过程,为机器学习做准备。
- 应用 K-means 聚类,一种无监督的机器学习算法,将具有相似单词的食物名称分组在一起。
- 通过聚类标记和可视化评估 聚类质量。
- ****微调步骤 1–4 以提高集群质量。
本文是第 1 部分,将涵盖:预处理和矢量化。
请务必查看 第 2 部分 ,其中将涵盖:K-means 聚类、评估聚类质量和微调。
完全披露:这个数据集实际上带有一个列“分类名称”,有 268 个类别,但为了演示的目的,让我们假装它不存在;)
装置
本指南将使用熊猫**、 NumPy 、 scikit-learn 、 FuzzyWuzzy 、 Matplotlib 和 Plotly 。可选的是用于预处理该特定数据集的库。我用了 Gensim 、 String 、 NLTK 和 Webcolors 。如果您还没有安装所有的东西,最简单的方法是通过 pip 安装。**
pip install fuzzywuzzy
pip install plotly
pip install gensim
pip install webcolors
让我们导入库,加载数据集,并将食物名称放入熊猫系列中。
预处理
这个游戏的目的是删除不必要的单词和字符,以便我们的食物名称中的单词对以后的聚类有意义。
有许多预处理技术,选择使用哪一种取决于它们对集群的影响。以下是我使用的技巧和原因。
删除停用字词、标点和数字
停用词是语言中的常用词,如“the”、“a”、“is”、“and”。例如,因为所有的食物名称都包含单词“and”而产生一个聚类,这与食物无关,是没有用的。
我们将使用 Gensim 库删除停用词,使用字符串库删除标点和数字。
词干化和使单词小写
词干包括把它们缩短成它们的词根形式。例如,“apple”和“apple”都变成了“appl ”,在矢量化阶段被视为同一个单词。
注意:基于上下文,词条满足会将两个单词都简化为真正的单词“apple”。它的计算量更大,并且不是这个练习所必需的,因为我可以很容易地判断词干所指的是什么。
使用 NLTK 库也将使所有单词小写。这是有用的,以便在矢量化阶段将“appl”和“Appl”视为同一个单词。
去除颜色
在我们的食物名称中加入颜色可能会产生颜色相同但在其他方面不相关的食物群。我们将使用 Webcolors 字典删除颜色,但不删除也是食物的颜色(例如:“巧克力”和“酸橙”)。
这是我们食物名称的前后对比。我们最终在文本中找到了 851 个不同的单词。
作者图片
在矢量化阶段使用的一些 Python 库内置了这些技术。然而,如果测试多个矢量化模型,最好从一致、干净的文本开始,以便能够比较输出。
矢量化
我们现在希望将清理后的文本转换成数字数据,以便对其进行统计分析。
就像预处理一样,有很多技术可以选择。这些是我测试过的模型。
一袋单词
单词包(使用 sci-kit learn 的 CountVectorizer)是一个基本模型,用于统计文档中单词的出现次数。在这里,每一行——一个食物名称——都是一个文档。结果是一个矩阵,其中包含文本中每个不同单词的特征,以及一行(或向量)中每个单词的计数作为其数值。
原始食物名称的单词表|图片由作者提供
这又是一个矩阵,只显示了第一行中的单词。注意每一行的计数。
作者图片
像这样的基本单词计数可能不足以提取意思。在这种情况下,食物名称中的一些词更能说明它是什么类型的食物。例如,在“西兰花,新鲜的,生的”中,单词“西兰花”比“新鲜的”或“生的”对我们的聚类更重要,但是单词包给了这三者同等的权重。
TF-IDF(单词级)
TF-IDF(使用 sci-kit learn 的 TfidfVectorizer)测量一个单词在文档中的频率,并将其与文本中所有单词的频率进行比较,以给它分配一个加权的重要性分数。
让我们在单词级别上看看它的作用,在这个级别上,单词被认为是彼此独立的意思。
作者图片
现在向量的每个单词都有不同的值。在第一行中,“豆蔻”得分最高,这太棒了!
TF-IDF (n 克级)
我们可以在 n-gram 级别使用 TF-IDF,其中也考虑了单词序列的频率。
作者图片
在这里,我使用 ngram_range 参数告诉模型考虑 1(单个单词)和 2(两个单词的序列或二元语法)之间的 n 元语法。第一行具有相对于“小豆蔻种子”、“干燥的种子”和“干燥的地面”的值,“小豆蔻种子”的得分最高。厉害!
我测试了将 ngram_range 的上限增加到 3、4 和 5,但是 2 在稍后的聚类中最适合这个数据集。文档(我们的食物名称)相对较短,并且没有太多超过两个单词的有意义的 n-grams。
潜在狄利克雷分配
LDA 识别词频模式,以概率估计文档的主题和在这些主题中使用的词。它假设每个文档由几个主题组成,相似的主题使用相似的词。就像在单词包中一样,每个单词在模型中都被认为是相互独立的。
LDA 对于大型文档(如新闻文章)在揭示其高级主题方面非常有用。然而,这个数据集并不完全正确,因为每个食物名称并不一定由多个主题组成。
我测试了最佳学习速度和告诉模型要查找的主题数量。这是 30 个话题的结果和每个话题的前 5 个单词。
作者图片
它已经完成了它该做的。我们有共同使用的词汇模式来描述我们的食物,但它们不能说明我们数据集中的食物类型。
模糊的
最后,Fuzzywuzzy 计算两个字符串之间的相似性得分,非常适合模糊(而不是精确)匹配。这是一些打破常规的想法。我的逻辑是,如果相同食物类型的食物名称措辞稍有不同(例如:不同种类的苹果),它们会产生很高的相似性分数。
在这里,我创建了一个每个食物名称及其与每个其他食物名称的相似性得分的矩阵。我最终得到了 1,534 行(每个食物名称一行)和 1,500 列(预处理后每个不同的食物名称一列)。
作者图片
无可否认,这是最慢的矢量化方法,因为它对 1,534 x 1,500 只熊猫的数据帧进行内存计算。聚类后,它的表现类似于单词袋。
继续阅读第 2 部分,找出聚类的结果。
本文是第 1 部分,内容包括:预处理和矢量化。
请继续阅读 第二部分 ,其中将涵盖:K-means 聚类、评估聚类质量和微调。
本指南中使用的数据集来自 澳大利亚食品成分数据库 ,并经澳大利亚新西兰食品标准局许可。
用 Python 对产品名称进行聚类—第 2 部分
原文:https://towardsdatascience.com/clustering-product-names-with-python-part-2-648cc54ca2ac?source=collection_archive---------4-----------------------
使用自然语言处理(NLP)和 K-Means 聚类 Python 中的未标记文本
李可莹在 Unsplash 上拍照
介绍
本指南介绍了我们如何使用自然语言处理(NLP)和 Python 中的 K-means 来自动聚类未标记的产品名称,以快速了解数据集中的产品种类。
本文是第 2 部分,将涵盖:K-means 聚类、评估聚类质量和微调。
如果你还没有,请阅读 第 1 部分 ,其中包括:预处理和矢量化。
现在我们有了单词矩阵,让我们开始聚类。
k 均值聚类
这是有趣的部分:聚集我们的单词矩阵。
K-means 聚类根据数据点之间的相似性或接近性将数据点分配到离散的组中。我们指定聚类数 K,并且该算法迭代地将每个观察值分配给一个聚类,直到每个聚类的观察值尽可能接近其均值(或质心)。
作者图片
理论上,相似的食物名称应该聚集在一起,因为它们对相同的单词(和 n-grams)有相似的值。
作者图片
最佳聚类数
我们怎么知道把什么指定为 K?我们可以使用肘方法来测试不同的 K 值,并比较每个数据点到其质心的距离(误差平方和或 SSE)。
为了理解数据集中的食物类型,我们希望在一个聚类(低 SSE)中使食物名称尽可能相似,并使每个聚类包含 1 或 2 个以上的食物名称。
让我们用我们的词汇矩阵来做这件事。我们知道在我们的食物名称中有 851 个不同的单词,所以不可能有比这更多的食物类型。
作者图片
我们创建的集群越多,SSE 应该越低,并且每个集群离其质心越近。如果我们将图表扩展到 K=1,500(每个不同的食物名称一个聚类),SSE 将是 0。
肘点看起来在 200。此后上证指数的跌幅开始越来越小。
创建集群
让我们从这里开始,测试 K=200。
作者图片
现在我们的单词包矩阵中的每一行都被分配到 0 到 199 之间的一个聚类中。你可以看到我们的研磨香料在前 5 排是在同一个簇中。哇哦!
评估集群质量
创建集群非常简单。现在我们想知道聚类是否恰当地回答了数据集中有哪些食物的问题。我们已经知道,更多的集群意味着更低的 SSE。但是这如何影响聚类的意义呢?
我们需要其他的方法来比较不同数量的聚类以及不同的单词矩阵。注意:SSE 不应该用来比较不同的矩阵,因为它们的值本质上是不同的。例如,单词包使用整数(0、1、2 等。)来表示单词的出现,而 TF-IDF 使用 0 到 1 之间的加权分数。
可读性聚类标签
现在我们的集群是 0 到 199 之间的数字。让我们给我们的集群贴上人类可读的标签。我们可以通过检索每个集群中每行的值大于 0 的矩阵列名来自动完成这项工作。这样我们可以看到一个聚类中所有食物名称共有的单词。
作者图片
我们可以开始理解每个集群代表什么。注意:有一些食物名称中没有任何常用词,所以它们没有被标注。
集群规模
现在我们已经有了集群标签,我们可以查看带标签的集群的数量及其大小。
作者图片
在 K=200 的单词袋矩阵中,1534 个食品名称中只有 96 个没有被标注,8 个食品名称在 1 个一组中。总的来说,93%的食物名称被归为一类。对于第一次测试来说,听起来相当不错!
进一步的标记是可选的
为了更容易地评估集群质量,我将集群分成了高级超市类别(水果和蔬菜、食品柜等等)。这是不必要的,特别是在集群较少的情况下,但是可以轻松阅读。
对 1534 种食物名称进行人工分类并不好玩。手动对数百个集群进行分类更容易管理。如果您有部分标记的数据,这就是分类算法派上用场的地方。
想象这一切
可视化文档相似性的常用方法是 t-SNE 。它将高维的矢量数据投影到二维空间。
来源:黄砖 t-SNE 文档
然而,由于我们有大量的集群,t-SNE 并不是可读性最好的。很难看到离散的集群及其大小。在 200 个集群中,我们多次循环通过颜色图来给每个集群着色,这使得它更难阅读。
相反,我选择了一个树形图,它可以在各自的超市类别中整齐地显示我们的聚类标签和大小。让我们看看我们的单词包矩阵能得到什么。
结果呢
单词包| K=200 | 93%在干净的簇中
作者图片
对于几行代码来说,这已经很棒了。
让我们在 K=200 时评估我们的集群。对于大多数类别,我们有几大串通用词来描述食物的种类。例如,'生的','干的','未煮的','煮的','沥干的'。即使是较小的聚类,我们也不知道数据集中的食物类型。
K=200 最终是单词包矩阵的最佳值。100、150、250 和 300 的测试将更少的食物名称放入干净的聚类中,并且没有使聚类标签更有意义。
如果一个单词包被赋予(大部分)向量中的每个单词相等的权重,那么聚类产生最常出现的单词组是有意义的。
模糊模糊| K=500 | 86%在干净的集群中
作者图片
就像单词包结果一样,我们模糊不清的聚类集中在描述食物的单词上,而不是食物本身:“添加脂肪”、“商业”、“生的”。
它能够找到更多具有长尾描述的组,如“煮过的,没有添加脂肪或盐”,因为矩阵强调字符串相似性,而不是单词相似性。
同样,聚类是基于最常见的单词或单词序列。
TF-IDF(字级) | K=300 | 78%在干净的簇中
作者图片
单词级 TF-IDF 生成的结果最符合大多数超市类别的人的感觉。
我们现在可以在大多数集群中看到食物类型:“猪肉”、“烤牛肉”、“无盐坚果”、“小麦粉意大利面”、“卷心菜”、“生苹果”!
这些单词能够被聚类,因为它们被 TF-IDF 算法赋予了更大的权重,而更常见的描述性单词的权重较小。
TF-IDF (n-gram 水平)| K=500 |在干净的簇中为 87%
作者图片
N-gram 级别的 TF-IDF 比 word 级别的 TF-IDF 为某些类别添加了更多的颜色,因为有关键的 bi-gram。例如,在茶水间,我们现在有“早餐麦片”、“甜饼干”和“牛奶什锦早餐”。在乳制品、鸡蛋和冰箱中,我们现在有“人造黄油脱脂”、“山羊奶酪”和“奶油脂肪”。
微调
虽然这些测试令人印象深刻,因为只需要很少的人工输入,但总有一些食物名称没有标签或标签不太相关(例如,“生的”远不如“卷心菜”有用)。
这里有一些进一步的调整,可以测试,以尽量减少残留的食物名称的数量。
- 考虑在预处理阶段删除更多的单词,或者在矢量化阶段降低它们的权重。
- 测试 min_df 和 max_df 设置中的设置阈值,以忽略在矢量化阶段出现太频繁或不够频繁的术语。
- 对于标签较宽的较大聚类,再次单独聚类可以进一步区分食品名称。
- 相反,测试分层聚类,以获得自下而上的食物名称分组方法。注意:这最适用于较小或唯一性较差的数据集。
- 如果所有这些都失败了,试着用你想要的标签手动标注足够多的食物名称,并使用分类算法来代替。
结论
我们已经看到 NLP 和 K-means 聚类对于组织未标记的文本是多么有效。
与任何建模一样,没有一个模型适合所有数据集和用例。但是有一些测试的实际步骤和注意事项。
这在电子商务产品分类中的应用产生了许多好处:解放人力、更准确和动态的分类、更好的库存洞察和更有意义的竞争分析,等等。
还有许多现实世界的应用:社交媒体帖子和评论的情感分析、模糊搜索、产品推荐、电子邮件过滤。
本指南中使用的数据集来自 澳大利亚食品成分数据库 ,并由澳大利亚新西兰食品标准局许可。
聚类句子嵌入识别短文本意图
原文:https://towardsdatascience.com/clustering-sentence-embeddings-to-identify-intents-in-short-text-48d22d3bf02e?source=collection_archive---------0-----------------------
行业笔记
UMAP + HDBSCAN 的超参数调整以确定未标记文本数据中的聚类数
由迈克·提尼翁在 Unsplash 上拍摄的照片
TL;DR 聚类短文本消息的无监督学习问题可以转化为约束优化问题来自动调优 UMAP + HDBSCAN 超参数。chat intents包使得这个调优过程很容易实现。
介绍
用户对话交互可以成为如何改进产品或服务的巨大信息源。理解人们为什么联系客服也是自动化部分或全部回复的重要的第一步(例如,使用聊天机器人)。有几种方法来分析对话交互数据以提取有用的见解,并且通常通过讨论的主题、情感和意图来表征交互。
从想要改进产品或服务的角度来看,确定意图特别有用,因为它回答了这样一个问题:为什么人们首先伸出手来?然而,利用用户消息意图的一个主要障碍是,确定它通常被视为一个分类问题。这意味着您通常需要已经有了大量的标记数据才能开始。例如,微软的路易斯和谷歌的 Dialogflow 都是从这样一个前提开始的,你要么可以使用预先构建的域标记数据,要么你已经有了标记数据。
但是,如果您还没有任何带标签的数据,并且您认为任何公开可用的带标签的数据都不相关(这是经常发生的情况),该怎么办呢?除了无监督学习问题的挑战之外,包含意图的消息通常非常短(少于 15 个单词)。我最近接受了这个挑战,还有一个额外的障碍:我们总共只有大约 1000 个样本。我立刻想起了几年前看到的一些明智的建议:
来源:https://twitter.com/RichardSocher/status/840333380130553856
在对我的特殊问题思考了一会儿,并尝试了几次把它当作一个无监督的学习问题,但毫无结果之后,我最终手动标记了这些数据(大约花了一周……)。手动标注让我对数据有了有益的理解和直觉。但与此同时,这让我非常好奇,想知道是否有一种方法可以更自动化地实现那些被标记的意图。这篇文章将提供一种我学到的方法,可以自动对短文本消息数据进行聚类,以识别和提取意图。
定义目标
在我们进一步讨论之前,让我们先定义一下我们要做什么。在这里我有兴趣回答这个问题:
给定用户和公司代表之间的一组未标记的对话,有没有办法自动获得用户意图的有用标记?
由于这是一个无人监管的问题,标记意图可能相当主观,我不指望能够找到一个完美的解决方案。但是,类似于 auto-EDA 库并不详尽,但在面对新数据时可以提供一个有用的起点,我们可以在进行耗时的手动标记之前做些什么来提供初步的见解吗?自动化的结果可能已经足够好了,使人们从一周或更长时间的手动标记数据中节省下来。或者,它可以通过提供一个有用的起点来加速标记过程。
数据
显然,我无法分享激发本文灵感的原始数据集,所以我开始尽可能地寻找公开可用的类似资料。虽然有几个对话数据集已经标记了意图,但其中许多的主要限制是所表示的意图数量很少(通常约 10 个)。拥有少量的意图或类会使问题过于简单。尽管手工标注过程本身是主观的,但我发现对于我正在处理的数据来说,很容易有超过 50 种不同的意图。对于现实世界的应用程序来说,这似乎很常见。
幸运的是,PolyAI 团队发布了 banking77 数据集,其中包含了 77 种不平等表示的意图:
来自 bank77 数据集的样本数据。图片由作者提供。
完整数据集包含 77 个意图的训练数据集中的 10,0003 条消息。最大和最小类别计数分别为 187 和 35。
为了更接近我之前面临的挑战,我将从训练集中的 10,000 个样本中随机抽取 1,000 个样本:
data_sample = data_full.sample(1000, random_state=123)
请注意,尽管该数据集对于本练习的演示目的很有用,但这仍然有些人为,并且您将在真实环境中面临额外的挑战。例如,你首先需要确定在一个完整的对话序列中什么信息或句子实际上与意图相关,以及处理随机的系统错误信息、打字错误和无意义的信息。这篇关于发现和分类 AirBnB 信息意图的文章触及了一些现实世界的挑战。
尝试主题建模
有几种方法可以解决像这样的无监督学习问题。面对这个问题,第一个想到的方法就是主题建模。这是一种用来发现文档集合中潜在主题的技术。
可以使用许多算法来执行主题建模,但一个非常常见的算法是潜在狄利克雷分配(LDA) 。LDA 是一种生成概率模型,它假设每个文档由固定数量的主题分布组成,每个主题由单词分布组成。当尝试使用 LDA(和许多其他主题建模算法)时,一个很大的挑战是决定实际使用多少主题,这是一个必要的模型超参数。显然,如果这是我们希望从分析中得到的,那么这就是一个问题。连贯性是一种通过测量每个主题中单词的相似程度来评估所学主题质量的方法,连贯性分数越高越好。 Gensim ,一个非常流行的主题建模库,让计算模型一致性变得很容易。不幸的是,对于我们在这里处理的短文,使用 coherence 选择多少主题并不明显:
LDA 相干性作为应用于 bank77 数据集样本的主题数量的函数。图片由作者提供。
似乎增加主题的数量会继续增加这个数据集的一致性,这对于我们选择多少主题几乎没有指导意义。
更具挑战性的是,主题模型可能很难解释。例如,考虑以下确定的主题:
从 bank77 数据集的样本中提取的 LDA 主题。图片由作者提供。
虽然有些话题有意义,但许多很难解读。关于皮尤研究中心工作的系列文章很好地解决了解释主题模型的挑战。
最终,最大的问题是意图比主题更微妙。LDA 和其他主题建模方法的一个局限性是,它们将文档中的词汇表视为一个单词包,其中的顺序无关紧要。这对于较长的文档(和较大的语料库)很有用,在这些文档中,识别同现的单词可以很好地描述主题。此外,主题的数量通常相对较少,而且主题相当独特。然而,短文本意图带来了挑战,例如两个短语具有几乎相同的单词但意图非常不同,或者具有相同的意图但几乎没有共同的单词。这严重限制了标准主题建模方法在短文本中识别意图的有效性。
聚类嵌入
除了主题建模,聚类是解决无监督学习问题的另一种非常常见的方法。为了能够对文本数据进行聚类,我们需要做出多个决定,包括如何处理数据以及使用什么算法。
选择嵌入
首先,有必要用数字表示我们的文本数据。一种方法是创建每个单词的嵌入或向量表示,用于聚类。这篇文章很好地概述了嵌入单词的各种方式。由于每个消息由几个单词组成,一种选择是简单地对每个消息中所有单词的单个单词嵌入进行平均。对于某些应用程序来说,这已经足够好了,但是最好是直接计算完整句子的嵌入,以便更有效地考虑含义。特别是考虑到每条消息有多短,这将有助于避免上述主题建模算法的一些缺陷。
事实证明,有许多方法可以找到完整消息或句子的单一向量表示。本文对实现这一目标的各种方法进行了概述。Google 的通用句子编码器 (USE),由 Cer 等人于 2018 年首次发布,是一种流行的句子嵌入模型。使用模型在各种数据上进行训练,包括维基百科、网络新闻、网络问答页面和论坛,它在句子语义相似性任务上表现良好。
通用句子编码器模型。来源:tensor flow Hubhttps://tfhub.dev/google/universal-sentence-encoder/4
2019 年,Reimers 和 Gurevych 发表了一篇论文,介绍了句子-BERT,这是一种“对预训练的 BERT 网络的修改,使用连体和三元网络结构来导出语义上有意义的句子嵌入,可以使用余弦相似性进行比较”。他们还发布了一个 Python 实现,使得下载和使用许多不同的预训练模型变得容易。
鉴于我们的数据集如此之小,在这里使用预先训练的模型是更可取的。对于这个分析,我将比较四个预训练的句子嵌入模型的结果:USE 和三个不同的句子-BERT 模型( all-mpnet-base-v2 、 all-MiniLM-L6-v2 和all-distilloberta-v1)。
将我们的信息转换成句子嵌入就很简单了:
使用各种预训练的嵌入模型嵌入形状。图片由作者提供。
降维
如上所述,我们所有的句子嵌入都有很高的维数(每个大于 500 个特征)。维数灾难的一个表现是,聚类所需的距离度量(如欧几里德和曼哈顿)在如此高的维数上变得毫无意义(更多细节,请参见 Aggarwal 等人的“关于高维空间中距离度量的惊人行为”)。虽然一些句子转换器预训练模型是以保留一些距离度量的有用性的方式创建的,但是在聚类之前进行维度缩减将极大地改善结果。(为了向自己证明这一点,我在没有先降维的情况下,使用不同的聚类算法和嵌入简单地探索了一下。)
由麦金尼斯等人于 2020 年提出的一致流形逼近和投影降维( UMAP )作为一种降维技术,已经迅速普及。UMAP 比 t-SNE 更快、更具可扩展性,同时也更好地保留了数据的全局结构。这使得它既可用于可视化,也可作为聚类前的预处理降维步骤。我们将在这里使用它。
选择聚类分析算法
Scikit-learn 文档中有一个有用的概述,介绍了它支持的许多不同的聚类算法以及每种算法何时性能最佳。对于我们当前的应用,最好是使用一种不需要预先指定聚类数的算法,并且还可以容忍噪声数据。基于密度的算法在这里是一个很好的选择,因为它们不需要指定簇的数量,并且与簇的形状无关。具有噪声的应用的基于层次密度的空间聚类(HDBSCAN)已经变得流行,因为它具有比 DBSCAN 更少且更直观的超参数,并且对可变密度聚类是鲁棒的。HDBSCAN 文档提供了不同聚类算法的有益比较。HDBSCAN 对当前的问题最有效,所以在本文中我们将重点关注它。
从 UMAP + HDBSCAN 生成集群
为了主题建模的目的,至少有两个包(可能更多)可以将 UMAP 和 HDBSCAN 链接在一起:Top2Vec ( github 和 paper )和 BERTopic ( github 和 article )。然而,两个包中使用的默认超参数对于像当前这样的具有短文本和小语料库的问题(大多数数据最终被分类为噪声,并且总共只找到三个聚类)并不工作良好。为了更容易适应我们当前的意图提取问题,我们将直接使用 UMAP 和 HDBSCAN 软件包进行超参数调整。
UMAP 有几个超参数来控制它如何执行降维,但最重要的两个是n_neighbors
和n_components
。n_neighbors
参数控制 UMAP 如何平衡数据中的局部与全局结构。该参数控制 UMAP 学习流形结构的邻域的大小,因此较低的值n_neighbors
将更多地关注非常局部的结构。n_components
参数控制输入数据降维后最终嵌入数据的维度。不幸的是,没有地面真实标签,没有明显的方法来挑选最佳 UMAP 参数。这里我们有标签,我们将在最后使用它来确定我们做得有多好。但是这项工作的重点是当我们有未标记的数据时确定一种使用的方法。在安杰洛夫的 Top2Vec 论文中,他提到n_neighbors
= 15 和n_components
= 5 最适合他的下游任务,但这不太可能总是适用于任何数据集。
HDBSCAN 还有几个重要的超参数,但要考虑的最重要的一个是min_cluster_size
。直观地说,这控制了您想要视为集群的最小分组。此外,min_samples
参数控制聚类的保守程度,如果未指定,该参数默认为等于min_cluster_size
。它越大,作为噪声/异常值丢弃的点就越多。解耦这两个超参数并使min_samples
小于min_cluster_size
将通过将它们与它们最相似的相邻聚类合并来基本上保留将被标记为异常值的点。如果我们试图发现集群的数量,这并不是我们想要发生的事情。因此,这里我只考虑直接修改min_cluster_size
参数:
注意,UMAP 是一种随机算法,使用随机性来加速逼近步骤并执行优化。因此,我们将随机种子状态设置为一个常量值,以获得给定的一组 UMAP 超参数的一致结果。
定义评分函数
我们现在有了一个管道,其中有三个我们想要调优的超参数(n_neighbors
、n_components
和min_cluster_size
)。接下来,我们需要决定如何实际评估我们的聚类,以选择最佳超参数。虽然通常与各种聚类算法一起使用,但轮廓分数对于基于密度的算法(如 DBSCAN 和 HDBSCAN)来说并不是一个很好的验证度量,因为它假设所有点都被分配到一个组中,并且不能适当地处理噪声/异常值。基于密度的聚类验证(DBCV) 已经被一些人提出并用于调整 HDBSCAN 超参数。虽然它可能在一些应用中运行良好,但对于当前的问题,它倾向于使用较少的聚类数,而将过多的样本放在“噪声”类别中。
相反,我们将利用有用的probabilities_
HDBSCAN 属性,该属性来自文档:
每个样本作为其指定分类成员的强度。噪声点概率为零;聚类中的点的赋值与它们作为聚类的一部分存在的程度成比例。
这篇由 Nikolay Oskolkov 撰写的文章提供了一个非常直观且符合逻辑的解决方案,只需将我们想要最小化的成本函数定义为:
Cost = percent of dataset with < 5% cluster label confidence
这将有助于确保我们将尽可能多的数据点分配给实际的聚类,而不是将它们标记为噪声。但是,是什么阻止我们设置超参数,使每个单独的点成为一个“集群”,或者仅仅是一个巨大的集群呢?
**这里我们必须使用一些领域知识来应用约束。**对于这个问题,根据我对这类数据的经验,我预计至少会有 30 个标签,但不会超过 100 个。所以我们的目标函数变成了一个约束优化问题:
minimize(Cost = percent of dataset with < 5% cluster label
confidence)Subject to: 30 < num_clusters < 100
随机超参数搜索
在当前数据集大小仅为 1,000 个样本的情况下,对于给定的一组输入,生成聚类并对其进行评分仍然需要大约 3 秒钟。尝试进行例如 10×10×10 超参数搜索空间的全网格搜索将花费几乎一个小时。较大的数据集需要更长的时间。我关心找到正确的超参数,但不太关心T4。执行随机搜索而不是全网格搜索是一个非常有效的替代策略:
运行对 100 个随机选择的超参数值的搜索得到:
UMAP+HDBSCAN 随机搜索超参数空间的结果。图片由作者提供。
我们看到,成本最低的运行总共也只有不到 10 个集群。聚类数在 30 和 100 之间的第一个条目有 59 个聚类,成本为 0.140(即大约 14%的数据被标记为异常值或低置信度)。跑步也只用了 6 分钟。还不错。
基于超点的贝叶斯优化
随机搜索超参数空间工作得相当好,但是有一个更好的选择:贝叶斯优化。在这里,我们将利用流行的超远视包来做到这一点。如果你不熟悉 hyperopt 和贝叶斯优化,这篇文章提供了一个很好的概述。
首先,定义我们想要最小化的目标函数。如果聚类的数量落在期望的范围之外,则通过添加惩罚项将优化约束包括在目标函数中:
然后使用树形结构 Parzen 估计器(TPE)算法在超参数搜索空间上最小化目标函数:
在我们的参数空间上运行具有 100 个最大评估的贝叶斯搜索产生比随机搜索稍好的结果:
对 UMAP+HDBSCAN 的超参数空间进行贝叶斯搜索的结果。图片由作者提供。
然后,使用来自多个不同模型的嵌入来运行管道就很容易了:
此处考虑的每个模型的最佳超参数。图片由作者提供。
在这一点上,我们可以做更多的事情,如可视化集群或手动检查其中一些以确保它们有意义。但最终,我们试图从最佳分析管道中找到“最佳”聚类结果。如果我们相信损失函数,那么选择损失最低的配置是有意义的。在上面尝试的组合中,似乎我们应该使用句子转换器#1 ( all-mpnet-base-v2 ),它使用n_neighbors
= 6、n_comonents
= 9 和min_cluster_size
= 6 生成了 55 个集群。
评估绩效,了解基本事实标签
在这种情况下,我们碰巧也知道基本事实标签,因此我们可以看到我们的损失函数与性能的相关性。我们可以手动检查模型在一些地面真实集群上的表现:
四种不同模型的单一基本事实类别的示例结果。图片由作者提供。
如上所示,所有模型在将card_about_to_expire
基本事实组中的大部分消息放在同一个集群中时表现相对较好。至少对于这个类别来说,第一句话-transformer 模型似乎在正确地将所有消息分配到同一个集群方面表现突出。
除了手动检查所有组,我们还可以定量评估模型性能。评估文本聚类的两个常用指标是归一化互信息和调整后的 Rand 指数。这两个指标的值都在 0 到 1 之间,越大越好。计算考虑中的四个模型的最佳超参数的这些度量得出:
四个模型结果的比较和对地面真实标签的评估。图片由作者提供。
与我们之前的结论一致,句子转换器#1 实际上表现最好,ARI 为 0.46,NMI 为 0.81。然而,某些其他模型的性能排序并不遵循其成本函数值的预期顺序。因此,我们对超参数调整的评分方法并不完美,但显然对当前的应用仍然有用。
自动聚类标记
为了使结果更有帮助,我们还可以自动将描述性标签应用到我们找到的分类中。Liu 等人的论文提供了一种有趣的方法,通过从每个聚类中的短语中提取最常见的动作-对象对作为聚类标签(例如“book-flight”)。我们在这里考虑的 bank77 数据集比那篇论文中的数据集稍微复杂一些,但是我们可以做一些类似的事情。在这里,我们将连接最常见的动词、直接宾语和每个簇中的前两个名词。spaCy 包有一个强大的语法依赖解析器,我们可以用它来做这件事:
对一个例句应用 spaCy 的句法依存解析器的结果。图片由作者提供。
我们可以编写一个简单的函数来提取每个分类的标签:
将这些标签应用到我们的最佳模型找到的每个聚类中,产生了我们的最终结果:
带有计数和描述性标签的提取分类的摘要。图片由作者提供。
使用我们的调整方法,我们已经自动提取了描述性标签,并将其应用于数据集中的 55 个分类。
因为在这种情况下,我们知道每个文档的基本事实标签,所以我们还可以检查一些文档,以查看我们的派生标签与基本事实标签的匹配程度:
原始数据的样本,带有派生的描述性标签和原始的基本事实标签(“类别”字段)。图片由作者提供。
它们并不完美,但提取的标签与地面类别标签非常匹配!
摘要
在这篇文章中,我概述了一个利用领域知识创建约束优化问题的框架,以自动调整 UMAP 和 HDBSCAN 超参数。这使我们能够轻松地对短文本文档进行聚类,并应用描述性标签。本文的重点是小数据集,但是同样的方法也可以应用于更大的数据集。在决定或需要完成耗时的手动标注之前,聚类结果在很短的时间内提供了对未标注文本数据的有用见解。
本文中的所有代码示例,以及我为简化这些概念的应用而创建的 chatintents python 包,都可以在这里找到:
https://github.com/dborrelli/chat-intents
感谢阅读。如果你觉得这篇文章很有帮助,请在下面留言或联系 LinkedIn。
使用 GPT3 嵌入对 20 个新闻组数据集进行聚类
原文:https://towardsdatascience.com/clustering-the-20-newsgroups-dataset-with-gpt3-embeddings-10411a9ad150?source=collection_archive---------7-----------------------
新 API 端点的实验
图片:www.pexels.com
嵌入是为文本寻找数字表示的一种方式,它捕捉文本与其他文本的相似性。这使得它们成为应用聚类方法进行主题分析的理想基础。在本文中,我想通过将语言模型 GPT3 与文档中的主题进行比较,来测试语言模型GPT 3的嵌入,该语言模型最近通过 API 变得可用。OpenAI 正在向所有 API 用户推出嵌入,作为公共测试版的一部分。我们现在可以使用新的嵌入模型进行更高级的搜索、聚类和分类任务。嵌入也用于可视化。
数据集
20 个新闻组数据集(许可证:公共域/来源:【http://qwone.com/~jason/20Newsgroups/】T4)是大约 20,000 个新闻组文档的集合,分为 20 个类别。该数据集是由斯坦福大学自然语言处理小组历时数年收集的。它是一个标准的数据集合,通常在自然语言处理中用于评估过程。
我们使用数据集的训练部分(60%的数据),并过滤掉过长的文章,以避免 GPT3 模型的上下文长度问题。仅使用少于 2000 个令牌的文档。
使用“Scikt Learn”加载数据,并用 GPT2 Tokenizer 检查数据长度是否合适。然后创建一个 Pandas 数据框,其中包含帖子的文本和一个表示新闻组来源的编号。
下载嵌入
要从 OpenAI API 中检索数据,您需要一个 API 键。检索是有成本的,这取决于所用的模型。嵌入模型将免费到 2021 年底。
目前,他们为不同的功能提供了三类嵌入模型:文本搜索、文本相似性和代码搜索。每个系列包括多达四种型号的尺寸:
- Ada (1024 嵌入维数),
- 巴贝奇(2048 嵌入尺寸),
- 居里(4096 嵌入维度),
- 达芬奇(12288 嵌入维度)。
达芬奇是最有能力的,但比其他型号更慢也更贵。Ada 能力最差,但速度明显更快,成本也更低。
我们使用巴贝奇相似性模型“巴贝奇-相似性”进行测试。
嵌入端点的文档可在以下位置找到:
在 OpenAI 的 Python 包和 GPT3 的文档的辅助函数的帮助下,我们现在可以下载每个文档的数字表示,并将其作为一列添加到数据框中。
基于嵌入的聚类
对于聚类,我们使用 KMeans 算法。这是一种分区算法,它将对象分成 k 个簇,使得簇内所有对象对之间的距离之和最小。为了找到数据集的最佳聚类数,我们计算 k 值范围内的聚类,然后选择具有最高轮廓分数的聚类。
作者剪影评分/图片
在本例中,18 是该范围内的最大值。这对应于语料库中的 18 个不同主题。集群的大小从 431 到 1052 不等。
嵌入和集群的可视化
为了可视化,我们使用 TSNE 算法。这是一种非线性降维技术,将高维数据投影到二维或三维。这有助于更好地了解数据并识别模式。
首先,我们用颜色代码可视化嵌入及其新闻组关系。
作者从新闻组成员/图像中嵌入颜色
这表明,如果以新闻组成员作为衡量标准,空间位置很好地反映了文档的内容以及它们之间的相似性。我们只使用了 GPT3 的嵌入作为文档的表示,没有来自文本的更多信息,也没有任何进一步的微调。
其次,我们考虑相同的表示,但是用 KMeans 找到的聚类作为颜色代码。
作者使用聚类/图像中的颜色进行嵌入
有很小的区别,特别是使用的颜色,但是结构和聚类中心非常相似。这也强调了主位结构在嵌入中得到了很好的体现。
描述集群
为了描述各个集群代表什么内容,我们尝试创建集群的描述。为此,我们从每个集群中随机抽取一些文档,并将其作为 GPT3 本身的输入来生成描述。我们在 OpenAI API 中使用“davinci-instruct-beta-v3”模型是因为它的表达能力。
对于每个集群,我们随机抽取 3 个文档(每个文档的前 1000 个字符,否则 GPT3 的提示会太长。)将此与这些文档有什么共同点的问题结合起来,将此发送到 GPT3,从而获得每个集群的描述。
这给了我们以下结果:
Cluster 0 Topic: GraphicsWhat do the following documents have in common?They are all about graphics.
Cluster 1 Topic: space station redesignAuthor: Michael F. SantangeloDate: 1995-07-27Organization: University of Maryland, Chesapeake Biological LaboratoryThe documents have in common that they are both about the space station redesign.
Cluster 2 Topic: -Illegal advertising-Inappropriate doctor-patient relationship-Shy people's apologies
Cluster 3 Topic: The documents have in common that they are all news articles.
Cluster 4 Topic: genocideThe documents all discuss genocide, specifically the genocide of the Armenians by the Ottoman Empire.
Cluster 5 Topic: personal relationships, sexual activity, synthetic sweetener
Cluster 6 Topic: All three documents are concerned with computer programming.
Cluster 7 Topic: What do the following documents have in common?The documents have in common that they are all examples of writing.
Cluster 8 Topic: All three documents discuss the use of old SIMMs.
Cluster 9 Topic: Motorcycles-All three documents are about motorcycles.-All three documents mention the CX500 Turbo.-All three documents mention the Ducati Mike Hailwood Replica.
Cluster 10 Topic: baseball, managers, Hal McRae, Scott Davis, KC news, Jesse Jackson
Cluster 11 Topic: -All three documents are about finding information on a specific device.
Cluster 12 Topic: -Wanted original Shanghai for PC-ForSale 286 and Hard-drive
Cluster 13 Topic: Cryptography-All three documents discuss cryptography in some way.
Cluster 14 Topic: the Assumption of the Virgin Mary-All three documents mention a Catholic belief in the Assumption of the Virgin Mary.-All three documents mention that this belief is unusual.-All three documents mention that some people object to this belief.-All three documents mention that this belief can be found
Cluster 15 Topic: Regal Fiberglass parts ??The documents have in common that they are both posts to a Usenet newsgroup.
Cluster 16 Topic: What do the following documents have in common?They are all examples of sports news.
Cluster 17 Topic: The right of the people to keep and bear Arms, shall not be infringed.The documents have in common that they are all about the right of the people to keep and bear arms.
有些描述相当不错,例如
"这三份文件都与计算机编程有关。"
或者
“都是体育新闻的例子。”
然而,其他的非常奇怪,例如
"这些文件的共同点是都是新闻文章。"
为了达到更好的效果,有必要对新闻组文本进行预处理,例如过滤电子邮件地址,而且还要压缩内容以包括更多的文档,而不会达到 GPT3 的提示限制。
摘要
文章中的研究表明,可以通过 API 从 GPT3 中检索到的嵌入非常适合描述文本语料库的内容结构。使用 20 个新闻组数据集的例子,通过可视化和 KMeans 聚类的方式表明,由嵌入形成的空间结构反映了新闻组的主题。
GPT3 还可用于描述单个集群的内容。
具有各种应用的聚类类型
原文:https://towardsdatascience.com/clustering-types-with-various-applications-b6be738fb2e5?source=collection_archive---------23-----------------------
实践教程
通过 python 实现解释了聚类类型及其使用范围
***Table of Contents* 1\. Introduction
2\. Clustering Types
2.1\. K-Means
-----Theory
-----The optimal number of clusters
-----Implementation
2.2\. Mini-Batch K-Means
2.3\. DBSCAN
2.4\. Agglomerative Clustering
2.5\. Mean-Shift
2.6\. BIRCH
3\. Image Segmentation with Clustering
4\. Data Preprocessing with Clustering
5\. Gaussian Mixture Model
-----Implementation
-----How to select the number of clusters?
6\. Summary**
1.介绍
利用无监督学习技术,可以通过考虑未标记数据集的相似属性来对其进行分组。但是,这些相似特征在每个算法中的观点是不同的。无监督学习提供关于数据集的详细信息,并标记数据。有了这些获得的信息,数据集可以重新排列,变得更容易理解。通过这种方式,无监督学习被用于客户细分、图像细分、遗传学(聚类 DNA 模式)、推荐系统(将具有相似观看模式的用户分组在一起)、异常检测等等。根据数据集的统计特性,使用 PCA 获得新的和简洁的成分,PCA 是最常用的降维技术之一,在前一篇文章中提到过。本文详细介绍了聚类的类型,利用聚类进行图像分割,利用聚类进行数据预处理,以及高斯混合方法。python 实现支持所有解释。
由瓦伦丁·萨尔加在 Unsplash 上拍摄的照片
2.聚类类型
2.1。K-Means
理论
K-means 聚类是常用的聚类算法之一。基本思想是按照用户确定的数目,根据距聚类中心的距离来放置样本。下面的代码块解释了如何从头开始构建 k-means 聚类。
来源
确定数量的聚类的中心被随机放置在数据集中。所有样本都被分配到最近的中心,这种接近度是用上述代码块中的欧几里德距离计算的,但是也可以使用不同的计算方法,例如曼哈顿距离。样本被分配到的中心根据它们的人口更新它们的位置(平均值)。阶段 2,即重新计算样本距中心的距离,并分配给最近的中心,并重复该过程。阶段 3,每个聚类中心根据数据集使自己重新居中。这个过程持续到一个平衡状态。通过从mglearn
库中导入这里口头描述的步骤,上面的代码块在图 1 中被可视化。
图一。mg learn . plots . plot _ k means _ algorithm(),图片作者
上面的代码是由 sklearn 库导入的,并在实践部分中举例说明。众所周知,方法有如.fit``.predict
.transform
。使用 .fit
导入的 K-means 算法通过将样本放入聚类中、更新聚类中心并重复这些操作来执行上述操作。当达到平衡状态时,即没有变化时,算法完成。星团的中心可以用Kmeans.cluster_centers_
看到。使用.predict
我们可以预测任何外部样本的聚类,我们想知道它将属于哪个聚类。用 .transform
,可以得到样本和每个聚类之间的距离作为一个矩阵。该矩阵的每一行代表样本距每个聚类中心的距离。选择最小值(将样本分配到最近的中心)称为硬聚类。在这一点上,值得一提的是,作为每个样本到所选数目的聚类的距离的结果而获得的新数据集(与 **.transform**
)实际上是一种非常有效的非线性降维技术。
最佳集群数
找到每个 k 值的惯性值是选择最佳聚类数的方法之一。惯性是每个聚类的误差平方和。根据这个定义,具有最低惯性值的数字 k 将给出最准确的结果。虽然理论上是正确的,但是我们在概化模型的时候,惯性值达到最小值即 0 的地方就是 k =样本数,也就是每个样本接受聚类的点。从这一点来看,最好的方法是检查图形并确定断点,以便选择最准确的集群。
图二。惯性图——聚类数,作者图片
图 2 显示了实际部分中用 k-means 分组的数据集的聚类图的惯性数。查看图表,可以看到衍射(肘形)发生在 n=2 点,这被解释为要选择的最佳簇数。
另一种方法是确定轮廓得分并比较聚类数中的轮廓得分值。剪影得分是一个介于-1 和 1 之间的值,等于(b-a)/max(a,b),其中 a 是到同一聚类中其他实例的平均距离,b 是平均最近聚类距离。根据定义,最高分用于确定最佳聚类级别。唯一的缺点是计算复杂。在图 3 中,显示了实际零件的轮廓分数图形。
图 3。剪影评分,作者图像
可以看出,最高值是在 2 个集群的级别获得的。
不添加值 1,因为至少需要 2 个聚类来确定轮廓分数。
履行
导入 Sklearn 库中的数据集,然后将 K-Means 聚类算法应用于这两个数据集,如下所示:
肘图和剪影的结果已经显示在上面,k-means 的效果显示在图 4 中。
图 4。k-means 在数据集上的聚类能力,按作者分类的图像
2.2.小批量 K 均值
顾名思义,它以小批量更新聚类中心,而不是整个数据集。正如预期的那样,惯性值更高,尽管与 k-means 相比它缩短了时间。它可用于大型数据集。它在 Python 中实现如下:
如图 5 所示,与 K-Means 相比,结果几乎相同。
图 5。小批量 k-means 在数据集上的聚类能力,按作者分类的图像
2.3.基于密度的噪声应用空间聚类
我们可以将带噪声的应用程序的基于密度的空间聚类(DBSCAN)的原理与在一个装满链的盒子中整理出链进行比较。聚类是根据数据集彼此的接近度而不是总体中的样本与中心的接近度来创建的,并且聚类的数量不是由用户设置的。用更正式的术语来说,该算法对距离比用户设置的€
超参数更近的样本进行分组。另一个超参数min_samples
是将该集合分配为一个聚类所需的最小样本数。从表达式和名称可以理解,分组是根据数据集的密度来完成的。密集区的样品称为岩心样品。上面的菜谱如图 6 所示,使用了mglearn
库。
图 6。mglearn.plots.plot_dbscan(),图片作者
当eps=1.5
被检查时,同时创建 3 个不同的组,并在min_samples=2
的情况下对所有样本进行标记。因为所有数据集都比eps=1.5
更接近最近的数据。在相同的情况下,当min_samples=5
被设置时,仅创建 5 个数据簇,而 7 个数据保持未标记。因为数据离所创建的簇的距离远。另外,没有形成新的聚类的原因是在eps=1.5
距离处没有 5 个彼此接近的样本。可以看出,簇的数量是根据用 DBSCAN 设置的超参数来确定的。如预期的那样,在具有适当设置的异常检测中使用非常有用。
它已应用于以下代码块中的数据集:
Moons 数据集在结构上不适合用 k-means 进行分离,但经过数据标准化处理后,用 DBSCAN 进行了相当优雅的聚类。与 K-Means 不同,DBSCAN 的结构中不包含 .predict
方法,因此无法根据这个数据集确定外部数据属于哪个聚类。但是用dbscan.component_
提取 DBSCAN 分量,然后称为矩阵 X;使用dbscan.labels_
方法提取标签,然后调用 y,在最后一步,使用 KNeighbourClassifier 对标签进行训练,该模型对外部数据也很有用。
图 7。DBSCAN 对数据集的聚类能力,按作者分类的图像
2.4.凝聚聚类
每个样本从一个聚类开始,小聚类(样本聚类)与用户选择的条件相结合,直到达到指定的聚类数。这些条件是:
linkage= ‘ward’
:最小化被合并聚类的方差(默认)
linkage= ‘average’
:使用每次观察距离的平均值
linkage= ‘complete’
:使用两个集合的所有观测值之间的最大距离。
linkage =‘single’
:使用两个集合的所有观测值之间的最小距离。
此外,聚类之间的距离可以用亲和度超参数来调整。【欧几里得】【L1】【L2】【曼哈顿】【余弦】,或者*【预计算】*。用图 8 所示的mglearn
库可视化凝聚聚类。
图 8。mg learn . plots . plot _ aggregate _ algorithm(),图片由作者提供
可以看出,聚类过程从最接近的样本开始,并且合并继续进行,直到用户确定了聚类的数量。由于其结构,凝聚聚类不包括.predict
方法,就像 DBSCAN 一样。外部数据是用 fit_predict 方法估计的。凝聚聚类通过生成层次聚类来工作。可视化这些层次聚类的最佳方式是创建树状图。它通过以下代码块应用于我们的 moons 数据集:
代码块的输出如图 9 所示。
图 9。聚集聚类在数据集上的聚类能力,按作者分类的图像
如果从低级到高级来解读,每个样本就是一个聚类。所以,我们有一些样本群。由于它们的数量太多,合并过程发生在底部,如图 10 所示。这一过程将继续,直到用户确定集群的数量,并将在指定点中断。
图 10。月球数据集的树状图,图片由作者提供
2.5.均值漂移
它从放置在数据集中的一个圆开始,然后移动以显示该圆中数据的平均值。到达新位置后,将计算内部数据的平均值,并再次将其置于中心位置。这个过程一直重复到平衡状态。具有高密度的地方可以被定义为基于密度的算法,因为它们会将平均值拉向它们(即均值偏移)。我们还可以在密集区域内检测不同的集群,假设我们缩小了圆圈的大小。一旦带宽发生变化,就会创建许多集群,如图 12 所示。
bandwith=0.75
设置在月球数据集中,结果如下:
图 11。Mean-Shift 对数据集的聚类能力,按作者分类的图像
图 12。不同带宽对均值漂移聚类算法的影响,图片由作者提供
2.6.桦树
BIRCH(使用层次结构的平衡迭代缩减和聚类)是一种基于树的算法,适用于大型数据集。与 Mini Batch k means 相比,它能以相似的成功率提供更快的结果。由于聚类过程是基于树的,因此它可以快速地将样本分配到聚类中,而无需将它们与创建的模型一起存储。所以才快。但是,由于它是基于树的,所以建议在特征数不超过 20 时使用它。
图 12。Birch 在数据集上的聚类能力,按作者分类的图像
3.聚类图像分割
由于在本节之前我们已经处理了足够多的 sklearn 库,所以让我们通过使用 CV2 库将 K-Means 应用于图 13 中看到的图像。以下代码块已应用于不同 k 值的图像。
- K 均值的结果如下:
图 13。使用 k-means 的图像分割,按作者分类的图像
- DBSCAN 的结果如下:
图 14。使用 DBSCAN 的图像分割,按作者分类的图像
4.聚类数据预处理
如果我们从图像数据集中对其进行解释,则有数百个特征,并且如果这些特征是通过聚类得到的,则可以认为这些特征被分组并且进行了降维。在以下代码块中,使用决策树算法对 Load_digits 数据集进行分类,包括应用聚类和不应用聚类:
可以看出,当聚类数设置为 40 时,得分率从 83 增加到 88。
5.高斯混合模型
GMM 是一种概率模型,它假设数据集由具有未知参数的单个高斯分布的组合组成。如上所述,使用 K-means 进行硬聚类,并将样本分配到最近的聚类。考虑到 k 均值数据集中的分布和密度等因素,这是一种基于聚类中心的无监督学习技术,k 均值可能会给出误导性的结果。对于密度,上面可以看出 DBSCAN 更成功。如果按照分布来处理,GMM 的聚类效果会更好。为了更好地理解 GMM,我们来定义构造块高斯。什么是高斯,它是主要成分,它揭示了什么?
当样本绘制在直方图中时,高斯分布代表独特的钟形曲线。当存在与测量值相互作用的随机因素时,会出现正态(高斯)分布。在正态分布中,大多数数据点将具有类似于平均值的度量,并且平均值是钟形曲线的中心。然而,更少的数据点具有比平均值大得多或小得多的值。分布中曲线的宽度对应于标准差。在 1.0 std 区间中,整个数据集的 68.3%发生,而在 2.0 std 区间中,则为 95.4%。图 15 显示了从直方图中绘制的正态(高斯)分布和均值、标准差点。
图 15。高斯(正态)分布,图片由作者提供
高斯混合模型组是高斯组合的结果,它揭示了数据集中的统计分布。从高斯模型中创建的标准偏差值导出的方差(对于 1D)或协方差(对于 2D)值在这一点上起着积极的作用。K-means 不考虑方差值,只根据与聚类中心的接近程度进行分布。虽然高斯分布生成关于数据属于哪个聚类的概率比率(这些比率之和=1),但这意味着软聚类;K-Means 聚类偏好硬聚类。还应该注意到,GMM 使用期望最大化算法来拟合形成它的高斯分布。高斯混合模型将在后续文章中详细介绍。
履行
由于在 sklearn 数据集上实现 GMM 非常容易,因此在下面的代码块中,它被应用于图像分割中使用的花朵图像:
图 16。GMM 的图像分割,作者的图像
有必要在实现部分提到一个基本的超参数,协方差 _type。协方差类型可以是:
covariance_type=‘full’
:每个组件都有自己的通用协方差矩阵,这意味着聚类可以是任何形状、大小、方向(默认)
covariance_type=‘tied’
:所有分量共享相同的一般协方差矩阵,这意味着所有聚类具有相同的椭球形状、大小、方向
covariance_type=‘diag’
:每个分量都有自己的对角协方差矩阵,这意味着聚类可以是任何椭球大小。
covariance_type=‘spherical’
:每个组件都有自己的单个方差,这意味着所有簇必须是球形的,但它们可以有不同的直径。
图 17。协方差类型的可视化,来源
如何选择集群的数量?
上面提到轮廓分数或惯性可以用在 k 均值头中。然而,因为高斯混合模型的聚类形状可能不是球形的或者可能具有不同的大小,所以根据特定的度量系统进行选择可能会产生误导。在为 GMM 选择最佳聚类数时,使用贝叶斯信息准则或赤池信息准则更为正确。
AIC 和 BIC 是用于评分和选择最佳模型的概率模型选择技术。
让我们看看上面月亮数据集的 bic&aic 值,并将其可视化:
图 18。AIC 和 BIC-k 的图表,图片由作者提供
可以看出,在 n=2 的情况下,AIC 和 BIC 都是最大值。在代码块的中间部分,还测试了它们针对不同协方差类型的性能,结果如图 19 所示。
图 19。不同协方差类型的比较,按作者分类的图像
可以看出,对于每个 k 值,获得了最佳 BIC 值covariance_type=‘spherical’
。
6.摘要
上面讨论了大多数聚类技术。解释了它们的理论部分,并用 python 实现了它们,并给出了基本示例。图 20 显示了包括聚类技术摘要的图像。
图 20。聚类技术总结,来源
上一篇文章涉及到最有用的降维技术之一,即主成分分析(PCA)。本文涵盖了集群类型及其在 Python 实现中的一些使用领域。
剩余的主题,如离群点检测,期望最大化元算法(EM),自组织映射(SOM),模糊 C 均值等。将在后续文章中讨论。
https://ibrahimkovan.medium.com/machine-learning-guideline-959da5c6f73d
使用 K-Means、Foursquare 和 follow 在大马尼拉聚集村庄并寻找新鲜农产品供应商
原文:https://towardsdatascience.com/clustering-villages-and-finding-fresh-produce-suppliers-in-metro-manila-using-k-means-foursquare-2dc27ea417cf?source=collection_archive---------59-----------------------
疫情期间可能的商机?向富裕的大马尼拉居民运送新鲜农产品。
大 Dodzy 在 Unsplash 上的照片
由于新冠肺炎疫情,菲律宾大马尼拉地区自 2020 年 3 月以来一直处于隔离状态。检疫限制使大多数企业难以运营,但这些也大大增加了对送货服务的需求,因为外出到公共场所不安全。
由于高额的送货费对大多数顾客没有吸引力,一些商家提供免费送货到某些地区,通常是独家经营的村庄,如果他们在那个地区有许多顾客的话。这些企业通常在每个村庄都有一个 Viber 聊天群,那里的居民可以发送订单。
这种配送模式非常适合销售蔬菜、海鲜和肉类等基本易腐商品的企业,因为这些商品经常被相同的客户购买。因此,将这些商品运送到大马尼拉的专属村庄是疫情期间可能的商机之一。
目标市场
本报告的目标读者是那些有兴趣在菲律宾大马尼拉地区开办生鲜农产品配送业务的利益相关者。
商业问题
如果一周送货 6 天,你怎么知道每天送货到哪个村庄以优化物流,以及从哪个市场供应商那里获得新鲜农产品?
1.数据
a. 所需数据
根据问题的定义,以下是影响决策的因素:
- 大马尼拉专属村庄的位置
- 离每个送货组最近的菜市场的名称和等级(因为顾客通常对他们购买的商品质量很挑剔)
b .数据来源
以下数据源将用于提取或生成所需信息:
- 命名 API 地理编码 —用于查找大马尼拉地区每个专属村庄的经度和纬度
- Foursquare API —用于确定专属村庄周围的集市及其等级
- 大马尼拉独家住宅区列表,由向这些村庄送货的全国顶级面包店之一提供,用于确定目标市场将向其送货的独家村庄
- 这里列出的村庄的居民就是目标市场想要吸引的人。
- 这是公开信息,因为该列表可在面包店的在线订单上获得。
2.方法学
a.收集数据
该国一家顶级面包店每周向大马尼拉最高档的村庄运送面包。他们送货到的住宅区包括在他们的在线订单中,因为客户必须选择他们居住的村庄。
我记下了这 45 个区域,并将每个村庄的经度和纬度合并到一个 CSV 文件中,这是我使用 Nominatim API 地理编码得到的。
这是一个我如何得到每个村庄的经度和纬度的例子:
#get latitude and longitude of North Greenhillsaddress = 'North Greenhills, Metro Manila'geolocator = Nominatim(user_agent="gh_agent")
location = geolocator.geocode(address)
latitude = location.latitude
longitude = location.longitude
print(latitude, longitude)
然后,我将这个 CSV 文件上传到笔记本中。CSV 文件中包含的唯一数据是每个村庄的名称、经度和纬度。
b. 导入库和数据
以下是我在这个项目中使用的库:
一、请求:处理请求
二。熊猫:用于数据分析和数据帧制作
三。 Numpy :以矢量化的方式处理数据
四。 Json :将 Json 文件解析成 Python 字典或列表
动词 (verb 的缩写) Json_normalize :将 Json 文件转换成 pandas dataframe 库
不及物动词 Matplotlib :用于绘制地图上的点
七。叶子:用于创建地图
八。名称:用于地理编码不同地区所需的经度和纬度
九。 KMeans :用于创建 k-means 聚类模型来对村庄进行聚类
import requests # library to handle requests
import pandas as pd # library for data analsysis
import numpy as np # library to handle data in a vectorized mannerimport json #library to parse JSON files into a Python dictionary or listimport matplotlib.cm as cm # library for plotting points in the map
import matplotlib.colors as colors #library for plotting points in the mapfrom pandas.io.json import json_normalize # library for tranforming json files into a pandas dataframe library!python3 -m pip install foliumimport folium # library for creating maps
from geopy.geocoders import Nominatim # library for geocoding the longitude and latitude of different areas neededfrom sklearn.cluster import KMeans # library for creating a k-means clustering modelprint('Libraries imported.')
导入这些库之后,我还定义了我的 Foursquare API 凭证,因为 Foursquare API 会请求村庄附近不同集市的名称和等级。
#Foursquare credentials (hidden cell)# [@hidden_cell](http://twitter.com/hidden_cell)CLIENT_ID = '[insert Foursquare ID here]'
CLIENT_SECRET = '[insert Foursquare Secret here]'
ACCESS_TOKEN = '[insert Access Token here]'
VERSION = '20180605' # Foursquare API version
LIMIT = 100 # A default Foursquare API limit value
然后,我将村庄位置数据的 CSV 文件作为熊猫数据帧上传到笔记本上,命名为“df_villages”。
村庄数据的数据框架,称为“df_villages”(图片由作者提供)
c. 可视化村庄位置
我做了一些探索性的数据分析,用 follow 在地图上可视化这些村庄。我在大马尼拉周围制作了一张地图,用蓝点标出了各个村庄。
#get latitude and longitude of Metro Manilaaddress = 'Metro Manila'geolocator = Nominatim(user_agent="mm_agent")
location = geolocator.geocode(address)
latitude = location.latitude
longitude = location.longitude# generate map of villages in Metro Manilavillage_map = folium.Map(location=[latitude, longitude], zoom_start=13)# add the villages as blue circle markers
for Latitude, Longitude, label in zip(df_villages.Latitude, df_villages.Longitude, df_villages.Village):
folium.CircleMarker(
[Latitude, Longitude],
radius=5,
color='blue',
popup=label,
fill = True,
fill_color='blue',
fill_opacity=0.6
).add_to(village_map)# display map
village_map
大马尼拉专属村庄地图,蓝色标记(图片由作者提供)
一眼望去,我看到大多数村庄都位于大马尼拉市中心,而北部和南部有少数离群点。
从这里看,似乎有 4 个可能的村庄群,但由于每周有 6 个工作日用于送货,我想将所有这些村庄分成 6 个群。
**d .**K-均值聚类的村庄
因为交付的货物容易腐烂,很容易变质,只有邻近村庄的居民才能在一天内被送到。
k 均值聚类算法用于根据未标记数据彼此的接近程度对其进行分组;在这种情况下,不同的村庄。
*#get k-means clusters of Metro Manila exclusive villages*
*#6 clusters because one cluster for each working day of the week*
kclusters = 6
kmeans = KMeans(n_clusters=kclusters, random_state=0).fit(df_villages[["Latitude", "Longitude"]])
“kclusters = 6”部分意味着将根据该公式创建 6 个集群。在数据集被分成 6 组之后,一个新的列被添加到聚类标签的数据帧中。
*#add cluster labels to dataframe*
df_villages.insert(0, 'Cluster Labels', kmeans.labels_)*#show first 5 rows of dataframe*df_villages.head()
“df_villages ”,添加了另一个分类标签列(作者图片)
为了可视化聚类,创建了一个名为“cluster_map”的新地图,其中每个聚类标签都被分配了一种特定的颜色,并使用 folium 绘制在地图上。
*#map the clusters*
cluster_map = folium.Map(location=[latitude, longitude], zoom_start=12)
*# set colors for the clusters*
x = np.arange(kclusters)
ys = [i + x + (i*x)**2 **for** i **in** range(kclusters)]
colors_array = cm.rainbow(np.linspace(0, 1, len(ys)))
rainbow = [colors.rgb2hex(i) **for** i **in** colors_array]
centers = kmeans.cluster_centers_
*# put markers*
cluster_markers = []
**for** lat, lon, village, cluster **in** zip(df_villages['Latitude'], df_villages['Longitude'], df_villages['Village'], df_villages['Cluster Labels']):
label = folium.Popup(str(village) + ' Cluster ' + str(cluster), parse_html=**True**)
folium.CircleMarker(
[lat, lon],
radius=5,
popup=label,
color=rainbow[cluster-1],
fill=**True**,
fill_color=rainbow[cluster-1],
fill_opacity=0.7).add_to(cluster_map)
cluster_map
每个村庄群都被赋予了一种新的颜色,以使群体形象化(图片由作者提供)
3.结果和分析
既然明确了哪些村庄将在同一天送达,就必须为每个村庄群分配一个特定的市场,以最大限度地减少货物在送达过程中的行程时间。
重要的是,选择的菜市场要尽可能靠近菜市场,尤其是如果有顾客点海鲜或其他容易变质的产品。
奎松市 Cubao 的农贸市场是大马尼拉地区较为高端的菜市场之一,这些专属村庄的居民经常在这里购买新鲜农产品。
由于这个原因,我不再在集群 0 和集群 4 的区域周围寻找菜市场,因为农贸市场位于这些集群之间。
聚类 0(红点)和 4(绿点),农贸市场 Cubao 位于聚类之间(标签为“Cubao”)(图片由作者提供)
我推荐这是这些集群中村庄的市场供应商,因为 1)它已经有了良好的声誉,2)suki文化意味着市场供应商通常会给持续购买他们摊位的顾客更低的价格。
因为目标市场将为这两个集群的居民从农贸市场的相同摊位购买商品,价格也将被最小化。
我当时只搜索了为第 1、2、3 和 5 组村庄供货的最佳市场。
为集群 1 寻找湿货市场供应商候选人
因为聚类 1 仅包括 2 个村庄(Ayala Alabang 和 Ayala Southvale),所以我选择了一个作为参考,用于查找聚类 1 附近的市场,这将是第一个被交付的村庄。
我获得了 Ayala Alabang 的纬度和经度,并搜索了 Ayala Alabang 附近的“wet markets ”,可以通过 Foursquare API 访问这些市场。
*#get latitude and longitude of Ayala Alabang Village*
address_1 = 'Ayala Alabang, Metro Manila'
geolocator_1 = Nominatim(user_agent="1_agent")
location_1 = geolocator_1.geocode(address_1)
latitude_1 = location_1.latitude
longitude_1 = location_1.longitude*#search wet markets near each selected address*
search_query = 'wet market'
radius = 2000
print(search_query)*#define the url to find wet markets near Cluster 1*
url_1 = 'https://api.foursquare.com/v2/venues/search?client_id=**{}**&client_secret=**{}**&ll=**{}**,**{}**&oauth_token=**{}**&v=**{}**&query=**{}**&radius=**{}**&limit=**{}**'.format(CLIENT_ID, CLIENT_SECRET, latitude_1, longitude_1,ACCESS_TOKEN, VERSION, search_query, radius, LIMIT)*#get the results of wet markets near Cluster 1*
results_1 = requests.get(url_1).json()*# assign relevant part of JSON to venues*
venues_1 = results_1['response']['venues']
*# tranform venues into a dataframe*
df_results_1 = json_normalize(venues_1)
df_results_1
阿亚拉阿拉邦附近集市的结果(图片由作者提供)
既然聚类 1 附近有一个湿市场列表,我清理了数据,以便更容易理解。我将清理后的数据保存为“df_markets_1”
*# keep only columns that include venue name, and anything that is associated with location*
filtered_columns_1 = ['name', 'categories'] + [col **for** col **in** df_results_1.columns **if** col.startswith('location.')] + ['id']
df_markets_1 = df_results_1.loc[:, filtered_columns_1]
*# function that extracts the category of the venue*
**def** get_category_type(row):
**try**:
categories_list = row['categories']
**except**:
categories_list = row['venue.categories']
**if** len(categories_list) == 0:
**return** **None**
**else**:
**return** categories_list[0]['name']
*# filter the category for each row*
df_markets_1['categories'] = df_markets_1.apply(get_category_type, axis=1)
*# clean column names by keeping only last term*
df_markets_1.columns = [column.split('.')[-1] **for** column **in** df_markets_1.columns]
df_markets_1
清理后的数据框架“df_markets_1”(图片由作者提供)
我在这里可以看到,并不是所有的搜索结果实际上都是市场,比如“Filinvest Corporate City”,它被标记为一个社区。但由于这些市场中的大多数都是湿漉漉的,我在地图上显示了这些点,并找出了离 Ayala Alabang 最近的市场。
*# add the wet markets to the map as yellow circle markers*
**for** lat, lng, label **in** zip(df_markets_1.lat, df_markets_1.lng, df_markets_1.name):
folium.CircleMarker(
[lat, lng],
radius=5,
color='yellow',
popup=label,
fill = **True**,
fill_color='yellow',
fill_opacity=0.6
).add_to(cluster_map)
*# display map*
cluster_map
聚类 1 的地图,村庄为紫色点,菜市场为黄色点(图片由作者提供)
根据地图,离阿亚拉阿拉邦最近的市场是大学大道上的周六市场
阿亚拉阿拉邦附近的集市地图(紫色圆点)和“大学大道周六集市”的标记(图片由作者提供)
我检查了大学大道上的周六市场的评级,看看这个市场是否符合潜在客户的标准,即村里的独家居民。
*#check the rating of Saturday Market on University Ave.*
venue_id_SMUA = '4b9c7413f964a520d96936e3' *# Saturday Market on University Ave.*
url_SMUA = 'https://api.foursquare.com/v2/venues/**{}**?client_id=**{}**&client_secret=**{}**&oauth_token=**{}**&v=**{}**'.format(venue_id_SMUA, CLIENT_ID, CLIENT_SECRET,ACCESS_TOKEN, VERSION)
result_SMUA = requests.get(url_SMUA).json()
**try**:
print(result_SMUA['response']['venue']['rating'])
**except**:
print('This venue has not been rated yet.')
(图片由作者提供)
因为这个场地还没有评级,所以我试着去附近的菜市场看看评级。然而,他们都没有评级,所以我试着看看我是否能得到一张场地的照片,并判断它是否看起来有序,产品质量是否良好。
url_SMUA_photo = 'https://api.foursquare.com/v2/photos/**{}**?client_id=**{}**&client_secret=**{}**&oauth_token=**{}**&v=**{}**'.format(venue_id_SMUA, CLIENT_ID, CLIENT_SECRET,ACCESS_TOKEN, VERSION)
result_SMUA_photo = requests.get(url_SMUA_photo).json()
result_SMUA_photo
(图片由作者提供)
Foursquare API 上也没有照片,所以在谷歌上进行了外部图片搜索。照片显示,市场看起来很干净,似乎迎合了合适的顾客(宣传材料是英文的,防水布标志设计得很好,有充足的步行空间)。
因此,我建议目标市场将周六市场供应商作为集群 1 的供应商。
我为集群 2、3 和 5 重复了相同的选择湿市场供应商的过程。
为集群 2 寻找湿货市场供应商候选人
因为聚类 2 只包括 3 个村庄,所以我选择了一个不是中间的村庄作为参考,用于查找聚类 2 附近的市场(Serendra One),这将是第一个被交付的村庄。
在为 Serendra One 附近的湿货市场创建了一个名为“df_markets_2”的新数据框架后,我在“cluster_map”上绘制了这些数据。
聚类 2 的地图,村庄为蓝点,菜市场为黄点(图片由作者提供)
从地图上可以看出,在集群 2 附近有许多市场,因为它就在一个名为“市场!市场!”这可能是使用 Foursquare API 的限制之一,因为即使是商场中的非食品商店也包含在搜索结果中,因为它们的名称中含有“市场”一词。
然而,在检查附近的点时,发现在购物中心市场内还有一个农贸市场!市场!,所以这可能是集群 2 的潜在供应商。
Serendra One(蓝点)附近的湿货市场地图和“市场!市场!农贸市场”(作者图片)
我查了市场的评级!市场!农贸市场,看到没有。我决定看看它是否有来自 Foursquare 用户的提示,来提示它是怎样的。
*## MMFM Tips*
limit_MMFM = 15 *# set limit to be greater than or equal to the total number of tips*
tips_MMFM = 'https://api.foursquare.com/v2/venues/**{}**/tips?client_id=**{}**&client_secret=**{}**&oauth_token=**{}**&v=**{}**&limit=**{}**'.format(venue_id_MMFM, CLIENT_ID, CLIENT_SECRET,ACCESS_TOKEN, VERSION, limit_MMFM)
results_MMFM = requests.get(tips_MMFM).json()
results_MMFM
(图片由作者提供)
Foursquare API 上也没有可用的提示。因为这个菜市场和下一个最近的菜市场(已经离聚类有点远)也没有评级,所以我的决定是推荐市场!市场!农贸市场是第二组的供应商,在谷歌图片中可以找到它的照片。
从照片来看,它看起来像一个干净、有信誉的市场,特别是因为它位于一个受欢迎的购物中心。所以,我会推荐行情!市场!农贸市场作为集群 2 居民的供应商。
接下来,我为集群 3 寻找最佳的湿货市场供应商。
为集群 3 寻找湿货市场供应商候选人
因为聚类 3 只包括 3 个村庄,所以我选择了一个不是中间的村庄作为参考,用于查找聚类 3 附近的市场,这将是第一个被送达的村庄。
群组 3 的地图,淡蓝色圆点代表村庄(图片由作者提供)
我特别挑选了拉维斯塔村作为参考,因为其他两个村庄彼此有点接近,都在一条河的一边,所以从后勤上来说,先送到拉维斯塔更容易。
同样,邻近的菜市场被放置在数据框架“df_markets_3”中,并绘制在“clusters_map”上
群组 3 的地图,村庄为浅蓝色点,菜市场为黄色点(图片由作者提供)
拉维斯塔附近的集市地图(浅蓝色点)和“维亚加公共市场”的标记(图片由作者提供)
根据地图,离 La Vista 最近的市场是 Viaga 公共市场。由于这个地方在 Foursquare 上没有评级、提示或照片,我查看了下一个最近的菜市场,看看他们是否有评级、提示或照片。
不幸的是,他们都不知道。我试着在谷歌图片中搜索维亚加公共市场、图马纳公共市场和塔博安公共市场(离拉维斯塔最近的菜市场)的照片,但同样没有这些市场的图片。
我想在大马尼拉(甚至在菲律宾)还没有太多的场地在 Foursquare API 上有评论、提示和照片。要么这样,要么没有太多的人在这个地区的菜市场上查看和留下提示。
在这种情况下,我将让本报告的用户自己探索建议的菜市场,并判断这些菜市场是否适合他们的客户。
最后,我对集群 5 重复了这个过程。
为集群 5 寻找湿货市场供应商候选人
因为 Urdaneta 村通常位于聚类 5 的中心,所以我使用它作为搜索离聚类最近的市场列表的参考。这是聚类 5 附近的集市地图:
聚类 5 的地图,村庄为橙色点,菜市场为黄色点(图片由作者提供)
查看聚类 5 的地图,我注意到许多标绘的点实际上不是集市,因为有些是夜市或超市。如果市场供应商靠近集群边界的至少一个村庄,例如位于集群右上角的 Rockwell Makati,这可能是最好的。
这是为了使得湿货市场供应商可以靠近该组的交付路线的“入口点”。罗克韦尔马卡蒂附近最近的点是高端超市“Rustans Market by”和高端美食街“Grid Food Market”。
由于这两个市场都不是真正的新鲜农产品市场,我推荐 Poblacion Public Market 作为该集群的市场供应商,因为它是离 Rockwell Makati 最近的点。
罗克韦尔马卡蒂附近的湿货市场地图(橙色圆点)和“Poblacion 公共市场”标记(图片由作者提供)
同样,由于这个地点没有评级,提示,或可用的照片,我再次基于谷歌图片这个市场的质量。
我在谷歌上只看到了一张市场的图片,它的内部与 Cubao 农贸市场相似,所以我认为这个市场的产品质量应该也差不多。因此,我推荐 Poblacion Public Market 作为集群 5 的湿货市场供应商。
4.结论
由M . Ashraful Alam在 Unsplash 上拍摄的照片
大马尼拉地区的 45 个专属村庄根据彼此的接近程度被分成 6 个交付组(第 0-5 组)。
使用 Foursquare API 和一些额外的人类知识(如了解农贸市场 Cubao 在目标客户中的声誉),我能够确定一些推荐的市场,目标市场可以在这些市场购买供应品,这些供应品将出售给这些独家村庄的居民。这些湿货市场是:
1。 集群 0 *(西格林希尔斯,瓦克瓦克村等。)——*农贸市场
2。 集群 1 *(Ayala Alabang,Ayala south vale)——*大学大道上的周六市场
3。 集群 2 *(塞伦德拉一、塞伦德拉二、麦金利山)——*市场!市场!农贸市场
4。 集群 3 *(La Vista、Loyola Grand Villas 和 Ayala Heights)——*Viaga 公共市场、Tumana 公共市场或 Taboan 公共市场
5。 集群 4 (科林斯园林,Valle Verde 1 等。)— 农贸市场存保
6。 集群 5 (达斯马里纳斯村、福布斯公园等。)— 公共市场
通过这个项目,我还得出结论,尽管这种数据和技术可用于帮助商业决策,但大部分分析仍然依赖于人类的经验和直觉。
例如,来自 Foursquare 的数据可以向我们显示,基于其与生成的集群的接近程度,标记为湿市场的某些场所将是最实际的供应商选择,但这并不能说明一个商人通过选择允许他为批量订单讨价还价的供应商可以节省的成本。
归根结底,技术是一种让决策变得更容易的工具,但只有将其与现实世界的人类知识相结合,它才能得到优化。
这份报告是我的 IBM 数据科学专业证书 的顶点工程的一部分。你可以在我的 笔记本 上查看完整代码。
关于如何改进这一点,有什么建议吗?在下面留下评论或者和我连线LinkedIn!非常感谢反馈。
CNN:计算机真的能看见吗?
原文:https://towardsdatascience.com/cnn-can-a-computer-really-see-96f237dcf171?source=collection_archive---------50-----------------------
卷积神经网络讲解!
卷积神经网络(CNN 或 ConvNet)是一类深度学习,受人类视觉系统的启发,专门从图像、文本和音频等复杂输入中提取高级特征。
在 Unsplash 上 NeONBRAND 拍摄的照片
事实上,与手工设计特征的经典神经网络不同,CNN 获取输入的原始数据,自动区分有意义的模式,并基于这些特征而不是原始像素进行学习。这就是为什么 CNN 是图像分析中经常使用的神经网络[1]。
但是计算机如何分析图像呢?
基本上,卷积神经网络主要包括:
- 输入图层
- 卷积层
- 激活功能层
- 汇集层
- 展平全连通图层
我们先从 CNN 的输入层开始,来了解计算机是如何看到一个图像的。
输入层:
图像通常表示为像素值的三维(3D)矩阵:
- 高度和宽度取决于输入图像的尺寸。
- 深度一般是三通道 RGB(红绿蓝)对于每个像素的颜色值。
*作者的图像:*图像表示的示例
卷积层:
卷积运算是 Y. Bengio 和 Yann Lecun 发明的 CNN 的基本组成部分[2],它包括对输入图像应用滤波器以检测与每一类相关的特征。
*图片作者:*9 像素的红色通道图片
滤波器(固定大小)由随机初始化的权重组成,这些权重将通过每个输入的反向传播来更新。
滤镜以步长(卷积中跳过的像素数)垂直和水平滑动图像,将图像的“像素”值乘以滤镜的值。然后,将所有这些乘法相加得到一个数,该数构成特征图的一个像素。
*图片作者:*水平滑动操作
*图片作者:*垂直滑动操作
在卷积过程结束时,所获得的特征图表示包含输入图像的检测模式的较小矩阵。
显然,我们对图像应用的过滤器越多,提取的特征就越多,网络在检测图像模式方面就变得越好。
最后,卷积层由相同大小的多个滤波器组成,这些滤波器从图像的 3D 通道表示的输入输出各种特征图。下图对此进行了总结:
作者图片:步长=1、滤波器大小=33 的 99 像素输入图像的卷积层
ReLU 的非线性:
考虑到真实世界数据的非线性,我们必须在每个卷积层之后引入一层激活函数,因为卷积是线性运算(乘法和加法)。
事实上,通过增加网络的非线性,我们创建了一个复杂的网络,使我们能够检测和区分输入图像的许多模式。
该任务最常用的激活函数是 ReLU 16。数学上,它被定义为:
作者图片
由于它的数学特性,它是一种元素式操作(在我们的例子中应用于每个像素),在特征图中用零替换负像素的值。
池层:
类似于卷积层,池层用于独立地进一步降低先前矩阵的维度(维度降低),以显著降低数据处理所需的参数数量和计算能力。
此外,该操作从输入中提取主导特征,同时保持有效训练模型的过程,因为网络对于输入图像的小变换和平移变得不变。
作者图片:使用最大池化方法,使用步长 2 和大小 33 的过滤器,对 77 像素的输入图像进行池化图层
可以通过多种方法完成汇集:最大汇集、最小汇集、平均汇集和平均汇集。最常用的方法是最大池化。
展平和完全连接的层:
卷积层和池层的组合从输入图像中提取主要特征到一个数量的矩阵,然后 flatten 将其转换为一个一维数组,创建一个适合于全连接层的输入的单一长特征向量。
全连接层完成分类的任务,它代表一个多层感知器,主要具有 softmax 激活功能。然后,网络将能够学习高级特征的非线性组合,并区分每个图像规格。
*作者图片:*展平并完全连接的图层示例
总而言之,CNN 架构执行两个主要任务:
- 特征提取:卷积层+池层
- 分类:全连接层
这张图片展示了 CNN 的完整架构:
*图片作者:CNN 架构概要以 99 像素输入为例
一般来说,卷积层数越多,模型能够识别的特征就越多。
参考资料:
[1] Maria Valueva,Nikolay Nagornov,Pavel Lyakhov,G.V. Valuev,和 N.I.Chervyakov .应用剩余数系统减少卷积神经网络实现的硬件成本数学和计算机模拟,177,05 2020。
[2] Y .本吉奥和扬·勒昆。图像、语音和时间序列的卷积网络。11 1997.
[3]田畑秀则·伊德。还有栗田泷雄。稀疏正则化对 relu 激活的 cnn 学习的改进。IEEE,2017 年 07 月。
基于 CNN-LSTM 的多并行输入多步预报模型
原文:https://towardsdatascience.com/cnn-lstm-based-models-for-multiple-parallel-input-and-multi-step-forecast-6fe2172f7668?source=collection_archive---------1-----------------------
针对多个时间序列和多步预测用例的不同神经网络方法,以及多步预测的真实实践
时间序列预测是机器学习的一个非常热门的领域。这背后的原因是时间序列在日常生活中几乎每个领域的广泛使用。深入时间序列预测的细节,我们会遇到许多不同种类的子领域和方法。在本文中,我将关注通过接收多个并行时间序列来执行多步预测的特定子域,并提及在时间序列预测中应考虑的基本要点。请注意,预测模型在不同点上与预测模型不同。
法鲁克·凯马克在 Unsplash 上拍摄的照片
-问题定义
让我们想象一下,大量网络设备分布在广阔的地理区域内,流量不断地流经这些设备。另一个例子可能是关于连续测量不同位置的天气温度的许多不同温度设备,或者另一个例子可能是计算系统中许多设备的能量消耗。我们可以很容易地扩展这些例子。目标很简单;预测接下来的多个时间步;在我们的例子中,这对应于分别预测流量值、温度或许多设备的能耗。
首先想到的当然是分别对每个器件建模。我想我们可能会得到最高的预测结果。如果有超过 100 种甚至更多的不同设备呢?这意味着设计 100 种不同的模型。考虑到部署、监控和维护成本,它并不太适用。因此,我们的目标是用一个单一的模型来涵盖整个问题。我认为它仍然是时间序列预测的一个非常受欢迎和搜索的领域,尽管时间序列预测已经摆在桌面上很久了。我在这个领域遇到了很多不同的学术研究。
这个问题也可以定义为 seq2seq 预测。特别是在语音识别和翻译中,这是非常常见的情况。 LSTM 对于这类问题非常方便。 CNN 也可以认为是另一种类型的神经网络,常用于图像处理任务。通常,它也用于特征提取和时间序列预测。我将提到 LSTM 和 CNN 在多个并行输入和多步预测情况下对时间序列预测的应用。对 LSTM 和 CNN 的解释超出了本文的范围。
为了更清楚,我在下面描绘了一个简单的数据示例。这是一个通过查看前 3 个小时的时隙来预测未来 2 个小时 3 个不同设备的流量值的示例。
作者图片—图 1
-数据集描述
在本文中,我将利用由 15 分钟时间间隔内 288 台不同服务器的 CPU 使用情况组成的数据集。为简单起见,我将把范围缩小到 3 台服务器。
数据集示例,按作者分类的图像—图 2
-预建模步骤
预建模在神经网络实现中非常关键。你通常不能简单地直接向神经网络提供原始数据,需要一个简单的转换。然而,在转换之前,我们应该对原始数据应用一些额外的步骤。
在我们的例子中,下面是旋转原始数据。
df_cpu_pivot = pd.pivot_table(df, values=’CPUUSED’,
index=[‘DATETIME’], columns=[‘ID’])
以下是对数据集中缺失值的插值。在时间序列中输入空值本身是非常重要的,也是一项具有挑战性的任务。这个数据集中没有很多空值,输入空值超出了本文的范围,因此我执行了一个简单的实现。
for i in range(0, len(df_cpu_pivot.columns)):
df_cpu_pivot.iloc[:,i].interpolate(inplace = True)
在进入建模阶段之前的第一件事,在时间序列预测的数据预处理步骤的最开始,在我看来是绘制时间序列。让我们看看数据告诉了我们什么。正如我之前提到的,为了简单起见,我只选择了 3 个不同的服务器。可以看出,它们在不同的尺度上都遵循非常相似的模式。
import plotly
import plotly.express as px
import plotly.graph_objects as godf_cpu_pivot.reset_index(inplace=True)
df_cpu_pivot['DATETIME'] = pd.to_datetime(df_cpu_pivot['DATETIME'])trace1 = go.Scatter(
x = df_cpu_pivot[‘DATETIME’],
y = df_cpu_pivot[‘HSSFE-hssahlk01CPU-0’],
mode = ‘lines’,
name = ‘cpu_1’
)
trace2 = go.Scatter(
x = df_cpu_pivot[‘DATETIME’],
y = df_cpu_pivot[‘HSSFE-hssumrk03CPU-29’],
mode = ‘lines’,
name = ‘cpu_2’
)
trace3 = go.Scatter(
x = df_cpu_pivot[‘DATETIME’],
y = df_cpu_pivot[‘HSSFE-hssumrk03CPU-4’],
mode = ‘lines’,
name = ‘cpu_3’
)layout = go.Layout(
title = “CPU Usage”,
xaxis = {‘title’ : “Date”},
yaxis = {‘title’ : “Cpu Usage”}
)
fig = go.Figure(data=[trace1, trace2, trace3], layout=layout)
fig.show()
Cpu 使用情况—图 3
下一步是将数据集分成训练集和测试集。它在时间序列上与传统的机器学习实现略有不同。我们可以直观地确定分离数据集的拆分日期。
from datetime import datetime
train_test_split = datetime.strptime(‘20.04.2020 00:00:00’, ‘%d.%m.%Y %H:%M:%S’)
df_train = df_cpu_pivot.loc[df_cpu_pivot[‘DATETIME’] < train_test_split]
df_test = df_cpu_pivot.loc[df_cpu_pivot[‘DATETIME’] >= train_test_split]
由于其敏感性,我们还在将数据输入任何神经网络模型之前对其进行归一化。
from sklearn.preprocessing import MinMaxScaler
cpu_list = [i for i in df_cpu_pivot.columns if i != ‘DATETIME’]
scaler = MinMaxScaler()
scaled_train = scaler.fit_transform(df_train[cpu_list])
scaled_test = scaler.transform(df_test[cpu_list])
最后一步是将训练集和测试集转换成神经网络可接受的格式。可以实现以下方法来转换数据。除了序列本身,它只需要两个参数,分别是时滞(回顾的步骤)和预测范围。还可以看看 Keras 中定义的 TimeSeriesGenerator 类来转换数据集。
def split_sequence(sequence, look_back, forecast_horizon):
X, y = list(), list()
for i in range(len(sequence)):
lag_end = i + look_back
forecast_end = lag_end + forecast_horizon
if forecast_end > len(sequence):
break
seq_x, seq_y = sequence[i:lag_end], sequence[lag_end:forecast_end]
X.append(seq_x)
y.append(seq_y)
return np.array(X), np.array(y)
LSTM 模型期望数据具有以下形状:*【样本,时间步长,特征】。*同样,CNN 也期望 3D 数据为 LSTMs。
# Take into consideration last 6 hours, and perform forecasting for next 1 hour
LOOK_BACK = 24
FORECAST_RANGE = 4
n_features = len(cpu_list)X_train, y_train = split_sequence(scaled_train, look_back=LOOK_BACK, forecast_horizon=FORECAST_RANGE)
X_test, y_test = split_sequence(scaled_test, look_back=LOOK_BACK, forecast_horizon=FORECAST_RANGE)print(X_train.shape)
print(y_train.shape)
print(X_test.shape)
print(y_test.shape)(4869, 24, 3)
(4869, 4, 3)
(1029, 24, 3)
(1029, 4, 3)
补充说明
我还想提一下时间序列预测的额外预建模步骤。这些不是本文的直接范围,但值得了解。
平稳对于时间序列来说是一个非常重要的问题,大多数预测算法如 ARIMA 都期望时间序列是平稳的。平稳时间序列基本上在一段时间内保持非常相似的均值、方差值,不包括季节性和趋势。要使时间序列平稳,最直接的方法是取序列中后续值的差。如果方差与均值相比波动很大,取序列的对数使其平稳也是一个好主意。与大多数其他预测算法不同,LSTMs 能够学习序列中的非线性和长期相关性。因此,静态是 LSTMs 不太关心的问题。尽管如此,让时间序列保持平稳并稍微提高 LSTMs 的性能是一个很好的实践。静态测试有很多,最著名的是 增强的 Dicky-Fuller 测试 ,在 python 中有现成的实现。
这里有一篇很优秀的文章,简单的设计了一个模型来预测一个随机游走过程产生的时间序列,评价准确率非常高。事实上,预测随机行走过程是不可能的。但是,如果您直接使用原始数据而不是静态差异数据,可能会出现这种误导性的推断。
关于时间序列要提到的另一件事是绘制 ACF 和PACF图,并研究时间序列相对于不同历史滞后值的相关性。这肯定会让你深入了解你正在处理的时间序列。
-基线模型
拥有一个基线模型来衡量你的模型的相对性能总是一个好主意。基线模型应该简单、快速且可重复。建立基线模型最常用的方法是持久性模型。它有一个非常简单的工作原理,只是预测下一个时间步为前一步,换句话说 t+1 与 t 相同。对于多步预测,可能将预测 t+1,t+2,t+3 修改为 t ,整个预测范围将是相同的。在我看来,那不太合理。相反,我更喜欢将预测范围内的每个时间步长预测为相同设备之前相同时间的平均值。下面是一个简单的代码片段。
df[‘DATETIME’] = pd.to_datetime(df[‘DATETIME’])
df[‘hour’] = df[‘DATETIME’].apply(lambda x: x.hour)
df[‘minute’] = df[‘DATETIME’].apply(lambda x: x.minute)train_test_split = datetime.strptime(‘20.04.2020 00:00:00’, ‘%d.%m.%Y %H:%M:%S’)
df_train_pers = df.loc[df[‘DATETIME’] < train_test_split]
df_test_pers = df.loc[df[‘DATETIME’] >= train_test_split]df_cpu_mean = df_train_pers.groupby([‘ID’, ‘hour’, ‘minute’]).mean(‘CPUUSED’).round(2)df_cpu_mean.reset_index(inplace=True)
df_cpu_mean = df_cpu_mean.rename(columns={“CPUUSED”: “CPUUSED_PRED”})df_test_pers = df_test_pers.merge(df_cpu_mean, on=[‘ID’,’hour’, ‘minute’], how=’inner’)# the method explanation is at the next section
evaluate_forecast(df_test_pers[‘CPUUSED’], df_test_pers[‘CPUUSED_PRED’])mae: 355.13
mse: 370617.18
mape: 16.56
可以看出,我们的基线模型预测误差约为 16.56%。我将在模型部分的评估中详细介绍评估指标。让我们看看我们是否能超过这个结果。
-不同的模型示例
我将提到用于*多个并行输入和多步预测的不同的基于神经网络的模型。*在描述模型之前,让我分享一些常见的东西和代码片段,比如 Keras 回调、应用逆变换以及评估结果。
编译模型时使用的回调如下。model check point是以一定的频率保存模型(权重)。 提前停止 用于在监控的评估指标不再提高时停止进度。ReduceLROnPlateau用于在监控指标停止改善时降低学习率。
checkpoint_filepath = ‘path_to_checkpoint_filepath’
checkpoint_callback = ModelCheckpoint(
filepath=checkpoint_filepath,
save_weights_only=False,
monitor=’val_loss’,
mode=’min’,
save_best_only=True)early_stopping_callback = EarlyStopping(
monitor=”val_loss”,
min_delta=0.005,
patience=10,
mode=”min”
)rlrop_callback = ReduceLROnPlateau(monitor=’val_loss’, factor=0.2, mode=’min’, patience=3, min_lr=0.001)
由于我们在将数据输入模型之前对其进行了规范化,因此我们应该将其转换回原始比例以评估预测。我们可以简单地利用下面的方法。在对数据进行差分以使其稳定的情况下,您应该首先反转缩放,然后依次反转差分。预测的顺序与此相反,即首先应用差异,然后归一化数据。为了反演差异数据,简单的方法是将差异预测累加到最后的累积观测值上。
def inverse_transform(y_test, yhat):
y_test_reshaped = y_test.reshape(-1, y_test.shape[-1])
yhat_reshaped = yhat.reshape(-1, yhat.shape[-1]) yhat_inverse = scaler.inverse_transform(yhat_reshaped)
y_test_inverse = scaler.inverse_transform(y_test_reshaped)
return yhat_inverse, y_test_inverse
为了评估预测,我简单地分别考虑了均方误差(mse)、平均绝对误差(mae)、和平均绝对百分比误差(mape) 。您可以扩展评估指标。注意,均方根误差(rmse)和 mae 给出的误差与变量本身的单位相同,并被广泛使用。在本文中,我将根据 mape 来比较这些模型。
def evaluate_forecast(y_test_inverse, yhat_inverse):
mse_ = tf.keras.losses.MeanSquaredError()
mae_ = tf.keras.losses.MeanAbsoluteError()
mape_ = tf.keras.losses.MeanAbsolutePercentageError() mae = mae_(y_test_inverse,yhat_inverse)
print('mae:', mae)
mse = mse_(y_test_inverse,yhat_inverse)
print('mse:', mse)
mape = mape_(y_test_inverse,yhat_inverse)
print('mape:', mape)
常见的导入包如下。
from tensorflow.keras import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout, TimeDistributed, Conv1D, MaxPooling1D, Flatten, Bidirectional, Input, Flatten, Activation, Reshape, RepeatVector, Concatenate
from tensorflow.keras.models import Modelfrom tensorflow.keras.utils import plot_modelfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint
在这一步,我认为在 Keras 中提及 时间分布 和 重复向量 层是有益的。这些不是经常使用的层,但是,它们在一些特定的情况下可能非常有用,比如我们的例子。
简而言之, TimeDistributed 层是一种包装器,并期望另一层作为参数。它将该层应用于输入的每个时间片,因此允许构建具有一对多、多对多架构的模型。类似地,它期望输入至少是三维的。我知道这对于初学者来说不是很清楚,你可以在这里找到有用的讨论。
重复矢量基本上重复输入 n 次。换句话说,它将输出形状的维度增加了 1。重复向量 在这里有很好的解释和图解,看看吧。
epochs = 50
batch_size = 32
validation = 0.1
以上是为编译模型而定义的。
编解码器型号
model_enc_dec = Sequential()
model_enc_dec.add(LSTM(100, activation=’relu’, input_shape=(LOOK_BACK, n_features)))
model_enc_dec.add(RepeatVector(FORECAST_RANGE))
model_enc_dec.add(LSTM(100, activation=’relu’, return_sequences=True))
model_enc_dec.add(TimeDistributed(Dense(n_features)))
model_enc_dec.compile(optimizer=’adam’, loss=’mse’)plot_model(model=model_enc_dec, show_shapes=True)history = model_enc_dec.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=validation,callbacks=[early_stopping_callback, checkpoint_callback, rlrop_callback])yhat = model_enc_dec.predict(X_test, verbose=0)yhat_inverse, y_test_inverse = inverse_transform(y_test, yhat)evaluate_forecast(y_test_inverse, yhat_inverse)mae: 145.95
mse: 49972.53
mape: 7.40
编码器-解码器模型—图 4
编码器-解码器架构是序列到序列学习的典型解决方案。该架构包含至少两个 RNN/lstm,其中一个用作编码器,而另一个用作解码器。编码器主要负责读取和解释输入。编码器部分将输入压缩成原始输入的小型表示(固定长度的向量),并将该上下文向量作为输入提供给解码器部分进行解释和执行预测。一个 RepeatVector 层用于重复我们从编码器部分获得的上下文向量。它会根据您想要预测的未来步骤数进行重复,并输入到解码器部分。就每个时间步长而言,从解码器接收的输出被混合。一个完全连接的密集层通过时间分布包装器被应用于每个时间步长,从而分离每个时间步长的输出。在每个编码器和解码器中,可以使用不同种类的架构。下一部分给出了一个例子,其中 CNN 被用作编码器中的特征提取器。
CNN-LSTM 编解码器型号
以下模型是编码器-解码器架构的扩展,其中编码器部分由 Conv1D 层组成,与之前的模型不同。首先在开头放置两个后续的 Conv1D 层提取特征,然后在汇集 *Conv1D 的结果后将其展平。*架构的其余部分与之前的模型非常相似。
为了简单起见,我只是不分享绘图,模型的拟合,测试集的预测,以及逆向转换步骤,这些将与模型的其余部分完全相同。
model_enc_dec_cnn = Sequential()
model_enc_dec_cnn.add(Conv1D(filters=64, kernel_size=9, activation=’relu’, input_shape=(LOOK_BACK, n_features)))
model_enc_dec_cnn.add(Conv1D(filters=64, kernel_size=11, activation=’relu’))
model_enc_dec_cnn.add(MaxPooling1D(pool_size=2))
model_enc_dec_cnn.add(Flatten())
model_enc_dec_cnn.add(RepeatVector(FORECAST_RANGE))
model_enc_dec_cnn.add(LSTM(200, activation=’relu’, return_sequences=True))
model_enc_dec_cnn.add(TimeDistributed(Dense(100, activation=’relu’)))
model_enc_dec_cnn.add(TimeDistributed(Dense(n_features)))
model_enc_dec_cnn.compile(loss=’mse’, optimizer=’adam’)mae: 131.89
mse: 50962.38
mape: 7.01
CNN 编码器-解码器模型—图 5
矢量输出模式
与上面提到的模型相比,这种架构可能被认为是更常见的架构,但是,它不太适合我们的情况。不过,我分享一个例子来说明一下。与编码器-解码器架构不同,既不存在重复向量也不存在时间分布层。重点是用 FORECAST_RANGE*n_features 节点添加一个 Dense 图层,然后在下一层做相应的整形。你也可以用 RepeatVector 层代替 Reshape 层来设计一个类似的架构。
在这种结构中,每个序列的时间步长将被展平,并且在训练和预测期间,必须将每个输出解释为特定序列的特定时间步长。这意味着我们也可以将标注集调整为二维而不是三维,并相应地解释输出图层中的结果,而无需使用调整图层。为了简单起见,我没有改变标签集的形状,只是记住这种替代方式。在架构的开始,我还利用了 Conv1D 层。
这种结构也可以称为多通道模型。不要高估名字。在处理多个时间序列时,传统上使用多通道的细胞神经网络。在这种结构中,每个通道对应于单个时间序列,并且类似地为每个时间序列分别提取卷积特征。由于所有提取的特征在输入到 LSTM 图层之前会被合并,因此每个时间序列的一些典型特征可能会丢失。
input_layer = Input(shape=(LOOK_BACK, n_features))
conv = Conv1D(filters=4, kernel_size=7, activation=’relu’)(input_layer)
conv = Conv1D(filters=6, kernel_size=11, activation=’relu’)(conv)lstm = LSTM(100, return_sequences=True, activation=’relu’)(conv)
dropout = Dropout(0.2)(lstm)
lstm = LSTM(100, activation=’relu’)(dropout)
dense = Dense(FORECAST_RANGE*n_features, activation=’relu’)(lstm)
output_layer = Reshape((FORECAST_RANGE,n_features))(dense)model_vector_output = Model([input_layer], [output_layer])
model_vector_output.compile(optimizer=’adam’, loss=’mse’)mae: 185.95
mse: 92596.76
mape: 9.49
CNN 的矢量输出模型—图 6
多头 CNN-LSTM 模型
这个架构和上面提到的型号有点不一样。在对卡尼佐的研究中已经解释得很清楚了。多头结构使用多个一维 CNN 层来处理每个时间序列,并从每个时间序列中提取独立的卷积特征。这些独立的 CNN 被称为“头”,在馈入 LSTM 层之前分别被展平、连接和整形。总之,多头结构利用多个 CNN,而不是像多通道结构那样只有一个 CNN。因此,他们可能更成功地保留每个时间序列的重要特征,并在这个意义上做出更好的预测。
input_layer = Input(shape=(LOOK_BACK, n_features))
head_list = []
for i in range(0, n_features):
conv_layer_head = Conv1D(filters=4, kernel_size=7, activation=’relu’)(input_layer)
conv_layer_head_2 = Conv1D(filters=6, kernel_size=11, activation=’relu’)(conv_layer_head)
conv_layer_flatten = Flatten()(conv_layer_head_2)
head_list.append(conv_layer_flatten)
concat_cnn = Concatenate(axis=1)(head_list)
reshape = Reshape((head_list[0].shape[1], n_features))(concat_cnn)lstm = LSTM(100, activation=’relu’)(reshape)
repeat = RepeatVector(FORECAST_RANGE)(lstm)
lstm_2 = LSTM(100, activation=’relu’, return_sequences=True)(repeat)
dropout = Dropout(0.2)(lstm_2)
dense = Dense(n_features, activation=’linear’)(dropout)multi_head_cnn_lstm_model = Model(inputs=input_layer, outputs=dense)mae: 149.88
mse: 65214.09
mape: 8.03
多头 CNN-LSTM —图 7
-模型评估
评估基本上与任何预测建模方法相同,模型的一般性能可以用我在前面部分分享的 evaluate_forecast 方法来计算。然而,在我们的案例中有 2 个不同的点,把它们考虑进去也是有益的。第一,我们正在执行多步预测,因此我们可能希望分别分析每个时间步的预测准确性。这将有助于选择准确的预测范围。第二,我们正在对多个平行的时间序列进行预测。因此,观察每个时间序列预测的结果也是有益的。对于特定的时间序列,该模型的效果可能比其他时间序列差得多。
您可以简单地利用不同种类的评估指标,我更喜欢本文中的平均绝对百分比误差 ( mape) 来处理不同的时间序列尺度。
考虑到模型的随机性,的良好做法是多次评估给定的模型,并报告测试数据集的平均性能。为了简单起见,在本文中我只运行它们一次。
关于每个时间步的输出,我只分享一个简单的代码片段和图表,它代表了每个时间步的预测的 mape 值。不出所料, mape 随着预测范围的增加而增加。该图代表多头 CNN-LSTM 架构,并且可以直接应用于我上面提到的其他架构。如果您观察到 mape 急剧增加,您可能会减少您的预测范围,并将其设置为急剧增加之前的点。
y_test_inverse_time_step = y_test_inverse.reshape(int(y_test_inverse.shape[0]/FORECAST_RANGE), FORECAST_RANGE, y_test_inverse.shape[-1])yhat_inverse_time_step = yhat_inverse.reshape(int(yhat_inverse.shape[0]/FORECAST_RANGE), FORECAST_RANGE, yhat_inverse.shape[-1])# yhat_inverse_time_step and y_test_inverse_time_step are both same dimension.
time_step_list_yhat = [[] for i in range(FORECAST_RANGE)]
time_step_list_y_test = [[] for i in range(FORECAST_RANGE)]for i in range(0, yhat_inverse_time_step.shape[0]):
for j in range(0, yhat_inverse_time_step.shape[1]):
time_step_list_yhat[j].append(list(yhat_inverse_time_step[i][j]))
time_step_list_y_test[j].append(list(y_test_inverse_time_step[i][j]))yhat_time_step = np.array(time_step_list_yhat)
yhat_time_step = yhat_time_step.reshape(yhat_time_step.shape[0], -1)
y_test_time_step = np.array(time_step_list_y_test)
y_test_time_step = y_test_time_step.reshape(y_test_time_step.shape[0], -1)# plotting
mape_list = []
for i in range(0, FORECAST_RANGE):
mape = mape_(y_test_time_step[i], yhat_time_step[i])
mape_list.append(mape)plt.plot(range(0, FORECAST_RANGE), mape_list, marker=’o’)
plt.xticks((range(0, FORECAST_RANGE)))
plt.xlabel(‘Forecast Range’)
plt.ylabel(‘MAPE’)
预测范围与 MAPE —图 8
以下代码片段可用于分析不同输入时间序列的模型性能。与基线模型的整体结果相比,该模型对所有 CPU 的预测性能都更好。尽管第二个 CPU 的 mae 与其他 CPU 相比明显较低,但其 mape 明显高于其他 CPU。事实上,这也是我在本文中使用 mape 作为评估标准的原因之一。每个 CPU 使用率值的行为类似,但规模完全不同。老实说,这是我观点的一个很好的例子。为什么第二个 CPU 的错误率这么高?这种情况下我该怎么办?将整个时间序列分成子部分,并为每个子部分开发单独的模型可能是一种选择。还有什么?我真的很感激在评论中读到任何有价值的方法。
尽管对于我们的情况来说,绘制每个时间序列的性能直方图没有太大的意义,但是对于包含更多并行时间序列的数据集来说,绘制直方图还是很有意义的。
for i in range(0, n_features):
print(‘->‘, i)
mae = mae_(y_test_inverse[:,i],yhat_inverse[:,i])
print('mae:', mae)
mse = mse_(y_test_inverse[:,i],yhat_inverse[:,i])
print('mse:', mse)
mape = mape_(y_test_inverse[:,i],yhat_inverse[:,i])
print('mape:', mape)-> 0
mae: 126.53
mse: 32139.92
mape: 5.44
-> 1
mae: 42.03
mse: 3149.85
mape: 13.18
-> 2
mae: 281.08
mse: 160352.55
mape: 5.46
-最后的话
在结束这篇文章之前,我想谈谈现实生活中时间序列预测的几个重要问题。首先,机器学习中用于模型评估的传统方法在时间序列预测中大多不成立。这是因为它们没有考虑时间序列的时间依赖性。
这里提到了 3 种不同的方法。最直接的方法是确定一个分割点,将数据集分成训练集和测试集,而不像本文中所做的那样进行洗牌。然而,在现实生活中,它并不能提供对模型性能的可靠洞察。
另一种是多次重复相同的策略,即多次列车测试拆分。在这种方法中,您可以创建多个训练集和测试集以及多个模型。您应该考虑保持测试集大小不变,以便正确地比较模型的性能。您也可以通过只考虑最新数据的固定长度来保持训练集的大小不变。请注意, sklearn 中有一个名为 TimeSeriesSplit 的包来执行这种方法。
最后一个最可靠的方法是向前行走验证,这是时间序列世界的 k 倍交叉验证。在这种方法中,通过将新的已知值包括到训练集中,在每次预测之后创建新的模型。它通过滑动窗口方法不断重复,并考虑最小数量的观察值来训练模型。这是最稳健的方法,但显然有成本。为特别大量的数据创建许多模型可能很麻烦。
除了传统的 ML 方法,时间序列预测模型应该更频繁地更新,以捕捉变化的趋势行为。然而,在我看来,无论何时你想要生成一个新的预测,模型都不需要重新训练,如这里所说的。如果时间序列不以非常频繁和剧烈的方式变化,这将是非常昂贵和不必要的。我完全同意上面的文章,准确定义预测的置信区间与预测本身一样重要,在考虑异常检测用例的现实场景中甚至更重要。它值得成为另一篇文章的主题。
最后但并非最不重要的是,在生产中运行多步预测模型与传统的机器学习方法截然不同。有几个选项,最常见的是递归和直接策略。在 递归策略 中,在每一个预测步骤中,模型被用来预测前一步,然后从预测中获得的值被馈入同一个模型来预测下一步。每个预测都使用相同的模型。但是,在这种策略下,预测误差会如您所料沿着预测范围传播。这可能是一种负担,尤其是对于长期预测来说。另一方面,在直接策略中,为每个预测范围设计了单独的模型。很明显,随着预测范围的不断扩大,它将不堪重负,这意味着模型数量的不断增加。此外,它没有考虑预测之间的统计相关性,因为每个模型都是相互独立的。作为另一个策略,你也可以设计一个模型,像我们在本文中所做的那样,能够一次执行多步预测。
在本文中,我将重点关注时间序列预测的一个非常具体的用例,但同时也是现实生活场景中的一个常见用例。此外,我提到了在实现预测模型时应该考虑的几个一般要点。
当您遇到多个时间序列,并且应该对每个时间序列执行多步预测时,首先尝试创建单独的模型以获得最佳结果。然而,时间序列的数量在现实生活中可能会非常多,在这种情况下,您也应该考虑使用上面提到的单一模型架构。您也可以利用不同种类的层,如遵循架构的双向、 ConvLSTM ,并通过调整参数获得更好的结果。我提到的用例大多由相同的单位时间序列组成,如流经每个设备的流量值或分布在一个大区域的不同设备的温度值。观察不同时间序列的结果也会很有趣。例如,一次性预测温度、湿度和压力的单一模型方法。我相信这仍然是一个开放的研究领域,因为在这个领域有很多不同的学术研究。从这个意义上说,我很高兴在评论中听到不同的方法。
有用的链接
https://www.sciencedirect.com/science/article/abs/pii/S0925231219309877 https://link.springer.com/chapter/10.1007/978-981-15-3357-0_14 https://ieeexplore.ieee.org/document/8292737 https://machinelearningmastery.com/how-to-develop-lstm-models-for-multi-step-time-series-forecasting-of-household-power-consumption/ https://machinelearningmastery.com/how-to-develop-lstm-models-for-time-series-forecasting/ https://irosyadi.netlify.app/research/time-series-forecasting/
用于音频分类的 CNN
原文:https://towardsdatascience.com/cnns-for-audio-classification-6244954665ab?source=collection_archive---------3-----------------------
使用张量流进行音频分类的深度学习入门
作者图片
卷积神经网络
CNN 或卷积神经网络是一种深度学习算法,在学习图像方面做得非常好。
那是因为他们可以学习到 平移不变 且具有 空间层次 的模式(F. Chollet,2018)。
作者图片
也就是说如果如果 CNN 学习了上图左角的狗,那么它就可以识别出另外两张被移动过的图片中的狗( 平移不变性 )。
如果 CNN 从上图的左上角学习这只狗,它会在另外两张图片中识别出原始图像的部分,因为它已经学习了她患有异色症的眼睛的边缘是什么样子,她狼一样的鼻子和她时尚耳机的形状( 空间层次 )。
这些属性使 CNN 成为强大的图像学习者,因为真实世界并不总是看起来完全像训练数据。
我能把这个用于音频吗?
是的。你可以提取看起来像 T21 图像的特征,并以某种方式塑造它们,以便将它们输入 CNN。
本文解释了如何训练 CNN 根据音频信息对物种进行分类。
这个例子的数据是来自 Kaggle 竞赛雨林连接物种音频检测的鸟和青蛙的录音。
作者图片
首先,加载必要的输入:
import pandas as pd
import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
from sklearn.preprocessing import normalize
import warnings
warnings.filterwarnings('ignore')
import numpy as np
import pickle
import joblib
from sklearn.model_selection import train_test_split
from tensorflow.keras import models, layers
import tensorflow as tf
然后是数据帧:
os.chdir('/kaggle/input/rfcx-species-audio-detection')
df = pd.read_csv('train_tp.csv')
该数据集是一个 csv 文件,音频文件的名称列在 recording_id 下,标签列在 species_id 下,音频样本的开始/结束列在 t_min 和 t_max 下:
df.head()
使用 librosa 包加载并显示一个音频文件,如下所示:
sample_num=3 #pick a file to display
#get the filename
filename=df.recording_id[sample_num]+str('.flac')
#define the beginning time of the signal
tstart = df.t_min[sample_num]
tend = df.t_max[sample_num] #define the end time of the signal
y,sr=librosa.load('train/'+str(filename)) #load the file
librosa.display.waveplot(y,sr=sr, x_axis='time', color='cyan')
棘手的部分
CNN 期待一个图像:
- 灰度图像(1 个通道)
- 具有三个通道的彩色图像:红色、绿色和蓝色(RGB)
作者图片
所以你必须让你的音频特征看起来像图像。
- 为灰度图像(一个要素)选择 1D,或为彩色图像(表示多个要素)选择 3D。
- 缩放和填充音频功能,使每个“通道”大小相同。
#This code was adapted from Nicolas Gervais on [https://stackoverflow.com/questions/59241216/padding-numpy-arrays-to-a-specific-size](https://stackoverflow.com/questions/59241216/padding-numpy-arrays-to-a-specific-size) on 1/10/2021def padding(array, xx, yy):
"""
:param array: numpy array
:param xx: desired height
:param yy: desirex width
:return: padded array
"""h = array.shape[0]
w = array.shape[1]a = max((xx - h) // 2,0)
aa = max(0,xx - a - h)b = max(0,(yy - w) // 2)
bb = max(yy - b - w,0)return np.pad(array, pad_width=((a, aa), (b, bb)), mode='constant')
难道我不能把我的音频特征分成三等份,重新塑造成 3D 形状吗?
它们毕竟只是数字。
号它必须使视觉感知。垃圾进,垃圾出。
作者图片
建模的特征
Librosa 有关于如何提取特征的很棒的教程在这里。
对于这个例子,我将计算:
- 梅尔谱图( MFCCs )
- 光谱带宽
- 光谱质心
- 色度图
- 短时傅立叶变换( stft )
输入到 CNN 的 3D 图像是 4D 张量
第一个轴是音频文件 id,代表 tensorflow-speak 中的批处理。在这个例子中,第二轴是光谱带宽、质心和色谱图,其被重复、填充并适合第三轴(stft)和第四轴(MFCCs)的形状。
#The eventual shape of the features
print(X_train.shape,X_test.shape)
第一轴 1226 是批量大小,128 是高度,1000 是宽度(由下面代码中的 max_size 设置), 3 是训练数据中的通道数。如果我有 1226 个音频文件,那么批量大小是 1226。如果我们只提取 dataframe.head()图中所示的 5 个音频文件的特征,则输入的形状将是 5×128×1000×3。如果您想在训练时使用更少的内存,您可以减小批量大小。对于这个例子,批量大小被设置为音频文件的数量。
def generate_features(y_cut):
**max_size**=1000 #my max audio file feature width
stft = padding(np.abs(librosa.stft(y_cut, n_fft=255, hop_length = 512)), 128, max_size)
MFCCs = padding(librosa.feature.mfcc(y_cut, n_fft=n_fft, hop_length=hop_length,n_mfcc=128),128,max_size)
spec_centroid = librosa.feature.spectral_centroid(y=y_cut, sr=sr)
chroma_stft = librosa.feature.chroma_stft(y=y_cut, sr=sr)
spec_bw = librosa.feature.spectral_bandwidth(y=y_cut, sr=sr) #Now the padding part
image = np.array([padding(normalize(spec_bw),1, max_size)]).reshape(1,max_size)
image = np.append(image,padding(normalize(spec_centroid),1, max_size), axis=0) #repeat the padded spec_bw,spec_centroid and chroma stft until they are stft and MFCC-sized
for i in range(0,9):
image = np.append(image,padding(normalize(spec_bw),1, max_size), axis=0)
image = np.append(image, padding(normalize(spec_centroid),1, max_size), axis=0)
image = np.append(image, padding(normalize(chroma_stft),12, max_size), axis=0)
image=np.dstack((image,np.abs(stft)))
image=np.dstack((image,MFCCs))
return image
以下三个特征被挤压、填充和重复…
…进入以下轴:
第二轴
最后两个轴被设计成相同的形状:
stft
MFCCs
我必须计算这些完全相同的特征吗?
否。只要你把它们垫成同样的形状,就用建模中效果最好的。
X=df.drop('species_id',axis=1)
y=df.species_id
提取训练集、测试集和验证集
#Split once to get the test and training set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=123, stratify=y)
print(X_train.shape,X_test.shape)
#Split twice to get the validation set
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=123)
print(X_train.shape, X_test.shape, X_val.shape, len(y_train), len(y_test), len(y_val))
为每个音频文件计算这些特征,并存储为特征和标签:
**def** get_features(df_in):
features=[]
labels = [] *#empty array to store labels*
*#For each species, determine how many augmentations are needed
* df_in=df_in.reset_index()
**for** i **in** df_in.species_id.unique():
print('species_id:',i)
*#all the file indices with the same species_id*
filelist = df_in.loc[df_in.species_id == i].index
**for** j **in** range(0,len(filelist)):
filename = df_in.iloc[filelist[j]].recording_id
+str('.flac') *#get the filename*
*#define the beginning time of the signal*
tstart = df_in.iloc[filelist[j]].t_min
tend = df_in.iloc[filelist[j]].t_max *#end of signal
* recording_id = df_in.iloc[filelist[j]].recording_id
species_id = i
songtype_id = df_in.iloc[filelist[j]].songtype_id
*#Load the file
* y, sr = librosa.load(filename,sr=28000)
*#cut the file to signal start and end*
y_cut=y[int(round(tstart*sr)):int(round(tend*sr))]
*#generate features & output numpy* *array*
data = generate_features(y_cut)
features.append(data[np.newaxis,...])
labels.append(species_id)
output=np.concatenate(features,axis=0)
**return**(np.array(output), labels)#use get_features to calculate and store the features
test_features, test_labels = get_features(pd.concat([X_test,y_test],axis=1))
train_features, train_labels = get_features_noOS(pd.concat([X_train,y_train],axis=1))
将数据规范化并转换为 numpy 数组
X_train = np.array((X_train-np.min(X_train))/(np.max(X_train)-np.min(X_train)))
X_test = np.array((X_test-np.min(X_test))/(np.max(X_test)-np.min(X_test)))
X_train = X_train/np.std(X_train)
X_test = X_test/np.std(X_test)
y_train = np.array(y_train)
y_test = np.array(y_test)
创建一个 CNN
在下面的示例模型中,2D 卷积层 (Conv2D)单元是学习平移不变空间模式及其空间层次的部分。
最大池 图层通过将特征地图缩减采样至窗口内的最大值,将特征地图的大小减半。为什么要缩减采样?因为否则它会导致一个巨大数量的参数,你的计算机会崩溃,毕竟,模型会大规模地过度拟合数据。这种神奇的层是 CNN 能够处理图像中大量数据的原因。最大池对模型有好处。
剔除 层通过将一部分数据的权重随机设置为零来防止过度拟合,而密集单元包含与模型必须尝试拟合数据的自由度相关的隐藏层。数据越复杂,模型需要的自由度就越多。注意 不要添加一堆这样的东西,否则会过度拟合数据。
展平层将所有特征地图信息压缩成一列,以便输入到密集层,最后一层输出模型应该将音频记录分类到的 24 个种类。
CNN 模型架构示例
作者图片
在 tensorflow 中,您可以像这样创建上面的模型
input_shape=(128,1000,3)
CNNmodel = models.Sequential()
CNNmodel.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
CNNmodel.add(layers.MaxPooling2D((2, 2)))
CNNmodel.add(layers.Dropout(0.2))
CNNmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))
CNNmodel.add(layers.MaxPooling2D((2, 2)))
CNNmodel.add(layers.Dropout(0.2))
CNNmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))
CNNmodel.add(layers.Flatten())
CNNmodel.add(layers.Dense(64, activation='relu'))
CNNmodel.add(layers.Dropout(0.2))
CNNmodel.add(layers.Dense(32, activation='relu'))
CNNmodel.add(layers.Dense(24, activation='softmax'))
激活功能赋予模型向模型添加非线性的能力。这里使用了 relu 函数,它将负权重清零。你可以在这里阅读其他激活功能,但这是一个很好的开始。最后一个密集层的激活函数类型是 softmax ,它为每个类输出一个概率。
编译模型
CNNmodel.compile(optimizer='adam',loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),metrics=['accuracy'])
Adam 优化器为您管理学习率, loss 函数用于评估预测数据和实际数据的差异,并对预测不佳的模型进行惩罚。在这个例子中,损失函数是SparseCategoricalCrossentropy,当每个样本属于一个标签时使用,而不是一个以上,和它不是二元分类。这是一个合适的选择,因为每个音频样本属于一个物种,而它们有 24 个。.)
符合模型
history = CNNmodel.fit(X_train, y_train, epochs=20, validation_data= (X_val, y_val))
为了避免过度拟合,从最简单的模型开始,一步步向上
这是因为如果模型过于复杂,它将准确地学习你的训练数据,而无法推广到看不见的数据。
试试这个:
input_shape=(128,1000,3)
CNNmodel = models.Sequential()
CNNmodel.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=input_shape))
CNNmodel.add(layers.MaxPooling2D((2, 2)))
CNNmodel.add(layers.Flatten())
CNNmodel.add(layers.Dense(32, activation='relu'))
CNNmodel.add(layers.Dense(24, activation='softmax'))
CNNmodel.summary()
注意:这个模型太简单了,根本无法预测数据*(如个位数精度)。*
接下来,添加层,直到你的模型已经开始适应数据。
评估您的模型训练和验证集
- 注意训练集和测试集之间的性能差异。如果训练集表现明显更好,它不会很好地推广到看不见的数据。
- 如果验证集的性能开始下降,停止迭代。
#Adapted from Deep Learning with Python by Francois Chollet, 2018
history_dict=history.history
loss_values=history_dict['loss']
acc_values=history_dict['accuracy']
val_loss_values = history_dict['val_loss']
val_acc_values=history_dict['val_accuracy']
epochs=range(1,21)
fig,(ax1,ax2)=plt.subplots(1,2,figsize=(15,5))
ax1.plot(epochs,loss_values,'bo',label='Training Loss')
ax1.plot(epochs,val_loss_values,'orange', label='Validation Loss')
ax1.set_title('Training and validation loss')
ax1.set_xlabel('Epochs')
ax1.set_ylabel('Loss')
ax1.legend()
ax2.plot(epochs,acc_values,'bo', label='Training accuracy')
ax2.plot(epochs,val_acc_values,'orange',label='Validation accuracy')
ax2.set_title('Training and validation accuracy')
ax2.set_xlabel('Epochs')
ax2.set_ylabel('Accuracy')
ax2.legend()
plt.show()
结束语
现在,您知道了如何创建用于音频分类的 CNN。从简单的模型开始,然后添加层,直到您开始看到训练数据的表现优于测试数据的迹象。添加 Dropout 和 Max 池层以防止过度拟合。最后,当您注意到与训练数据相比,验证数据的性能下降时,停止迭代。
快乐造型!
来源
萨卡尔,迪潘坚 (2021)个人通信。
Chollet,F. 用 Python 进行深度学习(2018),v. 361,纽约州:曼宁。
Gervias,Nicolas, (2021) 代码摘自https://stack overflow . com/questions/59241216/padding-numpy-arrays-to-a-specific-size,2021 年 1 月 10 日检索。
frenzykryger(2021)https://data science . stack exchange . com/questions/41921/sparse-category-cross entropy-vs-category-cross entropy-keras-accuracy #:~:text = Use % 20 sparse % 20 category % 20 cross entropy % 20 when,0.5%2C%200.3%2C%200.2%5D ,2021 年 2 月 21 日检索
美国有线电视新闻网预测过程故障
原文:https://towardsdatascience.com/cnns-to-predict-process-failures-28c17e5fd6c2?source=collection_archive---------9-----------------------
作者的“盒子里的猫”图片
原型——在单个图像中堆叠多个时间片并分类:正常、警告或故障
这是一个探索应用 CNN 预测过程中系统故障可能性的原型。目标不是对故障进行分类,而是将一组当前和过去的时间片分类为未来故障的指示。
在我开始之前,请注意,这是作为一个概念/原型提出的,以测试 CNN 模型是否能够合理地预测工业系统中即将发生的故障。我确实将它应用于造纸机故障数据集,我将在下一篇文章中讨论。这不是“成为全部,结束全部”或最先进的人工智能应用程序。我在这里展示它是为了启发他人,给数据科学的新手提供另一个“项目”来修补,并可能从经验丰富的从业者那里激发一些想法。
我第一次想到这一点是在一次使用时间 CNN (TCN)模型的 meetup(深度学习研究金)会议上讨论一篇论文时(白、J 科尔特和弗拉德伦科尔顿,“序列建模的一般卷积和递归网络的实证评估”,arXiv:1803.01271,2018)。那篇论文评估了一个通用的 TCN 来回顾过去并预测未来或下一个状态。
我的申请更简单。目标是将几个时间片的数据整理成图像,即过去和当前状态的快照,并假设故障前几个时间段的过程偏差不同于正常操作,从而发出警告—黄灯。目的不是对故障和正常情况进行分类,而是对“即将发生的故障”进行分类。警告可能有几种类型。(参考下面的“盒子里的猫”,警告可以是在猫跳出盒子之前竖起耳朵、爪子或尾巴。)
为此,每个时间片被转换成图像中的一行像素,多个时间由不同的像素行表示。第一幅图像的时间段为 0 到 n,下一幅图像的时间段为 1 到 n+1,依此类推。如果没有显著的偏差发生,那么每个图像将是相似的,只是有一些变化(噪声)。如果流程连续偏离故障点,图像可能会改变,从而提供即将发生故障的警告。想想“盒子里的杰克”或“盒子里的猫”。在猫跳出来之前,我们能看到它的耳朵从盒子里伸出来吗?
作者图片
为什么要这么做?工业系统依靠过程控制运行。这些使系统在参数范围内运行。然而,系统关闭了。排除其他因素,如手动关闭或设备故障,扰乱仍会发生。识别即将发生的故障可以给操作人员留出时间来防止故障。此外,以这种方式分析一个过程可以提供对为什么或什么样的事件组合会导致不良事件的洞察。
综合数据准备
我从 Excel 开始,做了 10 个流程变量。每个变量都有一个正常的设定点和一个围绕这个设定点的随机方差。大多数变量会在故障点之前和故障点处偏离。这些是根据故障在未来多长时间内发生而定的。请记住,我是在创建它,只是在某个随机的时间将一个失败标志设置为 1,然后从那里返回一个小于 1 的值。正常操作为 0。
这是我用来创建轨迹的参数。每个点随机变化,从-0.5 到+0.5 倍的范围值加上故障位移乘以导致故障的故障规模(如下)。一些轨道不随故障而改变,而其他轨道以不同的百分比改变。在故障之前,范围偏移和故障偏移的组合值并不总是在正常范围之外,因为这些值可能具有相反的符号。如果它们都是正的或都是负的,则过程值可能会在正常范围的边缘或外部。
合成数据参数-作者图片
400+离散时间的随机生成的合成数据如下所示。它可能看起来是大幅度波动的高频,但那是每个轨迹图上的小范围。系统故障点是底部轨道中的尖峰(特征 Y)。
训练集轨迹值和故障点(特性 Y)如下所示。测试集是在不同时间失败的 Excel 模型的另一个随机实现。它是不同的,但在相同的参数定义内。
要素 A 至 J 和故障点(要素 Y)的数据轨迹-按作者分类的图像
准备数据和图像
在之前的试验中,我只是使用了位置数据,然后添加了一个导数(值的变化率,例如速度),最后合并了一个二阶导数,这样就相当于位置、速度和加速度的轨迹值。速度和加速度表是通过计算单位时间的差值来创建的。在故障为 1 和故障为 2 之前,我将正常状态标记为 0,5 时间片。
图像准备包括将数据缩放到 0 到 1 的范围内,并将前 6 个周期(0–5)的数据移动到一个 3-D Numpy 数组中,从而将它们分配给一幅图像。在每个图像中,位置、速度和加速度时间片值被堆叠在一起。对于 18x10 像素的图像,图像行为:0 至 5-位置、6 至 11-速度和 12 至 17-加速度。时间段 1-6 填充了第二个图像,依此类推。每个图像通过对应于该图像中最后一个时间片的标签进行分类。一旦故障时间片成为图像中的最后一行,就通过从故障时间片之后的下 6 个时间段开始构建下一个图像来重复该过程。
接下来,他们被重塑,并通过一个 CNN 模型进行训练。对我们来说,它看起来不像猫,也不像猫耳朵,但 CNN 模型可以区分这些图像。以下是这些图像序列的摘录。
具有六个时间段的示例图像—按作者分类的图像
培养
训练类似于 MNIST 手写数字或时尚 MNIST。我使用了一个顺序 CNN 模型,其中有 Conv2D 、 MaxPooling 、 Flatten layers 馈入一个三层128–64–3 网络和一个漏层。详情可以在 Github [这里](http://Process-Fault-Identification-with-CNN/Simulated Process Fault Prediction with Vel and Accel-3Class.ipynb at main · dvbckle/Process-Fault-Identification-with-CNN · GitHub)找到。
CNN 模型训练—作者图片
结果
测试结果如下图所示。实际类标签显示在顶部,预测类显示在中间,以便与其他两个进行比较。
作者图片
下一个图表在顶部显示预测,在中间显示类别标签,在底部显示警告或故障类别的概率,用于将概率与类别标签进行比较。
作者图片
这表明有足够的希望将这种方法应用到造纸机的实际数据集,这将是另一篇文章的主题。要探索的一个变化是只在正常和警告类上训练,因为识别故障或停止为时已晚,不需要。目标是防止停工。
此处包含的方法的使用或应用由读者自行承担风险。作者对读者的申请不负任何责任。
欢迎大家的评论。
#数据科学# CNN #机器学习#预测#原型#过程失败
R 中的粗化精确匹配
原文:https://towardsdatascience.com/coarsened-exact-matching-in-r-a36ae7ef6849?source=collection_archive---------11-----------------------
由 Geran de Klerk 在 Unsplash 拍摄的照片
数据科学基础
匹配的因果推理
我们不是都听过“相关性并不意味着因果关系”这句话,并想知道“那么,什么意味着因果关系”?嗯,因果推断。因果推理使我们能够得出关于因果影响的结论,从而做出重要的决策,并提供有价值的数据驱动的见解。因此,了解因果推断的基础知识对于数据科学家和分析师来说是一项巨大的投资。粗化精确匹配(CEM)是一种从观察数据进行因果推断的简单而直观的方法。这篇文章通过一个在 r 中使用MatchIt
库的例子展示了 CEM 背后的基本直觉。
redcharlie 在 Unsplash 上的照片
🔍 1.关于 CEM 的一点点
想象一下,我们想要了解治疗对感兴趣的结果的因果影响。我们能做的最简单的事情就是比较治疗组和未治疗组的平均结果。然而,这种比较可能不能给我们一个准确的估计,因为即使在没有治疗的情况下,治疗组和未治疗组的数据也不具有可比性。解决这个问题的一个方法是尝试将这两个组进行比较。这就是 CEM 等匹配技术的用武之地。
在我们开始讨论 CEM 之前,让我们从一种叫做精确匹配(EM) 的匹配技术开始。对于 EM,我们匹配处理过的和未处理的记录,这些记录在其协变量中具有完全相同的值。换句话说,这些匹配的记录将具有相同的特征,除了它们的治疗状态。一旦我们完成了所有可能的匹配并丢弃了不匹配的记录,那么匹配数据中的治疗组与未治疗组现在将更具可比性,我们可以分析组均值的差异来推断因果影响。
Neil 和 Zulma Scott 在 Unsplash 上的照片
然而,由于在进行 EM 时没有匹配,许多记录可能被排除在分析之外。例如,如果有许多数字协变量,就很难找到精确的匹配。在这方面,CEM 提供了一个很好的选择。做 CEM 时,有三个主要步骤:
- 粗化数据以降低粒度级别。这意味着宁滨数值和/或分组类别值。
- 对粗化的数据应用精确匹配,以找到可比较的对照组和治疗组。这意味着找到至少有一个对照和一个处理记录的协变量的所有组合,并保留属于这些组合的记录,丢弃其余的记录。每个组合被称为地层。
- 使用匹配的数据估计因果影响。
了解了 CEM 背后的基本直觉后,我们可以看到它的名字是多么有信息量。让我们看一个简单的例子来更好地理解这项技术。
📍 2.R 中带有 MatchIt 的 CEM 示例
让我们导入必要的库并加载数据集。我们将使用 Lalonde 数据集的一个小子集来保持事情的易管理性和易监控性。
library("dplyr")
library("MatchIt")
library("lmtest")
library("sandwich")
options(scipen = 100, digits=4)# Prepare sample data --------------------
data("lalonde")
set.seed(42)
(df <- lalonde %>%
select(treat, educ, race, re78) %>%
sample_n(30))
对于 30 个随机选择的记录,我们有以下变量:
◼️ 协变量: educ
受教育年限和race
◼️ 治疗: treat
治疗状态
◼️ 结果:re78
1978 年实际收入
让我们假设我们想要理解treat
对re78
的因果影响。
我们可以通过指定method = 'cem’
来用matchit
执行 CEM:
# Perform CEM --------------------
matching1 <- matchit(treat ~ educ + race, data = df,
method = 'cem', estimand = 'ATE')
summary(matching1, un=FALSE)
仅部分输出
我们可以看到,有 22 条质控记录可用,但只有 5 条匹配,其余 17 条不匹配,将从分析中删除。对照组匹配记录的有效样本量(Matched (ESS)
)为 4.91。治疗组也有相同的总结。
现在,让我们看看 12 条匹配记录的匹配数据:
# Extract matched data --------------------
(matched_df1 <- match.data(matching1) %>% arrange(subclass, treat))
subclass
显示了 3 个地层。虽然我们在这里看不到粗化的数据,但我们可以从原始值中大致猜出粗化的程度。例如,subclass
3 似乎包含有9–10
年教育和black
种族的记录。我们可以看到每条记录都增加了权重。我们先来了解一下这些权重是怎么算出来的。
📍 2.1.CEM 重量
每个层有两个权重:一个权重用于层中的处理记录,另一个用于控制记录。当计算权重时,我们要确保两件事:
◼️在加权后,治疗组和对照组的比例在总体水平上保持在每个阶层内:
◼️加权数等于阶层内未加权数;
根据我们感兴趣的estimand
的类型,该公式可以重新排列并简化为以下形式:
🔷**对被治疗者的平均治疗效果(ATT)——**治疗记录不加权(即权重为 1),对照记录加权:
ATT 公式
🔷**对对照的平均处理效果(ATC)——**ATC 也是如此。质控记录不加权,治疗记录加权:
ATC 公式
🔷**平均治疗效果(ATE)——**两组均加权:
ATE 公式
如果你想了解 ATT,ATC,ATE,查看本帖 中 的 1.5 节。
之前我们明确表示我们有兴趣了解ATE
。使用公式,让我们以子类 1 的重量为例:
我们自己计算了记录PSID376
和NSW153
的权重,以获得与函数返回的权重相同的权重。如果你很热衷,为其他两个类计算权重,巩固你的理解。
我们前面已经看过Matched (ESS)
。如果你想知道它是如何计算的,这里有一个公式:
例如,让我们计算匹配对照组的 ESS:
📍 2.2.估计因果影响
匹配完记录,就该看看预估的ATE
:
# Estimate causal impact - look at ATE --------------------
model1 <- lm(re78 ~ treat, data = matched_df1, weights = weights)
coeftest(model1, vcov. = vcovCL, cluster = ~subclass)
这里可以看到4907
的估计值及其统计意义。该估计值是各组加权平均值之间的差值:
matched_df1 %>% group_by(treat) %>%
summarise(w_mean = weighted.mean(re78, weights))
8255–3348 = 4907
我们还可以检查估计值的置信区间:
coefci(model1, vcov. = vcovCL, cluster = ~subclass)
95%置信区间为-1073
至10887
。这些输出表明,处理对输出没有统计学上的显著影响。这并不奇怪,因为我们使用的是非常小的玩具数据集。
📍 2.3.控制粗化的级别
到目前为止,我们让函数使用其默认的粗化级别:宁滨数值变量使用斯特奇斯方法并保持分类变量不变。然而,在实践中,如果我们能够控制粗化的水平,这将是有用的。我们现在将学习对数字变量使用自定义切割点,对分类变量使用自定义分组。
在应用 CEM 时,为了实现平衡(即,使组具有可比性),删除一些记录,但是删除太多记录是不可取的。在我们的第一次匹配中,超过一半的记录(即 30 个中的 18 个)被遗漏。让我们尝试减少被排除的记录的数量,同时尝试在每个层中映射相似的记录。
# Perform CEM with custom coarsening --------------------
cutpoints <- list(educ = c(8.5, 10.5))
grouping <- list(race = list(c("white", "black"), c("hispan")))
matching2 <- matchit(treat ~ educ + race, data = df,
method = 'cem', estimand = 'ATE',
cutpoints=cutpoints, grouping=grouping)
summary(matching2, un=FALSE)
我们使用了两个分界点为educ
创建了三个箱,并将非西班牙裔种族分组在一起。通过使数据更加粗糙,我们将不匹配记录的数量从 18 个减少到了 3 个。然而,这样做的风险是,在观测值不太可比的同一地层中,包含不太相似的观测值。这意味着我们需要在不排除太多记录和不在层中包含太多不同记录之间找到微妙的平衡。让我们看看匹配的数据,以评估每个地层中的记录有多相似:
# Extract matched data
(matched_df2 <- match.data(matching2) %>% arrange(subclass, treat))
子类中的记录看起来相互之间有可比性吗?这是我们需要评估和必要时重申的,直到我们满意为止。让我们假设我们是快乐的,我们可以继续检查估计:
# Estimate causal impact - look at ATE --------------------
model2 <- lm(re78 ~ treat, data = matched_df2, weights = weights)
coeftest(model2, vcov. = vcovCL, cluster = ~subclass)
coefci(model2, vcov. = vcovCL, cluster = ~subclass)
查看该输出后,前面分析的结论保持不变。
在这篇介绍性的文章中,我们学习了 CEM 的基础知识:算法如何工作,如何控制粗化的程度,以及如何分析因果影响。对于热衷于学习的人来说,这个和这个是非常棒的额外资源。我希望您能够使用这种技术为您的利益相关者提供有价值的见解。✨
照片由 Geran de Klerk 在 Unsplash 上拍摄
您想访问更多这样的内容吗?媒体会员可以无限制地访问媒体上的任何文章。如果您使用 我的推荐链接成为会员,您的一部分会费将直接用于支持我。
感谢您阅读这篇文章。如果你感兴趣,这里有我其他一些帖子的链接:
◼️ 倾向得分匹配 (因果推断)
◼️ 解释 Scikit-learn 模型与 SHAP
◼️️ K 近邻解释
◼️️ 逻辑回归解释
◼️️ 比较随机森林与梯度推进
◼️️ 决策树是如何建立的?
◼️️ 管道、柱变压器及特性 Union 说明
再见🏃 💨
从代码到生产就绪的机器学习,4 个步骤
原文:https://towardsdatascience.com/code-to-production-ready-machine-learning-in-4-steps-b8cfc84e8d97?source=collection_archive---------36-----------------------
我们如何将数据科学代码库转变为数据和模型版本化、实验跟踪的项目,为生产做好准备
在 Unsplash 上由 C Dustin 拍摄的照片
TL;速度三角形定位法(dead reckoning)
我们将从 GitHub 获取一个纯代码的机器学习项目,并展示如何添加:
- 使用 DVC 和 DAGsHub 的数据和模型版本控制
- 使用 DAGsHub Logger 以人类可读的格式进行实验跟踪
- 允许任何人试验模型的笔记本
如果你想直接看到结果,请查看 BioBERT DAGsHub repo 。
使用你在网上找到的机器学习项目很难,尤其是如果你想在生产中使用它们。在很大程度上,这是因为您需要将项目包含的所有信息拼凑在一起。你通常从 GitHub 上的一些代码开始。然后,您必须找到对模型进行训练和评估的数据、使用的参数以及模型实现的结果。这通常是在没有明确方法的情况下完成的,即在您自己的示例中尝试该模型,以确保它按预期工作。
直到最近,解决这些问题还是一项艰巨的任务,需要创建者同步多个平台,以使一切触手可及。现在情况不再是这样了。您可以将项目从纯代码项目转变为生产就绪的 ML 项目,使用:
- 数据版本控制
- 模型版本控制
- 实验跟踪
- 交互式推理——加载模型并让您进行实验的笔记本
全部使用开源工具。也许与直觉相反,这真的很容易做到。在这篇文章的最后,我将向你展示我是如何改造这样一个项目的,并且在这个过程中实现了数据浏览、区分和共享、实验可视化,甚至笔记本区分。
一个你永远无法使用的伟大项目
GitHub 上有许多数据科学项目,但当您在寻找可以在项目中使用的东西或想要修改结果时,通常不会找到您需要的所有东西。毕竟,一个完整的数据科学项目不仅包括代码,还包括数据、模型、实验和管道。通常,你最终会花费大量的时间来修补这些组件,并且让事情正常工作变得非常痛苦。这意味着数据科学项目被忽视,甚至更糟,从零开始重新实施。我们有更重要的事情要做。
将所有这些组件都放在一个地方,可以更容易地在所需的上下文中共享我们的数据科学项目,与其他人合作,并提高工作效率。
我们将把我们的项目从目前的状态提升为一个开源的 代码 项目, 到一个 开源数据科学 项目 。
现在,你可能会说:“这当然是我们想要的。我们看不到这种情况发生的原因是,这非常难以实现。”有了今天的工具,那就不再是问题了。
项目背景
我们开始这个项目是作为合作努力的一部分,在 ML 方面,重点是从医学文本中分析和提取信息。目标是了解临床试验是如何进行的。
因此,我们对医学文本的语言模型感兴趣,特别是 NER。我们搜索了互联网,选择了 BioBERT 作为一个好的起点。该模型具有良好的效果,似乎相对容易使用。
当我们找到 GitHub BioBERT 项目时,我们有所有的代码,我们有一个脚本来下载数据,这是使用wget
从一些谷歌文档中完成的,我们有 4 个文件夹,其中 3 个用于模型可以执行的每个任务 done(命名实体识别)、QA(问题回答)和 RE(关系提取)。嵌入本身也有一个文件夹。每个文件夹都包含预处理数据的代码,并为该任务训练模型。每个文件夹中的自述文件包括结果。
不错的开始,但是我们想要更多。
一件更难重现的事情(根据定义),也是我们在这篇文章中不会关注的,是该项目的实验历史。我们希望看到哪些实验没有成功,就像我们希望看到那些成功的实验一样——想象一下,尝试一种方法,然后发现,有人已经尝试过了,但没有成功,但从未被记录下来。获得我们的实验历史的最好方法是从一开始就使用数据&模型版本和实验跟踪,最好添加一个有意义的提交消息来描述你的实验方法。
添加数据版本
第一步是添加要版本化的数据作为项目的一部分。最初,为了获得数据,您必须运行一个脚本来下载数据集。一种方法是将此转换为 DVC 管道步骤,这将使我们能够更改脚本并自动运行。因为我们想以最简单、最直接的方式来做这件事,所以我们只在本地运行脚本。数据下载到我们的系统后,我们添加了 DVC 要跟踪的文件夹。
下载完数据后,我们的datasets/
文件夹看起来是这样的:
$ ./download.sh
$ tree datasets -d
datasets
├── NER
│ ├── BC2GM
│ ├── BC4CHEMD
│ ├── BC5CDR-chem
│ ├── BC5CDR-disease
│ ├── JNLPBA
│ ├── NCBI-disease
│ ├── linnaeus
│ └── s800
├── QA
│ └── BioASQ
└── RE
├── GAD
│ ├── 1
│ ├── 2
│ ⋮
│
└── euadr
├── 1
├── 2
⋮34 directories
对于模型执行的每个任务(NER、QA、RE),我们都有一个文件夹,其中包含每个任务的各种数据集。每个文件夹包含一些文件(依赖于任务),主要是训练集、开发集和测试集。
使用 dvc,我们不需要单独跟踪每个文件,而是可以将整个文件夹视为一个数据集对象,只需在终端中键入:
$ dvc add datasets
接下来,我们有预处理步骤。这三项任务中的每一项所需的预处理步骤都是不同的。因为在这篇文章中,我们关注的是 NER 任务,我们的预处理脚本位于named-entity-recognition/
文件夹中。这个脚本所做的是将.tsv
文件转换成.txt
文件,然后运行preprocess.py
脚本,该脚本将数据标记化并将数据保存到标签旁边的文本文件中。这些预处理数据被保存到我们的preprocessed_datasets/
文件夹中,在适当的任务和数据集文件夹中。在我们这里,那就是NER/
。在预处理步骤完成后,我们可以通过在终端中键入以下命令来添加预处理后的数据,以便由 DVC 进行跟踪:
$ dvc add preprocessed_datasets
当我更改数据时会发生什么
现在,假设您想要为 RE 任务添加预处理数据。我们要做的是运行预处理步骤,然后代替dvc add ...
,我们要做:
$ dvc commit preprocessed_datasets
其次是提交和推送至 Git,然后是 DVC:
$ git add .
$ git commit -m "Updated preprocessed data with RE task"
$ git push origin master
$ dvc push -r origin
定型模型并使其可访问
所以预处理是一个相对“轻量级”的步骤。在这个具体的例子中,我们可以在一台不太强大的计算机上,在合理的时间内完成。当我们开始训练时,情况就不一定了,如果可能的话,我们希望拿出大枪。因为我们希望这个项目可以被社区访问,那些大家伙就是 Google Colab,它给了我们一个免费的 GPU。我们仍然希望从 DAGsHub 中提取代码和数据,并在训练后将它们与模型一起推回。
在我们的例子中,我们创建了这个笔记本,并提交给我们的项目库。它由以下部分组成:
- 使用
git pull
和dvc pull
命令加载代码、数据和模型 - 在相关生物医学数据集上微调模型
- 加载模型,并查看它在一些用户提供的示例上的表现。
- 将所有代码、数据和模型更改提交回我们的 DAGsHub Git 和 DVC 远程。
在最后一节中,我们使用与添加数据相同的命令提交模型:
# If this is the first time adding the output folder $ dvc add outputs # If we changed our model $ dvc commit outputs
轻松添加实验跟踪
我们想补充的最后一点是实验跟踪。正如我在开篇提到的,为历史实验添加这一点很有挑战性,因为如果项目没有从第一天开始记录实验,这些就会丢失。因为我们想让将来的协作更容易,所以我们认为晚添加总比不添加好。
为了做到这一点,我们对运行脚本做了一些小的修改,以便它能够根据自动记录训练期间的所有指标🤗变形金刚库,用于微调模型。 这里可以看到 的变化。这将生成一些保存所有实验上下文的metrics.csv
和params.yaml
文件。然后,我们将这些文件和我们的代码一起推送到 DAGsHub 存储库中。
现在,当我们对一些新数据或不同参数进行实验时,我们将创建一个可以过滤、共享和比较的实验。这也意味着,如果有人想为项目做贡献,他们会更容易理解我们尝试了什么,什么在起作用,什么需要改进。
实验跟踪有助于我们理解测试了哪些方法。来源:作者
模型的交互式推理
我在上面已经提到过,但是我们在笔记本中增加了一个“操场”部分,让任何人都可以加载我们的模型,并在他们可以编辑模型的同一个地方进行测试。在这里自己尝试一下。
看看吧!我们的模型基于用户提供的示例进行预测!来源:谷歌 Colab 作者截图
我们认为这对于任何数据科学项目都很重要,尤其是对于那些您想要分享和协作的项目。每个严肃的 OSS 项目都有一个演示,每个严肃的 OSDS 项目也应该有一个。在 ML 中,这可能需要更多的资源,所以演示笔记本是最好的选择。笔记本还有一个额外的好处,那就是让用户改变模型的某些方面,或者测试他们自己的例子,看看模型在哪里可能不工作。
**另一个好处:**如果您决定对模型进行更改,并希望看到您的结果与原始模型的比较,您可以将您的笔记本提交给 DAGsHub,以使用笔记本差异作为我们数据科学拉取请求的一部分。
DAGsHub 上的笔记本差异。来源:作者
摘要
🥳祝贺你!如果您在这里成功了,那么您已经成功地将一个数据科学代码报告转换为一个生产就绪的数据科学项目——所有这些都有数据和模型版本、实验跟踪,甚至还有一种在 GPU 机器上训练模型并为合作者演示模型的简洁方法。如果你有任何问题,欢迎加入我们的不和谐频道。如果你正在转换一个项目,让我知道,我很乐意帮忙。
用 Knime 进行无代码数据处理
原文:https://towardsdatascience.com/codeless-data-processing-with-knime-33e9032d02ee?source=collection_archive---------39-----------------------
Knime 数据清理和操作简介
KOBU 机构在 Unsplash 上拍摄的照片
Python、SQL、R 和 Julia 是全球数据科学家和分析师在数据分析中使用的一些流行编程语言。有些软件套件,如 Alteryx 和 Knime,有一个 IDE(集成开发环境),数据爱好者和几乎没有编程背景的技术专家可以处理他们的数据,从中提取有意义的信息。这些 IDE 的关键特性称为可视化编程,允许用户可视化从原始信息到经过处理的信息、模型以及最终有意义的输出的数据流。在这篇文章中,我将简要介绍使用来自 Kaggle 的 Fitbit 健康数据使用 Knime 进行可视化编程。
本练习将使用提取→加载→转换方法。下载的数据已经被“提取”。加载和转换将使用 Knime 来完成。
读取和操作数据
简单的数据输入和操作。来源:截图来自 Knime IDE
“CSV reader”节点用于将数据从数据源加载到 Knime 平台。还有 Excel 阅读器、JSON 阅读器、表格阅读器、Web 阅读器等类似的节点。在这篇文章中,我将重点介绍 CSV 阅读器。Knime IDE 中的描述窗口以及 Knime Hub 中的文档有更多关于 Knime 中使用的每个数据输入节点的信息。
要输入数据,右键单击 CSV reader 并从选项中选择“配置”。在打开的“配置”窗口中,您可以选择要从源位置以 CSV 格式导入的文件。
在数据输入过程中过滤列。来源:截图来自 Knime IDE
如果您熟悉这些数据,您可以单击“配置”窗口中的“转换”选项卡,并选择要输入的列。这样,在构建模型等大型数据处理过程中,您就不必处理不必要的信息。在上面的例子中,我只选择了“总步数”、“总距离”和“卡路里”栏,剩下的就不做了。
列筛选器节点。来源:截图来自 Knime IDE
另一种选择列的方法是使用“列过滤器”节点。此处显示了该节点的配置窗口。两种选择柱子的方法都是好的;然而,CSV reader 窗口中的“Transformation”选项卡可以让您深入了解您的数据类型,并允许您移动列,以便以您喜欢的格式排列它们。可以通过右键单击“列过滤器”并选择“过滤的表”来查看最终的表。
列重命名节点。来源:截图来自 Knime IDE
另一个有用的数据输入节点是“列重命名”节点。顾名思义,它允许您为您的模型将输入数据的列名更改为简单的变量名(就像在编程中一样)。这根本不会改变源文件中的列名。这里,我将“总步数”和“总距离”的列名分别更改为“步数”和“距离”。
连接表格。来源:截图来自 Knime IDE
在我的例子中,我使用了两个 CSV 阅读器节点从两个源读取数据。既然输入已经被修改为具有相同的列,那么这两个表就可以连接起来,形成一个输出表,用于我们的数据处理。连接节点用于此目的。您可以选择是否可以跳过表中的重复值或以值作为后缀,或者是否应该失败。其次,您可以选择想要列的交集还是列的并集。通过选择 intersection,您将只看到数据匹配的列,而在 Union of columns 中,所有的数据都被合并在一起,得到一个连接表。
筛选表中的行。来源:截图来自 Knime IDE
现在数据已经按列过滤并合并了,我们要做的最后一个操作是清理数据,删除步骤为 0 的所有行。“行过滤器”节点可用于此目的。筛选器节点有各种选项,可以根据行类型、行号、行值和行 ID 来包含或排除行。我选择了“Steps”作为列,并排除了值为 0 的行。正如您所看到的,您可以使用这个节点来过滤一列中的行。若要筛选多个列,可以使用“基于规则的行筛选器”节点,而不是使用多个行筛选器节点。这将允许您为多个列的过滤编写简单的指令。
来自线性相关节点的相关矩阵。来源:截图来自 Knime IDE
“线性相关”节点是一个可视化节点,它为您提供了数据中不同列之间的相关性度量。这使您可以看到一列中的更改将如何影响另一列的数据或输出。此处显示的相关矩阵是线性相关节点的输出。深蓝色单元格紧密相关,而浅蓝色单元格相关性较小。如果任何单元格是红色的,那么它们在该单元格中的变量(X 和 Y 列)之间具有反向相关性。叉号(X)表示没有相关性。
散点图节点输出。来源:截图来自 Knime IDE
“散点图”节点允许您在一个柱上绘制另一个柱。它不允许有第二个轴。散点图节点的输出如上所示。您可以使用标签、标题和副标题定制绘图,Knime 还允许您选择在 X 和 Y 轴上显示其他列的视图。这样可以更快地查看不同列之间的关系,而不必为每个图表创建单独的节点。
结论
本文旨在简要介绍 Knime 中的数据输入和转换。Knime 是一个强大的可视化编程工具,可以通过它的 IDE 和 Knime hub 提供一个巨大的节点和特性库。几乎不需要编程,Knime 允许用户处理他们的数据,创建模型,并在他们的数据上部署机器学习模型以进行快速处理,而不是必须使用 Python,R 或 SQL 编写所有代码。虽然 Python、R 和 SQL 是数据科学所需的关键技能,但 Knime 为那些不熟悉编程但需要根据模型输出做出决策的人提供了一个极好的选择。
参考资料:
- 克尼姆中心—https://hub.knime.com/
- Knime 课程—【https://knime.learnupon.com/dashboard
- https://www.kaggle.com/
- 来自 Unsplash 的封面图像
傻瓜用无代码机器学习词典
原文:https://towardsdatascience.com/codeless-machine-learning-dictionary-for-dummies-fa912cc7bdfe?source=collection_archive---------36-----------------------
为最激动人心的领域找到正确的术语
照片由 坤摄 上 像素
知识的诅咒
机器学习已经变得如此受欢迎,以至于它成为人们认为你知道它的一切的话题之一。现在很常见的是使用花哨的术语,如训练/拟合模型、训练集、验证模型、成本函数和许多其他术语,而不考虑人们是否理解它。有时候,感觉你生来就应该知道这些事情…
看看我,漫无边际地谈论机器学习,却不解释它是什么。
今天,我在这里通过解释一些围绕机器学习的最常见的术语来打破这种知识偏见,并且希望你有一些背景知识来理解。
https://ibexorigin.medium.com/membership
获得由强大的 AI-Alpha 信号选择和总结的最佳和最新的 ML 和 AI 论文:
https://alphasignal.ai/?referrer=Bex
什么是机器学习?
机器学习的第一个定义出现在 60 年代末:
机器学习是在没有明确编程的情况下赋予计算机学习能力的研究领域。——阿瑟·塞缪尔
但是没有编程,计算机是怎么学习的?你的笔记本电脑上可能有一千本科学书籍,但这意味着机器知道一些东西吗?你可以很容易地通过问为什么水是湿的来检查,你会得到你的答案。
机器学习最早的应用之一是一个垃圾邮件过滤器。到目前为止,垃圾邮件过滤器已经变得如此之好,我敢打赌,你甚至不记得你最后一次将一封邮件标记为垃圾邮件是什么时候了。
在全面解释机器学习之前,我们先来谈谈如果没有机器学习,你将如何编写一个程序来标记垃圾邮件。
首先,您查看许多垃圾邮件的示例并识别模式。这些词可以是紧急词,如立即行动、立即打电话、尽快结束,或者垃圾邮件发送者经常使用的 188 个词中的任何一个。然后,编写规则来检查这些短语,以检测垃圾邮件。
与此同时,垃圾邮件发送者不会坐以待毙,意识到他们的电子邮件没有通过,所以他们想出了更好的技术来逃避过滤器。随着垃圾邮件模式的变化,您的程序变成了一个更长的复杂规则列表,并且不断扩展。
照片由 托尔斯滕 发自 像素
相比之下,基于机器学习的垃圾邮件过滤器可以检测出与普通电子邮件相比在垃圾邮件中出现异常频繁的单词(也称为“ham”),并开始自动标记它们。
如果垃圾邮件发送者开始使用新的模式,用户开始手动标记它们,基于 ML 的程序会意识到这一点,并开始过滤这些类型的垃圾邮件,而无需您的干预。
基于 ML 的程序的这种能力使它们更容易编码和维护。
机器学习就是在随机数据(数字和文本)的海洋中检测模式。它可以用来从最疯狂的现象中提取有用的信息,比如预测股票价格。
特征和目标
所有的 ML 算法都试图根据现有的数据来预测未来的结果。为了创建垃圾邮件过滤器,成千上万封电子邮件被输入到机器学习算法中。每封电子邮件都有一些质量或属性,如字数、句子数、主题、正文、邮件类型等等。
根据您试图预测的内容,这些属性分为两组:要素和目标。顾名思义,目标属性(ML 工程师也叫目标变量)就是你要预测的值。在我们的例子中,电子邮件的类型(垃圾邮件或垃圾邮件)是目标属性。
相反,特征是帮助预测目标变量的所有属性。如果你试图预测房子的价值,目标是房子的价格和特征,可以是房间数量、地段面积、浴室数量、靠近公共交通等等。
当您将现有数据提供给 ML 算法时,您可以判断哪些属性是特征,哪些是目标。该算法同时查看所有特征并检测模式。换句话说,它学习什么样的特征组合构成特定类型的目标变量。
目标变量的类型决定了使用哪种 ML 算法。通常,试图预测数字目标的算法被称为回归算法,而试图预测某种标签或组的算法被称为分类算法。
比如预测房价,你用回归,预测邮件类型,你用分类。
什么是模型?
你会看到人们互换使用术语机器学习模型和机器学习算法。然而,它们之间有一个关键的区别。
ML 算法是复杂的数学和统计学的结合。没有任何数据和计算机能力,它什么也做不了。你不能用它来预测。
ML 模型是一种算法,已经对数据进行了训练,并准备好预测与训练数据相同类型的新值。
你问培训是什么?嗯,我已经提到过几次了:它是将数据输入算法的过程(也称为拟合模型)。这是实际学习发生的地方。该算法使用其基本公式或规则,从输入数据中检测模式,并将信息存储在其内存中。
一般来说,大多数常见的算法都是使用 Python 这样的编程语言来实现的。Python 提供了标准的应用编程接口(API ),使得用几行代码访问和训练任何数据上的 ML 算法变得容易。
总之,算法只是一套原始的、未经训练的数学规则,而模型是一个经过训练的、可以预测的程序。
训练/测试设备
我希望我们已经达成一致,机器学习就是预测未来的价值。但是我们能说一个模型的预测总是可信的吗?换句话说,我们如何检查它的性能?
考虑到这个目的,ML 工程师将可用数据分为两组:训练集和测试集。正如您所猜测的,该算法在包含所有要素及其标签的训练集上接受训练。
测试集也包含特征和标签,但为了模拟预测过程,您只需将特征提供给训练好的模型,它就会预测它们的目标/标签。
例如,假设你有 3 种玫瑰的 1 万张图片。每张图片都以其物种名称命名或标注。要建立一个将玫瑰分类的模型,首先需要创建一个训练集。通常,您会分离 80%的可用数据来训练您的模型。
为了检查模型的学习效果,你给另外 20%的图像进行预测。只是这一次,你去掉了图像标签。在模型预测了它们的种类之后,你将它们与这 2000 张图片的实际标签进行比较。
如果一个模型的精确度足够高,你就可以安全地用它来对未来的玫瑰图像进行分类。
监督/非监督学习任务
机器学习模型根据训练数据进一步分为两组。
第一种是监督学习。除了相关特征,监督学习算法还需要相应的标签来建立相关的联系。这就像给婴儿看一个苹果,并告诉他这是什么,这样婴儿下次看到或触摸一个圆形的红色物体时就可以说“苹果”。
监督学习模型以同样的方式工作。为了预测一个有 100 平方英尺和 3 个卧室的房子,模型必须已经在具有相似属性的房子的许多实例上训练过,更重要的是,具有它们的给定价格(在这种情况下是标签)。
由于这些标签是手工收集的,这些任务被称为监督,或者换句话说,由人类控制。
然而,在那里很难找到正确标记的整洁数据集。大多数将是无标签和无结构的,就像社交媒体帖子一样。为了处理这种类型的数据,使用无监督学习算法。
这些算法往往更加复杂和强大。程序员只需在训练数据上启动算法,它就会自己找到标签和有意义的见解。一个非常受欢迎的例子是神经网络,它被用于图像和语音识别、自动驾驶、异常检测和销售预测等领域的当今最先进技术中。
结论
不言而喻,机器学习比这里讨论的要多得多。这是一个令人兴奋和非常有趣的领域,吸引了数百万专业人士。我希望这篇文章是对机器学习的一个很好的介绍,并且你有基本的背景知识来理解更复杂的 ML 主题。此外,每当你被 ML 世界中的一些花哨术语绊倒时,我推荐由谷歌开发者创建的 ML 词汇表。再见!
法典:云之间的桥梁?
原文:https://towardsdatascience.com/codex-a-bridge-between-clouds-835250399fe9?source=collection_archive---------16-----------------------
图片— shutterstock
Codex 可以在 AWS 和 Google Cloud 之间翻译命令吗?
许多企业需要应对多种云环境。AWS、Azure 和 Google Cloud 都有自己的命令集来执行云操作,如设置存储桶、定义服务帐户和其他管理任务。如果能有一种自动化的方法将命令从一个云环境翻译成另一个云环境的等效命令,那就太好了。在这篇文章中,我将继续之前关于 OpenAI 的 Codex 的文章(使用 Codex 在 Keras 和 fastai 之间进行翻译,使用 Codex 将 COBOL 翻译成 JavaScript ),探索 Codex 是否可以帮助应对这一挑战。我将尝试让 Codex 将一系列 AWS 命令翻译成 Google Cloud 的等效命令。
实验 1:创建虚拟机实例
创建虚拟机(VM)实例是一项常见的云任务。我想看看 Codex 是否能把创建 VM 的 AWS 命令翻译成创建 VM 的有效 Google Cloud 命令。我决定从 Codex 示例提示“为库或框架重写代码”开始,如下所示:
// Rewrite this as <TARGET><SOURCE CODE>// <TARGET> version:
从 AWS 文档中用于创建 VM 的示例命令开始,我试图让 Codex 生成等效的 Google Cloud 命令。下面是我在 Codex 中使用的实际提示,带有 AWS VM 创建命令,后跟 Codex 生成的 Google Cloud 代码:
// Rewrite this for Google Cloud
aws opsworks --region us-east-1 create-instance --stack-id 935450cc-61e0-4b03-a3e0-160ac817d2bb --layer-ids 5c8c272a-f2d5-42e3-8245-5bf3927cb65b --hostname myinstance1 --instance-type m1.large --os "Amazon Linux"// Google cloud version:
gcloud compute instances create myinstance1 --zone us-central1-a --machine-type n1-standard-1 --image-project centos-cloud --image centos-7-v20160301 --tags http-server,https-server
我从 Codex 获取输出,并尝试在 Google Cloud 项目的 Cloud Shell 中运行它,命令运行成功:
作者图片
我可以在谷歌云控制台中看到新的虚拟机:
作者图片
Codex 产生了一个可行的谷歌云命令,但它并不完美。特别是,它指定了一个不推荐使用的图像,如以下警告消息所示:
WARNING: Some requests generated warnings:
- The resource 'projects/centos-cloud/global/images/centos-7-v20160301' is deprecated. A suggested replacement is 'projects/centos-cloud/global/images/centos-7-v20160329'.
实验 2:创建一个桶
从 AWS 文档中用于创建 bucket 的示例命令开始,我试图让 Codex 生成等效的 Google Cloud 命令。下面是我在 Codex 中使用的提示,其中带有 AWS bucket creation 命令,后跟 Codex 生成的 Google Cloud 代码:
// Rewrite this for Google Cloud
aws s3api create-bucket --bucket my-bucket-bridge-test --region us-east-1// Google Cloud version:
// gsutil mb -l us-east1 gs://my-bucket-bridge-test
这次,Codex 在输出的开头添加了“//”。我从 Codex 获取输出(去掉注释前缀),并在 Google Cloud Shell 中运行它:
作者图片
我可以在谷歌云控制台上看到新的桶:
作者图片
同样,Codex 从 AWS 输入生成了有效的 Google Cloud 命令。
实验 3:创建安全组/防火墙规则
从 AWS 文档中用于创建安全组的示例命令开始,我试图让 Codex 生成等效的 Google Cloud 命令。下面是我在 Codex 中使用的实际提示,AWS 命令后跟 Codex 生成的 Google Cloud 代码:
// Rewrite this for Google Cloud
aws ec2 create-security-group --group-name my-sg --description "My security group"// Google Cloud version:
gcloud compute firewall-rules create my-sg --description "My security group" --allow tcp:22
我能够在 Google Cloud Shell 中成功运行 Codex 的输出:
作者图片
我可以在谷歌云控制台上看到新的防火墙规则:
作者图片
我承认我无法验证 Codex 生成的 Google Cloud 命令在功能上是否等同于 AWS 输入命令,尽管这个话题表明它至少是在正确的范围内。
结论
本文中的实验非常简单,只是触及了创建和管理云环境所需的全部命令的皮毛。这些基础实验并没有证明 Codex 可以对实际问题做出重大贡献,比如从 AWS 到 Google Cloud 的迁移。然而,有趣的是,Codex 为每个输入 AWS 命令生成了有效的工作 Google Cloud 命令。
OpenAI 的法典,在行动中
原文:https://towardsdatascience.com/codex-by-openai-in-action-83529c0076cc?source=collection_archive---------7-----------------------
为每个编码的人(甚至是不编码的人)提供强大的人工智能驱动的支持。
作者照片
T 何代号是我们这个世界的数字层 DNA。通过掌握代码——它的特征和特性——你建立了我们都生活在其中的数字现实。今天,OpenAI 向我们的 AI 春天揭示了一个新的里程碑(提醒:AI 冬天已经结束),这将使更多的人能够创造:
法典
官博:https://openai.com/blog/openai-codex/
论文:https://arxiv.org/abs/2107.03374
加入候补名单:https://openai.com/join
什么是法典?
OpenAI Codex 是 GPT-3 的后代;它的训练数据包含自然语言和数十亿行公开来源的源代码,包括公共 GitHub 库中的代码。OpenAI Codex 最擅长 Python,但它也精通十几种语言,包括 JavaScript、Go、Perl、PHP、Ruby、Swift 和 TypeScript,甚至 Shell。它有 14KB 的内存用于存储 Python 代码,相比之下,GPT-3 只有 4KB——因此它在执行任何任务时都可以考虑超过 3 倍的上下文信息。[ OpenAI 博客
上个月,你能够见证由 Codex 实现的多种可能性之一——GitHub 与 OpenAI 合作展示了运行在 Codex 上的 CoPilot 。CoPilot 是一个助手,理解你的方法,为你提供例子、提示和适当的代码片段,一个智能自动更正,增强你的编码。
但这仅仅是开始。Codex 是一个强大的变压器驱动系统,可以作为 NLP 模型与 GPT-3 相比较。
就像 GPT 3 号一样,它的使用案例是无穷无尽的。食品法典委员会理解你的任务,并最有效地完成它。
第一步
我们有机会研究法典并尝试它的功能。感觉我们只是在抓表面,我们想分享几个演示,展示与代码交流的新方式。
**但是等等,谁是“我们”?**早在 2020 年,随着 GPT 3 的发布,OpenAI 正在寻找社区大使,他们将帮助和支持不断增长的 GPT 3 社区(后来大约有 6 万名成员)中的开发人员、研究人员、艺术家和作家。他们要求我们中的一些人,论坛中最活跃的用户,来提供帮助——这就是我们, OpenAI 社区大使。我们在开放时间为 GPT-3 用户提供建议,我们集思广益如何增强用户体验,我们还代表大社区与 OpenAI 讨论用户观点。
有时,我们会深入了解 OpenAI 的最新发展,以便更好地向世界传播这些知识。就像法典的情况一样。下面你会看到一些由 OpenAI 社区大使制作的很酷的 Codex 演示。
法典长什么样?
Codex 的当前界面是极简的(并且无疑将会改变,因为 OpenAI 正在继续努力)。
Codex 界面—作者截图
在**字段 1 中,**你可以输入你的任务,用简单的英语(以及几乎所有其他语言,我们将在后面看到)。
字段 2 向您显示由 Codex 生成的代码。
字段 3 预览结果。
做法
你用明文给 Codex 你的指示。生成的代码可用于您的项目——您节省了时间并实现了更高效的工作,您尝试了新的事物,具有创造性,并打破常规进行思考。
当然,编码纯粹主义者可以继续手工编码。法典不会给他们带来挑战或竞争。Codex 使每个人都能够互动地学习和应用代码。法典不会杀死编码员,就像电影不会杀死剧院一样。就像 GPT 3 不会杀作家一样。是的,它改变了我们的工作方式,但它增强了我们的创造力,而不是取代我们。两种方法(人工智能驱动和真正的人类)可以并行存在。Codex 可以让你更有效率、更有效、更有教育意义地编码。
它是如何工作的?就像在 GPT-3 的指令引擎中,你需要输入的所有东西——只要问(礼貌地), Codex 就会完成请求。
你想看看它的实际效果吗?在这个演示中,我们要求 Codex 为一个名为 NTech 的网站创建"一个登录页面","该页面应该处于黑暗模式,带有一个电子邮件列表,供人们注册":
由 Abran Maldonado 演示
当然,你必须设置一个电子邮件,并微调其他元素,但你会看到 Codex 如何将你的需求付诸行动。
谈到法典/无障碍方法。
有了一些变通办法,你可以用你的声音控制食品法典委员会:
布拉姆·亚当斯的演示
这不仅是一个易于编码的有价值的功能,它还将使身体残疾的人能够创造和实现他们的想法和梦想。此外,想想孩子们从与机器的对话中可能获得的巨大教育价值(和乐趣)。
另一种非接触式控制 Codex 的方法是使用您的网络摄像头和动作:
由布拉姆·亚当斯演示
用例
在我们第一次接触这个系统的时候,让我们看看 Codex 能做什么。
数学。
这个系统可以做数学运算:
Russell Foltz-Smith 的演示
评估测试
创建评估测试需要功能和知识——Codex 具备这两方面:
由 Abran Maldonado 演示
应用程序?是的,可以。
【倒计时】
在下面的演示中,使用几个控制按钮实现了倒计时功能。简单—只需要简单的文本:
Natalie Pustinovich 的演示
图像处理
使用 Codex,您可以轻松创建一个简单的应用程序来修改图像:
由 Lucas Negritto 演示
盒子外面
Codex 可以与您的浏览器和计算机系统进行交互。
例如,您可以控制您的网络摄像头,并让 Codex 在网络摄像头流的下半部分将语音转换为文本。
Yash Dani 的演示
该系统甚至允许您控制您的浏览器:
布拉姆·亚当斯演示
体验一下!
由 Codex 提供的“maslo occure”首次展示了一种全新的网络体验,在这种体验中,交互、编辑和呈现是实时进行的:
maslo occure的演示(基于 Codex 的平台)由 Russell Foltz-Smith 完成。
其他语言?
法典是全球性的。再也没有语言障碍了。在我的实验中,我尝试了一个简单的任务:用特定的颜色创建和修改一个形状。但是:我是用英语、德语、日语、俄语问的。
如你所见:结果是一样的。法典明白了!不管你对它说什么语言。
由弗拉德·亚历克斯(默兹曼施)演示
作为讲故事工具的抄本?
当然,抄本不是一个作家。它不是为了写精彩的小说而设计的——如果你想拥有一个人工智能驱动的叙事,你最好使用 GPT-3。但是它仍然可以帮助你。
比如:创造模因。
布拉姆·亚当斯演示
它还能写简单的(或有趣的)诗,并把它们翻译成另一种语言:
Vlad Alex 演示(Merzmensch)
结论
Codex OpenAI 提供了巨大的教育价值:
想象一下在学校使用这个——玩着法典,孩子们会爱上代码。我可以向你保证,他们不会把自己变成那些来自瓦力的懒人,他们会研究和接触。
Codex 使不编码的人能够投入进去,尝试一些东西,并实现他们的想法。艺术家、教师、许多其他职业不涉及编程语言的人将创造他们的方法并实现他们的愿景。
它还将帮助编码人员进行短暂的尝试和打破头脑风暴实验,而不必“仅仅为了尝试”而在编程上投入大量时间。
这个系统是人机交互的巨大飞跃。
更新 1:
这是几个小时前 OpenAI 录制的 CODEX 官方演示,包含更多信息和实验:
更新 2:
2021 年 8 月 12 日星期四有一场法典挑战:https://challenge.openai.com报名法典候补:https://openai.com/join
更新 3 (2021.08.24):
看看这些和更多的演示,由 Sandra Kublik 编辑在这个信息丰富的视频中:
https://www.youtube.com/watch?v=66xTYJrOxKk
Codex 将 COBOL 翻译成 JavaScript
原文:https://towardsdatascience.com/codex-translates-cobol-into-javascript-266205d606c0?source=collection_archive---------33-----------------------
图片— shutterstock
Codex 能把各种 COBOL 翻译成 JavaScript 吗?
今年早些时候,OpenAI 发布了 Codex 作为人工智能驱动的环境,用于处理计算机代码。Codex 可以将英语语言描述转换成代码,从代码创建注释,并从一种编程语言翻译成另一种编程语言。我对与 COBOL 语言相关的 Codex 语言翻译能力特别感兴趣,COBOL 是大型机/穿孔卡时代的通用语言。
我已经发表了几篇文章,描述了 Codex 如何从基本的 COBOL 程序和非平凡的 COBOL 程序中为现代语言生成代码。在本文中,我将从优秀文章 7 COBOL 示例及解释中为 Codex 提供一些额外的 COBOL 示例。JavaScript 是本文中描述的实验的目标语言——我在让 Codex 从 COBOL 生成 Python 方面取得了有限的成功,但是 JavaScript 作为目标语言更有前途。让我们看看 Codex 能否处理更复杂的 COBOL 程序,并将其翻译成 JavaScript。
实验 1:从具有各种变量类型的 COBOL 程序中生成 JavaScript
首先,我想回到第二篇文章中的 COBOL 变量示例,但是这次保留整个 COBOL 程序。下面是开始的 COBOL:
下面是 Codex 从这个 COBOL 输入中生成的 JavaScript 输出,经过清理,删除了无关的 Python 风格的注释:
下面是 node.js 中运行的 JavaScript 的输出:
1ST VAR : 000.00
2ND VAR : -123.45
3RD VAR : ABCDEF
4TH VAR : A121$
GROUP VAR : {
subvar1: 337,
subvar2: 'LALALALA',
subvar3: 'LALALA',
subvar4: 'LALALA'
}
下面是原始 COBOL 的输出:
还不错!在没有干预的情况下,Codex 没有被任何 COBOL 阻塞,JavaScript 产生的输出非常接近 COBOL 程序的输出。
实验 2:用条件从 COBOL 程序生成 JavaScript
现在让我们看看 Codex 是否可以处理 COBOL 条件语句。下面是一个 COBOL 程序,来自 7 COBOL 示例和解释,其中包括各种条件语句:
下面是 Codex 从这个 COBOL 输入中生成的 JavaScript:
以下是 JavaScript 的输出:
IN LOOP 1 - IF BLOCK
IN LOOP 2 - ELSE BLOCK
PASSED WITH 65 MARKS.
NUM1 LESS THAN 1000
下面是原始 COBOL 的输出:
相同的结果!这是 Codex 能够高保真地翻译成 JavaScript 的两个 COBOL 程序。
实验 3:从 COBOL 字符串操作程序生成 JavaScript
COBOL 有一些奇特的字符串操作结构。本实验中的示例程序展示了 COBOL 字符串处理。我们来看看 Codex 是怎么处理的。
下面是 Codex 从这个 COBOL 输入中生成的 JavaScript:
以下是 Codex 生成的 JavaScript 的输出:
WS-CNT1 : 20
WS-CNT2 : 6
NEW STRING : XBCDXDXDXDXBVDFDFFXF
WS-STRING : TUTORIALSPOINTWELCOMETO ANDTUTORIALSPOINTXBCDXDXDXDXBVDFDFFXF1
WS-COUNT : 1
WS-STR1 : WELCOME
WS-STR2 : TO
WS-STR3 : TUTORIALSPOINT
这是原始 COBOL 程序的输出:
让我们看看 COBOL 和 JavaScript 输出之间的一些差异:
- WS-CNT1 :在 COBOL 中,这个变量被分配了 25 个字符的大小,尽管它只有 20 个字符长。
- WS-CNT2 :这是 Codex 处理 COBOL 最好的例子之一——它正确地解释了 COBOL 结构检查 WS-STRING 计数 WS-CNT2 的所有‘A’,并在 JavaScript 中实现了一个 FOR 循环,实现了相同的目标。
- 旧字符串 : JavaScript 完全忽略了这个输出
- 新字符串:两个输出相同
- WS-STRING : JavaScript 没有接近这个字符串
- WS-COUNT : JavaScript 初始化了这个变量,但是错过了处理
- WS-STR1,WS-STR2,WS-STR3 : JavaScript 得到了正确的字符串分段,但是打乱了子字符串的输出顺序。
这个实验有一些很好的结果,但总体来说,它表明如果没有人工清理,Codex 无法生成功能上等同于 COBOL 字符串操作代码的 JavaScript。
实验 4:从 COBOL 循环程序生成 JavaScript
COBOL 有一些循环结构,现代语言的程序员会觉得很奇怪。在这个实验中,我们将采用一个具有各种循环设置的 COBOL 程序,看看 Codex 是如何处理它的。
这个程序的 Codex 输出没有产生有效的 JavaScript——它缺少变量定义。注释是在 JavaScript 上执行的,但是在 node.js 中运行时产生了代码错误。
为了尝试获得有效的 JavaScript 输出,我从 COBOL 程序中删除了注释,并重新运行 Codex 翻译以获得以下 JavaScript 输出:
下面是这个 JavaScript 的输出:
In B-PARA-TIMES
In B-PARA-TIMES
In B-PARA-TIMES
WS-CNT : 0
WS-CNT : 1
WS-CNT : 2
In C-PARA-THRU
In C-PARA-THRU
In C-PARA-THRU
In D-PARA-THRU
In D-PARA-THRU
In D-PARA-THRU
In E-PARA-THRU
In E-PARA-THRU
In E-PARA-THRU
In B-PARA 0
In B-PARA 1
In B-PARA 2
In B-PARA 3
In B-PARA 4
这是 COBOL 的输出:
一些循环的开始和结束条件没有被准确地翻译成 JavaScript,JavaScript 完全丢失了 WS-A 的输出。与实验 3 类似,这个实验表明 Codex 可以处理一些非常复杂的 COBOL 输入,但是如果没有人工清理,它无法生成与 COBOL 循环代码功能相当的 JavaScript
实验 5:从编写文件的 COBOL 程序生成 JavaScript
最后,让我们尝试一个写文件的 COBOL 程序。下面是输入 COBOL 程序,它汇编一条记录并将其写入文件:
这是 Codex 从 COBOL 程序中生成的 JavaScript。注意这个例子的 JavaScript 有多紧凑。
下面是 JavaScript 生成的输出文件的内容:
12345,TEST TRANSACTION,000124.34,000177.54,53.2,1234567,JOHN SMITH
以下是 COBOL 生成的输出文件的内容:
12345TEST TRANSACTION 0001243400017754000053200000000
Codex 在 JavaScript 输出中估算 ACCOUNT-ID 和 ACCOUNT-HOLDER 的值,但在其他方面,输出与 COBOL 程序的输出一致。
结论
以下是我从本文描述的实验中得出的总体结论:
- Codex 可以将一系列 COBOL 代码翻译成可用的 JavaScript。事实上,除了实验 4 中第一个版本的 COBOL 循环程序,Codex 总是能够生成有效的 JavaScript。
- 对于某些 COBOL 语法,包括循环结构和条件语句,Codex 无法始终如一地生成功能等同的 JavaScript。
你可以在这个报告中找到本文描述的实验的输出:https://github.com/ryanmark1867/codex_experiment
这里有一个视频,是这篇文章中的一个实验:【https://youtu.be/2dYSMvlwFjg
编码矩阵
原文:https://towardsdatascience.com/coding-a-matrix-5e1d7eb1e6e5?source=collection_archive---------30-----------------------
我们将实现一个矩阵数据结构,支持像乘积和分解这样的线性代数计算
一种 3×3 矩阵数据结构。图片作者。
通用数组类
矩阵将从一般的类似数组的类继承。array 类可以支持额外的数据结构,如向量和张量。我们希望 array 类支持以下常规属性和方法:
- 以嵌套列表的形式返回数组数据,并计算数组形状。
- 确保数组对象只能用有效的输入数据初始化。
- 支持索引,以便我们可以检索和更新数组的内容。
- 支持加、减、标量乘、标量除等运算符。
数组初始化
数组对象将通过传递包含complex
或float
数字的嵌套数据列表进行初始化。我们将通过检查其形状来验证输入数据是否有效。[1,2,3]
的输入有效,而[1,[2,3]]
的输入无效。一旦输入数据形状得到验证,我们将计算数组形状。
阵列形状
具有 2 行 2 列的矩阵的形状是(2,2)。图片作者。
为了验证数组的形状是否有效,我们可以沿着给定维度的宽度进行迭代,以检查每个元素(将是可迭代的对象)是否具有相同的形状。然后,我们可以使用递归来更深入地遍历数组。停止条件将是当我们到达一个不可迭代的对象(这将是数组元素本身)。
为了计算数组的形状,我们可以假设数据具有有效的数组形状,并递归计算每个维度的长度。
数组索引
设置(左)和获取(右)一个矩阵的元素。图片作者。
我们可以使用 Python 的特殊索引方法来实现数组 getter 和 setter 函数。我们需要确保数组对象有多个维度,这样索引才是允许的。对于 setter,我们需要检查新数组是否具有有效的形状。
数组运算符
添加数组将添加每个数组的相应元素。图片作者。
我们可以利用 Python 的特殊运算符方法来实现加、减、标量乘、标量除等运算。下面是数组加法的实现。
矩阵初始化
要实现一个矩阵类,我们可以从通用数组类继承,并对其形状应用约束。如果输入数据不具有矩阵的形状,则矩阵对象不能被初始化。
矩阵属性
现在我们可以初始化一个矩阵对象,我们可以计算矩阵的各种属性,包括:
- 无论是方阵
- 是否是一个单位矩阵
- 矩阵行列式
- 矩阵轨迹
- 矩阵转置
- 是否是一个对称矩阵
方阵
行数和列数相同的矩阵是正方形。图片作者。
我们可以通过比较矩阵的行和列来检查矩阵是否是正方形的。
单位矩阵
主对角线上为 1 而其他地方为 0 的矩阵是单位矩阵。图片作者。
如果一个矩阵的每个主对角线元素的值都是 1,而其他元素的值都是 0,那么这个矩阵就是单位矩阵。
矩阵行列式
2×2 矩阵的行列式是对角线乘积的差。图片作者。
我们可以用一个拉普拉斯展开来计算矩阵行列式。请注意,还有更有效的算法,如矩阵分解。
矩阵轨迹
矩阵的迹是主对角线元素的和。图片作者。
轨迹可以通过沿着矩阵的主对角线对每个元素求和来计算。我们还需要检查矩阵是否是正方形的。
矩阵转置
矩阵的转置会翻转行和列。图片作者。
要在一行代码中计算矩阵转置,我们可以使用一些 Python 语言的特性;即zip
方法、使用*
操作符的参数解包和列表理解。
对称矩阵
对称矩阵等于它们的转置矩阵。图片作者。
我们可以通过比较一个矩阵与其转置矩阵来检验它是否对称。
包括单元测试在内的整个 matrix 类实现可以在这里找到。
编码训练营——他们是什么样的?
原文:https://towardsdatascience.com/coding-bootcamps-what-are-they-like-6226d0280722?source=collection_archive---------25-----------------------
当我参加一个活动时,我经历了什么
马文·迈耶在 Unsplash 上的照片
毕业后,我从一个漫无目的的大学生变成了一个漫无目的的大学毕业生。拥有我的学位的职业并不是我理想中的。但是我决定完成我的本科学业,而不是转到一个自己不感兴趣的专业。一年多过去了,突然我发现了一件我甚至没有想象过我会喜欢的事情——编程!经过学习和实践,我决定进入科技行业,成为一名全职程序员。
但是即使自学了,在网上看了课,我还是觉得没有做好准备。经过大量的研究,我发现了在可预见的未来会改变我职业方向的东西——编码训练营 。
在这里注册一个中级会员,可以无限制地访问和支持像我这样的内容!在你的支持下,我赚了一小部分会费。谢谢!
编码训练营?
对于那些不知道的人来说,编码训练营是一个有抱负的程序员为了向业内有经验的人学习而参加的机构或学校。他们被教授在该领域找工作所需的有价值的技能和专业知识。它的主要重点是教授编程概念,以便更好地理解和实际应用。换句话说,学生们被教导如何为这项工作编码。
由 Austin Distel 在 Unsplash 上拍摄的照片
当时,我从未真正了解过它们,它们仍然相对较新(尽管它们可能已经存在了九年)。然而,这个概念立即迷住了我。我立刻开始研究一个编码训练营的评论、经历和成果。
根据我的研究,这些训练营并不便宜。我发现的几个训练营都有很糟糕的评论和经历,这让我很警惕。然而,我确实找到了一些享有盛誉的公司。它们仍然很贵,你可能不得不申请学生贷款,但对我来说,这是值得的。
在训练营之前
就我而言,我决定参加纽约一所相当知名的大学的数据科学项目,该项目也有“退款保证”。这种“退款保证”确实有几个条件,以便有资格获得它。它们的范围从一致编码到网络义务以及介于两者之间的一切。在我看来,条件是艰苦的,但也是合理的。
申请和面试
一旦我知道要参加哪个训练营,我就递交了申请。该应用程序本身包括输入一些基本信息和安排与一名员工的视频面试。面试主要是为了评估我对数据科学项目的兴趣以及我为什么想参加。这是非常基本和随意的——他们只是想更多地了解我。后来,他们决定让我提前入学。
照片由 LinkedIn 销售解决方案在 Unsplash 上拍摄
完成我的录取
下一步是与训练营的一名教练进行第二轮面试。这次面试包括一项编码评估,旨在衡量我的编程技能。一开始有点令人紧张,但我得到了一些编程资源,可以提前热身。面试本身非常简单,编码挑战本身也很简单。导师对我的表现很满意,并同意我参加今年夏天的数据科学项目。
在交了定金以确保我的位置后,我被允许进入学校的在线平台,在那里我被要求通读并“跟着代码”几节入门课。我也获得了更多关于我应该期待什么以及如何为第一天做准备的资源。彻底复习后,我准备好了…
开学第一天
在我的第一天,我遇到了许多来自不同项目的有抱负的程序员。我们被分成我们选择的训练营项目,并被引导到大楼的不同区域。建筑的不同部分和房间容纳了每个项目的参与者。大约有 25 人参加了我的数据科学班,也就是所谓的小组。
当我们到达数据科学区时,我们每个人都被分配到一个个人办公桌,在那里我们可以完成大部分工作。很快安顿下来后,我们被通知到教室集合,正式见面。
老师们
照片由 Unsplash 上的 NeONBRAND 拍摄
我们的团队配备了一位具有真实世界数据科学经验、热爱教学的主要讲师。我们还有两位数据科学教练,他们是该项目的前学生。在整个项目期间,只要我们需要,这些教练都会帮助我们。
随着时间的推移,我们都是通过几次破冰游戏相互介绍认识的。之后,我们听了一个简短的讲座,内容是我们的课程和日常活动会是什么样子。
课程
我们在整个项目中的学习大部分是在我们自己的电脑上完成的,还有许多讲座和小组项目。训练营有一个强大而全面的在线平台,包含了我们需要学习的所有课程。然而,我们不允许挑选我们想学的。随着我们作为一个团队一起进步,每周都会有一些课程被解开。这样做是为了让我们都在同一页上,一起学习。
位置
训练营的校园位于曼哈顿的金融区。这是一个伟大的地区,有一吨的地方吃午餐休息,并位于水边。训练营本身非常整洁。它有一个开放的布局,各种教室和私人摊位。我会说它有现代、新兴的科技公司的感觉。我觉得这是一个学习数据科学的好地方。
学校正常的一天
每天早上,我们被随机配对进行“结对编程”。在这里,我和我的搭档接受了一个编码挑战,并被告知要在 30 分钟左右的时间内解决它。这些挑战反映了真实世界的编码面试挑战。随着时间的推移,结对编程的难度会增加。
结对编程后,我们会聚集在教室里学习当天的课程。这节课将设定一天或一周的重点,由主讲老师给我们讲。这一课将很快在我们被要求完成的在线平台上为我们解锁。
学习过程
我们在讲台上的学习大部分是我们坐在一起自己完成的。大多数课程遵循这个简单的模式:
- 阅读和学习课文。
- 根据课程内容编写代码。
- 做一个与课程相关的迷你编码项目。
韦斯·希克斯在 Unsplash 上的照片
如果我们发现自己被困在一个问题上,我们被鼓励去找我们的同学或教练。
一整天也有一些讲座。这些讲座与当天或一周的当前课程相关。对于数据科学,它通常涉及统计或编程。
我在训练营的大部分时间里,这个学习过程都是这样进行的。
小组项目
除了学习方面,很多时候我们被召集在一起参与小组项目。通常是三人或更少人一组。其目的是让我们熟悉编程和数据科学环境中的协作和合作。这些项目本身也将为潜在雇主建立我们未来的投资组合。
我们被指示开发一个与我们正在研究的当前数据科学主题相关的项目,并让我们自己决定如何合作。用于小组项目的时间长度从几天到一整周不等。
和小组演示
很多时候这些项目伴随着小组报告。这些演示基于我们项目的幻灯片。我们被教导要把重点放在项目的商业应用上,以更好地模拟现实世界的期望。
这些小组项目为我们每个人独特的编码风格提供了真正的见解。学习如何与他人合作,看看我们每个人是如何处理各种问题的,这是有趣和有益的。
特别活动
雅各布·达尔比约恩在 Unsplash 上的照片
在整个项目过程中,我们会多次举办特别活动。这些活动包括周五下班后在训练营举行的派对,以及在技术领域邀请演讲嘉宾提供食物。这些特殊事件发生的确切时间各不相同。有时是在午餐时间,有时是在下午 6 点以后。
其他时候有每周的活动,我们会在周末聚在一起讨论一周的感受。有时会有团队建设游戏,我们都可以参加。在纽约市的许多地方,我们都被鼓励去参加校外的联谊活动。
最终项目
在数据科学项目的最后几周,我们被分配了一个期末项目。这是我们计划中最伟大的项目。我们会在求职面试中自豪地展示出来。
我们可以为我们的项目选择任何主题,只要我们应用我们新学到的数据科学工具和知识。不再有小组项目——这个项目将由个人完成。我们仍然可以在某些方面寻求建议,但项目的其余部分取决于你。
新环境
为了在最后几周容纳我们,我们搬到了另一栋大楼的共同工作空间。我们将利用这个新空间来建造我们的项目。新的空间也更好,尽管我们与其他公司共用一层楼。其他公司有他们自己的房间,但我们共用公共区域和厨房。如果训练营有科技创业的感觉,这个地方有科技公司的感觉。
也是最后的陈述
马库斯·斯皮斯克在 Unsplash 上的照片
我们在项目的最后三周致力于期末项目。但更像是两个半。在最后一周的中间,我们要向学校的其他学生和任何想看的人展示我们的期末项目。演示是以一种科学博览会的方式进行的,观众们漫步到我们的每一个项目来观察我们的工作。
在做最后一个项目
我们每个人都很快去上班了。集思广益,征求意见。我们的教练和指导员会偶尔检查我们,看看我们做得如何,并确保我们在正确的轨道上。即使在这个项目上花了两个半星期,我们中的许多人仍然觉得时间不够。很多时候,我们中的一些人会发现自己熬夜只是为了完成一件事。就我而言,我几乎总是呆到晚上 8 点。
我想说在我的项目中工作是一个顺利的过程,但不是。我中途转向修复一个自己造成的错误。在整个项目中,我也有了各种各样的认识,这使我回溯了我所做的事情。最后,我还是按时完成了,我为自己的成就感到骄傲。
我的最终项目
如果你好奇的话,我以前的一篇文章实际上涉及了我最后一个项目的一个具体特征:
https://medium.com/swlh/teaching-a-machine-to-trade-stocks-like-warren-buffett-part-i-445849b208c6 [## 我建立了一个机器学习模型,像沃伦·巴菲特一样交易股票(第一部分)
medium.com](https://medium.com/swlh/teaching-a-machine-to-trade-stocks-like-warren-buffett-part-i-445849b208c6)
我的项目的最终演示也涉及到一些其他的机器学习功能。我建立了一个平台,人们可以使用大量的机器学习算法来分析任何公司的股票。我还为我的项目构建了一个前端,使它更有吸引力,这是我花了几天时间编写的。
总的来说,我花在构建项目上的时间极具挑战性和成就感。我很高兴我能按时完成我的项目,尽管有一些障碍迫使我熬夜。
训练营结束后
当我们离项目毕业还有一两周的时候,我们被指派了一名职业教练。这位教练会通过给我们建议和对求职过程的见解来帮助我们毕业后找工作。
如果你想知道更多关于我在训练营之后的时间,请随意阅读我的另一篇文章:
毕业过程非常平淡。没有像大学那样的大型仪式,但我们班更私人。毕业后,我们出去喝了几杯,开始了下一步。
我对新人的建议
如果你想参加编码训练营,这里有一些建议:
- 寻找成熟的编码训练营。
- 你会写很多代码,所以在参加之前先练习一下,这样你就不会感到不知所措了。
- 慢慢来,不要害怕在其他人都回家后呆很久。
- 尽可能多参加活动,带上你的同学。
- 做好独立学习的准备,但是向你的同伴、教练和指导者提问和寻求建议也是可以的。
照片由海伦娜·洛佩斯在 Unsplash 拍摄
你应该这样做吗?
我不建议你参加编码训练营,除非你喜欢以这样或那样的方式编码。这次经历绝对是独一无二的,我深深地享受着每一刻。我喜欢我在那里的时光,我会把它推荐给任何想进入科技行业的人!
注:我的经验是 Covid 之前的,所以它可能不能准确反映今天的训练营编码状态。
金融科技的编码语言:JVM 如何让你成功?
原文:https://towardsdatascience.com/coding-languages-for-fintech-how-will-jvm-make-you-succeed-89f84af22296?source=collection_archive---------8-----------------------
Java,Kotlin,Groovy,Scala,Clojure
来源:贝尔软件
BellSoft 正在用金融科技企业的顶级语言来结束 2020 年。无论你是一个正在启动你的第一个 MVP 的初创公司,一个正在崛起的企业,还是一个正在寻找创新优势的老牌公司,这个列表保证满足你所有的 IT 需求。
在这里,我们将解释为什么应该选择 JVM 语言而不是特定于平台的本地语言,看看它们的关键特性和排名。我们将特别关注语言如何应用于用例场景,涵盖从金融和银行到保险的一切。这个列表将帮助你了解每一个提供的优势和机会。在选择最适合您的项目的编程语言时,您可以遵循我们的建议。
介绍
在这项比较研究中,我们从各种来源收集数据,根据不同的参数对语言进行排名:
- TIOBE 编程社区索引,
- 编程语言流行指数(PYPL)、
- JetBrains,Stack Overflow 和 GitHub 开发者调查。
我们的研究仅涵盖 2020 年,因此你可以获得最相关的行业概况——因为在金融科技领域,了解最新动态至关重要!
但是首先,我们想解释一下这篇文章的重点。许多人会说 Python 最适合金融科技公司,因为它对开发人员友好,适应性强。尽管这可能是真的,但对高风险企业来说,它缺乏某些好处。从历史上看,金融机构广泛使用的是 Java。考虑到数据安全性、生产率和稳定性是他们的首要任务,他们经常转向基于 Java 的语言。
1995 年,詹姆斯·高斯林引入 Java 作为高级面向对象编程语言。从一开始,它的一个关键特性就是平台独立性,这是由 Java 虚拟机(JVM)带来的。JVM 从底层物理硬件和操作系统中抽象出来。有了这种高效的程序执行方式,Java 开发人员就不需要关注对象生命周期管理或其他底层的复杂问题。相反,他们能够将全部精力投入到业务逻辑中。
多年来,JVM 在垃圾收集、性能和成熟度方面有了显著的改进。编程语言设计者意识到了这种运行时的潜力。因此,许多著名的、主流的、甚至更新的语言都是用 JVM 提供的特性和巨大的类库开发的。每个企业现在都可以找到满足其需求的解决方案。
当甲骨文在 2018 年 7 月为 JDK 推出基于订阅的许可时,IT 社区内部对 JVM 的状态存在轻微的不确定性。幸运的是,由于 OpenJDK 倡议,JDK 规范仍然是免许可和开源的。一些公司现在提供他们自己的开源 Java SE 实现,包括 BellSoft。其 Liberica JDK 是市场上领先的运行时之一,具有可选的企业支持。
既然我们已经介绍了历史,那么是时候进行我们的抵抗了:金融技术行业的最佳 JVM 语言列表: Java、Kotlin、Groovy、Scala 和 Clojure 。你会发现猜第一个不会太难…
1.Java 语言(一种计算机语言,尤用于创建网站)
Java 是商业应用程序开发的主要选择,也是最主要的语言之一。它是第一个构想并广泛接受“编写一次,在任何地方运行”范式的公司,该范式专注于开发人员的生产力和人体工程学。它为 Python、JS 和 Kotlin 等其他语言的成功铺平了道路。Java 采用了许多实用的概念,如内存模型、中间表示(字节码)、多线程和作为一等公民的处理函数。作为迄今为止最具颠覆性和影响力的编程语言之一,Java 已经永远地改变了软件开发的前景。
让我们看看为什么它现在几乎和 25 年前一样成功:
稳定可靠
N26 ,一家在单一欧元支付区和美国提供服务的德国新银行,使用 Java(确切地说是 RxJava)来构建 Android 应用程序。1 它提供了一个标准工作流来管理应用程序中的所有数据和事件。这就是它在 Android 开发者中日益流行的原因。工程团队实现了关注点的清晰分离,这使得特性更容易在代码中导航,并改进了代码审查。
看一看应用程序功能的一个简短片段,显示用户信用草稿列表:
Flowable<Option<List<CreditDraft>>> getAllCreditDrafts() {
return store.getAll();
}Completable fetchCreditDrafts() {
return creditService.getCreditDrafts()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.computation())
// map from raw to safe
.flatMapObservable(Observable::fromIterable)
.map(creditDraftMapper)
.toList()
// put mapped objects in store
.doOnSuccess(store::replaceAll)
.toCompletable();
}
Java 不是为移动开发而构建的?我们不同意。一个银行系统,无论是运行在服务器上还是云中,都必须是健壮的,能够持续工作多年,而不需要做任何调整。在这里,Java 是一种理想的语言,拥有一个大型的、成熟的生态系统和不间断的变化。
曾经流行过
Java 是目前为止企业和后端开发中使用最多的技术。大多数流行的编程语言排名网站都倾向于将它放在首位。
专门评估和跟踪软件质量的 TIOBE 将 Java 评为 2020 年第二大最受欢迎的语言,也是过去 20 年中最受欢迎的两种语言之一!在此期间,它只被 C 语言超越过几次。
来源: TIOBE
对于 2020 年, PYPL (编程语言流行指数),基于谷歌趋势数据,将 Java 列为仅次于 Python 的第二大流行编程语言。这里我们想指出的是,Java 只是在 2018 年失去了领先地位。
来源: PYPL
此外, JetBrains 的第四次年度开发者调查将其排在第二位,仅次于 JavaScript。
来源: JetBrains
裁决
Java 正面临来自 Python 和 JavaScript 的激烈竞争。它可能永远不会拥有曾经在该行业拥有的市场份额。然而,开发人员仍然认为学习 Java 是对未来的安全投资,因为职位空缺的数量和以前一样多。考虑到 Java 的采用量和它最近的许多创新,它将仍然是未来商业软件开发的首选。
2.科特林
最近,Java 在开发人员体验和人机工程学方面受到了很多批评:它冗长,产生样板代码,容易出现意外特性,并且缺少许多现代特性。其他几种语言试图解决这些缺点,努力成为“更好的 Java”我们坚信科特林是其中的佼佼者。
流行的 IntelliJ IDE 背后的公司 JetBrains 在 2016 年发布了 Kotlin。它试图在不影响编译时间的情况下解决 Java 的问题。Kotlin 引入了许多来自其他先进的、高生产率语言的优秀特性。它被认为是 Java 的更简单、更现代、更简洁的替代品。
Android 和许多企业应用支持旧的 LTS 版本的 Java。在这种用例中,Kotlin 为开发人员提供了更强大的现代语言特性,因为 Kotlin 可以面向各种旧的 JDK 版本(如 Java 6 或 7)。
2019 年,当谷歌宣布 Kotlin 为首选 Android 应用程序开发选项时,kot Lin 获得了显著的推动。但为什么增长如此之快呢?
两全其美
万事达卡与 Corda 达成合作伙伴关系,共同开发并试点一种新的基于区块链的跨境支付解决方案。2 它连接由万事达卡运营的清算和结算网络支持的全球快速支付基础设施、方案和银行。Corda 是一个用 Kotlin 编写的开源区块链项目,用于存储、管理和同步各种金融机构之间的金融义务。
这个例子摘自 Corda 项目:
/ Add this import:
import net.corda.core.identity.Party
// Replace TemplateState's definition with:
@BelongsToContract(TemplateContract::class)
class IOUState(val value: Int,
val lender: Party,
val borrower: Party) : ContractState {
override val participants get() = listOf(lender, borrower)
}
如果团队希望一方面利用创新,另一方面利用 JVM 提供的可持续性,Kotlin 是理想的选择。与 Java 相比,这种语言以其进步的特性、平坦的学习曲线和更高的开发速度吸引着许多公司。
在上涨
Kotlin 于 2016 年首次发布,越来越受欢迎,正在成为顶级趋势语言。截至 2020 年 12 月,它在 PYPL 上排名第 13,仅次于 TypeScript 和 Go。看到它在 Ruby(第 14)这样的强手之上,已经是一个相当令人印象深刻的结果了。
Kotlin 专为更好的开发人员人体工程学而设计,在全球范围内广受欢迎。根据 Stack Overflow 2020 开发者调查,对于近 63%的受访者来说,它是第四大最受欢迎的语言,仅次于 Python。
根据 GitHub Octoverse 的数据,2019 年至 2020 年间,它的年同比增长率为 182%,是全球增长最快的编程语言之一。
JetBrains 2020 年开发人员调查表明,Kotlin 是开发人员最想移植和采用的三种主要工具语言之一:
来源: JetBrains
裁决
Kotlin 是少数几个在酷功能和简单性之间取得平衡的例子之一。下一个十年,它肯定会更受欢迎。对于那些想学习一门高产语言或尝试 Android 应用程序开发的好奇者来说,Kotlin 是一个绝佳的选择。一些人甚至声称,在不久的将来,押注科特林将是一个明智之举。你可以在 BellSoft 关于 Kotlin 的两部分系列文章中了解更多关于它的特性以及这种语言对行业的意义。
3.绝妙的
在特定的场景中,从开发速度的角度来看,动态类型语言比静态类型语言有显著的优势。受 Python 和 Ruby 的启发,James Strachen 在 2003 年开始为 JVM 开发动态类型编程。四年后,Groovy 作为同类产品中的第一个问世。它引入了类似 Python 的干净编码和类似 Ruby 的动态性。
Groovy 是一种值得尊敬的语言选择,并被广泛使用,原因如下:
它是可选的类型和多范例(面向对象的、函数式的、命令式的、脚本式的)。
Groovy 带来了许多实用功能:类型推断、多行字符串、闭包、原型扩展。这种方法后来严重影响了其他语言,如科特林。
- 它与 Java 无缝兼容,并拥有庞大的库生态系统。很多流行的框架,比如 Spring,都支持 Groovy。
- 它可以用于特定领域语言(DSL)。它还支持在运行时实现特征。
- 通过元对象协议而不是直接调用方法来调度方法使其具有很高的性能。
- Groovy 现在是 Apache software foundation 的一部分,在业界得到了广泛应用。由于其动态、简洁的特性,它是脚本、工具和开发人员的理想选择。Gradle、Jenkins 和 SoapUI 等流行工具使用 Groovy 作为主要编程语言。处于 DevOps 和架构领域也延长了它的生命周期。
速度是关键
总部位于澳大利亚的 Auto & General Insurance 有限公司需要内部工具来管理其 DevOps 系统。它计划为 Gradle 创建一个类似 Maven 原型的插件,从本地模板生成项目。对于这个其他系统依赖的小规模项目来说,快速开发至关重要。由于 Groovy 的动态特性、对 DSL 的支持以及在 DevOps 领域的广泛采用,它是与公司现有工具进行互操作的最佳选择。
一点点可以走很长的路
Groovy 是一种成熟的编程语言,在 JVM 中提供了类似 Python 的生产力。这种组合证明了它在各种小型任务中的优势:工具、脚本、概念开发的证明。因此,尽管它不是像 Java 或 Kotlin 那样的通用语言,但它还是相对较受欢迎。
2020 年 12 月,Groovy 从第 12 位升至第 11 位。
然而, PYPL 指数同月排名第 23 位:0.45%的市场份额似乎并不值得夸耀。
裁决
可选类型的 Groovy 不适合大规模开发:它的好处在于快速交付和动态性。方法缓存和其他实用特性是出色性能背后的秘密。企业认为 Groove 是一种成熟的语言,无论如何都会有用户。
4.斯卡拉
从事 Java 泛型和当前 Java 编译器 javac 工作的 JVM 老手 Martin Odersky 决定研究 Java 的缺点。2004 年,他发布了 Scala,结合了许多函数式编程特性和面向对象的范例。它成为最早将 JVM 作为运行时平台的语言之一。Scala 成功地加速了技术进步,并直接促进了 Java 的现代化。如果没有这种语言,这个行业就不一样了:在过去的十年中,它在推广函数式编程范例方面发挥了关键作用。
它有什么特点?
惊人的表现
2016 年, PayPal 将 Scala 作为其系统的一部分,以增加其可以接收的交易量。5 基于 Akka(一个运行时和工具包,用于简化在 JVM 上构建应用程序)和 Akka Streams,由 Scala 和 Kafka 提供支持;他们新的开源 squbs 平台展示了令人难以置信的结果。应用程序每天处理超过 10 亿次点击,“每个应用程序只有 8 个虚拟机和 2 个虚拟 CPU。”之前,有了 Spring/Java 组合,公司的业绩几乎是团队所取得成绩的十分之一。
PayPal 对技术堆栈的要求是:
- 水平和垂直可扩展性,
- 近乎实时的性能,
- 高效的资源利用(最有可能用于云部署),以及
- 高爆裂下的弹性。
下面你会看到一个永恒的流,它随着系统而开始和停止。它提供了一个便利的特性,可以帮助编写由系统生命周期控制的流,同时最小化甚至消除消息丢失。它提供了定制钩子和 killSwitch(来自 Akka)来嵌入到流中。
class MyStream extends PerpetualStream[Future[Int]] {
def generator = Iterator.iterate(0) { p =>
if (p == Int.MaxValue) 0 else p + 1
}
val source = Source.fromIterator(generator _)
val ignoreSink = Sink.ignore[Int]
override def streamGraph = RunnableGraph.fromGraph(
GraphDSL.create(ignoreSink) { implicit builder =>
sink =>
import GraphDSL.implicits._
source ~> killSwitch.flow[Int] ~> Sink
ClosedShape
}
)
}
在这里,Scala 非常适合其函数式编程特性以及与 Apache Spark 和 Apache Flink 等主流流媒体平台的潜在互操作性。
总能找到自己的目标
尽管 Scala 发布时被看好,被认为会超越 Java,但它仍然是一种特殊用途的语言。我们看到它的采用在过去五年里趋于平缓。但是在数据密集型应用和流处理领域,Scala 几乎超越了所有其他应用,包括 Java 和 Kotlin。此外,许多广受好评和流行的框架和运行时支持该语言(如 Akka、Play、Finagle、Lagom),证明了它在行业中的强大立足点。
裁决
Scala 在改进 Java 方面有发言权,并影响了许多其他现代语言,包括 Kotlin 但是它还没有得到更广泛的接受。它多年来引入的许多突破性变化在企业中并没有得到很好的接受。它真正擅长的一件事是流处理,上面的 PayPal 用例显示了这一点。最新发布的 Scala 3 最终采用了实用主义特性,成为一种更主流的语言。我们确实希望这个版本有潜力使它成为通用的,并在更大范围内使用。
5.Clojure
Lisp 是最早的高级编程语言之一,发布于 1958 年。很久以后,一位著名的软件工程师 Rich Hickey 致力于创建一种针对 JVM 的动态的、功能性的通用 Lisp 方言,后来成为 Clojure。与结合了面向对象和函数式范例的 Scala 不同,Clojure 是一种纯函数式语言。它有一个 Lisp 宏系统,把代码当作数据,把程序当作模型。Clojure 鼓励不变性和不可变的数据结构,并明确管理身份及其状态。
我们可以把它的主要特点总结如下:
微观分析
Nubank 是拉丁美洲最大的金融科技公司,于 2018 年成为独角兽创业公司,它与 Clojure 开发了一个复式会计系统。该公司声称这是“一项使用了几个世纪的古老技术”,它与这种函数式编程语言有着奇妙的联系。在它的要求中,Nubank 提到语言应该能够并行处理,提供可维护的代码,并管理变量。
这里有一部分代码展示了运动的声明性规则:
(def new-purchase
[{:entry/debit-account :book-account.asset/settled-brazil
:entry/credit-account :book-account.liability/payable-brazil
:entry/amount (comp :amount :purchase)
:entry/post-date (comp time->date :time :purchase)}
{:entry/debit-account :book-account.liability/payable-brazil
:entry/credit-account :book-account.profit-and-loss/interchange-brazil
:entry/amount (comp :interchange :purchase)
:entry/post-date (comp time->date :time :purchase)}
{:entry/debit-account :book-account.liability/current-limit-counterparty
:entry/credit-account :book-account.asset/current-limit
:entry/amount (comp :interchange :purchase)
:entry/post-date (comp time->date :time :purchase)])
这种系统允许通过任何标准行为对特定用户或用户组进行分析。例如,该公司可以预测其客户明年将花费多少。
非常适合绿地
由于其开发速度和干净的代码,Clojure 越来越受到从零开始从事大规模项目的公司的欢迎。对于特定的用例(例如,并发编程、大数据项目),它是一种优秀的语言;缓慢但稳定地,它在行业中获得牵引力。尽管如此,Clojure 还不是一种通用的主流编程语言。
裁决
尽管 Clojure 在它所做的事情上非常优秀,但它缺乏 Kotlin 或 Groovy 的实用主义。企业通用语言既需要面向对象的范例,也需要函数式范例。我们预测 Clojure 不会超出它的范围,仍然是专用的。
摘要
到目前为止,JVM 是使用最广泛的进程虚拟机。它强大,久经沙场,经受住了时间的考验。在本文中,我们解释了金融科技公司如何从 JVM 的多功能性中受益,并总结了 5 种基于 JVM 的顶级语言,每种语言都有其优势和特定的用例。
使用这五个选项中的一个,任何业务任务都是可能的。您可以放心,在任何情况下,您的解决方案都将是高性能的、实施快速的,并且在未来许多年都是适用的。
如果您想进一步了解基于 JVM 的解决方案如何推进您的业务,请联系 BellSoft。该公司的工程师愿意分享他们在 JDK 世界工作十年来收集的最佳实践。他们会很乐意回答您的所有问题,并提供满足您需求的渐进式 Java 运行时。
参考
- n26/n26 androidsamples GitHub
- 万事达卡与 R3 合作开发基于区块链的新型跨境支付解决方案
- 科达 GitHub
- 汽车&通用保险有限公司 GitHub
- PayPal 仅使用 8 台虚拟机,通过 Akka、Scala、Kafka 和 Akka 流,每天就能完成超过 10 亿笔交易
- 建立强大的复式记账系统——卢卡斯·卡瓦尔康蒂
我与BellSoft合作撰写了这篇文章,原文发表于【https://www.bell-sw.com】。
类似文章
* </21-predictions-about-the-software-development-trends-in-2021-600bfa048be> *