TowardsDataScience 博客中文翻译 2020(六百六十九)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

数字会说谎

原文:https://towardsdatascience.com/numbers-can-lie-3474e0efa1e1?source=collection_archive---------35-----------------------

分析的常见陷阱:它们如何误导决策者以及如何避免它们。

由于技术的进步,分析和统计几乎已经成为业务各个方面不可或缺的一部分。这对数据科学家和分析师来说很好,但也会产生一些非常现实的问题。

主要问题是由分析融入业务流程的速度引起的,因为事实上大多数人没有受过多少统计教育,即使受过教育,也往往从学生时代起就没有重温过这些主题。这给组织带来了一个非常现实的问题。

盲目相信决策是基于那些实际上站不住脚的指标和数字,这种现象正在蔓延。

如果你是一名数据科学家或分析师,记住我们的工作不会凭空出现是至关重要的。我们的分析是共享的,并将影响决策的方式,因此在构建报告、仪表板等时记住这一点很重要。以确保它们不会无意中误导最终用户。

简单地说,如果你不能证实你的数字,为什么会有人相信你的分析?或者更糟糕的是,如果你的分析是无意的误导,它会造成严重的伤害。

在这篇文章中,我将探讨一些可能导致决策者被误导的不同因素,以及如何在您的工作中避免这种情况。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 @thisisengineeringUnsplash 上拍摄

模糊平均值

首先要思考的是:术语“平均”是什么意思。

有三种:均值、中值、众数。

当你看到“平均”这个词时,你可能指的是他们中的任何一个。最常见的是,提到的平均值是均值,但并不总是如此,在我的工作中,我选择称之为“均值平均值”,除非客户特别要求。

我将更深入地研究平均值,因为它们可能会非常容易误导,因为不同的数据集可能会以多种方式产生相同的平均值。例如,三个值“1,2,3”可以具有与“2,2,2”相同的含义。

均值可能误导的主要原因是异常数据,相对非常大或非常小的值对均值有很大的影响。

一个真实的例子:一家公司的月平均销售额为 25000 英镑。高管们看到了这一点,并对公司的状况感到满意。
实际上,平均销售额会因为一个每月 50,000 的客户被竞争对手收购而出现偏差。这位客户的即将流失实际上降低了 15,000 英镑的均值,这对公司来说是一个非常危险的现金头寸。在这种情况下,查看分布或另一种类型的平均值可以帮助管理人员预见这些事件并做好准备。

我倾向于“越多越好”的方法,并在我自己不展示结果的任何场景中包含其他描述,这几乎没有出错的余地。永远记住考虑最终用户的需求,而不是你的需求,我可以保证他们没有像你一样花几个小时扫描原始数据,所以不要假设他们了解数据集。

这是具有相同平均值的不同数据集的示例

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第一个数据集

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二数据集

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三个数据集

上述分析显示了三个完全不同的数据集,它们都具有相同的平均值、计数和总和,然而,它们都具有非常不同的分布(我保持了相似的标度以强调这一点)。这种情况在分析中经常发生,并且经常被完全掩盖。

说到分析,描述性统计是必须的。仅仅制作漂亮的度量标准和图表而没有适当的背景会导致弊大于利。如果您计划使用平均值作为报告和仪表板的一部分,那么我建议至少用它们来显示分布,这样平均值背后的上下文是可以理解的,并且请记住将其标记为“均值、众数、中等”。如果您不确定最适合您数据集的平均值,我建议您事先详细研究每个平均值。

失踪的小字

统计数据经常被引用,而没有任何原始数据的参考,以及遗漏某些可能违背创造者假设的数字。

向自己展示调查结果时,要问自己的一个重要问题是“此图中谁的利益是正确的”?这并不是说这些数字不正确。只是没有办法确切知道。
因此,不应该仅仅依赖这些数字。

如果你要展示数据,一定要注明来源、方法和其他相关信息。如果你遗漏了什么,问问自己为什么,如果答案是防御性的,不要遗漏。我们不再需要那么多虚假的事实。

虚假陈述的一个常见例子是调查数据,其中遗漏了关于方法或样本大小的信息。这通常包括总下载量等数据,这是营销人员喜欢的,但却忽略了活跃用户等其他指标。

这在以下两个陈述中清楚地显示出来,两个陈述都是准确的。

中国的 GDP 比卢森堡高。
卢森堡的 GDP 比中国高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GDP /人均 GDP |来源世界银行(2018 年)

这两种说法都是正确的,因为中国的 GDP 总量要大得多。但是,人均来说,卢森堡要高很多。在这种情况下,你可以说两个经济体的表现都比另一个好。

大假设,小暗示。

统计数字经常被用来证明一个观点或巩固一种观点。尽管事实上他们经常两者都不成功。

想出一个令人心酸的陈述并以准复杂的统计数据为依据是很容易的,但当你深入挖掘表面之下时,它们就会被推翻。

其中一种说法是“首席执行官的收入比以往任何时候都高”。这种说法得到了一些数据的支持,比如“首席执行官现在的平均收入为 25 万英镑。与 1950 年相比,他们只赚了 5 万英镑。这本身似乎是一个强有力的证明,但实际上,1950 年的 5 万英镑相当于今天的 48 万英镑。因此,尽管初看起来,这种说法是荒谬的。我知道这似乎是显而易见的,但还有很多不那么明显的。

我个人看到的另一个常见例子是,一家大型人力资源分析软件公司在其网站上声明:“我们的客户实现了高达 80%的投资回报率。”

这种说法有两个主要问题。

首先,从数学的角度来看,短语“高达”在这个场景中实际上可以表示任何东西,即公司的大多数客户可能获得零投资回报,而一个客户可能获得 80%。因此,这种说法是正确的,但具有误导性。

这种说法的另一个问题是方法中的假设。假设在这个场景中,公司销售的产品是销售软件。他们计算出,与前一年相比,使用第一年的销售额增加导致 80%的投资回报率。他们很方便地忽略了一个事实,即在软件推出之前,销售额每年增长 50%。因此,声称这种增长是由软件引起的是没有根据的,因为这种增长已经在客户的正常操作趋势之内。

避免这种情况的一个简单的方法就是避免一般化,因为这给错误留下了太多的空间。请记住,你试图用你的数据来讲述一个故事,这个故事需要包括细节。

相关性而不是因果关系。

这可能是查看统计数据时最常犯的错误,这样做的后果可能是巨大的。

假设您想要了解工作场所敬业度和员工服务年限之间的关系,因此您进行了一项调查并获得了结果。

你会发现时间长度和参与度之间存在正相关关系。由此你可以得出结论,一个人在组织中工作的时间越长,他们就会越投入。我们怎么能确定这是真的呢?首先,您需要访问服务年限的分布。这是接近正态分布的水平,还是分布有很大的偏差?记住,拿苹果和桔子做比较没有什么价值。

值得庆幸的是,有一个有用的方法可以理解相关性有多重要,那就是 P 值。该计算用于显示如果相关系数为零,则具有相同结果的概率。如果 P 值小于 5%,(0.05),则认为相关性具有统计学意义。

这并不意味着这种相关性是一种因果关系,只是值得进一步研究,以确定这种相关性实际上是否是由于因果关系。

由于对 P 值含义的无知或仅仅依靠相关系数,看似相关的事物通常被认为是因果关系。如果你发现两件事是相关的,并希望进一步了解这种关系,那么贝叶斯统计将是一个有助于更深入地了解数据的工具。

关于相关性,需要考虑一些简单的事情:
通常的相关性分为四类(这些可以是积极的或消极的关系):

**不相关:**不言自明。
**相关,但不一定:**有时候事情在统计上是相关的,但实际上并没有关系,只是偶然发生的。避免这种情况的两种方法是获得更多的数据或进行实验,在受控条件下检验这种关系。
**实际相关:**这些输入有关系,但如果影响条件改变,它们可能会改变或破坏这种关系。记住数据不存在于虚空中,事物是变化的,不要假设 其他条件不变
因果:输入直接支配输出,考虑关系的顺序 eg 是 X 引起 Y 变化,还是相反,还是关系是双向的?这当然取决于你的数据的性质。

相关性是数据科学的一个重要组成部分,但是当你得到你想要的结果时,很容易被冲昏头脑。真正挖掘,直到你完全明白发生了什么,你会惊讶你的发现。

结论

这些问题中的大多数可能看起来很明显,但在快节奏的商业环境中,它们很容易悄悄进入您的分析中而没有人注意到,尤其是您正在使用现成的分析工具,这些工具不允许您检查原始数据或运行自定义查询和公式。

一般来说,为了更好地实践,如果你不理解或不知道漂亮的图表或先进的机器学习模型背后发生了什么,那么当涉及到决策时,你不应该依赖他们的输出,总是提供上下文。

令人欣慰的是,网上有很多阅读统计、数据科学和机器学习的好地方,让每个人都能提高自己的数据素养。

美国人纠结于图表

原文:https://towardsdatascience.com/numeracy-and-graph-literacy-in-the-united-states-ea2a11251739?source=collection_archive---------56-----------------------

新的研究显示对数标度的 y 轴混淆。但是当与“公众”交流数据时,需要有多简单呢?人们能处理多少复杂性?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片来自作者+ VectorStock )

上个月,亚历山德罗·罗马诺、基亚拉·索蒂斯、戈兰·多米尼奥尼和塞巴斯蒂安·圭迪对 2000 人进行了调查,证明“公众不理解用来描绘新冠肺炎的对数图。

他们发现,只有 41%的参与者能够正确回答关于对数标度图的基本问题(线性标度的准确率为 84%)。

但是这个问题比对数秤更难。正如您将在下面看到的,许多“公众”甚至连最基本的图表都难以理解,更不用说复杂的可视化了。

知识的诅咒

评论中有一条引起了我的注意:

“作为一家大报的前信息图表编辑,我一直认为我的优势之一是缺乏数学技能。如果我能理解图表,也许读者也能。是的,我从来没有用过对数图表。”——罗伯特·b

这引发了更多的问题:有多少数据记者像罗伯特·b 一样思考?或者,正如 Romano & friends 建议的那样,大众媒体中的人们是否“习惯性地”假设对数标度轴是广泛可理解的?如果是后者,他们高估了世界的量化能力,那么普通观众会忽略多少其他重要的数据故事?

我从个人经验中知道,这是一个容易犯的错误。如果您一天中的大部分时间都花在 python 笔记本上,或者您的午餐谈话经常转向 arXiv 上的新内容,那么您可能也是如此。

斯坦福/杜克大学的教授丹/奇普·希斯称之为“知识的诅咒”。

“一旦我们知道了一些事情,我们很难想象不知道它是什么样子。我们的知识“诅咒”了我们。我们很难与他人分享我们的知识,因为我们不能轻易地重现听众的心理状态。”—奇普&丹希斯,制成贴

也就是说,如果你有很高的计算能力,通常很难和没有计算能力的人交流。

为了治愈“诅咒定量知识”,并通过更典型、更不了解的观众的眼睛来看待数据世界,我们将关注三项不同的研究,这些研究大规模地测量了计算能力和图形读写能力。

他们的一般发现是有帮助的,但为了使其具体化,我们还将看看这些研究中的 10 个具体问题,我将提供 1)一个典型用户可能解释它们的准确程度,以及 2)我们成年人能够正确可靠地解释它们的百分比。

有了这些基准,希望你能有一个更直观的感觉,一个故事需要简化到什么程度,才能被更广泛的读者所理解。

当用数据讲故事时,如果你想让你的(来之不易的)见解变得平易近人,没有太简单这一说。

tldr/外卖:

  • 美国的基线计算能力不是很好。
  • 图形理解依赖于计算能力和“阅读”的复杂性。
  • 有一些令人惊讶的基本解释让许多人纠结。

算术问题

计算能力不是天生的。

显然,婴儿和啮齿动物天生就能区分简单的数量。如果在两堆饼干中做出选择,婴儿知道要选择较大的那一个( src )。老鼠可以学会按 8 次或 16 次杆来接收零食( src )。

但这大概是我们与生俱来的数字能力的极限。剩下的,包括比率、负数等基本概念都是学的。

PIAAC 研究 38 个国家的“计算能力”。

每隔几年,经济合作与发展组织都会进行一项名为“国际成人能力评估项目”的大型研究。它考察了世界各地成年人的基本技能,其中之一是计算能力。

研究人员与来自 38 个国家的约 24.5 万人坐下来,每人约一小时,并对他们进行测试。他们在 1-500 的范围内计算自己的分数,其中 500 是满分。然后将这些分数分成 5 个等级,其中 1 级最不熟练,5 级最熟练。

3 级似乎是一个重要的门槛。典型的“3 级”人员得分在 276-326 分之间( src ,第 71 页)。他们可以在 67%的情况下回答“3 级”问题。我们稍后将探讨示例问题,但 PIAAC 将 3 级问题描述为:

这一级别的任务要求回答者理解可能不太明确的数学信息,嵌入在不总是熟悉的上下文中,并以更复杂的方式表示。任务需要几个步骤,可能涉及解决问题的策略和相关过程的选择。任务倾向于要求数感和空间感的应用;认识并运用以口头或数字形式表达的数学关系、模式和比例;以及对文本、表格、图表中的数据和统计数据的解读和基本分析。( src ,第 71 页)

根据 PIAAC,我们成年人的计算能力如何?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在接受调查的 38 个国家中,美国在 3 级或 3 级以上的成人比例方面排名第 28 位。(转载自技能很重要:美国成人技能调查的额外结果2017 年美国 PIAAC 结果网络报告的亮点)

美国在接受调查的 38 个国家中排名第 28 位。美国成年人的平均分数为 255 分( src ),这让他们稳稳地处于 2 级范围(226-276 分)( src ,第 71 页)。只有 37%的美国成年人达到 3 级或以上,日本为 63%,芬兰为 58%。

因此,如果 10 个美国成年人中只有 4 个表现在 3 级以上,那么 10 个中就有 6 个会努力“识别和运用以口头或数字形式表达的数学关系、模式和比例;并能对文本、表格和图表中的数据和统计数字进行解释和基本分析

“这些结果是另一个信号,表明许多美国人在最基本的数学技能上挣扎,”NCES 副专员佩吉·卡尔说。

“但我的观众很聪明”

这是一个很好的实践,坦率地说,假设一个聪明的、善意的观众是值得尊敬的,但是仅仅因为某人受过良好的教育,并不意味着他们精通数量。

计算能力和教育之间有很大的关系,但也有例外。例如,即使在高中以上学历的人群中,47%的人在 PIAAC ( src )中的表现仍为 2 级或以下。

2008 年,莎拉·霍利(& friends)发现,即使在至少拥有学士学位的参与者中,也有 33%的人被归类为低算术水平( src )。在 2001 年对“高学历者”的一项研究中,艾萨克·利普库斯(&朋友)发现,16-20%的参与者错误地回答了与风险大小相关的非常基本的问题(例如*“哪一个代表更大的风险:1%、5%还是 10%?”* ) ( src )。

Goutham Rao 在 2008 年的评论表明,即使是医生也在挣扎。一项对家庭医生的调查显示,尽管 95%的参与者肯定了理解生物统计学的重要性,但只有 25%的人表示对该学科有信心。根据他们的测试结果,缺乏信心是有根据的:他们平均只有 41%的正确答案。诚然,生物统计学是一个更高的门槛,但希望这表明,即使是先进的观众也不总是像他们希望的那样先进。

图形理解

算术和交流数据有什么关系?

Mirta Galesic 和 Rocio Garcia-Retamero 表明,低计算能力不仅限制了一个人的数学能力,还与他们的“图形素养”或解释图表的能力密切相关。

根据 Galesic 和 Garcia-Retamero 的说法:*“导致高计算分数的相同的元认知能力也培养良好的图形读写技能。”*反之亦然:在 261 名“低计算能力”的美国成年参与者中,只有 89 人(34%)表现出高图形读写能力。

用户将如何“读取”数据?

Galesic 和 Garcia-Retamero 的另一个聪明见解是:图形理解不仅仅基于读者的能力,它还取决于他们需要如何解释数据。他们提出了三种人们“阅读”图表的方式。用户可以:

  1. “读取数据”——识别图表上的特定值
  2. “在数据之间读取”——识别图表数据中的关系
  3. “阅读数据之外的内容”——从图表数据中做出推论

这些水平中的每一个都越来越难,这反映在他们的结果中。美国参与者可以在 86%的回答中正确“阅读数据”,在 67%的回答中正确“阅读之间”,在 63%的回答中正确“阅读之外”。

请注意,这些结果似乎比 PIAAC 建议的更积极。为了更好地理解数据读者实际能处理什么,让我们来看看这两项研究中的一些潜在问题。

人们能处理多少复杂性?

为了说明这一点,让我们看看一些图形理解问题&来自 PIAAC、国家成人识字调查问题和 Galesic/Garcia-Retamero 的“图形识字”研究的结果。

PIAAC 样题

我们将从第三级开始,即“中等难度”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个“3 级”问题。只有 37%的美国成年人会定期正确回答这个问题。(图片来自 NCES, src )

级别 3:对于时间序列折线图:“在哪个(些)时期出生人数有所下降?”

美国成年人 PIAAC 计算能力的平均分数是 255/500。因此,美国成年人平均有大约 26%的机会正确回答 3 级问题。一个得分在 276-326 分之间的“3 级”的人,在 50-80%的时间里回答正确。由于 37%的美国成年人得分在 3 级以上,我们可以说,只有十分之四的美国成年人能够可靠地回答这样的问题。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个“1 级”问题。92%的美国成年人会定期正确回答这个问题。(图片来自 NCES, src )。

对于刻度盘温度计:

  • 级别 1: “温度计上显示的温度是多少华氏度(F)?”
  • 级别 2: “如果显示的温度降低了 30 摄氏度,那么温度是多少摄氏度?”

这些似乎是 1 级和 2 级问题。一个典型的美国成年人在 89%的情况下会正确回答 1 级问题(92%的美国成年人是 1 级,并且在大多数情况下会正确回答)。他们会在 66%的情况下正确回答第二级问题(70%的美国成年人是第二级,大多数情况下会正确回答)。

(注:NCES 网站将这些问题列为 3 级,但读者指南将类似的问题列为“低难度”或 1/2 级)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个“二级”问题。70%的美国成年人会正确回答这个问题(通过国家教育研究中心)

对于表格和条形图:“哪两个条形是不正确的?”

这是一个“二级”问题。一个典型的美国成年人在 66%的情况下会正确回答这个问题(70%的美国成年人在大多数情况下会正确回答这个问题)。

全国成人识字调查问题

美国的一项早期研究“全国成人识字调查”表明,普通美国成年人只能在大约 50%的时间里“从描述能源和年份的条形图中识别信息”。他们只能在大约 25%的时间里“使用信息表来确定多年的石油出口模式”( src )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示“2 级”问题。(图片来自 NCES, src )

第 2 级:“你是一家小型制造公司的营销经理。这张图表显示了贵公司过去三年的销售额。根据图中所示的季节模式,在图上画一个“x”来预测 1985 年春季的销售额(以千计)

一个普通的美国成年人在 60-80%的时间里回答正确。( src ,第 102 页)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

提示 3 级问题。(图片来自 NCES, src )

第三级:“假设你在一个周六乘坐下午 12:45 的公交车从 U.A.L.R .学生会到第 17 大街。按照时间表,大巴要坐几分钟?”

一个普通的美国成年人在 35-65%的时间里回答正确。

“图形素养:跨文化比较”问题

在《图形素养:跨文化比较》中,Galesic 和 Garcia-Retamero 告诉我们“即使是最简单的图形对许多人来说也可能难以理解”( src )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3 个不同的图表,提示了以下来自 Galesic 和 Garcia-Retamero“图形素养”研究的问题。(转载自 src )

一些示例问题和预期结果:

  • 读出柱状图上的一个点(左图):“化疗后痊愈的患者比例是多少?”——85%的美国成年人回答正确。
  • 确定两个条形图之间的差异(中图):“手术后康复的患者百分比与放射治疗后康复的患者百分比之间的差异是什么?” — 70%的美国成年人回答正确。
  • 比较一条线的两个区间的斜率(中图):“什么时候患支气管炎的人的百分比增加得更高?(1)从 1975 年到 1980 年,(2)从 2000 年到 2005 年,(3)在这两个时间间隔内的增长是相同的,(4)不知道“——62%的美国成年人回答正确。
  • 确定两组图标之间的差异(右图):“100 名 X 病患者中,男性比女性多多少?” — 59%的美国成年人回答正确。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个也许会计算的伐木工人考虑简单的木材分配。

外卖:

在交流数据时,上述问题提供了有用的基准,用于根据可视化或数据故事的复杂性确定您的目标受众规模:

  • 如果它大致像识别和减去两个值一样复杂(例如,“手术后康复的患者百分比和放射治疗后康复的患者百分比之间的差异是什么?”),你在和 10 个人中的 7 个人说话。
  • 如果它和识别线图上的趋势一样复杂(例如,“在哪个(些)时期出生人数下降了?”),你只能和 10 个人中的 4 个人说话

基于这些,您可以相应地调整数据的显示。如果你知道你只是在和一群高级观众说话,你就可以开始了。但是如果你想获得更广泛的受众,想办法简化。

我们能做得更好吗?

记住我们的观众比以往任何时候都重要。新冠肺炎是一场数字概念和条件的龙卷风,人们在与之斗争(例如,大数、指数曲线、政治/情感等)。此外,受病毒影响最严重的社区在算术教育方面也是最缺乏服务的。这两者都提高了传播者的门槛,使他们的见解更容易被人接受。

那么,我们能做些什么来解决“[定量]知识的诅咒?”

  • 不要假设普遍的计算能力。意识到你的观众对复杂性的偏好。
  • 在真人身上测试你的作品。没有什么比用户对表面区域的反馈更简单的了。
  • 当大多数人(至少是我们成年人)需要访问数据时,问问自己:这比在条形图上减去 2 个值复杂还是不复杂?
  • 注释一切。只要有可能,就提供如何解释你的视觉化图像的书面说明,并用关键要点的叙述性描述来补充视觉化图像。
  • 如果你知道像对数标度轴这样的东西不会被广泛理解,无论如何都要去做。许多人认为,接触更难的图形实际上有助于提高图形素养,所以也许团队需要一个?

我是谁?不,不,你是谁?!

我是伊莱。我的数据可视化咨询公司帮助客户使用数据(可视化)创造积极的变化,不仅通过理性地吸引受众,还通过情感和文化吸引受众。变化发生在头脑心里。

如果你对用户测试数据感兴趣,或者如果你是在数据、设计和用户心理学的交叉领域工作的创始人、制造者、讲故事者或商业领袖,我很乐意联系和交换故事。

你可以给我发电子邮件,地址是eli@3iap.co或者关注我的推特

参考

数字锦标赛:融合传统量化方法和现代机器学习

原文:https://towardsdatascience.com/numerai-tournament-blending-traditional-quantitative-approach-modern-machine-learning-67ebbb69e00c?source=collection_archive---------17-----------------------

如何提高金融机器学习的智能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Erol Ahmed 在 Unsplash 上拍摄的照片

介绍

数字锦标赛

Numerai 是一个众包基金,一个对冲基金,它根据不特定数量的人做出的股价预测结果进行操作。Numerai 举办比赛,参与者为预测业绩而竞争。锦标赛参与者将根据 Numerai 提供的加密数据集建立一个预测模型,然后使用它来创建一个提交。参与者将根据他们的预测表现进行排名并获得报酬(有时会被封杀)。Numerai 的支持者包括复兴科技的联合创始人霍华德·摩根(Howard Morgan)、保罗·都铎-琼斯(Paul Tudor-Jones)、联合广场风险投资公司(Union Square Ventures)和其他知名风险投资家以及具有丰富对冲基金经验的人士。数字数据集由专门从事金融机器学习的顾问监督。迄今为止,支付给参与者的奖金总额已超过 3400 万美元,该项目可能进展良好。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由numeri提供

关于作者

作者使用市场中性方法投资日本股票市场。市场中性旨在通过结合买入和卖出(多头和空头),预测宇宙(要投资的一组股票)中股票价格的相对涨跌,获得独立于市场价格运动的绝对回报。在传统的定量方法和统计学的基础上,作者通过机器学习建立了该预测模型。结果一直不错,收益率在 40%左右。

本文的目的

在这篇文章中,我将分享在建立作者模型的过程中获得的见解。我首先解释了传统定量方法的概念,并讨论了如何将其与机器学习相结合,以建立一个现代预测模型。

笔记

Numerai 的数据集是加密的,作者对此一无所知。这篇文章仅仅是作者投资和建模经验的观点。

传统定量方法

预测股票收益的研究由来已久。让我们从解释什么是传统的定量方法及其起源开始。

巴拉风险模型

现在的 quants 的原型很可能就是 Barr Rosenberg 提出的风险模型[1]。关于这一点有很多理论,但是对于华尔街这方面的历史,你绝对应该读一读彼得·伯恩斯坦的书《资本理念》[2]。

在 20 世纪 60 年代,基于 Markowitz 的协方差模型,Rosenberg 设计了一种方法,使用各种因素来解释单个公司的风险。他还发现这些风险因素与股票价格的超额收益(风险溢价)相关。1975 年,罗森博格成立了一家咨询公司,Barr Rosenberg Associates,Inc .这家公司被全世界的管理公司称为 BARRA。

目前,BARRA 模型是最知名的风险模型,MSCI 作为供应商提供。其他风险模型包括公理。虽然有各种类型的 BARRA 模型,但 BARRA 全球股票模型(GEM)是全球主要股票市场股票的风险模型[3]。该模型将股票收益分解为国家因素、行业因素、风险因素和个人因素,如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这可以用多元回归模型描述如下。Rn 是股票 n 的超额收益(相对于无风险利率),x 是股票 n 对每个因子(k,j,I)的因子敞口,f 是因子收益,en 是具体收益。这里的关键是要素收益的概念。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因子回报

为简单起见,我将用单因素模型而不是多因素模型来解释。我还将把数字数据集结构作为一个具体的例子。因子收益是以下横截面回归中的回归系数 f。这里 r 是 eraX 中的目标向量,x 是 eraX 中 featureA 的向量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因子回报是通过对宇宙中的风险因子下注来衡量预期的回报。因子暴露是股票暴露于该风险因子的程度,暴露越大,因子回报的收益越大。从上面的等式可以看出,回归模型是一个特定时间段(eraX)的横截面模型,在实际测试过程中,我们在一段时间内(如每月)对其进行累积,并观察其特征。

以下是 BARRA GEM 文档中的因子回报示例。如果一个因子收益明显向右,说明只要赌上那个因子,就能获得稳定的收益。如果价格明显下跌,那么你可以赌这个因素无效(转换多头和空头)。在当前的 2020 年,很少有一个方向的要素回报是显著的。因此,我们应该考虑每只股票的因素敞口,构建一个分散于各种因素的投资组合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

各种风险因子的因子收益。来源:[3]

因素回报和相关性

由于因子收益是回归系数,因此可以使用目标变量和解释变量的波动性将它们转换为相关性。在下面的等式中,b 是解释变量 x 对目标变量 y 的回归系数,σxy 是 x 和 y 的协方差,σx 和σy 分别是 x 和 y 的标准差。相关性,可以这么说,是标准化在-1 和 1 之间的因子收益,用波动性修正。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

相关性在风险模型中是一个非常重要的指标,因此在主动投资组合管理理论中也是如此。在主动投资组合管理理论中,相关性被称为信息系数,它是基金经理技能的一个指标。我将不详细解释这一领域。有兴趣可以参考最著名的主动管理理论的书[4]。

在这里,我描述了每个数字特征的因子回报(通过相关性计算)。计算简单地通过单因素模型来完成。从这个图中,我们可以一目了然的看出哪些特征有哪些特点,它们本身有多大的解释力。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数字特征的因子收益。来源:作者

应该注意的是,这些因素回报包括由于随机性引起的变化。以下是相关性=0.0 和相关性=0.005 (100 次试验)情况下的蒙特卡罗模拟。我们应该始终记住,这种程度的可变性可能是由于随机性而产生的。在 120 左右的样本期内确定统计显著性是一个非常困难的问题。我们可以看到最重要的因素回报是由敏捷 4 和 7 获得的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

随机因子回报。来源:作者

相关性评估

当我们这样想的时候,我们就能明白为什么 Numerai 使用相关性来评估。每个锦标赛参与者提交的预测本身就是一个丰富的超级因子——一个包含比典型因子更多信息的信号。Numerai 随后从这些由参与者独立产生的超级因素中寻求高额回报。如果因子回报很好,Numerai 可以简单地通过组合它们来操作,或者在某些情况下,可以从收集的单个因子中实现进一步的学习,以提高它们的性能。

风险因素作为一个特征

在这一章中,我们讨论如何将传统的风险因素作为机器学习的特征。首先,国别特征和行业特征很重要。

国家特色

Numerai 被认为在全球所有主要市场都有股票。在数字锦标赛的数据集中,个股的 id 是加密的,我们无从得知。不过,由于 Numerai Signals 公布了一份目标股票清单,我整理了一下。从股票总数来看,我怀疑它与当前的数字锦标赛相同。在数字信号列表中有 41 个国家,美国拥有最多的股票,其次是日本、韩国和英国。

这些可能不是简单地按国家合并,而是按地区(北美、南美、太平洋等)合并。).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个市场的股票数量。来源:作者

在通常的风险模型中,国家特征被作为 0/1 分类变量引入。然而,数字数据集基本上是一个 5 分位数,并且每个分位数的数量在大多数特征中是相同的。因此,如果我以这种方式创建一个特性,我将对每个国家(或每个地区)的指数进行多元回归,然后使用 beta 作为该特性的分位数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

例如,如果我们这样做,日本股票相对于东京市场指数将具有更高的 beta,并且将被聚集在该特征的更大(或更小,取决于分类符号)分位数中。然后,如果 Numerai 中有一个国家特征,最大的分位数只提供信息,其余的没有信息。Numerai 的 analysis_and_tips 报道了某些特征在特征值为 0 或 1 时具有显著的特征,我认为可能就是这种情况。

作为参考,我展示了自 2010 年以来每个国家的相对回报率趋势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个国家的累积相对收益。来源:作者

行业特征

其次,行业特色很重要。在《股市奇才》中,史蒂夫·科恩指出,40%的股票价格变动是由市场决定的,30%是由行业决定的,剩下的 30%是由个人原因决定的。没有理由不包含这一行业特征。行业的定义各不相同,但 BARRA GEM 定义了 38 个行业。此外,GICS 定义了 60 个部门,FactSet 的 RBICS 定义了 12 个经济体、31 个部门和 89 个子部门。作为参考,美国市场按经济体划分的股票数量如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

美国市场各行业股票数量。来源:作者

行业特征也可以用行业指数上的多元回归贝塔进行量化,就像国家特征的情况一样。同样在这种情况下,只有最大的分位数是有信息的,其余的没有信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作为参考,我展示了自 2010 年以来美国市场各行业的相对回报率趋势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

各行业累计相对收益。来源:作者

风险指数特征

风险指数很可能包含 BARRA 中使用的那些指标。它们是规模、价值、成功(势头)和波动性。这些可以简单地合并,但考虑到国家和行业的偏差,通常按类别进行标准化。

对于规模指数,可以考虑诸如销售额、总资产和雇员人数以及市场资本总额等因素。对于价值指数,可以考虑市净率、市盈率、现金流比。其他风险指数包括流动性、增长、股息和财务杠杆。除了这些传统的风险指数之外,还可以纳入其他变量,如从新闻中提取的分析师修正值和情绪指数。

作为参考,我展示了 2010 年以来美国市场各风险指数的相对收益趋势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每个风险因素的累积相对回报。来源:作者

融合传统定量方法和现代机器学习

在这一章中,我们将讨论如何使用机器学习来提高传统量化指标的性能。

树形模型

BARRA 模型只是单个风险因素的加权组合。有一种简单易行的方法可以改善这种情况。即考虑个体风险因素之间的相互作用。

举个简单的例子,有些行业更有可能是价值导向的,有些则不是。如果我们看股票的大小,有一个因素最适合大盘股,也有一个因素最适合小盘股。此外,不同的行业在不同的国家表现出色。

为了考虑这种相互作用,线性模型是不够的。在线性模型中,交互变量必须由人指定并设置为特征。在基于树的模型的情况下,模型可以在没有任何特定意图的情况下自己学习交互。另一方面,基于树的模型不善于理解原始 BARRA 模型的风险溢价,因为由于网格状划分,它们不善于线性分类。

对此的解决方案是线性和树模型的集合或堆叠。事实上,在 Kaggle 举行的两次适马金融竞赛中,岭回归和 ExtraTrees 的组合获得了好奖[5]。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 Kaggle 举行的双西格玛金融挑战赛中获得第五名。来源:[5]

深层因素模型

另一方面,也有在模型中使用深度学习的情况。这是一种叫做深度因子模型的技术[6]。在常规的量化管理中,基金经理根据他或她的经验创建和选择因素,但深度因素模型旨在通过用深度学习取代人类判断来消除人类判断,从而捕捉单个因素的非线性。

该方法使用 80 个因素来预测月度回报,并已被证实能够优于线性模型和其他机器学习方法(SVR 和随机森林)做出的预测。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

深度因子模型。来源:[6]

我认为,通过这种方式混合机器学习,相对容易胜过传统的量化模型。但另一方面,模型的复杂性可能会降低其可解释性,可能存在过学习和窥探偏差等陷阱,因此机器学习模型的构建需要金融领域特有的知识和直觉。关于这方面的更多技术技巧,我们应该参考 Numerai 首席科学顾问 Prado 的《金融机器学习》一书[7]。

结论

在本文中,我解释了传统定量方法的概念,然后描述了一种将传统风险因素作为一种特征的方法,并展示了如何将传统定量方法和现代机器学习融合在一起。这样,显著提高预测性能是可行的。

我也希望读者通过了解如何在传统的量化方法的基础上观察市场,对实际的市场更感兴趣,这将使对数字的分析更加愉快。

希望这篇文章能激发读者的好奇心,启发读者的预测模型。谢谢你看完。

UKI

参考

[1]巴尔·罗森博格、马拉泰·维奈,《投资风险的预测:系统性和剩余风险》,1975 年
[2]彼得·伯恩斯坦,《资本理念:现代华尔街的不可思议的起源》,1992 年
[3]巴拉全球股票模型手册
[4]理查德·格林诺德、罗纳德·卡恩,《主动投资组合管理》,1995 年
[5]团队最佳拟合,《两次适马金融建模代码竞赛,第 5 名获奖者访谈》,2017 年
[6]中川圭佑

数字阵列—您想知道的一切

原文:https://towardsdatascience.com/numpy-array-all-you-want-to-know-d3f8503a2f8f?source=collection_archive---------49-----------------------

如果您对 NumPy 数组有问题,请从阅读本文开始。

对于任何数据科学家来说,最具挑战性的步骤之一是理解如何使用和修改 NumPy 数组。今天,您将从库的角度学习关于数组的核心概念。我们一起潜水吧!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Pixabay — Pexels 提供

目录

  • 什么是 NumPy 数组
  • 关于异次元
  • 如何创建 NumPy 数组?
  • 用整形修改
  • 使用 NumPy 的操作
  • 转置你的数组
  • 带 NumPy 的条件
  • 额外的

什么是 NumPy 数组?

相同类型的数字表,由非负整数元组索引,也称为多维数组。

NumPy 的数组和标准数组的主要区别是后者只处理一维数组,提供的功能较少。

关于不同的维度

在我们开始讨论 NumPy 数组之前,有必要知道我们有哪些类型的维度。是的,他们有不同的名字,以后会引起一些误解。首先,让我们从标量开始。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

1.数量

也称为零阶张量;例如,它可以是任何有/没有单位、数量的数字,甚至是向量的函数。有量,无维度。

2.矢量

一阶张量;通常是单个数字的有序数组,表示为矩阵的一行(或一列)。只需要一个尺寸

  • 从向量及其以外,都将有大小和维度

3.[数]矩阵

二阶张量;就是一个由多行(或多列)数字组成的矩形数组。为了简单起见,矩阵是由几个向量组成的。

4.张量

封装标量、向量和矩阵。它们可以代表从零到 N 维的任何东西,这使得它们在深度学习中非常有用。张量可以是不同阶的,但通常我们用三阶或四阶;最后一个更复杂。

如何创建 NumPy 数组?

有几种方法可以创建数组。您可以从头开始生成数据,并使用生成的数据填充您的列,或者使用您已经拥有的数据,并将其转换为 NumPy 数组。让我们逐一讨论。

当你已经有了数据

这非常简单:只需将数据转换成一个数组。对于这个例子,我将创建一个熊猫系列。让我们检查一下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

多好啊!我们把我们的系列变成了 ndarray!现在我们可以开始将我们的数学工具应用于这些数据了!还有一点:如果你不知道什么是系列, 点击这里 学习。

从头开始生成数据

当您需要处理操作、条件和循环时,创建新数据非常有用。不用生成完整的数字列表,只需将开始、停止和步进参数传递给 NumPy 数组。有些函数甚至不需要这些参数!我们去看看。

1) np.arange()

你想用生成一个具有均匀间隔值的元素数组吗?所以试试 np.arange()函数。当你需要创建快速列表时,这是非常有用的。让我们检查代码。

来自 NumPy 文档:

  • 对于整数参数,该函数相当于 Python 内置的 range 函数,但是返回的是 ndarray 而不是 list
  • 当使用非整数步长时,如 0.1,**结果通常不一致。**这些情况最好使用 numpy.linspace。

2) np.linspace()

这与上面描述的非常相似,但有一个具体的区别:当在这里处理非常小的数字时,你不会受到影响,有更多的参数要定义,并且你**不需要定义任何步骤,只需要在你的数组上有多少个数字,**让我们看看。

3) np.random()

这是一个非常大的模块,每个案例都有许多特定的功能;当需要随机创建数字时,它被广泛使用。我将集中讨论最常用的方法。

numpy.random.randint()

从“半开”区间[ ]中指定数据类型的“离散均匀”分布中返回随机整数。如果为 None(缺省),那么结果是从【0,】低)”。来自文档

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

纪念

  • 如果尺寸参数大于高值,将重复输出。

numpy.random.random()

“返回半开区间[0.0,1.0]内的随机浮点数”。来自文档

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

纪念

  • 值的范围从 0.0 到小于 1.0。

numpy.random .指数()

“从指数分布中抽取样本”。来自文档

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

还有更多值得探索的地方!想看看吗? 点击这里 查看随机模块。

4 ) np.ones()和 np.zeros()

在你的任务中,可能需要创建只有 1 或 0 的 n 维数组,谁知道呢?NumPy 有这方面的函数,我们来看看. np.eye()

输出将是只有 1 或 0 的数组,如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

5) np.eye()

创建一个 0 和 1 的数组(数字 1 创建一条对角线);您可以毫不费力地找到该函数的实用程序。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

用整形修改 NumPy 数组

这是任何使用 NumPy 的人都必须知道的。在使用神经网络和深度学习时,重塑我们的阵列是一个至关重要的过程。

在调整形状期间,您可以修改阵列的格式,即行数、列数和维数。让我们用代码试试。

随着整形改变了数组的形状,我们将检查输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

别忘了

如果乘法产生的元素数量与之前不同,则不能修改尺寸。如果你有 20 个元素,你可以改造成(4,5),(5,4),(2,2,5),等等。

使用 NumPy 的操作

看看你的学习变得多么优秀!我们现在学到了很多东西,但是还有更多隐藏的东西!我们需要学习如何使用一些数字操作功能。

例如,因为你是数据科学家,所以没有理由解释 sum 函数是做什么的。因此,我将创建一个包含一些非常重要的操作的代码片段,并讨论输出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

我们有两个每 5 列 2 行的矩阵。上面,你可以查看每个操作的输出。这里没有什么玄机,但是如果你是新手,我会解释元素式乘法和点积的区别。

元素式产品

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自维基百科— 哈达玛产品

也称为哈达玛乘积,是一种二元运算,它采用两个维数相同的矩阵,并生成另一个维数相同的矩阵作为操作数。每个元素都是原始两个矩阵元素的乘积。看看下面的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图像通过矩阵乘法

点积

简单来说,点积就是两个数列对应项的乘积之和。没有比这更简单的方法了。用一个数字来理解吧。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由可汗学院

当我们需要直接处理数组时,点积广泛用于机器学习;通常当我们使用梯度下降法时。由于是高级内容,我推荐你去看看 这篇可汗学院关于矩阵乘法的文章

转置你的数组

转置矩阵是使用点积非常必要的功能,但它并不止于此:

  • 熊猫图书馆允许你的数据框架使用转置;
  • 您可以使用它来快速反转您的数组的列和行,用于任何您想要的目的;

因此,您将翻转您的行与列!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

有条件带 NumPy

最后,我想和大家分享两个用 NumPy 进行条件选择的有用函数:np.where()和 np.select()。两者都广泛用于熊猫,是本馆必备。

np.where()

np.where (条件,真则返回,假则返回)

首先,您传递您的布尔条件;然后,需要加上条件结果为真时要返回的值;最后,相反(如果假)。通过代码你会更好地理解它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

别忘了:np.where()只有在需要用条件返回一两个值的时候才有用。如果有更多的值,请使用 np.select()。

np.select()

NP . select*(cond list,choicelist,default)*

选择功能可以处理两个以上的条件,例如,当您需要应用 数据宁滨 时,它非常有用。在这里,您将一个条件列表传递给选项列表;两者将一起填充新列表。默认参数是不满足条件时使用的值。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

额外的

如果不先教你如何洗牌,我还是无法完成这篇文章。在训练机器学习算法时,这是一个非常重要的过程,以避免过度调整。还可以找到其他很棒的资源!

numpy.random.shuffle()

"通过混洗其内容来就地修改序列。这个函数只沿着多维数组的第一个轴打乱数组。子数组的顺序改变了,但它们的内容保持不变”。来自文档

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由雷南·洛里科拍摄——中号

纪念

  • shuffle 函数返回 None,它只是打乱原始数组,给值分配一个新的顺序。

就这样,伙计们!

我希望你喜欢这个内容,并能熟练运用你的新知识!如果你想每天学习有趣的东西,我很乐意与你分享精彩内容!

另外,你可以在 Github 上查看我的个人资料。我从事一些数据科学项目已经有一段时间了。所有的关键概念都可以学习和重用!

[## 雷南·洛利科-吉图布

在 GitHub 上注册你自己的个人资料,这是托管代码、管理项目和构建软件的最佳地方…

github.com](https://github.com/renfelo)

文献学

Numpy 数组指南:在 Python 中生成和操作数组

原文:https://towardsdatascience.com/numpy-array-cookbook-generating-and-manipulating-arrays-in-python-2195c3988b09?source=collection_archive---------10-----------------------

我的 numpy 数组清单

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我曾经作为一名数据科学家毫无准备地走进一家公司。虽然我期望成为训练模型,但我的角色却是软件工程,这个应用程序使用了我所见过的最大量的 numpy。

虽然我已经多次使用np.array()将一个列表转换成一个数组,但我并没有为一行又一行的linspacemeshgridvsplit做好准备。

如果我想能够读写代码,我需要尽快熟悉 numpy。

这是我为自己构建的 numpy 数组函数和示例的精选列表。

我们将在第一部分介绍数组的背景信息,然后讨论一些高级函数,这些函数将帮助您更快地处理数据。

**目录:**1。阵列概述
2。生成数组
3。操纵数组

1)阵列概述

什么是数组?

数组是存储同类数据的数据结构。这意味着所有的元素都是同一类型。

Numpy 的数组类是ndarray,意思是“N 维数组”。

import numpy as nparr = np.array([[1,2],[3,4]])
type(arr)#=> numpy.ndarray

它是 n 维的,因为它允许根据初始化时传递的形状创建几乎无限维的数组。

例如: np.zeros((2))生成一个 1D 数组。np.zeros((2,2))生成一个 2D 数组。np.zeros((2,2,2))生成一个 3D 数组。np.zeros((2,2,2,2))生成一个 4D 数组。诸如此类…

**np.zeros((2))**
#=> array([0., 0.])**np.zeros((2,2))**
#=> array([[0., 0.],
#=>        [0., 0.]])**np.zeros((2,2,2))**
#=> array([[[0., 0.],
#=>         [0., 0.]],
#=> 
#=>        [[0., 0.],
#=>         [0., 0.]]])
...

数组与列表

  • 数组比列表使用更少的内存
  • 阵列有更多的功能
  • 数组要求数据是同质的;列表不
  • 数组上的算术运算类似于矩阵乘法

重要参数

shape: 表示数组维数的元组。形状为(2,3,2)的数组是一个 2×3×2 的数组。看起来像下面。

np.zeros((2,3,2))#=> array([[[0., 0.],
#=>         [0., 0.],
#=>         [0., 0.]],
#=> 
#=>        [[0., 0.],
#=>         [0., 0.],
#=>         [0., 0.]]])

dtype: 存储在数组中的值的类型。数组是同质的,所以我们不能混合多种数据类型,如字符串和整数。dtype的值可以是np.float64np.int8intstr几种其他类型中的一种。

2)生成数组

零点

生成具有指定形状的零数组。

当您希望在开始训练之前将 ML 模型中的权重初始化为 0 时,这很有用。这也常用于初始化一个具有特定形状的数组,然后用您自己的值覆盖它。

np.zeros((2,3))
#=> array([[0., 0., 0.],
#=>        [0., 0., 0.]])

一念之差

生成具有指定形状的一个数组。

如果您需要在增量相减之前将值初始化为 1,这很有用。

np.ones((2,3))
#=> array([[1., 1., 1.],
#=>        [1., 1., 1.]])

空的

np.empty()与 0 和 1 略有不同,因为它没有在数组中预设任何值。有些人说初始化稍微快一点,但这可以忽略不计。

为了代码可读,在用数据填充数组之前初始化数组时,有时会用到这种方法。

arr = np.empty((2,2))
arr
#=> array([[1.00000000e+000, 1.49166815e-154],
#=>        [4.44659081e-323, 0.00000000e+000]])

全部

用给定值初始化数组。

下面我们用10初始化一个数组。然后是另一个有['a','b']对的数组。

**np.full((3,2), 10)**
#=> array([[10, 10],
#=>        [10, 10],
#=>        [10, 10]])**np.full((3,2), ['a','b'])**
#=> array([['a', 'b'],
#=>        ['a', 'b'],
#=>        ['a', 'b']], dtype='<U1')

排列

这可能是你在现实生活中见过最多的。它从一个“类数组”对象初始化一个数组。

如果您将数据存储在另一种数据结构中,但需要将其转换为 numpy 对象以便传递给 sklearn,这将非常有用。

li = ['a','b','c']
np.array(li)#=> array(['a', 'b', 'c'], dtype='<U1')

注意: *np.array* 还有一个参数叫做 *copy* ,可以设置为 *True* 来保证生成一个新的数组对象,而不是指向一个已有的对象。

_ 喜欢

有几个_like函数对应于我们已经讨论过的函数:empty_likeones_likezeros_likefull_like

它们生成的数组与传入的数组形状相同,但具有自己的值。所以ones_like生成一个 1 的数组,但是你传递给它一个现有的数组,它取那个数组的形状,而不是你直接指定形状。

a1 = np.array([[1,2],[3,4]])
#=> array([[1, 2],
#=>        [3, 4]])np.ones_like(a1)
#=> array([[1, 1],
#=>        [1, 1]])

请注意第二个 1 的数组是如何呈现第一个数组的形状的。

边缘

用随机值生成一个数组。

当您希望将模型中预先训练的权重初始化为随机值时,这很有用,这可能比将它们初始化为零更常见。

np.random.rand(3,2)
#=> array([[0.94664048, 0.76616114],
#=>        [0.395549  , 0.84680126],
#=>        [0.42873   , 0.77736086]])

阿萨瑞

np.asarraynp.array的包装器,设置参数copy=False。参见上面的np.array

阿兰格

生成一个值数组,其间隔设置在上限和下限之间。这是 numpy 版本的list(range(50,60,2))列表。

下面我们生成一个 50 到 60 之间的每秒值的数组。

np.arange(50,60,2)
#=> array([50, 52, 54, 56, 58])

林空间

生成两个其他数字之间间隔相等的数字数组。我们不是像arange那样直接指定区间,而是指定在上限和下限之间生成多少个数。

下面我们返回一个由 10 到 20 之间的 6 个数字和 0 到 2 之间的 5 个数字组成的数组。

np.linspace(10, 20, 6)
#=> array([10., 12., 14., 16., 18., 20.])np.linspace(0, 2, 5)
#=> array([0\. , 0.5, 1\. , 1.5, 2\. ])

请注意,我们是如何指定数组中元素的数量,而不是指定区间本身的。

网格

基于两个输入数组生成坐标矩阵。

这可能有点棘手。让我们看一个例子。生成 2 个数组并将它们传递给np.meshgrid

x = np.array([1,2,3])
y = np.array([-3,-2,-1])

xcors, ycors = np.meshgrid(x, y) xcors
#=> [[1 2 3]
#=> [1 2 3]
#=> [1 2 3]]ycors
#=> [[-3 -3 -3]
#=> [-2 -2 -2]
#=> [-1 -1 -1]]

在这里,我们可以看到两个不同的矩阵输出,基于输入数组的值和形状。

但是不要把它想象成两个独立的矩阵。这些实际上是一对(x,y)坐标,代表平面上的点。下面我把它们组合起来了。

[[(1, -3), (2, -3), (3, -3)]
 [(1, -2), (2, -2), (3, -2)],
 [(1, -1), (2, -1), (3, -1)]]

3)操纵数组

复制

制作现有阵列的副本。

将一个数组赋给一个新的变量名将会指向原来的数组。你需要小心这种行为,这样你就不会无意中修改现有的变量。

考虑这个例子。虽然我们修改了a2,但是a1的值也会改变。

a1 = np.array([1,2,3])
a2 = a1a2[0] = 10
a1
#=> array([10,  2,  3])

现在比较一下这个。我们修改了a2但是a1没有改变…因为我们做了一个拷贝!

a1 = np.array([1,2,3])
a2 = a1.copy()a2[0] = 10
a1
#=> array([1, 2, 3])

形状

获取数组的形状。

在处理大规模多维数组时非常有用,因为无法观察维度。

a = np.array([[1,2],[3,4],[5,6]])
a.shape
#=> (3, 2)

使再成形

重塑数组。

这非常有用,我无法想象没有它会使用像 Keras 这样的库。让我们看一个创建和整形数组的例子。

生成一个数组。

a = np.array([[1,2],[3,4],[5,6]])
a
#=> array([[1, 2],
#=>        [3, 4],
#=>        [5, 6]])

检查它的形状。

a.shape
#=> (3, 2)

将阵列从 3x3 调整为 2x3。

a.reshape(2,3)
#=> array([[1, 2, 3],
#=>        [4, 5, 6]])

将数组展平为一维。

a.reshape(6)
#=> array([1, 2, 3, 4, 5, 6])

将阵列重新整形为 6x1 矩阵。

a.reshape(6,1)
#=>array([[1],
#=>       [2],
#=>       [3],
#=>       [4],
#=>       [5],
#=>       [6]])

将数组重塑为 3 维,2x3x1。

a.reshape(2,3,1)
#=> array([[[1],
#=>         [2],
#=>         [3]],
#=> 
#=>        [[4],
#=>         [5],
#=>         [6]]])

调整大小

类似于reshape但是它改变了原来的数组。

a = np.array([['a','b'],['c','d']])
a
#=>array([['a', 'b'],
#=>       ['c', 'd']], dtype='<U1')a.reshape(1,4)
#=> array([['a', 'b', 'c', 'd']], dtype='<U1')a
#=>array([['a', 'b'],
#=>       ['c', 'd']], dtype='<U1')a.resize(1,4)
a
#=> array([['a', 'b', 'c', 'd']], dtype='<U1')

注意调用reshape并没有改变a,但是调用resize却永久地改变了它的形状。

移项

转置一个数组。

在生成 pandas 数据框或进行计数或求和等聚合计算之前,我们可以交换行和列吗?

a = np.array([['s','t','u'],['x','y','z']])
a
#=> array([['s', 't', 'u'],
#=>        ['x', 'y', 'z']], dtype='<U1')a.T
#=> array([['s', 'x'],
#=>        ['t', 'y'],
#=>        ['u', 'z']], dtype='<U1')

注意所有的东西是如何在sz之间的对角线上翻转的。

变平

将数组展平为一维并返回一个副本。

这实现了与下面的reshape(6)相同的结果。但是当您事先不知道数组的大小时,flatten会很有用。

a = np.array([[1,2,3],['a','b','c']])
a.flatten()
#=> array(['1', '2', '3', 'a', 'b', 'c'], dtype='<U21')a.reshape(6)
#=> array(['1', '2', '3', 'a', 'b', 'c'], dtype='<U21')

解开…的纠结

将类似数组的对象展平为一维。类似于flatten,但是它返回数组的视图而不是副本。

最大的好处是它可以用在非数组上,比如列表,而在列表中flatten会失败。

np.ravel([[1,2,3],[4,5,6]])
#=> array([1, 2, 3, 4, 5, 6])np.flatten([[1,2,3],[4,5,6]])
#=> AttributeError: module 'numpy' has no attribute 'flatten'

hsplit

将数组水平分割成子数组。

您可以将这想象成将矩阵中的每一列拆分成自己的数组。

如果每一列描述一个对象,每一行是这些对象的一个时间段,则在 ML 中用于拆分时间序列数据。

a = np.array(
    [[1,2,3],
     [4,5,6]])
a
#=> array([[1, 2, 3],
#=>        [4, 5, 6]])np.hsplit(a,3)# #=> [array([[1],[4]]), 
# #=>  array([[2],[5]]), 
# #=>  array([[3],[6]])]

