无监督数学评分模型
释放数学模型的力量
一个数学模型是使用数学方程对一个系统的描述。该系统由一组数学方程控制,这些方程可以是线性的、非线性的、静态的或动态的。该模型可以从可用数据中学习方程的参数,甚至预测未来。
在这篇博客中,我将讨论一个这样的实用数学模型,它可以在缺乏带有一些领域知识的标记数据的情况下用于各种问题。本博客中使用的所有代码和数据集都可以在这里找到。
我们的数学模型:逻辑函数
逻辑函数俗称 Sigmoid 函数 是一种具有特征“S”形曲线或 sigmoid 曲线的数学函数。
逻辑函数可以取-∞到+∞ 源之间的任何 x 值
在哪里,
X₀ =乙状结肠中点的 x 值
L =曲线的最大值
k =曲线的逻辑增长率或陡度。
逻辑函数可以取-∞到+∞之间的任何 x 值。对于 x 接近+∞,f(x)接近 L,对于 x 接近-∞,f(x)接近 0。
标准 sigmoid 函数返回 0 到 1 范围内的值。该等式由下式给出
Sigmoid 可以取-∞到+∞之间的任何 x 值来源
对于 x = 0,S(x=0) = 0.5
x < 0, S(x<0) < 0.5 and x > 0,S(x>0) > 0.5
所以,Sigmoid 函数是以 0 为中心的。
来源:维基
问题陈述
我们有客户的财务数据。其中一个特征是信用额度,即客户名下的信用额度。现在,根据信用额度,我们打算生成一个介于 0-1 之间的风险评分。
客户和现有信贷金额数据的快照
在不同的数据集和不同的要素中,数据的分布会有所不同。我们来看看 credit_amount 的分布。
贷方金额直方图
credit_amount 向右倾斜。在不同的数据集和用例中,数据的偏斜度或分布可能会有所不同。
我们希望提出一个评分机制,更多地惩罚离群值。
在我们的例子中,我们将提出一个理想的行为,并尝试学习最能模拟理想行为的逻辑函数的参数。让我们定义一下理想行为:
- 风险分值在 0 到 1 的范围内。
- 数据以第 65 个百分位为中心。(假设,因为我们希望更多地惩罚异常值)
- 理想情况下,我们希望第 65 百分位的分数为 0.50,第 75 百分位的分数为 0.65,第 80 百分位的分数为 0.70,第 85 百分位的分数为 0.75。对于其余的数据,我们希望分数有相应的变化。
- 不同的特征可能具有不同的分布和范围,因此我们希望提出一种技术,能够学习逻辑函数的参数,以匹配步骤 3 中定义的理想行为。
对于我们使用逻辑函数为 credit_amount 定义风险分值的问题,让我们解码参数。
逻辑函数可以取-∞到+∞ 源之间的任何 x 值
在哪里,
X₀ =乙状结肠中点的 x 值
L =曲线的最大值
k =曲线的逻辑增长率或陡度。
因为我们希望风险分值范围在 0 到 1 之间,所以 L = 1。
因为我们希望逻辑函数以第 65 个百分点的数据为中心,所以 X₀ =信用额的第 65 个百分点
增长率 k,我们将通过随机搜索来学习,它可以从步骤 3 中定义的理想行为中以最小的均方误差最佳地模仿理想行为。
# Logistic function ~ b denotes X₀ and c denotes k(growth rate)
def sigmoid(x,b,c):
return 1 / (1 + math.exp(-c * (x-b)))
可能增长率“k”的计算误差
# Mean Squared error between ideal and observed behavior
# b denotes X₀ and c denotes k(growth rate)
def cal_error(c,pcts,values_expected):
error = math.pow(sigmoid(pcts[0],pcts[3],c) - values_expected[0],2) + math.pow(sigmoid(pcts[1],pcts[3],c) - values_expected[1],2) + math.pow(sigmoid(pcts[2],pcts[3],c) - values_expected[2],2) + math.pow(sigmoid(pcts[3],pcts[3],c) - values_expected[3],2)
return error
随机搜索以找到最佳“k”,增长率
def find_best_decay_parameter(pcts,values_expected):
best_error = 999999
best_c = 1.0
iterations = 5000
for i in range(iterations):
tmp = random.random()
error = cal_error(tmp,pcts,values_expected)
if error<best_error:
best_error = error
best_c = tmp
return best_c
调用函数
percentiles = [85,80,75,65]
values_expected = [0.75,0.70,0.65,0.50]
b,c = find_decay_parameter(df.credit_amount,values_expected)
输出
Best value of Growth rate 'k' = 0.00047
Value of L = 1
value of X₀ = 3187
**65th 75th 80th 85th**
**Value 3187 3972 4720 5969**
**Expected Score 0.50 0.65 0.70 0.75
Observed Score 0.50 0.59 0.67 0.79**
我检查了分数是如何随着不同的信用额度而变化的
credit_amounts = [100,500,1200,3000,4000,5200,6000,7500,10000,12000,20000,25000]
risk = []
mp_values = {}
for credit_amount in credit_amounts:
mp_values[credit_amount] = round(sigmoid(credit_amount,b,c),2)
输出:
不同信用额度的观察风险评分
信用金额的风险分值在 0 到 1 范围内的变化
找到参数“l”、“‘X₀’”和“k”的正确值后,我们拟合了一个数学模型,使风险得分接近我们想要的理想得分行为,即更多地惩罚异常值。
提高
在上一节中,我们看到风险评分是一个变量的函数,即 credit_amount。但是,如果我们有不止一个变量,并且我们希望风险分数是所有这些变量的函数,那该怎么办呢?
在这种情况下,我们可以首先找到每个变量的权重/重要性,使得权重总和为 1。然后,我们可以为每个变量拟合一个单独的逻辑函数,最后对个体风险评分进行加权求和。
让我们以 3 个变量及其风险分值和权重为例。
变量和风险分数
变量和权重
最终风险得分= 0.72 * 0.3+0.65 * 0.25+0.81 * 0.45 = 0.743
结论
通过这篇博客,我们了解了什么是数学模型,并使用逻辑函数研究了一个这样的数学模型。这种模型可以在缺乏带有一些先验领域知识(如特征的重要性和特征的分布)的标记数据的各种问题中使用。本博客中使用的所有代码和数据集都可以在这里找到。
如果你有任何疑问,请联系我。我很想知道你是否认为你有一个可以利用这种数学模型的用例。
我的 Youtube 频道更多内容:
嗨,伙计们,欢迎来到频道。该频道旨在涵盖各种主题,从机器学习,数据科学…
www.youtube.com](https://www.youtube.com/channel/UCg0PxC9ThQrbD9nM_FU1vWA)
关于作者-:
Abhishek Mungoli 是一位经验丰富的数据科学家,拥有 ML 领域的经验和计算机科学背景,跨越多个领域并具有解决问题的思维方式。擅长各种机器学习和零售业特有的优化问题。热衷于大规模实现机器学习模型,并通过博客、讲座、聚会和论文等方式分享知识。
我的动机总是把最困难的事情简化成最简单的版本。我喜欢解决问题、数据科学、产品开发和扩展解决方案。我喜欢在闲暇时间探索新的地方和健身。关注我的 中 、Linkedin或insta gram并查看我的往期帖子。我欢迎反馈和建设性的批评。我的一些博客-****
- 降维:PCA 与自动编码器
- 体验遗传算法的威力
- 每个数据科学家都应该避免的 5 个错误
- 以简单&直观的方式分解时间序列
- GPU 计算如何在工作中拯救了我?
- 信息论& KL 分歧第一部分和第二部分
- 使用 Apache Spark 处理维基百科,创建热点数据集
- 一种基于半监督嵌入的模糊聚类
- 比较哪个机器学习模型表现更好
- 分析 Fitbit 数据,揭开疫情封锁期间身体模式变化的神秘面纱
- 神话与现实围绕关联
- 成为面向商业的数据科学家指南
在 Windows 10 上安装 Tensorflow-GPU 2.0 的简单指南
根据你的网速,不会超过 15 分钟。
TensorFlow 是谷歌的开源库,使您能够开发和训练深度学习模型。虽然大多数安装指南侧重于安装 CPU 版本,这是您的常规pip install
,但今天我想重点安装它的更大、更强大的兄弟 GPU 版本。
你想要使用 GPU 版本而不是 CPU 版本的主要原因是速度——如果你决定在 GPU 上训练模型,速度会有令人难以置信的提高,我不会去解释原因——因为这是一个如何指南,而不是为什么指南。
最重要的是,安装将在 Windows 10 x64 机器上完成。所以这里没有 Linux,因为我知道在 Linux 上安装是相当简单的。
事不宜迟,让我们直接开始吧。下一节将简要讨论您需要什么。
要求
在整个过程中,我们需要下载并安装三个工具:
- 微软 Visual Studio (如果没有专业版的话社区版也可以)
- Nvidia CUDA 工具包 (我用的是 10.0 版本)
- Nvidia cud nn(7 . 6 . 5 版本即可)
下面几节将重点介绍如何安装每个工具。
Microsoft Visual Studio
现在我们不会真正使用 Visual Studio,但 Nvidia CUDA 工具包的一些组件需要它,所以它就是这样。
Visual Studio 可以从这个链接下载,从这里很容易下载社区版:
安装时,你不需要检查任何额外的组件——让一切保持原样,点击几次下一个。大约 5 到 10 分钟后,安装应该完成。在 Tensorflow 方面,您将不再需要接触 Visual Studio。
Nvidia CUDA 工具包
该工具包使您能够创建高性能 GPU 加速的应用程序。在可以从下载此链接的中,只需确保选择我已经选择的所有内容,然后点击下方的下载按钮即可。
它的大小略超过 2 GB,所以根据你的网速,可能需要一段时间。
下载后,您可以运行**。exe** 文件,它会要求你将内容解压到某个临时文件夹中。一旦安装开始,你可以坚持使用 Express 选项:
几分钟后,Nvidia CUDA Toolkit 将安装完毕!
接下来,Nvidia cuDNN。
Nvidia cuDNN
Nvidia cuDNN 是一个用于深度神经网络的 GPU 加速库。可以从这个链接下载。请记住,你需要创建一个帐户,但你可以登录谷歌,你就可以走了。
登录后,您将被重定向至以下页面—点击下载 cuDNN 7.6.5 for CUDA 10.0 :
这是一个 ZIP 文件,大小可能为 250MB,所以应该可以快速下载。下载完成后,你可以将 contents˛(that 解压到你的 CUDA 安装目录中,该目录位于:
C:\Program Files\Nvidia GPU Computing Toolkit\CUDA\v10.0
如果您在安装时没有做任何更改。仅此而已。设置完成!
在 GPU 上安装 TensorFlow 2.0
我们已经完成了繁琐的安装过程,现在只需要做一个简单的 pip 安装。在撰写本文时,最新的支持 GPU 的 TensorFlow 版本是 2.0.0 RC1。
要安装它,打开命令提示符并执行以下命令(我假设您已经安装了 Python):
pip install tensorflow-gpu=2.0.0-rc1
如果你不能提供版本,它将安装 1.14 版,这是我们不想要的。
就这样,下载需要一些时间(300+ MB),但是 TensorFlow 现在应该已经安装在你的机器上了。让我们快速验证一下这个说法:
如你所见,我在命令提示符下打开 Python shell,导入 TensorFlow 并检查 GPU 是否可用。这个函数调用了 return True,你也可以在提示符的底部看到我的 GPU 是黄色的。
在你走之前
拥有一台轻薄的笔记本电脑是很好的——你可以去任何地方而不会弄乱你的背。但比没有背部问题更酷的是拥有一台能够在 GPU 上训练神经网络的强大笔记本电脑。
如果你有一个合适的网速,这篇文章不应该花费你超过 5 分钟来阅读,15 分钟来安装和配置一切。
感谢阅读。玩得开心——我知道我会的。
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
Anaconda:从这里开始学习 Python 中的数据科学!
在 Python 虚拟环境中使用 Anaconda
如果你一直关注我或者读过我的一些文章,你一定知道我是 Python 虚拟环境的忠实粉丝。我以前也写过这方面的文章,你可以在这里阅读从那以后,我几乎所有的项目都包含了requirements.txt
文件,其他人可以很容易地复制我的作品。
我和几个虚拟环境经理一起工作过,但是从来没有真正关注过 Anaconda。然而,现在我需要在康达环境下进行日常的大学工作。这里,推荐的工作方式是使用虚拟环境,我的同事使用 Anaconda。所以,我决定试一试!
Anaconda 就像任何其他虚拟环境管理器一样,但是它不仅仅是管理环境。它有自己的名为conda
的 Python 包管理器,也支持pip
。它并不局限于 Python,也可以用于其他语言。但是也有一些警告,比如一些包只能用pip
安装,而不能用conda
。因此,在这篇文章中,我们将探索一些关于 Anaconda 的知识,然后查看一些最有用的命令,这些命令是您成为虚拟环境专家所需要的。
什么是蟒蛇?为什么要用?
以一条蛇命名一个项目听起来很荒谬,但是,嘿,我们知道 Python 也是一条蛇
Anaconda 完全是关于数据科学的。它侧重于包含帮助数据科学家拥有一个可以完成所有工作的工作台的特性和包。它从一开始就托管了几个数据科学包,使数据科学家能够快速起步。凭借环境的额外优势,它成为任何人迈向数据科学之旅的理想起点。
听起来很有趣!但是,与其他虚拟环境管理器相比,您为什么更喜欢它呢?我已经使用了一段时间,以下是我发现它真正吸引人的地方:
- **不需要目录:**与其他类似
virtualenv
的目录不同,您不需要指定某个目录来安装环境。这使您能够在系统的任何地方激活虚拟环境,而不必担心位置问题。 - **选择任意 Python 版本:**只要服务器上存在 Python 的一个版本,它是否安装在您的系统上并不重要。Anaconda 的
conda
可以通过从服务器获取 Python 的精确版本来轻松创建环境。 - **conda 包管理器:**虽然
pip
擅长管理 Python 包,但是conda
在检索包并将它们安装到环境中也做了类似的工作。额外的好处是,它与 Anaconda 发行版捆绑在一起,使之变得容易。
但是,我还是觉得没有pip
的conda
是不完整的。如果你试图通过conda
安装一些软件包,它可能会给出一个错误,但同样的软件包可以很容易地使用pip
安装。
在 Python 环境中使用 conda 和 pip。
关于 Python3 和 Python2 的注记
由 Kelly Sikkema 在 Unsplash 上拍摄的照片
Python2 不再被开发,所有的开发工作都是针对 Python3 的。然而,有几个包和项目仍然依赖于 Python2,所以不要与它失去联系是一个好习惯。查看下面基于 Python 2 的项目。创造了一些非凡的艺术品。
在几分之一秒内将名画的风格添加到任何照片中!你甚至可以设计视频!在…上需要 100 毫秒
github.com](https://github.com/lengstrom/fast-style-transfer)
本文适用于 Python2 和 Python3,因为在设置环境时,它们在选择 Python 版本上只有本质上的不同,但我们现在将使用 Python3 发行版。
在 Python3 中启动任何新项目都是面向未来的。
安装 Anaconda
如果你以前安装过任何软件,你会有宾至如归的感觉。转到这里,选择你的操作系统(我用的是 Mac ),然后选择 Python 3.x 版本Download
按钮,它会将安装程序下载到你的机器上。
选择 Python 3.7 版本下方的“下载”按钮
然后,打开机器上的安装程序,按照所有步骤进行操作,同时阅读并同意协议。您不需要修改任何东西,因为所有的东西都是自己设置好的,一旦完成,您就可以在您的机器上使用 Anaconda 了。
使用 Python 包
正如我之前提到的,Anaconda 包附带了conda
管理器,它允许你安装包,创建和激活虚拟环境等等。
开放终端
我使用 iTerm2 作为我的主要终端,这是我根据自己的喜好设计的。按照我在 Medium 上发布的指南,您可以创建一个类似的(甚至更好的)终端视图。
简单的外壳定制技术
towardsdatascience.com](/customising-the-mac-terminal-to-increase-productivity-and-improve-the-interface-894f6d86d573)
您会注意到终端现在在计算机名前面写有(base)
。这意味着您的基本 conda 环境已经设置好了(意味着您正在为整个用户而不是一个特定的环境工作)。
(基地)在司令部前面
我将首先描述这个基础环境中的几个命令,但是它们也可以在任何特定的环境中工作。我们将在本文后面看到如何设置和使用环境。
查看已安装的软件包
一个最基本的命令是知道您的环境中所有已安装软件包的列表。请注意,Anaconda 内置了许多包,因此您将看到比预期多得多的包。该命令如下所示:
conda list
已安装软件包列表
搜索并安装软件包
conda
非常直观,因为您想要做的正是该命令可能看起来的样子。假设我们想安装numpy
,但是我们不知道版本。我们可以使用以下命令来搜索它的版本:
conda search numpy
在康达搜索一个包
假设我们计划安装版本为1.18.1
的numpy
,我们将使用以下命令来完成:
conda install numpy==1.18.1
安装 numpy 版本 1.18.1
移除包
假设在某种情况下,您不再需要某个特定的包,或者您安装了一个错误的版本,您可以简单地使用下面的命令来删除它。用numpy
来做吧。
conda remove numpy
拆卸数字
使用 Python 环境
conda
您还可以根据需要创建、激活和停用虚拟环境。所有这些环境都是相互隔离的,可以托管非常不同的包和包版本组合,而不会相互干扰。
创建虚拟环境
可以使用以下命令创建虚拟环境,并选择在创建环境时直接安装几个软件包:
conda create -n env_name python=3.7.6 <list_of_packages>
-n
后面的字就成了环境的名字。在我们这里,它是env_name
。然后,我们按照上面的定义指定 python 的版本。然后,我们可以指定在创建环境时要安装的软件包列表。这意味着包将在<list_of_packages>
处列出。例如,要创建环境并安装numpy
和pandas
,我们将使用以下命令:
conda create -n env_name python=3.7.6 numpy pandas
创建名为“环境名称”的虚拟环境
激活环境
激活环境非常容易。只需使用以下命令:
conda activate env_name
如果您碰巧使用了先前版本的conda
,您将需要在 Linux/MacOS 上使用命令source activate
或者在 Windows 上使用命令activate
。
激活环境
正如我们在上面的图像中看到的,环境的名称在命令行的前面,表明我们在环境中。
现在,我们可以使用conda install
或pip install
按需安装软件包,它们不会干扰这个环境之外的任何软件包。
停用环境
停用同样简单。使用命令
conda deactivate
同样,如果您使用的是先前版本的conda
,请在 Linux/MacOS 上使用source deactivate
或在 Windows 上使用deactivate
。
停用环境
你会注意到前面的文字变回了(base)
,表明我们已经不在我们的环境中了。
共享环境
使用环境的主要原因之一(除了管理隔离的环境之外)是能够与他人共享精确的 Python 包及其精确的版本。conda
使用 YAML 文件来共享环境信息,而requirements.txt
通常与pip
一起使用。为了导出所有包,无论是通过conda
还是pip
安装的,我们在环境中使用以下命令:
conda env export > environment.yml
该文件将类似于下图:
environment.yml
我建议我们也创建requirements.txt
文件,这样不使用conda
的用户仍然可以使用我们的环境配置。为此,请在环境中使用以下命令:
pip freeze > requirements.txt
您可以简单地与您的项目共享文件environment.yml
和requirements.txt
,以便于复制。
一旦你有了一个environment.yml
文件,你就可以在创建环境时简单地使用它,并像下面这样设置它以备使用:
conda create env --file environment.yml
列出所有环境
当您处理多个项目时,您会创建许多环境。您可能会忘记您可能已经创建的环境。有一个快速命令可以查看所有可用的环境:
conda env list
所有环境的列表
正如你所看到的,我有相当多的环境有我们通常有的特殊的base
。
移除环境
一旦您不再处理某个项目,您可能还想删除它的环境。使用命令来执行此操作:
conda env remove -n env_name
这里,env_name
应该替换为被删除的环境的名称。我正在删除env_name
,所以我将保持不变。
正在删除“环境名称”环境
结论
在本文中,我们探讨了什么是 Anaconda,以及它如何优于其他虚拟环境管理器。我们探索了使用conda
处理包以及创建和运行 Python 虚拟环境的方法。
一旦你熟悉了本文中的基础知识,你也可以参考 conda 备忘单。
我希望你喜欢我的作品。如果你有任何建议、想法或者你面临任何问题,请在评论中告诉我。也可以在 LinkedIn 上联系我。
分析和分类真实的患者咳嗽声
阴性(左)和阳性(右)新冠肺炎咳嗽谱图——分析吸入剂
冠状病毒:使用机器学习对新冠肺炎患者进行分类
作者劳里·威廉姆斯 — 7 分钟阅读
在近 5 个月内,当前的新型冠状病毒(新冠肺炎)将爆发一年。尽管我们还远远不知道如何全面应对这种病毒,但我们已经看到了一些非常酷的社交距离技术解决方案(如点餐应用),以及医疗领域的解决方案(如自动检测肺部 x 光片中的肺炎样迹象)。
Alexander Sinn 在 Unsplash 上拍摄的照片
创业公司需要问的关于人工智能的三个问题
维亚切斯拉夫·波隆斯基博士——8 分钟阅读
数十亿美元的人工智能投资正在蓬勃发展。这对那些指望人工智能来获得创新和竞争优势的初创公司来说意味着什么?这个策略看起来很简单:用机器学习解决人类的一个长期问题。谷歌、脸书、网飞和优步做到了。一个显而易见的问题是为什么不使用人工智能?
数据仓库综合指南
妮可·珍妮薇的账单 — 7 分钟阅读
作为一名数据科学家,了解一些基本的数据仓库概念是很有价值的。我们所做的大部分工作都涉及到在需要清晰易懂的数据集上增加企业价值。
使用 Pandas、Matplotlib、Seaborn 和 Plotly 分析和可视化 1955 年至 2020 年的乡村人口
100 天数据科学的第 1、2、3 天。
2020 年 8 月 12 日,我开始了 100 天的数据科学挑战。这项挑战的主要目标是在 100 天内每天学习 1 小时数据科学并编写代码。我打算学习和编码项目,以提高我的技能和获得实践经验。我将在 GitHub、Instagram 和 Medium 上分享我的旅程。别忘了在社交媒体上关注我。
前三天,我在 Kaggle 上研究一个国家的人口数据集。每天我都会用数据分析和可视化回答一些问题。
首先要做的事。让我们导入所有需要的库。对于这个项目来说, Pandas , Matplotlib , Seaborn ,和 Plotly 库就足够了。
先导入吧。
# data analysis
import pandas as pd# data visualization
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as pxplt.style.use('fivethirtyeight')%matplotlib inline
我用了fivethirtyeight
的剧情风格。点击查看更多款式。
现在让我们导入数据。你可以从 kaggle 下载数据集。从 kaggle 下载数据后,我们有一个 csv 文件— Countries Population from 1995 to 2020.csv
。现在让我们在 dataframe 中导入数据。
# load dataset
population = pd.read_csv('./Countries Population from 1995 to 2020.csv')
关于数据集:
Year — Year detail in which population data is recordedCountry — Name of CountryPopulation — Population of Country in a given yearYearly % Change — Change in population since last year (in %)Yearly Change — Change in population since last yearMigrants — Number of migrantsMedian Age — Median age of the populationFertility Rate — Fertility rate (in %)Density (P/Km²) — Density of countryUrban Pop % — % of the population is living in an Urban areaUrban Population — Net population living in Urban areaCountry’s Share of World Pop % — Country’s share in Total World PopulationWorld Population — World PopulationCountry Global Rank — Global rank of country
现在让我们来看一些例子。
population.head()
是时候进行一些数据分析了。
让我们看看数据的形状。
population.shape# output
(4195, 14)
我们有 4195 个样本和 14 个特征。
让我们检查数据集的信息。
population.info()# output<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4195 entries, 0 to 4194
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Year 4195 non-null int64
1 Country 4195 non-null object
2 Population 4195 non-null int64
3 Yearly % Change 4195 non-null float64
4 Yearly Change 4195 non-null int64
5 Migrants (net) 3600 non-null float64
6 Median Age 3600 non-null float64
7 Fertility Rate 3600 non-null float64
8 Density (P/Km²) 4195 non-null object
9 Urban Pop % 4082 non-null float64
10 Urban Population 4082 non-null float64
11 Country's Share of World Pop % 4195 non-null float64
12 World Population 4195 non-null int64
13 Country Global Rank 4195 non-null int64
dtypes: float64(7), int64(5), object(2)
memory usage: 459.0+ KB
通过查看上面的输出,我可以说一些事情。
- 国家和密度(P/Km)是对象类型。所以我会把它们分别换成 String 和 integer。
- 密度(P/Km)在数值上有额外千个逗号。例 1111。所以让我们先去掉它。
- 很少有丢失的值,但是现在我将忽略它们。
# remove extra symbol
population['Density (P/Km²)'] = population['Density (P/Km²)'].replace(',','')
现在让我们更改国家类型和密度值。
population['Density (P/Km²)'] = population['Density (P/Km²)'].astype(int)population['Country'] = population['Country'].astype(str)
现在我们来看看描述性统计。
population.describe()
数据分析和可视化
问题 1:2020 年人口排名前 30 的国家。
*# 2020 population data*
current_population = population[population['Year'] == 2020][:30]
plt.rcParams['figure.figsize'] = (25, 7)
ax = sns.barplot(x = current_population['Country'][:30], y = current_population['Population'][:30], palette = 'dark')
ax.set_xlabel(xlabel = 'Countries', fontsize = 10)
ax.set_ylabel(ylabel = 'Population in Billion', fontsize = 10)
ax.set_title(label = 'Population of top 30 countries in 2020', fontsize = 20)
plt.xticks(rotation = 90)
plt.show()
2020 年前 30 个国家的人口。
plt.figure(figsize=(9,25))
ax = sns.barplot(x="Population", y="Country",
data=current_population, palette="tab20c",
linewidth = 1)
for i,j **in** enumerate(current_population["Population"]):
ax.text(.5, i, j, weight="bold", color = 'black', fontsize =10)
plt.title("Population of each country in 2020")
ax.set_xlabel(xlabel = 'Population in Billion', fontsize = 10)
ax.set_ylabel(ylabel = 'Countries', fontsize = 10)
plt.show()
问题 2:2020 年前 10 个国家在世界人口中的总份额。
unique_countries = population['Country'].unique()
plt.style.use("seaborn-talk")
*# set year*
year = 2020df_last_year = population[population['Year'] == year]series_last_year = df_last_year.groupby('Country')['Population'].sum().sort_values(ascending=False)
labels = []
values = []
country_count = 10
other_total = 0
for country **in** series_last_year.index:
if country_count > 0:
labels.append(country)
values.append(series_last_year[country])
country_count -= 1
else:
other_total += series_last_year[country]
labels.append("Other")
values.append(other_total)
wedge_dict = {
'edgecolor': 'black',
'linewidth': 2
}
explode = (0, 0.1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
plt.title(f"Total Share of in World's Population the top 10 countries in **{**year**}**")
plt.pie(values, labels=labels, explode=explode, autopct='**%1.2f%%**', wedgeprops=wedge_dict)
plt.show()
- 中国是世界人口最多的国家,其次是印度。
问题 3:世界上人口最多的五个国家。
population_top5_2020 = population[population['Year'] == 2020][:5]
top_5_countries = population_top5_2020['Country'].unique()top5_popultion = population[population['Country'].isin(top_5_countries)][['Year', 'Country', 'Population']]
top5_popultion_pivot = top5_popultion.pivot(index='Year', columns='Country', values='Population')
top5_popultion_pivot.style.background_gradient(cmap='PuBu')# Please note, in medium I am unable show the gradient color.
fig,ax = plt.subplots(figsize=(20, 10))
sns.despine()
sns.set_context("notebook", font_scale=1.5, rc={"lines.linewidth": 2})
sns.barplot(x="Year", y="Population", data=top5_popultion, hue='Country')
ax.set_ylabel(ylabel = 'Population in Billion', fontsize = 10)
ax.set_xlabel(xlabel = 'Year', fontsize = 10)
ax.set_title('Top 5 most populated countries in the World')
ax.legend();
问题 4:2020 年哪个国家人口密度高?
population_2020 = population[population['Year'] == 2020]fig = px.choropleth(population_2020, locations="Country",
locationmode='country names', color="Density (P/Km²)",
hover_name="Country", range_color=[1,1000],
color_continuous_scale="blues",
title='Density of Countries in 2020')
fig.update(layout_coloraxis_showscale=True)
fig.show()
*# highest dense country by population*
population_2020[population_2020['Density (P/Km²)']==population_2020['Density (P/Km²)'].max()][['Country','Density (P/Km²)']]
*# lowest dense country by population*
population_2020[population_2020['Density (P/Km²)']==population_2020['Density (P/Km²)'].min()][['Country','Density (P/Km²)']]
问题 5:哪个国家人口众多?
*# highly populated country*
population_2020[population_2020['Population']==population_2020['Population'].max()][['Country','Population']]
fig = px.choropleth(population_2020, locations="Country",
locationmode='country names', color="Population",
hover_name="Country",
color_continuous_scale="dense",
title='Population of Countries in 2020')
fig.update(layout_coloraxis_showscale=True)
fig.show()
问题 6:人口超过 100 万的国家数量。
population_more_than_one_million = population[(population['Population'] >= 1000000) & (population['Year']==2020)]number_of_countries = population_more_than_one_million.shape[0]
print("There are **{}** countries in the world with more than 1 million population.".format(number_of_countries))## Output
There are 159 countries in the world with more than 1 million population.
让我们看看世界地图,那里的国家人口超过 100 万。
fig = px.choropleth(population_more_than_one_million, locations="Country",
locationmode='country names', color="Population",
hover_name="Country",
color_continuous_scale="blues",
title='Countries with more than 1 million Population')
fig.update(layout_coloraxis_showscale=True)
fig.show()
问题 7:人口超过 10 亿的国家数目。
population_more_than_one_billion = population[(population['Population'] >= 1000000000) & (population['Year']==2020)]number_of_countries = population_more_than_one_billion.shape[0]
print("There are **{}** countries in the world with more than 1 Billion population.".format(number_of_countries))# output
There are 2 countries in the world with more than 1 Billion population.
让我们看看世界地图,上面有超过 10 亿人口的国家。
fig = px.choropleth(population_more_than_one_billion, locations="Country",
locationmode='country names', color="Population",
hover_name="Country",
color_continuous_scale="reds",
title='Countries with more than 1 billion Population')
fig.update(layout_coloraxis_showscale=True)
fig.show()
只有两个国家中国和印度的人口超过 10 亿。
最后的话
我希望这篇文章对你有帮助。我尝试用数据科学来回答几个问题。还有很多问题要问。现在,明天我将转向另一个数据集。所有数据分析和可视化的代码都可以在这个 GitHub 库或者 Kaggle 内核中找到。
感谢阅读。我感谢任何反馈。
如果你喜欢我的工作并想支持我,我会非常感谢你在我的社交媒体频道上关注我:
- 支持我的最好方式就是跟随我上 中级 。
- 订阅我的新 YouTube 频道 。
- 在我的 邮箱列表 报名。
使用 Python 分析公司收入呼叫
构建一个 Python 脚本来分析公司盈利呼叫。
在本帖中,我们将摘录管理层在最近的收入电话会议中陈述的关于公司近期和未来业绩的主要要点。
代码将非常简单。我们将通过我们感兴趣的任何公司的股票,结果将是一个令人惊讶的收益电话会议的简短总结。
卡罗琳娜·格拉博斯卡在Pexels.com拍摄的照片
为什么要分析公司盈利电话
公司盈利电话是了解企业经营状况和下一季度预期的主要信息来源之一。
公司盈利电话是公开的。通常,我们可以访问该公司的网站,并拨入电话,听取管理层的意见。收益电话会议通常安排在公司收益公开发布的同一天。电话会议的结构很简单,管理层概述了上个季度的运营情况和未来的指导。此外,记者可以向最高管理层询问有关业务的问题。
他们听起来很有见地。但是,浏览整个电话可能会很耗时,尤其是当我们对多家公司感兴趣时。
因此,在这篇文章中,我们要做的是使用 Python 自动分析公司盈利呼叫。
Python 如何帮助分析公司盈利电话?
使用 Python,我们不仅能够执行定量分析,正如我们在我以前的帖子中所学的那样。其中,我们可以,例如,使用自然语言处理来分析语言结构或执行情感分析。
在本帖中,我们将重点传递公司收入电话的完整记录作为输入。然后,我们将提取关键点,这将有助于我们了解一家公司的发展方向以及最近的表现如何。以下是我们将回答的一些问题:
- 公司上个季度表现如何?
- 销售额的预期增长是多少?
- 哪条线的产品表现更好?
- 公司有望增加净利润吗?
- 还有更多
Python 脚本分析公司盈利电话
我们通过向 financialmodelingprep 发出 get 请求来开始我们的代码,以便检索最新收益的副本。
在本帖中,我们将分析苹果,但是可以随意更改公司名称来分析任何其他公司。此外,取消对变量 demo 的注释,并传递您的 API 密钥(注册后您可以在 financialmodelingprep 中免费获得一个),以便对 API 的请求能够工作。
然后,我们将从 API 获得的完整字符串存储在变量的副本中。接下来,我们可以使用 Python split 方法。该方法将创建一个 Python 列表,其中包含由每个新行(即/n 字符)分割的脚本,如下面的结果所示。
import requests
import pandas as pd
#demo= 'your api key'
company = 'AAPL'
transcript = requests.get(f'https://financialmodelingprep.com/api/v3/earning_call_transcript/{company}?quarter=3&year=2020&apikey={demo}').json()
transcript = transcript[0]['content'].split('\n')
print(transcript)
#outcome
["Operator: Good day, everyone. Welcome to the Apple Incorporated Third Quarter Fiscal Yea
现在我们有了一个 Python 列表,其中包含了最新的苹果公司的每一句话,我们将把它传递给熊猫数据帧。我们将用熊猫来分析收益记录。我们将搜索单词“expect”以保留包含单词 expect 的所有句子。
earnings_call = pd.DataFrame(transcript,columns=['content'])
word_to_analyze = 'expect'
analysis = earnings_call[earnings_call['content'].str.contains(word_to_analyze)]
text_earnings = analysis['content'].values
然后,在分析变量中,我们使用 str.contains 方法过滤掉所有含有except单词的句子。你可以随意改变这个词来分析公司的任何其他方面,比如收入、利润。
然后,我们从熊猫系列中提取值,以得到如下所示的句子。只保留带期待字样的句子。
print(text_earnings)
#outcome
array(["Tim Cook: Thanks, Tejas. Good afternoon, everyone. Thanks for joining the call today. Be...
如果你进一步研究变量 text _ incomes,你会发现有些句子还是太长了。我们将循环遍历它们,以便在每次遇到“.”时将它们分开。然后,我们将只打印包含单词和的句子:
for text in text_earnings:
for phrase in text.split('. '):
if word_to_analyze in phrase:
print(phrase)
print()
#outcome
Due to the uncertain and ongoing impacts of COVID-19, we did not provide our typical guidance when we reported our results last quarter, but we did provide some color on how we expected the June quarter to play out
In April, we expected year-over-year performance to worsen, but we saw better-than-expected demand in May and June
We expected iPad and Mac growth to accelerate and we saw very strong double-digit growth for these devices this quarter
Wearables growth decelerated as we expected, but still grew by strong double-digits and set a revenue record for a non-holiday quarter
First, results for advertising and AppleCare were impacted by the reduced level of economic activity and store closures to a degree that was in line with our expectations
However, we will provide some additional insight on our expectations for the September quarter for our product categories
On iPhone, we expect to see recent performance continue for our current product lineup, including the strong customer response for iPhone SE
We expect the rest of our product categories to have strong year-over-year performance
For services, we expect the September quarter to have the same trends that we have observed during the June quarter except for AppleCare where during the September quarter a year ago we expanded our distribution significantly
As a consequence, we expect a difficult comp for AppleCare also considering the COVID related point of sale closures this year
For OpEx, we expect to be between $9.8 billion and $9.9 billion
We expect the tax rate to be about 16.5% and OI&E to be $50 million
First one, Tim, when you look at the services business and in terms of your TV+ content production have the movement restrictions impacted the content production efforts? And along the same path four years ago your premonition on services being a $50 billion business in 2020 came sooner than expected, I don't know if you want to make any such forecast four years out and how you think services revenue is going to be
With the strong sales in Mac given the shelter-in-place, do you think the back-to-school season got pulled in by a quarter or do you expect the momentum to still continue? Thank you very much.
Luca Maestri: As I said, when I was talking about providing some commentary for the September quarter, we expect all the non-iPhone product categories to have a very strong year-over-year performance
So we expect the performance that we've seen for Mac in the June quarter to continue.
And then, can you talk a little bit more about the decision to bring Mac Silicon in-house, then the benefits that you
包扎
最后,我们总结了收益电话会议,以提取关键信息供我们分析。从上面的例子中,我们可以快速而容易地看出:
- 苹果在 5 月和 6 月的需求好于预期
- 苹果实现了非常强劲的收入增长,并创造了新的非假日季度记录
- 在今年余下的时间里,预计会有强劲的同比表现
- 运营支出约为 99 亿美元
- 产品类别绩效
这个脚本很酷的一点是,你可以将 expect 替换为要分析的单词(例如 profits ),你将得到你感兴趣的任何公司的简短摘要。
在以后的文章中,我们将继续分析盈利电话记录,执行 Python NLTK 情绪分析。
与此同时,你可以继续阅读我在 Python for Finance 上的其他帖子。
原载于 2020 年 10 月 18 日【https://codingandfun.com】。
用 Pyspark 分析 Scrum 和敏捷的区别
由 Kelly Sikkema 在 Unsplash 上拍摄的照片
Scrum 和 Agile 是两种现代软件开发方法,大多数科技公司一直在使用这些框架来开发或维护软件应用程序。那么这两者到底有什么区别呢?只需谷歌搜索,你可能会看到大量比较两者差异的文章,但如果我们尝试使用数据科学方法来发现差异,会怎么样呢?
资料组
那么我们从哪里开始呢?在这两个框架引起科技公司的注意之前,人们已经写了很多关于这两个框架的书,让我们来分析一下这些书吧!这是我们将要分析的两本书:
- 软件工程和极限编程中的敏捷过程
- Scrum 手册(杰夫·萨瑟兰)
正在初始化 Pyspark
Pyspark 是向 Python 公开 spark 编程模型的 Spark Python API。Sparkcontext 是 Spark 功能的主要入口点,它将在我们启动一个新应用程序时创建。这个 sparkcontext 向 master 请求一些内核来进行处理,这些内核将被搁置起来,不会用于其他应用程序。
我们将首先从 pyspark 创建一个 SparkContext sc
,通过设置master = local[*]
使用机器上所有可用的内核。然后,我们使用 SparkConf 对象中设置的配置创建 SparkContext 对象中提供的 SparkSession 对象spark
。
# create entry points to spark
from pyspark import SparkContext, SparkConf # Spark
from pyspark.sql import SparkSession # Spark SQL# create or use existing spark context
sc = SparkContext.getOrCreate()# If there is no existing spark context, we now create a new context using all local processors
if (sc is None):
sc = SparkContext(master="local[*]", appName="Agile Scrum comparison")
spark = SparkSession(sparkContext=sc)
创建弹性分布式数据集(rdd)
弹性分布式数据集(RDDs)是 Spark 的基本数据结构,我们将为集群上的每本书创建两个。
# read in first txt file
scrum_txt = sc.textFile('./Scrum Handbook.txt')
# print number of lines
print("Number of lines in Scrum Handbook is: ", str(scrum_txt.count()))# read in second txt file
agile_txt = sc.textFile('./Agile Processes in Software Engineering and Extreme Programming.txt')
# print number of lines
print("Number of lines in Agile Processes in Software Engineering and Extreme Programming is: ",\
str(agile_txt.count()))
我们看到软件工程和极限编程中的敏捷过程有 21569 行,大约是有 4617 行的 Scrum 手册的 5 倍。
数据清理
在此步骤中,我们执行以下文本清理和操作步骤:
- 使用
split
和flatMap
将这些行拆分成单个单词(即,标记化) - 使用正则表达式
[A-Za-z\s]
删除除空格以外的所有非字母字符 - 使用
lower
和map
将所有单词转换成小写 - 使用
strip
和map
删除所有前导或尾随空格
# import re for regular expression
import re# function to do the 3 text cleaning and manipulating steps
def cleantext(rdd):
# split the lines into individual words
words = rdd.flatMap(lambda x: x.split(' '))
# remove all characters which are not alphabets except spaces
alpha_words = words.filter(lambda x: re.findall('[A-Za-z\s]+',x))
# replace all characters which are not alphabets or spaces with ''
alpha_words_cleaned = alpha_words.map(lambda x: re.sub('[^A-Za-z\s]+','',x))
# change all to lower case
lower_alpha_words = alpha_words_cleaned.map(lambda x: x.lower())
# remove all leading or trailing spaces
cleaned_words = lower_alpha_words.map(lambda x: x.strip())
# return the result
return cleaned_words# apply cleantext function to scrum_txt
scrum_txt_cleaned = cleantext(scrum_txt)# apply cleantext function to agile_txt
agile_txt_cleaned = cleantext(agile_txt)
数数单词
在这一步中,我们执行一个转换步骤,首先使用map
为每个值为 1 的单词创建一个单词对,然后使用reduceByKey
对每个单词的频率求和。然后我们使用带有选项-1
的sortBy
按照单词出现的频率对单词进行排序,以表示降序。
# function to transform the data and count the words
def count_words(rdd):
# transformation to convert each word to a key/value pair of (word, 1)
pairs = rdd.map(lambda x: (x,1))
# transformation to sum the frequency of each word
word_count = pairs.reduceByKey(lambda x,y: x+y)
# sort the words by frequency in descending order
sorted_word_count = word_count.sortBy(lambda x: -x[1])
# output
return sorted_word_count
我们将count_word
应用于 Scrum,并使用take(20)
显示前 20 个最常用的单词
# apply count_words function to scrum_txt_cleaned and display top 20 most frequent words
scrum_txt_wordcount = count_words(scrum_txt_cleaned)
scrum_txt_wordcount.take(20)
我们将count_word
应用于敏捷,并使用take(20)
显示前 20 个最常用的单词
# apply count_words function to agile_txt_cleaned and display top 20 most frequent words
agile_txt_wordcount = count_words(agile_txt_cleaned)
agile_txt_wordcount.take(20)
根据每本书中的频率比较前 20 个词,它们大多是停用词,如 the,of 和。我们应该在下一步中删除它,以便更好地分析书籍。
删除停用词
在计算中,停用词是在处理自然语言数据之前或之后过滤掉的词。在自然语言处理中,无用词(数据)被称为停用词,它在文本分析中几乎不提供上下文。我们将从nltk.corpus
包中获取停用词列表,并使用函数filter
删除两本书中的停用词。最后,我们显示每本书中独特单词的数量。
# import nltk package and stopwords
import nltk
from nltk.corpus import stopwords
# get the english stopwords since there are 16 languages available
eng_stopwords = set(stopwords.words('english'))# filter off those words in scrum_txt_wordcount that are in eng_stopwords list
scrum_txt_no_stopwords = scrum_txt_wordcount.filter(lambda x: x[0] not in eng_stopwords)
# get the number of unique words of each text after removal of stopwords
print("Number of unique non stopwords in Scrum Handbook is:",str(scrum_txt_no_stopwords.count()))
# filter off those words in agile_txt_wordcount that are in eng_stopwords list
agile_txt_no_stopwords = agile_txt_wordcount.filter(lambda x: x[0] not in eng_stopwords)
# get the number of unique words of each text after removal of stopwords
print("Number of unique non stopwords in Agile Processes in Software Engineering and Extreme Programming is:",\
str(agile_txt_no_stopwords.count()))
一个词的平均出现次数
在这一步,我们先用sum
和map
求出每本书的总字数,然后用这个值除以唯一字的数量,从而求出一个字的平均出现次数。
# get total number of words in scrum_txt_no_stopwords
total_scrum_words = scrum_txt_no_stopwords.map(lambda x: x[1]).sum()
# find avg occurence of the words and return result in 3 decimal place
print("Average occurence of words in Scrum Handbook is:",\
round(total_scrum_words/scrum_txt_no_stopwords.count(),3))
# get total number of words in agile_txt_no_stopwords
total_agile_words = agile_txt_no_stopwords.map(lambda x: x[1]).sum()
# find avg occurence of the words and return result in 3 decimal place
print("Average occurence of words in Agile Processes in Software Engineering and Extreme Programming is:",\
round(total_agile_words/agile_txt_no_stopwords.count(),3))
单词分布
我们可以使用可视化matplotlib.pyplot
来分析单词的分布,方法是绘制每本书中的单词总数,然后绘制每本书中单词的平均出现次数。
# import the standard python plotting library and numpy for easy data manipulation
import matplotlib.pyplot as plt
import numpy as np
import math
# to show plot in jupyter notebook
%matplotlib inline# create three subplots
f, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(12,4), tight_layout=True)# Plot 1 - Total number of words
# prepare the data
y_axis_1 = [math.log10(total_scrum_words), math.log10(total_agile_words)]
x_axis = ('Scrum Handbook', 'Agile Processes')
bar_width = 0.5
# plot
ax1.bar(x_axis, y_axis_1, bar_width, align='center', color='C0')
ax1.set_xlabel('Book')
ax1.set_ylabel('Log Scale of number of words')
ax1.set_title('Total number of words in each book')# Plot 2 - Total number of unique words
# prepare the data
y_axis_2 = [scrum_txt_no_stopwords.count(), agile_txt_no_stopwords.count()]
x_axis = ('Scrum Handbook', 'Agile Processes')
bar_width = 0.5
# plot
ax2.bar(x_axis, y_axis_2, bar_width, align='center', color='C1')
ax2.set_xlabel('Book')
ax2.set_ylabel('Number of unique words')
ax2.set_title('Total number of unique words in each book')# Plot 3 -Average Occurence of word
# prepare the data
y_axis_3 = [total_scrum_words/scrum_txt_no_stopwords.count(), total_agile_words/agile_txt_no_stopwords.count()]
bar_width = 0.5
# plot
ax3.bar(x_axis, y_axis_3, bar_width, align='center', color='C2')
ax3.set_xlabel('Book')
ax3.set_ylabel('Average Occurence of word')
ax3.set_title('Average Occurence of word in each book')plt.show()
作者图片— matplotlib 绘制单词分布图
从图中可以清楚地看出,软件工程和极限编程中的敏捷过程是一本比 Scrum 手册更长的书,在去除了停用词和文本处理之后,在 log10 的标度上有 1.25 倍多的单词, 3 倍多的独特单词,并且前者中的每个单词比后者出现两次多。
最常见的单词
现在让我们比较一下每本书中最常见的 15 个单词。
# create two subplots
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(12,4), tight_layout=True)# Plot 1 - Top 15 of scrum handbook
# prepare the data
top15_scrum_word = scrum_txt_no_stopwords.map(lambda x: x[0])
top15_scrum_word = top15_scrum_word.take(15)
top15_scrum_value = scrum_txt_no_stopwords.map(lambda x: x[1])
top15_scrum_value = top15_scrum_value.take(15)
# plot
bar_width = 0.5
ax1.bar(top15_scrum_word, top15_scrum_value, bar_width, align='center', color='C0',label='Scrum Handbook')
plt.setp(ax1.get_xticklabels(), rotation=90)
ax1.set_xlabel('Scrum Handbook')
ax1.set_ylabel('Count of words')
ax1.set_title('Total 15 words in Scrum Handbook')
ax1.legend()# Plot 2 - Top 15 of agile processes
# prepare the data
top15_agile_word = agile_txt_no_stopwords.map(lambda x: x[0])
top15_agile_word = top15_agile_word.take(15)
top15_agile_value = agile_txt_no_stopwords.map(lambda x: x[1])
top15_agile_value = top15_agile_value.take(15)
# plot
bar_width = 0.5
ax2.bar(top15_agile_word, top15_agile_value, bar_width, align='center', color='C1',label='Agile Processes')
plt.setp(ax2.get_xticklabels(), rotation=90)
ax2.set_xlabel('Agile Processes')
ax2.set_ylabel('Count of words')
ax2.set_title('Total 15 words in Agile Processes')
ax2.legend()plt.show()
按作者分类的图像— matplotlib 在最常用的单词上绘图
对比两本书的前 15 名,两本书的内容非常相似,都围绕着产品、团队、开发和软件。
摘要
基于这篇我在 Google 上找到的关于敏捷和 Scrum 的区别的文章,敏捷是一种项目管理哲学,它利用了一套核心的价值观或原则,而 Scrum 是一种特定的敏捷方法,用于促进项目。
基于我们对这两本书的分析,我们发现了一个相似的发现,即 Scrum Handbook 关注团队开发,这是项目经理促进项目的一种方式,而软件工程和极限编程中的敏捷过程更关注一般的软件开发。
这就对了,希望这种数据分析方法可以给你另一个角度来比较差异,而不是依赖我们最可靠的合作伙伴,谷歌!
分析我的锁定睡眠数据
过去的几个月对我们大多数人来说都是动荡不安的时期,不管是以这样还是那样的形式,但是我们的睡眠是变好了还是变坏了呢?
过去的几个月对我们大多数人来说都是一段动荡的时期,无论形式如何。无论这种动荡是来自生活方式的彻底改变,还是更简单的事情,比如与你的公寓“伙伴们”全天候关在一起。
就我个人而言,我经历过:
- 完全可变的工作时间表
- 由于搬家,完全不同的社会环境
- 对当前和未来计划的新看法
因此,我问自己的一个问题是,这种生活方式的改变在多大程度上改变了影响我健康的关键因素:睡眠、锻炼和饮食。不幸的是,我还没有记录任何关于我饮食的数据,然而,我很幸运地在去年 9 月投资了一个健康穿戴设备,允许我访问我在锁定前、锁定后和锁定中的睡眠和运动数据。以下是我的发现…
一年的睡眠数据
几周前,我在健身应用程序的设置中翻找,该应用程序允许我检查我的睡眠和健身数据(通过我的手表检测的运动来跟踪),我注意到了以下选项:
一个下载按钮!
在意识到我可以请求方便的 CSV 文件,包含我的数据的简化视图后,我知道我必须这样做。这将允许我执行任何我希望的分析,消除应用程序的所有限制(即,现在我可以比较更长时间内的数据,而不是滚动查看每周的平均值)。
通过少量的 Python 代码,我现在有能力可视化一整年的健康数据。想到的第一个分析指标是什么?每晚总睡眠时间。
因此,为了避免看到不可读、参差不齐的混乱,我选择了 30 天滚动平均值,加上一些颜色,瞧:
作者图片
很高兴看到我每晚的平均睡眠时间持续超过 7 小时。除此之外,随着国家进入封锁期,我们可以看到总睡眠时间明显增加,在我搬家后,这种情况还会继续(如果不是又一次增加的话)。
表面上看,这很棒。但是我们至少应该带着一些怀疑的态度来看待它(也许你已经是了)。更多的睡眠不一定意味着更好的睡眠。有趣的是,我们可以深入研究,看看睡眠是如何分为浅睡眠和深睡眠的:
作者图片
没想到啊!随着我的总睡眠时间在禁闭期间开始增加,深度睡眠没有明显的变化;但是,当我们进入八月时,价格明显下降。今年年初,我的浅睡和深睡比例接近 50:50(这实际上是标准应用程序指标所建议的),但当我进入一个新环境和新房子时,一个非常明显的差异出现了。
最后,我的手表还测量我晚上醒着的时间:
作者图片
另一个有趣的情节是,由于在任何特定点的总清醒时间从来没有那么高(谢天谢地),然而,随着我们从 2 月到 3 月,以及最终的锁定,仍然有明显的增加。也许是新冠肺炎时代前后矛盾的结果?
这就是我们对睡眠的长达一年的回顾,涵盖了全球疫情、全国禁闭和本地重新安置。总结一下:
- 当我们进入一级防范禁闭状态时,我的总平均睡眠时间似乎增加了,在我搬家后又增加了。
- 尽管浅睡眠遵循相似的趋势,但深睡眠看起来是负相关的。
- 在一月份,我的浅度睡眠和深度睡眠的平均时间大致相等,但是最近,在一级防范禁闭后,这种情况迅速逆转。
- 我醒着的时间也越来越长。这不是一个好的趋势,尽管实际金额仍然相对较低。
我对未来的最后想法是:
- 饮食也是分析封锁前/后/中期变化的有趣领域。感觉好像我已经养成了一些新习惯。特别是重复相同的食物组合。
- 想知道我在数据中发现的趋势对大多数人来说是否是共同的,这将是一件有趣的事情。或者其他人在禁闭期间有过相反的经历?
- 总的来说,这些实验提供了非常有用的见解,我愿意继续实验。具体来说,如果锁定导致我的总睡眠时间增加,但我的睡眠质量下降,那么可以隔离导致这些影响的锁定组件,从而使它们可以在锁定之外帮助增加睡眠和睡眠质量吗…?
如果您喜欢这篇文章,您可能也会喜欢我在锁定期间对我的活动数据所做的类似分析🏃🏼♂️即将上映…
用 Python 分析药品销售数据
如何使用 Python、Pandas、Matplotlib 和回归模型分析药品销售数据
介绍
这个项目的目的是分析药品销售数据。分析销售数据并根据历史数据预测未来销售是一项非常常见的数据科学任务。这是开始研究数据科学的好方法。
你会学到什么?
在本项目中,您将学习将数据集从文本文件加载到 Pandas,这是最流行的数据操作和数据分析 Python 库,并在不同的销售数据集中查找特定信息,如特定药物最常何时销售。除此之外,我们还将根据现有数据,使用线性回归、多项式回归和简单向量回归来预测未来的销售额。我们将做一些数据预处理和标准化。为了获得更好的结果,我们还将学习一种重要而有用的数据科学技术——集成学习。
您还将学习如何使用 Matplotlib 测试模型和绘制结果。
让我们开始吧。
问题定义
以下是我们将在本练习中回答的具体问题:
- 第二种药物(M01AE)最常在一周的哪一天售出?
- 2015 年 1 月,2016 年 7 月,2017 年 9 月哪三种药销量最高?
- 2017 年周一哪种药卖得最多?
- 2020 年 1 月可能有哪些药品销售?(我们的数据集仅包含 2014 年 1 月至 2019 年 10 月的销售信息)
逐步解决方案
创建项目文件夹
在电脑上为一个名为“分析-制药-销售-数据”的项目创建一个文件夹
从这个 Kaggle 项目下载数据集:
https://www.kaggle.com/milanzdravkovic/pharma-sales-data
将这些数据集放在项目文件夹中名为“data”的文件夹中。
如果你从未在电脑上使用过 Python 或 Jupyter Notebook,请阅读我的文章如何为数据科学设置你的电脑以检查你是否拥有在电脑上运行以下分析所需的一切。
开始新的笔记本
在终端/命令提示符下键入命令,启动 Jupyter Notebook:
$ jupyter notebook
点击右上角的新建,选择 Python 3。
作者图片
这将在您的浏览器中打开一个新的 Jupyter 笔记本。将未命名的项目名称重命名为您的项目名称,您就可以开始了。
作者图片
如果您的计算机上安装了 Anaconda,那么您的计算机上已经安装了这个项目所需的所有库。
如果你用的是 Google Colab,打开一个新的笔记本。
加载库和设置
在新笔记本中,我们通常做的第一件事是添加我们在项目中需要使用的不同库。
现在我们准备解决我们的第一个问题。
第二种药物(M01AE)最常于一周的哪一天售出?
一旦我们加载了所有的库,通常我们下一步要做的就是加载数据集。因为我们需要找出一周中的哪一天是第二种最常销售的药物,所以我们需要加载每日数据。我们正在加载此数据集,以便进一步探索熊猫数据框。
这是我们数据的样子。
作者图片
这将显示数据集中的前几行,这样我们就可以看到数据的结构和内容。
为了找出第二种药物(M01AE)在一周中的哪一天最常被卖出,我们需要将所有结果相加
因为 Python Pandas 非常强大,我们可以使用一行代码来完成这些事情中的大部分。
上面的命令将按工作日名称对所有销售额求和,然后进行排序,因此药品销售最多的那一天将出现在第一行。
作者图片
现在我们只需要从第一行中获取工作日的名称和值。
我们现在需要做的就是打印结果。
如果您正确完成了任务,屏幕上的结果应该是这样的。
第二种药物 M01AE 在周日的销量最高,为 1384.94 英镑
我们鼓励您也找出其他药物在一周中的哪一天最常出售。
现在我们来看第二个问题。
【2015 年 1 月、2016 年 7 月、2017 年 9 月哪三种药销量最高
对于这个任务,我们需要将每月的销售数据加载到 Pandas 数据框架中,让我们看看我们的数据是什么样子的。
作者图片
因为我们将对不同的年份和月份重复计算,所以最好定义一个将月份和年份作为参数的函数。
该函数将如下所示。
一旦定义了函数,我们就可以对一个月和一年的不同整数值运行该函数。
如果您正确完成了任务,您应该会收到以下结果。
【2015 年 1 月销售额排名前三的药物
- 产品:N02BE,销量:1044.24
- 产品编号:N05B,销量:463.0
- 产品:R03,销量:177.25
2016 年 7 月销售额排名前三的药物
- 产品:N02BE,销量:652.36
- 产品编号:N05B,销量:240.0
- 产品:M01AB,销量:203.97
2017 年 9 月销量前三的药品
- 产品:N02BE,销量:863.75
- 产品:N05B,销量:223.0
- 产品:R03,销量:139.0
这是我们完成的第二项任务。让我们看看第三项任务。
2017 年周一哪种药卖得最多?
为了回答这个问题,我们需要加载一个每日销售数据集。
这就是我们熊猫数据框的样子。
作者图片
现在,我们需要过滤销售额,以便只获得 2017 年星期一的销售额。
我们现在需要按照工作日名称和总和值对结果进行分组。
现在我们需要对这些值进行水平排序,以获得左边的最大值。水平排序类似于更常用的垂直排序,但水平滚动不是按列排序,而是按行排序。
现在,我们将在左起第一列中获得 2017 年周一销售最频繁的药物。
作者图片
我们唯一需要做的就是获取这个值并打印出结果。
The drug most often sold on Mondays in 2017 is N02BE
with the volume of 1160.56
在上述练习中,我们将数据集加载到 Pandas 数据框中,并使用分组、排序和汇总等功能寻找特定信息。这些是练习这些类型的数据操作的很好的练习,我们将在接下来的练习中经常使用它们。
【2020 年 1 月可能有哪些药品销售?
我们现在来看看回归,这是一项非常常见的数据科学任务。回归的思想是根据一个或多个自变量的值来预测因变量的值。使用不同的回归方法和过去的数据,我们可以尝试预测未来的值。
在本练习中,我们将针对 2014 年至 2019 年间记录的数据,尝试预测未来几个月的销量。
预处理
查看数据集,我们可以看到数据质量良好,但有些记录中至少有一组药物的销售额为 0。这通常是我们在运行任何机器学习模型之前需要注意的事情。在这种情况下,我们有几个选择;我们可以删除至少一组药物的记录销售值为 0 的行,或者我们也可以用该组的平均值或中值替换 0 值。为简单起见,我们将删除至少一组药物的记录销售额为 0 的所有记录,但我们建议您再次重复此练习,并用该组的平均值或中值替换 0 值,以查看您是否会获得更好的结果。
数据的另一个重要特征是,它包含了 2019 年不完整的销售数据。记录的最后一天是 10 月 8 日,这意味着 10 月份的销售数据不完整。因为对于本练习中的回归方法,我们仅使用月度销售数据,所以我们从分析中排除了 2019 年 10 月的数据。
车型和技术
我们将使用 Pandas 来读取 CSV 数据文件和数据预处理,并使用 Scikit-learn Python 库来学习回归模型。
对于数据可视化,我们将使用 Matplotlib Python 库。
我们将使用以下回归模型:
- 线性回归
- 多项式回归
- 简单向量回归
Scikit-learn 库包括所有上述模型的实现。
我们已经在笔记本的开头加载了所有需要的 Scikit-learn 库。
我们将分割数据,我们将使用 70%的数据训练模型,30%的数据进行测试。
我们将使用投票回归器来组合不同的机器学习回归器,并返回平均预测值。我们这样做是为了平衡个体回归者的弱点。
计算和绘图
我们将显示所有回归和投票回归变量的单个结果,并将所有回归绘制在图表上,以直观地评估数据如何分散以及回归如何在数据集值之间绘制。
因为我们正在处理一个相对较大的项目,所以使用函数来组织代码是一个好主意。
让我们从将我们的训练和测试数据分散在图表上的函数开始。
现在,我们将创建线性回归、多项式回归和 SVR 预测函数。这些函数将训练和测试值作为参数,计算回归并显示 2020 年 1 月的预测值以及计算的精度和误差值,以便我们可以看到模型的有效性。
线性回归预测函数。
多项式回归预测函数。
简单向量回归(SVR)预测函数。
在下一个 Jupyter 笔记本单元中,我们可以编写使用上述函数的代码,显示预测值,并使用 Matplotlib 可视化我们的训练和测试数据以及不同的回归模型。
对于计算,我们将再次使用第二个产品(M01AE),但我们鼓励您也对其他产品进行类似的计算。
我们需要用产品名定义我们的产品变量,我们将为其计算回归。接下来,我们将定义 Pandas 数据框,我们将在其中存储我们的回归结果。然后我们将定义 predictFor 变量,它是值序列中的一个月的数字,用于预测相关销售额。因为我们有 2019 年 10 月之前的数据,而不是 2019 年 12 月,我们预测未来 3 个月。
作者图片
作者图片
Predictions for the product N02BA sales in January 2020
执行并保存线性回归的结果。
作者图片
执行并保存多项式回归的结果。
作者图片
执行并保存简单向量回归(SVR)的结果。
为了获得更好的结果,我们将使用投票回归器,这是一种集成技术,它使用几个模型,然后对单个预测进行平均,并返回最终预测。
Voting Regressor January 2020 predicted value: 98.0
显示所有结果
regResults
作者图片
总结
在本练习中,我们学习了使用 Python Pandas,这是数据科学中最流行的数据操作和分析库。对于初学数据科学家来说,使用 Pandas 加载数据集并执行统计分析是最重要的元素之一。
接下来,我们看了回归,这是数据科学的另一个非常重要的元素。线性回归、多项式回归和支持向量回归是回归的基本模型。
为了巩固你的知识,考虑从头开始完成任务,不要看书中的代码示例,看看你会得到什么结果。这是巩固你的知识的一件极好的事情。
Jupyter 笔记本的完整 Python 代码可在 GitHub 上获得:
https://GitHub . com/pj online/Basic-Data-Science-Projects/tree/master/1-analyzing-Pharmaceutical-Sales-Data
编码快乐!
还没有订阅媒体?考虑报名成为中等会员。每月只需 5 美元,你就可以无限制地阅读媒体上的所有报道。订阅 Medium 支持我和其他作家在 Medium 上。
使用 tableau 分析(ADIL)股票
“作者提供的图像”
你在学习如何摆拍吗?厌倦了使用默认的超级商店数据,想尝试一些更实用的东西吗?试试这个分析股票的快速指南,看看它会带你去哪里!
收集您的数据
- 去雅虎财经查一只股票。真的,什么股票都行。如果是你碰巧持有的股票就更好了!
- 在股票的摘要页面上,转到标签为历史数据的选项卡。
- 将视图更改为所需的时间段(默认为一年)。
- 单击“下载数据”链接下载 CSV 文件。
请注意,在示例的剩余部分,我将使用 CSV 显示该股票在以下时间段的数据:2019 年 1 月 20 日-2020 年 1 月 20 日。
“作者提供的图像”
ADIL 雅虎财务历史数据
准备您的数据
数据准备始终是将原始数据引入 Tableau 的第一步。在这种情况下,我们的数据已经相对干净和简单。但为了以防万一,我们需要检查一下。
要准备数据,请在 Excel 或 Google Sheets 中打开它。检查一下格式。如果您愿意,可以更改任何列的默认标题。在这些情况下,我们很可能不会改变什么。
“作者提供的图像”
在 Tableau 中可视化您的数据
如果需要,在 Excel 中保存对 CSV 文件的任何更改,然后关闭它。然后,我们开始 Tableau 吧!
在 Tableau 中打开 CSV 文件
- 打开 Tableau 桌面。
- 在“连接”下,查找“到文件”,然后选择“更多…”
- 浏览到 CSV 文件的位置并打开它。现在我们看到了 Tableau 数据源视图。
- 单击“工作表 1”选项卡打开工作簿视图。现在我们准备开始可视化!
请注意左侧的数据窗格。这里,我们有维度和度量。由于这些数据大多包含可衡量的数字,如开盘价、收盘价和调整后收盘价以及成交量,因此需要衡量的项目要多得多。
构建工作簿—可视化每日收盘价
- 双击‘日期’维度。这将自动将其带到工作簿的列区域。
- 点击并拖动“调整接近”指标到工作簿的行区域。请注意,我们使用的是调整后的收盘价,而不是收盘价,因为这更准确。如果你想知道原因,请点击这里阅读更多内容。
现在我们有了一个基本的线图,向我们展示了……到底是什么?绝对不是我们要找的。所以,我们需要进一步分解。
注意到标有年份(日期)的列区域中的药丸了吗?当我们双击日期维度时,它出现了。这表明我们目前只查看了数据中的年份— 2019 年和 2020 年的前几周。我们的可视化显示,我们的股票价格在 2019 年至 2020 年期间下跌。它还把今年所有的收盘价加起来,这也肯定不是我们想要的。
这是因为我们的日期目前是离散的,这意味着它添加了整个相应年度的每个调整后收盘价。由于我们的例子中 2019 年大约有 49 周,2020 年有 3 周,当然 2019 年的价格更高。 - 将鼠标悬停在月份(日期)药丸上,直到您看到右侧有一个朝下的三角形。点击三角形调出菜单。
注意,菜单显示了两个看起来相同的日期选项,顶部的年份选项被选中。还要注意选择了离散。边注,我们也可以看出这个维度是离散的,因为药丸是蓝色的。如果它是绿色的,它将是连续的。 - **在菜单中,从第二组日期选项中选择“日”。**注意药丸现在是绿色的,可视化看起来像我们需要的!我们现在正在查看一个线形图,显示 CSV 文件中整个日期期间每天调整后的收盘价。
“作者提供的图像”
我们的第一次股票价格可视化!
设置工作簿的格式
让我们清理一些东西,使这个东西看起来更专业一点。
格式化标题
- 双击工作簿的标题(当前为“工作表 1”)。
- 将名称改为描述性的名称,例如“ADIL 收盘价”,并在下面加上副标题和日期范围。调整字体大小,让标题比副标题更有影响力。
“作者提供的图像”
格式化 Y 轴
- 在 Y 轴(垂直轴)旁边,双击标题“Adj Close”
- 在对话框中,在轴标题下,让我们继续清除标题。假设我们已经将图表命名为 ADIL 收盘价,那么 Y 轴表示收盘价应该是很直观的。完成后关闭对话框。
- 右键单击(或在 Mac 上按住 control 键单击)Y 轴数字上的任意位置,然后选择“格式”
- 在“比例”下,选择“数字”旁边的箭头,然后选择“货币(标准)”现在我们的观众肯定知道这是收盘价的范围。
- 既然我们在这里,让我们继续将“Ticks”更改为“None”
X 轴格式 对于 X 轴(水平轴),我们真的不需要标题,因为我们知道那些是日期。
- 双击“日期”,在“轴标题”下,简单地删除标题。
看起来已经好多了!但是还有一件事我们可以做,让这个看起来更专业——删除那些网格线! - 转到格式>工作簿。
- 在现在出现在左侧的“工作簿格式”选项下,转到“线条”并选择“网格线”旁边的向下三角形。把它从自动改为关闭。
“作者提供的图像”
现在我们看起来不错!
但是等等,我们还可以添加更多!还记得我们的 CSV 文件有一个显示容量的列吗?这是某一天交易的股票数量。你可以在这里阅读更多关于交易量的信息,但是添加这个会让这个可视化看起来特别专业。我们有两个选择。
添加第二个度量值作为颜色
这个很简单。我们希望更改图表中线条的颜色,以指示交易量较高的区域。只需将“音量”从测量区域拖放到“标记”下的“颜色”框中
注意这条线在某些区域改变了颜色——较暗的区域是股票交易量较高的地方。你能把这些和股价的涨跌联系起来吗?
添加第二个度量作为双轴
如果你想看起来更高级更专业一点(你当然想),试试这个!
- 如果需要,通过将药丸从标记拖到下面的空白区域来删除上一部分的测量颜色。(将任何药丸拖到此区域会将其从工作簿中删除。)
- 将“Volume”从度量区域一直拖到工作簿的最右侧,直到它显示一个垂直矩形。在这里释放。现在,左边的 Y 轴显示了我们的收盘价范围,右边的 Y 轴显示了我们的成交量范围。现在,让我们格式化一下。
- 在“Marks”下,您现在应该会看到三个可折叠的部分——All、SUM(Adj Close)和 SUM(Volume)。展开最后一个,SUM(体积)。
- 使用下拉菜单,将其从线条更改为条形。
- 同样在标记>总和(体积)下,单击标记为“大小”的框,将其从“固定”更改为“手动”
- 让我们继续更改工作簿的标题,这样我们就可以完成新 Y 轴的格式化。双击标题,并将其更改为 ADIL 收盘价和成交量。单击“确定”退出对话框。
- 双击右侧的 Y 轴;删除标题。
- 在同一对话框中,选择“刻度”标签。将“主要刻度线”从“自动”更改为“固定”关闭对话。
- 最后一点家务——让我们去掉剩下的线。右键单击(或按住 command 键单击)左侧的 Y 轴,然后选择“格式”
- 在左侧“格式”面板的顶部,选择“边框”选项(看起来像方形窗格)。
- 在行分隔线>窗格下,选择无。
- 在列分隔符>窗格下,选择无。关闭“格式”面板。
“作者提供的图像”
嘿,你都快成职业选手了!
我们还没完呢!想解决股票分析和研究的基本介绍?你当然知道!
研究发现
看你的练习册。看到什么突出的东西了吗?
注解一下!
让我们从两个明显的点开始——52 周高点和 52 周低点。这些应该很容易在你的练习册中找到。你甚至可以将光标放在该点上,Tableau 会告诉你日期和价格。让我们这样注释它们。
- 右键单击(或按住 command 键单击)高点,然后选择“批注”>“点”。
- 清除对话中的默认值。将 justification 设置为 left,并输入一些内容来帮助我们理解这里发生的事情,如“52 周高点:6.88 美元,2 月 1 日。”
“作者提供的图像”
注释对话
对 52 周低点重复这些步骤。然后,对交易量中的主要异常值做类似的事情。在我们的例子中,我们可以在 2 月 21 日看到一个主要的异常值。让我们在 12 月 16 日标记今年晚些时候的另一个异常值。称之为“主要交易量:550 万,2 月 21 日。”使用与 52 周最高价和最低价相同的格式。
研究一下吧!
现在真正有趣的部分来了——看看我们是否能找出这些事件发生的原因。你能通过查看公司的投资者关系页面回答以下问题吗?提示:所有上市公司的网站上都有这一部分。
- 为什么该股在 2 月 1 日创下历史新高?
- 为什么股票在 12 月 5 日跌到了历史最低点?
- 为什么该股在 2 月 21 日出现如此高的交易量?
- 为什么 12 月 16 日会出现随机的高成交量?
- 季度业绩是什么时候公布的?(找到这些日期时,请注明)
在公司的投资者关系页面,从新闻稿开始。你的基本答案一般都在这里。就我们使用的股票而言,我们可以发现:
- 这位首席执行官出现在 2 月 1 日的两个新闻节目中,其中一个是在湾区…也是众所周知的充满风险资本和投资者的地区。请注意,这与同一天的高交易量(近 190 万)相关。
- 2 月 21 日,该公司公开发行 800 万美元股票,试图筹集更多资金。这与交易量的大幅上升相关,但也与股价的螺旋式下降相一致,因为这可能会稀释价值。
- 季度业绩分别于 5 月 13 日、8 月 13 日和 11 月 14 日发布。这些都与图上任何未完成的活动无关。然而,这种结果往往与交易量的上升和价格的上涨或下跌相关,这取决于消息的好坏。
- 最后,在 12 月 16 日,该公司宣布了一项额外专利的许可,这与更大的交易量和收盘价的大幅上升相关。
结论
在注释完你发现的重要的东西后,看看你可能会有什么!一张漂亮的信息图,有股票的基本分析。
“作者提供的图像”
你学到了什么:
- 如何在雅虎财经上查找一只股票并下载其一年的历史数据?
- 检查数据,以确保为 Tableau 做好准备。
- 将 CSV 导入 Tableau。
- 创建带有折线图、双轴折线图和条形图的工作簿。
- 研究和分析股票的基本历史活动。
最后说明:如果你想下载并玩它,这在 Tableau Public 上。祝你的舞台和股市之旅好运!
欧洲电视网变得不那么俗气了,我们可以从数学上证明这一点
数字音乐
借助 Spotify 公共 API 的一点点帮助
有一项年度电视赛事,全球观众约有两亿人(大约是超级碗的两倍)收看 T2 的比赛。它的 YouTube 频道号称有超过 43 亿的浏览量。没有它,不管是好是坏,你都不会听说过 ABBA。或者是史诗萨克斯手。
2019 年欧洲电视网歌曲大赛的获奖表演
“像凤凰一样崛起”
欧洲电视歌曲大赛于 1956 年由欧洲广播联盟创立,旨在将饱受战争蹂躏的欧洲大陆聚集在一个“轻松娱乐节目”的周围。尽管自成立以来技术细节已经发生了变化,但欧洲电视网的主要前提依然如故。每个参赛国都会送出一首原创歌曲,作为一个晚间电视节目的一部分。
在节目的最后,每个人都会根据全国听众来电的结果和音乐专业人士组成的“全国评审团”的意见,给其他国家的歌曲打分。哪首歌得分最高,哪首歌就获胜,获胜的国家将获得举办明年比赛的“荣誉”。
欧洲电视网以不敬和印花棉布闻名。精心制作的舞台表演、烟火表演和华丽的服装比比皆是(这场比赛在 LGBT 群体中拥有狂热的追随者。然而,许多人对真正的音乐的看法被 90 年代和 00 年代的记忆所模糊,在那个时期,大多数国家都不幸地倾向于非常令人震惊的流行音乐。对于英国的许多人来说,欧洲电视网仍然是吉娜·G 1996 年参赛作品的同义词,“哦,啊…就一点点”,一大块严重老化的音乐奶酪,最好被丢弃在时间的迷雾中。
如何看待欧洲电视网在过去十年里已经“长大”的说法?乌克兰在 2016 年以一首关于约瑟夫·斯大林驱逐克里米亚鞑靼人的歌曲赢得了比赛,这表明自吉娜·g 时代以来,一些事情确实发生了变化。
贾马拉为乌克兰赢得 2016 年世界杯
然而,由于 Spotify 的一些非常聪明的数据科学工作,我们甚至可以超越歌曲的抒情主题,而是通过音频特征来分析歌曲。为此,我们可以将欧洲电视网过去十年的歌曲与其他曲目的对照组进行比较,看看这场比赛的负面内涵是否仍然值得(未来的博客也将使用这些“音频”数据来预测哪首歌会赢得 2020 年的比赛,这场比赛在新冠肺炎之后不可避免地被取消)。
“这就是你如何写一首歌”
Spotify 的公共 API 允许用户访问平台上任何歌曲的信息。这些范围从显而易见的(歌名、作曲家、发行日期等。)到更奇特的,包括由音轨音频文件的波形直接推断出来的指标。
注意——Spotify 的 API 可以通过使用“ Spotipy ”库用 Python 访问。观看 Ian Annase 的系列视频以获得对此的完整介绍,或者深入研究这个项目的 GitHub repo。
要获得这些信息,我们只需将惟一的 track ID 输入 API。正如人们所希望的那样,获取数百首歌曲的 id 是一项可以由 Spotipy 自动完成的任务——只需创建所需歌曲的播放列表,然后调用一个方法来获取这些播放列表的信息。这将返回简洁的 JSON 文件,其中包含每个播放列表轨道的基本数据,包括其唯一的 ID。
芒斯·塞默洛为瑞典赢得 2015 年世界杯
除了 2009 年以来的欧洲电视网歌曲库,本博客还分析了另外两个“控制”歌曲列表:
- “图表”: 382 首曲目摘自 Spotify 自 2015 年以来英国最热门歌曲的年度“热门曲目”播放列表(注意——非整数是因为删除了多年播放列表中出现的重复曲目)。这包括商业上超级成功的艺术家,如艾德·希兰、德雷克、贾斯汀比伯等。
- **“Pitchfork”😗*400 首选自 Pitchfork 的 200 首最佳歌曲,以及十年来的 200 张最佳专辑。这个播放列表代表了广受好评的“高质量”音乐(在之前的博客中,我们发现 Pitchfork 通常可以很好地判断一张唱片的内在质量)。
“玩数字”
让我们依次看看不同的音频特征,看看欧洲电视网过去十年与这两个对照组相比如何。
**节奏。**简单来说,每首歌每分钟多少拍(BPM)?
我们注意到欧洲电视集团紧紧围绕 120–125 BPM 范围。这可能是因为欧洲电视网的歌曲不能超过三分钟(比赛的乐趣之一是,如果你不喜欢一首歌,你永远不必等待它结束)。
一首典型的歌曲每小节有四个节拍。两个 16 小节的韵文、三个 16 小节的合唱、一个中 8 小节和四个引子和结尾小节(现代音乐的主要结构,全部在内)总共有 360 个节拍,当以 120BPM 播放时,正好需要三分钟。
我们应该注意到,图表音乐也有大约 100 和 120BPM 的峰值。这可能是出于类似的考虑(期望大量广播播放的歌曲将致力于 3 到 3.5 分钟的持续时间)。广受好评的 Pitchfork 播放列表上的歌曲对时长的限制更少,因此没有那么紧密地捆绑在一起。
**能量。**这是 Spotify 第一个更主观的指标。根据 API 文件:
能量代表强度和活动的感知度量。通常,高能轨道感觉起来很快,很响,很嘈杂。例如,死亡金属具有高能量,而巴赫前奏曲在音阶上得分较低。
我们可以看到所有三个歌曲组都向右倾斜(根据 Spotify 的说法,与人口分布一致)。然而,欧洲电视网的轨道特别有活力。我们预料到了这一点——欧洲电视网的参赛作品必须在漫长的表演之夜与 20 多首其他歌曲争夺关注。低能量的歌曲迷失在混音中,除非有惊人的声音转折。
**可跳舞性。**根据 Spotify:
可跳舞性描述了基于音乐元素(包括速度、节奏稳定性、节拍强度和整体规律性)的组合,一首曲目适合跳舞的程度。
不出所料,高度流动的排行榜音乐似乎非常适合跳舞。正如我们所料,Pitchfork 播放列表的范围要广得多——舞蹈和好评没有明显的相关性。也许出乎意料的是,尽管欧洲电视网的音乐是所有三个组合中最有活力的,但平均来说却不太适合跳舞(事实上,分布相当正常)。
Spotify 没有给出任何关于“danceability”背后的精确计算的进一步细节,但我们可以在下图的右下方找到线索:
可跳舞性最低的歌曲(Japandroids 的《Younger Us》)恰好是所有被分析歌曲中能量第二高的。曲目节奏非常快,由摇滚吉他和鼓带动。这听起来很有活力。然而,这首歌中有一些地方明显有损于它的可跳舞性——乐器在大约 30 秒钟内被完全切断,歌曲最后几个和弦的演奏不合拍(如果你试图跟着它们跳舞,你会看起来非常奇怪)。
**键。**不用过多钻研音乐理论,歌曲的“调”决定了演奏时使用的音符。最常见的键族是“大调”和“小调”。一般来说,大调听起来是快乐的,小调听起来是悲伤的。这不是一个听众通常会注意的事情,尽管你会注意到一首熟悉的歌曲的音调是错误的——听村民用小调唱“基督教青年会”是一种真正痛苦的经历。
我们看到,欧洲电视网的小调音比例最高(49%)。同时,c 大调、C#大调和 D 大调是所有播放列表中特别常见的调。
**价。**这是 Spotify 得出的最有趣的指标之一:
描述音轨所传达的音乐积极性的量度。高价曲目听起来更积极(例如,快乐、愉快、欣快),而低价曲目听起来更消极(例如,悲伤、沮丧、愤怒)。
我们看到排行榜音乐更倾向于正面。这并不奇怪——自从有史以来,排行榜音乐一直是快乐和乐观的。然而,我们看到欧洲电视网实际上是所有组中最负向倾斜的,这表明它有更高浓度的情绪负面歌曲。
小调歌曲的较高比例将对此有所贡献,尽管 Pitchfork 组有类似的配价分布(尽管有更多的大调歌曲),但这可能不是整个故事。
“告别昨天”
从音乐上来说,我们已经看到欧洲电视网的歌曲占据了现代流行音乐和更小众、广受好评的音乐之间的一个有趣的中间地带。它乐观而充满活力,但也更情绪化,更可能是小调。
萨尔瓦多·索布拉尔(Salvador Sobral)为葡萄牙赢得了 2017 年欧洲电视网(Eurovision)近十年来最没有活力的歌曲
事实上,如果我们以年为基础绘制欧洲电视网条目的分布(kde),我们可以看到明显的趋势——歌曲变得越来越没有活力,它们的效价(或音乐“快乐”)比过去低得多。
我们可以将这两个指标绘制在一起,并显示欧洲电视网的歌曲是如何从右上角的高能量、快乐(俗气)的角落向左下角的低能量、悲伤(不那么俗气)的角落移动的。
给定年份欧洲电视网歌曲的平均价和能量值
在 2014 年的比赛之后,参赛作品的音乐性质发生了特别明显的变化(不管是不是巧合,一首能量和效价评级特别低的歌曲赢得了比赛——尽管声乐表演非常出色)。
肯奇塔·沃斯特为澳大利亚赢得 2014 年世界杯
这一趋势看起来似乎将持续到 2020 年——在整个取消之前,博彩公司最看好的是保加利亚。维多利亚的歌曲“眼泪变得清醒”的效价评分为 0.26,能量评分仅为 0.18——在整个欧洲电视网数据集中排名第二低。
“哦,啊…就一点点”,不是的。
这是我的“ Music By Numbers ”专栏中的最新博客,它使用数据来讲述关于音乐的故事。在接下来的博客中,我们将看到如何在机器学习环境中使用上述音频特征。我也很乐意听到对以上分析的任何评论——欢迎在下面留言,或者通过 LinkedIn 联系我!
分析具有因果影响的时间序列干预:货币波动
我们如何解释时间序列中的干预?
免责声明:本文是在“原样”的基础上编写的,没有任何担保。它旨在提供数据科学概念的概述,不应被解释为投资建议或任何其他类型的专业建议。
当检查一个时间序列时,有一个干预在一个特定的点上影响该序列是很常见的。
这方面的一些例子可能是:
- 导致销售显著变化的广告活动
- 交通政策的积极变化降低了交通事故的死亡率
- 影响资产价格的经济政策变化
分析干预效果的问题是,如果没有干预,人们就无法检查该序列的趋势。
例如,假设一家公司实施了一项广告活动,目的是促进销售。虽然可以在干预后记录销售数据,但如果没有干预,很难说的销售额会是多少。
我们的例子
对于这个例子,让我们考虑一下利率变化对货币波动的影响。
当中央银行操纵利率时——这被假设为对一种货币有重大影响,因为它影响了该货币相对于市场上其他货币的感知价值。
然而,如果我们希望量化这种影响,该怎么办呢?让我们看看这是如何与因果影响包一起工作的。这个包最初是由 Google 为 R 开发的,但是在这个例子中我们将使用 Python 版本(pycasualimpact)。
让我们考虑 2017 年英镑/美元的波动。
2017 年 11 月,英国央行决定加息。
资料来源:tradingeconomics.com
我们将使用因果影响来尝试调查:
- 如果没有这种干预,英镑对美元的预测汇率会是多少
- 这种干预是否重要,是否影响了货币水平
为了确定这种干预是否对时间序列有显著影响,我们必须使用合适的协变量(X)。这个协变量不能受到干预的影响。
例如,我们可以看到,2017 年,欧洲央行维持利率不变(此后一直如此):
资料来源:tradingeconomics.com
考虑到这一点,欧元/美元将被用作本例的协变量。
X = eurusd
y = gbpusd
虽然假设货币会受到美元波动以及许多其他宏观经济条件的影响,但假设英格兰银行的干预不会影响欧元/美元。
分析
使用 Quandl 从 FRED 数据库下载相关的货币对:
>>> eurusd = quandl.get("FRED/DEXUSEU", start_date='2017-01-01', end_date='2018-01-01', api_key='enter_api_key')>>> gbpusd = quandl.get("FRED/DEXUSUK", start_date='2017-01-01', end_date='2018-01-01', api_key='enter_api_key')
gbpusd
这是两种货币对的图表:
英镑/美元
资料来源:美联储经济数据
欧元/美元
资料来源:美联储经济数据
随着英国央行在 2017 年 11 月 2 日做出利率决定, t = 0 至 229 被定义为前期(干预前),而 t = 230 至 248 被定义为后期(干预后)。
data = pd.DataFrame({'y': y, 'X': X}, columns=['y', 'X'])
pre_period = [0, 229]
post_period = [230, 248]
根据这个软件包的官方 GitHub,这个模型“使用经典的卡尔曼滤波方法来求解状态空间方程”。
后验推断可以如下产生:
>>> ci = CausalImpact(data, pre_period, post_period)
>>> print(ci.summary())
>>> print(ci.summary(output='report'))
>>> ci.plot()
下面是生成的输出:
Posterior Inference {Causal Impact}
Average Cumulative
Actual 1.34 25.46
Prediction (s.d.) 1.32 (0.0) 25.17 (0.08)
95% CI [1.32, 1.33] [25.01, 25.33]
Absolute effect (s.d.) 0.02 (0.0) 0.29 (0.08)
95% CI [0.01, 0.02] [0.13, 0.45]
Relative effect (s.d.) 1.15% (0.32%) 1.15% (0.32%)
95% CI [0.52%, 1.77%] [0.52%, 1.77%]
Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 100.0%
根据上述发现,英镑/美元的实际汇率为 1.34 ,而在没有干预的情况下,该汇率将为 1.32 。
此外,该模型表明,有一个 100%的因果关系的后验概率。
在分析更详细的报告时,输出还指出:
偶然获得这个效果的概率很小
(贝叶斯单侧尾区概率 p = 0.0)。
这意味着因果关系可以被认为是统计上
显著的。
从这个角度来看,有证据表明英镑/美元的走势比没有加息的情况下更高。以下是实际比率与预测比率的概述:
来源:Jupyter 笔记本输出
如前所述,Python 使用了一种不同于 R 的方法来生成预测,无需干预——后者更依赖于强调用户先验知识的贝叶斯方法。事实上,人们可以尝试这两种方法来验证生成的预测是否一致。
关于对数变换的一个注记
在处理资产价格数据时,通常的做法是将数据转换成对数格式。
这样做有两个原因:
- 能够比较不同价格范围的资产,例如,比较 200 美元股票和 2000 美元股票的变动
- 考虑百分比方面的波动
在上面的例子中,两种货币具有相似的标度,因为它们都以美元为基准。在这方面,没有使用对数变换。
此外,在我们试图分析的干预背景下,货币价格比股票价格相距更近的事实将使价格变化难以察觉。
但是,如果将这种转换应用到数据上会怎么样呢?是否仍然观察到统计上显著的因果影响?
以下是以对数形式表示的两个时间序列:
欧元/美元
来源:Jupyter 笔记本输出
英镑/美元
来源:Jupyter 笔记本输出
对经过对数转换的数据运行时,输出结果如下:
Posterior Inference {Causal Impact}
Average Cumulative
Actual 0.29 5.56
Prediction (s.d.) 0.28 (0.0) 5.34 (0.07)
95% CI [0.27, 0.29] [5.21, 5.47]
Absolute effect (s.d.) 0.01 (0.0) 0.22 (0.07)
95% CI [0.0, 0.02] [0.09, 0.35]
Relative effect (s.d.) 4.1% (1.22%) 4.1% (1.22%)
95% CI [1.68%, 6.47%] [1.68%, 6.47%]
Posterior tail-area probability p: 0.0
Posterior prob. of a causal effect: 100.0%
用对数表示,如果没有干预,英镑/美元的自然对数应该是 0.28。然而,实际结果是 0.29。
来源:Jupyter 笔记本输出
因此,即使进行了对数变换,干预仍会显示为改变了时间序列的轨迹。这两种货币的比例仍然有很大的不同,在这种情况下是否需要对数变换仍有争议(这种变换通常对比例偏差较大的大值最有效)。
然而,证据表明,干预导致了有关时间序列的变化。
结论
这是对因果影响库的一个介绍性示例,以及如何在一个时间序列中检查干预的效果。
非常感谢您的时间,任何问题或反馈都非常欢迎。
参考
使用 Python 分析 WhatsApp 群组消息
谁发的信息最多?最常用的词是什么?最常用的表情符号有哪些?人们什么时候最常发信息?如果你曾经想知道你和你的朋友们在 WhatsApp 上的这些事情,那么这篇文章就是给你的。用一些(相对)简单的 Python 来了解一下吧!
我相对来说是 Python 的新手,但是这个项目给了我一个很好的 Python 数据争论入门,因为我必须在这里使用许多不同的技术,并试图探索最好的一种。
卡斯帕·卡米尔·鲁宾在 Unsplash 上的照片
获取数据
比我想象的更简单,我从来没有意识到你可以在 WhatsApp 上得到这个。在你的手机上,进入 WhatsApp 群组,点击右上角的点点点。然后进入“更多”和“导出聊天”。然后,您可以选择保存该文件的位置。我选择了 Google Drive,并把它放在我将要创建 Jupyter 笔记本的地方。
设置
只是对我的设置做一点小小的评论。我用了一个 Jupyter 笔记本来进行这种分析,这种分析是在小部件中完成的,我认为它可以很好地执行每个单元。这里有几个技巧和一些在 Jupyter 中有用的特殊函数。
我已经在评论中解释了它们的作用,但是为了解释为什么:Jupyter 限制了每个单元格显示的输出数量。因此,如果您想在一个单元格中输出一些数据的图形以及一个支持表,那么您需要运行第一个命令。后两个我用来控制输出多少。我不喜欢它默认如此少的行数/列数,尤其是当您可以使用像。head()取而代之,所以我没有限制。但是在查看数据的时候一定要小心,当你需要的时候你会限制它。
争论数据
我在这里做了一些笔记。我喜欢有两组数据,留下一组作为原始数据,可以与争论的数据集进行比较,因此有了 raw_data_csv 和 data 。
不幸的是,WhatsApp 的这种数据导出并不完美,当一条消息包含多行/换行符时,很难将其归因于正确的消息细节。我尝试了一些方法,但是找不到任何简单的方法。为了这个分析的目的,我已经把它们去掉了,因为没有它们我们仍然可以得到足够好的洞察力。这就是日期时间列上的 dropna 正在做的事情。
text_message 的第二个缺点是去掉了一些系统消息,比如当人们被添加到组中时。
实际上,我在 Jupyter 的不同单元格中运行了这些部分,并在每个点运行 head、tail 和 info,以了解每个点的数据情况。
分析数据
一些 WhatsApp 群上下文
所以接下来的几个部分的一些背景,我用的 WhatsApp 群是我的(场)曲棍球队,所以主要谈论训练,比赛和我们度过的夜晚。但是你很快就会看到这个!
最受欢迎的消息时间
我认为热图可以最好地显示一天中的小时和一周中的天。这是我最感兴趣的,因为其他事情是显而易见的,比如曲棍球赛季开始的月份。因此,我的构建方法是为这两个数据点创建新列,然后用这些维度的分组计数创建一个新的数据框。
作者图片
你能猜出我们在哪个晚上训练吗?周一和周三晚上,是的。这将是消息说,人们是在,外出,或迟到的会议。我们的比赛显然是在周六,这是我们大部分信息的来源,将主要谈论前往比赛,然后是赛后的滑稽动作。
按发件人排列的邮件
接下来是发件人邮件数,我选择用条形图显示,如下所示:
作者图片
显示为条形图可以让您直观地看到数字的差异,而不仅仅是一个数字表。亚历克斯是队长,所以他会发送很多管理信息,而我是社交安全专员,当他们显然不想出去的时候,我会试图组织一群人出去做些有趣的事情。甚至我也很惊讶亚历克斯和我比其他人多发了多少信息,但我们经常得不到任何回应,所以这很有意义。
最流行的词
现在谈谈流行词,这确实需要相当多的操作和运行时间。希望这些评论能解释大部分正在发生的事情。
最难的部分,也可能是最大的警告是如何定义非 _ 词,最终我只是使用了那些我在分析中根本不关心的词,但我可能在这里可以走得更远,因此我们作为一个整体有一些非常无趣的顶级词:
作者图片
所以我想可能更有趣的是挑选单词,看看它们的排名有多高,就像这样:
健身搭售啤酒是一个有趣的“巧合”…作者图片
我认为另一件有趣的事情是发件人的字数统计。不幸的是,我们没有大量的信息/文字,所以除了 Alex S 和我之外,对任何人进行细分实际上只能提供很少的数据,但不管怎样,我们还是要这样做:
作者图片
最流行的表情符号
我想补充的最后一点是表情符号的使用。现在我们并不是表情符号用户中最疯狂的,所以也没有太多的数据,也很难定义/细分表情符号到底是什么,所以这里有一些奇怪的表情符号,我认为它们对应着与表情符号相关的性别和肤色,但我们开始了:
作者图片
好吧,那就结束了。对于这个数据集,我想不出更多可以分析的东西,但我很想听到一些建议。此外,如果任何人对代码有任何建议,请告诉我,因为我对 Python 还很陌生,所以我觉得肯定有更好的方法来完成某些部分。
享受吧。
多尺度 CNN 特征图的分析与应用
摘要
在这篇博文中,我们提出了卷积层感受域的正式处理方法,并使用一个衍生的数学框架描述了多尺度卷积特征图的特征。使用开发的数学框架,我们计算了不同卷积和汇集操作下的特征图的感受野和空间尺度。我们展示了汇集操作的重要性,以确保要素地图的空间比例作为图层深度的函数呈指数增长。此外,我们观察到,如果没有嵌入到 CNN 中的池化操作,要素地图空间比例只会随着图层深度的增加而线性增长。我们引入空间尺度轮廓作为 CNN 的分层空间尺度表征,其可用于评估特征图与训练数据集中对象维度直方图的兼容性。通过计算 ResNet-50 的空间比例剖面图来说明这一使用案例。此外,我们解释了特征金字塔模块如何生成多尺度特征地图丰富了增强语义表示。最后,与常规卷积滤波器相比,虽然扩展卷积滤波器保留了特征图的空间维度,但它们保持了更大的空间尺度指数增长率。
阅读这篇博文,你会更深入地了解最近提出的用于各种视觉任务的 CNN 架构中多尺度卷积特征图用例背后的直觉。因此,这篇博客帖子可以被视为一个教程,以了解不同类型的图层如何影响要素地图的空间比例和感受域。此外,这篇博客文章面向那些参与设计 CNN 架构的工程师和研究人员,他们厌倦了从 CNN 主干中选择哪些特征图来提高其模型的性能的盲目试验和错误,相反,他们更喜欢在设计过程的早期阶段将特征图的空间比例轮廓与训练数据集中的对象维度进行匹配。为了方便这样的用例,我们在 https://github.com/rezasanatkar/cnn_spatial_scale公开了我们的代码库。
介绍
一般的假设和理解是,由 CNN 的早期卷积层生成的特征图编码基本的语义表示,例如边和角,而更深的卷积层在其输出特征图中编码更复杂的语义表示,例如复杂的几何形状。细胞神经网络生成多语义层特征图的这一特性是其基于多层深层结构的分层表征学习能力的结果。具有不同语义级别的特征图对于 CNN 是至关重要的,因为以下两个原因:(1)复杂语义特征图建立在基本语义特征图之上,作为它们的构建块(2)许多视觉任务如实例和语义分割受益于基本和复杂语义特征图。基于视觉 CNN 的架构将图像作为输入,并将其通过几个卷积层,目的是生成对应于输入图像的语义表示。具体而言,每个卷积层输出一个特征图,其中该特征图中编码语义的程度取决于该卷积层及其先前卷积层的代表性学习能力。
CNN 特征图是空间方差
CNN 特征图的一个重要特征是它们是空间方差的,这意味着 CNN 特征图具有空间维度,并且由给定特征图编码的特征可能仅对特征图的空间区域的子集变得活跃。 为了更好的理解 CNN 特征图的空间方差性质,首先我们需要理解为什么全连通图层生成的特征图不是空间方差。由于全连接层的每个神经元都连接到全连接层的所有输入单元,因此由全连接层生成的特征图(可以将给定全连接层的神经元的激活视为其输出特征图)不具有空间维度。因此,不可能定义和考虑神经元激活输出的空间方面。
另一方面,CNN 特征图的每次激活仅连接到几个输入单元,这些输入单元在彼此的空间邻域中。CNN 特征图的这一特性导致了其空间方差特性,这是卷积滤波器的空间局部结构及其空间受限感受野的结果。下图显示了全连接图层和卷积图层之间的差异,这种差异会导致一个图层的空间不变性和另一个图层的空间变化,其中输入图像由绿色矩形表示,棕色矩形表示卷积要素地图。此外,具有两个输出神经元的全连接层由两个蓝色和灰色圆圈表示。如你所见,全连接层的每个神经元受到所有图像像素的影响,而特征图的每个条目只受到输入像素的局部邻域的影响。
此图说明了为什么全连接图层生成的要素不是空间差异,而卷积图层生成的是空间差异要素地图。绿色矩形表示输入图像,棕色矩形表示由 CNN 的卷积层生成的尺寸为 5×7×1 的特征图。另一方面,两个蓝色和灰色圆圈表示具有两个输出神经元的全连接层的激活输出。假设如果输入图像中有自行车,则全连接层的蓝色神经元(特征)将变为活动的,而如果输入图像中有汽车,则灰色神经元(特征)将变为活动的。换句话说,蓝色神经元是自行车特征,而灰色神经元是汽车特征。由于全连接层的性质,即每个神经元的输出受所有输入图像像素的影响,全连接层生成的特征不能编码任何现成的定位信息,以便告诉我们如果输入图像中有自行车,则自行车在输入图像中的位置。另一方面,由卷积层生成的特征图是空间变化的,因此,除了对象的存在信息之外,它们还编码了定位信息。特别地,由卷积层生成的 which 维的特征图包含 C 个不同特征的存在信息(每个通道,特征图的第三维,编码唯一特征的存在信息),其中特征的空间维度 W×H 告诉我们对于输入图像的哪个位置,该特征被激活。在这个例子中,布朗卷积特征映射只编码一个特征,因为它只有一个通道(它的第三维等于 1)。假设这个棕色特征图是自行车特征图,那么只有在输入图像中的该条目的感受域中有自行车时,该特征图的条目才变为活动的。换句话说,如果在输入图像中有一辆自行车,但在其特定的感受域中没有,则该条目不会被激活。卷积特征图的这种特性使得它们不仅能够编码关于输入图像中物体存在的信息,而且能够编码物体的定位信息。
CNN 特征图的空间比例和空间重叠
在本节中,我们正式定义了 CNN 特征地图的空间比例。CNN 特征图具有空间维度,它们的空间比例用于计算它们的条目和输入图像区域之间的空间映射。 特别地,给定 CNN 特征图的条目的空间尺度被定义为影响该特征图条目的值的输入图像的矩形子区域的像素大小 *。*最简单的情况是计算第一层的空间尺度。例如,如果 CNN 的第一层是 3×3 卷积层,那么第一层特征地图的条目的空间尺度是输入图像的 3×3 像素子区域。计算较深 CNN 图层的输出要素地图的空间比例需要知道其输入要素地图的空间比例和空间重叠。在后面的章节中,我们将根据输入要素地图的空间比例和空间重叠,推导出不同卷积和汇集图层的输出要素地图的空间比例和重叠公式。
**这里,空间重叠被定义为两个相邻特征地图条目的空间尺度之间的重叠百分比。**在下图中,我们绘制了两个相邻特征地图条目的空间比例和重叠,其中绿色矩形表示输入图像,棕色矩形表示由 CNN 的一个卷积层生成的特征地图。橙色要素地图条目的空间比例是输入图像上的橙色阴影区域,蓝色要素地图条目的空间比例是输入图像上的蓝色阴影区域。相邻蓝色和橙色条目之间的空间重叠是输入图像上两个空间尺度区域之间的重叠区域。
绿色矩形表示输入图像,而棕色矩形表示由 CNN 网络的一个卷积层生成的尺寸为 5×7×1 的 CNN 特征图。在该图中,该特征图的两个相邻条目用橙色和蓝色标记。橙色要素地图条目的空间比例在输入图像上绘制为橙色阴影区域,而蓝色要素地图的空间比例在输入图像上绘制为蓝色阴影区域。如您所见,蓝色和橙色的空间比例矩形大小相同,并且相互重叠。这两个相邻空间尺度矩形之间的重叠区域的大小与空间尺度区域的大小的比率被定义为空间重叠。
作为计算空间重叠的例子,假设 CNN 的第一层是跨度为 1 的 3×3 卷积层。然后,第一层生成的特征地图将具有 3×3 的空间比例和 9 个像素中的 6 个像素的空间重叠,这是大约 67%的空间重叠。这个重叠百分比是因为选择步幅等于 1。如果步幅选择为 2,则空间重叠将等于 33%,而步幅 3 导致 0%的空间重叠。 一般来说,我们应该避免非常高的空间重叠百分比,因为特征映射条目最终会以计算和存储资源的代价对冗余信息进行编码。另一方面,非常低的空间重叠百分比会导致生成的特征地图条目中的混叠效应。
汇集操作确保要素地图的空间比例呈指数级增长
在本节中,我们将讨论 CNN 如何依靠池化操作来确保要素地图空间比例的指数增长率作为图层深度的函数。首先,我们证明了在 CNN 中不嵌入池操作并且仅依赖于步长为 1 的卷积层导致了特征地图的空间尺度的线性增长率。然后,显示合并图层以实现要素地图空间比例的指数级增长。最后,给出了有和没有汇集操作的两种细胞神经网络变体的案例研究,以说明使用汇集操作对特征地图的空间尺度增长率的影响。
在这里,我们表明,仅由 3×3 卷积层组成的步幅为 1 的 CNN 只能显示特征地图空间比例的线性增长率。仅仅由于输入图像上的 3×3 感受野,第一层特征图的空间比例将是 3×3。步长为 1 的第二层 3×3 卷积的特征映射输出的空间比例将等于 5×5。这是因为第二层特征图的感受野相对于第一层特征图是 3×3,而第一层特征图的感受野也是 3×3,但是相对于输入图像。因此,如果您顺序组合这两个 3×3 感受野,并考虑第一层特征图的相邻条目的感受野的空间重叠,您可以计算出第二层特征图相对于输入图像的空间比例是 5×5。下图显示了这一点,为简化起见,假设输入图像是一维的,卷积层假设为 1 x 3,步长为 1。可以观察到,第二层特征地图的蓝色条目相对于输入图像的空间比例是 1×5。
在该图中,我们展示了 1 x 3 卷积层生成的特征图的空间比例,在 1 维输入图像上应用了步长 1。绿色矩形表示一维输入图像,其中棕色矩形示出了第一卷积层输出的三个相邻特征映射条目,蓝色矩形示出了第二卷积层生成的单个特征映射条目。如您所见,第一层要素地图条目的空间比例为 1 x 3,而第二层要素地图条目的空间比例为 1 x 5。
基于上述示例和归纳,可以表明,以步长 1 添加每个 3×3 卷积层,将沿着每个维度将特征地图的空间比例增加 2 个像素。让 S(n)表示第 n 层要素地图的空间比例。然后,我们可以写出 S(n) = (3 + 2 * (n-1)) x (3 + 2 * (n-1)),这表明空间尺度增长率相对于层深度是线性的。空间比例的这种线性增长率主要是因为相邻要素地图条目的显著空间重叠。如果使用该网络的视觉任务需要相对较大的空间比例特征地图,则空间比例的线性增长率将是一个问题。例如,为了将最终特征图(由网络的最后一个 CNN 层生成的特征图)的空间比例增加到输入图像的 40×40 像素,那么 CNN 网络需要大约 20 个 3×3 的 CNN 层。由于在训练和推断期间卷积层的计算成本,在大多数情况下,我们宁愿避免仅仅为了满足特征地图的空间比例要求而增加越来越多的卷积层。
联营业务
在大多数 CNN 架构中,卷积层与池操作交错,以通过减少特征地图条目之间的空间重叠来增加特征地图的空间尺度的增长率。将空间尺度的增长率提高到超过线性增长率,使我们能够节省仅仅为了更大的空间尺度而增加更多的卷积层。我们可以通过显式池层或选择大于 1 的卷积滤波器步长来实现池操作。最常见的池层是跨度为 2 的 2 x 2 最大池层。该池图层将要素地图的空间维度减半,这意味着它将大小为 W x H x C (W x H 表示要素地图的空间维度,C 表示要素地图的通道数)的输入要素地图转换为大小为 W/2 x H/2 x C 的输出要素地图。将要素地图的空间维度减半的主要动机是减少相邻要素地图条目之间的空间重叠。
跨度为 2 的 2 x 2 池图层的空间比例和重叠
在本节中,我们将根据输入要素地图的空间比例和重叠程度,推导出跨距为 2 的 2 x 2 池图层的输出要素地图的空间比例和重叠公式。让 S 和 P 分别表示输入特征地图的空间比例和空间重叠。此外,s '和 p '表示最大池图层的输出要素地图的空间比例和空间重叠。我们可以计算 S(S,P)= S+2(1-P)S+(1-P)S =(2-P)S。S
等式是基于以下事实得出的:由最大池化图层生成的要素地图条目的空间比例将等于其 4 个相应输入相邻要素地图条目的空间比例的总和,其中(1-P)和(1-P)因子确保 4 个输入条目的联合空间比例的每个子区域仅计数一次。
为了进一步阐明 2 x 2 池化图层的空间比例公式的推导过程,我们在下图中演示了其背后的推理过程。绿色矩形表示输入影像,而棕色矩形表示池图层的输入要素地图(尺寸为 5 x 7 x 1),蓝色矩形表示池图层的输出要素地图(尺寸为 3 x 4 x 1)。为了说明 s’的推导,我们考虑输出特征图的单个条目(用灰色标记)。灰色条目的空间比例取决于其 4 个相应输入要素地图条目的空间比例和重叠,如下图所示。不失一般性,我们可以假设 S` = S + 2(1-P)S + (1-P) S 中的第一项 S 对应于输入要素的橙色条目的空间比例。此外,第二项 2(1-P)考虑了输入要素地图的蓝色和紫色条目的空间比例,其中因子(1-P)用于确保它们不会与橙色条目的空间比例重叠。最后,项(1-P) S 对应于输入要素地图的黑色条目,其中因子(1-P)用于确保黑色条目的有效空间比例不会与橙色、蓝色和紫色条目的已计数空间比例重叠。
2 x 2 汇集图层空间比例公式推导演示。绿色矩形表示输入图像;棕色矩形表示稍后池化的输入要素地图,蓝色矩形表示池化图层的输出要素地图。橙色输出条目的空间比例是输入影像上标记的 4 个区域的联合,这 4 个区域对应于 4 个相邻输入要素地图条目的空间比例。
另一方面,在应用 2×2 最大汇集之后,每两个相邻条目之间的空间重叠的绝对值将等于 2PS-P S=P(2-P)S,其中 2PS 来自于两个相邻输出条目的 2×2 感受域通过两对输入条目相邻的事实。最后,我们需要减去 P S 以避免重复计算重叠的子区域。
下图说明了计算跨度为 2 的 2 x 2 最大合并图层的绝对空间重叠的上述推理,其中绿色矩形表示输入影像,棕色矩形表示合并图层的输入要素地图,蓝色矩形表示合并图层的输出要素地图。在此图中,不失一般性,我们关注用灰色和橙色标记的两个输出相邻条目的空间重叠。注意,由于步幅 2,这两个条目的感受野没有明显的重叠。但是,基于它们的输入相邻对,它们在空间尺度上具有有效的重叠。特别地,灰色输出条目的蓝色输入条目与橙色输出条目的绿色输入条目相邻,而灰色输出条目的黑色输入条目与橙色输出条目的红色输入条目相邻。2PS-P S 的绝对重叠被标记为输入图像上的紫色虚线区域。每个相邻对(蓝、绿)和(黑、红)在绝对空间尺度的最终值中贡献一个 P S 项,而减去 PS 是为了确保我们不会对重叠的空间尺度计数两次。
演示步幅为 2 的 2 x 2 池层的空间重叠推导。绿色矩形表示输入图像,而棕色矩形表示输入特征图,蓝色矩形表示输出特征图。相邻灰色和橙色输出条目之间的绝对空间重叠在输入图像上显示为紫色虚线区域。
空间重叠 P′等于绝对空间重叠 P(2-P)S 除以 S′。所以我们有 P`(S,P) = P(2-P)S/((2-P) S)=P/(2-P)。这个结果是有意义的,因为它表明 P’总是小于 P,这表明跨距为 2 的 2×2 汇集层将总是减少相邻特征地图条目之间的空间重叠。例如,如果在应用合并操作之前,空间重叠为 2/3,那么在应用合并操作之后,空间重叠将减少到 2/4。
跨度为 1 的 3×3 卷积层的空间比例和重叠
这里,我们依靠与上一节中讨论的相同的推理路线,来推导步长为 1 的 3×3 卷积层的空间比例和重叠公式。让 S 和 P 表示输入要素地图条目的空间比例和重叠。此外,让 s′和 p′表示在步长为 1 的 3×3 卷积滤波器输出端的特征映射入口的空间比例和空间重叠。然后,我们可以将 3 x 3 卷积层的空间比例计算为 S`(S,P) = S + 4(1-P)S + 4(1-P) S。接下来,我们重点计算空间重叠。特别是,计算步长为 1 的 3 x 3 卷积滤波器的输出要素地图的绝对空间重叠比计算步长为 2 的 2 x 2 合并图层的空间重叠更简单,如下图所示。
在下图中,绿色矩形表示输入图像,而棕色和蓝色矩形表示步长为 1 的 3 x 3 卷积层的输入和输出特征图。注意,步长 1 导致特征图的空间维度不变,因此输入和输出特征图的空间维度都是 4 x 6 x 1。在此,不失一般性,我们着重于计算相邻灰色和橙色输出要素地图条目之间的空间重叠。由于步幅 1,这两个输出条目在输入特征图上的重叠感受野是 3×2,并由棕色输入特征图上的紫色阴影区域表示。
这个 3×2 的显式重叠区域简化了计算灰色和橙色输出条目之间的空间重叠的绝对值。特别是,它们的绝对空间重叠等于属于 3 x 2 紫色重叠区域的输入要素地图条目的聚合空间比例。可以看出,绝对空间重叠等于 S + 3(1-P)S + 2(1-P) S。在该示例中,在输入图像上被标记为蓝色阴影区域的项 S 对应于紫色阴影区域的第二行第一列上的条目。此外,3 个术语(1-P)在输入图像上用黑色、红色和绿色区域标记,并且相对于第二行和第一列上的条目对应于顶部、右侧和底部条目。最后,2 个术语(1-P)在输入图像上被标记为棕色区域,并且对应于紫色重叠区域的右上和右下条目。因此,空间重叠 P(S,P)=(S+3(1-P)S+2(1-P)S)/S
=(1+(1-P)(5–2P))/(1+4(1-P)(2-P))。
演示步长为 1 的 3 x 3 卷积层输出特征图的空间重叠计算。绿色矩形表示输入图像,而棕色矩形表示到 3×3 卷积层的输入特征映射,蓝色矩形表示 3×3 卷积层的输出特征映射。输入棕色特征图上方的紫色阴影区域表示两个相邻输出特征图条目灰色和橙色的感受野的 3×2 重叠区域。这两个相邻输出条目之间的绝对空间重叠被标记为输入图像上 6 个区域(蓝色、黑色、红色、绿色、棕色和棕色)的并集。
案例研究-具有 20 个 3 x 3 卷积层的 CNN
通过使用步长为 1 的 3 x 3 卷积图层和步长为 2 的 2 x 2 最大合并的派生空间比例和重叠公式,我们展示了应用合并图层以增加要素地图条目的有效空间比例的重要性。对于我们的示例,我们考虑 20 层 CNN 的以下两种变化:(1)20 层 CNN,具有 20 个 3×3 CNN 层,跨度为 1,没有池层,下图中的蓝色曲线(2)20 层 CNN,具有 20 个 3×3 CNN 层,跨度为 1,与 2×2 最大池层交错,跨度为 2,每 4 个 CNN 层,下图中的红色曲线。
在下面绘制的曲线中,x 轴是图层深度,y 轴是由 CNN 图层在 x 轴指定的深度生成的要素地图条目的空间比例宽度(空间比例的宽度等于空间比例的平方根)。如您所见,在这两种情况下,要素地图条目的空间比例都会随着图层深度的增加而增加。然而,具有汇集层的 CNN(红色曲线)的空间比例增长率是指数的,而没有汇集层的 CNN(蓝色曲线)的空间比例增长率是线性的。具有合并图层的 CNN 的空间比例的指数增长率导致其最终要素地图条目具有 243 x 243 的空间比例,而没有合并图层的 CNN 的最终要素地图条目的空间比例仅增长到 50 x 50。这意味着由具有汇集层的 CNN 生成的特征地图可以编码在输入图像中捕获的大到 243 x 243 像素的对象,而没有汇集层的 CNN 只能编码大到 50 x 50 像素的对象。
两个都具有 20 个 3x3 CNN 层的 CNN 的空间尺度的比较;红色曲线:每 4 个 3x3 CN 层 2x2 最大池化;蓝色曲线:只有 3x3 CNN 层,没有池。x 轴:层深;y 轴:特定于图层的空间比例宽度。具有汇集的 CNN 的空间尺度增长率是指数的,而没有汇集的 CNN 的空间尺度增长率是线性的。
空间比例剖面
在设计 CNN 架构时,有必要聚集训练数据集中的对象维度的统计,并检查所设计的 CNN 架构的特征图是否提供了跨越对象维度直方图的所有主要模式的空间尺度。 我们称 CNN 的逐层空间尺度,为其空间尺度轮廓。作为最佳实践,有必要首先基于训练数据集的对象维度直方图来设计空间尺度轮廓,然后根据空间尺度轮廓要求来设计 CNN 架构。
例如,在这里,我们计算 ResNet-50 (50 层)的空间比例剖面。如前所述,CNN 架构中的池化操作可以通过使用显式池化层或选择大于 1 的卷积滤波器步长来实现。对于 resnet(用于图像识别的深度残差学习),跨距大于 1 的 CNN 卷积滤波器和显式池层都用于减少相邻特征地图整体之间的空间重叠。在用于图像识别的深度残差学习中给出的 5 种 ResNet 架构(下表所示的 18 层、34 层、50 层、101 层和 152 层)中,我们导出了 ResNet-50 的空间尺度轮廓。然而,给出的结果可以很容易地扩展到其他 4 个配置。在 ResNet50 中,使用了三种类型的池操作:(1)步长为 2 的 7×7 卷积滤波器(2)步长为 2 的 3×3 最大池层(3)步长为 2 的 1×1 卷积滤波器。
ResNet-18、ResNet-34、ResNet-50、ResNet-101 和 ResNet-152 配置。对于 ResNet-50,下采样按以下顺序执行:第一层(跨度为 2 的 7x7 卷积层)、第二层(跨度为 2 的 3x3 最大池层)和跨度为 2 的 1x1 卷积层,作为 conv3_1、conv4_1 和 conv5_1 块的第一层。
跨距为 2 的 7×7 卷积层仅被用作 ResNet-50 的第一层。因此,可以简化其输出空间比例和重叠计算。特别地,7×7 卷积滤波器的每个特征映射入口输出的空间尺度是 7×7,因为它们直接应用于输入图像。此外,相邻要素地图条目之间的绝对空间重叠等于 7 x 5。因此,其相应的空间重叠将等于(7×5)/(7×7)= 5/7。
跨距为 2 的 3 x 3 最大池层仅用作 ResNet-50 的第二层。让 S 和 P 分别表示输入特征地图条目的空间比例和重叠,S’和 P’表示输出特征地图条目的空间比例和空间重叠。3 x 3 汇集图层的空间比例等于 3 x 3 卷积图层的空间比例。因此,我们得到 S(S,P) = S + 4(1-P)S + 4(1-P) S。另一方面,我们需要使用我们已经针对其他图层讨论过的相同技术,推导出跨度为 2 的 3 x 3 池图层的空间重叠。我们可以将空间重叠计算为:P
(S,P) = (1+ 2(1-P)) / (1+4(1-P)(2-P))。
在 ResNet-50 的不同深度使用了跨度为 2 的 1 x 1 卷积层作为主要汇集操作,以减少相邻要素地图条目之间的空间重叠,并确保要素地图条目的空间比例呈指数增长。接收域为 1×1 的 1×1 卷积滤波器在应用于特征地图时不会改变特征地图条目的空间比例。但是,跨距为 2 时,它们会修改要素地图条目的空间重叠。设 P 和 P’分别表示应用步长为 2 的 1×1 卷积层之前和之后的特征映射条目的空间重叠。然后,我们可以计算 P`(S,P) = 2 max(P - 0.5,0)。这意味着,如果输入特征映射表项的空间重叠小于 0.5,则输出特征映射表项的空间重叠将为零,因为 1×1 卷积滤波器的感受域仅为 1×1,并且步长 2 确保它们相邻的输出表项没有重叠的感受域。因此,为了具有非零的空间重叠,必须从网络的前几层进行。
下图绘制了 ResNet-50 的空间比例剖面图,其中 x 轴横跨 ResNet-50 的各层,y 轴表示 ResNet-50 各层的空间比例宽度(空间比例宽度等于空间比例的平方根)。可以看出,ResNet-50 中使用的汇集操作导致 ResNet-50 的空间规模以指数速度增长,这是层深度的函数。特别地,由 ResNet-50 生成的最终特征图具有 483×483 像素的空间比例,这意味着其特征图条目对嵌入在输入图像中的大至 483×483 像素的对象的表示进行编码。此外,我们观察到 ResNet-50 的空间尺度是分段常数,这是由主要在 ResNet-50 中使用的步长为 1 的 1×1 卷积层引起的,以对特征图进行通道维度缩减。
ResNet-50 的空间比例剖面图,其中 x 轴横跨 ResNet-50 的各层,y 轴表示 ResNet-50 各层的空间比例。ResNet-50 的空间尺度剖面显示,作为层深的函数,逐层空间尺度呈指数增长。
多比例特征地图
在本节中,我们将讨论为什么针对不同视觉任务的大多数 CNN 架构依赖多尺度特征图来提高其检测、分类和回归性能。答案相当简单明了。在自然图像中捕获的对象以各种像素维度来表现它们自己。例如,如果一辆汽车距离摄像机 5 米远,那么与它距离摄像机 50 米远的情况相比,它在图像中显得更大。因此,对于这个示例,我们需要两个具有不同空间比例的特征地图,其中一个适用于汽车距离摄像机 5 米的情况,另一个适用于汽车距离摄像机 50 米的情况。注意,即使具有较大空间比例的特征地图(当它离摄像机 5 米远时匹配汽车图像)也能够封装当它离摄像机 50 米远时的汽车图像,但是它不能为 50 米远的汽车提供准确的表示,因为它在图像汽车周围的空间比例不够紧密,并且包含来自场景中其他物体的大量信息泄漏。
在具有不同像素维度的图像中出现的对象的问题被称为图像的*,并且连同遮挡和相机视点变化一起,使基于视觉的检测系统变得复杂。设计用于解决图像比例模糊的最著名的非基于 ML 的方法是比例不变特征变换 (SIFT)。可以说,SIFT 一直是深度学习多尺度特征地图图像编码器的主要灵感。SIFT 依靠图像金字塔(将输入图像调整到不同的比例,并在处理输入图像的每个比例版本后聚合检测到的关键点)和具有不同σ的高斯平滑滤波器来检测不同比例的斑点,作为输入图像的关键点。当自然图像中存在尺度模糊时,检测具有不同尺度的斑点使得 SIFT 生成可靠的图像编码。*
由对应于输入图像的给定 CNN 生成的语义表示是由 CNN 的每个卷积层生成的所有特征图的联合,而不仅仅是最终特征图。依靠几幅特征图提供不同空间尺度的网络。
用于目标检测模型的多尺度特征图
可以肯定地说,在基于 CNN 的视觉模型领域,多尺度特征图的优势最初表现在 2d 对象检测模型上。特别是 SSD:单次多盒探测器依靠 VGG-16 作为骨干网络(特征生成器),通过 6 个不同空间尺度的特征图对输入图像进行编码。特征图的不同空间尺度允许 SSD 检测嵌入在输入图像中的具有不同像素维度的对象。
再如,用于目标检测的特征金字塔网络 (FPN)使用 ResNet-50 和 ResNet-101 作为主干网络来生成多尺度特征地图。在 ResNet-50 的情况下,选择 conv2_3(第 11 层)、conv3_4(第 23 层)、conv4_6(第 41 层)和 conv5_3(第 50 层)的特征地图输出,以提供不同空间比例的特征地图。使用我们在上一节中介绍的 ResNet-50 的空间比例配置文件,我们可以将 conv2_3、conv3_4、conv4_6 和 conv5_3 的输出要素地图的空间比例分别计算为 35 x 35、99 x 99、291 x 291 和 483 x 483。因此,所选择的特征图可以表示输入图像中出现的不同大小的对象。
然而,FPN 的主要贡献是利用深层特征图中编码的语义信息,增强了浅层特征图的语义表示能力。 浅层生成的特征图的主要弱点是语义不如深层生成的特征图丰富。是因为输入图像的语义编码到特征图的过程是一个层次化的过程,意味着基本语义出现在早期的层特征图中,而更复杂的语义出现在更深层的特征图中。
为了更好地理解为什么这将是对象检测模型的一个问题,考虑以下以 ResNet-50 作为主干网络的例子。假设一辆汽车距离摄像机 50 米,它是通过一个 35×35 像素的方框在输入图像中捕获的,因此由 conv2_3(第 11 层)生成的特征图是对其进行编码的最佳候选。此外,假设第二辆汽车距离摄像机 5 米远,并且其在输入图像中的对应框具有 480×480 像素的尺寸,因此 conv5_4(第 50 层)最适合对其进行编码。有理由假设这两辆车具有相似的语义复杂度,与它们在输入图像中的大小无关。但是,我们知道 ResNet-50 的第 11 层在语义上不如 ResNet-50 的第 50 层丰富。
FPN 使用自上而下的路径来解决这个问题,该路径经由最近邻上采样操作将由较深层编码的语义传送到较浅层,以确保传送的较深特征地图的空间维度与较浅特征地图的空间维度相匹配(较浅层特征地图具有更大的空间维度,其特征在于较深层的地图)。下图演示了这一过程。来自较深层和较浅层的语义的合并通过在 1×1 横向卷积层下较深层的上采样特征图和较浅层特征图的变换版本的逐元素相加来实现。最后,为了确保由这些元素相加操作生成的特征图不会受到混叠效应的影响,它们使用 3×3 卷积层进行过滤。
FPN 模块,通过右侧自上而下的分支将较深层的丰富语义转移到较浅层。
扩张的回旋
在本节中,我们将重点介绍 2016 年首次推出的扩张卷积层(通过扩张卷积进行多尺度上下文聚合)。与常规卷积滤波器不同,扩展卷积滤波器对输入特征图进行稀疏采样,以增加输出特征图的空间比例。因此,您可以将它们视为跨距大于 1 的池图层和卷积图层的替代方案,以增加 CNN 要素地图的空间比例。扩展卷积滤波器基于嵌入在它们的卷积滤波器中的孔来执行输入特征图的稀疏采样,这不同于没有孔并且依赖于输入特征图的密集局部采样的常规卷积滤波器。
为了更好地理解如何将膨胀卷积滤波器应用于输入要素地图,在下图中,我们在左侧(红色标记)显示了常规 3 x 3 卷积滤波器的卷积运算,在右侧(蓝色标记)显示了膨胀率为 2 的膨胀 3 x 3 卷积滤波器的卷积运算。如您所见,扩展卷积滤波器通过跳过(跳过被称为孔洞)每个维度中的每隔一个输入条目来对其输入要素图执行稀疏采样。换句话说,膨胀率为 2 意味着卷积滤波器对输入特征图的每个 2 x 2 区域只采样一个条目。因此,一般来说,n 的膨胀率相当于对输入特征图的每个 n×n 区域采样一个条目。注意,常规卷积滤波器是膨胀率为 1 的膨胀卷积滤波器的特例。
左:常规 3 x 3 卷积滤波器,右:膨胀率为 2 的膨胀 3 x 3 卷积滤波器
扩张卷积依赖于其感受野中的孔来增加其输出特征地图条目的空间比例。具体而言,扩展卷积滤波器的感受域中的空洞(跳跃)减少了采样的输入特征映射表条目之间的空间重叠,这导致输出特征映射表条目的空间比例增加。在上面的例子中,扩张率为 2 的扩张卷积滤波器在每两个连续的采样条目之间跳过一个特征映射条目,这导致采样特征映射条目之间的空间重叠减少。如果相邻输入要素地图条目之间存在非零空间重叠,则扩展卷积滤波器的有效空间比例将大于常规卷积滤波器的空间比例。
在这里,首先,我们推导出计算步长为 1、扩展速率为 2 的扩展的 3×3 卷积滤波器的空间尺度和重叠的公式,然后,我们将它们的空间尺度的增长率与步长为 1 和 2 的常规 3×3 卷积滤波器的增长率进行比较。让 S 和 P 分别表示输入要素地图的空间比例和重叠。此外,让 s’和 p’分别表示跨距为 1 和扩张率为 2 的扩张的 3×3 卷积滤波器的输出特征图的空间比例和重叠。然后,对于 P < 0.5, then S will be equal to 9 times of the input spatial scale S, which is the maximum increase in spatial scale that we can expect from dilated 3 x 3 convolution filters with dilation rate of 2\. In order to compute P
, two formulas are derived based on whether P < 0.5 or P > 0.5 的特殊情况,我们可以计算出 S(S,P) = 9S - 24Max(P - 0.5,0)S .如果 P < 0.5, then P
(S,P) = 15P / [9 — 24Max(P — 0.5, 0)] and if P > 0.5,那么 P`(S,P)=[6+3(1-P)-(14+4(1-P))Max(P-0.5,0)]/[9–24 Max(P-0.5,0)]。
接下来,我们比较了步长为 1 和扩张率为 2 的扩张型 3×3 卷积滤波器与步长为 1 和 2 的常规 3×3 卷积滤波器的空间尺度增长率。在下图中,我们根据图层深度绘制了对比图。蓝色曲线指的是一个 5 层卷积网络,其中所有 5 层都是步长为 1、膨胀率为 2 的膨胀卷积层。红色曲线是由 5 个步长为 2 的规则 3×3 卷积层组成的 5 层卷积网络,绿色曲线对应的是由 5 个步长为 1 的规则 3×3 卷积层组成的 5 层 CNN 网络。y 轴表示分层空间尺度宽度,其中空间尺度宽度等于空间尺度的平方根。
正如可以观察到的,具有步距 1 和扩张率 2 的扩张的 3×3 卷积层和具有步距 2 的常规 3×3 卷积层都显示了作为层深度的函数的空间尺度的指数增长率,而具有步距 1 的常规 3×3 卷积层的增长率是线性的。也就是说,扩张的 3×3 卷积层的空间尺度增长率大于步长为 2 的常规 3×3 卷积层的空间尺度增长率。特别地,扩展卷积层的最终特征图的空间比例是 243×243 像素,而跨度为 2 和 1 的 3×3 卷积层的最终特征图的空间比例分别等于 63×63 和 11×11。
步长为 1 且扩张率为 2 的扩张的 3×3 卷积层、步长为 2 的常规 3×3 卷积层和步长为 1 的常规 3×3 卷积层的逐层空间尺度宽度的比较。x 轴表示层深度,而 y 轴表示对应于每个层的空间尺度宽度。虽然步长为 1 且扩张率为 2 的扩张的 3×3 卷积层和步长为 2 的常规 3×3 卷积层都显示了作为层深度的函数的空间尺度的指数增长率,但是步长为 1 的常规 3×3 卷积层仅显示了空间尺度的线性增长率。
尽管步长为 2 的常规 3×3 卷积滤波器显示了与扩展卷积滤波器相似的空间尺度的指数增长率,但是步长为 2 的常规卷积滤波器在每次将特征地图应用于特征地图时都会导致特征地图的空间维度(宽度和高度)减半。如前所述,合并操作(如跨距大于 1 的显式合并层和跨距大于 1 的卷积层)依赖于降低要素地图的空间维度,以增加要素地图条目的空间比例。另一方面,扩张卷积滤波器基于它们的步幅 1 保持特征图的空间维度。 保持特征图的空间维度,同时通过扩张卷积滤波器以指数增长率增加其空间尺度,使其能够兼容具有密集预测的视觉任务。
具有密集预测的视觉任务的例子是语义分割、实例分割、深度估计和光流。例如,在语义分割的情况下,目标是对每个输入图像像素的类别进行预测。换句话说,如果输入图像是 W×H 像素,那么为语义分割设计的 CNN 预计会为像素类生成 W×H 预测。与执行像图像分类这样的稀疏检测任务的 CNN 相比,针对这种密集预测的 CNN 需要具有更高分辨率(更大空间维度)的特征图。对于像图像分类这样的稀疏预测视觉任务,CNN 只需要为整个输入图像输出单个预测,因此高分辨率特征图不像密集预测任务那样重要。
对于密集预测视觉任务,每个像素对应的预测既要基于嵌入在该像素局部邻域的信息,也要基于称为图像上下文的全局信息 。例如,考虑单目(单个相机)深度估计任务,像像素是建筑物的一部分这样的全局信息向网络提供像素深度的粗略估计,而像纹理这样的局部特征帮助网络进一步改进其对像素深度的估计。 保持特征图中像素的局部邻域信息需要卷积层保持特征图的空间维度,这就是为什么步长为 1 的扩张卷积滤波器对于密集预测视觉任务是必不可少的。
步长为 1 的扩展卷积滤波器保持了特征图的空间维度,这不足以确保由这些卷积滤波器生成的特征图准确地编码了像素的局部邻域信息。特别是,我们需要步长为 1 的扩展卷积滤波器将它们的空间比例限制在局部邻域内。也就是说,具有显著的空间尺度指数增长率的扩张卷积滤波器也适用于编码全局图像上下文信息。 事实上,一个设计良好的 CNN 网络受益于并行的具有一系列不同膨胀率的膨胀卷积滤波器,以编码一组具有一系列不同空间尺度的特征图,从而同时表示局部和全局信息。 这种思想被用在下面的论文中。
在用于单目深度估计的深度有序回归网络中,他们使用三个平行的膨胀卷积层(下图中称为 ASPP 模块)生成不同空间尺度的特征图,其核大小为 3×3,膨胀率为 6、12 和 18。这三个具有不同膨胀率的卷积层被应用步长 1 和零填充,以确保它们的输出特征图具有相同的空间维度,以便沿着它们的信道维度被连接。由这 3 个扩展卷积层生成的特征图的逐通道级联的统一特征图结果是具有 3 个不同空间尺度的多尺度特征图,其对特征图的每个条目的局部和全局信息进行编码。
由 ASPP 表示的三个平行分支是 3×3 的扩张卷积层,扩张率为 6、12 和 18。
下一步
该项目的下一步是为更多数量的卷积和汇集层变体导出空间比例和重叠公式,并将它们添加到代码库中。
Billboard 下一首热门歌曲的分析与预测(上)
利用 Spotify 和 Billboard 的数据来理解是什么让一首歌成为热门。
图片来自https://www . max pixel . net/Circle-Structure-Music-Points-Clef-Pattern-Heart-1790837
每年有成千上万的歌曲在世界各地发行。有些在音乐界非常成功;其他人不太喜欢。事实上,在这个行业取得成功仍然是一项艰巨的任务。投资制作一首歌需要各种活动,会消耗大量资源。很少有唱片公司会资助研究,以发现他们即将发行的歌曲在多大程度上可能成为音乐热门。
我对音乐的好奇心促使我花一些时间研究这个课题。对许多人来说,德雷克近年来成功的秘诀是他作为艺术家的风格;对其他人来说,这主要是因为他的恶名。一般来说,在解释为什么一首歌很受欢迎,而另一首却不是的时候,观点并不是单向的;或者一个艺术家在创作一首歌的时候应该优先考虑什么,如果他想让这首歌红起来的话。
这篇由两部分组成的文章是我在过去几周一直从事的项目的快照。我使用数据科学技术来了解流行歌曲的特征,更准确地说,如何可能仅根据歌曲的音频特征和歌手的个人资料来预测歌曲的流行程度。我建立了一个机器学习模型,可以将一首歌归类为热门与否。
虽然社会因素,如歌曲播放的背景,听众的人口统计数据,以及营销活动的有效性,也可能在它的病毒式传播中发挥重要作用,但我假设歌曲的固有特征,如演唱它的艺术家的简介,它的持续时间,它的音频特征可能是相关的,也揭示了它的病毒式传播。
作者图片
我的数据
我不能从一个单一的来源得到一个包含所有变量的数据集。为了克服这个问题,我借助了数据丰富技术,使用了以下三个数据源:Billboard、Spotify 和 Genius。
先用美人汤收集了 2010-2019 年 Billboard 年终热门 100 首歌曲的列表,以每年 100 首的速度。然后,使用 Spotipy 包来恢复与歌曲音频特征相关的数据,例如可跳舞性、乐器性、活跃度等。,一方面;另一方面,与艺术家的简档相关的那些,例如追随者的数量、受欢迎程度等。对于先前恢复的同一时期的热门歌曲和其他非热门歌曲。
最后, Genius 将主要用于检索已经收集的所有歌曲的歌词。
在我们的数据集中,如果一首歌在报告期内的任何一年中至少一次出现在 Billboard 年终热门 100 强排行榜上,就被认为是热门歌曲。换句话说,我们的模型的任务是预测一首歌是否会进入 Billboard 的 100 首最受欢迎歌曲名单。
使用的工具:
- 从 Spotify 音乐平台获取数据的 Spotify 包
- seaborn 和 matplotlib 用于数据可视化
- 熊猫和 numpy 进行数据分析
- LightGBM 和 scikit-learn 库,用于构建和评估模型
特性
Spotify 是世界上最大的流媒体平台之一。像 Twitter 或脸书一样,它提供了一个 API(应用程序编程接口),以便开发者可以与它庞大的音乐数据库进行交互。通过这个 API 的端点,我能够收集超过 22,000 首歌曲的数据;每首歌都有二十多个变量。
API 返回的变量信息丰富多样。然而,我只选择了那些被认为与工作相关的。然后,使用特征工程技术对它们进行转换,以便为训练模型准备尽可能好的数据集。在这里,您将找到中使用的每个变量的描述。一般来说,项目的完整代码可以通过这个链接访问。
其中一些变量仅用于分析,其他变量则涉及整个流程的各个阶段。现在让我们看看数据集的前五个观察值是什么样的。
我们数据集的前五个观察值,包含来自 24 个变量的 19 182 个观察值。
数据可视化
就在构建模型之前,我想通过可视化来探索一下数据;尽管这项工作的主要目标不是进行全面的探索性分析。
图一
根据上面的图表,一月是发行更多热门歌曲的月份;七月是最少被要求的。我们还注意到,这段时间的大部分点击都发生在一周的第四天;也就是周四。最后,月初一多用来发表一首歌。
基于这一观察,我们可以推断出在 1 月 1 日发表一首歌可能是朝着优化其病毒式传播的机会迈出的一步。我们仍然必须小心:相关性不是因果关系。为了使这一结论更加准确,我们必须进一步分析。
我继续想象,想知道在这段时间里哪些艺术家录制了最多的热门歌曲。不出所料,下图显示,德雷克、蕾哈娜和泰勒·斯威夫特等艺术家在此期间的点击率比其他任何人都高。也就是说,如果一首歌包含这些艺术家之一的声音,它更有可能被广泛传播。
图 2
去理解是什么让一首歌成为热门;而另一个则不然,研究这两个类别的音频相关变量势在必行。这就是我想要得到的,关于这两类变量分布的想法。
图 3
这两个类别中的主要变量是相同的:能量,可舞性和化合价。唯一的区别是,对于热门歌曲类别,这些变量的平均值更高。这证明了热门音乐更快更响亮。他们更适合跳舞,更倾向于激发喜悦、欢乐和兴奋。
机器学习方法
到目前为止,我们已经发现了一些关于数据的有趣见解。为了缩短这篇文章,让我们直接进入关于使用的机器学习算法的部分。
我想建立一个模型,根据一组解释变量来预测一首歌最有可能属于哪个类别,热门还是非热门,正如本文开头所解释的那样。
在其原始状态下,收集的数据还不能用于训练机器学习模型。所以我治疗他们;首先,使用 SMOTE 技术,因为与非热门类别相比,热门歌曲类别的代表性不足,然后通过使用其他特征工程技术来标准化数据。
此外,我想要一个性能尽可能好的模型。为此,我训练了几个算法,并根据选定的评估标准比较了结果。结果表明,LightGBM 分类算法在训练时能够更好地检测出解释变量和待预测变量(hit)之间的模式。
混乱矩阵
对于模型的第一级性能分析,我们将使用混淆矩阵。混淆矩阵的可视化将允许我们理解我们的分类器与测试子集相比所产生的错误。
这个矩阵衡量一个分类系统的质量。在二元分类中,主对角线代表被模型正确分类的观察值;和次对角线,那些分类不正确的。因此,该模型最常犯的错误是将一首歌曲分类为非热门歌曲,而实际上它是热门歌曲(129 例),更准确地说是第二类错误。
第一类错误是模型把宋在非命中(误命中)的情况下归类为命中;而第二类错误,则相反;也就是说,它将一首音乐分类为未命中,但它却被命中(假未命中)的情况。如果我们试图理解一个音乐制作人的心理,第一类错误比第二类错误更不可接受。我们不想承担与制作和推广一首歌曲相关的所有费用,因为一个模特已经预测这首歌会很受欢迎,但最终却不会。类型 I 误差的值应该是最小的。
分类报告
分类报告显示从混淆矩阵中的数据计算出的统计数据。每个指标描述了分类的不同方面。我们将使用此报告对模型进行二级性能分析。
准确度是 96%,它全面衡量了模型执行的正确分类的百分比。由于测试子集是不平衡的,这个百分比被过度表示的类(在本例中为非命中类)拉伸。所以这个指标不是我们能使用的最好的。
召回衡量模型对每个类别正确分类的事件的百分比。当预测类别与实际类别匹配时,分类是正确的。一方面,从我们用来测试模型的 5484 首非热门歌曲中,98%被正确分类。另一方面,该算法只正确分类了我们提交给它的 271 首热门歌曲中的 52%。你就明白了:算法把一首热播的歌归类为热播(真热播)比把一首非热播的歌归类为非热播(真非热播)更难。
非命中类和命中类的精度级别分别为 0.98 和 0.55。这意味着模型归类为非热门的所有歌曲中的 98%实际上都是非热门的;而且,只有 55%它预测会成功的歌曲是真的。
当涉及到非热门歌曲时,我们的模型反应更好。这很可能是因为从一开始这个类就有更多的数据。因变量的非命中模态和其他解释变量之间的模式检测可能因此而受到青睐。
一旦对模型的表现感到满意,我就决心去了解在确定一首给定歌曲的类别时最有影响力的解释变量。这就是为什么我在下面使用了情节重要性。
图 4
我们可以看到,一首歌在 Spotify 上的受欢迎程度是预测它最有可能属于哪个类别的过程中最重要的变量。然后,艺术家在 Spotify 上的受欢迎程度、他的粉丝数量以及这首歌在哪些市场上销售,构成了这一过程中的第二波决定性变量。最后主要是与具有相对相似影响水平的歌曲的音频相关的变量。
这一分析引起了人们对一些重要问题的关注。从本质上来说,如果一首歌在 Spotify 上很受欢迎,由一位在 Spotify 上也很受欢迎并拥有大量粉丝的艺术家演唱,最后,如果这首歌在世界上最大数量的国家都能听到,那么这首歌就是热门歌曲。这个结论似乎是合乎逻辑的,而且……🙂我们的模型也验证了这一点。
为了更好地理解这一结论的相关性,应该记住,Billboard 的年终 100 首音乐排行榜主要基于商业方面。事实上,这个排名忠实地反映了美国的实物和数字销售、广播收听和音乐流媒体;所有直接或间接的创收活动。
这首歌在 Spotify 上越受欢迎,在线收听的次数就越多。;更多的流媒体可以转化为更多的收入,因为在用户听完每首歌曲后,流媒体平台会向艺术家或音乐公司支付费用。这位艺术家在 Spotify 上的受欢迎程度以及他在 Spotify 上的粉丝数量,这些渠道放大了流量和销售额,这将有助于增加他的音乐带来的收入。
音乐产生的收入越多,它就越有可能在年底登上 Billboard 的 100 首音乐排行榜;因此,它也越有可能被我们的模型排名命中,因为根据我们的重要性图,主要决定音乐收入水平的变量在排名过程中最有影响力(逻辑,不是吗😉?).
通常,歌曲还有一个我们还没有考虑到的重要特征:歌词。是否可以通过使用歌词来进一步增加模型的性能?这是我们将在文章的第二部分探讨的内容。
一如既往,我欢迎建设性的批评和反馈。你可以在 Twitter @ jbobym 上找到我。