admin管理员组

文章数量:1645531

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

缩小机器学习和人类学习之间的差距

原文:https://towardsdatascience/closing-the-gap-between-machine-learning-and-human-learning-536720af00cd

大型语言建模的进展

由 Lukas 在 Unsplash 拍摄的照片

人类拥有强大的推理能力。他们能理解他人提出的问题,并给出最恰当的答案。人脑可以通过快速的数学运算来回答一个微不足道的问题,比如“如果我有 10 个球,买了两个罐头,每个罐头有 5 个球,我会有多少个球?”人类可以进行常识性的推理,比如“如果一个司机在交叉路口看到一个行人,他会怎么做?”人类有智能理解某人是否在开玩笑,并可能更深刻地理解说话者真正想说什么?

问题是,我们能训练机器获得我们人类拥有的这种智能吗?近年来,科学家们在这一领域进行了大量的研究。随着深度神经网络(DNN)和大型语言模型(LLM)的发明,我们在实现这一目标方面取得了良好的进展。在本文中,我将向您介绍通过使用 LLM 和 Google 最新的 PaLM[ ] (Pathways 语言模型)所取得的成就。

首先,让我们考虑一下我们正在努力完成的任务。

NLU 任务

在大型神经网络在自然语言处理(NLP)中取得巨大成功之后,研究人员将注意力集中在语言理解(NLU)和生成上,而不是简单的文本处理任务。那么,我们试图用这些巨大的网络来解决什么问题呢?我在下面给出了我们寻求解决的 NLU 任务的简短列表。尽管下面的列表并不详尽,但它会让您对我们的目标有所了解。

  • 语言翻译
  • 聊天机器人(问答)
  • 文本摘要
  • 语言生成
  • 论证

语言翻译

从英语翻译到德语或反之亦然,更确切地说,从任何语言翻译到任何语言,一直是我们的需要。今天,有几个 ML 模型甚至移动应用程序使用这样的预训练模型来以非常高的准确度完成这项任务。

聊天机器人(问答)

用自动化系统取代庞大的客户服务代表队伍一直是企业的梦想。这一点现在可以通过近乎完美的聊天机器人来实现。聊天机器人需要自然语言理解和问答能力。尽管特定领域的问答系统已经非常完善,但是开发一个面向开放领域的问答系统仍然是一个挑战。人类很快理解问题的上下文(领域)来回答问题。这就需要我们所知的 LLM 的少量学习[ ]。GPT-3[ ]是第一个应用少镜头学习的。最近的法学硕士如 GLaM[⁴],LaMDA[⁵],Gopher[⁶]和威震天-图灵·nlg[⁷]都采用了少击学习。

文本摘要

很多时候,我们需要创建一个长文档的摘要。虽然这是一项 NLP 任务,但语言理解在创建有意义的摘要时也起着有效的作用。具有注意力的编码器-解码器架构和基于转换器的架构在创建抽象和提取摘要方面都表现出了突出的成功。

语言生成

像莎士比亚那样写作是许多人的梦想。从 RNN(循环神经网络)、LSTM(长短期记忆)和最新的 Transformer 开始的神经网络架构允许创作可以模仿阿加莎·克里斯蒂和许多著名作家作品的小说。有许多工具可用,如 Arria NLG PLC[⁸],AX Semantics[⁹],Yseop[ ⁰],Wordsmith[ ],SimpleNLG[ ],NaturalOWL[ ]和其他自然语言生成(NLG)[ ⁴].

论证

人类有很强的常识推理能力、概念理解能力、玩琐事、同义词游戏的能力,以及根据反事实做出反应的能力。

这些仅仅是 NLP/NLU 研究进展强劲的几个领域。上述目标可以通过创建大型语言模型来实现。

创建 LLM

创建 LLM 的主要挑战是训练一个具有数百万和数十亿参数的超大型深度神经网络。像 GLaM 和 LaMDA 这样的模型是在一个单独的 TPU v3 吊舱上训练的。威震天-图灵 NLG 使用流水线并行在 GPU 集群中扩展到 2240 - A100 个 GPU。使用多个 TPU v3 pod 的 Gopher 实现了 4096 个 TPU v3 芯片的规模。他们观察到,具有更多训练参数的更大模型改善了 NLG 结果。PaLM 是这一类别中最新的一个,它使用谷歌的路径系统将训练扩展到 6144 个芯片,并创建了 5400 亿参数语言模型。它实现了 57.8%的硬件 FLOPs 利用率的训练效率,这是迄今为止 LLM 实现的最高效率。Google 重新设计了 Transformer 模块,允许并行计算注意力前馈层。这有助于为训练网络创建更好的并行策略。

https://medium/@profsarang/membership

手掌训练

他们在英语和多语言数据集的组合上训练 PaLM。其中包括维基百科文章、书籍、网络文档、对话甚至 GitHub 代码。注 PaLM 也能写计算机代码,那大概是因为它在 GitHub 上的训练。在代码生成中,空格很重要。因此,培训师创造了一个保留空白的“无损”词汇。他们还负责处理词汇表之外的 Unicode 字符,并将大数字拆分成单个数字。所有这些都有助于有效的代码生成。

现在,我将讨论 PaLM 的一些成就。

棕榈成就

研究人员在 29 个广泛使用的 NLP 任务上评估了 PaLM。在这 29 个任务中的 28 个上,它超过了先前语言模型的少数表现。它还在多语言 NLP 基准测试中显示了强大的性能,包括翻译。BIG ⁵是最新的基准,包含了 150 多个新的语言建模任务。与地鼠、龙猫和人类相比,PaLM 在 58/150 任务的子集上表现更好。它有效地区分了原因和结果。对于特定的上下文,它会为您的问题提供合适的答案。它可以玩同义词游戏。它可以从一篇文章中推导出相反的事实。

在我之前提出的问题中——“如果我有 10 个球,买了两个罐头,每个罐头有 5 个球,我会有多少个球?”—单纯的答案可能不容易以其准确性说服读者。你需要给出多步算术,推理出结论性的答案是如何推导出来的。使用思维链提示,PaLM 将通过为所有中间步骤生成文本来推理出答案。Google 博客[1]提供了一些例子来展示这些能力。

PaLM 可以生成一个明确的解释,甚至是一个笑话。生成这样的解释需要多步逻辑推理、世界知识和深刻的语言理解。博客[ ]中提供了一个很好的例子来说明这一点。

除了自然语言文本生成,代码生成是我们期望 LLMs 执行的另一个重要任务。代码生成可能意味着文本到代码,从一种编程语言翻译到另一种,甚至修复编译错误(代码到代码)。PaLM 训练数据集包括编码示例,尽管只有 5%。它已经显示出与诸如 Codex 12B[ ⁶].我将再次向您推荐 Google 博客[ ]中的优秀示例。

结论

在查看了 LLM 的最新发展,尤其是 PaLM 之后,人们可以观察到机器在学习自然语言和我们人类之间的差距正在迅速缩小。最近,Meta AI 也向研究社区提供了它的 OPT-175[ ⁷]十亿参数模型。我们可以希望看到机器学习和人类能力之间的差距很快缩小。

参考资料:

  1. 通路语言模型(PaLM)
  2. 少投学习
  3. GPT-3
  4. 多面手语言模型(GLaM)
  5. LaMDA
  6. 地鼠
  7. 威震天-图灵 NLG
  8. 阿里亚 NLG 公司
  9. AX 语义
  10. Yseop
  11. 语言大师
  12. 简单明了
  13. 自然猫头鹰
  14. 自然语言生成(NLG)
  15. 大板凳
  16. 抄本 12B
  17. OPT-175

闭包在起作用:闭包函数作为类型的巨大威力

原文:https://towardsdatascience/closures-in-action-the-dramatic-power-of-closure-functions-as-types-bf52be2b632e

在 Julia 中,将函数视为正常类型的各种用法产生了一些相当有趣的结果。

(图片由 Pixabay 上的 roketpik 提供)

介绍

Julia 编程语言及其功能的一个非常强大的地方是对闭包的强大支持。也就是说,在将函数视为数据方面,Julia 是一种出色的语言。使用 dispatch 函数是完全可能的,因此会产生一些非常棒的语法。当涉及到使类型和函数协同工作以实现给定目标时,这种语法也有许多应用。如果您不熟悉闭包函数,这可能是本文信息的一个先决条件。幸运的是,我正好有一篇文章更详细地介绍了这些是什么,你可以在这里阅读:

另一篇文章提供了更多相关信息,介绍了这类事情在 Julia 中通常是如何通过匿名函数定义来实现的,在接下来的文章中也会有更详细的讨论:

如果代码是你正在寻找的,我在这个项目中使用的代码可以在 Github 的这个资源库中以笔记本格式获得。

快速复习

在 Julia 中,闭包函数定义处理得非常漂亮。通常情况下,函数和类型之间的差异是无法衡量的,除非我们想通过提供()将该函数用作函数。它总是含蓄的,这是一件伟大的事情。同样,函数也很容易定义,任何东西都可以等同于函数,例如我们可以这样定义:

n = function hello(x, y)
   println("hi") 
end

然后我们可以像调用 hello()的定义一样调用 n。

n(5, 1)

我们当然也可以内联定义函数,使得函数和传统构造的数据结构之间的区别更加抽象——这是一件很棒的事情。特别重要的是,这种实现也不会妨碍其他事情,而这类事情经常会发生。这是闭包赋予的基本能力,仅仅利用这种思想,就可以实现一些非常激进和强大的解决方案。

原始闭包实现

使用函数作为参数的第一个实现实际上将是一个非常酷的用例。在这个例子中,我们需要为我们的服务器制作一个路由器,因为默认的 HTTP。HTTP 包中的路由器类型只能在非异步的服务器上工作,至少据我所知是这样。无论哪种方式,这都可以被认为是一种更加手动的方式,实际上,人们可以围绕这个实现制作他们自己的 mimes 所以这非常酷。为了清楚起见,mime 是 Julia 中的 display()函数到常规 HTT 协议之间的转换层。这只是一种奇特的方式来表达我们如何把这个 Julia 翻译成 HTML。所有这些都可以通过闭包有效地完成。想想这可能会有多强大是有点意思的。让我们看看这在 Julia 代码中是什么样子的。

using HTTP

我从定义一些构造函数开始编写代码,使一些类型实际上保存我们可能希望在服务器上保存的大量信息。这些信息包括不同的部分,比如路径、页面的组成部分,以及我们希望通过 HTTP 在前端显示的所有信息。我们将从路由构造器开始:

mutable struct Route
    path::String
    page::Any
    function Route(path::String = "", page::Any = "")
        new(path, page)
    end
end

这是我们自己的独特类型,最著名的构造函数是 Route(::String,:Any)。也就是说,每当我们要创建一条路线时,我们都要注意这一点。接下来,我将为我们的服务器创建一个外部构造函数。我将使用闭包方法定义,并将它们保存在一个常规闭包实现之上的结构中,使用一个函数来控制传入的路由。

mutable struct OurServer
    ip::String
    port::Integer
    routes::AbstractVector
    remove::Function
    add::Function
    start::Function

考虑到这一点,我们需要首先查看为我们创建这些方法的支持函数,

function funcdefs(routes::AbstractVector, ip::String, port::Integer)
    add(r::Route) = push!(routes, r)
    remove(i::Int64) = deleteat!(routes, i)
    start() = _start(routes, ip, port)
    return(add, remove, start)
end

这些新功能只是添加和删除路由以及启动服务器。记住,start 只是开始为 HTTP 服务器提供服务。

