使用 Keras 简化影像分类的单一功能
我们一步一步地展示了如何构建一个单一的、通用的效用函数,从目录中自动提取图像,并训练一个卷积神经网络模型。
介绍
已经有很多关于深度学习框架的文章,如 Keras 和 PyTorch ,以及如何强大而简单地使用来构建和玩精彩的深度学习模型。
已经有很多关于模型架构和优化器的教程/文章——卷积的概念、最大池、优化器,如 ADAM 或 RMSprop 。
如果您想要的只是一个函数,从磁盘上的指定目录中自动提取图像,并返回给您一个完全训练好的神经网络模型,准备用于预测,会怎么样?
因此,在本文中,我们将重点讨论如何使用 Keras (TensorFlow) API 中的一些实用方法,通过适当的数据预处理来简化此类模型的训练(专门用于分类任务)。
基本上,我们想,
- 获取一些数据
- 将它们放在按类别排列的目录/文件夹中
- 用最少代码/fuss 训练神经网络模型
最后,我们的目标是编写一个单独的实用函数,它可以获取存储训练图像的文件夹的名称,并返回一个完全训练好的 CNN 模型。
数据集
在这个演示中,我们使用了一个由 4000 多幅花的图像组成的数据集。数据集可以从 Kaggle 网站下载。
数据收集基于 Flickr、谷歌图片、Yandex 图片等数据。这些图片被分为五类,
- 黛西,
- 郁金香,
- 罗斯,
- 向日葵,
- 蒲公英。
每个班级大约有 800 张照片。照片分辨率不高,320 x 240 像素左右。照片不是缩小到单一尺寸,它们有不同的比例。
然而,它们被整齐地组织在五个目录中,并以相应的类标签命名。我们可以利用这种组织并应用 Keras 方法来简化卷积网络的训练。
代码回购
完整的 Jupyter 笔记本在我的 Github repo 这里是 。随意分叉延伸,喜欢就给它一颗星。
我们将在本文中使用一些代码来展示重要的部分。
该不该用 GPU?
建议在 GPU 上运行该脚本(使用TensorFlow-GPU
),因为我们将构建一个具有五个卷积层的 CNN,因此,如果您不使用某种 GPU,使用数千幅图像的训练过程可能会计算量大且速度慢。
对于 Flowers 数据集,在我配有英伟达 GTX 1060 Ti GPU (6 GB 视频内存)、Core i-7 8770 CPU 和 16 GB DDR4 内存的普通笔记本电脑上,单个纪元需要大约 1 分钟。
或者,你可以利用 Google Colab ,但是加载和预处理数据集可能有点麻烦。
数据预处理
内务处理和显示图像
请注意,笔记本代码的数据预处理部分的第一部分对于神经网络的训练并不重要。这组代码只是为了举例说明,并显示一些训练图像作为示例。
在我的笔记本电脑上,数据存储在比我的笔记本文件夹高一级的文件夹中。这是这个组织,
使用一些基本的 Python 代码,我们可以遍历子目录,对图像进行计数,并展示它们的示例。
一些雏菊的照片,
还有一些美丽的玫瑰,
请注意,图片的大小和长宽比各不相同。
构建ImageDataGenerator
对象
这是真正的奇迹发生的地方。
ImageDataGenerator
类的官方描述称“通过实时数据增强生成批量张量图像数据。数据将(分批)循环。
基本上,它可以用于通过大量内置预处理(如缩放、移位、旋转、噪声、白化等)来增强图像数据。现在,我们只是使用rescale
属性在 0 和 1 之间缩放图像张量值。
这里有一篇关于这方面的有用文章。
结合 Keras 的 ImageDataGenerator 实现我们的自定义生成器的博客,以执行各种…
medium.com](https://medium.com/@arindambaidya168/https-medium-com-arindambaidya168-using-keras-imagedatagenerator-b94a87cdefad)
但是这个类在当前演示中的真正用途是超级有用的方法flow_from_directory
,它可以从指定的目录中一个接一个地提取图像文件。
注意,这个目录必须是顶层目录,在这里各个类的所有子目录都可以单独存储。flow_from_directory
方法自动扫描所有子目录,并获取图像及其相应的标签。
我们可以指定类名(就像我们在这里用classes
参数做的那样),但这是可选的。然而,我们稍后会看到,这对于从大量数据中进行选择性训练是如何有用的。
另一个有用的参数是target_size
,它让我们将源图像的大小调整到统一的 200 x 200,不管图像的原始大小是多少。这是一些很酷的图像处理,带有一个简单的函数参数。
我们还指定了批量大小。如果不指定batch_size
,默认情况下,它将被设置为 32。
我们选择class_mode
作为categorical
,因为我们在这里做多类分类。
运行这段代码时,Keras 函数扫描顶层目录,找到所有图像文件,并自动用适当的类(基于它们所在的子目录)标记它们。
是不是很酷?
但是等等,还有更多。这是一个 Python 生成器对象 ,这意味着它将用于在训练过程中一个接一个地 生成数据。这大大减少了处理非常大的数据集的问题,因为数据集的内容不能一次放入内存。看看这篇文章可以更好地理解它,
生成器表达式是 Python 中一个有趣的特性,它允许我们创建延迟生成的可迭代对象…
towardsdatascience.com](/pythons-list-generators-what-when-how-and-why-2a560abd3879)
建立 conv 网络模型
正如所承诺的,我们不会花时间或精力去分析 CNN 模型背后的代码。简而言之,它由 5 个卷积层/最大池层和 128 个神经元组成,最后是 5 个神经元输出层,具有用于多类分类的 softmax 激活。
我们使用 RMSprop,初始学习率为 0.001。
这里又是代码。请随意试验网络架构和优化器。
使用’ fit_generator’ 方法进行训练
我们之前讨论过train_generator
对象用flow_from_directory
方法和它的参数做了什么很酷的事情。
现在,我们在上面定义的 CNN 模型的fit_generator
方法中使用这个对象。
注意fit_generator
的steps_per_epoch
参数。由于train_generator
是一个通用的 Python 生成器,它从不停止,因此fit_generator
不知道一个特定的时期在哪里结束,下一个时期在哪里开始。我们必须让它知道一个时期内的步骤。在大多数情况下,这是总训练样本的长度除以批量大小。
在上一节中,我们发现总样本量为total_sample
。因此,在这种特殊情况下,steps_per_epoch
被设置为int(total_sample/batch_size)
,即34
。因此,您将在下面的训练日志中看到每个时期 34 步。
部分培训日志…
我们可以用通常的绘图代码来检查准确性/损失。
好的。到目前为止,我们完成了什么?
我们已经能够利用 Keras ImageDataGenerator
和fit_generator
方法从单个目录中自动提取图像,给它们加标签,调整它们的大小和比例,并一个接一个地(成批地)流动它们来训练神经网络。
我们能把所有这些都封装在一个函数中吗?
将所有这些封装在一个函数中?
制作有用的软件/计算系统的中心目标之一是 抽象 ,即隐藏内部计算和数据操作的血淋淋的细节,并向用户呈现简单直观的工作界面/API。
作为实现这一目标的一种实践,我们可以尝试将上述过程封装在一个函数中。想法是这样的,
目标是用有用的参数实现灵活的 API
当你在设计一个高级 API 时,为什么不去做比这个特定的 flowers 数据集演示所需要的更一般化的东西呢?考虑到这一点,我们可以考虑为这个函数提供额外的参数,使它适用于其他图像分类情况(我们很快就会看到一个例子)。
具体来说,我们在函数中提供了以下参数,
train_directory
:训练图像存储在单独文件夹中的目录。这些文件夹应该按照类来命名。target_size
:训练图像的目标尺寸。一个元组例如(200,200)classes
:一个 Python 列表,包含我们希望进行训练的类。这迫使生成器从train_directory
中选择特定的文件,而不是查看所有的数据。batch_size
:培训批量num_epochs
:训练的次数num_classes
:要考虑的输出类的数量verbose
:训练的详细程度,传递给fit_generator
方法
当然,我们可以提供与整个模型架构或优化器设置相对应的附加参数。本文并不关注这些问题,因此,我们保持它的简洁。
同样,完整的代码在 Github repo 中。下面,我们只展示了 docstring 部分,以强调使它成为一个灵活的 API,
测试我们的效用函数
现在,我们通过简单地提供一个文件夹/目录名来测试我们的train_CNN
函数,并获得一个可用于预测的训练好的模型!
让我们还假设我们现在只想为“雏菊”、“玫瑰”和“郁金香”训练,而忽略其他两朵花的数据。我们简单地将一个列表传递给classes
参数。在这种情况下,不要忘记将num_classes
参数设置为 3。您会注意到,当训练样本的数量少于上述情况时,每个时期的步数会自动减少到 20。
另外,请注意,在上面的函数中,verbose
默认设置为 0,因此,如果您想要按时段监控训练进度,您需要明确指定verbose=1
!
基本上,我们现在能够用 2 行代码得到一个完全训练好的 CNN 模型!
该函数对另一个数据集有用吗?
这是对这种功能效用的严峻考验。
我们能不能不做太多修改就把它应用到另一个数据集?
加州理工学院-101
Caltech-101 是一个丰富且易于管理的影像分类数据集。我说的可管理的是指,没有 ImageNet 数据库那么大,它需要大规模的硬件基础设施来训练,因此超出了在笔记本电脑上快速测试酷想法的范围,但足够多样,可以练习和学习卷积神经网络的技巧和交易。
加州理工学院-101 是属于 101 个类别的不同类型的对象的图像数据集。每个类别大约有 40 到 800 张图片。大多数类别大约有 50 张图片。每个图像的大小大约为 300 x 200 像素。
这个数据集是 2003 年加州理工学院的费·李非教授和她的同事(马尔科·安德烈托和马克·奥雷利奥·兰扎托)建立的,当时她还是那里的一名研究生。因此,我们可以推测,加州理工学院-101 是她研究 ImageNet 的直接先驱。
用两行代码训练 Caltech-101
我们下载了数据集,并将内容解压缩到与之前相同的数据文件夹中。该目录如下所示,
因此,我们得到了我们想要的东西——一个顶级目录,其中包含包含训练图像的子目录。
然后,和之前一样的两行,
我们所做的就是将该目录的地址传递给函数,并选择我们想要为训练模型的图像类别。假设我们要训练模型在 【杯子】 和 【螃蟹】 之间进行分类。我们可以像以前一样将他们的名字作为列表传递给classes
参数。
此外,请注意,我们可能必须显著减少该数据集的batch_size
,因为与 Flowers 数据集相比,训练图像的总数将会低得多,并且如果batch_size
高于总样本,那么我们将使steps_per_epoch
等于 0,这将在训练期间产生错误。
瞧啊。该函数找到相关图像(总共 130 个)并训练模型,每批 4 个,即每个时期 33 步。
测试我们的模型
因此,我们看到了将训练图像的目录地址传递给函数并使用我们选择的类训练 CNN 模型是多么容易。
**模型好吗?**用网上下载的随机图片测试一下就知道了。
请记住,加州理工学院-101 数据集是由费李非和他的同事早在 2003 年创建的。因此,互联网上任何较新的图像都不太可能出现在数据集中。
我们随机下载了以下“螃蟹”和“杯子”的图片。
在一些基本的图像处理(调整大小和尺寸扩展以匹配模型)之后,我们得到了下面的结果,
model_caltech101.predict(img_crab)>> array([[1., 0.]], dtype=float32)
该模型正确预测了螃蟹测试图像的类别。
model_caltech101.predict(img_cup)>> array([[0., 1.]], dtype=float32)
该模型正确地预测了杯子测试图像的类别。
但是这个呢?
model_caltech101.predict(img_crab_cup)>> array([[0., 1.]], dtype=float32)
因此,该模型将测试图像预测为一个杯子。几乎是公平的,不是吗?
验证集和其他扩展
到目前为止,在fit_generator
中我们只有一个train_generator
对象用于训练。但是验证集呢?它遵循与train_generator
完全相同的概念。您可以从您的训练图像中随机分割一个验证集,并将它们放在一个单独的目录中(与训练目录相同的子目录结构),并且您应该能够将它传递给fit_generator
函数。
甚至还有一个用于ImageDataGenerator
类的flow_from_dataframe
方法,在这里您可以传递包含在熊猫数据帧中的图像文件的名称,然后训练可以继续进行。
请随意试验这些扩展。
摘要
在本文中,我们回顾了 Keras 的几个实用方法,它们可以帮助我们构建一个紧凑的实用函数,以便为图像分类任务有效地训练 CNN 模型。如果我们可以在一个公共目录下的子目录中组织训练图像,那么这个函数可能允许我们只使用几行代码来训练模型。
这很有意义,因为使用这些内置的类/方法和我们的实用函数,我们可以将代码/数据流完全保留在 Keras 中,并以紧凑的方式训练 CNN 模型,而不是使用其他库(如 PIL 或 Scikit-image)单独抓取和预处理图像。
如果你有任何问题或想法要分享,请联系作者tirthajyoti【AT】Gmail . com。另外,你可以查看作者的 GitHub 资源库中其他有趣的 Python、R 和机器学习资源中的代码片段。如果你像我一样对机器学习/数据科学充满热情,请随时在 LinkedIn 上添加我或在 Twitter 上关注我。
[## Tirthajyoti Sarkar - Sr .首席工程师-半导体、人工智能、机器学习- ON…
通过写作使数据科学/ML 概念易于理解:https://medium.com/@tirthajyoti 开源和有趣…
www.linkedin.com](https://www.linkedin.com/in/tirthajyoti-sarkar-2127aa7/)
我的数据科学转型之旅中的一个亮点
从童年开始,我就被视为铺设了一条有远见的道路,这条道路可以被兄弟姐妹追随,并得到长辈的赞赏。我的故事不是很英雄或者激励人心。只有我和“我的简单故事”。
在初中和高中时期,我是一个聪明勤奋的孩子。后来,我甚至准备了所有的入学考试,任何科学/数学专业的学生都会准备的。是的,我说的是 IIT-JEE!我对自己的目标很高(现在也是),但当时事情并没有很好地解决。我进入了一所颇有名气的政府工程学院。像其他学生一样,我不确定自己未来想做什么,所以工程是我的“首选”领域,也是一个安全的选择。它让我探索不同的领域。
但还是那句话,你必须有始有终。我对自己有不同的计划,但我必须为自己找到一个位置。这让我选择了 Python 语言 ,也让我从整体上更接近数据科学的概念。我脑子里有许多问题。我会比同龄人挣得少吗?我会有一个薪水不断上涨的快速职业生涯吗?还有什么不可以!但是,数据科学成了我的救星。就像一个真正的救世主,它帮助我走出混乱。
我选择 数据科学 的 原因不是出于直觉,而是因为数据的大规模指数增长。数据是推动行业发展的燃料。
“宁为玉碎,不为瓦全。”
我参加了 2-3 个月的线下培训,培训内容是 Python 和数据科学。我在技术和非技术方面都学习过,但是我更喜欢非技术方面。它包括商业意识、沟通技巧和解决问题的策略。
渐渐地,Python 成为我在技术部分生存的力量【即数据预处理和数据分析】。我觉得数据科学比我所接触到的要多。我继续与我的同事和前辈讨论如何在这个庞大的领域进一步提高。然后,我决定通过线上培训开始学习 大数据 和 Hadoop 。我甚至有机会参加现场视频会议,并报道了各种项目来实践这一点。
**抓住它需要时间。数学或基本上统计部分根本不是问题,但编程确实给我带来了一些缺点。为此,我开始使用各种在线代码练习网站,这些网站确实增加了我之前所学的内容。**这些在不同平台和项目上的严谨实践完善了我的简历!**我开始申请一些实习机会,为我一直在学习的数字增值。
最初,反响不太好,更确切地说,应该说没有任何反应。我学会了如何保持动力,激励我实现目标。我用一些“**技术文献”来充实我的知识,例如——Python 速成班——作者 Eric Matthes,Peter Bruce 的《数据科学家实用统计学》,R-作者 Garrett Gorlemund 的《动手编程》,R . for Data Science and Learning SQL——作者 Alan Beaulieu。
虽然我不能全部完成,但它们确实为我之前所学的知识增加了一些实用性,并向我介绍了新技术,如和 SQL 。
由于 在线课程 ,我对 Hadoop 和大数据很满意,也掌握得很好,所以我没有参考任何书籍。
但是,如果在学习过程中,你认为你需要关于这些技术的任何指导,你可以随时查阅《Hadoop—权威指南》和《实践中的大数据 Barnard Marr》**
后来,我用一些新项目更新了我的简历,这些项目涵盖了我所学到的最新技术。很快,我开始接到实习的电话。我参加了其中的一个“暑期培训/暑期实习”。这 75 天揭示了数据科学的本质以及当时获得的信息背后的现实意义。然后,我加入了大学的就业机会。
我所期望掌握的知识和我之前学习的课程直接刺激了我作为初级数据科学家的起步。这里的印象是,它通常不提供给新生。但是,我的项目工作和培训在我的职业生涯中起到了至关重要的作用。我遵循了我在训练期间学到的所有步骤,并在这里练习了几次。所有这些都让我在整个项目分配过程中更有效率。
我对使用哪种方法、应用哪种工具有了自己的想法和主意。学会区分什么是重要的,什么是不重要的。所有这些知识帮助我成为一名更有效的数据科学家。我认识到,在少数项目中取得成功或实现一个目标并不意味着你有权给自己贴上“有效”的标签。高效是一个持续的过程,它让你更谦虚地学习,并提高你的生产力。所有这些让我接触到了新项目,并帮助我每天都学到一些新东西。
我很早就意识到这一点,没有免费的午餐,如果你想在生活中得到什么,你必须全心全意地付出。要获得真实世界的经验,你需要:
a)找到你感兴趣的数据集,b)询问并尝试回答相关问题,c)记录结果,d)冲洗并重复以积累经验。
要称自己为真正的数据科学家,并有一个操纵它的“长期计划”,你必须铺平道路并创造你自己的身份【那种快乐的感觉是无法形容的:】。
简而言之,我们开始工作吧。
如何建立一个只有两栏的社交网络
好吧,如果你很挑剔的话,也许 3 张,如果你想让它真正有用的话,也许多几张桌子…
…但我的观点仍然成立。社交网络的本质可以很容易地存储在一个有两列的表中。
这篇文章的灵感来自于描述社交网络的复杂方式,尤其是在图表中,它让我思考如何简化它的想法,以便任何人都可以理解它。
让我们从概述什么是社交网络开始
简单来说,它是一个描述社会关系和互动的网络。他们在互联网出现之前就存在了。自从人类存在以来,事实上自从任何社会生物存在以来,城市、城镇、村庄和人们都有他们自己的小社会网络。
然而,一旦互联网允许社交网络被记录、存储和扩展,这个术语就爆炸了。
如今,你的社交网络可以不仅仅包括你认识的人,还包括你经常交往的人。它可以包括你从未谋面的人,或者仅仅通过网上交流认识的人。
想想就有点疯狂。
但是这些都不是新的。我们都很清楚这一点,但这些在线社交网络实际上在做什么呢?
Photo by Dương Hữu on Unsplash
它们存储了一个人(或者实体,如果你真的很迂腐的话)和另一个人之间的联系。
就是这样。只是两个人之间简单的联系。很多很多很多次。
这种规模就是为什么我认为我们把它们描绘成复杂的东西,但是如果你回到核心原则:存储两个人之间的联系,现在看起来并不太糟糕,对吗?
但是你说是两栏的表格,请解释一下…
…嗯,如果一个社交网络只是两个人之间的一个巨大的链接。那么你需要一种方法来存储两个人之间的链接。一种方法是创建一个表,存储代表每个人的两个用户标识符。
CREATE TABLE friend
(
user_id VARCHAR(64),
friend_user_id VARCHAR(64)
);
搞定了。
嗯,不完全是,但是你明白了。这个表现在可以很容易地存储两个用户之间的关系(我们称之为朋友)。
如果您想知道存储关系的顺序。如果是我设计的,我会把发起好友请求的人放在第一列,把他们请求的人放在第二列。
图遍历找朋友的朋友怎么样?
现在我们在谈话。现在我们来看看那些超级复杂的社交网络图片,它们让你大吃一惊。
A super complex social network: Image Source
让我们从简单的开始。
对于一个用户来说,找到他们的朋友,然后找到他们所有的朋友,这些朋友还不是最初用户的朋友。
所有的社交网络都是这样开始向你展示“推荐的朋友”或“你可能认识的人”。逻辑是,如果你认识一个人,你可能也认识同样的人。
SELECT user.user_id, friends.friend_user_id
FROM friend user
LEFT JOIN friend friends ON user.friend_user_id = friends.user_id
LEFT JOIN friend same_friends ON same_friends.user_id = friends.friend_user_id
WHERE a.user_id = 1 AND c.user_id IS NULL;
同样不太难。虽然我不想假装,当你想认识朋友的朋友的朋友等等的时候,它不会变得有点笨拙。
有趣的是,脸书遇到了同样的问题,并决定走图形数据库这条路。图形数据库旨在帮助解决这类问题,因为它们在构建时(显然)考虑了图形遍历。这使得询问更复杂的网络问题变得更加琐碎。
那么一个社交网络真的只是一个有两列的表格吗?
是也不是…
正如您所看到的,用一个表和两列来存储用户之间的关系是可能的。你甚至可以查询这些数据,并使用它们来查找推荐的朋友,以帮助用户建立他们的网络。
但实际上,你会希望它周围有很多额外的数据,以使它在现实世界中更有用。
首先,您将需要表来存储关于用户及其配置文件的数据。
你可能还想知道好友请求的概念,这样你就可以区分请求和真正的友谊。
您可能希望存储关于好友请求被发出和接受的事件的元数据。
然后扩展到构成社交网络的所有其他东西,包括帖子和赞——同样,赞只是用户和另一个实体之间的关系,更可能是用户和帖子之间的关系。
希望这种对社交网络世界的简化看法引发了一些思考,即简单的想法如何能很快变成一些最大和最强大的工具。
罪恶之歌:通过《权力的游戏》刻画总统候选人
作者:韦林多·曼格罗邦和米娅·伊瑟曼
Image by author
这个夏天,很多人对《权力的游戏》表达了强烈的意见——龙,浪漫,当然还有谁应该统治七大王国。事实上,你可能已经听过很多现实世界中的政治理由来解释这个故事中的事件——这个故事的背景是一个有龙和魔法存在的世界。粉丝们喜欢分析节目的政治,他们从第一季就开始分析了。
现实政治呢?希望每个对《权力的游戏》有强烈意见的人都同样关注即将于 2020 年举行的非虚构的美国总统选举。以防你对临冬城之战比对民主党辩论日程更感兴趣,我们用科学的方法整理了一份《权力的游戏》人物提名名单!
伯尼·桑德斯?更像伯尼·珊莎!詹德利——来自南方的好男孩,有一个令人困惑的同名者——那就是贝托!谁会在夜王再次召集他的僵尸大军之前最终击败他呢?艾莉亚·史塔克,又名伊丽莎白·沃伦!以下是目前民调超过 2%的总统候选人的完整名单以及他们对应的《权力的游戏》角色:拜登&乔恩、桑德斯&桑莎、沃伦&艾莉亚、Buttigieg &达沃斯、哈里斯&托尔蒙德、奥鲁克&詹德利、布克&吉利、克洛布查尔&乔拉。
如果到目前为止这感觉有点刺激,你没有错。本文的其余部分详细记录了创建我们的列表的过程。请继续阅读这些配对背后的科学,并随时查看我们的 Github 库。
获取和准备数据
我们使用 Reddit 注释和自然语言处理来创建映射。通过 Reddit API,以及来自这篇文章的一点帮助,我们将来自政治和权力的游戏子编辑的超过 30 万条评论保存到亚马逊网络服务关系数据库服务。
一旦我们有了一个很长的评论列表,我们需要将这些评论归属于特定的人。(出于我们的目的,“人物”既指虚构的人物,也指非虚构的被提名者。)为了做到这一点,我们创建了一个函数来检查评论数据帧中的每一行,将每条评论与一个人及其假名的字典进行比较,并记录该名字是否出现在评论中以给予该人信任。这被证明是非常耗时的,所以我们找到了一个更好的方法:矩阵!
使用 sklearn 的计数矢量器,我们将 324629 条评论和 114 个假名变成了一个矩阵。我们还为 114 个假名(例如卡丽熙和丹妮是同一个人)和 67 个人创建了一个 114 乘 67 的矩阵。然后,我们对这两个矩阵进行点积,得到每个人在评论行中的评论数:
An example of the dot product’s resulting matrix (Image by the author)
以情感和音量为特征的聚类
因为我们最感兴趣的是对每个角色进行分析,所以我们创建了一个矩阵,将人物作为第一列,将他们的特征作为其他列。我们使用维德来分析每个评论的情绪,并使用正面分数作为第一个特征,然后负面分数作为另一个特征。我们还使用 Reddit 的“投票率”(投票数除以投票数)、评论数和评论长度作为特征。sub_num_comments 列最终也用于根据所有的评论来查找特性的平均值。
Image by the author
如果我们使用无监督的 kmeans 聚类来查看不同的组是什么,我们会发现什么?最佳 k (3)并不比被提名者和其他被提名者组合在一起多多少,对角色也是一样。有趣的是,我们确实注意到,对人物的情感通常比被提名者更积极地被解读。
Image by the author
添加语义特征
在寻找更有吸引力的集群时,我们想要不同于用户情绪和数量的特性。如果我们看看角色的名字是如何相互关联的呢?为此,我们使用了 Gensim ,这是一个允许您“分析纯文本文档的语义结构”和“检索语义相似的文档”的工具我们就是这么做的!
我们使用所有的评论作为训练 word2vec 模型的语料库,该模型将单词转化为向量。然后,我们使用 Gensim 的最相似特征(利用余弦相似度)将这些人与“总统”、“宝座”和“领袖”进行比较。当我们使用这些特性重新聚类( k =6)时,我们得到了稍微有趣一些的结果,但是它仍然没有给我们两个不同领域中的自然重叠。
Image by the author
使用相似性得分进行匹配
很明显,我们需要变得更笨手笨脚,以实现我们的点击诱饵目标,将《权力的游戏》中的人物与总统候选人匹配起来。所以,我们把情感和数量抛到了九霄云外,只使用*最相似的相似度分数。*为了简化我们的分析,我们决定只关注前 8 名被提名者,即当时民调支持率超过 2%的人:拜登、桑德斯、沃伦、Buttigieg、哈里斯、奥罗克、布克和克洛布查尔。
Hodor — not a politician! (Image by the author)
为了创建我们的最终排名,我们按照投票顺序查看了被提名者,并将他们与最匹配的角色配对。拜登&乔恩,桑德斯&桑莎,沃伦&艾莉亚,布蒂吉格&达沃斯,哈里斯&托尔蒙德,奥鲁克&詹德利,布克&吉利,克洛布查尔&乔拉。
你有它!你怎么想呢?你会做些不同的事情吗?请在评论中给我们留言。
此外,不要忘记投票,否则你不会比《权力的游戏》更好。
使用网络摄像头扫描条形码的独立应用程序
在购物商店开发经济高效的自动化计费流程的一步
什么是条形码阅读器
当你逛任何一家购物中心或商店时,你一定见过条形码检测机(见图 1,图片来源 flickr ),它能读取你购买的商品的条形码并计算出价格。最后,你会得到一张购物收据,上面有你所购买的物品以及每件物品的价格。在购物中心使用条形码扫描仪在很大程度上减少了文书工作和数字化购物。然而,它仍然需要人的努力。
Figure 1: A typical bar code scanner
另一个问题是,它的成本很高。变化和耐久性也是这种条形码扫描仪的一个问题。因此,有必要开发这样一种系统,它能使扫描产品的过程自动化,并且成本低,维护要求低。
在这篇文章中,使用 python 开发了一个条形码扫描仪,它可以使用网络摄像头读取产品的条形码,解码条形码中加密的项目的成本,并计算产品的价格,最后在购物结束时,您将获得您购买的项目数量、购买日期、购买项目的名称和相应的成本。发现开发的系统具有成本效益,耐用,易于使用,完全自动化的计费过程,即不需要人工扫描条形码。
条形码生成
现在,python 中有许多标准库可以用来创建条形码。我用过 pyBarcode 。它可以提供 EAN-8,EAN-13,EAN-14,UPC-A,JAN,ISBN-10,ISBN-13,ISSN,Code 39,Code 128,PZN 类型的标准条形码。要安装 pyBarcode ,请使用 pip 作为
*pip install pyBarcode*
一旦安装了 pyBarcode ,运行以下四行代码来创建条形码图像。这将在中保存条形码图像文件。svg 格式。不过也可以另存为*。以下代码中的*与略有变化,摘自此处的。
>>>import barcode
>>>EAN = barcode.get_barcode_class('ean13')
>>>ean = EAN(u'5901234123457')
>>>fullname = ean.save('ean13_barcode')
上述代码将以欧洲商品编号(ean)标准保存条形码。您可以根据选择更改标准。使用 python 脚本生成的条形码如图 2 所示。
Figure 2: Generated barcode using python script
或者,您可以从互联网上免费下载任何软件来生成条形码。我用的工具是从这个网站下载的。您只需要在(可选)条形码的上方和下方设置数据和文本。您还可以设置条形码图像的宽度和高度,并将其提取为。 png 或储存在 excel 中。在我的应用程序中,我使用了 CODE 128 标准,并将图像提取为。 png 。使用软件工具生成的条形码如图 3 所示。
Figure 3: Barcode generate using software.
类似地,我为四个产品(两本书、一个计算器和一个计算机鼠标)生成了条形码,将这些条形码打印出来并粘贴到产品上。经过这些步骤,我的四个产品看起来像,如图 4 所示。
Figure 4: Barcode stick on products under consideration
因此,通过这种方式,您还可以为您的购物商店创建自己的产品条形码。
条形码扫描
在这里,我开发了一个 python 应用程序来读取我创建的条形码,并使用网络摄像头解码数据。该脚本初始化实时视频流,并从视频中提取每一帧。它通过模糊帧来寻找边缘。双边滤波器或高斯滤波器可用于此目的。然后采用自适应阈值获得处理后的图像。在形态学操作之后,围绕条形码绘制轮廓。所有这些步骤都由 pyzbar 的解码对象负责。因此,在执行程序之前,确保您已经安装了 pyzbar ,可以使用 pip as 安装
*pip install pyzbar*
对于剩余的过程,请从 GitHub 库下载完整的代码,并按照 readme 中提到的步骤进行操作。
工作原理:
条形码中加密的数据(产品成本)是产品名称及其成本的组合。例如,物品计算器条形码的数据被设置为 C4,其中“C”被视为物品 ID ( C 计算器),而“4”被视为以美元为单位的物品成本。对于每个扫描的项目,应用程序记录购买日期,购买的项目 ID 和项目成本。一旦我们按下按钮“e”退出条形码读取过程,应用程序会添加每一个购买项目的成本,并显示最终的购物成本。完整过程的演示视频显示在这里。
Demo of the execution of barcode reader script using webcam
优点
- 这种应用可以被认为是成本有效的,因为与条形码阅读器的成本相比,网络摄像头的成本非常非常低。
- 它非常容易操作,也不需要人力,因为网络摄像头可以固定在某个位置,客户只需要将要购买的商品面向网络摄像头的条形码。
- 与条形码阅读器相比,网络摄像头更耐用,即使出现问题,也很容易修复。
- 这个应用程序可以用在购物中心和小商店,以自动化计费过程。它也可以用来开发类似的应用程序,如在图书馆,一本书可以分配给学生使用条形码扫描系统。
挑战
- 如果条形码尺寸较小,或者网络摄像头和条形码之间的距离过大,则系统无法扫描条形码。
这个应用程序也可以用来读取二维码与矿工改变代码。您可以下载代码并创建自己的条形码,根据您的要求设置产品成本。最后,您将拥有一个适用于您的商店/购物店的自动计费流程的完整应用程序。感谢 Jayeeta Chakraborty,他帮助我开发了这个项目。希望这个应用程序可以帮助研究人员和开发人员开发定制的条形码扫描仪。
A 星(A*)搜索算法
Image from Pixabay and created by Author
分步编码的 A-Star 搜索算法
通过最短的路线到达目的地是我们每天都在做的事情。A-star(也称为 A*)是寻找节点或图之间最短路径的最成功的搜索算法之一。这是一种有根据的搜索算法,因为它使用关于路径成本的信息,并且还使用启发式来找到解决方案。
在本文中,我将重点介绍如何使用简单的 python 代码构建 A-star (A*)搜索算法。我发现许多文章和博客都非常关注理论,但没有太多关于这个项目的信息。我在这里尝试用易于理解的细节一步一步地展示代码。
首先,让我们先来点理论热身。
A*实现 最优性 和 完备性 ,搜索算法的两个有价值的性质。
当搜索算法具有最优性时,意味着保证找到最佳可能解。当一个搜索算法具有完备性的性质时,意味着如果一个给定问题的解存在,该算法保证找到它。
为了理解 A*的工作原理,我们首先需要理解几个术语:
- 节点(也叫状态 ) —所有潜在的位置或停止点都有唯一的标识
- 转换 —在状态或节点之间移动的动作。
- 开始节点— 从哪里开始搜索
- 目标节点— 停止搜索的目标。
- 搜索空间 —节点的集合,就像棋盘游戏的所有棋盘位置
- 成本 —从一个节点到另一个节点的路径的数值(比如距离、时间或财务费用)。
- g(n) —这代表从起始节点到任意节点 n 的路径的 精确成本
- h(n) —这代表从节点 n 到目标节点的启发式 估计成本 。
- f(n) —邻居节点 n 中的最低成本
每次 A*进入一个节点,它计算到达所有相邻节点的成本 f(n)(n 是相邻节点),然后进入 f(n)值最低的节点。
我们使用以下公式计算这些值:
f(n) = g(n) + h(n)
这里我们将解决一个迷宫问题。我们必须在迷宫中找到从起点到终点的最短路径。
- Left: Maze problem 2) Right: Position of every node (2D NumPy array positions) of the Maze (Image by Author)
对于这个问题,如果有一个有效的步骤可用,从迷宫位置有四个移动(左,右,上,下)。在红色方块位置,不允许移动(像在开始位置,只有向下的运动是可用的,因为向上和向左的移动被墙阻挡,而对于右边是红色方块位置,因此不允许移动)。
我采用了来自这里和这个博客的代码,这是一个极好的信息来源。如果你需要更清晰的理论和解释,请阅读帕特里克·莱斯特在 A*上的文章。
首先,我们将创建下面的类和帮助函数:
(1) **类“节点”**可用于为每个节点创建一个对象,其信息为父节点、迷宫中的当前位置和成本值(g,h & f)。
(2)我们需要定义一个路径函数,它将返回从 A*开始到结束节点的路径
我们将建立一个搜索函数,它将驱动代码逻辑:
(3.1)初始化所有变量。
(3.2)将起始节点添加到“尚未访问列表”定义停止条件以避免无限循环。用相对位置来定义运动。
重复以下步骤,直到满足停止标准:
(3.3)在“尚未访问列表”中寻找 f 成本最低的方块这个方块成为当前的方块。我们还检查是否达到了最大迭代次数
(3.4)检查当前方块是否与目标方块相同(意味着我们已经找到路径)
(3.5)使用当前正方形并检查与该当前正方形相邻的四个正方形,以更新子节点。如果它是不可移动的,或者如果它在“已访问列表”中,忽略它。否则,以父节点作为当前节点创建新节点,并更新节点的位置。
(3.7)检查创建的所有子节点以查看
如果它不在“尚未访问列表”中,请将其添加到“尚未访问列表”使当前方块成为该方块的父方块。记录正方形的 f、g 和 h 成本。
如果它已经在“尚未访问的列表”中,使用 g 成本作为度量,检查一下到那个方块的路径是否更好。较低的 g 成本意味着这是一条更好的路径。如果是,将方块的父方块更改为当前方块,并重新计算方块的 g 和 f 分数。
(4) **主程序:**我们将定义迷宫、起点和终点位置。然后,我们将使用搜索功能,如果路径存在,我们可以从路径功能打印路径。
现在,我将一步一步地检查代码中的上述步骤(参考括号中的数字)。
首先,我们将为一个节点创建一个类,该类将包含与该节点相关联的所有属性,如节点的父节点、节点的位置以及该节点的所有三个成本(g、h & f)。我们初始化该节点,并构建一个方法来检查该节点与另一个节点是否相等。
Image by Author
现在我们将构建 path 函数,它将用于返回从起始节点到目标节点(结束节点)的路径。
Image by Author
现在我们将定义搜索函数,它有多个步骤。第一步是初始化我们将在函数中使用的节点和列表。
Image by Author
将起始节点添加到“尚未访问列表”定义停止条件以避免无限循环。根据相对位置定义移动,这将用于查找子节点和其他相对位置。
Image by Author
现在我们通过比较所有 f 成本并选择成本最低的节点进行进一步扩展来使用当前节点。我们还检查是否达到了最大迭代次数,设置一个消息并停止执行(避免无限循环)
Image by Author
从“尚未访问列表”中删除所选节点,并将该节点添加到已访问列表中。现在我们检查是否找到了目标方块。如果我们已经定位了目标方块,那么调用 path 函数并返回。
Image by Author
对于选定的节点,找出所有子节点(使用移动来查找子节点)。获取所选节点的当前位置(这将成为子节点的父节点)
a)检查是否存在有效位置(边界墙将使少数节点无效)
b)如果任何节点位置无效(红色方块),则忽略该位置
c)添加到所选父节点的有效子节点列表中
在图中,我们显示黑色圆圈节点是当前节点,绿色圆圈节点是正确的子节点。
Image by Author
对于所有子节点:
a)如果子节点在已访问列表中,则忽略它,并尝试下一个子节点。
b)计算子节点 g、h 和 f 的值。对于 h 启发式算法,此处使用欧几里德距离计算当前节点到达目标节点的成本。
c)如果孩子在“尚未访问列表”中,则忽略它,将孩子移至“尚未访问列表”
Image by Author
现在,最后,我们将运行迷宫的主程序,并获得路径。参考同样使用箭头显示的路径。
Image by Author
结论
A-star (A*)是人工智能中一个强大的算法,有着广泛的用途。然而,它只能发挥它的启发功能(考虑到问题的性质,它可以是高度可变的)。A*是寻路最流行的选择,因为它相当灵活。
它已经在许多软件系统中找到应用,从机器学习和搜索优化到游戏开发,其中角色通过复杂的地形和障碍到达玩家。
你可以在这个 GitHub 仓库中找到完整的代码。
感谢阅读。你可以在 LinkedIn 上和我联系。
每月只需 5 美元,就可以无限制地获取最鼓舞人心的内容……点击下面的链接,成为一名媒体会员,支持我的写作。谢谢大家!
星巴克案例研究:优化顾客与促销的匹配
Photo Credit: Adrianna Calvo
简介
销售活动是用来促进短期销售的营销工具。成功取决于针对正确的客户进行正确的促销。设计不佳的销售活动会让公司付出代价;例如,收入可能会以奖励的形式流失。这意味着,每次公司发起销售活动时,必须仔细考虑奖励的形式——做出该决定所需的关键信息是:1)不同类型促销的预测销售增长,以及 2)了解特定客户对不同促销广告的反应。像星巴克这样的大型零售商在美国有近 14000 家店铺,为数百万顾客提供服务,一场糟糕的促销活动的代价可能是巨大的。
在这篇文章中,我将使用从星巴克的一个实验(见下文)中收集的数据来分析顾客对不同促销的反应。在星巴克,大多数销售活动都是通过互联网进行的,这些促销活动可以分为三类:
- 折扣
- 买一送一(BOGO)
- 信息(例如,新产品或季节性产品)
如果星巴克的老顾客在促销期间花的比她多,促销活动就成功了。如果一个星巴克常客在此期间不改变他的消费行为,销售活动就有让公司付出代价的危险。据估计,星巴克拥有 2300 万“星巴克移动应用”会员,以及关于这些客户的人口统计数据、收到的促销和购买记录的大量数据。通过结合几种数据分析技术,我将回答以下问题(概述了每个目标的简要方法):
**1。细分客户群。**对于不同类别的销售活动,我们能否将客户分为有响应的和无响应的客户?
我将设计功能,并手动将客户分为两组:一组不响应促销,另一组响应促销。反应迅速的顾客是在促销期间在星巴克消费增加的顾客。
2。预测新客户行为。给定之前没有星巴克购买记录的顾客的基本资料(年龄、收入、性别、会员日期),我们能否预测他或她对某种促销活动的反应?
根据现有的客户人口统计数据(性别、年龄、收入和会员资格),我将使用机器学习来建立一个预测模型,以帮助预测新的星巴克会员是否会成为特定促销类别的响应客户。
**3。识别成功促销的特征。**与成功的销售活动相关的一些特征是什么?
使用探索性数据分析(EDA),我将确定成功促销中的常见特征。
术语
促销子类型可以归入三个类别之一:1)折扣,2) BOGO,或 3)信息。例如,促销子类型“花 10 美元减 2 美元”和“花 20 美元减 5 美元”都属于折扣类别。
在折扣类别中,客户在消费一定金额后会获得小额奖励(例如,消费 10 美元可获得 2 美元的折扣)。在 BOGO 类别中,顾客支付一件商品的全价,并免费获得第二件商品。在“信息”类别中,不提供金钱或奖励,但会通知客户关于新产品或季节性产品的信息。
单个报价是发送给客户的广告,宣布促销子类型。
销售活动是在给定时间向客户群发送多个单一报价的行为。
星巴克的实验
在星巴克进行的这个实验中,收集了六个销售活动的数据。在第 1、8、15、18、21 和 24 天宣布了销售活动。在每次销售活动中,大约有 12700 个单次报价(大约。每个子类型 1270 个单个报价)被发送给随机选择的客户。总共有十个促销子类型可用:四个属于折扣类别,四个属于 BOGO 类别,两个属于信息类别。
数据集
三个数据集可用: 作品集 , 成绩单 ,以及 简介 。
Portfolio 包含星巴克提供的所有促销类别和子类型的参考列表。
抄本 记录客户的交易历史,发送给客户的单笔报价的数量和子类型,并提供分析单个客户行为所需的数据。通过一个月的过程收集抄本数据。
简档 包含关于客户的人口统计信息(例如,性别、年龄、收入和会员资格期限),并且当与从抄本数据导出的信息相结合时,可以用于构建客户行为的预测模型。
数据清理
对 组合 、 抄本 、 概要 数据集的部分特征进行了数据清理。
在 组合 中,“渠道”和“报价 _ 类型”被转换为虚拟特征。
在 抄本 中,“事件”被转换为虚拟特征。在“值”中,条目格式根据描述的事件类型而有所不同。我把这些条目分成不同的特征。如果该值反映了单个要约事件(例如,已接收、已查看或已完成的要约),则将对应于该单个要约的子类型的 id 输入到名为“ID”的新特征列中。如果该值反映了一个事务事件,则事务金额被输入到一个名为“transaction_amount”的新特性列中
在 轮廓 中,加工了几个特征。在“年龄”功能中,2175 名客户被列为 118 岁(可能是未透露年龄的客户的默认条目)。我将年龄列中的所有 118 个值转换为 NaN 值。在“成为会员”功能中,客户成为星巴克会员的日期以八位数格式记录(例如,20180726 表示 2018 年 7 月 26 日)。我将其转换为自八位数参考日期以来客户成为会员的总天数,并将该特性重命名为“tension _ length”。“性别”被转换为虚拟特征。
数据分析
1。细分客户群。
在这里,我将执行数据处理和特征工程,针对每种促销类别(折扣、BOGO、信息),将响应客户与非响应客户进行细分。回应型顾客是指在促销期间收到一个报价,并以比平时在星巴克消费更多的钱来回应的顾客。
基于交易和单个报价(例如,收到的报价、查看的报价或完成的报价)数据,我确定了客户在促销和非促销期间的每小时支出(SPH)(见下文),并使用设定的比率(促销-SPH/非促销-SPH)来确定响应客户。用于计算比率的几个指标定义如下:1)异常值,2)感知时间(客户感知促销的时间长度),以及 3)每个促销类别的 SPH。
度量标准。
- 极端值
在星巴克,主要产品是饮料和糕点,大多数交易金额低于 50 美元(见图 1-A)。然而,一小部分交易金额大得惊人(例如,一次付款超过 1000 美元,图 1-B)。这些大额交易可能是餐饮订单,不太可能受到促销的影响,因此不在此处分析。
Figure 1. Histograms of transaction amounts for normal transactions (A) and outlier transactions (B). Note that x an y axes are scaled differently between (A) and (B)
要被视为异常交易,交易金额必须高于由截断四分位数间距(IQR)方法确定的阈值。如果 IQR 得出的阈值低于 50 美元,那么我使用 50 美元作为阈值。
截断的 IQR 是通过首先将客户交易从高到低排序,然后删除前 20%的记录而得到的。这有助于避免人为的高 IQR。阈值是通过第一个四分位数(Q1)值以上的 IQR 值的两倍来计算的(阈值= 2 * IQR + Q1)。
2)意识时间
重要的是要确定顾客知道一次促销活动的时间长度,因为这是顾客的购买行为可能受到促销活动影响的时期。
对于折扣和 BOGO 类别,知晓时间是指客户查看报价的时间,即 1)客户完成报价(即购买)或 2)报价到期(即没有购买)。对于“信息”类别,知晓时间是指客户查看报价的时间到报价到期的时间。
3)每小时支出(SPH)
促销-SPH 按类别(折扣、BOGO 或信息)计算,并定义为:
知晓时间内所有正常交易的总和/属于某一类别的所有单个报价的知晓时间总和
例如,为了计算客户的 SPH 折扣,将在知晓时间内发生的所有正常交易的总和除以属于折扣类别的单个报价的知晓时间总和。
非促销 SPH 的定义是:
非知晓时间内所有正常交易的总和/非知晓时间的总和
所有 SPH 计算都排除了异常值。
识别响应的客户。
对于给定的促销类别,客户是否可以被归类为响应客户取决于(促销-SPH/非促销-SPH)比率。如果(促销-SPH/非促销-SPH)比率高于 1.04(针对折扣)、1.12(针对 BOGO)和 1.00(针对信息),则认为客户对特定促销类别做出了响应。
这里有一个例子。
Table 1. Hypothetical transcript data of a customer.
假设一个客户收到了折扣类别中的单个报价(事件 A,表 1),查看了单个报价(事件 C),进行了三次交易(事件 B、D、E 和 F),并完成了报价(事件 G)。交易 B 发生在知晓时段之外,将被排除在 SPH 促销计算之外。交易 F 被确定为异常值,将从促销 SPH 计算中排除。交易 D 和 E 发生在 aware 时段,将予以考虑。
在本例中:
折扣-SPH =(事件 D 交易金额+事件 E 交易金额)/(事件 G 时间戳-事件 C 时间戳)
= ($3.00 + $6.00) / (100–50)
=每小时 0.18 美元
如果该客户的非促销 SPH 为每小时 0.10 美元,则(折扣-SPH/非促销-SPH)比率将为:0.18 美元/ $0.10 = 1.80 美元
由于响应客户的“通过”(折扣-SPH/非促销-SPH)比率为 1.04,我将该客户确定为响应客户。
探索性数据分析(EDA)。
快速浏览一下响应型客户和 简档 【性别】、【年龄】和【收入】中的可用特征之间的可能关系,可以发现客户是否是响应型客户(参见图 2 中使用“年龄”特征的示例)。“任期长度”似乎显示了积极响应之间的微小差异(图 3 )。
Figure 2. Histograms showing similar “age” distribution for responsive vs. non-responsive customers. Histograms for “gender” and “income” also show no notable differences between responsive vs. non-responsive customers.
Figure 3. Histogram of “tenure_length” for responsive vs. non-responsive customers.
评论。
这里没有使用复杂的预测算法,但是基本的数据处理和分析可以有效地将客户群分为响应客户和非响应客户。
2。预测新客户行为。
在这里,我将使用机器学习来建立一个模型,用于预测新客户对特定促销类别(折扣、BOGO、信息)的反应。新客户是一个新的“星巴克移动应用程序”成员,具有基本的个人资料数据,但没有与星巴克的先前交易记录。基于这些客户的档案数据,我建立了三个分类器模型(每个促销类别一个)来预测一个新成员是否会成为某个促销类别的响应客户。
初始算法扫描。
对包括逻辑回归、线性判别分析、K-最近邻、支持向量机(SVM)、AdaBoost (Ada)、随机森林(RF)和 XGBoost (XGB)在内的七种算法的初始扫描显示,RF 具有最佳性能。F1 分数用于评估性能,因为它反映了第一类和第二类错误。
如果出现第一类错误,意味着一个响应客户被预测为一个非响应客户,那么响应客户的数量将被低估。如果销售活动是基于具有这种误差的预测模型设计的,那么星巴克促销的奖励可能被设置在不能最大化潜在销售促进的水平。
如果出现第二类错误,意味着一个非响应客户被预测为响应客户,那么响应客户的数量将被高估。如果销售活动是基于有这种误差的预测模型设计的,更多的顾客将享受促销的回报,而不会促进销售,星巴克可能会损失收入。
优化模型超参数。
来自 Ada、SVM、RF 和 XGB 的最佳性能模型得到了优化。折扣和 BOGO 的优化模型显示没有改善,而信息模型显示略有改善。
性能。
收集了折扣(0.65)、BOGO (0.67)和信息(0.53)测试集的 F1 分数。
重要特征。
“任期长度”被认为是区分所有促销类别的响应客户和非响应客户的最重要特征。但是由于“任期长度”对于任何新客户来说总是零天,所以这个特性不是一个有用的区分指标。“年龄”、“性别”和“收入”不是区分特征。
评论。
给定新客户的基本概况信息,无法使用机器学习模型预测客户与促销的匹配。可能会收集其他特征,如客户的职业、教育水平或位置,以帮助开发更有效的预测模型(尽管额外的数据收集可能会降低客户的用户体验)。
3。识别成功促销的特征。
这里我使用数据处理来确定推广子类型的成功率。成功的单次优惠必须满足以下标准:1)交易发生在单次优惠被查看之后,以及 2)客户花费的金额高于促销优惠所要求的金额。
促销子类型的成功率计算方法如下:
成功单笔报价数 /总单笔报价数
探索性数据分析(EDA)。
计算了所有十个推广子类型的成功率,范围从 17.5%到 61.0%,没有显示出对推广类别的显著依赖性(参见表 2 )。此外,还计算了要约子类型特征和成功率之间的点双列相关(图 4)。
Figure 4. Selected point biserial correlations of offer sub-type features and the success rate.
Table 2. Ten sub-types and their id’s, selected features (“purchase requirement,” “channel”), and projected success rate.
选择何种渠道(即社交媒体、移动应用、网页和电子邮件)提供单一优惠是成功促销的决定性因素(参见图 4 )。对于每一个子类型,一套固定的渠道被用来发出单一的报价,那些通过社交媒体和星巴克移动应用程序分发的成功率最高。
成功率也与较低的购买要求相关;也就是说,在奖励生效之前,客户支付的金额越少或购买的商品越少,促销就越成功(见图 3 )。例如,在给予“20%奖励”的基础上,要求客户“花 5 美元减 1 美元”的子类型优惠将比“花 20 美元减 4 美元”的促销更有效。
评论。
一次成功的促销可以归入任何类别,但高成功率的决定因素是发送单一优惠的渠道选择和奖励障碍。
建议星巴克采取的行动
下面列出了一些在促销期间提升短期销售额的建议措施。
1.为了最大限度地提高客户响应:
- 从现有会员处收集特定时间段的数据,确定单个客户的客户-促销类别匹配,并相应地发送单个报价。
2.预测新客户行为:
- 当新顾客注册成为星巴克会员以测试可能有助于顾客-促销匹配的可能特征时,在简档部分中可能要求附加数据(例如,职业、教育水平、位置)。
3.要最大限度地提高单次报价的成功率:
- 通过社交网络和移动应用程序发送单个报价。
- 提供折扣和 BOGO 促销,购买要求低。
下一步是什么?
可以做的一个有趣的实验是,发出邀请客户“选择你自己的促销”的单个报价。例如,单个报价可能包含使用折扣子类型、BOGO 子类型的选项,或者获得新的或季节性产品的第一视图。因为客户有“选择”的权利,所以像这样的促销将吸引客户,并揭示每个客户喜欢什么的洞察力,从而有助于改善客户与促销的匹配。可能是一个有趣的想法来测试?
谢谢你看我的帖子。请参见我的 GitHub 库了解这里介绍的工作细节。
回答技术面试中任何问题的循序渐进的方法
在分析和数据科学领域工作的 4 个建议——一个可以利用的框架
任何求职者都知道,整个过程中最紧张的部分几乎肯定是令人恐惧的求职面试!如果你想从事分析方面的职业,那么面试过程会有一系列独特的考验和磨难。但是就像生活中的任何事情一样,你能做的最好的事情就是做好准备。
这篇文章将帮助你做好准备——我们将解释从分析面试中可以期待什么,以及你如何最好地准备。
Image from Unsplash
对于分析领域的大多数职业来说,公司希望你能够很好地编码,或者至少足够好地了解语法,使它不会成为你日常工作的障碍。因此,虽然这些技能通常会受到考验,但这并不是面试官关注的唯一技能。除了技术部分(即编码部分),您可能还需要解决一个“用例”,这是一个他们经历过的问题,一个假设的问题,或者一个他们正在积极尝试解决的问题。
他们不仅测试你解决问题的方法,也测试你解决问题的方法。
成功的步骤
1。关注方法而不是代码
更多的重点通常放在你的方法和途径上,而不是代码本身是否 100%正确
这里需要注意的是,他们不只是在寻找你的解决方案。他们希望看到你解决问题的方法,以及你与主题相关的扎实的技术基础。即使是错误的解决方案,如果您向他们介绍一下您是如何做到这一点的,他们也会留下深刻印象。
你需要向他们展示你理解方法论和你需要做出的潜在的假设来达成解决方案。因此,您需要向他们介绍您所做的假设,以及您做出这些假设的原因。例如,你对用户数量有什么假设?
你还必须思考和解释支撑你的方法论的数学。思考在这种情况下,什么会影响您正在处理的指标,并告知您了解导致这些变化的原因。
如果你还看不到,沟通是贯穿所有这些建议的关键变量。在解释你的方法时,你需要表现出对形势的充分把握。解释你对问题的假设,以及你对解决方案的假设。
Image from Unsplash
2.在代码上注重细节,但只有在被问到的时候
证明你的技术基础足以胜任手头的工作
在工作面试问题中,你经常会看到一段代码,希望你能分析它或者改正错误,从而解决问题。这就是显示你注重细节的极端重要的地方。然而,在这部分之前,你最有可能关注的是解决问题的方法和途径,所以先参考上面的提示 1。
你应该引导面试官完成这个问题的每一部分。看着语法,向面试官解释每个代码块要实现什么。从这里开始,您将能够对这段代码要实现的目标有一个“大致的了解”,并理解可以添加(或删除)什么来实现一个适当的解决方案。
一旦你恰当地解释了整个代码,以及你解决问题的方法,带面试官看一下你认为的解决方案是什么。
Image from StrataScratch, with permission from founder
如您所见,解决方案很重要,但如何实现同样重要。如果面试官能看到你的思维过程,看到你基本上是在正确的轨道上,对所涉及的方法论有着坚实的理解,他们会更愿意原谅你的错误。
3.想想边缘案例
向他们证明您可以将业务问题与技术解决方案联系起来
在编码中,理解边缘案例总是很重要的,工作面试也不例外。
想一想你认为准则可能会被打破的情况,并与你的面试官交流。
如果您能够将这些边缘案例与他们在业务中实际遇到的特定场景联系起来,将会非常有帮助。这是一个很好的机会,不仅可以展示你的编码知识,还可以展示你对他们业务的理解。
然后,一旦你确定了这些潜在的边缘情况,建议一些方法来解释它们,这样问题就不会发生了。一旦你清楚地识别出潜在的问题,解决方案总是更容易达成。这是你向面试官展示你总是在思考潜在的问题领域,并且能够解决它们的机会。
4.不要接受明显的事实!
它们是用来绊倒你的
在面试中出现的任何问题,永远记住不要接受显而易见的答案!如果它是显而易见的,它可能不会在工作面试中作为一个问题给你。
这就是为什么考虑上面的建议如此重要。考虑呈现的每个细节,寻找代码中的漏洞,并考虑真实的业务边缘案例。通过沟通所有这些,你将有可能确定问题所在,并从那里你可以建立一个解决方案。
记住,这是一个需要解决的复杂问题,否则,他们不会给你看。如果你一开始很纠结,慢慢来,陪面试官看一遍,反正他们想看你的思维过程。
帮助您成功的结论和资源
我们无法确切地告诉你在求职面试中会遇到什么问题。但是通过考虑以上所有的建议,你可以制定一个可靠的策略来解决你可能遇到的任何问题。
如果你想对你的编码进行一些额外的练习,看看过去的一篇关于学习 SQL 和 Python 的最好平台的文章。
如果你面试的是一个涉及编码的分析职位,那么编码几乎应该成为你的第二天性。面试官更感兴趣的是你如何分解问题,如何识别需要改进的地方,以及如何找到解决方案。他们还希望看到你了解他们的业务,这意味着考虑具体的优势案例和可能与他们经营的竞争环境相关的相关因素。
Image from StrataScratch, with permission from founder
所以你有它,慢慢来,彻底,但最重要的是沟通你的整个思维过程。
祝你好运!
最初发表于T5【https://www.stratascratch.com】。
使用 Seaborn / Matplotlib 创建高级 Python 数据可视化的分步指南
尽管 Python 中有大量优秀的可视化工具,Matplotlib + Seaborn 仍然因其创建和定制各种绘图的能力而脱颖而出。
Photo by Jack Anstey on Unsplash
在本文中,我将首先浏览几个部分,为一些不熟悉 Matplotlib 的读者准备背景知识:
- 了解两个不同的 Matplotlib 接口(已经造成了很多混乱!) .
- 理解图中的元素,这样你就可以很容易地查找 API 来解决你的问题。
- 看一下几种常见的情节类型,这样读者会对何时/如何使用它们有更好的了解。
- 学习如何增加你的情节的“维度”。
- 了解如何使用 GridSpec 对图形进行分区。
然后我将通过一个例子来讨论创建高级可视化的过程:
- 树立一个目标。
- 准备变量。
- 准备可视化。
让我们开始旅程吧。
两个不同的 Matplotlib 接口
在 Matplotlib 中有两种编码方式。第一个是基于状态的:
import matplotlib.pyplot as plt
plt.figure()
plt.plot([0, 1], [0, 1],'r--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.title('Test figure')
plt.show()
这有利于创造简单的情节(你称之为一堆 plt。XXX 来绘制图形中的每个组件),但您没有对图形的太多控制。另一个是面向对象的:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(3,3))
ax.bar(x=['A','B','C'], height=[3.1,7,4.2], color='r')
ax.set_xlabel(xlabel='X title', size=20)
ax.set_ylabel(ylabel='Y title' , color='b', size=20)
plt.show()
这将需要更多的时间来编码,但你可以完全控制你的数字。这个想法是,你创建一个“图形”对象,你可以把它想象成你要构建的整个可视化的边界框,和一个或多个“轴”对象,它们是可视化的支线剧情,(不要问我为什么这些支线剧情叫“轴”。名字太烂了……)支线剧情可以通过这些“轴”对象的方法来操作。
(关于这两个接口的详细解释,读者可以参考
https://matplotlib . org/tutorials/introductive/life cycle . html
或
https://pbpython.com/effective-matplotlib.html)
让我们在本教程中坚持使用面向对象的方法。
面向对象界面中图形中的元素
下面这幅取自 https://pbpython.com/effective-matplotlib.html 的图很好地解释了一个图形的组成部分:
让我们看一个简单的例子,如何用面向对象的界面创建折线图。
fig, ax = plt.subplots(figsize=(3,3))
ax.plot(['Alice','Bob','Catherine'], [4,6,3], color='r')
ax.set_xlabel('TITLE 1')
for tick in ax.get_xticklabels():
tick.set_rotation(45)
plt.show()
在上面的代码中,我们创建了一个 axes 对象,在其上创建了一个线图,添加了一个标题,并将所有的 x-tick 标签逆时针旋转了 45 度。
查看官方 API,看看如何操作轴对象:https://matplotlib.org/api/axes_api.html
几种常见的绘图类型
在对 Matplotlib 的工作原理有了大致的了解之后,是时候看看一些常见的情节了。他们是
散点图(x:数值#1,y:数值#2),
线形图(x:分类序数#1,y:数值# 1)[感谢 Michael Arons 在前图中指出一个问题],
条形图(x:分类#1,y:数字#1)。数字#1 通常是分类#1 的计数。
直方图(x:数值#1,y:数值#2)。数字#1 组合成组(转换成分类变量),数字#2 通常是这个分类变量的计数。
内核密度图(x:数值#1,y:数值#2)。数字#2 是数字#1 的频率。
二维内核密度图(x:数值#1,y:数值#2,颜色:数值#3)。数值#3 是数值#1 和数值#2 的联合频率。
箱线图(x:分类#1,y:数值#1,标记:数值#2)。箱线图显示了分类#1 中每个值的统计数据,因此我们可以了解其他变量的分布情况。y 值:另一个变量的值;标记:显示这些值是如何分布的(极差、Q1、中位数、Q3)。
小提琴图(x:分类#1,y:数值#1,宽度/标记:数值#2)。小提琴图有点类似于箱线图,但它更好地显示了分布。
热图(x:分类#1,y:分类#2,颜色:数字#1)。数值#1 可以是分类#1 和分类#2 的共同计数,也可以是该对中每个值的其他数值属性(分类#1、分类#2)。
为了了解如何绘制这些图形,读者可以通过谷歌搜索以下列表来查看 seaborn APIs:
SNS . bar plot/SNS . distplot/SNS . line plot/SNS . kdeplot/SNS . violinplot
SNS . scatter plot/SNS . box plot/SNS . heat map
我将给出两个示例代码,展示如何在面向对象的界面中生成 2D kde 图/热图。
# 2D kde plots
import numpy as np
import matplotlib.pyplot as plt
import seaborn as snsnp.random.seed(1)
numerical_1 = np.random.randn(100)
np.random.seed(2)
numerical_2 = np.random.randn(100)fig, ax = plt.subplots(figsize=(3,3))
sns.kdeplot(data=numerical_1,
data2= numerical_2,
ax=ax,
shade=True,
color="blue",
bw=1)
plt.show()
关键是参数 ax=ax。跑步的时候。kdeplot()方法,seaborn 会将更改应用到 ax,一个“axes”对象。
# heat mapimport numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsdf = pd.DataFrame(dict(categorical_1=['apple', 'banana', 'grapes',
'apple', 'banana', 'grapes',
'apple', 'banana', 'grapes'],
categorical_2=['A','A','A','B','B','B','C','C','C'],
value=[10,2,5,7,3,15,1,6,8]))
pivot_table = df.pivot("categorical_1", "categorical_2", "value")# try printing out pivot_table to see what it looks like!fig, ax = plt.subplots(figsize=(5,5))sns.heatmap(data=pivot_table,
cmap=sns.color_palette("Blues"),
ax=ax)
plt.show()
增加你的图的维度
对于这些基本图,只能显示有限的信息量(2-3 个变量)。如果我们想显示这些图的更多信息呢?以下是几种方法。
- 覆盖图
如果几个折线图共享相同的 x 和 y 变量,您可以多次调用 Seaborn plots,并将它们全部绘制在同一个图上。在下面的例子中,我们在覆盖图中添加了一个分类变量[value = alpha,beta]。
fig, ax = plt.subplots(figsize=(4,4))
sns.lineplot(x=['A','B','C','D'],
y=[4,2,5,3],
color='r',
ax=ax)
sns.lineplot(x=['A','B','C','D'],
y=[1,6,2,4],
color='b',
ax=ax)
ax.legend(['alpha', 'beta'], facecolor='w')
plt.show()
或者,我们可以将 x 轴相同但 y 轴不同的条形图和折线图结合起来:
sns.set(style="white", rc={"lines.linewidth": 3})fig, ax1 = plt.subplots(figsize=(4,4))
ax2 = ax1.twinx()sns.barplot(x=['A','B','C','D'],
y=[100,200,135,98],
color='#004488',
ax=ax1)sns.lineplot(x=['A','B','C','D'],
y=[4,2,5,3],
color='r',
marker="o",
ax=ax2)
plt.show()
sns.set()
这里提几点意见。因为两个图具有不同的 y 轴,我们需要创建另一个具有相同 x 轴的“轴”对象(使用。twinx())然后绘制在不同的“轴”上。sns.set(…)是为当前剧情设置特定的审美,我们最后运行 sns.set()将一切设置回默认设置。
将不同的柱状图组合成一个分组柱状图也为该图增加了一个分类维度(多了一个分类变量)。
import matplotlib.pyplot as pltcategorical_1 = ['A', 'B', 'C', 'D']
colors = ['green', 'red', 'blue', 'orange']
numerical = [[6, 9, 2, 7],
[6, 7, 3, 8],
[9, 11, 13, 15],
[3, 5, 9, 6]]number_groups = len(categorical_1)
bin_width = 1.0/(number_groups+1)fig, ax = plt.subplots(figsize=(6,6))for i in range(number_groups):
ax.bar(x=np.arange(len(categorical_1)) + i*bin_width,
height=numerical[i],
width=bin_width,
color=colors[i],
align='center')ax.set_xticks(np.arange(len(categorical_1)) + number_groups/(2*(number_groups+1)))# number_groups/(2*(number_groups+1)): offset of xticklabelax.set_xticklabels(categorical_1)
ax.legend(categorical_1, facecolor='w')plt.show()
在上面的代码示例中,您可以自定义变量名、颜色和图形大小。number_groups 和 bin_width 是根据输入数据计算的。然后,我编写了一个 for 循环来绘制条形,一次一种颜色,并在最后设置刻度和图例。
2.面-将数据集映射到多个轴,它们之间有一两个分类变量的差异。读者可以在https://seaborn.pydata.org/generated/seaborn.FacetGrid.html中找到一堆例子
3.散点图中节点的颜色/形状/大小:下面的代码示例来自 Seaborn 散点图 API,展示了它是如何工作的。(https://seaborn . pydata . org/generated/seaborn . scatter plot . html)
import seaborn as snstips = sns.load_dataset("tips")
ax = sns.scatterplot(x="total_bill", y="tip",
hue="size", size="size",
sizes=(20, 200), hue_norm=(0, 7),
legend="full", data=tips)
plt.show()
使用 GridSpec 划分图形
面向对象界面的一个优点是,我们可以很容易地将我们的图形划分成几个子图形,并用“轴”API 操纵每个子图形。
fig = plt.figure(figsize=(7,7))
gs = gridspec.GridSpec(nrows=3,
ncols=3,
figure=fig,
width_ratios= [1, 1, 1],
height_ratios=[1, 1, 1],
wspace=0.3,
hspace=0.3)ax1 = fig.add_subplot(gs[0, 0])
ax1.text(0.5, 0.5, 'ax1: gs[0, 0]', fontsize=12, fontweight="bold", va="center", ha="center") # adding text to ax1ax2 = fig.add_subplot(gs[0, 1:3])
ax2.text(0.5, 0.5, 'ax2: gs[0, 1:3]', fontsize=12, fontweight="bold", va="center", ha="center")ax3 = fig.add_subplot(gs[1:3, 0:2])
ax3.text(0.5, 0.5, 'ax3: gs[1:3, 0:2]', fontsize=12, fontweight="bold", va="center", ha="center")ax4 = fig.add_subplot(gs[1:3, 2])
ax4.text(0.5, 0.5, 'ax4: gs[1:3, 2]', fontsize=12, fontweight="bold", va="center", ha="center")plt.show()
在示例中,我们首先用 gridspec 将图形划分成 3*3 = 9 个小方框。GridSpec(),然后定义几个 axes 对象。每个轴对象可以包含一个或多个框。在上面的代码中,gs[0,1:3] = gs[0,1] + gs[0,2]被分配给 axes 对象 ax2。wspace 和 hspace 是控制地块间距的参数。
创建高级可视化
有了前几节的一些教程,是时候制作一些很酷的东西了。让我们从 https://www.kaggle.com/mehdidag/black-friday的
下载分析 Vidhya 黑色星期五销售数据,并做一些简单的数据预处理:
df = pd.read_csv('BlackFriday.csv', usecols = ['User_ID', 'Gender', 'Age', 'Purchase'])df_gp_1 = df[['User_ID', 'Purchase']].groupby('User_ID').agg(np.mean).reset_index()df_gp_2 = df[['User_ID', 'Gender', 'Age']].groupby('User_ID').agg(max).reset_index()df_gp = pd.merge(df_gp_1, df_gp_2, on = ['User_ID'])
然后,您将获得一个表,其中包含用户 ID、性别、年龄以及每个客户购买的商品的平均价格。
第一步。目标 我们很好奇年龄和性别会如何影响黑色星期五期间的平均购买价格,我们也希望看到价格分布。我们还想知道每个年龄组的百分比。
第二步。变量
我们希望在图中包括年龄组(分类)、性别(分类)、平均商品价格(数值)以及平均商品价格的分布(数值)。我们需要包括另一个图,每个年龄组的百分比(年龄组+计数/频率)。
为了显示平均物品价格+它的分布,我们可以用核心密度图,箱线图,或小提琴图。其中,kde 显示的分布最好。然后,我们在同一个图形中绘制两个或更多的 kde 图,然后绘制小平面图,这样年龄组和性别信息都可以包括在内。对于另一个图,条形图可以很好地完成这项工作。
第三步。可视化
一旦我们有了关于变量的计划,我们就可以考虑如何将它可视化。我们需要先做图形分区,隐藏一些边界、xticks、yticks,然后在右边加一个条形图。
下面的情节就是我们要创造的。从图中,我们可以清楚地看到,根据数据,男性比女性倾向于购买更昂贵的物品,老年人倾向于购买更昂贵的物品(对于前 4 个年龄组,趋势更明显)。我们还发现,18-45 岁的人是黑色星期五销售的主要买家。
以下代码生成绘图(注释中包含解释):
freq = ((df_gp.Age.value_counts(normalize = True).reset_index().sort_values(by = 'index').Age)*100).tolist()number_gp = 7**# freq = the percentage for each age group, and there’re 7 age groups.**def ax_settings(ax, var_name, x_min, x_max):
ax.set_xlim(x_min,x_max)
ax.set_yticks([])
ax.spines['left'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_edgecolor('#444444')
ax.spines['bottom'].set_linewidth(2)
ax.text(0.02, 0.05, var_name, fontsize=17, fontweight="bold", transform = ax.transAxes)
return None**# Manipulate each axes object in the left. Try to tune some parameters and you'll know how each command works.**fig = plt.figure(figsize=(12,7))
gs = gridspec.GridSpec(nrows=number_gp,
ncols=2,
figure=fig,
width_ratios= [3, 1],
height_ratios= [1]*number_gp,
wspace=0.2, hspace=0.05
)ax = [None]*(number_gp + 1)
features = ['0-17', '18-25', '26-35', '36-45', '46-50', '51-55', '55+']**# Create a figure, partition the figure into 7*2 boxes, set up an ax array to store axes objects, and create a list of age group names.** for i in range(number_gp):
ax[i] = fig.add_subplot(gs[i, 0])
ax_settings(ax[i], 'Age: ' + str(features[i]), -1000, 20000)
sns.kdeplot(data=df_gp[(df_gp.Gender == 'M') & (df_gp.Age == features[i])].Purchase,
ax=ax[i], shade=True, color="blue", bw=300, legend=False)
sns.kdeplot(data=df_gp[(df_gp.Gender == 'F') & (df_gp.Age == features[i])].Purchase,
ax=ax[i], shade=True, color="red", bw=300, legend=False)
if i < (number_gp - 1):
ax[i].set_xticks([])**# this 'for loop' is to create a bunch of axes objects, and link them to GridSpec boxes. Then, we manipulate them with sns.kdeplot() and ax_settings() we just defined.**ax[0].legend(['Male', 'Female'], facecolor='w')**# adding legends on the top axes object ** ax[number_gp] = fig.add_subplot(gs[:, 1])
ax[number_gp].spines['right'].set_visible(False)
ax[number_gp].spines['top'].set_visible(False)ax[number_gp].barh(features, freq, color='#004c99', height=0.4)
ax[number_gp].set_xlim(0,100)
ax[number_gp].invert_yaxis()
ax[number_gp].text(1.09, -0.04, '(%)', fontsize=10, transform = ax[number_gp].transAxes)
ax[number_gp].tick_params(axis='y', labelsize = 14)**# manipulate the bar plot on the right. Try to comment out some of the commands to see what they actually do to the bar plot.** plt.show()
像这样的地块也被称为“喜悦地块”或“山脊线地块”。如果你试图使用一些 joyplot 软件包来绘制相同的图形,你会发现这有点困难,因为每个支线剧情中都包含了两个密度图。
希望这是一个快乐的阅读给你。
为乳腺组织分类构建多类分类器的分步指南
从头开始构建您自己的分类器
Photo by Paweł Czerwiński on Unsplash
这篇文章包含一步一步的建立和训练一个简单的多类分类模型来分类乳房组织的指南。我们将使用来自 UCI 机器学习知识库的乳房组织数据集作为我们训练和测试分类器模型的数据集。
让我们开始吧。
了解数据集
你可以从这个链接下载数据集。数据集是一个带有。xls 扩展名,文件名为***breast tissue . xls .***打开文件,我们可以发现两个选项卡:描述和数据。
通读该描述,我们知道该数据集包含 106 个从乳房新切下的组织的电阻抗测量实例。该数据集有 9 个要素和 1 个类属性。每个乳房组织属于六类中的一类。
数据选项卡包含我们需要的数据。我们可以继续操作,只使用 data 选项卡创建一个新的 CSV 文件。
导入数据
让我们将之前保存的 CSV 文件导入到 pandas 数据帧中。
快速浏览数据
现在,我们已经加载了数据,我们可以看到数据的形状,找出数据中有多少个不同的类,并通过查看数值的平均值、标准偏差和百分比分布来了解数据分布的基本概念。
定义输入和输出
让我们把数据分成输入和输出。我们将 9 个特征作为输入 X,类作为输出 y。
分割训练和测试数据
现在,我们将数据集进一步划分为训练数据集和测试数据集,其中总数据集的 0.33%被划分为测试集。 X_train 为训练输入, y_train 为训练输出, X_test 为测试输入, y_test 为测试输出。
创建并拟合分类模型
让我们使用 xgboost python 库构建一个多类梯度提升分类器,并使用训练数据集训练分类器。
将训练好的模型应用于测试数据集
我们有一个经过训练的多类分类器,现在我们将使用它来预测测试集的类。我们将使用 ROC AUC 作为该模型的评估矩阵。
直观比较输出
您还可以直观地比较测试数据集的预期输出和预测输出。
现在,您已经成功构建并训练了一个乳房组织分类器,它可以将给定的数据分类到六个不同的类别中。我们从 CSV 文件中提取数据,指定输入和输出,分成训练集和测试集,训练一个梯度提升分类器,并在测试集上测试它。
这里有一个完整代码的链接。
觉得这个帖子有用吗?请在下面留下你的想法。
点击这里 阅读我其他关于 AI/机器学习的帖子。
数据来源:
https://archive.ics.uci.edu/ml/datasets/Breast+Tissue
Dua d .和 Graff c .(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。
参考文献:
[## sk learn . preprocessing . label binarizer-sci kit-learn 0 . 21 . 3 文档
以一对一的方式对标签进行二进制化。有几种回归和二进制分类算法可用于…
scikit-learn.org](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelBinarizer.html) [## sk learn . metrics . roc _ AUC _ score-sci kit-learn 0 . 21 . 3 文档
根据预测得分计算受试者工作特征曲线下的面积(ROC AUC)。注意:这个…
scikit-learn.org](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html)
制作销售仪表板的分步指南
我写过一些关于 业务仪表盘 数据可视化的入门指南,但是那些文章还是有点理论化。最近,我一直在做一个数据可视化的销售仪表板项目。从指标的确定、版面设计、图表类型到动态效果,我总结了一些经验和看法。在本帖中,我将与你分享制作销售仪表板的具体步骤。
1。制作仪表盘的工具
仪表板的生产可以通过代码开发或现有的可视化工具来完成。很多人会用 JS 和 Ecahrts,但通常涉及到数据支持、后台响应、实时更新、平台运维等。,需要更多的技术,这里就不赘述了。
另一种方法是使用现成的可视化工具。使用像 FineReport 或 Tableau 这样的工具来构建业务仪表板是相对简单和高效的。由于自己的工作需要,对 FineReport 的操作比较熟悉,所以本文中我将向大家展示的是我是如何使用 FineReport 制作销售仪表盘的。
2。确定分析指标
观看销售仪表盘,你可能会被酷炫的视觉效果所吸引。但是,请记住,仪表板必须基于数据的呈现,任何酷的效果都不能影响数据的有效显示。
因此,我们应该首先考虑哪些数据和哪些指标应该放在仪表板上。您可以使用关键指标分解方法来确定要显示哪些数据。
步骤 1 :识别关键指标。对于销售仪表盘来说,你的总销售额一定是最重要的,这是主题。
第二步:从多个维度分解关键指标,也就是分解你的销售额。
- 从时间维度来看。每个季度或每个月的销售情况如何?为什么有些时间段销量特别高?采取了哪些措施?
- 从地理维度来看。各地区销售情况如何?他们的排名是什么?
- 从规划的角度来看。现在的销售和之前的计划有什么区别?
- 从比例维度来看。每个产品的销量如何?哪些是最赚钱的明星产品?
3。设计布局
一般情况下,一个指标独占仪表盘上的一个区域,所以通过关键指标的定义,你就知道仪表盘上会显示什么内容,仪表盘会分成多少块。您可以根据业务场景确定指标的重要性,然后设计仪表板的布局。
布局的目的是合理地呈现业务指标和数据。有主次指标。一级指标反映的是核心业务,二级指标用于进一步细化,所以在设计布局时赋予了不同的权重。
这里我推荐几种常见的布局。
4。选择图表类型
关键指标确定后,我们需要确定指标的分析维度。数据能否分析透彻,能否为决策提供支持,取决于指标的分析维度。我们常见的分析方法有类比、趋势、分布、构成等。分析方法的选择取决于实际的业务场景。
以购物中心的数据为例,我将告诉你如何选择正确的图表类型。
如果想了解更多关于图表的类型和应用,可以参考本文 数据可视化中的 16 大图表类型 。
5。添加动态效果
动态效果是可视化的重要组成部分。它们使整个仪表板更具吸引力。但是过多的动态使观众眼花缭乱,它不能突出关键信息。所以需要注意动态设计的比例。
动态效果的范围很广。有动态图像、页面旋转、列表滚动、实时数据更改等等。以下是 FineReport 的一些内置动态效果。
练习
以上是制作仪表盘的基本步骤。说到这里,我将向您展示我如何使用 FineReport 来制作销售仪表板。
①导入数据
首先,我们准备数据并将其导入 FineReport Designer。这里的数据是虚构的,因为我用的是 FineReport 的内置数据集。
如下图所示,在真实场景中,我们需要连接各种数据库来导入数据。
连接的数据可以是常见的关系数据库,也可以是 Excel 之类的文件数据。并且 FineReport 支持连接大数据平台。
②制作模板
一旦数据准备就绪,下一步就是创建模板。
首先,我创建一个空白模板,如下所示。原理是在空白模板上拖拽一个可视化组件(比如图表),然后绑定数据。
在我们开始之前,我们需要考虑我们想要在这个空白界面上显示什么样的销售数据。
经过深思熟虑,我设计了以下布局。中间是主旋律,左右是副主旋律。
③选择可视化元素
对于销售,我们首先分析量化指标。拖放表格和图表来显示,如上所示。
在 FineReport Designer 上选择合适的图表样式,连接开始导入的数据。
④添加动态效果
在这个销售仪表板中,我添加了一个流程图来显示全国或全球销售业务的分布。
动态效果如下图所示,数据是销售地点的经纬度信息。
最后,经过一系列的美化设置,仪表盘就完成了。
这个销售仪表板相对简单,这里是我用 FineReport 制作的一些其他仪表板。
最后我想说,做一个仪表盘并不难。最重要的是,我们必须找出业务运营性质的关键指标,并让领导者看到数据的价值。这是数据可视化中最重要的一步。希望今天分享的文章能对你有一点帮助。如果你想自己做一个销售仪表盘,可以下载 FineReport 来练习,这是一个零编码的可视化工具。它的个人版本是完全免费的。
您可能也会对…感兴趣
梯度下降和反向传播的逐步实现
从头开始构建神经网络的一个例子
这篇文章背后的初衷仅仅是我在神经网络中梳理数学,因为我喜欢精通算法的内部工作,并获得事物的本质。然后我想,与其一遍又一遍地重温记事本上的公式,我还不如编一个故事。尽管您可能会找到一些从头构建简单神经网络的教程。不同的人看待事物的角度不同,学习的侧重点也不同。另一种思维方式可能在某种意义上增强理解。所以让我们开始吧。
Photo from Unsplash
概括地说神经网络
神经网络的核心是一个大函数,它将一些输入映射到所需的目标值,在中间步骤中执行生成网络的操作,这是通过在一个反复执行此操作的流水线场景中乘以权重并添加偏差来实现的。训练神经网络的过程是确定一组参数,使期望值和模型输出之间的差异最小化。这是使用梯度下降(又名反向传播)来完成的,根据定义,梯度下降包括两个步骤:计算损失/误差函数的梯度,然后响应于梯度更新现有参数,这就是下降是如何完成的。重复这个循环,直到达到损失函数的最小值。这个学习过程可以用简单的等式来描述:W(t+1) = W(t) — dJ(W)/dW(t)。
数学直觉
Photo from https://blog.goodaudience.com/artificial-neural-networks-explained-436fcf36e75
出于我自己的练习目的,我喜欢使用一个如图所示的只有一个隐藏层的小网络。在该布局中,X 表示输入,下标 I、j、k 分别表示输入、隐藏和输出层中的单元数量;w_ij 表示连接输入到隐藏层的权重,w_jk 是连接隐藏到输出层的权重。
在这种情况下,模型输出计算如下:
损失函数的选择通常是误差平方和。这里,我使用 sigmoid 激活函数,为了简单起见,假设偏差 b 为 0,这意味着权重是影响模型输出的唯一变量。让我们推导出计算隐藏到输出权重 w_jk 的梯度的公式。
确定隐权输入的复杂性在于它间接影响输出误差。每个隐藏单元输出影响模型输出,因此对隐藏权重 w_ij 的输入取决于它所连接的所有单元的误差。推导开始也一样,只是把 z_k 处的链式法则展开到子函数上。
更多思想:
请注意,两个权重的梯度具有相似的形式。误差通过激活函数的导数反向传播,然后通过来自前一层的输入(激活输出)加权。在第二个公式中,来自输出层的反向传播误差被进一步投影到 w_jk 上,然后重复相同的反向传播方式并通过输入进行加权。这种反向传播过程一直重复到任意层神经网络的第一层。“因此,关于每个参数的梯度被认为是参数对误差的贡献,并且应该在学习期间被否定。”
将上述过程编写成代码:
以下是完整的示例:
import numpy as npclass NeuralNetwork:
def __init__(self):
np.random.seed(10) # for generating the same results
self.wij = np.random.rand(3,4) # input to hidden layer weights
self.wjk = np.random.rand(4,1) # hidden layer to output weights
def sigmoid(self, x, w):
z = np.dot(x, w)
return 1/(1 + np.exp(-z))
def sigmoid_derivative(self, x, w):
return self.sigmoid(x, w) * (1 - self.sigmoid(x, w))
def gradient_descent(self, x, y, iterations):
for i in range(iterations):
Xi = x
Xj = self.sigmoid(Xi, self.wij)
yhat = self.sigmoid(Xj, self.wjk)
# gradients for hidden to output weights
g_wjk = np.dot(Xj.T, (y - yhat) * self.sigmoid_derivative(Xj, self.wjk))
# gradients for input to hidden weights
g_wij = np.dot(Xi.T, np.dot((y - yhat) * self.sigmoid_derivative(Xj, self.wjk), self.wjk.T) * self.sigmoid_derivative(Xi, self.wij))
# update weights
self.wij += g_wij
self.wjk += g_wjk
print('The final prediction from neural network are: ')
print(yhat)if __name__ == '__main__':
neural_network = NeuralNetwork()
print('Random starting input to hidden weights: ')
print(neural_network.wij)
print('Random starting hidden to output weights: ')
print(neural_network.wjk)
X = np.array([[0, 0, 1], [1, 1, 1], [1, 0, 1], [0, 1, 1]])
y = np.array([[0, 1, 1, 0]]).T
neural_network.gradient_descent(X, y, 10000)
参考资料:
- https://theclevermachine . WordPress . com/2014/09/06/derivation-error-back propagation-gradient-descent-for-neural-networks/
- https://towards data science . com/how-to-build-your-own-your-own-neural-network-in-python-68998 a08e 4 f 6
开始 nbdev 的逐步介绍——探索性编程
使用 nbdev 的简化 Hello World 示例
“我真的认为[nbdev]是编程环境的巨大进步”:Swift、LLVM、Xcode 和 Swift Playgrounds 的发明者克里斯·拉特纳。
Image by Alfons Morales — Unsplash
杰瑞米·霍华德不停地用他伟大的库给我们留下深刻的印象,例如 Fastai (一个使用 PyTorch 的高级 API)。
今天(2019 年 2 月 12 日)杰瑞米·霍华德和西尔万·古格发布了另一个令人敬畏的库[“nbdev”](/(from nbdev)),它允许在 Jupyter 笔记本上完全开发一个库,将你所有的代码、测试和文档放在一个地方。
也就是说,正如 Donald Knuth 在 1983 年所设想的那样,您现在拥有了一个真正有文化的编程环境!
Exploring the notebook file format in the nbdev source code
nbdev:探索性编程(来自 nbdev)
探索性编程是一种基于观察的编程技术。在编码时,编码人员倾向于花费大量时间探索和试验不同的 API、数据、算法等。尤其是 ML 工程师,他们花了很多精力去改变超参数,并把它们记录在某个地方——实验管理。当您使用 REPL 或笔记本系统(如 Jupyter 笔记本)编码时,这样的过程更容易。但是这些系统对于“编程”部分来说并不强大。这就是为什么人们主要使用这样的系统进行早期探索,然后在项目的后期切换到 IDE 或文本编辑器。
nbdev 的特点(来自 nbdev)
nbdev 的主要目的是将 IDE/编辑器的关键特性带到笔记本电脑中,让您不必担心整个生命周期。此外,nbdev 还提供以下功能:
- Python 模块是按照最佳实践自动创建的,比如用导出的函数、类和变量自动定义 all ( 更多细节)
- 在标准文本编辑器或 IDE 中导航和编辑您的代码,并将任何更改自动导出到您的笔记本中
- 从代码中自动创建可搜索的超链接文档。您用反勾号括起来的任何单词都将被超链接到相应的文档,在您的文档站点中将为您创建一个侧栏,其中包含到您的每个模块的链接,等等
- Pip 安装程序(为您上传到 pypi)
测试(直接在您的笔记本中定义,并并行运行)
持续集成 - 版本控制冲突处理
设置您的 nbdev (Hello World 示例)
设置 nbdev 很简单:
- 点击此处此链接将引导您进入 Github,在这里您只需给出一个回购名称
- 之后,克隆 repo 并编辑
settings.ini
文件以符合您的要求。不要忘记取消注释所需的行(lib_name、user 等。)
- 每次编辑后,运行命令
nbdev_build_lib
,它预装了 nbdev。
然后启动 Jupyter 笔记本,如果你在基本目录下,你应该看到以下内容:
点击00_core.ipynb
,在这里你将创建你的第一个模块!
当您开始创建单元格和编写代码时,不要忘记以#export
或#exports
开始每个单元格,以显示文档中的源代码。
最后,您有两种选择,是否将下面的代码放在最后一个单元格中:
from nbdev.export import *
notebook2script()
或者运行命令:nbdev_build_lib
不要忘记编辑index.ipynb
。这将被转换为您的项目自述文件,也将成为您的文档的索引。
运行命令nbdev_build_lib
后,将创建一个新目录,其名称与您在settings.ini
中设置的lib_name
相同。注意exploratoryprogramming
:
exploratoryprogramming
的内容:
现在,您将开始创建令人惊叹的深度学习项目!如果您有任何问题或意见,请告诉我。
资源
用动态记忆网络实现通用自然语言处理的一步
用动态记忆网络和问答格式解决不同的自然语言处理任务
Image by Pete Linforth from Pixabay
Source: [1]
我假设你已经熟悉 LSTMs 和 GRUs 等递归神经网络(包括 seq2seq 编码器-解码器架构)。
通用自然语言处理的一个障碍是不同的任务(如文本分类、序列标记和文本生成)需要不同的顺序架构。处理这个问题的一个方法是将这些不同的任务视为问答问题。因此,例如,可以向模型询问对一段文本的情感是什么(传统上是文本分类问题),答案可以是“正面”、“负面”或“中性”之一。
论文“问我任何问题:自然语言处理的动态记忆网络”介绍了一种新的、模块化的问答体系结构。
对于复杂的问答问题,LSTMs 和 GRUs 的内存组件可能会成为瓶颈。很难一次就在内存组件中积累所有相关信息,因此,本文背后的关键思想是允许模型根据需要多次访问数据。
尽管该架构乍看起来极其复杂,但它可以被分解成许多简单的组件。
模块
语义记忆模块
语义记忆模块简单地引用单词嵌入,例如手套向量,输入文本在被传递到输入模块之前被转换成该单词嵌入。
输入模块
输入模块是一个标准的 GRU(或 BiGRU),其中每个句子的最后一个隐藏状态是显式可访问的。
问题模块
问题模块也是一个标准的 GRU,要回答的问题作为输入,最后一个状态隐藏状态是可访问的。
情节记忆模块
这是对输入数据进行多次传递的模块。在每一遍中,来自输入模块的句子嵌入作为输入被馈送到情节记忆模块中的 GRU。这里,每个嵌入的句子被分配一个权重,该权重对应于其与所问问题的相关性。
不同的权重可以被分配给不同遍的句子嵌入。例如,在下面的例子中;
由于句子(1)与问题没有直接关系,因此可能不会在第一遍中给予很高的权重。然而,在第一次传递中,模型发现足球与约翰相关联,因此在第二次传递中,给予句子(1)更高的权重。
对于第一遍(或第一“情节”),嵌入“q”的问题用于计算来自输入模块的句子嵌入的注意力分数。
句子 sᵢ 的注意力分数然后可以通过 softmax(这样注意力分数总和为 1)或单个 sigmoid 来获得 gᵢ。
gᵢ 是赋予语句sᵢ的权重,并在时间步长 i. 充当 GRU 输出的全局门
时间步 i 和情节 t 的隐藏状态计算如下:
当 g = 0 时,隐藏状态被简单地向前复制。也就是说,
第 *t 集的 GRU 的最后隐藏状态,*被称为 m ᵗ,可以被视为在第 t. 集期间发现的事实的聚集。从第二集开始, m ᵗ被用于计算第 t+1 集的句子嵌入以及问题嵌入 q 的注意力分数。
计算如下:
在 sᵢ 和 *q、*和 sᵢ 和 m ᵗ⁻之间计算多个简单的相似性度量,即逐元素乘法和绝对差。连接的结果然后通过 2 层神经网络来计算 *sᵢ的注意力分数。*第一集, m⁰ 换成了q
剧集的数量可以是固定的、预定义的数量,或者由网络本身确定。在后一种情况下,一个特殊的刀路结束表示被附加到输入中。如果这个向量被选通函数选择,那么迭代停止。
回答模块
答案模块由一个解码器 GRU 组成。在每个时间步,与问题嵌入连接的前一个输出作为输入。
使用词汇表上的标准 softmax 生成输出。
解码器通过 m 向量(来自情节存储模块的 GRU 计算的最后隐藏状态)上的函数初始化。
应用于情感分析
该模型在发表时达到了情感分析的艺术水平。
对于下面的例子,该模型关注所有的形容词,并且当仅允许 1 次通过时,最终产生不正确的预测。然而,当允许两次通过时,该模型对第二次通过时的正面形容词给予显著更高的关注,并产生正确的预测。
Analysis of Attention for Sentiment: [1]
在其他数据集上的性能
Source: [1]
Source: [1]
开关模块
模块化的一个重要好处是,只要替换模块具有正确的接口,就可以用另一个模块替换另一个模块,而无需修改任何其他模块。
论文“用于视觉和文本问答的动态记忆网络”展示了使用动态记忆网络来回答基于图像的问题。
输入模块被另一个使用基于 CNN 的网络从图像中提取特征向量的模块代替。如前所述,提取的特征向量然后被馈送到情节记忆模块。
Source: [2]
Source: [2]
Visual Question Answering Accuracy: [2]
Attention visualisations of answers to some questions: [2]
额外资源
参考
[1] K. Ankit,O. Irsoy,J. Su,J. Bradbury,R. English,B. Pierce,P. Ondruska,I. Gulrajani 和 R. Socher,随便问我:自然语言处理的动态记忆网络,(2016)。
[2] C .熊,S. Merity 和 R. Socher,视觉和文本问答的动态记忆网络,(2016)。**
一针延迟——对数据科学中最大的小问题的适度修复
对于科学家如何报告和重复使用结果,可以说没有标准。我们已经达成了一个务实的约定,但它存在严重缺陷。在这里,我建议一种新的和几乎通用的方法来提高报告结果的可重复性,而不需要额外的成本或努力。
当使用、发布和阅读统计数据时,很容易被欺骗。
不是出于故意或恶意,而是因为对复杂概念的误解和误用。
*尽管这也很容易——一个有才华的数据科学家可以让数字说出他们想说的任何话
今天,我想解决一个简单的概念和一个长期以来扭曲科学结果的误解,只是轻微的。
然后我想告诉你如何解决它,而几乎不用动一根手指。
我想花点时间来充分解释这篇文章的动机——但是对于那些在数据科学方面有经验的人来说,你可能想跳到猴子的图片来得到问题的结论和解决方案的陈述。
首先我们要问,什么是结果?
是什么将每份学术著作中的无数数字和图形分成结果。我认为,也许令人困惑的是,这完全不在作者的掌控之中。结果是被其他人使用的任何数字、图形或概念。
这就是为什么我们要小心谨慎的原因,作为作者,我们要清楚地区分结果,以及它们晦涩的表亲汇总统计数据。
汇总统计试图用尽可能少的数字来解释数据的分布、偏斜和形状——它们有助于作者展示和读者理解我们可能应用于任何数据集的指示性指标。它们并不试图描述数据的一般形式,只是一些相关的特征(例如,数据集的范围—最高值和最低值之间的差异—可能是有用的,但它不能告诉您这些值内的分布情况)。
我在这篇文章中提出的一切都适用于(或可能)被解读为结果的数字——这些数字试图代表所有数据的一般行为,可以放心地引用和重复使用。
结果是我们继承的数字。这些数字可能几十年都没有经过检验和检查。这些数字可以成为通用的说法并在全球传播。这些数字输入并影响着新的结果和新的思想,随着时间的推移不断涌现。
结果是交换的——它们是共享和给予的——我们需要知道我们所说的是公平的。
如果我们能够简单地、一般地(也许是普遍地)表达它们,那么其他人就更容易理解、评价它们并从中受益。
最少的信息中最真实的信息——我们如何用尽可能少的语言表达一些关于数据的有意义的东西?
A dataset which we might hope to describe, simply and briefly, with just a few numbers. Without intending to shame the authors or editors I shall not name the publication I’ve pulled it from (which is otherwise an excellent piece of work which this misstep barely dampens)
让我们从一个数据集开始,并从那里解释我们可能如何着手构建一个*结果,*以及不同方法的优点和危险。
左边的图片取自一份出版物。然而,让我们假设这三个面板来自我们所做的分析——让 1000 个人猜一个瓶子里有多少个球以及球的总重量。
每个人的答案可以被认为是 2D 平面上的一个位置——x 代表球的数量,y 代表重量。如果我们在每个人的 x,y 坐标上放一个大头针,我们会看到一些区域布满了大头针(希望在正确答案附近),而一些区域几乎是空的(就像如果有人认为有 10 个球,那么它就是一公吨)。
右下角的面板显示了他们猜测的密度——就像小山上的等高线——在大多数人猜测的区域上升到一个平滑的峰值。上面和右边的图分别是 x 和 y 各自的分布(虽然不太正确,但如果我们沿着 x 和 y 方向分割,你可以把它们看作我们的山的横截面)。
我们可以看到,人们对权重的看法相对一致——大多数答案都落在一个小区域内,并且在那个区域内,分布是均匀的。
但是,球的数量会引起更多的问题。人们倾向于高估比低估多得多的数量(想象三个连续的回答者猜测 10,100 和 1000)。有一个峰值——但它周围有一个不对称性。
正是在处理这种不对称时,当前的惯例出了问题。
总结数据的最常见方法之一是查看中位数(如果我们将所有数据按升序排列,值在中间)以及第 16 个和第 84 个百分位(值大约在有序列表的 1/8 和 7/8 处)。
为什么是这些数字?16–50–84*
*这恰好是我的分类代码
它们与每一位统计学家的老朋友都有关系——正态分布——这是一种近乎怪异的普适表示,描述了数据如何在峰值处分组,并围绕峰值均匀分布。这使我们能够只用两个值来很好地描述大量数据集——平均值(峰值)和标准差(分布)。
我们可以看到,将这个应用到上面的 y 值,我们会得到一个非常好的拟合。瞧——不错的*结果,*和只用了两个数字!(我的意思是,如果我们只写下两个数字——假设平均值为 1 千克,分布范围为 200 克——你可以画出一条曲线,这条曲线看起来与我们的数据非常相似,但你从未见过它)
因此,明智地将正态分布应用于适当的数据并恢复两个数字是一个好主意。如果你能做到,那就去做!
但是很多时候,就像我们的 x 数据一样,我们不能。这两个参数没有办法描述不对称,我们需要第三个。我们有很多选择,但我想列出 3 个——好的、坏的和丑陋的。
丑陋的(但实际上非常好的)方法——均值、标准差和偏斜
如果我们用湿沙做一个正态分布,然后倾斜它会怎么样?
我们会得到一个偏态分布,有两个不对称的尾部。如果我们向左倾斜沙堆,我们会得到负的偏斜(更多的分布高于平均值),向右倾斜会得到正的偏斜。
然而,我们仍然通过平均值和标准差来描述我们的数据,现在只是增加了一个额外的、深奥的参数。许多读者可能会对选择哪种偏斜是正的和负的皱起眉头,当他们被告知如何计算时更是如此。
有了这三个数字,我们几乎可以肯定可以重建 x 的分布——但是画出来却是一场噩梦。我们有所有需要的信息,但只是以抽象的形式——没有简单的错误栏,也没有明显的方法来引用和绘制结果。
这是一种非常好的做事方式,如果你喜欢那种方式的话,但它很丑陋,也不直观(尽管来吧)。
坏方法——16–50–84
我还没有兑现解释这些数字的承诺。让我们解决这个问题。
正态分布下 16%的区域位于平均值以下 1 个标准差的左侧。
正态分布下 84%的区域位于平均值上方 1 个标准差的左侧。
因此,如果我们有正态分布的数据,这两个数字,当与平均值比较时,告诉我们标准偏差。两次。
而当分布不是完全正态分布时,这两个数字告诉我们…什么都没有?
这里有一个基本问题——16 和 84(以及 50)是只与严格对称的正态分布相关的三个数字——然而我们试图用它们来描述一种不同的非对称分布。
我们衡量的东西和衡量的方式之间存在脱节。显然这两者之间有联系,但是从一个到另一个,我们必须采取一些非线性的步骤。这就像用种子的重量来衡量森林的生物量。那里有信息,但它被抽象成无用的。
为了更好地演示这一点,试着根据第 16、50 和 84 百分位值画出一个分布图。
如果你画的曲线介于 0 和一个无穷数之间,那你就没画对。这三个数字不足以约束曲线,并且与任何型号都不相关。
让那件事过去一会儿。
Hello grainy old friend
我们实验中 x 的分布就是一个很好的例子。这三条虚线显示的是 16–50–84%。
想象一下,拿走分布图,只留下那些——然后把这个图传给其他人,让他们解释这个分布图。
谁会看着这三条线,然后想把波峰放到左边。谁能猜出右边尾巴的长度。
如果给出结果,谁能够解释数据的真实形式。
在这一点上,你可能会想“是啊,这种方法太可怕了——为什么会有人这么做呢?”
或者你可能在想“是的,它并不伟大,但它完成了工作——不要捣乱”
第一个回应来自任何出于合理原因相信改变传统的人。
Sweden — shortly after the side of the road you drive on was legally changed
第二种人知道改变约定代价很高,会导致一段时间的混乱,通常不值得从解决一个小问题中获益。
这篇文章的标题提到了最大的小问题——这是一个小问题——可能只占百分之几的错误和误述。
显然有更好的方法,也有很多人使用,但几乎都有额外的成本。
- 你可以传递你的全部数据集——数据的完美表现,但是很沉重。它占用空间,需要时间和精力去寻找和整合,并且可能有作者很好理解但继承者可能永远不知道的细微差别。
- 您可以将您能想到的最佳模型拟合到每个数据集,这很好,但将曲线拟合到数据并不是一门完美的艺术,报告您的结果不仅需要陈述数字,还需要陈述所使用的分布以及得出分布的方法。
这两种方法都是完全合法且广泛使用的方法——但是它们需要大量的时间和精力。
16-50-84 的实用主义惯例继续存在的原因是它简单、快捷且易于理解。说明你做了什么,怎么做的,很简单。
务实的捷径惯例没有错,事实上,我认为它们通常比它们在准确性上的花费付出更多的红利(节省时间和精力)。
那么,如果我告诉你,有一种同样简单的方法(至少在计算复杂性方面)可以在任何数据集上工作,并给出很好地代表更广泛的数据形式的结果,会怎么样呢?
如果我试图提出一个新的结果报告的最低标准会怎么样?
好方法——直接计算分裂法线
在一轮关于模糊统计分布的公开测验中,分裂正态分布是比较容易回答的问题之一。它经常被发现、再发现和遗忘。如果你取两个不同的正态分布(每个都有自己的标准差),把它们切成两半,然后把它们错误地拼在一起,你就会得到这个结果。
- 包括我在内,直到我发现了一份 的伟大文件 详细记载了其他所有声称发现的人
The left-hand side has a standard deviation of 1, whilst the right-hand side deviation varies. When they are both equal we just have a normal normal distribution (which is what I’ve taken to calling it to reduce confusion)
发现它的原因是,它给出了一个有用的简单方法来描述不对称分布。在三个数字中,它映射出数据的模式*-它是峰值-以及数据从该模式的任一侧下降的速率。这三个数字是直接可见的(不像偏斜度),实际上给出了有意义的结果(不像 16–50–84)。
- 还记得你在学校学过这个吗,把它用在一个关于鞋码的问题上,然后就再也没听说过它了
它被遗忘的原因是它只有一点点用处——有很多其他分布也很适合,有些甚至有一些更令人羡慕的属性(虽然正态分布和对数正态分布在自然界中相对常见,但分裂正态分布本质上是人工的,虽然它可以很好地描述数据,但它永远不会是“完美的”)
然而,我在这里给你一个全新的优势,我认为它使分裂正态分布成为一个可行的替代品,作为结果报告的最低实用标准——我找到了一种方法使它可以直接计算。
通过直接计算,我的意思是您可以通过少量的基本数学运算(如平均值,只需要加法,或中位数,只需要对数据进行排序)来拟合数据的分裂正态分布,而不像其他方法,您必须通过尝试一系列不同的模型并找到最佳模型(如最大似然估计)来拟合数据。
我将把如何做到这一点的完整描述留给一个干燥机来源——我写的关于这个主题的论文。
这意味着寻找分裂正态参数与 16–50–84 百分位值一样简单,而且更具代表性。
那我们该怎么办?好吧,我的建议是开始使用它:)跟随那个链接,你会找到一个(非常基本的)python 脚本*,它可以对它建模、拟合并从中随机取样。
如果任何阅读的人知道如何将这样的东西放入 numpy(或 scipy library)中,那似乎是它的自然去处。
使用分裂法线总是很好的。这不是最优雅或最准确的解决方案,但它永远不会不起作用。
这一切都是为了降低获得更好工具的门槛,简化人们处理数据的方式,而不是使其复杂化。我不知道它是否会被采纳——或者是否还能提出更好的标准——但我真的希望这将有助于阻止其他人以后采用 16-50-84 的方法。
我建议任何感兴趣的人开始将这些价值观融入他们的工作中,而不是 16-50-84 方法中的 T1。两个相互竞争的标准只会让事情变得更复杂,这是为了让世界变得更简单(更准确)。
如果您这样做了,但确实想表明您对数据的处理有所不同,那么像这样引用您的值怎么样?:
对任何人来说都很容易阅读,但微妙地表明你正在使用这种约定。(并引用这个。如果你想——【https://doi.org/10.22541/au.155733227.75726722】T2
也许我说服了你,也许没有。每个人做任何事情都没有一个正确的方法。我对我认为做得不对的人的数量感到震惊——但这是一个非常主观的观点,即使如此,我也很少相信这使他们的工作或结论无效——这只是一个不幸的、普遍的、希望可以解决的问题。
俗话说,及时缝一针可省九针。这一针来得有点晚——也许只省了三四针。但是,任何微小的时间或准确性的节省,当在全世界制作、阅读和使用统计数据的人群中发挥出来时,都将拯救生命。
摆弄概念和工具。如果你认为还有更好的方法,请告诉我。重要的是,如果你是过去犯过这种错误的人,不要觉得自己被挑了出来(令人尴尬的是,我想我可能犯过)——这是一个进步的时代,而不是防御的时代。
如果你愿意,你可以在推特上找到我,在那里我倾向于发布关于不可穿越网络的神秘笑话,但有时也是关于其他科学的。
这很可能是一个不断发展的文档——我欢迎任何人的意见,如果你回来发现它被修改了,不要感到惊讶(希望是更好的)。你正在阅读的版本是最早的草稿。
一个关于我在一次单人滑雪比赛中获得第一枚金牌的故事:完成的事情和吸取的教训
或者一个关于伟大团队的故事
参加卡格尔比赛是一项严峻的挑战。你需要花费大量的时间和努力,学习新的东西,尝试很多花样才能得高分。通常这还不够,因为有很多伟大的人,他们有更多的经验,更多的空闲时间,更多的硬件或其他一些优势(也许他们甚至拥有所有的优势)。
以前我只能在比赛中获得银牌。有时是由于运气(在重组之后),有时是由于大量的工作。也有很多比赛我获得了铜牌(或者没有奖牌),尽管我花了很多时间在上面。
竞争描述
当我看到一个新的比赛在 5 月底开始,我立刻对它产生了兴趣。这是一场针对特定领域的竞赛,旨在预测分子中原子之间的相互作用。
这项挑战旨在预测原子之间的相互作用。核磁共振(NMR)是一种使用类似于 MRI 的原理来理解蛋白质和分子的结构和动力学的技术。
世界各地的研究人员进行核磁共振实验,以进一步了解分子的结构和动力学,涉及环境科学、制药科学和材料科学等领域。
在这个竞赛中,我们试图预测一个分子中两个原子之间的磁相互作用(标量耦合常数)。量子力学的最新方法可以计算出这些耦合常数,只要给定一个 3D 分子结构作为输入。但是这些计算非常耗费资源,所以不能总是使用。如果机器学习方法可以预测这些值,这将真正有助于药物化学家更快、更便宜地获得结构洞察力。
比赛的开始
我通常为新的 Kaggle 竞赛编写 EDA 内核,这次也不例外。当我在做的时候,我意识到这个比赛非常有趣和独特。我们有关于分子和它们的原子的信息,所以分子可以用图形来表示。Kaggle 竞赛中表格数据的常用方法是广泛的特征工程和使用梯度推进模型。
我在早期的尝试中也使用了 LGB,但是我知道应该有更好的方式来处理图形。这是相当迷人的,我决定认真参加这次比赛。
第一步
我没有领域知识(上次我关注化学公式是在学校),所以我决定从纯 ML 技术开始:大量的特征工程,创建出折叠元特征等等。像往常一样,我用内核发表我的作品。正如你在截图中看到的,他们很受欢迎:)
当时,这种方法在排行榜上给出了相当好的分数,我能够留在银区。
论与时俱进的重要性
真正帮助我的事情之一是阅读论坛和内核。从比赛开始到最后,我阅读了所有的内核和论坛帖子。它们包含许多有用的信息,否则这些信息可能会被忽略。甚至不太流行的内核也可以包含有趣的新特性。小线索可能包含洞察力,这可能有助于增加分数。
组建团队
几乎从一开始,我就意识到领域专业知识将提供一个重要的优势,所以我搜寻每一条这样的信息。当然我注意到有几个活跃的专家,他们在论坛上写文章,创造内核,所以我从他们那里读到了一切。
有一天,我收到了鲍里斯的电子邮件,他是这个领域的专家,认为我们的技能可以互补。通常我更喜欢一个人参加一段时间的比赛,但在这种情况下,联合起来对我来说似乎是个好主意。这个决定被证明是一个伟大的决定:)
合并方法
我们的方法在开始时非常不同:我做技术特征工程,Boris 致力于创建描述符。一段时间后,我们意识到我的模型在一些原子对类型上工作得更好,而他的模型在其他类型上工作得更好——所以我们为不同的类型训练了不同的模型。
我们很幸运还与菲利普·马戈利斯合作。不久之后,他的模型显示出比我们更好的结果。
我们团队的另一名成员成为了博扬,我们能够进一步提高我们的成绩。
他们真的是伟大的 ML 专家,在这场比赛中与他们一起工作是一次很棒的经历。
图形神经网络
当时我们已经看到了神经网络在竞赛中的潜力:著名的 kaggler Heng 贴出了一个模型的例子。
过了一段时间,我甚至能够在我的电脑上运行它,但结果比我们的 LGB 模型更差。然而,我们的团队知道,如果我们想要志存高远,我们就需要使用这些神经网络。
一些辩论确定了,因此我们邀请克里斯托夫加入我们的团队。看到他能够极快地构建一个新的神经网络,真是令人惊讶。很快我们停止了对 LGB 的训练,因为他们远远落后于克里斯托夫的神经网络。
神经网络时代
从那时起,我的角色变成了一个支持者。我用我们的神经网络做了很多实验:尝试各种超参数,不同的架构,对训练计划或损失的各种小调整等等。有时,我对我们的预测进行 EDA,以找到我们感兴趣或错误的案例,然后我们使用这些信息来进一步改进我们的模型。
我的主要贡献之一是寻找新的方法:
- 我翻阅了很多关于神经网络架构的论文:EAGCN、3DGNN 等很多;
- 我试过各种亏,比如胡贝尔。我甚至找到了一篇关于焦点损失回归思想的论文,但是实施起来并不可行;
- 当然,我尝试了像 RAdam 和 Ranger 这样的新的热门优化器,但是简单的 Adam 在我们的情况下更好;
- 和许多其他事情;
但最终是 Christof 实现了架构,这给我留下了非常深刻的印象和启发。
五金器具
好的硬件对于训练这些神经网络真的很重要。我们用了很多硬件,相信我,真的很多:)但是!我们还大量使用了 kaggle 内核:你可以同时用 P100 在 4 个 kaggle 内核中训练模型(现在只有 1 个),所以即使没有额外的硬件,我们也可以获得金牌。
结果和结论
我们的最终解决方案确保了我们的第八名和金牌。而我现在是 kaggle 大师:)
值得注意的是,我们的团队是能够获得比-3 lmae(各种类型平均绝对误差的对数)更好的分数的团队之一。在这个帖子中,竞赛主持人写道,他们会很高兴看到比-3 更好的分数,我们做到了!
我从这次比赛中学到了很多东西,下面我想分享一些经验:
- 看内核和论坛,他们提供了很多有用的信息;
- 做好做很多失败实验的准备。当你试图寻找下一个能提高你分数的新事物时,你会测试很多想法,但大多数都不会奏效。不要气馁;
- 总是寻找新的想法,阅读新的论文和文章。你永远不知道你会在哪里找到一个新的很酷的工作想法;
- 创建一个团队将使用的验证,以便实验具有可比性;
- 一个伟大的团队由拥有不同技能的人组成,他们应该涵盖不同的领域;
- Kaggle 比赛很有趣,尽管很累:)
我很幸运能和这些了不起的人一起工作,为此我要感谢他们!
机器讲的故事
艾写作的迂回之路
德克·克内梅尔和乔纳森·福利特
Figure 01: Our languages and our writing mirror the societies in which we live.
[Illustration: Saint Jerome Writing by Hans Springinklee German, 1522 woodcut, National Gallery of Art, Open Access]
你可能没有意识到,但人工智能已经在编写你可能已经读过的故事了。多年来,股票简介都是由机器编写的。最近,小联盟体育比赛总结也已经。接下来是长篇故事和小说吗?在加州大学圣克鲁斯分校,人工智能研究员 Snigdha Chaturvedi 和她的团队正在设计自然语言处理模块,有朝一日将使机器能够讲述长篇叙事故事。虽然目前这项技术令人印象深刻,但离这个目标还有很长的路要走。通过他们的研究,我们可以开始更好地理解自然语言生成技术将如何成为我们生活的一部分。
Figure 02: AI is already writing stories that you’ve probably read, like minor league sports game summaries.
[Photo: “Base hit” by Chris Chow on Unsplash]
语言是一面镜子
如果我们试图标记迄今为止人工智能写作的进展,我们会发现自己处于恐怖谷阶段——至少在涉及比股票广告或棒球统计数据更复杂的故事时。就像长相接近人类的机器人,其怪异的美学令人反感,人工智能写作同样可以表现为不太像人类,粗糙,有时古怪或跑题。对于人工智能研究来说,语言是如此具有挑战性的领域,原因有很多。
“语言是我们生活的社会的镜子,”查图维迪说。“所以,问题是当计算机科学家设计试图理解语言的算法时,他们通常不会考虑语言理解的社会方面。人类说的或做的大多数事情都由两个标准来定义:他们的个性和他们与他人的关系。”
查图维迪解释说:“人与人之间的这种关系在解释他们的行为和言语方面起着非常重要的作用。”。“如果你理解关系,你就能更好地解释人类行为。由于语言只是人类世界的反映,这将有助于理解语言。”所有这些因素都与上下文相关——这是人工智能努力解决的问题,至少在当前的实例化中是如此。人工智能在特定的专业领域可以无情地有效——例如破解国际象棋、围棋和扑克等游戏。在这些场景中,背景问题几乎无关紧要。粉碎这些竞争策略游戏的人工智能通常甚至不考虑对手。这只是看着瞬间的快照,以数学上最佳的方式行动。从计算和战略的角度来看,这是很难做到的,因为人脑基本上无法做到这一点。然而,人类擅长理解背景。如果人工智能要实现其拥护者为其设想的潜力,它必须在这一领域取得进展。
Chaturvedi 说:“在模拟或理解人际关系方面已经有了一些工作,但这是有限的。“这项工作面临两个主要挑战。第一个是超越了自然语言处理中大多数先前科学工作中使用的二元关系的主导概念。在这种二元关系的范例中,您假设关系只能有两种类型。例如,处理脸书等社交媒体数据的人会假设用户要么是朋友,要么不是。所以只有两种可能。因此,这些关系的二元性质。他们没有对人际关系做出更微妙的假设。这是因为从计算的角度,从自然语言处理的角度来看,发展这个微妙的概念更具挑战性。但是如果你想想现实世界的关系,它们并不是二元的。真实的社会关系可以有多个方面。例如,两个人可以是朋友或家庭成员,或者他们可能处于浪漫的关系中。他们可能是正式或非正式的关系。查图维迪说:“人们可能处于监督-被监督的关系中,等等。
二进制对工程师开发计算技术有重大影响。从某种意义上来说,用 1 和 0 来思考是一切开始的地方。二进制模式继续渗透到软件的行为方式中,比如查图维迪在脸书发现的粗糙的关系框架。真正的关系,其中存在一些意义和理解,要微妙得多,这又回到了问题的难度:不仅我们的各种关系是微妙的和非二元的,每个人的关系,以及他们独特的关系星系,可以与下一个人大相径庭。一刀切的方法不太可能让任何人满意。真正的理解至少需要更大的关系世界的背景和细微差别,以及一个人更小的独特世界的背景和细微差别。还有其他的问题:“这项工作的另一个主要挑战是融入人类关系的进化或变化的本质。想想看,人际关系不是一成不变的,而是随着时间而变化。例如,你七岁时的朋友可能与你现在的朋友大不相同。这在分析故事时甚至更为重要,因为各种角色之间关系的变化使故事变得有趣,”查图维迪说。
语境的挑战:这个故事如何结束?
那么,你如何开始解决人工智能讲故事的背景问题呢?Chaturvedi 和她的团队承担的一个研究领域是帮助机器识别一个故事的好结局。“我们试图解决的技术问题是,你有一个故事和两个结局选项,但两个选项中只有一个是正确的或更符合逻辑的,而另一个只是一个糟糕的结局。“对人类来说,这是一个非常容易解决的问题,”查图维迪说。“人类真的很擅长辨别两种结局中哪一种更合理,因为另一种选择在大多数情况下都是荒谬的。在这个项目中,我们希望看到计算机系统或人工智能算法识别明智的选择有多容易。如果计算机可以解决这个问题,这将意味着它对文本连贯性和常识性知识有所了解,以及是什么让技术变得有意义,等等。所以,事实证明,设计这样一个人工智能系统并不是一个容易的问题。”
这是一个明显的构建模块,首先,机器以某种有意义的方式开发理解故事的能力,然后潜在地开发它们自己的故事。不用说,这对写作专业人士来说意义重大。“所以这是一个具有挑战性的研究问题,因为识别好的或合理的结尾需要理解是什么让一段文字像一个故事一样连贯或合理,”查图维迪说。“如果你仔细想想,这是一个非常开放的领域问题。例如,很难雇佣一个能够写出所有规则来告诉我们是什么让一段文字连贯的人。这可能是因为我们作为人类,甚至不知道当我们判断一段文字是否连贯时,我们会考虑哪些因素。”
为了评估连贯性,Chaturvedi 和她的研究小组考虑了三个因素。首先,故事的结尾需要遵循事件的逻辑顺序。第二,完整的故事必须有一个合理的情感轨迹——发生在主角身上的事情必须有意义。最后,结尾需要和故事的主题一致。“我们提出了一个系统,可以将所有这三个因素缝合在一起……并判断一个结局是否与故事相符,”查图维迪说。“我对这个项目非常兴奋,因为它给了我一个思考文本连贯性和故事的机会。这促使我致力于一个更具挑战性的问题,即设计人工智能系统来生成完整的故事。”
Chaturvedi 描述了该团队研究的下一步:“我们正在尝试让机器与人类合作来生成一个短篇故事。所以,本质上,故事是由机器生成的,但人类是与机器合作或引导它生成特定类型的故事。从研究的角度来看,自动讲故事通常是一项非常具有挑战性的任务。它要求人工智能系统不仅能说出好的、语法正确的英语句子,而且它们必须结合在一起,形成一个连贯的故事。生成的故事需要主题一致。它应该有一个有趣的情节,有目标的人物,规则,关系等等。这个故事应该有情感流动。它应该有特定的道德价值,特定类型的结局,等等。换句话说,故事生成需要大量的规划和思考。这些挑战已经吸引了人工智能专家非常非常长的时间。”
“最近,人们对讲故事重新产生了兴趣,尤其是在自然语言处理领域,出现了一种称为深度学习算法的学习算法。这些更新、更好的算法的问题是,它们比传统的自然语言处理生成系统更难控制。在我们的工作中,我们希望通过让人类用户参与进来,对商店的再生过程有更多的控制。更具体地说,用户会告诉系统,他们希望看到故事后面发生的特定事情,系统必须一次一句地生成故事。这类似于在 Bandersnatch 中非常成功的互动讲故事的想法,这是在网飞播出的黑镜集。”
AI 和伟大的计算小说
2016 年,未来大学函馆分校的松原仁史(Hitoshi Matsubara)带领团队与人工智能合作开发了一部中篇小说,通过了日野新一文学奖的第一轮评审。法官 Satoshi Hase 认为这部小说结构良好,但其他方面有所欠缺,如人物描述。这部名为《电脑写小说的那一天》的中篇小说,是根据丹尼·刘易斯(Danny Lewis)为史密森尼杂志(Smithsonian Magazine)撰写的报道,使用以下过程写成的:首先,人类设计师写了自己的中篇小说,并将其提炼为基本组成部分:单词、句子和基本结构。基于这些参数,计算机使用一种算法从原始作品中重新混合出一部新的中篇小说。例如,它与在我们的短信中建议自动完成的技术重叠。显然,考虑到这种基本的方法,我们离竞争主要文学奖的机器还有很长的路要走。我们更多地处于工具开发阶段,在这个阶段中,应用程序不仅与让我们眼花缭乱的输出相差甚远,而且甚至不能以对实际训练有素的作者特别有用的方式运行。
Figure 03: We are a long way away from machines competing for major literary prizes. We are more in the tool development stage.
[Photo: “Library at Orchard, Singapore” by Fahrul Azmi on Unsplash]
一般来说,人工智能系统不擅长生成长文本。在最好的情况下,他们可以创建少量的内容,这些内容与故事中先于它的现有内容是一致的。然而,人工智能顺序生成的文本越多——它们的原始文本离它自己生成的内容之前的设定叙事越远——它就变得越不连贯。它似乎更像一个智能句子生成器,而不是一个作家。
“我们正在使用基于深度学习的系统,这些系统因理解起来非常复杂而臭名昭著。在很高的层面上,深度学习模型[是]数学表示的复杂集合,如矩阵和向量,它们相互作用,给你想要的输出。Chaturvedi 说:“虽然这种复杂性使它们变得非常强大,但数学表达方式甚至让人类专家或科学家都难以破译该系统到底是如何工作的。“现在,由于我们不了解这些模型是如何工作的,命令它们做一件特定的事情变得越来越困难,就像指示它们生成特定的故事情节一样。在我们的工作中,我们通过为这一信息提供一个特定的重要组件来引导模型包含人工监督。所以,本质上,主要的技术挑战是你如何教这些系统注意用户在说什么,用户希望故事中发生什么?他们在创作故事的时候是如何整合这些信息的?”
这是深度学习模型呈现的另一个更普遍的限制——甚至是风险。我们人类无法理解它们,也无法对它们进行逆向工程。他们的力量和潜力通过在大量数据上放松来创造他们自己的模型而被释放。但它把引擎变成了某种黑匣子,我们只有有限的机构去理解,更不用说在某些方面去调整了。不像过去的物理或机械系统,甚至更传统地由人类编写的软件,我们并不完全了解正在发生什么。
人工智能写作的应用
目前用于撰写金融或体育报道的人工智能系统在本质上是有限的,至少目前如此。Chaturvedi 说:“有几家公司对自动识别新闻故事、新闻稿文档等中的关键事件感兴趣,并将其转换为故事,以便人类或算法读者可以使用。”“这个过程基本上有两个步骤。第一步,训练一个人工智能模型,从新闻稿和此类文档中自动提取相关事件。不幸的是,这些人工智能系统的输出…不一定是一种好的、自然的格式。它通常以表格的形式呈现,可以方便地存储在数据库中,但不一定以易读的方式传达全部信息。因此,第二步是将这些表格状的事件数据转换成看起来自然的英语句子或故事。这是目前商业人工智能系统不擅长的一步,在这个过程中需要大量的人工努力。”
这些故事是使用模板生成的。“你可以把模板想象成人工或半自动生成的句子或带槽的短篇故事。机器的工作是获取一个模板,但是它必须选择一个与它工作的上下文相关的模板。一旦它选择了模板,它的任务就是用相关的类似素材的事件填充这些槽。”这些刻板的模板通常不能产生流畅的、像人类一样的散文:例如,至少就目前而言,它们不能意译。正因为如此,这种模板化的人工智能故事通常类似于复制粘贴的文本。“在实践中,当这些系统输出基于模板生成的文本时,人类进入系统并平滑内容,”Chaturvedi 说。
人工智能书写系统具有大量市场应用的潜力。Chaturvedi 说:“专业作家可以利用它们来获得关于他们下一部创作作品的想法。“你可以想象出更多类似的电影,但它们会在艾的帮助下制作,而不完全是人类作家写的。它们也可以用来改进现有的电脑游戏。这种系统的交互性质可以使它们在培训和教育领域非常成功。例如,你可以用这样的系统来教孩子们语言连贯和讲故事。人工智能生成的故事也可以用来帮助记者制作新闻故事。”
因此,虽然今天人工智能写作的艺术水平仍然很粗糙,但 Chaturvedi 看到了一条前进的道路,在那里生成的文本将得到很大的改善。这是否意味着有能力的小说不会很快由人工智能产生?“那需要一些时间。目前,系统通常试图生成短文本,并且这些文本限于特定类型的领域。对于生成更长的故事,我认为我们可能需要等待几十年才能拥有完全由人工智能系统生成的故事和由人工智能系统生成的小说,”Chaturvedi 说。“问题是,当人类写长文档时,比如小说,他们在头脑中为文档准备了一个叙述计划或故事情节。Chaturvedi 说:“当他们写一个句子时,它是在他们刚刚写的上下文中,以及他们对整个文档的想法中。这一切都回到了背景的挑战。机器甚至不能记住之前整个故事的背景,甚至不能记住它自己写的故事的整个部分。
Figure 04: One day, maybe sooner than we think, AI-based generation systems will enable amateur writers to express themselves in a professional manner, making it possible for essentially everyone to be a writer.
[Photo: “Weathered books” by Syd Wachs on Unsplash]
然而,Chaturvedi 设想了一个实际的未来,这种人工智能研究将发展为创意专业人士提供有用的工具,即使小说写作还有很长的路要走。“人工智能写作肯定会让职业作家的工作轻松很多。它不仅会在某些内容不正确、含糊不清或难以阅读时提供建议,还会为作者提供创造性的想法,帮助他们清除写作障碍。”有一天,也许比我们想象的更快,基于人工智能的生成系统将使业余作家能够以专业的方式表达自己,使基本上每个人都成为作家成为可能。此外,在新闻等领域,这种人工智能系统将能够大大减少记者的工作量,使他们能够专注于收集事实和有新闻价值的材料。Chaturvedi 说:“这也肯定有助于他们加快撰写报道的过程,为用户提供更多的实时新闻。”
Creative Next 是一个播客,探索人工智能驱动的自动化对创意工作者,如作家、研究人员、艺术家、设计师、工程师和企业家的生活的影响。本文伴随 第二季第四集— AI 与增强讲故事 。
微妙的闺蜜特质:通过 Spotify 和网飞了解你的闺蜜
Credit to Kaleb Bruel — Head of US Consumer Marketing @ Spotify
Spotify release 2019 年结束的时候已经是年底了。我惊讶于我的播放列表在全球范围内的流派和艺术家的变化。两年前我可以不停地听音乐歌曲,但今年我的音乐品味变成了流行和民谣。受 Spotify Wrapped 的启发,我决定做一个有趣的分析,不仅对我自己,也对我朋友的音乐品味进行分析,以弄清楚这些数据会给我们带来什么。
除了音乐,通过分析我们在网飞的观影历史,我很好奇我们的电影品味有多相似。通过了解这些细微差别,我可以节省决定看哪些电影或听哪些歌曲的时间,并在我们共度时光时更好地推荐我们的共同兴趣。
是的,像其他亚洲朋友团体一样,我们分享每一个订阅账户,包括 Spotify 和网飞·😄
你可以在这里找到我的 Github repo 的链接:
Spotify release 2019 结束时是年底。我惊讶于我的播放列表在流派和艺术家方面的变化…
github.com](https://github.com/giginghn/spotify-netflix-analysis)
概述
- 数据收集
- 数据分析
- 机器学习方法
- 结论
数据收集
- Spotify:
为了阅读 Spotify API,我需要通过他们的开发者网站申请许可和证书。然后,我在 R 中使用了一个由 Charlie Thompson 开发的名为 spotifyR 的包装函数,从我和我朋友的 10 个最受欢迎的艺术家中提取所有专辑和歌曲。
初始数据包含 22 列,其中 595 首歌曲来自我的列表,714 首歌曲来自桑的列表。然而,重要的是承认我没有使用所有 22 个变量,而只是使用了与音频功能高度相关的变量——根据 Spotify:
-
情绪:可跳性、效价、能量、节奏
-
属性:响度、语音、乐器性
-
语境:活跃度,声音
这些功能的解释如下:
- Acousticness :一个从 0.0 到 1.0 的置信度度量,表示音轨是否是声学的。1.0 表示音轨是声学的高置信度。
- 可跳舞性:可跳舞性描述了一首曲目在音乐元素组合的基础上适合跳舞的程度,包括速度、节奏稳定性、节拍强度和整体规律性。值 0.0 最不适合跳舞,1.0 最适合跳舞。
- 能量:能量是一个从 0.0 到 1.0 的度量,代表强度和活动的感知度量。通常,高能轨道感觉起来很快,很响,很嘈杂。例如,死亡金属具有高能量,而巴赫前奏曲在音阶上得分较低。对该属性有贡献的感知特征包括动态范围、感知响度、音色、开始速率和一般熵。
- 乐器性:预测一个音轨是否不包含人声。“Ooh”和“aah”在这种情况下被视为乐器。Rap 或口语词轨道明显是“有声的”。乐器度值越接近 1.0,轨道不包含人声内容的可能性就越大。高于 0.5 的值旨在表示乐器轨道,但随着该值接近 1.0,置信度会更高。
- 活跃度:检测录像中是否有观众。较高的活跃度值表示音轨被现场执行的概率增加。高于 0.8 的值很有可能表示该音轨是实时的。
- 响度:音轨的整体响度,单位为分贝(dB)。响度值是整个轨道的平均值,可用于比较轨道的相对响度。响度是声音的质量,是与体力(振幅)相关的主要心理因素。值的典型范围在-60 和 0 db 之间。
- 语速:语速检测音轨中是否存在口语单词。越是类似语音的录音(例如脱口秀、有声读物、诗歌),属性值就越接近 1.0。高于 0.66 的值描述可能完全由口语单词组成的轨道。介于 0.33 和 0.66 之间的值描述可能包含音乐和语音的轨道,可以是分段的,也可以是分层的,包括说唱音乐。低于 0.33 的值很可能代表音乐和其他非语音类轨道。
- 效价:从 0.0 到 1.0 的一个量度,描述一个音轨所传达的音乐积极性。高价曲目听起来更积极(例如,快乐、愉快、欣快),而低价曲目听起来更消极(例如,悲伤、沮丧、愤怒)。
- 速度:轨道的整体估计速度,单位为每分钟节拍数(BPM)。在音乐术语中,速度是给定作品的速度或节奏,直接来源于平均节拍持续时间。
2.网飞:
我在这里下载了我们 2019 年内的观看历史,并与 Imdb 数据集合并,提取电影属性和特征。
网飞数据集的一个缺点是它不记录重复的活动。所以如果我在 2019 年 12 月看《奇怪的事》,我在 6 月看的同一集会被 12 月的那集取代。
我最初从 Imdb 下载了 3 个数据集,每个数据集都包含电影的独特属性。出于分析目的,我将所有这些孤立的数据集集成为一个,并且只保留最重要的特征:
- 类型 —该备选标题的枚举属性集。以下一项或多项:备选、dvd、节日、电视、视频、工作、原创、imdbDisplay。将来可能会在没有警告的情况下添加新值
- 运行时间分钟 —标题的主要运行时间,以分钟为单位
- 类型 —包括多达三种与标题相关的类型(纪录片、戏剧、喜剧、电视剧、真人秀、犯罪、动作、冒险、惊悚等)。)
- 平均 —所有个人用户评分的加权平均值
- numVotes —标题获得的票数
数据分析
- 音乐分析
柱状图和雷达图都表明我们在音乐上有非常相似的品味,但是,我的歌有更多的声音,舞蹈性和效价(积极),而他的歌更活泼,更有活力,更有乐器感。这证实了我在分析之前的假设,因为当我喜欢听独立音乐和民谣时,桑的音乐品味一直是越摇滚和音乐。其实我们的歌都是很高能的,暗示了我们对流行歌曲的共同品味。
速度和响度也和旋律、和声或节奏一样重要,因为它们代表了歌曲的速度和力度以及它所承载的情绪。
比如一首歌的 BPM 和 dB 越高,这首歌的节奏越快,越强劲,就越趋于刺激和欢快。另一方面,低 BPM 和 dB 意味着歌曲速度较慢,暗示悲伤、戏剧或浪漫。
从上面的图表中可以看出,我们的播放列表的速度都接近 120 BPM,平均响度接近-9 dB,这表明速度快且充满活力。这再一次证实了我的期望,因为我们的前 10 名艺术家中的一些人有我们在锻炼或健身房中不断重复的歌曲。
我也对我们选择音乐的多样性感到好奇。为了利用数据集中的这个因素,我计算了标准偏差,然后计算了所有标准偏差的平均值,以获得能够代表我们播放列表多样性的数字。
从上面的条形图可以看出,桑的播放列表往往比我的更多样化。通过下面的图表,我们可以更深入地了解每个功能的多样性:
发现这些音频变量之间的线性关系也很有趣。
根据线性回归分析,当化合价增加 1 个单位时,能量和可跳舞性都增加大约 1.2 个单位。如果我们仔细观察桑的特征,他的歌曲即使在低价位也具有高能量,而我的播放列表在价位增加时具有显著更高的可跳性。
现在我们可以理解我和我朋友的音乐品味之间的细微差别,让我们直接进入我们对电影的选择。
2.电影分析
根据上面的柱状图,我和桑都喜欢电视剧,但是他比我更喜欢短片。事实上,我们的电影品味非常相似,因为我们都喜欢纪录片、喜剧、惊悚片、动作片、爱情片和剧情片。如果我们仔细看看,桑的电影列表在类型上又一次比我的更多样化。
平均来说,我们欣赏的电影评分在 7.0 到 8.0 左右,但根据 Imdb,我们的电影有多受欢迎呢?《冒险》是桑的热门电影,而我的惊悚片是 Imdb 上最受欢迎的。我们俩都喜欢动作片和戏剧类的电影。
现在,我们已经对数据有了一些有意义的了解,我想在预测应用方面更进一步。
机器学习方法
我们知道我和桑在音乐和电影方面的品味的差异和相似之处,那么什么是最有预测性的特征,可以准确地将一首歌或一部电影归类为更有可能被我选中或演唱?
为了找到最具预测性的特征,我们将计算所有预测变量的特征重要性。有两种常见的特征重要性模型——随机森林和 XGBoost。
在这个特定的问题中,我将对 Spotify 和网飞数据集应用随机森林分类器,因为它们都存在共线性问题。共线性是指某些独立变量高度相关的情况,这可以通过在 Python 中可视化相关图来检测。
选择 Random Forest 而不是 XGBoost 的原因是:
- 当有几个相关的特性时,XGBoost 倾向于选择一个并在几个树中使用它,这样其他相关的特性就不会被经常使用。因此,其他相关特征在分割过程中不再有帮助,并且它们不会带来关于已经使用的特征的新信息。
- 而随机森林中的每棵树都不是由相同的特征构建的,因为每棵树都有随机选择的特征。因此,每个相关特征可能有机会在树之一中被选择。因此,学习是并行进行的,所以每个树都不知道其他树使用了什么。
在发现协变量后,我们将尝试不同的机器学习模型,看看哪一个具有最佳性能,然后我们可以在该模型上进行优化。
- Spotify 数据
我们可以看到,声音、舞蹈性、能量、响度、活跃度、效价和节奏是歌曲分类的最具预测性的特征。
对于这个预测问题,我用分类算法来预测一首歌会被我听还是被唱。在平衡数据并将其分成训练集和验证集之后,我使用了 3 个模型:随机森林、逻辑回归和线性判别分析。
为了评估模型的性能,我决定访问 5 个核心指标来对每个模型的质量进行评分:准确性、精确度、召回率、F1 和 AUC。
从指标和 ROC 曲线可以看出,逻辑回归在 3 种算法中表现最好。但是,可以更好!然后,我将对逻辑回归进行超参数调整,看看模型是否可以改进。
为了优化这个模型,我将使用带有不同正则项的网格搜索来调整这个模型。
random.seed(123)#train test split
X_train_logit, X_test_logit, y_train_logit, y_test_logit = train_test_split(os_data_X, os_data_y, test_size=0.4, random_state=0)#generate random grid with l2 penalty
grid={“C”:np.logspace(0.01,0.001,10,100,1000), “penalty”:[“l2”]}# l2 ridgelogreg=LogisticRegression(solver=’lbfgs’)
logreg_cv=GridSearchCV(logreg,grid,cv=5)
logreg_cv.fit(X_train_logit,y_train_logit)#choosing the best parameters
logreg_cv.best_params_,logreg_cv.best_score_
然而,即使在调优之后,该模型也没有显著的改进。为了简单起见,我们可以将原始模型作为性能最好的模型。
2.网飞数据
从上面的特征重要情节可以清楚地看出,( 1)动作片、冒险片、喜剧片、纪录片、电视剧、真人秀是最具预测性的类型,( 2)电视剧是最具标题类型预测性的类型,( 3)平均评分和投票数是最具预测性的协变量,用于对哪部电影可能被我或桑观看进行分类。
同样,我将使用分类算法来预测一个移动是否会被我或桑观看。在上采样以平衡数据并将其分成训练集和验证集之后,我使用了两个模型:随机森林和线性判别分析。
为了评估模型的性能,我将再次应用 5 个核心指标对每个模型的质量进行评分。
从指标来看,随机森林分类器显然是赢家。AUC 分数为 65.8%,准确性分数为 65.5%,该模型在仅使用默认参数的测试集上表现相当好。我仍然相信这个模型可以通过超参数调整得到进一步改进。
我将再次应用网格搜索来寻找模型优化的最佳参数。
# Number of trees in random forest
n_estimators = [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)]# Number of features to consider at every split
max_features = [‘auto’, ‘sqrt’]# Maximum number of levels in tree
max_depth = [int(x) for x in np.linspace(10, 110, num = 11)]
max_depth.append(None)# Minimum number of samples required to split a node
min_samples_split = [2, 5, 10]# Minimum number of samples required at each leaf node
min_samples_leaf = [1, 2, 4]# Method of selecting samples for training each tree
bootstrap = [True, False]# Create the random grid
random_grid = {‘n_estimators’: n_estimators,
‘max_features’: max_features,
‘max_depth’: max_depth,
‘min_samples_split’: min_samples_split,
‘min_samples_leaf’: min_samples_leaf,
‘bootstrap’: bootstrap}#train test split
X_train_rf, X_test_rf, y_train_rf, y_test_rf = train_test_split(os_data_X, os_data_y, test_size=0.4, random_state=0)# Use the random grid to search for best hyperparameters
random.seed(123)# Create the base model to tune
rf = RandomForestRegressor()# For random search of parameters, using 5 fold cross validation,
# search across 150 different combinations, and use all available coresrf_random = RandomizedSearchCV(estimator = rf, param_distributions = random_grid, n_iter = 30,cv = 5, verbose=2, random_state=42, n_jobs = -1)# Fit the random search model and select the best param
rf_random.fit(X_train_rf, y_train_rf)
rf_random.best_params_, rf_random.best_score_
当我应用调整后的参数时,性能有了显著的提高,尤其是在精度方面,提高了 7.69%。
结论
通过探索性的数据分析和机器学习分析,我发现了自己的音乐和电影品味,同时更多地了解了朋友喜欢的流派。
据此,我可以断定,无论是歌曲还是电影,他的榜单都比我更加多元。此外,我的歌曲意味着更多的声音,舞蹈性和效价(积极),而他的歌曲更活泼,更有活力和乐器。另一个见解是,当我反复重复电视节目时,桑更喜欢短片。
为了更深入地进行分析,我找到了最具预测性的特征,这些特征可以准确地将一首歌或一部电影分类为更有可能被我选择或演唱,并相应地将其输入机器学习模型。在尝试了不同的模型来预测歌曲是否会出现在我或桑的播放列表中之后,表现最好的模型是逻辑回归。另一方面,对电影列表进行分类的最佳模型是具有调整参数的随机森林。
总的来说,我对我的发现非常满意,希望我的分析能够有意义,并对预测网飞和 Spotify 上共享帐户的歌曲或电影产生影响,以进一步改善用户体验!
参考: