TowardsDataScience 博客中文翻译 2021(二百一十七)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

数据科学、意义和多样性

原文:https://towardsdatascience.com/data-science-meaning-and-diversity-bb842602e55d?source=collection_archive---------24-----------------------

思想和理论

更好地做数据科学的认知谦逊和立场理论

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

图片来自 PublicDomainPictures 来自 Pixabay

数据科学基本上是关于数据的科学。它试图通过研究数据来产生关于世界的可操作的知识。所谓“可操作的知识”,我指的是可以被其他研究人员和政策制定者用来继续推进社会如何与世界互动和理解自身的知识。因此,我假设科学调查通常寻求产生可以采取行动的知识。然而,我们在数据科学背景下处理数据的方式将影响分析是否会产生与现实世界相关的可操作知识。在这篇文章中,我为立场理论提出的认知谦逊多样性的必要性进行辩护,因为数据有助于实践科学知识。

这个职位的结构如下。在第一部分,我介绍了数据的四个特征,因为它与整个科学相关。这四个特性回答了以下问题:什么使数据有意义?然后,我详细阐述了数据科学中出现的四个特征。在第二节中,我阐述了提供四个特征的数据所固有的三个问题。在第三节中,我介绍了认知谦逊立场理论作为缓解已发现问题的工具。在第四部分,我为支撑这篇文章的两个假设辩护:(1)多学科性可能是有问题的,以及(2)数据既与科学期望有关又与代表现象的有关。

1.数据科学中的数据

在之前的一篇文章中,我指出了数据的四个特征,它们可以使数据变得有意义:

  1. **解释:**数据通过被解释而具有意义——没有独立于思想的数据(在我对数据的描述中);
  2. **具体化:**对于数据的解释,它们必须采取某种“有形”的形式——这可能是. jpg 文档、笔记本上的涂鸦、墙上的砖块……——以便进行分析和操作;
  3. **背景:**了解数据点需要我们关注它们如何与数据集内甚至数据集外的其他数据点互动——了解某个社区的人均收入相对较低,与关注其居民如何受到制度性种族主义的影响截然不同(例如:Razai 等人,2021);和
  4. **元数据:**这些是用更容易理解的语言表达的关于数据的信息,同时也提供了关于数据本身的更多细节——例如,收集日期、原始格式、文件大小等等。

这四个特征的目标是让数据在科学中发挥有用的作用。“有意义”的要求回应了一种对科学的解释,即科学寻求更好地理解世界,而不是为了理解世界,而是帮助人类更好地与他人和环境互动。虽然科学研究确实可以回应不太值得称赞的愿望,但科学通常会促进人类知识,因此可以改善人类生计。

在数据科学的背景下,这四个特征受到审查,但提出的问题可能与其他学科不太相关。

例如,数据科学中的解释提出了一个重要的问题:谁来解释?虽然科学很容易更广泛地回答这个问题——是研究团队解释数据——但数据科学通常是多学科的努力。数据科学家通常是我所谓的多学科认知团体的一部分(更多关于 MEGs 这里)。在这些小组中,数据科学家与其他领域的专家合作,这些专家在大数据分析方面知识较少。相反,数据科学家不知道如何充分利用其他领域的理论基础。为此,数据的解释由数据科学团队和他们所从事领域的专家(我们称之为其他领域的专家)共同提供。这是假设两个团队都有大量的专业知识,并且两者之间没有太多的重叠。考虑到这一限制(这一假设在大量数据科学工作中并不成立),其他领域的专家会对他们提供给数据科学家的“原始数据”进行解释。其他领域的专家对原始数据进行分类、标记等等——他们在这方面更有经验。然后,数据科学家“清洗”数据,并将其标准化,以对其进行计算、数学和统计分析。一旦完成,他们就向其他领域的专家返回一种新形式的数据——带有进一步的见解。其他领域的专家提供了一个新的解释层,因为他们将新的见解整合到他们领域的理论框架中。

数据的物化在数据科学中是一个至关重要的方面,因为必须收集数据并将其物化用于计算分析。事实上,数据科学与计算工具一起工作,这些工具可能要求数据采用特定格式并满足其他标准。数据科学项目中提出的问题还要求数据符合特定的规范。考虑到这一点,在数据科学的背景下,我将数据理解为可量化的信息单位。数据是从世界中提取的信息,是由其他领域的专家“收集”的,并且为了他们通过定量方法进行分析的目的而提取的。对于数据科学家来说,当数据是可量化的,并且可能只具有数学特征时,它们就被物化了。这对数据科学如何理解数据的背景产生了影响。

数据的上下文由于数据科学工具和方法的性质而丢失。这可能是一个大胆的主张,但它承认了数据收集后的数据争论过程的重要性。数据必须被处理以满足计算方法的标准。考虑对一个国家的人口普查的研究,其中个人根据性别、年龄、年收入等类别成为价值。应用于人口普查的数据科学除了提供一些与平均值的比较之外,对任何一个人都没有什么有意义的说法,但是数据科学从来没有告诉我们人们的身份。这没有问题——人口普查不应该为人口中的个人提供深刻的见解——但它确实突出了数据科学家研究的数据和它们产生的背景之间的距离(艾伦图灵研究所数据女权主义 的作者对此做了更多的说明)。火上浇油的是,数据科学方法和工具的设计甚至不需要依赖于“真实”数据的收集。创建此类工具的现代方法依赖于所谓的“合成数据”。合成数据相当于包含我们在“真实数据”中期望的某些特征的数据。合成数据有助于人工智能系统和机器学习模型弥补数据量不足或难以匿名的数据。简而言之,合成数据是通过反映出现在“真实数据”中的单个(“不真实”)数据点参数而产生的人工产物。当综合分析时,合成数据反映了与我们在“真实数据”中发现的类似的那些参数的分布。我不想再深入研究合成数据(即使我尝试了,我也做不到),但提到它只是为了强调,数据科学可以处理真正抽象和脱离上下文的数据。

元数据可能为数据科学提供一个克服去上下文化问题的机会。毕竟,元数据是关于被分析数据的数据。然而,元数据通常仅限于描述数据点的输入日期、大小、格式等等。理论上,元数据可以提供背景——我甚至建议元数据可以包括关于项目伦理考虑的信息。数据科学中数据物化的特殊形式也强调了元数据的重要性(这里的是我试图以一种创造性的方式阐明这一点)。

2.数据科学中的数据问题

数据科学中数据的上述四个特征对该领域提出了三个挑战。简单概括一下:

  1. 多学科问题与数据科学家需要与其他领域的专家合作有关,反之亦然。由于各自在各自领域的专业程度不同,两人都无法完全理解对方对数据的看法;
  2. 抽象问题出现在需要清理的数据中,以便适合数据科学家使用的工具;和
  3. 与此相关的去语境化问题来自数据的数学化,否则这些数据可能对更广泛的公众有意义。

这些问题都错综复杂地联系在一起。考虑到数据科学方法和工具日益专业化和复杂化。这意味着更少的其他领域的专家可以参与其中,因此多学科问题恶化了,数据被进一步抽象和操纵以用于日益复杂的工具,并且它们的上下文被留得更加混乱。

这里最大的问题是数据科学研究的东西——数据——与我们期望科学帮助我们理解的现实脱节。我称之为数据科学的本体论问题(并希望在其他地方写这个问题)。为了部分克服这一点以及上述三个问题,我现在介绍对更准确的科学交流和数据“锚定”的需要。

3.在数据科学中求解数据

我们已经看到,元数据作为数据的一种特性,可能会为数据科学家分析的数据提供急需的上下文。然而,元数据通常只有知道在哪里可以找到它们的科学家同事才能访问。元数据也不经常以我上面建议的方式使用。他们的潜力往往得不到利用。

克服一些问题的另一种方法是通过提高数据科学所能实现的透明度。我们可以称之为“认知谦逊”;粗略地说,承认数据科学的局限性。这可以通过三种相互关联的方式表现出来。首先,数据科学可以承认他们分析的数据的特别抽象的本质。这可以帮助数据科学家更清楚地传达他们的发现属于抽象概念,而不是世界上更有形的现象。这有助于数据科学中认知谦逊的第二种形式:范围限制。目前,数据科学被视为在所有领域推进人类知识的全能工具。虽然这有一定的道理,但交流其发现的抽象性质可以帮助其他领域的专家更加谨慎地对待数据科学——数据科学最终不是银弹。第三,在多学科合作中对自己的专业知识更加谦逊,可以让其他领域的专家对自己的分析更加自信。这种合作中的解释阶段(如第 1 节中所介绍的)必须与相应的专家坐在一起,如果他们没有在彼此的学科中受过训练的话。虽然对话对于理解其他领域专家提出的科学问题是必要的,但当数据科学家展示他们的发现时,对彼此专业知识的大量信任也是必要的,而这种信任最好来自谦逊的立场。

对这三个问题的另一个解决方案是我所说的“锚定”。锚定可以说是数据再次被语境化和“非抽象”的过程。锚定的要点是让数据科学家将他们分析的数据视为更常见的突出现实的参考。锚定是记住数据是更重要的世界和经历的抽象。从某种意义上来说,“重新语境化”和“去抽象”你没有完全抓住这里正在发生的事情。让我们后退一步。

最终,数据是世界上各种现象的表示(正如前面提到的,合成数据不是这种情况)。它们以某种方式从世界中提取出来,然后抽象成可量化的信息单位,以供分析之用。锚定归结为承认这个过程留给我们的数据是“唯一的”表示。锚定的过程是关于记住数据代表什么;它允许数据科学家在分析时考虑周全。这种更多的考虑,反过来又考虑到了我们在讨论更透明的科学交流时已经描述过的好处。

我所说的锚定的意义是受女权主义认识论的启发。女权主义认识论的一个分支是 T2 立场理论。简而言之,立场论无意为这个丰富的哲学领域提供注释,而是试图为那些传统上被边缘化的人提供一个声音。立场理论承认,对世界有大量的理解是科学探究中所没有的。这正是因为边缘化。然而,这并不是说任何在社会中被边缘化的人都可以因为他们被边缘化而获得有科学价值的知识。必须让科学界听到被边缘化的声音,这些声音来自于那些了解到自己被压迫的处境、了解到塑造了他们的生活和世界观的不公正结构的人。为此,数据科学中的立场理论允许两种有用的转换。

首先,具有社会意识的边缘化声音可以重视他们分析的数据,因为这些数据在涉及他们的社区和生活经历时具有更多意义。例如,考虑一个科学项目,该项目分析关于特定边缘化群体的一些行为模式的数据。该项目将从与该社区的研究人员的合作中获益匪浅,这些研究人员已经意识到维持其社区边缘化地位的不公正的权力结构。突然之间,已经被抽象和量化的数据得到了更多的关注。如果不承认这一点的数据科学家进行分析,它们所代表的重要现象就失去了意义。

其次,同样重要的是,通过认识到数据科学在整个科学中日益增长的重要性,应该可以清楚地看到,在一个如此受理论驱动的世界中,数据科学拥有巨大的力量。人工智能、机器学习等成果融入了我们日常生活中使用的技术,这意味着数据科学在世界上占据了主导地位。数据科学有能力表现当前的不公正,并将其投射到未来。允许数据科学主要招募那些历史上拥有权力的人是错误的。事实上,女权主义认识论者让我们注意到系统的不公平,边缘化和歧视的表演性质。如果我们允许数据科学继续建立在不公正的假设上,并向那些使世界不公正永久化的不灵活的技术提供信息,很难想象数据科学能够提供多少知识来帮助我们更好地理解和参与我们的周围环境。

4.一些细微差别

到目前为止的想法总结如下:

  1. 当数据被解释、物化和语境化,以及用元数据澄清时,数据在科学中变得有用。
  2. 数据科学中的数据被从现实中提取成可量化的信息单元。
  3. 数据科学中的数据提出了多学科、抽象和去语境化的问题。
  4. 认知谦逊和立场理论强调了数据科学多样性的价值,因为它有助于克服这三个问题。

还有两个更深层的假设值得一提。首先,有一个多学科的问题,以及数据科学家和其他领域的专家是否真的没有共同的理解。第二,这意味着在整个文本中,数据“仅仅”是现实的代表,而不是任何更有意义的东西。

在多学科问题上,我确实提供了一个过度简化的例子。然而,值得澄清的是,这样做并不是为了削弱数据科学家或其他领域专家的专业知识。这一假设来自于科学社会学文献,这些文献清楚地表明,学术人员和研究人员在培训中需要将专业知识置于知识广度之上(见,Poteete et al ., 2010 )。当然,这并不包括那些拥有数据科学以外的某个领域的背景,然后接受数据科学方法和工具培训的研究人员。就这一点而言,我必须说,在我看来,数据科学上升到了它自己的一个领域,而不是一个人在前进的道路上获得的一套工具和方法。不过,现在我必须澄清,这并不是贬低那些在其他领域接受广泛培训后成为专家、数据科学家的人。然而,我将坚持这一立场,即这些特殊的研究人员在他们的训练中是跨学科的,因此在他们的工作中也是跨学科的。在这篇文章中,当谈到“数据科学家”时,我并没有想到他们。最后,为了推进本文的论点,我有必要确定一些多学科的基本概念。对于社会学家和科学哲学家来说,探索数据科学中多学科、跨学科和跨学科的精确本质仍然是一个有趣的问题。

关于我引用数据的方式,这与莱奥内利的( 2016a ) 关系账户相差不远,其中数据的“可移植性”和“重要性”是突出的方面(参见莱奥内利、 2016b )。通过这个账户,数据也被收集,期望成为关于世界的主张的证据(同上 : 197)。然而,我把数据说成是“代表”现象,莱昂内利认为这是不同的、代表账户。根据这种说法,实质性。比如说,jpg 格式是一种特征,而不是数据的核心价值。根据代表性的说法,数据在整个时间和空间中都有意义,因为它们涉及世界上的现象,不管它们的格式如何。然而,莱昂内利解释说,这种解释是有问题的,因为它限制了数据可以引用的内容。的确,它们只能代表个别现象。在数据科学的世界里,这是不成立的,数据是通过科学模型抽象和分析的,而这些模型可能并不代表数据的初始现象。但是这种抽象正是我在这篇文章中所质疑的。也许我应该澄清一下,这个案例并不是为了避免将数据抽象到新模型 tout court 中,而是为了尽可能地承认数据的来源和表示价值。

5.结束的

这篇文章介绍了科学中的数据是有意义的,因为它有四个属性:解释、物化、语境化和元数据。与数据科学相关的这四个属性提出了多学科、抽象和脱离上下文的问题。我认为,一方面,这三个问题可以通过认知谦逊来解决;另一方面是多样性。相应地,认知上的谦逊相当于承认一个人专业知识的局限性;多样性是作为女权主义立场理论所规定的那种而引入的。然后探讨了两个强有力的假设:科学家专业知识的狭隘性,以及本文对数据的描述。正如社会学家和科学哲学家所研究的那样,专业知识的狭隘性是在学术基础设施的基础上得到辩护的。这篇文章对数据的描述后来被发现模糊了关系型和代表型描述之间的界限,但讨论有助于澄清我的总体主张:如果我们在寻求可操作的知识,承认数据科学中数据的来源和代表价值是重要的。

进一步阅读

关于认知谦逊,参见 Medina,J. (2013) 主动无知、认知他人和认知摩擦,DOI:10.1093/AC prof:oso/9780199929023 . 003 . 0001

关于立场理论,参见英特曼(2010) 25 年的女性主义经验主义和立场理论:我们现在在哪里?,DOI:10.1111/j . 1527–2001 . 2010 . 01138 . x

在多学科方面,我有一份不错的阅读清单——所有的我都有显然阅读——在我写硕士论文的地方的最上面,在“参考资料”部分:https://hackmd.io/IqPngF_XS1uDwDg50sE9Zw?view#Resources

谢谢大家!

乔纳森·舒尔特(Jonathan Schulte)令人沮丧的严谨的哲学输入——我期待你对数据的看法!
Maria Eriksson 的冗长聊天,并确保我不会被无端的认知傲慢冲昏头脑!
阿瑞尔·贝内特马尔维卡·莎兰的深刻而广泛的评论!

关于认知上的谦逊…

我花了很大的力气来写上面的内容。主要是因为我不是数据科学家,也因为数据科学提出了大量的问题,我简直无法理解。例如,这篇文章以前的版本提到了“作为本体论的数据科学”。可笑的事情比合成数据更让我困惑!(我希望我没有犯太大的错误,并且它对完全不属于数据科学的人是有用的)。

在艾伦图灵研究所,我周围都是才华横溢的人,他们在做着令人着迷的工作,但我可以看到,更广泛地说,数据科学作为解决方案的提供者是理所当然的。

我最近开玩笑说,科学进步越来越快,嗯,需要停下来闻闻花香。我想我实际上问的是数据科学家什么时候有机会接触科学哲学。或者科学哲学家如何更有意义地参与数据科学。

实际上,我想说的是:我希望你——已经看完了我的文章——感到有勇气去质疑传统的做事方式。听听关于在数据科学方面做得更好的专题讨论,看看关于的纪录片,看看人工智能和类似的东西对的反应,和比我知道得多的人交流!但也谢谢你。我真的很感谢你抽空过来!

数据科学。措施

原文:https://towardsdatascience.com/data-science-measures-213521b6a878?source=collection_archive---------24-----------------------

如何使用描述性统计来查看数据显示的内容

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

有很多工程师从未涉足统计学或数据科学领域。但是,为了构建数据科学管道或者将数据科学家产生的代码重写为适当的、易于维护的代码,工程方面会出现许多细微差别和误解。对于那些数据/ML 工程师和数据科学家新手,我做这个系列的帖子。我将尝试用简单的英语解释一些基本方法,并在此基础上解释一些数据科学的基本概念。

在统计学中,我们在我们的数据中看到的东西不是我们自己感兴趣的,而是评估它来自哪里(人口)。为了评估和描述特征,我们需要知道一些事情。首先是这些特性的值,这些值对于所研究的分布来说是典型的。其次,只要这些值是不同的(分散的),它们有多少是典型的这样的分布。

第一个任务是通过集中趋势的措施来解决的。第二个任务是通过测量变化来解决的。

集中趋势测量

为了研究集中趋势的各种措施,我们将创建数据,让它们以故事的形式出现。

想象一个场景,5 个人坐在一个酒吧里,收入 4 万。坐在酒吧里的人平均收入 4 万。

data = [40, 40, 40, 40, 40]

利用这些数据,我们现在将转向理论。

平均

概率论与随机变量的研究有关。为此,计算描述其行为的各种特征。随机变量的主要特征之一是均值(其他人也称之为数学期望或平均值),这是可用数据的一种平均值。

平均值给我们一个概括的估计,可以帮助我们做决定。例如,一家公司的平均收入给我们一个大概的估计,我们可以雇用多少新员工,一家餐馆的平均支票帮助我们决定是否去那里。

平均值是一个简单的度量,其公式如下:

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

其中 Xi——随机变量,pi——它们的概率

从公式中可以看出,随机变量的平均值是权重等于相应概率的值的加权和。

例如,如果您计算投掷两个骰子时点数之和的平均值,则得到数字 7。但是在这里,我们确切地知道所有可能的可接受值及其概率。如果没有这些信息呢?只有一些观察的结果。该怎么办呢?答案来自统计学,它允许我们得到一个平均值的近似值,从可用的数据中进行估计。

数理统计为估计平均值提供了几种选择。主要的一个是算术平均值,有一些有用的属性。例如,算术平均值是一个无偏估计,即平均期望等于估计期望。

因此,算术平均数是由任何学生都知道的公式计算出来的。

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

其中 Xi——随机变量,n——数值个数。

def mean(x):
    return sum(x) / len(x)mean(data)  # 40

这种方法的缺点是对样本中不同的偏差和异常值敏感,即容易受到严重偏离分布中心的异常值的显著扭曲。

如果任何其他人带着 4 万美元的收入来到我们想象的酒吧,酒吧里人们的平均收入将保持不变。

data1 = data + [40] 
mean(data1) # 40

如果杰夫·贝索斯走进一家收入为 100 亿美元的酒吧,酒吧的平均收入会上升到1700,尽管前 4 个人的收入没有变化。

data2 = data + [10000] 
mean(data2) # 1700

为了处理这个问题,还有其他集中趋势的度量:截尾均值,众数,中位数。

方式

另一个简单的方法。模式只是数据集中最常见的值。

可能有几种模式。而多模态的存在也是待观察数据的某种特征。这表明数据有一些内部结构,可能有一些子组在性质上彼此不同。也许不把这种分布作为一个整体来看是有意义的,而是把它分成小组,分别来看。

