R 中运行路线的自动化
实践教程
使用 Graphhopper API(在 rvest 和 PostcodesIO 的帮助下)运行伦敦的每个 Mews
冬天已经来到了英国,当其他人都在匆忙修理锅炉时,我最关心的是保持每周的运行里程,而温度却在相反的方向。
探索伦敦的新地方似乎是个好主意,而且不必考虑走哪条路似乎更好。所以计划是跑遍伦敦的每一条消息,让 R 决定怎么做。
本文中有一些代码片段,其余的在 fredwise/run_the_mews 上。
新闻
隐藏在伦敦一些大排屋后面的是 386 个原始的和幸存的消息。这些小街是真正的马动力的残余,虽然马厩和马车房现在大多是车库和底层厨房,但它们仍然是很好的观光景点。
找到他们
Everchanging Mews 在这里做了腿的工作,在过去的 10 年里,他们访问了 1200 多个 Mews,在他们的百科网站上对它们进行了分类。
原始/幸存的 mews 列表分为 8 页,每个列表都有一个包含更多详细信息的网页。Chrome Dev Tools 找到保存这个网址的元素,并对 R 包做了一些工作 rvest 列出了它们。
对它们进行地理编码
这些网页中的每一个都有一个邮政编码,邮政编码员将查询的邮政编码,io 以获得位置数据。当邮政编码不可靠或者在邮政编码. io 数据库(386 中的第 7 个)中不存在时,这里需要进行一些手工清理。之后,只需通过邮政编码 _ 查找运行它们。
映射它们
在这里,我们只需要将经度和纬度作为一个形状文件传递给活页。
一页上的 386 条原始/幸存的消息
路由它们
希望所有这些的真正价值来自于路线生成的自动化。最初的问题陈述是:
在 20 公里或更短的路线中,查找覆盖所有 386 家酒店的最短总路线。每条路线都从同一个地方开始。
GraphHopper 是这类路线优化的优秀免费资源。它允许所有种类的车辆(在这个例子中是脚)的路线,但是它的免费 API 只允许每个请求最多 5 个位置。
GraphHopper 甚至可以让你为一辆小型摩托车导航。
一个简单的解决方案是一次随机选择 5 个位置。这样做的代价是没有优化总距离,但是在这种情况下,这意味着完成了更多的运行,并且没有消息被访问两次(只要随机采样没有替换),所以应该这样做!
使用 GraphHopper API
GraphHopper 的文档非常棒,所需要的就是以正确的格式传递 5 个位置的纬度和经度。下面的代码片段显示了一个函数,它将这个请求构建为 R 列表,并使用 jsonlite 将其转换为 JSON。提醒一下,完整的脚本可以在 Github 上找到。
对我们的 5 个位置运行路线的 78 个查询使用 httr::POST 发送到 GraphHopper API
使用 sf 包将响应路径坐标转换成简单特征,并在活页中绘制成折线。
Graphopper 做了大量的工作来优化我们五个 mews 集合之间的路线
线串到 GPX
最后但并非最不重要的是,在设备上具有这些路线将是有用的,以便跟随该路线。只需将从每个 GraphHopper 响应路径创建的简单特性传递给 sf::st_write
哇,78 个 GPX 文件和 78 天的奔跑,不用考虑去哪里!
使用 SQLite 关系数据库和 Python 实现周日膳食准备自动化
创建和使用储物件,满足您所有的烹饪需求
成为一个真正的成年人(现在,被隔离)意味着加入 r/meal prep Sunday,重新创造所有的膳食准备食谱。然而,随着我的食谱越来越多,我对存储的需求也越来越大。
我现有的谷歌电子表格的快照,准备在未来几年成倍增长
我最初在一个电子表格中跟踪我所有尝试过的食谱,首先按照餐点,然后按照主料精心组织。我还包括了我想要跟踪的其他属性,包括烹饪、难度和食谱中的任何饮食限制。但是行数的增长也意味着组织和搜索时间的增长。我需要一个新的,更强大的存储单元。那时,我开始研究电子表格的轻量级(尽管在 UI 方面没有那么吸引人)表亲 SQLite 关系数据库的用途。
我想要这个新的食谱数据库来补救我的电子表格的困境。因此,我将它设计成:
- 最大化增长空间(我可能会在我的烹饪生涯中一直使用它
- 允许使用我现有的属性轻松存储和排序
- 通过汇总我为这一周选择的食谱中的所有材料来简化购物
最终,我的食谱数据库完成了所有这些目标。结果证明这是最用户友好/可行的选择吗?可能不会,而且我了解到 SQLite 可能不是这样一个项目的最佳选择。然而,我确实创建了食谱数据库的一些基本构件,并对现有的电子表格应用程序有了新的认识。如果您有兴趣了解 SQLite 和 python 的 pandas 如何用于食谱的上下文,那么让我们来看看实用性。
完整代码可以在我的 Github 这里 找到。为了方便查看,我用了一个 Jupyter 笔记本,但是你可以随意把它分成有标签的文件。
目录:
- 设置关系数据库模式
- Python for SQLite 入门
- Python 中的 SQLite 关系基础:配方版
- 用关键字参数和熊猫检索食谱
- 随时可用— Python 的 input()作为 UI
- 结论
设置关系数据库模式
我希望我的数据库满足的第一个标准是最大化增长空间,这直接受其结构的影响。随着数据库的扩展,最大限度地减少可能影响存储效率的冗余尤为重要。这个概念叫做规范化。
虽然不同的规范化形式包含它们自己特定的规则,但是作为一个整体,规范化通常需要将一个大表分解成多个小表,并维护这些部分之间的联系。这些小表的结构由底层数据的关系决定,有三种类型:一对一、一对多和多对多。
一个配方对应一套说明
最简单的数据库关系是一对一的。这是指表 A 中的一条记录与表 b 中的一条且仅有一条记录相关联。在配方数据库中,配方及其说明具有一对一的关系,因为两个配方几乎不可能具有完全相同的说明。因此,配方名称表和配方指令表将具有一行配方名称,对应于仅仅一行配方指令。
一对一的配方数据库模式
一个配方多种属性
对于大多数其他食谱属性(例如,难度、烹饪、课程和饮食类型),存在一对多的关系。表 A 中有一条记录链接到(你猜对了!)表 b 中的多个记录。例如,一个难度级别(例如“容易”)可以有许多与其相关联的食谱,因为可以有许多“容易”食谱。然而,反过来就不正确了——一个食谱不可能既“简单”又“困难”(除非我的烹饪能力一天比一天有很大的变化)。
一对多配方数据库模式
多种配料的多种食谱
表之间的最后一种关系是多对多关系。在配方数据库中,一个配方可以有许多配料,一种配料可以用于许多配方。
多对多关系的实现需要第三个连接表来符合规范化规则。在我的 Recipes 表和 Ingredient 表之间,我创建了一个名为 Recipe_Ingredient 的连接表。第三个表将多对多关系分解为两个一对多关系。
多对多配方数据库模式
在图的右侧,您可能已经注意到不只是一个成分表,而是四个独立的表,包括单位表、数量表和制备方法表。这种结构利用了配料的单位、数量和制备方法与食谱之间的多对多关系。虽然我可以利用配料及其各自的单位、数量和制备方法之间的一对多关系,但我更喜欢将所有与配料相关的信息集中在 Recipe_Ingredients 表中的一个地方。
主键和外键
既然表已经拆分,那么如何将它们链接起来的问题就出现了。所有以前的模式图都有箭头,从一个特定的表指向另一个表中与其等价的“id”列。箭头底部表示主键,或特定表中行的唯一标识符。箭头的尖端指向一个外键,或者指向一个主键的引用。
这些关键不仅有助于建立关系,还能减少冗余。在做改变的时候,如果有一天我想把“容易”变成“毫不费力”,我只需要在难度表上做一个改变。如果主外键关系不存在,我需要用“easy”遍历所有行,并单独进行更改。建立此链接还可以通过防止删除具有依赖外键的主键来保存孤立记录。有关 SQLite 外键的更多信息,请查看这里的文档。
Python for SQLite 入门
现在设置已经完成,是时候用 Python 实现了。
选择数据库管理系统
数据库管理系统,简称 DBMS,是帮助处理数据库的系统的总称。其中的一个子集可以处理关系,将它们分类到 RDBMS 下,用额外的 R 表示关系。因为我需要关系管理,所以我选择了 SQLite,一个 RDBMS,因为它的易于设置并且不需要服务器。
设置和关闭
# getting start with sqlite
import sqlite3# create database file by specifying location
cnn = sqlite3.connect(r"C:\file\path\here\mealpreprecipes.db")# initialize cursor object to interact with database
cur = cnn.cursor()
当我们希望 Python 与数据库交互并处理 SQL 查询时,Cursor 对象将会派上用场。更多信息可以在 Python 文档这里找到。
一旦进行了任何更改,您需要使用 Commit 语句进行保存。
cnn.commit()
完成连接后,使用以下命令关闭它:
cnn.close()
或者,您可以使用with
语句来确保在运行必要的代码后连接被关闭。
with cnn:
* insert code *
更多直接来自源代码的设置信息,请访问 Python 文档这里。
Python 中的 SQLite 关系基础:配方版
虽然我不会介绍简单的 SQL 语法,但我会解释在实现本文开头创建的数据库结构时我发现有用的技巧和诀窍。
创建具有主键和外键的表
前面建立的主键和外键现在可以在我们创建表时实现。以下是一个配方表示例:
cur.execute("""CREATE TABLE recipe
(recipe_id INTEGER PRIMARY KEY NOT NULL,
recipe_name TEXT,
recipe_notes TEXT,
difficulty_id INTEGER,
cuisine_id INTEGER,
course_id INTEGER,
diet_id INTEGER,
instructions_id INTEGER,
FOREIGN KEY (difficulty_id) REFERENCES difficulty(difficulty_id),
FOREIGN KEY (cuisine_id) REFERENCES difficulty(cuisine_id),
FOREIGN KEY (course_id) REFERENCES difficulty(course_id),
FOREIGN KEY (diet_id) REFERENCES difficulty(diet_id),
FOREIGN KEY (instructions_id) REFERENCES difficulty(instructions_id))""")
应用这些FOREIGN KEY
约束可以确保recipe
表的任何一行中的所有外键都将链接到另一个表的主键。例如,如果插入到recipe
表的difficulty_id
中的一行在difficulty
表中没有对应的主键,插入将会失败。
插入主键和外键的值
在设置了具有主键和外键的表之后,我们现在想要插入一些值。
感谢我们使用的INTEGER PRIMARY KEY NOT NULL
关键字,我们不必为表的主键插入显式值。只需为该行插入一个值,表就会自动生成一个唯一的整数对其进行编号。
diet_id 列表示稍后要引用的主键
为了插入外键,我喜欢使用下面的语法:
sql = """INSERT INTO recipe(recipe_name, recipe_notes, difficulty_id, cuisine_id, course_id, diet_id, instructions_id) VALUES (?, ?,
(SELECT difficulty_id FROM difficulty WHERE difficulty = ?),
(SELECT cuisine_id FROM cuisine WHERE cuisine = ?),
(SELECT course_id FROM course WHERE course = ?),
(SELECT diet_id FROM diet WHERE diet = ?),
(SELECT instruction_id FROM instructions WHERE instructions = ?))"""
以这种方式使用SELECT
语句可以确保我找到正确的对应主键,即使我不知道唯一的整数。
具有外键列的配方表条目
数据插入
我希望既不是主键也不是外键的行条目是用户给定的值。幸运的是,SQL 为我们提供了准备好的语句来插入我们事先不知道的值。有了准备好的语句,我们可以将参数指定为查询,使用问号作为语法。这些用来代替传统的 Python 字符串格式来保护我们免受 SQL 注入的影响。在下面的函数中,我使用了一条准备好的语句来插入食谱的指令。
def insert_instructions(self):
sql = "INSERT INTO instructions (instructions) VALUES (?)"
# insert values as tuples
# single item tuples need trailing comma to show tuple-ness
values = (self.instructions,)
cur.execute(sql, values)
cnn.commit()
检查是否存在
对于某些属性,比如 cuisine,我知道插入的值很可能是数据库中已经存在的值。为了与效率的主题保持一致,我想通过检查存在来防止重复。在 select 表中,我在一个准备好的语句中使用了一个SELECT
语句。
sql = "INSERT INTO cuisine (cuisine) SELECT (?) WHERE NOT EXISTS (SELECT 1 FROM cuisine WHERE cuisine = ?)"values = (self.cuisine, self.cuisine)cur.execute(sql, values)
cnn.commit()
插入已知的表格值
虽然我的大多数表都根据用户输入插入了行,但是我希望我的两个表course
和diet
只包含我预先选择的值。
# example in diet table
cur.execute("""CREATE TABLE diet
(diet_id INTEGER PRIMARY KEY NOT NULL,
diet TEXT)""")cur.execute("""INSERT INTO diet (diet) VALUES ("None", vegan", "vegetarian", "gluten-free")""")
虽然 SQLite 不支持 None 类型,如NULL
,但我添加了字符串“None”作为选项。我发现当我使用 select 方法插入外键时,SQLite 不认为NULL
是可搜索的值。因此,我选择将“None”作为一个值,这样食谱就可以被表示为没有饮食限制。
关于 execute()与 executemany()的补充说明
正如上面两个例子中所使用的,Cursor 对象有一个Cursor.execute()
方法,用于将 SQL 查询作为字符串传递。上面没有显示的是Cursor.executemany()
,方便一次插入多行。确保将您想要插入的行作为列表传入。
我如何处理配料
规划这个食谱数据库时最大的挑战是配料处理,因为一种配料有四个属性:名称、数量、单位和制备方法。我最终选择将这些属性按照每种成分组成一个字典。对于 Python 来说,这似乎是一个自然的电子表格,每一列都被转换成一个键。
pesto_tilapia = {'ingredient': ['butter', 'pesto', 'coconut milk'],
'unit': ['tbsp', 'cup', 'can'],
'quantity': [3, 1, 1],
'prepmethod': ['room temp', 'None', 'None']}
虽然手动输入这样的词典很麻烦,但一个好的用户界面有望使这变得易于管理。
用关键字参数和熊猫检索食谱
检索和查看食谱对使用至关重要。为了实现这个数据库的第二个和第三个目标,我在 view.py 中构建了两个函数:一个用于查看选择的食谱,另一个用于收集配料的汇总列表。
查看选定的配方
第一个函数我命名为【非常原本】print_recipes()
。我想根据我选择的标准过滤和选择食谱,并使用关键字参数实现这个“搜索”功能,然后格式化成一个 SQL SELECT
查询。关键字 arg 将 category 作为键,将 category selection 作为值。因为参数不是位置性的,所以我可以根据需要传入任意多的标准。
不幸的是,Python 中的 SQL 查询是麻烦的字符串,所以函数的其余部分专门用于格式化参数。在有多个参数的情况下,我决定用一个OR
而不是一个AND
来连接搜索标准。这是因为我知道我的大部分搜索会是前一周我想用完的成分。为了找到包含所有我想用的配料的食谱,我需要配料的联合,而不是交集。如果你要寻找的东西需要你的标准的交集,请随意将它改为AND
。如果你感觉更有野心,尝试在OR
和AND
搜索之间集成一个切换。
在所有的字符串格式化之后,您将会得到一个函数,它会显示出您用关键字参数选择的食谱的数据帧。现在是时候列出购物清单了。
带有 kwarg {‘ingredients’: ‘fish’}的示例数据帧
收集成分的汇总列表
第二个函数在一个名为convert()
的函数中返回我的购物清单。它获取在前面的函数print_recipes()
中创建的食谱数据帧,并返回其配料的字典,其中包括所有重复的配料。
虽然具有相同单位的成分组合起来很简单,但是需要单位转换的成分就比较棘手了。使用 pandas 的groupby()
和nunique()
,该函数首先在数据帧中搜索独特的配料。基于该成分的单位是否可转换(字典conversion_chart
中硬编码的选项),该函数将该成分的多个实例聚合(在大量数据帧过滤之后)成用户在convert()
参数中指定的一个单位。
所有的食材都加入字典后,你就有了你的购物清单!
用户提示后的购物清单词典
随时可用— Python 的 Input()作为 UI
由于没有用户界面经验,我需要一种快速简单的方法来访问我的数据库。我使用 Python 的input()
函数来获得用户响应并实现基本的控制。然后,这些输入用于启动 main.py 文件中的数据库插入和检索。
使用 input()的用户提示
结论
现在你有了一个全功能的(有些易坏的)食谱数据库,它最大化了增长空间,允许简单的分类和搜索,并简化了你一周的购物。
如果你更愿意拥有一个充满来自互联网的食谱的数据库,尝试使用 Selenium 和 Beautiful Soup 从你最喜欢的网站上收集食谱。可以在这里找到这些工具不同用例的教程。
快乐的用餐准备!
完整代码可以在我的 Github 这里 找到。为了方便查看,我用了一个 Jupyter 笔记本,但是你可以随意把它分成有标签的文件。
自动化枯燥的东西:数据问题
一个懂 SQL 的机器人
加入 froma tob 10 天后,2019 年 9 月,当我还住在酒店的时候,我们决定重组我们的 Google DataStudio 仪表盘。目的是帮助人们理解哪些问题已经可以用图表来回答了。关于数据的简单、重复的问题不应该在每次被问到时都手动回答。在理想的情况下,人们应该能够通过快速访问仪表板来回答这些问题。
为了让我们的仪表板更加用户友好,我有了开发 Slack bot 的想法。一个友好的 Slack 机器人,将用户重定向到我们的仪表板。破折号就是这样诞生的:
来源:迪士尼粉丝维基
这个想法很简单:每次你问 Dash 一个问题,他都会给你一两个与可能答案最匹配的仪表盘链接。
我记得我花了一个晚上学习 node.js,做了第一个 Dash 原型。最大的挑战实际上是让他能够与我们的 Slack 组织沟通。后来,定义内部逻辑是我最接近手动解决机器学习问题的一次。我定义了一个 dashboard 字典- >(关键字列表),以及一个 dashboard 评分系统,我必须手动调整它的权重,直到我的所有测试都通过,并且我认为我的工具足够健壮,可以使用。
Dash 使用下义词/上义词系统、拼写检查器、字符串相似性和单词嵌入的概念,还会讲笑话:
来源:作者
当被问到一个问题(“上周的皈依”)时,他是这样回答的:
来源:作者
与 Dash 的所有通信对其他用户来说是不可见的。这意味着你可以在任何频道或私人对话中使用 Dash,其他人不会注意到你使用了这个机器人。无数次,我在谈话中使用它来快速回答我关于数据的问题。
几个月前,我发现了谷歌的 DataQnA,并要求访问他们的私人 alpha。DataQnA 允许您将自然语言中的问题转换为 SQL 查询。
经过几次面试后,我获得了访问权限,并开始在 Dash 的新版本中工作。首先,2020 年的 Dash 现在有了一个面具:
来源:迪士尼粉丝维基
第二,Dash now 不仅仅会将你指向一个仪表盘— 它现在会尝试直接回答你的问题,因此你甚至不需要放松。DataQnA 的整合并不容易——但这是值得的。我们将不断集成越来越多的数据表到 Dash 中。这里有一个视频演示——当然是用假数据:
演示。来源:作者
我迫不及待地想看到 Dash 是如何不断成长的,直到我自动失业,然后他们解雇我。
原载于 2020 年 10 月 8 日https://fluent data . tech*。*
自动化 DCF 估价
使用蒙特卡罗模拟预测财务状况
DCF(贴现现金流)估值模型可能是金融专业人士拥有的最重要的金融工具。这种模型在理论和实践上都很棒,但是传统上在 excel 中执行,它有时在功能上相当繁琐。幸运的是,使用 Python,我们可以自动化这些评估步骤,然后更进一步,创建一个蒙特卡罗模拟函数,用于可视化潜在 DCF 结果的分布。
在 Unsplash 上由 Carlos Muza 拍摄的照片
**import** numpy **as** np
**import** pandas **as** pd
**import** matplotlib.pyplot **as** plt
%matplotlib inline
我们首先需要的是对我们年销售额的预测。我们将创建一个未来六年的数据框架,从理论上讲,它将从以前的财务报表中结转初始销售数据。
years = ['2020A', '2021B', '2022P', '2023P', '2024P', '2025P']
sales = pd.Series(index=years)
sales['2018A'] = 31.0
sales
我们现在已经构建了未来五年的销售增长(注:“A”=实际;“B”=预算;“P”=预计)。现在,我们将把预计的年度销售增长用于未来的预测。最终,我们可以用概率分布来代替这些估计,从而得到更真实的预测。
growth_rate = 0.1**for** year **in** range(1, 6):
sales[year] = sales[year - 1] * (1 + growth_rate)
sales
类似地,我们现在需要为 DCF 模型中的所有关键变量分配值或公式。这些变量将保持标准的财务定义。(注意:纳税将需要一个额外的 lambda 函数,以确保如果税前利润为负,我们就不会有正的纳税)。
ebitda_margin = 0.14
depr_percent = 0.032
ebitda = sales * ebitda_margin
depreciation = sales * depr_percent
ebit = ebitda - depreciation
nwc_percent = 0.24
nwc = sales * nwc_percent
change_in_nwc = nwc.shift(1) - nwc
capex_percent = depr_percent
capex = -(sales * capex_percent)
tax_rate = 0.25
tax_payment = -ebit * tax_rate
tax_payment = tax_payment.apply(**lambda** x: min(x, 0))
free_cash_flow = ebit + depreciation + tax_payment + capex + change_in_nwc free_cash_flow
我们现在有了预计的自由现金流(百万)。现在我们有了 FCF,我们可以开始实际的 DCF 估值模型。我们将计算终值,并将所有现金流贴现回现在。
cost_of_capital = 0.12
terminal_growth = 0.02terminal_value = ((free_cash_flow[-1] * (1 + terminal_growth)) /
(cost_of_capital - terminal_growth))discount_factors = [(1 / (1 + cost_of_capital)) ** i **for** i **in** range (1,6)]dcf_value = (sum(free_cash_flow[1:] * discount_factors) +
terminal_value * discount_factors[-1])
为了便于查看,让我们将这些变量打包成一个熊猫数据帧:
output = pd.DataFrame([sales, ebit, free_cash_flow],
index=['Sales', 'EBIT', 'Free Cash Flow']).round(1)output
创建蒙特卡洛模拟
因为我们对 DCF 模型变量使用了硬编码值,所以我们没有一个非常健壮的模型。幸运的是,我们可以通过引入蒙特卡罗模拟来改进这一点,该模拟将使用正态分布来随机生成和采样大量变量输入,然后将它们绘制成分布图。我们使用 numpy 来生成这些随机样本,然后迭代 10,000 次。
iterations = 10000**def** **run_mcs**():
*# Create probability distributions*
sales_growth_dist = np.random.normal(loc=0.1, scale=0.01, size=iterations)
ebitda_margin_dist = np.random.normal(loc=0.14, scale=0.02, size=iterations)
nwc_percent_dist = np.random.normal(loc=0.24, scale=0.01, size=iterations)
*# Calculate DCF value for each set of random inputs*
output_distribution = []
**for** i **in** range(iterations):
**for** year **in** range(1, 6):
sales[year] = sales[year - 1] * (1 + sales_growth_dist[0])
ebitda = sales * ebitda_margin_dist[i]
depreciation = (sales * depr_percent)
ebit = ebitda - depreciation
nwc = sales * nwc_percent_dist[i]
change_in_nwc = nwc.shift(1) - nwc
capex = -(sales * capex_percent)
tax_payment = -ebit * tax_rate
tax_payment = tax_payment.apply(**lambda** x: min(x, 0))
free_cash_flow = ebit + depreciation + tax_payment + capex + change_in_nwc
*# DCF valuation*
terminal_value = (free_cash_flow[-1] * 1.02) / (cost_of_capital - 0.02)
free_cash_flow[-1] += terminal_value
discount_factors = [(1 / (1 + cost_of_capital)) ** i **for** i **in** range (1,6)]
dcf_value = sum(free_cash_flow[1:] * discount_factors )
output_distribution.append(dcf_value)
**return** output_distribution
当我们绘制这个模拟图时:
这个输出图向我们显示,当迭代 10,000 个模型输入变量的潜在组合时,我们的贴现现金流值最常见的是在 2,300-2,500 万左右。
这是一个非常基本的介绍,介绍了 Python 在自动化金融操作方面的强大功能,但是蒙特卡洛模拟清楚地展示了这种强大的计算能力,它给了我们我们开始寻找的最终数字。请关注未来的帖子,这些帖子将进一步详细介绍如何使用 Python 实现日常财务任务的自动化。
利用卫星图像自动搜索土耳其的非法垃圾场
使用谷歌地球引擎为联合国进行图像分类
多年来,我作为地理信息系统和遥感专家的经历在人道主义领域的项目中留下了印记:联合国、世界银行、红十字会、WRI、无国界翻译组织;你说吧,我可能为他们做过一些工作。早在 2018 年,当我为 城市恢复平台——一家致力于为人道主义危机中的固体废物管理开发软件的法国初创公司——工作时,我们被赋予了一项非常简单但难以完成的任务:帮助 UNDP 和土耳其政府识别土耳其的每一个 非法垃圾场。
但是为什么呢?
土耳其独特的地理位置,与叙利亚和 T21 之间长达 911 公里的边境线,以及土耳其作为通往欧洲的陆路移民通道,导致土耳其接收了大量涌入的叙利亚难民。自 2016 年叙利亚危机开始以来,数百万人越境逃往土耳其东南部的安纳托利亚地区。2018 年 7 月安纳托利亚东南部登记在册的叙利亚人数量超过 350 万。
到 2016 年,移民将流入土耳其境内叙利亚人数最多的省份。东南部省份是难民营最多的省份,如桑尼乌尔法、加济安泰普和奥斯马尼耶。
这导致几个土耳其边境城市的人口结构发生了快速变化。例如,在基利斯,叙利亚难民的数量大于当地人口。
随着人口的流动,他们产生的垃圾也在增加。随着国内固体废物数量翻了一番,Analotia 东南部的省份开始面临越来越多的问题,如处理不足和收集和处理新人口产生的所有废物的能力不足。这导致了固体废物价值链的不平衡,导致了许多新的非法垃圾场的出现,以接收市政当局无法处理的废物。
Gaziantep 郊区的一个非法垃圾场,主要用于处理生活垃圾。
联合国开发计划署以其支持城市废物管理的明确任务为回应,推出了 东道社区有效城市废物管理方案,其中包括**关键基础设施投资、**如废物转运站和回收设施。
但是将垃圾从不受控制的垃圾场转移出去仅仅是升级整个垃圾收集系统的第一步。联合国开发计划署还想确保这些垃圾场正在进行重建。因此,需要一种方法来识别垃圾场。
你如何处理整个国家的图像?
因为我们没有办法走遍全国,希望能撞上隐藏得很好的垃圾场,所以我们求助于使用(滚筒…)卫星图像!
遥感领域的人们在机器学习技术成为现在的热点之前就已经在研究它了。主要的区别是他们一直在用一种几乎类似的方式做这件事,包括大量的点击按钮。该过程通常如下所示:
- 决定你将使用哪家卫星图像提供商,通常是在像 Maxar 的 Discover 这样的系统的帮助下;
- 通过从服务器上一张一张地下载或者购买(这通常需要两三次电子邮件交流)来获得你需要的每张图片;
- 训练像 ERDAS Imagine、eCognition 和 ArcMap 这样的桌面软件来识别您感兴趣的任何土地特征。
这就是 Maxar 的 Discover 的样子。这对于挑选一两张图像来说很好,但是如果你需要评估整个国家就不太好了。
嗯,在你不得不下载和分析像 T21 这么大的国家的图像之前,这都是有趣的游戏。
这需要你下载大量的图片,用它们建立一个马赛克,设置正确的参数,并指望你的机器能够在合理的时间内处理它。
幸运的是,我们现在可以用相当简单的脚本运行所有这些过程,而且更好的是,在云上运行。这就是谷歌提供的免费使用的 地球引擎 工具。
GEE 用户界面,文档、代码、控制台和地图都在同一个页面中。
正确物体的正确光谱带
如果你以前从事过图像分类工作,你会知道你应该总是对你正在看的任何东西的组成、形式和纹理有很好的理解。然而,废物的成分具有不同的密度、总体尺寸、化学成分,因此 光谱特征 。简而言之,也就是说,我们的目标以不同的强度反射不同的颜色(或光波波长),这使得很难将垃圾场检测为一种单一类型的物体。
Osmaniye 实地考察期间拍摄的建筑垃圾堆放场。
所以我们决定利用一个辅助分类模型。这个非常经典的模型包括用一组卫星图像中的训练样本“教”我们的代码垃圾场是什么样子,并告诉它搜索更多。这意味着为了开始,我们必须首先决定我们将使用哪个图像集合。由于我们没有任何获取图像的预算,我们将使用我们可以获得的最好的免费图像:哥白尼计划的 Sentinel-2 ,它提供了一个不错的空间分辨率(20 米像素,如果使用全景锐化,则为 10 米)和一个更好的光谱分辨率 (13 个波段,范围从 443 到 2190 纳米)。
哨兵 2 的光谱分辨率相当高。
为了用 GEE 实现这一点,我们声明一个我们称之为SENTINEL
的变量,然后使用ee.ImageCollection
方法声明我们正在寻找 哥白尼/S2 集合。然后,我们可以过滤这个集合,通过为云的百分比(< 10%)和采集日期(2018 年 1 月至 2018 年 8 月)设置阈值,找到实际上有用的图像。我们还使用 GEE 的 Assets 选项卡上传了一个压缩的 shapefile,其中包含我们感兴趣的区域,我们称之为southeasternturkey
,然后将它应用为边界过滤器。
这就是有趣的地方。即使我们刚刚过滤了集合,我们的SENTINEL
变量仍然保存了大量的图像,这些图像都是叠加的,有时是重叠的。我们要花很长时间来挑选最好的图像,并用它们构建一个马赛克。但是 GEE 提供了非常有用的median
方法,考虑到我们已经提供的过滤器,它提供了空间中任何给定点的中值像素值。所以我们把新的SENTINELMED
镶嵌图添加到地图上,看看它的自然色 RGB (B4,B3,B2)合成是什么样子。
我们的中间像素值马赛克的自然颜色 RGB 组成。
那是废物还是到处都是石头?
好的,太好了!那将是我们用来寻找弃尸点的拼图。我们接下来需要做的是建立一些训练样本,这样我们的代码就知道哪些像素是垃圾场,哪些不是:水、森林、庄稼、城市、裸露的土壤等等。对于垃圾场,我们将只导入由联合国提供的一些以前已知的垃圾场的 shapefile,对于其余的土地使用特征,我们将在 GEE 的地图上直接绘制这些**。一旦在地图窗格中创建了一个新图层,它就会在导入窗格中显示为一个变量。重要的是,我们导入的数据和绘制的特征都有一个属性,我们称之为class
,以及一个唯一的值。例如,垃圾场将会是'class:1'
,水将会是'class:2'
,等等。**
在 GEE 的导入窗格中设置训练样本。
一旦我们收集了足够多的样本,包括类别和范围,我们就可以将它们全部放入一个变量中。我们还需要确定哪些光谱带将用于执行分类。在我们的例子中,我们使用了所有这些。接下来,我们需要告诉 GEE 使用我们的几何图形并从选择的集合中提取像素,以便建立 样本区域 。这是我们的class
属性被使用的时刻。
现在我们可以使用Classifier
方法来训练一个算法。GEE 有许多不同的分类器,比如决策树和*随机森林,*举两个最流行的。这里我们将使用经典的推车** 分类器。我们将我们的样本区域和选择的波段输入它,它将返回我们自己的自定义分类器,我们可以使用我们想要的任何图像集合。**
最后,我们可以创建一个classification
变量,在这个变量中,我们将告诉我们的分类器用我们的SENTINELMED
马赛克施展魔法。然后我们可以将这个分类的结果添加到地图中,为我们创建的每个类指定颜色。
我们的分类镶嵌图是在云上计算的,并被添加到地图窗格中。
为了做更多的处理,我们需要将生成的光栅文件导出到本地机器上。GEE 提供了导出到 Google Drive 的功能,让这一切变得简单。
现在怎么办?
像素的分类是不防错的,尤其是考虑到不同的弃尸点可能彼此不同。为此,该模型需要最后一步,即通过视觉观察分析重新分类的像素群,如下所示。在进行分类之前,我们本可以使用一个分割程序**——也就是说,将我们的镶嵌图转换成单色几何图形——但是我们觉得既然没有那么多垃圾倾倒点,人眼就能更准确地识别它们。**
先前未知垃圾场的例子(1);重新分类的像素群集的形成(2);以及垃圾场的矢量化描述(3)
呈现暗色的潜在垃圾场
呈现浅色的潜在垃圾场
该模型在识别接收生活垃圾的垃圾场时最为有效,因为有机物呈现的深色是非常典型的。相反,当垃圾场接收来自建筑工地或拆除工地的碎石或废物时,识别集群的任务变得更加困难,因为这些很容易被误认为是采矿场。对于这些情况,视觉分析是最重要的,因为人眼比像素分类更容易识别这种垃圾场中观察到的模式。
通过这一过程总共描绘了 70 个多边形。这些多边形中的每一个都被怀疑是垃圾场。尽管如此,一些地点仍存在一些不确定性,仍需进一步核实。为此,我们使用 ArcGIS Online 应用程序模板 创建了一个 WebApp 用于数据编辑。该应用程序与联合国和土耳其政府官员共享,允许每个用户通过将每个划定的多边形分类为(1)建筑垃圾,(2)生活垃圾或(3)非垃圾场来提供输入。
开发地图注记工具是为了从了解具体环境的关键信息提供者那里收集见解。
根据关键线人的反馈,我们现在终于可以说我们成功识别了土耳其东南部的每一个垃圾场。该项目于 2018 年 8 月开展,是开发署为恢复该地区非法垃圾场而采取的第一步。接下来是一系列密集的实地行动,以确保废物价值链中的所有利益攸关方,从非正式收集者到回收者,都了解新的可用废物处理结构。土耳其政府采取的控制行动可以为垃圾场的有效恢复扫清道路。
由模型识别的所有七十个垃圾场
您可以通过下面的链接找到谷歌地球引擎图像分类模型。如果你愿意,不要犹豫,在这里或 Linkedin 上给我写信吧!
谷歌地球引擎上的古伊列梅·伊布洛诺夫斯基
code.earthengine.google.com](https://code.earthengine.google.com/2df85ba615c3223daaf2c72b85b31494) [## 古伊列梅·m·亚布洛诺夫斯基-产品经理| LinkedIn
我对如何重新利用专注于领域的学科的技术和论述充满热情…
www.linkedin.com](https://www.linkedin.com/in/guilherme-m-iablonovski-08013143/)**
使用假设在 Python 中自动化单元测试
凯文·Ku 在 Unsplash 上的照片
单元测试是产生高质量代码的关键。下面是如何实现自动化。
单元测试是开发高质量代码的关键。有许多可用的库和服务,你可以用它们来完善你的 Python 代码的测试。然而,“传统的”单元测试是时间密集型的,不太可能涵盖你的代码应该能够处理的所有情况。在这篇文章中,我将向你展示如何使用基于属性的测试和假设来自动测试你的 Python 代码。我还讨论了使用基于属性的测试框架的一些优点。
基于属性的自动化测试
单元测试包括测试代码的单个组件。典型的单元测试获取输入数据,通过一段代码运行它,并根据一些预定义的预期结果检查结果。
假设做了一些不同的事情。它是一个基于属性的(或:“生成的”)测试框架。基于属性的测试包括定义对代码的一般期望,而不是具体的例子。例如,如果您有一些代码来计算一些交易的总增值税,您可以定义一组假设的数字及其相应的增值税金额(100 美元交易→ $xx.xx 税),并对其进行测试。然而,如果你知道增值税是,比方说,20%,一个基于财产的测试将验证总增值税始终是总额的 20%。
假设是建立在这些原则之上的。它根据某个规范生成任意输入数据,并随后对该数据进行测试。更重要的是,当 Hypothesis 发现一个导致断言失败的例子时,它会试图简化这个例子,并找到最小的失败案例——这个过程称为“收缩”。假设实际上会试图“破坏”你的代码。因此,您的测试将用相同数量的代码覆盖更大的领域空间。而且,你一定会发现你甚至没有想到的边缘情况。
假设入门
让我们看看假设在实践中是如何工作的。假设有三个关键部分:你正在测试的代码,定义你的测试数据的策略,和一个使用策略测试你的代码的函数。
让我们假设我们有一段简单的(无意义的)Python 代码,它将浮点值转换为整数:
这段代码有一个明确的属性:结果应该总是整数类型。
策略
为了测试这段代码,我们将首先定义一个“策略”。策略定义了假设为测试生成的数据,以及如何“简化”示例。在我们的代码中,我们只定义数据的参数;简化(或:“缩小”)是假说的内在要求。
我们将从生成 0.0 到 10.0(包括 0.0 和 10.0)之间的浮点值的策略开始。我们在一个名为data_strategies.py
的单独文件中对此进行了定义。为此使用一个数据类可能看起来有点过头,但是当您处理带有一堆不同参数的更复杂的代码时,这是很有用的。
使用数据类和假设来定义数据策略
很多时间可以用来定义策略,事实上也应该如此。使用假设进行基于属性的测试的全部要点在于,您定义了生成数据的参数,以便您随后允许您的自动化测试发挥其魔力。你在这上面花的时间越多,你的测试必然越好(想想:“高投入;高奖励”)。
将代码和策略结合在一起:用假设运行测试
在我们定义了我们的策略之后,我们添加了一小段代码来将假设生成的示例传递给我们的函数,并断言我们想要测试的代码的所需结果(“属性”)。下面的代码从我们在上面的data_strategies.py
文件中定义的generated_data
dataclass 对象中提取一个浮点值,通过我们的convert_to_integer
函数传递该值,最后断言期望的属性保持不变。
使用假设定义您的测试模块
配置假设:有用的设置
在我们运行上面开发的测试模块之前,让我们回顾一下一些配置,我们可以使用这些配置来为我们的用例定制假设。假设自带一堆设定。这些设置可以使用settings()
装饰器传递到您的测试函数,或者通过在一个概要文件中注册设置,并使用装饰器传递概要文件(参见下面的示例代码)。一些有用的设置包括:
max_examples
:控制测试结束前需要多少个通过的例子。如果您对一段新代码通过评审所需的测试量有一些内部指导方针,这是很有用的。一般来说:你的代码越复杂,你想要运行的例子就越多(假设的作者注意到他们在测试 SymPy 的时候,在几百万个例子之后找到了新的 bugsdeadline
:指定单个例子允许用多长时间。如果您有非常复杂的代码,其中一个示例运行的时间可能会超过默认时间,您会希望增加这个值;suppress_health_check
:允许您指定忽略哪些“健康检查”。当您处理大型数据集(HealthCheck.data_too_large
)或需要很长时间才能生成的数据(HealthCheck.too_slow
)时非常有用。
让我们在测试模块中使用这些设置。有了这些简单的代码行,我们现在可以继续前进,在我们的函数中抛出 1000 个例子来验证它是否按预期工作。您可以从终端(python -m pytest test_my_function.py
)运行测试,或者如果您使用像 Pycharm 这样的 IDE,通过 s 为您的代码指定适当的 pytest 配置。
使用假设设置对 Python 代码进行基于属性的测试
升级你的游戏:使用复合策略
到目前为止,我使用的例子都很简单。Hypothesis 可以使用复合策略处理复杂得多的测试用例,顾名思义,复合策略允许您组合策略来生成测试用例。所以,让我们开始游戏,在更复杂的环境中使用假设。
假设您已经开发了一段计算数组百分比值的代码。有很多 Python 库可以为您完成这项工作,但是假设您对百分位特别感兴趣,并且只是想要一个自己的实现。在这个例子中,我们的目标是根据现有的实现对我们的解决方案进行基准测试。考虑到这一点,我们可以定义这段代码的两个简单属性来进行测试:
- 我们用来计算百分位数的数值数组的顺序对其结果并不重要;
- 该函数的输出需要与用另一个普遍接受的库计算的值一致(注意,将它定义为“属性”有点不典型——在本文的最后一节会有更多的介绍)。
让我们从百分位数函数开始。这里,我们实现了一个使用中点插值的版本。该函数接受整数值或浮点值(arr
)的数组,对其进行排序,根据指定的百分位(perc
)确定下限和上限,最后取两个值的中点。
简单的百分位数函数
现在,让我们继续我们的策略,也就是,我们为测试生成的数据的定义。这里,我们定义了一个名为generate_scenario
的函数,它基于随机选择的分布(dist
)产生一个随机长度的浮点值数组(n
)。我们还生成我们想要计算的百分比值(perc
)。我们将值和百分位数作为字典返回,因此我们可以轻松地访问测试所需的值。注意@st.composite
装饰器的使用,它将"一个返回一个例子的函数转换成一个返回产生这样的例子的策略的函数。
在假设中定义复合策略
最后,我们可以在测试模块中使用我们的复合策略。在这个模块中,我们指定我们的策略设置(SETTINGS
),并指定一个运行我们自己代码的函数。test_calc_percentile
函数测试反转数组顺序不会影响我们的 percentile 函数的输出,并将结果与 NumPy 实现进行比较。使用我们在这里设置的配置文件,我们运行 10,000 个示例,在我五年前的笔记本电脑上大约需要 30 秒来完成。
使用复合策略的测试模块示例
在你开始测试之前:关于你什么时候应该和不应该使用假设的说明
在你开始开发你自己的单元测试之前,有一些事情你需要知道。基于属性的测试在特定的环境下非常有效。当一段代码的属性被很好且容易地定义时,它是一个强大的框架,也就是说,“我的代码的 x 部分需要产生一个具有属性 y 的结果”。当定义“assert”语句的条件与您试图测试的代码一样复杂时,您将最终重新实现您现有的代码。
在某些情况下,拥有两个并行的实现可能是合适的,例如,当您创建了一段新的代码,或者用一个新的框架重新实现了一些东西,您需要针对现有的实现进行基准测试,如上面的示例所示。然而,在大多数情况下,事实并非如此:您将浪费时间和资源,最终不得不维护两段做完全相同事情的代码。
即使在自动化测试时,在“传统的”单元测试和基于属性的测试之间走一条中间路线也是明智的。您将希望避免让您的测试成为太多的“黑盒”,并确保您覆盖了明显的情况,尤其是在开发的早期阶段。总是建议至少创建几个很好理解的场景。并且,将你自己的“手动”测试用例与自动化测试结合起来,将会对提高你的测试覆盖率大有帮助,并且可以极大地改进你的代码。
感谢阅读!你喜欢用哪些 Python 工具来提高代码质量?请在评论中留下你的建议!
支持我的工作: 如果你喜欢这篇文章并愿意支持我的工作,请考虑通过我的推荐页面 成为付费媒介会员。如果你通过我的推荐页面 注册 ,订阅的价格是一样的,但是我会收取你每月的部分会员费。
如果你喜欢这篇文章,这里还有一些你可能喜欢的文章:
实施代码风格是简化开发过程的关键,下面是如何实现自动化。
medium.com](https://medium.com/python-in-plain-english/how-to-improve-your-python-code-style-with-pre-commit-hooks-e7fe3fd43bfa) [## 为您的 Python 项目自动化版本标签和变更日志
基于项目的提交历史,使用 commitizen 实现版本标签和变更日志自动化的实践指南
towardsdatascience.com](/automating-version-tags-and-changelogs-for-your-python-projects-6c46b68c7139) [## 简化您的 Python 代码:用 Wily 自动化代码复杂性分析
以下是如何让评估代码复杂性成为 Python 开发例程的一部分
towardsdatascience.com](/simplify-your-python-code-automating-code-complexity-analysis-with-wily-5c1e90c9a485)
请仔细阅读 本免责声明 中的任何内容后再依托 我的 Medium.com 文章 。
Py-Spark & SparkNLP 上的情感分析和主题建模自动化(使用 Twitter 大数据)
大数据平台 SparkNLP 上的高级 NLP
如何使用 spark 框架处理文本大数据并自动化 NLP 模型
马库斯·温克勒在 Unsplash 上的照片
“如今的选举不一样了,社交媒体已经大大改变了它们!”—哦,是的,我。
在过去的十年里,政治社交媒体(主要是推特)账户的使用量激增。许多政治领袖(有时是他们的家人)正在使用 Twitter 作为与他们的公民交流的一种卓越模式。然而,这导致了一些有趣的问题。不仅是美国的选举,最近世界上最大的民主国家印度的选举也因社交媒体的影响而被指责为**''(查看此文由’ 《华盛顿邮报》 ’ 了解我这里的意思)。这种偏见,主要以 两极化的“公众情绪” 的形式,通过扭曲脆弱的社交媒体结构而注入。
想到美国政治和推特,你脑海中可能会浮现唐纳德·特朗普总统。自 2015 年特朗普发起政治竞选以来,他因所谓的负面、贬损&有些挑衅的推文而臭名昭著。给他 280 个字符的限制,他会把它翻译成一个由情感、情绪、事实和观点组成的包(通过’ 《纽约时报》 ’ 了解他玩的大部分推文)。甚至Vox(美国著名新闻与观点网站),在其一篇文章中,也证实了特朗普发很多,&量子真的在那里。
所有上述事实,结合我先进的分析知识,让我思考——我能开发一个能够跟踪 2020 年美国总统大选候选人社交媒体行为的直播应用吗?
我花了大约一个月的时间,用下面的话完整地回答了我上面的问题:
作者图片**
研究问题:
在进行这个项目时,我特别关注以下问题,同时牢记两位候选人(Donald j . Trump&Joe Biden):
- 两位候选人的*【Twitter-holdings】***(用户群)是否存在微小差异?(回答人:子话题 1.2 中的一般 Twitter 分析)
- 候选人试图从他们的日常推文中获得什么样的?(回答人:使用子主题 2.2 中的 SparkNLP 对推文进行情感分析)
- **【用户行为】 (通过研究用户层面的推文情绪)对这些候选人的日常表现如何?(回答人:使用子主题 2.2 中的 SparkNLP 对推文进行情感分析)
- 这些候选人在推特上谈论的(前 3 名)‘讨论最多的话题’是什么?(回答人:使用子主题 2.3 中的 SparkNLP 进行 LDA 主题建模)
- 有没有一种方法可以让我每天的分析自动化?(回答:使用 windows cmd 的模型本地部署&将数据连接到子主题 3 中的实时开源 RDBMS PostgreSQL)
1.数据管道:
回答上述问题的第一步是收集适当的数据&将它们存储在数据库中。为了理解候选人水平分析(问题 1、2 和 4),我需要与特定候选人相关的信息。对于用户层面的分析(用户观点——问题 3 ),我需要与接受调查的候选人相关的一般推文数据。
1.1 候选级别数据收集:
为了获取候选级别的数据,我决定使用官方的tweeper 的开发者 API ,而不是 python 原生的‘Tweepy Package’。在处理新获取的自然文本数据时,我还使用了一个清理函数(“clean_tweets”),如下面的代码片段所示:
1.2 用户级数据收集:
根据官方指南,Twitter API 每 3 小时只允许 3 00 条推文。因此,这么多的数据不允许我对用户级别的数据进行适当的情感分析。为了避开这个限制,在做了一些研究之后,我决定使用优化的 Get Old Tweets 3 包装器。它允许我获取与候选人相关的历史性推文。尽管如此,推特的最高点击率是 10,000 次。因此,我每次点击都附上 15 分钟的睡眠周期。
1.3 在 RDBMS PostgreSQL 中存储数据:
由于我计划自动化模型,并考虑到每天 20k+ tweet 数据读取量,我正在寻找一个开源 RDBMS 来存储我的数据。我使用 python 的【psycopg 2】库将我的数据连接到 PostgreSQL,在这里,我将候选人级别和用户级别的数据分别存储在不同的表中。
2.使用 SparkNLP 进行情感分析和主题建模:
由于我计划每天更新我的应用程序数据,我一直在寻找一个 NLP 解决方案,它可以让我获得最快且更准确的“情感分析”和“主题建模”框架。经过几天的研究,我发现了一个由 约翰斯诺实验室 开发的 大数据框架。 该框架被称为【Spark NLP】。 它是建立在 Apache Spark ML 之上的。它提供了 简单的表演的*&精确的 NLP 标注,便于在分布式环境下为机器学习流水线中的**进行缩放。Spark NLP 自带220+管道 和 型号 超过 46+ 语言。它支持最先进的变形金刚,如 伯特 ,XLNet,【ELMO*,* 艾伯特 , 通用它还提供了标记化、词性标注、命名实体识别、依存解析、拼写检查、多类文本分类、多类情感分析以及更多 NLP 任务。***********
2.1 设置 Spark NLP 环境:
那些使用过 py-spark 的人应该知道在我的本地机器上实现 py-spark 环境的挑战。经过多次修改安装&卸载各种版本的 py-spark,终于找到了正确的组合’py spark 2.4。4’&Java 版本’JDK v . 8.0’与 spark NLP 完美配合。一旦我安装了&并为我的 pyspark 设置了路径,我就安装了最新版本的“ sparkNLP ”。此外,在安装了 spark & sparkNLP 之后,我使用 sparkNLP 启动了一个 spark 会话(您也可以使用 spark 本身启动一个自定义会话)&导入了必要的 SQLContext,在模型构建的后续阶段,可能需要用到它来处理 spark 数据帧。
2.2 使用 SparkNLP 设置情感分析管道:
设置好环境后,我构建了一个主函数,它将我之前构建的 熊猫数据帧作为输入 &提供每条推文的 文本长度 以及 情感分数 。该函数是使用类似于许多其他机器学习库的 管道 概念构建的,它由两个主要组件组成,如估计器(估计数据和训练模型)和 转换器 (转换数据和应用模型),它们被定义为 注释器 。在构建管道时,注释格式保持非常特定,这与**'注释指南’相匹配,因为它们以非常特定的格式获取输入和输出数据。因此,保持按特定顺序构建的管道的流动变得非常重要。例如,在标记器的 Spark NLP 的 文档 中,您可以看到这个注释器只接受注释器类型文档的输入数据,并输出标记类型的数据。因此,在 Spark NLP 管道中进出注释器的正确类型需要特别注意。**
以下是用于我的分析的管道元件的流程和基本功能:
I . ‘document assembler’ Transformer:为我们的第一个注释器格式化原始输入文本数据
二。标记器‘注释器:用标记化开放标准识别标记
三。规格化器注释器:清理数据并执行小写
四。 LemmatizerModel '注释器:将数据中的所有单词放到它的 lemma(基本形式)中
动词 (verb 的缩写)停用词清理器’注释器:删除不必要的(重复的)常用词集(如’ a ‘、’ the ‘、’ in ‘、’ is ‘、’ to ‘、’ at '等)。)
不及物动词注释器:将 n 元语法合并到我们的 NLP 管道中
七。感知器模型’注释器:使用一个预建的词性标注模型来避免我们的 n 元语法中不相关的词性(POS)标签组合
八。完成器转换器:将最终的注释器输出转换成可用的格式
***一旦在输入数据上拟合了上述管道(代码行 1 : 78),我就利用一个 *预训练管道‘analyze _ sentiment dl _ use _ Twitter’来确定我的完成器输出的情感分数(代码行 80 : 85)。
最后,一旦安装了定制管道并计算了情感分数,所有的原始列都在‘id _ tmp’列上被连接到新的’ sentscores '列(代码行 95: 98),并生成最终输出。一旦制作了 Spark 数据帧,它将再次转换为 pandas 数据帧,以供用户使用(代码行 107: 120)
上述函数的输出如下所示(对于每个传递的数据文件):
2.3 使用 SparkNLP & Py-Spark 进行主题建模:
因为 SparkNLP 本身不支持文本矢量化,所以我结合 SparkNLP 和 Py-spark ML 特性来构建 LDA 模型。我使用了从 SparkNLP 管道开发的干净的 n-grams & unigrams 作为对 pyspark ml 库 的“”模型(帮助我们计算 TF-IDF 词频-逆词频/词重要性)的输入。此外,TF-IDF 输出用于训练 pyspark ml 的 LDA 聚类模型(最流行的主题建模算法)。**
3.自动化:
为了实现上述所有步骤的自动化,我结合使用了 python 框架和 windows 命令提示符。我将所有的函数和它们的 python 脚本按顺序连接起来,产生了一个主函数。py 文件。这个 python 主脚本被本地 python.exe 使用 windows 批处理(.bat)文件。最后,使用 windows 任务计划程序将批处理文件置于自动执行模式。此外,使用 python 中适当的打印行文本命令,我设法在每天执行代码时在. txt 文件中获得’ 执行报告 '。执行报告的一个片段如下:
为了利用我的开源 twitter (Election2020)数据&关于用 Python 中的 Spark 进行主题建模管道的更详细脚本,请查看我的 github 代码报告。
检查我的Live-App(Tableau-Public),在一个平台上展示所有上述分析。
在我的 LinkedIn 、电子邮件、&、个人作品集中找到更多我的信息。
自动机和超级智能
照片由 Maximalfocus 在 Unsplash 上拍摄
通过人工智能的两种潜在状态来理解它。
近十年来,人工智能一直是技术和媒体领域的新流行语。它(很快)未来的工作自动化是杨安泽的普遍基本收入的动机,它通过谷歌和脸书对我们的理解导致了隐私和道德方面的可疑行动——导致了两部著名的网飞纪录片 The Great Hack 和The Social Dilemma——其快速的改进速度让许多领域外的人感到恐惧。
一旦人工智能达到超级智能,没有人知道人类的未来将走向何方——就像普通公众如何忘记我们的数据将成为新的石油一样。未来人工智能将呈现两种状态:机器人和超级智能生物。自动机是一种能够准确有效地执行重复性程序任务的机器人,而超级智能生物是——你猜对了——一种超越我们目前所理解的智能的程序,为了方便起见,我现在在本文的其余部分将其称为 AGI(人工通用智能)。
现在,我必须指出显而易见的是,AI 的这两种状态产生了许多可能性。在这篇文章中,我的目标是分解我们应该从这些状态中期待什么,以及在处理它们时可能出现的伦理问题。
在自动机的情况下:
目前有许多不同模式的自动机在运行,但没有一种能与 AGI 的潜力相提并论。暂且忽略典型的人工智能程序,机械臂、爪子和其他自动化机械主导着工厂生产,因为它们与人类相比具有一致的生产率,而且随着时间的推移,这只会进一步增加。
我们已经习惯了生活中许多方面的自动化。越来越多的工作被机器人自动化只是时间问题。当与 AGI 的潜力相比时,我认为我们看到并与之交互的大多数——如果不是全部——人工智能程序在未来将被视为基本的自动机,因为它们很简单。
但是等等,谷歌和脸书利用我们的大量数据,可能比我们更了解我们。那不算超级聪明吗?
你完全可以说,与人类相比,谷歌和脸书的广告人工智能超级聪明。然而,我仍然认为它是一台自动机——是我们迄今为止最聪明的一台。这种考虑的主要原因很简单:它所做的一切都可以归结为一个目标:为我们提供它认为我们喜欢的帖子(无论是图片、视频、广告等等)。)它有一个目标,并不断优化以实现这个目标,而且做得很好。
**快速切线:**我想非常明确的说,它的知识库来自于不可逾越的数据量。对我来说,试图描述数据到底有多大是没有意义的,因为我们都不会真正理解它。把它想象成空间的大小,你知道它很大但是它到底有多大?随着这些数据而来的是智能,让我们与为我们量身定制的东西进行交互。然而,由于其唯一目标的“局限性”,它只是一个真正智能的自动机,给我们提供越来越多各种形式的帖子,而没有真正理解我们如何解释帖子——它只是(准确地)假设我们会与它互动。
那么,所有这些都摆在我们面前,我们该何去何从呢?
机器人将不可避免地在各自的应用领域变得更加智能,并取代人类完成这些任务。这些任务可以是在麦当劳卖汉堡,给我们送信,清扫街道,建造摩天大楼。任何物理任务都可以而且将会自动化。
作为一个集体,我们的工作是让技术进步改善我们的生活,而不是毁掉它。为机器以很小的价格(长期)夺走了你的工作而愤怒是一回事,但为机器抢走了你的工作而愤怒又是另一回事。这忽略了一个事实,那就是取代你的是人类的决定,而不是机器人。当谈到自动机时,它们不会决定一个濒临财务不稳定的努力工作的工人阶级家庭的未来。另一个人会。
就 AGI 而言:
把机器人和 AGI 混为一谈是愚蠢的。很多人都这样做。别犯傻了。
尽管 GPT-3 是目前写这篇文章时最好的自然语言模型,但与人类相比,它还是很笨。我相当节制地使用愚蠢;这是一个极其智能的程序,但这是因为用于训练它的数据量庞大,而不是因为它的实际智能。它在性能上的失败表明,要被认为与人类没有区别,它还有很长的路要走。就目前而言,这是一个记忆和反刍大量文本的优秀程序。
出于一个原因,很难对 AGI 做出假设。就像我们无法预测谷歌和脸书内部的技术-广告复合体一样,我们也无法准确预测 AGI 将如何形成。我不怀疑许多公司推动以人为中心的 AGI 背后的动机,例如 OpenAI 、 DeepMind 和 SingularityNET 。事实上,他们是我个人最信任的公司。然而,即使有了所有的制衡机制,我们仍然无法预测结果会是什么。
我们不知道 AGI 是否会从智力低下的起点开始,随着时间的推移慢慢提高,或者以超出人类理解的速度成倍提高。我们不知道它在运作时将如何或是否考虑人的价值。我们不知道它是否会爱我们,帮助我们更多地了解自己,是否会恨我们,杀死我们所有人,或者认为我们如此愚蠢,以至于人类对他们没有价值,让地球完全把我们带回到我们开始的地方。
无论是在面部识别中大量使用 POC技术,还是在招聘中歧视女性,以及如果你有很重的口音就无法识别你的声音,这些事件发生的一个主要原因是:偏见。假设 AGI 有能力学习人类的一切,当我们自己对彼此的看法有偏见时,它将永远达不到这种潜力。然而,创造无偏见的数字头脑是极其困难的,因为我们只能在这些机器已经为大众使用而训练和调整时才能看到它们的偏见。即使非常小心地确保一个系统是公正的,它也可能不可避免地在其他地方表现出偏见。一些偏差,像上面提到的那些,并不是微不足道的,并且显示了这些模型的当前和未来迭代的大量危险信号。
关于高维度偏见是什么样子,或者它如何影响 AGI 对人类的“态度”,没有固定的答案。然而,彻底消除偏见是伟大的第一步。然而,说起来容易做起来难。这个论点来自于一个人类物种不知道如何消除彼此之间的偏见。
总而言之,随着人工智能越来越多地与人类融为一体,人类生活将从根本上发生变化。这种转变对许多人来说是可怕的,对另一些人来说是令人兴奋的,但也有一些人对此视而不见。如果历史重演,我相信人工智能会让人类走向更高的生活水平和更好的生活质量。考虑到这一点,不平等必然会一直存在。我们只能希望这些超级聪明的人发现不平等是一个微不足道的人类问题,需要解决,而不是加剧。
感谢您的阅读。
大数据和自动化
或者如何对 40+ GB 的数据集使用 Google AutoML
Cloud AutoML 是谷歌云平台的一部分。AutoML 提供令人印象深刻的图像分类结果,无需任何数学或技术背景知识。对于 40 GB 以下的图像数据,图像可以直接加载到 AutoML 模块中。对于更大的数据集,必须首先将数据下载到一个虚拟机中,然后传输到存储桶,再从那里传输到 AutoML。
对于小于 40 GB 的数据,请考虑这个教程(它为你节省了一些开销)。
我使用的数据集由 112,120 张 X 射线图像组成,这些图像带有来自 30,805 名不同患者的疾病标签[1]。本教程的目标不是深入医学细节,而是展示大型数据集的 AutoML 工作流。您可以在以下位置找到本教程的数据:
来自 30,000 多名不同患者的 112,000 多张胸部 x 光图像
www.kaggle.com](https://www.kaggle.com/nih-chest-xrays/data)
新项目
在 Google 云平台中,首先创建一个新项目。
并建立一个新的帐户。有了 300 美元的免费积分,本教程对于了解 AutoML 工作流来说是完美的。
虚拟计算机
设置新的虚拟机实例。我用的是 50 GB 磁盘的 Debian GNU/Linux 9 (stretch)。
设置好 VM 后,打开云 Shell 并输入以下命令来下载 python 和 pip。
sudo apt update
sudo apt install python3 python3-dev
wget [https://bootstrap.pypa.io/get-pip.py](https://bootstrap.pypa.io/get-pip.py)
sudo python get-pip.py
pip –version
然后执行:
sudo pip3 install kaggle
能够通过 kaggle API 下载数据集。
将您的 kaggle API 令牌上传到环境中。你可以在你的卡格尔账户里找到它。
创建一个新文件夹,并将 API 令牌放入其中。
mkdir .kaggle
mv kaggle.json .kaggle/kaggle.json
然后下载数据集:
kaggle datasets download -d nih-chest-xrays/data
在不到 15 分钟的时间里,您已经下载了完整的 42 GB。最后,解压缩数据:
unzip data.zip
传输文件可能需要允许完全访问所有云 API。
查看这篇 StackOverflow 帖子以获得更多帮助。
存储桶
解压文件后,你将数据传输到谷歌云存储中。创建一个新的存储桶,并给它一个明确的名称。
执行
gsutil -m cp -r [DATA FOLDER] gs://[BUCKET NAME]
将所有数据复制到云存储中。为了加速这个过程,–m 标志确保使用所有的虚拟机内核。尽管如此,这需要一些时间。–r 标志复制完整的文件夹。
AutoML
在数据被完全复制后,转到 Google Cloud 中的 AutoML 并创建一个新的数据集。
在这种情况下,我们有一个多标签分类。这些图像将通过您必须提供给 AutoML 的 CSV 来选择。
AutoML 需要标签的 CSV 文件来指示图像是如何分类的。标签必须以字母开头,并且只能包含字母、数字和下划线。一张图片最多可以容纳 20 个标签。您还可以将标签留空,以便使用 UI 或人工标注服务进行手动标签定义。
有关详细信息,请查阅:
https://cloud.google.com/vision/automl/docs/prepare
培养
然后你看到你的图像的标签,你可以开始训练一个模型。我建议从 1 或 2 小时这样的低预算(训练时间)开始。完成训练后,你总是可以训练更长时间。
为了避免成本,请记住关闭您的虚拟机,或者在不再需要该项目时将其完全删除。
我希望这篇教程能帮助你用 Google Cloud AutoML 处理大型数据集!
[1] X. Wang,Y. Peng,L. Lu,Z. Lu,M. Bagheri 和 RM .Summers, ChestX-ray8:医院级胸部 X 射线数据库和常见胸部疾病弱监督分类和定位基准 (2017),IEEE CVPR
15 个人对 2 台机器。谁赢了?
15 名学生研究了 8 个数据集,试图超越 2 个领先数据科学平台的性能。找出谁赢了!
有很多关于自动机器学习(AutoML)工具的讨论,这些工具可以自动化数据科学流程,从而自动生成数据驱动的见解,而不需要数据科学专家。听起来很有希望,但他们在现实中表现如何?这样的平台能胜过人类吗,数据科学家会过时吗?还是人类能打败机器?
在这篇博客中,15 名学生使用机器学习模型研究了 8 个数据集,试图击败 2 个领先的数据科学平台(H2O 和 SparkBeyond)的性能。
选手们
机器
https://www.h2o.ai/products/h2o-driverless-ai/()H2O 无人驾驶人工智能使数据科学家能够更快、更有效地开展项目,通过自动化在几分钟或几小时内,而不是几个月内完成关键的机器学习任务。它提供自动特征工程、模型验证、模型调整、模型选择和部署、机器学习可解释性、自带配方、时间序列和模型评分的自动管道生成。
spark beyond(https://www.sparkbeyond.com/)是一个人工智能驱动的研究引擎,用于发现模式,预测结果,并利用网络上的数据仓库。SparkBeyond 的独特竞争优势在于其强大的特征发现引擎。专注于提高模型预测准确性的特征,SparkBeyond 能够在短时间内生成数十万个特征,并根据其重要性进行筛选。
学生们
来自 NYU 的 15 名金融工程硕士学生参与了这个项目。我们有相关的机器学习经验,并努力成为合格的数据科学家。我们深入研究了 AutoML,以加深我们对机器学习领域的理解。
数据集
我们在比赛中使用了 8 个著名的开源数据集。
分类:
泰坦尼克号(从 H2O 下载):利用乘客的信息预测泰坦尼克号上乘客的生存情况。
鸢尾:利用萼片和花瓣的长度和宽度预测鸢尾的种类。
心脏病:利用生理数据预测患者是否患有心脏病。
Lending Club(由 Spark Beyond 提供):使用财务指标预测贷款违约。
回归:
零售销售预测(由 H2O 提供):使用商店和区域数据预测销售量。
广告:利用不同媒体上的广告支出预测销售额。
波士顿房价:利用社区和房屋数据预测波士顿房价。
金县的房屋销售:利用房屋特征预测房屋销售价格。
实施
对于实现,我们使用最低接触(以避免给机器人类的优势!)H2O 和 SparkBeyond 的 AutoML 功能;我们还花了 1 周时间让学生建立模型和预测数据。
对于 H2O,用户可以使用它开箱即用,没有很多调整。对于 SparkBeyond,用户可以选择他们想要使用的算法和功能数量。对于人类,15 名学生在每个数据集上测试了几种算法,保留了最好的一种与 AutoML 进行比较。
超越界面的 H2O 和火花
结果
下图是机器对人类和 H2O 对 SparkBeyond 的赢家数量的饼状图。决定获胜者的标准是:如果该方法的 CV 和测试分数都获胜,则该方法为获胜者;如果该方法的 CV 或测试分数中只有一个获胜,则结果为“平局”。
中奖人数(详细数据见附录中的表 1 和表 2)
下面的条形图显示了标准化的指标—人与机器的百分比。需要注意的是,我们对前 3 个数据集使用了均方误差,包括金县的房屋销售、波士顿房价和广告。为了更容易与其他指标进行比较,我们选择使用这 3 个数据集的归一化指标的倒数。
如果标准化度量> 100%,则表明人类优于机器。我们可以看到,对于 CV 分数,人类只在一个数据集上对机器有细微的优势。然而,就考试成绩而言,一半的人打败了机器。
人%机器(人的结果占机器结果的百分比)
那么谁赢了,人还是机器?
“竞争”的结果是,在 8 个数据集里,AutoML 赢了 4 场,3 场平局,人类赢了 1 场。
对于我们测试的 8 个基本数据集,AutoML 模型相对于手工挑选的模型显示出明显的优势。然而,如果我们仔细观察预测分数,人类和 AutoML 之间的表现差距是微妙的。
只有一组在交叉验证分数上超过了机器。然而,有 4 组在测试分数上超过了机器。这个特殊的实验表明人类模型在测试集上比在训练集上有更好的机会击败 AutoML 模型。 AutoML 的特征工程和模型选择完全基于性能,这可能会在训练集上获得更高的分数。然而,这种方法也降低了模型的可解释性,并可能导致轻微的过度拟合问题。另一方面,学生更依赖于对数据集的理解,因此,人类模型可以生成有竞争力的样本外结果。但请注意,即使是样本外的分数,也只有一半的人类模型击败了机器模型。总体而言,AutoML 仍有不可忽视的优势。
关于 AutoML 的利与弊,你需要知道什么
总的来说,AutoML 可以成为数据科学家解决问题的一个很好的起点。它还可以帮助非数据科学家轻松获得最好的机器学习。
H2O 和斯帕克比谁更强?
总的来说,在我们测试的 8 个数据集(H2O 3 胜,spark beyond 2 胜,3 平)上,一个平台相对于另一个平台没有明显的优势。在这两个平台上的实验中,学生们发现 SparkBeyond 具有更好的特征工程功能,而 H2O 通过提供详细的报告和模型解释功能而更加用户友好。
下一步是什么?
在我们的实验中,一些团队通过将 SparkBeyond 生成的要素添加到数据集,然后在 H2O 上执行 AutoML,取得了出色的结果。结合每个数据科学解决方案提供商的最佳功能可能是未来探索的一个有趣方向。
我们在这个实验中使用的数据集既简单又普通。当处理更复杂的数据集时,数据科学平台可能会展现出更多的魅力。我们的团队将继续探索这些平台,在具有不同结构的更复杂的数据集上实现它们的功能,如时序数据、非结构化/文本数据、不平衡/倾斜数据等。请继续关注我们的下一篇文章。
如果您想了解我们项目的更多信息,请随时通过 LinkedIn 联系 15 名才华横溢、训练有素的 NYU 金融工程硕士学生。我们对与 AutoML、数据科学和量化金融相关的讨论持开放态度。
分类:
泰坦尼克号:,于
虹膜:,顾
回归:
广告:,杨
波士顿房价:刘贺静,
景县房屋销售:元泰谢,
附录
最佳机器和最佳人类的表现
H2O 和斯帕克的表现
标准化指标:人%机器
时间序列预测的 AutoML
《辛普森一家》第七季第 135 集(“特大号荷马”)
虽然我不是现在汽车的粉丝,但我喜欢参加汽车比赛。我相信这样的比赛是一个很好的学习机会,可以为未来的项目提供强大的管道。AutoML 竞赛介于 Kaggle 类竞赛和 LeetCode 任务之间:您的代码应该给出高分,并且应该稳定快速。
最近我参加了汽车系列——汽车时间序列数据竞赛,我在 40 名参赛者中获得了第一名(15 名进入决赛)。这篇文章概述了我的解决方案。
我在莫斯科 2020 年奥维托 ML 培训期间关于最终解决方案概述的讲话
竞争描述
AutoSeries 是网络搜索和数据挖掘( WSDM )大会的竞赛项目之一。该比赛是由 4Paradigm 和 ChaLearn 举办的第 10 届 AutoML 比赛。之前的目标是为表格数据、计算机视觉、自然语言处理和语音识别任务提供自动化的机器学习解决方案。过去挑战赛的完整列表可以在 AutoML 挑战赛的官方网站上找到。
这项挑战旨在为时间序列回归任务提出自动化解决方案。AutoSeries 仅限于多元回归问题,这些问题来自不同的时间序列领域,包括空气质量、销售、工作场所、城市交通等。挑战中的每个数据集都是表格数据,其特征主要有三种类型:Id(可能有多个特征,也可能没有)、时间戳(每个数据集只有一个时间戳)、其他特征(数字或分类)以及预测目标。Id 特征的组合识别一个变量(一个时间序列)。
给定数据集的示例。正如你所看到的,数据是混乱的,但是有一些时序模式
参与者要提交代码,代码将在 Docker 容器中运行(CPU: 4 核,16 Gb RAM,无 GPU)。首先,该模型是在完整数据上训练的,但是在推理过程中,它可以被更新或重新训练。公共排行榜是在五个数据集上计算的,私人——没有人为干预的五个新数据集。私有数据集的结果决定了最终的排名。
最终解决方案概述
最终解决方案的一般步骤
这一部分专门讨论最终解决方案的主要部分。它的代码公布在这里:
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/DenisVorotyntsev/AutoSeries)
特征工程
该解决方案由几个步骤组成。首先,为时序任务生成公共特征。这些特征的数量和类型是管道的超参数,应该针对每个任务分别进行优化,但是由于缺乏计算时间,我决定为所有任务生成相同的特征,并在特征选择阶段删除无用的特征。
第一批特征是基于最关键的数字特征的特征。数字特征对的数字运算(加、减、乘、除)总是提高基于树的模型的得分,因为新特征可能揭示数据中的一些隐藏关系。
让我们以预测公寓的价格为例。关于公寓楼层( ap_floor )和建筑物中楼层总数( total_floors )的已知信息可以通过添加新特征来丰富,该新特征显示公寓楼层在建筑物中的相对位置:
*rel_floor* = *ap_floor / total_floors*
此功能可能有助于模型理解排屋中的第三层( rel_floor 更接近 1)与摩天大楼中的第三层( rel_floor 更接近 0)不同。
然而,如果我们执行所有可能对的数值运算,这种特征工程策略有两个重大问题:过拟合,这在时序任务中尤其重要,以及存储器问题(使用了 16 RAM docker)。为了减少负面影响,选择一小部分特征用于配对。这是通过将整个数据集拟合到浅层 LigtGBM 模型(10 棵树)来完成的。所有使用的特征按照“增益”重要性排序,即使用该特征的分裂的增益的总和。然后 top-n 最重要的数字特征被选择成对。
下一批特征基于数据的时间序列性质:以前的值和差异。我计算目标的滞后值、最重要的数字和分类特征、目标的最后值(滞后= 1)和目标的滞后值(滞后> 1)之间的差异。这些新特性是最重要的特性之一。
最后一批是时间序列特征:年、月、星期几、一年中的某一天和小时。我可以添加更多基于时间的特性,比如一天中的一分钟,一年中的四分之一,等等,但是我决定不这样做,所以我的解决方案是通用的。将这些新特征分类有时会提高分数,但在其他情况下,会显著降低分数。我在推理过程中没有足够的计算时间来优化这个超参数(即,作为数值或分类处理),所以它们都被作为数值处理。
验证和基线模型
在生成新特征之后,基线模型被训练。基线模型使用所有初始和创建的特征。它使用 CatBoost 编码器对类别进行编码,并按原样使用目标。该模型分两步训练:
- 首先,数据被分成训练和验证部分。通常,您希望您的培训/验证/测试分割能够模拟“生产设置”中模型的使用。在时间序列的情况下,这意味着模型不会频繁更新,您在验证部分采用 20–30%的数据(或使用相同比例的滚动窗口)。在这个竞赛中,模型的频繁更新是可能的,因此,验证部分应该更小:验证部分是全部训练数据的 10%。它用于早期停止,即优化 boosting 集成中的树的数量。在这一步之后,模型可以开始进行预测,接下来的所有步骤都是可选的(对于高分来说是至关重要的)。
- 使用最佳数量的树在全部数据上重新调整模型。
我使用 solo LigthGBM 模型进行预测。我测试了 CatBoost(没有 GPU 太慢)和 LinearModels(不够准确)。我还用不同的种子测试了打包和训练,以减少预测的方差,但这些方法花费了大量时间,并且没有将分数提高到足以包含在最终解决方案中。
超参数优化
超参数优化的步骤
我在超参数优化的推理过程中时间太少,所以我决定将所有可能的超参数组合缩小到最有希望的组合,即:
- 处理分类变量:将分类特征视为 pandas 类别类型,将难题留给 LightGBM,或者用 CatBoost 编码对每个类别进行编码(如果您还没有阅读,请查看我以前关于编码类别的文章)。
- 目标预处理:按原样使用目标或者通过微分计算一个新的目标进行回归:new _ target(t)= target(t)-target(t-1)。差分有助于克服时间序列数据的非平稳性。我还测试了 power transformation(对 target 和 Box-Cox 求根)来减少平稳性,但它没有将分数提高到足以包含在最终解决方案中。
通过选择最佳类别编码器来增加 ML 模型的分数
towardsdatascience.com](/benchmarking-categorical-encoders-9c322bd77ee8)
首先对每组参数进行验证,如果新的验证分数更高,则对模型进行改装。在选择了最佳的管线超参数集之后,模型开始特征选择:使用前 5、10、20 等来重新调整模型。最重要特性的百分比(“获得”重要性)。如果分数有所提高——一组新的特征被用于最后的可选步骤——优化超参数(随机网格)。
更新
更新很简单:用完整的数据(训练数据加上新的训练数据)改装最优模型。然而,频繁更新对高分至关重要。
结果
我在这个项目上投入了大量的精力,奋斗得到了回报。我在公共排行榜上获得第三名,在私人排行榜上获得第一名。
比赛的最终私人排行榜(已更新)
经验教训
在比赛期间,我面临了很多 bug,这些 bug 耗费了我的时间和提交材料。bug 是不可避免的,但是有注释,如果一开始就用的话对我帮助很大:
- 记录尽可能多的有用信息:数据框中的列(训练和测试数据中的列顺序可能不同)、数据类型(训练和测试数据框中的数据类型可能不同)、每次训练的时间、训练的剩余时间等。这将有助于理解为什么提交失败或得分低。例如,由于一个愚蠢的错误,我提交的一些模型没有更新,我没有注意到这一点。因此,我的分数远低于应有的水平。一条简单的消息*打印出来(“型号更新!”)*化险为夷,帮我找到了 bug。
- 在 AutoML 中,对未知数据的测试是必不可少的。您可能很容易使您的解决方案过度适应公共部分,并且它可能会在看不见的数据上崩溃。这就是我的情况——我提交的第一个任务失败了。尽量在比赛开始的时候收集更多的数据。新的数据集应该是多样化的,例如,在类别和其他因素中缺少值或字符串,这可能会使您的代码崩溃。用不同的时间预算来测试它们:当你时间紧迫时,试着输出甚至很差的模型。
- 以“即插即用”的方式组织代码:管道的每个部分都不应该依赖于其他部分。例如,我想拟合线性回归而不是 LightGBM,这样做容易吗?如果你的代码是组织良好的,它将是。在这次比赛中,我朝着更干净、更有条理的代码迈出了一大步。然而,有时我认为它仍然是垃圾,我看到了进步。
- 不要在熊猫身上使用代替操作,因为有问题。只要有可能,就不要使用它。
感谢
我要感谢汽车系列赛的组织者——4 个 Paradigm 和 ChaLearn 团队。他们做得很好:收集了数据,准备了提交评分引擎,编写了一个强大的基线解决方案,并回答了论坛和电子邮件中出现的问题。谢谢你的工作!
AutoML + Pentaho + Grafana 用于快速解决方案原型制作
TPOT 机器学习实验。
克里斯托弗·伯恩斯在 Unsplash 上拍摄的照片
在构建机器学习解决方案时,数据科学家通常会凭直觉选择适当的特征、建模技术和超参数来解决手头的问题。在实践中,这涉及到利用经验(和代码!)从以前的项目中,结合来自主题专家的领域知识,以及许多(许多、许多、许多、许多…!?!)迭代开发周期。
无论实验阶段是有趣的、极其乏味的还是介于两者之间的,有一点是肯定的;这个开发过程并不适合快速解决方案原型,尤其是对于新的或者不熟悉的问题领域。
在本帖中,我们将介绍使用自动化机器学习(AutoML)和 Pentaho(我们的数据集成平台选择)和 Grafana(可视化)快速设计、构建和评估大量建模方法,以预测重型斯堪尼亚卡车中的气压系统(APS)故障(2016 年工业挑战在第 15 届智能数据分析国际研讨会上举行)。我们想看看这种方法是否能够:
(1)加快充分执行模型的时间。
(2)帮助我们探索替代的建模/数据准备方法。
(3)为我们未来的项目提供一个可重复的、快速的开发模板。
数据集
我们决定在 UCI 机器学习库上使用 Scania CV AB 发布的数据集。它分为训练集和测试集,都有 171 个属性。由于专有原因,属性名称被匿名,但每个字段都对应于卡车上的传感器。训练集总共有 60,000 个样本,其中 59,000 个属于负面类别,1000 个属于正面类别。为了处理数据集中的许多缺失值,我们使用了中位数插补技术。数据集是高度不平衡的,为了对负类进行欠采样,我们使用了随机欠采样和压缩最近邻规则欠采样的组合,以便创建平衡的数据集。至于评分,我们使用了与本文中相同的成本指示值。在这种情况下,每个假阳性将花费 10 美元(不必要的检查),假阴性花费 500 美元进行相关的修复。基于这些价值,我们将计算总成本。
我们的 AutoML 工具包
AutoML 库旨在使特征工程和模型选择的过程自动化。我们决定使用 Python TPOT(基于树的流水线优化工具)库,该库使用进化算法来评估多种机器学习技术、特征工程步骤和超参数。换句话说,TPOT 尝试了一种特定的机器学习管道,评估其性能,并随机改变管道的部分内容,以寻求更好的整体预测能力。
除此之外,我们使用 Pentaho 为未来项目构建可重用的 AutoML 模板,管理实时模型目录和管理数据准备。 Grafana 用于显示搜索过程中各种管道/算法组合的性能。
入门
在 Pentaho 中,我们导入了 Scania APS 数据,采样以重新平衡类,并将所需的 Python 代码嵌入到数据流中以利用 TPOT 函数。
图 Pentaho 中的数据清理和欠采样
我们当前的任务是分类任务(APS 系统故障/无故障),所以我们将使用 TPOT 分类器。TPOT 的用法和语法类似于任何其他 sklearn 分类器。分类器参数的完整列表可在这里找到。出于开发目的,我们使用了:
世代:运行流水线优化过程的迭代次数。
population_size :每一代在遗传编程群体中保留的个体数量。
mutation_rate: 告诉进化算法每一代应用随机变化的管道数量。
**评分:**功能用于针对分类问题评估给定管道的质量。我们使用“召回”作为开始,因为由于较大的相关成本,最初优化识别所有真正的 APS 故障是有意义的,而不是最小化不必要的呼叫。
**periodic _ check point _ folder:**如果提供,这是一个文件夹,TPOT 将在优化时定期保存帕累托前沿的管道。我们希望在搜索过程中实时记录性能最佳的管道,以感受性能最佳的算法,并记录下来供以后比较。
**详细程度:**TPOT 在运行时传递了多少信息。随着搜索的进行,我们希望看到一切。
#example TPOT codeimport pandas as pd
import numpy as np
import pickle
import timefrom tpot import TPOTClassifier
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn.externals import joblib#scaling training data and saving scalermin_max_scaler = preprocessing.MinMaxScaler()x_scaled = min_max_scaler.fit_transform(x)scaler_name=’/home/demouser/Desktop/Aldrin/scalers/scaler’+str(int(time.time()))+’.save’joblib.dump(min_max_scaler, scaler_name)X=np.asarray(x_scaled)#splitting train and CV setsX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=None)#Training TPOT classifiertpot = TPOTClassifier(generations=50, verbosity=3,population_size=100, periodic_checkpoint_folder=path_to_folder, scoring=’roc_auc’ , mutation_rate=0.9)tpot.fit(X_train, y_train)output_score=str(tpot.score(X_test, y_test))tpot.export(path_to_pipeline)pickle.dump(tpot.fitted_pipeline_, open(file_name, ‘wb’))
构建并可视化模型目录
我们还运行了一个 Pentaho 作业来收集 TPOT 生成的 ML 管道,并创建一个实时模型目录(图 2 & 3)。
图 2: Pentaho 收集 TPOT 管道并将结果传输到 Grafana 的工作。
图 3:用于数据摄取、争论和执行 TPOT 模型搜索算法的 Pentaho 转换。
我们在 Grafana(图 4)中可视化搜索性能最佳的管道,这使我们能够调整初始 TPOT 搜索参数,以获得运行时间与精度的正确平衡。
图 Grafana AutoML 仪表板的初始示例,用于跟踪 TPOT 搜索进度,包括一段时间内表现最佳的模型管道和召回分数。
快速成型?
我们的测试集由 16k 个样本组成,其中 375 个是 APS 系统中的类阳性故障。具体来说,对于斯堪尼亚来说,这些失败的成本是 375 * 500 美元= 187,500 美元。
我们能够在第一次通过时获得相当好的结果:在不到 30 分钟的时间内,使用我们的训练数据集,在测试集的肯定类上获得了 82%的召回率和 78%的准确率。然而,总的来说,成本相当高——33,400 美元。跑了 30 分钟后,TPOT 建议使用基于 XGBoost 的模型。你需要运行 TPOT 多长时间才能让它正常工作,这取决于数据的大小、维度、精度要求以及你必须投入的计算能力。通常用户运行 TPOT 算法几个小时甚至几天来得到最好的管道。我们的目标是获得总成本
模型可解释性
接下来,我们想了解 170 个特征(在这种情况下是传感器馈电)中的每一个对我们的 APS 故障预测有多大贡献。这将有助于我们了解哪些传感器反馈是重要的(鉴于我们缺乏斯堪尼亚重型卡车的专业知识!),以及那些积极阻碍我们成功的因素。使用SHAP(SHapley Additive exPlanations)库并将所需的 Python 代码嵌入到我们的 Pentaho 数据流中,我们能够从 170 个特征中识别出 30 个最重要的特征,并减少模型训练中使用的数量。
探索不同的建模方法
Grafana 中的 AutoML 仪表板允许我们看到哪些建模方法对我们的用例表现良好(图 4 中的示例视图)。除此之外,SHAP 值使我们能够探索哪些特征对模型预测最重要,每个特征的分布对正确分类的概率的贡献,以及不同特征之间的依赖关系(图 5)。
图 5:在 Grafana 中可视化 SHAP 值,探索哪些特征对模型预测最重要,以及不同特征之间的依赖关系。
初步结果
在运行了 8 个小时的优化数据流后,TPOT 提出了一个随机森林模型,这与之前的工作【1】是一致的,随机森林也产生了最好的结果。就平衡假阳性和假阴性而言,我们确定 0.2 的阈值是最有希望的。我们的阳性类别概率阈值为 0.2 的最终模型识别出 357 个真阳性、639 个假阳性、14986 个真阴性、18 个假阴性或 95.2%的召回率和 35.8%的精确度。这相当于不必要的维护呼叫的总成本为 6390 美元,错过的 APS 故障的总成本为 9000 美元,与最初挑战期间先前工作和中报告的成本相当。总成本为 15390 美元,比最初运行时提高了两倍多。
进一步改进
我们能够显著提高模型性能,但它仍远未达到[1] 中所示的最佳模型性能。我们决定用超参数调谐来获得 TPOT 输出的最佳管道。在对随机森林模型(最佳参数 n_estimators=200,max_depth=10)执行超参数网格搜索后,我们能够得到 12320 美元的总成本,其中有 13 个假阴性和 582 个假阳性,38.3%的精确度和 96.5%的召回率。这让我们更接近于车型在【1】和原挑战赛【2】中产生的最佳成本。
总结
TPOT 图书馆与 SHAP 合作,为探索各种模型提供了一个很好的工具集,同时更好地理解了哪些功能正在影响模型的行为。这种方法的优点包括相对容易使用和需要配置的参数最少。另一方面,TPOT 能够找到最佳的模型配置,但无法在 10 小时的运行周期内优化超参数。从我们的角度来看,这突出了两种方法(TPOT 和 SHAP)的计算复杂性。人们需要等待相当长的时间(例如 10 个小时)才能得到结果,但正如 TPOT 的创造者所说,AutoML 算法并不意味着运行半个小时。总之,考虑到我们对数据集的不熟悉,我们认为 AutoML 方法减少了我们的实验时间或“获得合适的原型解决方案的时间”。当使用熟悉的数据源时,在减少开发时间方面可能没有什么好处,但是 TPOT 可以以辅助方式用于寻找替代的建模方法,或证明当前使用的建模技术。
参考文献
[1]Mr unal sawant 在 https://link.medium.com/zrKQJkThv6 T2 @ the startup _ 的斯堪尼亚卡车上的 APS 故障
[2]费雷拉·科斯塔,卡蜜拉和纳西门托,马里奥。(2016).IDA 2016 工业挑战:使用机器学习预测故障。381–386.10.1007/978–3–319–46349–0_33.【https://archive.ics.uci.edu/ml/datasets/IDA2016Challenge
自动归零
我们花了 60 年才发现一个可以自我发现的东西。
我们人类设计模型,模型有参数。可以把参数想象成稍微向左或向右旋转的旋钮,改变模型的行为。近年来,神经网络在各种各样的任务上表现出显著的成功,并且已经看到了巨大的普及增长。考虑到技能、计算资源和 ML 研究的难度等因素,它催生了一个名为 AutoML 的新领域,,旨在用机器计算的时间代替人类的研究时间。
什么导致了自动归零?
AutoML 研究已经通过使用人类专家预先描述的构建块来限制搜索空间(算法可以从中提取操作的项目池),如ReLU 层、卷积层、批处理规范化层,这往往会使搜索结果偏向于人类设计的算法。一个常见的例子是神经结构搜索,它使用复杂的人为设计的层作为构建块,并遵循反向传播的规则来搜索新的结构和最佳超参数。
AutoML 的其他变体通过预定义某些他们认为至关重要的超参数来限制他们的搜索空间,但该算法无法像反向传播期间的学习速率那样实现它。一些研究建议使用固定的预处理管道将处理后的输入馈送到算法,如图像情况下的数据扩充。因此,许多这些方面仍然是手工设计的。这些方法可能会节省计算时间,但可能会降低 AutoML 的创新潜力。
AutoML-Zero 背后的概念很简单,为什么我们不假设我们没有花哨的运算(像反向传播或梯度下降)并让算法通过使用基本的数学运算从零开始设计一切,这就是为什么它被称为机器学习从零开始。 把它想象成没有 TensorFlow,没有 PyTorch,只是用 NumPy 来进化机器学习的概念。令人惊讶的是,它可以发现非线性模型、学习率、梯度等概念。所以基本上在你眼前持续了 30 年的神经网络进化。
高级工作概述
AutoML-Zero 框架背后的想法是,它们初始化大量的程序,每个程序包括三个在启动时为空的函数。这三个功能是
- setup() - >该函数用于初始化变量。
- predict() - >该函数用于对给定的数据点进行预测。
- learn() - >此函数用于更新变量,以便预测函数随着时间的推移执行得更好。
给定这三个函数,AutoML-Zero 必须在这些通用函数中填充程序的其余部分。
来源:https://github . com/Google-research/Google-research/tree/master/automl _ zero
以上是 AutoML-Zero 发现的一个线性回归问题的算法片段。如您所见,设置函数初始化了一个名为“s2”的变量,该变量后来被用作学习函数中的学习速率,预测函数通过应用输入特征和学习权重“v1”之间的点积进行预测,学习函数首先计算实际标注和预测标注之间的误差,应用学习速率,计算梯度并更新权重。让我们看另一个片段
以上是自动发现的 CIFAR-10 分类算法的片段。设置函数初始化学习速率,预测函数将噪声引入特征(它发现引入噪声可以提高其预测精度),学习函数是计算误差、估计梯度、归一化梯度、归一化误差等等。
记住,程序开始时是空函数。事实上,这些程序可以学习像点积、梯度和归一化这样的东西,这是令人惊讶的,因为它必须搜索这个巨大的搜索空间,这个空间非常稀疏,而你在这种空间中发现的大多数程序都是完全无用的。
内部工作
在这一部分,我们将回答两个问题。如前所述,AutoML-Zero 框架初始化了大量的程序。为什么?(请记住,每个程序都包含这三个功能——设置、预测和学习)第二个问题是,它如何准确地填写功能中的指令?。
AutoML-Zero 设置使得搜索空间非常稀疏,因此,一个好的学习算法,即使是一个琐碎的任务,也可能是十分之一。在这种环境下,随机搜索无法在合理的时间内找到解决方案。为了克服这个问题,通过使用正则化进化搜索在搜索空间中发现这些机器学习程序。
正则化进化搜索
在*正则化进化搜索中,*大量程序被初始化(称为种群),它们的函数为空。然后,算法从总体中选择一个样本(两个或更多),对它们进行评估,并选择表现最好的一个作为父代。然后父母克隆自己创造一个孩子,孩子变异了。这种突变是从三个选项中随机选择的
- 在随机位置随机插入或删除指令。
- 随机替换组件函数中的所有指令
- 修改指令的一个参数,将其替换为随机选项。
跟随动画可能会让你对进化搜索有更深的理解
演进实施加速
机器学习算法的自动零搜索空间是非常稀疏和通用的。这意味着这些程序中的大部分是完全无用的。例如,在第二种类型的变异中,预测函数接受标量“s0 ”,并将其分配给某个矩阵的平均值,该矩阵在设置中根本没有定义,在学习函数中也根本没有学习,然后它将另一个随机标量值“s3”分配为另一个随机标量值“s7”的余弦。所以你可以观察到,这些函数完全没有用,没有做任何有助于将指针移向机器学习算法的事情。
来源:https://github . com/Google-research/Google-research/tree/master/automl _ zero
为了让这种算法发挥作用,他们需要用他们的进化搜索策略评估大量不同的模型。因此,研究人员特别描述了通过 5000–10000 个模型/秒/cpu 核心的搜索。他们这样做的一些方法是通过实现迁移,这是一种在不同的 CPU 之间混合这些不同模型的方法,以确保在这个分布式系统中不同工作人员的多样性。然后是 FEC(功能等价检查),这是一种确保两个程序对于给定的输入特性没有相同输出的方法。还有一些数据集多样性,其中算法必须从多标签分类数据集(如 MNIST ( [0 对 8]或[6 对 9])中执行二元分类任务。一组更加多样化的任务进一步有助于提高这些程序的实用性。然后是渐进式动态跨栏,在那里他们有一个中级健康评估,以截断表现不太好的模型。
算法进化
投射的双星 CIFAR-10 上的一个演化实验的进展。
来源:https://storage . Google APIs . com/gresearch/automl _ zero/progress . gif
结论
这是对 AutoML 新版本的一瞥。在 AutoML-Zero 中,我们还没有达到最先进的水平。但令人兴奋的是,它仅仅从矩阵向量乘法中生成一个程序来进行机器学习,这是非常令人兴奋的。目标是减少搜索空间中的人为偏差。我希望这种方法将发现机器学习概念的新的基本构件。
自回归模型— PixelCNN
深度学习/生成模型
使用深度生成模型创建数字!
编剧沃尔特·雨果·洛佩兹·皮纳亚、佩德罗·f·达·科斯塔和杰西卡·达弗伦
大家好!这是我们关于现代自回归模型系列的第一篇文章。以下是我们将在本系列中涉及的主题:
总结
- 自回归模型— PixelCNN
- 模拟彩色图像
- PixelCNN 的盲点及如何修复——门控 PixelCNN
- 使用门控像素 CNN 的条件生成
- 带裁剪卷积的门控像素 CNN
- 提高性能— PixelCNN++
- 缩短采样时间—快速 PixelCNN++
- 使用注意机制——pixels nail
- 生成多样化的高保真图像——VQ-VAE 2
每个主题的实现都可以在这个库中找到
开始吧!
介绍
生成模型是来自无监督学习的一类重要的模型,在过去的几年中受到了很多关注。这些可以被定义为一类模型,其目标是学习如何生成看起来来自与训练数据相同的数据集的新样本。在训练阶段,生成模型试图解决**密度估计的核心任务。**在密度估计中,我们的模型学习构造一个估计量——p model(x)——尽可能的类似于不可观测的概率密度函数——pdata(x)。值得一提的是,创成式模型应该能够从分布中构造新的样本,而不仅仅是复制和粘贴现有的样本。一旦我们成功地训练了我们的模型,它就可以用于各种各样的应用,从图像修复、着色和超分辨率等重建形式到艺术作品的生成。
有几种不同的方法可以用来进行这种概率密度估计,例如:
- 生成敌对网络(GANs) 使用一种方法,其中模型执行 隐式密度估计 。在这种情况下,我们训练一个模型,它可以从p model(x)创建样本,而无需显式定义p model(x);该模型学习产生数据的随机程序,但不提供观察概率的知识或指定条件对数似然函数;
- 变分自动编码器(VAE) 使用一个 显式密度估计 但是定义了一个难以处理的密度函数,其潜在变量不能被直接优化。所以,为了训练模型,我们改为推导并优化似然的下界( 近似密度);我们通过最大化证据下限(ELBO)来优化数据的对数似然性(更多细节可在此处的和此处的中找到);
- 自回归(AR)模型创建一个 显式密度 模型,该模型易于处理以最大化训练数据的可能性( 易于处理的密度 )。为此,使用这些方法,很容易计算数据观察的可能性,并获得生成模型的评估度量。
正如我们提到的,自回归是一种实用的方法,它提供了似然函数的显式建模。然而,为了对具有多个维度/特征的数据进行建模,自回归模型需要施加一些条件。首先,输入空间 X 需要有一个来决定其特征的 排序。这就是为什么自回归模型通常用于具有内在时间步长序列的时间序列。然而,它们可以用于图像,例如,通过定义左边的像素在右边的像素之前,顶部的像素在底部的像素之前。第二,为了对数据观察中的特征的联合分布进行易处理的建模(p(x),自回归方法将*p(x)*作为条件分布的产物。自回归模型在给定先前特征的值的情况下,对每个特征使用条件来定义联合分布。例如,来自图像的像素具有特定强度值的概率取决于所有先前像素的值;而一幅图像的概率(所有像素的联合分布)就是它所有像素的概率的组合。因此,自回归模型使用链式法则将数据样本 x 的可能性分解为一维分布的乘积(下面的等式)。因式分解将联合建模问题转化为序列问题,在序列问题中,人们学习在给定所有先前生成的像素的情况下预测下一个像素。
这些条件(即确定排序和条件分布的乘积)是自回归模型的主要定义。
现在,大挑战是计算这些条件可能性 p(x ᵢ| x₁,…,x ᵢ ₋ ₁) 。我们如何在一个易于处理和扩展的表达模型中定义这些复杂的分布呢?一种解决方案是使用通用近似器,如深度神经网络。
像素 CNN
DeepMind 在 2016 年推出了 pixel CNN(Oord et al .,2016 ),这个模型开启了自回归生成模型最有前途的家族之一。从那时起,它就被用于生成语音、视频和高分辨率图片。
使用 VQ-VAE-2 生成图像(链接)
PixelCNN 是一个深度神经网络,可以捕捉其参数中像素之间的依赖关系分布。它沿着两个空间维度在图像中一次一个像素地顺序生成。
感兴趣的像素 I(红色)由所有先前的像素(蓝色)定义。PixelCNN 可以沿着深度神经网络使用卷积层对它们的关联进行建模。
使用卷积运算,PixelCNN 可以并行学习图像中所有像素的分布。然而,在确定特定像素的概率时,标准卷积层的感受野违反了自回归模型的顺序预测。在处理一个中心像素的信息时,卷积滤波器考虑其周围的所有像素来计算输出特征图,而不仅仅是前面的像素。然后采用掩模来阻挡来自尚未预测的像素的信息流。
屏蔽卷积层
可以通过将不应考虑的所有像素置零来进行掩蔽。在我们的实现中,创建了一个与卷积滤波器大小相同、值为 1 和 0 的掩码。在进行卷积运算之前,该遮罩与权重张量相乘。在 PixelCNN 中,有两种类型的遮罩:
- 掩码类型 A :该掩码仅适用于第一个卷积层。它通过将遮罩中的中心像素置零来限制对感兴趣像素的访问。这样,我们保证模型不会访问它将要预测的像素(下图中的红色)。
- 屏蔽类型 B :该屏蔽应用于所有后续卷积层,并通过允许从一个像素到其自身的连接来放松屏蔽 A 的限制。为了说明第一层的像素预测,这是很重要的。
掩码 A 仅用于第一卷积层。在所有其他层中使用掩码 B,以允许以感兴趣的像素为中心的卷积运算的信息沿着网络传播。
在这里,我们展示了一个片段,展示了使用 Tensorflow 2.0 框架实现的掩码。
体系结构
在 Oord et al. 2016 中,PixelCNN 使用了以下架构:第一层是带有 7x7 滤波器的掩蔽卷积(A 型)。然后,使用 15 个残差块。每个模块使用掩码类型为 B 的 3×3 卷积层和标准 1×1 卷积层的组合来处理数据。在每个卷积层之间,有一个非线性 ReLU。最后,残余块还包括残余连接。
像素 CNN 的架构。
在块序列之后,网络具有 RELU-CONV-RELU-CONV 层链,使用具有 1x1 滤波器的标准卷积层。然后,输出层是预测像素的所有可能值中的值的 softmax 层。模型的输出具有与输入图像相同的空间格式(因为我们需要每个像素的输出值)乘以可能值的数量(例如,256 个强度级别)。
在这里,我们展示了使用 Tensorflow 2.0 框架实现网络架构的一个片段。
预处理
像素 CNN 的输入值被缩放到[0,1]的范围内。在这个预处理过程中,有可能以较低数量的强度等级量化像素值。在我们的实现中,我们首先呈现用两个强度级别训练的模型,然后用所有 256 个级别。我们注意到,由于问题复杂性较低(在像素的概率分布中要考虑的可能值较少),该模型在具有较少级别的数据中表现更好。
目标数据对应于指示像素强度的分类(整数)值。
模型评估
PixelCNN 有一个简单的训练方法。该模型通过最大化训练数据的可能性来学习其参数。
由于大多数优化问题被定义为最小化问题,一个常用的技巧是将训练目标转化为最小化负对数似然 (NLL)。
由于 p(xᵢ|θ) 对应于 softmax 层输出的概率,NLL 等价于交叉熵损失函数——监督学习中常用的损失函数。此外,NLL 是一种用于比较生成方法之间性能的指标(使用 nats 单位或每像素位数)。
推论
由于 PixelCNN 是一个自回归模型,推理恰好是顺序的——我们必须逐个像素地生成。首先,我们通过向模型传递零来生成图像。它不应该影响第一个像素,因为它的值被建模为独立于所有其他像素。因此,我们执行向前传递并获得它的分布。给定分布,我们从多项式概率分布中抽取一个值。然后,我们用采样的像素值更新我们的图像,并且我们重复这个过程,直到我们产生所有的像素值。这里使用 PixelCNN 使用 MNIST 数据集在 150 个时期后生成样本。每张生成的图像都有四级像素强度。
相同的采样过程可以用于部分遮挡的图像作为起点。
现在,我们还尝试训练或建模以产生具有 256 个像素强度级别的图像。
生成了 256 个强度级别的数字。
部分遮挡的图像。
与其他生成模型(VAE 和甘斯)相比,这种采样过程相对较慢,在其他模型中,所有像素都是一次性生成的。然而,最近的进展已经使用缓存值来减少采样时间(快速 PixelCNN++,在接下来的帖子中解决)
结论
PixelCNN 模型的优点是联合概率学习技术是易处理的,并且可以使用梯度下降来学习。没有近似值;我们只是试图在给定所有先前像素值的情况下预测每个像素值。由于 PixelCNN 是通过最小化负对数似然来训练的,因此与替代方法(例如 GANs 需要找到纳什均衡)相比,它的训练更加稳定。然而,由于样本的生成是连续的(逐个像素),原始的 PixelCNN 在可扩展性方面存在问题。在下一篇文章中,我们将在具有 RGB 通道的数据集中训练 PixelCNN 模型。
参考
- http://sergeiturukin.com/2017/02/22/pixelcnn.html
- https://towards data science . com/auto-regressive-generative-models-pixel rnn-pixel CNN-32d 192911173
- 【https://deepgenerativemodels.github.io/
- https://eigenfoo.xyz/deep-autoregressive-models/
- https://wiki.math.uwaterloo.ca/statwiki/index.php?title = stat 946 f17/Conditional _ Image _ Generation _ with _ pixel CNN _ Decoders
- https://www . code project . com/Articles/5061271/pixel CNN-in-auto regressive-Models
- https://towards data science . com/blind-spot-problem-in-pixel CNN-8c 71592 a 14 a
- https://www.youtube.com/watch?v=5WoItGTWV54&t = 1165s
- https://www.youtube.com/watch?v=R8fx2b8Asg0
- https://arxiv.org/pdf/1804.00779v1.pdf
- https://blog.evjang.com/2019/07/likelihood-model-tips.html
- https://arxiv.org/abs/1810.01392
- http://bjlkeng.github.io/posts/pixelcnn/
- https://jrbtaylor.github.io/conditional-pixelcnn/
- http://www.gatsby.ucl.ac.uk/~balaji/Understanding-GANs.pdf
- https://www.cs.ubc.ca/~lsigal/532S_2018W2/Lecture13b.pdf
- https://tinyclouds.org/residency/
- https://tensor flow . blog/2016/11/29/pixel CNN-1601-06759-summary/
- https://web . cs . hacettepe . edu . tr/~ ay Kut/classes/spring 2018/CMP 784/slides/le C10-deep _ generative _ models-part-I _ 2 . pdf
AutoVIML:自动化机器学习
为任何给定的数据集自动选择最佳的机器学习模型
法托斯 Bytyqi 在 Unsplash 上的照片
机器学习提供了学习算法的优势,该算法随着经验自动改进。有“n”种机器学习算法和技术,通常,我们需要测试其中的大多数,以便为我们的数据集找到具有最高准确性的最佳预测模型。
大多数机器学习方法,如回归技术、分类技术和其他模型都是在 Sklearn 中定义的,但为了选择哪种技术最适合我们的问题陈述或数据集,我们需要尝试所有这些模型以及超参数调整,并找出性能最佳的模型。这需要花费大量的时间和精力,使用名为 AutoVIML 的 python 包可以减少这些时间和精力。
AutoVIML 是一个开源的 python 包,使机器学习变得容易。它所做的是,通过不同的机器学习模型呈现你的数据,并为给定的数据集找出精确度最高的最佳模型。无需对数据集进行预处理即可将其传递给 AutoVIML。它会自动清理您的数据,帮助您对变量进行分类,执行特征约简,可以在单个模型中处理不同类型变量的数据,如文本、数字、日期等。
在本文中,我们将了解如何使用 AutoVIML 来减少创建机器学习模型的时间和精力。我们将看到我们在 AutoVIML 中使用的不同参数,以及它们对我们的预测有什么变化。
安装 AutoVIML
像任何其他 python 库一样,我们将使用 pip 来安装 autoviml。
pip install autoviml
导入 AutoVIML
from autoviml.Auto_ViML import Auto_ViML
加载数据集
为了探索 AutoVIML,您可以使用任何数据集,这里我将使用一个与心脏病相关的数据集,您可以从 Kaggle 下载。这个数据集包含不同的属性和目标变量。
import pandas as pd
df = pd.read_csv('heart_d.csv')
df
使用的数据集(来源:作者)
现在让我们了解一下如何使用 autoviml 来使用这个数据集制作预测模型,以及 AutoVIML 中有哪些参数。
#Basic Example with all parameters
model, features, trainm, testm = Auto_ViML(
train,
target,
test,
sample_submission,
hyper_param="GS",
feature_reduction=True,
scoring_parameter="weighted-f1",
KMeans_Featurizer=False,
Boosting_Flag=False,
Binning_Flag=False,
Add_Poly=False,
Stacking_Flag=False,
Imbalanced_Flag=False,
verbose=0,
)
在上面的代码中,我们可以清楚地看到如何使用 AutoVIML 创建模型,以及我们可以使用哪些参数。现在让我们详细讨论这些参数是什么。
- train:它应该包含数据集的位置,或者如果您已经将数据集加载到数据帧中,则应该包含数据帧的名称。在本文中,我们将它加载到名为“df”的数据帧中,因此我们将它设置为“df”。
- target:它包含目标变量的名称。在我们的例子中,目标变量名是“TenYearCHD”。
- test:它包含测试数据集。如果我们没有任何测试数据集,我们也可以像这样将其留空,以便将训练数据集拆分为训练和测试。
- sample_submission:我们将把它留空,这样它将在我们的本地目录中自动创建提交。
- hyper_param:我们将随机搜索 cv,因为它比网格搜索 CV 快 3 倍。我们需要将此设置为“RS”。
- feature_reduction:我们将把它设置为 true,这样它将考虑到模型创建中最重要的预测变量。
- scoring_parameter:您可以给出自己的评分参数,否则它将根据模型假设合适的参数。我们将在这里使用“加权 f1”。
- KMeans_featurizer:这对于线性分类器应该为真,对于 XGboost 或随机分类器应该为假,因为它会导致过度拟合。
- boosting_flag:用于升压。这里我们将保持它为假。
- 宁滨 _ 标志:默认情况下,它是假的,当我们想把顶部的数字变量转换成装箱的变量时,它可以被设置为真。
- add_poly:我们将它设置为 false。
- stacking_flag:默认为 False。如果设置为 True,将添加从另一个模型的预测中派生的附加要素。我们将保持它为假。
- Imbalanced _ flag:如果设置为 TRUE,它将检查数据不平衡,并将使用 SMOTING 技术消除数据不平衡。
- Verbose:通常用于打印所执行的步骤。我们将它设置为 3。
现在让我们将所有这些参数用于我们的数据集,并使用 AutoVIML 创建具有最高精度的最佳性能模型。
model, features, trainm, testm = Auto_ViML(
train=df,
target="TenYearCHD",
test="",
sample_submission="",
hyper_param="RS",
feature_reduction=True,
scoring_parameter="weighted-f1",
KMeans_Featurizer=False,
Boosting_Flag=True,
Binning_Flag=False,
Add_Poly=False,
Stacking_Flag=True,
Imbalanced_Flag=True,
verbose=3
)
让我们分析一下我们得到的输出。
- 数据分析部分
数据分析(来源:作者)
2.数据清理和特征选择
数据清理(来源:作者)
3.数据平衡和模型创建
数据平衡(来源:作者)
4.分类报告和混淆矩阵
困惑矩阵(来源:作者)
5.模型可视化
模型可视化(来源:作者)
6.特征重要性和预测概率
来源:作者
在上面的集合中,我们看到了 AutoVIML 如何处理数据,清理数据,平衡结果变量,以及创建最佳模型和可视化以获得更好的理解。
同样,您可以使用不同的数据集探索 AutoVIML,并在对本文的回复中分享您的经验。AutoVIML 是一种根据数据集创建最佳性能机器学习模型的简单方法。
在你走之前
感谢 的阅读!如果你想与我取得联系,请随时通过 hmix13@gmail.com 联系我或我的 LinkedIn 个人资料 。可以查看我的Github简介针对不同的数据科学项目和包教程。还有,随意探索 我的简介 ,阅读我写过的与数据科学相关的不同文章。
如何测量分布式系统中的可用性
可用性是分布式系统的一个关键特征。
图片作者作者
可用性是分布式系统的一个重要方面。在当今时代,大多数系统都需要保证可用性。我们可以说,可用性是一个系统在一个特定的时期内保持功能以执行其所需任务的时间。
根据维基百科,可用性通常被定义为正常运行时间除以总时间(正常运行时间加上停机时间)
我们有时会互换使用可靠性和可用性这两个术语,但它们并不相同。如果我们考虑可能发生的所有可能的真实世界情况,可靠性是随着时间推移的可用性。如果一个系统是可靠的,你可以说它是可用的。但是,如果有,也不一定可靠。
★为什么可用性至关重要?
假设我们正在推出一个教程网站。我们必须确保教程、编码和阅读材料的视频的可用性。每当客户访问教程或学习材料的网站时,他们都希望该系统能够完全运行和可用。该系统可能会失去客户,也很难获得新的客户。一个破碎的系统会给你带来不好的名声。
如果系统经常不可用,用户会不满意。他们甚至可能转向提供相同服务的其他竞争对手的系统。因此,对于系统设计师来说,确保可用性非常重要。
现在,这些 web 服务如果不可用,可能会对其宣传、财务安全等造成危害。但这不会是世界末日。没有这样的系统不会有时变得不可用。
让我们以支持一个飞机软件为例。帮助飞机在空中正常运行的软件。现在,这种系统变得不可用甚至几分钟都是不可接受的。因此,一架可以飞行许多小时的飞机可以说具有极高的可用性。如你所见,这可能会影响到生死存亡。
但是我们不需要在我们的想象中走那么远来寻找高可用性场景的生死状况。
即使是 youtube 这样的平台,试想一下,如果 youtube 一旦宕机,会对多少用户造成多大的影响。每天有数亿人使用 youtube,他们中的许多人也依靠 youtube 谋生。AWS 或谷歌云平台等云提供商也是如此。你能想象有多少服务会因此被封锁吗?你现在可能无法阅读这篇文章!!是…那种不好的效果。
此类云提供商的一次宕机可能会产生巨大而深远的影响。所有这些例子都告诉我们,可用性对于系统设计非常重要。
★如何衡量可用性?
好了,我们明白了,可用性是必不可少的,但是我们如何衡量可用性呢?它可以计算为系统或服务在正常条件下保持运行的时间百分比。
假设我们根据一年中系统正常运行时间的百分比来衡量系统的可用性。因此,如果一个系统一年中有六个月处于运行状态,它将有 50%的可用性。现在,想象一下,如果脸书或优步一年下跌 50%!!!那真的很糟糕;这是不可接受的。没人会用它们,对吧?
在可用性方面,我们需要处理非常高的百分比。老实说,即使 90%的可用性也不够好。按照这个速度,脸书每天会停机 2.5 小时。一年有 35 或 36 天。那你会用它吗?如果发生这种情况,我怀疑扎克伯格是否会使用它。只有 90%的可用性,任何产品都不可能在今天的市场上生存。
★可用性中的 9 是什么
如果一个系统的可用性为 99%,那么它就被称为“两个九”可用性,因为数字“九”会出现两次。即使是 99%可用的系统,一年也有将近四天的停机时间,这对于脸书、谷歌这样的服务来说是不可接受的。
可用性的百分比有时用数字中的“9”的数量“T1”或“9 的类别”来表示。
照片由🇨🇭·克劳迪奥·施瓦茨| @purzlbaum 在 Unsplash 上拍摄
对于 99.9%的可用性称为“三个九”,99.99%的可用性称为“四个九”。“五个九”的可用性(99.999%)给出了一年中 6 分钟的停机时间,可以说这是高可用性的黄金标准。
高可用性(HA)是系统的一个特征,旨在确保一个约定级别的操作性能,通常是正常运行时间,比正常时间长。
高可用性伴随着更高的延迟或更低的吞吐量等代价。当您是系统设计人员时,您的工作就是考虑这些权衡,并决定您需要多高的可用系统。也许您的系统的一部分需要高度可用,而不是整个系统。
比如说,我们以 Medium 为例;它有系统的许多部分。我们需要在配置文件中有 stat 页面的高可用性吗?不完全是。另一方面,文章写作、阅读、主页加载部分需要高可用。如果您在一段时间内看不到统计页面,比如说 5-10 分钟,这有关系吗?我不这么认为。因此,系统的这一部分可能不太可用(当然,不是 50%的可用性)。
★高可用性的解决方案是什么?
现在,我们需要知道如何提高系统的可用性。第一个简单的解决方案是您的系统不应该有单点故障。因此,如果系统中的某个组件出现故障,整个系统都会崩溃。
图:服务器的单点故障(图片由作者提供)
**冗余是单点故障的解决方案。**冗余是复制或倍增系统组件的行为。
现在让我们假设一个系统有一个服务器来处理客户端的请求。这是一个单点故障。
因此,我们需要添加更多的服务器来处理请求。但是我们需要一个负载平衡器来平衡服务器之间的负载。现在,如果负载平衡器失效,系统将不可用。
图:添加更多的服务器以实现冗余,但是负载平衡器现在是单点故障(图片由作者提供)
因此,我们需要多个负载平衡器来消除系统的单点故障。现在,如果其中一个服务器出现故障,其他服务器可以处理客户端请求。如果一个负载平衡器关闭,其他负载平衡器可以接收请求并将其发送到服务器。
图:负载平衡器和服务器消除单点故障的冗余(图片由作者提供)
结论:
可用性是分布式系统的一个关键属性。如果您想使系统可用,您需要消除系统中的任何单点故障。你可以通过使系统的这一部分冗余来做到这一点。此外,您需要在系统中有一个处理系统故障的流程。在系统出现故障的情况下,可能需要人工干预来恢复系统;然后,您需要在系统中建立流程,确保人们在一定时间内收到系统故障的通知。
可用的超参数优化技术
我们在分类模型集上应用三种不同的超参数优化技术来比较它们的准确性。
背景
我经常收到关于自动搜索超参数优化的文章。一旦我理解了这些技术的意图和范围,我就想知道通过这种优化一个模型可以改进多少。
本文的目的是调查不同的可用优化技术,并在一个简单的例子上测试它们,比较它们并查看所获得的改进的概述。
超参数是模型可调参数,必须对其进行调整以获得具有最佳性能的模型。然后,优化模型的超参数是提高所选算法性能的关键任务。
在某种程度上,我们需要知道每个超参数在每个算法中的含义及其可能的值。深入理解不同算法中每个超参数的含义是必要的,也是一项艰巨的任务,有时意味着了解算法内部的工作方式及其背后的数学原理。这篇文章的内容没有达到那个深度,虽然我们会在每一个里面选取一些超参数,用不同的算法来分析。
使用过任何算法的人可能已经对缺省值集进行了一些手动优化尝试。这种手动调整通常需要很长时间,并不总是严格地进行,并且很难将结果系统化
第二,我们可以应用可用的自动化和相当简单的技术,例如网格搜索和随机搜索,它们通常给出更好的结果,但是时间和机器计算的成本很高。我们将应用这两种技术来比较它们的结果
最后,我们将应用贝叶斯优化,这是一种找到函数最小值的方法,在测试的最佳算法上使用 Python 的 hyperopt 库。这种技术的实现可能不那么容易,但它可以在性能或时间上给我们比以前更好的结果。
数据集
我们将在练习中使用的数据集是 Kaggle 的泰坦尼克号乘客数据集,这是一个二元分类练习,用于预测哪些乘客幸存,哪些乘客没有。
import os
import numpy as np # linear algebra
import pandas as pd #
from datetime import datetime
from sklearn.model_selection import train_test_split
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import RidgeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
import lightgbm as lgb
from sklearn.metrics import confusion_matrix
import scikitplot as skplt%matplotlib inlinenp.random.seed(7)
train = pd.read_csv('./data/train.csv', index_col=0)
y = train.Survived #.reset_index(drop=True)
features = train.drop(['Survived'], axis=1)
features.head()
选择的指标是准确性:正确预测的乘客百分比。
准确率= (TP+TN) /(合计)
特征工程和结果数据框架
我们将应用数据工程的基本技术,这将使我们能够无误地使用算法(记住,本文的目的不是获得好的结果,而只是比较应用优化技术时的性能)。
我们选择了八种算法来完成这项工作;这个决定是基于重用杰森·布朗利和 T2·威尔·科尔森的部分工作,他们开发了这里使用的大部分代码。
这些模型中的每一个都将是我们结果表中的不同列:
- 随机梯度推进
2.脊线分类器
3.k-最近邻(KNN)
4.支持向量机(SVM)
5.袋装决策树
6.随机森林
7.逻辑回归
8.LGBM
对于这些列中的每一列,我们将尝试应用以下优化技术:
- 默认超参数
- Sklearn GridSearchCV
- Sklearn 随机搜索 CV
- Python 的远视
features = features.drop(['Cabin'], axis=1)
features = features.drop(['Name'], axis=1)
objects = [col for col in features.columns if features[col].dtype == "object"]features.update(features[objects].fillna('None'))
numeric_dtypes = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
numerics = [col for col in features.columns if features[col].dtype in numeric_dtypes]
features.update(features[numerics].fillna(0))
features.info()
# dummies and split
X = pd.get_dummies(features)
X_train, X_valid, y_train, y_valid = train_test_split(X,y,train_size=0.70,test_size=0.30,random_state=0)#Results dataframe
cols = ['Case','SGD','Ridge','KNN','SVM','Bagging','RndForest','LogReg','LGB']resul = pd.DataFrame(columns=cols)
resul.set_index("Case",inplace=True)
resul.loc['Standard'] = [0,0,0,0,0,0,0,0]
resul.loc['GridSearch'] = [0,0,0,0,0,0,0,0]
resul.loc['RandomSearch'] = [0,0,0,0,0,0,0,0]
resul.loc['Hyperopt'] = [0,0,0,0,0,0,0,0]resul.head()
结果的空数据框架
第 1 行—每个算法的默认超参数
如上所述,我们的结果表的第一行是分析的起点,采用每个算法的超参数的默认值:
#Models creation
sgd = SGDClassifier()
ridge = RidgeClassifier()
knn = KNeighborsClassifier()
svc = SVC(gamma='auto')
bag = BaggingClassifier()
rf = RandomForestClassifier(n_estimators=10)
lr = LogisticRegression(solver='liblinear')
lgg = lgb.LGBMClassifier()models = [sgd,ridge,knn,svc,bag,rf,lr,lgg]col = 0
for model in models:
model.fit(X_train,y_train.values.ravel())
resul.iloc[0,col] = model.score(X_valid,y_valid)
col += 1resul.head()
第 2 行—应用 GridSearchCV
“网格搜索通过尝试您想要在模型中尝试的每个可能的参数组合来工作。这些参数中的每一个都在一系列交叉验证过程中被尝试。在过去的几年里,这种技术作为一种调整你的模型的方法已经流行起来了,“⁴.
现在,我们必须为每个算法定义一个包含不同参数及其值的字典
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import RepeatedStratifiedKFold#SGD
loss = ['hinge', 'modified_huber', 'log']
penalty = ['l1','l2']
alpha= [0.0001,0.001,0.01,0.1]
l1_ratio= [0.15,0.05,.025]
max_iter = [1,5,10,100,1000,10000]
sgd_grid = dict(loss=loss,penalty=penalty,max_iter=max_iter,alpha=alpha,l1_ratio=l1_ratio)#Ridge
alpha = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
ridge_grid = dict(alpha=alpha)#K-Nearest - Neighborg
n_neighbors = range(1, 21, 2)
weights = ['uniform', 'distance']
metric = ['euclidean', 'manhattan', 'minkowski']
knn_grid = dict(n_neighbors=n_neighbors,weights=weights,metric=metric)#Support Vector Classifier
kernel = ['poly', 'rbf', 'sigmoid']
C = [50, 10, 1.0, 0.1, 0.01]
gamma = ['scale']
svc_grid = dict(kernel=kernel,C=C,gamma=gamma)#Bagging Classifier
n_estimators = [10, 100, 1000]
bag_grid = dict(n_estimators=n_estimators)#Random Forest
n_estimators = [10, 100, 1000,10000]
max_features = ['sqrt', 'log2']
rf_grid = dict(n_estimators=n_estimators,max_features=max_features)#Logistic Regrresion
solvers = ['newton-cg', 'lbfgs', 'liblinear']
penalty = ['l2']
c_values = [100, 10, 1.0, 0.1, 0.01]
lr_grid = dict(solver=solvers,penalty=penalty,C=c_values)#LGB
class_weight = [None,'balanced']
boosting_type = ['gbdt', 'goss', 'dart']
num_leaves = [30,50,100,150] #list(range(30, 150)),
learning_rate = list(np.logspace(np.log(0.005), np.log(0.2), base = np.exp(1), num = 10)) #1000
lgg_grid = dict(class_weight=class_weight, boosting_type=boosting_type, num_leaves=num_leaves, learning_rate =learning_rate)
然后,对每个应用 GridSearchCV:
models = [sgd,ridge,knn,svc,bag,rf,lr,lgg]
grids = [sgd_grid,ridge_grid,knn_grid,svc_grid,bag_grid,rf_grid,lr_grid,lgg_grid]col = 0
for ind in range(0,len(models)):
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3,
random_state=1) grid_search = GridSearchCV(estimator=models[col],
param_grid=grids[col], n_jobs=-1, cv=cv,
scoring='accuracy',error_score=0) grid_clf_acc = grid_search.fit(X_train, y_train)
resul.iloc[1,col] = grid_clf_acc.score(X_valid,y_valid)
col += 1resul.head()
不同的算法有更多的参数,这里没有特意包括,您可以在每个超参数中强制搜索更多的值。
这个缩减是根据我们愿意投入的时间和计算能力来发展的。
第 3 行—应用 RandomSearchCV
“进入随机搜索。考虑尝试每一种可能的组合需要大量的蛮力计算。数据科学家是一群没有耐心的人,所以他们采用了一种更快的技术:从一系列参数中随机取样。这个想法是,你会比网格搜索更快地覆盖接近最优的参数集。然而,这种技术是幼稚的。它不知道也不记得以前运行过的任何东西。”⁴
出于实用目的,代码与 GridSearchCV 相同,只是修改了:
random_search = RandomizedSearchCV(models[col],
param_distributions=grids[col],n_iter=n_iter_search,
cv=cv)
代替
grid_search = GridSearchCV(estimator=lr, param_grid=lr_grid,
n_jobs=-1, cv=cv, scoring='accuracy',error_score=0)
完整的代码如下:
from scipy.stats import randint as sp_randint
from sklearn.model_selection import RandomizedSearchCVcol = 0
for ind in range(0,len(models)):
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3,
random_state=1)
n_iter_search = 3
random_search = RandomizedSearchCV(models[col],
param_distributions=grids[col],n_iter=n_iter_search, cv=cv) random_search.fit(X_train,y_train)
resul.iloc[2,col] = random_search.score(X_valid,y_valid)
col += 1resul.head()
分析结果
到目前为止,如果我们检查结果网格,我们发现自动搜索技术的应用已经给出了良好的结果。
在某些情况下,像 SGD 或 SVM 算法已经有了很大的改进,从 67–69%的下限提高到 78–76%。
总的趋势是提高 1、2 或 3 个百分点,GridSearchCV 比 RandomSearchCV 获得更好的结果,随机应用时间比网格应用时间好。
我们来分析一下他版本的 GridSearchCV 中的获胜算法(光照渐变提升):
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3,
random_state=1)
n_iter_search = 3
grid_search = GridSearchCV(estimator=lgg, param_grid=lgg_grid,
n_jobs=-1, cv=cv, scoring='accuracy',error_score=0)
grid_win = grid_search.fit(X_train, y_train)#Predict values based on new parameters
yv_pred = grid_win.predict(X_valid)print(confusion_matrix(y_valid, yv_pred))
skplt.metrics.plot_confusion_matrix(y_valid, yv_pred,figsize=(8,8))
要了解我们使用的算法版本中的超参数:
print("Best: %f using %s" % (grid_win.best_score_, grid_win.best_params_))
第 4 行——使用 hyperopt 库应用贝叶斯超优化
我必须承认,在我理解如何应用贝叶斯优化技术之前,我感到非常失落和困惑,几乎要放弃了。我可以参考的来自图书馆和其他文章的文档和例子都很模糊,或者太枯燥,或者非常过时。
所有这一切,直到我发现这个优秀的图图利亚 l⁵和它的代号 ⁶由威尔·科尔森所作,我建议你一步一步地回顾和尝试,因为它是清晰和详尽的。跟着他,我们要做的第一件事是定义我们的目标函数,它必须返回一个至少带有标签‘loss’和‘status’的字典。
import csv
from hyperopt import STATUS_OK
from timeit import default_timer as timerMAX_EVALS = 500
N_FOLDS = 10def objective(params, n_folds = N_FOLDS): """Objective function for Gradient Boosting Machine Hyperparameter Optimization""" # Keep track of evals
global ITERATION
ITERATION += 1 # Retrieve the subsample if present otherwise set to 1.0
subsample = params['boosting_type'].get('subsample', 1.0) # Extract the boosting type
params['boosting_type'] = params['boosting_type']
['boosting_type']
params['subsample'] = subsample # Make sure parameters that need to be integers are integers
for parameter_name in ['num_leaves', 'subsample_for_bin',
'min_child_samples']:
params[parameter_name] = int(params[parameter_name]) start = timer()
# Perform n_folds cross validation
cv_results = lgb.cv(params, train_set, num_boost_round = 10000,
nfold = n_folds, early_stopping_rounds = 100,
metrics = 'auc', seed = 50)
run_time = timer() - start # Extract the best score
best_score = np.max(cv_results['auc-mean']) # Loss must be minimized
loss = 1 - best_score # Boosting rounds that returned the highest cv score
n_estimators = int(np.argmax(cv_results['auc-mean']) + 1) # Write to the csv file ('a' means append)
of_connection = open(out_file, 'a')
writer = csv.writer(of_connection)
writer.writerow([loss, params, ITERATION, n_estimators,
run_time]) # Dictionary with information for evaluation
return {'loss': loss, 'params': params, 'iteration': ITERATION,
'estimators': n_estimators, 'train_time': run_time,
'status': STATUS_OK}
域空间:域空间表示我们想要为每个超参数评估的值的范围。每次搜索迭代,贝叶斯优化算法将从域空间中为每个超参数选择一个值。当我们进行随机或网格搜索时,域空间是一个网格。在贝叶斯优化中,想法是相同的,除了这个空间对于每个超参数具有概率分布而不是离散值。
space = {
'class_weight': hp.choice('class_weight', [None, 'balanced']),
'boosting_type': hp.choice('boosting_type', [
{'boosting_type': 'gbdt', 'subsample': hp.uniform('gdbt_subsample', 0.5, 1)},
{'boosting_type': 'dart', 'subsample': hp.uniform('dart_subsample', 0.5, 1)},
{'boosting_type': 'goss', 'subsample': 1.0}]),'num_leaves': hp.quniform('num_leaves', 30, 150, 1),
'learning_rate': hp.loguniform('learning_rate', np.log(0.01),
np.log(0.2)),
'subsample_for_bin': hp.quniform('subsample_for_bin', 20000,
300000),
'min_child_samples': hp.quniform('min_child_samples', 20, 500, 5),
'reg_alpha': hp.uniform('reg_alpha', 0.0, 1.0),
'reg_lambda': hp.uniform('reg_lambda', 0.0, 1.0),
'colsample_bytree': hp.uniform('colsample_by_tree', 0.6, 1.0)}
这里使用不同的域分发类型(在hyperopt 文档中寻找完整的分发列表):
choice
:分类变量quniform
:离散均匀(间隔均匀的整数)uniform
:连续均匀(浮动间隔均匀)loguniform
:连续的均匀圆木(在圆木刻度上均匀分布的浮子)
from hyperopt import tpe
from hyperopt import Trials# optimization algorithm
tpe_algorithm = tpe.suggest# Keep track of results
**bayes_trials = Trials()**# File to save first results
out_file = './gbm_trials.csv'
of_connection = open(out_file, 'w')
writer = csv.writer(of_connection)# Write the headers to the file
writer.writerow(['loss', 'params', 'iteration', 'estimators', 'train_time'])
of_connection.close()
最后,准备好所有代码后,我们通过 fmin 函数寻找参数的最佳组合:
from hyperopt import fmin# Global variable
global ITERATION
ITERATION = 0
MAX_EVALS = 100# Create a lgb dataset
train_set = lgb.Dataset(X_train, label = y_train)# Run optimization
best = fmin(fn = objective, space = space, algo = tpe.suggest,
max_evals = MAX_EVALS, trials = bayes_trials,
rstate =np.random.RandomState(50))
它触发了寻找最佳组合的过程。在最初的例子中,变量 MAX_EVALS 被设置为 500;由于本练习的性能问题,它被减少到 100,这可能会影响最终结果。
一旦流程结束,我们就可以获取 Trials 对象(在我们的例子中是 bayes_trials)并分析其结果:
# Sort the trials with lowest loss (highest AUC) first
bayes_trials_results = sorted(bayes_trials.results, key = lambda x: x['loss'])
bayes_trials_results[:2]
我们还可以从 CSV 加载数据帧,并使用“ast”库将文本转换为字典,并为我们的最终模型提供最佳结果。
results = pd.read_csv('./gbm_trials.csv')# Sort with best scores on top and reset index for slicing
results.sort_values('loss', ascending = True, inplace = True)
results.reset_index(inplace = True, drop = True)
results.head()
import ast# Convert from a string to a dictionary
ast.literal_eval(results.loc[0, 'params'])
# Extract the ideal number of estimators and hyperparameters
best_bayes_estimators = int(results.loc[0, 'estimators'])
best_bayes_params = ast.literal_eval(results.loc[0, 'params']).copy()# Re-create the best model and train on the training data
best_bayes_model = lgb.LGBMClassifier(n_estimators=best_bayes_estimators, n_jobs = -1,
objective = 'binary', random_state = 7,
**best_bayes_params)
best_bayes_model.fit(X_train, y_train)# Evaluate on the testing data
preds = best_bayes_model.predict(X_valid)
print(confusion_matrix(y_valid, preds))
print (best_bayes_model.score(X_valid,y_valid))
skplt.metrics.plot_confusion_matrix(y_valid, preds,figsize=(8,8))resul.iloc[3,7] = best_bayes_model.score(X_valid,y_valid)
resul.head()
远视在 LGB 模型中的应用
摘要
我们开发了完整的代码来应用三种可用的优化技术,八种不同的分类算法。应用这些技术所需的时间和计算能力是一个需要考虑的问题;当所选模型的技术水平足够高时,似乎有必要执行这种优化。
参数优化并不一定意味着训练模型的结果相对于测试数据的持续改进,因为参数的选择可能会产生过度拟合。
最后,应该指出的是,在不同模型上观察到的改进通常具有相当大的幅度,这至少为通过这些技术中的任何一种来提高算法性能的可能性留下了余地。
来源和参考
[1]https://en.wikipedia.org/w/index.php?title = Accuracy _ and _ precision&action =编辑& section=4
在二进制分类中,准确度也用作一种统计度量,用于衡量 二进制分类 测试正确识别或排除某个条件的程度。即准确率是真实结果(既有 真阳性 又有 真阴性 )占检查病例总数的比例……量化二进制准确率的公式为:
准确度= (TP+TN)/(TP+TN+FP+FN)
其中:TP =真阳性;FP =假阳性;TN =真阴性;FN =假阴性
[4]https://medium . com/apprentice-journal/hyper-parameter-optimization-c9b 78372447 b
法国的雪崩危险
使用 GeoPandas 和 Bokeh 库在 Python 中可视化地理空间数据
从布兰克湖看布兰克山,图片来源:卡米拉·哈马尔奇科瓦
对徒步旅行者和登山运动员来说,法国哪些山脉最危险?这是我的主要问题,因为我最近搬到了格勒诺布尔,那里基本上是法国徒步旅行的天堂。
不幸的是,我只从ANENA(法国雪和雪崩研究组织)按公社(法国的小行政单位)划分的报道中找到了关于每年雪崩事故的地区性数据。这是除了按山脉分组的山区事故之外第二好的事情,因为我找不到,所以在扑克或俄罗斯方块中,我玩了我拿到的那手牌,并搜索了法国公社的【shape file】(幸运的是,法国政府的官方消息来源没有让我失望)。这只是我的可视化“拼图”的两块,我需要在 Jupyter 笔记本上开始编码,以创建过去 10 年法国雪崩事故的互动地图。****
不说话,只管码
Jupyter 笔记本中所有带源码数据和代码的文件都可以在我在法国的 GitHub repo 雪崩危险中找到。
1)安装
假设您已经安装了像 Pandas 和 Numpy 这样的标准 Python 库,为了处理地理空间数据和 shapefiles,我需要添加 GeoPandas 和 Bokeh。
**在我的例子中(带有 Anaconda 的 Windows ),我的命令行的神奇单词是; conda install geopandas 和 conda install bokeh,如 GeoPandas 和 Bokeh 库文档中所述。
最终可视化预览,用彩色描绘了法国过去 10 年中发生 1 - 30 次雪崩的公社,用灰色描绘了没有雪崩的公社
2)熟悉 Geopandas 数据框架
之前,我用了两次术语 shapefile 而没有进一步解释,这有点刻薄,我不想成为刻薄的女孩,所以…
Shapefile 格式是指点、线或多边形形式的地理空间数据,通常用于 GIS(地理信息系统)。shapefile 的扩展名是。shp,但是为了显示数据,你实际上需要一个文件夹中的 3 个文件。shp,。shx 和。dbf** 。**
如果 polygon 听起来更像是 Jean-Luc Piccard 在修理他的企业时必须飞行的宇宙飞船的名字,你会从下面的例子中有更好的想法。这是法国阿斯奈尔斯-苏尔-瓦兹公社的多边形(在几次随机试验后,我能找到的最接近宇宙飞船的多边形)。
用 iloc()方法显示某个多边形
在这里,我们可以看到,使用 iloc 方法,地理数据框中的多边形或地理空间数据通常可以以与传统 Pandas 数据框中的行相同的方式显示。对于多边形的图像,我们需要寻找具有活动的 几何图形的列, 数据以 GPS 坐标的形式存储在哪里。(具有活动几何图形的柱最有可能被命名为几何图形。)**
带坐标系(几何)的列将 GeoPandas 中的地理数据框与 Pandas 中的其他数据框区分开来。
读取和查看地理数据框与简单的数据框非常相似(除了已经提到的需要。shp,。shx 和。一个文件夹中的 dbf 文件,以便加载 shapefile)😗*
Jupyter 笔记本中带有活动几何图形的地理数据框架
我的两个可视化拼图(shape file with all communities and avalanche incidents report)都需要有一个连接列。就是公社( gdf 地理数据框架中的 NOM_COM 和雪崩数据框架中的公社*)。*
不幸的是,地理数据框架和数据框架中的社区名称是使用不同的大写/小写字母、特殊法语字符(é、à、等)编写的。)有时甚至混合使用连字符和空格。
3)法语的数据清洗和陷阱
因此,我用 str.lower( ) 方法将所有的公社名称改为小写,并替换特殊的法语字符,以避免相同公社名称的两个版本。
理想情况下,avalanche 数据框架中的所有社区名称也应包含在 gdf 地理数据框架中,但由于以下几个原因,情况并非如此:
- 雪崩报告中的社区名称是由人插入的,因此包括一些拼写错误,有时记录中提到的不是滑雪站的社区名称
- 随着时间的推移,一些公社合并成不同的公社或改变了名称,因此一些公社的名称今天已经过时
- 不同地区的公社很少有名字完全相同的
- shapefile 中的多边形不是从公社派生出来的,而是从更小的单元派生出来的,这些单元在大多数情况下与公社相同,但不是所有的都是如此
我通过简单更改 gdf 地理数据框架或雪崩数据框架的名称解决了前三个问题。这很费时间,但是因为它只对我的情况非常具体,并且与地理空间数据没有特别的联系,所以我不会在这里详细讨论它(无论如何,更多的细节可以在我的 GitHub repo 中找到)。
多边形的最后一个问题并不总是来源于你需要的形状,这也是你在处理地理空间数据时可能遇到的问题。这里我们可以看到夏蒙尼勃朗峰社区由 4 个不同的多边形组成。
在这里,夏蒙尼勃朗峰公社由四个不同的多边形组成,我们可以在几何栏的四个不同条目中看到。
它可以通过使用溶解函数来解决,该函数基于所选的列创建新的多边形(例如:dissolve(by="column_x "))。社区边界被定义为仅保留我们想要保留的列的地理数据框架。创建缓冲区以避免新多边形相交。
徒步旅行者在法国格勒诺布尔附近的山脉没有探测到雪崩的危险。资料来源:Kamila Hamalcikova
4)创建最终的地理数据框架,以便在散景中进一步使用
现在,我终于有了源自公社的完美多边形。但是我也需要每个公社雪崩事故的总数。简单的 groupby()函数和创建新的数据帧就可以达到这个目的:
当然,丑陋的列名 0 需要一点修饰。
最后,我可以将 gdf 地理数据框架中的数据与 aval_final 数据框架中的累积雪崩报告合并。
NaN 值是指在过去 10 年中没有发生雪崩的社区。稍后,当使用散景时,我们需要将此地理数据框架转换为 GeoJSON 格式。这将触发错误,因为 NaN 值不被识别为 JSON 对象。因此,我将用 fillna()函数*将所有 NaN 替换为字符串“No avalanche ”,并验证之后地理数据帧中没有出现 NaN。*
如果你坚持这么长时间阅读这篇文章,我认为在攻击在散景图书馆创建可视化的最后一步之前,你应该得到一张更酷的法国阿尔卑斯山的照片。
右侧为勃朗峰的麂皮,来源:卡米拉·哈马尔契科娃
Bokeh 雪崩事故互动地图
Bokeh 库使用 GeoJSON 格式进行数据可视化,因此我需要将最终的地理数据框架转换为 GeoJSON 格式。
与大多数 Python 库不同,散景库中的元素需要单独成组导入。在下面的代码中,我导入了我将使用的所有元素,但是还有更多选项。
接下来,我将选择颜色设置。在散景文档中有大量的调色板。在 color_mapper 中,选择 vis 值的最小值和最大值以及所选调色板外的颜色(nan_color) 来表示 nan 值,或者更准确地说是 GeoJSON 中的字符串“No avalanche”。
我还使用了 major_label_overrides 来突出显示只有至少发生过一次雪崩事故的公社 才会出现在调色板中。如果不使用此功能,所有 0 到 4 次雪崩的社区将会以相同的颜色结束在一个组中,这在视觉上是非常不清楚和混乱的。
为了最终的可视化,我们需要创建图形对象。
方法 patches() 用于绘制图形中公社的形状。除了定义 x 和 y 坐标,我们还需要指定 fill_color 。我们的颜色必须在每个多边形上改变,因此我使用带有关键字字段和变换的字典。字段值是我们想要绘制的变量,转换值是该变量的颜色组。
在 hovertool 的工具提示中,我们选择了在地图上移动光标时显示给用户的数据(在我的例子中是社区名称和雪崩事故总数,所以列社区和雪崩事故计数*)。*
如果您仍然发现上面的代码中有不清楚的地方,我建议检查具有非常相似的可视化的散景库。
最后,我将最终的可视化保存为单独的 html 文件,但是如果你想在 Jupyter 笔记本中直接显示图形,你可以使用 save()函数 show()。只是别忘了从 bokeh.io 导入之前的功能。
任何人都可能会猜测,大多数雪崩事故发生在法国的阿尔卑斯山,在勃朗峰和比利牛斯山脉附近,靠近西班牙边境。对我来说,很惊讶地发现雪崩也出现在阿尔萨斯地区或中央高原,甚至在科西嘉岛也有一例发生。
用户指出夏蒙尼勃朗峰公社是过去 10 年里雪崩事故发生最多的地方。ANENA 组织报告了从 2010/11 年冬季到 2019/20 年冬季的 30 起病例。
有这么多多边形的地图可视化的一个缺点是缩放非常慢,并且需要 GitHub 上的额外存储,以防你想把它发布在那里。另一方面,地图非常详细和精确。
参考文献:
- ANENA:全国雪崩和雪崩研究协会,事故报告 (2020),Anena.org
- *Data.gouv.fr (2020),【Data.gouv.org *
- 南 PATEL,使用 Python 制作交互式地理地图的完整指南 (2019),TowardsDataScience.com
- 地球实验室,第六课。如何使用 Geopandas 融合多边形:python 空间数据开源 Python 工作坊中的 GIS(2019)EarthDataScience.org
- 地理信息系统,在 geopandas (2018),gis.stackexchange.com中,溶解原因“不能从空值创建有形状的几何图形”
- Stackoverflow,在 geopandas (2020) ,Stackoverflow.com
用最后的气宗化身实现 Python 中的数据可视化
学习使用 Plotly、Seaborn 和 Matplotlib 库制作令人惊叹的可视化效果。
《最后的气宗》是那种你迫不及待想知道下一集会发生什么的剧集。它有一个伟大的故事情节,强大的人物和一些好的战斗。看了第二遍《阿凡达》后,我决定寻找比我们大多数人年轻时看的更多的关于这部电视剧的东西。为此,我将使用 Plotly、Seaborn 和 Matplotlib 来用很酷的图表支持我们的分析。
注意:你可以在 Kaggle 上找到我用于此分析的头像数据集(或者从我的Github下载,我也将此分析的完整代码留在那里)
人物
阿凡达团队的成员(安昂、卡塔拉、索卡、托弗和祖寇)在所有角色中拥有最多的台词。然而,前 10 名中的一些角色可能会让你大吃一惊。例如,指挥官赵只在第一部(水)中出现,但他在那一季中有很多屏幕时间,这反映在他进入前 10 的大量台词中。
另一个没有出现在所有剧集中的角色是杰特,他只在第一部和第二部(地球)中出现过。此外,它引起了我对第三部(火)中 Iroh 叔叔的几句台词的注意。我记得他被抓了,只在几个场景里出现过,所以说得通。
作者图片
像上面这样的交互式可视化很容易用 Plotly 实现。一旦数据准备就绪,您只需要几行代码:
谁跟谁说话?
我们已经知道在 61 集阿凡达中谁说的话最多。然而,前 10 个角色之间有很多对话,所以我很好奇他们之间的互动频率。我们可以通过使用 Seaborn 库中的热图来发现角色之间的交互细节。
行与列对话。每个方块的颜色代表每行中的字符对每列中的字符说的行数。较亮的方块意味着说出了更多的台词——图片由作者提供
热图揭示了人物之间的一些关系。自然有很多团队头像成员之间的对话。然而,也有许多团队成员之间的对话头像和休息,例如,索卡-淑熙和艾罗-祖寇。最后,我不禁注意到前 10 个角色之间从未在屏幕上发生过的一些对话。意料之中的是赵从来没有和像阿祖拉这样后来在节目中介绍的角色说过话,但是当我发现 Jet 在节目中从来没有面对过阿祖拉或者的时候,我有点惊讶。
他们在说什么?
有很多方法可以窥见顶级人物在说什么。在这种情况下,我将使用其中的两个:情感分析和词云。
情感分析
我们可以使用自然语言处理技术(VADER 情感分析)来量化角色所说的每一行的情感。有了这个工具,获得情感分数非常简单。关于处理情感分析数据的细节在我的 GitHub 上。一旦我们获得分数,我们就可以使用 Matplolib 用柱状图展示它。
作者图片
上面的图表揭示了按照积极程度排序的前 10 位人物。显然,艾罗和安昂是剧中最积极的角色。一个是开茶叶店的快乐大叔,另一个是当事情出错时喜欢跳舞的和平主义僧侣,所以结果是合理的,对吗?
另一方面,赵是该剧中迄今为止最消极的角色。事实上,我期待阿祖拉在这个位置上,但它仍然有意义。还有,祖寇的前两个赛季足以让他们被认为是一个消极的家伙,数据也证明了这一点。
词汇云
让我们来看看水、土、火这三本书里所有角色说的话。我去掉了角色名以获得更有意义的单词。
水、土、火……—作者图片
为了创建这个单词云,我同时使用了stylecloud
和wordcloud
。第一个给出了时尚的文字云,包括惊人的颜色和图标,而第二个你可以使用自己的图片,就像我在右边使用的“火国符号”。这是我用styleloud
*做文字云的代码。*其余的可以在 GitHub 上找到。
额外收获:我的卷心菜!
记得白菜商的大车被砸的时候笑了很多次。我发现这个短语他在 61 集里重复了 5 次。他第一次说这句话是在第一集奥玛舒王(第一集),而最后一次是在第二集大蛇的通行证
IMDb 评分与口语
我们可以用散点图找到两个变量之间的关系,并使之与 Plotly 交互。
有趣的是,口语数量最少的剧集(索金的短号第 3 和第 4 部分)获得了最高的 IMDb 评分,而口语数量最多的剧集之一(大分裂)获得了最低的 IMDb 评分。似乎粉丝们更喜欢有更多动作和精彩打斗的剧集,而不是冗长的对话。
作者图片
这是我用 Plotly 做上面散点图用的代码:
结论
在这篇文章中,我们发现了一些关于《最后的气宗阿凡达》的见解,这些见解可能是你和我从未想过的。我们已经知道谁用柱状图说话最多,谁用热图和谁说话,以及这些角色通过情感分析和文字云在说什么。
最重要的是,我们发现我们可以从学习数据科学工具中获得乐趣。请随意在 Github 上查看该分析背后的代码。