一、医疗保健中的机器学习概述
2018 年 1 月下旬,我坐在班加罗尔市中心的一家豪华酒店里,与医疗保健领域的一位精英,以及一位著名的国际医生和一位 Python 程序员在一起。讨论围绕如何在医疗保健和金融领域应用机器学习展开。作为我的客户之一,他不仅想获得想法,还想从 Python 代码的实用角度了解如何将数据用于他的大型连锁医院的一些工作,以及他在股票市场、商品投资等领域的投资。在为期 4 天的会议中,我的讨论不仅激烈,而且深入到了医疗保健行业的商业领域。在与我的客户一起研究了我的许多医疗保健项目中的类似模式后,在本书中,我向您展示了一些很好的实现实例,这些实例不仅可行,而且具有很大的商业意义。虽然我所做的大部分工作都属于保密协议的范畴,因此不允许我泄露机密,但在这本书里,你会发现许多来自现实世界的想法的实现的例子。真实的数据没有被使用。我在本书中展示的大部分数据来自公共领域。在本书中,我将使用 Python 版兼容代码。
注意
Python 3 . x 版贯穿全书。如果您有一个旧版本的 Python,代码示例可能无法工作。您需要 Python 3.x 或更高版本才能成功运行它们。
为练习安装 Python
要运行本书中的练习,您需要 Python 3.x。为此,我建议您使用 WinPython。WinPython 是一个简单的 Python 发行版,它不需要像 Anaconda 那样的任何安装。你可以把它复制到 Windows 的一个文件夹里,把你的$PYTHONPATH 改成你复制 WinPython 的文件夹,就大功告成了。WinPython 已经预装了我们在本书中需要的所有主要包。所以如果你使用 WinPython,你会节省时间。你可以从 github 上的 https://winpython.github.io/ 下载 WinPython。根据您的计算机需求,选择 64 位或 32 位版本的发行版。在撰写本书时,WinPython 网站发布了 WinPython 3 . 5 . 4 1gt-64 bit。本书中的所有代码练习都适用于这个版本的 WinPython。然而,如果你想在 Windows 上工作,我会推荐你在 Linux 上安装 Anaconda for Python,这里给出: https://anaconda.org/anaconda/python 。
技术采用过程
在我们开始看机器学习如何改变医疗保健之前,让我们看看机器学习技术及其采用的过程。这个过程是所有部门和行业共有的。我还将举例说明在医疗保健、零售和金融等领域的采用过程。
根据机器学习的定义,它是计算机科学的一个领域,赋予计算机系统利用数据进行“学习”(即逐步提高特定任务的性能)的能力,而无需显式编程 5 。该定义的后半部分“没有被显式编程”是有争议的,因为几乎没有任何计算机不需要编程来学习。但这对于在商业中应用机器学习来说意味着使用监督和非监督的机器学习技术。监督学习技术是指计算机需要参考过去的数据,并从中对模式、趋势和事实进行明确的分类和解释。然而,对于无监督学习,这不是必需的;我们让计算机自己学习去发现模式、趋势和事实。这也称为自动发现或自动数据挖掘。
所以当我们使用无监督学习时,你可以说计算机程序没有被明确地编程来学习。它通过发现事实、模式和趋势来进行自我学习。但是我们确实通过选择它将用来发现它们的算法来给它编程。它不会自己选择算法。为了给你一个这是如何发生的例子,让我们说我们想要开发一个机器学习算法,用于开发和发现医院消费者数据是否有任何给定的模式来预测特定的门诊病人是否会被医院接纳。简单来说,数据中有没有隐藏的模式可以找出一个病人的侧写?这可以通过两种方式完成:第一种是使用人类机器学习工程师,他可以开始查看医院门诊和住院数据集,然后查看是否有任何模式;第二种方法使用无监督学习,并让计算机选择聚类算法来找出门诊和住院数据集中是否存在任何聚类。我们将在第三章中用代码以及如何实现来看这个例子。现在我们看下图 1-1 机器学习技术采用流程。
现在,让我们看看机器学习技术在行业中是如何采用的。我在这里概述了所有部门共有的流程,不管它们的技术复杂程度如何。在图 1-1 中的技术采用图中,你会发现任何行业都会出现技术采用的四个阶段。第一阶段是快速应用。这个阶段具有某些特征。这是企业试图将机器学习技术应用于低挂果实的阶段。例如,一家公司可能希望自动化其社交媒体分析或情感分析。它还将寻求自动化一些由员工执行的不到 1 分钟的任务。这项任务的技术复杂度将会很低。它还希望其员工列出重复性任务,并针对业务系统中的任何故障或问题进行类似根本原因分析的工作。这里的重点是事后诸葛亮**。这意味着企业正在努力关注此类问题,并努力解决那些在过去导致失败的问题。作为该技术的早期采用者,企业仍在试图理解机器学习将如何帮助他们推进其业务增长的应用。**

图 1-1
机器学习技术采用流程
下一个阶段是机器学习的早期应用,企业将尝试创建学习操作。这意味着他们试图查看过去的数据,并从中找出可以学习的内容。该企业还试图解决低效率测试问题,以便在运营中进行效率审计,帮助找出可以学习和提高业务运营效率的领域。在机器学习的早期应用中,企业也可以考虑降低现有运营的成本。在这方面,它还可以对其雇员进行的各种业务活动进行成本审计。作为早期采用者,它可以瞄准那些高成本、高增长的业务。这也是为了清楚地诊断业务,这将着眼于业务问题和它所面临的问题的原因,并侧重于如何在未来避免它们。企业还会考虑建立**问题检测系统,**比如建立信用卡欺诈检测系统。在这种情况下,以及在早期的应用程序中,企业试图集中精力并获得后见之明。
现在我转到技术采用的第三阶段,这里有机器学习的辅助应用。这里应用低级智能来帮助专家完成高技能任务。这里自动化的焦点是增强人的能力以促进业务增长和发展。这里的工作是从数据中预测业务需求,并利用这种预测来增强业务。在这里,业务的重点是获得洞察力,而不仅仅是自动化其操作,还包括从隐藏在数据中的隐藏模式、事实或趋势中获益。在这一阶段,组织正在发现其客户、员工和运营,并因此试图了解以业务问题或难题的形式困扰它的事情。这实际上是商业组织开始寻求将机器学习监督技术与非监督技术相结合的地方。
现在,我们进入技术采用的第四个也是最后一个阶段,即使用机器学习的独立操作应用。这是一个公司自动化达到最大能力的阶段。它的大部分操作本质上都是机器人操作。这也是有一个专家人类替换发生的阶段。在这一阶段,对于特定的商业战略或愿景或使命,还存在对未来行动过程的预见和规定。正如我之前所说的,这是人类专家在高水平上被取代或协助的阶段。所以在这里,机器学习被用在机器学习最充分的水平上。机器能够从商业运作中产生的大量数据中学习。它还开发了找出隐藏的模式、事实和趋势的技能,以向其业务领导指明未来的方向修正或行动,以便业务增长。这种机器学习能力还可以用于避免任何种类的灾难,例如可能在未来发生的或者可能反映在商业组织的当前数据中的金融危机或诈骗。在这个阶段,业务正在使用预见,而正是这种预见实际上赋予了其运营的航向修正能力。这是商业运作可以使用机器学习的最大限度,以使在市场中获得相对于竞争对手的优势。我并不是建议整个公司的运作都以自动模式运行。这不是这个阶段所代表的。这种状态是一个拥有智能自动化的组织的状态。通过智能自动化,我的意思是关键的业务功能,比如财务、营销和采购,已经足够自动化,可以提供对业务运营的预见。该公司还能够从其业务环境中收集数据,并避免任何不是由于公司的过错而是由于业务环境的性质(如经济衰退、市场崩溃等)而可能发生的悲剧事件。
我现在以表格的形式呈现每个阶段的特征,以便你对整个过程有一个清楚的了解。
表 1-1
技术采用和进步的阶段
|阶段
|
特征
|
焦点
|
使用的分析
|
预测水平
|
技术复杂性
|
| — | — | — | — | — | — |
| 快速应用 | 1)技术复杂性低 2)重复和平凡任务的替代 3)常见问题的解决方案 | 解决运营中面临的日常问题 | 描述性分析 | 后见之明 | 低的 |
| 早期应用 | 1)提高效率和生产力 2)降低运营成本 3)诊断业务问题和过去面临的问题 4)构建问题检测系统 | 从其业务中面临的问题中吸取教训 | 诊断分析 | 后见之明 | 中等 |
| 辅助应用 | 1)在业务运营中协助高技能专业人员 2)增强人类专家能力 3)预测业务需求 | 自动化 | 预测分析 | 见识 | 中等至复杂 |
| 独立运营 | 1)机器人操作 2)机器人在向人类专家学习后获得专家能力。3)对未来事件的预测和提前纠正过程的能力 4)认知能力建设 | 认识 | 规定性分析 | 深谋远虑 | 高度复杂 |
从表 1-1 中,我们可以清楚地看到我在图 1-1 中描述的内容,也可以了解技术采用过程的更多方面。我还将通过医疗保健行业中一些组织使用这些功能的例子来详细解释这个表。我在表 1-1 中添加了分析的方面,到目前为止我还没有在本书中讨论过,所以让我们看看这些分析形式是什么,以及它们如何被医疗保健组织所使用。
我已经在我的书*《预测项目经理》第 1 卷*(第二章,第 17 页)中解释了这些分析类型,我从那里得到了分析的定义 [6 ]。
**描述性分析:**这个分析领域被调用来了解已经发生的项目的问题的答案,例如“X 项目的状态如何?”
**诊断分析:**该分析领域用于了解现象的根本原因,如项目的成功或失败。X 项目为什么会失败?我们可以从这个项目的成功中学到什么积极的经验?所有这些问题都可以用诊断分析来回答。
**预测分析:**这种类型的分析用于确定未来事件的结果,如项目成功或失败、项目预算超支或正在进行的项目的进度延误。
**规定分析:**在这一分析领域,分析的最大价值是在基于预测分析的预测基础上实现的,它规定了未来应采取的行动。
我曾为美国的一个客户使用描述性分析来检测一家医疗机构在其运营中是否存在种族歧视行为。我得到了病人记录及其背景的数据。患者数据按其种族取向给出,如亚洲人、美洲土著人等。,以及入住 ICU、手术和入住医院病房和私人病房的数据。我必须使用统计技术来分析并给出确凿的证据,证明是否存在种族偏见。通过使用描述性分析和查看患者记录,我可以自信地说,在数据中没有太多这种行为的证据。我的发现后来也被用作法律诉讼的证据。所以我必须小心翼翼地从各个角度分析数据,以确认数据集中不存在这种模式。
每个医疗保健专业人员的生活中都会用到诊断分析。该行业是非常诊断驱动的,因为它试图根据症状来诊断疾病。因此,构建诊断问题的系统并不困难。基因组学是 IBM Watson 项目进行大量诊断研究的领域,因为基因组学处于此类研究的最前沿。IBM Watson 是由 IBM 构建的用于机器学习和人工智能的分析引擎。机器学习引擎 IBM Watson 正在使用其由医学文献、临床研究结果、药典等组成的庞大数据集,帮助找到癌症患者个体化治疗的解决方案。为癌症患者寻找治疗方法。这是一项面向全球肿瘤学家的公共研究,有助于发掘各种癌症的新疗法 [1 ]。
预测分析是机器学习在医疗保健行业的下一个实现阶段。例如,在这样的实现中,重点将是预测可能患癌症的人群。如此开发的系统将能够准确预测可能患某种特定类型癌症的人的年龄和类型。它将有能力创建癌症患者的档案,当这样的人接触到这种类型的分析系统时,它将对可能发生的癌症病例发出警报。
IBM Watson 的基因组学项目正在使用规范分析,它不仅可以诊断疾病,还可以通过查看临床药物试验及其结果来预测癌症类型,然后给出可能的处方。虽然该系统正在接受严格的测试,但当它能够提高其预测和规定的准确性时,它将产生重大的结果。
机器学习如何改变医疗保健
现在让我们看看机器学习正在改变医疗保健行业的一些方式。医疗保健行业是全球劳动密集型行业之一。它需要人类的存在来照顾处于不同疾病阶段的人们。我参加了亚马逊 2017 年在班加罗尔举行的人工智能秘密会议,惊讶地看到一直困扰英国医疗保健行业的员工短缺这一严重问题是如何通过创建人工桌面机器人来解决的,这些机器人将照顾老年患者的需求 (1) 。人工桌面机器人提醒老年患者吃药,跟踪他们的处方,并跟踪和建议唤醒程序。Echo Alexa(众所周知)的核心是亚马逊团队使用其云基础设施亚马逊网络服务(AWS)开发的机器学习。Alexa 的核心是 Python 机器学习代码,通过反馈机制帮助它执行任务并从中学习。这项服务的精彩之处在于,一个普通的 Python 开发者可以使用 Echo Alexa 来使用和开发他们自己的基于亚马逊基础设施的程序和产品。
在 2017 年的另一次 DataHack 峰会上,我有机会看到了 IBM Watson 用于医疗保健服务的演示。开发人员在这个基础分析引擎的基础上构建了自己的应用程序。IBM 已经证明了其分析引擎在基因结果测试、药物发现、肿瘤学和护理管理等应用中的应用。不仅仅是 IBM,其他分析引擎也在另一个领域取得进展,那就是利用成像技术诊断疾病。在医疗保健成像中,如 X 射线图像或 CAT 扫描图像,传统上都是由人类来解释的。然而,我们需要机器来更有效地完成这项工作是有原因的:
-
随着患者数量的增加,成像数据量增加。
-
高容量给医生带来的压力使他们更容易出错。机器可以以较低的错误率处理大量成像数据。
-
医疗保健专业人员无法从成像数据中联系和了解全局。例如,机器可以通过评估大量图像数据集来帮助他们,并确定患者群体或地点群体之间是否存在任何模式或任何联系。
-
在医生或专家不在时代替他们。这是一个机器可以完成的关键操作——当专家不在时,它可以代替人类专家,甚至在危急情况下提供诊断。在我看来,机器的这一功能将会越来越多地被使用,并且整个图像诊断领域将由机器在没有人工干预的情况下完成的日子不远了。
-
药物研发是医疗保健行业的一个非常关键的领域。制药公司对癌症或艾滋病毒等疾病的研究正在持续进行。机器学习正在通过分析医学数据和提供药物反应的预测模型来帮助加快药物发现,甚至在药物被注射到受控环境中的受试者之前。这节省了时间和金钱,因为药物反应的模拟给出了可能的治疗模式和对药物的反应的估计。
-
癌症等困难领域的患者研究。在这一领域,有大量数据可用于药物的患者和临床试验。临床试验非常耗时,需要收集人体反应的受试者数据。这或者是侵入性的,例如通过血液测试,或者是非侵入性的,例如通过尿液测试或者将探针放在受试者的某些身体部位。
我从医疗保健专业人士那里听到的一个普遍担忧是,他们担心人工智能会取代他们。这些机器可能会使他们的工作变得多余。这种担心是有根据的,也不是没有证据的。这篇报道来自中国,一个名叫“萧艺”的机器人成功地通过了中国国家医师资格考试,并获得了行医的所有技能。有人说这是一个可怕的趋势。有人说这是机器人将统治人类的一个明显迹象。然而,我说这只是冰山一角。就机器而言,以下是我们在医疗保健领域可能会看到的一些趋势:
-
机器人首先取代了低收入工作的工人,在这些工作中,人类不想做平凡的工作,例如亚马逊的 Echo Alexa 因员工短缺而取代了老年医疗保健。
-
机器人成为高级专家的助手,如神经外科医生,并学习诊断和手术技能。
-
机器人将取代高级专家进行诊断,因为这需要更多的分析和处理。人类无法处理大量信息,也无法发现大数据集中的模式。在这一点上,机器人的诊断准确率要比人类专家高得多。
-
手术将由人类在机器人的协助下完成。牛津大学外科医生已经证明了这一点。因此,在我看来,随着越来越多的机器人被制造出来为人类做精确的手术并获得成功,它们将与人类专家共同工作,进行复杂的、基于精度的手术,这是可能的。这一趋势将在未来 2 到 3 年内开始显现。他们可以被称为自动医生和引导医生。
自动医生将使用无监督学习技术来治疗新发现疾病的患者。
被指导的医生会使用监督学习技术。他们将致力于已知疾病的已知治疗。在第 3 “如何在医疗保健中实现机器学习”一章中,我们将深入探讨一个用于监督学习的 Python 程序的例子
尾注
-
第一次,一个机器人通过了医生执照考试,Dom Galeon,
https://futurism.com/first-time-robot-passed-medical-licensing-exam/ -
机器人通过了医师执照考试:
https://www.thesun.co.uk/tech/4943624/robot-doctor-medical-exam-china-beijing/ -
第 17 页,第二章,预测程序管理器第 1 卷,Puneet Mathur
-
http://www.ox.ac.uk/news/2016-09-12-world-first-robot-eye-operation#世界上第一个进行机器眼手术的人
二、医疗保健领域的关键技术进步
情景 2025
在不太遥远的 2025 年,一个晴朗的早晨,一位老太太在她的个人家庭管理设备上收到一个警报,她将在不久的将来患上癌症。这份报告是她的机器人医生在她上周去做检查后发来的。听到这样的消息,她有点震惊。然后,她决定从人类医生那里获得第二种意见。在她的城市里,人类医生的数量很少,而且比机器人医生更贵。所以她决定去看离她家最近的人类医生。她去看医生,并给他看了她的报告,这是机器人医生今天早上发给她的。人类医生仔细看了这份报告,发现机器人提到了 2019 年完成的一项临床研究,该研究证明,连续睡眠障碍超过 3 周的人有 90%的机会患某种癌症。使用安装在患者家中的探针传感器,机器人医生已经检测到她连续 6 周以上的睡眠模式受到干扰。基于这一事实,机器人医生查看了她的生命统计数据,如她的心率、血压、呼吸模式等。,并得出结论,她是在获得癌症的道路上。另一方面,人类医生再次检查她的生命统计数据,并要求她进行一些血液测试和其他必要的测试,以确定她当前的医疗状况。几天后,当她的医疗报告到达时,人类医生宣布她没有任何癌症的迹象。
这是不是听起来有些牵强,有些太遥远了?
这不是不可能的场景,而是一旦机器人医生成为现实,我们可能会目睹的事情。我们在第一章已经看到,中国有一个机器人已经顺利通过体检,取得了医生的医学学位。当你看到这种情况时,你会想到什么问题?如果这样的事情发生在你身上,你会怎么做?你会相信机器人医生吗?你会更信任人类医生吗?在人类医生给了你一份关于你目前医疗状况的干净的账单后,你会认为机器人医生的报告是假的而不予理会吗?一旦我们接受机器人作为医疗保健行业的专家,未来社会将不得不处理这些问题。
如果你注意到了,这是一个人类专家没有能力根据在人类身上观察到的模式开出任何药物的场景。在这种情况下,机器人医生可以根据从其连接的探针或传感器获得的数据,更好地预测和给人类开出纠正疗程的药物。
医疗保健行业尤其关注人类及其生活。这是一个简单的判断错误可能导致病人死亡的行业之一。然而,当我们谈论基于机器学习(ML)建立预测模型时,机器学习是任何机器人背后的大脑,我们知道无论选择什么算法来预测任何数据集的结果,模型的最终预测都会有一定比例的误差。在人类的情况下,人类或人类医生或保健专业人员也容易出错。这就是我们所知的人为错误。霍普金斯医学组织或约翰霍普金斯医学组织最近的一项研究表明,美国所有州的 10%是由于医生的医疗错误而发生的,这是美国第三大死亡原因。因此,如果我们要为人类医生制造一个替代品或竞争对手,我们知道它必须比这个错误率做得更好。只有当它以比人类医生更低的错误率给出预测诊断时,它才能生存。由于我们在医疗保健行业处理人类生活,我们需要一种渐进和谨慎的方式来采用技术,因为很多事情都处于危险之中。要求是建立具有更高精度水平的预测模型的稳健算法。
狭义与广义机器学习
现在让我们来了解机器人背后的大脑,也就是 ML。有两种类型的 ML 应用:一种是狭义的,第二种是广义的。狭义 ML 处理创建程序、算法和机器人软件,以满足一组狭义的活动或技能。在这里,狭义的意思是应用的领域是一种专门的技能。它与专家有关,其目的是在专业技能上模仿并超越人类专家。当有专家可以学习和复制时,狭义的 ML 效果最好。窄 ML 机器人的一个例子是用于心脏手术的机械臂带,例如从动脉中移除血凝块。这个例子是一个机器人,它需要人类的帮助来完成它的操作。我们可以在图 2-1 中看到这一点。