function _start(routes::AbstractVector, ip::String, port::Integer)
    server = Sockets.listen(Sockets.InetAddr(parse(IPAddr, ip), port))
    println("Starting server on port ", string(port))
    routefunc = generate_router(routes, server)
    [@async](http://twitter/async) HTTP.listen(routefunc, ip, port; server = server)
    println("Successfully started server on port ", port, "\n")
    println("You may visit it now at http://" * string(ip) * ":" * string(port))
    return(server)
end

虽然这个基本实现中没有日志记录,但这可能是处理整个事情的更好方法,因为现在我将只使用 println()。我们的 start 函数只是启动一个服务器,然后使用一个自动生成的 router 函数异步地为它服务。

function generate_router(routes::AbstractVector, server)
    route_paths = Dict([route.path => route.page for route in routes])
    routeserver = function serve(http)
     HTTP.setheader(http, "Content-Type" => "text/html")
        fullpath = http.message.target
    if contains(http.message.target, '?')
         fullpath = split(http.message.target, '?')
         args = ""
    end
     if length(fullpath) > 1
         args = fullpath[2]
     end
     if fullpath in keys(route_paths)
        write(http, route_paths[fullpath])
     else
         write(http, route_paths["404"])
     end
 end # serve()
    return(routeserver)
end
function stop!(x::Any)
    close(x)
endfunction stop!(x::Any)
    close(x)
end

还有一站!()函数杀死服务器。最终,这个 generate_router 函数就是神奇之处,它定义了一个到其内容的页面路由,然后使用 write()将正确的内容写出流。需要注意的重要部分是 routeserver 定义所在的位置。这使得该功能在关于路由的所有情况下都是可再现的,并且在没有找到路由的情况下,该路由请求 404 路由。现在我们完成了我们的内部构造函数,它依赖于我们在它下面创建的这个新的类型系统。

mutable struct OurServer
    ip::String
    port::Integer
    routes::AbstractVector
    remove::Function
    add::Function
    start::Function
    function OurServer(ip::String, port::Int64)
        routes = []
        add, remove, start = funcdefs(routes, ip, port)
        new(ip, port, routes, remove, add, start)
    endfunction OurServer()
        port = 8001
        ip = "127.0.0.1"
        OurServer(ip, port)
    end
end

使用这种技术,我们现在已经构建了一个服务器,它将根据请求本身的内容来引导或限制流量请求。非常棒,这个结果非常好合作。首先,我们创建路线:

home = Route("/", "<h1>HELLO WORLD</h1>")
four04 = Route("404", "<h1> Directory not found </h1>")

然后,我们创建一个服务器,并在其中添加两条新的 HTTP 路由。感谢我们的内部构造器,这绝对是轻而易举的事:

server = OurServer()
server.add(home)
server.add(four04)

现在我们可以像这样启动一个新的异步服务器:

serving = server.start()Starting server on port 8001
Successfully started server on port 8001

You may visit it now at [http://127.0.0.1:8001](http://127.0.0.1:8001/)Sockets.TCPServer(RawFD(45) active)

访问该链接会产生以下结果:

(图片由作者提供)

现在我们可以关闭服务器,转到另一个更酷的闭包实现。

stop!(serving)

作为参数的函数

虽然使用这些闭包函数的非常规酷的方式可能是将它们用作 HTTP 服务器的路由函数,但更有可能的情况是,人们最终会看到这些函数被用作参数。这通常是在处理复杂数据结构的基本 Julia 方法中完成的,所以这绝对是你想了解 Julia base 及其生态系统的东西。像这样的函数的一个例子就是过滤器!()函数,它采用一个函数作为筛选依据。这通常是通过匿名函数完成的。

x = [5, 10, 15, 20, 25]

假设我们想从这个数组中得到的只是 15 以上的值。分离这些值的典型方法是制作一个掩码。掩码是一个 bitarray,意思是一个布尔值数组,它决定每个值是否满足某个条件。我们真正需要做的是设计一个函数,然后应用于每个单独的值,以创建这个掩码。我们使用按位逻辑右操作符->创建这些函数。下面是我们如何单独创建该函数的示例:

x -> x > 15
#11 (generic function with 1 method)

或者,我们可以在过滤器的直接调用中定义它!()方法:

filter!(x -> x > 15, x)

虽然我们可以简单地通过名称将函数作为参数传递,但是还有另一个非常好的语法您可能想知道。这种语法称为 do/end 语法,它允许您在给定调用后将函数定义为代码块,然后将该函数作为参数进行处理。作为一个例子,我引用了我的代数数组的实现。这里有两个链接,一个是我详细介绍这些阵列如何工作的文章,另一个是这个项目的笔记本资源:

https://github/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/Algebraic Arrays.ipynb

代数数组基本上是可以用某种规范形式表示的数据,所以计算机只计算它需要处理的部分。这个想法是将所有这些内存消耗和事物排除在环境之外,通过选择何时与什么数据进行交互,使科学在更大范围内变得更加可行。Julia 实际上使这个实现变得非常简单,这要归功于完成这类事情所需要的非常简单的多重调度绑定。无论如何,这里是看看什么类型,然后是使用 do/end 语法计算函数。

mutable struct AlgebraicArray
    f::Function
    n::Int64
    calls::Vector{Pair{Function, Tuple}}
    function AlgebraicArray(f::Function, n::Int64)
        new(f, n, [])
    end
end

在这之上是生成层,它允许我们为一个调用生成单独的索引。这存在于几种不同的调度形式中,如 range、bitarray 和没有附加参数的代数数组。

function generate(aa::AlgebraicArray, range::UnitRange)
    if range[2] > aa.n
        throw(BoundsError(string("Invalid algebraic index, ", string(range[2], 
                        " on algebraic expression of length ", string(aa.n)))))
    end
    [aa.f(n) for n in range]
end

最后一个前端是计算()。Compute 是通常用来从类似这样的代数运算中获取值的方法。使用 do 语法,我们可以将它作为一个流参数来使用,为了设置它,我们应该像这样构造我们的方法:

function compute(f::Function, aa::AlgebraicArray) # compute(aa)
    gen = generate(aa)
    for call in aa.calls
        gen = [call[1](gen, call[2]...)]
    end
    return(f(gen))
end

这一努力的最终结果变成了这样的语法:

mask = compute(z) do aa
    [if val > 12 true else false end for val in aa[1]]
end
20-element Vector{Bool}:
 0
 0
 0
 0
 0
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1
 1

如果您想深入了解这背后的实际代码,并且想了解更多关于它的一般信息,那么我肯定会建议您阅读上面的文章,因为它可能会给出关于这些数组实际如何工作的更多解释。

结论

关闭的力量被大大低估了。该技术提供了许多好处和解决困难或复杂问题的新方法,这无疑使它有别于许多其他编程技术和方法。此外,Julian 实现确实允许以一些非常酷的方式使用函数。虽然在其他编程语言中肯定有这种元素,Python/Java 的 lambda 和 Javascript 的函数定义浮现在脑海中,但我必须说我真的更喜欢 Julia 处理这些事情的方式。

感谢您阅读我的文章,我希望对闭包功能的强调似乎是有道理的。也许在你的下一个项目中,你会用它来解决一些问题,因为它们经常会派上用场!

云基础:自动扩展服务器

原文:https://towardsdatascience/cloud-basics-auto-scaling-servers-71aa9945178a

AWS 中基于负载自动扩展服务器的教程

Jorge Ramirez 在 Unsplash 上的照片

云的优势之一是不必提前为生产中的工作负载准确预测和调配资源。在内部模型中,您需要通过纵向扩展(增加现有服务器的 cpu、内存等)来过度配置硬件资源。)或水平(添加更多同等资源的服务器)来尝试满足预期的峰值工作负载。这导致大部分时间服务器资源利用不足和浪费。

云允许我们根据各种参数自动扩展和缩减资源(服务器)。

图 1:云中的自动扩展选项

在本教程中,我们将根据上面列出的选项#1 和#2 测试自动缩放,步骤如下:

  1. 在负载平衡器后面的自动扩展组中启动一组 2 个 EC2 web 服务器。
  2. 基于测试工作负载的自动扩展
    -手动触发 CPU 峰值超过 90%持续 2.5 分钟
    -观察额外的服务器被自动创建
    -观察服务器在 CPU 低于 70%的 2 分钟后被移除
  3. 测试基于可用性的自动伸缩
    -手动删除 1 台服务器&观察新服务器的创建

先决条件

从下面链接的帖子中完成以下部分。

  1. AWS 设置
  2. GitHub 帐户设置和安装

1.启动自动扩展堆栈

目标:使用 CloudFormation 模板在负载平衡器后面的自动扩展组中启动一组 web 服务器。

图 2:虚拟私有云中负载平衡器后面的自动扩展服务器组的架构

  1. 转到https://github/shrestha-ajay/cloud-basics2.git
  2. 遵循"自述文件中的步骤。MD 文件中的回购或遵循以下步骤
  3. 通过点击 GitHub UI 中的“Fork”来分叉这个库
  4. 通过运行以下命令,将此存储库克隆到您的本地计算机上:
$ git clone [git@github:YOUR-USERNAME/YOUR-REPOSITORY.git](http://git@github:YOUR-USERNAME/YOUR-REPOSITORY.git)
$ cd YOUR-Repository-Folder

6.确保按照先决条件在您的计算机中配置了 AWS CLI

7.运行以下命令创建自动扩展解决方案堆栈

aws cloudformation deploy \
  --stack-name my-cloudbasic-autoscaling \
  --template-file AutoScalingMultiAZWithNotifications.template \
  --parameter-overrides KeyName="EC2Keypair" OperatorEMail="Email"

注:用您的值替换ec2 key pair*&Email。*

8.转到 AWS 控制台> CloudFormation 和 AWS 控制台> EC2 以确认资源已创建。

9.从云信息堆栈的输出选项卡中打开 URL

10.堆栈启动后,检查您的电子邮件并确认订阅通知

图 3:从 CloudFormation 堆栈创建的负载平衡器的 URL

2.基于工作负载的自动扩展

目标:连接堆栈中的两台服务器,在 2.5 分钟内将服务器的 CPU 提高到 90%以上。这将触发组中新服务器的创建。这可能需要 5-7 分钟。当服务器上的负载在 2.5 分钟内降至 70%以下时,第三台服务器将自动终止。

代码 1:如果 CPU 负载在 2 分钟内> 90%,则自动添加新服务器的 CloudFormation 代码片段

步骤

  1. 从 AWS 管理控制台> EC2 列出当前作为自动伸缩组的一部分运行的 2 个服务器实例

图 4:自动缩放组的 EC2 实例列表

2.SSH 到服务器的公共 IP,并运行以下命令

$ **sudo ssh -i "yourEC2key.pem" ec2-user@54.146.219.38**[ec2-user@ip-10-0-1-116 ~]$ **yes > /dev/null &**[1] 12777[ec2-user@ip-10-0-1-116 ~]$ **top**[ec2-user@ip-10-0-1-116 ~]$ **kill -9 12777**[ec2-user@ip-10-0-1-116 ~]$ **top**

注意:
a. ssh 命令:Replace "yourec 2 key . PEM"和 IP 来匹配你的值 b. top 命令 : 显示 CPU 和资源利用率
c.
kill 命令:只有在第 3 台服务器启动后才运行 kill 。用你的进程 ID 替换 12777 警告 :请勿在您的电脑中运行“yes>/dev/null&”。这可能会导致您的计算机过热。

图 5:显示执行命令序列的屏幕截图

图 6:增加 CPU 后运行 top 命令的输出

图 7:显示创建第三个 EC2 实例的屏幕截图

图 8:显示服务器高 CPU 的屏幕截图

图 9:显示低 CPU 和移除(自动终止)第三个服务器的屏幕截图

3.基于可用性的自动扩展

目标:终止两个正在运行的服务器中的一个,并看到一个新的服务器被自动创建,因为 CloudFormation 模板表明我们需要至少两个服务器一直运行。

代码 2:定义自动扩展组中最小和最大服务器数量的云信息资源

步骤:

  1. 从 AWS 管理控制台> EC2 终止服务器
  2. 等待几分钟,让新服务器自动配置。

图 10:终止正在运行的实例,并看到自动创建的新实例

图 11:自动创建的实例的初始化

摘要

在本教程中,我们演示了自动伸缩如何适用于基于负载和可用性的场景。请注意,在整个实验中,负载平衡器的 URL 应该是打开的,而服务器根据负载和最低可用性进行伸缩。自动伸缩实现了 web 服务的高可用性和可靠性。有关实现的更多信息,请查看 GitHub 资源库中的 CloudFormation 基础设施代码。

图 12:从 CloudFormation 堆栈创建的负载平衡器的 URL

清除

温和的提醒删除云形成堆栈,以避免在你的实验后被收费。删除云形成堆栈后,应终止 EC2 服务器。

图 13:显示堆栈终止的屏幕截图

资源

  1. https://aws.amazon/autoscaling/
  2. https://aws.amazon/cloudformation/
  3. 【https://github/shrestha-ajay/cloud-basics2
  4. https://en . Wikipedia . org/wiki/Yes _(Unix)

云基础知识:与 AWS 交互

原文:https://towardsdatascience/cloud-basics-interacting-with-aws-da179d3f5829

关于使用各种接口创建云资源的教程

在 Unsplash 上 engin akyurt 拍摄的照片

有基于编程和 GUI/web 的方式与云提供商进行交互,以创建和管理云中的资源。在本实验教程中,我们将通过以下四种方式与 Amazon Web Services(AWS)API 进行交互,以创建 AWS EC2 实例(虚拟化服务器)和 S3(云存储)。

  1. AWS 管理控制台(浏览器)
  2. AWS CLI(命令行界面)
  3. 交互式开发环境
  4. 自动气象站云形成

通过控制台进行更改对于实验来说很好,但除此之外并不可取。它也不支持自动化和版本控制。CloudFormation 之类的基础设施代码解决方案应该用于实验之外的任何事情。

表 1:比较不同的云 API 交互方法

先决条件

AWS 设置

  1. AWS 设置
    -设置自由层 AWS 帐户( 链接)
  2. 使用 root 用户登录 AWS 控制台,并创建 IAM 用户。
    -按照链接中的创建 IAM 用户(控制台)下的步骤操作。为两个程序性 & AWS 管理控制台访问
    创建凭证——在第 6 步(权限,选择“直接附加现有策略”&添加“管理员访问”,并完成其余步骤
  3. 为 EC2
    创建密钥对——确保您位于 AWS 控制台
    中的 us-east-1 (北弗吉尼亚)地区——使用链接中的“创建密钥对”下的说明创建 ec2 密钥对
  4. 安装 AWS CLI — 链接
    —使用“ aws configure ”命令配置 aws-cli。在这里使用上面创建的 IAM 凭据。参见链接寻求帮助。下面的例子:
$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMMPLEKEY
Default region name [None]: us-east-1
Default output format [None]: json

5.这将存储在 ~/中。AWS/凭证文件为:

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
region = us-east-1
format = json

6.使用以下命令测试 AWS CLI 凭据和配置。

aws sts get-caller-identity 

如果对您的 AWS 帐户的身份验证成功,不管您的授权级别是什么,即 IAM 权限,它都应该返回以下输出。

{
    "Account": "123456", 
    "Arn": "arn:aws:sts::123456:assumed-role/role-name/role-session-name",
    "UserId": "AR#####:#####"
} 

GitHub 账户设置&安装

  1. 创建免费 GitHub 账户— 加入 GitHub
  2. 从这里下载并安装 git 到你的电脑上
  3. 在您的终端/shell 中使用以下命令配置您的用户名和电子邮件。
$ git config — global user.name "Your name here" 
$ git config — global user.email "your_email@example"

4.在您的终端/shell 中使用以下命令在您的计算机上创建 SSH 密钥。只需接受默认值并一直按 enter 键,直到生成了 2 个文件(私钥和公钥)(如果您愿意的话)。

$ ssh-keygen -t rsa -C "your_email@example"

5.上面的步骤将在/中创建 2 个文件作为 ~/。ssh/id_rsa & ~/。ssh/id_rsa.pub

6.将您的公共 ssh 公钥添加到您的 github 帐户。
-转到您的 github 帐户设置
-单击“ SSH 密钥
-单击“添加 SSH 密钥
-给出一个标签(例如,“我的笔记本电脑”)并将公钥粘贴到文本框
-通过键入以下内容来测试与您的 github 帐户的连接:

$ ssh -T git@github

它应该是这样的:

Hi <your username>! You've successfully authenticated, but GitHub does not provide shell access.

Vistual Studio 代码和 AWS 工具包

  1. 安装 IDE(如 Visual Studio 代码)https://code.visualstudio/
  2. 为 VS 代码安装 AWS 工具包—https://aws.amazon/visualstudiocode/

AWS 管理控制台

这是 AWS 的 web 界面。

  1. 转到https://aws.amazon/console/
  2. 在 AWS 控制台中,确保您位于 us-east-1(北弗吉尼亚)地区
  3. 从控制台启动 Windows 实例
  4. 遵循https://docs . AWS . Amazon . com/AWS C2/latest/windows guide/EC2 _ get started . html中的步骤
  5. 使用实例的公共 IP 连接(RDP)到您刚刚创建的 Windows 实例。
  6. 确保终止 EC2 实例,以避免充电

图 1:显示运行 ec2 实例细节的屏幕截图

AWS CLI

  1. 使用以下命令从命令行界面启动 EC2 Linux 实例。用您的 ec2 密钥对名称替换。
aws ec2 run-instances --image-id ami-08e4e35cccc6189f4 --count 1 --instance-type t2.micro --key-name <Key-Pair-Name> --security-groups default

暂时向所有 IP 开放实例的安全组上的 SSH 端口(请注意,这不是一个好的安全做法)。请参见https://docs . AWS . Amazon . com/AWS C2/latest/user guide/authoring-access-to-an-instance . html的“向 Linux 实例添加入站 SSH 流量规则”一节

2.从控制台使用“ EC2 实例连接连接到实例。

3.确保终止 EC2 实例,以避免充电

图 2:显示创建 ec2 实例的 CLI 命令后终端输出的屏幕截图

交互式开发环境(IDE)

AWS Toolkit for Visual Studio 包括 AWS SDK。既然您在 VS 代码上安装了工具包,我们将在 VS 代码中使用 AWS 扩展来创建 AWS S3。

  1. 打开 Visual Studio 代码
  2. 打开 AWS 浏览器
  3. 右键单击 S3 并创建一个桶
  4. 从控制台验证铲斗

图 3:显示 VS 代码 UI 中 S3 创建链接的屏幕截图

自动气象站云形成

CloudFormation 是 AWS 的 IaC(基础设施即代码)服务,它允许我们建模、创建和管理 AWS 和第三方资源。

  1. 从云形成模板启动 EC2
  2. 去 https://github/shrestha-ajay/cloud-basics1.git
  3. 遵循"自述文件中的步骤。MD 文件中的回购或遵循以下步骤
  4. 通过点击 GitHub UI 中的“Fork”来分叉这个库
  5. 通过运行以下命令,将此存储库克隆到您的本地计算机上:
$ git clone git@github:YOUR-USERNAME/YOUR-REPOSITORY.git
$ cd YOUR-REPOSITORY-Folder

6.在本地计算机中配置 AWS CLI

7.运行以下命令,在您的 AWS 帐户中创建 ec2 实例和安全组

aws cloudformation deploy \
  --stack-name my-cloudbasic-ec2 \
  --template-file ec2_securitygroup.template \
  --parameter-overrides KeyName=General-key-1

注意:用您的 EC2 密钥对名称替换“General-key-1”密钥名称

8.确保终止 EC2 实例,以避免充电

图 4:显示带有 EC2 实例的 CloudFormation 堆栈的屏幕截图

总结

在本实验中,我们使用四种方式与 AWS 交互来创建云资源(ec2 和 s3):控制台、CLI、IDE 和 CloudFormation。存在一种方法可能优于另一种方法的用例,所以熟悉每种方法是有好处的。

打扫

温和地提醒终止资源,以避免被收取费用。

资源

  1. https://aws.amazon/free
  2. https://docs . AWS . Amazon . com/IAM/latest/user guide/id _ users _ create . html
  3. https://docs . AWS . Amazon . com/AWS C2/latest/windows guide/ec2-key-pairs . html
  4. https://AWS . Amazon . com/CLI/
  5. https://docs . AWS . Amazon . com/CLI/latest/user guide/CLI-configure-files . html
  6. http://github/signup ?
  7. https://git-SCM . com/downloads
  8. https://AWS . Amazon . com/SDK-for-python/
  9. https://code . visualstudio . com/
  10. https://AWS . Amazon . com/visualstudio code/
  11. https://AWS . Amazon . com/console/
  12. https://docs . AWS . Amazon . com/awsec 2/latest/windows guide/ec2 _ getstarted . html
  13. https://github . com/sh restha-ajay/cloud-basics 1 . git

云 ML 性能清单

原文:https://towardsdatascience/cloud-ml-performance-checklist-caa51e798002

优化基于云的培训的指南

杰克·威瑞克在 Unsplash 上的照片

在云中培训有很多好处。其中包括对多种培训实例类型的可访问性,将培训无限制地扩展到多个实例和多个并行实验的能力**,以及丰富的生态系统功能和服务促进了 ML 工作负载。**然而,如果管理不当,cloud ML 会产生相当高的成本。虽然主要职责是制定和实施治理政策、监控云服务的使用和成本、与云服务提供商(CSP)协商定价策略等。,可能会落到您组织的云支持团队头上,算法开发人员也有责任尽自己的一份力量来提高效率,减少浪费。下面嵌入推文中的迷因说明了一切。

本文档描述了一个项目清单,我们发现该清单有助于指导算法开发人员提高训练效率,进而降低训练成本。

性能测定

我们的主要性能指标是 每美元的样本数 ,即每花费一美元,训练循环遍历的样本数。 样本每美元 的公式为:

每美元公式示例(按作者)

其中每秒样本数=批量每秒批次数*。培训实例费用可在您的 CSP 网站上找到。

虽然您的目标应该是最大化每美元 的 样本,但有时您需要考虑其他因素。例如,您可能决定将训练分布在多个 GPU 上以加速训练,即使这可能会减少每美元个样本。另一个例子是,最大化每美元的样本会损害训练工作的收敛速度(例如,对批量大小的增加敏感的模型)。

性能优化是一个迭代过程,如下图所示:

性能优化流程(按作者)

这个迭代过程应该伴随项目的整个生命周期。

性能分析工具

有许多分析性能的工具和方法。一些基本指标包括云服务提供商(CSP)报告的资源利用率指标和 TensorBoard profiler 插件。

这张图片显示了一个由亚马逊云观察监控工具报告的低 GPU 利用率的例子:

亚马逊 CloudWatch 中的 GPU 利用不足(作者)

TensorBoard profiler 插件是一个强大的工具,支持许多流行的机器学习框架的分析(包括 TensorFlow 、 PyTorch 和 Jax )。一开始,这个分析器看起来有点吓人,但是它非常容易设置,并且是识别性能瓶颈的一个非常有用的工具。更多详情参见分析器文档。

下图来自 TensorBoard profiler trace viewer,显示了长时间的 GPU 空闲时间,表明训练步骤中存在重大瓶颈。

TensorBoard Profiler 插件显示的性能瓶颈(作者)

性能分析清单

本节包括衡量培训工作当前绩效的基本指南。

  1. 您的培训计划是否包括定期报告每秒培训样本的平均数量
  2. 您目前衡量每美元样品的标准是多少?
  3. 在整个培训过程中,每美元样品测量值是否相对稳定?
  4. 您的培训脚本是否支持启用概要分析的选项,例如通过 TensorFlow 中的 TensorBoard 回调?
  5. CSP 的云指标报告的当前平均 GPU 内存利用率是多少?一般来说(但不总是),通过增加训练批量来最大化 GPU 内存的使用是一个好主意。这通常会增加每秒的样本数,因为它降低了固定操作(如内核加载和梯度共享)的成本。在某些情况下,批量大小的选择会对 GPU 内存对齐产生影响,这也会影响性能。
  6. CSP 的云指标报告的当前平均 GPU 利用率是多少?你的目标应该是尽可能地增加这一点。95%的利用率是一个很好的目标。任何低于 80%的数据都意味着你的训练出现了瓶颈,应该会让你夜不能寐。
  7. 其他系统指标,包括 CPU 和网络利用率,可能会对潜在的性能问题提供一些提示,但通常很难从中获得有用的信息。这些指标中是否有任何一项表明可能存在瓶颈?
  8. 评估训练管道性能的一个有用方法是对缓存的输入运行训练循环。通过这样做,您可以有效地隔离出所有的输入流水线计算,并在这种情况下计算每美元 的 个样本。这个数字表示当数据输入管道上没有瓶颈时可以达到的性能。如果有您正在努力解决的瓶颈,这个数字应该被视为您的目标性能。您的脚本支持在缓存的输入上计算每美元样本的选项吗?在 Tensorflow 中,缓存输入可以通过应用: dataset = dataset.take(1)轻松完成。缓存()。在数据集创建结束时重复()(预取之前)。请注意,通过在数据集的其他阶段应用缓存,可以获得对 CPU 争用的潜在来源的更多见解,并且应该在分析输入管道上的瓶颈时使用。
  9. TensorBoard profiler 是一个非常有用的性能分析工具。让它成为你发展周期的一个常规部分是很重要的。对其功能的全面概述超出了本文档的范围,但是强烈建议(并没有您想象的那么困难)学习如何使用它。您运行(并分析)分析器了吗?
  10. 查看探查器摘要报告。它是否报告了输入管道瓶颈?(请注意,如果在“内核加载”上花费了大量时间,这可能表明 CPU 争用率很高,并且可能表明存在 CPU 瓶颈。)
  11. 打开跟踪查看器。有没有什么麻烦的模式比如 GPU 长时间闲置或者频繁的 CPU 到 GPU 的拷贝?
  12. 查看十大 TensorFlow GPU 操作。它们是你所期望的吗?这些有时可以暗示对模型的潜在优化。

实例选择

根据您选择的培训实例,每美元的样本量可能会有很大差异。选择错误的训练实例会对成本产生可怕的后果。一般来说,新一代的实例(比如 Amazon EC2 G5 和 p4 实例类型)包含了提高性能的硬件增强。另一个考虑因素是 CPU 与 GPU 计算能力的比率。较低的比率可能会增加对 CPU 资源的争用,并导致 CPU 瓶颈。

  1. 您目前的培训情况如何?你考虑过其他选择吗?如果你使用的是老一代 GPU,比如 Amazon EC2 p2 或 p3,你应该有一个很好的理由。
  2. 替代(非 GPU)加速器,如亚马逊 EC2 dl1 (基于哈瓦那高迪)和谷歌云 TPU (在 GCP)通常(但不总是)提供比 GPU 更高的性价比。然而,它们有时需要对这些加速器进行一些调整。你有没有尝试过在一个专门的 DNN 培训加速器上运行你的模型?使用这些替代品有什么障碍?

培训优化

下图显示了典型训练步骤的各个阶段。每一步都是性能瓶颈的潜在来源:

典型训练步骤的步骤(作者)

存储到 CPU

训练步骤的第一阶段是将原始训练样本加载到 CPU 上。存储数据的方式需要特别注意,这样这个阶段才不会成为瓶颈。如果您的数据存储在远程(云)对象存储中,比如亚马逊 S3,这一点尤其正确。实例类型网络入站容量、S3 出站容量或 CPU 争用的限制可能会导致数据匮乏。训练速度可能会受到您选择的数据格式(例如顺序与列格式)、数据文件的大小、用于流式传输数据的方法(管道模式、FFM、直接下载等)的影响。)、数据压缩的使用等。

分析数据流速度的一种方法是直接迭代数据集,测量每美元的 样本 ,而不运行训练步骤。理想情况下,结果将明显高于使用训练步骤跑步时的结果。

  1. 您的文件大小是否在 100 MB 左右?
  2. 如果你在使用 Amazon SageMaker,你会利用 FFM 或 PipeMode 来传输你的数据吗?
  3. 在没有训练的情况下迭代数据集时, 每美元样本数 是多少?
  4. 在输入数据管道的开始应用数据缓存时,每美元的 样本 是什么?如果它高于基准值,这可能表明有问题。
  5. 使用数据压缩可以减少网络带宽需求,也可以降低存储成本。另一方面,数据解压缩可能会增加 CPU 争用。你是否研究过数据压缩对你训练速度的潜在影响?

CPU 瓶颈

GPU 利用率不足的最常见原因之一是 CPU 上的瓶颈。如果由于 CPU 争用而出现瓶颈,可以考虑以下选项:

  1. 您是否使用了基本的并行化技术,比如批处理预取num_parallel_calls
  2. 有没有可以转移到数据准备阶段的计算?
  3. 有没有可以移到 GPU 上的计算层?请注意,这将增加整体 GPU 计算,但可能会导致步骤时间缩短。
  4. 将一些输入数据预处理卸载到辅助 CPU 会有帮助吗?请注意,需要考虑很多因素,例如总体成本、对网络数据流量的影响等。
  5. 您是否探索过优化 CPU 操作的选项(例如使用 XLA )?

提高 GPU 利用率

即使您的 GPU 得到了充分利用,您也可以采取一些措施来提高其性能:

  1. 使用混合精密浮子。TensorFlow 和 PyTorch 的当前版本支持 16 位精度浮点。当使用 TensorFlow 混合精度时,模型参数存储在全精度浮点表示中,而算术运算用低精度浮点执行。使用混合精度可以大幅降低 GPU 内存的使用(从而增加批量大小)并增加每美元的样本数。有两种类型的 16 位浮点表示:float16 和 bfloat16。Bfloat16 是首选,因为它的动态范围与 float32 相似。Bfloat16 由现代 GPU(例如 A100 和 A10)、云 TPU 和 Habana Gaudi 支持。如果您的实例支持 bfloat16,那么您可以启用混合精度,而不会对您的模型收敛产生任何影响。对于 float16,事情会变得更棘手,因为你可能需要使用渐变缩放技术来确保收敛。你的实例支持 bfloat16 吗?你在使用混合精度吗?
  2. XLA 是一个编译器,它通过融合单个操作来优化 GPU 计算。在许多情况下,启用 XLA 将导致每美元的样本增加。你在用 XLA 吗?对性能有什么影响?
  3. 有时,您的计算图可能包含加速器不支持的操作。在这种情况下,操作可能会卸载到您的 CPU。这会大大降低你的训练速度,应该避免。在 TensorFlow 中,可以使用TF . debugging . set _ log _ device _ placement来识别这种情况。这种情况有时也可以在 TensorBoard profiler trace viewer 中发现,在 GPU 计算过程中,您会看到主机和设备之间频繁的内存复制。你确保所有的运算都在 GPU 上运行了吗?
  4. DNN 专用加速器,如云 TPU 和 HPU (Habana Gaudi)可以增加每美元的样本数,但可能需要一些改造才能获得最佳性能。例如,TPU 和 HPU 在具有动态形状(例如 boolean_mask)的张量上表现不佳。您的模型是否针对您正在训练的加速器进行了优化?
  5. 您是否正在为您的任何模型层使用 tf.py_function ?如果是这样,您可能需要考虑其他性能替代方案。
  6. 记忆格式会影响训练效果。例如,参见这篇文章关于将你的内存格式编程到底层加速器的重要性。你用的是什么内存格式?你的选择对你的培训资源来说是最优的吗?

多 GPU 训练

多 GPU 训练是一种用于提高整体开发速度的常用技术。使用多个 GPU 的一种常见方法是执行数据分布式训练,在这种训练中,我们将全局批量大小划分到多个 GPU 上,每个 GPU 维护一个相同的模型副本。通过在每个训练步骤结束时共享梯度来保持同一性。理想情况下,您的培训绩效将呈线性增长,即每美元的样本数不会减少。然而,通常情况下,梯度共享,尤其是它所暗示的增加的网络通信流量,会降低每 美元样本。但是,有多种方法可以缓解这种情况:

  1. 你的多 GPU 训练的每美元的样本是多少?与单 GPU 每美元采样相比如何?
  2. 一般来说,比起多个实例,您应该总是更喜欢具有多个 GPU 的单个实例。是这样吗?
  3. CSP 通常包括专门的网络接口,可以提高节点间网络通信的性能(例如亚马逊 EFA 和谷歌 FastSocket )。你在多种情况下训练吗?您选择的实例支持加速的节点间网络通信吗?
  4. 你有没有探索替代的梯度分享策略?共享渐变的常见/默认策略是环全减。你可能会发现你的模型受益于替代策略,比如鲱鱼。
  5. 现代梯度共享策略将把梯度分块,并把它们并行分布到后退步骤。如果 TensorBoard profiler 跟踪查看器显示所有的设备到设备通信在该步骤结束时聚集在一起,这可能表明存在问题。
  6. 梯度共享 API 将包括一个压缩梯度的选项,以减少网络流量。你考虑过这个选择吗?
  7. 由于多 gpu 旨在加速培训,并且您可能不太关心评估时间,因此您可能希望考虑将评估转移到单独的单个 GPU 实例。

项目优化

上一节重点介绍了对单个培训作业的优化。这里,我们建议在项目级别进行优化:

  1. 你的项目包括自动提前停止失败实验的回调吗?
  2. 您是否使用自动化超参数调整技术?
  3. 您的开发流程包括删除未使用的存储吗?
  4. 你在用的工具(TensorBoard,comet.ai,clearML,Neptune 等。)来管理你的实验?高效的实验管理可以增加订单并减少重复。

摘要

本页分享的列表绝非包罗万象。自然要适应自己项目的具体需求。请随时提出问题/评论/更正,特别是您认为应该包括的其他项目。

聚类—对数据科学家来说是一项艰巨的任务

原文:https://towardsdatascience/clustering-a-daunting-task-for-a-data-scientist-5c7f362ccfb8

设计群集模型的准则

照片由 Unsplash 上的尼克·费因斯拍摄

考虑这样一种情况,一个政党邀请您(一名数据科学家)分析人口数据,以帮助他们赢得即将到来的选举。你的任务是找出全国人口中支持该党的群体。有了这些信息,党就可以在不同的地区策划他们的运动。这是在大规模数据集上聚类(形成组)的经典例子之一。还有许多其他情况下数据集很小,主要是因为数据隐私和收集数据本身的方式。

无论您拥有的是小数据还是大数据,即使对于经验丰富的数据科学家来说,聚类也始终是一项挑战。这主要是因为“集群”本身的概念没有精确的定义。一个数据科学家可能在一个数据集中找到三个聚类,而另一个数据科学家可能将同一个数据集聚类成四个区域。通常,数据科学家之间可能不会就此达成共识;然而,最终的决定通常是由数据集的利益相关者做出的。正是他们对数据的知识和理解最终满足了他们的需求。

那么,数据科学家如何满足客户的要求呢?

数据科学家的方法

对于数据科学家来说,解决聚类问题的第一个也是最重要的方面是检查数据集的大小。根据大小,数据科学家选择合适的聚类模型和算法。一段时间以来,研究人员开发了许多满足各种数据大小的特定需求的聚类算法。对于小到中等大小的数据集,我们使用简单的基于连通性的聚类算法;而对于具有多元分布的非常大的数据集,必须使用基于非常先进的统计技术的算法。选择聚类算法是数据科学家的知识和技能。在本文中,我将描述数据科学家解决这个重要问题的方法。为了理解这种方法,让我们简要地考虑一下聚类类别和每一类别中的各种算法。

聚类类别

聚类算法大致分类如下:

  • 基于质心的
  • 基于连通性
  • 基于分布的
  • 基于密度
  • 聚类巨大的数据集
  • 八卦式聚类
  • 基于网格的

我现在将向您介绍这些类别,并简要描述每个类别中的算法。

基于质心的

k-meansk-medoids 算法就属于这一类。这些可能是最容易理解的,并且通常是学习集群的起点。在这里,您需要在运行算法之前指定想要形成的聚类数。有一些可用的技术,如平均轮廓间隙统计,用于选择集群形成的最佳数量。这种情况下的优化问题是 NP 难的,因此它通常只提供近似解。该模型非常适合中小型数据集。

基于连通性

凝聚分裂聚类算法就属于这一类。这些算法基于这样的概念,即根据对象之间的距离来连接对象。他们为整个数据集创建一个树状图或层次结构。这种可视化表示有助于您识别集群。聚类主要取决于距离函数的类型和连锁准则的选择。我们在专门的应用中使用这种类型的聚类,如确定动物进化的系统进化树、通过绘制系统进化树来跟踪病毒、通过分析文本相似性来分类文档等等。如果您希望在确定聚类时获得数据集的分层表示,可以使用这些算法。

基于分布的

高斯混合模型 (GMM)就是属于这一类的一种算法。这里,我们假设利益相关者对其数据集的统计分布有所了解。由于在数据分布中存在强假设,如果假设出错,算法将产生不利的聚类。因此,仅当您确定数据集的统计分布时,才使用此类算法,在这种情况下,该算法将产生出色的聚类结果。

基于密度

DBSCAN 算法就属于这一类。某个区域中数据点的高密度定义了群集。密度的下降标志着星团的边界。对于像高斯混合这样的分布,这种算法非常有效。这种类型的聚类的最重要的方面是它可以创建任意形状的聚类,而前面讨论的算法大多产生圆形聚类。第二,算法复杂度相当低,并且输出是确定的——这意味着它们在每次运行中发现相同的结果。

光学是属于同一类别的另一种算法。它推广了 DBSCAN。该算法还产生链接可视化,这有助于数据科学家创建他选择的集群。

Mean-Shift 算法是这一类别中的另一种算法,其中我们基于核密度估计(KDE)来形成聚类。该算法可以检测任意形状的簇,但比 DBSCAN 慢。此外,它不能在多维数据集上产生良好的聚类。

当数据集很大时,数据科学家使用基于密度的聚类。

庞大的数据集

你如何聚集巨大规模的数据集?你使用了一个众所周知的策略——分而治之。T4 桦树 T5 算法就属于这一类。我们将数据集分成更小的单元,在每次分割中尽可能多地保留原始数据集的信息。然后,我们使用其他已知的聚类技术对每个分割单元进行聚类。这种技术的优势在于,它消除了将整个数据集加载到内存中的需要。

CLARANS 是这一类别中的另一种算法,它在对数据集进行聚类时使用随机搜索。然后,它对每个单元应用 PAM(围绕 Medoids 划分)算法来确定其聚类质量。如果不好,它重复整个聚类过程。因此,它保持了计算成本和数据随机采样之间的平衡。它允许多边形物体和可以使用任何任意距离测量功能。它提供了高质量的聚类。

八卦式聚类

也被称为相似性传播聚类,这里我们通过对等体之间的闲聊来形成聚类。这就像社交网络。我们根据成员和他们的领导之间的某种亲密关系来组建团体。同伴消息传递和一个人成为小组领导的意愿决定了亲和力度量。你不需要预先估计集群的数量。该算法肯定会产生非常好的结果,尤其是当您不知道数据集可能具有的聚类数时。该算法计算量很大。

基于网格的

到目前为止,我们考虑的所有上述算法都是基于查询的。如果您决定尝试另一个查询,您将需要再次扫描整个数据集。因此,所有这些聚类技术的计算量都很大。

STING 算法就属于这一类。最初,我们将整个数据集分割成矩形单元,层次结构中的每个较高级别的单元包含较低级别的单元集合的摘要。由于该结构是独立于查询的,因此我们可以并行化整个集群过程,从而节省集群时间。不仅如此,由于其性质,它可以处理增量更新,这是动态数据集中的一个要求。另一个优点是该算法的低复杂度。

CLIQUE 是这一类的另一个算法。它结合了基于密度和网格的聚类技术。该算法从一维子空间开始,不断融合计算高维子空间。它使用一种先验技术来寻找可聚类的子空间,非常适合聚类高维数据集。

结束语

到目前为止,我已经讨论了许多聚类类别,这些类别可以帮助您根据数据集大小和客户对聚类的期望来决定使用哪种算法。我在这篇小文章中介绍的概述可以帮助您选择一种算法来对小型、中型、大型甚至空间数据集进行聚类。

聚类通常是非平凡的,因为它的无监督的性质和事实上可能没有对最终结果的共识。作为一名数据科学家,您应该对这些不同的聚类算法、构建它们的目的以及它们所解决的聚类问题有一个很好的概念性概述。几个库提供了这些算法的有效实现,作为一名数据科学家,你不必担心它们背后的数学。只要了解每一类算法的用途,你就能解决任何聚类问题。

要了解更多信息,你可能想参考我即将出版的书,思考数据科学(应用机器学习中的斯普林格系列)。它有一大部分是关于聚类的,有关于所有算法的实际例子。

https://medium/@profsarang/membership

聚类算法基础及其 Python 实现

原文:https://towardsdatascience/clustering-algorithm-fundamentals-and-an-implementation-in-python-31a482592b04

创建包含相似元素的数据组的无监督过程

伊恩·杜利在 Unsplash 上拍摄的照片

什么是集群?

聚类是一种可以通过创建有意义的组或簇来帮助机器学习工程师理解未标记数据的方法。这通常会揭示数据中的模式,这可能是机器学习中有用的第一步。由于您正在处理的数据是未标记的,聚类是一项无监督的机器学习任务。

通过一个称为相似性度量的度量标准,数据根据彼此的相似性被分类成组,其中用于找出数据集中对象的相似程度。为了计算这种相似性度量,使用数据集中对象的特征数据**。为每个集群提供一个集群 ID ,这是一个强大的集群应用。这样可以简化大型数据集,还可以将对象的整个特征集压缩到其分类 ID 中。**

这一原则的一个简单现实例子是收集关于家庭规模和家庭收入的数据,以创建用户群,如小家庭高消费群、小家庭低消费群、大家庭高消费群和大家庭低消费群。

聚类的用途

如今,集群被广泛应用于行业中的各种用例。其中包括搜索结果分组、社交网络分析和市场细分。聚类也用于图像分割、异常检测和医学成像。

扩展上面提到的集群 id 的优点,集群可以用于根据不同的特征对对象进行分组。例如,星星可以根据亮度分组,音乐可以根据流派分组。

在像 Google 这样的组织中,集群用于:

  • 概化:当集群中的对象缺少要素数据时,可以从集群中的其他对象推断出它们。
  • 数据压缩:特征数据可以完全由集群 ID 代替。这节省了存储空间并简化了特征空间。这有助于使 ML 模型训练更简单、更快速。
  • 保护隐私:将用户分组并将他们的数据与集群 id 相关联可以防止将用户数据与特定用户相关联,从而确保用户隐私。

聚类分析的结果。来源:hellisp,公共领域,via Wikimedia Commons

聚类算法

现在我们已经了解了聚类的概念,让我们看看一些常见的聚类算法。关于详尽的清单,你可以参考这篇论文。

分层聚类

这种方法适用于分层数据,它创建了一个聚类树。对于大多数数据集来说,标准算法太慢,因为它的时间复杂度为 O(n ),内存需求为ω(n)。然而,运行时间的减少是以内存需求为代价的,尽管内存开销在大多数情况下很难实际使用。

Orange 数据挖掘套件中的层次聚类和交互式树状图可视化。blazupan(橙色数据挖掘), CC BY-SA 4.0 ,通过维基共享

基于分布的聚类

在这些算法中,假设数据属于不同的分布。然后,集群被定义为那些包含相似分布的对象的集群。一个缺点是基于分布的聚类容易过度拟合。因此,必须对模型的复杂性加以限制。

下图显示了一个示例,其中数据被聚类为三个高斯分布。较暗的颜色更接近分布的中心,条带显示数据属于某个分类的概率强度。随着到中心的距离增加,数据属于该聚类的可能性将降低。

如果您没有关于数据集分布类型的信息,此算法可能不是最好的。

基于高斯分布的聚类。由 Chire-Own 工作, CC BY-SA 3.0 ,通过维基共享

基于密度的聚类

这些算法通过连接包含高密度对象的区域来创建聚类。它要求密集区域是可连接的,并且根据设计,离群值不会被分配给聚类。一个缺点是基于密度的聚类算法在处理更高维度以及具有不同密度的数据时面临困难。

使用 DBSCAN 算法对基于密度的数据集进行聚类分析。 Chire , CC BY-SA 3.0 ,通过维基共享

基于质心的聚类

这种形式的聚类将数据分组到非分层分区中。虽然这些类型的算法是有效的,但它们对初始条件和异常值很敏感。最常用的基于质心的算法称为 k-means,其中 k 是定义聚类数量的超参数。

K-means 提供了一些优势,例如扩展到大型数据集的能力、易于实现以及适应新数据。另一方面, k 值必须费些力气手动找到,并且质心会被离群值拖动。考虑在聚类之前移除离群值是有益的。

给定一组 n 个数据点,k-means 算法的目标是将它们分成 k 个组,其中每个组包含相似的数据点。为了做到这一点,我们首先需要选择一个数字 k,然后我们开始随机分配每个点到它最近的聚类中心。接下来,计算每个数据点与其指定中心之间的距离。然后,我们重复上述步骤,直到没有进一步的变化发生。一旦我们完成了距离和中心的计算,我们返回到步骤 1 并重新计算聚类。这种情况一直持续到集群没有变化。此时,我们知道我们的集群是稳定的。

k 均值算法的实现

现在,让我们实现上面讨论的算法之一,并可视化产生的集群。为此,我们将使用 k-means 算法和 scikit-learn。该代码受 scikit-learn examples 提供的手写数字数据 K-Means 聚类演示的启发,并包含其中的代码。

实现 k 均值。包含来自 scikit-learn 示例 ( BSD 许可证)的代码

输出如下图所示。

结果图是从上面的代码中产生的。

除了 k-means 算法之外,scikit-learn 库还提供了其他几种算法,可以根据您所拥有的数据来使用。这些算法包括:

  • 亲和传播
  • 凝聚聚类
  • 桦树
  • 基于密度的噪声应用空间聚类
  • k 均值
  • 小批量 K 均值
  • 光学
  • 谱聚类
  • 高斯混合

请记住,没有固定的算法可以提供最好的结果。您必须运行受控实验,以确定最适合您正在处理的数据集的算法。

如果您想更深入地研究所提供的算法,scikit-learn 集群 API 是一个很好的起点。

结论

在本文中,我们研究了集群、其用途以及一些常用的集群算法类型。我们还研究了它们的优缺点,以及一些算法与其他算法相比的闪光点。最后,我们看了一个如何进行 k 均值聚类的编码示例。我希望这些信息对你有用。请在下面的评论区告诉我你的想法和问题。

基于聚类的运行风力发电机数据预处理

原文:https://towardsdatascience/clustering-based-data-preprocessing-for-operational-wind-turbines-268e231d90a

创建资产组的有效数据科学方法

左:涡轮集群(图片由作者提供)。右图:照片由菲利普·梅(Philip May)通过维基媒体提供

介绍

运行风力涡轮机产生数据流,同时产生清洁和可再生的电力供我们日常使用。数据是环境、机械和生产变量的时间序列,使用监控和数据采集(SCADA)系统获得。

风能分析通常需要对 SCADA 数据进行预处理,包括识别哪些涡轮机可被视为“邻居”。其中邻居的概念取决于感兴趣的变量,例如涡轮机位置、风速、风向和功率输出。

例如,在地理上,如果两个或更多涡轮机的纬度和经度与其余涡轮机相比彼此更近,则两个或更多涡轮机可以被认为是邻居。从技术上讲,如果两个涡轮机在调查期间经历相似的风速,也可以基于风速将它们分组为邻居。

风力涡轮机集群的应用

对风电场中的涡轮机进行分组是一个有用的数据预处理步骤,需要相对频繁地执行,并且对于非地理变量,涡轮机之间的关系可能会随着时间而改变。风力涡轮机分组的一些有用应用包括:

  • **处理缺失和虚假数据:**识别代表给定涡轮机的一组涡轮机提供了用邻居传感器数据的平均值回填缺失或虚假数据的有效方式。这对于风速等变量尤其有用,因为风速计的可靠性相对较低。
  • **并排分析:**在该分析中,控制涡轮机通常根据产生的功率被选为试验涡轮机的代表。在涡轮机升级结束时,有必要通过将其生产与相邻涡轮机的生产进行比较来测量试验涡轮机的性能改进。在这种情况下,使用基于聚类的方法需要进一步探索,并与现有方法进行比较。
  • **组功率预测:**为了降低计算成本,功率预测模型可以针对风电场中的涡轮机组而不是针对单个涡轮机来构建。此外,与为整个农场建立单一模型相比,这种方法有望提供更准确的结果。
  • **组偏航控制:**通过对一组涡轮机实施最佳偏航控制策略,可以提高风力发电场的发电量,这些涡轮机在相对于风向的位置上是相邻的,而不是单独的。

虽然聚类技术已经用于风能分析的不同领域,如风电场功率预测和偏航控制,但本文建议将这种方法扩展到其他应用,如并排分析和处理缺失或虚假的 SCADA 数据。

基于聚类的 SCADA 数据分析

涡轮机分组的一种方法包括计算一台涡轮机和农场中其他涡轮机的测量值之间的平方差之和(SSD)。其中选择具有最小 SSD 的涡轮机作为邻居。这种方法在计算上非常昂贵,尤其是如果由非编程专家编写脚本的话。

对风电场中的涡轮机进行分组的另一种方法是基于感兴趣的变量使用不同涡轮机之间的相关系数。这种方法很简单,计算量也不大,但是对于处理缺失值这样的应用可能没什么用。

基于聚类的方法采用现有的公开可用的最新数据科学技术和工具。这种方法中最流行的是 K 均值聚类。该方法确保一个组中的涡轮机不仅具有最小的组内平方和,而且与其他组中的涡轮机具有最大的组间平方和。

虽然 K-Means 聚类类似于 SSD 方法,但它也针对聚类间的不相似性进行了优化,这有望提高其健壮性。此外,该方法适用于比相关系数法更广泛的风力涡轮机分析,并且可以优雅地处理多个变量。因此,这种方法对 SCADA 数据分析更有效。

此外,聚类技术在数据科学中得到了很好的研究,可以很容易地在几行代码中实现。可以探索的其他聚类方法包括分级、谱和基于密度的聚类方法。

案例研究:

使用聚类统计识别涡轮机组并处理缺失的风速数据。

在本例中,我们展示了一种高效而简单的数据科学方法,使用来自 Sklearn 库的 K-Means 聚类技术在风力发电场中创建涡轮机组。我们还比较了使用获得的聚类预测缺失风速数据的两种方法。

首先,让我们导入相关的库

# Import relevant libraries
import os
os.environ['OMP_NUM_THREADS'] = "1"import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsfrom sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error, mean_absolute_percentage_errorfrom scada_data_analysis.modules.power_curve_preprocessing import PowerCurveFiltering

数据

数据集在 Kaggle 上公开,并在必要的引用下使用。它由 134 个运行中的涡轮机组成,运行时间超过 245 天,分辨率为 10 分钟。还提供了每个单位的位置数据。数据加载如下:

# Load data
df_scada = pd.read_csv('wtbdata_245days.csv.zip')
df_loc = pd.read_csv('sdwpf_baidukddcup2022_turb_location.csv')

数据探索

让我们通过检查数据集的头部来确保数据被正确读取。

作者图片

作者图片

原始 SCADA 数据包括 470 万行和 13 列。

数据清理

让我们提取相关列,即涡轮机唯一标识(混浊)、天(日)、时间戳(Tmstamp)、风速(Wspd)、风向(Wdir)、机舱方向(Ndir)和功率输出(Patv)。

# Extract desired features
dff_scada = df_scada[['TurbID',  'Day', 'Tmstamp', 'Wspd', 'Wdir', 'Ndir', 'Patv']]

现在,让我们检查丢失的值并删除受影响的行。在移除缺失值之前,数据质量如下所示:

作者图片

由于缺少值,总共只有 1.05%的行被删除,新的数据质量显示如下:

作者图片

接下来,我们创建一个唯一的日期时间字符串,用于根据需要创建变量的时间序列。

dff_scada['date_time'] = dff_scada[['Day', 'Tmstamp']].apply(lambda x: str(x[0]) + 'T' +str(x[1]), axis=1)

数据过滤

原始 SCADA 数据可能相当混乱,需要过滤以提取每个涡轮机的典型操作行为。我们将使用开源的 scada 数据分析库,它有一个功率曲线过滤工具用于这一步。这个库的 GitHub 库可以在这里找到。

作者图片

用于数据过滤的代码和由此产生的干净的 scada 数据如下所示。首先,我们基于领域知识移除虚假数据。

# set parameters
cut_in_Speed = 2.85# Initial filtering of obviously spurious data
ab_ind = dff_scada[(dff_scada['Wspd'] < cut_in_speed) & (dff_scada['Patv'] > 100)].indexnorm_ind = list(set(dff_scada.index).difference(set(ab_ind)))assert len(dff_scada) == len(norm_ind) + len(ab_ind)scada_data = dff_scada.loc[norm_ind, :]

然后,我们使用功率曲线滤波器来去除异常运行数据。

# Instantiate the Power Curve Filter
pc_filter = PowerCurveFiltering(turbine_label='TurbID',                                     
windspeed_label='Wspd', power_label='Patv', data=scada_data, cut_in_speed=cut_in_speed, bin_interval=0.5, z_coeff=1.5, filter_cycle=15, return_fig=False)# Run the data filtering module
cleaned_scada_df, _ = pc_filter.process()

作者图片

清理后的数据有 190 万行,更能代表运行中的风力涡轮机的风速和功率输出之间的预期关系。

现在,我们创建测试数据,用于评估预测缺失值时聚类方法的性能。测试数据是从清理后的数据中随机抽取的,并且具有与原始数据集中相似的流行率(1.05 %)。

作者图片

数据转换

在这一步中,我们为每个期望的变量转换过滤的数据,这使它为聚类分析做好准备。风速的转换数据如下所示:

作者图片

聚类建模

我们希望根据风速、风向、机舱方向和功率输出对涡轮机进行分类。其思想是识别哪组涡轮机可以被认为是相邻的,并用于给定涡轮机的统计表示。

在这个例子中,我们使用 KMeans 算法。最佳聚类数的选择是建立模型的关键,为此采用了流行的肘方法。所有情况下的弯管图如下所示:

作者图片

尽管使用 4 或 5 个聚类也给出了合理的结果,但是基于单个和组合特征选择的聚类的最佳数量是 3。

我们使用 Sklearn 预处理模块中的标准缩放工具来缩放所有特征的输入数据,因为它们具有不同的数量级。

结果

我们创建了一个基于每个变量和所有变量组合的聚类模型,并确定了这些情况下的涡轮机组。结果如下所示:

作者图片

在上面的结果中,风速和风向涡轮机集群显示出相似的模式,其中第一组中的涡轮机位于公园的边缘,这是有意义的,因为两个位置的障碍物水平都降低了,特别是如果主导风向是沿着 X 轴。此外,第 2 组和第 3 组位于公园的中间,横跨柱子(沿 X 轴)。

在功率输出聚类结果中,第 1 组涡轮机位于 X 轴的右侧,边界清晰。第 2 组涡轮机位于公园的中间,沿着 X 轴,而第 3 组涡轮机是最大的一组,主要占据公园的边缘。

机舱方向不同于其他变量,因为它很大程度上取决于应用于涡轮机的偏航逻辑,并且可能在整个现场发生变化。因此,集群没有明确的边界。然而,当结合生产数据时,这种分析可能有助于排除与偏航不对准相关的性能不佳。

使用所有特征组合的聚类结果类似于风速聚类,并显示在文章标题图片中。

基于聚类的缺失值插补方法

这里,我们将探讨两种基于聚类的方法来处理基于风速数据的缺失值,即朴素聚类(NC)和列敏感聚类(CSC)。这两种方法都是作者直观命名的。

朴素聚类

在这种方法中,给定涡轮机的缺失值被涡轮机在期望的时间戳所属的组的平均值(或中值)代替。我们将使用平均聚类值进行分析。

对列敏感的聚类

该方法通过仅取相同组和列中的涡轮机的平均值,扩展了朴素聚类方法。这考虑了涡轮机的地理位置的影响,并且对于诸如风速之类的变量可能尤其更准确。

聚类模型评估

测试数据由 19,940 行组成,包含使用聚类方法预测的缺失风速数据的地面实况。

基于训练聚类数据中的可用数据,简单聚类方法可以填充 99.7%的缺失值,而当聚类被进一步分箱成列时,由于较少的训练数据,列敏感方法只能填充 93.7%。

这两种方法都使用平均绝对误差(MAE)指标进行评估,该指标基于它们可以预测的缺失值。此外,平均绝对百分比误差(MAPE)度量用于评估非零预测。对于这两个指标,模型性能越小越好。

SCS 方法比基于 MAE 和 MAPE 的 NC 方法分别提高了 2%和 8%。但是,它会填充更少的缺失值。因此,两种方法的互补使用将提供更大的好处。

为了对结果进行直观的比较,我们从测试数据中随机抽取了 100 个点,如下所示:

作者图片

接下来,我们设想两种方法的缺失值插补误差。插补误差是地面真实风速值和预测值之间的差值。

作者图片

两种方法都有良好的插补误差,插补误差关于零误差位置是对称的。

结论

在本文中,我们使用不同的单独变量和组合变量执行了基于聚类的 SCADA 数据预处理。此外,我们使用简单的和列敏感的聚类方法预测缺失的风速数据。最后,我们从分析中推断,这两种方法可以互补以获得更大的利益。

我希望你喜欢阅读这篇文章,直到下次。干杯!

什么更有趣?你可以通过我下面的推荐链接订阅 Medium 来获得更多我和其他作者的启发性文章,这也支持我的写作。

https://aolaoye.medium/membership

不要忘了查看在可再生能源领域应用最新数据科学原理的其他故事。

参考文献

周军,陆,徐,肖,苏,吕军军,马,窦,(2022)。SD wpf:2022 年 KDD 杯空间动态风力预测挑战数据集。 arXiv 。https://doi/10.48550/arXiv.2208.04360

风能分析工具箱:迭代功率曲线滤波器

聚类备忘单

原文:https://towardsdatascience/clustering-cheat-sheet-dcf72259abb6

在 11 分钟内你应该知道的关于聚类的所有事情

聚类。作者图片

在本文中,您将找到一个完整的集群备忘单。在 11 分钟内,你将能够知道它是什么,并刷新你对主要算法的记忆。

聚类(也称为聚类分析)是将相似的实例分组到聚类中的任务。更正式地说,聚类是将未标记数据点的群体分组为聚类的任务,其方式是同一聚类中的数据点彼此之间比其他聚类中的数据点更相似。

聚类任务可能是无监督学习中最重要的,因为它有许多应用,例如:

  • 数据分析:一个庞大的数据集往往包含几个大的聚类,分别对其进行分析,可以得出有趣的见解;
  • 异常检测:如前所述,位于低密度区域的数据点可视为异常;
  • 半监督学习:聚类方法通常可以帮助你为分类任务自动标记部分标记的数据;
  • 间接聚类任务(聚类有助于获得良好结果的任务):推荐系统、搜索引擎等。,以及
  • 直接聚类任务:客户细分、图像细分等。

Scikit Learn 的聚类算法。图像来源

所有的聚类算法都需要数据预处理和标准化。大多数聚类算法在大量特征的情况下表现较差,因此有时建议在聚类之前使用维度缩减的方法。

k 均值

K-Means 算法基于质心概念。质心是聚类的几何中心(所有聚类点的坐标的平均值)。首先,随机初始化质心(这是基本选项,但还有其他初始化技术)。之后,当质心移动时,我们迭代执行以下两个步骤:

  • 更新聚类——为每个数据点分配一个质心最近的聚类数,以及
  • 更新聚类的质心 —计算聚类元素的新平均值以移动质心。

K-均值算法的收敛性。公共领域

算法的优点和缺点是直观的。它简单而快速,但需要关于聚类数的初始知识。它也不能很好地检测复杂形状的聚类,并且可能导致局部解决方案。为了选择好的聚类数目,我们可以使用从数据点到聚类质心的距离平方和作为度量,并选择该度量停止快速下降时的数目( 肘方法 )。为了找到全局最优解,可以多次运行算法,选择最佳结果( sklearn 中的n_init参数)。

这个算法的一个加速版本是小批量 K-Means 。在这种情况下,我们使用随机子样本而不是整个数据集进行计算。还有很多其他的修改,很多都是在 sklearn 中实现的。

优点:

  • 简单直观;
  • 扩展到大型数据集;
  • 因此,我们也有质心,可以用来作为标准的集群代表。

缺点:

  • 关于群集数量的知识是必要的,并且必须作为参数来指定;
  • 不能很好地处理大量的特征;
  • 仅很好地分离凸的和均匀的簇;
  • 可能导致较差的本地解决方案,因此需要运行几次。

分层聚类

分层聚类(也称为分层聚类分析(HCA)凝聚聚类)是一系列聚类算法,在分析过程中构建聚类的层次结构。

它被表示为一个树状图(一个树形图)。树的(通常是上部或左侧元素)是一个包含所有数据点的大型集群。(底部或右侧元素)是微小的簇,每个簇只包含一个数据点。根据生成的树状图,你可以选择所需的分离成任意数量的聚类。

iris 数据集上的层次聚类树状图示例。改编自公共领域

这类算法需要计算聚类之间的距离。为此使用了不同的度量标准(简单关联、完全关联、平均关联、质心关联等)。),但其中最有效也最受欢迎的是沃德距离或沃德联动。

要了解更多关于测量聚类之间距离的不同方法,请阅读本文:

https://dataaspirant/hierarchical-clustering-algorithm/#:~:text=creates meaningful clusters.-,Difference ways to measure the distance between two clusters,-There are several

优点:

  • 简单直观;
  • 当数据具有层次结构时效果很好。
  • 不需要知道集群的数量。

缺点:

  • 需要额外的分析来选择聚类的结果数量;
  • 仅很好地分离凸的和均匀的簇;
  • 贪婪算法可能会导致较差的局部解。

谱聚类

谱聚类方法基于图论和线性代数。该算法使用相似度矩阵(包含每对数据点的相似度)的(一组特征值)进行降维。然后它使用这个低维空间中的一些聚类算法(sklearn.cluster.SpectralClustering类使用 K-Means)。

由于维数降低,该算法可以检测复杂的聚类结构和形状。它还可以用于在图形中搜索聚类。然而,由于其计算复杂性,它不能很好地处理大型数据集。

优点:

  • 可以检测复杂的团簇结构和形状;
  • 可用于在图形中搜索聚类。

缺点:

  • 关于群集数量的知识是必要的,并且必须作为参数来指定;
  • 不能很好地处理大量的实例;
  • 当簇的大小非常不同时不能很好地处理。

基于密度的噪声应用空间聚类

DBSCAN 缩写代表带噪声应用的基于密度的空间聚类

根据该算法,聚类是由低密度区域(数据点彼此远离)分隔的高密度区域(数据点彼此靠近)。

DBSCAN 算法的中心概念是一个核心样本的想法,这意味着样本位于一个高密度的区域。如果至少有min_samples个其他实例(通常包括 A )位于距 Aeps距离内,则数据点 A 被视为岩心样本。

DBSCAN 核心样本示例。min_samples=4,核心样本标记为红色。公共领域

因此,聚类是一组彼此靠近的核心样本和一些靠近核心样本的非核心样本。其他样本被定义为异常值(或异常值)并且不属于任何聚类。这种方法被称为基于密度的聚类。它允许您不将簇的数量指定为参数,而是查找复杂形状的簇。

DBSCAN 聚类。公共领域

DBSCAN 算法的扩展或推广是光学算法(排序点以识别聚类结构)。

优点:

  • 关于聚类数量的知识不是必需的;
  • 还解决了异常检测任务。

缺点:

  • 需要选择和调整密度参数(eps);
  • 不能很好地处理稀疏数据。

亲和传播

相似性传播算法也不需要关于聚类数量的知识。但是与 DBSCAN 不同,DBS can 是一种基于密度的聚类算法,相似性传播基于在数据点之间传递消息的思想。基于某个距离函数(即欧几里德距离)计算成对相似性,然后该算法收敛于某个数量的标准代表。然后使用这少量的标准代表来描述数据集,这些代表被识别为特定集群上最具代表性的实例。

Scikit Learn 的仿射传播聚类。图像来源

这种算法的结果常常不尽如人意,但它有许多强大的优势。然而,它的主要缺点是计算复杂性(由于需要计算所有可能的数据点对的距离)不允许它用于大型数据集。

优点:

  • 关于聚类数量的知识不是必需的;
  • 因此,我们也有集群的标准代表
    与 K 均值质心不同,这些实例不仅仅是平均值,而是来自数据集的真实对象。

缺点:

  • 由于计算复杂性,比其他算法慢得多;
  • 不能很好地处理大量的实例;
  • 仅很好地分离凸簇和同质簇。

均值漂移

均值漂移算法首先在每个数据点的中心放置一个一定大小的圆(圆的半径是一个叫做bandwidth的参数)。之后,它迭代计算每个圆的平均 T2(圆内各点的平均坐标)并移动 T4。执行这些均值偏移步骤,直到算法收敛并且圆圈停止移动。

您可以在这里看到均值漂移算法的可视化效果:

均值漂移收敛到密度最大的局部区域。然后所有彼此足够接近的圆形成一个集群。因此,同时解决了密度估计任务,并计算出聚类质心。

与 DBSCAN 一样,该算法代表了一种基于密度的方法,因此在处理稀疏数据时效果不佳。

优点:

  • 关于聚类数量的知识不是必需的;
  • 只有一个超参数:圆的半径*;*
  • 求解密度估计任务并计算聚类质心;
  • 找不到实际不存在的簇结构。

缺点:

  • 不能很好地处理稀疏数据和大量特征;
  • 不能很好地处理大量的实例;
  • 不能很好地处理复杂形状的簇:倾向于将这些簇切成碎片。

桦树

桦树代表使用层次结构的平衡迭代减少和聚类

这种分层聚类算法是专门为大型数据集设计的。在大多数情况下,它的计算复杂度为 O(n) ,因此只需要对数据集进行一次扫描。

在训练期间,它会创建一个包含足够信息的树状图,以便将每个新数据实例快速分配给某个集群,而不必将所有实例的信息存储在内存中。与其他聚类算法相比,这些原则允许为给定的一组内存和时间资源获得最佳质量。它们还允许执行在线学习的增量集群输入数据实例。

优点:

  • 是专门为非常大的数据集设计的;
  • 显示给定的一组内存和时间资源的最佳质量;
  • 允许实现联机群集。

缺点:

  • 不能很好地处理大量的功能。

高斯混合模型

高斯混合模型( GMM )是一种概率算法,可以解决多达三个无监督学习任务:聚类密度估计异常检测

该方法基于期望最大化算法,并假设数据点是从一组(混合)高斯分布中生成的。这种算法会导致较差的局部解,因此需要运行几次,只保留最佳解( sklearn 中的n_init参数)。

众所周知,在一般情况下,高斯分布有两个参数:平均值的向量和方差的矩阵。然后,如果已知数据可以分成M维空间中的N个簇,那么算法的任务就是选择N个μ向量(带有M个元素)和N个σ矩阵(带有MxM个元素)。

在一维空间的情况下,μ和σ都是标量(单个数)。

一维空间中不同参数的高斯(正态)分布。公共领域

在下图中,你可以看到二维空间中的两种分布。每个分布都有以下参数:

  • 平均向量的两个值(x 和 y 坐标);
  • 方差矩阵的四个值(主对角线的方差和其他元素的协方差)。

GMM 的例子。图像来源

为了选择一个好的集群数量,你可以使用 BICAIC (贝叶斯/阿凯克信息标准)作为度量,并选择具有最小值的模型。另一方面,你可以使用贝叶斯 GMM 算法。该模型只需要一个大于可能的聚类数的值,就可以自己检测出最佳的聚类数。

此外,高斯混合模型是一个生成模型,这意味着您可以从中采样新的实例。还可以在任何给定的位置估计模型的密度。

优点:

  • 完美地处理由不同形状和大小的高斯分布混合生成的数据集;
  • 同时解决了密度估计异常检测任务;
  • 是一个创成式模型,所以可以生成新的实例。

缺点:

  • 关于聚类数量的知识是必要的,并且必须被指定为一个参数(不是在贝叶斯 GMM 的情况下);
  • 期望最大化算法会导致局部解不佳,所以需要多次运行;
  • 无法很好地扩展大量功能;
  • 假设数据实例是由混合高斯分布生成的,那么就很难处理其他形状的数据。

如何选择一种聚类算法?

正如您所看到的,聚类任务非常困难,并且有各种各样的应用程序,因此几乎不可能建立一些通用的规则来选择聚类算法—它们都有优点和缺点。

当你对你的数据有一些假设 时,事情会变得更好,所以数据分析可以帮助你。集群的数量大概是多少?它们彼此相距很远还是相交?它们的形状和密度相似吗?所有这些信息可以帮助你更好地解决你的任务。

如果集群的数量未知,一个好的初始近似值是对象数量的平方根。您也可以首先运行一个不需要将集群数量作为参数的算法( DBSCANAffinity Propagation ),并使用结果值作为起点。

另一个重要的问题仍然是质量的评估——你可以尝试所有的算法,但如何决定哪一个是最好的?这方面有很多衡量标准——从同质性完整性轮廓——它们在不同的任务中表现出不同。理解这些指标以及如何成功地使用它们需要经验,这超出了本文的范围。

尽管如此,我还是设法列出并回顾了所有主要的聚类算法和方法。希望这能帮助你并激励你更深入地进行聚类分析。

本文是以下内容的一部分:

您可能还对以下内容感兴趣:

感谢您的阅读!

  • 我希望这些材料对你有用。在媒体上关注我以获得更多类似的文章。
  • 如果您有任何问题或意见,我将很高兴得到任何反馈。在评论里问我,或者通过 LinkedIn 或者 Twitter 联系。
  • 为了支持我作为一名作家,并获得数以千计的其他媒体文章,使用我的推荐链接获得媒体会员资格(不收取额外费用)。

用于主题建模的聚类上下文嵌入

原文:https://towardsdatascience/clustering-contextual-embeddings-for-topic-model-1fb15c45b1bd

通过聚类上下文句子嵌入提取主题

在 Unsplash 上由 Luisa Denu 拍摄的照片

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

我们进行了大量的实验来比较基于聚类的主题模型和传统的神经主题模型(NTMs ),展示了一种从文档中提取主题的替代方法。

查看我们的T5 NAACL 2022论文📄" 神经话题建模比聚类好吗?关于主题和官方 Github 的语境嵌入聚类的实证研究。

范例 1:传统的主题建模

opic 建模是一种无监督的方法,用于提取文档中的语义主题。从传统的潜在狄利克雷分配(LDA)模型到神经网络增强的神经主题模型(NTMs ),主题建模取得了显著的进步。然而,这些主题模型通常采用词袋(BoW)作为文档表示,这限制了模型的性能。

后来,由各种预训练语言模型(如 BERT)产生的上下文化单词和句子嵌入出现,并在多种自然语言处理(NLP)任务中显示出最先进的结果。最近的作品如 CombinedTM 和 ZeroShotTM ⁴将这些情境化的嵌入整合到 NTMs 中,显示出比传统 NTMs 更好的建模性能。

尽管结果很有希望,但是这种 NTM 遭受计算开销,并且当前将预训练的嵌入集成到 NTM 架构中是幼稚的。

有了高质量的上下文化文档表示,我们真的需要复杂的 ntm 来获得连贯和可解释的主题吗?

范例 2:基于聚类的主题建模

相反,我们探索了另一种从文档中建模主题的方法。我们使用一个简单的集群框架和上下文嵌入来进行主题建模,如下所示。

我们方法的架构。图片作者。

我们首先通过预先训练的语言模型对预处理的文档进行编码,以获得情境化的嵌入。之后,在应用聚类方法(例如,K-Means)来分组相似的文档之前,我们降低嵌入(例如,UMAP)的维度。每个群组将被视为一个主题。最后,我们采用加权的方法选择代表词作为主题。降低嵌入维度是可选的,但可以节省运行时间(更多细节见下文)。

这种基于聚类的主题建模范例并不新鲜。 Top2vec ⁵联合提取单词和文档向量,将每个密集区域的质心作为主题向量,n 个最近的单词向量作为主题词; BERTopic ⁶采用类似的方法,但是它使用提出的 c-TF-IDF 来选择每个聚类内的主题词; Sia 等人(2020) ⁷聚类词汇级的单词嵌入,并使用加权和重新排序从每个聚类中获得顶部单词。

然而,上述方法忽略了最近提出的有前途的 NTMs。基于聚类的主题模型的性能还没有与传统的主题模型进行比较。

我们提议的工作

在这里,我们介绍一下我们的 NAACL 2022 论文📄" 神经话题建模比聚类好吗?主题和官方 Github 的语境嵌入聚类实证研究。据我们所知,我们是第一个使用各种基于 transformer 的模型产生的上下文嵌入来与 ntm 进行比较的。此外,我们提出了新的单词选择方法,该方法将全局单词重要性与每个聚类中的本地词频率相结合。

我们以[Health News in Twitter](https://archive.ics.uci.edu/ml/datasets/Health+News+in+Twitter) ⁰数据集(从 UCI 机器学习库中检索)为例,说明 范式 2:基于聚类的主题建模 也能抽取高质量的主题。

1.数据准备

我们首先使用 OCTIS 加载预处理过的数据集:

文档被标记化,给出了 3929 个预处理的句子:

**length of documents: 3929
preprocessed documents: [
  'breast cancer risk test devised',
  'workload harming care bma poll',
  'short people heart risk greater',
  'new approach hiv promising',
  'coalition undermined nhs doctors',
  'review case nhs manager',
  'day empty going',
  'overhaul needed end life care',
  'care dying needs overhaul',
  'nhs labour tory key policies',
  ...
]**

2.把…嵌入

其次,我们需要将这些文档转换成矢量表示。我们可以使用任何嵌入,这里,我们使用来自 SimCSE 的预训练princeton-nlp/unsup-simcse-bert-base-uncased嵌入。

3.减少和集群嵌入

现在,我们有了文档的嵌入表示,我们可以通过应用聚类方法将相似的文档分组在一起。减小嵌入大小可以有效地节省运行时间。

4.从聚类中选择主题词

最后,我们可以应用加权方法从每个聚类中选择主题词:

推特中健康新闻设置 5 个话题时的评价是:

**num_topics: 5 td: 1.0 npmi: 0.106 cv: 0.812**

示例主题包括:

**Topic:
0: ['nhs', 'amp', 'care', 'hospital', 'health', 'mental']
1: ['ebola', 'vaccine', 'flu', 'liberia', 'leone', 'virus']
2: ['dementia', 'obesity', 'alzheimer', 'diabetes', 'brain', 'disabled']
3: ['cancer', 'heart', 'breast', 'surgery', 'transplant', 'lung']
4: ['cigarette', 'cigarettes', 'pollution', 'smoking', 'sugar', 'drug']**

我们可以看到 范式 2:基于聚类的主题建模 发现的主题也可以是高度连贯和多样的,虽然文档的长度相对较短。尽管所有话题都是关于健康的,但我们可以区分话题 1 是关于传染性病毒和疾病的,话题 2 是关于疾病症状的,等等。

为了进行比较,我们还使用 CombinedTM ,一个 范例 1:基于常规主题建模 的模型来提取 Twitter 数据集中相同的健康新闻。我们使用相同的princeton-nlp/unsup-simcse-bert-base-uncased嵌入。

对推特中健康新闻的评价在设置 5 个话题时分别是:

**num_topics: 5 td: 1.0 npmi: -0.267 cv: 0.401**

示例主题包括:

**Topic:
0: ['cancer', 'amp', 'drug', 'death', 'audio', 'test']
1: ['food', 'obesity', 'cigarette', 'smokers', 'link', 'smoking']
2: ['ebola', 'mers', 'liberia', 'vaccine', 'malaria', 'virus']
3: ['babies', 'brain', 'sperm', 'man', 'human', 'cell']
4: ['nhs', 'health', 'mental', 'care', 'staff', 'hospital']**

我们可以看到,一些主题是不连贯的,例如,主题 0 和 3。

我们总结了基于聚类的主题建模的发现。

直接聚类高质量的嵌入可以产生好的主题。

实验表明,高质量的嵌入对于基于聚类的主题建模至关重要。我们实验了不同的嵌入,包括伯特、罗伯塔 ⁸、辛姆塞 ⁹等。,基于三个不同长度的数据集。对 RoBERTa 进行聚类得到的结果与上下文化的 ntm 相似或更差,这表明嵌入质量很重要。

最近的 DiffCSE 在某些数据集上可以达到略高的性能!

前 10 个词的主题连贯性(NPMI 和 CV)和主题多样性(TU)的不同嵌入。图片由纸

选词方法至关重要。

一旦我们有了一组聚类的文档,选择有代表性的主题词对于识别主题的语义是至关重要的。与以前提出的方法不同,我们捕获每个聚类中的全局词重要性和本地词频率,并比较 4 种不同的方法:

图片作者。

图片作者。

图片作者。

图片作者。

我们发现,在所有方法中,TFTDF × IDFᵢ取得了明显更好的结果。这表明 TFIDF 标记出整个语料库中每个文档的重要单词,而 IDFᵢ惩罚多个簇中的常见单词。相反,其他三种方法忽略了一个聚类中的频繁词也可能在其他聚类中流行,因此选择这样的词导致低主题多样性。

不同主题词选择方法的比较。图片由论文

嵌入维度对主题质量的影响可以忽略不计。

在聚类之前,我们应用 UMAP 来降低句子嵌入的维数。我们发现,在聚类之前降低维数对性能的影响可以忽略不计,但可以节省运行时间。

用法示例

如 Github 中所述,你可以从[tfidf_idfi, tfidf_tfi, tfidfi, tfi]中选择一种选词方法。如果您不想使用 UMAP 减少嵌入维数,只需设置dim_size=-1。您可以训练模型,并获得评估结果和主题:

预期的输出应该类似于:

结论

在这篇文章中,我们介绍了一种基于聚类的方法,只要使用高质量的上下文嵌入,就可以产生值得称赞的主题,以及一种合适的主题词选择方法。与神经主题模型相比,
基于聚类的模型更加简单、高效,并且对各种文档长度和主题数量更加鲁棒,这可以作为一种替代方案
应用于某些情况。

[1]:大卫·M·布雷,安德鲁·吴和迈克尔一世·乔丹。2003.潜在狄利克雷分配。机器学习研究杂志,3:993–1022。

[2]: Devlin,j .,Chang,M.W .,Lee,k .和 Toutanova,k .,2018。Bert:用于语言理解的深度双向转换器的预训练。 arXiv 预印本 arXiv:1810.04805

[3]:比安奇,女,特拉尼,s 和霍维,d,2020。预训练是一个热门话题:语境化的文档嵌入提高了主题的连贯性。arXiv 预印本 arXiv:2004.03974 。

[4]:比安奇,f .,特拉尼,s .,霍维,d .,诺扎,d .,费尔西尼,e .,2020。零镜头学习的跨语言语境化主题模型。arXiv 预印本 arXiv:2004.07737 。

[5]:安杰洛夫特区,2020 年。Top2vec:主题的分布式表示。 arXiv 预印本 arXiv:2008.09470

[6]:格罗腾多斯特,m,2022。BERTopic:使用基于类的 TF-IDF 过程的神经主题建模。 arXiv 预印本 arXiv:2203.05794

[7]: Sia,s .,Dalmia,a .和 Mielke,S.J .,2020。厌倦了话题模型?预先训练的单词嵌入集群也是快速和良好的主题!。arXiv 预印本 arXiv:2004.14914 。

[8]:刘,y .,奥特,m .,戈亚尔,n .,杜,j .,乔希,m .,陈,d .,列维,o .,刘易斯,m .,泽特勒莫耶,l .,斯托扬诺夫,v .,2019。Roberta:稳健优化的 bert 预训练方法。 arXiv 预印本 arXiv:1907.11692

[9]:高,汤,姚,陈,2021。Simcse:句子嵌入的简单对比学习。 arXiv 预印本 arXiv:2104.08821

[10]:卡拉米,a .,甘戈帕迪亚,a .,周,b .,&哈拉齐,H. (2017)。健康和医学语料库中的模糊方法主题发现。国际模糊系统杂志,1–12。

[11]: Dua,d .和 Graff,C. (2019)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。

[12]:张,z,方,m,陈,l .,&纳马齐-拉德,M. R. (2022)。神经主题建模比聚类好吗?基于主题上下文嵌入的聚类实证研究。 arXiv 预印本 arXiv:2204.09874

混合数据类型上的聚类

原文:https://towardsdatascience/clustering-on-mixed-data-types-5fe226f9d9ca

利用高尔相和 HDBSCAN

资料来源:Unsplash。

聚类是一种无监督的机器学习技术,旨在将相似的数据点分组到不同的子组中。通常,用于这种分组的距离度量对于数值数据是欧几里德距离,对于分类数据是雅克卡距离。大多数聚类算法也是为数字或分类数据显式设计的,但不是同时为两者设计的。在本文中,我将概述一种通过利用一种称为高尔相异度的距离度量来对混合数据进行聚类的方法。虽然各种聚类算法可以将预先计算的距离度量作为输入,但我将使用 HDBSCAN,因为它对异常值具有鲁棒性,并且能够识别有噪声的数据点。

数据集和预处理

为了说明,我使用公开可用的泰坦尼克号测试数据集。高基数要素(主要是每个乘客独有的要素,如 PassengerIdNameCabin )以及任何包含 nan 的行和包含超过 50% nan 的列都已从数据集中移除。为了简单和更好的可视化,只使用了 30%数据的随机部分。

预处理的 Titanic 测试数据集的随机样本。

高尔不同

高尔相异度( GD ) 是表示两个样本差异程度的度量。度量范围从 0 到 1,0 表示无差异,1 表示最大差异。它是基于任意两个样本的部分相似性来计算的。部分相似性( ps )根据数据类型是数值型还是分类型进行不同的计算。对于分类数据,如果值相同,ps = 1,如果值不同,ps = 0。对于数值数据, ps 计算如下:

首先,确定特征列的范围。

第二, ps 是对数据中任意两个样本计算的。

第三,高尔相似度( GS )是通过取所有部分相似度的算术平均值来计算的。

最后,通过从 1 中减去相似性度量( GS )来将其转换成距离度量( GD )。

视觉插图

为了更好地说明,让我们再次查看预处理数据的前五行:

预处理的 Titanic 测试数据集的随机样本。

查看第 0 行和第 3 行,人们会立即意识到这两行非常相似,只有在年龄费用上略有不同。因此,我们预计 GD 会非常低(接近于零)。其实准确的 GD 是 0.0092(见下图)。更不相似的样本,如第 0 行和第 2 行,具有更大的距离值,在本例中为 0.24。

上面概述的样本的相应高尔距离矩阵。

我们整个预处理数据集的 GD 矩阵如下所示:

整个预处理测试数据集的高尔距离矩阵。

使聚集

作为聚类算法,我选择了 HDBSCAN (针对有噪声的应用的基于层次密度的空间聚类)。HDBSCAN 擅长识别高密度集群,计算效率高,对异常值具有鲁棒性。

设置了两个参数来运行 HDBSCAN。影响聚类结果的主要参数是最小聚类大小。这是指被视为一个组或簇的最小数量的数据点。可以设置一个附加参数 min_samples 来控制分类为噪声的数据。该值越低,归类为噪声的数据点就越少。在该示例中,最小聚类大小被设置为 6,而最小样本数被设置为 1。

这些参数可以使用集群质量度量进一步调整,例如基于密度的集群验证(DBCV) 分数。然而,为了简洁起见,本文省略了这一点。

形象化

为了可视化结果,应用了 2D t 分布随机邻居嵌入 (t-SNE)投影。

HDBSCAN 输出 6 个不同的簇和一个被视为噪声的簇(暗红色)。

让我们通过可视化其中一些集群的值来看看这些分组的质量。

紫色集群

组成紫色集群的数据点样本。

黄色集群

组成黄色聚类的数据点样本。

绿色集群

组成绿色聚类的数据点样本。

噪声集群

正如所料,归类为噪声的样本彼此非常不同:

组成噪声群的数据点的样本。

结论

在本文中,我演示了如何对混合类型的数据进行聚类,方法是首先计算高尔距离矩阵,然后将其输入 HDBSCAN。结果表明,对于所使用的数据,该方法在将相似的数据点分组在一起方面表现得相当好。然而,这不是一个适用于所有混合数据类型的通用方法,最终使用的方法将取决于手头的数据。例如,HDBSCAN 要求集群内的密度一致,集群之间的密度下降。如果没有,就需要考虑其他方法。

如何利用机器学习自动检测文本中的模式

原文:https://towardsdatascience/clustering-text-with-k-means-c2953c8a9772

用 k-Means 聚类葡萄酒评论

Maksym Kaharlytskyi 在 Unsplash 上的照片

什么文本聚类?

在上一篇文章中,我们谈到了主题建模或者从文档语料库中识别几个主题的方法。这里使用的方法是潜在的狄利克雷分配或 LDA。在本文中,我们将执行类似的任务,但通过无监督的机器学习方法聚类。虽然方法不同,但结果是几组(或主题)彼此相关的单词。

对于这个例子,我们将使用来自 Kaggle 的葡萄酒评论数据集。它包含了超过 100,000 种不同的全球葡萄酒评论。作为品尝笔记的葡萄酒描述是基于文本的变量,我们将使用它来聚类和解释结果。

从导入所需的库开始。

:这里不打算展示文本的预处理。你可以在 GitHub 上看到完整的代码。还有一篇关于文字清理的完整文章可以参考。

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

文本矢量化

向量化文本是将文本文档转换成数字表示的过程。这有不同的版本,例如单词袋** (BoW),以及术语频率-逆文档频率 (TF-IDF),我们将在这里使用。**

  • BoW 或 TF :表示每个文档中每个单词的计数。在这种情况下,文档记录了我们所针对的列的数据集中的观察结果。
  • TF-IDF :它不是只计算单词的数量,而是反过来,给那些出现频率较低的单词更高的权重。常见单词具有较低的权重,而可能更特定于领域且出现较少的单词将具有较高的权重。

创建 TF-IDF ,创建矢量器的一个实例,然后fit-transform数据框的列是非常容易的。

vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(df['description_clean'])

确定最佳聚类数

我上面提到聚类是一种无监督的机器学习方法。无监督意味着我们的数据集中没有告诉我们正确答案的信息;这通常被称为标记数据。在我们的例子中,我们不知道文本中有多少不同类型的酒或不同的主题。然而,仅仅因为我们不知道这些信息,并不意味着我们不能找到正确的集群数。

有了聚类,我们需要初始化几个聚类中心。这个数字被输入到模型中,然后在结果输出后,具有数据知识的人可以解释这些结果。然而,有一些方法可以评估哪一个是正确的聚类中心数量,我将介绍两种常用的方法。

肘法

第一种称为肘法。该名称源自运行此分析后的图形外观。理想情况下,我们在寻找曲线开始变平的点。这种方法使用inertia来确定簇的数量。惯性是从每个点到聚类中心的距离的平方的总和。我们可以对一系列不同的聚类值进行计算,绘制它们,并寻找弯头

Sum_of_squared_distances = []
K = range(1,10)
for k in K:
    km = KMeans(init="k-means++", n_clusters=k)
    km = km.fit(X)
    Sum_of_squared_distances.append(km.inertia_)

ax = sns.lineplot(x=K, y=Sum_of_squared_distances)
ax.lines[0].set_linestyle("--")

# Add a vertical line to show the optimum number of clusters
plt.axvline(2, color='#F26457', linestyle=':')

plt.xlabel('k')
plt.ylabel('Sum of Squared Distances')
plt.title('Elbow Method For Optimal k')
plt.show()

在绘制数据后,肘形并不明显,但最佳近似是在 2 个集群处,我们在曲线中看到一个轻微扭结。我画了一条垂直线来识别它。

作者图片

剪影分数

另一种计算最佳聚类中心的方法是轮廓系数。使用每个样本的平均聚类内距离和平均最近聚类距离来计算轮廓系数。换句话说,样本和样本不属于的最近聚类之间的距离。

最好的值是1,最差的是-10附近的值表示重叠的簇。负值通常表示样本被分配到了错误的分类,因为不同的分类与其被分配的分类更相似。让我们也为不同的聚类中心值计算这些分数。

def get_silhouette_score(X, k):
    for n_clusters in range(2, k):
        clusterer = KMeans(init="k-means++", n_clusters=n_clusters, random_state=42)
        y = clusterer.fit_predict(X)

        message = "For n_clusters = {} The average score is: {}"
        print(message.format(n_clusters, silhouette_score(X, y)))

get_silhouette_score(X, 10)
For n_clusters = 2 The average score is: 0.00821919113279018
For n_clusters = 3 The average score is: 0.006522933295313797
For n_clusters = 4 The average score is: 0.006237960319271207
For n_clusters = 5 The average score is: 0.006266850309331783
For n_clusters = 6 The average score is: 0.006381665959703946
For n_clusters = 7 The average score is: 0.005549433908077499
For n_clusters = 8 The average score is: 0.005962146586290015
For n_clusters = 9 The average score is: 0.00632540099660495

根据定义,最接近1的数字是最好的,在我们的例子中是2簇。但是,这些值接近于零,这意味着我们的聚类有很高的重叠。

虽然这两种方法都不能让我们理想地了解集群的数量,但是我们应该使用,两者都指向2作为最佳值。

k-均值聚类

好吧!我们准备好构建模型并检查结果。这个过程非常简单,我们将重复上面所做的大部分工作,但是只对我们选择的集群数量进行一次运行。

对于这个例子,我们将使用 k-Means。k-Means 是最常见的聚类算法之一,如果不是最常见的话。通常,k-Means 会随机初始化聚类中心,然后迭代,直到找到理想的位置。指定init="k-means++"意味着我们将使用 k-means++算法来初始化集群中心,这是 2007 年提出的一种减少随机初始化问题的方法。首先,我建议使用这个工具,并稍微阅读一下它是如何工作的。

# Set the number of clusters
k = 2
# Vectorize the text
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(df['description_clean'])
# Fit our Model
model = KMeans(init="k-means++", n_clusters=k, max_iter=25, n_init=1)
model.fit(X)

您可以将聚类分配保存为数据框中的新列,其中包含聚类编号,以供将来参考。

# Get the cluster labels
clust_labels = model.predict(X)
cent = model.cluster_centers_

kmeans_labels = pd.DataFrame(clust_labels)
df.insert((df.shape[1]),'clusters',kmeans_labels)

最后,让我们构建一个快速数据框,显示两个集群中的前15个单词,看看我们得到了什么。

order_centroids = model.cluster_centers_.argsort()[:, ::-1]
terms = vectorizer.get_feature_names_out()

results_dict = {}

for i in range(k):
    terms_list = []

    for ind in order_centroids[i, :15]:  
        terms_list.append(terms[ind])

    results_dict[f'Cluster {i}'] = terms_list

df_clusters = pd.DataFrame.from_dict(results_dict)
df_clusters
Cluster 0   Cluster 1
0   pineapple      cherry
1      flavor      flavor
2     acidity         dry
3     vanilla  blackberry
4       fruit      tannin
5         oak        cola
6       crisp   raspberry
7        pear     currant
8       apple        good
9       peach        rich
10       lime        soft
11     butter       spice
12      toast        show
13      sweet         oak
14      lemon       sweet

看看集群0,我们看到的单词通常与酒相关,集群1酒相关。

预测新文档

接下来,我们可以看到该模型如何对过去没有的新葡萄酒评论进行聚类。我用白葡萄酒和红葡萄酒可能与之相关的词造了几个句子。

new_docs = ['Rich deep color of oak and chocolate.',
            'Light and crisp with a hint of vanilla.',
            'Hints of citrus and melon.',
            'Dark raspberry and black cherry flavors.']

pred = model.predict(vectorizer.transform(new_docs))
print(pred)
[1 0 0 1]

正如我们所料,红酒被归类为1,白酒被归类为0!你可以试试其他的弦,看看它的表现如何。

结论

第一次在这个数据集上执行聚类时,我真的被震惊了。显而易见,通过2聚类,算法可以识别和聚类红葡萄酒和白葡萄酒。这感觉有点像魔术,但最终,这只是数学!享受这个过程。它功能强大,可以帮助你识别文本中相关的主题组!

如果你喜欢阅读这样的故事,并想支持我成为一名作家,可以考虑报名成为一名媒体成员。一个月 5 美元,让你可以无限制地访问成千上万篇文章。如果你使用我的链接注册,我会赚一小笔佣金,不需要你额外付费。

CLVTools:评估客户的强大 R 包

原文:https://towardsdatascience/clvtools-a-powerful-r-package-to-evaluate-your-customers-4fd1781811d

客户的终生价值对企业来说是一种无价的战略工具

包装使用说明。来源:作者。

在这篇与 Patrick Bachmann 共同撰写的文章中,我们浏览了广泛的 R 包“CLVTools”,其中包括一些最知名的模型的便捷实现,以估计客户终身价值(CLV 或 LTV,这里以为例介绍)。这篇文章是基于在找到的这个包的相当详细的预排。还有一个(更老的)youtube 视频提供了进一步的解释。

我们将主要关注 ParetoNBD 模型及其扩展,在关于 LTV 的文献中,它被视为一种黄金标准。该模型假设交易以所谓的“泊松过程”发生,并且客户是(I)异质的,(ii)可以在任何时间购买,以及(iii)可以在任何时间结束他们与公司的关系。情况(iii)被认为是永久性的,一旦你失去了一个客户,他们就不会回来了。因此,除了交易或泊松过程之外,一个单独的过程被建模来表示客户的“生命周期”。这是这类模型中的一个典型主题,因此人们通常将事务过程和生命周期或损耗过程区分开来。

因为这个模型有点复杂,它的表亲 BG-NBD 模型经常被考虑,例如在这个帖子中。不同之处在于,BG-NBD 模型在本质上更加离散——特别是,客户只能在交易后直接变得不活跃(而在帕雷顿 BD 模型中,他们可以在任何时候变得不活跃)。这在某些情况下可能是可取的,但在(许多)其他情况下就不那么可取了。

CLVTools 中包含的模型概述。来源:经过作者许可,此处的演练。

关于模型本身已经说得够多了,我们如何将它们与 CLVTools 结合使用呢?使用软件包进行成功的分析通常需要遵循 3 个步骤:

  1. 创建“clv.data”对象,其中包含数据集和所需的元信息(使用的日期格式、列名等)。初始化之后,可以添加更多关于潜在协变量的信息。
  2. 符合模型。
  3. 使用估计的模型参数进行分析,即绘制、预测客户行为等。

上图也说明了这一点。我们现在用一个示例数据集来完成这些步骤。

第一步:初始化

library(CLVTools)
data("apparelTrans")
data("apparelDynCov")

我们使用包装中的“apparelTrans”数据,如下所示。这个截屏很重要,因为它显示了该包所需的数据格式:每个客户应该有一个唯一的 Id 号、交易日期(以某种给定的格式,如 YYYY-MM-DD )和交易价格。

交易数据。来源:作者。

此外,我们假设客户的协变量(即属性)存储在“apparelDyncov”中。特别是公司知道客户的性别和他们的获取渠道(“线下”=0 或“线上”=1)。这些是静态协变量,这意味着它们可能因人而异,但随着时间的推移是恒定的。然而,也有“营销”,这表明有多少直接营销尝试在一个单一的客户。这是一个时变协变量,这意味着它不仅会因客户而异,还会随时间而变。软件包中只有一个(非常新的)模型目前能够处理这种时变结构,扩展的 ParetoNBD 模型在这里开发,我们将充分利用这一点。

所有客户的附加协变量。来源:作者。

现在,我们采取必要的第一步,用“clvdata”命令将这些数据引入到包中,这将产生一个对象,第二步和第三步的所有函数都可以轻松地处理该对象。在这个命令中,我们需要指定数据集、我们使用的日期格式(如在“lubridate”R 包中)、时间单位以及何时(或是否)应该将数据划分为估计和验证周期。最后,我们需要指定 id、日期和价格的列名。

clv.apparel <- clvdata(apparelTrans,
                       date.format = "ymd",
                       time.unit= "week",
                       estimation.split=40,
                       name.id="Id",
                       name.date="Date",
                       name.price="Price")

这里可以看到摘要输出:

clv.apparel 对象的摘要输出。来源:作者。

第二步:评估

我们现在可以估计我们的上述对象的模型。有了默认选择,没有协变量,这就简单了:

## Estimate the PNBD model
est.pnbd<- pnbd(clv.data=clv.apparel)
## Estimate the BGNBD model
est.bgnbd <- bgnbd(clv.data=clv.apparel)

另一方面,对于(时变)协变量,我们需要指定更多:特别是,我们需要指定生存期或损耗过程(data.cov.life)和事务过程(data.cov.trans)的协变量数据。此外,我们需要在 names.cov.life 和 names.cov.trans 中给出这两个进程的名称。

clv.dyn <- SetDynamicCovariates(clv.data=clv.apparel,
                                data.cov.life = apparelDynCov,
                                data.cov.trans = apparelDynCov,
                                names.cov.life = c("Marketing", "Gender", "Channel"),
                                names.cov.trans = c("Marketing", Gender", "Channel"),
                                name.id = "Id",
                                name.date = "Cov.Date")
# Estimate the PNBD with Covariates (This takes a while (!))
est.pnbd.dyn <- pnbd(clv.dyn)

然后,我们可以首先检查这些模型的汇总输出。该输出类似于简单线性回归:给出了标准误差以及参数的显著性值,此外,还提供了关于优化收敛的信息,如最终似然值。请注意“est.pnbd.dyn”比 est.pnbd 多了 6 个参数。这对应于交易和流失流程的 3 个协变量(“性别”、“渠道”、“营销”)中每一个的一个协变量值。我们也可以利用这一点,限制协变量只影响两个过程中的一个,或者用相同的参数影响两个过程。

ParetoNBD 模型的摘要输出。来源:作者。

BG-NBD 模型的概要输出。来源:作者。

有协变量的 ParetoNBD 模型的汇总输出。来源:作者。

有趣的是,该模型暗示了直接营销努力的不同效果(假设因果解释是可能的):它似乎增加了交易频率(trans。营销是正面的),但对一个客户的平均寿命(寿命)有负面影响。营销是负面的)。这可能意味着直接营销可能会在短期内促进销售,但会增加客户提前离开公司的机会。像往常一样,人们必须小心这种因果关系的陈述,但该模型至少提供了对影响的暗示(上面链接的原始论文详细解释了如何使用工具变量(iv)等恢复因果关系)。).

但是干输出已经足够了,让我们做一些绘图。检查样本内拟合的一个有趣的图是“跟踪图”,通常在这种情况下完成。

ParetoNBD 中所有客户的重复交易次数的预测值与实际值。来源:作者。

BG-NBD 预测的与实际的所有客户的重复交易数量。来源:作者。

对于有协变量的 ParetoNBD,所有客户的重复交易的预测数与实际数。来源:作者。

BG-NBD 和 ParetoNBD 图看起来非常相似:它们很好地穿越了不稳定的交易,似乎也很好地捕捉到了均值。对于时变协变量,这变得更加有趣,我们突然能够匹配一些起初看起来随机的模式。这就是设计良好的时变协变量所能带来的优势。事实上,加上单独的,但时间不变的协变量,单独的预测有时可以大大改善,超出了这个聚合图中可见的。除了大量经典模型和极快且优雅的实现,这才是 CLVTools 真正与众不同的地方。

但最终我们感兴趣的是预测而不是良好的样本内拟合。让我们开始吧:

第三步:预测

从代码的角度来看,这也是非常简单的(如果我们使用默认值):

predict(est.pnbd)
predict(est.bgnbd)
predict(est.pnbd.dyn)

不幸的是,这里没有什么华而不实的东西可以展示,只有方便的表格给出了不同模型的所有预测(我们在这里省略了 est.bgnbd):

PartoNBD 模型的预测表:来源:作者。

有协变量的 PartoNBD 模型预测表:来源:作者。

这里要提到一件奇怪的事情:虽然 ParetoNBD 和 BG-NBD 可以预测交易的预期数量(“CET”)和客户仍然留在公司的概率(“PAlive”),但他们无法独自模拟支出过程。为此,模型的输出通常与用于支出的伽马-伽马(GG)模型相结合。这模拟了消费过程,当我们要求预测时,它会自动拟合,这就是红色部分。这不仅会导致预测的平均支出,还会导致我们期望的预测客户终身价值。每个 ID 在表格的最后一列给出。

这些预测可以用于更明智的商业决策。例如,关注 Id 为 100 和 1000 的客户可能是明智的,因为他们的 LTV 估计相当高。然而,给定参数估计,在这个例子中不清楚直接营销是否是可行的方法:至少有一个暗示,直接营销可以减少顾客在公司停留的平均时间。

结论

本文简要介绍了用于客户价值建模的 CLVTools 包。该软件包具有广泛的功能和优势,我们不可能在一篇文章中涵盖,但我们希望它能帮助感兴趣的读者开始使用该软件包并使用它做有用的事情。

美国二氧化碳排放数据集:使用 Python 的统计分析

原文:https://towardsdatascience/co2-emissions-dataset-in-usa-a-statistical-analysis-using-python-e8f2ab8eb78f

从二氧化碳排放数据集中提取信息

Marek Piwnicki 在 Unsplash 上的照片

免责声明:**这个笔记本不是由气候科学家写的!**一切都由数据科学家的观点独家分析。所有的统计分析都是用来作为任何一种时间序列分析的工具。

让我们从陈述显而易见的事实开始:

数据科学家的工作是提取洞察力。

你正在使用的工具的复杂性并不真正相关。更重要的是,无论你使用什么,对你想要研究的分析都是有用的。

1.介绍

在我们的例子中,我们有一个时间序列。这一时间序列当然在 x 轴(特别是*记录)上有时间,在 y 轴上有 上有美国燃煤发电产生的二氧化碳排放量。*

这个数据集是公开的,没有任何版权限制( CC0:公共领域)。可以免费下载,在 Kaggle 上,这里。

让我们来看看。首先,让我们导入库:

然后,让我们绘制时间序列(最后 7 个条目是 2016 年的,但这是一个截断的年份,所以我们将其截断);

第一个数据点是 1973 年的第一个月,最后一个数据点是 2015 年的最后一年。没有缺失值,因此数据集的长度正好是 12x(2015–1973)。

现在,什么样的分析与本案相关?嗯,我认为提出三个问题是很自然的:

a . CO2 排放量是否普遍增加?大趋势是什么?

B .这个 CO2 时间序列有没有什么重现的模式?

C .时间序列是“稳定的”还是我们可以期待不愉快的惊喜?

让我们调查一下,一步一步来:

2.一般趋势

我们感兴趣的是描绘这个时间序列的总体趋势。这并不是一种真正的回归技术,因为我们使用的是整个时间序列,这也不是一项真正的预测任务,因为……因为我们根本不是在预测的😃**

这只是趋势的一个侧面,以一种通用的方式对时间序列建模是有用的。如果你真的想拥有预测能力,使用更复杂的回归技术和/或将数据集分成训练集和测试集,可以很容易地改变代码,但这不是我们现在的情况。

我们对模型的预期是,从起点到峰值会有一个巨大的增长(x3 ),然后回到更合理的值,这个值仍然在初始值的 x2 附近。

使用至少三阶模型(它看起来不像抛物线,并且它肯定不是线:D)可以获得合理的模型(不太复杂,不太有损耗)。在我看来,degree = 4 更好,因为它捕捉到了更多的细节,但实际上并没有太大的区别。(同样,如果您想对此更加稳健,请对数据集的较小部分使用以下方法,并使用验证集来挑选误差最低的模型)。

所以我们来拟合一下四度模型。两步走:

A .拟合:

B .预测+绘图:

这看起来和我们预期的一模一样:

  1. 单调增加,直到 2002 年左右
  2. 从 2002 年到 2015 年单调(快得多)下降

我们没有更多关于具体数据来源的信息,但我们可以说,在长时间的增加后,排放量有所减少。增加看起来比减少更渐进(甚至可能更自然,与工厂的节奏有关),也更慢。一种猜测可能是,在达到排放的危险值后,有人故意开始减少排放(可能有某种规定)(我不太清楚,只是一种似是而非的猜测)。

3.循环模式

我们在前一章所做的考虑很有趣,但是不应该妨碍我们接下来要做的事情:让我们去趋势我们的时间序列。

现在看起来是这样的:

现在,正如你们所看到的,《泰晤士报》非常活跃。让我们用一个非常强大的工具来分析这种起伏:神奇的傅立叶变换。

我❤傅里叶变换,我已经用了很多次了。特别是,我在几篇博客文章前在这里谈到过它。在那里,你可以找到傅立叶变换的概念,为什么它是有用的,希望你会像我一样喜欢它:)

