TowardsDataScience 博客中文翻译 2019(二百五十三)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

如何工程贝叶斯比率特征?

原文:https://towardsdatascience.com/how-to-engineer-bayesian-ratio-features-548b9862446b?source=collection_archive---------32-----------------------

这样我们的机器学习模型就可以区分 1 / 2 和 50 / 100。

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

Photo by Jeffrey F Lin on Unsplash

假设我们想要建立一个机器学习模型来预测足球点球大战的获胜者。在我们拥有的关于不同足球运动员的数据中,有点球得分点球未遂。遵循传统智慧,我们设计了这个特征

*penalty_success_rate* = *penalties_scored* / *penalties_attempted*

然而,由于点球和点球决胜并不经常发生,我们对这一新功能有以下问题:

  • 有些球员从来没有罚过球,所以他们的点球成功率是不确定的。
  • 对于之前正好罚过一次的玩家,他们的 penalty_success_rate 不是 100%就是 0%。这两个数字都不能反映球员获得下一个点球的概率,并且会误导我们的机器学习模型。(作为参考,世界杯点球大战的平均点球成功率约为 70% )
  • 当我们用新数据更新 penalty_success_rate 时,对于只接受了几次处罚的玩家来说,这些值可能会大幅波动。例如,如果一名球员罚进了第一个点球,但错过了第二个,他的特征值将从 100%大幅下降到 50%。这可能会导致模型性能不稳定。
  • 最后,我们希望我们的特征考虑成功率证据的强度。2 分之 1 的记录仍然属于一个非常好的点球手,但是一个 100 分之 50 的记录的球员几乎肯定不擅长点球。但是 penalty_success_rate 的公式对两种情况都给出了 50%,无法区分。

贝叶斯方法

贝叶斯统计解决了上述所有问题。天真地说,在贝叶斯框架内,首先给玩家一个初始特征值,对应于我们关于玩家的先验知识。然后当我们接收到新的数据时,我们逐渐更新特征值。只有当我们接收到足够多的数据时,新值才会与初始值有很大的偏差。

我们的贝叶斯特征的公式是

*bayesian_penalty_success_rate* = 
        (*penalties_scored* + α) / (*penalties_attempted* + α + β)

其中α和β是我们需要选择的超参数。直觉上,我们可以把α和β理解为我们分别给予点球得分和罚失的“领先”数量。

公式的动机

因为我们只关心点球是进了还是没进(而不是怎么进的),所以我们可以用二项式分布来模拟结果。然后,用贝塔分布来模拟球员得分的概率是自然和方便的,贝塔分布是二项式似然函数的共轭先验。

上面的公式是贝塔分布的平均值

Beta(*penalties_scored* + α, *penalties_missed* + β)

其中点球 _ 未进 = 点球 _ 未遂 - 点球 _ 进球

具体的例子

让我们选择α = 7,β = 3,并考虑一个之前从未罚过球的球员。

  • 最初,处罚 _ 得分处罚 _ 未遂均为 0。因此
    贝叶斯 _ 惩罚 _ 成功率 = (0 + 7) / (0 + 7 + 3) = 0.7
  • 假设我们的玩家第一次罚分:
    Bayesian _ penalty _ success _ rate=(1+7)/(1+7+3)≈0.7272
  • 然后我们的玩家错过了她的第二次惩罚:
    贝叶斯 _ 惩罚 _ 成功 _ 率 = (1 + 7) / (2 + 7 + 3) ≈ 0.6667
  • 最后,假设我们的玩家最终的总战绩是 100 分中的 50 分:
    贝叶斯 _ 惩罚 _ 成功率 = (50 + 7) / (100 + 7 + 3) ≈ 0.5182

我们看到Bayesian _ penalty _ success _ rate总是定义良好。它的值在收到新数据时会逐渐变化,并且它需要强有力的证据来证明该值明显偏离初始值。

如何选择α和β

  • 贝叶斯 _ 惩罚 _ 成功率的初始值为α / (α + β)。我们可以选择α和β,使得α / (α + β)等于全局平均惩罚成功率。这对应于用平均值替换缺失值的常见做法。

在满足上述等式的所有对(α,β)中,我们可以使用以下方法选择一对:

  • 查看 beta 分布的不同百分位数,看看它们是否与你的领域知识相匹配。
  • 决定多少数据算作强有力的证据。例如,假设我们做了一些探索性的数据分析,发现前 5 个点球得分的球员最终职业生涯点球成功率都在 82%以上。因此,我们可能希望选择α和β,使
    (5 + α) / (5 + α + β) >为 0.82
  • 对数据进行聚类,看看是否有解释聚类的α和β。例如,如果 3 个记录中有 2 个,7 个中有 5 个,11 个中有 8 个的玩家表现出相似的特征,我们可以选择α = 7,β = 3,分别产生特征值 0.6923,0.7059 和 0.7143。

一般来说,较小的α和β意味着我们的先验知识较弱,新数据将对β分布产生较大影响,从而影响我们的特征值。

一个具体的例子

  • 首先,我们希望α / (α + β) = 0.7,这是世界杯点球大战中的平均点球成功率。

在所有满足α / (α + β) = 0.7 的不同值中:

  • 对于α= 70 °,β= 30 °,β(70,30)的第一百分位是 0.5887。这转化为一个先验知识,即,有 99%的可能性,我们的球员的下一个点球得分的概率至少是 58.87%。这对一个从未罚过球的球员来说似乎太高了。因此,我们将拒绝这一对价值观。
  • 对于α = 7,β = 3,β(7,3)的第 1 和第 99 百分位分别为 0.3437 和 0.9467。这意味着有 98%的可能性,我们的玩家的概率在 34.37%和 94.67%之间,这比上面说的有意义得多。

另外,我们希望(5 + α) / (5 + α + β) > 0.82,因为关于球员前 5 个点球全部进球的探索性数据分析。

  • 对于α = 7,β = 3,(5 + 7) / (5 + 7 + 3) = 0.8 小于我们想要的。
  • 对于α = 3.5,β = 1.5,(5 + 3.5) / (5 + 3.5 + 1.5) = 0.85 满足我们的条件。

快速检查一下β的百分位数(3.5,1.5)看起来也不错,所以我们将选择α = 3.5,β = 1.5。

备注:通常有很多对(α,β)满足我们的条件。通常,它们的相关特征以类似的方式对我们的机器学习模型做出贡献,所以我们可以简单地选择其中一个。

常见问题

问:α和β必须是整数吗?

答:不需要。唯一的要求是它们是正实数。

问:我们可以为不同的玩家选择不同的α和β吗?

答:是的。回想一下,α和β定义了描述我们先验知识的β分布。很可能我们对不同的球员有不同的先验知识,例如前锋通常擅长点球,而后卫则不然。

问:上面的贝叶斯特征公式使用了 beta 分布的平均值。我们可以使用其他统计数据(如标准差)来定义新特征吗?

答:是的。我们可以很容易地在维基百科上找到这些公式。

问:如果我们已经在我们的机器学习模型中使用 penalty_success_ratepenalty _ scored、penalty _ attempted,那么创建这个贝叶斯特征是否有益?例如,为了区分 1/2 和 50/100,我们的模型可以简单地使用 penalties_scored 特性。

答:是的,这样做还是有好处的。假设我们开始时只有两个特征罚分 _ 得分罚分 _ 未遂。即使一个足够复杂的模型可以做除法,我们仍然会设计 penalty_success_rate 特性来使我们的模型学习得更好。工程我们的贝叶斯特征是一样的。

进一步阅读

  1. 这是一篇以棒球为例的关于 beta 发行版的博文。
  2. 威尔逊评分区间也可用于对小样本量的成功概率进行良好的估计。

如何评价 B2B 行业营销对销售的整体影响?🤑

原文:https://towardsdatascience.com/how-to-evaluate-marketing-in-the-b2b-retail-industry-5a183510006?source=collection_archive---------29-----------------------

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

Photo by Merakist on Unsplash

#营销# b2b #数据科学#归属#购买行为

本文旨在解决 B2B 行业的营销归因问题,其中客户有购买频率(家具,it 材料等)。

营销归因

如果你是 B2B 行业的营销人员,你可能很难找到正确的指标来评估你的活动对销售的影响。有时营销活动可以促进销售,有时可以向销售团队介绍新客户,有时客户会直接致电销售团队,而不会受到任何营销活动的激励。

处理这种销售和营销与客户互动的大熔炉的一个众所周知的方法是利用渠道&由机会产生的收入,这些机会开始于通过营销活动中的行动号召产生的线索。这些都是很好的指标,但是您可能想要创建新的指标来查看整体情况,例如对客户群销售的支持和协助。这是为什么呢?因为,你可能错过了一部分你也影响了的收入和渠道,这一部分可能是巨大的。

让我解释一下,在某些时候,潜在客户会转化为分配给销售代表的客户。因此,在一次活动中,每当向他们发出行动呼吁时,他们可以:

  • 转换并进入营销漏斗,将他们重新引导到一个队列中,有望引导到他们的销售代表。
  • 直接打电话给他们的销售代表。

简而言之,如果您使用每当客户或潜在客户点击您的活动行动号召时创建的线索标识符来评估营销对销售的影响,那么您主要是在评估您的部门将新的潜在客户转化为客户的能力。

影响管道&收入

T 这些是基于归因问题的旅程方法的简单指标,旨在描绘营销可以获得信贷的机会。

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

A simple attribution model

上图所示的方法在一定程度上运行良好。如果客户流失,去购买他的竞争对手的家具,然后决定再次购买你的业务,下面的错误归因问题将会发生。

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

A simple representation of the attribution problem

在上图中,你可以清楚地理解我们正在处理的问题:每当在与你的活动进行一次或多次互动后产生管道,你都会将其归因于营销努力,即使这没有意义。

每个客户都有自己的购买频率,如果你能接近它,你就知道在客户层面上,将机会归因于之前的营销活动是否有意义。

为您的机会创建受影响的标志(python 语言)

1.导入库

2。负载

首先,从 salesforce 或任何其他 B2B CRM 加载所有已关闭的机会。在这些字段中,您只需要三个字段:客户 id、机会 id、结束日期(如果您在此字段中有许多 NAs,您可以用最后修改日期来替换它们😉).

3。计算购买频率

您可以通过计算帐户级别的连续机会之间的时间范围来计算购买频率。

你应该保留每个客户的第一次机会。我们当时对客户知之甚少,因此我们无法知道机会的创造是否受到营销的影响(我们可以,但不是使用这种方法,而是使用线索生成分析),他可能与营销活动互动过多次,目的是创造机会,但最终在您的企业为他创造第一个机会之前就去了竞争对手那里。根据您的关注点,我们将在后面看到如何处理这些问题。

现在,从这些时间范围,你可以使用 K 均值算法,推断出一些关于你的人口购买行为的有趣行为。

4。找到拟合数据的最佳聚类数&

K-means 算法是无监督的模型,它从一维或多维(结构化)数据中形成组。核心概念是根据两个规则形成组:

  • 每个点到其聚类质心的距离被最小化。
  • 这些点到其他簇的质心的距离被最大化。

为了找出你应该形成多少个聚类,你可以计算一个聚类数范围的 SSE (误差平方和= >点到它们的组均值的距离)和/或剪影分数

一旦找到了最佳的聚类数,就可以训练模型,确保多次运行拟合过程,并选择 SSE 最低的版本,否则您的算法可能会收敛到局部最优。完成后,您可以预测每个计算时间范围的聚类。

为了让定义每个聚类的值具有完整的意义,我们应该根据它们的平均值对它们进行重命名。聚类“0”应该是包含较慢购买频率的聚类,而聚类“k”应该是包含最快购买频率的聚类。

5。在账户级别标记购买频率群的变化

在客户层面,在连续的机会之间,购买频率群变得更慢是一个时期流逝的迹象。

对于每个客户,您可以在失效期后的第一个机会上轻松标记失效期(也就是从一个集群到另一个集群的变化,由连续机会之间较慢的平均购买频率定义)。

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

6。创建一组临时的假数据点来表示错过的转换

为了避免出现的错失归因问题,你可以利用目前收集的信息,创建一组与错失机会相对应的虚假记录。为此,您只需选择所有被标记的机会,并将它们的购买频率分别除以最后一个机会的聚类平均购买频率,这将为您提供在逝去期间错过的机会的近似数量。

对于每个标记机会,迭代错过的转换数,每次增加在先前机会日期的数据集中错过的转换的新观察,加上其分类的平均购买频率乘以迭代器索引。为所有创建的错过的机会分配一个唯一的机会 id。

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

7。处理客户的首次机会

您可以在每个帐户的第一个机会放回。根据分析结果,您还可以假设您无法理解第二次销售之前的任何购买行为,将他们排除在分析之外,并使用其他指标来评估营销能力,以转化新的潜在客户。如果你这样做,不要忘记正确过滤你的营销数据集。

8。将受影响的标志映射到机会

引入营销参与数据,并将其叠加到机会数据集中。按客户和日期对数据集进行排序,并在客户级别向后传播机会 id。

此外,禁止错过机会和机会结束日期与其结束日期之间的约定。正如图中所示,这些业务可能会引入有偏见的归因,这是归因问题的一个简单表示。

根据机会 id 进行分组,如果您获得的观察数量大于 1(则您在机会之前有营销互动),您可以将标志“受影响”归属于该机会。

现在,对于每个机会,您都有一个标志,可以用来评估受影响的渠道和收入。

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

您可以在我的 Github 上找到本文中的所有代码。

最后的想法

在提议的实现中,我使用了机会结束日期,假设结束日期和创建日期相对接近。虽然在某些行业可能是这样,但并不是所有行业都是这样。如果您的业务机会结束日期和创建日期相差很远,一个解决方案是将结束日期用于除步骤 8 之外的所有流程,在步骤 8 中,您可以在(实际)业务机会中更改创建日期的结束日期。

如果您觉得这很有趣,并且有一些改进的想法,请联系。总有改进的余地。

如何评估潜在客户-数据科学成熟度

原文:https://towardsdatascience.com/how-to-evaluate-potential-clients-data-science-maturity-bd4714920988?source=collection_archive---------24-----------------------

可操作的清单✅

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

Photo by Amogh Manjunath on Unsplash

好消息!数据科学技能的市场过去是,现在是,而且很可能会继续是非常好的。

在供给方面,训练营和 MOOCs 正在彻底改变教育,并将继续让众多来自不同背景的人才分享数据经济的战利品。从博士项目出来的聪明的学术头脑有一个奇妙的和真实的机会来建立改变生活的商业解决方案。

你是这样的一个人吗?你在寻找新客户吗?从新雇主开始?小心——寻找正确的事情,以确保该项目将是一个成长、贡献的机会,并且是一个值得骄傲和满意地回顾的事情。你的环境是决定你轨迹的一个极其重要的因素。

随着应用数据科学在商业上的成功,该领域吸引了相当程度的宣传,这是很自然的,不幸的是,这反过来又导致了各种不良后果。对于希望培养或雇佣人才的组织来说,这通常意味着筛选态度或准备有问题的候选人。对于数据科学专业人员—与缺乏组织准备和数据科学成熟度的客户或雇主打交道。这篇文章旨在帮助专业人士评估组织。

症状🤕

它们有各种各样的风格——从战略和文化的,到实际的。它们会是什么呢?

过度“利用 AI 和机器学习”,只在 PowerPoint 幻灯片上?“这将是一项巨大的人工智能计划”,尽管没有人知道如何实现,或者是否真的需要人工智能?
也许是“带后缀另存为”这种古老的版本控制技术?
你坐在椅子上的时间比你交付的东西更有价值?
数据管理和数据质量缺乏流程?
可怕的临时隐私保护措施不起作用,反而会减慢工作速度?每个项目都从编写相同的低级例程开始?
定制 CSV 阅读循环?
以 Excel 和电子邮件为中心的工作流程?
Python 2.6?

是的,这是一些症状。问题是,在你开始之前,或者之后相当长一段时间,你都不会看到很多。那是除非你仔细看。

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

Photo by Drew Coffman on Unsplash

请注意,风险很高。一个无心的错误判断很可能导致一个有着花哨头衔的实习生的不稳定地位。其职责包括全栈开发、监督部署,以及定期帮助同事解决 Excel 格式问题。也不学习。滚出我的草坪!

另一方面,期望客户尽善尽美的态度是不合理的,总有一些需要补充和改进的地方。努力弄清楚是你的责任。培养有益的习惯和过程是你的责任。这包括为改善你的环境做出贡献。

但是你做你的工作的条件存在吗?你将承担什么额外的任务?你想接受他们吗?他们让你走上了你想要的学习轨道吗?你一天、一周、一年的大部分时间都在工作。工作应该充满乐趣和自豪感——这取决于你,而不是其他任何人。话虽如此,你需要一定的条件。大多数公司都有合规流程。为什么没有自己的呢?

让我通过一些测试和问题来了解情况。

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

Photo by Glenn Carstens-Peters on Unsplash