图 2-1
窄 ML 与宽 ML
在图 2-1 中,我们可以清楚地看到狭义 ML 集中在医疗保健、金融和零售等领域。相比之下,广义 ML 是关于建立一个人形机器人,赋予它人工智能(AI)的认知能力和模仿人类身体特征的能力。
现在让我们来看看广义的 ML 应用。在这里,我们谈论的是创造程序、算法和机器人软件来迎合一般技能而不是专业技能。它模拟人类的一般行为,目的是证明机器人的能力等同于人类。最近一个广泛应用人工智能的例子是名为索菲亚的机器人,由于其被证明具有模仿人类对话的能力,该机器人已经获得了沙特阿拉伯王国的公民身份。随着技术的进步,我们将会看到更多的机器人在广泛的 ML 应用中被开发出来。然而,医疗保健行业目前的趋势是狭义地采用机器人及其应用,并帮助模仿或取代新药和其他类似领域的疾病诊断研究专家。我们可以看看表 2-1 的区别。
表 2-1
狭义与广义的机器学习应用
|应用机器学习
|
应用领域
|
焦点
|
目的
|
| — | — | — | — |
| 狭窄的 | 专业技能 | 专家能力 | 模仿并超越专家的表现 |
| 辽阔的 | 通用技能 | 一般人类行为能力 | 证明类似人类的能力 |
世界各地医疗保健机构的现状
现在,我想看看全球医疗保健行业的现状。图 2-2 描绘了医疗保健领域正在发生的动荡。
请注意两种对立的力量:一种是传统的医疗保健机构,通常由健康诊所、医生诊所和医院组成。另一组新出现的机构是基于机器人人工智能的。在我参加的 2018 年 3 月在班加罗尔举行的 XIME 医疗保健管理最佳实践国际会议上,这一趋势被清楚地提了出来。您可以通过以下网址了解更多关于大会的信息: http://xime.org/Health%20care%20conference%20report 。
传统的医疗保健系统从医生的同情心、人情味和治疗中获得价值。与此相反,另一组机构正在迅速崛起。这些机构带来的价值是医疗保健运作的效率和准确性,更好的资源管理,以及避免传染病传播的最少人力接触。这两个系统的目标都是为病人提供更好的护理。在传统观点中,医生是不可替代的,是医疗机构的中心。然而,新的现代观点是,医生的分析能力有限,无法分析大局——因此,这样的机器算法和机器人可以做得更好。我已经在这一章讨论了狭义和广义的 ML 应用。读者应该注意到,基于机器人人工智能和人工智能的机构正试图通过首先瞄准狭窄的人工智能应用来取代传统的医疗保健系统。这里的尝试不是取代医生作为一个整体,而是取代或模仿,然后取代医生或医疗保健专业人员的某些专门功能。