让我们准备数据:

让我们画出傅立叶变换(振幅对周期,以月为单位)

为了清楚起见,让我转贴这张图片:

作者图片

这个其实很有意思。为了简洁起见,让我们考虑一下, y 轴上的每一次选择都是一个循环模式,在正好 M 个月之后被周期性地验证,其中 M 是相对于该选择的 x 轴值。

一些重要的趋势得到了证实:

  1. 大约 2.5 个月后
  2. 三个月后
  3. 4 个月后
  4. 半年后
  5. 整整一年后

同样,我们也不知道,但看起来二氧化碳排放确实与雇主的休假时间有关**:通常他们在 6 个月或 12 年后休假,这是最显著的峰值。另一个提示是 2.5/3/4 个月的高峰期,因为不是所有的雇主都在准确的时间休息。**

现在看起来很明显,等你意识到才明显:)

4.稳定性

为了理解时间序列的稳定性,我们可以做如下(合理的)假设:

时间序列是被一些高斯和白噪声“扰乱”的物理过程的结果

我是一个物理学家,这是我们的黄油和面包。这就是我们处理每一个问题的方式,并且有大量的关于误差“高斯性”的统计考虑。现在,让我们接受它,继续前进,就像你应该分手一样:)

预测物理过程产生的平均值并找到数据集的不确定性的一种非常有效的方法是使用著名的高斯过程回归器(GPR)。这是另一个我非常喜欢的工具,因为它是可解释的、足够通用的并且易于使用。我也在多个博客中谈论它(比如这里的和这里的和和)。简而言之,GPR 模型给你一个平均值和一个方差(+1.96 方差意味着在该区域找到点的概率为 95.7%)。这听起来可能令人困惑,让我们慢一点。****