def mode(x):
    """returns a list, might be more than one mode"""
    counts = Counter(x)
    max_count = max(counts.values())
    return [x_i for x_i, count in counts.iteritems() if count == max_count]mode(data)  # [40]

Mode 对于定性变量是必不可少的,对于定量变量用处不大。它还帮助我们估计数据样本的最典型的值。

中位数

中心趋势不仅可以被认为是具有零总偏差(算术平均值)或最大频率(模式)的值,还可以被认为是将有序数据分成两个相等部分的某个标记(分析特征的某个水平)。也就是说,它的值中有一半的初始数据小于这个标志,另一半大于这个标志。这是中值

众数和中位数是重要的衡量指标,它们反映了数据结构,有时用来代替算术平均值。

def median(v):
    """finds the 'middle-most' value of v"""
    n = len(v)
    sorted_v = sorted(v)
    midpoint = n // 2
    if n % 2 == 1:
        # if odd, return the middle value
        return sorted_v[midpoint]
    else:
        # if even, return the average of the middle values
        lo = midpoint - 1
        hi = midpoint
        return (sorted_v[lo] + sorted_v[hi]) / 2

median(data)  # 40
median(data2)  # 40

显然,在对称分布中,将样本分成两半的中间点就在正中心,与均值和众数在同一位置。可以说,当众数、中位数和均值重合时,这是一种理想的情况。然而,生活并不像正态分布那样对称。

要了解数据采样特征是如何表现的,光知道均值是不够的,光知道这些特征的典型值是不够的,还需要知道它们的可变性。也就是说,我们不仅要知道什么是典型的,还要知道与平均值有多大的不同,与平均值不相似的值有多大的不同。为此,我们有变异的度量。

让我们回到我们想象的情况。假设我们现在有两个小节:

data1 = [40, 40, 40, 40, 40]
data2 = [80, 40, 15, 25, 40]mean(data1)  # 40
mean(data2)  # 40
median(data1)  # 40
median(data2)  # 40
mode(data1)  # [40]
mode(data2)  # [40]

他们看起来在我们所观察的特征上是相似的,但是数据实际上是不同的。

范围

最简单和最直接的可变性测量是范围。该范围是最小和最大特征值之间的距离。

def data_range(x):
    return max(x) - min(x)data_range(data1)  # 0
data_range(data2)  # 65

一方面,产品系列可以提供丰富的信息,非常有用。比如一个城市一套公寓的最高价和最低价之差,一个地区的最高工资和最低工资之差等等。另一方面,范围可以很大,没有实际意义。

这个度量显示了样本中的值有多大的变化,但是它并没有告诉我们关于分布本身的任何事情。

差异

如果平均值反映了随机值的中心,方差给出了的特征,数据围绕中心展开,并考虑了所有对象值的影响。

方差的公式如下:

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

其中 x —随机 variables,^x —平均值, n —数值个数。

对于每个值,我们将从平均值中提取一个偏差,将它们竖立在一个正方形中,然后除以样本中值的数量。

我们为什么要把它做成方形?

负变化和正变化之和为零,因为负变化和正变化相互抵消。为了避免这种相互抵消,使用分子中这种测度的平方。至于分母,我们用n除。然而,使用不同于 n 的值以不同的方式改进了估计。分母的总值消除了偏差。

def de_mean(x):
    """translate x by subtracting its mean (so the result has mean 0)"""
    x_bar = mean(x)
    return [x_i - x_bar for x_i in x]def sum_of_squares(y):
    """the total squared variation of y_i's from their mean"""
    return sum(v ** 2 for v in de_mean(y))def variance(x):
    """assumes x has at least two elements"""
    n = len(x)
    deviations = de_mean(x)
    return sum_of_squares(deviations) / (n - 1)variance(data1)  # 0
variance(data1)  # 612

因此,我们考虑了每一个偏差,总和除以对象的数量给出了可变性的估计。

这里有什么问题?

我们平方的事实给了我们测量的倍数增加。也就是说,如果在第一种情况下,我们的工资是以美元,以千美元为单位,那么当我们平方它时,我们就开始以百万甚至数十亿美元为单位进行操作。这使得关于组织中的人获得的具体工资的信息变得更少。

标准偏差

把方差回归现实,也就是把它用在更实际的用途上,从中提取平方根。就是所谓的标准差

这就是公式:

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

def standard_deviation(x):
    return math.sqrt(variance(x))standard_deviation(data1)  # 0
standard_deviation(data2)  # 24.7

标准差也是可变性测量的特征,但现在(与方差相反)它可以与原始数据进行比较,因为它们具有相同的测量单位(这从计算公式中可以清楚地看出)。

例如,的三西格马规则指出,正态分布的数据在平均值的 3 个标准偏差内有 997 个值。标准差作为一种不确定性的度量,也涉及到许多统计计算。它可以用来确定各种估计和预测的准确性。如果偏差非常大,那么标准差也会很大,因此预测也会不准确,这将表现为,例如,非常宽的置信区间。

结论

这些是数据工程师应该知道的基本度量,但不是全部。它们将在本系列的下一部分中使用,其中将引入一些新的度量。

感谢您的阅读!

有什么问题吗?请在下面留下您的评论,开始精彩的讨论!

查看我的博客或者来打个招呼👋在 Twitter 或订阅我的电报频道。规划好自己!

数据科学将基础设施视为代码

原文:https://towardsdatascience.com/data-science-meets-infrastructure-as-code-d2f62328646c?source=collection_archive---------48-----------------------

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

奥斯卡·伊尔迪兹在 Unsplash 上拍摄的照片

使用软件工程的最佳实践,数据科学功能集成的最新发展为许多数据科学家带来了 Docker、Jenkins、REST APIs 等工具的知识,尽管这些知识使他们中的大多数能够部署他们的数据科学项目,为他们所插入的业务增加价值,但当项目在本地构建,然后被重新考虑部署到云中时,会有一些警告和妥协。

意识到这些警告,我撰写本文的主要目的是将数据科学知识(及其工具)与基础设施(如 Packer 和 Terraform 等代码工具)相结合,以确保创建一个数据科学环境,帮助同时使用 R 和 Python 的用户在云中调配基础设施,并利用许多大数据工具(如 AWS EMR)来分析和处理大量数据。

尽管本文是使用 AWS 堆栈创建的(由于整个基础设施超出了 AWS 免费层,因此可能会产生成本),但它也可以用于其他云提供商,只需对打包映像创建和部署机器的 Terraform 进行适当的修改。这项工作的进一步更新应该会为项目带来对更多云的支持。

TL;速度三角形定位法(dead reckoning)

这个项目(在 Github 中可用)的主要目标是创建一套工具,允许使用 Packer 和 Terraform 部署数据科学堆栈。它包括以下基础设施:

  • 创建一个 packer 映像,其中 JupyterHub 托管在端口 8000 中,RStudio 服务器托管在端口 8787 中,这个 Packer 映像的结果将是一个 Amazon 机器映像,可以在将来多次使用。
  • 创建 VPC 和必要的子网,以确保堆栈所需的所有基础架构都可用。
  • 最后,当所有这些都创建好后,目标将是在 EC2 实例中部署这两个服务(JupyterHub 和 RStudio Server)。

构建要使用的自定义图像

通过使用 Packer 和创建要在任何云中部署的定制机器映像来利用映像的定制,我们还使用 Ansible 来创建行动手册,以允许定制应该在机器中安装什么。通过使用单个源创建这个映像,并指定添加到机器映像中的许多特性,我们可以确保一旦构建了映像,它将在其整个生命周期中保持不变,这意味着安装在机器上的任何包和依赖项都不应在其日常使用中进行更新。

这使得用户,无论是数据科学家还是数据分析师,都可以确信一旦一个项目建立在一个定制的 AMI 之上,任何依赖关系都不会随着时间而改变。当用户自己使用依赖项管理器,比如 R 的 Renv ,或者使用 Python 的环境中的 requirements.txt 时,这种再现性特性也可以得到增强。

可以定制映像的创建来添加或删除特性,比如安装或不安装 RStudio Server,或者部署安装或不安装 Anaconda 的映像,在 Packer 和 Ansible 最终构建 AMI 之后,它将可以多次使用。

这个项目正在构建的 AMI 主要关注 RStudio 服务器的安装和配置,以及带有 conda 的 Jupyterhub。

使用自定义图像

许多用户在开始使用云提供商部署强大的机器来训练模型或分析大量数据时,并不使用允许以可再生和可扩展的方式提供这种基础架构的工具(很多时候,这些资源最终会在月底形成一大笔云账单)。这就是 Terraform 出现的原因,因为它帮助用户使用代码部署定制的基础架构,并在工作完成后销毁相同的基础架构。

这个项目的 terraform 模块包含一个简化版本的基础设施,但与 Packer 一样,如果需要,用户可以添加更多的模块。安全模块控制将使用自定义 AMI 部署的机器使用的入口和出口端口,而网络模块控制机器将使用的网络和网关,IAM 设置该机器在云提供商中可以拥有的权限,EC2 模块实际部署机器。

Terraform 带来的许多优势,以及它对基础设施作为代码的定位,允许使用 Git 跟踪基础设施随时间的变化。在 Terraform 部署结束时,用户将拥有机器的 IP 地址,因此它可以连接并使用其资源(以及 Packer 先前安装的应用程序)、托管在端口 8787 中的 RStudio 服务器和端口 8000 中的 Jupyterhub(这些端口先前在安全组模块中是允许的)。

进一步发展

尽管这个项目本身可以作为一个可以轻松部署到云的数据科学堆栈,但我们也可以将这个自定义 AMI 用于 EMR 集群,从而加快其配置,因为我们可以取消一些通常在集群配置的引导步骤中执行的安装。

此外,这并不取代任何允许数据探索和模型创建以及部署的数据科学堆栈的正式和官方版本,如 Sagemaker、Google AI Platform 或 Azure Data Studio,而是这些解决方案的替代方案,因为它允许用户完全定制他们需要的东西,并将其部署在他们想要的任何云中。

数据科学需要重构、教程、案例研究、技巧和诀窍

原文:https://towardsdatascience.com/data-science-needs-refactoring-a-tutorial-case-study-tips-tricks-8fff8f38acbb?source=collection_archive---------60-----------------------

实践教程

放慢速度会让你更快,方法如下

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

你也可以很快!确保你重构了…照片由莎莉·法约米Unsplash 上拍摄

TLDR

如果你引入了写得很差的代码,并且没有重构你的工作,不管你是否意识到,你都在无形中减慢你自己的速度,让你的生活更加艰难。重构是有趣的,它让你的代码更快,让你写代码更快,你写的代码更容易维护,一旦你不得不清理干净,它帮助你在第一时间写出更好的代码。

技术债务是一种无形的粘合剂,随着你每一次未经检查的提交,你的代码库就会增加更多的技术债务,你的进展最终会停滞不前。每次都是这样,不管你有多努力去逃避。

学习重构从学习如何在不改变输出的情况下重写现有代码开始,但是要提高代码的易读性、性能、简单性、可维护性或者以上的任何组合。“一次写得很差,以后再也没碰过代码”和仅仅重构过一次的代码之间的区别,使你的软件在质量和易扩展性上从 a 2 级变成了 a 7 级。每个人(包括几天后你遇到自己以前写的代码时的自己)都会因此而喜欢你。

如果你计划花几天时间开发一个软件,重构需要成为你故事的一部分。如果你花了几个小时写了一个脚本,然后就扔掉了,这是一个警告,你可以放心大胆地写代码,自由自在地生活。看看你以前写的一个小脚本,并借鉴其中的一些重构技巧,这可能是一个有趣的练习!

让我们开始吧…

什么是重构

比我聪明的人已经为我们定义了这一点,请看下面马丁·福勒的至理名言。

一种规范的技术,用于重组现有的代码体,改变其内部结构而不改变其外部行为

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

照片由 Shifaaz shamoonUnsplash 上拍摄

介绍

重构是一个不受欢迎的习惯,它永远会带来回报,我希望有更多的数据科学投资者将它纳入他们的编程习惯组合中。这是任何优秀软件工程师的习惯,但在数据从业者的世界中并不经常出现,我想改变这一点,从这篇博客开始。

前几周,通过做一些简单的重构(我将在下面带您看一下),性能提高了 113 倍,将数据管道处理时间从大约 84 小时减少到 45 分钟

这并不是说你的代码会变得多快,这仅仅是我的经验,我觉得这是一个值得分享的故事。

这也是用一个小时左右的简单工作完成的。仍有改进的空间,不知道能快多少。重构对你的代码的影响可能是更多数量级的代码改进,或者你可能没有性能问题,只是在阅读你上周写的东西时有一个头疼的问题。重构通常对两者都有帮助。

限制

我想指出的是,这是一个穷人版的 Raymond Hettingers talk(底部链接)的弗兰肯斯坦博客,一个案例研究,一个教程和我漫无边际的想法。Raymond 的演讲让我对重构和解决问题的体验从一件苦差事变成了一种爱好。我在这一页末尾的“比我聪明得多的人”部分记下了他的讲话。请去观看并在 twitter 上关注他,他是核心 python 开发团队的一部分,他在这个星球上投入了大量的智慧和爱,他需要不惜一切代价得到保护。

我声称速度提高了 113 倍,这与我前几周在工作中为一位同事重写函数的经历有关,当然,这与重构对您的情况有多大帮助没有关系。我也用 python 写所有东西,所以我的风格、行为和建议偏向于 python 和熊猫。

球赛

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

照片由 CHUTTERSNAPUnsplash 上拍摄

从杰瑞米·霍华德和雷切尔·托马斯以及他们的教学风格中汲取灵感,而不是从基础和建设开始,重要的是首先看到最终结果,这样就有一个明显的结果来努力。在教我怎么踢球之前,先给我看一场 AFL 的比赛。

然后,我们可以分解实现目标的思路、步骤和工作,以及为什么这一过程如此重要。

我们案例研究的目标

因此,我们的情况涉及两个数据帧的样本:

  • 参考数据集:包含主数据集中某个要素的信息、其条柱和我们关心的特殊值。

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

一些参考值

  • 主数据集:我们需要放入参考箱中的值,并将幻值附加到这些箱中的值。

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

一些主要价值观

因此,对于主数据集中每个要素的每个观测值,参考数据集中都会有一组条目,其中包含要将这些主数据集值放入其中的条柱以及该条柱的相应特殊值。我们的目标是将每个主数据集条目连接到一个 bin,然后这个 bin 再连接到我们的特殊值,然后让所有这些都可以在主数据集中使用。

请注意,我们只显示了单个变量的解决方案,但是通过将我们的解决方案打包成一个循环等方式,解决 1 个特征会解决 n 个特征。

下面是我们期待的最终结果

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

最后会是这个样子

既然我们已经有了既定的最终目标,现在让我们看看代码…

代码

参见下面的 3 个要点,第一个是设置虚拟数据帧,第二个是花了大约 85 个小时在完整数据集上运行的旧代码,第三个要点是产生相同输出的重构重写。第二个要点用于大约 3000 个特征,几百万行花费了大约 85 个小时。这是我们正在研究的样本的替代品。我们将使用模拟样本,但变化仍然是一样的。我还加入了一些关于我不喜欢的错误的评论,以及为什么我认为重构的代码行更好管理的原因。

我们将针对最简单的情况(一个要素)来解决这个问题,然后可以针对主数据集中存在的尽可能多的要素进行循环/扩展。我发现在解决一个问题时,解决最简单和最小的方向跳跃是有效的,然后慢慢扩展和迭代到你的结果。

设置数据帧代码

上述内容不言自明,您可以看到引用数据帧为 ref_df,主数据帧为 main_df,我们在上面有截图示例。

可怕的老方法

这是我们可怕的原始方法,我前几周研究过。花点时间想想你是否能理解它,或者作者是如何试图实现我们的既定目标的。不要担心它是否令人尴尬或难以理解,它是,它是。我们将从头开始重写这个问题,并讨论如果我们坚持使用当前形式的方法,我们可以就地修改代码的方法。你会注意到我在代码的右边写了 sins 作为注释。

漂亮干净的 10 号内胆!

这是实现相同目标的最后 10 艘班轮。我已经在上面几行的右边加入了一些行为,这些行为是我比较这个要点和旧的代码要点时喜欢的。

另外,如果你想了解这 10 条线背后的想法,可以看看这个 colab 笔记本。见下文,我也把它放在了我的参考资料的末尾。

https://colab.research.google.com/github/nglillywhite/blog_resources/blob/main/Refactoring Resources-checkpoint.ipynb

那么我们如何从第二个要点转向第三个要点呢?!乍一看,这似乎是一个巨大的飞跃,中间没有故事,但我保证魔术中有简单。

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

乔尔·穆尼斯在 Unsplash 上拍摄的照片

分解问题

所有的程序和问题通常都可以分解成输入、对这些输入的处理和一些输出。在问题解决和重构的开始设置阶段是一个很好的方法,可以让你理清思路,提炼手头的问题。让我们在案例研究中快速完成,因为这将揭示我们在几行代码中采取的步骤。

一旦你把一个问题分解成简单的输入、输出和中间的步骤,你就可以逐步完成每一步并到达你的目的地。试图同时做每件事太难了,而且你也没有足够的心智记录来做这件事(提示:看看雷蒙德的精彩演讲,他谈到了心智记录和你脆弱的人类思维极限)

输入

  • 参考数据框架
  • 主数据框

处理

  1. 创建箱子|第 1–4 行
  2. 将容器添加到参考数据框|第 6–8 行
  3. 将箱子添加到主数据框|第 10–12 行
  4. 合并 bin 类别上的数据集。第 14 行

输出

  • 单个数据帧,其参考特殊值与入库的参考值相关联

思维模式和行为

这比试图吃掉呈现给我们的原始方法要容易管理得多。有了上面的参考,我可以更清楚地解决我头脑中的问题,而不是试图解释原来的方法和实现。如果你觉得游戏,开始单元测试,并再次提炼你的代码,以进一步改善你重新写的东西。

一遍又一遍地这样做来提炼和提炼你的代码,本质上就是重构。只要你提高了易读性、性能、简单性或易用性,那么你就在正确的道路上。代码被阅读的次数比它被编写的次数多,所以要为读者而不是你这个作者进行优化。要有同理心,因为你可能会在一周内读到它,但你已经忘了你是在第一时间写的。

迭代和调整

最好的起点是对代码进行小的但是有方向的改进。这可以带来任何好处,例如易读性、简单性、简洁性、使用库而不是手写过程等。让我们看看下面的一个小例子。查看第 1–5 行和第 7–11 行,它们是来自原始大型方法的相同代码片段的原始版本和重构版本。

1–5 是原始代码| 7–11 是我们的修改版本。发现差异!

我将在下面快速列出这些变化:

  • " out_val =" → "return out_val "
  • " if PD . ISNA(x)= = True:“→” if PD . ISNA(my _ df):"
  • x → my_df
  • 改进的注释

这些都很好,原因如下:

  1. 向读者发出信号,这是期望的输出&一旦找到所需的值就返回函数,而不是继续计算不需要的代码
  2. 如果你能用更少的代码做同样的事情(removing = = True ),那就去做吧!Python 有一种“真”和“假”的行为,这种行为造就了像这样干净的语法。如果对您来说是新的,请阅读该堆栈溢出以了解更多信息。
  3. 使用更好的变量名,my_df 并不完美,但它至少表明了数据类型。“x”是如此的不明确,我必须找到声明或者调试它,才能知道这个变量是什么数据类型。
  4. 写一个注释,意思是如果我不想读代码,我可以不读。我的评论并不完美,但它比之前的评论更好。

所以我知道以上是一点点的区别,但也有一些微妙的改进。像这样的小调整可能感觉不到神奇或强大,但是当你迭代、迭代、迭代同一个片段,并将其浓缩成一些东西时,它通常是非常好的代码!我们还没有达到上面的例子,但我想展示一小部分。

拆除策略

这是一个完全重写的例子,其中没有考虑旧的代码,通过分解问题并回归基础,构建了一个全新的解决方案。有时候,如果你正在处理一个你有信心解决的问题,那么拆除现有的东西并重新开始会更快。要小心,因为这通常不是最好的途径,通常有人已经对他们写的东西进行了长时间的思考,值得花时间了解在你之前的人和他们的想法。然而,在这种情况下,有太多的花园路径要走,对于一个问题来说太复杂了,当你后退一步,实际上是非常简单的,并会受益于重写。

尝试一下,跟着做

去看看 colab 笔记本,看看我是如何完成这个解决方案并产生第二个要点的。如果你想知道如果我没有足够的勇气从头开始写它,并试图在代码质量上做出方向性的改进,我会如何修改原来的方法,请继续阅读。

重构技巧和诀窍

参考最初的方法,让我们看看这些小错误,当它们加在一起时,会使代码难以理解、缓慢且难以更改或维护。我还将公布如何解决这些问题。我弹出了一张截图,后面是我发现的一些罪恶。

