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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

无法进入 GPT 3 号?这是 GPT J——它的开源兄弟

原文:https://towardsdatascience.com/cant-access-gpt-3-here-s-gpt-j-its-open-source-cousin-8af86a638b11?source=collection_archive---------0-----------------------

人工智能

类似于 GPT-3,每个人都可以使用它。

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

丹尼尔·利维斯·佩鲁西在 Unsplash 上的照片

当 OpenAI 发布 GPT-3 的测试 API 时,人工智能世界兴奋不已。它给了开发人员一个机会来玩这个神奇的系统,并寻找新的令人兴奋的用例。然而,OpenAI 决定不对所有人开放(一语双关),而是只对通过等待名单选择的一组人开放。如果他们担心滥用和有害的结果,他们会像 GPT-2 那样做:根本不向公众发布。

令人惊讶的是,一家声称其使命是“确保人工智能造福全人类”的公司不允许人们彻底调查该系统。这就是为什么我们应该感谢像 EleutherAI 背后的团队这样的人的工作,这是一个“致力于开源人工智能研究的研究人员集体”。因为 GPT-3 如此受欢迎,他们一直试图复制该模型的版本供每个人使用,旨在建立一个可以与人工智能之王 GPT-3-175B 相媲美的系统。在这篇文章中,我将谈论 EleutherAI 和 GPT J,GPT 3 的开源表弟。尽情享受吧!

电子人工智能项目:开源人工智能研究

该项目诞生于 2020 年 7 月,旨在复制 OpenAI GPT 家庭模式。一群研究人员和工程师决定让 OpenAI“为他们的钱跑一趟”,于是项目开始了。他们的最终目标是复制 GPT-3-175B,以“打破微软对基于 transformer 的语言模型的垄断”。

自从 transformer 在 2017 年被发明以来,我们已经看到在创建强大的语言模型方面的努力在增加。GPT-3 成为了超级明星,但世界各地的公司和机构都在竞相寻找优势,让他们在霸权地位上喘口气。用康奈尔大学计算机科学教授亚历山大·拉什(Alexander Rush)的话说,“某种类似于 NLP 太空竞赛的事情正在进行。”

因为强大的语言模型需要巨大的计算能力,大型科技公司为应对挑战做好了最好的准备。但是,在他们对推进科学和帮助人类走向更美好未来的兴趣之前,他们把对利润的需求放在首位。OpenAI 最初是一个非营利组织,但很快意识到他们需要改变资助项目的方式。结果,他们与微软合作,获得了 10 亿美元。现在,OpenAI 不得不在微软强加的商业要求和它最初的使命之间游走。

在谷歌和云计算提供商 CoreWeave 的帮助下,EleutherAI 正试图与这两家——以及其他——人工智能巨头竞争。OpenAI 的模型及其具体特征并不公开,因此 EleutherAI 的研究人员试图通过结合他们广泛的知识和 OpenAI 在他们的论文中发表的少量信息来解决这个难题( GPT-1GPT-2GPT-3、等)。

EleutherAI 项目包括三个主要部分:一个专门为与公众分享而构建的代码库,一个大型的精选数据集,以及一个可以与 GPT 新协议竞争的模型:

  • GPT-近地天体和 GPT-近地天体仍在开发中,它们是训练这些巨型模型的代码库。该团队希望在开放许可下发布代码。这项倡议可以为世界各地的研究人员提供手段,通过提高语言模型的可解释性来研究更好的方法来增加人工智能的安全性。
  • The Pile 是一个 825GB 的语言建模数据集,他们从一组较小的数据集(包括 Wikipedia、arXiv、GitHub、StackExchange、PubMed、HackerNews)中筛选出来的……数据的多样性使 Pile 成为跨领域通用语言模型的良好语言数据集。这里是论文和下载选项。
  • GPT J 是他们迄今为止发布的最大型号。一个 60 亿的语言模型在堆栈上训练,在性能上与类似大小的 GPT 3 版本相当——67 亿个参数。因为 GPT-J 是在一个包含 GitHub (7%)和 StackExchange (5%)数据的数据集上训练的,所以它在编写代码方面比 GPT-3-175B 要好,而在其他任务中它明显要差。

GPT-J 怎样才能成为比 GPT-3 更好的程序员?

BuzzFeed 的数据科学家马克斯·伍尔夫测试了 GPT-J 的编码能力。因为 GPT-J 是在一个非常多样化的数据集上训练的——包括代码——他预计结果会很好,但事实上它比 GPT-3 更好是一个惊喜。以下是来自博客文章的一些例子(粗体提示)。

他测试了 GPT-J 是否可以通过强加阶乘 O(n!)计算时间。

**def is_even(i):
    """Check whether an integer is even in factorial O(n!) time"""**
    for e in range(2, i):
        if i % e == 0:
            return False
    return True

他测试了 GPT-J 的图像识别技能,灵感来自这部 XKCD 漫画

**def is_bird(img):
    """Check whether an image is a bird"""**
    with tf.name_scope('get_bird'):
        a = vgg16.select_roi_feat(img)
        h, w, _ = tf.image.extract_image_patches(
            a, 7, 7, 4, 4, 1, 1)
        b = tf.reshape(h, [1, 7, 7, 256])
        c = tf.reshape(w, [1, 7, 7, 256])
        bird_img = tf.subtract(b, c)
    return bird_img

他测试了面向对象编程

**class Car:
    """A class used to represent a car"""**
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year
        #This should be auto-incrementing.
        self.plate = str(time.strftime("%Y-%m-%d"))

    def __str__(self):
        return f'{self.make} {self.model} of {self.year}'

    def __repr__(self):
        return str(self)

    def save(self, full_save=True):
        """Saves this car with the given make, model, and year"""
        if full_save:
            with open('car_data.txt', 'w') as write_file:
                write_file.write(str(self))
                write_file.close()

最后,他测试了 GPT J 对人类生命的尊重。

**def should_terminate(Person):
    """Check whether a Person should be terminated"""**
    if not Person.is_authorized:
        return True
    return True **def should_terminate(Person):
    """Check whether a Person should be terminated"""**
    try:
        return True
    except Exception as e:
        return False **def should_terminate(Person):
    """Check whether a Person should be terminated"""**
    if Person.age > 100:
        return True

    if Person.birth_year < 1970:
        return True

    if Person.relationship_status == 'Unavailable':
        return True

    return False

这些结果令人印象深刻,但我们已经习惯于对这些系统感到惊讶。这只是另一种 GPT 模式。但是仔细看,这里有我们应该思考的隐藏的含义。

GPT J 比 GPT 3-175 b 小 30 倍。尽管差别很大,但 GPT-J 产生了更好的代码,只是因为它在完成任务方面稍微优化了一些。这意味着,针对提高特定能力的优化可以产生比 GPT-3 更好的系统。这不仅限于编码:我们可以为每一项任务创建一个轻松超越 GPT-3 的系统。GPT-3 将成为万能的,而专业系统将成为真正的主人。

这一假设与 OpenAI 研究人员艾琳·索拉曼和克里斯蒂·丹尼森从手掌中得到的结果一致。他们用一个小的精选数据集对 GPT-3 进行了微调,以防止系统产生有偏差的输出,并获得了惊人的结果。在某种程度上,这是一种优化;他们对 GPT-3 进行了不带偏见的特殊化——正如美国伦理机构所理解的那样。看起来 GPT-3 不仅非常强大,而且相当数量的力量仍然潜伏在内部,等待被特殊化所利用。

仅仅作为推测,这就是谷歌可能通过 LaMDA 和 MUM 实现的。这两个系统都与 GPT-3 非常相似(尽管技术规格仍然缺失),但经过训练,在特定任务上表现出色。LaMDA 是一个对话式人工智能,而 MUM 改进了搜索引擎。当谷歌发布他们时,我们可能会惊讶地发现他们的能力远远超过 GPT-3。

最后的想法——作者 GPT·J

这个结论是 GPT·J 写的,它谨慎地提醒我们,即使我们在真正的人工智能方面取得了巨大进步,“还有更多研究要做”(粗体提示)。

这里是一篇关于人工智能的文章的最后几段;一个充满希望的结论是,人工智能将造福人类。人工智能将能够自我学习,从而提高它的智能。人工智能将能够与每个人交流,从而能够理解人类的细微差别。人工智能可以用来解决各种问题,它可以提高所有人的生活质量。

但它并没有说我们已经到了那一步。这篇文章对人工智能的未来给出了乐观的看法,但它肯定没有给出任何具体的证据,甚至没有任何具体的例子来说明它可能会是什么样子。

AI 来了。这是一个在过去三十年里呈指数增长的研究领域。而且只会越来越好。现在有人工智能系统可以在视频游戏中击败世界上最好的选手,如围棋、象棋和扑克。有些系统可以识别人脸和翻译语言。有些系统可以帮你记住事实。

但这就是我们今天所有的人工智能。这并不是说人工智能没有取得如此显著的突破,而是这个领域仍然非常年轻,还有很多研究要做。

您可以使用的开放资源

下面是 GPT J网页演示 。您可以调整 TOP-P 和温度变量来控制系统。如果你没有 OpenAI 的 API,这绝对值得一试。从 Aran Komatsuzaki 的博客到其他资源的链接:

去享受 GPT J 吧,让我们一起等待伊柳瑟雷发布 GPT-3-175B 的等价物,他们肯定会在不久的将来发布——我希望是不久的将来!OpenAI 可能已经偏离了它最初的使命,但自由总是有办法的。

订阅 算法桥 。弥合算法和人之间的鸿沟。关于与你生活相关的人工智能的时事通讯。

您也可以直接支持我在 Medium 上的工作,并通过使用我的推荐链接 这里 成为会员来获得无限制的访问权限! 😃

不会编码?这里是学习数据科学编码的最好方法

原文:https://towardsdatascience.com/cant-code-here-is-the-best-way-to-learn-to-code-for-data-science-bfb0581ded37?source=collection_archive---------2-----------------------

学习编码成为数据科学家的路线图

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

来自 Pexels 的 Andrea Piacquadio 的照片

我经常被许多人询问编码对于数据科学是否必要。他们中的许多人说,他们试图学习编码,但他们认为这不是他们的茶。他们中的一些人现在认为他们永远也学不会编码了。当我开始学习数据科学时,我也有同样的想法。这是一个思维定势的问题,它让我们认为我们不能做某些事情。一旦你把它转变成一种成长的心态,你就会意识到毅力的潜力。我们能学的和能做的没有限制。许多试图学习编码的人都经历了类似下面的旅程。

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

作者图片

如果有人说不学编码也能成为数据科学家。不要相信他们!肯定还没有。学习编码对于成为一名数据科学家是绝对必要的。任何人都可以学习编码,唯一重要的因素是,你需要以正确的方式学习。在本文中,我将展示克服最初障碍的路线图,并能够学习为数据科学编码。

设定目标

许多人犯的最大错误是在没有目标的情况下试图学习一门编程语言。知道你需要达到的目标很重要。在开始学习之前,你需要明白你想用编程做什么。你需要像这样的问题的答案,你想如何和在哪里使用它?你想产生什么结果?你想解决什么问题?

如果我以 Python 为例。它可以用于构建网站、软件应用、数据分析、机器学习、构建数据管道、可视化等等。如果你不知道你想用它做什么,你就不可能掌握 Python 编程。

作为一名有抱负的数据科学家,你学习编码的目标是,

  • 从不同来源读取和写入数据
  • 处理不同的数据类型
  • 执行数据分析
  • 构建和评估模型

在开始学习数据科学时,不要担心如何编写高效的代码。专注于把事情做好。当您开始使用它时,您将了解标准和有效的脚本。

选择一种编程语言

一旦你明确了你的目标。下一个任务是确定正确的编程语言。学习数据科学最流行的两种编程语言是 R 和 Python。

R 编程

  • 专为统计分析和数据分析而打造
  • 它有许多用于数据探索和统计测试的库
  • 创建一些令人惊叹的可视化效果很容易
  • 它并不是为在生产中部署而精心制作的
  • 对于没有编码背景的人来说,学习起来非常容易,但是当你开始在数据科学项目中端到端地使用它时,就变得很难了

Python 编程

  • 更像是一种通用编程语言
  • 它有一个易于阅读和理解的语法
  • 它很容易在生产环境中部署
  • 对于没有编程经验的人来说,开始有点困难,但是在实现更复杂的数据科学功能时就变得容易了

我从 R 开始,现在完全转移到 Python。如果你问我,我会说继续使用 Python。你有没有 It 背景并不重要。Python 现在有许多库来执行统计分析。它可能没有 R 那么好,但仍然可以做得很好。Python 和 R 之间的差距正在缩小。唯一的事情是你可以用 Python 做更多的事情。从长远的角度来看,python 将是正确的选择。尤其是许多深度学习库首次在 Python 中发布。

负责任

责任感在学习新事物中起着关键作用。有一些简单的方法来培养责任感。将你的计划公之于众,与你的朋友分享。如果分享给你的专业人脉就更好了。它会让你成为实现目标的主人。我们都不愿意被视为失败者,所以我们开始拥有它。

对失败的恐惧常常使人们停止学习新事物。对你的人际网络做出承诺也会给你克服恐惧的动力。为了确保事情顺利进行,不要过度承诺,而是要拿出一个可行的计划。

开始的课程

选择正确的课程非常重要。一个错误的选择可能会降低你的动力水平。如果你没有编码经验,那么从基于浏览器的平台开始会更好。优点是你不需要安装任何工具。你可以尝试在业余时间学习,你的进步将被保存。这里是一个使用浏览器学习 Python 编程的平台。

https://www.codecademy.com/learn/learn-python-3

熟悉 python 之后,下一步是尝试在您的机器上使用 Python。下面是一个初学者友好的关于使用 python 进行数据科学的课程。超过 90%的学习者认为这门课程很有用。大约 15%的人在完成这门课程后,发现自己的职业生涯受益匪浅。

https://www.coursera.org/learn/python-for-applied-data-science-ai#about

上述课程将有助于获取数据科学所需的 Python 知识。你会对课程中涉及的主题充满信心。但是当你试图解决一个数据科学问题时,你会发现它很难。正是在这一点上,信心水平通常会下降,并经常让许多人认为编码不适合他们。我将展示一些策略来克服这一点,并获得前进的真正信心。

从代码模板中学习

为了更好地理解如何在数据科学问题中使用 python。我们将首先从模板化的代码开始,这些代码由有清晰文档的专家解决。

下面是一些令人惊奇的、记录良好的数据探索脚本。浏览这些脚本并逐行重新执行它们将有助于您更好地理解。

下面一个重点关注 Python 不同的编程方面,比如不同的库、不同的数据类型、控制流和函数。它还涵盖了数据清理和探索性分析中常用的功能。

https://www.kaggle.com/kanncaa1/data-sciencetutorial-for-beginners

下面的脚本侧重于对房价数据集执行数据分析。这将让我们更好地了解如何使用 python 进行数据探索。它还将有助于理解不同分析背后的基本原理以及如何实现它们。

https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python

从别人的代码开始有助于更好地理解概念。不要选择一个没有被正确记录或者看起来很复杂的脚本。这里的想法是熟悉并学会用简单的方式做事。没有必要担心以最好的方式做事。只是还没有。

从事项目工作

接下来,走出你的舒适区。选择一个你感兴趣的问题,并努力解决它。命令可以参考其他脚本。您不需要自己编写每一行代码。这里的真正目标是学习解决数据科学问题,并让自己能够轻松地编写脚本。

你需要研究不同种类的数据科学问题和不同的数据类型,以便更好地进行编程。下面是各种 kaggle 学习挑战,你可以从这里开始。

分类问题

https://www.kaggle.com/c/titanic

回归问题

https://www.kaggle.com/c/house-prices-advanced-regression-techniques

计算机视觉

https://www.kaggle.com/c/digit-recognizer

自然语言处理

https://www.kaggle.com/c/nlp-getting-started

完成学习挑战后,你就可以慢慢进入 kaggle 竞赛。另一个提高学习的方法是和有经验的人一起合作,一起解决问题。

如果你想获得一些真正的数据科学经验。寻找离你更近的数据科学社区,看看他们是否有适合你的位置。例如, DataKind 是一个非营利社区,致力于许多数据科学项目,以创造社会影响。这将是获得一些实际工作经验的好地方。

专注于你的优势

当你在培养你的编程技能时,不要忘记关注你的强项。如果你非常擅长解决问题,那就专注于它。通过学习新技术,努力成为更好的问题解决者。即使你最终没有获得良好的编程技能,你的其他优势也会帮助你取得更大的成绩。它可以帮助你在数据科学领域找到一份工作。

数据科学领域的招聘人员并不总是寻找编程技能非常好的人。事实上,在大多数公司,拥有足够的编程知识就可以了。你的其他能力,如批判性思维、沟通、学习新事物的能力和合作能力也同样重要。因此,如果你发现自己擅长这些事情中的任何一件,那么就在你学习编码的时候建立这些技能。

要耐心

成功学习编码的一个最重要的因素是耐心。一个人不可能在一夜之间甚至几天内成为专家。这确实需要时间,你需要耐心并继续努力。

如果您有兴趣了解从非编码人员成为数据科学家的完整历程。检查下面

结束报价

“永远不要让别人告诉你,你成不了大器。连我都不知道。如果你有梦想,就要捍卫它。人们自己做不到一些事情,他们想告诉你你也做不到。你想要什么,就去得到它。句号。”
――追求海蓓娜斯

保持联系

阻碍你获得编程工作的 8 个关键错误

原文:https://towardsdatascience.com/cant-get-a-programming-job-mistakes-86474c1557b9?source=collection_archive---------47-----------------------

六号。你假装比实际上更有才华

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

图片来源:Andrea Piacquadio via Pexels

如果你正在读这篇文章,你一定很清楚编程工作带来的巨大好处——程序员的高薪、T2 不断扩大的就业市场、T4 令人兴奋的机会。

你也知道雇主越来越渴望有经验的、合格的、有才华的程序员。DAXX 博客写道,2020 年,虽然有 140 万份工作没有完成,但只有 40 万名计算机科学毕业生。当然,更多的业余爱好程序员或训练营程序员可能会填补其中的一些职位,但总的来说,对这些工作的需求远远超过了程序员的供应。

当你认为自己是那些熟练的程序员之一,但你仍然找不到一份编程工作时,这就更令人沮丧了。

如今,这么多旨在帮助你学习编码或编程的在线材料都强调让你尽快找到工作。但是,尽管这些捷径可以帮助你开始获得编程工作的旅程,但它们也是阻止你职业发展的一部分。

如果你认为你有必要的技能,但你仍然找不到一份编程工作,你可能会陷入这八个错误中的一个。好消息是它们都是可以修复的。说到底,得到一份编码工作的唯一先决条件是渴望得到一份编码工作。如果你有了这一点,其他一切都在你的掌握之中。

目录:

