解读大学录取
Photo by Pang Yuhao on Unsplash
我们大多数人都会同意,大学入学可能是一个高度偏见的过程,普遍缺乏透明度。一年前对申请人有效的方法,一年后可能就完全无效了。就其本身而言,这并不奇怪。一所大学的需求每年都会发生变化。有一年,他们可能需要一个出色的四分卫。下一年,也许会是一个优秀的赛跑运动员或物理明星学生。这些需求会以我们永远不知道的方式指导招生委员会。例如,在许多学校,遗产和运动员有优势(尽管很难衡量有多少)。
至少可以说,最近关于招生过程中作弊的新闻破坏了它的可信度。因此,我决定以数据驱动的方式研究大学招生。鉴于录取过程缺乏透明度,我从看 SAT 成绩开始。SAT 考试的设计可能并不完美,但它确实给了我们一个一致的指标来分析。
获取数据
我使用了谷歌的数据集搜索,这是一个追踪数据的神奇工具。我刚刚搜索了“加州 SAT”,最初的几个结果是不同学年的 SAT 报告,最近的是 2015-2016 年的加州 SAT 报告,可从 data.world 下载。数据集显示了加州每所学校的平均分数。(为了保持匿名,数据集不包括参加考试的学生少于 15 人的学校的分数。)
探索和可视化分数
SAT 的最高分数为 2400 分,阅读、写作和数学三个独立的部分的分数从 200 到 800 不等。
数据集中的一列显示了得分大于或等于 1,500 分的学生的百分比。我决定将每个学校的百分比按县分组,然后取每个县的平均值。对于 1500 分及以上的分数,平均百分比最高的五个县是:
内华达州——67.8%
阿玛多——65.6%
马林——65.2%
埃尔多拉多——62.4%
圣马特奥——60.5%
平均百分比最低的五个县是:
默塞德——21.1%
Colusa——23.6%
弗雷斯诺——24%
图莱雷——24.9%
河边——27.4%
California Counties Average Percentage of Students with SAT Higher than 1,500.
California Counties Average Total SAT Score.
我决定也看看各县 SAT 的平均总分,换句话说,就是各县三个部分(阅读、写作和数学)的平均分数之和。由于总分在 600-2,400 之间,所以我除以 2,400,再乘以 100,以百分比的形式查看这一指标。同样,我们看到了相同的高点和低点的一般模式:
内华达州——67.3%
马林——66.9%
圣克拉拉——66.9%
圣马特奥——66.6%
埃尔多拉多——66%
…与…相比
Merced——54.7%
弗雷斯诺——54.9%
图莱雷——55.4%
因约——55.6%
河边——55.8%
我发现平均总分最高的来自圣克拉拉县:85.3%。这是 2400 分中的 2043 分。在圣克拉拉县,最高分来自弗里蒙特联合高中学区的蒙他维斯塔高中。我能够使用 Zillow 来验证结果的准确性,它提供了大量组织良好的学校信息。不足为奇的是,Zillow 将蒙他 Vista 排在了十分之十的位置。(我展示的是 2017 年的结果,但在 Zillow 应用中,你可以看到过去 3 年的结果。)
在后续的文章中,我将探索每个学校或地区的房地产价格数据的相关性。我怀疑有一个很强的。
SAT 部分之间的相关性(阅读、写作和数学)
我怀疑数学部分分数高的学生在阅读和写作方面的分数会更低。我能够通过计算阅读、写作和数学考试之间的线性相关性来探索这个想法。我错了。事实上,配对(数学,阅读)和(数学,写作)之间的线性相关性都相当强,正如你在下面的图中所看到的。我想知道这种强烈的相关性是否也适用于 GRE 成绩,在 GRE 考试中,更大比例的考生是非英语母语者。
Correlations Between Reading, Writing and Math SAT Scores Sections
摘要
由于公共数据很少,解读大学录取很难。作为替代,我查看了加州 2015 年至 2016 年的 SAT 成绩,以探索其在县、区和学校的分布情况。我还观察到 SAT 分数的不同部分之间的相关性很强。换句话说,在某一方面表现出色的学生在其他方面也会表现出色。对于这一探索的第二个阶段,我很高兴引入县的财产成本和学校水平,以了解它们与 SAT 分数的关系。
特别感谢史蒂夫·摩尔对这篇文章的大力反馈。
**T3【豪尔赫·卡斯塔尼翁】博士 **
Twitter:@ castan LinkedIn:@jorgecasta
使用 Seaborn 通过数据可视化分析数据
使用不同的图来可视化数据,并学习何时使用这些图。
数据可视化是任何数据分析的重要组成部分。它有助于我们认识变量之间的关系,也有助于我们发现哪些变量是重要的,或者哪些变量会影响预测的变量。
Explorative data analysis
在机器学习模型中,当训练任何模型时,你需要首先找到哪些特征是重要的,或者结果依赖于哪些特征。这可以通过数据分析和数据可视化来实现。
我们将学习如何可视化不同类型的数据,我们可以从图中推断出什么,以及何时使用它们。
Seaborn 是一个建立在 matplotlib 之上的库。它很容易使用,可以很容易地与 Numpy 和 pandas 数据结构一起工作。
我们将使用 seaborn name tips
提供的内置数据集。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
加载数据集
tips = sns.load_dataset("tips")
tips.head()
Tips dataset head
我们可以看到性别、吸烟者、日期和时间是分类数据。total_bill、tip 和 size 是数字数据。
我们将检索一些公共信息,如给定数值数据的最小值、最大值、唯一值和计数。
tips.describe()
Descriptive statistics of numerical data.
现在我们将使用图来推断不同变量之间的关系。
单变量图
这些图基于单个变量,显示了给定变量的唯一值的频率。
柱状图
sns.distplot(tips['tip'], kde=False, bins=10);
Histogram
箱值越大,结果越准确。
Histogram for bins=30
我们可以看到数据集中出现的不同 tip 值的计数,并推断大多数 tip 在 2 和 4 之间。
肯纳密度估计(KDE)
sns.distplot(tips['tip'],hist=False, bins=10);
Kernel density estimate of tip
KDE 是一种估计连续随机变量的概率密度函数的方法。当你需要知道变量的分布时,就会用到它。
二元图
当您需要找出两个变量之间的关系以及一个变量的值如何改变另一个变量的值时,可以使用这种类型的图。根据变量的数据类型,使用不同类型的图。
统计数据类型
散点图
sns.relplot(x="total_bill", y="tip", data=tips);
Scatterplot
relplot
的默认绘图类型是散点图。它显示了两个变量之间的关系。所以,如果需要找到两个变量之间的相关性,可以使用散点图。
在给定的例子中,我们可以看到,如果total_bill
在 10-20 之间,那么小费通常会高于 2。
我们还可以在散点图中添加第三个变量,使用不同颜色或形状的点。
sns.relplot(x="total_bill", y="tip", hue="smoker", data=tips);
scatterplot for 3 variables
线图
该图类似于散点图,但它不是点,而是通过排列 x 轴上表示的变量值来显示连接所有点的线。
sns.relplot(x="total_bill", y="tip", kind="line", data=tips)
Lineplot
正如我们所看到的,相对于总账单,小费的分布过于随意。我们可以推断,小费并不太依赖于 total_bill 的值。
因为线图按照 total_bill 排列行,然后连接点,所以我们可以禁用排序。
sns.relplot(x="total_bill", y="tip", sort=False, kind="line", data=tips)
lineplot sort false
情节太混乱了,我们无法在这张图表中做出准确的推断。
对于大型数据集,该图需要时间,因为首先需要排序。
分类数据类型
散点图
sns.catplot(x="sex", y="tip", data=tips);
categorical scatterplot
我们可以看到,不管gender
如何,大部分提示都集中在 2 和 4 之间。
使用 seaborn 中的属性kind
可以制作不同类型的散点图。
第三个变量可以在 seaborn 中使用属性hue
。
sns.catplot(x="day", y="total_bill", hue="sex", kind="swarm", data=tips);
scatterplot using hue and kind
要在 x 轴上表示的类别按照熊猫类别排序。如果你想要你的需求顺序,你可以使用 seaborn 中的order
属性。
sns.catplot(x="smoker", y="tip", order=["No", "Yes"], data=tips);
scatterplot using order
箱线图
箱线图(或盒须图)以一种便于变量之间或分类变量水平之间比较的方式显示定量数据的分布。它可以在一个图中给出数据集.describe
中提供的所有统计数据。如果数据集太大,值的范围太大,那么它会根据四分位函数将一些值显示为异常值。
boxplot description
sns.catplot(x="day", y="total_bill", kind="box", data=tips);
boxplot
阴影框表示 25-四分位数和 75-四分位数之间的值。阴影框中的水平线表示中间值。底部和顶部的两条水平线分别代表最小值和最大值。圆点表示基于四分位间距函数计算的异常值。使用这些图表,我们可以在一个图表中比较不同类别的值。我们可以从给定的图表中推断出 total_bill 的金额在周末比平日高。
要在箱线图中使用第三个变量
sns.catplot(x="day", y="total_bill", hue="sex", kind="box", data=tips);
Boxplot using the third variable
我们可以从一张图中获得如此多的信息。在这张图表中,我们可以看到女性的平均总账单金额总是少于男性。因此,我们可以说total_bill
的数量依赖于sex
。
小提琴情节
该图用于可视化数据的分布及其概率密度。这张图表是箱线图和密度图的组合。因此,如果你需要找到频率分布以及箱线图,而不是小提琴图。
Violin plot description
sns.catplot(x="day", y="total_bill", hue="sex",
kind="violin", data=tips);
violin plot
在星期五,我们可以看到女性的账单总额比男性的账单总额少得多。
点图
散点图通过散点图点的位置来表示数值变量集中趋势的估计值,并使用误差线来表示该估计值周围的不确定性。点图仅显示平均值和这些平均值周围的误差率。它们提供的信息不多,但很容易发现基于不同类别的变量的变化。
sns.catplot(x="day", y="total_bill", hue="sex", kind="point", data=tips);
Point plot
使用这个图,很容易找到 total_bill 按天的变化。随着周末的到来,男性的总账单会上升,而女性的总账单会在周五下降,周六会上升,周日基本保持不变。
这些图可用于各种数据分析,我们可以推断关于不同变量之间关系的信息,并有助于从数据集中提取更重要的特征。
分析 38 万 Kickstarter 活动
在今天的帖子中,我想做一些不同的事情。最近,他们都专注于数据科学的某个领域,但今天我想做一个基本的探索性分析,总结一下我过去谈论的所有内容。
Photo by Kaboompics .com from Pexels
而你,我的读者朋友,这将是对你的款待。不,我不会给你巧克力棒,但我有更好的东西——在我的 GitHub 个人资料上有完整的分析笔记本。
我将使用的数据集可以在这个链接上找到。你不必跟着编码,但是嘿,**为什么不呢?**我故意不在谷歌上搜索任何关于这个数据集的探索性分析,因为,嗯,我想给你一些原创的东西。前所未见的东西。在这个过程中,也许我会犯一个灾难性的错误,这个错误可以通过做一些研究来避免,但是我喜欢生活在边缘。
事不宜迟,让我们开始吧!
一些基本统计数据
数据集导入后,首先我想看看数据是什么样的,至少是前几行(希望您可以轻松阅读):
Head of Kickstarter Dataset
好吧,15 栏,没什么疯狂的。需要以某种方式管理大量文本数据。在本文中,我不会开发任何预测模型,所以没有必要为标签编码而抓狂,但一些行动将是必要的。
调用 。数据集上的形状 产生以下结果:
没错。数据量不错,差不多 380K 行!我必须说有很多战役。天知道这些数据收集了多少年——应该以后再探索。这里我要检查的最后一件事是缺失值:
哇,这是我见过的最完整的数据集之一。很奇怪,活动名称怎么会是空的,这真的没有意义。对于第二个缺失的属性,USD _ pleated,数据集的文档说明它表示质押列的“美元转换(由 Kickstarter 完成的转换)。“没什么好担心的,至少可以说。
现在是图表时间
该是我最喜欢的部分了——数据可视化。承认吧,你不喜欢看表格数据。这很正常。人类并不打算这样做。即使是你,数据科学家,或者有抱负的数据科学家,也应该知道,在你专业工作的某些方面,你需要向你的上级展示你的成果。
浏览一大堆只有表格数据的幻灯片对你来说绝对是一个好方法不要得到你一直想得到的提升,所以,让我们看看如何制作一些好看的可视化效果。我已经在我以前的一篇文章中讨论过这个问题:
[## 使用 Matplotlib 实现惊人可视化的 5 个步骤
Matplotlib 烂透了。默认情况下。以下是对此的处理方法。
towardsdatascience.com](/5-steps-to-amazing-visualizations-with-matplotlib-ca61f0ec5fec)
按年份列出的活动数量
我想展示的第一件事是每年活动的数量,如果你读过前面的部分,这不会让你感到惊讶。380,000 次活动听起来确实很多,所以我预计至少需要 5-7 年的时间跨度。
我已经决定声明一个用于绘制条形图的自定义函数(,因为我觉得我会在这个分析中做很多次):
Bar Chart Function — https://gist.github.com/dradecic/97652676c6d228ed571c0ed67dc0eeb2
现在制作这种可视化并不是最困难的任务——但是请记住,数据集中没有单独的年份列,所以您将需要使用 lambda 函数的魔力来从launch属性中提取它们。代码如下:
Years Bar Chart — https://gist.github.com/dradecic/0b827e5f3a4a74cc7dd198c4b3fdc8b5
这是图表(最后,天哪):
啊,当 Matplotlib 图表看起来不像是用 Matplotlib 制作的时候,真是太好了。如果你做的那些看起来还是很糟糕,参考我上面链接的文章。此外,这个官方 Kickstarter 绿色在条形图上看起来真的很好。
按国家列出的活动数量
现在是时候使用同一个make _ bar _ chart函数来可视化 country 属性了——因此来看看这些活动是从哪里来的(我感觉好像有一个国家来统治它们所有的)。
我相信你有能力让这个函数自己调用,你只需要把“已启动”改为“国家”,并根据你的意愿调整标题和轴标签。
一旦你做了调整,点击 SHIFT 和回车键,看看魔术在行动:
我的假设没有错。美国有差不多 30 万个竞选活动。这没什么不好,但这让我想知道为什么其他国家没有参与进来。
探索活动类别
现在让我们再次使用make _ bar _ chart函数来查看特定类别有多少个活动—attributemain _ category。与前面的图表一样,我不会编写函数调用的代码,因为您只需要更改属性名称和标题(,如果您愿意的话)。
貌似电影&视频,旁边还有音乐在 Kickstarter 上很受欢迎。舞蹈活动最少,但这并不意味着它们的整体成功率最低——这将在一分钟内进行探讨。
活动持续时间
但在此之前,我想了解一下这些活动的平均持续时间。为此,我需要做一些编码,因为没有活动持续时间的数据。为了计算它,我将从属性中减去属性 【已启动】 的值,然后将结果保存为两者之间天数的整数表示。
听起来像一个简单的计划,所以让我们执行它。我已经使用 pythonzip函数同时迭代两个数组(或系列)。代码如下:
Duration Attribute Creation — https://gist.github.com/dradecic/436539fceeeca338c3ed803b4412a231
这里均值和中值真的很接近,但是标准差感觉怪怪的。这需要进一步探索。我已经打印出了持续时间最长的 10 个活动,得到了一些有趣的结果:
由此看来,第一次运动开始于 1970 年 1 月 1 日,这显然没有意义。我决定过滤掉任何持续超过 100 天的活动(其中 7 天是)。
现在,我还声明了一个绘制直方图的函数,因为我想可视化这个连续变量的分布:
Histogram Function and Call — https://gist.github.com/dradecic/229903b0a35198a2650cdf652e4722f3
在这里,您可以看到—看起来大约 20 万个活动持续了一个月,两个月之后似乎会有一个高峰—大约 4 万个活动。
现在让我们来看看好东西。到目前为止,这很容易,现在是我用更长的代码,但也是更惊人的可视化来抨击你的时候了。我相信你,我的读者朋友,我知道如果你花时间一行一行地阅读代码,你将能够理解一切。
按类别探索营销活动的成功
首先,数据集需要以某种方式改变。存在一个属性— state —它代表了活动的状态,您可能不会相信!其中一些还在进行中(好吧至少在 2018 年初是这样的,所以那些会被过滤掉。然后,我将替换属性中的值,因此最终它的编码是这样的:
- 0:活动不成功
- 1:活动很成功
用 Python 完成这个任务并不困难,但是在完成之后,还需要做一些其他的修改和调整。在下面的代码片段中了解更多信息:
Success vs. Failure chart — https://gist.github.com/dradecic/a34b36a2f9c56495d2e382a0cd1b17c3
执行这个代码单元将会产生这个惊人的可视化效果:
简而言之,它以百分比的形式显示了每个类别中有多少活动失败(深绿色)以及有多少活动成功(浅绿色)。从这里可以清楚地看到, 手艺 和技术是大忌(大多数情况下),而剧场和舞蹈看起来大有可为。**
活动目标与承诺分析
让我们更深入地了解一下,看看每个单独的活动类别中,设定为活动目标的平均金额(嗯,中位数)与实际获得的金额。再次强调,实现这一点需要一些代码,但我相信你:
Money Goal vs. Pledged — https://gist.github.com/dradecic/e469bffddcbf13d6ff502f7c57f978a4
上图的结论仍然成立——舞蹈和戏剧似乎仍然是最有希望的竞选类别。
标题探索
现在让我们讨论一下今天将要绘制的最终图表。我敢于进一步探索头衔,探索特定头衔长度组的平均所得金钱(中值再一次)。
在 的帮助下,我将标题长度分成了 10 个分位数。qcut 功能:
Obtained Money per TItle group — https://gist.github.com/dradecic/a4477c8e18b91baf022fc0b8fbc3c4fa
这是最终的图表:
看起来,如果他们想筹集一些资金,活动应该尽可能地描述他们的标题— 谁会说?
最后的话
有一点是肯定的——这不是一个详尽的探索性数据分析项目。但是我已经介绍了足够多的基础知识,所以我的读者朋友,你可以自己进一步探索。
也许你想开发一个预测模型,它将能够确定一个给定的活动是否会成功。也许你想通过 NLP 进一步分析竞选标题。也许这对你来说已经足够了。不管是哪一种,我肯定你能想出下一步该怎么做。
现在该说再见了,但只是一小会儿。感谢阅读…
By GIPHY
喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
** [## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)**
分析亚马逊野火数据
由于气候变暖,亚马逊雨林的野火越来越令人担忧。在这里,我们将探索和分析巴西政府提供的巴西火灾数据集。数据在这里可用。
在数据科学中,探索数据通常是构建预测模型的第一步。探索性数据分析包括总结数据集的特征。这包括关于数据特征的统计摘要,如平均值、标准差、分布和记录数。
第一步是用 python 导入 pandas 包,并将数据读入 pandas 数据框。您可以将熊猫数据框想象成数据表或 excel 电子表格。
import pandas as pddf = pd.read_csv(“amazon.csv”, encoding = “ISO-8859–1”)print(df.head())
前五行的输出是:
如你所见,数据包括年份、巴西州、月份、野火数量和日期。我们可以从计算每个州的火灾平均数开始分析。我们在熊猫身上使用了“分组”方法:
df = df.groupby(‘state’)[‘number’].mean().reset_index()print(df)
Mean Number of fires for each state
我们也可以使用 python 中的“seaborn”包来实现这一点:
import seaborn as snsbar = sns.barplot(df['state'], df['number'], color = "red")
bar.set_xticklabels(df['state'], rotation=45)
Mean Number of fires for each state
我们还可以查看每个州火灾数量的标准偏差:
df = df.groupby(‘state’)[‘number’].mean().reset_index()
bar = sns.barplot(df['state'], df['number'], color = "black")
bar.set_xticklabels(df['state'], rotation=45)
Standard Deviation in Number of fires for each state
我们还可以查看各州火灾数量的分布情况:
我们可以看到森林火灾数量的分布是长尾的。巴西各州的情况也是如此。
如果我们想要查看单个状态的集合,我们可以如下操作:
print(set(df['state'].values))
当被执行时,其给出:
The unique set of states
这在您有一个大型数据集并希望分析特定的数据段或数据组时尤其有用。在这种情况下,我们只有 22 个州,现在让我们称它们为类别。有些情况下,您可能有数百万行,并且对一组可能只有 5 个值的类别感兴趣。手动查看 excel 文件来计算类别的数量是非常困难的。此外,您可以查看每个类别有多少数据可用:
from collections import Counter
print(Counter(df['state'].values))
The number of rows/records for each state
小警告:对于大于 1 GB 的数据集,pandas 非常慢,最好使用其他工具进行分析。其他工具包括 Spark clusters、Hadoop 和 Hive。因为这些工具需要大量的时间来学习和设置其他替代方法,包括将数据分成几批,使用 pandas,以及使用 numpy 数组。
建立精确预测模型的一个好方法是找到将整个数据集分成具有相似属性的聚类的方法。如果我们希望查看单个州的数据,比如说“罗赖马”,我们可以过滤数据框:
df = df[df['state'] == 'Roraima']
df = df.head().reset_index()
df.drop('index')
print(df.head())
我们还可以通过绘制罗赖马州 1 月份的野火数量与年份的对比图,来寻找任何给定月份和州的野火数量的规律:
import matplotlib.pyplot as plt
df = df[df['month'] == 'Janeiro']
plt.plot(df['year'], df['number'])
plt.xlabel('Year')
plt.ylabel("Number of Wildfires")
plt.title("Wildfires in Roraima in the month of January")
您还可以针对不同的州和月份执行此分析:
这将为您的模型构建过程提供信息。一个有趣的方法是为每个州和每个月建立一个模型。这不是唯一的前进道路,但探索性数据分析的目的是了解您的数据,并随后从特征工程和模型构建中获得灵感。
在下一篇文章中,我们将使用 python 机器学习包“sklearn”中的随机森林算法建立一个预测模型。
感谢您的阅读!
分析和预测星巴克的选址策略
在波士顿,感觉走不出一个街区就看不到星巴克了。事实上,在 Stax 波士顿办事处方圆一英里的范围内,我们有 15 个(!)星巴克的位置。
Starbucks locations in Back Bay, Boston
鉴于此,很自然会问:星巴克是如何考虑选址的?
从更广的层面来看,他们的商店位置能告诉我们关于他们的客户群的什么信息,以及他们认为服务于这个客户群的有吸引力的位置是什么?我们能否从高层次上推断出他们应该或将要在哪里探索进一步的门店扩张?
通过分析商店数据以及这些数据与人口普查数据的对应关系,我们可以对星巴克认为有价值的位置创建一个高层次的“轮廓”,此外还可以看到在这些区域及其周围可能有进一步扩大足迹的机会。
R 中的完整项目代码, 点击此处 。
我们将从美国商店的总体情况开始分析。
Note: Each dot represents one Starbucks location and darker regions means more stores. Data is as of 2017 and will not include more recent openings.
从视觉上看,我们可以看到对沿海地区和主要大都市地区的偏好,所有这些都是有道理的,因为作为一个高端大众市场品牌,我们正在寻找能够支付略高价格的消费者。
事实上,我们将通过tidycensus
获得的美国社区调查的结果进行对比,并比较有星巴克和没有星巴克的地点的人口统计数据,这些数据证实了这一点:
Demographics of U.S. (red) versus Starbucks locations (blue).
数据清楚地表明,星巴克的目标位置是更富裕的家庭(家庭收入中值约为 6.5 万美元对 5 万美元)、更多的人(人口中值约为 3.15 万美元对 3K)、更年轻的年龄(37.6 岁对 41.7 岁)以及受教育程度更高的劳动力。
如果你了解这个品牌,这一点都不奇怪,但用数据填充直觉是一种重要的方式,可以让你对每一组数据探索和策略更有信心。
现在,让我们更深入地了解位置。下面的地图有助于我们理解,在一个州的水平上,星巴克位置的数量,点的大小代表位置与人口的比例。例如,加州拥有最多的星巴克门店(截至 2017 年约 2750 家;最暗的红色)而华盛顿拥有最多的人均位置(最大的气泡)。
从上面我们可以看出,星巴克不仅有更多与人口增长成比例的位置(即人口越多的州有更多的商店),而且他们在有主要大都市地区的州指数过高(即这些位置有更多的商店和更多的人口商店)。
因此,下一步是寻找哪些位置“看起来”像今天的星巴克位置——使用星巴克位置的人口统计数据——但还没有星巴克。
为了简洁起见,我们将只测试新的邮政编码,而不是在现有邮政编码范围内的扩展。为了实现这一点,我们将使用逻辑回归模型来预测一个邮政编码有星巴克位置的可能性,并查看没有星巴克位置的最高预测概率。接下来,我们将使用星巴克位置的“典型”特征,并在这些因素中寻找最高的邮政编码相似性。
逻辑回归预测
使用人口统计变量的基本逻辑回归可以正确预测大约 60%有星巴克的邮政编码和 90%没有星巴克的邮政编码。考虑到数据集的不平衡性质——31,000 个观察值和大约 5,500 个星巴克观察值——60%的预测率应该足以满足本练习的目的。
我们的最高结果(没有星巴克的最高预测概率)是邮政编码 60629,位于芝加哥。一项小小的调查显示了以下情况:
Left: Zip code area of 60629. Right: Starbucks locations near this area; Note how they fall just outside the boundaries. Maybe the area is residential?
该邮政编码在区域外有 2 个毗邻星巴克的位置,模型预测该邮政编码有 99%的可能性有星巴克。这应该会给我们信心,让我们相信这个模型是可行的。
下面的地图显示了目前没有星巴克的县一级邮政编码的总概率。例如,如果一个县有 20 个没有星巴克的邮政编码,该地图将显示所有这些地理区域的预测概率总和。
虽然这偏向于有更多邮政编码的县——因此有更多潜在的邮政编码要加总——但我认为这没关系,因为每个县不应该被同等加权;我们只对那些最有机会的人感兴趣。
Darker green = higher total probability of attractive locations; Rolled up from a zip-code level to county. The color scale is set to the median probability as a baseline and darker green indicates a probability increasingly above that level.
对我来说,这表明有机会在目前的大都市及其周边地区的邮政编码水平上进一步扩张。特别是,芝加哥、南加州、大纽约和大波士顿似乎仍有空间容纳更多的位置。鉴于我们所知道的他们过分强调人口密集地区的倾向,我们会说在这些地区有进一步的增长。
相似度
接下来,我们过渡到邮政编码的相似性。这里的方法是计算所有星巴克位置的中值统计,并在标准化变量以抵消不同尺度(即人口数量>年龄数量)的影响后,计算每个非星巴克行与中值之间的差异。
事实上,当用基本的人口统计信息重新构建箱线图时,这种方法的发现是有效的。下面,你可以看到前 100 个最相似的非星巴克所在地的邮政编码的比较,以及它与星巴克所在地的邮政编码的比较。
Top 100 Non-Starbucks locations by similarity compared to Starbucks locations. Note how this compares more favorably compared than the previous chart above.
这些相似的地点在哪里?让我们看看下面按州排列的前 20%的邮政编码:
Top 20th percentile of similar Non-Starbucks zip-codes
风险和后续步骤
不受约束地扩张到新的有吸引力的地点在理论上可能看起来不错,但还有其他因素要考虑。以下是我在 Stax Inc. 工作的地方,如果有客户找到我们,我们可能会问的几个问题:
- *与公司战略保持一致:*管理层制定了什么样的前进战略,哪些地点与该战略保持一致?
- 评估顶级地区的竞争活动:有哪些国家连锁店,数量如何?有哪些区域连锁店?谁应该被视为我们的竞争对手?
- *了解当地市场的细微差别:*每个市场的当地细微差别是什么?与波特兰或俄勒冈州(重视本地和氛围)相比,马萨诸塞州波士顿的进一步渗透(重视便利和速度)如何?为了在每个市场中获胜,我们需要相信什么和做什么?
- 考虑市场饱和:在什么情况下市场会过度饱和,并存在商店之间互相蚕食的风险?在一个给定的位置有多少家店是“太多”了?
- *房产和人力成本:*每个市场都有哪些房产?成本会阻碍开设一家盈利的商店吗?劳动力可用性和成本如何?
- *描述目标客户:*在每个市场中,谁是我们的目标客户?我们知道这个位置应该反映出上面的参数——高收入、年轻、密集——但是在这个群体中,我们希望接触到 75000 美元到 90000 美元或者 100000 美元到 120000 美元的家庭吗?25-34 岁还是 45-60 岁?想要工作空间的人拿了就走?这些人有多少?
随着我们一步一步地走下去,我们不仅能更好地了解位置,还能更好地了解顾客。这将有助于我们分析那些竞争太激烈和/或太昂贵、没有足够的特定目标客户、或者没有推进我们公司战略的地点。然后,在这个练习之后,我们应该希望留下一个较小的高价值位置集,并过渡到思考与开设新店相关的运营和物流因素。
所展示的分析并没有告诉我们在哪里开设一个位置,而是帮助我们将美国的范围缩小到一组目标位置,在这些位置上我们可以进行更深入的探索。这些数据为我们提供了一个平台,让我们在制定战略、实现增长目标以及最终实现更好的业务成果时更加自信。
作为后续,我发表了第二个故事,强调了定位策略的新方法。点击这里查看!
有兴趣讨论你的企业或项目的选址策略吗?在 jordan@jordanbean.com 给我发邮件或者在 LinkedIn 上联系我。
分析 R 中的动漫数据
如果你是一个动漫迷,那么你会喜欢我在 R 中做的这个分析。这个数据来自于 MyAnimeLis t 网站,是 R for Data Science 社区发起的 Tidy Tuesday 计划的一部分。你可以从这里下载这个数据的整洁版本。他们每周发布有趣的数据集,社区分享他们的分析,大多使用 Tidyverse 软件包,这是一个很好的学习资源。我还建议关注大卫·罗宾逊的 YouTube 频道。他每周都会上传新的视频,在视频中他分析了来自 Tidy Tuesday 的新数据集,你可以从他那里学到很多很酷的东西。
加载库
像往常一样,我们将加载一些库。
library(tidyverse)# Data manipulation and visualization
library(scales)# Converting data values to units
library(patchwork) # For Patching multiple ggplots together
数据的读取和初步调查
使用 read_csv 函数,我可以通过为文件参数提供到数据集的链接,直接从网站读取数据。加载数据后,让我们使用视图功能来查看数据
tidy_anime <- read_csv(file="[https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-04-23/tidy_anime.csv](https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-04-23/tidy_anime.csv)")View(tidy_anime)
如您所见,这是一个巨大的数据集,我不需要所有的列来进行分析。如果你看第一张截图,你会看到每个动画 ID 都被复制了。这是因为 MyAnimeList 网站上的每部动漫都被归类在不同的流派下。因此,每部不同类型的动漫都有一行,因此出现了重复。同样的问题也出现在制作人和工作室栏目,因为一部动漫可以有多个制作人和工作室
tidy_anime <- tidy_anime%>%
select(-c(title_synonyms,synopsis,background,related,genre,studio,producer))
要删除这些列,我只需将它们包装在一个 “-” 中,这是一种取消选择的方式。
unique_anime <- tidy_anime%>%
distinct()%>%
filter(!is.na(title_english))View(unique_anime)
然后我们使用 distinct 函数,这样我们就可以为每一行获得一个唯一的动画 ID。我只对那些有英文标题的感兴趣,所以我删除了所有没有英文标题的。现在让我们再看一下数据。
不错!现在我们在每一行都有一个唯一的动漫 ID。我们现在可以开始分析我们的数据。
分析和可视化
如果你们中的任何一个人是动漫迷,那么你应该知道动漫电视剧和动漫电影不应该被放在一起比较。两者应该在各自的范畴内进行比较。为此,我们将进一步将这些数据分为电视和电影类别
tv_anime <- unique_anime%>%filter(type=="TV")
tv_plot <-tv_anime%>%
mutate(graph_name=paste0(title_english," (",premiered,")"))%>%
top_n(-20,wt=popularity) %>%
ggplot(aes(reorder(graph_name,desc(popularity)),popularity,colour=title_english))+
geom_point(show.legend = FALSE)+
geom_segment(aes(x=graph_name,xend=graph_name,y=0,yend=popularity),show.legend = FALSE)+
coord_flip()+
theme_classic()+
labs(x="",y="Popularity",title = "Top 20 Most Popular Anime TV Shows")
让我们一步一步地看这段代码:
- 我只过滤电视节目的日期
- 在我的图中,我还想看看它们何时开始,所以我使用 mutate 函数创建了一个新列— graph_name 。在 mutate 函数中,我使用了 Paste0 函数来组合 title_english 和 premiered 列
- 然后我用 top_n 函数得到了最受欢迎的 20 部动漫。请注意,我使用了-20,因为这将获得 20 个最低值,而且因为这是一个基于排名的值,最低值意味着最受欢迎
- 然后我使用标准的 ggplot 函数来绘制我们的 x 和 y 轴值。我在 x 轴上使用了 reorder 函数,因为我想根据流行度值对它进行排序
- 我正在创建一个棒棒糖图,为此,我需要将几何点和几何段组合在一起以获得我的结果。几何点绘制点,而几何段绘制线
- coord_flip 使其垂直和其他标准功能来标记情节和改变主题的外观。
这没什么奇怪的。所有这些节目都非常受欢迎,但值得注意的一件有趣的事情是,所有这些节目目前都没有播出,因此像 Once Piece 和漂白剂这样的节目也没有播出。让我们来看看目前正在播放的最受欢迎的节目
tv_anime_airing <- unique_anime%>%filter(type=="TV",airing=="TRUE")
tv_plot_airing <-tv_anime_airing%>%
mutate(graph_name=paste0(title_english," (",premiered,")"))%>%
top_n(-20,wt=popularity) %>%
ggplot(aes(reorder(graph_name,desc(popularity)),popularity,colour=title_english))+
geom_point(show.legend = FALSE)+
geom_segment(aes(x=graph_name,xend=graph_name,y=0,yend=popularity),show.legend = FALSE)+
coord_flip()+
theme_classic()+
labs(x="",y="Popularity",title = "Top 20 Most Popular Anime TV Shows")+
theme(axis.text.y.left = element_text(size = 12))
代码和以前一样。我对目前正在播放的节目的过滤做了一点调整
啊!一块放在当前正在播放的节目的顶部。我很惊讶一拳第二季和袭提坦第三季(下)不在这里。收集这些数据时,它们可能还没有播出。我只看过这些中的暴民惊魂记 100** 。**我们也来看看评分最高的动漫吧。
嗯,有些令人失望的是,这些动漫中的大多数甚至没有超过 8 分。接下来,我有兴趣看看哪些流行动漫得分高,它们与这些动漫的得分人数有什么关系
tv_anime %>%
filter(popularity <= 50) %>%
mutate(title_english = str_replace(title_english, "Code Geass: Lelouch of the Rebellion", "Code Geass")) %>%
ggplot(aes(score, scored_by)) +
geom_point(shape=21,aes(fill=title_english,size=members)) +
geom_text(aes(label = title_english ), check_overlap = T, show.legend = F, size = 3, hjust = 1) +
xlim(c(6, 10)) +
scale_y_log10()+
labs(title = "Which popular anime also score high?",
subtitle = "Top 50 anime shown based on popularity",
y = "Number of users that scored",
x = "Score (1-10)") +
theme_classic()+
theme(legend.position = 'none',aspect.ratio = 0.5)
死亡笔记再次置顶。我会假设像死亡笔记、攻击泰坦和剑术在线这样的动漫有一个真正忠诚的粉丝群,他们会去网站为他们评分。像 Once Piece 这样的节目已经播出了相当长一段时间,但相对而言,很少有人获得它的评分。
现在让我们来看看流行度与分数。有没有哪部热门动漫没得高分,反之亦然。
tv_anime%>%
filter(popularity<=100) %>%
ggplot(aes(popularity,score,fill=rating))+
geom_point(shape=21,size=3,alpha=0.8)+
geom_text(aes(label=title_english),size=3,check_overlap = TRUE)+
scale_x_log10()+
theme_classic()+
scale_color_brewer(palette = 'Set1')+
theme(legend.position = "bottom")+
labs(title = "Popularity vs Score",subtitle = "Do all Popular Anime score high?")
所以最受欢迎的动漫肯定得分最高。虽然图表中充满了 PG-13 级的节目,但得分最高的动画肯定是 R-17+。有点惊讶的是,《我的赫拉学院》第二季&第三季没有第一季那么受欢迎,尽管它们的收视率都比第一季高。
最后,我想比较一下前 20 名最受欢迎的成员和最受欢迎的人。
**most_members** <- tv_anime%>%
top_n(20,wt=members) %>%
mutate(graph_name=paste0(title_english," (",premiered,")"),graph_name=fct_reorder(graph_name,members))%>%
ggplot(aes(graph_name,members,fill=graph_name))+
geom_bar(stat = 'identity',width=0.5,show.legend = FALSE,color='black')+
coord_flip()+
theme_classic()+
scale_y_continuous(limits = c(0,1700000),labels = comma)+
geom_text(aes(label=comma(members)),size=3)+
labs(x="",y="Rank",title = "Top 20 Most Members")**most_favorite**<-
tv_anime%>%
top_n(20,wt=favorites) %>%
mutate(title_english=fct_reorder(title_english,favorites))%>%
ggplot(aes(title_english,favorites,fill=title_english))+
geom_bar(stat = 'identity',width=0.5,show.legend = FALSE,color='black')+
coord_flip()+
theme_classic()+
scale_y_continuous(limits = c(0,150000),labels = comma)+
geom_text(aes(label=comma(favorites)),size=3,hjust=1,fontface='bold')+
labs(x="",y="Favourites",title = "Top 20 Most Favorite")**most_scored**<-
tv_anime%>%
top_n(20,wt=scored_by) %>%
mutate(title_english=fct_reorder(title_english,scored_by))%>%
ggplot(aes(title_english,scored_by,fill= title_english))+
geom_bar(stat = 'identity',width=0.5,color='black',show.legend = FALSE)+
coord_flip()+
theme_classic()+
scale_y_continuous(limits = c(0,1500000),labels = comma)+
geom_text(aes(label=comma(scored_by)),size=3,hjust=1,fontface='bold')+
labs(x="",y="Favourites",title = "Top 20 Most Scored by")most_favorite + most_members+ most_scored + plot_layout(widths = 20)
很明显,拥有最多成员的动漫会有更多人给它打分。我从未在我的动画列表上为一部动画打分,但我认为你需要成为这部动画的一员才能为它打分。最喜欢的是一个不同的故事。这可以潜在地突出具有最忠实的粉丝基础的动画,这些粉丝如此喜爱该动画以至于他们将它添加到他们的最爱中。
结论
我希望你觉得这个分析很有趣。如果你想分析动画电影,你可以使用相同的代码,但唯一的区别是只过滤电影而不是电视。
分析 Billboard 的说唱排行榜
从小到大,我身边都是说唱音乐。店面、汽车收音机和电视扬声器发出的刺耳声音是所有不同海岸的声音汇集在一起。这种对嘻哈音乐的不断接触和我受保护的亚洲成长环境让我讨厌它,我花了一部分青少年时光沉浸在经典摇滚中。
这并没有持续很长时间。
在我高中的第一年,我被介绍给新鲜的说唱行为,如丹尼布朗,运行珠宝,和索尔威廉姆斯。我被重新介绍给像坎耶·韦斯特和图帕克这样的童年旧爱。嘻哈音乐占据了我的世界,我的品味在大学期间也慢慢变得更好了。在被介绍给 Geto 男孩后,我对南方说唱产生了一种近乎不自然的痴迷。这个地区结合了我对身临其境讲故事的热爱,不仅有我可以跟着跳舞的节拍,还有黑暗制作,就像我童年时喜欢的朋克音乐和我小时候可以听的一小部分“可接受”音乐中常见的爵士乐影响。南方是实验的温床,我想传播这个福音。
从那以后,我的大部分工作都围绕着既古老又新颖的南方嘻哈音乐。我不断发现新的艺术家和声音从南方的每一个缝隙里传出来。我认为南方在主流音乐中很大程度上被低估了,只是在过去的三年里才看到了复兴。像 A A P R o c k y 这样的艺术家对孟菲斯传奇人物托米 ⋅ 怀特三世进行了采样,并尝试了由得克萨斯州自己的 D J S c r e w 开创的切碎和拧紧制作。 C a r d i B 在她的热门专辑《侵犯隐私》中收录了 P r o j e c t P a t 的《小鸡头》。一个 AP Rocky 这样的艺术家对孟菲斯传奇人物托米·怀特三世进行了采样,并尝试了由得克萨斯州自己的 DJ Screw 开创的切碎和拧紧制作。Cardi B 在她的热门专辑《侵犯隐私》中收录了 Project Pat 的《小鸡头》。一个 APRocky这样的艺术家对孟菲斯传奇人物托米⋅怀特三世进行了采样,并尝试了由得克萨斯州自己的DJScrew开创的切碎和拧紧制作。CardiB在她的热门专辑《侵犯隐私》中收录了ProjectPat的《小鸡头》。一个AP Ferg 在他的单曲《平凡的简》中重新构思了三个 6 黑手党的地下热门歌曲《Slob On My Nob》。甚至在最近,Lil Nas X 的“老城路”在复兴“乡村说唱”方面取得了巨大的成功,德克萨斯的 UGK 在几十年前就以他们独特的南方鼻音和勇敢的乐器开创了这一潮流。
我决定通过查看 Billboard 从 1990 年到 2018 年的顶级说唱歌曲排行榜来验证这个理论。为了简洁起见,我决定省略他们的 R & B 图。根据 airplay,每首歌曲都被确定为全国第一,直到 2012 年,流媒体数字和数字下载被加入到标准中。我编辑了我的列表,只从每首歌曲中选取艺术家,并找到他们来自的州及其相应的海岸,这意味着我排除了任何不是来自美国的艺术家。如果他们出生在德克萨斯州,但他们的事业和成功却源于纽约,那么他们就是来自纽约的东海岸艺术家。使用世界地图集上这张方便的地图可以区分海岸。
Image courtesy of World Atlas
我每年还会拿出副本。因此,如果梅西·埃丽奥特在一年内三次排名第一,我只统计了一次,以免进一步扭曲数据。在接下来的几年里,我会把她算作第一名。这是关于艺术家,而不是歌曲。
总而言之,我查阅了 291 行数据。我找到了 1990 年到 2018 年的 191 位独特的艺术家。在研究的最后,我还发现自己在调查一个完全不同的问题。
我决定先问一个最简单的问题:这些艺术家来自哪个地区?结果令我吃惊。
查看 28 年的数据,就近 300 首歌曲中的第一名而言,南方紧随东海岸之后(再次记住,每年都有重复的艺术家被淘汰)。我决定看看十年来沿海趋势是如何变化的。
有趣的是,从 2000 年开始,南方实际上主导了排行榜。回顾我的数据,奥特卡斯特和耐莉在 2000 年代早期都有好几年的冠军单曲。考虑到当时的音乐氛围,这是有意义的。南方大量生产有趣的、适合跳舞的热门歌曲,挤满了舞厅,手机扬声器里响起铃声。最重要的是,南方有独特的声音和来自各州的艺术家,相比之下,其他沿海地区有独特的音乐中心,如纽约和加利福尼亚。我想看看每年有哪些州入选,我把它编成了一个有趣的 gif!越黑暗的州,越多的顶级艺术家来自那里。
在 90 年代,纽约和加州是游戏的主要参与者,但加州在 00 年代初开始淡出。随着 1996 年图派克·夏库尔和 1997 年臭名昭著的 B.I.G .死亡后海岸战争的停止,他们各自的州在排行榜上的统治也不约而同地结束了,加州更甚于纽约州。随着 21 世纪的到来,更多的佛罗里达、乔治亚和德克萨斯艺术家加入了排行榜。由于纽约州和加利福尼亚州一直位居榜首,我想看看在我观察的 28 年中各州代表的多样性。
正如我所料,纽约是东海岸说唱游戏中最大的玩家。对于 hip hop 的发源地,我不期待少一点。它也是一个非常大的州,是东海岸的文化中心。另一方面,南方有更多的变化。
佐治亚州是一个明显的主要参与者,因为亚特兰大是一个交通和文化中心,有一个大型机场,地理位置便利,正好位于其他州的中间。作为一个文化中心,佛罗里达很像佐治亚州,并且是许多适合跳舞的音乐的故乡,因为它靠近加勒比群岛,所以继续占据排行榜的主导地位。南方和它所有的州共享各种各样的声音和文化。西海岸?没有那么多。
在这种情况下,饼状图不能公正地显示数据。西海岸 24 位独特的艺术家中,只有一位不是来自加州,那就是华盛顿自己的麦克摩尔。其余的艺术家都来自加州。虽然令人震惊,但我并不感到惊讶,因为加州是一个包含大部分沿海地区的大州。也许更深入地看图表,我们可能会发现稍微多一点的州变化,但是为了这个故事的目的,我们只看排名第一的热门歌曲。
我的发现让我想到了我的最后一个假设:随着数字媒体和下载的兴起,观众听的新音乐还不够多。在 90 年代,有几年见证了 20 多位独特的艺术家轮流争夺令人垂涎的第一名。2014 年,有四个。四位独特的艺术家。在测试这个理论时,我并没有完全错。
以下是按十年细分的数据,让我们看得更清楚一些:
这种下降令人痛心,尤其是当我知道每周有多少美妙的音乐从这个国家的每一个地方传出来。发生了什么事?那个,我回答不了。作为音乐爱好者,当我们的手机上有源源不断的音乐可供收听时,我们可能会感到精疲力竭。这也可以从电台作为一种可靠的听音乐方式的衰落中得到启示。当时,音乐可以通过物理媒体和广播电台获得。电台有更大的动机来提高音量以保持听众的兴趣。然后,盗版音乐在 21 世纪初成为一种普遍现象,Limewire 和 Napster 等客户让人们更容易在自己的时间通过电脑访问音乐。便携式音乐播放器带来了 CD 和唱片,现在你可以随时随地把几乎无穷无尽的音乐放在口袋里。当具有互联网功能的智能手机进入市场时,那些 iPods 和 Zunes 被塞进抽屉,mp3 文件开始在我们的桌面上堆积数字灰尘。现在对多样化的刺激减少了,广播电台每小时播放蕾哈娜或德雷克的同一首歌更容易了。它把钱放进了他们的口袋。
我记得我是一个年轻的,易受影响的 11 岁的孩子,偶然发现了纽约另类摇滚宝藏 101.9 RXP。他们从不在一个小时内演奏同一位艺术家两次,我听到了从《新秩序》到《红辣椒乐队》再到当地乐队的所有音乐。周日,我会听 DJ Rich Russo 的任何音乐,他会在只有几百名 Twitter 粉丝的新兴纽约乐队中演奏布鲁斯·斯普林斯汀。DJ 们成了我的朋友。他们真诚地接受请求,并在编程中抓住机会。他们最后一次广播的那天令人心碎,我再也没有过同样的广播经历。然而,那个电台启发了我去利用互联网。我得自己去找这音乐。
我从事这项工作的目的是为了找出南方是否出现在说唱排行榜上,最终我意识到这并不重要。排名第一的点击率只能量化受欢迎程度。重要的是,我们都找到了对我们说话的音乐,不管它是不是每小时通过广播电台播放,或者在 Youtube 的最深处找到。让我们更加自觉地支持我们热爱的艺术家。
今天找一个新的艺人来听,告诉一个朋友!买张 CD!去看表演!让音乐重新变得有趣。
分析 CNET 的标题
使用 Python 和熊猫探索 CNET 上发布的新闻
我写了一个爬虫从 CNET 的网站地图中抓取新闻标题,并决定对其进行一些探索性分析。在这篇文章中,我将向你介绍我的发现、一些异常现象和一些有趣的见解。如果你想直接进入,你可以在找到代码。
履带
爬虫使用 Scrapy 编写,这是一个用 Python 编写的开源网络爬行框架。有一个选项可以将数据转储到 csv 或 json 文件中,只需对命令稍作修改。你可以在我的 GitHub repo 中找到代码和命令。是时候深入分析了。
装载和清洗数据
第一步是加载数据,然后清理数据,为分析做好准备。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inlinedf = pd.read_csv('cnet_data.csv')df.head()
df.head()只输出数据帧的前 5 行。这里我们有 3 列:标题,链接和日期。这里明智的做法是将 date 列中的值转换为 datetime 对象。这将使访问年,月,日,工作日更容易。
df['date'] = pd.to_datetime(df.date, format='%Y-%m-%d')
注意:df.date 与 df[‘date’]相同。只要列名是有效的变量名,就可以使用点(.),否则您将需要使用 df[‘列名’]
数据集最常见的问题之一是空值。让我们从数据帧中删除标题为空的行。
df = df[pd.notnull(df['title'])]
现在我们可以开始分析了。
分析
让我们按日期分析文章发表的频率。
ax = df.groupby(df.date.dt.year)['title'].count().plot(kind='bar', figsize=(12, 6))ax.set(xlabel='Year', ylabel='Number of Articles', title="Articles Published Every Year")plt.show()
上面几行代码按年份对记录进行分组,并绘制计数。代码中的一切似乎都是不言自明的。我们可以将kind
参数设置为其他值,如 line 表示线图,barh 表示水平条。查看文档了解更多详情。
我们可以为月份和工作日绘制类似的图表。
ax = df.groupby(df.date.dt.month)['title'].count().plot(kind='bar')
months = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']ax.set_xticklabels(months)
ax.set(xlabel='Month', ylabel='Number of Articles', title="Articles Published Every Month")plt.show()
ax = df.groupby(df.date.dt.weekday)['title'].count().plot(kind='bar')days_of_week = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']
ax.set_xticklabels(days_of_week)
ax.set(xlabel='Day of Week', ylabel='Number of Articles', title="Articles Published Every WeekDay")plt.show()
- 2009 年发表的文章数量最多,1995 年最少。
- 九月份发表的文章数量最多。
- 除了九月,其他月份发表的文章数量几乎相同。
- 星期三是一周中最忙的一天。
- 不出所料,周末发表的文章数量很少。
df['date'].value_counts().head(10)
有趣的是,2009 年 9 月 2 日有 15000 多篇文章,前一天有 35000 多篇。这可能是为什么我们在之前的图表中看到 9 月和 2009 年以相当大的优势赢得比赛的原因。
让我们忽略前 5 个结果,绘制一个图表来显示按日期发布的文章的分布。
ax = df['date'].value_counts()[5:].plot(color='red', figsize=(12,6))
ax.set(xlabel='Date', ylabel='Number of Articles')
plt.show()
我仍然很好奇 2009 年 9 月 2 日发生了什么,导致如此大量的文章被发表。我们来看看当天出现在头条上的主导关键词。
from wordcloud import WordCloud
stopwords = set(open('stopwords.txt').read().split(','))
wc = WordCloud(stopwords=stopwords)
wordcloud = wc.generate(' '.join(df[df.date=='2009-09-02']['title'].apply(str)))plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()
苹果似乎在当天的新闻中占据主导地位。我们可以在词云中看到 Mac,Apple,iTunes 这样的关键词。
wordcloud = wc.generate(' '.join(df['title'].apply(str)))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()
纵观整个数据框架,头条新闻被谷歌、苹果、微软和脸书占据,这是意料之中的。
我们还可以统计一些热门关键词在头条中的出现次数。
keywords = ['microsoft', 'apple', 'facebook', 'google', 'amazon',
'twitter', 'ibm', 'iphone', 'android', 'window', 'ios']for kw in keywords:
count = df[df['title'].str.contains(kw, case=False)].title.count()
print('{} found {} times'.format(kw, count))microsoft found 12918 times
apple found 17762 times
facebook found 6342 times
google found 13409 times
amazon found 4162 times
twitter found 3340 times
ibm found 3178 times
iphone found 11543 times
android found 5801 times
window found 6063 times
ios found 3199 times
这是对 CNET 头条新闻的基本分析。你可以在我的 github repo 这里找到笔记本和数据。
随便玩玩,看看能不能在数据里找到什么有趣的东西,如果我漏掉了什么,就告诉我。
喜欢这篇文章吗?在我分享类似内容的 Twitter 上找到我。
使用聚类分析分析信用卡购买模式
使用各种聚类模型来评估信用卡购买模式,然后为客户提供建议
问题简介
在深入研究各种聚类方法之前,让我们简短地看一下我们在这里试图解决的问题。随着时间的推移,一家信用卡公司支持其拥有的各种客户的数据。该公司收集了与客户相关的各种事实的数据,如他们的余额、购买量、预付现金、信用额度等。该团队的任务是从数据中获得有意义的见解,然后制定战略,使公司能够锁定客户并增加信用卡销售额,从而增加收入。
在绘制了简短的数据集描述后,我们注意到数据如下所示:
Partial Data Description of the Credit Card dataset
我们首先分析各种聚类方法,然后向客户提供我们的建议。让我们先简单了解一下聚类和 K 均值。
集群简介
聚类是对一组对象进行分组的任务,使得同一组(称为簇)中的对象比其他组(簇)中的对象更相似(在某种意义上)。聚类处理数据分组,将一对相似的数据点放在同一个聚类中。因此,数据点之间匹配的相似性的概念在聚类中起着重要的作用。集群是平面的或分层的,使用 scikit-learn 的集群包( sklearn.cluster )在 Python 中实现。
扁平聚类将帖子分成一组簇,这些簇之间没有关联。目标是创建内部相似但与其他集群不同的集群。在层次聚类中,聚类的数量不需要预先指定,而是取决于树状图。创建了一个集群层次结构。
让我们首先实现 K-Means 聚类方法,然后评估有哪些建议。
k 均值聚类
如上所述,K-Means 聚类是一种平面聚类,我们可以用一组聚类数来初始化模型。K-Means 模型的工作原理是选择 K 个质心,然后根据最小数据点对数据点进行分组,然后重新定位质心,直到实现收敛,前提是聚类是稳定的。
K-Means working. Source: Anirudh Sharma’s answer on Quora
现在,让我们绘制一个肘形图来评估最佳的集群数量应该是多少。肘形图,也称为 Scree 图,是一种给出关于簇的信息的图。肘图:
The Elbow Plot
所以,看上面的图,我们假设我们分析的最佳聚类数是 4。现在,使用 4 个聚类,并应用 K-Means 聚类,我们的结果是:
Clusters plotted against the various variables
对于上面的 K-Means 聚类,我们使用随机初始化方法。随机初始化的问题是,每次运行时,类内平方和都会改变,因为质心是随机选择的。这被称为 随机初始化陷阱 ,应该避免。为了避免这种情况,只需使用 k-means++初始化方法,该方法使用固定点作为质心,因此可以得到更好的结果。
K-Means++ Initialization
使用 K-Means init 方法的聚类可视化如下所示:
Visualization for K-Means Init Method
我们可以看到 K-Means++初始化方法确实比 random init 方法工作得更好。
分层聚类
转到其他类型的聚类方法,我们可以观察层次聚类方法。该方法不需要预先指定聚类,而是通过使用树状图来选择聚类。树状图是一种描述聚类分布方式的图表。分层聚类从其聚类中的每个数据点开始,并继续组合聚类,直到达到单个聚类。然而,为了阻止单个聚类的形成,通常使用树状图标准,该标准将不与水平线交叉的最长边作为最小距离标准。任何穿过这条线的聚类都将在最终模型中被选择。
这里需要注意的一点是,K-Means 聚类旨在减少距离,而层次聚类试图减少聚类中的方差。因此,HC 提供了更好和更清晰聚类,尽管它们不是最佳的,因为它们没有被距离分开。
Agglomerative HC Working Source: Machine Learning A-Z by Kirill Eremenko
通过使用 scikit-learn.cluster 包中的 AgglomerativeClustering(),可以在 python 中实现层次聚类。我们分析的树状图如下:
Dendrogram for the Credit Card dataset
从上面我们知道,我们可以选择集群的数量为 3。在这样做之后,使用上面的方法,我们可以观察到集群看起来像:
The behavior of various clusters across various variables
基于密度的聚类
基于密度的聚类方法基于根据聚类的不同密度来分布点。DBScan 聚类是一种聚类方法,它使用基于密度的方法,而不是 K-Means 和 HC 中基于距离的聚类。DBSCAN 的全称是带噪声应用的基于密度的空间聚类。将 DBSCAN 方法拟合到信用卡数据集,然后可视化聚类,我们得到:
Visualization for DBSCAN Clustering
通过查看上面的 DBSCAN 分析,可以更清楚地观察到,在这种情况下,聚类具有更非线性的形状,因此,当数据不是线性可分的时,应该使用这些类型的聚类方法。
来自数据的营销洞察
以下是营销策略的一些输入:
高余额,高购买量 —这些人购买了昂贵的东西,但他们也有更高的余额来支持这些购买。他们也支付了大笔款项,可能成为市场研究的目标。
高余额,低购买(较高的购买值)——这些人有较高的余额,但购买量较低,有中等或较高的信用额度,并提取大量现金预付款。
中等余额,中等购买量 —这些客户没有低余额或高余额,也没有大额或小额购买,但他们做的一切都处于中等水平。
节俭型客户(低余额、低购买量)——这些客户购买量最小,因为他们的信用额度也很低,这意味着他们不经常购买。因此,可以假设这些客户流失了,可以设计营销策略来减少这种流失。
因此,着眼于这四个群体的营销策略可以非常有效地解决这个问题。
聚类方法的利与弊
K-Means:这些方法简单易懂,适应性强,适用于小型或大型数据集,但是我们需要选择聚类的数量
HC 凝聚聚类:这些中的最优聚类数可以由模型本身获得,并且可以用树状图进行实际可视化,但是该模型不适用于大型数据集。’
请在我的 Github 上找到这个项目的完整实现。
分析神经网络中不同类型的激活函数——选择哪一种?
在构建神经网络时,我们需要做出的强制性选择之一是使用哪个激活函数。事实上,这是一个不可避免的选择,因为激活函数是神经网络学习和逼近变量之间任何复杂和连续关系的基础。它只是增加了网络的非线性。
任何神经元(输入层神经元除外)计算输入的加权和,加上一些偏差,然后对其应用激活函数。在谈论更多关于激活函数之前,让我们先看看为什么需要它。
补充说明
本文假设读者对神经网络的概念、前向和后向传播、权重初始化、优化算法等有基本的了解。如果你不熟悉,我建议你关注我的其他关于这些主题的文章。
需要激活功能
参考下面的具有两个隐藏层的神经网络,输入层和输出层。该网络适用于三元类分类问题。
考虑在该网络中不使用激活函数的情况,则从隐藏层 1 计算的输入的加权和将被直接传递到隐藏层 2,它计算输入的加权和并传递到输出层,它计算输入的加权和以产生输出。输出可以表示为
因此,输出只是权重和输入的线性变换,不会给网络增加任何非线性。因此,这个网络类似于一个 线性回归模型 ,它只能处理变量之间的线性关系,即一个能力有限的模型,不适合图像分类、物体检测、语言翻译等复杂问题。
所以没有激活功能的神经网络
- 只能代表变量之间的线性关系。
- 不成立普适近似定理。
流行的激活功能
有许多可用的激活功能。因为激活函数只是一个数学函数,所以你也可以想出自己的激活函数。常用的激活功能有
- 物流的
- 双曲正切
- 整流线性单位
- 泄漏 ReLu
逻辑激活功能
这是一条带有等式的“S”形曲线
范围从 0 到 1。它也被称为乙状窦激活功能。输入的加权和作为输入应用于它。
对于一个大的正输入,它导致一个大的正输出,倾向于触发,对于大的负输入,它导致一个大的负输出,倾向于不触发。
激活函数的导数有助于反向传播期间的计算。在反向传播期间,计算损耗 w.r.t .参数的导数。逻辑函数的导数
物流激活功能的问题:
1.饱和问题
如果一个神经元达到其最大或最小峰值,则称其饱和。
当 f(x) = 0 或 1 时饱和,则 f’(x) = f(x)(1- f(x)) = 0
我们为什么关心饱和度?
参考下面的神经网络,其中假设权重 w211 需要在反向传播期间使用梯度下降更新规则来更新。
如果 h21 是 1,那么它的导数就是 0。所以权重 w211 没有任何更新,这个问题被称为**消失梯度问题。**重量梯度消失或降至零。
因此,使用逻辑激活函数,饱和神经元可能导致梯度消失,因此网络拒绝学习或以非常小的速率保持学习。
2.不是以零为中心的函数
零线(x 轴)两侧质量相等的函数称为零中心函数。换句话说,在以零为中心的函数中,输出可以是负的,也可以是正的。
在逻辑激活函数的情况下,输出总是正的,并且输出总是仅向一侧(正侧)累积,因此它不是以零为中心的函数。
为什么我们会关心以零为中心的函数?
让我们假设权重 w311 和 w312 需要在反向传播期间使用梯度下降更新规则来更新。
h21 和 h22 由于逻辑激活功能将始终为正。w312 和 w312 的梯度值可以是正的或负的,这取决于公共部分的值。
因此,连接到同一神经元的所有权重的梯度要么是正的,要么是负的。因此,在更新规则期间,这些权重只允许在某些方向上移动,而不是在所有可能的方向上移动。这使得优化更加困难。
这就好比你只能向左和向前移动,不能向右和向后移动,那么你就很难到达你想要的目的地。
理解了这一点,让我们指出与逻辑激活功能相关的问题
- 饱和的逻辑神经元导致梯度 消失 。
- 它不是一个 以零为中心的 函数,
- 由于 e^x,它是高度 计算密集型 这使得收敛速度较慢。
2.双曲正切
它类似于逻辑激活功能,有一个数学方程
输出范围从-1 到 1,零轴两侧的质量相等,因此是 零居中 功能。所以 tanh 克服了逻辑激活函数的非零中心问题。因此,优化变得比逻辑相对容易,并且总是优先于逻辑。
但是,一个 tanh 激活的神经元可能导致饱和并导致消失梯度问题*。*
tanh 激活函数的导数
发布与 tanh 激活功能:
- 饱和的 tanh 神经元导致 渐变消失 。
- 因为 e^x,它是高度计算密集型的。
3.整流线性单位
由于其简单性,它是最常用的函数。它被定义为
如果输入是正数,函数返回数字本身,如果输入是负数,函数返回 0。
ReLu 激活函数的导数为
ReLu 激活功能的优点
- 容易 计算 。
- 对于输入的加权和的正值, 不饱和 。
因为简单, ReLu 在 CNN 中被用作标准的激活函数。
但是, ReLu 并不是一个以零为中心的函数。
ReLu 激活功能的问题
ReLu 定义为 max(0,w1x1 + w2x2 + …+b)
现在考虑一种情况 b(偏置)呈现(或初始化为)大的负值,然后输入的加权和接近 0,并且神经元未被激活。这意味着 ReLu 激活神经元 现在死亡 。这样, 多达 50% 的 ReLu 激活神经元可能在训练阶段死亡。
为了克服 T21 的这个问题,有两个解决方案
- 将偏置(b) 初始化为较大的正值。
- 使用 ReLu 的另一种变体,称为泄漏 ReLu 。
4。泄漏的 ReLu
提出修复 ReLu 的 濒死神经元 问题。它引入了一个小斜率来保持神经元的更新有效,其中输入的加权和为 负 。它被定义为
如果输入是一个正数,函数返回该数本身,如果输入是一个负数,那么它返回一个按 0.01 缩放的负值(或任何其他小值)。
LeakyReLu curve
LeakyReLu 的导数为
leaky relu 的优点
- 正负区域都没有 饱和 问题
- 神经元 不会死 因为 0.01x 确保至少有一个小的梯度流过。虽然权重的变化很小,但经过几次迭代后,它可能会从其原始值出来。
- 容易 计算 。
- 接近零点功能。
Softmax 激活功能
对于分类问题,输出需要是包含不同类别的不同概率值的概率分布。对于二元分类问题,逻辑激活函数工作良好,但对于多类分类问题则不然。所以 Softmax 用于多类分类问题。
softmax 激活功能也是一种 s igmoid 功能。顾名思义,这是 max 函数的“软”风格,它不是只选择一个最大值,而是为最大元素分配分布的最大部分,其他较小元素获得分布的某一部分。
Softmax equation
Softmax 通常是输出层的首选,我们试图在输出中获得不同类别的概率。它应用于输出层中获得的输入加权和。
需要 Softmax 激活功能
考虑这样一种情况,对于一个三元分类问题,我们在输出层中有[2.4,-0.6,1.2]的预激活输出。预激活输出可以是任何实数值。
现在,如果我们通过取一个值并除以所有值的总和来直接计算每一类的概率。然后我们得到概率[0.57,-0.14,0.12]。因为概率永远不会是负的,所以这里不接受类别 2 的预测概率。因此,我们在输出层使用 softmax 激活函数来解决多类分类问题。
如果输入值为负,那么 softmax 也会返回正值,因为 e^x 总是给出正值。
结尾注释:现在更喜欢哪一个?
理解了所有的激活函数,现在有趣的问题是使用哪一个?
嗯,基于场景的激活功能选择没有硬性规定。决策完全取决于问题的性质,即你试图近似的关系具有一些性质,基于这些性质,你可以尝试不同的激活函数,并选择一个有助于更快收敛和更快学习过程的函数,或者可以根据你选择的不同评估参数。
- 根据经验,您可以从 ReLu 开始作为通用近似器,如果 ReLu 不能提供更好的结果,则切换到其他函数。
- 对于 CNN , ReLu 被视为标准激活功能,但如果它遭遇死神经元则切换到 LeakyReLu 。
- 永远记住 ReLu 应该只用于隐藏 层。
- 对于分类, Sigmoid 函数(Logistic,tanh,Softmax) 及其组合工作良好。但同时可能会遭遇消失渐变问题。
- 对于 RNN,****tanh激活功能是首选的标准激活功能。
用 VAR 模型预测 Python 中的电价时间序列数据
向量自回归模型的时间序列分解和预测速成班
在过去的几年里,我处理过一些涉及时间序列分析和预测的项目,但是我总是发现这个主题对于初学者来说有些难以理解,因为缺乏全面的 Python 教程。因此,为了纠正这一点,这篇文章带领初学者通过时间序列分析,使用能源信息管理局的 API 提供的德克萨斯州每月电价数据。具体来说,本教程涵盖了时间序列分解和向量自回归(VAR)建模,以预测德克萨斯州的电价。
首先,简单介绍一下能源信息署(EIA)的背景。EIA 是美国能源部的一个分支,负责收集和分析能源相关数据,包括石油和天然气、煤炭、核能、电力和可再生能源。通过其开放数据应用编程接口(API) ,用户可以直接将 EIA 时间序列数据拉入 Python 进行分析。
关于在 Python 中设置 EIA API 访问的更多背景,请查看本教程:https://techrando . com/2019/06/26/how-to-use-the-energy-information-administration-EIA-application-programming-interface-API-and-pull-live-data-directly-into-Python-For-analysis/
在本分析中,我们将把德克萨斯州的电价时间序列放入 Python 进行分析,如下所示:
Snapshot of the time series data for electricity prices, pulled via the EIA API
首先,让我们看看月度电力数据是否显示了季节性和趋势。为此,我们使用 statsmodels.tsa.seasonal 包中的季节性分解()函数。该函数将时间序列分解为其核心部分:趋势、季节性和随机噪声。代码及其输出显示如下:
Time Series Decomposition: Monthly Electricity Prices in TX
那么上面的情节是什么意思呢?如果我们仔细观察分解的季节性成分,我们可以验证一个合乎逻辑的趋势:在德克萨斯州的夏季,电价飙升。对于任何一个在盛夏去过德克萨斯州的人来说,那里酷热难当,没有空调几乎无法居住(我知道,我住在休斯顿)。因此,更多的空调导致更多的用电量,从而导致更高的电价。
此外,每年年初左右,电价会出现第二次小幅上涨。这可能是由于天气足够凉爽,德州人求助于加热他们的家,办公室等。由于德州大部分地区冬天的天气相当温和,所以这种价格上涨明显不如夏天的电价上涨明显。
现在,我们已经使用时间序列分解进行了一些初步分析,我们希望确定是否可以使用另一个预测时间序列作为代理来预测电价。为了了解什么因素会影响电价,让我们先来看看德克萨斯州的电力是如何产生的。美国能源情报署在其网站上提供了德克萨斯州电力来源的分类,如下图所示:
Image courtesy of https://www.eia.gov/state/?sid=TX#tabs-4
根据上述图表,截至 2019 年 3 月,天然气似乎是德克萨斯州发电的主要来源,燃煤和可再生能源并列第二。
虽然我们分析的电力数据可以追溯到 2001 年,上面的细分数据是从 2019 年 3 月开始的,但为了简单起见,我们假设天然气是过去 15-20 年德克萨斯州发电的主要来源之一。因此,我们将通过 EIA API 提取天然气价格的时间序列,并与德克萨斯州电价时间序列进行对比:
Plotted Natural Gas Prices and Electricity Prices over Time
天然气价格时间序列似乎有更多的变化(高点特别高,低点特别低),但在大多数情况下,两个时间序列的趋势似乎非常相似。事实上,我们很有可能使用天然气价格作为代理来估算 TX 电价。
这提出了一个有趣的问题-使用一个时间序列的滞后值以及其他时间序列集的滞后值来预测未来值。解决此类问题的一种方法叫做向量自回归,或 VAR。VAR 是自回归(或 AR)模型的扩展,在生成预测时使用多个变量。VAR 模型因其在分析经济和金融时间序列时的灵活性而非常受欢迎,并且非常适合预测。
下图给出了带有两个变量和一阶动力学的 VAR 方程的分解。这是一个非常简单的线性方程,其中 t-1 时刻的 x 值和 y 值用于预测 t 时刻的 x 值和 y 值。由于变量 x 依赖于变量 y,反之亦然,因此使用一个方程组来共同考虑它们。基本上,VAR 模型通过使用多个相关时间序列的滞后数据来预测未来值。
VAR equation for two variables and first-order dynamics: Image courtesy ofhttp://www.ams.sunysb.edu/~zhu/ams586/VAR_Lecture2.pdf
如果你想了解更多的背景知识,华盛顿大学提供的以下讲义对 VAR 模型背后的数学进行了深入的描述:【https://faculty.washington.edu】。
此外,芝加哥大学布斯商学院在以下演讲中对风险值建模进行了高度概括:https://faculty . Chicago Booth . edu/Jeffrey . Russell/teaching/time series/讲义/notes5.pdf
与大多数经济计量分析一样,VAR 模型的运行有几个要求。首先,过去的时间序列需要是静态的,即时间序列的统计属性,包括均值、方差和自相关,需要随时间保持不变。因此,显示季节性或趋势的时间序列不是静止的。
有几种方法可以让模型静止。它们如下:
- 差分时间序列。数据差分或多或少是计算每个数据点的瞬时速度,或时间序列从一个值到下一个值的变化量。
- 转换时间序列。这可以通过对数据应用对数或幂变换来实现。
接下来,为了使风险值模型发挥作用,采样频率(即每日、每月、每年的数据)需要相同。如果不是,则需要使用插补/线性插值等方法将数据转换成相同的频率。
在下面的代码中,每个时间序列都使用 numpy 自然对数函数进行转换,然后按一个间隔进行差分:
为了检验时间序列现在是否是平稳的,我们使用扩展的 Dickey Fuller 检验。扩展的 Dickey-Fuller 检验检验单位根存在于时间序列中的零假设(即,如果单位根存在于时间序列中,那么它不是平稳的)。要成功确定时间序列是平稳的,测试必须返回小于. 05 的 p 值。在下面的 Python 代码中,我们对转换后的差分时间序列运行了扩展的 Dickey-Fuller 测试,确定它们都是平稳的(对于电力和天然气时间序列,返回的 p 值分别为. 000299 和 0):
Outputs for the Augmented Dickey-Fuller Test for the electricity price time series and the natural gas price time series, respectively
现在,我们已经使我们的两个时间序列平稳,是时候将数据拟合到 VAR 模型中了。下面的 Python 代码成功构建了模型并返回了结果摘要,其中我们对训练/验证集使用了 95/5%的拆分:
VAR Model Summary, with y1=Electricity Price Time Series, and y2=Natural Gas Price Time Series
在上面的模型总结中,我们真正想要关注的是 y1 的等式,其中 y1 根据其自身的滞后值和滞后天然气价格来估计德克萨斯州的电价。
存在与滞后电价数据(L1.y1)和滞后天然气价格数据(L1.y2)相关联的 t 统计量和 p 值。t 统计将数据与零假设下的预期结果进行比较。如果样本结果正好等于零假设,则 t 统计量为 0。或者,t 统计值越高,我们就越有可能拒绝零假设。基本上,t 统计值越高,两个变量之间的相关性就越大。
每个 t 统计量都有一个相应的 p 值。p 值也用于拒绝零假设。p 值越低,反对零假设的证据越强。通常,小于 0.05 的 p 值用于确定统计显著性。
有关 t-统计和 p-值的更多信息,请查看以下链接:https://blog . minitab . com/blog/statistics-and-quality-data-analysis/what-are-t-values-and-p-values-in-statistics
记住所有这些信息,让我们来解释方程 y1 的模型总结的结果。
对于滞后电价变量,t 统计量为 3.002,p 值为 0.003-显然,电价时间序列的滞后值会影响时间序列的未来值,我们可以拒绝零假设。
天然气价格时间序列的滞后值也很有希望,t 统计值为 2.225,p 值为 0.026,远低于统计意义的临界值,并且明确表明天然气时间序列中的滞后值会影响电价时间序列中的未来值。
现在我们已经建立了一个模型,是时候生成预测并与测试/验证集中的实际数据进行比较了。需要注意的是,为了理解电价预测,数据必须是无差异的和反向转换的。以下代码执行非差分和反向转换操作,并计算与评估模型性能相关的预测指标,包括预测偏差、平均绝对误差、均方误差和均方根误差:
Actual electricity price vs. VAR-model predicted electricity price, predicted out 10 months (after un-differencing and back-transformation)
Accuracy metrics for the forecast: forecast bias, mean absolute error, mean squared error, and root mean square error
这里的结果看起来很有希望!VAR 似乎相当准确地估计了电价。预测偏差度量为-0.041638,表明模型有过度预测或预测过高的趋势。平均绝对误差、均方误差和均方根误差也相当低,这很好。根据平均绝对误差(MAE ),预测值和实际值之间的平均偏差为 0.22 美元。
有关时间序列预测模型指标的更多背景信息,请查看以下链接:https://machinelingmastery . com/time-series-forecasting-performance-measures-with-python/
本教程到此结束。感谢您的阅读!
此分析的完整脚本可通过 Github 获得:https://Github . com/kperry 2215/electricity _ price _ time _ series _ analysis/blob/master/analyze _ monthly _ electricity _ data . py
查看我的其他一些与能源相关的 Python 教程:
分析开源 FracFocus 数据以获得完井见解:https://techrando . com/2019/07/14/using-public-available-frac focus-data-and-python-matplotlib-function-to-visualize-oil-and-gas-companies-completions-strategies-in-the-二叠纪盆地/
原载于 2019 年 7 月 19 日http://techrando.com。
分析员工评论:谷歌 vs 亚马逊 vs 苹果 vs 微软
值得为哪个公司工作?
概观
无论是因为他们提供高薪、奢侈津贴的能力,还是他们令人兴奋的使命宣言,很明显,像谷歌和微软这样的顶级公司已经成为人才磁铁。客观地说,仅谷歌每年就收到超过 200 万份工作申请。
为顶级科技公司工作是许多人的梦想,这当然是我很长一段时间的梦想,但我们不应该问自己“为这些公司工作真的值得吗?”有谁比他们自己的员工更能帮助我们回答这个问题呢?在这篇文章中,我将带你浏览我对谷歌、微软、亚马逊和苹果员工评价的分析,并试图发现一些有意义的信息,希望这些信息能在我们决定值得为哪家公司工作时有所启发。
我将从描述我如何清理和处理数据开始,然后借助一些可视化来谈谈我的分析。我们开始吧!!
[## 通过我的推荐链接加入 Medium-Andres Vourakis
阅读安德烈斯·沃拉基斯(以及媒体上成千上万的其他作家)的每一个故事。您的会员费直接支持…
medium.com](https://medium.com/@avourakis/membership)
数据
数据收集
用于这项分析的员工评论数据是从 Kaggle 数据集下载的,它来自 glass door——一个现任和前任员工匿名评论公司及其管理层的网站。该数据集包含超过 6.7 万条谷歌、亚马逊、脸书、苹果和微软的员工评论。
这些评论分为以下几类:
- 指数:指数
- 公司:公司名称
- 位置:该数据集是全球性的,因此它可能包括括号中的国家名称[即“安大略省多伦多(加拿大)”]。但是,如果位置在美国,那么它将只包括城市和州[即“洛杉矶,加利福尼亚州”]
- 发布日期:格式如下年月日
- 职位:该字符串还包括审核人在审核时是“现任”还是“前任”员工
- 总结:员工考核的简短总结
- 赞成:赞成
- 缺点:缺点
- 总体评分:1-5 分
- 工作/生活平衡评分:1–5 分
- 文化和价值观评分:1–5 分
- 职业机会评级:1–5
- 薪酬&福利等级:1–5
- 高级管理层评级:1–5
- 有帮助的评论统计:统计有多少人认为该评论是有帮助的
- 链接到评论:这将为您提供包含评论的页面的直接链接。然而,这种联系很可能会过时
以下是表格形式的数据:
Preview of data in tabular form (Not showing the last two columns)
数据清理
在做了一些基本的数据探索之后,我决定做以下事情来为我的分析准备数据:
- 只包括谷歌,亚马逊,微软和苹果的员工评论。尽管脸书和网飞有大量的综述,但加在一起,它们只代表了不到 4%的数据集,所以为了简单起见,我决定将它们排除在分析之外。
- “链接”和“给管理层的建议”专栏被删除了,因为我认为它们不会像其他专栏那样有见地。
- 删除了“日期”列中缺少值的行。
- 创建了一个名为“Year”的新列,包含进行评审的不同年份。
- 以下各列中缺少值的行将被删除:“公司”、“年份”、“总体评分”和“职位”。
- 删除了所有列中都缺少值的行。
- 包含数值的列被转换为适当的数据类型。
洞察力和分析
哪家公司评论最多?
我从可视化我选择的 4 家公司的员工评价的分布开始我的分析。
**解读:**我们可以清楚地看到,亚马逊拥有最多的员工评论(超过 25000)。这很好,因为这可能意味着我们将看到各种观点的良好融合。虽然谷歌的员工评论数量最少,但它仍然足够大,足以让它与其他公司相比。
让我们来看看这些评价是如何在各个公司中分布的。
**解释:**如我们所见,有十年的员工评估可用,但它们只持续到 2018 年。
- 微软:大多数评论都是过去 4-7 年的
- 谷歌:大多数评论都是过去 4 年的
- **亚马逊:**大多数评论都是过去 3-4 年的
- **苹果:**大多数评论都是过去 2-4 年的
基于这些观察,并考虑到这些公司每年发展和变化的速度,我决定继续分析过去 4 年(2015 年至 2018 年)的员工评估,因为我认为它们是最相关的。
谁在复习?
现在我们已经知道我们要处理多少评论,让我们弄清楚是谁写的。这个问题可以用许多不同的方法来回答,我的第一个方法是找出评审者的职称,下面是前 5 名的样子:
Anonymous Employee 21910
Software Engineer 930
Specialist 648
Software Development Engineer 618
Warehouse Associate 585
不幸的是,大部分职位都被贴上了“匿名员工”的标签。考虑到很多时候公司对同一份工作的称谓略有不同,我决定不再深究。相反,让我们看看有多少评审者是现任和前任员工
正如我们所看到的,大多数评论来自当前的员工,但为了获得更多的洞察力,让我们看看每个公司的分布情况:
**解读:**再一次,我们看到大多数对每家公司的评论都是来自现在的员工。这些是在试图解读数据时想到的一些想法:有大量来自当前员工的评论是一件好事还是意味着更多的偏见?也许,有更多前员工的评论可以给我们一些我们不常读到的关于这些公司的见解。让我们继续…
哪家公司综合评分最高?
让我们来看看过去几年(2015 年至 2018 年)每家公司的平均总体评分是如何变化的
**解读:**我们可以看到,自 2015 年以来,除了苹果,每家公司的平均综合评分都没有下降。谷歌在这四家公司中拥有最高的平均综合评分,并且在过去的几年里一直保持这种状态。让我们来谈谈每家公司的趋势:
- **谷歌:**似乎从 2016 年开始略有减少。
- **微软:**从 2015 年开始缓慢增长
- **苹果:**好像在慢慢减少。
- **亚马逊:**从 2015 年到 2017 年急剧增长。
哪家公司能更好地平衡工作和生活?
让我们看看这些公司在允许员工拥有工作之外的生活方面做得有多好:
**解读:**谷歌的工作生活平衡评分最高(超过 4 星),微软紧随其后。在提供良好的工作生活平衡方面,亚马逊似乎有所欠缺。
哪家公司的文化价值观更好?
让我们看看员工如何评价他们公司的核心原则和理念:
**解读:**谷歌的文化价值观评分最高,苹果排名第二(超过 4 星)。亚马逊在 4 个等级中排名最低,但仅略高于 3.5 星。
哪个公司的职业机会比较好?
他们在帮助你推进职业发展方面有多出色?
**解读:**谷歌对职业机会的评分最高(超过 4 星)。考虑到这家公司有多大,他们正在使用多少种不同类型的技术,这并不奇怪。苹果的评分最低,仅略低于 3.5 星。
哪家公司福利待遇更好?
让我们看看这些公司在员工福利方面做得如何。
**解读:**谷歌的福利/津贴评分最高,超过 4.5 星。苹果和微软似乎也提供了很好的好处,但亚马逊有点不足。
哪个公司的高层管理比较好?
领导力是管理层的一项重要职能,让我们看看这些公司是如何评价高级管理层的领导力的:
**解读:**谷歌的高级管理层获得最高评级,但仅略低于 4 星,与其他评级相比是最低的。亚马逊对高级管理层的评价最低。
每个公司的优点是什么?
让我们用文字云来探索一下专业人士的评论:
以下单词在所有 4 家公司中都很常见(非常频繁),但不包括在单词云中:利益、公司、文化、环境、好、伟大、很多、机会、人、工作和工作。
这些词在试图找出这些公司的优秀之处时都很重要,但我决定省去它们,以便为其他频繁出现的关键词腾出空间,这些关键词可能对每个公司更独特/更有见解。以下是员工喜欢他们公司的几个方面:
- **谷歌:**额外津贴、聪明人、免费食物和高薪。
- **亚马逊:**学习的能力,他们的团队,聪明的人和管理。
- 苹果公司:员工折扣、产品、团队、有趣的环境和良好的培训。
- **微软:**聪明的人、产品、薪酬、技术和他们的团队。
每个公司的缺点是什么?
让我们使用单词云来研究一下反对意见:
以下单词在所有 4 家公司中都很常见(非常频繁),但不包括在单词云中:company、get、lot、management、manager、people、time 和 work。
这些词在试图找出是什么让这些公司变得糟糕时都很重要,但我决定不考虑它们,以便为其他频繁出现的关键词腾出空间,这些关键词可能对每个公司更独特/更有洞察力。以下是员工不喜欢公司的几个方面:
- 谷歌:他们的团队、艰苦的工作、项目、办公室政治以及缺乏工作与生活的平衡
- **亚马逊:**缺乏工作与生活的平衡,工作时间和文化。
- **苹果:**工作生活平衡的缺失,零售店,顾客,薪酬。
- **微软:**办公室政治、工作与生活缺乏平衡、他们的团队、努力工作和文化
结论
通过分析,我们发现谷歌不仅拥有最高的整体平均评分(低于 4.4 星)(截至 2018 年),而且在工作生活平衡、福利/津贴、文化价值观、高级管理和职业机会方面也排名第一。微软排名第二,总体平均评分略高于 4 星,但苹果似乎有更好的高层管理和文化价值观,并提供更好的福利/津贴。除了就业机会,亚马逊几乎在所有类别中都排在最后。
我们还了解到,尽管有评级,但总的来说,员工发现他们公司缺乏工作与生活的平衡是有问题的。此外,单词云显示,所有 4 家公司的首要缺点是管理、人员(其他员工)和工作本身。这三个缺点也是人们辞职的主要原因之一。
我们应该问自己的是,知道谷歌有多受欢迎,为什么在我们分析的 4 家公司中,它的评论最少?是因为它的员工数量最少还是我们遗漏了什么?
我当然想到了许多其他问题,但必须指出,这绝不是详尽的分析。
尽管如此,我希望这篇文章是有见地的,并且您会受到启发来扩展这一分析,或者使用您的数据科学技能来研究不同的感兴趣的主题。如果你想看代码,所有的代码都被仔细地记录在这个 Jupyter 笔记本上。
请在评论中告诉我你的想法和反馈。有什么事情你会做得不一样吗?我可以使用哪些其他数据作为分析的一部分?
此外,如果你希望支持我成为一名作家,可以考虑注册成为❤️的媒体成员
用 Python 分析英超数据及用 Tableau 可视化
Photo by Nathan Rogers on Unsplash
由 M.P.Karthick、 Janmejay Singh 和 Pritam Kumar Patro 出版
数据科学家和数据本身一样优秀。因此,为了获得可操作的见解,使用正确格式的数据集和正确的变量非常重要。体育分析是一个新兴领域,其中数据驱动的见解用于制定战略。在本教程中,我们将探索使用 Python 的数据分析和使用 Tableau 的可视化。我们将使用的 python 库是 pandas、os、glob 和 regex。
我们将使用的数据集是发布在 http://www.football-data.co.uk/的英超联赛数据集。我们分析了从 2009 年 10 月到 2018 年 19 月的 10 个 EPL 赛季的数据。使用这些数据集将帮助我们学习数据整理和转换过程,这在 iris 和 mpg 等内置数据集上是不可能的。
提问:
我们希望从数据集中了解并得出以下见解:
如何追加不同季节的数据,创建主数据集?
如何整理和转换主数据集?
曼联各个赛季的进攻表现如何?
曼联各个赛季的防守表现如何?
曼联在不同的主教练手下表现如何?
在穆里尼奥的领导下,曼联是一支防守型球队吗?
加载库和模块:
import pandas as pdimport osimport globimport re
Pandas 是一个开源库,为 python 编程语言提供了易于使用的数据结构和数据分析工具。python 中的 OS 模块提供了与操作系统交互的功能。这个模块属于 python 的标准实用程序模块。该模块有助于提供一种使用操作系统相关功能的便携方式。
glob 模块根据 UNIX shell 使用的规则找到所有与指定模式匹配的路径名。但是,这些结果以任意顺序返回。正则表达式是构成搜索模式的字符序列。Python 通过库支持正则表达式。正则表达式模式通过 Python 中的 re 模块导入。RegEx 可用于检查字符串是否包含指定的搜索模式。
数据整理和转换
在将数据集导入 Python 环境之前,我们将确保 CSV 格式的 10 个季节的数据表位于运行 Python 程序的同一个文件夹中。
我们发现数据集中缺少我们分析所需的两个重要变量。我们需要“赛季”变量来产生赛季洞察力,需要“经理”变量来理解曼联在不同经理下的表现。我们从英超网站上获得了这 10 个赛季的主教练名单,数据集已经按赛季排列好了。因此,我们将把这两列添加到数据集中,稍后将它们追加到一个数据表中。
man=["SAF","SAF","SAF","SAF","DM","VG","VG","JM","JM","OS"]a=glob.glob("season*.csv")b=[]for i in a:c=re.search(r"\d{2,}",i).group()b.append(c)
追加数据集:
EPL 的数据集是季节性的。当我们对数据集进行初步观察时,我们没有发现任何缺失值。当我们跨赛季匹配变量时,从 2012-13 赛季开始出现了新的变量。我们只保留了我们在分析和可视化方面感兴趣的变量。
count=0for i,j,k in zip(a,b,man):dataL=pd.read_csv(i)dataL.insert(0,"season",j)dataL.insert(0,"manager",k)if count==0:data.to_csv("dataL.csv",mode="a",index=False)count=count+1else:dataL.to_csv("dataL.csv",mode="a",index=False,header=False)
使用上面的代码,我们在工作文件夹中得到一个名为 dataL.csv 的数据表,其中包含所有 10 个赛季,包括赛季和经理列。
由于我们只分析与曼联相关的数据,我们删除了所有与其他俱乐部相关的数据。因此,我们已经使用 python 成功地清理和转换了数据,现在可以进行可视化了。
dataMU1=pd.read_csv(“dataL.csv”)dataMU2=dataMU1.loc[(dataMU1[‘HomeTeam’] == ‘Man United’) | (dataMU1[‘AwayTeam’] == ‘Man United’)]dataMU2.to_csv(“finaldataManUtd.csv”)
创建 Tableau 仪表板
Tableau 是一个强大的数据可视化工具,有助于以仪表板和工作表的形式创建可视化效果。tableau 的好处是它有点击和拖动的选项,这使得编程技能较低的人可以制作出令人惊叹的可视化效果。我们开发的 tableau 仪表板非常具有交互性,让您挑选感兴趣的见解。我们只分析了数据集中的一些变量。还有更多变数,比如犯规次数,黄牌数量等等。如果你感兴趣的话,可以去探索一下。
[## Tableau 公共
编辑描述
public.tableau.com](https://public.tableau.com/profile/pritam.kumar.patro#!/vizhome/ManUnitedComparison/Dashboard9)
对比曼联各个赛季的进攻表现
很多参数可以用来评估一支球队的进攻表现。我们使用进球数(主客场)、总射门数和目标变量进行分析。当我们绘制跨赛季的进球时,我们可以看到,自从 2012-13 赛季结束弗格森爵士退役以来,曼联的进攻表现已经不一样了。弗格森爵士执教下(2009-10 赛季至 2012-13 赛季)的平均主场进球是 49.5 个,相比之下,范加尔和穆里尼奥分别为 34.0 和 32.0 个。类似的趋势也可以在客场进球中观察到。
投篮命中率(命中目标的投篮次数/总投篮次数)是决定一个队能否赢得比赛的重要因素之一。另一项分析显示,与那些仅仅比对手创造更多投篮机会的球队相比,命中率更高的球队获胜的概率明显增加。我们的分析表明,自从弗格森爵士退役以来,曼联的射门准确率明显下降,从未越过 50%。
对比曼联各个赛季的防守表现
与进攻表现不同的是,防守表现对于不同主帅手下的曼联来说差别并不大。上赛季(2018–19)出现了近 10 个赛季以来最差的防守表现。
曼联在不同主帅手下表现如何?
毫无疑问,曼联在弗格森爵士手下的表现是最好的。比较整个赛季的联赛积分和联赛排名给了我们清晰的叙述。在弗格森爵士之后,下一个最佳教练是穆里尼奥,81 分,2017-18 赛季亚军。
曼联在穆里尼奥手下是防守型球队吗?
何塞·穆里尼奥的足球哲学与其他顶级教练不同。他的比赛风格已经被证明能够在对抗最好的球队时取得好成绩。但它也被认为是防御性的和无聊的。这篇博客还认为,随着职业生涯的发展,他变得更加具有防御性。如爆炸图所示。在穆里尼奥的带领下,曼联的防守表现比其他教练都要好。当我们比较进攻表现的时候,这和其他曼联经理类似,比如大卫·莫耶斯和路易斯·范加尔。
希望这能帮助你对你喜欢的体育相关数据进行基本的分析和可视化。Python 语法非常简明易懂。Tableau 是最好的用户友好的可视化工具之一。上面给出的所有可视化都可以用 python 来完成,但是我们想讨论一下这两个神奇的工具,并展示使用它们是多么容易!
分析数据和人工智能初创公司的特征和全球分布
我喜欢初创公司,也喜欢人们可以做什么来让这个世界变得更好。而且,由于我在数据和人工智能领域工作,我对探索 AngelList 上的数据和人工智能初创公司更感兴趣。从 AngelList 收集数据并不简单,因为它不会让您一次导出超过 100 条记录。因此,我应用了多个过滤器,如 Type="Startup “,” Market="Big Data Analytics “,” Data Science “,” Big Data “,” Machine Learning,Predictive Modeling “,” Computer Vision “,” Natural language Processing “,” Neural Networks “,” Deep Learning “,” Reinforcement Learning ",然后排除了重复的过滤器,因为这些过滤器的结果在一些操作中有重叠。我 26 次得到不到 100 条记录,因此创建了 26 条。csv 文件。最后,我合并了这些。csv 文件合二为一。csv 文件,并随后在数据帧中添加了标题。
sed 1d companies*.csv > startup.csv
这是对初始数据集的一瞥。
df=pd.read_csv("startup.csv",names=["Name","Profile URL","Signal","Joined","Location","Market","Website","Employees","Stage","Total Raised"])
我对该数据集进行了处理,将“Joining”拆分为“Joining_Year”和“Joining_Month ”,并删除了“Joining ”,在 Year 前面附加了“20 ”,使用以下命令删除了重复的行。
df.drop_duplicates(keep=False,inplace=True)
df[['Joining_Month','Joining_Year']]=df.Joined.str.split("'",expand=True)
df.drop(['Joined'], axis=1, inplace=True)
df['Joining_Year'] = ('20' + df['Joining_Year'])
df.head()
使用 python 的计数器,我用下面的代码找出了 10 大创业市场。
from collections import Counter
c=Counter(df.Market)
histo=c.most_common(10)
freq={}
for item,count in histo:
freq[item]=count
explode = (0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05)
plt.pie([float(v) for v in freq.values()], labels=[(k) for k in freq],
autopct='%.2f',startangle=90, pctdistance=0.85, explode = explode,radius=3,textprops={'fontsize': 14})centre_circle = plt.Circle((0,0),0.90,fc='white')
fig = plt.gcf()
fig.gca().add_artist(centre_circle)
plt.tight_layout()
plt.show()
Top 10 Startup Markets in Data/AI. We see SaaS is the leader followed by ‘Big Data Analytics’, ‘Predictive Analytics’ and ‘IoT’.
类似地,我努力寻找这些创业公司的多种属性,你可以找到如下的环形图。
Distribution of number of employees across startups. ‘nan’ indicates that number was not specified in the AngelList database for these companies.
Top 10 cities across the world for DS/AI startups, note 7 are in the USA with the exception of Berlin and London. ‘nan’ indicates that city was not specified in the AngelList database for these companies.
Distribution of funds raised across the startups. ‘nan’ indicates that funds raised was not specified in the AngelList database for these companies.
Distribution of the stages of the startup. As we see majority are in ‘nan’ stage, this indicates that stage was not specified in the AngelList database for these companies. Amongst the valid stages, most startups are in seed stage, which makes sense, as initially startups struggle to get funded.
贴完这篇文章,我想到了在 2013 年之前和之后的时代描绘全球各地的创业公司。为此,我使用了以下代码。我从 IGIS 地图上下载了“continentsshp31.shp”。此外,为了在地图上绘制这个数据帧,我需要每个城市的经度和纬度,这是我使用 geopandas 计算的。
#install the following libraries# !pip3 install geopandas
# !pip3 install descartes
# !pip install geopyimport matplotlib.pyplot as plt
import geopandas
from geopy.geocoders import Nominatim
world = geopandas.read_file("continentsshp3147/continentsshp31.shp")
geolocator = Nominatim(user_agent="ds")# code to retrieve latitude and longitude
from geopy.extra.rate_limiter import RateLimiter# 1 - convenient function to delay between geocoding calls. I did this in groups of 100 as the service was getting timed out. Later, I combined all slices.geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)# 2- - create location column
df_100=df[:100]
df_100['location'] = df_100['Location'].apply(geocode)# 3 - create longitude, latitude, altitude from location column (returns tuple)
df_100['point'] = df_100['location'].apply(lambda loc: tuple(loc.point) if loc else None)# 4 - split point column into latitude, longitude and altitude columns
df_100[['latitude', 'longitude', 'altitude']] = pd.DataFrame(df_100['point'].tolist(), index=df_100.index)# combine the slices with latitude and longitude
df_new = pd.concat([ df_100,df_101_200,df_201_300,df_301_400,df_401_497])
df_new = df_new.sample(frac=1).reset_index(drop=True)
df_new.head()
产生的数据帧如下所示。
下一步是获取几何格式的数据。方法是将 Pandas 数据框架转换为 geo-data 框架,这需要原始数据框架、坐标参考系统(CRS) 和新数据框架的几何参数。为了适当地格式化几何图形,我们需要将经度和纬度转换成点(我们从上面的 shapely 中导入点),所以让我们传递熊猫数据帧,并使用 EPSG:4326 CRS 获得经度和纬度。
from shapely.geometry import Point, Polygon
crs={'init': 'epsg:4326'}
geometry=[Point(xy) for xy in zip(df_new["longitude"],df_new["latitude"])]geo_df=gpd.GeoDataFrame(df_new,crs=crs,geometry=geometry)
fig, ax = plt.subplots(figsize=(20, 20))
world.plot(ax=ax,alpha=0.4,color='grey')geo_df[(geo_df['Joining_Year']).astype(str).astype(int)>2013].plot(ax=ax,markersize=20,color='green',marker="o",label="2014-2018")geo_df[(geo_df['Joining_Year']).astype(str).astype(int)<=2013].plot(ax=ax,markersize=20,color='red',marker="^",label="2010-2013")plt.legend(prop={'size':15})plt.title("Global distribution of DS/AI Startups joining AngelList before and after 2013")
结果图如下所示。我们看到(如右边绿色部分)在 2014-2018 年间,很少有创业公司出现在非黄金创业区。此外,世界上大多数人看起来缺乏创业精神。创业文化主要集中在美国、英国和欧洲的一些地方。
我还绘制了另一个 geopandas 地图,以查看筹集资金的全球分布和密度。
从这个数据集中可以得出更多的见解。如果你对使用这个数据集感兴趣,我已经在 kaggle 链接上上传了这个(https://www . ka ggle . com/shilpbhattacharyya/data ai-startups-dataset-from-angellist)——敬请访问。
分析被撤回的生物医学文献中隐藏的主题
在我之前的博客文章中,我讨论了生物医学和生命科学文献中涉及撤稿的各种参与者。有一个问题引起了我的兴趣,但没有得到回答——这些被撤回的出版物中有哪些研究主题?在这篇博文中,我试图用主题建模来回答这个问题。
主题建模是从语料库或文档集中发现、组织和理解文本信息。这是一种无监督的学习方法,其中主题模型学习未标记文档中的主题。它基于这样的假设,即每个主题都由单词组组成,每个文档都是主题的集合。因此,语料库中潜在的或隐藏的主题可以通过收集频繁共现的词来发现。
有许多主题建模技术可用。这里,我使用了一种最流行的技术,潜在狄利克雷分配(LDA)。
LDA 是文档集合的生成概率模型。它基于狄利克雷分布,这是一种多项式分布的分布,并假设文档是潜在主题的概率分布,主题是单词的概率分布。LDA 回溯并发现构成语料库的不同主题以及每个主题在文档中出现的数量。
从数学上讲,这种生成过程可以解释如下:
这样的图表被称为图版符号。由于媒介不允许下标,请遵循图表或提供的等式中的符号,或者在我的 网站 上阅读这篇帖子。从具有参数λ的狄利克雷分布中,我们获得了主题𝑘∈1 的单词分布…𝐾,这代表了𝛽𝑘。这里,每个主题是一个𝑁-dimensional 向量(𝑁是词汇量的大小),根据𝛽.分布,它具有主题𝑘中每个单词的概率根据具有参数𝛼的第二狄利克雷分布,我们绘制了每个文档𝑑∈1 的主题分布…𝑀,这代表了𝜃𝑑.因此,对于每个文档,我们有一个𝐾-dimensional 向量,根据主题的分布,它具有每个主题的概率(𝐾是主题的数量)。为每个单词定位𝑛∈1…𝑁在文件中给来自𝜃.的𝑧𝑛画了一个题目然后,我们使用与主题赋值𝛽𝑧𝑛相对应的𝛽来生成单词。由于 LDA 知道这些词,它打算找到𝑧、𝛽和𝜃.
简而言之,LDA 工作如下:首先,我们指定语料库中我们期望的主题𝐾的数量。然后 LDA 为每个文档中的每个单词随机分配主题。接下来,它查找语料库中的每个单词,并检查该特定主题在文档中出现了多少次,以及该特定单词在指定主题中出现了多少次。根据结果,它为这个特定的单词指定一个新的主题,这样反复下去,直到主题有意义为止。最终还是由用户来解读题目。
这篇博文将描述从我的撤稿文献语料库中提取潜在主题的以下步骤。
- 数据预处理
- 构建 LDA 模型
- 形象化
正如我在之前的博客文章中提到的,这些数据是从 PubMed 获得的,包含 6485 篇被撤稿的出版物。对于当前的分析,我只使用了这些出版物的摘要。关键词可用于确定任何摘要的主题,但在可用的数据集中,84%的摘要没有关键词,这促使我从摘要中提取主题。
数据预处理:
这一步涉及数据清理,在任何文本挖掘任务中都至关重要。我将此细分为 3 个步骤:
一.词汇化
这一部分涉及词性(POS)标记,以过滤名词、专有名词或形容词。我忽略了其他词类,如动词和副词,因为它们似乎对我当前的任务不重要。产生的单词然后被词条化,这意味着只有单词的词根形式被保留。我使用了非常棒的 Python 库 spaCy 来做这个处理。
*# load spacy and return english language object*
nlp**=**spacy**.**load('en_core_web_sm')
**def** **lemmatization**(doc, allowed_pos**=**['NOUN','ADJ','PROPN']):
```filtering allowed POS tags and lemmatizing them```
retracted_corpus**=**[]
**for** text **in** doc:
doc_new **=** nlp(text)
retracted_abstract**=**[]
**for** token **in** doc_new:
**if** token**.**pos_ **in** allowed_pos:
retracted_abstract**.**append(token**.**lemma_)
retracted_corpus**.**append(retracted_abstract)
**return** retracted_corpus
abstract_lemmatized **=** lemmatization(doc,allowed_pos=['NOUN','ADJ','PROPN'])
这些是科学文档,有时仅用空格断句并不是最佳选择(例如,公式或等式可能使用=或+等其他字符)。因此,在一个额外的步骤中,我使用了一个不同的文本分割实现,它使用了 NLTK 的一些功能,NLTK 是另一个用于自然语言处理(NLP)的 Python 库。
**from** nltk.tokenize **import** RegexpTokenizer
*# tokenizer that splits only in the selected symbols or space*
tokenizer**=**RegexpTokenizer('\s+|[<>=()-/]|[±°å]',gaps**=**True)
**def** **remove_punctuation**(text):
updated_abstract**=**[]
**for** doc **in** text:
sent**=**' '**.**join(doc)
updated_abstract**.**append(tokenizer**.**tokenize(sent))
**return**(updated_abstract)
abstract_processed **=** remove_punctuation(abstract_lemmatized)
二。删除停用词
在自然语言处理中,一个相当常规的任务是去除停用词,或者没有足够含义来区分一个文本和另一个文本的常用词,例如“a”、“the”、“for”等等。为此,我使用了 NLTK 的停用词库。它包含 179 个单词。因为在生命科学和生物医学研究语料库中有更多的词,如“证明”、“记录”、“研究者”等。,没有区分单词,我将额外的单词(我在当前语料库中找到的)添加到停用词表中,使其长度为 520 个单词。此外,在这一步,我把所有的字母都小写了,这是为了避免算法把“read”和“Read”当成两个不同的单词。
**def** **remove_stopwords**(doc):
retracted_corpus**=**[]
**for** text **in** doc:
retracted_abstract**=**[]
**for** word **in** text:
word**=**word**.**lower()
**if** word **not** **in** nltk_stopwords:
retracted_abstract**.**append(word)
retracted_corpus**.**append(retracted_abstract)
**return** retracted_corpus
abstract_no_stop **=** remove_stopwords(abstract_processed)
三。制作二元模型
生命科学文献经常包含诸如“细胞周期”和“蛋白磷酸酶”的二元模型。当单独考虑两个单词时,这些双字表达的意思并不明显。因此,我决定使用 python 库 Gensim 来收集二元模型,这是另一个用于自然语言处理的伟大的 python 库。该步骤提供二元模型和单元模型,其中二元模型是根据语料库中出现频率的特定条件来选择的。
*#using gensim to construct bigrams*
**from** gensim.models.phrases **import** Phrases, Phraser
bi_phrases**=**Phrases(abstract_processed, min_count**=**5, threshold**=**10)
bigram **=** Phraser(bi_phrases)
*#provides unigrams and bigrams*
**def** **dimers**(doc):
updated_abstract**=**[]
**for** text **in** doc:
di **=** bigram[text]
updated_abstract**.**append(di)
**return** updated_abstract
abstract_bigram **=** dimers(abstract_no_stop)
在这之后,我删除了所有只有数字或者少于 2 个字符的内容。
**def** **abstract_bigram_clean**(doc):
retracted_corpus**=**[]
**for** text **in** doc:
retracted_abstract**=**[]
**for** word **in** text:
**if** **not** word**.**isdigit() **and** len(word)**>**1:
retracted_abstract**.**append(word)
retracted_corpus**.**append(retracted_abstract)
**return** retracted_corpus
abstract_clean **=** abstract_bigram_clean(abstract_bigram)
从这些处理步骤中,我获得了列表的列表,每个列表包含来自单个摘要的单词。为了说明语料库的复杂性,在语料库中有 35,155 个独特的单词,语料库本身包含 6,000 多个摘要。
构建 LDA 模型
在构建模型之前,我们需要将我们的语料库(所有文档)以矩阵形式呈现。为此,我准备了一本字典,其中每个独特的单词都被分配了一个索引,然后用它来制作一个文档术语矩阵,也称为单词袋(BoW)。我使用 Gensim 来执行所有这些任务。此外,有 11,998 个单词只出现一次。我删除了它们,因为它们不表示模型将检测到的任何模式。此外,在超过 20%的文档中出现的任何单词都被删除,因为它们似乎不局限于少数主题。
*# create a dictionary*
**from** gensim.corpora **import** Dictionary
dictionary **=** Dictionary(abstract_clean)
dictionary**.**filter_extremes(no_below**=**2, no_above**=**0.2)
*# convert the dictionary into the bag-of-words (BoW)/document term matrix*
corpus **=** [dictionary**.**doc2bow(text) **for** text **in** abstract_clean]
为了构建 LDA 模型,我们需要提供语料库中我们期望的主题数量。这可能很棘手,需要多次反复试验,因为我们不知道有多少主题。估计这个数字的一种方法是通过计算一致性度量,这是一种对主题模型计算的主题质量进行评级的分数,从而区分好的主题模型和坏的主题模型。
相干性度量按以下四个步骤计算:
- 分割——其中单词集 t 可以被分割成单词子集 S
- 概率计算——其中基于参考语料库计算单词概率 P
- 确认措施—确认措施使用两组 S 和 P 来计算成对 S 的协议𝜙
- 汇总—最后,所有确认汇总成一个一致性值 c 。
为了找到语料库中主题的最佳数量,可以用不同数量的主题建立多个 LDA 模型。从这些模型中,人们可以选择具有最大分数的主题值,并结束一致性值的快速增长。进一步增加主题的数量可能会导致许多关键字出现在不同的主题中。Gensim 库提供了一致性度量的实现。
*# instantiating an lda model*
LDA **=** gensim**.**models**.**ldamodel**.**LdaModel
*#computing coherence for different LDA models containing different number of topics*
**def** **calculate_coherence**(dictionary, corpus, texts, start, stop, step):
coherence_scores**=**[]
**for** num_topics **in** range(start,stop,step):
model**=**LDA(corpus**=**corpus, id2word**=**dictionary, num_topics**=**num_topics)
coherence_lda**=**CoherenceModel(model**=**model, texts**=**texts, dictionary**=**dictionary, coherence**=**'c_v')
coherence**=**coherence_lda**.**get_coherence()
coherence_scores**.**append(coherence)
**return** coherence_scores
coherence_scores **=** calculate_coherence(dictionary**=**dictionary, corpus**=**corpus, texts**=**abstract_clean, start**=**2, stop**=**40, step**=**3)
在相干值图中,我们可以观察到高度几乎相同的多个峰。第一个高峰出现在 14 点。
我决定用 14 个主题建立我的 LDA 模型。
lda_model_abstract **=** LDA(corpus**=**corpus,id2word**=**dictionary, num_topics**=**14, random_state**=**10,chunksize**=**6485,passes**=**100)
形象化
这是阅读和理解从 LDA 和 pyLDAvis 那里获得的主题的关键一步。pyLDAvis 是用于主题的交互式可视化的 python 包。它源自 LDAvis,LDAvis 是一个基于 web 的可视化工具,用于使用 LDA 估计的主题。
pyLDAvis 提供了两个可视化面板:左边的面板以二维圆圈的形式显示主题。通过计算主题间的距离来确定圆圈的中心,然后使用多维标度将它们投影到二维上。因此,密切相关的主题更接近。此外,圆圈区域代表主题的总体流行程度。因此,圆圈越大,语料库中的主题越普遍。右侧面板显示了左侧面板中所选主题的关键术语的条形图。重叠的条形用红色表示各种术语的特定主题频率,用灰色表示语料库范围内的频率。因此,右边的面板帮助我们找到主题的含义。两个面板的链接方式是,在左侧面板中选择一个主题会在右侧面板中显示其重要术语。此外,选择右侧面板上的术语时,会显示其在所有主题中的条件分布。pyLDAvis 中一件有趣的事情是它在一个叫做相关性的主题中对术语进行排序的方法。相关性是一个词的概率及其提升的对数的加权平均值。提升被定义为术语在主题中的概率与其在语料库中的边际概率的比率。带有权重参数 λ 的术语 w 与主题 k 的相关性可以数学定义为:
其中𝜙𝑘𝑤是𝑤∈1 项的概率…𝑉代表话题𝑘∈1…𝐾,其中𝑉是语料库的词汇中的术语数量;𝑝𝑤是语料库中术语𝑤的边际概率。𝜆介于 0 和 1 之间。它决定了相对于与𝑤.相关联的提升,给予主题𝑘中的术语𝑤的概率的权重当𝜆=1 出现时,术语按照其主题特定概率的降序排列。当𝜆=0 时,术语根据它们的寿命排列在一个主题中。pyLDAvis 提供了一个用户界面来调整𝜆.对于解释主题,我保留了𝜆=0.6,这也是从用户研究中获得的最优值。
您可以在下面查看当前分析的可视化效果。请查看我的博客来看看和玩互动可视化。
获得了以下主题(按其流行程度降序排列):
结论:
首先,使用 LDA 的主题建模显示了主题 1-9 和 12 的主题特定术语的良好解析/分离,除了主题 5,我发现主题解释相当容易。但是对于其他主题的解释是困难的,因为许多不相关的术语出现在一个主题中,这表明主题模型在语料库中拾取了噪声或特殊的相关性。选择更多的主题并没有给主题解释带来任何改进。重要的是,由于语料库不大(只有大约 6000 篇文章),只包含摘要(短文本)和 23,157 个词汇,这可能是为什么在某些情况下主题模型会产生噪音的原因。
第二,主题 1 至 7 显示了相似的主题流行度,范围从 10.2%到 7.9%的令牌。因此,表明这些主题中的大部分在收回文献的语料库中是同等重要或普遍的。
总之,尽管数据集很小,但 LDA 可以在收回的文献中找到 14 个主题,主要包括医学、细胞周期和增殖、癌症、免疫学、氧化应激、遗传学、中枢神经系统和认知。可以说 LDA 是一个非常强大的工具,它提供了一种简单快速的方法来探索语料库中的模式或主题。
这个分析的源代码可以在我的 Github 存储库中找到。这篇文章最初发表在我的博客。请随意参观。
- 布雷博士、Ng 博士和乔丹博士,2003 年。潜在狄利克雷分配。机器学习研究杂志,第 3 期(一月),第 993–1022 页。
- 罗德,m .,两者,a .和欣内堡,a .,2015 年 2 月。探索话题连贯性测量的空间。《第八届 ACM 网络搜索和数据挖掘国际会议论文集》(第 399-408 页)。ACM。
- 西沃特和雪莉,2014 年。LDAvis:一种可视化和解释主题的方法。交互式语言学习、可视化和界面研讨会论文集(第 63-70 页)。
使用亚马逊转录和理解分析历史演讲
使用 Python 和 AWS 服务的快速简单的 NLP 教程
FIgure 1. From left to right: Winston Churchill, Ronald Reagan, John F. Kennedy, Martin Luther King and General Douglas MacArthur.
1.介绍
半个多世纪前,试图让计算机理解我们的语言是人工智能(AI)研究人员面临的首批挑战之一。最近几年,它在一个被广泛称为自然语言处理(NLP)的领域里大受欢迎。翻译、语音识别、boots 和许多其他工具和应用程序是我们生活的一部分,并且以某种方式利用了与 NLP 相关的某种算法或模型。如果你正在做一个软件项目,你可能需要使用工具来处理 NLP。学习基本理论和如何使用传统库需要时间,所以我们在这里介绍一种使用 AWS 提供的服务分析音频文件的简单方法。
目标:
本文的目标是使用 Python 和 boto3 展示两个 AWS NLP 工具,Amazon transcriptor 和 Amazon understand。我们将使用 Youtube-dl 从 Youtube 下载一些历史演讲,将其转录为文本并进行情感分析。我们还将音频转录与原始转录进行比较,以评估亚马逊转录所用模型的相似性和一致性。
2.选择演讲
我们将使用从 Youtube 上下载的五篇历史演讲来说明上述工具的潜力。你可以在这篇由 Brett & Kate McKay 发表的关于男子气概艺术的文章中找到历史和演讲的原始转录。选定的演讲如下:
A) 温斯顿·丘吉尔《我们将在沙滩上战斗》 :
1940 年 7 月 4 日,温斯顿·丘吉尔去下议院发表了历史上最勇敢也是最重要的演讲之一。德国军队迅速征服了欧洲,法国已经落入希特勒的控制之下,英国军队不得不从敦刻尔克战役中撤退。通过这次演讲,丘吉尔号召英国人民放弃一切投降的机会,抗击纳粹的威胁,成为第二次世界大战历史的转折点。
Figure 2. Winston Churchill ““We Shall Fight on the Beaches”
B) 罗纳德·里根,《在勃兰登堡门的演讲》 :
1987 年 6 月 12 日,美国前总统罗纳德·里根在勃兰登堡门前与苏联领导人米哈伊尔·戈尔巴乔夫并肩呼吁结束冷战,向世界展示了他的领导力和自由。
Figure 3. Ronald Reagan, “Remarks at the Brandenburg Gate”
C) 马丁·路德·金《我有一个梦想》 :
马丁·路德·金部长是美国五六十年代民权运动的主要领导人。在 1963 年的华盛顿游行中,他发表了著名的“我有一个梦想”的演讲,呼吁白人和黑人之间的和平与尊重。
Figure 4. Martin Luther King Jr., “I Have a Dream”.
D) 道格拉斯·麦克阿瑟将军,“职责、荣誉、国家” :
历史上很少有美国人能在军事生涯成就方面接近道格拉斯·麦克阿瑟将军。他参加过三次战争,体现了军事领袖的责任和荣誉。他在西点军校的最后演讲是一首爱国主义颂歌,是对为自由而牺牲的士兵的敬意。
Figure 5. General Douglas MacArthur, “Duty, Honor, Country”.
E) 约翰·肯尼迪《登月决定》 :
美国前总统约翰·肯尼迪是现代史上最伟大的演说家之一,1961 年 5 月 25 日在休斯顿的一次活动中,他向全国和全世界传达了美国和人类登月的目标。在我们的历史上,很少有项目像太空竞赛和登月这样对科学和现代社会产生如此大的影响。
Figure 6. John F. Kennedy, “The Decision to Go to the Moon”.
3.分析的要求和工具
要遵循本教程,您需要以下内容:
a)安装了以下库的 python 3:boto 3、 pandas 、 matplotlib 、 seaborn 、 spacy 和 wmd 。
AWS 上的活跃账户;
c)安装并配置好 AWS 命令行界面()AWS CLI);
d)Youtube-DL安装。
重要提示
为了增加这篇文章的可读性和理解性,我决定只展示分析中最重要的代码块,但是你可以在我的GitHubrepository上的 Jupyter 笔记本上找到所有细节,包括完成这些情节的代码。
Youtube-DL
为了从 Youtube 下载音频文件,我们将使用一个名为Youtube-DL的命令行工具。安装之后,你可以在终端上输入下面描述的命令,并输入任何 Youtube 视频的 URL 来下载它。Youtube-DL 是用 Python 开发的,GitHub 上的社区正在积极开发。
**# To download the video file to your local folder **youtube-dl <youtube_video_url>**# To download the audio file in mp3
**youtube-dl -x --audio-format "mp3" <youtube_video_url>`****
boto3 和 AWS 服务
Boto3 是 AWS 为用户访问其服务而开发的 Python SDK。它调用 AWS API,有两种类型的服务访问:客户端和资源。客户端是低级服务访问,响应是 JSON 格式(Python 字典)。资源是以面向对象的方式构造的高级服务访问。基本上,您可以使用两种类型的服务访问中的任何一种,而与您需要在 AWS 上执行的任务无关,但是一般来说,可以使用较少的代码行来使用 Resource。有关 boto3 的更多信息,请查看 Ralu Bolovan 的精彩文章。我们将在 Jupyter 笔记本上使用 Python 进行所有的分析,boto3 对于工作流来说是必不可少的。
亚马逊转录
为了将我们的音频转换成文本,我们将使用亚马逊转录,这是一项 AWS 服务,为位于 S3 桶上的音频文件提供自动语音识别。它支持 9 种不同的语言和一些变体:美国英语、英国英语、澳大利亚英语、法语、加拿大法语、美国西班牙语、es 西班牙语、意大利语、巴西葡萄牙语、德语、韩语、印地语、印度口音英语和现代标准阿拉伯语。Amazon transcribe 接受 4 种格式的文件(mp3、mp4、wav 和 flac ),并能够识别音频中的多个扬声器,为每个扬声器返回相应的转录。如果您在 S3 存储桶上有一个音频文件,您可以简单地使用它的 URL 在 AWS 转录控制台上创建一个转录作业。但是当我们用 Python 进行分析时,我们将使用 boto3 调用 AWS API 来调用转录作业。
亚马逊理解
亚马逊理解是在 AWS ML/AI 套件上找到的服务,它为你提供了各种各样的功能,让你从你的文本中获得洞察力,像情感分析、标记化和实体识别以及文档分类。我们将使用这一工具对我们的文稿进行情感分析,试图捕捉在上述每一篇演讲中发现的全球信息。
空间
Spacy 是一个 Python 的 NLP 库,提供了一组已经为 9 种不同语言训练好的模型。它建立在 Cython 的基础上,可以轻松地与其他机器和深度学习库集成,如 TensorFlow,PyTorch,scikit-learn 和 Gensim,所以它真的很高效,很容易使用。Spacy 被不同的公司和项目广泛使用,并在全球拥有越来越多的用户。
4.执行分析
从 Youtube 下载视频
我们分析的第一步是从 Youtube 下载引言中提到的五个演讲的音频文件。为了组织我们的分析并使其可重复,我们将创建一个 Pandas 数据框架来存储分析过程中生成的数据。
首先,我们创建了一个字典,将每个发言者的名字作为关键字,将各自的 Youtube URLs video 作为值 (1) 。接下来,我们遍历这些值并执行 youtube-dl 命令,使用 os.system 将每个文件下载到我们的本地文件夹 (2) 。在步骤 (3) 中,我们从字典中创建 Dataframe,并用每个下载文件的名称创建一个新列 (4) 。
亚马逊转录音频转录
现在我们已经有了用于分析的音频文件,我们只需要把它上传到一个 S3 桶中,然后转录成文本。在步骤 (5) 中,我们使用 boto3 创建了一个新的 S3 桶,并将音频文件上传到其中 (6) 。为了启动自动语音识别,我们需要位于新 S3 存储桶上的每个文件的路径。因此,通过使用 S3 路径约定,我们为每个文件定义了路径,并将其保存到我们的数据帧 (7) 。在步骤 (8) 中,我们创建了一个名为 start_transcription 的函数来使用 boto3 调用 AWS API,并为每个语音迭代调用它 (9) 。我们还在函数 start_transcription 上定义了将结果作为 JSON 文件输出到我们的 S3 桶上。
使用 spaCy 将音频转录与原文进行比较
当亚马逊转录工作完成后,你可以通过读取保存在 S3 桶 (10) 上的 JSON 文件来访问结果。为了评估 Amazon Transcribe 生成的转录的质量,我们将使用存储在 JSON 文件 (11) 中的原始文本。最初的文字记录是从男子气概的艺术文章上提供的链接复制的,新的行字符被删除。原始文本的一些部分被删除,以与音频内容完全匹配,因为一些部分不是完整的语音。在进行任何文本比较之前,我们将删除停用词、标点符号、代词,并对标记进行词条化 (12) 。为了建立文本之间的相似性,我们将使用空间方法进行语义相似性 (13) 。这不是文本的字面比较,因为它是基于 Word2vec 的,这意味着我们在比较每个单词在整个句子/文本中的百分比。
单词向量相似性的结果绘制在图 7 中。我们可以看到,根据这一指标,我们可以说亚马逊转录在将音频转录为文本方面做得很好,因为所有转录与原始转录的相似度超过 99%。
Figure 7. Word Vectors similarity for the speeches.
由于词向量的相似性是基于文本上每个词的表示,所以它会给我们一种两个文本相似的错觉。为了更好地衡量文本差异,我们将使用单词移动距离来比较原始转录和使用 Amazon Transcribe 生成的转录。为了估计这个距离,我们需要库 wmd ,它可以与空间 (14) 集成。有关评估文本相似性的更多信息,请看看阿德里安·锡格河的伟大的文章。
Figure 8. Word Movers Distance for each analyzed speech.
正如我们在图 8 中看到的,有一些转录显示原始和音频转录之间的距离更大,丘吉尔和麦克阿瑟的演讲是最明显的。
为了将原始抄本的结构与 Amazon Transcribe 生成的结构进行比较,我们将使用名为 displacy (15) 的 spaCy 可视化工具进行实体识别。
Displacy 提供了单词及其各自类别的可视化标识,使得比较文本的结构更加容易(图 9)。
Figure 9. SpaCy entity recognition visualizer. On the left Kennedy’s original transcription, and on the right the one generated using Amazon Transcribe.
通过查看 displacy 创建的可视化效果,我们发现了一些不一致之处,尤其是在丘吉尔和麦克阿瑟演讲的音频转录上。似乎音频的质量和演讲者的措辞对转录的质量有影响。当我们听里根和肯尼迪的演讲时,我们可以注意到音频的质量更高,文字更清晰,因此原始和自动转录之间的 WMD 更小,这意味着亚马逊转录模型可以显示更好的性能。
使用亚马逊理解进行情感分析
在我们分析的最后一部分,我们将使用 Amazon understand 对演讲进行情感分析。如前所述,AWS 提供了一个预先训练的模型,您可以使用它来返回 4 种不同情绪的百分比:积极、消极、混合或中性。为了执行情感分析,我们只需要提供字符串形式的文本和语言。Amazon understand 强加的一个限制是可以分析到 5000 字节的文本大小(翻译成包含 5000 个字符的字符串)。由于我们要处理大于这个限制的文本副本,我们创建了 start _ intensive _ job 函数,该函数将输入文本分割成更小的块,并使用 boto3 为每个独立的部分调用情感分析。然后将结果汇总并作为字典返回 (16) 。因此,我们在每个扬声器的音频转录上使用了这个功能,并保存在我们的数据帧上以供进一步分析 (17)。
Figure 10. Barplot for Sentiment Analysis for each historical speech.
Figure 11. Radarplot for Sentiment Analysis for each historical speech.
图 10(柱状图)和 11(雷达图)显示了对每个所选语音的情感分析结果。似乎中性句子在所有演讲中是最普遍的,其次是肯定、混合和否定。丘吉尔的演讲似乎是负面百分比最高的一个,而肯尼迪的演讲是最正面的。
5.结论
AWS 提供了一组 ML/AI 工具,使用 boto3 进行 API 调用可以轻松访问和集成这些工具。
当音频质量良好时,亚马逊转录似乎是一致的,如里根和肯尼迪的演讲,但当音频不清晰时,表现往往不好,如丘吉尔的演讲。
Amazon understand 提供了一种从文本中提取情感的简单方法,如果能看到它与其他 NLP 工具和其他模型相比的结果,那就太好了。
非常感谢你阅读我的文章!
更多资源
在这篇文章中,我们将了解一个非常有趣的研究领域,叫做自然语言处理…
medium.com](https://medium.com/datadriveninvestor/the-brief-history-of-nlp-c90f331b6ad7) [## 历史上最伟大的 35 次演讲|男子气概的艺术
这些著名的演讲在黑暗时期振奋人心,在绝望中给人希望,精炼人的性格,激励勇敢的人…
www.artofmanliness.com](https://www.artofmanliness.com/articles/the-35-greatest-speeches-in-history/) [## Python、Boto3 和 AWS S3:揭秘——真正的 Python
亚马逊网络服务(AWS)已经成为云计算的领导者。其核心组件之一是 S3,即对象存储…
realpython.com](https://realpython.com/python-boto3-aws-s3/) [## Python 中的自然语言处理简介
自然语言处理(NLP)是数据科学最有趣的子领域之一,数据科学家是…
towardsdatascience.com](/a-short-introduction-to-nlp-in-python-with-spacy-d0aa819af3ad) [## 单词嵌入之间的单词距离
单词移动距离(WMD)被提出用于测量两个文档(或句子)之间的距离。它利用了 Word…
towardsdatascience.com](/word-distance-between-word-embeddings-cc3e9cf1d632) [## 文本相似度:估计两个文本之间的相似程度
读者注意:Python 代码在最后是共享的
medium.com](https://medium.com/@adriensieg/text-similarities-da019229c894)****
分析贾斯廷·特鲁多的演讲
Photo by sebastiaan stam on Unsplash
基本原理
加拿大正在进入 2019 年选举季,有迹象表明这将是一个有争议的事件。
一方面,总理特鲁多的自由派在过去 4 年里推动了几项改革,从大麻合法化到买断管道。另一方面,在过去的一年中,反对派驱逐自由党的能量显著增加。保守派和 NDP 选择了新的领导人,绿党的支持率也在上升。
然而,当加拿大人反复思考选举谁担任国家最高职位时,只有几种方法可以分析候选人是否适合担任总理:
- 社交媒体:候选人的账户有多活跃?它们诱人吗?
- 辩论:候选人与其他政党平台的互动如何?他们对手的政治策略有哪些重大漏洞?
- 第三方分析:候选人提出的哪些政策客观上是最好的?
这些分析候选人的方法对于维护加拿大的民主至关重要;他们为个人选择符合他们理想的最佳候选人提供了一种方法。
在很大程度上,这些分析渠道运行良好,并且非常容易使用。不幸的是,政客们的一个方面,尤其是在职者,往往被这些更受欢迎的分析平台所忽略。
演讲。首相的官方讲话是了解政府政策和首相总体情绪的绝佳窗口。这些演讲可以用来全面理解首相的动机和首相自上次选举以来提出的政策。
作为一个刚刚年满 18 岁的人,我终于有幸在联邦选举中投票。由于没有主要的工具来分析贾斯廷·特鲁多总理的演讲,我被激励去创建自己的工具。
方法
网页抓取
总理办公室发布了总理在 https://pm.gc.ca/en/news/speeches演讲的所有文字记录。我必须克服的第一个挑战是将所有的演讲下载成一种格式,以便用于进一步的分析。
输入网页抓取。Web 抓取脚本以编程方式解析来自特定网站的文本,并将其呈现为可通过附加代码进一步操作的格式。对我来说,这是收集特鲁多总理所有演讲的最佳方式。
最初,我决定使用 Selenium,它允许用户控制一个可以与 Javascript 交互的浏览器驱动程序。在下面的代码示例中,我指示 Chrome 驱动程序遍历列表中的所有文章,并通过 CSS 选择器和 XPATHS 的组合来提取日期、标题和语音副本。
**for** article **in** article_list:
article.click()
time.sleep(3)
# Getting title
title = article.find_element_by_xpath("//h1[@class = 'field-content']")
print(title.text)
# Getting date
date = article.find_element_by_class_name("date-display-single")
print(date.text)
# Getting place
place = article.find_element_by_xpath("//div[@class = 'inline-date']")
print(place.text)
# Getting speech
speech_div = browser.find_elements_by_xpath("//span[@lang = 'EN-CA']")
**for** p **in** speech_div:
print(p.text)
不幸的是,我遇到了硒的问题。在演讲网站上,每份文稿都隐藏在一个可扩展的 HTML div
中。上面的 Selenium 脚本无法处理这个问题。
相反,我决定采用 AJAX 抓取方法。首先,我注意到每个演讲都是使用 AJAX 下载的,并带有唯一的 ID。其次,我发现这个 ID 可以在可扩展的 div 上的 teaser 中找到。使用来自 teaser 的 ID,我使用 requests 库以编程方式下载了所有演讲,使用 BeautifulSoup 解析了文本中的重要信息,并将所有信息保存在 MongoDB 数据库中。以下是 AJAX 抓取脚本的一部分,它使用 AJAX 请求来下载演讲:
**def fetch_speech_details**(speech_id: str) -> str:
# AJAX requests link. Replaced ID with speech_id collected from teaser
url = 'https://pm.gc.ca/eng/views/ajax?view_name=news_article&view_display_id=block&view_args={id}'
url = url.format(id = speech_id)
# Get the speech
res = requests.get(url, headers=headers)
res.raise_for_status()
# Convert to proper form using BeautifulSoup
data = res.json()
html = data[1]['data']
soup = BeautifulSoup(html, 'html.parser')
# Select the speech content
body = soup.select_one('.views-field-body')
speech_text = body.get_text()
**return** str(speech_text)
清洁
我采取了几个步骤来清理这些支离破碎的演讲稿:
- 记号化:记号化是指将文本分成称为记号的片段的实践。在这个特别的项目中,我将演讲标记成单个的单词,但是我也可以将演讲标记成句子。此外,我将每个标记转换成小写以确保一致性。这是使用 spacy 库完成的。
An example of tokenization
- ngram:ngram 是指文本样本中的一系列 n 项。在这个项目中,我尝试将上述标记转换为单字(一个单词)、双字(两个单词)和三字(三个单词)。ngram 函数在 NLTK 库下可用。
- 词汇化:这个过程移除单词的屈折词尾,以到达词根或词汇。比如‘学习过’和‘正在学习’都有‘学习’的引理。通过单词的词条化,我们能够到达基础并减少句子之间的差异。同样重要的是要注意,词汇化并没有粗暴地砍掉动词的词尾(也称为词干);相反,它使用语法规则来获得基本单词。这个步骤使用了 NLTK 库中的 WordNet lemmatizer 函数。
Examples of lemmatization. Note how grammar rules are used to arrive at the stem of the word rather than simply cutting off the end of the word (‘ed’, ‘es’, ‘ing’).
- 停用词移除:在任何语言中,都有一些极其常见的词,它们不会给句子带来任何额外的意义。例如,句子“Billy 在上学前吃煎饼”可以转换为非停用词句子“Billy 在上学前吃煎饼”。删除停用词有助于简化后面模型的计算,如词袋,同时仍保留句子的含义。停用字词的移除是使用 NLTK 库执行的。
情绪分析
情感分析是指破译一个给定句子是肯定的、否定的还是中性的过程。如果有足够的标签数据可用,朴素贝叶斯模型可以用来预测一个句子是否有总体积极或消极的情绪;然而,缺乏情感的标记语音语料库阻止了这种方法。
相反,我使用了 Vader perspection 库,它优雅地提供了一个用于自动情感分析评分的 API。复合分数与积极、中性和消极分数一起提供;复合分数有助于确定文章的整体情绪。
以下是用于分析演讲中情绪的代码示例:
# Getting sentiment score of each speech
**def sentiment_score**(speech):
# Initializing analyzer object
analyzer = SentimentIntensityAnalyzer()
# Outputting and returning speech sentiment score
score = analyzer.polarity_scores(speech)
print("Speech: ", speech)
print("Score: ", score)
**return** score
话题分析
主题分析采取了几个步骤,因为我必须训练自己的模型,而不是利用 API:
- 创建单词袋模型:机器学习算法有一个共同的缺点——模型只能对向量或数列起作用。当然,这不是文本的自然表示,因此将文本转换为特征向量是自然语言处理中不可或缺的任务。将文本转换为特征向量的一种方式是通过单词袋模型。这个机制需要几个步骤。首先,必须创建一个语料库或词典;在我的项目中,我使用了特鲁多总理的演讲令牌的全部集合作为字典。第二,模型必须记录字典中所有不同类型的词汇,并给每个单词一个特定的 ID。最后,每篇演讲都要根据词汇表进行评分。为这个项目的每个演讲打分是一个相对简单的任务:我只是简单地计算每个单词-ID 组合出现的次数。这里有一个简单的图表来解释单词袋模型的创建。
An example of a bag-of-words representation
- 潜在狄利克雷分配(LDA)模型的创建:LDA 模型是目前存在的最有用的主题模型之一。本质上,LDA 基于文本序列在每个主题中的特定出现的概率来确定文档属于特定主题的概率。例如,如果单词“环保主义”和“管道”在主题 1 中出现的概率很高,并且如果文档包含“环保主义”和“管道”的多次出现,则该文档成为主题 1 文档的概率很高。关于 LDA 模型工作原理的更漂亮、更深入的解释,请访问这篇文章。在我的项目中,这个模型是基于所有演讲的单词袋模型建立的。
Each topic has a few words that contribute to a high probability of having that topic. Finding those words in a document increases the probability of the document having that topic (source)
- 预测:有了最终构建的模型,我们可以通过单词袋模型将每个语音转换为特征向量,并使用 LDA 预测主题。与 k-means 不同,LDA 给出的是文档属于某个主题的概率,所以肯定比 k-means 更模糊。这意味着预测输出是主题及其各自概率的列表。
最后,所有的观点和话题都存储在 MongoDB 数据库中。
结果和分析
由于这个项目是我的第一个 NLP 项目,我尝试了许多分析技术。其中一个是单词云:它代表了在演讲中发现的所有单词,每个单词的大小与其频率相对应。这里有几个单词云的例子:
Wordcloud for speech on National Inquiry into Missing and Murdered Indigenous Women and Girls
Wordcloud for remarks on New Zealand mosque shooting
Wordcloud for all speeches
虽然它们看起来很吸引人,但是这些文字云是一个很好的分析来源。例如,最终的 wordcloud 给了我们一些启示:
- 强调自己是加拿大人:当然,作为加拿大总理,提到“加拿大”或“加拿大人”的次数并不奇怪。
- 土著人:鉴于加拿大与土著人交往的历史充满了悲剧和特鲁多总理的和解政策,与土著人有关的词语的出现频率表明,特鲁多一直在集中努力试图纠正过去的错误。
- 《时代》杂志:有趣的是,特鲁多的讲话表明,他的政策更关注“今天”和过去(“几年前”),而不是未来,特别是考虑到特鲁多竞选时对未来持乐观态度。他的官方演讲和竞选承诺可能不会像预期的那样一致!
我还研究了平均每场演讲的代币数量。这是所有演讲的标记数量的直方图(x 轴是标记数量,y 轴是演讲数量)
这种分布大致正常,平均约为 1750 个单词。平均语速为 150 字/分钟,也就是说平均发言时间大约为 12 分钟。对于大多数官方演讲来说,这个长度是合理的,但竞选演讲肯定会更短,大约 5-7 分钟。
我还想检查各种情感分数的分布。以下是我使用情感分析脚本编译的直方图集合:
在很大程度上,这些演讲似乎有一种中立评分的趋势。然而,正如在复合分数分布中所看到的那样,还有几个正分数超过负分数的例子。此外,似乎有更多的积极意义大于消极意义的演讲。
总的来说,特鲁多的演讲风格反映了他在政府中乐观的竞选承诺。
我想分析的情绪的另一个方面是情绪随着时间的变化。我创建了一个小线图来研究任何趋势:
这里有几点需要注意:
- 在很大程度上,特鲁多总理的讲话是积极的,这可以从绿色积极情绪线相对于红色消极情绪线的优势看出。
- 从 3 月到 4 月,特鲁多演讲中的负面性明显增加。此时总理办公室卷入SNC-拉瓦林事件,可能间接影响了特鲁多的讲话风格
- 随着选举的临近,乐观情绪增加了。这可能表明,随着选举的临近,特鲁多正在回归他之前对加拿大积极前景的战略。
最后主要分析特鲁多演讲中的主题。在一个 5 主题的 LDA 结构中,我的脚本输出了以下主题:
主题 0-2 似乎更倾向于一个土著主题,主题 3 与加拿大身份更相关,主题 4 与环境保护主义相关。
然后,脚本系统地检查每篇演讲,并记下每篇演讲出现这些话题的概率。例如,关于失踪和被谋杀的土著妇女和女孩的全国调查的演讲有 0.997 的概率有主题 0,这从直觉上讲是有道理的。
总的来说,结果非常成功。
结论
这是我参与过的最复杂的项目之一,通过它我学到了很多东西。在这个项目之前,自然语言处理和 LDA 是我一无所知的术语;然而,分析总理的演讲帮助我将我的知识扩展到机器学习的这个领域。
此外,我通过 MongoDB 学习了大量新技术和技能,从 NLTK 这样的包到非关系数据库管理。老实说,如果不是这样一个深入的项目,这些技术我永远也学不会。
正是通过像语音分析这样高度复杂的项目,我受到启发,学习新的技术和技能。此外,这个项目是巩固我已经知道的技能的一个极好的方式。在探索新技能时,我强烈推荐基于项目的学习。
只有一个月的时间来完成这个项目,优先顺序迫使我放弃了以下组件,这些组件可以将这个项目向前推进一步:
- 创建一个脚本,用一个命令运行所有功能
- 收集更多的演讲:出于某种原因,我的脚本很难收集到超过 10 个演讲。这可能是因为“显示更多”按钮会拉更多的发言。
- 用二元模型和三元模型做更多的实验:我真的对二元模型和三元模型如何影响我的 LDA 模型的准确性很感兴趣,所以我会继续用它做实验。
总的来说,这是一个非常有趣和具有挑战性的项目,我将继续尝试。该项目的源代码可以在这里找到如果你想试验我的分析。加拿大的任何人,请在十月投票!