vsplit

将数组垂直拆分成子数组。

您可以将这想象成将每一行拆分成自己的列。

如果每一行代表一个对象,每一列是这些对象的一个不同的特性,那么在 ML 中就很有用。

a = np.array(
    [[1,2,3],
     [4,5,6]])
a
#=> array([[1, 2, 3],
#=>        [4, 5, 6]])np.vsplit(a,2)#=> [array([[1, 2, 3]]), 
#=> array([[4, 5, 6]])]

连接轴上的数组。

这本质上与vsplithsplit相反,它将独立的数组组合成一个数组。

沿着axis=0

a = np.array(['a', 'b', 'c'])
b = np.array(['d', 'e', 'f'])np.stack((a, b), axis=0)
#=> array([['a', 'b', 'c'],
#=>       ['d', 'e', 'f']], dtype='<U1')

沿着axis=1

a = np.array(['a', 'b', 'c'])
b = np.array(['d', 'e', 'f'])np.stack((a, b), axis=1)
#=> array([['a', 'd'],
#=>        ['b', 'e'],
#=>        ['c', 'f']], dtype='<U1')

结论

我认为这是 numpy 的基础。当您在工作中阅读现有代码或在线学习教程时,您会反复遇到这些函数。

熟悉以上内容意味着你不会陷入理解如何使用meshgrid来生成 matplotlib 图表的困境。或者如何快速添加维度,使您的数据符合 Keras 模型的输入要求。

有哪些你离不开的 numpy 函数?

NumPy 数组操作

原文:https://towardsdatascience.com/numpy-array-manipulation-5d2b42354688?source=collection_archive---------26-----------------------

修改数组形状的实用指南

数据科学的一切都始于数据,数据有多种格式。数字、图像、文本、x 光、声音和视频记录只是数据源的一些例子。无论数据以何种格式传入,都需要转换成数字数组进行分析。复杂的计算机视觉模型无法像人类一样看到或处理图像。在分析之前,图像被转换成一组数字。因此,在数据科学中有效地存储和修改数字数组是至关重要的。NumPy(数字 Python)是一个科学计算包,它提供了非常实用的方法来创建和操作数字数组。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

阿里·耶尔马兹Unsplash 拍摄的照片

在这篇文章中,我将介绍在 NumPy 中使用以下操作来操作数组形状的方法:

  • 使再成形
  • 扩展 _ 变暗
  • 散开并弄平

如果你想了解 NumPy 的基础知识,你可以访问下面的帖子:

[## 数据科学中最被低估的工具:NumPy

NumPy 的强大功能以及如何有效地使用它

towardsdatascience.com](/the-most-underrated-tool-in-data-science-numpy-68d8fcbde524)

让我们从导入 NumPy 开始:

import numpy as np

提示:就存储和处理而言,NumPy 数组比列表有效得多。

重塑

Numpy 提供了灵活的工具来改变数组的维数。在更改维度之前,最好记住数组的维度是什么意思,以及不同维度的数组是什么样子:

a = np.random.randint(10, size=5)
a
array([9, 7, 3, 7, 5])a.ndim
1a.shape
(5,0)

我们还可以用 numpy 创建多维数组:

# 2-dimensional
b = np.zeros((3,4))b
array([[0., 0., 0., 0.],        
       [0., 0., 0., 0.],        
       [0., 0., 0., 0.]])b.ndim
2# 3-dimensional
c = np.ones((2,2,2))c
array([[[1., 1.],         
        [1., 1.]],

        [[1., 1.],         
         [1., 1.]]])c.ndim
3

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

有不同的方法来改变数组的维数。 Reshape 函数通常用于修改数组的形状和维度。我们只需要将新形状作为参数传递给 shape 函数:

提示:举例来说,我在创建数组时使用了不同的方法,这样您也可以熟悉如何创建数组。

np.arange(6)
array([0, 1, 2, 3, 4, 5])np.arange(6).reshape(2,3)
array([[0, 1, 2],        
       [3, 4, 5]])

shape (2,3)返回一个 2 行 3 列的二维新数组。因此,我们应用 reshape(2,3)的数组必须是 6 个元素。

让我们也使用 reshape 创建一个三维数组:

np.arange(8).reshape(2,2,2)array([[[0, 1],         
        [2, 3]],                 [[4, 5],         
         [6, 7]]])

reshape 函数的一个非常有用的特性是,如果不知道原始数组中元素的数量,可以将其中一个维度指定为“-1”。

因为我们几乎总是使用非常大的数组,所以键入(-1,1)而不是(100000,1)也很方便。

提示:调整数组形状时,新形状需要与原始形状兼容。

np.arange(6).reshape(-1,2)
array([[0, 1],        
       [2, 3],        
       [4, 5]])np.arange(6).reshape(-1,3)
array([[0, 1, 2],        
       [3, 4, 5]])

也可以在不改变元素顺序的情况下增加维度。我们可以通过整形(-1,1)或(1,-1)来实现:

np.random.normal(0,1,3)
array([-0.14788456,  0.01909406,  0.88659889])np.random.normal(0,1,3).reshape(-1,1)
array([[-0.14588167],        
       [ 0.06871804],        
       [ 2.32699261]])np.random.normal(0,1,3).reshape(1,-1)
array([[ 1.46812451,  0.48818206, -0.80228877]])

Expand_dims

顾名思义, expand_dims 扩展一个数组的形状。

a = np.array([1,2,3])np.expand_dims(a, axis=0)
array([[1, 2, 3]])np.expand_dims(a, axis=1)
array([[1],        
       [2],        
       [3]])

轴参数允许选择通过哪个轴进行扩展。

axis=1 的 expand_dims 等效于 shape(-1,1)。

np.expand_dims(a, axis=1)
array([[1],        
       [2],        
       [3]])np.expand_dims(a, axis=1)
array([[1],        
       [2],        
       [3]])

拆卷压平

Ravel 返回一个扁平数组。如果你熟悉卷积神经网络(CNN),汇集的特征映射在馈送到完全连接的层之前被展平。该操作将二维数组转换为一维数组。

a = np.random.randint(10, size=(2,3))
aarray([[6, 8, 2],        
       [5, 1, 8]])np.ravel(a)
array([6, 8, 2, 5, 1, 8])

第二行连接在第一行的末尾。Ravel 函数还允许使用顺序参数进行列级连接:

np.ravel(a, order='F')
array([6, 5, 8, 1, 2, 8])

展平也执行相同的操作:

array([[3, 5, 2],        
       [6, 7, 8]])a.flatten()
array([3, 5, 2, 6, 7, 8])

松散和展平的区别:

  • Ravel:尽可能返回原始数组的视图。
  • Flatten:总是返回原始数组的副本。

因此,您在 flatten 返回的数组上所做的更改将永远不会在原始数组上进行。但是,如果通过 ravel 修改返回的数组,也可能会改变原始数组。让我们看一个例子来说明这一点:

array([[3, 5, 2],        
       [6, 7, 8]])a.flatten()[0] = 10
a
array([[3, 5, 2],        
       [6, 7, 8]])np.ravel(a)[0] = 10
a
array([[**10**,  5,  2],        
       [ 6,  7,  8]])

如你所见,我们在 ravel 上所做的改变也改变了原始数组。

感谢您的阅读。如果您有任何反馈,请告诉我。

采用 Cython 的 NumPy 阵列处理:速度提高 5000 倍

原文:https://towardsdatascience.com/numpy-array-processing-with-cython-1250x-faster-a80f8b3caa52?source=collection_archive---------14-----------------------

本教程将向您展示如何使用 Cython 加速 NumPy 数组的处理。通过在 Python 中显式指定变量的数据类型,Cython 可以在运行时大幅提高速度。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

茱莉亚·乔皮恩:【https://unsplash.com/photos/IojCPQ2rWe8】T2

本教程涵盖的部分如下:

  • 遍历 NumPy 数组
  • NumPy 数组的 Cython 类型
  • NumPy 数组元素的数据类型
  • NumPy 数组作为函数参数
  • 对 NumPy 数组进行索引,而不是迭代
  • 禁用边界检查和负索引
  • 摘要

关于 Cython 及其使用方法的介绍,请查看我在上发表的关于使用 Cython 提升 Python 脚本的帖子。要不,我们开始吧!