让我们考虑 60%的数据点作为训练集。

让我们在训练集上拟合 GPR 模型,并在整个数据集上应用拟合的模型。通过这最后一步,我们将有一个预测的时间序列,根据“平均”值及其相对不确定性。让我展示给你看:

它看起来有点乱,但实际上做得很好:

现在,为了看看它是否“稳定”,我们可以调查有多少点落在预测的边界之外。

结果如下:

再一次,为了清晰起见,让我给你看一下情节:

作者图片

这意味着:

  1. 从 1973 年到 1983 年只有两个点在边界之外
  2. ****1983 年至 1993 年 7 点越界
  3. 从 1993 年到 2003 年有 8 个点超出界限
  4. ****7 分2003-2013 年越界

这意味着,从 1983 年开始,时间序列的行为变得更加不规则。但是还有!时间序列应该适应行为的变化,不确定性应该增加。这意味着,即使不确定性增加,仍然有很多点超出边界:时间序列的不稳定性不断增加。它实际上是首先通过查看时间序列就可以看到的东西。

5.结论

一些要点:

  1. 经过几十年的增长,二氧化碳的排放量似乎已经开始下降了
  2. 二氧化碳排放可能与雇主的休假时间有关,或者至少与公司的生产节奏有关
  3. 时间序列越来越不稳定,在第一个十年的数据后,不稳定性发生了很大的变化