清单

  1. **策略。**公司有战略吗?他们是否有特定的目标来使自己处于持久的优势?他们有可行的成果计划吗?他们是否清楚地表达了他们期望团队和你在未来 6 个月或 12 个月内取得的成果?
    对此要非常小心。没有明确性或战略就意味着没有责任和高度的不确定性,这将导致压力或听天由命的态度。那是你最不想要的。更不用说那些无聊的会议和计算时间而不是计算进度了。尊重你的时间。
    我倾向于问的一个问题已被证明是调查的一个很好的切入点,这个问题有以下几种:“假设您决定与我合作,我们的项目已经进行了 6 个月,您对我的参与感到非常高兴和满意。我为帮助我们成功做出了哪些贡献?”
    寻找答案的清晰性和具体性,并提出后续问题。
  2. **期望和领导力。**你未来的团队要么必须对你的贡献有明确的期望,要么他们希望你积极参与工作的安排和领导。警惕混乱和移动目标。你要明确期望和超额交付,以建立信任和成功。再说一次,你不想为了展示(表面上的)奉献而在办公室里花费最多的时间——你想要交付成果。
  3. **文化。**你想和一群渴望自己和周围人成功的人在一起。这意味着他们没有时间参与政治。他们不会尊重无用功。他们会以高度的正直来交付坚实的工作,并感谢你也这样做。你会为你所做的感到骄傲,对你所学到的心存感激,并且会和优秀的人建立良好的关系。
    三思而后行,问问他们最自豪的成就是什么,或者他们在这个项目中从同事那里学到的最重要的一件事是什么。看看他们看待他人和与他人互动的方式。
  4. **灵活性。**这个是面向员工/顾问的。你从事的是创造性职业,这应该是谈话的一个起点。应该根据你的产出的质量和数量以及你对他人的积极影响来评估你。自然,在初始阶段与团队面对面交流并了解每个人是很重要的。也就是说,正确的灵活性会大大提高你对生活的满意度,而不会对工作效率产生任何负面影响。这是值得谈判的——你再也不会拥有你生命中那些美好的岁月了。了解典型的一周是什么样的,并尝试收集有人展示灵活文化时的故事。
  5. 技术堆栈和变更流程。 非古风科技栈。你想聪明地工作,这里的关键是获得适合工作的好工具。您知道工具和行业实践都在不断改进和完善。新的框架也正在发布。负责任的和有效的变更管理是一个很大的话题,但是你至少要对两个场景有个感觉,这两个场景会非常直接地影响你的日常生活。
    第一个是你的个人编码环境——例如,安装你最喜欢的代码编辑器有多容易?您的环境中有什么级别的访问权限?这要么很容易,要么很麻烦。
    其次——询问主要依赖项更新是什么样的,需要多长时间,以及进行了哪些验证工作。它会告诉你很多关于组织发展速度的信息。
  6. **个人适合。**一定要见你的直接联系人或经理。他们对你的工作被看待和接受的方式有很大的影响,也对你的日常生活有很大的影响。不是你的房东,也不是你的丈母娘,不过是类似类型的交易!理想情况下,他们应该渴望并自豪地分享他们如何让同事发展和成长的故事。相信你的直觉!

我会注意到,与你的客户的关系是不断变化的,当你把自己树立为一个值得信赖和有价值的贡献者时,你可能会获得灵活性,以及对文化和战略的影响力。一开始就推迟大的需求是合理的,但也要注意几个月后机会的总体水平,让它在你的决策中发挥作用。

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

Photo by Brian Metzler on Unsplash

结论

如果机会没有勾选所有的框,但是因为其他原因非常令人兴奋呢?如果你有推动工作的外部压力怎么办?

专注才是王道。专注于能带来结果的行动,并以此为杠杆引导每个人走向更好的境地。至少,在下一个项目开始之前,你已经贡献了一些有意义的东西。

我希望这个清单有助于你的成功。祝你好运!

感谢亚历克斯·格雷斯、 马頔·谢尔巴科夫*米哈尔·马祖雷克 的建议和点评。*

如何向烹饪过的人解释机器学习项目的组成部分

原文:https://towardsdatascience.com/how-to-explain-the-components-of-machine-learning-projects-to-anyone-whos-ever-cooked-8ce7af4050e1?source=collection_archive---------10-----------------------

作为制药行业的机器学习团队负责人,我经常发现自己在教育非技术受众关于机器学习项目如何工作。这种对烹饪的类比确实引起了人们的共鸣,并帮助他们理解了主题专业知识、质量数据、数据工程的作用和重要性,以及为什么将一个成功的概念验证投入生产需要这么长时间!

我希望这有助于你理解或向他人解释机器学习项目!

事不宜迟,这里有一个抓住这个故事的执行幻灯片:

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

Source of Pasta Image

数据=配料

成分和数据就是原材料。与流行的说法一致,垃圾进来,垃圾出去,如果原料(数据)腐烂和滋生,就无法使最终结果可口。

数据工程=配料准备

烹饪的大部分时间都花在准备和加工食材上,这一事实会引起任何在厨房里伸出援手的人的共鸣。数据工程也是如此。我们有了特征工程、数据清理和标准化,而不是烹饪的切片、腌泡和剁碎。

机器学习算法=烹饪技术

在大多数情况下,这些事情只是自己发生
一个生土豆+一壶开水+ 15 分钟=软土豆。
标记数据+ logistic 回归+ 15 分钟=系数和优势比。

当然,了解食材和技术的厨师(和 ML 从业者)对好的结果至关重要。

硬件和软件架构=炊具和器皿

不同的问题需要不同的工具和不同尺寸的工具。

一份两人份的舒适食谱需要不同的技能和设备,而不是满足 2000 人的需求。同样,处理 1,000 行数据或文档可能在一台笔记本电脑上运行,但处理 10 亿行可能需要专门的分布式编程语言和服务器。

领域专长=主厨专长

其实第一次业余都可以做饭!

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

Source

也就是说,有专业厨师来烹饪或至少提供建议会大大改善任何菜肴。同样,拥有专业知识可以极大地改善机器学习项目和产品。

这里实际上有两种类型的专业知识——业务领域(例如,金融市场、临床路径)和技术领域(例如,自然语言处理)。最成功的项目需要两类专家之间的密切合作。

~~~内部技术团队的插头~ ~ ~

如果你在一家大公司工作,那里对机器学习的需求和依赖不断增长,以帮助业务增长或扩大,投资内部人才至关重要。将每一个机器学习项目外包给第三方供应商,就像一家餐馆将每一单订单外包给其他餐馆一样。它成本高、速度慢、不灵活,并且缺乏一致性和可扩展性。

临时演员

可以得出许多额外的类比。如果有兴趣,我可以写第二篇文章来扩展这些概念:
项目/平台通常是由单个组件组成的,就像一道菜是中间熟的或生的配料的组合。
获取数据可能是一件苦差事,就像从各种供应商处采购高质量的原料可能在物流方面具有挑战性一样。
在云中操作就像租用厨房(或特定的器具、炉灶、冰箱等)。)点播。
API 是服务员:【https://www.youtube.com/watch?v=s7wmiS2mSXY】T4

使用 Python 浏览和可视化数据集

原文:https://towardsdatascience.com/how-to-explore-and-visualize-a-dataset-with-python-7da5024900ef?source=collection_archive---------4-----------------------

或者如何学习用 Python——一个代码向导——创建漂亮而有洞察力的图表

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

在上周的故事“用 Python 从各种工作表中提取数据”中,您了解了如何从不同来源(Google Sheets、CSV 和 Excel)检索和统一数据。这两个故事都是独立的故事,所以如果你跳过了上周的那篇,也不用担心。

[## 用 Python 从各种工作表中提取数据

或者如何学习统一 Google 工作表、Excel 和 CSV 文件——代码指南

towardsdatascience.com](/replacing-sheets-with-python-f1608e58d2ca)

在今天的故事中,你会学到:

  • 如何组合和争论数据,
  • 如何探索和分析数据,
  • 如何创建漂亮的图表来可视化您的发现

这篇文章是写给谁的:

  • 经常与数据打交道的人
  • 对 Python 和熊猫有基本了解的人

概述一下情况:

你的任务是找出如何提高你的销售团队的业绩。在我们假设的情况下,潜在客户有相当自发的需求。发生这种情况时,您的销售团队会在系统中输入一个订单线索。然后,您的销售代表会尝试在订单线索被发现时安排一次会议。有时在之前,有时在之后。你的销售代表有一个费用预算,并且总是把会议和他们付钱的一顿饭结合在一起。销售代表报销他们的费用,并将发票交给会计团队处理。在潜在客户决定是否接受你的报价后,勤奋的销售代表会跟踪订单线索是否转化为销售。

对于您的分析,您可以访问以下三个数据源:

  • order_leads (包含所有订单线索和转换信息)
  • sales_team (包括公司和负责的销售代表)
  • 发票*(提供发票和参与者的信息)*

导入和设置:

使用的库相当标准。但是,您可能需要在笔记本中运行以下命令来安装 seaborn。

!pip install seaborn

加载数据:

你可以下载并组合上周文章中展示的数据,也可以从这里下载文件并把它们载入你的笔记本。

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

first two rows of sales_team Dataframe

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

first two rows of order_leads Dataframe

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

first two rows of invoices Dataframe

让我们开始探索:

总体转换率发展:

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

Conversion rate development over time

显然,事情似乎在 2017 年初开始走下坡路。在与首席销售官核实后,发现大约在那个时候有一个竞争对手进入了市场。很高兴知道,但是我们现在在这里什么也做不了。

  1. 我们使用下划线_作为临时变量。我通常会对那些我以后不会再使用的变量这样做。
  2. 我们在order_leads.Date上使用了pd.DateTimeIndex,并将结果设置为索引,这允许我们
  3. 使用pd.Grouped(freq='D')将我们的数据按天分组。或者,您可以将频率更改为 W、M、Q 或 Y(表示周、月、季度或年)
  4. 我们计算每天“已转换”的平均值,这将给出当天订单的转换率。
  5. 我们使用.rolling(60).mean()来获得 60 天的滚动平均值。
  6. 然后,我们格式化 yticklables,使它们显示一个百分号。

销售代表之间的转换率:

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

看起来销售代表之间存在相当大的差异。让我们对此进行更深入的调查。

就所使用的功能而言,这里没有多少新东西。但是请注意我们如何使用 sns.distplot 将数据绘制到轴上。

如果我们回忆一下 sales_team 数据,我们会记得并非所有销售代表都有相同数量的客户,这肯定会有影响!让我们检查一下。

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

Distributions of conversion rates by number of assigned accounts

我们可以看到,转换率数字似乎与分配给销售代表的客户数量成反比。转换率下降是有道理的。毕竟,销售代表拥有的客户越多,他花在每个客户身上的时间就越少。

这里,我们首先创建一个助手函数,它将把垂直线映射到每个子图中,并用数据的平均值和标准偏差来注释这条线。然后我们设置一些 seaborn 绘图默认值,比如更大的 font_scale 和 whitegrid 作为 style

膳食的影响:

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

sample meals data

看起来我们已经有了吃饭的日期和时间,让我们快速看一下时间分布:

out:
07:00:00    5536
08:00:00    5613
09:00:00    5473
12:00:00    5614
13:00:00    5412
14:00:00    5633
20:00:00    5528
21:00:00    5534
22:00:00    5647

看起来我们可以总结如下:

请注意我们在这里如何使用pd.cut来给我们的数字数据分配类别,这是有意义的,因为毕竟,早餐是在 8 点还是 9 点开始可能并不重要。
另外,请注意我们如何使用. dt.hour,我们只能这样做,因为我们之前已经将invoices['Date of Meal']转换为 datetime。.dt就是所谓的存取器,有三个那些cat, str, dt。如果您的数据具有正确的类型,您可以使用这些访问器和它们的方法进行简单的操作(计算效率高且简洁)。

不幸的是,invoices['Participants']是一个字符串,我们必须先将它转换成合法的 JSON,这样我们才能提取参与者的数量。

现在我们来结合数据。为此,我们首先通过 order_leads 上的Company Id左连接所有发票。然而,合并数据会导致所有餐都加入到所有订单中。也把古代的餐点改成了更近的订单。为了减轻这种情况,我们计算了用餐和订购之间的时间差,并且只考虑订购前后五天的用餐。
仍有一些订单被分配了多餐。当同时有两份订单和两份餐时,可能会发生这种情况。然后,两餐将被分配给两个订单线索。为了删除重复的内容,我们只保留最接近订单的食物。

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

part of the combined data frame

我创建了一个已经包含一些样式的绘图栏函数。通过该功能绘图使得目视检查更快。我们马上就要用到它了。

膳食类型的影响:

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

**哇!**有餐点的订单和没有餐点的订单之间的转换率差异非常大。不过,看起来午餐的转化率比晚餐或早餐略低。

时间的影响(即用餐发生在订单引导之前还是之后):

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

'Days of meal before order'的负数意味着用餐发生在订单线索进来之后。我们可以看到,如果用餐发生在订单线索出现之前,似乎会对转化率产生积极影响。看起来对订单的预先了解给了我们的销售代表优势。

将这一切结合起来:

现在,我们将使用热图来同时显示多个维度的数据。为此,让我们首先创建一个助手函数。

然后,我们应用一些最终数据争论来额外考虑与订单价值相关的餐费,并将我们的交付周期划分为Before Order, Around Order, After Order,而不是从负四天到正四天,因为解释起来会有些忙。

运行下面的代码片段将生成一个多维热图。

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

Heatmap to visualize four dimensions in one graphic

热图当然很漂亮,尽管一开始有点难读。所以让我们过一遍。该图表总结了 4 个不同维度的影响:

  • 用餐时间:点餐后、点餐前后、点餐前**(外排)**
  • 用餐类型:早餐、晚餐、午餐**(外列)**
  • 餐费/订单值:最便宜、不太贵、成比例、较贵、最贵**(内排)**
  • 参加人数:1,2,3,4,5 (内列)

很明显,图表底部的颜色更深/更高,这表明

  • 当用餐发生在点菜之前时,转化率更高
  • 当只有一个参与者时,晚餐的转化率似乎更高
  • 看起来与订单价值相比,更贵的饭菜对转化率有积极的影响