看到什么了吗?你认为应该改变什么?

  1. 编写有用的方法和变量名,它们应该简短、易记且信息丰富。“x”不是一个好的变量名…
  2. 为你的方法写 docstring,我喜欢谷歌的 docstring 风格,它包括参数和清晰的缩进等。文档字符串是大多数 autodoc 工具的动力,如 Sphinx 。“他们也停电了??"jupyter 笔记本中的魔法命令,当你想偷看一个你想使用的方法时非常有用。第 7 行以后没有 docstring,这个方法如此复杂,当然需要一个。这种方法不包括。
  3. 在适当的范围内使用变量。如果您发现自己到处都在编写全局变量并引用代码库其他部分的变量。尝试重构和封装您的代码,以便相关的数据片段靠近需要它们的功能。否则,您可能会有杂乱的代码和混杂的变量,您不知道它们是如何在其他地方或被其他函数使用的。该方法不必要地使用了全局变量。

少可以多

  1. 让事情尽可能简单,如果你不必写一些东西来达到同样的效果,就不要写,除非它增加了上下文或者不清楚的信息。

一次做一件事。

  1. 一次做一件事。上面这条线太多了。根据“START”列调用 pd.isnull,然后根据该数据帧的输出提取“my_var ”,然后提取第一行的 iloc。这在一行中太多了,为了可读性,可以分成多行。玩 codegolf 如果你想写复杂的一行程序解决方案,通过写他们喜欢读的简单代码行来让你的同事们省心。

out_val 赋值 3 次,只返回一次。如果你有你的值,返回你的函数。

  1. 如果可以的话,尽早从一个函数中返回,这样可以通知读者并且更快。如果你已经在一个方法中找到了你的答案,并且不需要做更多的工作,直接返回。您可以在一个方法中编写多个 return 语句,遇到的第一个语句将从该方法/堆栈框架中退出代码执行,并且您不必继续处理已有的答案。这也让读者明白,这些语句是最终的,如果他们在查看特定的代码路径,他们可以停止读取并从该方法返回,但如果变量正在被赋值,他们必须不必要地继续读取代码,以便找到它最终返回的时间。

太多决定了!停下来想一想你是否写了这么多 if 语句

  1. **每种方法都应该做一件事,并且把这件事做好。**如果你发现自己编写了一个包含 5 个以上 if else 语句/决策点的方法,你很可能在这个方法中做了不止一件事,你应该将你的问题分解成几个不同的步骤。软件工程师通常称单一责任原则或 SRP 在这个场景中被违反。如果您想在一个方法中编排多个目标,请编写完成一件事情的多个函数并一起引用它们。深度嵌套的 if else 语句很难调试和理解。比起一个庞大的方法一次完成所有的事情,你最好写许多可以实现不同目标的方法,这些方法可以综合在一起。当你的方法超过 10-15 行时,开始流汗,重新思考你写的东西,以便更容易阅读。这条规则总有例外,但我敢打赌它是对的,而不是错的。

能不这样就不要这样。令人头痛的燃料

  1. 不要把一行代码写得太长,要分成 3 行以上才能读懂。你可能一次又一次地做了太多的事情,你可以把问题分解成步骤,并有清晰明确的步骤。它也非常非常难以阅读和理解,你已经给跟随你的每个人带来了头痛,通常是你自己。你不会真的想让自己头疼吧?当然也有例外,但在大多数情况下,多行代码通常不是好兆头。
  2. 几乎所有你想用数据做的事情都已经被构建到像 pandas 和 spark 这样出色的库中。如果没有必要,不要重写宁滨逻辑,熊猫比你想的要快得多,也聪明得多。上面的代码片段就是这样做的一个尝试,它比让熊猫做要慢几个数量级。维护起来也困难得多。

兰姆达斯是有目的的,不是这个。

  1. 兰姆达斯是善变和分裂的生物。非常有用和聪明,但一旦使用 lambda 锤子,许多程序员开始将所有东西与 map、filter 和 reduce 函数结合起来看,就像是 lambda 钉子。它们被定义为匿名函数,只使用一次,不会被再次引用。如果你发现自己传入指定的函数,并在 pd.apply 函数中做一些有趣的事情,比如 pd.apply,那么你会有惊人的创造力,但是你会让下一个看到你写的东西的人感到头疼。将你的问题简化成步骤,如果某件事需要做多次,创建循环/生成器来迭代。迭代器是很棒的东西,Raymond Hettinger 有很多关于这个主题的资源和讲座。

虽然这个评论在这种情况下是不言自明的,但它是一个很好的开始

  1. 最后,**在你的代码中为下一个人写一些有用的注释和参考,这样他们的生活就容易了。**以这段代码为例,我敢肯定它是在几个小时内匆忙写成的,但我花了很多时间写博客,自己对它进行了重构,你正在阅读这篇关于这段代码的博客,阅读这段代码的时间比写这段代码的时间要长得多。花在阅读和理解代码上的时间比花在编写代码上的时间要多得多,确保你为读者进行了优化。你可能会花更长的时间来写,但移情是一个很好的特质,代码是表达这种美德的散文。无论如何,你都会经常感谢自己,所以即使你很自私,这也是对你最有利的。

更多博客

我喜欢在这个博客中有什么有趣或无用的反馈和评论,以帮助推动进一步的写作。我正在考虑做一个关于单元测试的小教程,这会让重构变得更加有趣。你有一个测试工具来保护你的屁股,你有可证明的证据,给定相同的输入,你得到相同的输出。您可以编辑和重构自己喜欢的内容,因为您没有引入奇怪的行为。我对这篇文章中可能提出的任何想法都持开放态度,欢迎并鼓励任何评论。

要知道这只是解决问题的一种方式,你可以随意写下你自己对这个问题的解决方案,或者重写你对另一个问题的解决方案。我的解决方案甚至还有重构和缩减的空间。重构永远不会结束,总有办法简化、提炼、改进和精炼你的工作!

比我聪明的人&额外的资源

特别感谢科尔荣鼓励我开始写作。我总是感谢他的指导、鼓励、问题和同志情谊。我强烈推荐他的作品,这是很棒的东西,在很大程度上是我开始写博客的灵感。

这里有一个完整的跑步笔记本,如果你想看上面的要点和一些额外的评论,你可以参考:

https://colab.research.google.com/github/nglillywhite/blog_resources/blob/main/Refactoring Resources-checkpoint.ipynb

这是科林,我喜欢和他一起工作,我可能会永远缠着他要知识和陪伴

https://col-jung.medium.com/

这是 Raymond 的演讲,让我爱上了重构&让我用不同的方式思考解决问题。

这是乔尔,他是一个了不起的作家,他的顶级博客,如关于编码的博客,非常精彩。

https://www.joelonsoftware.com/

马丁·福勒是另一位我非常喜欢的伟大作家,他写了大量关于重构的文章

https://martinfowler.com/

这是他关于重构的页面!

https://refactoring.com/

杰瑞米·霍华德 & 雷切尔·托马斯是我的两个英雄,雷切尔在 fast.ai 深度学习程序员课程中鼓励每个人创建博客并开始写作,所以我也将这个博客的创建部分归功于她。我想把它们分享给每个人,因为它们很棒。他们制作了《T4》fast . ai 以及其他一些东西,非常棒。对于所有与伦理和实用神经网络相关的东西,去那里尽情享受他们制作的精彩内容。

https://www.fast.ai

r .区块链上的数据科学第一部分:阅读区块链

原文:https://towardsdatascience.com/data-science-on-blockchain-with-r-afaf09f7578c?source=collection_archive---------10-----------------------

数据科学家进入区块链的窗口。

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

密码朋克是 NFTs 的最早版本(www.larvalabs.com/cryptopunks)。图片由 https://commons.wikimedia.org/wiki/File:Cryptopunks.png 的修改而来。

Thomas de March in(pharm Alex 统计和数据科学高级经理)和 Milana Filatenkova(pharm Alex 统计和数据科学经理)

简介

什么是区块链: 区块链是一个不断增长的记录列表,称为块,它们使用加密技术链接在一起。它用于记录交易、跟踪资产以及在参与方之间建立信任。区块链主要以比特币和加密货币应用而闻名,现在几乎用于所有领域,包括供应链、医疗保健、物流、身份管理……数百个区块链存在,它们有自己的规范和应用:比特币、以太坊、Tezos……

***什么是 NFT:***不可替换的令牌用来表示唯一物品的所有权。他们让我们将艺术品、收藏品、甚至房地产等事物符号化。他们一次只能有一个官方所有者,并且他们受到区块链的保护,没有人可以修改所有权记录或复制/粘贴新的 NFT。你可能听说过艺术家皮普尔,他以 6900 万美元的价格卖出了他的一件 NFT 艺术品。

什么是 R: R 语言在统计学家和数据挖掘者中被广泛用于开发数据分析软件。

为什么在区块链做数据科学: 随着区块链技术的蓬勃发展,越来越需要能够阅读、理解和总结这类信息的工具和人员。

***什么是 API:***API 是一种软件中介,允许两个应用程序相互对话。API 旨在帮助开发人员向另一个软件发出请求(即下载信息),并以预定义的易读格式获得结果,而不必了解该软件的工作原理。

在 R 中已经有几篇关于区块链数据分析的文章,但是大部分集中在价格预测上。获取加密货币价格的数据非常简单,互联网上有许多数据库。但是如何真正读懂区块链呢?在这篇文章中,我们将重点阅读区块链交易。并非所有交易,但特别是与 NFTs 相关的交易。我们将阅读以太坊区块链,可能是用来交易非功能性交易的顶级场所。有几个市场可以作为 NFTs 的交易平台:OpenSea,Rarible……我们将在这里集中讨论 OpenSea,目前 NFT 最大的交易平台。

阅读区块链的原著是可能的,但是很难。首先,您必须设置一个节点并下载区块链的内容(在撰写本文时大约 7TB)。同步可能需要一段时间…其次,数据是按顺序存储的,这需要开发特定的工具来跟踪事务。第三,块的结构特别难读。例如,以太坊网络上的典型交易如下所示。每个块有 200 到 300 个事务,在编写本文时,我们处于块 12586122。

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

图 1:链中的每个块都包含一些数据和一个“哈希”,即使用加密技术从块中包含的数据生成的数字指纹。每个块还包括来自前一个块的散列。这成为用于创建较新块的散列的数据集的一部分,这就是块被组装成链的方式。图片来自 ig.com。

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

图 2:事务的结构。

幸运的是,有一些 API 可以方便我们的工作。

*# First, let's load a few useful packages*
**library**(tidyverse)
**library**(httr)
**library**(jsonlite)
**library**(scales)
**library**(waffle) #install.packages("waffle", repos = "[https://cinc.rud.is](https://cinc.rud.is)")
**library**(ggrepel)

OpenSea API

OpenSea 提供了一个 API,用于根据一组查询参数获取不可替换的 ERC721 资产。让我们来看看:

*# Retrieve sold NFTs* 
resOpenSea <- GET("https://api.opensea.io/api/v1/events",
          query = list(limit=300, *#number of events to retrieve*
                       event_type="successful", *#retrieve only the sales*
                       only_opensea="true")) *#retrieve only sales from the opensea website*

*# Convert the raw unicode (not human friendly) into JSON format* 
*# Don't forget the option flatten=TRUE, otherwise the objects will be a complex list of list of list, impossible to work with*
dataOpenSea <- fromJSON(rawToChar(resOpenSea$content), flatten=TRUE)[[1]] 

*# There are a lot of columns. We have to clean a bit.*
*# Let's start removing the one containing only NA values*
dataOpenSea <- dataOpenSea %>% 
  select_if(~!all(is.na(.)))

OpenSea 网站上并没有太多关于这个数据集内容的解释。因此,我选择了几个似乎包含有趣信息的专栏(至少是我能理解的)。

*# Let's select a few columns with interesting information*
dataOpenSea <- dataOpenSea %>% select("collection_slug", 
                                      "contract_address", 
                                      "id", "quantity", 
                                      "payment_token.name", 
                                      "total_price", 
                                      "seller.address", 
                                      "transaction.timestamp", 
                                      "winner_account.address", 
                                      "payment_token.usd_price", 
                                      "payment_token.eth_price", 
                                      "asset.asset_contract.schema_name") 
*#"asset.asset_contract.address", "asset.asset_contract.asset_contract_type", "asset.asset_contract.created_date", "asset.asset_contract.name"*

*# Get a glimpse of the data* 
glimpse(dataOpenSea)

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