如果你喜欢这篇文章,你想知道更多关于机器学习的知识,或者你只是想问我一些你可以问的问题:

A.在 Linkedin 上关注我,我在那里发布我所有的故事
B .订阅我的 简讯 。这会让你了解新的故事,并给你机会发短信给我,让我收到你所有的更正或疑问。
C .成为 推荐会员 ,这样你就不会有任何“本月最大故事数量”,你可以阅读我(以及数千名其他机器学习和数据科学顶级作家)写的任何关于现有最新技术的文章。

Python 中的二氧化碳排放信息图

原文:https://towardsdatascience/co2-emissions-infographics-in-python-369dd968eb84

如何用 Python 和 Matplotlib 构建数据信息图

从国际空间站看到的地球 NASA 提供的公开图片https://www . NASA . gov/mission _ pages/station/images/index . html

信息图这个词被用来描述各种可爱的图片,这些图片上有卡通人物和指向各处的箭头。

但是这里我们谈论的是传达数据信息的图形,这些数据可能会在报告或报纸文章中使用。从本质上来说,它们是一种有吸引力的数据呈现方式,带有支持性的图表和文本。

所以,让我们想象一下,我们要写一篇关于我们的大气状况和导致气候变化的二氧化碳水平的报告或文章。

我们将通过创建两个信息图表来告诉我们的读者大气中二氧化碳的水平,在过去和现在。

