TowardsDataScience 博客中文翻译 2016~2018(三百三十)
与熊猫争论数据
熊猫以竹子为食,非常擅长长时间睡眠。但是他们也有一个秘密的力量:啃下大数据集。今天,我们将介绍数据争论中最强大和最受欢迎的工具之一,它叫熊猫!
当你想到数据科学时,熊猫可能不是第一个想到的。这些黑白熊通常大部分时间都在吃竹子和睡觉,而不是做数据科学!但是今天,我们将使用熊猫来操作我们的数据集,并为机器学习设置它。我不能在一个视频中对整个图书馆进行公正的评价,但希望这个概述能帮助你开始,我会让你更深入地探索熊猫的迷人世界。
Chomping on datasets! This dataset looks like bamboo, however.
Pandas 是一个开源的 python 库,它提供了易于使用的高性能数据结构和数据分析工具。撇开 Cuddley bears 不谈,这个名字来自术语‘panel data’,指的是统计学和计量经济学中遇到的多维数据集。
要安装 pandas,只需在 python 环境中运行pip install pandas。然后我们就可以import pandas as pd了。
熊猫最常见的用途之一是使用pd.read_csv读取 CSV 文件。往往是利用熊猫的起点。
pd.read_csv将该数据加载到数据帧中。这可以被认为本质上是一个表格或电子表格。我们可以通过在数据帧上调用head()来快速浏览一下我们的数据集。
数据帧包含带有命名列的数据行,在 pandas 中称为“系列”。
对我来说,Dataframes 最棒的地方之一是describe()函数,它显示了关于 Dataframe 的统计表。这对于检查数据集的完整性非常有用,可以查看数据的分布是否合理,以及属性是否符合您的预期。
我有时也会用熊猫来打乱我的数据。这在您想要混洗整个数据集而不仅仅是在提取数据时有一个先行缓冲区的情况下非常有用。例如,如果您的数据根本没有被打乱,而且实际上是排序的,那么您会希望对它进行额外的混合。
然而,对于不适合内存的非常大的数据集,如果没有更复杂的方法,这可能是不切实际的。
列访问
要访问数据集的特定列,请使用括号符号来提取该列,并传递该列的名称。如果您想知道可能的列名是什么,您可以回顾一下.describe()输出的顶部,或者使用.columns将数据帧中的所有列作为一个数组来访问。
行访问
访问数据帧的行与访问列略有不同。例如,如果我们想要一个给定数据帧的索引为i的行,我们可以使用.iloc[i]。
This is index 5, so it’s the 6th row of data
请记住,Pandas 是基于 0 的索引系统,所以第一行实际上是索引 0。
列和行在一起
有时您可能需要特定的行和列。因为行和列的访问方式不同,所以我们需要结合上述技术来完成这项工作。
你也可以把事情调换一下,使用csv_data.iloc[5][‘sepal_len’],但我觉得这样可读性较差。
行和列范围
更有趣的是当你想得到一系列的行和列时。
在列方面,获取多列的方法是传入一个列名数组。
如果需要输入更多的列名,您可以使用csv_data.columns输出数组并从中选择一系列列名,然后使用它来选择列。
I guess I could have just typed the names of the 2 columns … but you get the idea.
如果我们想要得到一系列的行,我们在跟随.iloc的括号内使用冒号符号:
包括起始索引,但不包括结束索引。请注意,这会返回行索引 5、6、7、8 和 9,但不会返回行索引 10。
行和列的范围
假设我们两个都想要——列的子集和行的子集。那会是什么样子?我们可以将目前使用的所有技术结合起来,做出一个表达式来完成这项工作。
首先,像前面一样选择列名:
cols_2_4 = csv_data.column[2:4]
然后我们得到列:
df_cols_2_4 = df[cols_2_4]
现在从该数据帧中选择行:
df_cols_2_4.iloc[5:10]
一旦你掌握了窍门,你将开始把这些变量压缩成一个表达式,就像这样:
csv_data[csv_data.columns[2:4]].iloc[5:10]
我鼓励你在这里停下来,看看这个表达式是如何等价于我们刚刚在上面展示的。你回来的时候我还会在这里。
包扎
Pandas 中的链接操作不仅能让你更快地处理数据,而且一旦你掌握了它,它的可读性会更好。
到目前为止,我们已经看到了一些简单的数据帧操作,但是熊猫生态系统还提供了更多的功能,从 PyTables 和 HDF5 格式的高效文件存储,到运行各种统计分析。
走出去,尝试野生大熊猫!
感谢阅读这一集的云人工智能冒险。如果你喜欢这个系列,请为这篇文章鼓掌让我知道。如果你想要更多的机器学习动作,一定要关注媒体上的我或订阅 YouTube 频道以观看未来的剧集。更多剧集即将推出!
带有 map、reduce、filter 和 ES6 的 Javascript 数据结构
如果你是一个 javascript 爱好者,并且每天都在使用它,那么你会爱上它的😃
Javascript 是一种允许以任何风格编写代码的语言,从命令式到声明式。大多数程序员使用命令式,要么是因为他们来自 OOPs 背景,也许他们热爱它,要么是因为他们不熟悉其他风格。在我们深入到函数式编程(FP)的声明式风格之前,让我们通过看一个例子来理解两者之间的区别(如果你已经知道区别,那么你可以跳过几段)
必要的
命令式风格很酷,但是想象一下,如果这里有一个复杂的数学逻辑,那么代码的大小和可读性将会很差。它增加了阅读时的认知负荷,随着时间的推移,在推理和逻辑上更容易动摇。
此外,这段代码片段的主要复杂性源于这样一个事实,即我们不是告诉计算机我们想要它做什么,而是指示它如何做。
宣言的
现在,这看起来非常干净、简短、有表现力、简洁的代码,不容易出错,更容易维护,也更容易调试。我们是在告诉计算机我们想要它做什么,而不是如何去做。
声明式方法在编译器端很容易优化,副作用也较少。
注意:如果你关心上面两个和其他 javascript 函数(map、reduce、filter、find)的性能,那么你应该在这里阅读获取小数据集,可以在这里查看获取大数据集(100–1000000)
让我们从 FP 最常用的 Javascript 函数— .map()开始真正的操作。
地图
// definition
collection.map((currentValue, index) => {
// Return element for newArray
});
// example
const arr = [1,2,3,4,5];
const newArray = arr.map(i => i*10);
// return a new array with all value as multiple of 10;
map 作用于一个数组并返回一个数组。上面的代码片段作用于一个集合,即一个数组,接受一个带有当前迭代值的回调,索引作为参数,并返回一个新的数组。
注意:Map 非常适合改变/转换整个数组,而不是在某些情况下中断流程,Map suck 的性能明智,请查看此处的但易于用于小数据集。
减少
// definition
collection.reduce((accumulator, item, index) => {
// logic to perform to get accumulator as a return value
}, initialValue for accumulator);// example
const arr = [1,2,3,4,5];
const total = arr.reduce((acc, item) => acc+= item, 0);
// return a total as 15
Reduce 在一个数组上工作,但是可以返回任何你想让它返回的东西。顾名思义,它可以简化为任何形式,可以表现为map、find、filter或任何其他 JavaScript 数组函数。上面的代码片段作用于一个数组,并简化为计算数组中项目的总值。
解释上面的例子,在第一次运行 reduces 时,acc被赋值为 0,然后acc+= item即acc = acc+item将计算出为 1 的0+1。这个 1 将是下一次迭代的acc值,这将一直持续到我们完成所有的数组项。
发现
// definition
collection.find((item) => {
// return first element that satisfy the condition
});// example
const arr = [1,2,8,4,5];
const value = arr.find(i => i%4 == 0);
// return the first value i.e 8
Find 作用于数组,返回函数中满足条件的第一个元素。
注意:容易,简单但在大数据集上效率不高,为什么?看这里这里
过滤器
// definition
collection.filter((currentValue, index) => {
// logic to filter array on
});
// example
const arr = [1,2,3,4,5];
const newArray = arr.filter(i => i%2 == 0);
// return a new array with value [2, 4]
**过滤器作用于一个数组,返回一个已过滤项目的数组。**也就是说,它将删除返回 false 值的项目,只返回从函数返回的 true 值数组。
让我们用它们来做一些真实世界的场景+一些 ES6。(让我们在下面的对象键上尝试一些 ARMD)
想知道什么是 ARMD 它的添加,阅读,修改,删除,它的酷硬币你自己的行话😄
我们将使用users它作为一个数组来进一步举例。
1。一个RMD**——给** **users**增加一个新元素
const newUser = {
id: 4,
name: "Denomer Crazy",
username: "crazy.1",
email: "[deno@crazy.com](mailto:deno@crazy.com)",
phone: "",
website: "crazy.app",
password: "crazed_checker"
};const newData = [...users, newUser]; // add element at last
or
const newData = [newUser, ...users]; // add element at first
or
const newData = users.concat(newUser) // the old way
ES6 spread 运算符的使用使得向数组添加元素变得非常容易。我们可以使用 spread 操作符连接两个不同的数组,修改对象的形状,或者添加动态键值对,等等。
const hobbies = ['chess', 'pool'];
const newUsers = users.**map**(u => ({...u, hobbies}))
// this will add hobbies to users array and return newUsers array
2。ARMD**——将** **users** 的电子邮件地址、电话号码和网址放入新数组
const contactInfo = users.**map**(({email, website, phone}) => ({email, website, phone}));
使用 ES6 析构对象键和map来获取用户的联系信息数组。
3.AR M D —查找并替换对象的键值
const newUsers = users.**map**(u => u.id == 2? ({...u, name: 'te'}): u);
// this will return newUsers with all user having name 'te'
4.手臂D—从对象中删除一些关键点
注意:我们实际上不会删除键而是返回一个新的对象,如果你想删除键使用 delete 操作符,这里我们考虑的是对象的不变性。
删除键有很多种方法,但我们将着眼于最简单的,单行的。让我们试着从用户中删除网站。
const newUsers = users.**map**({id, email, name, username, phone, password} => ({id, email, username, email, phone, password}));
// will return an array with all keys other than website
上面的代码似乎很难对大对象进行编码。
const newUsers = users.**map**(u => Object.keys(u).**reduce**((newObj, key) => key != 'website' ? { ...newObj, [key]: u[key]} : newObj, {}));
我们对用户进行映射,然后对每个用户进行归约并形成一个新对象(newObj),然后检查网站关键字,如果是网站,我们返回之前形成的newObj,如果不是,我们进行扩展操作,并将所需的关键字添加到obj,最后返回newObj。
如果您想加入我的电子邮件列表,请考虑在此输入您的电子邮件地址关注我在medium上阅读更多关于 javascript 的文章,并在github上查看我的疯狂代码。如果有什么不清楚或者你想指出什么,请在下面评论。
你可能也会喜欢我的其他文章
- Javascript 执行上下文和提升
- Javascript —生成器-产出/下一个&异步-等待🤔
- 理解 Javascript 'this '关键字(上下文)。
- Javascript- Currying VS 部分应用
- Javascript ES6 —可迭代程序和迭代器
- Javascript 性能测试—针对 vs 针对每个 vs (map,reduce,filter,find)。
- Javascript —代理, Javascript —作用域
如果这篇文章有帮助,请随意分享并帮助他人找到它!
谢谢!
编写代码:
Skyscanner 推荐目的地背后的架构
安德烈·巴博萨
在 Skyscanner,我们处理大量数据。一部分来自我们的合作伙伴的机票、酒店或租车费用,一部分来自我们的用户。传统上,我们的产品专注于使用我们从合作伙伴那里收集的数据来为我们的旅行者产品提供支持,我们使用来自用户的匿名行为数据来验证我们的假设并做出商业决策。
我们现在开始构建新一代产品,这些产品不仅基于我们合作伙伴的数据,还基于匿名化的用户行为数据,以提供更好、更个性化的体验。这些新产品带来了新的挑战,我们正在用新的方法和技术应对这些挑战。 你可以通过订阅我们的 CodeVoyagers 简讯 在这里看到更多我们的报道。
最近,我们在移动应用程序的“探索”屏幕上添加了推荐目的地。
Skyscanner’s Recommended Destinations functionality pictured above
这意味着我们的用户不仅可以获得最优惠的价格,还可以利用我们的集体知识为他们的旅行寻找灵感。我们每天都会计算这些建议,并根据用户位置对其进行个性化设置。
历史上,这个屏幕上的发现提要是由我们的“无处不在”搜索提供的,允许用户探索市场上最好的交易。对于推荐的 feed,我们采取了一种稍微不同的方法,将价格放在一边,专注于用户的实际去向。到目前为止,自发布以来,我们已经看到我们的转化率增加了 5%以上。
这篇文章将概述我们为提供目的地推荐而构建的技术架构。
要求
让我们先来看看支持这些建议的平台要求。从高层次的角度来看,有三点是问题的核心。我们需要:
- 存储大量历史数据,可用于训练和测试我们的模型;
- 处理大量数据;
- 以最小的延迟向用户提供结果建议。
但是,当我们开始深入挖掘时,我们需要关心的事情更多了:
- 快速实验——我们依靠用户反馈来验证我们的假设,因此我们需要能够轻松地即插即用新算法,并从管道的另一端获得结果;
- 最低运营成本—我们专注于产品,因此我们负担不起花费太多时间来运行手动工作或维护基础架构。
体系结构
考虑到这些需求,我们设计了一个两层架构,如下图所示。
Two-tiered architecture behind Skyscanner’s Recommended Destinations
在最底部,我们有“日志数据存储”,它存储任何 Skyscanner 团队通过我们的数据平台记录的每个用户事件。我们的批处理层离线运行,并通过消费数据和运行一系列算法来利用这个数据存储。完成后,它会向实时数据存储提供新的推荐。这个数据存储是一个低延迟 web API 的基础,它为我们的用户提供计算数据。
在批处理和实时之间进行明确分离的主要优势之一是,它为试验新算法和数据集提供了很大的空间。只要结果符合预定义的模式,我们知道它们可以由 API 提供服务。
因为我们希望保持较低的运营成本,所以该架构构建为在 AWS 云上运行。日志数据存储基于 S3,由我们的数据管理团队维护。
深入探讨批处理
The batch processing layer is where we do all the data transformations that generate the recommendations that we serve through the live service.
批处理层是我们进行所有数据转换的地方,这些数据转换生成我们通过实时服务提供的建议。
我们使用 AWS 数据管道来协调这项工作。DataPipeline 非常适合我们的用例,有助于为我们的批处理作业带来可靠性。
附加到我们的数据管道,我们有一个时间表,我们希望我们的批处理作业运行。这并不比普通的 cron 工作更花哨。但是将它与整个系统集成并完全由 AWS 管理是非常方便的。
我们还附加了一系列先决条件。这些有助于使管道更加可靠。我们使用这个特性来确保在开始这个过程之前,我们已经得到了我们需要的所有数据。当一些输入是不同批处理作业的输出时,这尤其重要。也可以将前提条件配置为等待一段时间,因此即使在计划的时间没有满足某个条件,也不一定意味着作业会失败,它可能只是稍微晚一点执行。这还意味着,如果先决条件从未得到满足,作业将在配置任何硬件之前失败,因此我们不会产生任何不必要的成本。
当所有先决条件通过时,DataPipeline 将提供一个 EMR 集群。EMR 是 AWS 托管的 Hadoop YARN 版本,适合您选择的分布式数据处理系统。我们选择了星火。我们选择 Spark 有两个主要原因:它非常快,很大程度上是因为它的内存缓存,而且它对开发人员非常友好。我们特别喜欢 Spark SQL 和 DataFrame 抽象。此外,PySpark 是我们的一大卖点。
我们编写的大部分代码都是作为 Spark 作业运行的。即使细节可能变得有点复杂,从高层次的角度来看,代码如下图所示。
Read Clean Rank Write
现场服务的深度探讨
我们已经看了我们如何产生推荐;现在让我们来看看我们是如何为他们服务的。你可能已经猜到了,这一层非常薄,我们尽最大努力让它尽可能的轻和简单。
对于我们的实时数据存储,我们决定使用 Postgres 。我们选择它是因为:
- 它在 RDS 中可用,AWS 的托管关系数据库具有开箱即用的多区域复制,这意味着我们的维护工作最少
- 它具有非常低的延迟(我们一贯测量每个查询低于 5 毫秒)
- 很容易针对读取密集型工作负载进行扩展
- 随着产品的成熟,修改模式和查询相对容易
在数据存储的前面有一个服务 REST API 的 web 服务。在 Skyscanner,我们相信微服务,最近开始向前端的后端发展。这意味着我们的移动客户端不需要直接查询这个 API,他们通过一个 BFF 服务来完成,这个 BFF 服务聚合了他们渲染最终 UI 所需的所有数据。这个特殊的架构决策使得我们在这一层的工作变得更加容易。这意味着我们可以提供一个非常简单的 API,供另一个内部服务使用。这样,我们最大化了可重用性,并使我们能够在不改变合同的情况下试验许多不同的 UI。
结论
我们已经在生产中运行了一段时间。到目前为止,它基本上是无痛的,但也不是没有学习和迭代的公平份额。在批处理层编写新算法并让它们立即投入使用的灵活性已经得到了回报,我们正在不断迭代。另一方面,维护 DataPipeline 所需的维护工作可能被低估了一点,因为我们最终花费了相当多的时间来处理服务中的许多警告。
我们预计未来面临的挑战之一是扩大批处理层的输出规模。输出的大小与我们使用的个性化因子成比例。例如,如果我们开始计算为每个 Skyscanner 用户单独定制的推荐,输出的大小将乘以我们用户群的大小。我们当前替换实时数据存储上的数据集的策略可能无法在这种规模下保持,在某个时候,我们将需要重新考虑该架构决策。
还有实时模型的问题。目前,一切都是批量完成的,但可能有产品需要更新鲜的结果。在 Skyscanner,我们已经使用 Kafka 进行流式数据处理,使用 Samza 进行一些实时处理。所以基础设施的这一面不会是最难的部分。但是,我们可能需要重新考虑我们为实时数据存储选择的 Postgres,并可能转向更容易在写入繁重的工作负载上扩展的东西。
与我们合作
我们在 Skyscanner 以不同的方式做事,我们正在全球办事处寻找更多的工程团队成员。看看我们的 Skyscanner 职位寻找更多空缺。
关于作者
大家好,我是 André,是 Skyscanner 的一名软件工程师。我是忠诚的常客部落中的一员,我们致力于改善那些知道乘务员名字的旅客的体验。我热衷于提供产品,为人们的生活增加价值,并将其发展到世界规模。
Andre Barbosa
我们的常见问题
2023 年 3 月更新
读者
- 阅读器使用条款和条件
- 如何充分利用数据科学?
- 我如何退订你的来信?
- 我需要付费阅读你的出版物吗?
作家
写作
- 你只用英文出版吗?
- 我应该在我的个人资料中使用我的真实姓名吗?
- 我应该写些什么话题?
- 如何提高写作能力?
- 我可以写一篇关于我的书、活动、播客、会议等的帖子吗??
- 我可以写我公司的产品吗?
- 我被要求加入一些关于我的主题/数据集的潜在风险或道德问题的句子。你还能指望什么
提交和发布
- 作者使用条款和条件
- 隐私政策
- 我应该把我的新文章作为草稿还是作为已发表的文章提交?
- 当我向 TDS 提交文章时会发生什么?
- 我的帖子发布后会出现在哪里?
- 我可以发送我已经在 Medium 上发表的帖子吗? ️
- 我可以复制帖子吗?
- 我的帖子被拒绝了,你能告诉我为什么吗?
数据来源
广告和促销
- 我可以付费出版吗?
- 您允许哪种广告或赞助内容?
- 公司可以在 TDS 发布吗?
其他人
- 我能把帖子翻译成另一种语言吗?
- 我可以在我的 Linkedin 个人资料中提到数据科学吗?
- 如何联系您?
读者
读者使用条款和条件
阅读我们的媒体出版物时你应该知道什么
towardsdatascience.com](/readers-terms-b5d780a700a4)
我如何退订你的信?
- 请访问我们出版物的主页。
- 单击出版物页眉上的下列按钮。
- 取消选中收件箱接收信件框。
您也可以通过点击您从 TDS 收到的信件底部的取消订阅按钮来取消订阅,或者通过用户图标菜单从您的出版物页面取消订阅。
我需要付费阅读你的出版物吗?
不,我们会一直提供免费文章给对数据科学感兴趣的人阅读。然而,由于我们是媒体生态系统的一部分,我们的作者可以决定只向成员锁定他们的帖子。请点击此处的了解更多信息。
作家
你只用英语出版吗?
是的。
我应该在我的媒体简介上使用我的真实姓名吗?
是的,请附上你的真实姓名、照片、简历。我们不会发表匿名人士的帖子。如果你想让我们和你的读者信任你,你必须公开你是谁。
我应该写些什么话题?
TDS 的文章涵盖了广泛而多样的领域——从针对数据专业人员的职业建议到数据驱动的方法气候变化。您可以在我们的标签页面上探索一些我们最受欢迎的话题。
作者从许多不同的角度探讨这些(和其他)主题。有的帮助新手入门,创建动手教程,或者分享自己最新的小技巧和窍门;其他深入复杂问题或者写关于前沿研究。
如果你不确定写什么,选择离家近的。向我们介绍一下你最近的工作项目。分享您在学习过程中获得的一些见解,或者基于您数据科学职业生涯的高潮和低谷提出的建议。
好的想法往往能在你读了能引起你共鸣的东西后浮出水面。要获得有益的灵感,请浏览我们的编辑精选的关于 TDS 的一些精心制作的文章,或者前往我们的作者聚焦,在那里我们采访了杰出的 TDS 贡献者,了解他们的工作和写作。
另一种开始头脑风暴的方法是以更具体的方式考虑你的听众。通过查看以下链接,您可以更好地了解数据科学家的热门话题:
- 我们的档案列出了 TDS 上阅读量最大的文章。
- 中型标签页可以按趋势帖子排序。
- 在 GitHub 的趋势页面上,你可以指定编程语言和日期(例如:2022 年 1 月以来 Python 上的趋势帖子),或者直接进入他们的数据科学专题页面。您可以使用您的发现来撰写令人兴奋的新 Python 库。
- 另一个强大的工具:谷歌趋势!
- 你知道 Twitter 有自己的数据科学主题页面吗?它能让你深入了解正在进行的和新出现的对话。
- 如果你想围绕一个常见问题的答案写一篇文章,试试 Quora。
无论你是一个经常投稿的人还是一个有抱负的 TDS 作者,我们都迫不及待地想看你的下一篇文章!如果你以前没有和我们一起发表过,我们会特别高兴收到你的来信。
我该如何提高我的写作技巧?
互联网上有很多帮助提高写作的资源。然而,我们发现许多作者缺乏一些基本技能,这使他们无法正确地表达他们的信息。以下是我们选择的写作资源:
- 如何成为一名更好的作家:来自哈佛大学史蒂芬·平克的 6 条建议
- 史蒂芬·平克的风格感
- 为学术期刊写作的 10 个技巧。卫报
- 如何写一篇博客文章(真正被阅读)
- 来自成功作家的 6 条最佳建议
在写文章之前,你需要非常清楚你想达到什么目的。一旦你对你的文章有了想法,你应该试着回答这些问题:
- 你文章的目标或目的是什么?
- 你的文章试图回答什么关键问题?
- 内容是否回答了你文章的主要问题?
- 你的文章开始有力,结束有力吗?(你是否创造了一个谜/问题,然后解决了它?)
- 每一个概念都暴露了它的本质,以有序的顺序叙述并且用类比来说明吗?
我可以写一篇关于我的书、事件、播客、会议等的帖子吗??
看情况!我们通常不发布活动或书籍公告,并避免主要作为宣传您最新播客剧集、YouTube 视频或其他平台上的其他媒体的文章。例如,一篇只有简短介绍和视频嵌入或链接到另一个网站的帖子不适合 TDS。
如果你的文章具有这些元素中的一个,如果它满足几个条件,我们仍然会考虑发表它:
- 它为读者提供了足够的价值——例如,作为新书发布会一部分的独立书籍摘录,或者嵌入相关数据科学或 ML 主题的深思熟虑的讨论中的播客片段。
- 它避免了过度的宣传语言和框架(例如,多个链接和 CTA、滔滔不绝的最高级等等)。
提交和发布
作者使用条款和条件
如果您有任何问题,可以在这里联系我们。你也可以在这里找到我们以前的版本:
towardsdatascience.com](/author-terms-and-conditions-of-use-b9b3935ff999)
隐私策略
我们收集、存储和使用个人信息的方式为我们提供了
towardsdatascience.com](/privacy-policy-b9f519aae672)
我应该把我的新文章作为草稿还是作为已发表的文章提交?
我们很高兴你问了!我们强烈建议您以草稿形式向 TDS 提交您的新文章,而不是作为已发布的帖子。为什么?TDS 主页和 Medium 的后续订阅源都是按首次发布日期的倒序排列的。这意味着最近发表的文章显示在顶部附近,因此我们收到的任何草稿文章在我们将其添加到出版物时都会有更大的影响力和可见性。
相比之下,你已经自己发表的帖子——甚至就在 TDS 上出现的几天前——将很容易在我们每天发布的所有新帖子中消失。简而言之:分享草稿可以增加你文章的潜在读者。
提交草稿也有助于我们的团队在发布您的文章之前分享反馈和改进建议,这意味着没有发布后的编辑或更正。它让我们能够与您合作,为您的观众留下尽可能好的第一印象。
如果你已经发表了你的文章,但仍然希望与 TDS 分享,这很好——我们总是很高兴考虑你的工作。不过,对于未来的文章,给我们发一份草稿是可行的。
当我向 TDS 提交文章时会发生什么?
非常感谢您抽出时间向我们的团队提交您的文章!我们会尽快审查。
如果我们认为你的文章很好,可以发表了,这就是你将你的文章添加到我们出版物的方式。如果在页面顶部的下拉菜单中点击“添加到出版物”后显示“走向数据科学”,这意味着我们已经将您添加为作者,并等待您提交您的文章。一旦你提交了你的文章,在做出最终决定之前,它将会被编辑审阅。
如果我们认为你的文章很有趣,但需要改进,我们团队的人会直接在你提交的中等文章上给你反馈。
请注意我们仅回复使用我们的表格或通过电子邮件正确提交的文章,这些文章完全遵循此处 列出的 **说明。**我们不会对已经在我们的常见问题解答或 Contribute 页面上回答的推介或问题做出回应。我们也会忽略不符合我们规则的文章。
如果您在接下来的五个工作日内没有收到我们的回复,请仔细检查您提交给我们团队的文章。看看你现在是否可以直接提交给 TDS,并从我们这里寻找你可能已经错过的任何私人笔记。您还应该确保检查您的垃圾邮件文件夹。
如果你联系不到我们,你最好把你的文章提交给另一家出版社。虽然我们很想这样做,但我们无法为每个人提供定制的反馈,因为我们只是收到了太多的提交。你可以在这里进一步了解我们的决定,并在一个月后提交另一篇文章。
我的帖子发布后会出现在哪里?
如果你的文章是最近发表的,它会出现在我们主页的“最新”下面。根据您的标签,您的帖子也会出现在我们的不同页面上。
在提交你的帖子之前,确保你已经阅读了 Medium 的策展指南。即使是我们最好的作者也往往会犯一些基本的错误,使得他们的文章没有资格在 Medium 的主题(数据科学、机器学习、人工智能……)中发布,也没有资格在数据科学专题中发表。
如果您希望我们的团队在 Twitter 上提及您,请确保您的媒体个人资料包含您的 Twitter 帐户。您的帖子可能需要几天时间才能在我们的社交媒体上出现。
最后,您的帖子将在我们的出版物中被搜索到,出现在我们的档案中,并可以在您的同行撰写的其他文章的底部推荐给我们的读者。
我可以发送我已经在 Medium 上发表的帖子吗?
是的,只要你的文章与我们的读者相关,我们有兴趣将其添加到 TDS。请不要在媒体上复制你的文章!他们不允许在自己的平台上发布重复内容。
我能复制一个帖子吗?
允许交叉发布你在别处(非媒体上)发布的内容,前提是它符合媒体指南,并且你的帖子尚未在媒体上发布。
我的帖子被拒绝了,你能告诉我为什么吗?
虽然我们希望能够对我们收到的所有令人难以置信的提交内容留下反馈,但我们是一个小团队,我们无法对我们评论的所有文章提出建议。然而,我们拒绝一个新职位有一些常见的原因。
我们是一家媒体出版物,我们对发表的每篇文章都使用 策展指南 **。**这意味着我们寻找具有高质量写作和内容的文章,为读者提供可靠价值的文章,以及没有错别字和语法错误的文章。这也意味着我们拒绝包含取消资格元素的文章,如点击诱饵、赞助内容、营销/广告、新闻稿或抄袭。我们建议您看一下指南!你可能会惊讶地发现,包含朋友链接或鼓掌请求的文章是不允许的。
我们也有自己的指导方针,你可以在这里 找到 。我们的指导方针包括诸如你的代码应该如何显示以及你的图片必须如何被引用等主题。除了我们的指导方针,您还可以找到关于出版和确保您将您的信息传达给我们的受众的建议和提示。
如果你仔细阅读上面的指导方针,你很可能会找到你的文章被拒绝的原因。然而,以下是我们拒绝提交的一些最常见的原因:
- 格式:有关系!例如,如果你的代码格式不正确,你的图片模糊不清,大小随意,你有很长的文字,或者你给每一句话都有自己的段落,我们可能不会接受你的提交。请花时间让你的文章清晰、有帮助,并且读起来令人愉快。
如果你不确定如何嵌入你的代码,这是一个 伟大的资源 。如果需要语法方面的帮助,你可以尝试一个免费的工具,比如grammarly.com。 海明威 可以是另一个很棒的写作辅助资源。如果你不确定如何在介质上格式化数学方程,你可能会喜欢 这篇文章 或者embed . fun工具。如果你想要《走向数据科学》的编辑们正在寻找的例子,看看我们的 编辑精选 !
- 图片:如果你在文章中使用了某个图片,你需要核实你有权利使用它,并正确引用它的来源。请仔细检查您的图片,确保您有权使用您提交的所有图片,包括您修改过的图片。你可以在这里 (#10)了解更多关于这个的信息。
- 数据集:始终确保你有权收集、分析和展示你正在使用的数据。在你的文章中,请给数据集添加引用,并说明其许可。请注意,在 TDS 中发布需要商业许可或数据集所有者的许可(是的,这也包括网络抓取)。你可以在这里 (#11)了解更多我们的数据政策。
- 点击诱饵和列表文章:我们对发布点击诱饵、列表文章或基本内容不感兴趣,如果你提供了广泛可用的信息而没有原创观点,我们可能会拒绝你的文章。我们感兴趣的是,是什么让你的文章与你主题的其他文章不同。做你的研究,并确保你有一些原创的东西要说。
- 选题:虽然我们会根据具体情况做出编辑决定,但我们不太可能发布关注金融或投资建议、医疗建议以及赌博的帖子。我们也不会发布促进数据和人工智能的可疑或不道德使用的帖子。感谢您在选择项目和数据集进行写作时牢记这一点。
- 营销内容和赞助帖子:根据 Medium 的监管准则,营销内容、广告和赞助帖子是不允许的。由于我们发布的所有内容都使用 Medium 的策展指南,我们通常会拒绝那些看似营销的内容。
- 公司账号和匿名账号:我们目前只发布个人撰写的文章。我们不接受由公司帐户或匿名帐户撰写的文章。
- 最少解释的技术教程:我们很高兴你愿意与我们的读者分享你的技术。但是,请记住你的观众!如果你在教读者如何建造或修理某样东西,很可能他们还不知道如何去做。请确保用自己的话提供足够清晰的信息。
- **使用普通技术的个人项目:**如果你完成了一个令人惊叹的项目,我们想听听它的故事!然而,如果你正在一个流行的数据集上使用基本的技术,或者你只是简单地回顾一门课程或教程的步骤而没有添加任何新的东西,请等待提交你的文章。继续做你的项目,当你有独特的东西要写时,我们很乐意与我们的读者分享。
- **无关内容:**我们是关于数据科学的刊物。如果你写的主题与数据科学、机器学习、编程、数据可视化和人工智能没有直接关系,我们不太可能接受你的提交。
我可以写我公司的产品吗?
我们喜欢发布具有行业经验的数据科学专业人士的帖子。如果你的帖子围绕你从事的产品或项目,欢迎你提交给 TDS,只要它的主要目的是教育和信息,而不是销售或推广。
请注意,我们不太可能发表以产品为中心的文章,这些文章的作者最近写过类似的主题,或者他们的文章主要关注他们的产品/公司。
几个要点:
- 公开你与有问题的公司或项目的关系,并明确后者是否开源。
- 避免使用你公司的标志,尤其是在特色图片中——这会让你的帖子感觉太像广告,把读者吓跑。
- 描述你的产品的好处是好的,如果它与手边的主题相关,但是把你的读者看作是同龄人,而不是潜在的客户。避免营销术语(“限时优惠”、“特别促销”)和滔滔不绝的最高级词汇(“最简单”、“最快”、“同类最佳”)。
- 无论你谈论的是你的日常工作还是一个新的功能发布,确保读者可以学到一些新的东西,即使他们从来没有使用过你的产品。例如,你可以讨论你的团队克服的一个困难的技术挑战,你为构建你的产品而创建的新工作流,或者你的工作如何利用人工智能或机器学习的最新进展。
- 我们通常会拒绝重复产品文档或支持页面的帖子,以及那些旨在引导读者设置和使用相关产品的帖子。
我被要求加入一些关于我的主题/数据集的潜在风险或道德问题的句子。你还能指望什么
如果我们要求您思考您的项目的道德或安全风险,您可能已经写了关于面部识别、跟踪或检测识别个人标志(年龄、种族和性别等)的主题,或者您正在使用可能引起道德问题的数据集。
由于道德和风险问题是该主题和数据集所固有的,因此没有放之四海而皆准的解决方案。所以,我们准备了一些你可能需要回答的问题,来为你的文章创造一个合适的讨论。我们还收录了一些作者在讨论风险或伦理问题方面做得很好的已发表文章。
数据集
- 对你的文章重要吗?为什么/如何?
- 你为什么选择这个特有的数据集?
- 你有没有注意保护文章中输出的个人信息和任何共享的 GitHub 库?
- 你研究过你所使用的数据中潜在的偏见吗?你是如何解决这些问题的?
话题
- 你是否思考过潜在的风险或与你的项目相关的道德问题?
- 你的方法与风险或道德问题有什么关系?
- 你是否研究过与你的主题相关的伦理问题?你把这些观点融入你的文章了吗?
- 您是否已采取措施解决风险和/或道德问题?
- 是否有与您的主题相关的未来工作可以降低风险?
发表文章讨论道德/风险
检查你的偏见维罗妮卡·维拉著(道德/偏见风险)
用深度学习和 PyTorch 训练一个模型来检测乳腺 MRI 肿瘤作者 Nick Konz(医疗风险)
数据来源
我如何确定数据集许可是否合适?
如果所有数据集许可证都很容易找到,有相同的语言,并且容易阅读,那就太好了。可悲的是,事实并非如此。通常需要耐心和毅力来决定你是否有权使用数据集。
以下是一些要点:
- 确保你实际上是在原始数据源的网站上,而不是别人的拷贝。
- 有些网站在主页上以简单的方式显示许可证信息,或者将许可证信息包含在有关数据的信息中。其他时候,您必须更深入一点,搜索 FAQ、条款和条件以及支持页面。如果其他方法都失败了,最好联系业主获得许可。请记得将许可的副本发送到 publication@towardsdatascience.com的我们这里。
- 请留意许可证中描述的允许用法中的“商业”一词。《走向数据科学》是一份商业出版物,商业使用必须得到许可。
- 尽管不是标准的,许多网站已经采用了知识共享许可,这使得解释许可更加简单。以下是一些允许商业使用的许可证代码:
**小心!**有两个类似的代码不允许商业使用,这意味着这些数据集不能用于 TDS 文章:
- CC BY-NC —允许非商业使用
- CC BY-NC-SA 4 —允许非商业带归属使用
5.适用于程序源代码的许可,例如 MIT 和 Apache ,并不自动涵盖或暗示使用相关数据集的权利。
6.将使用限制在“研究和教育目的”的许可证带来了一个问题。尽管你可能已经在文章中做了研究,或者出于教育目的展示了材料,但你是在商业出版物上发表文章。一般来说,研究和教育仅适用于发表在学术期刊、学院/大学课程和会议记录中的工作。
7.书籍、电影剧本、杂志和报纸文章都受版权保护。你想用的那些哈利波特剧本?除非你获得许可,否则禁止入内。然而,旧的出版物可能在公共领域,你的文章可以免费使用。版权一般持续作者的一生加 50 年(加拿大)到 70 年(欧盟、美国)。关于版权有更多的规则,最好咨询作品首次出版所在国家的版权法,以确定版权是否已经过期,你可以自由使用该文档。当有疑问时,请求许可!
我可以使用上传到存储库的数据集吗?
这个问题没有简单的答案,因为任何人都可以将数据上传到存储库中,每个数据集都有自己的许可证。在您的文章中使用数据之前,请仔细阅读提供的信息,以确定数据的来源和适用的许可,这一点很重要。
很多时候,数据集是从抓取的数据中创建的,然后(由抓取它的一方)给予公共域许可,错误地认为存储库所有者允许提供数据/程序。请记住,只有原始数据所有者才能授予权限。
如果你正在参加数据科学竞赛或黑客马拉松,并计划在 TDS 上分享你的进展或解决方案,请确保他们的规则允许你分享数据。一些数据集仅用于竞赛或黑客马拉松,不能在 TDS 发布的文章中共享。
通过 API 获取的数据可以吗?
如果您计划使用 API 来创建自己的数据集,请在将您的文章提交给 TDS 之前,绝对确保您有权使用 API(以及通过 API 获取的任何数据)。检查 API 或网站的使用条款,看看他们是否允许商业使用,并仔细阅读任何限制。
如果没有版权声明或许可证怎么办?
首先,需要注意的是,没有通知或许可证并不意味着可以免费使用。有时,数据包含在一个伞式组织中,例如,一个城市的公用事业部门可能包含在该城市的通用数据共享策略中。
其他时候,业主只是忘记张贴通知。在这些情况下,我们建议您考虑联系所有者请求许可,而不是假设数据可以使用。
请求数据集权限的邮件包括什么?
发送给数据集所有者请求许可的电子邮件不必很长。它应该包括关于你打算写的文章、你自己以及对数据科学的看法的信息。这里有一个例子,你可能会觉得有帮助:
我正在写一篇关于[主题]的文章,这篇文章将发表在《走向数据科学》杂志上,该杂志可在媒体上获得。我在这里[链接]找到了你的数据集,认为它与我的工作非常吻合。我联系您是为了请求允许我在文章中使用这个数据集。你可以在这里了解更多关于我的信息【个人资料、LinkedIn、网站等链接。],关于走向数据科学这里。
广告和促销
我可以付费出版吗?
不,我们不允许赞助帖子。
你允许什么样的广告或赞助内容?
我们不允许任何广告或赞助帖子。
公司可以在 TDS 发布吗?
是的。但是,我们更喜欢发布来自一个属于真人的媒体简介的帖子。还有,我们不允许做广告,也不提出代写服务。
其他人
我能把帖子翻译成另一种语言吗?
你需要直接联系文章的作者。文章属于作者,所以我们不能批准他们的翻译。
我可以在我的 Linkedin 个人资料中提到数据科学吗?
是的,你可以提到你是 TDS 出版物的独立撰稿人。此外,通过将链接添加到您的媒体简介中,将链接添加到您对 TDS 出版物的贡献中也是一种很好的做法。
怎么联系你?
你可以在这里联系我们。
为数据科学职业撰写简历
Source: Pexels
因此,您已经决定进入数据科学职业生涯的下一阶段,无论您是刚刚起步,还是认为自己已经准备好进入职业阶梯的下一阶段。然而,这意味着写一份全新的简历来确保你在面试阶段的位置。
虽然你可能认为这只是简单地写一份新的 Word 文档,但请记住,你的简历将是你未来业务对你的第一印象,所以你必须做到正确,尤其是因为现在的公司只希望获得顶级人才。
今天,我们将探讨撰写数据科学简历时您需要知道的细节,让您获得梦想中的工作。
用你的数据变得具体
一份典型的普通简历会充满模糊而宽泛的陈述和成就,如果你的简历属于这一类,没有数据科学公司会雇用你。当你谈论你在过去工作岗位上的成就时,一定要具体到细节。
例如,不要说“我能够将一个表现不佳的团队变成一个高绩效的团队”,而是通过说类似“我能够在两年内将我团队的绩效和产出提高 14%,从而为公司带来 45%的增长率”这样的话来表明你了解自己的能力。
为你的成就和教育自豪
当你谈论你过去的经历或你在生活中获得的技能时,不要陷入用“绒毛”掩盖有益事实以增加简历字数的陷阱。
对于这个要素,不要写“我在统计学方面有很强的背景”,而是尝试更具体地写一句话,如“在哈佛大学学习统计分析,并因论文工作获得最高奖项”。你在这些方面做得越详细,你就越有可能获得这份工作。
强调你的工作经历
“无论你是在教育行业,还是参加了工作经验安置,或者你已经在数据科学行业有了很长的历史,请确保你强调了这一经验。EliteAssignmentHelp 的职业教练马克·诺兰说:“雇主更看重经验,而不是学历。
使用在线写作工具
作为一名数据科学家,不能保证你的写作技能达到专业水平,但这并不意味着你不能制作一份专业的简历。在网上,你可以找到大量的写作工具,在写作过程的每个阶段都可以帮到你。这里有几个让你开始;
简历服务(Resume Service)——一个简历制作网站,里面有很多写作指南和简历模板,供你在制作简历时参考。
简单字数统计 & 语法检查——两个免费在线工具,帮助你跟踪简历的字数,并检查你的语法。
Essayroo & 作业写作服务——这是两个领先的简历校对服务,以确保你的内容没有错误,正如澳大利亚最佳作家在澳大利亚帮助评论中评论的那样。
通过写作在 & 中引用——两个免费的在线工具和博客,帮助你在简历中添加参考资料,以及提高写作技巧的技巧。
academialized&BoomEssays——这是两家领先的写作咨询服务机构,为你提供更好的写作风格的知识,这是《赫芬顿邮报》推荐的。
写作状态 & 我的写作之道 —两个写满写作指南的博客,帮助你提高一般写作技巧。
英国顶级作家评论的两个专家编辑工具,确保你的简历有意义。
不要只用同一个简历
当你申请一份数据科学的工作时,重要的是要记住,阅读你简历的人可能已经在人力资源行业工作了几十年,当他们看到一份通用的多用途简历时,他们会知道。
你需要确保为你申请的每一份数据科学工作定制你的简历,否则你可能会错过所有的工作。
定制 Keras 生成器
定制您的数据生成器,加快培训速度
使用 Keras 生成器的想法是在训练过程中即时获得成批的输入和相应的输出,例如读入 100 幅图像,获得相应的 100 个标签向量,然后将这组输入馈送到 gpu 进行训练步骤。
Keras : keras.io
我面临的问题是标准的 Keras 生成器的内存需求。内存生成器创建原始数据的副本,并且必须将dtype从uint8转换为float64。另一方面,从目录中读取的 Keras 生成器期望每个类中的图像都在一个独立的目录中(在多标签问题、分割问题等中是不可能的)。)
因此,我喜欢将批处理生成器分为 4 个步骤:
1\. Get input : input_path -> image
2\. Get output : input_path -> label
3\. Pre-process input : image -> pre-processing step -> image
4\. Get generator output : *(* *batch_input, batch_labels )*
步骤 1 : 定义一个函数来获取输入(可以是子集化一个 numpy 数组,pandas dataframe,从磁盘读入等等。) :
from skimage.io import imreaddef get_input(path):
img = imread( path )
return( img )
第二步: 定义一个函数来获取输出:
import numpy as np
import pandas as pddef get_output( path, label_file = None ):
img_id = path.split('/')[-1].split('.')[0]
labels = label_file.loc[img_id].values
return(labels)
第三步: 定义一个函数对输入进行预处理:
def preprocess_input( image ):
--- Rescale Image
--- Rotate Image
--- Resize Image
--- Flip Image
--- PCA etc.
return( image )
第四步: 把所有的东西放在一起定义你的生成器:
def image_generator(files, label_file, batch_size = 64):
while True: # Select files (paths/indices) for the batch
batch_paths = np.random.choice(a = files,
size = batch_size)
batch_input = []
batch_output = []
# Read in each input, perform preprocessing and get labels for input_path in batch_paths: input = get_input(input_path )
output = get_output(input_path,label_file=label_file )
input = preprocess_input(image=input)
batch_input += [ input ]
batch_output += [ output ] # Return a tuple of (input, output) to feed the network batch_x = np.array( batch_input )
batch_y = np.array( batch_output )
yield( batch_x, batch_y )
现在,您可以添加特定数据集定义的预处理功能,将输出作为图像掩模(分割问题、定位问题等)。).
在这之后,使用这个定制生成器与使用一个预定义的Kerasimagedata generator 并简单地将生成器对象传递给model.fit_generator().是一样的
#网络安全 WTF 是敏捷风险分析?
注意:“风险”这个词有很多解释。因此,为了清楚起见,我们在这里将“风险”定义为以下两种情况之一:a)暴露于可信的威胁参与者对企业非常关心的东西的危害;或 b)已确认的危害,使业务面临不可接受的影响。]
TL;DR — ARA(我们将简称为 ARA)是从各种各样且不断扩大的安全相关数据源中获得越来越有意义且及时的风险洞察的能力。
在“运营/流程术语”中,这意味着能够:
- 轻松快速地接收、建模、探索、丰富和关联企业规模的数据集
- 将您的分析建立在支持关键业务服务和创收的运营“实体”(如用户、计算机、应用程序)的环境中
- 将结果放在业务和 IT 流程的背景下,(如果您想识别那些只有在分析长期趋势时才会出现的讨厌的系统问题,请比较“现在”和“时间的开始”)
- “雷达扫描”风险(在 Panaseer 我们称之为“风险搜寻”),通过使用任何分析技术以任何频率对任何数据进行数字处理
- 根据网络安全 100 个移动部分的数据,不断地(或根据你的需要频繁地)重新安排活动的优先级
他们说一幅画描绘了 1000 个单词(…虽然这幅画主要是单词,所以我不确定它是否有资格作为一幅画…)
在“实际示例术语”中,这意味着:
“我想把我们的#n 千个客户,我们的#n 千个设备,我们的谁知道有多少#n 个用户/开发人员,等等等等。我想获取收入和关键业务服务所依赖的所有实体的数据;我想对所有这些进行参照完整性检查;数据库、流源、来自业务和 IT 工作流程的数字废气;来自安全控制的数据;我们所有的日志。
无论我选择什么频率,我都想处理这些数据以了解: -我的环境中有什么?有什么新的,它连接到什么,它合法吗? -我的环境是否得到了预期的管理? -流程是被遵循还是被颠覆? -是否存在需要弥合的技术或流程方面的控制差距? -工作流程和控制是否一切正常,但有些东西我只能在日志中检测到,我需要我的 SOC 的狙击手瞄准镜在上面划区域? -相对于需要立即提升到董事会级别的内容,我可以在日志中忽略哪些我不关心的内容?
然后,我想把所有这些总结成一个观点,告诉我的 CISO 和他整天开会的人,“这是我们本周、本月或今天转移资源的地方,以便最大限度地保护对我们的业务最重要的东西。”
有了这些,我希望对数据的完整性、准确性和一致性有信心,以便能够自动化背后的工作流程。
然后,在任何时候,我都希望引入另一个数据源,重新运行我的所有问题,以获得 50,000 英尺地面的更好分辨率,或者放大地面上行驶在特定街道上的汽车的牌照。
哦,我希望这一切能在几小时或几分钟内完成,而不是几个月或几周,或者根本不可能。
-纽约某投资银行的信息安全智能分析主管
@Panaseer_Team 将于 9 月 25-28 日在纽约的地层;如果你在那里,来和我们谈谈我们与英国和美国的 CISO 团队在这方面所做的工作。如果你不打算一起去,你可以随时在这里联系我们。
假人的机器学习
ML 和 AI 正在对我们的生活产生巨大的影响,它们的作用只会越来越大。你了解的越多,在这些变化发生时,你就能准备得越充分。
所以,我会给你们一个快速的视角来看什么是机器学习😉
机器学习是教计算机如何从数据中学习以做出决策或预测。对于真正的机器学习,计算机必须能够在没有明确编程的情况下学习识别模式。
它位于统计学和计算机科学的交叉点,然而它可以戴上许多不同的面具。你可能还会听到它被标上了其他几个名字或流行语:
数据科学、大数据、人工智能、预测分析、计算统计、数据挖掘等……
机器学习工作流
机器学习工作流是执行机器学习项目所需的过程。以下是对这些核心步骤的可视化描述,很有帮助:
机器学习有四种:
1-监督学习
2-无监督学习
3-半监督学习(监督学习类)
4-强化学习
不要担心这些术语对你来说毫无意义。完成本指南后,您将能够自己讲述这些技巧!😉
下面是通过自学学习机器的 4 个步骤:
- 建立统计学、编程和一点数学的基础。
- 沉浸在 ML 背后的本质理论中。
- 利用图书馆等进行有针对性的练习..
- 实践机器学习项目
让我们深入了解机器学习(Badass)的一些基本术语和概念
1)监督学习
在监督学习中,我们提供数据以及期望的输出(即标记数据)。例如,如果我们希望我们的系统学习马匹检测,我们将收集成千上万的图像,在马匹周围绘制一个边界框,并将整个数据集馈送给机器,这样它就可以自己学习。
Supervised Learning Infographics
2)无监督学习
在无监督学习中,我们只是提供数据,让机器找出数据集中的模式。例如,我们可以提供三种不同的形状(圆形、三角形和正方形)并让机器将它们聚集在一起。这种技术被称为聚类。
UnSupervised Learning Infographics
3)半监督学习
半监督学习是一类监督学习任务和技术,也利用未标记的数据进行训练。在半监督学习中,机器从部分标记的数据中学习,并将这些学习映射到未标记的数据。例如,一个照片存储服务会将一个人的所有照片进行分组,你只需标记一张照片,其他所有照片都会被标上相同的名字,因为它们是同一个人。
4)强化学习
在强化学习中,机器通常被称为代理,代理根据它的每个动作获得奖励(或惩罚)。然后,它学习什么是最大化奖励和减轻惩罚的最佳行动。
什么是过度拟合和欠拟合?
在对数据进行训练后,我们训练模型的目标是尽可能准确地对未知数据进行归纳。如果模型在训练数据上产生非常准确的结果,但未能对看不见的数据进行归纳,则称为过度拟合,因为模型过度拟合了训练数据。如果模型甚至不能准确预测训练数据,这意味着模型没有学到任何东西,这就是所谓的欠拟合。
我们在进行机器学习时会遇到哪些挑战?
- 数据不足
- 质量差的数据
- 无关的特征
数据不足
为了训练机器学习模型,我们需要海量的数据集。在物体检测等复杂问题中,我们有时需要数千幅图像和数百万条记录来进行预测。
质量差的数据
如果输入的数据是错误的,无论我们的机器学习算法多么健壮,它总是会产生意想不到的结果。我们必须减少噪音,并丢弃数据集中的异常值,以使我们的系统性能更好。离群值是同一组中所有成员都不同的实体。
无关特征
有时,我们拥有的数据集不具备训练模型所需的正确特征。在这种情况下,我们要么丢弃不相关的特性,要么将它们合并在一起以产生一个有意义的特性。这个特征选择和提取的过程称为特征工程。
如果你喜欢这个故事,请点击👏按钮并分享,以帮助其他人找到它。你也可以给我买杯咖啡帮我给你写更多有趣的内容!
WTF 是传感器融合?优秀的老式卡尔曼滤波器
在本系列的前一篇文章中,我谈到了基本上用于所有传感器融合算法的两个方程:预测和更新方程。然而,我并没有展示任何实用的算法,使方程分析容易处理。因此,在这篇文章中,我将解释可能是最著名和最广为人知的算法——卡尔曼滤波器。
尽管它在很多方面是一个简单的算法,但仍然需要一些时间来建立对它实际工作方式的直觉。良好的直觉很重要,因为正确调整卡尔曼滤波器有时并不容易。
等等,这两个方程现在在哪里?
让我们快速总结一下传感器融合是怎么回事,包括预测和更新等式。为了做到这一点,我们将重温在本系列第 1 部分中首次出现的飞机示例。如果你感到迷茫,我强烈建议你通读一遍。
好吧。我们用雷达传感器来追踪一架飞机。我们有兴趣了解飞机的状态 x_k ,其中 k 表示时间步长。状态包含了我们感兴趣评估的飞机的动态特性。例如,这可以是位置、速度、滚动、偏航等。
我们对时间步长之间的飞机动力学有一些了解,我们将其表示为运动模型。然而,模型中存在不确定性,这就是为什么我们将其视为概率分布
用文字表达,该模型说状态 x_k 是从 x_k 的可能值的分布中得出的,并且该分布取决于先前的状态 x_{k-1} 。我们也可以选择将运动模型表示为
这个等式说的是同样的事情,但是在这个公式中我们有一个确定性函数 f() 和一个随机变量 q_{k-1} 。因此,用文字表达,我们知道状态 x_k 是前一状态 x_{k-1} 和某个随机运动噪声****q _ { k-1 }的函数,该噪声是随机的(即从某个分布中抽取)。
除了飞机的动态特性,我们还知道雷达的动态特性,我们可以用测量模型来表示。传感器并不完美,所以我们收到的测量结果中会有噪声 y_k 。因此,我们也可以将测量模型视为概率分布
用文字表达,该模型表示测量值 y_k 来自测量值 y_k 的可能值的分布,并且该分布取决于状态 x_k 。我们也可以选择将度量模型表达为
在这个公式中,我们有一个确定性测量模型 h() ,它接收当前状态 x_k 以及随机变量 r_k 。这表示测量值 y_k 是状态 x_k 以及一些随机的(即从一些分布中抽取的)测量噪声 r_k 的函数。
我们正在寻找一种方法将这两种模型结合起来,这样当我们从雷达上观察测量结果时,我们就可以得出以下密度
这被称为整个状态的后验分布,并且可以被视为描述了对于 x_k 的一个似是而非的值的区域,给出了我们到目前为止观察到的所有值。
我们可以通过计算两个方程来表达这个密度,即预测和更新方程
预测方程使用来自前一时间步 k-1 的后验以及运动模型来预测当前状态 x_k 将会是什么。然后,通过使用贝叶斯定理将观察到的测量值 y_k 与测量模型和预测状态相结合,经由更新方程来更新该信念。然后我们得到后验分布!对于下一次测量,我们只需重复这些步骤,当前的后验概率就变成了先前的后验概率。
好吧,我现在知道速度了。那么,什么是卡尔曼滤波器?
预测和更新方程提供了一种递归方式来计算我们接收到的每个测量的状态的后验。然而,如果我们看看这些方程,它们在实践中并不那么容易计算。
首先,我们需要以这样一种方式表达密度,即我们实际上可以求解方程(即,我们想要数值稳定的方程)。其次,如果我们能找到解析解就好了,因为这样我们就不必数值求解方程(这可能需要大量的计算)。这两者都很重要,尤其是当您考虑到许多传感器以数百或数千赫兹的速率提供测量时。由于我们不想丢弃测量值,我们需要找到一种方法来快速计算这两个方程。
这就是卡尔曼滤波器的用武之地。卡尔曼滤波器是围绕一个关键概念建立的
这是因为高斯密度有很多好的特性:
- 如果我们从高斯函数中提取值并执行线性运算(即乘法和/或加法),这些值仍将按照高斯函数分布。
- 高斯密度的另一个好特性是它们是自共轭的。这意味着如果我们有一个高斯似然和一个高斯先验**,那么后验肯定也是高斯的。**
- 最后,高斯密度可以完全由它们的前两个矩来描述:均值和方差。****
如果我们看看预测和更新方程,你就有希望看到所有这些属性是如何派上用场的。通过使每个密度成为高斯型,每个方程都归结为寻找相应的均值和方差的表达式!
线性和高斯运动和测量模型可以表示为
就像以前一样,我们可以选择将这两个模型表示为函数,而不是密度
有了这些,我们可以重写预测和更新方程,其中所有的密度都是高斯型的
我们要寻找的是找到如何计算上面用橙色和洋红色标记的矩的方程:预测的均值和协方差,以及更新的均值和协方差。我将跳过推导,但我们最终得到的是****
好了,我们现在有了一个解析解,可以计算每个时间步的状态 x_k 的后验分布!因为我们以高斯计算结束,所以 MMSE 或图是微不足道的,因为后验平均值充当两者。另一种看待这一切的方式如下
“后验(洋红色)均值是状态的最优估计,后验(洋红色)协方差是估计的不确定性”。
在我们开始实际的例子之前,让我们简单地看一下每一行,并分析一下发生了什么。
- 我们通过采用过去的后验平均值并将其乘以矩阵 A_{k-1} 来获得预测的平均值,这是有意义的,因为 A_{k-1} 描述了状态如何随时间演变。
- 预测协方差以类似的方式计算,其中我们将过去的后验协方差乘以 A_{k-1} 两次,并加上 Q_{k-1} 。我们添加协方差 Q_{k-1} 因为我们在运动模型中有不确定性,所以它被添加到变换的协方差中。
- v_k 被称为新息,可以被看作是在将实际测量值与我们从测量模型中获得的预测测量值进行比较时获得的新信息的表示。
- S_k 表示预测的测量协方差。 R_k 表示测量模型中的测量不确定性,利用 S_k 我们将预测状态的不确定性与测量模型的不确定性结合起来。
- K_k 被称为卡尔曼增益,表示预测状态和协方差应该用从测量中获得的新信息调整多少。
- 后验均值是通过采用预测的均值并用已经获得的新信息对其进行调整来计算的。如上所述, K_k 是一个比例因子,它决定了应当增加多少 v_k 。
- 后验协方差是通过采用预测的协方差并用从测量中获得的信息对其进行调整来计算的。新的信息允许我们减少状态的不确定性,这就是为什么有一个负号。
是的,数学很好,但我还是有点迷茫…
为了更好地理解这 7 行方程所代表的内容,在概念层面上想象一下卡尔曼滤波器中的情况是很有帮助的。
首先,我们可以想象我们有两个不同的平面(或维度):测量****平面(红色,用 Y 表示)和状态****平面(蓝色,用 X 表示)。状态 x_k 在状态平面中随时间演变。问题是我们不能以任何方式访问或显式观察状态平面,我们只能访问测量平面。测量平面是我们观察由状态引起的测量的地方。
我们无法确切知道状态平面中发生了什么(即,我们无法观察到状态的精确值),但使用卡尔曼滤波器,我们可以将状态平面中的状态行为描述为高斯密度。
在卡尔曼滤波器中,我们从初始高斯开始,描述时间步长 k-1 的状态。这个初始高斯用黑点和圆圈表示(点表示平均值,圆圈是协方差矩阵的轮廓线)。我们使用运动模型来预测状态在时间步长 k 的位置,用蓝色的高斯图表示。然后,我们使用测量模型将预测状态(蓝高斯)从状态平面投影到测量平面。我们最终得到的是红高斯,它本质上描述了我们可以预期测量发生的地方。一旦观察到测量值(用绿色表示),我们就使用红高斯来决定应该使用多少测量值来更新状态平面中的预测状态。在我们更新了预测的状态之后,我们以一个新的黑高斯结束,描述了在时间 k. 的状态的后验概率,然后对所有未来的时间步重复这个过程。
好的,酷,我如何在实践中使用它?
好了,让我们通过展示卡尔曼滤波器在代码中的样子来将所有这些付诸实践,并将其应用到一个玩具示例中。
在玩具示例中,我们将使用我之前提到的飞机示例。为了简单起见,让我们假设飞机在恒定高度飞行。因此,在这种情况下,我们可以选择在状态中包括 xy 位置和 xy 速度
飞机的运动可以用恒速模型来描述。CV 模型很好,因为它是一个实现起来简单的线性模型,同时它能很好地描述飞机的行为。简单地说,它假设飞机的下一个位置是其当前位置和当前速度的函数。假设速度是随机的(受附加高斯噪声的影响),这是有意义的,因为我们不知道飞行员正在采取什么行动。在 1D,这个模型被表述为
参数 T 表示系统中使用的采样时间,而 σ 用作协方差矩阵的比例因子(即表示模型中有多少不确定性)。现在,协方差模型看起来如此时髦的原因是因为我们正在使用一个离散化的 CV 模型(阅读 this 了解更多信息)。这一点很重要,因为我们选择的采样时间 T 会影响滤波器性能(我将在以后的文章中更深入地讨论这个话题)。
在我们的例子中,我们在 x 和 y 两个方向上都有运动,运动模型变成
每个方向的 1D 协方差分量σ分别标有 x 和 y 。这是因为两个方向不一定遭受相同数量的噪声。
好了,现在我们知道如何表达 A 和 Q 了。让我们继续测量模型。这个模型相当简单。我们假设我们在每个时间步测量飞机的位置,并且测量是随机的(服从加性高斯噪声)。这可以表示为
类似于之前我们使用λ作为测量协方差矩阵 R_k 的比例因子。
在为该系统实施卡尔曼滤波器之前,我们将使用这两个模型来生成运动和测量数据。我们稍后将使用这些数据来测试卡尔曼滤波器,看看它的效果如何。为此,我们需要一个可以模拟系统并创建所有模型参数的脚本(注意,@操作符与 numpy 中的 np.matmul 相同,因此 A @ B 与 np.matmul(A,B)相同)。
运行 simulate_model.py 后,我们得到了下面的图,说明了状态的位置分量(x 和 y)如何在 20 个时间步长(采样时间 T=1)内演变,以及观察到的测量值。现在请记住,我们正在模拟系统,这就是我们如何知道真实状态的。**
现在让我们实现卡尔曼滤波器,这是一个简单的过程,因为滤波方程从数学转换成代码非常容易。
有了卡尔曼滤波器,我们现在可以运行它,看看它在我们的模拟数据上表现如何。为此,我们将编写一个脚本,将 kalman_filter.py 和 simulate_model.py 中的功能结合起来。
运行脚本后,我们得到了下面的图,它与之前的图相同,但增加了卡尔曼滤波器对 x 和 y 位置的估计。
仅通过观察该图,很明显卡尔曼滤波器给出了比仅使用原始测量更好的 x 和 y 位置估计。还可以数值分析卡尔曼滤波器优于仅使用测量值的性能。通过使用欧几里德距离作为 x 和 y 位置的误差度量,我们可以计算卡尔曼滤波器和测量的均方根误差(RMSE) 。对于这个 20 个时间步长的场景,每种方法的 RMSE 为
**(20 time-step simulation)
RMSE Kalman Filter: **0.2917**
RMSE Measurements: 0.4441**
卡尔曼滤波器的 RMSE 值比测量值低很多。由于 20 个时间步长相当短,所以让我们研究一下 RMSE 结果是否适用于更长时间的模拟,从而减少统计不确定性。
**(100,000 time-step simulation)
RMSE Kalman Filter: **0.3162**
RMSE Measurements: 0.4241**
就像之前的卡尔曼滤波器一样,这是一个比仅仅使用测量值更好的选择。
(比较只集中在位置状态,因为它们更容易绘制。但是不要忘记,使用我们选择的运动模型,我们也可以从卡尔曼滤波器中得到 x 和 y 方向的速度估计值!)
需要强调的是,玩具示例的目的是说明卡尔曼滤波器是如何工作的。在现实世界的应用中,我们事先不知道模型 参数(Q和 R ),我们甚至可能不知道使用什么运动模型。在这种情况下,大量时间花费在调整滤波器参数和尝试不同的运动模型上。更糟糕的是,大多数时候我们最终处理的是非线性系统,高斯假设不成立。
但与此同时,正是这些类型的问题实际上是解决起来最有趣的!这就是卡尔曼滤波器更复杂的变体或扩展的用武之地——它们根据需要提供不同的方法和策略来解决所有或部分这些问题。
在本系列的下一篇文章中,我将探索一系列的 sigma-point 滤波器,它们由几种不同的滤波器组成,能够在不同程度上处理非线性和非高斯模型。
感谢阅读!
" WTH,神经网络会学习吗?"—新来者的困境
Photo by ANDRIK LANGFIELD PETRIDES on Unsplash
我相信,我们的大脑中都有一个喜欢思考思维是如何发生的心理学家/哲学家。
“深度网络具有层次结构,这使得它们特别适合于学习知识的层次,这些知识在解决现实世界的问题时似乎是有用的。更具体地说,在解决图像识别等问题时,使用不仅理解单个像素,还理解越来越复杂的概念的系统会有所帮助:从边缘到简单的几何形状,一直到复杂的多对象场景。”
——迈克尔·尼尔森在他的书 神经网络和深度学习
那里。
神经网络学习内容的简单、清晰的鸟瞰图——它们学习“越来越复杂的概念”。
这感觉不熟悉吗?我们不就是这样学习的吗?
例如,让我们考虑一下,我们作为孩子,可能是如何学会识别物体和动物的——
- 我们学习什么是“手”、“腿”、“眼睛”、“鼻子”、“嘴”和“耳朵”。
- 我们学习数数,知道我们有两条腿、手、眼睛和耳朵,只有一个鼻子和嘴。
- 然后,我们观察狗,了解到狗和我们一样,但是有四条腿而不是两条腿,而且没有手。
- 然后我们了解到大象是一种动物,就像狗一样,但是很大,鼻子长得出奇。
看到了吗?
所以,神经网络像我们一样学习!
这几乎让我们相信我们拥有这种无形的东西..人造的“东西”那是类比于心灵本身的!对于刚开始深度学习之旅的人来说,尤其具有吸引力。
但不是。神经网络的学习与我们自己的学习不同。几乎所有关于深度学习的可信指南和“入门包”都附有警告,大致如下:
免责声明:神经网络只是非常松散地受到大脑的启发。它们并不代表真实人脑的功能。 警告:在神经学家面前,他们这样做的任何主张都可能引发一场激烈的舌战。
..这就是所有混乱的开始!
Francois Chollet- one of the pioneers of Deep Learning, author of the Keras framework
困惑和为什么它会在那里
我认为这主要是因为大多数教程和初级书籍处理这个问题的方式。
让我们看看迈克尔·尼尔森(Michael Nielsen)在他的书《神经网络和深度学习:
An excerpt from Neural Networks and Deep Learning by Michael Nielsen
像许多其他人一样,他使用神经网络和人类思维之间的类比来试图解释神经网络。线条和边缘形成循环的方式有助于识别一些数字,这就是我们想要做的。许多其他教程试图使用类似的类比来解释构建知识层次的含义。
不得不说,因为这个类比,我对神经网络的理解更深了。
但是这是一个悖论,使一个困难的概念为大众所理解的类比,也能在他们中间产生一种知识的幻觉。
读者需要明白,这只是一个类比。不多不少。他们需要明白,每一个简单的类比后面都需要有更严谨、看似困难的解释。
别误会我的意思。我非常感谢迈克尔·尼尔森写了这本书。这是关于这个主题的最好的书之一。他小心翼翼地提到这是*“只是为了论证”*。
但我把它理解为这个意思— 也许,网络不会使用完全相同的片段。也许,它会找出一些其他的碎片,并以其他方式将它们连接起来,以识别这些数字。但本质会是一样的。对吗?我的意思是,每一部分都必须是某种边缘或线条或某种环状结构。毕竟,如果你想建立一个层次结构来解决识别数字的问题,似乎没有其他的可能性。
随着我对它们以及它们如何工作有了更好的直觉,我明白这种观点显然是错误的。它击中了我..
甚至循环和边缘都不像是 NN 的可能性!
让我们考虑一下循环—
能够识别环对我们人类书写数字至关重要-8 是两个首尾相连的环,9 是下面有尾巴的环,6 是上面有尾巴的环。但是当涉及到识别图像中的数字时,像循环这样的特征对于神经网络来说似乎是困难和不可行的(记住,我说的是你的普通神经网络或 MLPs 这里是)。
- 除了“0”和“8”之外,如果“6”在图片的下半部分,循环只能帮助识别它;如果“9”在图片的上半部分,循环可以帮助识别它。
- 因此,如果我们有一个简单的网络,只有一个隐藏层,我们已经“用完”了该层的 2 个神经元,每个神经元对应于环路的一个位置(上/下)。当你考虑到可能出现的不同形状的环,以及这些数字可以被画出的不同空间位置时,这个数字会迅速增加。
- 现在,即使是一个基本的网络架构(香草神经网络)也可以在只有 20-30 个隐藏神经元的情况下实现显著的准确性(> 95%)。所以,你可以理解为什么这样一个神经网络可能不会进入循环那么多。
我知道这只是一大堆“手动波动”的推理,但我认为这足以令人信服。很可能,边缘和所有其他手工设计的功能将面临类似的问题。
..这是一个两难的问题!
那么,神经网络实际上会学习哪些特征呢?
直到 3blue1brown 发布了一组关于神经网络的视频,我才知道答案或者如何找到它。格兰特·桑德森负责向新来者解释这个问题。也许他甚至觉得其他人的解释中有一些缺失,他可以在他的教程中解决这些问题。
好家伙,他做到了!
视频
3blue1brown 的格兰特·桑德森(Grant Sanderson)使用了一个有两个隐藏层的结构,他说
最初,我激发这种结构的方式是通过描述一种希望,即第二层可能会拾取小边缘,第三层将这些边缘拼凑在一起以识别循环和更长的线,这些可能被拼凑在一起(在最后一层)以识别数字。
我们上面排除的环和边。
Structure of the neural network used in 3blue1brown’s video series
这就是我们的网络实际在做的事情吗?
至少在这一点上——一点也不!
The weight matrices for the 1st hidden layer visualised
他们不再四处寻找孤立的小边缘,而是寻找..嗯,几乎随机(!)只是中间却有些非常松散的模式
他们不是在寻找循环或边缘或任何一点点接近的东西!他们在寻找..好莫名其妙的事情..一些奇怪的模式,可以混淆为随机噪声!
该项目
我发现那些权重矩阵图(在上面的截图中)真的很吸引人。我认为它们是一个乐高拼图。
权重矩阵图像就像基本的乐高积木,我的任务是找出一种方法将它们排列在一起,这样我就可以创建所有的 10 个数字。这个想法的灵感来自于我上面贴的神经网络和深度学习的节选。在那里,我们看到了如何使用手工制作的特征(如边缘和曲线)组装 0。所以,我想,也许,我们可以对神经网络实际发现的好的特征做同样的事情。
我所需要的只是 3blue1brown 的视频中使用的那些权重矩阵图像。现在的问题是格兰特在视频中只放了 7 张图片。所以,我不得不自己制作它们,创造我自己的一套乐高积木!
乐高积木,组装!
我把迈克尔·尼尔森书中使用的代码输入到一个 Jupyter 笔记本中。然后,我在那里扩展了Network类,以包含帮助我可视化权重矩阵的方法。
网络中的每个连接对应一个像素。每个神经元的一个图像显示它有多“喜欢”(颜色:蓝色)或“不喜欢”(颜色:红色)前一层神经元。
因此,如果我观察隐藏层中某个神经元的图像,它就像一张显示一个特征的热图,一个基本的乐高积木,将被用来识别数字。蓝色像素代表它“喜欢”的连接,而红色像素代表它“不喜欢”的连接。
Heat map showing the Carbon Monoxide density. Credits- Nasa Earth Observatory
我训练了一个神经网络:
- 1 个输入层(784 个节点)
- 1 个隐藏层(30 个节点)
- 1 个输出层(10 个节点)
请注意,我们将有 30 种不同类型的基本乐高积木用于我们的乐高拼图,因为这是我们隐藏层的大小。
和..这是它们的样子!—
Hidden layer of the neural network (size- 30 neurons)
这些就是我们一直在寻找的功能!根据网络比环和边更好的那些。
这是它对所有 10 个数字的分类方式:
Weight matrix images attached to the neurons of the output layer
猜猜看?这些都没有任何意义!!
这些特征似乎都没有捕捉到输入图像中任何孤立的可区分特征。所有这些都可能被误认为只是在随机选择的地方随机形成的斑点。
我的意思是,只要看看它如何识别一个‘0’:
这是识别“0”的输出神经元的权重矩阵图像:
Weight matrix image used to identify a ‘0'
为了清楚起见,这个图像中的像素代表连接隐藏层和识别“0”的输出神经元的权重。
我们将只考虑每一个数字的几个最有用的特征。为此,我们可以从视觉上选择最强烈的蓝色像素和最强烈的红色像素。在这里,蓝色的应该给我们最有用的特征,而红色的应该给我们最可怕的特征(把它想象成神经元在说——“如果它是 0,图像将绝对不匹配这个原型”)。
三个最强蓝色像素的指数:3,6,26 三个最强红色像素的指数:5,18,22
Recognising 0’s; indices- 3, 6, 26 (blue) 5, 18, 22 (red)
矩阵 6 和 26 似乎捕捉到了类似蓝色边界的东西,围绕着内部的红色像素——这实际上有助于识别“0”。
但是《黑客帝国 3》呢?它没有抓住任何我们甚至可以用语言解释的特征。《黑客帝国 18》也是如此。为什么神经元会不喜欢它?好像和《黑客帝国 3》挺像的。我们甚至不要在 22 分钟内进入奇怪的蓝色。
荒谬,看!
让我们为‘1’做这件事:
Weight matrix image used to identify a 1
三个最强蓝色像素的指数:0,11,16 顶部两个最强红色像素的指数:7,20
Recognising 1; 0, 11, 16 (blue) 7, 20 (red)
我对此无话可说!我甚至不想评论。
在什么情况下这些可以用来识别 1!?
现在,备受期待的‘8’(它将如何表示其中的 2 个循环??):
Weight matrix image used to identify an 8
前 3 个最强烈的蓝色像素:1,6,14 前 3 个最强烈的红色像素:7,24,27
Recognising 8; 1, 6, 14 (blue) 7, 24, 27 (red)
不,这也不好。似乎没有我们预期的循环。但是这里还有一件有趣的事情需要注意——输出层神经元图像(拼贴上方的那个)中的大多数像素是红色的。看起来这个网络已经找到了一种方法,利用它不喜欢的特征来识别 8!
推理
所以,不。我不能用这些特征像乐高积木一样把数字放在一起。我在这项任务上非常失败。
但是平心而论,这些功能也不是那么像*乐高积木!*原因如下
- 它们可以部分使用。我的意思是他们的贡献状态不是 0 或 1。这些特性中的一些被完全使用,一些被部分使用,一些没有被使用,一些有负面影响(然而重要的是!)对数字结构的影响。这不像乐高积木,既可以用也可以不用。
- 它们似乎没有捕捉到任何特定的特征。相反,它们似乎只有与其他隐藏的神经元结合起来才是有用和合理的(还记得 matrix 3 和 matrix 18 在识别‘0’方面的失败吗?)。一些奇怪的组合,网络已经用我们给它的强大的微积分能力计算出来了!一个如此不可理解的组合,看起来就像“几乎是随机的”!
原来如此,原来如此。如果你像我们一样考虑神经网络构建特征层次的方式,可以说神经网络像我们一样学习。但是当你看到功能本身时,它们与我们使用的完全不同。网络几乎没有给你解释它们所学习的特征。
神经网络是很好的函数近似器。当我们构建和训练一个模型时,我们主要关心它的准确性— 它在多大比例的测试样本上给出了肯定的结果?
这对于许多目的来说都非常有效,因为现代神经网络可以具有非常高的准确性——超过 98%并不少见(这意味着失败的几率仅为 1/100!)
但是这里有一个问题——当他们错了,没有简单的方法去理解他们错的原因。它们不能被传统意义上的“调试”。举个例子,这是谷歌因为这个发生的一个尴尬的事件:
Because of this incident, When it comes to gorillas, Google Photos remains blind even now!
理解神经网络学习什么是一个非常重要的课题。这对释放深度学习的真正力量至关重要。它会帮我们进去
- 仅基于神经网络创建可调试的端到端系统
- 使用这样的系统来拓宽我们对各种主题的理解,并最终实现使用人工智能来增强人类智能的目标
几周前,《纽约时报》杂志刊登了一篇关于神经网络如何被训练成以惊人的准确度预测癌症患者死亡的报道。
这位作家是一位肿瘤学家,他说:
那么,关于死亡的过程,算法到底“学到”了什么?反过来,它能教给肿瘤学家什么?这是这样一个深度学习系统的奇怪之处:它学习,但它不能告诉我们它为什么学习;它分配概率,但是它不能容易地表达分配背后的推理。就像一个通过反复试验学会骑自行车的孩子,被要求说出骑自行车的规则,只是耸耸肩就离开了,当我们问“为什么?”时,算法茫然地看着我们就像死亡一样,它是另一个黑匣子。
一位肿瘤学家在《纽约时报杂志》上发表的文章
因为我的小项目,我想我对此有强烈的共鸣。:-)
奖金部分(请随意跳过)
在我之前描述的小项目中,我偶然发现了一些其他的结果,我觉得它们真的很酷,值得分享。所以他们在这里—
较小的网络:
我想看看我能使隐藏层的大小变得多小,同时在我的测试集中仍能获得相当高的精确度。结果表明,用 10 个神经元,该网络能够从 10000 张测试图像中正确分类 9343 张。只用 10 个隐藏神经元就能对从未见过的图像进行分类,准确率达到 93.43%。
只需 10 种不同类型的乐高积木就能识别 10 个数字!!
我觉得这非常有趣。
Hidden layer of the neural network with 10 neurons in it
当然这些权重也没有太大意义!
Weight matrix images for the output layer
如果你好奇的话,我也用 5 个神经元进行了测试,我得到了 86.65%的准确率;4 个神经元——准确率 83.73%;在此之下,下降幅度非常大——3 个神经元下降了 58.75%,2 个神经元下降了 22.80%。
重量初始化+正则化带来很大不同:
仅仅是调整你的网络和对权重使用良好的初始化就能对你的网络学习产生巨大的影响。
让我来演示一下。
我使用了相同的网络架构,意味着相同的层数和相同的神经元数。然后我训练了 2 个Network物体——一个没有正则化,使用相同的旧np.random.randn(),而另一个我使用正则化和np.random.randn()/sqrt(n)。这是我观察到的:
Comparison of what the weight matrices look like before/after using regularisation + good weight initialiser
是啊!我也震惊了!
(注: 我已经在上图拼贴中展示了与不同指数神经元相关的权重矩阵。这是因为由于不同的初始化,即使是相同索引的节点也学习不同的特征。所以,我选择了那些看起来效果最明显的。 )
要了解更多关于神经网络中的权重初始化技术,我推荐你从这里的开始。
感谢您的阅读!😄
如果你想讨论这篇文章或你脑海中的任何其他项目或真的任何事情,请随时在下面评论或在 LinkedIn 或 Twitter 上给我留言。
我是一名自由作家。你可以雇我为你公司的博客写类似的深入、热情的文章,解释 ML/DL 技术。给我发邮件到 **nityeshagarwal[at]gmail[dot]com** 讨论我们的合作。
还有,你可以在 Twitter 上关注我;我不会给你发垃圾邮件;-)
最初发表于 Zeolearn 博客。
将 XGBoost 模型转换成 if-else 格式
New river, WV, photo by myself
在本文中,我将向读者展示如何使用正则表达式的一些技巧将 XGBoost 模型转换成. py 文件。py 文件是“numpy”包。因此,在您训练了 XGB 模型之后,您可以在另一个不需要 XGBoost 包的环境中部署该模型。
当您计划在 AWS lambda 中部署 XGBoost 模型时,这个技巧可以帮助您满足包大小的限制。如果你打算用其他方法(AWS sage maker/Docker+Flask+Nginx……)部署模型,那么这篇文章可能真的帮不了你。
本教程分为几个部分:下载数据并训练模型→将模型转换为. py 文件→使用。py 文件来预测测试数据。
步骤 0。下载 jupyter 笔记本
这本笔记本包含了下面所有的代码。把它放在你的目标文件夹里。
第一步。下载数据并训练模型
让我们使用众所周知的泰坦尼克号数据集来建立一个玩具模型。从链接下载 train.csv 和 test.csv。创建一个子文件夹“/data”并将。csv 在那里。
因为 XGBoost 只接受数字输入,所以让我们跳过分类变量编码,随机选择几个数字列进行建模。
这个 XGBoost 模型产生 3 个决策树,每个决策树的最大高度= 3。因为 gamma(分裂次数的惩罚常数)被设置为一个较大的值,所以它可以防止对某些树节点进行分裂。
决策树看起来像:
每个记录的预测得分由“基础得分+所有树的最终叶值”给出。
第二步。将模型转换为. py 文件
在 XGBoost Python API 中,您可以找到允许您将模型作为字符串或. txt 文件转储的函数,或者保存模型以备后用。但是没有 API 将模型作为 Python 函数转储。这里有一个技巧:我们首先将模型作为一个字符串转储,然后使用正则表达式解析这个长字符串并将其转换成一个. py 文件。
完成这项工作的代码片段:
使用模型训练中使用的基本分数和训练的模型,我们能够将其转换为. py 模型,该模型只需要“numpy”包(用于缺失值处理)。
model_to_py(params['base_score'], model, 'xgb_model.py')
生成的“xgb_model.py”的一部分如下所示:
第三步。使用。py 文件来预测测试数据。
我们现在可以导入刚刚创建的 xgb_model.py,执行预测非常简单。
让我们将其与 XGBoost 模型产生的预测进行比较。
结果匹配。
一些警告:
- 这些代码在 python 3.5.2 + xgboost 0.6 下运行良好。不保证为其他版本生成正确的结果。
- 我没有在我的代码中做任何错误处理。
- 的。py 是为给 python 字典打分而设计的,但是您可以做一些小的修改来适应您的用例。
- 在生成。py 文件,确保没有。目标文件夹中同名的 py 文件。
XGBoost 不是黑魔法
Photo by Tobias Tullius on Unsplash
不输入缺失值并不总是正确的选择。
如今,在数据科学任务中取得令人满意的结果相当容易:对这个过程有一个大致的了解,对 Python 有一个基本的了解,花十分钟的时间实例化 XGBoost 并拟合模型就足够了。好的,如果这是你的第一次,那么你可能会花几分钟通过 pip 收集需要的包,但是仅此而已。这种方法的唯一问题是它工作得相当好🤷🏻♂️:几年前,我在一次大学竞赛中,通过将数据集输入到一个具有一些基本功能工程的 XGBoost,击败了展示非常复杂的架构和数据管道的团队,名列前五。XGBoost 最酷的特性之一是它处理缺失值的方式:决定每个样本的最佳估算方式。这个特性对我在过去几个月中遇到的许多项目和数据集非常有用;为了更配得上以我的名字命名的数据科学家的头衔,我决定更深入一点,花几个小时阅读的原始论文,试图理解 XGBoost 实际上是什么,以及它如何能够以某种神奇的方式处理缺失值。
从决策树到 XGBoost
决策树可能是机器学习中最简单的算法:树的每个节点是对一个特征的测试,每个分支代表测试的一个结果;树叶包含模型的输出,无论是离散的标签还是实数。决策树可以被描述为一个函数:
(1)
函数 f 根据树结构 T 基于 m 大小的样本 x 所遵循的从根到叶子的路径分配一个权重 w 。
现在想象有不止一棵决策树,而是 K 棵;最终产生的输出不再是与叶子相关联的权重,而是与每一棵树产生的叶子相关联的权重的总和。
(2)
这些结构不是固定的,与经典梯度下降框架中发生的情况不同,在经典梯度下降框架中,网络结构不变,权重在每一步更新,在每次迭代中添加新的函数(树)以提高模型的性能。为了避免过度拟合和/或非常复杂的结构,误差由两部分组成:第一部分对在第 k 次迭代中获得的模型的良好性进行评分,以及第二部分对与叶子相关联的权重的大小以及所开发的树的深度和结构的复杂性进行惩罚。
(3)
然后,使用二阶梯度统计简化该目标函数,并且——无需输入太多细节——可以直接用于以封闭形式计算与固定树结构相关联的最佳叶的权重。重量可以直接与误差相关联,因此与所使用的固定结构的良好性相关联(3)。
训练 XGBoost 是一个迭代过程,它在每一步计算第 k 棵树的最佳可能分裂,枚举在路径中该点仍然可用的所有可能结构。这种对所有可能拆分的详尽列举非常符合本文的范围,但在实践中不可行,它被一种近似的版本所取代,该版本不尝试所有可能的拆分,而是根据每个特性分布的百分位数仅列举与相关的个。
XGBoost 和缺失值:神奇的事情发生在哪里
一旦训练了一个树结构,也就不难考虑测试集中缺失值的存在:为每个决策节点附加一个默认方向就足够了。如果样本的特征丢失,并且判定节点在该特征上分割,则路径采用分支的默认方向,并且路径继续。但是给每个分支分配一个默认的方向更复杂,这可能是本文最有趣的部分。
已经解释过的分裂寻找算法可以稍微调整一下,不仅返回每一步的最佳分裂,还返回分配给新插入的决策节点的默认方向。给定一个特征集 I,,所有可能的分裂都被枚举,但是现在相应的损失不是被计算一次而是两次,对于该特征的缺失值可能采取的每个默认方向一次。根据特征 m 的值 j 进行分割时,两者中最好的一个是要分配的最佳默认方向。最好的分割仍然是最大化计算分数的分割,但是现在我们给它附加了一个默认的方向。
这种算法被称为稀疏感知分裂查找,这也是 XGBoost 背后的魔力所在;最后不太复杂。稀疏感知方法仅保证平均而言采用默认方向会导致给定已经遍历的分裂的最佳可能结果,它不保证已经遍历的分裂(可能通过采用默认方向解决)是考虑整个样本的最佳结果。如果样本中缺失值的百分比增加,内置策略的性能可能会大大下降。
好吧,默认方向是最佳选择,因为它到达了当前位置,但是考虑到当前样本的所有特征,不能保证当前位置是最佳情况。
克服这一限制意味着在处理样本时同时考虑其所有特征和直接处理同一实现中可能同时存在的多个缺失值。
输入缺失值并提高性能
为了击败 XGBoost 内置策略,我们必须同时考虑样本的所有特征,并以某种方式处理样本中可能存在的多个缺失值。这种方法的一个很好的例子是 K-最近邻(KNN ),它具有专门的距离度量来适当地处理缺失值。一般来说,KNN 是一种众所周知的算法,它检索 K 个(例如 3,10,50,…)最接近所考虑样本的样本。它既可用于对未知输入进行分类,也可用于估算缺失值,在这两种情况下,考虑 K 个最近邻,将平均值或中值分配给目标值。这种方法需要距离度量(或者相应地,相似性度量)来实际排列训练集中的所有样本,并检索最相似的 K 个*。*
为了超越 XGBoost 内置的默认策略,我们需要两件事情:
- 考虑到缺失值的距离度量(感谢 AirBnb 的这篇文章带来的灵感)
Python implementation of the distance metric employed
- 对数据集进行归一化处理,以获得有意义的距离,该距离是对不同属性域的要素之间的差异进行求和而获得的(XGBoost 并不严格要求这样做,但 KNN 插补需要这样做!).
使用 K 个最接近样本的所述特征的中值来估算特征的缺失值,并且在 K 个检索到的邻居中找不到至少一个非缺失值的非常特殊的情况下,使用整个列的中值。
实验结果
我在 scikit-learn 中使用三个著名的免费数据集进行了一些测试(两个分类和一个回归)。已经通过比较三种不同插补策略的 k 倍交叉验证来测量性能:
- 默认的内置在 XGBoost 算法中
- 简单的按列中位数插补
- 如前一段所述的 KNN
对于 KNN 的情况,我已经针对 k (要考虑的邻居数量)和 λ (当两个样本中至少有一个样本的某个特征缺失时,要添加到距离中的常数)绘制了所考虑的缺失值百分比的最佳性能。
Figure 1
使用稀疏感知 KNN 来输入缺失值始终优于其他两种方法。差异的程度当然取决于数据集。第一个天真的结论是:数据集的质量越差,更好的插补策略的影响就越大。如图 2 所示,内置策略最终的性能接近于普通的列式中位数插补。
Figure 2
看到 k 和 λ 如何影响最终结果,以及引入惩罚因子不仅仅是在纸面上是有意义的,这非常有趣。距离度量不仅丢弃缺失值,而且为它们中的每一个增加权重,这对于用这种方法获得的性能是至关重要的,即使它的值与缺失值百分比的增加不直接相关。
Figure 3
测试表明,根据经验法则,缺失值的数量越多,就有越多的邻居需要考虑进行更好的插补。再一次非常直观的结论。
XGBoost:每个人的王者之剑
Photo by Daniel Mayovskiy on Unsplash
当我发现 XGBoost 算法时,我对它的能力有点怀疑,因为无论我在哪里读到它,每个人都在谈论它有多么伟大和神奇。在进一步挖掘 XGBoost 的“魔法”因素时,我发现它一直是许多 Kaggle 竞赛获胜者的基本元素,在某些情况下,人们将“ only 算法应用于他们的数据集。
自然的做法是从现有的代码样本中测试该算法,亲自看看它有多好。我在我自己的一个正在运行的项目中这样做了,我首先使用随机福里斯特回归器并计算它的平均绝对误差,然后我将相同的数据帧传递给我的 XGB 回归器并计算它的平均绝对误差。结果大相径庭!(比我之前的型号好了近 20%)
在访问 XGBoost 的官方文档时,我发现甚至有一些参数可以进一步调整以获得更好的结果。这太神奇了!没有时间浪费,我快速阅读了文档,并为我的模型添加了一些参数。我得到了一些错误,无法理解这些参数中的大多数在做什么,留下了一些像 n_estimators 和 learning_rate 的错误,但我能够拟合我的模型,结果再次以更好的准确性打破了以前的记录。(增长并不显著,但我猜不同型号之间会有所不同)
我将在这里分享我的一些发现,我相信这些发现会让您很好地了解如何在下一次分析中使用 XGBoost。
一些灵感:
陈天琦开发了 XGBoost,它最初是作为分布式(深度)机器学习社区(DMLC)小组的一部分的一个研究项目。第一次发布是在 2014 年 3 月。
除了使用机器学习和数据分析之外,增强树的功能已经得到了极大的利用。值得一提的是,希格斯玻色子 T21 的发现有可能是通过使用增强的树木实现的。可以看一下这个发现相关的论文。
Bagging 和 Boosting 的区别 XGBoost 是如何工作的
为了理解 XGBoost 是如何工作的,是什么让它变得更好,我们必须理解 Boosted 树与 Random Forrest 有什么不同。
随机福里斯特回归器中使用了装袋概念。Bagging 代表Bootstrap aggregate*,这意味着选择一个随机样本并替换。Bagging 算法的基本步骤是从数据集生成 n 个样本(与决策树回归器中形成的单个树相反),单独训练每个样本,并在最后对所有预测进行平均。需要注意的重要一点是装袋减少了我们模型的方差。*
在我们的 XGBoost 回归器中使用了 Boosting 概念。在 Boosting 中,我们用来训练每个迷你树的随机样本被挑选出来,并替换加权数据*。由于这个事实,我们可以将每个样本称为弱学习者。这些弱学习者中的每一个都基于其分类的准确性被分配一个权重。在这些弱学习者被训练之后,他们的估计的加权平均被用于最后的最终预测。所以我们的弱学习者结合在一起,形成强学习者。*
Source: XGBoost
Source: XGBoost
XGBoost 代表极限梯度提升。梯度推进是一种集成方法*,它依次添加我们训练过的预测器,并为它们分配一个权重。然而,该方法不是在每次迭代后给分类器分配不同的权重,而是将新模型拟合到先前预测的新残差,然后在添加最新预测时最小化损失。*因此,最后,您使用梯度下降来更新您的模型,因此得名梯度推进。回归和分类问题都支持这一点。具体来说,XGBoost 通过在目标函数中添加一个自定义正则项来实现决策树提升算法。
一个好的方法是考虑一个项目组,每个人在一个领域比其他人更好,这些人可以组合在一起成为一个伟大的项目。所以,许多弱学习者成为强学习者。挺实用的!
使用目标函数(损失函数+罚函数)来实现该算法,其中添加了重要的正则化项(罚函数,其将“增强”置于梯度增强中)。
你可以在 XGBoost 介绍页面上阅读更多关于算法工作的内容。
SauceCat 还写了一篇很棒的帖子,深入探讨了算法背后的数学原理以及数据科学方面的代码。
代码中的 XGBoost
使用 XGBoost 回归器就像使用任何其他基于回归的方法一样,比如 Random Forrest。我们遵循相同的方法:
- 清理数据
- 选择重要的参数
- 制作培训和测试集
- 让模型适合您的训练集
- 根据您的测试数据评估您的模型
当然,还有在这之间你可能采取的每一步。
我们认为您已经有了训练和测试数据,并且在拟合模型之前已经执行了所需的步骤。如果您还没有,只需在 Pandas 中制作一个简单的数据框架,并使用 Scikit-Learn 的 train_test_split 函数将您的数据自动拆分为一个训练和测试集。
*from xgboost import XGBRegressor #The library to be importedmodel = XGBRegressor()
model.fit(training_Set_X, training_Set_y, verbose=False)
predictions = model.predict(testing_Set_X)from sklearn.metrics import mean_absolute_error#Computing the MAE of our predictions
print("Mean Absolute Error : " + str(mean_absolute_error(predictions, testing_Set_y)))*
使用 XGBRegressor 的一个更好的方法是利用可以传递给它的附加参数。你可以在下面的截图中看到参数是如何对我们预测的准确性产生巨大影响的。(差异可能会更大或更小,这取决于您的数据集
XGBRegressor 提供了许多调整参数,可用于显著减少训练时间和准确性。
**
XGBoost 提供的另一个伟大特性是 plot_importance 函数,它可以提供我们的模型的特性及其重要性的图表。
这对于分析我们的模型和评估我们的特性是一个很好的补充。我们可能会选择放弃一些功能,以防它们对我们的模型没有意义。
请务必访问 XGBoost 网站,因为它们提供了对特性和算法的简单易懂的解释,不会让读者被沉重的数学符号所迷惑。(虽然我们看到的大多数与机器学习相关的符号都只是由求和符号组成,但这个符号有一些让人们害怕的东西。)
我希望这篇介绍足以让您开始使用 XGBoosting(这个名字肯定是 DataScience Block 上最酷的名字)。如果你一直在使用这个算法,请发表你的见解。我会试着更新这篇文章来介绍它的数学概念。
xkcd.com+人工智能
这篇文章向您展示了我们如何使用数据科学、深度学习和肘部油脂来创建 xkcd.com 漫画分类器。我们可以从漫画的描述中预测漫画的主题。
xkcd is an excellent example of time well wasted.
我的朋友圈里有一个巨大的书呆子迷恋兰道尔·门罗,xkcd 漫画的作者,还有像如果这样的书?。 Mary Kate MacPherson 主动,为每一部漫画刮抄本,用我的专利分析器代码把抄本变成嵌入向量。然后,她将向量和标签放入 tensorflow,并使用 t-SNE 将数据分解成簇 T10。那些了解 xkcd.com 的人会很清楚漫画是按顺序编号的。我打赌兰德尔会在漫画编号与当前年份(2018 年)相同时提及,所以我必须尽快发表这篇文章!写这句话的时候,他已经在 2017 年了!
这里有一个视频,展示了降维是如何进行的,有 3D 的也有 2D 的:
Sorry I didn’t have the time to clip and edit the video like I wanted to, so it’s a bit long. Feel free to jump around and see the difference between 2D and 3D, and other settings. A learning rate of 1 worked best for us. The result we used is shown in an annotated screenshot below.
t-SNE 降维的输出是从原始的 300 维嵌入空间压缩下来的 2D 空间中的一串点。
玛丽·凯特·麦克弗森接着查看了 2D 结果上的聚类,以理解它们的含义。下图向我们展示了按主题和实体分类的文章。
This is our look into Randall Munroe’s brain.
纵观全局,我们可以看到关于食物的漫画聚集在一起,关于星球大战、趋势、文字游戏、儿童、图表等等的文章也是如此。作为人类,我们可以识别十几个或更少项目的小集群(例如,kid cluster),但为了做好工作,深度学习希望看到大量的例子,因此我将在下面向您展示如何使用更少的集群建立 xkcd 主题模型。作为背景,xkcd.com 总共有大约 2000 本漫画。
让我们来看看漫画是如何在时间域中聚集的:
Brighter dot = newer comic. Darker dot = older comic.
下面是原始代码:
Original patent application to vectors code… but comics are way more fun!
在 python 中应用 t-SNE 和 GMM ,我们得到以下集群:
Not super nice clumps. Let’s try again….
当我们看到像上面这样的星团时,这不是一个好结果。我们希望在有数据的地方看到簇,在簇之间看到空洞。这让我想起我经常从我的一个朋友那里听到的一句话“ ”未来已经在这里了——只是不是很均匀地分布 。因此,当我们看到这样的均匀分布时,这通常意味着我们需要再试一次。
以下是我们希望看到的分离类型的示例:
This MNIST example looks way better than what we got from our python code so far… Source: this online book.
The color of each dot shows the cluster membership for that dot. There are still not as nice separations as we saw with the embedding projector…
我想我找到 tensorboard 和我的 python 代码不匹配的原因了。我在 25 岁而不是 12 岁时感到困惑。DOH。现在我改变了 2D 和 3D 困惑值,并重新运行代码。以下是我们得到的结果:
Each color is a different cluster. It looks quite similar to the original non-working example… But a later version worked amazing, as you will see…
2D slice of the 3D t-SNE results. Clusters 4 and 6 are pretty mixed up.
我对 2D t-SNE 的结果很满意,但是 GMM 没有做好细分工作:
More separation than the last time.
归一化t-SNE 之前的 300 列给了我们这个结果:
Let’s just go for it…
让我们退出对 t-SNE 的研究,试着去理解集群,但首先这里是用来做这些事情的数据…
提醒您一下,我们已经使用漫画创建了一个主题模型。这里是每个漫画的主题模型向量,这里是每个漫画的主题标签(只是整数)。我已经把一些东西组织到了 github repo 中,以满足你的编码乐趣。
下面是使用上述自动化方法为每个漫画制作的聚类数据帧: 3D 和 2D 。这是在 2D 和 3D 中应用 t-SNE 的笔记本。下面是使用下面描述的手动方法为每个漫画(10 个聚类的样本)制作的聚类标签(只是整数)。
这一切意味着什么?
以下是我们对由 GMM 聚类的 3D t-SNE 数据的聚类解释:
来自该 3D 数据集的聚类示例有:零(问题)一(技术)两(图形)三(日期+地点)四(时间)五(思考的东西)六(帽子!是的,帽子!)、七(烂东西)八(数学)九 (interwebz)。
以下是我们对使用嵌入式投影仪手工创建的 2D 星团数据的解读:
来自这个数据集中的聚类例子有:一个(时间)两个(哲学)三个(科学)四个(视角)五个(兴奋)六个(梅根)七个(计算机网页)八个(连字符)九个(科技),以及十个(思维素材)。
特别感谢玛丽·凯特·麦克弗森为集群标记做了所有的体力劳动,也感谢马修·勒梅让她来做这件事。
要手动制作您自己的分类标签…
为了手动获得聚类(标签),我们运行 10,000 次 t-SNE 迭代(学习率= 1;困惑= 12 ),而不是使用聚类(k-means 或 GMM ),我们只是目测它,并提取每个聚类的 id。我非常喜欢你们这些读者能够前往 projector.tensorflow.org 完全复制这个实验。
下面是如何自己“手动”完成这项工作的大图:
This is the picture of the hand-made data we used.
现在让我们一步一步地来看:
1)加载数据
以下是嵌入式投影仪中数据交互版本的链接:
可视化高维数据。](projector.tensorflow.org/?config=htt…)
2)运行 t-SNE。当你觉得聚类看起来不错的时候就停下来。
3)通过使用注释工具拖动来手动创建聚类
This is the tool you want
Drag the tool to make a box over the points you want to label. We can see that the cluster includes samples such as 1834, 128, 307, 459, 89, and 477. They are about disaster, pain, disaster, angry exclamation… I see a pattern.
The points will show up in the list on the right hand side
4)检查右边列表的来源,复制出列表的 HTML DIV(我知道:gross,它有一个限制 100,所以你没有得到大集群的所有数据)
5)在 notepad++中用空格替换所有 HTML。为此,只需转到替换菜单(CTRL+H ),用空格字符替换此正则表达式:
<[^>]+>
现在用单空格替换所有双空格,直到只剩下单空格,然后用换行符替换所有单空格。去掉第一个空格字符,我们现在有了这个集群的 id 列表。对每个集群重复上述步骤,直到覆盖了您关心的所有集群。砰。完成了。
您可以在 python 或 excel 中将所有聚类合并到一个文件中。这里很容易看出我们是如何构建主题模型的熊猫数据框架的。
预测的东西!
如果能建立一个 xkcd 的主题模型,并且 预测 给定漫画是关于什么样的主题,那就太棒了。
我们知道输入(X)是漫画的主题模型向量和漫画的升序 ID,预测(Y)是聚类标签。因此,我们知道这是一个分类问题,需要一个 softmax,MLP (DNN)似乎适合这个工作。
这是我们在 3D t-SNE 数据集上使用的网络(random_state=42!):
model = Sequential()
model.add(Dense(128, activation='relu', input_dim=X_train.shape[1]))
model.add(Dropout(0.5))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(y_train.shape[1], activation='softmax'))
我们从这个网络中得到了非常好的预测(89%的准确率):
Confusion Matrix
[[11 0 0 1 0 0 0 0 0 0]
[ 0 27 0 0 0 0 1 2 1 1]
[ 0 2 11 0 0 0 0 0 4 2]
[ 0 1 0 16 0 0 0 0 0 0]
[ 0 0 0 0 24 0 1 1 0 0]
[ 1 0 0 1 0 25 0 0 0 0]
[ 0 0 0 0 1 0 18 0 0 0]
[ 0 0 0 0 0 0 0 12 0 0]
[ 0 0 0 0 0 0 0 0 23 0]
[ 0 2 0 0 0 0 0 0 0 13]]
如果你真的在玩这个数据集,那么听到你的结果将会很棒!我相信兰德尔会很高兴我们都厌倦了他多年来的涂鸦。
快乐 xkcd 编码,
丹尼尔
daniel@lemay.ai ←打个招呼。 LEMAY . AI 1(855)LEMAY-AI
您可能喜欢的其他文章:
另一个文本生成项目
我对深度学习比较陌生。我正努力尽快赶上进度,但我担心在这个过程中我可能会挖出一些旧东西。从我初学者的角度来看,文本生成还是很刺激的!我希望我能通过这篇文章和附带的知识库帮助一些人…
和很多人一样,我是在看了 Andrej Karpathy 的著名博文:《递归神经网络的不合理有效性》后爱上递归神经网络(RNN)的。这篇文章令人大开眼界,它证明了 RNN 在学习序列数据方面有多好,以及一个训练有素的网络如何可以用来生成新的和类似的数据。
在他的文章中,要学习的序列数据是文本。文本被认为是一串相继出现的字符。一个基于 RNN 的神经网络被训练来从前面的字符序列中预测下一个字符。这种网络通常被称为“char-rnn”。
为了更好地工作,网络从字符序列中学习高级概念。它逐渐了解数据中越来越多有趣的方面。它可以学习单词和如何拼写单词,如何尊重良好的语法,最终,它可能能够生成或多或少有意义的带标点的句子。对于最后一部分,为了生成从头到尾都有意义的长句(甚至是更大的任务,如生成整个故事),网络必须学会保存和管理大量的上下文(这很难)。
多年来,相关代码已经被移植到更新的深度学习库中,如谷歌的 tensorflow ,以及高级 API keras 。RNN 的生成性用法现在非常流行。然而,让我开始这个主题的是一个应用程序的想法(我以为我首先想到的,我太天真了)。
特朗普机器人军队
由于唐纳德·特朗普的言论非常有趣,我想,作为一个个人项目,我可以训练一个神经网络来产生更多的言论,也许我可以通过阅读结果来获得一两个笑声。很快就发现我不是第一个有这个想法的人。
我发现的一些项目可以追溯到 2015 年,像这个叫做 RoboTrump 的项目,网络在单词级别工作(下一个单词预测)。
有些是特朗普在总统竞选中还是局外人时创造的,他们几乎不知道:
“我写这篇文章的时候,美国正在进行总统选举。这次我们有一些不寻常的候选人,我想看看 RNN 能从他们的演讲中学到多少有趣的东西。”deeplearningathome.com
最成功的似乎是 @DeepDrumpf (有自己的推特账号)。它甚至引起了我们最喜欢的 char-rnn 专家的注意:
足够的考古学,回到我(非革命的)对这个主题的看法。
我对特朗普的看法
我用 Keras 2.0.6 创建了一个 char-rnn(用 tensorflow 后端)。在这个地址的什么都有。它采用两个 python 笔记本的形式,一个用于训练,一个用于测试。您可以使用数据集,从头开始训练模型,或者跳过这一部分,使用提供的权重来玩文本生成(玩得开心!).
注意:训练代码是“多 GPU 兼容”。根据我的经验,如果输入网络的序列很长(例如 120 个),可以显著减少训练时间。对于双 GPU,我每个时期的时间减少了 56%。
收集和清理数据
我基于特朗普推特档案建立了一个文本数据集,这是一个所有总统推特的最新档案(从 2009 年开始约有 32000 条推特)。
这表示 3.3MB 的文本数据,大约是 350 万个字符。据我所知,对于我们要做的事情来说,它并不是很大。 字符“词汇”按顺序固定为 98 个可打印的 ASCII 字符(在稳定的词汇上工作有助于改变模型的用途)
数据准备
训练基于向网络输入 60 个字符的固定大小的序列。使用我的 GPU,我能够处理包含 512 个样本的大批量数据。
一批是 512 个 60 个字符的序列的列表。每个字符只能是词汇表中 98 个可用条目中的一个。对于每个 60 个字符的序列,预期的输出是第 61 个字符。预测只是一个步骤(长度为 1 的序列)。
准备这些批次会占用大量内存。因此,批量创建是在训练时实时完成的。
模型架构和培训
该建筑的灵感来自弗朗索瓦·乔莱(Franç ois Chollet)的作品,该作品可在 Keras repository 中找到(它本身源自卡帕西的作品)。
神经网络有 4 个堆叠的 512 单元 LSTM 层,每一层后面都有 20%随机神经元丢失用于正则化。 最后一个递归层被设置为只返回其最终状态(一步)。 一个全连接的常规层获取大小为 512 的“隐藏”向量,并将其带回词汇表的大小(98)。 最后一个处理是将 softmax 函数应用于该向量,使其成为字符概率分布。 最后,使用 Adam 优化器训练网络,以最小化交叉熵损失函数(或多或少分布之间的距离)。
经过十几代的训练,输出开始听起来连贯。
注意:对于 Keras 鉴赏家,我使用“无状态”模式进行训练,这意味着在两个(甚至连续的)60 个字符的序列之间的网络中没有保存任何东西。但是,在生成文本时,网络以 1 对 1 字符的“有状态”模式使用(RNN 单元状态从不重置)
模型检验
这个模型现在可以用来生成类似 Trump 的文本。可以给网络一个种子(一些文本)来预热,并在生成过程中 100%自主之前获得一些上下文。
在生成的同时也加入了一些即兴创作。在每一步中,所选择的字符并不总是网络输出中概率最高的字符。这个额外的步骤防止了循环,并给出了更多的人工结果。
下面是一个低多样性的例子:
[I, Donald J. Trump, president of the United ]States of The Apprentice and the world in the world that we have to be a great trade deal and the people of the World Trade Center in the world that we have to be a great person to be a great problem.
同样的种子和更高的多样性:
[I, Donald J. Trump, president of the United ]States. Were going to have you to say what happens to try to make America great again. We're going to tell you that we have to win. We owe $100.
这个模型本身很有趣,但它很少连贯。它无法长时间保持上下文。很容易看到网络忘记了不久前开始的事情。
60 个字符的序列长度相对较短可能是一个原因。该长度决定了训练时梯度可以向后传播多远(随时间截断的反向传播)。更大的“回顾”可以使学习更长的依赖性成为可能。例如,一个经过理想训练的 char-rnn 应该能够跟踪引号和括号,以便确保将它们关闭,记住当前句子的主题等。
糟糕的结果也可能来自数据本身。可能是尺寸太有限了。此外,推特可能不是学习语言的最佳方式。Tweets 很短并且独立,它们包含奇怪的文本,比如 URL 和用户句柄等等。
最后的测试…
基于该网络了解到的一切,它能回答一个真正的问题吗:covfefe 推文的真正结局是什么?
以下是以推文开头为种子的一些尝试:
[Despite the constant negative press cov]erage. I was going to be great. But if they’re going to stop the good guy who has a big night.[Despite the constant negative press cov]erage. Looking forward to it. The fundraisers are totally promised by the Central Park South...[Despite the constant negative press cov]erage lines to Trump Tower. That’s not the relationships. It doesn’t have to be a disaster to Iraq.[Despite the constant negative press cov]erage car millions of people and spot. We are going to come back. We have to go to golf.
看起来他真的是指报道…强大的 Covfefe 被错误的召唤了。
这个故事到此结束。如果你喜欢,可以关注我的 中 或 推特 获取最新消息。如果你喜欢美食,你可能会喜欢阅读 这篇 。如果你更喜欢《权力的游戏》, 去那里 。
另外,如果你发现有什么不对的地方,或者有任何问题,欢迎在下面评论。
另一个推特情绪分析第一部分——解决阶级不平衡
Photo by Piret Ilver on Unsplash
不久前,我在 Twitter 情绪分析上完成了 11 篇系列博文。为什么我要再做一次情感分析?我想进一步扩展,对真实检索的推文进行情感分析。我之前的情感分析项目还有其他限制。
- 该项目停止在最终的训练模型上,并且缺乏对检索到的推文的模型应用
- 该模型仅在正面和负面类别上训练,因此它缺乏预测中性类别的能力
关于中性类别,可以为负面、中性和正面类别设置阈值,并将最终输出概率值映射到三个类别中的一个,但我想用训练数据训练一个模型,该模型有三个情感类别:负面、中性和正面。
因为我已经写了一个相当长的关于 NLP,情感分析的系列文章,如果一个概念已经在我以前的文章中提到过,我就不详细解释了。此外,主要的数据可视化将与检索到的 tweets 有关,我不会对我用于训练和测试模型的数据进行大量的数据可视化。
除了我将附上的简短代码块,你可以在这篇文章的末尾找到整个 Jupyter 笔记本的链接。
数据
为了训练我的情感分类器,我需要一个满足以下条件的数据集。
- 优选地,推特带有注释情感标签的文本数据
- 有 3 个情绪等级:消极,中立,积极
- 大到可以训练一个模特
当我在谷歌上寻找一个好的数据源时,我了解到了一个著名的 NLP 竞赛,叫做 SemEval。 SemEval(语义评估)是正在进行的一系列计算语义分析系统的评估,由 SIGLEX 组织,SIGLEX 是计算语言学协会词汇方面的特别兴趣小组。
如果你对 NLP 感兴趣,你可能已经听说过这个。来自世界各地的高技能团队在几个任务上竞争,例如“语义文本相似度”、“多语言语义单词相似度”等。比赛任务之一是推特情感分析。它也有几个子任务,但我想重点关注的是“子任务 a .:消息极性分类:给定一条消息,分类该消息是正面、负面还是中性情绪”。
幸运的是,他们为比赛提供的数据集可供下载。训练数据由 SemEval 之前的训练和测试数据组成。更棒的是他们提供测试数据,所有参赛的队伍都是用同样的测试数据打分。这意味着我可以将我的模型性能与 2017 年 SemEval 的参与者进行比较。
我先下载了 SemEval 2017 Task 4 的全训数据。
总共有 11 个 txt 文件,跨度从 SemEval 2013 到 SemEval 2016。当试图将文件读入熊猫数据帧时,我发现两个文件不能作为 tsv 文件正确加载。似乎有一些条目没有正确地用制表符分隔,所以最终会有 10 条或更多的推文粘在一起。我本来可以尝试用提供的 tweet ID 来检索它们,但是我决定先忽略这两个文件,用 9 个 txt 文件组成一个训练集。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('fivethirtyeight')%matplotlib inline
%config InlineBackend.figure_format = 'retina'
一旦我导入了基本的依赖项,我将把数据读入熊猫数据框架。
import glob
path ='Subtask_A/'
all_files = glob.glob(path + "/twitter*.txt")
frame = pd.DataFrame()
list_ = []
for file_ in all_files:
df = pd.read_csv(file_,index_col=None, sep='\t', header=None, names=['id','sentiment','text','to_delete'])
list_.append(df.iloc[:,:-1])
df = pd.concat(list_)df = df.drop_duplicates()
df = df.reset_index(drop=True)
df.tail()
数据集看起来相当简单,有单独的 tweet ID、情感标签和 tweet 文本。
df.info()
总共有 41705 条推文。作为另一项健全性检查,让我们看看每条推文中有多少单词。
df['token_length'] = [len(x.split(" ")) for x in df.text]
max(df.token_length)
df.loc[df.token_length.idxmax(),'text']
好的,令牌长度看起来很好,最大令牌长度的 tweet 看起来像是一个正确解析的 tweet。让我们来看看数据的类别分布。
df.sentiment.value_counts()
数据不平衡,负类的数据条目最少,为 6,485 个,中性类的数据条目最多,为 19,466 个。我想重新平衡数据,这样我至少在训练时会有一个平衡的数据集。我将在定义清洗函数后处理这个问题。
数据清理
数据清理过程与我之前的项目类似,但这次我添加了一个很长的收缩列表,以将大多数收缩形式扩展为其原始形式如“不要”到“不要”。这一次,我使用 Spacy 而不是 Regex 来解析文档,并过滤数字、URL、标点符号等。以下是我清理推文的步骤。
- 解码:unicode 字符前的多余“\”的 unicode_escape,然后是 unidecode
- 撇号处理:人们用两个字符来表示缩写。“'”(撇号)和“'”(单引号)。如果这两个符号都用于收缩,将很难检测和正确映射正确的展开形式。所以任何“'”(撇号)都改成“'”(单引号)
- 收缩检查:检查是否有收缩形式,并将其替换为原始形式
- 解析:已完成空间解析
- 使用 Spacy 方法过滤标点、空格、数字、URL,同时保持 hashtag 的文本内容完整
- 移除@提及
- Lemmatize:使用 Spacy 方法对每个标记进行 lemma tize。引理 _ '。代词保持原样,因为 Spacy lemmatizer 将每个代词转换为“-PRON-”
- 特殊字符删除
- 单音节标记去除
- 拼写纠正:这是一个简单的拼写纠正,处理重复的字符,如“sooooo goooood”。如果同一个字符重复出现两次以上,它会将重复次数缩短为两次。例如,“sooooo goooood”将被转换为“soo good”。这不是一个完美的解决方案,因为即使在纠正之后,在“soo”的情况下,它也不是正确的拼写。但是通过将“sooo”、“sooo”、“sooooo”变成同一个单词“soo ”,至少有助于减少特征空间
好了,现在让我们看看这个自定义清理器是如何处理推文的。
pd.set_option('display.max_colwidth', -1)
df.text[:10]
[spacy_cleaner(t) for t in df.text[:10]]
看起来它正在做我想让它做的事情。我将清理“text”列,并创建一个名为“clean_text”的新列。
df['clean_text'] = [spacy_cleaner(t) for t in df.text]
通过运行清理功能,我可以看到它遇到了一些“无效的转义序列”。让我们看看这些是什么。
for i,t in enumerate(df.text):
if '\m' in t:
print(i,t)
包含“\m”的推文实际上包含一个表情符号“\m/”,我在谷歌上搜索后才知道这件事。显然, '\m/'代表你用手做的喇叭手势。这种手势在金属音乐中很流行。无论如何,这只是一个警告,而不是一个错误。让我们看看清洁工是如何处理这个问题的。
df.text[2064]
spacy_cleaner(df.text[2064])
这看起来又像是在做我想让它做的事情。到目前为止一切顺利。
不平衡学习
"在分类问题中,当某些类别的实例比其他类别多得多时,通常会出现类别不平衡问题。在这种情况下,标准分类器往往会被大类淹没,而忽略小类。
正如我已经意识到的,训练数据并不是完全平衡的,“中立”类的数据是“消极”类的 3 倍,“积极”类的数据是“消极”类的 2.4 倍。我将尝试用三种不同的数据拟合一个模型;过采样、下采样、原始,以了解不同的采样技术如何影响分类器的学习。
我将用来比较不同数据集性能的简单默认分类器是逻辑回归。从我以前的情感分析项目中,我了解到 Tf-Idf 和逻辑回归是一个非常强大的组合。在我应用任何其他更复杂的模型,如人工神经网络,美国有线电视新闻网,RNN 等,与逻辑回归的性能将有望给我一个好主意,我应该选择哪些数据采样方法。如果你想更多地了解 Tf-Idf,以及它如何从文本中提取特征,你可以查看我的旧帖子,“另一个使用 Python 的 Twitter 情绪分析-第 5 部分”。
在验证方面,我会使用 K 重交叉验证。在我之前的项目中,我把数据分成三份;训练、验证、测试和所有参数调整都是用保留的验证集完成的,最后将模型应用于测试集。考虑到我有超过一百万的数据用于训练,这种验证集方法是可以接受的。但是这一次,我拥有的数据要小得多(大约 40,000 条推文),通过从数据中省去验证集,我们可能会省去关于数据的有趣信息。
原始不平衡数据
from sklearn.pipeline import Pipelineoriginal_pipeline = Pipeline([
('vectorizer', tvec),
('classifier', lr)
])lr_cv(5, df.clean_text, df.sentiment, original_pipeline, 'macro')
对于没有任何重采样的数据,我们可以看到精度高于召回率。如果你想了解更多关于精确度和召回率的知识,你可以查看我的旧帖子,“T2,另一个使用 Python 的 Twitter 情绪分析——第四部分”。
如果我们仔细观察每一次折叠的结果,我们还可以看到,否定类别的召回率很低,大约为 2830%,而否定类别的准确率高达 6165%。这意味着分类器非常挑剔,不认为许多事情是负面的。它归类为负面的所有文本有 61~65%的时间确实是负面的。然而,它也错过了很多实际的负面类,因为它非常挑剔。我们的召回率很低,但是准确率很高。这种精确和回忆背后的直觉来自 Andreas Klintberg 的媒体博客。
过采样
有一个非常有用的 Python 包叫做“unbalanced-Learn”,它帮助你处理类不平衡问题,它与 Scikit Learn 兼容,并且易于实现。
在不平衡学习中,可以使用不同的技术进行过采样。我会用两个以下。
- RandomOverSampler
- 合成少数过采样技术
如果使用过采样数据进行交叉验证,还有一点需要考虑。如果在交叉验证之前过采样,过采样少数类会导致过拟合问题。为什么会这样呢?因为通过在交叉验证拆分之前进行过采样,您已经将验证数据的信息泄露给了您的训练集。就像他们说的“已经看到的,不能再看不见了。”
如果你想要更详细的解释,我推荐这个 Youtube 视频"机器学习——过- &欠采样——Python/Scikit/Scikit-imb learn"
幸运的是,我在上面定义为“lr_cv()”的交叉验证函数将只适合交叉验证拆分后的训练集拆分,因此它不会向模型泄露任何验证集的信息。
RandomOverSampler
随机过采样只是重复少数类的一些样本并平衡数据集中类之间的样本数量的过程。
from imblearn.pipeline import make_pipeline
from imblearn.over_sampling import ADASYN, SMOTE, RandomOverSamplerROS_pipeline = make_pipeline(tvec, RandomOverSampler(random_state=777),lr)
SMOTE_pipeline = make_pipeline(tvec, SMOTE(random_state=777),lr)
在我们安装每个管道之前,让我们看看 RadomOverSampler 是做什么的。为了更容易看到,我在下面定义了一些玩具文本数据,以及每个文本的目标情感值。
sent1 = "I love dogs"
sent2 = "I don't like dogs"
sent3 = "I adore cats"
sent4 = "I hate spiders"
sent5 = "I like dogs"
testing_text = pd.Series([sent1, sent2, sent3, sent4, sent5])
testing_target = pd.Series([1,0,1,0,1])
我的玩具数据一共 5 个条目,目标情绪是三正两负。为了平衡,这个玩具数据需要多一个负类的条目。
一件事是采样器将无法处理原始文本数据。它必须被转换到一个特征空间,过采样器才能工作。我将首先安装 tfidf 矢量器,并使用文本的 Tf-Idf 表示进行过采样。
tv = TfidfVectorizer(stop_words=None, max_features=100000)
testing_tfidf = tv.fit_transform(testing_text)
ros = RandomOverSampler(random_state=777)
X_ROS, y_ROS = ros.fit_sample(testing_tfidf, testing_target)
pd.DataFrame(testing_tfidf.todense(), columns=tv.get_feature_names())
pd.DataFrame(X_ROS.todense(), columns=tv.get_feature_names())
通过运行 RandomOverSampler,现在我们在末尾多了一个条目。RandomOverSampler 添加的最后一个条目与从顶部开始的第四个条目(索引号 3)完全相同。RandomOverSampler 只是重复少数类的一些条目来平衡数据。如果我们看看 RandomOverSampler 之后的目标情绪,我们可以看到它现在通过添加更多的负面类条目而在类之间达到了完美的平衡。
y_ROS
lr_cv(5, df.clean_text, df.sentiment, ROS_pipeline, 'macro')
与用原始不平衡数据建立的模型相比,现在的模型表现相反。负类的准确率在 4749%左右,但是召回率要高得多,在 6467%之间。现在我们面临着高召回率,低准确率的局面。这意味着分类器认为很多东西是负面的。然而,它也认为大量的非否定性文本是否定性的。所以从我们的数据集中,我们得到了许多被归类为否定的文本,它们中的许多在实际否定集中,然而,它们中的许多也是非否定的。
但是在没有重采样的情况下,负类的召回率低至 2830%,而通过重采样得到的负类的精确率在 4749%左右。
另一种方法是看 f1 分数,它是精确度和召回率的调和平均值。原始不平衡数据的准确率为 66.51%,F1 值为 60.01%。然而,采用过采样时,我们得到的精度略低,为 65.95%,但 F1 值却高得多,为 64.18%
合成少数过采样技术
SMOTE 是一种过采样方法,其中通过创建“合成”样本对少数类进行过采样,而不是通过替换进行过采样。
根据最初的研究论文“SMOTE:Synthetic Minority Over-sampling Technique”(Chawla et al .,2002),“合成样本以如下方式生成:取所考虑的特征向量(样本)与其最近邻之间的差。将该差乘以 0 和 1 之间的随机数,并将其添加到所考虑的特征向量中。这导致沿着两个特定特征之间的线段选择一个随机点。这种方法有效地迫使少数类的决策区域变得更普遍。”这意味着当 SMOTE 创建一个新的合成数据时,它将选择一个数据进行复制,并查看其 k 个最近的邻居。然后,在特征空间上,它将在原始样本和它的邻居之间的特征空间中创建随机值。
一旦你看到玩具数据的例子,它会变得更加清晰。
smt = SMOTE(random_state=777, k_neighbors=1)
X_SMOTE, y_SMOTE = smt.fit_sample(testing_tfidf, testing_target)
pd.DataFrame(X_SMOTE.todense(), columns=tv.get_feature_names())
最后一个条目是 SMOTE 创建的数据。为了更容易看出,我们只看负类。
pd.DataFrame(X_SMOTE.todense()[y_SMOTE == 0], columns=tv.get_feature_names())
上面的两个条目是原始数据,下面的一个是合成数据。你可以看到它不只是重复原始数据。相反,Tf-Idf 值是通过取前两个原始数据之间的随机值来创建的。如您所见,如果两个原始数据的 Tf-Idf 值都为 0,那么合成数据的这些特征也为 0,如“adore”、“cactus”、“cats”,因为如果两个值相同,则它们之间没有随机值。对于这个玩具数据,我特意将 k_neighbors 定义为 1,因为只有两个负类条目,如果 SMOTE 选择一个进行复制,那么就只剩下一个其他的负类条目作为邻居。
现在让我们来拟合 SMOTE 管道,看看它如何影响性能。
lr_cv(5, df.clean_text, df.sentiment, SMOTE_pipeline, 'macro')
与随机过采样相比,SMOTE 采样似乎具有略高的精度和 F1 值。根据目前的结果,似乎选择 SMOTE 过采样比原始或随机过采样更可取。
向下采样
下采样怎么样?如果我们在上述过采样中对少数类进行过采样,利用下采样,我们试图减少多数类的数据,从而使数据类平衡。
from imblearn.under_sampling import NearMiss, RandomUnderSamplerRUS_pipeline = make_pipeline(tvec, RandomUnderSampler(random_state=777),lr)
NM1_pipeline = make_pipeline(tvec, NearMiss(ratio='not minority',random_state=777, version = 1),lr)
NM2_pipeline = make_pipeline(tvec, NearMiss(ratio='not minority',random_state=777, version = 2),lr)
NM3_pipeline = make_pipeline(tvec, NearMiss(ratio=nm3_dict,random_state=777, version = 3, n_neighbors_ver3=4),lr)
随机欠采样器
同样,在我们运行管道之前,让我们将它应用于玩具数据,看看它能做什么。
rus = RandomUnderSampler(random_state=777)
X_RUS, y_RUS = rus.fit_sample(testing_tfidf, testing_target)
pd.DataFrame(X_RUS.todense(), columns=tv.get_feature_names())
pd.DataFrame(testing_tfidf.todense(), columns=tv.get_feature_names())
与原始不平衡数据相比,我们可以看到下采样数据少了一个条目,这是原始数据中属于正类的最后一个条目。RandomUnderSampler 通过从多数类中随机移除数据来减少多数类。
lr_cv(5, df.clean_text, df.sentiment, RUS_pipeline, 'macro')
现在准确性和 F1 的分数已经明显下降。但低精度和高召回率的特点与过采样数据相同。只是整体表现下降了。
差点错过
根据“不平衡学习”的文档,“ NearMiss 增加了一些启发式规则来选择样本。NearMiss 实现了 3 种不同类型的启发式算法,可通过参数 version 进行选择。NearMiss 启发式规则基于最近邻算法。
还有一篇关于重采样技术的好论文。“用于改善不平衡数据集分类性能的重采样技术调查”(Ajinkya More,2016 年)
我借用了莫尔论文中对 NearMiss 三个不同版本的解释。
近距离-1
在 NearMiss-1 中,来自多数类的那些点到少数类中 k 个最近点的平均距离最低的点被保留。这意味着它将保持与少数阶级相似的多数阶级的观点。
nm = NearMiss(ratio='not minority',random_state=777, version=1, n_neighbors=1)
X_nm, y_nm = nm.fit_sample(testing_tfidf, testing_target)
pd.DataFrame(X_nm.todense(), columns=tv.get_feature_names())
pd.DataFrame(testing_tfidf.todense(), columns=tv.get_feature_names())
我们可以看到,NearMiss-1 已经删除了文本“I adore cats”的条目,这是有意义的,因为单词“adore”和“cats”都只出现在该条目中,因此使其在特征空间中的 Tf-Idf 表示方面与少数民族类最不同。
lr_cv(5, df.clean_text, df.sentiment, NM1_pipeline, 'macro')
看起来准确性和 F1 分数都比随机欠采样差。
近地小行星-2
与 NearMiss-1 相反,NearMiss-2 保留了多数类中那些到少数类中 k 个最远点的平均距离最低的点。换句话说,它会保留多数阶级与少数阶级最大的不同点。
nm = NearMiss(ratio='not minority',random_state=777, version=2, n_neighbors=1)
X_nm, y_nm = nm.fit_sample(testing_tfidf, testing_target)
pd.DataFrame(X_nm.todense(), columns=tv.get_feature_names())
pd.DataFrame(testing_tfidf.todense(), columns=tv.get_feature_names())
现在我们可以看到,NearMiss-2 删除了文本“我喜欢狗”的条目,这也是有意义的,因为我们也有一个负面条目“我不喜欢狗”。两个条目在不同的类中,但是它们共享两个相同的标记“like”和“dogs”。
lr_cv(5, df.clean_text, df.sentiment, NM2_pipeline, 'macro')
与 NearMiss-1 相比,准确性和 F1 得分甚至更低。我们还可以看到,所有指标在不同的筹码之间波动很大。
NearMiss-3
最后的 NearMiss 变体 NearMiss-3 为少数类中的每个点选择多数类中的 k 个最近邻。在这种情况下,欠采样比率直接由 k 控制。例如,如果我们将 k 设置为 4,则 NearMiss-3 将选择每个少数类条目的 4 个最近邻居。
然后,我们将根据我们设置的 n 个邻居,得到比少数类更多或更少的多数类样本。例如,对于我的数据集,如果我在默认 n_neighbors_ver3 为 3 的情况下运行 NearMiss-3,它将会抱怨,并且中性类(在我的数据集中是多数类)的数量将小于负类(在我的数据集中是少数类)。因此,我显式地将 n_neighbors_ver3 设置为 4,这样我将拥有足够多的多数类数据,至少与少数类的数量相同。
有一点我不能完全确定,就是当用 n_neighbors_ver3 参数选择的所有数据都多于少数类时,它应用什么样的过滤。正如您将在下面看到的,在应用 NearMiss-3 之后,数据集达到了完美的平衡。然而,如果算法只是根据 n_neighbors_ver3 参数选择最近的邻居,我怀疑它最终会为每个类提供完全相同的条目数。
lr_cv(5, df.clean_text, df.sentiment, NM3_pipeline, 'macro')
NearMiss-3 产生了 NearMiss 家族中最稳健的结果,但略低于 RandomUnderSampling。
from collections import Counternm3 = NearMiss(ratio='not minority',random_state=777, version=3, n_neighbors_ver3=4)
tvec = TfidfVectorizer(stop_words=None, max_features=100000, ngram_range=(1, 3))
df_tfidf = tvec.fit_transform(df.clean_text)
X_res, y_res = nm3.fit_sample(df_tfidf, df.sentiment)
print('Distribution before NearMiss-3: {}'.format(Counter(df.sentiment)))
print('Distribution after NearMiss-3: {}'.format(Counter(y_res)))
结果
五重交叉验证结果 (用于验证的分类器:默认设置的逻辑回归)
基于上述结果,我将在下一篇文章中使用的采样技术将被 SMOTE。在下一篇文章中,我将使用 SMOTE 过采样数据尝试不同的分类器。
感谢您的阅读,您可以通过以下链接找到 Jupyter 笔记本:
[## tthustlea/yeth _ another _ tiw tter _ 情操 _ 分析 _part1
通过在 GitHub 上创建一个帐户,为另一个 _ tiwtter _ 情操 _ 分析 _part1 开发做出贡献。
github.com](github.com/tthustla/ye…)
YOLO 迷上了绵羊:统一目标探测中的环境背景
我最近将约瑟夫·雷德蒙(Joseph Redmond)的 YOLO 算法用于 MATLAB(目前为止没有非最大值抑制),并花了一个小时在一系列图像上测试它。总的来说,这种算法非常有效:
然而,人们很快就会意识到 YOLO 对羊有一点痴迷。请注意下面两张图片中牧羊人和狗的标注错误:
Sheep, Sheep, Sheep….
Sheep, sheep, and some more sheep…
那只看门狗看起来需要度个假。在某个地方,她会觉得自己像一只狗,而不仅仅是羊群中的一只羊:
Impressive Photoshop skills, I know.
那更好。农夫和他的牧羊犬呢?去月球旅行怎么样?
A shepherd and his sneaky looking cow on the old Apollo studio lot in Hollywood (#moonlandingfaked)
公平地说,牧羊犬看起来确实像狡猾的奶牛。
似乎这个统一的对象检测器已经学会在对象环境的上下文中做出它的决定。与其他 CNN 对象检测算法不同,整个图像,包括周围的视觉背景,是通过网络一次馈入的。我喜欢把 CNN 想象成学习一系列越来越复杂的视觉特征来对一个物体进行分类。然而,我认为 YOLO 已经学会了一种便捷的逻辑捷径来解决检测绵羊的问题——绵羊通常是成群出现的。所以,靠近羊的物体更有可能是羊。
让我们测试一下,YOLO 所反应的周围视觉环境是否不是羊群,而是一个相关的视觉线索,比如周围的风景。这是我们的牧羊人和他的物种困惑的牧羊犬在一个领域。不是任何一块田地,而是澳大利亚的一块看起来非常像你可能会发现绵羊的那种贫瘠的地方的田地:
有意思。一个没有羊群的牧羊人仍然是一个人——即使是在田野里(一只牧羊犬仍然是一只偷偷摸摸的牛)。
YOLO 检测算法的这种行为让我想起了最近我听到的一个关于人工智能未来潜在危险的争论。由于没有足够详细地说明学习算法如何找到解决方案,或者没有对算法的解决方案空间进行足够的限制,我们最终可能会得到我们不喜欢的复杂重要问题的解决方案。最近听到的一个例子(可能来自 AI 扫兴者埃隆马斯克?)是一种算法可能“决定”让世界摆脱癌症的最简单方法是让世界摆脱所有动物。
当然,这个意外的物体识别捷径的例子远没有那么可怕。当然,除非该算法正被用于自动分类牲畜,以便在畜牧场屠宰…
还有人注意到 YOLO 或其他统一对象检测算法中的类似错误吗?