[## 使用 Cython | Paperspace 博客提升 Python 脚本

Python 可能是当今最流行的编程语言之一,但它肯定不是最高效的。在…

blog.paperspace.com](https://blog.paperspace.com/boosting-python-scripts-cython/)

遍历 NumPy 数组

我们将从与上一教程相同的代码开始,除了这里我们将遍历一个 NumPy 数组而不是一个列表。NumPy 数组是使用 arrange()函数在 arr 变量中创建的,该函数从 0 开始以 1 为步长返回 10 亿个数字。

import time
import numpytotal = 0
arr = numpy.arange(1000000000)t1 = time.time()
for k in arr:
    total = total + k
t2 = time.time()print("Total = ", total)
t = t2 - t1
print("%.20f" % t)

我在一台配备 Core i7–6500 u CPU @ 2.5 GHz 和 16 GB DDR3 RAM 的机器上运行这个程序。Python 代码在 458 秒(7.63 分钟)内完成。太长了。

让我们看看在编辑了在之前的教程中创建的 Cython 脚本后,需要多长时间才能完成,如下所示。唯一的变化是在 for 循环中包含了 NumPy 数组。请注意,在使用 Cython 脚本之前,您必须使用下面的命令来重新构建它。

python setup.py build_ext --inplace

当前形式的 Cython 脚本在 128 秒(2.13 分钟)内完成。仍然很长,但这是一个开始。让我们看看如何让它更快。

NumPy 数组的 Cython 类型

之前我们看到,在为所使用的变量显式定义 C 类型后,Cython 代码运行得非常快。NumPy 数组也是这种情况。如果我们保留 NumPy 数组的当前形式,Cython 的工作方式与常规 Python 完全一样,为数组中的每个数字创建一个对象。为了让事情运行得更快,我们还需要为 NumPy 数组定义一个 C 数据类型,就像为任何其他变量一样。

NumPy 数组的数据类型为 ndarray ,代表 n 维数组。如果您使用关键字 int 来创建整数类型的变量,那么您可以使用 ndarray 来创建 NumPy 数组的变量。注意n array必须使用 NumPy 调用,因为n array在 NumPy 内部。因此,创建 NumPy 数组变量的语法是 numpy.ndarray 。下面列出的代码创建了一个名为 arr 的变量,数据类型为 NumPy ndarray

首先要注意的是,NumPy 是使用第二行中的常规关键字 import 导入的。在第三行,您可能会注意到 NumPy 也是使用关键字 cimport 导入的。

现在我们来看看 Cython 文件可以分为两类:

  1. 定义文件(。pxd)
  2. 实现文件(。pyx)

定义文件的扩展名为。pxd,用于保存 C 声明,例如要导入并在其他 Cython 文件中使用的数据类型。另一个文件是带有扩展名的实现文件。pyx,我们目前用它来编写 Cython 代码。在这个文件中,我们可以导入一个定义文件来使用其中声明的内容。

下面的代码将被写入扩展名为. pyx 的实现文件中。 cimport numpy 语句在 Cython 中导入一个名为“numpy”的定义文件。这样做是因为 cy thon“numpy”文件具有处理 NumPy 数组的数据类型。

下面的代码定义了前面讨论的变量,分别是 maxvaltotalkt1t2t 。有一个名为 arr 的新变量保存数组,数据类型numpy.ndarray。之前使用了两个导入语句,即import numpycimport numpy。这里哪一个是相关的?这里我们将使用需要的cimport numpy,而不是常规的import。这让我们可以访问在 Cython numpy 定义文件中声明的 numpy.ndarray 类型,因此我们可以将 arr 变量的类型定义为 numpy.ndarray。

maxval 变量被设置为等于 NumPy 数组的长度。我们可以从创建一个长度为 10,000 的数组开始,并在以后增加这个数字,以比较 Cython 相对于 Python 的改进。

import time
import numpy
cimport numpycdef unsigned long long int maxval
cdef unsigned long long int total
cdef int k
cdef double t1, t2, t
cdef numpy.ndarray arrmaxval = 10000
arr = numpy.arange(maxval)t1 = time.time()for k in arr:
    total = total + k
print "Total =", totalt2 = time.time()
t = t2 - t1
print("%.20f" % t)

在创建了一个类型为numpy.ndarray的变量并定义了它的长度之后,接下来是使用numpy.arange()函数创建数组。注意,这里我们使用的是 Python NumPy,它是使用import numpy语句导入的。

通过运行上面的代码,Cython 只用了 0.001 秒就完成了。对于 Python,代码耗时 0.003 秒。在这种情况下,Cython 比 Python 快近 3 倍。

maxsize变量设置为 100 万时,Cython 代码运行 0.096 秒,而 Python 需要 0.293 秒(Cython 也快了 3 倍)。当处理 1 亿个时,Cython 需要 10.220 秒,而 Python 需要 37.173 秒。对于 10 亿,Cython 需要 120 秒,而 Python 需要 458 秒。尽管如此,Cython 可以做得更好。让我们看看怎么做。

NumPy 数组元素的数据类型

第一个改进与数组的数据类型有关。NumPy 数组arr的数据类型根据下一行定义。注意,我们所做的只是定义数组的类型,但是我们可以给 Cython 更多的信息来简化事情。

请注意,没有任何东西可以警告您有一部分代码需要优化。一切都会起作用;你必须调查你的代码,找出可以优化的部分,以便运行得更快。

cdef numpy.ndarray arr

除了定义数组的数据类型,我们还可以定义两条信息:

  1. 数组元素的数据类型
  2. 维度数量

数组元素的数据类型是int,根据下面的代码行定义。使用 cimport 导入的 numpy 有一个对应于 NumPy 中每种类型的类型,但在末尾有 _t 。比如常规 NumPy 中的 int 对应 Cython 中的 int_t

参数是ndim,它指定了数组中的维数。这里设置为 1。请注意,它的默认值也是 1,因此可以从我们的示例中省略。如果使用了更多的维度,我们必须指定它。

cdef numpy.ndarray[numpy.int_t, ndim=1] arr

不幸的是,只有当 NumPy 数组是函数中的一个参数或者函数中的一个局部变量时——而不是在脚本体中——才允许这样定义 NumPy 数组的类型。我希望 Cython 尽快解决这个问题。我们现在需要编辑前面的代码,将其添加到下一节将要创建的函数中。现在,让我们在定义数组之后创建它。

注意,我们将变量arr的类型定义为numpy.ndarray,但是不要忘记这是容器的类型。该容器包含元素,如果没有指定其他内容,这些元素将被转换为对象。为了强制这些元素为整数,根据下一行将dtype参数设置为numpy.int

arr = numpy.arange(maxval, dtype=numpy.int)

这里使用的 numpy 是使用cimport 关键字导入的。一般来说,无论何时发现用于定义变量的关键字 numpy,都要确保它是使用cimport关键字从 Cython 导入的。

NumPy 数组作为函数参数

准备好数组后,下一步是创建一个函数,它接受下面列出的类型为numpy.ndarray的变量。这个函数被命名为do_calc()

import time
import numpy
cimport numpyctypedef numpy.int_t DTYPE_t
def do_calc(numpy.ndarray[DTYPE_t, ndim=1] arr):
    cdef int maxval
    cdef unsigned long long int total
    cdef int k
    cdef double t1, t2, t

    t1 = time.time() for k in arr:
        total = total + k
    print "Total = ", total

    t2 = time.time()
    t = t2 - t1
    print("%.20f" % t)

构建完 Cython 脚本后,接下来我们根据下面的代码调用函数do_calc()

import test_cython
import numpy
arr = numpy.arange(1000000000, dtype=numpy.int)
test_cython.do_calc(arr)

这种情况下的计算时间从 120 秒减少到 98 秒。这使得 Cython 在对 10 亿个数字求和时比 Python 快 5 倍。正如你现在所期望的,对我来说这仍然不够快。我们将在下一节看到另一个加速计算的技巧。

NumPy 数组上的索引与迭代

Cython 只是将计算时间减少了 5 倍,这并不鼓励我使用 Cython。但这不是 Cython 的问题,而是使用的问题。问题在于循环是如何产生的。让我们仔细看看下面给出的循环。

在之前的教程中,提到了非常重要的一点,那就是 Python 只是一个接口。界面只是让用户觉得事情更简单。请注意,简单的方法并不总是做某事的有效方法。

Python 有一种特殊的方法来迭代数组,这在下面的循环中实现。循环变量 k 循环遍历 arr NumPy 数组,从数组中一个元素一个元素地取出。变量 k 被分配给这样的返回元素。以这种方式循环遍历数组是 Python 中引入的一种风格,但它不是 C 用于循环遍历数组的方式。

for k in arr:
    total = total + k

对于编程语言来说,循环遍历数组的通常方式是从 0(有时从 1)开始创建索引,直到到达数组中的最后一个索引。每个索引用于索引数组以返回相应的元素。这是循环遍历数组的正常方式。因为 C 不知道如何以 Python 风格遍历数组,所以上面的循环是以 Python 风格执行的,因此执行起来要花很多时间。

为了克服这个问题,我们需要创建一个普通样式的循环,使用索引for访问数组元素。新的循环实现如下。

首先,有一个名为arr _ shape的新变量用于存储数组中元素的数量。在我们的示例中,只有一个维度,其长度通过使用索引 0 索引 arr.shape 的结果来返回。

然后 arr_shape 变量被提供给range()函数,该函数返回访问数组元素的索引。在这种情况下,变量 k 代表一个索引,而不是一个数组值。

在循环内部,通过索引 k 对变量 arr 进行索引来返回元素。

cdef int arr_shape = arr.shape[0]
for k in range(arr_shape):
    total = total + arr[k]

让我们编辑 Cython 脚本来包含上面的循环。下面列出了新脚本。旧循环被注释掉了。

import time
import numpy
cimport numpyctypedef numpy.int_t DTYPE_tdef do_calc(numpy.ndarray[DTYPE_t, ndim=1] arr):
    cdef int maxval
    cdef unsigned long long int total
    cdef int k
    cdef double t1, t2, t
    cdef int arr_shape = arr.shape[0] t1=time.time()#    for k in arr:
#        total = total + k for k in range(arr_shape):
        total = total + arr[k]
    print "Total =", total

    t2=time.time()
    t = t2-t1
    print("%.20f" % t)

通过构建 Cython 脚本,在将循环改为使用索引后,对 10 亿个数字求和的计算时间现在大约只有一秒钟。所以,时间从 120 秒减少到仅仅 1 秒。这是我们对 Cython 的期望。

请注意,当我们使用 Python 风格遍历数组时,不会发生任何错误。没有迹象可以帮助我们找出代码没有优化的原因。因此,我们必须仔细寻找代码的每一部分,寻找优化的可能性。

注意,普通 Python 执行上述代码需要 500 多秒,而 Cython 只需要 1 秒左右。因此,对于 10 亿个数的求和,Cython 比 Python 快 500 倍。超级棒。记住,为了减少计算时间,我们牺牲了 Python 的简单性。在我看来,将时间减少 500 倍,值得使用 Cython 优化代码。

代码速度提高 500 倍固然很好,但还有一个改进,这将在下一节讨论。

禁用边界检查和负索引

Cython 文档中所述,导致代码变慢的因素有以下几个:

  1. 边界检查,以确保索引在数组的范围内。
  2. 使用负索引访问数组元素。

当 Cython 执行代码时,这两个特性是活动的。可以使用负索引(如-1)来访问数组中的最后一个元素。Cython 还确保没有索引超出范围,如果出现这种情况,代码不会崩溃。如果您不需要这些功能,您可以禁用它以节省更多时间。这是通过添加以下行来实现的。

cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)

禁用这些功能后的新代码如下:

import time
import numpy
cimport numpy
cimport cythonctypedef numpy.int_t DTYPE_t@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False)  # turn off negative index wrapping for entire function
def do_calc(numpy.ndarray[DTYPE_t, ndim=1] arr):
    cdef int maxval
    cdef unsigned long long int total
    cdef int k
    cdef double t1, t2, t
    cdef int arr_shape = arr.shape[0] t1=time.time()#    for k in arr:
#        total = total + k for k in range(arr_shape):
        total = total + arr[k]
    print "Total =", total t2=time.time()
    t = t2-t1
    print("%.20f" % t)

构建并运行 Cython 脚本后,对 0 到 100000000 的数字求和的时间大约为 0.09 秒。与 Python 脚本大约 500 秒的计算时间相比,Cython 比 Python 快 5000 多倍。

在下一段代码中使用numpy.sum()函数的情况下,时间大约为 0.38 秒。那就是 Cython 快了 4 倍。

import numpy
import timearr = numpy.arange(100000000)t1 = time.time()
result = numpy.sum(arr)
t2 = time.time()
t = t2 - t1
print("%.20f" % t)

摘要

本教程使用 Cython 来提高 NumPy 数组处理的性能。我们通过四种不同的方式实现了这一目标:

1.定义 NumPy 数组数据类型

我们首先使用numpy.ndarray指定 NumPy 数组的数据类型。我们看到这个类型在使用cimport关键字导入的定义文件中是可用的。

2.指定数组元素的数据类型+维数

仅仅将numpy.ndarray类型赋给一个变量是一个开始——但这还不够。仍然需要提供两条信息:数组元素的数据类型和数组的维数。两者都对处理时间有很大影响。

只有当 NumPy 数组被定义为函数参数或函数内部的局部变量时,这些细节才会被接受。因此,我们在这些点上添加了 Cython 代码。您还可以指定函数的返回数据类型。

3.使用索引遍历 NumPy 数组

减少处理时间的第三种方法是避免 Pythonic 循环,在这种循环中,一个变量由数组中的值逐个赋值。相反,只需使用索引遍历数组。这导致时间的大量减少。

4.禁用不必要的功能

最后,您可以通过禁用 Cython 中为每个函数默认完成的一些检查来减少一些额外的毫秒数。这些包括“边界检查”和“回绕”禁用这些功能取决于您的具体需求。例如,如果使用负索引,则需要启用回绕功能。

本文原载于 Paperspace 博客 。你可以在渐变 上免费运行我的教程的代码

结论

本教程讨论了使用 Cython 操作 NumPy 数组,其速度是 Python 单独处理的 5000 倍以上。减少计算时间的关键是指定变量的数据类型,并对数组进行索引而不是迭代。

在下一篇教程中,我们将通过使用 Cython 来减少遗传算法的 Python 实现的计算时间,从而总结和推进我们迄今为止的知识。

Numpy 备忘单

原文:https://towardsdatascience.com/numpy-cheat-sheet-4e3858d0ff0e?source=collection_archive---------9-----------------------

Python Numpy 库基础的快速指南,包括代码示例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

查尔斯·德鲁维奥在 Unsplash 上的照片

NumPy 是一个库,它赋予 Python 快速处理数据的能力。与数据清理和操作相比,Numpy 有几个优点。它允许对机器学习中经常使用的数据结构进行有效的操作:向量、矩阵和张量。

当我第一次学习 NumPy 时,我很难记住所有需要的函数和方法。所以我把最常用的 Numpy 操作放在一起。我有时会回过头来看看这张便条,以唤起我的记忆。如果这对你的旅程有所帮助,我也很高兴。

这张纸条的结构是:

  1. n 维数组
  2. 阵列形状操作
  3. 数组上的数值运算
  4. 数组操作例程(选择和分割)
  5. 统计操作

这是一封长信,给自己泡杯茶,我们开始吧!

和往常一样,我们需要导入 NumPy 库:

import numpy as np

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源: me.me

1.n 维数组

什么是数组?

数组是存储相同类型元素的数据结构。存储在数组中的每一项称为一个元素。数组中元素的每个位置都有一个数字索引,用于标识元素。

1D vs 2D 阵列

1D 数组(即一维数组)存储同一数据类型的变量列表。使用索引可以访问每个变量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1D 阵列

2D 数组(即多维数组)以由行和列组成的格式存储数据。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2D 阵列

数组与列表

  • 数组比列表使用更少的内存
  • 阵列有更多的功能
  • 数组要求数据是同质的;列表不
  • 数组上的算术运算类似于矩阵乘法

NumPy 用于处理数组。NumPy 中的数组对象叫做ndarray

创建一个向量

要创建一个向量,我们只需创建一个一维数组。就像向量一样,这些数组可以水平(即行)或垂直(即列)表示。

# Create 1 dimensional array (vector)
vector_row = np.array([1,2,3]) # Create vector as a row
>>> array([1, 2, 3])vector_column = np.array([[1],[2],[3]]) #Create vector as a column
>>> array([[1],
           [2],  
           [3]])

创建矩阵

为了创建一个矩阵,我们可以使用一个 NumPy 二维数组。在我们的解决方案中,矩阵包含三行和两列。

matrix = np.array([(1,2,3),(4,5,6)]) # Two dimensional array
>>> array([[1, 2, 3],
          [4, 5, 6]])

创建稀疏矩阵

稀疏矩阵是大部分元素为零的矩阵。稀疏矩阵只存储非零元素,并假设所有其他值为零,从而节省大量计算资源。

想象一个矩阵,其中列是媒体上的每篇文章,行是每个媒体读者,值是一个人阅读该特定文章的时间(分钟)。这个矩阵会有数万列和数百万行!然而,由于大多数读者不会阅读所有文章,因此绝大多数元素都是零。

比方说,我们想创建一个有两个非零值的 NumPy 数组,然后把它转换成一个稀疏矩阵。如果我们查看稀疏矩阵,我们可以看到只有非零值被存储:

from scipy import sparse
matrix_large = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                         [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                         [3, 0, 0, 0, 0, 0, 0, 0, 0, 0]])# Create compressed sparse row (CSR) matrix
matrix_large_sparse = sparse.csr_matrix(matrix_large)
print(matrix_large_sparse)
>>>   (1, 1)	1
      (2, 0)	3

在上面的例子中,(1, 1)(2, 0)分别代表非零值13的索引。例如,元素1位于第二行第二列。

创建特殊数组

**np.zeros()**函数返回给定形状和类型的新数组,用零填充。

# Create  1d array of zeros, length 3
np.zeros(3) 
>>> array([0., 0., 0.])# 2x3 array of zeros
np.zeros((2,3))
>>>array([[0., 0., 0.],
         [0., 0., 0.]])

函数返回一个给定形状和类型的新数组,用 1 填充。

# Create 3x4 array of ones
np.ones((3,4)) 
>>> array([[1., 1., 1., 1.],
           [1., 1., 1., 1.],
           [1., 1., 1., 1.]])

**np.eye()**函数返回对角线上有 1 而其他地方有 0 的矩阵。

# Create 5x5 array of 0 with 1 on diagonal (Identity matrix)
np.eye(5) 
>>> array([[1., 0., 0., 0., 0.],
           [0., 1., 0., 0., 0.],
           [0., 0., 1., 0., 0.],
           [0., 0., 0., 1., 0.],
           [0., 0., 0., 0., 1.]])