第一个将从 NASA 的这张图片中获得灵感:

大气中二氧化碳的历史水平——公共领域图片由美国宇航局提供https://climate . NASA . gov/climate _ resources/24/graphic-the-renely-rise-of-carbon-CO2/

这张图表记录了几十万年来大气中的二氧化碳水平。它本质上是一个带注释的图,我们将使用 Pandas 和 Matplotlib 从原始数据构建我们的版本。

第二张图将包含两个图表,一个在上面,另一个显示各大洲的二氧化碳排放量。我们将把这些和一些支持文字一起放在一个背景图片上。

我会给你看我们进行的代码,但整个代码,数据和图像将可从我的网页。

我们将使用的数据全部由优秀的我们的数据世界 (OWID)网站和 Github 页面提供。在 CC-BY 许可下,他们所有的可视化、数据和文章都是免费和开源的。

我们的方法

我们将使用 Matplotlib 的功能,它允许我们注释图表并在图表中定位图像。

首先,我们将数据读入 Pandas dataframes,然后我们将根据这些数据创建一个基本图表。一旦我们有了这个,我们就像你在上面的 NASA 例子中看到的那样注释图表,并把它保存为图像。

为了构建信息图,我们创建了一个新的 Matplotlib 图,并将我们保存的图表图像与背景图像(您在本文顶部看到的图像)一起放入其中。

