TowardsDataScience 2024 中文翻译(七十七)
原文:TowardsDataScience协议:CC BY-NC-SA 4.0如何在企业层面同时实施知识图谱和大型语言模型(LLMs)原文:towardsdatascience.com/how-to-implement-knowledge-graphs-and-large-language-models-llms-together-at-the-enterprise-level-cf2835475
如何在企业层面同时实施知识图谱和大型语言模型(LLMs)
来源:OpenArt SDXL
当前集成方法的调研
https://stevehedden.medium.com/?source=post_page---byline--cf2835475c47--------------------------------https://towardsdatascience.com/?source=post_page---byline--cf2835475c47-------------------------------- Steve Hedden
·发布于Towards Data Science ·阅读时长 13 分钟·2024 年 4 月 19 日
–
大型语言模型(LLMs)和知识图谱(KGs)是提供更多人群访问数据的不同方式。KGs 通过语义将数据集连接起来,即通过它们所代表的实体的含义。LLMs 通过向量和深度神经网络来预测自然语言。它们通常都旨在“解锁”数据。对于实施 KG 的企业,最终目标通常是类似于数据市场、语义层,将数据公平化,或者使企业更加以数据为中心。这些都是不同的解决方案,目标相同:让更多的数据更快地提供给正确的人。对于实施 LLM 或其他类似生成 AI 解决方案的企业,目标通常是类似的:为员工或客户提供一个“数字助手”,帮助更快地将正确信息提供给正确的人。潜在的协同效应是显而易见的:LLM 的一些主要弱点——它们是黑箱模型,且在事实知识上表现较差——恰恰是 KG 的一些最大优势。KG 本质上是事实的集合,并且是完全可解释的。但究竟 KG 和 LLM 应如何以及应该如何在企业中结合实施呢?
去年我在找工作时,必须写很多求职信。我使用 ChatGPT 来帮助——我会将我现有的求职信复制到提示窗口中,再加上我的简历和我所申请的职位的职位描述,然后让 ChatGPT 完成剩下的部分。ChatGPT 帮助我快速起步,写出了几份相当不错的初稿,但如果不加以审查,它也给了我一些我并没有的工作经验,还声称我去过我从未就读过的学校。
我提到我的求职信是因为 1) 我认为它是 LLM 的优缺点的一个很好的例子,说明了 KG 在 LLM 实现中的重要性;2) 这个使用案例与许多大型企业当前使用 LLM 的方式并没有太大不同:自动化报告生成。ChatGPT 在通过改变内容使其更加针对特定职位描述的同时,能够很好地重建求职信,**只要你在提示中明确包括现有的求职信和职位描述。确保 LLM 拥有正确的内容正是 KG 发挥作用的地方。**如果你只是写道:“为我想要的工作写一封求职信”,结果将是可笑的。此外,求职信示例是 LLM 的一个很好的应用,因为它涉及到总结和重组语言。还记得 LLM 中的第二个 L 代表什么吗?LLM 历史上专注于非结构化数据(文本),而这正是它们的强项,而 KG 则擅长于整合结构化和非结构化数据。你可以使用 LLM 来写求职信,但你应该使用 KG 来确保它有正确的简历。
注:我不是 AI 专家,但我对任何假装知道 AI 未来的人也有些怀疑。这个领域变化如此之快,根本无法跟上,更不用说预测企业层面 AI 实现的未来样貌了。以下是我认为当前 KG 和 LLM 集成的一些方式,这绝不是一个全面的列表,我也愿意接受补充和建议。
KG 和 LLM 的两种关联方式
目前,知识图谱(KG)和 LLM 的互动方式有两种:LLM 作为构建 KG 的工具,以及 KG 作为 LLM 或生成型人工智能(GenAI)应用的输入。我们这些在知识图谱领域工作的人,正处在一个奇怪的位置:我们在构建旨在改善 AI 应用的事物的同时,AI 又在改变我们构建这些事物的方式。我们被期望在日常工作中将 AI 作为工具进行优化,同时改变我们的输出,以促进 AI 的优化。这两种趋势相互关联,且常常重叠,但我将在下面逐一讨论它们。
使用 LLM(大语言模型)辅助知识图谱的创建和管理过程
LLM 是构建 KG 的有价值工具。在 KG 管理过程中,利用 LLM 技术的一个方法是通过将 KG 向量化(或嵌入)到向量数据库中。向量数据库(或向量存储)是为存储向量或数字列表而构建的数据库。向量化是驱动语言模型的核心技术组件之一(如果不是唯一的核心技术的话)。这些模型通过大量的训练数据,学会将单词与向量关联起来。这些向量根据训练数据中的上下文,捕捉关于单词的语义和句法信息。通过使用经过大量数据训练的嵌入服务,我们可以在 KG 中利用这些语义和句法信息。
注:将知识图谱向量化绝不是使用 LLM 技术进行知识图谱策划和构建的唯一方式。此外,LLM 在这些应用中的使用对于知识图谱的创建并不新鲜。例如,NLP 已经被用于实体提取几十年,LLM 只是作为一种新的能力来协助本体论专家/分类法专家。
大型语言模型(LLM)在知识图谱创建过程中可以提供帮助的一些方式包括:
-
**实体解析:**实体解析是对指向同一现实世界实体的记录进行对齐的过程。例如,扑热息痛(acetaminophen),一种在美国常用的止痛药,以泰诺(Tylenol)为品牌销售,在英国被称为对乙酰氨基酚(paracetamol),并以潘达洛(Panadol)为品牌销售。这四个名称看似毫无相似之处,但如果你将你的知识图谱(KG)嵌入到向量数据库中,向量将具备语义理解,知道这些实体是紧密相关的。
-
**无结构数据标注:**假设你想将一些无结构数据整合到你的知识图谱中。你有一堆文件名模糊的 PDF 文件,但你知道这些文件中有重要信息。你需要为这些文档添加文件类型和主题标签。如果你的主题分类法和文档类型分类法已经嵌入,所有你需要做的就是将文档向量化,向量数据库将能够识别出每个分类法中最相关的实体。
-
**实体和类别提取:**根据一组无结构数据创建或增强受控词汇,如本体论或分类法。实体提取类似于标注,但这里的目标是增强本体论,而不是将无结构数据整合到知识图谱中。假设你有一个地理本体论,并且你希望将城镇、城市、州等实例填充到其中。你可以使用大型语言模型(LLM)从一组文本中提取实体来填充本体论。同样,你也可以使用 LLM 从文本中提取类别和类别之间的关系。假设你忘记在本体论中包含“首都”这一类。LLM 可能能够将其提取为新的类别或城市的一个属性。
使用知识图谱(KG)来驱动和管理生成式人工智能(GenAI)流水线
使用知识图谱(KG)来驱动和管理你的生成式人工智能(GenAI)流水线和应用程序有多种理由。根据Gartner的说法,“到 2025 年,至少 30%的生成式人工智能项目将在概念验证(POC)阶段之后因数据质量差、风险控制不足、成本上涨或商业价值不明确而被放弃。”知识图谱可以帮助提高数据质量、降低风险并减少成本。
数据治理、访问控制和合规性
只有授权的人和应用程序才能访问某些数据并用于特定目的。通常,企业希望某些类型的人(或应用程序)以良好的治理方式与某些类型的数据进行交互。你如何知道哪些数据应该进入哪个生成型人工智能(GenAI)流程?你如何确保个人身份信息(PII)不会进入你希望所有员工都能与之对话的数字助手?答案就是数据治理。以下是一些额外的要点:
-
政策和法规可能会发生变化,尤其是在人工智能领域。即使你的人工智能应用程序现在符合规定,未来也未必如此。一个良好的数据治理基础可以帮助企业适应这些变化的法规。
-
有时,问题的正确答案是“我不知道”,或者“你没有访问回答该问题所需的信息”,或者“回答这个问题对我来说是非法或不道德的”。回应的质量不仅仅是事实或准确性的问题,还涉及到合规性问题。
-
实施或支持通过知识图谱(KG)进行数据治理的主要参与者(按字母顺序): 语义知识图谱公司,如Cambridge Semantics、data.world、PoolParty、metaphacts和TopQuadrant,还有数据目录如Alation、Collibra和Informatica(以及更多)。
准确性和上下文理解
知识图谱(KG)还可以帮助提高整体数据质量——如果你的文档充满了矛盾和/或错误的陈述,当你的聊天机器人告诉你不一致和错误的信息时,不要感到惊讶。如果你的数据结构不良,将其存储在一个地方也不会有帮助。这就是数据湖的承诺如何变成数据沼泽的灾难。同样,如果你的数据结构不良,将其向量化也无法解决你的问题,它只会创造一个新的头痛问题:向量化的数据沼泽。然而,如果你的数据结构良好,知识图谱可以为大型语言模型(LLMs)提供额外的相关资源,从而以多种方式生成更个性化和准确的推荐。有多种方法可以利用知识图谱提高大型语言模型的准确性,但它们通常都属于自然语言查询(NLQ)范畴——使用自然语言与数据库互动。据我所知,目前实现 NLQ 的方式包括 RAG、提示到查询(prompt-to-query)和微调。
检索增强生成(RAG): RAG 指的是用训练数据之外的额外相关信息来补充提示,从而生成更准确的回答。尽管 LLM 已经在大量数据上进行过训练,但它们并没有在你的数据上进行训练。想象一下上面提到的求职信示例。我可以让 LLM“为 Steve Hedden 写一封申请 TopQuadrant 公司产品管理职位的求职信”,它会返回一个回答,但其中可能包含虚假信息。一种更聪明的做法是让模型接收这个提示,检索 Steve Hedden 的 LinkedIn 资料,检索 TopQuadrant 公司该职位的职位描述,然后再写求职信。目前有两种主要的检索方式:通过将图谱向量化或将提示转换为图谱查询(提示到查询)。
-
基于向量的检索: 这种检索方法要求将你的知识图谱(KG)向量化,并将其存储在向量存储中。如果你随后将自然语言提示也向量化,你就可以在向量存储中找到与提示最相似的向量。由于这些向量对应于图谱中的实体,你可以根据自然语言提示返回图谱中最“相关”的实体。这与上述标记能力描述的过程完全相同——我们本质上是在用来自知识图谱的相关标签来“标记”提示。
-
提示到查询检索: 作为替代方案,你可以使用大语言模型(LLM)生成一个 SPARQL 或 Cypher 查询,并使用该查询从图谱中获取最相关的数据。注意:你可以使用提示到查询的方法直接查询数据库,而不将结果用于补充 LLM 的提示。这将不属于 RAG 应用,因为你并没有“增强”任何内容。该方法在下面将进一步详细说明。
关于 RAG 和两种检索方法的一些额外优缺点和说明:
-
RAG 本质上需要一个知识库。知识图谱是一个知识库,因此知识图谱的支持者也会支持基于图谱的 RAG(有时称为 GraphRAG)。但是 RAG 也可以在没有知识图谱的情况下实现。
-
RAG 可以根据提示的内容以及提示中的元数据,从你的 KG 中补充最相关的数据。例如,我们可以根据谁提出问题、他们可以访问哪些资源以及关于他们的其他人口统计信息来定制回答。
-
如上所述,使用基于向量的检索方法的一个好处是,如果你已将 KG 嵌入到向量数据库中进行标签和实体解析,困难的部分已经完成。找到与提示相关的最相关实体与用来自 KG 的实体对一段非结构化文本进行标记并没有什么不同。
-
RAG 提供了一定程度的可解释性。用户现在可以看到进入其提示的补充数据,以及潜在的,回答他们问题的答案所在的那些数据。
-
我在上面提到,人工智能正在影响我们构建知识图谱的方式,而我们被要求构建能够促进 AI 的知识图谱。提示到查询的方法就是一个完美的例子。知识图谱的架构将影响 LLM 查询的效果。如果知识图谱的目的是为 AI 应用提供数据,那么“最佳”本体不再是现实的反映,而是 AI 视角下对现实的反映。
-
理论上,更多相关的信息应该能够减少幻觉现象,但这并不意味着 RAG 可以消除幻觉。我们依然在使用语言模型生成回应,因此仍然存在大量的不确定性和幻觉。即使有我的简历和职位描述,一个大型语言模型(LLM)仍然可能夸大我的经验。对于文本查询方法,我们使用 LLM 来生成知识图谱(KG)查询和回应,因此实际上存在两个可能出现幻觉的地方。
-
同样,RAG 提供了一定程度的可解释性,但并非完全。例如,如果我们使用基于向量的检索,模型可以告诉我们它包含了哪些实体,因为这些实体是最相关的,但它无法解释为什么这些实体是最相关的。如果使用自动生成的 KG 查询,自动生成的查询“解释”了为什么图谱返回了某些数据,但用户需要理解 SPARQL 或 Cypher 才能完全理解为什么这些数据会被返回。
-
这两种方法并不互相排斥,许多公司正在同时追求这两种方法。例如,Neo4j 提供了关于实现 RAG 的教程,涉及 基于向量的检索 和 从提示生成查询。据我个人经验,我在参加一个重点讨论生命科学中知识图谱与 LLM 实施的会议后写下这些内容,许多我看到的生命科学公司都在做基于向量的和从提示到查询的 RAG 的组合。
-
实施或支持 RAG 解决方案的著名玩家(按字母顺序): data.world,Microsoft,Neo4j,Ontotext,PoolParty,SciBite,Stardog,TopQuadrant(还有很多很多其他公司)
仅使用提示-查询: 使用 LLM 将自然语言查询转换为适用于你的 KG 的正式查询(例如 SPARQL 或 Cypher)。这与上面描述的提示-查询检索方法(RAG)相同,只不过我们在数据检索后不会将其发送给 LLM。这里的想法是,通过使用 LLM 来生成查询而非解释数据,你可以减少幻觉的发生。尽管如此,正如前面提到的,LLM 生成的内容可能仍然包含幻觉。采用这种方法的论据是,用户更容易在自动生成的查询中发现幻觉,而不是在自动生成的响应中。我对这种说法有些怀疑,因为推测许多使用 LLM 生成 SPARQL 查询的用户可能对 SPARQL 不够熟悉,无法检测到自动生成查询中的问题。
用于微调 LLM 的知识图谱(KGs): 使用你的 KG 为现成的 LLM 提供额外的训练。与其在查询时将 KG 数据作为提示的一部分(RAG),你可以使用 KG 来训练 LLM 本身。这样做的好处是,你可以将所有数据保留在本地——无需将提示发送给 OpenAI 或其他任何人。缺点是,LLM 中的第一个 L 代表“大型”,因此下载和微调一个 LLM 是资源密集型的。此外,虽然基于你的企业或行业特定数据微调的模型会更加准确,但它并不能完全消除幻觉。对此的一些额外思考:
-
一旦使用图形数据来微调模型,你也会失去将图形数据用于访问控制的能力。
-
根据使用案例,微调 LLM 可能不是必须的。例如,如果你主要使用 LLM 来总结新闻文章,那么 LLM 可能不需要特别的训练。
-
与其通过行业特定的信息来微调 LLM,有些人更倾向于使用已经微调过、专门生成代码的 LLM(比如Code Llama)作为其提示-查询解决方案的一部分。
-
实施或启用专注于使用 KG 来微调 LLM 的解决方案的知名企业: 据我所知,Stardog的 Voicebox 是唯一一个使用 KG 来为客户微调 LLM 的解决方案。
关于我在这里列出的集成 KG 和 LLM 的不同方式的说明: 这些分类(RAG、提示查询和微调)既不全面,也非互斥。还有其他实施 KG 和 LLM 的方法,并且未来会有更多。此外,这些解决方案之间有相当大的重叠,你可以将不同的解决方案结合使用。例如,你可以在一个经过微调的模型上运行基于向量的提示查询 RAG 混合解决方案。
效率与可扩展性
构建许多相互独立且无法连接的应用程序是低效的,这正是 Dave McComb 所称的软件荒原。即使这些应用程序是“由 AI 驱动”的也无关紧要。孤立的应用程序会导致数据和代码的重复,以及整体的冗余。知识图谱(KG)为消除这些冗余提供了基础,确保数据在整个企业中能够顺畅流动。
上述 Gartner 的观点是,许多 GenAI 项目将因为成本上升而被放弃,但我不确定 KG 是否能显著降低这些成本。我不知道有任何研究或成本效益分析来支持这一观点。为企业开发一个基于 LLM 的聊天机器人是昂贵的,开发 KG 也是如此。
结论
我不会假装知道“最优”解决方案,但正如我之前所说,我认为没有人知道。我确实相信,KG 和 LLM 是任何希望更快将更多数据提供给正确人员的有用工具,它们各自有其优点和缺点。用 LLM 写求职信(或监管报告),但用 KG 确保你给了它正确的简历(或研究、期刊文章等)。
一般来说,我相信尽可能多地使用 AI 来构建、维护和扩展知识图谱,我也认为 KG 对那些希望采用 GenAI 技术的企业来说是必要的。这有几个原因:数据治理、访问控制和监管合规性;准确性和上下文理解;以及效率和可扩展性。
如何实现最先进的掩码自编码器(MAE)
使用视觉变换器(Vision Transformers)构建 MAE 的一步步指南
https://medium.com/@francoisporcher?source=post_page---byline--6f454b736087--------------------------------https://towardsdatascience.com/?source=post_page---byline--6f454b736087-------------------------------- François Porcher
·发布于 Towards Data Science ·阅读时间:7 分钟·2024 年 9 月 16 日
–
大家好!对于还不认识我的朋友们,我叫 Francois,我是 Meta 的研究科学家。我热衷于解释先进的 AI 概念,并使其更加易于理解。
今天,我很高兴深入探讨计算机视觉领域,继视觉变换器(Vision Transformers)之后最重要的突破之一:掩码自编码器(MAE)。本文作为我之前文章的实践实现伴随教程:掩码自编码器(MAE)终极指南
在以下教程中,我们将使用此 GitHub 仓库中的代码:
[## GitHub - FrancoisPorcher/awesome-ai-tutorials: 最佳 AI 教程合集,帮助你成为数据科学的高手…
最佳的 AI 教程合集,帮助你成为数据科学的高手! - FrancoisPorcher/awesome-ai-tutorials
github.com](https://github.com/FrancoisPorcher/awesome-ai-tutorials?source=post_page-----6f454b736087--------------------------------)
这里简要提醒一下其工作原理:
图像来自文章 MAE 是可扩展的学习器
以下是该方法的工作原理:
1. 图像被分割成多个补丁。
2. 这些补丁的一个子集被随机掩盖。
3. 仅将可见的补丁输入到编码器中 (这至关重要)。
如何通过理解嵌入质量提升人工智能性能
了解如何确保你的嵌入质量,这对于你的机器学习系统至关重要。
https://oieivind.medium.com/?source=post_page---byline--8bcbcb37a60f--------------------------------https://towardsdatascience.com/?source=post_page---byline--8bcbcb37a60f-------------------------------- Eivind Kjosbakken
·发表于 Towards Data Science ·阅读时间:10 分钟·2024 年 2 月 14 日
–
创建高质量的嵌入是大多数人工智能系统的重要组成部分。嵌入是人工智能模型进行工作的基础,因此,创建高质量的嵌入是打造高精度人工智能模型的关键元素。因此,本文将讨论如何确保嵌入的质量,从而帮助你创建更好的人工智能模型。
“为人工智能创建可读取嵌入图像”提示。图像由ChatGPT提供,OpenAI,2024 年 2 月 7 日。chat.openai.com.
引言
首先,嵌入是以数字数组形式存储的信息。在使用人工智能模型时,通常需要嵌入,因为人工智能模型只接受数字作为输入,你不能直接将文本输入到人工智能模型中进行自然语言处理分析。创建嵌入可以通过多种方法实现,如自编码器或通过下游任务的训练。然而,嵌入的问题在于它们对于人眼来说是没有意义的。你不能仅凭数字就判断嵌入的质量,而且一般来说,衡量嵌入质量是一个具有挑战性的任务。因此,本文将解释如何获得你嵌入质量的一个指示,尽管这些…
如何在不到 5 分钟内提升任何提示(聊天界面与代码)
将半成品的句子转化为专家级的提示
https://nabil-alouani.medium.com/?source=post_page---byline--8a819e2fa2ba--------------------------------https://towardsdatascience.com/?source=post_page---byline--8a819e2fa2ba-------------------------------- Nabil Alouani
·发表于Towards Data Science ·9 分钟阅读·2024 年 2 月 5 日
–
所有图片均由作者通过手机、Midjourney 和 Canva 提供。
我靠写提示赚钱,我的朋友们都知道这一点。正因为如此,当其中一个朋友问道:“我们不能只用 ChatGPT 来计算最终的投票结果吗?”时,所有人都把目光投向了房间里的秃头男。
我们有八个人,刚刚品尝了六种不同的国王蛋糕。
“国王蛋糕”是一种传统的法国糕点,通常在一月享用。这是一个根植于基督教和古罗马“萨图尔那利亚节”的庆祝活动,那个节日里社会规范会短暂地被颠倒。
对我们来说,这不过是另一个借口来吃精美的蛋糕,我们决定给它们排名。
每个人都打开了手机上的备忘录应用,但没有人就写下投票的清晰模板达成一致。
-
有些人使用了动态列表,每切下一块蛋糕就把它上下移动。
-
有些人没有按顺序列出它们,而是在每个蛋糕前面加上一个表示排名的数字。有时是之后再加。
-
唯一不变的?拼写错误,这也很自然,因为法国的面包店非常喜欢文字游戏。
如何改善图表,以提升机器学习模型的性能
了解如何改善你的图表,以便用于机器学习任务。
https://oieivind.medium.com/?source=post_page---byline--f7a533a73fc2--------------------------------https://towardsdatascience.com/?source=post_page---byline--f7a533a73fc2-------------------------------- Eivind Kjosbakken
·发表于Towards Data Science·14 分钟阅读·2024 年 4 月 5 日
–
由拓扑信息定义的图表在许多机器学习场景中非常有用。它们可用于社区检测、节点影响、分类等任务。机器学习模型在这些任务上能达到的性能将极大地依赖于图表的质量,这使得改善图表质量变得尤为重要。由于图表质量的重要性,本文将讨论如何改善用于机器学习的图表质量。
了解如何在本文中改善图表。图像由 ChatGPT 生成。“为一篇标题为:如何改善由拓扑信息定义的图表”的文章生成图像提示。ChatGPT,4,OpenAI,2024 年 4 月 3 日。chat.openai.com.
动机
本文的动机来源于我正在进行的一个涉及图表的项目。我创建的图表质量对我的社区聚类算法的性能至关重要,这也是我花费大量时间理论化如何提升图表质量的原因。我将会在本文中提到的每个想法,我都在我自己的图表上进行了测试。一些想法改善了我的图表质量,另一些则降低了质量,还有一些对质量没有影响。如果你想了解每个想法对图表的影响,可以阅读我在《Towards Data Science》上关于测试图表质量的文章:
如何通过更好的采样参数改进 LLM 的响应
深入探讨温度、top_p、top_k 和 min_p 的随机解码
https://medium.com/@leoneversberg?source=post_page---byline--b31a348381f7--------------------------------https://towardsdatascience.com/?source=post_page---byline--b31a348381f7-------------------------------- Dr. Leon Eversberg
·发表于Towards Data Science ·阅读时间 10 分钟·2024 年 9 月 2 日
–
在使用 Python SDK 调用 OpenAI API 时,你是否曾经想过temperature和top_p参数到底是做什么的?
当你向大型语言模型(LLM)提问时,模型会为其词汇表中的每个可能令牌输出一个概率。
在从这个概率分布中采样一个令牌后,我们可以将选定的令牌附加到输入提示中,以便大型语言模型(LLM)可以输出下一个令牌的概率。
这个采样过程可以通过如著名的temperature(温度)和top_p等参数进行控制。
在这篇文章中,我将解释并可视化定义 LLM 输出行为的采样策略。通过理解这些参数的作用并根据我们的使用案例设置它们,我们可以改进 LLM 生成的输出。
对于本文,我将使用VLLM作为推理引擎,并使用微软的新模型Phi-3.5-mini-instruct,该模型采用 AWQ 量化技术。为了在本地运行这个模型,我使用了我笔记本电脑的 NVIDIA GeForce RTX 2060 GPU。
目录
· 理解带 Logprobs 的采样
∘ LLM 解码理论
∘ 使用 OpenAI Python SDK 获取 Logprobs
· 贪心解码
· 温度
· Top-k 采样
· Top-p 采样
· 组合 Top-p…
如何通过 RAG 提高 LLMs
面向初学者的介绍,附带 Python 代码
https://shawhin.medium.com/?source=post_page---byline--abdc132f76ac--------------------------------https://towardsdatascience.com/?source=post_page---byline--abdc132f76ac-------------------------------- Shaw Talebi
·发布于Towards Data Science ·13 分钟阅读·2024 年 3 月 9 日
–
本文是关于在实践中使用大型语言模型(LLMs)更大系列的一部分。在上一篇文章中,我们使用 QLoRA 微调了 Mistral-7b-Instruct,以回应 YouTube 评论。尽管经过微调的模型在回应观众反馈时成功捕捉了我的风格,但它在回答技术性问题时并没有完全符合我的解释。在这里,我将讨论如何通过检索增强生成(即 RAG)来提高 LLM 的表现。
原始的 RAG 系统。图像来源于 Canva。
大型语言模型(LLMs)展示了在回应用户查询时存储和调度海量知识的令人印象深刻的能力。这使得像 ChatGPT 这样的强大 AI 系统的诞生成为可能。然而,以这种方式压缩世界知识存在两个主要限制。
首先,LLM 的知识是静态的,也就是说,随着新信息的出现,它不会更新。其次,LLM 可能对在其训练数据中不突出的小众和专业信息理解不足。这些限制可能导致模型对用户查询的反应不理想(甚至是虚构的)。
我们可以通过利用一个专门的、可变的知识库来缓解这些限制,例如,客户常见问题、软件文档或产品目录。这可以帮助创建更多…
如何在不构建更大模型的情况下提高模型质量
进入谷歌 DeepMind 的“Scaling LLM Test-Time Compute Optimally can be More Effective than Scaling Model Parameters”
https://medium.com/@mgunton7?source=post_page---byline--d6c8e76a86fe--------------------------------https://towardsdatascience.com/?source=post_page---byline--d6c8e76a86fe-------------------------------- Matthew Gunton
·发表于 Towards Data Science ·阅读时间 11 分钟·2024 年 10 月 8 日
–
作者提供的图片 — Flux.1 12B
最近,OpenAI 推出了他们最新的模型 o1。与其突出该模型的参数规模,OpenAI 更强调的是该模型因为花费更多时间而表现得更好。当你向模型提问时,它通常需要几秒钟来响应——这与大多数人现在对大型语言模型(LLM)期望的毫秒级响应速度相去甚远。尽管如此,这额外的时间似乎是值得的,因为 o1 在 LMSYS Chatbot Arena 的得分远高于其他模型。
鉴于这一性能飞跃,每个人都在问:他们是怎么做到的?
Lmsys Chatbot Arena 2024 年 9 月 23 日的数学排名屏幕截图
尽管 OpenAI 尚未公开声明他们是如何取得这些成果的,但最近有几篇论文可能为我们揭示了幕后发生的事情。其中一篇论文是“Scaling LLM Test-Time Compute Optimally can be More Effective than Scaling Model Parameters”。这篇论文探讨了如何利用……
如何将 AI 和数据科学融入到您的商业战略中
数据科学咨询
内部咨询指南:如何成功举办为期两天的高管研讨会
https://medium.com/@hc.ekne?source=post_page---byline--29767ca82b8f--------------------------------https://towardsdatascience.com/?source=post_page---byline--29767ca82b8f-------------------------------- Hans Christian Ekne
·发表于 Towards Data Science ·阅读时间 12 分钟·2024 年 12 月 6 日
–
作者通过 Canva 制作的图片
“我们的行业不尊重传统 — 只尊重创新。” — 萨蒂亚·纳德拉,微软首席执行官,2014 年致员工的信
虽然并非所有行业像软件和云计算行业那样竞争激烈、残酷,但创新并应用最新的技术进展依然是高管们的一个根本主题。经验丰富的商业领袖明白,紧跟相关技术的发展对于成功是必要的。
作为一名数据科学顾问,客户经常问我一些问题:“我们如何有效地将合适的 AI 和机器学习工具整合到我们的业务中?”,以及“我们如何优先考虑 AI 项目,并将其与我们更广泛的公司战略整合?”尤其是在经历了最新的 AI 热潮后,这些问题现在成为议程的重中之重,看起来比以往任何时候都更加紧迫。
使这些问题变得困难的是,好的答案不仅需要了解技术创新,还需要具备领域和商业专业知识。此外,还需要对当前公司的战略有一个基本的理解,以便优先排序并选择合适的举措。因此,与公司高层或某一部门的高层领导进行全面的战略研讨会,是揭示答案的最佳途径之一。
在本文中,我分享了一个蓝图,介绍如何进行为期两天的战略研讨会,目的是找出如何将 AI 和数据科学工具最佳应用于业务。我涵盖了从需要做哪些准备、谁应该参加、如何识别需要深入探讨的主题、研讨会后需要做哪些工作等内容。这个思路是,它可以作为模板,应用于任何行业和几乎任何规模的公司举办研讨会。
在我作为顾问的多年经历中,我与许多能源和金融服务公司合作过,因此你将在文章中看到来自这些行业的案例示例,然而,这个蓝图的设计是行业无关的,方法和原则本质上是通用的。
初步工作
由作者使用 DALL-E 生成的图像
与这种类型的研讨会相关的大部分工作实际上是在研讨会开始之前完成的。引用我最喜欢的发明家和政治家的话:
“不做准备就是准备失败。” — 本杰明·富兰克林
功能领域研究与对齐
根据你对行业的了解程度,准备在研讨会前的研究上投入大量时间。有几个主题需要在你能够草拟研讨会大纲之前解决。
-
行业的高层次理解: 谁是主要参与者,关键驱动因素是什么,趋势是什么,当前的挑战有哪些
-
功能业务领域: 彻底调查你所工作的业务中的关键功能业务领域,然后深入研究每一个领域
尝试将功能领域细分到更细一级,以获得更详细的视角。以能源公用事业为例,典型的功能领域列表可能如下所示:
-
电力生产和能源资源管理: 传统电厂、可再生能源(太阳能、风能、水能)、分布式发电、能源存储系统、发电优化
-
电网管理和资产维护: 输电网络、配电网络、智能电网技术、预测性维护、停运管理、资产生命周期管理
-
客户基础管理、营销和销售: 客户服务、账单与支付、客户关系管理(CRM)、营销活动、销售运营、客户分析
-
能源交易、市场运营和风险管理: 能源采购、批发交易、价格预测、市场分析、对冲策略、风险评估
-
供应链管理和运营效率: 采购、供应商管理、库存管理、物流、流程优化、成本降低
-
财务、合规和监管: 财务规划、预算编制、会计、合规性、审计、政府关系、政策倡导
-
人力资源与劳动力管理: 人才招聘、培训与发展、员工参与、绩效管理、劳动力规划、健康与安全
-
信息技术、网络安全与创新: IT 基础设施、网络安全措施、数据分析、商业智能、创新项目、研究与开发(R&D)、新兴技术(物联网、人工智能、区块链)
-
环境可持续性与企业社会责任: 排放减少计划、可持续性报告、环境合规性、可再生能源证书、社区参与、CSR 项目
你现在已经完成了研究的第一部分,理想情况下,应与客户对齐,确认这份清单是否是他们想要关注的重点,或者他们是否希望在排除某些领域的同时扩展其他领域。上述结构将帮助你更详细地指定工作坊的议程,并有助于引导工作坊的其余研究。
功能领域深入分析
在对结构达成一致后,我们可以开始深入研究每个子类别,了解人工智能和数据科学如何应用于创造价值。这通常是我需要花费最多时间进行研究的部分。
我通常从具体查询开始,比如:“人工智能如何在发电中应用,特别是在风力发电中?”这个查询的结果可能会得出以下主题:
-
使用人工智能和量子计算更好地理解如何规划和优化陆上风电场中风机的位置
-
用于风机故障检测和诊断的时间序列建模
-
用于风机预测性维护的时间序列建模
如果可能的话,尽量量化使用该技术带来的潜在价值。例如,如果能源公司 Equinor 在实施预测性维护项目后能够将风机的非计划停机时间减少 40%,这将如何转化为货币价值?如果你拥有一个包含 1000 个风机的风电场,这个例子如何转化到你的具体业务中?量化这一方面非常重要,因为它将有助于后续工作的优先级排序。
在这个研究阶段,思考跳出框框也很重要,或许可以探索如何将某一特定技术从一个行业借用到另一个行业。许多技术起初在某一行业中应用,随后逐步进入具有类似功能领域的其他行业。例如,数据驱动的客户流失管理最初由电信和银行公司使用,但很快在几乎所有行业得到了应用。
起草议程
在了解了行业、功能性业务领域和技术可能性之后,便可以开始为工作坊起草议程。
对于为期两天的研讨会,我建议至少预留 30 分钟的时间进行介绍,展示研讨会的目标和计划。我还会安排时间回顾研讨会前的发现,这将为参与者提供对他们的集体先验观点、期望和优先事项的深入了解。接下来的时间将专注于选择的职能领域的会议。最后,用对所涵盖话题的总结和后续步骤结束研讨会。
一个为期两天的研讨会,涵盖 9 个职能领域的深入探讨,可以按照以下结构进行安排:
第一天
9:00 AM — 9:30 AM: 欢迎与介绍
9:30 AM — 10:00 AM: 研讨会前发现的回顾
10:15 AM — 11:30 PM: 第一场会议
1:00 PM — 2:15 PM: 第二场会议
2:30 PM — 3:45 PM: 第三场会议
4:00 PM — 5:15 PM: 第四场会议
5:15 PM — 5:30 PM: 第一天总结
第二天
9:00 AM — 9:15 AM: 第一日总结
9:15 AM — 10:30 AM: 第五场会议
10:45 AM — 12:00 PM: 第六场会议
1:00 PM — 2:15 PM: 第七场会议
2:30 PM — 3:45 PM: 第八场会议
4:00 PM — 5:15 PM: 第九场会议
5:15 PM — 5:45 PM: 最终总结与后续步骤
上述结构在各场会议之间留出了休息时间,并有效地利用时间覆盖每个不同的职能领域。在每一场会议中,我通常会花时间处理以下内容:
-
对当前流程的互动讨论
-
案例研究和可行性分析的展示
-
就进一步的人工智能和数据科学发展进行头脑风暴
-
优先考虑关键举措
涉及正确的人员
鉴于人工智能和数据科学的技术性质,首席技术官(CTO)或类似的高管角色是研讨会的自然联系点。理想情况下,你希望有一个真正从技术角度理解业务的人员,并且足够资深,能够吸引其他高管团队的注意。
此外,为了使研讨会的结果具有意义,通常希望公司的大部分高级领导出席。如果首席执行官(CEO)或常务董事不能参加,那是一个警示信号。如果可能,重新安排时间以确保她至少参加研讨会的一部分。
研讨会前的访谈或问卷
为确保研讨会的内容符合公司的成熟度水平、雄心和整体战略,最好进行与领导团队主要成员的访谈。(精心编写的问卷也适用于此目的。)这可以帮助你了解他们在公司各个部门中,人工智能和数据科学的进展情况,从而调整内容的深度。
例如,如果他们已经非常成熟并且拥有一支非常高效的内部数据科学团队,那么你可以采取比从零开始更为激进的策略。
幻灯片展示
我从管理咨询转行做数据科学的原因之一,是为了避免做太多 PowerPoint 幻灯片(😅),但即便是数据科学家,也很难摆脱 PowerPoint 的神秘吸引力。也许你现在已经换用 Canva 了;不过,事实是,如果你希望工作坊有效,拥有一个坚实的幻灯片演示文稿是至关重要的。
演示文稿作为工作坊进行中的指南和参考点,帮助你将所探讨的思想和概念以视觉形式展示。一个好的幻灯片演示文稿能够帮助你保持进度,是成功举办工作坊的关键。
内容的最终确认
在工作坊开始前,你应该始终确保最终获得对内容的批准。与关键利益相关者达成一致非常重要,原因有几个。首先,确保内容正确且相关,并且能够识别需要覆盖的知识盲点。其次,或许最重要的是,通过在规划过程中让关键参与者参与,你能增加利益相关者的支持度,并提高工作坊成功的机会。
主持工作坊
作者使用 DALL-E 生成的图像
一旦完成所有前期步骤,主持工作坊应该相对简单,但仍有一些关键点需要注意。
主持人角色
在你作为主持人的角色中,记住你真正需要的是参与者的互动。你希望避免工作坊变成主持人的演讲和独白。参与者的意见对于成功至关重要。他们通常拥有深厚的行业知识,并且作为高管,他们也有能力推动各种举措。
最终,他们的参与将有助于产生对过程的归属感,使未来的步骤更容易实施。
时间管理
日程安排作为在各个话题之间如何管理时间的指南,然而,时间管理仍然可能是一个挑战。自然,某些话题会引起比其他话题更多的兴趣,必须考虑到这一点。如果某些讨论时间超出了预期,要允许调整日程,避免为了赶时间而匆忙推动参与者完成话题。
远程与现场
尽管可以远程进行工作坊,我仍然强烈建议将关键参与者聚集在同一个房间内。虽然远程工作在很多情况下是个不错的选择,但这不是其中之一。
理想情况下,会议也应在 Teams 或类似平台上进行,这样你可以录制过程并稍后获取工作坊的转录内容。在我们还没有 AI 会议转录之前,我总是会安排专人做记录,以确保我们记录下所有内容。如果没有满意的录音选项,这一点应该考虑到。
工具和产物
我之前的一位雇主喜欢使用棕色纸(我们可以挂在墙上的大卷宽纸)和便利贴来激励参与者并记录结果。我认为这种方法不错,但并非必要。像数字白板这样的工具也很适用。关键在于能够激发参与者的积极性,并记录下发现的内容。
研讨会后的活动
作者使用 DALL-E 生成的图像。
研讨会结束后,您现在需要分析所有的发现和洞察,并草拟一份战略文档,以作为进一步实施工作的指南。
这份文档需要包含的关键点是:
-
一份优先排序的人工智能和数据科学机会清单。
-
一次数据和基础设施评估。
-
一份人工智能和数据科学路线图。
让我们逐一分析上述各点。
一份优先排序的人工智能和数据科学机会清单。
研讨会结束后,您应该能够编制一份优先排序的人工智能和数据科学机会清单,供公司集中关注。这些机会应根据其潜在影响、实施难度、实施成本和与业务目标的一致性进行排名。这样可以更容易选择哪些活动和机会值得追求。
数据与基础设施评估
一旦所有的机会被识别出来,您可以开始理解这些机会将如何影响当前的数据和 IT 基础设施。除非组织在使用人工智能和数据科学方面已经达到较高的成熟度,否则可能需要采取重要步骤来升级基础设施。例如,如果其中一项优先活动是开始对风力涡轮机进行预测性维护,那么您需要开始为涡轮机添加传感器——如果它们还没有安装——并创建数据管道和数据基础设施,以便能够处理传感器数据并将其格式化为可操作的时间序列数据。
人工智能和数据科学路线图
将所有内容汇总成一个计划后,您可以制定一份路线图,详细列出实施这些机会所需的步骤、时间表和资源。在时间表和资源分配上,我更喜欢使用甘特图。然而,为了更直观地理解不同活动如何在不同职能领域下相互配合,我喜欢使用日射图。下图展示了不同机会如何汇聚成完整的未来转型状态。
作者提供的日射转型图示例
跟进研讨会以对齐结果。
我的最后一步是安排另一次研讨会,以对战略文档进行对齐。您发现的人工智能和数据科学计划的路线图及优先排序,现在需要得到领导层的认可,并纳入他们的整体战略中。
拥有一个单独的 AI 和数据科学战略是适得其反的,相反,目标应是将它们的 IT 和 AI 计划整合到公司整体战略中。
总结发言
到目前为止,您应该已经拥有了一个全面的指南,用于规划和执行一个战略研讨会,以识别对您的业务最有价值的 AI 和数据科学机会。
我们已经详细讨论了如何准备研讨会,包括:
-
将公司活动划分为职能领域
-
探讨如何将 AI 和数据科学应用于每个领域
-
起草议程以有效分配时间
-
确定参与过程的关键人员
我们还介绍了如何有效地组织研讨会,强调良好的引导、时间管理、使用适当的工具,以及现场与远程举行研讨会的优势。
我们在文章中讨论的这类研讨会可以成为将 AI 和数据科学整合到您的商业战略中的重要第一步。它有助于确保高层的共识,是转型之旅的起点。
感谢阅读!
想在我发布新文章时收到通知吗? ➡️ 在这里订阅我的新闻通讯 ⬅️。它是免费的,您可以随时取消订阅!
如果您喜欢阅读这篇文章并希望访问更多我的内容,请随时通过 LinkedIn 与我联系,链接在此: https://www.linkedin.com/in/hans-christian-ekne-1760a259/ 或访问我的网页: https://www.ekneconsulting.com/ 以了解我提供的一些服务。如有需要,请随时通过电子邮件联系我,邮箱地址:hce@ekneconsulting.com
如何解释 GPT2-Small
预测重复令牌的机制可解释性
https://medium.com/@vanillaxiangshuyang?source=post_page---byline--76e0536a588a--------------------------------https://towardsdatascience.com/?source=post_page---byline--76e0536a588a-------------------------------- Shuyang Xiang
·发表于Towards Data Science ·阅读时长 7 分钟·2024 年 3 月 22 日
–
大规模语言模型的发展,特别是 ChatGPT,令那些曾经试验过它的人,包括我自己,感到惊讶于它卓越的语言能力和执行各种任务的能力。然而,许多研究人员,包括我自己,虽然对它的能力感到惊叹,但也发现自己感到困惑。尽管我们了解模型的架构以及权重的具体数值,但我们仍然难以理解为何某一特定输入序列会导致特定的输出序列。
在这篇博客文章中,我将尝试通过机制可解释性来揭开 GPT2-small 的神秘面纱,研究一个简单的案例:重复令牌的预测。
机制可解释性
传统的数学工具在解释机器学习模型时,并不完全适用于语言模型。
以 SHAP 为例,它是一个有助于解释机器学习模型的工具。它擅长确定哪些特征显著影响了优质葡萄酒的预测。然而,重要的是要记住,语言模型是在令牌级别进行预测的,而 SHAP 值通常是在特征级别计算的,这使得它们可能不适用于令牌。
此外,语言模型(LLM)有大量的参数和输入,形成了一个高维空间。即便在低维空间中,计算 SHAP 值也非常昂贵,而在 LLM 的高维空间中,这一成本则更为庞大。
尽管容忍了高昂的计算成本,SHAP 提供的解释可能显得肤浅。例如,知道“potter”这个词由于之前提到“Harry”而最影响输出预测,但这并没有提供太多的洞见。这让我们无法确定模型的哪一部分或具体机制对这种预测负责。
机制可解释性提供了一种不同的方法。它不仅仅识别模型预测的重要特征或输入。相反,它揭示了模型的底层机制或推理过程,帮助我们理解模型是如何做出预测或决策的。
GPT2-Small 对重复标记的预测
我们将使用 GPT2-small 进行一个简单的任务:预测一系列重复的标记。我们将使用的库是TransformerLens,该库旨在提供 GPT-2 风格语言模型的机制可解释性。
gpt2_small: HookedTransformer = HookedTransformer.from_pretrained("gpt2-small")
我们使用上面的代码加载 GPT2-Small 模型,并对由特定函数生成的序列进行标记预测。该序列包含两个相同的标记序列,后面跟着 bos_token。例如,当 seq_len 为 3 时,序列为“ABCDABCD” + bos_token。为清晰起见,我们将从序列开始到 seq_len 的部分称为前半部分,将剩余部分(不包括 bos_token)称为后半部分。
def generate_repeated_tokens(
model: HookedTransformer, seq_len: int, batch: int = 1
) -> Int[Tensor, "batch full_seq_len"]:
'''
Generates a sequence of repeated random tokens
Outputs are:
rep_tokens: [batch, 1+2*seq_len]
'''
bos_token = (t.ones(batch, 1) * model.tokenizer.bos_token_id).long() # generate bos token for each batch
rep_tokens_half = t.randint(0, model.cfg.d_vocab, (batch, seq_len), dtype=t.int64)
rep_tokens = t.cat([bos_token,rep_tokens_half,rep_tokens_half], dim=-1).to(device)
return rep_tokens
当我们允许模型在生成的标记上运行时,发现一个有趣的现象:模型在序列的后半部分表现明显优于前半部分。这是通过正确标记的对数概率来衡量的。具体来说,前半部分的性能为-13.898,而后半部分的性能为-0.644。
作者图片:正确标记的对数概率
我们还可以计算预测准确率,定义为正确预测的标记(与生成的标记相同的标记)与总标记数的比率。前半部分序列的准确率为 0.0,这不足为奇,因为我们使用的是没有实际意义的随机标记。与此同时,后半部分的准确率为 0.93,明显优于前半部分。
归纳电路
寻找归纳头
上述观察可能是由归纳电路的存在所解释的。归纳电路扫描序列中的当前标记的前序实例,识别出它之前跟随的标记,并预测相同的序列将会重复。例如,如果它遇到一个‘A’,它会扫描嵌入空间中与‘A’相似的前一个‘A’或标记,识别出随后的标记‘B’,然后预测‘A’之后的标记将是‘B’或与‘B’非常相似的标记。
作者图片:归纳电路
这个预测过程可以分为两个步骤:
-
识别之前相同(或相似)的 token。序列后半部分的每个 token 应该“关注”前面
seq_len位置的 token。例如,如果seq_len为 3,那么位置为 4 的 ‘A’ 应该关注位置为 1 的 ‘A’。我们可以将执行此任务的注意力头称为“引导头”。 -
识别下一个 token ‘B’。这是从前一个 token(例如,‘A’)复制信息到下一个 token(例如,‘B’)的过程。当 ‘A’ 再次出现时,这些信息将用于“重现”‘B’。我们可以将执行此任务的注意力头称为“前一个 token 头”。
这两个头构成了一个完整的引导回路。请注意,有时“引导头”一词也用来描述整个“引导回路”。关于引导回路的更多介绍,我强烈推荐阅读这篇文章 In-context learning and induction head,这是一篇杰作!
现在,让我们在 GPT2-small 中识别注意力头和前一个头。
以下代码用于查找引导头。首先,我们使用 30 个批次运行模型。然后,我们计算带有seq_len偏移量的注意力模式矩阵对角线的平均值。此方法使我们能够衡量当前 token 对 seq_len 之前出现的 token 的关注程度。
def induction_score_hook(
pattern: Float[Tensor, "batch head_index dest_pos source_pos"],
hook: HookPoint,
):
'''
Calculates the induction score, and stores it in the [layer, head] position of the `induction_score_store` tensor.
'''
induction_stripe = pattern.diagonal(dim1=-2, dim2=-1, offset=1-seq_len) # src_pos, des_pos, one position right from seq_len
induction_score = einops.reduce(induction_stripe, "batch head_index position -> head_index", "mean")
induction_score_store[hook.layer(), :] = induction_score
seq_len = 50
batch = 30
rep_tokens_30 = generate_repeated_tokens(gpt2_small, seq_len, batch)
induction_score_store = t.zeros((gpt2_small.cfg.n_layers, gpt2_small.cfg.n_heads), device=gpt2_small.cfg.device)
rep_tokens_30,
return_type=None,
pattern_hook_names_filter,
induction_score_hook
)]
)
现在,让我们检查引导得分。我们会注意到一些头,如第 5 层第 5 头,具有高达 0.91 的引导得分。
作者提供的图片:引导头得分
我们还可以显示该头的注意力模式。你会注意到有一条清晰的对角线,直到 seq_len 的偏移量。
作者提供的图片:第 5 层,第 5 头的注意力模式
类似地,我们可以识别前一个 token 头。例如,第 4 层第 11 头展示了对前一个 token 的强烈模式。
作者提供的图片:前一个 token 头得分
MLP 层如何归因?
让我们考虑这个问题:MLP 层有影响吗?我们知道 GPT2-Small 包含了注意力和 MLP 层。为了解决这个问题,我提出使用消融技术。
消融,顾名思义,是系统地去除模型中的某些组件,并观察性能变化的过程。
我们将用序列前半部分的输出替换序列后半部分的 MLP 层输出,并观察这如何影响最终的损失函数。我们将使用以下代码计算替换 MLP 层输出后的损失与原始后半序列损失之间的差异。
def patch_residual_component(
residual_component,
hook,
pos,
cache,
):
residual_component[0,pos, :] = cache[hook.name][pos-seq_len, :]
return residual_component
ablation_scores = t.zeros((gpt2_small.cfg.n_layers, seq_len), device=gpt2_small.cfg.device)
gpt2_small.reset_hooks()
logits = gpt2_small(rep_tokens, return_type="logits")
loss_no_ablation = cross_entropy_loss(logits[:, seq_len: max_len],rep_tokens[:, seq_len: max_len])
for layer in tqdm(range(gpt2_small.cfg.n_layers)):
for position in range(seq_len, max_len):
hook_fn = functools.partial(patch_residual_component, pos=position, cache=rep_cache)
ablated_logits = gpt2_small.run_with_hooks(rep_tokens, fwd_hooks=[
(utils.get_act_name("mlp_out", layer), hook_fn)
])
loss = cross_entropy_loss(ablated_logits[:, seq_len: max_len], rep_tokens[:, seq_len: max_len])
ablation_scores[layer, position-seq_len] = loss - loss_no_ablation
我们得出了一个令人惊讶的结果:除了第一个标记外,消融实验并没有产生显著的 logit 差异。这表明,在重复标记的情况下,MLP 层可能没有显著的贡献。
作者提供的图片:消融前后 MLP 层的损失差异
一个归纳电路
鉴于 MLP 层对最终预测没有显著贡献,我们可以手动构建一个归纳电路,使用第 5 层的头部 5 和第 4 层的头部 11。回想一下,这些是归纳头和前一个标记头。我们通过以下代码来实现:
def K_comp_full_circuit(
model: HookedTransformer,
prev_token_layer_index: int,
ind_layer_index: int,
prev_token_head_index: int,
ind_head_index: int
) -> FactoredMatrix:
'''
Returns a (vocab, vocab)-size FactoredMatrix,
with the first dimension being the query side
and the second dimension being the key side (going via the previous token head)
'''
W_E = gpt2_small.W_E
W_Q = gpt2_small.W_Q[ind_layer_index, ind_head_index]
W_K = model.W_K[ind_layer_index, ind_head_index]
W_O = model.W_O[prev_token_layer_index, prev_token_head_index]
W_V = model.W_V[prev_token_layer_index, prev_token_head_index]
Q = W_E @ W_Q
K = W_E @ W_V @ W_O @ W_K
return FactoredMatrix(Q, K.T)
计算该电路的 top 1 准确率得到了 0.2283 的值。这对于一个仅由两个头部构建的电路来说相当不错!
有关详细的实现,请查看我的notebook。非常感谢 Neel Nanda,他开发了这个精彩的TransformerLen,这是一个用于大语言模型机制可解释性的伟大工具!
如何解释矩阵表达式 — 变换
数据科学家的矩阵代数
https://medium.com/@jaroslaw.drapala?source=post_page---byline--a5e6871cd224--------------------------------https://towardsdatascience.com/?source=post_page---byline--a5e6871cd224-------------------------------- Jaroslaw Drapala
·发表于Towards Data Science ·阅读时间:23 分钟·2024 年 12 月 4 日
–
本文开启了一个系列,专为那些觉得矩阵代数让人感到压倒性的人准备。我的目标是将你害怕的东西转变为你着迷的东西。如果你想理解机器学习的概念和方法,你会发现这篇文章特别有帮助。
目录:
-
介绍
-
前提条件
-
矩阵-向量乘法
-
转置
-
变换的组合
-
逆变换
-
不可逆变换
-
行列式
-
非方阵
-
逆矩阵和转置:相似性与差异
-
向量平移
-
结语
1. 介绍
你可能已经注意到,虽然很容易找到解释矩阵计算算法的材料,但要找到教授如何解释复杂矩阵表达式的资料却更加困难。我通过我的系列文章来填补这个空白,专注于数据科学家最常用的矩阵代数部分。
我们将更多地关注具体的例子,而不是一般的公式。我宁愿牺牲一般性,以确保清晰性和可读性。我将经常启发你的想象力和直觉,希望我的材料能激发你探索这些主题的更正式资源。对于精确的定义和一般公式,我建议你查阅一些优秀的教科书:经典的线性代数书籍¹和专注于机器学习的另一部著作²。
本部分将教授你
将矩阵视为对数据应用的变换的表示。
那么让我们开始吧——让我引领你进入矩阵的世界。
2. 前提条件
我猜你可以处理接下来的表达式。
这是使用行向量和列向量表示的点积:
矩阵是一个按行和列排列符号的矩形数组。以下是一个具有两行三列的矩阵示例:
你可以将其视为一系列列
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/52f93ad2eec4d242106deb5d97e6d084.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/744dcfeea4c9ef2f971961a72eb40350.png
或者一系列行一个接一个地堆叠在一起:
如你所见,我使用了上标表示行,使用下标表示列。在机器学习中,明确区分观察值(表示为向量)和特征(按行排列)是非常重要的。
表示该矩阵的其他有趣方式包括A₂ₓ₃和A[aᵢ⁽ʲ ⁾]。
矩阵A 和B的乘积结果是第三个矩阵C = AB,包含每一行的A与每一列的B的标量积,按照相应的顺序排列。以下是一个例子,表示C₂ₓ₂= A₂ₓ₃B₃ₓ₂。
其中 cᵢ⁽ʲ ⁾ 是矩阵B的第i列与矩阵A的第j行的标量积:
请注意,这一定义的矩阵乘法要求左矩阵的行数与右矩阵的列数相匹配。换句话说,矩阵的内维度必须匹配。
确保你能够手动进行任意项的矩阵乘法。你可以使用以下代码来检查结果或练习矩阵乘法。
import numpy as np
# Matrices to be multiplied
A = [
[ 1, 0, 2],
[-2, 1, 1]
]
B = [
[ 0, 3],
[-3, 1],
[-2, 2]
]
# Convert to numpy array
A = np.array(A)
B = np.array(B)
# Multiply A by B (if possible)
try:
C = A @ B
print(f'A B = \n{C}\n')
except:
print("""ValueError:
The number of rows in matrix A does not match
the number of columns in matrix B
""")
# and in the reverse order, B by A (if possible)
try:
D = B @ A
print(f'B A =\n{D}')
except:
print("""ValueError:
The number of rows in matrix B does not match
the number of columns in matrix A
""")
A B =
[[-4 7]
[-5 -3]]
B A =
[[-6 3 3]
[-5 1 -5]
[-6 2 -2]]
3. 矩阵-向量乘法
在本节中,我将解释矩阵乘法对向量的影响。向量x与矩阵A相乘,产生一个新的向量y:
这是数据科学中常见的操作,因为它可以实现数据的线性变换。使用矩阵来表示线性变换非常有优势,正如你将在以下示例中看到的那样。
在下方,你可以看到你的网格空间和标准基向量:蓝色代表x⁽¹⁾方向,品红色代表x⁽²⁾方向。
网格空间中的标准基
一个好的起点是使用将二维向量x映射到二维向量y的变换,且它们处在同一个网格空间中。
描述期望的变换其实是一个简单的技巧。你只需要说明基向量在变换后的坐标是如何变化的,并使用这些新坐标作为矩阵A的列。
作为示例,考虑一个线性变换,它产生如下所示的效果。标准基向量绘制得较淡,而变换后的向量则显示得更清晰。
由矩阵A变换的标准基底
通过比较变换前后基向量,你可以观察到该变换涉及关于原点的逆时针 45 度旋转,并伴随着向量的伸长。
这个效果可以通过矩阵A实现,其构成如下:
矩阵的第一列包含变换后的第一个基向量的坐标,第二列包含第二个基向量的坐标。
方程(1)然后变为如下形式
让我们取两个示例点x₁和x₂:
并将它们变换为向量y₁和y₂:
我建议你先手工计算这些内容,然后再使用像这样的程序:
import numpy as np
# Transformation matrix
A = np.array([
[1, -1],
[1, 1]
])
# Points (vectors) to be transformed using matrix A
points = [
np.array([1, 1/2]),
np.array([-1/4, 5/4])
]
# Print out the transformed points (vectors)
for i, x in enumerate(points):
y = A @ x
print(f'y_{i} = {y}')
y_0 = [0.5 1.5]
y_1 = [-1.5 1\. ]
下图显示了结果。
由矩阵A变换的点
x点为灰色且较小,而它们变换后的对应点y具有黑色边缘且较大。如果你更愿意将这些点看作箭头的尖端,下面是相应的插图:
由矩阵A变换的向量
现在你可以更清楚地看到,点已经围绕原点旋转并略微推远了。
我们来研究另一个矩阵:
并查看变换如何作用
影响网格线上的点:
由矩阵B变换的网格线
将结果与使用B/2 得到的结果进行比较,后者对应于将矩阵B的所有元素除以 2:
由矩阵B/2 变换的网格线
一般来说,线性变换:
-
确保直线保持直线,
-
保持平行线平行,
-
按均匀因子缩放它们之间的距离。
为了简洁起见,本文中我将使用“变换 A”这一表述,而不是完整的“由矩阵 A 表示的变换”。
让我们回到矩阵
并将变换应用于一些示例点。
变换B对各种输入向量的作用
注意以下几点:
-
点x₁已被逆时针旋转,并且靠近原点。
-
点x₂,另一方面,已经顺时针旋转并且被推离了原点,
-
点x₃只是被缩小了,意味着它在保持方向不变的情况下移动得更靠近原点,
-
点x₄经历了类似的变换,但被缩放了。
该变换在x⁽¹⁾方向上进行了压缩,而在x⁽²⁾方向上进行了拉伸。你可以把网格线想象成像手风琴一样变化。
像x₃和x₄所表示的方向在机器学习中扮演着重要角色,但那是另一个话题。
目前,我们可以称它们为特征方向,因为沿这些方向的向量可能只会被变换缩放,而不会被旋转。除了旋转之外,每个变换都有一组特征方向。
4. 转置
记住,变换矩阵是通过将变换后的基向量按列堆叠而构建的。也许你想看看如果我们交换行和列(即转置)之后会发生什么。
例如,我们考虑矩阵
其中Aᵀ表示转置矩阵。
从几何角度来看,第一个新基向量的坐标来自于所有旧基向量的第一个坐标,第二个新基向量的坐标来自于第二个坐标,依此类推。
在 NumPy 中,这就是这么简单:
import numpy as np
A = np.array([
[1, -1],
[1 , 1]
])
print(f'A transposed:\n{A.T}')
A transposed:
[[ 1 1]
[-1 1]]
我现在必须让你失望,因为我无法用几句话表达变换A和Aᵀ之间的关系。
但让我向你展示一个原始变换和转置变换都共享的特性,这将在稍后派上用场。
这是由矩阵A表示的变换的几何解释。灰色阴影区域被称为平行四边形。
由矩阵A变换的基向量所生成的平行四边形
将其与应用矩阵Aᵀ得到的变换进行比较:
由矩阵Aᵀ变换的基向量所生成的平行四边形
现在,让我们考虑另一个变换,它对单位向量应用完全不同的缩放:
与矩阵B相关的平行四边形现在变得窄了许多:
由矩阵B变换的基向量所生成的平行四边形
但结果证明它与矩阵Bᵀ的大小是一样的:
由矩阵Bᵀ变换的基向量所生成的平行四边形
让我这样说吧:你有一组数字需要分配给向量的各个分量。如果你给某个分量分配一个较大的数字,那么你就需要给其他分量分配较小的数字。换句话说,构成平行四边形的向量的总长度保持不变。我知道这个推理有点模糊,如果你想要更严谨的证明,可以查阅参考文献部分的相关文献。
这里是这一部分的关键:可以通过计算矩阵的行列式来找到平行四边形的面积。更重要的是,矩阵的行列式与其转置的行列式是相同的。
更多关于行列式的内容将在接下来的部分中介绍。
5. 变换的组合
你可以应用一系列变换——例如,首先对向量x应用A,然后将结果传递给B。这可以通过先将向量x与矩阵A相乘,然后将结果与矩阵B相乘来完成:
你可以将矩阵B和A相乘,以获得矩阵C供进一步使用:
这是矩阵C所表示的变换效果:
由复合矩阵BA描述的变换
你可以按相反的顺序进行变换:首先应用B,然后应用A:
让D表示按此顺序执行的乘法序列:
这就是它如何影响网格线的:
由复合矩阵AB描述的变换
所以,你可以亲自看到矩阵乘法的顺序很重要。
复合变换的转置有一个很酷的性质。来看一下当我们将A乘以B时会发生什么:
然后转置结果,这意味着我们将应用(AB)ᵀ:
你可以很容易地将这个观察结果扩展为以下规则:
在结束这一部分之前,我们考虑逆问题:仅给定C = AB,是否可以恢复矩阵A和B?
这是矩阵分解,正如你所预料的,它没有唯一的解。矩阵分解是一种强大的技术,可以提供对变换的深入理解,因为变换可以表示为多个更简单、基本变换的组合。但这是另一个话题,我们稍后再谈。
6. 逆变换
你可以很容易地构造一个表示不做任何变换的矩阵,它不会改变标准基向量:
它通常被称为单位矩阵。
取矩阵A并考虑一个能够逆转其效果的变换。表示该变换的矩阵是A⁻¹。具体来说,当在A之后或之前应用时,它会得到单位矩阵I:
有很多资源解释如何手动计算逆矩阵。我推荐学习高斯-约旦法,因为它涉及对增广矩阵进行简单的行操作。在每一步中,你可以交换两行、重新缩放任意一行,或者将其余行的加权和加到选定的行上。
以以下矩阵为手动计算的例子:
你应该得到逆矩阵:
手动验证方程(4)是否成立。你也可以在 NumPy 中进行验证。
import numpy as np
A = np.array([
[1, -1],
[1 , 1]
])
print(f'Inverse of A:\n{np.linalg.inv(A)}')
Inverse of A:
[[ 0.5 0.5]
[-0.5 0.5]]
看一下下面的插图,了解这两种变换的区别。
变换A
变换A⁻¹
乍一看,很难看出一个变换是否能逆转另一个变换的效果。
然而,在这些图表中,你可能会注意到一个迷人且深远的变换与其逆变换之间的联系。
仔细看看第一个插图,它展示了变换A对基向量的作用。原始单位向量以半透明的方式呈现,而由矩阵A乘法得到的变换后向量则清晰、实心地描绘出来。现在,想象这些新画出的向量是你用来描述空间的基向量,你从它们的视角来看待原始空间。那么,原始的基向量会显得更小,第二,它们将朝东偏移。这正是第二个插图所展示的,说明了变换A⁻¹的效果。
这是我在下一篇文章中将讨论的一个主题预告,内容是使用矩阵表示数据的不同视角。
这一切听起来很棒,但有个问题:有些变换是无法逆转的。
7. 不可逆的变换
下一次实验的主力将是对角线上全是 1,反对角线上全是b的矩阵:
其中,b是区间(0, 1)中的一个分数。根据定义,这个矩阵是对称的,因为它恰好与其自身的转置相同:A=Aᵀ,但我只是顺便提一下,这在这里并不特别相关。
使用高斯-约旦法逆转这个矩阵,你将得到以下结果:
你可以在网上轻松找到计算 2x2 矩阵行列式的规则,它会给出
这不是巧合。一般来说,成立的是
请注意,当 b = 0 时,两个矩阵是相同的。这并不令人惊讶,因为 A 退化为单位矩阵 I。
当 b = 1 时,事情变得棘手,因为 det(A) = 0,det(A⁻¹) 变为无穷大。因此,A⁻¹ 对于一个完全由 1 组成的矩阵 A 是不存在的。在代数课程中,老师通常会警告你零行列式的问题。然而,当我们考虑矩阵的来源时,很明显,行列式为无穷大的情况也可能发生,从而导致 致命错误。无论如何,
行列式为零意味着该变换是不可逆的。
现在,为不同的 b 值进行实验的条件已经具备。我们刚刚看到,在极限处计算会失败,现在我们将通过可视化方式,仔细观察当我们接近这些极限时会发生什么。
我们从 b = ½ 开始,最终接近 1。
步骤 1)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/eeace7b7e5bd790b47317dff9520bf3d.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0c0250b06e9b3484f32e994538d49b5e.png
变换 A
变换 A⁻¹
步骤 2)
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/32a130667236785712ba893d8dc5385e.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/1dacc8d80f399a3697998a94b3b87bed.png
变换 A
变换 A⁻¹
回想一下,表示变换的矩阵的行列式对应于由变换后的基向量形成的平行四边形的面积。
这与插图一致:变换 A 的平行四边形面积越小,变换 A⁻¹ 的面积就越大。接下来是:变换 A 的基向量越窄,其逆变换的基向量就越宽。还要注意,我不得不扩展坐标轴的范围,因为变换 A 的基向量变得更长。
顺便说一下,请注意
变换 A 和 A⁻¹ 具有相同的特征方向。
步骤 3) 快完成了……
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/762d7551521b13fdada37d678056e7a3.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/51eb1cc88dc35bd03432b484d5d8ce04.png
变换 A
变换 A⁻¹
网格线被压得非常紧,几乎重叠,这最终发生在 b 达到 1 时。基向量被拉伸得太长,以至于超出了坐标轴的限制。当 b 恰好等于 1 时,两个基向量会重合在同一条线上。
看过前面的插图后,你现在可以猜测应用一个不可逆变换到向量上会有什么效果。先花点时间思考一下,然后可以尝试运行一个计算实验,或者查看我下面提供的结果。
.
.
.
这样考虑一下。
当基向量不平行时,意味着它们形成的角度不是 0 度或 180 度,你可以用它们来表示整个平面上的任何点(数学家称这些向量张成平面)。否则,整个平面就无法再被张成,只有沿着基向量所覆盖的直线上的点可以被表示。
.
.
.
这就是当你将不可逆变换应用于随机选定的点时的效果:
一个不可逆矩阵A会降低数据的维度。
应用不可逆变换的一个后果是,二维空间会塌缩成一个一维子空间。变换后,不再可能唯一恢复点的原始坐标。
看一下矩阵A的条目。当b = 1 时,两列(或行)是相同的,这意味着变换矩阵实际上表现得像一个 1×2 矩阵,将二维向量映射到一个标量。
你可以轻松验证,如果一行是另一行的倍数,问题将是相同的。这可以进一步推广到任何维度的矩阵:如果任意一行可以表示为其他行的加权和(线性组合),则意味着一个维度塌缩。原因是这样的向量位于其他向量张成的空间内,因此不能提供超出已经能表示的点的能力。你可以将这个向量视为冗余的。
从第四部分的转置部分可以推断出,如果有冗余的行,那么必定有相等数量的冗余列。
8. 行列式
你现在可能会问是否有一种非几何的方式来验证矩阵的列或行是否冗余。
回想一下第四部分中的平行四边形和被称为行列式的标量。我提到过
矩阵的行列式表示在变换下,单位平行四边形的面积如何变化。
行列式的精确定义有点棘手,但正如你已经看到的,它的图形解释应该不会引起任何问题。
我将展示由矩阵表示的两种变换的行为:
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/983afc1e1e9040443ea782b7f54a953c.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/5188224ee675e76f85ee6713653134e0.png
det(A) = 2
det(B) = -3/4
行列式的大小表示变换总体上如何拉伸(若大于 1)或缩小(若小于 1)空间。虽然变换可能在一个方向上拉伸,在另一个方向上压缩,但总体效果由行列式的值决定。
此外,负的行列式表示一个反射;注意,矩阵B会反转基向量的顺序。
一个面积为零的平行四边形对应一个压缩了一个维度的变换,这意味着行列式可以用来检测矩阵基向量中的冗余。
由于行列式衡量的是在变换下平行四边形的面积,我们可以将其应用于一系列的变换。如果 det(A)和 det(B)分别表示变换A和B的单位面积的缩放因子,那么在依次应用这两个变换后,单位面积的缩放因子,即AB,等于 det(AB)。由于这两个变换独立且顺序执行,总效果由 det(AB) = det(A) det(B)给出。将矩阵A⁻¹代入矩阵B并注意到 det(I) = 1,得到了上一节引入的方程(5)。
下面是如何使用 NumPy 计算行列式的方法:
import numpy as np
A = np.array([
[-1/2, 1/4],
[2, 1/2]
])
print(f'det(A) = {np.linalg.det(A)}')
det(A) = -0.75
9. 非方阵
到目前为止,我们专注于方阵,并且你已经培养了对它们所代表变换的几何直觉。现在是时候将这些技能扩展到具有任意行列数的矩阵了。
宽矩阵
这是一个宽矩阵的例子,它的列数多于行数:
从方程(1)y = Ax的角度来看,它将三维向量x映射到二维向量y。
在这种情况下,一列总是可以表示为另一列的倍数,或者是其他列的加权和。例如,这里第三列等于第一列的 3/4 倍加上第二列的 5/4 倍。
一旦向量x被转换为y,就无法从y中重建原始的x。我们说这种变换降低了输入数据的维度。这类变换在机器学习中非常重要。
有时,一个宽矩阵会伪装成一个方阵,但你可以通过检查其行列式是否为零来揭示它。我们以前遇到过这种情况,记得吗?
我们可以使用矩阵A来创建两个不同的方阵。试着自己推导出以下结果:
矩阵AᵀA由矩阵A中所有可能列对的点积组成,其中一些列对显然是冗余的,从而将这种冗余转移到AᵀA。
另一方面,矩阵AAᵀ只包含矩阵A行的点积,这些行的数量少于列的数量。因此,构成矩阵AAᵀ的向量很可能(虽然不能完全保证)是线性独立的,这意味着一个向量不能表示为另一个向量的倍数或其他向量的加权和。
如果你坚持从之前计算得到的y = Ax中确定x会发生什么?你可以将方程两边左乘A⁻¹,得到方程A⁻¹y = A⁻¹Ax,并且因为A⁻¹A = I,得到x = A⁻¹y。但这一切从一开始就会失败,因为矩阵A⁻¹是非方阵,肯定是不可逆的(至少在之前所介绍的意义上)。
然而,你可以扩展原始方程y = Ax,以包含一个在需要的地方使用的方阵。你只需要在方程两边左乘矩阵Aᵀ,从而得到Aᵀy = AᵀAx。右边现在是一个方阵AᵀA。不幸的是,我们已经看到它的行列式为零,因此看起来我们再次无法从y中重建x。
高矩阵
这是一个高矩阵的例子
它将二维向量x映射到三维向量y。我通过简单地将第一行的条目平方来创建了第三行。虽然这种扩展并没有给数据添加任何新的信息,但它却能出奇地改善某些机器学习模型的性能。
你可能会认为,与宽矩阵不同,高矩阵允许从y中重建原始的x,其中y = Bx,因为没有信息被丢弃——只是添加了信息。
你说得对!看看当我们像之前尝试过的那样左乘矩阵Bᵀ时会发生什么,但这次成功了:Bᵀy = BᵀBx。这次,矩阵BᵀB是可逆的,所以我们可以左乘它的逆矩阵:
(BᵀB)⁻¹Bᵀy = (BᵀB)⁻¹(BᵀB)x
最终得到:
这就是它在 Python 中的实现方式:
import numpy as np
# Tall matrix
B = [
[2, -3],
[1 , 0],
[3, -3]
]
# Convert to numpy array
B = np.array(B)
# A column vector from a lower-dimensional space
x = np.array([-3,1]).reshape(2,-1)
# Calculate its corresponding vector in a higher-dimensional space
y = B @ x
reconstructed_x = np.linalg.inv(B.T @ B) @ B.T @ y
print(reconstructed_x)
[[-3.]
[ 1.]]
总结一下:行列式衡量矩阵列和行的冗余性(或线性独立性)。然而,只有在应用于方阵时,它才有意义。非方阵表示不同维度空间之间的变换,并且必然具有线性相关的列或行。如果目标维度高于输入维度,便有可能从高维向量中重建低维向量。
10. 逆矩阵与转置矩阵:相似性与差异
你肯定已经注意到,逆运算和转置运算在矩阵代数中发挥了关键作用。在本节中,我们将汇总与这些运算相关的最有用的恒等式。
每当我应用逆运算符时,我假设被操作的矩阵是方阵。
我们将从尚未出现的显而易见的那个开始。
这里是先前给出的恒等式(2)和(5),并排放置:
让我们通过以下推理,首先从方程(4)中的恒等式开始,其中A被复合矩阵AB替代:
右边的括号是多余的。去掉它们后,我将矩阵B⁻¹右乘到等式两边,然后是A⁻¹。
https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c71c62e2e8f8911aea2ae49a4b949246.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/7711ca2ab945fb221b91d72f15936b4f.pnghttps://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/db6b16f6655d291f2de92931dc97448f.png
因此,我们观察到反演和转置之间的下一个相似性(参见方程(3)):
你现在可能会失望,因为接下来的内容只适用于转置。
但是假设A和B是标量。对于逆操作来说,这将是一个数学丑闻!
为了变化,方程(4)中的恒等式仅适用于逆操作:
我将通过讨论反演和转置之间的相互作用来结束这一部分。
从最后一个方程和方程(3)结合,我们得到以下结果:
请记住,Iᵀ = I。右乘Aᵀ的逆矩阵将得到以下恒等式:
11. 通过一个向量平移
你可能会想,为什么我只关注将向量与矩阵相乘的运算,而忽略了通过加上另一个向量来平移向量的操作。
其中一个原因纯粹是数学上的。线性运算提供了显著的优势,比如变换的便利性、表达式的简洁性和算法的高效性。
线性运算的一个关键特性是,输入的线性组合会导致输出的线性组合:
其中α,β是实数标量,Lin表示一个线性操作。
让我们首先检查方程(1)中的矩阵-向量乘法算子Lin[x] = Ax:
这证实了矩阵与向量相乘是一个线性操作。
现在,让我们考虑一个更一般的变换,它涉及通过向量b的平移:
代入一个加权和,看看会得到什么结果。
你可以看到,添加b会破坏线性。像这样的操作被称为仿射,以区别于线性操作。
不过不用担心——有一种简单的方法可以消除翻译的需要。只需事先对数据进行平移处理,例如通过居中,使得向量b变为零。这是数据科学中常用的方法。
因此,数据科学家只需要关注矩阵-向量乘法。
12. 结语
我希望现在线性代数看起来更容易理解了,也希望你已经感受到它有多么有趣。
如果我激发了你进一步学习的兴趣,那太好了!但即便只是让你对课程内容更有信心,那也是一种收获。
请记住,这更像是对该主题的半正式介绍。要了解更严谨的定义和证明,您可能需要查阅专门的文献。
除非另有注明,所有图片均由作者提供
参考文献
[1] Gilbert Strang. 线性代数导论. 威尔斯利-剑桥出版社, 2022 年。
[2] Marc Peter Deisenroth, A. Aldo Faisal, Cheng Soon Ong. 机器学习中的数学. 剑桥大学出版社, 2020 年。
如何持续发展为数据科学家
图片由 Midjourney 生成
关于如何在日常工作中持续学习的几个实用建议
https://eryk-lewinson.medium.com/?source=post_page---byline--3b33cdda853a--------------------------------https://towardsdatascience.com/?source=post_page---byline--3b33cdda853a-------------------------------- Eryk Lewinson
·发表于 Towards Data Science ·12 分钟阅读·2024 年 4 月 25 日
–
虽然我知道这可能听起来像是老生常谈,但作为数据科学家通常需要具备终身学习的心态。这个领域发展得如此迅速,以至于保持跟上最新进展需要时间和大量的努力,不论是最先进的机器学习模型、一个新的数据处理库,还是刚刚发布的 arXiv 论文,您可能希望实现它们。难怪我们许多人(包括我自己)会患上冒名顶替综合症。
尽管现在有许多学习的机会,但我们最宝贵的资源是时间。我们不能(或至少不应该)把大部分清醒时间都花在工作和学习上,因为那样我们很容易会迅速感到精疲力尽。因此,在这篇文章中,我想重点讲述在您每天的 9 到 5 工作(或者适用于您的其他时间段)中的发展机会。
我知道每个公司都是不同的,您可能已经在使用我在这里提到的一些方法。这很棒!从我的角度来看,如果您能发现至少一个新的学习方法,我会认为这是成功的。
如何成长为一名数据科学家的建议
如何自学 AI(自学指南)
https://medium.com/@vuthihienthu.ueb?source=post_page---byline--a67e23350c24--------------------------------https://towardsdatascience.com/?source=post_page---byline--a67e23350c24-------------------------------- Thu Vu
·发布于 Towards Data Science ·阅读时间 12 分钟·2024 年 1 月 5 日
–
如果你的工作需要接触键盘,人工智能将在未来几年改变你的工作。
在这篇博客文章中,我将与您分享拓展 AI 技能的路线图,并提供学习资源。
这份路线图从基础开始,即使你没有机器学习、数学或编程的背景,我希望你能从中获得一些有用的想法,帮助你找到学习的起点。
👉 注意:你也可以观看本博客文章的视频版本,并在我的 Youtube 频道下载完整的路线图 PDF:
现在,开始吧!💪
为什么你应该学习 AI?
人工智能、机器学习和深度学习自 1950 年代以来就已存在。由于算法、计算能力的进步,尤其是数据的丰富,这一领域在过去十年(尤其是近几年)飞速发展。
我们今天常谈的 AI 是生成式 AI,它是机器学习和深度学习的一个子集。
如何免费自学因果推理
适用于所有水平的终极自学指南
https://medium.com/@quentin.gallea?source=post_page---byline--98503abc0a06--------------------------------https://towardsdatascience.com/?source=post_page---byline--98503abc0a06-------------------------------- Quentin Gallea, PhD
·发表于Towards Data Science ·阅读时长 12 分钟·2024 年 2 月 20 日
–
作者提供的图片
在每个人都专注于人工智能和预测推理时,脱颖而出需要掌握的不仅仅是预测,而是理解数据背后的“为什么”——换句话说,就是掌握因果推理。
你可能听说过“相关性不代表因果性”,但很少有人真正理解其含义,也很少有人知道何时可以自信地断言因果关系。
预测推理与因果推理之间的区别是深刻的,后者经常被忽视,导致代价高昂的错误。这两种方法的逻辑和模型差异巨大,本指南旨在帮助你掌握辨别因果关系的知识,做到自信应对。
来自谷歌趋势的“因果推理”结果,揭示了最近快速增长的兴趣以及与机器学习的关联。图片由作者提供
我坚信因果推理无疑是当今最值得学习的技能之一,原因有三:
-
它对几乎任何工作都极为有用,不仅限于数据科学家,还包括商业领袖和经理(见下一节)。
-
它仍然是一个小众领域,真正的专家寥寥无几,但兴趣正在快速增长(见上图)。
-
如谷歌趋势结果所示(见上图),*“因果机器学习”*是当前最新的关联趋势。因此,掌握因果推理将帮助你将这一知识与当前的人工智能焦点相连接,并使你走在前沿。
为了帮助你掌握因果推理,并在职场及其他领域拥有一项有价值的技能,我制作了这份自学指南,适合各个层次的人,不需要任何先决条件,并且完全由免费的在线资源组成。
指南的计划:
-
介绍:因果推理的关键概念
-
技术工具
-
随机化实验(A/B 测试)
-
准实验设计
-
高级话题
-
结论
完整的视频指南
1. 介绍:因果推理的关键概念
因果关系是研究因果与结果之间关系的领域,旨在回答诸如“为什么?”和“如果呢?”等关键问题。理解因果关系的概念对抗击气候变化、追求幸福以及战略决策至关重要。
需要因果推理的主要问题示例:
-
禁止燃油车会对污染产生什么影响?
-
某些健康问题传播背后的原因是什么?
-
减少屏幕时间是否能提高幸福感?
-
我们广告活动的投资回报率是多少?
在接下来的内容中,我将主要引用两本免费的电子书,这些书中包含 Python 代码和可以进行实验的数据。第一本电子书提供快速概览,而第二本则允许更深入地探讨内容。
- 勇敢与真实的因果推理 作者:Matheus Facure
2. 因果推理:混音带 作者:Scott Cuningham
图片来源:Timo Elliott
1.1 因果推理的根本问题
让我们通过一个我们可能都熟悉的情境,深入了解理解因果推理所必需的最基本概念。
想象一下,你已经在电脑前工作了一整天,截止日期临近,你开始感到头痛。你还有几个小时的工作需要完成,于是你决定服用一颗药丸。过了一会儿,头痛消失了。
但是,接着你开始怀疑:真的是药丸起了作用吗?还是因为你喝了茶或休息了一下?令人着迷但最终也令人沮丧的一点是,回答这个问题是不可能的,因为所有这些效应是交叉混淆的。
确定是否是药丸治愈了你的头痛的唯一方法就是拥有两个平行世界。
在两个世界中,一个你服用了药丸,另一个你没有,或者理想情况下,你服用了安慰剂。只有在你感到在服用了药丸的世界中有所好转时,你才能证明药丸的因果效应,因为药丸是这两个世界之间唯一的区别。
不幸的是,我们无法访问平行世界来进行实验并评估因果关系。因此,许多因素是同时发生的并且相互混淆(例如,为头痛服药、喝茶和休息;在销售旺季增加广告支出;将更多警力分配到犯罪率较高的地区等)。
为了快速深入理解这一基本概念,而无需任何额外的技术知识,您可以阅读以下关于《Towards Data Science》的文章:
📚资源:
因果关系的科学与艺术(第一部分)
1.2 一些形式化:潜在结果
现在你理解了基本概念,是时候进一步理论化并正式化这些概念了。最常见的方法是潜在结果框架,它允许清晰地表达模型假设。这些假设对于明确问题和识别解决方案至关重要。
该模型中使用的主要符号是:
-
Yᵢ(0) 代表个体 i 在未接受处理时的潜在结果。
-
Yᵢ(1) 代表个体 i 在接受处理时的潜在结果。
请注意,使用了不同的符号。处理(1 或 0)的引用可能出现在括号中(如上所用),也可能以上标或下标形式出现。字母“Y”表示关注的结果,例如一个二元变量,当出现头痛时值为 1,否则为 0。下标“i”表示观察到的实体(例如,一个人、一只实验鼠、一座城市等)。最后,术语“处理”指的是你关心的“原因”(例如,一颗药丸、一则广告、一项政策等)。
使用这个符号,我们可以通过陈述因果推断的基本问题来指出:不可能同时观察到 Yᵢ(0) 和 Yᵢ(1)。换句话说,你永远无法在同一时刻观察到同一人接受和未接受处理后的结果。
虽然我们无法识别个体效应 Yᵢ(1)-Yᵢ(0),但我们可以衡量平均处理效应(ATE):E[Yᵢ(1)-Yᵢ(0)]。然而,如果两个组之间存在除处理外的系统性差异,这个平均处理效应将会有偏。
要深入了解这部分内容,您可以参考以下两章:
📚资源:
-
简要概述:潜在结果(因果推断:勇敢与真实的指南)
-
深入阅读:潜在结果(因果推断:混音带)
1.3 因果关系的可视化表示:有向(无环)图
可视化表示是减少认知负担、澄清假设并促进沟通的强大工具。在因果推断中,我们使用有向图。顾名思义,这些图描绘了各种元素(如头痛、药丸、茶)作为节点,通过单向箭头连接,显示因果关系的方向。(注:我故意没有提到与这些图相关的常见假设“无环性”,因为它超出了本概述的范围,但在本小节末尾的第二篇参考文献中有讨论。)
有向图示例,图像来自作者
因果推断与预测推断的主要区别在于假定的潜在因果关系。这些关系通过一种特殊的图形——有向(无环)图明确表示。这个工具与潜在结果框架一起,构成了因果推断的核心,将帮助清晰地思考潜在问题,并因此找到评估因果关系的解决方案。
📚资源:
-
简短介绍:有向无环图(勇敢且忠诚的因果推断)
-
深入了解:有向无环图(因果推断:混音带)
2. 技术工具
如果你想进一步深入并将这些方法应用于数据分析,你需要掌握两种技术工具。
-
对概率、统计和线性回归的基础理解。
-
掌握一款统计软件的使用。
2.1 概率、统计与线性回归
这些工具对于数据科学来说非常有价值,你可以专注于最重要的部分。此外,两本参考书中都有专门讨论这一主题的章节,重点讲解与因果推断相关的概念:
📚资源:
此外,在我看来,线性回归相关的一个非常有价值但常被忽视的话题是“坏控制”的概念。理解你应该控制哪些因素,以及哪些因素实际上会引发问题,这是关键。以下两篇参考文献将帮助你理解这个概念。
📚资源:
最后,理解固定效应回归对因果推断至关重要。这种回归方法允许我们考虑那些可能无法测量的(例如文化)或根本没有数据的混杂因素。
📚资源:
-
深入了解:固定效应(《因果推断:混音带》)
2.2 统计工具
有许多工具可以帮助我们进行因果推断和统计分析,在我看来,最好的工具是 STATA、Python 和 R。
STATA 专为统计学设计,尤其是计量经济学,使其成为一个极其强大的工具。它提供了来自前沿研究的最新包。然而,它价格昂贵且不够多功能。
另一方面,Python 是当今领先的编程语言。它是开源的,功能非常多样化,这些都是它成为我首选的关键原因。此外,ChatGPT 在处理 Python 相关问题时表现非常出色,这在这个人工智能时代是一个重要的优势。
R 在统计学方面非常强大。R 与 Python 之间的辩论仍在进行中,我将这个判断留给你。需要注意的是,R 的多功能性不如 Python,而且似乎 ChatGPT 在 R 上的熟练度不如 Python。此外,我参考的两本主要书籍都包含了 Python 代码(《勇敢与真实的因果推断》;《因果推断:混音带》)。这进一步支持了将重点放在 Python 上的观点。
有成千上万的免费资源可以从零开始学习 Python(如果你有更好的建议,请评论)。但如果你从零开始(完全没有编码经验),以下是我通常会推荐的资源:
📚资源:
3. 随机实验(A/B 测试)
在本指南的第一部分,我们发现了因果推断的基本问题。这个问题突显了评估因果关系的困难。那么我们能做什么呢?
通常,因果推断中最先提出并被认为是*“黄金标准”*的解决方案是随机实验(随机对照试验)。
从本质上讲,随机实验的思想是复制,或者至少尽可能接近一个平行世界的情景。这使我们能够隔离治疗(原因)的效果(后果)。
正如我在第一部分提到的《面向数据科学》文章中解释的:
“我们采取一个样本,希望它能代表一个更大的群体,并随机将受试者分配到两个组(治疗组和对照组)或更多组。受试者通常不知道自己是否接受治疗(这一过程称为盲法)。因此,这两个组可以说是可比的。由于唯一的区别是治疗,如果我们观察到一个效应,那么它可能是因果关系,前提是没有其他偏差存在。”
随机实验的简单表示。图片来源:作者。
📚资源:
-
A/B 测试的简单完整指南(Lunar Tech)
4. 准实验设计
控制实验并不总是可能的(例如,改变性别/种族以研究歧视)或符合伦理的(例如,暴露人类于致死剂量的污染物以研究呼吸道疾病)。
此外,随机化实验往往具有非常强的内部效度,但外部效度较弱。内部效度意味着在研究范围内能够精确地衡量因果关系,而外部效度则指的是将结果推广到研究范围之外的能力。
控制实验的主要限制之一是外部效度。图片来源:作者。
例如,医学研究广泛依赖于近亲繁殖的老鼠/小鼠。这些动物几乎拥有相同的基因组,过着相同的实验室生活,吃着相同的食物,等等。因此,当你用这些动物做控制实验时,几乎就像是在平行世界中工作,几乎是与克隆体打交道。然而,由于研究对象的同质性,外部效度较弱。此外,在控制实验中,通常整个环境都被控制,在某些情况下,这使得实验设定显得有些不现实,从而降低了结果的实用性。
让我通过以下研究论文来说明这一点。《英国医学杂志》(最具声望的医学期刊之一)上发表的一项研究发现,跳伞时使用降落伞对“死亡或重大创伤性伤害的复合指标”没有影响(Yeh et al. (2018))。在这项随机实验中,参与者从一架小型、静止在地面的飞机上跳下。这个荒谬的设定说明了在控制实验中,当实验设定不现实时,常常会出现的问题。论文的目的是提高医学研究人员对外部效度问题的关注,这是一个当前且严峻的挑战。
解决这个问题的一种方法是依赖其他方法,称为准实验设计。其理念是在自然环境中观察群体之间的准随机分配。“准随机”意味着一旦我们隔离或控制潜在的系统性差异,分配效果实际上就像随机分配一样。
4.1 示例
为了说明准实验设计的概念,我将解释一种方法——回归不连续设计(RDD)背后的直觉,这种方法用于衡量饮酒对死亡率的影响。
回归不连续设计(RDD)的理念是利用治疗分配中的不连续性(例如,地理边界、与年龄相关的行政法律等),在这些情况下,相似的个体或地点根据某一截止点接受不同的治疗。
例如,在 Carpenter 和 Dobkin(2009)的研究《饮酒对死亡率的影响》中,作者利用法定最低饮酒年龄的分界点,研究饮酒对死亡率的即时影响。
与移动交通事故相关的死亡率在 21 岁时突然上升,可以说是由于饮酒引起的。复现(Carpenter 和 Dobkin (2009))的主要结果。图片由作者提供。
本研究的理论是,饮酒的人与不饮酒的人通常无法直接比较,因为存在许多其他系统性差异(例如年龄、社会经济状况、各种疾病的风险等)。然而,通过比较刚刚低于 21 岁和刚刚超过 21 岁的个体,可以认为他们非常相似,假设在那个年龄没有其他显著变化。这种方法可以更清楚地将死亡率变化归因于饮酒行为。这个例子,连同数据和代码,也包含在下一个子节 4.2 方法末尾提供的第一个参考中。
4.2 方法
有许多方法可以使用。然而,我建议你按照以下顺序学习这三种方法:
-
回归不连续设计(RDD)
-
差分中的差分(Diff-in-Diff)
-
工具变量(IV)
这三种方法在学术研究中是标准方法,同时也广泛应用于行业。它们共同构成了一个工具箱,可以帮助你在各种场景下解决因果问题。
📚资源:
-
深入了解:回归不连续设计(因果推断:混音带)
-
深入了解:差分中的差分(因果推断:混音带)
-
差分法示例:ChatGPT 对 Stack Overflow 的影响
-
深入探讨:工具变量(因果推断:混音带)
6. 高级主题
当然,因果推断是非常丰富的。掌握这些工具将使你在因果推断领域中游刃有余。然而,还有其他潜在的主题值得探索。以下是一些列表:
📚 合成控制(非常流行且增长最快的准实验方法):
-
深入探讨:合成控制(因果推断:混音带)
📚 因果机器学习(结合因果推断和机器学习两者的优势):
-
机器学习与因果推断:短期课程(斯坦福大学)
-
!收费!因果分析:影响评估与因果机器学习在 R 中的应用(马丁·胡贝尔)
📚 因果发现
- !收费!Python 中的因果推断与发现
6. 结论
遵循本指南将为你提供扎实的理论基础和全面的工具箱,帮助你将因果推断融入你的技能集。这些概念不仅仅局限于衡量你工作的因果效应;它们还能提升你的批判性思维能力。新闻、政治、‘专家’、经理以及其他人中,滥用因果声明的情况屡见不鲜。应用这些概念可以减少被操控的风险。这个工具箱在日常的朋友讨论或团队会议中也能发挥作用,尤其是在做决策或反思观察时。
当然,这仅仅是开始。要真正整合并掌握这些技能,实践至关重要。我鼓励你选择一个相关的问题,寻找数据,并使用本指南中提供的工具尝试回答它。然后,将这个项目纳入你的作品集中,以展示你的新知识。
享受这段令人兴奋的旅程,解答那永无止境的“为什么”问题。
如何为数据分析学习 SQL
在一个月内掌握 SQL,并在数据分析师面试中脱颖而出。
https://natassha6789.medium.com/?source=post_page---byline--5e50fa343b72--------------------------------https://towardsdatascience.com/?source=post_page---byline--5e50fa343b72-------------------------------- Natassha Selvaraj
·发布于Towards Data Science ·6 分钟阅读·2024 年 6 月 14 日
–
由Christopher Gower拍摄,图片来源:Unsplash
所以…你想成为一名数据分析师。
也许你已经有了一份全职工作,想转行进入数据行业。
或者你可能是数据分析领域的新手,正在积极寻找分析类职位。
无论你属于哪一类,数据分析面试中有一个技能总是会被考察:SQL。
在本文中,我将为你提供一份从零开始学习 SQL 的完整路线图。
若需要视频版,请点击这里:
本文分为三个部分,你可以随意跳到任何你感兴趣的部分:
-
什么是 SQL,为什么它是数据分析师必备的技能?
-
如何学习 SQL?
-
如何准备 SQL 面试?
尽管我看到许多资源已经详细覆盖了前两点,但许多资源往往忽略了…
如何学习数据科学所需的数学
数据科学所需的三大基础数学领域的解析:统计学、线性代数和微积分。
https://medium.com/@egorhowell?source=post_page---byline--86c6643b0c59--------------------------------https://towardsdatascience.com/?source=post_page---byline--86c6643b0c59-------------------------------- Egor Howell
·发表于 Towards Data Science ·阅读时间:8 分钟·2024 年 3 月 4 日
–
图片来源:Karolina Grabowska:www.pexels.com/photo/blackboard-with-handwritten-calculations-6256066/
成为数据科学家不仅仅是使用即插即用的机器学习工具包。你首先必须理解算法到底在做什么,并知道何时以及为何使用它。学习算法背后原理的过程就是通过研究其基础数学。
要成为一名高水平的数据科学家,你必须掌握扎实的基础数学。这就是残酷的事实。然而,所需的数学知识并不需要达到博士或甚至硕士学位的水平。大部分内容都在高中后期以及许多本科课程的前几年中涉及。
因此,在本文中,我将详细介绍数据科学所实际需要的数学知识,以及你应该学习的内容,并提供有用的资源。
你实际需要的东西
如何在 2024 年提升你的数据可视化技能
https://towardsdatascience.medium.com/?source=post_page---byline--ace6c567ffb6--------------------------------https://towardsdatascience.com/?source=post_page---byline--ace6c567ffb6-------------------------------- TDS 编辑
·发表于 Towards Data Science ·订阅至 新闻通讯 ·阅读时长 3 分钟·2024 年 1 月 18 日
–
AI 流行词汇时兴时衰,新兴的机器学习趋势爆发又迅速消退,但有些东西始终保持一致——其中之一便是良好的数据可视化所具有的讲故事的力量。
通过视觉媒介呈现数据支持的见解依然是数据专业人士的核心技能,而我们也喜欢深入探讨那些让图表、图形和信息图表“奏效”的细节。我们认为,深入理解基本构建模块和跟上最新工具及新颖方法同样具有价值。本周,我们展示了一些出色的文章,涵盖了这两个极端之间的整个领域:如果你计划在 2024 年深化和拓展你的可视化技能,那么你来对地方了。让我们开始吧。
-
可视化 101:选择最佳的可视化类型当谈到创建有效的视觉效果时,坚实的设计战略基础至关重要。Mariya Mansurova的入门指南——涵盖了数据可视化的不同使用场景,以及如何根据最终目标调整方法——是你在这一领域迈出第一步时能找到的最扎实的资源之一。
-
声明式与命令式绘图从你脑海中美妙的构想到屏幕上最终产品的过程充满了许多中间步骤,其中许多(如果不是大多数的话)以代码的形式出现。Lee Vaughan关于如何在 Python 中进行绘图的解释是任何希望了解可视化工具内部运作原理并根据需要选择合适工具的人必读的文章。
图片来源:Kelly Sikkema提供,来自Unsplash
-
可视化珠穆朗玛峰探险
如果你想获得大量关于可视化灵感的启发,不容错过Karla Hernandez的逐步教程,她将带领我们完成创建一个简洁、多层次且高效信息图的整个过程。虽然教程的主题是登山,但 Karla 概述的原则无论在哪个项目中都具有价值。
-
在互动地图上可视化路线:第一部分像 Google Maps 这样的应用已经无处不在,我们几乎把它们视为理所当然;Carlos J. Uribe的实践指南强调了创建地图背后的复杂性,但也展示了如果使用正确的工具,以简化的方式进行丰富的地理空间数据可视化是完全可行的。
我们的作者们以令人兴奋的活动开启了新的一年。选择总是很难,但这里有几篇我们不希望你错过的优秀文章。
-
跟上图形和几何机器学习领域的最新进展,并了解该领域在 2024 年可能的发展方向——Michael Galkin和Michael Bronstein为你准备了一个庞大的、分为两部分的“前沿摘要”,让你深入研究。第一部分聚焦于理论与架构,而第二部分则聚焦于实际应用。
-
对于批处理的全面指南,请参阅Xiaoxu Gao的最新文章,该文从技术和商业角度全面讲解了这一主题。
-
生成式 AI 将如何塑造软件工程团队的工作?Omer Ansari的深度分析解读了风险并提供了见解,帮助领导者为(不久的)未来做好准备。
-
在她的最新初学者友好型文章中,Gurjinder Kaur介绍了 AdaBoost 算法,并提供了关于其内部原理的清晰解释,以及完整的 Python 实现。
-
将理论与实践结合,Shuai Guo提供了一份关于常微分方程的详细指南,并探讨了如何利用它们来建模动态系统。
-
如果您一直在研究检索增强生成(RAG),并希望探索优化工作流程的新方法,不妨将Iulia Brezeanu的高级查询转换教程加入您的必读书单。
感谢您对我们作者工作的支持!如果您感到受到启发并希望加入他们的行列,为什么不写下您的第一篇文章?我们期待阅读。
直到下期 Variable,
TDS 团队
如何利用 SvelteKit、Skeleton 和 Chart.js 进行快速原型开发和高效执行
一个用于高级图表和数据可视化的模板
https://medium.com/@thomas.reinecke?source=post_page---byline--8173f7356ce1--------------------------------https://towardsdatascience.com/?source=post_page---byline--8173f7356ce1-------------------------------- Thomas Reinecke
·发布于 Towards Data Science ·阅读时长 8 分钟 ·2024 年 1 月 22 日
–
Svelte 和 SvelteKit 是 快速增长的 Web 开发替代方案,适用于 React/Next 和 Vue/Nuxt 生态系统,是针对注重快速原型开发、数据可视化和高效执行的 Web 开发者和数据科学家而言的“必学”技术。
由 DALL·E 生成 — 提示词由作者提供
Svelte的最大优势在于其独特的构建网页界面的方法——它在构建时将组件编译为高效的命令式代码,而不是依赖于运行时的虚拟 DOM。这带来了更快的运行时性能和更小的打包体积。
[## React vs. Svelte vs. Vue: 哪个更适合 2023 年的商业应用?
为你的业务做好准备:比较 React、Svelte 和 Vue,找出最适合的框架…
selectedfirms.co](https://selectedfirms.co/blog/react-vs-svelte-vs-vue?source=post_page-----8173f7356ce1--------------------------------)
而Svelte是一个语言、编译器和组件框架,SvelteKit则是一个应用框架(或元框架),它解决了构建生产就绪的应用时所面临的诸多问题,包括路由、SSR、数据获取、服务工作者、预渲染、单页应用(SPA)等。
如何使用 Elastic (ELK) Stack 记录 Databricks 工作流
一个使用软件工程世界最佳实践来设置数据管道可观察性的实际示例
https://medium.com/@yury-kalbaska?source=post_page---byline--a03f940cbc88--------------------------------https://towardsdatascience.com/?source=post_page---byline--a03f940cbc88-------------------------------- Yury Kalbaska
·发布于 Towards Data Science ·阅读时间:8 分钟 ·2024 年 7 月 30 日
–
图片由 ThisisEngineering 提供,来源于 Unsplash
介绍
在本文撰写时(2024 年 7 月),Databricks 已成为云端数据工程的标准平台,这一崛起突显了支持强大数据操作(DataOps)功能的重要性。在这些功能中,可观察性能力——日志记录、监控和警报——对一个成熟且适用于生产环境的数据工程工具至关重要。
有许多工具可以记录、监控和警报 Databricks 工作流,包括内建的原生 Databricks 仪表板、Azure Monitor、DataDog 等。
然而,上述内容没有明显涵盖的一个常见场景是需要与现有的企业监控和警报系统进行集成,而不是使用上述提到的专用工具。通常,这将是 Elastic Stack(也称为 ELK)——在软件开发世界中,作为日志记录和监控的事实标准。
ELK Stack 的组成部分是什么?
ELK 代表 Elasticsearch、Logstash 和 Kibana —— 这是 Elastic 提供的三种产品,提供端到端的可观察性解决方案:
-
Elasticsearch — 用于日志存储和检索
-
Logstash — 用于日志摄取
-
Kibana — 用于可视化和警报
以下部分将展示如何将 ELK Stack 与 Databricks 集成,以实现强大的端到端可观察性解决方案的实际示例。
一个实际示例
前提条件
在继续实施之前,请确保以下内容已准备好:
-
弹性集群 — 需要一个运行中的弹性集群。对于简单的使用场景,这可以是一个单节点的设置。然而,ELK 的一个关键优势是它是完全分布式的,因此在大型组织中,你可能会处理一个在 Kubernetes 中运行的集群。或者,可以使用 Elastic Cloud 的实例,这对于本例来说是等效的。
如果你正在进行实验,参考 DigitalOcean 的优秀指南,了解如何将 Elastic 集群部署到本地(或云)虚拟机。
-
Databricks 工作区 — 确保你有权限配置集群范围的初始化脚本。如果你打算设置全局初始化脚本,则需要管理员权限。
存储
对于日志存储,我们将使用 Elasticsearch 自己的存储能力。我们首先进行设置。在 Elasticsearch 中,数据是按索引组织的。每个索引包含多个文档,这些文档是 JSON 格式的数据结构。在存储日志之前,必须创建一个索引。这个任务有时由组织的基础设施或运维团队来处理,但如果没有,也可以通过以下命令来完成:
curl -X PUT "http://localhost:9200/logs_index?pretty"
可以根据需要进一步自定义索引。有关详细的配置选项,请参考 REST API 参考文档:www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html
一旦索引设置完毕,可以通过以下命令添加文档:
curl -X POST "http://localhost:9200/logs_index/_doc?pretty"\
-H 'Content-Type: application/json'\
-d'
{
"timestamp": "2024-07-21T12:00:00",
"log_level": "INFO",
"message": "This is a log message."
}'
要检索文档,请使用:
curl -X GET "http://localhost:9200/logs_index/_search?pretty"\
-H 'Content-Type: application/json'\
-d'
{
"query": {
"match": {
"message": "This is a log message."
}
}
}'
这涵盖了 Elasticsearch 在我们场景中的基本功能。接下来,我们将设置日志摄取过程。
传输 / 摄取
在 ELK 堆栈中,Logstash 是负责将日志摄取到 Elasticsearch 的组件。
Logstash 的功能被组织为 管道,这些管道管理从数据摄取到输出的整个流程。
每个管道可以由三个主要阶段组成:
-
输入:Logstash 可以从多个来源摄取数据。在本例中,我们将使用 Filebeat,这是一种轻量级的数据传输工具,作为我们的输入源来收集并转发日志数据——稍后会详细介绍。
-
过滤器:这一阶段处理传入的数据。虽然 Logstash 支持多种过滤器用于解析和转换日志,但在这个场景中我们不会实现任何过滤器。
-
输出:最后阶段将处理过的数据发送到一个或多个目标。在这里,输出目标将是 Elasticsearch 集群。
管道配置在 YAML 文件中定义,并存储在 /etc/logstash/conf.d/ 目录下。在启动 Logstash 服务时,这些配置文件会自动加载并执行。
你可以参考Logstash 文档了解如何设置。下面提供了一个最小的管道配置示例:
input {
beats {
port => 5044
}
}
filter {}
output {
elasticsearch {
hosts => ["http://localhost:9200"]
index => "filebeat-logs-%{+YYYY.MM.dd}"
}
}
最后,确保配置正确:
bin/logstash -f /etc/logstash/conf.d/test.conf --config.test_and_exit
收集应用日志
ELK 中还有一个组件——Beats。Beats 是轻量级代理(发送器),用于将日志(和其他)数据直接传送到 Logstash 或 Elasticsearch。Beats 有很多种——每种用于不同的场景,但我们将集中讨论Filebeat——目前最流行的,它用于收集日志文件,处理它们,并直接推送到 Logstash 或 Elasticsearch。
Beats 必须安装在生成日志的机器上。在 Databricks 中,我们需要在每个我们希望采集日志的集群上设置 Filebeat——无论是 All-Purpose(用于原型设计、在笔记本中调试等)还是 Job(用于实际工作负载)。安装 Filebeat 包括三个步骤:
-
安装本身——下载并执行适用于你的操作系统的分发包(Databricks 集群运行的是 Ubuntu——因此应该使用 Debian 包)
-
配置已安装的实例
-
通过 system.d 启动服务并验证其活动状态
这可以通过 Init 脚本来实现。下面建议了一个最小的 Init 脚本示例:
#!/bin/bash
# Check if the script is run as root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit 1
fi
# Download filebeat installation package
SRC_URL="https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.14.3-amd64.deb"
DEST_DIR="/tmp"
FILENAME=$(basename "$SRC_URL")
wget -q -O "$DEST_DIR/$FILENAME" "$SRC_URL"
# Install filebeat
export DEBIAN_FRONTEND=noninteractive
dpkg -i /tmp/filebeat-8.14.3-amd64.deb
apt-get -f install -y
# Configure filebeat
cp /etc/filebeat/filebeat.yml /etc/filebeat/filebeat_backup.yml
tee /etc/filebeat/filebeat.yml > /dev/null <<EOL
filebeat.inputs:
- type: filestream
id: my-application-filestream-001
enabled: true
paths:
- /var/log/myapplication/*.txt
parsers:
- ndjson:
keys_under_root: true
overwrite_keys: true
add_error_key: true
expand_keys: true
processors:
- timestamp:
field: timestamp
layouts:
- "2006-01-02T15:04:05Z"
- "2006-01-02T15:04:05.0Z"
- "2006-01-02T15:04:05.00Z"
- "2006-01-02T15:04:05.000Z"
- "2006-01-02T15:04:05.0000Z"
- "2006-01-02T15:04:05.00000Z"
- "2006-01-02T15:04:05.000000Z"
test:
- "2024-07-19T09:45:20.754Z"
- "2024-07-19T09:40:26.701Z"
output.logstash:
hosts: ["localhost:5044"]
logging:
level: debug
to_files: true
files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
permissions: 0644
EOL
# Start filebeat service
systemctl start filebeat
# Verify status
# systemctl status filebeat
时间戳问题
注意到在上面的配置中,我们设置了一个处理器来提取时间戳。这是为了解决 Filebeat 的一个常见问题——默认情况下,它会用日志从指定目录采集时的时间戳填充 @timestamp 字段,而不是实际事件的时间戳。虽然对于很多应用程序来说,时间差通常不会超过 2–3 秒,但这会严重影响日志的顺序——更具体地说,它会扰乱日志记录的顺序。
为了解决这个问题,我们将用日志本身的值覆盖默认的 @timestamp 字段。
日志记录
一旦 Filebeat 安装并运行,它将自动收集输出到指定目录的所有日志,并将其转发到 Logstash,然后进入后续管道。
在此之前,我们需要配置 Python 日志库。
第一个必要的修改是设置 FileHandler,将日志输出为文件并存放到指定目录。默认的日志 FileHandler 将能正常工作。
然后,我们需要将日志格式化为 NDJSON,这对于 Filebeat 正确解析是必需的。由于标准 Python 库不原生支持此格式,我们需要实现一个自定义的 Formatter。
class NDJSONFormatter(logging.Formatter):
def __init__(self, extra_fields=None):
super().__init__()
self.extra_fields = extra_fields if extra_fields is not None else {}
def format(self, record):
log_record = {
"timestamp": datetime.datetime.fromtimestamp(record.created).isoformat() + 'Z',
"log.level": record.levelname.lower(),
"message": record.getMessage(),
"logger.name": record.name,
"path": record.pathname,
"lineno": record.lineno,
"function": record.funcName,
"pid": record.process,
}
log_record = {**log_record, **self.extra_fields}
if record.exc_info:
log_record["exception"] = self.formatException(record.exc_info)
return json.dumps(log_record)
我们还将使用自定义的 Formatter 来解决我们之前讨论的时间戳问题。在上面的配置中,向 LogRecord 对象添加了一个新的字段 timestamp,该字段将包含事件时间戳的副本。这个字段可以在 Filebeat 中的时间戳处理器中使用,用来替换发布日志中的实际 @timestamp 字段。
我们还可以使用格式化器添加额外的字段——如果您的组织使用一个索引来收集多个应用程序的日志,这可能有助于区分日志。
根据需要可以进行额外修改。一旦设置好 Logger,我们可以使用标准的 Python 日志 API —— .info() 和 .debug(),将日志写入日志文件,它们会自动传播到 Filebeat,再到 Logstash,接着到 Elasticsearch,最后我们就能在 Kibana(或任何其他我们选择的客户端)中访问这些日志。
可视化
在 ELK 堆栈中,Kibana 是一个负责可视化日志(或任何其他数据)的组件。为了本示例的目的,我们将其仅作为一个强化版的 Elasticsearch 搜索客户端使用。然而,它也可以(并且旨在)被设置为一个功能完善的监控和告警解决方案,鉴于其丰富的数据展示工具集。
为了最终在 Kibana 中查看我们的日志数据,我们需要设置索引模式:
-
导航到 Kibana。
-
打开“汉堡菜单”(≡)。
-
转到管理 -> 堆栈管理 -> Kibana -> 索引模式。
-
点击创建索引模式。
Kibana 索引模式创建界面
Kibana 会智能地建议索引模式的可用数据源名称。输入一个能够捕捉源名称的名称。在本示例中,可以是例如*filebeat**,然后点击创建索引模式。
选择后,进入 Discover 菜单,选择左侧下拉菜单中的新建索引模式,调整时间间隔(一个常见的陷阱——默认设置为 15 分钟),然后开始输入你自己的第一个 KQL 查询以检索日志。
在 Kibana 中可视化的日志流
我们现在已经成功完成了从在 Databricks 上托管的 Python 应用程序中生成日志条目,到使用客户端接口可视化和监控这些数据的多步骤过程。
结论
本文已经介绍了使用 ELK 堆栈与 Databricks 配合设置强大日志记录和监控解决方案的入门知识,然而,还有其他需要考虑的事项和高级主题,建议进一步探索:
-
选择 Logstash 还是直接摄取:评估是否使用 Logstash 来处理额外的数据处理功能,还是直接将日志从 Filebeat 转发到 Elasticsearch。
-
架构考虑:决定是否采用 Elastic Common Schema (ECS),或者为日志数据实现自定义字段结构。
-
探索替代解决方案:调查其他工具,如 Azure EventHubs 和其他可能更适合特定用例的日志收集工具。
-
扩展范围:将这些实践扩展到其他数据工程工具和平台,确保整个数据管道的全面可观察性。
这些主题将在后续文章中进一步探讨。
除非另有注明,所有图片均由作者提供。
如何在 Google BigQuery 中进行低通滤波
在处理时间序列数据时,应用滤波器去除噪声可能非常重要。本篇文章展示了如何在 SQL / BigQuery 中实现低通滤波,这对于改进机器学习特征非常有用。
https://medium.com/@benjamin.thuerer?source=post_page---byline--3eefa082b497--------------------------------https://towardsdatascience.com/?source=post_page---byline--3eefa082b497-------------------------------- Benjamin Thürer
·发表于 Towards Data Science ·阅读时间:9 分钟·2024 年 1 月 21 日
–
时间序列数据的过滤是数据科学中最有用的预处理工具之一。实际上,数据几乎总是信号和噪声的结合,其中噪声不仅由缺乏周期性定义,还因为它没有代表感兴趣的信息。例如,假设你在关注零售店的日常访问。如果你关注的是季节性变化对访问的影响,你可能对由于工作日变化导致的短期模式不感兴趣(比如周六的访问量可能普遍高于周一,但那并不是你关心的重点)。
时间序列过滤是清理数据的一种工具
即使这看起来只是数据中的一个小问题,噪声或无关信息(比如短期的访问模式)也会显著增加特征复杂度,从而影响你的模型。如果不去除这些噪声,你的模型复杂度和训练数据量应该相应调整,以避免过拟合。
如何构建一个 RAG 系统,以便轻松访问您的数据
本文将展示如何构建一个 RAG 系统,使您的数据通过提示轻松访问。
https://oieivind.medium.com/?source=post_page---byline--caf4bb9186ea--------------------------------https://towardsdatascience.com/?source=post_page---byline--caf4bb9186ea-------------------------------- Eivind Kjosbakken
·发布于 Towards Data Science ·阅读时间 13 分钟·2024 年 3 月 19 日
–
RAG 系统是一种创新的信息检索方法。它结合了传统的信息检索方法,如向量相似度搜索,以及最先进的大型语言模型技术。这些技术的结合,构成了一个强大的系统,能够通过简单的提示访问大量信息。
ChatGPT 生成的 RAG 系统图像。图像来自 ChatGPT。“你能画一个 RAG 系统的插图,展示计算机如何访问知识库?”这个提示。ChatGPT,4,OpenAI,2024 年 3 月 17 日。chat.openai.com.
动机
我写这篇文章的动机来源于我在试图查找一封旧邮件时的沮丧。我通常会有一些关于邮件的信息,比如发件人是谁,或者大致知道邮件的主题是什么。然而,当我在 Gmail 中进行直接的关键词搜索时,我必须更加具体,这使得找到我想要的那封邮件变得具有挑战性。我希望能有一个 RAG 系统,允许我通过提示邮件进行搜索。举个例子,如果我需要一封来自我大学的旧邮件,内容是关于某个科目的,我可以像这样发出提示:“我在 NTNU 第二年时修读了什么技术课程?”。与这个提示等效的直接关键词搜索具有挑战性,因为我在提示中需要更多具体的信息。相反,如果有一个 RAG 系统,它可以根据邮件中已有的内容找到这封邮件……
如何在 Python 中制作高级蛛网图
逐步讲解,最后提供一个易于使用的函数
https://medium.com/@zvonimir.boban.mef?source=post_page---byline--adbdb6c24a66--------------------------------https://towardsdatascience.com/?source=post_page---byline--adbdb6c24a66-------------------------------- Zvonimir Boban
·发表于Towards Data Science ·8 分钟阅读·2024 年 9 月 5 日
–
图片由Divyadarshi Acharya拍摄,来源于Unsplash
💡动机
有多种 Python 库可以用来制作经典的蛛网图/雷达图。这些库的共同点在于它们只提供带有单一比例刻度轴的蛛网图,通常显示的刻度范围是从 0 到 100。
当然,为了能够比较特征值,将其重新调整为一个公共刻度是必要的,但这样做却忽略了每个特征的绝对值范围。由于这些信息无法从图表中获得,我们不得不回到数据中去查找。在最好的情况下,这个过程既耗时又繁琐;而在最坏的情况下,我们可能无法访问原始数据,这意味着我们无法获得充分理解比较所需的关键信息。
一个合乎逻辑的进阶做法是制作一个带有显示每个特征绝对值的轴的蛛网图——这种图表被称为多轴蛛网图。你可能会认为很多库也会提供这种图表,但我搜索了许多资料后依然没有找到相关结果。受此启发,我决定自己制作一个解决方案,并通过这篇逐步指南分享给大家,最后会提供一个易于使用的函数供你使用。
🕸️ 图表
为了演示如何制作多轴蜘蛛图,我将使用著名的mtcars数据集的一小部分。该数据集来源于 1974 年《Motor Trend》杂志,并在 Henderson 和 Velleman 的 1981 年研究中首次发布[1]。让我们加载数据和所需的库。
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from plotnine import *
mtcars_values = {
'mpg': [19.7, 15, 21.4],
'cyl': [6, 8, 4],
'disp': [145, 301, 121],
'hp': [175, 335, 109],
'drat': [3.62, 3.54, 4.11],
'wt': [2.77, 3.57, 2.78],
'qsec': [15.5, 14.6, 18.6],
'vs': [0, 0, 1],py
'am': [1, 1, 1],
'gear': [5, 5, 4],
'carb': [6, 8, 2],
'wtdip': [401.65, 1074.57, 336.38]
}
mtcars = pd.DataFrame(mtcars_values,
index=["Ferrari Dino", "Maserati Bora", "Volvo 142E"])
# Select and rename columns
p_data = mtcars.reset_index().rename(columns={'index': 'group'})[['group', 'mpg', 'cyl', 'hp', 'wt', 'qsec']]
p_data.columns = ['group', 'Miles per Gallon', 'Cylinders',
'Horsepower', 'Weight', 'Quarter mile\ntime']
如你所见,我将使用plotnine库来创建图表。受ggplot2启发,plotnine库也基于图形语法的概念,通过将多个图层叠加在一起来创建图表。这个强大的概念使我们能够创建几乎任何我们能想到的可视化图形。
使用图形语法方法构建图表。图片由作者提供
分层方法要求分别构建图表的不同方面。首先我们将创建图表轮廓。由于蜘蛛图处理的是极坐标,我编写了一个函数,根据数据集中变量的数量来计算多边形顶点的坐标。
# Calculate the coordinates of polygon tips
def circle_coords(r, n_axis=len(p_data.columns) - 1):
fi = np.linspace(0, 2*np.pi, n_axis+1) + np.pi/2
x = r * np.cos(fi)
y = r * np.sin(fi)
return pd.DataFrame({'x': x, 'y': y, 'r': r})
central_distance = 0.2
axis_name_offset = 0.2
circle_df = pd.concat([circle_coords(r) for r in np.arange(0, 1.25, 0.25) + central_distance])
step_1 = (ggplot(circle_df, aes('x', 'y')) +
geom_polygon(data=circle_coords(1 + central_distance, p_data.shape[1] - 1), alpha=1, fill='beige') +
geom_path(aes(group='r'), linetype='dashed', alpha=0.5) +
theme_void() +
theme(legend_title=element_blank(),
legend_direction='horizontal',
legend_position='bottom',
legend_box_spacing=0))
第一步:为图表创建背景。图片由作者提供
接下来,我们需要计算轴的坐标并将它们添加到图表中。
# Calculate the coordinates for the axis lines
def axis_coords(n_axis):
fi = np.linspace(0, 2*np.pi*(1-1/n_axis), n_axis) + np.pi/2
x1 = central_distance * np.cos(fi)
y1 = central_distance * np.sin(fi)
x2 = (1 + central_distance) * np.cos(fi)
y2 = (1 + central_distance) * np.sin(fi)
return pd.DataFrame({'x': np.concatenate([x1, x2]),
'y': np.concatenate([y1, y2]),
'id': np.tile(np.arange(1, n_axis + 1), 2)})
step_2 = (step_1 + geom_line(data=axis_coords(p_data.shape[1] - 1), mapping=aes(x='x', y='y', group='id'), alpha=0.3))
为数据集中的每个变量添加轴。图片由作者提供
现在我们可以叠加重新缩放后的数据点了。
# Calculate the rescaled coordinates for each point
n_axis = len(p_data.columns) - 1 # Subtract 1 to exclude the group column
scaler = MinMaxScaler()
rescaled_data = p_data.copy()
rescaled_data.iloc[:, 1:] = scaler.fit_transform(rescaled_data.iloc[:, 1:])
rescaled_data['copy'] = rescaled_data.iloc[:, 1]
melted_data = rescaled_data.melt(id_vars=['group'], var_name='parameter', value_name='value', ignore_index=False)
melted_data['parameter'] = pd.Categorical(melted_data['parameter'], categories=np.array(rescaled_data.columns[1:]), ordered=True)
melted_data = melted_data.sort_values(by = ['group', 'parameter'])
melted_data['fi'] = np.tile(np.linspace(0, 2 * np.pi, num=n_axis+1) + np.pi / 2, p_data.shape[0])
melted_data['x'] = (melted_data['value'] + central_distance)*np.cos(melted_data['fi'])
melted_data['y'] = (melted_data['value'] + central_distance)*np.sin(melted_data['fi'])
rescaled_coords_data = melted_data
step_3 = (step_2 +
geom_point(data=rescaled_coords_data, mapping=aes(x='x', y='y', group='group', color='group'), size=3) +
geom_path(data=rescaled_coords_data, mapping=aes(x='x', y='y', group='group', color='group'), size=1) +
geom_polygon(data=rescaled_coords_data, mapping=aes('x', 'y', group = 'group', color = 'group', fill = 'group'), size = 1, alpha = 0.05, show_legend = False))
将数据点叠加到图表上。图片由作者提供
剩下要做的就是添加轴的文本标签和名称。
# Radius and corresponding feature value for each feature
text_data = pd.DataFrame({col: np.linspace(p_data[col].min(), p_data[col].max(), 5)
for col in p_data.columns if col != 'group'})
text_data['r'] = np.arange(0, 1.25, 0.25)
text_data = text_data.melt(id_vars=['r'], var_name='parameter', value_name='value')
text_data['parameter'] = pd.Categorical(text_data['parameter'], categories=np.array(p_data.columns[1:]), ordered=True)
text_data = text_data.sort_values(by = ['r', 'parameter'])
def text_coords(r, n_axis=len(p_data.columns) - 1):
fi = np.linspace(0, 2*np.pi*(1-1/n_axis), n_axis) + np.pi/2 + 0.01*2*np.pi/r
x = r * np.cos(fi)
y = r * np.sin(fi)
return pd.DataFrame({'x': x, 'y': y, 'r': r - central_distance})
# Coordinates for the axis labels
labels_data = pd.concat([text_coords(r) for r in np.arange(0, 1.25, 0.25) + central_distance])
# Combine with text_data
labels_data = pd.concat([labels_data.reset_index(drop=True),
text_data.drop('r', axis=1).reset_index(drop=True)],
axis=1)
labels_data['value']=labels_data['value'].round(2)
step_4 = (step_3 +
geom_text(data=labels_data, mapping=aes(x='x', y='y', label='value'), alpha=0.65, size=8,
color='#303030') +
geom_text(data=text_coords(1 + central_distance + axis_name_offset, p_data.shape[1] - 1),
mapping=aes(x='x', y='y'),
label=[param for param in p_data.columns[1:]],
size=9) +
labs(color='', title = 'Comparison of car properties'))
添加轴名称和标签。图片由作者提供
以及一些最后的美学修饰……
#Final aesthetic touches
step_5 = (step_4 +
labs(color='', title='Comparison of car properties') +
theme(legend_position='bottom',
legend_text=element_text(size=7, face='bold'),
legend_box_margin=0,
legend_margin=-20,
plot_title=element_text(size=10, margin={'b': -30}, face='bold')) +
lims(x=(-1.75, 1.75), y=(-1.5, 1.8)))
最终的图表。图片由作者提供
让我们再花一点时间评论一下显示的数字。即使是一个普通的蜘蛛图,也能明显看出沃尔沃是最慢的车。然而,在这里我们还可以看到确切的绝对差异——沃尔沃用了 18.6 秒才走完四分之一英里的距离,而三者中最快的玛莎拉蒂则少用了整整四秒。当然,预期的结果是,沃尔沃在燃油消耗方面最为经济,每加仑油能行驶比玛莎拉蒂 Bora 多 6 英里。作为跑车,玛莎拉蒂 Bora 和法拉利 Dino 也拥有更多的气缸和马力,且比沃尔沃重。
其他示例
这是另一个使用泰坦尼克号数据集并且自定义了字体的蜘蛛图示例。
另一个使用泰坦尼克号数据集的示例。图片由作者提供
这张图清晰地显示了头等舱乘客是三者中最年长且最富有的。三等舱乘客中男女乘客最多,且是最年轻的一组——可能大多数是寻求更好生活的年轻人和家庭。然而,头等舱乘客的生还率最高,三等舱则最低。这可能部分是因为头等舱靠近船甲板,部分是由于该舱位女性的比例较高(因为妇女和儿童优先获救)。
➕功能
如承诺所示,这里是封装上述所有代码的函数。第一个参数是格式化后的数据框,其中第一列包含组的 ID,其他列是要绘制的组特征。两个额外的参数确定内圈空白多边形的半径和图表中轴标题的偏移量。
# Wrapping the above code into an easy-to-use function
def multiaxis_radar(p_data, central_distance=0.2, axis_name_offset=0.2):
def circle_coords(r, n_axis=len(p_data.columns) - 1):
fi = np.linspace(0, 2*np.pi, n_axis+1) + np.pi/2
x = r * np.cos(fi)
y = r * np.sin(fi)
return pd.DataFrame({'x': x, 'y': y, 'r': r})
circle_df = pd.concat([circle_coords(r) for r in np.arange(0, 1.25, 0.25) + central_distance])
def axis_coords(n_axis):
fi = np.linspace(0, 2*np.pi*(1-1/n_axis), n_axis) + np.pi/2
x1 = central_distance * np.cos(fi)
y1 = central_distance * np.sin(fi)
x2 = (1 + central_distance) * np.cos(fi)
y2 = (1 + central_distance) * np.sin(fi)
return pd.DataFrame({'x': np.concatenate([x1, x2]),
'y': np.concatenate([y1, y2]),
'id': np.tile(np.arange(1, n_axis + 1), 2)})
n_axis = len(p_data.columns) - 1
scaler = MinMaxScaler()
rescaled_data = p_data.copy()
rescaled_data.iloc[:, 1:] = scaler.fit_transform(rescaled_data.iloc[:, 1:])
rescaled_data['copy'] = rescaled_data.iloc[:, 1]
melted_data = rescaled_data.melt(id_vars=['group'], var_name='parameter', value_name='value', ignore_index=False)
melted_data['parameter'] = pd.Categorical(melted_data['parameter'], categories=np.array(rescaled_data.columns[1:]), ordered=True)
melted_data = melted_data.sort_values(by=['group', 'parameter'])
melted_data['fi'] = np.tile(np.linspace(0, 2 * np.pi, num=n_axis+1) + np.pi / 2, p_data.shape[0])
melted_data['x'] = (melted_data['value'] + central_distance)*np.cos(melted_data['fi'])
melted_data['y'] = (melted_data['value'] + central_distance)*np.sin(melted_data['fi'])
rescaled_coords_data = melted_data
text_data = pd.DataFrame({col: np.linspace(p_data[col].min(), p_data[col].max(), 5)
for col in p_data.columns if col != 'group'})
text_data['r'] = np.arange(0, 1.25, 0.25)
text_data = text_data.melt(id_vars=['r'], var_name='parameter', value_name='value')
text_data['parameter'] = pd.Categorical(text_data['parameter'], categories=np.array(p_data.columns[1:]), ordered=True)
text_data = text_data.sort_values(by=['r', 'parameter'])
def text_coords(r, n_axis=len(p_data.columns) - 1):
fi = np.linspace(0, 2*np.pi*(1-1/n_axis), n_axis) + np.pi/2 + 0.01*2*np.pi/r
x = r * np.cos(fi)
y = r * np.sin(fi)
return pd.DataFrame({'x': x, 'y': y, 'r': r - central_distance})
labels_data = pd.concat([text_coords(r) for r in np.arange(0, 1.25, 0.25) + central_distance])
labels_data = pd.concat([labels_data.reset_index(drop=True),
text_data.drop('r', axis=1).reset_index(drop=True)],
axis=1)
labels_data['value'] = labels_data['value'].round(2)
plot = (ggplot(circle_df, aes('x', 'y')) +
geom_polygon(data=circle_coords(1 + central_distance, p_data.shape[1] - 1), alpha=1, fill='beige') +
geom_path(aes(group='r'), linetype='dashed', alpha=0.5) +
theme_void() +
theme(legend_title=element_blank(),
legend_direction='horizontal',
legend_position='bottom',
legend_box_spacing=0) +
geom_line(data=axis_coords(p_data.shape[1] - 1), mapping=aes(x='x', y='y', group='id'), alpha=0.3) +
geom_point(data=rescaled_coords_data, mapping=aes(x='x', y='y', group='group', color='group'), size=3) +
geom_path(data=rescaled_coords_data, mapping=aes(x='x', y='y', group='group', color='group'), size=1) +
geom_polygon(data=rescaled_coords_data, mapping=aes('x', 'y', group='group', color='group', fill='group'), size=1, alpha=0.05, show_legend=False) +
geom_text(data=labels_data, mapping=aes(x='x', y='y', label='value'), alpha=0.65, size=8,
color='#303030') +
geom_text(data=text_coords(1 + central_distance + axis_name_offset, p_data.shape[1] - 1),
mapping=aes(x='x', y='y'),
label=[param for param in p_data.columns[1:]],
size=9) +
labs(color='', title='Comparison of car properties') +
theme(legend_position='bottom',
legend_text=element_text(size=7, face='bold'),
legend_box_margin=0,
legend_margin=-20,
plot_title=element_text(size=10, margin={'b': -30}, face='bold')) +
lims(x=(-1.75, 1.75), y=(-1.5, 1.8)))
return plot
# Use the function to recreate the above plot
multiaxis_radar(p_data, central_distance=0.2, axis_name_offset=0.25)
🏁 结论
本文展示了如何在 Python 中从零开始构建一个高级的多轴蜘蛛图。尽管我所知道的任何 Python 包目前都不支持这种图表,但利用 plotnine 包中的图形语法方法,给了我自己创建这种图表的工具。当然,仍然有进步的空间,因为最终的函数可以通过添加更多参数和选项来进一步定制,控制图表的各个方面,例如线条和背景颜色、字体大小等,但我暂时把这些留给读者😉。
就这些了,希望你觉得这篇文章有用,并且能够运用它制作更多精美的蜘蛛图。享受吧!
参考文献
[1] Henderson, H. V., & Velleman, P. F. (1981). 交互式构建多重回归模型。《生物统计学》,37,391–411。
更多推荐



所有评论(0)