**np.linspace()**函数返回指定间隔内均匀分布的序列。

# Create an array of 6 evenly divided values from 0 to 100
np.linspace(0,100,6) 
>>> array([  0.,  20.,  40.,  60.,  80., 100.])

**np.arange(start, stop, step)**函数返回在给定范围内包含均匀间隔值的ndarray对象。

这些参数决定了值的范围:

  1. start定义数组中的第一个值。
  2. stop定义数组的结尾,不包含在数组中。
  3. step是定义数组中每两个连续值之间的间距(差)的数字,默认为1

N 注:step不能为零。否则我们会得到一个ZeroDivisionError。如果增量或减量是0,我们就不能离开start任何地方。

# Array of values from 0 to less than 10 with step 3 
np.arange(0,10,3)
>>> array([0, 3, 6, 9])

**np.full(shape, fill_value)**函数返回一个指定形状的新数组,用fill_value填充。

# 2x3 array with all values 5
np.full((2,3),5)
>>> array([[5, 5, 5],
           [5, 5, 5]])

**np.random.rand()**函数返回指定形状的数组,并用随机值填充。

# 2x3 array of random floats between 0–1
np.random.rand(2,3)
>>> array([[0.37174775, 0.59954596, 0.50488967],
           [0.22703386, 0.59914441, 0.68547572]])# 2x3 array of random floats between 0–100
np.random.rand(2,3)*100
>>> array([[23.17345972, 98.62743214, 21.40831291],
           [87.08603104, 84.23376262, 63.90231179]])# 2x3 array with random ints between 0–4
np.random.randint(5,size=(2,3))
>>> array([[2, 3, 4],
           [4, 4, 0]])

2.阵列形状操作

形状

检查一个数组的形状和大小对于进一步的计算和简单地在一些操作后进行检查是有价值的。

NumPy 数组有一个名为shape的属性,它返回一个元组,每个索引都有相应元素的数量。

arr = np.array([(1,2,3),(4,5,6)])
arr.shape # Returns dimensions of arr (rows,columns)
>>> (2, 3)

在上面的例子中,(2, 3)表示数组有 2 个维度,每个维度有 3 个元素。

使再成形

了解如何重塑 NumPy 数组很重要,这样我们的数据才能满足特定 Python 库的期望。例如,Scikit- learn 要求输出变量y的一维数组的形状像一个二维数组,其中一列和每行的结果。

一些算法,如 Keras 中的长短期记忆递归神经网络,需要将输入指定为由样本、时间步长和特征组成的三维数组。

reshape()允许我们重新构建一个数组,这样我们可以维护相同的数据,但是它被组织成不同数量的行和列。

N 注:原矩阵和新矩阵的形状包含相同数量的元素(即相同的大小)

arr1 = np.arange(1, 11)  # numbers 1 to 10
>>> array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])print(arr1.shape) # Prints a tuple for the one dimension.
>>> (10,)

我们可以使用reshape()方法将我们的数组整形为一个 2 乘 5 维的数组。

arr1_2d = arr1.reshape(2, 5)print(arr1_2d)
>>> array([[ 1,  2,  3,  4,  5],
           [ 6,  7,  8,  9, 10]])

如果我们希望 NumPy 自动确定特定维度的大小/长度,那么将维度指定为-1,这实际上意味着“需要多少就有多少”例如,reshape(2, -1)表示两行和任意多列。

arr1.reshape(2, 5)
arr1.reshape(-1, 5)  # same as above: arr1.reshape(2, 5)
arr1.reshape(2, -1)  # same as above: arr1.reshape(2, 5)

移项

转置是线性代数中的常见操作,其中每个元素的列和行索引被交换。

在最后一个例子中,arr1_2d是一个 2×5 维的数组,我们希望用它的列来交换它的行。

arr1_2d.T
>>> array([[ 1,  6],
          [ 2,  7],
          [ 3,  8],
          [ 4,  9],
          [ 5, 10]])

展平矩阵

flatten()是将一个矩阵转换成一维数组的简单方法。

arr1_2d.flatten()
>>> array([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10])

调整矩阵大小

**resize(arr, new_shape)**函数返回指定形状的新数组。
如果新数组比原数组大,那么新数组用arr的重复副本填充。

# Resize arr1_2d to 3 rows, 4 columns 
resize_arr = np.resize(arr1_2d, (3,4))
resize_arr
>>> array([[ 1,  2,  3,  4],
           [ 5,  6,  7,  8],
           [ 9, 10,  1,  2]])

矩阵求逆

矩阵 A 的是这样一个矩阵,当乘以 A 时得到恒等式。一个很好的例子是在线性回归中寻找系数值的向量。

使用 NumPy 的线性代数inv方法:

matrix = np.array([[1, 2],
                   [3, 4]])# Calculate inverse of matrix
np.linalg.inv(matrix)
>>> array([[-2\. ,  1\. ],
          [ 1.5, -0.5]])

将数组转换为列表,反之亦然

当我第一次学习 Python 时,我经常遇到的一个错误——有时现在仍然会遇到——是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数组需要声明,而列表不需要声明,因为它们是 Python 语法的一部分。这就是列表比数组更常用的原因。但是在对我们的列表执行一些算术函数的情况下,我们应该用数组来代替。

如果我们想要存储大量数据,我们应该考虑数组,因为它们可以非常紧凑和高效地存储数据。

arr = np.array([(1,2,3),(4,5,6)])
>>> array([[1, 2, 3],
          [4, 5, 6]])arr_to_list = arr.tolist() # Convert arr to a Python list
>>> [[1, 2, 3], [4, 5, 6]]np.array(arr_to_list) # Convert list to array 
>>> array([[1, 2, 3],
          [4, 5, 6]])

描述阵列的其他有用函数:

arr.size # Return number of elements in arr
len(arr) #Length of arrayarr.ndim # Number of array dimension
arr.dtype # Return type of elements in arr
arr.dtype.name # Name of data type
arr.astype(int) # Convert an array to a different type
arr.astype(dtype) # Convert arr elements to type dtype
np.info(np.eye) # View documentation for np.eye

3.数组上的数值运算

迹(线性代数)

轨迹是一个方阵的所有对角元素的总和。

arr = np.array([[2, 0, 0], [0, 2, 0], [0, 0, 2]])
np.trace(arr)
>>> 6

决定因素

行列式矩阵是一种特殊的数,可以从方阵中计算出来。计算矩阵的行列式有时会很有用。NumPy 用det()让这变得简单。

matrix = np.array([[1, 2, 3],
                   [2, 4, 6],
                   [3, 8, 9]])# Return determinant of matrix
np.linalg.det(matrix)
>>> 0.0

求矩阵的秩

矩阵的秩是矩阵中线性无关的行或列的数量的估计。知道矩阵的秩很重要。在解线性方程组时,秩可以告诉我们Ax = 0是有一个解还是多个解。

matrix = np.array([[1, 1, 3],
                   [1, 2, 4],
                   [1, 3, 0]])# Return matrix rank
np.linalg.matrix_rank(matrix)
>>> 3

求特征值和特征向量

许多机器学习问题可以用线性代数建模,其解来自特征值和特征向量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征值和特征向量

在 NumPy 的线性代数工具集中,eig让我们计算任何方阵的特征值和特征向量。

matrix = np.array([[0, 1, 2],
                   [3, 4, 5],
                   [6, 7, 8]])# Calculate eigenvalues and eigenvectors
eigenvalues, eigenvectors = np.linalg.eig(matrix)
eigenvalues
>>> array([ 1.33484692e+01, -1.34846923e+00, -2.48477279e-16])
eigenvectors
>>> array([[ 0.16476382,  0.79969966,  0.40824829],
           [ 0.50577448,  0.10420579, -0.81649658],
           [ 0.84678513, -0.59128809,  0.40824829]])

标量运算

当我们对一个矩阵加、减、乘或除一个数时,这就叫做标量运算。在标量操作期间,标量值应用于数组中的每个元素,因此,该函数返回一个具有相同行数和列数的新矩阵。

new_arr = np.arange(1,10)
>>> array([1, 2, 3, 4, 5, 6, 7, 8, 9])# Add 1 to each array element
np.add(new_arr,1)
>>> array([ 2,  3,  4,  5,  6,  7,  8,  9, 10])

同样,我们可以使用下面的函数对矩阵进行减法、乘法或除法运算:

np.subtract(arr,2) # Subtract 2 from each array element
np.multiply(arr,3) # Multiply each array element by 3
np.divide(arr,4) # Divide each array element by 4 (returns np.nan for division by zero)
np.power(arr,5) # Raise each array element to the 5th power

矩阵运算

如果两个矩阵具有相同的维数,即它们必须具有相同的行数和列数,则只能将一个矩阵与另一个矩阵相加(或相减)。

矩阵相乘时,我们取第一个矩阵的行,乘以第二个矩阵对应的列。

注意:记住“行优先,列第二”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

乘法矩阵

了解矩阵的形状是很重要的。然后矩阵操作使用 NumPy 库是简单的。

np.add(arr1,arr2) # Elementwise add arr2 to arr1
np.subtract(arr1,arr2) # Elementwise subtract arr2 from arr1
np.multiply(arr1,arr2) # Elementwise multiply arr1 by arr2
np.divide(arr1,arr2) # Elementwise divide arr1 by arr2
np.power(arr1,arr2) # Elementwise raise arr1 raised to the power of arr2
np.array_equal(arr1,arr2) # Returns True if the arrays have the same elements and shape

其他数学运算:

np.sqrt(arr) # Square root of each element in the array
np.sin(arr) # Sine of each element in the array
np.log(arr) # Natural log of each element in the array
np.abs(arr) # Absolute value of each element in the array
np.ceil(arr) # Rounds up to the nearest int
np.floor(arr) # Rounds down to the nearest int
np.round(arr) # Rounds to the nearest int

4.数组操作例程

添加/删除元素

**append()**函数用于将值追加到给定数组的末尾。

np.append ([0, 1, 2], [[3, 4, 5], [6, 7, 8]])
>>> array([0, 1, 2, 3, 4, 5, 6, 7, 8])np.append([[0, 1, 2], [3, 4, 5]],[[6, 7, 8]], axis=0)
>>> array([[0, 1, 2],
           [3, 4, 5],
           [6, 7, 8]])

沿其追加值的轴。如果没有给定轴,数组和值在使用前都被展平。

**insert()**:用于在数组的给定索引前插入元素。

arr = np.arange(1,6)
np.insert(arr,2,10) # Inserts 10 into arr before index 2
>>>array([ 1,  2, 10,  3,  4,  5])

**delete()**我们可以从ndarray中删除任何行和列

arr = np.arange(12).reshape(3, 4)
>>> [[ 0  1  2  3]
     [ 4  5  6  7]
     [ 8  9 10 11]]np.delete(arr,2,axis=0) # Deletes row on index 2 of arr
>>> array([[0, 1, 2, 3],
           [4, 5, 6, 7]])np.delete(arr,3,axis=1) # Deletes column on index 3 of arr
>>> array([[ 0,  1,  2],
           [ 4,  5,  6],
           [ 8,  9, 10]])

**sort()**函数可以用来对列表进行升序和降序排序。

oned_arr = np.array([3,8,5,1])
np.sort(oned_arr)
>>> array([1, 3, 5, 8])arr = np.array([[5, 4, 6, 8],
                [1, 2, 4, 8],
                [1, 5, 2, 4]])# sort each column of arr
np.sort(arr, axis=0)
>>> array([[1, 2, 2, 4],
           [1, 4, 4, 8],
          [5, 5, 6, 8]])# sort each row of X
np.sort(arr, axis=1)
>>> array([[4, 5, 6, 8],
          [1, 2, 4, 8],
          [1, 2, 4, 5]])

加入 NumPy 数组

连接意味着将两个或多个数组的内容放在一个数组中。在 NumPy 中,我们通过轴连接数组。我们传递一系列我们想要加入到concatenate()函数中的数组,以及轴。如果没有显式传递该轴,则该轴被视为 0。

# Adds arr2 as rows to the end of arr1
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
arr = np.concatenate((arr1, arr2), axis=0)
>>> array([1, 2, 3, 4, 5, 6])# Adds arr2 as columns to end of arr1
arr1 = np.array([[1, 2, 3],[4, 5, 6]])
arr2 = np.array([[7, 8, 9],[10, 11, 12]])
arr = np.concatenate((arr1,arr2),axis=1)
>>> array([[ 1,  2,  3,  7,  8,  9],
           [ 4,  5,  6, 10, 11, 12]])

拆分 NumPy 数组

酷,现在我们知道如何将多个阵列合并成一个。如何把一个数组拆成多个?我们使用array_split()来分割数组,我们传递给它我们想要分割的数组和分割的数目。

N 注意:如果数组的元素比要求的少,它将从末尾进行相应的调整。

# Splits arr into 4 sub-arrays
arr = np.array([1, 2, 3, 4, 5, 6])
new_arr = np.array_split(arr, 4) 
>>> [array([1, 2]), array([3, 4]), array([5]), array([6])]# Splits arr horizontally on the 2nd index
arr = np.array([1, 2, 3, 4, 5, 6])
new_arr = np.hsplit(arr, 2)
>>> [array([1, 2, 3]), array([4, 5, 6])]

选择元素

NumPy 为索引和分割数组中的元素或元素组提供了多种方法。

注意:NumPy 数组是零索引的,这意味着第一个元素的索引是 0,而不是 1。

假设我们有两个数组,一个包含 user_name,另一个存储这个人阅读的文章数量。