我的猜测是——这里我们有:

  • collection_slug: 项目所属的集合
  • contract_address: 所有的销售都由一个合同(一段代码/一个软件)来管理,它将 NFT 发送给中标者。这是公海合同的地址。我们可以看到,所有销售只有一个地址,这意味着所有销售都由同一个合同管理。
  • id: 每笔交易的唯一标识符
  • **数量:**每笔交易售出的商品数量(参见下面的可替代/半可替代)。和在超市一样,你可以买 1 个苹果或者 20 个。
  • payment_token.name: 用于购买物品的加密货币。
  • total_price: 中奖者支付的费用。对乙醚来说,这是用乙醚的最小单位卫来表示的。1 以太= 10 亿魏(10
  • **卖家地址:**卖家的地址
  • **交易.时间戳:**交易的日期
  • winner_account.address: 买家地址
  • payment_token.usd_price: 用于以美元进行交易的代币价格

让我们来看看货币的分布:

dataOpenSea %>% 
  group_by(payment_token.name) %>% 
  summarise(n=n())

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

我们看到大多数销售是在乙醚中进行的(注意,包裹的乙醚可以被认为与乙醚相同),让我们在文章的其余部分重点关注这些乙醚销售。

*# Change the format of some columns to something more adapted than character*
dataOpenSea <- dataOpenSea %>% 
  mutate(quantity=as.numeric(quantity), 
         total_price=as.numeric(total_price), 
         transaction.timestamp=as.Date(transaction.timestamp), 
         payment_token.usd_price=as.numeric(payment_token.usd_price)) 

*# filter on sales in ETH*
dataOpenSea <- dataOpenSea %>% 
  filter(payment_token.name %**in**% c("Ether", "Wrapped Ether"))

*# Convert the price in Ether and then USD. We divide by the quantity as one sale can contain multiple items and then divide by 10^18 to convert the price from Wei to ETH (see above).*
dataOpenSea <- dataOpenSea %>% mutate(priceUSD = total_price / 10^18 * payment_token.usd_price / quantity)

*# Let's visualize this*
*# Histogram of the price distribution (with a log scale as prices are quite spread)*
pHistoOpenSea <- ggplot(dataOpenSea, aes(priceUSD)) + 
  geom_histogram() + 
  labs(x="Price (USD)") + 
  scale_x_log10(labels = comma)
ggsave("figures/histoOpenSea.png", pHistoOpenSea, height=7, width=7)
pHistoOpenSea*# Pie chart* 
dataOpenSea$cut <- cut(dataOpenSea$priceUSD, breaks = c(0, 10, 100, 1000, 10000, 100000, 1000000),
                       labels = c("0-10USD", "10-100USD", "100-1000USD", "1000-10000USD", "10000-100000USD", "100000-1000000USD"), include.lowest = TRUE)

dataPieChartOpenSea <- dataOpenSea %>% 
  group_by(cut) %>% 
  count() %>% 
  ungroup() %>% 
  mutate(percent=`n`/sum(`n`)) %>% 
  arrange(desc(cut)) %>%
  mutate(label=scales::percent(percent))

pPieChartOpenSea <- ggplot(dataPieChartOpenSea, aes(x="", y=percent, fill=cut))+
geom_bar(width = 1, stat = "identity") +
  coord_polar("y", start=0) +
  geom_text_repel(aes(y = cumsum(percent) - percent/2, label=label)) +
  theme_void()
ggsave("figures/pieChartOpenSea.png", pPieChartOpenSea, height=7, width=7)
pPieChartOpenSea*# Waffle chart*
pWaffleOpenSea <- waffle(dataPieChartOpenSea, rows = 8, reverse=TRUE)
ggsave("figures/waffleChartOpenSea.png", pWaffleOpenSea, height=5, width=7)
pWaffleOpenSea

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

图 3:每笔销售价格的直方图。来自 OpenSea API 的数据。

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

图 4:每笔销售价格的饼图。来自 OpenSea API 的数据。

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

图 5:每笔销售价格的华夫饼图表。来自 OpenSea API 的数据。

这看起来很好,但有一个很大的缺点… OpenSea API 限制事件的数量为最后 300 个事务。如果我们使用他们的 API,我们对此无能为力。此外,下载的交易是由 OpenSea 预处理的数据,而不是区块链本身。这已经是获得关于事务的信息的良好开端,但是如果我们想要读取块呢?我们之前已经看到,直接从区块链检索数据可能相当复杂。希望有像以太扫描这样的服务,让你以一种简单的方式探索以太坊街区。你猜怎么着?他们还开发了一个 API!

以太扫描 API

以太网扫描是一个块浏览器,它允许用户查看提交给以太坊区块链的交易信息,验证合同代码,可视化网络数据…因此我们可以用它来读取任何涉及 NFTs 的交易!EtherScan 在其免费版本中将事务数量限制为 10000,这比 OpenSea API 好得多,如果需要更多,您仍然可以订阅。

我们从哪里开始?我们再来关注一下 OpenSea:从上面提取的数据中,我们看到他们的合同地址是“0 x7be 8076 f 4 ea 4a 4 ad 08075 c 2508 e 481d 6 c 946d 12 b”。如果我们在以太网扫描中输入该地址,并过滤已完成的交易(即通过网络验证的交易,而不是等待批准的交易),https://etherscan.io/txs?a = 0 x7be 8076 f 4 ea 4a 4 ad 08075 c 2508 e 481 D6 c 946d 12 b,我们看到了不可思议的数量(撰写本文时为 848,965。)当然也不全是和销售有关的。

让我们看看我们能利用这些数据做些什么。

# EtherScan requires a token, have a look at their website
EtherScanAPIToken <- "Your token"*# Retrieve the last 10000 transactions (maximum allowed by Etherscan) from the OpenSea contract*
resEtherScan <- GET("https://api.etherscan.io/api",
          query = list(module="account", 
                       action="txlist", 
                       address="0x7Be8076f4EA4A4AD08075C2508e481d6C946D12b",
                       sort="desc",
                       apikey=EtherScanAPIToken))

*# Convert the raw unicode (not human friendly) into JSON format* 
*# Don't forget the option flatten=TRUE, otherwise the objects will be a complex list of list of list, impossible to work with*
dataEtherScan <- fromJSON(rawToChar(resEtherScan$content), flatten=TRUE)$result

dataEtherScan <- dataEtherScan %>% 
  mutate(value=as.numeric(value), *# Convert price in numeric*
         timeStamp=as.POSIXct(as.numeric(timeStamp), origin="1970-01-01")) *# Convert the timestamp to a date*

*# There are many transactions with a value of 0 ether. Among them, not all are directly linked to sales. We won't go into details here, but there are many other types of actions that can be recorded as transactions (publishing a sale, maintenance of the contract...). Among those that are linked to sales, some involve a token transfer (wrapped ETH for instance) instead of ether directly. To keep things simple, let's keep only transactions involving transfer of some ether.*
dataEtherScan <- dataEtherScan %>% 
  filter(value>0) 

*# Convert ETH price in USD*
*# For this, we first need to obtain the last USD price*
resEtherScanPrice <- GET("https://api.etherscan.io/api",
          query = list(module="stats", 
                       action="ethprice", 
                       apikey=EtherScanAPIToken))
dataEtherScanPrice <- fromJSON(rawToChar(resEtherScanPrice$content), flatten=TRUE)$result$ethusd %>% as.numeric()

dataEtherScan <- dataEtherScan %>%
  mutate(value=value/10^18) %>% *#We divide by 10^18 to convert the price from Wei to ETH (see above).* 
  mutate(priceUSD=value*dataEtherScanPrice) *# convert in USD* 

*# Let's visualize this*
*# Histogram of the price distribution (with a log scale as prices are quite spread)*
pHistoEtherScan <- ggplot(dataEtherScan, aes(priceUSD)) + 
  geom_histogram() + 
  labs(x="Price (USD)") + 
  scale_x_log10(labels = comma)
ggsave("figures/histoEtherScan.png", pHistoEtherScan, height=7, width=7)
pHistoEtherScan*# Pie chart*
dataEtherScan$cut <- cut(dataEtherScan$priceUSD, breaks = c(0, 10, 100, 1000, 10000, 100000, 1000000),
                       labels = c("0-10USD", "10-100USD", "100-1000USD", "1000-10000USD", "10000-100000USD", "100000-1000000USD"), include.lowest = TRUE)

dataPieChartEtherScan <- dataEtherScan %>% 
  group_by(cut) %>% 
  count() %>% 
  ungroup() %>% 
  mutate(percent=`n`/sum(`n`)) %>% 
  arrange(desc(cut)) %>%
  mutate(label=scales::percent(percent))

pPieChartEtherScan <- ggplot(dataPieChartEtherScan, aes(x="", y=percent, fill=cut)) +
geom_bar(width = 1, stat = "identity") + 
  coord_polar("y", start=0) +
  geom_text_repel(aes(y = cumsum(percent) - percent/2, label=label)) +
  theme_void()
ggsave("figures/pieChartEtherScan.png", pPieChartEtherScan, height=7, width=7)
pPieChartEtherScan*# Waffle chart*
dataPieChartEtherScan <- dataPieChartEtherScan %>%
  mutate(n=n/20)
pWaffleEtherScan <- waffle(dataPieChartEtherScan, 
                  rows = 10, 
                  reverse=TRUE,
                  xlab = "1 square = 20 sales") 
ggsave("figures/waffleChartEtherScan.png", pWaffleEtherScan, height=5, width=7)
pWaffleEtherScan

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

图 6:每笔销售价格的直方图。来自以太扫描 API 的数据。

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

图 7:每笔销售价格的饼状图。来自以太扫描 API 的数据。

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

图 8:每笔销售价格的华夫饼图表。来自以太扫描 API 的数据。

请注意,从 ETH 到 USD 的价格转换并不完全正确。我们使用当前的 ETH/USD 价格,而一些交易是在一段时间以前完成的。即使在一天之内,价格也会有很大的变化!这可以通过检索历史 ETH/USD 价格轻松解决,但这需要一个 EtherScan Pro 帐户。

结论

本文介绍了如何阅读区块链并获得可以分析和可视化的事务数据。这里,我们展示了一个简单分析区块链交易的例子——NFT 销售价格的分布图。这是一个良好的开端,但我们还可以做得更多!在第二部分中,我们将研究如何更进一步。例如,我们可以跟踪特定的非功能性食物,探索它们在释放后被占有的时间以及它们随后被重新获得的比率。请让我知道你可能会对哪些属性感兴趣。

注意,用于生成本文的代码在我的 Github 上有:https://Github . com/tdemarchin/datascienceonblockschainwithr-PartI

如果你想帮助我订阅一个 EtherScan Pro 帐户,并能够检索更多的交易,请不要犹豫,向我的 ETH 地址捐款:0 xf 5 fc 137 e 7428519969 a52c 710d 64406038319169

参考

https://docs.opensea.io/reference

https://www.dataquest.io/blog/r-api-tutorial/

https://ethereum.org/en/nft

https://influencermarketinghub.com/nft-marketplaces

https://www.r-bloggers.com/

https://etherscan.io/

https://en.wikipedia.org/wiki/Blockchain

r .区块链上的数据科学第二部分:跟踪 NFT

原文:https://towardsdatascience.com/data-science-on-blockchain-with-r-part-ii-tracking-the-nfts-c054eaa93fa?source=collection_archive---------10-----------------------

关于节点和顶点的故事

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

怪异鲸鱼 NFT 的例子。这些 NFT(令牌 ids 525、564、618、645、816、1109、1523 和 2968)属于集合的创建者便雅悯·艾哈迈德(贝诺尼),他允许我们在本文中展示它们。

托马斯·德·马尔钦和米拉娜·菲拉滕科娃

Thomas 是 Pharmalex 的高级数据科学家。他对区块链技术让世界变得更美好的不可思议的可能性充满热情。你可以在 Linkedin 或者Twitter上联系他。

Milana 是 Pharmalex 的数据科学家。她对分析工具发现我们周围世界的真相和指导决策的力量充满热情。你可以在Linkedin上联系她。

此处 提供这篇文章的 HTML 版本 。用来生成它的代码在我的Github上有。

1.介绍

什么是区块链: 区块链是一个不断增长的记录列表,称为块,它们使用加密技术链接在一起。它用于记录交易、跟踪资产以及在参与方之间建立信任。区块链主要以比特币和加密货币应用而闻名,现已用于几乎所有领域,包括供应链、医疗保健、物流、身份管理……一些区块链是公共的,任何人都可以访问,而一些是私有的。数以百计的区块链都有自己的规范和应用:比特币、以太坊、Tezos……

***什么是 NFT:***不可替换的令牌用来表示唯一物品的所有权。他们让我们将艺术品、收藏品、专利甚至房地产等事物符号化。他们一次只能有一个正式的所有者,他们的所有权记录在区块链上是安全的,没有人可以修改或复制/粘贴一个新的 NFT。

什么是 R: R 语言在统计学家和数据挖掘者中被广泛用于开发数据分析软件。

什么是智能合约: 智能合约就是存储在区块链上的程序,当满足预定条件时运行。它们通常用于自动执行协议,以便所有参与者可以立即确定结果,而无需任何中介的参与或时间损失。他们还可以自动化工作流,在满足条件时触发下一个操作。智能合约用例的一个例子是彩票:人们在预定义的时间窗口内购买彩票,一旦到期,就会自动选出一名中奖者,并将钱转移到他的账户上,所有这一切都没有第三方的参与。

这是关于使用 r 与区块链进行交互的系列文章的第二篇。第一部分重点介绍与区块链相关的一些基本概念,包括如何阅读区块链数据。如果您还没有阅读,我强烈建议您阅读一下,以便熟悉我们在第二篇文章中使用的工具和术语:第一部分

听说加密货币受黑手党欢迎并不罕见,因为它是匿名和保密的。这只是部分正确。虽然我们不知道某个地址背后到底是谁,但每个人都可以看到该地址进行的交易。除非你非常小心,否则几乎有可能通过跨数据库来确定谁是该地址的幕后操纵者。现在有公司专门从事这项工作。这是通向一个更加透明和公平的世界的突破性道路。区块链有可能解决世界面临的与缺乏可追溯性和问责制相关的主要问题。以象牙海岸的可可文化为例。在过去的 25 年里,尽管农业综合企业正式参与到与森林砍伐的斗争中,该国已经失去了超过 60%的“受保护”森林。当前保护野生森林的策略效率低下的主要原因是追溯可可豆的原产地极其困难,现有的追溯解决方案很容易被操纵。区块链可以帮助解决这个问题。在制药业,区块链也有潜力改善药品生产行业的某些方面。例如,这项技术将提高制造过程和供应链的透明度,以及临床数据的管理。

本文涉及的主题是如何提取和可视化区块链事务。我们将探索 R 上的一些可用工具来做到这一点。为了避免与黑手党搅在一起,让我们把注意力集中在区块链技术的一个更良性但目前非常流行的应用上:艺术 NFTs。我们将更具体地观察怪异的鲸鱼。这里描述的方法当然可以扩展到存储在区块链上的任何东西。

怪异鲸鱼项目是一个由 3350 只鲸鱼组成的集合,这些鲸鱼是通过编程从组合的海洋中产生的,每只鲸鱼都有其独特的特征和特性:https://weirdwhalesnft.com/。这个项目是由 12 岁的程序员便雅悯·阿迈德创建的,他在著名的 NFT 市场 OpenSea 上出售。根据这个感人的故事,3350 只计算机生成的怪异鲸鱼几乎立即销售一空,便雅悯在两个月内赚了 40 多万美元。鲸鱼最初以大约 60 美元的价格出售,但从那以后,它们的价格已经翻了 100 倍……阅读这篇来了解这个令人难以置信的故事。

这篇文章的 HTML 版本以及用来生成它的代码可以在我的 Github 上找到。

2 数据

该部分专用于下载销售数据,包括哪些代币被转移到哪个地址以及销售价格。这是一个非常有趣的话题,但也有点技术性,因此如果您仅对数据分析感兴趣,可以跳过这一部分,直接进入第 3 部分。

2.1 转让

所有智能合约都是不同的,理解它们以解码信息是很重要的。通过阅读源代码和使用像 EtherScan 这样的块探索者进行逆向工程通常是一个好的开始。这些怪异的鲸鱼由以太坊区块链的一个特殊的智能合同管理。这份合同存放在一个特定的地址,你可以在这里阅读它的代码

为了更容易地从区块链中提取信息,由于它在分类账中的存储方式,这可能相当复杂,我们可以读取事件。在 Solidity 中,用于在 Ehtereum 上编写智能合约的编程语言,事件被分派为智能合约可以触发的信号。任何连接到以太坊网络的 app 都可以监听这些事件,并据此采取行动。以下是最近的怪鲸事件列表:https://ethers can . io/address/0x 96 ed 81 C7 f 4406 eff 359 e 27 BFF 6325 DC 3c 9 e 042 BD #事件

我们最感兴趣的是一种特定类型的事件:转移。每次发生令牌传输时,事件被写入区块链,其结构为:Transfer (index_topic_1 地址从,index_topic_2 地址到,index _ topic _ 3 uint 256token id)。正如其名称所示,该事件记录了令牌传输的起始地址、目的地址和令牌 ID,从 1 到 3350(因为生成了 3350 条怪异的鲸鱼)。

因此,我们将提取所有与怪异鲸鱼有关的转移事件。为此,我们过滤该事件的散列签名(也称为主题 0)。通过对 ethers can(https://ethers can . io/tx/0xa 677 CFC 3 b 4084 f 7 a 5 f 2e 5 db 5344720 bb 2c a2 c 0 Fe 8 f 29 c 26 b 2324 ad 8 c 8d 6 c 2 ba 3 # event log)做一点逆向工程,我们看到这个事件的主题 0 是“0x ddf 252 ad 1 be 2c 89 b 69 C2 b 068 fc 378 DAA 952 ba 7 f 163 C4 a 11628 f 5

下面,我们概述了创建包含怪异鲸鱼贸易数据的数据库的过程。我们使用 EtherScan API 下载数据,更多详情参见第一部分。EtherScan 的 API 被限制为每次调用 1000 个结果。这不足以分析怪异的鲸鱼交易,因为只有铸造(在区块链上创建令牌的过程)生成 3350 个交易(每个铸造的 NFT 一个交易)。而且这还不包括所有后续的转账!这就是为什么我们必须使用一个肮脏的 while 循环。请注意,如果您准备支付一点,有其他区块链数据库没有限制。例如,以太坊数据库可以在 Google BigQuery 上找到。

这是传输数据集的外观:

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

2.2 销售价格

虽然转让和销售都可以由同一个合同管理,但在 OpenSea 上是以不同的方式完成的。销售由主要的 OpenSea 合同管理,如果它被批准(达到要求的价格),第一个合同调用第二个 NFT 合同,这里是怪异鲸,然后触发转让。如果我们想知道 NFT 的销售价格(除了上面讨论的转让),我们需要从主合同中提取数据(https://ethers can . io/address/0x7be 8076 f 4 ea 4a 4 ad 08075 c 2508 e 481d 6 c 946d 12 b)。销售额由一个名为 OrderMatch 的事件记录。

请注意,这个循环可能需要一段时间来运行,因为我们下载了 OpenSea 上所有 NFT 销售的所有销售价格,而不仅仅是怪异的鲸鱼。鉴于在撰写本文时,OpenSea 上平均每分钟有 30 个事务,下载可能需要一段时间…这个代码块与上面的代码块非常相似,所以如果您不确定一行代码具体做什么,请阅读上面的代码注释。

如果我们查看 orderMatch 事件结构,我们会看到价格在数据字段中以 uint256 类型编码。它前面是另外两个字段,buyHash 和 sellHash,都是 bytes32 类型。uint256 和 bytes32 类型的长度都是 32 个字节,因此有 64 个十六进制字符。我们对 buyHash 和 sellHash 数据不感兴趣,只对价格销售感兴趣。因此,我们必须检索最后 64 个字符,并将它们转换成十进制,以获得销售价格。

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

图 orderMatch 事件的结构

2.3 将两个事件结合起来

现在让我们通过怪异鲸鱼转账的交易散列来合并这两个数据集。

2.4 将 ETH 价格换算成美元

因为我们在区块链以太坊工作,所以交易价格是以以太坊给出的。以太币/美元汇率波动很大。如果我们试图将 ETH 转换为 USD,我们不能只应用乘法因子。因此,我们必须下载历史 ETH USD 价格。这一次,我们将从 Poloniex 交换下载数据,而不是 EtherScan(你需要一个专业帐户)。Poloniex 交易所提供免费的 ETH-USD 兑换服务。

我们将使用样条函数近似来平滑和插值转换率。这是因为交易事件的时间戳以秒为单位,而历史价格数据集的分辨率要低得多,它们平均每 30 分钟记录一次。因此,我们必须插入历史价格来涵盖交易事件。

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

图 2:历史汇率。红线:样条。

现在,让我们使用交易时价格的内插值,将怪异鲸交易的 ETH 转换为美元。

2.5 最终数据集

请注意,如果您无法从 EtherScan 下载所有数据,您可以加载 github 上的数据集。

这是最终数据集的样子:

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

3 分析

3.1 描述性统计

下面我们通过计算一些描述性统计数据对数据集进行总结:

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

表 1:数据集内容的汇总统计。

另一个有趣的练习—我们可以确定每个地址的事务数量。第一个地址(0x00…)不是一个真实的地址—它指的是 NFT 的铸造。其中的交易数量就是在区块链上注册的 NFT 的总数。此外,我们看到一些地址在交易怪异鲸鱼方面相当活跃,因为它们已经参与了数百次交易!

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

现在让我们把交易价格想象成时间的函数,而不考虑令牌 ID。在最初的几天,我们看到价格的高度可变性。接下来是一段相对平静的时期,我们在八月的最后几天看到了上升趋势的开始。随着怪异鲸鱼创造者的故事成为病毒,价格上涨恰逢社交媒体上的密集活动。一笔交易飙升至 25000 美元,与最初的 45 美元相比,这相当于增加了约 55555%!

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

图 3:怪异鲸 NFTs 交易的销售价格(美元)演变。

3.2 可视化网络

到目前为止,我们已经查看了交易价格摘要。现在,知道每个 NFT 都是独一无二的,需要与其他的区分开来,如何可视化事务呢?我们需要的工具是一个网络。我们收集的数据集非常适合绘制成网络。网络由顶点(或节点)和边(或链接)来描述。这里我们将对钱包地址使用节点表示。我们要构建的网络会显示所有曾经交易过怪鲸的钱包地址。顶点之间的连接,即所谓的边,将代表事务。

在 R 中有几个类和相应的包可以用来绘制网络,最著名的是网络igraph 。请查看参考资料部分,了解一些关于该主题的精彩教程。我个人偏好的是网络包,因为它提供了通过网络动态ndtv 包创建互动剧情的可能性。除此之外,还开发了其他的包来方便对这些对象的操作和绘制,例如gg graph包,它将熟悉的 ggplot2 框架引入到网络类中。

让我们试一试!我们将首先创建一个简单的静态(即没有时间维度)网络,并使用 ggraph 包绘制它。在一张图中显示的数据太多,因此我们将通过仅绘制涉及 7 个以上交易的 NFT 来划分数据子集。

我们现在可以绘制我们的网络。我们看到所有代币的所有交易都源自单个铸造地址(1)。一些地址涉及多个交易,这就是为什么我们看到这些交易有几个(弯曲的)边。我们还看到,一些令牌被传输到一个地址,但却被发送回发送方。

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

图 WheirdWhales NFTs 事务的静态网络。每个地址由一个节点(圆圈)表示,事务由边(线)表示。边缘颜色指的是令牌 ID。这里有一个高分辨率的图可用https://tdemarchin.github.io/DataScienceOnBlockchainWithR-PartII//DataScienceOnBlockchainWithR-PartII.html

现在让我们使用事务的时间戳为我们的网络添加一个时间维度。这将允许我们可视化网络随时间的演变。为此,我们将使用令人惊叹的 networkDynamic 包。

我们可以创建一个时间线图来显示事务活动的频率。我们看到大多数(约 2/3)的交易发生在 NFT 诞生后不久。接下来是一个相对平静的时期,然后在 1000 点左右出现一个活动高峰。

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

图 5:显示事务频率的时间线图。

下面,我们创建一个可以直接从浏览器启动的动画。可以点击边和顶点来显示关于相关地址和交易令牌的更多信息。

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

图 6:whe ird wheels NFTs 交易的动画网络。每个地址由一个节点(圆圈)表示,事务由边(线)表示。边缘颜色指的是令牌 ID。可以点击边和顶点来显示关于相关地址和交易令牌的更多信息。互动版可用 此处

4 结论

希望您喜欢阅读这篇文章,并且现在对如何可视化区块链交易有了更好的理解。这里,我们展示了一个如何下载和绘制与 NFTs 相关的交易网络的例子。我们看到,一旦有了数据,分析和绘制交易就很容易了。另一方面,以适当的格式获取数据需要对区块链有深刻的理解,尤其是在使用智能合同时。

在接下来的文章中,我们将探索泰佐斯区块链,一个新的进行非功能性交易的地方。我们还可以挖掘氦区块链,这是一种物理分散的无线区块链供电网络,用于物联网(IoT)设备。如果你想了解更多,请在 MediumLinkedin 和/或 Twitter 上关注我,这样你就会得到新文章发布的提醒。感谢您的阅读,如果您有任何问题或意见,请随时联系我们。

这篇文章的 HTML 版本带有高分辨率的数字和表格,可在这里获得。用于生成它的代码可以在我的 Github 上获得。

如果您希望帮助我们继续研究和撰写关于区块链的数据科学,请不要犹豫,向我们的以太坊地址(0 xf 5 fc 137 e 7428519969 a 52 c 710d 64406038319169)或 Tezos 地址(tz 1 ffzlhbu 9 adcobxmd 411 ufbdcvgrw 14 mbd)捐款。

敬请期待!

5 参考文献

由 Etherscan.io 和 Poloniex APIs 支持:

https://etherscan.io/

https://docs.poloniex.com/

常规:

https://ethereum.org/en

https://www.r-bloggers.com/

网络:

https://kateto.net/network-visualization

https://www.jessesadler.com/post/network-analysis-with-r/

https://programminghistorian . org/en/lessons/temporal-network-analysis-with-r

https://ggraph.data-imaginist.com/index.html

数据科学管道:窥视 Scikit-Learn 管道

原文:https://towardsdatascience.com/data-science-plumbing-peeking-into-scikit-learn-pipelines-f9233ad638e?source=collection_archive---------23-----------------------

实践教程

您是否想过如何从 scikit-learn 管道中提取信息?

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

照片由米卡·鲍梅斯特Unsplash 上拍摄

斯科特·a·亚当斯和阿莫迪尼·古普塔撰写

介绍

Scikit-learn 管道是非常有用的工具,可以为数据科学项目提供额外的效率和简单性(如果您不熟悉 scikit-learn 管道,请参见 Vickery,2019 获得详细概述)。管道可以在单个对象中组合和构建从数据转换到建模的多个步骤。尽管它们总的来说很有用,但是使用它们需要一个学习过程。特别是,窥视单个流水线步骤并从所述步骤中提取重要的信息片段并不总是最直观的过程。因此,我们写了这篇文章,作为创建一个简单管道并在其中获得几条相关信息的简要指南。

获取数据

我们使用加州住房数据,这是一个常用的实践数据集,提供了 1990 年加州的街区群体层面的住房市场信息(见 Géron,2017)。对于此工作流程,目标是使用 scikit-learn 管道生成一个线性回归模型,使用 3 个特征预测median_house_value的目标:

  • median_income——街区组家庭收入中位数(万美元),
  • popbin —区块组的分组人口分为 3 个四分位数(小,大,),
  • ocean_proximity —区块群靠近海洋的程度( < 1H 海洋内陆近洋近湾)。

请注意,以下代码通过随机移除 10%的数据集值引入了人为缺失数据,以展示 scikit-learn 管道的插补实施。如果您运行此代码,请注意,由于缺失数据分配过程中的随机性,分配给缺失数据的实际观测值可能与您的数据不同。我们还将数据分为训练和测试数据,以更好地模拟实际的机器学习工作流程。有关将管道适当应用于训练和测试数据的更多信息,请参见 scikit-learn 入门页面。

设置管道

准备好数据集后,下一步是应用适当的数据转换,以便数据集可以在机器学习模型中使用。对于本文中使用的示例,我们使用[ColumnTransformer](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html)估算器为多种数据类型实现数据转换过程,如插补、编码和缩放。

为了对数据集进行适当的转换,需要为不同的数据类型分别定义ColumnTransformer估算器的转换步骤。在下面的示例中,为该数据集中的数值、序号和分类度量建立了不同的数据转换过程(有关数值、序号和分类度量方案的更多信息,请参见这里的),然后将它们合并到管道中。一旦建立,单独的数字、序数和分类数据转换管道就充当完整管道中ColumnTransformer的步骤,其中完整 管道指的是结合数据转换和建模的管道。现在让我们仔细看看数据转换的步骤。

数字数据

如果决定估算数值数据中的缺失值(在本例中为median_income),可使用SimpleImputer估算缺失数据。在我们的例子中,我们使用中位数作为数值数据的插补值。处理完丢失的值后,是时候调整数值数据了。这里,[StandardScaler](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.StandardScaler.html)median_income重新调整为平均值为 0,单位方差为。请注意,StandardScaler在本例中用作说明,在真实世界的设置中,您可能想要尝试其他的变换技术MinMaxScaler,这取决于您的特征分布。

以下为有序列和分类列建立数据转换步骤的示例遵循与数值转换管道相同的总体结构,即缺失值插补后进行适当的转换。请注意,在所有这些步骤中,我们使用SimpleImputer进行说明,但是根据您的数据,您可能会发现另一种处理缺失数据的技术更合适。

序数数据

SimpleImputer可以用各个列中出现频率最高的值来填充缺失的数据,这对于像popbin这样的顺序列很有用。在输入丢失的值之后,我们使用[OrdinalEncoder](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html)popbin列进行顺序编码,这样转换后的列呈现从 0 到 *k-1、*的整数值,其中 k 是原始popbin列中唯一值的数量。

分类数据

一键编码为分类列中的每个唯一值创建一个新列。然后,给定的观察值在对应于原始分类列中的观察值的列上被编码为值 1,并且在从原始分类列生成的所有剩余列上被编码为值 0。

我们从下面的SimpleImputer开始分类转换过程,用新的字符串值'missing’填充ocean_proximity上所有缺失的值。输入缺失值后,OneHotEncoder会对ocean_proximity列进行一次热编码,这也会为新输入的'missing'值创建一个单独的列。

安装管道

一旦为每种数据类型定义了上述步骤,这三个单独的数据转换管道就被聚合到transformer_steps中,然后在ColumnTransformer中被声明为transformers参数。

我们现在可以创建完整的管道,包括标记为'transformation’ColumnTransformer步骤和标记为'linreg'的线性回归模型步骤。然后需要在训练集上拟合完整的管道,我们可以将这个拟合的管道分配给一个名为lm(用于“线性模型”)的变量。

这条管道里塞满了信息!让我们看看可以提取的一些最重要和最有用的信息。

闯入管道

查看管道的所有步骤

我们刚刚构建了一个漂亮的管道,但是有没有一种方法可以在不参考建立管道的代码的情况下看到管道的所有步骤呢?还好答案是肯定的!我们所要做的就是将named_steps应用到安装好的管道的名称上(将steps应用到管道上也将提供必要的输出,只是格式略有不同)。

不幸是,管道输出并不容易阅读。作为替代,我们可以将管道打印成 HTML 文件,并使用以下代码在 web 浏览器中查看。

这是呈现的 HTML 文件的样子。

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

现在让我们更深入地看看在各种管道步骤中使用的实际标签和值。

获取数值和序数数据的插补值

挖掘管道的一个原因是提取数值和序数数据的估算值。让我们从数字列开始,其中中值用于替换缺失的数据。Pipeline属性named_steps输出一个类似于字典的对象的键值对,帮助我们解析管道中的步骤,而ColumnTransformer属性named_transformers_输出一组键值对,帮助我们解析ColumnTransformer中的步骤。对于这个例子,用于识别数字列转换的步骤名为num。因此,从num步骤调用imputer会输出用于数字列的插补信息。

要查看用于估算缺失数字数据的实际值,我们可以从imputer调用statistics_属性。

通过将named_transformers_['num']中的num替换为ord,上述代码也可用于获取用于估算序数列popbin中缺失数据的值。

请注意,由于为数据分配缺失值的随机性,插补步骤和一些后续步骤的输出可能会略有不同。

获得用于标准化的平均值和方差

如下面的代码所示,为数值列提取标准化步骤中使用的平均值和方差值与前面从数值转换器的数值步骤中提取中值的步骤非常相似。我们只需要将imputer替换为normalize,将statistics_替换为mean_var_

提取数字列和序号列的功能名称

ColumnTransformer有一个transformers_属性,它为每个匹配的转换器返回一个元组,由(1)转换器的标签,(2)转换器本身,以及(3)应用了转换器的列组成。

数字列和序号列的特征名提取的目标是对输出进行切片,以获得数字列和序号列的名称。

  • 数字列:因为我们将num指定为transformer_steps的第一个元素,所以num transformer 管道是transformers_ 输出中返回的第一个元组。感兴趣的实际列名是给定转换器的元组中的第三项,因此我们需要输出第一个transformers_元组([0])的第三项([2],如下所示(记住 Python 是零索引的)。

  • 顺序列:顺序转换器是transformers_输出的第二个元组,这里使用的顺序列名是这个元组中的第三项。

提取独热编码列的功能名称

这个有点不同,因为 one-hot 编码用指定变量中每个类别的一组新列替换了原来的分类列。幸运的是,OneHotEncoder有一个方法get_feature_names,可以用来获得描述性的列名。所以这里的目标是首先在数据转换管道中访问OneHotEncoder,然后调用get_feature_names

为了使列名前缀更具描述性,我们可以将原始的一键编码变量的列名作为参数传递给get_feature_names

查看回归模型的系数

LinearRegression有一个属性coef_,存储回归系数(关于线性回归的概述以及如何解释回归系数,请参见。因此,要查看系数,我们需要从整个管道访问linreg步骤,并调用coef_属性。

同样,请注意,由于为数据分配缺失值的随机性,您的输出可能会略有不同。

结论

Scikit-learn 管道是组织和有效执行数据转换和建模任务的好工具。正如我们自己的经验所表明的,有时候从管道的各个步骤中提取特定的信息是有帮助的,这也是我们写这篇文章的动机。例如,我们可能想要创建一个定制的表/特性重要性结果的可视化,需要提取列名(包括单个的独热编码列名)和模型参数。或者,我们可能正在起草一份关于模型的报告,需要包括用于在插补步骤中替换缺失数据的方法或中位数。或者,也许我们只是好奇,想看看流程中特定步骤的结果。在这些场景中,知道如何从管道中的特定步骤中提取相关信息将被证明是有用的。

感谢您花时间阅读这篇文章。你可以在活页夹上的 Jupyter 笔记本中运行全部代码。如果你觉得这篇文章的内容有用,请留下一些掌声。此外,请随时提出任何建设性的意见。

参考

Géron,A. (2017)。使用 Scikit-Learn 和 TensorFlow 进行动手机器学习:构建智能系统的概念、工具和技术。奥莱利媒体。

Vickery,R. (2019 年 2 月 5 日)。sci kit-learn 管道的简单指南。维克数据。https://medium . com/vick data/a-simple-guide-to-sci kit-learn-pipelines-4 ac0 d 974 bdcf

本文提供的内容由作者开发,不一定反映任何其他个人、实体或组织的观点。任何错误和遗漏都是我们自己的。

从雇主的角度看数据科学产品组合

原文:https://towardsdatascience.com/data-science-portfolio-from-employer-point-of-view-840a111a96c9?source=collection_archive---------14-----------------------

公司希望从您的数据科学产品组合中获得什么?

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

凯利·西克玛在 Unsplash 上的照片

如果你喜欢我的内容,并想获得更多关于数据或作为数据科学家的日常生活的深入知识,请考虑在这里订阅我的时事通讯。

近年来,公司意识到利用他们的数据来获得对竞争对手的优势是多么重要。从公司、初创公司到小型企业,都已经开始使用数据项目来改善他们的业务。这反过来又增加了对合格数据人员的需求,这种需求直到现在还在持续增长。

随着热门行业的兴起和需求的增加,许多人试图学习数据科学以进入这一领域-这造成了激烈的竞争。为什么需求增加,但竞争仍然激烈?因为这个领域还是新的,许多公司都在寻找有经验的人,而不是更新鲜的人。这也是为什么数据科学岗位入职岗位成为瓶颈的原因。那么,你如何在申请者的海洋中脱颖而出呢?一种方法是调整你的投资组合,以满足雇主的需求。

在本文中,我想概述一下我从潜在申请人数据科学组合中寻找什么的经历。让我们开始吧。

结构化投资组合

有什么比看到一堆乱七八糟的数据科学作品集更让人不爽的?故事不清楚,结论也不存在——如果您让所有的编码和数据探索组合保持原样,就会发生这种情况。乱七八糟的项目是我经常看到的问题:人们已经知道你想做什么样的数据科学项目,并试图解决;然而,他们没有从你的投资组合中创建一个结构,让人们能够消化这个过程。

例如,一个人想要通过创建一个模型来预测欺诈并实现良好的指标,从而解决欺诈问题。由于这种欺诈模式,此人设法获得了面试机会,但没有形成一个关于该模式如何发展以及如何帮助公司的良好结构故事。这个人没有得到聘用,因为面试官觉得这个人不能清楚地解释工作流程,并担心这个人在工作期间会一团糟。

这个例子在我的经历中很常见。人们只是关注他们的结果,而不是详细说明过程——根本没有结构。雇主想看的不是你创造的模型有多好,而是你实现这个模型的思维过程。创建结构化数据科学产品组合以脱颖而出非常重要。

结构可以是多种多样的,取决于您自己的数据科学项目。然而,它应该总是从头到尾讲一个故事——即使它在你的笔记本里。常见的结构是:

  1. 解释你想解决的问题
  2. 解释这些数据以及你是如何获得的
  3. 数据探索
  4. 建模过程
  5. 结果和结论

通过这五个步骤,您已经可以创建一个结构良好的数据科学投资组合。你可以使用 presentation、Git、Notebook 或任何媒介来创建它——只要它讲述了一个好故事。在我看来,如果你能通过应用你的项目解释详细的好处,那就是加分。

解决业务问题

开发一个惊人的神经模型,可以准确预测某人的面部特征和穿着,这是一种很棒的感觉,但这个项目能解决你申请的公司的任何实际问题吗?有可能,但会有很多延伸——这不太可能出现在当前的面试阶段。

该公司聘请数据科学家来解决他们的业务问题,而每个公司都会有不同的问题。招聘广告通常只列出技术要求(有些是特定领域的),但很少详细说明他们需要解决什么样的问题。当你用一般的投资组合申请这种工作时,它可能会起作用,但也可能不起作用;因为许多申请人会提交“相似”的简历和数据科学作品集。

那怎么脱颖而出呢?成为公司想要的!那就是解决他们的业务问题。尝试创建解决业务问题的特定数据科学产品组合;例如,您申请金融行业的数据科学家职位,这意味着您可以创建一个数据科学组合来解决该行业的常见问题,如投资、欺诈、风险等。

我喜欢看到申请人至少对他们申请的公司做了调查,因为他们做的调查意味着他们愿意花额外的时间去了解这家公司。与不了解业务或公司的人相比,雇佣了解业务或公司的人肯定符合公司的最佳利益,这就是为什么如果您的数据科学产品组合解决了公司的业务问题,它会让您脱颖而出。

有创意

这与您的数据科学产品组合应该如何解决业务问题有关。当你决定你的项目时,不要使用你从课程或书本上学到的固定项目 —相反,你应该基于你自己的创造力建立数据科学组合。

想象一下,你正在用泰坦尼克号或 iris 项目申请银行行业的数据科学家职位;会是什么样子?

**首先,**这是每个人都做的项目。

**其次,**那些项目不需要商业(也许是历史学家或生物学家?).

第三,这会破坏你的机会,因为雇主会认为你懒惰。

您可以做许多其他项目来展示您在构建数据科学组合时的创造力。创意可以通过多种方式表现出来,包括:

  • 你试图解决什么商业问题
  • 你如何处理这个问题
  • 你探索数据和总结见解的方式
  • 开发模型并解决技术问题
  • 对您的数据科学产品组合做出总结

还有很多。创造力意味着你不局限于课程或惯例,而是你如何从中突破。

根据我的经验,当我探索申请人的数据科学产品组合时,我会尝试观察他们如何解决他们决定解决的问题。许多人倾向于陷入类似的模式,但是当我发现有人可以给我不同的东西(以一种好的方式),我会变得兴奋。

我记得许多申请人使用类似的数据集作为他们的数据科学组合,并试图解决相同的问题;然而,只有一个脱颖而出。他之所以突出,是因为他总结见解的方式与众不同。许多人把洞察力总结为特性并不重要。尽管如此,这个人设法做了更深入的分析,并发现实际问题在于复合问题——这需要创造性思维才能知道这就是问题所在。

在某种程度上,创造性可能需要更多的练习,因为它与批判性思维有关。尽管如此,一旦你习惯了从多方面看问题,我确信许多雇主会渴望你的创造力。

结论

数据科学是一个仍在崛起且竞争激烈的行业。要成功获得该职位,您需要有一个良好的数据科学组合。然而,雇主从你的投资组合中寻找什么?

在本文中,我从雇主的角度解释了我从数据科学组合中寻找的经验。它们是:

  1. 结构化投资组合
  2. 解决业务问题
  3. 有创造力

希望有帮助!

如果您不是作为中等会员订阅,请考虑通过 我的推荐 订阅。

在我的 LinkedInTwitter 上访问我。

数据科学产品经理应该影响变更管理

原文:https://towardsdatascience.com/data-science-product-managers-should-influence-change-management-fb3159dc631e?source=collection_archive---------28-----------------------

产品经理应采取的 4 项关键行动,以推动数据科学项目的成功采用

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

弗兰基·查马基在 Unsplash 上拍摄的照片

COVID 和高级分析功能给零售业务带来了颠覆性的变化,原本需要几年时间才能实现的功能现在只需几个月就能推出。一如既往,商业界将人工智能视为应对零售业所有挑战的灵丹妙药。尽管商业模式正在被颠覆,但一个不变的因素将永远是人以及他们是否有能力适应新的工作方式。采用数据科学算法不仅仅是转向一项新技术,它还涉及思维和问题解决方式的改变。虽然数据科学被用作解决所有问题的通用短语,但激励企业重新思考他们开展业务的方式并采纳分析建议仍然具有挑战性。通常在项目管理路线图中,有一个单独的泳道来关注变更管理。确保产品采用的责任完全在于商业利益相关者和变更管理组织。但是,由于迫切需要实施事实驱动的建议来提高准确性,将变更管理视为单独的活动而不是基本的产品管理责任将导致时间表延迟和采用率降低。

已经有多个公司在人工智能上投入巨资的案例,只是建立了一个原型,很少投入生产。这主要是因为业务部门不愿意让算法做出影响损益的决策。尽管在业务构思会议上花费了大量时间来研究问题并研究合适的模型来推荐解决方案,但情况仍然如此。数据科学产品经理在弥合业务和工程之间的差距时,应在项目早期积极考虑变更管理,并在流程的每个步骤中继续扮演业务客户的角色,以提高采用率。

**与能够支持您的产品的业务用户建立关系:**虽然定期与业务利益相关方进行演示是一种常态,但产品经理应该与能够影响其同行并为数据科学建议带来更多可信度的业务用户保持更多接触。仔细选择在其业务领域有广泛背景的用户,并继续经常与他们接触。与业务客户召开小组会议,了解他们对数据科学建议的疑虑。在绞尽脑汁想出解决方案之前,真诚地倾听并从他们的担忧中学习。拥抱这学习的时刻;打开思维,从借给你的商业光学中去看世界,将有助于从商业中获得信任。建立这种伙伴关系并说服这些业务冠军对于产品推出期间更广泛的认同至关重要。

**在算法中建立透明度:**业务用户对使用分析推荐持怀疑态度的原因之一是,逻辑对他们来说是一个黑箱。安排多次会议来解释细节只会增加业务团队对这种转变的挫败感。对算法透明绝对不意味着让用户浏览 python 代码。为了创建正确的约定并理解算法,构建输入变量和输出的可视化表示是有帮助的。一个好的叙事完全没有深奥的分析典故,更粗略是有效的。一个组织良好的分析可视化表示有助于业务涉众快速确定这个框架是否符合需求。熟悉启发法对于长期以来以某种方式做事的商业用户来说可能是创新的障碍。突出相关性和趋势的视觉效果可能是一个良好的开端。根据不同的用例,建立一个建议的概念验证,并允许用户使用假设场景,可以说服他们重新考虑他们的方法。最终提出能引起利益相关者强烈共鸣的见解是在用户中建立信心的关键,高级分析模型可以基于电子表格无法实现的多个信号提供更精确的输出。

**筑小胜:**投资机器学习项目,应该认为是一次远征;为了使这一旅程的成果更加丰硕,需要在数据分析、数据科学家的研究以及机器学习工程师的扩展和优化方面投入更多的时间和资金。但是,对于希望在短时间内进行彻底战略变革的组织来说,等待成熟的数据科学模型似乎不是一个有吸引力的解决方案。为了建立可信度,可以设定一些小目标,专注于实现长期数据科学战略的某个方面。如果最终目标是建立一个预测需求的机器学习模型,请与数据分析师合作,在一个月内推出时间序列模型,而数据科学家则研究影响需求的外部因素。不要等待工具通过高级分析来自动化业务流程,而是构建一个 power bi 或 tableau 报告,向业务用户展示数据科学见解。看到结果而不被迫使用分析建议将大大减少阻力,并允许用户以自己的速度摄取输出;同时还向数据科学家提供反馈。

**构建强大的数据驱动文化:**在当今的环境中,业务用户精通数据并掌握分析知识并不罕见。尽管人们对数据科学感兴趣,但对于它所带来的破坏,总会有一些尖刻的怀疑。此外,在业务用户已经在应对大量创新的组织中,在他们的流程中引入分析模型将被视为增加了复杂性。即使有更有效的改进流程,动摇稳定的日常程序也会产生怨恨和抵触情绪。虽然发现会议和设计思维研讨会将有助于数据科学和产品团队了解当前的业务流程和战略,但业务用户接受分析解决方案培训也很重要。促进面向业务用户的分析 101 会话,该会话涵盖监督与非监督模型的基础知识,可以帮助获得一些兴趣。产品经理可以与数据分析师合作,提出与业务相关的数据集,用于演示简单的聚类或回归分析。为业务用户配备易于使用的 BI 工具,如 SAS enterprise miner 或 Alteryx,并指导他们建立预测模型,也有助于突出采用先进的机器学习算法的好处,该算法基于多个数据信号进行推荐,而不是基于历史 KPI 进行简单分析。

成功的产品管理之旅不会止步于产品实施,而是追求并实现 100%的采用率和目标投资回报率。业务合作对于任何新技术都至关重要,但对于数据科学项目来说尤其重要,因为数据科学项目会挑战业务用户快速而直观的思维,有时甚至会推翻这种思维。在商界找到一个能够游说这项事业的盟友是很重要的。第一步是通过倾听和向你的商业伙伴学习来建立信任。通过展示视觉效果来简化数据科学的各个层面,让企业了解解决方案并增强信心。关注短期行动,通过推出概念证明和仪表板在用户群中建立信誉。摆脱推动前数据科学时代进程的认知偏见和 1 型思维并不容易,但通过分析培训使分析技能集民主化将允许用户自己创造挑战其方法的见解。这反过来又建立了一种事实驱动的文化,这种文化将对新的工作方式和发现洞察力更加开放。

数据科学项目—营销分析和数据驱动的解决方案

原文:https://towardsdatascience.com/data-science-project-marketing-analytics-data-driven-solutions-72d050084642?source=collection_archive---------1-----------------------

使用 Python 进行 EDA、执行统计分析、可视化洞察,并向公司的首席营销官展示数据驱动的解决方案

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

作者照片

语境

“我是一名数据分析师,首席营销官告诉我,以前的营销活动没有达到预期的效果。我需要分析数据集来理解这个问题,并提出数据驱动的解决方案。”-上下文从到这里进行了解释和调整。

(澄清:以上内容引自并调整自 Kaggle 数据集。我想把这个项目的背景、想法和许多灵感归功于这个 Kaggle 数据集提供商。感谢分享这个令人惊叹的项目创意和与之相关的背景资料!)

数据集概述

这个项目的数据集由 Omar Romero-Hernandez 博士提供。它被授权为 CC0: Public Domain,声明“你可以复制、修改、分发和执行该作品,即使是出于商业目的,都无需征得许可”你还可以在这个 Kaggle 页面上看到许可状态并下载该数据集。

分析过程

1.评估和清理数据

2.探索性数据分析

3.执行统计分析

4.数据可视化和进一步分析

5.形成数据驱动的解决方案

6.向公司的首席营销官做 8 分钟的陈述

注意:本文不是要解释每一行代码,而是每个分析步骤中最重要的部分。因此,您可能会发现一些部分只是对结果的描述。如果你对代码本身感兴趣,请在这里勾选https://github.com/YuehHanChen/Marketing_Analytics

步骤 1:评估和清理数据

我们先来看特征信息:

  • ID:客户的唯一标识符
  • Year_Birth:客户的出生年份
  • 教育:客户的教育水平
  • 婚姻状况:客户的婚姻状况
  • 收入:客户的家庭年收入
  • 儿童之家:客户家庭中的儿童数量
  • Tennhome:客户家庭中青少年的数量
  • Dt_Customer:客户在公司注册的日期
  • 最近:自客户上次购买后的天数
  • MntWines:过去两年在葡萄酒上花费的金额
  • 水果:过去两年在水果上花费的金额
  • MntMeatProducts:过去两年在肉类上花费的金额
  • MntFishProducts:过去两年在鱼上花费的金额
  • MntSweetProducts:过去两年在糖果上花费的金额
  • MntGoldProds:过去两年在黄金上花费的金额
  • NumDealsPurchase:打折购买的数量
  • NumWebPurchase:通过公司网站购买的次数
  • NumCatalogPurchase:使用目录进行购买的次数
  • NumStorePurchase:直接在商店购买的数量
  • NumWebVisitsMonth:上个月公司网站的访问量
  • AcceptedCmp3:如果客户在第三次活动中接受了报价,则为 1,否则为 0
  • AcceptedCmp4:如果客户在第四次活动中接受了报价,则为 1,否则为 0
  • AcceptedCmp5:如果客户在第五次活动中接受了报价,则为 1,否则为 0
  • AcceptedCmp1:如果客户在第一次活动中接受了报价,则为 1,否则为 0
  • AcceptedCmp2:如果客户在第一次活动中接受了报价,则为 2,否则为 0
  • 回答:如果客户在上一次活动中接受了报价,则为 1,否则为 0
  • 投诉:如果客户在过去 2 年内投诉,则为 1,否则为 0
  • 国家:客户所在地

这个数据集有 28 列,2240 行,0 个重复行。

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

作者照片

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

作者照片

评估数据后,我发现了几个问题:

1.在收入栏名称前面有一个空格

2.有美元符号的是收入栏的数值

3.“收入”列有 23 个缺失值

4.收入的类型是字符串

5.Dt_Customer 的类型是字符串

因为数据清理不是这个项目的主要部分,所以让我们进入下一步。(你可以在这里找到清理这些问题的代码)

步骤 2:探索性数据分析

在这个数据集的 Kaggle 页面中,有一些数据发布者建议遵循的 EDA 方向,我决定选择以下三个问题进行探讨:

  • 有没有异常值?你将如何处理他们?
  • 有没有什么有用的变量可以用给定的数据来设计?
  • 你注意到数据中的任何模式或异常吗?你能画出它们吗?

现在我们一个一个来看问题。

1。有没有异常值?你会如何处理他们?

我使用箱线图来可视化所有的数字特征,它将显示数据的 5 个数字:不是异常值的最小数字,Q1(第 25 个百分点),Q2(第 50 个百分点),Q3(第 75 个百分点),以及不是异常值的最大数字。

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

作者照片

许多列都有异常值,但大多数看起来像是来自总体的自然异常值。相比之下,Year_birth 中的异常值似乎是输入错误,因为 1900 年之前出生的人不可能还活着。因此,我将删除 Year_birth 中的异常值。

异常值意味着它们低于或高于平均值的 3 个标准差。

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

作者照片

2。有没有什么有用的变量可以用给定的数据来设计?

在评估数据集之后,我列出了我认为对最后的分析有用的新特性。例如,如果我们知道普通人成为客户的平均月份和星期几,那么当我们在那一天或那一个月开展活动时,它可能有助于增加更多的首次客户。

  • Join_month:该人成为客户的月份,可以从“Dt_Customer”设计
  • Join_weekday:这个人成为客户的那一天,可以从“Dt_Customer”设计
  • Minorhome:他们家未成年人总数,可以通过 Kidhome 和 Teenhome 相加获得。
  • Total_Mnt:最近两年花费的总金额,可以通过合计所有与“Mnt”相关的列获得
  • Total_num_purchase:最近两年采购的总次数,可以通过将所有与“num”相关的列相加得到
  • Total_accept:客户在所有营销活动中接受报价的总额,可以通过合计所有与“接受”相关的列和“回应”列来获得
  • “AOV”:AOV 代表每个客户的平均订单量,可以通过将总数量除以总购买数量来计算

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

作者照片

3。你注意到数据中的任何模式或异常吗?你能画出它们吗?

我们可以使用热图来查看每个变量之间的相关性。当天气变得更蓝时,它们更正相关,当天气变得更红时,它们更负相关。

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

作者照片

调查结果:

图案: 1。高收入人群倾向于花费更多,购买更多。
—倾向于比其他人更少地访问公司网站。
—倾向于购买少量打折商品

2.家里有孩子的人倾向于少花钱,少购物。
—倾向于购买大量打折商品

3.平均订单量高的人
——倾向于购买更多的葡萄酒和肉制品
——倾向于使用目录进行大量购买
——倾向于不访问该公司的网站。

异常: 1。凭直觉,我认为顾客的投诉越多,他们在我们商店的消费可能就越少,但过去两年的投诉数量与过去两年的总消费金额几乎没有相关性。= >进一步调查数据后,我发现是因为我们最近两年投诉的客户只有 20 个,但我们总共有 2200 个客户。所以,因为不平衡的比例,它们没有关联。公司的客户服务部在过去的两年里工作出色。

第三步:进行统计分析

在这个数据集的 Kaggle 页面中,有一些数据发布者建议回答的统计分析问题,我决定选择以下三个问题进行探讨:

  • 哪些因素与店铺购买次数显著相关?
  • 你的主管坚持认为买黄金的人更保守。因此,在过去 2 年里购买黄金数量高于平均水平的人会有更多的店内购买。使用适当的统计测试证明或反驳这种说法
  • 鱼含有对大脑有益的欧米伽 3 脂肪酸。因此,“已婚博士候选人”与花在鱼上的钱有显著关系吗?

现在我们一个一个来看问题。

1。哪些因素与店铺购买次数显著相关?

我们可以使用随机森林来预测商店购买,然后利用模型的功能重要性分数来对因素进行排序。

结果:

平均绝对误差:0.78703125
均方误差:1.4546007812500001
均方根误差:1.

NumStorePurchases 的范围是 13,均方根误差只有 1.2(不到范围的 10%),这意味着它是一个可靠的模型。

现在,让我们使用 random forest 的功能重要性分数来查看哪些因素对 NumStorePurchase 的影响最大。

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

我们现在可以看到前 7 个因素是

1\. Average order volume
2\. Total amount spent in the last two years
3\. Total number of purchases in the last two years
4\. Amount spent on wine in the last 2 years
5\. Number of purchases made using a catalog
6\. Number of visits to company's web site in the last month
7\. Total number of purchases through website in the last two years

但是,我们无法判断每个因素与商店购买次数是正相关还是负相关。我们可以用 SHAP 来解释。

有一篇由塞缪尔·马赞蒂写的著名文章解释了什么是 SHAP。请点击查看

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

作者照片

调查结果:

  1. 商店购买次数随着更高的总消费金额(Total_Mnt)、更高的总购买金额(Total_num_purchase)、更高的 AOV 和更高的葡萄酒购买金额(MntWines)而增加。
  2. 商店购买次数随着网站访问量(NumWebVisitsMonth)、通过目录购买次数(NumCatalogPurchases)和通过网站购买次数(NumWebPurchases)的增加而减少。

总结:主要在商店购物的人倾向于购买更多的葡萄酒,平均订单量更高,通过互联网或目录购物的人更少。

2。你的主管坚持认为买黄金的人更保守。因此,在过去两年里,在黄金上花费高于平均水平的人会有更多的商店购买。使用适当的统计测试证明或反驳这种说法。

为了从统计上验证这一说法,我们需要使用相关性测试来查看 MntGoldProds 和 NumStorePurchases 是否正相关。首先,让我们看看这两个变量的散点图。

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

作者照片

正如我们所看到的,有一个非常模糊的趋势,即随着 MntGoldProds 的增加,NumStorePurchases 也会增加。现在,让我们看看相关性测试。

Pearson correlation (r):  0.38326418634704296
Pearson p-value:  3.4668974417790955e-79

我们得到的皮尔逊相关系数为 0.38,p 值几乎为零,这表明它们在统计上是显著的,并且具有正相关性**。(如果 p 值为> 0.05,我们将无法拒绝零假设,因为它们不相关。)**

3。鱼含有对大脑有益的欧米伽 3 脂肪酸。因此,“已婚博士候选人”与花在鱼上的钱有显著关系吗?

为了从统计上验证这些,我首先将数据分为两组。一个是已婚博士群体,其余的。然后,我们可以用一个箱线图来可视化这两组,看看他们是否不同。最后,我们可以使用 t 检验来检验它们的平均值是否相似。

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

作者照片

该图显示,其余客户在鱼产品上花费更多,因为其第 50 百分位高于已婚博士组。现在,让我们来看看 t 检验。

T-test p-value:  0.005297012242158541

由于 p 值小于 0.05,我得出结论,我们拒绝零假设,这意味着他们的均值是不同的,但已婚博士的均值低于其他人,从图表中可以看出。

步骤 4:数据可视化和进一步分析

以下是我将使用数据可视化探索的问题:

  • 哪个营销活动最成功?
  • 这家公司的普通客户是什么样的?哪些产品表现最好?
  • 调查最成功的活动与其他活动在客户特征和购买行为方面的差异。

现在我们一个一个来看问题。

1。哪个营销活动最成功?

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

作者照片

回应是指最后一次营销活动,也是最成功的一次。除了第二次竞选,它的表现几乎是前两次竞选的两倍。

2。这家公司的普通客户是什么样的?哪些产品表现最好?

使用后。均值(),我发现一个普通客户…

  • 年收入为 52200 美元
  • 49 天前购买的
  • 拥有 26.8 美元的 AOV
  • 已经花了 605 美元
  • 已经购买了 20 次
  • 6 月中旬成为客户
  • 周四成为顾客
  • 花在葡萄酒上的钱最多(300 美元),其次是肉制品(165 美元)
  • 在水果(26 美元)和甜食(27 美元)上花费最少

3。调查最成功的活动与其他活动在客户特征和购买行为方面的差异。

现在我们已经知道最后一个活动是最成功的,我们可以进一步调查最成功的活动、最后一个活动以及活动 1-5 中其他活动之间的客户特征和购买行为(如下所列)的差异。

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

作者照片

与前几次活动吸引的客户相比,上一次活动在 AOV、花费总额和购买总量方面吸引了更多有价值的客户。

就产品类别而言,上一次活动的顾客在肉制品和葡萄酒上的花费是前一次活动顾客的近两倍。

关于购买渠道,上一个活动中的客户通过商店、网站和目录购买的更平均,而前一个活动中的客户主要通过商店和网站购买。

上一个活动中的客户比上一个活动中的客户多挣 20%的工资。

让我们看看每个国家从以前的运动到最成功的运动的比例变化。

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

作者照片

西班牙的顾客相对较多(增加了 4%),而印度吸引到上一次活动中的顾客较少(减少了 3%)。

第 5 步:形成数据驱动的解决方案

让我们回顾一下这个项目的主要目标

我是一名数据分析师,首席营销官告诉我,以前的营销活动并不像预期的那样有效。我需要分析数据集来理解这个问题,并提出数据驱动的解决方案。

为了形成数据驱动的解决方案,我首先总结了从分析中获得的所有见解,然后利用这些见解形成了可操作的策略。

见解总结:

1 .上一个战役的表现几乎是前几个战役的两倍

与前几次活动吸引的客户相比,上一次活动在 AOV、花费总额和购买总数方面吸引了更多有价值的客户。

西班牙的顾客相对较多(4%),印度的顾客较少(3%)

就产品类别而言,上一次活动的顾客在肉制品和葡萄酒上的花费是前一次活动顾客的近两倍。

就购买渠道而言,上一次活动的客户通过商店、网站和目录购买的比例更平均,而前一次活动的客户主要通过商店和网站购买。

上一个活动中的客户比上一个活动中的客户多挣 20%的工资。

2 .大多数客户通过实体店购买,在那里人们倾向于每次购买花费更多。原因可能是当顾客在商店里看到其他类似的产品时,他们会更冲动地购买。

3。家里有孩子的人是不太有价值的顾客,因为他们……

倾向于减少购买

倾向于购买大量打折商品

4。普通顾客……

成为周四的顾客

6 月中旬成为客户

可行的数据驱动解决方案

关于收购:

  1. 继续使用上次活动中相同的营销技巧,但重点是推广肉制品和葡萄酒
  2. 在西班牙投入更多营销预算,在印度投入更少
  3. 在周四有一个品牌折扣日,或者在六月有一个品牌折扣月来吸引新顾客

关于增加收入:

  1. 开展营销活动,将主要在网站或目录上购物的客户转化为店内购买者,因为大多数店内购买的平均订单量很高。
  2. 建立忠诚度计划,让高收入客户尽可能长久地保持忠诚度

第六步:给公司的首席营销官做一个 8 分钟的陈述

我在这个视频中也解释了这个数据集的背景和基本信息,所以如果你想看演示,请跳到 2:20。

https://www.youtube.com/watch?v=3Nij8BCQ0ig

谢谢你看完!如果你对这个项目的完整代码感兴趣,请查看 my Github 。另外,我喜欢反馈。如果有任何不清楚的地方或应该做得更好的地方,请联系我。这是我的 LinkedIn 或者通过我的电子邮件联系我(yuehhanchen@gmail.com

数据科学项目,以提高您的业务理解

原文:https://towardsdatascience.com/data-science-project-to-improve-your-business-understanding-776386abbf63?source=collection_archive---------7-----------------------

业务是数据科学的核心

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

斯科特·格雷厄姆Unsplash 上拍照

数据科学项目总是与改进业务流程有关。改善可以是任何方面——增加收入、消除滞后时间、留住客户等。您的数据科学项目总是将改进作为您需要实现的主要 KPI。

问题是,我看到的许多数据科学教育都不足以解决业务理解部分。大多数时候,这是一种事后的想法,学生被引导专注于编程和机器学习部分。这是一个遗憾,因为商业理解技术无疑会帮助学生更容易地获得数据就业。

我不是在谈论理解整个商业领域,因为这需要大量的经验,而且每个组织都是独一无二的。我更关注的是数据科学家的心态,只关注技术部分,不考虑业务。你可以拥有世界上最好的模型,但如果这个模型没有考虑到商业方面,那它就是无用的。

业务理解是理解我们的数据科学项目如何影响业务的过程;这意味着我们需要获得尽可能多的信息来构建我们的数据科学项目。在实际业务中,我们总是可以与业务用户讨论,以获得更好的洞察力。我们可以询问的信息示例:

  • 什么是业务目标,我们如何衡量这个目标?
  • 业务流程是什么样的?
  • 数据集位于何处?
  • 我们是否需要一个机器学习模型,或者简单的统计学就足够了?
  • 使用该模型会引发任何隐私或道德问题吗?

我们还可以问更多的问题。这是转换齿轮对我们的工作至关重要的时候。

因为我希望每个人都有商业思维,所以我想举一个项目实践的例子来提高你的商业理解能力。对业务的理解可能不像编程或统计那样技术性,但你可以为此接受培训。这就是为什么本文中介绍的所有项目都很简单,但是我们会从不同的角度来看待它们。让我们开始吧。

旅游保险客户线索

我们要处理的项目是旅游保险客户线索。预测哪些客户有兴趣购买产品是经典的数据科学项目之一,但它仍然受到每个公司的追捧。每个公司都需要他们的客户作为收入来源;这就是为什么预测项目适用于所有公司——反过来,这也是一个学习商业理解的好项目。

对于客户导向项目示例,我将使用来自 Kaggle 的数据集。该数据集旨在**建立一个预测模型,预测哪些客户有兴趣购买旅游保险。**许多人最初会想探索数据并创建分类模型,但在实际业务中,我们会从业务理解部分开始。

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

旅游保险客户线索

你可能会想,“我不是保险行业的,对这个领域不感兴趣,我怎么可能做业务理解呢?”—没错,要进行深入的商业分析,你可能需要这个行业的经验;然而,这并不意味着我们不能实践和创造性地理解我们不属于的业务。

商业假设

通常,我们会与业务用户一起工作,但是我们没有业务用户;我们可以询问我们案例中的业务问题。让我们利用现有的有限信息,尝试根据这些信息做出假设。我们可以从数据集获得的业务上下文是:

  1. 该公司是一家提供旅游保险套餐的旅游公司。
  2. 新的一揽子保险还包括新冠肺炎保险。
  3. 该公司想知道哪些顾客会购买旅游保险套餐。
  4. 所用数据来自 2019 年客户历史数据。

商业理念看似简单;用户想要一个机器学习模型来预测客户是否会对旅游保险感兴趣。然而,根据我们掌握的信息,你认为**这个想法有什么问题吗?**我已经发现了一些问题。

例如,我们指的是新客户还是现有客户?旅游保险套餐的什么细节?你会为这份保险卖多少钱?企业会有具体的活动吗?还有很多我能想到的问题。你也可以试着自己去找其他人。

我们可以根据手头的信息进行假设,并做出创造性的猜测来回答前面的问题。假设客户是现有客户,目标客户是收入较高的常旅客。那么,如果企业已经有了这个目标,目标预测会改变吗?绝对的。标记目标定义变得不同,您需要重新定义它。这是现实商业世界中通常会发生的事情。

商业理解实践

这里我想强调的是简单的想法并没有那么简单。开发机器学习模型很容易,但你总是需要考虑业务方面。这是一个商业理解练习,使用我可以给你的数据集。

  1. 尝试假设业务流程。如果太难,尝试简单的,如业务市场目标和保险价格。如果你做一些研究,假设整个过程会更好。
  2. 选择具有商业合理性的建模特征。例如,毕业与否,根据教育水平将某人排除在旅游保险之外可以吗?这只是为了实践,但我们在为机器学习模型选择特征时,会尝试进行逻辑思考。
  3. 当选择一个机器学习指标时,尝试评估它将如何给企业带来好处。比如准确率 70%,会对销量产生怎样的影响?如果预测下降了 30%,会对销售产生什么影响?多少钱?尝试创建一个模拟来处理这个问题。
  4. 你可能想创建一个仪表板预测或报告分析来展示你的数据分析能力和机器学习发展。尽量拥有企业可能想知道的所有商业信息。证明你为什么选择这些图或信息。
  5. **解释力 vs 预测力。**你能有一个机器学习模型来解释为什么预测模型创建现有的预测吗?你可能有最好的模型,但是可解释性将帮助你解释业务的结果。
  6. 如果你对保险行业感兴趣,从各种来源研究商业问题。它将帮助您创建一个数据科学项目来满足保险业务的需求。如果没有,试着找一个自己感兴趣的行业。

花时间思考业务问题,并在过程中保持创造性。一旦你对业务有了理解,你就可以更容易地继续进行各种项目。展示你在商业理解方面的能力会让你在公司和商业用户的眼中脱颖而出。

就材料而言,这里有一些你可能想要阅读的阅读材料,以及遵循业务流程的项目示例。

https://github.com/cornelliusyudhawijaya/Cross-Sell-Insurance-Business-Simulation

结论

虽然开发机器学习模型对于数据科学家来说至关重要,但我们必须记住,我们的工作是为业务服务的。因此,发展我们对商业的理解对我们的工作和脱颖而出变得非常重要。

在这篇文章中,我为您概述了一些实践,以提高您的业务理解。

希望有帮助!

在我的 LinkedInTwitter 上访问我。

如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的 简讯。

如果您没有订阅为中等会员,请考虑通过 我的推荐 订阅。

数据科学 Python 面试问题演练

原文:https://towardsdatascience.com/data-science-python-interview-question-walkthrough-5a679c6351ef?source=collection_archive---------19-----------------------

办公时间

在本文中,我们展示了如何处理和解决旧金山市的一次采访中提出的一个具有挑战性的数据科学问题。如果您想在从地址字符串中提取信息方面做得更好,您会发现这很有用。

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

图片来自 Canva

根据各种消息来源,旧金山市和县雇用了 3.5 万至 4.5 万人。这些职位分布在许多部门,如金融、卫生、交通、执法、博物馆甚至旧金山国际机场。这包括受雇于技术部或在其他部门担任辅助角色的数据科学家。

一般来说,要成为旧金山市的一名数据科学家,需要具备使用 SQL、Python 库(例如 NumPy 和 pandas)和大数据工具(例如 Hadoop MapReduce 和 Spark)进行数据挖掘、数据处理和探索性数据分析的经验。尤其是在 Python 中编程和开发算法的知识是一个主要要求。数据科学家的工作包括假设检验、回归、分类、聚类、时间序列分析、自然语言处理、特征工程和预测建模。

面试问题中测试的技术概念

在本文中,我们讨论并解决了数据科学面试问题中的一个问题,该问题需要对地址进行字符串操作和信息提取。这个例子代表了旧金山市数据科学问题的很大一部分,因为在许多情况下,候选人被要求从与城市治理相关的数据中提取信息或总结数据,如商业注册、人口普查数据、统计数据、工资单等。

在许多这样的问题中,任务包括从文本中提取信息,比如从名称中提取企业类型,从地址中提取邮政编码或街道名称,或者从职位名称中提取部门。像这样的作业需要操作字符串、构造条件语句和将方法应用于大型数据集的知识。此外,他们测试不特定于任何特定编程语言的技能,例如,识别和解决边缘情况。

数据科学面试问题:每条街道的健康检查

这个问题曾被问及到旧金山市参加求职面试的人,题目是“每条街的健康检查”。这是一个很难回答的问题,因为处理地址时处理所有的边缘情况总是很棘手。

问题链接:https://platform . stratascratch . com/coding/10181-health-inspections-per-street?python=1

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

截图来自 StrataScratch

我们被要求查找分配了风险类别值的每个街道名称的检查次数。我们将看到数据,并马上找出风险类别值。它还说我们应该输出结果和街道名称,并根据检查的数量按降序排列结果。

这已经告诉我们,我们需要从一个地址中提取一个街道名称,第二段给了我们如何做的进一步说明。它正确地意识到很难抓住街道名称的每一种写法。这里有一个例子:您的代码应该跳过只包含一个字母的街道名称,如 295 B Orizaba Ave 中名为“B”的街道。字母“B”是“门牌号”的一个元素,而不是街道名称。应该返回 Orizaba,而不是提取 b。

这个问题警告我们的是,不要简单地假设我们可以找到地址字符串中的第一个空格,并假设空格之前的所有内容都是门牌号,之后的所有内容都是街道名称。有一些边缘案例,比如门牌号为 295B 的案例,我们需要在解决方案中加以考虑。

解决问题的框架

在我们开始设计解决方案之前,让我与您分享解决任何数据科学问题的三步通用框架。考虑到压力,这对于解决面试任务特别有用,有一个系统的方法来处理任何问题是救命的,但它在一般情况下也很有用,例如在你的数据科学职业生涯中。

  1. 理解您的数据:
    a )列出您对数据列的假设,这样您就知道使用哪些列了
    b )如果您仍然对自己的数据不够了解,请查看数据的前几行(单个或多个表)。或者,如果在面试中,询问一些示例值,以便理解实际数据,而不仅仅是列。它将帮助您识别边缘情况,并将您的解决方案限制在您的假设范围内。
  2. 制定你的方法:
    a )写下你要编程/编码的逻辑步骤。
    b )确定你将使用/实现来执行逻辑的主要功能。
    c )面试官会看着你;他们会在需要时介入,确保你要求他们澄清任何模糊之处,他们还会指定你是否可以使用现成的函数,或者你是否应该从头开始写代码。
  3. 代码执行:
    a )构建你的代码,不要过于简单,也不要过于复杂。
    b )根据与面试官概述的步骤,分步骤构建。这意味着代码可能效率不高,但没关系。你可以在最后和面试官谈优化。
    c )最重要的一点是,不要在每个代码块中使用多个逻辑语句和规则,使代码过于复杂。代码块可以定义为 CTE 或子查询,因为它是自包含的,并且与代码的其余部分相分离。
    d )在你写代码的时候大声说出来,因为面试官会评估你解决问题的能力。