图 2-2
全球医疗保健行业的对立力量
一个用于狭义医疗任务的 ML 的例子来自西门子公司医疗工程部门。他们在计算机断层扫描上进行计算机视觉成像,并通过核磁共振扫描来观察大脑线路的样子。他们有被称为特斯拉机器的大脑解剖机器,我用它来完成这项任务。同一公司的 ML 的另一个应用是 CT 扫描仪,用于参数成像或分子成像,医疗保健工作者已经应用它来显示肿瘤是良性还是恶性。这项研究是基于将人工智能应用于 path lab 机器的 250 幅精选图像而完成的。他们开发了精确的算法,使用特斯拉机器内部的 3D 相机来定位患者,因为这曾经是一项人工辅助的任务,每个人都有自己不同的方法来定位机器内部的患者,有时会导致图像质量差。ML 算法现在能够尽可能快地定位患者,以获得更好的图像。他们还开发了深度学习算法,用于读取胸部 x 光片,并检测 x 光机中的异常。这是一种尝试,用所有摆在他们面前的 X 射线,包括核磁共振成像和 CT 扫描,来取代拥有大量专业知识的放射科医生的专业角色。在同一条线上,西门子开发了一种 MRI 图像指纹技术,使用深度学习来模仿放射科医生的工作。它也是实验室机器人自动化领域的先驱,使用了一种电磁悬浮技术,这种技术被用于世界各地的高速列车。
我现在向读者展示另一个例子,一个组织使用 ML 应用程序开发一个解决方案,以创新的方式克服社会障碍。这家公司是印度的一家初创公司,名为尼拉迈4;这个概念是由两位女性 Geetha Manjunath 和 Nidhi Mathur 提出的,她们创建了这个创业公司。Nidhi 在 XIME Healthcare conference 上展示了其公司开发的用于识别女性乳腺癌的所有解决方案。在像印度这样的国家,传统观念在农村地区盛行,检测乳腺癌的主要障碍是传统系统需要医生触摸患者的乳房来检测可能癌变的肿块。甚至今天使用的主要方法是医生用他/她的手来感觉和查看身体区域是否存在肿块。为了克服这一缺点,Manjunath 和 Nidhi 研究了如何利用技术来帮助诊断乳腺癌,而不使用触摸或侵入性程序或通过乳房 x 线照相术施加压力,这是很痛苦的。因此,他们寻找一种解决方案,通过使用高分辨率、全感知的 ML 热成像,并使用图像来检测癌症的患病率。通过使用高分辨率的热传感设备和人工智能以及 ML,他们能够开发 API,这是非侵入性的,不需要任何测试,也不会给患者带来任何痛苦。他们要求在机器检测癌症患病率以及癌症是恶性还是良性时,脱掉病人的衣服,这与任何人工进行的乳房 x 光检查相匹配。随着时间的推移,我确信算法会自己学习和改进。这种专注于克服医疗保健中的社会问题的创新技术将在人口众多的国家更快地被采用,这些国家存在反对医疗帮助的社会污名,这阻止了医疗帮助作为一种治疗方法在普通人群中的传播。****
****### 机器学习在医疗保健中的重要性
将医疗保健与金融和零售等其他领域区分开来的事实是,医疗保健涉及人类生活,当我们应用 ML 时,我们需要以渐进和谨慎的方式采用技术,因为这里有很多风险。需要具有更高精度水平的预测模型的稳健算法。这可以从一个非常简单的例子中改变,我们建立了一个预测模型,以 95%的准确率预测特定类型的癌症。在这种情况下,预测模型将对 25 名患者进行准确预测,而对另外 5 名患者进行不正确预测。所以被错误预测的病人仍然会认为他们没有患癌症。这就是为什么在医疗保健中应用 ML 需要在生产中部署模型之前进行更多测试的原因。
医疗保健应用机器学习的一些关键领域是:
-
疾病识别
-
个性化医疗
-
药物发现
-
药品制造
-
临床试验研究
-
放射科
-
数字健康记录
-
疫情爆发预测
-
外科机器人
医疗保健的所有这些领域都是医疗保健行业的核心。现在,我们将关注医疗行业的上述领域,并执行我在第一章图 1-1 中讨论的 ML 技术采用过程。这种映射将有助于我们理解这些领域在当前场景中的技术采用过程中所处的位置。通过这样做,我们可以进一步了解在这些特定领域中的每一个领域中会发生什么样的进步。关于如何使用该映射信息的示例,假设您的医院已在心脏外科领域实现了手术机器人。通过从该图表中了解机器人手术在技术采用过程方面的先进程度,我们可以了解该手术应用在未来可能会有什么样的技术进步。
为了对 2018 年的全球医疗保健行业有一个当前的看法,我使用德尔菲法对 18 名医疗保健专业人员进行了一项研究。这是我做的独立研究,没有任何机构赞助。我也没有定期与任何医疗机构直接联系,以便从更独立的角度进行研究。这项研究的目的是听取专家的意见,并找出医疗保健行业中人工智能和 ML 的现状。我在研究中使用了德尔菲法。我们需要了解什么是德尔菲法,以及它如何在这项研究中帮助我们。让我们先来看看这项研究中使用的研究方法。
研究目标 : 本研究的主要目标是利用专家意见找出并绘制人工智能和人工智能的两个参数:(1)人工智能和人工智能在医疗保健行业关键领域的当前技术成熟度水平,以及(2)医疗保健行业内部技术采用流程的参数。
在第一次迭代中,专家组最初确定了 12 个关键领域。然后,专家组重申了这些领域,以找出未来将会发展的最重要的领域。专家组确定了对医疗保健行业进一步发展至关重要的九个医疗保健领域。调查研究不提供关键领域的迭代选择结果,但它从专家选择这九个关键领域的点开始。我已经在本章讨论了这九个领域,从疾病识别到手术机器人。
**研究样本:**从总共 232 名专家中选出一组专家。专家组由在医疗保健行业工作超过 20 年的医疗保健专业人员组成,他们的工作岗位包括患者护理、医疗保健机构的管理专家、大型医疗保健机构的董事和首席执行官,以及从事医疗保健行业研究并发表论文的学术教授。我涵盖了医疗保健各个领域的所有专家,例如患者管理、药物研究、外科医生、首席执行官和人工智能专家——仅举几例。共有 18 名这样的专业人士被列入本次研究的候选名单。在这项研究中没有缺席或流失。
**所需信息:**为了做出决策并支持决策,我们提供了各种辅助数据,如关于医疗保健中 ML 和 AI 状态的已发表论文。西门子医疗工程师艾玛·沃森在基因组研究和癌症检测方面的研究就是一个例子。在前面提到的两个参数之间建立映射所需的信息是基于专家对九个领域技术实现现状的理解,从疾病诊断到临床试验研究。向他们提供了关于技术成熟度水平和技术分阶段识别的专家解释的决策。除此之外,没有提供其他信息,所以要小心不要在专家的头脑中产生偏见。这项研究需要的信息包括背景知识、理论知识和专家知识。这项研究还要求专家们运用他们的隐性或固有知识,这些知识是他们长期从事医疗保健行业所积累的。
研究设计概述:
这项研究涉及的主要步骤如下:
-
定义研究的目标。
-
寻找愿意帮助这项研究的专家。
-
设计收集信息的问卷,减少专家的写作工作量。
-
向专家发放调查问卷。
-
收集对问卷的答复,并对其进行分析,以了解是否达成了共识。
-
重复并管理更多的问卷,直到专家们就某个特定的关键领域达成共识。
-
一旦达成共识,就进入下一个关键领域,重复调查问卷,直到达成共识。在达成共识之前,根据专家之前的回答提供更多信息。
-
分析并创建 AI 和 ML 采用的技术成熟度级别和阶段图。
数据收集方式:
关于医疗保健的文献不是本研究要收集的数据。我之前提到的测试研究是在专家的帮助下,将对医疗保健行业的未来至关重要的 12 个关键领域缩小到 8 个。这一点很重要,因为在我们的研究中,我们根据专家过去的经验,对医疗保健行业的发展重点做出了判断。我们使用了 Chittu Okoli 和 Suzanne De Poweski 的一篇名为“德尔菲法”的论文中的德尔菲法作为研究工具和设计考虑和应用的示例 [6 。
问卷调查法用于通过电子邮件在线管理调查和以纸质方式亲自发放问卷向专家收集数据。
数据分析:
在一个特定的迭代过程中,当收集数据时,使用 Microsoft Excel 以表格的形式记录专家的回答。对于任何给定的关键领域,都会绘制一个图表来检查是否达成了共识,以及该图表是否充分显示了专家的共识。然后迭代停止。所以数据分析是在计算机软件的帮助下手工完成的。使用 Excel 软件绘制技术成熟度和技术采用阶段图,以创建技术地图。
道德考量:
如果我们没有确保结果是专家的回答,并且是匿名的,不影响这项研究的结果,那么研究可能会出现偏差。因此采取了适当的措施,以确保专家之间互不相识。正如我已经提到的,在医疗保健行业有两类人:一类人喜欢技术,另一类人不喜欢技术。我们没有根据这些特定的标准进行专家选择,所以这项研究很可能在这些基础上有所偏差,我们还没有对此进行测试。
研究的局限性:
定性研究的最大局限是不能准确量化未来的结果,这也非常适用于我们的研究。然而,通过在我们的问卷中使用分类变量,我们也试图对我们的结果进行定量分析。绘制技术采用图和了解技术成熟度不是一个普通人能做的事情,除非他们已经与行业相关联,这就是为什么我们选择专家来进行这项研究。然而,有可能一些专家可能没有足够的知识或接触人工智能和人工智能的进展。我们承认这可能是研究的一个局限。
从第一章中的图 1-1 我们已经知道技术采用有四个阶段。在图 2-3 中,我们看到了这个映射。

图 2-3
医疗保健行业技术采用阶段
在图 2-3 中有两个轴。x 轴代表技术采用阶段,如图 1-1 所示,y 轴显示技术成熟度。技术成熟度应用级别。成熟度应用程序级别分为低、中和高。低表示该技术处于研究阶段,尚未投入生产。中等意味着该技术已经在生产中实现,有些成功和失败,需要更多的研究来推动主流生产。高意味着该技术已经过充分研究,准备投入生产或正在生产环境中使用,如医院等。
表 2-2 和图 2-4 展示了根据德尔菲研究法分析的数据。
表 2-2
关于研究中使用的德尔菲研究方法的数据
|主题
|
保健专家人数
|
迭代次数
|
| — | — | — |
| 德尔菲法 | 邀请 | 入围的 | |
| 人工智能和人工智能在医疗保健中的应用现状 | Two hundred and thirty-two | Eighteen | four |
我们已经在本章的方法一节中讨论了这些数据。现在,我们来看看医疗保健中人工智能和人工智能的第一参数技术成熟度的数据及其图形表示。

图 2-4
AI 和 ML 在疾病诊断中的地位
在疾病诊断领域,关于医疗保健行业人工智能和人工智能技术成熟度水平的第一个参数,56%的专家认为疾病诊断具有中等成熟度水平。将疾病诊断识别为中等成熟度意味着该技术已经在生产中的疾病诊断领域中实现,但是存在成功和失败,并且需要更多的研究才能进入主流生产。这个领域的一个很好的例子是谷歌用于检测糖尿病眼病的深度学习 [5 ]。
在以传统方式使用人工智能进行疾病检测的过程中,眼科医生使用眼睛后部的照片以及计算机视觉视网膜病(CVR)来检测是否有糖尿病眼病的迹象。CVR 确定图像中存在的损伤类型,其显示眼睛中是否有任何液体渗漏或是否有出血。在眼科医生对视网膜病变进行的如此复杂的分析中,谷歌的糖尿病眼睛检测器能够通过使用 327 名眼科医生提供的 100 和 28,000 张图像的开发数据集来创建一个基于人工智能的系统。深度神经网络对这些糖尿病视网膜病变图像进行了训练,当它应用于超过 12,000 张图像时,它能够与 728 名美国委员会认证眼科医生的大多数决定相匹配。该算法的 AP 分数与眼科医生手动进行的疾病检测分数相比是相同的,都是 9.5 分。

图 2-5
数字健康记录中 AI 和 ML 的状态
现在让我们看看另一个领域:数字健康记录。我们的专家得出结论,这是一个中等水平的技术成熟度,61%的专家同意这一观点。我们可以在图 2-5 中看到,他们中的一部分人(约 28%)也觉得成熟度水平处于较低水平。中等意味着该技术没有进入主流生产,在这里和那里有一些成功和失败。然而,低状态意味着研究还没有进入生产。给你一个在电子健康记录中使用人工智能的应用,有一家名为 Savana(西班牙马德里)的公司已经成功开发了一个使用人工智能 [7 ]重新使用电子健康记录的应用。
该系统最显著的特征是,它使用由医疗从业者在电子健康记录或数字健康记录中书写的自由文本形式的自然语言来分析由医生生成的实时信息。Savannah 系统对其软件记录中的所有患者进行即时统计分析,并提供与用户提供的输入变量相关的结果。它使用自然语言处理在后台完成这一目标。它使用监督 ML 将医生的书面文本分类为背景信息或诊断信息。无监督 ML 技术使用案例来确定单词的语义内容,因为算法在没有任何预定义的语义或语法关系的情况下自主学习。例如,工程师和帕金森有相似或不同的含义,例如萘普生和布洛芬或不对称类似,只是给你一个实际操作的想法。现在让我们看一下图 2-6AI&ML 在数字个性化医疗中的状态。

图 2-6
人工智能和人工智能在个性化医疗中的现状
现在我们来看看人工智能和人工智能在个性化医疗领域的现状。在四次迭代之后,我们的专家告诉我们,技术采用成熟度处于非常低的水平。我们 83%的专家肯定地告诉我们是这样的。个性化医疗领域也被称为精准医疗。在这里,对疾病的治疗和对病人的预防是基于他们个人的基因变异、他们生活的环境和每个人遵循的生活方式。这就像建立你自己的定制治疗。很明显,如果不使用人工智能,这个职业是不可能的,人工智能运行在超级计算机上,以便使用深度学习进行学习,并开发认知能力。这类似于医生的工作——计算机需要高处理能力。他们使用深度学习算法,并且他们需要他们希望进行诊断的领域的专业诊断知识,例如心脏病科、皮肤科和肿瘤科的医生,等等。
现在我们来看另一个关键领域,即图 2-7 中的流行病爆发预测。

图 2-7
AI 和 ML 在疫情预测中的地位
在图 2-7 中,我们可以清楚地看到,我们的专家告诉我们,技术成熟度处于较低水平。我们的专家中有 67%的人在三轮迭代后有这种感觉,当时达成了共识。一个很好的例子是谷歌流感趋势 [2 ],谷歌能够预测流感在许多国家的传播;然而,它不再公布结果。它过去的工作方式是,谷歌将分析搜索查询,以确定如此大量的查询来自世界哪些地区,它将自动预测这些地区将受到流感的影响。这个项目始于 2008 年,由于各种机构对隐私问题的担忧而被关闭。然而,在后台,谷歌将向不同的公共卫生机构提供这些数据,以帮助他们了解和分析趋势。这种技术是存在的,但在成为主流之前,它需要解决隐私问题。
在图 2-8 中,我们现在来看看人工智能和人工智能在放射学领域的有趣应用。

图 2-8
放射学中人工智能和人工免疫的现状
我们的专家告诉我们,经过四次迭代后,这一领域的技术成熟度很高,72%的专家得出了这一结论。西门子医疗团队的一项显著成就是将神经网络应用于 X 射线等成像,并将这些图像转换为数据,然后像放射科医生一样进行分析。这使用了深度学习,更具体地说,是复制人类神经元的人工神经网络(ann)。据报道,他们以 97%的灵敏度通过胸部 x 光片检测,并以 100%的特异性检测肺结核病例 [3 ] ( https://www.healthcare.siemens.com/magazine/mso-artificial-intelligence-in-radiology.html )。
越来越多的此类应用将会出现,它们可能会集成到医疗设备中,使它们具有自动化的独立机器人功能。这是当今放射学的未来。我们现在来看看图 2-9 中 AI & ML 在下面手术中的状态。

图 2-9
AI 和 ML 在外科中的地位
正如我们在图 2-9 中看到的,在外科领域,我们的专家看到人工智能和人工智能的使用处于非常高的成熟水平,在我们的迭代之后,56%的专家同意这一观点。在割肉这一外科医生的基本技能中,与人类外科医生相比,机器人能够进行精确的切割,对组织的损伤要小得多[8; https://spectrum.ieee.org/the-human-os/biomedical/devices/in-fleshcutting-task-autonomous-robot-surgeon-beats-human-surgeons 。
有一个名为 STAR(智能组织自主机器人)的机器人,它悬停在患者上方,然后根据算法,进行专家外科医生进行的精确切割,但 STAR 通过包围肌肉造成的伤害较小。这种 STAR 系统能够缝合手术中切下的肉,而且这种缝合比有经验的外科医生的缝合更规则,更防漏。所以这清楚地表明,机器人在外科领域的使用确实处于先进阶段。在图 2-10 中,我们看到了 AI & ML 在药物发现中的状态。

图 2-10
人工智能和人工智能在药物开发中的地位
我们的专家告诉我们,人工智能和人工智能在药物发现领域的应用处于中等技术成熟度水平,这意味着尽管有技术,但仍有许多成功和失败,因此该技术尚未进入主流生产。整个药物发现领域与临床试验密切相关,但实际上,药物发现发生在任何药物的临床试验发生之前很久。药物发现过程需要许多药物测试来检查,并且它是在许多不同的药物化合物上进行的,这可能有助于消除或限制特定疾病的传播。因此,这一发现表明,一种特定的化合物在实验室中对这种疾病起作用,用于毒性测试和其他测试,如人体吸收、运动代谢率等。一旦这些化合物在这些早期实验室测试中显示出结果,它们就会被转移到临床试验中,以获得政府的批准。最大的制药公司正在使用人工智能。像 50 Shades SK 这样的公司正在使用人工智能和 ML 来寻找潜在药物的新化合物。他们还建立模型来预测潜在药物在测试阶段的表现。发现药物及其组合正在使用人工智能开发,用于组合治疗,人工智能正在根据患者的遗传密码创造个性化的药物[9; https://emerj.com/ai-sector-overviews/machine-learning-drug-discovery-applications-pfizer-roche-gsk/ 。在下图 2-11 中,我们看到了 AI & ML 在药品生产中的状态。

图 2-11
AI 和 ML 在药品生产中的地位
现在我们来看看 AI 和 ML 在药物制造领域的状态。这是一个有趣的案例,在四次迭代结束时,我们的专家能够最终告诉我们,药物制造处于所有三个成熟度水平(即低、中和高)。因此,这意味着在药物制造领域,这项技术还处于研究阶段,其中一些还没有投入生产。还有一些技术已经在生产中进行了测试,但尚未进入主流生产环境,如医院。专家们还告诉我们,在药物制造领域,有一些技术已经过充分研究,可以投入生产,或者已经在生产环境中使用。在卡车制造中,机器人和人工智能正被用于制药厂的自动化检测和包装,从而提高效率,并将工人从危险和重复的任务中解救出来。医药制造设施中使用的机器人为笛卡尔并联和选择性柔顺装配机械臂(SCARA)[10; http://www.pharmtech.com/using-robotics-pharmaceutical-manufacturing 。
默克公司正在其装瓶生产线上使用一个机器人来将配药盖放在瓶装过敏药物上,这提高了其运营效率。Enclave 的机器人越来越多地用于药瓶灌装应用、检查和包装,以及各种药品装配检查——仅举几例。
现在我们来看最后一个也是第九个领域,即下图 2-12 中的临床试验研究。

图 2-12
AI 和 ML 在临床试验研究中的地位
从图 2-12 中,我们可以看到我们的专家告诉我们,它处于中等技术成熟度的阶段,AI 和 ML 状态处于那个水平。经过四次反复,这个小组中 67%的专家能够得出这个结论。这意味着在这个领域有很多研究在进行。然而,有成功也有失败,它需要更仔细的研究,以便将技术转移到主流生产中。麻省理工学院机器人实验室在 2014 年 9 月进行了一项研究[11; https://news.mit.edu/2014/mit-robot-may-accelerate-trials-for-stroke-medications-0211 。
也有毕马威之声在 2016 年做的研究[12; https://www.forbes.com/sites/kpmg/2016/12/21/using-smart-robots-to-run-clinical-drug-trials/#749ef31f36d2 。
这有望实现自动化临床试验,以便在数百名患者中证明药物治疗的有效性。由于实验室仍在研究这项技术,它在现实世界中的应用很少,但有很多实验正在进行,以了解它如何帮助最大限度地减少药物发现的临床试验阶段。如果这项技术进入生产,那么它将降低药物发现和临床试验的成本,这可能需要高达 200 万美元,是一件极其昂贵和耗时的事情。

图 2-13
《医疗保健行业技术采用的阶段,2018》让我们快速了解了本书中医疗保健调查报告的技术采用流程。
现在我们继续我们研究的第二个参数,即医疗保健中技术采用的阶段,我们已经在第一章图 1-1 机器学习技术采用流程中讨论过。正如您在上一章中所回忆的,有四个阶段:阶段 1:快速申请阶段,阶段 2:早期申请阶段,阶段 3:辅助申请阶段,阶段 4:独立运营。这里我们有第二阶段的快速应用,第四阶段分析的独立操作。从图 2-13 中我们可以看到,正如我们的专家组告诉我们的,疾病诊断处于早期应用阶段 2 的状态。数字健康记录处于第二阶段,56%的专家在三次迭代后得出结论。个性化医疗处于第一阶段,即快速应用阶段,我们 83%的专家在四次迭代后得出了这一结论。流行病爆发预测领域处于人工智能和人工智能应用的第 2 阶段,这是我们 67%的专家得出的结论。我们的专家还得出结论,56%的人认为放射学处于第 3 阶段辅助应用阶段,我们已经看到在技术成熟度水平上,西门子等公司在其特斯拉机器中使用了各种应用。对于外科手术,我们的专家在三次迭代后得出结论,50%的人认为 AI 和 ML 在第三阶段为 50%,这是辅助应用阶段。我已经看到机器人手术在主流应用中的应用,如矫正心脏病的手术;这是个陷阱。在药物发现方面,我们的专家得出结论,人工智能和人工智能的应用处于初级阶段,其中 56%的专家得出结论,人工智能和人工智能处于 2 期早期应用水平。对于药物制造,56%的专家得出结论,人工智能和人工智能的使用处于第 3 阶段水平。对于临床试验研究,我们的专家认为 AI 和 ML 的使用处于 2 期早期应用水平。
至此,我们结束了这项研究的演示,我和医疗保健行业的专家花了 3 个多月的时间来实现这项研究。我真的希望它能为读者提供一个简明的观点,让读者了解医疗保健行业在人工智能和人工智能的应用和适应方面的情况。
尾注
-
研究提示医疗差错现为美国第三大死亡原因,2016 年 5 月 3 日,
https://www.hopkinsmedicine.org/news/media/releases/study_suggests_medical_errors_now_third_leading_cause_of_death_in_the_us -
尼拉姆斯: ・T1️ ・T0️ ・T2️
-
“谷歌的人工智能程序可以检测糖尿病眼病”,2017 年 7 月 17 日,
https://research.googleblog.com/2016/11/deep-learningfor-detection-of-diabetic.html。第二章医疗保健领域的关键技术进步 35 -
Medrano,I. H .,J. T. Guijarro,C. Belda,A. Ureñ,I. Salcedo,L. Espinosa-Anke 和 h . sag gion“Savana:使用人工智能重新使用电子健康记录”,2017 年 3 月 27 日,国际交互式多媒体和人工智能杂志 4(7):8-12。
http://www.ijimai.org/journal/sites/default/files/files/2017/03/ijimai_4_7_1_pdf_22755.pdf -
伊莱扎·斯特里克兰,2017 年 10 月 13 日格林尼治时间 19:30,机器人命名为 STAR(智能组织自主机器人),
https://spectrum.ieee.org/the-human-os/biomedical/devices/in-fleshcutting-task-autonomous-robot-surgeon-beats-human-surgeons -
机器学习药物发现应用——辉瑞、罗氏、葛兰素史克等等,最后更新于 2018 年 11 月 29 日,发表于 2017 年 10 月 12 日作者:乔恩·沃克,
https://emerj.com/ai-sector-overviews/machine-learning-drug-discovery-applications-pfizer-roche-gsk/ -
笛卡尔平行和选择性柔顺装配机械臂(SCARA),詹妮弗·马卡里安,2014 年 11 月 19 日,
http://www.pharmtech.com/using-robotics-pharmaceutical-manufacturing -
https://news.mit.edu/2014/mit-robot-may-accelerate-trials-for-strokemedications-0211 -
使用智能机器人进行临床药物试验,阿什拉夫·谢哈塔,2016 年 12 月 21 日上午 11:45,
https://www.forbes.com/sites/kpmg/2016/12/21/using-smart-robots-to-run-clinical-drug-trials/#3d61d05336d2****
三、如何在医疗保健中实现机器学习
我们现在着眼于拥有巨大潜力的医疗保健领域。为此,我们需要仔细检查第二章图 2-2 中的技术映射图。图中的某些区域处于阶段 1,技术成熟度较低。虽然这些都有潜力,但它们并没有给我们带来巨大的机会,因为技术目前还不能支持这些领域的发展。例如,个性化医疗是非常新的,必须进行大量的研究,包括使用人工智能,以使其进入下一阶段。这种研究必须与医疗保健行业紧密联系,以便更快地被采用。接下来是流行病爆发预测的第 2 阶段,该阶段有一些成功和失败,需要解决隐私问题才能进入第 3 阶段。真正的潜力在于第三阶段的领域,该技术已经进入辅助应用阶段。
潜力巨大的医疗保健研究领域
我不会讨论图 2-2 的第三阶段专栏中使用的所有技术,但我会讨论那些拥有巨大潜力的技术。医疗保健中最有前途的三个领域是:
-
数字健康记录
-
疾病诊断
-
放射科
数字健康记录拥有巨大的潜力,原因有三:首先,随着世界人口的增加,医生的病人数量也在增加;第二,每个病人的数据量也会增加。最后,医生只有掌握了患者的完整病历,才能做出正确的治疗决定。数字健康记录拥有巨大潜力还有另一个原因。机器学习和人工智能的进步允许以快速有效的方式分析数据。未来的医院或医疗保健机构将访问数字健康记录或患者记录,当患者授权医疗保健机构查看其记录时,这些记录将被数字化并可供所有医疗保健机构访问。本质上,我们将有**个联网的医院,**个除了存储病人的私人数据之外,还能访问普通的电子病人健康记录。在美国,任何执业医生都必须保留电子病历。然而,这些数据在医院、政府或任何其他想要治疗患者的机构或个人之间是不可用和不共享的。因此,在未来,将会有一个通用的患者数据库的变化,这将使任何由患者和该国政府授权的医疗机构能够访问共同的病例记录。可能阻碍这种数据共享机制的主要挑战涉及对数据隐私的担忧。然而,如果中央节点机构和政府能够保证数据的适当授权和安全,那么很快就有可能建立这样一个病历数据库,并可能导致建立全球数字健康记录系统。
在不久的将来,我们可以看到技术领域正在开发更好的记录共享机制,将数据隐私和安全等问题抛在脑后。因此,医院不再各自为政,而是开始以相互联系的方式工作。在一个假设的场景中,可能有一个患者,他在接受了特定医院的治疗后,对所给予的治疗线不满意,想要改变他们的医院或医疗保健机构。在这种情况下,他们只需同意与新医院共享所有医疗诊断报告,一旦完成,患者即将入住的新医院将自动访问这些数据。另一个挑战是目前不允许互联医院的概念,那就是不相连的诊断中心。诊断中心是实验室,满足病人的需要,完成他们的实验室测试,如血液或尿液测试。他们根据实验室测试的结果给出报告。因此,在实验室测试完成后,他们会生成大量数据,以测量值的形式显示在报告中。为患者生成的每个报告中的数据目前是通过以 PDF 文件的形式打印报告或通过在纸上打印报告来完成的。没有诊断中心可以上传患者报告的中央机制,并且在医疗保健行业中没有当前的基准可以使他们使用相同的标准来发布他们的报告。所有这些都必须标准化,包括实验室测试报告的格式和中央数据库,患者的电子记录将在那里得到更新。为了从阶段 3 过渡到阶段 4,或者甚至从中等技术成熟度过渡到高技术成熟度,数字健康记录将需要标准化所有上述内容。
现在让我们看看疾病诊断。这一领域有巨大的潜力,因为我们有医生,但在某些地区医生的数量很少。一些人认为医疗保健领域聊天机器人的发展不同于疾病诊断。然而,当我与我们的专家交谈时,他们证实了聊天机器人将成为疾病诊断和病人护理系统的一部分。
任何使用机器学习或人工智能开发的疾病诊断系统都需要具有与人类医生相同的能力。这是技术的狭义应用,也是速赢。我现在引用 Devi Shetty 博士的话,他是班加罗尔 Narayana Health 的主席,来自我在本书前面提到的 XIME Bangalore 会议,“智能软件比医生更聪明。只有 6000 种疾病,其中 1000 种是常见的。这些疾病有大约 50,000 种症状和体征。有十万种化验报告。任何软件都可以很容易地将这些匹配起来以诊断疾病,这需要医生多年的练习。“除了 Devi Shetty 博士所说的,任何机器人软件都需要理解医生是如何工作的。它也可以包括研究外科医生的日志,等等。,才能获得这样的专业知识。我们需要机器进行疾病诊断的主要原因是:
-
美国每年有 19.5 万名病人死于医疗诊断错误。
-
人类无法处理大量信息,分析这些信息,并将其应用于特定的疾病诊断
-
与医生相比,克隆一个专家机器人既便宜又快捷,而克隆专家人类医生在许多国家是被法律禁止的。
-
诊断的准确性至关重要,因为错误的诊断会增加患者的医疗成本。使用机器学习,我们可以根据机器人或机器对诊断准确性的反馈进行跟踪、测量、优化、学习和改进。
-
为了增加医疗保健对患者的价值,降低患者的诊断成本是绝对必要的。
-
价值=在治疗上花费的每一美元的患者健康结果。
如果由于错误的诊断导致病人健康状况不佳,那么医疗保健的价值就会下降。如果病人的健康结果是好的,那么所提供的医疗保健的价值就会上升。因此,我们使用机器学习来增加患者医疗保健的价值是极其重要的。
现在让我们看看放射学及其在医疗保健发展中的潜力。
放射学中常见的机器学习应用
下面是一个列表:
-
医学图像分割
-
登记
-
计算机辅助检测和诊断
-
大脑功能或活动分析
-
来自 FMR 图像的神经疾病诊断
-
使用 自然语言处理(NLP) 的基于内容的图像检索系统,用于 CT 或 MRI 图像和放射学报告的文本分析
机器学习的主要目的是帮助放射科医生对放射学数据做出智能决策,如传统的射线照片、CT、MRI 和 PET 图像以及放射学报告。
在我看来,我们即将看到应用机器学习和人工智能第四阶段的出现。基于机器学习的自动放射学疾病检测 和诊断系统将会有快速的进步。这项技术存在于实验室中,并显示出与训练有素、经验丰富的放射科医生相当的测试结果,因此这项技术进入生产应该只需要几年时间,就可以创造出机器人放射科医生[1***]。***
使用医疗保健数据集
现在,我们将研究一个带有医疗数据集的非常小的 python 代码实现。这将使读者能够理解机器学习在医疗保健领域的实际应用。我已经使用 Python 3.x 运行了这段代码,安装一些必需的 Python 库的过程在下面的练习中给出。我在这里展示的所有练习都是使用 spyder 3.x IDE 运行的,并且经过测试可以在 iPython 内核上运行,所有源代码都可以从我的 github 配置文件( https://github.com/puneetmathurDS/ )中下载。
在我们开始研究机器学习并将预测模型应用于各种数据集之前,我想提醒读者注意,练习中使用的数据不属于我的任何客户,也不来自现实世界中的真实患者。与世界上任何数据集的任何相似之处都仅仅是巧合。本书的作者或出版商对该数据集的真实性或隐私不承担任何责任。发布这个医疗数据集的目的是让读者了解如何在生产环境中对医疗数据集应用机器学习。此数据集不能用于任何其他目的,如临床试验或任何生产或商业相关的电子或其他活动。
机器学习发展的生命周期
在继续查看数据集和构建机器学习模型之前,让我们首先看看什么是典型的机器学习生命周期,并了解它在我们的短应用程序中的实现。这是我向读者展示的一个通用生命周期模型;这可以应用于任何机器学习应用程序的开发,不仅是在医疗保健行业,也可以在零售,金融或其他部门。遵循一步一步的方法可以确保在应用程序中执行机器学习的人不会迷路或错过过程的任何重要部分,并且能够按照专业标准完成他们的应用程序。这种模式没有任何参考价值;因为它是基于我多年来为客户开发机器学习应用程序的经验知识,所以我给出了这个生命周期过程。
在图 3-1 中,我们可以看到机器学习的生命周期从识别业务需求开始。这种业务需求是任何机器学习应用程序的关键,因为它为生命周期开发期间的资源需求提供了理由。业务需求也是我们在生命周期的不同阶段回顾的东西,以便实现项目的团队不会忘记最初的目标。

图 3-1
机器学习生命周期通用框架
下一步是创建机器学习解决方案架构。在此过程中,机器学习工程师和数据科学团队着手创建一个模板,基于该模板将创建机器学习应用程序。正是在这个阶段,业务需求的概念化和业务需求到技术架构的转换发生了。这也是生命周期的一部分,机器学习应用程序的架构师会回到业务中,以便更好地了解他们的需求,并开始将其转化为可实现的解决方案。
下一个阶段是数据准备阶段,这是一个非常重要的阶段,因为我们需要从数据中确定需要什么样的数据,以确定数据的来源。一旦我们知道构建这个机器学习解决方案需要什么数据,我们就可以知道这样的数据是否存在于构建应用的组织内部,或者它需要来自组织外部。数据准备的下一个阶段是获取数据,构建机器学习解决方案的团队需要获取数据。如果整个数据集很大,那么至少可以使用一个样本数据集,在此基础上构建解决方案。需要从内部和外部来源获取数据。这里最重要的任务是确定数据可用的格式,比如 csv、XML、JSON、Oracle 数据库或 DB2 数据库等平面文件。实现团队根据什么是结构化数据的来源,什么是非结构化数据的来源进行分类。机器学习中对非结构化数据和结构化数据的处理是非常不同的,因此其识别同样重要。在数据准备的下一步中,我们执行数据争论,这主要涉及清理数据。在这里,所有对我们的业务解决方案需求没有任何价值的数据都被删除,只有解决业务需求所需的数据被保留。
数据清理完成后,我们进行机器学习周期的下一步,即探索性数据分析。在探索性数据分析中,我们查看数据的基本统计数据,如平均值、中值和众数,以及不同标签之间的相关性,并确定数据是由数字变量还是分类变量组成,等等。这种探索性的数据分析为模型构建提供了方向。例如,算法的选择取决于变量的种类。在样本中,我们可能有带有分类变量的数据集,如基于其他标签预测的性别(男性或女性)。在这种情况下,我们可能必须使用非定量算法来建立模型。下一步是建立模型,它与探索性数据分析密切相关。在这个过程中,我们进行描述性统计分析,确定我们将使用哪种建模技术,然后建立一个基准预测模型。我们对数据集使用其他方法和算法,并尝试解释和找到创建预测模型的最佳算法。一旦模型的识别完成,下一步就是创建模型验证。我们使用更接近生产的阶段数据集,并观察我们的模型如何表现;如果它给出了好的结果,那么这个模型就被部署和实现了。在这之后,反馈被用来查看它是否满足了它被构建的业务需求。如果有新的业务需求或模型需要处理业务要求的一些事情,那么我们再次回到解决方案架构数据准备、EDA 模型和构建模型的流程,然后我们进行模型验证。本质上,这是一个循环过程,一直持续到机器学习应用程序终止。
实现患者电子健康记录数据集
我们已经查看了整个机器学习应用程序开发生命周期,现在让我们在患者电子健康记录数据集中实现它。该数据集是平面文件的形式,可从以下 URL 获得: http://www.PuneetMathur.me/Book009/Diabetes_Dataset.csv 。我们现在来看看清单 3-1 中的代码,这些代码是关于加载和分析电子健康记录数据集的 python 代码。
# -*- coding: utf-8 -*-
"""
Created on Thu Mar 15 23:46:06 2018
@author: PUNEETMATHUR
"""
#Importing python libraries
import pandas as pd
import os
os.getcwd()
#Reading dataset from flat file
fname="Diabetes_Dataset.csv"
patients= pd.read_csv(fname, low_memory=False)
df= pd.DataFrame(patients)
#Look at the first record
print(df.head(1))
Listing 3-1Code for Loading Electornic Health Record Data Set
在清单 3-1 给出的 Python 代码中,我已经加载了所需的 Python 库。首先,我已经加载了 Pandas 库来加载 csv 平面文件。这是处理 csv 和 JSON 平面文件最有效的库。接下来,我加载了操作系统库来识别当前的工作目录。如果您已经从数据集和 Python 脚本 ElectronicHealthRecord.py 所在的目录启动了 Python,那么您不需要更改目录;否则,您可以使用操作系统包中的 curdir()函数来更改它。你可以从我的 github 档案( http://www.PuneetMathur.me/Book009/ )下载这个。
表 3-1
探索数据集
|患者 ID
|
性别
|
年龄
|
糖尿病类型
|
糖尿病状况
|
a1c 测试
|
收缩压
|
心脏舒张期
|
| — | — | — | — | — | — | — | — |
| 5.557686412 | 女性的 | Twenty-nine | 类型 2 | one | Eight point eight one | One hundred and forty-seven | Ninety-three |
现在我们进入下一步:数据准备。为此,我们需要探究并查看下图 3-2 中数据的形状和大小()。
print(df.size)
8632
print(df.shape)
(664, 13)
print(df.columns)
Index(['Patient ID', 'Gender', 'Age', 'Type of diabetes', 'Diabetes status',
'A1cTEST', 'BPSystolic', 'BPDiastolic', 'HeartRateBPM', 'BMI',
'FrozenShoulder', 'CarpalTunnelSynd', 'DupuytrensCont'],
dtype='object')
Listing 3-2Exploring the Shape and Size of Data Set
在清单 3-2 中,我们可以看到 df.size 语句给出的数据集中总共有 8632 个单元格。我们总共有 664 行和 13 列由 df.shape 语句给出。按 df.columns 语句列出,我们看到从性别、年龄、糖尿病类型、糖尿病状态、糖化试验等开始的各种列。现在让我们看一下数据字典,它描述了每一列及其值。
“患者 ID”:这是唯一的患者 ide,由十进制值表示。
‘性别’:男性或女性。
“年龄”:以年为单位,给出了患者开始治疗时的总年龄。
“糖尿病类型”:1 型或 2 型是我们正在追踪的两种类型的糖尿病。
“糖尿病状态”:这是宣布一个人是否患有糖尿病的预测值列。0 表示没有糖尿病,1 表示患者有糖尿病。
’ A1cTEST ':测试结果以百分比表示。正常:血红蛋白 A1c 水平的正常范围在 4%到 5.6%之间。糖尿病前期:血红蛋白 A1c 水平在 5.7%到 6.4%之间意味着你患糖尿病的几率更高。糖尿病:6.5%或更高的水平意味着你有糖尿病。
“收缩压”:成年人的正常血压收缩压低于 140 毫米汞柱,舒张压低于 90 毫米汞柱。
“舒张压”:成年人的正常血压收缩压低于 140 毫米汞柱,舒张压低于 90 毫米汞柱。
“心率 BPM”:成年人的正常静息心率范围是每分钟 60 到 100 次。
身体质量指数:身体质量指数低于 18.5 公斤/平方米表明你体重过轻。你可能需要增加体重。如果你的身体质量指数是 19 到 24.9 公斤/平方米,你是一个健康的体重,应该努力保持下去。25 到 29 公斤/平方米的身体质量指数被定义为超重。为了你的健康着想,减肥是个好主意,或者至少是为了防止体重进一步增加。身体质量指数超过 30 公斤/平方米被定义为肥胖,意味着你的健康处于危险之中。减肥会改善你的健康。
“FrozenShoulder”:是/否由医生根据对患者的身体检查来决定。
“腕管综合症”:在体检医生确定结果后是/否。谷歌 [1 ]字典对腕管综合征的定义是:
腕管综合征
名词
由于通过手腕前部通道穿过腕骨的主要神经受压而引起的手和手指疼痛。它可能是由持续的重复运动或液体潴留引起的。
DupuytrensCont ':是/否医生在体检和测试结果后决定。
受影响的手指无法完全伸直,这可能会使日常活动变得复杂,例如将手放入口袋、戴上手套或握手。杜普伊特伦挛缩主要影响无名指和小指,最常发生在北欧血统的老年男性 [2 ]。
既然我们已经理解了这个数据集的数据字典,现在让我们仔细看看这个数据,清理它,然后在下面的清单 3-3 中探索它。为此,我们将使用 Python 库和函数。这些通常与机器学习算法一起使用,所以你必须熟悉它们并更详细地理解它们。
#You can use the Describe method to see; however, since our columns are more
#We will use individual functions to do EDA
print(dfworking.describe)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 664 entries, 0 to 663
Data columns (total 13 columns):
Patient ID 664 non-null float64
Gender 664 non-null object
Age 664 non-null int64
Type of diabetes 664 non-null object
Diabetes status 664 non-null int64
A1cTEST 664 non-null float64
BPSystolic 663 non-null float64
BPDiastolic 663 non-null float64
HeartRateBPM 663 non-null float64
BMI 663 non-null float64
FrozenShoulder 664 non-null object
CarpalTunnelSynd 664 non-null object
DupuytrensCont 664 non-null object
dtypes: float64(6), int64(2), object(5)
memory usage: 67.5+ KB
Listing 3-3Code for Checking Missing Values
我们注意到在清单 3-3 中没有一列有 null 或空值。然而,在现实世界中,你可能很少会发现这是真的。肯定需要清理数据。对于每个列空值,您可以做三件事。第一种方法是删除整行。数字 2 是用平均值替换行。第三是保持行不变。无论您如何决定您的数据,您都需要仔细分析,看看它将如何影响您的整体结果。删除行或列会导致丢失没有缺失值的列中的宝贵信息。它还有助于了解给定列中丢失的值的百分比。这有助于我们做出深思熟虑的决定。我们现在将进入探索性数据分析的下一步。你会注意到我已经通过删除清单 3-4 中的 PatientID 列使用了 df.working dataframe。这是一个很好的做法,因为它保留了原始的 Pandas 数据帧,而不是删除它。例如,您可以将这些行写成:df- df.drop("Patiend ID ",axis=1)。更容易实现;然而,当您在代码执行过程中发现您采用的代码执行路径不起作用或没有给出任何有意义的结果时,您将需要返回并采用原始数据帧 df,然后进行另一轮代码执行。但是您可能已经丢失了 df.dataframe 中的原始值。因此,我建议您使用另一个数据帧,该数据帧将是工作数据帧,并且作为机器学习应用程序中的编码最佳实践,不要接触原始数据帧。事实上,您应该在您的代码中使用一个替代的 dataframe 名称,只要您可能需要返回到 dataframe 状态,以便查看结果对于满足业务目标是否有意义。现在让我们对数据集做一些探索性的数据分析,如下面的代码清单 3-4 所示。
#Now using a dfworking dataframe to maintain original data in df pandas dataframe
dfworking=df.drop('Patient ID',axis=1)
dfworking.mean()
Out[146]:
Age 38.899096
Diabetes status 0.240964
A1cTEST 5.890858
BPSystolic 116.278522
BPDiastolic 93.130680
HeartRateBPM 91.812971
BMI 23.870348
dfworking.median()
Out[148]:
Age 30.000000
Diabetes status 0.000000
A1cTEST 5.600000
BPSystolic 100.720000
BPDiastolic 91.539001
HeartRateBPM 91.000000
BMI 24.000000
Listing 3-4Code and Results of EDA
现在我们有了 EDA 的代码和结果,我们需要解释并看看我们的数据告诉我们什么。在我们的数据集中,一个人的平均年龄是 39 岁。普通患者的 A1ac 测试百分比为5.89%,这意味着患者样本处于糖尿病前期。平均收缩压是 116。8,也就是说一般患者血压正常。舒张压是 93。平均而言,这意味着它略高于我们数据集中舒张压标准的基准血压舒张压水平约 90 mmHG。平均每分钟心率(bpm)为 91.8,在 60 至 100 bpm 标准范围内。平均身体质量指数是 23 岁。这表明普通患者具有健康的体重。所以这些是从研究我们数据集的统计矩中得到的重要发现。在查看了数据集中的统计数据之后,我们现在来看另一个定义数据集中变量之间关系的统计度量。请注意,我们的预测指标是糖尿病状态,即 0 表示无糖尿病,1 表示患者有糖尿病。中位数也是一个要寻找的重要状态,通常在数据中有异常值时使用。如果一列或变量的中值和平均值之间存在巨大差异,则表明数据中存在异常值。然而,在我们的数据集中,当我们比较列表 3-5 中给出的平均值和中值之间的变量值时,我们发现年龄与 30 岁的平均值有差异,对于其余的列,差异可以忽略。
现在,我们将检查数据集是否存在异常值。我们将首先看看这些列中的数据是如何分布的。这将使我们对数据的传播有所了解。在代码清单 3-5 中,我现在使用标准差向您展示数据的分布。
dfworking.std()
Out[160]:
Age 19.109127
Diabetes status 0.427991
A1cTEST 1.833379
BPSystolic 27.826840
BPDiastolic 5.112349
HeartRateBPM 3.649444
BMI 1.990809
Listing 3-5
Spread of Data
我们知道标准差是每个观察值与平均值 [3 ]的差异的汇总度量。
在我们的数据中,我们可以看到 19 岁年龄的标准偏差,这意味着从 39 岁的平均年龄有大约 19 年的差距。我们将忽略糖尿病状态数,因为它没有任何意义,因为它是 0 或 1 的二进制值,并且该值是 0.4,介于 0 和 1 之间。我们将查看 A1c 测试标准偏差,它与平均值相差 1.8%。同样的,收缩压是 27。这意味着高血压有更多的变异,这就是我们样本患者的问题所在。血压舒张压的标准差为 5,当我们将其与血压收缩压的标准差相比时,这似乎不是很高。心率 bpm 标准差为 3.64,也可以忽略不计,身体质量指数为 2 值得关注,这也意味着我们有体重指数变异较高的患者。现在让我们更深入地研究我们的数据,更仔细地观察它是如何传播的,以及我们可以从中解读什么。为此,我们将使用最大值/最小值、分位数峰度和偏度函数,它们是 pandas 数据框的一部分。在代码清单 3-6 中,我们查看数据集中数值变量的最大值。
dfworking.max()
Out[167]:
Gender Male
Age 79
Type of diabetes Type 2
Diabetes status 1
A1cTEST 10.99
BPSystolic 212
BPDiastolic 126
HeartRateBPM 113
BMI 30.9951
FrozenShoulder Yes
CarpalTunnelSynd Yes
DupuytrensCont Yes
dtype: object
dfworking.min()
Out[168]:
Gender Female
Age 10
Type of diabetes None
Diabetes status 0
A1cTEST 2.02
BPSystolic 100.01
BPDiastolic 87
HeartRateBPM 88
BMI 17.1278
FrozenShoulder No
CarpalTunnelSynd No
DupuytrensCont No
Listing 3-6Checking Spread of Variables in Data Set
年龄的最大值是 79,这意味着该样本中年龄最大的患者是 79 岁。最常见的糖尿病类型是 1 型,糖尿病状态是 1,a1c 测试百分比最大值是 10,这是非常高的。血压收缩压值 212,也很高,舒张压值 126,也很高。心率 bpm 最大值 113,也偏高。身体质量指数最大值是 31,这是超重,其余项目有分类值。与最大值类似,我们也有最小值。在这个样本数据集中,患者的最小年龄是 10 岁。最低糖尿病状态为 0,这意味着患者没有糖尿病。100 测试的最小值是 2。这低于正常的血红蛋白 A1c 水平。血压收缩压的最小值是 100。这低于 140 毫米汞柱,对成年人来说是正常的。血压舒张最小值为 87,如果患者的血压低于 90 mmHg,也认为是正常的。如果心率 bpm 在 60 到 100 bpm 的范围内,则认为它是正常的,这里我们有最小值 88,这在正常范围内。身体质量指数最小值是 17。这意味着患者体重过轻,因为低于 18.4。其余的列值是分类的。
检测异常值
现在我们进入检测异常值的任务。除非我们知道每个变量或列在数据集中是否有异常值,否则任何严肃的数据分析都无法进行。为了检测异常值,我们需要首先定义它是什么。这是一个关于离群值计算方法的争论问题;然而,我采用常用的 1.5 倍四分位距的截止值。通过使用熊猫数据框中的最大值和最小值函数,可以知道任何列的数据集范围。为了计算异常值,我将首先取下面清单 3-7 和 3-8 中数字列的最大值和最小值。
dfworking.max()
Out[203]:
Gender Male
Age 79
Type of diabetes Type 2
Diabetes status 1
A1cTEST 10.99
BPSystolic 212
BPDiastolic 126
HeartRateBPM 113
BMI 30.9951
FrozenShoulder Yes
CarpalTunnelSynd Yes
DupuytrensCont Yes
dtype: object
Listing 3-7Calculating Maximum Values
我们在清单 3-7 中看到,年龄的最大值是 79,100 测试的最大百分比是 10.9,收缩压是 212,舒张压是 126,心率 bpm 是 113,身体质量指数是 30.99。类似地,我们在清单 3-8 中看到年龄的最小值是 10,对于 100%的测试百分比是 2.2。收缩压为 100.0,舒张压为 87,心率 bpm 为 88,身体质量指数为 17.12。
dfworking.min()
Gender Female
Age 10
Type of diabetes None
Diabetes status 0
A1cTEST 2.02
BPSystolic 100.01
BPDiastolic 87
HeartRateBPM 88
BMI 17.1278
FrozenShoulder No
CarpalTunnelSynd No
DupuytrensCont No
Listing 3-8Calculating Minimum Values
让我们拿起年龄栏来帮助理解这一栏的范围。我们已经看到,对于年龄,最大值是 79,最小值是 10。所以在我们的患者中,最小的 10 岁,最大的 79 岁。所以我们的区间是 79 减 10,也就是 69 年。因此,我们正在测量年龄范围为 69 岁的患者的健康记录。
现在我们知道了最大值和最小值,并且计算了数据的范围,我们需要查看这个年龄列的四分位数范围。四分位数间距是数据集的第一个四分位数和第三个四分位数之间的差值。它用于描述数据集 [4 ]内数据的分布情况。在代码清单 3-9 中,我们现在来看数值数据集的第一个四分位数。
dfworking.quantile(0.25)
Out[206]:
Age 29.000000
Diabetes status 0.000000
A1cTEST 5.177500
BPSystolic 100.375000
BPDiastolic 91.107946
HeartRateBPM 91.000000
BMI 23.000000
Listing 3-9Measuring 1st Quartile of Our Data Set
清单 3-9 和 3-10 向您展示了一种快速计算我们数据集中第一个四分位数和第三个四分位数的方法。我们看到,在第一个四分位数中,年龄为 29,A1c 试验为 5.1,收缩压为 100,舒张压为 91.2,心率 bpm 为 91,身体质量指数为 23。在清单 3-10 中,我们现在来看看数据集的第三个四分位数。
dfworking.quantile(0.75)
Out[210]:
Age 49.000000
Diabetes status 0.000000
A1cTEST 6.000000
BPSystolic 122.355000
BPDiastolic 92.070602
HeartRateBPM 92.000000
BMI 24.441247
Listing 3-10Measuring 3rd Quartile of Our Data Set
为了确定数据集中每个变量的异常值的阈值,在清单 3-11 中,我展示了计算这些阈值的代码。
dfworking.quantile(0.25)*1.5
Out[214]:
Age 43.500000
Diabetes status 0.000000
A1cTEST 7.766250
BPSystolic 150.562500
BPDiastolic 136.661919
HeartRateBPM 136.500000
BMI 34.500000
Name: 0.25, dtype: float64
dfworking.quantile(0.75)*1.5
Out[215]:
Age 73.500000
Diabetes status 0.000000
A1cTEST 9.000000
BPSystolic 183.532500
BPDiastolic 138.105902
HeartRateBPM 138.000000
BMI 36.661871
Listing 3-11Measuring Outlier Threshold Values of Our Data Set
在清单 3-11 中,给出了每列的第一个分位数乘以 1.5 个阈值。对于年龄列,下限是 43.5,第三个分位数是 73.5。我们可以看到,数据实际上向我们表明,任何低于年龄 43.5 的第一个分位数值的年龄都是异常值。类似地,年龄列中任何大于 73.5 的值也是异常值。类似地,对于 A1c 测试,异常值的阈值下限是 7.7,A1c 测试的阈值上限是 9。样本中任何低于下阈值 7.7 或高于上阈值 9.4 的值都是异常值。同样,对于收缩压,任何低于 150.5 而高于 183 的值都是异常值。对于舒张压,我们知道这个范围远小于下限(136 点)和上限(138 点)。类似地,我们有心率 bpm,其下限为 136.5,上限为 138。即使对于身体质量指数来说,该值也遵循舒张压和心率 bpm,具有其阈值之间的较低范围,因为较低阈值是 34,而身体质量指数的较高阈值是 36.6。为了更好地理解数据集中的这种分布,我现在向您展示一个图表,使用箱线图来表示清单 3-12 中的变量。在代码清单 3-12 中,我现在向您展示如何查看我们 6 列中每一列的数据分布的可视化。
#Horizontal default boxplot chart
dfworking.boxplot(figsize=(10, 6))
#Vertical Boxplot chart
dfworking.plot.box(vert=False)
#Boxplot by selecting only the required columns
dfworking.boxplot(column=['A1cTEST','BPSystolic','BPDiastolic','HeartRateBPM','BMI','Age'],figsize=(10, 6))
Listing 3-12Visualization of the spread of data for each of our 6 columns.
图 3-2 直观地向我们展示了变量的方框图。年龄显示了均匀的分布,并且在视觉上没有显示任何异常值;然而,对于 A1c 测试,我们可以看到该百分比位于非常窄的范围内。在下限阈值和上限阈值上,我们可以看到一些异常值散落在图上。对于 BP 收缩压,我们可以看到异常值位于 150+的范围内。对于血压舒张期,我们可以看到一些阈值下限范围内的异常值,但大多数位于阈值上限范围内。这与心率 bpm 和身体质量指数列类似。从视觉上可以看出,舒张压和心率 bpm 与身体质量指数之间的共同差异表明它们的范围很窄。然而,对于 BP 收缩压,该范围非常高,因此在用于计算四分位数范围然后计算异常阈值的函数分位数中是明显的。我决定保留异常值是基于这样一个事实,即在像 BP systolic 这样的列变量中,这是本研究中的关键变量之一,如果我删除异常值以上的值,那么我将剩下更少有意义的数据来分析。通过使用代码 dfworking[‘BPSystolic’]。loc[df[’ BP systolic ']>= 183.562500。count(),我们得到的值是 35,这表明在这个列变量中有 5.3%的异常值,这是非常显著的。因此,我们将保留异常数据进行分析。然而,我们需要选择一个对异常值稳健的分类算法,比如决策树 [5 ]。

图 3-2
电子患者健康记录数据集的箱线图
现在,我们了解了数据的分布情况,并通过命令直观地看到了数据的分布情况。让我们看看我们的列变量的另外两个度量:偏斜度和峰度。这将为我们提供关于数据曲线的形状和大小的具体信息。在清单 3-13 中,我们可以看到偏斜度和峰度的值。
dfworking.skew()
Age 0.878405
A1cTEST 0.344770
BPSystolic 1.720338
BPDiastolic 3.693222
HeartRateBPM 3.327100
BMI 1.098987
dfworking.kurtosis()
Age -0.286342
A1cTEST 0.461561
BPSystolic 1.948725
BPDiastolic 15.712615
HeartRateBPM 13.172057
BMI 5.468543
Listing 3-13Skew and Kurtosis Values of Our Variables in Our Data Set
在我们研究偏斜度和峰度之前,我想提醒读者正态分布曲线具有均值=众数=中位数的性质。然而,通过观察数据集变量的偏斜度和峰度,我们试图了解它们与正态曲线有多接近或有多不同。这也可以通过情节直观地看到,我们将在后面做;然而,偏斜度和峰度数值也有助于我们理解数据集的分布。我不会深入讨论计算偏斜度和峰度的公式,因为我希望读者了解这一点,或者参考互联网上的一些好的参考资料。偏斜度(或偏斜度)是通过数学方法计算的,是我们首先得到的数字的结果。如果偏斜度大于 0,那么我们说分布是正偏斜的;然而,如果我们计算的偏斜数小于 0,那么我们说分布是负偏斜的。如果偏斜的数量等于 0,则称该分布是对称的。负偏态分布有一个长的左尾巴,正偏态分布有一个长的右尾巴。有了这些知识,我们现在开始解释数据集中每一列的结果。年龄列的值为 0.8,这意味着这个可变年龄是正偏的,并且沿着右尾分布。稍后,我们将通过可视化来验证我们对变量的数字数据分析。对于 A1c 测试偏度,我们的值为 0.34,这意味着它更接近于正态曲线;然而,它稍微有点偏正。对于收缩压,我们的值为 1.2,这显然意味着数据是正偏的。舒张压也具有非常高的正值 3.9,这表明它也是高度正偏的。心率 bpm 的值也是 3.3,这也意味着它是高度正偏的。身体质量指数也是正面倾斜的。
接下来我们转向峰度,它显示了分布的厚度。如果一个数据分布有更多的峰值,则称之为左分布或薄分布,称之为厚尾分布。在这样的分布中,与正态分布相比,出现极端结果的可能性更大。峰度公式计算值等于 3 的正态分布的邪恶程度。过多的峰度意味着变量的分布值将高于 3,而较少的峰度意味着它将低于 3。如果峰度值小于 3,那么它也表示一种称为中峰度的分布类型;然而,中峰度分布的范围是介于 0 和 3 之间的峰度值。如果峰度值小于 0,则称之为扁峰度。平顶分布的故事更短更薄,中央峰更低更宽。年龄的峰度是负值 0.2。A1c 测试是 0.4 的正值,但低于 3 的值。血压收缩压值为 1.9,但低于 3 且大于 0。血压舒张压 15.1,心率 BPM 13.1。身体质量指数是 5.4。我们已经注意到,如果峰度数值小于 0,那么这样的分布是平峰度的,这意味着它的尾部更短更细,并且它的中心峰值通常更低更宽。我们有介于 0 和 3 之间的变量 A1c 测试和 BP 收缩压,表明这些变量的分布是中等的。我们数据集中的三个变量,舒张压、心率 bpm 和身体质量指数,具有超过 3 的峰度值,表明这些变量的数据分布是尖峰的。尾巴更长更粗,中央的峰更高更尖。
在图 3-3 中,您可以看到使用 Pandas dataframe 的最高方法的数据集中变量的可视化输出。

图 3-3
可视化数据集中变量的分布
dfworking.hist(figsize=(10, 6))
我们可以通过图 3-3 中的可视化来确认偏度和峰度的数值解释。在下面的代码清单 3-14 中,我们使用 dataframe dfworking 的 corr()函数查看相关系数结果。
dfworking.corr()
Age Diabetes status A1cTEST BPSystolic BPDiastolic \
Age 1.000000 -0.006059 0.011436 0.013097 0.028190
Diabetes status -0.006059 1.000000 0.816808 0.902857 0.560962
A1cTEST 0.011436 0.816808 1.000000 0.827919 0.591827
BPSystolic 0.013097 0.902857 0.827919 1.000000 0.735363
BPDiastolic 0.028190 0.560962 0.591827 0.735363 1.000000
HeartRateBPM -0.052383 0.151831 0.147737 0.168413 0.058129
BMI 0.027911 0.181897 0.167908 0.181927 0.130275
HeartRateBPM BMI
Age -0.052383 0.027911
Diabetes status 0.151831 0.181897
A1cTEST 0.147737 0.167908
BPSystolic 0.168413 0.181927
BPDiastolic 0.058129 0.130275
HeartRateBPM 1.000000 0.107147
BMI 0.107147 1.000000
Listing 3-14
Correlation Coefficient Results
接下来是计算,看看变量之间是否有某种关系。为此,我们将使用 Pandas dataframe 的 corr()函数,这将使我们能够查看这些变量之间的相关性。为了提醒读者如何解释相关结果,两个变量之间的相关值等于 1 意味着完美的线性正关系,如果它是负的,则意味着变量之间的负线性关系。如果相关系数值等于 0,那么就说两个变量之间没有真正的线性关系。从 0 到 1 或-1 交错在 0.34 到 0.3 之间的值被称为具有弱线性关系。介于 0.5 和-0.5 之间的值被称为具有适度的正或负线性关系。介于-0.7 和+0.7 之间的值被认为与我们的数据集 [6 ]有很强的正或负线性关系。有了这些信息,我们现在可以快速分析对数据集应用相关函数的结果。
当我们查看清单 3-14 时,我们的主要动机是取出那些至少具有中等或强的变量,如果可能的话,还有一个完美的线性关系。因此,我们在寻找相关系数从正负 0.5 到 0.12 尽可能接近 1 或 1 的变量。我们可以看到,年龄变量与其他变量没有任何显著的线性关系;然而,当我们观察糖尿病状态的预测变量时,它似乎与 A1c 试验呈 0.8 的正相关,与收缩压呈 0.9 的正相关。与血压舒张压(0.5)有中度关系。可以理解,A1c 试验与预测变量糖尿病状态(0.8)、收缩压(0.83)和舒张压(0.59)有很强的关系。收缩压和舒张压的正相关系数为 0.74。舒张压与糖尿病状态呈中度正相关,预测变量为 0.5。心率 bpm 似乎与我们数据集中的任何变量都没有任何显著的相关性。身体质量指数的情况也是如此,它似乎与我们的任何数据集都没有任何关联。
现在,我们能够看到那些看起来有某种关系的重要变量,直观地观察它们,并理解它们是如何放置的。举例来说,在图 3-4 中,散点图显示了列变量 A1c 测试和 BP 收缩压之间的直观关系。

图 3-4
A1cTest 和 BP 收缩压变量之间的散点图
dfworking.plot.scatter(x='A1cTEST', y="BPSystolic",s=dfworking['A1cTEST']*2)
在图 3-4 中,我们看到了两个变量之间的某种模式。我们看到有几组群集被放置用于 A1c 测试;随着结果的上升,患者被分组到特定的聚类模式中,这些模式显示出阶梯状的上升趋势。它从 100 BP 的收缩压开始,超过 200 BP 的收缩压,并从 A1c 测试值的 2%以上开始。通过可视化早期检测这种模式在机器学习中非常重要。我们可以尝试实现某些分类技术,将患者分为视觉上对我们有吸引力的这几组。
探索性数据分析的最后一步是查看包含分类变量(包括预测变量糖尿病状态)的列。我们的数据集中有六个分类变量列。第一个是性别,将我们的数据集分为男性或女性。下一个分类栏是糖尿病的类型。在我们的数据集中,没有 1 型糖尿病患者;然而,我们也有没有糖尿病或二型糖尿病的病人。糖尿病状态列是预测变量,其值也是分类的,其中 0 表示没有糖尿病,1 表示患者有糖尿病。肩周炎由医生通过人工检查确定,有“是”或“否”的值:“是”表示患者有肩周炎,“否”表示患者没有肩周炎。在腕管综合征中,它与冻结肩相同,其中 yes 表示患者患有腕管综合征,no 表示患者没有这种疾病。对于袢掌腱膜挛缩症,也有“是”和“否”两栏,其中“是”表示患者患有该疾病,“否”表示患者没有该疾病。现在,我将使用基于这些分类变量的交叉列表,来看看我们的数据集是如何针对这些列进行分类的。在代码清单 3-15 中,我们查看了数据集中的性别分类。
my_tab = pd.crosstab(index=df["Gender"], columns="Count") # Name the count column
my_tab=my_tab.sort_values('Count', ascending=[False])
print(my_tab)
col_0 Count
Gender
Female 351
Male 313
Listing 3-15Gender Classification in the Data Set
在清单 3-15 中,我们可以看到,在我们的数据集中,总共 664 名患者中有 351 名女性,男性患者有 313 名,因此按性别划分,53%的患者为女性。这也可以在图 3-5 给出的图表中直观地看到。

图 3-5
性别分类数据可视化
data_counts = pd.DataFrame(my_tab)
pd.DataFrame(data_counts).transpose().plot(kind='bar', stacked=False)
现在我们来看下一列,即清单 3-16 中的糖尿病类型。
my_tab = pd.crosstab(index=df["Type of diabetes"], columns="Count") # Name the count column
my_tab=my_tab.sort_values('Count', ascending=[False])
print(my_tab)
col_0 Count
Type of diabetes
None 504
Type 2 160
Listing 3-16Type of Diabetes Classification
我们可以看到数据集中 24%的患者患有二型糖尿病,504 名患者没有糖尿病。计算百分比的原因对于任何分类列都很重要,因为我们需要确定我们是否正在处理一个罕见的事件。如果我们正在处理一个罕见的事件,我们需要使用单变量分析来处理模型的建立。图 3-6 给出了糖尿病类型栏的直观表示。

图 3-6
糖尿病类型分类可视化
接下来,我们来看看清单 3-17 中的列冻结肩。
my_tab = pd.crosstab(index=df["FrozenShoulder"], columns="Count") # Name the count column
my_tab=my_tab.sort_values('Count', ascending=[False])
print(my_tab)
col_0 Count
FrozenShoulder
No 533
Yes 131
Listing 3-17Classification of Frozen Shoulder Disease in Our Data Set
在列表 3-17 中,我们可以看到我们数据集中 19.1%的患者患有肩周炎,533 名患者没有肩周炎。由于这个百分比高于 10 %,我们现在可以确定肩周炎不是我们预测的罕见事件。冻结肩的数据可视化如图 3-7 所示。

图 3-7
冻结肩疾病分类可视化
data_counts = pd.DataFrame(my_tab)
pd.DataFrame(data_counts).transpose().plot(kind='bar', stacked=False)
Out[316]: <matplotlib.axes._subplots.AxesSubplot at 0x243ae851278>
my_tab = pd.crosstab(index=df["CarpalTunnelSynd"], columns="Count") # Name the count column
my_tab=my_tab.sort_values('Count', ascending=[False])
print(my_tab)
col_0 Count
CarpalTunnelSynd
No 546
Yes 118
Listing 3-18Carpal Tunnel Syndrome Classification
现在让我们看看腕管综合症。在图 3-8 中,我们可以看到交叉列表的代码,以及自称患有腕管综合征的人数和未被诊断为腕管综合征的人数。我们的样本中有 17%被诊断患有这种疾病。总共有 118 人,其中 546 人没有这种症状。

图 3-8
腕管综合征可视化
data_counts = pd.DataFrame(my_tab)
pd.DataFrame(data_counts).transpose().plot(kind='bar', stacked=False)
Out[319]: <matplotlib.axes._subplots.AxesSubplot at 0x243ae6a45c0>
这种分类的可视化如图 3-8 所示。
现在让我们来看看掌腱膜挛缩症及其分类,如图 3-8 所示。在代码列表 3-19 中,我们使用交叉列表来查看杜普伊特伦挛缩症患者的分类。
my_tab = pd.crosstab(index=df["DupuytrensCont"], columns="Count") # Name the count column
my_tab=my_tab.sort_values('Count', ascending=[False])
print(my_tab)
col_0 Count
DupuytrensCont
No 544
Yes 120
Listing 3-19Dupuytren’s Contracture Classification
被诊断患有掌腱膜挛缩症的患者占我们数据集的 18 %, 544 名患者没有这种疾病。我结束了对所有分类列的分析,因为我们已经探索了我们的数据集,并对其进行了充分的分析,以开始构建预测模型。
数据准备
现在,我们已经完成了探索性的数据分析,并在构建模型之前继续实际的数据准备工作。我在表格 3-2 中给出了我们需要做的一些步骤及其目的。我们在表中看到有四个步骤。首先是将数据划分为目标变量和特征;我们这样做是为了避免计算带有特征的目标变量。这在机器学习中很常见,需要避免。第二步是标准化数据,这样做是为了建立一致性或标准化尺度来衡量我们数据集中的所有变量。下一步是创建虚拟变量,主要目的是将所有分类变量转换成虚拟变量,比如性别(男性或女性)。我们可以说性别 0 等于男性,性别 1 等于女性。20 代表男性,1 代表女性,因此数字编码是我们在这一特定步骤中需要做的。数据准备的最后一步是数据的混洗和分割,这两个步骤都是为了增加一定程度的随机性并删除数据中的任何病毒。一旦我们完成了这四个步骤,我们将能够开始建立我们的预测模型。对于每个步骤,我将向您展示我们数据集的代码和结果,以及如何进行数据准备。
表 3-2
数据准备步骤
|数据准备步骤
|
| — |
|
没有#
|
工作
|
描述
|
| — | — | — |
| one | 将数据分为目标变量和特征。 | 我们需要将数据分为特征和目标变量,以确保我们不会将目标变量算作特征;否则,我们的预测模型会给出错误的结果。 |
| Two | 标准化数据。 | 我们需要将数据标准化,因为这将所有的变量带到一个共同的尺度上。俗话说,你不能把橘子和苹果相提并论。我们的变量也是如此。它们是具有不同测量尺度的不同测量,例如血压收缩压不同于心率 bpm 的尺度。 |
| three | 虚拟变量 | Python 中的 Scikit 库的一个局限性是它只能处理数值数据,而不能处理分类数据。消除这种限制的一种方法是将数据集中的分类变量(如冻结肩列)转换为数字编码格式。 |
| four | 洗牌和分割数据。 | 我们现在打乱数据以引入随机因素,然后将其分为训练和测试,以消除数据中的偏差。 |
清单 3-20 中给出了步骤 1 的代码。
#Data Preparation Steps
#Step 1 Split data into features and target variable
# Split the data into features and target label
diabetics = pd.DataFrame(dfworking['Diabetes status'])
features = pd.DataFrame(dfworking.drop('Diabetes status', axis = 1))
diabetics.columns
features.columns
features.columns
Out[352]:
Index(['Gender', 'Age', 'Type of diabetes', 'A1cTEST', 'BPSystolic',
'BPDiastolic', 'HeartRateBPM', 'BMI', 'FrozenShoulder',
'CarpalTunnelSynd', 'DupuytrensCont'],
dtype='object')
Listing 3-20Step 1 of Data Preparation
在清单 3-20 中,在实现步骤 1 的代码时,我们看到 features dataframe 没有列 diabetes status,这是我们的目标变量。我创建了两个数据框:糖尿病数据框,它是预测值或目标变量熊猫数据框;特征数据框,它没有糖尿病状态列。我使用了熊猫数据框的拖放方法来删除糖尿病状态列。现在我们进入第二步:标准化数据。这可以从清单 3-22 中看出。为了实现这一点,我将使用 sklearn.preprocessing 库并从中导入 MinMaxScaler 来标准化我们的数据集。请注意,这种标准化只适用于数字变量,而不适用于分类变量或虚拟变量。
dfworking.dtypes
dfworking.dtypes
Out[355]:
Gender object
Age int64
Type of diabetes object
Diabetes status int64
A1cTEST float64
BPSystolic float64
BPDiastolic float64
HeartRateBPM int64
BMI float64
FrozenShoulder object
CarpalTunnelSynd object
DupuytrensCont object
Listing 3-21Numerical Columns in Our Working Data Set
我们可以在清单 3-21 中看到,年龄 A1c 测试、收缩压、舒张压、心率 bpm 和身体质量指数列是数字。我们将忽略糖尿病状态列,因为它是患者的分类变量,其中 0 表示没有糖尿病,1 表示患者患有糖尿病。在清单 3-22 中,我提供了提取这些数字特征的代码,然后对它们应用标准化标量。
# Import sklearn.preprocessing.StandardScaler
from sklearn.preprocessing import MinMaxScaler
# Initialize a scaler, then apply it to the features
scaler = MinMaxScaler()
numerical = ['age', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']
features_raw[numerical] = scaler.fit_transform(dfworking[numerical])
# Show an example of a record with scaling applied
display(features_raw[numerical].head(n = 1))
Age A1cTEST BPSystolic BPDiastolic HeartRateBPM BMI
0 0.275362 0.756968 0.419591 0.153846 0.028571 0.545713 No Yes Yes
Listing 3-22Step 2 of Data Preparation
在清单 3-22 中,我们可以看到一个已经被缩放的特征的示例记录。请注意,我还没有将分类变量转换成虚拟变量,这是清单 3-23 中给出的下一步。
# Step 3 One-hot encode the 'features_raw' data using pandas.get_dummies()
features = pd.get_dummies(features_raw)
#Checking output
display(features.head(1),diabetics.head(1))
# Print the number of features after one-hot encoding
encoded = list(features.columns)
print("{} total features after one-hot encoding.".format(len(encoded)))
# See the encoded feature names
print(encoded)
display(features.head(1),diabetics.head(1))
Age A1cTEST BPSystolic BPDiastolic HeartRateBPM BMI \
0 0.275362 0.756968 0.419591 0.153846 0.028571 0.545713
Gender_Female Gender_Male Type of diabetes_None Type of diabetes_Type 2 \
0 1 0 0 1
FrozenShoulder_No FrozenShoulder_Yes CarpalTunnelSynd_No \
0 1 0 0
CarpalTunnelSynd_Yes DupuytrensCont_No DupuytrensCont_YEs \
0 1 0 0
DupuytrensCont_Yes
0 1
Diabetes status
0 1
encoding.".format(len(encoded)))
17 total features after one-hot encoding.
print(encoded)
['Age', 'A1cTEST', 'BPSystolic', 'BPDiastolic', 'HeartRateBPM', 'BMI', 'Gender_Female', 'Gender_Male', 'Type of diabetes_None', 'Type of diabetes_Type 2', 'FrozenShoulder_No', 'FrozenShoulder_Yes', 'CarpalTunnelSynd_No', 'CarpalTunnelSynd_Yes', 'DupuytrensCont_No', 'DupuytrensCont_YEs', 'DupuytrensCont_Yes']
Listing 3-23Step 3: Dummy variables
从图 3-3 我们可以看到热编码的代码。我已经使用了熊猫库中的 get_dummies()函数将原始特征转换成最终的基于虚拟的特征。然后,您可以看到 get_dummies 函数如何自动创建虚拟变量的输出;例如,它创建了一个性别为女性的和一个性别为男性的。完成后,我们查看总共有多少个特性被热编码,发现共有 17 个。最后,打印编码后,我们看一下数据集中的所有列。下一步和第四步也是最后一步是洗牌和分割数据。在清单 3-24 中,我们可以看到生成第一次洗牌和拆分,然后是训练和测试拆分的代码。
#Step 4 Shuffle & Split Final Dataset
# Import train_test_split
from sklearn.cross_validation import train_test_split
from sklearn.utils import shuffle
# Shuffle and split the data into training and testing subsets
features=shuffle(features, random_state=0)
diabetics=shuffle(diabetics, random_state=0)
# Split the 'features' and 'income' data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(features, diabetics, test_size = 0.2, random_state = 0)
print("Training set has {} samples.".format(X_train.shape[0]))
print("Testing set has {} samples.".format(X_test.shape[0]))
Training set has 531 samples.
Testing set has 133 samples.
Listing 3-24Step 4 of Data Preparation
清单 3-24 显示了代码和结果,首先随机改组特性和目标变量,然后将其分成训练和测试数据集。我们可以看到,为训练集创建了 531 个,为测试集创建了 133 个,总共 664 个。至此,我们的数据准备步骤就完成了。我们现在进入机器学习生命周期的模型构建验证和实现阶段。在代码清单 3-25 中,我现在向你展示如何使用 7 种分类算法来构建一个模型。
#Loading model Libraries
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
# prepare models
#Using seed to maintain reproducability and consistent results
seed = 7
models = []
models.append(('LR', LogisticRegression()))
models.append(('LDA', LinearDiscriminantAnalysis()))
models.append(('KNN', KNeighborsClassifier()))
models.append(('CART', DecisionTreeClassifier()))
models.append(('NB', GaussianNB()))
models.append(('SVM', SVC()))
models.append(('RFC', RandomForestClassifier()))
Listing 3-25Model Building Initializing the Classifier Algorithms
清单 3-25 显示了分类器建模初始化的算法。我已经初始化了七个公共类。我将使用逻辑回归、决策树分类器、k 近邻分类器、线性判别分析原因、朴素贝叶斯分类器、SVC 和随机森林分类器。在清单 3-26 中,你可以看到我已经从 Python 库 SKlearn 加载了这些算法,然后我通过逐个初始化它们来准备这些模型。现在,下一步是为所有模型的字典运行一个循环,运行 kfold 交叉验证,然后将结果加载到结果数据字典中,并显示每个算法或分类器的平均值和标准偏差。接下来,我以图形的形式展示了每种算法的算法比较结果。这是使用 matplot 库显示的。
表 3-3
分类器算法准确性
|分类器算法
|
准确
|
神学博士。
|
| — | — | — |
| 实验室反应堆 | One | Zero |
| 皱胃向左移 | One | Zero |
| 近邻算法 | One | Zero |
| 手推车 | Zero point nine nine eight | Zero point zero zero six |
| 铌 | Zero point nine nine eight | Zero point zero zero six |
| 支撑向量机 | One | Zero |
| 请求评论 | Zero point nine nine eight | Zero point zero zero six |
# evaluate each model in turn
results = []
names = []
scoring = 'accuracy'
import warnings
warnings.filterwarnings("ignore")
for name, model in models:
kfold = model_selection.KFold(n_splits=10, random_state=seed)
cv_results = model_selection.cross_val_score(model, X_train, y_train, cv=kfold, scoring=scoring)
results.append(cv_results)
names.append(name)
msg = "%s: %f (%f)" % (name, cv_results.mean(), cv_results.std())
print(msg)
Listing 3-26. Model Evaluation
在表 3-3 中,我们可以从“精确度”一栏中查看分类器算法的精确度,我们可以看到,对于朴素贝叶斯和随机森林分类器,与精确度分数小于 1 的其他算法相比,有三种算法表现不佳。至此,我结束了关于如何在医疗保健中实现机器学习的章节。我曾尝试收集一个与医疗保健电子病历相关的数据集,在我看来,这在医疗保健领域非常常见。我敢肯定,当你试图实现代码及其结果时,读者会发现本章中的完整应用程序非常有用。您还可以使用 AUC 值或 RoC 指标对算法进行比较,这项任务我留给读者来计算和验证。您可以从以下网址了解有关 Scikit learn libraries auc metrics 的更多信息:sklearn.metrics.auc(x,y,reorder=False [8 ])。您也可以从官方 Scikit learn library 网址 [9 ]查看计算 AUC 和 RoC 评分指标的快速方法。
尾注
-
ShijunWangRonald M . Summe,医学图像分析,第 16 卷,第 5 期,2012 年 7 月,第 933-951 页
https://www.sciencedirect.com/science/article/pii/S1361841512000333 -
杜普伊特挛缩症,由梅奥诊所工作人员,
https://www.mayoclinic.org/diseases-conditions/dupuytrens-contracture/symptoms-causes/syc-20371943 -
为什么基于树的模型对异常值具有鲁棒性?
https://www.quora.com/Why-are-tree-based-models-robust-to-outliers -
www . dummies . com/education/math/statistics/how-to-interpret-a-correlation-coefficient-r/ -
Scikit 了解 Auc 指标:
http://scikit-learn.org/stable/modules/generated/sklearn.metrics.auc.html -
Scikit 学库 RoC 和 AUC 评分:
http://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html
四、医疗保健人工智能案例研究
声明:本书中的案例研究来自现实生活中的组织。已采取措施确保组织的名称及其员工的姓名被更改,并且与我的客户没有任何相似之处。熟悉医疗保健行业的读者肯定会发现这些情况非常实用和有见地。
在我们开始看案例研究之前,让我们先看看案例研究方法及其优势。有人可能会说,案例研究方法主要用于 MBA 项目,尤其是这种方法的发源地哈佛商学院[ https://www.hbs.edu/mba/blog/post/3-benefits-of-the-case-method ]。在这里,我们将讨论使用 Python 的机器学习应用程序,以及如何将这种方法用于涉及编程代码的解决方案。在我回答这个具体问题之前,让我们先来看看案例研究方法今天带来的三个优势,以及我们在商业环境中通过使用案例研究获得的其他好处。
我们从案例研究方法中得到的第一个好处是,为案例研究提供解决方案的人不仅要阅读案例和案例研究提出的问题,还要对手头的业务问题做一些背景工作,供问题解决者用来解决问题。在案例研究解决方案完成后,这些信息会留在当事人那里,并以非正式的方式继续学习。没有必要为回答案例研究而填充任何网状课程,因为它们是独特的业务情况,并且不一定有支持其解决方案的理论。
使用案例研究方法的第二个好处是,在给出案例研究业务问题的解决方案时,人们应该对案例问题提出自己的独立观点。这是将机器学习和 Python 代码应用于业务情况的实践,然后当你仔细观察它并试图通过编写解决特定业务问题的代码来为它们提供解决方案做准备。值得注意的是,在案例研究方法中,没有绝对的对错,因为一个特定的业务问题可以通过多种方式解决。这里的实践是尽可能多地提出商业问题的解决方案,并在给定的情况下探索最有价值的方案。因此,使用案例研究方法解决问题的第三个优势是,它在商业环境中很重要,并且是应用机器学习工程师最受欢迎的技能。
我从现实生活的例子中仔细选择了这些案例研究,我很确定读者会发现它们很有用。我建议你在回答每个案例研究中的问题之前至少阅读两遍案例研究。在我看来,你应该做的是,先把案例研究文中给出的业务情况读一遍,理解一遍,然后看每一个问题再回到案例研究文中,把情况再理解一遍。一旦你看了关于每个问题的案例研究,你应该开始在你的头脑中制定解决方案,如果你在医疗保健行业面临这种情况,你会怎么做。回想一下我在第三章给大家展示的机器学习应用的过程。在制定解决方案时,注意不要错过任何步骤。
一旦您有了一个您认为在给定的业务情况下最合适的解决方案的草图,那么您应该继续查看所提议的解决方案以及给定案例研究的代码。请记住,在案例研究法中,不同的人可以提出不同的解决方案,解决方案没有对错之分。然而,它遵循的标准是,解决方案应该满足业务问题的所有需求,并且应该是业务可以接受的。在本书给出的案例研究解决方案中,我给出了企业可以接受的解决方案,因此读者可以将其作为基准来判断他们为案例研究提出的解决方案。目标是首先创建您自己的解决方案,而不看我在本书中给出的解决方案,以使您开始独立思考,并开始在医疗保健业务场景中应用机器学习。
案例研究 1:实验室协调员问题
周一早上,Deshmukh 博士坐在办公室里,他面前的笔记本电脑屏幕上显示着一份财务部门的报告,内容是关于他的医疗保健组织 DIRECTPyth 诊断中心全球连锁的财务状况,该组织由全球 250 多个诊断中心组成。
DIRECTPyth 的核心业务是糖尿病诊断中心。DIRECTPyth 诊断中心的突然增长发生在过去的 5 年里。DIRECTPyth 最初是一家本土诊断公司,在印度只有四个中心。在过去 10 年的运营中,它将其诊断中心扩展到了印度以及东南亚、中东和加拿大的所有主要城市。大多数海外中心是在过去 5 年中出现的,因为诊断公司看到人们对糖尿病诊断的需求迅速增长。
世界卫生组织关于糖尿病的报告( http://www.who.int/diabetes/global-report/en/ )显示,糖尿病现在已经成为世界范围内的流行病。2012 年,糖尿病导致 150 万人因心脏病发作、中风、失明、肾衰竭和下肢截肢而死亡。世界各国政府已经通过在媒体上运行关于糖尿病流行的信息程序来传播意识。德里·福特还强调,自 1980 年以来,二型糖尿病患者的数量一直在增加,到那时已经翻了两番。为了控制这种流行病,世界各国政府在过去 5 年中加强了预防和治疗糖尿病的计划。DIRECTPyth 糖尿病诊断医疗保健链正处于这场流行病的中间,为任何人提供测试,以诊断他们是否患有糖尿病。
德什穆克博士正在看的报告指出,在过去的两年里,经济损失高达 2 亿美元。公司的财务状况如表 4-1 所示。
表 4-1
两年期财务概要报告
|财务概要
(百万美元)
|
2015-2016 财年
|
2016-2017 财年
|
| — | — | — |
| 诊断收入 | Nine hundred and thirty | One thousand two hundred and twenty-one |
| 运营成本 | One thousand and thirty-one | One thousand three hundred and fifty-four |
| 诊断中心的平均运营天数 | One hundred and eighteen | One hundred and six |
| 非经营损失 | One hundred and one | One hundred and thirty-three |
我来简单解释一下表 4-1 。给出了两个财政年度的财务数据:2015-2016 年和 2016-2017 年。第 2 列和第 3 列中给出的状态是财务部门提供的诊断收入,您可以看到 DIRECTPyth 组织的收入每年都在增长。第一年和第二年的运营成本都高于诊断收入。最后一行给出了非手术造成的损失,这是从诊断收入中直接减去手术成本。这两年的总损失为 2 . 34 亿美元。第三行提供了全世界所有 DIRECTPyth 诊断中心的平均运行天数。DIRECTPyth 的平均运行天数为 118 天,远远低于 DIRECTPyth 内部衡量其性能的基准数 200。我们还可以看到,在 2016 年和 2017 年,诊断中心的平均运营天数下降到了 106 天。非操作性损失也从第一年的 1.01 亿美元上升到第二年的 1.33 亿美元。
为了让 DIRECTPyth 在市场上保持竞争力,它需要降低运营成本和非运营损失,现在就需要采取切实措施。
该报告清楚地表明了由于人力资源的限制而造成的损失。德什穆克博士要求与 DIRECTPyth 的人力资源经理进行一次晨会。目的是讨论经济损失并找出这个问题的最主要原因。人力资源经理是 Abbey 女士,她将向 Deshmukh 博士介绍直接造成财务损失的原因以及今后如何防止这些损失。然后,德什穆克博士起床,为上午 10 点的会议做好了充分准备。艾比女士和她的工作人员一起到达会场。问候结束后,她开始介绍两年的财务概要。她向德什穆克博士指出,手术费用在几年间上涨了 131%。这一损失也是同样的百分比,因为它是从业务成本中得出的。她解释说,诊断中心的平均运营天数是根据诊断中心在全年任何给定工作日保持开放的天数计算的。DIRECTPyth 的目标平均运营天数是 200 天。她展示了表 4-2 中给出的平均运行诊断中心数据的细分。
表 4-2
平均运营天数细分(AOD)数据
|平均运营天数
|
达到 AOD 基准的中心数量
|
未达到 AOD 基准的中心数量
|
| — | — | — |
| 印度 | Thirty-two | Two hundred and thirty-four |
| 海外的 | Thirteen | Ninety-eight |
| 加固的 | Forty-five | Three hundred and thirty-two |
| %年龄 | Eleven point nine | Eighty-eight |
平均运行天数的细分数据显示,在全球范围内,DIRECTPyth 的诊断中心达到 200 天基准的百分比仅为 11.9%,未达到 AOD 基准的中心百分比为 88%。这显示了 DIRECTPyth 问题的严重性和范围。它还表明,由于这些中心没有达到 AOD 基准,收入损失严重。为了进一步深入研究这个问题,Abbey 女士展示了与 DIRECTPyth 组织的实验室诊断设施的人力资源相关的数据。该数据在表 4-3 中给出。
表 4-3
DIRECTPyth 实验室的人力资源数据
|DIRECTPyth 实验室的人力资源
|
实验室协调员
|
实验室技术员
|
实验室正在等待
|
| — | — | — | — |
| 平均当前天数 | Eighty-eight | Ninety-seven | One hundred and ninety-four |
| 平均缺勤天数 | Twenty-six | Fifteen | eight |
| 损耗率(%) | 12% | 9% | 6% |
我们可以从表 4-3 中看到,最高的缺勤发生在实验室协调员和实验室技术员角色。实验室服务员平均缺勤率最高,缺勤率最低。最好的数据来自 DIRECTPyth 实验室的工资系统,记录了实验室每个人力资源的每日出勤情况。目前的总天数被视为 220 个生产工作日的基准值。实验室协调员的角色是与走进诊断实验室的客户进行互动,带他们了解实验室中可用的各种诊断选项,然后帮助他们找到最适合其糖尿病状况的测试。实验室协调员检查患者是否已经在诊断中心注册,然后调出计算机记录并请求新的测试。DIRECTPyth 的技术人员实际上是为排队等候的病人进行实验室测试的人。实验室服务员是从实验室技术人员那里获取特定患者的数据,将数据输入计算机,然后生成报告提交给患者的人。这三个关键职位对于 DIRECTPyth 诊断中心的业务运营非常重要。Abbey 女士在会上表示,实验室协调员和实验室技术员的高缺勤率导致了 DIRECTPyth 的收入损失。本组织迫切需要找到如何提高生产率和减少这一角色的缺勤率。我们还可以看到,实验室协调员的流失率最高(12%),其次是实验室技术员(9%)。最低的流失率(6%)表明 DIRECTPyth 需要找到一种方法来降低实验室协调员的缺勤率和流失率。最重要的是实验室协调员的角色,那里的缺勤率和自然减员率非常高。人力资源部应该想办法降低缺勤率和离职率。在过去的三年里,他们尝试了五种方法,但在寻找解决方案方面收效甚微。因此,很明显,如果 DIRECTPyth 想要提高其盈利能力并减少损失,它需要紧急解决实验室协调员角色的缺勤和流失问题。
需要立即实现的解决方案应该是使用技术来模拟实验室协调员的角色。DIRECTPyth 获得了外国投资者的资助,能够投资于技术,以提高效率,从而增加收入。你需要使用基于 Python 的机器学习来解决和回答本案例研究中给出的问题。
-
你认为 DIRECTPyth 诊断中心亏损的原因是什么?
-
我们正在处理什么样的人类问题,你认为如何解决这些问题?
-
你认为技术能帮助解决你在问题 2 中发现的问题吗?
-
基于 Python 的机器学习解决方案能够解决 DIRECTPyth 的这些问题吗?
-
你提议的基于 Python 的机器学习解决方案是什么?请为您的解决方案使用 Python 3.x 源代码。
-
你对你的解决方案给出了什么样的商业理由,你认为它会被 DIRECTPyth 的商业领袖所接受?
我建议你先试着独立回答这些问题,然后看看这本书给出的解决方案。请注意,我给出的解决方案是这个业务场景中可以给出的众多解决方案之一。最终决定您的解决方案是否好,是否能够解决他们的业务问题的是业务所有者。
亲提示
在应用机器学习中,我们机器学习顾问与一个组织的业务领导密切合作,以确定什么对他们有效。永远记得和他们一起讨论,提出哪怕是一个不完整的小计划,并在将其转化为成熟的解决方案之前对其进行审查。这样可以节省你很多浪费的会议和精力。
现在让我试着用我自己的方式回答这些问题,给出我提出的解决方案,该方案已被组织接受。
- 你认为 DIRECTPyth 诊断中心亏损的原因是什么?
DIRECTPyth 诊断中心损失的原因是高运营损失,大约 88%的诊断中心没有达到平均运营基准。造成这种情况的真正原因是组织中实验室协调员的高缺勤率和损耗率。实验室协调员的缺勤率非常高,为 26%,自然减员率为 12%,而实验室技术员的缺勤率为 15%,自然减员率为 9%。人力资源部想出了五种不同的方法来阻止自然减员和旷工,但收效甚微。
- 我们正在处理什么样的人类问题,你认为如何解决这些问题?
我认为我们面对的是士气低落的员工,这就是我们看到高缺勤率和离职率的原因。
- 你认为技术能帮助解决你在问题 2 中发现的问题吗?
在我看来,在人类无法以业务所需的最佳水平执行的领域使用技术是引入自动化、机器学习和人工智能的合适场景。技术的好处在于它可以重复做任何给定的任务,而不会感到无聊或疲劳。它还可以使用数据智能,并经过训练非常容易地执行专家任务。在 DIRECTPyth 诊断中心的情况下,我们可以使用技术来取代实验室协调员的任务,将自动化实验室机器放在它的前提下,从而让客户选择他们想要执行的实验室测试。自动化实验室机器可以运行基于 Python 的机器学习程序,帮助客户选择适合其场景的最佳诊断测试。
- 基于 Python 的机器学习解决方案能够解决 DIRECTPyth 的这些问题吗?
是的,基于 Python 的机器学习系统可用于自动化实验室中的整个过程,从客户进来并选择诊断包以生成实验室测试,到生成报告并为客户提供有意义的解释的下一阶段。基于 Python 的机器学习系统可以连接到任何现代自动化实验室测试机器,以从中获得输出。
- 你提议的基于 Python 的机器学习解决方案是什么?请为您的解决方案使用 Python 3.x 源代码。
在本书中,我将给出一个简短的解决方案;但是,它将模拟我在客户的生产环境中提供给客户的真实解决方案。读者可以在现实世界中类似的情况下使用自己的想法来构建这个解决方案。给读者一个警告:这是我用来创建聊天机器人的一个非常简单的方法;然而,它并不限制用户通过使用本书中给出的代码来扩展其功能。现实生活中的聊天机器人比我在这里给出的代码更复杂,因为它涉及到使用 nltk . corpora nltk 知识库的情感分析。它还将使用词汇化自然语言处理技术,为 Python 程序的用户提供最佳响应。这个解决方案是并且应该被认为是一个模板代码,而不是最终的解决方案,因为不可能在一本书里写一个完整的生产聊天机器人的源代码,因为它会运行成数百万行代码。我将带您浏览代码,让您了解为什么要编写代码的每个部分,包括它的意图和功能,以及如何在生产中应用它的一些技巧。
- 业务需求:该解决方案的业务需求是模拟实验室协调员的工作,并通过聊天界面与用户进行交互。我将向您展示一些适用于此案例研究场景的用例。
亲提示
甚至在你开始编码之前,将你的工作划分成简短的用例,并得到系统实际用户的认可,因为你将为他们开发。如果您跳过这一步,很可能您将开发一个用户可能拒绝的产品,因为您可能误解了一些需求。
-
用例:作为一个用于糖尿病诊断的自动聊天机器人的用户,我应该能够知道我过去的测试数据记录,以便我检查我的历史。
-
用例:作为一个用于糖尿病诊断的自动聊天机器人的用户,我应该能够知道该中心进行的测试类型及其目的,以便我的医生和我可以决定进行测试。
-
用例:作为一个用于糖尿病诊断的自动聊天机器人的用户,我应该能够得到我的测试结果,这样我就可以得到一份报告。
-
用例:作为一个用于糖尿病诊断的自动聊天机器人的用户,我应该能够得到关于我的测试结果的建议,以便我能够知道未来的行动过程。
对于 DIRECTPyth 诊断中心,有比这里给出的更多的可用用例。然而,为了简化流程,我们将只考虑我们的解决方案的这四个用例。
现在我们来看看图 4-1 中的流程图,它应用了其他聊天机器人在与客户交互时将遵循的流程。请记住,我对这个解决方案使用了极简的方法,因为它不是一个生产代码;这是给你一个想法,如何应用机器学习领域的模拟实验室协调员在医疗保健部分。

图 4-1
客户和实验室协调员聊天机器人之间的交互过程
在图 4-1 中,我们可以看到,当客户走进并与实验室协调员中的聊天机器人会面时,该流程就开始了,因此在该流程中没有人工交互或人工监督。这个售货亭有传感器,可以检测附近是否有人,并向顾客发出问候。在该过程的下一部分,如果是现有客户,聊天机器人会要求客户提供会员 ID。现在,如果在数据库中找到了客户提供的会员 id,实验室协调员 chatbot 必须根据提供的输入做出决定;然后,它向客户显示最后的测试记录结果。如果它不是现有客户,那么聊天机器人会显示糖尿病测试——许多列出了实验室可用的整套测试。一旦客户从列表中选择了测试,实验室协调员将进行测试,然后生成报告。在我们的例子中,在 Python 程序中。机器人要求客户坐在自动测试机旁边进行糖尿病诊断的部分已经被我标记了,我会在标记发生的代码中指明这一点。我这样做的原因是因为 Python 程序会为报告生成随机结果;然而,在生产环境中,该数据将来自承担测试的实验室技术人员机器。在现实世界中,通过内部医疗记录与医生共享报告的过程中会有其他步骤;然而,为了保持简单,我在这个解决方案中跳过了所有这些过程。
现在我们已经定义了聊天机器人的流程图,我们可以进入 Python 代码来实现简单的聊天机器人了。
小费
在您的机器上运行这个例子之前,加载 wordnet lemmatizer 和 punkt 包。
Install using the following commands:
import nltk
nltk.download('wordnet')
[nltk_data] Downloading package wordnet to
[nltk_data] C:\Users\PMAUTHOR\AppData\Roaming\nltk_data...
[nltk_data] Unzipping corpora\wordnet.zip.
Out[4]: True
import nltk
nltk.download('punkt')
清单 4-1 展示了我们聊天机器人的初始化代码,其中第一行声明我们的代码遵循 UTF 8 编码。在这之后我们有下一组语句,它们导入 GUI 库 tkinter 及其组件,如潦草的文本图像和图像 TK,以及时间包(用于配置睡眠功能)。我还引入了 random 函数,因为它可以帮助我们的聊天机器人从我们的答案中随机选择,这一点我们稍后会讲到。
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 24 10:20:18 2018
@author: PUNEETMATHUR
"""
#Loading tkinter libraries which will be used in the UI of chatbots
import tkinter
from tkinter import *
from tkinter.scrolledtext import *
from tkinter import ttk
import time
from PIL import ImageTk, Image
import tkinter
#Loading random for random choices in our chat program
import random
Listing 4-1Loading chatbot User Interface
清单 4-1 显示了我们聊天机器人的初始代码。在清单 4-2 中,我们看到了使用 tkinter 包实现闪屏的 Python 代码。为了做到这一点,我们首先创建一个名为 tkinter window TK 对象的 Splash 的新对象,然后我给它一个欢迎用户进入 Splash 屏幕的标题。然后,我使用飞溅的对象给高度和重量使用几何函数。我正在创建一个 1000×100 像素高和重的飞溅窗口,所以我在几何函数的参数中使用了 1000×100。接下来,我用参数 background 等于绿色的配置函数给 Splash 窗口设置了一个背景色。为了在程序加载时显示要求用户等待的文本,我使用了中央库中 label 对象的 label 小部件,名为 w,在初始化 w 时,我将它链接到 Splash 对象,这是将要创建标签的窗口。因此,第一个参数是标签与闪屏窗口的连接位置。接下来的第二个参数是你输入你想要标签显示的文本,我已经输入了一个字符串。我输入的第三个参数是字体,为了显示文本,我使用了 26 号 Helvetica 字体。下一个参数是 FG,它代表窗口的前景色,前景色是标签的文本和它将被显示的颜色。在我的例子中,我使用了白色。在下一个参数中,我使用了 BG,它代表背景颜色,我给了它一个绿色的值。在下一条语句中,我修改了标签,以便它可以显示在启动窗口上。完成后,我使用 Splash 的 update 方法,以便标签在 Windows 屏幕上更新。一旦屏幕出现,我们希望它在用户面前出现一段时间,您可以通过让程序休眠 X 秒来指定时间。我在下一个代码语句中使用了 time to sleep,参数为 6,表示程序将休眠 6 秒。您可以尝试这样做,看看什么适合您的闪屏,您可以相应地修改秒数。在闪屏显示 6 秒钟后,我希望它消失,因此我会识别该屏幕,然后在接下来的两个语句中销毁它。
#Splash Screen
splash = tkinter.Tk()
splash.title("Welcome to Applications of Machine Learning in Healthcare, Retail & Finance")
splash.geometry("1000x100")
splash.configure(background='green')
w = Label(splash, text="DIRECTPyth Diabetes Diagnostics Chabot by Puneet Mathur\nLoading...",font=("Helvetica", 26),fg="white",bg="green")
w.pack()
splash.update()
time.sleep(6)
splash.deiconify()
splash.destroy()
Listing 4-2Splash Screen
现在是时候加载我们的聊天机器人应用程序的主聊天窗口了,因此在清单 4-3 中,您可以看到加载聊天窗口所需的代码。在清单 4-3 的第一条语句中,我在 tkinter 包中创建了一个 TK 类的窗口对象。然后,我使用滚动条类中的实例化 nS 对象将滚动条添加到窗口中,并使用 window 实例化滚动条类,使其与 window 对象相关联。如果你有滚动条而没有文本,那么它将变得无用,所以在下一个语句中,我用窗口对象实例化了一个文本框。这个文本框被称为聊天消息,我们将在以后的程序中广泛使用它,因为用户的所有输入和输出都将通过这个文本框。在下一个语句中,我使用 focus set 对象来设置文本框上的焦点。在下一个语句中,我打包了滚动条,并使用第一个参数将滚动条固定在窗口的右侧,并使用 y 轴作为滚动条。在下一条语句中,我将文本框 chat MSG 移动到窗口的顶部,并在 y 轴上填充它。在下一个语句中,我使用滚动条的 config 方法来配置从聊天消息评论中获取 nd。我还将 chatmsg 文本框与滚动条相链接,以设置–s.config 方法和 yscrollcommand 函数,然后与 s . config 的值相链接。现在,下一步是通过创建 stringware 类的对象来为输入用户和输入字段创建一个条目,然后通过实例化 entry 类并将其附加到第一个参数中的窗口以及第二个参数中的文本创建的 stringware 对象来将其与输入字段相链接。如果您不这样做,那么您的文本框将无法获取文本和回复文本。在下一条语句中,我将输入字段附加到底部,并沿 x 轴填充它。这是用户将要输入所有数据并与我们的聊天机器人进行交互的地方。在下一条语句中,我创建了一个可变的下划线文本,欢迎用户访问诊断中心。请记住,这将作为一个自动化程序在 kiosk 中运行,因此在客户到达时,kiosk 上会连接传感器,DIRECTPyth 将装配该程序。然而,在这个代码实现中,所有这些都被删除了,因为不可能在这样一本简短的书中展示完整的产品代码。在下一个语句中,我们使用 chat MSG,这是我们的文本框,并插入文本的值,这是我们的变量。在下一条语句中,我们将焦点转移到文本框。
#Initializing tkinter library for UI window show up
window = tkinter.Tk()
s = tkinter.Scrollbar(window)
chatmsg = tkinter.Text(window)
chatmsg.focus_set()
s.pack(side=tkinter.RIGHT, fill=tkinter.Y)
chatmsg.pack(side=tkinter.TOP, fill=tkinter.Y)
s.config(command=chatmsg.yview)
chatmsg.config(yscrollcommand=s.set)
input_user = StringVar()
input_field = Entry(window, text=input_user)
input_field.pack(side=tkinter.BOTTOM, fill=tkinter.X)
bot_text="Welcome to DIRECTPythPyth Diagnostic Center\n"
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
bot_text = "Press enter to continue "
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
chatmsg.focus()
Listing 4-3Creating the Chatbots Window and Welcoming the User
在现实世界中,使用 NLP 的机器学习的生产级应用程序中,您需要首先花时间与业务人员在一起,并开发一个语料库,它只不过是业务词典或组织日常生活中使用的术语。由于这个实现很短,我只给你一个关于如何在清单 4-4 中构建语料库的想法。您将看到,我已经使用 Python 变量类型的列表创建了我们的诊断语料库。第一张单子很棒;这只不过是我们的聊天机器人在新用户到来时给他们的各种问候的列表。下一个列表是添加确认,是,耶,耶,哟。你可以添加更多的确认,这个列表可能会很大,这样你才能理解用户想说什么。该列表的重要部分是该列表正在为我们的聊天机器人学习,我们提供了一些现成的答案以及客户可以在该语料库中提出的问题。在下一个列表中,我使用成员 ID,我已经使用了五个成员 ID,因为这只是一个原型应用程序。然而,在现实世界中,您可能有数百甚至数千个成员 id,这些数据可能来自一些平面文件或数据库,比如 mongo DB。在下一个列表中,我使用 customer 来捕捉这样的反应,并帮助我们的机器人识别它们,这是他们说 hello,hi 或 hey 的输入。在下一个列表答案中,我只给出了两个陈述:第一个是肯定的陈述,第二个是否定的陈述。我们将在后面查看我们的程序,看看这在实践中是如何使用的。在接下来的列表中,我使用了一些简单的问题及其回答;然而,它们可能没有被使用过。但是如果聊天机器人知道问题和回答,它会给你一个如何反应的想法。在下一个列表中,我已经给出了测试,它只是当用户输入他们的成员 ID 时弹出的菜单。我们有五个测试可以进行;然而,请记住,在诊断中心的真实业务中,他们有数百项测试,此外,他们还根据不同的客户要求打包这些测试,例如糖尿病患者概况测试和心脏状况测试,这只是一个例子。在下一组测试响应中,我使用了用户可以在之前的测试列表中输入的选项。例如,在测试响应中,一个对应于测试列表的第一项,HB A1c 测试,等等。
#Diagnostics Corpus for the chatbots
greet=['Hello welcome to DIRECTPythPyth','Hi welcome to DIRECTPythPyth','Hey welcome to DIRECTPythPyth','Good day to you welcome to DIRECTPythPyth']
confirm=['yes','yay','yeah','yo']
memberid=['12345','12346','12347','12348','12349']
customer = ['hello','hi','hey']
answer = ['I understand you feel happy but please stay to the point and select one of the options',"I sympathize with you, However please do not deviate from the topic"]
greetings = ['hola Welcome to DIRECTPythPyth again', 'hello Welcome to DIRECTPythPyth again', 'hi Welcome to DIRECTPythPyth again', 'Hi Welcome to DIRECTPythPyth again', 'hey! Welcome to DIRECTPythPyth again', 'hey Welcome to DIRECTPythPyth again']
question = ['how are you?', 'how are you doing?']
responses = ['Okay', "I'm fine"]
another = "do you want another test?"
tests=['Type 1 for hbA1c test', "Type 2 for Blood Viscosity test","Type 3 for Heart rate test","Type 4 for Blood Oxygen test","Type 5 for Blood Pressure"]
testresponse= ['1','2','3','4','5','6']
Listing 4-4The Diagnostics Corpus
现在我们从聊天机器人的实际程序开始,定义它的程序结构。在清单 4-5 中,我们可以看到这段代码是我们聊天机器人的核心。在代码的第一部分,我初始化了一些全局变量。第一个是第一开关,我给它赋值为 1。这用于确定聊天机器人是否是第一次运行。接下来,我初始化一个新的 ID。对于第一次到达诊断中心的人来说,这只是一个新的会员 ID。接下来,我用值 0 初始化了成员 ID (Mem ID)变量。在代码的下一部分,我使用了一个名为 chat 的函数,它有一个 event 参数,每当一个带电的事件发生时,它就会被触发。在这个函数中,我导入了时间和随机包,并声明了全局成员 id 变量或条件变量以及第一个开关变量。在下一个语句中,有一个 if 条件,我检查第一个 switch 是否等于 1,如果它等于 1,那么它通过从网格列表中选择一个值来对随机选择进行网格划分,我们在前面已经看到过。
它将 bot 文本变量中的值插入到 chat MSG 文本框中,因此当 chatbot 第一次运行时,用户能够看到一个问候语。然后它给出一个声明,如果你是 DIRECTPyth 的现有成员,那么你可以输入你的成员 ID;否则,根据用户输入,如果您不是成员,请输入值“否”。第一个开关变量现在的值为 2,如果用户输入一个值,它将再次触发并进入下一个 if 语句,其中第一个开关不等于 1。因此,这意味着这个特定的 if 条件将只在用户第一次问候之后运行,并且用户输入的这个值是通过输入字段接收的。我们在这里使用 lower 函数,这样我们就不必处理大写和小写,我们把值输入到下划线 get 变量中。检查该值以查看用户输入的成员 ID 是否在成员 ID 列表中找到,如果您还记得,我们有五个 ID,如果找到了,则满足 if 条件,内存函数存储用户在输入下划线 get 变量中输入的任何内容。然后填充机器人文本,感谢用户成为忠诚的成员,并向用户显示一个菜单,告诉用户最后一个退出程序的选项是什么类型的测试。
如果用户输入 no,这意味着它是一个新用户,并且他们没有成员 ID,则生成一个新的成员 ID。请记住,因为我正在创建一个原型程序,所以我不会详细讨论存储这个新 ID 和自动创建这个 ID 的细节。然而,在现实世界中,您将把这个值存储在一个平面文件或一个 mongo DB 数据库中,然后增加这个值以获得新的用户 ID。如果用户在下一个 if 语句中输入 1 到 6 之间的有效值,我会检查用户输入的 get 语句是否在测试响应列表中。如果您还记得的话,测试响应列表有从 1 到 6 的数字,所以这个 if 语句只有在测试响应被满足时才会被触发。一旦收到有效的响应,机器人模拟器会给用户一条消息,让他们将手指放在信息亭的手指面板上进行测试。它等待 10 秒,我在这里放了一个延迟计数器。
然而,在现实世界中,会有一个传感器来检测用户何时将手指放在手指面板上,并自动开始读取数据。在我们的例子中,我使用了一个 for 循环来模拟 10 秒,并使用聊天消息的时间数据表将延迟计数器休眠 1 秒。我将这些值插入聊天机器人,向用户显示我正在读取它们的值。在 for 循环的 10 个步骤完成后,机器人会说,“请等待,正在生成您的报告”,然后它会休眠 2 秒钟。然后,基于用户给出的测试输入,它为每个测试生成随机数。例如,让我向您介绍一下 if 语句,其中用户输入的值为 1,这意味着根据菜单,用户想要进行 HB A1c 测试。在这种情况下,机器人会生成一个介于 4 和 10 之间的随机数,这是 A1c 测试的有效值,并且会类似地向用户显示结果。在它完成之后,我向你展示我们如何给我们的聊天机器人添加智能,它正在模拟一个实验室协调员,而实验室协调员永远不会对报告的结果发表意见。然而,我们增加了第一次测试 HP A1c 的值,我已经向您展示了它如何根据结果智能地告诉用户他们是否患有糖尿病、糖尿病前期或没有糖尿病。在我们的例子中,它在 if 条件下寻找一个值,变量 HB A1c 在 4 到 5.6 之间。如果这个条件被满足,那么它说你没有糖尿病。它再次检查 HB A1c 变量,如果值在 5.7 和 6.4 之间,它说你是糖尿病前期。如果 HB A1c 变量值大于或等于 6.5,则患者被诊断为糖尿病。这种智能还可以添加到其他测试中,如血液粘度测试(范围从 30 到 44 MB)、心率(范围从 60 到 100 次/分钟)、血氧(范围从 95 到 100)以及血压收缩压和舒张压。您可以自己在这些条件下添加这种智能,我将让您来修改代码并更智能地使用它。
#Global variable to check first time greeting
firstswitch=1
newid="12310"
memid=0
def chat(event):
import time
import random
global memid
condition=""
#Greet for first time
global firstswitch
if (firstswitch==1):
bot_text = random.choice(greet)
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
bot_text = "If you are an existing Member of DIRECTPythPyth please enter your membershipid: or enter no if you are not a member"
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
firstswitch=2
if (firstswitch!=1):
input_get = input_field.get().lower()
if any(srchstr in input_get for srchstr in memberid):
memid=input_get
bot_text = "Thank you for being a loyal member of DIRECTPythPyth\n Please choose a test from following menu to continue\nType 1 for hbA1c test\nType 2 for Blood Viscosity test\nType 3 for Heart rate test\nType 4 for Blood Oxygen test\nType 5 for Blood pressure test\nType 6 to exit\n\n"
elif (input_get=="no"):
memid=newid
bot_text = "Your new Memberid is: " + newid + " Please remember this for future reference.\n Please choose a test from following menu to continue\nType 1 for hbA1c test\nType 2 for Blood Viscosity test\nType 3 for Heart rate test\nType 4 for Blood Oxygen test\nType 5 for Blood pressure test\nType 6 to exit\n\n"
elif any(srchstr in input_get for srchstr in testresponse):
bot_text = "Please place any of your finger on the Finger panel above to conduct the test"
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
delaycounter=0
for delaycounter in range(0,10):
bot_text = str(delaycounter)
time.sleep(1)
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
bot_text = "Please wait generating your report\n"
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
time.sleep(2)
if (input_get=="1"):
hba1c=random.randint(4,10)
bot_text = "MemberID: " + str(memid) + " Your hbA1c test result is: " + str(hba1c)
if(hba1c>=4 and hba1c<=5.6):
condition="You don't have diabetes"
elif(hba1c>=5.7 and hba1c<=6.4):
condition="You are Prediabetic"
elif(hba1c>=6.5):
condition="You are Diabetic"
bot_text=bot_text + " Your condition is: " + condition
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
elif (input_get=="2"):
viscosity=random.randint(20,60)
bot_text = "MemberID: " + str(memid) + " Your Blood Viscosity level test result is: " + str(viscosity)
elif (input_get=="3"):
heartrate=random.randint(40,150)
bot_text = "MemberID: " + str(memid) + " Your Heart rate test result is: " + str(heartrate)
elif (input_get=="4"):
oxygen=random.randint(90,100)
bot_text = "MemberID: " + str(memid) + " Your Blood Oxygen level test result is: " + str(oxygen)
elif (input_get=="5"):
systolic=random.randint(80,200)
diastolic=random.randint(80,110)
bot_text = "MemberID: " + str(memid) + " Your Blood Pressure test result is: Systolic: " + str(systolic) + " Diastolic: " + str(diastolic)
elif (input_get=="6"):
import sys
window.deiconify()
window.destroy()
sys.exit(0)
else:
from nltk.stem import WordNetLemmatizer
import nltk
if((not input_get) or (int(input_get)<=0)):
print("did you just press Enter?") #print some info
else:
lemmatizer = WordNetLemmatizer()
input_get = input_field.get().lower()
lemvalue=lemmatizer.lemmatize(input_get)
whatsentiment=getSentiment(lemvalue)
if (whatsentiment=="pos"):
bot_text = answer[0]
#print("Positive Sentiment")
elif (whatsentiment=="neg"):
bot_text = answer[1]
#print("Negative Sentiment")
chatmsg.insert(INSERT, '%s\n' % lemvalue)
#bot_text = "I did not understand what you said !"
chatmsg.insert(INSERT, 'Bot:%s\n' % bot_text)
#label = Label(window, text=input_get)
input_user.set(“)
#label.pack()
return "break"
Listing 4-5Chatbot Code
在这个聊天机器人中,我用 NLP 展示了如何在这样的应用程序中进行情感分析。但是,请记住,我使用的 NLP 是有限制的,因为我无法编写数百万行代码来模拟现实世界的聊天应用程序。我简单地使用了一个小的训练集作为列表,但是在真实的场景中,您将使用一个文件,该文件可能会有来自客户的反馈,并且会包含积极和消极情绪的分类。让我们浏览一下代码,以便简单地理解我是如何在获取情感函数中进行情感分析的。你可以参考图 4-6 中的代码,我在那里导入了 nltk 库,然后从 nltk 中导入了 tokenize 和 word tokenize 以便进一步分析。在这个例子中,我只使用了三个步骤来执行情感分析;但是,请记住,要进行全面的情感分析,还需要遵循更多的步骤。
在第一步中,我使用训练数据来建立糖尿病语料库,这可能只是客户对响应的积极和消极反馈分类。积极情绪被归类为 POS,消极情绪被归类为 energy。完成这些后,我创建了一个字典,并通过将每个单词转换成小写来标记它。在这之后,我为我们必须组织的每个单词创建一个字典,并通过我们一直在跟踪的训练数据集运行它。完成此操作后,我们已经创建了在训练数据中定位单词的步骤 3,现在我转到步骤 4 来训练分类器,在我们的示例中,是对样本数据进行朴素贝叶斯训练,因此我调用了朴素贝叶斯分类器,并对已定位的世界进行了训练。然后我得到新的数据,这被称为测试数据;例如,这里是“哦,我的上帝”,但是你可以用这个函数的文本变量替换它,以便创建你的测试数据。一旦创建了测试数据,我们需要为字典中标记的每个单词创建特征,这是我们在前面的步骤 3 中创建的。一旦完成,我们现在就可以告诉我们的数据特征是如何被分类的了。有没有被归类为能源或者 POS?该函数返回分类器点分类测试数据特征的值。如果你回到图 4-1 中,我在条件中定义了聊天功能。
在 else 语句的最后一个条件中,我使用了一个 wordnet lemmatizer,并检查了数据用户给出的输入是否不是一个条目。
然后,它使用单词 net lemmatizer,并获取用户以小写形式输入的值。它对值进行了引理。词汇化是将一个较大的单词转换成它的词根的过程。举个例子,cars 有一个词根词 car。在下一个语句中,我使用 get 情感函数并给出值,这是用户给定的 lemmatize 输入,作为回报,我从函数中获得 neg 能量或 POS 负面或正面情感。在下一个条件中,我检查值是否是 POS 则机器人回答 0 的肯定响应回答,或者,如果是否定情绪,则机器人回答否定响应。因此,您已经以非常简单的方式了解了如何实现聊天机器人应用程序并将其用于商业用途。
#Sentiment Analyzer using NLP
def getSentiment(text):
import nltk
from nltk.tokenize import word_tokenize
#nltk.download('punkt')
# Step 1 – Training data building the Diabetes corpus
train = [("Thanks for an excellent report", "pos"),
("Your service is very quick and fast", "pos"),
("I am pleased with your service", "pos"),
("I did not know i was diabetic until you gave me this report", "neg"),
("Service - Little slow, probably because too many people.", "neg"),
("The place is not easy to locate", "neg"),
("The place is very easy to locate", "pos"),
("Not satisfied will take a second opinion", "neg"),
("No human contact everything is so robotic here", "neg"),
("can i talk to a human not convinced with your report", "neg"),
("good results", "pos"),
("good service", "pos"),
("great service", "pos"),
("excellent service", "pos"),
("amazing technology", "pos"),
("fast service and satisfying report", "pos"),
("your report sucks", "neg"),
("this report will cost me a fortune", "neg"),
("I have diabetes", "neg"),
("this report will cost me a fortune", "neg"),
("this report means i have a dreadful disease", "neg"),
("will i need to take new medication", "neg"),
("i need to take my insulin injections regularly", "neg"),
("my lipids are getting worst need to talk to the doctor", "neg"),
("oh my god very bad results", "neg"),
("bad service", "neg"),
("very bad service", "neg"),
("poor service", "neg"),
("very bad service", "neg"),
("slow service", "neg"),
("very slow service", "neg"),
("diabetes got worst is this report accurate", "neg"),
("i dont believe this report", "neg"),
("i dont like this report", "neg"),
("i am in a diabetic hell", "neg"),
]
# Step 2 Tokenize the words to dictionary
dictionary = set(word.lower() for passage in train for word in word_tokenize(passage[0]))
# Step 3 Locate the word in training data
t = [({word: (word in word_tokenize(x[0])) for word in dictionary}, x[1]) for x in train]
# Step 4 – the classifier is trained with sample data
classifier = nltk.NaiveBayesClassifier.train(t)
test_data = "oh my god what is this"
test_data_features = {word.lower(): (word in word_tokenize(test_data.lower())) for word in dictionary}
print (classifier.classify(test_data_features))
return classifier.classify(test_data_features)
#Start the program chat and put in loop
input_field.bind("<Return>", chat)
tkinter.mainloop()
Listing 4-6Sentiment Analysis
案例研究 2:医院食物浪费问题
在这个案例研究中,我们要看一个非常普遍的医院现象:食物浪费。我们要应用机器学习的方法来解决这个商业问题。
Acadecia 医院是美国领先的国际连锁医院之一。它成立于 1986 年,位于加利福尼亚州的一个小镇欧康。刚开始的时候很小;然而,创始人 Jack Juice 博士的愿景是让小镇居民能够负担得起并轻松获得医疗保健。这家连锁医院最引人注目的事实是,它能够保持医院的低运营成本,以便为小镇居民提供负担得起的医疗保健。2017 年,它在全球拥有 120 多家医院,其中 70%位于人口不到 100 万的小城镇。
Twin Burger 博士正在啜饮他的早餐咖啡,并仔细阅读他从财务部收到的关于其医院网络运营成本的报告。他是 Acadecia 医院的负责人,带领连锁医院实现 Juice 博士的愿景,让全世界人民都能负担得起医疗保健。在图 4-2 中,你会看到 Burger 博士那天早上收到的报告。

图 4-2
Acadecia 医院的食品成本报告
在图 4-2 中,我们可以在 Burger 医生面前看到过去 3 年(2014-2016)每份医院报告的成本参数。报告显示,Acadecia 的医院数量稳步增长;员工人数也增加了,医院的平均床位也增加了。然而,对于我们的案例研究,相关数据在最后三行,第一行是医院每天的总食品订单,以千克为单位。随着医院的增多,这个数字也上去了。倒数第二行显示了食品通胀的上升,这是以美元计算的每公斤食品的平均成本,从 2.35 美元到 2.56 美元不等。以千克为单位的粮食浪费也从 2014 年的 74.9 千克下降到 109.8 千克。在 Acadecia 的所有医院中,食物浪费从 2014 年的 42%上升到 2015 年的 47 %,平均占食物订购总量的 55%。因此,很明显,正如报告中概述的那样,伯格医生正在考虑他的医院由于食物浪费增加而导致的成本上升。
在看完报告后,Burger 博士意识到问题正在失控,需要一些有针对性的解决方案。他记得在周末遇到了他的老朋友,他现在是一名机器学习顾问,他说他可以帮助伯格博士解决任何需要使用技术的问题。他向机器学习顾问发送了一封电子邮件,预约讨论问题并利用技术找到解决方案。
他见了机器学习顾问,和他签了协议后给他看了数据。他问机器学习是否可以帮助解决这个问题,并提出一个适当的解决方案来降低他的组织因食物浪费而产生的成本。
该顾问要求提供更多的数据,以便他找出原因,然后找到解决问题的可能办法。Acadecia 计算机部门的人给了他数据访问权,让他查看中央数据库中全球服务器上的数据存储。
有趣的是,我不打算讨论数据集成和数据争论的部分,因为我们在前面的案例研究中已经讨论过了。但是,请记住,在真实的生产环境中,您很难获得本案例研究中的现成数据。您需要从平面文件、Excel 表、Word 文档、PowerPoint 演示文稿、专有数据库(如 Oracle、sQL server 和 dB2)等来源中集成数据并将其收集到一个单一来源中,如 Hadoop 或 mongo DB 或 Cassandra。
现在我们来看看 Acadecia 的综合数据集,我们将在此基础上建立我们的机器学习模型。

图 4-3
样本数据集
在图 4-3 中,我们查看了 Acadecia 医院的样本数据集。这是三家医院的数据,为了保密,我特意去掉了名字。为了保持客户的匿名性,还对其原始来源进行了充分的修改。从 Acadecia 的 125 家医院收集的数据包括医院订购的食物总量、医院浪费的食物总量、提供的住院病人膳食数量、住院病人的客人数量以及医院的类型。所有这些信息是 2014 年至 2016 年所有 3 年的平均值。
在接下来的步骤中,我们将在 Python 中加载这个数据集,并开始应用机器学习的过程,我在本书的前几章中概述了这一过程。
import pandas as pd
import os
os.getcwd()
fname="Food_Raw_Data.csv"
hospitals= pd.read_csv(fname, low_memory=False, index_col=False)
df= pd.DataFrame(hospitals)
print(df.head(1))
Listing 4-7Loading the Data Set
最初在清单 4-7 中,我加载所需的 Python 库 Pandas os,然后打开文件 food raw data。csv 文件从本地 DIRECTPyth 导入到医院的 Pandas 数据帧中,然后通过 head 函数从数据帧中读取第一条记录。加载完数据集后,我们现在将查看数据集的形状、列和数据类型,以便进一步研究它。我还查看了清单 4-8 中数据框的列及其数据类型,该数据框的形状由 125 行 8 列组成。通过给定 from,我们可以看到所有 8 列,从订购的食物总数、浪费的食物总数、住院病人数、提供的膳食数、住院病人的客人数、反馈、医院类型和病床总数开始。在这之后,我们查看每一列的数据类型;数字列是特定医院订购的食物总量、特定医院浪费的食物总量、医院接收的住院病人数量、医院一天供应的膳食数量、医院住院病人的客人数量以及医院的病床总数。非数字列是医院名称和反馈,这是患者和客人对医院食品质量的评级,但我们不打算在我们的模型中使用它。
print(df.shape)
(125, 8)
print(df.columns)
Index(['Total Food ordered', 'Total Food Wasted', 'No of Inpatients',
'No of Meals served', 'No of Guests with Inpatient', 'Feedback',
'Type of Hospital', 'Total No of beds'],
dtype='object')
df.dtypes
Out[72]:
Total Food ordered int64
Total Food Wasted int64
No of Inpatients int64
No of Meals served int64
No of Guests with Inpatient int64
Feedback object
Type of Hospital object
Total No of beds int64
dtype: object
Listing 4-8Looking at the Shape and Size of the Data Set and Its Structure
在清单 4-9 中,我们可以通过 df.org 空值看到没有空值,我们用 bf.in 验证了这一点,对于每种数据类型,所有的值都是非空的。通过这种方式,我们可以确保数据集中的每一列和每一行都被填充,因此没有丢失的值。
#Check if there are any columns with empty/null dataset
df.isnull().any()
#Checking how many columns have null values
df.info()
df.isnull().any()
#Checking how many columns have null values
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 125 entries, Hospital 1 to Hospital 99
Data columns (total 8 columns):
Total Food ordered 125 non-null int64
Total Food Wasted 125 non-null int64
No of Inpatients 125 non-null int64
No of Meals served 125 non-null int64
No of Guests with Inpatient 125 non-null int64
Feedback 125 non-null object
Type of Hospital 125 non-null object
Total No of beds 125 non-null int64
dtypes: int64(6), object(2)
memory usage: 13.8+ KB
Listing 4-9Checking for Missing Values
既然我们已经检查了丢失的值,让我们继续探索性的数据分析,查看我们的数据集的数字列的平均值、中值和众数,并通过未定义的 df.com 众数查看清单 4-10 。为了从均值函数简单地理解我们的结果,总的食物订购平均值为 319.18,医院浪费的食物平均值为 54.68 千克。人数为 33 人,医院平均提供 140 顿饭。住院客人的平均人数为 8 人。医院平均共有 64 张床位。如果我们查看相同列的中值,我们会发现中值为 255 的总订购量和 23 的总浪费量之间存在巨大差异。住院病人人数为 26 人,提供的膳食数量为 113 份。住院客人数为 7 人,总床位数接近平均值 66 张。如果中值和平均值足够接近,则意味着我们的数据集是正态的或接近正态的,其特征是,如果数据集具有正态分布,则平均值、中值和众数的每一列的值将接近相等。但是,我们可以清楚地看到,我们的数据集并不是正态分布的。均值和中值之间的差异告诉我们的另一件事是,我们正在处理异常值,在总食物浪费、用餐次数和总食物订购列中有更多的异常值。其余的列彼此接近,因此其中可能没有很多异常值。
#How is the data distributed and detecting Outliers
df.std()
df.max()
df.min()
df.quantile(0.25)*1.5
df.quantile(0.75)*1.5
df.std()
Out[79]:
Total Food ordered 220.918186
Total Food Wasted 81.394658
No of Inpatients 22.565266
No of Meals served 97.742244
No of Guests with Inpatient 8.358886
Total No of beds 20.279047
dtype: float64
df.max()
Out[80]:
Total Food ordered 921
Total Food Wasted 454
No of Inpatients 91
No of Meals served 407
No of Guests with Inpatient 38
Feedback C
Type of Hospital Urban
Total No of beds 100
dtype: object
df.min()
Out[81]:
Total Food ordered 2
Total Food Wasted 0
No of Inpatients 0
No of Meals served 1
No of Guests with Inpatient 0
Feedback A
Type of Hospital Rural
Total No of beds 30
dtype: object
df.quantile(0.25)*1.5
Out[82]:
Total Food ordered 238.5
Total Food Wasted 7.5
No of Inpatients 25.5
No of Meals served 105.0
No of Guests with Inpatient 3.0
Total No of beds 66.0
Name: 0.25, dtype: float64
df.quantile(0.75)*1.5
Out[83]:
Total Food ordered 679.5
Total Food Wasted 87.0
No of Inpatients 70.5
No of Meals served 300.0
No of Guests with Inpatient 18.0
Total No of beds 123.0
Name: 0.75, dtype: float64
Listing 4-11Exploratory Data Analysis
df.mean()
Out[75]:
Total Food ordered 319.184
Total Food Wasted 54.680
No of Inpatients 32.952
No of Meals served 141.224
No of Guests with Inpatient 8.800
Total No of beds 64.776
dtype: float64
df.median()
Out[76]:
Total Food ordered 255.0
Total Food Wasted 23.0
No of Inpatients 26.0
No of Meals served 113.0
No of Guests with Inpatient 7.0
Total No of beds 66.0
dtype: float64
df.mode()
Out[77]:
Total Food ordered Total Food Wasted No of Inpatients \
0 110.0 0.0 23
1 NaN NaN 25
No of Meals served No of Guests with Inpatient Feedback Type of Hospital \
0 97.0 2.0 B Urban
1 NaN NaN NaN NaN
Total No of beds
0 44.0
1 NaN
Listing 4-10
Detecting Outliers
在清单 4-11 中,我们转到检测异常值,以检测我们首先查看标准偏差,它告诉我们数据在每一列中的离差,然后我们查看最大值和最小值,以找出数据集中每一列的范围。然后,我们使用分位数函数,使用第 25 个百分点和第 75 个百分点,并乘以 1,以获得下限异常值和上限异常值。例如,从分位数 0.2 中,我们可以看到,订购的食物总量的异常值下限为 238.5,而第 75 个百分位 X 1.5 的“订购的食物总量”列的值为 679。实际上,对于“订购的食物总量”列,任何低于 38.5 的值和任何高于 679 的值都将被视为异常值。你同样可以查看其他栏,如浪费的食物总量、住院病人数量、提供的餐饮数量等。
#How many Outliers in the BPSystolic column
df.columns
df.dtypes
df.set_index(['Hospital Name'])
df['Total Food ordered'].loc[df['Total Food ordered'] <=238.5].count()
Out[84]: 55
df['Total Food ordered'].loc[df['Total Food ordered'] >=679.5].count()
Out[85]: 11
Listing 4-12How Many Outliers in Any Particular Columns
现在我们来看图 4-3 ,在图中,我给出了一个示例,说明如何计算特定列中有多少值(如总点餐数)不符合异常值的下限和上限。我们可以看到,对于订购的总食物,异常值下限为 38.5,有 55 个值小于这个数字。类似地,对于异常值上限 679,“订购的食物总数”列有 11 个值超出了该阈值限制。
为什么我们需要知道这些?首先,任何机器学习顾问都会考虑这个值,因为他们需要决定是丢弃、保留还是修改离群值。在这种情况下,我决定保留离群值,因为如果我删除它们,我将丢失数据集的很大一部分(125 行中的 66 行将丢失),并且这些行可以带来的学习也将随之丢失。然而,这并不是您在每次建模练习中都必须遵循的规则。您应该独立思考什么是相关的,什么对您的数据集和您正在构建的模型是有益的。

图 4-4
可视化数据集的结构
#Visualizing the dataset
df.boxplot(figsize=(10, 6))
df.plot.box(vert=False)
df.kurtosis()
df.skew()
import scipy.stats as sp
sp.skew(df['Total Food ordered'])
在图 4-4 中,我们试图通过绘制盒状图的水平和垂直方向来可视化我们的数据集,从图中可以非常清楚地看出,订购的食物总量更加分散,并且在尾部末端有异常值。相比之下,浪费的食物总量要少得多;然而,它在尾部有更多的异常值。
类似地,读者会从第三章中回忆起峰度显示了我们数据集分布的厚度。这意味着厚度,如果峰向左,那么它被称为薄峰。如果分布是厚尾,那么这样的分布与正态分布比较,峰度值等于 3。过度峰度意味着峰度值将大于 3,而较少峰度意味着峰度值将小于 3。如果峰度值小于 0,则称之为平峰分布。记住这一点,现在让我们研究清单 4-13 中给出的四个变量。总食物顺序的峰度值是负的(0.1),所以它是平峰度。浪费的食物总量在 3 以上,价值 7。这意味着在数据中有更多的峰值和过度峰度,并且分布是中等峰度的。住院病人数和提供的膳食数列是 platykurtic,因为它们小于 0;同样,床位总数也小于 0。有住院病人的客人的列数是 2,这意味着它不是更小的峰度,因为该值小于 3。
df.kurtosis()
Out[91]:
Total Food ordered -0.150535
Total Food Wasted 7.432315
No of Inpatients -0.299269
No of Meals served -0.155185
No of Guests with Inpatient 2.008910
Total No of beds -1.224649
dtype: float64
df.skew()
Out[92]:
Total Food ordered 0.756837
Total Food Wasted 2.570979
No of Inpatients 0.712854
No of Meals served 0.754662
No of Guests with Inpatient 1.476908
Total No of beds -0.028728
dtype: float64
Listing 4-13Looking at Skew and Kurtosis
在清单 4-13 中,我们查看了每一列的偏斜度和峰度,您会从第三章中回忆起,如果偏斜度小于 0,那么我们说分布是负偏斜的;如果偏斜度等于 0,则称该分布是对称的;如果偏斜值大于 0,那么我们说分布是正偏斜的。偏斜告诉我们尾巴向哪个方向偏斜。负偏差的结果有一个长的左尾巴,正偏差的结果有一个长的右尾巴。从清单 4-13 中,我们可以看到,总点餐数为正值 0.7,总浪费食物数也正偏于 2。住院病人数正偏于 0.71,提供的餐饮数也正偏于 0.7,有住院病人的客人数高度偏于 1.4,总床位数略微负偏,但在 0.02 更接近于 0。
df.hist(figsize=(10, 6))
Out[95]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x0000019D18C1F940>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000019D18F2CB70>],
[<matplotlib.axes._subplots.AxesSubplot object at 0x0000019D18F64B70>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000019D18F9FC50>],
[<matplotlib.axes._subplots.AxesSubplot object at 0x0000019D18FDAC50>,
<matplotlib.axes._subplots.AxesSubplot object at 0x0000019D18FDAC88>]], dtype=object)
在图 4-5 中,我们可以清楚地看到数据集中的列是如何分布的。这表明列中的数据都不符合正态曲线。

图 4-5
可视化数据分布
现在我们进入下一步,识别数据之间的任何关系,因为我们在建模练习中讨论的是数字数据。在图 4-6 中,我们可以看到各列相关值的结果,我们案例研究的主要重点是基于总食物浪费值创建一个模型,这需要根据其他数据进行预测。其他数据是可用的,所以看相关值,我选择的最重要的是,浪费的食物总量与病人数量的相关值为 0.7;浪费的食物总量与用餐次数呈正相关,相关系数为 0.7;浪费的食物总量与有住院病人的客人数量呈非常高的正相关,为 0.9;与总食物订单相关的总食物浪费是 0.7。我提议基于这四个输入建立一个总食物浪费的预测模型。我们可以看到,住院病人的客人数量与总食物浪费的比例可能为 0.9,因此 Acadecia 医院可能需要研究住院病人数量增加导致医院设施食物浪费的原因。这一最重要的决定因素可以为他们节省大量的食物浪费。

图 4-6
用散点图可视化相关性
df.corr()
Out[96]:
Total Food ordered Total Food Wasted \
Total Food ordered 1.000000 0.770522
Total Food Wasted 0.770522 1.000000
No of Inpatients 0.998059 0.765459
No of Meals served 0.999994 0.770236
No of Guests with Inpatient 0.696581 0.934847
Total No of beds 0.410256 0.357904
No of Inpatients No of Meals served \
Total Food ordered 0.998059 0.999994
Total Food Wasted 0.765459 0.770236
No of Inpatients 1.000000 0.998056
No of Meals served 0.998056 1.000000
No of Guests with Inpatient 0.697330 0.696443
Total No of beds 0.411096 0.409509
No of Guests with Inpatient Total No of beds
Total Food ordered 0.696581 0.410256
Total Food Wasted 0.934847 0.357904
No of Inpatients 0.697330 0.411096
No of Meals served 0.696443 0.409509
No of Guests with Inpatient 1.000000 0.296937
Total No of beds 0.296937 1.000000
Figure 4.22 Correlation for all the numeric column variables
df.plot.scatter(x='Total Food Wasted', y='No of Guests with Inpatient',s=df['Total Food Wasted']*2)
Out[98]: <matplotlib.axes._subplots.AxesSubplot at 0x19d190eec50>
现在,图 4-6 向您展示了一种观察这种相关性的方法,并创建了一个散点图,清楚地显示了总食物浪费量和住院客人数量之间的联系。我们可以在图表中清楚地看到一种模式。虽然我们有两个分类列,反馈和医院类型,但因为我们的案例研究不需要对它们进行任何计算或理解,所以在我们的模型构建练习中,我们将忽略它们。接下来,我进入数据准备步骤,将数据分为特性集和目标集。第一个数据框是浪费,这是我们的目标数据集,我们需要根据其他列来预测浪费的食物总量。为了创建要素数据框,我从数据框中删除了浪费的食物总量,这是我们的目标列、反馈列、医院类型列和床位总数列。这在清单 4-14 中进行了描述。
wastage = pd.DataFrame(df['Total Food Wasted'])
dropp=df[['Total Food Wasted','Feedback','Type of Hospital','Total No of beds']]
features= df.drop(dropp, axis=1)
wastage.columns
features.columns
Out[102]:
Index(['Total Food ordered', 'No of Inpatients', 'No of Meals served',
'No of Guests with Inpatient'],
dtype='object')
Listing 4-14Preparing Features and Target Data Sets
接下来,我们继续洗牌,并按照 80%比 20%的比例将数据分成训练集和测试集。这可以在清单 4-15 中看到。
from sklearn.cross_validation import train_test_split
from sklearn.utils import shuffle
# Shuffle and split the data into training and testing subsets
features=shuffle(features, random_state=0)
wastage=shuffle(wastage, random_state=0)
# Split the 'features' and 'income' data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(features, wastage, test_size = 0.2, random_state = 0)
# Show the results of the split
print("Training set has {} samples.".format(X_train.shape[0]))
print("Testing set has {} samples.".format(X_test.shape[0]))
Training set has 100 samples.
Testing set has 25 samples.
Listing 4-15Shuffling and Splitting the Data
接下来,我继续构建和评估模型。我将使用两个回归变量:一个是线性回归模型,另一个是线性 SVC(支持向量机)。您可以在清单 4-16 中看到库导入及其初始化。
import matplotlib.pyplot as plt
import numpy as np
from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.svm import LinearSVC
#Creating Linear Regression object
regr = linear_model.LinearRegression()
linear_svm = LinearSVC().fit(X_train,y_train)
Figure 4.26 Model Evaluation and Initializing
regr.fit(X_train,y_train)
y_pred= regr.predict(X_test)
yy_pred= linear_svm.predict(X_test)
#Printing Codfficients
print('Coefficients: \n',regr.coef_)
print(LinearSVC().fit(X_train,y_train).coef_)
Coefficients:
[[ 3.84820846 -4.81910798 -7.39895629 7.71902335]]
[[ -3.53041635e-02 5.09097801e-02 3.14979916e-02 -3.88312025e-01]
[ -2.32668818e-02 -1.42174073e-01 7.43984582e-02 -1.16573785e-02]
[ 4.72789182e-02 1.47150837e-01 -1.36891194e-01 -5.32241337e-02]
[ 2.93890989e-02 -1.19191185e-01 -2.58725709e-02 -3.82878378e-02]
[ 4.11308074e-02 2.64727641e-02 -9.78443211e-02 -5.51862063e-02]
[ 7.00718282e-02 -8.10166533e-02 -1.22951514e-01 1.71447192e-01]
[ 3.42043753e-02 -2.05910747e-02 -6.20141160e-02 -9.89629458e-02]
[ 2.77961883e-02 -4.46751024e-02 -4.37038593e-02 2.66465015e-01]
[ 1.13547353e-02 -2.71632958e-02 -2.08526490e-03 1.70754244e-01]
[ 3.32914578e-02 -1.67505293e-02 -5.77349454e-02 2.09845962e-03]
[ 4.77186007e-02 -8.23837686e-02 -9.30268666e-02 3.78425737e-02]
[ 3.41540305e-02 -7.34444501e-02 -6.46481812e-02 3.54015691e-02]
[ 3.84521437e-02 -6.41689817e-02 -7.31629621e-02 2.70787385e-01]
[ 4.87625884e-02 -6.84474198e-02 -8.67811679e-02 -5.64164062e-02]
[ 1.49537087e-02 -3.77585007e-02 -1.36249294e-02 7.99620681e-02]
[ 4.89155675e-02 -9.21493872e-02 -8.01503822e-02 1.77140915e-01]
[ 4.24949470e-02 -4.87499272e-02 -7.78022864e-02 1.34518802e-01]
[ 3.50542029e-02 -3.54090045e-02 -6.63975873e-02 1.09584692e-03]
[ 9.38169848e-03 -3.67554573e-02 -1.71349625e-02 2.41221242e-01]
[ 1.00033106e-02 -4.53600521e-02 -6.24499229e-03 1.58324477e-01]
[ 1.41868325e-02 -3.95136457e-02 -1.76177176e-02 2.42552491e-02]
[ 2.67055967e-02 -3.86757704e-02 -5.58150253e-02 2.54908921e-01]
[ 4.79369084e-02 -6.20604669e-02 -8.98633410e-02 -7.57650121e-03]
[ 3.08510176e-02 -8.53705374e-02 -5.20465381e-02 2.20385612e-01]
[ 1.73454354e-02 1.98721103e-02 -4.24878889e-02 9.81570693e-02]
[ 1.24536489e-02 -4.20971569e-02 -1.23960336e-02 3.52634992e-02]
[ 2.57398024e-02 -9.16159713e-02 -4.47215477e-02 2.19305087e-01]
[ 4.23505923e-03 6.72353051e-04 -6.50834658e-03 1.49214594e-01]
[ 2.53837094e-02 -6.98875557e-02 -4.85734903e-02 2.22530149e-01]
[ 1.43908959e-02 -4.75516908e-02 -1.95433533e-02 1.51543940e-01]
[ 2.74067987e-02 -7.52560330e-02 -4.01603079e-02 1.10143783e-01]
[ 4.64045608e-02 -4.05773937e-02 -8.79857548e-02 1.03748880e-02]
[ 1.90491415e-02 -4.10809528e-02 -3.62574033e-02 -1.81196597e-02]
[ 2.22912356e-02 -2.72874169e-02 -4.39681811e-02 1.09394978e-01]
[ 4.20384279e-02 -3.25727010e-02 -8.51492094e-02 -6.37752010e-03]
[ 2.61534393e-02 -2.94261743e-02 -5.41846630e-02 -2.75644483e-02]
[ 2.45319444e-02 -5.09991059e-02 -5.06126410e-02 2.02505939e-01]
[ 2.61919602e-03 -1.25839053e-02 -6.30409084e-03 1.80773339e-01]
[ 2.74789306e-03 -2.73580886e-02 -6.50473121e-03 2.01205405e-01]
[ 2.44669007e-02 -7.03696516e-03 -4.64750958e-02 2.60881871e-02]
[ 1.51200603e-02 -6.89484027e-02 -8.71324723e-03 -8.82744952e-02]
[ 2.65609136e-02 -4.97286727e-02 -5.75957648e-02 3.38979678e-02]
[ 7.11056619e-03 -3.27401201e-02 -1.46946498e-02 1.84639962e-01]
[ -3.19488770e-03 -1.29730299e-02 -6.65748840e-03 2.30931190e-01]
[ 2.39725322e-02 -4.20831865e-02 -5.23242642e-02 6.14469586e-02]
[ 6.08374964e-03 -3.24197530e-02 -1.01534653e-02 1.56827822e-01]
[ 6.69569094e-03 4.31666176e-03 -3.94068509e-02 1.51761293e-01]
[ 4.25886521e-04 -2.49710716e-02 -1.34306904e-02 2.29936692e-01]
[ -1.00182507e-03 -2.39362307e-02 -8.88224128e-03 2.23843885e-01]
[ 1.51225156e-02 -4.74318832e-02 -3.73751734e-02 1.50716919e-01]
[ 2.45229013e-02 -5.96876827e-02 -5.15767695e-02 1.86736550e-02]
[ 1.13573008e-02 -2.92617710e-02 -3.19670746e-02 1.29940982e-01]
[ 1.33635906e-02 -3.62729876e-02 -2.39250008e-02 1.03188376e-01]
[ 1.22517696e-02 -4.33917684e-02 -1.70961907e-02 8.42211744e-02]
[ 7.24558495e-03 -3.29668719e-02 -1.44697007e-02 1.50876782e-01]
[ 9.93726094e-04 -3.39403174e-02 -9.35154827e-03 2.01139275e-01]
[ 4.76853411e-03 -1.52811320e-02 -2.65559075e-02 1.66170095e-01]
[ 3.07916719e-03 3.05077312e-05 -2.62159469e-02 1.62382755e-01]
[ 1.07347039e-02 -4.44424820e-02 -3.08244532e-02 1.32283650e-01]
[ 1.24123818e-02 -4.00221036e-02 -3.10893289e-02 1.28289289e-01]]
print('Coefficients: \n',regr.coef_)
Coefficients:
[[ 3.84820846 -4.81910798 -7.39895629 7.71902335]]
plt.plot(X_test, y_pred, linewidth=3)
plt.show()
Listing 4-16Results of Regressors


图 4-7
线性回归与线性 SVM 可视化
line = np.linspace(-15, 15)
for coef, intercept in zip(linear_svm.coef_, linear_svm.intercept_):
plt.plot(line, -(line * coef[0] + intercept) / coef[1]) #HOW DO WE KNOW
plt.ylim(-10, 15)
plt.xlim(-10, 8)
plt.show()
在图 4-7 中,我们看到线性回归的结果以及来自线性 SVC 的系数,同时我们看到来自线性回归的系数有四个参数,正如预期的那样。然而,在这种特殊情况下,线性 SVC 是一种不好的方法,因为为了预测解,它给了我们更多的划分。为了让你理解这个概念,我将在清单 4-17 中列出线性回归的结果,以及在线性 SVM 中使用的预测和图形表示。当我们比较线性回归和线性 SVM 的图形时,我们看到线性 SVM 中有更多的边界,而线性回归中只有四个边界。所以我们应该使用线性回归来建立我们的模型。
predicted= regr.predict([[820,81,363,35]])
print(predicted)
[[ 312.23258101]]
Listing 4-17Predict Using Linear Regression Using Our Model on the Amount of Wasted Food Based on Four Parameters
我使用清单 4-17 中的最后一步,通过给定我们的因变量和自变量的四个值来随机预测,以获得特定医院的总食物浪费。
这就是我对这一章案例研究的全部内容。我希望您能像我有幸向您展示案例一样,喜欢阅读这些案例。

被折叠的 条评论
为什么被折叠?