调查结果:

  1. 不要给你的销售代表超过 9 个账户(因为转化率会迅速下降)
  2. 确保每笔订单都伴随着一次会面/用餐(因为这将使转化率提高一倍以上
  3. 当客户只有一名员工时,晚餐是最有效的
  4. 你的销售代表应该支付大约订单金额 8%到 10%的餐费
  5. 时机是关键,理想情况下,你的销售代表尽可能早地知道交易即将到来。

点击此处获取代码: GitHub Repo/Jupyter 笔记本

热图备注:

要解决可能不可靠的格式,您可以通过先卸载(您必须在终端中完成)然后运行以下命令,将 matplotlib 降级到版本 3.1.0:

!pip install matplotlib==3.1.0

如果你对此有问题,请告诉我

如何使用 Python 提取在线数据

原文:https://towardsdatascience.com/how-to-extract-online-data-using-python-8d072f522d86?source=collection_archive---------8-----------------------

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

Photo by Aaron Burden on Unsplash

关于 HTML、XPath、Scrapy 和 spiders 的基本概念

她的一位同事说:“我希望能拥有网站的所有文件。”

“是的,这能给我们提供很多信息”——另一位同事说

“你会做刮刀吗?”他们都转头看着她

"嗯……我可以……她开始喃喃自语

【完美】——他们都说

“…。她说完了,但为时已晚

她一生中从未用过刮刀。所以她当时不知所措。

“我不知道该怎么办” —她哭着给我打电话— “我觉得这对我来说太难了”

“你别担心!我们可以一起做”——我说

我完全理解她。第一次我不得不为一个 scraper 编码时,我也感到很失落。

就像我在看一场魔术表演。我记得当我开始阅读刮痧时。

“Web scrapers…mm…HTML 标签…mm…蜘蛛什么…?"对我来说,这听起来像是一门外语

但我读得越多,就越开始明白,就像魔术一样,你需要知道要寻找什么才能理解其中的诀窍。

到底什么是 web 刮刀?web scraper 是一种从网站上自动收集数据的程序。

我们可以收集网站的所有内容,或者只是关于某个主题或元素的特定数据。这将取决于我们在脚本中设置的参数。这种多功能性是 web 刮刀的魅力所在。

我们举个假设的例子。我们想从一个网址为https://www.mainwebsite.com的网站上抓取数据。特别是,这个网站包含不同的文件。我们对获取他们的文本感兴趣。

在主页中,我们可以找到三个子部分,如下图所示。

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

例如,点击topic1,我们将进入另一个页面(https://www.mainwebsite.com/topic1,在那里我们可以找到我们感兴趣的文档列表。

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

如果我们点击document1,我们将进入另一个页面(https://www.mainwebsite.com/topic1/document1/date),在那里我们可以获得该文档的内容。

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

如果我们要手动操作,我们会将内容复制并粘贴到文件中。相反,我们将自动化这一过程。

我们看到了获取数据所需遵循的路径。现在,我们应该找到一种方法来告诉 web scraper 在哪里寻找信息。

网站上有很多数据,比如图片、其他页面的链接、标题,我们都不感兴趣。因此,我们需要非常具体。

这是我们开始揭开魔术的地方。那我们解剖一下吧。

1HTML 代表超文本标记语言。它与层叠样式表(CSS)和 Javascript 一起,用于在交互式网站上构建和呈现内容。

你不需要学习如何使用 HTML 编码来构建一个 scraper。但是你应该知道如何识别 HTML 标签和元素。

为什么?因为数据会有一个特定的 HTML 标签。我们可以通过向 scraper 显示正确的 HTML 元素来提取这些数据。

一个 HTML 标签由一个用尖括号括起来的标签名组成。通常,您需要一个开头和一个结尾标签来框定一段特定的文本。

开始标记由一个名称和可选属性组成。结束标签由相同的名称加上一个正斜杠(/)组成。

每个标签名称都指一个特定的元素。我们会注意下面的标签:<p>用于段落;<a>或锚标记为超链接;<img>为图片;<h1><h2>等。对于文本标题;<div>为分隔线,<tr>为表格行,<td>为表格列。

大多数标签还带有idclass属性。id为 HTML 文档中的 HTML 标签指定了一个惟一的 id。class用于定义标签将采用的样式。

让我们观察一个 HTML 元素:

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

在这种情况下,我们希望提取 HTML 元素的内容“2019 年 6 月 28 日版”。我们会告诉 scraper:寻找所有的

元素,给我一个带有类“text-primary”的元素。

如果有一个以上的元素具有这些特征,我们就需要更加具体。指示 ID 属性可以实现这一点。

好的。但是我在网站上哪里可以找到这些信息呢?

这是一个简单的步骤:右击网页上的任何地方。将出现一个小窗口。接下来,你点击检查,如下图所示。

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

你可以访问网站的源代码,图片,CSS,字体和图标,Javascript 代码。

此外,您可以使用光标选择器(下面的图片)选择网站中的项目。

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

因此,对应于所选项目的 HTML 元素将被突出显示。

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

在上图中,我们可以观察到一个典型的 HTML 结构是什么样子。

正常情况下,所有内容都包含在开始和结束body标签中。每个元素都有自己的标签。

一些 HTML 元素嵌套在其他元素中,形成层次结构。这可以用树来表示。

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

如果我们在树中从左向右移动,我们向前移动了几代。如果我们从上到下移动,我们会在同一代之间移动,或者在来自同一个父元素的兄弟元素之间移动。

注意两个<div>元素。他们是兄弟姐妹,因为他们共享<body>作为父母。他们是html元素的第二代传人。他们每个人都有孩子。第一只<div>有两个孩子。它的第一个孩子是一个包含“网页抓取有用!”元素。然而,这个元素并不是第二个<div>的后代。这是因为您不能沿着从这个 div 元素到 paragraph 元素的路径。

这些关系也将有助于我们向 web scraper 指示所需的元素。

2XPath 代表 XML 路径语言。跟网页抓取有什么关系?我们将学习如何识别 HTML 元素。但是现在出现的问题是我如何向刮刀指出元素?答案是 XPath。

XPath 是一种特殊的语法,可用于浏览 XML 文档中的元素和属性。此外,它将帮助我们获得某个 HTML 元素的路径并提取其内容。

让我们看看这个语法是如何工作的

/用于向前移动一个代,tag-names给出哪个元素的方向,[]告诉我们选择哪个兄弟元素,//查找所有后代,@选择属性,*是通配符,表示我们希望忽略标记类型。

如果我们看到下面的 XPath:

Xpath = '//div[@class="first"]/p[2]'

我们会理解,从所有(//)div元素中带class"""(div[@class="first"]),我们要第二个([2])段落(p)元素。

幸运的是,web 浏览器有一种简单的方法来获取元素的 XPath。

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

检查网站时,右键单击突出显示的元素。将显示一个小窗口。然后可以复制 XPath

3Scrapy 是一个 Python 框架,专为抓取网站和提取结构化数据而设计。它是专门为网络抓取而设计的,但是现在它也可以通过 API 来提取数据。

为了安装 Scrapy,你需要安装 Python。建议只使用 Python 3。Python 2 将于 2020 年 1 月弃用。

要安装 Scrapy,您可以使用 pip:

pip install Scrapy

或者使用康达

conda install -c conda-forge scrapy

Scrapy 的一个重要方面是它使用了 Twisted,这是一个流行的 Python 事件驱动网络框架。Twisted 为并发性异步工作*。*

这是什么意思?同步意味着您必须等待一个作业完成,以便启动一个新作业。异步意味着您可以在前一个作业完成之前移动到另一个作业。

*44**蜘蛛。*因为这个特点,Scrapy 可以在很短的时间内抓取一组 URL。因此,Scrapy 与蜘蛛合作,而不是在一个网站上抓取。

蜘蛛是我们定义的类,Scrapy 使用它来抓取多个页面的链接并抓取信息。

蜘蛛结构:

蜘蛛必须满足某些要求才能正常工作。他们必须子类化***scrapy.Spider***,并定义要发出的初始请求。此外,他们还可以决定如何在页面中跟随以及如何解析下载的页面内容。

让我们详细看看这些要求:

  1. 每个蜘蛛必须是***scrapy.Spider***类的子类:这意味着它必须把它作为一个参数。
  2. 蜘蛛的***name***在一个项目中必须是唯一的。
  3. 他们必须定义最初的请求:必须有一个方法调用***start_requests()***。Scrapy 将总是寻找它来发起请求。它还必须返回一系列请求,蜘蛛将从这些请求开始爬行。
  4. 他们可以决定如何解析下载的内容:通常会定义一个***parse()***方法。我们调用它来处理为每个请求下载的响应。parse()方法通常会解析响应,提取抓取的数据,还会找到新的 URL 并根据它们创建新的请求。
  5. 我们也可以找到**allowed_domains**名单。这告诉蜘蛛什么是允许抓取的域名。
  6. 此外,我们可以设置一个列表。用来指定我们要刮什么网站。默认情况下,Scrapy 使用 HTTP 协议。还得改成 https。

现在,我们已经剖析了 web 刮刀的所有组件。

→该写了!!←

我们将带来 URL 为https://www.mainwebsite.com的网站的初始示例。

让我们回顾一下事实:

  • 我们有一个主网站,有三个链接到三个不同的部分。
  • 在每个部分中,我们都有一个文档链接列表。每个部分都有一个特定的 URL,例如https://www.mainwebsite.com/topic1
  • 每个链接都将我们带到我们感兴趣的文档内容。我们可以在每个部分的 HTML 结构中找到每个链接。

首先,我们将设计我们的文件架构。

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

让我们探索一下我们的文件夹*。*

我们已经创建了一个名为scraper的主文件夹,在这里我们将存储与我们的刮刀相关的所有文件。

然后,我们将收集 JSON 文件中的所有数据。这些文件都将保存在JSON文件夹中。

常用文件夹还有一个文件夹叫spiders。在那里,我们将为每个蜘蛛保存一个文件。我们将为每个主题创建一个蜘蛛。所以,总共三只蜘蛛。

现在,是时候了解我们创建的文件了。

先从settings.py说起吧。Scrapy 设置允许我们定制所有 Scrapy 组件的行为,包括核心、扩展、管道和蜘蛛本身。

在那里,我们可以指定由 Scrapy 项目实现的 bot 的名称,Scrapy 将在其中寻找蜘蛛的模块列表,以及 HTTP 缓存是否将被启用,等等。

现在,我们到达主要的两个文件。

我们先从**topic1.py** 蜘蛛开始。我们将只研究一个例子,因为它们都非常相似。

我们需要做的第一件事是导入所有需要的库。

显然,我们需要导入 scrapy。模块将允许我们使用正则表达式提取信息。json模块将在保存信息时帮助我们。os模块对于处理目录很有用。

我们之前说过,蜘蛛必须继承***scrapy.Spider*** 所以我们将创建一个名为FirstSpider 的类来继承它。我们将指定**name** 主题 1。然后,我们将定义**allowed_domains**列表。

我们还需要创建**start_request()**方法来初始化请求。在这个方法中,我们为请求定义了一个 URL 列表。在我们的例子中,这个列表只包含 URL [www.mainwebsite.com/topic1](http://www.mainwebsite.com/topic1.) 然后,我们要用scrapy.Request提出请求。

我们将用[yield](https://pythontips.com/2013/09/29/the-python-yield-keyword-explained/)代替return。我们将告诉 scrapy 使用回调参数中的**parse()**方法来处理下载的内容。

到目前为止,你可能认为关于 HTML 和 XPath 的解释是没有用的。现在是我们需要它的时候了。

在我们定义了启动初始请求的方法之后,我们需要定义处理下载信息的方法。

换句话说,我们需要决定如何处理这些数据。哪些信息值得保存。

为此,让我们假设这是我们网站的 HTML 结构。

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

正如您在图片中看到的,突出显示的元素是我们提取链接所需的元素。

让我们建造到达那里的路径。从所有(//)具有class col-md-12 ( div[@class='col-md-12'])的div元素中,我们需要来自a子元素(a/@href)的属性href

因此,我们有了 XPath: //div[@class='col-md-12']/a/@href

在我们的parse方法中,我们将使用response.xpath()来指示路径,使用extract()来提取每个元素的内容。

我们期待得到一个链接列表。我们希望提取那些链接中显示的内容。蜘蛛需要跟踪它们中的每一个,并使用我们称之为parse_first的第二种解析方法解析它们的内容。

注意,这次我们在响应变量中使用follow发送链接,而不是创建一个请求。

接下来,必须定义parse_first方法来告诉蜘蛛如何跟踪链接。

我们将提取文档的标题和正文。

*在探索了一个文档的 HTML 结构之后,我们将得到任何一个id为 *titleDocument、的元素,以及任何一个idBodyDocument 的元素的子元素的所有段落。

因为我们不关心他们有哪个标签,所以我们将使用*

得到每个段落后,我们将把它们添加到一个列表中。

之后,我们将把文本列表中的所有段落连接在一起。我们会提取日期。最后,我们将使用datetitletext定义一个字典。

最后,我们将数据保存到一个 JSON 文件中。

这里是函数extractdate的定义,我们将使用正则表达式来提取日期。

现在,我们的蜘蛛完成了。

B 该调查**scraper.py**文件了。我们不仅需要创造蜘蛛,还需要发射它们。

首先,我们将从 Scrapy 导入所需的模块。CrawlerProcess将启动抓取过程,而settings将允许我们安排设置。

我们还将导入为每个主题创建的三个蜘蛛类。

之后,我们启动一个爬行过程

我们告诉进程使用哪些蜘蛛,最后,我们将开始爬行。

完美!我们现在有我们的铲运机了!!!

但是等等,我们实际上如何开始抓取我们的网站呢?

在终端中,我们通过命令行导航到 scraper 文件夹(使用cd)。一旦进入,我们就用图中看到的python3命令启动蜘蛛。

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

然后瞧啊*!蜘蛛正在爬网站!*

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

在这里,我列出了一些非常好的资源和课程来学习更多关于网络抓取的知识:

  1. 数据营课程。
  2. 网页抓取教程
  3. 刺儿头文档
  4. HTML 长解释

如何假装成为一名优秀的程序员

原文:https://towardsdatascience.com/how-to-fake-being-a-good-programmer-cbef2c39764c?source=collection_archive---------0-----------------------

秘密就在光学中

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

Photo by Braydon Anderson on Unsplash

程序员是巫师——贫穷、衣衫褴褛的角色将咖啡变成代码。我不懂魔术,我只是个魔术师。我的工作是做一个假程序员比做真正的程序员更真实。

我很擅长我的工作,一个十足的江湖骗子。我骗过一些商人,让我成为他们的技术合伙人。我骗过了工程师,让他们向我咨询人工通用智能。我的行为如此真实,以至于司法部曾经征求我的建议,用 Visual Basic 创建一个 GUI 界面来追踪一个连环杀手的 IP 地址

秘诀:重要的不是你知道什么,而是你表现出什么。

真正的工程师缓慢而乏味,因为他们被现实所拖累。一个魔术师只受他的想象力的限制。他可以自由地表演最复杂的场景,越色情越好。公众对黑客的认知是由狂欢口交的场景塑造的——成为利用他们错误观念的罕见个体,允许门外汉沉迷于他们的幻想,你将被誉为英雄。

一场令人信服的表演需要一个精心设计的舞台,因为它会分散观众的注意力,让他们意识不到你缺乏深度。在电影中,软件是通过将 3D 块堆叠在彼此之上,或者通过抚摸一些全息图来编写的。当然,这是幻想。在现实生活中,最接近它的方法是结合使用三种古老的技术,这些技术都是几十年前发明的。

首先,你有 vim一个高度可配置的文本编辑器,很难使用数百万开发者无意中被困在它的爪子里,无法弄清楚如何关闭这个该死的东西。你大胆使用它的事实提升了你在同事中的地位。你似乎是彻头彻尾的神话,就神圣的编辑战争这样的历史主题启发他人,并激起对你讨伐 Emacs 教会的支持。

第二,tmux 是一个允许你在一个终端窗口中打开多个窗格的工具。这意味着您可以在一个面板中编写代码,在另一个面板中运行终端命令,并在剩下的面板中打开完全无用的插件,如音频声谱图和超大时钟。一般来说,你希望尽可能多的窗格打开,用这种突兀的景象压倒观众的感官。我自己强调永远不要关闭窗格,因为没有功能的代码不会老化。

给你一个例子,这是我生成一些 deepfakes 时的屏幕快照:

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

Spectrogram credit: M.O.P. — Ante Up

最后,最重要的是你要掌握 bash,一种直接在命令行中使用的脚本语言。了解 bash 可以让你最大限度地利用在终端的时间——在表演中途离开是一种亵渎,相当于在电影中途打开电影院的灯。需要计算一些东西吗?给你:echo "scale=0; 2 + 2" | bc。想知道自己的 CPU 使用率?命令如下:mpstat | grep -A 5 "%idle" | tail -n 1 | awk -F " " '{print 100 - $ 12}'a。你明白了。

比离开终端更糟糕的事情是离开键盘。使用光标会显得无能。如果你有一台个人电脑,立即把你的牙齿咬进人体工程学的怪物——鼠标的尾巴。如果你使用笔记本电脑,在触摸板上粘上砂纸——你想把它的使用与鲜血和痛苦联系起来。

现在,当你在终端时,敲击键盘很容易。要继续在浏览器中聊天,请使用 Vimium ,这是一个 Chrome 扩展,可以在不使用鼠标的情况下帮助浏览网页。它通过一系列按键突出显示网站上的每个链接,按下这些按键会模拟鼠标点击,从而打开所需的页面。它看起来是这样的:

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

Vimium

作为一个专业提示,请注意我是如何在浏览互联网时打开终端的。正如剧作家约翰·海伍德所说,“半块面包总比没有好”。此外,仔细看看我的 Chrome 标签,可以发现 arXiv 论文和堆栈溢出帖子的混合。这不是偶然的。战略性编排的标签阵列传达出你已经跨坐在令人垂涎的机器学习工程师的椅子上,一条腿在理论上摇摆,另一条在实践中摇摆。

T2:舞台布置好了,表演可以开始了。你的一举一动都表明你最不需要一只老鼠。也许你可以靠在椅子上,把腿放在桌子上,把键盘放在腿上。我自己在离我的 40 英寸显示器 10 英尺远的豆包里晒太阳。

至于行为本身,记住:这是巴洛克风格,不是极简主义。你想用你敏捷的手指动作和复杂的过渡来吸引观众。在 vim 中,您从一行跳到另一行,从一个函数跳到另一个函数,速度之快,旁观者几乎没有注意到。就在他们的眼睛开始适应,就在他们要理解你的废话的时候——很少有任何一行真正包含有效的代码——你切换到另一个 tmux 面板,他们的斗争重新开始。

一场好的演出是由它引起的混乱和沮丧的程度来衡量的。伟大的表演令人作呕。它简直让观众神魂颠倒——他们情不自禁地抽搐着倒在地上,垂涎三尺。

也许你认为这样的权谋策略太天真和不真诚,浮夸太轻浮。你宁愿保持低调,专注于这门手艺,希望在努力、诚实工作的最后,你会得到认可。

也许会,但为什么要浪费你生命中最美好的十年去辛苦工作呢?为什么不把你的脚放在桌子上,马上表现得像个高手?让我告诉你,做一个假的大人物比做一个真正的无名小卒要好。

如何以正确的方式“养殖”Kaggle

原文:https://towardsdatascience.com/how-to-farm-kaggle-in-the-right-way-b27f781b78da?source=collection_archive---------3-----------------------

本文描述了如何有效地使用 Kaggle 作为竞争平台,以最大的效率和盈利能力提高数据科学从业者技能的建议和方法。

农场(farming) —一种游戏策略,玩家通过重复动作来获得经验、点数或某种形式的游戏内货币。

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

描述

这些方法帮助我在六个月内获得了 Kaggle 竞赛大师的称号,仅仅是在单人模式下参加了三场比赛。当我在 Kaggle 上登上200 强世界排名时(在撰写 2018-10-18 原文时),他们也帮助了我。我希望这回答了我为什么冒昧地写这样一篇文章的问题。

介绍

最近(2019 年 2 月 11 日)新一期关于机器学习的惊人课程已经上线。这门课程是英文的,它是根据一群 Kaggle 大师的意见创建的,我强烈推荐它作为任何想在数据科学领域开始职业生涯的人的入门课程。像往常一样,在完成这门课程(或任何这方面的课程)后,学生中出现了一个问题:我们在哪里以及如何获得实践经验来巩固新获得的理论知识。如果你在任何相关论坛上问这个问题,答案很可能是“Kaggle”。好吧,Kaggle 不错,但是从哪里入手,如何最高效的利用这个平台进行实践技能的提升呢?在本文中,我将根据自己的经验尝试给出这些问题的答案,并描述如何避免竞争数据科学领域的一般错误,并在过程中获得乐趣的同时加快提振您技能的过程。

关于课程的创始人的几句话:

mlcourse.ai 是 OpenDataScience 社区的主要活动之一。 Yury Kashnitskiy(约尔科) *& Co. (~60 多人)*表明原则上不需要大学就能获得现代技术技能;此外,你可以完全免费这样做。这门课程的主旨是理论和实践的最佳结合。一方面,基本概念的介绍涉及一些数学知识,另一方面,在你的努力下,课堂竞赛和项目中的大量作业、将提高你的机器学习技能。更不用说这门课程的竞争性质了——互动的学生评分让参与变得有趣,并激励他们坚持到最后。此外,该课程发生在一个真正充满活力的社区。

在课程进行期间,有几场班级竞赛。两者都非常有趣,都是必需的特性工程。第一个是在 上,通过 访问站点的顺序进行用户识别。第二种尝试 预测媒体文章的流行度 。在一些作业中,你需要尽最大努力在这些比赛中超越基线。

向课程和它的创造者致敬,我们继续我们的故事…

我记得一年半前的自己,当我通过来自吴恩达的第一版 ML 课程,完成 MIPT 专精,读了堆积如山的书……不用说,我有很多理论知识,但是当我试图从现实生活中解决一个基本任务时,我碰壁了。我不知道从哪里开始。我知道如何解决这个问题,知道使用哪些算法,但是写代码非常困难,必须不断地搜索提示,查看 sklearn 帮助等。为什么?因为我没有完成这样一项任务的工作流程和实践经验。

这样是行不通的,我想,然后走向卡格尔。从排名赛开始很吓人,第一个目标是入门赛“房价:高级回归技术”。在进行这项竞赛的过程中,形成了高效的 kaggle 农业方法,本文对此进行了描述。

本文中描述的方法并不是唯一的,也没有“诀窍”,所有的方法和技术都是众所周知和简单明了的,但是这并没有降低它们的有效性。这些方法帮助我在六个月内获得了 Kaggle 竞赛大师的称号,仅仅是在单人模式下参加了三场比赛。当我在 Kaggle 上登上200 强世界排名时(在撰写 2018-10-18 原文时),他们也帮助了我。我希望这回答了我为什么冒昧地写这样一篇文章的问题。

一言以蔽之,Kaggle 是什么?

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

Kaggle 是举办数据科学竞赛的最著名平台之一。在每场比赛中,赞助商主持真正的任务,提供任务的描述、任务的数据、用于评估解决方案的指标,还设置截止日期和奖金。参与者通常每天有 3 到 5 次机会“提交”该任务的解决方案。

数据分为训练集和测试集。您将获得培训部分的目标变量的值,而不是测试部分的目标变量的值。参与者应该创建一个模型,当对数据的训练部分进行训练时,该模型在测试集上实现最大结果(根据所选的度量)。

每个参与者对一个测试集进行预测,并将结果发送到 Kaggle 上,然后机器人(它知道测试集的目标变量)评估收到的结果,对其进行评分,并将其显示在排行榜上。

但事情没这么简单,测试数据依次按一定比例分为公共部分和私人部分。在比赛期间,根据测试集公共部分的既定指标对提交的解决方案进行评估,并将结果放在“公共”排行榜上,参与者可以在比赛期间评估他们模型的质量。最终解决方案(通常是参与者选择的两个)在测试数据的私人部分进行评估,结果将进入私人排行榜,该排行榜仅在比赛结束后才可见,实际上,最终评级将根据该排行榜进行评估,并分发奖品和奖牌。

因此,在比赛期间,参与者只知道他们的模型在测试数据的公开部分表现如何(产生的结果或分数)。如果在真空中的球形鸡的情况下,数据的私人部分具有与公共部分相同的分布和统计,那么一切都可能是好的。如果不是这样,那么这个被证明对测试集的公共部分有好处的模型可能会在私有部分失败。这被称为“在公共董事会上过度配合”。这导致了“排行榜外逃”,当公共排行榜上排名第 10 位的人在私人部分跌至 1000–2000 位,因为他们选择的模型过度拟合,无法在看不见的数据上给出所需的准确性。

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

如何避免?首先,您需要建立一个适当的验证方案,这是几乎所有数据科学课程的第一课。为什么这么重要?好吧,如果你的模型不能对之前从未见过的数据集做出正确的预测,那么无论你使用什么样的技术或者你的神经网络有多复杂都没有用。您不能在生产中发布这样的模型,因为看不见的数据的结果将是没有价值的。

对于每场比赛,Kaggle 管理员都创建了自己的独立页面,其中包含数据、时间表、指标描述以及对我们来说最有价值的部分——论坛和内核。

论坛是一个标准的论坛,人们可以在这里讨论和分享想法。但是内核更有趣。事实上,是运行您的代码直接访问 Kaggle 云中的竞争数据(类似于 AWS、GCE 等)的机会。)每个内核的计算资源都是有限的,所以如果数据集不太大,你可以直接在 Kaggle 网站的浏览器上使用它。您可以编写代码、执行代码、调试代码,当然还可以提交结果。两年前,Kaggle 被谷歌收购,因此“引擎盖下”这一功能使用谷歌云引擎并不奇怪。

此外,还有几个竞赛(例如, Mercari )要求你只能通过内核处理数据。这是一种令人兴奋的格式,它补偿了参与者之间的硬件差异,并让您在代码优化和方法的主题上使用您的大脑,因为内核当时对资源有硬性限制(4 个内核/ 16 GB RAM / 60 分钟运行时间/ 1 GB 暂存磁盘空间和输出)。在这次比赛中,作者学到了比任何理论课程都多的关于神经网络优化的知识。得分比黄金级低一点,在单人模式中排名第 23,但获得了很多经验和快乐…

我很高兴借此机会再次感谢 ods.ai 的同事们——亚瑟·斯特塞潘尼卡(亚瑟)康斯坦丁·洛普欣(科斯蒂亚)谢尔盖·菲罗诺夫(谢尔盖夫)对本次比赛的建议和支持。总的来说,有许多有趣的时刻,Konstantin Lopuhin(kostia),他在这次比赛中与pawejankiewicz一起获得了第一名,随后做了被称为“75 行参考羞辱”的帖子,他们发布了 75 行内核,给出了黄金排行榜区的结果。你真得去看看!

好吧,让我们回到比赛上来。人们编写代码并发布带有解决方案、有趣想法等的内核。在每次比赛中,通常在比赛开始后的几周内,都会出现一两个漂亮的 EDA(探索性数据分析)内核,其中包含对数据集、属性统计、特征等的详细描述。和几个基线内核(基本解决方案),当然,它们不会在排行榜上显示最佳结果,但您可以使用它们作为创建自己的解决方案的起点。

为什么是 Kaggle?

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

其实玩什么平台没什么区别。Kaggle 只是第一个也是最受欢迎的一个,有很棒的社区和舒适的环境(我希望他们会为了稳定性和性能而修改内核。许多人还记得在墨卡里发生的事情,但是,总的来说,这个平台是非常方便和自给自足的,卡格尔等级(大师)仍然很有价值。

在竞争数据科学的主题上有点偏离主题。很多时候,在文章、对话和其他交流中,人们认为比赛中获得的经验不能用于现实生活中的问题,所有这些人都只调了分数的第五位小数,这是疯狂的,离现实太远了。让我们更仔细地看看这个问题:

作为一名实践数据科学的专业人士,与来自学术界和科学界的人相比,我们应该并将在工作中解决实际的业务问题。换句话说,(这里引用的是 CRISP-DM )要解决这个问题有必要:

  • 为了理解业务问题
  • 评估数据以确定它是否能解决这个业务问题
  • 如果现有数据不足以得到答案,则收集额外的数据
  • 选择最接近业务目标的指标
  • 并且只有在选择了一个模型之后,才转换所选模型的数据并“堆栈 xgbosts”。

这个列表中的前四项在任何地方都没有教授(如果有这样的课程,请纠正我——我会立即报名参加),唯一的方法是从在特定行业工作的同事那里学习经验。但是最后一条——从选择车型开始,你可以,也应该在比赛中提高。

在任何比赛中,赞助商已经为我们完成了大部分工作。我们已经有了业务目标、选定的近似度量、收集的数据,我们的任务是从所有这些中构建一个工作管道。这里是技能需要改进的地方——如何处理缺失值,如何为神经网络和树准备数据(以及为什么神经网络需要一种特殊的方法),如何建立一个验证方案,如何不过度拟合,如何选择合适的超参数,以及许多其他“如何做”,在我们的专业中,专家与路人之间的区别在于其执行能力。

你可以在 Kaggle 上“耕种”什么

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

基本上,所有的新人来到 Kaggle 都是为了提高他们的实践经验,但不要忘记,除此之外,至少还有两个额外的目的:

  • 农场奖章和军衔
  • Kaggle 社区的农场声誉

需要记住的关键一点是,这三个目标是完全不同的,实现它们需要不同的方法,尤其是在初始阶段,不应该混淆!

请注意单词**、【初始阶段】、**,因此当你提高技能时——这三个目标将合并为一个,并平行实现,但当你刚刚开始时——不要把它们混淆!这样你将避免痛苦、挫折和对这个不公正世界的怨恨。

让我们自下而上简要介绍一下目标:

  • 声誉 —通过在论坛上写好的帖子(和评论)和创建有用的内核来提高声誉。比如 EDA 内核(见上),有创新技术描述的帖子等。
  • 奖牌 —一个非常有争议的话题,但是……它可以通过混合公共内核(*)、加入经验不平衡的团队,当然也可以通过创建自己的顶级解决方案来改进
  • 经验 —通过对决策和错误的分析得到增强。

(*) 混合公共内核—获得奖牌的技术,当选择公共排行榜上得分高的内核时,对它们的预测进行平均(混合),并提交结果。通常,这种方法会导致在公共排行榜上很难超配,但有时会让你几乎获得银牌。在初始阶段,作者不推荐这种方法(阅读下面关于腰带和裤子的内容)。

我建议首先选择“体验”目标,并坚持下去,直到你觉得准备好同时为两三个目标努力。

还有两件事值得一提(Vladimir Iglovikov(tern aus)——感谢提醒)。

第一个是将在 Kaggle 投入的精力转化为一份新的、更有趣和/或报酬更高的工作。对于理解题目的人来说,简历中的那一行“Kaggle 竞赛大师”和其他成就还是有价值的。

为了说明这一点,你可以阅读两个采访(一个两个请注意,这些采访是用俄语进行的)与我们的同事谢尔盖·穆欣斯基(切佩拉 _ 昂)亚历山大·布斯拉耶夫(阿尔布)

还有 Valeriy Babushkin (venheads) 的意见:

valeriy Babushkin——X5 零售集团数据科学负责人(领导一个 50 多人的团队,分为 5 个部门:CV、机器学习、数据分析、NLP 和 Ad Hoc),Yandex Advisor 分析团队负责人

Kaggle 竞赛大师是评估未来团队成员的一个很好的替代指标。当然,由于最近的事件是 30 人一组,而且几乎没有人做任何事情,这就需要比以前更仔细地研究这个轮廓,但这仍然只是几分钟的事。获得大师头衔的人,很有可能能够写出至少一般质量的代码,精通机器学习,能够清理数据并构建可持续的解决方案。如果你没有硕士学位,仅仅参与的事实也是一个加分项,至少候选人知道 Kaggle 的存在,并花了一些时间来熟悉它。如果他贡献的解决方案不仅仅是一个公共内核(这很容易检查),这是一个关于技术细节的具体对话的好机会,这比传统的应届毕业生求职面试好得多,也更有趣,因为后者提供的信息少得多,不知道未来人们将如何在工作中取得成功。我们唯一需要担心的是,我遇到的是一些人认为数据科学工作与 Kaggle 相同,这完全不是事实。很多认为数据科学=机器学习,这也是错误的。

第二点许多任务可以以预印本或文章的形式安排,一方面,它允许集体智慧在竞争中获得的知识不会在论坛的荒野中消亡,另一方面,它为作者的作品集增加了另一条线,为可见性增加了+1,这在任何情况下都会对职业生涯和引用指数产生积极影响。

例如,这是我们同事在几个比赛结束时的作品列表:

如何避免失去奖牌的痛苦

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

别管他们!

让我解释一下。实际上,在每一场接近尾声的比赛中,都有人用一个解决方案编写了公共内核,让整个排行榜上升,但你用你的解决方案却下降了。每次在论坛上痛苦就开始了!“哦,在这里我有一个银的解决方案,现在我甚至不在铜。到底是怎么回事,我们把东西都拿回来。”

请记住,Kaggle 是竞争数据科学,你在排行榜上的位置只取决于你自己。不是来自发布内核的人,也不是来自聚集在一起或不聚集在一起的明星,只是取决于你在决策中投入了多少努力,以及你是否使用了所有可能的方法来改进它。

如果公共内核把你从排行榜上抢走了——那不是你的位置。

而不是不得不为这个世界的不公倾吐痛苦——感谢这个家伙。说真的,比你的解决方案更好的公共内核意味着你在自己的管道中错过了一些东西。找到它,改进它,并以相同的分数绕过所有的仓鼠。记住,要回到原来的位置,你只需要比这个公共内核好一点点。

在第一场比赛的这个时刻,我是多么的沮丧!我的手开始下垂,我准备放弃了。刚才你还在银牌级别,而现在你在……排行榜的末尾。没关系,我只需要让自己明白在哪里错过了什么,就可以改变我的决定,回到比赛中来。

此外,这一时刻只会出现在你竞争过程的早期。你越有经验,就越感受不到发表的内核和明星的影响。在最近的一次比赛(谈话数据,我们的团队获得第八名)中有这样的内核,但在我们的团队聊天中,来自的 Pavel Pleskov (ppleskov) 在一行文字中提到了它:“伙计们,我把它与我们的解决方案混合在一起,它变得更糟了,所以我把它扔掉了”。这意味着内核从数据中提取的所有有用信号都已经被我们的模型提取出来了。

顺便说一句,关于奖牌,请记住:

“没有技能的腰带只起到撑住裤子的作用”

在哪里以及如何编写代码

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

我推荐的是Ubuntujupyter 笔记本python 3.6 。鉴于大量的库和社区,Python 已经成为数据科学中事实上的标准。Jupyter,尤其是有了jupyter _ contrib _ nb extensions的存在,对于快速原型制作、分析和数据处理非常方便。Ubuntu 本身很简单,而且数据处理部分有时用 bash 比用 python 更自然。

在安装了jupyter _ contrib _ nb extensions之后,我建议启用:

  • 可折叠标题 (真正有助于组织代码块)
  • (同)
  • (如果你需要调试什么东西的话很有用)

你的生活会变得更加舒适和愉快。

一旦您的管道变得或多或少稳定,我建议将您的代码转移到单独的模块中。相信我——你会重写不止一次两次甚至五次,这没关系。

有一种相反的方法,参与者试图尽可能少地使用 jupyter notebook,并且只在必要时使用,他们更喜欢通过脚本编写管道。(这个选项的内行,比如(弗拉基米尔·伊格洛维科夫(ternaus) )。你也可以阅读“与卡格尔大师弗拉基米尔·伊格洛维科夫(Vladimir I. Iglovikov)的任意提问环节”,在那里他描述了这种方法。

还有人试图将 jupyter 与任何 IDE 结合起来,比如 Pycharm。

每种方式都有存在的权利,各有利弊,就像他们说的,口味不同。选择你觉得舒服的工作。

但是在任何情况下,记住这条规则

**保存每次提交/OOF 的代码。(见下文)

()OOF—out of folds,一种使用交叉验证为数据集的训练部分获取模型预测的技术。对于几个解决方案的进一步组合是至关重要的。***

怎么会?嗯,至少有三种选择:

  • 对于每个竞赛,我们在 GitHubBitBucket 上创建一个单独的存储库,并为我们提交到存储库的每个代码提交一个注释,其中包含获得的分数、模型参数等。
  • 每一次提交后的代码被组合成一个单独的档案,其文件名包含所有元信息(获得的分数、选项等)。)
  • 使用了用于数据科学任务的专用版本控制系统。比如说 DVC

一般来说,在社区中,有一种逐渐过渡到第三种选择的趋势,因为第一种和第二种都有缺点,但它们简单可靠,老实说,对 Kaggle 来说,它们绰绰有余。

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

对于不是程序员的人,再多说几句 python。不要害怕。你的任务是理解基本的代码结构和语言的基本本质。它将使你能够理解别人的内核代码,并编写自己的库。在互联网上有许多优秀的初学者课程,也许在评论中,有人会给你链接。不幸的是(或者幸运的是)我不能评价这些课程的质量,所以我不会把这些链接放在文章里。

好了,我们去框架

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

本文中描述的所有技术都基于处理表格和文本数据。使用图片是一项独立的任务,具有独立的框架。在基本层面上,能够与它们一起工作是很好的,至少可以运行像 ResNet/VGG 这样的东西并获得特性,但是与它们进行更深入、更微妙的工作是一个单独的、非常广泛的主题,不在本文中讨论。

我不太擅长处理影像数据。唯一一次尝试是在比赛相机识别中,顺便说一下,在比赛中,带有【ODS . ai】标签的团队炸毁了整个排行榜,所以 Kaggle 管理员必须来我们的松弛区检查一切是否符合规则。在这次比赛中,我以第 46 名的成绩获得银牌,但当我阅读了我们同事对顶级解决方案的描述后,我明白这是我最好的地方,因为他们使用了一个真正的黑魔法,增加了图片,增加了 300 多 GB 的数据,牺牲了其他东西。例如,您可以阅读来自Vladimir Iglovikov(tern aus)的关于“数据增强的重要性”的帖子。

一般来说,如果你想开始使用图像,那么你需要其他的框架和指南。

主要目标

你的主要任务是为以下任务编写管道(以 jupyter 笔记本+模块的形式下发):

  • 探索性数据分析。这里有必要做一个评论,Kaggle 上有专门训练过的人:),他们每次比赛都写出非常好看和全面的 EDA 内核。击败他们很难,但理解如何看待数据仍然是必要的,因为在你的工作任务中,这个经过特殊训练的人就是你。所以你需要研究方法和途径,扩大你的图书馆。
  • 数据清理—数据清理的所有方面。处理缺失值、异常值等。
  • 数据准备就是为模型准备数据。多个块(通用,用于回归/神经网络,用于树模型,特殊(时间序列,图像, FM/FFM ),文本(矢量器,TF-IDF嵌入))
  • 模型(线性模型、树形模型、神经网络、外来(调频/FFM))
  • 特征选择
  • 超参数搜索
  • 全体

在公共内核中,所有这些任务通常都集中在一个代码中,但是我强烈建议为这些子任务中的每一个创建单独的笔记本和单独的模块(或模块集)。这个方法以后会对你有帮助。

为了防止可能的圣战,请记住——这个框架的结构并不是最后一个实例的真相,还有许多其他方式来构建管道,这只是其中之一。

数据以 CSV 或 feather/pickle/hdf 格式在模块之间传输,这是您喜欢的方式,也是您习惯或喜欢做的事情。

其实很多还是要看数据量。例如,在 TalkingData 竞赛中,我必须通过 memmap 来避免在为 lgb 创建数据集时出现内存不足的错误。

在其他情况下,主数据存储在 hdf/feather 中,这是 CSV 中的一个小文件(如所选属性集)。我重复一遍——没有模板,这只是可能的方式之一。你应该尝试所有的方法,选择最适合你的一个。

初始阶段

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

从任何入门竞赛开始(如前所述,我从房价:高级回归技术开始),开始创建你的管道和笔记本。读取公共内核,复制代码片段、过程、方法等。,然后运行您的数据管道,提交—查看结果,改进,清洗并重复。

这一阶段的主要任务是创建一个高效运行的全周期管道——从读取和清理数据到创建最终提交。

在进行下一步之前,应准备好并 100%工作的样本列表:

  • EDA(数据集统计、图表、一系列类别等)
  • 数据清理(使用 fillna 填充缺失,清理类别,合并类别)
  • 数据准备(通用(处理类别-标签/ohe/频率,数值到分类的投影,数值转换,宁滨),用于回归(不同的比例))
  • 模型(线性模型(不同的回归-岭/逻辑),树模型(lgb))
  • 特征选择(网格/随机搜索)
  • 集合(回归/ lgb)

投入战斗

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

选择任何你喜欢的比赛,让我们开始…

  • 查看数据,阅读论坛,建立一个强大的验证方案。如果没有强大的验证,你将在排行榜上落榜,就像在梅赛德斯、桑坦德和其他公司的竞争中发生的那样。例如,看看梅赛德斯讨论的排行榜(绿色箭头和数字表示与公众相比,人们在排行榜中上升的位置数,红色表示下降的位置数)

此时(2018-02-10)箭头从所有比赛的排行榜中移除。我不知道原因,但希望它会回来。

不要继续,直到您构建了一个健壮的验证模式——!!!

好了,你得到了可靠的验证,下一步做什么?

  • 运行您的管道并提交结果
  • 抓住你的头,吓坏了,冷静下来…并继续…
  • 阅读所有内核/论坛,了解使用的技术和方法
  • 用新技术重建你的管道
  • 转到步骤 1

记住你这个阶段的目标是获得经验!我们必须用工作方式和方法填充我们的管道,用工作代码填充我们的模块。不要担心奖牌——我的意思是,如果你能立即在排行榜上占据一席之地,那就太好了,但如果不能,也不要沮丧。我们来这里才五分钟,所以勋章和军衔不会去任何地方。

好了,比赛结束了,你在排行榜的某个位置,你学到了一些东西,想去参加下一场比赛?

不!

下一步做什么:

  • 等五天。不要看论坛,暂时忘记 Kaggle。让大脑休息一下,让眼睛有机会重新磨砺。
  • 然后回到比赛中。在这五天中,根据礼仪规则,所有顶级团队都将在论坛上发布他们的解决方案,以帖子、内核或 GitHub 资源库的形式。

这里你的个人地狱开始了

  • 你拿几张 A4 纸,在每张纸上写上来自上述框架的模块名称(EDA/Preparation/Model/Ensemble/Feature selection/Hyperparameters search/…)
  • 然后坚持阅读所有高层决策,并用新的技术、方法和途径填写相应的表格。

还有最差的:

  • 对于每个模块,您依次编写这些方法的实现,扩展您的管道和库。
  • 然后运行更新后的管道并提交解决方案。
  • 重复这个过程,直到你在排行榜的黄金区域找到解决方案,或者直到你失去耐心和勇气。

只有在那之后才能进入下一场比赛。

不,我没开玩笑。是的,你可以做得更容易。由你来决定。

为什么要等 5 天,而不立即阅读论坛?嗯,你正在失去问一些问题的机会,但在这个阶段(在我看来),最好是阅读已经形成的讨论解决方案的线索,然后问一些别人已经问过的问题,或者最好不要问,自己寻找答案。

你为什么要这么做?好吧,再说一遍——这个阶段的目的是开发你自己的解决方案、方法和途径的数据库。创造一个有效的渠道。所以在下一场比赛中,你不要浪费时间,只要说——是的,的意思是这里可以使用目标编码,顺便说一下,我有正确的代码,它使用了折叠中的折叠。或者,我记得在那个任务中,最好的方法是使用 scipy.optimize 使用 ensemble,顺便说一下,我已经为它准备好了代码。

差不多吧…

进入工作模式

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

用同样的方法,你应该参加一些其他的比赛。每次我们注意到工作表中的条目越来越少,而模块中的代码越来越大。渐渐地,分析的任务收敛到确保你阅读解决方案的描述,说耶,地狱耶!并在你的库中添加一两种新的方法或途径。

此后,学习模式变为纠错模式。基础库已经准备好了,现在只需要正确使用了。每次比赛后,你都会阅读解决方案的描述,看看你做了什么,哪些地方可以做得更好,你错过了什么,或者你具体哪里搞砸了,就像我在有毒中做的那样。我在黄金地带的下腹部走得很好,私下跌了 1500 点。这简直是侮辱到流泪…但我冷静下来,找到了一个 bug,在我们的 Slack 社区写了一个帖子——并吸取了教训。

建立工作模式的一个标志是,顶级解决方案的一个描述将写在你的昵称下。

粗略地说,在这个阶段结束时,您的管道中应该有什么:

  • 预处理和创建数字特征的各种方法—投影、关系
  • 关于如何处理类别的不同方法—意味着以正确的形式、频率、标签/ ohe 进行目标编码
  • 文本的各种嵌入方案(Glove、Word2Vec、Fasttext)
  • 文本的各种矢量化方案(计数、TF-IDF、哈希)
  • 几个验证方案(N*M 代表标准交叉验证,基于时间,按组)
  • 贝叶斯优化/超点/超参数选择的其他方法
  • 用于特征选择的洗牌/目标排列/博鲁塔/ RFE
  • 线性模型—编写代码,在一个处理过的数据集上以相同的风格运行不同的模型
  • LGB/XGB/Catboost —编写一个代码,在一个处理过的数据集上以相同的风格运行不同的模型

作者为具有相同外部接口的线性和基于树的模型分别创建了几个元类,以中和模型库的不同实现之间的 API 差异。但是现在他可以通过一行代码在一个处理过的数据集上运行同一类型的不同模型(例如 LGB 或 XGB)。

  • 几个不同类型的神经网络(不用于图片)——文本的嵌入/CNN/RNN,序列的 RNN,其余的前馈。理解和实现自动编码器是很好的。
  • 基于 lgb/regression/scipy 的集成—分别用于回归和分类任务。
  • 能够使用遗传算法很好,有时它们工作得相当好。

总结

正如在任何运动中一样,在竞争数据科学中,有大量的汗水和大量的工作。这不好也不坏,这是事实。参加比赛(如果你正确地对待这个过程)会大大提高技术技能,而且或多或少会培养一种体育精神——当你真的不想做某事,但你拿起笔记本电脑,重建模型并运行它来提高你分数的这该死的第五位小数时。

所以去玩 Kaggle 吧——收获经验、奖牌和乐趣!

关于作者的管道说几句话

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

在这一节中,我将尝试描述一年半以来我收集的管道背后的基本思想。同样,这种方法并不要求普遍性或独特性,但也许您会发现它很有用。

  • 除了平均目标编码之外,特征工程的所有代码都作为函数写在一个单独的模块中。我试图通过对象来实现,但结果很麻烦,在这种情况下没有必要。
  • 特征工程的所有函数都采用相同的风格,并具有相同的调用签名和返回:
**def do_cat_dummy(data, attrs, prefix_sep=’_ohe_’, params=None):
 *# do something*
return _data, new_attrs**

输入是数据集、属性、新属性的前缀和附加参数。输出是具有新属性的新数据集和这些属性的列表。此外,这个新数据集存储在一个单独的 pickle/feather 中。

它提供了什么—我们能够从预先构建的部件快速组装工作数据集。例如,我们对类别进行了三种不同的处理——标签编码/ OHE /频率,并将它们存储在三个单独的羽毛中,然后在建模阶段,我们需要做的只是玩这些块,通过一个优雅的动作创建不同的数据集进行训练。

**pickle_list = [
 ‘attrs_base’,
 ‘cat67_ohe’,
 # ‘cat67_freq’,
 ]
short_prefix = ‘base_ohe’

_attrs, use_columns, data = load_attrs_from_pickle(pickle_list)
cat_columns = []**

如果有必要组装另一个工作数据集—我们只需要替换 pickle_list,重新加载并使用新的数据集。

表格数据(实数和分类数据)的一组基本函数包括各种类别编码、数字属性到分类数据的投影以及各种转换。

**def do_cat_le(data, attrs, params=None, prefix=’le_’):
def do_cat_dummy(data, attrs, prefix_sep=’_ohe_’, params=None):
def do_cat_cnt(data, attrs, params=None, prefix=’cnt_’):
def do_cat_fact(data, attrs, params=None, prefix=’bin_’):
def do_cat_comb(data, attrs_op, params=None, prefix=’cat_’):
def do_proj_num_2cat(data, attrs_op, params=None, prefix=’prj_’):**

Universal Swiss army knife 用于组合属性,它将源属性列表和转换函数列表作为输入,其输出通常是数据集和新属性列表。

**def do_iter_num(data, attrs_op, params=None, prefix=’comb_’):**

加上各种附加的特定转换器。

为了处理文本数据,使用了单独的模块,包括预处理、标记化、词条化/词干化、频率表中的翻译等不同方法。,使用 sklearn,nltk 和 keras。

时间序列在一个单独的模块中处理,该模块具有为常见任务(回归/分类)以及序列到序列任务转换源数据集的功能。感谢 Franç ois Chollet 对 keras 的更新,所以现在构建 seq-2-seq 模型看起来不像是恶魔召唤的巫毒仪式。

顺便说一下,在同一个模块中还有传统的序列统计分析功能——平稳性测试、STL 分解等。在分析的初始阶段“感受”时间序列并了解它实际上是什么是非常有用的。

  • 不能立即应用于整个数据集的函数,以及您需要在折叠交叉验证中使用的函数,被移到单独的模块中:
  • 平均目标编码
  • 上采样/下采样
  • 它们在训练阶段被传递到模型类的内部(见下文)。
**_fpreproc = fpr_target_enc
 _fpreproc_params = fpr_target_enc_params

 _fpreproc_params.update(**{
 ‘use_columns’ : cat_columns,
 })**
  • 对于建模,创建了新的元类,它用抽象方法概括了模型的概念:fit/predict/set_params/ etc。对于每个库(LGB、XGB、Catboost、SKLearn、RGF……)来说,已经创建了这个元类的单独实现。

换句话说,为了与 LGB 合作,我们创建了一个模型

**model_to_use = ‘lgb’
model = KudsonLGB(task=’classification’)**

对于 XGB:

**model_to_use = ‘xgb’
metric_name= ‘auc’
task=’classification’

model = KudsonXGB(task=task, metric_name=metric_name)**

现在在我们的代码中,我们可以通用地操作这个模型。

  • 为了验证,创建了几个函数,一个为几个种子同时计算预测和 OOF,另一个是使用 train_test_split 的基本验证,等等。所有函数都使用元模型方法进行操作,这提供了与模型无关的代码,并方便了与任何其他库的管道连接
**res = cv_make_oof(
model, model_params, fit_params, dataset_params,     XX_train[use_columns], yy_train, XX_Kaggle[use_columns], folds, scorer=scorer, metric_name=metric_name, fpreproc=_fpreproc, fpreproc_params=_fpreproc_params, model_seed=model_seed, silence=True
)score = res[‘score’]**
  • 对于特征选择——没有什么有趣的,只是标准的 RFE,以及我最喜欢的所有可能方式的混合排列
  • 为了找到超参数,我主要使用贝叶斯优化,再次以标准化的形式能够运行任何模型的搜索(通过交叉验证模块)。这段代码驻留在建模笔记本中
  • 对于系综,创建了几个函数,根据岭/对数、LGB、神经网络和我最喜欢的 scipy.optimize 对回归问题和分类进行了标准化
  • 稍微解释一下——管道中的每个模型都生成两个文件作为输出:sub_xxx 和 oof_xxx,分别表示测试集的预测和训练集的 oof 预测。接下来,在 ensemble 模块中,这些文件(来自所有模型)从指定目录加载到两个数据帧中— df_sub / df_oof。然后我们查看相关性,选择最好的,然后在 df_oof 上建立第二级模型并应用于 df_sub
  • 有时候用遗传算法搜索模型的最佳子集会产生极好的结果(我用的是这个库,有时候卡鲁阿纳的一个方法效果很好。在最简单的情况下,标准回归和 scipy.optimize 可以完成这项工作。
  • 神经网络生活在一个独立的模块中,我在中使用 keras 一个函数风格,是的,我知道,它不如 pytorch 灵活,但也足够了。同样,通用的训练函数被编写,对网络的类型是不变的

这一管道在最近的 Home Credit 的比赛中再次得到了检验,所有模块和模块的谨慎和准确应用为作者带来了第 94 名和一枚银牌。

作者其实很愿意表达一个煽动性的想法,对于表格数据和体面的管道,任何比赛的最终结果都必须在排行榜的前 100 名。当然也有例外,但总的来说,这种说法似乎是正确的。

关于团队合作

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

如何解决 ka ggle——在团队或 solo 中——主要取决于一个人(和一个团队),但我对刚开始的人的建议是——尝试开始 solo。为什么?我会试着解释我的观点:

  • 首先,你会看到自己的优势和劣势,并能够评估自己作为一名数据科学家的总体潜力。
  • 其次,即使是在一个团队中工作(除非是一个建立良好的、角色分离的团队),团队仍然会等待你的一个完成的解决方案。所以你必须有工作管道来很好地合作。
  • 第三,最理想的是,当团队中球员的水平差不多时(并且足够高),你可以学到一些真正有用的东西。在弱队(没有什么贬义,我说的是 Kaggle 上的训练水平和经验)IMHO 学点东西很难,不如看论坛和内核。是的,这是有可能的农场奖牌,但看到以上关于目标和一个腰带保持你的裤子

来自明显队长的好建议和承诺的一般错误地图:

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

这些小技巧反映了作者的经验,可以(也应该)通过自己的实验来验证

  • 总是从建立一个健壮的验证方案开始——否则,所有其他的努力都是徒劳的。再看看奔驰的排行榜。

令作者非常高兴的是,在这次比赛中,他建立了一个强大的交叉验证方案(3x10 倍),保持了一个分数,并获得了第 42 名。

  • 如果你已经建立了一个可靠的验证——永远相信你的验证结果。如果你的模型的分数因为验证而提高,但是在公共排行榜上变得更差,相信验证是更明智的。在分析中,只考虑数据,这是一个公共排行榜作为另一个折叠。你不会想让你的模型在一个单一的折叠上过度拟合,对吗?
  • 如果模型和方案允许-始终进行 OOF 预测并将其保存在模型旁边。在合奏阶段,你永远不知道什么最有帮助。
  • 总是将代码保存在结果/OOF 旁边,以便重新创建它们。在哪里保存并不重要——在 GitHub,本地,任何地方。有两次,我发现最好的模型是两周前开箱的,而且没有保存代码。痛苦。
  • 放弃选择交叉验证的“正确”种子。最好选择任意三个一,做 3хN 交叉验证。结果会更稳定。
  • 不要追逐集合中模型的数量——越少越好,但要更加多样化——在模型、预处理和数据集方面多样化。例如,在最坏的情况下,在参数中,一个深树具有硬正则化,一个浅树。
  • 对于特征选择,使用无序排列/博鲁塔/ RFE,记住在不同的基于树的模型中,特征的重要性是一袋锯屑中鹦鹉的度量。
  • 作者个人意见(可能与读者意见不一致)贝叶斯优化 >随机搜索> 超视对于超参数的选取。("> " ==更好)
  • 如果您在公共排行榜上看到分数更高的公共内核,最好的处理方式是:
  1. 如果您有时间,看看有什么新内容,更新您的渠道
  2. 更少的时间-为您的验证方案重建它,运行,获得预测-并在您的集合中使用它
  3. 没有时间—只要混合您的最佳解决方案并查看分数。
  • 如何选择两个最终的提交——当然是凭直觉。但说真的,通常每个人都会实践以下方法:
  1. 保守提交(可持续模式)/风险提交。
  2. 在验证/公共排行榜上获得最高分

记住——你周围的一切都是数字,使用它们的可能性只取决于你的想象力。用分类代替回归,把序列当成图片等等。

最后:

  • 加入 ods.ai ,享受数据科学和生活带来的乐趣!

有用的链接

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

请注意,下面的一些材料是俄语的,

普通的

http://ods.ai/—面向那些想要加入最好的数据科学社区的人

【https://mlcourse.ai/ —尼斯机器学习课程网站

https://www.Kaggle.com/general/68205——在 Kaggle 上发布关于课程的帖子(上一个链接)

总的来说,我强烈推荐使用本文描述的方法观看系列视频 ml training(Rus),其中有许多有趣的方法和技巧。

录像

课程

你可以从这个专业化如何赢得数据科学竞赛:向顶尖 kaggler学习的第二个课程中学到更多在 Kaggle 上解决问题的方法和途径。

额外阅读:

结论

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

一般来说,数据科学的主题,特别是竞争数据科学的主题是“像原子一样永不枯竭”*。在这篇文章中,作者仅仅触及了使用竞争平台提升实践技能这个主题的表面。如果你感兴趣——在 Kaggle 上注册,考察它,收集经验——写你自己的文章。好内容的数量越多,对我们大家越好!*

不,作者的管道和库还没有公开。

非常感谢来自 ods.ai 的同事们:弗拉迪米尔·伊格洛维科夫(特尔瑙斯)尤里·卡什尼茨基(约尔科)瓦列里·巴布什金(文海德)阿列克谢·普龙金(普龙金 _ 阿列克谢)德米特里·彼得罗夫(德米特里 _ 彼得罗夫)阿图尔·库津(n01z3)

特别感谢Nikita Zavgorodnii(njz)—最后的校对。

也感谢阿列克谢·伊斯克洛夫弗拉德·伊凡诺夫【命运】对翻译的修改。

感谢您的关注,希望这篇文章对某人有用。

我在ka ggle/ODS . ai:kruegger

本文原文为俄语, 发表于 2018 年 10 月 18 日 habr.com**

使用卷积神经网络(CNN 深度学习)对乳腺癌肿瘤类型进行分类

原文:https://towardsdatascience.com/how-to-fight-breast-cancer-with-deep-learning-ab28e42e4250?source=collection_archive---------15-----------------------

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

在美国,八分之一的女性(约 12%)预计会在其一生中患浸润性乳腺癌,这显然是对人类的医疗保健相关挑战。早期检测肿瘤的存在和类型是避免大多数威胁生命的情况发生的关键。

高风险女性和那些表现出乳腺癌发展症状的女性可以获得乳房区域的超声波图像。有经验的肿瘤学家应该能够查看这些图像的样本,并确定是否存在肿瘤以及肿瘤的类型。

基于其特征和细胞水平行为,肿瘤被分为两种类型:良性和恶性。

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

Illustration explaining difference between benign and malignant tumours Image source

被检测出患有恶性肿瘤的人,建议进行治疗以治愈那些癌细胞。

随着机器学习技术的出现,特别是在可以从标记有每个图像代表的类型的图像中学习的深度神经网络的方向上,现在可以基于其超声图像以高精度自动识别一种类型的肿瘤。

错误识别肿瘤类型的后果

如果医生将肿瘤错误地分类为良性而不是恶性,而实际上肿瘤是恶性的,并且选择不建议患者接受治疗,那么随着时间的推移,细胞转移到更大形式或扩散到身体其他部位的风险很大。这可能会导致威胁患者生命的情况。在统计学术语中,这将被认为是医生犯了“1 型”错误,即患者患有恶性肿瘤,但她没有被确定为患有该肿瘤。

考虑到这种可能性,如果医生保守地建议每一个患有肿瘤的患者进行癌症治愈治疗,不管他们是良性还是恶性肿瘤,那么一些患者就有遭受不必要的精神创伤和与治疗相关的其他费用的风险。在良性肿瘤的情况下,即使患者不选择接受治疗,也可以正常生活,而不会出现任何威胁生命的症状。医生的这种错误被认为是统计学意义上的“2 型”错误:患者没有恶性肿瘤,但被确定为患有恶性肿瘤。

我们还必须明白,在这种情况下,医生犯第二类错误比犯第一类错误更容易接受。在这种情况下,犯 1 型错误会给患者带来威胁生命的并发症,而 2 型错误会给患者带来不必要的费用和情感负担。

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

同样重要的是将所有患有恶性肿瘤的患者识别为患有恶性肿瘤。假设患有恶性肿瘤的患者为真阳性病例,敏感性是患有恶性肿瘤的人中通过测试被正确识别为患有恶性肿瘤的比例。

如果我们选择关注良性肿瘤患者免于不必要的治疗费用,我们必须评估诊断测试的特异性。特异性是没有恶性肿瘤的人被确定为没有恶性肿瘤的比例。

理想的肿瘤类型诊断测试将具有 1 的特异性和敏感性分数。

卷积神经网络非常适合于图像识别等应用,使用卷积神经网络可以根据肿瘤的超声图像确定肿瘤的类型。

为了探索和展示如何使用这种技术,我使用本页的提供的数据集进行了一个小实验。数据集包含 250 个肿瘤的超声灰度图像,其中 100 个为良性,150 个为恶性。

这是一些在数据集中发现的良性肿瘤的样本图像。

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

Ultrasonic images of Benign Tumours in breast

下面是一些在数据集中发现的恶性肿瘤样本。

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

Sample ultrasonic images of malignant tumours in breast

尽管与训练通常具有大量要调整的权重的神经网络所需的数据量相比,该数据集非常小,但是通过向神经网络提供分配用于训练目的的图像的随机失真,可以训练高度准确的深度学习神经网络模型,该模型可以将肿瘤类型分类为良性或恶性,具有相似的数据集质量。

训练图像数据可以通过轻微旋转、翻转、完全变换、拉伸来扩充,然后馈送到网络用于学习。这种技术有助于神经网络能够很好地进行归纳,以便在测试过程中正确地对看不见的图像进行分类。

Python 中用于构建神经网络的 Keras 库有一个非常有用的类,名为 ImageDataGenerator ,它有助于在将图像训练或测试到模型之前将这种转换应用到图像。

我将原始图像数据集分成三组:训练、验证和测试,比例为 7:2:1。只有训练和验证数据集是用 ImageDataGenerator 扩充的。

卷积神经网络的体系结构

CNN 的核心是一个多层感知器,由三种主要的层组成。

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

This how output of convolution operation from specific kernel is calculated

卷积层

在这些层中,检测边缘、形状和对象等过滤器的过滤器被应用于前一层,该前一层可以是原始输入图像层或深层 CNN 中的其他特征地图。在这一层,我们必须指定网络的重要超参数:用于过滤前一层的核的数量和大小。

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

This is how kernel moves with stride value = 2 and extra padding added around the border to apply convolutional to points located at the boundary of layer.

卷积层的另外两个参数是步幅和填充。在计算该层的下一个输出之前,步距控制内核的移动量。填充控制是否在输入层的边界上添加额外的虚拟输入点,以便应用滤波器后的结果输出与前一层相比保持相同的大小或从边界收缩。

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

汇集层

它降低了维度并消除了来自前一层的噪声激活。对于给定位置,可以通过计算从前一层连接到内核的输入的最大值或平均值来完成汇集操作。Max pooling 在应用程序中更受欢迎,因为它消除了干扰,而不会影响层的激活值。

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

展平层

它将 2D 或更高维度的前一层转换成一维向量,这更适合作为全连接层的输入。

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

Fully connected hidden layers

全连接层

这用于学习非线性决策边界,以便在以简单前馈方式紧密连接到前一层的层的帮助下执行分类任务。

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

Comparison of Standard Neural network and the one with dropout applied

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

Effect of dropout layer on the nodes in preceding layer during training and test

脱落层

在这里,我们还可以在完全连接的层之间包括脱落层。它在训练阶段随机避开来自前一层的某一部分节点的输出,并在预测阶段按比例抑制相同部分的激活。如果没有丢弃层,隐藏层中只有一小部分节点通过更新连接它们的边的权重从训练中学习,而其他节点通过在训练阶段不更新它们的边权重而“保持空闲”。在训练阶段,Dropout 通过随机避开来自前一层的特定部分节点的所有连接来强制所有边进行学习。为了在预测阶段保持类似的效果,来自先前层的所有激活都以与丢失分数相同的比例衰减。这种特殊的技术使得神经网络在最近几年变得更深更广,而不用担心一些节点和边处于空闲状态。总的来说,这种技术通过帮助 generalise 在测试阶段以更高的精度更好地分类更多看不见的案例来防止网络的过度拟合。

隐藏层通过重新激活层以仅允许正激活通过下一层。念此为理。

输出节点是一个 sigmoid 激活函数,对于从负到正的输入范围,它从 0 到 1 平滑变化。

我在 Keras 中创建了一个神经网络模型,用 Python 中的以下代码解决了这个问题。

def generate_model():
    model = Sequential()
    model.add(Conv2D(64, (3, 3), input_shape=input_shape, padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, (3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, (3,3)))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten())
    model.add(Dense(64))
    model.add(Activation('relu'))
    model.add(Dropout(0.5)) model.add(Dense(64))
    model.add(Activation('relu'))
    model.add(Dropout(0.5)) model.add(Dense(1))
    model.add(Activation('sigmoid'))    

    model.compile(loss='binary_crossentropy',
              optimizer=keras.optimizers.Adam(),
              metrics=['accuracy', sensitivity, specificity, fmed, f1])
    return model# Training Modelnum_train_samples = 10000
num_validation_samples = 1000
batch_size = 32
model = generate_model()
history_val_fmed = model.fit_generator(
    train_generator,
    steps_per_epoch= num_train_samples // batch_size,
    validation_data=validation_generator,
    validation_steps= num_validation_samples // batch_size,
    epochs=1000, 
    verbose=1,
        callbacks=[
          EarlyStopping(monitor='val_fmed', mode="max", verbose=1, patience=50),
          ModelCheckpoint(data_dir + '/nn_best_model_cv_val_fmed.h5', monitor='val_fmed', mode="max", verbose=1, save_best_only=True)
        ],
    class_weight=class_weights)

决定模型的复杂性

各种参数,如卷积层中的滤波器数量、滤波器大小和全连接层中的节点数量,决定了模型的复杂性和学习能力。在创建具有这些参数的一些值的模型并通过一些时期训练该模型之后,如果我们注意到训练误差和验证误差/损失都没有开始减小,那么这可能意味着该模型具有高偏差,因为它太简单,并且不能在问题的复杂程度上学习以准确地对训练集中的模型进行分类。在这种情况下,我们可以尝试增加模型的复杂性,例如通过在卷积层中使用更多数量和大小的滤波器,以及在全连接层中使用更多节点。

另一方面,如果我们注意到模型在训练集上做得非常好,即训练数据值的误差/损失随着模型通过更多数量的时期学习而保持下降,但是验证数据的误差/损失显著滞后或者根本没有下降,即在相同数量的时期之后保持相对显著地高于误差/损失训练数据集,则这意味着模型过度拟合训练数据集。它有很高的方差。通过减少卷积层中滤波器的数量和/或大小以及减少全连接层中节点的数量来降低模型的复杂性,有助于使验证集上的误差/损失值与训练集上的误差/损失值一样快。

用类权重处理数据不平衡

由于良性肿瘤与恶性肿瘤的样本数量比为 2:3,因此在拟合模型时,我使用了 Keras 的类别权重特征,通过为每个类别的训练样本分配不同的权重,将两个类别同等对待。

批量的重要性

将输入的训练数据分批送入神经网络。根据经验,建议将输入的批量大小保持在 32–512 之间。在神经网络训练中,在一个时期完成后更新权重。批量越大,训练越快,但是在训练和测试集上获得的总体准确度越低。你可以在这里阅读更多。

尽早停止训练并将最佳模型保存为检查点

在训练神经网络时,在称为时期的循环中训练神经网络是一种实践,其中相同或扩充的训练数据用于重复训练神经网络。这提高了神经网络在训练和验证数据集上的性能,直到一定数量的时期。在此之后,训练数据的准确性不断提高,而验证数据开始下降。这在神经网络中称为过拟合。为了防止这种情况发生,我们可以在每个时期完成后,在验证数据集上测量对我们重要的评估指标。我们可以保存最后的最好成绩,并耐心等待一定次数,以便在训练后得到提高。此外,由具有新的最佳性能测量的模型学习的权重可以被保存为模型的检查点。每次有改进,patience就被认为是复位到满。如果经过patience指定的次数后网络性能没有改善,我们可以停止用更多的次数训练模型。小patience可以在未成熟阶段停止训练模型。建议对就地保存模型检查点具有更高的耐心,以保存在搜索更好的模型中迄今为止看到的最佳性能模型的参数。通过这样做,我们可以得到参数最接近最优的模型,同时避免我们的模型过度拟合。

在处理扩充的训练样本时,我们还需要决定每个历元中用于训练的样本数量。较高的数字导致每个时期更多的训练,但是它可以降低管理性能改进和防止过度拟合之间的折衷的粒度。换句话说,对于单个时期中的大量样本,即使单个或几个额外时期也可能导致高度过度拟合的神经网络。

正如我前面提到的,我们模型的敏感性和特异性都是衡量其性能的重要指标。我们希望最大化这两者。因此,我选择使用自定义评估指标,该指标将在每个时期后进行评估,并基于其改进,决定是否提前停止训练神经网络。我把它叫做 F_med

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

注意,它类似于在信息检索任务中用于测量其质量的 F1 分数**、**的构造。但是请注意,精确度和特异性在概念上是不同的,而敏感度和召回率在概念上是相同的。

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

我选择保持每个时期的样本大小为 10,000。在每个时期之后,在样本量为 1000 的验证数据集上测试神经网络的性能,用于评估指标,如灵敏度、特异性、验证损失、验证准确性、F_med 和 f 1。我选择用 50 的耐心尝试最多 1000 个纪元。在我的例子中,在模型开始显示出过度拟合的迹象之前,花了大约 300 个历元,并且使用 Keras 的 EarlyStopping 回调在该点停止训练。训练集上的 F_med 为 0.9617,验证集上的 F _ med 为 0.9733。

通过历元训练模型时,模型性能会发生什么变化?

使用 Adam Optimizer

这是模型性能图与时期的关系。

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

评估在 Adam optimiser 上对看不见的测试数据训练的最佳执行模型,在 25 个图像的测试数据集(即原始数据集的 10%)上证明了 0.8666 的灵敏度和 0.9 的特异性。

采用 SGD 优化器和内斯特罗夫动量

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

评估在 SGD +内斯特罗夫动量优化器上对未知测试数据训练的最佳执行模型,在 25 个图像的测试数据集(即原始数据集的 10%)上证明了 0.9333 的灵敏度和 1.0 的特异性。

这里有项目笔记本Github 代码库

更多探索的方向

在这个实验中,我使用了一个小的乳腺癌肿瘤超声图像数据集来快速概述使用卷积神经网络处理癌症肿瘤类型检测问题的技术。

还有一些公开可用的数据集,包含组织病理学图像格式的乳腺细胞图像。数据集更大,图像也有多个颜色通道。感兴趣的读者也可以利用这些数据集来训练神经网络,该网络可以根据图像标签的可用性将图像分类为乳腺癌的各种亚型。

[## 乳房组织病理学图像

下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…

www.kaggle.com](https://www.kaggle.com/paultimothymooney/breast-histopathology-images) [## BreakHis

下载数千个项目的开放数据集+在一个平台上共享项目。探索热门话题,如政府…

www.kaggle.com](https://www.kaggle.com/ambarish/breakhis)

这里有一些研究论文集中在 BreakHis 数据集,用于将肿瘤分类为乳腺癌肿瘤的 8 种常见亚型之一。

https://www . science direct . com/science/article/pii/s 0925231219313128

[## 基于深度学习的乳腺癌组织病理学图像分析

乳腺癌是世界上发病率最高的癌症,并且已经成为主要的癌症

www.ncbi.nlm.nih.gov](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6390493/)

我希望你发现这篇文章很有见地,可以帮助你开始探索和应用卷积神经网络来基于图像对乳腺癌类型进行分类的方向。就像你一样,我非常兴奋地看到临床世界采用人工智能和机器学习的现代进步来解决人类面临的挑战。

如何通过列值过滤熊猫数据帧的行

原文:https://towardsdatascience.com/how-to-filter-rows-of-a-pandas-dataframe-by-column-value-51996ea621f8?source=collection_archive---------1-----------------------

过滤行的两种简单方法

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

Image Courtesy of Peter Oslanec via Unsplash

通常需要根据列值过滤表格数据。我们可能会看到一个表格,并希望执行自定义过滤操作。幸运的是,我们可以利用熊猫来做这个手术。Pandas 是一个用于数据分析的开源 Python 库。它使 Python 能够处理类似电子表格的数据,实现快速文件加载和操作等功能。为了实现这些特性,Pandas 向 Python 引入了两种数据类型:Series 和 DataFrame。

本教程将重点介绍通过列值过滤数据帧的两种简单方法。

以下示例是 BLAST 搜索的结果。在生物信息学中,BLAST(基本局部比对搜索工具)是一种用于比较一级生物序列信息的算法,例如蛋白质的氨基酸序列或 DNA 和/或 RNA 序列的核苷酸。这个表有一个用数字表示的查询序列的 ID 和与之匹配的物种,以及其他元数据。

这个例子完全是任意的,下面的技术可以应用于大量的其他情况。

首先,我们导入 pandas 库,并给它起别名 pd

然后我使用熊猫 read_csv() 函数读取我的数据帧。我用文件扩展名保存了我的数据帧。csv(逗号分隔值文件)。接下来,我执行一些基本操作来熟悉数据帧。下面显示的是我常用的三种操作。其中包括:使用 head 方法打印前 5 行,使用 DataFrame 对象的 column 属性访问列名。最后,我查看 DataFrame 对象的 shape 属性。

这三个打印函数的输出如下所示(为了增强表示,我建议对 Jupyter 笔记本运行相同的代码,这将把 pandas DataFrame 对象显示为一个更加浏览器友好的 HTML 表)。shape 属性返回一个元组,该元组在逗号的左侧给出行数,在右侧给出列数。该数据帧有 29 行和 5 列。但是请注意,只显示前 5 行。

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

假设我们想要过滤该数据帧,以便排除Species _ name _ blast _ hit列中的任何“细菌”条目。

我们将如何着手做这件事?

我将介绍两种选择性过滤表格数据的方法。

首先,我创建了一个布尔值的 Python 列表。然后,我编写了一个 for 循环,该循环迭代熊猫系列(系列是数据帧中的一列)。熊猫系列,Species _ name _ blast _ hit是一个可迭代的对象,就像一个列表。然后,我在条件语句中使用一个基本的正则表达式,如果“细菌”不在序列值中,则附加 True,如果“细菌”存在,则附加 False。当我打印布尔列表的前 5 个条目时,所有的结果都为真。

这完全在意料之中,我们从前面的表格中可以看到, 中的前 5 个条目 Species_name_blast_hit 名称中没有细菌。

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

这里,我创建了一个布尔列表,其长度与 DataFrame,29 相同。接下来,我将布尔列表转换成 Pandas 系列,并给它分配变量名 Filtered。

您可以通过向 ***pd 传递一个列表来创建一个熊猫系列。*系列()**功能。

接下来,我对我的原始 Pandas 数据帧使用布尔子集/索引,使用方括号符号 Blast,并为新数据帧分配变量名 New_blast_df 。在这里,我写了原始的 DataFrame,Blast,后面是方括号,里面是经过过滤的熊猫系列。该系列指示选择哪些行,因为它由真值和假值组成,这些值与 Blast 数据集中的行相对应。

从 Jupyter 笔记本输出中可以清楚地看到,所有的“细菌”条目都被忽略了!

我们可以通过检查从原始数据帧中删除的行数,从 shape 属性返回的 New_blast_df 的第一个索引中减去 shape 属性返回的元组的第一个索引。现在,我们可以看到删除了 8 行。

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

幸运的是,还有一种更简单的方法可以通过列值来划分数据帧的子集。对于这个例子,让我们假设我们只想要包含那些包含物种名‘Phoxinus’的行。

这种方式使用了 包含 的方法。 包含 方法返回一个布尔数组,如果每个字符串都包含该模式。要使用它,您需要输入 DataFrame 的名称,然后使用点标记法选择感兴趣的适当列名,接下来是。str 和最后的 包含 ()。contains 方法还可以找到部分名称条目,因此非常灵活。

默认情况下. str.contains 区分大小写。要忽略大小写,只需将关键字参数 case 设置为 False,. str.contains(case=False)。这进一步增加了灵活性,但必须谨慎使用。

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

结论

本教程演示了两种基于列值过滤表格数据的方法。虽然这里给出的例子利用了单个条件,但是可以容易地应用多个条件来进一步微调滤波输出。

如何找到黑盒模型的特征重要性?

原文:https://towardsdatascience.com/how-to-find-feature-importances-for-blackbox-models-c418b694659d?source=collection_archive---------17-----------------------

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

Source: DavidRockDesign, Randomness-the lifeblood of many algorithms

DS 算法

置换重要性作为一种特征选择方法

数据科学是对算法的研究。

我每天都在努力学习许多算法,所以我想列出一些最常见和最常用的算法,这些算法将在这个新的 DS 算法系列中使用。

有多少次,当你创建了很多功能,然后你需要想办法减少功能的数量?

上次我写了一篇名为“每个数据科学家都应该知道的 5 种特征选择算法”的文章,其中我谈到了使用相关性或基于树的方法,并在特征选择过程中添加一些结构。

最近,有人向我介绍了另一种新颖的特征选择方式,叫做 排列重要性 ,我非常喜欢这种方式。

因此,这篇文章解释了排列重要性是如何工作的,以及我们如何用 ELI5 来编码它。

什么是排列重要性?

简单地说,我们可以根据我们的评估指标(F1、准确性 AUC 等)来确定某个特征的重要性。)在我们从数据集中移除特定要素时会发生变化。

这可能非常简单—我们从数据集中移除一个要素,训练分类器,然后查看评估指标如何变化。我们对所有功能都这样做。

因此,我们至少拟合我们的模型 n 次,其中 n 是模型中特征的数量。这是如此多的工作和计算。 我们能做得更好吗?

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

Source: We permute a feature and predict using the updated dataset. Intuitively, if our accuracy or any evaluation metric doesn’t take a hit, we can say that the feature is not important. If our accuracy does take a hit, we consider this feature important.

是的,我们可以。为了计算排列重要性,我们对单个要素的值进行混洗/排列,并使用生成的数据集进行预测。

然后,这些预测用于计算我们的评估指标。直观地说,如果我们的准确性或任何评估指标没有受到影响,我们可以说这个特性不重要。如果我们的准确性受到影响,我们认为这个特性很重要。

数据

我们将尝试使用数据集来更好地理解它。

我将使用一个足球运动员数据集,并尝试使用它找出最重要的特征。

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

如果你不懂足球术语,也不用担心。我会尽量把它保持在最低限度。

你可以在这个 Kaggle 内核中看到完整的代码。

一些简单的数据预处理

我们已经做了一些基本的预处理,如删除空值和一个热编码。我们还使用以下公式将问题转化为分类问题:

y = traindf['Overall']>=80

在这里,我们用高总体来代表一个伟大的球员。我们的数据集(X)如下所示,有 223 列。

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

train Data X

履行

1.对于 sklearn 型号

ELI5 库让我们很容易对sklearn模型使用排列重要性。首先,我们训练我们的模型。

from sklearn.ensemble import RandomForestClassifier
my_model = RandomForestClassifier(n_estimators=100,
                                  random_state=0).fit(X, y)

然后我们使用来自eli5.sklearn模块的函数PermutationImportance

from eli5.sklearn import PermutationImportance
import eli5
perm = PermutationImportance(my_model,n_iter=2).fit(X, y)
eli5.show_weights(perm, feature_names = X.columns.tolist())

结果看起来像:

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

这里我们注意到反应、拦截和控球是衡量一名球员水平的最重要的特征。

2.对于黑盒模型或非 sklearn 模型

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

我们还可以使用 eli5 来计算非 scikit-learn 模型的特征重要性。这里我们训练一个 LightGBM 模型。

import numpy as npfrom lightgbm import LGBMClassifierlgbc=LGBMClassifier(n_estimators=500, learning_rate=0.05, num_leaves=32, colsample_bytree=0.2,
            reg_alpha=3, reg_lambda=1, min_split_gain=0.01, min_child_weight=40)lgbc.fit(X,y)

我们需要为分数函数创建一个包装器来计算我们的评估指标。

from sklearn.metrics import accuracy_score#define a score function. In this case I use accuracy
def score(X, y):
    y_pred = lgbc.predict(X)
    return accuracy_score(y, y_pred)

我们现在可以使用来自eli5.permutation_importanceget_score_importances函数来获得最终的特征重要性。

from eli5.permutation_importance import get_score_importances# This function takes only numpy arrays as inputs
base_score, score_decreases = get_score_importances(score, np.array(X), y)feature_importances = np.mean(score_decreases, axis=0)

我们可以使用以下工具来查看前 5 大功能:

feature_importance_dict = {}
for i, feature_name in enumerate(X.columns):
    feature_importance_dict[feature_name]=feature_importances[i]print(dict(sorted(feature_importance_dict.items(), key=lambda x: x[1], reverse=True)[:5]))---------------------------------------------------------------
{'Reactions': 0.019626631422435127,
 'Interceptions': 0.004075114268406832,
 'BallControl': 0.0025001376727793235,
 'ShortPassing': 0.0012996310369513431,
 'Strength': 0.0009251610771518149}

结论

特征工程和特征选择是任何机器学习管道的关键部分。

我们力求模型的准确性,如果不一次又一次地重温这些作品,就不可能达到良好的准确性。

在这篇文章中,我试图解释排列作为一种特征选择方法的重要性。它帮助我们找到任何黑盒模型的特征重要性,不像我之前的文章中关于特征选择的技术。

如果你想了解更多关于特征工程/选择的知识,我想在 Kazanova 的高级机器学习专业化课程中喊出如何赢得数据科学竞赛:向顶级 Kagglers 学习。本课程讲述了许多使用有用的特征工程/选择技术来改进模型的直观方法。绝对推荐。

谢谢你的阅读。将来我也会写更多初学者友好的帖子。在关注我或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系。

如何使用 MATLAB 找到线性(支持向量机)和二次分类器

原文:https://towardsdatascience.com/how-to-find-linear-svms-and-quadratic-classifiers-using-matlab-97ea7550655a?source=collection_archive---------28-----------------------

使用 YALMIP 寻找用于数据分类的分离超平面和二次超曲面的快速指南(带图片)

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

A pretty smart looking elliptic hyperboloid

想知道线性分类器是否可以推广到其他形状,而不仅仅是一个看起来无聊的平面(或超平面)?

是的。欢迎来到二次分类器的世界,其中两个或更多类别的数据点由二次曲面分隔开!

现在,在我们进入所有这些之前,让我们看看什么是线性分类器,以及我们如何用 MATLAB 和 Johan Lö fberg 开发的优化包 YALMIP 对它们建模。然后,在本文的后半部分,我将讨论二次分类器以及如何对它们建模。

*这篇文章的某些部分可能看起来有点过于数学化,但我会尽可能保持简单,以便在编程部分花更多的时间。

我们都从数据开始

我们从一些随机数据点开始,每个数据点在欧几里得空间中有 3 个维度。这些点来自 2 个不同的类(X & Y),我们每个类有 5 个点。

% Define some key problem parameters
nDimension = 3;
nVariable = 5;% Generate some random numbers
X = randn(nDimension, nVariable);
Y = randn(nDimension, nVariable);

*你总是可以将问题一般化到更高的维度、更多的类和更多的数据点,但在本文中我们将保持这些值较小,以保持事情简单和易于可视化。

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

Random data points that we have just generated in 3D-space

然后,想法是找到一个分类器,使用来自给定数据点的信息,将整个空间(在这种情况下是 3D 欧几里得空间)分成两个,其中位于一侧的所有点属于类别 X,而位于另一侧的点属于第二类别 y。

但是我们如何选择一个边界来分隔整个空间呢?快速直观的方法是使用平面。

分离超平面

超平面指的是一个子空间,它的维数比它所在的空间的维数小一。换句话说,一个超平面在一个 n 维空间中将有 n-1 维。

例如,在 2D 空间中,超平面将是 1D 线,而在 3D 空间中,超平面将仅仅是 2D 平面。

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

Visualisations of what a hyperplane is (Image: DeepAI)

回到我们的问题,我们想要构建一个超平面来将整个空间一分为二。特别地,我们希望超平面(仅由向量 a 和标量 b 定义)满足以下等式:

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

Equations that define a separating hyperplane

其中 ab ,分别是一个矢量和一个标量。

如您所见,这假设数据点的坐标之间存在某种线性关系。

然而,正如我们的本能现在可能已经告诉我们的那样,并不总是可能找到一个超平面,它会以这样一种方式完美地分隔整个空间,即只有属于 X 的点位于一侧,而属于 Y 的点位于另一侧。

尽管如此,即使这是真的情况,我们仍然希望找到最好的超平面,在某种程度上将空间一分为二,即使这意味着有一些点在错误的一边结束。

为此,我们需要在方程中引入一些误差变量(每个数据点一个),以便在定义超平面时留有余地:

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

Equations for a less than perfect hyperplane

类似于 ab ,这些误差变量由我们决定,用最优化的说法就是我们所说的决策变量。

现在我们的问题以这种方式定义,最佳超平面可以说是最好地减少这些误差总和的超平面。因此,我们问题的目标可以简洁地改写为:

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

A linear programme that when solved, provides a separating hyperplane

正如你们中的一些人现在已经注意到的,我们上面定义的问题被称为线性规划,因为它的目标函数(最小化函数)和约束条件(所有其他方程/不等式)都是线性的。

用 MATLAB 实现线性规划

回到我们离开 MATLAB 的地方,我们想使用 YALMIP 来求解我们已经定义的线性规划,以便获得一个分离超平面。

我们从定义线性规划中的决策变量开始。这需要为它们中的每一个创建一个 sdpvar 对象,然后 YALMIP 会将其识别为决策变量:

% Hyperplane variables
a = sdpvar(nDimension, 1, 'full');
b = sdpvar(1);% Error variables for points in X and in Y
xError = sdpvar(1, nVariable);
yError = sdpvar(1, nVariable);

接下来,我们继续定义问题中的约束:

% Error variables should be above 0
constraints = [xError >= 0, yError >=0];% Hyperplane constraints
constraints = [constraints, a'*X+b <= -(1-xError), a'*Y+b >= 1-yError];

最后,我们需要指定我们的目标函数:

% Minimise error values for all points in X and in Y
objective = sum(xError) + sum(yError);

定义了我们的问题,剩下的就是解决问题了!我们通过调用 optimize() 函数来实现这一点。

% Solve the linear programme
diagnosis = optimize(constraints, objective);disp(diagnosis.info); % Success/failure report

检索决策变量的值和最优目标值是容易的;它们的最佳值存储在创建它们时所在的对象中。

然而,我们需要将它们从SDP 变量转换为实际值,以访问它们的最佳值:

a = value(a);
disp('a =');
disp(a);b = value(b);
disp('b =');
disp(b);objective = value(objective);
disp('Optimal objective =');
disp(objective);

如果确实可以为您生成的随机数据点找到一个完美的超平面,您应该会得到这样的结果,其中最佳目标值正好是 0:

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

否则,高于 0 的目标值将指示所找到的超平面没有将 3D 空间完美地分成仅包含来自每一侧的 X 或 Y 的数据点的两个半空间。

绘制超平面

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

Where’s the fun in solving the problem if we don’t get to see anything?

因为我使用的例子非常简单——只有来自两个不同类的 10 个数据点的三维例子,所以很容易(也是可行的)将我们从求解线性规划中获得的结果绘制到图上。

让我们首先从绘制超平面开始。

回想一下超平面需要满足的两个方程?那么,为了画出实际的分离超平面,我们只需要画出超平面的一般方程:

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

General equation of a hyperplane

为此,我们将生成一些虚拟的x-坐标和y-坐标值,然后通过求解上面的等式来计算它们各自的z-坐标值。在 MATLAB 中,这看起来像这样:

% Generate x and y dummy data points
[xValuesDummy,yValuesDummy] = meshgrid(-4:0.1:4);% Solve for z
zValuesDummy = -1/a(3)*(a(1)*xValuesDummy + a(2)*yValuesDummy + b);% Plot the hyperplane
surf(xValuesDummy, yValuesDummy, zValuesDummy, 'FaceAlpha', 0.5, 'FaceColor', 'blue')% Holds the figure before displaying
hold on;

接下来,我们需要沿着每个轴检索每个数据点的坐标值,并将它们存储在相应的数组中。我们还想选择不同的颜色来绘制这两个类的数据点。

% Retrieve values of each data point along each axis
xValues = [X(1,:) Y(1,:)];
yValues = [X(2,:) Y(2,:)];
zValues = [X(3,:) Y(3,:)];% Create different colours for points from different classes
Colour = repmat([1,10],nVariable,1);
colour = Colour(:);% Plot the data points
scatter3(xValues.', yValues.', zValues.', 100, colour,'filled');

完成后,您应该能够制作出如下漂亮的 3D 图:

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

A perfect separating hyperplane

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

A hyperplane that fails to separate the data points into 2 separate half-spaces

现在,如果您不想使用超平面将空间分成两半,尤其是当您的数据似乎不是线性分布时,该怎么办?

嗯,我们可以尝试找到我们的数据点之间的非线性关系,其中一种方法是考虑将它们分开的二次函数!

分离二次曲面

什么是二次曲面?简单地说,它们是 2D 圆锥曲线(椭圆、双曲线和抛物线)的一般化形式。

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

I hope you find these more cool-looking than hyperplanes (Image: Saeid Pashazadeh & Mohsen Sharifi)

正如您可能已经想到的,这些形状在某些情况下可能更适合某些数据,所以让我们来试试吧!

类似于我们如何提出定义分离超平面的方程,我们需要寻找满足这些二次方程的对称矩阵 A ,向量 b 和标量 c :

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

Equations that define a separating quadric surface

同样,我们需要包含误差变量,以使我们的模型能够拟合无法通过二次曲面分离的数据集:

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

Equations for a not-so-perfect separating quadric surface

有了这些方程,我们现在可以定义我们的新问题,就像在超平面的情况下一样:

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

Problem to solve to find a quadric surface

用 MATLAB 求解

现在,我们的决策变量不再像我们在超平面问题中使用的那些变量,让我们看看我们应该如何定义它们,以便可以使用 YALMIP 解决它们:

% Quadric surface variables
A = sdpvar(nDimension, nDimension, 'symmetric');
b = sdpvar(nDimension, 1);
c = sdpvar(1);% Error variables for points in X and in Y
xError = sdpvar(1, nVariable);
yError = sdpvar(1, nVariable);

接下来,我们必须定义问题中的约束:

% Error variables should be above 0
constraints = [xError >= 0, yError >=0];% Quadric surface constraints
constraints = [constraints, diag(X'*A*X)'+b'*X+c<= -(1-xError), diag(Y'*A*Y)'+b'*Y+c >= 1-yError]; % We are only concerned with the diagonal entries of the nVariable x nVariable matrix

最后,我们指定问题的目标函数:

% Minimise average error values for all points in X and in Y
objective = sum(xError) + sum(yError);

现在,是时候使用我们在超平面问题中使用的同一个函数 optimize() 来解决问题了:

diagnosis = optimize(constraints, objective);disp(diagnosis.info); % Success/failure report

在成功完成算法后,我们检索最优决策变量和最优目标值。

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

A perfect separating quadric surface is found!

绘制二次曲面

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

A hyperboloid that separates the two data classes

与我们在上一节中绘制超平面的方式不同,我们需要采用一种稍微不同的方法来绘制二次曲面。

我们首先在整个绘图区域生成虚拟的 x、y 和 z 值,当使用函数 isosurface() 时,这些值将用于求解一般的二次曲面方程。 lhs 表示将用作函数第 4 个参数的等式左侧,而 0 表示用作第 5 个参数的等式右侧。

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

General equation of a quadric surface

% Generate x, y and z dummy data points
[xValuesDummy,yValuesDummy,zValuesDummy]= meshgrid(-5:0.05:5); q1 = A(1,1)*xValuesDummy+A(2,1)*yValuesDummy+A(3,1)*zValuesDummy;
q2 = A(1,2)*xValuesDummy+A(2,2)*yValuesDummy+A(3,2)*zValuesDummy;
q3 = A(1,3)*xValuesDummy+A(2,3)*yValuesDummy+A(3,3)*zValuesDummy;lhs = q1.*xValuesDummy+q2.*yValuesDummy+q3.*zValuesDummy+b(1)*xValuesDummy+b(2)*yValuesDummy+b(3)*zValuesDummy + c; isosurface(xValuesDummy,yValuesDummy,zValuesDummy,lhs,0);hold on;

最后但同样重要的是,我们将绘制两个类中发现的单个数据点:

% Plot data points
xValues = [X(1,:) Y(1,:)];
yValues = [X(2,:) Y(2,:)];
zValues = [X(3,:) Y(3,:)];Colour = repmat([1,10],nVariable,1);
colour = Colour(:);scatter3(xValues', yValues', zValues', 25, colour,'filled');

瞧,你完成了!这将允许您生成各种二次曲面,将您的数据点分隔在醒目的图中,如下所示:

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

2-sheet hyperboloid

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

Hyperbolic paraboloid (or saddle)

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

Hyperbolic cylinder

当然,如果生成的任何二次曲面未能完美分离所有数据点,也不必过于惊慌。就像在超平面的情况下,不可能总是找到适合每个可能的数据集的完美解决方案。

结论

我刚刚向您展示了如何使用 MATLAB 和 YALMIP 不仅可以找到而且可以绘制分离超平面和二次曲面以进行数据分类。

然而,重要的是要记住,我给出的例子非常简单,当然可以推广到更高维度和更大数量。尽管这些问题仍然很容易解决,但是如果数据大于三维,就很难用同样的方式显示所有的数据。

我希望你已经对各种功能和情节玩得很开心了,非常感谢你阅读我的文章,如果你设法一直做到这里的话!

如何从概率密度图中找到概率

原文:https://towardsdatascience.com/how-to-find-probability-from-probability-density-plots-7c392b218bab?source=collection_archive---------5-----------------------

通过知道一个范围内的实际概率来理解数据的分布

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

在进一步发展之前,让我们面对它。

如果您已经在数据科学领域工作了一段时间,那么您可能已经制作了概率密度图(如下所示)来了解数据的总体分布。

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

(Source)

嗯…首先,什么是密度图?Will Koehrsen 给出了一个伟大而清晰的解释:

密度图是根据数据估计的直方图的平滑、连续版本。

最常见的估计形式被称为核密度估计 (KDE)。

在这种方法中,在每个单独的数据点绘制一条连续的曲线(内核),然后将所有这些曲线加在一起,进行一次平滑的密度估计。

最常用的内核是一个高斯(它在每个数据点产生一个高斯钟形曲线)

概率密度图简单地表示概率密度函数(Y 轴)对变量数据点(X 轴)的密度图。

通常,概率密度图用于了解连续变量的数据分布,我们希望知道获得连续变量可以假设的数值范围的可能性(或概率)。

但问题是。

通过显示概率密度图,我们只能直观地了解数据的分布,而不知道某一范围值的确切概率。

换句话说,仅仅看图很难量化曲线下的概率。

然而,得到曲线下的确切概率是极其重要的(我会在下一节告诉你为什么),尤其是当你向商业利益相关者陈述的时候。**

在本文中,我将向您展示我用来计算概率的完整代码,并一步一步地向您解释您如何也能这样做。

在本文结束时,我希望您能够通过计算一系列值中的实际概率来更好地理解数据的分布,并随后能够用您的见解说服利益相关者。

你可以从我的 GitHub 获取数据集和 jupyter 笔记本。

我们开始吧!

为什么概率密度图说服力不够?

从视觉上回顾上面的密度图,你可能会得出一个结论,阿拉斯加航空公司的航班往往比联合航空公司更早。

想象一下,现在你的老板问了这个问题,并质疑你的说法,“阿拉斯加航空公司的航班比联合航空公司的航班早多少,发生这种情况的几率有多高?你有什么数字证据证明你的结论是正确的吗?”****

你惊呆了。因为结论来自于你对数据整体分布的观察。

更糟糕的是,现在你没有任何数字证据——确切的概率——来支持你的说法。

你没有做好充分的准备,如果你不能证明自己的观点,你作为数据科学家的可信度就会立刻下降。

这就是从概率密度图计算概率的重要性所在。

不幸的是,如果你使用 Seaborn 来制作使用distplot的密度图,很难计算概率。

在花了一些时间弄清楚如何计算概率之后,我决定使用来自sklearnKernelDensity

这个方法非常有效,我很高兴能和你分享这个!👇🏻

下面是如何从概率密度图中找到概率

我们将使用小费数据,它由一些可能影响餐馆中顾客给小费数量的因素组成。你可以在这里得到数据

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

Tips data loaded in a dataframe

因为我们的目标是从密度图中找到概率,所以为了简单起见,我们将集中回答一个问题— 顾客在午餐/晚餐时间会给更多小费吗?

由于数据已经足够清晰,因此我们可以开始绘制密度图并直接计算各自的概率值。

对于以下步骤,请参考笔记本了解所用功能的完整代码实现。

1.绘制概率密度图

Function to make probability density plots without using Seaborn

由于 Seaborn 没有提供任何从 KDE 计算概率的功能,因此代码遵循这 3 个步骤(如下)来绘制概率密度图,并输出 KDE 对象来计算概率。

  • 绘制标准化直方图
  • 执行核密度估计(KDE)
  • 绘图概率密度

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

Probability density plot of tips amount (USD) given by customers

现在我们有了午餐和晚餐时间小费数量的概率密度图来进行比较。

仅从顾客给的 1-3 美元的小费来看,我们可以得出这样的结论:与晚餐时间相比,的顾客更倾向于在午餐时间给 1-3 美元的小费。

同样,为了有数字证据(也称为概率值)来加强我们的陈述,让我们计算一下顾客在午餐和晚餐时间给 1-3 美元小费的概率,以作比较。

2.计算概率

Function to calculate probability

一旦我们使用函数plot_prob_density绘制了概率密度图,我们将使用这个函数的输出 KDE 对象作为输入来使用下一个函数get_probability计算概率。

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

Calculate and output probability

现在你知道了!

标准化密度曲线下的概率总和总是等于 1。由于概率是曲线下的面积,因此我们可以指定一个值范围(本例中为 1-3 美元小费)来计算该范围内的概率。

因此,概率就是概率密度值(Y 轴)和小费数量(X 轴)的乘积。

乘法在每个评估点上完成,然后将这些相乘的值相加,以计算最终概率。

计算出的概率证明支持了我们最初的说法——与晚餐时间相比,顾客倾向于在午餐时间给 1-3 美元的小费,概率为 63%比 49%。****

最后的想法

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

Photo credit: Campaign Creators

感谢您的阅读。

我希望这篇文章能让你对概率密度图有更好的理解,最重要的是,向你展示如何计算概率密度曲线下值范围内的实际概率。

计算概率相当简单,但并不简单。它确实起到了至关重要的作用让利益相关者更好地理解你的概率密度图,从而根据数字证据而不是主观和模糊的观察提出可行的见解。

一如既往,如果您有任何问题或意见,请随时在下面留下您的反馈,或者您可以随时通过 LinkedIn 联系我。在那之前,下一篇文章再见!😄

关于作者

Admond Lee 目前是东南亚排名第一的商业银行 API 平台【Staq】的联合创始人/首席技术官。

想要获得免费的每周数据科学和创业见解吗?

加入 Admond 的电子邮件简讯——Hustle Hub,每周他都会在那里分享可行的数据科学职业技巧、错误&以及从创建他的初创公司 Staq 中学到的东西。

你可以在 LinkedInMediumTwitter脸书上和他联系。

** [## 阿德蒙德·李

让每个人都能接触到数据科学。Admond 正在通过先进的社交分析和机器学习,利用可操作的见解帮助公司和数字营销机构实现营销投资回报。

www.admondlee.com](https://www.admondlee.com/)**

如何用 spaCy 和 StanfordNLP 寻找最短依赖路径

原文:https://towardsdatascience.com/how-to-find-shortest-dependency-path-with-spacy-and-stanfordnlp-539d45d28239?source=collection_archive---------7-----------------------

最短依赖路径是关系抽取中常用的方法

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

Photo by Caleb Jones on Unsplash

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

考虑到文档和依赖解析的准确性,我推荐使用 spaCy 而不是 StanfordNLP。

内容结构如下。

  • 什么是最短依赖路径(SDP)?
  • 用空间寻找最短依赖路径
  • 用 StanfordNLP 查找最短依赖路径

什么是最短依赖路径(SDP)?

语义依存句法分析曾被频繁地用于剖析句子和捕获单词的语义信息,这些语义信息在上下文中靠近,而在句子距离较远的地方靠近**。**

要提取两个实体之间的关系,最直接的方法是使用 SDP。使用 SDP 的动机是基于这样的观察实体之间的 SDP 通常包含识别它们关系的必要信息。

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

A dependency tree example

Convulsions that occur after DTaP are caused by a fever.

在上图中,方括号中的单词是标记的实体。红色虚线箭头表示两个实体之间的 SDP

用空间寻找最短依赖路径

首先,在终端中安装必要的库。为了清晰起见,我添加了版本号。

pip install spacy==2.1.4
python -m spacy download en_core_web_smpip install stanfordnlp==0.2.0
pip install networkx==2.3

首先,我们按照官方教程打印出所有的依赖标签。

import spacy
import networkx as nxnlp = spacy.load("en_core_web_sm")doc = nlp(u'Convulsions that occur after DTaP are caused by a fever.')for token in doc:
    print((token.head.text, token.text, token.dep_))# output: (head, current_token, dep_relation)
('caused', 'Convulsions', 'nsubjpass')
('occur', 'that', 'nsubj')
('Convulsions', 'occur', 'relcl')
('occur', 'after', 'prep')
('caused', 'DTaP', 'nsubjpass')
('caused', 'are', 'auxpass')
('caused', 'caused', 'ROOT')
('caused', 'by', 'agent')
('fever', 'a', 'det')
('by', 'fever', 'pobj')
('caused', '.', 'punct')

我们可以通过方便的空间可视化工具绘制整个依赖树。

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

下面的代码可以给 SDP

import spacy
import networkx as nxnlp = spacy.load("en_core_web_sm")doc = nlp(u'Convulsions that occur after DTaP are caused by a fever.')print('sentence:'.format(doc))# Load spacy's dependency tree into a networkx graph
edges = []
for token in doc:
    for child in token.children:
        edges.append(('{0}'.format(token.lower_),
                      '{0}'.format(child.lower_)))graph = nx.Graph(edges)# Get the length and path
entity1 = 'Convulsions'.lower()
entity2 = 'fever'print(nx.**shortest_path_length**(graph, source=entity1, target=entity2))
print(nx.**shortest_path**(graph, source=entity1, target=entity2))

edges如下图所示。

In [6]: edges
Out[6]:
[('convulsions', 'occur'),
 ('occur', 'that'),
 ('occur', 'after'),
 ('caused', 'convulsions'),
 ('caused', 'dtap'),
 ('caused', 'are'),
 ('caused', 'by'),
 ('caused', '.'),
 ('by', 'fever'),
 ('fever', 'a')]

输出如下

3
['convulsions', 'caused', 'by', 'fever']

这意味着从“抽搐”到“发烧”的 SDP 长度为 3。

如果你不想使用 networkx 库,而只使用 spaCy,你可以查看我的另一个帖子,用 spaCy 找到最低公共祖先最短依赖路径

用 StanfordNLP 查找最短依赖路径

首先,我们按照官方教程打印出所有的依赖标签。

import stanfordnlpstanfordnlp.download('en')
nlp = stanfordnlp.Pipeline()doc = nlp('Convulsions that occur after DTaP are caused by a fever.')
doc.sentences[0].print_dependencies()# output: (current_token, head_index, dep_relation)
('Convulsions', '0', 'root')
('that', '3', 'nsubj')
('occur', '1', 'acl:relcl')
('after', '7', 'mark')
('DTaP', '7', 'nsubj:pass')
('are', '7', 'aux:pass')
('caused', '3', 'advcl')
('by', '10', 'case')
('a', '10', 'det')
('fever', '7', 'obl')

为了遵循 networkx 图的[(token, children), (token, children),...]格式,我们需要根据源代码修改代码。

import stanfordnlpstanfordnlp.download('en')
nlp = stanfordnlp.Pipeline()doc = nlp('Convulsions that occur after DTaP are caused by a fever.')# Load stanfordnlp's dependency tree into a networkx graph
edges = []
for token in doc.sentences[0].dependencies:
    if token[0].text.lower() != 'root':
        edges.append((token[0].text.lower(), token[2].text))graph = nx.Graph(edges)# Get the length and path
entity1 = 'Convulsions'.lower()
entity2 = 'fever'
print(nx.shortest_path_length(graph, source=entity1, target=entity2))
print(nx.shortest_path(graph, source=entity1, target=entity2))

edges如下图所示。

In [19]: edges
Out[19]:
[('occur', 'that'),
 ('convulsions', 'occur'),
 ('caused', 'after'),
 ('caused', 'DTaP'),
 ('caused', 'are'),
 ('occur', 'caused'),
 ('fever', 'by'),
 ('fever', 'a'),
 ('caused', 'fever'),
 ('convulsions', '.')]

输出如下

3
['convulsions', 'occur', 'caused', 'fever']

即使是 StanfordNLP 计算的 SDP 长度也与 spaCy 相同。但在 SDP 中两个实体之间的词语应该是 **'caused', 'by'** 。因此,spaCy 的依赖解析精度优于 StanfordNLP。

查看我在 中的其他帖子 一个归类视图
git hub:
BrambleXu LinkedIn:徐亮***Blog:***BrambleXu

参考

** [## 如何在 Python 中找到两个单词之间的最短依赖路径?

您的问题可以很容易地想象成一个图形问题,我们必须找到两个节点之间的最短路径。去…

stackoverflow.com](https://stackoverflow.com/questions/32835291/how-to-find-the-shortest-dependency-path-between-two-words-in-python) [## 基于最短依赖路径的蛋白质-蛋白质关系卷积神经网络…

生物医学关系在生物过程中起着重要的作用,在生物医学领域得到了广泛的研究。

www.ncbi.nlm.nih.gov](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4963603/)**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值