了解您的数据

让我们先来看看我们现有的解决这个问题的数据。通常,在面试中我们不会得到任何实际记录,相反,我们会看到有哪些表格或数据框,以及这些表格中的列和数据类型。

在这个问题中,我们可以看到我们只有一个数据框,“SF _ restaurant _ health _ violations”,但它有很多列。似乎这个数据集中的每一行都对应一次违规。最后 3 列描述了每个违规。它是在某次检查中识别的,其中检查有一些 ID、日期、分数和类型。最后,通过前 10 列确定的特定业务来识别每个违规。因为我们只是对数据做了一些假设,所以与面试官分享所有这些并与他们确认你的假设是否正确总是一个好主意。

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

截图来自 StrataScratch

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

截图来自 StrataScratch

幸运的是,我们实际上不需要担心所有这些列来解决问题。这是一个很好的实践,回到问题上来,想想哪些列可能是有用的。我们需要找到检验的数量,因此我们需要计算‘inspection _ id’列的数量。“风险类别值的分配位置”表明我们需要使用“风险类别”列过滤数据。最后,“输出结果和街道名称。”告诉我们将注意力集中在应该包含街道名称的“business_address”列上。

制定你的方法

熟悉这些数据后,重要的是要想出几个通用步骤,我们在设计这个面试问题的解决方案时会遵循这些步骤。在我们的例子中,我们可以遵循以下步骤:

  1. 编写一个从“business_address”列的字符串中提取街道名称的方法。我们需要假设地址以街道名称开头,在这种情况下,我们需要从字符串中提取第一个单词,或者以一个数字开头,后跟一个字母,在这种情况下,我们应该提取字符串的第二个或第三个单词。
  2. 有了这个方法,我们可以用它向数据集添加一个新列——街道名称
  3. 在第三步中,我们将过滤数据,只留下分配了风险类别的这些行,换句话说,只留下“risk_category”列不为空的记录
  4. 接下来,我们可以使街道名称的格式一致,让它们在所有情况下都以小写字母开头。这一步确保每个街道名称在最终输出中只出现一次。
  5. 最后一步是按照面试问题中的指示准备最终输出:
    a )我们将只有两列:街道名称和检查次数。因此,我们需要按照街道名称对结果进行分组,这样我们就可以计算每个街道名称在数据集中出现的次数。
    b