然后,我们重复这个过程来创建另一个信息图,但这次我们有两个图表和一些说明性文本。

结果将是这样的:

我们将创建的两个信息图——作者图片

代码

我将一步一步地浏览代码,并在每一节的末尾包含该部分完整代码的要点。所有的代码也可以通过我的网站上的链接获得。

我们需要做的第一件事是导入我们将使用的 Python 库。

**import** pandas **as** pd
**import** matplotlib.pyplot **as** plt

我们将从 OWID 数据创建 Pandas 数据帧,并使用 Pandas 和 Matplotlib 创建图表和其他视觉效果。

获取数据

我们将使用的第一个数据集包括许多国家和地区(实体)的各种气候指标。我们将使用全球的二氧化碳浓度数据,因此我们将相应地过滤数据。

首先,我们将数据读入数据帧co2,当然,这将包含所有的数据。

接下来,我们过滤数据,只考虑其中的实体名称为“World ”,并将其存储在数据帧co2world.

*# original source:* # [*https://ourworldindata/co2-and-other-greenhouse-gas-emissions*](https://ourworldindata/co2-and-other-greenhouse-gas-emissions)co2 **=** pd**.**read_csv('data/climate-change.csv')co2world **=** co2[co2['Entity']**==**'World']
co2world

历史二氧化碳浓度—作者图片