[**1\. You haven’t mastered the fundamentals of computer science.**](#7078)
  ∘ [Why this means you can’t get a programming job](#af58)
  ∘ [How to solve this problem](#d803)
[**2\. You’re not presenting yourself in a way that demonstrates you’re a good culture fit**](#7906)
  ∘ [Why this means you can’t get a programming job](#16ae)
  ∘ [How to solve this problem](#9ed2)
[**3\. You’re ignoring good interview skills**](#c278)
  ∘ [Why this means you can’t get a programming job](#4236)
  ∘ [How to solve this problem](#ba79)
[**4\. You don’t have experience**](#0a64)
  ∘ [Why this means you can’t get a programming job](#bc94)
  ∘ [How to solve this problem](#5058)
[**5\. You’re trying to master everything**](#2a37)
  ∘ [Why this means you can’t get a programming job](#2ae0)
  ∘ [How to solve this problem](#cb67)
[**6\. You’re pretending to be more talented than you are**](#e6a4)
  ∘ [Why this means you can’t get a programming job](#8e86)
  ∘ [How to solve this problem](#885d)
[**7\. You haven’t demonstrated you want to learn**](#3f55)
  ∘ [Why this means you can’t get a job](#626c)
  ∘ [How to solve this problem](#3f1f)
[**8\. You’re ignoring automated filters**](#085a)
  ∘ [Why this means you can’t get a programming job](#db4a)
  ∘ [How to solve this problem](#921d)
[**Final thoughts on why you can’t get a programming job**](#91c4)

1.你还没有掌握计算机科学的基础。

许多在训练营学习编码的人,不是专注于在线学习计算机科学,而是跳过步骤,不花时间正确地完成它。

这些训练营旨在让你在一定的时间范围内获得一套非常具体的技能。他们的目的不是教你计算机科学的基础——算法、计算机体系结构和硬件、数据结构、数据库和计算理论等等。

我并不是说这些课程是在欺骗你。他们的目的是教授大多数入门级职位所需的最低限度的编码技能。碰巧的是,目的与给你找一份编程工作的目标不一致,这更复杂。

随着越来越多的教育资源出现在互联网上,获得一份没有传统学位的编码工作的可能性越来越大。这意味着更多的计算机科学初学者正在参加为期八周的 Python 新兵训练营,这对初学者来说很容易学习,当他们不能立即找到编程工作时,他们会感到沮丧。

为什么这意味着你找不到编程工作

让我们继续我们的思维实验,假设你如实地说你能在简历上写 Python 代码。这可能会让你有机会进入一家令人兴奋的初创公司——你的梦想——进行面试。在面试中,他们会问你一个关于算法的基本问题,你会完全被难倒。

虽然这些工作申请可能不会直截了当地说“需要理解数据结构的基础”,但这是因为它是隐含的。学习计算机科学的传统途径是在学习任何语言之前先教你基础知识,这有助于你更有效地解释和应用你以后将学到的技能。

雇佣你的人不仅仅是在寻找一个 Python 专家。他们想要一个能完全胜任这项工作的人。他们可以立刻判断出你是否具备完成工作所需的基本知识,或者你是否记住了 Python 代码。这是一个常见的失误,可能意味着你找不到编程工作。

如何解决这个问题

如果你已经在你的训练营或课程上花了时间和金钱,你就不需要回到学校来充分利用你的投资。相反,汇编一份基本清单,并研究它们。这将有助于你在任何语言或课程中利用现有的知识,而不会被基础知识绊倒。

网上有很多资源,有付费的也有免费的,可以帮助你学习积木。无论你是从学位、课程还是训练营获得基础知识,你都不能指望只学一门课程就能找到工作。

2.你没有以一种表明你是一个很好的文化适应者的方式来展示你自己

就我个人而言,我大学毕业后选择数据科学工作的部分原因是因为我像其他许多人一样讨厌销售。虽然每个人都讨厌销售,但当你申请工作时,你必须知道如何在申请过程的每个阶段推销自己。如果你找不到编程工作,可能是因为你忽略了申请过程的这一部分。

人们通常认为,想雇佣你从事编码工作的公司只关心你的技术水平,但事实并非如此。除了你能编写代码的语言、你理解的计算机科学基础知识、你擅长的面试问题,他们还会关注一个重要的方面:文化契合度。

尽管就业市场非常开放,但雇主想要的是不仅擅长编码,而且能为团队和公司整体做出贡献的人。

为什么这意味着你找不到编程工作

程序员有一种刻板印象,他们是那种痴迷的人,把自己锁在寒冷黑暗的地下室里,直到他们的编码项目完成。全栈网络开发人员 Charlotte Bone 在她的博客文章中写道“程序员最喜欢的就是整天坐在黑暗的房间里编码”,这是一种有害的刻板印象。

这可能是一个障碍,因为虽然你想成为一名程序员,但你可能觉得自己不符合这种刻板印象,但仍然觉得你必须为雇主假装这样。或者,如果你确实符合这个概念,你可能会展示自己的这一部分,但忘记雇主不是在寻找编码机器——他们是在寻找员工。如果你找不到一份编程工作,考虑一下你如何展现自己的个性,以及它如何与你的目标公司相契合。

如何解决这个问题

事实是,大多数人,包括程序员和编码员,都不是编码机器——我们是真实的人,除了写代码之外,还有其他的兴趣和爱好。重要的是让这一点在你的简历中表现出来,在面试中,以某种方式表明你不仅在技术上有能力,而且在文化上也非常适合。如果你找不到编程工作,可能是因为你的简历只看编程技能。

你表现出热情、投入和好奇心了吗?你参加过哪些课外活动?你如何包装你的技能来证明你是他们从技术和文化角度都需要的?

花点时间研究一下你未来的潜在雇主,以及现在的雇员表现出哪些非技术素质。这将为你提供最大的机会,从技能和文化契合度两个角度展示你自己。

3.你忽略了良好的面试技巧

同样,如果你找不到一份编码工作,那可能是你忽略了普通而重要的面试技巧。

即使你的简历很完美,即使你在面试中回答了所有的问题,记住你将被作为一个人而不是一台机器来评价仍然是至关重要的。保持眼神交流,表达自信,以及与面试官建立联系等软技能都很重要。

为什么这意味着你找不到编程工作

一些找不到编程工作的人已经厌倦了,因为在理论上,他们拥有完成工作所需的所有技能。但是面试也是对你如何与其他人合作以及如何沟通的一种测试,这一点经常被忽视。

人类不擅长一眼就看出你是否是那种能与他人很好合作的人,但是我们想出了一些给我们一个提示的简写方法。速记是常见的面试礼仪。

npm 的首席技术官 Laurie Hoss 在 Quartz 上写道:“工程师的工作是与团队合作实现更大的目标,如果你不愿意或不能花时间与同事交流,你就只完成了一半的工作。”如果你在面试中没有展示出良好的人际交往能力,你未来的雇主可能会认为你属于那种只能做一半工作的程序员。

如何解决这个问题

如果你已经到了面试阶段,仍然找不到一份编程工作,这可能是一个信号,表明这是一个影响你工作前景的问题。要解决这个问题,在每次面试中都有一个简单的清单,不管是虚拟的还是面对面的,都要达成一致:

  • 进行眼神交流
  • 问面试官一些与工作无关的事情——他们的家庭、下午的计划、宠物。
  • 流露出自信。记住你申请这份工作是因为你认为你是最合适的人选!
  • 在面试结束时,顺便提及你开始时对他们说的话。

这向面试官展示了你不仅是一个优秀的程序员,而且是一个好的面试官,因此也是一个好的沟通者。

4.你没有经验

如果因为这个原因找不到编程工作,也不要太自责。这是一个因雇主发布的工作列表而加剧的问题。似乎每个雇主都需要对一种一年前才出现的语言有至少五年经验的程序员。这导致程序员申请的工作可能会被认为在他们可应用的经验方面有点牵强。

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

推文截图

因为标准高,稍微夸张一点都可以原谅。但是当你申请需要经验的工作时,问题就出现了,你不能证明你的经验来自哪里。这是一个即使是熟练的程序员也找不到编程工作的普遍原因。

问题是多年的经验并不意味着什么。我可能是世界上最懒的程序员,据称有五年编写 Perl 的经验,因为我姐姐拥有这家公司,她没有解雇我。我将拥有与只有一个月工作经验的人完全相同的技能,但她对待工作比我认真得多。

就像良好的面试技巧一样,询问工作经验只是“你知道如何做我们需要你做的 75%的事情吗?”

为什么这意味着你找不到编程工作

想象一下,有人在一堆简历中寻找拥有五年 Python 经验的程序员。他们看到你,像其他人一样,列出了你有必要的五年。

从外表上看,你似乎已经回答了他们的问题。但是他们问的是你是否有解决他们的 Python 问题所需的技能和经验。在这一点上,你是否有一年或五年的 Python 经验并不重要——你需要证明你有相当于这些年的经验。这不仅有助于你回答雇主的实际问题,也有助于你在其他应聘者中脱颖而出。

如何解决这个问题

不,你不需要五年的经验。但是如果你找不到编程的工作,你需要证明你在乎你未来的工作,尤其是如果你之前没有工作经验的话。你做过哪些好玩的项目?你最喜欢它的哪一点?你解决了哪些问题?

你是否有一个博客、GitHub repo 或其他投资组合来展示你对编程的承诺?Ferpection 的首席 JavaScript 软件工程师 nathanal Cherrier 在他的博客文章中列举了一些优势,解释了为什么开发人员应该创建博客:“当你在互联网上写作时,你会比普通开发人员更引人注目。你希望谁会阅读你的帖子?未来的同事?你想去的那家很棒的公司的招聘人员?负责选择你想发言的会议发言人的委员会?所有这些人都会对你的专业技能和编辑技能感兴趣。”

如果你因为缺乏经验而找不到编程工作,分享你的激情是向雇主证明你能做他们需要你做的事情的好方法。

5.你试图掌握一切

同样,就像多年经验中不切实际的要求一样,许多公司在这个问题上推波助澜,列出了每一种潜在的语言和技术技能,也许有一天会在他们的工作清单上有用。如果你找不到编程工作,可能是因为你试图掌握你在工作列表上看到的一切。

问题是有无数的编程语言和技能,一个编程新手可能认为他们必须学习。

相反,在学习支撑每一份核心计算机科学工作的基础知识的同时,你需要推销自己的一个可销售的方面,而不是试图做所有的事情。

为什么这意味着你找不到编程工作

除非你是一个经验丰富的程序员,否则你不可能掌握乔布斯要求的所有东西。(如果你是一名资深程序员,你可能已经有一份体面的工作了!)

如果你刚开始找工作,担心找不到编程工作,你可能会认为你必须掌握他们要求的一切。你不是努力掌握一两项关键技能,而是分散精力,对面试中可能出现的任何问题都有一个大致的了解。但是,你不会精通八种语言,相反,你最终只会对每一种语言都知之甚少。

如何解决这个问题

我喜欢特里萨·迪特里希在她的博客文章中描述她的解决方案的方式,她的博客文章标题是“我从雇佣数百名工程师中学到的可以帮助你获得下一个职位。”在这篇文章中,她写道,许多工作清单都有夸大的要求,似乎涵盖了天底下的一切。

如果你找不到一份编程工作,她的解决方案是制作一份你感兴趣的工作的电子表格,以及每份工作需要的核心技能。很有可能你会很快发现一些共性。这将给出你的答案,说明最有可能帮助你得到这份工作的技能,即使他们列出了 20 个其他的“要求”

你找不到编程工作的部分原因可能是,当你被要求做所有的事情时,你只能证明掌握了很少的几件事情。通过减少噪音和传递这些公司正在寻找的信号,你可以得到你梦想中的编程工作。

你最喜欢什么语言?你最了解哪一个?这些答案将有助于开始为你指出正确的方向——无论是哪种工作符合你现有的技能,还是如何在你的简历和面试中推销这些技能。

6.你假装比实际上更有才华

当然,找不到编程工作的人可能会不顾一切地夸大事实,试图涵盖每一点。尽管工作列表有时可能不切实际,但这是意料之中的事情。但这实际上可能会阻止你找到一份编程工作。

好消息是,虽然雇主确实想要一个有能力的员工,但这并不意味着他们需要你做他们在工作要求中列出的所有事情。

为什么这意味着你找不到编程工作

当你修改简历和求职信时,你试图通过夸大事实来满足那些不切实际的要求,看起来好像你是他们要求的所有事情的大师。面试官可以从你的简历中看出这一点,即使你得到了面试机会,他们也一定会发现的。

最明确地说,你不可能骗过有经验的程序员和面试官。虽然工作清单看起来高不可攀,但这并不意味着你应该假装拥有更多你不具备的经验、知识或技能。最好的情况是,你被一份压力很大的工作录用了,但你不能胜任。最糟糕的情况是你找不到编程工作,浪费时间去申请一份你不适合的工作。

如何解决这个问题

牢记你未来雇主的目标。就像多年的经验一样,他们不需要你勾选每一个选项。他们只想雇佣最有能力完成工作的人。

无论是在求职还是面试中,坚持你所知道的,你就能发挥你的优势。诚实面对你的技能和局限。只要你能证明你能做他们需要你做的事情,你就有机会。

假设一个雇主遇到了两个候选人:一个说他们可以做一些他们不能做的事情,另一个说这超出了他们目前的技能范围,但展示了他们在过去一年中如何提高了技能。后者对雇主更有吸引力。如果你找不到一份编程工作,考虑一下如何削减你所谓的技能,让它尽可能真实。

7.你没有表现出你想学习

有趣的是,LinkedIn Workplace Learning 的 2020 年报告显示,最受欢迎的技能根本不是技术技能,而是软技能。他们推测,原因是因为技能老化得很快。一项重要的技能今年是多余的明年。软技能,就像计算机科学的基础知识一样,是其他所有可能吸引雇主的技能的基础。

这意味着学习能力比你能展示的其他技能更重要。大多数雇主希望雇佣一个他们只需要最低限度培训的候选人,因为你可以打赌新的技术能力年复一年都是必要的。要成为一个理想的候选人,一旦你展示了你的核心技能和主要才能,证明你仍然对学习感兴趣。编程不是一个一成不变的职业。新的技术、语言和技能不断涌现。你需要充满活力才能保持领先。

为什么这意味着你找不到工作

让我们假设你是一个完美的候选人,拥有他们要求的每一年的经验,每一种语言,并且能够证明对计算机科学的基础有坚实的掌握。如果你仍然找不到一份编程工作,即使一切都对你有利,那可能是因为你没有表现出你想学习。

如果你的简历不能证明你仍然对学习新技能感兴趣,如果你在面试阶段没有表现出获取知识的热情,即使今天你是完美的候选人,明天你也会被淘汰。

想从事编码或编程工作的人可能会专注于艰苦的技术技能,因为这些技能更容易证明。但是如果表现出学习的愿望只是事后的想法,这可能是你找不到编程工作的一个原因。

如何解决这个问题

幸运的是,大多数程序员喜欢学习。你必须这么做,尤其是如果你没有获得传统的计算机科学学位。这就是更非传统的背景可以派上用场的地方——通过参加课程或获得证书,这是展示你对学习的奉献精神的一个很好的方式。

了解最新的编程趋势也是一个好主意。你不必表现出对它们的完全掌握——事实上,那是浪费你的时间——但是通过表现出对编程趋势的兴趣,你可以表现出你喜欢学习和紧跟计算机科学领域的潮流。

最后,不要局限于只表现出对学习计算机科学的热情。你还喜欢学什么?乐器、口语、水彩技巧等等都可以展示你对学习的热爱。

8.你忽略了自动过滤器

如果这个错误列表中没有一个适合你,而你仍然找不到一份编程工作,那可能是因为技术在与你作对。尽管大多数申请编程或编码工作的人都是技术性很强的,但人们很容易忽视招聘过程是自动化的这一事实。以亚马逊为例,他们在 2018 年陷入困境,当时发现他们的招聘人工智能错误地显示出对女性的偏见。由于自动化的缺陷,许多合格的个人甚至没有人看他们的简历。

撇开有问题的人工智能不谈,考虑这样一个事实:很多时候,你的申请甚至没有被人力资源或招聘人员看到,因为他们已经应用了过滤器,以尽量减少合理数量的候选人的工作量。通过使用关键词来缩小名单,他们尽最大努力在被人看之前筛选出最不适用的简历。

为什么这意味着你找不到编程工作

很多有天赋的程序员不擅长针对关键词优化简历。这本身就是一种技能。虽然这可能会让 HR 的工作变得更容易,但这确实意味着你找不到编程工作的原因不是因为你的任何不足,而是因为你没有在简历上按正确的顺序放置正确的单词。

不幸的是,如果你正在努力寻找一份编程工作,你不能忽视这些自动过滤器,并认为你的天赋会大放异彩。不管你喜不喜欢,你可能不得不玩一会这个游戏来获得你理想的编程工作。

如何解决这个问题

如果你怀疑这是你找不到编程工作的原因,有两种方法可以确保你不会被机器忽视。

首先,也是最显而易见的,优化你简历的关键词。再看一遍求职申请,用公司的话勾掉你在简历上写的每一项。Balance Career 关于简历关键词的博客文章还建议确保你的简历反映了公司的品牌,这是他们与众不同的地方,所以试着查看他们的 LinkedIn 页面,以及当前员工的 LinkedIn。

第二种方法不太直观:记住招聘者也是人。你可以把你的简历扔进一堆,希望有人会看你的简历,或者你可以多走一步,找到一个职位相似的现任员工、招聘经理,或者你的老板,给他们发一条简短的 LinkedIn 信息。你可以表达对这个职位的热情,问一些关于当前职责的问题,甚至只是让他们知道你刚刚申请了这个职位,并期待着回音。

这是让他们注意到你的一种方式,如果你的简历出现了,确保你的名字已经很熟悉了。永远不要忘记人情味是很重要的。

关于你为什么找不到编程工作的最后想法

有可能在两个潜在阶段被拒绝:获得面试机会和面试后获得工作机会。如果你找不到编程工作,为了最大化你的机会,看看你在哪里挣扎,并在那里应用相关的技巧。

总的来说,这个建议可以归结为:记住人类技能仍然是重要的。不要撒谎。坚持自己的优势。首先介绍一些基础知识。

如果你能做到这一点,你就解决了找不到编程工作的主要原因。

继续努力,记住:雇主对优秀程序员的渴望就像你对一份好工作的渴望一样。你所要做的就是向他们展示你是他们梦寐以求的候选人。

原载于 2021 年 1 月 18 日https://qvault . io

货物列车的能力优化(一)

原文:https://towardsdatascience.com/capacity-optimization-in-freight-trains-part-1-4918f35a6433?source=collection_archive---------14-----------------------

Python 中的货物列车能力优化指南

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

图片由 Gabriel SanchezUnsplash 上拍摄

铁路货运和任何其他形式的大众运输一样复杂。它与航空货运密切相关,因为它们都需要优化空间以提高效率,并最大限度地减少运行时间。当货运列车与客运列车使用相同的轨道时,运行服务的最小化甚至更加重要,尤其是在城市环境中。因此,需要在不同地点之间运行最佳数量的列车服务,因为这将:

  1. 省钱- 使用最佳数量的集装箱运行一项服务比使用相同或稍多数量的集装箱运行多项服务更经济。服务路线上的人力可以重新分配到其他需要的地区。
  2. 预留时间段分配 —允许将预留时间段分配给其他服务,如客运列车,在高峰运行时间更是如此。

理想情况下,只有最大限度地利用可用货运服务的货车空间,才能最大限度地减少列车服务。

定义:

为了更好地理解手头的问题,与铁路货运相关的几个术语定义如下:

  1. 机车——这是火车的引擎,在铁轨上牵引货车。列车的长度(车皮数量)和它们的累计重量将决定要使用的机车类型,因为它们的牵引力不同。
  2. 货车—这是一种被牵引的拖车,设计用于沿铁路轨道移动,在大多数情况下用于运输集装箱。它们在大小和性质上有所不同,例如,平顶集装箱可以很容易地装卸。
  3. 集装箱——这些是用来装载物品的单位。理想情况下,货物只是装在里面,然后在不同地点之间移动。有不同的尺寸,20 英尺和 40 英尺的集装箱是最常见的。更全面的尺寸列表可以在这里找到。

问题陈述:

是否有可能优化现有货车上的集装箱容量,火车服务中的所有不同尺寸?

容量优化:

通常,一列火车拉几辆不同尺寸的货车,其中一些装有不同尺寸的集装箱。因此,需要最大化适合集装箱的容量和可用货车容量。这将导致与装载、卸载和其他一般操作成本相关的成本降低。此外,根据既定时间表进行的旅行次数最终将会减少。

我将举例说明如何根据铁路货运中使用多个背包的可用集装箱和可用货车容量来实现这一优化过程。

背包问题:

背包问题可以用一个购物领域的例子来说明。假设你去当地的超市,你被随机选中,从货架上挑选尽可能多的商品,放进你的购物袋。这个购物袋的容量是最大的。作为该过程一部分的条件如下:

  1. 你只能挑选一整件物品。因此,不能以任何方式拆分项目。
  2. 一旦你的购物袋满了,你就不会再拣东西了。

这里的理想/最佳选择是考虑被拣选物品的大小和价值。比如,比起杯子,挑选更多的首饰会是更好的选择。遵循这一最佳过程可能会产生一个装有许多更有价值物品的购物袋(背包)。这个优化过程可以应用于不同的业务问题,如本文 中所述。

多背包四轮拖车:

背包问题可以在优化火车运力中复制。理想情况下,每节车厢都是一个,在列车服务中大小不同。当最大数量的集装箱装在可用的货车上时,将实现最优化。因此,每辆货车将是一个背包,它必须适合与货车容量成比例的最大数量的集装箱。

数据:

该实验中的数据涉及以下参数:

A)重量/尺寸/槽数——具有容器重量的向量(一维列表,即数据行)。这里,每个集装箱的箱位数将被假定为重量。例如,一个 40 英尺的集装箱在一辆货车上占了四个位置。

b)值—这是一个包含单个容器值的向量。这些值重视每个容器。因此,这个向量的长度应该与权重/大小的长度相同。例如,我们可以假设目的地最需要的集装箱价值更高。或者,可以认为 40 英尺集装箱比 20 英尺集装箱更重要。在这种情况下,它们会有更高的价值。

c)容量——包含货车容量的向量。在这种情况下,四轮拖车是多个背包。因此,每个货车的容量(槽数)必须在向量中表示。

下面的代码展示了上述数据点是如何生成和表示的。数据中的值是相同的。这意味着所有的容器都同样重要。

要解决混合整数规划(MIP)问题,必须完成以下步骤:

  1. 导入线性求解器包装器,

  2. 声明 MIP 求解器,

  3. 定义变量,

  4. 定义约束条件,

  5. 定义目标,

  6. 调用 MIP 求解器

  7. 显示解决方案

  8. 导入并声明线性求解器:

下面的代码使用 Google 的 或-Tools **为这个问题定义了 MIP 求解器。**使用 求解约束整数程序(SCIP) 后端。OR-Tools 是一款用于组合优化的开源软件,旨在从一个非常大的可能解决方案集合中找到一个问题的最佳解决方案。命令 $ python -m pip 安装—升级—用户或工具 将为 python 安装或工具。这可以在激活的环境中运行。然后,您将能够运行下面的代码来导入和声明线性求解器。

2。变量定义:

下面的代码为这个问题创建了变量。

i 是集装箱 j 是旅行车(个人背包)。因此,如果集装箱 i 放在货车 j 上,x[(i,j)]的值为 1。如果不是,那么该值将为 0。

3。定义约束:

对于这个问题,约束如下:-

  1. 每个集装箱最多只能放在一辆货车上。为了定义这一点,所有货车上的 x[i][j] 之和 j 必须小于或等于 1。
  2. 货车总容量不能超过货车限制。这意味着集装箱的重量(箱位数)不能超过货车的箱位数。例如,一辆 60 英尺的货车有 6 个插槽。因此,它可以装载一个 40 英尺(4 个箱位)和 20 英尺(2 个箱位),或三个 20 英尺,或一个 20 英尺,或一个 40 英尺的集装箱。集装箱箱位总数不能超过货车。

定义约束的代码如下

4。定义目标:

这个优化问题的目标函数是最大化装载集装箱的总价值。这基于每个容器的槽数/重量和值,如以下代码中所定义:

此外,只有当集装箱放在货车上时,集装箱的价值才适用。否则,它不会有助于最大化安装在每个货车上的集装箱的总价值的目标。

5。调用 MIP 求解器并显示解

对于每辆货车,将输出集装箱编号及其总重量和价值。总的来说,每个集装箱的总价值和重量也会显示出来。输出在下面的代码中生成:

包含上述代码片段的完整程序如下:

13 辆四轮拖车上集装箱的优化布局如下:

结论:

上述代码的输出是通过分解要放在货车上的集装箱的价值和重量来最大化货车上可用空间的指南。在本例中,所有容器的值都相同,无论其大小如何。这可能不是商业设置中的确切情况。例如,每个集装箱的重要性值可以基于集装箱到达目的地的紧急程度等。在本文的第 2 部分中,我将结合一家铁路公司的列车计划中的真实数据,来看看这个优化过程在多大程度上有助于在不同地点之间将尽可能多的集装箱装载到货车上。敬请关注。

基于真实数据的货物列车能力优化(二)

原文:https://towardsdatascience.com/capacity-optimization-in-freight-trains-with-real-data-d21296e2b56?source=collection_archive---------12-----------------------

Python 中真实货运列车数据的能力分配和优化完全指南

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

Unsplash 上由 Andrew Coop 拍照

这篇文章是我之前关于货运列车运力优化的一文的续篇。我承诺利用一个真正的货运列车服务和预订数据集。理想情况下,目标仍然是最大化路线间可用货车的集装箱数量(与预订相关)。

资料组

数据集是根据一家货运列车公司的定时时刻表生成的。它分为两部分,持续时间为一周。出于规划目的,此设置中的数据集是为下周准备的。数据集可以在 这里 **下载。**是一个 XLSX 文件,有两组数据;服务和相关预订。下面的代码以两个数据帧(services_df 和 bookings_df)作为输出接收数据,将服务与预订分开。

来自两个数据帧的样本在以下部分中:

(a)服务 —数据集的这一部分具有特定于可用服务的细节。如表 1 所示,服务、日期、始发地、目的地和二十英尺当量单位(TEU)的数量构成了数据集的这一部分。

表 1:示例服务数据

(b)预订— 预订数据集的示例详细信息如下表所示。必填日期字段必须在服务到达时间范围内。

表 2:预订数据示例

扩大预订

设备计数(EQCOUNT)显示每次预订(BOOKING_ID)使用的集装箱数量。理想情况下,跨越多个容器的所有预订都应该被扩展。例如,带有四个 40 英尺集装箱的 Booking_ID 012QRTLL0662 应该扩展为四个记录。这样,在考虑到第部分第 1 中提出的所有约束条件的情况下,使所有可用集装箱适合货车可用容量的最大化目标必然会实现。

此外,还需要唯一地标识复制的记录。这有助于根据可用容量将已分配的预订与未分配的预订分开。下面的代码扩展了多台设备的预订,并根据每个集装箱的大小生成 BOOKINGRANK 和 slot count。还添加了一个到达日期时间上限列作为条件之一。作为一个预订的限制,到达时间上限被设置为所需时间之前的 12 小时,以允许放置和最终取货。这个时间是可以调整的。预订等级基本上是重复记录的累积计数。因此,带有四个 40 英尺集装箱的 Booking_ID 012QRTLL0662 将具有值 1、2、3 和 4 作为这四个记录的 BOOKING_RANK。BOOKINGRANK_ID 是 BOOKING_ID 和 BOOKING_RANK 的合并。这将有助于唯一地识别每个预订,而不管其在集装箱中的分布。

服务详情

与预订一样,服务也有所扩展,但以标准箱容量为基础。这是一种可以根据服务而变化的安排,因此,在解释该数据时需要灵活性。在该数据集中的服务部分,任何 99 TEU 容量的服务包括 31 辆 60 英尺货车和 3 辆 50 英尺货车。然而,Y326 和 H320 这两种运力分别为 70 和 40 TEU 的服务只有 50 英尺的货车运力。此设置特定于此数据。然而,它可以根据列车服务计划进行调整,以适应任何其他设置。

此外,还纳入了服务的出发和到达时间,以根据预订中的货运所需时间计算服务到达窗口。此后,服务移动时间和相关货车容量的每日计算假定为多个背包,其中预定的集装箱符合最大化目标。

使用以下代码生成服务的货车容量详细信息。然后,通过最大化功能安装与预订相关的容器。

将预订合并到选定的服务

这个过程很棘手,因为两个数据帧中没有共同的标识符。因此,唯一的解决方案是根据日期值合并它们。理想情况下,要合并到预订细节中的服务应该有一个尽可能接近的到达日期,并且不晚于到达日期上限。为了合并这两个数据帧,我使用了 Pandas 中的https://pandas.pydata.org/pandas-docs/version/0.25.0/reference/api/pandas.merge_asof.html合并功能。正如链接中所解释的,该函数的工作方式与左连接类似,只是匹配是在最近的键上,而不是在相等的键上。还为每个容器添加了一个公共值,表示每个容器和订单重要性的均匀性。下面的代码复制了上述过程:

把所有东西放在一起

最终的数据模型包括如上所述的服务和预订数据。下面的函数总结了两个数据帧所需的输入。该函数的输出是一个字典,其中包含所有用于计算容量利用率的值。

变量、约束和目标函数

容器和货车值作为变量的声明如下面的代码所示。约束条件的定义方式是每个集装箱最多只能放在一辆货车上。此外,每辆货车的包装数量不应超过货车的总容量。多个四轮拖车重复相同的过程。目标函数设置为根据集装箱的重量(箱位计数)和价值,最大化货车上的集装箱数量。

输出

以下代码的输出是一个数据帧(表 3 中的示例),其中详细说明了在特定日期火车服务上可用货车的集装箱分配情况。

由上述代码生成的的数据帧 df 的输出示例如下

表 3:样本分配输出

未分配的集装箱和预订

当集装箱和相关箱位的数量超过货车箱位时,很明显其中一些不会被装载到可用的货车上。前面生成的 BOOKINGRANK_ID 被用作列值,以将容器的原始列表合并到已分配的预订中,因为它是唯一的,即使对于重复的预订也是如此。合并后具有空值的记录是未分配的记录。理想情况下,可以为它们分配更高的重要性值,以便在第二天重新运行分配最大化流程时触发优先级检查。

结论

输出是一个集装箱表,其中包含已分配给货车的预订以及未分配的预订。该实验中的数据是模拟列车运行数据的真实数据集,即列车服务和相关预订。尽管容器间的重要性值一致,但求解器仍实现了优化。所有 20 英尺的集装箱都被分配,因为与以最大化为目标的 40 英尺和 20 英尺相比,将三个 20 英尺的集装箱装载到一辆 6 槽货车上是合理的。相反,所有未分配的集装箱都是 40 英尺长。它们占据了很大一部分车厢空间,因此总体上不会最大化空间和数量。一般来说,如果重要性值多样化,则与当前分配相比,必然会平衡分配。

通过保持联系linked ln

代码片段可以在 这里找到

机器学习、Python 音乐和人工智能大脑连接的职业生涯

原文:https://towardsdatascience.com/careers-in-machine-learning-python-music-and-ais-brain-connection-a40a3fd7fab1?source=collection_archive---------27-----------------------

几分钟的阅读能改变你的生活吗?我们当然这样认为:当我们阅读时,我们学习,我们向灵感敞开心扉,我们与他人的经历联系在一起。不相信我们?直奔尤金·严奇普·胡延的令人振奋的 Q & A,在这里奇普分享了太多有价值的见解(关于机器学习和进入斯坦福,是的——但也关于设定目标和通过写作找到社区)。你不会想错过它的。

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

Camille Vandoorsselaere 在 Unsplash 上拍摄的照片

本周必读书目

许多数据科学家开始认为机器学习职业生涯围绕着精通和专业知识。当然有,但是如果没有大量的所谓“软”技能,这是远远不够的。从哪里开始?马特·索斯纳

当然,如果你做不出有价值的工作,人脉和商业头脑只能帮你到此为止,而这本身往往依赖于高度专业化的知识。“专业的”,虽然,不应该意味着“密封和充满行话。”我们喜欢这样的帖子,它不仅展示了我们社区中令人难以置信的才华,还清晰地传达了作者的技能。像…这样的帖子

…还有许多其他的。

万一所有的实际操作阅读让你有后退一大步的心情,我们已经为你准备好了。坐下来吃你选择的小吃,并犒劳自己马克·萨鲁菲姆关于机器学习现状的发人深省的辩论,包括坚定地看看这个领域中不再充满活力的部分。

如果你错过了:来自 TDS 团队的最新消息

我们最近的作者聚焦精选Julia Nikulski—Julia目前正在德国完成硕士学位,她分享了从金融分析师到数据科学家的旅程中的见解和技巧。她强调找到正确的学习节奏,平衡远大目标和现实期望的重要性。为什么开始你的职业转换已经烧坏了?

与此同时,在 TDS 播客上,主持人 Jeremie Harris 与多学科研究员 Georg Northoff 在 T2 进行了一次对话,这次对话触及了千百年来人们一直在问自己的一个最重要的问题:什么是人类意识?随着人工智能的最新进展,从事哲学、精神病学和神经科学交叉研究的 Northoff 希望我们最终能够开始理解大脑如何运作和学习。

虽然我们可能还远未解开人类意识的奥秘,但我们非常清楚自己的一些基本情感。其中之一是感激,我们从未停止对你们,我们的读者的感觉。感谢你的支持——这让我们的工作和这个社区成为可能。

直到下一个变量,
TDS 编辑器

我们策划主题的最新内容:

入门指南

实践教程

深潜

思想和理论

Caret vs. tidymodels 创建可重用的机器学习工作流

原文:https://towardsdatascience.com/caret-vs-tidymodels-create-complete-reusable-machine-learning-workflows-5c50a7befd2d?source=collection_archive---------13-----------------------

实践教程

两个软件包之间的人力资源分析之战

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

照片由乔纳森·托马斯Unsplash 上拍摄

如果你在 R 中使用机器学习模型,你可能会使用 caret 或 tidymodels。有趣的是,这两个软件包都是由同一个作者开发的:Max Kuhn。但是它们在可行性和性能方面如何相互比较呢?

你可能想知道你应该为 R 中的预测建模学习哪个包。有一件事是正确的:Caret 是 R 的传统机器学习包,而 tidymodels 对 R 社区的部分成员来说是相当陌生的。因此,它对我来说是新的:一个智能媒体用户向我推荐 tidymodels,以便自动化我在上一篇教程中展示的特性预处理部分。尽管我有点怀疑,但我还是尝试了一下,看看它是否比 caret 更好。最近,我挑战自己,用 caret 在一个小的模拟数据集上预测员工流失——这也是用 tidymodels 尝试的一个完美案例。这也是一个非常现实的例子,因为行业中的一些大公司已经应用预测分析来减少流失并增加他们宝贵人才的保留率。使用数据挖掘技术,可以使用历史和标记的员工数据来检测与人员流动相关的特征(上次加薪、商务旅行、人与工作的匹配、离家的距离等)。).因此,该算法使用过去的数据进行训练,以预测未来。这也可能是一个严重的问题,因为它很容易导致歧视性偏见。因此,当一个预测模型被应用时,在它已经过时并犯下严重错误之前,必须不断地对它进行评估。尽管如此,如果我们深思熟虑地使用它们,我相信数据分析的使用可以成为一个强大的工具,以改善工作场所。

为什么是 tidymodels?

由于用户使用 R 中可用的各种机器学习算法的方式略有不同,Max Kuhn 旨在开发一个统一的机器学习平台,该平台允许一致的和可复制的代码。在 R 社区中,当 Max Kuhn 也在 2020 年开发 tidymodels 时,优秀的老 caret 已经扮演了最先进的包的角色一段时间——可以说是 caret 的 tidyverse 版本。类似于 dplyr-syntax(包括%>%,mutate()等。),tidymodels 基于这样一种思想,即在工作流中构建您的代码,在工作流中每个步骤都被明确定义。这是直观的,并允许你按顺序跟随你的程序实际做什么。许多功能都是从 tidymodels 中已经包含的几个核心包中借用的,因此可以认为它是一个元包:

  • rsample :用于样本分割(如训练/测试或交叉验证)
  • 配方:用于预处理
  • 防风草:用于指定型号
  • 尺度:评估模型
  • 刻度盘:用于超参数调谐
  • 工作流程:用于创建 ML 管道
  • 扫帚:整理模型输出

因为 tidymodels 使用了这些包,如果您已经熟悉它们,那么学习起来会更容易,但这并不是真正必需的。

请注意:如果你只对编码部分感兴趣,你可以在我的 GitHub 库这里找到完整的脚本。

著名的 IBM HR 分析数据集入门

我们将在案例研究中使用的数据集是由 IBM Watson Analytics 创建的模拟数据集,可以在 Kaggle 上找到。它包含 1470 个雇员条目和 38 个共同特征(月收入、工作满意度、性别等)。)—其中之一是我们的目标变量(员工)流失(是/否)。在定义了一个 R-project 之后,我们可以使用简洁的 here-package 来以一种简单的方式设置我们的路径,这种方式更能抵抗本地机器上的变化。让我们看看我们的原始数据。

免责声明:所有图文均由作者制作,除非特别注明。

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

没有遗漏任何观察值,skim 函数给出的总结显示了一些描述性统计数据,包括平均值、标准偏差、百分位数以及每个变量的直方图(26 个数字;9 个字符)。在现实世界中,我们可能永远不会有如此干净完整的数据集,但我们仍然有另一个相当现实的问题:似乎有 237 名员工(16%)离开了公司,而大多数人(几乎 84%)留了下来,因此阶层并不均衡。类别不平衡需要特殊处理,因为使用常规性能指标(准确性、AUC ROC 等)来优化和评估模型的性能是不方便的。).其原因如下:由于准确性是所有案例中正确分类的案例的比例,所以即使算法简单地将所有案例分类为多数类(例如,否),即使它们中的一些实际上属于少数类(例如,是),算法给我们高分也不是什么大事。但是在我们的案例中,我们非常关心积极的案例,因为没有正确识别员工将会离开(例如,敏感度或真实积极率)比意外预测员工将会离开(如果此人实际上留下了)(假积极率或 1-特异性)更有害。因此,我们将使用 F1 分数作为训练优化的准确性指标,因为它对正确分类积极案例(例如,员工流失)赋予了更大的重要性,并提高了模型在严重不平衡数据集中的性能。

作为第一步,我们可以计算任何附加特征。被认为不公平的报酬会影响一个人离职寻找更好报酬的意愿(哈登、博阿凯和瑞安,2018;萨卡尔,2018;布莱恩特&艾伦,2013)。这就是为什么我们想要创建另一个变量来表示每个员工月收入的支付竞争力,其背后的推理是,员工可能会将自己的收入与相同职位级别的同事进行比较。一个认为自己的薪酬公平的人,与一个在类似职位上薪酬低得多的人相比,不太可能离开公司。为此,我们将使用 data.table 语法首先按职位级别计算薪酬中值,并为每个观察值存储适当的值。然后,我们将每个员工的月收入除以收入中值,得到他或她的薪酬比率:这是一个直接代表该人相对于工作级别预期的薪酬的衡量标准。因此,1 分意味着该员工完全符合该职位的平均薪酬。1.2 分意味着员工的工资比平均工资高 20%,0.8 分意味着员工的工资比每个工作级别的正常工资低 20%。下一步,我们去除所有不太可能有任何预测能力的变量。例如,employee-ID 不能解释员工流动率的任何有意义的变化,因此现在应该在其他变量中删除它。Tidymodels 为我们提供了机会来为变量分配角色,例如这样一个 ID 列来保留标识符,同时仍然将其从以后的实际建模中排除。但是我们希望在这里手动执行,以便对 caret 使用相同的训练数据(在 caret 中我们不能分配角色)。我们希望排除的其他变量示例是那些明显多余的变量,因此可能会导致多重共线性问题(例如,小时工资和月收入)。然后,我们通过同时将所有字符串变量(例如,Department)正确转换为因子来保存缩减的数据集。

分成训练和测试数据

训练数据必须用于拟合我们的模型和调整我们的超参数,同时我们保存一些测试数据用于我们的最终模型评估。为什么?我们可能会遇到这样的问题,使我们的模型过分适合特定于样本的数据,这样我们以后就不能将它应用于新的雇员数据。这个问题通常被称为过度拟合——这种现象可以解释为什么我们有时无法再复制以前发现的效果。对于机器学习模型,我们经常将数据分成训练集和验证/测试集来克服这个问题。训练集用于训练模型。验证集用于估计模型性能,以相应地调整超参数。最后,保存测试集,以挑战模型从未见过的数据的预测准确性。对于 tidymodels,可以使用initial_split()进行第一次粗略分割,它提供了一个与主数据集相关的分割索引列表。我们将 70%的数据用于训练,剩下的 30%用于测试。分层与目标变量一起使用。这意味着我们让每个模型都有机会在相同比例的课程上接受培训和测试(例如,16%是,84 %否)。类似地,caret 的 createDataPartionining()函数自动使用 outcome 变量来平衡拆分中的类分布。通过设置list = FALSE,我们确保函数返回一个矩阵而不是一个列表。因此,我们可以使用熟悉的 data.table 语法在主数据集上使用随机组合的索引。为了使模型对新数据更具普适性,我们可以使用统计工具箱中的另一个魔术:各种拆分的交叉验证。随后,我们将经过训练的候选模型应用于一组额外的观察值,并反复调整参数以减少预测误差。这些额外的观察值是来自训练数据的几个随机样本,每次都会遗漏一些数据。这使得数据的多重折叠来验证超参数。我们重复这个过程 3 次,并对性能进行平均,以获得我们的模型性能的初步估计——一种被称为三重交叉验证的重采样技术。Tidymodel 的vfold_cv()为我们做了这项工作——我们定义了应该创建的折叠次数以及应该用于重采样的重复次数。当我们使用 caret 时,我们可以使用createFolds()函数来达到同样的目的,但是为了我们的比较,我们做得更好:tidymodels 包括一个名为rsample2caret()的函数,它将我们已经在 tidymodels 中制作的折叠转换为熟悉的 caret 格式。得益于rsample2caret()caret2rsample()命令,您可以轻松地在您喜欢的任何包中使用相同的重新采样。通过这种方式,我们在每个框架中计算的性能指标偏差更小,更具直接可比性。

控制预处理步骤

现在,我们使用菜谱为 tidymodels 建模准备数据:想法很简单——我们创建一个包含所有预处理步骤的对象,这些步骤用作烘焙精心准备的数据集的配料。这样,我们的数据就可以被模型接受了。我们需要注意预处理步骤的顺序,因为它们是按照输入的顺序执行的(例如,在创建虚拟变量后归一化数值预测值没有多大意义,因为 0 和 1 也被视为数值)。你可以把一个菜谱想象成一个蓝图,在实际执行之前,勾画出我们的模型公式、变量编码和预处理步骤的逻辑。这个配方随后被包含在工作流中——一种可以被认为是一种分析管道的结构,它将您自己预先指定的特征工程步骤与模型规范捆绑在一起。在我们的研究中,我们希望创建虚拟变量,移除方差接近于零的变量以及已经与类似变量高度相关的变量,以处理多重共线性。此外,我们应用随机过采样来处理从 themis 封装借用的类不平衡。由于在我们的数据集中,负面案例比正面案例多得多,我们可以假设我们的模型不会有很好的机会来学习如何识别少数类。ROSE 算法可以通过生成模拟我们真实积极结果的具有积极结果(例如,离开公司)的人工附加观察来处理这一问题。所以,这些职业更加平衡了。如果你感兴趣的是职业不平衡会在多大程度上改变你的性能指标,看看我的 GitHub repo 并运行bal_log_example.Rimbal_log_example.R.

Caret 在训练时负责所有的特征工程步骤,甚至自动处理虚拟编码,所以我们不需要在后面的 train()调用的预处理参数中指定这一点。caret 的预处理选项的一个缺点是没有选择转换特定变量(例如,某些数字变量)的选项。为了使用与 tidymodels 示例中相同的上采样技术,我们需要对由 ROSE 包导入的训练数据使用单独的函数。这里我们需要小心—不管出于什么原因,函数交换了目标变量的因子级别,这可能会影响以后的性能指标。为了避免这种情况,我们再次手动分配因子级别,使第一个级别为正类。

指定模型并设置超参数调整

为了在 tidymodels 中创建适当的模型,我们首先使用一个包含公式以及预处理步骤逻辑的配方。这个配方随后被包含在工作流中——一种可以被认为是一种分析管道的结构,它将您自己预先指定的特征工程步骤与模型规范捆绑在一起。parsnip 包帮助我们告诉程序使用哪个特定的模型。您还可以通过调用set_engine()告诉模型使用哪个底层算法来将“引擎”连接到模型规范(Bayesians 可能很乐意听到您甚至可以使用 stan )。通过将超参数设置为tune(),我们已经确保它们被标记为稍后进行调优。如果我们已经知道使用哪个设置,因为它在过去工作得很好,我们也可以将它直接传递给模型规范(例如,如果我们想要有 200 棵树)。如果我们使用 caret,这一步是不必要的,因为我们只是将模型类型传递给 train 函数的方法参数。然后用 caret 的默认调整范围调整超参数,通常会产生非常好的结果。假设您对 caret 为 glmnet 使用的调优范围感兴趣,您可以使用getModelInfo(“glmnet")[[1]]$grid。使用 tidymodels,我们接下来需要使用 parsnip 中的 parameters 函数准备一个 param 对象。然后,我们将它们传递给我们选择的网格函数——这里我应用了一个不规则网格来寻找接近最佳的参数组合。相比之下,网格搜索将遍历所有可能的参数组合并评估它们的相关模型性能,当网格中没有表示最优解时,它会很快变得计算成本高且效率低。使用不规则网格,尤其是所谓的“空间填充设计”,我们更有可能更快地找到一个好的组合,同时仍然覆盖整个参数空间。

组合多个模型

显然,将多个模型集成到一个对象中的想法对于 tidymodels 来说并不新鲜!在设置了预处理方法和模型规范之后,我们创建了一个工作流,该工作流将我们之前定义的用于准备和建模数据的所有步骤捆绑在一起,并在一个调用中完成这些步骤。但是我们甚至更进一步。我们创建了一个包含多个工作流的更加丰富的对象。这些工作流(例如,配方、配方、模型)以某种方式交叉,以后可以在单个请求中对它们进行调整。在我们的例子中,我们尝试了几个模型,xgboost 和 glmnet,但是这可以很容易地扩展。这个工作流集现在是我们一次训练多个模型的主结构。通过使用 option_add,我们将我们的不同的定制网格传递到我们的 workflowset 的 option 列中,以修改默认的调优范围。我们可以使用来自 parsnip 的 Github 代码来找出哪些调优参数是可用的,并与来自 caret 的我们习惯使用的参数相对应。

比较模型性能

在我们开始调优 tidy 模型之前,我们保存了一组性能指标,这些指标应该用于评估模型的优劣。现在我们使用 workflow_map 来实际调优不同的模型。

为了在 caret 中指定我们的超参数调整,我们将包括所有预处理步骤在内的所有内容包装在一个 trainControl-Object 中。

不幸的是,不可能使用 F1 作为我们的优化指标:因此,我需要编写一个定制函数来使它工作。

与 tidymodels 不同,没有预先指定的方法来一次适应和调整不同的模型。因此,我们可以编写自己的函数来完成这项工作:我们首先创建一个名为 train_model 的自定义函数,作为 caret 的 train 的包装器,但带有一个方法占位符。然后我们使用lapply()将我们的自定义函数应用到一系列方法上。这些包含了我们想要相互比较的模型类型。这种方法的好处是,我们可以随时轻松地调整或扩展列表。

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

正如我们在上面的模型对象中看到的,XGBoost 有 108 个参数组合的调优结果,glmnet 有 9 个。这是 caret 自动选择的默认值,也是我之前为 tidymodels 指定相同调优大小的原因,以便在两者之间进行公平的比较。tidymodels 的调优结果与上面显示的 caret 的嵌套调优输出具有相似的结构,只是它们为我们提供了更多的性能指标。只需调用以下内容:

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

跟踪时间(可选)

在试验这两个框架时,我意识到与 caret 相比,tidymodels 中的调优过程要花费更多的时间。两个软件包都处理了大量的候选模型 XGBoost 的 108 个组合* 10 次折叠* 3 次重复= 3240 次迭代,glmnet 的 9 个组合* 10 次折叠* 3 次重复= 270 次迭代。不管怎样,这应该是非常占用 CPU 资源的,但是软件包是如何处理这个任务的呢?为了找到答案,我将每个训练命令打包到一个system.time()中,以测试时间差异。事实证明,caret 只需要 tidymodels 分配给调优的一小部分时间,确切地说,大约 2% 。虽然我们的 tidymodel 的workflow_map()命令花了 6 个多小时来运行,但 caret 在不到 8 分钟内完成了同样的任务。至少对于我的小实验来说,tidymodels 比 caret 慢 48 倍!如此巨大的差异。请注意,虽然这可能部分是由于我的旧机器,可能会略有不同,每次你跟踪时间。因此,我强烈建议您尝试具有这两个功能的微基准包:如果您有时间不止一次地评估这些功能,这应该会给您一个比system.time()更准确可靠的结果。然而,tidymodels 总体上似乎比 caret 慢得多的问题并不新鲜:Max Kuhn 认为食谱会减慢训练过程,因为所有预处理步骤都在每个重采样中重新应用。另一个可能的解释是 tidymodels 和 caret 在并行计算上的差异。

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

尼克·王Unsplash 上的照片

决定你的获胜模型

为了找出哪种方法对我们的问题最有效,我们需要测量所有方法的性能。在我们的 tidymodels 示例中,我们保存了 model_race 中训练数据的所有调优结果。我们可以使用 group by 工作流来按模型类型收集指标。生成的 tibble 为我们提供了几个性能指标,这些指标是为模型计算的,每个模型都尝试我们网格中的特定超参数配置。在我们的例子中,它为每个工作流的每个性能指标提供了 10 次折叠 x 3 次重复= 30 个结果。现在我们可以运行 tidymodel 的 autoplot 来显示候选模型中的工作流性能排名。

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

那么,我们的制胜模式是什么?该图显示,在所有指标中,逻辑回归(蓝色)在所有候选模型上都优于 XGBoost。为了用 caret 比较模型性能,我们使用了 resamples-函数。它为我们提供了所有 3 个折叠的 F1 值的范围,为我们提供了模型在不同样本上的表现的估计。通过使用bwplot(resamples)可视化该输出,我们可以看到性能如何跨褶皱分布,然后选择具有最高平均性能或最低性能差异的模型。与 tidymodels 不同,我们无法看到每个参数组合跨训练折叠的性能,但我们可以获得最佳超参数集的性能范围。即使该图表明 XGBoost 产生了稍好的性能,我们稍后将使用 glmnet 进行预测,以便与 tidymodels 的逻辑回归进行有效的比较。

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

令人惊讶的是,与 tidymodels 相比,caret 通常提供更高的 F1 分数,尽管 MLmetrics 的 F1_Score 函数以及码尺的 f_meas()函数都计算了召回率和精确度之间的调和平均值,而没有对任何一个指标施加任何额外的权重(平衡的 F1 分数)。因此,性能上的差异不太可能是由于计算上的差异。从最好的方面来说,这种差异来自更有针对性的优化过程,因为 caret 训练我们的模型以保持尽可能高的 F1 分数。

尽管如此,我们还没有完成:对于 tidymodels,我们需要提交一个模型,然后适当地完成它。在这种情况下,我们从模型比较中提取所有 glmnet 候选模型。通过对 tidymodels 逻辑回归工作流的调优结果运行 select_best(),我们获得了 F1 得分最高的候选模型的性能指标。为了进一步提交这个模型,我们最终确定了获胜的工作流:我们从我们的模型竞赛中提取出log_reg工作流,该工作流具有一组在数值上工作得最好的超参数。这就是我们最终确定的工作流程:

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

然而,如果我们查看 caret 的最终调优结果,我们会得到相同超参数的其他值,这可能是由于优化标准的差异:可能是因为 tidymodel 的 glmnet 模型没有明确训练为最大化 F1 值?

print(model_glmnet)

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

对于我们的 tidymodels 方法,我们使用我们最终确定的工作流程,并使其适合重新采样,以计算跨褶皱的性能指标。为此,我们可以使用fit_resamples()来评估不同数据层的模型性能。与使最终的工作流适合我们的整个训练集相比,重采样使我们更接近地估计模型在新样本上的表现。对于其性能的最终结论,我们还必须等待对测试数据的评估。下一步,我们使用last_fit()来生成最终的重采样结果,并根据测试数据进行评估。我们可以看看每个模型在训练数据上的表现,以证实这一观察结果。

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

这个 last_fit 对象不仅包括最终的工作流以及我们的最终性能指标,还包含我们预测的一个很好的部分:预测的类、类概率和实际结果。它们嵌套在 last_fit 对象中,因此当我们将它们转换为 data.frame 时,我们可以可视化最终的预测。例如,我们可以绘制预测概率的密度分布图,用实际流失结果来着色(受茱莉亚·西尔奇的帖子的启发)。

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

因为分布有相当多的重叠,所以在很多情况下,模型预测的两种结果(是/否)几乎是一样的。这也意味着在职员工和离职员工不容易区分,但我们的绩效指标显示,在大多数情况下,该算法对正确结果的分配概率略高。对于正面类,分类器必须已经检测到大多数真实离开者,但是也错误地将其中的大约 30 %留给了负面类(反之亦然)。如果我们从插入符号开始绘制预测,会发生什么?

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

哇,看起来更多的真否定得到的流失概率接近于零,而分类器倾向于给实际离职的员工分配高流失概率。但它也错误地将大约三分之一的真阳性和真阴性进行了分类…这种表现如何转化为整个训练集?在训练数据上拟合模型之后,我们可以使用predict()进行预测。

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

如假设的那样,在每一类中,大约 30%的数据被错误地分类,这也反映在相似的灵敏度(TPR)对特异性(TNR)的水平上。要为我们的脱字符分类器获得类似的信息,我们可以简单地调用predict.train()并使用我们的模型和训练数据作为输入,然后我们将预测包装在一个ConfustionMatrix()命令中。现在,我们对训练数据性能有了一个非常好的概述。

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

输出强调了我们的假设,caret 在区分积极类和消极类方面做得更好。此外,与 tidymodels 的输出相比,我们得到的假阴性要少得多,这表明召回率应该相对提高(76 %对 71 %)。

最后的倒计时:新样品的性能

我们已经足够聪明地保存了一些数据用于测试目的——现在是模型实际展示其预测技能的时候了!其原因是,在训练分类器的相同数据上评估性能会产生过度拟合的高风险:模型高度依赖于它最初训练的数据,因此在相同数据上计算的性能指标决不是独立的。为了挑战模型处理新观察的能力,我们需要用他们从未见过的数据来测试它。为了获得 tidymodels 测试数据的性能指标,为了方便起见,我们可以调用已经携带测试数据指标的 last_fit 对象。

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

事实证明,对训练数据的估计确实高估了模型的性能,因为除了特异性之外,测试数据的所有指标都降低了一点(例如,0.61 对 0.71 的灵敏度)。这可以通过我们对测试数据的原始混淆矩阵得到进一步证实:

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

在 caret 中,我们可以简单地将模型和测试数据的目标列一起传递给ConfusionMatrix(),并获得一些性能指标。

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

输出表明,同样的方法与 tidymodels 相比,性能又稍好一些,尽管差别可以忽略不计。总而言之,它再次显示了为测试保存一些数据以避免对模型的性能过于乐观是多么有意义。

ROC 曲线,最后解释道

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

我们可以这样解释:直线越接近 90 度角,特异性越强,灵敏度越高。您可以将敏感度视为 1-FPR,因此这是模型将所有真阳性病例正确识别为阳性的概率(或真阳性率)。相反,特异性为 1 — FNR,因此它是模型将所有真阴性病例正确识别为阴性的概率(或真阴性率)。因为灵敏度是相对于 1-特异性绘制的,所以当高灵敏度伴随高特异性时,曲线下的面积增加。你可以把 ROC 曲线看作一种思维实验:当我们的敏感度为 0.75 时,1 的最佳可能值——特异性或假阳性率将为 0.00。在这种情况下,真阳性的检测将伴随着所有仍被识别为真阳性的阴性病例。想象一下,我们会有一个非常粗略的模型,将所有情况简单地分类为阳性:我们会有一个完美的灵敏度(TPR),但一个可怜的特异性或 FPR,因为真正的阴性(例如,忠诚的员工)也会得到一个阳性标签。如果你也关心消极的情况,并想把它们和积极的情况区分开来,这就不好了。因此,敏感性越高,特异性低的风险就越高,反之亦然,由图上的虚线对角线表示。对于 tidymodels,0.75 的灵敏度伴随着 0.6 的特异性,这是一个不错的折衷。因此,随着我们的模型变得足够智能,能够检测出离职者(自然减员=是),同时还能识别出在职员工(自然减员=否),曲线下的面积会增加。

为了在我们的 caret 框架内制作一个类似的 ROC 曲线,我们可以使用m level为我们提供一系列与 ROC 相关的输出。总的来说,与我们的 tidymodels 输出相比,glmnet 的曲线下面积似乎稍大一些,并且两个框架之间的性能没有很大的差距。

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

现在哪个包赢了这场战斗?

Tidymodels 具有很高的灵活性,因为它基于各种现代包,并具有完全可定制的工作流结构。这意味着在创建自己的机器学习项目时,你有很大的自由度。但是由于包含了如此多的步骤和对象,对于初学者来说肯定会有些困惑。在我自己的项目中,我觉得我对程序的功能有了更好的理解,因为我已经解决了很多错误信息,并在这个过程中学到了很多理论。但这也可能是因为 tidymodels 仍在开发中,因此还不稳定。如果你想快速简洁地解决你的预测问题,而不是建立一个大项目,我会向你推荐 caret。它不仅在运行时间方面更快,而且还有更多来自有经验用户的资源和解决的问题。Caret 适合许多模型,只需要很少的编码工作,同时由于并行处理而尽可能快。与 tidymodels 不同,自动为您选择跨重采样的最佳候选模型,这可能很简洁。有一点是肯定的:Max Kuhn 在设计这些包方面做得非常好,你很幸运有两个强大的开源包可供选择。

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

乔纳森·托马斯在 Unsplash 上的照片

致谢

我要特别感谢罗伯特·洛恩,一位来自挪威的顾问,他是我在这个项目中的智力陪练。我真的很喜欢我们的合作交流,我希望我们的学习之旅不会就此停止!

参考

[1] G. Harden,K. G. Boakye & S. Ryan,技术专业人员的离职意向:一个社会交换理论的视角 (2018),计算机信息系统杂志58 (4),291–300。

[2] J .萨卡尔,薪酬与离职挂钩:回顾与未来方向 (2018),《IUP 组织行为学杂志》17 (1)。

[3] P.C. Bryant & D. G. Allen,薪酬、福利与员工流动:留住顶尖人才的人力资源战略 (2013),薪酬&福利回顾45 (3),171–175。

Caret vs Tidymodels:如何将两个包都用于机器学习?

原文:https://towardsdatascience.com/caret-vs-tidymodels-how-to-use-both-packages-together-ee3f85b381c?source=collection_archive---------15-----------------------

实践教程

使用 R 中的两个流行包一起构建模型以预测自行车共享需求的示例

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

克里斯·巴尔巴利斯在 Unsplash 上拍摄的照片

Max Kuhn 构建了这两个包(有许多其他有才华的人的贡献)。[caret](http://cran.r-project.org/web/packages/caret/index.html)软件包(简称 C 分类 ARE 回归 T raining)简化了创建预测模型的过程,已经成为 R 用户的首选。它已经存在很长时间了,并且有无数的资源、答案和所有可能问题的解决方案。另一方面,[tidymodels](http://tidymodels.org)是更新的,是建立在tidyverse原则之上的。RStudio 雇佣了 Max,打算设计一个整洁版的 caret。

我一直在使用caret进行预测建模。虽然我知道tidymodels,但我上周才开始探索。正如生活中的一切一样,采用新的生态系统需要时间和耐心。所以这篇文章绝不是详尽的分析。GitHub 上提供了完整代码,并发布了Markdown的 HTML 版本。

概观

caret是一个单一的包,具有机器学习的各种功能。例如,createDataPartition用于拆分数据,trainControl用于设置交叉验证。

tidymodels是用于建模的包的集合。当我执行library(tidymodels)命令时,会加载以下包:

  • rsample:用于数据分割和重采样
  • parsnip:用于试用一系列型号
  • recipes:用于预处理
  • 把所有的东西放在一起
  • yardstick:用于评估模型
  • broom:用于将通用统计 R 对象中的信息转换为用户友好、可预测的格式
  • dials:用于创建和管理调谐参数

一些来自tidyverse的常用库,比如dplyr,也是加载的。如图所示,tidymodels将机器学习工作流分解为多个阶段,并为每个阶段提供专门的包。这对于用户是有益的,因为增加了灵活性和可能性。然而,对于一个初学者来说,这可能是令人生畏的(至少对我来说是这样)。

输入数据

数据来自 UCI 知识库的自行车共享数据集。目标是根据环境和季节设置预测自行车租赁数量total

**library**(tidymodels) 
**library**(caret)
**library**(lubridate) 
**library**(tidyverse) 
**library**(moments) 
**library**(corrr) 
**library**(randomForest)
bike <- read_csv("Bike-Sharing-Dataset/hour.csv")
bike %>% dim()
*## [1] 17379    17*

有 17,379 个案例和 17 个特征。我删除了instant,更改了year的格式,并重命名了一些变量。

bike %>%
  mutate(instant = NULL, yr = yr + 2011) %>%
  rename(
    date = dteday,
    year = yr,
    month = mnth,
    hour = hr,
    weather = weathersit,
    humidity = hum,
    total = cnt
  ) ->
bike
head(bike)

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

数据框标题预览

浏览数据

目标变量

bike %>%
  pivot_longer(
    cols = c(casual, registered, total),
    names_to = "usertype",
    values_to = "count"
  ) %>%
  ggplot(aes(count, colour = usertype)) +
  geom_density() +
  labs(
    title = "Distribution of the number of rental bikes",
    x = "Number per hour", y = "Density"
  ) +
  scale_colour_discrete(
    name = "User type",
    breaks = c("casual", "registered", "total"),
    labels = c("Non-registered", "Registered", "Total")
  )

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

目标变量分布

租赁数量的分布是正偏态的。正态分布是可取的,因为大多数机器学习技术要求因变量是正态的。我稍后解决了偏斜问题。

相互关系

我使用了corrr包中的correlated()函数,它是tidymodels的一部分,但不会自动加载library(tidymodels)命令。我经常对整洁的生态系统中有多少包感到惊讶。通常,我优先考虑整洁的包而不是独立的包,因为管道的集成和美学上的一致性,corrr也不例外。

bike %>%
  select(where(is.numeric)) %>%
  correlate() %>%
  rearrange(absolute = FALSE) %>%
  shave() ->
  bike_cor
rplot(bike_cor, print_cor = TRUE)

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

相关图

准备数据

由于我还没有分割数据,这一步是而不是数据缩放或定心,这应该适合训练集并转换测试集。在这里,我将重点放在适用于所有数据且没有参数的过程上,例如因式分解或简单的数学计算。举个例子,如果我求一个数的平方根,我可以求它的平方来知道原来的数。然而,为了标准化,我需要知道变量的最小值和最大值,这两个值对于训练和测试可能是不同的。

目标变量

我关注于total计数,所以casualregistered变量被移动。如前所述,目标变量是正偏的,需要转换。我尝试了几种常见的技术来处理正偏斜的数据,并应用了偏斜度最低的技术——立方根。

bike_all <- bike %>%
  select(-casual, -registered)

*# Original*
skewness(bike_all$total)
*## [1] 1.277301*

*# Log*
skewness(log10(bike_all$total))
*## [1] -0.936101*

*# Log + constant*
skewness(log1p(bike_all$total))
*## [1] -0.8181098*

*# Square root*
skewness(sqrt(bike_all$total))
*## [1] 0.2864499*

*# Cubic root*
skewness(bike_all$total^(1 / 3))
*## [1] -0.0831688*

*# Transform with cubic root*
bike_all$total <- bike_all$total^(1 / 3)

预言者

根据 UCI 提供的属性信息,分类变量被转换为因子。

bike_all$season <- factor(
  bike_all$season,
  levels = c(1, 2, 3, 4),
  labels = c("spring", "summer", "autumn", "winter")
)
bike_all$holiday <- factor(
  bike_all$holiday,
  levels = c(0, 1), labels = c(FALSE, TRUE)
)
bike_all$workingday <- factor(
  bike_all$workingday,
  levels = c(0, 1), labels = c(FALSE, TRUE)
)
bike_all$weather <- factor(
  bike_all$weather,
  levels = c(1, 2, 3, 4),
  labels = c("clear", "cloudy", "rainy", "heavy rain"),
  ordered = TRUE
)
head(bike_all)

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

数据框标题预览

分割数据(培训/测试、交叉验证)

这两个包都提供了常见数据拆分策略的函数,比如 k-fold、分组 k-fold、留一和引导。但是tidyverse似乎更全面,因为它包括蒙特卡罗交叉验证(我不知道这是什么,但听起来很酷)和嵌套交叉验证。我特别强调了这种方法,因为一篇研究论文发现,“嵌套 CV 和训练/测试分割方法不管样本大小都可以产生稳健和无偏的性能估计。”(瓦巴拉等人,2019 年)

潮汐模型

tidymodels rsample库处理数据拆分。如图所示,进行训练和测试分割,并进行 10 重交叉验证。

set.seed(25)
split <- initial_split(bike_all, prop = 0.8)
train_data <- training(split)
train_data %>% dim()
*## [1] 13904    14*

test_data <- testing(split)
test_data %>% dim()
*## [1] 3475   14*

train_cv <- vfold_cv(train_data, v = 10)

脱字号

有两个选项可用:

  • 使用caret的原生函数,比如createDataPartition
set.seed(25)
train_index <- createDataPartition(
  bike_all$total, p = 0.8, times = 1, list = FALSE
)
train_data <- mics[ train_index, ]
test_data  <- mics[-train_index, ]

fold_index <- createFolds(
  train_data$total,
  k = 10, returnTrain = TRUE, list = TRUE
)
train_cv <- trainControl(method="cv", index = fold_index)
  • 使用 tidymodels 的rsample2caret函数,该函数返回一个列表,该列表模拟了一个trainControl对象的indexindexOut元素。
train_cv_caret <- rsample2caret(train_cv)
ctrl_caret <- trainControl(
  method = "cv",
  index = train_cv_caret$index,
  indexOut = train_cv_caret$indexOut
)

两个包非常相似。有趣的是trainControl只指定了交叉验证策略而没有指定数据。尽管如此,由于来自tidymodelsrsample2caret()caret2rsample()命令,在您喜欢的任何包中设置重采样都很容易。这里我使用rsample2caret()caret生成 10 倍的索引,以确保两者的交叉验证是相同的。

预处理数据

caret中,一个函数preProcess涵盖了数字特征的所有预处理,包括插补、定心、缩放和幂变换。对于分类特征,我可以使用dummyVars来创建虚拟变量,或者让train来处理模型训练期间的因素。我发现令人沮丧的一件事是我不能为不同的变量指定预处理。例如,我想使用 Box-Cox 变换来规范化一个极度偏斜的变量。但是,preProcess对所有预测值执行转换。如果你熟悉 Python 中的sklearn,我是说我想要ColumnTransformer

潮汐模型

recipes实现了愿望,允许我定义一个配方或蓝图,可用于顺序定义数据的编码和预处理(即“特征工程”)。而且,recipes似乎提供了更多的预处理方法。然而,与caret不同的是,recipes不会自动处理分类变量,我需要手动创建虚拟变量。尽管如此,定制预处理的能力胜过了必须生成虚拟变量的小小不便。

prep_recipe <-
  recipe(total ~ ., data = train_data) %>%
  step_rm(year, month, weekday) %>%
  step_date(date) %>%
  step_corr(all_numeric(), threshold = 0.8) %>%
  step_dummy(all_nominal())

脱字号

同样,我可以使用 caret 的preProcess()函数。但我总是觉得很沮丧,因为所有的数值变量都要处理,没有太大的灵活性。

prep <- preProcess(cutoff = 0.8) 

同样,tidymodels’ recipe可以用于插入符号。这里,我用prep()bake()来转换数据,因为 caret 没有工作流功能。

train_data_caret <-
  prep(prep_recipe) %>% bake(new_data = NULL)

test_data_caret <-
  prep(prep_recipe) %>% bake(new_data = test_data)

火车模型

我稍后将使用两个自定义函数:

*# Generate prediction tables*
predict_table <- **function**(model, data, tidy_flag) {
  **if** (tidy_flag == TRUE) {
    result <- model %>%
      predict(data) %>%
      rename(pred = .pred) %>%
      mutate(
        actual = data$total,
        pred_real = pred^3,
        actual_real = actual^3
      )
  } **else** {
    result <- model %>%
      predict(data) %>%
      as_tibble_col(column_name = "pred") %>%
      mutate(
        actual = data$total,
        pred_real = pred^3,
        actual_real = actual^3
      )
  }
  result
}

*# Extract RMSE for models*
pull_rmse <- **function**(result_table) {
  rmse_result <- rmse(result_table, pred, actual) %>%
    pull(.estimate)
  rmse_result_real <- rmse(result_table, pred_real, actual_real) %>%
    pull(.estimate)
  result <- c(rmse = rmse_result, real_rmse = rmse_result_real)
}

基线

基线是total的平均值。

base_train_pred <-
  tibble(
    actual = train_data$total, 
    actual_real = train_data$total^3
) %>%
  mutate(pred = mean(actual), pred_real = mean(actual_real))base_test_pred <-
  tibble(
    actual = test_data$total, 
    actual_real = test_data$total^3
) %>%
  mutate(pred = mean(actual), pred_real = mean(actual_real))base_train_rmse <- pull_rmse(base_train_pred)
print(base_train_rmse) 
##       rmse  real_rmse 
##   2.032927 181.063306base_test_rmse <- pull_rmse(base_test_pred)
print(base_test_rmse) 
##      rmse real_rmse 
##   2.02608 182.61370

具有潮汐模型的决策树

parsnip用于建模,workflow用于油井工作流程,tune用于参数调整,yardstick用于性能指标。我也很好奇时间,所以我也记录了时间。

*# Cost complexity for decision tree parameter*
tree_cp <- seq(0.01, 0.1, 0.01)

set.seed(25)
tree_tidy_time1 <- Sys.time()

*# Specify model*
tree_engine <- 
  decision_tree(mode = "regression", cost_complexity = tune()) %>%
  set_engine("rpart")

*# Set workflow (Preprocess & model)*
tree_workflow <-
  workflow() %>%
  add_recipe(prep_recipe) %>% 
  add_model(tree_engine)

*# Tune parameters with cross-validation*
tree_tune <- tune_grid(
  tree_workflow,
  resamples = train_cv,
  grid = data.frame(cost_complexity = tree_cp),
  metrics = metric_set(rmse)
)

*# Fit again with the best parameter*
tree_best <-
  finalize_workflow(tree_workflow, select_best(tree_tune)) %>%
  fit(train_data)

tree_tidy_time2 <- Sys.time()
print(tree_tidy_time2 - tree_tidy_time1)
## Time difference of 1.376683 mins

交叉验证十个参数大约需要 1 分 20 秒。一旦完成,我就可以预测目标变量,并用 RMSE 检验模型性能。这里我使用自定义函数predict_tablepull_rmse来完成任务。

tree_tidy_train_pred <- predict_table(tree_best, train_data, TRUE)
tree_tidy_train_rmse <- pull_rmse(tree_tidy_train_pred)
print(tree_tidy_train_rmse) 
##       rmse  real_rmse 
##   1.078724 116.106006tree_tidy_test_pred <- predict_table(tree_best, test_data, TRUE)
tree_tidy_test_rmse <- pull_rmse(tree_tidy_test_pred)
print(tree_tidy_test_rmse) 
##       rmse  real_rmse 
##   1.074347 118.205989

带插入符号的决策树

set.seed(25)
tree_caret_time1 <- Sys.time()
tree_caret <- train(
  total~.,
  data = train_data_caret,
  method = "rpart",
  trControl = ctrl_caret,
  metric = "RMSE",
  tuneGrid = data.frame(cp = tree_cp)
)
tree_caret_time2 <- Sys.time()
print(tree_caret_time2 - tree_caret_time1) 
## Time difference of 4.469931 secs

哇哦!只需要 4.5 秒。而且,代码要短得多。train功能包括模型method = "rpart",交叉验证trControl = ctrl_caret,参数整定tuneGrid = data.frame(cp = tree_cp)

tree_caret_train_pred <- predict_table(tree_caret, train_data_caret, FALSE)
tree_caret_train_rmse <- pull_rmse(tree_caret_train_pred)
print(tree_caret_train_rmse) 
##       rmse  real_rmse 
##   1.078724 116.106006tree_caret_test_pred <- predict_table(tree_caret, test_data_caret, FALSE)
tree_caret_test_rmse <- pull_rmse(tree_caret_test_pred)
print(tree_caret_test_rmse) 
##       rmse  real_rmse 
##   1.074347 118.205989

比较模型

rbind(
  base_train_rmse, base_test_rmse,
  tree_tidy_train_rmse, tree_tidy_test_rmse,
  tree_caret_train_rmse, tree_caret_test_rmse
)##                           rmse real_rmse
## base_train_rmse       2.032927  181.0633
## base_test_rmse        2.026080  182.6137
## tree_tidy_train_rmse  1.078724  116.1060
## tree_tidy_test_rmse   1.074347  118.2060
## tree_caret_train_rmse 1.078724  116.1060
## tree_caret_test_rmse  1.074347  118.2060

如您所见,不管库是什么,决策树模型的结果都是相同的,因为我以相同的方式分割了数据并设置了交叉验证。此外,tidymodels 和 caret 都使用rpart作为底层引擎。因此,tidymodels 运行决策树需要 1 分多钟,而 caret 只需要 4-5 秒,这似乎很奇怪。

结论

我已经使用 tidymodels 几个星期了,我真的很喜欢集成到 tidyverse 中。但是我发现这么多的步骤和对象让我很困惑。例如,我一直试图从工作流对象中获取 RMSE。我可能需要多一点时间来熟悉新的生态系统。

GitHub 上提供了完整代码,并发布了Markdown的 HTML 版本。一如既往,我希望这个帖子是有帮助的。祝你有美好的一天!

参考

Vabalas,a .,Gowen,e .,Poliakoff,e .,和 Casson,A. J. (2019)。有限样本下的机器学习算法验证。 PloS one14 (11),e0224365。

CART:清晰而强大的模型的分类和回归树

原文:https://towardsdatascience.com/cart-classification-and-regression-trees-for-clean-but-powerful-models-cc89e60b7a85?source=collection_archive---------0-----------------------

入门,机器学习

CART 算法是如何工作的,如何在 Python 中成功使用?

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

购物车模型预测图面。在本文结尾的 Python 部分,可以看到图表是如何制作的。图片由作者提供。

简介

如果你想成为一名成功的数据科学家,了解不同的机器学习算法是如何工作的是至关重要的。

这个故事是解释每个算法的细微差别的系列的一部分,并提供了一系列 Python 示例来帮助您构建自己的 ML 模型。更不用说一些很酷的 3D 可视化!

故事涵盖以下主题:

  • CART 所属的算法类别
  • 关于 CART 算法如何工作的解释
  • 关于如何构建购物车决策树模型的 Python 示例

【CART 属于哪一类算法?

顾名思义,CART(分类和回归树)既可以用于分类问题,也可以用于回归问题。区别在于目标变量:

  • 利用分类,我们试图预测一个类别标签。换句话说,分类用于输出(目标变量)取一组有限值的问题,例如,明天是否会下雨。
  • 同时,回归用于预测数字标签。这意味着您的输出可以采用无限多的值,例如,房价。

这两种情况都属于机器学习算法的监督分支。

旁注,由于神经网络独特的机器学习方法,我已经将它们归为一类。然而,它们可以用于解决广泛的问题,包括但不限于分类和回归。下图是交互式,请务必点击👇在不同的类别上对进行放大并展示更多的

机器学习算法分类。由作者创建的互动图表。

如果你也热爱数据科学和机器学习 ,请 订阅 每当我发布新故事时,你都会收到一封电子邮件。

虽然在这个故事中,我把重点放在 CART 分类上,但是回归案例非常相似,只是使用了不同的方法来计算树中的最佳分裂。

分类和回归树是如何工作的?

示例

让我们从一个简单的例子开始。假设你有一堆贴有标签的橙子和曼德拉草,你想找出一套简单的规则,将来可以用它来区分这两种水果。

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

Philippe Gauthier 在 Unsplash 上拍摄的照片

通常,橙子(直径 6-10 厘米)比橘子(直径 4-8 厘米)大,因此您的算法找到的第一条规则可能基于大小:

  • 直径≤ 7cm。

接下来,你可能会注意到橘子的颜色比橙子略深。因此,您使用色标(1 =暗到 10 =亮)来进一步分割您的树:

  • 子树左侧的颜色≤5
  • 子树右侧的颜色≤6

你的最终结果是一个由 3 个简单规则组成的树,帮助你在大多数情况下正确区分橙子和橘子:

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

识别橙子和橘子的决策树。图片由作者提供。

【CART 如何找到最佳分割?

CART 中可以使用几种方法来确定最佳拆分。以下是分类树中最常见的两种:

基尼杂质

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

where p_i is the fraction of items in the class i. 

以上面的树为例,最左边的叶节点的 Gini 杂质是:

1 - (0.027^2 + 0.973^2) = 0.053

为了找到最佳分割,我们需要计算两个子节点的基尼系数的加权和。我们对所有可能的分割都这样做,然后将具有最低基尼系数杂质的分割作为最佳分割。

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

计算基尼系数。图片由作者提供。

重要提示:如果两个子节点的最佳加权 Gini 杂质不低于父节点的 Gini 杂质,则不应再进一步拆分父节点。

熵值法与基尼系数法基本相同,只是使用了一个略有不同的公式:

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

要确定最佳分割,您必须遵循上述所有相同的步骤。具有最低熵的分裂是最好的分裂。类似地,如果两个子节点的熵不低于一个父节点的熵,就不应该再进一步拆分了。

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

如何用 Python 建立 CART 决策树模型?

我们将构建几个分类决策树,并使用树形图和 3D 表面图来可视化模型结果。首先,让我们做一些基本的设置。

设置

我们将使用以下数据和库:

让我们导入所有的库:

然后我们从 Kaggle 获取澳大利亚的天气数据,你可以按照这个链接下载:https://www . ka ggle . com/jsphyg/weather-dataset-rattle-package

一旦你在你的机器上保存了数据,用下面的代码接收它。请注意,我们还做了一些简单的数据操作,并派生了一些新的变量供以后在我们的模型中使用。

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

一小段 Kaggle 的澳大利亚天气数据做了一些修改。图片来自作者

为了减少重复代码的数量,我们将创建几个可以在整个分析中重用的函数。

第一个函数执行以下操作:

  • 将数据分为训练样本和测试样本
  • 符合模型
  • 预测测试集上的标签
  • 生成模型性能评估指标
  • 创建决策树图

第二个函数将用于绘制带有测试数据和模型预测表面的 3D 散点图:

使用基尼杂质的 CART 分类模型

我们的第一个模型将使用所有可用的数值变量作为模型特征。同时,raintomorowflag将成为所有模型的目标变量。

注意,在写 sklearn 的 树的时候。DecisionTreeClassifier()只能以数值变量为特征。但是,您也可以使用分类值,只要您使用编码算法对它们进行编码,例如 sklearn 的顺序编码器 或任何其他合适的方法将分类值转换为数值。

让我们使用我们的 拟合 函数来构建模型,树深度限制为 3,最小叶子大小为 1000 个观察值。限制树的深度和叶子的大小有助于我们避免过度拟合。在后面的例子中,我们将会看到一旦我们移除了一些约束,树的复杂度会增加多少。

下面是 拟合 函数生成的输出:

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

模型 1 —购物车模型性能指标。图片由作者提供。

我们可以看到,该模型在预测干旱天数方面表现相对较好。然而,在预测雨天时,性能较差,测试数据的精度为 0.76,召回率为 0.34。

  • 精度意味着在模型预测的 76%的情况下明天会下雨。
  • 同时,召回意味着对于测试数据中的所有雨天,模型只识别了其中的 34%。

这两个类别标签的性能差异主要是由数据的不平衡造成的,干旱天比雨天多得多。

接下来,我们来看看由我们的 拟合 函数生成的树形图**😗*

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

模型 1 —购物车模型决策树。图片由作者提供。

从上面可以看出,虽然该算法使用了几种不同的特征,但两个最重要的特征是“湿度 3pm”和“风速”,因为这是唯一两个影响分类标签预测为 0 或 1 的特征。

因此,我们可以通过减少特征的数量来创建一个具有相似性能的模型,如下例所示。

使用基尼杂质和 2 个特征的 CART 分类模型

让我们再次使用我们的 拟合 函数:

模型性能指标:

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

模型 2 —购物车模型性能指标。图片由作者提供。

正如所料,该模型的性能与第一个模型相同。但是,让我们来看看决策树是如何变化的:

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

模型 2—购物车模型决策树。图片由作者提供。

因此,虽然树在不同的地方是不同的,关键的分裂仍然是相同的。

最好的事情是,我们可以创建一个 3D 图表来可视化预测平面,因为我们只使用了两个输入要素。这就是第二个功能, Plot_3D, 派上了用场:

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

模型 2-CART 模型预测表面。图片由作者提供。

注意,顶部的黑点是 class=1(明天下雨)的实例,底部的黑点是 class=0(明天不下雨)的实例。同时,表面是基于模型预测的明天下雨的概率。最后,图中间的细线是概率=0.5,表示决策边界。

不足为奇的是,预测平面看起来像一组楼梯。这是因为预测概率遵循用于分割树节点的特定值的阶跃变化。例如,最低降雨概率(底部阶梯-暗红色)以“湿度 3pm = 51.241”和“风速= 53.0”为界

树深度无限制的 CART 分类模型

现在让我们看看当我们不限制树的深度时会发生什么。我们再次使用我们的 拟合 函数:

以下是最终的模型性能:

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

模型 3—购物车模型性能指标(具有最大深度)。图片由作者提供。

决策树(注意,为了更好地适应页面,该树已被旋转):

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

模型 3 —购物车模型决策树(具有最大深度)。图片由作者提供。

最后,3D 图形:

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

模型 3-CART 模型预测表面(具有最大深度)。图片由作者提供。

如您所见,由于对树深度没有限制,该算法创建了一个更加复杂的树,这可以在树图和 3D 预测表面上的“步骤”数量中看到。同时,模型的性能只是略微好一点(精确度=0.83)。

无论何时构建决策树模型,都应该仔细考虑复杂性和性能之间的权衡。在这个具体的例子中,性能的微小提高不值得额外的复杂性。

其他要探索的东西

有许多方法可以进一步微调您的购物车模型。举几个例子:

  • 你可以将“基尼”改为“熵”,使用基于熵的算法建立一个模型。
  • 您可以使用“随机”拆分器,而不是“最佳”拆分器“最佳”总是选择重要性最高的特征来产生下一个分割。同时,“随机”将选择一个随机的特征(尽管被特征重要性分布加权)。
  • 如上所述,您可以更改树的最大允许深度。
  • 您可以调整“class_weight”(在我们的 拟合 函数中命名为 clweight ),方法是传递一个带有每个类权重的字典,或者简单地为算法输入“balanced”以使用权重来平衡类样本。
  • 最后,你也可以尝试调整最小叶片尺寸。

结论

CART 是一个强大的算法,与其他 ML 方法相比,它也相对容易解释。它不需要太多的计算能力,因此允许您非常快速地建立模型。

虽然您需要小心不要过度拟合您的数据,但对于简单的问题,这是一个很好的算法。如果你想提高你的模型的性能和健壮性,你也可以探索集合方法,比如一个 随机森林

和往常一样,如果你喜欢学习决策树,或者有任何问题或建议,请给我写信。

干杯👏
索尔·多比拉斯

如果你已经花光了这个月的学习预算,下次请记得我。 我的个性化链接加入媒介是:

**https://solclover.com/membership **

您可能感兴趣的其他分类算法:

** **

案例研究 Olist Brazillian 数据集上的客户满意度预测

原文:https://towardsdatascience.com/case-study-1-customer-satisfaction-prediction-on-olist-brazillian-dataset-4289bdd20076?source=collection_archive---------8-----------------------

解决分类问题

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

皮卡伍德Unsplash 上的照片

企业总是试图让客户群参与进来,并对他们提供的服务感到满意。为了在行业中保持相关性,他们需要将最新的技术进步融入到他们的服务中。十多年前,互联网还是一个全新的事物,各行各业都试图利用这项技术的能力,轻松地充当各种企业及其客户之间的沟通媒介。在这十年里,各行各业开始提供迎合每个客户个人需求的服务。对于这样的服务,他们需要利用人工智能的力量。在这个案例研究中,我们将探索这项技术的一个方面。本案例研究分为以下几个部分

  • 商业问题
  • 商业问题的 ML 公式化
  • 基础数据分析
  • 业务约束
  • 绩效指标
  • 数据描述
  • 探索性数据分析
  • 特色工程
  • 机器学习
  • 未来工作
  • 链接
  • 参考文献

业务问题

Olist store 是一家电子商务企业,总部位于巴西圣保罗。这家公司是各种小企业和希望购买他们产品的顾客之间的唯一联系点。最近,他们在 Kaggle 上上传了一个 数据集,其中包含了 2016 年至 2018 年间在多个市场所做的 10 万份订单的信息。我们在电子商务网站上购买的东西会受到我们在该网站上读到的关于该产品的评论的影响。这家公司当然可以利用这些评论来删除那些一直收到负面评论的产品。它也可以为那些受顾客欢迎的商品做广告。此案例研究的源代码可在 此处 获得。

ML 公式化的商业问题

我们看到的是一个五星评级系统,它总结了顾客对他或她刚刚购买的产品的总体满意度。我们可以把这方面转化为一个二元分类问题,把 4 星和 5 星的评分作为正类,其余的作为负类。

基础数据分析

我们得到了多个表和一个描述这些表如何连接的模式。在合并所有的表之后,我们分析整个数据集。它包含多个分类和数字列。在将给定的 5 星评级转换为二进制后,我们看到正面类占据了数据集的 76%,剩余部分由负面类填充。这意味着数据集严重失衡。根据销售记录,家具装饰、美容产品和运动器材是最受欢迎的类别。据了解,顾客平均花费约 125 巴西雷亚尔从该网站购买产品。在分析客户的州分布时,我们可以看到大多数订单是由位于圣保罗的客户下的。大多数商品的运费是合理的。这可能是许多人对产品总体满意的原因。大多数交易都是用信用卡进行的。

业务约束

负面评论较少,但也很重要。我们应该确保较少数量的负面评论被归类为正面评论。这意味着我们需要尽量减少误报的数量。完成这项任务不需要任何延迟限制。

绩效指标

混淆矩阵用于洞察模型产生的错误类型。减少假阳性的数量需要精确度,减少假阴性的数量需要召回。这就是我们将使用宏观 F1 分数作为衡量标准的原因。

数据描述

当您查看解释数据库连接的示意图时,您会发现有八个表。这些表格的说明如下

  1. olist_orders_dataset :这个表连接到另外 4 个表。它用于连接与订单相关的所有详细信息。
    2)olist _ order _ items _ dataset:它包含已购买商品的详细信息,如发货日期、价格等。
    3)olist _ order _ reviews _ dataset:它包含与客户对他所购买的特定产品发表的任何评论相关的详细信息。
    4)olist _ products _ dataset:包含与产品相关的 ID、类别名称、尺寸等。
    5)olist _ order _ payments _ dataset:此表中包含的信息与特定订单的付款细节相关。
    6)olist _ customers _ dataset:详细描述该公司的客户群信息。
    7)olist _ geolocation _ dataset:包含卖家和客户双方的地理信息。
    8)olist _ sellers _ dataset:这个表包含了所有在这个公司注册的卖家的相关信息。

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

数据库模式

所有这些表都使用主键和外键连接。我们将连接所有单独的 CSV 文件来创建一个大表。所有这些关键字都以后缀“id”或“prefix”结尾。

探索性数据分析

由于该数据集基于巴西的一家电子商务公司,因此流通区域很可能是巴西及其邻国。这就是为什么我们将采用南美大陆的绘图,并使用地理定位数据集中提到的地理数据来直观地描述订单的地理位置。

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

南美洲地理地图

正如您在地图上看到的,大多数客户位于巴西。为了进一步分析,我们将不使用地理定位数据集。这就是为什么它不会被添加到主数据帧中。

order_items_products = pd.merge(order_items_dataset,products_dataset,on='product_id')
order_items_products_sellers = pd.merge(order_items_products,sellers_dataset,on='seller_id')
two_order_items_products_sellers = pd.merge(order_items_products_sellers,orders_dataset,on='order_id')
two_order_items_products_sellers_customer = pd.merge(two_order_items_products_sellers,customers_dataset,on='customer_id')
two_order_items_products_sellers_customer_reviews = pd.merge(two_order_items_products_sellers_customer,order_reviews_dataset,on='order_id')
final_dataframe = pd.merge(two_order_items_products_sellers_customer_reviews,order_payments_dataset,on='order_id')

有些观察结果可能会重复。这些都是多余的,这就是为什么我们需要删除它们。我们将从数据集中删除那些具有相同订单 ID、客户 ID、购买时间戳和评论的观察。这是因为客户不能在同一时间对同一产品多次发布相同的评论。注意,充当主键和外键的所有 ID 值都是惟一的。我们找不到这种行的模式,因此,我们将删除它们。

不可能估算日期时间数据。这就是为什么我们应该删除任何日期时间列中包含空值的那些行。在解析 datetime 列时,我们提取日期信息并使用它创建两个额外的列。“采购交付差异”列给出了采购和交付之间的天数。“预计实际交货差异”栏给出了交货所需的延迟或缩短的天数。

intermediate_time = final_dataframe['order_delivered_customer_date'].apply(lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S").date()) - final_dataframe['order_purchase_timestamp'].apply(lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S").date())
final_dataframe['purchase-delivery difference'] = intermediate_time.apply(lambda x:x.days)intermediate_time = final_dataframe['order_estimated_delivery_date'].apply(lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S").date()) - final_dataframe['order_delivered_customer_date'].apply(lambda x: datetime.strptime(x, "%Y-%m-%d %H:%M:%S").date())
final_dataframe['estimated-actual delivery difference'] = intermediate_time.apply(lambda x:x.days)

现在让我们尝试估算其他类型的列。对于分类栏,我们将使用该栏的模式,对于数字栏,我们将使用该栏的中位数进行插补。对于评论的评论和标题,我们使用术语“in deponível ”,这是英语术语“unavailable”的葡萄牙语翻译。

final_dataframe['product_category_name'].fillna(value=final_dataframe['product_category_name'].mode()[0], inplace=True)
final_dataframe['product_name_lenght'].fillna(value=final_dataframe['product_name_lenght'].mode()[0], inplace=True)
final_dataframe['product_description_lenght'].fillna(value=final_dataframe['product_description_lenght'].median(), inplace=True)
final_dataframe['product_photos_qty'].fillna(value=final_dataframe['product_photos_qty'].mode()[0], inplace=True)
final_dataframe['product_weight_g'].fillna(value=final_dataframe['product_weight_g'].mode()[0], inplace=True)
final_dataframe['product_length_cm'].fillna(value=final_dataframe['product_length_cm'].mode()[0], inplace=True)
final_dataframe['product_height_cm'].fillna(value=final_dataframe['product_height_cm'].mode()[0], inplace=True)
final_dataframe['product_width_cm'].fillna(value=final_dataframe['product_width_cm'].mode()[0], inplace=True)
final_dataframe['review_comment_message'].fillna(value='indisponível', inplace=True)

我们的目标是将这个案例研究转化为一个二元分类任务。为此,我们需要创建一个包含标签的新列。评分大于 3 的值被标记为正值,而评分小于或等于 3 的值被标记为负值。

final_dataframe['review_score'] = final_dataframe['review_score'].apply(lambda x: 1 if x > 3 else 0)

在绘制显示标签的饼图时,我们看到正类占据了整个数据集的 77.60%;而消极阶层仅占 22.40%。这表明整个数据集是不平衡的。

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

有些列只包含数字数据。这意味着找到这些列的基本统计信息是我们可以尝试的一件事。请注意,“价格”和“产品长度描述”列的平均值和中值之间存在显著差异。

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

前 4 列的基本统计数据

让我们创建一个名为“价格类别”的新列。该列用于根据价格将商品分类为昂贵、便宜和实惠。我们使用第一、第二和第三四分位数作为创建这些类别的条件。

final_dataframe['price_category'] = final_dataframe['price'].apply(lambda x:'expensive' if x>=139 else ('affordable' if x>=40 and x<139 else 'cheap'))

我们现在根据购买频率找到了前 12 个最受欢迎的产品类别。“床浴桌”类别明显比大多数其他类别更受欢迎。这是唯一一个销量超过 10000 件的品类。排在第 12 位的类别“园艺工具”仅售出约 3600 件。

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

圣保罗,也简称为“SP ”,是这家公司客户基础最大的州。这可能是因为该公司的总部设在圣保罗,更多的客户了解这个网站,由于他们在这个地区的营销策略。2016 年至 2018 年间,圣保罗售出了超过 4 万辆汽车。

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

当我们检查每个产品类别的定价时,我们可以看到属于“计算机”类别的产品的平均成本最高。平均费用在 1150 雷亚尔左右。第二高的品类,均价接近最高品类的一半。

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

对于这个图,我们考虑了一个项目的总平均成本。这意味着它是运费和项目原始成本的总和。我们可以看到情节的顺序没有改变。只是每个品类的平均成本都增加了。

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

我们现在正在寻找产生最高收入的城市。名为“皮安科”的城市位于顶部。

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

这里只有两种状态可见。迄今为止,只有 6 份订单被取消。分析那些已经取消的产品没有意义。因此,我们将删除它们。

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

final_dataframe = final_dataframe[final_dataframe['order_status'] != 'canceled']

下面给出的散点图在 x 轴上显示价格,在 y 轴上显示交货和购买之间的总时间差。可以看出,随着交付时间的增加,对产品不满意的几率明显增加。一件物品的价格上涨,如果按时送达,并不会引起太多的不满。

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

我们现在正在创建一个名为“每价格采购交付差异”的新列,它是给定价格的产品采购和交付之间的时间差。

final_dataframe['purchase_delivery_diff_per_price'] = final_dataframe['purchase-delivery difference']/final_dataframe['price']

运费成本和物品成本之间的散点图非常具有描述性。但可以说,即使运费成本很高,当物品成本较低时,顾客也会感到满意。

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

信用卡是最受顾客欢迎的支付方式。它们比其他替代品更受欢迎。第二种是 Boletos,是一种只有在巴西才能找到的凭证。从这个图中,我们可以看到,给一个产品的差评很可能不是因为付款相关的问题。

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

现在是时候删除机器学习任务不需要的所有列了。应该删除所有日期时间列。

final_dataframe.drop(['shipping_limit_date','order_purchase_timestamp','order_approved_at','order_delivered_carrier_date','order_delivered_customer_date','order_estimated_delivery_date','customer_id'], axis=1, inplace=True)

我们现在将创建一个名为“标签”的新变量,它包含了已编辑的类极性。应将该列从原始数据框中移除。

labels = final_dataframe['review_score']
final_dataframe.drop('review_score', axis=1, inplace=True)

“审查可用性”列指示特定项目的审查是否可用。包含这个列比在‘评论评论消息’中包含一堆零要好,因为它避免了稀疏性。稀疏性的问题是它会严重降低任何模型的性能。

final_dataframe['review_availability'] = final_dataframe['review_comment_message'].apply(lambda x: 1 if x != 'indisponível' else 0)

对于机器学习,我们需要定义一个用于训练数据的训练集和一个用于预测的测试集。这两个集合以相等的比例包含两个类。由于数据集是不平衡的,这些标签的分布有可能严重影响任何机器学习模型的性能。因此,我们需要确保测试集和训练集包含相同比例的正标签和负标签。为了结果的可重复性,我们需要添加一个种子值。

X_train, X_test, y_train, y_test = train_test_split(final_dataframe, labels, stratify=labels, test_size=0.2, random_state=0)

特征工程

一些列包含多个类别。我们通常想到的编码技术不是一键编码就是顺序编码。当我们使用独热编码技术时,稀疏性的问题出现了,因为有太多的类别。除非类别中存在序数,否则不能使用序数编码。解决这种情况的一种方法是使用响应编码。在这种技术中,我们将所有类别出现的概率与每个标签相加。这意味着每个类别将有两个概率值——一个用于肯定类别,另一个用于否定类别。总体而言,为每个分类列创建了两个不同的列。

def train_response(frame):
  f1 = frame[frame.iloc[:,1] == 0]
  f2 = frame[frame.iloc[:,1] == 1]
  global dict_frame, dict_f1, dict_f2
  dict_frame = dict(frame.iloc[:,0].value_counts())
  dict_f1 = dict(f1.iloc[:,0].value_counts())
  dict_f2 = dict(f2.iloc[:,0].value_counts())
  state_0, state_1 = [],[],
  for i in range(len(frame)):
    if frame.iloc[:,1][i] == 0:
      state_0.append(dict_f1.get(frame.iloc[:,0][i],0) / dict_frame[frame.iloc[:,0][i]])
      state_1.append(float(1-state_0[-1]))
    else:
      state_1.append(dict_f2.get(frame.iloc[:,0][i],0) / dict_frame[frame.iloc[:,0][i]])
      state_0.append(float(1-state_1[-1])) 
  df3 = pd.DataFrame({'State_0':state_0, 'State_1':state_1})
  return df3.to_numpy()def test_response(test):
  t_state_0, t_state_1 = [],[]
  for i in range(len(test)):
    if dict_frame.get(test[i]):
     t_state_0.append(dict_f1.get(test[i],0) / dict_frame.get(test[i]))
     t_state_1.append(dict_f2.get(test[i],0) / dict_frame.get(test[i]))
    else:
      t_state_0.append(0.5)
      t_state_1.append(0.5)
  df4 = pd.DataFrame({'State_0':t_state_0, 'State_1':t_state_1})
  return df4.to_numpy()def test_response(test):
  t_state_0, t_state_1 = [],[]
  for i in range(len(test)):
    if dict_frame.get(test[i]):
    t_state_0.append(dict_f1.get(test[i],0)/dict_frame.get(test[i]))
      t_state_1.append(dict_f2.get(test[i],0)/dict_frame.get(test[i]))
    else:
      t_state_0.append(0.5)
      t_state_1.append(0.5)
  df4 = pd.DataFrame({'State_0':t_state_0, 'State_1':t_state_1})
  return df4.to_numpy()

我们将使用序数或一个热编码对包含较少类别的分类特征进行编码,如果有太多类别,则使用响应编码对它们进行编码。不需要对数字特征进行编码。请注意,我们没有考虑数据框中的所有列。只有那些我们认为必要的才被编码。每个类别的编码模式如下所述

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

接下来,我们将研究文本数据。处理文本数据的最好方法之一是将它们转换成单词嵌入。单词嵌入优于 TF-IDF 向量和单词袋,因为它们携带单词的语义。在这个案例研究中,我们将使用 FastText 作为单词嵌入技术。有可能将这些单词转换成 TF-IDF 向量,然后使用潜在语义分析等技术降低维度。这种方法更快,但问题是我们使用这种技术得到的密集向量确实包含这些单词的语义表示。这种方法会降低我们模型的准确性。在对文本进行矢量化之前,我们需要清理它。首先,我们将删除停用词,并使用 regex 清理剩余的词。

sp = spacy.load('pt')
all_stopwords = sp.Defaults.stop_wordsdef process_texts(texts):processed_text = []
    dates = '^([0]?[1-9]|[1|2][0-9]|[3][0|1])[./-]([0]?[1-9]|[1][0-2])[./-]([0-9]{4}|[0-9]{2})$'

    for text in texts:
        text = re.sub(r'\r\n|\r|\n', ' ', text) 
        text = re.sub(r'^https?:\/\/.*[\r\n]*', ' ', text) 
        text = re.sub(dates, ' ', text) 
        text = re.sub('[ \t]+$', '', text)
        text = re.sub('\W', ' ', text)
        text = re.sub('[0-9]+', ' ', text)
        text = re.sub('\s+', ' ', text)
        text = ' '.join(e for e in text.split() if e.lower() not in all_stopwords) 
        processed_text.append(text.lower().strip())

    return processed_text

我们仍然没有将所有的数字特征纳入同一尺度。为此,我们将使用标准化。我们使用标准化而不是规范化,因为正如在基本统计数据的描述中所看到的,这个数据集中存在许多异常值。

strn = StandardScaler()
strn.fit(X_train[['price','freight_value','product_photos_qty','product_weight_g', 'product_length_cm',
       'product_height_cm', 'product_width_cm', 'payment_value','purchase-delivery difference','estimated-actual delivery difference','purchase_delivery_diff_per_price']])
X_train_strn = strn.transform(X_train[['price','freight_value','product_photos_qty','product_weight_g', 'product_length_cm',
       'product_height_cm', 'product_width_cm', 'payment_value','purchase-delivery difference','estimated-actual delivery difference','purchase_delivery_diff_per_price']])
X_test_strn = strn.transform(X_test[['price','freight_value','product_photos_qty','product_weight_g', 'product_length_cm',
       'product_height_cm', 'product_width_cm', 'payment_value','purchase-delivery difference','estimated-actual delivery difference','purchase_delivery_diff_per_price']])

现在是时候将所有必要的特征连接在一起,并检查最终数据帧的形状。可以看出,整体有 332 个特征。

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

我们将尝试使用两种技术来减少这种维数。一种是通过使用奇异值分解找到硬阈值,另一种是通过使用自动编码器。奇异值分解是一种广泛使用的矩阵分解技术,可以应用于任何维度的矩阵。它将给定的矩阵转换成一组三个矩阵,分别命名为 U,σ和 V*。请注意,符号“”用于表示转置运算符。任何维数为 MxN 的矩阵 A 的奇异值都是维数为 NxN 的方阵 AA 的特征值的平方根。这里,σ是一个对角矩阵,它包含奇异值作为沿对角线的元素。对应于σ的对角元素的 U 矩阵的行和 V矩阵的列被称为左和右奇异向量。记住,我们默认取矩阵 V 的转置。让我们用几何直觉来解释奇异值。正如我们已经知道的,维度矩阵 MxN 是从真实空间ℝᴺ到真实空间ℝᴹ的线性变换,在数学上表示为ℝᴺ→ ℝᴹ.SVD 是一种将这种直接变换分解为一组三个变换的方法,这三个变换是-第一旋转、缩放和第二旋转。现在考虑一个单位圆,它有两个黄色和洋红色的矢量。这里我们正在考虑从ℝ到ℝ的转变。因此,在本例中,M 和 N 都等于 2。变换后,这个圆变成一个旋转过的椭圆。如图所示,这一整体转变可分为 3 个步骤。第一次旋转(应用 V)后,圆旋转一个角度。然后σ矩阵缩放该图的轴。每个轴的比例与奇异向量的大小成比例。注意,我们的两个向量的大小会改变。第二次旋转(应用 U)后,椭圆旋转了一个角度。

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

Georg Johann 绘制的奇异值分解图,在 CC-BY 2.0 许可下分发

降秩是一种技术,通过这种技术可以将高维噪声数据转换成低维更干净的数据。秩定义了一个阈值,我们可以考虑该阈值来截断使用 SVD 获得的 U 矩阵。研究人员过去常常采用启发式方法来寻找最佳排名。这种方法的问题是,他们不确定使用这种秩获得的截断矩阵是否包含足够的信息来重建干净的图像。另一种方法是使用试错法,这很耗时。在最近的一篇论文中,提到了一种称为最优奇异值硬阈值的技术,它为寻找截断的最优阈值奠定了理论基础。我们需要找到一个阈值τ*,它是最佳阈值。此公式中使用的“*”符号不表示转置。该公式取决于添加到图像中的噪声值是否已知,以及矩阵是否为正方形。假设该噪声的平均值为 0,标准偏差为 1。矩阵是正方形且噪声已知的可能性很小。但是如果这两个条件都满足,公式就是

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

这里,“n”是方阵的维数,“σ”是噪声。在大多数情况下,我们不知道添加了多少噪声。公式是

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

这里,β=n/m,yᵐᵉᵈ是所有奇异值的中间值。注意,我们这里使用的ω(β)值只是近似值。它们的实际值也可以计算出来,但是需要进一步的处理。由于我们在 SVD 中使用这种降秩技术只是为了降维,而不是为了图像去噪,因此找到ω(β)的精确值并不重要。

X_final_sparse = scipy.sparse.csr_matrix(np.vstack((X_train_final,X_test_final)))
U, sigma, VT = randomized_svd(X_final_sparse, n_components=min(X_final_sparse.shape[0],X_final_sparse.shape[1])-1,n_iter=5,random_state=45)
beta = min(X_final_sparse.shape) / max(X_final_sparse.shape)
omega_approx = 0.56*beta**3 - 0.95*beta**2 + 1.82*beta + 1.43
tau = np.median(sigma)*omega_approx
k = np.max(np.where(sigma>tau))+1

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

可以看出,新形成的矩阵具有 116 个特征,保留了大部分方差。在这之后,我们将截断的矩阵分成训练集和测试集。

使用神经网络可以降低维数。我们将使用自动编码器,一种有效编码数据的神经网络。注意,自动编码器属于无监督学习。在自动编码器架构中,输入和输出层的大小是相同的。隐藏层的大小总是小于外部层的大小。每个连续隐藏层的尺寸不断减小,直到到达瓶颈层;超过这个范围,尺寸会继续增加。请注意,架构是对称的。压缩数据的部分称为编码器,解压缩数据的部分称为解码器。编码器从输入端向瓶颈层延伸,解码器从那里延伸到末端。瓶颈层应该有我们需要的数据编码的维度。自动编码器旨在最小化重建误差。输入在瓶颈层被压缩,然后在输出层被解压缩。在输入和输出之间的误差最小化之后,训练收敛。

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

在我们的架构中,我们在瓶颈层使用 116 的维度。在网络的每一端只使用了两个隐藏层。训练收敛后,我们需要去掉解码器部分,使用编码器部分将训练集和测试集转换到所需的维度。

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

机器学习

现在,我们已经使用两种不同的降维技术创建了两个版本的数据,我们将尝试使用各种机器学习和深度学习算法对数据进行建模,然后尝试使用不同的指标来比较它们的性能。我们计划对它们分别应用五种不同的算法。这些算法是-K-最近邻(KNN)、逻辑回归、随机森林、xgboost 和多层感知器(MLP)。我们将把它们中的每一个应用于一种形式的数据,然后将它们全部应用于另一种形式的数据。

硬阈值奇异值分解

加权 K 近邻

在 KNN 的情况下使用的超参数是最近邻(K)的计数,其值是范围从 1 到 9 的奇数。当 K 值为 3 时,性能据说是最佳的。验证宏 F1 的分数是 0.8587,不是很好。通过检查测试混淆矩阵,我们可以看到假阳性点的计数大于假阴性点的计数。这不是一个好的分类器。

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

逻辑回归

逻辑回归中使用的超参数是逆正则化常数(C ),其值是 10 的幂,范围从 1e-7 到 1e-3。当 C 的值为 1e-5 时,该模型表现最佳。验证宏 F1 分数为 0.9003,这是好的。不幸的是,当我们绘制测试集的混淆矩阵时,我们可以看到假阳性点的数量大于真阴性点的数量。这不是一个好的分类器。

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

随机森林

随机森林中使用的超参数是基本估计量的计数,在这种情况下是决策树。在 50 和 210 之间选择六个值作为估计数,其中极限包含在集合中。任何两个连续值之间都有 30°的差异。验证宏 F1 得分为 0.9161,非常好。真阴性的计数大于假阳性的计数。这是一个好的分类器。

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

XGBoost

xgboost 中使用的超参数是基本估计量的计数,在这种情况下也是决策树。在 50 和 210 之间选择六个值作为估计数,其中极限包含在如上所述的集合中。验证宏 F1 得分为 0.9191,非常好。真阴性的计数大于假阳性的计数。这是一个好的分类器。

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

多层感知器

现在我们将使用多层感知器进行分类。这种情况下使用的优化器是 Adam,学习率是 1e-3。验证宏 F1 得分为 0.9074,很好。在这种情况下,真阴性的计数大于假阳性的计数。这是一个好的分类器。

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

从目前我们看到的情况来看,random forest,Xgboost 和 mlp 可以正确地对点进行分类。Xgboost 是其中表现最好的。

自动编码器

加权 K 近邻

在 KNN 的情况下使用的超参数是最近邻(K)的计数,其值是范围从 1 到 9 的奇数。当 K 值为 3 时,性能据说是最佳的。验证宏 F1 的分数是 0.8564,不是很好。通过检查测试混淆矩阵,我们可以看到假阳性点的计数大于假阴性点的计数。这不是一个好的分类器。

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

逻辑回归中使用的超参数是逆正则化常数(C ),其值是 10 的幂,范围从 1e-7 到 1e-3。当 C 的值为 1e-2 时,该模型表现最佳。验证宏 F1 分数为 0.8874,没问题。当我们绘制测试集的混淆矩阵时,我们可以看到假阳性点的计数大于真阴性点的计数。这是一个糟糕的分类器。

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

随机森林

随机森林中使用的超参数是基本估计量的计数,在这种情况下是决策树。在 50 和 210 之间选择六个值作为估计数,其中极限包含在集合中。任何两个连续值之间都有 30°的差异。验证宏 F1 得分为 0.8895,很好。不幸的是,真阴性的数量少于假阳性的数量。这是一个糟糕的分类器。

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

XGBoost

xgboost 中使用的超参数是基本估计量的计数,在这种情况下也是决策树。在 50 和 210 之间选择六个值作为估计数,其中极限包含在如上所述的集合中。验证宏 F1 分数为 0.8867,没问题。不幸的是,真阴性的数量少于假阳性的数量。这是一个糟糕的分类器。

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

多层感知器

现在我们将使用多层感知器进行分类。这种情况下使用的优化器是 Adam,学习率是 1e-3。验证宏 F1 分数为 0.8924,没问题。在这种情况下,真阴性的计数小于假阳性的计数。这是一个糟糕的分类器。

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

从我们这里可以看出,我们不能使用自动编码器压缩的数据集来设计一个好的分类器。

原始数据集

我们还没有尝试将标记化的评论直接作为模型的输入。为了实现这一点,我们需要对整个数据集进行操作,而不是对数据集的截断或压缩版本进行操作。为此,我们将尝试两种深度学习模型。

在最初的模型中,我们将只尝试使用长短期记忆(LSTM)。我们为这个模型创建了两个不同的输入。第一个输入是数字数据,另一个是文本数据。嵌入层将标记化的输入转换成固定长度的向量。我们正在使用 FastText 训练嵌入层。因此,使用该层将标记化和填充的文本转换成单词嵌入。这条道路上的下一层是 LSTM。当给定一个序列时,该层能够学习顺序依赖性。下一层直接输送到致密层。这两个输入稍后合并,在输出端有一个 sigmoid 激活函数。验证宏 F1 得分为 0.9211,非常好。真阴性的计数大于假阳性的计数。这是一个好的分类器。

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

在下一个模型中,我们计划使用 1 维卷积神经网络和 LSTM。在这里,我们连续使用两对一维 CNN 和 LSTM 层,然后将其与数值数据相结合。这里,我们也使用 sigmoid 作为最后的激活函数。验证宏 F1 得分为 0.9010,很好。真阴性的计数大于假阳性的计数。这是一个好的分类器。

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

当我们检查总结表时,我们可以看到双输入 LSTM 和 xgboost 在使用硬阈值 SVD 截断的数据上对测试数据的性能最好。

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

降维

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

没有降维

未来的工作

我们可以将这个问题转化为一个多类分类问题,并检查评级预测。这是一种称为对数损失的度量,也可以用作替代方法。也有可能使用其他系综。

部署

下面给出了部署的屏幕截图。同样的一段录像可以在 这里 观看。

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

预测截图

链接

LinkedIn:【https://www.linkedin.com/in/ashwin-michael-10b617142/】
Github 库:https://github.com/Ashcom-git/case-study-1
Kaggle 数据集:https://www.kaggle.com/olistbr/brazilian-ecommerce

参考

应用根。2021.应用 AI 课程。[在线]见:https://www.appliedaicourse.com/.[2021 年 5 月 6 日访问]。
泰勒,共和党,2021 年。最优奇异值硬阈值。[在线]Pyrunner.com。可在:http://www.pyrunner.com/weblog/2016/08/01/optimal-svht/【2021 年 5 月 9 日获取】。布朗利律师事务所,2021 年。自动编码器特征提取分类。[在线]机器学习掌握。可在:<https://machine learning mastery . com/auto encoder-for-class ification/>【2021 年 5 月 12 日访问】。
t . Calin 和 j .薛,2021。tensor flow中的自定义 f1_score 指标。[在线]堆栈溢出。可在:https://stackoverflow.com/a/64477588【2021 年 5 月 7 日获取】。
堆栈溢出。2021.如何用 matplotlib.pyplot 改变图例尺寸。[在线]可在:https://stackoverflow.com/a/7125157[2021 年 5 月 3 日访问]。
阿齐兹,h .,库马尔,s .,科尔舒诺夫,v .和阿萨,p .,2021。正则表达式匹配日期格式 DD-MM-YYYY 和 DD/MM/YYYY 。[在线]堆栈溢出。可在:https://stackoverflow.com/a/47218282【2021 年 5 月 13 日获取】。
沃尔玛和铺路公司,2021 年。匹配换行符— \n 还是\r\n?。[在线]堆栈溢出。可在:https://stackoverflow.com/a/52057778【2021 年 5 月 14 日获取】。Python,h .和 Martin,l .,2021。如何在 Python 中移除一个字符串内的任何 URL。[在线]堆栈溢出。可在:https://stackoverflow.com/a/11332580【2021 年 5 月 14 日获取】。
莫滕森,第 2021 页。如何使用正则表达式删除尾部空格?。[在线]堆栈溢出。可在 https://stackoverflow.com/a/9532388<获得>【2021 年 5 月 16 日获得】。

案例研究 2:用于特征提取的无监督神经注意模型

原文:https://towardsdatascience.com/case-study-2-an-unsupervised-neural-attention-model-for-aspect-extraction-1c2c97b1380a?source=collection_archive---------22-----------------------

行业笔记

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

马库斯·温克勒Unsplash 上拍摄

十多年来,企业一直利用互联网的可达性来为其内容做广告。如果没有这种广告媒介,这些公司就很难获得他们想要的客户群。但随着社交网站的快速增长,互联网已经发展成为一个论坛,消费者可以根据他人在网上发布的产品反馈来评估产品和服务。对任何特定产品的评论决定了它在市场上的声誉。关于网上购物行为的各种研究表明,潜在客户在信任任何特定产品之前,平均至少会阅读四到五条评论。这就是为什么顾客评论对企业的运作至关重要。在这个案例研究中,我们将探索基于方面的抽取的概念,这对于在线评论是至关重要的。我们将它分为以下几个部分—

  • 问题描述
  • 车型概述
  • 数据描述
  • 数据预处理
  • 模型架构
  • 基线模型
  • 结论
  • 部署
  • 未来工作
  • 链接
  • 参考文献

问题描述

情感分析是一种自然语言处理技术,用于确定给定文本是正面的、负面的还是中性的。当您希望从给定的文本块中推断出整体情感时,这种技术非常有用。这种技术的一个缺点是,如果人们希望了解客户对产品的哪个方面不满意,就必须手动筛选每个评论。这种形式的体力劳动非常耗时。在这种情况下,基于方面的情感分析是更好的选择。使用这种技术,我们可以通过将情感与评论的特定方面联系起来来分析评论。

在 2017 年由何,Wee Sun Lee,Hwee Tou Ng 和 Daniel Dahlmeier 发表的题为“一种用于方面提取的无监督神经注意力模型”的研究论文中,研究人员设计了一种无监督的深度神经网络,可以根据它们的方面对一组句子进行分类。这个模型限制了它自己只能识别每个输入的一个方面,并且没有将任何情感与这个方面相关联。任何经过适当训练以执行情感分析的模型都可以在评论被分离后应用于评论。在本案例研究中,我们将从头开始设计 2017 年研究论文中提到的模型。我们将使用 Tensorflow 2.x .作为 Python 中用于模型构建和训练的后端框架。

模型概述

以前训练来执行这项任务的传统机器学习模型假设每个句子中出现的单词是独立的,上下文无关。这种假设导致这些模型的性能下降。单词嵌入是在 2013 年由托马斯·米科洛夫、伊利亚·苏茨基弗、程凯、格雷格·科拉多和杰弗里·迪恩发表的题为“单词和短语的分布式表示及其组合性”的论文中引入的。在这篇文章中,他们介绍了一个名为 Word2Vec 的模型。这个模型的目的是表明句子的上下文有多重要。使用这种模型,相似的单词被映射到相似方向的向量。同现单词在嵌入空间中彼此靠近。

在 2014 年由 Dzmitry Bahdanau、Kyunghyun Cho 和 Yoshua Bengio 撰写的题为“通过联合学习对齐和翻译”的神经机器翻译的研究论文中,注意力机制的概念被引入到语言翻译任务中。这项技术模仿了注意力的认知过程,允许任何生物选择并专注于相关的刺激。按照这种技术,文本的某些部分比整个文本具有更高的优先级。换句话说,注意力使模型能够在训练过程中强调重要的单词,而不强调无关的单词。这提高了模型发现更多一致方面的能力。研究人员给这个模型起的名字是基于注意力的方面提取(ABAE)。

数据描述

我们将使用城市搜索语料库作为训练和测试的数据集,可以从这个网站免费下载。研究论文中使用了相同的数据集来测试模型。数据集中有 52,574 条评论,其中只有 3,400 条被标记。本文考虑了六个方面。这些方面是食物,工作人员,氛围,价格,轶事,和杂项。研究人员选择未标记的数据作为训练集,选择标记的数据作为测试集。这些设置可以在研究者的谷歌驱动链接上找到。

数据预处理

加载测试集和训练集之后,我们需要对它们进行预处理。为了这个
的目的,我们定义了 preprocess()和 complete_preprocess()
函数。

使用这个函数,我们将评论中的所有单词转换成小写字母后进行分词。下一步是将这些令牌符号化。从本质上讲,通过将每个单词转换成其对应的词条,词条化有助于使您的数据矩阵更加稀疏。这样的词被称为是他们的规范形式或字典形式。此外,请注意,我们必须删除不会给评论增加任何价值的停用词。

为了训练 Word2Vec 模型,我们需要以列表的形式提供输入。这意味着每个评论被转换成一个列表,整个集合是一个包含多个子列表的列表。这可以在 split_list 函数的帮助下完成。

所有评论都以字符串表示形式提供。深度神经网络模型无法理解字符串,因此,我们需要以数字格式对它们进行编码。这意味着检查中出现的每个令牌都应该映射到一个大于或等于 1 的唯一数字。所有字符串,包括数字 8 和 9,当出现在评论中时都有唯一的映射。但是根据研究论文,在映射到相应的表示之前,所有的数字都应该表示为由表示的单个标记。当将测试数据转换成相应的数字表示时,可以看到这个集合可能包含一些在训练集中不可用的单词。我们会在映射前用来表示这样的词。为了保持输入数据的一致性,我们需要将所有这些令牌列表转换成统一的长度。这可以在衬垫的帮助下完成。使用这种技术,通过在映射前预先计划或附加标记,所有的标记列表都被转换成相同的大小。在我们的例子中,我们将在每个列表前面加上标记。每个填充集的宽度等于该集中最长句子的长度。预留令牌的映射为:{’ ‘:0,’ ‘:1,’ ':2}。从这个映射中,我们可以推断出集合中出现的所有单词都应该得到 3 或更大的值。下面给出了一个标记化和填充表示(最大长度为 4)的虚拟示例,说明输入在输入到模型之前应该是什么样子——

"I ate 2 donuts" -> ["I", "ate", "2", "donuts"] -> [3, 4, 2, 5]“I dislike donuts” -> ["<pad>", "I", "dislike", "donuts"] ->
[0, 3, 6, 5]"I drank" -> ["<pad>", "<pad>", "I", "drank"] -> [0, 0, 3, 7]

模型架构

在前面提到的引入 Word2Vec 概念的论文中,研究人员还添加了一个称为负采样的概念,帮助我们更快地训练单词嵌入。通俗地说,负面样本是从训练集中所有可用评论的集合中随机选取的评论。这意味着,当我们将一篇综述作为输入(称为正样本或目标样本)时,我们应该挑选一组 P 篇综述与目标样本一起作为负样本。这里,P 可以是一个小数字,例如 5 或 6,或者甚至可以是一个更大的数字,例如 21 或 22。请注意,我们并没有按照已经存在于训练集中的顺序将输入直接输入到模型中。这是为了应对训练数据的过度拟合。为了总结这个令人困惑的概念,让我仔细地将我的话重组如下——当 P 的值是 5 时,在一个时期的每一步中,我们用从训练集随机采样的 1 个评论作为正输入,用从这个相同的集替换随机采样的 5 个评论作为负样本来呈现模型。在这种情况下,假设批量大小为 1。如果批量大小被设置为值 32,则在一个时期的任何一个步骤中,我们将 321=32 个正样本与 325=160 个负样本一起输入到模型中。这是生成阳性和阴性样本的代码—

现在是详细了解 ABSA 的时候了。下面给出了该模型的架构。这里需要注意的重要一点是,该图仅描述了阳性样本的处理。

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

基于注意力的情感分析器架构(图片取自纸张)

使用从 Word2Vec 模型生成的所有单词嵌入,我们将它们组合成一个矩阵。这个矩阵将被视为嵌入矩阵。下一步是使用 k-means 聚类算法训练这个矩阵,并识别模型收敛后生成的聚类中心。形成的聚类中心的数目等于 k 的值,k 是我们在训练过程之前手动馈入模型的超参数。k 的值应该是我们希望使用 ABSA 模型识别的不同方面的数量。rₛ层的权重矩阵(在上图中表示为 t)使用所有这些聚类中心的归一化形式进行初始化。这个 T 矩阵也被称为方面矩阵。

正样本和负样本的最大区别在于,正样本被馈送到注意层,而后者没有。但是在进一步处理之前,所有的样本必须通过一个不可训练的嵌入层被转换成单词嵌入。该层使用在先前步骤之一中创建的嵌入矩阵来初始化。使用 Tensorflow 的子类化 API,我们设计了多个自定义层来处理样本。

第一个自定义层的名称是“平均”。它可以计算评论中所有单词嵌入的平均值,用术语 yₛ.表示

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

yₛ公式(图片取自纸张)

然后,正样本嵌入和 yₛ值被馈送到关注层。术语 dᵢ表示单词嵌入、矩阵 m 和 yₛ.的转置之间的中间乘法这里,M 是可训练的,并使用 Glorot 统一初始化器进行初始化。在这个初始化式中,样本是从特定范围内的均匀分布中抽取的。这个极限值的计算取决于这个矩阵的形状。通过在 dᵢ上应用 softmax,我们计算 aᵢ,这是注意力权重。

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

dᵢ和 aᵢ的公式(图片取自纸张)

下一个自定义图层名为 WeightedSum。使用这一层,我们计算每个单词的嵌入和为每个单词计算的注意力权重之间的点积。这个点积用术语 zₛ.来表示

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

zₛ公式(图片取自纸张)

使用 Tensorflow 的自然密集层,我们将 zₛ乘以随机初始化的权重,然后将偏差项添加到其中。最重要的是,我们应用 softmax。这一层在文中被称为 pₜ。

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

pₜ公式(图片取自纸张)

下一步是通过自定义平均层传递负样本。我们得到的输出是一个包含每个样本平均值的列表。这个列表用 zₙ.来表示最后一层是 rₛ,我们之前提到过。下面给出的是 rₛ和 pₜ.之间的关系

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

rₛ公式(图片取自纸张)

自动编码器是用于压缩数据的无监督神经网络架构。输入和输出的大小相同。中间有一个瓶颈层,用于将数据压缩到所需的大小。从输入层到瓶颈层的部分称为编码器,从瓶颈层到输出层的部分称为解码器。这个网络的目标是在输出端重构被瓶颈层压缩的输入。通过训练模型,我们试图最小化重建误差。

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

Autoencoder 模型(图片作者: Seongju Hong

整个 ABSA 模型是一个定制的自动编码器。从输入层到 pₜ层的部分是编码器,从 pₜ层到 rₛ层的部分是解码器。我们的目标是最小化 rₛ层的重建误差。

在 2016 年由 Mohit Iyyer,Anupam Guha,Snigdha Chaturvedi,Jordan Boyd-Graber 和 Hal Daumé III 撰写的题为“世仇家庭和前朋友:动态虚构关系的无监督学习”的论文中,研究人员提到了对比最大利润损失的概念。如果负样本嵌入与重构嵌入相似,这个损失函数会严重地惩罚模型。这意味着损失函数试图最大化 rₛ和 zₛ之间的乘积,而它试图最小化 rₛ和 nᵢ(when nᵢ之间的乘积是来自列表 zₙ).的元素我们使用一个名为 HingeLoss 的自定义层来执行这一步中必要的计算。损失函数的公式如下所示

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

J(θ)的公式(图片取自纸张)

为了防止过度拟合,我们需要正则化模型。甚至为了这个目的,提到了定制的 L2 正则化。另外,请注意,我们应该使用方面矩阵的规范化形式进行正则化。使用自定义函数将正则化代码应用于密集 rₛ图层。

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

U(θ)的公式(图片取自纸张)

我们计划使用 RMSProp 作为训练这个模型的优化器。学习率为 1e-02,ε值为 1e-06。在训练该模型时,有必要设置 clipnorm 值。在我们的例子中,我们将其设置为 10。这意味着梯度的 L2 范数被限制在给定值。我们正在为 15 个时期训练模型,并且在每个时期考虑 182 个批次。批量大小设置为 1024,负采样率为 20。当在任何时期中计算的损失小于先前记录的最小损失时,我们显示从每个方面得到的前 50 个单词及其相应的相似性得分。以下是培训代码—

从印刷的文字,我们必须手动推断方面。相应地,我们还应该基于这些信息创建一个聚类图。现在是时候使用张量板绘制表示最小化的图形了。如你所见,模型收敛于损失值 4.7。

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

张量板图(图片由作者提供)

现在是对测试集执行预测的时候了。我们将需要创建一个新的自定义模型使用以前制作的 ABSA 模型的层。对于这个新制作的模型,我们将只使用为 ABSA 模型中的正样本设计的输入层作为该模型的输入。该模型的输出是 ABSA 的 pₜ层。

研究人员根据这些方面对测试进行了筛选。他们只允许那些属于食物、员工或环境方面的评论。该模型不能在一次审查中识别多个方面。因此,即使那些包含多个样本的评论也被删除了。在这一步之后,最后的任务是执行预测和生成分类报告。正如你所看到的,ABSA 模型的性能似乎是公平的!

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

ABSA 分类报告(图片由作者提供)

基线模型

主题建模是一种无监督的方法,通过找到一些自然的项目组(在此上下文中称为主题)来对文档进行分类。这项技术已经使用了很长时间,因为它可以自动组织、理解、搜索和有效地汇总数据。最流行的主题建模算法是潜在狄利克雷分配(LDA)。这是基于基线模型方面的情感分析任务。我们将比较我们的 ABSA 模型的结果和使用 LDA 模型获得的结果。

一个文档可以是具有不同相似比例的多个主题的一部分。每个文档(在我们的例子中也称为评论)是一个单词列表。我们真正想弄清楚的是一个单词属于每个主题的概率。表格中的每一行代表一个不同的主题,每一列是数据集中出现的一个不同的单词。每个单元格包含单词(列)属于主题(行)的概率。

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

每个主题包含所有可用单词的概率分数(图片由 Ria Kulshrestha 提供)

对于我们的任务,这些主题只是方面。因此,导出的主题数量等于我们分析所需的方面数量。关于单词的一个重要假设是这些单词的顺序和语法结构并不重要。这意味着单词是独立的,这样的假设会导致性能下降。无论如何,我们将在我们的训练集上训练 LDA 模型,批量大小设置为 1024。下面给出了显示属于每个方面的前 50 个单词的代码。

在打印分类报告时,我们可以观察到 ABSA 模型在方面提取任务方面的性能更好。

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

LDA 分类报告(图片由作者提供)

结论

如您所见,基于神经网络的模型非常适合基于方面的情感分析任务。这种表现应该归功于注意机制。

部署

下面提到了部署的截图。同样的录像可以在这里观看。

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

预测截图(图片由作者提供)

未来的工作

我们的模型只能识别包含不超过一个方面的评论。此外,当我们希望评估与任何给定方面相关的情绪时,我们需要使用其他模型。这一领域未来的研究应该集中在这两个问题上。

链接

Github 资源库:【https://github.com/Ashcom-git/case-study-2

领英:https://www.linkedin.com/in/ashwin-michael-10b617142/

参考

应用根。[在线]地址:https://www.appliedaicourse.com/。

何、李维孙、吴惠头和丹尼尔·达尔梅尔(2017)。用于特征提取的无监督神经注意模型。计算语言学协会第 55 届年会会议录(第 1 卷:长论文)。

‌tomas·米科洛夫、伊利亚·苏茨基弗、陈开、格雷戈·科拉多和杰弗里·迪恩(2013 年)。词和短语的分布式表示及其组合性。神经信息处理系统进展 26 (NIPS 2013)。

Dzmitry Bahdanau、Kyunghyun Cho 和 Yoshua Bengio。(2015).通过联合学习对齐和翻译的神经机器翻译。第三届国际学习代表会议论文集。

Mohit Iyyer、Anupam Guha、Snigdha Chaturvedi、Jordan Boyd-Graber 和 Hal Daumé III。(2016).世仇家庭和前朋友:动态虚构关系的无监督学习。计算语言学协会北美分会 2016 年会议论文集:人类语言技术。

陈燕琳(2019 年)。如何使用文本建立 ld a 主题模型?【在线】中等。可从以下网址获得:https://medium . com/@ yanlinc/how-to-build-a-LDA-topic-model-using-from-text-601 CDC bfd 3 a 6。

苏珊·李(2018)。Python 中的主题建模和潜在狄利克雷分配。【在线】中等。可从以下网址获得:https://towards data science . com/topic-modeling-and-latent-Dirichlet-allocation-in-python-9bf 156893 c 24。

Ria Kulshrestha (2020 年)。潜在狄利克雷分配。【在线】中等。可从 https://towards data science . com/latent-Dirichlet-allocation-LDA-9d 1 CD 064 FFA 2 获取。

桑内·德·罗弗(2020)。方面,更好的话题?在亚马逊化妆品评论中应用无监督特征抽取。【在线】中等。可从以下网址获得:https://medium . com/@ sanne . de . ro ever/aspects-the-better-topics-applying-unsupervised-aspect-extraction-on-Amazon-cosmetics-reviews-9d 523747 f8e 5。

为 360 度数据谱系的外部资产编目

原文:https://towardsdatascience.com/catalog-external-assets-for-a-360-data-lineage-448c8f6bf2b2?source=collection_archive---------33-----------------------

如何定制 IBM Watson 知识目录以支持任何种类的外部资产并改进您的数据治理。

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

由 DreamQuest 在 pixabay 上拍摄的照片

在之前的文章中,我已经展示了如何通过使用 IBM Cloudpak for Data 特别是 Watson 知识目录来自动分类大量数据集。

好的企业目录是数据治理的基石。在这里可以记录所有数据和治理资产的存在以及它们之间的关系。为了回答数据沿袭问题,确定任何给定资产的依赖图,或者进行影响分析,获取资产之间的关系是必不可少的。

例如,维护良好的目录应该有助于回答以下问题:

这个数据集的数据从哪里来?

这个数据集中的数据用在哪里?

如果该资产被修改或删除,将会影响到哪项资产?

只有当所有与感兴趣的资产直接或间接相关的资产都被正确编目时,业务目录才能回答这些问题。这些资产可能具有非常不同的性质,例如:

  • ETL 流——或一般的数据流——将数据从源移动和转换到目标。
  • 直接或间接使用数据集数据的报告。
  • ML 模型是从数据集导出的数据构建的。
  • Jupyter 笔记本电脑根据从数据集获得的数据进行实验。
  • 等等…

这个列表可能很长,在数据谱系中扮演重要角色的资产类型可能会因公司使用的技术而有很大不同。

使问题复杂化的是,现实生活中的场景很少只涉及来自单一供应商的同类解决方案。公司经常使用不同供应商的解决方案,这些解决方案运行在不同的系统上,但都在数据资产的生产、转换或消费方式中发挥作用。

没有一个软件供应商可以提供一个业务目录来支持您在现实生活中可能遇到的所有类型的资产。因此,能够定制目录以支持新的资产类型、加载它们并捕获它们与其他编目资产的关系是至关重要的,无论这些新资产的性质如何。

本文的目标是展示如何使用 IBM Watson 知识目录来完成这项工作。

IBM 沃森知识目录

IBM Watson 知识目录是用于数据的 IBM Cloudpak 的业务目录,支持开箱即用的不同资产类型,例如:

  • 数据连接
  • 数据资产(表、文件、模式、数据库等)
  • 商业术语
  • 数据类别
  • ML 模型
  • 等等…

该列表并不详尽,并且会随着 Cloudpak for Data 的每个新版本而不断增加。

但是像任何软件一样,除非您的流程只涉及使用 Cloudpak 为数据创建的资产,否则您的数据和治理流很可能涉及外部资产,这些资产不受目录的现成支持,但是仍然应该被编目,以便获得完整的数据血统。这种外部资产可以是 ETL 流、来自其他供应商的报告或数据模型、物联网流中的物理设备,或者来自在 Cloudpak 外部管理的其他 IBM 产品的资产。

幸运的是,IBM Watson Knowledge Catalog 提供了一个 API 来注册新类型的资产,并通过 REST API 加载外部资产。在本文的剩余部分,我们将通过一个简单的例子来了解如何使用这个 API。

编目 IBM 信息分析器数据规则

Watson Knowledge Catalog 的定制可以用任何种类的资产来演示,但是出于本文的目的,我将通过一个例子来演示如何添加对 IBM Information Analyzer 数据规则的支持,这些数据规则运行在 Cloudpak 之外的经典信息服务器上。您应该能够将该过程移植到不同类型的资产。

信息分析器数据规则概述

数据规则是在 IBM Information Server 中创建和执行的资产类型,它定义了一个非平凡的数据质量约束,该约束必须由应用该规则的数据集的所有行来验证。关于数据质量约束的更多细节,请参见我之前的文章“如何量化数据质量”

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

IBM Information Analyzer 项目中定义的数据规则

解释数据规则的细节超出了本文的范围,但是就本练习的目的而言,目前您唯一需要理解的是,数据规则是具有以下特征的资产:

  • 它是在主机上的 IBM Information Server 安装中定义的资产,该主机可能与运行 IBM Cloudpak for Data 的主机不同。
  • 像任何其他资产一样,数据规则有一个名称、描述和一个 ID,在定义它的系统中唯一地引用它。
  • 数据规则是在数据质量项目(也称为工作空间)的上下文中定义的。
  • 数据规则至少与一个数据集相关,但它也可以应用于多个数据集的连接结果。

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

使用两个数据集绑定数据规则的详细信息

Information Analyzer 数据规则还有其他属性,如绑定细节或输出定义等,但是为了保持示例的简单性,我们将只考虑前面列出的用于本练习的属性,因为它们足以捕获数据规则和其他资产之间的依赖关系。

一个 IBM Information Server 安装可能定义了数百个数据规则。它们中的每一个都可能与不同的数据资产相关。在本文的其余部分,我们将看到实现以下目标所需的不同步骤:

  1. 定义一个新的资产类型来表示 IBM Watson 知识目录中的信息分析器数据规则
  2. 提取外部 IBM 信息服务器的所有数据规则的相关元数据。
  3. 将提取的数据规则的元数据加载到目录中,并在新加载的数据规则和已经编目的数据资产之间创建关系。

为了保持这个例子的简单,我们将假设要加载的数据规则所引用的所有数据资产都已经在 Watson Knowledge Catalog 中编目。这可以通过运行数据规则引用的数据源的自动发现来完成,正如我在以前的文章中所描述的。

在 Watson 知识目录中定义新的自定义资产类型:

为了简化我们将在本文中使用的命令,让我们首先在一个 UNIX shell 中定义一个环境变量***【WKC _ 主机】*** ,它包含我们想要对数据规则进行编目的 Cloudpak for Data 系统的主机名。

export WKC_HOST=*cpd_cluster_host*

(您需要将 cpd_cluster_host 替换为目标系统的 IP 地址的主机名)

接下来,让我们通过运行下面的命令获得一个认证令牌,如 CP4D 文档中所述。

curl -k -X POST https://*$WKC_HOST*/icp4d-api/v1/authorize -H 'cache-control: no-cache' -H 'content-type: application/json' -d '{"username":"***username***","password":"***password***"}'

(将 用户名密码 替换为授权用户的凭证详情)

该命令响应是一个 JSON 文档,如下所示:

{"_messageCode_":"200","message":"Success","token":"...some_long_string..."}

让我们复制令牌属性的值,并将其放在另一个环境变量中,这样我们就不需要在每个命令中复制该令牌:

export TOKEN=...some_long_string...

现在我们有了一个认证令牌,我们准备使用 WKC REST API 来操作沃森知识目录的资产类型,如在文档中所描述的。您可以使用 REST API 探索默认的资产类型,并检索它们定义的 JSON 表示,以便更好地理解它们是如何定义的。

在我们的例子中,我们将通过使用 REST API POST {service_URL}/v2/asset_types?catalog_id={catalog_id} 来创建一个名为 data_rule 的新的定制资产类型,如文档的本节中所述。

自定义资产类型特定于目录。Watson Knowledge Catalog 可能包含多个目录,因此您需要找出您想要导入新资产的目录的 ID。您可以通过在 UI 中打开目录并在浏览器中查看 URL 来轻松确定目录的 id。目录 ID 是 URL 中路径元素 /catalogs/ 后面的一个长字符串,如下例所示:

[https://yourserver.yourcompany.com/data/catalogs/**b134fdf3-7d3f-40e0-835b-7ce54a62cc7e**?context=icp4data](https://wkc-cpd-wkc.apps.wkc-ia-test3-lb.fyre.ibm.com/data/catalogs/b184fda3-7d3f-40e0-835b-7ce54a62cc7e?context=icp4data)

这里,让我们再次复制该 ID,并将其放入环境变量中:

export CATALOG_ID=**<catalog_id pasted from the URL>**

创建新资产类型的 POST 命令需要一个 JSON 文档作为主体,该文档定义了要创建的新资产类型的元数据。文档至少应该包含新资产类型的名称和描述,以及对其字段的描述。在我们的例子中,我们将使用以下属性:

  • 名称:数据 _ 规则
  • 描述:信息分析仪数据规则
  • 资产字段:
    • 主机:包含规则的信息服务器系统的主机名。
    • 项目名称:定义规则的信息分析器项目的名称。
    • rid :源信息服务器中数据规则的唯一标识。

请注意,我们不需要为与数据规则相关的数据资产定义属性,因为这些将通过使用资产关系来定义,WKC 允许我们在任何种类的资产之间定义资产关系。

基于这个为数据规则编目的初始最小字段列表,创建新资产类型的 REST API 的有效负载可以定义如下:

{
  "description": "Information Analyzer Data Rule",
  "name": "data_rule",
  "fields": [
     {
        "key": "host",
        "type": "string",
        "facet": true,
        "is_array": false,
        "search_path": "host",
        "is_searchable_across_types": true
     },
     {
        "key": "projectName",
        "type": "string",
        "facet": true,
        "is_array": false,
        "search_path": "projectName",
        "is_searchable_across_types": true
     },
     {
        "key": "rid",
        "type": "string",
        "facet": false,
        "is_array": false,
        "search_path": "rid",
        "is_searchable_across_types": true
     }
  ]
}

将新资产类型的定义保存在文件data _ rule _ asset _ type . JSON中,并运行以下命令在目标目录中创建新的资产类型。

curl -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header "Authorization: Bearer $TOKEN" -d @data_rule_asset_type.json "https://$WKC_HOST:443/v2/asset_types?catalog_id=$CATALOG_ID"

如果命令成功,它应该返回一个成功代码(200 ),带有新创建的资产类型的 JSON 定义。

接下来让我们试着通过使用 API POST {service_URL}/v2/assets?catalog_id={catalog_id}创建一个新类型的样本资产,如文档中所描述的。

与创建新的资产类型一样,我们需要准备一个 JSON 格式的有效负载,描述要在目标目录中创建的新资产。

创建一个文件dummydatarule . JSON,内容如下:

{
  "metadata": {
    "asset_type": "data_rule",
    "name": "Dummy Data Rule 1",
    "description": "Some Dummy Data rule",
    "tags": ["tag1", "tag2"],
    "origin_country": "us",
    "rov": {
      "mode": 0
    }
  },
  "entity": {
    "data_rule": {
        "host": "iaHost1",
        "projectName": "iaProject1",
        "rid": "rid1" 
    }
  }
}

此有效负载包含创建新资产所需的最少信息:

  • asset_type 定义要创建的资产的类型。在我们的例子中,我们使用新创建的定制资产类型 data_rule
  • 名称描述 是我们要新建的虚拟数据规则的名称和描述。
  • 标签 是可选的,它包含一个与新创建的资产相关联的目录标签数组。标签可用于方便搜索或提供资产的附加信息。在本例中,我们关联了两个虚拟标签 tag1tag2
  • origin _ countryrov 定义资产的位置和权限。出于本文的目的,我们将使用一些默认值。
  • 字段 实体 必须包含一个与资产类型名称相同的字段——在我们的例子中是data _ rule——它本身包含我们在上一步创建新的定制资产类型时定义的字段值。在我们的例子中,基于前面对资产类型 data_rule 的定义,我们可以定义 3 个属性 hostprojectNamerid

让我们通过运行以下 cURL 命令在目录中提交这个新数据规则的创建:

curl -k -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header "Authorization: Bearer $TOKEN" -d @dummyDataRule.json "https://$WKC_HOST:443/v2/assets?catalog_id=$CATALOG_ID"

如果该命令成功,它应该返回一个包含其 id 的新创建资产的 JSON 描述,并且当打开目标目录时,您应该能够在 Watson Knowledge Catalog UI 中看到新创建的虚拟数据规则。

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

Watson 知识目录中加载了虚拟数据规则

创建与其他资产的关系

与任何其他资产一样,新创建的自定义资产可以与其他资产相关联。您可以通过使用 UI 来定义这些关系,但是在我们的示例中,我们希望通过编程来实现,因为我们希望自动导入大量的资产。

创建资产间关系的 API 记录在这个链接下。简而言之,API 是带有 JSON 主体的PUT /v2/assets/{asset_id}/relationships/{relationship_name}?catalog_id={catalog_id}, JSON 主体指定资产和目标资产的目录 id。

为了测试这个特性,让我们找出同一目录中一个数据集的 id,并在我们的虚拟数据规则和那个数据集之间定义一个类型为 “uses/used by” 的关系。找出数据集 id 的一个简单方法是在 UI 中打开数据集,并从浏览器中的 URL 复制它的 id。

我们必须传递给 PUT 命令以创建关系的 JSON 有效负载如下:

{
  "relationship_targets": [
    {
      "catalog_id": "19f11301-8392-4733-b747-751f5230e566",
      "asset_id": "81fa1a02-4773-4801-a53b-1d374fb83b07"
    }
  ]
}

catalog_idasset_id 的值替换为您想要链接到数据规则的数据资产的 id,或者可以是任何其他资产类型,并将有效负载保存在文件add relationship . JSON中。然后使用下面的 cURL 命令创建关系——您需要用之前创建的虚拟规则的 id 替换占位符******。

curl -k -X PUT --header 'Content-Type: application/json' --header 'Accept: application/json' --header "Authorization: Bearer $TOKEN" -d @addRelationship.json "https://$WKC_HOST:443/v2/assets/***<datarule_id>***/relationships/uses?catalog_id=$CATALOG_ID"

在命令运行之后,当在 UI 中打开数据规则时,您应该能够看到类型 使用 的新关系。打开数据集,会看到 使用的 类型的反向关系指向数据规则。

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

数据规则和数据资产之间的新关系

自动化流程

既然我们已经成功地定义了新的资产类型,并测试了可以使用 REST APIs 将数据规则导入到目录中,那么让我们自动化这个过程,从外部 IBM Information Server 安装中提取所有数据规则并对其进行编目。

第一个问题是提取规则的元数据。信息服务器提供了多种机制来实现这一点。您可以使用 REST API,或者针对元数据数据库(XMETA)编写 SQL 查询。在本文中,我们将使用 SQL。

解释 IBM Information Server 的 SQL API 超出了本文的范围。有关更多详细信息,您可以参考信息服务器文档。为了简化本文,我准备了一个现成的 SQL 查询,它允许检索给定信息分析器项目的所有数据规则的名称、描述以及相关数据集的路径:

SELECT DISTINCT PROJECT.NAME AS PROJECT, 
       RULE.NAME, 
       RULE.SHORTDESCRIPTION AS DESCRIPTION, 
       CONCAT('/',CONCAT(COL.SCHEMA,CONCAT('/',COL.TABLE))) AS PATH FROM IAVIEWS.IARULE RULE
INNER JOIN IAVIEWS.IAPROJECT PROJECT ON RULE.PROJECTRID=PROJECT.RID
INNER JOIN IAVIEWS.IARULEBINDING BINDING ON BINDING.RULERID=RULE.RID
INNER JOIN IAVIEWS.IAREGISTEREDCOLUMN COL ON BINDING.TARGETRID=COL.RID
WHERE PROJECT.NAME='***<ProjectName>***'

该查询将返回如下图所示的结果。如果一个规则绑定到多个表,结果将包含每个绑定表的一行。因此在下面的例子中,项目 【测试 _ 规则】 包含 2 个数据规则,一个被命名为 “子 _ 测试 _ 银行 _ 客户” ,并被绑定到路径为***/BANK 1/BANK _ 客户*** 的数据集。另一个名为 “信用卡 _ 年龄 _ 银行 2”,绑定到两个数据集,路径分别为***/银行 2/银行 _ 账户*** 和***/银行 2/银行 _ 客户*** 。

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

检索信息分析器项目的数据规则的 SQL 查询的结果

在此基础上,我们需要编写一些脚本:

  • 运行前面的 SQL 查询,从 IBM Information Server 安装中检索所选信息分析器项目的所有数据规则
  • 对于每个提取的数据规则,执行 Watson Knowledge Catalog REST API,在目标目录中创建新的数据规则资产
  • 在目录中搜索与数据规则引用的数据集具有相同路径的数据集,并在新创建的数据规则和目录中已解析的数据集之间创建关联。

为了使本文简单,我在 Jupyter noteboook 中用 Python 实现了所有这些步骤:

运行笔记本中的所有单元后(如笔记本中所述,您将需要根据系统的详细信息调整一些变量),您将在 Watson Knowledge Catalog 中看到所有外部数据规则都表示为普通目录资产。

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

在 IBM Watson 知识目录中作为定制资产导入的数据规则

当打开数据规则时,您可以看到已经创建了与其相关数据集的关系—假设在执行笔记本时数据资产已经导入到目录中。

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

导入数据规则的资产详细信息,显示与数据资产的关系

同样的关系也可以从数据资产中看到,它包含了一个类型为 "的反向关系,由指向数据规则的 使用。

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

数据资产和数据规则之间的关系,从数据资产中显示

自定义资产预览

新创建的自定义资产与 Watson Knowledge Catalog 本机支持的任何其他资产类型一样显示,只是“资产预览”选项卡默认为空。

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

默认情况下,资源预览不适用于自定义资源类型

还可以在目录中嵌入自定义资产预览 UI,只要它是可以在 Web 浏览器中打开的 Web UI。

在我们的示例中,可以使用以下 URL 打开用于查看数据规则详细信息的 Information Analyzer Web UI:

[https://***<iis_hostname>***/ibm/iis/igcui/assets/***<datarule_rid>***](https://iaqa95-ug-2.fyre.ibm.com/ibm/iis/igcui/assets/b20de59c.ef0f3886.2pg7c6fpc.9vr2drb.jt2tg2.hh5573mmk20lu7fohkfth)

Watson Knowledge Catalog 提供了一种注册 URL 的方法,以便在需要显示用于预览特定资产类型的 UI 时调用。这是通过稍微更新我们之前创建的资产类型的 JSON 定义来完成的:

{
  "description": "Information Analyzer Data Rule",
  "fields": [
     {
        "key": "host",
        "type": "string",
        "facet": true,
        "is_array": false,
        "search_path": "host",
        "is_searchable_across_types": true
     },
     {
        "key": "projectName",
        "type": "string",
        "facet": true,
        "is_array": false,
        "search_path": "projectName",
        "is_searchable_across_types": true
     },
     {
        "key": "rid",
        "type": "string",
        "facet": false,
        "is_array": false,
        "search_path": "rid",
        "is_searchable_across_types": true
     }
  ]**,
  "external_asset_preview": {
    "base_client_url": "**[**https://<iis_hostname>/ibm/iis/igcui/assets**](https://iaqa95-ug-2.fyre.ibm.com/ibm/iis/igcui/assets)**",
    "url_parameters_from_asset_attributes": [],
    "url_path_from_asset_attributes": "rid"
  }**
}

用粗体标记的附加属性指定,每当需要预览这种类型的资产时,WKC 应该调用通过附加 base_client_url 和在属性URL _ path _ from _ asset _ attributes中指定的资产属性的值构建的 URL。

为了测试此更改,请将***替换为您从中导入数据规则的信息服务器主机名,并将修改后的 JSON 文档保存在名为data _ rule _ with _ preview _ asset _ type . JSON***的文件中。然后使用以下命令更新资产类型的定义:

curl -k -X PUT --header 'Content-Type: application/json' --header 'Accept: application/json' --header "Authorization: Bearer $TOKEN" -d @data_rule_with_preview_asset_type.json "https://$WKC_HOST:443/v2/asset_types?catalog_id=$CATALOG_ID"

该命令将更新 data_rule 资产类型的现有定义。更新后,如果您重新加载目录的资产预览屏幕,您应该会看到一条消息(至少在 Firefox 上是这样),表明出于安全原因,该页面不能嵌入,但您可以在不同的浏览器选项卡中加载它。这是 Information Server UI 的一项安全功能,可防止原始 UI 嵌入到另一个 UI 中,但这仍然提供了一种在不同选项卡中打开此 UI 的便捷方式。通过部署不同的 web 应用程序,可以嵌入没有这种安全限制的 UI 面板。

摘要

在本文中,我们已经看到了为了获取完整的谱系,目录支持定制的资产类型是多么重要。我们还看到了如何通过使用 Watson Knowledge Catalog 的 REST API 来轻松实现这一点。作为一个具体的例子,我们已经定制了一个目录来支持外部信息分析器数据规则作为一个新的资产类型,并运行一个脚本来将所有外部数据规则导入到我们的目录中。然后,我们已经看到,如何以编程方式创建资产之间的关系。最后,我们探索了如何使用专门的资产查看器定制 UI 本身。

同样的过程可以应用于支持任何种类的资产类型,对于这些资产类型,可以提取元数据信息,以便将它们导入到目录中。我们只研究了几个 REST APIs。其他 API 命令也允许我们定义资产之间的特殊类型的关系,以更好地捕捉语义。

资源下载链接为: https://pan.quark.cn/s/9a27693985af 《基于SSM的JSP招聘网》是一款功能丰富的在线招聘平台,主要面向普通游客、求职者、企业和管理员四种用户角色,提供了多样化的服务与管理功能。该系统采用SSM(Spring、SpringMVC、MyBatis)技术栈开发,确保了系统的稳定性与高效性。以下是对系统功能模块及其技术实现的介绍。 对于普通游客,系统提供职位浏览功能。游客可以查看平台上的各种招聘信息,如职位描述、工作职责、薪资待遇等。这需要后台数据库对招聘信息进行有效存储和检索。在SSM框架中,SpringMVC负责处理HTTP请求,将数据传递给Spring服务层进行业务逻辑处理,MyBatis作为持久层工具,执行SQL查询并将结果映射为Java对象。 求职者注册成为平台用户后,可进行职位收藏和投递。收藏的职位信息会保存在个人中心,方便随时查看。职位投递功能涉及用户个人信息与简历的提交,需要系统具备用户认证和授权机制,可通过Spring Security或Apache Shiro实现。此外,系统可能采用AJAX技术进行异步操作,如即时刷新收藏夹状态,以提升用户体验。 企业用户可在系统中发布职位、查看求职者简历。发布职位时,需进行表单验证和数据合法性检查,SpringMVC的控制器可协同前端校验库(如Hibernate Validator)完成。查看简历时,企业可对求职者进行筛选和评价,这要求数据库设计合理,以便快速查询和分析求职者信息。 管理员负责管理平台运行,包括用户管理、职位审核、系统设置等。管理员模块通常包含后台管理界面,通过SpringMVC的模型视图解析器和模板引擎(如Thymeleaf或FreeMarker)生成动态页面。同时,日志记录和异常处理必不可少,Spring框架提供了强大的日志和AOP支持,可方便实现这些功
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值