代码执行

制定了方法之后,我们现在可以实际编写将产生预期输出的代码了。我们将使用 Python 编程语言,因此我们可以假设数据存储为名为“SF _ restaurant _ health _ violations”的熊猫数据帧。Pandas 是用于查询和操作数据集的流行 Python 库。我们可以从导入开始,以便以后使用。

 import pandas as pd

现在让我们遵循我们之前制定的方法。第一步是从地址中提取街道名称的方法,所以我们可以从编写这个方法开始。现在,我们不关心数据集或任何特定的地址,我们将只编写一个 Python 函数,给定某个地址 x,它将返回街道名称。我们可以从键入以下内容开始:

 def street(x):

我们希望从 x 中提取街道名称,其中 x 是包含地址的字符串。我们可以从检查字符串第一部分的第一个字符是数字还是字母开始。如果第一部分以字母开头,我们可以假设它是一个街道名称,并返回第一个单词。我们可以使用 split()函数,当它应用于一个字符串时,会根据我们可以选择的分隔符将字符串分成几部分。

 if str(x.split(' ')[0][0]).isdigit() == True:
           # first part is a number
     else:
           return x.split(' ')[0]

让我们检查一下这段代码。我们使用 x.split(’ ‘)将我们的地址字符串分成几个部分,用空格键作为分隔符。例如,如果 x 是’ 295 B Orizaba Ave ‘,那么使用 x.split(’)会将它转换为一个列表,其中第一个元素是 295,第二个是 B,第三个是 Orizaba,第四个是 Ave。我们现在只对字符串的第一部分感兴趣,所以我们编写了 x . split(‘)[0],它对应于列表中的第一个元素,即第一个空格键之前的字符串中的所有内容。请记住,在 Python 中,第一个元素的索引是 0。在我们的例子中,它只是一个数字 295。然而,我们不仅对第一部分感兴趣,而且特别对第一部分的第一个字符感兴趣,这就是为什么我们添加另一个[0]来实现 x . split(’)[0][0]。我们现在可以使用一个函数。isdigit(),当应用于一个字符时,如果该字符是数字,则返回布尔值 True,否则返回值 False。然而,我们需要小心,因为。isdigit()只能应用于字符数据类型。但是如果我们的第一个字符确实是一个数字,我们就要冒 Python 会自动将其转换成数字数据类型的风险,例如 integer。在这种情况下。isdigit()会导致错误,因为它不能应用于整数。为了避免这种情况,我们可以通过将字符转换为字符串来确保字符被视为字符串而不是数字。这就是为什么我们有 str()函数。