数据中还有其他几列,但我们只对 CO2 浓度数据感兴趣。

绘制基本图表

我们可以这样绘制这些数据:

co2world**.**plot(y **=** "CO2 concentrations", 
              x **=** 'Year', 
              grid **=** **True**, 
              figsize **=** (20,10))

历史二氧化碳浓度—作者图片

结果是一个相当令人震惊的图表,它显示,在过去的 80 万年里,地球大气中的二氧化碳浓度低于 300 ppm(百万分之一),但在过去的几十年里,它飙升至 400 ppm 以上。

然而,除非你熟悉数据,否则解读图表并不容易。所以,让我们帮读者一个忙,让我们看到的东西更明显一点。

x 轴代表时间,但大多数年份是负值。这些值是相对于共同时代的开始,因此,例如,-800,000 意味着 800,000 BCE(在共同时代之前),0 是我们在当前系统中开始计算世纪的位置,最后一年是 2022 年,即今年。

我们将设置记号和标签,使其更具可读性,因为标签很长,我们将旋转它们,使它们不会重叠。

plt**.**xticks([**-**800000, **-**600000, **-**400000, **-**200000, 0], 
           ['800,000 BCE', '600,000 BCE', '400,000 BCE',
            '200,000 BCE','0'],
             rotation**=**20)

我们还定义了 x 轴和 y 轴标签,移除图例(这是多余的)并添加标题。

plt**.**ylabel("carbon dioxide level (parts per million)")plt**.**xlabel("years before today (0 = 1950)")plt**.**legend("")plt**.**title("CO2 Concentrations")

然后,我们将生成的图形保存为图像。

plt**.**savefig('images/co2world.png')

以下是完整的代码:

这是结果图。

历史二氧化碳浓度,可读性更强的版本——图片由作者提供

我们这里有一个可读的图表,但它并不包含上面 NASA 图表中的所有信息。

给图表加注释

我们需要添加标题“几千年来,大气中的碳从未超过这条线”,并绘制标题所指的线。

caption = "For millennia, atmospheric carbon has never been above this line"plt**.**text(**-**790000,320, caption,
        verticalalignment**=**'top', horizontalalignment**=**'left',
        fontsize**=**fontsize, color **=** color)

plt**.**plot([**-**800000,0],[305,305], linestyle **=** 'dashed', 
          color**=**'red', linewidth **=** 2)

在上面的代码中,我们将标题定义为一个字符串,然后将其添加到图表中的 x/y 位置-790000,320,然后在 CO2 浓度水平为 305ppm 时从-800000,0 绘制一条水平虚线。

接下来,我们添加注释——指向 1950 年和 2022 年的标签和箭头。

plt**.**annotate("1950",xy **=** (0,312), xytext **=** (70000,306),
              arrowprops**=**dict(facecolor**=** color, shrink**=**0.1), 
              fontsize**=**fontsize, color **=** color)
plt**.**annotate("2022",xy **=** (0,417), xytext **=** (70000,411),
              arrowprops**=**dict(facecolor**=** color, shrink**=**0.1),
              fontsize **=** fontsize, color **=** color)

最后要做的事情是去掉脊骨:

ax**.**spines['top']**.**set_visible(**False**)
ax**.**spines['right']**.**set_visible(**False**)
ax**.**spines['bottom']**.**set_visible(**False**)
ax**.**spines['left']**.**set_visible(**False**)

然后将结果保存为图像文件。

plt**.**savefig('images/'co2.png', transparent **=** **True**)

结果如下:

完整的二氧化碳浓度图表—图片由作者提供

这是这个阶段的完整代码。你会注意到我已经改变了默认的颜色和字体大小,并在开始时将它们声明为变量,这样我们就可以很容易地改变它们。

创建信息图

该图现在看起来像美国宇航局的图像,但我们想把它放在一个背景图像。这不仅仅是向当前图表添加图像的问题。如果我们这样做,轴标签将在图像之外,我们希望将整个图表放置在背景图像内。

解决方案是创建一个新的 Matplotlib 图形,如下所示:

ax**.**plot([0,100],[0,100], alpha **=** 0)

这给了我们一个 100 乘 100 的图表,我们可以使用它作为画布来放置我们的图表图像。请注意,我已经将 alpha 值设置为零,这意味着图表将不可见。

我们现在可以将图表图像添加到这个新图形中:

img1 **=** plt**.**imread('images/co2.png')
ax**.**imshow(img1, aspect**=**'auto', alpha**=**1, extent**=**(1,99,1,99))

请注意,通过使用范围参数,我使图像比图形稍微小一点,但是在它的中心。

背景图像以类似的方式添加:

bground**=**plt**.**imread('images/ISS_earth.en.jpg')
ax**.**imshow(bground, aspect**=**'auto', alpha**=**0.3, extent**=**(0,100,0,100))

但是这一次,图像的范围是图形的全部。

我已经将两张图像的 alpha 值设置为图表图像为 1(这是默认值),背景为 0.3。这意味着图表将完全不透明,但背景图像将部分透明。

完整的信息图-作者提供的图片

这是第一个信息图的代码。

更复杂的信息图

信息图通常包含不止一个图表和一些说明性文字,所以这是我们接下来要尝试的。

我们将使用相同的技术创建一个空白图形,并在该图形上放置图像和(这次)文本。我们将使用已经为其中一个图表和背景创建的图像,并添加另一个图表和一些文本。

从另一个 OWID 数据集,我们可以创建一个图表,表示世界各地二氧化碳排放量的增加。这是:

各大洲二氧化碳排放量—数据来源,数据中的我们的世界,图片由作者提供

创建它的代码如下。首先,我们读取数据,然后根据我们指定的大洲列表过滤结果表。然后直接遍历这些大陆的名称,并在图表中添加一个新的绘图。

我们将结果保存为图像。

现在我们有了我们需要的图像,但是我们需要指定三个字符串中的文本。

title **=** """
CO2 Emissions
"""text1 **=** """
CO2 emissions have risen 
significantly in all parts 
of the World in modern times,
particularly in Asia.
"""text2 **=** """
For hundreds of millennia,
CO2 levels never rose above 
around 300ppm. In 1950 it 
was just over 300 and now it 
is over 400ppm
"""

我不会重复放置图像,因为这几乎是我们之前所做的重复,但是使用范围参数来将图像放置在图的右上角和左下角。

然而,文本的定位略有不同。这里有一个例子。

ax**.**text(5,80, text1,
        verticalalignment**=**'top', horizontalalignment**=**'left',
        color**=**'black', fontsize**=**18)

在这个对 ax.text 的函数调用中,前两个参数是文本的位置,第三个是文本本身,其他的不言自明。

我们现在拥有了完成信息图的所有组件和技术。这是结果,代码如下。

完整的信息图-作者提供的图片

大概就是这样。感谢阅读,我希望这是有用的,并会启发你产生自己的惊人的图形。

像往常一样,在这篇文章发表后不久,完整的代码将通过我的网站上的链接提供——你也可以在那里看到我的其他作品。

如果你想看更多的文章,请在媒体上关注我或者订阅我偶尔发的子栈简讯。

https://medium/membership/@alan-jones

笔记

通过下面的链接,你可以在“数据世界”和美国宇航局的图片中找到原始数据。

https://ourworldindata/co2-and-other-greenhouse-gas-emissions https://github/owid/co2-data https://climate.nasa.gov/climate_resources/24/graphic-the-relentless-rise-of-carbon-dioxide/ https://www.nasa.gov/mission_pages/station/images/index.html

本文标签: 中文翻译博客TowardsDataScience