user_name = np.array(['Katie','Bob','Scott','Liz','Sam'])
articles = np.array([100, 38, 91, 7, 25])user_name[4] # Return the element at index 4
>>> 'Sam'articles[3] = 17 # Assign array element on index 1 the value 4
>>>array([100,  38,  91,  17,  25])user_name[0:3] # Return the elements at indices 0,1,2
>>> array(['Katie', 'Bob', 'Scott'], dtype='<U5')user_name[:2] # Return the elements at indices 0,1
>>> array(['Katie', 'Bob'], dtype='<U5')articles<50 # Return an array with boolean values
>>> array([False,  True, False,  True,  True])articles[articles < 50] # Return the element values
array([38,  7, 25])# Return the user_name that read more than 50 articles but less than 100 articles
user_name[(articles < 100 ) & (articles >50)]
>>> array(['Scott'], dtype='<U5')

我们使用类似的方法来选择多维数组中的元素:

arr[2,5] # Returns the 2D array element on index [2][5]
arr[1,3]=10 # Assigns array element on index [1][3] the value 10
arr[0:3] # Returns rows 0,1,2
arr[0:3,4] # Returns the elements on rows 0,1,2 at column 4
arr[:2] # Returns returns rows 0,1
arr[:,1] # Returns the elements at index 1 on all rows

5.统计操作

求最大值和最小值

通常我们想知道数组或数组子集的最大值和最小值。这可以通过maxmin方法完成。使用axis参数,我们也可以沿某个轴进行操作:

假设我们将一个人每月的文章数量存储在一个数组中。

articles = np.array([[10, 23, 17],
                   [41, 54, 65],
                   [71, 18, 89]])# Return maximum element
np.max(articles)
>>> 89
np.max(articles, axis=0) *# Find maximum element in each column
>>>* array([71, 54, 89])
np.max(articles, axis=1) # Find maximum element in each row
>>> array([23, 65, 89])

我们可以用类似的方法找到最小元素:

np.min(arr) # Return minimum element
np.min(arr,exis=0)# Find minimum element in each column
np.min(arr,axis=1)# Find minimum element in each row

计算平均值、方差和标准差

就像使用max()min()一样,我们可以很容易地获得整个矩阵的描述性统计数据,或者沿着单个轴进行计算。

np.mean(arr,axis=0) # Return mean along specific axis
arr.sum() # Return sum of arr
b.cumsum(axis=1) # Cumulative sum of the elements
np.var(arr) # Return the variance of array
np.std(arr,axis=1) # Return the standard deviation of specific axis
arr.corrcoef() # Return correlation coefficient of array

本笔记中的代码可在 Github 上获得。

就是这样!

我认为这个音符是 NumPy 的基础。在工作中阅读现有代码或在线学习教程时,您可能会反复遇到这些函数。当我发现更多有用的 Numpy 函数时,我会不断更新它。

所有的学习活动都是在时间和经历中进行的。在几个小时内学会 Python 是不可能的。记住,任何努力最困难的部分是开始,你已经度过了,继续努力,继续努力!!!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:模因

资源

Numpy 是一个非常重要的库,几乎每个数据科学或机器学习 Python 包(如 SciPy、Matplotlib、Scikit-learn)都在一定程度上依赖于它。对基本面有很强的理解是很重要的。方便的是,有一些很棒的资源可以帮助完成这项任务。下面我列出了一些我最喜欢的,其中一些深入到线性代数的各个方面;如果您渴望了解更多信息,请查看它们!

  1. 线性代数,麻省理工
  2. 深度学习的基础线性代数
  3. 【NumPy 数组和 matrics 的区别
  4. 稀疏矩阵,SciPy 文档
  5. NP . shape()一步一步来
  6. 机器学习—特征值和特征向量

NumPy 的备忘单:基本功能和鲜为人知的功能

原文:https://towardsdatascience.com/numpy-cheatsheet-for-essential-functions-python-2e7d8618d688?source=collection_archive---------40-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(照片由克里斯·利维拉尼Unsplash 上拍摄)

终极指南

学习你可能不知道的 NumPy 的各种基本功能(用代码)

Numpy ( 代表数值 Python )是 Python 编程语言中可用的库,支持矩阵数据结构和多维数组对象。这是我们需要学习的最基本的科学计算库,以开始我们在数据科学领域的旅程。

Numpy 可以计算基本数学计算以使创建高级机器学习和人工智能应用程序的过程更容易(通过使用库中可用的综合数学函数)。Numpy 允许我们毫不费力地进行各种复杂的数学计算以及几个补充库(如 matplotlib、pandas、scikit-learn 等)。)建在它上面。

这个库是每个数据科学专业人员高效处理和分析数据的一个很好的工具。此外,与 python 的 list 相比,使用 numpy 数组执行数学运算要容易得多。

Numpy 库中有各种可用的函数。在本文中,我们将学习本库的一些基本鲜为人知的函数,以及如何高效地实现它们。

注意:在本文中,我们将使用 谷歌合作实验室 来执行我们的代码。

导入数字

Numpy 可以通过使用以下代码简单地导入到笔记本中:

import **numpy** as **np**

在这里,numpy 写成 np 是为了节省编码时的时间,也是数据科学界的事实。

现在,让我们从 numpy 函数开始吧!

使用 numpy 创建 n 维数组

数组是 numpy 库中的一种数据结构,它就像一个可以存储值的列表,但不同之处在于,我们可以指定数组元素的数据类型(dtype函数),数组速度更快,存储数据占用的内存更少,允许代码进一步优化。

要创建一个一维数组我们可以使用下面的代码:

import numpy as np
array = **np.array(**[1,2,3,4,5]**)**

创建多维数组的过程类似,我们只需在[]括号中添加更多的值:

array = **np.array(**[[1.1,2.2,3.0,4.6,5.0],[6.4,7.3,8.5,9.1,10.2]**)**

numpy.linsapce()函数

这个numpy.linspace()函数用于在给定的区间内创建一个均匀分布的数组。我们还可以确定我们想要生成的样本数(但是,它是一个可选参数,缺省值设置为五十个样本)。我们可以添加到该函数的另一个可选参数是restep,如果True将返回space,即样本与列表之间的间距。功能是:numpy.linspace(start, stop)。让我们在一个例子中应用这个函数:

import numpy as np
import matplotlib.pyplot as plt
x = **np.linspace(0,10,10,dtype = int, retstep=True)**
print(x)
x = np.linspace(0,10,100)
y = np.sin(x)
plt.plot(x,y,color = 'orange')
plt.show()

正如我们在这里看到的,即使是计算数学函数,我们也在使用numpy库。我们使用linspace()函数生成等距值,并使用该数组绘制sine函数图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 正弦函数图使用 linspace()函数生成数值

随机抽样函数

在这里,numpy.random函数帮助我们以各种方式计算随机值,比如以给定的形状生成随机值,通过从给定的 1D 数组中随机选择值来生成数组,或者随机置换给定数组或范围的序列。

  • **numpy . rand()😗*使用此函数,我们可以在给定的输入形状上创建一个均匀分布的值数组,范围为0,1。例如:
**np.random.rand**(3,4)

正如我们在本例中所看到的,shape (3,4)的数组是用范围在[0,1]内的所有值生成的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 生成随机值

  • numpy.random.choice(): 这个随机函数从给定的输入数组中返回一个随机样本数组。我们可以定义的其他可选参数是- size即数组的输出形状,replace即我们是否希望输出数组中有重复值,以及p即输入数组的每个给定样本的概率。看看下面的例子:
**np.random.choice**([1,2,3,4],(1,2,3),replace=True,p=[0.2,0.1,0.4,0.3])

这里,我们已经给函数提供了以下输入参数——一个具有四个元素的输入数组,输出数组的形状(上面代码中的1是我们想要作为输出的数组的编号,2,3是输出形状),值的重复是True和每个样本的概率(其中值的总和应该等于 1)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 随机抽样使用 numpy.random.choice()

  • **NP . random . permutation()😗*此函数返回一个随机排列的序列(对于输入数组)或排列的范围(对于单输入)。
arr = np.random.permutation(5)
print('Permutation of a range: ' + str(arr))
arr_ = np.random.permutation([1,2,3,4,5,6,7,8,9])
print('Permutation of elements of input array: ' + str(arr_))

在第一种情况下,我们返回了一个输入范围内的置换数组,在第二种情况下,我们返回了一个输入数组内的置换数组。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 使用 numpy 随机排列

***numpy.random***中可用的功能不仅仅限于这些,您还可以在这里找到完整详尽的功能列表: numpy 文档页面

数组的索引和切片

为了访问和修改数组的对象,我们使用索引和切片方法。长度为**n**的数组中第一个元素的索引值,从**0**值开始,数组最后一个元素的索引将为**n-1**

a = [1,2,3,4,5,6]
b = a[3]
#output = 4

在上面的例子中,这个索引方法将返回数组的第四个元素a.

对于数组的基本切片(即,简单地说,拆分数组),我们使用**[start:stop:step_size]**符号。

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
**arr[1:7:2]**
#output array([1, 3, 5])

**高级索引和切片:**对于多维数组,我们可以通过输入特定的行和列值(以**[rows,column]**格式)来索引和切片数组。为了更好地理解,请看下面的例子:

x = np.array([[ 0,  1,  2],
[ 3,  4,  5],
[ 6,  7,  8]])
**x[0:2,1:2]**

这里,我们选择了前两行的索引(即代码中的0:2)和索引为1(即代码中的1:2)的单列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 高级索引和切片

numpy.ravel()和 numpy.flatten()函数

这些函数返回输入数组的 1D 展平形式。

arr = np.array([[1,2], [3,4],[5,6]])
x = arr.flatten()
print(x)
y = arr.ravel()
print(y)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 输出上面的代码

您可能会观察到两个函数的输出是相同的!现在你可能想知道这两个函数有什么不同,因为它们的输出结果是一样的。很简单,在numpy.flatten()中创建原始数组的副本,而在numpy.ravel()中改变原始数组。此外,numpy.ravel()功能比numpy.flatten()快,因为它不占用任何内存。

numpy.isclose()函数

此函数用于检查两个数组在容差范围内的元素是否相等,并返回一个布尔数组。.isclose函数数组可以用来assert(验证)你的代码。

def inv(arr):
  arr = np.array(arr)
  inverse = **np.linalg.inv**(arr)
  return inverse**assert** np.all(**np.isclose**(inv(np.array([[6, 1, 1], [4, -2, 5], [2, 8, 7]])).tolist(),np.array([[0.17647058823529413,-0.0032679738562091526, -0.02287581699346405],[0.05882352941176469, -0.130718954248366, 0.0849673202614379],[-0.1176470588235294, 0.1503267973856209, 0.0522875816993464]])))print("Sample Tests passed", '\U0001F44D')

在上面的例子中,我们正在使用另一个 numpy 函数numpy.linalg.inv()寻找给定矩阵的逆矩阵。之后,我们使用assert函数验证结果,并使用numpy.isclose()函数检查输出值是否接近真实值。只有当所有的值都是Trueassert 函数才会起作用,否则它会给出一个断言错误。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 实施。isclose()函数

numpy 中的堆栈数组

numpy 中有两个函数可用于堆叠不同的数组。

  • numpy.hstack(): 此函数按列(即水平)堆叠数组,类似于沿第二个轴串联数组(除了 1D 数组,它沿第一个轴串联)。对于这个函数,输入数组应该是相同的形状(1D 数组除外,它可以是任意长度)。
a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[7,8],[9,10],[11,12]])
**np.hstack**((a,b))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 水平堆叠的数组使用。hstack()函数

numpy.vstack(): 这个函数按行(即垂直)堆叠数组,类似于 shape (N,)的一维数组被重新整形为(1,N)后沿第一个轴的数组的串联。对于这个函数,输入数组应该具有相同的形状(1D 数组必须具有相同的长度)。

a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[7,8],[9,10],[11,12]])
**np.vstack**((a,b))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 垂直堆叠的数组使用。vstack()函数

numpy 的统计功能

Numpy 库有一些有用的功能,可以用来发现见解和统计分析数据。我们可以计算平均值、中值、方差、标准差,计算一组数据的直方图,等等。

  • numpy.mean(): 使用这个函数,我们可以计算给定数组的算术平均值,我们还可以指定轴。
arr = a = np.array([[1, 2], [3, 4]])
np.mean(a,axis=1)
**#output:** 
array([1.5, 3.5])
  • 这个函数帮助我们计算一组数据的直方图。这里,我们必须输入一个我们想要计算直方图的数据的展平数组,我们还可以定义bins的数量(即给定范围内等宽面元的数量(可选)),以及面元上限和限制的range(可选)。
arr = np.array([1,2,3,2,2,3,4,5])
np.histogram(arr, bins= [1,2,3,4,5])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(图片由作者 ) 使用 numpy 计算直方图

您也可以使用 matplotlib 库在绘图上显示直方图值。

你可以在这里找到其他的 numpy 统计函数: numpy 文档页面

结论

我希望通过这篇文章,您一定已经了解了这个库的一些基本的和新的功能。为了更好地理解,我建议您尝试自己实现这些功能。

在日常使用中贯彻这些技巧,作为数据科学专业人士,一定会让你受益匪浅!

如果你有任何问题或意见,请发表在评论区。

如果你想了解如何可视化数据,并从中找到直观的见解,那么看看我们的另一篇文章:

[## 用 Python 实现数据可视化

Master python 的数据可视化库

towardsdatascience.com](/data-visualization-with-python-8bc988e44f22)

最初发表于:

*Resources:
[https://numpy.org/](https://numpy.org/)
[https://numpy.org/doc/stable/](https://numpy.org/doc/stable/)*
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值