所以这段代码 str(x . split(‘)[0][0])。如果字符串的第一个字符是数字,isdigit()返回 True,如果是字母,则返回 False。如果是后者,那么当地址中的第一个字符是一个字母时,我们可以假设第一个单词确实是一个街道名称,并使用 return x . split(’)[0]返回它—这样我们就输出了地址字符串中第一个空格键之前的所有内容。

在另一种情况下,当第一个字符是一个数字时,我们知道地址的第一部分是门牌号,而不是街道名称。我们将忽略它并返回第二个或第三个单词。哪一个?这取决于第二个单词是只有一个字母还是更多。如果它比一个字母长,那么我们可以假设它是一个街道名称,并返回第二个单词。否则,如果它只有一个字母,那么它就是数字的一部分,我们需要返回第三个单词。

 if len(x.split(' ')[1]) > 1:
             return x.split(' ')[1]
     else:
             return x.split(' ')[2]

在这段代码中,我们使用 len()函数返回对象的长度,在本例中是字符串中的字符数。我们也只将它应用于地址字符串的第二部分(在 Python 中索引为 1),所以我们计算第一个和第二个空格键之间的字符数。如果长度大于 1,那么我们可以返回第二个单词作为街道名。否则,我们返回第三个单词,也就是索引为 2 的那个。现在,从地址字符串 x 中提取街道名称的整个函数如下所示:

 def street(x):
           if str(x.split(' ')[0][0]).isdigit() == True:
                if len(x.split(' ')[1]) > 1:
                    return x.split(' ')[1]
                else:
                    return x.split(' ')[2]
           else:
                return x.split(' ')[0]

我们可以通过几个例子来验证这个函数是否有效。如果地址是’ 295 B Orizaba Ave ‘,那么第一个 If 语句返回 true,因为第一个字符是一个数字,第二个 if 语句返回 false,因为 B 不超过 1 个字符,所以我们返回第三部分,Orizaba,它确实是街道名称。如果地址是’ 700 Sutter St ',那么第一个 If 语句再次返回 true,因为第一个字符是一个数字。但是现在第二个 if 语句也返回 true,因为 Sutter 不止一个字母,所以我们返回 Sutter 作为街道名。最后,如果我们只输入“百老汇街”作为地址,那么第一个 if 语句返回 false,因为第一个字符不是数字,所以我们立即返回第一个单词,在本例中是“百老汇”。

现在,我们可以将刚刚编写的方法应用到数据框中:

 sf_restaurant_health_violations['street_name'] = sf_restaurant_health_violations['business_address'].apply(street)

此代码将创建一个新列“street_name ”,这样,在对“street”列应用 street()方法后,该列的内容将等于“business_address”列的内容。我们用熊猫来实现它。对“business_address”列应用()函数,并使用我们的函数名,因此将“street”作为参数。

我们已经介绍了方法的前两步。我们有从地址中提取街道名称的方法,并且我们已经将列添加到数据框中,其中包含从地址中提取的街道名称。它是“街道名称”列。下一步是过滤数据,只留下分配了风险类别的行。我们可以用下面一行代码来实现:

 assigned_risk = sf_restaurant_health_violations[]

这将创建一个新的数据框“assigned_risk ”,该数据框将根据条件仅包含原始数据框中的一些值。我们现在将在方括号内添加条件。条件是风险类别需要赋值,换句话说‘risk _ category’一栏不能说‘null’。幸运的是,有一个 Pandas 函数 notnull()可以做到这一点。因此,条件将如下所示:

