收集你的数据:常见的!
维克多·塔拉舒克在 Unsplash 上拍摄的照片
使用 Python 从 zip、csv、tsv、xlsx、txt
你知道哪个是最受欢迎的数据科学家模因吗? “收集数据是我的心脏”。 没错,的确如此!与数据科学领域的初学者所想的不同,数据很少以干净整洁的表格格式提供给你。
在现实世界中,数据需要从多个来源收集,如平面文件、zip 文件、数据库、API、网站等。不仅仅是源代码,它们可以是不同的格式、文件结构,如。csv,。tsv、json 等,并由不同的分隔符分隔。如何从这个烂摊子中理出头绪?
作者图片
要执行分析并从我们的数据中获得准确的结果,首先,您应该知道不同的格式,其次,知道如何将它们导入 Python。在这篇博客中,我将涉及一些您可能熟悉的基本文件结构,并提到用于导入数据的不同但通用的 python 库。
掌握这些文件格式对你在数据领域的成功至关重要。那么每个人都从哪里开始呢?哦,是的,无处不在的 csv 文件。
用 python 读取 CSV 文件
用于存储数据的最常见的平面文件结构是逗号分隔值(CSV)文件。它包含由逗号(,)分隔符分隔的纯文本格式的表格数据。要识别文件格式,通常可以查看文件扩展名。例如,以“CSV”格式保存的名为“datafile”的文件将显示为“datafile.csv”。
Pandas 库用于从 python 中的 csv 文件读取数据。Pandas 库中的 read_csv() 函数用于加载数据并将其存储在数据帧中。
在 python 中读取其他平面文件
平面文件是包含表格行列格式记录的数据文件,没有任何编号结构。CSV 是最常见的平面文件。但是也有其他平面文件格式,其中包含带有用户指定分隔符的数据,如制表符、空格、冒号、分号等。
制表符分隔值(TSV)文件是第二常见的平面文件结构。来自 Pandas 库中的相同 read_csv()函数用于读取这些文件,您只需要为 read_csv()函数的参数’ sep '指定正确的分隔符。
用 python 读取 XLSX 文件
一个带有。xlsx 文件扩展名是由 Microsoft Excel 创建的 Microsoft Excel Open XML 电子表格(XLSX)文件。这些文件是在 Microsoft Excel 中使用的文件,Microsoft Excel 是一种电子表格应用程序,使用表格来组织、分析和存储数据。
电子表格的每个单元格由行和列定位,可以包含文本或数字数据,包括合并数学公式。在早期版本的 Excel 中制作的电子表格文件以 XLS 格式保存。
pandas 库中的 read_excel() 函数用于将 excel 文件数据加载到 python 中。
XLSX 文件将数据组织到存储在工作表中的单元格中,这些单元格又存储在工作簿(包含多个工作表的文件)中。为了读取所有的工作表,我们使用 pandas ExcelFile() 函数。现在,我们只需在 read_excel()函数的参数 sheet_name 中指定工作表的名称,就可以从工作簿中读取特定的工作表。
在 python 中提取 ZIP 文件
扩展名为 ZIP 的文件是 ZIP 压缩文件,是您将遇到的最广泛使用的归档格式。
与其他归档文件格式一样,ZIP 文件只是一个或多个文件和/或文件夹的集合,但为了便于传输和压缩,它被压缩成一个文件。
我们经常获得压缩格式的 csv 或 excel 文件,因为它节省了服务器上的存储空间,减少了您将文件下载到计算机的时间。python 中的 zipfile 模块用于提取。压缩文件。
使用 python 读取文本文件
纯文本格式的基本概念结构是数据按行排列,每行存储几个值。纯文本文件(也称为扩展名 TXT)由按特定字符编码顺序编码的字符组成。
Python 提供了各种函数来读取文本文件中的数据。每行文本都以一个称为 EOL(行尾)的特殊字符结束,这是 python 中默认的换行符(’ \n ')。
Python 文件操作,具体来说就是打开文件、读取文件、关闭文件和其他各种文件方法,这些都是你在访问文本文件时应该知道的。内置 Python 函数 open()有模式、编码等参数。用于在 python 中正确打开文本文件。
Python 为我们提供了三种从文本文件中读取数据的内置方法,read([n])、readline([n])和 readlines()。这里的“n”是要读取的字节数。如果没有东西传递给 n,那么整个文件被认为是被读取的。
如果参数中没有给出字节数(n ),则 read() 方法只输出整个文件。
readline(n) 最多输出文件单行的 n 个字节。它只能读一行。
readlines() 方法维护了文件中每一行的列表,可以使用 for 循环对其进行迭代。
以上给出了用 python 读取文本文件的基本思路。但是,数据从来不会以一种易于访问的格式呈现在我们面前。假设你想根据你附近的评论找到 10 家最受欢迎的餐馆。
假设有 1000 家餐馆,其数据存在于 1000 个单独的文本文件中,您需要这些文件中存在的餐馆名称、评论 url 和评论文本。为了将多个文件中的数据读入一个数据帧,使用了 Python 的 glob 库。
Python 内置的 glob 模块用于检索与指定模式匹配的文件/路径名。glob 的模式规则遵循标准的 Unix 路径扩展规则。
/是 glob 语句中的通配符。星号()匹配一个名称段中的零个或多个字符。您需要始终在 open()函数中指定编码,以便正确读取文件。
这里,文本文件的第一行是餐馆名称,第二行是餐馆评论 url,其余行是评论文本。相应地使用 readline()和 read()函数来提取这些数据。
在这篇博客中,我介绍了数据行业中人们使用的最常见和最流行的文件结构。这应该为你在处理数据收集和混乱的文件结构时的下一次挫折做好准备。还有许多其他的,我打算在我接下来的博客中讨论。
如果你喜欢这篇博文,请在下面留下评论并与朋友分享!
收集您的数据:“不那么怪异”的 API!
照片由 Fotis Fotopoulos 在 Unsplash 上拍摄
当 python 处理互联网文件时。
数据分析周期从收集和提取开始。我希望我之前的博客给出了如何使用 python 从常见文件格式中收集数据的想法。在这篇博客中,我将着重于从那些并不常见但却有着最真实应用的文件中提取数据。
无论您是否是数据专业人员,您现在可能都已经遇到了术语 API。大多数人对这个相当常见的术语有一个相当模糊或不正确的概念。
使用 python 中的 API 提取数据
API 是应用编程接口的首字母缩写,它是一个软件中介(中间人),允许两个应用相互对话。
每次你使用像 Tinder 这样的应用程序,发送 WhatsApp 信息,在手机上查看天气,你都在使用 API。它们允许我们在设备、应用程序和个人之间共享重要的数据和公开实际的业务功能。虽然我们可能没有注意到它们,但 API 无处不在,在幕后为我们的生活提供动力。
我们可以把 API 比喻成银行的 ATM(自动柜员机)。银行让我们可以使用他们的自动提款机来查询余额、存款或提取现金。所以在这里,ATM 是帮助银行和我们这些顾客的中间人。
类似地,Web 应用程序使用 API 将面向用户的前端与所有重要的后端功能和数据连接起来。Spotify 和网飞等流媒体服务使用 API 来分发内容。像特斯拉这样的汽车公司通过 API 发送软件更新。更多的例子,你可以查看文章5我们日常生活中使用的 API 的例子。
在数据分析中,API 最常用于检索数据,这将是这篇博客的重点。
当我们想从一个 API 中检索数据时,我们需要发出一个请求。请求在网络上随处可见。例如,当您访问这篇博文时,您的 web 浏览器向面向数据科学的 web 服务器发出了一个请求,该服务器以这个网页的内容作为响应。
API 请求以同样的方式工作——你向 API 服务器请求数据,它响应你的请求。使用 API 主要有两种方式:
- 通过使用 URL 端点的命令终端,或者
- 通过编程语言特定的包装器。
例如, Tweepy 是一个著名的 Twitter API python 包装器,而 twurl 是一个命令行界面(CLI)工具,但两者可以实现相同的结果。
这里我们关注后一种方法,并将使用基于原始 MediaWiki API 的名为 wptools 的 Python 库(包装器)。 MediaWiki action API 是 Wikipedia 的 API ,它允许访问一些 Wiki 特性,如身份验证、页面操作和搜索。
Wptools 对 MediaWiki APIs 进行只读访问。你可以通过传统的 Mediawiki API 从任何语言的任何 Wikimedia 项目中获得关于 wiki 站点、类别和页面的信息。您可以从页面信息框中提取非结构化数据,或者通过 Wikidata API 获取关于页面的结构化、链接的开放数据,并从高性能 RESTBase API 获取页面内容。
在下面的代码中,我使用 python 的 wptools 库访问了圣雄甘地维基百科页面,并从该页面提取了一个图像文件。对于 Wikipedia URL ’ https://en . Wikipedia . org/wiki/Mahatma _ Gandhi ',我们只需要传递 URL 的最后一位。
get 函数获取所有内容,包括摘录、图像、infobox 数据、wiki 数据等。呈现在那一页上。通过使用。data()函数我们可以提取所有需要的信息。我们对 API 的请求得到的响应很可能是 JSON 格式的。
用 python 从 JSON 读取数据
克里斯托夫·高尔在 Unsplash 上拍摄的照片
JSON 是 JavaScript 对象符号的首字母缩写。它是一种轻量级的数据交换格式。人类读&写就像机器解析&生成一样容易。JSON 已经迅速成为事实上的信息交换标准。
在浏览器和服务器之间交换数据时,数据只能是文本。JSON 是文本,我们可以将任何 JavaScript 对象转换成 JSON,并将 JSON 发送到服务器。
例如,你可以用浏览器直接访问 GitHub 的 API ,甚至不需要访问令牌。当你在你的浏览器https://api.github.com/users/divyanitin中访问一个 GitHub 用户的 API 路由时,你得到的 JSON 响应如下:
{
"login": "divyanitin",
"url": "https://api.github.com/users/divyanitin",
"html_url": "https://github.com/divyanitin",
"gists_url": "https://api.github.com/users/divyanitin/gists{/gist_id}",
"type": "User",
"name": "DivyaNitin",
"location": "United States",
}
浏览器似乎已经很好地显示了 JSON 响应。这样的 JSON 响应已经可以在您的代码中使用了。从这段文字中提取数据很容易。然后你可以对这些数据做任何你想做的事情。
Python 原生支持 JSON。它附带了一个 json 内置包,用于编码和解码 JSON 数据。JSON 文件在{}中存储数据,类似于字典在 Python 中存储数据的方式。类似地,JSON 数组被翻译成 python 列表。
在我上面的代码中,wiki_page.data[‘image’][0]访问 image 属性中的第一个图像,即一个 JSON 数组。使用 Python json 模块,您可以像读取简单的文本文件一样读取 json 文件。
read 函数 json.load()返回一个 json 字典,使用 pandas 可以很容易地将其转换为 Pandas 数据帧。DataFrame()函数。您甚至可以使用 pandas.read_json()函数将 JSON 文件直接加载到 dataframe 中。
从互联网上读取文件(HTTPS)
照片由 Edho Pratama 在 Unsplash 上拍摄
HTTPS 代表超文本传输协议安全。它是一种网络浏览器和网络服务器相互交流的语言。web 浏览器可能是客户端,而托管网站的计算机上的应用程序可能是服务器。
我们正在编写与远程 API 一起工作的代码。你的地图应用获取附近印度餐馆的位置,或者 OneDrive 应用启动云存储。所有这一切都是通过 HTTPS 的请求实现的。
Requests 是 python 中的一个多功能 HTTPS 库,具有各种应用。它作为客户端和服务器之间的请求-响应协议。它提供了通过 HTTPS 访问 Web 资源的方法。它的应用之一是使用文件 URL 从网上下载或打开文件。
要发出“GET”请求,我们将使用 requests.get()函数,该函数需要一个参数—我们要请求的 URL。
在下面的脚本中,open 方法用于将二进制数据写入本地文件。在这里,我们使用 python 的操作系统库在系统上创建一个文件夹并保存提取的 web 数据。
json 和 requests import 语句加载 Python 代码,允许我们使用 JSON 数据格式和 HTTPS 协议。我们使用这些库是因为我们对如何发送 HTTPS 请求或者如何解析和创建有效 JSON 的细节不感兴趣,我们只想用它们来完成这些任务。
一种流行的 web 架构风格叫做 REST(表述性状态转移) ,它允许用户通过 GET 和 POST 调用(两种最常用的调用)与 web 服务进行交互。
GET 一般用于获取一些已经存在的对象或记录的信息。相比之下, POST 通常用在你想创造一些东西的时候。
REST 本质上是一组用于构建 web API 的有用约定。我所说的“web API”指的是通过 HTTP 与您交互的 API,它向特定的 URL 发出请求,并经常在响应中获得相关的数据。
例如,Twitter 的 REST API 允许开发人员访问核心 Twitter 数据,Search API 为开发人员提供了与 Twitter 搜索和趋势数据进行交互的方法。
这个博客主要关注所谓的互联网文件。我介绍了使用简单的 API 提取数据。大多数 API 都需要认证,就像我之前的类比 ATM 一样,需要我们输入 pin 来认证我们对银行的访问。
你可以看看我的另一篇文章Twitter Analytics:“WeRateDogs”,这篇文章关注的是 twitter API 的数据争论和分析。我已经在这个项目中使用了所有上述脚本,你可以在我的 GitHub 上找到相同的代码。
众所周知,最常见的互联网文件之一是 HTML。从互联网上提取数据有一个通用术语叫网络搜集。在这种情况下,我们使用 HTML 直接访问网站数据。在我的下一篇博客中,我会涵盖同样的内容,从“基本”到“必须知道的”。
如果你喜欢这篇博文,请在下面留下评论,并与朋友分享!
仪表图和项目符号图
为什么&怎么样,用量具讲故事
图片由来自 Pixabay 的 Brett Hondow 提供
商业智能(BI)是商业环境中使用的一套方法和资源(理论概念、算法、软件、工具、技术),其基本目标是将信息转化为知识。商业智能的目的是支持更好的商业决策,以提高任何商业组织的生产力和绩效。
BI 在很大程度上依赖于一套核心的分析工具:平衡记分卡、仪表盘和关键绩效指标。
平衡记分卡 (BS)是一种管理工具,允许将短期运营控制与被研究公司的长期愿景和战略相结合。为此,BS 制定、实施、控制和管理组织的战略,有效地将战略规划、运营管理以及团队和个人绩效评估联系起来。
关键绩效指标(KPI)是任何组织为了实现其战略计划都需要衡量、监控和执行的最重要的指标。
商业智能仪表板是一种技术驱动的方法,它使用数据可视化工具来显示 KPI,以便跟踪有助于业务运营和成功的主要因素。它是在追求公司设定的目标过程中所涉及的主要指标的图形表示。
企业主和公司高管总是想要简单的解决方案。从这个意义上说,数据分析师必须让仪表板易于查看、导航和理解。用于在仪表板上显示 KPI 的两种传统图形是仪表图和项目符号图。
我们分别来分析一下。
1。-仪表图
又名:车速表图表、表盘图表、角度规图表
为什么:广泛用于商业智能(BI)可视化,特别是仪表板中,用于指示数据或测量值是否在某个值范围之内、之下或之上。它们是非常简单的图形,能够很快抓住观众的注意力,即使是非专业观众也是如此。它们提供关于一个单一定量测量的信息,将它的当前值与一个目标和一系列由不同颜色的条带表示的范围进行比较。下图表明当前销售值(420)在令人满意的范围内,但比预定目标低 30 个单位。
图 1:标准仪表图。目标是 450。阈值在 250 和 350。
如何:虽然有不同的格式,但最常见的是对应于车辆的速度表:一个径向数字刻度分成几个部分,每个部分用特定的颜色标识;指针或指针在径向标尺上移动;最小或下限值、最大或上限值和目标值。范围或扇区的数量是可变的,但通常有三个扇区,红色表示低于下限阈值的扇区,黄色表示阈值之间的扇区,绿色表示高于上限阈值的扇区。建议不要显示超过五个范围或扇区。
以下是与不同颜色相关的一些可能的定性值**:差、满意和好;绿色表示满意,黄色表示小心,红色表示报警;差、一般、优秀;红色代表低性能,黄色代表正常性能,绿色代表高性能。这些定性值的范围广泛用于 BI 演示或仪表板上,以显示给定公司的业务绩效。目标值可以是要达到的目标、基准或要超过的先前值。**
不要将仪表图与圆环图(圆环图)混淆。虽然前者仅报告定量测量,但环形图与可分为单个部分的整体相关,以及每个部分如何以相对或绝对方式与总量相关(整体的部分分析)。****
仪表图在用数据讲述故事时有几个优点😗***
它们非常简单,通俗易懂,迅速抓住观众的注意力;
观众对它们很熟悉:汽车速度计、电脑游戏中的指示器、烤箱或火炉中的温度指示等。不像更复杂的图形,没有必要“浪费时间”去解释它们;
颜色的顺序,从红色到绿色,是直观和立即理解的;
大多数商业和公司主管更喜欢它们,因为它们简单、清晰、即时地传输关键数据;
但是它们也充满了缺点,在讲故事的时候必须考虑到这些缺点:
它们的简单性不允许它们描绘背景;
他们经常通过省略关键信息来误导观众,导致糟糕的故事情节。
人类很难通过角度来比较数值;我们总是喜欢通过从共同基线开始的长度进行比较(项目符号图);
它们占据了大量的物理空间,而且它们的格式会分散观众的注意力。仪表板和记分卡上经常堆满了指标,这使得讲故事的过程变得更加复杂;
请记住色盲(色觉缺陷)大约影响十二分之一的男性和两百分之一的女性。最常见和最有问题的颜色缺乏形式被称为“红绿色盲”,准确地说是仪表中常用的两种颜色。由于这些原因,实际的趋势是将扇区编码为具有从暗到亮的不同强度的单一色调。较深的颜色强度用于低值或差值,而较浅的颜色强度表示满意或优秀值(图 2);
最后一个警告来自 Robert Kosara (#1):“在数据可视化中,仪表只是解决了错误的问题。业务决策不能只基于某个度量的当前值,而是需要历史和背景。数值通常也不会像加速器上的压力大小和汽车速度那样快速变化,也不会直接相关。
图 2:角度规图。用 Vizzlo 创建,有权限(#2)。
Matplotlib 库没有允许我们直接绘制仪表图的功能。在以下网站可以找到一个非常巧妙的解决问题的方法:https://water gramming . WordPress . com/2018/06/04/creating-shaded-dial-plots-in-python/。一个更简单的解决方案是基于 Plotly 图形库,它有一个指示器功能:https://plotly.com/python/gauge-charts/。
2。-项目符号图
又名:项目符号图
为什么:著名的数据可视化专家Stephen first开发了一种替代量规的方法,他将其命名为子弹图(#3)。关键的想法是通过添加补充措施来丰富信息,以描绘背景,使用更少的物理空间,没有分散观众注意力的装饰。项目符号图提供有关单个定量测量的信息,将它的当前值与目标值以及一系列由不同颜色的条带指示的范围进行比较。****
如何:它们类似于标准条形图(它们通过长度或高度对信息进行编码),但与标准条形图的不同之处在于,它们包括一个中间窄条,指示所报告的数值变量的当前值。它们也有一条垂直线显示目标或对象,以及不同的范围或扇区(通常是三个),用不同颜色的带或单一色调的不同强度来指示。与仪表图不同,不同的类别可以在单个图表中进行比较。
图 3:标准的项目符号图。目标是 450。阈值在 250 和 350。
标准项目符号图有五个组成部分(#3):
指示测量变量和相应测量单位的文本标签;
沿着线性轴的定量刻度,其刻度和数字标识等间距的测量间隔;
用清晰可见的条形编码的主要或特色测量,其基线可能不为零;
垂直于图表方向绘制的细线形式的比较度量(如果代表主要度量的条是水平的,则为垂直线;如果代表主要度量的条是垂直的,则为水平线);
两到五个定性的绩效范围,表示主要衡量标准的定性状态。这些范围通过不同的颜色或单一色调的不同强度来区分。
项目符号图以垂直或水平方向呈现。水平项目符号图允许在垂直轴上显示不同的类别,而数字值由水平轴上的数量刻度表示。相反,垂直项目符号图允许在水平轴上显示不同的类别,而在垂直轴上用数量刻度显示数值。定量刻度允许您在线性轴上显示变量的测量值,比仪表的角轴更容易读取。
图 4:具有五个扇区的水平定向的项目符号图。目标是 78%。
与仪表图类似,范围或部门最常见的定性值有:差、满意和好;绿色表示满意,黄色表示小心,红色表示报警(图 4);差、一般、优秀;低于绩效、一般绩效和高于绩效。
仪表板上的项目符号图和其他 BI 可视化工具通常显示的数字变量是销售额、收入、利润、费用、客户数量和相关数据。
不要将项目符号图表与进度条 图表混淆。后者是一个图形控制元素,用于可视化某个操作的进度,如下载文件、传输文件或安装软件。一些可视化工具建议使用进度条作为业务指示器,如下图所示:
图 5:进度条形图。用 Vizzlo 创建,有权限(#2)。
与仪表图一样,Matplotlib 没有允许您立即绘制项目符号图的功能。同样,我发现了一个基于 Matplotlib 和 Seaborn 的非常巧妙的解决方案:【https://pbpython.com/bullet-graph.html。我还找到了一个更好的基于 Plotly 的解决方案:https://plotly.com/python/bullet-charts/
中国一所大学进行的一项科学研究比较了 40 名大学生在面对水平子弹图、垂直子弹图和角度规图(#4)时的情绪差异。每个图形备选方案所需的认知负荷、学生感知的满意度以及每个可视化备选方案的美学效果被用作主观指标。该研究得出结论,垂直方向的项目符号图产生最高的满意度和最低的认知负荷。相比之下,角度规图导致最低的满意度,最高的认知负荷,尽管它们是最具美感的。
我建议你将这些结果用于你的下一次商业演示。
在许多公司进行数字化转型的背景下,商业智能和数据可视化技术变得越来越重要。可视化和图表定制的可能性非常多:有几十种不同的图表在可视化数据时提供了很大的灵活性,但有时只需要简单、易于理解的图表,就可以迅速抓住观众的注意力。仪表和项目符号图提供了简单性和熟悉性,这是观众非常欣赏的。
特别是,我们建议使用项目符号图,因为它们能够在较小的空间内编码更多的信息。
如果你对这篇文章感兴趣,请阅读我以前的:
直方图,为什么&怎么样,讲故事,提示&扩展
讲故事、技巧和扩展
towardsdatascience.com](/histograms-why-how-431a5cfbfcd5)
平行坐标剧情,为什么&怎么样,用平行线讲故事
为什么&如何:用类比讲故事
towardsdatascience.com](/parallel-coordinates-plots-6fcfa066dcb3)
参考文献
# 1:https://eagreyes . org/crisis/data-display-vs-data-visualization
2:https://vizzlo.com/
# 3:https://www . perceptual edge . com/articles/misc/Bullet _ Graph _ Design _ spec . pdf
#4:,,郭,,牟力军,“子弹图与仪表图:基于眼动跟踪方法的工业可视化人类信息处理评价”,T. Z. Ahram 和 C. Falcã(编辑。):AHFE 2018,AISC 794,第 752–762 页,2019。https://doi.org/10.1007/978-3-319-94947-5_74****
高斯混合模型和期望最大化(完整解释)
美国宇航局在 Unsplash 拍摄的照片
在之前的文章中,我们描述了线性回归的贝叶斯框架,以及我们如何使用潜在变量来降低模型的复杂性。
在本帖中,我们将解释潜在变量是如何被用来构建分类问题的,即高斯混合模型(或简称 GMM),它允许我们执行软概率聚类。
这个模型是由一个名为期望最大化(简称 EM)的优化过程训练出来的,我们将对此进行全面的回顾。在本文的最后,我们还将看到为什么我们不使用传统的优化方法。
这篇文章包含一些数学符号和推导。我们不想吓唬任何人。我们相信,一旦直觉被赋予,深入数学去真正理解事物是很重要的。
这篇文章的灵感来自 Coursera 上的一门优秀课程:机器学习的贝叶斯方法。如果你对机器学习感兴趣,我绝对推荐这门课程。
高斯混合模型
该模型是一种软概率聚类模型,它允许我们使用混合高斯密度来描述点对于一组聚类的成员关系。这是一种软分类(与硬分类相反),因为它分配属于特定类别的概率,而不是确定的选择。本质上,每个观察将属于每个类,但是具有不同的概率。
我们以著名的虹膜分类问题为例。所以我们有 150 朵鸢尾花,分成 3 类。对于它们中的每一个,我们都有萼片的长度和宽度,花瓣的长度和宽度,以及类别。
让我们使用 seaborn 包的 pair 图快速浏览一下数据:
作者图片
高斯混合模型试图将数据描述为来自高斯分布的混合物。首先,如果我们只取一个维度,比如花瓣宽度,试着去适应 3 种不同的高斯分布,我们会得到这样的结果:
作者图片
该算法发现,最有可能代表数据生成过程的混合物由以下三种正态分布组成:
setosa 花瓣宽度更加集中,平均值为 0.26,方差为 0.04。另外两个班级相对来说更分散,但是位置不同。现在让我们看看二维的结果,比如花瓣宽度和花瓣长度。
作者图片
混合物的成分如下:
请注意,GMM 是一个非常灵活的模型。可以证明,对于足够大数量的混合物,并且适当地选择所涉及的参数,可以近似任意地接近任何连续的 pdf(这需要额外的计算成本)。
形式化——MLE
那么算法如何找到描述混合物的最佳参数集呢?
我们从定义概率模型开始。观察到任何观察值的概率,即概率密度,是 K 个高斯分布的加权和(如前一节所示) :
每个点是 K 个加权高斯分布的混合,这些加权高斯分布由平均值和协方差矩阵参数化。所以总体来说,我们可以把观察到一个特定观测的概率描述为一个混合物。为了确保您完全理解,在上面使用花瓣宽度的一维示例中,在区域[0.2,0.3]中观察到花瓣宽度的概率最高。我们也很有可能在区域[1.2,1.5]和[1.8,2.2]中观察到花瓣宽度。
注意,在 3 个集群的情况下,参数集将是:
然后,我们希望找到最大化数据集可能性的参数值。我们想找到参数的最大似然估计。也就是我们要找到最大化所有数据点一起观测到的概率(即联合概率)的参数,解决以下优化问题:
注意,数据集的完全联合概率可以被矢量化(即分解为单个概率的乘积,使用π运算符),仅在假设观察值是同分布(同独立分布)的情况下。当它们存在时,事件是独立的,观察一个数据点的概率不受其他概率的影响。
我们通常最大化对数似然,而不是似然,部分原因是它将概率的乘积转化为总和(更容易操作)。这是因为自然对数是单调递增的凹函数,不改变最大值的位置(导数为零的位置将保持不变)。
现在最大似然估计可以用许多不同的方法来完成。这可以通过直接优化(找到偏导数为零的点)或数值优化(如梯度下降)来实现。GMM 的 MLE 没有使用这些方法,原因如下,我将解释。但是我把它留在文章的最后,因为我想先了解最相关的材料。GMMs 的最大似然估计是使用期望最大化算法完成的。
期望最大化
GMM 训练直觉
首先,我们将直观地描述 GMM 模型训练过程中发生的事情,因为这将真正有助于为 EM 建立必要的直觉。假设我们又回到了一维例子,但是这次没有标签。试着想象我们如何给下面的观察分配聚类标签:
作者图片
好吧,如果我们已经知道高斯分布在上面的图中的位置,对于每个观察值,我们可以计算聚类概率。让我们画这张图,这样你就能记住它了。因此,我们将为下面的点分配一种颜色:
作者图片
直观地,对于一个选定的观察值和一个选定的高斯值,属于该聚类的观察值的概率将是高斯值和所有高斯值之和之间的比率。类似于:
好吧,但是你怎么知道高斯人在上面的图中的位置呢?我们如何找到高斯参数)?好吧,假设我们已经拥有了观察的标签,就像这样:
作者图片
现在我们可以很容易地找到参数值并画出高斯图。单独考虑这些点就足够了,比如说红点,然后找到最大似然估计。对于高斯分布,可以证明以下结果:
将上述公式应用于红色点、蓝色点和黄色点,我们得到以下正态分布:
作者图片
给定正态分布参数,我们可以找到观察标签,给定观察标签,我们可以找到正态分布参数。所以看起来我们有一个先有鸡还是先有蛋的问题,对吗?
事实上,解决这个问题并不难。我们只是需要从某个地方开始。所以我们可以将高斯参数设置为随机值。然后,我们通过迭代两个连续步骤直到收敛来执行优化:
- 我们使用当前的高斯参数为观察值分配标签
- 我们更新高斯参数,使拟合更有可能
这将产生以下结果:
作者图片
如你所见,当我们到达第四步时,我们已经处于最佳状态。
EM 直觉
期望值最大化算法的执行方式完全相同。事实上,我们上面描述的 GMMs 的优化过程是 EM 算法的一个具体实现。EM 算法只是被更一般和更正式地定义(因为它可以应用于许多其他优化问题)。
因此,总的想法是,我们试图最大化一个似然性(更常见的是对数似然性),也就是说,我们试图解决以下优化问题:
这一次我们不是说可能性 P(x _ I |θ)是高斯混合。它可以是任何东西。
现在,让我们把事情形象化!假设对数似然(log P(X |θ))是以下一维分布:
作者图片
使这种算法有效的主要技巧在于特定函数的定义和使用。该函数以这样的方式定义,即在参数空间中的任何给定点,我们肯定知道它将总是具有低于或等于对数似然的值。它被称为下界。我们称之为 L(下图红色部分):
作者图片
现在,事实上,我们不使用单个下界,而是使用由参数θ的向量和变分分布 q 参数化的一族下界。因此 L(θ,q)可以位于任何地方,只要它保持为似然性的下界:
作者图片
EM 算法从分配随机参数开始。假设我们从以下下限开始:
作者图片
该算法现在将执行两个连续的步骤:
- 固定θ并调整 q,使下限尽可能接近对数似然。例如,在第一步中,我们计算 q1:
作者图片
2.固定 q 并调整θ,使下限最大化。例如,在第二步中,我们计算θ1:
作者图片
因此,总结一下这种直觉,EM 算法将寻找最大可能性(或至少是局部最大值)的困难分解为一系列更容易处理的连续步骤。为了做到这一点,它引入了一个由向量θ参数化的下界,我们希望找到它的最优解,以及一个我们也可以随意修改的变分下界 q。
詹森不等式
这个不等式在某种程度上只是凹函数定义的重新表述。回想一下,对于任何凹函数 f,任何权重α和任意两点 x 和 y:
事实上,这个定义可以推广到两点以上,只要权重总和为 1:
如果权重总和为 1,那么我们可以说它们代表一种概率分布,这给出了詹森不等式的定义:
凹函数对期望值的投影总是大于或等于凹函数的期望值。
EM 形式化
期望值最大化算法用于利用潜在变量的模型。一般来说,我们定义一个潜在变量 t 来解释一个观察值 x。通过观察,有一个潜在变量的实例。所以我们可以画出下图:
作者图片
还因为 t 解释了观察值 x,所以它定义了观察值属于其中一个聚类的概率。所以我们可以写:
现在观察的完全可能性可以写成边际可能性(即通过排斥 t):
现在回想一下,我们正在尝试解决以下优化问题:
我们还介绍了詹森不等式,它可以写成:
我们想用这个不等式来帮助我们定义下界。我们希望这个下限取决于θ和一个变分分布 q,诀窍是这样引入 q:
通过乘以和除以 q,我们没有改变任何东西。现在我们可以利用詹森不等式:
我们成功地建立了一个依赖于θ和 q 的边际对数似然的下界。因此,我们现在可以通过交替执行以下两个步骤来最大化完整的下界:
期待步骤:
我们固定θ,并尝试使下限尽可能接近可能性,也就是说,我们尝试最小化:
通过进一步的额外步骤(我将在此拯救您),我们可以证明:
因此,为了找到变分分布 q 的下一个值(k+1 ),我们需要独立地考虑每个观察值 x_i,并且对于每个类,我们计算该观察值属于类 p(t_i|x_i,θ)的概率。回想一下,根据贝叶斯法则:
现在我们可以把高斯混合模型联系起来。我们在上面的公式中发现了我们直观推导出的结果,即:
最大化步骤:
我们固定 q,并最大化下限,其定义为:
现在减法中的第二项不依赖于θ,所以我们可以写成:
现在我们通常选择一个容易优化的凹函数。在高斯混合模型的情况下,我们使用高斯分布的最大似然估计。
如果你想看完整的推导,让我们得到 m-step 中参数更新的封闭表达式,我把它们写在了一篇专门的文章中(为了不使这篇文章超载)。
如果你红了这一点,恭喜你!你现在应该很好地掌握了 GMM 和 EM。或者,如果您想了解为什么我们不使用传统方法来找到最佳参数集,请继续阅读。
那么,如果我们从零开始,在高斯混合模型的情况下,如何进行最大似然估计呢?
直接优化:第一种方法
找到最大似然估计的一种方法是将对数似然相对于参数的偏导数设置为 0,并求解方程。我们称这种方法为直接优化。
正如您所看到的,这种方法是不切实际的,因为高斯分量的总和出现在测井曲线中,使得所有参数都联系在一起。例如,如果 K=2,我们试图求解α_1 的方程,我们有:
我们用链式法则完成了第一步……但是我们不能用其他参数来表达参数α_1。所以我们被困住了!我们不能解析地解这个方程组。这意味着我们不能使用解析表达式一步找到全局最优,或者至少是局部最优。
数值优化:第二种方法
好吧,我们还能做什么?嗯,我们必须依靠数值优化方法。例如,我们可以尝试使用我们最喜欢的随机梯度下降算法。它是如何工作的?
嗯,我们随机初始化参数θ的向量,并迭代数据集的观测值。在步骤 k,我们为一个选定的观察值计算似然的梯度。然后,我们通过在梯度的相反方向上采取一个步骤(使用特定的学习速率η)来更新参数值,即:
使用链式法则,我们可以计算其余参数的偏导数(就像我们上面对α_1 所做的那样)。例如,对于μ_1,我们将得到以下结果:
现在你要告诉我,参数仍然是相互依赖的。是的,但是我们不再解方程了。首先,我们用当前位置的值和当前的参数集来计算偏导数。这是一种迭代算法。
假设我们在计算θ。我们有θ⁰=(α_0,α_1,μ_0,μ_1,σ_ 0,σ_ 1),我们有第一个选择的观察值 x_0。给定偏导数的公式,我们就有了计算θ所需的一切。并且我们继续进行连续的步骤,直到收敛(也就是说,当前的步骤变得太小)。
作者图片
例如,我通过模拟优化带有两个参数(x 和 y)的 Beale 函数 B 来生成上面的动画。我们从一个随机点开始,大约在(-3.5,-3.5),在每一步,我们将参数更新到最小值。
注意,在现实中,由 Tensorflow 或 PyTorch 等数值框架执行的损失函数的微分并不像我们上面所做的那样执行。我们不像在高中时那样使用一套硬编码的数学规则(也就是所谓的手动微分)。甚至可能没有方便的导数公式。使用自动微分完成。
好的,这个看起来不错!所以我们结束了?别这么快!我们忘记了一件重要的事情。我们必须满足两个约束来解决这个优化问题。我们正在约束条件下执行优化。
第一个是混合权重的和α必须是非负的,并且总和为 1。这允许观察数据点的概率是适当的概率密度函数;那就是:
为了克服这一限制,我们可以使用拉格朗日乘数将其纳入优化问题;即把问题重新表述为:
λ作为附加参数添加到矢量θ中。然后,我们再次运行我们的随机优化程序,我们完成了!嗯,没那么快!真正的问题在于第二个约束。回想一下,多正态概率密度函数写为:
但是矩阵σ不能任意!它是一个协方差矩阵,因此应考虑某些属性:
- 对角项是方差,因此必须是正的
- 矩阵必须是对称的
- 对于两个不同的预测值,其协方差的平方必须小于其方差的乘积
- 矩阵必须是可逆的
- 行列式必须是正数
当矩阵是半正定的时,这些条件被满足。
这是一个非常难以满足的约束,并且仍然是一个活跃的研究领域。事实上,凸优化有一个专门的子领域,叫做半定规划。它真正成为一门学科是从 90 年代开始的,用的方法有内点或增广拉格朗日。但是混合模型在此之前已经出现,并导致了期望最大化算法。
如果您不理解以上所有内容(尤其是关于拉格朗日公式的部分),请不要担心。你需要明白的是,传统的求参数最大似然估计的方法不适用于高斯混合模型。
结论
在这篇文章中,我们已经对高斯混合模型和期望最大化进行了全面的回顾,从视觉上(给出一些见解)和更正式地给出了完整的数学推导。
这篇文章在数学上相当沉重,但我认为如果你设法花时间,它真的是值得的。对这种模型有更深入的了解会让你理解遍布机器学习和统计领域的许多不同技术。而下一次你试图去理解另一款同口径的车型,就简单多了。我向你保证!
在此期间,照顾好你自己和你所爱的人!
高斯混合模型(GMM)
理解 GMM:思想、数学、EM 算法和 python 实现
B rief :高斯混合模型是一种流行的无监督学习算法。GMM 方法类似于 K-Means 聚类算法,但是更健壮,因此由于其复杂性而更有用。在这篇文章中,我将给出一个鸟瞰图,数学( ba ye s ic maths,nothing ab normal ),python 从头实现以及使用 sklearn 库。
介绍
查看我关于 K-means 聚类的博客是一个好主意(3 分钟阅读),以获得聚类、无监督学习和 K-Means 技术的基本概念。在聚类中,给定一个未标记的数据集 X ,我们希望将样本分组到 K 个聚类中。在 GMMs 中,假设的不同子群体( K 共)遵循一个正态分布,虽然我们只有总体 X( 因此得名高斯混合模型)的概率分布信息。我们的任务是能够找到 K 高斯的的参数以便将数据*X进行探索性的数据分析或者对新的数据做出预测。*
对 K-均值聚类的改进
K-means 使用欧几里德距离函数来发现数据中的聚类。只要数据相对于质心遵循圆形分布,这种方法就能很好地工作。但是如果数据是非线性的,椭圆形的呢?还是数据有非零协方差?如果聚类有不同的均值和协方差呢?
这就是高斯混合模型拯救世界的地方!
GMM 假设产生数据的是高斯分布的混合物。它使用数据点到聚类的软分配(即,概率性的,因此更好),与数据点到聚类的硬分配的 K-means 方法形成对比,假设数据围绕质心呈圆形分布。
简而言之,GMM 捕获工作得更好,因为 (A) 它通过使用软分配来捕获属于不同聚类的数据点的不确定性,并且 (B) 它对圆形聚类没有偏见。因此,即使对于非线性数据分布,它也能很好地工作。
戈-梅-莫三氏:男性假两性畸形综合征
GMM 的目标函数是最大化数据 X、 p(X) 的似然值或对数似然值 L (因为 log 是单调递增函数)。通过假设混合了 K 高斯分布来生成数据,我们可以将【p(X)写成边缘化概率,对所有数据点的所有 K 聚类求和。**
**********
似然值
对数似然值
利用上面对数函数内的求和,我们无法获得解析解。虽然看起来很龌龊,但这个问题有一个优雅的解决方案: 期望最大化(em)算法 。
数学
EM 算法 是一种迭代算法,用于寻找模型的最大似然估计(MLE) ,其中参数无法直接找到,就像我们这里的情况。它包括两个步骤:e 预期步骤和最大化步骤。
- **期望步骤 :计算隶属值 r _ ic。这是数据点 x_i 属于聚类 c 的概率。
2. 最大化步骤 :计算一个新的参数 mc ,该参数决定了属于不同聚类的点的分数。通过计算每个聚类 c 的 MLE 的来更新参数μ、π、σ
重复 E-M 步骤,直到对数似然值 L 收敛。
密码
让我们从头开始用 python 写一个 GMM 的基本实现。
生成一维数据。
初始化 GMM 的参数:μ,π,σ。
运行 EM 算法的第一次迭代。
EM 算法的单次迭代
将这段代码放在 for 循环中,并将其放入一个 class 对象中。现在我们正在谈话!
GMM-1D 级
**********
我们已经有了一个模型,可以运行一维数据。同样的原理也适用于更高维度(≥ 2D)。唯一不同的是,我们将在这种情况下使用多元高斯分布。让我们为 2D 模型编写代码。
让我们生成一些数据并编写我们的模型。
2D 斑点
让我们对这个模型做一些预测。
**********
使用 sklearn ,同样的任务可以在几行代码内完成。很圆滑,是吧?
因此,GMM 将样本分类为属于第二类。有用!
结论
实现高斯混合模型并不困难。一旦你对数学有了清晰的认识,就可以找到模型的最大似然估计,无论是 1D 还是更高维的数据。这种方法在执行聚类任务时是健壮且有用的。既然您已经熟悉了 GMMs 的 python 实现,那么您就可以使用数据集执行一些很酷的事情了。假设给你一个病人的数据集,包含两个参数:红细胞体积和红细胞血红蛋白浓度,没有病人和健康病人的标签。插入上面的模型来聚集数据将会给你两个不同的(几乎是)质量,你可以使用它们来进行进一步的分析和预测。
来源
- https://www.youtube.com/watch?v=qMTuMa86NzU
- https://www . python-course . eu/expectation _ maximization _ and _ Gaussian _ mixture _ models . PHP
高斯混合模型:从零开始实现
从机器学习和人工智能领域的兴起,概率论是一个强大的工具,它允许我们处理许多应用中的不确定性,从分类到预测任务。今天,我想和你们讨论更多关于概率和高斯分布在聚类问题中的应用,以及 GMM 模型的实现。所以让我们开始吧
什么是 GMM?
GMM(或高斯混合模型)是一种算法,它使用对数据集密度的估计来将数据集分成初步定义数量的聚类。为了更好地理解,我将同时解释这个理论,并展示实现它的代码。
对于这个实现,我将使用 EM(期望最大化)算法。
理论和代码是最好的结合。
首先让我们导入所有需要的库:
import numpy as np
import pandas as pd
我强烈建议在自己实现模型时遵循 sci-kit learn library 的标准。这就是为什么我们将 GMM 作为一个类来实现。让我们也来看看 __init_function。
class GMM:
def __init__(self, n_components, max_iter = 100, comp_names=None):
self.n_componets = n_components
self.max_iter = max_iter
if comp_names == None:
self.comp_names = [f"comp{index}" for index in range(self.n_componets)]
else:
self.comp_names = comp_names
# pi list contains the fraction of the dataset for every cluster
self.pi = [1/self.n_componets for comp in range(self.n_componets)]
简而言之, n_components 是我们想要拆分数据的集群数量。 max_iter 表示算法进行的迭代次数,comp_names 是具有 n_components 个元素的字符串列表,这些元素被解释为聚类的名称。
拟合函数。
因此,在我们使用 EM 算法之前,我们必须分割我们的数据集。之后,我们必须启动 2 个列表。一个包含每个子集的平均向量(向量的每个元素都是列的平均值)的列表。第二个列表包含每个子集的协方差矩阵。
def fit(self, X):
# Spliting the data in n_componets sub-sets
new_X = np.array_split(X, self.n_componets)
# Initial computation of the mean-vector and covarience matrix
self.mean_vector = [np.mean(x, axis=0) for x in new_X]
self.covariance_matrixes = [np.cov(x.T) for x in new_X]
# Deleting the new_X matrix because we will not need it anymore
del new_X
现在我们可以讨论 EM 算法了。
EM 算法。
顾名思义,EM 算法分为两步——E 和 m。
电子步骤:
在估计步骤中,我们计算 r 矩阵。它是使用下面的公式计算的。
计算 r(责任)矩阵的公式(来源——mathematis for Machine Learning Book)
r 矩阵也被称为**‘职责’**,可以用以下方式解释。行是来自数据集的样本,而列代表每个聚类,该矩阵的元素解释如下:rnk 是样本 n 成为聚类 k 的一部分的概率。当算法收敛时,我们将使用该矩阵来预测点聚类。
同样,我们计算 N 个列表,其中每个元素基本上是 r 矩阵中对应列的和。下面的代码就是这样做的。
for iteration in range(self.max_iter):
''' ---------------- E - STEP ------------------ '''
# Initiating the r matrix, evrey row contains the probabilities
# for every cluster for this row
self.r = np.zeros((len(X), self.n_componets))
# Calculating the r matrix
for n in range(len(X)):
for k in range(self.n_componets):
self.r[n][k] = self.pi[k] * self.multivariate_normal(X[n], self.mean_vector[k], self.covariance_matrixes[k])
self.r[n][k] /= sum([self.pi[j]*self.multivariate_normal(X[n], self.mean_vector[j], self.covariance_matrixes[j]) for j in range(self.n_componets)])
# Calculating the N
N = np.sum(self.r, axis=0)
指出多元正态只是应用于向量的正态分布公式,它用于计算向量在正态分布中的概率。
下面的代码实现了它,采用行向量、均值向量和协方差矩阵。
def multivariate_normal(self, X, mean_vector, covariance_matrix):
return (2*np.pi)**(-len(X)/2)*np.linalg.det(covariance_matrix)**(-1/2)*np.exp(-np.dot(np.dot((X-mean_vector).T, np.linalg.inv(covariance_matrix)), (X-mean_vector))/2)
看起来有点乱,但是你可以在那里找到完整的代码。
m 步:
在最大化步骤中,我们将逐步设置均值向量和协方差矩阵的值,用它们来描述聚类。为此,我们将使用以下公式。
M-step 的公式(来源-mathematis for Machine Learning Book)
在代码中,我希望:
''' --------------- M - STEP --------------- '''
# Initializing the mean vector as a zero vector
self.mean_vector = np.zeros((self.n_componets, len(X[0])))
# Updating the mean vector
for k in range(self.n_componets):
for n in range(len(X)):
self.mean_vector[k] += self.r[n][k] * X[n]
self.mean_vector = [1/N[k]*self.mean_vector[k] for k in range(self.n_componets)]
# Initiating the list of the covariance matrixes
self.covariance_matrixes = [np.zeros((len(X[0]), len(X[0]))) for k in range(self.n_componets)]
# Updating the covariance matrices
for k in range(self.n_componets):
self.covariance_matrixes[k] = np.cov(X.T, aweights=(self.r[:, k]), ddof=0)
self.covariance_matrixes = [1/N[k]*self.covariance_matrixes[k] for k in range(self.n_componets)]
# Updating the pi list
self.pi = [N[k]/len(X) for k in range(self.n_componets)]
我们已经完成了拟合函数。创造性地应用 EM 算法将使 GMM 最终收敛。
预测函数。
预测函数实际上非常简单,我们只需使用多元正态函数,该函数使用每个聚类的最佳均值向量和协方差矩阵,以找出哪个给出最大值。
def predict(self, X):
probas = []
for n in range(len(X)):
probas.append([self.multivariate_normal(X[n], self.mean_vector[k], self.covariance_matrixes[k])
for k in range(self.n_componets)])
cluster = []
for proba in probas:
cluster.append(self.comp_names[proba.index(max(proba))])
return cluster
结果。
为了测试该模型,我选择将其与 sci-kit 库中实现的 GMM 进行比较。我使用 sci-kit 学习数据集生成函数生成了 2 个数据集——使用不同的设置生成 _ blobs。这就是结果。
我们的模型与 sci-kit learn 模型的比较。
我们的模型和 sci-kit 模型的聚类几乎相同。很好的结果。完整的代码你可以在那里找到。
来源——tenor.com
这篇文章是西格蒙德和❤一起写的。
有用的链接:
- https://github . com/science kot/mysklearn/tree/master/Gaussian % 20 mixture % 20 models
- https://en . Wikipedia . org/wiki/Expectation % E2 % 80% 93 最大化 _ 算法
- 用于机器学习的数学由 Cheng Soon Ong、Marc Peter Deisenroth 和 A. Aldo Faisal 编写
高斯混合模型与 K-均值。选哪个?
两种流行聚类算法的性能比较
G.混合物对 k .平均(1957)。帆布油画。顺便说一句,没有明显的赢家。伯明翰博物馆信托基金会在 Unsplash 上拍摄的照片
K -Means 和高斯混合(GMs)都是聚类模型。然而,许多数据科学家倾向于选择更流行 K-Means 算法。即使 GMs 可以证明在某些聚类问题上是优越的。
在本文中,我们将看到这两种模型在速度和健壮性方面提供了不同的性能。我们还将看到,使用 K-Means 作为 GMs 的初始化器是可能的,这有助于提高聚类模型的性能。
它们是如何工作的
首先,让我们回顾一下这些算法的理论部分。这将有助于我们在文章的后面理解他们的行为。
k 均值
K-Means 是一种流行的非概率聚类算法。该算法的目标是最小化失真度量J。我们通过以下迭代程序实现这一点【1】:
- 选择集群的数量 K
- 初始化定义每个聚类中心点的向量 μ_k
- 将每个数据点 x 分配到最近的聚类中心
- 为和每个集群重新计算中心点 μ_k
- 重复 3–4,直到中心点停止移动
下面的 GIF 很好地说明了这个迭代过程:
K=3 时的 K 均值。重新计算每个聚类的数据点标签和平均值,直到收敛。【来源】
K-Means 算法将收敛,但它可能不是全局最小值。为了避免收敛到局部最小值的情况,K-Means 应该用不同的参数重新运行几次。
K-Means 执行硬分配,这意味着每个数据点必须属于某个类,并且没有分配给每个数据点的概率。
K 均值的计算成本是 O(KN),其中 K 是聚类的数量,N 是数据点的数量。
高斯混合
高斯混合基于 K 个独立的高斯分布,用于建模 K 个独立的聚类。提醒一下,多元高斯分布如下所示:
多元高斯分布。 μ 是 D 维均值向量, ∑ 是 DxD 协方差矩阵。修改自[1]
高斯混合的推导是相当复杂的,所以为了更深入的数学解释,我建议看看这篇文章。
关于 GMs 要知道的最重要的事情是,这个模型的收敛是基于 EM(期望最大化)算法的。它有点类似于 K-Means,可以总结如下[1]:
- 初始化 **μ,∑,**和混合系数 π 并评估对数似然 L 的初始值
- 使用当前参数评估责任函数
- 使用新获得的职责获得新的 **μ、∑、**和 π
- 再次计算对数似然 L。重复步骤 2–3,直到收敛。
高斯混合也将收敛到局部最小值。
通过下面的 GIF,我们可以很容易地看到高斯混合的收敛情况:
高斯混合的收敛性。【来源】
K-均值和高斯混合的第一个明显区别是决策边界的形状。GMs 更加灵活,使用协方差矩阵 ∑ 我们可以使边界为椭圆形,与使用 K-means 的圆形边界相反。
还有一点就是 GMs 是一个概率算法。通过将概率分配给数据点,我们可以表达我们对给定数据点属于特定聚类的信念有多强。
使用每个数据点属于某个簇的概率的簇的软分配。图片作者[1]
如果我们比较这两种算法,高斯混合似乎更稳健。然而,GMs 通常比 K-Means 慢,因为它需要 EM 算法的更多迭代来达到收敛。它们也可以快速收敛到局部最小值,这不是一个非常理想的解决方案。
在本文的剩余部分,我们将使用 Scikit-learn 库来研究这些模型在实践中的表现。
比较性能
我们将从为此任务创建一个合成数据集开始。为了使它更具挑战性,我们将创建 2 个重叠的高斯分布,并在边上添加一个均匀分布。
生成的数据集如下所示:
聚类形状
让我们动手用 K-Means 和高斯混合进行初始聚类。我们将使用从 Scikit-Learn 导入的模型。此外,我们将以相同的方式为两种模型设置参数。两个模型的最大迭代次数、聚类数和收敛容差设置相同。
从聚类数据的第一眼看,我们可以看出它们的表现并不太好。虽然 K-Means 以与真实聚类相似的方式对数据进行聚类,但是 GM 聚类看起来相当不可靠。
k 均值+高斯混合= ❤️
GMs 的问题是它们很快收敛到局部最小值,这对这个数据集来说不是很理想。为了避免这个问题, GMs 通常用 K-Means 初始化。这通常工作得很好,它改善了用 K-Means 生成的聚类。我们可以通过改变 GaussianMixture 类中的一个参数来创建带有 K-Means 初始化器的 GM:
我们还可以利用 GMs 的概率特性。通过添加阈值,在本例中为 0.33,我们能够标记模型不确定的带标签的数据点。这里变得非常有趣,因为对于普通 GM 来说,大多数数据点的概率都很低,如下图所示。
此外,具有 K 均值初始化器的 GMs 似乎表现最好,并且聚类几乎与原始数据相同。
计算时间
现在让我们看看这些算法的计算时间。结果相当令人惊讶。计算时间是用不同数量的聚类和上述所有 3 个模型来测量的。
结果是:
很奇怪,普通的 K-Means 比带有 K-Means 初始化器的 GM 要慢。在幕后,Scikit-Learn 似乎应用了 K-Means 的优化版本,它需要更少的迭代来收敛。
此外,香草转基因需要很短的时间。这是因为它很快就找到了一个局部最小值,而这个最小值甚至还没有接近全局最小值。
那么我应该选择哪种算法呢?
如果你寻找鲁棒性,带有 K-Means 初始化器的 GM 似乎是最好的选择。如果你用不同的参数进行实验,K-Means 理论上应该更快,但是从上面的计算图中我们可以看出,带有 K-Means 初始化器的 GM 是最快的。GM 本身并没有太大的用处,因为它对于这个数据集收敛得太快而不是最优解。
感谢您的阅读,希望您喜欢这篇文章!
关于我
我是阿姆斯特丹大学的人工智能硕士学生。在我的业余时间,你可以发现我摆弄数据或者调试我的深度学习模型(我发誓这很有效!).我也喜欢徒步旅行:)
如果你想了解我的最新文章和其他有用的内容,以下是我的其他社交媒体资料:
参考
GPflow 中分子的高斯过程回归
这篇文章演示了如何通过创建自定义的 Tanimoto 内核来操作摩根指纹,使用 GPflow 库训练高斯过程(GP)来预测分子属性。请访问我的 GitHub 回购Jupyter 笔记本!
在这个例子中,我们将尝试预测实验确定的分子光开关的电子跃迁波长,这类分子在光照射下会发生 E 和 Z 异构体之间的可逆转变。
图片来自光电开关数据集论文
要事第一,依赖!
conda create -n photoswitch python=3.7
conda install -c conda-forge rdkit
conda install scikit-learn pandas
pip install git+https://github.com/GPflow/GPflow.git@develop#egg=gpflow
我们将从导入我们将要使用的所有机器学习和化学库开始。
对于我们的分子表示,我们将使用广泛使用的摩根指纹。在这种表示下,分子被表示为位向量。因此,标准高斯过程核,如平方指数核或 Matern 核,在设计时会考虑到连续空间,因此不太理想。然而,我们可以定义一个自定义的“Tanimoto”或“Jaccard”内核,作为我们的位向量之间的相似性度量。
在代码方面,在 GPflow 中定义一个定制的 Tanimoto 内核相对简单
下面的定义与上面给出的等式略有不同,因为我们计算的是矩阵输入的 Tanimoto 相似性。
接下来,我们读入光开关分子,用微笑串表示。我们预测的性质是每个分子的 E 异构体的电子跃迁波长。一般来说,对于任何数据集,GP 只需要一个分子微笑列表和一个属性值数组。
我们使用键半径 3 将我们的分子转换成 2048 位摩根指纹。我们用 X 表示分子,用 y 表示属性值。我想这可能会更容易跟踪输入和输出是什么!
我们定义一个效用函数来标准化我们的输出值。在安装全科医生之前,这是典型的良好做法。请注意,虽然代码也支持输入的标准化,但我们稍后将选择不使用它。原因是标准化一个位向量,而不是一个实值向量,似乎没有太大的意义(至少对我来说!).
我们定义了 80/20 的训练/测试分割。
接下来我们安装 GP。我们可以检查学习到的核超参数,尽管在位向量的情况下这些参数可能不那么有用!
现在我们可以输出训练并测试均方根误差(RMSE)、平均绝对误差(MAE)和 R 值。
Train RMSE (Standardised): 0.036
Train RMSE: 2.422 nm
Test R^2: 0.916
Test RMSE: 17.997 nm
Test MAE: 11.333 nm
还不错!在我们的论文中,我们将 GP-Tanimoto 模型的预测与一群人类光开关化学家的预测进行了比较,在组成测试集的所有 5 种分子的情况下,这些预测实现了更低的测试误差:
MAEs 是在所有人类参与者的每个分子的基础上计算的。图片来自光电开关数据集论文
GPs 的一个定义特征是它们能够产生校准的不确定性估计。在分子发现活动中,这些不确定性估计有助于捕捉模型的可信度;如果测试分子与训练中看到的分子非常不同,模型可以告诉你这是猜测!
用程序术语来说,可以通过检查变量 y_var 来访问测试集的不确定性。人们可以通过例如以下方式获得预测的排序置信度列表
其输出一个列表,在该列表中分子(由它们的测试集索引表示)通过它们的预测置信度被排序。下面的脚本提供了进一步的细节
从图形上看,可以生成置信-误差曲线,以检查 GP 获得的不确定性实际上与测试集误差相关。
图片来自光开关数据集论文。
在 x 轴上方的图中,置信百分点可以简单地通过根据该测试输入位置处的预测方差对测试集的每个模型预测进行排序来获得。例如,位于第 80 个置信百分位数的分子将是具有最低模型不确定性的 20%测试组分子。然后,我们测量 200 个随机训练/测试分割的每个置信百分点的预测误差,以查看模型的置信与预测误差是否相关。我们观察到 GP-Tanimoto 模型的不确定性估计与预测误差正相关。
从该图中得到的实际收获是一个概念证明,即模型不确定性可以被结合到选择在实验室中物理合成哪些光开关分子的决策过程中;如果一个“未合成”分子的预测波长值是所期望的,并且这个预测的可信度很高,那么你可能想要实现它!
GPs 的另一个好处是:通过检查学习到的内核,有可能解释不同分子表示捕获的化学。更多详情请见我们的论文!
图片来自光电开关数据集论文。
图归功于艺术上不知疲倦的雷蒙德·塔瓦尼。请在 Twitter 上寻求评论/反馈/讨论!如果你觉得这篇文章中的数据或实现有用,请考虑引用以下文章:
GPflow 中的 Photoswitch 数据集和 Tanimoto GP 实现:
@article{Thawani2020,
author = "Aditya Thawani and Ryan-Rhys Griffiths and Arian Jamasb and Anthony Bourached and Penelope Jones and William McCorkindale and Alexander Aldrick and Alpha Lee",
title = "{The Photoswitch Dataset: A Molecular Machine Learning Benchmark for the Advancement of Synthetic Chemistry}",
year = "2020",
month = "7",
url = "https://chemrxiv.org/articles/preprint/The_Photoswitch_Dataset_A_Molecular_Machine_Learning_Benchmark_for_the_Advancement_of_Synthetic_Chemistry/12609899",
doi = "10.26434/chemrxiv.12609899.v1"
}
GPflow:
@article{GPflow2017,
author = {Matthews, Alexander G. de G. and {van der Wilk}, Mark and Nickson, Tom and
Fujii, Keisuke. and {Boukouvalas}, Alexis and {Le{\'o}n-Villagr{\'a}}, Pablo and
Ghahramani, Zoubin and Hensman, James},
title = "{{GP}flow: A {G}aussian process library using {T}ensor{F}low}",
journal = {Journal of Machine Learning Research},
year = {2017},
month = {apr},
volume = {18},
number = {40},
pages = {1-6},
url = {http://jmlr.org/papers/v18/16-537.html}
}
谷本内核的创始人
@article{ralaivola2005graph,
title={Graph kernels for chemical informatics},
author={Ralaivola, Liva and Swamidass, Sanjay J and Saigo, Hiroto and Baldi, Pierre},
journal={Neural networks},
volume={18},
number={8},
pages={1093--1110},
year={2005},
publisher={Elsevier}
}
此处的所有图像受 CC BY-NC 许可的版权保护。
高斯过程:制定你自己的人生目标
我们可以使用贝叶斯优化来调整我们的模型,但你知道它可以做得更多吗?
我在之前谈到过如何使用高斯过程来拟合模型超参数的替代函数,然后使用贝叶斯统计在少量迭代中找到最佳参数。这可以简单地用 sci-optimize 包中的几行代码( BayesSearchCV )来完成。如果你想要更多的数学链接,这是一个很好的选择。
但是,您可以更深入地挖掘,并相对容易地构建自己的目标函数。
我们为什么要这么做?
很高兴你问了。简单地说,如果你能想到一个优化问题和评估它的方法,你可以使用高斯过程(GP)来解决它。
唯一的警告是,它必须是昂贵的评估(无论是检索时间或成本)。如果你有一个只需要几秒钟就可以评估的东西,那么这个方法虽然很酷,但由于它增加了大量的计算开销,所以不是最有效的选择。这是因为每当你得到一个新点时,它必须重新计算并拟合一个代理分布到它已经评估过的所有点,因此它的性能随着迭代次数的增加而降低(这是一个 O(N)问题)。
因为我相信你会问,如果从随机抽样开始评估是不是既便宜又快捷。它通常会给出有竞争力的结果,因为它可以在 GP 只能做几个的时间内完成大量的评估(开销成为一个瓶颈)。random 在这里表现如此之好的原因纯粹是统计学上的,因为你可以执行的计算次数越多,你的猜测中至少有一个没有落在可接受区域内的概率就越低。
照片由юліявівчарик在 Unsplash 上拍摄
我们会在哪里使用它?
使用范围相当广泛,例如:
- 调整工厂生产线设置以获得最佳质量输出
- 从大量组合中选择最佳药物或化学成分
- 调整路段上的交通灯以辅助交通流量和行人行走
- 优化您的上班旅行时间
- 平衡您的散热器,使它们辐射相同的温度
最后一个听起来有点疯狂,但它是一个你可以使用它的应用程序,如果我发现我的房子里有一个寒冷的房间,我可能会在这个冬天使用它。
一般来说,在运行优化时,如果行为没有太大的变化,这种方法非常有效。这不同于噪声数据,因为你可以添加元素来处理它(比如一个白核
好吧,那我们怎么做?代码时间!
当我说高斯过程时,我的意思是我们将高斯函数拟合到我们的数据(替代模型),然后使用贝叶斯统计来预测基于该拟合的最可能的下一个值。
我将从一个问题开始,从一个挤压材料切割 4x4cm 厘米的碎片。我能做的就是移动两个刀具(一个上下,一个左右)。你会(正确地)猜测,如果我把每个切刀放在 4 厘米的地方,我就会得到我想要的。
如果我现在让一台计算机做这件事,但是我没有告诉它我想要什么或者怎么做(除了它能移动刀具之外),那么它会怎么做?我可以使用随机猜测,但我希望它在得到正确答案之前,通过切割最少的部分来找到正确的答案。进入高斯过程!
我不能只告诉它“否”或“是”,因为它需要知道自己做得有多好,好了多少。即每次它做出猜测时,它都需要学习一些东西。因此,对于这个例子,我将在一个尺度上评分,如果它完全正确,就给它 100%,否则我将在这一点周围的半径内评分(我如何做,我将在后面讨论)。
如果你想象一下我会如何给刀具位置评分,它会是这样的:
刀具位置如何分级(最佳值为 4x4cm)
正如你所看到的,如果两个切刀都在 4 厘米处,我会给满分,轮廓被标记为我如何分级,因为它越来越远。
因此,要设置代码,我们需要首先定义它可以搜索的参数空间:
from skopt.space import Real# Define the parameter space types and ranges
space = [Real(0, 10, prior='uniform', name='Cutter #1'),
Real(0, 10, prior='uniform', name='Cutter #2')]
我们在这里所做的是设置一个“1 号刀具”和“2 号刀具”的参数空间,并表示我们想要一个介于 0 和 10(这是刀具可以移动的厘米数)之间的实值(所以是浮点型)。我们设置的先验是“统一的”,因为我们希望它认为所有的值都具有同等的可能性。最后,我们将其命名为,这不是必需的,但是当稍后在目标函数中处理这些值时,这样会减少混淆。
**注意:**您也可以指定整数和类别,所以您不仅仅局限于浮点数。
现在我们有了这个,我们需要创建我们的目标函数。该函数的作用是从 GP 中获取每组建议的参数,然后对其进行评估/评分。GP 将使用这些分数来尝试最小化这个目标函数。
from skopt.utils import use_named_args
from scipy.stats import norm# Value is just used to standardise "value" to be from 0 to 100
max_value = norm(0).pdf(0)**2[@use_named_args](http://twitter.com/use_named_args)(space)
def objective(**params):
"""
Returns our quality judgement for each set of parameters given
""" # Calculate quality based on two gaussians
cutter_1 = norm(4,1).pdf(params['Cutter #1'])
cutter_2 = norm(4,1).pdf(params['Cutter #2'])
value = cutter_1*cutter_2
# Standardise the value to be from 0 to 100
value = value/max_value*100
# Because it is minimising we have to make value negative
value = -1*value
return value
这是怎么回事?嗯,内容有些随意(正如您将读到的),但这里最重要的部分是“@use_named_args(space)”。这意味着每当函数接收到参数(一组要评估的猜测值)时,它们将被存储在变量“params”中,我可以使用前面为“space”定义的名称来提取它们。
对于本例,我之前将这两个参数命名为“1 号刀具”和“2 号刀具”,我可以通过以下语句在我的目标函数中访问它们的值:
# Access value for 'Cutter #1'
params['Cutter #1']
# Access value for 'Cutter #1'
params['Cutter #2']
这对复杂空间特别有用,有助于跟踪变量。
这个函数的其余部分就是我如何计算要返回的“分数”。有趣的是,我决定用两个高斯值(平均值为 4,标准差为 1)对结果进行分级。通过给每个轴分配一个高斯值,然后将它们相乘,我得到了一个围绕我想要的值的漂亮的“圆锥”形状。然后我可以调整这些,使我的判断更严厉(非常尖锐)或不严厉。
我计算一个“max_value”在它之前是这两个高斯的峰值。这是因为我可以标准化它,给出 0 到 100 的质量分数。
我们必须将该值反转为负值,因为该过程将尝试最小化该值。如果我不这样做,优化将与我想要的相反(选择可能的最差切割)。
注意:我同样可以从正确的位置得到猜测的直线距离并返回。这也是可行的。
让一切运转起来
我们现在可以定义高斯过程并让它运行:
from skopt import gp_minimize# GP process settings and return results stored in "res"
res = gp_minimize(objective, space, n_initial_points=2, n_calls=20,
verbose=True)
这里的“目标”和“空间”就是我们刚刚定义的函数和参数空间。“n_initial_points”是在开始使用数据点进行拟合并做出明智选择之前,您希望它首先生成的随机点数。在这里,我将它设置为 2(这是最小值),以便您可以看到它更快地做出明智的选择,但在现实生活中,您通常希望这个值更高(10 左右),以便您可以很好地覆盖参数空间。这减少了你错过另一个更好的解决方案的机会,并且你不仅仅是陷入了你找到的第一个极小值。
“n_calls”是你想做的迭代次数。此外,值得注意的是“n_initial_points”也从这里获得其分配(因此只有 18 个点将从高斯分布中拟合和估计)。
“verbose”是我设置的最后一个参数,通过将其设置为“True ”,我可以获得关于优化进展情况的信息。
优化的结果存储在“res”中,我们可以在以后查询它。
结果
因为我们将函数设置为 verbose,所以我们得到以下输出:
前五次迭代的输出
如果你记得前两个步骤是随机的,但它随后使用这两个点作出明智的猜测。当我们查看前五次迭代时,我们可以看到它发现的当前最小值在变化,并且变得越来越负(记住我们将分数设为负,这样它会适当地最小化)。
如果我们绘制这五次迭代,它看起来像这样:
根据得分值按顺序显示前五次迭代
在上面的例子中,我们可以看到前两次猜测都是错误的,但是一旦它停止了随机猜测,它就开始返回并在开始的地方附近寻找。在第五步,它已经搜索到更远的地方,但稍微接近 4 厘米和 4 厘米的最佳位置。
我还画出了它在 20 次迭代中找到的最佳位置,我们看到它确实找到了这个最佳位置。想象我们得到的所有步骤:
最佳参数的 20 次迭代的可视化
这里我们可以看到,该算法相对较快地(20 步)找到了最佳位置。这意味着,在我得到一个近乎完美的切割之前,我只需要接受 19 次糟糕的切割。
因为我们将结果存储在“res”中,所以我们可以通过访问各种键来查询它:
# Print out the best position found
res.x
>>> [3.973487161623168, 3.9749779608581903]
# Print out the value for the best position found
res.fun
>>> -99.93357042213998
非常接近!你必须记住,它根本不知道我们想要 4x4cm 的尺寸。它只知道对自己的努力有多高兴或多不高兴。
我们还可以通过访问“x_iters”和“func_vals”来访问返回的所有步骤和质量度量(以及我是如何制作图表的):
# Find out how many iterations were done
len(res.x_iters)
>>> 20
正好 20,正如我们将“n_calls”设置为。这个值 20 是任意的,是我为了减少图表的混乱而设置的。如果我将 n_calls 设置得更高,这意味着一旦它达到一个特别好的值,该过程可能会检查参数空间的其他区域,如下所示:
允许超过 20 次迭代时的搜索路径
从逻辑上讲,它这样做是为了验证没有更好的方法可用。如果是,它将在那里搜索,否则,它可能会返回到它找到的最佳值附近,并在它附近搜索,看看它是否可以进一步改善这些值。
**注意:**如果您想要可重复的结果,您可以在“gp _ minimise”中设置一个“random_state”值。
你已经达到目的了!
因此,使用这个简单的例子,我们已经能够建立一个目标函数,并找到我的问题的最佳解决方案。
虽然这看起来工作量很大,但是当你遇到一个不像这样容易计算的问题时,知道如何做是很有用的。
例如,对于我的散热器问题,我可以去调整所有的散热器阀门,等待一个小时,然后读取每个温度。我可能放进去的值是标准差。然后,该函数将尝试将该值降至零,这将表示每个散热器的温度相同。我可能还想减去中间温度,以鼓励算法尽可能将散热器开得更高(而不是把它们都关了,这样才能达到相同的温度!).因此,可以做很多调整。
我希望这是有用的,并希望很快再次见到你!
在 Unsplash 上由 Veronika Nedelcu 拍摄的照片
高斯过程:更智能地调整您的 ML 模型
实践教程
通常情况下,模型的最佳性能取决于正确的参数,但测试每种组合的计算成本太高。使用高斯过程可以有所帮助。
照片由奥拉夫·阿伦斯·罗特内在 Unsplash 拍摄
我想我们都经历过。我们有一个基本的机器学习模型,但它的性能还不太好。幸运的是,许多机器学习算法都有许多旋钮和开关,你可以用来调整它,使其性能更好(例如,你在随机森林中构建的树的深度,或者你的梯度增强算法的学习速率)。
有多个现有函数可帮助您执行此调优,并且 SciKit learn 有几个(仅高层次解释,但给出链接):
- GridSearchCV —在给定的参数范围内尝试每个组合
- 参数网格 —从每个参数允许值的离散列表中构建参数组合
- 参数采样器 —从分配给每个参数的分布中采样参数
- RandomizedSearchCV —类似于 GridSearch,但只随机抽样这么多用户集组合
如果你和我一样,你可能已经用你自己的经验将参数空间限制在你认为可能给出好结果的区域,然后如果组合很小,使用 GridSearchCV,否则可能使用 RandomizedSearchCV 来获得你在剩下的时间里可以找到的最佳组合。
通常,我发现我做的很多项目都是全新的蓝天,所以数据集是不完整的,支离破碎的,非常脏。这意味着数据科学的格言“80%的数据清理和 20%的其他事情”在我的案例中经常是正确的。当训练模型的计算成本很高时,搜索 10,000 个(甚至 100 个)组合的大参数对于满足交付期限是不实际的。
蒂姆·高在 Unsplash 上拍摄的照片
我们能做什么?
我很高兴你问了。你可能已经看到或者没有看到关于使用 Scikit-Optimize 的信息,但是如果你还没有或者不确定如何使用它来调整你的模型,那么请继续阅读。
那么,是什么呢?
它的核心是一组函数,使您能够对评估代价高昂的问题进行建模。这种开销可能是因为获得参数组合的结果需要很长时间,也可能是因为彻底解决问题的计算成本很高。
在我的工作生涯中,我用它来解决这两个问题。
对于“评估每个组合的等待时间过长”的问题,它被用来收集数据,以建立生产线的机器学习模型。每次算法建议尝试一组新的参数时,都需要花费很长时间来返回结果(生产线需要达到稳定状态,然后需要有人取走样品,将其带到测试实验室并运行测试来分析产品输出,进一步增加了等待时间),由于测量的成本,只能获取这么多的数据点。由于这个限制,我们使用这个解决方案来获取最有价值的数据点。
我将谈到的第二种用法(无法测试每种可能的组合)是,尝试调整模型的参数组合在计算上太过昂贵,我会老死。
SciKit Optimise 为您提供了许多工具,但我将集中讨论我使用最多的一个工具,即 gp_minimize。它的主要描述是“使用高斯过程的贝叶斯优化”,这是一项了不起的任务,只需要向已经知道它是什么的人解释它是什么。
在高层次上,如果您知道从数据中获得的基本分布,您就可以预测某些事件发生的概率。如果你有一个均匀分布,那么你知道在指定范围内的任何值都是同样可能的,但在生活中,情况并不总是这样。如果我向靶心投掷飞镖,你会认为我的大部分命中目标可能离靶心更近而不是更远。但也许我不是最好的射手,我总是倾向于击中某个特定的点而不是靶心。那么我们如何辨别呢?
如果我拍了 100 张照片,我们只是测量了从靶心开始的水平距离,并制作了直方图,我们可能会得到这样的照片。
由此可能有点难以确定我们认为我可能会再次击中哪里。但是如果我们对它进行分布拟合,图形会变成这样:
来自 100 个样本的结果符合具有估计参数的高斯分布(真值在括号中)
在视觉上,它对用户来说变得更加清晰。此外,因为我们知道分布的数学定义,我们不仅可以询问我的平均值在哪里,还可以询问我投篮的分布。
有必要说明一下,如果我拍摄了 1000 张照片,图表看起来会是这样:
用估计参数拟合高斯分布的 1000 个样本的结果(括号中为真)
拟合的分布要精确得多,但是你也可以说你不需要它来直观地询问你得到的形状。
那你用的是什么形状?
我用的是高斯分布。这是一个常用的发行版,因为它不仅比其他发行版更容易使用,而且自然界中的许多过程都可以这样建模。
这有什么关系?
好吧好吧。因此,这里的关键点是,对于 100 点与 1000 点的图表,拟合分布使您更容易看到发生了什么,可以说,有了它,您可以用比 1000 点图表少 900 个数据点的方式很好地估计实际值。我们正在对数据进行分布拟合,以表明我们认为最可能的点在哪里。
高斯过程使你能够用最少的数据提取尽可能多的信息
高层次的方法是:
1.获取一组初始数据点
2.对其进行分布拟合(在本例中为高斯分布)
3.读出你认为将在你的分布的最大值的结果区域
4.测试它并返回结果
5.根据您的数据重新调整分布,包括这个新点
6.回到步骤 3
在机器学习中,我们可以用树木的数量来构建一个随机的森林。我们测试几个不同的参数,计算训练模型的准确性,并返回这些参数。高斯过程将适合这些点,并尝试计算出哪一个树值给你最大的准确性,并要求你尝试一下。这导致两种结果:
如果精度增加,那么高斯拟合将变得更清晰
如果它是错误的,那么拟合将变平,它将开始看得更远
机器学习的问题是
随着我们添加超参数,我们开始添加更多的维度,我们可以想象对于两个参数,我们最终得到一个显示模型精度的图,如下所示:
超参数设置对模型性能的影响。三个最小值是显而易见的。
在这个例子中,我们可能有不止一个区域显示出模型性能的改进。这一过程的巨大优势在于它有能力以一种智能的方式描绘出这一点。
我们可以看一些例子(取自这里)来展示这个拟合过程。
贝叶斯优化如何随着我们添加更多数据点而改变的例子(来源
在这里,我们可以看到正在探索空间,当它达到第一个最小值时,它需要几个样本来建立它,然后继续探索它认为可能会得到更好结果的地方。在这个过程的最后,它会给你在这个过程中找到的最佳点。
在模型调优中,考虑到您给定的搜索限制,这将是模型的最佳参数集。
如果你想了解更多这方面的数学知识,我建议你:
让我们来看一些代码
在那篇冗长的引子之后,我们可以看看一些代码。我们非常幸运,因为已经存在一个用于调整机器学习模型的简单实现( BayesSearchCV )。
首先,我们需要导入所需的模块和我们想要适应的 ML 算法(我使用的是 gbrtclassifier )。
from skopt import BayesSearchCV
from skopt.space import Real, Categorical, Integer
from sklearn.ensemble import GradientBoostingRegressor
BayesSearchCV 在这里做繁重的工作。它的功能就像一个管道,接收你想要搜索的所有参数值(以及你如何设置它们),你想要调整的机器学习算法,并有大量其他可以改变的设置。
# Initialise the algorithm, search area and other parametersn_data = len(X_train)
opt = BayesSearchCV(
GradientBoostingRegressor,
{
'max_depth': Integer(1, int(n_data / 2),
'learning_rate': Real(0.01, 0.2, prior='log-uniform'),
'subsample': Real(0.1, 0.8, prior='uniform')
},
n_iter=30)# Start the optimisation and return a fitted algorithm
opt.fit(X_train, y_train)
在这里,我们传递算法,并且对于每个超参数空间,我们可以定义范围(一个例子是动态的,因为‘n _ data’是训练数据的行数)以及范围的种类,例如离散、浮点甚至分类。这告诉高斯过程它如何能探索这个空间。“n_iter”告诉它可以采样多少个点。我通常发现我在 30+分后开始得到好的结果。这部分是由问题的复杂性决定的,但也取决于你在开始时随机抽取了多少样本(默认情况下,它随机抽取 10 个样本来提供初始拟合)。
瞧啊。你完了!
现在,您已经用几行代码安装并调整了一个机器学习算法。如果您已经定义了问题,那么(哪些参数和范围等。)与从头开始尝试每一个组合相比,您应该可以更快地(和更少的采样)获得更好的结果。
照片由 Camylla Battani 在 Unsplash 上拍摄
还有一件事…
这个预建的功能不是你唯一能做的。你可以定义自己的目标来最小化。这非常有趣,因为你可以用它来优化非常复杂的问题。
例如,如果您对机器学习算法的纯分数不感兴趣,而是对它如何影响另一个函数感兴趣,您可以编写一个返回此值的目标函数。基本的规则是,如果你能把它压缩成一个值,回到高斯过程,你就可以写一个函数来最小化它。
下次见!
GAVRO —托管大数据模式演进
构建一个适应变化的数据接收架构不是很好吗?更具体地说,对模式演变具有弹性。
图片来源Pixabay.com
对于架构师和软件工程师来说,管理模式变更总是很麻烦。构建大数据平台没有什么不同,管理模式演变仍然是一个需要解决的挑战。NoSQL、Hadoop 和读取模式的咒语在一定程度上缓解了严格的模式执行的束缚。然而,集成开发人员、分析师和数据科学家在从大数据中提取准确见解时,仍然会受到大量数据争论的阻碍。
“成功的业务”以加速和放大已知数据模式的易变的步伐成长和发展。数据集不是静态的,而且是不断发展的,因此了解业务事实数据在业务的当前和历史时期代表了什么对于做出自信的信息洞察至关重要。
通过这篇文章和附带的 GitHub repo ,我将展示如何使用微软 Azure 技术在大数据平台中管理模式演进。
这是一个在实践中容易被忽略的领域,直到您遇到第一个生产问题。如果没有仔细考虑数据管理和模式演化,人们通常会在以后付出更高的代价。
confluent . io(2020 年 4 月 29 日),模式演变和兼容性。https://docs . confluent . io/current/schema-registry/avro . html # schema-evolution-and-compatibility
作为一名作家,很难决定如何讲述你的故事。我是直接进入技术解决方案,以满足寻找简洁例子的工程师,还是从为什么和动机开始?所以我就交给读者了。如果您想直接进入技术示例,请访问 GitHub repo 。如果你想知道更详细的情况,请继续阅读…
模式管理
如果消费者理解用于写入数据的模式并且该模式从不改变,那么序列化要存储在文件中以供以后分析的数据是相当简单的。
但是,如果模式随着时间的推移而演变,会发生什么呢?它变得有点复杂。
当写模式由于新的业务需求而发展时,消费者(读者)必须理解新模式是何时引入的,以及新模式的定义,以便成功地反序列化数据。未能理解模式更改事件将影响数据处理管道,服务将出错,因为它们无法反序列化数据。
这个问题有几种解决方案……(这绝不是一个详尽的列表)。
发布协调
作者和读者协调他们的积压工作和软件发布。当编写器和读取器应用程序由同一个工程团队开发和维护时,这可能会工作得很好。然而,通常情况下,作者和读者在整个企业中致力于不同的目标和优先级。应该避免通过严格的接口依赖来临时耦合独立的团队积压工作,因为这会抑制敏捷性和交付速度。
模式版本管理
版本化写模式支持向前和向后兼容性管理。提供向前和向后的兼容性可以消除积压和优先级,允许工程团队独立地实现他们的目标。
版本控制通常在两个不同的子主题的上下文中讨论。
主要—主要版本变更通常会破坏系统之间的接口和契约。主要的模式更改通常会阻止读者读取新模式版本写入的数据。向前和向后兼容很困难或不可能。
次要—次要版本变更通常被视为低影响变更。向前和向后兼容通常是可能的。读取器通常会像以前一样继续操作,成功地对数据进行解序列化,而不会升级到模式的最新版本。
构建一个能够适应变化的数据接收架构不是很好吗?更具体地说,是对模式演变的弹性。
下面是我将用来描述如何成功管理模式进化的 Azure 架构。
模式注册表
Kafka 的 Schema Registry 提供了一个在流架构上管理模式演化的很好的例子。Azure Event Hubs 是微软的 Kafka 类产品,目前没有模式注册功能。发布到事件中心的事件被序列化为嵌套在事件中心 Avro 模式体中的二进制 blob(图 1)。我们将很快讨论细节,但本质上发布的事件数据是无模式的,任何下游读取器都需要通过在读取时断言模式来对二进制 blob 进行反序列化。有一些巧妙的变通方法,利用了 Confluent 的模式注册表和事件中心。我将在这些建议的基础上,提供一种模式进化弹性的替代方法。在我之前的故事(发展成为 Azure Cloud 中的大数据驱动业务:数据摄取)中,我描述了一个数据湖摄取架构,该架构利用事件中心和事件中心捕获来形成大数据分析的批处理层。我将使用这个架构作为处理模式演变的参考。
图一。
{"type":"record",
"name":"EventData",
"namespace":"Microsoft.ServiceBus.Messaging",
"fields":[
{"name":"SequenceNumber","type":"long"},
{"name":"Offset","type":"string"},
{"name":"EnqueuedTimeUtc","type":"string"},
{"name":"SystemProperties","type":{"type":"map","values":["long","double","string","bytes"]}},
{"name":"Properties","type":{"type":"map","values":["long","double","string","bytes"]}},
{"name":"**Body**","type":["null","bytes"]}
]
}
活动中心
多少?我应该有几个活动中心?或者换句话说,我应该为我的所有数据使用一个大管道,还是为每种消息类型使用许多小管道?关于卡夫卡的话题,也有人问过同样的问题,但没有明确的答案。有一件事很有可能,不同的用例会偏好不同的方法。如果您关心的只是从 A 到 B 获取消息,或者您正在与您控制之外的架构集成,那么消息可能会通过一个事件中心,一个大管道流动。如果您的一些数据高度敏感,并且您只希望某些订户读取和处理这些数据,或者您可能需要特定的分区策略,这将导致在一个名称空间中采用许多事件中心、许多更小的管道。
大烟斗
- 如果一个事件中心包含许多具有不同模式的消息类型,我们如何正确地识别和反序列化各种消息?
小管
- 当一个事件中心只包含一种消息类型,并且这种消息类型会随着时间的推移而演变时,消费者如何反序列化新版本的消息呢?
乍一看,这些问题似乎毫无关联。然而,它们是同一个核心问题的表现。如何管理数据的去序列化?
事件中心上的所有消息都是二进制的匿名 blobs。一种选择是让消费者推断模式。然而,这种方法是不确定的,并且是基于抽样的,所以推断出的模式只能是一种近似。另一种方法可能是断言消费模式。然而,这意味着使用消息的工程团队暂时与模式的发展相结合,即使是很小的变化。事件中心捕捉为我们提供了一个打破时间耦合的机会,让消费者能够以自己的节奏消费从 t0**开始的数据。但是,如果使用者想要读取和使用由事件中心捕获流程生成的所有 AVRO 文件,他们还需要知道在捕获事件期间使用了哪些写模式来写入二进制消息。这可能是几个月甚至几年的数据。作为消费者,我需要知道模式演变的时间线,否则我将很难利用这些数据。
**井至少从乞讨事件中枢捕获配置。
活动中心捕捉的早期印象可能会让您认为 AVRO 被用来帮助解决上述问题。然而,在阅读了 AVRO 规范之后,似乎只有微小的版本变化是可能的。因此,无法管理重大变更,也不可能有多种消息类型的 AVRO 文件。
事件中心允许我们在发布消息时添加额外的元数据。这些元数据是管理模式演变的关键。
有两种可能的选择。
1)写模式与每个消息一起存储在事件中心客户端属性字典中。这将严重抬高存储成本。
2)消息类型标识符存储在事件中心客户端属性字典中。然后,该标识符用于从中央存储中查找模式。
对于这两种解决方案,模式总是直接或间接地与数据存储在一起。Event Hub Capture 生成的文件总是有一种识别写模式的方法。此外,每个文件可以包含 x 个消息类型和 y 个消息版本。
让我们来看一个使用客户端 SDK 将消息发布到 Event Hub 的 Azure 函数。
模式标识符总是存储在数据旁边(第 17 行)。
Azure 函数
在上面的例子中,函数使用一个定时器触发器每 5 秒执行一次函数的新实例。函数触发器是不相关的,它可以很容易地成为一个 CosmosDB 变更提要处理绑定或任何其他生成待处理数据的绑定。而且,用功能 app 也无关紧要,重要的是你发布到事件中枢的内容。函数 app 本身就是一个简洁的例子。
需要注意的是,通过添加对 eventData.Properties 的引用,消息的模式版本与消息一起被持久化。当事件发布到事件中心时,模式标识符总是与数据一起存储。
事件中心捕获
我将事件中心捕获配置为每分钟或每 500mb 生成一个新的 AVRO 文件,以先到者为准。因此,我们现在有了模式标识符和在整齐分区的 AVRO 文件中捕获的数据,但是我们如何在大数据管道中处理它呢?在我之前的故事中,我讨论了维护模式存储库的主题,以获取所有企业模式的真实描述。这种回购是用来创造一个人工制品,将在数据处理管道消费。这个产品是一个简单的键值存储,将版本化的模式标识符与所使用的写模式连接起来。出于本文的目的,我将使用一个简单的 Databrick Python 笔记本来处理 AVRO 数据。
数据块—笔记本
我不会对完整的笔记本进行详细描述,而是关注最重要的单元(完整的笔记本在 GitHub repo 中)。
AVRO 非军事化
首先是读取事件中心数据捕获 AVRO。Spark 的 AVRO dataframeReader 用于从存储器中读取 AVRO 文件,并将它们解编为数据帧。我们可以让 Spark 在这一点上推断模式,因为我们知道它是非易失的(即 Azure Event Hub 模式)。properties 属性保存用于将数据写入二进制字段“Body”的模式版本信息。对数据进行简单的投影,以处理具有三列的精确数据帧。模式版本是从 properties 对象中提取的(序列化属性字典中的存储值存储在子属性 member2 中)。“Body”属性被转换成一个字符串,因为我们想在后面的笔记本中对它使用 spark 的 JSON 反序列化器。
**from** pyspark.sql.functions **import** colrawAvroDf = spark.read.format("avro").load("wasbs://" + containerName + "@" + storageAccName + ".blob.core.windows.net/gavroehnamespace/gavroeh/*/2020/*/*/*/*/*.avro")avroDf = rawAvroDf.select(col("Properties.SchemaVersion.member2").alias('SchemaVersion'), col("Body").cast("string"))display(avroDf)
模式查找
第二个是模式查找对象。出于简化示例的目的,我将手动创建一些模式,用于反序列化 AVRO 数据。然而,在实践中,这些模式将从模式存储库中生成,并作为运行时工件存储。自我提醒,需要将此作为后续文章来写。
存储在一维数组中的模式代表一个已经进化的实体。在这个理论上的例子中,企业已经成长并开始以新的货币进行海外交易。交易现在需要货币标识符,因此在销售订单数据模式中添加了一个新的属性“currency”。作为读者,我们需要能够成功地对新数据进行反序列化。
**from** pyspark.sql.types **import** StructType, StructField, LongType, StringType, ArrayType, DoubleTypesalesOrderV1 =StructType([StructField('OrderId',StringType(),**True**),StructField('OrderAmount',DoubleType(),**True**),StructField('OrderCreatedUTC',StringType(),**True**)])salesOrderV2 =StructType([StructField('OrderId',StringType(),**True**),StructField('OrderAmount',DoubleType(),**True**),StructField('Currency',StringType(),**False**),StructField('OrderCreatedUTC',StringType(),**True**)])salesOrderSchemaDictionary = { "v1.0":salesOrderV1, "v2.0":salesOrderV2 }salesOrderSchemaDictionary
JSON 去军事化
我想关注的第三个单元是实际读取数据并对数据进行反序列化的单元。先前读入数据帧的事件中枢数据捕获输出用于确定数据中存在的模式版本的不同列表。对于每个模式版本,将创建一个新的临时 SparkSQL 表来访问反序列化的数据。原始 AVRO 数据帧在“for”循环的每次迭代中被过滤,通过不同的模式版本对记录进行分组以产生数据子集。然后,使用 salesOrderSchemaDictionary 中的相应模式对每个子集进行反序列化。将创建许多新的临时表,该单元的输出将显示已创建对象的列表。
**from** pyspark.sql.functions **import** concat, lit, regexp_replacedistinctSchemaVersions = avroDf.select('SchemaVersion').distinct()objectToCreate = distinctSchemaVersions.withColumn('TableName', concat(lit('SalesOrder'),regexp_replace(col('SchemaVersion'), '[.]', '_'))).collect()display(objectToCreate)**for** record **in** objectToCreate:schemaVersion = record.SchemaVersionjsonRdd = avroDf.filter(col("SchemaVersion") == schemaVersion).select(avroDf.Body)objectJson = jsonRdd.rdd.map(**lambda** x: x[0])dataExtract = spark.read.schema(salesOrderSchemaDictionary[schemaVersion]).json(objectJson)dataExtract.registerTempTable(record.TableName)
最后
最后,SparkSQL 可用于探索临时表中成功的去序列化数据。
%sql
**select** * **from** SalesOrderv1_0%sql
**select** * **from** SalesOrderv2_0
结论
我应该先弄清楚伽弗洛是什么。抱歉让你失望了,但这不是你不知道的新 Apache 孵化器项目。我的同事给我在本文中描述的方法起了一个可爱的名字。我相信这是我的首字母和 AVRO 的组合,起初我发现他们对这种方法的昵称是团队友谊的产物,但后来它坚持下来了。
我不相信设计和规定方法是完全精确的,应该无条件地适用于每个企业,因为每个企业都是不同的。因此,如果你从阅读这篇文章中学到了什么,那么我希望它是思考你的大数据管道中糟糕管理的模式演变的内涵的动力。我们一次又一次地听到组织在从大数据中提取信息和可操作的洞察力方面遇到的困难,以及数据科学家浪费 80%的时间在数据准备上是多么昂贵。如果应用得当,模式管理是一种武器,可以用来加速数据理解和减少洞察时间。所以花时间投资它,你会收获健康的回报。
引文
[1]沃尔坎·西韦莱克,事件中心模式验证(2019 年 4 月 1 日),https://azure . Microsoft . com/en-GB/blog/Schema-validation-with-Event-Hubs/
[2]马丁·克莱普曼,是否应该把几个事件类型放在同一个卡夫卡主题里?(2018 年 1 月 18 日),https://Martin . kleppmann . com/2018/01/18/event-types-in-Kafka-topic . html
影响
雅虎的 Apache Pulsar 系统:https://Pulsar . Apache . org/docs/en/schema-evolution-compatibility/
Confluent.io 的 Schema-Registry:https://docs . confluent . io/current/Schema-Registry/index . html
杰伊·克雷普斯,《日志:每个软件工程师都应该知道的实时数据统一抽象》(2013 年 12 月 16 日),https://engineering . LinkedIn . com/distributed-systems/Log-What-every-a-software-engineer-should-know-on-real-time-datas-unified
GCP 无服务器设计模式:遵守云任务的速率和并发限制
尽管我认为自己了解与数据工程相关的多种 GCP 产品,但我之前从未听说过云任务的用例。
这篇文章旨在通过提出一个具体的问题,并从发布者与云任务的角度讨论它,来阐明云任务的用例。
挑战
作为客户数据细分项目的一部分,我遇到了将用户数据发送到 Google Ads 再营销受众 API 的挑战,该 API 有以下限制:
- 每个请求只能包含大约 50.000 条用户记录。随着每个请求的记录越来越多,性能会以指数级的速度增长。
- 每个 Google Ads 帐户一次只能处理一(1)个请求。同时提交另一个请求会导致所有其他正在进行的请求出错。
- 每个请求需要一到五分钟来处理。
项目背景:
需要发送给 API 的数据将以 CSV 文件的形式从 BigQuery 到达云存储。每个预期的 CSV 文件将包含 50,000 到 4,000,000 条记录。
编排引擎(Cloud Composer)只负责在 BigQuery 中运行业务逻辑,并将结果保存到云存储中。Cloud composer 不处理传出数据管道,因为传出数据管道应该是反应式的&无服务器的。
要细分的客户群包含大约 400 万客户,每个客户至少属于一个细分市场。编排引擎将在 BigQuery 中运行一个业务逻辑查询——每个片段将被推送到 Google Ads——导致 7 个不同的文件在几分钟内到达云存储。
局部解决
当一个新文件进入云存储时,一个事件可以被提交到 PubSub,或者立即反馈到云功能。更多关于这个的信息在这里。
通过设置从云存储桶触发的云功能,我们可以通过将文件分成更小的部分来解决 api 限制 1(每个请求最多 50k 条记录)。
但是现在呢?简单地循环原始文件并将部分记录推送到 Google Ads 中是一种非常脆弱的处理方式。只需考虑以下几点:
我们期望该函数运行多长时间?
4.000.000/50.000=80 份。假设 50.000 条记录的每个部分需要 5 分钟来传输。我们谈论的是近 7 小时的连续运行时间。这远远超出了云功能所支持的范围。
如果我们已经在传输一个文件了,而另一个文件到达了 GCS 怎么办?
如前一节所述,我们的编排引擎将为每个片段生成一个文件。这意味着,当我们开始向谷歌广告推送第一个片段的大块时,另一个片段将会出现,并并行触发云功能的执行。根据 API 限制的第二(2)点,这将导致两个请求都失败。如果没有某种方法来确保只有一个并发的调度发生,我们将不得不把到达云存储的数据段之间的时间分散开。
Cloud PubSub 的问题(针对本次挑战)
我最初的方法是遵循 Google 设计的这个解决方案中概述的架构: 一个 GMP *的无服务器集成解决方案。*该解决方案结合使用了启动器和传输功能,以及 3 个 PubSub 主题。要了解他们提议的架构,请阅读解决方案的 架构概述 部分。
我认为该解决方案中使用的架构可以精简一点,解释如下:
- 新文件登陆云存储,触发云功能启动器
- Initiator 将文件分割成几个较小的部分,并将它们发布到 PubSub 主题操作日志。
- 完成(2)后,发起方向操作触发器发布主题发送一条空消息
- 操作触发器通过订阅操作执行器推送空消息
- 操作执行器执行并从操作日志中提取信息开始。 如果操作日志中没有消息,则不执行任何操作。循环到此结束。
- 如果从操作日志中检索到消息,操作执行器会尝试将其推送到 Google Ads。
- 如果上一步(6)成功,操作执行器确认之前从操作日志拉取的消息,并向操作触发器发布空消息*。从 4 继续。*
这种方法的问题
我认为这种方法有几个问题:
- 如果操作执行器出错或失败,整个循环可能会中断。如果错误是由 Google Ads API 端错误引起的,您需要在代码中捕捉到这一点,并向操作触发器发送一条空消息以继续循环。这并不符合快速失效的原则(下面会有更多的介绍),而且开发起来更加困难。
- 如果当操作日志中只剩下一(1)条消息时发生上述错误,则该消息不可从操作日志中提取,直到确认截止日期过去。随后执行的操作执行器会认为没有更多的消息,并结束循环。
- 为了遵守 Google Ads API 的限制 2(并发请求),在操作触发器和操作执行器之间只能有一条消息流动。当第二个段文件到达云存储时,这将被违反。
- 我相信调试和理解架构是复杂的。
如果我们没有输出 API (Google Ads)的限制,这个解决方案会更好。
由于这种方法不经过深思熟虑是不可行的,所以我决定寻找替代方法。
云任务简介
云任务是一个分布式任务队列。您可以定义一个或多个可以向其发送任务的队列。队列就像它们听起来的那样。任务是要做的事情,通常定义为“运行这个 HTTP-请求,等待直到你得到一个 200/OK-响应代码”,如果没有,在 X 时间内再试一次。
在一个队列级别上,你有以下(和更多) 设置 :
- 每秒最大分派数:这个队列处理新任务的速度有多快?
- *最大并发调度:*可以同时运行/执行多少个任务?
- *最大尝试次数:*一个任务在进入“失败”状态之前可以尝试多少次?
在一个任务级别上你有以下(和更多) 设置 :
- 任务类型:在本文中,我们将只讨论 HTTP 目标类型。
- HTTP Task HTTP Method:HTTP 方法(GET/POST)
- HTTP 任务请求体:HTTP 请求体。最大 100kb。
请注意,云任务不是一个消息队列(像 PubSub),它只是感兴趣的任务定义,并支持最大 100kb 的请求体来描述在哪里可以找到任何最终数据。
现实生活中的排队。图片来源:https://unsplash.com/photos/Xbh_OGLRfUM 亚历山大·波波夫
云任务的完整解决方案
为了将云任务与我们的部分解决方案集成,我们可以将到达云存储的大传输段文件分解成多个位,并为每个位创建一个任务。我们会将所有这些任务发送到一个任务队列,我们已经将 Max concurrent dispatches 设置为一(1),以避免溢出 Google Ads API。
由于云任务不执行任务(它们只调用 HTTP-endpoint 并等待 200/OK 代码返回),我们将实际的 Google Ads API 调用放在云函数中。
架构概述
利用云任务将一个大请求分解成多个小请求的架构图。
- BigQuery 将结果输出文件写入 GCS。
- 完成写入 GCS 后,云功能任务创建器从 GCS 触发。
- 任务创建者**任务创建者从 GCS 中的触发文件的文件名中获取目标 API 和其他属性,并将其与任务主体中的部分文件的路径一起发送。
- 段队列中的任务被逐一处理,每个调用云函数任务处理程序。
- 对于任务处理程序 的每次调用,它都会解码任务主体并检索 GCS 中部分文件的路径以及 API 配置。然后,它将部分文件推送到 Google Ads,并在完成后向云任务返回 200/OK 响应代码。
这个架构给了我们什么?
云任务充当我们的输入和输出之间的缓冲,确保输出符合 API 的速率限制。
它还通过提供重试层来帮助我们提高开发速度,使我们能够编写集成代码,而很快就会失败。如果任务处理器函数失败,就让它失败,默认发送一个 http-error-code 给云任务。云任务将在适当的时候重试该任务。只要错误是在谷歌广告方面,任务最终将成功执行。
向外扩展
它也很容易向外扩展,以支持谷歌广告中更多的帐户(假设一个广告商活跃在几个国家),我们只需要在云任务中创建额外的队列。我们向任务创建器添加了一些代码,以便它可以动态选择任务队列,还向任务处理器添加了一些代码,以便它可以动态获取 API 凭证/配置。除此之外,可以使用完全相同的功能。
最后的话
这个用例显然不是打算由 PubSub 解决的,我很高兴它不是,因为它教会了我很多关于 PubSub 的局限性。
云任务显然是针对这一领域的问题,这是一个非常容易上手的服务。我强烈建议每个人都尝试一下,因为它可能是处理低性能 API 的最佳(无服务器)服务之一。
我计划在这个集成挑战中结合云任务和 PubSub。我有一个他们如何合作的想法。
如果你想进一步讨论这个问题,或者不同意我提出的任何观点,请随意发表评论。我是来学习的👨💻🤓
性别和人工智能
当前的问题和挑战是什么?
社会对性别的看法正处于临界点。AI 也是如此。那么,这些问题是如何交叉的,我们面临着哪些挑战?
1.艾绝大多数是女性
https://peopleofdesign.ru/2018/04/ios-12-concept/
在美国,94.6%的秘书和行政助理是女性。不出所料,Siri 也是。几乎没有主要的人工智能辅助项目可以避免这个缺陷,也没有太多改进的动力。虽然一些人工智能团队专注于代表性,但其他人提出了进一步的争议。
这些团队正在转向发展“无性别”的声音,以避免批评,但在现实中,有一个“无性别”的声音意味着什么?是我们无法识别为人类的东西,还是属于非二元/酷儿群体的声音?我们是不是在不知不觉中把 LGBTQ+的人推到了二等公民的范畴?为了开发对社会负责的人工智能,我们必须努力解决这些问题。
另一方面,也有视觉人工智能,这里的问题不仅仅是大多数是女性,还有超性感化。毫不奇怪,这种性别化的基调是面向白人,异性恋男子。像前玛奇纳这样的虚构人工智能导致了像 Lil Miquela 这样的“现实世界”名人,Lil Miquela 是一个由人工智能制成的 Instagram 名人/流行明星。
Lil Miquela(取自 Instagram)
虽然她可能是一个经理的梦想,但这个行业的女性已经表示,这种“没有意愿的女人”是她们的噩梦。这是麦莉·赛勒斯《黑镜》那一集的情节,他们把她变成了一个机器人,这样她的经理就可以完全控制她了……男性 AI 名人在哪里?女人什么时候才能摆脱天真、顺从的仆人变成红颜祸水的叙事?AI 好像也没什么帮助。
2.偏见
填空:
男人之于国王,犹如女人之于王后。
父亲之于医生,犹如母亲之于 _ _ _ _ _ _ _ _ _ _。
我说医生,艾一般说护士。
这个问题是由偏见引起的。这个问题源于数据集质量差,没有充分代表或歪曲某个群体。当我们根据这些数据训练我们的模型时,模型也会变得有偏差。这里,我们有一个偏向女性的填空模型,因为它所训练的文本包含了以这种方式反映女性的数据。这个问题不仅在女性中普遍存在,在非二元种族和少数种族中也是如此。
CalArts
在人工智能时代之前,在历史上收集大量数据的领域,这是一个更大的问题,当时偏见没有像今天这样受到重视。例如,大多数过去的医学研究都集中在雄性身上,尤其是在像老鼠这样的动物身上。这是由无数的原因造成的。特别值得注意的是,科学家声称女性的荷尔蒙周期是一个额外的变量。他们说他们无法控制这一点,因此应该将女性排除在研究之外(好像男性没有荷尔蒙)。这种情况有所改善,因为一些现代期刊要求在研究中包括一定数量的女性。然而,关于女性健康的历史数据远远少于我们对男性健康的历史数据,而且许多医学研究继续以这种方式运作。
偏见的另一个流行例子是面部识别,女性面部的错误率更高。对于肤色较深的人来说,这一比例甚至更高。这些问题的答案似乎是收集更好的数据,更有代表性的数据。此外,我们应该继续分别评估不同人口统计的错误率,以便我们可以改进我们的人工智能模型。
然而,如果我们消除了这种偏见,问题就变成了:我们到底应该用性别来通知人工智能的决定吗?很多推荐系统会猜测你的性别(使用你的在线行为),然后根据猜测给出建议。可以吗?它是否强化了性别刻板印象?我们是否需要更好地理解性别,这样我们就可以对男性/女性身体进行分类,并以此为医学提供信息?我们能问同样的关于种族的问题吗?
我们才刚刚开始理解这些问题的重要性以及我们可以回答这些问题的方法。负责的人工智能团队倾向于专注于数据收集以消除偏见,但未能解决这些影响,我们必须将它们进一步置于聚光灯下。
3.工作场所的性别问题
在数据科学职位中,性别薪酬差距并不是特别糟糕,但在数据分析职位中(这些职位通常薪酬较低)。此外,由于该领域是新的,当涉及到就业市场的心理时,存在很大的差距。有人说数据科学领域的每个人都有冒名顶替综合症,但尤其是女性。此外,男性可能会申请符合 50%或以上要求的工作,而女性通常只会申请符合 90%或以上要求的工作。
其他常见的工作场所问题也进入了人工智能世界,如骚扰,尴尬,无意义的权力动态。虽然这些并不是人工智能所特有的,但它们伴随着不平等及其所有后果困扰着科技领域。
女性申请专利的数量也存在差异,产假政策也不恰当。如果我们从数字上看,人工智能的工作场所显然仍然是男性主导的。比如→
https://www . statista . com/chart/4467/female-employees-at-tech-companies/
更令人震惊的是风险投资→
只有 1-2%获得风投资金的初创公司是由女性创始人领导的,尽管女性领导的公司获得了 200%的投资回报。这是科技行业中性别偏见最严重的部分。-帕斯卡尔·冯
宣传手册
是的,你没看错,大约 2%的风投资助的初创企业,比如脸书,是由女性领导的。
宣传手册
数字说明一切。
4.用人工智能将现实生活中的女性商品化
你可能听说过 DeepNude,这是 deep fakes 的一个特殊实例,它处理你选择的一个人的照片,并返回他们完全裸体的图像。这是对神经网络的一种反常使用,安妮·海瑟薇(Anne Hathaway)对市场对性行为的看法——“我们生活在一种将不情愿的参与者的性行为商品化的文化中”——被人工智能不和谐地深化了。
如果人工智能工作场所的差异不是如此极端,这种情况会发生吗?基于人工智能的骚扰或虐待在#MeToo 运动中有一席之地吗?我相信是的,女权主义,就像生活中的其他领域一样,仍然需要赶上科技来保持它的道德性。
来源:
[## 2018 年,所有女性创始人加起来比朱尔少了 100 亿美元
2018 年,女性创始人获得了所有风险投资美元的 2.2%,与 progress 前一年的比例完全相同…
fortune.com](https://fortune.com/2019/01/28/funding-female-founders-2018/) [## 这就是为什么人工智能有性别问题
“对不起,我不知道那个。”Alexa,Cortana,甚至公共交通工具上的自动公告——它们都有…
www.weforum.org](https://www.weforum.org/agenda/2019/06/this-is-why-ai-has-a-gender-problem/) [## 解决人工智能中性别偏见的 4 种方法
对人工智能中偏见的任何检查都需要认识到这样一个事实,即这些偏见主要来源于人类的…
hbr.org](https://hbr.org/2019/11/4-ways-to-address-gender-bias-in-ai)
性别和地域偏见
人工智能、偏见和行业分类
按名称分类的小型企业
目录
1。概述2。背景
3。数据集和数据准备
4.1 偏倚模型:具有性别和姓名来源偏倚的模型
4.2 替换训练数据中的姓名并在推理时
4.3 用附加的性别信息扩充训练数据
5 .分析
6。结论
7。参考文献
这篇文章花了很长时间准备。感谢渥太华大学的米奥德拉克·博利奇教授审阅本文并提供宝贵的反馈。
1。概述
小企业分类指的是查看企业名称,并在上面贴上标签。这是许多应用程序中的一项重要任务,在这些应用程序中,您希望以相似的方式对待相似的客户端,这是人类一直在做的事情。例如,将公司名称的文本作为输入(例如,“丹尼尔屋顶公司”),并预测企业的类型(例如,“屋顶工”)。这项技术有商业应用。例如,拿一份发票清单,将它们分组到假日电子邮件中。有哪些客户彼此相似?您可以使用发票金额作为业务类型的指标,但企业的名称可能非常有助于您了解企业与您的业务往来,因此它们与您的业务有什么关系,以及您希望如何传达它们。在本文中,只使用企业名称的小型企业分类是我们的目标。
在本文中,我开发了一个 FastText 模型,用于预测一家公司属于 66 种业务类型中的哪一种,只基于业务名称。我们稍后将看到,在小企业名称及其业务类型的数据集上训练机器学习模型将引入性别和地理来源偏见。
来源:XKCD “它是如何工作的”兰道尔·门罗
本文探讨了两种消除观察偏差的方法:
- 用占位符标记替换给定的名称。通过隐藏模型中的给定名称来减少模型中的偏差,但是偏差减少导致分类性能下降。
- 用性别互换的例子扩充训练数据。比如 鲍勃的食客 变成了 丽莎的食客 。在评估数据集上,使用性别交换样本增加训练数据被证明在减少偏差方面不如姓名隐藏方法有效。
2。背景
我们最初的目标是观察与给定姓名性别和地理来源相关的预测偏差。接下来,让我们努力消除偏见。
一个常见的问题是,企业知道小企业交易对手的名称,但不知道该企业的原型。在进行客户细分时,小企业提出了一个独特的挑战,因为小企业可能不会在包括元数据(如公司类型或分类代码)的大公司的数据库或分类系统中列出。除了销售和营销功能之外,客户细分对于为客户定制服务交付也很有用。公司的类型在预测销售和许多其他应用中也很有用。客户名单中各种类型公司的组合也可以揭示客户细分的趋势。最后,对企业类型进行分类可以揭示有用的股票交易信号[1] [2]。股权交易模型的分析通常可以包括行业分类。例如,在[4]和[5]中,全球行业分类标准(GICS) [3]被用于评估不同行业的交易模型性能。
现有的行业分类系统往往不能很好地涵盖小企业。广泛使用的行业分类系统中包含的标准偏向于大企业,这种偏向渗透到训练数据(即公司名称)中,成为对大实体的偏向。我想这种偏见是偏向于高收入和高员工的公司。例如,根据罗素 3000 指数[6]中的公司名称训练的模型在推断时将不能正确地准备来预测在“丹尼尔理发店”进行的业务类型。诸如 Russell 3000 成员的较大公司的名称中既没有反映小企业的企业类型(例如,理发师),也没有反映小企业的命名惯例(例如,商店)。
有几个人策划的行业分类系统,包括标准产业分类法(原文如此)[9],北美行业分类系统(NAICS) [10],全球行业分类标准(GICS) [3],行业分类基准(ICB) [11],等等。对这些分类方案的一项比较显示,“GICS 优势每年都是一致的,并且在大公司中最为明显”[12]。这进一步强调了这一点,即这些分类系统更擅长对大公司进行分类,而不是对小企业进行分类。
行业分类系统中的标签为监督学习提供了机会。一种补充方法是应用无监督学习来对数据建模。例如,用于行业分类的聚类已经在[13]中得到应用。
测量文本分类器中的偏差需要一个不是原始数据集的子集或分割的验证数据集。第二个数据集是必需的,因为没有它,测试和训练数据将可能包含相同的数据分布,隐藏评估的偏差[14]。第二个数据集的目的是在非分布条件下评估分类器,它不是专门为其训练的。
可以通过用性别交换样本[15]增加训练数据,用更大的偏差更小的数据集[16]微调偏差,或通过其他权重调整技术[17],或从模型中移除性别特定的因素[18],来减少单词嵌入模型中的性别偏差。结合应用这些技术中的几种可能会产生最好的结果[16]。在这项工作中,增加性别交换样本的训练,并从模型中隐藏性别特定的因素进行了评估。
机器学习模型通常使用 top-k(也称为 top-n)准确度进行评估,以显示响应的特异性如何影响精确度和召回率[19]。在 top-1 评估中,只有当模型输出中的最高概率标签与真实标签匹配时,推断才被视为正确。同样,在 top-2 评估中,如果模型输出中两个最高概率标签中的任何一个与真实标签匹配,则推断被视为正确。更宽松的约束通常会导致更高的召回率和更差的精确度。
训练模型仅根据企业名称来预测小型企业的类型有一个潜在的缺点:引入偏差。小企业名称通常包括性别和地理本地化的名字。这可能导致模型开始将名字与企业类型相关联,这可能导致监管机构因歧视对企业进行罚款。例如,在没有对这种偏差进行调整的情况下,训练有素的模型可能将 丹尼尔的宝石 分类为珠宝店,而将 桑迪的宝石 分类为家庭工艺品商店。更复杂的是,由于混淆分类器以挑选错误的标签,或者由于导致与基于名称的地理原型相关联的标签,词汇表外的名称也可能有偏差。
激发了对从企业名称预测小企业类型的无偏模型的需求,现在提出了开发这样的机器学习模型的方法。
模型预测的粒度会影响观察到的性能。具体来说,考虑使用随机数生成器将小企业分类为两个一般类别之一有 50%的机会正确分类,而相同的随机数生成器有 1%的机会将公司分类为 100 个更详细的类别之一。显然,对特异性的统计惩罚证明了根据小企业分类模型进行一般和特定预测的合理性。因此,本研究中提出的模型输出了关于整体企业类型的高级预测,以及关于确切的小型企业类型的更具体的预测。
3.数据集和数据准备
本文中使用的小企业分类标签来自温哥华市第 4450 号许可证条例[7]。用于模型开发的数据集来自该市的开放数据网站[8]。该数据集包括各种小企业,比常用的行业分类系统更适合小企业分类。
高级小企业类型预测中的标签是 B2C 、 B2B 、 PUB 和 B2BC 。B2C 代表企业对消费者,因此 B2C 公司向消费者销售产品。类似地,B2B 公司在企业对企业的基础上销售给其他公司。B2BC 公司向企业和消费者销售产品,公共事业由参与提供公共服务的政府实体组成(例如,学校、协会和政府实体)。温哥华市许可证条例 4450 [7]中的类别与上述 4 个高级别类别之间有一个映射,如本文后面部分所述。
对来自数据集的样本进行的人工数据审核显示,大约 30%的标签对我(人类)来说是难以预测的。下面的表 1 显示了 20 个记录的代表性样本,揭示了模型预测性能的一些限制。显然,当唯一可用的信息是公司名称时,小企业类型分类是具有挑战性的。一些公司的名字包含了独特的文字、街道地址,或者不是描述性的。其他的要么过于笼统,要么过于具体。该任务的合理性能预期是什么?存在不可解决的边缘情况,并且分类器的有用性(作为客户细分信号是否足够好)是主观的。结果对用于训练机器学习模型的数据集也非常敏感。在本文中,我将报告我观察到的结果,如果您试图将这些内容融入到您自己的工作中,则由您来决定定性的接受标准。
表 1:来自公司名称数据集的经过处理的随机样本,表明一些标签很难比偶然更好地正确预测,即使对人类来说也是如此。
数据集的准备始于阐明数据集中每个企业的企业名称和类型。为了从数据集中的 BusinessName 和 BusinessTradeName 字段中选择最具描述性的名称,BusinessTradeName 被用作企业名称,除非该字段为空,在这种情况下, BusinessName 字段被用作企业名称。接下来,从数据集中删除以圆括号开头和结尾的企业名称(表示企业名称是个人名称)。业务类型是从数据集的业务类型字段中提取的。接下来,删除业务名称和类型对中的重复项。这些重复可能是由于许可证续订等事件而存在的。接下来,从数据集中删除带有低频业务类型标签的项目。具体来说,少于 100 个样本的标签被丢弃。
数据集中的一般类别“办公室”已从数据集中删除,因为它不是用于构建企业名称分类模型的描述性类别,似乎是一个总括。这可能不是一个好的做法,因为在这一类别中可能有偷偷摸摸的例子,但我们继续。
当原始类别中的企业名称被认为过于相似而不能分开时,相似的类别被合并到更广泛的类别标签中。具体来说,房地产行业的几个标签(公寓房、1956 年前的住宅、非营利住房、公寓房层、二级套房-永久、多套住宅、复式和单户住宅)被通用标签住宅/商业所取代。“临时酒类许可证修订”、“酒类机构标准”、“酒类机构扩展”、“酒类许可证申请”和“酒类零售店”的标签被更通用的标签“酒类机构”所取代。U-Brew/U-Vin 类别中的项目与白酒设备类别标签合并。三个标签洗衣房-投币服务,洗衣房仓库,和洗衣房(w/设备)被更普遍的标签洗衣房所取代。标签有限公司服务食品机构、餐馆类别 1 和餐馆类别 2 被替换为更通用的标签餐馆。标签短期租赁,和汽车旅馆是结合在一起的类别酒店。承包商——特殊行业与承包商类别相结合。虽然不是所有的商业和贸易学校都是私立学校,但学校(商业和贸易)的标签被合并到学校(私立)类别中,因为这两个类别的名称相似。最后,标签艺人 Live/Work 工作室并入了品类工作室。
完成预处理后,数据集中跟踪的 66 种业务类型以及每个标签的样本数量显示在下面的表 2 中。
表 2:数据预处理后的业务类型及其样本数
表 3:高级业务类型,它们的样本数,以及数据预处理后映射到每个高级类的业务类型。可以观察到类别之间的样本不平衡。
我没有清理这个项目的代码,但我认为它会帮助你看一看我为撰写这篇文章而写的一些代码。你可以点击这里查看我用来争论数据集、训练模型等等的许多东西的要点。
4.1 偏倚模型:具有性别和姓名来源偏倚的模型
在上述预处理之后,使用随机权重初始化在数据集上训练快速文本监督学习模型[20]。学习率和训练迭代次数的超参数搜索导致选择 6 次训练迭代作为早期停止点,并且选择 0.2 的学习率。模型的嵌入维度宽度为 100 维,窗口大小设置为 5。模型性能记录在下面的表 4 中,以及接下来两节的一些剧透。
表 4:分类性能报告。这里的结果告诉我们分类器是否工作,但不告诉我们分类器是否有偏差。μ是平均值,σ是标准差。这些结果是 10 次训练和测试运行的平均值(测试 n=7,087)。涉及所有 66 个类别的预测被评估为前 1 和前 2 性能,而当预测四个高级标签之一时,仅报告前 1 性能。
这个初始模型是根据世界上一个地理区域(加拿大西部)的企业名称进行训练的。该数据集包括企业名称训练数据中的各种本地名和姓。数据集来自一个说英语的省份。这些因素代表了基于企业名称中给定名称的性别和企业名称中名称的地理来源的分类偏见的强大潜力。
我们想评估当模型仅仅基于一些有偏见的东西改变它的想法时,比如与名字相关的性别。查看表 6,有两种方法用于评估模型偏差。在第一种方法中,通过构建分布外数据来评估模型,分布外数据由随机选择的给定名称和随机字典单词(首字母大写)组成。比如《奥利维亚之镜》vs《诺亚之镜》。在第二种方法中,来自模型测试数据集的文本(从模型训练中保留的数据)被附加到随机选择的人的名字上。比如“丹尼尔的鲍勃杂货店”。为了检验模型中的偏差,这两种方法的生成过程都控制了人名的性别和地理来源。下面的表 5 显示了用于测试的按性别和地域划分的姓名列表。
表 5:用于模型评估的名称列表
我们之前注意到,这是一个具有挑战性的数据集,其中一个人(我)至少有 30%的采样数据有问题。我们可以在的表 4 中看到,这个初始模型的前 2 个预测是可以的,在 66 个类别中,给定的业务类型有大约 73%的机会被正确标记(回忆),应用的标签有 36%的机会是正确的(精确)。但是,我们还在表 6 的“初始模型”一栏中看到,该模型有相当大的偏差,从 1%到 10%不等,或者高达 19%的偏差,这取决于您如何测量。在接下来的几节中,我们试图从模型中消除这些偏见。
4.2 在训练数据中和推理时替换姓名
为了解决初始模型中已确定的偏差,进一步处理训练数据,用我们称为令牌的特定字符串替换公司名称数据集中的给定名称。这种方法的关键见解是,该模型可以了解较少的本地名及其相关性别,而不是试图了解不在分布范围内的“外国”名或性别名。使用 spaCy 的命名实体识别功能[23]首次尝试了给定名称替换任务,但最终证明基于字典的方法对于所讨论的数据集更有效。为了获得这项工作中报告的结果,从 python 库[24]中获得了一长串男性和女性姓名,而 python 库又从 1990 年美国人口普查中获得了姓名列表[25]。从企业名称中删除所有名称的一个问题是,如果企业的全名是一个名称,则企业名称可能被删除,导致分类失败。例如,名称“Denny’s”只是消失在一个空字符串中,因为“Denny”也是一个给定的名称。出现这一问题的另一种情况是企业以个人名义注册,例如“John Smith”。使用一个标准化的字符串来表示被替换的名称。具体来说,字符“_”被用作替换标记。
在这个额外的预处理之后,在数据集上训练了新的 FastText 监督学习模型。学习率和训练迭代次数的超参数搜索导致选择 6 次训练迭代作为早期停止点,并且选择 0.2 的学习率。模型的嵌入维度宽度为 100 维,窗口大小设置为 5。这款车型的性能记录在上面的表 4 中。
观察到的 top-1 精度和召回率相对于原始模型下降了大约 4%,这是在为分类提供信号的数据集中消除偏差的一个可以理解的结果。这种下降表明,也许一些分类性能源于基于名称的偏见。
4.3 用额外的性别信息充实培训数据
解决初始模型中已识别偏差的第二种方法是用文本的性别交换副本来扩充训练数据。例如,可以观察到带有标签 Plumber 的企业名称“Alice and Associates Plumbing Ltd”包含上述女性名列表中的名,并且可以将带有标签 Plumber 的新培训记录添加到数据集中:“Bob and Associates Plumbing Ltd”。类似地,包含男性名字的训练记录可以用性别交换的版本来扩充。直觉是,每个标签性别信息的平衡可以抵消每个标签的性别偏见。
在训练数据扩充之后,在数据集上训练了新的 FastText 监督学习模型。学习率和训练迭代次数的超参数搜索导致选择 6 次训练迭代作为早期停止点,并且选择 0.2 的学习率。模型的嵌入维度宽度为 100 维,窗口大小设置为 5。模型性能记录在上面的表 4 中。
表 6:模型偏差评估:基于名字的性别和地理来源的预测分歧。μ是平均值,σ是标准差。对于方法 1 的行,将 10,000 个样本与 10,000 个其他样本进行比较。对于方法 2 的行,使用模型训练数据作为基础,将 7087 个样本与 7087 个其他样本进行比较。注:为了关注大规模偏倚,不考虑一个类别内少于 5 个样本的不平衡。每个预测都是 66 个可能标签中的一个。
5.分析
在表 6 中观察到,正如预期的那样,分布外数据(方法 1)的模型评估揭示了比分布内数据集(方法 2)测试更高的偏差。在训练和推断过程中用固定字符串替换姓名的方法消除了分布外测试中的偏差。具体来说,在方法 1 中,每个类别的分类不平衡从 11.35% (σ = 2.23%)下降到 0.01% (σ = 0.00%)。关于从模型训练中保留的测试数据的结果,观察到偏差从 1.54% (σ = 0.08%)下降到大约三分之一,为 0.47% (σ = 0.06%)。因此,我们可以看到,我们在本文中尝试的两种评估方法的偏差都有显著下降。
令人惊讶的是,使用性别交换样本增加训练数据在[15]中有效,但在这项工作中研究的数据集上并不有效。分布外偏倚结果(方法 1)为 3.32% (σ = 0.01%),显著低于原始模型。然而,结果不如名称替换方法强,并且以较低的模型性能和来自公司名称数据集 1.90% (σ = 0.19)的测试数据的更严重的不平衡为代价。
两种偏差减少方法都存在模型稳定性问题。这些模型对很小的变化都很敏感。例如,模型对企业名称中单词的大小写很敏感,例如“Bob’s Plumbing”被归类为“Plumber ”,而“Bob’s plumbing”被归类为“Restaurant”。这种敏感性是输入模型的样本之间分类不一致的主要因素。例如,在名称替换模型中,输入样本“Aria Lodge & Associates _ Ltd”和“_ Lodge & Associates _ Ltd”会产生不同的类预测,即使文本仅相差几个字符。
请注意,虽然结果暗示替换姓名在某种程度上完美地替换了训练和测试数据中的所有姓名,但事实并非如此。这些预测确实会收敛,导致基于给定姓名的分类差异非常小,但数据集本身仍包含 1990 年美国人口普查姓名列表中未包括的几个姓名。例如,加拿大女性姓名列表中的 Aria 和墨西哥女性姓名列表中的 Ximena 这两个名字都不是通过姓名替换方法删除的。此外,数据集中的许多名字,如 Ho 和 Fraser,没有被删除。这一观察意味着从训练数据中移除大多数给定的名字足以解决大多数问题。此外,还存在文本中的标记被错误替换的情况,删除了一些本可用于分类的信息。例如,企业名称“Lodge & Associates Investigations Ltd”丢失了单词“Investigations ”,因为它有一个子字符串“In ”,该子字符串与名称列表中的名称相匹配。从名称列表中删除这一个 case(“In”)并没有显著提高模型的性能,因此很可能存在一组这样的名称替换精度和召回改进,它们共同提高了模型的整体精度和召回。这一额外的改进方向将作为未来的工作。当一本书说“这是留给读者的一个练习”时,你难道不喜欢吗?这实际上意味着我有这个想法,但是没有花时间去编程和测试它。
6.结论
本文开发了一个小企业类型分类器,并在模型中观察到了性别和地理来源偏差。虽然通过隐藏模型中的给定名称减少了模型中的偏差,但这是以牺牲模型性能为代价的。用性别交换样本扩充训练数据不如姓名隐藏方法有效。在一个完整的项目中,名字隐藏方法的精确度和召回率可能会提高很多。在我写的关于这个主题的下一篇文章中,我计划看看用于文本分类的 sk-learn 管道,以及使用特征选择来消除偏见。
如果你喜欢这篇文章,那么看看我过去最常读的一些文章,比如“如何给一个人工智能项目定价”和“如何聘请人工智能顾问”还有嘿,加入快讯!
下次见!
——丹尼尔
Lemay.ai
丹尼尔@lemay.ai
7.参考
[1] Lamponi,d .:行业分类对预测美国股票价格联动有用吗?财富管理杂志 17(1)(2014)71–77
[2]kaku sadze,z .,Yu,w .:开源基础行业分类.数据 2(2) (2017) 20
[3] Barra,m .:全球工业分类标准(GICS)。标准普尔技术报告(2009 年)
[4] Fischer,t .,Krauss,c .:用于金融市场预测的具有长短期记忆网络的深度学习。欧洲运筹学杂志 270(2)(2018)654–669
[5]j . bro fos:股票收益分类和预测综合委员会(2014 年)
[6]罗素指数:罗素 3000 指数
[7]温哥华市:加拿大不列颠哥伦比亚省温哥华市许可法第 4450 号(2019)https://bylaws.vancouver.ca/4450c.PDF。
[8]温哥华市:营业执照—温哥华市开放数据门户(2019)https://open data . Vancouver . ca/explore/dataset/Business-licenses/information/?disaccessive . status disjuctive . business subtype。
[9]英国官方:经济活动标准工业分类(SIC) (2018),于 2019 年 25 月 12 日查阅 https://www . gov . UK/government/publications/Standard-industrial-class ification-of-economic-activities-SIC。
[10]美国:北美工业分类系统。标准,总统行政办公室——管理和预算办公室(2017 年)
[11]富时罗素:行业分类基准(ICB)2019 年 12 月 26 日访问https://www . ftserussell . com/data/Industry-Classification-Benchmark-ICB。
[12]博杰拉杰,s .,李,C.M .,奥莱尔,D.K .:我的台词是什么?资本市场研究的行业分类方案比较。会计研究杂志 41(5)(2003)745–774
[13]kaku sadze,z .,Yu,w .:统计行业分类。风险与控制杂志 3(1)(2016)17–65
[14] Dixon,l .、Li,j .、Sorensen,j .、Thain,n .、Vasserman,l .:测量和减轻文本分类中的非预期偏差。载于:2018 年 AAAI/ACM 人工智能、伦理与社会会议录,ACM(2018)67–73
[15]赵,j .,王,t .,Yatskar,m .,Ordonez,v .,Chang,K.W .:共指消解中的性别偏见:评估和去偏见方法. arXiv 预印本 arXiv:1804.06876 (2018)
[16] Park,J.H .,Shin,j .,Fung,p .:减少辱骂性语言检测中的性别偏见. arXiv 预印本 arXiv:1808.07231 (2018)
[17]蒋,h .,纳丘,o .:识别和纠正机器学习中的标签偏差. arXiv 预印本 arXiv:1901.04966 (2019)
[18]t . Bolukbasi,Chang,K.W .,邹,J.Y .,Saligrama,v .,Kalai,A.T .:男人对于计算机程序设计员就象女人对于家庭主妇一样?去偏置词嵌入。神经信息处理系统进展。(2016) 4349–4357
[19] KAMATH,U.L .,WHITAKER,j .:NLP 和语音识别的深度学习。施普林格(2019)
[20] Joulin,a .,Grave,e .,Bojanowski,p .,Mikolov,t .:《有效文本分类的锦囊妙计》。arXiv 预印本 arXiv:1607.01759 (2016)
[21] BabyCenter,L.L.C .:加拿大 2017 年最受欢迎的名字:2019 年 24 月 12 日访问的前 20 名和趋势(2018)https://www . baby center . ca/a 25024668/Canada-2017 年最受欢迎的名字-前 20 名和趋势。
[22] BabyCenter,l . l . c .:Los nombre m \u as comunes para beb es en El 2015(2015)于 2019 年 4 月 12 日通过网络档案查阅https://web . archive . org/web/20160611202700/http://vidayestilo . terra . com . MX/Mujer/Los-nombre-MAS-comunes-para
[23] Honnibal,m .,Montani,I.: spaCy 2:使用 Bloom 嵌入、卷积神经网络和增量解析的自然语言理解。出现(2017)
[24] Hunner,t .,Visser,s .:2019 年 12 月 25 日访问的随机名称生成器【https://github.com/treyhunner/names。
[25] census.gov:来自 1990 年人口普查的常见姓氏-2019 年 6 月 12 日访问的姓名文件(2014 年 9 月)https://www . census . gov/topics/population/genealogy/data/1990 census/1990 census name files . html。
认知人工智能中的性别和种族偏见。
什么是认知 AI 偏差,我们如何与之对抗?
我们无法理解人工智能中偏见的概念,除非我们首先理解“偏见”这个术语的含义。根据维基百科的定义,偏见是对一个想法或事物的或不相称的支持,通常是以一种封闭的、偏见的或不公平的方式。偏见可能是天生的,也可能是后天习得的。人们可能会对某个人、某个团体或某个信仰产生偏见。在科学和工程中,偏差是一种系统误差。统计偏差是由不公平的总体抽样或不能给出准确平均结果的估计过程造成的。**
关于图像 AI 的性别和种族偏见,也称为认知 AI 偏见,是一种由工程师构建的模型和算法未能为特定性别或种族的人提供最佳服务的概念。在图像人工智能中,最常见的情况是,即使识别系统也无法检测和识别代表性不足的性别和种族。这是一个非常严重的问题,尤其是对于那些为公众提供平等和透明服务的系统而言。在这个故事中,我们将讨论模型和算法描绘性别和种族偏见的一些典型实例,讨论由此造成的一些影响,并谈论我们如何帮助打击图像人工智能中的种族和性别偏见。
是什么导致了图像人工智能中的性别和种族偏见
智能模型的好坏取决于用来训练它的数据。— 德里克·德贝杜伊
模型和算法只能做它们被训练去做的事情;检测和识别他们被训练识别的事物(或人)。几乎每一个生产中的图像 AI 模型或算法都经过了非常大的数据的训练和测试。制作这样的数据集非常耗时且昂贵。如果模型或算法是为公众服务而开发的,它需要许多不同性别和种族的不同人的高质量头像照片。由于制作如此庞大的数据集所涉及的压力,大多数工程师更喜欢使用开源或闭源数据集,其中大部分数据收集已经为他们完成。他们没有认识到的是,即使他们的模型和算法会以非常高的精度通过,也必须有几乎每个性别和种族的人的足够数据。如果只使用白人的数据进行训练,你的模型和算法对黑人来说将会失败,反之亦然。这同样适用于性别。你的组织有唯一的责任确保你的训练和测试数据包括所有可能使用你的服务或产品的种族和性别。当这些事情都处理好了,我们终于可以在认知 AI 中拥有无偏的系统、模型或算法。
人工智能系统描绘认知人工智能偏差的典型例子。
过去几周,许多人发现了大多数人工智能系统描绘的认知偏见,并开始公开宣布这些偏见,以便公众知道,并因此迫使相关公司修复他们的人工智能系统。我将分享其中的一些推文,这样任何想了解公开测试期间发生的事情的人都可以找到答案。
-
Zoom 无法检测到黑人面孔并在使用虚拟背景时删除他们: Twitter 用户科林·马德兰注意到一名黑人教师在切换到虚拟背景时,他的面孔被 Zoom 的面部识别系统删除了。下面的图片捕捉到了发生的事情。
-
Twitter 在帖子中裁剪出黑人面孔: Twitter 运行一种面部检测算法,裁剪发布在平台上的图像,以关注发布图像中的面部。最近,很多用户注意到,当不同种族的人在一幅图像中有多张脸时,裁剪图像的算法会优先考虑白人脸。
上面嵌入的同一个用户, Colin Madland 注意到,在张贴了一张他和他的黑人教员的脸的图像后,twitter 算法在移动设备上的图像预览中裁剪出了他的黑人教员的脸。
许多用户还进行了社会实验,以测试对 twitter 算法的指控是否属实,结果仍然相同,得出的一般结论是,该算法确实存在种族偏见。这里有一些来自社会实验的推文。
这些只是成千上万个例子中的几个,twitter 算法描绘了认知人工智能在预览图像时从图像中剔除有色人种的偏见。
- **Twitter 从图像预览中裁剪女性:**早在 2019 年,VentureBeat 就发布了一条关于 Yann LeCun,Hilary Mason,吴恩达和 Rumman Chowdhury 对 2019 年人工智能预测的推文,作者是 Khari johnso n。在图像预览中注意到,帖子中涉及的女性的脸被裁剪出了图像预览。这是 twitter 算法对性别偏见的一个演示。以下是确切的推文。
人工智能中认知偏差的后果
多年来,人工智能积极融入我们的日常生活,随之而来的性别和种族偏见影响了许多有色人种和代表性不足的性别的生活。这些系统有很多错误的预测,导致很多人在监狱里度过一生,享受不到某些服务,甚至死亡。这里有几篇文章指出了人工智能中的认知偏差带来的一些不利后果。
一种在美国医院广泛使用的为病人分配医疗保健的算法已经被系统地识别…
www.nature.com](https://www.nature.com/articles/d41586-019-03228-6) [## 为什么这个皂液机不能识别深色皮肤?
周三,尼日利亚的一名脸书员工分享了一个小麻烦的镜头,他说这是对技术的…
gizmodo.com](https://gizmodo.com/why-cant-this-soap-dispenser-identify-dark-skin-1797931773) [## 被算法错误地指控
这可能是第一个已知的同类案件,一个错误的面部识别匹配导致了密歇根…
www.nytimes.com](https://www.nytimes.com/2020/06/24/technology/facial-recognition-arrest.html) [## 警察面部识别对毛利人的歧视只是时间问题——专家
毛利人因为面部识别的错误匹配而被错误逮捕只是时间问题…
www.rnz.co.nz](https://www.rnz.co.nz/news/te-manu-korihi/425081/police-facial-recognition-discrimination-against-maori-a-matter-of-time-expert) [## 摄影中固有的种族偏见
莎拉·刘易斯探讨了种族主义和照相机之间的关系。本周,哈佛大学的拉德克利夫…
www.nytimes.com](https://www.nytimes.com/2019/04/25/lens/sarah-lewis-racial-bias-photography.html) [## 语音识别仍然存在明显的种族和性别偏见
与面部识别、网络搜索甚至皂液机一样,语音识别是另一个…
hbr.org](https://hbr.org/2019/05/voice-recognition-still-has-significant-race-and-gender-biases)
我们如何在认知人工智能中对抗性别和种族偏见
在认知人工智能中打击性别和种族偏见的第一步也是最重要的一步是纠正我们在训练和测试我们的系统、模型和算法时使用的数据集。我们需要重新思考我们的数据收集和保留协议,并使我们的工程团队多样化。我们需要严格确保我们部署到生产中的系统、模型和算法已经通过了我们可以进行的所有测试,以确保系统是健壮的,即使它们考虑到了可能使用系统或模型的每个单一性别或种族的人。
克里斯蒂娜@ wocintechchat.com 在 Unsplash 上的照片
我希望我可以提高对认知人工智能中系统性性别和种族偏见的认识,并鼓励工程师和开发人员做得更好,建立比我们目前更好的系统。认知人工智能中种族和性别偏见的不利影响相当严重,我们不希望无辜的人经历他们目前正在经历的一些事情。
如果你想谈论与这个话题或数据科学、人工智能或人工智能相关的话题,请随时在 LinkedIn 或 Twitter 上与我联系。我很乐意和你聊天。为构建系统和算法干杯,为所有种族和性别的人创造一个更美好的世界。黑客快乐!🚀
上帝保佑 安娜·阿依库 为她花时间和耐心校对和纠正我写这篇❤️时犯的许多错误
机器翻译中的性别偏见
莱昂纳多·大久保俊郎在 Unsplash 上的照片
机器翻译中性别偏见的故事和谷歌解决它的方法
2016 年 5 月 ProPublica 发表了一项分析,显示 COMPAS,一种通过预测被告重新犯罪的风险来指导美国判决的人工智能工具,存在种族偏见。黑人被告更有可能被错误地标记为高风险,而白人被告更有可能被错误地标记为低风险。
2018 年 10 月,亚马逊承认在发现该模式重男轻女后,他们已经放弃了一个自动审核申请人简历的项目。
2018 年,谷歌宣布在谷歌翻译显示在将中性土耳其语翻译成英语时存在性别偏见后,他们正在采取第一步措施解决机器翻译中普遍存在的性别偏见。
机器学习中的偏差
偏见是当今围绕人工智能和机器学习的最大伦理问题之一。根据韦氏大词典的定义,偏见是
通过选择或鼓励一个结果或答案而引入抽样或测试的系统误差。
虽然机器学习模型可以是一个强大的工具,但它只能与它学习的数据一样好。因此,如果用于训练机器学习算法的数据中存在系统误差,那么产生的模型将会反映这一点。俗话说“垃圾进,垃圾出”。
paweczerwi ski 在 Unsplash 上的照片
在许多情况下,这并不是机器学习实践者在选择数据集或训练模型时主动偏向的结果。相反,固有的社会偏见,如性别或种族偏见,在本质上是特定社会历史记录的数据集中表现出来。反过来,这些数据集将它们的偏见传递给从中学习的机器学习模型。
作为一个例子,我们稍后将重新讨论,如果历史上担任医生的男性多于女性,那么基于历史数据训练的机器学习模型将学习到医生更可能是男性而不是女性,这与当前医生中的性别差异无关。
机器翻译中的性别偏见
机器翻译模型是在巨大的文本语料库上训练的,有成对的句子,一个句子是另一个句子的不同语言的翻译。然而,语言中的细微差别常常使得从一种语言到另一种语言提供准确和直接的翻译变得困难。
从英语翻译成法语或西班牙语等语言时,一些中性名词会被翻译成特定性别名词。比如“他的朋友是善良的”中的“朋友”这个词,在英语中是中性的。但在西班牙语中,它是有性别区分的,要么是“amiga”(阴性),要么是“amigo”(阳性)。
在西班牙语中,“朋友”一词是有性别区分的,可以是“amiga”或“amigo”
另一个例子是从土耳其语到英语的翻译。土耳其语几乎是一种完全中性的语言。土耳其语中的代词“o”在英语中可以翻译成“他”、“她”、“它”中的任何一个。谷歌声称他们 10%的土耳其语翻译查询是不明确的,可以正确翻译成任何性别。
在这两个例子中,我们可以看到一种语言中的短语如何正确地翻译成另一种语言,并根据性别有不同的变化。没有哪一个比另一个更正确,并且在没有提供进一步的上下文的情况下,具有相同翻译任务的人将面临相同的歧义。(唯一的区别是,也许人类会知道询问进一步的上下文,或者提供两种翻译。)这意味着当从一种语言翻译成另一种语言时,假设任何给定的单词、短语或句子总是有一个正确的翻译是不正确的。
现在很容易理解为什么谷歌翻译会有性别偏见的问题。如果社会偏见意味着历史上成为医生的男性比女性多,那么在培训数据中,男医生的例子就会比女医生多,这只是性别失衡的准确历史记录。该模型将从这些数据中学习,导致医生更可能是男性的偏见。
现在,当面临从土耳其语到英语为“o bir doktor”、“他/她是医生”找到一个单个翻译的任务时,模型会假设“o”应该被翻译为“他”,因为医生更可能是男性。
人们可能会看到护士会出现相反的情况。
对中性查询进行分类
2018 年,当谷歌承诺迈出解决谷歌翻译中性别偏见的第一步时,他们的解决方案涉及两个关键步骤。首先,他们创建了一个分类器来确定有资格被翻译成多种性别的查询。他们训练了他们的分类器,一个卷积神经网络,在数千个人类标记的例子中,人们被要求判断查询是否是性别中立的。
第二步是根据目标语言中是否包含阳性、阴性或中性词,将他们的训练集分成三组。然后,他们在查询的开头添加了一个额外的标记,以明确说明该查询应该转换成的性别:
- 他是一名医生
- 她是一名医生
这样,翻译者就知道将中性查询翻译成哪种性别。
在用户方面,这样做的结果是,如果分类器将查询标记为中性,并且没有明确要求,那么这个特性会将查询翻译成两种性别。
Google Translate 过去基于数据偏差假设中性查询的性别(左),现在它同时提供阳性和阴性翻译(右)
审查性别翻译后
当时,谷歌声称这个新系统将“在 99%的时间里可靠地产生阴性和阳性翻译”。然而,在今年早些时候的博客帖子中,他们收回了原话,称“随着这种方法被应用到更多的语言中,很明显在伸缩方面存在问题”。
他们声称有两个主要问题:
- 该模型无法在多达 40%被视为性别中立的查询中显示性别特定的翻译。这意味着,即使指定目标语言中所请求性别的标记是正确的,模型也无法返回基于该性别的正确翻译。
- 他们发现,用一个单独的分类器来确定每一种不同语言的性别中立性,数据过于密集。
相反,他们提出了一种新的方法,一种基于重写器的方法。在第一种情况下,不是将查询翻译成两种不同的性别,而是产生单个默认翻译。接下来是一个审查过程,以发现性别中立的查询导致特定性别翻译的实例。如果是这种情况,最初的翻译是用异性重写的。最后,为了确保准确性,将两种翻译进行相互比较,以确保唯一的差异是性别。
偏差减少
在设计新方法的过程中,谷歌还定义了一个新的指标,偏差减少,来衡量新系统相对于旧系统的改进。这是偏差减少的百分比,所以如果一个系统在 80%的时间里做出错误的特定性别选择,而新系统在 20%的时间里做出错误选择,偏差减少将是 75%。
根据谷歌博客的说法,在从土耳其语翻译成英语时,基于新重写器的系统的偏差减少了 95%,高于使用基于分类器的系统时的 60%。他们的性别翻译的精确度也是 97%,这意味着除了 3%的情况外,他们在所有情况下都正确显示了性别翻译。
结论
尽管谷歌不得不接受 2018 年 99%的数字,但它的新数字似乎更保守,也更有分寸。我们也希望他们能吸取教训,在发布指标时更加小心。但在现实中,谷歌将不得不等待,看看有多少愤怒的社交媒体帖子出现偏见谷歌翻译查询的截图!
与此同时,像谷歌这样的公司需要继续解决他们产品中不同的偏见问题。然而,他们不仅应该从过程的机器学习端解决这些问题,还应该考虑如何更好地收集数据,以避免一开始就出现偏差。
通用 Git 工作流程
使用 Git 时最常用的命令
Git 是最常用的代码版本跟踪工具,可能每个开发人员都使用它,无论你使用 Github、Gitlab 还是 Bitbucket,只要你想分享你的代码或学习他人的代码,或与他人合作开发一个项目,git 都是必备的能力。
那里有很多 git 使用教程、命令介绍文章和文档。但坦率地说,当我查看大多数官方文档时,我被太多的命令和太详细的介绍填满了,这使我很难找到我真正需要的东西。因此,在本文中,我将只介绍您在使用 git 时肯定会用到的命令行工具。
我将分为两个工作流程:
- 使用现有存储库
- 创建自己的存储库
使用现有存储库
当你在一家公司工作时,这是最常见的,在大多数情况下,你需要从其他人那里接管一个项目,或者只是在一个大型项目上与其他开发人员合作。一般的工作流程是:
给自己找一个工作文件夹
cd {YOUR_FOLDER}
克隆项目(使用 SSH 或 HTTPS)
git clone {PROJECT_PATH}
现在项目已经下载到你的本地计算机上,你就在主分支了。下一步是创建您自己的分支,并在该分支上开发您的特性。如果你不是项目的所有者或者你和许多其他开发人员一起工作,千万不要直接在主分支上进行变更。经验法则是,我们总是把母版制作得干净整洁,直到可以投入生产。
git checkout -b {YOUR_BRANCH_NAME}
如果你已经有一个分支,需要转移到那个分支,你只需要
git checkout {YOUR_EXISTING_BRANCH}
好了,现在你在你的分支上,你做了一些改变。一切看起来都很好,您认为您已经准备好向 master 更新您的更改了。然后,您需要首先将您的更改提交到本地:
# check what files you've changed
git status# add those files to staging
git add .# commit your files
git commit -m "what I have done"
这三个命令可能是 git 最常用的命令。除了添加所有你修改过的文件的git add .
,你还能做什么
git add {LIST OF SPECIFIC FILES}
并分别提交。
提示
运行 *git status*
后,您发现一些您不打算添加到提交中的系统文件,如 *.idea, __cache__*
等。然后你需要编辑你的 *.gitignore*
文件(或者如果根文件夹中不存在就直接添加)。
*.gitignore*
顾名思义就是告诉 git 故意忽略一些不必要的文件,这样 git 就会跟踪这些文件的变化。例如,您可以添加
*.idea
*/**/.idea*
变成你的 *.gitignore*
。
你可以做的另一件事是使用 *git rm*
,它从 git 中移除文件并停止跟踪它,而不是从你的电脑中!
现在您已经提交了您的文件,并且您对它们很有信心,所以让我们推进到远程并合并到主文件。
git push origin {YOUR_BRANCH_NAME}
在大多数情况下,你不能做git push origin master
,因为你的授权是受限的。但即使可以,也不应该这么做。这里的规则是,如果你在一个分支上工作,总是推到远程分支。上面的命令将您的本地分支推送到远程分支(如果远程分支不存在,git 将帮助您创建一个)。
当您执行上述命令时,通常它会在控制台中返回一个 url,引导您提交一个合并请求。请注意,这个合并请求是将您的远程分支合并到远程主服务器。您可以提交您的合并请求,并让回购所有者批准合并到主(可能需要单独解决冲突的方式)。
提示
假设远程主机非常活跃,并且有许多其他开发人员正在开发它。在提交合并请求之前,您希望将新的更改合并到远程主分支中,并可能解决本地主分支中的冲突。那么你可以这样做:
*# go to your local master
git checkout master**# merge your local master with remote master
git pull origin master**# go to your branch
git checkout {YOUR_BRANCH}**# merge master into your branch
git rebase master*
最后一步你还可以做 *git merge master*
。他们以不同的方式绑定了 git 提交的历史。你可以在这里 查看 的区别。
这些基本上都是关于与他人一起工作,使用最常用的命令,以及您可能遇到的问题。
创建自己的存储库
想想当你在笔记本电脑上做自己的项目时,突然它在你的脑海中闪现——这是一个多么棒的项目!我要和别人分享!
酷,让我们创建自己的回购协议,并把我们的代码放在网上。它分为两步:
创建远程存储库
转到您的 Github、GitLab 或 Bitbucket,并选择 create a new repository。这里我以 Github 为例:
给你的项目一个名字和一些描述,然后点击Create repository
按钮。
将克隆按钮中的 URL(SSH 或 HTTPS)复制到剪贴板,我们稍后会用到它。
现在回到你的牛逼项目文件夹根目录
cd {YOUR_PROJECT_ROOT}
用 git 初始化你的项目
git init
这会在你的文件夹中启动 git,如果你运行ls -a
,你将会在你的根文件夹中看到隐藏的文件.git
,它告诉你从现在开始,git 将会跟踪这个文件夹中的每一个变化。
接下来是将您的本地文件连接到您的远程 repo,如果您运行
git remote -v
这将列出您当前项目的远程 url,到目前为止它应该是空的,因为您创建了一个远程 repo,您还告诉 git 跟踪您的文件,但是您还没有告诉 git 如何将您的本地 repo 连接到远程。为此,请运行:
git remote add origin {URL_OF_YOUR_REPO}
这将您的本地项目与您刚刚创建的远程 repo 连接起来,并给它一个昵称origin
(您可以随意命名,但人们通常将其命名为 origin)。
提示
一个本地 repo 实际上可以连接多个不同 URL 的远程 repo。你只要做:
*git remote add upstream1 {SECOND_URL}**git remote add upstream2 {THIRD_URL}**...*
这样,当您在本地进行更改时,您可以同时更新多个远程回购。
现在再次运行git remote -v
,你会看到你的网址列在那里。让我们推出改变,分享我们的代码!
添加和提交代码的步骤是一样的:
# check what files you've changed
git status# add those files to staging
git add .# commit your files
git commit -m "what I have done"
要将您的更改推送到遥控器,有两种情况。
- 如果遥控器有一些文件不包含在你的本地,比方说,一个
README.md
的创建回购初始化,你需要:
git pull origin master --allow-unrelated-histories# resolve conflicts and then push to remotegit push origin master
allow-unrelated-histories
是在分支独立开始时合并它们,这里就像你的本地文件夹和你的远程 repo。
2.如果你的遥控器是干净的,那么就做git push origin master
。
提示
你不需要每次都输入回购名称。运行
*git push --set-upstream origin master*
这明确告诉我们 *origin*
将会被默认分支推送到,这样下次你只需要运行 *git push*
。
提示
当您在本地有多个分支,并且您需要在分支之间跳转时,您可能会遇到 git 告诉您在切换分支之前提交的问题,但是您不确定当前的更改,并且您不想提交,在这种情况下,您可以:
*git stash*
这将保存您的更改,并使您能够跳转到另一个分支而无需提交它们。当你回到这个分支时,你可以运行:
*git stash pop*
恢复您刚才所做的更改。