SF _ restaurant _ health _ violations[’ risk _ category ']。notnull()

数据框“SF _ restaurant _ health _ violations”中的“risk_category”列不能为“null”。然后,我们可以将这个条件添加到前面的代码中:

 assigned_risk = sf_restaurant_health_violations[sf_restaurant_health_
violations['risk_category'].notnull()]

这种重复“SF _ restaurant _ health _ violations”名称的结构乍一看可能很奇怪,但这是一种完全正常的过滤熊猫的方式。

过滤结果后,下一步是确保格式的一致性。特别是,我们希望确保所有街道名称都以小写字母开头。为此,我们需要更新我们最近创建的列“street_name”。

 assigned_risk['street_name] = assigned_risk['street_name'].str.lower()

基本上,lower()函数可以应用于一个字符串,并强制第一个字母小写。我们需要使用这个构造. str.lower()来指定我们想要将 lower()专门应用于“street”列中的字符串。

我们快到了。最后一步是根据面试问题中的说明准备输出。我们需要按街道名称对结果进行分组,计算每个街道名称出现的次数,然后按降序对结果进行排序。令人惊讶的是,使用熊猫,我们只用一行代码就可以完成所有的工作。让我们从创建一个新变量“结果”开始,现在,让我们将它设置为等于我们的过滤数据框“assigned_risk”。

 result = assigned_risk

要按街道名称对结果进行分组,我们可以使用 Pandas groupby()函数。我们需要指定它应该根据哪一列对结果进行分组,在我们的例子中,我们将说“street_name”。然后,我们需要告诉它以什么方式对结果进行分组。我们希望计算每个街道名称出现的行数,这可以使用 Pandas groupby()来实现。size()函数。

 result = assigned_risk.groupby(['street_name']).size()

上面的代码将成功地对结果进行分组,但是它将只返回每个街道名称出现的次数——只有一列数字,没有街道名称。此外,“result”已经变成了一个系列 Dataframe 中的另一种数据类型,它只允许存储一列数据。我们想把它转换回熊猫数据帧,并显示街道的名称。我们可以首先使用 Pandas 函数 to_frame()将一个系列转换成一个数据帧。顺便说一下,我们可以在这里为包含违规数量的列指定一个名称,比如说“number _ of _ risky _ restaurants”——这看起来比没有名称的列要好。然后,我们还将使用一个函数 reset_index()。在此之前,Pandas 将街道名称视为索引,不会在数据框中将它们显示为单独的列。使用此函数将变回数字索引,并将街道名称显示为一列。

 result = assigned_risk.groupby(['street_name']).size().to_frame
('number_of_risky_restaurants').reset_index()

最后,我们要对结果进行排序。面试问题说根据检查次数降序排列结果。此外,我们可以添加一个二级排序规则,这样当几条街道具有相同数量的检查时,它们将按字母顺序排序。我们可以通过使用函数 sort_values()来实现这个结果。

 result = assigned_risk.groupby(['street_name']).size().to_frame
('number_of_risky_restaurants').reset_index().sort_values
(['number_of_risky_restaurants', 'street_name'])

然而,这个输出有一个问题。默认情况下,函数 sort_values()按升序对所有内容进行排序。这意味着它将数字从最小到最大排序,并将文本按字母顺序排序。我们需要它有点不同,这个问题特别要求按降序或从最大到最小排列数字。但是对于基于街道名称的二级排序,我们仍然需要字母顺序。要对此进行编码,我们只需向 sort_values()函数添加一个布尔参数‘ascending ’,并为主要规则将其设置为 False,为次要规则将其设置为 True。

 result = assigned_risk.groupby(['street_name']).size().to_frame
('number_of_risky_restaurants').reset_index().sort_values
(['number_of_risky_restaurants', 'street_name'], ascending=[False, True])

这非常长的单行代码足以产生所需的输出。下面是解决这个 Python 数据科学面试问题的完整代码:

import pandas as pd

def street(x):
    if str(x.split(' ')[0][0]).isdigit() == True:
        if len(x.split(' ')[1]) > 1:
            return x.split(' ')[1]
        else:
            return x.split(' ')[2]
    else:
        return x.split(' ')[0]

sf_restaurant_health_violations['street_name'] = sf_restaurant_health_violations['business_address'].apply(street)

assigned_risk = sf_restaurant_health_violations[sf_restaurant_health_violations['risk_category'].notnull()]
assigned_risk['street_name'] = assigned_risk['street_name'].str.lower()
result = assigned_risk.groupby(['street_name']).size().to_frame
('number_of_risky_restaurants').reset_index().sort_values
(['number_of_risky_restaurants', 'street_name'], ascending=[False, True])

此外,查看我们之前在 上发布的关于数据科学家职位 的 Python 面试问题,找到针对初学者或寻求更具挑战性任务的人的问题。

结论

就是这样,我们已经成功地写出了来自旧金山市的“每条街道的健康检查”这一面试问题的解决方案。Python 编程语言的使用让我们只用几行代码就能编写出整个解决方案,但最困难的部分可能是提出通用方法。特别是,考虑地址字符串的所有可能变化是至关重要的。当从字符串中提取信息时,尤其是从地址中提取信息时,经常会出现这种情况,我们首先需要仔细检查数据,并尝试捕捉尽可能多的边缘情况,然后还要找出如何在代码中涵盖所有这些情况。

但是,请记住,在采访中,我们通常不会得到准确的数据,只有列名、数据类型和一些例子,就像本例一样。这就是为什么,为了解决这个问题,我们需要依靠一些假设,虽然假设事情是完全可以的,但绝对重要的是要与面试官沟通清楚,让他们知道你何时做出任何假设。在编写代码时,与面试官沟通也是一个关键,这是一个很好的实践,在你编写代码时解释这些步骤,并谈论你正在使用的最重要的功能——这样你不仅向面试官展示你可以解决这个任务,而且更重要的是,你总体上掌握了编程语言。

最后,不要忘记坚持解决任何数据科学问题的框架,这将使你的面试和生活变得更加容易。同样,您从检查和理解数据开始,然后制定您的方法——解决问题所需的几个一般步骤。最后,基于这两点,你可以一步一步地编写你的代码。

最初发表于https://www.stratascratch.com

数据科学快速提示#012:用 FastAPI 创建机器学习推理 API

原文:https://towardsdatascience.com/data-science-quick-tips-012-creating-a-machine-learning-inference-api-with-fastapi-bb6bcd0e6b01?source=collection_archive---------25-----------------------

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

与你分享如何使用 FastAPI 构建一个机器学习推理 API

你好,朋友们!我们又回来了,带来了另一篇关于用 Docker 和 FastAPI 创建机器学习推理 API 的半快速文章。说实话,我写这篇文章是为了我自己。虽然我已经非常熟悉 Docker,但我个人过去一直使用 Flask 来构建我的 ML 推理 API。这并不是说 Flask 一定有什么问题,但是看起来 FastAPI 正在迅速成为行业标准。FastAPI 的一些优势包括…

  • 比 Flask 更快:说实话,我试图使用蝗虫工具演示 Flask 和 FastAPI 之间的速度测试,我发现它们的性能相当。当然,我测试的模型是一个非常基本的泰坦尼克号分类模型,所以也许我的测试一开始就不是一个好的测试。无论如何,我只是相信人们的话,FastAPI 比 Flask 快
  • 内置的 Swagger 文档:如果你不熟悉 Swagger 是什么,它是人们记录如何正确使用他们的 API 的主要行业标准方法之一。这在 Flask 中根本不存在,所以这绝对是一个受欢迎的好处。
  • 内置数据验证 : FastAPI 允许一个非常简单的方法来实现对你的传入 API 调用的数据验证,这非常好。我们肯定会在稍后的帖子中对此进行报道。

如果您以前使用过 Flask,您会发现这种向 FastAPI 的转移非常容易。这两个框架在 Python 代码中的实际实现非常相似。在本帖中,我们将创建一个 API,为经典的 Iris 数据集提供逻辑回归模型。这个模型一点也不花哨,但它将演示如何使用 FastAPI 轻松地服务于您自己的机器学习模型。

和往常一样,如果你想了解这篇文章中显示的代码,你可以在我的个人 GitHub 中找到这个

让我们开始吧!

训练虹膜模型

在我的 GitHub repo 中,我实际上已经创建并导出了 Iris 逻辑回归模型,您可以随意使用,但是如果您想训练自己的模型,下面是我为此创建的脚本:

# Importing the required Python libraries
import numpy as np
import pandas as pd
import pickle
from sklearn import datasets
from sklearn.linear_model import LogisticRegression# Loading the iris dataset from Scikit-Learn
iris = datasets.load_iris()# Converting the iris dataset into a Pandas DataFrame
df_iris = pd.DataFrame(data = np.c_[iris['data'], iris['target']],
            columns = iris['feature_names'] + ['target'])# Separating the training dataset (X) from the predictor value (y)
X = df_iris.drop(columns = ['target'])
y = df_iris[['target']]# Instantiating a Logistic Regression (LR) model
lr_model = LogisticRegression()# Fitting the dataset to the LR model
lr_model.fit(X, y)# Saving the model to a serialized .pkl file
pkl_filename = "../model/iris_model.pkl"
with open(pkl_filename, 'wb') as file:
 pickle.dump(lr_model, file)

再说一次,我们在这里没有做任何花哨的事情。因为 Iris 数据集本身是一个非常干净的数据集,所以我所做的唯一一件事就是加载原始形式的数据集,并立即将其输入到 Scikit-Learn 的逻辑回归模型中。一旦模型被训练,我们就把它作为一个序列化的.pkl文件转储出来,这就是我们将用于模型推理的精确文件。

这一节到此为止!让我们开始使用 FastAPI 来构建我们的 API。

用基本 GET 端点实例化 FastAPI

好的,在我们开始之前,我们需要从 PyPi 快速安装我们将要使用的 Python 库。幸运的是,这非常简单:

pip3 install fastapi uvicorn

安装fastapi对你来说可能是显而易见的,但是你可能对uvicorn很好奇。Flask 和 FastAPI 都需要一种网关接口。Flask 需要一个类似于gunicorn的 WSGI 服务器,而uvicorn本质上是 WSGI 的“精神”继承者,也就是所谓的 ASGI 服务器。如果这有点令人困惑,请不要担心。你需要知道的主要事情是,当我们在终端中启动 FastAPI 时,我们实际上将使用uvicorn来执行它。

正如你在我的 GitHub 脚本中注意到的,整个 API 非常容易上手。让我们从一个非常基本的 GET 端点开始。与 Flask 一样,FastAPI 利用位于函数之上的 Python 装饰器来提供不同的端点。这里的语法将用这个单一的 GET 端点创建一个超级简单的 API。

from fastapi import FastAPI, Request# Instantiating FastAPI
api = FastAPI()# Defining a test root path and message
@api.get('/')
def root():
  return {'message': 'Hello friends!'}

信不信由你,这实际上是一个全功能的 API。它显然什么都不做,但是如果您想看看它目前的运行情况,让我们启动 FastAPI 来看看这个小东西的运行情况。为此,我们将执行以下命令:

uvicorn api:api --host 0.0.0.0 --port 5001 --reload

这是在寻找一个名为api.py的 Python 文件,然后寻找一个名为api的 FastAPI 实例。然后我们将它绑定到端口5001上的主机0.0.0.0,最后一个--reload标志只是在您更改api.py脚本时重新加载您的 API。这对于测试来说很好,但是我建议您在生产环境中去掉最后一个标志。

现在您的 API 在一个终端窗口中运行,打开另一个终端窗口并执行下面的curl命令:

curl 0.0.0.0:5001

因为我们没有指定任何路径,它将默认为主要的'/'路径,因此应该返回我们的小“Hello friends!”给你回信息。整洁!现在,打开浏览器,前往 http://localhost:5001/docs。这是你应该看到的:

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

作者截图

正如您所看到的,Swagger 已经在这里编目了我们的基本 GET 端点,甚至允许您做一点测试触发器来测试这个端点。现在这里没有太多内容,但是随着我们在这篇文章中的继续,您将看到这是如何成为一个非常强大的工具,用于快速记录您的机器学习推理 API。不错!

好了,现在我们的 API 已经有了一个很好的开始,让我们继续用 Iris 模型创建一个基本的推理端点。

基本推理终点

好了,我们现在准备开始围绕我们在前面部分中训练的 Iris 模型构建一个端点!首先,让我们首先导入我们需要的其他 Python 库,并加载模型本身:

import pandas as pd
import pickle# Loading in model from serialized .pkl file
pkl_filename = "../model/iris_model.pkl"
with open(pkl_filename, 'rb') as file:
 lr_model = pickle.load(file)

好了,这里的lr_model对象与我们之前针对 Iris 数据集训练的逻辑回归模型相同。就像我们处理任何其他 Python 脚本一样,我们将通过调用模型的.predict()函数将数据传递给该模型进行推理。

对于 Flask 用户来说,这是我觉得有点奇怪的地方。我不想解释 Flask 是如何工作的,但它就是…与众不同。在 Flask 中,我习惯于直接从请求体获取 JSON,这就是我们在这个基本端点中要做的。(剧透:有一个比这更好的选择,我们将在下一节演示,但如果您想尽可能地与 Flask 保持一致,这就是您要寻找的模式。

这里是我们的/basic_predict端点的完整代码:

from fastapi import Request# Defining the prediction endpoint without data validation
[@api](http://twitter.com/api).post('/basic_predict')
async def basic_predict(request: Request):

 # Getting the JSON from the body of the request
 input_data = await request.json()

 # Converting JSON to Pandas DataFrame
 input_df = pd.DataFrame([input_data])

 # Getting the prediction from the Logistic Regression model
 pred = lr_model.predict(input_df)[0]

 return pred

FastAPI 是围绕 Python 新的异步特性构建的,因此我们在这里看到了asyncawait关键字。为了实际使用请求体中的 JSON,我们必须首先从 FastAPI 导入Request类对象,然后将它作为参数传递给这里的basic_predict函数。(再说一次,这可能不是你在 Flask 中所习惯的。)幸运的是,从这里可以很快地从我们的虹膜模型中得到预测的推论。我们从请求体中取出 JSON,将其转换成 Pandas 数据帧,将数据帧传递给逻辑回归模型以产生一个推断,最后将该推断返回给用户。

好吧!现在我们来试试这个。为了方便起见,我创建了一些 shell 脚本来快速测试我们的端点。它们可以在这个 GitHub repo 目录中找到。您可以简单地通过运行bash script_name.sh来执行这些。例如,运行bash basic_predict.sh脚本实际上是在做以下事情:

curl --request POST \
--header 'Content-Type: application/json' \
--data [@test_json/test_data](http://twitter.com/test_json/test_data).json \
--url [http://0.0.0.0:5001/basic_predict](http://0.0.0.0:5001/basic_predict)

通过我们的模型运行这个脚本应该会返回一个“0.0”值。不错!现在让我们回过头来检查一下我们的 Swagger UI,看看事情发生了怎样的变化。下面是您现在应该看到的:

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

作者截图

除了我们原来的 GET 端点颜色为蓝色之外,我们现在看到我们的基本 predict POST 端点颜色为绿色。因为这是一个非常基本的端点,所以您会注意到这里没有多少文档。这是可以增强的,我们不仅要用我们的最终端点来增强它,还要添加最后一个非常酷的功能:数据验证。

带数据验证的推理端点

好了,虽然我们的基本预测端点如预期的那样工作,但我们现在将通过向传入请求添加数据验证来提高性能。数据验证确保我们的模型被正确地传递期望值。如果调用者传递了不正确的内容,则向用户返回一个响应,告诉他们由于数据验证错误,请求无法处理,并且还向用户具体描述了哪里出错了。

FastAPI 通过与一个名为 Pydantic 的框架合作,在他们的BaseModel类的基础上构建 Python 类来实现这一点。对于我们的 Iris 数据集,下面是我们将为验证构建的数据模型:

from pydantic import BaseModel # Creating the data model for data validation
class Iris(BaseModel):
 sepal_length: float
 sepal_width: float
 petal_length: float
 petal_width: float

(注意:默认的 Iris 数据集以不同的方式命名其特征,并包含空白。我一辈子也想不出如何用包含空格的特性名称创建这个 Pydantic 数据模型,所以我适当地更改了特性的名称。这也反映在我们的测试 JSON 文件中。)

我在这里描述的验证非常简单。使用这个Iris数据模型的端点期待一个具有这四个特性的请求,并且所有这些特性都应该是float数据类型。这是非常基本的,但是您可以通过数据验证进行深入研究。您甚至可以具体定义每个特性的期望值范围。例如,如果您定义了一个期望值范围在 0 到 366 之间的days特性,那么当用户试图传递一个值为 367 的days时,FastAPI 将返回一个验证错误。

为了在端点中实际使用这个Iris数据模型,下面是它的语法:

# Defining the prediction endpoint with data validation
[@api](http://twitter.com/api).post('/predict')
async def predict(iris: Iris):

 # Converting input data into Pandas DataFrame
 input_df = pd.DataFrame([iris.dict()])

 # Getting the prediction from the Logistic Regression model
 pred = lr_model.predict(input_df)[0]

 return pred

这与我们的/basic_predict端点非常相似,但是现在,FastAPI 将自动传递传入的请求,并在我们的模型处理它之前对它执行数据验证。

让我们付诸实践吧!为了方便起见,我提供了两个测试 JSON 文件:一个包含正确的信息,另一个包含错误的信息。好的那个看起来是这样的:

{"sepal_length":5.1,"sepal_width":3.5,"petal_length":1.4,"petal_width":0.2}

这是坏的那个的样子:

{"sepal_length":"dkhundley","sepal_width":3.5,"petal_length":1.4,"petal_width":0.2}

正如你所看到的,我把sepal_length改成了我名字的string值,这应该无法通过我们设置的数据验证,因为我们期望的是float值。通过用这些坏数据发出 curl 命令(可以用我的test_bad_predict.sh脚本完成),FastAPI 告诉我们:

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

作者截图

我的截图被剪掉了一点,但是你可以看到 FastAPI 指出sepal_length应该是一个浮点数。如果您正在调用 API,而您自己不是开发人员,那么这非常清楚地描述了您出错的地方。不错!

传入正确的数据(可以用我的test_predict.sh脚本来完成)会产生我们期望的推断值。

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

作者截图

好吧,让我们最后看一眼我们的招摇文件来结束这篇文章。你现在应该看到一些新的东西了!首先,看一下“模式”部分:

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

作者截图

在这里,您可以看到我们的Iris数据模型,包括所有预期的特性和预期的数据类型。现在,让我们来看看我们的/predict端点文档:

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

作者截图

与我们的/basic_predict端点相比,我们现在可以看到一些额外的东西。也就是说,我们现在看到了一个端点所期望的样本,此外,FastAPI 提供了一个虚拟数据集,您可以从 Swagger UI 随时随地对其进行测试。非常好!

朋友们,今天的帖子到此结束!尽管我很喜欢 Flask,但我个人将来会将 FastAPI 用于我所有的机器学习模型。我很清楚为什么数据科学社区很快采用 FastAPI 而不是 Flask。这是一个非常简洁、功能丰富的工具!感谢你查看这篇文章。请继续关注机器学习和数据科学的最新进展。

一个方便的数据科学相关资源列表,用于学习、面试和职业发展

原文:https://towardsdatascience.com/data-science-resources-for-learning-interviewing-and-professional-development-4530898d789c?source=collection_archive---------14-----------------------

学习编码,为面试做准备,以及为初学者提供其他有用的数据科学资源和信息

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

数据科学家本世纪最性感的工作

大家好,我整理了一份有用的网站和信息列表,以帮助您处于该过程的任何阶段,无论您是开始数据科学之旅、面试公司、谈判报价,还是只是希望继续了解更多信息。

这包括面试准备资源、面试后薪酬研究等。随着我在旅途中找到更多的资源,我也会继续更新这个列表。

以下是您将在下面找到的目录:

1。对于对数据科学感兴趣的初学者

a)学习 Python、R 和 SQL 的免费资源

b)为统计释放资源

b)学习数据科学的付费渠道

c)机器学习资源

d)在哪里可以找到数据集

2。面试准备

a)个人守则实践

b)现场代码实践

c)备忘单

3。求职中的

4。岗位面试

a)薪酬信息

b)谈判

5。职业发展

a)实现出色的可视化

b)学习技巧和窍门/其他很酷的东西

对于对数据科学感兴趣的初学者

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

任何人都可以做数据科学。安·trần 在 Unsplash 上拍摄的照片

如果你认为这是你想从事的领域,作为一个开始,看看这个非常酷的信息图名为“通过 8 个简单步骤成为数据科学家”。

你的旅程将占用大量时间和个人投资,所以如果你准备好了,这里有一些资源供你培养数据科学家的技能。编码、SQL、机器学习算法和统计学是你需要学习的基本技能。

学习 Python、R 和 SQL 的免费资源

有很多免费的资源可以教初学者如何用 Python 和 r 编程,谷歌搜索会给你很多结果。我在下面列出的是我认为能一步一步带你走过的网站。

当你开始做项目时,看看我的文章Git的简单入门指南可能会对你有所帮助。Git 是一个用于项目的版本控制软件。

免费资源统计

学习数据科学的付费渠道

如果独自练习不太适合你的学习风格,还有其他选择。你可以参加训练营或者获得硕士学位。

我实际上参加了旧金山的一个名为激励的数据科学训练营,那是一个课堂环境,我非常喜欢面对面的互动。如果你最终选择了激励,你可以用我作为推荐人,这给了你学费折扣。

也有网上训练营,有些会保证你会得到一份工作。做你的研究,找到适合你的,因为每个训练营都有优点和缺点。有些提供工作保障。有些可能会提供指导。例如,目前我是 Springboard 的分析训练营的导师,我每周与一名学生进行半小时的电话会谈,回答问题并复习课程。如果你想查看跳板的节目, 点击这里

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

照片由元素 5 数码Unsplash 上拍摄

如果你有时间和金钱,如果你想更深入地了解这些材料,硕士课程可能是一个选择。训练营往往提供更多的广度而不是深度。我目前正在乔治亚理工学院攻读硕士学位,这是一个比其他大多数项目都更好也更便宜的选择。

如果你对训练营或我的硕士项目有任何疑问,欢迎在下面发表评论。

我想指出的另一件很酷的事情是 Coursera 开始的一些新东西。一旦你在编码方面有了良好的基础,你可以通过尝试一个指导的项目来练习,在两个小时内由一个主题专家学习一项与工作相关的技能。注意,这不是免费的。https://www.coursera.org/courses?query=guided%20projects

机器学习和其他资源

对于那些对机器学习感兴趣的人来说,这里有一些有用的网站。

一旦你学会了机器学习模型,你就可以开始参加比赛了。Kaggle 是一个很好的方法来实践你在实际问题中学到的东西。https://www.kaggle.com/competitions

哪里可以找到数据集

如果您正在寻找用于顶点项目的数据,这里有一个列表,可以作为一个很好的起点。

面试准备

数据科学职位的面试与其他职位有很大不同,需要做大量的准备工作。

一般来说,会有多轮面试,包括带回家的作业、招聘人员面试、技术面试和现场编码面试。

下面是一些你可以练习 SQL 或 Python 或其他编程语言的网站。我还附上了一些备忘单,可能对你的准备工作或工作有用。

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

我准备好面试了吗?假的!问题是,这次面试我准备好了吗?斯蒂芬妮·勒布朗在 Unsplash 上的照片

顺便说一句,我听说盖尔·麦克道尔的《破解编码面试》这本书非常有帮助。它包含了大型科技公司提出的近 200 个编程问题和答案。

个人代码实践(顺便说一下,这些都是免费的)

  • Leetcode 有超过 800 个问题可供你选择,它们有不同的难度,从简单到中等到困难不等。【https://leetcode.com/problemset/all 号
  • Codewars 有点像一个结构化的程序,当你完成挑战时,你会经历不同的等级。https://www.codewars.com/
  • HackerRank 是一个竞争性的平台,在这个平台上,你的解决方案将根据准确性进行评分,你将与其他用户进行比较。https://www.hackerrank.com/

现场代码实践

  • 我建议您尝试一下,与您的同事一起练习现场模拟面试和编码问题。这让它感觉更像一个真实的面试环境,这将是一个很好的练习。 Pramp 免费使用。https://www.pramp.com/#/
  • 或者,你也可以和你申请的公司的人一起练习模拟面试。(免费,但目前新冠肺炎需要付费。)https://interviewing.io/
  • 当然,不要忘记练习在白板上编写问题代码。随便找个朋友冒充面试官!

备忘单

为了提高你的工作效率,有备忘单作为参考总是好的。这里有一些我喜欢的。

SQL

R

Python

杂项

在找工作

如果你准备好开始申请和面试,你可以先去热门网站,比如 Indeed、ZipRecruiter 和 Google,也可以在这里查看这些资源。

  • 获得顶级科技公司的推荐【https://repher.me/
  • 在这里寻找创业工作【https://angel.co/
  • 轻松申请数百家使用 LinkedIn 的公司https://www.linkedin.com/jobs/linkedin-jobs/
  • 别忘了,你最好的选择是向你的朋友和家人寻求推荐!

最后,我听说了一个名为 Blind 的新网站,通过验证的员工可以匿名提问和回答问题。你可以对文化进行研究,也许还可以了解薪水。https://www.teamblind.com/

我得到的一个建议是,先从你不感兴趣的公司开始实习,把你真正感兴趣的公司留到你实习之后。

面试后

既然你得到了一份工作,你准备好谈薪水了吗?

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

这是什么,蚂蚁的工资?水晶钻Unsplash 上拍照

薪酬信息

公司给这种职位的工资是多少?做你的研究,这样你就知道市场的价格。

我通常从 Glassdoor.com 开始,看是否能找到薪水信息。其他几个提供评估的网站包括https://www.salarylist.com/https://www.payscale.com/

这里有几个我认为也不错的网站

谈判

谈判总是值得的!**照做就是了。**问问真的没坏处。

专业发展

学习是一个持续的旅程。为了更好地创建可视化,获得新知识,或者只是学习技巧和诀窍,请查看下面的一些内容。

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

Woohoo,职业发展。Jimmy Conover 在 Unsplash 上拍摄的照片

制作出色的可视化效果

学习技巧和窍门/其他很酷的东西

  • 每周一次的 Python 播客,包含采访、编码技巧以及与来自 Python 社区的嘉宾的对话https://realpython.com/podcasts/rpp/
  • 使用 R 软件的博客作者的博客集【https://www.r-bloggers.com/
  • 生成虚拟 JSON 数据【https://www.mockaroo.com/

如果你有任何问题或任何网站/信息想与他人分享,请在下面留言!

祝您的数据科学之旅好运!

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

你能行的!照片由 Unsplash 上的 Prateek Katyal 拍摄

数据科学短片:分解

原文:https://towardsdatascience.com/data-science-shorts-decomposition-a40bdd6826aa?source=collection_archive---------29-----------------------

有时用最简单的方法也能获得可观的收益

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

(来源:https://pixabay.com/)

在一系列短文的第一篇中,我想概述一下关于输入数据的关键见解:分解我们的训练特征并提取组成它们的更基本的特征,这使我们能够大大提高模型的预测质量。

为了说明我们的观点,假设我们正在尝试生成一个任意时间序列的未来值的预测。为了简单起见,我们将使用线性模型来提供预测。这个概念对于更复杂的模型也是有效的。

从线性模型生成预测可以通过将时间序列训练数据视为特征空间内的向量集合来完成。如果我们将每个向量的标量值视为时间的函数,我们可以拟合回归模型,通过沿回归线外推来预测该特征向量在未来任何时间的值。然后,可以将每个特征的未来值作为因子,使用第二个回归模型预测目标变量(即预测目标),这次是通过沿回归线插值这些值。

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

第一个回归模型(左图)让我们可以将每月的水果销量作为时间的函数进行外推。这允许我们使用第二个回归模型(右图)将收入作为水果销售的函数进行插值。(图片由作者提供)

例如,我们可以使用售出的水果数量作为训练数据来预测杂货店的月收入。我们可以扩充训练数据(滞后数据、非线性变换……),但这些都源于一个单一的特征:我们卖了多少水果。在训练第二个回归模型时,我们收敛到一个等式,该等式将收入表示为销售水果的函数:

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

线性回归模型的标准公式

这就是我们的见解——水果销售可以进一步细分。例如,如果我们的商店卖橘子和甜瓜,我们的水果总销售额将是卖出的橘子数加上卖出的甜瓜数。

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

水果销售额是橙子和甜瓜销售额的总和

即使是简单的水果种类分解也会显示出不同的季节模式。橙子的销售高峰在冬天,而甜瓜的销售高峰在夏天。但是将橙子和甜瓜的销售数据视为一个特征迫使模型赋予它们相同的权重:

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

请注意,β1 在等式的右侧出现了两次——如果不进行分解,模型无法学习橙子和甜瓜销售的单独权重。

通过分解水果销售,模型可以为每个特征分配不同的权重,从而提高预测质量:

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

分解允许我们分配单独的权重。

在我工作中使用的样本数据集(B2B 营销数据-通过与销售团队的互动次数预测新客户)上测试这一点,我们可以将通过互动总数的预测与通过每次互动发生的渠道(例如 LinkedIn、直接呼叫……)细分的预测进行比较

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

左图:通过与销售团队的互动次数预测 B2B 客户获取量。右图:同样的预测,将互动次数考虑在内,按渠道分解。(图片由作者提供)

结果显示,仅通过分解我们的数据,预测质量就提高了40%(使用平均-平均比例误差测量)。整洁!

感谢阅读,敬请关注本系列的后续文章:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值