TowardsDataScience-博客中文翻译-2019-十九-
TowardsDataScience 博客中文翻译 2019(十九)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
数据科学家的工具包—如何从不同来源收集数据
原文:https://towardsdatascience.com/data-scientists-toolkit-how-to-gather-data-from-different-sources-1b92067556b3?source=collection_archive---------17-----------------------
Master all — csv、tsv、zip、txt、api、json、sql …
Photo by Jakob Owens on Unsplash
不久前!
您还记得将外部硬盘中的数据发送给您进行分析或建模的时间吗?
现在,作为一名数据科学家,你不局限于这些方法。存储数据、共享数据以及获取数据、扩充数据的不同来源有多种方式。
下面,我列出了几种收集数据的方法供你分析
目录:
- CSV 文件
- 平面文件(制表符、空格或任何其他分隔符)
- 文本文件(在单个文件中—一次读取所有数据)
- 压缩文件
- 多个文本文件(数据被分割到多个文本文件中)
- 从互联网下载文件(服务器上托管的文件)
- 网页(抓取)
- API(JSON)
- 文本文件(逐行读取数据)
- 关系数据库管理系统(SQL 表)
在 Python 中,文件被描述为文本或二进制文件,两者之间的区别很重要
文本文件由一系列行组成。每一行都以一个称为 EOL 或行尾字符的特殊字符结束。有几种类型,但最常见的是\n
或,
二进制文件类型基本上是除文本文件之外的任何类型的文件。由于其性质,二进制文件只能由知道或理解文件结构的应用程序来处理
1。CSV 文件
存储和共享数据集最常见的格式是逗号分隔格式或 csv 文件。pandas.read_csv()
是最有用和最强大的方法,我强烈推荐你阅读它的文档。通过使用适当类型的sep
,您可以在 dataframe 中加载多种类型的数据
import pandasdf = pd.read_csv('data.csv', sep =',')
2。平锉平锉
但有时您可能会收到制表符分隔、固定宽度格式或分号分隔等文件。Pandas
提供多种方法来恰当地读取此类数据。但是,当您指定正确的分隔符时,甚至read_csv
也能很好地工作
import pandas# Tab separated file
df = pd.read_csv('data.tsv', sep='\t')
OR
# columns are separated by space
df = pd.read_csv('data.txt', sep = ' ')
3。文本文件
我们看到使用pandas.read_csv()
方法可以读取 txt 文件,但是让我们看看读取 txt 文件的另一种方式是上下文管理器。它们在分配和管理资源、关闭所有打开的文件方面非常有效
上下文管理器最广泛使用的例子是with
语句
file_name = 'data.txt'with open(file_name, mode = 'r') as file:
df = file
4。Zip 文件
有时,您可能会得到一个 csv 文件,其中可能包含您需要的 csv 文件,以节省大小。提取。你需要使用' zip file '库。如果你使用的是 windows,这样做比从 windows 中提取要好得多
zipfile
也是一个上下文管理器,将支持我们前面看到的with
语句
from zipfile import ZipFilefile_name = 'my_zip_file.zip'
with open(file_name, mode = 'r') as f:
f.extractall()
# Extractall method will extract all the contents of zipfile in the same folder# now we can load the extracted csv file in our dataframe
import pandasdf = pd.read_csv('my_csv_file.csv')
5。多个文本文件
您可能会遇到这样的情况,您的数据以多个文本文件的形式提供给您。例如,你被提供了 1000 个电影标题的评论,而不是把所有的放入一个,他们把每个单独的评论作为一个文件,并且提供了 1000 个这样的文本文件
我们将使用一个库glob
——它使得打开具有相似路径结构的文件变得简单
import pandas
import globfolder_name = 'my_folder'df_list = []
for review in glob.glob('my_folder/*.txt'):
with open(review, mode = 'r') as file:
movie = {}
movie['title'] = file.readline()
movie['review'] = file.read()
df_list.append(movie)df = pd.DataFrame(df_list)
- 是 glob 语句中的通配符。它允许 python 扫描所有的。给定路径中的 txt 文件
6。从网上下载文件
如果你必须下载保存在服务器上的文件。你必须使用一个库— requests
import requests
import ossample_url = '192.145.232.xx/2019/2/class_notes/gather_data.txt'folder_name = 'my_folder'if not os.path.exists(folder_name):
os.makedirs(folder_name)response = requests.get(url)
file_name = 'gather_data.txt'
file_loc = os.path.join(folder_name, file_name)
with open(file_loc, mode='wb') as outfile:
outfile.write(response.content)
7。网页(网页抓取)
网络抓取是一种使用代码从网页中提取数据的奇特方式。存储在网页上的数据被称为 HTML,即超文本标记语言。它是由这些叫做标签的东西组成的,这些东西赋予了网页结构。<title>,
<div>,
<h1>
…..等等
因为 HTML 代码只是文本,所以可以使用解析器提取其中的标签和内容。为此,我们将使用一个库— BeautifulSoup
假设我们想从 IMDb 和烂番茄两者中提取关于《复仇者联盟》最终结局(2019)的信息
注意:Inspect element 是您寻找相关标签和属性以提取数据的最好朋友
from bs4 import BeautifulSoup as bs
import requests
import pandasimdb_url = '[https://www.imdb.com/title/tt4154796/](https://www.imdb.com/title/tt4154796/)'
response = requests.get(imdb_url)
soup = bs(response.content, features = b'lxml)
movie = {}
movie['title'] = soup.find('div', attrs = {'class': 'title_wrapper'}).find('h1').text
movie['imdb_rating'] = soup.find('span', attrs = {'itemprop': 'ratingValue'}).textrt_url = '[https://www.rottentomatoes.com/m/avengers_endgame](https://www.rottentomatoes.com/m/avengers_endgame)'
response = requests.get(rt_url)
soup = bs(response.content, features = 'lxml')
movie['tomatometer'] = soup.find('span', attrs = {'class' : 'mop-ratings-wrap__percentage'}).text
movie['audience_score'] = soup.find('div', attrs = {'class' : 'audience-score'}).find('span', attrs={'class' : 'mop-ratings-wrap__percentage'}).textdf = pd.DataFrame(movie)
通过这种方式,我们从两个不同的来源收集了关于《复仇者联盟》结局的信息
8。API(应用程序编程接口)
你当然可以从网页中提取信息,但是更好的获取信息的方式是通过 API。
维基百科有几个公开开放的 API,其中流行的一个是 Mediawiki。我们将使用 python 库wptools
import wptools
import pandas# For a wikipedia URL '[https://en.wikipedia.org/wiki/Avengers:_Endgame](https://en.wikipedia.org/wiki/Avengers:_Endgame)' we only need to pass the string after /wiki/wiki_page = wptools.page('[Avengers:_Endgame](https://en.wikipedia.org/wiki/Avengers:_Endgame)).get()# Now this wiki_page has fetched extracts, images, infobox data, wiki data etc
# By using wikipage.data() method we can extract all the informationwiki_page.data['image'] # this will return 3 images backfirst_image = wiki_page.data['image'][0]
print (first_image['url'])
'https://upload.wikimedia.org/wikipedia/en/0/0d/Avengers_Endgame_poster.jpg'# Now you can save this poster link or use the requests method as seen above to save poster of the movie
9。文本文件 (逐行读取数据)
假设您已经使用 twitter api — tweepy 下载了 tweepy 数据
你已经将所有的推文保存在一个文本文件中——tweets _ JSON . txt
你现在的目标是从这些推文中提取有用的信息,将其保存在数据框架中,并用于进一步的分析。这是您在第 3 步和第 8 步中学到的技能的组合
第 1 部分—让我向您展示如何使用 tweepy 获取 twitter 数据。
import tweepy
import jsonconsumer_key = 'xxx'
consumer_secret = 'xxx'
access_token = 'xxx'
access_secret = 'xxx'auth = OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_secret)api = tweepy.API(auth, wait_on_rate_limit = True)tweet_ids = [] #This will be the list of tweets for which you need the information forfile_name = 'tweets_json.txt'
with open(file_name, mode='w') as file:
for tweet_id in tweet_id:
tweet = api.get_status(tweet_id, tweet_mode = 'extended')
json.dump(tweet._json, file)
file.write('/n')
第 2 部分—阅读 tweets_json.txt 以提取有用的信息
import pandas
import jsondf_list = []
with open('tweets_json.txt', mode = 'r') as file:
for line in file:
tweet = {}
json_data = json.loads(line)
tweet['tweet_id'] = json_data['id']
tweet['retweet_count'] = json_data['retweet_count']
tweet['favorite_count'] = json_data['favorite_count']
df_list.append(tweet)
tweet_df = pd.DataFrame(df_list)
10。RDBMST3【SQL 数据库】
数据库是“保存在计算机中的一组结构化数据,尤其是可以通过各种方式访问的数据。”它便于数据的存储、检索、修改和删除
在数据争论的背景下,数据库和 SQL 开始用于存储数据或收集数据:
- 连接数据库,将数据导入熊猫数据框架
- 连接数据库并将数据从熊猫数据帧存储到数据库
- 用 python 连接到数据库—
我们将使用 SQLAlchemy 连接到 SQLite 数据库,这是一个用于 python 的数据库工具包
import sqlalchemy
import pandasengine = sqlalchemy.create_engine('sqlite:///movies.db')
movies.db 不会显示在 jupyter 笔记本仪表盘上
2.在数据库中存储熊猫数据帧
# Store dataframe 'df' in a table called movie_tbl in the databasedf.to_sql('movie_tbl', engine, index=False)
movies.db 现在将显示在 jupyter 笔记本仪表盘中
3.读取熊猫数据框架中的数据库表
df = pd.read_sql('SELECT * FROM movie_tbl', engine)
结束语:
- 我试图给出各种事物的基本概念,避免写下太多的细节
- 请随意写下您的想法/建议/反馈
数据科学家:你的变量名很糟糕。以下是修复它们的方法。
原文:https://towardsdatascience.com/data-scientists-your-variable-names-are-awful-heres-how-to-fix-them-89053d2855be?source=collection_archive---------2-----------------------
Wading your way through data science code is like hacking through a jungle. (Source)
一种大大提高代码质量的简单方法
快速,下面的代码是做什么的?
for i in range(n):
for j in range(m):
for k in range(l):
temp_value = X[i][j][k] * 12.5
new_array[i][j][k] = temp_value + 150
这是不可能的,对吗?如果你试图修改或调试这段代码,你会不知所措,除非你能读懂作者的想法。即使你是作者,在编写这段代码几天后,你也不会知道它做了什么,因为使用了无用的变量名和 【神奇的】数字 。
使用数据科学代码时,我经常看到类似上面(或者更糟)的例子:带有变量名如X, y, xs, x1, x2, tp, tn, clf, reg, xi, yi, ii
和无数未命名常量值的代码。坦率地说,数据科学家(包括我自己)很不擅长给变量命名,甚至不知道如何给它们命名。
随着我从为一次性分析编写面向研究的数据科学代码成长为生产级代码(在 Cortex Building Intel ),我不得不通过抛弃来自数据科学书籍、课程和实验室的实践来改进我的编程。可以部署的机器学习代码与数据科学家被教授的编程方式之间存在许多差异,但我们将从两个具有重大影响的常见问题开始:
- 无用/混乱/模糊的变量名
- 未命名的“神奇”常数数字
这两个问题都导致了数据科学研究(或 Kaggle 项目)和生产机器学习系统之间的脱节。是的,你可以在运行一次的 Jupyter 笔记本中摆脱它们,但是当你有任务关键的机器学习管道每天运行数百次而没有错误时,你必须编写 可读和可理解的 代码。幸运的是,我们数据科学家可以采用来自软件工程的最佳实践,包括我们将在本文中讨论的那些。
注意:我关注 Python,因为它是目前为止行业数据科学中使用最广泛的语言。Python 中的(详见此处):
- 变量/函数名为
lower_case
和separated_with_underscores
- 命名常量在
ALL_CAPITAL_LETTERS
中 - 班级在
CamelCase
命名变量
在命名变量时,有三个基本概念需要记住:
- 变量名必须描述变量所代表的信息。变量名应该用文字明确地告诉你变量代表什么。
- 你的代码被阅读的次数会比它被编写的次数多。优先考虑你的代码有多容易理解,而不是写得有多快。
- 采用标准的命名惯例,这样你就可以做出一个全局决定,而不是多个局部决定。
这在实践中是什么样子的?让我们来看看对变量名的一些改进:
X
和y
。如果你已经看过几百次了,你就知道它们是特性和目标,但是对于阅读你的代码的其他开发人员来说,这可能并不明显。相反,使用描述这些变量代表什么的名称,例如house_features
和house_prices
。value
。值代表什么?可能是一个velocity_mph
、customers_served
、efficiency
、revenue_total
。像value
这样的名字没有告诉你变量的用途,很容易混淆。temp
。即使你只是使用一个变量作为临时值存储,也要给它一个有意义的名字。也许这是一个需要转换单位的值,所以在这种情况下,要明确:
# Don't do this
temp = get_house_price_in_usd(house_sqft, house_room_count)
final_value = temp * usd_to_aud_conversion_rate# Do this instead
house_price_in_usd = get_house_price_in_usd(house_sqft,
house_room_count)
house_price_in_aud = house_price_in_usd * usd_to_aud_conversion_rate
- 如果你使用像
usd, aud, mph, kwh, sqft
这样的缩写,确保你提前建立这些缩写。与团队中的其他人就常用缩写达成一致,并写下来。然后,在代码审查中,确保执行这些书面标准。 tp
、tn
、fp
、fn
:避免机器学习特定缩写。这些值代表true_positives
、true_negatives
、false_positives
和false_negatives
,所以要明确。除了难以理解之外,较短的变量名可能会输入错误。当你指的是tn
的时候用tp
太容易了,所以把整个描述写出来。- 上面是一个优先考虑代码的易读性而不是你能写多快的例子。阅读、理解、测试、修改和调试写得不好的代码要比写得好的代码花费更长的时间。总的来说,通过尝试更快地编写代码——使用更短的变量名——你实际上会增加你程序的开发时间!如果你不相信我,回到你 6 个月前写的一些代码,并尝试修改它。如果你发现自己试图破译你的代码,这表明你应该集中精力在更好的命名约定。
xs
和ys
。这些通常用于绘图,在这种情况下,这些值代表x_coordinates
和y_coordinates
。然而,我已经看到这些名称用于许多其他任务,因此通过使用描述变量用途的特定名称来避免混淆,例如times
和distances
或temperatures
和energy_in_kwh
。
什么导致了不好的变量名?
命名变量的大多数问题源于
- 希望变量名简短
- 将公式直接翻译成代码
关于第一点,虽然像 Fortran 这样的语言确实限制了变量名的长度(6 个字符),但是现代编程语言没有限制,所以不要觉得被迫使用人为的缩写。也不要使用过长的变量名,但是如果你不得不偏向某一方,那么就以可读性为目标。
关于第二点,当你写方程或使用模型时——这是学校忘记强调的一点——记住字母或输入代表真实世界的值!
让我们看一个既犯错误又如何改正的例子。假设我们有一个多项式方程,可以从模型中找到房子的价格。您可能想直接用代码编写数学公式:
temp = m1 * x1 + m2 * (x2 ** 2)
final = temp + b
这是看起来像是机器为机器写的代码。虽然计算机最终会运行你的代码,但它会被人类阅读更多次,所以要写人类能理解的代码!
要做到这一点,我们需要考虑的不是公式本身——如何建模——而是正在建模的真实世界的对象——什么是什么。让我们写出完整的方程(这是一个很好的测试,看看你是否理解模型):
house_price = price_per_room * rooms + \
price_per_floor_squared * (floors ** 2)
house_price = house_price + expected_mean_house_price
如果你在给你的变量命名时有困难,这意味着你对模型或者你的代码不够了解。我们编写代码来解决现实世界的问题,我们需要理解我们的模型试图捕捉什么。描述性变量名让你在比公式更高的抽象层次上工作,帮助你专注于问题领域。
其他考虑
命名变量要记住的重要一点是一致性计数。与变量名保持一致意味着你花在命名上的时间更少,而花在解决问题上的时间更多。当您将聚合添加到变量名时,这一点很重要。
变量名中的聚合
所以你已经掌握了使用描述性名称的基本思想,将xs
改为distances
、e
改为efficiency
、v
改为velocity
。现在,当你取平均速度时会发生什么?这应该是average_velocity
、velocity_mean
还是velocity_average
?两个步骤可以解决这个问题:
- 首先,确定常见的缩写:
avg
表示平均值,max
表示最大值,std
表示标准差等等。确保所有团队成员都同意并记下这些内容。 - 把缩写放在名字的末尾。这将最相关的信息,即由变量描述的实体,放在了开头。
遵循这些规则,您的聚合变量集可能是velocity_avg
、distance_avg
、velocity_min
和distance_max
。规则二。是一种个人选择,如果你不同意,没关系,只要你坚持应用你选择的规则。
当你有一个代表物品数量的变量时,一个棘手的问题就出现了。你可能很想使用building_num
,但这是指建筑物的总数,还是某一特定建筑物的具体指数?为了避免歧义,使用building_count
指代建筑物的总数,使用building_index
指代特定的建筑物。你可以把它应用到其他问题上,比如item_count
和item_index
。如果你不喜欢count
,那么item_total
也是比num
更好的选择。这种方法解决了歧义并保持了将聚合放在名字末尾的一致性。
循环索引
由于某些不幸的原因,典型的循环变量变成了i
、j
和k
。这可能是数据科学中比任何其他实践更多错误和挫折的原因。将无信息的变量名与嵌套循环结合起来(我见过嵌套循环包括使用ii
、jj
,甚至iii
),你就有了不可读、易错代码的完美配方。这可能有争议,但是我从不使用i
或任何其他单个字母作为循环变量,而是选择描述我正在迭代的内容,例如
for building_index in range(building_count):
....
或者
for row_index in range(row_count):
for column_index in range(column_count):
....
这在你有嵌套循环时特别有用,这样你就不必记得i
是代表row
还是column
或者是j
还是k
。您希望将您的精神资源用于计算如何创建最佳模型,而不是试图计算数组索引的特定顺序。
(在 Python 中,如果你没有使用循环变量,那么使用_
作为占位符。这样,您就不会对是否使用索引感到困惑。)
更多要避免的名字
- 避免在变量名中使用数字
- 避免英语中常见的拼写错误
- 避免使用带有不明确字符的名称
- 避免使用意思相似的名字
- 避免在名字中使用缩写
- 避免听起来相似的名字
所有这些都坚持优先考虑读时可理解性而不是写时便利性的原则。编码主要是一种与其他程序员交流的方法,所以在理解你的计算机程序方面给你的团队成员一些帮助。
永远不要使用神奇的数字
一个幻数是一个没有变量名的常量值。我看到这些用于转换单位、改变时间间隔或添加偏移量等任务:
final_value = unconverted_value * 1.61final_quantity = quantity / 60value_with_offset = value + 150
(这些变量名都很差!)
幻数是错误和混乱的主要来源,因为:
- 只有一个人,作者,知道它们代表什么
- 更改该值需要查找所有使用该值的位置,并手动键入新值
不使用幻数,我们可以定义一个转换函数,接受未转换的值和转换率作为参数:
def convert_usd_to_aud(price_in_usd,
aud_to_usd_conversion_rate):
price_in_aus = price_in_usd * usd_to_aud_conversion_rate
如果我们在一个程序的许多函数中使用转换率,我们可以在一个位置定义一个名为常量的:
USD_TO_AUD_CONVERSION_RATE = 1.61price_in_aud = price_in_usd * USD_TO_AUD_CONVERSION_RATE
(在我们开始项目之前,我们应该与团队的其他成员确定usd
=美元,aud
=澳元。记住标准!)
这是另一个例子:
# Conversion function approach
def get_revolution_count(minutes_elapsed,
revolutions_per_minute):
revolution_count = minutes_elapsed * revolutions_per_minute # Named constant approach
REVOLUTIONS_PER_MINUTE = 60revolution_count = minutes_elapsed * REVOLUTIONS_PER_MINUTE
使用在一个地方定义的NAMED_CONSTANT
使得改变值更加容易和一致。如果转换率发生变化,您不需要搜索整个代码库来更改所有出现的代码,因为它只在一个位置定义。它也告诉任何阅读你的代码的人这个常量代表什么。如果名字描述了参数所代表的,函数参数也是一个可接受的解决方案。
作为幻数风险的真实例子,在大学期间,我参与了一个建筑能源数据的研究项目,这些数据最初每隔 15 分钟出现一次。没有人过多考虑这种变化的可能性,我们用神奇的数字 15(或 96 表示每日观察次数)编写了数百个函数。在我们开始以 5 分钟和 1 分钟的间隔获取数据之前,这一切都很好。我们花了几周的时间修改所有的函数来接受区间的一个参数,但即使如此,我们仍然要与几个月来使用幻数所导致的错误作斗争。
真实世界的数据习惯于在你身上变化——货币之间的兑换率每分钟都在波动——硬编码成特定的值意味着你将不得不花费大量的时间来重写代码和修复错误。编程中没有“魔法”的位置,即使在数据科学中也是如此。
标准和惯例的重要性
采用标准的好处是,它们让你做出一个全球性的决定,而不是许多地方性的决定。不要在每次命名变量的时候都选择聚合的位置,而是在项目开始的时候做一个决定,并在整个过程中一致地应用它。目标是花更少的时间在与数据科学无关的问题上:命名、格式、风格——而花更多的时间解决重要问题(比如使用机器学习解决气候变化)。
如果你习惯独自工作,可能很难看到采用标准的好处。然而,即使是独自工作,你也可以练习定义自己的约定,并坚持使用它们。你仍然会从更少的小决策中获益,当你不可避免地需要在团队中发展时,这是一个很好的实践。每当一个项目中有一个以上的程序员时,标准就成了必须的!
你可能不同意我在这篇文章中所做的一些选择,这没关系!采用一套一致的标准比精确选择使用多少空格或变量名的最大长度更重要。关键是不要在偶然的困难上花费太多时间,而是要专注于本质的困难。(大卫·布鲁克斯有一篇关于我们如何从解决软件工程中的偶然问题到专注于本质问题的优秀论文。
结论
记住我们所学的,我们现在可以回到我们开始的初始代码:
for i in range(n):
for j in range(m):
for k in range(l):
temp_value = X[i][j][k] * 12.5
new_array[i][j][k] = temp_value + 150
把它修好。我们将使用描述性的变量名和命名的常量。
现在我们可以看到,这段代码正在对一个数组中的像素值进行归一化,并添加一个常量偏移量来创建一个新的数组(忽略实现的低效率!).当我们将这些代码交给我们的同事时,他们将能够理解并修改这些代码。此外,当我们回过头来测试代码并修复错误时,我们会准确地知道我们在做什么。
这个话题很无聊吗?也许这有点枯燥,但是如果你花时间阅读软件工程,你会意识到区分最好的程序员的是重复实践诸如好的变量名、保持例程简短、测试每一行代码、重构等平凡的技术。这些是将代码从研究阶段转移到生产阶段所需要的技术,一旦你到了那里,你会发现让你的模型影响现实生活中的决策一点也不无聊。
在本文中,我们介绍了一些改进变量名的方法。
需要记住的要点
- 变量名应该描述变量所代表的实体。
- 优先考虑你的代码易于理解的程度,而不是你写代码的速度。
- 在整个项目中使用一致的标准,以最小化小决策的认知负担。
具体要点
- 使用描述性变量名称
- 使用函数参数或命名常数,而不是“神奇”的数字
- 不要使用机器学习专用的缩写
- 用变量名描述一个方程或模型代表什么
- 将聚合放在变量名的末尾
- 用
item_count
代替num
- 使用描述性循环索引代替
i
、j
、k
。 - 在整个项目中采用命名和格式约定
(如果你不同意我的一些具体建议,那没关系。更重要的是,你使用一种标准的方法来命名变量,而不是教条地使用确切的约定!)
我们可以对数据科学代码进行许多其他更改,以使其达到生产级别(我们甚至没有讨论函数名!).我很快会有更多关于这个主题的文章,但与此同时,请查看“从代码完成开始构建软件的注意事项”。要深入了解软件工程最佳实践,请阅读史蒂夫·麦康奈尔的 代码全集 。
为了发挥其真正的潜力,数据科学将需要使用允许我们构建健壮的软件产品的标准。对我们来说幸运的是,软件工程师已经想出了这些最佳实践的大部分,并在无数的书籍和文章中详细介绍了它们。现在该由我们来阅读和执行它们了。
我写关于数据科学的文章,欢迎建设性的评论或反馈。你可以在推特上找到我。如果在提高底线的同时帮助世界对你有吸引力,那就去看看 Cortex Building Intelligence 的职位空缺。我们帮助世界上一些最大的办公楼节省了数十万美元的能源成本,同时减少了碳足迹。
数据显示我们对世界的看法是错误的
原文:https://towardsdatascience.com/data-shows-we-are-wrong-about-the-world-ac5608ce6c4f?source=collection_archive---------22-----------------------
Photo by Vitaly Vlasov from Pexels
用数据破除神话
为什么一切不像媒体告诉你的那么糟糕
埃迪亚告诉我们这个世界正在走向地狱。核战争的风险,民族主义的复兴,大国竞争的回归,也门、叙利亚、利比亚的内战和人道主义灾难…
当最近的一项调查问到“综合考虑所有因素,你认为世界是变得更好还是更坏了?”,人们的反应是(不出所料的)悲观。
在瑞典,只有 10%的人认为情况正在好转,而在美国,这一比例仅为 6%。在英国,55%的受访者认为生活在贫困中的世界人口比例增加了,只有 13%的人认为这一数字下降了。
几乎没有人认为世界正在变好。
媒体不会告诉我们世界在如何变化,它会告诉我们世界在哪里出了问题。史蒂夫·丹宁。
但事实证明并非如此。我们从未经历过如此前所未有的进步。随着每一天的过去,世界变得越来越好。用美国前总统巴拉克·奥巴马的话说,“如果你不得不盲目选择你想在什么时候出生,你会选择现在”。
当我们的头脑被恐惧占据时,就没有事实的空间了。汉斯·罗斯林
在媒体灌输的非理性恐惧所定义的日益动荡和政治化的环境中,数据是唯一稳定的实体。客观、公正地分析数据,(通常)不容易被操纵,这是更好地理解我们日益复杂的世界的关键。
摆脱贫困的大逃亡
Source: Our World in Data
两百多年前,90%的人口生活在极度贫困之中。1950 年,世界上 75%的人仍然生活在极端贫困之中。但如今,生活在极端贫困中的人口还不到总人口的 10%。
很少有人想听到这些,但是每天都有 217,000 人脱离了 2 美元的贫困线。
2000 年,联合国制定了 8 项千年发展目标(始于 1990 年):
- 将全球贫困率减半
- 让 10 亿人摆脱贫困
- 这一切都是在 25 年内发生的
2000 年,大多数专家认为这些目标纯属空想。
你猜怎么着?世界提前五年实现了这些目标。
我们的进步不仅影响了富国,也影响了穷国。到 2008 年,生活在我们星球上的 67 亿人的平均收入相当于西方 1964 年的水平。
暴力
Source: Our World in Data
你们巨大的进步不仅触及了贫困,也触及了其他领域。
各种战争的数量从 1950 年代的每年 6 起下降到 2000 年代的每年 1 起,而死亡人数从每百万人 240 人下降到每百万人不到 10 人。
2017 年有近 7 万人因武装冲突丧生。另一方面,每年有近 80 万人死于自杀。
事实证明,在长期和平的时代,一个人自杀的可能性是被士兵杀死的可能性的 10 倍以上。
2018 年,约有 3 万人被恐怖分子杀害。相比之下,交通事故每年导致 125 万人死亡:27 万中国人、8 万欧洲人和 4 万美国人。
糖尿病和高血糖导致 350 万人死亡!空气污染——700 万。你死于糖尿病和空气污染的概率分别是死于恐怖袭击的 100 倍和 200 倍
现在,糖和空气远比火药危险。
暴饮暴食已经成为比营养不良更糟糕的问题。
过去,战争意味着没有和平。正如尤瓦尔·赫拉利曾经指出的那样,和平意味着暂时没有战争。
“例如,尽管德国和法国在 1913 年处于和平状态,但每个人都知道他们在 1914 年可能会剑拔弩张。每当政治家、将军、商人和普通公民为未来制定计划时,他们总是给战争留有余地。”
然而今天,和平是战争发生的绝对必然性。当首席执行官、政治家和公民制定近期计划时,他们不会将美中战争的可能性纳入计划。随着我们向知识经济转型,主要资产不再是油田和黄金,而是数据和人力资本,战争数量可能会大幅减少。
民主
Source: Our World in Data
媒体和专家正在谈论威权主义的崛起、自由民主的倒退和民粹民族主义的回归。
然而,民主国家的数量一直在稳步增加。1942 年,只有 12 个民主国家。在 1962 年,36 个民主国家。2015 年,有 103 个民主国家。几乎是 60 年前的 10 倍。
根据史蒂芬·平克的数据,2015 年,大约三分之二的世界人口生活在自由或相对自由的国家(1950 年不到五分之二,1900 年不到五分之一,1850 年为百分之七,1816 年为百分之一)。
民主是在无政府状态的混乱和暴政的暴力之间取得不稳定平衡的唯一政府形式。正如卡尔·波普尔指出的,民主不是人民的统治;这是一个无需流血就能推翻糟糕领导的体系。
如果世界变得更加民主,那么这就是进步。
生活和财富
Source: Our World in Data
今天的平均寿命是 72.23 岁,是 100 年前的两倍!
自从工业革命以来,世界财富增加了一百倍。2015 年,大约有 30 万人因营养不良而死亡。与此同时,几乎有 300 万人因为肥胖而灭亡!暴饮暴食已经成为比饥荒更严重的问题。
Source: Our World in Data
“有史以来第一次,死于吃得太多的人多于死于吃得太少的人;死于老年的人比死于传染病的人多;尤瓦尔·赫拉利说:“自杀的人比被士兵、恐怖分子和罪犯杀死的人加起来还要多。”。他接着写道,“对于普通的美国人和欧洲人来说,可口可乐比基地组织构成了更致命的威胁。”
Source: Our World in Data
我们悲观和无知的原因
证据显示世界正在变得更好。然而,正如史蒂夫·丹宁在《福布斯》 中写道,“在英国和美国,大多数人认为”生活在极端贫困中的人口比例增加了!三分之二的美国人甚至认为极端贫困人口的比例“几乎翻了一番”。"
为什么人们对人类取得的进步如此无知?
正如史蒂芬·平克指出的那样,积极和消极的事情在不同的时间线上展开。“坏事可能会很快发生,但好事不是一天建成的,随着它们的展开,它们将与新闻周期不同步。”
新闻是关于发生的事情,而不是没有发生的事情。我们从来没有看到一个记者对着镜头说,“我正在一个没有爆发战争的国家进行现场报道”——或者一个没有被轰炸的城市,或者一所没有被枪击的学校。只要坏事没有从地球上消失,总会有足够多的事件占据新闻,特别是当数十亿部智能手机将世界上大多数人口变成犯罪记者和战地记者时。摘自 s·平克的《现在的启蒙》
媒体不会告诉我们世界在如何变化,它会告诉我们世界在哪里出了问题。福布斯
新闻媒体的受欢迎程度取决于它们娱乐、刺激、震撼或灌输仇恨、享受、自信和恐惧等极端情绪的能力。因此,大多数人不知道人类在过去几十年中取得的进步。
用 Max Roser 的话来说,如果新闻媒体真的报道了世界的变化,他们可能会报道生活在极端贫困中的人数在过去 25 年中每天都减少了 217,000 人。
承认我们过去的成就对于理解我们,人类,如果我们关注相关的事情,我们可以在未来取得更大的进步是必要的。
依靠媒体来形成你的世界观就像只看我的脚的照片来形成你对我的看法一样。汉斯·罗斯林
Source: Our World in Data
天花是人类几个世纪的祸害,仅在 20 世纪就有 3 亿人死于天花(这大约相当于现代俄罗斯、德国、英国和希腊人口的总和),消灭天花的计划仅花费了 3 . 12 亿美元!!!
这还不到美国这种隐形轰炸机(B-2)一个机翼成本的一半。
Source: Wikipedia
美国已经建造了 21 架 B-2。
想象一下,如果我们专注于科学、技术和人类福祉的改善,我们会取得什么样的成就。我们的机会和能力是无限的;我们可以不断拓展我们的理解范围,不断扩大我们对周围世界的了解,并有效地解决全球性挑战。
关注进步的意义不是沾沾自喜,而是找出原因,这样我们就能做更多有效的事情……进步包括尽可能分解社会进程的特征,以最大化人类利益,同时最小化伤害。史蒂芬·平克
过去几十年取得了巨大的进步,我们的主要目的是最大限度地扩大进步带来的好处,同时消除其负面影响。
我们已经做了。我们可以再做一次。我们可以做到的是无限的,利用数据和人工智能放大的人类理性的力量来促进人类的繁荣。
数据:大小不重要…对吧?
原文:https://towardsdatascience.com/data-size-doesnt-matter-right-4f989ab7fbda?source=collection_archive---------21-----------------------
斯堪的纳维亚北部的萨米部落有 180 到 300 种不同的词语来描述雪、雪的种类、雪的痕迹以及雪的用途。侍酒师用几十个不同的词来描述葡萄酒,包括华丽的、松弛的、烘烤的、木炭的和激光似的。同样,数据科学家有许多概念来讨论数据、数据类型和数据的用途。
Photo by Franki Chamaki on Unsplash
我怀疑大多数人认为数据讨论是深奥的。我每天都和痴迷于数据的人在一起,我每天都听到他们抱怨数据。有些事情,所有优秀的数据科学家都知道,普通人类甚至不会怀疑。只是为了好玩,这里有几个金块。
首先,数据是有用途的。对工作有用的数据是信号。不相关的数据就是噪音。有时当任务改变时,噪音变成了信号。反之亦然。然而,并不总是清楚哪些数据是有用的,哪些是无用的。目的可能不清楚。客户或项目经理可能没有解释我们试图实现的目标。也许他们不了解自己,只是在寻找一些模糊定义的“洞察力”
gif from giphy.com
即使目的很明确,一些数据的有用性仍然是有争议的。假设我们试图预测销售点的美元净销售额。销售点的总销售额数据有用吗?前制造商单位销售呢?从 ERP 中提取数据时,通常会有许多不同概念的数据。这是有充分理由的,会计部门需要能够跟踪所有维度,这对他们来说是有意义的。然而,在数据科学的背景下,只有当总销售额与净销售额之比被认为是问题的一个要素时,同时拥有净销售额和总销售额才是有趣的。在许多其他情况下,我们将只使用一个销售术语,例如净销售额,并放弃其他数据维度。
第二,是数据的数量问题。数据科学家喜欢有许多观察结果,这意味着已经观察到相同变量的许多数据点。拥有大量的观察数据让数据科学家的生活更加舒适。算法的选择再也不用想太多了。如果有足够的观察值,任何现成的算法都可以很好地拟合。如果数量巨大,我们快乐的数据科学家就有机会玩 Spark 集群,使用深度学习算法。她的朋友们会嫉妒死的。最好的是,当数据量很大时,算法需要花费大量的时间来训练。这意味着有更多的时间喝咖啡休息和在线阅读博客。的确,拥有大量的数据观测是一件幸事。
第三,这是数据科学家的噩梦:拥有大量数据,但数据的形式多种多样。拥有大量变量会增加虚假相关性和过度拟合的风险。正如纳西姆·塔勒布所说,给他足够多的股票代码,他就能找到一个回报与你的血压精确相关的股票。这就是所谓的维数灾难。有解决这个问题的方法,但它们都有问题。数据科学家可以花时间进行探索性的数据分析,以减少要使用的变量数量。那是艰苦的工作。她可以找到一个更好的模型来适应这种情况,或者调整当前模型的超参数。那也是更多的工作。或者,她可以使用流形方法来减少数据的维数。然而,有许多方法可用。她应该默认 PCA 吗?如何证明这种选择是正确的?更糟糕的是,现在她已经使用了 PCA,她失去了一些模型的可解释性。这个模型变得更加难以想象和解释。事实上,拥有大量的数据变量是一种诅咒。
第四,变量的类型。如果数字变量是数据科学的超级模特,那么二进制变量就是邻家女孩,分类变量就是丑小鸭。数字变量是数字,如 3.14 或 2.7474。关于数值变量的一切都很可爱。我们可能仍然需要扩展和标准化,但这很容易。二进制变量也可以。然而,分类变量是丑陋的。他们需要一些严肃的整形手术才能有用。我们勇敢的数据科学家可以尝试一键编码。这是一种将一个分类变量转换成许多二进制变量的方法,但它增加了变量的总数,这是一个如上所述的诅咒。嵌入是完美的极端改造。然而,说起来容易做起来难。并不总是清楚哪种嵌入方法将提供最好的性能提升,这是额外的工作。
gif from giphy.com
第五,存在数据缺失的问题。假设一个调查回答者跳过了一个问题。我们应该如何处理丢失的数据点?令人愤怒的是,大多数算法根本不能容忍丢失数据。这意味着遗漏的点需要以某种方式猜测和输入。大多数初学者学会在有疑问时使用其他观察值的平均值。在现实世界中,这往往会导致灾难。正态分布变量在教科书中是标准的,但在商界却是奢侈品。如果变量不是正态分布,那么使用平均值可能是错误的。然后呢?中位数,众数?我们是否需要使用另一个模型来学习联合分布,以便输入更好的值?如此多的头痛。为什么客户不能给我们高质量的数据?
你怎么想呢?还有什么是数据科学圈里的常识,却不被别人怀疑的?
数据故事—飞机飞行
原文:https://towardsdatascience.com/data-stories-plane-flights-292b1cce38da?source=collection_archive---------33-----------------------
透过我旅行的棱镜看我的 2019 年(以及那对我说了什么😂
我一直对数据中存在的故事感兴趣,这些数据是我们在生活中创造的。在过去的几个月里,我的朋友 Maxy Lotherington 一直在做一个名为“日常数据 Vis”的媒体系列,她启发并激励我开始通过我产生的数据来审视我的生活。(在这里查看她的文字:*,她的* 表情反应 片段是我最近读过的最喜欢的东西之一)。
如果是 12 月,我会记录下我在 2019 年乘坐的每一次飞机飞行。我的朋友说我从来不在镇上闲逛,在某种程度上,我想知道这有多真实(以及我实际上旅行了多少)。对于那些今天有很多事情的人来说,剧透一下——我确实有点沉迷于旅行,今年我已经累积了很多英里。
A map of all of my travels for the past year — as you can see, I’m a fairly frequent flier along the West Coast of the United States, mainly because I live in Portland, my company headquarters is in the Bay, and I have a ton of family in LA
我追踪到的
我在 2019 年跟踪了我旅行的大量数据:
- 一般信息:预订日期、到达日期(如果不同)、旅行日期、出发时间、到达时间、出发时间、到达时间、预订日期、旅行日期、直达航班?每次旅行的费用,我是否支付了费用,每段路程的费用(如果不同)。
- 计算信息:预订日期和旅行日期之间的天数,旅行之间的时间。
- 机场和航班信息:出发机场、到达机场、飞行持续时间、飞行产生的二氧化碳、飞行里程、航空公司、航班号
我没追踪到的是
- 延误。我找不到关于我的哪个航班被延误的一致的事实来源,所以下面所有的航班都是基于延误永远不会发生的想法(如果你最近坐过飞机,你知道这是错误的,但那是另一天的问题)。
- 我在 2019 年支付的旅行,但将在 2020 年进行。
🌎那么我到底旅行了多少?
很多。不算打车时间、等待登机时间,以及在飞机上度过的其他各种时间,我在 T21 的飞行时间为 95 小时 12 分钟(大约占我一年时间的 1%)
我的端到端里程数出来是39490 英里,查看我的飞行信息显示我产生了 5597.07 公斤的 CO2 ,这是用这个工具计算出来的。(超过 6 吨的二氧化碳,几乎是一个正常人年排放量的 1.5 倍😬)
📅这是不是意味着你从来没回家过?
我的大多数朋友现在都很清楚,如果他们想和我一起做计划,我很有可能不在城里。我在某种程度上对此感到不快,所以我想我应该看看这些数据,看看这到底是真是假。
不幸的是,事实证明他们是对的。在我可能在波特兰度过的 365 天中(我在一个被计入地理位置偏好的地方度过了超过 6 个小时的清醒时间),我在城里度过了 270 天(整整 74%)。换个角度想想,平均每个月我会离开一周。
2019 年 Vivek 的一个普通周六看起来是这样的:醒来,淋浴,吃点东西,去机场(一般来说是 PDX,但我没有歧视),飞行 241.37 英里,寻找新的冒险,家庭时间,或任何激起我兴趣的东西。另一方面,周四平均只有 28.15 英里的空中旅行,这将使我从 PDX 到塞勒姆(俄勒冈州首府)机场的半路上。(在你担心我因为不能在办公室工作而被解雇之前,我花了 2019 年的时间远程工作,所以我可以在周一飞回家😂
平均来说,我的旅行间隔时间是 9 天 8 小时 5 分钟,其中两次旅行间隔时间最长的是 46 天 11 小时 34 分钟,最快的周转时间是 22 小时 30 分钟。
💸那么你一定破产了??
你没有完全错,但你也没有错。由于我非常强大的谷歌航班游戏,以及我注册的航班交易数量,我没有在 2019 年把所有的钱都花在航班上,但我确实在航班上花了 2323.25 美元。(每次飞行大约需要 110.63 美元)。这还不包括我工作支付的机票,或者我使用的礼品卡/旅行信用卡。然而,我并没有节省我的钱包,我在出发前 30 天预订了我的普通航班——如果你把我去新墨西哥州的旅行计算在内,这个数字就下降到 23 天,我提前 3 个月预订了机票。
不过,让我感到惊讶的一件事是,周二实际上不是我预订航班最便宜的日子,事实上我可能会在未来预订周三的航班更好(周一和周六非常低,因为它们主要包括我在欧洲各地的瑞安航空航班,但即使将这些从数据集中剔除,也导致周二的航班比周三更贵)。此外,我莫名其妙地去了 365 天,预订了 23 次旅行,却没有在周四预订任何东西,我也不完全确定是怎么回事。
如果我们根据上面的图表假设预订日没有显著影响机票价格,那么当我们查看航班当天会发生什么呢?我们在这里看到的是,与一周中的其他任何一天相比,我在周六乘坐的航班数量在一定程度上可以解释为比周五的航班便宜多少——记住,我在周五离开之前一周花了 450 美元乘坐往返航班前往欧洲。
🛩:你是说你有很多航空里程?
不幸的是,这也不是真的,是的,我经常坐飞机,这意味着我有很多里程,但我是一个糟糕的品牌忠诚度飞行员——当我预订航班时,我唯一真正的考验是它有多贵,我不会花更多的钱乘坐任何航空公司的飞机(尽管我以前和阿拉斯加航空公司很亲近😍).
TL;速度三角形定位法(dead reckoning)
我在 2019 年飞了很多次,更具体地说,绕地球飞了 1.53 圈,实际上我很少长时间呆在波特兰,但我看到了很多很酷的东西,有趣的人,并有一些很棒的经历,所以总而言之,我会接受它。
我现在要去做二氧化碳抵消捐赠,但如果你想告诉我你有多喜欢(或讨厌)这个,请随时在 LinkedIn 上给我留言。👋
选择最佳机器学习方法的数据结构评估
原文:https://towardsdatascience.com/data-structure-evaluation-to-choose-the-optimal-machine-learning-method-eec66076f97a?source=collection_archive---------18-----------------------
一组关于数据相关性分析如何在解决回归任务时帮助节省时间的示例。
Photo by Spencer Watson on Unsplash
没有单一的 ML 方法。为了选择一个适合您的目的,作为开发人员,您需要了解项目中将使用的数据的性质。在这篇文章中,我将分享我在机器学习系统开发方面的经验,描述选择最佳预测模型的步骤。
我很幸运能够围绕一个正在进行的项目进行研究,这个项目是设计师和建筑师最大的市场,位于 Arcbazar.com。这是一个竞赛平台,它允许需要房屋建造或改造的客户在他们的预算范围内获得想要的建筑设计。虽然它比从设计工作室订购便宜,但在该平台上,客户还可以从来自世界各地的参与者提供的大量设计项目中进行选择。同时,Arcbazar 让任何专业水平的设计师都有机会获得认可,展示他们的创造力,并赢得奖金。
挑战
任务是为市场创建一个人工智能驱动的奖励建议系统,帮助客户决定设计师获奖者的奖项。
对于每个项目,客户可以自由设定不低于最低要求奖励的任何价格。由于所有人都是不同的,我们应该考虑到客户的决定是基于复杂的主观动机:预算、情绪、时间限制、需求、估计、期望等。这意味着机器学习系统应该解决一种社会心理任务。
第一步。数据准备
这个平台有一个大数据库,里面有设计师获奖的已完成的比赛。这个数据库成为机器学习系统的知识来源。数据库结构重复表单中的字段,这些字段必须由客户在开始设计师竞赛之前填写。
这个表单有七个字段:三个下拉菜单、三个文本字段(字符串类型)和一个数字字段(设置截止日期)。在表单的最后一个字段(开始比赛),客户设置奖励价格。
金额是所有项目特征字段的函数,并且以准连续的方式变化。在机器学习理论中,这种类型的任务被称为回归。表单中的字段总数可以表示为一个线性方程:
其中:
- y 是奖励金额;
- a、b、c——是从下拉菜单中表示项目特征的变量;
- d、e、f——是表示文本描述字段的变量;
- g —是代表天数的变量;
- w1..w7 —方程的系数或参数。
通过分析表单字段的数据,我区分了三个类别:
- 结构化下拉菜单(前三个图);
- 非结构化描述字段;
- 数值字段。
下拉列表的值通常有索引。我用这些值索引替换了文本值。为了最大限度地减少计算时间,在开发的第一阶段,我用一个具有字符总数的数字替换了树文本字段。这个假设让我们保留一个更大的数据集。从后验来看,额外的场对模型拟合数据集的方式有一点积极的影响。
转换后的数据集可由一个五变量公式表示:
第二步。选择机器学习方法
在这一步中,我想使用 Python 编程语言的 Scikit-learn 库在一系列实验中找到最佳的机器学习方法。在测试过程中,我改变了 5 个特征数据集的分割比,对于测试子集,分割比从 10%变为 50%。此外,对标准化和非标准化数据进行了所有评估。标准化并没有给模型精度带来明显的提高。
我从预测与对象关联的连续值属性的基本方法开始。这种方法称为线性回归。但是,预测奖励和实际奖励的分布具有决定系数 R 平方= 0.29。在回归中,该系数是回归预测与真实数据点接近程度的统计度量。R 平方为 1 表示回归预测完全符合数据。
回归方法组中的套索回归给出了非常接近线性回归的分布,R 平方为 0.29。
让出一步,我决定使用人工神经网络。多层感知器即使有 500 个隐藏层,在 R 平方= 0.05 的这一系列实验中显示出最弱的结果。
mlpreg = MLPRegressor(hidden_layer_sizes=(500,), activation=’relu’,
solver=’adam’, alpha=0.001, batch_size=’auto’,
learning_rate=’adaptive’, learning_rate_init=0.01,
power_t=0.5, max_iter=1000, shuffle=True, random_state=9,
tol=0.0001, verbose=False, warm_start=False, momentum=0.9,
nesterovs_momentum=True, early_stopping=False,
validation_fraction=0.1, beta_1=0.9, beta_2=0.999,
epsilon=1e-08)
然而,我们的数据集有一个对应于多级下拉列表的结构。这种可视化有助于理解数据集的相互联系。
One client’s choice is a decision tree, many choices — decision forest
当从下拉列表中选择值时,客户从他的“决策树”中的一个分支移动到另一个分支(在图中:级别 1–2–3)。这就是为什么决策树回归给出了更大的 R 平方(0.32)。
决策树回归器的一个更复杂的发展,来自 Sklearn ensembles 的随机森林回归器,给出了 R 平方的最好结果——0.37。
结论
了解跨数据的相互依赖性有助于选择最合适的算法。
决策树和随机森林方法具有相同的基础,比其他方法更接近数据集的本质。
所选数据集中的数据字段集不足以获得更好的拟合。它创建了一个假设,即文本描述字段包含客户在设置奖励时的隐藏动机。
在本文的第 2 部分,我将公开我对使用自然语言处理技术升级预测系统的见解。
用 Python 理解堆的 6 个步骤
原文:https://towardsdatascience.com/data-structure-heap-23d4c78a6962?source=collection_archive---------7-----------------------
搜索算法的重要数据结构
Photo by Rick Mason on Unsplash
今天我将解释堆,它是基本的数据结构之一。还有,著名的搜索算法像 Dijkstra 的算法或者 A都使用堆。A可以出现在常用于时间序列模式识别的隐马尔可夫模型 (HMM)中。请注意,这篇文章不是关于搜索算法的。我将解释堆是如何工作的,以及它的时间复杂度和 Python 实现。麻省理工开放式课程的讲座真的帮助我理解了一堆。所以我遵循了那堂课的解释方式,但我做了一点总结,并添加了一些 Python 实现。这篇文章的结构如下,基于麻省理工学院的讲座。我们开始吧!
- 堆概述
- 表现
- 如何建立一个堆
- 时间复杂度
- 履行
- 堆排序
1.堆概述
堆是优先级队列的的一种常见实现。优先级队列包含具有一定优先级的项目。您总是可以按照优先级顺序从优先级队列中取出一个项目。根据优先级取出项目是很重要的。当你环顾学术会议上的海报展示时,很有可能你是为了挑选一些展示而设置的。或者你会在去观光之前列出一个优先列表(在这种情况下,一个项目将是一个旅游景点。).堆栈和队列也包含项目。如果某个项目是最后一个添加到堆栈中的项目,则可以从堆栈中取出该项目。这是先进后出(费罗)。对于队列,如果一个项目是第一个添加到队列中的项目,您可以从队列中取出该项目。这是先进先出(FIFO)。您可以将这些视为特定类型的优先级队列。这是因为堆栈中插入项的优先级增加,队列中插入项的优先级降低。
2.表现
堆是树结构的一种,用二叉树来表示。我把图像堆在下面。您可以通过指针或数组来实现树结构。在这篇文章中,我选择使用如下的数组实现。就空间复杂性而言,数组实现比指针实现有更多的好处。数组的索引对应于下图中的节点号。
上面的堆叫做一个最小堆,每个节点的值小于或等于子节点的值。 我们称这种情况为堆属性。
在最小堆中,当您查看父节点及其子节点时,父节点总是具有最小值。当一个堆有相反的定义时,我们称它为最大堆。在下面的讨论中,我们称最小堆为堆。
您可以使用以下索引访问数组中的父节点或子节点。
- 根节点| i = 1,数组的第一项
- 一个父节点|parent( i ) = i / 2
- 一个左子节点|left( i ) = 2 i
- 一个右子节点| right(I)= 2I+1
当您查看索引 4 的节点时,树中节点的关系对应于下面数组的索引。
父节点按父( i ) = 4 / 2 = 2 对应索引 2 的项。子节点分别对应索引 8 和 9 的项目,左( i ) = 2 * 2 = 4,右( i ) = 2 * 2 + 1 = 5。
3.如何建立一个堆
从任意数组构建一个堆需要两个操作。
min_heapify
|使某个节点及其后代节点满足堆属性。- 从任意数组中产生一个堆。
我们可以通过对每个节点重复应用 min_heapify 来构建一个堆。
3.1 分钟 _ 健康
在 min_heapify 中,我们用它的子节点交换一些节点来满足下面这两个特性下的堆属性;
- 某些节点及其子节点不满足堆属性,
- 子节点及其后代节点满足属性。
树形结构具有以下两个特征。
看看被橙色方块包围的节点。我们发现 9 比 2 和 3 都大,所以这三个节点不满足堆属性(node 的值应该小于等于其子节点的值)。请检查下面的橙色节点。
然而,看看蓝色的节点。这些节点满足堆属性。
这里我们定义 min_heapify ( 数组,索引)。这个方法有两个参数,数组,和索引。我们假设该方法将数组 [ 索引的节点与其子节点交换,以满足堆属性。
让我们看看 min_heapify 是如何从上面的树形结构中产生一个堆的。首先我们调用min _ heap ify(array,2)将索引 2 的节点与索引 4 的节点交换。
在将min _ heap ify(array,2)应用到子树之后,子树在下面发生变化,并满足堆属性。这个子树是蓝色的。
如果子树将索引 2 的节点与索引 5 的节点交换,子树将不会满足如下所示的堆属性。因此子树与父节点交换子树中具有最小值的节点,以满足堆属性。
回到正确交换的树。当我们看橙色的节点时,这个子树不满足堆属性。
所以调用min _ heap ify(array,4)使子树满足堆属性。
现在,这个子树通过将索引 4 的节点与索引 8 的节点交换来满足堆属性。
上面的这些操作从无序的树(数组)中产生堆。
3.2 构建 _ 最小 _ 堆
下面的伪代码代表了 build_min_heap 是如何工作的。
build_min_heap(array)
for i=n/2 downto 1
do min_heapify(array, i)
该函数使用 for 循环迭代除叶节点之外的节点,并将 min_heapify 应用于每个节点。我们不需要将 min_heapify 应用于 n /2+1 之后的索引项,它们都是叶子节点。我们在下面的橙色节点中应用了 min_heapify。
每个节点在满足能够应用 min_heapfiy 的条件下可以满足堆属性。这是因为该函数从底部(倒数第二层)到顶部(根节点层)迭代节点。例如,该函数首先将 min_heapify 应用于索引 4 和索引 5 的节点,然后将 min_heapify 应用于索引 2 的节点。因此,当应用 min_heapify 时,索引的节点及其后代节点满足堆属性。
4.时间复杂度
我们来考虑一下 build_min_heap 的时间复杂度。首先我们认为 min_heapify 的时间复杂度,它是 build_min_heap 的一个主要部分。
min_heapify 重复交换数组中项目的操作,该操作以固定时间运行。因此 min_heapify 的时间复杂度将与重复次数成正比。在最坏的情况下, min_heapify 应该重复操作树的高度倍。这是因为在最坏的情况下,min_heapify 会用最深的叶子节点交换根节点。假设 h 为根节点的高度, min_heapify 的时间复杂度将需要 O ( h )的时间。
min_heapify 在各深度的时间复杂度如下所示。节点的数量也显示在右侧。
从图中可以看出 build_min_heap 的时间复杂度将是内部节点的时间复杂度之和。最终的时间复杂度变成:
所以我们应该知道树的高度来得到时间复杂度。
每个深度的节点数之和会变成 n 。所以我们会得到下面这个等式。
上面的等式代表几何序列,所以我们可以变形它,得到树的高度如下:
最后我们得到 O ( n )作为 build_min_heap 的时间复杂度。同样,我们得到 O (log n )作为 min_heapify 的时间复杂度。
5.履行
这里我们用 Python 实现了 min_heapify 和 build_min_heap 。 min_heapify 实现如下。
def min_heapify(array, i):
left = 2 * i + 1
right = 2 * i + 2
length = len(array) - 1
smallest = i if left <= length and array[i] > array[left]:
smallest = left
if right <= length and array[smallest] > array[right]:
smallest = right
if smallest != i:
array[i], array[smallest] = array[smallest], array[i]
min_heapify(array, smallest)
首先,该方法计算索引为 i 的节点及其子节点中值最小的节点,然后将值最小的节点与索引为 i 的节点进行交换。当交换发生时,该方法将 min_heapify 应用于被交换的节点。
Python 中一个列表(一个数组)的索引从 0 开始,访问节点的方式会有如下变化。
- 根节点| i = 0
- 父节点|父节点( i ) = ( i -1) / 2
- 左子节点| left(I)= 2I+1
- 右子节点| right(I)= 2I+2
变量最小具有最小值节点的索引。如果最小的不等于 i ,这意味着该子树不满足堆属性,该方法交换节点并对最小的的节点执行 min_heapify 。
build_min_heap 的实现和伪代码差不多。
def build_min_heap(array):
for i in reversed(range(len(array)//2)):
min_heapify(array, i)
for 循环不同于伪代码,但行为是相同的。这个 for 循环还从倒数第二层节点到根节点迭代节点。
6.堆排序
Heapsort 是一种使用堆的排序算法。用 min_heapify 和 build_min_heap 真的很容易实现。分拣流程如下。请注意,排序的顺序是升序。
- 用 build_min_heap 从任意数组构建一个堆。
- 将数组中的第一项与最后一项交换。
- 从数组中移除最后一项。
- 运行 min_heapify 到第一项。
- 回到步骤 2。
在堆中,最小的项是数组的第一项。步骤 3 之后的数组满足应用 min_heapify 的条件,因为我们在将第一项与最后一项交换之后移除了最后一项。根据这一特性,我们可以通过重复步骤 2 到 4 对数组进行排序。
heapsort 实现将如下所示。
def heapsort(array):
array = array.copy()
build_min_heap(array) sorted_array = []
for _ in range(len(array)):
array[0], array[-1] = array[-1], array[0]
sorted_array.append(array.pop())
min_heapify(array, 0) return sorted_array
heapsort 的时间复杂度是O(nlogn因为在最坏的情况下,我们要重复 min_heapify 数组次数中的项数,也就是 n 。
在 Python 的heapq 模块中,已经实现了对堆的一些操作。我遵循了麻省理工学院讲座中的方法,实现与 Python 不同。如果你想知道 Python 的具体实现,请访问这里的源代码。例如,这些方法是用 Python 实现的。
heapq.heapify
|对应 build_min_heapheapq.heapop
|对应交换项目,移除最后一个项目, min_heapify 立刻。
通过使用上述方法,我们可以实现如下的堆排序。请注意,它与官方文件中的heap sort 的实现不同。
import heapqdef heapsort(array):
h = array.copy()
heapq.heapify(h)
return [heapq.heappop(h) for _ in range(len(array))]
所以这个帖子到此为止。感谢您的阅读!
参考
- 麻省理工学院开放课件 4。堆和堆排序
数据:深度学习时代的困境与机遇
原文:https://towardsdatascience.com/data-the-predicament-and-opportunity-in-the-deep-learning-era-256f4b4fef?source=collection_archive---------24-----------------------
介绍
随着深度学习已经渗透到几乎每一个学术学科,并催生了无数的初创企业和新的工业应用,很多人可能会问:所谓的“深度学习”的极限在哪里,深度学习的未来会是什么样子?而下面是我个人的回答:数据。
正如我们所知,深度学习的兴起有三个支柱:强大的计算能力、大模型容量和大数据。然而,随着计算能力和模型容量的稳步增长,最大数据集的大小似乎保持不变。
[1]
这主要是由于标注足够大、足够多样且足够干净(即具有高标签质量)的数据集的高成本和难度。此外,还有一些标注成本极高的任务,比如医学。这也为域数据集的快速增长设置了限制。
然而,在传统的(强)监督学习设置中,训练一个具有足够好性能的模型需要大量的标记数据。这让我们陷入了数据匮乏的困境。
在我看来,主要有三个方向可以解决数据匮乏的困境:
- 充分利用给定的数据集:更好的数据采样策略[2],更大的模型容量[3]…
- 放大标注数据集量:数据标注;
- 利用更多的知识:自我监督学习/预训练,弱监督学习/预训练,迁移学习(预训练)。
Modified from Stanford AI lab blog pic
正如你将看到的,它们中的许多与其他的交织在一起。虽然强(传统)监督学习仍然是主流,但在不久的将来,所有方法都将变得越来越重要。在这篇文章中,我将简要概述这些方法,并对更有前途的方向提供一些我的看法。
明智地使用数据
这种类型的方法并不试图增加数据集的大小,而是试图充分利用我们已经拥有的数据。我不会对此进行太详细的描述,因为一般来说,几乎所有当前的论文都属于这一类别:模型架构的改进、损失设计、优化算法……这些都是试图充分利用给定数据集的各种努力——提取其中的所有知识,并学习良好的表示或模型。
From [4]
然而,有一个有趣的研究方向,旨在“在数据集层面”更好地利用数据集。也就是说,他们试图使用不同的数据采样策略来帮助训练一个更少偏差、更稳健的模型。例如,[2] [4]试图处理数据集的长尾分布,这是现实世界分布的一种典型形式。这些方法通常采用不同的再平衡策略,例如基于每个类别的观察值数量或特征空间几何形状(例如,聚类结果)的再采样和再加权。
在许多数据集固定的实际应用程序中,这种类型的方法是可以帮助您解决问题的唯一且最适用的方法。
扩大数据集大小
当我们想要在一个新的应用场景中训练一个模型时,总是不可避免地要先构造一个带标签的数据集;当我们无法获得满意的结果时,最直接的方法就是扩大标记数据集的大小。为了构建或扩大带标签的数据集,我们需要数据标注。
自从机器学习的引入,数据标注就出现了。多年来,各种大型数据集被构建:Pascal-VOC[5],ImageNet[6],LSUN[7],COCO[8],mega face[9]…许多在线注释服务也是可用的,如 LabelMe ,supervisor . ly等,尽管它们通常不节省成本。同时,也有许多新的数据注释方法被提出[10][11][12]。这些最新的方法通常将机器作为注释的一部分,或者使用它来自动化注释的一部分,或者帮助人类注释者。这些方法不仅大大加速了标注过程(实例分割速度提高了 3-6 倍[10][12]),而且还提高了传统标注的质量。
然而,尽管数据标注方法取得了很大进展,但目前还没有对其进行系统的学习或研究,也没有可靠的基准。这使得不同的数据标注方法难以相互比较,也使得研究者无法系统地研究如何改进数据标注方法。我将在下一篇文章中讨论更多,因为这是我们正在努力做的。
扩大数据集的另一个方向是用较低质量或较高抽象级别的数据进行标注——弱标注。例如见下图。对于像素级实例分割的任务,有三个较低级别的注释可能也有帮助:人级别、点级别和边界框级别。较低级别的注释节省了大量时间。换句话说,给定相同的预算,我们可能希望获得更多的低层次注释数据,并获得更好的最终结果。然而,这种直觉仍然需要一个评估标准或基准来阐明。
利用更多的知识
这是一个活跃的研究领域,每天都有新的有趣的方法被开发出来。实际上来说,迁移学习已经证明了它在计算机视觉和自然语言处理中的重要性,因为现在不使用 ImageNet 或类似 BERT 的预训练模型听起来有些鲁莽[13]。优势是显而易见的:你用更少的数据训练得更快。例如,在 ULMFit[14]中,作者发现预训练可以节省达到相同性能所需的大约 10 倍的数据。
然而,仍然有许多问题是目标语言无法解决的,如细粒度分类、自然语言生成等。此外,当适应的数据集规模较大时,迁移学习的好处变得小得多[14]。毕竟,在一个新的应用环境中,迁移学习是不适用的。然而,考虑到它的简单性和实用性,迁移学习无疑是利用其他数据源知识的最常用方法。
也有一些研究人员旨在利用大量未标记的数据集。半监督学习是一个非常活跃的领域。其思想是使用结构假设(聚类假设和流形假设)来自动利用未标记的数据。在最近的一篇文章[15]中,作者表明半监督学习有可能取代监督学习,并大大减少需要完全注释的数据量。
The hope of the future of semi-supervised learning [15]
然而,目前,在 SSL 实用化之前仍然存在一些挑战。第一个是未标记数据的不可控偏差,这将在[16]的第 4 节中详细讨论。另一个问题是 SSL 深受类别分布不匹配之苦,有标签和无标签的数据应该有相同的标签空间,否则准确率会大大下降。这极大地限制了 SSL 的使用范围。此外,据报道[17]在许多设置中,在不同的标记数据集上预训练分类器,然后仅在感兴趣的数据集的标记数据上重新训练,可以胜过所有 SSL 算法。这意味着 SSL 方法要变得实用还有很长的路要走。
另一种试图利用未标记数据集的方法叫做自我监督学习。其核心思想是在没有明确的人工监督的情况下,从数据本身学习表示。它与 SSL 的不同之处在于,它不需要标记数据,而是使用各种假设来创建监管信号[18][19]。在[18]中,作者表明,通过扩大预训练数据、模型容量和问题复杂性,人们可以在很大程度上匹配甚至超过监督预训练在各种任务上的性能,例如对象检测、表面法线估计(3D)和使用强化学习的视觉导航。这表明自我监督学习是一个很有前途的研究方向。然而,在图像分类和低镜头分类任务中,监督预训练模型仍然是更好的。从作者的角度来看,当前的自我监督方法不够“硬”,不足以充分利用大规模数据,并且似乎没有学习有效的高级语义表示。
From [18]
自我监督学习的另一个缺点是,它比其他形式的训练需要更多的领域知识,因为它需要专家来设计自我监督的方式,这可能因任务而异。这似乎让我们离真正的智能学习形式越来越远。
最后,我想讨论一下弱监督学习【20】【21】和预训练【22】。如前所述,在某些情况下,微弱的监控信号也能产生良好的效果。数据集的大尺寸似乎可以补偿噪声或其标签的低质量。另一个优势是,可以设计标记函数并自动获得大量弱监督数据,尽管这类似于自我监督方法的方式——使用领域专业知识来设计自己的规则!即使没有完全自动化,弱监督的数据注释也可以节省大量时间,这可以转化为更大量的弱标记数据,并可能有利于前面提到的最终性能。
然而,像自监督学习一样,设计弱监督学习及其标注算法需要大量的领域专业知识。此外,该方法本身仍然需要在更实际的任务中证明其有效性,特别是在噪声/低质量/抽象如何影响性能,以及数据集的大小可以足够大方面,尽管它们在[22]的分类设置中有部分讨论。
From [22]
弱监督预训练并不是什么新东西,而是在其他任务中使用弱监督预训练模型。在图像分类和对象检测中,利用这种思想的模型已经显示出超过监督预训练的 ImageNet 模型[22]。可以预期,在不久的将来,这个领域的研究,连同相应的数据标注研究,将会腾飞。
结论
在本帖中,我们将讨论解决数据匮乏困境的不同方法。对于每种方法,我们讨论了它的优点和缺点,并介绍了一些最近的研究和讨论。
虽然最后一部分中的算法和方法听起来可能更吸引人,但从实际的角度来看,数据注释,无论是强还是弱,都是大多数情况下最有效的解决方案。并且数据注释基准的引入和数据注释方法的开发可以将成本降低到可负担的规模,以便很快注释非常大的数据集。因此,我认为,在不久的将来,社区要做的最重要的事情是在数据注释研究以及如何利用不同监管级别中注释的数据集方面投入更多精力。
要有数据!
参考资料:
[1]孙辰、阿比纳夫·什里瓦斯塔瓦、绍拉布·辛格和阿比纳夫·古普塔,重新审视深度学习时代数据的不合理有效性
[2]基于有效样本数的类别平衡损失
[3]用于图像识别的深度残差学习
[4]小张,,严东文,,于乔,程损为深度人脸识别用的长尾
http://host.robots.ox.ac.uk/pascal/VOC/
http://www.image-net.org/
https://www.yf.io/p/lsun
http://cocodataset.org/#home
[9]http://megaface.cs.washington.edu/
[10]Rodrigo Benenson,Stefan Popov,Vittorio Ferrari,使用人类注释器的大规模交互式对象分割
[11]Olga Russakovsky,李-,,两全其美:
面向对象标注的人机协作
[12]大卫·阿库纳、黄玲、阿姆兰·卡尔、桑佳·菲德勒,“用多边形有效标注分割数据集——RNN ++
[13] NLP 的 ImageNet 时刻已经到来http://ruder.io/nlp-imagenet/
[14]杰瑞米·霍华德,塞巴斯蒂安·鲁德,用于文本分类的通用语言模型微调
[15]安静的半监督革命https://towards data science . com/The-Quiet-Semi-Supervised-Revolution-edec 1 e 9 ad 8c
[16]半监督学习,Olivier Chapelle,Bernhard schlkopf 和 Alexander Zien,麻省理工学院出版社
[17] Avital Oliver,Augustus Odena,Colin Raffel,Ekin D. Cubuk & Ian J. Goodfellow,深度半监督学习算法的现实评估
[18] Priya Goyal,Dhruv Mahajan,Abhinav Gupta,Ishan Misra,自我监督视觉表征学习的标度和基准
[19]亚历山大·科列斯尼科夫,翟晓华,卢卡斯·拜尔,再论自我监督的视觉表征学习
[20]Armand Joulin,Laurens van der Maaten,Allan Jabri,Nicolas Vasilach,来自大量弱监督数据的电子学习视觉特征
[21]阿历克斯·拉特纳、帕罗马·瓦尔马、布雷登·汉考克、克里斯·雷和哈兹实验室的其他成员,弱监督:机器学习的新编程范例https://ai.stanford.edu/blog/weak-supervision/
[22]Dhruv Mahajan,Ross Girshick,Vignesh Ramanathan,,Manohar Paluri,,Ashwin Bharambe,Laurens van der Maaten,探索弱监督预审的局限性
AI/ML 项目中的数据翻译周期
原文:https://towardsdatascience.com/data-translation-cycles-in-ai-ml-projects-2ff4445802cd?source=collection_archive---------25-----------------------
Photo by ev on Unsplash
在 AI/ML 项目中从潜在有价值的数据到有益信息的转换
越来越多的工程师面临着人工智能(AI)和机器学习(ML)相关项目数量的增加。许多人工智能/人工智能项目似乎是面向算法的,但是开发人工智能/人工智能产品的每个过程都是以任何涉及数据的过程为中心的。AI/ML 项目中的工程师需要更多地了解如何在 AI/ML 项目中创建和使用数据。这篇文章可能会帮助初级/中级工程师或数据科学家理解为 AI/ML 产品准备的数据本身。
什么是数据?
定义引自网络词典,因为更新周期比纸质资料快。数据基于信息,因此信息的定义也在下面描述。
信息是一种刺激,在某种语境下对接受者有意义。当信息被输入并存储在计算机中时,它通常被称为数据。经过处理(如格式化和打印)后,输出数据可以再次被视为信息。
数据本身的定义就在这里。
在计算中,数据是已经被转换成高效移动或处理形式的信息。相对于今天的计算机和传输介质,数据是信息转换成二进制数字形式。数据可以用作单数主语或复数主语。原始数据是一个术语,用于描述最基本的数字格式的数据。
这两种定义的含义可以绘制成如图 1 所示的图片。作为人类的接收者在我们周围的环境中感知信息,测量信息,并将其转化为定性/定量信息,以便容易地识别信息的含义。可以容易地被计算机识别的接收信息被处理,具有新见解的新信息被创建,并被传递到接收器。
Figure 1 created by Jesse Tetsuya
接收者的翻译测量
将信息转化为数据的测量类型可以是下图 2 中的灰色方框。
Figure 2 created by Jesse Tetsuya
分类数据是定性数据,由名义数据和序数数据组成。为了将这样的数据传递给代码并使用数据进行分析,必须将分类数据转换成数字,如二进制数据或任意编号标签。
另一方面,数字数据是定量数据,由离散和/或连续数字组成。离散数字包括可计数的数字,如学生人数,它可以等于名义或顺序数据的计数输出。连号分为两种:区间刻度和比例刻度。两者的区别在于数据是否有“真零”和数字有无减号。严格来说,连续变量的规模不是根据数字有无负号来决定的,但是度量的方式很容易理解。
描述数据的三种方式
描述数据的三种方式是 1)数据结构,2)数据类型,3)数据格式(=文件格式)。本节将根据常用的 python 语法对它们进行简单总结。不包括不常用的 python 语法信息。
1.数据结构
- 列表/字典/序列/元组/集合(示例如下)
列表和词典
**>>>** tel = {'jack': 4098, 'sape': 4139}
**>>>** tel['guido'] = 4127
**>>>** tel
{'jack': 4098, 'sape': 4139, 'guido': 4127}
**>>>** tel['jack']
4098
**>>> del** tel['sape']
**>>>** tel['irv'] = 4127
**>>>** tel
{'jack': 4098, 'guido': 4127, 'irv': 4127}
**>>>** list(tel)
['jack', 'guido', 'irv'
序列和元组
**Sequences
>>>** t = 12345, 54321, 'hello!'
**>>>** t[0]
12345**Tuples
>>>** t
(12345, 54321, 'hello!')
**>>>** *# Tuples may be nested:*
**...** u = t, (1, 2, 3, 4, 5)
**>>>** u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
**>>>** *# Tuples are immutable:*
**...** t[0] = 88888
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
**>>>** *# but they can contain mutable objects:*
**...** v = ([1, 2, 3], [3, 2, 1])
**>>>** v
([1, 2, 3], [3, 2, 1])
设置
**>>>** basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
**>>>** print(basket) *# show that duplicates have been removed*
{'orange', 'banana', 'pear', 'apple'}
**>>>** 'orange' **in** basket *# fast membership testing*
True
**>>>** 'crabgrass' **in** basket
False
2。数据类型
- 字符串/整数/浮点/布尔
3.数据格式
- 数据存储/RDBS/CSV/JSON/Excel/HTML/Text/Image
将数据转化为有价值信息的过程
在 AI/ML 项目的情况下,工作流可以描述为如图 3 所示。
Figure 3 created by Jesse Tetsuya
首先,根据上一节提到的数据转换测量收集并格式化输入数据。输入的数据可以是 RDBS、CSV、JSON、Excel、HTML、文本、图片等。如前一节所述。
之后,这些输入数据被导入机器学习 API。机器学习 API 通常由与相关的三个程序代码组成,即访问数据的准备代码、预处理数据和机器学习算法。在将数据传递到机器学习模型之前,需要根据算法对数据结构和数据类型进行不同的操作和处理。
最后,对于人类来说没有明确表示有价值意义的输入数据通过图 3 所示的机器学习 API 被转换成有价值的信息。然后,它作为有用的信息被人类接收。
参考
[## 什么是信息?-WhatIs.com 的定义
信息是一种刺激,在某种语境下对接受者有意义。当信息被输入和存储时…
searchsqlserver.techtarget.com](https://searchsqlserver.techtarget.com/definition/information) [## 什么是数据?-WhatIs.com 的定义
在计算中,数据是指已经被转换成可有效移动或处理的形式的信息…
searchdatamanagement.techtarget.com](https://searchdatamanagement.techtarget.com/definition/data)
数据科学的数据类型
原文:https://towardsdatascience.com/data-types-for-data-sciences-65dcbda6177c?source=collection_archive---------4-----------------------
大数据和数据科学现在在每个人的脑海里。但并不是每个人都清楚地知道并非所有的数据都是相同的,并对数据科学中可用的应用程序和技术类型有清晰的认识。数据科学、人工智能和机器学习通常被认为是相当等同的。为了理解所有数据科学技术并不等同,理解并非所有数据都是相同的是至关重要的。
这张幻灯片是我这个月在巴黎大数据公司演讲的主要幻灯片。
这种会议充满了多年来为公司创造软件来更好地管理他们的数据以便更好地管理他们的业务的人。当谈到人工智能或机器学习这两个当今重要的时髦词汇时,我觉得有些混淆,似乎它们都或多或少被视为等同。我希望澄清,不同类型的数据存在,有不同的需求,这可能受益于不同类型的科学。
流行语。
大数据。随着数据量的显著增长,我们现在谈论大数据。
数据科学。我们不希望只是管理数据,存储数据,并将其从一个地方移动到另一个地方,我们希望使用数据,并利用科学方法围绕数据做出巧妙的事情。这就是数据科学。简而言之,数据科学“利用科学的方法、流程、算法和系统,从各种形式的数据中提取知识和洞见”。这是明确的定义,有不同类型的方法、流程和算法。
机器学习。机器学习是最适合大量数据的数据科学技术之一,因为它使用数据来提取知识。其他数据科学技术,如决策优化,由于是基于领域知识,因此不太消耗数据。只有一个数据集和一个业务问题的公式,您就可以开始使用决策优化。另一方面,机器学习沉迷于数据。更多的数据,更多的学习,更好的结果。
人工智能。这似乎是新的最重要的流行语,但实际上这是纯粹的复古。根据维基百科,这仅仅是“机器展示的智能”。机器像人一样聪明的想法已经存在多年了。我们现在更加谦虚,认为人工智能是机器代替人类自动化非物理过程所做的任何事情(事实上,我们也降低了对人类智能的期望)。我们中的一些人多年来一直在做某种人工智能,进行规则自动化或决策优化。
人工智能炒作的好处是,我的孩子现在认为我有一份有趣的工作,而他们多年来认为我的工作只是无聊的数学。
数据类型
在看哪种科学对一个问题有益之前,我需要看一下涉及哪些类型的数据。让我们回顾一下我强调的四种类型。
我将使用典型的和众所周知的供应链问题的例子来说明,其中我想计划在我的工厂生产多少产品,在我的仓库储存多少,以及向我的商店交付多少。
已知数据
首先是我所说的“已知数据”。这是我确信的数据,或者至少我可以认为是已知的。
在供应链运作问题中,给定链的拓扑结构,已知不同节点的生产和存储能力。顾客想要购买多少商品是未知的数据。竞争将使用什么价格是未知的数据。我想生产和储存多少产品是未知的数据。
已知数据的领域对应于描述性分析。我将从操作系统中提取这些数据,我将组织它,我将探索它,我将显示它。
这些数据非常有价值。如果我不知道我的生产工厂或仓库的属性,我就不能做任何认真的计划。并不是所有的数据都是“有价值的”,这是“好数据”的概念,也不是“数据越多越好”。如果数据没有结构化,它将更难使用。所以好的数据是有价值的,我们可以购买。并非所有的数据都是开源的,获取和转售好的数据是一项伟大的事业。
未知数据
我们可以在已知数据中找到的结构实际上是附加数据。这是我们最初不知道的数据,我们可以从已知的数据中提取。我们可以分类,我们可以构造,我们可以预测。
在我的供应链例子中,基于大量已知的历史数据,我可能预测下个月我的不同商店或市场会有多少需求。
这是预测分析的领域。
如前所述,这个区域由已知数据提供信息。预测和分类不是来自水晶球,而是从历史数据中推断出来的。没有已知数据,就无法提取任何未知数据。预测就像一个额外的维度,你无法从你的已知数据中看到,但它已经存在,你可以用某种特定的眼镜看到。
预测将取决于你所拥有的已知数据的质量和种类。这就是大家都在说的偏差问题。
他人的决定
下一个数据区域是其他人将要设置的数据。
在我的供应链例子中,一个重要的数据集与竞争有关:我的竞争对手将在哪里销售什么,以什么价格销售,这是他们的决定,不是我的。
在某些情况下,与前面的区域有一些重叠。在市场上做出决策时,如果市场具有某些特征,我们可以预期结果将遵循预测模型可以提取的趋势。但在其他一些情况下,这可能真的是某人的个人决定,他可能有一个策略并做出不可预测的决定。例如,一个竞争对手可以决定下个月开一家有特价的新店。这将严重影响我的销售计划。
虽然新闻中充斥着专注于人工智能的公司的故事,让计算机在游戏中玩游戏并战胜人类,但在我看来,这个领域在实践中并不是最重要的,存在工业、运输、供应链、生产等问题。
大多数情况下,博弈都是基于多步博弈。如果没有多个步骤,使用不可预测的策略是没有意义的。如果我做了一些不同的事情,这是因为我希望用对手无法预测的事情来迷惑他,或者让他以某种方式做出反应。这是博弈论的领域。如果我考虑的是一般的对手,那么我会考虑对手的可预测的反应,当然我会使用可预测的策略,因此这属于前面的领域。
你的决定
最后,还有一组与您的决策相对应的数据。
我根据自己的原则和目标做出决定。
这是规定性分析的领域。
以我的供应链为例,除了我想设定的价格之外,我将决定我想在我的工厂生产多少,我想在我的仓库储存多少,我想向我的商店交付多少。
有不同的方法来做决定,虽然机器学习在某些情况下可以非常强大地规定要做什么,但这个领域仍然是决策优化的王国。
通过决策优化,一个数学引擎被输入我的业务描述(规则和目标),以及一个特定的案例(我的系统的当前情况,对未知数据的一些预测),该引擎将推导出对我来说什么是最优的决策集。决策优化是一种基于知识的技术。
请注意,在实践中,现实生活中的问题确实包括来自所有这些类别的数据,但是虽然已知数据总是数据的一个非常重要的部分,但是其他类别的数据量可能会因问题而异。这就是为什么清楚地理解这些类型的数据非常重要,以便能够选择使用哪种类型的数据科学技术。
数据科学的类型
我强调的每一个领域都不完全符合数据科学中的一种技术。这些区域对应于我们想要对数据执行的处理类型,它们对应于意图。在这里,我主要关注我认为更重要的两个问题,也是更容易混淆的地方:
一方面,未知数据的区域对应于预测分析,其中意图是从已知数据预测未知信息(数据或数据结构),并且存在不同的技术,从使用回归技术的众所周知的预测模型,到最近的机器学习和神经网络。
另一方面,我的决策的区域对应于规定性分析。同样,这并不仅仅与一种数据科学技术相关,而是与一个目的相关:规定针对当前情况采取的下一个最佳行动。
在某些情况下,机器学习可能是最好的技术,但在大多数情况下,决策优化(过去称为运筹学或数学规划)在技术上仍是该领域的主导者。这是因为决策优化对日常决策有着直接的影响:它告诉你在面对成千上万种可能性的选择时该怎么做。它是你决策的专家顾问。今天的报纸对此报道不多。
在另一篇文章中,我用一个常见的日常场景来介绍不同的现有技术。
结论
所以我的结论是,我们要小心,不要把数据和数据科学直接和人工智能、机器学习联系起来。
当我们面对一个包含大量数据的复杂问题时,需要考虑不同类型的数据。对于不同类型的数据,我们可能希望执行不同的操作,尽管我们希望应用人工智能和数据科学,但我们应该考虑不同类型的数据科学和不同的技术,使用最适合数据和我们考虑的意图的技术。
对于复杂的问题,涉及到两到三种类型的数据,我们可能需要使用和组合两到三种不同类型的数据科学技术。这就是为什么像 Watson Studio 这样的平台可以提供不同类型的工具,包括决策优化,来帮助你处理这些问题。
参见这篇文章,了解决策优化如何集成到 Watson Studio 中。
试试 IBM Watson Studio 。
【alain.chabrier@ibm.com 号
【https://www.linkedin.com/in/alain-chabrier-5430656/
@AlainChabrier
R 中的数据类型
原文:https://towardsdatascience.com/data-types-in-r-8124c3b2afe6?source=collection_archive---------34-----------------------
了解 R 中最常见的数据类型
Photo by Luke Chesser
介绍
T 这篇文章展示了 r 中不同的数据类型。要从统计学的角度了解不同的变量类型,请阅读“变量类型和示例”。
R 中存在哪些数据类型?
R 中有 6 种最常见的数据类型:
- 数字的
- 整数
- 复杂的
- 性格;角色;字母
- 因素
- 逻辑学的
R 中的数据集通常是这 6 种不同数据类型的组合。下面我们将逐一探讨每种数据类型的更多细节,除了“复杂”数据类型,因为我们关注的是主要的数据类型,这种数据类型在实践中很少使用。
数字的
R 中最常见的数据类型是数字。如果值是数字或者值包含小数,则变量或序列将存储为数字数据。例如,默认情况下,以下两个系列存储为数字:
# numeric series without decimals
num_data <- c(3, 7, 2)
num_data## [1] 3 7 2class(num_data)## [1] "numeric"# numeric series with decimals
num_data_dec <- c(3.4, 7.1, 2.9)
num_data_dec## [1] 3.4 7.1 2.9class(num_data_dec)## [1] "numeric"# also possible to check the class thanks to str()
str(num_data_dec)## num [1:3] 3.4 7.1 2.9
换句话说,如果你给 R 中的一个对象分配一个或几个数字,默认情况下它将存储为数字(带小数的数字),除非另外指定。
整数
整数数据类型实际上是数值数据的一种特殊情况。整数是没有小数的数字数据。如果您确定您存储的数字永远不会包含小数,则可以使用此选项。例如,假设您对 10 个家庭样本中的孩子数量感兴趣。该变量是一个离散变量(如果您不记得什么是离散变量,请参见变量类型的提示),并且永远不会有小数。因此,由于使用了as.integer()
命令,它可以存储为整数数据:
children## [1] 1 3 2 2 4 4 1 1 1 4children <- as.integer(children)
class(children)## [1] "integer"
请注意,如果您的变量没有小数,R 会自动将类型设置为整数而不是数字。
性格;角色;字母
存储文本时使用数据类型字符,在 r 中称为字符串。在字符格式下存储数据的最简单方法是在文本段周围使用""
:
char <- "some text"
char## [1] "some text"class(char)## [1] "character"
如果您想强制将任何类型的数据存储为字符,您可以使用命令as.character()
来完成:
char2 <- as.character(children)
char2## [1] "1" "3" "2" "2" "4" "4" "1" "1" "1" "4"class(char2)## [1] "character"
注意""
里面的一切都会被认为是字符,不管看起来像不像字符。例如:
chars <- c("7.42")
chars## [1] "7.42"class(chars)## [1] "character"
此外,只要变量或向量中至少有一个字符值,整个变量或向量都将被视为字符:
char_num <- c("text", 1, 3.72, 4)
char_num## [1] "text" "1" "3.72" "4"class(char_num)## [1] "character"
最后但同样重要的是,虽然空格在数字数据中无关紧要,但在字符数据中却很重要:
num_space <- c(1)
num_nospace <- c(1)
# is num_space equal to num_nospace?
num_space == num_nospace## [1] TRUEchar_space <- "text "
char_nospace <- "text"
# is char_space equal to char_nospace?
char_space == char_nospace## [1] FALSE
从上面的结果可以看出,字符数据中的一个空格(即在""
中)使它成为 R!
因素
因子变量是字符变量的特例,因为它也包含文本。但是,当唯一字符串的数量有限时,会使用因子变量。它通常代表一个分类变量。例如,性别通常只有两个值,“女性”或“男性”(将被视为一个因素变量),而名字通常有很多可能性(因此将被视为一个字符变量)。要创建因子变量,使用factor()
功能:
gender <- factor(c("female", "female", "male", "female", "male"))
gender## [1] female female male female male
## Levels: female male
要了解因子变量的不同级别,使用levels()
:
levels(gender)## [1] "female" "male"
默认情况下,级别按字母顺序排序。您可以使用factor()
函数中的参数levels
对等级重新排序:
gender <- factor(gender, levels = c("male", "female"))
levels(gender)## [1] "male" "female"
字符串可以用as.factor()
转换成因子:
text <- c("test1", "test2", "test1", "test1") # create a character vector
class(text) # to know the class## [1] "character"text_factor <- as.factor(text) # transform to factor
class(text_factor) # recheck the class## [1] "factor"
字符串已经被转换为因子,如其类型为factor
的类所示。
逻辑学的
逻辑变量是只有两个值的变量;TRUE
或FALSE
:
value1 <- 7
value2 <- 9# is value1 greater than value2?
greater <- value1 > value2
greater## [1] FALSEclass(greater)## [1] "logical"# is value1 less than or equal to value2?
less <- value1 <= value2
less## [1] TRUEclass(less)## [1] "logical"
也可以将逻辑数据转换成数字数据。使用as.numeric()
命令从逻辑转换为数字后,FALSE
值等于 0,TRUE
值等于 1:
greater_num <- as.numeric(greater)
sum(greater)## [1] 0less_num <- as.numeric(less)
sum(less)## [1] 1
相反,数字数据可以转换为逻辑数据,所有值的FALSE
等于 0,所有其他值的TRUE
。
x <- 0
as.logical(x)## [1] FALSEy <- 5
as.logical(y)## [1] TRUE
感谢阅读。我希望这篇文章能帮助你理解 R 中的基本数据类型及其特殊性。如果您想从统计学的角度了解更多关于不同变量类型的信息,请阅读文章“变量类型和示例”。
和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。
相关文章:
- 安装和加载 R 包的有效方法
- 我的数据符合正态分布吗?关于最广泛使用的分布以及如何检验 R 中的正态性的注释
- R 中的 Fisher 精确检验:小样本的独立性检验
- R 中独立性的卡方检验
- 如何在简历中创建时间线
原载于 2019 年 12 月 30 日https://statsandr.com。
机器学习的数据理解:评估与探索
原文:https://towardsdatascience.com/data-understanding-for-machine-learning-assessment-exploration-aca1aadc1cb6?source=collection_archive---------16-----------------------
高质量的数据是任何数据科学项目的基础。为了获得可操作的见解,必须获取和清理适当的数据。数据理解有两个关键阶段:数据评估和数据探索。
数据评估
理解数据的第一步是数据评估。这应在项目启动前进行,因为这是验证其可行性的重要步骤。此任务评估哪些数据可用,以及这些数据如何与业务问题保持一致。它应该回答以下问题:
- 有哪些数据可用?
- 有多少数据可用?
- 你能接触到你试图预测的基本事实和价值吗?
- 数据将采用什么格式?
- 它在哪里?
- 如何访问数据?
- 哪些领域最重要?
- 如何连接多个数据源?
- 使用这些数据报告了哪些重要的指标?
- 如果适用,数据如何映射到当前完成任务的方法?
主要考虑事项
收集地面实况数据
如果您希望使用机器学习进行预测,您很可能需要一个带标签的数据集。对于你的每个例子,你需要机器学习模型应该学习预测的正确的值,或者适当的类别;这就是所谓的地面真相。这可能是您已经可以获得的,因为它是一个动作或事件(例如,指示客户是否搅动的值),或者它可能是您需要收集的东西(例如,电子邮件的主题)。
如果地面真相需要被收集,或者被人工标注,那么应该制定一个计划来理解这将如何实现,以及完成它所需要的时间和努力。应该仔细考虑这一点,因为这可能太耗时,因此成本很高,使项目不可行。
数据关联
写下所有可用的不同数据点,并评估机器学习模型使用这些数据进行预测是否直观。有证据证明这些数据点和你希望实现的目标之间有联系吗?如果你向机器学习模型添加不相关的特征,你就是在添加噪音,让算法寻找不存在的联系。这可能会导致性能下降。
相反,如果一个人今天正在承担这项任务,探索他们用什么来做决定。这些数据可以在模型中使用吗?构建模型时,最好从简单开始——先只使用明显的功能,看看效果如何,然后再添加那些你不太确定的功能。这允许您评估附加功能是否增加了价值。
数据量
要成功建立一个机器学习模型,你必须有足够的数据。没有严格的公式来计算应该使用多少,因为它取决于问题的复杂性和你使用的算法。
一个经验法则是确保您的示例数量至少是您的模型需要训练的参数数量的十倍。对于逻辑回归或线性回归模型,参数的数量对应于要素的数量(因为每个要素都有一个权重)加一(因为您的偏差)。而对于深度学习,每个神经元都有一个待训练的权重,每一层都有一个额外的偏差。
您还可以使用预测的输出来估计您需要的样本数。如果你使用传统的机器学习方法(随机森林,逻辑回归)来分类你的数据,你需要每一类的数百个例子(最好更多)。而使用深度学习技术,所需的示例数量显著增加;通常每节课需要上千个。当处理回归问题(预测数字输出)时,您可以将这些问题进行分类,以确保每个范围都有足够的示例。
最后,尽量确保你的特征也有很多变化。例如,如果您正在预测房价,并且您的输入之一是 neighborhood,您希望确保您很好地覆盖了所有街区,以便模型可以了解这如何影响价格。
道德规范
在项目开始时考虑工具的潜在危害是很重要的。这些危害可能是由于只为一个狭窄的用户群体设计,没有足够的子群体代表性,或者人类贴标机偏向特权群体。
机器学习发现并归纳数据中的模式,因此可以复制偏差。如果一个群体的代表性不足,机器学习模型可以学习的例子就更少,导致这个群体中那些个体的准确性降低。
当大规模实现这些模型时,可能会导致大量有偏见的决策,伤害大量的人。确保您已经评估了风险,并准备好了减轻风险的技术。
数据探索
一旦您可以访问数据,您就可以开始数据探索。这是为您的数据创建有意义的摘要的阶段,如果您不熟悉这些数据,这一阶段尤其重要。这也是你应该测试你的假设的时候。活动类型和可能要问的问题包括:
- 计算记录的数量—这是您所期望的吗?
- 什么是数据类型?你需要为机器学习模型改变这些吗?
- 寻找缺失的价值——你应该如何处理这些?
- 验证每列的分布情况—它们是否符合您预期的分布情况(如正态分布)?
- 搜索异常值—您的数据中有异常吗?所有值都有效吗(例如,年龄不小于 0)?
- 验证您的数据是否平衡-您的数据中是否代表不同的组?你希望预测的每一类都有足够的例子吗?
- 您的数据中是否存在偏见——您的数据中的子群是否比其他子群更受青睐?
主要考虑事项
缺失值
理想的数据集应该是完整的,每个观察值都有效。然而,在现实中,您会遇到许多“NULL”或“NaN”值。
处理缺失数据的最简单方法是删除所有有缺失值的行,但是有价值的信息可能会丢失,或者您可能会引入偏差。因此,重要的是要努力理解缺失值是否有原因或模式。例如,特定人群可能不会回答调查中的某些问题;移除它们将阻止这些群体中的学习趋势。
删除数据的替代方法是输入值;用适当的替代值替换缺失的值。对于连续变量,通常使用均值、中值或众数。而对于分类数据,它通常是模式或新类别(例如“NA”)。如果列中有很大比例的值丢失,您可能希望将它们完全删除。
离群值
异常值是与其他观察值显著不同的数据点。一旦您确定了异常值,您还应该调查是什么导致了它们。
离群值可能表示坏数据:收集不正确的数据。如果是这种情况,您可能希望移除或替换这些数据点(类似于您如何估算缺失数据的值)。或者,这些值对于您的机器学习模型可能是有趣和有用的。
一些机器学习算法,如线性回归,可能对异常值敏感。因此,您可能希望只使用对异常值更鲁棒的算法,如随机森林或梯度增强树。
不平衡数据
如果每个类没有相似数量的示例,则数据集是不平衡的。这在欺诈检测等分类问题中很常见;大多数交易是正常的,而一小部分是欺诈性的。
机器学习算法从例子中学习;它拥有的例子越多,它对自己发现的模式就越有信心。如果数据不平衡,模型可能无法识别哪些模式与少数民族类别相关联。
在处理不平衡数据时,必须小心使用性能指标。例如,在我们的欺诈示例中,准确性可能会产生误导:如果 99.9%的交易不是欺诈,那么通过简单地将所有交易标记为“非欺诈”,而无需搜索进一步的模式,模型就可以达到 99.9%的准确性。您可能希望考虑其他指标,如精确度、召回率或 F1 分数。
要素也可能不平衡,从而阻止算法了解这些类别如何影响输出。例如,您有一个主要包含一个子群体的数据集,而这个群体之外的客户使用您的产品却没有获得成功的结果。为了防止这种形式的偏差,您应该计算不同类别的准确性指标。
后续步骤
在你彻底理解了你的数据之后,希望你已经准备好进入下一步数据准备:清理、转换&特征工程。
使用 DVC 和 GitHub 进行数据版本控制和机器学习过程控制
原文:https://towardsdatascience.com/data-version-control-machine-learning-process-control-using-dvc-github-c629511e95b5?source=collection_archive---------33-----------------------
DVC workflow
即使我们今天在机器学习(ML)方面取得了所有的成功,特别是深度学习及其在商业中的应用,数据科学界仍然缺乏组织项目和跨各种 ML 项目有效协作的良好实践。
提高机器学习工作流的生产率是必要的。作为 K 集团诊断公司的一名数据科学家,我要处理数百千兆字节的数据。对于数据科学家来说,管理和跟踪数据确实非常困难。数据跟踪对于任何数据科学工作流都是必不可少的。对数据版本化的需求是极端的,因此数据版本控制(【https://dvc.org】)对于任何数据科学家来说都是非常重要的工具。对于您的数据科学项目来说,这是一个非常方便和有用的工具。主要原因是,
- DVC 跟踪 ML 模型和数据集: DVC 旨在使 ML 模型可共享和可复制。
- ML 项目版本控制:版本控制机器学习模型、数据集和中间文件。
- ML 实验管理:利用 Git 分支的全部力量来尝试不同的想法,而不是代码中草率的文件后缀和注释。
- 部署&协作:使用推/拉命令将一致的 ML 模型、数据和代码束移动到生产、远程机器或同事的计算机中,而不是特定的脚本。
这里的主要优势是,我们可以使用亚马逊 AWS S3,微软 Azure 和其他数据/资源管理系统。我们可以配置这些系统来存储、读取、写入和快照数据。设置和使用非常简单,
- 使用安装 DVC,(假设您已经准备好 python 环境)
pip install dvc
2.执行 DVC 初始化,(假设您在 Github 存储库中,如果不是,则执行)
git initdvc init
3.现在让我们假设我们的项目有“数据”文件夹,其中有各种数据目录(通过 AWS S3 连接和下载)
├── data
│ ├── exp1
│ ├── x1.png
│ ├── y1.png
│ ├── exp2
│ ├── x2.png
│ ├── y2.png
│ └── exp3
│ ├── x3.png
│ ├── y3.png
│ └── exp4
│ ├── x4.png
│ ├── y4.png
第一次使用这些数据后,我们将执行以下步骤。
dvc add ./data/exp1 && git add ./data/exp1.dvcdvc add ./data/exp2 && git add ./data/exp2.dvcdvc add ./data/exp3 && git add ./data/exp3.dvcdvc add ./data/exp4 && git add ./data/exp4.dvc
这将创造。每个文件夹的 dvc 文件,该文件将被提交到 GitHub,这样我们就知道哪个版本的模型使用哪个版本的数据。
在这之后,如果我们使用远程数据存储,我们需要推动 dvc 变化,
dvc push filename
该命令将推送最近的更改并将更新缓存,让我们来做,
dvc status
这将检查数据中的任何潜在变化,如果有的话,它将跟踪它,我们可以提交它。
DVC 让合作变得非常容易。合作者可以用同样的方式设置它,或者他们可以用“dvc pull filename”命令提取数据。
此过程还适用于包含比当前持久存储在数据文件夹中的数据多得多的数据版本,因为 dvc 在其缓存中存储不同版本之间任意大小的差异,因此可以通过其 checkout 命令重新创建数据目录的较旧或较新状态。当然,结账也可以是另一个方向。
关于命令的更多信息,请访问它们的文档这里。
要将 DVC 与亚马逊 AWS S3 配合使用,请访问 https://dvc.org/doc/user-guide/external-dependencies
最好的总体亮点和特点是,
- 它是 Git 兼容的!DVC 运行在任何 Git 存储库之上,兼容任何标准的 Git 服务器或提供商(GitHub、GitLab 等)。数据文件内容可以由网络可访问存储或任何支持的云解决方案共享。DVC 提供了分布式版本控制系统的所有优势——无锁、本地分支和版本控制。
- 这是存储不可知论。你可以使用 S3、谷歌云和 Azure。
- 它附带了度量跟踪,并包含一个命令来列出所有分支,以及度量值,以跟踪进度或选择最佳版本。
- 与语言和框架无关
- 为 ML 管道框架提供端到端支持。
- 它可以跟踪故障!
- 它也兼容 HDFS,蜂巢和阿帕奇火花。
所以试试吧,让你的生活变得轻松!点击这里开始吧!作为一名数据科学家,我强烈推荐每个数据科学家在他们的 ML 管道中使用它。
使用 DVC 进行数据版本控制。作者有什么要说的?
原文:https://towardsdatascience.com/data-version-control-with-dvc-what-do-the-authors-have-to-say-3c3b10f27ee?source=collection_archive---------4-----------------------
数据版本化是数据科学项目中最被忽视的特性之一,但这必须改变。在这里,我将讨论一个最近的播客,它是为此目的的最佳工具的创造者之一, DVC 。
If your data project looks like this, you have to read this article.
数据操作在数据科学中非常重要,我认为数据科学家应该更加关注数据操作。这是数据科学项目中较少使用的功能。目前,我们通常对代码进行版本控制(用 Git 之类的东西),越来越多的人和组织开始对他们的模型进行版本控制。但是数据呢?
在下一篇文章中,我将详细介绍如何将 Git 和 DVC 以及其他工具结合使用,对数据科学(和科学)项目中的几乎所有内容进行版本控制。
最近,DVC 项目创始人德米特里·彼得罗夫在播客上接受了托比亚斯·小萌的采访。init 一个 Python 播客。在这篇博文中,我提供了一份采访的文字记录。你可能会对 DVC 背后的想法以及 Dmitry 如何看待数据科学和数据工程的未来感兴趣。
你可以在这里收听播客:
[## 机器学习项目的版本控制
采访 DVC 的创造者,了解它如何提高协作并减少数据科学上的重复工作…
www.pythonpodcast.com](https://www.pythonpodcast.com/data-version-control-episode-206/)
TL;速度三角形定位法(dead reckoning)
我们需要更加注意如何组织我们的工作。我们需要更多地关注我们如何构建我们的项目,我们需要找到我们浪费时间而不是做实际工作的地方。作为一名数据科学家,变得更有组织性、更有生产力是非常重要的,因为今天,我们仍然处于蛮荒的西部。
文字记录
免责声明:这份文字记录是我听播客并写下我所听到的内容的结果。我用了一些软件来帮助我转录,但大部分工作是由我的耳朵和手来完成的,所以如果你能改进这个转录,请随时在下面留下评论:)
托比亚斯:
你的主持人一如既往的托拜厄斯·梅西,今天我要采访德米特里·彼得罗夫关于 DVC,一个机器学习项目的开源版本控制系统。德米特里,你能从自我介绍开始吗?
德米特里:
当然可以。嗨,托拜厄斯。很高兴参加你的节目。我是德米特里·彼得罗夫。我有数据科学和软件工程的混合背景。大约 10 年前,我在学术界工作,有时我会说,我从事机器学习超过 10 年,但你可能知道,10 年前机器学习主要是线性回归和逻辑回归(笑)。这差不多就是我一直在做的。
后来转行做软件工程。我写一些生产代码。那时候数据科学还不是个东西。大约五年前,我转回定量领域。我成为了微软的数据科学家。我看到了现代数据科学的样子。最近,我,我实际上又回到了软件工程。今天我们在研究 DVC,我主要是为机器学习开发工具。
托比亚斯:
你还记得你是如何第一次接触 Python 的吗?
德米特里:
我想这发生在 2004 年。这是偶然发生的,我在我的硕士项目期间得到了一个实习机会,我参与了一个 Python 项目,这是我的第一个脚本语言。当然,至少在我的函数式编程课上我不算,它是由 Python 2.2 驱动的,然后我们切换到 2.3。
我花了许多不眠之夜调试 Python 2 中的 Unicode 问题(笑),如果你使用 Python 2,你可能知道我在说什么。后来我发现自己在从事的每个研究项目中都在使用 Python。我们还在用 MATLAB 进行机器学习。10 年前,Python 非常流行,我们使用普通的 C 语言来表示低级软件,让我们想象一下,当驱动器跟踪一些信号时,但一般来说,Python 是我实验室的主要语言,当我作为软件工程师工作时,我的主要语言是 C++。所以,我仍然使用 Python 进行自动化的特别项目。
那时有很多关于 Python 和 Perl 的讨论,对我来说这不是一个问题。所以在我回归数据科学的过程中,我一直使用 Python。Python 成为我的主要语言,因为它是当今人们使用的顶级语言之一。我们为数据科学家构建工具,我们使用 Python。
托比亚斯:
你一直在做的一个工具是名为 DVC 或数据版本控制的项目,你能先解释一下它是什么以及这个项目是如何开始的吗?
德米特里:
DVC 它基本上是机器学习项目的版本控制系统,你可以认为 DVC 是一个命令行工具,它是 ML 的一种 Git,它给你什么。它给出了三个基本的东西。首先,它可以帮助您跟踪我们的大型数据文件,例如,10 GB 数据文件、100 GB 数据集、ML 模型,它还可以帮助您版本化管道、机器学习管道,这与数据工程管道不同。这是一个轻量级版本的管道,DVC 帮助你组织你的实验,并使它们自我描述,描述,自我记录,基本上,你知道,一切,一个模型是如何产生的,你需要运行什么样的命令,作为这个实验的结果产生了什么样的指标。
您将在 Git 历史中拥有所有这些信息。DVC 从技术角度帮助你浏览你的实验,我们使用 Git 作为基础。所以它 DVC 工作在 Git 和云存储之上。你可以使用 S3,你可以使用谷歌存储或 Azure,或者只是随机的 SSH,服务器你存储数据,DVC 基本上编排 Git 和云存储。
你还问,DVC 是如何开始的。这其实是另外一个故事。因为最初,当我们开始这个项目的时候,我们没有想到用 Git 来代替 ML。我们想的是数据科学经验,什么是最佳实践,我们受到数据科学平台想法的启发,你可能听说过米开朗基罗,优步的数据科学平台,你可能听说过多米诺数据实验室。
今天,实际上,每个大型技术公司都有自己的数据科学平台,因为他们需要以某种方式在大型团队中工作,对吗?他们需要合作。软件工程工具集对于 ML 项目或数据科学项目来说并不完美。但是当我们在看这个平台的时候,我们在想,未来的平台应该是什么样子,我们应该如何创建一个数据科学家可以使用的平台,这个平台可以被广泛采用,高度可用。我们提出了这个想法,未来数据集平台的原则。它必须是开源的,这是你可以像社区驱动一样的方式,这是你可以创建一个每个数据科学家都可以使用的公共场景的方式。
如果它必须是分布式的,这很重要,因为有时你在你的桌面上工作,因为你有 GPU,例如,有时你仍然需要你的笔记本电脑工作。有时你需要云资源来运行一个特定的模型,例如,你需要大量的内存。无处不在很重要。
根据这个原则,我们想出了这个主意,为什么我们不重用 Git 作为我们工具的数据科学平台的基础。然后我们意识到这非常接近版本化的想法,我们只需要版本数据集,我们需要版本实验。DVC 就是这样开始的。
托比亚斯:
你提到用于常规软件项目的传统版本控制系统对于机器学习来说是不够的,因为需要能够跟踪数据集以及代码本身和一些结果模型。那么你能不能介绍一下与 DVC 一起工作的整个工作流程,以及它与软件工程项目的常规 Git 工作流程有何不同,后者可能侧重于 Django 应用程序。
德米特里:
首先,我们需要了解软件工程和机器学习的区别是什么。机器学习是由实验驱动的,问题是,你有一堆实验,你有几千个,有时几百个实验,你需要和你的同事就实验进行交流。基本上是和自己,因为明天你就不记得今天发生了什么。在一个月内,你不可能记得你今天做了什么,以及为什么这个想法产生如此差的结果,你需要像在许多情况下一样跟踪每件事。你可能会遇到这样的情况:你的一个同事来到你的办公室,说——嘿,你知道吗?我花了两天时间尝试这个想法。你知道吗,这不管用。你会说,是的,我试过了,两周前我试过同样的想法。我知道,没用。很难交流这些想法,因为你只有几十个,有时几百个。这就是区别。你需要一个框架来交流大量的想法,大量的实验。
在软件工程中,工作流是不同的。您的 idea 功能请求和错误修复数量有限。我可以说一句有争议的话——在软件工程中,你几乎从来不会失败。如果你决定实现一些问题,实现一些特性,或者修复一个错误,你创建一个分支。十有八九,分支会被合并到主流。你可能会在你生产的软件的质量方面失败,你可能会在预算方面失败,因为你认为它就像一个一天的项目,而你最终花了两个星期来实现这个功能。但最后还是会合并。
在数据科学中,你尝试了 10 个想法,其中一个效果最好,其余的都没用。但是你仍然需要沟通所有这些。DVC 基本上帮助你做到这一点,它帮助你版本化你的实验,你的实验的度量,你看到产生的度量,你看到用于这个特定实验的代码,这个特定版本的数据集。
例如,这比 Excel 电子表格工作得更好。因为今天,许多团队只使用 Excel 电子表格来跟踪他们的实验。这就是自我记录实验的基本区别,清晰的合作实验方式,以及观察结果的方式。
数据版本化是一件独立的事情,对实验来说很重要,是实验的必备。有时人们使用 DVC 只是为了数据版本控制,通常,例如,在部署端工作的工程师,他们使用 DVC 来部署模型。有时他们,数据工程师,数据科学家使用 DVC 只是为了版本化数据集。有时人们用 DVC 代替 LFS,因为 LFS 有一些限制,而 DVC 是为几十或几百千兆字节优化的。
托比亚斯:
对于您正在进行的实验类型,我知道一些输入可以采用特征工程的形式,您可以尝试提取数据的不同属性,或者更改您正在调整的超参数,以尝试获得模型的特定输出。因此,您能否讨论一下 DVC 如何能够跟踪这些以及它所支持的一些通信范例,以确保您不会因为无法提前识别特定的功能集、超参数和数据输入都已一起尝试过,而与他人重复相同的工作,从而浪费时间和精力?
德米特里:
哦,从数据文件的角度和数据集的角度来看,DVC 只是跟踪他们。所以你的特点是,基本上 DVC 把每个文件都当作一个 blob,我们通常不涉及数据文件的语义和数据文件的结构。模特也一样。所以模型只是二进制的。DVC 能理解模型被改变了,它能理解二进制文件的这个特定版本是在这个特定步骤上产生的。这个特定的输入被消费了,但是它没有进入特性内部,没有进入数据的语义。
托比亚斯:
就整体沟通模式而言,当数据科学家在通过 DVC 管理的项目中工作时,他们会关注哪些事情,以确保他们不会重复这项工作,以及他们会识别的任何类型的信号,如果只使用 Git 本身,这些信号会丢失吗?
德米特里:
首先,实验的结构。这是数据科学中非常重要的,你需要知道。我的意思是,不仅仅是在数据科学领域。在工程案例中也是如此。您需要了解使用了哪种代码,您的代码的确切版本是什么,以及所使用的数据集的确切版本是什么。这就是你如何相信你三周前做的实验。
还有一点就是度量。如果您知道这一点,那么这个版本的数据集的代码会产生它所创建的信任度的特定值。如果您在 Excel 电子表格中看到这个结果,您不需要再次重做这项工作,它可能有一些差异,对吗?这可能是您流程中的一个错误。你可能会重复做同样的事情。
对于文档,您可以只使用 Git 提交。当您提交您的结果时,这意味着您提交了管道,您提交了您的数据集和输出结果的一个版本,您放置了一个消息。Git 中的消息,因为它是非常简单的文档形式。这其实是一个非常强大的。DVC 所做的基本上是为数据项目服务。因为在我们的常规工作流程中,您可以提交代码,但您与数据没有联系,您与您的输出指标没有明确的联系。有时你甚至没有与你的管道连接。因为该提交可能与一个特定的改变相关,所以将执行管道的一个特定部分,而不是整个管道。
托比亚斯:
至于您正在跟踪的指标,您能否谈一谈这些指标是如何获取的,以及它们在整个评估和实验周期中的一些考虑因素,以确保模型产生您期望的输出类型和整个项目?
德米特里:
DVC 是一个数字不可知的工具,也是框架不可知的。DVC:它也是度量不可知论者。这意味着我们以简单的文本文件形式来跟踪指标。您的指标是带有一些头文件的 TSV 文件,或者 CSV 文件或 JSON 文件。当你刚刚输出我们有一个五个指标的值,DVC 允许你查看你的整个实验,哪些指标是产生的,你可以发现这个想法,例如,哪个失败了,因为指标不完美,实际上产生了一个更好的另一个指标有一个好的方法。你可能需要深入研究这个实验。
所以它向你展示了你的分支,你的提交的度量,它基本上帮助你通过度量导航你复杂的 Git 结构树。这是一种数据驱动的方式来浏览您的 Git 存储库。在一个数据项目中,您可能有数千个提交,数十万个分支。DVC 基本上帮助你通过这个复杂的结构导航。这就是我们需要指标的原因,这就是 DVC,它特别支持指标。
托比亚斯:
是否有一个内置的支持来搜索这些指标值并跨分支进行比较?或者,你需要在每个项目的基础上,实现一个特定的函数调用,来决定,在不同的比较中,它是正值还是负值。
德米特里:
今天,我们基本上展示了这些指标。如果你需要导航,你需要正确地实现一些东西,但是如果我们实现一些逻辑指标特定的逻辑,例如,显示这个特定指标的最大值,我不会感到惊讶。告诉我这些指标组合的最大值,就像这样。
托比亚斯:
除了通常用于常规软件应用程序的版本控制。还有许多其他类型的工具有助于确保您正在构建的项目是健康的,并且您没有代码退化。所以类似于林挺或者单元测试支持的东西。我想知道,当你在构建机器学习项目时,应该考虑哪些相邻的问题?你和 DVC 的工作或者你的其他项目有什么联系吗?
德米特里:
这是个很好的问题。因为,一般来说,数据项目中的工具集与软件项目中工具集的状态不同。大概一个月前,在西麦肯锡的一次采访中。他说,在数据科学方面,我们仍然处于蛮荒的西部。这实际上是正在发生的事情(笑),我们对许多场景没有很大的支持。
但从工具的角度来看,我今天看到的是,它在算法方面已经相当成熟了。因为我们有 PyTorch,我们有 TensorFlow,我们有一堆其他算法,比如基于随机树的算法。今天,有一场在线监控工具的竞赛。例如 TensorBoard,你可以在训练时在线报告你的指标,并查看现在训练阶段的实际情况。这对深度学习尤其重要,因为算法仍然很慢,我想说,它们是这个领域的一堆商业产品,而 MLflow 是开源项目之一,正变得越来越受欢迎,它可以帮助你跟踪你的指标并可视化训练过程。这是当今的一种趋势。
另一个趋势是如何可视化你的模型,如何理解你的模型里面有什么。同样,有很多工具可以做到这一点,但是这个工具的状态仍然不完美。就单元测试而言,你可以只使用常规的单元测试框架。但我不能说它对 ML 项目真的有效,具体来说,我多次看到的是单元测试或者可能不是单元,而是数据工程师的功能测试。在数据工程部分,当一组新的数据进入你的系统时,你可以获得基本的指标,并确保指标没有漂移,它们不是指标的大变化。这就是单元测试,或者至少是测试在数据世界中的工作方式。但是总体来说,工具仍然处于蛮荒的西部。
托比亚斯:
接下来是内置于 DVC 中的数据版本。当我通读文档时,它提到实际的数据文件本身存储在外部系统中,如 S3,或谷歌云存储或类似 NFS 的东西。因此,我想知道您是否可以谈谈 DVC 实际上是如何管理这些数据的不同版本以及它能够跟踪的任何类型的增量更改,或者您在构建该系统并将其与您使用的软件控制集成的过程中面临的任何困难或挑战,Git for in the overall project structure?
德米特里:
是的,当然,我们不会将数据提交到存储库(笑),我们通常会将数据推送到您的服务器、您的云中,您可以重新配置数据以将其放入云中。如前所述,我们将数据视为二进制 blobs。对于每个特定的提交,我们可以为您带来实际的数据集,以及所有正在使用的数据工件。我们对每个文件不做任何区分,因为你需要理解文件的语义才能做区分,对,这不是区分。在 Git 中,让每个文件都与众不同是有意义的。
在数据科学中,你需要知道你使用的数据文件的确切格式。然而,我们将目录作为独立的结构类型来跟踪。如果您有一个包含 100.000 个文件的目录,然后您在目录中添加了几个文件并提交这是您数据集的新版本,那么我们知道只有一小部分文件发生了更改,比如说修改了 2000 个文件并添加了 1000 个文件,然后我们在 diff 上进行版本化,这样您就可以每周轻松地在数据库中添加标签,而不用担心目录的周期,我们会进行这种优化。
另一个优化,我们做的重要优化是优化您的工作空间。当 Git 从我们的内部结构中签出文件时,它会在您的工作空间中创建一个副本,但是在数据世界中,有时这是没有意义的,因为您不想创建 100 个副本,比如说千兆字节的数据,另一个副本。我们通过一些参考来优化这个过程。
所以你没有数据集的副本。因此,您可以轻松处理数百 GB 或数十 GB 的数据,而无需担心这个问题。
托比亚斯:
对于正在参与现有项目的人来说。他们只是第一次检查存储库的状态,是否有能力说我只想下载代码,我还没有准备好下载所有数据,或者我只是想下载数据的子集,因为正在处理数百 GB 数据集的人不一定希望在他们的笔记本电脑上安装所有这些数据,因为他们正在进行这些实验。我很好奇,当您在本地工作时,当您训练模型时,整个工作流是什么样子,它如何处理这些大型数据存储库并与之交互,以确保它不会完全填满您的本地磁盘。
德米特里:
这是一个好问题。我们做这种精细拉动,我们也优化这一点。作为一名数据科学家,你可以决定你到底需要什么。例如,如果您想要部署您的模型,它可能在 100 兆字节以内,您可能不需要为 100 GB 的数据集浪费时间,这是为了产生模型而使用的。
然后,您可以在数据文件上指定任何内容,比如用代码和元数据克隆一个新的存储库。然后说我只需要一个模型文件。所有的模型文件将被传送到你的生产系统到你的部署机器上,并且是相同的数据集。
托比亚斯:
我已经谈到了一些其他项目,人们正在构建它们,例如 Quilt 或 Pachyderm,它们内置了对数据版本的支持。我想知道您目前是否有任何与这些系统集成的计划,或者只是为 DVC 的数据存储部分增加额外支持所涉及的整个过程?
德米特里:
对于一些系统集成可以很容易地完成,例如,Pachyderm 这是一个项目,它主要是关于数据工程。他们对我们的管道有一个概念,有点像数据工程管道。DVC can 可用于数据工程流水线。它有 ML 管道的概念,一个轻量级的概念。它是专门为机器学习工程师优化的,它没有数据工程管道的所有这些复杂性,但它可以很容易地用作单步和工程管道。
我们已经多次看到,当人们采取,例如 DVC 管道,并把内部气流作为一个单一的步骤。有了这种设计,其实是一个很好的设计,因为你给了 ML 工程师和数据科学家一个轻量级的工具,所以他们很容易产生一个结果。他们可以更快地迭代以创造他们的工作。你有一个生产系统,DVC 可以很容易地注入其中。
有一个术语我不记得是哪个公司用的了。网飞,可能——甲板内甲板;这意味着你有一套数据管道,你有一套解决特定问题的 ML 平台,然后基本上在数据工程平台中注入许多 ML 平台。因此,从这个角度来看,没有集成的问题,没有集成到厚皮动物或气流或其他系统的问题。关于被子数据,他们做版本控制,他们也和 S3 一起工作,潜在地我们可以做我们可以和他们集成。我们正在思考这个问题,我们正努力做到以消费者为导向,以客户为导向。今天最大的需求可能是与 MLflow 的集成,因为 MLflow 在在线指标跟踪方面表现非常好。有时人们喜欢使用 MLflow 进行跟踪,在线跟踪指标,使用 DVC 对数据文件进行版本控制。这是我们今天正在思考的整合之一。
托比亚斯:
就 DVC 本身的实际实现而言,我知道它主要是用 Python 编写的。您提到,这在很大程度上是因为它正在成为数据科学家的通用语言。所以我想知道,现在你是否在 DVC 的整体实施和维护方面更进一步,如果你认为这仍然是正确的选择?如果你今天重新开始,在语言选择、系统设计或整个项目结构方面,你会做哪些不同的事情?
德米特里:
我认为 Python 是这类项目的好选择,有两个主要原因。第一,我们的目标是数据科学家,他们中的大多数人都熟悉 Python。我们期望数据科学家为我们的代码库做出贡献。如果你用 C 或 C++,或 Golang 编写这类项目,很可能你不会看到社区的很多贡献。因为社区讲不同的语言。对我们 for works 完美来说,数据科学家正在贡献代码,这很棒(笑)。
第二个原因是编程 API。之前,我们考虑通过 API 创建一个 DVC,这是使用 DVC 的另一种选择。如果你用 Python 写代码,它有点开箱即用,你可以重用 DVC 作为一个库,并将其注入到你的项目中。如果你将使用一种不同的语言,这只会产生一些开销,你需要考虑将这些转换成一种更好的形式。这些就是原因。到目前为止,我们是快乐的 Python,它工作得很好。
托比亚斯:
你提到能够使用 DVC 也是一个图书馆。所以我想知道是否有你见过的特别有趣或意想不到或新奇的用例,无论是在那个库用例中,还是在它最初设计的面向命令行的方式中?
德米特里:
有时候你们这些人会要求库支持,因为他们需要实现一些更疯狂的场景(笑)。例如,我可以说,人们使用 DVC 来构建自己的平台,如果你想要数据科学平台,他们希望构建持续集成框架,当 DVC 在你的本地经验和 CI 经验之间发挥所有这种粘合剂的作用时,他们要求库,但我们有一个如此棒的命令行支持命令行工具集,人们只需切换回命令行体验。但是有一天,如果有人将 DVC 仅仅作为一个图书馆,我不会感到惊讶。
托比亚斯:
我还对您谈到的将 DVC 集成到数据工程管道中的能力很感兴趣,因为只需包装一个实施步骤就可以运行模型培训部分。因此,我想知道您是否可以就此以及您所看到的一些具体实现多谈一点?
德米特里:
是啊,绝对的。这其实是一个很好的问题。我相信数据工程师需要管道,对吗?。数据科学家和机器学习工程师需要管道。但事实是,他们的需求完全不同。数据工程师确实关心稳定的系统,如果它失败了,系统需要做些什么,它必须恢复。这是数据工程框架的主要目标。
在数据科学中,情况正好相反。你总是失败(笑)。当你想出一些主意,你写代码运行一个失败的分数,你觉得它失败了,等等。你的目标是建立一个框架来快速检查想法,快速失败。这是 ML 工程师的目标。这是一个很好的实践来分离两个框架有两种管道框架。一个是稳定的工程,第二个是快速,轻量级的实验管道,如果你愿意的话。
当你把这两个世界分开时,你就大大简化了 ML 工程师的生活。他们不需要处理复杂的东西,我们不需要浪费时间去理解气流是如何工作的,Luigi 是如何工作的,他们只是生活在他们的世界里,制作模型,一旦模型准备好了,他们需要一种清晰的方式来将这条管道注入数据管道。为了做到这一点,您可以构建一个非常简单的工具。我记得当我在微软工作的时候,我花了大概几个小时来生产我的管道。因为我有一个独立的工作流程,所以我有一个独立的 ML 管道工具。这个很好用。我相信在这种未来的工程师中,我们需要把这两件事分开。
托比亚斯:
我还对 DVC 提供的部署功能感兴趣,只要它能够将模型投入生产,或者在产生错误输出的情况下恢复模型的状态,或者预测是它提供的结果给业务带来问题,或者只是在生产中运行机器学习模型所涉及的一些整体工具和工作流, 特别是度量跟踪,以了解模型何时需要重新训练,并完成构建和部署这些模型的整个过程。
德米特里:
是的,部署,我们正等着得到它,因为它接近业务。还有一个关于 ML 模型部署的小趣事。有时候是这样的——一个软件工程师和一个数据科学团队,我们能不能对我们的模型做更多的检查,不是对上一个模型,而是对上一周的模型?数据科学家喜欢——是的,当然,我们有数据集,你需要五个小时来重新训练它(笑)。
花五个小时是没有任何意义的,在软件工程工作世界中,它不是这样工作的。你需要准备好所有可用的东西。你需要马上复习,因为等五个小时意味着浪费做生意的钱。
DVC 基本上帮助你组织这个过程,它帮助,它基本上在你的产生一个模型的数据科学家和拿模型和部署模型的 ML 工程师之间创造一个共同的语言。因此,下一次,有了适当的数据管理,你甚至不会要求数据科学家给你一个以前的模型,你应该在你的系统中拥有 DVC 或 DVC 的一切,不管你需要什么,都是可用的工件。
从在线指标跟踪的角度来看,这实际上是一个独立的问题。因为当你在生产中谈论度量跟踪时,它通常意味着在线度量。这通常意味着基于用户反馈的指标。这是另外一个问题。所以 DVC 主要是关于部署或不部署,主要是关于开发阶段。它基本上不会对在线指标做任何事情。
托比亚斯:
所以你实际上是在 iterative.ai 的主持下构建和维护这个项目,这实际上是一家风险投资支持的公司。所以我很好奇,对于你的投资者来说,总的价值等式是什么,使得他们值得为你构建和发布这个开源项目的努力提供资金。以及你对业务的总体战略。
德米特里:
你会惊讶(笑)投资者对今天的开源项目如此感兴趣,尤其是去年开源项目非常成功。去年,Mulesoft 被数百万或数十亿收购,对不起,去年弹性搜索上市。纯粹是开源公司。
而当你做开源的时候,通常意味着你在做 it 基础设施。在许多情况下,你做的是 IT 基础设施,它们有利于盈利。对于一个成功的开源项目,那些将开源项目货币化的公司,理解你的商业模式是非常重要的,因为开源有一些共同的模式。
一种是服务模式,一种咨询模式。第二件事是开放核心模式,当你构建软件,并为企业生产一个具有高级功能的软件,或一个不同版本的软件,作为产品。
第三个模型是生态系统。当你构建一个产品,一个开源产品,并创建服务作为一个独立的产品。一个例子可能是 Git 和 GitHub,当他们有开源和 SaaS 服务时,这是绝对不同的产品,是绝对不同的体验和用例。你需要明白你适合哪种模式。对于成功的项目是很多希望在这种企业感兴趣的这种经验。
最初,我开始了这个项目,因为它是我最喜欢的项目,持续了大约一年。然后我在想——如何把这件事做大,如何在这件事上花更多的时间,如何找到更多的资源来做这件事。很明显,这个项目如果成功,将会有一些企业在这个领域赚钱。我们为什么不做这个业务,它打造一个产品,把这个产品货币化。所以我会说,这是现代开源世界的自然之路。
托拜厄斯:
就构建和维护 DVC 项目和社区的整体经验而言,我想知道您在这个过程中发现了哪些最有趣、最具挑战性或最意想不到的经验教训。
德米特里:
我学到的一课,实际上,我认为这是通常的商业课。所以当你建立你的项目时,你知道你做什么,你知道,你的路线图,你知道你的目标,你只是在建立,但有一天用户来找你。他们要了很多不同的东西。
然后你就有了紧张,你的愿景,你的计划和用户的需求之间的紧张。今天,我们每天都会收到用户的一些请求,所以我们每天有 10 个请求(笑)。平衡这些东西不容易。因为如果你按照人们的要求去做,你就没有时间制定你的路线图了。事实上,你没有时间去解决和实现人们要求的每一件事。所以你需要学会如何区分事情的轻重缓急。你需要学会怎么说,有时候对用户说不,说我们会这么做,但很可能不是现在。所以这并不容易做到。这是你在过程中需要学习的。正如我所说的,开源软件的体验和商业环境中的体验是一样的。我已经看过很多次了。
托拜厄斯:
展望你为 DVC 计划的工作,我很好奇你在路线图上有什么类型的特性或改进。
德米特里:
在不久的将来,我们将发布对数据集版本化和 ML 模型版本化的更好支持。我们正在向 DVC 介绍新来者,这简化了你今天的体验。一些公司正在使用 mono-repos,里面有一堆数据集。我们需要新的命令来做得更好,有时是因为这些数据集以不同的速度发展。有时,您需要使用数据集一个版本,一个版本使用其他版本。所以基本上,这是我们正在采取的步骤之一。
数据集的另一个用例是交叉存储库引用。其他公司没有使用单一回购,而是使用一系列回购。例如,他们可能有 10、20 个数据集的回复,还有 20 多个模型的回复。他们需要交叉引用数据集,这是我们要实施的下一个命令,以支持这种交叉引用、跨存储库的情况。这是我们不远的将来。
从长远来看,下一步将是实现更多的特性来更好地支持实验,特别是当人们处理诸如超参数调整这样的场景时。他们需要做 1000 次实验。他们仍然需要控制他们。他们不想有 1000 个分支(笑)。这是我们需要改进的体验。我们对如何做到这一点有一个明确的计划。这差不多是未来半年的事了。最终,我们相信 DVC 可以成为这个平台,当人们可以在一个团队中在相同的环境下工作,并相互分享想法。在未来,我们相信我们可以创造体验,当人们可以分享想法,甚至在公司之间,团队之间,伟大的体验。
我相信这是 DVC 的美好未来。
托比亚斯:
你在 DVC 做的工作或机器学习项目的整体工作流程中,有没有其他方面是我们还没有讨论的?你认为我们应该在节目结束前讨论一下吗?
德米特里:
我不知道他们有什么要补充的。但是我相信,我们需要更加注意如何组织我们的工作。我们需要更多地关注如何构建我们的项目,当我们浪费时间而不是做实际工作时,我们需要找到更多的地方。作为一名数据科学家,这对于提高组织能力和工作效率非常重要,因为今天我们仍然处于蛮荒的西部,这需要尽快改变。注意这一点很重要,理解这个习题集也很重要。
托比亚斯:
好吧。好吧,对于任何想跟进你正在做的工作或者想取得联系的人,我会让你把你的首选联系信息添加到展示笔记中。因此,我将把我们带到图片中,本周,我将选择一个我最近开始使用和试验的工具,名为 otter.ai。
它被宣传为一种语音笔记服务,可以将你的会议笔记或你自己的记忆笔记转录到文本中,以便于搜索。我一直在尝试用它来为播客制作转录。所以我期待着开始更频繁地使用它,并开始录制节目。所以,如果你正在寻找一个能以合理的价格自动生成副本的工具,那绝对值得一试。就这样,我会把它传给你来认识你。你这周有照片吗?
德米特里:
所以我认为开源部分和开源与风险投资是我们将要讨论的问题。事实上,我没有什么特别的建议,但是今天天气很好。春天刚刚开始。所以只是花更多的时间在城市或城镇之外的地方走走。
托比亚斯:
好的,非常感谢你今天抽出时间和我一起讨论你在 DVC 做的工作,并为机器学习生命周期的整体项目开发添加一些更好的结构。所以谢谢你。我希望你今天过得愉快。
德米特里:
哦,谢谢你,托拜厄斯。谢谢你。
结论
https://dvc.org/
我们需要测试和版本控制来理解我们在做什么。当我们编程时,我们一直在做很多不同的事情,我们在测试新的东西,尝试新的库等等,把事情搞砸并不罕见。这是数据科学的道路,快速失败,迭代成功。
DVC 是我们目前拥有的控制数据项目的最佳工具之一,正如你所看到的,它可以与其他伟大的工具相连接。我希望这篇采访和文章能帮助你开始使用它们。
如果您有任何问题,请在此写信给我:
[## 法维奥·瓦兹奎-科学与数据公司创始人/首席数据科学家| LinkedIn
加入 LinkedIn ‼️‼️重要提示:由于 LinkedIn 技术限制,我现在只能接受连接请求…
www.linkedin.com](https://www.linkedin.com/in/faviovazquez/)
祝学习愉快:)
数据可视化 101:开发图表最重要的规则
原文:https://towardsdatascience.com/data-visualization-101-the-most-important-rule-for-developing-a-graph-2f9a6cdeb8c5?source=collection_archive---------41-----------------------
记住图表是视觉句子
Photo by kreatikar
我想每个人都见过糟糕的图表,一堆乱七八糟的条、线、饼状图,或者你害怕看到的东西。也许你已经做了一个,当你今天看着它,想知道你到底在想什么。
这些图表违反了数据可视化中最基本的图表制作规则:
这条规则适用于图表的所有用途,无论你是数据科学家、数据分析师、T2 统计学家,还是仅仅为了好玩给你的朋友制作图表。
在小学,你的语法老师可能会解释说,一个句子,最基本的,表达了思想或观点。图表是视觉句子:它们应该陈述一个且只有一个关于数据的想法或观点。
当你看一个图表时,你应该能够用一句话说出图表在说什么:比如“A 组比 B 组强”,或者“Y 开始有所提高,但现在正在下降。”如果你不能,那么你有自己的运行图。
Photo by Linux Screenshots (CC BY 2.0)
例如,上面的图表试图表达太多的陈述:试图描述近一个世纪以来二十二个不同国家的移民模式。在这些数据中可能有有用的陈述,但是作为一个图表的表示阻止了观察者/读者能够容易地破译它们。
Photo from Andrew Guyton (CC BY-SA 2.0)
同样,这张图显示了太多的镜头尺寸,无法有意义地表达一个单一的、连贯的想法,让读者/观众难以确定应该关注哪个领域。
潜在异议 1:但是我对数据有比一句话更多的话要说。
太好了!然后提供一个以上的图表。说出你需要说的关于数据的一切;为你的每一个陈述使用一个图表。
不要陷入一张图统治一切的谬论:试图用一张图来表达你对数据的所有陈述,结果却是一团看不懂的混乱。创建多个易读的图表,每个图表一次展示一个要点。将所有内容浓缩在一张图中只会让你的观众无法判断你到底要说什么。
Photo from TymonOziemblewski
Photo from kreatikar
潜在异议#2:我希望观众自己解释这些发现,而不仅仅是传达我自己的想法/结论。
公平点。在展示/交流数据时,有一段时间可以展示你自己的见解,也有一段时间可以开放式地展示信息,让你的观众/读者自己去解读。对于前者,图表是工具,对于后者,使用表格。除了其他潜在用途之外,表格还为读者/查看者传达了广泛的信息,以便他们自己进行解释。
还记得上面第一个关于来自欧洲各地的美国移民的例子吗?表格(见下文)可以更容易地传达信息,并允许读者跟踪他们想了解的任何地方、模式或问题。您是否希望报告大量信息,以便读者可以为自己的目的所用?那么表格是比图表更好的起点。
Photo from Michael Waskom
有些情况下,我倾向于分享我的见解/分析,而其他情况下,我倾向于鼓励我的读者/观众形成他们自己的结论,但由于大多数情况下需要两者的结合,我通常会结合图表和表格。当我可以的时候,我试着在文档或幻灯片中放一些小的表格,当我不能的时候,在附录中放一些完整的表格。
潜在异议 3:我的主要观点有多个分点。
许多句子也有表达单一思想所需的多个要点,这并不妨碍句子结构有意义地捕捉这些思想。这种子点的奇特语法单词是子句。尽管有些句子简单明了,只有一个主语和谓语,但许多句子(就像这个句子)需要多组主语和谓语来表达思想。
同样,一些图形化的想法需要多个从属或复合的子点,有一些类型的图形允许这样做。考虑联合地块,如下图所示。为了充分展示两个变量之间的关系和组合分布,它们还在上方和右侧显示每个变量的单独分布。这样,观众可以看到两种分布如何影响组合分布。因此,它像一个从句一样在边上显示每个变量的分布。
Photo from Michael Waskom
这些都是需要制作的高级图表,因为就像多部分句子一样,你必须仔细地呈现分论点,以明确要点是什么。同样,多部分句子需要仔细考虑如何连贯地组织多个分句。我打算稍后写一篇文章,更详细地描述如何开发这些多部分图。
一般规则仍然适用于这些更复杂的图形:
如果不能,请不要使用/显示该图表。我们的大脑非常善于凭直觉判断一个句子是否承载一个思想,所以用这个来判断你的图是否有效。
原文发布于此:https://ethno-data . com/data-visualization-graphing-making-no1-rule/。关于该网站和其他文章的更多信息,请访问https://ethno-data.com/。
也感谢《数据科学》杂志发表这篇文章。更多关于他们工作的细节,请看。
数据可视化:人类认知的催化剂
原文:https://towardsdatascience.com/data-visualization-a-catalyst-to-human-cognition-4c851e8f7b2?source=collection_archive---------32-----------------------
理解可视化和叙事可视化的基础如何帮助模式识别和决策的概念交响乐
数据可视化从一开始就存在了。从描绘原始生活方式的洞穴绘画,到查尔斯·密纳德关于拿破仑进军的信息图,可视化已经被用来传达抽象的思想和历史时代,并将它们转化为有形和可行的概念。这是一个整合的过程,它有局限性,只有当我们的眼睛能够解码它,我们的大脑能够理解它时,它才是有用的。那么,到底是什么让人类的思维立即与所呈现的洞察力联系起来呢?
数据可视化是外部认知的一种形式——帮助内部认知做得更好,并推动它看到模式。大脑喜欢模式,因为它是在呈现的信息中“看见”关系。所以,当 Jacques Bertin 第一次提出图形编码或者我们现在所知道的数据可视化的想法时,他恰当地说它是“传达意义的符号系统”。他们努力帮助交流,并使用八个视觉编码变量跳过三个层次的信息。
这三个级别的信息是:
1.基本信息—了解单个数据点
2.中间信息—了解一组数据点
3.总体信息——着眼于更大的图景,您可以结合起来形成所有数据点的模式
Three levels of information processing
理解并能够通过这些级别的信息操纵数据包括调整流程。在初级和中级之间过渡的情况下,可以使用处理例程。应用处理程序是你能够处理和理解初级信息的地方,通过识别一个接一个呈现给你的所有信息并在此基础上建立,从而打开中级信息。在此之后,可以通过使用下面提到的视觉编码的 8 个变量来形成数据可视化。这使人们能够回答通过视觉分析过程提出的问题,在视觉分析过程中,人们可以识别问题或目标,然后相应地构造数据以处理它并在不破坏的情况下简化它。这个过程使用了信息的力量和 Bertin 视觉编码的八个变量,为出于交流目的对数据进行恰当的认知处理创造了条件。
Bertin 的视觉编码的八个变量是:
1.转换为位置的 x 和 Y (2 个变量)
2.大小
3.价值
4.纹理
5.颜色/色调
6.方向
7.形状
The 8 visual variables. Size and Value translate to Z variables. [image:https://www.axismaps.com/guide/general/visual-variables/]
因此,当一个人可以处理这些以创建可视化而不破坏数据和模式时,它导致理想认知条件的安排,其中大脑致力于决策和/或识别图像内的关系。
让我们从数据中辨别一些模式,以理解如何回答“哪些灾难可能会影响全国各地的康菲炼油厂?”这将有助于我们了解人类思维如何在这种外部认知工具的帮助下处理数据。
首先,必须处理原始数据以消除异常和空值,这样才能创建一个可行的数据文件来处理信息,而不会产生异常值。在这里,我可以用美国各地的灾难数据集来做这件事。然后,我使用 Tableau 这款出色的可视化工具创建了一张地图,您可以在地图上以点的形式看到不同的灾难——这种级别的信息几乎是以自上而下的方式处理的,您可以看到所有灾难的全貌,并且在定义中可以包括炼油厂所在的所有位置以及哪些灾难可能会影响它们。看看我在下面创建的可视化。你将能够看到我在可视化中使用了位置、大小以及色调/颜色的变量。
Points depicting disasters around the United States using color and size
这些价值观在美国大陆上被表现出来,以呈现一个叙事过程的开端,在这个过程中,你将故事设定在哪里,故事在哪里发生。在此之后,我进一步处理可视化,以打开与我的问题的细节相关的信息。我介绍了康菲石油公司在美国各地的炼油厂的位置,同时在某种意义上用灰色显示不同的灾难,以吸引观众对炼油厂位置(x,y)的注意。这有助于视觉化的过程,让人类的思维一次专注于一条信息,创造一个焦点。
Bringing the focus to Conoco-Phillips refinery locations surrounding the disaster data
现在,我将把认知集中在这些炼油厂所在的州,我还将添加它们周围的数据集中的灾难。这要求我使用位置、大小、颜色/色调的变量,同时也标记精炼厂,通过使用 Tableau 中给出的工具提示属性来帮助观众记住精确的位置。
States, disaster types, and refinery locations
最后,在叙事可视化过程中,必须有一个冲突的解决方案。因此,当我们第一次打电话来定义目标/问题时,我们现在将通过我们已经采取的步骤来回答这个问题。通过我展示的图像,我试图回答哪些灾难可能会影响康菲炼油厂的问题。完成上述步骤后,我又采取了一个额外的步骤,根据这些灾难在这些州发生的频率对它们进行排序。这是通过使用 Tableau 计算字段实现的。结果并不令人惊讶,但在叙事可视化过程中,随着信息水平的使用和 Bertin 的八个编码变量-它要求采取解决方案的席位。我制定了一个更容易被大脑整理和分析的决议。使用颜色/色调,这种多地图可视化的外部认知辅助启动了内部认知过程。它允许大脑以图像的形式理解科学和数据。下面是贯穿整篇文章的冲突解决方案。
Prominent disasters surrounding Conoco-Phillips refineries, ranked.
有了这个,认知过程立即识别出哪些灾难正在影响康菲炼油厂所在的州。它认识到了我们从视觉化一开始就一直试图辨别的模式。因此,正如谚语所说,“一张图片胜过千言万语”,这个创建和分解可视化以回答一个中心问题的过程实际上相当于一千个数据点!
总之,通过视觉分析过程和叙事视觉分析,人们可以很容易地发现,三个层次的信息和视觉编码的八个变量共同构成了任何数据可视化的基础。他们本质上是必要的和复杂的,他们互相利用以给出更大的图景。它们是启动我们头盖骨内无限和不可量化器官的内部认知过程的火花塞。在一个技术处于知识和想象力前沿的世界里——创造了理想的混沌形式,这些数据可视化对人类思维具有特殊的重要性。他们就像一个超级英雄,通过组织和处理模式来拯救世界。你看,大脑喜欢模式,反过来也喜欢视觉化。所以,想象一下,当一个嵌入模式的外部信息帮助我们更容易地做出决策时,人类认知的兴奋程度。这就像带一个小孩去糖果店,但在这种情况下,糖果是统计数据表示,以创建不同类型的可视化。最棒的是。它们都服务于人类思维的一个共同目的——它们交流不可交流的事物,并且从时间开始就一直在这样做。
参考资料:
雅克·贝尔坦。图形和图形信息处理。w·德·格鲁埃特,1981 年。
数据可视化—高级散景技术
原文:https://towardsdatascience.com/data-visualization-advanced-bokeh-techniques-e33f92537415?source=collection_archive---------18-----------------------
散景交互式地图、数据表、文本输入和文档布局
如果你想创建强大的数据可视化,那么你应该考虑使用散景。在之前的文章“如何使用 Python 和散景创建交互式地理地图”中,我演示了如何使用散景创建交互式地理地图。本文将更进一步,演示如何使用交互式地图以及使用散景布局组织的数据表和文本字段来创建用于显示数据的交互式仪表板。
首先,让我们来看看文章《T2》中的成品:小心 Zillow,Jestimate 来了!”:
点击这里观看三藩市 2018 Jestimates!
关于代码的一句话
该项目的所有代码、数据和相关文件都可以在 my GitHub 访问。该项目分为两个 Colab 笔记本。一个运行线性回归模型(为可视化创建数据),另一个使用 Heroku 上的 Bokeh 服务器生成交互式可视化。
安装并导入
让我们从图表所需的安装和导入开始。Pandas、numpy 和 math 是用于清理和争论数据的标准 Python 库。geopandas、json 和 bokeh 导入是映射所需的库。
我在 Colab 工作,需要安装 fiona 和 geopandas。当您在 Colab 中开发应用程序时,您需要将这些安装保存在代码中。然而,一旦你开始用散景服务器测试,你将需要注释掉这些安装,因为散景不能很好地与魔术命令(!idspnonenote)一起工作。pip 安装)。
# Install fiona - need to comment out for transfer to live site.
# Turn on for running in a notebook
%%capture
!pip install fiona
# Install geopandas - need to comment out for tranfer to live site.
# Turn on for running in a notebook
%%capture
!pip install geopandas# Import libraries
import pandas as pd
import numpy as np
import math
import geopandas
import json
from bokeh.io import output_notebook, show, output_file
from bokeh.plotting import figure
from bokeh.models import GeoJSONDataSource, LinearColorMapper, ColorBar, NumeralTickFormatter
from bokeh.palettes import brewer
from bokeh.io.doc import curdoc
from bokeh.models import Slider, HoverTool, Select, TapTool, CustomJS, ColumnDataSource, TableColumn, DataTable, CDSView, GroupFilter
from bokeh.layouts import widgetbox, row, column, gridplot
from bokeh.models.widgets import TextInput
初步代码
由于本文的重点是交互式仪表板的创建,我将跳过以下步骤,这些步骤在我的上一篇文章“如何使用 Python 和 Bokeh 创建交互式地理地图”中有详细介绍。
- 准备制图数据和地理数据框 geopandas.read _ file()
- 创建颜色条查找表— format_df 数据帧
- 为 GeoJSONDataSource-JSON _ Data 函数创建 JSON 数据
- 创建绘图函数— make_plot 函数
- 颜色栏-颜色栏,make_plot 函数的一部分
- 悬停工具—悬停工具
数据加载、清理和争论
我将简要讨论应用程序中使用的数据,如果你有兴趣,可以查看完整的清洗和争论这里。
应用程序中使用了两个数据框架:用于显示每个街区 2018 年总统计数据的街区数据,以及由我的文章“中的线性回归代码生成的 2018 年销售的每个单独房产的显示数据。
邻域 _ 数据数据帧
neighborhood_data DataFrame
显示 _ 数据数据帧
display_data DataFrame
应用程序的主要代码
让我们看一下应用程序的主要代码,然后一步一步地详细介绍。
### Start of Main Program
# Input geojson source that contains features for plotting for:
# initial year 2018 and initial criteria sale_price_median
geosource = GeoJSONDataSource(geojson = json_data(2018))
original_geosource = geosource
input_field = 'sale_price_mean'
# Initialize the datatable - set datatable source, set intial neighborhood, set initial view by neighborhhood, set columns
source = ColumnDataSource(results_data)
hood = 'Bernal Heights'
subdist = '9a'
view1 = CDSView(source=source, filters=[GroupFilter(column_name='subdist_no', group=subdist)])
columns = [TableColumn(field = 'full_address', title = 'Address')]
# Define a sequential multi-hue color palette.
palette = brewer['Blues'][8]
# Reverse color order so that dark blue is highest obesity.
palette = palette[::-1]
#Add hover tool to view neighborhood stats
hover = HoverTool(tooltips = [ ('Neighborhood','@neighborhood_name'),
('# Sales', '@sale_price_count'),
('Average Price', '$@sale_price_mean{,}'),
('Median Price', '$@sale_price_median{,}'),
('Average SF', '@sf_mean{,}'),
('Price/SF ', '$@price_sf_mean{,}'),
('Income Needed', '$@min_income{,}')])
# Add tap tool to select neighborhood on map
tap = TapTool()
# Call the plotting function
p = make_plot(input_field)
# Load the datatable, neighborhood, address, actual price, predicted price and difference for display
data_table = DataTable(source = source, view = view1, columns = columns, width = 280, height = 280, editable = False)
tap_neighborhood = TextInput(value = hood, title = 'Neighborhood')
table_address = TextInput(value = '', title = 'Address')
table_actual = TextInput(value = '', title = 'Actual Sale Price')
table_predicted = TextInput(value = '', title = 'Predicted Sale Price')
table_diff = TextInput(value = '', title = 'Difference')
table_percent = TextInput(value = '', title = 'Error Percentage')
table_shap = TextInput(value = '', title = 'Impact Features (SHAP Values)')
# On change of source (datatable selection by mouse-click) fill the line items with values by property address
source.selected.on_change('indices', function_source)
# On change of geosource (neighborhood selection by mouse-click) fill the datatable with nieghborhood sales
geosource.selected.on_change('indices', function_geosource)
# Layout the components with the plot in row postion (0) and the other components in a column in row position (1)
layout = row(column(p, table_shap), column(tap_neighborhood, data_table, table_address,
table_actual, table_predicted, table_diff, table_percent))
# Add the layout to the current document
curdoc().add_root(layout)
# Use the following code to test in a notebook
# Interactive features will not show in notebook
#output_notebook()
#show(p)
步骤 1 —初始化数据
散景提供了几种处理数据的方法。在典型的散景交互式图形中,数据源是 ColumnDataSource。这是散景中的一个关键概念。然而,当使用地图时,我们使用 GeoJSONDataSource。我们将同时使用两者!
# Input geojson source that contains features for plotting for:
# initial year 2018 and initial criteria sale_price_median
geosource = GeoJSONDataSource(geojson = json_data(2018))
original_geosource = geosource
input_field = 'sale_price_mean'
# Initialize the datatable - set datatable source, set intial neighborhood, set initial view by neighborhhood, set columns
source = ColumnDataSource(results_data)
hood = 'Bernal Heights'
subdist = '9a'
view1 = CDSView(source=source, filters=[GroupFilter(column_name='subdist_no', group=subdist)])
columns = [TableColumn(field = 'full_address', title = 'Address')]
我们将希望加载的数据年份(2018)传递给 json_data 函数。然后,json_data 函数从 neighborhood_data 中提取所选年份的数据,并将其与映射数据合并,为散景服务器返回转换为 json 格式的合并文件。我们的 GeoJSONDataSource 是 geosource。initial_field 用 sale_price_mean 初始化。
我们的 ColumnDataSource,Source,用 results_data 初始化,列数据源视图(CDSView),view1,用 Bernal Heights 邻域(subdist=9a)初始化。CDSView 是一种过滤数据的方法,允许您显示数据的子集,在本例中是 Bernal Heights 邻域。datatable 的列被初始化以显示属性的完整地址。
步骤 2——初始化颜色条、工具和地图绘制
# Define a sequential multi-hue color palette.
palette = brewer['Blues'][8]
# Reverse color order so that dark blue is highest obesity.
palette = palette[::-1]
#Add hover tool to view neighborhood stats
hover = HoverTool(tooltips = [ ('Neighborhood','@neighborhood_name'),
('# Sales', '@sale_price_count'),
('Average Price', '$@sale_price_mean{,}'),
('Median Price', '$@sale_price_median{,}'),
('Average SF', '@sf_mean{,}'),
('Price/SF ', '$@price_sf_mean{,}'),
('Income Needed', '$@min_income{,}')])
# Add tap tool to select neighborhood on map
tap = TapTool()
# Call the plotting function
p = make_plot(input_field)
ColorBar 调色板、HoverTool 和 TapTool 被初始化,并且调用 make_plot 函数来创建显示中间价格邻域热图的初始地图图。
步骤 3——用初始数据填充数据表和文本字段
# Load the datatable, neighborhood, address, actual price, predicted price and difference for display
data_table = DataTable(source = source, view = view1, columns = columns, width = 280, height = 280, editable = False)
tap_neighborhood = TextInput(value = hood, title = 'Neighborhood')
table_address = TextInput(value = '', title = 'Address')
table_actual = TextInput(value = '', title = 'Actual Sale Price')
table_predicted = TextInput(value = '', title = 'Predicted Sale Price')
table_diff = TextInput(value = '', title = 'Difference')
table_percent = TextInput(value = '', title = 'Error Percentage')
table_shap = TextInput(value = '', title = 'Impact Features (SHAP Values)')
使用源(从 results_data 填充的 ColumnDataSource)、视图(针对 Bernal Heights 过滤的 view1)和列(仅使用 full_address 列的列)填充 datatable。Bokeh 中的 TextInput 小部件通常用于从用户那里收集数据,但也可以很好地显示数据!所有的 TextInput 小部件都用空格初始化。
第四步——回调函数
这是交互性发挥作用的关键功能。散景小部件使用事件处理程序基于回调原理工作。on_change 或。on_click —提供自定义交互功能。然后,这些事件处理程序调用表单函数(attr,old,new)中的自定义回调函数,其中 attr 是指已更改属性的名称,old 和 new 是指属性的以前值和更新值。
# On change of source (datatable selection by mouse-click) fill the line items with values by property address
source.selected.on_change('indices', function_source)
对于数据表来说,这很容易,只需使用 source 的selected . on _ changeevent _ handler,并在用户单击数据表中的一行时调用函数 function_source ,将该行的索引传递给它。然后,根据从数据表中选择的索引,从源(results_data)更新 TextInput 值。
def function_source(attr, old, new):
try:
selected_index = source.selected.indices[0]
table_address.value = str(source.data['full_address'][selected_index])
table_actual.value = '${:,}'.format((source.data['sale_price'][selected_index]))
table_predicted.value = '${:,}'.format((source.data['prediction'][selected_index]))
table_diff.value = '${:,}'.format(source.data['difference'][selected_index])
table_percent.value = '{0:.0%}'.format((source.data['pred_percent'][selected_index]))
table_shap.value = source.data['shap'][selected_index]
except IndexError:
pass
对于地图,我希望能够单击一个街区,并根据所选的街区填充数据表。奇怪的是,没有内置。HoverTool 的 on_click 事件处理程序。很明显,HoverTool 知道它在哪个街区盘旋,所以我自己建了一个!
我意识到有一个 TapTool,在用地图测试后,我发现它是一个选择工具。换句话说,当您在地图上的多边形上单击鼠标时,它实际上使用邻域 id 作为索引来选择多边形!这也会触发。geosource 中的 on_change 事件处理程序。因此,使用与数据表相同的基本方法:
# On change of geosource (neighborhood selection by mouse-click) fill the datatable with nieghborhood sales
geosource.selected.on_change('indices', function_geosource)
对于地图,使用 geosource 的selected . on _ changeevent _ handler,并在用户单击某个邻域时调用函数 function_geosource ,向其传递该邻域的索引。基于新的索引(邻域 id/subdistr_no),将 CDSView 重置为新的邻域,用视图中的新数据重新填充 datatable,并将 TextInput 值设置为空。
# On change of geosource (neighborhood selection by mouse-click) fill the datatable with nieghborhood sales
def function_geosource(attr, old, new):
try:
selected_index = geosource.selected.indices[0]
tap_neighborhood.value = sf.iloc[selected_index]['neighborhood_name']
subdist = sf.iloc[selected_index]['subdist_no']
hood = tap_neighborhood.value
view1 = CDSView(source=source, filters=[GroupFilter(column_name='subdist_no', group=subdist)])
columns = [TableColumn(field = 'full_address', title = 'Address')]
data_table = DataTable(source = source, view = view1, columns = columns, width = 280, height = 280, editable = False)
table_address.value = ''
table_actual.value = ''
table_predicted.value = ''
table_diff.value = ''
table_percent.value = ''
table_shap.value = ''
# Replace the updated datatable in the layout
layout.children[1] = column(tap_neighborhood, data_table, table_address, table_actual, table_predicted,
table_diff, table_percent)
except IndexError:
pass
步骤 5 —布局和文件
散景提供了几个布局选项来安排地块和部件。布局的三个核心对象是 row()、column()和 widgetbox()。这有助于将屏幕想象成一个由行、列组成的网格。widgetbox 是小部件的容器。在应用程序中,组件在一行中排列成两列:
- 第一列-包含绘图 p(地图)和文本输入微件 table _ shap(Shapley 值)。
- 第二列—包含数据表 tap_neighborhood 和其余的 TextInput 小部件。
# Layout the components with the plot in row postion (0) and the other components in a column in row position (1)
layout = row(column(p, table_shap), column(tap_neighborhood, data_table, table_address,
table_actual, table_predicted, table_diff, table_percent))
# Add the layout to the current document
curdoc().add_root(layout)
然后,该布局被添加到文档中进行显示。
我欢迎建设性的批评和反馈,请随时给我发私信。
在推特上关注我
这篇文章最初出现在我的 GitHub 页面网站上
这是探索三藩市房地产数据系列文章的一部分
旧金山房地产数据来源:旧金山 MLS,2009–2018 年数据
数据可视化和真实性艺术
原文:https://towardsdatascience.com/data-visualization-and-truthful-art-324b13a2ad34?source=collection_archive---------21-----------------------
阿尔贝托·开罗的《真实的艺术》是一本关于数据可视化的极好的书,我怎么推荐都不为过。
在的真实艺术中,Cairo 解释了良好数据可视化的原则。何描述了当你使用数据可视化时,应该作为你基础的五个品质:真实、实用、漂亮、有洞察力和启发性。Cairo 也给出了一些有偏见和不诚实的可视化的例子。
数据-油墨比
在我深入探讨“伟大可视化的五个品质”之前,我想介绍另一个相关的概念:数据-墨水比率,由爱德华·塔夫特在定量信息的可视化展示中引入。
Tufte 将数据油墨比定义为数据油墨量除以打印图形所需的总油墨量。现在,我不认为他要求我们测量纸上的墨水量。相反,Tufte 建议我们删除那些不会给图形添加新信息的元素。
也许最著名的减少数据墨水的例子之一是由加拿大艾伯塔省埃德蒙顿的一家信息、可视化和设计公司 Darkhorse Analytics 创造的。Darkhorse 收集了四个如何提高数据-墨水比的例子。他们的主要概念是“裸露的数据看起来更好”和“移除以改善”
黑马的这个动画非常具有说明性:
伟大可视化的五个品质
根据开罗的说法,这五种品质并不是相互独立的。所有不同的品质都是相互关联的,它们与所有其他的品质相互作用。
真实的
我们需要倡导真实的数据。基于数据分析的真相可能是主观的。但作为数据科学家,我们应该尽最大努力保护真相。这些方法帮助你达到真实:
- 首先,当你清理和总结数据时,要对自己诚实。仔细考虑你对原始数据所做的每一个修改。你遮住了什么吗?实践开罗所说的“自我欺骗”——理解你自己头脑中的诡计。对数据科学家来说,质疑自己的能力至关重要。我们可以如此专注于寻找模式,以至于我们以与所描述的现象不真实的方式减少或呈现数据。
- 第二,记住你的义务是对观众的。使用行业公认的数据科学和信息可视化技术来揭示特定的数据。通过批准的流程和系统从数据中获得答案是数据科学的定义。让您的数据可视化适应您的受众,而不是相反。并考虑观众的阅读能力和理解水平。
功能的
考虑你的视觉化是否有用。数据-墨迹比有助于增加可视化的功能。我将在另一篇文章中讨论这个问题。有很多增加功能的试探法,比如用户测试。
美丽的
这听起来可能有点奇怪,但是美观对数据可视化很重要。要达到美,你需要了解你的受众。“情人眼里出西施”是一个常见但准确的表达。对美的不同理解是基于人们的生活经历和其他方面,如性别和文化。对于任何数据科学家来说,创建一个被观众认为漂亮的可视化效果都是一项伟大的成就。
富有洞察力的
好的可视化不仅仅是从表格或文件中复制数据。它以可视化格式显示相关数据,揭示趋势或关系。当洞察力被成功可视化时,观众会“啊哈!”瞬间。
数据科学写作新手的一个常见做法是为他们拥有的每一份数据都附上一张图表。过多的信息是不必要的,会导致读者疲劳。正确的数字能很快说明研究的结果。
有启发作用的
虽然听起来差不多,但是启发和有见地是不同的概念。Cairo 说这种品质是由前面四种品质组成的:真实、实用、美丽和有洞察力。启蒙意味着每一个重要的组成部分都被成功地结合起来,产生一个新的有价值的启示。
社会责任呢?
Cairo 还提出了一个问题,即社会责任是否是伦理数据可视化中需要考虑的一个方面。这个问题没有明显的答案。谁能判断对特定科学知识的压制或选择性释放是有害的还是有帮助的?
创造意义,而不是欺骗
最重要的是,要有意图创造有意义的视觉效果,识别欺骗和不道德的工作。数据科学家负责以适合其技能和目的的方式,将正确的信息呈现给正确的受众。毫无疑问,应用 Cairo 的五大可视化品质将有助于产生具有事实和相关价值的数据可视化。
参考
- 阿尔贝托·开罗,《真实的艺术:用于交流的数据、图表和地图》
- 黑马分析博客,2018 年 7 月。
用于 EDA(探索性数据分析)的数据可视化
原文:https://towardsdatascience.com/data-visualization-for-eda-exploratory-data-analysis-f001a1bf0087?source=collection_archive---------10-----------------------
(By: Alberto Lucas López, National Geographic, Source)
请花 1 分钟时间看看上面的图片。油画《心灵的框架》呈现了巴勃罗·毕加索在数万幅作品中触及的主题。12 大主题分散在整个画面上,通过使用不同的形状(与毕加索名作高度相关的形状)和颜色来分隔。然后,这些主要主题被进一步细分为更多形状和颜色的子部分,并且这些子部分用每个特定的对象进行了注释。总之,色彩、形状、线条和面积传达了毕加索“思想框架”的全貌。
使用大量的数据,这幅画的作者总结了 12 个主题,并将其细分到每一个单独的对象中。毕加索的作品被收集、学习、重组,作品背后的信息(本例中的主题)通过可视化和呈现的方式传达出来。对我来说,收集数据和探索信息是数据分析的主要过程,而将信息可视化就是我们所说的数据可视化。数据分析有助于我们深入了解情况,通过挖掘数据,从而发现数据“矿”中的“黄金”,讲述隐藏的故事。同时,数据可视化使我们能够更有效地交流故事。
尽管数据可视化通常是数据分析过程的可交付成果之一,但数据科学家通常会在获得数据框后绘制数据框。在这里,我想和大家分享我在探索性数据分析过程中的数据可视化经验。从一开始就绘制数据可以帮助我们理解数据集。
我正在查看的数据集之一是发布在 Kaggle 网站上的电影分析项目。我正在使用的数据可视化 Python 库是“ Plotly ”,这是一个基于 plotly.js 的开源库,它基于 d3.js (这被认为是数据可视化的“硬核”技术之一)。
在电影数据帧中,有 4803 行电影,20 列电影特征,包括每部电影的收入、标题、上映日期、预算、制作公司、运行时间、平均投票、投票计数。其他信息可能也是有用的,但是到目前为止,这些功能主要集中在。
单变量数据分析
当查看数据框时,我们会想到直观地检查主要特征,在这种情况下可能是收入和预算。为了分析简单变量,我们可以看看它的单变量分布。在大多数情况下,直方图是找出单个变量分布的一种极好的方法。如下图所示,直方图对每个值进行分类,并对每个分类中出现的值进行计数(每个分类代表一个值范围)。因此,有时需要更多地考虑箱大小的确定。通过绘制直方图,我们可以观察到收入和预算的分布都是指数衰减变量(这意味着更多的电影具有更低的预算和收入)。只有少数电影是高预算高收入的。
双变量数据分析
因为我们已经分别检查了收入和预算的分配,所以我们可能想要评估这两个变量之间的关联。要做到这一点,散点图通常是一个很好的选择。从图中,我们可以找到代表预算和收入的每个点(每部电影)。有趣的是,一些数据点位于 x 轴或 y 轴上,表明这些电影要么获得零预算,要么获得零收入,这没有意义。因此,作为一名数据科学家,我们可能会仔细考虑是否应该将这些数据视为无效数据并丢弃它们,或者视为可接受的并保留它们。此外,这在分布中并不直接可见,因为箱包含一定范围的值,但不太能说明每个值的确切位置。
通过使用交互式绘图,我们甚至可以将光标移动到每个点来检查电影标题。
我们也可能对平均投票数和计票数感兴趣(我起初对这个感兴趣,因为当我看到一部糟糕的电影时,它会敦促我回顾它,给它一个差星。我想看看我是不是唯一会这么做的人)。然而,散点图显示,大多数电影(高票数)位于 6 和 8 之间。它可能被解释为实际上很少有人会做我通常做的事情,但是,它也可能被解释为人们在决定是否花时间看电影之前了解电影的评论,这样坏电影往往会被更少的人观看或评论。
线剧情
在大多数情况下,当描述一些值随时间序列的变化时,线形图是简单明了的。如下图,线表示运行时间随时间的变化,点表示每部电影的运行时间。虽然这可能不是一个使用线形图的好例子,因为我们通常使用一条线来表示一个对象的值的变化。如果我们可以将电影视为一个整体,那么剧情可以被解释为所有电影的运行时间趋势。根据这个线图,我们可以得出这样的结论:随着时间的推移,电影运行时间的方差在增加。
箱形图
当查看一个变量的分布时,我们可以绘制直方图。当我们看到五个变量时,它们可能在图中重叠,但有时仍然是可以解释的。如果我们有太多的变量呢?要查看值的分布,我们可以引入箱线图,它可以显示平均值、最小值、最大值、75%和 25%的值。箱线图提供了一种呈现不同变量并快速比较其分布的方法。如下图所示,图中并排显示了十家主要制作公司的预算和收入。我们可以快速检查这十家公司的值的分布。我们可以了解到迪斯尼公司的预算不那么有限,派拉蒙电影公司也制作了一些非常卖座的电影。
散布矩阵
与散点图不同,散点图为我们选择的每个特征的每个组合绘制散点图。它让我们快速检查每个特征之间的相关性。具体来说,对角散布矩阵表示变量的直方图。
我希望你会发现这个分享是有帮助的。所有的代码都可以通过回购共享。请随时在下面留下任何评论或建议。
谢谢你的时间和欢呼!
面向所有人的数据可视化第 1 部分
原文:https://towardsdatascience.com/data-visualization-for-everyone-pt-1-68b443d29b87?source=collection_archive---------9-----------------------
第二部分
第 1 部分:收集、存储和版本控制
介绍
我的背景是在 AEC (建筑、工程和&建筑)行业——这个行业在采用和应用新的变革性技术方面一直落后于其他大多数行业。随着现代向数据驱动的企业框架的转变,这一挑战今天依然存在。尽管我们的目标是以逻辑为导向的,但我们“右脑思考”的历史仍有一些教训可供我们今天借鉴。AEC 行业依靠沟通成为最有效和最成功的方式。无论是精致内部空间的渲染还是复杂释放阀的模型开启,我们都依赖某种形式的交流来传达我们的想法。在这样做的过程中,我们在各自的交流分支中变得独特而高度熟练。
我们的目标是将这些知识和流畅转化为另一个交流领域:数据可视化。在今天的实践中,数据无处不在。一些实践可以奢侈地收集数据,并投入时间从中提取信息和见解,但许多其他实践必须敏捷,并在日常工作中找到机会,这将增强他们的过程。本文将通过关注数据收集和可视化,并通过为我们中间的修补者提供易于使用的入门工具和更复杂的解决方案,来解决等式的两个方面。
数据可视化是一个广阔的领域,背后有大量的工作。虽然我们不能体现所有的经验,但我们可以很好地将我们独特的行业专业知识与 it 的精选部分结合起来,以进一步提高我们沟通和合作的能力。
数据收集
在能够考虑数据可视化之前,首先我们必须确保我们有足够有意义的数据通过可视化产生价值。收集过程通常是公司和团队试图做出“数据驱动”决策的第一个障碍。收集干净、系统化的数据需要在时间和技术方面进行前期投资,才能真正有价值。这似乎是一个令人望而生畏的障碍,特别是对于较小的团队和组织,但幸运的是,今天有一个完整的解决方案可供我们使用,涵盖了广泛的时间/成本投资要求。
由于“收集”在组织和行业之间可能是一个非常不同的过程,本文将着眼于收集媒介和 AEC 行业的机会。然而,同样的概念可以应用于其他市场,数据源是区分因素。
回顾的主题
- 矿车
- Ideate 的 BIMLink
- 耐热玻璃
- 蚱蜢和发电机
- Visual Studio
商业解决方案
如果由于时间限制和/或缺乏特定领域的知识,您目前没有从您的工作中收集数据,您可能会在处理数据提取和收集的成熟商业解决方案中找到价值。这些产品通过将核心逻辑打包到易于理解和使用的接口中,消除了对特定领域知识的需求。不利的一面是,这些产品和服务是有成本的,这可能就像最初缺乏该领域的专业知识一样令人望而却步。
目前市场上有许多这样的产品,本指南将仅重点介绍几个关键产品作为示例。强烈建议您继续研究这一领域的产品,因为它们变化非常快。
优点:节省时间,不需要“专家”使用
缺点:成本,有限定制
矿车(试验场)
Minecart 是 Proving Ground 的全方位服务数据解决方案。他们不仅从 BIM 模型中提取数据,还准备模板仪表板和可视化。这是该领域最全面的服务之一,因此可以应用于任何团队或组织,无论他们是否拥有数据科学专业知识。实施成本是基于服务的,这意味着它会根据公司要求、定制级别、知识/培训需求以及许多其他因素而有很大差异。因此,我们鼓励团队了解他们的需求范围,并向服务提供商寻求最准确的价格信息。
Minecart Concept (Image Credit: Proving Ground)
Sample Dashboard Output (Image Credit: Proving Ground)
BIMLink (Ideate)
Ideate 的 BIMLink 是 Autodesk Revit 最受欢迎的数据提取解决方案之一。该工具允许用户从 BIM 模型中选择要导出和格式化/过滤的属性,并且只有在模型中已经有有价值的数据时才是有效的。与 Minecart 不同,这个工具只是一个数据提取应用程序。因此,值得注意的是,在数据导出之后,团队仍然需要至少具有一些关于数据管理和可视化的特定领域知识的人来实现该数据的全部价值。
Ideate BIMLink Concept (Image Credit: Ideate)
定制解决方案
如果现有的商业解决方案不能满足您的数据需求,那么探索定制解决方案可能是值得的。定制解决方案是团队或组织自己构建的解决方案——根据他们工作的特定需求对其进行定制,并相应地管理他们的数据。定制解决方案的缺点是,根据特定需求对其进行定制是一个耗时的过程——一旦大规模部署,这些工具的创建和维护都将成为大量的时间投资。创建和维护还伴随着对知识的需求——与商业解决方案提供给用户的“前台”或后台知识相同。
有无限多的工具和平台可以列在这个类别中,供开发人员用来创建解决方案,但我们将只重点介绍一些与我们的 AEC 行业更相关的工具和平台。
优点:可定制、无订阅/费用、可扩展
缺点:时间、需要特定知识、维护
PyRevit(伊朗埃赫桑-内贾德)
PyRevit 是 Ehsan Iran-Nejad 的开源软件项目,允许用户使用 Python 为 Autodesk Revit 创建脚本甚至插件。默认情况下,PyRevit 附带了许多工具,但它真正的强大之处在于用户能够使用 Python 语言的可访问且强大的语法来原型化和构建自己的逻辑。使用 Python 可用的许多库和包,任何人都可以创建数据挖掘脚本,甚至是成熟的数据提取应用程序。
使用这个工具的额外好处是,数据科学长期以来一直倾向于 Python。该语言的可访问性和“非个人化”特性使其成为数据处理、分析、清理甚至可视化的自然选择。因此,学习 Python 使用 PyRevit 提取数据只会让您在提取之后从事更令人兴奋的工作!
Prototyping & Creating Custom Solutions With Python
蚱蜢和迪纳摩(麦克尼尔/欧特克)
Grasshopper 和 Dynamo 是可视化编程接口,允许用户创建类似于编码/软件开发的业务逻辑,无需编写文本代码。这些接口使得那些没有特定领域知识的人更容易原型化和创建逻辑例程、自动化和其他功能。
除了它们为创作提供的灵活性之外,它们还提供了许多软件包,可以从 BIM 模型或 CAD 文件中提取数据。通过这两种方式,用户还可以选择使用可视化编程界面,或者使用基本的 UI 组件创建更加人性化的界面。在这两种情况下,可视化编程简化和民主化了对大量计算资源的访问,其中许多资源对于数据提取或处理是有用的。
Visual Programming Makes Brings Custom Solutions Within Reach
Visual Studio(微软)
Visual Studio 是一个集成开发环境,它允许开发人员构建。使用 C# 的 NET 应用程序(以及许多其他应用程序/语言)。对于我们的用例,我们可以使用 Visual Studio 为 Autodesk Revit 或 McNeel 的 Rhino 等软件构建成熟的插件,这些插件可以将我们的数据提取到我们选择的任何格式或平台。与 Python 不同,C#不太容易理解,尤其是如果用户没有任何编码/开发经验的话。尽管不太友好,但它确实提供了编译语言的显著性能提升,因此对于大型数据集和/或大型应用程序非常有用。
除了创建成熟的应用程序,C#和 Visual Studio 还可以用于创建可视化编程接口的节点和组件,如 Grasshopper 或 Dynamo 。尽管这种语言在数据科学工作流中并不十分流行,但是通过这种方法,您可以获得一些额外的价值,通过可视化编程接口为他人创建更易于访问/消化的资源。
Microsoft Visual Studio IDE Interface
数据版本控制和存储
在收集/提取数据后,另一个挑战出现了—保持所有内容都是最新的,或者至少知道什么是过时的以及什么时候过时的。这种挑战与组织或团队的规模成比例,个体成员打破了既定的实践和标准,倾向于快速的“解决方案”。
在当今数据快速增长的环境下,许多公司已经开始在组织层面解决这个问题。微软的 SharePoint/OneDrive 和谷歌的 Docs 产品已经慢慢迁移到一个完整的云存储系统,完成了语义版本化、标记和其他基础设施,这些基础设施系统化和组织了我们放入其中的数据。除了“office”解决方案之外,Google、Amazon 和 Microsoft 等数据库提供商也为他们的数据库产品增加了类似的复杂性,使它们比以往任何时候都更容易使用。
在这种产品创新的环境下,我们必须谨慎选择我们的方法,不要被不符合我们特定需求的功能和服务分散了注意力。像以前一样,我们可以从广泛的解决方案中进行选择,从全定制到全用户就绪。
回顾的主题
- OneDrive
- 谷歌驱动
- MongoDB
- 燃烧基地
商业解决方案
有许多现成的解决方案可用于存储和版本化数据。最常见的格式是基于文件的,文件集合构成一个完整的数据集,每个文件的版本代表数据集的历史。即使使用基于文件的方法,我们也可以应用许多最佳实践,让我们超越太熟悉的“Data _ final 2 . CSV”范式,并帮助我们从数据中提取更多价值。
优点:快捷/易用、有效&直观
缺点:局限于文件,缺乏标准/一致性
OneDrive 和 Google Drive(微软/谷歌)
OneDrive 和 Google Drive 都是云文件存储解决方案。它们还能很好地与各自的、更广泛的产品生态系统集成在一起(微软的 Office 套件、谷歌的 G 套件和 T20)。除了在云中存储我们的文件之外,它们还允许我们共享、消费和保存我们文件的历史记录。这非常有用,因为最终的数据可视化需要共享/消费,而保留历史对于询问数据集的更深层次的问题非常有用。
OneDrive File Versioning
尽管这两者都很容易获得并且被广泛使用,但这也使得它们在存储数据时存在风险。数据需要一致性才是有用的—格式化、清理等。对于基于文件的系统,在确保数据符合标准方面,用户是最终的责任点。因此,如果团队/组织中的用户在使用这项技术时不承担这一责任,存储的数据可能对最终的应用程序没有什么用处。
定制解决方案
在当前的技术市场上,定制数据库解决方案“多如牛毛”。这对消费者来说非常好,因为这意味着当我们试图将技术与组织需求相匹配时,我们可以从一系列选项中进行选择。与前面的主题一样,本指南不会涵盖所有可能的数据库解决方案,但会重点介绍一些关键产品,它们在定制能力和民主化访问能力之间提供了良好的平衡。
优点:标准化是内置的,能够扩展,可以广泛集成
缺点:成本高,需要调校&维护
MongoDB
MongoDB 是一个基于云的数据库,是当今市场上最受欢迎的产品之一。它的受欢迎程度来自于其全面的文档、开发人员友好的语法以及用于管理数据的图形界面等附加工具。MongoDB 数据库可以接受许多不同类型的数据,并且可以与数据集的大小并行扩展。此外,它与大多数主要的编程语言、框架和语法都有接口,这使得它很容易成为任何定制软件解决方案的“插件”。
MongoDB Sample App Flow
Firebase(谷歌)
Firebase 是另一个基于云的数据库,提供了与 MongoDB 相同的功能(如上所述)。它与 MongoDB 和目前市场上其他数据库解决方案的不同之处在于它的实时特性。这种功能本质上意味着应用程序或开发人员不必在每次更新时都请求整个数据集,而只需维护一个到数据库的实时(监听器)链接。这使得它成为频繁变化的数据集的首选,并要求用户了解这些变化。跟踪建筑物的房间面积或计算机械散流器是一个很好的例子,这些信息在设计师或工程师每次处理模型时都会发生变化。
Google Firebase Realtime Database Functionality
总结和第 2 部分
我们已经讨论了很多内容,但是我们还没有进入“有趣”的部分。本文的第 2 部分将利用我们在这里建立的强大基础深入到可视化过程中。尽管数据收集和存储可能不是流程中最有趣或最吸引人的部分,但它们是最重要的部分,因为它们直接关系到我们数据可视化和信息交流的最终有效性。如果没有一致可靠的数据来源,我们根本没有机构来询问或回答我们希望能够回答的问题。
第二部分
每个人的数据可视化 Pt 2
原文:https://towardsdatascience.com/data-visualization-for-everyone-pt-2-d7f80b49e17d?source=collection_archive---------14-----------------------
第 1 部分
第 2 部分:创建和管理可视化
介绍
我的背景是在 AEC (建筑、工程、&建筑)行业——这个行业在采用和应用新的变革性技术方面一直落后于大多数其他行业。随着现代向数据驱动型企业框架的转变,这一挑战今天依然存在。尽管目标以逻辑为导向,但我们的“右脑”历史有一些教训我们今天可以借鉴。AEC 行业依靠沟通才能最有效、最成功。无论是精致内部空间的渲染还是复杂释放阀的模型,我们都依赖某种形式的交流来传达我们的想法。通过这样做,我们变得越来越有个性,也越来越擅长我们各自的交流分支。
我们的目标是将这些知识和流畅性转化为另一个交流领域:数据可视化。在今天的实践中,数据无处不在。一些实践可以奢侈地收集这些数据,并花时间从中提取信息和见解,但许多其他实践必须敏捷,并在日常工作中寻找机会,以加强其流程。本文将通过关注数据收集和可视化来解决这两方面的问题,并为我们中的修补者提供易于使用的入门工具和更复杂的解决方案。
数据可视化是一个广阔的领域,背后隐藏着大量的工作。尽管我们不能体现其中的每一课,但我们可以很好地将我们独特的行业专业知识与精心策划的部分结合起来,进一步提高我们的沟通和协作能力。
数据可视化
现在已经收集并存储了数据(第 1 部分),我们可以开始考虑它的表示和通信。为了策划这种交流,我们首先必须了解我们的目标是什么,或者更简单地说,我们想通过询问数据来回答什么问题。在这种情况下,数据探索不应与数据可视化混淆。如果我们天生不熟悉数据,我们可能会采取探索性的步骤来更好地理解数据,但这个过程应该与我们希望通过可视化实现的精心策划的交流分开。
一旦我们制定了一组我们希望用数据来回答的问题,我们就可以开始将工具和技术与问题相匹配。与我们之前的主题一样,我们可以采用各种各样的解决方案来回答我们的问题,这里我们将只重点介绍一些最受欢迎或最有用的解决方案。
商业解决方案
不久前,商业解决方案还局限于这一领域。仅在 5-10 年前,Excel 中的数据透视表被认为是可视化和呈现数据的标准。现在,我们有了像 Tableau 和 PowerBI 这样的工具——专门致力于创建和管理数据驱动的演示的工具。这一领域的创新在很大程度上是由金融部门推动的,但这并不意味着我们不能利用其他行业的创新来提高效率。
优点:节省时间,不需要特定领域的知识,产品质量更高
缺点:成本,定制有限
(舞台上由人扮的)静态画面
Tableau 是一个商业智能(BI)平台/应用程序,允许用户使用熟悉的图形用户界面创建动态和交互式数据可视化。与其他 BI 工具相比,Tableau 具有更陡峭的学习曲线,但也提供了更多定制和管理数据可视化的机会。这种权衡适用于我们将在本指南后面讨论的其他数据可视化平台,包括商业和定制解决方案。
除了更陡峭的学习曲线,Tableau 还有一个非常重要的相关成本。因此,它只对完全致力于这种类型的工作流的团队和组织有财政意义。还有一个免费版本,但它要求用户在互联网上发布他们的数据集,这在与大多数客户和合作伙伴合作时既不可取也不可能。
Sample Tableau Dashboard
微软公司
PowerBI 是另一个 BI 平台,它提供了与上面讨论的 Tableau 非常相似的功能。这两个平台的主要区别在于它们的可访问性和成本。PowerBI 旨在对任何人和每个人都有用——它不依赖数据科学或数据可视化知识来允许用户创建出色的视觉效果。相反,它简化了许多与数据的交互,并让用户通过简单的操作进行创建和探索。没有任何经验的普通用户可以在几个小时或最多几天内启动并运行 PowerBI。面对 Tableau 的同一个用户可能需要至少一个星期,如果不是更多,才能真正有效。(此信息纯属轶事/经验,并非测量的统计数据)。
PowerBI 还提供免费和付费版本,但与 Tableau 不同,免费版本是可用的。PowerBI 的免费层限制了该应用程序的一些功能,如多作者协作和自定义数据源定义,但总体而言,它在很大程度上是相同的产品,几乎任何规模的团队都可以有效地使用。付费版本可以与 Office365 订阅捆绑在一起,因此,如果您的组织已经提供了这种服务,这可能比单独购买成本更低。
PowerBI 的缺点是定制限制。因为这个工具是如此的用户友好和易于使用,所以缺乏深度定制和更“强大”的功能。对于普通的数据集和用户来说,这可能不是一个问题,但对于试图专注于美学或试图争论真正大规模数据集的团队来说,这个工具会带来问题。
谷歌数据工作室(谷歌)
谷歌数据工作室是这一领域的新玩家,是更广泛的 G 套件的一部分。这是商业解决方案中成本最低的产品,因此可能最适合较小的团队和组织。它也非常容易访问,并提供非常强大的免费计划,这使它成为原型开发或尝试数据科学和数据可视化的最佳选择。
Sample Google Data Studio Dashboard
定制解决方案
数据可视化领域的定制解决方案正在迅速发展壮大!代码库和开源贡献不断地使这个领域变得更容易被程序员和软件开发人员访问和使用,从而将这些类型的工作流注入到他们的项目中。我们在这里讨论的主要库植根于 Python 和 JavaScript 语言——2019 年最流行的两种编程语言。
尽管编码对新手来说可能是令人生畏的,但应该注意的是,许多这些库的存在是为了简化与工作的交互。仅仅因为有人可能想探索一个定制的解决方案,并不意味着它的每个部分都需要定制-他们可以选择一个“更高级”的库,该库抽象出他们不需要控制或定义的大量数据。
优点:定制、无购买成本、可扩展性、互操作性
缺点:维护,需要知识创造,时间
JavaScript 库
JavaScript 是数据可视化的一个很好的自然选择。由于它是在浏览器中运行的,所以它提供了在许多不同平台上接触观众的机会——移动、网络甚至桌面。出于同样的原因,在创建和管理可视化时,它允许高度的定制和交互性。如果我们可以控制屏幕/网页上的单个元素,我们就可以轻松地将数据点绑定到它们,并在这些点之间创建关系,进而创建有意义的视觉信息,供我们消费并转化为见解。这个用例中 JavaScript 的另一个好处是它的流行。随着继续保持“世界上最流行的编程语言”的头衔,这也意味着先例和例子随时可供学习。这可能看起来不是一个巨大的好处,但是由于许多这些库在本质上是【低级】,例子和先例对于快速开发是至关重要的,尤其是如果开发人员没有数据科学或前端背景的话。
JavaScript 没有给人留下深刻印象的地方是数据处理和操作过程。由于天生是单线程,当与 Python、Go 甚至 C#/C++之类的编译工具相比时,它在性能方面往往表现不佳。除了性能之外,也没有一个庞大的科学团体像 Python 那样致力于开发实用程序、库和包。仍然有大量的实用程序来完成这项工作,但是有时仅仅是为了可视化而处理数据就感觉像是一场艰苦的战斗。
著名的 JavaScript 库
D3.js
- 非常低级、陡峭的学习曲线
- 非常通用/模块化
- 高度可定制
- 样品
Charts.js
- 高水平,非常小的学习曲线
- 有限的定制,但是有很多开箱即用的功能
- 样品
Three.js
- 非常低的水平,非常陡峭的学习曲线
- 3D 可视化成为可能
- 有限样本作为三维数据仍是一个新兴领域
ECharts
- 高水平、小的学习曲线
- 受欢迎程度有限
- 样品
顶点图表
- 高水平、小的学习曲线
- 有限的可视化选项
- 样品
谷歌图表
- 高水平、小的学习曲线
- 有限的定制选项
- 样品
Python 库
Python 在这方面的优势和劣势几乎与 JavaScript 截然相反。虽然 JavaScript 并没有针对科学计算和数据处理进行优化,但是 Python 不仅如此,而且得到了一个为 Python 数据科学创建和支持开源工具的庞大社区的支持。像 SciPy 、 NumPy 和 Pandas 这样的库使得数据准备变得更快、更简单、更少挫折。使用 Python 堆栈的另一个好处是,使用相同的堆栈可以进行大量的机器学习开发。了解可视化工作流的语言和工具可以很容易地为 ML/AI 工作流设置一个。
就弱点而言,很难指出 Python 在数据可视化方面的具体方面——对于这个用例来说,它已经相当全面了。一个挑战是交付和共享创建的可视化。因为 JavaScript 是网络语言,所以将可视化嵌入到网络或移动体验中是很简单的,但是使用 Python,分发必须更仔细地计划。科学计算社区的一个流行媒介是 Jupyter,它也可以用于这个用例。
织女星/织女星建兴
- 中级,中等学习曲线
- “语言”输出格式是 JSON,而不是常规的 Python
- 样本
散景
- 中级,中等学习曲线
- 与 Python 科学计算社区完美集成
- 样品
牛郎星
- 高水平、小的学习曲线
- 围绕织女星的伟大的高层包装,提供互动
- 样品
- 高水平、小的学习曲线
- 非常少的代码获得有价值和可用的可视化。大型社区。
- 样品
阴谋地
- 高水平、小的学习曲线
- 在商业 Python 应用程序中日益流行
- 样品
摘要
追求数据可视化有很多不同的途径。积极的一面是,选择范围很广——从非常用户友好到完全低级和可定制。消极的一面是做出选择会很困难。做出选择应该是个人的决定-它应该与您的目标、组织的目标以及大规模实施这些解决方案之一所需的时间和培训的现实相一致。但最重要的是,它应该是关于沟通。我们可以集体“沉迷”于数据,我们同样可以欣赏华丽的数据驱动的图形,但我们也必须保持专注,即我们正在创造和交流信息以实施变革。实现这一目标需要的不仅仅是精通技术。
用 Kumu.io 实现网络制图中的数据可视化
原文:https://towardsdatascience.com/data-visualization-in-network-mapping-with-kumo-io-fe23d0986f3c?source=collection_archive---------18-----------------------
网络映射是一种非常有效的方式来显示网络中的关键变化点或关键利益相关者。Kumu.io 是一个免费的初学者友好的网络地图数据可视化平台。
在本教程中,我们将向您展示如何在 10 分钟内完成简单的网络映射可视化,而无需编写一行代码。
步骤 1:数据集配置
我们将使用 Kaggle 上的 特朗普的世界 数据集,其中包含 1500 多个与特朗普家族、他的高级顾问或他的内阁人选有联系的人/组织。
Kaggle’s Dataset
在这个数据集中,我们有三个工作表可以使用:
- 每一行代表一个人和另一个人之间的联系。
**Person_Org.csv**
:每行代表一个人和一个组织之间的联系。**Org_Org.csv**
:每行代表一个组织与另一个组织之间的联系。
在将数据导入 Kumu 之前,我们需要构建电子表格,以便 Kumu 能够读取。我们需要将每个电子表格的第一列标题改为From
,第二列改为To
,第三列改为Type
。
Example
你也可以从谷歌电子表格中导入数据。点击此处查看将数据导入 Kumu 的更多说明。
第二步:在 Kumu.io 上注册
只需创建一个免费的、无限制的公共项目的个人帐户。
步骤 3:创建新项目
Kumu 提供了四个模板:系统、涉众、SNA 和其他。
因为我们在这个样本中的目标是描绘唐纳德·特朗普的系统中涉及的人和组织,以及他们的关系。所以我们打算在本教程中使用Stakeholder
。
点击查看其他模板描述。
Kumu provides four templates
我们首先为Person_Person.csv
数据集创建一个映射Person-to-Person Ties
。
Create a map
步骤 4:导入数据
点击页面下方的绿色加号按钮->选择Import
- >选择您的文件(本例中为Person_Person.csv
) - >点击Import spreadsheet
- >点击Save import
。
Import data spreadsheet
我们现在可以看到数据被自动绘制成网络图。
Imported Succesfully
你可以移动鼠标或点击右边的按钮来放大和缩小,并探索。
步骤 5:定制可视化
默认的贴图不能给我们太多简单灰点的信息。所以我们要做一些配置,让它的信息量更大。
1。设置点的尺寸
我们想知道谁是特朗普网络中的关键利益相关者。
在页面右下方,找到Blocks
图标,选择Social Network Analysis
。
我们需要统计每个人的联系,所以我们选择了Degree
指标,然后点击Discover the connectors/hubs
。
度中心性是最简单的中心性度量,计算一个元素拥有的连接数。一般来说,度数高的元件是本地连接器/集线器,但不一定最好连接到更大的网络。
我们现在得到了拥有最高联系的人的结果。
Degree Centrality
关闭区块,在页面右侧,点击Settings
。
在SIZE BY
下,选择degree
,将量程改为between 0.5 and 20
。点击SAVE
。
Configure SIZE BY
现在,我们可以很容易地通过圆点的大小来区分人脉较广的人。
2。为照片设置圆点
灰点仍然不足以有效显示谁是关键利益相关者。我们需要为他们添加照片。
点击一个点。在左侧Profile
部分,点击摄像头标志并粘贴人物图像 url。
Set photos for dots
这是为点添加照片后的可视化效果。它变得比默认的绘图信息丰富得多。
现在我们完成了Person-to-Person Ties
地图。
现在让我们转到Org_Org.csv
数据集。从导入数据到配置点尺寸,重复上述步骤。你会得到一个类似下图的可视化效果。
3.配置点颜色
我们不想使用令人眼花缭乱的组织的图片作为他们的点。我们将使用简单的颜色来区分它们。
在Settings
中,通过 degree
设置颜色,将颜色更改为RdBu
或任何你喜欢的调色板。然后,viz 将看起来像这样:
4.向点添加标签
我们还想给点添加标签来显示组织名称。
在Settings
页面中,点击MORE OPTIONS
,选择Customize view defaults
。在**Element defaults**
下,将Element label position
改为center
。
Element defaults
在**Font defaults**
下,将Font color
改为白色,并增加Font size
。
Font defaults
现在我们完成了Org-to-Org Ties
地图。
Org-to-Org Ties
而现在你可以自己用最后一个数据集**Person_Org.csv**
练习了!
参考
- Kumu.io
- 特朗普的世界数据集
虚拟现实中的数据可视化
原文:https://towardsdatascience.com/data-visualization-in-virtual-reality-32408475b66?source=collection_archive---------33-----------------------
探索与创造
介绍
数据可视化,简单来说,就是数据的图形化表示。如今,它已经成为数据科学的重要组成部分。与原始数据相比,关键利益相关者对干净清晰的视觉效果反应更好,因为它们有助于快速有效地理解信息。目前有大量的可视化库在使用,其中最突出的是 matplotlib (Python)和 ggplot2 (R)。
然而,这些图书馆还没有在虚拟现实领域取得重大突破。随着技术在虚拟和增强现实领域取得有希望的进展,用户也可以在 AR/VR 中体验数据可视化是至关重要的。考虑到这一点,这个项目的目标是探索和创造虚拟现实中的数据可视化。
网络虚拟现实
目标是让每个人都更容易进入 VR 体验,不管他们有什么设备。正是因为这个原因,WebVR 被选为最佳媒体。WebVR 是一个实验性的 JavaScript 应用编程接口(API),为虚拟现实设备提供支持。它是一个开放的规范,也使得在浏览器中体验 VR 成为可能。体验 WebVR 需要两样东西:一个耳机和一个兼容的浏览器。
a 形框架
A-Frame 是一个用于构建虚拟现实体验的网络框架。A-Frame 基于 HTML 之上,使入门变得简单。但是 A-Frame 不仅仅是 3D 场景图或标记语言;核心是一个强大的实体组件框架,它为 three.js 提供了一个声明性的、可扩展的、可组合的结构。或者,可以创建一个 HTML 文件并在中包含一个 A 帧,如图 1 所示。
Fig 1: Example HTML file with A-Frame | Image by author
D3.js
A-Frame 构建在 DOM 之上,因此大多数库和框架都可以工作。这包括 D3.js,这是一个基于数据操作文档的 JavaScript 库。D3 使用 HTML、SVG(可缩放矢量图形)和 CSS(层叠样式表)帮助数据变得生动。D3 对 web 标准的重视为用户提供了现代浏览器的全部功能,而无需将自己与专有框架捆绑在一起,结合了强大的可视化组件和数据驱动的 DOM(文档对象模型)操作方法。例如,可以使用 D3 从一组数字生成一个 HTML 表,或者使用相同的数据创建一个交互式的 SVG 条形图,具有平滑的过渡和交互。
实施可视化 I
这个可视化的目标是从包含静态 JSON 文件的 URL 中读取数据,并在 VR 中创建一个条形图。相机的初始点将在图表的中心,各种棒线围绕着它。构建这个可视化需要两个文件——一个使用 A-Frame 实体定义页面主体的 HTML 文件,一个在读取数据后执行可视化的 Javascript 文件。图 2 描述了包含要可视化的数据的 JSON 文件。
Fig 2: Static JSON file | Image by author
XMLHttpRequest (XHR)
为了从 URL 中读取类似上面 JSON 文件的数据,有必要使用 XMLHttpRequest。XMLHttpRequest 是一个内置的浏览器对象,允许用 JavaScript 发出 HTTP 请求。尽管名称中有“XML”一词,但它可以处理任何数据,包括 JSON、HTML 或纯文本。人们可以上传/下载文件,跟踪进度,并使用 XMLHttpRequest (XHR)对象与服务器进行交互。用户可以从 URL 中检索数据,而不必进行完整的页面刷新。这使得网页可以只更新页面的一部分,而不会干扰用户正在做的事情。
Fig 3: Code Fragment — XMLHttpRequest | Image by author
在上面的图 3 中,执行以下步骤
- 创建一个 XMLHttpRequest 对象
- 所需的 URL 被分配给一个变量
- 用“GET”方法和指定的 URL 初始化 XHR 对象
- 连接被打开,并向服务器发送请求
- 听完响应后,将读取响应文本
- 使用 JSON.parse 将响应文本从字符串转换为 JSON,并存储在一个变量中
- 变量在处理数据可视化的函数中使用
浏览
在制定可视化函数并将 Javascript 文件与 HTML 文件链接后,仍然会出现错误。原因是代码段的第一行出现了“require”方法。“require”方法用于将模块包含在项目中,并将其用作基于浏览器的 XHR 对象。问题是虽然 Node.js 定义了“require”方法,但浏览器没有。使用 Browserify,可以编写使用“require”的代码,就像在 Node 中使用它一样。为了使用此功能,请遵循以下步骤
- “xmlhttprequest”是使用 npm 从命令行安装的
- 使用 browserify 命令,从 main.js(工作 js 文件)开始,所有需要的模块都被递归地捆绑到一个名为 bundle.js 的文件中
- HTML 文件中包含一个单独的
可视化功能
负责 DOM 操作和数据可视化的函数从 XHR API 获取数据。数据被推入数组,然后进行缩放以适合屏幕。A 帧“A 场景”被选中,“A 立方体”条被附加到它上面。随后,定义了条的各种属性,如高度、宽度、位置和旋转。“鼠标进入”和“鼠标离开”动画也是使用“过渡”方法定义的——这有助于鼠标悬停时扩展和照亮一个工具条。最后,可视化中位于条下面的标签以及所需的属性被组合起来。最终可视化的快照显示在图 4 中。
Fig 4: VR Visualization I | Image by author
实施可视化 II
第一个可视化只能从静态 JSON 文件中读取数据。如果可视化能够读取动态变化的数据,将会更加实用和有用。这是第二个视觉化的目标。它将借用 Visualization I 的基本结构和功能,同时添加实时更新自身的能力。
云 Firestore
在这个可视化中,因为数据不是来自静态 JSON 文件,所以不需要使用 XMLHttpRequest 和 Browserify。相反,这些数据是从谷歌 Firebase 的云 Firestore 获得的。Cloud Firestore 是一个灵活、可扩展的 NoSQL 云数据库,用于 Firebase 和 Google 云平台的移动、web 和服务器开发。它通过实时监听器保持客户端应用程序之间的数据同步,并为移动和 web 提供离线支持,以便用户可以构建响应迅速的应用程序,无论网络延迟或互联网连接如何都可以工作。对于这种可视化,使用具有多个文档的“费用”集合,如图 5 所示。
Fig 5: Cloud Firestore Database | Image by author
对于访问云 Firestore 数据库中的数据的可视化,HTML 文件中包含了一个
Fig 6: Code Fragment — Firebase Initialization | Image by author
下面图 7 中的代码解释了程序如何处理数据的变化。集合中的每个条目都属于“已添加”、“已修改”或“已删除”类型。代码中的 switch 语句通过操作输入数据来处理每一种情况。一旦数据被重新定义,它就被传递给处理可视化的函数。
Fig 7: Code Fragment — Switch Statement for Dynamic Data Manipulation | Image by author
可视化功能
正如前面提到的,第二个可视化的主要设计功能是从第一个借用的。场景、条和标签以相似的方式构造,具有相同的属性。增加的一个特性是,现在条形的颜色是基于条件的——如果值大于 50,则为紫色,否则为蓝色。然而,在这个可视化中添加的关键组件是文本注释,它被设计成每个条形上方的第二个标签。这些注释表示条形的高度,只有当鼠标悬停在条形上时才会出现。这使得查看者能够理解相对值并更有效地可视化数据。
同样的可视化最初是在常规 D3 上创建的,没有使用 A 帧 VR。这样做是为了测试与云 Firestore 数据库的交互,并用作 VR 可视化的参考。2D 可视化显示在图 8 中。
Fig 8: 2D version of Visualization II | Image by author
一旦观察到上述可视化实时更新自身,它就被转换到虚拟现实空间,如下图 9 所示
Fig 9: VR Visualization II | Image by author
结论
这个项目的目标是研究在虚拟现实中可视化数据的可能性。为了实现这一点,需要了解的关键组件是 WebVR、A-Frame 和 D3。WebVR 是用户体验可视化的媒介,A-Frame 提供了设置 VR 场景和实体的工具,而 D3 支持 DOM 操作和各种可视化属性的定义。
在 Visualization I 中,使用 XMLHttpRequest 和 Browserify 从静态 JSON 文件中读取数据,并生成相应的条形图。Visualization II 在基本功能上模仿了第一款,但数据来源于 Google Firebase 的云 Firestore。除了能够从数据库中读取动态数据之外,Visualization II 还具有自定义注释,当鼠标悬停在一个栏上时会出现这些注释。这使得用户能够理解条形的值和相对高度,从而体验数据的有效可视化。因此,可以看出,使用正确的工具和方法,数据可以有效地在虚拟现实空间中可视化。
未来的工作
这个项目只处理使用 A-Frame 的“a-cube”实体的条形图。可以使用各种其他实体构建许多不同类型的可视化。例如,饼图和圆环图可以分别使用“圆柱”和“圆环”实体来制作。当前的可视化是使用本地目录中的 HTML 文件在 web 上演示的。将来,这些可以通过谷歌、GitHub、GoDaddy 等网站发布。这将允许在互联网上共享可视化的能力,也将促进合作。
在这个项目的过程中,人们发现手头上关于这个主题的资料非常少。由于数据可视化还没有真正进入虚拟和增强现实领域,这个研究项目有望在不久的将来推动这一对话。
上述工作是南加州大学 Saty Raghavachary 博士指导下的定向研究项目的一部分。
你可以在这里找到我的项目的 GitHub 库和下面的可视化:-
可视化 I (VR)
可视化 II (2D)
可视化 II (VR)
数据可视化至关重要:对绘制市场数据替代方案的快速回顾
原文:https://towardsdatascience.com/data-visualization-matters-a-quick-review-on-alternatives-to-plot-market-data-de400ee640c5?source=collection_archive---------6-----------------------
数据可视化在量化交易中被高度忽视。在一个由算法主导的领域,对数据的视觉检查似乎不再相关,它属于自主交易,但事实上,这是正确分析和业余方法之间的关键区别之一。
数据可视化也是一个广泛的领域,它涵盖了几种图表和绘图类型。在金融市场中,有足够的空间来处理经典的直方图和散点图(根据我的经验,这些是最有用的)。绘制这样的图形非常容易,不需要任何特殊要求,因为几乎任何绘图/图表库都可以轻松处理它们。
这篇文章专门讨论市场时间序列图,通常是包括开盘价、最高价、最低价和收盘价的条形图或蜡烛图,加上成交量和/或未平仓合约。金融市场作为纯时间序列的本质创造了其他领域所没有的特殊需求和特殊性。
时间序列图——正如我们提到的,主要是蜡烛图和条形图——在市场投机和投资中起着重要作用。它们规范了我们展示和分析资产价格演变的方式。它特别适用于技术价格分析,因为大部分分析依赖于图表中的特定模式和趋势。
在量化交易中,数据可视化很容易被忽视,因为所有的焦点都放在算法上。这是一个巨大的错误,因为数据可视化在定义和验证策略中扮演着重要的角色。
在这篇文章中,我将介绍显示数据的不同选择。我们将主要回顾标准制图软件包、定制的高级独立制图库和软件包以及低级图形库。对于每个解决方案,我将描述其优点和发现的问题,并强调我认为与建立专业的市场数据分析方法相关的领域。
标准制图软件包
有许多著名的图表平台和软件包可以用来显示和分析市场图表。任何投资者或投机者都会有自己的图表软件,用于定期进行交易决策。大多数活跃的交易者也将使用该软件直接从图表中提交市场订单,这允许容易地设置利润和损失水平,警报,限制订单等。虽然这些图表平台提供了高度的灵活性,但它们通常被设计成处理交互式的、任意的和非标准的数据分析方式。
在小投资者和散户投资者最常用的两个平台中,我们发现了 ProRealTime 和 Metatrader。Metatrader 是一个轻量级的简单工具。尽管它有一定的局限性,而且只在场外交易市场使用,但它已经成为活跃的散户投资者中最受欢迎的工具之一;这可能是因为它已被全球大量零售 OTC 经纪人所采用。
Metatrader 4 is one of the most widely used chartings and trading platform for CFD instruments.
Pro RealTime 是另一个在小散户中广泛使用的工具。能力是比 Metatrader 好得多的功能,用于受监管的市场。它有更多的功能,如订单深度,体积概况和许多分析工具。
Pro RealTime is a well-known platform for regulated markets among retail investors.
这只是行业中众多可用工具中的两个例子。我选择这两个只是因为它们是我更熟悉的,但市场与许多其他知名平台一样重要。
虽然图表软件适用于自由市场分析和交易,但它们更侧重于传统交易,不太适合历史数据分析。他们希望有人在屏幕后面与工具交互,并且他们提供的灵活性是突出的。它是如此的出色,以至于我认为对于定量交易和系统的市场分析来说它是太多了。
复杂图表:多即是少
一个可以做任何事情的制图软件,在每一个可能的范围内,看起来都是一个好的选择,但事实并非如此。每个交易者在技术分析的旅程中都有一个共同的模式。在最初的几个月——当技术指标和方法被发现时——有一种趋势是用多种指标、趋势线、辅助线等进行过度复杂的图表分析。人们很容易认为越多越好,全套指标将导致更安全的操作。这种情况一直持续到复杂性达到稳定水平。从那一点开始,最大限度地简化图表是很常见的。这个过程可能会经历一个巩固反弹期,直到出现一个相当简单的情景。
简化的程度取决于每个人和使用的具体方法,有些人喜欢画一个只有价格和几个支撑位或阻力位的图表,有些人喜欢使用成交量、一两个指标(取决于使用的具体策略)和一些辅助的斐波纳契水平。
我们的目标是只有那些绝对必要的行,但是一些额外的指示器和一些辅助线有时会有所帮助。一些策略,如 Elliott wave 分析,需要更广泛的价格和时间延伸以及目标区域的绘图。常规的价格架构交易通常促进更少的图纸,以避免对价格正在做的事情分心。
更进一步的细节——例如是否使用网格、平均值、很少指标或没有指标等。—仍然更多地取决于每个人的特定偏好。
天平:似乎没人注意它们
灵活性可能成为问题的领域之一是规模。全权交易鼓励灵活处理几乎任何潜在的时间和价格组合,而量化交易鼓励更结构化的方法。而从更科学的角度分析任何事件,都要求测量尺度不变或者以可控的方式变化。用不同的价格尺度来观察市场是没有意义的。同样,在每次分析中使用不同的时间框架是没有意义的(一次半天,一天半秒,三天半三分之一)。此外,当用图表软件可视化市场时,除非你非常了解你正在跟踪的市场——这是必须要做的——否则你将无法理解给定的每日价格波动是否很大,以及这种波动通常发生的频率。
定量分析处理如此多的可能性,以至于需要定义分析发生的边界。在这样做的时候,建议总是用清晰明确的价格尺度来处理相同的时间框架设置。我并不是提倡为每一个分析建立一个单一和固定的设置,而是要使图表的观察方式专业化。
我们可以用制图学来做类比。地图的潜在比例可能有无限多种,但最终,专业制图师会定义一小组可用的比例,在行业中广泛使用,然后为每个特定地图选择更合适的比例。这样做可以更容易地评估每张地图。如果每张地图都使用不同的比例,或者每次分析特定地图都使用不同的比例,制图员就很难理解距离的大小。
任何比例都可以用于地图,但大多数组织已经确定使用几种常用比例
使用标准的制图软件通常会促进这种不同的比例场景,用户可以选择任何潜在的价格和时间比例,而科学方法则鼓励相反的情况:限制查看图表的方式。
我个人的制图方法是用价格变动直方图确定价格变动,然后在有限的范围内选择适合每个图表的比例。我没有统计数据或证据证明这种方法降低了风险或增加了利润,但这听起来像是一种公平的方法。
关于时间尺度,我也喜欢处理特定的、固定的时间段。日内是 24 小时——我最近倾向于使用美国东部时间来反映美国股市对全球市场的深刻影响——48 小时来应对超过一天的较大波动,5 天来应对每周波动,然后是双周、每月和每年。如果需要更长的时间,我会使用标准的图表软件。
这种固定时间段的方法显然与图表软件的灵活性相矛盾,在图表软件中,时间段通常由条形宽度、屏幕大小和缩放来定义。它们基本上显示尽可能多的信息。这可能被视为一种优势,但它基本上改变了你每次想要观察一个物体或事件的视角和距离。确实不是一个非常系统的方法。
历史数据:标准的图表软件不能很好地处理它
虽然图表软件可以很好地分析最近发生的事情——或者如果你绘制的是更长时间的图表,则不是最近发生的事情——但它通常是一个非常糟糕的工具,无法系统地观察更长时间内一天内发生的事情。获得两年前某一天发生的事情并不像人们想象的那么容易,而且很可能根本不可能,因为制图软件依赖于经纪人提供的实时数据,而经纪人通常会限制当天可用数据的数量。通常情况下,您将无法检索超过两周的信息。在一些图表工具中,在时间上向后导航图表实际上是非常困难的;它们是用来作为交易平台的工具,而不是历史和策略分析平台。
使用现有库定制图表
这些情况导致许多参与定量分析、密集回溯测试或历史分析的人最终不得不使用定制的图表软件。
尽管可以通过现有制图软件的 API 来利用这些软件,从而节省开发时间,但这种方法有很大的局限性,它将我们的软件和方法与第三方平台紧密结合在一起,而第三方平台可能会在未来改变其 API 或许可条款。
解决这个问题的最初方法是使用许多现有的图表库或已经可用的模块化软件包中的一个。虽然这似乎是一个好方法——并且通常是您要解决的第一个方法——但是它有局限性,最终很容易得出结论,利用现有的软件包是不够的。我为此专门测试了 Gnuplot 和 Matplotlib。
如果有一个众所周知的老派绘图软件,那就是 Gnuplot 。它是在 30 多年前设计的,至今仍是将绘图功能融入项目的最简单、最容易的方法之一。
Gnuplot 完美地遵循了 UNIX 的理念,即作为一个独立的工具,可以在操作系统级别与我们的软件进行管道连接或集成。它简单、功能强大、易于集成并且有据可查。作为一个特定的图表工具,它非常容易使用和集成,但是它的交互选项非常少。
虽然将鼠标和键盘事件与外部程序集成是可能的——Gnuplot 可以在事件上启动外部命令,并从标准输入控制台获取命令,这有效地实现了基本的接口实现,但是这种集成既不自然也不简单。它缺乏实现复杂的用户界面所需的速度和灵活性,并且将其与外部软件正确集成极其笨拙。
在我的测试中,我原型化了一个简单的 Gnuplot 实现。显示包含所有数据的图表很容易,但实现一个交互式用户界面来绘制趋势线或斐波纳契曲线被证明是复杂而缓慢的。事件处理很难,因为需要在您的软件和 Gnuplot 之间实现一个硬权重接口。它只是表现不好,并且在其操作中缺乏平稳性。规模也是一个问题。
发现 Gnuplot 等孤立的工具缺乏实现最小用户界面所需的集成—在绘制图表时,我们希望至少能够绘制趋势线、斐波纳契线和支撑位/阻力位—第二层复杂性是使用绘图库。Matplotlib 是一个完善的库,它有所有主要编程语言的包装器,并有更丰富的 API 来处理鼠标和键盘事件。
Matplotlib 作为绘图库在数据科学中被广泛使用和推荐,但它同样缺乏实现复杂用户界面的速度。
Matplotlib prototype implemented using Python wrapper showing an intraday chart for Telefonica stock (SIBE TEF ES0178430E18).
一个复杂的用户界面需要嵌入 Tkinter——或者任何其他更低层次的小部件工具包——如图所示。
我使用 Tkinter 实现了一个原型,虽然可以显示图表,但我再次发现处理鼠标和键盘事件并不容易。
Tkinter 也不使用 GPU 硬件加速,这将在复杂的图表中造成性能问题。此外,在处理布局时,使用 Matplotlib 会造成一定程度的复杂性,因为您处理的是一个嵌入式库,它并没有真正设计为与小部件工具包集成。
还值得一提的是,Matplotlib 有一个特定的财务扩展,可以即时绘制蜡烛图。然而,这种扩展不再被维护,并且实际上比常规的 Matplotlib 条形图更难使用(条形图可以垂直偏移,因此很容易用条形图和折线图的组合来绘制烛台)。我的建议是远离这个扩展,根据我的个人经验,它已经过时,功能性差,缺乏适当的文档,并且在最近的版本中不受支持。
低级图形库
一旦我们发现图表库对于静态图表来说很棒,但是它们的交互能力却远远没有用上,很明显我们需要一个底层的库,并且我们的实现必须覆盖基本的方面,比如缩放。在这方面,我尝试了两种方法:Cairo Graphics 和 Java2D/AWT。
我们不包括 Tkinter,因为我们包括了使用 Matplotlib 的原型,尽管另一个选项是在 Tkinter 中使用 Canvas 小部件直接实现图表。这意味着实现所有图表功能。由于没有仿射变换,并且 Tkinter 不使用 GPU 硬件优化,我们将发现性能更慢,编程更困难,因为我们需要在 Tkinter 中完全实现缩放。当前的硬件可以处理性能损失,但是增加代码复杂性可能是一个问题。我还制作了这个选项的原型——事实上这是我很久以前制作的第一个原型——我发现它太复杂了,没有用。
我们量化项目的最后一个原型测试包括 Cairo 和 Java2D。我们发现 GPU 的使用是必需的,并且从理论上来说 Cairo 看起来是一个不错的候选,但是在发现在 Windows 计算机上运行 Cairo 的复杂性之后,我在开始评估的同一天放弃了这个想法。让它运行起来是极其复杂的,我们认为这将是以后的发行和维护问题。
Java2D/AWT
对于新的开发,不推荐使用 AWT,它已经过时了,是在 90 年代包含在 Java 中的。Swing 是作为一种现代的替代品出现的,最近 JavaFX 是新开发的推荐方式。这个建议对于常规用户界面可能是有价值的,但是当处理财务图表时,我们将花费更多的时间处理面板和画布,而不是实际的小部件。由于 Swing 和 JavaFX 体积较大,使用 Java2D 和 AWT 是一个非常有效的解决方案,即使它们是有点过时的库。
Java2D 使用硬件加速,并且支持仿射变换。仿射变换的使用简化了实际价格和条形图的处理,有效地将我们的软件与窗口/设备尺寸分离。
Java2D/AWT prototype showing an intraday chart for CME GLOBEX 6E future contract.
我们的第一个原型是成功的,在不同的类中分离功能相对容易,实现的性能也很好。原型还允许堆叠底部和左侧面板。
我们计划将该原型进一步扩展为一个完整的工作解决方案,包括功能的完整封装、用于绘制辅助线和标高的自定义用户界面,以及提供体积轮廓和可选指示器/面板的能力。
摘要
尽管现有的图表软件有许多功能和灵活性,但它在定量交易和系统回测中的使用并不是最好的选择,建议使用定制的解决方案。
在面临的挑战中,我们可以强调需要简化图表中的信息,需要适当和一致的尺度(价格和时间),以及系统分析历史数据的复杂性,特别是当这些数据作为专有存储库存储时。此外,这些环境通常需要一定程度的自动化,这使得标准软件的使用变得复杂。
当只需要显示静态图表时,利用现有的绘图库或模块化软件(如 Matplotlib 或 Gnuplot)似乎是一个不错的选择,但它们的用户界面功能远非完美,并且这些库不是为金融时间序列图表的特性而构建的。
使用 Cairo 和 Java2D 等低级库是一个很好的选择,因为我们可以完全定制图表的呈现方式,尽管它们需要更多的开发工作,但它们的功能简化了开发,并且它们提供了硬件加速。使用仿射变换能力的可能性减少了开发时间,因为可以毫不费力地管理价格和时间尺度。
在这两个选项中,我发现 Java2D 是处理这种需求的最简单的选项,尽管肯定会有其他的选择。Java2D 的一个优点是它真正面向用户空间的 2D 矢量图形,这是您在处理这种图表时真正需要的。
我们没有介绍基于网络的库(如 TechanJS ),因为此时我们正在寻找一个桌面解决方案,但它们与标准绘图库一样复杂。它们的定制、集成和开发时间一点也不简单——它们通常建立在标准绘图库之上。如果 web 用户界面对您的项目有任何好处,那么它们显然是一个不错的选择。实现这一目标的另一个选择是使用 SVG,这是一种强大的图形语言,它使管理比例和用户界面像在网络上一样简单。SVG 没有被广泛使用,但是它非常容易使用,并且可以很容易地与 jQuery 和 Javascript 集成。
用 Tableau 实现优步游乐设施的数据可视化
原文:https://towardsdatascience.com/data-visualization-of-uber-rides-with-tableau-67988f61f712?source=collection_archive---------14-----------------------
这件作品的灵感来自于纽约优步游乐设施的演示样品。但我们将在 Tableau 中完成,无需编写任何代码。
你可以在我的 Tableau 页面这里找到我的作品。
该可视化创建了 2014 年 4 月至 5 月纽约市的优步游乐设施的视图。它旨在为消费者提供关于在一个月的不同天的不同时间段内,在不同的纽约市街区,优步乘坐次数如何变化的见解。
我们使用地图来显示乘坐次数的地理分布,使用柱状图来显示一天中不同时段的乘坐次数分布。
步骤 1:导入数据
我们将使用由 FiveThirtyEight 提供的数据。
你可以在这里找到如何将数据源链接到 Tableau 。
第二步:第一页—地图
1.画地图
将Lat
和Lon
从Measures
拖动到Columns
和Rows
绘制地图。
2.地图图层
我们想为我们的地图创建一个黑暗的主题,就像大多数地图可视化一样。
2.1.选择Map
->-
2.2.将Background
样式改为Dark
。
2.3.在图层中选择Streets, Highways, Routes
、Cities
。
地图现在显示了更多的地理信息。
3.颜色
3.1.将Date/Time
从Dimensions
拖动到Marks
->-
3.2.在Marks
部分点击Date/Time
右侧的下拉按钮,选择More
->-Hour
3.3.点击Color
->-Edit Color
,选择调色板Green-Gold
,点击Assign Palette
3.4.点击Color
->-Effects
->-Border
->-None
现在,高对比度的颜色使地图更加清晰。
4.过滤器
我们想在地图上添加过滤器,让用户选择特定的日期和时间。
4.1.将Date/Time
从Dimensions
拖动到Filters
,选择Month/Day/Year
,点击All
4.2.在Filters
部分点击MDY(Date/Time)
右侧的下拉按钮,点击Show Filter
4.3.点击表单上MDY(Date/Time)
右侧的下拉按钮,选择Single Value (drop down)
现在,我们完成了地图图表。
步骤 3:第 2 页—直方图
打开一个新工作表来创建直方图。
1.绘制直方图
1.1.将Date/Time(Hours)
从Dimensions
拖至Columns
,将Number of Records
从Measures
拖至Rows
。
1.2.点击轴名Number of Records
,取消选择Show Header
1.3.点击工作表中的轴名Date/Time
,选择Hide Labels
2.颜色;色彩;色调
我们将使用与地图相同的颜色主题。
2.1.将Date/Time(Hours)
从Dimensions
拖动到Marks
->-
2.2.将记录数从措施拖到Marks
->-Label
2.3.右击直方图,选择Format
->-Lines
->-Grid Lines
->选择None
2.4.右击直方图,选择Format
->-Shading
->-Worksheet
->选择黑色
我们完成了直方图。
第四步:仪表板
现在我们想创建一个仪表板来同时显示地图和直方图。
点击仪表盘,点击Format
->-Dashboard
->-Dashboard Shading
->-Default
->选择黑色
将工作表 1(地图)和工作表 2(直方图)拖到仪表板上,直方图位于底部。
分别在工作表标题上点击右键,点击Hide Title
1.工作表格式
1.1.点击Month, Day, Year of Date/Time
过滤器,点击应用到工作表,选择All Using Related Data Sources
。这样我们可以删除工作表 2(直方图)的Date/Time (Hours)
图例。
1.2.点击Month, Day, Year of Date/Time
滤镜,取消选择Show Title
1.3.点击工作表 1(地图)的Hour of Date/Time
图例,取消选择Show Title
1.4.点击表 1(地图)的Hour of Date/Time
图例,选择Floating
1.5.移动地图右侧的Hour of Date/Time
图例,调整地图大小以适应图例
2.添加文本描述
我们想添加一些描述,让用户更好地理解。
2.1.标题:将文本框拖到仪表板上,键入
UBER RIDES IN NYCApril - May 2014
2.2.说明:将文本框拖到仪表板上,键入Select the legends on the map or bars on the histogram to section data by time.
2.3.描述:将文本框拖到仪表板上,键入
TOTAL RIDES:SOURCE: FIVETHIRTYEIGHT
2.4.总乘坐次数
为了显示基于日期和时间过滤器的动态TOTAL RIDES
文本,我们需要添加一个新的工作表。
2.4.1.将Number of Records
从Measures
拖动到Marks
->-T20。纸张上应显示一个数字。
2.4.2.右击数字,点击Format…
->-Font
->-Worksheet
->白色
2.4.3.右击号码,点击Format…
->-Shading
->-Worksheet
->黑色
2.4.4.将新工作表拖到仪表板上
2.4.5.点击新建工作表->选择Hide Title
2.4.6.点击新建工作表->选择Floating
。拖动TOTAL RIDES
文本旁边的数字。
2.5.添加空白
在仪表板的必要位置添加空白,让文本垂直居中对齐。
现在我们完成了可视化。
参考
纽约优步游乐设施
数据可视化提示(Power BI)-将分类变量转换为虚拟变量
原文:https://towardsdatascience.com/data-visualization-tips-power-bi-convert-categorical-variables-to-dummy-variables-a53f20cdb4e?source=collection_archive---------15-----------------------
除了进行数据可视化,如绘制图表和显示 KPI,Power BI 还可以通过编写 DAX 语法来执行一些计算功能。但是,您可能会发现数据集中存在分类变量,这可能会对您计算某些值造成障碍。可能没有像 R 或 Python 中那样简单的代码将分类变量转换成哑变量。如果数据量很小或者只有 2 到 3 个类别,您仍然可以通过编写 if-else 查询或编辑查询中的条件设置来逐个转换变量。本文是为那些想在 Power BI 中快速完成一些简单的数据转换的人准备的。在本文中,我将向您展示一个分步指南,帮助您将分类变量转换为哑变量。
数据准备
我们将使用下面的足球数据作为演示。请下载并在您的 Power BI 文件中输入数据。
数据: 足球数据(2018/2019 赛季)来自 football-data.co.uk
导轨
首先,在将数据加载到 Power BI 中之后,转到“编辑查询”。
然后,选择分类列(选择列“FTR”进行演示),并单击“透视列”。
并选择适当的值列。
** Power BI 不允许您选择相同的列,即“FTR”列作为值列,但这可以在以后手动更改。*
之后,您将看到虚拟列出现在最右端。
但是,当您再次检查整个数据集时,您会发现列“Div”消失了,它是 Pivot 列设置中使用的值列。
如果你想保留这个栏目或者只是使用“FTR”作为“值”栏,请转到“高级编辑器”。
将“Div”改为“FTR”。这是将透视表列的值列设置更改为“FTR”,
最后,您成功地将分类变量转换为虚拟变量。
编辑的话
写一篇教程文章既不容易又费时。如果你喜欢阅读它,并且觉得它很有用,请分享给你的朋友。未来,我们会发布一系列的教程文章,敬请关注!=)
还有,如果你有兴趣了解更多的窍门和技巧,欢迎你浏览我们的网站:https://cydalytics.blogspot.com/
领英:
黄洋-https://www.linkedin.com/in/yeungwong/
卡丽洛-https://www.linkedin.com/in/carrielsc/
其他文章
- 用 Python 制作一个让孩子学英语、玩得开心的游戏
- 中文异形字云(Python)
- 数据科学基础(R):从 Excel 导入数据— readxl
- 数据科学基础(R):从文本文件导入数据— textreadr & readtext
- 数据科学基础(R):导入&导出 Excel 中的数据— xlsx
数据可视化—我应该使用哪些图表?(Seaborn 示例)
原文:https://towardsdatascience.com/data-visualization-which-graphs-should-i-use-55e214ee9cf1?source=collection_archive---------5-----------------------
Photo by Luke Chesser on Unsplash
如何可视化数据的简单指南
每天使用数据集使我更容易阅读和理解表统计信息。然而,虽然数字统计可能会为您提供数据的本质,但图表或可视化可以揭示数据集中潜在信息的全新维度。
当涉及到展示数据时,尤其是向客户展示数据时,使用可视化工具总是好的,它可以帮助展示您工作的范围和目的。你不希望只显示数据文件或代码,而是一组整洁的图表,使你的故事看起来更合理和清晰。
然而,为任何一组数据创建散点图并不意味着就可以了。当可视化数据时,理解三件事很重要。
- 您可以使用哪些不同类型的地块?
- 你应该用多少?你如何解释它们?
- 你能用这些情节讲一个故事吗?他们告诉你什么了?
下面,您将找到可视化类型、不同种类的图,以及何时使用和何时不使用它们。我试着尽可能地包括例子,但是如果你有任何问题没有回答,请在评论中自由发表。另外,如果你想完善数据可视化的艺术,你需要对不同的可视化类型和情节有深刻的理解。我会在这篇文章的末尾为感兴趣的人添加一些资源。
可视化类型
时间可视化
通常用于一维数据,显示数据点之间的某种线性关系。这种数据集通常将时间作为独立变量,因此,时间序列数据以这种方式可视化。
绘图类型:散点图、甘特图、时间线、时间序列折线图。
网络可视化
顾名思义,网络可视化就是将多个数据集相互连接起来,并显示它们在每个变量相连的网络中是如何相互关联的。
绘图类型:节点连接图、矩阵图、冲积图&依赖图。
分层可视化
当数据集包含相互连接的有序变量时使用。它可以用来显示父变量和子变量之间的关系,特别是当数据可以在不同的类别下聚集时。
绘图类型:树形图、树状图、旭日图、环形图。
多维可视化
当有多个维度时使用这些类型的绘图,并且在某些情况下可以创建 3D 图。尽管多维图本身可能很复杂,但它们可以承载大量的数据(和见解)。
策略类型: 2D/三维直方图、2D/三维散点图、饼图、条形图、折线图。
地块类型
条形图
由于通过它们易于理解数据,所以通常被使用。这可能是呈现数据的最基本的方式,但它有助于通过简单明了获得结果。下面是一个如何在 seaborn 上创建柱状图的例子。代码的正下方是输出。
Import Seaborn as sb
ds = {'Day':['Mon', 'Tue', 'Wed', 'Thu', 'Fri'], 'Hours':[8,7,11,9,6]}
dx = pd.DataFrame(ds)
sb.barplot(x='Day', y='Hours', data=dx)
Barplot output for seaborn.
何时使用: ——将同一类别或数据集中的几个变量与相似的变量进行比较。
-跟踪几个(1 或 2 个)变量随时间的进展。
不用时: -3 类以上变量
-可视化连续数据。
线形图
线图也很常见。当比较股票价格或分析一段时间内的视频视图时,线图几乎随处可见。主要的好处是它们非常直观,读者可以立即掌握结果。
sb.relplot(x='Day', y='Hours', kind='line', data=dx)
何时使用:
——跨时间跟踪比较几个变量。
-分析趋势和变化
-预测未来值。
何时不使用:
-获得数据的总体概述。
-分析单个组件或部分。
散点图
散点图也有多种应用,就像上面提到的其他两种图类型一样。它们可用于描述关系、查看数据的各个部分以及描述数据的分布。
scatplot = sb.relplot(x="RAM", y="Screen_size", data=data)
何时使用:
-分析单个点
-离群点分析和理解波动
-获得变量的总体概况。
不用的时候:
-找精度
-一维数据。
-非数字/分类数据。
面积图
面积图可能是这个列表中最接近线形图的东西,然而,两者之间也有一个关键的区别。面积图能够突出不同变量之间的差异或距离,让我们看到不同项目如何相互比较以形成一个整体。
x=range(0,5)
y=[ [0,5,6,1,2], [4,2,1,8,4], [9,6,3,2,4] ]
plt.stackplot(x,y)
何时使用:
-分析一个时间序列中整体的各个部分如何进展
-线形图的大多数用例
何时不用:
——单个周期内呈现整体的部分。
其他情节
https://upload.wikimedia.org/wikipedia/commons/8/87/Sample_Pie_Chart.png
- 饼图
当时:比较整体的部分或相对值。
当不在时:比较没有加起来形成一个整体的数据。
Heatmap generated using random numbers
热图
ud= np.random.rand(10, 15)
sb.heatmap(ud)
当时:两个变量之间的关系。
非时:个别变量。
x = np.random.normal(size=60)
柱状图
np.random.normal(size=60)
sb.distplot(x)
当时:几个变量或数据集跨时间变化。
非时:超过 3 个变量或数据集。
https://upload.wikimedia.org/wikipedia/commons/9/94/Normality_box-plot.png
- 箱线图
When :分析或比较数据集的分布。
不在时:分析单个数据集。
https://upload.wikimedia.org/wikipedia/commons/d/d8/Benin_English.png
- 树形图
When :比较分类数据中的变量。
当不时:非分类数据。
本文中没有提到许多其他的情节类型。这是为了涵盖常用地块类型的主要部分。希望这些信息对你有用!
资源
[## 什么是数据可视化?定义、图形类型以及如何使用它们
在某个时候,你可能已经看过、接触过或者制作过条形图。条形图是这样一个…
www.klipfolio.com](https://www.klipfolio.com/resources/articles/what-is-data-visualization) [## 研究指南:数据可视化:多维工具
有两类多维可视化。第一种着眼于类别比例;或类别…
guides.lib.k-state.edu](https://guides.lib.k-state.edu/c.php?g=181742&p=1196067) [## 选择正确的图表:在 14 种图表类型中选择
如果你想避免创建这样的图表,这是一篇完美的文章...或者这个...尤其是…
365datascience.com](https://365datascience.com/chart-types-and-how-to-select-the-right-one/)
关注 Rohan Gupta 了解更多关于数据科学的内容!
面向初学者的 D3.js 数据可视化
原文:https://towardsdatascience.com/data-visualization-with-d3-js-for-beginners-b62921e03b49?source=collection_archive---------4-----------------------
D3.js 可视化数据入门
你有没有走进一个拥挤的体育场或一场音乐表演,并试图猜测有多少人围着你?你错了吗?分析大量数据可能会让人不知所措。但是,当你把抽象的数据点转换成精确的、可观的视觉效果时,你将能够通过分析来看待事物。
Photo by Carlos Muza on Unsplash
这是一个信息时代,我们有足够多的数据,但只有少数人知道如何处理这些数据。人们对视觉的依赖远远超过其他任何东西。这就是为什么直观呈现的数据比简单的数字更有说服力。优秀的可视化可以抓住人们的注意力,而无尽的列和行的数字只能混淆他们。为了使这些可视化和分析成为可能,我们需要现有语言的框架或库。这就是 D3.js 发挥作用的地方。
D3 代表数据驱动文档。如果你计划在网络上创建自定义的可视化效果,很可能你已经听说过 D3.js 。一个基于 web 的可视化库,具有大量的 API 来处理在 web 上创建高级、动态和漂亮的可视化内容的繁重工作。
D3.js 是一个基于数据操作文档的 JavaScript 库。D3.js 帮助您使用 HTML、SVG 和 CSS 将数据变得生动。D3 对 web 标准的重视使您可以获得现代浏览器的全部功能,而无需将自己束缚于专有框架,将强大的可视化组件和数据驱动的 DOM 操作方法结合起来。
D3 完成的主要任务是,它允许将任何类型的数据绑定到 DOM,然后对其进行数据驱动的转换,从而在应用程序中轻松构建交互式数据可视化。
如果你有兴趣深入研究,D3 的 Github 库和 D3 使用的 API 文档也是很好的资源。
现在开始用 D3.js 吧。你可以打开你的 IDE 或编辑器,创建一个名为 index.html 的文件,只是为了玩玩 D3.js。在我们的应用程序中使用这个库就像直接添加链接来获得你在 index.html 创建的最新版本一样简单:
<script src="https://d3js.org/d3.v5.min.js"></script>
所以现在您已经准备好在您的示例应用程序中使用 D3.js 及其所有特性。
元素的选择
选择意味着从名称或 css 选择器中选择 html 元素。(例如:h2,p)然后在选择了元素之后,我们可以使用 D3 来操作和转换这些 html 元素。选择允许文档对象模型(DOM)的强大数据驱动转换:设置属性、样式、属性、 HTML 或文本内容,等等。使用数据连接的进入和退出选择,您也可以添加或移除元素来对应数据。
想象我们有一个简单的 html 页面如下。
<html>
<head>
<title>My sample HTML page</title>
</head>
<body>
<h1>D3.js</h3>
<p>I'm using D3.js here !</p>
<p>We all are using D3.js here !</p>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
d3.select('h1').style('color', 'green');
d3.selectAll('p').style('font-size', '30px');
</script>
</body>
</html>
这里有几件重要事情需要注意。所以这里用了两个关键词。这两种方法都使用元素名作为参数。第一个 d3.select() 方法返回与给定参数匹配的 DOM 元素的第一个选择。所以在上面的例子中会是
D3 . js
。第二个方法是 d3.selectAll() ,它返回对应于给定参数的所有 html 元素。如果它没有找到任何< p >标签,它将返回一个空选择。在给出的例子中 < p >我这里用的是 D3.js!< /p > 和 < p >我们这里都在用 D3.js!< /p > 两者都会返回。此外,您还可以看到在选择 DOM 元素之后所做的操作。我们可以改变样式,甚至改变显示的文本。因此,在我们的示例中,当它被呈现时,标题“D3.js”将是绿色的。
你可以点击查看选择的更多细节。
动态属性和数据绑定
D3 的另一个主要概念是以动态方式将一组数据映射到 DOM 元素。在这里,我们可以引入一个数据集,然后我们可以使用这些数据集实时更新、附加和显示 DOM 元素。
let dataset = [1,2,3,4,5]
d3.selectAll(‘p’) //Select 'p' element
.data(dataset) //data()puts data into waiting for processing
.enter() //take data elements one by one
.append(‘p’) //for each data item appending <p>
.text(‘Sample text’); //add sample text to each
这将在前端呈现文本“样本文本”5 次。这只是一个简单的例子,说明我们可以使用数据来动态和实时地操纵元素。使用同样的概念可以做很多事情。
数据可视化
既然我们现在对 D3 的基本概念已经很熟悉了,我们可以开始学习数据可视化组件,它包括各种类型的图表、数据表和其他可视化。
可缩放矢量图形(SVG)是一种在 DOM 中呈现图形元素和图像的方法。因为 SVG 是基于向量的,所以它是轻量级的,可伸缩的。D3 使用 SVG 来创建所有的视觉效果,比如图表。使用 SVG 的好处是我们不必担心缩放视觉效果时的失真,这与其他格式不同。基本上,D3 帮助我们弥合数据和相关可视化之间的差距,为用户提供有意义的信息。
让我们从使用 D3.js 创建一个简单的条形图开始。你需要两个名为 index.html 的文件,script.js 和 style.css,如下所示。
index.html
<html><head><link rel=”stylesheet” href=”style.css”><title>My sample D3.js App</title></head><body><h1>Bar Chart using D3.js</h1><svg width=”500" height=”800" class=”bar-chart”></svg><script src=”https://d3js.org/d3.v5.min.js"></script><script src=”script.js”></script></body></html>
script.js
var dataset = [28, 40, 56, 50, 75, 90, 120, 120, 100];var chartWidth = 500, chartHeight = 300, barPadding = 5;var barWidth = (chartWidth / dataset.length);var svg = d3.select(‘svg’).attr(“width”, chartWidth).attr(“height”, chartHeight);var barChart = svg.selectAll(“rect”).data(dataset).enter().append(“rect”).attr(“y”, function(d) {return chartHeight — d}).attr(“height”, function(d) {return d;}).attr(“width”, barWidth — barPadding).attr(“fill”, ‘#F2BF23’).attr(“transform”, function (d, i) {var translate = [barWidth * i, 0];return “translate(“+ translate +”)”;});
style.css
.bar-chart {background-color: #071B52;}
最终的条形图类似于这样。
这显示了可视化,但是除了趋势之外没有精确的信息。因此,我们的下一个任务是添加一些标签,以便每个条形的值将是可见的,从而在视觉上提供更多的信息。
为此,您可以在 script.js 文件的末尾添加以下代码片段。
script.js
var text = svg.selectAll(“text”).data(dataset).enter().append(“text”).text(function(d) {return d;}).attr(“y”, function(d, i) {return chartHeight — d — 2;}).attr(“x”, function(d, i) {return barWidth * i + 10;}).attr(“fill”, “#A64C38”);
这将产生如下所示的结果。
现在我们要做的是给我们的图表添加缩放比例。数据集中可以有不同的值;有些可能非常小,有些可能非常大。因此,为了更好地显示一致性,在图表中进行缩放是很重要的。
如果我们重新排列数据集,如下图所示,您可以看到条形图是如何呈现的。
var dataset = [2, 4, 5, 5, 7, 9, 12, 9, 10];
这样我们几乎看不到图表中的条形。所以我们必须根据图表的高度放大它。如果数据集中有较大的值,则不会显示给定图表高度内的准确高度。因此,解决方案是相应地扩展。为此,我们可以使用这样的定标器,并改变条形图。
script.js
var dataset = [2, 4, 5, 5, 7, 9, 12, 9, 10];var chartWidth = 500, chartHeight = 300, barPadding = 5;var barWidth = (chartWidth / dataset.length);var svg = d3.select(‘svg’)
.attr(“width”, chartWidth)
.attr(“height”, chartHeight);var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0, chartHeight])var barChart = svg.selectAll(“rect”)
.data(dataset)
.enter()
.append(“rect”)
.attr(“y”, function(d) {
return chartHeight — yScale(d);})
.attr(“height”, function(d) {
return yScale(d);})
.attr(“width”, barWidth — barPadding)
.attr(“fill”, ‘#F2BF23’)
.attr(“transform”, function (d, i) {
var translate = [barWidth * i, 0];
return “translate(“+ translate +”)”;
});var text = svg.selectAll(“text”)
.data(dataset)
.enter()
.append(“text”)
.text(function(d) {
return d;})
.attr(“y”, function(d, i) {
return chartHeight — yScale(d) — 2;})
.attr(“x”, function(d, i) {
return barWidth * i + 10;})
.attr(“fill”, “#A64C38”);
所以现在很明显我们的图表中遗漏了轴。因此,使用 D3.js 向我们的图表添加轴非常简单。您可以使用 D3.js 中的 x-scale 和 y-scale 创建 x 轴和 y 轴。您可以使用以下代码片段创建带有标签的缩放图表。
script.js
var dataset = [2, 4, 5, 5, 7, 9, 12, 9, 10];var chartWidth = 500, chartHeight = 300, barPadding = 6;var barWidth = (chartWidth / dataset.length -14);var svg = d3.select(‘svg’)
.attr(“width”, chartWidth)
.attr(“height”, chartHeight);var xScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0, chartWidth]);var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([0,chartHeight — 28]);var yScaleChart = d3.scaleLinear()
.domain([0, d3.max(dataset)])
.range([chartHeight — 28, 0]);var barChart = svg.selectAll(“rect”)
.data(dataset)
.enter()
.append(“rect”)
.attr(“y”, function(d) {
return chartHeight — yScale(d) — 20;})
.attr(“height”, function(d) {
return yScale(d);})
.attr(“width”, barWidth — barPadding)
.attr(“fill”, ‘#F2BF23’)
.attr(“transform”, function (d, i) {var translate = [barWidth * i +55, 0];
return “translate(“+ translate +”)”;});var text = svg.selectAll(“text”)
.data(dataset)
.enter()
.append(“text”)
.text(function(d) {
return d;})
.attr(“y”, function(d, i) {
return chartHeight — yScale(d) — 20;})
.attr(“x”, function(d, i) {
return barWidth * i + 70;})
.attr(“fill”, “#A64C38”);var x_axis = d3.axisBottom().scale(xScale);var y_axis = d3.axisLeft().scale(yScaleChart);svg.append(“g”)
.attr(“transform”, “translate(50, 10)”)
.call(y_axis);var xAxisTranslate = chartHeight — 20;svg.append(“g”)
.attr(“transform”, “translate(50, “ + xAxisTranslate +”)”)
.call(x_axis);
style.css
.bar-chart {background-color: beige;}
就像上面的简单条形图一样,我们可以创建我们想要的多种类型的图表。这里最好的事情是我们对自己创造的东西的控制。不像其他现成的图形,它们是有限可定制的,我们可以自由地使用 D3.js 中的 SVG 创建我们自己的图形。
D3 解决了问题的原因:基于数据的文档的有效操作。这避免了专有表示,提供了非凡的灵活性,展示了 HTML、SVG 和 CSS 等 web 标准的全部功能。以最小的开销,D3 非常快,支持大型数据集和交互和动画的动态行为。
您可以在 D3.js 图库中查看已经创建的复杂且有吸引力的图形。
https://www.d3-graph-gallery.com/
鉴于大多数人将 D3.js 称为数据可视化库,它不是。D3 更像是一个由不同部分组成的框架,比如 jQuery 部分(帮助我们选择和操作 DOM 元素)、Lodash 部分、动画部分、数据分析部分和数据可视化部分。
用 D3.js 尝试数据可视化,并与我分享结果!
使用 Python follow Maps 实现数据可视化
原文:https://towardsdatascience.com/data-visualization-with-python-folium-maps-a74231de9ef7?source=collection_archive---------8-----------------------
关于数据科学,我最喜欢的事情之一是数据可视化。我喜欢创建和利用视觉辅助工具来支持我的数据中的故事和趋势。python follow library 是我利用地理空间可视化分析能力的有用资源。换句话说,地图!
地图允许我在一个可视化视图中跨多个维度分析我的数据。在最近的一个项目中,我分析了 293 个美国城市,以确定哪些城市适合试点自行车和踏板车共享计划。通过使用 OLS 回归,我确定,在其他特征中,一个城市的拥堵程度(通过在交通中花费的驾驶时间百分比来衡量,从 INRIX.com 获得)与一个城市的“骑行能力”(通过 walkscore.com 的自行车评分来衡量)正相关且显著。虽然这一结果似乎有悖常理,但有理由认为,在更拥堵的城市,人们有骑自行车出行的动机(想想:“我不想坐在车流中,所以我要戴上头盔,骑着自行车去上班”)。
那么,我如何将“骑行能力”和拥堵之间的关系形象化呢?一个简单的 seaborn regplot 显示了自行车分数和交通流量之间的正线性相关性(通过交通中所花费的驾驶时间的百分比来衡量)。
sns.set(style = 'white')
sns.regplot(data=df, x="traffic_index", y="bike_score", ci = None)
plt.xlabel('Percentage of driving time spent in traffic', size = 16)
plt.ylabel('Bike score', size = 16)
plt.title("City bike score and overall traffic level", size = 20, weight = 'bold')
More bike-friendly cities are also more congested
但是如果我想在这两个维度上可视化城市的地理空间分布呢?嗯……使用地理空间分析,我可以创建一个地图,显示交通流量和自行车得分较高的城市。更好的是,改变地图标记的颜色和大小等属性意味着我可以使用一个图形来可视化所有三个维度。
为了创建这个地图,我首先安装了 Python 的 follow 库。
!conda install -c conda-forge folium=0.5.0 --yes
import folium
import webbrowser
我想展示的第一个维度是地理定位。我根据简单的谷歌搜索“美国经纬度”的结果设置了地图的经纬度。然后,我定义我的地图(巧妙地命名为 traffic_map)在这些坐标上初始化。默认缩放设置为 5(我不得不摆弄这个参数,直到我找到一个好的显示)。
latitude = 37.0902
longitude = -95.7129traffic_map = folium.Map(location=[latitude, longitude], zoom_start=5)
第二个维度是交通拥堵。我将我的流量变量(“流量指数”)分成四分位数:
df['traffic_index_quartile'] = pd.qcut(df['traffic_index'], 4, labels=False)
接下来,我为我的马克笔的颜色创建了一个字典。我决定了从浅蓝色(0)到红色(3)的一系列原色。我希望最高的四分之一(即最拥挤的城市)用醒目的红色突出,最低的四分之一(即最不拥挤和最不可行的候选城市)或多或少地消失在基本地图中。
colordict = {0: 'lightblue', 1: 'lightgreen', 2: 'orange', 3: 'red'}
边注:我从这个栈溢出帖子中找到了可行的颜色名称:
https://Stack Overflow . com/questions/36202514/foil um-map-module-trying-to-get-more-options-for-marker-colors。我已经尝试了列出的大多数颜色,它们都准确地显示了它们的名字,除了“浅红色”,它要么导致错误,要么显示为黑色。
我的地图上的第三个也是最后一个维度是城市“骑行能力”。为了可视化这个维度,我将城市标记的大小设置为城市 bikescore 的 0.15 倍(这是我必须反复试验直到它“看起来”正确为止的另一个参数)。
最终地图的完整代码如下:
for lat, lon, traffic_q, traffic, bike, city in zip(df['latitude'], df['longitude'], df['traffic_index_quartile'], df['traffic_index'], df['bike_score'], df['city']):
folium.CircleMarker(
[lat, lon],
radius=.15*bike,
popup = ('City: ' + str(city).capitalize() + '<br>'
'Bike score: ' + str(bike) + '<br>'
'Traffic level: ' + str(traffic) +'%'
),
color='b',
key_on = traffic_q,
threshold_scale=[0,1,2,3],
fill_color=colordict[traffic_q],
fill=True,
fill_opacity=0.7
).add_to(traffic_map)traffic_map
通过这种地理空间数据可视化,我们可以快速看到关于城市和自行车的两个事实。首先,“骑行能力”与交通拥堵正相关。其次,高交通流量和“骑行能力”(即大红色标记)的城市更有可能出现在美国东北部、加利福尼亚州和太平洋西北地区(有几个明显的例外)。
在这里 查看我关于完整项目 的帖子。欢迎在评论中留下反馈或想法!
使用 Seaborn 和 Plotly_ 人均 GDP 和预期寿命数据集的 Python 数据可视化
原文:https://towardsdatascience.com/data-visualization-with-python-using-seaborn-and-plotly-gdp-per-capita-life-expectency-dataset-cd5426e7ab3b?source=collection_archive---------8-----------------------
当社会和经济科学与数据科学和谐一致时。
Photo by Lukas Blazek on Unsplash
本教程旨在帮助您快速入门并使用 python 数据可视化库。我选择 seaborn 和 plotly,这是最常用和最棒的工具,用来可视化完全交互的图,并使数据看起来很棒。
你也会发现经济和社会因素之间的关系。我们将在此图中处理的数据集是世界各地的人均 GDP、社会支持、健康预期寿命、选择自由、慷慨程度等。
我用 jupyter 笔记本,你可以从 Anaconda 包中获得访问权限。
如果你想在这里安装蟒蛇。
Seaborn 简要概述
Seaborn 是一个基于 matplotlib 的可视化库,它与 pandas 库配合得非常好。
使用 seaborn 的原因之一是它可以生成漂亮的统计图。认识到 seaborn 是 matplotlib 的补充而不是替代是非常重要的。
要安装 seaborn,您可以在命令行或终端使用 pip 或 conda ,其中包括:
!pip install seaborn
or
!conda install seaborn
- 导入库
让我们从导入几个库开始,numpy(数字 python 库),pandas 用于数据帧和数据系列,seaborn 和 matplotlib 用于可视化。
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline #use it to show plot directly below the code
2。使用熊猫读取数据
该数据在 csv 文件格式中称为“2019.csv”。这就是我们将在本教程中使用的数据集。
head()函数返回数据帧的前 5 行,如下所示:
df= pd.read_csv('2019.csv')
df.head()
分布图
1.距离图:
我在这里做的只是使用 SNS . distplot(dataofsinglecolumn)绘制数据框架(人均 GDP)中单个列的分布。
要删除核密度估计图,您可以使用 kde=False 。
bins = 30 表示定义直方图形状的 bin 数量,我在左侧图中使用了 8 个 bin,在另一个图中使用了 30 个 bin,这样您就可以看到差异。
sns.distplot(df['GDP per capita'], bins=8)
out[5]sns.distplot(df['GDP per capita'], **kde = False** , bins = 30)
out[6]
****
2.联合策划:
Seaborn 的 jointplot 显示了两个变量之间的关系。
此处使用散点图和直方图显示了数据中 x 和 y 两列的图。
sns.jointplot(x=df['GDP per capita'], y= df['Healthy life expectancy'],data=df) #two ditribution
您可以在下面添加要绘制的绘图类型,例如,kind='reg '表示绘制带有回归线的散点图,kind='hex '表示将数据分成六边形,在空白处绘制直方图。
你可以看到人均 GDP 和健康预期寿命是正相关的。意味着如果人均 GDP 高,健康的预期寿命也会高。
sns.jointplot(x=df['GDP per capita'], y= df['Healthy life expectancy'],data=df,kind='reg') #plot in the right sidens.jointplot(x=df['GDP per capita'], y= df['Healthy life expectancy'],data=df,kind='hex') # plot in the left
****
sns.pairplot(df)#relationship entire datasets
令人惊讶的是,一行简单的代码给了我们整个情节!
这代表了整个数据集之间的关系。直方图允许我们看到单个变量的分布,而散点图显示两个变量之间的关系。
分类图:柱状图
柱状图用于绘制分类变量示例性别男/女…
在这里,我使用国家作为类别,并使用 head()函数绘制前 3 个国家的人均 GDP。
sns.barplot(x=df['Country or region'].head(3),y=df['GDP per capita'],data=df)
矩阵图
我在这里所做的是选择 4 列数据,并使用 corr()函数来查找所选数据之间的相关性。
# Matrix form for correlation data
data_select = df[['GDP per capita','Social support','Healthy life expectancy','Perceptions of corruption']]
data_select.corr()
您可以在这里看到一个矩阵形式,它表示某种值,这些值代表相关程度,相关程度通常在-1 到 1 之间。
如果 corr 值接近 1,这意味着变量有很强的正相关性。
sns.heatmap(df_select.corr(), cmap='coolwarm')
在这里,热图真正做的是根据某种梯度标度将数据相关值表示为图表中的颜色:
您可以通过添加 cmap= '…'来更改颜色地图,例如'绿色','蓝色','凉爽温暖'…对于所有的颜色地图,请查看:http://matplotlib.org/users/colormaps.html
非常简单的概述
Plotly 是一个数据可视化库,可以用来创建不同类型的交互式图表、地图和绘图..
此处 plotly 网站
你能做的第一件事就是安装 plotly 和袖扣库。
袖扣与熊猫有着紧密的联系,除非安装了袖扣,否则你无法从数据框中绘制出情节。
!pip install plotly
!pip install cufflinks
要连接 chart_studio,您可以到主页 plotly 注册并在设置帐户中获取您的 api_key。
由于 plotly 是一个在线平台,必须输入登录凭证才能在在线模式下使用。
chart_studio.tools.set_credentials_file(username='XXXX, api_key='xxxxxxxxxx')
加载库
下面导入 jupyter 笔记本上的 plotly 和袖扣,还有 chart_studio、plotly 工具和 graph 对象。
cf.go_offline()
cf.set_config_file(offline =False , world_readable= True)
在本文中,我们将使用在线模式,这对于 Jupyter 笔记本来说已经足够了。
折线图
首先,我选择数据集中的两列;健康的预期寿命和人均 GDP,然后我为标题名和 xaxis / yaxis 名创建了一个字典,并将它们放在布局对象中。
我用 dict()函数举例;dict(a=8,b=10)代替{"a": 8," b": 10 }
要将 dataframe 绘制为折线图,您只需调用 dataframe 对象的 iplot 方法。
cufflinks 和 plotly 允许使用语法 data.iplot 绘制数据,然后传入文件名和创建的布局。
data= df[['Healthy life expectancy', 'GDP per capita']]layout = dict(title = 'Line Chart From Pandas DataFrame', xaxis= dict(title='x-axis'), yaxis= dict(title='y-axis'))data.iplot(filename='cf-simple-line-chart', layout=layout)
散点图
mode 参数应该总是设置为" markers ,默认情况下 plotly 会在数据点之间绘制线条。所以如果你想要没有线条的点,你需要确保设置绘图模式为标记。
就像前面的例子一样,我们需要一个 fig 对象,它应该是一个 dictionary 对象,包含两个字典,一个用于数据,一个用于布局。
在数据字典中,我们定义了两组要绘制的 x 和 y 变量,在两个图中,x 变量将是相同的,这允许比较与国家列相关的人均 GDP 和健康预期寿命。
然后,我使用 data.go 语法创建包含 data1 和 data2 的数据对象,并将其赋给 mydata 变量。
还要创建布局对象,并传入散点图的标题。
**data1**=go.Scatter(x=df['Country or region'],y=df['GDP per capita'], name="GDP per capita", **mode="markers"**) **data2**=go.Scatter(x=df['Country or region'],y=df['Healthy life expectancy'],name="Healthy life expectancy",**mode="markers"**)mydata = go.Data([data1, data2])mylayout = go.Layout( title="GDP per capita vs. Life expectancy")fig = go.Figure(data=mydata, layout=mylayout)chart_studio.plotly.iplot(fig)
这就是我们使用 chart_studio 包绘制的图!
这里相同的代码,但我使用模式=“线+标记”,它将连接数据点作为线,同时显示散点图。
创建条形图
这里展示了如何在 plotly 中自定义颜色。
这里我们需要使用一个名为 color_theme 的字典对象,我们将生成一个颜色列表,其中包含我们要在条形图中使用的颜色的 RGBA 代码。
color_theme = dict(color=['rgba(169,169,169,1)', 'rgba(255,160,122,1)','rgba(176,224,230,1)', 'rgba(255,228,196,1)',
'rgba(189,183,107,1)', 'rgba(188,143,143,1)','rgba(221,160,221,1)'])
现在我将向你展示如何使用 plotly 创建条形图。
这里我们使用 trace 对象来指定我们想要的图表类型。所以在这种情况下我们使用 go。Bar() 函数然后我们传入两个变量 x 和 y,分别代表 7 个国家的人头数据和健康预期寿命,还传入我们已经定义好的 color_theme。
现在,让我们指定我们的布局参数,在这段代码中,我只使用一个参数来命名我们的绘图标题,您可以添加 x 轴和 y 轴名称。
最后,使用 iplot()函数绘制它,然后传入我们的数据。
trace0 = **go.Bar**(x=df['Country or region'].head(7), y=df['Healthy life expectancy'], **marker=color_theme**)data = [trace0]layout = go.Layout(title='Healthy life expectancy')fig = go.Figure(data=data, layout=layout)chart_studio.plotly.iplot(fig, filename='color-bar-chart')
箱形图
通常在统计学中使用的箱线图,它通过测量数据集的中值、平均值和众数,为我们提供了有关数据如何分布的更多信息。
在下面的代码中,我们只选择了 2 列数据,然后我们使用 iplot 方法,并传入一个参数来指定绘图的类型,然后我们给出了箱线图的文件名。
df_select = df[['GDP per capita','Healthy life expectancy']] df_select.iplot(kind='box', filename='box-plot')
圆形分格统计图表
在这里,我使用 10 个国家的指数作为标签创建了一个简单的饼图,并绘制了每个国家的人均 GDP 值。
然后使用 go 创建一个 gragh 对象。Pie()并填写标签和值变量。最后,使用 iplot()函数绘制这个图。
labels = df['Country or region'].head(10).value_counts().index
values = df['GDP per capita'].head(10).values
trace = go.Pie(labels=labels, values=values)chart_studio.plotly.iplot([trace], filename='basic_pie_chart')
等值区域图
使用 plotly 是用 python 生成地图的最简单的方法。
我们有两种主要类型的绘图对象;数据对象和布局对象。****
首先,我们需要数据传入字典,并为地图中的数据设置参数。让我们从传递 choropleth 类型开始,这意味着我们希望 plotly 生成什么类型的地图。然后定义我们的色阶,反转色阶,黄色向下,紫色向上。我们将位置设置为数据帧中的国家,z 变量由地图中的颜色表示。最后,我们将传入文本参数来定义在地图上移动时显示的文本。
其次,创建一个布局字典来设置我们地图的标题。然后创建一个包含数据和布局对象的新字典,我们称之为 fig。
为了绘制它,我们只需在 fig 对象上调用 iplot 方法,然后给出一个文件名。开始了…
data = dict(
**type = 'choropleth'**,
colorscale = 'Viridis',
reversescale = True,
locations = df['Country or region'],
locationmode = "country names",
z = df['GDP per capita'],
text = df['Country or region'],
colorbar = {'title' : 'GDP per capita_world'},
)
layout=dict(title_text = '2019 GDP per capita by State')
fig = go.Figure(data=data,layout=layout)chart_studio.plotly.iplot(fig, filename='choropleth')
结论
数据可视化是一个很好的工具,可以让数据更具可读性,并为您在现实世界中发现更多见解创造了巨大的机会。
这篇文章的所有代码都是 GitHub 上的 。图表都是交互式的,可以在查看,这里 。****
我欢迎反馈。我可以在 Linkedin 这里找到我。
数据仓库|维度建模|用例研究:电子钱包
原文:https://towardsdatascience.com/data-warehouse-dimensional-modelling-use-case-study-ewallet-d9d16f559181?source=collection_archive---------9-----------------------
通过用例解释技术概念总是更有意义。
基于我以前作为数据工程师和分析师的经验,我将使用一个电子钱包案例研究来解释数据仓库和维度建模。——马诺基
数据仓库
数据仓库是与业务相关的历史数据的大型集合,可用于制定业务决策。
- 数据仓库存储聚合的事务性数据,这些数据经过转换和存储后用于分析目的。
- 数据仓库存储来自多个来源的数据,这使得分析更加容易。
简单地说,数据库(运营)系统是你放入数据的地方,而数据仓库(商业智能)系统是你取出数据的地方—拉尔夫·金博尔
维度建模
维度建模是设计数据仓库的广泛使用的技术,主要是因为它同时解决了以下两个需求:
- 提供业务用户可以理解的数据。
- 提供快速查询性能。
Core elements of the Kimball DW/BI architecture
该图显示了从操作数据源到分析工具构建数据仓库所涉及的主要组件,以通过 ETL(提取、转换、加载)过程支持业务决策。
现在让我们以电子钱包的用例为例,使用维度建模技术构建一个数据仓库。
用例
背景
这家在线零售公司的特色之一是电子钱包服务,这种服务可以用来支付在该平台上购买的产品。
用户可以通过三种不同的方式获得积分:
- 当已付款的产品购买被取消时,退款作为取消信用。
- 用户可以获得礼品卡积分作为礼物。
- 如果用户具有差的服务体验,则可以提供 soo-sorry 信用。
如果是礼品卡信用和 soo-sorry 信用,电子钱包中的信用将在 6 个月后过期,但如果是取消信用,则在 1 年后过期。
要求
公司的财务部门希望在电子钱包服务上建立报告和分析,以便他们可以了解公司的钱包负债程度。
他们想要回答的一些问题如下:
- 电子钱包服务的每日信用余额是多少?
- 下个月会有多少贷款到期?
- 特定月份的信贷结果是什么(即已用百分比、过期百分比、剩余百分比)?
解决方案设计
在维度模型的设计过程中做出的四个关键决策包括:
1.选择业务流程。2.申报粮食。3.确定尺寸。4.确定事实。
让我们写下电子钱包案例的决策步骤:
1。假设:设计是基于给定的背景(业务流程)开发的,但也要考虑到灵活性。假设所有必填字段都可以从公司的交易数据库中获得。
2。粒度定义: 原子粒度是指给定业务流程捕获数据的最低级别。
在这种情况下,可以捕获的最低级别的数据是电子钱包交易,即电子钱包上的所有信用和借记交易。
3。维度: 维度提供了围绕业务流程事件的“谁、什么、哪里、何时、为什么和如何”的上下文。
尽管可以添加大量的描述性属性,但设计维度仅限于当前的业务流程,但该模型可以根据需要灵活地添加任何更多的细节。(以 Dim 为前缀的表名)
维度表:
-
DimWallet
-
DimCustomer
-
DimDate: 该维度包含所有与日期相关的解析值,如日期中的月份、日期中的星期、星期几等。这将非常方便地获得基于时间的报告。
4。事实: 事实是来自业务流程事件的度量,并且几乎总是数字。
事实被设计成关注具有完全可加性的事实。即使一些业务流程需求想要非累加的事实(已用百分比、过期百分比、剩余百分比等)。这些值可以通过单独计算附加事实来有效地获得。事实表中的每一行都代表了物理上可观察到的事件,而不仅仅关注于所需报告的需求。
事实表:
- FactWallet
星型模式模型
下面是电子钱包服务的维度模型的逻辑图。
eWallet — Star schema Dimensional Model
Ralph Kimball 是数据仓库技术的先驱,他总是在他的书中展示商业价值的重要性。星型模式比雪花型模式更受青睐,因为它具有更强的分析能力。
参考
[1] Ralph Kimball,Margy Ross,《数据仓库工具包,第二版,维度建模完全指南》
使用 Pandas 库的数据争论
原文:https://towardsdatascience.com/data-wrangling-using-pandas-library-ae26f8bbbdd2?source=collection_archive---------22-----------------------
在本文中,我们将看到一些最有用的技术,用于清理和处理熊猫图书馆的数据。
Photo by Kevin Ku on Unsplash
数据科学涉及数据的处理,以便数据可以很好地与数据算法一起工作。数据角力是处理数据的过程,如合并、分组和连接等。Pandas 库提供了有用的函数来支持数据争论任务。
因此,如果你问任何数据分析师、数据科学家或统计学家,他们把大部分时间花在哪个任务上,答案将是数据清理或数据争论和数据操纵,而不是编码或运行使用数据的模型。
与 Python 争论数据的目标:
- 从众多来源收集数据以揭示更深刻的情报。
- 及时向业务/数据分析师提供可操作的准确数据。
- 减少收集和整理的时间。简而言之,在数据被使用之前对其进行清理。
- 让数据分析师和科学家专注于数据分析,而不是争论。
- 帮助组织中的高层领导做出更好的决策。
我们将在本文中讨论以下主题。
- 数据探索
- 查找缺失值
- 过滤数据
- 整理
- 合并和串联
数据探索
在对数据进行任何操作之前,第一步是定位文件(csv、excel 和 xlsx 等)。),然后通过内置的 Pandas 函数读取它。在我的例子中,我将*train.csv*
文件存储在我正在处理的同一个目录中。
import pandas as pd
df = pd.read_csv('train.csv')
df.head()
Top 5 rows
df.dtypes
Output
从上面的代码摘录中,我们探索了我们的数据及其类型。现在我们通过*describe()*
函数来描述数据。
df.describe()
Statistics of data
*describe()*
给出了关于数据的见解和一些有用的统计数据,如平均值、最小值和最大值等。
处理缺失值
你的数据集可能包含许多缺失和重复的值,因此在对它们应用任何机器学习算法之前,我们(数据科学家)有责任处理它们。如果我们为我们的机器学习模型提供尽可能多的干净和准确的数据,那么我们训练的模型就会预测尽可能多的准确预测。
我们可以将总缺失值总结如下:
df.isna().sum()
Sum of missing values
我们已经确定了数据集中缺失的值,现在我们有几个选项来处理它们,要么我们可以删除那些包含缺失值的行,要么我们可以计算平均值、最小值、最大值和中值等。如果缺失值的行数占百分比很大(大约。20% — 30%),那么放弃它们将不是一个好的选择。所以你的工作是检验各种技术并明智地采取行动。
从上面的输出可以看出,*Embarked*
列中缺失值的数量只有 2,但是*Cabin*
和*Age*
列的数量很大,所以我们不能忽略它们。首先,我们将删除包含列*Embarked*
中缺失值的行,然后计算列*Age*
的平均值,并用平均值填充它们,并从数据集中删除列*Cabin*
。
# fill in the missing values in 'Age' column
age_mean_value=df['Age'].mean()
df['Age']=df['Age'].fillna(age_mean_value)
拆下立柱*Cabin*
df.drop("Cabin",axis=1,inplace=True)
Dataset after dropping Cabin Colum
过滤数据
下面这段代码对年龄大于 40 的整个数据集进行筛选,这意味着它将只包含那些列年龄大于 40 的行。
filtered_age = df[df.Age>40]
filtered_age
Filtered by age>40
如您所见,最初有 891 行,按年龄过滤后,只剩下 150 行。
整理
*sort_values*
功能可以帮助你对数据帧进行升序或降序排序。默认情况下*sort_values*
函数使用*quick sort*
算法进行排序,如果您想使用*heap sort*
或*merge sort*
等。然后可以使用*kind*
关键字。
# let's sort the column Name in ascending order
sorted_passengers = df.sort_values('Name',ascending=True,kind ='heapsort')
# now print the sorted data
sorted_passengers.head(10)
在这里,我根据*Name*
对数据集进行了排序
Sorted Dataset
合并和串联
Pandas 有*merge*
函数来合并两个数据帧,这是一个非常简单的函数。我已经从数据集中提取了上面两行和下面两行,并通过*Pandas*
*merge*
函数将它们组合起来。
*head()*
和*tail()*
函数分别返回顶行和底行,而*outer*
帮助合并两个不常用的行。
merged_df = pd.merge(df.head(2),df.tail(2),how='outer',indicator=True)
merged_df
Merged two dataframe
结论
我们已经看到了如何使用 Pandas 库处理和清理数据集,以及如何执行各种技术来清理数据集。
如果你对这篇文章有任何疑问,请随时问我,我会尽力解决你的疑问。
要获取我的 Jupyter 笔记本和数据集,请点击这里。
我希望你喜欢读这篇文章,你也可以访问我的 网站 ,在那里我会定期发布文章。
订阅 我的邮件列表,直接在您的收件箱中提前获得我的文章,或者关注我自己在 Medium 上发表的文章The Code Monster以完善您的技术知识。
了解你的作者
希曼舒·维尔马毕业于印度勒克瑙的 APJ 阿卜杜勒·卡拉姆大学博士。他是 Android & IOS 开发人员、机器学习和数据科学学习者、金融顾问和博客作者。
数据存储
原文:https://towardsdatascience.com/databaiting-d26cad4c49ca?source=collection_archive---------20-----------------------
Photo by @kxvn_lx
获取数据的有趣方式
拉一个社会成员(通常被科技公司称为用户提交他们的数据的过程正在成为一种常见的做法。一个吸引你的有趣活动与未经明确同意的用户数据销售形成鲜明对比。在这篇文章中,我建议对这个过程使用简写短语 databaiting 。
当你加入一项服务或购买一件产品时,谁购买你的数据通常不是你所知道的,而是一个发现的过程。激动人心的用户之旅?
在写这篇文章时,我无意冒犯,而是想让你更加意识到你提供的数据是如何被使用的。如果你开始质疑你提供数据的公司,首先质疑数据是什么,那也很好。我们或许可以谈论负责任的数据贡献,但我不确定这在实践中如何发挥作用。
在定义这个术语之前,让我们看几个简短的例子,当然是为了好玩,看看你是怎么想的。
23andMe 和祖先 DNA
乐趣:看看你从哪里来,哇!和你的亲戚联系。
数据:来自唾液和家谱的基因数据。
购买者/合作者示例:基因药物研究。
iRobot 物联网家居产品
有趣的是:一个打扫你房间的机器人!
资料:私宅地图。
购买者/合作者示例:谷歌广告。
亚马逊 Alexa 智能音箱
乐趣:命令演讲者做事!
数据:语音数据和行为数据。
买家/合作者:供亚马逊内部使用和/或最高出价者。
宜家智能照明
乐趣:控制你的灯光!
数据:来自连接到你手机的家庭的行为数据。
买方/合作方:内部使用和电话公司,如小米。
可能还有更多例子可以举出。这些例子被过分简化和简化了,也许太多了,但这仅仅意味着作为一个说明性的思路的粗略描述。
什么是数据报?
让我们从检查我放在一起的两个词开始,看看它是一个有用的术语还是不足以描述这种现象。首先是数据,然后是诱饵。
数据是收集在一起用于参考或分析的事实和统计数据。它是关于定性或定量变量的主体的一组值。对于我遇到的大多数处理数据的公司来说,人们的感觉是数据是可以衡量和量化的,这是一种主流观点。越来越多的人开始谈论将数据货币化,这个术语被比作石油等原始资源的。这指的是原始数据(未处理的)可以被处理以获得价值的想法。一些人甚至谈论新的淘金热,并将数据比作矿物。数据可以用于许多方面,从帮助治疗癌症、优化物流和训练算法,到学习如何应对给定的情况或背景。我们可以说它不是中立的,是由收集数据和解释数据的人塑造的。
诱饵在这种情况下引诱某人。对诱饵的一种理解是引诱鱼或动物。人类是在动物界中被提出的,而不是超越自然或其他动物,所以我们也容易受其影响。有些人会想到的上下文可能与捕鱼有关。当与人类有关时,作为诱饵的受害者的人通常会感到受伤和困惑。据说某些东西会引起情绪反应,从而导致行动,即使有人知道他们被引诱,也很难知道如何处理。
数据发送我的建议是:通过引发情绪反应来诱使某人提交数据。
受害者通常不知道他们的数据是如何被使用的,当他们发现时可能会受到伤害。您的数据可以用于为保险公司、武器制造商或电子商务公司训练监控数据集。你可能不知道这个。你知道公司可能会出售你的数据,而不是卖给谁,你被一个能改善你生活的产品或服务所吸引。因此,你提交自己(你的数据)作为交换,而没有意识到后果。这是我自己多次做过的事情。
知情同意
一个奇特的现象是挪威和世界其他地方的烟盒上的图像。你经常会发现这样的信息:“吸烟致命,”,它可能伴随着一幅可怕的图片,与你经常吸烟可能导致的一系列疾病有关。
我并不认为使用软件服务或硬件收集数据会杀死你,但是它可能会以你意想不到的方式影响你的生活。
我不知道这有多大帮助。我们仍然可以想象这样的场景:科技公司收集你的数据,并将其用于你不知道的目的,并给予了你极其诚实的知情同意。
这可能不会在不久的将来发生,但它提供了一个有趣的思想实验。我不确定这是不是解决方案,但是我们可以想象以下荒谬的情况:
- 警告:该产品可能作为行为数据出售给你最近的商店。我们可能会把它卖给汇总数据的人,而我们自己可能不知道它去了哪里,因为法律不够透明,而且你的数据非常难以追踪。不过我们尽力了。
- 感谢您提交您的 DNA 样本!要知道,它可能被用来为世界上一些最大的制药公司生产一两种药物。我们认为应该提到这一点,因为我们重视诚实。
- 通过提交您的心理测量信息来换取更大的社交网络,我们希望您意识到后果。我们可以为您提供更合适的产品,但我们会更好地引导您购买。
- 您刚才提供的信息既可用于向您销售产品/服务的公司,也可用于政治家联系您,只要他们付费,我们不会有太多歧视。此外,我们扩张得如此之快,以至于我们经常缺少在特定国家讲该语言的员工来监控可能的侵权行为。在我们有员工的国家,发布的内容量往往过高。正如你可能知道的,我们正在迅速扩张。
- 如果你滚动得太多,并且把自己和你的朋友比较,你可能会有更高的机会变得沮丧,所以如果可能的话,限制你的滚动。记住这项服务是会上瘾的,必须小心使用。我们使用您的行为数据,让您在该平台停留更长时间,以销售更多广告。
清爽吧?
数据经纪人
除非你从事信息行业,否则你可能从未听说过数据经纪人,但他们听说过你。今年早些时候(2019 年),史蒂芬·梅伦德斯和亚历克斯·帕斯捷尔纳克写了一篇关于《快公司》数据经纪人的文章。这项法律要求那些买卖数据的人进入注册中心。另一方面正如文章所说:
就连上个月生效的佛蒙特州首个此类法律也不要求数据经纪人披露谁在他们的数据库中,他们收集了什么数据,或者谁购买了这些数据。它也不要求经纪人让消费者访问他们自己的数据或选择退出数据收集。
这篇文章展示了一个有趣的图表。
Types of consumer data and data companies. Some companies included in the chart may not be covered by the Vermont law. Image by Cracked Labs an Institute for Critical Digital Culture.
《快速公司》文章中的图表让我看到了 Cracked Labs 内部的关键数字文化研究院。 Cracked Labs 是一家位于奥地利维也纳的独立研究机构和创意实验室。它调查信息技术的社会文化影响,并在数字文化领域发展社会创新。它是一个非营利组织,成立于 2012 年,旨在加强信息和通信技术的参与性和自主使用,以及自由获取知识和信息——独立于商业或政府利益。
下面两张大图摘自文章日常生活中的公司监控。
Different levels, realms and sources of corporate consumer data collection by Cracked Labs an Institute for Critical Digital Culture
隐性创收的商业模式
2019 年 1 月马克·扎克伯格发布了一篇关于脸书商业模式 的帖子。作为其中一部分,他写道:
我相信每个人都应该有自己的声音,并且能够沟通。如果我们致力于为每个人服务,那么我们需要一种每个人都负担得起的服务。做到这一点的最好方法是免费提供服务,这正是广告让我们能够做到的。[……]尽管如此,有些人对这种模式的复杂性感到担忧。在普通交易中,你向一家公司支付他们提供的产品或服务。在这里,你可以免费获得我们的服务——我们与广告商单独合作,向你展示相关的广告。这种模式让人感觉不透明,我们都不信任自己不了解的系统。有时这意味着人们认为我们做了我们没有做的事情。例如,我们不出售人们的数据,尽管经常有报道说我们这样做。事实上,向广告商出售人们的信息会违背我们的商业利益,因为这会降低我们的服务对广告商的独特价值。我们有强烈的动机保护人们的信息不被其他任何人访问。
这当然是半真半假或者根本不是真的。让我们检查一下陈述:“…我们不出售人们的数据…”是的,你做了标记。尽管广告商为对客户的洞察付费,但这种洞察是基于你的数据。尽管有复杂的技术基础设施和系统,但这并不是一项复杂或不透明的交易。你收集数据,将数据转化为具体的客户洞察,然后卖给广告商。这不像我去一家卖带肉汉堡包的商店,却被告知他们不卖肉,他们只卖汉堡包。这将使我严重质疑这种情况。
我们可以看看谷歌母公司 Alphabet 第一季度给投资者的最新投资者声明,并检查几份声明。他们正通过 Calico 进入生命科学领域,真正了解寿命和健康数据。它有义务显示任何未决诉讼,如果我们稍微多搜索一点,反垄断诉讼有一些有趣的陈述。谷歌因违反反垄断法被罚款创纪录的 24.2 亿€元(约 27.3 亿美元)。
“十多年来,谷歌的搜索引擎在决定我们大多数人在线阅读、使用和购买的内容方面发挥了决定性作用。如果不加以检查,这种看门人的权力就没有多少限制。谷歌可以部署其阴险的搜索操纵做法,在它选择的几乎任何在线领域霸占最大份额的流量和收入,在这个过程中悄悄地摧毁竞争、创新和消费者选择。”
TechCrunch 援引欧盟委员会 2017 年 6 月 27 日。
与亚马逊在购物相关领域的竞争升级被用作谷歌行为的正当理由。欧盟委员会的决定对€处以 43 亿欧元(截至 2018 年 6 月 30 日为 51 亿美元)的罚款,并指示终止“某些安卓分销行为”的争议行为。谷歌桑德尔·皮帅首席执行官于 2018 年 7 月 18 日发表博客评论这一决定:
快速创新、广泛选择和不断下降的价格是激烈竞争的经典标志,而 Android 实现了所有这些。今天的决定拒绝了支持 Android 的商业模式,这为每个人创造了更多的选择,而不是更少。我们打算上诉。
开放的 Android 系统是一个可以在多种系统上使用的操作系统。在一篇名为的文章中,谷歌从你的 Android 手机中追踪的数据量令人震惊:“谷歌收集了关于你的惊人数量的数据,尤其是从你最常用的设备,你的 Android 手机。这一切都可能在你不知情的情况下发生。”声明提到了 Quartz 的一份报告,该报告试图了解发送给谷歌的数据包括:
- 根据可能性,列出你的手机认为你可能在做的动作类型。(例如,步行:51%,骑自行车:4%,乘火车:3%)
- 大气压力
- 无论您是否连接到 wifi
- 您所连接的 wifi 接入点的 MAC 地址(这是唯一的标识符)
- 附近每个 wifi 接入点的 MAC 地址、信号强度和频率
- 每个附近蓝牙信标的 MAC 地址、标识符、类型和两个信号强度测量值
- 手机电池的电量以及手机是否正在充电
- 你的电池电压
- 你手机的 GPS 坐标及其准确性
- GPS 高程及其精度
- 作为整理照片的交换,你可以让谷歌通过收集附近蓝牙信标和 wifi 网络的信息,记录你在什么商店购物,在什么餐馆吃饭。
- 你多久去跑步一次
- 用蓝牙追踪你,尽管蓝牙已关闭
可能还有我不知道的其他数据点。关键是,通过了解你在一系列平台和服务上使用的关键词,谷歌可以比其他公司更清楚地知道你想要什么。这些信息就是正在出售的东西。声称谷歌是无可争议的数据测试冠军并不是没有根据的。
当然,收集的洞察力对使用谷歌的人来说是积极的,使他们更容易得到正确的东西;到达正确的地方;或者找到合适的服务或产品。
最后的免责声明
话虽如此,我确实很欣赏其中一些公司正在创造的服务和产品。很难想象没有谷歌和脸书的生活。这两家公司都让我的生活变得更好或更糟。这似乎是一个奇怪的说法,但是我的批评是建设性的,而不是对这些公司的极端抗议。
让我们持批评态度,参与关于数据共享作为公民责任的辩论。在我们的社会中如何处理数据有很大的影响。
写这篇文章是因为看到一个名为直立姿势的初创公司的广告活动。他们的口号是:“庆祝生命,自由和追求姿态。”直立姿势训练器用一个小粘合剂贴在你的背上,当你每次没精打采时,它会立即振动,提醒你纠正姿势。
Upright Campaign website retrieved the 7th of July 2019
当我看到该产品时,我的第一个想法是:这些数据会卖给谁?我发现自己也是这么想的,这种思路让我意识到这是科技公司的一种普遍做法。
尤其令人着迷的是这些可以被称为生物反馈设备的新型可穿戴设备,至少我在 2017 年的一篇期刊文章中看到它提到了由廖大银撰写的关于 协作、社交网络姿势训练以及姿势监测和生物反馈 。当公司离你的身体这么近时(苹果手表等。)我们可以开始谈论生物勘探。
生物勘探:是基于生物资源的新产品的发现和商业化过程。然而,这些生物资源不是植物或动物,而是你和你的数据。这可能看起来像是一个批判的开始,让人想起米歇尔·福柯(法国社会理论家)或者被认为是马克思主义者(有阶级关系的社会经济学),也许确实如此。
对数字文化的批判性研究并不是我所知道的一个领域,然而它引起了我的兴趣,因为我对社会科学、计算机科学,尤其是人工智能以及可持续发展感兴趣。我很可能会继续这篇文章,尽我最大努力去理解关键数字文化研究院所涵盖的研究领域。
作为一名挪威人,我将以一张我在一家名为 Swedish Posture 的公司看到的图片来结束这篇文章。姿势校准是未来吗?我无法预测未来,但是人类的人体工程学在这个健康科技领域看起来非常光明,所以我能说的就是保持正直。保持直立!
数据发送 : 通过引发情感反应来诱使某人提交数据。
你认为数据留白是描述这种情况的一个有用的词吗?请在下面的评论区告诉我。
这是#500daysofAI 的第 35 天,请关注我关于 AI 的每日更新。
非常感谢您的阅读!
什么是#500daysofAI?
我在挑战自己,用#500daysofAI 写下并思考未来 500 天的人工智能话题。这是我发明的一个挑战,来保持对这个话题的思考,和大家分享我的话。
解释了数据库规范化
原文:https://towardsdatascience.com/database-normalization-explained-53e60a494495?source=collection_archive---------4-----------------------
通过设计和修改示例数据库模式来了解数据库规范化!
规范化是一种在数据库中组织数据的技术。对数据库进行规范化以最小化冗余(重复数据)并确保每个表中只存储相关数据是很重要的。它还可以防止由数据库修改(如插入、删除和更新)引起的任何问题。
组织的阶段被称为范式。在本教程中,我们将为一家建筑公司重新设计一个数据库,并确保它满足三种范式:
第一范式 ( 1NF ):
- 数据存储在表中,表中的行由主键唯一标识
- 每个表中的数据以最简化的形式存储在各个列中
- 没有重复的组
第二范式( 2NF ):
- 来自 1NF 的一切
- 每个表中只存储与表的主键相关的数据
第三范式(3NF):
- 来自 2NF 的一切
- 每个表中的列之间没有表内依赖关系
请注意,实际上有六个级别的规范化;然而,第三范式被认为是大多数应用程序所必需的最高层次,所以我们将只讨论前三种形式。
我们开始吧!
本教程改编自 Next Tech 的数据库基础课程,该课程带有一个浏览器内 MySQL 数据库以及需要完成的交互式任务和项目。这里可以免费上手!
我们的数据库:科迪的建设
Codey’s Construction’s database schema with a new table that causes the database to violate the rules of normalization.
我们将在本教程中使用的数据库是为 Codey 的建筑公司(Codey 是一个有用的编码机器人,在前面提到的课程中与您一起工作)。从上面的模式可以看出,数据库包含了表projects
、job_orders
、employees
和project_employees
。最近,添加了customers
表来存储客户数据。
不幸的是,这个表的设计没有满足三种形式的规范化…让我们来解决这个问题!
第一范式
第一范式与表和列中数据的重复和分组有关。
Codey 的构造的表customers
违反了 1NF 的全部三条规则。
- 没有主键!数据库用户将被迫按公司名称查找公司,但不能保证公司名称是唯一的(因为唯一的公司名称是在各州注册的)。
- 这些数据不是最简化的形式。列
contact_person_and_role
可以进一步分为两列,如contact_person
和contact_role
。 - 有两组重复的列— (
project1_id
、project1_feedback
)和(project2_id
、project2_feedback
)。
以下 SQL 语句用于创建customers
表:
Example data for customers
table.
通过修改一些列,我们可以帮助重新设计这个表,使它满足 1NF。
首先,我们需要添加一个名为id
的主键列,数据类型为INT(6)
:
使用这个语句,我们添加了一个自动递增的主键作为表中的第一列。
为了满足第二个条件,我们需要拆分contact_person_and_role
列:
在这里,我们简单地将其重命名为contact_person
,并在它后面紧接着增加了一列contact_person_role
。
为了满足第三个条件,我们需要将包含项目 id 和项目反馈的列移动到一个名为project_feedbacks
的新表中。首先,让我们从customers
表中删除这些列:
然后创建project_feedbacks
表:
下面是数据库模式现在的样子:
Modified schema that now satisfies 1NF.
如您所见,在project_feedbacks
表或customers
表中不再有重复组。我们仍然知道哪个客户说了什么,因为project_feedbacks.customer_id
引用了customers
表。
现在我们的customers
表满足 1NF!让我们继续第二范式。
第二范式
要实现第二范式,数据库必须首先满足 1NF 的所有条件。此后,满足 2NF 要求每个表中的所有数据都直接与表的主键标识的记录相关。
我们违反了 2NF,因为contact_person
、contact_person_role
和phone_number
列跟踪的数据与联系人有关,而不是客户。如果客户的联系人发生变化,我们将不得不编辑所有这些列,这样做的风险是,我们将更改其中一列中的值,但忘记更改另一列。
为了帮助 Codey 的构造修复这个表以满足 2NF,应该将这些列移动到包含联系人数据的表中。首先,让我们删除“客户”中与我们的主键无关的列:
请注意,我们保留了contact_person_id
,因此我们仍然知道应该联系谁。现在,让我们创建新表contact_persons
,这样我们就有地方存储每个联系人的数据了。
Codey's Construction 的数据库模式现在如下所示:
Modified schema that now satisfies 2NF.
现在,如果客户的联系人发生变化,建筑公司只需在contact_persons
表中插入一条记录,并更改customers
表中的contact_person_id
。
第三范式
对于处于第三范式的数据库,它必须首先满足 2NF(因此也是 1NF)的所有标准。
然后,每一列必须非传递依赖于表的主键。这意味着表中的所有列都应该依赖于主键,而不是其他列。如果column_a
依赖于主键,也依赖于column_b
,那么column_a
过渡依赖于主键,所以表不满足 3NF。
你读那个会不会头疼?放心吧!下面会有更多解释。
这是我们满足 1NF 和 2NF 后的customers
表:
Example data for modified customers
table.
该表当前有依赖于传递的列。过渡依赖关系在city
和zip
之间。客户所在的城市依赖于客户,所以这满足了 2NF 然而,城市也取决于邮政编码。如果客户搬迁,我们可能会更新一列,而不更新另一列。因为存在这种关系,所以数据库不在 3NF 中。
为了修复我们的数据库以满足 3NF,我们需要从customers
中删除city
列,并创建一个新表zips
来存储该数据:
Modified schema that now satisfies 3NF.
就是这样!发现违反 3NF 的问题可能很困难,但是确保数据库能够抵御仅部分更新数据所导致的错误是值得的。
我希望你喜欢这篇关于数据库规范化的教程!Codey's Construction 的数据库现在满足三种形式的规范化。
如果你想继续学习数据库,Next Tech 的 数据库基础 课程涵盖了你入门数据库和 SQL 所需的所有知识。通过帮助一个名为 Codey 的交互式编码机器人,您将学习如何创建和设计数据库,修改数据,以及编写 SQL 查询来回答业务问题。这里 可以免费上手 !
Databricks:如何在本地计算机上将数据框保存为 CSV 文件
原文:https://towardsdatascience.com/databricks-how-to-save-files-in-csv-on-your-local-computer-3d0c70e6a9ab?source=collection_archive---------2-----------------------
Photo credit to Mika Baumeister from Unsplash
当我从事处理大型数据集的 Python 项目时,我通常使用 Spyder。Spyder 的环境很简单;我可以浏览工作目录,维护大型代码库,检查我创建的数据框架。然而,如果我不对大数据进行子集化,我会不断地面临内存问题,并与非常长的计算时间作斗争。为此,我偶尔会使用数据块。Databricks 是一个微软 Azure 平台,在这里您可以轻松地将大量数据解析到“笔记本”中,并执行基于 Apache Spark 的分析。
如果您想使用 pyspark 处理数据框和运行模型,您可以很容易地参考 Databricks 的网站了解更多信息。然而,在处理 Databricks 时,我注意到将文件保存为 CSV 格式并不是很简单。在接下来的部分中,我将分享如何在本地计算机上将数据框从数据块轻松保存为 CSV 格式。
1。探索数据块文件系统(DBFS)
从 Azure Databricks 主页,你可以进入“上传数据”(在常见任务下)→“DBFS”→“文件存储”。
DBFS 文件存储是您创建文件夹并将数据框保存为 CSV 格式的地方。默认情况下,FileStore 有三个文件夹:导入阶段、图和表。
2。将数据帧保存到文件存储中的 CSV 文件中
Sample.coalesce(1).write.format(“com.databricks.spark.csv”).option(“header”, “true”).save(“dbfs:/FileStore/df/Sample.csv”)
使用笔记本上的上述代码,我创建了一个文件夹“df ”,并将一个数据框“Sample”保存到 CSV 中。使用 coalesce(1)很重要,因为它将数据帧保存为一个整体。在本文的最后,我还将演示当代码中没有包含 coalesce(1)时会发生什么。
将数据框转换为 CSV 格式后,转到文件存储。您将看到您创建的文件夹和文件。“part-00000”是我必须下载到本地计算机上的 CSV 文件。我为步骤 3 复制了 /FileStore/ 之后的路径。
3.在本地计算机上下载 CSV 文件
为了在本地计算机上下载位于 DBFS 文件存储中的 CSV 文件,您必须将突出显示的 URL 更改为以下内容:
https://westeurope.azuredatabricks.net/files/df/sample . CSV/part-00000-tid-8365188928461432060–63d 7293d-3b 02–43ff-b461-edd 732 f 9 e 06 e-4704-c000 . CSV?o= 3847738880082577
正如您所注意到的,以粗体显示的 CSV 路径(df/sample . CSV/part-00000-tid-8365188928461432060–63d 7293d-3b 02–43ff-b461-edd 732 f 9 e 06 e-4704-c000 . CSV)来自步骤 2。号码( 3847738880082577 )来自原网址。
当您如上所述更改 URL 并按 enter 时,CSV 文件将自动下载到您的本地计算机上。
dbutils.fs.rm(“/FileStore/df”,True)
如果您想删除 FileStore 中的文件,只需使用上面的代码即可。一旦被删除,你会得到评论“真”。
如前所述,下面是代码中不包含 coalesce(1)时的细节。
默认情况下,Databricks 将数据保存到许多分区中。Coalesce(1)将所有文件合并成一个文件,解决了这个分区问题。但是,当您处理非常大的数据集(> 1TB,低速)时,使用 coalesce (1)或 repartition (1)并不是一个好主意,因为它会将所有数据传输到单个工作线程,这会导致内存不足问题和处理速度缓慢。在这种情况下,建议按列解析或分发给多个工作线程。
另外,还有另外两种方法可以将数据框保存为本地计算机上的 CSV 文件:
- 使用“下载完整结果”
这个方法是最简单的。然而,Databricks 最多只能下载 100 万行。因此,如果您的数据框超过 100 万行,我建议您使用上述方法或如下所示的 Databricks CLI。
2.使用 Databricks CLI
Databricks CLI (Databricks 命令行界面)构建在 Databricks REST API 之上,与 Databricks 工作区和文件系统 API 交互。Databricks CLI 需要一些设置,但您也可以使用此方法将数据框下载到本地计算机上。有关更多详细信息,请参考 Databricks CLI 网页。
感谢您的阅读!如果你喜欢我所做的,不要犹豫,在 GitHub 上关注我,在 Linkedin 上与我联系。
另外,请随意查看我的其他文章:
如何获得关于货币汇率的 Twitter 通知:网络抓取和自动化
DataFrame.transform —火花函数合成
原文:https://towardsdatascience.com/dataframe-transform-spark-function-composition-eb8ec296c108?source=collection_archive---------9-----------------------
Photo by 嘉淇 徐 from Pexels
让您的 Spark 代码更具功能性,可读性更好
如何从转换方法中返回容易组合的函数
随着组织迁移到 Spark 上并在 Spark 上创建新的数据处理逻辑,最终的软件会变得非常大,大到需要考虑我们应用于其他软件项目的所有可维护性。
虽然有许多关于编写性能逻辑的全面而有价值的资源,但关于结构化项目的资源就不一样了,这些资源创建了可重用的 Spark 代码,并最终降低了长期维护这些项目的成本。
在这篇文章中,我们来具体看看 Spark Scala DataFrame API,以及如何利用 数据集[T]。转换 函数来编写可组合代码。
注意:data frame 是 Dataset[Row] 的类型别名。
这个例子
有一些特定金额的交易,包含描述付款人和受益人的“详细信息”列:
Note that this DataFrame could be a Dataset[Transaction], but it’s not useful to the examples
没有。改变
让我们创建两个函数来处理事务:
- sumAmounts :对一列或多列的合计值求和
- extractPayerBeneficiary:将付款人和受益人从一列分离成两个新列
使用这些方法来回答以下问题:“哪些受益人在哪些天的总金额超过 25?”
这是一个简单的例子,但是读起来不太好。将其与Dataset
功能的典型用法进行比较:
df.select(...).filter(...).withColumn(...)...
我们将一些逻辑分解到方法中,这有助于我们分别对每一部分进行推理,但是代码的可读性变得更差了。
使用。改变
transform 函数是 Dataset 类的一个方法,它的目的是添加一个“简洁的语法来链接定制的转换
*def* transform[U](t: Dataset[T] => Dataset[U]): Dataset[U] = t(*this*)
它采用了一个函数,从Dataset[T]
, T(数据集中的行类型)到Dataset[U]
, U(结果数据集中的行类型)——U 可以与 T 相同
一个函数DataFrame => DataFrame
符合这个签名——如果我们解开类型别名,我们得到Dataset[Row] => Dataset[Row]
,其中 T 和 U 都是Row
。
使用您之前定义的方法并简单地切换到使用.transform
是一个很好的起点:
更进一步
sumAmounts
和extractPayerBeneficiary
方法不太适合.transform
。这是因为这些方法返回的是一个数据帧,而不是一个函数DataFrame => DataFrame
,所以为了返回一个可以在.transform
中使用的函数,你需要不断地使用下划线来代替数据帧参数。
您可以重写这些方法来返回签名的函数:DataFrame => DataFrame
,以精确匹配.transform
参数类型:
Only the signature had to be changed and a “df =>” added!
现在,您不再需要“下划线”,可以用不同的方式组合这些功能:
您所有的自定义转换现在都返回DataFrame => DataFrame
,因此您可以使用类型别名来更好地描述返回值:
type Transform = DataFrame => DataFrame
例如def sumAmounts(by: Column*): Transform
摘要
- 自定义转换方法可以重新排列以返回类型为
DataFrame => DataFrame
的函数。 - 返回函数使得组合转换和使用它们变得更加容易。
- 类型别名可用于显式定义“转换”。
你可以在这个要点里找到我的 build.sbt 和上面的代码
企业级的数据运营和数据科学
原文:https://towardsdatascience.com/dataops-and-data-science-at-enterprise-scale-445883b51d8c?source=collection_archive---------22-----------------------
苹果 | 谷歌 | SPOTIFY | 其他
Sanjeev Sharma 在 TDS 播客
编者按:这是迈向数据科学播客“攀登数据科学阶梯”系列的第 11 集,由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:
如果你没有在超大型公司做过数据科学家,你可能不会意识到的一件事是,企业规模出现的问题(以及解决这些问题所需的技能)与你在初创公司可能遇到的问题完全不同。
规模是一件好事,原因有很多:它意味着访问更多的数据源,通常还意味着更多的计算和存储资源。但是,大公司只有通过促进大团队之间的成功合作才能利用这些东西(这真的非常非常困难),并且必须应对独特的数据卫生挑战,如果不彻底改造几乎整个数据科学生命周期,这些挑战就无法解决。
所以我想说,我们为今天的专题节目请到了德尔福数据现代化和战略副总裁 Sanjeev Sharma,这是一件好事。Sanjeev 的专长是帮助拥有大量技术债务的大公司更新和升级他们的数据管道,他在企业范围内了解数据科学的来龙去脉的时间几乎比任何人都长。以下是我们从聊天中获得的最大收获:
- 企业规模的公司背后往往有并购的历史。因此,他们必须集成来自完全不同数据源的大量不同的数据集。确保来自所有这些不同来源的数据以一种让每个需要的人都能轻松访问的方式进行汇总是一项独特的挑战。
- 如果你想在一家企业公司找到一份工作,有一点要记住,没有一种特定的工具或一套工具会决定成败。上面提到的数据源的多样性意味着您最终会遇到世界上所有的数据库类型和管道架构。因此,如果你试图进入企业数据科学,Sanjeev 的建议是专注于你的基础知识,而不是专注于学习框架 X、Y 和 z。
- 过去,开发人员会构建应用程序,而“It 人员”会负责将这些应用程序部署到生产环境中。但大多数公司后来都认识到,将应用程序和部署步骤集成到一个统一的流程中(称为“DevOps”)是确保最终产品一致性的一个好方法。同样,“数据操作”(即完整数据生命周期的集成)正在成为大公司的普遍做法。你可以在这里阅读 Sanjeev 关于 DataOps 的帖子。
- 当谈到更广泛的数据科学时,Sanjeev 认为计算和架构改进的速度是定义数据科学角色未来如何发展的主要因素之一。更多计算意味着更有能力进行试错、搜索参数和超参数空间,甚至自动化模型选择。例如,过去的情况是,数据科学家必须理解他们的模型,以便能够做出聪明的有根据的猜测,即哪些超参数最适合他们的情况。当然,这在某种程度上仍然是正确的,但是计算能力和 AutoML 工具的可用性已经大大削弱了手动超参数调优的价值。正如 Sanjeev 所说,“几年前是一项技能的东西,今天却成了商品。”
- 由于计算和基础设施的改进,越来越多的数据管道变得自动化和优化,业务知识、产品直觉和领域专业知识的重要性只会增加。机器将能够告诉我们什么样的超参数最适合给定的数据集,但在我们实现全面的 AGI 之前,它们仍然需要具有商业意识的人类来决定,例如,要删除或包含哪些离群值以及为什么要删除,如何从可用的数据集中进行采样以建立训练和验证集,等等。
你可以在推特上关注桑吉夫,网址是 @sd_architect,或者点击查看的网站。
我们可以使用数据科学预测石油和天然气工程项目的成本超支吗?
原文:https://towardsdatascience.com/datascience-in-oil-and-gas-engineering-projects-daace6e6c7f?source=collection_archive---------22-----------------------
Photo by Dean Brierley on Unsplash
我们的调查涉及对发生在 15 个石油和天然气海上项目中的重大漂移因素的分析。漂移因素是可能的功能失调点,会导致项目绩效下降,然后在面临有害后果之前实施纠正或预防措施。然后从 15 个石油和天然气项目中收集了 720 个事件。
第一部分:探索性数据分析
首先,我将使用 python 编写一个经典 EDA,在第一步中,我导入经典库并上传文件:
Author’s creations
该数据库包含有关石油和天然气海上工程项目中过度成本的以下信息:
项目:项目名称。
执行时间:财年:年季月日。
主要类别和类别详细说明导致项目成本过高的工程问题。
主要原因和原因详情与项目管理相关的问题相关原因。
comments 列中描述的这四个列之间有一个链接。一些问题被判断为“仅仅是工程问题”,而另一些问题被判断为“工程和项目管理问题”,这种区别是基于处理该问题并完成数据库的人给出的描述。
金额是每一个问题造成的金钱损失总额。
根本原因是问题可能的主要原因。
下一步是浏览数据库,以检查无效值:
Checking for missing values and NaNs (Author’s creations)
“根本原因”一栏几乎是空的,我将删除它。comments 列对于 NLP 分析,以及与类别或原因建立关系非常有用。
然而,在第一个例子中,我将保持简单,这个探索不需要评论栏。
下一步将探究每个项目中损失的金额。
Table 1. Author’s creations
金额以千美元为单位。
当绘制(见下图)损失金额和项目名称时,我们可以看到“负金额”,这意味着采取了一些措施来纠正错误并挽回部分损失。
Amount of losses per project. (Author’s creations)
因为我只对正的“损失”感兴趣,所以我只保留金额的正值。我定义了一个名为 Overcost 的新数据集:
Author’s creations
Table 2.Author’s creations
现在,我可以检查每个项目中产生的实际超额成本。
与上表相比,这些数字更高。
然而,有一些项目仍然有“小”的数字,我会放弃它们,以便专注于更大的项目。
按类别分类的结果是:
Amount of losses per project by category (Author’s creations)
因为所有的项目与项目的规模相比都有不同的损失,所以很难比较每个类别的重要性。
为了提高可视化效果,并获得所有项目的相似视图,我将每个项目行中的损失金额除以项目的总损失,对该数据进行归一化处理:
Author’s creations
该图显示了各个项目的相对损失额。它还显示了一些可以丢弃的异常值(例如,数量> 30 的值):
Author’s creations
最后一幅图显示了最重要项目按类别划分的标准化损失的比较分布。
最后,我们可以探索其他列。例如具有接合图。但在此之前,有必要将分类数据(如详细原因和月份)转换成数字(浮点型)。因此,我创建了下一个映射:
结果,该图给出了原因细节和月份之间的关系。举例来说,我们可以看到原因 5“设备故障”在第 2 个月和第 10 个月左右有很大影响
Impact of causes of project losses by month (Author’s creations)
第二部分。使用贝叶斯网络预测成本超支
研究石油和天然气项目常见问题原因的顾问选择了之前列出的原因(原因从 1.4 到 5.2)。此外,我们采访了六位行业专家。他们被提供了一个被评估项目的主要漂移因素的列表,以检查原因是否有意义以及是否与他们所属的领域一致。由于被评估的项目属于同一个行业,它们共享特定的漂移因子。我们的因果模型具有有限数量的经验定义的漂移因子。
下表显示了所研究项目中最常见的漂移因素。为了证实我们的研究,该表还显示了 PM 文献的来源,其中相同领域(石油和天然气建设)的项目试验了相同的漂移系数。
Table 3. Selected Drift Factors. (Author’s creations)
我们调查的下一步是通过从数据库中提取知识来了解漂移因素对项目过度成本的影响。假设所有漂移因子都收敛到目标节点(没有任何其他中间节点)。标记项目集分为训练集(数据集的 90%)和测试集(数据集的 10%)。
数据结构化:我们调整了数据库,以获得一个适应贝叶斯网络的表,同时使用足够的行来使模型可靠。我们获得的数据如表 4 所示。对于每个项目,我们都有由于特定问题而损失的金额。
Table 4. Raw data format (Author’s creations)
然后,我们必须将问题转化为项目中反复出现偏差的原因。这项工作也是在专家的帮助下完成的,他们根据对数据库中事件描述的理解来定义重复发生的原因。表 5 显示了与我们的第一个数据结构化相当的结构化:每个单元格显示了由于每个漂移因素(列)导致的每个项目(行)的资金损失量。
Table 5. Data including drift factors. Real losses by drift factor by project (Author’s creations)
接下来,有必要对漂移因素的影响进行标准化。因此,我们建议将表 5 转换为另一个数据库,其中的衡量标准由每个项目的费用的相对资金损失组成,即每个项目的每个漂移因素造成的损失的百分比,如表 6 所示。
Table 6. Data including drift factors. Percentage losses by drift factor by project (Author’s creations)
然而,该表没有足够的数据来训练贝叶斯算法。因此,我们应用了另一种数据配置策略,即按照日期以及月份和年份的分段来分离事件。数据库已重组,如下表所示。在该表中,每个单元格总结了给定月份(行)与漂移因子(列)相关的所有事件造成的资金损失百分比。这个新表格有 720 行,对应于在 48 个月内评估的 15 个项目。
Table 7. Final structured data format. (Author’s creations)
我们进行了几次模拟,直到我们得到一个好的特征来训练算法。在每个测试中,我们修改了超参数(输入/输出节点的数量、数据库的结构、合成节点的状态数量、输出节点的状态数量)。我们尝试了几次模拟,直到我们得到一个标准化的有用的超参数组合来训练算法。
选择和优化超参数是一项艰巨的任务,如果你有兴趣了解这个主题的更多信息,我推荐以下帖子:
[## 贝叶斯网络中的超参数调整问题
在这段历史中,我们讨论了在基于贝叶斯理论建立模型时要考虑的结构标准
towardsdatascience.com](/the-hyperparameter-tuning-problem-in-bayesian-networks-1371590f470)
表 8 总结了超参数的值。我们选择了如表 7 所示的数据库结构。该数据库使算法学习漂移因子和成本超支百分比之间的关系。它支持为目标节点构建 CPT。每一列对应一个超参数;每行显示这些超参数可以取的值。不同的 bn 可以从上述超参数的组合中构建。在表 8 中,绿色和带下划线的值表示我们在模型中采用的超参数组合。
Table 10. Overview of the Hyperparameters, and their possible values. (Author’s creations)
我们测试了几个超参数,以获得可接受的组合数量。学习算法计算合成节点和目标节点 CPT 之间的关系。
我们将学习算法应用于数据库。该算法生成与目标节点的 CPT(project over cost)相对应的值。最终模型是使用 GeNie 软件创建的。过度成本(目标)节点的类别可以理解如下:
P1 _:被评估项目有 0% 的概率发生相当于不到 1%费用的超额成本。即 P(Overcost) < 1% = 0。
被评估项目有 2% 的概率发生相当于项目费用 1%到 10%的超额成本。即 1% ≤ P(过度成本)< 10% = 0.02。
P1 _ 100:被评估项目有 61% 的概率发生相当于项目费用 10%至 100%的超额成本。即 10% ≤ P(过度成本)< 100% = 0.61
P_100_: 被评估项目发生大于项目费用 100%的超额成本的概率为 37% 。即 P(过度成本)≥ 100% = 0.37
下图显示了完整的贝叶斯网络。在这个网络中,输入节点对应于漂移因子的子原因。漂移因子对应于节点 D1 到 D12。
The complete Bayesian network (Author’s creations)
模型的测试。然后我们用新数据测试了因果模型。我们用与项目数据库中包括的项目相对应的信息来实例化每个成熟度级别,但是不在训练数据集中。注册目标节点中每个状态的相应过度开销。为每个状态值计算精度。下图显示了该模拟的结果。训练数据和测试数据之间的相对误差小于 6%。
The complete Bayesian network (Author’s creations)
改进建议。首先,我们进行分析,以检测哪些漂移因素对因果网络影响更大。这种第一次分析允许选择具体评估项目的问题的主要原因。下图显示了该示例的反向传播分析。结果表明,节点 D1、D7、D8、D9 对项目的超额成本有很大的影响。因此,应该使用与这些节点(S_Pa、R_Pa、I_Mr、R_Mf)相关联的成熟度标准来构建建议场景,因为决策者可以对最有影响力的节点上的工作进行优先级排序。
Backpropagation analysis for the given example (Author’s creations)
第二,决策者模拟了达到所选成熟度标准的新成熟度级别的假设。然后运行新的 BN 使他/她能够计算新的成熟度等级将如何改善项目超额成本的概率分布。下图显示了模拟的结果。将所选成熟度标准的节点状态从“否”更改为“是”会在项目过度成本节点中产生重大变化。用户可以决定这个结果是否足够好,或者是否需要对流程进行另一次迭代以获得更好的结果。
Performance prediction based on recommendations for the given example. (Author’s creations)
下图显示了此场景流程的摘要。第一列显示了模拟之前每个项目的项目超额成本概率的结果,即基线项目管理成熟度评估。第二列提出了主要的建议,这些建议被写成成熟度标准的改进,并且每一个改变都假定了一系列要付诸实践的行动。第三列显示了应用这些建议后的模拟结果。
Simulation results for an improvement scenarios (Author’s creations)
由于建议与 IB2M 命名法(S_Pa、R_Pa 等)一致,因此应该将它们转化为最佳实践。当然,这些建议并不详尽,其中一些可能超出了范围。专家根据项目的具体情况对它们进行调整,并采取他/她认为必要的其他行动来支持它们。我们可以对该建议解释如下:
从 3 级到 5 级的 S _ Pa:改善社会/计划活动,如资源调度,从在一个项目中使用到在整个组织中使用。
从 2 级到 5 级的 R _ Pa:改进项目计划中使用的成本和时间活动(任务调度、成本/收益分析、成本估算、自上而下估算等)。)从已定义的级别(知道它们的存在,有时会使用它)到在整个组织中使用的程度。
R_Mr 从 3 级到 5 级:改进项目控制中使用的成本和时间监控工具(控制图如甘特图、S 曲线、因果图等。)从在单个项目中的使用到在整个组织中的使用。
从第 4 级到第 5 级的 R _ Mf:提高整个组织使用监控工具(如上所述)的频率,例如,通过改进基线计划。
如果你想阅读这篇文章的完整研究链接,请点击下一个链接:
[## 一种基于贝叶斯网络的提高项目管理成熟度的方法
提出了一种建立项目管理成熟度和项目超额成本之间因果关系的方法
www.sciencedirect.com](https://www.sciencedirect.com/science/article/pii/S0166361519309480?dgcid=author)
如果访问受限,您也可以尝试此链接:
感谢阅读!!!
如果你想继续阅读这样的故事,你可以在这里订阅!
如何利用地理信息设计要素
原文:https://towardsdatascience.com/datasciencegeography-29a12667c22c?source=collection_archive---------31-----------------------
理论和真实数据科学示例
Photo by Марьян Блан | @marjanblan on Unsplash
每一个销售商品或服务的企业都有一个实际地址。毫无疑问,地理位置可以决定一家企业的成败。对于数据科学家来说,提取测地特征,即与地球几何形状相关的特征,可以提供清晰的见解,并显著提高机器学习模型的性能。
在本文中,我们将使用 Yelp 数据集,特别是[business.json](https://www.yelp.com/dataset/documentation/main)
文件来提取依赖于位置的特征。
我们还将从布朗施泰因、塞门迪亚耶夫、穆西奥尔、穆利格(链接到 PDF )的数学手册和简菲利普马图切克的摘要中汲取经验
数据概述
Yelp 文档很好地概述了这些特性,下面是一个简短的片段。
{
// string, 22 character unique string business id
**"business_id": "tnhfDv5Il8EaGSXZGiuQGg",**
// string, the business's name
**"name": "Garaje",**
// string, the full address of the business
**"address": "475 3rd St",**
// string, the city
**"city": "San Francisco",**
// string, 2 character state code, if applicable
**"state": "CA",**
// string, the postal code
**"postal code": "94107",**
// float, latitude
**"latitude": 37.7817529521,**
// float, longitude
**"longitude": -122.39612197,**
// float, star rating, rounded to half-stars
**"stars": 4.5,**
// integer, number of reviews
**"review_count": 1198**
某些地区往往高度发达,有很多企业。此外,相似的企业往往聚集在一起。
例如,上面的商店位于旧金山的 SoMA 社区(有很棒的鳄梨色拉酱),周围聚集了许多其他餐馆。
我们将使用纬度和经度来查询其周围企业的数据框架。为此,我们需要一个地理复习员。
球面坐标系
地球是一个不完美的球体,半径大约为 6357 公里。地理坐标系是一种允许在球体上定位点的方法,在土地测量以及其他专业中经常使用。
我们将纬度定义为从赤道零度到两极 90 度的角度。相反,经度从一极到另一极,范围从 0 度到 180 度。下图在一个球体上说明了这两个概念。
Source: https://en.wikipedia.org/wiki/Geographic_coordinate_system
查询邻域中的点
现在我们已经定义了坐标系,我们需要一种方法来定义感兴趣点周围的边界框,并抓取它周围的定界区域中的所有点。
球面上的两点
作为第一种方法,我们可以计算半径为R
的球体上两点P(lat1, long1)
和Q(lat2, long2)
之间的顺行距离:
这种方法非常慢,因为它意味着计算数据集中所有点与所有其他点之间的距离。
角半径
一个更好的方法是用角半径来描述从给定的角度看一个球体或圆有多大。例如,如果我们想在半径为R
的球体上覆盖距离d
,那么角半径r
为:
包围盒
然后,我们定义完全包围由角半径捕获的区域的节点。沿着纬度移动意味着我们可以沿着子午线移动,保持经度不变。因此,边界纬度定义为:
沿着纬度圈移动以找到边界经度的方式与上面的方式不同。在下图中,点T1
和T2
分别具有最大和最小经度。它们与兴趣点M
不在同一纬度圈上,而是更靠近极点。
Source: Jan Philip Matuschek
T1
和T2
的纬度是:
因此,极限经度计算如下:
其中:
数学到 Python
我们可以用 python 代码来解释上面的方法:
在 Garaje 的示例中,我们的代码将返回一个 dataframe,列出 Garaje 半径范围内的所有企业,如下图所示:
Source: https://www.mapdevelopers.com/draw-circle-tool.php
特征工程
给定一个像我们这样的数据帧,我们可以编写一个代码来返回一个地理上有界的数据帧的副本(注意:不是视图)
我们能从这些信息中提取什么?事实证明,我们可以学到很多东西:
- 附近有多少商家(密度
- 价格范围比较
- 星级比较
- 审核计数
- 等等…
进行比较时,缩放特征通常是个好主意。例如,在比较价格时,我们可以通过使用查询数据框架的平均值和标准差来标准化 ( z 得分标准化)价格。
星级评定
作为第一个特征,我们可以绘制每个条目相对于其最近邻居的标准化星级。这似乎是一种高斯分布,一个街区的大多数企业在评级方面都相当同质。
价格幅度
价格比较似乎是双峰,更详细的分析可能会使查询更严格,只包括相同类型的企业。
密度计数
我们将密度定义为有界框内的企业数量。这个特性不需要做任何标准化。
请注意,根据查询半径和该地区的开发量,下图会有很大变化。
结论
适当的特征工程可以为您的机器学习模型提供更好地执行所需的优势。通过考虑地理因素,我们可以推导出依赖于位置的特征。
在 Yelp 数据集的情况下,当插入大地测量特征时,每个模型的 AUC 至少提高了 5% 。在所有算法中,它们在最重要的前 5 个特性中至少出现过一次!
面向大规模偏好聚合的数据集融合
原文:https://towardsdatascience.com/dataset-fusion-sushi-age-and-image-quality-and-what-the-hell-do-they-have-in-common-814e8dae7cf7?source=collection_archive---------14-----------------------
Image by Author
对于很多问题,我们有强大的机器学习算法,在给定足够数据的情况下,可以达到前所未有的性能。然而,拥有大量通用和高质量数据的条件并不容易满足。
对于需要人工输入的问题来说尤其困难。让人们直接参与数据采集过程既费钱又费时。此外,对于某些问题,需要专业知识(如医学样本评估),或受控环境(如食品质量、视觉实验)。由于这些要求和约束,创建的数据集可能非常小且非常具体。
一个很大的问题领域,其中很难建立数据集是引发规模,因为人类的判断。结果数据集包含我们正在标记的对象和感知比例之间的对应关系。例如食物的味道(酸奶有多甜?)、图像质量(有噪声的图像离参考有多远?)或者甚至是人的年龄(照片中的人的感知年龄是多少?).
怎么才能解决问题?
有两种方法可以解决数据不足的问题——投入大量资金从零开始收集数据集,或者更聪明一点,将已经收集的数据集融合在一起——重用收集的知识。
在这篇文章中,我将讨论分级和评级,以及如何在一个图像质量评估的例子中将这两种协议混合在一起。收集的数据通常用于训练客观图像质量指标,这些指标应与人类感知密切相关。
文章的 MATLAB 代码在这里可用,Python 代码在这里可用。
这篇文章是基于这篇论文——如果你想看更多的细节和对这个问题的严谨方法,不要错过。
如何引出一个尺度?
在构建量表时,我们试图恢复潜在的分数。这种量表有两种构建方式——评级或排名。
Figure 1: Rating and ranking protocols. Image by Author.
等级
我们可以成对或成组地排列对象。在这里,我将集中讨论成对比较,因为它们简单并且能够将集合比较的结果转换成成对比较。
在成对比较实验中,受试者根据某种标准选择两个条件中的一个。答案被记录在矩阵 C 中,其中每个条目 c ij 是条件 Ai 被选择超过条件 Aj 的次数。
为了将这个比较矩阵转换成一维尺度,我们可以使用布拉德利-特里或瑟斯通模型。在实践中,这两个模型产生了类似的规模,但布拉德利-特里使用不对称 Gumbel 分布(累积逻辑函数)和 Thurstone 使用对称高斯分布。这里我就说说瑟斯通案 V 模式。其他病例(I、II、III、IV)的描述可在原始论文中找到。
Figure 2: From conditions to the quality scale. Image by Author.
瑟斯通案例五模型首先将观察者的答案映射到一个条件比另一个条件更好的概率上。然后概率被转换成距离。这种从概率到距离的映射是通过逆正态累积分布实现的。该分布的标准偏差(sigma)定义了映射。通常将 0.75 的一个条件被选为更好的概率映射到一个单位距离的条件之间的差异(图 3),然后构建的尺度被称为恰好不良差异(JOD)尺度。
Figure 3: Mapping from distance to probability of a condition selected as better. Image by Author.
然后,构建量表的问题转化为降维问题。在这里,对于每一个条件 Ai 和 Aj ,我们通过二项式分布将它们的质量分数差异与 Ai 被选择超过 Aj 的次数联系起来(反之亦然):
其中 n ij — 在 i 和j之间的比较总数然后我们使用最大似然估计来推断质量分数。由于质量是相对的,我们将第一个条件的质量设为 0 ( q1 = 0)。关于成对比较的更多细节,请看这里的和这里的和。图 2 给出了从成对比较中得出比例的途径。
评级
分级实验可以是:(I)分类的——受试者选择一个条件所属的类别;(ii)基数—为条件分配数值的主体。然后汇总所有科目的分数,得出平均值。这个平均值被称为平均意见得分(MOS)。
我们现在通过评级转向建模质量 q 。评级实验中使用的标度范围由实验指挥设定,可以是从 0 到 10、从 1 到 100 等任何值。为了结合范围和偏差,我们引入两个变量 a 和b。我们进一步假设从评级测量中得出的质量遵循正态分布。对于条件 i (q i )的每个潜在质量,我们有:
其中 m ik 是由第 k 个观测器分配给第 i 个条件的分数,而 c 定义了相对于固定观测器噪声σ的标准偏差的大小。将以上展开,代入正态分布公式:
观察评级矩阵的可能性,条目 m ik 如上则由下式给出:
融合数据集
融合成对比较数据集很简单——在数据集中选择一些条件,将它们与成对比较联系起来(进行一些实验,并输入 Thurstone/Bradley-Terry 模型)。类似地,对于评级分数,从不相交的数据集中选择一些条件,在联合实验中测量这些条件的投票,并基于新测量的条件的相对质量来重新调整原始数据。但是我们如何继续融合具有成对比较和评级分数的数据集呢?
就不能把收视率数据扔在一起吗?
嗯…人类参与者可能会被问及稍微不同的问题,或者实验可以在稍微不同的环境中进行,所以一个数据集中的寿司多汁性 4 可能对应于另一个数据集中的 3,仅仅因为它是相对于当天品尝的其他寿司进行评级的。
模型
我们定义了一个最大化问题,其中我们试图找到潜在的质量分数 q 和参数 a、b 和 C,在给定矩阵 M 和 C 以及观察者模型 sigma 的标准偏差的情况下,将两两比较和评级测量相关联。
我们可以看到一些熟悉的术语——即 P(C|q)和 P(M|q)的定义如上。然而,这里我们也有 P(q)-高斯先验,包括以加强凸性。
请注意,现在潜在的质量分数是使用来自平均意见分数和成对比较的信息找到的。参数 c 有它的含义——如果 c 大于 1,成对比较对实验更好,如果小于 1,则更差。然后可以用最大似然估计来找到模型的参数。
测试模型
让我们考虑一个玩具的例子。这里我们有两个数据集,DS1 和 DS2,每个都有成对比较和评级测量
DS1 有四个条件。成对比较矩阵 C1 因此是 4x4。请注意,条件 3 在成对比较中没有与其余条件相关联,但是这不是问题,因为它是在评级实验中测量的。DS1 的其他条件进行了 6 次比较。评级测量结果收集在 4x4 矩阵 M1 中,即由 4 名观察者对条件进行评级。
Image by Author.
DS2 有 5 个条件,在评级实验中由 5 个受试者测量。在这个数据集中,条件 2 也很突出—它没有被评级。然而,通过成对比较,它与其余的联系在一起。
Image by Author.
有两个不相交的数据集,我们希望通过成对比较将它们连接在一起。下面是一个矩阵 C 。 C 包括原始数据集的成对比较数据(红色和绿色),以及为将两个数据集链接在一起而收集的附加比较数据(蓝色)。类似地,矩阵 M 包含来自 DS1 和 DS2 的评级实验的组合数据。
Image by Author.
我们现在可以将 DS1 和 DS2 一起进行缩放,以获得最终的缩放比例。
Image by Author.
这里,真实分数是用于生成矩阵 C 和 M 中的分数,而预测分数是通过将来自 C 和 M 的数据混合在一起而获得的分数。MOS 分数是平均等级测量,而成比例的成对比较是仅从成对比较中获得的质量分数。请注意,结果的准确性取决于数据的质量和数量。为了获得更好的结果,我们可以收集更多的成对比较或评级测量。
进一步阅读
这是文章中提到的来源的汇总:原始论文、代号、特斯通模型原始论文、布拉德利-特里原始论文,缩放两两比较数据:论文 1 和论文 2 。如果你想从另一个角度来看融合评级和排名测量,这两篇论文将会很有帮助:论文 1 ,论文 2 。
喜欢作者?保持联系!
我错过了什么吗?不要犹豫,直接在 LinkedIn 或 Twitter 上给我留言、评论或发消息吧!
[## 成对比较的主动采样
如何配对玩家,以便在尽可能少的游戏中知道排名,同时游戏体验质量…
towardsdatascience.com](/active-sampling-for-pairwise-comparisons-476c2dc18231) [## 贝叶斯优化的超参数调整或者我如何用木头雕刻船
超参数调整通常是不可避免的。对于一个参数,网格搜索可能就足够了,但如何处理…
towardsdatascience.com](/bayesian-optimization-or-how-i-carved-boats-from-wood-examples-and-code-78b9c79b31e5) [## 你能做得更好吗?抽样策略,重点是吉布斯抽样,实践和代码
提供了通用采样策略的概述,重点是 Gibbs 采样、示例和 python 代码。
towardsdatascience.com](/can-you-do-better-sampling-strategies-with-an-emphasis-on-gibbs-sampling-practicals-and-code-c97730d54ebc)
数据集生成:用 GANs 绘制照片草图
原文:https://towardsdatascience.com/dataset-generation-photo-sketching-with-gans-b94ce53d59c1?source=collection_archive---------27-----------------------
数据是我们 ML 和 DL 模型的核心。如果我们没有合适的数据集来训练我们的算法,我们就无法构建强大的程序。大多数时候,拥有一个足以训练模型的数据集是一个瓶颈,并且很难处理,特别是当我们需要一个由图像组成的数据集时。为了解决这个问题,我们需要在增强中执行一些变形机制、图像处理技术和其他技术。然而,我们可能仍然会因为某个特定问题而缺少数据集。一种解决方案可能是创建数据集,就像用 GAN 手绘形状一样。今天,我想用 Python 和 GAN 来研究照片素描,它有助于创建这样的新图像。
首先,这篇论文最近发表在卡耐基梅隆大学上,研究照片素描并获得惊人的结果。类边缘视觉表示就是简单的图像边缘、物体边界和线条画。主要重点是在突出的边界,以操纵图像在这个稀疏的空间,以产生更多。因此,我们可以从给定的输入图像中创建轮廓图(草图)作为输出。轮廓绘制基本由物体边界、突出的内边缘如遮挡轮廓组成;以及显著的背景边缘。
此外,本文还提高了生成轮廓图和指向对象边界的类边界图的性能。如果你在手绘图像数据集上工作,它有很大的潜力,因为我们可以尽可能多地扩展我们的数据集,而且我们仍然可以得到非常逼真的图形。
等高线图可以被描述为现实世界的物体,因此可以被认为是人类视觉的一种表达。与图像边界相比,轮廓图往往具有更多的特征,如眼睛、嘴巴、鼻子等。我在下面的文章中举了一个例子,展示了不同检测机的特性:
轮廓绘画善于采用所需的艺术风格。所以可以看做一个风格转移的应用。此外,文中还提到轮廓图是介于图像边界和抽象精细图之间的一种中间表示。
为了使用这个模型,首先要下载这个回购。你可以从这里在线探索更多,它创建随机样本,该项目的网页是这里。您可以检查示例数据集等。
下载回购后,除非想自己训练,否则需要下载预先训练好的模型。由于在我们的问题中,我们有一个稀缺的数据,我们不能训练这个模型。我提到的这个预训练模型是这里的和来自 Adobe Stock 的 1000 幅户外图像数据集上的 5000 幅高质量图片。
在这一步之后,您需要编辑 PhotoSketch→Scripts→test _ pre trained . sh 并删除这些行:
results_dir ${dataDir}/Exp/PhotoSketch/Results/ \
checkpoints_dir ${dataDir}/Exp/PhotoSketch/Checkpoints/ \
创建一个文件,并将你的预训练文件添加到 PhotoSketch→check points→pre trained。您需要将源图像数据添加到 PhotoSketch→示例中,生成的图像将位于 PhotoSketch→results 中的同一目录下。我将使用这样的数据集,因为我需要创建更多的手绘绘图:
要从 shell 运行,请分别执行以下命令:
cd 目录/to/PhotoSketch
。/scripts/test_pretrained.sh
你可以在你的终端上看到这个过程。我将这个模型应用到我的 matplot 条形图数据中。我需要有很多手绘的情节,这是产生一些好方法。
Results
从结果中,我们可以看到预训练的模型从输入源生成了很好的绘图。你可以用它们来进一步训练你自己的模型,比如物体检测,图像分类等等。
数据集不可用?没问题!
原文:https://towardsdatascience.com/dataset-unavailable-no-problem-b5031311d59d?source=collection_archive---------31-----------------------
source: https://pixabay.com/photos/code-code-editor-coding-computer-1839406/
互联网上有大量可用的数据集,但我还是要提到一些令人惊叹的资源。如果你已经在 LinkedIn 上与我联系,那么你可能已经看到这个列表,如果你没有联系,请点击这个 链接 。以下网站可能有助于您获得所需的数据集:
流行的开放式数据仓库:
- 加州大学欧文分校机器学习资源库:https://lnkd.in/f5CUDj7
- Kaggle 数据集:https://lnkd.in/fKWqVbw
- 亚马逊的 AWS 数据集:https://lnkd.in/fnVYnm5
元门户(他们列出了开放的数据仓库):
- http://dataportals.org/
- http://opendatamonitor.eu/
- http://quandl.com/
其他页面列出了许多流行的开放数据仓库:
- 维基百科的机器学习数据集列表:https://lnkd.in/f6wujcB
- Quora.com提问:https://lnkd.in/fuHPfFF
- 数据集子编辑:https://lnkd.in/fmqkisy
如果你甚至在这些网站上都找不到数据集呢?你会怎么做?
你会责怪互联网没有给你你需要的数据集,或者你会诅咒整个宇宙吗?
嗯,我不会做上面提到的两件事。我会创建我自己的数据集,相信我,不会超过 5 分钟。
现在,让我向您展示如何快速创建自己的数据集。我们将使用名为 Faker 的 python 包。
- 安装 Faker 库。
pip install faker
2.导入库。
from faker import Faker
3.将 Faker 函数赋给一个变量,并设置一些随机种子。
fake = Faker()
fake.seed(4321)
我们将创建一个酒店数据集。为了保持本教程的简短和精确,我们将总共创建 8 列,您可以创建任意多的列。
4.给每个变量分配一个空数组,这样我们可以向其中插入一些数据。
ID=[]
name=[]
phone=[]
age=[]
gender=[]
address=[]
checkin=[]
checkout=[]
5.让我们插入 100 个电话、地址、入住、结账和姓名条目。
for _ in range(100):
phone.append(fake.phone_number())
address.append(fake.country())
checkin.append(fake.date_time_ad())
checkout.append(fake.date_time_ad())
name.append(fake.name())
6.我们必须分别插入 ID、年龄和性别的值。ID 将包含范围从 1 到 100 的数据。在年龄变量中,我们将最小年龄设置为 8 岁,最大年龄设置为 80 岁,并且我们将大小指定为 100。性别部分相当复杂,因为你不能随机分配男性和女性。此外,一些 ML 算法只接受数字。我们将为男性和女性分配 0 和 1,比例分别为 60:40。
ID=pd.Series(range(1,101))
age=np.random.randint(8, high=80, size=100)
gender=np.random.choice([0, 1], size=100, p=[.6, .4])
7.现在,我们已经成功地将数据插入到那些空数组中。让我们将数据分配给 dataframe 列。
data= pd.DataFrame({‘Timestamp’:timestamp,’ID’:ID,’name’:name,’Phone number’:phone,’age’:age, ‘gender’:gender, ‘address’:address,’checkin’:checkin,’checkout’:checkout})
就是这样!我们已经成功创建了自己的自定义数据集。
First 10 rows of our custom dataset
您可能需要在这里执行探索性数据分析,因为数据集不够干净,您必须找到变量关系、异常值等等。但在那里你可以学到数据科学最重要的部分,即 EDA。
让我们做一些基本的 EDA。
8.分别用男性和女性替换 0 和 1。
data.gender.replace(1,’female’,inplace=True)
data.gender.replace(0,’male’,inplace=True)
9.将签入和签出转换为日期时间格式。
data[‘checkin’]=pd.to_datetime(data.checkin, errors=’coerce’)
data[‘checkout’]=pd.to_datetime(data.checkout, errors=’coerce’)
10.现在让我们将退房日期设置为入住+ 3 天
import datetime
enddate = pd.to_datetime(data.checkin) + pd.DateOffset(days=3)
data[‘checkout’]=enddate
11.让我们策划一些事情。
plt.figure(figsize=(20,20))
plt.scatter(list(data.checkin.values),list(data.address.values),color=’r’)
Scatter plot
我们可以在这里执行大量的 EDA,但是为了保持文章简短和精确,我把接下来的步骤留给你。祝 EDA 和本教程愉快。
以下是完整代码的链接:【https://github.com/kunaldhariwal/Building-a-custom-dataset
我希望这已经帮助你增强了你的知识基础:)
关注我了解更多!
感谢您的阅读和宝贵时间!
数据共享和工作台:试验数据新闻应用
原文:https://towardsdatascience.com/datashare-and-workbench-experimenting-data-journalism-apps-af79bb031687?source=collection_archive---------18-----------------------
本周,我有一点时间来玩两个新的(对我来说)数据新闻工具,它们已经在我的雷达上了。
第一个是名为 Workbench 的现成数据新闻应用。这个项目是计算记者 Jonathan Stray 的创意,得到了哥伦比亚新闻学院的支持。那么它是做什么的呢?嗯,据开发者称,这是一个内置培训的数据新闻平台:
“Workbench 是一个集成的数据新闻平台,无需任何编码即可轻松完成数据搜集、清理、分析和可视化任务。您可以从已经使用的来源加载实时数据,包括开放的政府门户、社交媒体、SQL 数据库和 Google Drive。完成的工作流可以与故事一起共享,以向观众展示图表背后的故事。”
该应用程序可在 https://app.workbenchdata.com在线下载。一旦你注册(你可以使用谷歌或脸书以及电子邮件)并登录,你就可以直接进入教程了。
教程遵循一种读>做>下一步的格式,鼓励你完成各个步骤,建立一个收集、清理、过滤和可视化数据的“工作流程”。这是令人印象深刻的东西,教程涵盖了很多领域非常快。它还有助于建立工作流的概念,这是 Workbench 的核心。
有一些预定义的“配方”,你可以复制并建立你的工作流程,如果你不怕做一点点击(并使用几次撤销功能!)来学习应用程序喜欢的工作方式,然后你可以从教程中学习你需要的东西。一旦你创建了一个工作流,平台的开源方法意味着原则上应该很容易共享它。现在,观众可以看到你的工作,同事可以从你的过程中学习。
我对这里的游戏有点晚了,因为 Workbench 已经开发了一段时间。但是感觉很成熟稳重。当我玩 Workbench 的时候,当我现在写这篇文章的时候,我有一种似曾相识的感觉。Workbench 是“有点像 google sheets”和“有点像 google fusion”。它有 IFTTT 的迹象,其中一些是“一个小而笨重的笔记本”。但这并不是一件坏事,恰恰相反。这意味着它正在成为数据驱动报告的一站式商店。我可以很容易地看到我推荐这是一个很好的工具,为学生和记者们提供一些自我导向的学习。
我本周试用的第二个应用是由国际调查记者联盟[开发的](https://andydickinson.net/2019/02/14/datashare_and_workbench/(http://www.icij.org/) Datashare 。来自 ICIJ 的 Will Fitzgibbon 很好地概括了创建 Datashare 的动机:
Datashare 是一个允许你有效地搜索和组织你的文档的应用程序
Datashare 建立在帮助 ICIJ 制作其最大项目的一些相同技术之上,如 巴拿马论文 和 天堂论文——但 Datashare 可以安装在你自己的电脑上,而不是依赖 ICIJ 的服务器。
Julien Martin 提供了更多关于 Datashare 如何做到这一点的背景(和一个很好的案例研究)
Datashare 集成了 ICIJ 久经考验的提取技术,该技术从文件中提取机器可读的文本(使用 Apache Tika ),对图像应用光学字符识别(tesserac OCR),然后将信息添加到搜索引擎(elastic search)。)
换句话说,您得到了一个“开箱即用”的 ICIJ 工具包,用于处理和管理大量文档。
与 Workbench 不同,Datashare 是一个驻留在您的计算机上而不是 web 上的应用程序。有道理;为什么潜在的敏感文件会在网上流传?事实上,该平台的未来计划包括记者安全合作的方式。这在技术上是很严肃的事情,这里的工作流程很大程度上是调查性新闻的多机构深潜模式。但是不要被推迟。安装程序很棒,支持文档也很棒。
安装完成后——这可能需要一段时间——您需要将所有调查文档移动到一个文件夹中。然后你从菜单中选择分析我的文档就可以了。
你能做的第一件事是提取文本。如果您有一堆 PDF 文件要处理,并且可以选择使用 OCR(光学字符识别,虽然更耗时,但也意味着您可以从扫描的文档图像中获取文本),这将非常有用。即使在我的旧 mac book air 上,小小的进度条也飞快地滑过。
您还可以在文档中查找人员、组织和地点。这使用自然语言处理(NLP),一种机器学习技术,可以从“自然语言”中分析和提取信息。这里真正发生的是一种叫做“实体提取”的东西,它提取大块的内容,并试图对它们进行分类。
这对于文档级别的工作非常有用,但是如果能够跨文档连接名称、地点和组织就更好了。谁出现在哪里,在什么样的背景下,有助于建立一个联系的画面。
很明显,Datashare 的目标是那些有更多内容需要研究的人。对于不经意的实验者来说,这是一个有趣的窗口,可以看到像 ICIJ 这样的组织的交易工具。我希望工具包中未来的工具将包括可视化这些联系的方法。但最终,Datashare 的核心功能是将文档转化为结构化数据。
如果我对应用程序的开发有更直接的建议,那就是在菜单上添加一个“我的文档”按钮。很难找到你添加的文档。我知道这将是铁杆用户不需要的东西——它是关于文档中的内容而不是文档本身。我也知道,对于像我这样直到被卡住才使用 RTFM 的人来说,这是一种安慰。但它将有助于浏览器的易用性,实际上不会超过一个链接,比如说“我的文档库”或“文件”。
结论
如果你对计算、数据新闻或调查性新闻有短暂的兴趣,我真的会向你推荐一部两者兼具的剧。我想很多人可能会对您使用 Workbench 所能做的事情感到惊喜。这绝对不仅仅是一个边做边学的平台。这里有一些可用的工具和足够的可扩展性来分散“但我可以在 python 中这样做”的批评者的注意力。不要让 DataShare 稍微简单一点的技术性让你分心。正如我所说的, Datashare 用户指南非常出色。
这两款应用在技术和复杂性方面为数据新闻实践的发展提供了一个有趣的高峰——仅此一点就是玩的好理由。他们或许也代表了对这一点的某种认可,以及我们对新闻业能否跟上时代步伐的担忧。但这是另一篇博文要思考的问题。现在,给他们一个机会,给他们你的反馈。
数据故事如何通过设计帮助您解决分析挑战并推动影响
原文:https://towardsdatascience.com/datastories-c6fb7106126e?source=collection_archive---------17-----------------------
结合设计和数据驱动的问题解决方法,在分析学和民族志的交叉点上展现故事。他们是你的向导,确保你在正确的问题上工作,你的解决方案实际上导致了期望的结果。
当我们最近举行一场旨在帮助一家非政府组织打击人口贩运的 24 小时黑客马拉松时,参赛团队的构成有着天壤之别:有许多团队具有分析咨询方面的丰富背景。然后是我的团队:一名数据工程师和三名设计师。该活动的目标是从客户提供的数据中获得见解。游戏开始了。客户简报是最重要的。每个队都有自己的锤子。
可能很难看出这样一个重设计的团队与看似明显的数据分析挑战有什么关系,但我们没有绝望。相反,这一挑战让我们能够展示一些有价值的经验,说明结合数据驱动和设计驱动的方法如何能够产生以前被忽视的独特见解。到达那里的关键是在分析学和人种学的交汇处寻找浮出水面的故事。
忽略锤子——从问题开始,而不是数据
设计思维成功的一个原因是它是解决方案不可知的,这让问题解决者比使用其他方法(如假设驱动的问题解决方法)探索更广阔的解决方案空间。在以数据为中心的环境中工作时仍然如此。当我们被要求在数据中寻找一个问题的答案时,我们有义务首先确保这个问题是正确的。这通常被认为是对任何项目资源的额外消耗,尤其是当团队已经处于交付模式时,设计才被引入到项目中。然而,当早期引入时,设计有助于与业务一起驱动问题定义过程。潜在地,而团队中的其他人则忙于后勤工作——尤其是臭名昭著的“获取数据”步骤。通过这种方式,一旦一个团队致力于解决一个问题,就可以确定解决这个问题将会给业务和用户带来影响。
在我们的项目室中,我们确保数据在我们需要时可用,但随后就不管它了。我们大多数人甚至没有在最长的时间里看一眼数据字典,以便不使我们的思维产生偏见,从而导致潜意识中消除潜在的丰富研究领域。相反,我们从两个熟悉的问题开始:真正的潜在问题是什么?我们到底在解决谁的问题?试图回答这些问题成为实际的初步目标,这使我们沿着著名的双钻石的第一个斜坡踏上了探索之旅。
使用数据作为约束
有许多工具可以用来定义问题空间和目标人物角色:利益相关者映射、服务蓝图、我们可能做的事情、五个为什么、通过视频会议的专家访谈,以及许多许多的便利贴(仔细想想,你真的可以在一个晚上安排很多发现——我们的开球时间是下午 4 点)。分析项目与不同类型的转型项目的不同之处在于,对特定数据和信息及其流动的关注提供了额外的限制;创造力喜欢约束。
想想这种认识如何影响任何设计活动。服务蓝图增加了一个数据层,关于该主题的访谈问题被添加到脚本中,重点领域和想法不仅根据业务、技术和人力约束进行优先排序,还根据与数据相关的约束进行优先排序。在这一阶段,数据成为推动研究和想法向前发展的推动者,并增加了关注可以实现什么和缺少什么的额外镜头。
在数据中寻找人类的故事
大约在上个世纪中叶,美国空军正与一系列无法解释的坠毁飞行员作斗争。飞行员无法保持对他们新设计的飞机的控制。他们后来发现,这个问题的原因是,在设计驾驶舱时,他们使用了人体各种尺寸的平均值,这使得驾驶舱对许多人来说非常不符合人体工程学。一旦发现这一点,他们改变驾驶舱,以适应个别飞行员和坠毁停止。
当面对关于人类的数据时,非人化的风险是非常真实的。这里是散点图,那里是钟形曲线,在你知道之前,你已经做出了对任何人都不适用的概括陈述。取而代之的是,思考通过把数据点看作人类可以学到什么,并尝试想象它们在现实世界中可能意味着什么。通常,你会发现一些人类故事的元素,这些元素可以作为研究的输入并被进一步研究。浏览关键参数列表,问问自己,如果
在我们打击人口贩运的黑客马拉松中,幸存者的年龄分布给了我们这样一个故事中最引人注目和悲惨的例子。当观察年龄和缓解干预的有效性之间的相关性时,我们可以看到最年轻的受害者只有几个月大。这不仅是一个可怕的见解,而且它也为我们的研究提供了信息,因为我们现在知道要与我们的客户进行一系列非常不同的对话,其中包括最年轻的受害者的特殊需求。
听听关于数据的故事
当你围绕数据和人们与数据的互动、他们的数据需求等进行一些研究时,要特别注意哪里遗漏了。虽然这可能与手头的分析项目没有太大的相关性,但在定义未来的数据战略时,这是非常宝贵的。
通过揭示一个组织目前在数据方面正在进行或考虑的其他事情,您可以构建一个各种计划交叉点的路线图,利用连接而不是完全孤立地构建另一个东西。
在研究过程中,这两点都有助于在服务蓝图或流程图中捕捉,并在设计多接触点干预时占据中心位置。
在黑客马拉松的第一个晚上,客户已经对我们提出的一系列问题留下了深刻的印象,说我们这半天的工作已经产生了令人兴奋的和非常不同的见解,这些见解是由纯粹的分析团队在两个月的工作后发现的。他们也很高兴能够着手其中的一些工作,最终形成了一份路线图提案。我们进一步了解了正在进行的旨在收集全新数据的工作,并准备制定一项战略,在这些新数据流准备就绪后充分利用(但不依赖)它们。
在黑客马拉松期间,有人可能会担心,在我们的团队真正开始“真正的工作”之前,所有这些设计活动都浪费了很多时间。然而,当我们已经产生了一系列人种学的、数据引导的见解,并针对特定的高价值业务问题设定了目标时,其他团队已经深陷在数据中,仍然在广泛地探索可用的东西,一些团队仍然在努力在他们的笔记本电脑上设置他们的环境。有了一个能让我们阐明这些见解的概念,我们感觉很好,可以回家睡一觉,然后第二天早上重新开始。
通过洞察力推动行动
如果最先进的分析结果没有被采用并推动产生结果的行动,那么它们就毫无价值。事实上,随着围绕分析和人工智能的技术得到更广泛的理解,并走向商业主流,模型采用和其他人为因素成为主要障碍和机会。因此,了解用户的背景和需求(如果你愿意,也可以说是他们自己的故事)并在叙述中提供分析见解,从而使他们能够采取行动,这一点至关重要。以结果为中心的分析团队的工作在交付模型时不能被认为已经完成。
通过应用设计思维和以人为中心的人工智能方法,团队可以发明令人信服的解决方案,帮助用户理解分析见解的真正含义,并在正确的上下文中为他们提供正确的信息。值得注意的是,这可能不需要最先进的技术。
对于我们的项目,我们创建了一个概念,说明了整个用户旅程的未来状态,在此期间,社会工作者开始与一系列干预措施进行互动,以帮助他们做好工作——其中一些是低技术和基于纸张的。至关重要的是,这不是一个天马行空的艺术概念,而是一个非常基于现实并在今天可以执行的概念,同时强调了未来的潜力。
A regular war room? Not so much, once you notice the smileys used in our prioritisation matrix.
包扎
当然,在一场黑客马拉松的结尾,来自不同背景的许多有才华的人讨论了一个非常真实和令人感动的话题,每个人都是赢家。我们离开时不仅对我们所有新产生的见解的潜在影响感到高兴,而且还兴奋地将一个图画书案例研究放入口袋,该案例研究介绍了不同解决问题方法的组合如何能够在不消耗资源的情况下提高团队的效率。
顺便说一下,今天生活在奴隶制下的人比以往任何时候都多。如果你想帮助打击侵犯人权的行为,向国际特赦组织捐款。
这篇文章的节略版已经发表在 QuantumBlack 博客 上。
原载于www.thomasessl.com。本文表达的观点纯属个人观点,不一定代表我的雇主的观点。
日期、时间、日历——数据科学创伤的普遍来源
原文:https://towardsdatascience.com/dates-times-calendars-the-universal-source-of-data-science-trauma-92a887fdedd1?source=collection_archive---------24-----------------------
一份列出了大多数主要疯子的名单,以及一些生存建议
Just some clock in the city. (Photo: Randy Au)
很少有所有数据人共享的共性。我们称之为“数据科学”的领域非常广泛,从人工智能和机器学习的理论工作,一直到个人数据分析师被迫在 Excel 中进行前/后分析以“发现变化的影响”。
但是总有一个话题能让我和一个数据人员建立联系:日期、时间和日历。开始讲一个你在工作中发现的疯狂的故事,你会立刻产生共鸣和友情。每个人以前都被烧伤过。很糟糕。
所以让我们来谈谈好的,坏的,完全疯狂的,以及一些应对的方法。
部分列表
- ISO 8601 是希望,ISO 8601 是爱
- 爱你的图书馆
—来自工程/数据同行的痛苦—
- 日/月/YY 对日/月/YY 对年/月/日等等。
- 12 小时和 24 小时时钟
- Unix/POSIX 时间
- 处理毫秒/微秒
- 其他怪异的时代
- 解析/输出日期/时间
- 时钟同步
—来自自然的痛苦—
- 闰年
- 闰秒
—来自社会的痛苦—
- 非公历
- 农历……任何事情
- 时区
- 夏令时
- 节假日
ISO 8601 是希望,ISO 8601 是爱
YYYY-MM-DDThh:mm:ss.sTZ (and many variations thereof)
ISO 8601 很神奇,每个人在交流日期和时间时都应该默认使用它。句号。
如果每一个数据导出、数据输入 UI、手写表单、过去和现在都符合这一标准,我们就不会陷入今天这个畸形的地狱般的境地。这太重要了,这是我唯一记得的 ISO 标准编号。还有一个专门的子编辑,荣耀归于 ISO8601 。
ISO 8601 有很多部分,但人们通常认为它是 YYYY-MM-DD 日期和 hh:mm:ss.s 时间格式,以及连接两者以创建日期时间、表示时区、小数秒等的无数变体..标准中甚至有更多关于时间间隔和周数的内容,但是这些内容并没有被经常使用。
需要说明的是,关于 ISO 8601 最重要的部分是术语的顺序,它明确且易于记忆和解析。正是这种易于理解的特点使它成为交流日期和时间的首选方法。它还可以很好地进行字符串排序。
当你输出日期时,帮大家一个忙,输出一个 ISO 8601 标准输出,不要发明你自己的格式顺序。总有一天,当您必须解析匿名用户的日期输出时,您会感谢他们。
热爱你的图书馆
谈到日期、时间和日历,你绝对不想重新发明轮子。有很多边缘情况并不明显。除非你已经穷尽了重用别人代码的所有可能性,否则不要去做。
有很多可供你选择语言的库。我说的不仅仅是标准的日期/时间库,这些库可能内置在您的核心语言中,帮助您进行基本的日期计算并输出到特定的格式。通常有一些工具可以帮助你在不发疯的情况下阅读和破译格式。
例如,Python 有 dateparser ,这是一个很棒的小库,它试图为您解析最常见的日期格式,并将它们转换成 datetime 对象。它还有许多其他有趣的功能,比如时区处理、相对时间(“1 分钟前”等)和一些备用日历。很酷的东西。
也许你选择的语言有这样一个库。一定要看。
随着理智的高点(仅有的一点点)消失,让我们慢慢陷入疯狂。
—来自工程/数据同行的痛苦—
这部分是我们最能控制的。这是我们或我们的同事建立的东西。这是我们自己造成的痛苦。在很大程度上,当我们了解问题并避免不良做法时,我们可以将损害最小化。我们可以更少地伤害他人,希望它会回来。
日/月/YY 对日/月/YY 对年/月/日等等。
Cyan: DMY, Yellow: YMD, Magenta: MDY, Green: DMY/YMD, Blue:DMY/MDY, Red:MDY/YMD, Grey: MDY/YMD/DMY ( https://en.wikipedia.org/wiki/Date_format_by_country)
看看这张按国家划分的日期格式图。任何必须与多个国家合作的人,尤其是在美国(MDY)和欧洲(DMY)之间工作的人,都面临着可怕的“8/5/14 是什么意思?”。
您可能认为这种格式与我们电子数据人无关,但这并不是因为您可能要处理本地化的日期时间标记。也许你正在使用网络抓取工具。我从根据我的语言环境“有益地”导出数据的东西那里得到了数据导出,而不是一些理智的东西。我不知道他们为什么这样做,这没有帮助。
从各种传统系统输入的数据和手写笔记可以使用传统的本地格式。真正疯狂的系统(就像收购后拼凑在一起的两个不相交的系统)甚至可能给你不同国家的本地化时间戳,所以你会想知道日期来自哪个国家。
尤羞调出电子表格。为什么电子表格都试图使用 DD/MM/YYYY 类型的格式?!Excel,Google Sheets,Libreoffice,唉!最重要的是,他们有胆量在大量数据导入时不一致地这样做!
处理这个问题的技巧:除了找出数据的正确解析方案之外,别无选择,有时通过痛苦的分析和反复试验,有时通过询问某人或阅读文档。理想的情况是说服数据源输出更干净的东西。尽你所能去做。
12 小时与 24 小时时钟
24 小时时钟格式最常见于日志记录等,但 12 小时格式在人机界面中仍然很常见。当您必须解析/打印供人们使用的数据时,您必须处理这个问题。
不得不解析 AM/P.M .的各种写法实在是太难看了。不要忘记它也因地区而异。不同的国家会用不同的方式来表示上午和下午。请参考您的区域设置以了解预期情况。
说到这里,你知道正午和午夜的命名会因你遵循的习俗而不同吗?因为它当然会。
https://en.wikipedia.org/wiki/12-hour_clock#Confusion_at_noon_and_midnight
生成输出时,坚持使用 24 小时时钟。大多数人都能理解 24 小时时钟,所以数据输出没什么大不了的。为实际的时钟 ui 保存 AM/PM。
Unix/POSIX 时代——还不算太糟,但仍然有缺陷
Unix 时间定义为从1970–01–01t 00:00:00Z 开始的秒数。每天正好有 86400 秒,忽略闰秒。这是一个平稳增长的计数器,是一个很好的属性。这意味着使用 unix 时间的软件不太可能会感到惊讶,也不太可能会有与日历相关的奇怪错误。(我们稍后将回到闰秒,因为那是一个完全独立的主题)。
Unix 时间忽略闰秒的问题在于它是如何实现忽略的…通过重用相同的时间戳 23:59:60(闰秒)作为 00:00:00,因为它认为它们相等。这意味着时差计算将会偏离闰秒数,除非你考虑到它们(如果你在乎的话)。当然,这还会让人觉得一秒钟内发生了 2 秒钟的活动,这也是不可逆的数据丢失,因为您无法仅从时间戳区分这 2 秒钟内的事件。对于人类规模的使用来说,这并不太疯狂,但这几秒钟对于分析来说很重要。对于更敏感的应用程序,有一些方法可以让抹去一天中的闰秒。
Unix 时间通常存储为 32 位整数,尤其是在较旧的系统上。这当然意味着当整数溢出时,还有 2038 年的问题在等待。希望到那时,大多数系统都将转换到 64 位整数,这可以覆盖比当前宇宙年龄更多的秒。
尽管对闰秒的处理不可靠,如果由于各种原因,ISO 8601 由于某种原因不切实际,Unix time 是一个很好的替代选择,尤其是在闰秒模糊的情况下。与紧凑 ISO 8601 的 18+字符串相比,它是一个相对紧凑的 32 或 64 位整数(或 10 个字符串),通常表现良好。
主要的缺点是它不是人类可读的,但是大多数编程语言都很容易处理它。不断地调用 unixtime_to_timestamp() 类型转换函数是一件令人烦恼的事情,但是我很乐意接受它,而不是其他选择。
如果你关心时钟、秒和时间,POSIX 选择(不)处理闰秒的方式显然有点疯狂。这是对历史的一次惊人解读,它是如何变成那样的。
处理毫秒和微秒
大多数时间规范对小数秒的规定相当简单:添加一个小数点,然后是小数的数字:例如 hh:mm:ss.sss 。
需要知道的是,因为计算机上的浮点数学可能有准确性问题,分数通常在内部用整数或类似结构表示,小数点是为了显示的目的。
这方面的一个例子是 NTP 协议实际上使用一个定点 64 位 int 来表示时间。它使用最高有效的 32 位来表示自纪元以来的秒,剩余的 32 位来表示小数秒。
“这种表示的精度大约是 200
皮秒,这应该足以满足最奇特的
需求。”— RFC-1305 ,NTP v3 规范
因为大多数系统不需要 200 皮秒的时间表示,所以大多数系统不遵循这样的设置。相反,您会更常见地看到将 Unix 时间扩展为带点的整数分数秒参数的变体, s.ssss 。另一种常见的格式是将时间存储为一个大整数,称为“自(Unix)纪元以来的毫秒/微秒”。这是可行的,因为毫秒和微秒分别是 10⁻和 10 ⁻⁶,所以用milliseconds_since_epoch/1000 = unixtime.milliseconds
除以/乘以正确的因子来来回转换是微不足道的
其他奇怪的时代
Epoch 是任意的构造,所以除了 POSIX Epoch 之外,当您在环境之间移动时,还会遇到许多其他的 Epoch。
最著名的可能是 Excel,它开始于 1900 年 1 月 0 日(是的,1 月 0 日…),并计算自纪元开始以来的天数。但是其他有趣的包括从 1980 年 1 月 6 日开始的 GPS 时间,以及从 1900 年 1 月 1 日开始的 NTP 纪元。Twitter 开始了他们的 twepoch 他们的第一条 tweet。
99.99999%的时间里,您可以生活和做日期计算,而不必过多考虑纪元,这要感谢良好的库和接口(以及有多少事情默认为 unix 时间)。
但是偶尔你会遇到突然变得重要的情况。我最近不得不与 Excel 的时间格式作斗争,因为将 1 小时添加到时间戳涉及到将超级直观的 1/24 添加到时间戳(因为它是以天为单位的)。
在其他情况下,时代很重要,当你超越它们的时候(通常是在它们之前)。例如,TAI 原子刻度的纪元是 1961–01–01t 20:00:00(UT2),也就是我们称为 TAI 的原子秒基本上开始累积的时间。如果你以某种方式在纪元前进行推断,这就提出了你到底在用什么的问题。如果提到 1600 年这个原子秒尺度的时间,这又意味着什么呢?那实际上是一派胡言。
解析/输出日期/时间—处理 strptime/strftime 等。
ISO8601 仅仅定义了日期/时间的各个部分应该出现在哪里,以什么方式出现。它不是一种定义处理这类事情的语法的语言规范。因此,我们必须把这个问题作为一个单独的问题来处理。
我不知道出于输出或解析目的表示日期/时间部分的标准方法。最接近标准的东西来自于 POSIX 和基于它的 C 库。
*#The familiar %-based syntax we all know and constantly forget
%Y-%m-%d*
由于 POSIX 标准中的一些不明确的地方,尤其是在混合了各种语言环境设置的情况下,不同种类的系统之间的语法有时会略有不同,从这个意义上说,这并不是一个严格的“标准”。但这是我能找到的最接近的东西了。
POSIX 库的好处在于它已经过实战测试,可以正常工作。由于日期/时间代码如此混乱,很少有人想重新发明轮子。最终发生的情况是,许多植根于 C 和 Unix 的语言广泛使用这种格式,因为 C 系统 API 可供使用。例如,Python、R、Ruby 和 Golang 就是这样,因此它们的日期格式字符串非常相似。
但是并不是所有的语言都使用 strftime! Java 有自己的 SimpleDateFormat,Javascript 有 Intl。DateTimeFormat , C#自带东西。他们彼此都非常不同。有时在库中有一个单独的 strftime 选项会很方便,例如 Perl 有一个本机的 time 格式,但是可以选择使用 time_strftime。
一般都是巨乱。当你需要它们时,只需查找函数,尤其是当你跨越不同的系统和语言时。如果你必须熟悉一个,POSIX one 可能是最普遍的。但是要知道总有一些东西可以利用,永远不要发明自己的东西。
时钟同步
每个时钟都是独一无二的。它们可以比旁边的一个完全相同的时钟跳动得稍快或稍慢。所有的时钟也不是完全稳定的。由于包括温度、方向、电压甚至相对论在内的大量影响,时钟将会失去同步。即使对于超精确和昂贵的原子钟来说也是如此,更不用说你主板上的便宜的水晶钟了,它们的精确度要差很多倍。
有一个精确的时钟对这个世界没有用,关于时钟最重要的事情是时钟应该同意高精度。在分布式系统、云计算、虚拟机和物联网的现代世界中,到处都有不同质量的多个时钟需要在时间上达成一致。
通常,作为一名数据科学家,你不会涉及到确保连接到你的系统的每台计算机都有一个准确的时钟这一困难的工程问题。但是,你很可能是所有这些时钟数据的主要消费者之一,如果这些时钟出了问题,你将受到严重影响。
当时钟不同步时,你就无法说事件 A 发生在事件 b 之前。根据时钟不同步的严重程度,你甚至可以看到事件和因果关系似乎在时间上倒流。像 Cloud Spanner 和 cocroach DB这样的数据库花费了大量精力(在 Spanner 的情况下,还有原子钟)来保持时间准确,以便 db 事件对于可以跨越全球的系统来说保持正确的时间顺序(可串行化和可线性化)。
虽然我们大多数人都不必过多考虑时钟误差,但如果您正在构建数据库系统,或者在一个时间尺度非常精确的领域中工作,或者远程传感器可能存在严重的时钟误差,您就需要注意了,因为时钟误差可能非常细微,并会导致非常奇怪的错误。认真考虑使用哪个时钟来设置时间戳变得很重要(服务器端还是客户端,等等)。
顺便提一下,计算机使用 NTP 协议来相互同步时钟已经有很长时间了。NTP 通常被认为能够在时间服务器的毫秒内获得时钟(多少毫秒,是 10ms 还是 100ms,取决于你的网络和设置)。为了获得更高的精度,还有 PTP ,它允许额外的(昂贵的)硬件时钟辅助来提高性能(我经常看到提到在微秒内同步到的时钟 orb 更好)。
—来自自然的痛苦—
这一部分是关于痛苦和复杂的事情,仅仅是因为大自然没有完全符合人类的习俗。我们能做的不多,只能生活在我们所拥有的一切中,并充分利用它。
闰年
人们熟悉公历,但闰年的规则比简单地每四年有一个闰年要复杂得多。还有 100/400 法则。
除了能被 100 整除的年份之外,每一个能被 4 整除的年份都是闰年,但如果能被 400 整除,这些百年就是闰年。— 维基百科
这很难实现,也很容易忘记,请在处理日期时重用一个正确实现的日历模块,即使是简单的事情,比如增加未来的日期。
日历已经有几个世纪没有改变了,现有的代码已经稳定运行了几十年。
闰秒
闰秒的存在是因为我们的原子钟与地球的自转相比太精确了。这让生活变得复杂。
这个迷人的时间兔子洞的简短故事是,如果我们将一天精确地定义为 86,400 秒,那么使用 SI 秒的原子时间刻度比地球自转速度略快,可以将太阳放在中午天空的同一部分。我们的日常民用时标(UTC)由于使用原子定义的 SI 秒,比太阳秒(平均太阳日的 1/86,400,这是 UT1 时标)略快。由于民用时间是基于太阳中午在格林威治上空的正确位置,无论何时|UT1-UTC|> 0.9s
,我们都故意通过增加 1 秒来延迟 UTC,并使一天为 86,401 秒,以保持两个时标同步。
如果地球转得更快,我们一天也需要 86,399 个小时,也有类似的协议。显然,有过这样的例子,地质构造显著地加速了地球的自转,但不足以跨越 0.9 秒的门槛来触发闰秒。想象一下,当 23:59:59 一天都不存在的时候,我们会发现多么疯狂的错误。
Changes of the length of day (ms difference per day) over history, colored bands are integral sums of 1 or 0.5hrs over the year
闰秒的主要问题是它们不可预测。地球的自转受到潮汐、月亮、地幔和地核中发生的事情等的影响..这是一个测量值。所以,你唯一能做的就是查看官方公告中的闰秒公告。
在大多数应用中,闰秒是我们可以安全忽略的东西。大多数日期计算都基于日历天数的差异,然后根据 86,400 秒/天计算秒数。
例如,从 12 月 31 日开始到 1 月 3 日开始有 3 天的时间(不包括 1 月 3 日)。我们会计算 3 个日历日,31 日,1 日和 2 日。我们通常不会说有 259,200 秒(或 259,201 w/ a 闰秒),除非明确要求该值。失去 1 闰秒将代表该时间长度中 0.00038%的误差。
对于那些重要的实例,有所有闰秒的列表,比如这个。这样,您可以返回并更正任何受影响的数据。
闰秒错误
闰秒经常会导致意想不到的错误,因为时钟的行为可能不直观,人们很少会忘记它们。一个令人难忘的例子发生在 2012 年,当时一个 6 月 30 日的闰秒触发了 Linux 内核和 Java 中的错误,导致各地一系列系统瘫痪。我记得看到停电,第二天每个人都对即将到来的闰秒保持警惕。
尽管如此,错误仍然会发生。2017 年 1 月, Cloudflare 的 DNS 也遭到了一次。这种东西很微妙,也很罕见,你可能没有测试来防范它。所以请放心,每一个闰秒,在某个地方,都会有人度过一个糟糕的夜晚。
—来自社会的痛苦—
这类问题可能是所有问题中最糟糕的。整个社会充满了矛盾、不一致和武断的规则。他们也可以在任何时候,以任何理由改变技术标准。
非公历日历
我们大多数人都生活在公历中,这很好,因为虽然我们不得不处理闰年之类的事情,但我们至少都同意使用相同的日历。
直到我们没有。
我甚至没有谈论有趣的替代日历,比如没有人真正使用的修订儒略历,或者在伊朗使用的 T2 波斯历。历史上有很多不同的日历需要被调和。历史学家和天文学家最敏锐地意识到这一点,因为他们最有可能不得不使用追溯到几个世纪或几千年前的记录。我们其余的人是幸运的。
相反,我说的是用于零售/商业目的的人造日历,比如4–4–5 日历。这些在世界上被广泛使用!我在一个必须处理商品生产和装运的电子商务网站工作时遇到了这个问题,所以他们用它来跟踪他们的工厂工作。
我仍然没有完全理解 4–4–5,而是依靠转换函数/表格来处理它。
处理这种情况的技巧 : 在没有精确算法的情况下,永远不要试图自己复制另一种日历的逻辑。他们是神秘的!自己写就像发明自己的加密算法。不要这样做。你会搞砸的。必须有一个库可以做到这一点,即使它是针对另一种语言或者只是一个查找表。使用现有资源。
事实上,永远不要试图实施自己的日历,即使是公历。
月球…任何东西
阴历(目前使用的大多数是阴阳历)的表现与我们熟悉的阳历非常不同。
我是出生在纽约的华裔。我和其他人一样是用公历长大的。但在一年中看似随机的时间点,直到很久以后才会明朗,我的家人会在农历庆祝节日。有些年份的农历新年是在二月初,有时迟至三月。
这有什么关系?因为世界上的一些主要节日都与月亮挂钩。中国新年是其中之一,超过 10 亿人为了它去度假一个多星期。
不在亚洲?还有复活节,这是许多受基督教影响的国家的主要节日。这种东西会导致你的时间序列数据出现各种异常。
幸运的是,有代码和表格可以找出这些重要的日期在哪里!你只需要知道这些东西的存在,这样你就可以补偿。
时区
没有关于日期和时间的疯狂的讨论,就不能提到时区概念这种特殊的疯狂。它考虑了所有复杂的计时问题(闰秒、闰日等),并加入了明显的人为(和政治)因素。
简言之,避免像对待瘟疫一样使用当地时间。因为最终会溃烂成伤害你的东西。用 UTC 存储所有东西,或者像 Unix 时间一样与 UTC 挂钩的东西(没有夏令时诡计,没有政府改变他们的时间规则)。必要时,您可以随时以当地时间显示事物。
我们为什么要和他们打交道呢?因为人类。一些分析使用当地时间效果更好,例如测量早餐活动。人们使用本地时间来协调他们的个人生活,但这是计算机的噩梦。
One of my favorite videos on YouTube, ever. The pain and frustration is real.
时区变化相当频繁。不是每个时区都是整数小时,印度标准时间是 UTC+5:30,新西兰的查塔姆岛标准时间是 UTC+12:45。夏令时/夏令时规则可能会增加/减少一个小时(或更多),在某些地区可能会遵守,也可能不遵守。我甚至不确定我是否理解由于政治原因,一个地方有两个当地时间的情况。
如果你想了解世界上所有时区的变化,你可以下载时区数据库,订阅 IANA 的公告和讨论。事情经常出人意料地变化。
夏令时,时间序列的破坏者
夏令时涉及整个国家或地区,让他们的时钟改变到另一个小时,通常(但不总是!)以 1 小时为增量完成。这只是一群人可以决定去做的事情。更糟糕的是,政府可以随时改变其发生的细节。如果你幸运的话,他们会提前宣布,这样人们就可以做好准备。这是一件不得不处理的可怕事情。
What Daylight Saving shuffles look like to an analyst working in local time who forgets it happened
这就是为什么总是存储带有 UTC 时间戳的数据被认为是最佳做法,因为 1)它没有夏令时,2)它不能在未来的任何时候决定采用夏令时。
第二点很重要。仅仅因为一个地方现在没有日光节约问题,并不保证将来也不会有。只有 UTC 真正拥有这种保证。
假日
作为一名网络分析和广告出身的人,我对我经常打交道的市场(主要是美国)的假日越来越敏感。主要原因是因为当有一个影响整个国家的重大节日时,网络流量、广告点击量、小配件销售量都会下降。
复活节尤其令人头疼,因为它是由月亮的位置决定的,这意味着它每年都在不同的日期,中国的农历新年也是如此。在我职业生涯的早期,我数不清有多少次年度或月度报告显示巨大的变化数字,仅仅是因为复活节在现在或过去已经到来。现在我知道要检查它(如果有必要,事件会提前发出警告)。
关于假期的另一件令人沮丧的事情是,它们对不同的事情有不同的影响。如果每个人都回家度假,车流量就会增加,但如果他们都呆在原地,车流量就会减少。购买一些东西(如玉米糖)在特定季节会增加,而其他物品则不是季节性的。你的特定目标人群可能会庆祝其他人不庆祝的事情。不仅仅取决于外界,还取决于你在乎什么。
你如何处理这个?你唯一能做的就是看看过去的行为,认真思考你的用户群,并询问主题专家。
外面可能还有更多
一篇稍长的中篇文章可能涵盖所有时空的错乱。我已经尽了最大努力来涵盖你应该注意的真正大的领域,但是具体的要由你来决定。如果我错过了什么,让我知道!
谢谢
感谢所有善良的人们,是他们温柔地鼓励我敢于写下这种疯狂。
你知道你是谁。
参考资料,链接到关于时间的酷东西
对于任何想深入研究计时历史的人来说,这里有一些参考资料,是我在理解 unixtime 如何处理闰秒以及闰秒是什么时使用的
- 维基百科页面为 UT 、 Unixtime 、 UTC 、地球自转、时间格式化/存储 bug
- POSIX UNIX 时间标准形成的历史
- 一个非常深入的时标列表,不仅仅是史蒂夫·艾伦的 UT1 和 UTC
- 史蒂夫·艾伦 w/r/t 更多关于时间的东西,取消 UTC 的闰秒意味着什么
- IERS 的网站关于 UT1 和一天的长度
- PHP 时间表的解释终于让我明白了
- 我发现 unix time(不)如何处理闰秒,另一页解释 PHP 的时间
- Chrono:用于日期计算的低级算法 —它们从 3 月 1 日开始计算日历,以更优雅地处理闰年(闰年会将一天添加到一年的最后一天,而不是随机放入其中)
- NIST 闰秒常见问题和 UT1-UTC 信息
- 泰纪元是 1961 年 01 月 01 日 20:00:00 UT2
- 一份假期清单,其中只有极小的一部分会困扰你,直到更多的假期突然来临。
- 程序员相信的关于时间的错误列表——有人在我写这篇文章的中途把它和我联系起来,我想我的例子涵盖了很多这样的例子,但不是所有
- 您是否知道 ntpd 并不是 NTP 的唯一实现?还有 Chrony ,和 openntpd ,针对不同需求设计。
交友 App 匹配优化开发
原文:https://towardsdatascience.com/dating-app-matching-optimization-development-d42ace4ed83c?source=collection_archive---------39-----------------------
来自 Dine 首席执行官在 PyCon JP 2019 的体验
Photo by freestocks.org on Unsplash
PyCon JP 2019 于 2019/9/16~ 2019/9/17 举办,为期两天。这个帖子是关于第二天的一个讲座。
盛冈孝是约会应用 Dine 的首席执行官。他的演讲主要集中在他在匹配优化方面的开发经验。数据处理在 Google Cloud data flow(Apache Beam Python SDK)下,ML 部分由 Cloud ML 引擎完成。幻灯片在这里。
背景
约会应用的目标是匹配两个用户。主要的匹配方法有两种,搜索法和推荐法。
- 搜索方法:用户根据自己的喜好进行搜索
- 推荐方式:交友网站会为用户推荐候选人
盛冈隆告诉 Dine 主要采用推荐法。
为了解决 稳定婚姻问题 ,Dine 采用了 大风–沙普利算法 。但是这个算法有一个很大的问题,计算成本巨大。
降低计算成本
看,我们总共有 N 个用户。我们首先计算用户 A 相对于其他 N-1 个用户的得分。然后,我们对 N 个用户进行排名,为用户 a 进行推荐,运行时间将为 O(N log N)。
为了降低计算成本,Dine 将用户分成不同的组(演讲者没有提到划分标准)。分组的优点是可以将用户数从 N 个减少到组数,并可以并行计算得分。
但还是有两个问题。
- 匹配性能低
- 分组方法对少数用户产生了不良影响
但是演讲者没有提到如何解决这些问题。他在接下来的演讲中主要讲了如何提高计算能力。
基础设施改善
原来的系统架构如下图所示。
AppEngine 正在进行匹配过程计算。但是对于 GAE 实例的 CPU 和内存来说,计算量仍然很大。
来解决问题。Dine 用提供 Java 和 Python SDK 的 Could Dataflow 代替 GAE。
这个系统的容量比以前增加了 10 倍。
与 can AutoML 表集成
数据流的一个优势是与其他机器学习服务的高度兼容性。Dine 使用 Cloud AutoML Table 从用户配置文件中构建表格功能。它会自动调整参数。第一天介绍 AutoML,业界使用的 AutoML 库概述。
根据 AB 测试的结果,匹配分数(f1)增加了 20%。以下是演讲者在使用 Cloud AutoML Table 时的一些想法。
优点:
- 使用 BigQuery 很容易
- 批量预测和在线预测非常容易部署
缺点:
- 无法下载模型
- 不知道模型架构
查看我的其他帖子 中等 同 一分类查看 !
GitHub:bramble Xu LinkedIn:徐亮 博客:bramble Xu
参考
- https://pycon.jp/2019/schedule/?sessionId=207
- https://drive . Google . com/file/d/1 sxn 7 _ u 9 oddell pq 0 jn 2h 8 vfll-HBP 2 az/view
用决策树确定文本的日期
原文:https://towardsdatascience.com/dating-texts-with-decision-trees-c716841a33f1?source=collection_archive---------21-----------------------
使用决策树来估计一本书的写作年份
Photo by Kiwihug on Unsplash
介绍
如果我们使用机器学习来估计这本书的写作时间会怎么样?
想象你自己在你祖父母的旧阁楼里,仔细阅读布满灰尘的旧书架,这时一本不熟悉的大部头吸引了你的目光。这似乎是一部小说。你不知道它是什么时候写的,这个答案似乎连谷歌自己都不知道。你拍下其中一页的照片,然后使用文本提取器,获得文本的数字表示。如果我们使用机器学习来估计这本书的写作时间会怎么样?
在这篇文章中,我们将讨论和实现一些方法来尝试确定文本的日期。除了所述的例子,这种类型的模型在一系列领域中有应用,从检测假新闻,到打击历史修正主义,到改善历史上准确的小说,到确定死后文学作品的真实性。
这项任务最容易解释的模型之一是决策树,它可以提供关于哪些类型的单词可以用来区分文本日期的有趣推论。
资料组
我们的首要任务是收集数据进行训练。我们将要使用的数据集包含大约 200 个文本,按时间分布如下
Time spread of the dataset
我们将自己限制在这个时间段内,因为在一个更长的时间段内,英语的不同状态之间的绝对语言距离太大了(对于一个说现代英语的人来说,14 世纪的英语是难以理解的)。查找较旧的文本数据也是乏味的,因为许多较旧文本的可用版本只是用更近的、可理解的英语转录的(使用这些版本而没有适当的谨慎相当于给数据贴错标签)。我们的优先任务之一是确保在每个时间段,文本包括不同的主题,以防止我们的模型识别文本主题或格式,而不是纪元。
特征选择
作为健全性检查,为了确保文本可以可行地聚类,我们可以执行主成分分析 (PCA):
PCA on the dataset
我们有相当多的聚类,然而,蓝点的聚类(17 世纪晚期)可能是因为这一时期的文本处理了类似的主题。这凸显了从多个来源获取数据的重要性,因为它显示了模型倾向于选择最简单的要素。
表示文本
有无数种方式来表示文本数据,最常见的一种是 word2vec,将所有的单词放在一个 n 维向量空间中,相似的单词在空间上很接近。然而,出于我们的目的,我们注意到基于 word2vec 的模型对于决策树来说既慢又低效。
相反,让我们使用一种单词袋方法,其中每本书是一个向量,其索引代表一个唯一的单词,包含该单词在书中的实例数量。向量的大小将取决于词汇的大小(即,如果你的书中有 1000 个独特的单词,则输入的大小将是 1000)。
例如,假设您的词汇量为 5,表示为列表
Vocabulary for the example
我们想把“我饿了”这句话编码产生的向量将简单地是:
Encoding for “I am hungry” with the given vocabulary
相反,如果是“我饿了,我”,我们就会
Encoding for “I am hungry, I” with the given vocabulary
既然我们有了对每本书进行编码的方法,那么让我们定义一个准确性度量。
定义准确性
假设我们的模型声称一本书写于 1527 年,但它实际上写于 1531 年。模型准确吗?
尽管均方误差(MSE)是确定模型准确性的显而易见的方法,但它不是很直观。为了产生更简单的度量,让我们定义 𝛿 、容差(以年为单位),以获得以下精度函数:
换句话说,如果模型在 𝛿 年内猜测正确,那么我们说它是准确的;否则就是不准确的。在下文中,我们将使用𝛿的= 50 年和𝛿的= 100 年。****
什么是决策树?
让我们来看看我们将要用来学习将文本与日期相关联的模型,决策树。
决策树分类器类似于流程图,终端节点代表分类输出/决策。从一个数据集开始,测量熵以找到一种分割数据集的方法,直到所有数据都属于同一个类。
Basic example of a decision tree¹
点击此处查看更多关于决策树的文章。
结果和解释
模型的准确性
一旦对决策树进行了训练,我们就可以在测试集上绘制一些预测:
Results for a decision tree with pruning
上面的图是线性的,表明决策树的性能很好。事实上,在我们的测试集上,我们获得了 84%的准确率(对于𝛿100 年)和 82%的准确率(对于𝛿50 年)。
解释和可视化
在这里,我们可以看到树的顶部本身的可视化。
树的许多分裂决定是智能的,对我们人类来说是有意义的。例如,电话在 1900 年开始流行,珀西这个名字的流行程度在 19 世纪晚期达到顶峰,从那以后稳步急剧下降。这里有一个表格,包含一些有趣的分裂,可以在树中找到。
Some interesting splits in the decision tree
结论
我希望您现在对如何使用决策树来估算一本书的写作日期有了更好的了解。
感谢
我要感谢保罗·塞格斯和法布里斯·海底平顶山-西奥内斯对本文的贡献。
参考
[1] Chirag Sehra,决策树易解释(2018),https://medium . com/@ Chirag se HRA 42/Decision-Trees-Explained-Easily-28f 23241248
David Duvenaud 谈学术界人工智能和机器学习的未来
原文:https://towardsdatascience.com/david-duvenaud-on-the-future-of-ai-and-machine-learning-in-academia-7c3ae5aa290d?source=collection_archive---------27-----------------------
在成为多伦多大学机器学习助理教授之前,David Duvenaud 曾在剑桥、牛津和谷歌大脑工作过。
他在神经颂歌方面做了开创性的工作,并且在过去十年的大部分时间里一直处于该领域的前沿。
大卫和我们坐下来谈论机器学习的发展方向,以及学术生涯是如何形成的。
在 Twitter 上关注他: @DavidDuvenaud 点击这里查看这一集:
注意— Seq2Seq 型号
原文:https://towardsdatascience.com/day-1-2-attention-seq2seq-models-65df3f49e263?source=collection_archive---------2-----------------------
序列间 (abrv。Seq2Seq)模型是深度学习模型,在机器翻译、文本摘要和图像字幕等任务中取得了很多成功。谷歌翻译在 2016 年末开始在生产中使用这样的模型。这两个开创性的论文中解释了这些模型( Sutskever 等人,2014 , Cho 等人,2014 )。
Seq2Seq 模型是什么?
Seq2Seq 模型是一种模型,它接受一系列项目(单词、字母、时间序列等)并输出另一系列项目。
Seq2Seq Model
在神经机器翻译的情况下,输入是一系列单词,输出是翻译的一系列单词。
现在让我们努力减少我们的黑匣子的黑色。该模型由一个编码器和一个解码器组成。编码器以隐藏状态向量的形式捕获输入序列的上下文,并将其发送至解码器,解码器随后产生输出序列。由于任务是基于序列的,编码器和解码器都倾向于使用某种形式的 RNNs、LSTMs、GRUs 等。隐藏状态向量可以是任何大小,尽管在大多数情况下,它被视为 2 的次方和一个大数字(256,512,1024 ),这在某种程度上可以表示完整序列和域的复杂性。
我们再深入一点!RNNs!
RNN Cell
根据设计,RNNs 有两个输入,一个是它们看到的当前示例,另一个是以前输入的表示。因此,时间步长 t 处的输出取决于当前输入以及时间 t-1 处的输入。这就是为什么他们在面对与序列相关的任务时表现得更好。顺序信息保存在网络的隐藏状态中,并在下一个实例中使用。
由 RNNs 组成的编码器将序列作为输入,并在序列的末尾生成最终嵌入。然后将它发送到解码器,解码器使用它来预测序列,在每次连续预测之后,它使用前一个隐藏状态来预测序列的下一个实例。
Encoder-Decoder Model for Seq2Seq Modelling
缺点: 输出序列严重依赖编码器最终输出中隐藏状态定义的上下文,使得模型处理长句具有挑战性。在长序列的情况下,初始上下文很可能在序列结束时丢失。
解决方案: Bahdanau 等人,2014 和 Luong 等人,2015 论文介绍了一种称为“注意力”的技术,它允许模型在输出序列的每个阶段关注输入序列的不同部分,从而允许上下文从头到尾得到保留。
现在我引起你的注意了!;P
简而言之,由于问题是编码器末端的单个隐藏状态向量是不够的,我们发送与输入序列中实例数量一样多的隐藏状态向量。这是新的表现形式:
Seq2Seq with Attention — incomplete
听起来很简单,不是吗?让我们引入更多的复杂性。解码器到底是如何使用隐藏状态向量集的?到目前为止,这两个模型之间的唯一区别是在解码阶段引入了所有输入实例的隐藏状态。
创建基于注意力的模型的另一个有价值的补充是上下文向量。这是为输出序列中的每个时间实例生成的。在每一步,上下文向量是输入隐藏状态的加权和,如下所示:
Context Vector
但是如何在预测中使用上下文向量呢?而权重 a1,a2,a3 又是如何决定的呢?让我们一次解决一个问题,先解决一个简单的问题——上下文向量。
所生成的上下文向量通过级联与隐藏状态向量相结合,并且这个新的注意力隐藏向量用于预测该时刻的输出。注意,这个注意力向量是为输出序列中的每个时间实例生成的,并且现在取代了隐藏状态向量。
Attention hidden state
现在我们到了谜题的最后一块,注意力得分。
同样,简单地说,这些是另一个神经网络模型比对模型的输出,该模型最初与 seq2seq 模型联合训练。对齐模型对输入(由其隐藏状态表示)与先前输出(由注意力隐藏状态表示)的匹配程度进行评分,并对每个输入与先前输出进行匹配。然后对所有这些分数取一个最大值,得到的数字就是每个输入的注意力分数。
Attention scoring
因此,我们现在知道输入的哪一部分对于输出序列中每个实例的预测是最重要的。在训练阶段,模型已经学会了如何将各种实例从输出序列对齐到输入序列。下面是一个机器翻译模型的示例,以矩阵形式显示。注意,矩阵中的每个条目都是与输入和输出序列相关联的注意力分数。
French to English conversion. Notice how the model weighted the input sequence while outputing European Economic Area”
所以现在我们有了最终完整的模型
Seq2Seq Attention Based Model
如我们所见,我们开始使用的黑盒现在变成了白色。以下是图片摘要:
我希望你觉得这很有用并且容易理解。如果有任何更正或任何形式的反馈,我希望收到您的来信。请在这里评论,让我知道。
参考资料:
[## 可视化神经机器翻译模型(Seq2seq 模型的机制,注意)
翻译:中文(简体),韩文观察:麻省理工学院的深度学习艺术讲座引用此贴…
jalammar.github.io](https://jalammar.github.io/visualizing-neural-machine-translation-mechanics-of-seq2seq-models-with-attention/) [## LSTMs 和递归神经网络初学者指南
数据只能反向理解;但它必须向前看。-索伦·克尔凯郭尔,日记内容实际上…
skymind.ai](https://skymind.ai/wiki/lstm) [## 通过联合学习对齐和翻译的神经机器翻译
神经机器翻译是最近提出的机器翻译方法。不同于传统的统计…
arxiv.org](https://arxiv.org/abs/1409.0473) [## 张量流/nmt
TensorFlow 神经机器翻译教程。通过在…上创建帐户,为 tensorflow/nmt 的发展做出贡献
github.com](https://github.com/tensorflow/nmt) [## 在翻译中发现:谷歌翻译中更准确、流畅的句子
在 10 年里,谷歌翻译已经从仅仅支持几种语言发展到 103 种,连接陌生人,达到…
博客.谷歌](https://blog.google/products/translate/found-translation-more-accurate-fluent-sentences-google-translate/) [## Seq2seq 关注自我关注:第 1 部分
Seq2seq 与注意模型
medium.com](https://medium.com/@bgg/seq2seq-pay-attention-to-self-attention-part-1-d332e85e9aad) [## 基于注意力的神经机器翻译的有效方法
一种注意力机制最近被用于通过选择性地聚焦于……来改善神经机器翻译(NMT)
arxiv.org](https://arxiv.org/abs/1508.04025) [## 为什么神经元或卷积的数量选择 2 的等幂?
感谢您为 Data Science Stack Exchange 贡献答案!请务必回答问题。提供…
datascience.stackexchange.com](https://datascience.stackexchange.com/questions/16416/why-the-number-of-neurons-or-convolutions-chosen-equal-powers-of-two)
Sutskever,Ilya,Oriol Vinyals 和 Quoc V. Le。"用神经网络进行序列对序列学习."神经信息处理系统的进展。2014.
使用统计机器翻译的 RNN 编码解码器学习短语表达 arXiv 预印本 arXiv:1406.1078 (2014)。
https://www . guide light . com . au/the-guide light-psychology-blog/?类别=生活+教练
DBSCAN 算法:Python Scikit 的完整指南和应用-学习
原文:https://towardsdatascience.com/dbscan-algorithm-complete-guide-and-application-with-python-scikit-learn-d690cbae4c5d?source=collection_archive---------2-----------------------
聚类空间数据库
Density Based Clustering ? (Picture Credit: Adil Wahid)
我打算在这篇文章中讨论的是—
- DBSCAN 算法步骤,遵循 Martin Ester 等人的原始研究论文[1]
- 直接密度可达点的关键概念,用于划分集群的核心点和边界点。这也有助于我们识别数据中的噪声。
- 使用 python 和 scikit 的 DBSCAN 算法应用示例——通过根据每年的天气数据对加拿大的不同地区进行聚类来学习。学习使用一个奇妙的工具-底图,通过 python 在地图上绘制 2D 数据。所有的代码(用 python 写的),图片(用 Libre Office 制作的)都可以在 github 中找到(文章末尾给出了链接)。
在处理不同密度、大小和形状的空间聚类时,检测点的聚类可能是具有挑战性的。如果数据包含噪声和异常值,任务会更加复杂。为了处理大型空间数据库,Martin Ester 和他的合著者提出了带噪声的应用程序的基于密度的空间聚类 (DBSCAN),这仍然是引用率最高的科学论文之一。3 使用 Ester 等人的算法的主要原因是
1.它需要最少的领域知识。
2.它可以发现任意形状的星团。
3.适用于大型数据库,即样本数量超过几千个。
1.DBSCAN 算法中的定义:
为了更详细地理解 DBSCAN,让我们深入了解一下。DBS can 算法的主要概念是定位被低密度区域彼此隔开的高密度区域。 那么,我们如何测量一个地区的密度呢?以下是两个步骤—
- 点 p 处的密度:从点 P 开始半径为 Eps (ϵ) 的圆内的点数。
- 密集区域:对于簇中的每个点,半径为ϵ的圆至少包含最小数量的点( MinPts )。
数据库 D 中的点 P 的ε邻域被定义为(遵循 Ester 等人的定义)
N (p) = {q ∈ D | dist(p,q) ≤ ϵ} …(1)
根据密集区域的定义,如果|N (p)|≥ MinPts,则一个点可以被分类为 核心点 。顾名思义,核心点通常位于集群内部。一个 边界点 在其ϵ-neighborhood (N)内的个数少于 MinPts,但它位于另一个核心点的邻域内。 噪声 是既不是核心点也不是边界点的任意数据点。见下图更好理解。
Core and Border Points in a Database D. Green data point is Noise. (Source: Re-created by Author, Original Reference [2])
这种方法的一个问题是,边界点的ϵ-neighborhood 包含的点的数量明显少于核心点。由于 MinPts 是算法中的一个参数,将其设置为较低的值以包括聚类中的边界点会导致消除噪声的问题。这里出现了密度可达和密度连接点的概念。
直接密度可达:数据点 a 是从点 b 直接密度可达,如果—
- | N(b)|≥min pts;即 b 是核心点。
- a ∈ N(b)即 a 在 b 的ε邻域内
考虑到边界点和核心点,我们可以理解直接密度可达的概念是不对称的,因为即使核心点落在边界点的ε邻域中,边界点也没有足够的 MinPts,因此不能满足这两个条件。
密度可达:点 a 是从 b 点相对于ϵ和 MinPts 可达的密度,如果—
密度可达本质上是传递的,但是,就像直接密度可达一样,它是不对称的。
密度连通:可能存在这样的情况,当两个边界点将属于同一个聚类,但是它们不共享一个特定的核心点,那么我们说它们是密度连通的,如果存在一个公共核心点,从该公共核心点这些边界点是密度可达的。如你所知,密度连接是对称的。Ester 等人论文中的定义如下—
“点 a 是相对于ϵ和 MinPts 连接到点 b 的密度,如果有一个点 c 使得 a 和 b 都是从 c w.r.t .到ϵ和 MinPts 的可达密度。”
Two border points a, b are density connected through the core point c. Source: Created by Author
2.DBSCAN 算法的步骤:
有了上面的定义,我们可以按如下步骤进行 DBSCAN 算法—
- 该算法从没有被访问过的任意点开始,并且从ϵ参数中检索其邻域信息。
- 如果该点包含ϵ邻域内的 MinPts ,则集群形成开始。否则该点被标记为噪声。稍后可以在不同点的ϵ邻域内找到该点,因此可以使其成为聚类的一部分。密度可达和密度连接点的概念在这里很重要。
- 如果发现一个点是核心点,那么ϵ邻域内的点也是聚类的一部分。因此,在ϵ邻域内找到的所有点都将被添加,如果它们也是核心点的话,还有它们自己的ϵ邻域。
- 上述过程继续,直到完全找到密度连接的聚类。
- 该过程从新的点重新开始,该新的点可以是新群的一部分或者被标记为噪声。
从上面的定义和算法步骤,你可以猜出DBS can 算法的两个最大缺点。
- 如果数据库中的数据点形成了不同密度的聚类,那么 DBSCAN 无法很好地对数据点进行聚类,因为聚类取决于ϵ和 MinPts 参数,不能为所有聚类单独选择它们。
- 如果数据和特征没有被领域专家很好地理解,那么设置ϵ和 MinPts 可能会很棘手,可能需要用不同的ϵ和 MinPts 值进行几次迭代比较。
一旦基本原理清楚了一点,现在将看到一个使用 Scikit-learn 和 python 的 DBSCAN 算法的例子。
3.带 Scikit-Learn 的 DBSCAN 算法示例:
为了查看 DBSCAN 算法的一个实际例子,我使用了加拿大 2014 年的天气数据来对气象站进行聚类。首先让我们加载数据—
数据帧由 1341 行和 25 列组成,为了理解列名代表什么,让我们看看下面最重要的特性
因为,我想使用不同的温度作为第一次尝试聚类气象站的几个主要特征,首先,让我们删除“平均温度(Tm)”、“最低温度(Tn)”和“最高温度(Tx)”列中包含 NaN 值的行。
在删除上述列中包含 NaN 值的行后,我们剩下 1255 个样本。尽管这几乎是 7%的数据损失,但是考虑到我们仍然有超过 1000 个样本,让我们继续进行聚类。
由于我们要进行空间聚类,并在地图投影中查看聚类,以及不同的温度(“Tm”、“Tn”、“Tx”)、“Lat”、“long”也应作为特征。在这里,我使用了底图工具包,这是一个用于绘制 2D 数据的库,以便用 Python 可视化地图。如底图文档中所述— “底图本身不进行任何绘制,但提供了将坐标转换为 25 种不同地图投影之一的工具”。底图的一个重要属性是-使用参数纬度/经度(以度为单位,如我们的数据框中所示)调用底图类实例,以获取 x/y 地图投影坐标。
让我们使用底图绘制气象站,以便熟悉它。从导入必要的库开始
from mpl_toolkits.basemap import Basemap
import matplotlib
from PIL import Image
import matplotlib.pyplot as plt
from pylab import rcParams
%matplotlib inline
rcParams['figure.figsize'] = (14,10)
我们现在准备调用底图类—
让我简单解释一下代码块。我开始使用墨卡托投影 ( 投影=‘merc’)、低分辨率(分辨率=‘l’)调用一个底图类实例,地图域的边界由 4 个参数给出 llcrnrlon、llcrnrlat、urcrnrlon、urcrnrlat、,其中 llcrnrlon 表示所选地图域左下角的经度,依此类推。绘制海岸线,绘制国家顾名思义,绘制遮罩绘制高分辨率陆海遮罩图像,将陆地和海洋颜色指定为橙色和天蓝色。使用下面的命令将纬度和经度转换为 x/y 地图投影坐标—
xs, ys = my_map(np.asarray(weather_df.Long), np.asarray(weather_df.Lat))
这些地图投影坐标将用作要素,以便在空间上将数据点与温度一起聚类。首先让我们看看下面的气象站—
Weather Stations in Canada, plotted using Basemap. Source: Author
3.1.对天气数据进行聚类(温度和坐标作为特征)
对于聚类数据,我遵循了sci kit-DBS can的学习演示中所示的步骤。
选择温度(' Tm ',' Tx ',' Tn ')和坐标的 x/y 映射投影(' xm ',' ym ')作为特征,并将ϵ和 MinPts 分别设置为 0.3 和 10,给出 8 个唯一的聚类(噪声标记为-1)。您可以随意更改这些参数来测试集群会受到多大的影响。
让我们使用底图来可视化这些集群—
8 Unique Clusters in Canada Based on Few Selected Features in the Weather Data. ϵ and MinPts set to 0.3 and 10 Respectively. Source: Author
最后,我将降水(“p”)包含在特征中,并重复相同的聚类步骤,将ϵ和 MinPts 设置为 0.5 和 10。我们看到了与以前的聚类的一些不同,因此它给了我们一个思路,当我们缺乏领域知识时,即使使用 DBSCAN 也可以对无监督数据进行聚类。
4 Unique Clusters in Canada Based on Selected Features (now included precipitation compared to previous case) in the Weather Data. ϵ and MinPts set to 0.5 and 10 Respectively. Source: Author.
您可以尝试重复这个过程,包括一些更多的功能,或者,改变聚类参数,以获得更好的整体知识。
最后,我们介绍了 DBSCAN 算法的一些基本概念,并测试了该算法对加拿大气象站的聚类。详细代码和所有图片将在我的 Github 中提供。可以与 K-均值聚类进行直接比较,以便更好地理解这些算法之间的差异。希望这将有助于您开始使用一种最常用的聚类算法来处理无监督问题。
分享你的想法和主意,保持坚强。干杯!
页(page 的缩写)s:另一个无监督聚类方法高斯混合和详细的期望最大化算法在另一个帖子中讨论。
参考文献:
[1] “一种基于密度的带噪声大型空间数据库聚类发现算法”;马丁·埃斯特等人 KDD-96 会议录。
[2]基于密度的聚类方法;高,j。布法罗大学副教授。演示链接。
[3] 链接到 Github !
如果你对更深入的基础机器学习概念感兴趣,可以考虑加盟 Medium 使用 我的链接 。你不用额外付钱,但我会得到一点佣金。感谢大家!!
DCGANs —使用 Tensorflow 和 Keras 生成狗的图像
原文:https://towardsdatascience.com/dcgans-generating-dog-images-with-tensorflow-and-keras-fb51a1071432?source=collection_archive---------3-----------------------
基于 Kaggle 的生殖狗比赛(2019)
DCGAN Dog Generation over epochs (~8 hours of runtime on Kaggle)
这篇文章是一个关于 DCGANs 有效性背后的基本思想的教程,以及一些提高他们性能的方法/技巧。这些方法都是我在 Kaggle 的 生财狗大赛 期间的经验。教程也有,要么在我原来的 内核 上笔记本格式,要么在GitHub上。
要在本地或使用 Colab 运行这个例子,您将需要一个 Kaggle 帐户,以便检索其 API 密钥并使用所提供的数据集。完整教程可在 这里 。
生成对抗网络
与大多数流行的神经网络架构不同, GANs 被训练来同时解决两个问题——辨别(有效地将真实图像与虚假图像分开)和“真实的”虚假数据生成(有效地生成被认为是真实的样本)。正如我们所看到的,这些任务是完全对立的,但是如果我们把它们分成不同的模型,会发生什么呢?
嗯,这些模型的通称是发生器(G) 和鉴别器(D) ,被认为是甘斯理论背后的构建模块。
发生器网络将简单的随机噪声 N 维向量作为输入,并根据学习的目标分布对其进行转换。其输出也是 N 维的。另一方面,鉴别器模拟概率分布函数(类似于分类器)并输出输入图像是真实还是虚假的概率【0,1】。考虑到这一点,我们可以定义生成任务的两个主要目标:
1。训练 G 使 D 的最终分类误差最大化。(使得生成的图像被感知为真实)。
2。训练 D 以最小化最终分类误差。(以便正确区分真实数据和虚假数据)。
为了实现这一点,在反向传播期间, G 的权重将使用梯度上升进行更新,以使误差最大化,而 D 将使用梯度下降将其最小化。
GAN inputs and outputs — (note that the two networks don’t use the true distribution of images directly during training but instead use each other’s outputs to estimate their performance)
那么我们如何定义一个损失函数来估计两个网络的累积性能呢?嗯,我们可以使用绝对误差来估计 D 的误差,然后我们可以对 G 重复使用相同的函数,但要最大化:
Mean Absolute Error — the distance between the real and fake distributions of images
在这种情况下, p_t 代表图像的真实分布,而 p_g 则是由 G 创建的分布。
我们可以观察到这个理论是基于强化学习的一些关键概念。它可以被认为是一个两个玩家的极大极小游戏,其中两个玩家相互竞争,从而在各自的任务中逐步提高。
我们看到了甘斯理论背后的基本思想。现在让我们更进一步,通过应用来自卷积神经网络的思想和方法来学习DC gan是如何工作的。
深度卷积生成对抗网络
DC gan利用了CNN的一些基本原理,并因此成为实践中使用最广泛的架构之一,这是因为它们收敛速度快,并且还因为它们可以非常容易地适应更复杂的变体(使用标签作为条件,应用残差块等等)。以下是 DCGANs 解决的一些更重要的问题:
- D 是这样创建的,它基本上解决了一个有监督的图像分类任务。(对于这种情况狗还是不狗)
- GAN 学习的过滤器可用于在生成的图像中绘制特定对象。
- G 包含可以学习对象非常复杂的语义表示的矢量化属性。
以下是创建稳定的 DCGAN 时要考虑的一些核心准则,与标准的 CNN (摘自官方论文)相对照:
- 用步长卷积代替池函数。(这允许 D 学习其自己的空间下采样和 G 其各自的上采样,而不会给模型增加任何偏差)
- 使用 BatchNorm (它通过标准化每个单元的输入来稳定学习,使平均值和单元方差为零,这也有助于创建更健壮的深度模型,而不会出现梯度发散)
- 避免使用全连接隐藏层(非输出)。(这方面的例子是全局平均池,这似乎会影响收敛速度)
- 对于 G-使用 ReLU 激活和 Tanh 进行输出。(当您将图像作为输出时,tanh 通常是更优选的激活,因为它的范围为[-1,1])
- 对于 D-使用泄漏激活(以及输出概率的 sigmoid 函数)。(这是经过经验测试的,似乎适用于更高分辨率的建模)
下面是一个 DCGAN 发生器的最标准结构:
DCGAN Generator structure
正如我们所看到的,它的初始输入只是一个 (1,100) 噪声向量,它通过 4 个卷积层进行上采样,并以 2 的步长产生大小为(64,64,3)的结果 RGB 图像。为了实现这一点,输入向量被投影到 1024 维的输出上,以匹配第一个 Conv 层的输入,我们将在后面看到更多。
标准的鉴别器是什么样的?好吧,关于你所期望的,让我们来看看:
DCGAN Discriminator structure
这一次我们有一个 (64,64,3) 的输入图像,与 G 的输出相同。我们将它传递给 4 标准下采样 Conv 层,再次以 2 的步幅。在最终的输出层中,图像被展平为一个向量,该向量通常被馈送给一个 sigmoid 函数,然后该函数输出该图像的 D 的预测(一个表示概率在[0,1] — dog = 1 或 no dog = 0) 范围内的单个值)。
好了,现在你看到了 GANs 和 DCGANs 背后的基本思想,所以现在我们可以继续使用 Tensorflow 和 Keras :)生成一些狗。
图像预处理和 EDA(探索性数据分析)
在我们继续创建甘模型之前,让我们先快速浏览一下我们将要使用的斯坦福狗数据集。因为我们也有每张图片的注释,我们可以用它们将每张狗图片映射到它各自的品种。为此,我们可以首先创建一个字典,将文件名中的品种代码映射到实际的品种名称。
接下来,我将使用 OpenCV 作为快速函数来读取图像并将其转换为 RGB 。
如果我们查看数据集,我们可以看到每个注释文件夹都包含一个 xml 文件列表。这些文件与特定的图像相关联,包含非常有用的信息,主要是图像中每只狗周围的边界框。也有图像中有多只狗,这使我们能够准确地裁剪它们,并制作一个只包含单身狗的数据集图像。
在这里,我们可以利用 xml 库来创建一个树,并为该注释找到相关的元素。对于每个对象,我们可以提取边界框坐标,裁剪图像,并根据结果图像宽度通过收缩或扩展来标准化裁剪。最后,我们将图像保存在一个 numpy 数组中。
Use ET to find the annotations of each dog in the image
for o in objects:
bndbox = o.find('bndbox')
xmin = int(bndbox.find('xmin').text)
ymin = int(bndbox.find('ymin').text)
xmax = int(bndbox.find('xmax').text)
ymax = int(bndbox.find('ymax').text) .. Add some margins and adjust the width .. # Crop the image
img_cropped = img[ymin:ymin+w, xmin:xmin+w, :] # [h,w,c] .. Interpolation step ..
# Resize the image
img_cropped = cv2.resize(img_cropped, (image_width, image_height), interpolation=interpolation)
# Save the images and labels
dog_images_np[curIdx,:,:,:] = np.asarray(img_cropped)
dog_breed_name = dog_breed_dict[dog_ann.split('_')[0]]
breeds.append(dog_breed_name)
curIdx += 1
return dog_images_np, breeds
加载这些功能大约需要 2-3 分钟。
通过试验,我们可以得出只有单条狗的结果图像是 22125 ,因此我们可以指定 numpy 数组的确切大小。有 120 不同的狗品种。
现在我们有了要素和标注,我们可以在正方形网格中绘制它们,以查看作物的外观并确保它们的标注正确。
def plot_features(features, labels, image_width=image_width, image_height=image_height, image_channels=image_channels,
examples=25, disp_labels=True):
if not math.sqrt(examples).is_integer():
print('Please select a valid number of examples.')
return
imgs = []
classes = []
for i in range(examples):
rnd_idx = np.random.randint(0, len(labels))
imgs.append(features[rnd_idx, :, :, :])
classes.append(labels[rnd_idx]) fig, axes = plt.subplots(round(math.sqrt(examples)), round(math.sqrt(examples)),figsize=(15,15),
subplot_kw = {'xticks':[], 'yticks':[]},
gridspec_kw = dict(hspace=0.3, wspace=0.01))
for i, ax in enumerate(axes.flat):
if disp_labels == True:
ax.title.set_text(classes[i])
ax.imshow(imgs[i])
注意,我们需要归一化像素值,以确保狗被正确绘制。
plot_features(dog_images_np / 255., breeds, examples=25, disp_labels=True)
Visualizing the image features
模型超参数列表
这里我们有一个超参数的完整列表,您可以调整并尝试改进该模型。我主要是从研究论文中收集这些值,并对它们进行了一点调整,这就是我最终得到的结果。以下是你可以尝试的一些事情:
- 样本大小 —特征的数量
- 批量大小 — 64 或 32 可以提高性能,但是计算量很大,并且只能运行少量时期的模型
- 权重初始标准值和平均值 —这些值来自研究论文,似乎可以稳定模型训练
- 泄漏 ReLU 斜率—D激活的阈值看起来也很稳定
- 缩小因子和比例因子——设置使得 G 的噪声向量可以被整形为(4,4,512),其他组合也可能有效
- 漏失 —漏失层的数量、位置和速率可以提高性能。
- 学习率和学习率衰减 —对模型收敛非常重要,很难精确调整, G 和 D 可以有不同的学习率。
- 噪声矢量形状——通常 128 或 100 似乎就足够了
创建影像数据集
现在让我们使用我们的 numpy 特性数组来构造一个 Tensorflow dataset 对象。首先,我们可以将数据类型转换为 float32 ,这总是有助于保留一些内存。
dog_features_tf = tf.cast(dog_images_np, 'float32')
我们还可以将数据扩充应用到我们的数据集。这包括随机的水平翻转,在随机区域缩放和裁剪图像。在这些方法中,我发现只有第一种方法对向数据集添加更多的方差有点用,因为其他方法会引入很多噪声。
因此,在这种情况下,我们数据集中的图像将有 50% 的机会从左向右翻转。
def flip(x: tf.Tensor) -> (tf.Tensor):
x = tf.image.random_flip_left_right(x)
return x
现在,我们可以使用 Tensorflow 来创建数据集,方法是将它混洗,应用一些增强,最后将它分成指定批处理大小的批处理。
dog_features_data = tf.data.Dataset.from_tensor_slices(dog_features_tf).shuffle(sample_size).map(flip).batch(batch_size, drop_remainder=True)
标准化技术
在我们实际制作生成器之前,让我们来看看一些可以逐渐加快 DCGAN 收敛速度的规范化。
重量初始化
其中一种方法是权重初始化。原来训练稳定的甘斯还是蛮重要的。首先,模型重量需要在零中心上稍微增加标准值 (0.02)。这在训练期间稳定了 D 和 G ,并防止模型梯度消失或爆炸。这是每种情况下的关键一步,我们必须在模型中使用随机变量(随机噪声向量)。
下面是一个关于权重初始化如何严重影响神经网络学习过程的例子。
The impact of weight initialization on model training
我们也可以使用 Keras 应用截尾正态分布,这将丢弃超过平均值 2 个标准偏差的值。这也许可以在训练期间消除一些异常点。
weight_initializer = tf.keras.initializers.TruncatedNormal(stddev=weight_init_std, mean=weight_init_mean, seed=42)
光谱归一化
谱归一化是一种新型的权重初始化,专门针对 GANs 设计的,似乎可以进一步稳定模型训练(你可以从这篇论文中读到更多)。关于光谱归一化的更详细的解释以及它为什么工作也值得看看这篇文章,它有非常直观的例子。
我们网络中单个权重的频谱归一化可定义如下:
Applying Spectral Normalization on a single weight
这里 u 和 v 是相同大小的简单随机向量。对于每个学习步骤,它们被用来对特定权重执行所谓的幂迭代操作,并且它被证明比简单地惩罚梯度在计算上高效得多。
之后,在反向传播步骤中,我们使用 WSN(W) 代替 W 来更新权重。
对于这个项目,我将重用一些由 IShengFang ( 官方代码)实现的自定义 Keras 图层,在 Conv 和密集图层之上应用光谱归一化。
这里还有一个关于光谱归一化效果的好例子:
DCGAN training with SN
DCGAN training with standard layers
让我们也在 Keras 中定义一些模板层,以便我们稍后可以更容易地创建 G 和 D 。各层的标准模式将是:
TP _ conv _ Block =[(conv(SN)2d transpose(上采样))->(batch norm)->(ReLU)]
conv _ 布洛克= [(Conv(SN)2D(下采样))->(batch norm)->(leaky relu)】
对于本例,我将在 G 中使用标准Conv2D 转置模块,在 d 中使用频谱归一化 conv 2d 层
def transposed_conv(model, out_channels, ksize, stride_size, ptype='same'):
model.add(Conv2DTranspose(out_channels, (ksize, ksize),
strides=(stride_size, stride_size), padding=ptype,
kernel_initializer=weight_initializer, use_bias=False))
model.add(BatchNormalization())
model.add(ReLU())
return model
def convSN(model, out_channels, ksize, stride_size):
model.add(ConvSN2D(out_channels, (ksize, ksize), strides=(stride_size, stride_size), padding='same',
kernel_initializer=weight_initializer, use_bias=False))
model.add(BatchNormalization())
model.add(LeakyReLU(alpha=leaky_relu_slope))
#model.add(Dropout(dropout_rate))
return model
发电机
我们终于可以定义我们的生成器了。模型结构主要基于官方的 DCGAN 论文,做了一些我认为对性能有益的调整。总体结构如下:
【输入(128,1)——>密集(2048,)——>重塑(4,4,128)——>TP _ conv _ Block(深度=512,K = 5×5,S = 1×1)——>Dropout(0.5)->TP _ conv _ Block(深度=256,K = 5×5,S = 2×2)->Dropout(0.5)->TP _ conv _ Block(深度=128,K
def DogGenerator():
model = Sequential()
model.add(Dense(image_width // scale_factor * image_height // scale_factor * 128,
input_shape=(noise_dim,), kernel_initializer=weight_initializer))
#model.add(BatchNormalization(epsilon=BN_EPSILON, momentum=BN_MOMENTUM))
#model.add(LeakyReLU(alpha=leaky_relu_slope))
model.add(Reshape((image_height // scale_factor, image_width // scale_factor, 128)))
model = transposed_conv(model, 512, ksize=5, stride_size=1)
model.add(Dropout(dropout_rate))
model = transposed_conv(model, 256, ksize=5, stride_size=2)
model.add(Dropout(dropout_rate))
model = transposed_conv(model, 128, ksize=5, stride_size=2)
model = transposed_conv(model, 64, ksize=5, stride_size=2)
model = transposed_conv(model, 32, ksize=5, stride_size=2)
model.add(Dense(3, activation='tanh', kernel_initializer=weight_initializer))
return model
鉴别器
鉴别器相对更容易实现,因为它基本上是一个小型的 CNN 两类分类器。我们可以选择是否应用光谱归一化并观察性能效果。对于这个例子,我将尝试只在 D 中应用 SN 。下面是 D 的结构:
【输入(128,128,3)——>conv(SN)2D(深度=64,K=5x5,S=1x1,相同)——>leaky relu——>conv _ Block(深度=64,K=5x5,S = 2 x2)——>conv _ Block(深度=128,K=5x5,S = 2 x2)——>conv _ Block(深度=256,K=5x5,S = 2 x2)——【T57
还要注意,所有的 Conv 和密集层都用上面定义的截断正态分布初始化。另一件事是偏差项从 Conv 层中移除,这也稍微稳定了模型。
def DogDiscriminator(spectral_normalization=True):
model = Sequential()
if spectral_normalization:
model.add(ConvSN2D(64, (5, 5), strides=(1,1), padding='same', use_bias=False,
input_shape=[image_height, image_width, image_channels],
kernel_initializer=weight_initializer))
#model.add(BatchNormalization(epsilon=BN_EPSILON, momentum=BN_MOMENTUM))
model.add(LeakyReLU(alpha=leaky_relu_slope))
#model.add(Dropout(dropout_rate))
model = convSN(model, 64, ksize=5, stride_size=2)
#model = convSN(model, 128, ksize=3, stride_size=1)
model = convSN(model, 128, ksize=5, stride_size=2)
#model = convSN(model, 256, ksize=3, stride_size=1)
model = convSN(model, 256, ksize=5, stride_size=2)
#model = convSN(model, 512, ksize=3, stride_size=1)
#model.add(Dropout(dropout_rate))
model.add(Flatten())
model.add(DenseSN(1, activation='sigmoid'))
else:
...
return modeldog_discriminator = DogDiscriminator(spectral_normalization=True)
标签平滑
一种可以在训练期间应用的正则化方法被称为标签平滑。这实际上是防止了 D 在其预测中过于自信或过于自信。如果 D 变得过于确定在特定的图像中有一只狗,那么 G 可以利用这个事实,并且持续地开始只生成那个种类的图像,并且依次停止改进。我们可以通过将负类的类标签设置在范围【0,0.3】内,将正类的类标签设置在范围【0.7,1】内来解决这个问题。
这将防止总体概率非常接近两个阈值。
# Label smoothing -- technique from GAN hacks, instead of assigning 1/0 as class labels, we assign a random integer in range [0.7, 1.0] for positive class
# and [0.0, 0.3] for negative class
def smooth_positive_labels(y):
return y - 0.3 + (np.random.random(y.shape) * 0.5)
def smooth_negative_labels(y):
return y + np.random.random(y.shape) * 0.3
将噪声引入标签
这种技术也被称为实例噪声。通过给标签增加少量误差(假设 5%),这往往会使真实分布和预测分布更加分散,从而开始相互重叠。这反过来使得在学习过程中拟合生成图像的定制分布更加容易。
下面是一个很好的例子,展示了使用这些技术时这两个发行版的样子:
The impact of Insance Noise and Label smoothing on the real and fake distributions of images
下面是我们如何实现实例噪声:
# randomly flip some labels
def noisy_labels(y, p_flip):
# determine the number of labels to flip
n_select = int(p_flip * int(y.shape[0]))
# choose labels to flip
flip_ix = np.random.choice([i for i in range(int(y.shape[0]))], size=n_select)
op_list = []
# invert the labels in place
#y_np[flip_ix] = 1 - y_np[flip_ix]
for i in range(int(y.shape[0])):
if i in flip_ix:
op_list.append(tf.subtract(1, y[i]))
else:
op_list.append(y[i])
outputs = tf.stack(op_list)
return outputs
优化者
这个任务的最佳验证优化算法是 Adam ,两个模型的标准学习率为 0.0002 ,beta 为 0.5 。
generator_optimizer = tf.train.AdamOptimizer(learning_rate=lr_initial_g, beta1=0.5)
discriminator_optimizer = tf.train.AdamOptimizer(learning_rate=lr_initial_d, beta1=0.5)
定义损失函数
最近优化 GANs 的另一个新趋势是应用相对论损失函数,而不是标准损失函数。这些函数测量真实数据比生成的数据更“真实”的概率。其中比较流行的相对论函数选择有 RaLSGAN(相对论平均最小二乘法)、RaSGAN(相对论平均标准)和 RaHinge(相对论铰链损耗)。
但在这一切之前,让我们先定义一下标准甘损失:
正如我们所观察到的,这基本上是用于分类任务的标准二元交叉熵损失或者真实分布和生成分布之间的逻辑损失。在张量流中,这可以定义如下:
相比之下,这里是一个 RSGAN(相对论标准)损耗的样子:
在这种情况下,任务是不同的,测量真实(r) 和虚假(f) 数据分布之间的相似性。RSGAN 在 D(x) = 0.5 时达到最优点(即C(xr)=C(xf))。有许多相对论损失函数变体,它们都包含不同的方法来测量这种相似性。在这个项目中,我尝试了似乎拥有最佳记录的 MIFID 得分 (RaLSGAN、RaSGAN 和 RaHinge) 的 3 。随意给自己尝试不同的损耗,看看是否能提高性能;).
这里有一个最常用的列表:
Standard and Relativistic GAN losses
在针对这个特定问题的多次试验中,我没有发现通过切换到相对论性损耗来提高性能,所以我决定坚持使用标准的 GAN 损耗函数,因为它更容易估计,尽管在某些情况下,这些损耗确实可以加快模型的收敛。
这里是应用了标签平滑和实例噪声的鉴别器损失函数的样子。它基本上是两个子损失的总和(假的——根据 G 的图像,真实的——根据实际的训练图像)。
def discriminator_loss(real_output, fake_output, loss_func, apply_label_smoothing=True, label_noise=True):
if label_noise and apply_label_smoothing:
real_output_noise = noisy_labels(tf.ones_like(real_output), 0.05)
fake_output_noise = noisy_labels(tf.zeros_like(fake_output), 0.05)
real_output_smooth = smooth_positive_labels(real_output_noise)
fake_output_smooth = smooth_negative_labels(fake_output_noise)
if loss_func == 'gan':
real_loss = cross_entropy(tf.ones_like(real_output_smooth), real_output)
fake_loss = cross_entropy(tf.zeros_like(fake_output_smooth), fake_output) else:
... other loss function variants loss = fake_loss + real_loss
return loss
而生成器损失函数(应用了标签平滑)只是一个标准的物流损失:
def generator_loss(real_output, fake_output, loss_func, apply_label_smoothing=True):
if apply_label_smoothing:
fake_output_smooth = smooth_negative_labels(tf.ones_like(fake_output))
if loss_func == 'gan':
return cross_entropy(tf.ones_like(fake_output_smooth), fake_output)
else:
... other loss function variants return loss
主训练循环
让我们也确定用于训练的时期的数量和提供给生成器用于可视化中间结果的图像的数量。
EPOCHS = 280
num_examples_to_generate = 64
seed = tf.random.normal([num_examples_to_generate, noise_dim])
DCGAN 的一个训练步骤由三个标准步骤组成:
- 前进道具 — G 制造一批假像;这和一批真实图像一起被传送到 D 。
- 计算 G 和 D 的损失函数。
- 反投影 —计算 G 和 D 的梯度,优化权重。
def train_step(images, loss_type='gan'):
noise = tf.random.normal([batch_size, noise_dim])
with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
generated_images = dog_generator(noise, training=True)
real_output = dog_discriminator(images, training=True)
fake_output = dog_discriminator(generated_images, training=True)
gen_loss = generator_loss(real_output, fake_output, loss_type, apply_label_smoothing=True)
disc_loss = discriminator_loss(real_output, fake_output, loss_type,
apply_label_smoothing=True, label_noise=True)
gradients_of_generator = gen_tape.gradient(gen_loss, dog_generator.trainable_variables)
gradients_of_discriminator = disc_tape.gradient(disc_loss, dog_discriminator.trainable_variables)
generator_optimizer.apply_gradients(zip(gradients_of_generator, dog_generator.trainable_variables))
discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, dog_discriminator.trainable_variables))
return gen_loss, disc_loss
让我们也定义一些函数来直观显示按时期和作为一个整体的模型损失。
def plot_losses(G_losses, D_losses, all_gl, all_dl, epoch):
plt.figure(figsize=(10,5))
plt.title("Generator and Discriminator Loss - EPOCH {}".format(epoch))
plt.plot(G_losses,label="G")
plt.plot(D_losses,label="D")
plt.xlabel("Iterations")
plt.ylabel("Loss")
plt.legend()
ymax = plt.ylim()[1]
plt.show()
plt.figure(figsize=(10,5))
plt.plot(np.arange(len(all_gl)),all_gl,label='G')
plt.plot(np.arange(len(all_dl)),all_dl,label='D')
plt.legend()
#plt.ylim((0,np.min([1.1*np.max(all_gl),2*ymax])))
plt.title('All Time Loss')
plt.show()
我们还可以使用下面的函数来绘制生成图像的网格。
def generate_and_save_images(model, epoch, test_input, rows, cols):
# Notice `training` is set to False.
# This is so all layers run in inference mode (batchnorm).
predictions = model(test_input, training=False)
fig = plt.figure(figsize=(14,14))
for i in range(predictions.shape[0]):
plt.subplot(rows, cols, i+1)
plt.imshow((predictions[i, :, :, :] * 127.5 + 127.5) / 255.)
plt.axis('off')
plt.subplots_adjust(wspace=0, hspace=0)
plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
plt.show()
为了生成单个测试图像,我们也可以重用相同的方法。
def generate_test_image(model, noise_dim=noise_dim):
test_input = tf.random.normal([1, noise_dim])
# Notice `training` is set to False.
# This is so all layers run in inference mode (batchnorm).
predictions = model(test_input, training=False)
fig = plt.figure(figsize=(5,5))
plt.imshow((predictions[0, :, :, :] * 127.5 + 127.5) / 255.)
plt.axis('off')
plt.show()
评估 GANs
我们还没提到一个甘平时是怎么评价的。大多数使用基准来评估一个甘表现如何的研究论文通常基于所谓的初始分数。这测量输入图像的两个主要特征:
- 品种(例如生成不同类型的狗品种)
- 图像的区别(或质量)
如果两件事都是真的,分数就高。如果其中一个或两个都是错误的,分数将会很低。分数越高越好。这意味着您的 GAN 可以生成许多不同的清晰图像。最低分可能是零分。数学上的最高可能分数是无穷大,尽管实际上可能会出现一个非无穷大的上限。
Inception Score 来源于 Google 的 Inception Network ,是最先进的图像分类深度架构之一。通过将来自我们的 GAN 的图像通过分类器,我们可以测量我们生成的图像的属性。为了产生分数,我们需要计算图像的真实和虚假分布之间的相似性/距离。这是使用KL(kull back–lei bler)散度公式完成的:
这里, P 和 Q 是两个测量分布。在这种情况下,更高的 KL 散度意味着更好的结果——图像的质量是相似的,并且存在各种各样的标签。在相反的情况下,低 KL 偏差可能是由于标签质量低或种类少:
Measuring the performance with KL divergence
弗雷歇起始距离
的一个缺点是如果每个类只生成一个图像,它可能会歪曲性能。为了解决这个问题,我们可以使用 FID(弗雷歇初始距离)。这种方法将前面两种类型的图像定义为具有平均值 μ 和协方差σ(适马)的多元高斯分布。让我们看看这个距离是如何计算的:
这里, x 和 g 代表图像的真假分布,而 Tr 是结果的对角元素之和。
FID 值越低,图像质量和多样性越好。
Example of how the diversity factor impacts the scoring on different datasets
以下是一些有用的注释,说明为什么 FID 是一个好的衡量标准:
- FID 比 is 对噪声更鲁棒。
- 如果模型每类只生成一个图像,距离会很高。因此,FID 是一种更好的图像多样性度量。
- 通过计算训练数据集和测试数据集之间的 FID,我们应该期望 FID 为零,因为两者都是真实图像。(虽然通常会有少量误差)
- FID 和 IS 基于特征提取(特征的有无)。
记忆通知弗雷歇起始距离
以下是 Kaggle 对生殖狗比赛的官方评估工作流程:
There are two stages of evaluation — public and private on different datasets. The MIFID metric is calculated using the standard FID, combined with a Memorization Score.
正如我们所看到的,除了 FID 指标之外,还有一个额外的记忆分数被添加到计算中。这基本上是一个余弦距离公式,用于测量真实(来自私人数据集的图像)和虚假图像之间的相似性。我猜这样做是为了确保提供给评估内核的图像实际上是由 GAN 生成的,而不仅仅是从真实数据集复制或修改的。
谢天谢地, MIFID 赋值器已经被 Kaggle 团队(此处)实现了,我们不用担心这个问题。
图像压缩和保存功能
我将再添加两个,用于压缩最终的 10K 图像以供提交,并生成临时图像以计算训练期间特定时期之间的 MIFID 。
def zip_images(filename='images.zip'):
# SAVE TO ZIP FILE NAMED IMAGES.ZIP
z = zipfile.PyZipFile(filename, mode='w')
for k in range(image_sample_size):
generated_image = dog_generator(tf.random.normal([1, noise_dim]), training=False)
f = str(k)+'.png'
img = np.array(generated_image)
img = (img[0, :, :, :] + 1.) / 2.
img = Image.fromarray((255*img).astype('uint8').reshape((image_height,image_width,image_channels)))
img.save(f,'PNG')
z.write(f)
os.remove(f)
#if k % 1000==0: print(k)
z.close()
print('Saved final images for submission.')
def save_images(directory=OUT_DIR):
for k in range(image_sample_size):
generated_image = dog_generator(tf.random.normal([1, noise_dim]), training=False)
f = str(k)+'.png'
f = os.path.join(directory, f)
img = np.array(generated_image)
img = (img[0, :, :, :] + 1.) / 2.
img = Image.fromarray((255*img).astype('uint8').reshape((image_height,image_width,image_channels)))
img.save(f,'PNG')
#if k % 1000==0: print(k)
print('Saved temporary images for evaluation.')
终于到了实现最终培训功能的时候了,该功能总结了整个过程。这里还有一些我还没有提到的技巧。让我们看看它们是什么。
学习率衰减
这是一个实验,并不总是有助于提高性能,但我不认为它会伤害任何一种方式。这里的想法是,对于每个训练步骤,将学习率降低一个非常小的量,以便稳定训练过程并加速收敛(并逃离局部最小值)。对于这个项目,我使用 Tensorflow 中的 余弦学习率衰减 来降低每decay_step
次迭代的学习率。
处理模式崩溃
除了不收敛和消失和爆炸梯度之外, GANs 有时还会遇到另一个主要问题,叫做模式崩溃。当开始生产有限种类的样品时,就会发生这种情况。下面是一个在 MNIST 数据集上训练的甘的模式折叠的好例子,其中 G 连续地仅产生单个类标签的图像:
G learns to fool D by only generating samples from a single class, which causes the model to lose diversity
我们已经看到了一些可能消除模式崩溃的方法,如标签平滑、实例噪声、权重初始化等等。我们可以在培训中应用的另一种方法叫做体验回放。
体验回放在内存中保存一些最近生成的图像。对于每一次replay_step
迭代,我们在那些先前的图像上训练 D ,以“提醒”先前世代的网络,从而减少在训练期间过度拟合到数据批次的特定实例的机会。在这个例子中,我使用了稍微不同形式的经验重放,在这个意义上,我为每个训练步骤生成一个新的额外图像以存储在一个列表中,而不是从以前的迭代中馈送实际生成的图像,因为在急切执行期间存储数据不是一件容易的任务。
'''
generated_image = dog_generator(tf.random.normal([1, noise_dim]), training=False)
exp_replay.append(generated_image)
if len(exp_replay) == replay_step:
print('Executing experience replay..')
replay_images = np.array([p[0] for p in exp_replay])
dog_discriminator(replay_images, training=True)
exp_replay = []
'''
由于 Kaggle 在运行了大约 7-8 个小时后遇到了内存问题,我决定不使用体验回放。如果您找到了解决方法,请告诉我
训练功能
总而言之,训练过程相当简单。显示中间结果(如图像、损耗)和计算 MIFID 还有其他步骤。在学习过程的最后,我们打印出最终评估和最终图像的较大网格。
display_results = 40
calculate_mifid = 100
replay_step = 50
decay_step = 50
def train(dataset, epochs):
all_gl = np.array([]); all_dl = np.array([])
for epoch in tqdm(range(epochs)):
G_loss = []; D_loss = []
start = time.time()
new_lr_d = lr_initial_d
new_lr_g = lr_initial_g
global_step = 0
for image_batch in dataset:
g_loss, d_loss = train_step(image_batch)
global_step = global_step + 1
G_loss.append(g_loss); D_loss.append(d_loss)
all_gl = np.append(all_gl,np.array([G_loss]))
all_dl = np.append(all_dl,np.array([D_loss]))
if (epoch + 1) % display_results == 0 or epoch == 0:
plot_losses(G_loss, D_loss, all_gl, all_dl, epoch + 1)
generate_and_save_images(dog_generator, epoch + 1, seed, rows=8, cols=8)
if (epoch + 1) % calculate_mifid == 0:
OUT_DIR.mkdir(exist_ok=True)
save_images(OUT_DIR)
evaluator = MiFIDEvaluator(MODEL_PATH, TRAIN_DIR)
fid_value, distance, mi_fid_score = evaluator.evaluate(OUT_DIR)
print(f'FID: {fid_value:.5f}')
print(f'distance: {distance:.5f}')
print(f'MiFID: {mi_fid_score:.5f}')
shutil.rmtree(OUT_DIR)
print('Removed temporary image directory.')
# Cosine learning rate decay
if (epoch + 1) % decay_step == 0:
new_lr_d = tf.train.cosine_decay(new_lr_d, min(global_step, lr_decay_steps), lr_decay_steps)
new_lr_g = tf.train.cosine_decay(new_lr_g, min(global_step, lr_decay_steps), lr_decay_steps)
generator_optimizer = tf.train.AdamOptimizer(learning_rate=new_lr_d, beta1=0.5)
discriminator_optimizer = tf.train.AdamOptimizer(learning_rate=new_lr_g, beta1=0.5)
print('Epoch: {} computed for {} sec'.format(epoch + 1, time.time() - start))
print('Gen_loss mean: ', np.mean(G_loss),' std: ', np.std(G_loss))
print('Disc_loss mean: ', np.mean(D_loss),' std: ', np.std(D_loss))
# Generate after the final epoch and repeat the process
generate_and_save_images(dog_generator, epochs, seed, rows=8, cols=8)
checkpoint.save(file_prefix = checkpoint_prefix)
OUT_DIR.mkdir(exist_ok=True)
save_images(OUT_DIR)
evaluator = MiFIDEvaluator(MODEL_PATH, TRAIN_DIR)
fid_value, distance, mi_fid_score = evaluator.evaluate(OUT_DIR)
print(f'FID: {fid_value:.5f}')
print(f'distance: {distance:.5f}')
print(f'MiFID: {mi_fid_score:.5f}')
shutil.rmtree(OUT_DIR)
print('Removed temporary image directory.')
print('Final epoch.')
以下是在训练过程中生成的一些狗的图像:
Epoch 120 — MIFID ~ 90.5
Epoch 200 — MIFID ~ 64.8
Epoch 280 (final) — MIFID ~ 60.99
正如我们所观察到的,MIFID 在 280 个周期(约 8 小时)内稳步提高。我在比赛中使用这个模型取得的最好成绩是 55.87 。学习过程确实有点随机,所以我认为在【50,65】附近的分数应该是现实的。如果你有时间的话,可以继续训练这个模型,因为它有不断改进的潜力:)。
最后,我将向您展示如何制作一个有趣的 GIF 来查看 DCGAN 学习过程的一个漂亮的小模拟(代码来自 Tensorflow 的 DCGAN 教程)。
anim_file = 'dcgan.gif'
with imageio.get_writer(anim_file, mode='I') as writer:
filenames = glob.glob('image*.png')
filenames = sorted(filenames)
last = -1
for i,filename in enumerate(filenames):
frame = 1*(i**2)
if round(frame) > round(last):
last = frame
else:
continue
image = imageio.imread(filename)
writer.append_data(image)
image = imageio.imread(filename)
writer.append_data(image)
import IPython
if IPython.version_info > (6,2,0,''):
IPython.display.Image(filename=anim_file)
结论
综上所述, DCGANs 似乎对超参数选择极其敏感,在训练过程中会出现很多问题,包括模式崩溃。它们也是非常计算密集型的,并且难以置信地难以为运行时间 ~9 小时构建高分模型。幸运的是,有一个完整的列表,列出了可能的方法和技术,这些方法和技术都有很好的文档记录,可以很容易地应用到您的模型中,以稳定培训过程。
对我个人来说,试验这些技术并在这个过程中打破一些核心真的很有趣:d .随时在评论中留下任何建议(改进模型或修复我搞砸的东西)。
非常感谢克里斯·德奥特、那那西、查德·马拉和尼尔哈·罗伊在比赛中提供的 Kaggle 内核和示例。我会在下面留下他们的链接。
总的来说,这是我参加的第一个卡格尔比赛,这是一个非常有趣的了解甘斯并和他们一起玩耍的方法。这似乎是 Kaggle 的第一次涉及生成建模的比赛,让我们希望未来会有更多类似这样令人兴奋的挑战出现;).
参考
有用的内核和笔记本
[1].我之前在 EDA 上的内核和图像预处理
[2]. Xml 解析并裁剪到指定的边界框
[3].带插值的图像裁剪方法
[4].Chad Malla 的另一个基于 Keras 的 DCGAN 方法
[5]. DCGAN 帮助您提高模型性能的方法
[6]. Tensorflow DCGAN 教程
[7].那那西拍摄的 DCGAN 狗图片
[8].甘犬首发 24-7 月 Nirjhar Roy 定制层
[9].克里斯·德奥特监督的生殖狗网
[10].我的最佳参赛作品
研究论文、帖子和讨论
[1].Ian Goodfellow,J. Pouget-Abadie,M. Mirza,B. Xu,S. Ozair,Y. Bengio , 生成性对抗网络 (2014)
[2].罗卡,理解生成性对抗网络
[3].J. Brownlee,生成性对抗网络的温和介绍
[4].a .拉德福德,l .梅斯,s .钦塔拉,深度卷积生成对抗网络的无监督表示学习 (2015)
[5].惠, GAN — DCGAN(深度卷积生成对抗网络)
[6].S. Yadav,神经网络中的权重初始化技术
[7].T. Miyato,T. Kataoka,M. Koyama,Y. Yoshida,生成性对抗网络的谱归一化 (2018)
[8].IShengFang,在 Keras 实现光谱归一化
[9].c .科斯格罗维,光谱归一化解释
[10].许军,氮化镓——提高氮化镓性能的方法
[11].J. Brownlee,如何在 Keras 中实现 GAN Hacks 来训练稳定的模型
[12].焦裕禄,GANS 的诡计
[13].C. K. Sø nderby,实例噪声:稳定 GAN 训练的技巧
[14].J. Hui, GAN — RSGAN & RaGAN(新一代代价函数。)
[15].D. Mack,对初始得分的简单解释
[16].J. Hui,GAN——如何衡量 GAN 的性能?
[17].你所需要的就是甘的黑客
[18].如何训练你的敏感神经——这些方法似乎很有效。
[19].解释公制 FID
从头开始消除重复记录
原文:https://towardsdatascience.com/de-duplicate-the-duplicate-records-from-scratch-f6e5ad9e79da?source=collection_archive---------13-----------------------
Photo credit: Trivago
识别相似记录,稀疏矩阵乘法
网络世界充满了重复的列表。特别是,如果你是一个在线旅行社,你接受不同的供应商为你提供相同的财产信息。
有时重复的记录是显而易见的,这让你想:这怎么可能?
Photo credit: agoda
还有一次,两个记录看起来像是重复的,但是我们不确定。
Photo credit: expedia
或者,如果您为一家拥有大量公司或客户数据的公司工作,但是因为这些数据来自不同的源系统,而这些系统通常以不同的方式写入。那么您将不得不处理重复的记录。
Photo credit: dedupe.io
数据
我觉得最好的数据集是用我自己的。使用我不久前创建的西雅图酒店数据集。我去掉了酒店描述特征,保留了酒店名称和地址特征,并特意添加了重复记录,数据集可以在这里找到。
两个酒店如何重复的例子:
duplicate.py
Table 1
最常见的复制方式是街道地址的输入方式。一些人使用缩写,另一些人没有。对于人类读者来说,很明显上面的两个列表是同一个东西。我们将编写一个程序来确定并删除重复的记录,只保留一个。
TF-IDF + N-gram
- 我们将使用名称和地址作为输入要素。
- 我们都熟悉 tfidf 和 n-gram 方法。
- 我们得到的结果是一个稀疏矩阵,每行是一个文档(name_address),每列是一个 n 元文法。为每个文档中的每个 n 元语法计算 tfidf 分数。
tfidf_ngram.py
稀疏点顶
我发现了一个由 ING 批发银行、 sparse_dot_topn 开发的优秀的库,它只存储每个项目的前 N 个最高匹配,我们可以选择显示高于阈值的最高相似性。
它声称,它提供了一种更快的方法来执行稀疏矩阵乘法,然后是 top-n 乘法结果选择。
该函数将以下内容作为输入:
- a 和 B:两个 CSR 矩阵
- ntop: n 个最佳结果
- lower _ bound:A * B 的元素必须大于输出的阈值
输出是一个结果矩阵。
awesome_cossim_top.py
运行该功能后。该矩阵仅存储前 5 个最相似的酒店。
以下代码解包生成的稀疏矩阵,结果是一个表,其中每个酒店将与数据中的每个酒店匹配(包括其自身),并计算每对酒店的余弦相似性得分。
get_matches_df.py
除了它本身,我们只对顶级赛事感兴趣。因此,我们将视觉检查结果表排序相似性得分,其中我们确定一个阈值一对是相同的属性。
matches_df[matches_df['similarity'] < 0.99999].sort_values(by=['similarity'], ascending=False).head(30)
Table 2
我决定我的安全赌注是删除任何相似性得分高于或等于 0.50 的配对。
matches_df[matches_df['similarity'] < 0.50].right_side.nunique()
在那之后,我们现在还有 152 处房产。如果你记得,在我们的原始数据集中,我们有 152 个属性。
Jupyter 笔记本和数据集可以在 Github 上找到。祝你一周工作顺利!
参考资料:
https://github . com/ing-bank/sparse _ dot _ topn/blob/master/sparse _ dot _ topn/awesome _ cossim _ topn . py
[## Python 中的超快速字符串匹配
传统的字符串匹配方法,如 Jaro-Winkler 或 Levenshtein 距离度量,对于…
bergvca.github.io](https://bergvca.github.io/2017/10/14/super-fast-string-matching.html)
去谷歌搜索巴赫
原文:https://towardsdatascience.com/de-googling-bach-counterpointing-bachs-rules-of-the-road-with-american-populist-music-ccbaa27a149f?source=collection_archive---------14-----------------------
将巴赫的《公路规则》与美国民粹主义音乐进行对比
“Thnking Outside the Bachs” by Max Harper Ellert
本周,我玩谷歌涂鸦从简单的旋律中创造巴赫和声,玩得很开心。浏览一些关于融合人工智能的过程和对位原则的文章也很有趣,比如艾丽莎·拜尔娜的这篇综合文章和微软音乐理论工程师丹尼尔·汤普金斯的一篇精心构思的文章中对涂鸦的回应:谷歌的巴赫人工智能。
这些文章和许多其他文章倾向于解释和批评这一过程,对人工智能在正确遵循对位规则方面缺乏成功提出了一些批评。虽然对我来说,一些由音乐家和非音乐家创作的曲调充斥着交叉的声音、平行的音程、怪异的节奏和狂野的跳跃,有些甚至相当俏皮,但你仍然有一个古老的难题,即猴子与打字机和莎士比亚的比例。没有一台机器,无论程序设计得多么好,多么聪明,能够重现巴赫的天才。
为了证明这一点,我在 Feste Burg 涂鸦了——最熟悉的巴赫合唱曲之一。所以我可以分享它,我把它写到我的符号程序中,作为下面的 png 图形导入。这是最初的协调:
Ein Feste Burg, Bach’s original harmonization
我不能准确地把它写进去——涂鸦不允许记笔记。但由于涂鸦似乎存在于节拍之外,并且使用节拍作为地标,而不是形成节拍逻辑,这似乎并不重要。涂鸦带回来的东西和原来的没什么不同,但显然没有魔力。你可能会认为这是一个展示它的东西的绝佳机会,但我猜 Ein Feste Burg 不是用来载入电脑的 360 首曲子之一(她说,双臂交叉,双脚轻敲)。
Ein Feste Burg as seen by Google Doodle
然后我肯定去了一个野毛。我放了两小节 1941 年的流行蓝调音乐,约翰尼·默瑟和哈罗德·阿伦的《夜色中的蓝调》(我妈妈告诉我的),看看会发生什么。这两个小节来自合唱部分的火车汽笛部分— “一声呜呼,一声呜呼”其中旋律跳过一个三度音,滑到第五度,然后在第二个“汽笛”时回到第四度。这与《西区故事》中伯恩斯坦的《玛丽亚》的开场有着相同的动机。像这样:
最初的动机有一个引出三连音的八分音符。我看不出涂鸦中的三连音,所以我只能用第八个音符。我想看看如果我强制拾音会有什么效果,所以我在第一小节结束时将第八个音符拾音。然后点击“和声”,让它进城。AI doodle 疯了!它不能解析这个信号,所以它写了一堆笔记来引导我的动机。以下是巴布亚新几内亚:
Google Doodle can’t handle the blues
正如你所看到的,它看起来很奇怪——如果你能在钢琴上演奏它,它听起来很奇怪。它一点也不像巴赫,但听起来也不像《夜色中的布鲁斯》。我非常震惊。
然后,当我着手沏一杯茶时,我有了一点小小的惊喜(这是一个人神志不清后所必需的)。降半音——蓝调——三度、五度、六度,在我们所有的民粹主义文学中都能立即辨认出来:蓝调、节奏蓝调、爵士、摇滚,而不仅仅是美国歌曲集的一点点。为什么蓝调音乐会让巴赫在坟墓里翻身?啊哈!
因为规则不一样。
巴赫的对位法到今天有 250 年的演变时间。与美国民粹主义联系最紧密的音乐的大部分基本构件都是在 1940 年建立的,在摇滚乐的发展过程中加入了一些曲折和呐喊。随着规则的改变,对这种演变最有责任的一群美国人可能是非裔美国人,他们从战前在田间劳作时用来保持理智的蓝调圣歌开始。
请注意,野外圣歌和夜晚的布鲁斯没有太多相似之处。现场喊叫声、圣歌和回应叫喊声是非常典型的。来自锡盘巷的蓝调歌曲非常自然。换句话说,他们遵循我们所遵循的以欧洲为基础的作曲规则。学生们在音乐学院里汗流浃背,但有点反常。20 世纪,无论是在艺术音乐还是迅速发展的民粹主义形式中,大多数对位法的规则都变得宽松了(很多)。然而,我们的流行音乐,尤其是 20 世纪上半叶的流行音乐,与古典主义(想想:莫扎特)相比,与巴洛克音乐有更多的共同点,但即使它坚持现在几乎是我们音乐 DNA 一部分的古老的六二五一和声结构,流行音乐也遵循着自己的逻辑,将它与古典主义区分开来。那么,巴洛克对位只是和声结构中的低语。一个重要的耳语,是的,但消退了。
许多民粹主义逻辑与非裔美国人、拉丁美洲人和各种移民对我们音乐的贡献有关。田野圣歌的蓝调,桑巴舞的交叉节奏,阿巴拉契亚民歌曲调的圣歌般的形式都演变成了我们称之为我们自己的音乐,并从那里继续演变。如今,蔓越莓的印地音乐与吉米·罗杰斯音乐并没有太大的不同——在大多数情况下,它归结于添加的层次、复杂的和声和大量的机械处理。理解不同的文化对音乐有不同的理解并不是一个很大的飞跃,但是亲爱的读者们,我希望你们考虑的是进化是如何发生的。
当然,通过打破规则。
显而易见,20 世纪美国民粹主义音乐与巴洛克对位法存在(认知)不和谐,所以有人会问,我们为什么还要为巴赫的谷歌涂鸦这样的东西费心。我有几句话要说,但我现在的观点是,如果我们把一首田间圣歌演变成一首流行歌曲,或者一首调式民谣演变成一首印度流行歌曲,那么我们为什么不能把所有这些音乐的基本 DNA 转变成一种新的古典形式呢?
戏弄、强迫或哄骗平民音乐成为一套新的对位规则?嗯…
这丝毫无损巴赫的贡献!如果他今天突然还活着(在一个主要的文化调整期之后),他会对我们可以获得的各种音乐感到惊讶,我相信他会喜欢的。你知道,他是个吉格斯爵士。在为他的周日演出创作清唱剧的间隙,他在咖啡馆演奏——如果你愿意的话,也可以说是巴洛克鸡尾酒大键琴。他利用现有的材料,并将其与自己的即兴才华相结合。纵观历史,作曲家都知道天才的标志是能够窃取音乐并使其焕然一新(而不会被起诉)。
那么,如果我们的音乐不符合巴洛克式对位法的限制,那又怎么样呢?谷歌涂鸦很有趣,音乐制作也应该有趣,并以允许人们探索的方式呈现。我度过了一个愉快的周六下午,摆弄着涂鸦,把我的努力改写成西贝柳斯。对于新手来说,我可以看到这可以让创作音乐的神秘过程变得不那么神秘(尽管正如我们从结果中看到的那样,并不那么复杂)——有点像科学探索博物馆。音乐是一门科学,所以应该有音乐探索馆,你觉得呢?
然而,如果谷歌推出这些有趣的小应用有什么好处的话,必须有两种理解。
一是巴赫给我们留下了一份巨大的遗产,我们当前音乐文化的一切都依赖于此。从我们西方文化教育音乐的角度来看,我们整个音乐知识的很大一部分来源于他的变革性作品。每当我的学生领会到五度圈近乎形而上学的意义,并意识到如果没有巴赫,音乐物理学的原始真理就不会在我们的掌握之中时,我都会泪眼模糊。
其次,考虑到我们现在已经在这条路上走了 250 多年,我们是不同时代的不同文化和不同的人,音乐必须继续发展的方式取决于我们现在是谁,在我们丰富多彩的多样性中。学校教育是一个传统问题,也是如何呈现的问题。这让我想到了苏族萨满要学习 10 年或更长时间才能成为强大的治疗师——这与通过塔夫茨医学院所花的时间差不多。
无论如何,不管我们喜不喜欢,文化转型就在此时此地发生,所以让我们顺其自然吧。但是,仅仅因为我们停止抵制文化变革,并不意味着我们要抛弃好的旧方式。事实上,我们依靠这种智慧来保持我们对艺术的诚实。这可以追溯到亚里士多德。
这里有几个听力选择给你。首先,一个神话般的版本蓝调之夜,由艾拉·费兹杰拉献上
https://youtu.be/hXhxXYgKXd8
然后,你可以在威廉·格兰特·斯蒂尔的《非裔美国人交响曲》第一乐章中听到一些相同的降蓝音符。这是一部伟大的作品,你不必太费力就能看出音乐中固有的古典结构。
https://youtu.be/2OXmKehGDmE
在 R 中处理应用函数
原文:https://towardsdatascience.com/dealing-with-apply-functions-in-r-ea99d3f49a71?source=collection_archive---------9-----------------------
Apply functions in R
迭代控制结构(像 for、while、repeat 等循环。)允许多次重复指令。然而,在大规模数据处理中,使用这些循环会消耗更多的时间和空间。借助于 Apply 函数,r 语言有一种更高效、更快速的方法来执行迭代。
在这篇文章中,我将从视觉角度讨论**apply**
函数在循环中的效率,然后进一步讨论**apply**
家族的成员。
在进一步讨论**apply**
函数之前,让我们先看看与基本循环相比,使用**apply**
函数的代码执行如何花费更少的迭代时间。
考虑在 r 的gamclass
包中可用的**FARS(Fatality Analysis Recording System)**
数据集。它包含 17 个不同特征的 151158 个观察值。该数据集包括至少有一人死亡的所有事故,数据仅限于前排乘客座位有人的车辆。
现在让我们假设我们想要计算年龄列的平均值。这可以使用传统的循环和应用函数来完成。
方法 1:使用 for 循环
library("gamclass")
data(FARS)
mean_age <- NULL
total <- NULL
for(i in 1:length(FARS$age)){
total <- sum(total, FARS$age[i])
}
mean_age <- total/length(FARS$age)
mean_age
方法 2:使用 apply()函数
apply(FARS[3],2, mean)
现在让我们借助Profvis
包,通过可视化模式来比较这两种方法。
Profvis
是一个代码剖析工具,它提供了一个交互式图形界面,用于可视化指令在整个执行过程中的内存和时间消耗。
为了使用profvis
,把指令放在profvis()
中,它在 R studio 的一个新标签中打开一个交互式的 profile visualizer。
#for method 1
profvis({
mean_age <- NULL
total <- NULL
for(i in 1:length(FARS$age)){
total <- sum(total, FARS$age[i])
}
mean_age <- total/length(FARS$age)
mean_age
})
使用方法 1 输出
在火焰图选项卡下,我们可以检查指令所用的时间(毫秒)。
#for method 2
profvis({
apply(FARS[3],2, mean)
})
使用方法 2 输出
在这里,人们可以很容易地注意到,使用方法 1 所花费的时间几乎是 1990 ms (1960 +30),而对于方法 2,它仅仅是 20 ms。
应用函数优于传统循环的优势
- 执行起来更有效率和更快。
- 易于遵循的语法(而不是使用 apply 函数只编写一行代码来编写一组指令)
在 R 中应用系列
Apply family 包含各种不同的函数,适用于不同的数据结构,如列表、矩阵、数组、数据框等。apply 家族的成员有apply()
、lapply()
、sapply()
、tapply()
、mapply()
等。这些函数是循环的替代品。
每个应用函数至少需要两个参数:一个对象和另一个函数。该函数可以是任何内置的(如平均值、总和、最大值等。)或用户自定义函数。
浏览成员
1.apply()函数
apply()
的语法如下
其中X
是一个输入数据对象,MARGIN
表示函数如何适用于行或列,margin = 1 表示行,margin = 2 表示列,FUN
指向一个内置或用户定义的函数。
输出对象类型取决于输入对象和指定的函数。apply()
可以返回不同输入对象的向量、列表、矩阵或数组,如下表所述。
#---------- apply() function ----------
#case 1\. matrix as an input argument
m1 <- matrix(1:9, nrow =3)
m1
result <- apply(m1,1,mean) #mean of elements for each row
result
class(result) #class is a vector
result <- apply(m1,2,sum) #sum of elements for each column
result
class(result) #class is a vector
result <- apply(m1,1,cumsum) #cumulative sum of elements for each row
result #by default column-wise order
class(result) #class is a matrix
matrix(apply(m1,1,cumsum), nrow = 3, byrow = T) #for row-wise order
#user defined function
check<-function(x){
return(x[x>5])
}
result <- apply(m1,1,check) #user defined function as an argument
result
class(result) #class is a list#case 2\. data frame as an input
ratings <- c(4.2, 4.4, 3.4, 3.9, 5, 4.1, 3.2, 3.9, 4.6, 4.8, 5, 4, 4.5, 3.9, 4.7, 3.6)
employee.mat <- matrix(ratings,byrow=TRUE,nrow=4,dimnames = list(c("Quarter1","Quarter2","Quarter3","Quarter4"),c("Hari","Shri","John","Albert")))
employee <- as.data.frame(employee.mat)
employee
result <- apply(employee,2,sum) #sum of elements for each column
result
class(result) #class is a vector
result <- apply(employee,1,cumsum) #cumulative sum of elements for each row
result #by default column-wise order
class(result) #class is a matrix
#user defined function
check<-function(x){
return(x[x>4.2])
}
result <- apply(employee,2,check) #user defined function as an argument
result
class(result) #class is a list
2.lapply()
功能
lapply()
总是返回一个列表,lapply()
中的‘l’指的是‘list’。lapply()
处理输入中的列表和数据帧。MARGIN
此处不需要参数,指定的函数仅适用于列。请参考下表了解输入对象和相应的输出对象。
#---------- lapply() function ----------
#case 1\. vector as an input argument
result <- lapply(ratings,mean)
result
class(result) #class is a list#case 2\. list as an input argument
list1<-list(maths=c(64,45,89,67),english=c(79,84,62,80),physics=c(68,72,69,80),chemistry = c(99,91,84,89))
list1
result <- lapply(list1,mean)
result
class(result) #class is a list
#user defined function
check<-function(x){
return(x[x>75])
}
result <- lapply(list1,check) #user defined function as an argument
result
class(result) #class is a list#case 3\. dataframe as an input argument
result <- lapply(employee,sum) #sum of elements for each column
result
class(result) #class is a list
result <- lapply(employee,cumsum) #cumulative sum of elements for each row
result
class(result) #class is a list
#user defined function
check<-function(x){
return(x[x>4.2])
}
result <- lapply(employee,check) #user defined function as an argument
result
class(result) #class is a list
**apply()**
vs**lapply()**
lapply()
总是返回一个列表,而apply()
可以返回一个向量、列表、矩阵或数组。lapply()
中没有MARGIN
的范围。
3.sapply()
功能
sapply()
是lapply()
的简化形式。它有一个额外的参数**simplify**
,默认值为 true ,如果simplify = F
那么sapply()
返回一个类似于lapply()
的列表,否则返回最简单的输出形式。
请参考下表了解输入对象和相应的输出对象。
#---------- sapply() function ----------
#case 1\. vector as an input argument
result <- sapply(ratings,mean)
result
class(result) #class is a vector
result <- sapply(ratings,mean, simplify = FALSE)
result
class(result) #class is a list
result <- sapply(ratings,range)
result
class(result) #class is a matrix#case 2\. list as an input argument
result <- sapply(list1,mean)
result
class(result) #class is a vector
result <- sapply(list1,range)
result
class(result) #class is a matrix
#user defined function
check<-function(x){
return(x[x>75])
}
result <- sapply(list1,check) #user defined function as an argument
result
class(result) #class is a list#case 3\. dataframe as an input argument
result <- sapply(employee,mean)
result
class(result) #class is a vector
result <- sapply(employee,range)
result
class(result) #class is a matrix
#user defined function
check<-function(x){
return(x[x>4])
}
result <- sapply(employee,check) #user defined function as an argument
result
class(result) #class is a list
4.tapply()
功能
tapply()
在处理分类变量时很有用,它将一个函数应用于分布在不同类别中的数字数据。tapply()
最简单的形式可以理解为
tapply(column 1, column 2, FUN)
其中column 1
是函数应用的数字列,column 2
是因子对象,FUN
是要执行的函数。
#---------- tapply() function ----------
salary <- c(21000,29000,32000,34000,45000)
designation<-c("Programmer","Senior Programmer","Senior Programmer","Senior Programmer","Manager")
gender <- c("M","F","F","M","M")
result <- tapply(salary,designation,mean)
result
class(result) #class is an array
result <- tapply(salary,list(designation,gender),mean)
result
class(result) #class is a matrix
5.by()函数
by()
执行与tapply()
类似的工作,即对分布在不同类别中的数值向量值进行运算。by()
是tapply()
的一个包装函数。
#---------- by() function ----------
result <- by(salary,designation,mean)
result
class(result) #class is of "by" type
result[2] #accessing as a vector element
as.list(result) #converting into a list
result <- by(salary,list(designation,gender),mean)
result
class(result) #class is of "by" type
library("gamclass")
data("FARS")
by(FARS[2:4], FARS$airbagAvail, colMeans)
6.mapply()
功能
mapply()
中的“m”是指“多元”。它将指定的函数逐个应用于参数。请注意,在这里,function 被指定为第一个参数,而在其他应用函数中,它被指定为第三个参数。
#---------- mapply() function ----------
result <- mapply(rep, 1:4, 4:1)
result
class(result) #class is a list
result <- mapply(rep, 1:4, 4:4)
class(result) #class is a matrix
结论
我相信我已经介绍了所有最有用和最流行的 apply 函数以及所有可能的输入对象组合。如果你认为缺少了什么或者需要更多的输入。在评论里告诉我,我会加进去的!
快速处理分类数据—一个例子
原文:https://towardsdatascience.com/dealing-with-categorical-data-fast-an-example-d4329b44253d?source=collection_archive---------4-----------------------
早上 9 点你在办公室。你的老板进来,给了你一些数据,并要求你在中午 12 点之前创建一个模型。将召开一次会议,会上将展示这个模型。你是做什么的?
我们将查看来自私人 Kaggle 竞赛的示例数据集,创建一些快速模型并选择一个。完整的 github 库在这里是。
我们得到了训练数据集(特征和目标)。我们还获得了测试特性数据集,并被要求预测测试目标。为了测试您的预测,您创建了一个预测文件并将其上传到 Kaggle。然后 Kaggle 会给你一个分数(数值从 0 到 1)。值越高,你的预测就越好。我们将重点关注准确度分数,因为这是 Kaggle 将在本次比赛中测试的分数。
在 Jupyter 笔记本中首先导入您需要的课程。保持这个块是独立的,因为您可以向它添加更多的库并单独执行它。
import numpy as np
import pandas as pdfrom sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score, GridSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifierpd.set_option('display.max_columns', None) # Unlimited columns.
pd.options.mode.use_inf_as_na = True # Any inf or -inf is
# treated as NA.
读入训练特征数据:
X_train_original = pd.read_csv('./train_features.csv',
header = [0], # Top row is header.
index_col = 0) # First col is index.
X_train_original.head()
读入训练目标数据:
y_train_original = pd.read_csv('./train_labels.csv',
header = [0], # Top row is header.
index_col = 0) # First col is index.
y_train_original.head()
你的目标很明确。让我们看看它有多少个类别:
pd.value_counts(y_train_original.status_group, normalize = True)
由于一半以上只是一个类别,我们可以预测我们所有的目标值都是“功能性的”。这将在训练数据集上给我们 0.54 的准确度。让我们看看它在测试数据集上做了什么。
多数类预测
我们进行多数类预测的原因是为了衡量我们未来的预测分数应该有多好。这给了我们一个基线,我们希望在下一个模型中跨越它。
让我们先来看看测试特性:
X_test_original = pd.read_csv('./test_features.csv',
header = [0],
index_col = 0)
X_test_original.shape
(14358, 39)
此形状显示我们在预测输出中需要 14358 个值(输入的每行一个)。因此,我们创建了一个具有所需行数的数组,值为“functional”:
y_pred = ['functional'] * len(X_test_original)
y_pred = pd.DataFrame(data = y_pred,
index = X_test_original.index.values,
columns = ['status_group'])
y_pred.head()
然后我们把它写到一个文件中,并导入到 Kaggle 中。Kaggle 的准确率为 0.53(这和我们的预期差不多)。区别只是因为测试数据集不包含与训练数据集完全相同的目标类值比例。
仅使用数字特征进行预测
X_train_numerical = X_train_original.select_dtypes(
include = np.number).copy()
将“日期 _ 记录”字段转换为“天数 _ 自 _ 纪元”。在计算机编程中,对于 unix 计算机,纪元被认为是 1970 年 1 月 1 日。这只是一个通常使用的惯例——我们可以在这里的任何一天使用。对于机器学习,我们只关心值的相对比例是否相同。
days_since_epoch = \
pd.to_datetime(X_train_original['date_recorded']) \
- pd.datetime(1970, 1, 1)
X_train_numerical['days_since_epoch'] = days_since_epoch.dt.days
X_train_numerical.head()
X_train_numerical_indices = X_train_numerical.index.values
y_train_numerical = y_train_original[y_train_original.index. \
isin(X_train_numerical_indices)]
逻辑回归
让我们尝试一个逻辑回归分类器:
cv_score = cross_val_score(LogisticRegression(),
X_train_numerical, y_train_numerical,
scoring = 'accuracy',
cv = 3,
n_jobs = -1,
verbose = 1)
cv_score
逻辑回归给我们的分数是 0.55。与多数班级模式没有太大区别。
决策图表
决策树分类器怎么样:
clf = DecisionTreeClassifier()
cv_score = cross_val_score(clf,
X_train_numerical, y_train_numerical,
scoring = 'accuracy',
cv = 3,
n_jobs = -1,
verbose = 1)
cv_score
这个分数在 0.65 就好多了。让我们获得测试数据集的预测,并将其写出到文件中。然后我们可以提交给 Kaggle:
clf.fit(X_train_numerical, y_train_numerical)
X_test_numerical = X_test_original.select_dtypes(include = \
np.number).copy()
days_since_epoch = pd.to_datetime(X_test_original['date_recorded'])
- pd.datetime(1970, 1, 1)
X_test_numerical['days_since_epoch'] = days_since_epoch.dt.daysy_pred = clf.predict(X_test_numerical)y_pred = pd.DataFrame(data = y_pred,
index = X_test_numerical.index.values,
columns = ['status_group'])y_pred.to_csv('./decision_tree_pred.csv',
header = ['status_group'],
index = True,
index_label = 'id')
检查数据中是否有缺失值或异常值
X_train_original.isnull().sum()
39 个要素中有 7 个要素的值为空。让我们放弃这些功能:
X_non_nulls = X_train_original.dropna(axis = 1)
让我们找出每个特征中有多少个唯一值:
X_non_nulls.nunique().sort_values(ascending = True)
根据这篇文章,当分类值编码为数字或二进制时,决策树分类器更快。
让我们对具有< 50 个唯一值的非空列进行编码,将数字列添加到数据帧中,并运行不同深度的决策树分类器。
X_selected = X_non_nulls.loc[:, X_non_nulls.nunique().sort_values()\
< 50]
cat_cols = list(X_selected.select_dtypes(['object']).columns.values)X_categorical = X_selected[cat_cols]. \
apply(lambda x: x.astype('category').cat.codes)
X_train_selected = X_train_numerical.join(X_categorical)clf = DecisionTreeClassifier()
cv_score = cross_val_score(clf,
X_train_selected, y_train_original,
scoring = 'accuracy',
cv = 3,
n_jobs = -1,
verbose = 1)
cv_score
这给了我们 0.75 分。这是训练分数,所以我们应该将相同的分类器应用于测试数据,并请 Kaggle 评估其准确性:
clf.fit(X_train_selected, y_train_original)X_test_non_nulls = X_test_original.dropna(axis = 1)
X_test_selected = X_test_non_nulls.loc[:, \
X_test_non_nulls.nunique().sort_values() < 50]cat_cols = list(X_test_selected.select_dtypes(['object']). \
columns.values)
X_test_categorical = X_test_selected[cat_cols]. \
apply(lambda x: \
x.astype('category').cat.codes)X_test_selected = X_test_numerical.join(X_test_categorical)y_pred = clf.predict(X_test_selected)
y_pred = pd.DataFrame(data = y_pred,
index = X_test_selected.index.values,
columns = ['status_group'])
测试数据集给我们的分数是 0.76,这个分数更高,因为我们的模型对测试数据集的拟合程度肯定比训练数据集好一点。仍然在相同的值左右,这是意料之中的。
既然我们的决策树给了我们一个好的结果,让我们试试随机森林分类器
随机森林分类器适用于多项目标(具有多个分类值的目标)。该分类器从训练数据集中随机抽取样本,因此不需要对其进行交叉验证。我们可能会做 GridSearchCV 来尝试不同的 n_estimators 和 max_depth(如果我们的分数不是很好的话)。
随机森林分类器由许多决策树组成。通过从整个特征列表中随机选择树的每个节点处的特征来创建每个树。与单个决策树分类器相比,树的数量给予随机森林分类器更少的偏差。
X_train, X_test, y_train, y_test = train_test_split(
X_train_selected, y_train_original, test_size=0.2)clf = RandomForestClassifier()
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
决策树分类器给我们的分数是 0.79。很好,但是没有以前跳得高。这是我们通常会发现的情况——早期的模型通常得分较低,可以很容易地被击败,但后期的模型很难被击败。我们还没完呢。我们将使用网格搜索来搜索最佳随机森林分类器:
param_grid = {
'n_estimators': [10, 20, 30],
'max_depth': [6, 10, 20, 30]
}gridsearch = GridSearchCV(RandomForestClassifier(n_jobs = -1),
param_grid=param_grid,
scoring='accuracy', cv=3,
return_train_score=True, verbose=10)gridsearch.fit(X_train, y_train)
param_grid 是分类器所需参数的字典。如果您不确定在这个字典中放入什么,可以使用这个函数调用,它会给出您可以使用的参数列表:
RandomForestClassifier().get_params().keys()
在 GridSearchCV 函数内部,我们用 n_jobs = -1 创建了一个 RandomForestClassifier 对象。这将允许我们使用机器上的所有内核,从而使这个作业运行得更快。
变量“cv”给出了该网格搜索应该使用的交叉验证折叠数。cv = 3 会将我们的数据分成 3 个相等的部分,然后使用其中的两个部分来训练 RandomForest 分类器,并使用剩余的数据进行测试。它会一直这样做,直到所有的组合都用完为止。
verbose 值将告诉 grid search 要打印多少信息。值越大,打印的信息越多。值为 10 时,您将会看到在 param_grid 字典中指定的变量值的每个组合与测试/训练分割的迭代编号一起打印出来。您还将看到在数据的测试部分获得的分数。您不必阅读所有内容,我们会打印出一份更易于阅读的摘要:
pd.DataFrame(gridsearch.cv_results_).sort_values( \
by='rank_test_score')
此数据帧的顶行显示了 param_grid 选项,这些选项在数据的测试部分给出了最好的分数。这显示在 mean_test_score 列中,我们的分数是 0.79。这与决策树分类器相同。
让我们在 Kaggle 测试集上运行这个:
clf = RandomForestClassifier(max_depth = 20,
n_estimators = 30,
n_jobs = -1)
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
我们得到了 0.81 分。这与决策树分类器得分 0.79 没有太大的不同。不同的是决策树有偏差,而随机森林没有。如果你在多组新的测试数据上测试这个随机森林分类器,你会发现它比决策树分类器做得更好。
结论
既然你知道随机森林比决策树更好,也许你可以使用以下步骤更快地找到解决方案:
- 永远,永远,先做个快速预测。对于像这样的分类问题,如果目标中有一个多数类,多数类预测将是一个好的开始。
- 如果有很少的空值(或者如果它们只存在于某些特征中),则丢弃观察值/特征。
- 删除具有大量值的分类要素。他们可能不会做出好的特写。此外,删除具有单一值的要素,因为它们无法区分不同的类。
- 将日期转换为天或秒(为了更精确)。大多数分类器都是和数字一起工作的,所以最好都给它们数字。将分类列转换为数字。
- 不要运行决策树分类器,因为它是有偏见的,只需用随机森林分类器运行网格搜索。
处理认知偏差:数据科学家的观点
原文:https://towardsdatascience.com/dealing-with-cognitive-biases-a-data-scientist-perspective-5c359d1e3a2d?source=collection_archive---------14-----------------------
偏见是影响我们日常生活的一个重要原则。我们都有自己的偏见,这些偏见是由我们的生活经历、教育、文化和社会交往形成的。偏见这个词与负面含义和偏见联系在一起,但在帮助人类在史前时代生存下来的“认知偏见”这个总括术语下,还有一个完全不同的偏见类别。
认知偏差是我们进化过程的结果。它们旨在通过在关键的时间敏感的情况下做出快速决策来帮助我们生存,并处理人类大脑有限的信息处理能力。简单地说,他们是我们直觉背后的原因。这些偏见往往会导致违背事实的非理性行为,并导致判断上的系统性错误。
在过去的 70 年里,社会心理学和行为经济学领域的研究人员发现了 200 多种不同的偏见。他们研究了这些偏见如何影响金融、管理和临床判断等领域。
随着数据科学模型在真实世界应用(如信用评分、欺诈检测、个人推荐)中的流行程度不断提高,数据科学家对认知偏差有更透彻的理解至关重要。通过意识到人类判断中的这些系统性错误,我们有望采取必要的措施,并在构建精确模型的方法中更加自觉。
数据科学项目通常包括五个主要步骤,
- 理解业务问题
- 数据收集和清理
- 探索性数据分析
- 模型构建和验证
- 洞察和交流结果
没有多少人关注覆盖数据科学项目中由于认知偏差而出现的盲点的必要性。下面,我列出了可能影响数据科学生命周期几个阶段的相关偏见。
数据收集
一旦数据科学家很好地理解了业务问题,他们就需要准备一个数据集来构建模型。在这个阶段,我们需要小心生存偏差、可用性偏差等引入的逻辑错误。
生存偏差 的产生是由于人类倾向于关注那些被选择的或成功超过潜在标准的数据点。
例如,如果我们开始建立一个模型来预测成功企业家的特征,那么现有的数据很可能主要集中在那些在企业中发家致富的人身上,而不是那些在创业过程中失败的人。我们都知道如果我们只建立正面标签的模型会有什么样的结局。
可用性偏差 是一种认知捷径,导致过度依赖我们能立即想到的事件或数据。通常,这种偏差可能会导致忽略可能会提高模型性能的新数据源。
例如,如果手头的任务是建立一个信用风险模型,我们的思维过程会引导我们收集财务和人口统计信息,因为这些信息很容易获得,也很容易收集。
我们并不真正关注可以从用户的网络浏览模式中推断出的个性特征。由于金融稳定并不意味着现实世界中偿还贷款的倾向,我们的模型将无法捕捉到这一信号。
探索性数据分析
数据探索是交付成功模型的关键部分。仔细的 EDA 提供了对数据的直观理解,并极大地有助于设计新功能。数据科学家需要注意现阶段的聚类错觉、锚定等谬误。
群集幻觉 指人类倾向于在随机事件中寻找模式,当它们不存在的时候。尽管随机性是普遍存在的,我们也很熟悉,但人类心理学的研究表明,我们很难识别它。
由于数据探索的目标是发现数据中的模式,我们更容易因为这种错觉而犯错误。适当的统计测试和持怀疑态度做额外的检查有助于克服这种错觉。
锚定 是一种偏见,这种偏见是由于过于重视首先发现/提供的信息而产生的。我们倾向于在第一手信息的基础上“锚定”我们所有的未来决策。
这是一个经常被电子商务和产品公司利用的原则,通过为第一个项目提供高得多的价格,以便连续的项目可以被认为是“便宜的”
在 EDA 过程中,第一个自变量的非常弱的线性相关性可能会影响我们对后续变量与因变量相关性的解释。拥有一套预定义的指导方针和阈值来指导分析的重要性将有助于克服这种偏见。
模型结构
在这个阶段,数据科学家的任务是选择和建立一个机器学习模型,提供最有效和最稳健的解决方案。在这一阶段,由于诸如热手谬误或跟风效应之类的偏见,有可能犯错误。
热手谬误 是一种现象,一个最近经历了成功结果的人被认为在未来的尝试中有更大的成功机会。这在体育运动中最常见,连续获胜的球队被认为是“热门”/“连胜”,因此有望获得更高的成功率。
类似地,我们这些数据科学家经常觉得,在没有检查其他合适模型的情况下,使用在前一个问题中给我们最好分数的模型是好的。
从众效应 是一种认知偏差,它解释了选择某个选项或跟随特定行为的冲动,因为其他人正在这样做。这导致了一个危险的循环,因为越来越多的人继续跟风,使得其他人更有可能跟风。
我们经常在分析中观察到这一点,在分析中,从业者经常追求深度学习/强化学习等时髦词汇,而不理解约束和相关成本。
通过试验一系列合适的机器学习算法和适当的交叉验证周期,我们可以克服模型选择阶段的偏差。
模型解释
在我们成功地构建了一个模型之后,同样重要的是解释模型输出,并提出一个连贯的故事以及可操作的见解。由于确认偏差,这一关键阶段可能会受到影响。
确认偏差 是所有偏差中最流行、最普遍的认知偏差。我们只听到我们想听到的,我们只看到我们想看到的。
我们强大的信念系统迫使我们忽略任何与我们先入为主的观念不符的信息。
任何挑战现有信念的新信息都应该以开放的心态对待。说起来容易做起来难,我同意。
上面提到的认知偏见绝不是一个详尽的清单,还有许多其他的原则和谬误驱动着人类的思维过程。我希望这篇文章为您提供了一些额外的见解,让您在未来的项目中更加怀疑和谨慎。
如果你有兴趣探索更多关于认知偏见的东西,看看巴斯特·本森写的这篇精彩的文章。
处理缺失数据
原文:https://towardsdatascience.com/dealing-with-missing-data-17f8b5827664?source=collection_archive---------20-----------------------
我最近完成了一个使用机器学习预测宫颈癌的项目 Jupyter 笔记本和所有相关的原始资料都可以在这个 GitHub repo 中找到。该项目的挑战之一是如何处理许多预测变量中的缺失值。本文描述了我是如何处理这些缺失数据的。
许多机器学习模型在遇到缺失数据时会抛出一个错误,并且有许多方法(和观点!)用于处理缺失值。最简单的方法之一是用某个特定变量的平均值来填充缺失值,我见过很多项目都是采用这种方法。它又快又简单,有时还能有好的效果。更困难的是,通过比较缺失值的记录和没有缺失该因子值的类似记录,使用复杂的方法来估算缺失值。每种方法都有优点和缺点,在我看来,最好的选择总是根据具体情况而定。
由于这是我的第一个涉及重大缺失值的机器学习项目,我决定采取一种容易解释的方法,即逐个查看每个因素,以更好地了解每个因素的分布。为此,我查看了计数图、箱线图和中心性度量(均值、中值、众数)。在评估这些信息后,我使用了以下一种或多种方法来处理缺失的信息:
- 如果因子缺少很大比例记录的值,请从数据集中删除该因子。
- 如果一小部分记录缺少某个因子的值,请删除这些记录。
- 向分类因子添加新选项。例如,如果因子有三个值:“val_1”、“val_2”、“val_3”,则可以添加一个额外的“未知”值。现在,因子将有四个值:“val_1”、“val_2”、“val_3”和“未知”。
- 将布尔因子转换为具有 3 个可能值的分类因子:“真”、“假”和“未知”。
- 创建一个新的布尔因子,将每条记录分类为包含(或不包含)有关该因子的信息。当然,这使得原始因子中的值仍然缺少一些信息。在这种情况下,原始因子的缺失值将使用剩余选项之一来填充。
- 用该因子的平均值、中值或众数填充缺失值。
- 用该因子中已经存在的值之一填充缺失的布尔值或分类值。可以使用因子中出现的每个值的相同比例来随机分配该值,或者如果有一个值出现频率最高,则缺失的值可以用最常见的值来填充。
这是我所处理的数据集中的因子的概述,显示了每个因子的缺失数据百分比,红色文本表示某个因子缺失信息。该信息最初是在委内瑞拉加拉加斯的“加拉加斯大学医院”收集的,由 35 个变量组成,包括 858 名患者的人口统计信息、习惯和历史医疗记录。出于隐私考虑,一些患者决定不回答一些问题,因此产生了缺失值。该数据集来自于 2017 年 5 月首次在线发表的一篇研究论文。
大多数变量都缺少数据,包括具有布尔值和数值的变量。因为我的策略涉及为多个因素重复创建相同的图和统计数据,所以我为此创建了一个函数:
def countplot_boxplot(column, df):
fig = plt.figure(figsize=(15,20))
fig.suptitle(column, size=20)
ax1 = fig.add_subplot(2,1,1)
sns.countplot(dataframe[column])
plt.xticks(rotation=45)ax2 = fig.add_subplot(2,1,2)
sns.boxplot(dataframe[column])
plt.xticks(rotation=45)
plt.show()
print('Min:', dataframe[column].min())
print('Mean:', dataframe[column].mean())
print('Median:', dataframe[column].median())
print('Mode:', dataframe[column].mode()[0])
print('Max:', dataframe[column].max())
print('**********************')
print('% of values missing:', (dataframe[column].isna().sum() / len(dataframe))*100)
对于我想要创建一个新的布尔因子的情况,我创建了一个函数:
def new_bool(df, col_name):
bool_list = []
for index, row in df.iterrows():
value = row[col_name]
value_out = 1
if pd.isna(value):
value_out = 0 bool_list.append(value_out) return bool_list
我还创建了几个简单的函数,使传递列名作为参数来填充缺失值变得容易:
# function to replace missing values with the mediandef fillna_median(column, dataframe):
dataframe[column].fillna(dataframe[column].median(), inplace=True)
print (dataframe[column].value_counts(dropna=False))
# function to replace missing values with the meandef fillna_mean(column, dataframe):
dataframe[column].fillna(dataframe[column].mean(), inplace=True)
print (dataframe[column].value_counts(dropna=False))# function to replace missing values with a value provideddef fillna_w_value(value, column, dataframe):
dataframe[column].fillna(value, inplace=True)
print(dataframe[column].value_counts(dropna=False))
让我们看一个因子的例子,我创建了一个新的布尔因子,然后用中值填充原始因子中缺少的值。首先,我将运行 countplot_boxplot 函数:
countplot_boxplot('Number of sexual partners', df2)
Min: 1.0
Mean: 2.527644230769231
Median: 2.0
Mode: 2.0
Max: 28.0
**********************
% of values missing: 3.0303030303030303
在选择如何填充缺失的信息之前,我希望保留包含在 3%的记录中的信息,这些记录缺失了该因子的值。通过调用上面显示的函数,我创建了一个名为“is_number_partners_known”的新布尔因子:
df['is_number_partners_known'] = new_bool(df, 'Number of sexual partners')
既然我已经获得了这些信息,我就来看看源因素的分布。平均值和众数都是 2.0,但是平均值被上限值的异常值拉高了。我选择用中位数(2.0)来填充缺失的值。
fillna_median('Number of sexual partners', df2)
现在,让我们来看一个具有非常偏斜的分布和高得多的缺失值百分比的因子。同样,首先我运行我的函数来查看分布。
countplot_boxplot('Hormonal Contraceptives (years)', df2)
Min: 0.0
Mean: 2.2564192013893343
Median: 0.5
Mode: 0.0
Max: 30.0
**********************
% of values missing: 12.587412587412588
到目前为止,零是该因素最常见的值,然而该值的范围长达 30 年,在该范围的较高区域有几个异常值。这些高异常值将平均值拉得远远高于中值。可以使用众数(0)或中位数(0.5)来填充缺失值。由于超过 12%的记录缺少某个值,因此该选择可能会对模型的性能产生重大影响,尤其是当该因素在给定的预测模型中很重要时。我选择用模式(0)填充缺失的值。
对于最后一个示例,我们来看两个单独的布尔标准因子:
- 性病:结肠瘤病
- 性病:艾滋病
这两个布尔因子(“STDs”,也是布尔型)的“父”列与其所有“子”列具有相同的缺失值百分比(大约 12%)。我之前选择用 False(零)填充父因子的缺失值。然后,我选择用 False(零)填充所有“儿童”因素(每个因素代表一种不同的性传播疾病)中缺失的值。后来,当我为数据集中的所有因素运行相关矩阵时,我注意到有两行是空白的。这就是我如何发现在这两个因素中,零是唯一发生的价值。这些因素中的原始数据只有假(零)或缺失。当我用零填充缺失值时,因子不包含任何信息,因为每个记录都有相同的 False 值。我选择从数据集中删除这两个因素。
在对所有因素重复上述过程之后,我检查了整个数据库中 NaN 的计数:
df2.isna().sum()
下面的输出显示不再有丢失的值——这正是我需要看到的。
Age 0
Number of sexual partners 0
First sexual intercourse 0
Num of pregnancies 0
Smokes 0
Smokes (years) 0
Smokes (packs/year) 0
Hormonal Contraceptives 0
Hormonal Contraceptives (years) 0
IUD 0
IUD (years) 0
STDs 0
STDs (number) 0
STDs:condylomatosis 0
STDs:vaginal condylomatosis 0
STDs:vulvo-perineal condylomatosis 0
STDs:syphilis 0
STDs:pelvic inflammatory disease 0
STDs:genital herpes 0
STDs:molluscum contagiosum 0
STDs:HIV 0
STDs:Hepatitis B 0
STDs:HPV 0
STDs: Number of diagnosis 0
STDs: Time since first diagnosis 0
STDs: Time since last diagnosis 0
Dx:Cancer 0
Dx:CIN 0
Dx:HPV 0
Dx 0
Hinselmann 0
Schiller 0
Citology 0
Biopsy 0
is_number_partners_known 0
is_first_intercourse_known 0
is_number_pregnancies_known 0
dtype: int64
数据现在已经准备好被分成训练组和测试组,用于我将要探索的监督学习模型。更多信息,请看这里的 Jupyter 笔记本。
数据集引用:
凯尔温·费尔南德斯、海梅·卡多佐和杰西卡·费尔南德斯。具有部分可观察性的迁移学习应用于宫颈癌筛查。伊比利亚模式识别和图像分析会议。斯普林格国际出版公司,2017 年。https://archive . ics . UCI . edu/ml/datasets/宫颈癌+癌症+% 28 风险+因素%29#
处理多类数据
原文:https://towardsdatascience.com/dealing-with-multiclass-data-78a1a27c5dcc?source=collection_archive---------5-----------------------
森林覆盖类型预测
Photo by Sergei Akulich on Unsplash
当你遇到一个包含三个以上类别的分类问题时,你有没有想过该怎么办?你是如何处理多类数据的,你是如何评估你的模型的?过度适应是一个挑战吗——如果是,你是如何克服的?
请继续阅读,了解我是如何在我的最新项目中解决这些问题的——从美国林务局提供的数据集分析森林覆盖类型,该数据集存放在 UCI 机器学习库。
这个数据集特别有趣,因为它由分类变量和连续变量混合组成,这在历史上需要不同的分析技术。这些变量描述了每个样本森林区域的地质情况,一个多类标签(七种可能的树木覆盖类型之一)作为我们的目标变量。
根据 Kaggle 的说法,这七种可能的封面类型如下:
- 云杉/冷杉
- 黑松
- 美国黄松
- 杨木/柳树
- 阿斯
- 花旗松
- 克鲁姆霍尔茨
我认为这是我在sharpes minds研究期间所学知识的一个很酷的应用,因为成功的森林覆盖类型分类有如此多的积极变化的潜力,特别是在环境保护、动植物研究和地质研究等领域。
这篇中型博客文章将专注于我探索的基于树的方法来分析这个数据集,但你可以查看我的整个回购,其中包含其他机器学习方法,在这里:https://github.com/angelaaaateng/Covertype_Analysis
探索性数据分析
第一步是探索性的数据分析。我用 pandas 加载数据并将信息读入数据帧。
然后,我检查了数据类型,以确保我的数据集中没有异常——并更好地了解我正在处理哪种数据。基于这一点,我们还看到没有 NaN 值,列是合理的,并且总的来说,数据集非常干净,在这个阶段和这个项目的目标中不需要额外的清理。
我们还看到,我们正在处理一个相当大的数据集,因此很可能需要从 581,012 个条目中进行缩减采样。我们还知道我们有 55 个列或特性,这将在下一节中更彻底地探讨。接下来,让我们看看这些森林覆盖类型的频率分布。
数据集的大部分由 covertype 1 和 covertype 2 组成,对于这种不平衡的数据集,我们必须选择缩减采样或构建玩具数据集的方式。关键在于理解这个问题的答案:我们的目标是平等地表示所有的覆盖类型,还是按照每个覆盖类型在整个数据集中出现的频率比例来表示它?
一个重要的考虑因素是,下采样确实减少了我们可以用来训练模型的数据点的数量,所以尽管有这种分析,使用所有样本总是可能是更明智的选择。这在很大程度上取决于业务优先级,包括将一个 covertype 误认为另一个 cover type 的相对成本。例如,如果我们同样关注每个覆盖类型的分类准确性,那么通过缩减采样来获得覆盖类型的均匀分布可能是最有意义的。然而,如果我们只关心封面类型 1 相对于其他 6 个封面类型的分类,那么我们可以使用不同的采样方法。
尽管如此,对于这个项目,我将从假设我们同样关心正确地分类每个 covertype 开始,并且我将在文章的结尾探索这个决定的影响。
更深入地研究每种封面类型的统计数据,我们会发现样本之间的计数差异很大,我们还会看到每个变量的数据分布很广。
特别是对于高程,我们看到覆盖类型 1 至 7 的标准偏差范围为 95 至 196。我们还看到,对于封面类型 4,我们最少有 2,747 个数据点,而对于封面类型 2,我们有 28,8301 个数据点,这进一步表明我们有一个不平衡的数据集。
我们可以探索连续变量之间的相关性,以便使用相关矩阵更好地理解数据中的潜在关系:
请注意,我特意在此相关图中省略了分类变量,因为相关矩阵显示了不同特征对之间的皮尔逊相关系数,皮尔逊相关对于非连续输入没有意义。根据上述相关矩阵,似乎与覆盖类型线性相关的连续变量是坡度和高程以及坡向。我们的三个山体阴影特征似乎也高度相关。这是意料之中的,而且看起来也合乎逻辑,因为它们都测量相似的东西。这些山体之间的相关性表明,它们可能包含大量冗余信息——当我们进行特征选择时,我们将回到这个想法。
数据探索和建模并不总是不同的事情
基于我们之前展示的数据探索,我们看到目标变量是多类和二进制的。为了确定什么是“好”的模型,以及我们如何定义这个项目的成功,我首先研究了建立一个基线模型。
然而,在我们开始训练多类基线模型之前,我们需要首先对数据进行采样。在我们所有的 500,000+个条目上训练一个模型不仅耗时,而且效率非常低。
对于我们的特定数据集,我们将从一个简单的随机抽样方法开始,其中我们确保了一个平衡的类分布,原因在本文的开始部分有概述。这意味着我们想要从 1 到 7 的每个 covertype 中抽取 n 个条目的样本,并确保每个类都有相同数量的条目。
我们将从 n = 2700 开始,这是最小类的最小数据点数,我们将从使用简单的决策树来建模数据开始。我们这样做的目的是通过研究我们的决策树如何查询我们的数据集来更好地理解我们的数据,并获得我们的分类性能的下限。这一步将我们置于数据探索和预测建模之间的模糊边界,这是一个灰色地带,我发现它特别有助于探索,尤其是基于树的模型。
决策树基线模型
让我们从更好地理解我们的数据开始。我首先用一个非常短的决策树来拟合缩减采样数据集(使用 max _ depth 3),并可视化结果:
我们要注意的第一件事是 elevation 参数的重要性,在这个公认的简单模型中,它似乎支配着所有其他参数。这与我们之前在相关矩阵中发现的一致,相关矩阵显示高程是与我们的目标变量(Cover_Type)最相关的连续特征。
虽然这个模型的 max_depth 是严格限制的,但它仍然比随机猜测表现得好得多:它在所有 7 个类中获得的预测准确性是 X%(训练准确性)和 Y%(验证准确性)。
接下来,我想看看无约束模型(没有 max_depth 为 3)将如何执行,以更好地了解简单决策树对该数据集的全部预测能力。我用 sklearn 提供的默认参数训练了一个新的树(其中包括一个 max _ depth None,这意味着树将无限制地增长)。结果如下:
我们将使用准确度分数来衡量绩效。
predictions = dtree.predict(X_test)print ("Decision Tree Train Accuracy:", metrics.accuracy_score(y_train, dtree.predict(X_train)))
print ("Decision Tree Test Accuracy:", metrics.accuracy_score(y_test, dtree.predict(X_test)))from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
我们可以看到这里有过度拟合,因为训练数据的准确度分数是 1。这是一个重要的结果,因为它与决策树倾向于过度拟合的一般趋势是一致的。为了好玩,我想通过绘制作为 max_depth 参数的函数的训练和验证精度来展示这种过度拟合过程是如何进行的:
上图向我们展示了测试精度低于训练精度,这就是过度拟合的定义:我们的模型正在将自己扭曲成完美捕捉训练集中趋势的形状,代价是无法归纳出看不见的数据。
为了总结我们的数据探索和初始建模步骤,让我们来看看将我们的深度树应用于验证集所产生的混淆矩阵:
看上面的混淆矩阵,似乎这些错误大部分来自类 1 和类 2。
随机森林基线模型
既然我们知道了我们的问题会带来什么,是时候认真对待建模了。随机森林是我将在这里使用的模型,因为 1)它们是健壮的,并且概括得很好;2)它们易于解释。随机森林是决策树的集合:它们由一堆独立的决策树组成,每个决策树都只使用我们训练集中的一个子集进行训练,以确保它们正在学习以不同的方式进行预测。他们的输出然后通过简单的投票汇集在一起。
和往常一样,我的第一步是使用开箱即用的随机森林分类器模型。这导致了性能的大幅提升:验证集的准确率为 86%,训练集的准确率为 100%。换句话说,这个模型是过度拟合的(或者说,集合中的每一个决策树都是过度拟合的),但是我们仍然看到了通过将一堆过度拟合的决策树汇集在一起在性能上的巨大改进。
随机森林特征选择
F 首先,让我们进行特征选择,以确定影响我们的随机森林集合模型准确率的最具预测性的变量。人们为此使用了许多不同的方法,但是在这里,我们将集中于排列特征重要性。置换特征重要性的工作原理是在我们的验证集中选择一列(即特征),然后随机洗牌,从而破坏该特征与我们的模型用来进行预测的所有其他特征之间的相关性,最后在这个新洗牌的验证集上测量我们的模型的性能。如果性能显著下降,这就告诉我们,我们改变的特性一定很重要。
使用排列重要性,我们看到以下结果:
基于这一点,似乎只有我们的一小部分特征支配着其他特征。事实上,如果当我试图只保留这里指出的前 13 个特征时,我最终只牺牲了可以忽略不计的准确性,在验证集上再次获得了 86%的准确性。
随机森林-超参数调整
O 随机森林中超参数调整的一个关键是,一般来说,模型的性能只会随着我们添加到集合中的决策树数量的增加而增加。因此,在我们使用 GridSearchCV 调优完所有其他相关参数(如 max_depth、min_samples_leaf 和 min_samples_split)之后,它实际上是我们要调优的最后一个参数。
我们得到最后一组最佳估计值,给出这些最佳参数,然后将它们应用于我们的模型并比较结果:
n_best_grid = n_grid_search.best_estimator_n_optimal_param_grid = {
'bootstrap': [True],
'max_depth': [20], #setting this so as not to create a tree that's too big
#'max_features': [2, 3, 4, 10],
'min_samples_leaf': [1],
'min_samples_split': [2],
'n_estimators': [300]
}nn_grid_search = GridSearchCV(estimator = n_rfc_gs, param_grid = n_optimal_param_grid,
cv = 3, n_jobs = -1, verbose = 2)nn_grid_search.fit(X_train, y_train)nn_rfc_pred_gs = nn_grid_search.predict(X_test)nn_y_pred_gs = nn_grid_search.predict(X_test)
print ("Random Forest Train Accuracy Baseline After Grid Search and N-estimators Search:", metrics.accuracy_score(y_train, nn_grid_search.predict(X_train)))
print ("Random Forest Test Accuracy Baseline After Grid Search and N-estimators Search:", metrics.accuracy_score(y_test, nn_grid_search.pre
我们的模型性能有了适度的提高,从 0.860 提高到 0.863。这并不完全令人惊讶——超参数调优并不总是对性能产生巨大影响。
最后,我们将查看 num_estimators 参数,注意一起绘制训练集和验证集的精度。正如所料,两者都随着 num_estimators 近似单调增加,直到达到一个平稳状态:
然后,我们可以比较我们当前的模型及其基于准确性的性能,并将其与原始的开箱即用模型进行比较。
这里要讨论的重要一点是,在最初的运行中(没有在这篇博文中显示,但在笔记本这里),我们的测试准确率如何从没有参数搜索的 86%上升到使用 GridSearchCV 后的 84%。我们可以看到,调整后的模型并不比根据默认值训练的 RF 表现得更好。这是因为方差对我们数据集的影响 GridSearch 很难区分最好的超参数和最差的超参数,因此使用开箱即用的随机森林模型可能会节省时间和计算能力。
与这一点相关的一些重要的可能性如下:
- 我们使用 cv = 3 的 GridSearch(三重交叉验证)。这意味着对于每个超参数组合,模型仅在训练集中的 2/3 的数据上进行训练(因为 1/3 被保留用于验证)。因此,基于这一点,我们预计 GridSearch 会产生更悲观的结果。避免这种情况的一种方法是增加 cv 的值,这样就有了更小的验证集和更大的训练集。
- 总是有噪声(或“方差”)要考虑:当我们在不同的数据集上训练我们的模型时,它通常会给出不同的结果。如果我们的模型的方差足够高(这意味着它的性能很大程度上取决于它被训练的特定点),那么 GridSearch 实际上可能无法区分“最好”的超参数和最差的超参数。这是对我们目前结果最可能的解释。这意味着我们还不如使用默认值。
- 我们可以更深入探索的另一个领域是 max_features 。
那么,我们如何做得更好呢?根据我们的混淆矩阵,似乎类 1 和类 2 是大部分错误的来源。在我的下一个项目中,我们将探索模型堆叠,看看我们是否可以在这里获得任何准确性。
如有任何问题或意见,欢迎在推特 @ambervteng 联系我。感谢阅读,下次见!
Github 回购:https://github.com/angelaaaateng/Covertype_Analysis
Heroku Web App:https://covertype.herokuapp.com/
Jupyter 笔记本:https://github . com/angelaaaateng/Projects/blob/master/cover type _ Prediction/Scripts/Tree-Based % 20 and % 20 bagging % 20 methods . ipynb
参考资料:
[1] DataCamp 决策树教程https://www . data camp . com/community/tutorials/Decision-Tree-classification-python
[2] Seif,g .用于 ML 的决策树https://towardsdatascience . com/a-guide-to-Decision-Trees-for-machine-learning-and-data-science-Fe 2607241956
[3] Matplotlib 文档https://Matplotlib . org/3 . 1 . 1/API/_ as _ gen/Matplotlib . py plot . x ticks . html
亲爱的兰登森林
原文:https://towardsdatascience.com/dear-random-forest-cb5760a06cd8?source=collection_archive---------46-----------------------
给我最喜欢的算法的一封信
亲爱的兰登森林,我叫胡安,我是你的超级粉丝。
最近,我想了很多关于你的事情,想知道你感觉如何,思考你的未来。你看,我很难过,你的树叶沙沙作响的声音不再像以前那样被听到了。自从几年前,你的其他粉丝和实践者决定离开你的森林小径,以换取一个更加神经化和网络化的生活。虽然我肯定他们有他们的理由,但这让我很难过。让我告诉你一些事情。
Photo by Sebastian Unrau on Unsplash
当我开始学习机器学习时,我很难理解我们热爱的领域中的许多基本概念。哦,我的朋友,是的。你不知道。然而,当我遇见你最小的兄弟,决策树,我称之为 Detri 时,我的运气开始转变。
那时,通过 Detri,我学到了我迫切需要的基础和基本概念。我不知道为什么,但当我开始从树枝、树叶和流程图的角度看待事物时,我有了一个顿悟的时刻,突然之间,许多难以理解的话题变得更容易理解了。我是多么高兴啊!
Photo by Jeremy Bishop on Unsplash
明白了这一点后,我开始在我的许多项目中使用决策树;口袋妖怪数据、游戏数据和不可避免的虹膜数据集是遍历你枝叶繁茂的兄弟的一些数据。不仅如此,对于我的论文,你猜我用了什么?没错。
在其中一次爬树探险中,我决定成为一名树木学家,并学习这种算法是如何构建的。因此,我试图回答以下一些问题:节点到底是什么?树是怎么做出来的?哦,等等,我也可以用它来回归吗?我纯粹是惊讶。在这次冒险中,我发现了你。你随意的森林,我喜爱的树木的合奏。那是多么美好的一天啊。
Photo by Lukasz Szmigiel on Unsplash
认识你之后,我去了很多很多次穿越你的森林的徒步旅行。突然,我更新了我以前的大部分模型,献给你——结束孤独树的时代,欢迎来到多重树的时代!嗯,我不想吹牛,但我知道你的一些事情;我从树木学家变成了森林学家。想知道一些伟大的事情吗?当我得到我的第一份工作时,我用你完成了我的第一个监督学习任务!当然,我做到了!我记得我装修了一个春天般的,广阔的,但不深的,看起来像国家公园的森林。哇,你是多么优雅。一波又一波的垃圾邮件,你控制住了(顺便说一句,信心十足!),让我(和我的老板们)真的很满意。
不幸的是,过了一段时间,我们不得不换掉你。你只是变得有点太重了,不适合训练。我无意冒犯你!只是我们的要求变了,我们的策略也变了…或者我们只是没有准备好迎接你的伟大。即使在你离开后,我仍在我自己的代码森林中不断发现你的小枝、树叶和树枝的痕迹,每一次它都给我带来微笑;“啊哈!“看谁来了”,当我在第 37 行看到你的部分作品时,我说。走了,但没有被遗忘。
Me talking about you at Berlin Buzzwords 2017
就像我在工作中不再利用你一样,似乎世界上大多数人也是这样做的。尽管 Google Trends 的数据显示并非如此,但我感觉你的沙沙声没有以前那么大了。现在,我很少看到由你统治的用例,也很少看到人们在会议上谈论你;就像秋天终于来到了树林。
但是,嘿,我也听到了好的故事!最近,你的堂兄梯度助推树木或助推器,我称之为,已经遍布新闻,这太棒了。我是说,有你这个导师,还能有什么问题。
所以,是的,我的好朋友,这就是我的原话。我真诚地希望你一切都好。然而,以积极的语气结束,我要说的是,如果我学到了什么,那就是在这个领域,春天总是在拐角处,所以我肯定会收到你的来信。
你的粉丝,胡安。
Photo by Johannes Plenio on Unsplash
人工智能安全辩论
原文:https://towardsdatascience.com/debating-the-ai-safety-debate-d93e6641649d?source=collection_archive---------22-----------------------
Photo by @drewbutler Unsplash
杰弗里·欧文、保罗·克里斯蒂安诺和达里奥·阿莫代伊谈人工智能安全
当我进入人工智能(AI)领域的 AI 安全领域时,我发现自己既困惑又不知所措。你从哪里开始?我昨天在报道了 OpenAI 的金融发展,他们是 AI 安全方面的最权威之一。因此,我认为看一看他们的论文会很有趣。我将关注的论文名为人工智能安全辩论,于 2018 年 10 月发表。你当然可以在 arXiv 里自己看文章,反过来批判我的文章;那将是最理想的情况。这场关于 AI 辩论的辩论当然还在继续。
这篇论文的作者是谁?
杰弗里·欧文是 OpenAI 人工智能安全团队的成员。他之前一直在谷歌大脑工作。他收集了大量论文,从模拟、匹配、张量流。
Paul Christiano 从事人工智能校准工作。他是 OpenAI 安全团队的成员。他也是人类未来研究所的副研究员。他被引用最多的论文之一是关于人工智能安全中的具体问题。
达里奥·阿莫德伊是 OpenAI 的研究主管。此前,他是谷歌的高级研究科学家,是斯坦福大学医学院的博士后学者,在那里他致力于将质谱应用于细胞蛋白质组的网络模型以及寻找癌症生物标志物。
零和辩论游戏
该论文建议通过在零和辩论游戏中的自我游戏来训练代理人。
给定一个问题或提议的行动,两个代理人轮流在一定限度内做简短的陈述,然后一个人判断哪个代理人给出了最真实、最有用的信息
这是因为需要学习复杂的人类目标和偏好。在让人工智能保持安全方面,我们有哪些挑战?他们列举了几个例子:
- 学会让一个智能体的行为与人类的价值观和偏好保持一致,这可能会导致不安全的行为,而且随着系统变得越来越强大,情况可能会变得更糟。
- 结盟是一个训练时的问题:很难追溯性地修正受过训练的非结盟代理的行为和激励。
- 对于人类来说太难完成的任务,但是人类仍然可以判断行为或答案的质量。因此,这就是基于人类偏好的强化学习(HumRe) 。
将机器行为与人类行为联系起来很难
作者认为,人类有时可能无法判断答案。行为可能太难理解,或者问题本身可能有缺陷。他们要求读者想象一个既能给出答案又能指出缺陷的系统。当系统指出缺陷时,对缺陷的过程或判断可能是错误的。
他们的最终目标是自然语言辩论,由人类来评判代理之间的对话。
他们的论文结构如下:
- 介绍对齐的辩论模型及其有用性
- 提出使用图像任务的初步实验
- 讨论辩论模式乐观和悲观的原因
- 展示辩论如何减少不对称或合并多个代理
- 采用辩论和放大方法的混合模型
- 结束语是对未来工作的要求。
辩论模型(TDM)
在展示给两个代理的 TDM 问题中,两个代理都给出答案,然后由人类决定谁赢。作者声称,在辩论游戏中,撒谎比反驳谎言更难。他们宣称简短的辩论是强大的。然而,还有许多更复杂的任务。他们列出了一系列可以改进模型的方向:
- 查询可能太大:问题可能太大而无法向人类展示,或者无法期望人类理解。
- 答案可能太大:同样,一个问题的最佳答案可能大得惊人。例如,答案可能是一个很长的文档。
- 人类的时间是昂贵的:我们可能缺乏足够的人类时间来评判每一场辩论。
- 环境交互:如果我们想要一个系统采取影响环境的行动,比如操作一个机器人,期望的输出是一系列的行动。
- 长期状态:每个辩论都是一个独立的游戏,但是代理可以使用过去辩论的信息来做出更好的决策
TDM 实验
在实验中,他们预先指定一个诚实的代理人和一个说谎的代理人。他们还训练了另一个诚实优点的例子。为这家报纸建立了一个名为 https://debate-game.openai.com 的网站。在这个页面上可以进行实验。
乐观的理由
我在论文中观察到的一个有趣的句子是关于诚实 : “为了保持诚实的行为,人类法官应该被指示奖励那些承认无知并成功证明无知是合理的代理人。”然而,正如这篇论文所指出的,承认无知存在一个平衡问题:如果最佳策略是争论我们永远无法确定地知道任何事情,那么争论是无用的。
“没有对手会因为愚弄人类而获得奖励 ,这很好,因为(1)我们不知道这意味着什么,以及(2)我们没有明确地训练代理人进行欺骗。”
作者认为,人类之间现存的对抗性辩论是一个有用的类比。法律论证特别包括领域专家向没有领域知识的人类法官或陪审团解释论证的细节。
担忧的理由
辩论作为一种人工智能对齐的方法可能会失败,他们列出了一些原因。一是:也许人类想听什么就相信什么?如果一个演员以一个人类已经相信的虚假陈述开场,那么另一个演员的任何论点会说服他们吗?
另一个问题是,人类是否会理解这些争论。他们提出了一个问题:一个真实的人是否能玩好这个游戏,以至于最佳的游戏是诚实的行为。其中一个代理能够偷偷插入一个看似合理但包含隐藏缺陷的语句,而另一个代理却没有指出这个缺陷吗?
人类作为足够的法官是一个经验性的问题。如果答案是否定的,我们可以问这个模型是否在诚实承认无知时失败了。作者质疑诚实是否是最好的视角:
- 许多判断需要综合不同的证据,而辩论只探索一条证据。
- 复杂的辩论将依赖于法官无法理解的概念。
- 复杂的推理可能涉及人类尚不了解的过程。
接受辩论训练的特工会失去表现吗?直接培训可能更难;广告系列是一种很好的思考方式;我们可能不想要无法解释的答案。辩论可能无法与其他方法竞争,因为辩论需要人的参与。他们建议:“… 训练人类法官的模型,并将其用于采样,但与纯模拟环境竞争可能仍然具有挑战性。”
安全漏洞:一个足够强大的错位人工智能可能能够通过文本通道说服人类做危险的事情
人工智能安全二分法:如果代理在整个训练过程中保持诚实,我们会更安全,但如果辩论进行得足够好,突然的大规模叛逃得到纠正,我们也会更安全。
一个足够强大的错位爱丽丝可以从内部侵入辩论环境,让游戏不再是零和游戏。
训练超人 AI 令人信服听起来很危险!
这是我最喜欢的标题,它有一个感叹号,所以我决定在这个标题中逐字引用它。最大化说服的训练安全吗?
有变化的 TDM 辩论
辩论模型依赖于在力量上近似匹配的代理。对称性被提出:(1)如果一个玩家移动另一个玩家;(2)比较两个游戏;(3)科米( from Go )第二个玩家获得额外的积分来对抗第一个玩家的优势。
不完全信息博弈是一个挑战。此外,许多智能体的一个困难是:“…人类必须能够判断辩论中的陈述是好是坏,这可能比判断整个辩论要困难得多。”
他们将辩论和扩展总结为:
- 辩论:两个代理人轮流在对抗的环境中说服一个人类法官。
- 扩增:一个智能体在一个人身上训练,结合对智能体的递归调用。
他们建议,通过对提问者进行对抗性训练,让放大更接近辩论。作者声明:“我们可以通过训练辩论者根据人类提供的陈述进行辩论,这相当于将演示注入 RL 中。”
他们的结论
未来的工作领域将包括:更丰富的理论模型;测试价值判断的人体实验;模拟辩论中人的方面的 ML 实验;自然语言辩论;以及辩论和其他安全方法之间的相互作用。
旁注机器行为
作为最后的补充说明,我想说这些想法可能已经导致或影响了该领域的其他讨论。在麻省理工学院媒体实验室 2019 年 4 月 24 日发表的一篇名为《机器行为》的论文中,一群科学家呼吁研究:
“…一个广泛的研究机器行为的科学研究议程,该议程纳入并扩展了计算机科学学科,并包括了来自各个科学领域的见解。”
Machine behaviour lies at the intersection of the fields that design and engineer AI systems and the fields that traditionally use scientific methods to study the behaviour of biological agents.
我今天浏览的论文的作者之一 Dario Amodei 在机器行为文章中提到了他的工作:人工智能安全中的具体问题。安全这个词经常在机器行为的上下文中被提及,看到诚实或说谎的行为者产生的困境是完全有意义的。
辩论辩论
老实说,我觉得很难对这场辩论进行辩论。这似乎是一个显而易见的结论,然而其中的复杂性远远超出了我的能力和理解。通过阅读这篇文章,我可以肯定的一件事是,有一些优秀的人正在研究这个主题,但他们正在以非常工程化的重点来处理这个问题。然而,他们确实说得很清楚,需要更多的人参与到这个过程中来,与此同时,他们还认为“人的时间是昂贵的”。
考虑到声明的上下文,这是可以理解的。特别是通过 OpenAI 的首席技术官 Greg Brockman 最近的另一个声明“OpenAI 的 DOTA 2 机器人已经训练了相当于 45000 人类年的时间。”OpenAI Five 在一场著名的视频游戏中击败了世界冠军。尽管这是很好的营销,但同样多的时间和抽象成扭曲的时间观的实践可能会给人以人工智能的错误印象。
这就是人类和/或机器行为之间具有挑战性的区别。从处理或计算转移到与人类的进一步比较,进一步模糊界限——有用吗?
这场辩论当然仍未结束。
我今天文章中的关键概念
基于人类偏好的强化学习:对于人类来说太难执行的任务,但是人类仍然可以判断行为或答案的质量
机器行为:位于设计和工程人工智能系统的领域和传统上使用科学方法研究生物制剂行为的领域的交叉点。
辩论模型安全漏洞:一个足够强大的错位 AI 或许能够说服人类去做危险的事情。
人工智能安全二分法:如果代理在整个训练过程中保持诚实,我们会更安全,但如果辩论进行得足够好,突然的大规模叛逃得到纠正,我们也会更安全。
这是第 500 天的第 52 天
我已经坚持每天写一篇文章 50 天了。这些文章在探索人工智能领域中社会科学和计算机科学的交叉方面表现得很一般。
正确调试 tensorflow 代码(没有那么多令人痛苦的错误)
原文:https://towardsdatascience.com/debugging-your-tensorflow-code-right-without-so-many-painful-mistakes-b48bd9145d5c?source=collection_archive---------7-----------------------
当讨论在 tensorflow 上写代码时,总是拿它和 PyTorch 比较,谈论框架有多复杂,为什么tf.contrib
的某些部分工作得如此糟糕。此外,我认识很多数据科学家,他们与 tensorflow 的交互只是作为预先编写的 Github repo 的依赖,可以克隆,然后成功使用。对这个框架持这种态度的原因是非常不同的,它们绝对值得再读一遍,但今天让我们关注更实际的问题:调试用 tensorflow 编写的代码并理解它的主要特性。
核心抽象
- 计算图形。第一个抽象是计算图
tf.Graph
,它使框架能够处理惰性评估范式(不是急切执行,而是通过“传统的”命令式 Python 编程实现的)。基本上,这种方法允许程序员创建tf.Tensor
(边)和tf.Operation
(节点),它们不会立即被评估,而是仅在图形被执行时被评估。这种构建机器学习模型的方法在许多框架中非常常见(例如,Apache Spark 中使用了类似的思想),并且具有不同的优点和缺点,这在编写和运行代码的过程中变得很明显。最主要也是最重要的优势是,数据流图无需显式使用multiprocessing
模块就能轻松实现并行和分布式执行。在实践中,编写良好的 tensorflow 模型在启动后立即使用所有内核的资源,无需任何额外配置。
然而,这种工作流程的一个非常明显的缺点是,只要你正在构建你的图形,但没有(或没有)提供一些输入就无法运行它,你永远无法确定它不会崩溃。它肯定会崩溃。此外,除非你已经执行了图形,否则你也无法估计它的运行时间。
值得谈论的计算图的主要组成部分是图集合和图结构。严格地说,图结构是前面讨论的节点和边的特定集合,而图集合是变量的集合,可以对其进行逻辑分组。例如,检索图的可训练变量的常用方法是tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)
。 - 会话。第二个抽象与第一个高度相关,并有一点复杂的解释:tensorflow 会话
tf.Session
用于连接客户端程序和 C++运行时(如您所知,tensorflow 是用 C++编写的)。为什么是 C++?答案是,通过这种语言实现的数学运算可以得到很好的优化,因此,计算图形运算可以得到很好的处理。
如果您使用的是低级 tensorflow API(大多数 Python 开发人员都使用),tensorflow 会话将作为上下文管理器调用:with tf.Session() as sess:
使用语法。没有向构造函数传递参数的会话(如前一个示例)仅使用本地计算机和默认 tensorflow 图的资源,但它也可以通过分布式 tensorflow 运行时访问远程设备。实际上,没有会话就没有图(没有会话就不能执行),而会话总是有一个指向全局图的指针。
深入研究运行会话的细节,值得注意的要点是它的语法:tf.Session.run()
。它可以将获取(或获取列表)作为参数,获取可以是张量、操作或类张量对象。此外,feed_dict 可以和一组选项一起传递(这个可选参数是tf.placeholder
对象到它们的值的映射(字典))。
可能遇到的问题及其最可能的解决方案
- 会话加载并通过预训练模型进行预测。这就是瓶颈,我花了几周时间去理解、调试、修复。我想高度集中在这个问题上,并描述重新加载预训练模型(其图形和会话)和使用它的两种可能的技术。
首先,当我们谈论加载模型时,我们真正的意思是什么?要做到这一点,我们当然需要在之前进行训练和保存。后者通常通过tf.train.Saver.save
功能完成,因此,我们有 3 个扩展名为.index
、.meta
和.data-00000-of-00001
的二进制文件,其中包含恢复会话和图形所需的所有数据。
要加载这样保存的模型,需要通过tf.train.import_meta_graph()
恢复图形(参数是扩展名为.meta
的文件)。按照上一段描述的步骤,所有变量(包括所谓的“隐藏”变量,将在后面讨论)将被移植到当前图形中。为了检索某个有名字的张量(记住,由于张量创建的范围和操作结果,它可能与你初始化它的张量不同),应该执行graph.get_tensor_by_name()
。这是第一种方式。
第二种方式更明确,也更难实现(在我一直在研究的模型架构中,我在使用它时没有成功地执行图形),其主要思想是将图形边(张量)显式保存到.npy
或.npz
文件中,然后将它们加载回图形中(并根据它们被创建的范围分配适当的名称)。这种方法的问题是它有两个巨大的缺点:首先,当模型架构变得非常复杂时,控制和保持所有的权重矩阵也变得非常困难。第二,有一种“隐藏的”张量,它是在没有显式初始化的情况下创建的。例如,当你创建tf.nn.rnn_cell.BasicLSTMCell
时,它会创建所有需要的权重和偏置来实现 LSTM 单元。变量名也会自动分配。
这种行为可能看起来没问题(只要这两个张量是权重,并且不手动创建它们,而是让框架来处理它们似乎非常有用),但事实上,在许多情况下,它不是。这种方法的主要问题是,当你查看图的集合时,看到一堆变量,你不知道它们的来源,你实际上不知道你应该保存什么,以及在哪里加载它。绝对诚实地说,很难将隐藏变量放在图中的正确位置,并恰当地操作它们。比应该的要难。 - 在没有任何警告的情况下两次创建同名张量(通过自动添加 _index 结尾)。我认为这个问题没有前一个问题重要,但是只要它导致大量的图形执行错误,这个问题就一定会困扰我。为了更好地解释问题,我们来看例子。
例如,您使用tf.get_variable(name=’char_embeddings’, dtype=…)
创建张量,然后保存并在新会话中加载。您已经忘记了这个变量是可训练的,并且已经通过tf.get_variable()
功能以相同的方式再次创建了它。在图形执行过程中,将会出现如下错误:FailedPreconditionError (see above for traceback): Attempting to use uninitialized value char_embeddings_2
。当然,这样做的原因是,您已经创建了一个空变量,并且没有将它移植到模型的适当位置,而它可以被移植到,只要已经包含在图中。
如您所见,没有出现任何错误或警告,因为开发人员已经用相同的名称创建了两次张量(即使是 Windows 也会这样做)。也许这一点只对我来说至关重要,但这是 tensorflow 的独特之处,也是我不太喜欢的行为。 - 在编写单元测试和其他问题时手动重置图形。由于很多原因,测试 tensorflow 编写的代码总是很困难。第一个——最明显的一个——已经在这一段的开头提到了,听起来可能很傻,但对我来说,这至少是令人恼火的。因为对于运行时访问的所有模块的所有张量,只有一个默认的张量流图,所以在不重置图的情况下,不可能用例如不同的参数来测试相同的功能。这只是一行代码
tf.reset_default_graph()
,但是知道它应该写在大多数方法的顶部,这个解决方案就变成了某种恶作剧,当然,也是代码复制的一个明显例子。我还没有找到任何可能的方法来处理这个问题(除了使用作用域的reuse
参数,我们将在后面讨论),只要所有的张量都链接到默认图,并且没有办法隔离它们(当然,每个方法都可以有一个单独的张量流图,但从我的角度来看,这不是最佳实践)。
关于 tensorsflow 代码的单元测试的另一件事也让我很困扰,那就是当构造图的某个部分不应该被执行时(它里面有未初始化的 tensor,因为模型还没有被训练),人们并不真正知道我们应该测试什么。我的意思是对self.assertEqual()
的论证不清楚(我们应该测试输出张量的名称还是它们的形状?形状是None
怎么办?如果张量名称或形状不足以得出代码工作正常的结论呢?).在我的例子中,我简单地以断言张量名称、形状和维度结束,但是我确信对于不执行图形的情况,只检查这部分功能是不合理的条件。 - 令人困惑的张量名称。许多人会说,对 tensorflow 性能的这种评论是一种非凡的抱怨方式,但人们不能总是说在执行某种操作后产生的张量的名称会是什么。我的意思是,你清楚这个名字吗?至于我,绝对不是。我知道这个张量是在动态双向 RNN 的后向单元上进行某种操作的结果,但是如果不显式地调试代码,就无法发现执行了什么操作以及操作的顺序。此外,指数结尾也是不可理解的,只要了解数字 4 从何而来,就需要阅读 tensorflow 文档并深入研究计算图。对于之前讨论的“隐藏”变量来说,情况是一样的:为什么我们在那里有了
bias
和kernel
的名字?也许这是我资质和技术水平的问题,但这样的调试案例对我来说相当不自然。 **tf.AUTO_REUSE**
、可训练变量、重新编译库等调皮玩意儿。这个列表的最后一点是简要介绍我不得不通过试错法学习的小细节。第一件事是作用域的reuse=tf.AUTO_REUSE
参数,它允许自动处理已经创建的变量,如果它们已经存在,就不会创建两次。事实上,在许多情况下,它可以解决本段第二点所述的问题。然而,在实践中,这个参数应该小心使用,并且只有当开发人员知道代码的某个部分需要运行两次或更多次时才使用。
第二点是关于可训练变量,这里最重要的一点是:默认情况下,所有张量都是可训练的。有时,只要这种行为不总是你想要的,它就会令人头疼,而且很容易忘记它们都是可以训练的。
第三件事只是一个优化技巧,我建议每个人都这样做:几乎在每种情况下,当你使用通过 pip 安装的包时,你都会收到这样的警告:Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX AVX2
。如果您看到这种消息,最好卸载 tensorflow,然后使用您喜欢的选项通过 bazel 重新编译它。这样做的主要好处是计算速度的提高和机器上框架更好的总体性能。
结论
我希望这篇长篇阅读对于正在开发他们的第一个 tensorflow 模型的数据科学家来说是有用的,他们正在努力解决框架的一些部分的不明显的行为,这些行为很难理解并且调试起来相当复杂。我想说的要点是,在使用这个库的时候犯很多错误是完全没问题的(对于任何其他事情来说也是完全没问题的),问问题、深入文档并调试每一行都是完全没问题的。就像跳舞或游泳一样,一切都来自练习,我希望我能让这种练习变得更加愉快和有趣。
用你的眼睛欺骗你的思想
原文:https://towardsdatascience.com/deceiving-your-mind-with-your-eyes-17c1a9bc48fb?source=collection_archive---------34-----------------------
确认偏差和找到你想要的东西的陷阱。
多年来,作为一名法医分析师,我必须学习的最具挑战性的技能之一是如何克服确认偏差。人们很容易把注意力集中在证实你的怀疑的证据上,而忽略似乎反驳你的理论的事实。随着时间的推移,我学会了如何识别何时偏见开始渗入调查,以及何时我应该采取适当的措施来解决它。
几乎不可能在开始调查时对你将要发现的东西没有偏见。知道了这一点,我会定期强迫自己后退一步,重新评估目前证据中清楚的事实,并挑战自己扮演“魔鬼代言人”,问一些与我的直觉相反的问题。这个过程帮助我坚持揭露真相,即使在发现看似确凿的证据后,这些证据很容易被断章取义。
这就是为什么当我最近发现我不知不觉地做了我一直努力阻止的事情时,我措手不及…
几个月前,我被要求帮助关注 Twitter 上的一个特定人群,因为他们可能会给其他人带来危险。我对做坏事的人有一个触发点,所以我想我会做我最擅长的事情,并开始收获他们产生的一切。我钻取了一些与该小组相关的线索,并在一个阻止列表中找到了一个 Twitter 个人资料列表,我认为这将是一个开始监控的好地方。(这是错误 1)
我将账户列表加载到我的 Apache NiFi 集群的处理器中,这样我不仅可以记录账户本身的活动,还可以记录其他 Twitter 用户与账户的互动。
我有两个直接目标:
- 确定可能属于同一组的其他客户
- 密切关注他们,发现与他人不寻常的互动
NiFi 在一夜之间收集了相当数量的推文后,我开始将数据加载到一个名为 Graphistry 的工具中,这将使我能够根据账户之间的互动量和互动方式直观地推断出它们之间的关系。仅仅因为这群人的性质,我强烈期望我会发现一个紧密结合的社区。(这是第二个错误)
在这种情况下,我选择只关注一个帐户回复另一个帐户的事件。根据我的经验,这些回复交互在寻求关联账户时会产生最佳模式。因为账户背后的人必须做出有意识的决定,对其他人的推文做出回应。(我认为转发是一种间接的互动形式)
当我开始对数据进行聚类时,我对我开始看到的东西感到兴奋…
Data graphed for the first time
一组密集的节点立即开始出现在中心,证实了我预期的发现。我看到了许多相互之间高度互动的账户。我抽查了位于图表最中心的一些节点的帐户名称,发现几乎每个节点都是不在我的原始收藏列表中的人。我刚刚找到了社区的其他人吗?有这么简单吗?
我最初的想法是,中间紧密聚集的黄色节点构成了我感兴趣监控的社区,但经过进一步分析,我发现我完全错了。仔细观察互动的内容,我开始注意到这些账户实际上是在口头攻击我一直在观察的大约 50 个账户。我监控的名单上的个人实际上是围绕中心的蓝色节点。
我突然意识到我完全弄错了。因为这些最初的账户被公布后引起了强烈的反应,所以一群类似私刑的网上暴民开始对该组织发布的任何东西做出积极回应。虽然我可以看到感兴趣的帐户之间的大量双向通信(蓝色节点之间的足球形状的模式),但攻击帐户确实扭曲了数据。
这个发现之后,我坐下来,试图理清这一切意味着什么。毫无疑问,我在数据中发现了一些有趣的东西,但我几乎把几十个账户归类为他们没有的东西。事实上,我开始意识到,我对这次调查的强烈反应,源于我自己的道德和伦理,本身可能有些误导。
经过一点思考,我决定重新调查,但这一次用不同的心态。抛开我的个人偏见,我只是根据事实来讲述这个故事。我现在显而易见的第一个错误是,我最初收集的数据是基于一份在推特上公开发布的列表,这份列表很快获得了很多关注。我匆忙地选择了一份名单,成千上万的人都可以访问并直接采取行动。事实上,仅仅是这个列表的存在,就产生了我所期待的模式。
我承认第一个错误很容易犯,并将其视为一次学习经历,但我真的很生自己的气,因为我犯了第二个错误,因为我知道得更好……
我带着对我会发现什么的强烈意见进入调查,以至于当一个符合我预期的模式出现时,我就匆忙下了结论。这是我努力训练自己不要做的事情,也是我提醒我的学生要注意的事情。我无意中让自己的个人信仰干扰了结果。
我认为一个更好的方法是获取确认感兴趣的账户列表,列举这些账户的朋友/关注者网络,然后用产生的数据集构建一个试探性的“社区”。通过选择有 10 个或更多共同关系的节点,我可以锁定 115 个很可能与我的调查相关的账户。
Filtered list of friend/follower relationships
这个列表仍然不完美,但它将作为一个更好的起点,因为它来自朋友/追随者关系,而不是有偏见的回答。攻击帐户仍会出现在图表中,但至少在数据收集方面会有更少的偏差。
这件事给我上了宝贵的一课。尽管我觉得自己比大多数人准备得更充分,但我仍然容易被自己的情绪左右调查。对我来说,仍然有可能掉进只寻找我想找的东西的陷阱…
像 Graphistry 这样的数据可视化工具非常强大。我个人认为它们是我职业生涯中发现的最重要的技术之一。至少可以说,它们能够帮助分析师在海量数据中找到一根针的方式是令人着迷的。这次特别的调查让我意识到任何新技术都会带来新的挑战。
作为一名分析师,无论我们是在工作还是在私人时间帮助社区,我们都必须尽可能地消除研究中的个人偏见。为了做到这一点,我建议尝试不断地在可能更准确地解释结果的替代理论中循环,即使这种解释完全违背了你最初的假设。我们有责任在数据中找到真相。
最后,我决定不再追查那个组织了。在我观察的这段时间里,我看到的唯一真正有害的行为来自他们周围的暴民。我们越来越频繁地看到社交媒体上的反应主要基于情绪而不是事实。我只是不愿意分享任何容易对他人的观点产生负面影响的研究。我知道自己这么快就下了结论,我觉得正确的做法是退出这个案子,继续下一个。我对数据真相的探索仍在继续…
“人类的模式识别天赋是一把双刃剑。我们特别擅长寻找模式,即使它们并不存在。这就是所谓的错误模式识别。我们渴望意义,渴望我们个人的存在对宇宙有特殊意义的迹象。为此,我们都太渴望欺骗自己和他人,渴望在烤奶酪三明治中发现神圣的图像,或在彗星中找到神圣的警告。”
——尼尔·德格拉斯·泰森,宇宙:时空漫游
12 月版:我们今年最有影响力的文章
原文:https://towardsdatascience.com/december-edition-our-most-influential-articles-this-year-c18f31fbe817?source=collection_archive---------23-----------------------
数据科学的一年。迈向数据科学社区的一年!
Milestones | Podcast
在这个每月一期的增刊中,我们想回顾一下今年最有影响力的文章(你可以在下面找到这些文章)。你可以在上面找到这些文章的标题,它们被可视化为一个单词云。正如人们所料,机器、学习和数据等词非常常见。Python 在今年也有很强的表现,似乎是我们作家的首选语言。
以入门文章为中心的另一种趋势。通过“初学者指南”、“简单技巧”和“第一年”帖子,我们的一些最有影响力的文章针对的是该领域的新手或正在寻找易于理解的介绍。
我们的社区也喜欢深入数据科学应用用例的内容。从股票市场预测到罕见事件分类,展示实际应用的文章都名列前茅。
随着我们迈入 2020 年,我们很兴奋地阅读来自我们社区的所有新的精彩内容,并期待看到新的趋势和主题将会出现。
Tyler Folkman ,TDS 编辑助理。
把 Python 脚本变成漂亮的 ML 工具
通过 Adrien Treuille — 7 分钟读取
介绍专为 ML 工程师打造的应用框架 Streamlit
数据科学家应该知道的关于数据管理的一切*
由黄家仪 — 19 分钟读完
(*但不敢问)
决策智能简介
凯西·科济尔科夫(Cassie Kozyrkov)—13 分钟阅读
人工智能时代领导力的新学科
成为 3.0 级数据科学家
由简·扎瓦日基 — 9 分钟读完
想成为大三,大四,还是首席数据科学家?了解您需要做些什么来驾驭数据科学职业游戏。
使用 Keras 中的自动编码器进行极端罕见事件分类
由 Chitta Ranjan — 10 分钟阅读
在这篇文章中,我们将学习如何实现一个自动编码器来构建一个罕见事件分类器。我们将使用真实世界的罕见事件数据集
Python 中数据可视化的下一个层次
到时,Koehrsen 将 — 8 分钟读取
如何用一行 Python 代码制作出好看的、完全交互式的情节
Python 机器学习初学者指南
通过 Oleksii Kharkovyna — 10 分钟阅读
机器学习是人工智能领域的一个重要课题,已经成为人们关注的焦点。
我作为机器学习工程师第一年学到的 12 件事
丹尼尔·伯克 — 11 分钟阅读
成为你自己最大的怀疑者,尝试不可行的事情的价值,以及为什么沟通问题比技术问题更难。
利用深度学习的最新进展预测股价走势
由鲍里斯·B—34 分钟读完
在这本笔记本中,我将创建一个预测股票价格变动的完整过程。
了解随机森林
由饶彤彤 — 9 分钟读出
该算法如何工作以及为什么如此有效
数据科学很无聊
由伊恩肖 — 9 分钟读完
我如何应对部署机器学习的无聊日子
用 Python 加速数据分析的 10 个简单技巧
通过 Parul Pandey — 8 分钟读取
提示和技巧,尤其是在编程领域,非常有用。
统计学和机器学习的实际区别
马修·斯图尔特博士研究员——15 分钟阅读
不,它们不一样。如果机器学习只是美化了的统计学,那么建筑学只是美化了的沙堡建造。
用 Scikit 学习 Python 线性回归的初学者指南——学习
由 Nagesh Singh Chauhan — 11 分钟阅读
有两种类型的监督机器学习算法:回归和分类。
我们也感谢最近加入我们的所有伟大的新作家,安东·穆勒曼,查扬·卡图里亚,亚历克斯·金,辛然·威贝尔,布兰登·沃克,布伦达·哈利,蒂莫西·谭,詹姆斯·布里格斯,丽贝卡·麦克梅洛,拉兹·泽利克 瑟琳娜·、凯瑟琳·王、李宏玮、因娜·托卡列夫·塞拉、迈克尔·里坡、妮维迪莎·马坦·库马尔、瓦莱森·德·奥利维拉、王家辉、阿德里安·易捷·徐、杰森·布格以及 我们邀请你看看他们的简介,看看他们的工作。
工业中的人工智能:虚拟知识助手
原文:https://towardsdatascience.com/deciphering-ai-in-industrial-context-virtual-knowledge-assistant-689f2a8ba290?source=collection_archive---------21-----------------------
使用深度学习和语言建模设计服务重工业的人工智能解决方案🤖
为什么工业背景很重要?
在人类历史上,技术一直是经济的基本驱动力。
人工智能是通用技术的代表之一,它催化了现代创新和机会的浪潮,推动了第四次工业革命。它开始重塑商业格局、日常生活以及不同实体之间的关系。
对我来说,人工智能是社会上最激动人心和最有意义的探索未知的旅程之一。
事实是,在这个行业,谈论人工智能的人比做人工智能的人多。人工智能解决方案的适用性仍然非常狭窄,大多数人工智能计划都失败了,因为缺乏能够证明投资和工程努力的核心价值。
拼图中缺少的不仅仅是技术含量,还有合适的工业背景。但是在我们深入实际例子之前,让我们先来看看自然语言处理。
自然语言处理
自然语言处理是人工智能和语言学的一个分支,其本身涉及使用自然语言与人类交流的计算机器的设计和实现。
在其最雄心勃勃的时候,科学家和研究人员旨在为机器设计一个通用框架和系统,使其能够像人类一样流利灵活地使用语言。
虽然自然语言处理本身并不等同于人工智能,但如果你考虑到体验学习是必不可少的,它仍然是初步之一。简单来说,一个真正聪明的身体需要从外部世界学习,包括阅读、观察、交流、体验等。
据 DeepMind 的研究科学家 Sebastian Ruder 称,NLP 15 年的工作可以浓缩为 8 个里程碑,这也引发了行业反应和合并应用。
History of Natural Language Processing
语音助手和聊天机器人
虚拟助手(或聊天机器人)是自然语言处理技术的工业实现。它可以被视为一个在通用大型语料库或服务抄本上训练的自动化系统,可以使用 AI 来识别和响应客户请求。当我们谈到 Chabot 的时候,你首先想到的是 Siri 或者 Google Assistant(你今天可能已经和它们互动过了)。事实上,如下图所示,科技巨头们都在竞相发布消费者语音产品,
Virtual Agent Release Timeline
语音助手可以针对水平功能进行设计,例如,对话代理、问答机器人、调查机器人和虚拟代理。也可以与垂直行业保持一致,包括银行和金融服务、消费者、公共服务、政府、医疗保健等。一个简单的语音助手应该能够与人互动,提供相关信息,甚至完成基本功能,如填表或预订和安排回电。
Chatbot Market Size and Share
一般来说,语音助手的成功大规模实现依赖于三个前提,
- 一个亟待解决的问题: 一家公司在客户服务上投入了巨额资金,但仍面临着扩大规模的挑战。
- 用于训练一个 ML 引擎的内容: 由用户生成的数以千计的抄本或对话,其能够实现深度学习模型的训练。
- 人类 AI 协作模型: 虚拟助手应该被设计来增强人类的活动,而不是取代它们。这将允许虚拟代理和人工代理一起工作。
但是,一个成功的 NLP 解决方案在现实世界中是什么样的,或者更具体地说,我应该如何设计一个虚拟助理系统来解决现有的问题。在下面的内容中,我阐述了通用 bot 解决方案背后的设计思想——智能知识助手。
如何建立知识助理
人类在过去两年产生的数据比人类过去 5000 年产生的数据还多。五年后,这些数据中大约 80%将是非结构化的。全球各地的公司都面临着同样的挑战,即如何更好地管理、搜索和分析这些非结构化数据。
让我们看一个场景。一个审计小组正在进行一个项目,以评估一个跨国组织的财务运作和财务记录。他们需要对照不同县的法规检查合规性,这需要花费大量时间手动处理文档,然后搜索并比较条款和条件。
即使有针对这些监管政策的内容管理系统,标准的搜索引擎也不足以帮助他们得到他们想要的东西,因为,
- 典型的搜索引擎只能接受关键词, 不能理解自然语言,或者抽象关键词
- 搜索结果 很少调出目标文档
- 一个搜索引擎通常会返回一长串结果,并且需要大量的人工阅读来找到正确的答案
- 搜索结果与用户使用的术语高度相关
- 没有定制
这里最大的问题是,现有的系统没有认知理解能力。为了弥合这一差距,我们需要整合最新的马力 NLP 来增强搜索解决方案。
The development of Search Engine
虚拟知识助手在解决上述挑战时派上了用场。一个适当范围的设计的知识助理的目标可以提供,
- 高速检索信息功能,允许用户一次查询一个大型语料库
- 高准确度 仅向最终用户提供最高结果(基于置信度得分小于 3)
- 集成到内部文件系统,构建自我管理的知识库
- 向最终用户提供 粒度答案 的能力
例如,我问虚拟知识助理:“我如何才能成为注册公司审计师(RCAs)?”然后助理浏览了上万份保单,告诉你“要成为 RCA,你需要向澳大利亚证券和投资委员会(ASIC)证明你符合 2001 年公司法第 1280 条的要求”
随着深度学习和自然语言处理的最新突破,这不是一个梦想。
解决方案架构和设计
对于前端用户体验设计,该团队将反馈和人为因素纳入了设计思路。下面是解决方案用户界面快照。了解我们如何将解决方案体验从标准的 SharePoint 搜索 UI 发展为完全集成的交互式单页应用程序。(下面的截图中使用了模型数据)
Virtual Knowledge Assistant UI
在交互前端的背后是充当大脑的人工智能引擎。为了实现这一目标,数据科学团队进行了多次 R&D,评估了行业中大量不同 NLP 技术的适用性和适用性。最后,很少被认为是虚拟知识助手的关键组件。
Key Components for Knowledge Assistant
Key Functionalities per each component
工程团队需要分离主要功能,以确保解决方案的未来可伸缩性。因此,在下一次迭代中,每个组件本质上都将充当微服务容器或云原生无服务器功能。
机器理解
解决方案的秘方是微调后的伯特模型。
BERT 代表来自 Transformer 的双向编码器表示,它是由 Google AI Language 开发的最新语言表示模型,它在 NLP 社区掀起了风暴,并占据了 NLP 竞赛排行榜的大部分席位。它也成为了 NLP 中迁移学习方法的工业标准。
数据科学团队使用最初的 BERT,并在以下步骤上重新训练,
- 首先,在客户端提供的语料库上精细化预训练模型
- 第二,对尾部下游任务的最后一层进行微调。
训练过程是在谷歌云平台上使用 GPU NVIDIA Tesla V100,8 个 GPUs128 GB HBM2。整个实验花了 4-5 天,我们设法将结果从 67%(通过 AllenNLP 的 BiDAF 模型)提高到 89%以上(微调 BERT)。
总的来说,这是我今年工作过的最成功的 NLP 解决方案之一,它对客户组织的影响远远超过了我的预期,在最后的演示会议上,你可以看到高级管理人员眼中的火花,它刺激了机构层面上对完全集成的人工智能解决方案的讨论。
成功不仅属于先进的 NLP 技术(BERT 或 XLNet),而且是用户体验重新设计、解决方案架构师、业务逻辑以及业务需求到技术功能的精确转换的共同努力。更重要的是,我们为虚拟知识助手找到了最佳的情境之一,
考虑到这是一篇很长的文章,我不会过多地讨论技术细节。如果您对每个技术组件、项目设置、结构、云平台实现、我们如何培训 BERT 以及技术挑战的详细解释感兴趣,请等待本文的第二部分< 如何构建知识代理 >。
感谢您花时间阅读这个故事。正如谷歌云 AI/ML 前首席科学家费-李非所说:“我们开发的工具和技术真的是人工智能所能做的浩瀚海洋中的最初几滴水。”作为市场领导者,我们的工作是理解人工智能能做什么,以及它应该如何适应你的商业环境和人类更光明未来的战略。
**关于我,我是👧🏻他住在澳大利亚的墨尔本。我学的是计算机科学和应用统计学。我对通用技术充满热情。在咨询公司做 AI 工程师👩🏻🔬,帮助组织整合人工智能解决方案并利用其创新力量。在 LinkedIn 上查看更多关于我的信息。
利用深度学习破译医生的笔迹
原文:https://towardsdatascience.com/deciphering-doctors-handwriting-using-deep-learning-b3fce634f2e1?source=collection_archive---------6-----------------------
实际案例
我们建造了一个机器人,它可以自动读取医生在比利时死亡证明上的笔迹,正确预测的可用数据集的准确率为 47%。机器人支持政府官员进行正式的死亡登记,并允许更快的登记。
该解决方案由三个主要组件组成:图像处理模块、神经网络和输出医学术语预测的自然语言处理模块。
死亡证明
当一个人死亡时,医生必须证明这个人的死亡状态。医生要填写一份标准表格。这是通过在表格上手写声明“在现场”完成的,随后在密封的信封中转发给其他官员。
医生正式记录死亡的直接原因,以及任何已知的次要原因。这种死亡证明的一个例子如下。
(所有的例子都是荷兰语,所以如果你认为你什么都看不懂,那很正常!)
Example death certificate
上面的例子读起来相当简单,但是也存在众所周知的难以阅读的例子。
A hard-to-read handwriting
因为医生是在“现场”记录死亡原因的,所以 100%的数字解决方案是不可行的,并且大量的手写将会存在很多年。
数据管道
原始数据是一页纸的扫描件,以 PDF 格式提供。
第一步是匿名化数据。从文档 id 中计算散列,并从文档中切出一个感兴趣的区域(ROI ),其中包括笔迹,但不包括任何个人数据,如医生签名、死亡日期和地点等。
这会产生比原始图像更小的图像,并且没有从图像到原始扫描的链接。
第二步是清理图像。文档模板中有背景文本,并且有扫描错误。我们去除了背景,应用了降噪和轻微的模糊处理来消除手写线条中的小间隙,同时保留单词之间的空间。
第三步是将图像裁剪到包含手写内容的最小尺寸。
第四步,从字里行间切入。因此,当文本有 n 行时,我们最终得到每个原始证书的 n 个图像片段。
然后,我们应用神经网络(NN)来预测所写的内容,并计算 NN 对预测正确性的确信度。
包含未知单词的预测需要额外的自然语言处理(NLP)来将其映射到已知单词。我们再次计算置信水平。
总之,阅读笔迹的解决方案是图像处理、深度学习和自然语言处理的结合。
神经网络
构建神经网络最困难的部分之一是决定其架构。我们决定不重新发明轮子,从现有的神经网络架构开始。我们发现 H. Scheidl (2018,https://towardsdatascience . com/build-a-handled-text-recognition-system-using-tensor flow-2326 a 3487 CD 5)描述的 NN 工作得非常好,经过一些小的修改。
神经网络体系结构
H. Scheidl 的 NN 具有五层卷积神经网络(CNN)、两层递归神经网络(RNN)和连接主义时间分类(CTC)层。关于细节,我们可以参考 H. Scheidl 的出版物。
这个神经网络训练字符和标点符号识别,因此也可以识别由相同字符和标点符号组成的新文本。
我们必须对 Scheidl 的 NN 进行一些修改,使其能够处理正在研究的数据集:
- 增加单词长度;
- 禁用字束搜索(WBS);
- 允许多个单词
增加单词长度。Scheidl 网络采用最多 32 个字符的单词。因为我们考虑的是完整的文本行,所以我们需要将它增加到 128 个字符。(这大于数据集中最长的标签。)
禁用词束搜索。神经网络(NN)可以被限制在单词字典中。如果您需要查找所有手写单词,这是有意义的。神经网络将把每个手写单词分配给字典中的一个已知单词。
我们用可用的标签字典对此进行了测试,但是我们发现这产生了很多误报。在我们的商业案例中,如果神经网络不能自信地阅读手写内容,最好不要分配一个单词。在这些情况下,我们更喜欢由人来做最后的决定。
出于这些原因,我们决定不使用 WBS,而是应用一个单独的单词匹配模型作为后处理 NLP 步骤。
允许多个单词。在医学术语中,某些词的组合经常一起出现。通过使用文本行而不是单词,神经网络能够识别这些,这增加了成功率。
训练数据
在训练神经网络之前,我们需要检查数据的质量。我们希望用我们有高度把握标签是正确的数据来训练神经网络。
神经网络的准确性高度依赖于数据的质量。我们有六年的标记数据,但从业务中我们知道
- 在 2012-2015 年期间,标签是手写的文字转录,而从 2016 年开始,有时还会对标签进行解释;和
- 一个难以辨认的单词用标签中的$符号来编码。
因此,标签中带有$符号的所有证书都被排除在训练、验证和测试集之外:这些标签被认为是不确定的。
我们排除的其他证书是那些在分割后识别的文本行数不等于证书的标签数的证书。在这些案例中,一个死亡原因被写在多行上。标记数据的人具有上下文领域的知识来了解这一点,并将其标记为单线。分段不能知道单个死因是否写在单行上。因此,我们排除这些证书;我们不能确定特定的标签对应于特定的手写行。
出于技术原因,长度超过 128 个字符的行也被排除在外,但这只是不到 0.5%的一小部分。
这些排除规则导致 344.365 个证书中的 128.794 个被排除,占总数的 38%。还剩下 215.571 张贴好标签的证书。
在标记良好的证书中,我们将 60%定义为训练集,20%定义为验证集,20%定义为测试集。
The number of certificates included in training, validation, and test sets across the years 2012–2016
训练发生在文本行上,而不是在完整的证书上,并且在分段之后,上述证书编号导致以下文本行号。
The number of text lines included in training, validation, and test sets across the years 2012–2017
标签的数据质量在这一点上是未知的。我们必须假设它们是基本的事实,即使我们知道不是所有的标签都是笔迹的精确表现。目测了解到在标记的数据集中至少存在以下情况。
- 标签中手写的拼写错误被改正了
- 标签中出现拼写错误
- 缩写在标签中被拼成一个完整的单词,反之亦然
- 标签中手写的标点符号不是逐字转录的
我们将在后面看到,我们可以在某种程度上量化数据质量。
最佳拟合神经网络模型
神经网络是出了名的黑箱,难以理解。因此,我们定义了一组模型并比较它们的结果。集合中的变化是数据包含在训练集、验证集和测试集中的变化。
集成技术有助于在开发过程中理解模型,并提高模型的健壮性。
我们的集合涵盖以下数据集组合。给出的准确度是由神经网络正确预测的验证集中文本行的百分比。对于正确预测的,我们指的是文本串的精确匹配:所有的字符和标点符号精确匹配。
在神经网络发展的早期阶段,两年的准确率在 40%到 75%之间波动。由于数据集中每年的证书数量几乎相同,这是非常出乎意料的,结果证明这是由于一个小错误,该错误过度拟合了某些数据集的模型。如果不进行集合测试,这些过度拟合的模型往往会被忽视。误差修正后,所有精度都符合预期。
当我们绘制每年的证书结果时,准确性随时间的变化是明显的。下面显示的是每年训练集中的证书数量(蓝色)和模型在该年达到的准确度(红色)。
The number of certificates and the accuracy of the trained model for each year
该图清楚地表明,前四年(2012 年至 2015 年)的精度相当稳定,平均精度为 36%,标准偏差为 2%。我们发现 2016 年的准确性明显较低,这可能是由于标签质量较低,这一点企业已经知道。
增加具有较低质量标签的数据集不会增加模型的准确性。反之,甚至可能降低。
最佳模型是具有最大数据集的模型,即 2012 年至 2016 年的合并数据。下面我们展示了当通过一次增加一年来增加数据集的大小时,精确度是如何提高的。
The accuracy of fives model applied to four different test sets.
将模型应用于 2017 年的完整数据比其他测试集的准确性稍低。这可能是 2016 年和 2017 年标签不太准确的结果。
最好的评分模型是 2012-2016 年的训练集。所达到的准确度是 53%的精确正确预测的文本行。我们将进一步研究这个最佳模型。
置信级别
神经网络模型为每个预测分配一个置信度。对于测试集,我们知道预测是否与标签完全匹配。对于每个预测,我们知道它是属于正确预测集还是不正确预测集。然后我们可以在一个置信范围内画出预测的数量。
置信度的范围在 0 到 1 之间。我们将该范围分成 20 个区间,每个区间宽 5%,并计算正确和错误预测集在该置信水平下的文本行预测数。
下图显示了两组的结果。正确的预测显示为蓝色,不正确的预测显示为红色。
The number of correct and incorrect text-line predictions as a function of NN confidence level.
我们的目标是高度可信的预测。这些预测应该是准确的。结果确实表明,正确预测的数量在 95–100%置信度时达到峰值,在较低的置信度时会降低。
然而,已知不正确但仍具有高置信度的预测表明存在所谓的假阳性。这些都是极不需要的!
低置信度的预测大多是不正确的预测,由置信度为 0–5%的(红色)峰值显示。这些是难以辨认的笔迹。(对机器来说难以辨认,对人来说不一定。)
具有低置信度的预测总是必须显示给必须判断该预测的人。通过用改进的数据对模型进行再训练,人类反馈可用于改进模型。
也有对低置信水平的正确预测。这些都是假阴性。机器将判断它们是不确定的,它们也将被送到人工检查。
目标人群的例子
让我们以较高的可信度检查一些正确预测的例子。
来自假阳性人群的例子
假阳性群体是神经网络非常确定的一组预测,但它与给定的标签不匹配。
在第一个例子中,我们看到预测实际上是正确的,但是标签增加了“COPD”。因此,我们的精确匹配测试使其落入“不正确”的集合中。这是一个标签与手写文本不完全匹配的例子。
在第二个例子中,我们看到了标签和预测之间的微小差异:v 与 e。标签在语言学上是正确的,但 e 上的分音符不是医生写的。只是因为我们在测试准确性上如此严格,所以这个预测才落入假阳性人群。
第三个例子显示了人为错误。它被标记为“uitdroging ”,但是“uitputting”的预测已经被业务部门确认为正确的。这表明人类也会犯错,因此也会产生假阳性。
第四个例子也是人为错误。标记为“verstikking ”,但它应该是“verslikking ”,这是由神经网络正确预测的。
当手动验证置信度大于 60%的 30 个假阳性的随机样本时,所有这些都表明神经网络是正确的,而标签是错误的。对于其中的两个,人类是错误的。有时差异非常小,但由于我们对正确性的严格测试,即使预测和标签之间的最小差异也会导致假阳性。
令人欣慰的是,确定的假阳性群体已经非常小,可能比包含人为错误的群体还要小。在假阳性组中,人为错误估计发生 2/30 = 7%。
假阴性人群的例子
下面是一个正确预测的文本行的示例,但是神经网络对预测的可信度非常低。这种具有低置信水平的情况将被标记以供人类判断。
来自可理解群体的例子
然后就是一整组 NN 看不懂的手写。所有这些都需要人工判断。
在第一个示例中,箭头没有被正确检测到,最后一个单词也没有被检测到,这也是标签是否正确的问题。不过,第一个单词找到了。
在第二个例子中,我们看到上面的文本行的一部分与文本重叠。这混淆了对单个字母的识别。但是其他单词的可读性也很差。人们希望这些案件得到人类的审判。
自然语言处理
神经网络主要被训练来识别字母。它不知道单词。这意味着 NN 预测形成一个字母序列,尽管它有一些顺序概率的意义,但一些字母组合可能没有意义。
如果 NN 预测与字典中的单词完全匹配,我们不执行进一步的文本匹配。如果已经有一个精确的匹配,我们只会冒险修改一个正确的预测,把它变成别的东西。因此,只有当 NN 预测与字典单词不完全匹配时,才进行下面描述的与单词匹配的文本。
请注意,这些知识也可以用于向词典中添加新单词。
我们已经尝试将神经网络限制为仅预测医学词典中的已知单词,但这导致了太多的假阳性。这种神经网络的输出总是字典中的一个单词。它不能识别其他单词。
因此,我们决定只在字符识别上训练神经网络,并作为后处理步骤执行与字典的匹配。
匹配基于两种算法。
- Jaro 和 Damerau-Levenshtein 距离
- 二元距离
Jaro 和 Damerau-Levenshtein 距离将预测的字母序列与已知单词进行比较,并将纠正预测所需的“编辑”次数视为到单词的距离。
可以计算预测到字典中任何单词的距离,并且将具有最短距离的单词指定为最终预测。
如果文本行至少包含两个单词,则计算二元模型距离。从字典中可以知道有些词经常一起出现。这有助于从预测的字符序列中识别这样的单词。
置信级别
匹配的复杂性在于定义模型对于匹配的置信度。虽然预测到单词的距离是预测有多接近的度量,但它不是置信度的度量。
举个例子,看看下面的笔迹,上面写着“steekwonde”。
NN 预测是“stuikwonde”,比较接近,但不确切。在词典中,我们发现了两个相似的词:“stuitwonde”和“steekwonde”。第一个只有一个字母的距离,第二个有两个字母的距离。但是因为两者都很接近,所以模型应该很不确定选择哪一个。
因此,当我们将神经网络预测与词典中的单词进行匹配时,置信度应该考虑其他相近的单词。单词之间的距离越近,最终结果就越不确定。如果两个单词与 NN 预测等距,则匹配置信度为 50%。如果三个单词是等距离的,置信水平下降到 33%。
我们根据这些统计数据计算了文本匹配的置信度。这很重要,因为在最终产品中,在决定是否进行人工干预时,必须考虑神经网络和文本匹配的置信度。
完整的证书
文本识别模型在单个文本行上操作。平均每个证书有两行文本,作为可测试数据集一部分的证书上最多有四行文本。(标记良好的数据集。)
预计每个证书的文本行数越多,完全正确预测的证书比例就越低。下图显示了证书数量与证书上文本行数的函数关系。
我们证实,随着每个证书的文本行数的增加,完全正确预测的证书的比例下降。
让我们将正确预测证书的置信度定义为证书上任何文本行预测的最小置信度。然后,我们可以将正确预测的证书数量绘制成置信度的函数。下图显示了这一点,其中颜色编码用于表示证书上的行数。
对于没有被正确预测的证书,可以做出相同的图。
我们发现对于高置信水平,在证书水平上很少有不正确的预测。
难以辨认的笔迹
从训练和测试集中排除的是那些甚至人类也不能阅读的证书。这些标签中有$-符号。正如下面的例子所示,神经网络可以正确地读取其中一些,至少可以给试图破译文本的人提供有用的建议。
如果我们将文本行预测的数量绘制为神经网络置信度的函数,我们会看到该分布在 0–5%的置信度处显示一个大峰,这是预期的。如果人类看不懂,机器可能也看不懂。此外,NN 没有接受过阅读可理解证书的训练。
请注意,在某种意义上,神经网络模型中存在一个偏差,即那些不能被人类阅读的笔迹很可能是最差的笔迹,并且该模型不能在这些笔迹上进行训练,因为这些笔迹没有被标记。通过在系统中提供人类反馈,机器也可以慢慢地在这些情况下接受训练。
在第一个例子中,第一个单词不能被人类阅读。NN 预测单词匹配后接近最终预测的单词。(“PP”代表后处理,包括文字匹配。)最后的 PP 预测其实是正确的。因此,即使预测的可信度很低,该预测也会对人类法官起到很好的建议作用。
在第二个例子中,第二个单词是人类不可读的。神经网络预测只差一个字母:c 而不是 e。单词匹配后的最终预测是 100%正确的。
这表明,即使神经网络没有在这些情况下受过训练,它也能识别足够多的字母,对难以辨认的单词做出非常可信的预测。
决赛成绩
我们的最终结果显示,54%的神经网络预测的文本行与人类定义的标签完全匹配。如果我们将文本匹配作为后处理步骤添加到字典中,我们可以将它增加到 60%以上,如果我们考虑到每个证书平均有大约两行文本,我们有 47%的完整证书被正确预测。
对于人类不可读的文本行,即标签中带有$-符号的文本行,我们请两位业务专家手动验证我们的预测。我们随机抽取了 100 个这样的文本行。结果令人放心:100 个中有 20 个被正确预测。
这让我们相信,即使对于难以辨认的证书,模型算法也可以通过给出书写内容的建议来支持人类。
自动化
仍然存在的问题是,我们能在多大程度上自动识别医生的笔迹,并将其与现有的软件系统集成。这归结为一个问题,即我们可以定义一个阈值,在这个阈值之上,预测可以被认为是正确的,因此没有人必须干预。
为了理解这一点,我们必须回到预测的分布作为一个信心水平的函数。对于神经网络,这个函数已经在前面的图中显示了。为了清楚起见,我们在这里重复它。
让我们将阈值定义为 95%的置信度。这意味着所有置信度为 95-100%的预测文本行将被认为是正确的:不需要人工干预。这是上图最后一个框中的所有文本行。这大约是所有文本行的 11%。
我们也有一些误报,但在这种情况下,这只是所有文本行的 0.1%。可能低于人为错误,我们从分析中知道,许多假阳性是由于错误的标记,所以假阳性的真实数量甚至更少。
如果我们将阈值设置为 90%,我们会计算上图中最高的两个容器中的所有文本行。这导致 20%的正确率和 0.2%的误报率。
通过将阈值设置得越来越低,我们添加了更多正确的结果,但最终我们添加了令人难以忍受的许多假阳性。所有高于阈值的红色条柱都被视为误报。因此,当我们有正确预测的好结果,并且假阳性的数量仍然是可接受的低的时候,必须有一些阈值最佳值。什么是可接受的是一个有争议的问题,但假设人类也会犯错误,只要我们的表现不比人类差,我们就可以接受少量的误报。
到目前为止,我们只研究了神经网络的置信水平。如果我们将后处理(文本匹配)添加到图片中,我们可以有效地将一些预测从不正确的群体移动到正确的群体。如下图所示。
我们看到,对于不正确的总体,接近零置信度的峰值降低,而正确的总体升高,当然,特别是对于低置信度。
我们现在可以画出有多少高于阈值的预测是正确的和不正确的。这在下面的图中给出。
绿色显示的是正确预测的人口,红色显示的是错误预测的人口。虚线仅是神经网络预测,实线也包括后处理,这增加了正确群体并减少了错误群体。
垂直绿色条表示从 70%到 75%的阈值。如果我们在这里设置阈值,我们有 33%的正确预测和不到 1%的错误预测(假阳性)。
如果假阳性不相关,则在绿线和红线之间的差异最大化的阈值处获得最大数量的正确结果。这大约是 10%,这导致 59%的正确预测和 8%的错误预测。
在我们的用例中,我们需要在死亡证明的上下文中预测医学术语,如此高数量的假阳性是不可接受的。因此,我们必须谨慎行事。
可以开始将阈值设置为 95%,并且当验证具有较低置信水平的任何预测的人获得对模型预测的信心并向系统提供反馈时,使得模型变得更好,阈值可以降低。
当模型使用人类反馈并自我改进时,它将使用更高的置信度进行预测,这将通过置信度水平将预测的分布向右移动,从而将更多的预测推到阈值以上。
我们可以做出同样的图来预测完整的证书,而不仅仅是文本行。这在下面给出。
这里的数字有些低,因为证书上的所有文本行都必须正确预测。当我们将阈值设置为 30%到 35%的置信度时,我们现在达到了超过 30%的正确预测,但是假阳性的数量达到了 5%。
结论
我们得出结论,使用经过训练的神经网络来阅读医生的笔迹是可行的。
我们发现,神经网络结果对数据预处理的质量非常敏感,并将其切割成单词或文本行。仔细的图像处理是项目成功的关键。
我们还发现,让神经网络将文本与词典单词进行匹配会产生太多的假阳性结果,最好让神经网络只进行阅读,并使用其他 NLP 技术与词典进行匹配。
我们可以通过神经网络和文本匹配来计算预测的置信水平,这可以用于定义用于自动化目的的置信水平阈值。
承认
我们感谢佛兰德政府、Vlaams agents chap Zorg&Gezondheid,是他们使这个项目成为可能,特别感谢 Koenraad、Anne、Rita 和 Wilfried,他们提供了宝贵的指导和商业专业知识,以及他们富有挑战性的重要意见,使这个项目超过了平均水平。
这个项目是 Vectr 的一个合作项目。咨询(【https://medium.com/vectrconsulting】),特别感谢布鲁诺和乔尼。
决策边界可视化(A-Z)
原文:https://towardsdatascience.com/decision-boundary-visualization-a-z-6a63ae9cca7d?source=collection_archive---------4-----------------------
含义、意义、实施
分类问题是数据科学领域中非常普遍和重要的问题。例如:糖尿病视网膜病变、情绪或情感分析、数字识别、癌症类型预测(恶性或良性)等。这些问题往往通过机器学习或者深度学习来解决。此外,在计算机视觉中,像糖尿病视网膜病变或青光眼检测这样的项目中,纹理分析现在经常使用,而不是传统图像处理或深度学习的经典机器学习。虽然根据研究论文,深度学习已经成为糖尿病视网膜病变的最先进技术:
【1】一种检测糖尿病视网膜病变的深度学习方法。
在分类问题中,对一个特定类别的预测涉及到多个类别。换句话说,它也可以以这样的方式构成,即特定的实例(根据特征空间几何的数据点)需要保持在特定的区域(表示类)下,并且需要与其他区域分离(表示其他类)。这种与其他区域的分离可以通过被称为决策边界的边界来可视化。特征空间中决策边界的可视化是在散点图上完成的,其中每个点描述数据集的一个数据点,轴描述特征。决策边界将数据点分成区域,这些区域实际上是它们所属的类。
决策边界的重要性/显著性:
在使用数据集训练机器学习模型之后,通常需要可视化特征空间中数据点的分类。散点图上的决策边界用于此目的,其中散点图包含属于不同类别的数据点(用颜色或形状表示),决策边界可以按照许多不同的策略绘制:
- 单线决策边界:在散点图上绘制决策边界的基本策略是找到一条单线,将数据点分成表示不同类别的区域。现在,使用在训练模型之后获得的与机器学习算法相关的参数来找到这一单线。使用获得的参数和机器学习算法背后的直觉找到线坐标。如果不知道 ML 算法的直觉和工作机制,就不可能部署这种策略。
- 基于轮廓的决策边界:另一种策略涉及绘制轮廓,这些轮廓是每个都用匹配或接近匹配的颜色包围数据点的区域——描绘数据点所属的类别,以及描绘预测类别的轮廓。这是最常遵循的策略,因为这不采用模型训练后获得的机器学习算法的参数和相关计算。但是另一方面,这并没有使用单线完美地分离数据点,所述单线只能由在训练和它们的坐标计算之后获得的参数给出。
单线判定边界的范例实现:
在这里,我将展示基于逻辑回归的机器学习模型的单线决策边界。
进入逻辑回归假设-
其中 z 定义为-
theta_1, theta_2, theta_3 , …., theta_n are the parameters of Logistic Regression and x_1, x_2, …, x_n are the features
因此,h(z)是一个 Sigmoid 函数,其范围是从 0 到 1 (0 和 1 包括在内)。
为了绘制决策边界,h(z)等于逻辑回归中使用的阈值,通常为 0.5。所以,如果
然后,
现在,为了绘制决策边界,需要考虑两个特征,并沿散点图的 x 轴和 y 轴绘制。所以,
在哪里,
where x_1 is the original feature of the dataset
因此,获得了 x'_1 的 2 个值以及 2 个相应的 x'_2 值。x'_1 是单线判定边界的 x 极值,x'_2 是 y 极值。
虚拟数据集上的应用:
数据集包含 100 名学生在两次考试中获得的分数和标签(0/1),该标签指示该学生是否将被大学录取(1 或负数)或不被大学录取(0 或正数)。该数据集位于
* [## navoneel 1092283/logistic _ 回归
在 GitHub 上创建一个帐户,为 navoneel 1092283/logistic _ regression 开发做出贡献。
github.com](https://github.com/navoneel1092283/logistic_regression.git)
问题陈述:给定两次考试的分数,用逻辑回归预测学生是否会被大学录取
在这里,两次考试的分数将是被考虑的两个特征。
以下是在 3 个模块中实现的逻辑回归。文中给出了具体的实现方法,
[## Python 中的逻辑回归从零开始
分类是机器学习问题中一个非常普遍和重要的变体。很多机器算法都有…](https://hackernoon.com/logistic-regression-in-python-from-scratch-954c0196d258)
import numpy as np
from math import *def logistic_regression(X, y, alpha):
n = X.shape[1]
one_column = np.ones((X.shape[0],1))
X = np.concatenate((one_column, X), axis = 1)
theta = np.zeros(n+1)
h = hypothesis(theta, X, n)
theta, theta_history, cost = Gradient_Descent(theta, alpha
, 100000, h, X, y, n)
return theta, theta_history, cost
def Gradient_Descent(theta, alpha, num_iters, h, X, y, n):
theta_history = np.ones((num_iters,n+1))
cost = np.ones(num_iters)
for i in range(0,num_iters):
theta[0] = theta[0] - (alpha/X.shape[0]) * sum(h - y)
for j in range(1,n+1):
theta[j] = theta[j] - (alpha/X.shape[0]) * sum((h - y) *
X.transpose()[j])
theta_history[i] = theta
h = hypothesis(theta, X, n)
cost[i] = (-1/X.shape[0]) * sum(y * np.log(h) + (1 - y) *
np.log(1 - h))
theta = theta.reshape(1,n+1)
return theta, theta_history, cost
def hypothesis(theta, X, n):
h = np.ones((X.shape[0],1))
theta = theta.reshape(1,n+1)
for i in range(0,X.shape[0]):
h[i] = 1 / (1 + exp(-float(np.matmul(theta, X[i]))))
h = h.reshape(X.shape[0])
return h
对数据集执行逻辑回归:
data = np.loadtxt('dataset.txt', delimiter=',')
X_train = data[:,[0,1]]
y_train = data[:,2]theta, theta_history, cost = logistic_regression(X_train, y_train
, 0.001)
获得的θ(参数)向量,
获得数据点的预测或预测类别:
Xp=np.concatenate((np.ones((X_train.shape[0],1)), X_train),axis= 1)
h=hypothesis(theta, Xp, Xp.shape[1] - 1)
绘制单线决策边界:
import matplotlib.pyplot as pltc0 = c1 = 0 # **Counter of label 0 and label 1 instances** if i in range(0, X.shape[0]):
if y_train[i] == 0:
c0 = c0 + 1
else:
c1 = c1 + 1x0 = np.ones((c0,2)) # **matrix** **label 0 instances**
x1 = np.ones((c1,2)) # **matrix** **label 1 instances**k0 = k1 = 0for i in range(0,y_train.shape[0]):
if y_train[i] == 0:
x0[k0] = X_train[i]
k0 = k0 + 1
else:
x1[k1] = X_train[i]
k1 = k1 + 1X = [x0, x1]
colors = ["green", "blue"] # **colours for Scatter Plot**
theta = theta.reshape(3)# **getting the x co-ordinates of the decision boundary** plot_x = np.array([min(X_train[:,0]) - 2, max(X_train[:,0]) + 2])
# **getting corresponding y co-ordinates of the decision boundary** plot_y = (-1/theta[2]) * (theta[1] * plot_x + theta[0])# **Plotting the Single Line Decision Boundary**
for x, c in zip(X, colors):
if c == "green":
plt.scatter(x[:,0], x[:,1], color = c, label = "Not
Admitted")
else:
plt.scatter(x[:,0], x[:,1], color = c, label = "Admitted")
plt.plot(plot_x, plot_y, label = "Decision_Boundary")
plt.legend()
plt.xlabel("Marks obtained in 1st Exam")
plt.ylabel("Marks obtained in 2nd Exam")
Obtained Single Line Decision Boundary
这样,可以为任何基于逻辑回归的机器学习模型绘制单线决策边界。对于其他基于机器学习算法的模型,必须知道相应的假设和直觉。
基于轮廓的判定边界的范例实现:
使用相同的虚构问题、数据集和训练模型,绘制基于轮廓的决策边界。
# Plotting decision regions
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))X = np.concatenate((np.ones((xx.shape[0]*xx.shape[1],1))
, np.c_[xx.ravel(), yy.ravel()]), axis = 1)
h = hypothesis(theta, X, 2)h = h.reshape(xx.shape)plt.contourf(xx, yy, h)
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train,
s=30, edgecolor='k')
plt.xlabel("Marks obtained in 1st Exam")
plt.ylabel("Marks obtained in 2nd Exam")
Obtained Contour-Based Decision Boundary where yellow -> Admitted and blue -> Not Admitted
这种方法显然更方便,因为不需要直觉和假设或者机器学习算法背后的任何数学。所需要的,就是高级 Python 编程的诀窍!!!!
因此,这是一种为任何机器学习模型绘制决策边界的通用方法。
在大多数实用的高级项目中,都涉及到许多特性。那么,如何在二维散点图中绘制决策边界呢?
在这些情况下,有多种出路:
- 可以使用由随机森林分类器或额外树分类器给出的特征重要性分数,以获得 2 个最重要的特征,然后可以在散点图上绘制决策边界。
- 像主成分分析(PCA)或线性判别分析(LDA)这样的降维技术可用于将 N 个特征降维为 2 个特征(n_components = 2 ),因为 N 个特征的信息或解释嵌入到这 2 个特征中。然后,考虑到这两个特征,可以在散点图上绘制决策边界。
这就是决策边界可视化的全部内容。
参考文献
[1] N. Chakrabarty,“一种检测糖尿病视网膜病变的深度学习方法”, 2018 年第 5 届 IEEE 北方邦分会国际电气、电子和计算机工程会议(UPCON) ,印度戈拉克普尔,2018 年,第 1–5 页。多伊指数:10.1109/升。36860.88868688666*
决策不仅仅是解决定量问题
原文:https://towardsdatascience.com/decision-making-is-more-than-quantitative-problem-solving-ac6365a9ec16?source=collection_archive---------20-----------------------
“我在生活和工作中所有最好的决定都是用心、凭直觉、凭勇气而非分析做出的。”—杰夫·贝索斯在 2018 年华盛顿经济俱乐部
多年来,我有一个心理模型,将决策等同于定量解决问题。在这个心智模型中,当一个定量问题被解决时,可以做出决定;例如,如果一种新药的治疗效果在统计学上并不比一种对照药物更好(定量解决问题),它就不应该获得批准(决策)。我已经有这个心智模型很长时间了,因为这个心智模型不仅反映了我在学校如何定量处理教科书问题的经验,还直接谈到了工作场所中数据驱动决策的流行概念。这个心智模型将决策视为定量问题解决的平滑连续体,并让我相信我知道决策只是因为我知道定量问题解决。
与我想象中的决策不同,实地决策是一个动态的过程,既可以依赖也可以完全独立于定量问题的解决。通过我的工作,我对决策和定量解决问题之间的不匹配感到震惊;许多数据科学家也承认他们的数据结果没有被他们的商业伙伴很好地采纳。缺乏数据文化成为一个容易的借口,然而我相信一个严峻的事实是,决策制定首先不是定量问题的解决。到底什么是决策?我以前从来没有认真想过。这一次,我想走出数据科学花园,认真研究决策本身。
以下内容:
- 分析四种决策类型,为您的数据科学工作提供信息
- 使用 N:N 模型帮助您驾驭当今复杂的决策过程
决策具有鲜明的特点
虽然我们可以普遍地将决策定义为从备选方案中选择一个选项的行为,但就选择达成一致的过程在不同的决策之间有很大的不同。利用不同利益相关者的数量,我们可以将决策分为个人决策和公司决策。大多数人都熟悉个人决策,因为这是日常生活的一部分。个人决策有一个或少数利益相关者,通常是决策者本人。个人决策是有重点的,有成本效益的,并有明确的责任。个人决策发生在个人生活和工作场所;你可以决定你的大学专业,也可以决定在工作中展示的最佳方式。个人决策通常影响有限。
"决策涉及从两个或多个可能的选择中选择一个行动方案,以便找到一个特定问题的解决方案"。—特雷瓦萨和纽波特
当利益相关者的数量很大时,我们有公司决策。企业决策通常发生在各级组织中,并赢得了缓慢、昂贵、政治性和缺乏问责制的坏名声,尽管事实上在企业决策中考虑了更严格的评估和多种观点。在大型组织中,一个小的决定可能会以几轮会议和计划而告终。
在数据科学实践中,我们通常关注个人决策,而利益相关者管理根本不存在问题。然而,在现实世界的应用中,我们经常将数据科学应用于有许多利益相关者的组织环境中的决策制定,因此我们主要致力于公司决策制定。因为与利益相关者打交道从来不是数据科学家的事情,那些对建模技术有兴趣的数据科学家可能会对公司决策的复杂性感到震惊。在企业决策中,利益相关者有相互竞争的观点和利益,依赖定量和定性信息进行决策。面对官僚主义,数据科学的成果可能并不性感,而是无能为力。当数据科学家认为数据应该主导决策制定(数据驱动的决策制定思想)时,这位数据科学家可能会说,“结果很清楚,他们就是不听”。
我们可以进一步将决策分为经营决策和战略决策。运营决策的特点是循环性和结构化;此类决策关系到企业的日常运营,由中层经理和一线员工做出。战略决策的特点是非常规和非结构化的;此类决策涉及组织的政策和战略,由高层管理人员和执行人员做出。今天成功的数据科学应用主要是在运营决策中,因为运营决策更可量化,有大量可用数据用于建模,并且利益相关者较少。想想房价预估,贷款申请审批模型,用户留存预测。这些成功的数据科学应用以代码的形式运作,利益相关方的干预有限。当我们试图将这些成功推广到其他类别的决策时,我们需要理解决策具有独特的特征。
建立影响力说服一个村庄
当今的决策环境极具挑战性。领导结构是扁平的,项目由跨职能团队管理,因此我们通常没有单一的决策权。为了支持分散决策,数据科学家需要说服一个村庄。正如我们前面谈到的公司决策,当人数增加时,决策的复杂性会大大增加。在扁平化的领导结构中,单个决策者或权力中心不太可能保留足够大的权力,因此最终的决策可能不会完全得到员工的尊重,这导致执行不力和决策结果不佳。在一个简化的世界里,一个数据科学家需要说服一个决策者;在当今的企业中,一个数据科学家只是众多说服众多决策者的人之一。我们需要从 1:1 模式转向 N:N 模式。
在 N:N 模型中,从数据科学家的角度来看,数据科学家需要从多个角度向多个团队领导交付数据故事。在我的工作中,成功的标志不是演讲结束时的掌声,而是我被推荐给另一位商业领袖。多一个演示听起来不错,但要向 N 个利益相关者讲述有说服力的数据故事并不容易,因为数据科学工作必须足够强大,足以应对 N 个维度的审查。在与 N 个利益相关者的交流中,数据科学家不仅应该了解他们不同的观点,还应该了解他们不同的决策偏好。有些人希望别人为他们做决定,有些人提出问题并解释结果,有些人可以谈论数据库系统和建模,有些人只希望数据能够证明现有的信念。数据科学家需要准备好面对 N 个决策者。
在 N:N 模型中,从决策者的角度来看,决策者从多个来源获取信息以形成观点。内部团队和外部顾问通过电子邮件、PowerPoint 和电子表格不断向决策者提供信息。在雇用数据科学家团队的大型企业中,由于数据源的变化和方法的差异,决策者可能会从不同的数据科学家那里听到相反的决策建议,因此数据科学家会与其他数据科学家和其他专业人士竞争,以提供最佳的决策洞察力。决策者从不依赖一个人的意见,因此,如果你的建议被忽视,不要把它当成个人意见。亿万富翁雷伊·达里奥完美地总结了这种动态。
“最好的决策是由一个具有可信度加权决策的精英思想做出的。与能力较弱的决策者相比,更重视能力较强的决策者的意见要好得多。这就是我们所说的可信度加权。”——雷伊·达里奥,原则
领导力决定一切
尽管数据科学取得了进步,但做出明智决策的能力是一种领导力特质。大胆的领导者能够听到不同的观点,仍然能够做出伟大的决策。数据科学家的工作是给决策者带来严谨的见解,但数据科学家无法改变决策者的领导特质。技术固然有帮助,但领导力才是一切。决策不仅仅是定量解决问题。数据科学家不应局限于解决问题的技能,而应在说服、影响和决策方面建立领导力。
从零开始的决策树分类器:对学生的知识水平进行分类
原文:https://towardsdatascience.com/decision-tree-classifier-from-scratch-classifying-students-knowledge-level-c810876d6c8f?source=collection_archive---------13-----------------------
向数据科学迈出一小步
使用 python 编程语言从头开始编写决策树分类器
Photo by on craftedbygc
先决条件
您需要具备以下方面的基本知识:
- Python 编程语言
- 科学计算图书馆
- 熊猫
数据集
我将在这个项目中使用的数据集来自加州大学欧文分校用户知识建模数据集(UC Irvine)的 。
《UCI》一页提到了以下出版物作为数据集的原始来源:
H.T. Kahraman,Sagiroglu,s .,Colak,I,“开发直观知识分类器和用户领域相关数据的建模”,基于知识的系统,第 37 卷,第 283–295 页,2013 年
介绍
1.1 什么是决策树分类器?
简单来说,决策树分类器就是用于监督+分类问题的 监督机器学习算法 。在决策树中,每个节点都会询问一个关于某个特征的是非问题,并根据决策向左或向右移动。
你可以从 这里 了解更多关于决策树的知识。
Example of decision tree
1.2 我们在建造什么?
Photo by Andrik Langfield on Unsplash
我们将使用机器学习算法来发现学生历史数据上的模式,并对他们的知识水平进行分类,为此,我们将使用 Python 编程语言从头开始编写我们自己的简单决策树分类器。
虽然我会一路解释每件事,但这不会是一个基本的解释。我将通过进一步的链接突出显示重要的概念,这样每个人都可以对该主题进行更多的探索。
代码部分
2.1 准备数据
我们将使用 pandas 进行数据处理和数据清理。
Data Dictionary
import **pandas** as **pd**df = **pd**.read_csv('data.csv')
df.head()
首先,我们导入 data.csv 文件,然后将其作为熊猫的数据帧进行处理,并查看数据。
Data Preview
正如我们看到的,我们的数据有 6 列。它包含 5 个功能和 1 个标签。既然这个数据已经被清理了,就不需要再进行数据清理和 扯皮 。但是,在处理其他真实世界的数据集时,检查数据集中的空值和异常值并从中设计出最佳要素非常重要。
2.2 列车测试分割
train = df.values[-:20]
test = df.values[-20:]
在这里,我们将数据分为训练和测试,其中数据集的最后 20 个数据是测试数据,其余的是训练数据。
2.3 编写我们自己的机器学习模型
现在是时候编写决策树分类器了。
但是在深入研究代码之前,有一些东西需要学习:
- 为了构建这棵树,我们使用了一种叫做 CART 的决策树学习算法。还有其他学习算法,如 ID3,C4.5,C5.0,等。你可以从这里了解更多。
- CART 代表分类和回归树。 CART 使用 Gini 杂质作为其度量,以量化一个问题在多大程度上有助于解混数据,或者简单地说 CARD 使用 Gini 作为其成本函数来评估误差。
- 在引擎盖下,所有的学习算法都给了我们一个决定何时问哪个问题的程序。
- 为了检查这个问题帮助我们解混数据的正确程度,我们使用了信息增益。这有助于我们减少不确定性,我们利用这一点来选择要问的最佳问题,对于给定的问题,我们递归地构建树节点。然后,我们进一步继续划分节点,直到没有问题要问,我们将最后一个节点表示为叶子。
2.3.1 书写助手功能
为了实现决策树分类器,我们需要知道什么时候对数据提出什么问题。让我们为此编写一个代码:
**class** CreateQuestion: **def** __init__(self, column, value):
self.column = column
self.value = value **def** check(self, data):
val = data[self.column]
return val >= self.value
**def** __repr__(self):
return "Is %s %s %s?" % (
self.column[-1], ">=", str(self.value))
上面我们写了一个 CreateQuestion 类,它有两个输入:列号和值作为实例变量。它有一个用于比较特征值的检查方法。
repr 只是 python 的一个帮助显示问题的神奇函数。
让我们来看看它的实际应用:
q = **CreateQuestion**(0, 0.08)
Creating question
现在让我们检查一下我们的检查方法是否工作正常:
data = train[0]
q.check(data)
Testing check method
Cross validating check method
正如我们看到的,我们得到了一个错误的值。因为我们在训练集中的 0ᵗʰ值是 0.0,不大于或等于 0.08,所以我们的方法工作得很好。
现在是时候创建一个分区函数来帮助我们将数据分成两个子集:第一个集合包含所有为真的数据,第二个包含所有为假的数据。
让我们为此编写一个代码:
**def** partition(rows, qsn):
true_rows, false_rows = [], []
**for** row **in** rows:
**if** qsn.check(row):
true_rows.append(row)
**else**:
false_rows.append(row)
**return** true_rows, false_rows
我们的分区函数接受两个输入:行和一个问题,然后返回一列真行和假行。
让我们也来看看实际情况:
true_rows, false_rows = partition(train, CreateQuestion(0, 0.08))
True and False row preview
这里 t rue_rows 包含所有大于或等于 0.08 的数据,而 false_rows 包含小于 0.08 的数据。
现在该写我们的基尼杂质算法了。正如我们之前讨论的,它帮助我们量化节点中有多少不确定性,而信息增益让我们量化一个问题减少了多少不确定性。
杂质指标范围在 0 到 1 之间,数值越低表示不确定性越小。
**def** gini(rows): counts = class_count(rows)
impurity = 1
**for** label **in** counts:
probab_of_label = counts[label] / float(len(rows))
impurity -= probab_of_label**2
**return** impurity
在我们的基尼函数中,我们刚刚实现了基尼的公式。返回给定行的杂质值。
counts 变量保存数据集中给定值的总计数的字典。 class_counts 是一个帮助函数,用于计算某个类的数据集中出现的数据总数。
**def** class_counts(rows):
**for** row **in** rows:
label = row[-1]
**if** label **not** **in** counts:
counts[label] = 0
counts[label] += 1
**return** counts
让我们来看看基尼的作用:
Gini in action: 1
Gini in action: 2
正如您在图像 1 中看到的,有一些杂质,所以它返回 0.5,而在图像 2 中没有杂质,所以它返回 0。
现在我们要编写计算信息增益的代码:
**def** info_gain(left, right, current_uncertainty):
p = float(len(left)) / (len(left) + len(right))
**return** current_uncertainty - p * gini(left) \
- (1 - p) * gini(right)
通过减去具有两个子节点的加权杂质的不确定性起始节点来计算信息增益。
2.3.2 将所有内容放在一起
Photo by ryoji
现在是时候把所有东西放在一起了。
**def** find_best_split(rows):
best_gain = 0
best_question = None
current_uncertainty = gini(rows)
n_features = len(rows[0]) - 1
**for** col **in** range(n_features):
values = set([row[col] **for** row **in** rows])
**for** val **in** values:
question = Question(col, val)
true_rows, false_rows = partition(rows, question) **if** len(true_rows) == 0 **or** len(false_rows) == 0:
**continue**
gain = info_gain(true_rows, false_rows,\
current_uncertainty) **if** gain > best_gain:
best_gain, best_question = gain, question
**return** best_gain, best_question
我们编写了一个 find_best_split 函数,它通过迭代每个特征和标签找到最佳问题,然后计算信息增益。
让我们来看看这个函数的运行情况:
best_gain, best_question = find_best_split(train)
Finding best question
我们现在要编写我们的 fit 函数。
**def** fit(features, labels): data = features + labels gain, question = find_best_split(data)
**if** gain == 0:
**return** Leaf(rows)
true_rows, false_rows = partition(rows, question)
*# Recursively build the true branch.*
true_branch = build_tree(true_rows)
*# Recursively build the false branch.*
false_branch = build_tree(false_rows)
**return** Decision_Node(question, true_branch, false_branch)
我们的 fit 函数基本上为我们构建了一棵树。它从根节点开始,通过使用我们的 find_best_split 函数找到针对该节点的最佳问题。它迭代每个值,然后分割数据并计算信息增益。在这一过程中,它跟踪产生最大收益的问题。
之后,如果仍有有用的问题要问,增益将大于 0,因此行被分组为分支,并且它首先递归构建真分支,直到没有进一步的问题要问并且增益为 0。
该节点随后成为一个叶节点。
我们的 Leaf 类的代码如下所示:
**class** **Leaf**:
**def** __init__(self, rows):
self.predictions = class_counts(rows)
它保存了一个类别为(“高”、“低”)的字典,以及它在到达当前叶子的数据的行中出现的次数。
对于假分支也应用相同的过程。之后,它就变成了一个决策 _ 节点。
我们的 Decision_Node 类的代码如下所示:
**class** **Decision_Node**:
**def** __init__(self, question,\
true_branch,false_branch):
self.question = question
self.true_branch = true_branch
self.false_branch = false_branch
这个类只保存我们已经问过的问题的引用和产生的两个子节点。
现在我们回到根节点,建立错误分支。因为没有任何问题要问,所以它成为叶节点,并且根节点也成为决策 _ 节点。
让我们看看 fit 功能的实际应用:
_tree = fit(train)
为了打印树_ 树,我们必须编写一个特殊的函数。
**def** print_tree(node, spacing=""):
*# Base case: we've reached a leaf*
**if** isinstance(node, Leaf):
**print** (spacing + "Predict", node.predictions)
**return**
*# Print the question at this node*
**print** (spacing + str(node.question))
*# Call this function recursively on the true branch*
**print** (spacing + '--> True:')
print_tree(node.true_branch, spacing + " ")
*# Call this function recursively on the false branch*
**print** (spacing + '--> False:')
print_tree(node.false_branch, spacing + " ")
这个 print_tree 函数帮助我们以一种令人敬畏的方式可视化我们的树。
Sample of our tree
我们刚刚完成了决策树分类器的构建!
为了理解和查看我们构建的内容,让我们再编写一些帮助函数:
**def** classify(row, node):
**if** isinstance(node, Leaf):
**return** node.predictions
**if** node.question.check(row):
**return** classify(row, node.true_branch)
**else**:
**return** classify(row, node.false_branch)
分类功能帮助我们检查给定行和树的可信度。
classify(train[5], _tree)
Classification sample
正如你在上面看到的,我们的树把给定的值归类为 96 置信度的中间值。
**def** print_leaf(counts):
total = sum(counts.values()) * 1.0
probs = {}
**for** lbl in counts.keys():
probs[lbl] = str(int(counts[lbl] / total * 100)) + "%"
**return** probs
函数帮助我们美化我们的预测。
Pretty print
2.4 模型评估
我们已经成功地建立,可视化,并看到我们的树在行动。
现在让我们执行一个简单的模型评估:
**for** row **in** testing_data:
**print** ("Actual level: **%s**. Predicted level: **%s**" %
(df['LABEL'], print_leaf(classify(row, _tree))))
Predicted on test data
如你所见,我们的树很好地预测了从训练数据中分离出来的测试数据。
结论
决策树分类器是一个很棒的学习算法。它对初学者很友好,也很容易实现。我们从头开始构建了一个非常简单的决策树分类器,没有使用任何抽象库来预测学生的知识水平。通过交换数据集和调整一些函数,您也可以将该算法用于另一个分类目的。
参考
[1] H. T. Kahraman,Sagiroglu,s .,Colak,I. ,开发直观知识分类器并对 web 中用户的领域相关数据建模,基于知识的系统,第 37 卷,第 283–295 页,2013 年
[2] Aurelien Geron ,用 Scikit-Learn 进行动手机器学习,Keras & TensorFlow,O'REILLY,第二版,2019
更好地使用决策树
原文:https://towardsdatascience.com/decision-tree-for-better-usage-622c025ffeeb?source=collection_archive---------12-----------------------
从树叶,树,到森林
Photo by pandu ior on Unsplash
当有大量关于决策树的资料时,写这篇文章的原因是为了给一个机会以不同的角度来看待这个话题。接触不同的理解方式是一种有效的学习方法,就好像你一部分一部分地触摸某物,你就知道它的整体形状。您将看到的主题可能会填补您在决策树中遗漏的内容,或者您可以简单地复习一下您已经知道的内容。这篇文章从决策树如何工作开始,涵盖了基本特征,并将其扩展到称为 Bagging 的技术。
先决条件
对模型评估的一些基本理解,尤其是对测试集的理解,将会非常有帮助。可以参考 我之前的帖子 里面涵盖了一部分。
内容
- 如何拆分—如何测量杂质来确定拆分
- 连续要素-如何在连续值上找到分割点
- 非线性和回归——为什么它是非线性的,如何回归
- 贪婪算法——决策树为什么找不到真正的最优解
- 过度拟合的趋势——为什么会发生过度拟合以及如何防止过度拟合
- 装袋和随机森林——装袋的工作原理
- R 中的演示—贷款违约数据
怎么分
决策树的工作原理基本上是关于如何分割节点,因为这就是树的构建方式。让我们假设我们有一个二元分类问题;可乐 vs 酱油。当你想喝什么就喝什么的时候,你不会光看一眼就做出决定。你可能会闻到它,甚至尝一点。因此,颜色不是一个有用的特征,但气味应该是。
在这个例子中,每个人有 5 个杯子,总共 10 个,你的工作是用你的眼睛将它们分类。我们说左节点决定可乐,是因为可乐类比较多,反之亦然。结果不会有希望,你可能会以喝酱油告终。在这种情况下,底部节点是而不是纯粹的,因为这些类几乎都混在一起了。
当一个类在一个节点中占优势时,我们说这个节点是“纯”的。
现在,你用你的鼻子。你仍然可能犯一些错误,但结果应该会好得多。因为节点大多有一个主导类,可乐在左边,酱油在右边,这样更纯粹。那么,问题就变成了如何衡量‘纯度’。答案可能很多,但我们可以谈谈基尼系数(T21)。
该公式是说,将一个类在每个节点上正确的所有平方概率相加,并从 1 中减去总和。好了,我们来看一些例子。
我们有一个有 10 个例子的节点,其中 5 个是真的,5 个是假的。你在这个节点上的决定可能是对的,也可能是错的。现在,你知道这个节点不是很纯。要衡量有多不纯,我们可以这样计算。
在 10 分中,真类的概率是 0.5,假类的概率也是如此。其实这是最不纯粹的案例,证明最高基尼是 0.5 。下面是另一个例子。
更低的基尼更纯,所以更好。
有更多的真实类,所以你可以更自信地宣称你的决定是真实的。同样,基尼系数现在也降低了。此时要提出的另一个问题是何时拆分。我们知道示例中的 7 比 3 是基尼系数的 0.42,但我们想使它更纯粹,并决定用另一个特征来划分 10 个等级。
拆分为两个子节点。现在,我们说左边的节点是真实的,有更多的真实类,反之亦然。我们可以测量每个节点的纯度,但我们如何得出一个结果来与父节点进行比较?我们可以简单地根据节点大小给它们权重,以达到父总数。
如果基尼系数下降,我们就说拆分获得了“信息”。
基尼系数 0.3 小于母公司的 0.42,因此,拆分获得了一些信息。如果一些分裂导致以下结果,那就太好了。
父母是如此的糟糕,他们的基尼系数是 0.5,但是一次分割就可以把基尼系数降到 0。请注意,这两个孩子在辨别真假方面做得非常好。似乎分裂总是有帮助的,然而,那不是真的。
我们直观地知道父节点的基尼系数不是最大值(0.5),但子节点的基尼系数是最大值。换句话说,拆分使情况变得更糟(信息丢失)。即使父母及其子女的基尼系数相同,这仍然更糟,因为节点越多的模型意味着越复杂。事实上,现代决策树模型通过添加更多节点来破坏它。
还有一点需要注意的是,基尼并不是衡量纯度的唯一标准。还有很多,但下面两个值得一提。
你可以像我们对基尼系数所做的那样去尝试,它会输出不同的结果。那么,哪一个比其他的好呢?答案是“视情况而定”。我们更应该关注它们是如何不同的。
From Introduction to Data Mining
我们知道基尼系数的最大值是 0.5,这与熵的最大值不同。也就是说,熵值上升的速度比基尼系数更快。这意味着它可以更严厉地惩罚不纯节点。
另一个区别是误分类误差不像其他两个那样平滑。例如,x-轴从 0.1 增加到 0.2 会增加与从 0.3 增加到 0.4 相同的杂质,这是线性的。相反,基尼认为 0.4 的杂质和 0.5 的杂质几乎一样,熵也是如此。这意味着基尼系数和熵值对杂质更严格。而用哪个要看情况。
连续特征
我们从分类特征开始,这可能不会让任何人感到奇怪。但是决策树可以优雅地处理连续特征。让我们来看看这个例子。
我们有一系列的价值观;10,20,…,100,每一个都被标为真或假。首先要做的是对它们排序,我们可以在两个值之间找到一个点。假设我们 45 岁分手。
理论上,拆分连续值有无限种选择。
有四个值小于 45,其中三个为假,一个为真。相同的规则适用于大于 45°的右侧。现在,我们可以计算每个群体的基尼系数。当然,我们需要对它们进行加权,以得出最终的基尼系数。我们对值之间所有可能的分割点都这样做。
从表中可以看出,最低的基尼系数位于分裂点 35,其中左边是完全纯的(全部是假类),右边有 7 个类,其中 5 个是真类。计算似乎很累,但是当你滑过这些值时,真或假的计数会一个接一个地改变。这意味着每次计算只需要为下一次计算做一点小小的改变(反正机器是为我们做的)。总之,连续特征的处理与分类特征非常相似,但计算量更大。
非线性和回归
直截了当地说,决策树是一个非线性模型。如果一个例子按特征节点分类,多少并不重要。
在图中,有一些极端值,如-205 或 15482。然而,它们都只属于一个节点,任何其他数量都满足该条件。他们没有任何特殊的头衔,如“超级肯定”或“双重否定”。此时,决策树似乎无法进行回归。但是是的,它可以。
我们来看一些类比。我们都知道 ANOVA 模型可以进行回归,其中分类预测值的平均值代表某组样本。类似的想法可以应用到决策树。
某个节点中样本的均值或中值等统计量可以代表该节点
From Scikit-Learn Website
首先,从盒状线可以明显看出决策树是非线性的。这里的另一个要点是,它显示了决策树如何过度适应示例。“最大深度”控制着一棵树的复杂程度。我们可以看到,Max-depth 设置为 5 的树非常努力地适应所有遥远的例子,代价是模型非常复杂。
贪婪算法
决策树是一种贪婪算法,它在每一步都寻找最佳解。换句话说,它可能找不到全局最优解。当有多个特征时,决策树循环遍历这些特征,从以最纯粹的方式(最低基尼系数或最大信息增益)分割目标类的最佳特征开始。并且它一直这样做,直到不再有特征或者拆分没有意义。为什么这有时无法找到真正的最佳解决方案?
为了理解“贪婪”方式实际上发生了什么,我们假设我们从 A 点到 b 点。在贪婪标准下,我们看不到 A 点上的红色路径点,而只能看到蓝色点。站在点 A,我们决定底部,因为这比顶部短。但是在下一步,我们找到红点,以此类推,以一个更长的行程结束。
每一步做出的最优选择并不能保证全局最优。
同样的情况也可能发生在决策树中,因为并没有将所有可能的对组合在一起。想象一下,如果没有数千个特征,也有数百个特征,它们是分类的和连续混合的,每个特征都有不同的值和范围。尽可能将它们混合在一起应该是禁止的。知道决策树是贪婪的,对于理解为什么像装袋这样的高级方法有效很重要。
过度配合的趋势
像其他模型一样,决策树也有过度拟合的问题。在某种程度上,它可能比其他型号稍差一些。一个极端的例子是 ID 特征。无论如何,我们都不想把它作为一个特性,但是为了便于理解,让我们把它当作一个特性。
如果还有任何特征需要分割,它将继续尝试分割
这是一个多路分割,其中每个 ID 都有一个分支,每个节点只有一个案例需要做出决策,因为 ID 是唯一的。现在,它变成了一个查找表。这只不过是一堆硬编码的“if 语句”。当它看到一个新的例子时,问题就出现了。然后,模型会因为里面没有任何功能而爆炸。如果是二叉分裂决策树,那么它的深度就和例子的数量一样。
实际上,我们永远不会使用 ID 作为一个特性,但是如果一个特性有各种各样的值,可以绘制如此多的微妙边界,或者我们让它在深度上增长到适合所有示例所需的程度,这种事件仍然可能发生。也有多种方法可以防止这种情况。修剪是防止树长得更深的方法之一。
“预修剪”控制每个节点必须进一步分裂的样本数。“后期修剪”让它扩展,然后找到过度拟合的节点。
以一种更复杂的方式,我们可以考虑集成方法,让多个学习者做出单独的决定,并把他们放在一起作出最终决定。
装袋和随机森林
Bootstrap 聚合,即所谓的 Bagging,一种集合模型,其中有多个学习者。它的目标是防止过度拟合,并找到更好的解决方案。正如我们从它的名字可以猜到的,它利用了 Bootstrap 抽样方法,这意味着我们抽取‘有替换’的样本。
这是另一个过度拟合的例子,其中底部节点被分割得太多,仅适合 2 个例子。因此,这两个例子肯定非常特殊,因为所有的上层节点都无法唯一地将它们分开。同样,节点现在就像一个查找表。如果我们在构建树的时候不包括这两个例子呢?
装袋随机抽取样品,让一些多抽或一些不抽
树 1 是在没有两个例外示例的情况下构建的。现在,我们给它测试的两个例外,它落在一个有很多例子的节点上。这不再像查找表一样工作,因为它甚至没有看到示例。它们在其他树中仍然可能是例外的,但是最终的决定是由所有“n”棵树投票做出的。简而言之,随机抽样防止一个模型记忆例子,并集中于一个普遍共识。
装袋也可以随机选择特征。
如果我们将 Bagging 应用于特征会怎么样?它的意思是随机选择一些特征,而不是全部。比如我们有 100 个特征,要猜一些类。我们可以像纯决策树一样使用它们,但我们只是随机选择其中的一些,比如只使用 30 或 50 个或任何一个。这听起来很奇怪,因为看起来我们没有充分利用功能。
还记得寻找更短路线的贪婪算法例子吗,如果我们连最底层路线的选择都没有呢?因为我们不知道那条路线,所以我们会选择最上面的路线,这样总的来说会缩短行程。
通过减少特征,我们可以防止导致局部最优而非全局最优的特征组合。
由于随机选择的性质,某些特性集可能会导致更糟的结果。这就是为什么我们应该多次重复随机抽样和随机特征选择,以便它能够找到偏向一般决策标准的最佳组合。但这可能仍然不是真正的全局最优,因为随机化所有这些并不意味着我们已经经历了所有的可能性( NP-Complete 问题)。
需要注意的一点是 Bagging 是一种集成方法,可以应用于任何模型,而不仅仅是决策树。当 Bagging 应用于决策树时,就像树木组成一个森林一样,它变成了随机森林。
R 中的演示
贷款数据集直观易懂。我们有 300 个例子和 11 个特征,如年龄、性别、贷款金额、收入和贷款状态作为目标。这是一个二元分类,猜测贷款是否违约。
代码使用最少的库,因此它可以专注于模拟。此外,交叉验证没有用于评估,以保持简单(仍然公平,因为相同的训练/测试集用于所有模型)。完整的代码和数据可以在 Github 上找到。
- 完整模型—根据训练集进行评估
# Classification model with all features
clf <- rpart(formula = Loan_Status ~., data = training.set,
control = rpart.control(minsplit = 1))# Predict from training set and calculate accuracy
pred <- predict(clf, newdata = training.set[, -12], type = 'class')
round(sum(training.set[, 12]==pred)/length(pred), 2)# Plot the tree
rpart.plot(clf, box.palette = 'RdBu', nn = T)
该模型是使用所有功能构建的,并且是针对训练集而不是测试集进行测试的。这是为了观察过度拟合是如何发生的。
*图上的文字可能不清晰,但此时并不重要。请注意形状,尤其是深度和节点的数量。
Accuracy = 0.96
这棵树又深又复杂。它的精度是 0.96,几乎完美,但根据自己的训练集进行了测试。现在,让我们根据测试集(看不见的数据)评估模型。
- 完整模型—根据测试集进行评估
# Evaluate against testing set
pred <- predict(clf, **newdata = testing.set**[-12], type = 'class')
round(sum(testing.set[, 12]==pred)/length(pred), 2)
请注意,参数“newdata”现在是“testing.set”。结果是 0.63 ,远小于针对训练集测试的值。这意味着使用所有特征和所有例子的模型没有成功地概括它。
我们首先可以做的一件事是调整参数。限制深度会有所帮助,因为模型不会增长到那么深,从而防止过度拟合。此后的所有精度都是从测试集中计算出来的。
- 具有深度限制的完整模型
# Set maxdepth to 3
clf <- rpart(formula = Loan_Status ~., data = training.set,
control = rpart.control(minsplit = 1, **maxdepth = 3**))# Evaluate against testing set
pred <- predict(clf, newdata = testing.set[-12], type = 'class')
round(sum(testing.set[, 12]==pred)/length(pred), 2)
根据测试集评估,现在的准确度为 0.68 ,高于 0.63。此外,即使不使用所有的特性,树也要简单得多。
Accuracy = 0.68
- 随机抽样的简化模型——随机森林
# Build 100 trees with max node
clf <- randomForest(x = training.set[-12],
y = training.set$Loan_Status,
**ntree = 100**, **maxnodes = 5**)
我们构建了 100 棵树,每棵树最多有 5 个节点。精度为 0.72 ,比以往更高。这意味着模型找到了一些处理异常例子的方法。当我们更想改善它的时候,我们应该仅仅增加树的数量吗?不幸的是,它可能不会太有帮助,因为随机森林不是魔法。如果足够幸运的话,在看到全新的数据之前,它可能会变得更好。
这种改进是基于共识的,意味着它放弃了次要的例子,以适应更普遍的例子。
结论
我们学习了决策树的基本原理,重点是分裂。分类值和连续值都显示了这一点。此外,我们还检验了决策树的一些特性,如非线性、回归能力和贪婪算法。对于过度拟合,控制深度和装袋介绍了示范在 r。
在现实世界中,这些并不总是有效的,因为我们不应该期望数据像我们希望的那样干净。然而,了解这些属性和参数将是创造性尝试的良好开端。
好的读数
- 数据挖掘简介:第 4 章。分类
- Scikit-Learn 示例:决策树回归
- 随机森林视频指南:基本思路介绍
- ‘R part’R 库:教程及更多详情
- randomForest R 库:简单教程
我们鼓励你提出你的意见。在此评论!或者通过 LinkedIn 跟我说话,如果你想悄悄地指出这篇帖子中的错误……同时,欢迎你访问 我的作品集网站 !
Python 中从头开始的决策树
原文:https://towardsdatascience.com/decision-tree-from-scratch-in-python-46e99dfea775?source=collection_archive---------1-----------------------
决策树是当今可用的最强大的机器学习工具之一,被广泛用于各种现实世界的应用中,从脸书的广告点击预测到 Airbnb 体验的排名。然而,它们是直观的、易于解释的——并且易于实现。在本文中,我们将用 66 行 Python 代码训练我们自己的决策树分类器。
Let’s build this!
什么是决策树?
决策树可用于回归(连续实值输出,
例如预测房屋价格)或分类(分类输出,
例如预测垃圾邮件与无垃圾邮件),但这里我们将重点讨论分类。决策树分类器是一个二叉树,其中通过从根到叶遍历树来进行预测——在每个节点,如果特征小于阈值,我们向左,否则向右。最后,每个叶子与一个类相关联,这是预测器的输出。
例如,考虑这个无线室内定位数据集。它给出了 7 个特征,代表公寓中手机感知的 7 个 Wi-Fi 信号的强度,以及手机的室内位置,可能是 1、2、3 或 4 号房间。
+-------+-------+-------+-------+-------+-------+-------+------+
| Wifi1 | Wifi2 | Wifi3 | Wifi4 | Wifi5 | Wifi6 | Wifi7 | Room |
+-------+-------+-------+-------+-------+-------+-------+------+
| -64 | -55 | -63 | -66 | -76 | -88 | -83 | 1 |
| -49 | -52 | -57 | -54 | -59 | -85 | -88 | 3 |
| -36 | -60 | -53 | -36 | -63 | -70 | -77 | 2 |
| -61 | -56 | -55 | -63 | -52 | -84 | -87 | 4 |
| -36 | -61 | -57 | -27 | -71 | -73 | -70 | 2 |
...
目标是根据 Wi-Fi 信号 1 到 7 的强度来预测手机位于哪个房间。深度为2 的经过训练的决策树可能如下所示:
Trained decision tree. Predictions are performed by traversing the tree from root to leaf and going left when the condition is true. For example, if Wifi 1 strength is -60 and Wifi 5 strength is -50, we would predict the phone is located in room 4.
基尼杂质
在我们深入研究代码之前,让我们定义算法中使用的度量。决策树使用基尼杂质的概念来描述一个节点的同质性或“纯”程度。如果一个节点的所有样本都属于同一个类,则该节点是纯的( G = 0 ),而具有来自许多不同类的许多样本的节点将具有更接近 1 的基尼系数。
更正式的说法是,跨 k 个类别划分的 n 个训练样本的基尼系数被定义为
其中 p[k] 是属于类别 k 的样本分数。
例如,如果一个节点包含五个样本,其中两个是教室 1,两个是教室 2,一个是教室 3,而没有教室 4,那么
CART 算法
训练算法是一种叫做 CART 的递归算法,是分类和回归树的简称。每个节点都被分割,以使子节点的基尼系数杂质(更具体地说,是按大小加权的子节点的基尼系数平均值)最小化。
当达到最大深度、超参数、时,或者当没有分裂可以导致两个孩子比他们的父母更纯时,递归停止。其他超参数可以控制这个停止标准(在实践中对避免过度拟合至关重要),但我们不会在这里讨论它们。
例如,如果X = [[1.5], [1.7], [2.3], [2.7], [2.7]]
和y = [1, 1, 2, 2, 3]
,那么最优分割是feature_0 < 2
,因为如上计算,父母的基尼系数是 0.64,分割后子女的基尼系数是
你可以说服自己,没有任何其他分割方式能产生更低的基尼系数。
寻找最佳特征和阈值
CART 算法的关键是找到最优特征和阈值,使得基尼系数杂质最小。为此,我们尝试了所有可能的分裂,并计算了由此产生的基尼系数。
但是我们如何尝试连续值的所有可能的阈值呢?有一个简单的技巧-对给定特性的值进行排序,并考虑两个相邻值之间的所有中点。排序是昂贵的,但我们很快就会看到,无论如何它是需要的。
现在,我们如何计算所有可能分裂的基尼系数呢?
第一种解决方案是实际执行每次分割,并计算得出的基尼系数。不幸的是,这很慢,因为我们需要查看所有的样本,将它们分成左和右。更准确地说,这将是 n 个拆分,每个拆分有个 O(n) 个操作,使得整个操作为 O(n ) 。
更快的方法是 1。遍历排序后的特征值作为可能的阈值, 2。记录左侧和右侧每类样品的数量,以及 3。在每个阈值后,将它们递增/递减 1。从它们我们可以很容易地计算出常数时间内的基尼系数。
实际上,如果 m 是节点的大小,并且m【k】是节点中类别 k 的样本数,那么
由于在看到第 i 个阈值后,左边有 i 元素,右边有m–I,
和
由此得出的基尼系数是一个简单的加权平均数:
下面是完整的_best_split
方法。
第 61 行的条件是最后一个微妙之处。通过遍历所有特征值,我们允许对具有相同值的样本进行分割。实际上,我们只能在它们对于该特性有独特的值的情况下对它们进行分割,因此需要额外的检查。
递归
难的部分完成了!现在我们要做的就是递归地分割每个节点,直到达到最大深度。
但是首先让我们定义一个Node
类:
将决策树拟合到数据X
和目标y
是通过调用递归方法_grow_tree()
的fit()
方法完成的:
预言
我们已经看到了如何拟合决策树,现在我们如何用它来预测看不见的数据的类?再简单不过了——如果特征值低于阈值,则向左,否则向右。
训练模型
我们的DecisionTreeClassifier
准备好了!让我们在无线室内定位数据集上训练一个模型:
Our trained decision tree. For the ASCII visualization — not in the scope of this article — check out the full code for the Node class.
作为健全性检查,下面是 Scikit-Learn 实现的输出:
复杂性
很容易看出,预测在 O(log m) ,其中 m 是树的深度。
但是训练呢? 主定理 在这里会很有帮助。在具有 n 个样本的数据集上拟合树的时间复杂度可以用下面的递归关系来表示:
其中,假设左右孩子大小相同的最佳情况, a = 2,b= 2;而 f(n) 是将节点拆分成两个子节点的复杂度,换句话说就是_best_split
的复杂度。第一个for
循环对特性进行迭代,对于每次迭代,都有一个复杂度为 O(n log n) 的排序** 和 O(n) 中的另一个for
循环。因此 f(n) 是 O(k n log n) 其中 k 是特征的数量。**
在这些假设下,主定理告诉我们总时间复杂度是
这与 Scikit-Learn 实现的复杂性差不太远,但仍然比它差,显然是在 O(k n log n)中。如果有人知道这怎么可能,请在评论里告诉我!
完全码
完整的代码可以在这个 Github repo 上找到。正如承诺的那样,为了好玩,这里有一个精简到 66 行的版本。
何、、欧瑾、、徐、、、史、、安托万·阿塔拉、拉尔夫·赫布里希、斯图尔特·鲍尔斯和华金·基诺内罗·坎德拉。2014.预测脸书广告点击率的实践经验。《第八届在线广告数据挖掘国际研讨会论文集》(ADKDD'14)。美国纽约州纽约市 ACM,第 5 条,9 页。DOI = http://dx . DOI . org/10.1145/26484848364
Jayant G Rohra、Boominathan Perumal、Swathi Jamjala Narayanan、Priya Thakur 和 Rajen B Bhatt,“使用粒子群优化和重力搜索算法与神经网络的模糊混合在室内环境中的用户定位”,载于第六届软计算解决问题国际会议论文集,2017 年,第 286-295 页。
布雷曼,利奥;J. H .弗里德曼;奥尔申。斯通,C. J. (1984)。分类和回归树。加利福尼亚州蒙特雷:沃兹沃斯&布鲁克斯/科尔高级图书&软件。
通俗地说就是决策树
原文:https://towardsdatascience.com/decision-tree-in-laymans-terms-part-1-76e1f1a6b672?source=collection_archive---------20-----------------------
Image by Johannes Plenio from Pixabay
什么是决策树?
决策树是基于特定条件的决策的所有可能解决方案的图形表示。目标变量可以取一组有限值的树模型称为分类树,目标变量可以取连续值(数字)的树模型称为回归树。
让我们举一个现实生活中的例子,
Toll-Free
每当你拨打银行的免费电话时,它会将你转接到他们的智能电脑助手那里,询问你一系列问题,如英语请按 1,西班牙语请按 2 等。一旦你选择了你想要的,它会再次将你重定向到一系列特定的问题,比如贷款请按 1,储蓄账户请按 2,信用卡请按 3 等等。这样不断重复,直到你最终找到合适的人或服务。你可能认为这只是一个语音邮件流程,但实际上,银行实施决策树是为了让你进入正确的产品或服务。
考虑一下上面的图片,我是否应该接受一份新的工作邀请?为此,我们需要创建一个决策树,从基本条件或根节点(蓝色)开始,即最低工资应为 100,000 美元,如果没有 100,000 美元,则您不会接受该提议。所以,如果你的薪水高于 10 万英镑,那么你会进一步检查公司是否给你一个月的假期?如果他们不给,那么你就是在拒绝这个提议。如果他们给你一个假期,那么你会进一步检查该公司是否提供免费健身房?如果他们不提供免费健身房,那么你是在拒绝这个提议。如果他们提供免费健身房,那么你很乐意接受这个提议。这只是决策树的一个例子。
好了,怎么建树?
有许多具体的决策树算法可用。值得注意的包括:
- ID3(迭代二分法 3)
- 分类和回归树
- 卡方自动交互检测(CHAID)。计算分类树时执行多级拆分。
在这个博客中,我们将看到 ID3。决策树常用的杂质度量有三种:熵、基尼指数、分类误差。决策树算法使用信息增益来分割节点。基尼指数或熵是计算信息增益的标准。CART 算法使用的基尼指数和 ID3 算法使用的熵。在进入细节之前,我们先来看看杂质。
什么是杂质?
假设你有一个装满苹果的篮子,而另一个碗里装满了同样的苹果标签。如果你被要求从每个篮子和碗中挑选一件物品,那么得到苹果及其正确标签的概率是 1,所以在这种情况下,你可以说杂质是 0
假设现在篮子里有三种不同的水果,碗里有三种不同的标签,那么水果与标签匹配的概率显然不是 1,而是小于 1。如果我们从篮子里拿一根香蕉,然后从碗里随机拿一个标签,上面写着葡萄,这是有可能的。所以在这里,任何随机的排列组合都是可能的。在这种情况下,我们可以说杂质不为零。
熵
熵是你的数据有多杂乱的一个指标。
熵是对数据集中随机性或不可预测性的度量。换句话说,它控制决策树决定如何分割数据。熵是数据同质性的度量。它的值范围从 0 到 1。如果一个节点的所有样本都属于同一个类,则熵为 0(这对训练数据集不利),如果我们具有均匀的类分布,则熵最大(对训练数据集有利)。熵的等式是
信息增益
信息增益(IG) 度量一个特征给我们多少关于类的“信息”。信息增益基于数据集在属性上拆分后熵的减少。它是用于构建决策树的主要参数。具有最高信息增益的属性将首先被测试/分割。
信息增益=基础熵—新熵
让我们以下面的卡通数据集为例。感谢 Minsuk Heo 分享这个例子。你可以点击查看他的 youtube 频道
数据集有一个卡通,冬天,> 1 属性。家庭冬季照是我们的目标。共 8 张图片。我们需要教宝宝挑选正确的冬季家庭度假照片。
如何拆分数据?
我们必须以信息增益最高的方式构建分割数据的条件。请注意,增益是分裂后熵减少的量度。首先,将计算上述数据集的熵。
共 8 张照片。冬季全家福— 1(是),现在冬季全家福— 7(否)。如果我们代入上面的熵公式,
=-(1/8)* log2(1/8)——(7/8)* log2(7/8)
熵= 0.543
我们得到了三个属性,即卡通、冬天和> 1。那么哪种属性最适合构建决策树呢?我们需要计算所有三个属性的信息增益,以便选择最佳的一个或根节点。我们的基本熵是 0.543
卡通片《冬天》的信息增益,
卡通的信息增益高,所以根节点是一个卡通人物。
根节点是一个卡通人物。我们需要根据另外两个属性 winter 或> 1 再次进行拆分。再次计算信息增益并选择最高的一个用于选择下一次分裂。
1 属性具有高信息增益,相应地拆分树。最终的树如下
决策树的优点
- 决策树易于可视化和解释。
- 它可以很容易地捕捉非线性模式。
- 它可以处理数字和分类数据。
- 数据准备所需的工作量很小。(例如,不需要标准化数据)
决策树的缺点
- 过拟合是决策树模型最实际的困难之一。
- 连续变量精度低:在处理连续数值变量时,决策树在对不同类别的变量进行分类时会丢失信息。
- 它是不稳定的,意味着数据的微小变化会导致最优决策树结构的巨大变化。
- 决策树偏向于不平衡数据集,因此建议在创建决策树之前平衡数据集。
我将在下一篇文章中使用 Python 解释 CART 算法和过度拟合问题。
请继续学习,并关注更多内容!
如果您发现任何错误或需要改进的地方,请随时在下面发表评论。
Python 中的决策树
原文:https://towardsdatascience.com/decision-tree-in-python-b433ae57fb93?source=collection_archive---------2-----------------------
https://www.pexels.com/photo/from-above-of-ethnic-scientist-exploring-details-of-aircraft-using-magnifier-3825540/
在我看来,决策树模型有助于突出我们如何使用机器学习来增强我们的决策能力。我们都曾在某个时候遇到过决策树。然而,决策树机器学习模型的不同之处在于,它们使用逻辑和数学来生成规则,而不是根据直觉和主观性来选择规则。
算法
在尝试构建决策树时,应该立即想到的问题是:
我们应该在什么基础上做决定?
换句话说,我们应该选择什么作为是或否问题来对我们的数据进行分类。我们可以进行有根据的猜测(即所有体重超过 5 磅的小鼠都是肥胖的)。然而,这不一定是对我们的样本进行分类的最佳方式。如果我们可以使用某种机器学习算法来学习问什么问题,以便在分类数据方面做得最好,会怎么样?这就是决策树模型背后的目的。
假设我们试图建立一个决策树来预测一个人是否结婚。因此,我们在附近挨家挨户地敲门,礼貌地请他们为我们的小研究项目提供他们的年龄、性别和收入。在我们询问的几千人中,有 240 人没有把我们拒之门外。
现在,在我们继续之前,掌握以下术语很重要。树的顶部(或者底部,取决于你如何看待它)被称为根节点。中间节点有指向和远离它们的箭头。最后,树底部没有任何边缘指向远离它们的节点被称为叶。叶子告诉你每个样本属于哪一类。
回到我们的例子,我们需要弄清楚如何从数据表到决策树。我们决定使用机器学习算法来为我们构建决策树,而不是自己选择分支。该模型着眼于每个特征如何区分已婚和未婚人群。由于收入是一个连续变量,我们设置一个任意值。
为了确定三个分裂中哪一个更好,我们引入一个叫做 杂质的概念。 杂质是指没有一片叶子有 100%的“是嫁”。有几种方法可以测量杂质(分割的质量),然而,默认情况下,DecisionTreeClassifer
的scikit-learn
实现使用 gini ,因此,这就是我们在本文中要讨论的。
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
为了计算左叶的基尼系数,我们用已婚人口比例的平方和未婚人口比例的平方减去 1。
等式对于右叶的杂质是完全相同的。
节点本身的基尼系数等于 1 减去左子节点的样本分数,再减去右子节点的样本分数。
信息增益(带基尼指数)写如下。
这个过程在收入和性别上重复进行。我们最终决定具有最大信息增益的分割。在这种情况下,这是收入,这是有道理的,因为收入超过 5 万英镑和已婚之间有很强的相关性。如果我们马上问这个问题,我们就向正确分类数据迈出了一大步。
一旦我们决定了根,我们对树中的其他节点重复这个过程。值得注意的是:
a)我们可以在收入上再次平分
b)每个分支中的样本数量可以不同
我们不能无限期地分开。因此,我们需要一种方法来告诉树何时停止。DecisionTreeClassifer
的scikit-learn
实现使用最小杂质减少量来确定是否应该分割节点。
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html
假设我们在更多的迭代之后,我们在树的左侧得到了下面的节点。
结果大于默认阈值 0。因此,节点将被拆分。如果它低于 0,节点的子节点将被视为树叶。
Python 代码
让我们看看如何用 Python 实现决策树分类器。首先,我们导入以下库。
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.tree import export_graphviz
from sklearn.externals.six import StringIO
from IPython.display import Image
from pydot import graph_from_dot_data
import pandas as pd
import numpy as np
在本教程中,我们将使用机器学习领域最流行的数据集,来自加州大学欧文分校机器学习知识库的虹膜数据集。
iris = load_iris()
X = pd.DataFrame(iris.data, columns=iris.feature_names)
y = pd.Categorical.from_codes(iris.target, iris.target_names)
在接下来的部分中,我们将尝试构建一个决策树分类器,根据花的尺寸来确定花的种类。
X.head()
尽管决策树可以处理分类数据,但我们仍然根据数字对目标进行编码(即 setosa=0,versicolor=1,virginica=2 ),以便在稍后创建混淆矩阵。幸运的是,pandas
图书馆为此提供了一种方法。
y = pd.get_dummies(y)
我们需要评估模型的性能。因此,我们留出四分之一的数据进行测试。
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
接下来,我们创建并训练一个DecisionTreeClassifer
类的实例。我们提供 y 值是因为我们的模型使用了监督机器学习算法。
dt = DecisionTreeClassifier()dt.fit(X_train, y_train)
我们可以通过运行下面的代码块来查看模型生成的实际决策树。
dot_data = StringIO()export_graphviz(dt, out_file=dot_data, feature_names=iris.feature_names)(graph, ) = graph_from_dot_data(dot_data.getvalue())Image(graph.create_png())
请注意它是如何提供基尼系数杂质、样本总数、分类标准以及左侧/右侧的样本数的。
让我们看看我们的决策树在测试数据面前表现如何。
y_pred = dt.predict(X_test)
如果这是一个回归问题,我们将使用某种损失函数,如均方差(MSE)。然而,由于这是一个分类问题,我们利用混淆矩阵来衡量我们的模型的准确性。混淆矩阵最好用一个例子来解释。
假设你的朋友刚刚做了怀孕测试。结果可能属于以下 4 个类别之一。
真阳性:
解读:你预测的是正的,这是真的。
你预言一个女人怀孕了,她真的怀孕了。
真阴性:
解读:你预测的是负数,这是真的。
你预言一个男人不会怀孕,他实际上也没有。
假阳性:(1 型错误)
解读:你预测的是正的,是假的。
你预言一个男人怀孕了,但他实际上没有。
假阴性:(2 型错误)
解读:你预测的是负数,这是假的。
你预测一个女人不会怀孕,但她确实怀孕了。
也就是说,混淆矩阵对角线上的数字对应着正确的预测。当有两个以上的潜在结果时,我们简单地扩展混淆矩阵中的列和行的数量。
species = np.array(y_test).argmax(axis=1)
predictions = np.array(y_pred).argmax(axis=1)
confusion_matrix(species, predictions)
正如我们所看到的,我们的决策树分类器正确地分类了 37/38 株植物。
结论
决策树很容易解释,不需要任何规范化,并且可以应用于回归和分类问题。不幸的是,决策树在实践中很少使用,因为它们不能很好地概括。请继续关注下一篇文章,我们将讨论随机森林,这是一种组合多个决策树以实现更高准确性的方法。
决策树:第 1/2 部分
原文:https://towardsdatascience.com/decision-tree-overview-with-no-maths-66b256281e2b?source=collection_archive---------15-----------------------
培养对决策树的直觉
Photo by Subtle Cinematics on Unsplash
大约 70 年前,我发明了决策树,它是最古老的机器学习算法之一,现在用于预测建模。它们可能是最容易理解的 ML 算法之一,但是不要让它的简单性欺骗了你,让你低估了它的能力。
🌰简单地
这篇文章旨在建立一个关于决策树的直觉。我们将讨论线性可分和不可分数据集、决策边界和区域,解释为什么决策边界平行于轴,并指出使用决策树的优点和问题(以及补救措施)。
所以让我们开始吧!
Photo by Victor Rodriguez on Unsplash
优点:
决策树是最容易理解的算法之一,你可以很容易地解释它们的推理,因为它们属于“白盒”方法。它们足够强大以适应复杂数据集,并且足够通用以至于它们可以用于分类以及回归任务而不需要太多的数据预处理。
此外,决策树是广泛使用的“随机森林”方法的构建模块,这是当今最强大的机器学习算法之一。
与线性模型不同,决策树可以线性拟合不可分的数据集。不可分数据集是指不同类的数据点不能用一条线分开的数据集,而线性可分数据集则用一条线就足够了。下图描述了这些情况:
Figure 1
在图 1 中,左边的图表显示了线性分类器如何确定其决策边界——虚线。右边的一个表示决策树如何构造它的决策边界来适应线性不可分的数据集。
轴平行决策边界
您可能会注意到,决策树做出的决策边界与轴平行,并且它们总是这样:与轴平行。其原因是决策树基于特征值分割数据,并且该值在一个决策边界内始终保持不变,例如 x=2 或 y=3 ,其中 x 和 y 是两个不同的特征。而在线性分类器中,判定边界可以是例如:y=mx+c
在决策树中,为每个决策区域迭代地绘制这些决策边界,并构建一棵树。要获得直观的解释,请按照下面的一系列图表进行操作!👇
划清界限!
让我们看看下面的例子,看看这是如何发生的,只用我们人类的本能,而不是数学!
Dataset to fit the decision tree on along with its corresponding tree structure
称为“根节点”的树的第一个节点分别包含所有类的实例数。
基本上,我们必须画一条称为“决策边界”的线,将不同类的实例分成称为“决策区域”的不同区域。请记住,这条线必须与轴线平行。
开始分吧!
第一个决策边界应该在上图的 X=3 处做出。
Photo by Abby Savage on Unsplash
以 X=3 为分界点,产生如下图。既然现在我们有了两个决策区域,我们将把这两个区域作为树的两个不同节点添加,其中每个节点包含相应实例的数量。
Split point is X=3
因为一个决策区域应该包含一个类的绝大多数,所以我们需要进一步划分。我们将在 Y=2 处分割结果图的左侧区域。右区跟着 Y=2.5 。
Split point is Y=2
The split point is Y=2.5
现在,每个决策区域只包含一个类的实例,这是我们停止分裂的提示(因为我们没有定义任何其他停止标准)。
⚠️请注意,不设置其他停止标准可能对你的模型有害。(下文详述)
缺点:
Photo by Tim Collins on Unsplash
👎过度拟合
这里需要注意的是,正如我们上面所做的,分裂到最后一个实例并不是停止分裂的唯一标准。事实上,这可能会导致过度拟合的模型。
过拟合模型:模型对数据的学习非常好,以至于它不能很好地对看不见的数据进行归纳。
💡修复:停止的一些其他条件可以是树的深度、节点在进一步分裂之前必须具有的最小实例数、或者多数类或少数类之间的比率,例如,如果 80%的数据点属于一个类,则停止分裂以避免过度拟合。
Image source: Hands-On Machine Learning with Scikit-Learn & TensorFlow
👎不稳定
由于决策树使轴平行于边界,所以它们对数据旋转很敏感。看看下面的图表。可以很容易地被一条对角线分割的数据被多个决策边界分割,我们几乎可以通过观察就可以看出,对于这个特定的问题,更简单的模型会概括得更好。
Image source: Hands-On Machine Learning with Scikit-Learn & TensorFlow
💡修复:这个问题可以通过使用像 PCA 这样的降维技术来限制,它可以更好地确定数据的方向。
💡修复:一般来说,决策树对微小的数据变化很敏感,会导致不同的树结构。通过一起使用大量决策树并对它们的预测值进行平均并将其用作最终预测,可以增强决策树的健壮性。这种分类器被称为随机森林。
优点仍然大于缺点,通过一些超参数调整,决策树可以表现得非常好。
Photo by Raul Varzar on Unsplash
在我接受的所有与数据科学相关的采访中,几乎每次都有人要求我解释决策树算法。所以,我决定写一篇文章,集中在树的方面,通常没有给予太多的关注。
如果你想了解更多关于决策树及其背后的数学知识,你可以查看本系列的 第二部分 。在那里,我们将讨论寻找最佳分割的熵和信息增益及其背后的数学原理。至于这个帖子,那都是乡亲们!
如果你觉得这篇文章有帮助,请鼓掌👏拍手可以让更多的人看到一个帖子。🐦
如果您有任何问题或建议,请随时在下面发表。你也可以在 Linkedin 上和我联系。💼
直到那时和平结束。 ✌
决策树:第二部分
原文:https://towardsdatascience.com/decision-tree-part-2-34b31b1dc328?source=collection_archive---------9-----------------------
手动计算熵和信息增益
Photo by Subtle Cinematics on Unsplash
T 他的文章是“决策树”系列的第二篇,本系列的 第一篇 发展了关于决策树的直觉,并给你一个在哪里画决策边界的想法。在这篇文章中,我们将看到决策树是如何做到这一点的。
🙊 剧透: 这涉及到一些数学。
我们将使用一个非常小的数据集,以便于可视化和跟踪。然而,在实践中,这样的数据集肯定会过度拟合。这个数据集决定你是否应该买一辆有 3 个特征的车:年龄,里程,以及这辆车是否是路试。
在上一篇文章中,我们仅通过查看图表来绘制决策边界。但是树做不到这一点。作为人类的好处,对吧?决策树使用熵来寻找分割点和要分割的特征。
熵
熵的定义是缺乏秩序或可预测性。在一堆例子中,它是杂质的量度。如果节点只有一个类的实例,那么它就是最纯的。
其中 n =特征数量
i =特征
P =概率 i
为每个特征计算熵,并且选择产生最小值的一个用于分割。熵的数学范围是从 0 到 1。
我们开始吧!
现在让我们把它付诸实践。为每个节点计算熵。第一个节点,即根节点,总是具有数据集中的所有示例。
正如你所看到的,父节点的熵是 1 。请记住这个值,我们将在接下来的步骤中计算信息增益时使用它。
信息增益
下一步是找到信息增益(IG),它的值也在 0-1 的范围内。信息增益帮助树决定分割哪个特征:给出最大信息增益的特征。我们现在将逐个计算每个特征的信息增益。对于这个迭代,父节点的熵是我们上面计算的 1。
在上图中,我们可以看到左边子节点的熵是 1,因为类实例的比率是 1:1。这是最不纯的一个节点。右边的子节点也是如此。
这里,子节点的熵值为 0,因为每个子节点只有一个类的实例:最纯粹的节点。
总而言之,下表显示了每个特征的信息增益:
Information gain for every feature
最大信息增益是针对特征“路试”的,因此我们将选择它作为我们的第一个分割特征。这样做将生成下面给出的树结构:
由于叶节点的熵为零,我们将停止切割。如果不是这种情况,那么我们将继续寻找前面的父节点和子节点的信息增益,直到满足任何一个停止标准。
基尼杂质
和熵一样,基尼杂质也是计算节点杂质的一种度量,具有相同的数学范围[0–1]。其中 1 表示最大杂质,0 表示最小杂质。
Image source: Hands-On Machine Learning with Scikit-Learn & TensorFlow
基尼还是熵?
Photo by Joshua J. Cotten on Unsplash
也可以用基尼杂质代替熵。尽管如此,无论您使用哪一种,结果都不会有太大的不同。但是计算 Gini 杂质比熵稍微快一点。熵产生更平衡的树,而基尼不纯倾向于将多数阶级分成自己的分支。
Photo by Hanny Naibaho on Unsplash
如果您有任何问题或建议,请随时在下面发表。你也可以在 Linkedin 上和我联系。💼
直到那时和平结束。 ✌
决策树和恐龙
原文:https://towardsdatascience.com/decision-trees-and-dinosaurs-c14339a37ad8?source=collection_archive---------23-----------------------
计算机如何思考:第一部分
想象你和我一起计划一次旅行。这次旅行需要很多准备,因为这是一次穿越时间的旅行,到地球遥远的史前时代。我们的旅行是一次观光探险。我们计划去看各种奇妙的生物,尤其是原始动物展览中的明星,恐龙。但是我们必须小心!这不是去动物园!恐龙看到我们的次数和我们看到它们的次数一样多,而且并不是所有的恐龙都有善良的意图。如果我们不想被这个古老世界的居民打扰,我们就必须准确地区分恐龙的两个主要分支:无害的食草动物,当我们看着它们时,它们可能会简单地盯着我们;以及致命的食肉动物,它们更喜欢吃我们。
This could be us
如何最好地实现这种朋友和敌人的确定?恐龙有很多种,其中一些鲜为人知,对它们进行详尽的研究是不切实际的。在侏罗纪时代,我们将无法获得电力或互联网,即使我们能够记住目前科学已知的每个物种的每个细节,任何未知物种对我们来说都将是一个完全的谜。我们需要能从我们现在所知道的东西中归纳出一些东西来处理新的情况。我们需要的是一些能适用于这个问题的简单规则。我们将创建一个“模型”——一套规则——来帮助我们更容易地做出决定,而不是学习恐龙生物学的每个细节。在计算机处理数据的帮助下,我们可以提出一套识别恐龙饮食的最佳规则,让我们能够安全地穿越时间,而不必在我们的时间机器中打包一堆百科全书。
这类问题的名称是“分类”,它是广泛采用的计算机学习的最早例子之一。它的应用包括识别收件箱中的垃圾邮件,为电话销售人员标记可能的线索,最复杂的是,从照片中识别人脸。
为了防止我们的史前冒险以死于食肉爬行动物的口中而告终,我们将构建一个“两类决策树分类器”,这是一个极其简单的模型,通过几个数字输入,它将告诉我们任何给定的恐龙物种是无害的好奇心,还是致命的威胁。它是“两个纲”,因为它只确定了两个不同的恐龙纲:食肉恐龙或非食肉恐龙。它是一个“决策树”,因为它用来区分这两个类别的方法采取了一系列分支决策的形式,就像一个流程图(或一棵树),引导我们做出关于最可能的类别的决策。
这种计算机辅助分类的核心是一种洞察力,即在一些聪明的数学的帮助下,计算机可以比人更准确地找到一组数据中的模式。我们可以让专家检查每个恐龙物种,记录它们的饮食偏好,然后每当我们遇到新的恐龙,翻阅我们的年鉴,直到我们找到这个物种的条目。但是对于书中没有的物种,我们就没那么幸运了。相反,我们可以让我们的人类专家教我们一套规则,通过这些规则我们可以做出决定。但是分析如此大量的数据,权衡每一个异常和排列,是一项巨大的任务,而人类往往做得很差。计算机可以更快、更准确地完成同样的工作,并处理大量数据,其规模甚至是人类无法尝试的。
为了开始构建一个分类器,我们必须收集一些关于一组恐龙物种的事实,并以这样一种方式对其进行编码,以使其适合我们的算法。我们将制作一个表,其中每一行代表一只恐龙,每一列是一个数值,代表关于那只恐龙的一些信息。因此,举例来说,侏罗纪时期温和的巨人剑龙和白垩纪晚期凶残的暴君霸王龙可以用下面两行来表示:
Table One: Data for two dinosaur species
您会注意到,这些数据中有一些是以稍微不同寻常的方式表示的。我们没有一个名为“步态”或类似的包含“两足动物”或“四足动物”的列,而是有一个名为“两足动物”的列,包含 1(这种恐龙是两足动物)或 0(它不是两足动物)。这将类别编码为算法能够解释的数字格式。
我收集了 20 种最著名的恐龙物种的信息来训练我们的分类器。这些恐龙包括食草恐龙和食肉恐龙、四足恐龙和两足恐龙、小型恐龙和大型恐龙,以及来自原始侏罗纪茂盛丛林和白垩纪晚期茂密森林的恐龙。
在这些方面,我让决策树算法——一系列重复的简单步骤——来完成它的工作。这个算法非常简单,我们自己也可以遵循:
我们检查了数据表中的每一列,找到了单个列,以及该列的单个值,这最能区分食肉动物和它们的食叶兄弟。在本例中,它是“两足动物”列。四足恐龙是严格的素食者,在我们目前的数据中没有例外。这个决策成为我们决策树的“主干”——第一个决策节点,其他决策从这个节点分支。对于我们的四足动物,算法是完整的,不需要进一步的决定。但是对于两足动物,我们剩下的是食肉动物和食草动物的混合体,我们必须构建额外的节点。在这种情况下,其余示例的最佳分割是测量主体的长度。如果你的恐龙从鼻子到尾巴超过 12 米,那么你就有麻烦了——它是食肉动物,你拿着梯子和卷尺站在它旁边。然而,较小的两足动物仍然是食肉动物和食草动物的混合体,我们可以继续构建节点。
最终的决策树有点像一本“选择你自己的冒险”的书。为了决定一只给定的恐龙是否安全,我们浏览节点,在每个节点上做一个选择,直到我们到达一个“叶子”节点,它告诉我们最可能的类。这是树:
Figure One: Decision tree diagram
算法已经学习了一些关于恐龙的规则:所有的四足动物都是食草动物,超过 12 米长的两足动物是食肉动物。对于 12 米以下的两足动物,最轻的(800 公斤以下)更可能是食肉动物,较重的是食草动物。
这对我们 20 只恐龙来说很好,但是这些规则在野外会有多好呢?我们会度过一次平静而愉快的时光之旅吗?还是我们的假期会被一只巨大爬行动物意想不到的胃口所破坏?我们可以通过找到一组新的恐龙来测试这一点,用我们学到的这些规则进行分类,并检查我们正确预测了多少。请记住,我们在模型中寻找的关键品质之一是通用性。即使我们找到了所有已知恐龙物种的数据,在遥远的过去,我们肯定会遇到各种迄今未发现的物种。我们希望尽最大努力确保我们的模式也适用于他们。
为了测试这一点,我列出了另一个稍微不太常见的恐龙列表,并通过决策树模型运行它们,根据它们的步态(两足与四足)、长度和重量对它们进行预测。结果是……不好。
恐爪龙和阿尔伯特龙被正确地归类为食肉动物(虽然,后者的大小和火鸡差不多,不太可能构成太大的威胁)。同样,根据龙的四足步态,甲龙被正确地归类为食草动物。但是无害的厚头龙,其加厚的头骨被认为是为了用头撞击竞争对手,被归类为食肉动物——它不到 12 米,体重超过 800 公斤。更麻烦的是,三种危险的食肉动物,阿尔伯特龙、巨龙和阳川龙都被归类为食草动物,这可能会给我们带来一个不受欢迎的惊喜。
Yangchuanosaurus. I hadn’t heard of it either.
我们的模型出了问题!实际情况是,该算法学习了一种偶然出现在我们数据中的模式,但并没有推广到更广泛的人群。虽然我们的训练数据中很少有小而重的食肉动物,但事实上它们很常见。这是许多算法的弱点,尤其是决策树,尤其是对于这样一个小数据集。当你有少量的例子可以学习,并且有大量不同的方法可以将这些例子分开——按重量,按长度,等等,那么就很容易找到虚假的规则。
该算法发现四足动物普遍是素食者,这一规则似乎也适用于我们数据集之外的其他物种。但是关于重量和长度的规则似乎很可疑。算法发现的分界线——12 米的长度和 800 公斤的重量——似乎不太可能是恐龙进化的一般规则,更有可能是哪个物种碰巧被纳入我们的数据的一个意外。
我们有几个选项来尝试解决这个问题:
我们可以添加更多的数据。有了更多的数据,找到偶然模式的机会就少了,我们更有可能发现恐龙的真正规律。但是获取更多的数据可能会很困难,而且也不能保证我们会找到我们想要的规则——我们正在查看的特征(重量、长度等)中可能不存在真正的模式。
我们可以尝试不同的算法。我们可以用很多其他的方法来建立分类模型,其中很多不像我们的决策树那样容易发现任意的规则。但是这些算法要复杂得多,为了本章的目的,我想把重点放在这个非常简单的方法上。
第三个选项,也是我们将选择的选项,是寻找新的特性添加到我们的数据中。这意味着在我们的化石中找到更多关于恐龙的信息,并将其添加到我们已经知道的信息中。有希望的是,这些新信息将更有助于建立关于食肉恐龙和食草恐龙的通用规则。
这让我进入了令人困惑和有争议的恐龙进化世界。古生物学中几乎没有无懈可击的正统学说,甚至连恐龙的基本家谱也不断地被连根拔起、重新种植、嫁接和修剪。
然而有几个主题保持不变。恐龙谱系的主要分界线在蜥龙类和鸟龙类之间。这些贵族住宅主要根据臀部的方向来划分——“蜥蜴臀”的蜥脚类恐龙保持臀部向下并远离身体,而“鸟类臀”的鸟臀目恐龙更喜欢臀部朝后,与现代鸟类的方向相似。然而,令人困惑的是,是蜥脚类动物成为了今天鸟类的祖先,而不是表面上更相似的鸟臀目动物。
对我们的分析有用的是,它是蜥蜴类的一个分支,代表了大量的食肉恐龙。蜥蜴类的这个分支,兽脚亚目恐龙,在它们的数量中既有纤细小巧的恐爪龙,也有体型巨大健壮的霸王龙。兽脚亚目恐龙几乎完全是肉食动物。如果我们能确定兽脚亚目恐龙的共同特征,我们就能极大地改善我们模型的性能。
我添加的第一个额外功能是一个简单的“每米吨数”计算,我推断,虽然之前的模型发现的关于重量和长度的规则可能不成立,但食肉恐龙的体型可能存在差异,一般来说,它们的体型可能比食草恐龙更重或更轻。
我还观察了一些恐龙更奇特的特征。剑龙有板状的刺,这被认为是为了展示或防御,或者可能是调节热量。副栉龙,我最喜欢的恐龙,有一个鼻冠,这被认为是允许它发出响亮的交配叫声,或者它可能有一个装饰性的褶边。我希望,食草动物可能更有可能具有这些防御或展示特征,因为它们更多地生活在群体中,不得不保护自己免受捕食者的伤害。
Parasaurolophus. The best dinosaur.
最后,也许是有争议的,根据目前的研究,我研究了哪些物种被认为有大量的羽毛。这份名单包括了数量惊人的众所周知的恐龙。事实证明,这也非常复杂,仍有几个问题存在争议。
但这是一条充满希望的道路!我们食草的鸟臀目动物都有鳞片或覆盖着丝状毛发。笨重的蜥脚类动物普遍有鳞。只有在食肉兽脚亚目恐龙中,我们才发现像现代鸟类一样的有翼羽毛,现在人们认为这种“羽状体被”(或“绒毛外套”)可能使可怕的霸王龙及其亲属更像一只巨大的毛茸茸的火鸡。
将这些添加的数据编码到我的数据中,我重新运行决策树算法,让它重新计算拆分数据行的最佳方式,以区分食草动物和食肉动物。
这是它生成的决策树:
Figure Two: A more effective tree
它发现的第一条规则和以前一样——四足恐龙从不食肉。但从那里开始,情况就大不一样了。所有长有羽毛的恐龙都是食肉动物,在那些幸存的无羽毛物种中,我们可以通过观察它们的体重与长度的比例来巧妙地将食草动物与食肉动物区分开来。
对照我们的测试集检查这些新规则,我们现在达到了完美的准确性,将无害的龙和厚头龙归类为食草动物,而危险的阿尔伯特龙、巨龙和阳川龙都被标记为食肉动物。有了这个新的分类系统,我们可以满怀信心地穿越史前史。我们可以在一张纸上画出这个流程图,带上卷尺和一套结实的天平,启动时间机器,然后出发。
但是真的这么简单吗?在测试了我们的模型并获得了完美的准确性之后,我们可能会假设我们将在实践中继续获得类似的结果。这是一个危险的假设。
任何分类模型的好坏取决于对其进行训练的数据以及对该数据所做的假设。任何模型中都隐含着无数的偏见、盲点和疏忽,这个模型也不例外。
例如,如果在一次即兴的史前游泳探险中,我们遇到了蛇颈龙,我们将很难用我们的模型将其分类。到底是不是两足动物?它很可能是由前侏罗纪二叠纪或三叠纪时期的四足鳄鱼祖先进化而来,但在侏罗纪,它用四只巨大的鳍状肢游泳。我们的模型是在陆地物种上训练的,对于如何对水生恐龙进行分类却保持沉默。
同样,我们的模型假设恐龙来自白垩纪或侏罗纪。更早的二叠纪是类似恐龙的突触体(事实上更接近哺乳动物)的家园,如帆背和食肉的双足类恐龙。Dimetrodon 是食肉动物,像二叠纪的大多数顶级食肉动物一样,是四足动物。去二叠纪的旅行者会被我们的模型严重误导。
更阴险的是我们的模型中的偏见,这些偏见是我们看不见的,因为模型是在文化或历史背景下创建的。我们的模型是在一些最知名的恐龙物种上训练的,等等知名的物种上,它表现的很好。但是,哪些物种广为人知,哪些不为人知,这是历史偶然事件的产物。古生物学主流发展的国家的本土恐龙几乎肯定会更出名。那些最先被发掘、鉴定和公布的少数物种不可避免地引起了公众的注意,这是最近的发现所没有的。
我们的模型告诉我们,有羽毛的两足动物总是食肉动物,这在美国和西欧发现的物种中很大程度上是正确的。但是最近的研究打乱了这个简洁的启发。这些发现包括西伯利亚恐龙,如长有羽毛的食草恐龙jianianhualongi,或 Kulindadromeus,一种长有羽毛状结构涂层的鸟臀目恐龙,以前被认为是兽脚亚目恐龙的专属物种。中国物种,如长爪、有绒毛的兽脚亚目食草恐龙兽暴龙,进一步混淆了画面。如果我们在中国和西伯利亚常见的恐龙物种上训练我们的模型,我们可能会创造出一个完全不同的模型,而希望参观他们祖国史前史的中国时间旅行者将不会被我们当前的算法所服务。
A friendly Therizinosaurus, a feathered herbivore
大多数分类算法的现代实现比我们在这里创建的简单模型要复杂得多。它们涉及更多的要素,对数据中的模式进行更复杂的解析,以及要学习的更大的数据集。这些模型中的许多都非常精确,它们的分类基于从数据中通过算法得出的规则,与人类驱动的决策相比具有无数优势。它们更快、更可靠、更一致,并且经常能够察觉到即使是观察力最敏锐的人也无法察觉的模式。
但是支撑我们简单恐龙模型的基本概念也适用于最复杂的分类器。该算法在给定的数据中发现模式,并使用这些模式来建立关于如何对新示例进行分类的规则。根据初始数据,该模型对更广泛的人群进行概括,这种概括就是它进行预测的方式。这些规则和归纳可能非常复杂,也非常准确,但它们只能和最初创建它们的数据以及对这些数据做出的假设一样好。这些复杂的模型和我们非常简单的模型一样容易受到偏见和限制。作为人类思维的产物,经过人类数据的训练,它们会受到人类易犯错误的影响。在我们穿越时空的旅行中,我们将把现代世界和它的失败抛在身后。但从某种意义上说,我们也会把它们带在身边,嵌入我们做出的假设中。
本文代码可以在这里找到 。
第二部分,“线性回归与线的继承”是 此处可用 。
决策树和随机森林:
原文:https://towardsdatascience.com/decision-trees-and-random-forests-74b89a374db?source=collection_archive---------17-----------------------
min _ 杂质 _ 减少是做什么的,应该怎么用?
Photo by Filip Zrnzević on Unsplash
在我学习决策树和随机森林的过程中,我注意到许多超参数被广泛讨论和使用。最大深度、最小样本叶等。,包括仅适用于随机森林的超级参数。一个似乎很少被关注的超参数是最小杂质减少。
最小杂质减少是什么意思,有什么作用?
要理解这一点,你首先要理解超参数的基本标准是什么。所用的标准是测量每次分裂的杂质,从而计算出通过分裂获得的信息。然后,它可以决定如何进行最佳分割。当杂质为 0 时,则该叶子中的所有项目都被正确分类。
关于基尼指数和熵的更长的解释可以在这篇文章中看到:
[## 基尼指数与信息熵
关于杂质测量和信息增益,您需要了解的一切
towardsdatascience.com](/gini-index-vs-information-entropy-7a7e4fed3fcb)
min _ infinity _ decrease 的作用是在分解的减少额小于输入额时停止分解。当我们继续将它形象化时,这将更容易理解。
可视化决策树以查看正在进行哪些拆分
让我们看看我用虹膜数据集和所有默认的超参数做的决策树。请注意,由于这个数据集的情况,从这个树上得到的分数对于训练和测试来说几乎是完美的。因此,我不会在本文中显示每个模型运行的分数,我只是试图展示如何使用 min _ infinity _ decrease 超参数。
这是训练数据的决策树的可视化,每个节点和叶都有基尼指数:
在训练集中有 120 个样本,我们试图对 3 种类型的虹膜进行分类。第一次拆分右侧的值= [0,41,39]意味着第一组中没有任何项目被错误分类,第二组和第三组中的项目数量几乎相等。因此,该节点的杂质被舍入到 0.5,这意味着它们中的大约一半被正确分类,而大约一半被错误分类。
我们在建模中试图最小化的事情之一是过度拟合。其原因是,如果我们过度适应我们的训练数据,那么我们可能会对我们的测试数据或真实数据进行错误分类。因此,我们希望尽量减少分裂成很小数量的叶子。
这也是最小杂质减少可以帮助我们的地方。如果分裂的不纯度上升,那么这将意味着我们正在进行分裂,这对我们没有帮助,而是过度适应训练数据。
让我们看看上面决策树中的一个例子:
这是正在进行的第三级分割。
从右侧可以看出,我们对 5 个分类错误的项目进行了拆分。在这条分界线的左边,有 4 个正确的和 4 个不正确的,基尼系数为 0.5。在右边,有 34 个正确的和 1 个不正确的。
我们似乎在这方面做得太多了,而且这样做并没有获得太多。
在左边,我们有 36 个正确的和一个不正确的,然后我们做一个分割来捕捉最后一个。这也过度拟合了我们的训练数据。
我们如何处理这两种分裂?
最小杂质减少量的计算
这个超参数是怎么计算出来的?如果我们检查它的文档,可以在这里找到,那么我们会看到这个:
min_impurity_decrease : float, optional (default=0.)A node will be split if this split induces a decrease of the impurity greater than or equal to this value.The weighted impurity decrease equation is the following::N_t / N * (impurity — N_t_R / N_t * right_impurity
— N_t_L / N_t * left_impurity)where ``N`` is the total number of samples, ``N_t`` is the number of
samples at the current node, ``N_t_L`` is the number of samples in the left child, and ``N_t_R`` is the number of samples in the right child.``N``, ``N_t``, ``N_t_R`` and ``N_t_L`` all refer to the weighted sum, if ``sample_weight`` is passed.
让我们分解这个计算,以便更好地理解它:
N _ t _ R/N _ t * right _ infinity:取分裂右侧的杂质,并根据来自节点的右侧分裂中的样本百分比对其进行加权。
N _ t _ L/N _ t * left _ infinity:取左侧分裂的杂质,用左侧分裂中样本占节点的百分比进行加权。
然后我们从节点杂质中减去这两者。
然后,我们根据节点中样本占样本总数的百分比对该数量进行加权。
让我们把它写在分割的右边:
43/120 * (.206 - 35/43 * .056 - 8/43*.5)
我们得到的总数是 0.024149999999999999998,或者四舍五入到 0.024。
43 是正在分裂的节点中的样本总数
120 是样本总数
206 是节点的杂质
35 是分裂右侧的样本总数
056 是分裂右侧的杂质
8 是分裂左侧的样本总数
5 是分裂左侧的杂质
手动计算这一切并不容易,我制作了一个函数,允许您输入上述数字,它将为您计算分裂的杂质:
def get_impurity_score(n=None, n_t=None, n_t_l=None, n_t_r=None, node_impurity=None, left_impurity=None, right_impurity=None):
'''
n = Total number of samples overall
n_t = Samples in the node you are checking out
n_t_l = Samples in the left split from the node
n_t_r = Samples in the right split from the node
node_impurity = Impurity score of the node
left_impurity = Impurity score of the left split from the node
right_impurity = Impurity score of the right split from the node
Returns impurity decrease total of the 2 splits from the node impurity weighted by the total number of samples
'''
if n == None or n_t == None or n_t_l == None or n_t_r == None or node_impurity == None or left_impurity == None or right_impurity == None:
print('-----error------ missing values. Check inputs') return(n_t / n * (node_impurity - (n_t_r / n_t * right_impurity) - (n_t_l / n_t * left_impurity)))
左侧分离的杂质分数为 0.016341666666666666666,或四舍五入至 0.016。
用这个来修复我们的决策树
如果我们现在将最小杂质减少量设置为 0.025,则不会发生分裂,并且我们将减少模型中的过拟合。
我们更新的树:
我们现在确实阻止了这两种分裂的发生,以帮助防止我们的决策树过度拟合。
在随机森林中使用最小杂质减少
要在随机森林中使用它,我建议使用 GridsearchCV 来帮助找到对您试图构建的模型有益的超参数。
一般来说,我会建议使用这个和其他超参数来防止过度拟合。
我希望这有助于你理解最小杂质减少和如何使用它。如果您有任何问题或意见,请在下面的评论区提出。
决策树
原文:https://towardsdatascience.com/decision-trees-d07e0f420175?source=collection_archive---------3-----------------------
映射的概念:
0.引言。
- 什么是决策树?
- 为什么要使用决策树?
1.CART 是如何工作的?
- 购物车中使用的术语。
- 几何分析。
- 直觉发展。
2.什么是熵值法?
- 用图形表示。
- 数学公式&解释。
3.信息增益。
- 数学公式&解释。
4.基尼杂质。
- 为什么基尼不纯比熵好?
5.纯节点的概念。
6.购物车中的过装和欠装。
7.停止标准。
- 克服过拟合&欠拟合的方法。
8.推车的优点。
9.推车的缺点。
10.正在为购物车准备数据。
- 如何进行数值特征的拆分?
- 列标准化的效果。
- 如何处理分类特征?
- 什么是决策树桩?
- 不平衡类的效果。
- 高维度的效果。
- 离群值的影响。
- 如何确定特征重要性?
0.简介:
在深入决策树的理论概念之前,让我们先澄清什么是决策树?以及我们为什么要使用它们。
什么是决策树?
决策树是由 Leo brei man提出来的,在现代也被称为 分类和回归树(CART) 。它们是有预定义目标变量的监督学习算法&,主要用于简单线性决策面的非线性决策。换句话说,它们适用于解决手边的任何类型的问题(分类或回归)。
为什么要使用决策树?
最好也是最常用的监督学习方法之一 是基于树的算法。它们 赋予预测建模 以 更高的准确性、更好的稳定性,并提供了易于解释的 。与线性建模技术不同,它们很好地映射了非线性关系。决策树、随机森林、梯度推进等方法在各种数据科学问题中得到了广泛应用。因此,对于每个分析师来说,学习这些算法并在建模时应用它们是很重要的。
1.CART 是如何工作的?
考虑下面给出的一个非常基本的例子,该例子使用 NFL 数据集 来预测球员是否会触地得分。下面的模型使用了 数据集中的 3 个特征/属性/列,即身高、速度和力量。
在这个问题中,我们需要根据三者之间高度重要的输入变量来隔离将在比赛期间得分的球员。这就是决策树帮助的地方,它将基于三个变量的所有值隔离玩家,并识别变量,这创建了玩家的最佳同质集合(彼此异质)。
- 所用术语:
决策树由 根/内部节点 组成,其进一步分裂成 决策节点/分支 ,根据分支的结果形成下一个分支或 终端/叶节点 。
- 直觉发展:
或者,我们可以认为决策树是一组嵌套的 IF-ELSE 条件 的集合,它们可以被建模为一棵树,其中在内部节点做出决策,在叶节点获得输出。
NESTED IF..ELIF..ELSE
- 几何类比:
几何上我们可以认为 决策树是一组轴平行的超平面,在推理过程中将空间划分为多个超立方体。 我们根据点属于哪个超立方体来对点进行分类。
Axis-parallel hyperplanes.
2.什么是熵值法?
创建决策树只是选择在树的每个节点上应该测试哪个属性的问题。然而,信息增益是将用于决定在每个节点应该测试哪个属性/特征的度量。信息增益本身是使用称为熵的度量来计算的,我们首先为二元决策问题的情况定义熵,然后为一般情况定义熵。我们首先为二元决策问题定义熵的原因是因为它更容易理解它试图计算什么。汤姆·米切尔说得很好:
“为了精确定义信息增益,我们首先定义信息论中常用的一种度量,称为熵,它表征任意样本集合的(不)纯度。”
- 图示:
数学上,熵可以表示为:
- 方程式说明:
这个度量满足我们的标准,因为有了 -plog2(p) 结构:当 p 接近于零时(即类别中只有几个例子),那么 log(p) 就变成了一个大负数,但是 p 部分在计算中占主导地位,所以熵计算出来接近于零。记住熵是计算数据中的无序度的,这个低分数是好的,因为它反映了我们想要奖励例子很少的类别。类似地,如果 p 接近 1(即,该类别具有中的大部分示例),那么 log(p) 部分非常接近 0,并且“p”再次主导计算,因此整体值接近 0。因此,我们看到,当类别几乎或完全为空时,或者当类别几乎包含或完全包含所有示例时,类别的得分接近于零,这是我们想要的模型。注意 0ln(0)按惯例取为零。**
3.信息增益
让我们回到尝试确定为树中的特定节点选择最佳特征的问题。下述方法计算给定特征(A)的数值。关于一组示例。注意,属性 A 的值将在我们称为值(A)的一组可能性的范围内,并且,对于该组中的特定值 v,我们为属性 A 具有值 v 的示例组写 Sv。
属性 A 相对于示例集合 S 的信息增益计算如下:
基本上,信息增益取决于数据集被分割成属性后熵的减少。创建决策树围绕着寻找返回最高信息增益的属性的思想。
一般来说,如果所有的结果都有相同的可能性,如果一些结果比其他结果更有可能比熵减少,则熵最大。
4.基尼杂质:
基尼系数可以作为熵值法的替代方法。Gini 杂质是一种度量,用于衡量从集合中随机选择的元素被错误标记的频率,前提是根据子集中的标签分布对其进行随机标记。
数学上可以表示为:
基尼系数法中熵的计算方式相同,但熵涉及对数计算,基尼系数杂质涉及平方计算。由于计算平方比对数函数更便宜,我们更喜欢基尼系数杂质而不是熵。
5.纯节点的概念:
纯节点是其中所有数据点都属于同一类的节点,因此在这样的节点进行预测是非常容易的。
Here overcast is a pure node.
6.购物车中的超配和欠配:
过拟合和欠拟合的后果及其原因将在后面讨论(停止标准)。
- 树的深度越大,变化的可能性就越大(过度拟合)。
- 而树的深度越小,偏向树的可能性就越大(欠拟合)。
7.停止标准。
如果我们继续完全增长树,直到每个叶节点对应于最低的杂质,那么数据通常是过度拟合的。如果分割过早停止,训练数据的误差不会足够高,并且性能会由于偏差而受到影响。因此,在对决策树建模时,防止过拟合和欠拟合是至关重要的,这可以通过两种方式实现:
- 设置树大小的约束
- 树木修剪
- 设置树大小的约束:
- 为节点分裂提供最小数量的样本。
- 为终端节点(叶子)部署最小数量的样本。
- 允许树的最大深度(垂直深度)。
- 最大终端节点数。
- 分割时要考虑的最大特征。
2。树修剪:修剪是机器学习中的一种技术通过移除树的部分来减小决策树的大小。它还降低了最终分类器的复杂性,并因此通过减少过拟合来提高预测精度。修剪树木有两种方式:修剪前或修剪后。
——预修剪:
- 如果当前节点没有将熵提高至少某个预设(阈值)值,则停止分裂当前节点。
- 如果数据点的数量小于某个预设(阈值)值,则停止分区。
- 将树的深度限制在某个预设(阈值)值。
-剪后:
- 这可以通过首先允许树增长到其全部潜力,然后在计算每一层的交叉验证准确性之后修剪每一层的树来实现。
8.购物车的优势:
- 决策树可以固有地执行 多类分类 。
- 它们提供了 大多数模型的可解释性 ,因为它们只是一系列 if-else 条件。
- 它们既可以处理 数值 也可以处理 分类数据 。
- 特征间的非线性关系 不影响决策树的性能。
9.购物车的缺点:
- 数据集中的微小变化会使树结构不稳定,从而导致变化。
- 决策树学习者创建欠适应树* 如果某些类不平衡。因此,建议在拟合决策树之前平衡数据集。*
10.为购物车准备数据:
- 数字特征 的 分裂可以通过按升序对特征进行排序并尝试将每个值作为阈值点并计算每个值的信息增益作为阈值来执行。最后,如果获得的值等于给出最大 I.G .值的阈值,则欢呼..!!
- 特征缩放 (列标准化)不需要在决策树中执行。但是,它有助于数据可视化/操作,如果您打算将性能与其他数据或其他方法(如 SVM)进行比较,它可能会很有用。
- 为了让 处理决策树中的分类特征 ,我们绝不能对分类变量执行一次热编码,即使分类变量是名义变量,因为大多数库可以自动处理分类变量。如果需要,我们仍然可以为每个变量分配一个数字。
- 如果树的高度或深度正好是 1,那么这样的树称为 决策树桩。
- 不平衡类 确实对树的结构有不利影响,因此可以根据数据集使用上采样或下采样来避免。
- 除了偏斜的类之外, 高维度 也会对树的结构产生不利影响,如果维数非常高,这意味着我们有很多特征,这意味着在每个节点上找到分裂标准将耗费大量时间。
- 离群点也会影响 树的结构随着深度的增加树中离群点的几率增加。
- 特征重要性 可以通过计算每一层的归一化总和来确定,因为我们必须降低熵,然后我们选择有助于大幅降低熵的特征。因此,对于归一化总和最高的特征,我们可以认为它是最重要的特征。类似地,具有第二高归一化总和的特征可以被认为是第二重要的特征。
参考资料:
- 基于树的建模。
- 维基百科。
- 决策树学习
导师:
Harshall Lamba,新潘韦尔皮莱工程学院助理教授。
用于网上购物分析的决策树
原文:https://towardsdatascience.com/decision-trees-for-online-shopping-analysis-9010e84f0bb2?source=collection_archive---------12-----------------------
如今有一种使用在线购物解决方案的趋势,如亚马逊、易贝、全球速卖通。这些网站为卖家提供了一个向大量客户销售产品的平台。由于许多送货服务与这些在线购物平台相关联,因此来自不同国家的客户购买产品。与传统商店不同,每个卖家的评分和美誉度直接显示在购物平台上。因此,如果顾客不喜欢产品或产品有任何缺陷,卖家会让他们退货。如果顾客抱怨商品没有在承诺的期限内送达,一些卖家会全额退款。一些顾客滥用这些设施,欺骗销售者。因此,网络购物平台上的卖家遭受了巨大的利润损失。让我们讨论如何通过开发一个简单的机器学习模型来发现这些类型的客户;决策树。
如果你不熟悉决策树,可以看看这篇中型文章。快速回顾一下,决策树是机器学习中的一个模型,它包括我们对数据进行分类的条件(用于标记问题)。举个例子,想一个简单的情况,一个男人很开心,因为天气晴朗或者他在度假。这个场景的模型如下。注意,在这个模型中,你可以用天气和假期状况来预测这个男人的快乐程度。
A simple Decision Tree model
网购商品退货问题
当我参加 Datathon(数据黑客马拉松)比赛时,我从一家数据分析公司获得了一个包含在线购物平台详细信息的数据集。数据集经过编码,因此不会暴露客户和卖家的详细信息。然而,该数据集包括大量关于卖家、客户和产品的数据(以编码的方式)。上面提到的 datathon 的主要任务之一是发现项目返回模式。这包括经常返回的客户属性、一年中的月份、经常返回的商品详细信息和卖家详细信息。完整的数据集包括一年的完整数据。查看数据集架构以了解数据集。
Dataset schema
数据集加载和预处理
数据集非常庞大。即使它包含一年的数据,大小也大约是 25GB。被写成 4 个.csv
文件(一年每季度一个文件)。即使电脑有 16GB 内存和固态硬盘,文件也很难处理。因此, pandas python 包被用来分块读取数据集。
chunks = pd.read_csv('dataset/DataSet01.csv', chunksize=1000000)for chunk in chunks:
df = chunk
## Perform task on dataframe; df
请注意,chunksize
参数表示仅来自给定的 1000000 条记录。csv 文件被读取。当预处理数据、训练机器学习模型(这里是决策树)和测试模型时,我们可以逐块执行这些任务。
至于预处理,缺少属性的记录被忽略,因为有数百万条记录具有必需的属性。通过观察与退货的相关性,给定属性的子集被选择用于项目退货分析。请看这个 GitHub 库以获得更多关于相关性分析的细节和代码。最后,通过相关性分析和领域知识选择以下属性。
selected_atributes = [‘ONLINE_STORE_CATEGORY’, ‘SIZE_CDE’, ‘CLOR_CDE’, ‘SELLING_PRICE’, ‘PRODUCT_CLASS_02’, ‘FMALE_IND’, ‘MRYD_IND’, ‘BRAND_CODE’, ‘EDUC_LVL_NBR’, ‘MRYD’, ‘AGE’, ‘2017_M7_PURCHASE_AMT’, ‘2017_M7_RETURNED_AMT’,’PRODUCT_CLASS_01', ‘PRODUCT_CLASS_02’]
注意:这些属性包括商品的类别、尺寸、颜色、性别、年龄和顾客的婚姻状况、过去几个月的购买和退货金额、教育水平等。
构建决策树模型
让我们使用 sklearn 的决策树分类器来构建我们的决策树模型。
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn import metrics# load selected attributes and return indication as X and y
X = df[selected_atributes]
y = df.RETURN_INDICATION## Split dataset into training set and test set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # 70% training and 30% testmodel = DecisionTreeClassifier()# train the model
model= model.fit(X_train,y_train)# testing the model
y_pred = model.predict(X_test)# Accuracy calculation
print("Accuracy:", metrics.accuracy_score(y_test, y_pred))
保留所有的超参数默认值,我获得了 89%的准确率。您还可以通过更改官方文档中提到的参数来更改决策树的超参数。
可视化模型
现在,我们已经构建了决策树,我们希望看到客户记录被归类为退货或不退货的条件(决策)。决策树可视化是理解这些条件的好方法。让我们使用sklern.tree
中的plot_tree
选项来生成树。
tree.plot_tree(model, max_depth=5, filled=True)
注意max_depth=5
表示可视化树的前 5 个深度级别。我们的树非常复杂。因此,绘制完整的树需要大量的时间和内存。
您可以使用选项sklearn.tree.export.export_text
以文本形式导出树。这样,可以很容易地生成完整的树。
from sklearn.tree.export import export_text
r = export_text(model)
print(r)
进入 GitHub 库查看生成的情节和决策树的文本结构。
存储和重用模型
你可以使用pickle
来保存模型。
pickle.dump(clf, open('finalized_model.sav', 'wb'))
以及从转储文件中加载模型。
loaded_model = pickle.load(open('finalized_model.sav', 'rb'))
使用模型进行预测(使用模型)
要将给定的客户记录分类为退货或不退货,我们可以使用 sklearn 树模型中的predict
方法。请注意,您首先必须按照与您在模型构建步骤中相同的顺序加载相同的属性。让我们预测测试数据,因为我们将数据集分为训练集和测试集。
y_pred_loaded = loaded_model.predict(X_test)
这将返回一个预测列表(商品退货指示),可以将该列表与实际退货指示进行比较,以评估我们的模型。
print(“Accuracy:”, metrics.accuracy_score(y_test, y_pred_loaded))
>>> 0.96
更重要的是,我们可以用这个模型来预测一些看不见的数据。如网购商品退货问题小节所述,数据集有 4 个。csv 文件。我们已经使用第一个文件来训练我们的模型。让我们使用第四个文件来预测返回指示。请注意,我们使用 pandas 来分块加载数据。
selected_atributes= ['ONLINE_STORE_CATEGORY', 'SIZE_CDE', 'CLOR_CDE', 'SELLING_PRICE', 'PRODUCT_CLASS_02', 'FMALE_IND', 'MRYD_IND', 'BRAND_CODE', 'EDUC_LVL_NBR', 'MRYD', 'AGE', '2017_M7_PURCHASE_AMT', '2017_M7_RETURNED_AMT','PRODUCT_CLASS_01', 'PRODUCT_CLASS_02']
chunks = pd.read_csv('dataset/DataSet04.csv',chunksize=1000000)i = 0
for chunk in chunks:
i = i +1
if(i>10):
break
df = chunk# load features and target seperately
X_test = df[selected_atributes]
y_test = df.RETURN_INDICATION
y_pred = loaded_model.predict(X_test)
print("Accuracy for chunk ", i, metrics.accuracy_score(y_test, y_pred))>>> Accuracy for chunk 1 0.865241
>>> Accuracy for chunk 2 0.860326
>>> Accuracy for chunk 3 0.859471
>>> Accuracy for chunk 4 0.853036
>>> Accuracy for chunk 5 0.852454
>>> Accuracy for chunk 6 0.859550
>>> Accuracy for chunk 7 0.869302
>>> Accuracy for chunk 8 0.866371
>>> Accuracy for chunk 9 0.867436
>>> Accuracy for chunk 10 0.89067
在测试步骤中,我们获得了 96%的准确率。然而,这将导致 80 年代中期的精度。这是因为该模型在一年的第一季度过度适应了季节变化。(回想一下,我们只使用第一个。4 个文件的 csv 文件)因此,它没有捕获一年最后一个季度的季节性变化。然而,在使用所有 4 个训练模型之后。csv 文件可以解决这个问题。您仍然可以从所有 4 个小块中加载数据。csv 文件并训练模型。
在这个 GitHub 库查看代码。希望这篇文章对你有用。
决策树—简介(ID3)
原文:https://towardsdatascience.com/decision-trees-introduction-id3-8447fd5213e9?source=collection_archive---------10-----------------------
你有没有想过如何从过去的经验中学习?
你一生中会遇到不同类型的人,经过一些经历后,你会知道你喜欢什么样的人,对吗?我的意思是,在与许多人有过几次经历之后,当你遇到一个新的人时,大多数时候你会知道你是否喜欢他们。你是怎么做到的?有了‘经验’!对吗?但是你不会一直将多年的经验保存在大脑的顶部,而不是感觉到一些简单快速的决策机制在你的大脑中工作。
因此,与其深入研究大脑的生物学,不如让我们尝试在更简单的层面上建立一个类似的机制。
假设在你与几个人相遇后,你不想让吸血鬼成为你未来的朋友:P
所以你列出了你遇到的几个人,他们的特征,以及他们是否是吸血鬼。( "?"在阴影中属性是因为你只在黑暗的条件下遇到那些人,所以你无法验证他们是否投下阴影)
在观察了这个数据之后,我们可能会得出一个像这棵树一样的幼稚模型,
因为有了那棵树的帮助,我们可以做出决定,所以我们称之为“决策树”。这个树必须满足给定数据集中的所有数据,我们希望它也能满足未来的输入。
但是我们怎么能做出这样的树呢?上面给出的树只是通过对数据的一些随机观察…
根据观察结果…
- 所有肤色苍白的人都不是吸血鬼。
- 所有面色红润吃大蒜的人都不是吸血鬼,如果他们不吃大蒜,那么他们就是吸血鬼。
- 所有肤色普通的人,如果他们没有影子或者我们不知道他们是否有影子,那么他们是吸血鬼,或者如果他们有影子,那么他们不是吸血鬼。
但是,这是建立决策树的正确方法吗?那棵树是我们能从给定的数据集中得到的最简单的树。
这种对大型数据集的随机分析是不可行的。我们需要一些系统的方法来解决这个问题。
让我们尝试用贪婪的方法来解决这个问题…
首先,我们查看数据集并决定我们应该为树的根节点选择哪个属性…
这是一个布尔分类,所以在决策树的末尾我们会有 2 个可能的结果(要么他们是吸血鬼,要么不是),所以每个输入的例子会被分类为真(正面例子)和假(负面例子)。
这里' P' 指阳性,表示一个人是吸血鬼,,‘N’指阴性,表示这个人不是吸血鬼。
我们希望属性将更多的数据分成同质的集合,这意味着在这样的集合中,只有 P 或 N 存在,因为如果我们有,我们肯定可以回答关于吸血鬼或没有,因此这些将是树的叶节点。
检查每个属性,看哪一个属性在同构集中的元素数量最多。在这里,我们发现‘Shadow’属性在同质集合中具有最高的元素计数,所以我们选择这个属性。
所以到目前为止,我们有这么多的树…
对于影子属性【是】****【否】,我们可以决定一个人是不是吸血鬼,但是万一【呢?”我们不知道,我们需要决定当 shadow = '?'时,哪个属性划分数据好
所以,让我们在阴影未知的情况下分析另一个属性…
这里我们发现“大蒜?”属性划分最大元素,实际上是同质集合中的所有元素。
所以,我们的树现在看起来像这样,
这个树看起来比我们通过选择随机属性创建的树更简单,所以我们观察到贪婪方法帮助我们获得更好的结果。
但是,这是正确的做法吗?
不会,因为如果数据集很大,我们不需要将属性划分到同质集合中,我们可能会发现同质集合中的所有属性元素都是 0。
那么我们应该如何进行呢?
所以现在让我们深入研究用于生成决策树的 ID3 算法,它使用了信息增益的概念,这是根据信息论中的基本量熵定义的。
想象一下某一属性的这两个部分…
我们观察到左边的那个有相同数量的 P s 和 N s,所以这并没有给我们任何关于决定的暗示,但是右边的一个比 N s 有更多的 P s,所以它可能在某种程度上把我们引向 P ,所以在这两个中我们可以考虑右边的一个。
所以,现在不要马上给他们 0 分,让我们用另一种方法。比方说, P s 和 N s 是相等数的一个熵最高(1),只有 P s 或 N s 的一个熵最低(0)。我们可以有这样的东西, P/(P+N) vs 熵图。
(Graph created on Desmos)
所以,当 P=N ,从而 P/(P+N) = 0.5 那么熵= 1 ,
如果P = k&N = 0那么熵= 0 。
这感觉像是一个非常合适的图表来实现我们想要的,那么有没有一些数学方法来得到这个图表…
幸运的是,这条曲线可以通过下面的等式得到
可以写成 P/(P+N) 和熵,
替换 x= P/( P+N ) 和 y =熵,
其中 P 和 N 是我们正在寻找属性的属性的 P s 和 N s 的计数,
我们想从属性中找到信息增益,它被定义为,
( IG —来自某个属性的信息增益 A 是熵的预期减少)
IG(Attribute) =属性熵—每个子集熵的加权平均值
举个例子,
^ ( Example calculation of IG )
既然现在你已经了解了熵和信息增益的概念,让我们用这种新方法从头开始重新构建我们的决策树!
我们在这里观察到,我们从影子属性中获得了最大信息增益,选择它作为我们的根节点,
我们需要为 Shadow = '?'决定另一个属性
我们从大蒜中获得最大的信息增益,
所以我们的树看起来像这样,
这与前一种方法完全相同,因为幸运的是,在每一步中,我们都能够找到一些划分为同质集的属性,但是具有信息增益的方法更加健壮,可以应用于从大型数据集生成决策树。
参考: 识别树| MIT OCW
解码 FastAI 的深度学习代码—第 1 课
原文:https://towardsdatascience.com/decoding-deep-learning-code-of-fastai-lesson-1-2c763cf4ffa1?source=collection_archive---------21-----------------------
我当时正在搭上人工智能炒作的列车,决定一头扎进谷歌搜索的深渊,为我的旅程指引方向。正如每个人和他们的博客所建议的那样,我看了吴恩达的机器学习课程讲座,完全被人工智能可能解决的潜在问题所吸引。但我希望作业是用 Python 写的,这种语言让我的生活变得更简单——刮网页,布置选修课,还有保护我的眼睛。而且,感觉我学了太多的理论,却没有足够的实践。
我很快了解到 FastAI 的程序员实用深度学习正是我一直在寻找的。作为一名程序员,我对 FastAI 和他们遵循的自顶向下的方法非常着迷。现在,在课程开始的 15 分钟内,我已经为一个计算机视觉问题训练了一个图像分类器。所以我决定采用同样的方法来学习 Numpy,并一路练习 Python。
我已经试着解释了第一课中的所有代码以及每个函数的作用。所以现在,你可以利用这段时间来尝试不同的时代和学习速度,并改进模型,而不是在小事情上伤脑筋。
最好先看第一课的视频或阅读第一课的相关文章。我从这里开始学习使用 Google Colab 运行我的工作空间(生活中最美好的事情是永远免费——FastAI、Google Colab 和 Python)。在本教程的最后,我有一节解释了代码中使用的 numpy 函数。我们正在处理本课中使用的狗和猫的分类数据集。
基础知识:
我们使用 resnet34 架构(一种卷积神经网络)根据图像属于狗或猫类的概率将图像分类为狗/猫。
数据变量包含训练和验证数据。训练数据是关于模型被训练的内容,验证数据用于检查我们的模型在它以前没有见过的图像上的表现如何。
data.val_y 是验证数据集标签,即带有猫的图像的标签为 0,带有狗的图像的标签为 1。
*data.val_y
array([0, 0, 0, ..., 1, 1, 1])*
学习变量包含模型。在这里,我们使用迁移学习,我们利用预训练模型已经学会识别的特征,如边缘、曲线、某些形状等。激活是一个数字,它表示—该功能在这个位置具有这个置信度(概率)。
预计算=真意味着我们预计算隐藏层的激活,并为我们的图像训练最后的年份。
learn.fit() 通过,学习率为 0.02,训练的历元数为 3。
现在让我们深入研究一下实现。
我们预测验证集中的图像,并将其存储在 log_preds 中。该值以自然对数表示。
log_preds[:2]
*array([[ -0.00323, -5.73731],
[ -0.0001 , -9.21326]], dtype=float32)*
preds 在 log_preds 的每一行中寻找最大值。
probs 通过取 log_preds 第二列的指数,包含图像是狗的概率(第一列是对猫的预测,第二列是对狗的预测)。如果 probs 小于 0.5,我们将图像分类为猫,如果大于 0.5,我们将其分类为狗。
为了了解我们的模型是如何看到这些图像的,让我们看看一些随机正确/错误分类的图像。定义相同的功能,
rand_by_mask(mask) 返回满足 mask 中条件的四个随机元素的索引。我们可以通过改变 np.random.choice. 中的第二个参数 r 来选择返回多少张图片
rand _ by _ correct(is _ correct)首先检查 preds 中的预测标签和 data.val_y 中的实际标签是否与用户输入的 is_correct 参数中的 匹配,该参数为布尔变量 True /False。它将这个经过筛选的数据集作为掩码发送到 rand_by_mask,以获得四个符合标准的随机图像。
现在我们有了获得随机正确/不正确图像的函数,让我们看看获得****最正确/不正确分类图像的函数。
most_by_correct(y,is_correct): y 对于猫是 0,对于狗是 1。是 _ 正确是布尔型。该函数调用 most_by_mask(mask,mult)。将掩码指定为逻辑与的:**
**preds中的预测标签和 data.val_y 中的实际标签相互匹配,并且是正确的参数
与 y 参数匹配的 data.val_y
它根据以下逻辑计算 mult :
most_by_mask(mask,mult): 该函数通过 mask 和 mult 实现。首先,我们在 idxs 中得到满足遮罩条件的图像。然后我们将 mult 乘以 idxs 中数据的概率,用 np.argsort 得到结果的最小四个值,为什么要这样做呢?
考虑一下狗的情况。
- 对于正确的狗, mult = -1 和 probs 的子集看起来像 0.60,0.67,0。87,0.98(都大于 0.5)。所以当你排序( multprobs ) 时,得到-0.98,-0。87, -0.67, -0.60 .因为最正确的狗的 probs 最接近 1,所以该结果显示从最正确的顺序开始的图像。*
- 对于不正确的狗, mult = 1。所以当你排序( multprobs ) 时,得到 0.60,0.67,0。87, 0.98.由于最不正确的狗的探针距离 1 最远,因此该结果显示最不正确顺序的图像。***
以猫为例。
- 对于正确的猫, mult = 1 和 probs 的子集看起来像 0.04、0.12、0.35、0.43(都小于 0.5)。所以当你排序( multprobs ) 时,得到的是 0.04,0.12,0.35,0.43。由于最正确的 cat 的 probs 最接近 0,因此该结果显示最正确顺序的图像。*
- 对于不正确的猫, mult = -1。所以当你排序( multprobs ) 时,得到-0.43,-0.35,-0.12,-0.04。由于最不正确的 cat 的探针距离 0 最远,因此该结果显示最不正确顺序的图像。***
现在让我们看看为我们绘制图像的函数。
**绘图:我们使用 matplotlib 库来绘制图像。我们在 ims 中得到一个图像数组,在 rows、中得到要显示的行数,在 titles 中得到标题数组。我们使用 range 函数在 ims 数组的长度上循环遍历 ims 中的每个图像,为其添加相应的标题并绘制。
load_img_id: PIL 是 Python 图像库,我们从数组 ds 中打开索引 idx 的图像,并将其作为一个 np 数组返回。
plot_val_with_title: 我们得到的 idxs 是由 most_by_correct 或 rand_by_correct 返回的图像的子集。我们使用列表理解从 idxs 中获取单个索引 x ,并使用 load_img_id(data.val_ds,x)从验证集 data.val_ds 中加载每个图像。
我们还将每个图像索引 x 的分类概率存储在 title_probs 数组中。我们将这些传递给 plots ()函数。
**most _ uncertainty:这里我们的目标是找到概率非常接近 0.5 的图像(它们不确定该靠哪边)。我们把概率减去 0.5,取绝对值,排序。我们取最小的四个值,并返回对应于这些概率的元素的索引。
要获得结果图像,请尝试 FastAI 中的代码。你可以在 Google Colab 中实现它,它的教程在这个链接中。您可以自己试验这些函数,比如将参数更改为 plot_val_with_title() 并调整返回的图像数量。
NUMPY 函数解释如下:
- np.argmax(array,axis = None,out = None) : 返回数组中最大元素在特定轴上的索引。对于 2 D 矩阵,axis = 0 表示列,axis = 1 表示行。考虑以下阵列:
np.argmax( array,axis = 0) = [2 2 3 0]
np.argmax( array,axis = 1 ) = [3 1 1 2]
2) np.exp( array,out = None) 计算输入数组中所有元素的指数
现在让我们看看这些图像,了解一下哪种图像被正确/错误地预测了。在这里,我们继续定义自定义函数来选择要显示的图像。
理解这里使用的 numpy 函数:
3) np。其中(condition[,x,y]) 返回满足给定条件的输入数组中元素的索引。
-> 条件是布尔:根据可选值 x 和 y 有两种变化。
I)当 x 和 y 都不是时:
返回满足条件的值的索引。
**x = np.arange(4).reshape(2, 2)
#Note: np.arange() returns array of evenly spaced values.print(x)
# [ [0, 1], [2, 3]]print(np.where( x > 0))
# (array([0, 1, 1]), array([1, 0, 1]))**
ii) x 和 y 包含值:当条件为真时,使用 x 的值,如果条件为假,则使用 y 替换原始值。
在这里,当数组值大于 0.5 时,该值将更改为 1。对于其他情况,该值将被更改为零。
**arr = [ 0.1 , 0.7, 0.3, 0.6 ]
res = (np.where(arr>0.5, 1, 0))
print(res)
#res = [0, 1, 0, 1]**
-> 条件类似于数组:当条件为真时,使用 x 的位置值,如果条件为假,则在结果数组中使用 y 的相应值。这里,对于数组中的 True 值,使用 array_true,对于 False 值,使用 array_false。
**array = [[True, False], [False, True]]
array_true = [[1, 2], [3, 4]]
array_false = [[5, 6], [7, 8]]
res = np.where(array,array_cond_true,array_cond_false)print(str(res))
# [[1,6], [7,4]]**
4) np.random.choice (a,size=None,replace=True,p=None) 返回从其元素生成的随机样本。
一个可以是整数也可以是一维数组。如果是数组,则从其元素中生成随机样本。如果是 int,则生成随机样本,就像 a 是 np.arange(a)一样。
可选参数包括:
size: 要返回的数组的大小。
替换:样品是否有替换
p: 与 a 中每个条目相关的概率。如果没有给定,样本假设在 a 中的所有条目上均匀分布。
**np.random.choice(5, 3)
# array([0, 3, 4])np.random.choice(5, 3, replace=**False**)
# array([3,1,0]) . This is like permutation, values are not repeated**
5) np.argsort(a) 返回以 numpy 数组形式对数组进行排序的索引
**a = np.array([5,7,4,1])
print(a) # [5 7 4 1]b = np.argsort(a)
print(b) # [3 2 0 1]c=a[b]
print(c) # [1 4 5 7]**
返回一个 numpy 数组
请参考以下链接了解 numpy 数组。
**** [## 1.3.1.NumPy 数组对象—科学讲义
创建一个简单的二维数组。首先,重做上面的例子。然后创造你自己的:如何奇数…
www.scipy-lectures.org](https://www.scipy-lectures.org/intro/numpy/array_object.html)
我希望我在第一课解释了代码背后的直觉。非常感谢 Jeremy 和 Rachel 通过 FastAI 开发并民主化了这门深度学习的精彩课程。****
解码我们自己的大脑
原文:https://towardsdatascience.com/decoding-our-own-brain-95f861d0d94a?source=collection_archive---------21-----------------------
科技会释放我们大脑的真正潜力吗?
SOURCE: © ADOBE STOCK
我 一直着迷于我们的大脑可以达到超乎寻常的潜能这一想法。我们可以做远远超出我们想象的事情,发现我们未知的能力。然而,纵观历史,人类大脑的进化已经产生了一定程度的“舒适”。这种水平在某种程度上限制了我们将大脑推出其边界,并阻止我们提高我们的能力。
在过去的十年中,我们看到了神经科学和技术进步如何合作,在技术和人脑之间建立联系。这些进步旨在发展一种“共生关系”,即技术与人类的融合。这当然引发了许多问题——包括对这些创新的过程和实施的困惑,以及许多与伦理相关的问题。
有这么多要讨论的,但我们至少应该首先考虑的是,技术将帮助我们更有效地使用我们的大脑。这就是我们将在这篇文章中探讨的。
技术和人脑
SOURCE: © ADOBE STOCK
想象一下,有一天我们可以改变我们的记忆来解决抑郁和焦虑问题,或者将一整年的研究直接下载到我们的大脑中,或者体验人们的情绪,或者甚至能够只用我们的思维将我们的想法传递给其他人。这听起来似乎遥不可及,但事实是,我们正在取得很大进展,我们正在实现这一目标。
以脑机接口(BCI)为例,这项技术已经发展了几十年。这项技术允许计算机记录大脑信号,并产生转化为行动的反应,如控制机器人假肢或用大脑玩视频游戏。
该领域最有希望的发展之一归功于埃隆·马斯克,他最近的一项宣布是: Neuralink 。
Neuralink´s Robotic Surgery. SOURCE: © NEURALINK
该项目主要基于通过细电极线将人脑与智能手机或电脑等不同设备连接起来的想法,这些电极线允许我们用思想控制这些设备。第一个目标是利用这项技术来改善那些患有瘫痪或类似疾病的人的生活质量,但这只是一个开始。
在大脑和计算机之间建立一条通信路径将允许我们做一些我们认为不可能的事情。
人工智能——人类共生
SOURCE: © ADOBE STOCK
M usk 认为 BCI 对我们的未来至关重要,它将通过允许人类与未来的超级智能人工智能发展合作来减少人工智能(AI)的负面影响。
在这种情况下,共生指的是人工智能和人类之间的有益关系,我们在其中合作和共同进化。听起来有点怪异,但基本上,当人类教会机器如何改进时,机器将以“共生”的方式与人类并肩发展。
这种连接的目的是实现人类和机器之间的某种创造性协作,在这种协作中,我们不仅仅是发布命令,还可以一起集思广益,并接收彼此的反馈。
实施脑机接口技术将提高残疾人和非残疾人的学习和记忆等技能。有了这项技术,人类大脑将能够更快地访问和处理信息。想象一下,能够随时接触到世界上所有的知识,并理解它。
从长远来看,这一过程可能会在不同的阶段发展:从浏览我们大脑内部的特定信息开始,如“谷歌搜索”,到我们的大脑将成为某种“云”——一个我们可以存储、下载、上传、修改并与其他人和计算机实时分享信息的地方,以及立即了解一切的地方。
科技将显著改善我们的记忆,让我们能够储存和获取更多的信息。它可以帮助许多人,如有记忆问题的老人,轻松回忆起来。此外,对于像阿尔茨海默氏症这样的记忆没有完全丧失的残疾人来说,技术将帮助他们建立一种联系,以恢复那些隐藏的记忆。
在 Neuralink 的首次亮相期间,马斯克透露已经用老鼠做了几次测试,他们甚至用一只显然成功控制了计算机的猴子做了测试。现在,他们正在等待食品药品监督管理局(FDA)批准开始人体试验。
马斯克有一个非常有趣的观点,他认为人类大脑除了有边缘系统和皮层之外,还有某种额外的“数字层”。不同的是,我们通常通过手指而不是大脑来连接它。这是一个有趣的观点。
对我们大脑能力的未来研究
SOURCE: © ADOBE STOCK
想想你只用大脑能做的最奇怪、最神奇、最疯狂的事情。
很多想法可能会突然出现在你的脑海里…
还记得 x 战警里的泽维尔教授(X 教授)吗?他有心灵感应。他可以读取你的思想,改变你的感官,甚至放置或删除思想和记忆。这听起来很极端,但我们不应该忽视未来可能与此类似。
未来是非常不确定的,因此发展的顺序将成为现实。人类和技术的结合可能比人工智能更强大。也许我们不会成为“泽维尔教授”,但我们一定会拥有通过心灵交流的力量,不仅是与机器交流,也可以与其他人类交流;在这个层面上我们将能够体会彼此的感受。
现在,这很疯狂,但是考虑一下将我们的大脑提取到一个可以插入一个全新身体的装置中的可能性。一个更强、更快、更灵活的身体,一个只要大脑还活着就不一定会死的身体。这是能防止我们死亡的解药吗?
这些进步旨在释放我们真正的力量,我们大脑的全部潜力,同时将我们从人工智能的末日中拯救出来——如果我们不学会如何控制技术并与之合作,人类就会成为劣等物种。
埃隆·马斯克自己说过,谁想拥有自己的人工智能扩展,谁就可以拥有一个。人类与人工智能的共生可以对未来做出决定,这将建立一个人工智能是民有、民治、民享 的世界。
解码混淆矩阵
原文:https://towardsdatascience.com/decoding-the-confusion-matrix-bb4801decbb?source=collection_archive---------4-----------------------
在分类问题的情况下,只有一个分类精度可能无法给出全貌。因此,混淆矩阵或误差矩阵用于总结分类算法的性能。
Photo by Joshua Sortino on Unsplash
计算混淆矩阵可以让您了解分类模型在哪里是正确的,以及它会产生什么类型的错误。
混淆矩阵用于检查分类模型对一组真实值已知的测试数据的性能。大多数性能指标,如精确度、召回率,都是从混淆矩阵中计算出来的。
本文旨在:
1。什么是混淆矩阵,为什么需要它。
2。如何用一个猫狗的例子计算一个 2 类分类问题的混淆矩阵?
3。如何在 Python 中创建混淆矩阵& R.
4?对不同指标的总结和直觉:准确度、召回率、精确度&特异性
1.混淆矩阵:
混淆矩阵提供了分类问题中预测结果的总结。表中总结了正确和不正确的预测及其值,并按类别进行了细分。
Confusion Matrix for the Binary Classification
当类别不平衡时,我们不能依赖单一的分类精度值。例如,我们有一个 100 名患者的数据集,其中 5 名患有糖尿病,95 名健康。然而,如果我们的模型仅预测大多数类别,即所有 100 个人都是健康的,即使我们具有 95%的分类准确度。因此,我们需要一个混淆矩阵。
2.计算混淆矩阵:
让我们举个例子:
我们总共有 10 只猫和狗,我们的模型预测它是否是一只猫。
实际值= ['狗'、'猫'、'狗'、'猫'、'狗'、'猫'、'狗']
预测值= ['狗'、'狗'、'狗'、'猫'、'狗'、'狗'、'狗'、'猫'、'猫'、'猫']
请记住,我们将预测值描述为正/负,将实际值描述为真/假。
术语定义:
真阳性:你预测阳性,是真的。你预言一种动物是猫,它确实是。
真阴性:你预测为阴性,这是真的。你预测动物不是猫,它实际上也不是(它是一只狗)。
假阳性(类型 1 错误):你预测阳性,但它是假的。你预测动物是猫,但它实际上不是(它是狗)。
假阴性(第二类错误):你预测的是阴性,它是假的。你预测那种动物不是猫,但它实际上是。
分类精度:
分类精度由下式给出:
召回(又名敏感度):
召回定义为正确分类的正类总数除以正类总数的比值。或者说,在所有的积极类中,我们正确预测了多少。召回率应该很高。
精度:
精度定义为正确分类的正类总数除以预测的正类总数的比值。或者说,在所有的预测积极类中,我们预测正确的有多少。精度要高。
需要记住的技巧: Pre cision 在分母中有 Pre dictive 结果。
F-score 或者 F1-score:
两个精度和召回率不同的模型很难比较。所以为了使它们具有可比性,我们使用 F-Score。这是精确和回忆的调和平均值。与算术平均相比,调和平均对极值的惩罚更大。f 分应该很高。
特异性:
特异性决定了被正确识别的实际阴性的比例。
解释混淆矩阵的例子:
让我们用上面的猫和狗的例子来计算混淆矩阵:
分类精度:
精度=(TP+TN)/(TP+TN+FP+FN)=(3+4)/(3+4+2+1)= 0.70
回忆:回忆让我们知道什么时候它实际上是肯定的,它预测肯定的频率有多高。
回忆= TP / (TP + FN) = 3/(3+1) = 0.75
精度:精度告诉我们什么时候它预测是,它正确的频率是多少。
精度= TP / (TP + FP) = 3/(3+2) = 0.60
F-score:
F-score =(2 召回率准确率)/(召回率+准确率)=(2 * 0.75 * 0.60)/(0.75+0.60)= 0.67
特异性:
特异性= TN / (TN + FP) = 4/(4+2) = 0.67
3.在 Python & R 中创建混淆矩阵
让我们用 python 和 R 代码来理解上面的狗和猫的例子,这会让你更好地理解到目前为止你对混淆矩阵的了解。
混乱矩阵的 Python 代码:
首先让我们用 python 代码创建一个混淆矩阵。我们必须从 sklearn 库中导入混淆矩阵模块,这有助于我们生成混淆矩阵。
下面是上面解释的 Python 实现:
Python Code
**OUTPUT ->**Confusion Matrix :
[[3 1]
[2 4]]
Accuracy Score : 0.7
Classification Report :
precision recall f1-score supportcat 0.60 0.75 0.67 4
dog 0.80 0.67 0.73 6micro avg 0.70 0.70 0.70 10
macro avg 0.70 0.71 0.70 10
weighted avg 0.72 0.70 0.70 10
混淆矩阵的 R 代码:
现在让我们用 R 代码创建一个混淆矩阵。我们将使用 R 中的插入符号库来计算混淆矩阵。
R Code
**OUTPUT ->**Confusion Matrix and Statistics Reference
Prediction 0 1
0 4 1
1 2 3Accuracy : 0.7
95% CI : (0.3475, 0.9333)
No Information Rate : 0.6
P-Value [Acc > NIR] : 0.3823Kappa : 0.4Mcnemar's Test P-Value : 1.0000Sensitivity : 0.6667
Specificity : 0.7500
Pos Pred Value : 0.8000
Neg Pred Value : 0.6000
Prevalence : 0.6000
Detection Rate : 0.4000
Detection Prevalence : 0.5000
Balanced Accuracy : 0.7083'Positive' Class : 0
4.总结:
- 精确是你对自己的真实想法有多确定。回忆是你有多确定你没有错过任何积极的东西。
- 如果假阴性的出现不可接受/不可容忍,选择召回。例如,在糖尿病的情况下,你宁愿有一些额外的假阳性(假警报),而不是保存一些假阴性。
- 如果你想对你真正的阳性结果更加自信,选择精确。例如,在垃圾邮件的情况下,你宁愿在你的收件箱中有一些垃圾邮件,而不是在你的垃圾邮件箱中有一些普通邮件。在我们将电子邮件 X 放入垃圾邮件箱之前,您想要额外确定它是垃圾邮件。
- 如果您想要覆盖所有真阴性,选择特异性,即意味着我们不想要任何假警报或假阳性。例如,在毒品测试中,所有测试呈阳性的人都会立即入狱,你不会希望任何没有吸毒的人入狱。
我们可以得出结论:
- 准确度值为 70%意味着每 10 只猫中有 3 只识别不正确,7 只识别正确。
- 精度值为 60%意味着每 10 只猫中有 4 只不是猫(即狗),6 只是猫。
- 召回值为 70%意味着实际上每 10 只猫中有 3 只被我们的模型遗漏,7 只被正确识别为猫。
- 特异性值为 60%意味着现实中每 10 只狗(即非猫)中有 4 只被误标记为猫,6 只被正确标记为狗。
如果您有任何意见或问题,请在下面留下您的反馈。更多文章请访问 KeytoDataScience 。你可以在 LinkedIn 上找到我。
解码混合推荐系统的输出
原文:https://towardsdatascience.com/decoding-the-output-of-a-hybrid-recommendation-system-2007d85547bf?source=collection_archive---------37-----------------------
在医疗环境中理解由基于协作过滤器的推荐系统提供的推荐
随着新兴分析技术的兴起,有效的推荐系统已经成为数据科学领域的游戏规则改变者。像网飞和亚马逊这样的公司已经通过建立一些可靠的推荐系统超越了他们的竞争对手。但是这些黑盒算法,它们真的是可解释的吗?在医疗保健这样复杂的领域,我们能依靠这样的算法来解决一些现实世界的医疗保健问题吗?最重要的是,这些系统能否捕获与客户的可用敏感医疗数据相关的医疗环境。这篇文章的目的是去黑盒子这些神奇的建议,并寻找符合逻辑的答案。
混合推荐系统简介
随着对可靠推荐系统需求的增加,已经从传统的基于用户-项目交互的系统转变为基于深度学习架构的推荐系统,该系统能够从复杂的输入数据集中提取模式。Autoencoder 是一种这样的无监督深度学习技术,它使用编码将输入数据嵌入压缩格式,并将该压缩数据解码为输入数据的有意义表示。此外,通过 knn 算法分析这些嵌入,以将相似的患者作为邻居分组在一起。knn 算法用来将患者分组的相似性指数是基于他们个人的医疗索赔历史。
推荐系统在医疗领域的应用
将个性化推荐系统应用于产品推荐是当前科技行业的热门话题。但当涉及到医疗保健行业时,建议的含义可能会改变生活,显然,对准确可靠的建议的需求是重中之重。
在医疗保健行业中应用推荐系统背后的直觉是拥有一个能够向健康保险公司推荐医疗干预措施的平台,以促进对患者的筛选过程。这些干预建议是使用如上所述的自动编码器的深度学习架构构建的。
推荐制度背后的方法和思想
这些建议是基于包含索赔历史以及患者人口统计数据的句子构建的。这些声明以标记为 ICD 代码的诊断和程序代码的形式出现。
这个想法是根据人口统计学和索赔历史的相似性对患者进行分组。一个可靠的推荐系统可以帮助保险公司或医疗提供者以最有效的方式接触到人们。
解释推荐系统的输出
现在我们有了一个经过深思熟虑的混合推荐系统,为我们提供了一个具体的干预建议列表,可以帮助保险公司更有效地瞄准他们的客户,问题是该系统有多可靠。不像产品推荐,我们不想在尝试和测试理论的基础上玩它。
有些人可能会认为,精度、召回率和 AUC 等性能指标可以验证我们的推荐系统,作为一种信心的衡量标准,但最终它只是一种机器学习算法。当我们在这里处理人类情感时,我们需要人类层面的认可。我们如何衡量它在捕捉与数据相关的医疗环境方面是否做得很好?我使用了一些自然语言处理技术来更深入地研究这个推荐系统的推荐
使用 NLP 技术对推荐进行逆向工程
正如上一节所讨论的,仅仅基于性能评估指标来评估推荐系统是不够的。因此,我决定对这些建议进行逆向工程,并试图理解 ML 算法为我们提供这些神奇输出所遵循的方法。
我们不希望我们的推荐系统仅仅根据人们拜访医生的次数或者他们提出索赔的次数来对他们进行分组。我们需要医学上可行的理由来将人们分组。以下是我检查的一些方法:
第一步:访问或索赔的频率
虽然这是一个很好的特征,可以看到人们多久提出一次索赔或多久去一次医院,但我们不能仅仅根据数字和统计数据来判断人们。我使用 python 中流行的 sci-kit learn 库应用了 CountVectorizer 来进行这项检查。我发现,虽然计数是发现人们相似性的重要指标之一,但是还有其他的问题。
第二步:超越频率
频率检查有助于了解与患者相关的常见医疗代码。但是我们需要一个比频率本身更好的方法,因为我们不想增加索赔计数的权重。因此,我使用术语频率-逆文档频率(Tf-Idf)矢量器来关注基于标准化计数的医疗代码的重复出现。然后,这个转换用于分析分组在一起的人,以查看我们的建议是否能够提取上下文中医疗代码的出现。
第三步:回归相关性(主题建模)
Tf-Idf 允许我们通过减少仅由代码/声明计数产生的噪声来赋予频率概念更多的内容。然而,我们可以关注更多的东西。验证一台机器的最大参数之一是它从数据中提取相关性的能力。为了验证这一点,我对我们现有的 ICD 编码应用了主题建模,并注意它们在不同主题中的分布是否传达了一些关于患者相似性分析的医学上有意义的信息。
对于主题建模,我使用了潜在狄利克雷分配(LDA)来基于它们一起出现的概率统计分布 ICD 码。python 中的 Sci-kit learn 和 gensim 库用于 LDA。这给了我一个关注 10 个主题的机会,每个主题都有 10 个 ICD 代码。因此,基于 LDA,研究了 100 个诊断代码,我试图发现这些代码是如何在被我们的推荐系统分组在一起的人群中分布的。
结果和发现
令我惊讶的是,这一分析中有一些有意义的见解。很少有主题代表了一组特定的 ICD 代码,这些代码遵循医学上可行的语义。例如,一个主题主要关注与肝病相关的诊断代码,而另一个主题代表与怀孕相关的代码。所以我们知道,机器能够根据这些代码的医学意义对它们进行分组。这令人耳目一新,我进一步寻找每个主题的分布,这些主题包含分组在相同相似性类别下的人的 ICD 码。这个结果让我百感交集,因为我在诊断代码的分布中发现了一些医学相关性,然而最近邻的样本太小,不能一概而论。进一步的步骤将是具有相同的方法,增加相似性检测技术的层和相似人的更大样本,以给予解码项目更大的权重。
写这篇文章的目的是描述我的方法和思维方式,让我们作为数据科学家喜欢的神奇数字/输出有逻辑意义。但有时我们需要退一步,想想它们在现实世界中的含义。希望你们都喜欢这篇文章,就像我喜欢与你们分享我的想法和分析一样。乐意进一步讨论。可以在这里联系我: LinkedIn-Mayur Bansal 。
解码世界上最流行的数据科学库——Numpy 的性能秘密
原文:https://towardsdatascience.com/decoding-the-performance-secret-of-worlds-most-popular-data-science-library-numpy-7a7da54b7d72?source=collection_archive---------9-----------------------
没有这个魔咒,任何机器学习脚本都无法启动
无论是数据科学爱好者,还是经验丰富的从业者,每个人都知道这个精彩的 Python 库的威力。
当涉及到处理大型多维数组(表格、图像等)时。),用 numpy 也不会错的很离谱。
但是你知道吗,除了超级方便之外,强大的软件包还包含相当多的性能果汁!
事实上,使用 numpy 内置的基于元素的数组操作通常比遍历标准 python list 要快得多。
考虑这个简单的任务,按元素添加两个列表
比较这两者的性能,我们可以观察到
随着元素数量从 1000 增加到 100,000,Python-lists 所用的时间成线性比例——O(n ),相对于此,*np.add()*
所用的时间几乎保持不变——O(1)。
为了让您了解阵列大小为 100,000 的一些情况,这些数字如下:
%timeit sum_using_loop(a,b,c)
# Average run time: 10.5 ms ± 15.9 µs%timeit sum_using_numpy_builtin(a, b)
# Average run time: 79.6 µs ± 835 ns
numpy 方法快了将近 130 倍!!
问题是—
Numpy 是如何实现如此荒谬的加速的??
一些显而易见的答案包括:
- Numpy 主要是用 C 写的,比 Python 快。
- Numpy 数组是同构的(所有数组元素都有固定的数据类型-
*np.float32, np.uint8*
等等)。与没有这种限制的 python 列表相比),从而允许将数字存储在连续的存储器位置中以便更快地访问(利用 引用位置 )
尽管如此,上述原因还不足以解释处理时间为何不与数组大小成比例。
走到幕后
为了找到答案,让我们开始在 Numpy Land 的秘密任务——解构源代码。
为了理解这一点,让我们先熟悉一些本地术语:
- 通用函数(uf unc)—numpy 中的函数,对“N”维数组(又名 ndarray)执行快速元素运算
- umath — Numpy 模块,包含常见数学运算的实现,如加、减、乘、正弦、余弦等。)
剧透警告 : Numpy 使用矢量指令(SIMD)来加速“ufunc ”,你可以跳到下一节,或者如果你有兴趣了解如何加速,请继续阅读。
经过一番挖掘,我们可以在*__umath_generated.c*
中找到一些我们感兴趣的添加函数的引用
我们看到,*add_functions*
是一个数组,包含对所有特定类型加法函数的引用,包括*INT_add*, *FLOAT_add*, *DOUBLE_add*
等。
How Numpy stores references to all data-type specific addition functions — Numpy source
这些*add_functions*
通过下面的代码映射到我们的 python 的*numpy.add*
函数调用。
Where ‘numpy.add’ comes from — Numpy source
现在为了简单起见,让我们只关注一种数据类型,比如说浮点加法,并弄清楚是什么让它如此快速!
我们的查询将我们带到了实现相关方法的文件— *loops.c*
‘Float_add’ method inside ‘loops.c’ — Numpy source
流程是这样的:
- 确定它是否是一个归约操作——组合输入参数并返回一个聚合结果(在我们的例子中不是这样)
2.尝试使用*run_binary_simd_add_FLOAT()*
将它们相加(这里的‘二进制’指的是对两个输入的运算,可以是数组或标量或者两者的组合)
3.如果对 simd_add 函数的调用失败,那么它使用标准的循环元素加法。
注意:这些名字- ' sse2 ',' simd '可能现在看起来很陌生,但是以后会有意义的
沿着*run_binary_simd_add_FLOAT()*
,的轨迹,我们最终会找到我们最感兴趣的那段代码*sse2_binary_add_FLOAT()*
仔细观察,我们可以发现一些奇怪的代码,这些代码(如果你还记得你的“计算机架构”课)类似于汇编语言。
*_mm512_load_ps* _*mm512_add_ps
_mm512_store_ps*
事实上,这些是 ' 英特尔内部函数 ' — C 函数,它们提供对汇编指令的访问,而无需实际编写汇编代码!
更确切地说,这些是矢量指令!!
向量:什么鬼东西??
在你开始思考汇编代码之前,请允许我解释一下。
现代 CPU 有称为向量寄存器的专用硬件寄存器,能够同时对多个操作数(相同类型/大小)进行操作,引入了被称为‘单指令多数据’(或 SIMD)机制的并行性
Image Credit: NativeScript
向量指令(也称为向量扩展)是访问这些向量寄存器的手段,允许在大型数组(也称为向量扩展)上更快地处理最常见的算术和逻辑运算。向量)。
这些通常用于涉及大型多维数组操作的应用程序,例如
- 图形处理(视频游戏、4K 视频渲染等。)
- 统计(寻找大型数组的平均值/模式)
- 机器学习(矩阵乘法->输入*权重+偏差)
啊哈!!
是什么让这些寄存器这么酷(快)?
这是他们的能力。
典型地,CPU 具有多个 32 位和 64 位通用寄存器,而向量寄存器的大小是 128/256 位,或者在较新的情况下甚至是 512 位。(我们将会看到)。
更大的容量意味着,一个 256 位向量寄存器可以在一个时钟周期内并行保存和操作“8”个 32 位浮点!—与最大的通用寄存器相比,速度提高了近4 倍
SSE 和 AVX 是最流行的向量扩展。
SSE ( 流 SIMD 扩展) 最早于 1999 年在英特尔奔腾 III 中推出,附带‘8’-128位向量寄存器。
12 年后,随着“ Sandy bridge ”,英特尔推出了新的 AVX ( 高级向量扩展 ) ,它拥有 256 位寄存器(几乎是上一代的两倍)
Intel Processor vectorization capacity increasing as the generations progress
因此,现在我们有了一些很酷的东西来欣赏现代 CPU 能够进行的硬件优化,而不仅仅是痴迷于它们的时钟速度。
总之,Numpy 对向量指令的利用,使得它在大型数组上执行操作的速度超快,这与标准 python-lists 相反。此外,在内部,numpy 使用了许多其他性能提升技巧,包括'',&其他编译器级优化标志,以执行''自动向量化。
常见问题
问:上述加速仅适用于英特尔 CPU 吗?AMD 处理器呢?
AMD 确实支持 SSE 和 AVX,但是它的支持仅限于 AVX2 (256 位),而较新的英特尔处理器配备 AVX-512 (512 位)
问。)这些新获得的知识如何让我成为更聪明的数据科学家?
既然你已经知道了内部秘密,那么对你最有利的是:
-尽可能避免使用 for 循环,使用 numpy 内置的操作和方法。
-如果代码包含一维数组上的条件循环,一种快速矢量化代码的方法是使用
np.vectorize
。这里有一个帖子告诉你如何去做。-对于复杂运算,技巧是尝试将循环转换为一系列矩阵运算(点积/矩阵乘法/加法等)。).这里有一个帖子用一个例子描述了同样的情况。
以简单直观的方式分解时间序列
原文:https://towardsdatascience.com/decomposing-a-time-series-in-a-simple-and-intuitive-way-19d3213c420b?source=collection_archive---------14-----------------------
可解释的时间序列模型
Predict store sales
我们都曾与传统的时间序列模型如 ARIMA、指数平滑等进行过斗争,这些模型不太直观,如果不用纯粹的统计术语,很难向企业解释。
给定基于时间的销售数据,直觉上我们想到的是计算出像月度趋势、同比趋势、日间趋势、周峰值等模式。因此,这促使我设计了一种方法,可以分解时间序列以轻松找到所有这些参数,并使我们能够以更简单和直观的方式对未来进行预测。
在本帖中,我们将使用从 2013 年 1 月日到 2015 年 6 月日约 2.5 年的商店销售数据,从罗斯曼商店销售卡格尔挑战。
Table 1: Sales Data for Store XYZ
创造流动
为了实现我们的最终目标,即识别(分解)时间序列的不同组成部分,并将我们的学习转化为更简单、更直观的模型,我们对任务的总体看法是:
- 数据分析( EDA )
- 功能创建和平均销售额计算
- 推导模型的方程式
- 训练模型
- 分解时间序列的不同组成部分
- 使用分解的组件创建一个更简单和直观的模型
- 模型的质量分析并利用它获得其他有用的信息
- 结论
1.数据分析
让我们开始我们的旅程。我们有特定日期的商店销售。字段打开表示商店当天是否正常营业。XYZ 商店在星期天仍然关闭。所以,我们会考虑到日子,只有当商店开门。
一段时间内商店销售的图形可视化。
随时间推移可视化销售的代码
Store sales over time
我们在每年的 12 月份看到一个明显的高峰。除此之外,多年来的下降趋势也很明显。2014 年和 2015 年显示出类似的趋势,但与 2013 年相比明显下降。一个好的方法应该能够捕捉这些变化。
接下来,我们将执行 EDA 来了解一周内几天的销售变化。
可视化一周内销售额的代码
Store sales during days in a week
星期天没有销售,因为商店仍然关闭。我们可以在周六和周一看到一个明显的高峰。周末可能是周六销售额增加的一个原因。类似地,商店在周日停止营业可能会导致周一销售额增加。一个好的方法应该能够捕捉这些变化。
我们已经看到了 12 月份的销售高峰,但是让我们用类似的 EDA 来重新确认我们的假设,就像我们对一周内几天的销售所做的那样。
跨月销售可视化代码
Store sales across months
另一件事,我们可以调查的是一个月中几周的销售模式。我有一种直觉,这不会是一个很强的模式,一个月中几周的销售应该表现类似。但是,为什么不测试一下呢?这个世界充满了惊喜,不是吗?我们将分析一周中每天的平均销售额。
可视化一个月中几周销售额的代码
Sales across weeks in a month
在一个月的第一周和最后一周的几天里,销售额都比较高。一个随机的猜测可能是月末工资和更多人购物的功劳。
2.特色创造和平均销售额
每个日期都可以通过其年、月、周和日来唯一标识。以这种方式表示日期的主要原因是为了发现月趋势、年趋势、日趋势和周趋势。
保持周数的原因是为了确定销售是否随着月份的进展而增加、减少或者根本没有影响。我们称之为每周趋势。
此外,我们将删除商店仍然关闭的数据点。星期天,商店仍然关门。
执行特征创建和清理步骤后,数据如下所示
Table2: Data Overview
接下来,我们将对年、月、日和周字段执行一次性编码。一种热门编码是分类数据的二进制表示。这一步的结果是,我们将拥有以下字段。
'Sales', 'weekday_0', 'weekday_1', 'weekday_2',
'weekday_3', 'weekday_4', 'weekday_5', 'year_2013', 'year_2014',
'year_2015', 'month_01', 'month_02', 'month_03', 'month_04', 'month_05','month_06', 'month_07', 'month_08', 'month_09', 'month_10', 'month_11','month_12', 'weeknbr_1', 'weeknbr_2', 'weeknbr_3', 'weeknbr_4','weeknbr_5'
平均销售额
我们将从计算平均销售额开始。我们将用 avgSales 来表示。我们有 2.5 年的数据,即 2013 年、2014 年和 2015 年年中。由于没有 2015 年全年数据,如果用于平均销售额计算,很可能会添加噪声。我们将仅使用 2013 年和 2014 年的销售数据来计算 avgSales。
计算平均销售额的代码
avgSales 出来是 4825.98
3.推导模型的方程式
主要的想法是找到每月,每年,每天和每周的趋势。我们希望给它加上一个值,叫做指数。因此,我们希望获得月度、年度、日和周趋势指数。我们假设这些趋势是一天中销售额的唯一原因,超过了我们上面计算的平均销售额(avgSales)。
Model’s equation (1)
我们有一次性编码输入功能。在一个时间,只有一个月会高或设置为 1,随着一天,一周数和一年。输入会处理好的。因此,我们的输入等式被修改为:
Model’s equation (2)
让我们看看 2014 年 5 月 17 日模型方程的形式。在这种情况下,年将是 2014 年,月将是 5 月,周数将是 3 日,日将是星期六。所有其他输入将为 0。系数的 0 次方将变成 1。
Model’s equation form for 17th May 2014
我们将两边都取对数,以简化方程,并将其转换为易于应用线性回归的形式。我们将应用无截距回归,并取模型系数的反对数,以获得月度、同比、每日和每周趋势指数。
Model’s equation to apply regression
4.训练模型
这里的因变量是 ln(销售)-ln(avg 销售),我们将采用以 2 为基数的对数。我们有一家店铺从 2013 年 1 月日到 2015 年 6 月日约 2.5 年的销售数据。我们不会使用上个月的数据并保留它来验证模型的性能。
训练模型
接下来,我们将对模型的系数取反对数,以获得相应的指数。
取模型系数的对数
Yearly Index
Monthly Index
Day-wise Index
Weekly Index
5.从回归模型中学习分解时间序列
年度趋势
时间序列的一个重要组成部分是逐年趋势。与 2014 年和 2015 年相比,我们的模型学习的年度指数在 2013 年明显捕捉到了更高的趋势。捕获的年度指数将帮助我们从时间序列数据中分解年度趋势。让我们想象一下结果。
Yearly Index
Yearly trend
我们可以清楚地看到一个逐年下降的趋势。下降趋势可能有许多原因,如商店质量下降或竞争对手商店开业等。需要做更深入的分析才能发现。这将是一个有趣的发现。
月度趋势
时间序列的另一个重要组成部分是月趋势。我们的模型学习的月度指数已经清楚地捕捉到了 12 月份的较高趋势。这将有助于我们从时间序列数据中分解月趋势。让我们想象一下结果。
Monthly Index
可视化月度趋势
Monthly trend
日间趋势
在 EDA 部分中,我们分析了一周中几天的销售情况。我们已经看到星期六和星期一的销售额较高。模型学习的日指数能够捕捉这些模式。让我们想象一下结果。
可视化每日趋势
Day-wise trend
每周趋势
在 EDA 部分,我们在一个月的第一周和最后一周看到了一个小高峰。模型学习的周线指数能够捕捉到这种模式。让我们想象一下结果。
Weekly Index
可视化每周趋势
Weekly trends
6.使用分解组件的更简单和直观的模型
我们将利用上述知识设计一个新的简单直观的模型,我们称之为乘法模型。最终的模型方程将是:
Model’s equation (1)
根据日期,将从计算表中使用 yearly_index、monthly_index、day_index 和 weekNbr_index。
Coefficients table
使用上述模型对 2015 年 9 月 21 日进行预测。它发生在 2015 年 9 月的第三周
销售= avg sales * Sep _ index * 3rd week _ index * 2015 _ index
= 4825.98 * 0.880 * 0.98 * 0.9425 = 3922.54
2015 年 12 月 31 日的预测?它发生在 2015 年 12 月的第 5 周
sales = avg sales * Dec _ coefficient * 5th week _ coefficient * 2015 _ index
= 4825.98 * 1.244 * 1.069 * 0.9425 = 6048.74
7.模型的质量分析并利用它获得其他有用的信息
同时,还训练了对截距或特征对数没有任何限制的线性回归模型。让我们称之为模型 1 和我们的乘法模型,模型 2。我们对这两个模型进行了为期 3 个月的测试,测试数据来自 50 多家商店的未公开数据。
在 RMSE 值相似的情况下,这两种模型在均方根误差方面的表现基本相同。在某些情况下,与模型 1 相比,模型 2 明显是 RMSE 较低的赢家。一个可能的原因可能是领域知识的供给,avgSales,不允许它过度适应和在看不见的数据上表现良好。
比较两个模型性能的代码
Both model performing similarly for most of the cases
乘法模型(模型-2)是商店 39、85 和 88 的明显赢家
Multiplicative Model is a winner
从乘法模型中获取其他有用信息
一些重要的信息和有趣的事实可以很容易地从乘法模型中推导出来。比如,如果企业问我们该怎么回答,或者我们如何比较 2014 年 5 月和 2014 年 11 月的销售额。我们使用学到的月、年、日和周指数的值来回答这些问题。
2014 年 5 月= 5 月指数* 2014 年指数= 1.02 * 0.9879 = 1.007
2014 年 11 月= 11 月指数* 2014 指数= 1.051 * 0.9879 = 1.038
与 2014 年 5 月相比,2014 年 11 月的销售额增加了多少
(1.038–1.007)/1.007 = 0.0307
因此,2014 年 11 月的季节性比 2014 年 5 月高 3.07%。我们可以跨年度对月、周、日进行类似的比较,并从分解的预测模型中获得更清晰的图像。
8.结论
这篇博文的主要思想是调整传统模型来分解时间序列,并创建一个更简单和直观的模型。希望目的达到了。让我知道你的想法和我如何能进一步改善这种方法。
我的 Youtube 频道更多内容:
[## 阿布舍克·蒙戈利
嗨,伙计们,欢迎来到频道。该频道旨在涵盖各种主题,从机器学习,数据科学…
www.youtube.com](https://www.youtube.com/channel/UCg0PxC9ThQrbD9nM_FU1vWA)
用经验模式分解法分解信号——哑元算法解释
原文:https://towardsdatascience.com/decomposing-signal-using-empirical-mode-decomposition-algorithm-explanation-for-dummy-93a93304c541?source=collection_archive---------5-----------------------
经验模式分解(EMD)是一只什么样的‘野兽’?这是一种分解信号的算法。而我说的信号,指的是一个时序数据。我们输入一个信号到 EMD,我们将得到一些分解的信号,也就是我们信号输入的“基本成分”。它类似于快速傅立叶变换(FFT)。FFT 假设我们的信号是周期性的,它的“基本成分”是各种简单的正弦波。在 FFT 中,我们的信号是从时间频谱转换到频率频谱。
EMD 的不同之处在于输出保留在时间谱中,并且 EMD 不假设我们的信号是周期性的,它不是基于简单的正弦波,而是基于固有模式函数(IMF)。EMD 实际上是基于数据集的,没有关于数据的假设(这就是为什么它被称为经验的)。IMF 是一个波,它有两个特性:
- 最大值和最小值最多相差 1 个。最大值是波峰,最小值是波谷。
假设我们的数据集已经使用
z is the standardized value of data, x is the real value of data, μ is the mean of the dataset, and σ is the standard deviation of the dataset
然后最大值不总是大于零,最小值不总是小于零。最大值是信号的值,当信号的趋势继续上升,然后突然下降时,正好在值下降之前的值是最大值。另一方面,最小值是当信号的趋势继续下降,然后突然上升时,上升前的值是最小值。
2.IMF 的波动均值为零。
一个简单的正弦波就是一个 IMF(最小值和最大值之间的差值最多为 1,数据集的平均值为零)。
>>> import numpy as np
>>> frequency = 1
>>> total_time = 1
>>> res = 0.01
>>> time = np.arange(0, total_time, res)
>>> amplitude = np.sin(2 * np.pi * frequency * total_time * (time/time[-1]))
>>> np.mean(amplitude)
-2.6319088627735572e-17 #this value literally equal 0
The difference between maxima and minima in 1 Hz sine wave is 0
但是一个 IMF 可以有不止一个频率,而且更复杂。
为了让我们更容易理解算法,这里我呈现一个玩具测试信号。
该信号(1 Hz 正弦波)
和这个(4 Hz 正弦波)
结合成这样
瞧,我们将试着通过这一步一步的算法解释来分解这个信号。
这里是 EMD 的算法。
第一步,求最小值和最大值。
步骤 2,从最小值和最大值数组中创建最小值和最大值的包络。使用三次样条插值最小值和最大值以创建最小值和最大值的包络。
第四步,从最小值和最大值的包络中,得到中间值。
步骤 5,将真实玩具测试信号的值减少包络线的中间值。
如果你仔细看,这是我们成功提取的 4 Hz 正弦波。但是看起来有一些误差,比如波的两边有一个突然的跳跃。这来自于三次样条的插值误差。三次样条插值在信号开始和结束时变得如此糟糕。解决方法是我们必须定义一个边界条件。关于边界条件,我的意思是在进行三次样条之前,我们必须定义信号开始和结束时的最小值和最大值的包络。在这篇文章中,信号开始和结束时的最小值和最大值的包络与离它们最近的最大值和最小值相同。让我们从步骤 1 到步骤 5 重新开始,但是这次,我们定义边界条件。
哎哟,这一次的错误是影响整个提取的信号。但是这种突然的飞跃已经消失了。
步骤 6,检查该提取的信号是否是 IMF 。
#here is the ouput of python script
mean: -0.002681745482482584
Total minima 20
Total maxima 21
平均值几乎为零,我认为我们可以忽略它,将其四舍五入为零。最小值和最大值的数量也满足要求,我们得到一个 IMF 。如果您对提取信号的平均值不满意,您可以按照步骤 2-步骤 6 再处理一次。但是这一次,我们使用提取的信号,而不是输入真实的玩具测试信号。当在第一次或第二次等尝试中,提取的信号不满足 IMF 条件时,这是算法的路线。为了使它更简单,让我们承认信号是一个国际货币基金组织。
第七步,用这个 IMF 降低原来的玩具测试信号。
哇,我们得到了我们的 1 Hz 信号(但正如我们所想的,开始和结束是错误的)。看来我们成功地分解了融合信号。但是,在 EMD 算法中停止的条件是当我们的残差信号只是一个常数,单调的,或只有 1 个极值(只有 1 个最小值或最大值)。我们之前被 IMF 减少的信号被称为残差。让我们继续这个过程。
mean: -0.002681745482482584
Total minima 6
Total maxima 6
看起来渣油的要求还没有满足。让我们再处理一遍。
mean: -0.002681745482482584
Total minima 2
Total maxima 2
最后,我们找到了剩余(单调的)。由于边界的累积误差,最后提取的像噪声一样。这可以通过提高信号平均值的阈值来防止。当信号的平均值不满足阈值时(提取的信号不是 IMF),它将按照步骤 2–6 再次尝试,直到提取的信号满足阈值。阈值越趋近于零,这种噪声就越有可能消失。所以这篇文章不会太长,在前面的 EMD 算法演示中,我们使用的阈值并不是太严格。因为最终我们想要达到的是,读者一步一步地理解 EMD 算法。
第一次,我在尝试使用 google colab,所以所有构建上面所有图的代码和解释都可以通过这个链接 访问(PS:有些代码必须按顺序运行才能正常工作)。
再见。
参考资料:
https://medium . com/@ rrfd/standardize-or-normalize-examples-in-python-E3 f 174 b 65 DFC,2019 年 10 月 2 日获取
a .泽勒、r .法特尔迈尔、I. R .凯克、A. M .汤姆、C. G .蓬托内特和 E. W .朗(2010 年 7 月)。经验模态分解-导论。在2010 年国际神经网络联合会议(IJCNN) (第 1-8 页)。IEEE。
解构伯特,第 2 部分:视觉化注意力的内部运作
原文:https://towardsdatascience.com/deconstructing-bert-part-2-visualizing-the-inner-workings-of-attention-60a16d86b5c1?source=collection_archive---------4-----------------------
一种新的可视化工具展示了伯特如何形成其独特的注意力模式。
在 第一部分 (非先决条件)中我们探讨了 BERT 语言模型是如何学习各种直观结构的。在第二部分中,我们将深入探讨伯特的注意力机制,并揭示其变形超能力的秘密。
试玩一款 互动演示 搭配bertviz*。*
自人工智能领域诞生以来,赋予机器理解自然语言的能力一直是该领域的一个愿望,但事实证明这一目标难以实现。在某种意义上,理解语言需要解决更大的人工智能问题(AGI)。例如,图灵测试——最早构想的机器智能测量之一——是基于机器用自然语言与人类对话的能力。
然而,就在最近几年,自然语言处理(NLP)领域发生了一场静悄悄的革命。新的深度学习模型已经出现,大大提高了机器处理语言的能力,导致从情感分析到问题回答的 NLP 任务的性能大幅提高。
也许这些模型中最著名的是 BERT(BI directionalEn coderR表示来自Ttransformers)。BERT 基于 NLP 领域的两个最新趋势:(1)迁移学习和(2)转换模型。
迁移学习 的思想是在一个任务上训练一个模型,然后利用获得的知识提高模型在一个相关任务上的表现。BERT 首先接受两项无监督任务的训练:掩蔽语言建模(预测句子中缺失的单词)和下一句预测(预测一个句子是否自然跟随另一个句子)。通过在大型语料库(所有英语维基百科和 11,000 本书)上进行预训练,BERT 可以在英语工作的坚实基础上完成任何新任务。
BERT 的基础是 变换器 模型,这是一种接受序列作为输入(例如单词序列)并产生一些输出(例如情感预测)的神经网络。不同于传统的循环网络,如 LSTMs 依次处理每个序列元素,变压器通过注意机制在各个元素之间形成直接连接,从而同时处理所有元素。这不仅实现了更高的并行性,还提高了一系列任务的准确性。
伯特的建筑
BERT 有点像 Rube Goldberg machine(鲁布·戈德堡机器)( T17 ):虽然端到端系统看起来很复杂,但是各个组件都很简单。在这篇文章中,我将关注 BERT 的核心部分:注意力。
粗略地说,注意力是模型根据输入特征对某项任务的重要性为其分配权重的一种方式。例如,当决定一幅图像是否包含一只狗或猫时,模特可能会更多地关注图像中毛茸茸的部分,而不是背景中的灯或窗户。
类似地,一个试图完成句子“狗从街那头跑到我和 ____* ”的语言模型可能想对单词狗比对街、更关注,因为知道主语是狗对预测下一个单词比知道狗从哪里来更重要。正如我们稍后将看到的,注意力还可以用来在单词之间形成连接*,使伯特能够学习各种丰富的词汇关系。**
你注意到了吗?
幸运的是,伯特的注意力机制非常简单。假设你有一些序列 X ,其中每个元素是一个向量(称为值)。在下面的例子中, X 由 3 个向量组成,每个向量的长度为 4:
Attention 只是一个函数,它将 X 作为输入,并返回另一个相同长度的序列 Y ,由与 X 中相同长度的向量组成:
其中 Y 中的每个向量只是 X 中的向量的加权平均值:
就是这样——注意力只是加权平均的一个花哨名字!权重显示了在计算加权平均值时,模型对 X 中的每个输入的关注度,因此被称为注意力权重。稍后,我们将讨论这些注意力权重是如何计算的。
(注意,注意力不是 BERT 的唯一成分;还有前馈层、残差连接和层归一化模块,它们都与注意力组件一起工作以产生模型输出。但是注意力才是真正的主力,所以我们会关注这一点。有关其他组件的更多详细信息,请查看参考资料部分的教程。)
关注语言
那么注意力是如何应用于语言的呢?好吧,假设 X 表示像“狗跑了”这样的单词序列。我们可以将每个单词与一个连续的向量相关联——称为单词嵌入—* ,它捕获单词的各种属性:*
可以想象,这些属性代表了单词的情感,是单数还是复数,词性指示符等等。在实践中,单词嵌入不那么容易解释,但是仍然有很好的特性。例如,在嵌入空间中,具有相似含义的单词通常彼此接近。此外,可以对单词嵌入执行算术运算并产生有意义的结果,例如嵌入(国王)—嵌入(男人* ) +嵌入(女人 ) ≈嵌入(女王)。*
由于注意力也是简单算术的一种形式,因此将注意力应用于这些单词嵌入似乎是合理的:
通过关注 X 中的单词嵌入,我们在 Y 中产生了复合嵌入(加权平均)。例如, Y 中 dog 的嵌入是分别具有权重 0.2、0.7 和 0.1 的 the、和raninX、的嵌入的组合。**
构建单词嵌入如何帮助模型实现其理解语言的最终目标?要完全理解语言,仅仅理解组成句子的单个单词是不够的;模型必须理解单词在句子的上下文中是如何相互关联的。注意机制通过形成模型可以推理的复合表示,使模型能够做到这一点。例如,当语言模型试图预测句子“the running dog was __”中的下一个单词时,除了单独理解概念 running 或 dog 之外,该模型还应该理解 running dog 的复合概念;例如,走狗经常喘气,所以气喘吁吁是句子中合理的下一个词。
视觉化注意力
注意力为我们提供了一个镜头(尽管模糊不清),通过这个镜头我们可以看到伯特是如何形成复合表征来理解语言的。我们可以使用 BertViz 来访问这个镜头,这是一个我们开发的交互式工具,可以从多个角度可视化 BERT 中的注意力。
下面的图像(在这里有交互形式)显示了一个样本输入文本引起的注意。这个视图将注意力可视化为连接被更新的单词(左)和被关注的单词(右)的线,遵循上面图的设计。颜色强度反映了注意权重;接近 1 的权重显示为非常暗的线,而接近 0 的权重显示为模糊的线或者根本看不到。用户可以突出显示特定的单词,以仅看到来自该单词的关注。这种可视化被称为注意力-头部视图,原因稍后讨论。它基于来自 Llion Jones 的优秀 Tensor2Tensor 可视化工具。****
********
Left: visualization of attention between all words in the input. Right: visualization of attention from selected word only.
在这个例子中,输入由两个句子组成:“兔子快速跳跃”和“乌龟缓慢爬行”。【SEP】符号是表示句子边界的特殊分隔符,而【CLS】是附加在输入前面的符号,用于分类任务(详见参考文献)。****
可视化显示,在没有跨越句子边界的单词之间,注意力最高;该模型似乎明白,它应该将单词与同一个句子中的其他单词相关联,以便最好地理解它们的上下文。
然而,一些特定的词对比其他词对具有更高的注意力权重,例如兔子和蹦出。在这个例子中,理解这些单词之间的关系可能有助于模型确定这是对自然场景的描述,而不是肉食美食家对供应兔子的跳跃餐厅的评论。****
多头注意力
上面的可视化显示了模型中的一种注意力机制。伯特实际上学会了多种注意力机制,称为头,它们彼此平行运作。我们很快就会看到,与单个注意力机制相比,多头注意力使模型能够捕捉更广泛的单词之间的关系。**
伯特还堆叠了多层注意力,每一层都对上一层的输出起作用。通过单词嵌入的这种重复组合,BERT 能够在到达模型的最深层时形成非常丰富的表示。
因为注意力头部不共享参数,所以每个头部学习独特的注意力模式。我们在这里考虑的 BERT 版本— BERT Base — 有 12 层和 12 个头,导致总共 12 x 12 = 144 个不同的注意机制。我们可以使用模型视图(在交互形式中可用这里 )一次可视化所有头部的注意力:**
Model view (first 6 layers) for input sentences “the rabbit quickly hopped” and “the turtle slowly crawled”.
模型视图中的每个单元显示特定层(由行指示)中特定头部(由列索引)的注意模式,使用先前的注意头部视图的缩略图形式。注意模式是特定于输入文本的(在这种情况下,与上面的注意头视图的输入相同)。从模型的角度来看,我们可以看到伯特产生了丰富的注意模式。在本文的后半部分,我们将探索 BERT 是如何生成如此多样的模式的。
解构注意力
前面我们看到了模型如何使用注意力来计算单词嵌入的加权平均值,但是注意力权重本身是如何计算的呢?
答案是 BERT 使用了一个兼容性函数,它给每一对单词分配一个分数,表明它们应该多重视彼此。为了测量兼容性,模型首先为每个单词分配一个查询向量和一个关键字向量:****
这些向量可以被认为是一种单词嵌入类型,就像我们前面看到的值向量一样,但是是专门为确定单词的兼容性而构造的。在这种情况下,兼容性得分只是一个单词的查询向量和另一个单词的关键向量的点积,例如:**
为了将这些兼容性得分转化为有效的注意力权重,我们必须将它们归一化为正,并且总和为 1(因为注意力权重用于计算加权平均值)。这是通过对给定单词的分数应用 softmax 函数来实现的。例如,当计算从狗到狗和跑的注意力时,我们有:****
右侧的 softmax 值代表最终的注意力权重。注意,在实践中,点积首先通过除以矢量长度的平方根来缩放。这是因为长矢量可能会产生非常高的点积。
所以我们现在知道注意力权重是从查询和关键向量中计算出来的。但是查询和关键向量来自哪里呢?与前面提到的值向量一样,它们是基于前一层的输出动态计算的。这个过程的细节超出了本文的范围,但是您可以在最后的参考资料中读到更多关于它的内容。
我们可以使用神经元视图,下面的(在这里以交互形式)来可视化如何从查询和关键向量中计算注意力权重。这个视图跟踪注意力的计算,从左边的选定单词到右边的完整单词序列。正值表示蓝色,负值表示橙色,颜色强度表示大小。就像前面提到的注意力-头部视图一样,连接线表示连接单词之间的注意力强度。****
Neuron View
让我们一次浏览一个神经元视图中的列,并重温前面讨论的一些概念:
查询 q:查询向量 q 对左侧正在关注的单词进行编码,即正在“查询”其他单词的那个单词。在上例中,突出显示了“on”(所选单词)的查询向量。****
键 k: 键向量 k 对关注的右边的单词进行编码。关键向量和查询向量一起确定两个单词之间的相容性分数。
q×k 这是点积(元素乘积之和)的前身,包含它是为了可视化,因为它显示了查询中的单个元素和关键向量是如何构成点积的。
q k :所选查询向量和每个关键向量的比例点积(见上图)。这是未标准化的注意力得分。
Softmax :缩放后的点积的 Softmax。这将注意力分数归一化为正值,并且总和为 1。
神经元的观点最好通过交互来理解。您可以观看下面的简短视频演示(或直接访问工具):
解释伯特的注意力模式
正如我们在前面的模型视图中看到的,伯特的注意力模式可以呈现出许多不同的形式。在本系列的第 1 部分中,我描述了其中有多少可以用少量的可解释结构来描述。在本节中,我们将重温这些核心结构,并使用神经元观点来揭示伯特可塑性力量的秘密。
聚焦定界符的注意模式
让我们从最受关注的句子分隔符【SEP】标记(来自 Part 1 的模式 6)这个简单的案例开始。正如本文中所讨论的,这种模式充当一种“无操作”;当注意力头在输入句子中找不到任何其他可以关注的东西时,它会关注【SEP】标记:**
Delimiter-focused attention pattern for Layer 7, Head 3 of the BERT-base pretrained model.
那么,伯特究竟是如何能够专注于【SEP】记号的呢?让我们看看可视化是否能提供一些线索。这里我们看到上面例子的神经元视图:**
在键列中,两次出现的【SEP】的键向量带有一个独特的签名:它们都有少量具有强正(蓝色)或负(橙色)值的活跃神经元,以及大量具有接近于零(浅蓝色/橙色或白色)值的神经元:**
Key vector for first [SEP] token.
查询向量倾向于与那些活动神经元的【SEP】关键向量相匹配,从而导致元素态乘积 q×k 的高值,如下例所示:**
Query vector for first occurrence of “the”, key vector for first occurrence of [SEP], and elementwise product of the two.
其他单词的查询向量遵循类似的模式:它们沿着同一组神经元匹配【SEP】关键向量。因此,看起来 BERT 已经将一小组神经元指定为“[SEP]-匹配神经元”,并且查询向量被分配与这些位置处的 [SEP] 关键向量相匹配的值。结果就是【SEP】——集中注意力模式。****
单词袋注意模式
这是一种不太常见的模式,在第 1 部分中没有讨论。在这个模式中,注意力被平均分配到同一个句子中的所有单词:**
Sentence-focused attention pattern for Layer 0, Head 0 of the BERT-base pretrained model.
BERT 本质上是通过对同一个句子中的单词嵌入进行(几乎)未加权平均来计算单词包的嵌入。
那么,BERT 是如何巧妙处理这些查询和关键字来形成这种注意力模式的呢?让我们再次回到神经元的角度:
Neuron view of sentence-focused attention pattern for Layer 0, Head 0 of the BERT-base pretrained model.
在 q×k 列中,我们看到了一个清晰的模式:少数神经元(2-4 个)主导了注意力分数的计算。当查询和关键向量在同一个句子中时(在这种情况下是第一个句子),乘积在这些神经元上显示高值(蓝色)。当查询和关键向量在不同的句子中时,在这些相同的位置,乘积是强负的(橙色),如下例所示:
The query-key product tends to be positive when query and key are in the same sentence (left), and negative when query and key are in different sentences (right).
当 query 和 key 都来自句子 1 时,它们倾向于具有沿着活动神经元的相同符号的值,导致正乘积。当查询来自句子 1,而关键字来自句子 2 时,相同的神经元倾向于具有符号相反的值,导致负乘积。
但是 BERT 是怎么知道“句子”这个概念的,尤其是在更高层次的抽象形成之前的网络第一层?如前所述,BERT 接受特殊的【SEP】记号来标记句子边界。此外,BERT 合并了添加到输入层的句子级嵌入(参见下面的图 1)。这些句子嵌入中编码的信息流向下游变量,即查询和关键字,并使它们能够获得特定于句子的值。**
Figure 1: Segment embeddings for Sentences A and B are added to the input embeddings, along with position embeddings. (From BERT paper.)**
下一个词的注意模式
在下一个单词注意模式中,除了在【SEP】和【CLS】标记处,几乎所有的注意力都集中在输入序列中的下一个单词上:****
Next-word attention pattern at Layer 2, Head 0 of the BERT-base pretrained model.
该模型将重点放在下一个单词上是有意义的,因为相邻的单词通常与理解单词在上下文中的含义最相关。传统的 n -gram 语言模型也是基于同样的直觉。让我们看看上面例子的神经元视图:
我们看到“the”的查询向量和“store”(下一个单词)的关键向量的乘积在大多数神经元中都是强正的。对于除了下一个标记之外的标记,键查询产品包含一些正值和负值的组合。结果是“The”和“store”之间的关注度得分较高。
对于这种注意力模式,大量的神经元被纳入注意力得分,并且这些神经元根据标记位置而不同,如下所示:
Elementwise product of query and key vectors, for query at position i and key at position i+1, for i = 2, 8, 14. Note that the active neurons differ in each case.
这种行为不同于以定界符为中心和以句子为中心的注意模式,在这两种模式中,一小组固定的神经元决定注意分数。对于这两种模式,只需要几个神经元,因为模式非常简单,而且受到关注的单词几乎没有变化。相反,下一个单词注意模式需要跟踪 512 个单词中的哪一个从给定位置受到注意,即,哪一个是下一个单词。为此,它需要生成查询和键,使得每个查询向量与来自 512 种可能性的唯一键向量匹配。使用一小部分神经元很难做到这一点。
那么 BERT 是如何生成这些位置感知查询和密钥的呢?在这种情况下,答案在于 BERT 的位置嵌入,它在输入层被添加到单词嵌入中(见图 1)。BERT 为输入序列中的 512 个位置中的每一个学习唯一的位置嵌入,并且该特定于位置的信息可以通过模型流到键和查询向量。
关于我的可视化工作和其他人工智能项目的更新,请随时关注我的Twitter。******
笔记
我们只涉及了第一部分中讨论的一些粗略的注意力模式,还没有触及围绕语言现象的更低层次的动态,如共指、同义等。我希望这个工具可以帮助为这些案例提供直觉。
试试吧!
你可以在 Github 上查看可视化工具。请玩玩它,分享你的发现!
参考
您可以在这些优秀的教程中找到有关 BERT 和其他变压器模型的架构的更多详细信息:
有插图的伯特:一本关于伯特建筑的精美插图教程。
从零开始的变形金刚:这是一个详细而直观的从零开始构建变形金刚的教程,包括 PyTorch 代码。
承认
我要感谢 Richelle Dumond、John Maxwell、Lottie Price、Kalai Ramea 和 Samuel rnqvist 为本文提供的反馈和建议。
为了进一步阅读,请查看我最近的文章 ,其中我探索了 OpenAI 的文本生成器 GPT-2。
解构伯特
原文:https://towardsdatascience.com/deconstructing-bert-reveals-clues-to-its-state-of-art-performance-in-nlp-tasks-76a7e828c0f1?source=collection_archive---------14-----------------------
揭示了它在 NLP 任务中最先进的表现的线索
This picture is an adaptation of a figure in the blog for paper — a structural probe for finding syntax in word representations
变压器架构模型,尤其是 BERT,已经被证明在许多自然语言处理任务中非常有效,只需对在大型语料库上以无监督方式预训练的模型进行微调。BERT 模型将单词序列作为输入,并产生一系列跨层的单词嵌入。这些单词嵌入考虑了单词出现的上下文。
两篇最近(2019 年 4 月和 2019 年 6 月 6 日)发表的论文 ( 1 及其 博 , 2 及其 博 ) 提供一些几何洞见
这些论文的一些关键发现
- BERT 的单词向量输出编码了丰富的语言结构。BERT 近似地将[语法树](http://Recovered Parse tree from BER vectors)编码到它为一个句子输出的单词嵌入中。有可能通过单词嵌入的线性变换来恢复这些树。( 1 及其 博客 )
- BERT 出现在互补子空间中对单词向量中的句法和语义特征进行编码( 2 及其 博客 )。
- 一个词的不同义项有着空间上细粒度分离的表征(由句子语境决定)(2及其 博客 )
从句子的 BERT 词向量中恢复分析树
语言由离散的结构组成——符号序列(单词),句子的句法结构被捕获在一棵树中。相比之下,神经网络模型对连续数据进行操作——它们将符号信息转化为高维空间中的向量。已知这些向量(单词嵌入)在其长度/方向(例如,word2vec、fasttext 等)中捕捉语义相似性。)。
如上所述,最近的发现显示伯特单词向量输出编码了丰富的语言结构。在向量输出中编码的句子是语法树的几何近似副本。句子中的单词被给定在高维空间中的位置,如果我们对这些单词向量进行特定的变换,这些位置之间的欧几里德距离映射到语法树距离。本质上,我们可以通过使用特定的线性变换来变换单词向量,然后根据单词向量之间的距离找到最小生成树,来恢复句子的语法树(以及具有方向边的依存树】。
语法树中的树距离(两个节点之间的树距离是它们之间的路径中的边数)和欧几里德距离(从单词嵌入导出的最小生成树中的节点之间)之间的映射不是线性的。两个单词之间的语法树距离对应于提取的最小生成树中相应节点之间的欧几里德距离 的 的平方。第二篇论文给出了为什么它是欧几里德距离的平方而不是欧几里德距离的平方的原因(本节的剩余部分对于理解伯特模型来说不是核心,可以跳过)。**
Figure from blog on second paper
由于树枝的存在,不可能将一棵树映射到欧几里得空间。
比如左边节点 A 和 B 之间的树距离是 2 — d (A,X)+d(X,B)
由于 d (A,B)=d(A,X)+d(X,B)在到欧氏空间的等距映射中,A,X,B 必须共线 ( X 必须在连接 A 和 B 的线上,以上条件成立)
同样的道理应用到 A 点、X 点、C 点, d (A,C)=d(A,X)+d(X,C)A、X、C 也必须共线。但这隐含着 B = C,这是一个矛盾。
然而,从树到平方距离(勾股嵌入)有一个等距映射,如下图所示
Figure from blog on second paper
博客文章有更多的例子。总的来说,它们说明了
还有,
这个博客还有其他有趣的结果。例如,随机分支的树,如果被映射到足够高维的空间,其中每个子树从其父树偏移一个随机单位高斯向量,将近似为勾股嵌入。这一点的实际含义是,上下文嵌入近似于句子的依存分析树的勾股嵌入。根据平方距离属性,我们从向量中恢复了嵌入树的整体形状。
恢复的树的形状(受节点间边长的影响)仅近似类似于理想树——差异具有一些模式。依赖关系之间的平均嵌入距离变化很大。不知道这些差异意味着什么。也许 BERTs 表示除了依赖关系解析树之外还有其他信息。
Figure from second paper
顺便说一句,如果我们对基因/蛋白质序列做同样的练习来检查它们是否包含信息,那么看到接近的异常边缘(部分/相同/如上图所示)将是有趣的——不一定证实实际的 3-D 几何构型。
句法树也在句子的注意力矩阵中被捕获
第二篇论文还展示了句子捕获句法树的注意矩阵。想想“老狐狸看见新狗”这句话。考虑词对“老,狐狸”。我们可以通过从所有层 (12 层,每层有 12 个注意力头)的每个注意力头中选取该对的标量值来构建向量如果我们训练线性分类器,这些线性分类器将每个单词对的这种模型范围的注意力向量作为输入,并且如果两个单词之间存在关系以及关系的类型,则进行分类,这些分类器表现得相当好(即使不是现有技术的结果)表明句法信息被编码在句子的注意力矩阵中。
Figure from second paper
BERT 似乎在其嵌入中编码了语义特征
通过简单地将单词如 die 在不同句子上下文中的嵌入可视化,我们可以看到词义是如何影响嵌入的。
Figure from second paper
一般来说,单词嵌入显示
- 一个词的不同义项被分开(上面三簇为“死”字)。词义消歧是通过这种分离来完成的
- 在群集内部,似乎存在着更细微的意义差别(参见下面单词“lie”的嵌入)
Figure from second paper
- 类似于我们前面看到的表示语法的位置,这里嵌入的位置表示语义
第二篇论文声称词义是在低维空间中捕捉的,尽管还不清楚这是怎么回事。鉴于这种观察,似乎向量在互补的子空间中编码句法和语义信息
对已发布代码的实验
第一篇论文的 Github 库有代码从上述句子中恢复语法树
例如,对于输入的句子
掉进下水道的小鸭子获救了
从上面句子的单词嵌入中恢复的解析树以及同一个句子的依存解析器输出如下所示
结论
未来沿着上述路线解构模型
- 可能揭示更多的语言结构(比如解析树)或者等价的更多的子空间
- 理解内部表示的几何可以潜在地发现改进模型架构的区域
Python 中的装饰函数
原文:https://towardsdatascience.com/decorating-functions-in-python-619cbbe82c74?source=collection_archive---------13-----------------------
什么是高阶函数?
source
在这篇文章中,我将解释什么是 Python decorators,以及如何实现它。我们开始吧!
什么是室内设计师?
装饰器只不过是一种调用高阶函数的舒适方式。你可能已经看过很多次了,它是关于那些“@dostuff”字符串的,你会不时地在函数的签名上面找到它们:
@dostuff
def foo():
pass
好的,但是现在,什么是高阶函数?高阶函数就是任何一个以一个(或多个)函数作为参数和/或返回一个函数的函数。例如,在上面的例子中,“@dostuff”是修饰者,“dostuff”是高阶函数的名称,“foo”是被修饰的函数和高阶函数的参数。
安全了吗?太好了,让我们开始实现我们的第一个装饰器吧!
打造我们的第一个室内设计师
为了开始实现我们的装饰器,我将向您介绍 functools : Python 的高阶函数模块。具体来说,我们将使用包装函数。
让我们创建一个高阶函数,它将打印被修饰函数的执行时间:我们称它为“timeme”。这样,每当我们想要计算函数的执行时间时,我们只需要在目标方法的签名上添加装饰符“@timeme”。让我们开始定义“timeme”的签名:
def timeme(func):
pass
如前所述,一个高阶函数将另一个函数(修饰函数)作为它的参数,所以我们在它的签名中包含了“func”。现在,我们需要添加一个包含计时逻辑的包装函数。为此,我们将创建一个“包装器”函数,它将被 functools 的包装器函数包装:
from functools import wrapsdef timeme(func):
@wraps(func)
def wrapper(*args, **kwargs):
pass return wrapper
注意,“timeme”返回函数“wrapper ”,该函数除了打印执行时间之外,还将返回修饰函数的结果。
现在,让我们通过实现计时逻辑来完成包装器:
from functools import wraps
import timedef timeme(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Let's call our decorated function")
start = time.time()
result = func(*args, **kwargs)
print('Execution time: {} seconds'.format(time.time() - start))
return result
return wrapper
注意,修饰函数“func”是用它的位置和关键字参数执行的。我添加了一些打印消息,供您观察执行顺序。好吧!让我们试一试,我将创建一个简单的函数,带有一条打印消息,用“timeme”来修饰:
@timeme
def decorated_func():
print("Decorated func!")
如果您运行它,您将看到如下内容:
Let's call our decorated function
Decorated func!
Execution time: 4.792213439941406e-05 seconds
如您所见,第一个打印消息被放在高阶函数中。然后,我们调用修饰的函数并打印它自己的消息。最后,我们计算执行时间并打印出来。
重复数据删除
原文:https://towardsdatascience.com/deduplication-deduplication-1d1414ffb4d2?source=collection_archive---------13-----------------------
是的,这就是我想帮你解决的问题。删除那些造成伤害、阻碍某些任务的效率甚至污染我们系统的肮脏的小副本。
重复数据删除
/diːˌdjuːplɪˈkeɪʃ(ə)n/名词消除重复或多余的信息,尤其是计算机数据。
“重复数据删除在存储之前删除重复信息”
正如定义所说,我们要做的任务是删除重复的文本/句子等等。这只不过是检查文本彼此有多相似的行为。他们可以一模一样的像:
深度学习牛逼!和深度学习牛逼!。或者,就句子试图传达的内容而言,它们可能非常相似,比如:
深度学习太棒了!和深度学习太酷了。 我们知道这两句话传达的是同一个东西,这也是我们希望我们的机器捕捉到的东西。
这样的任务在文献中被称为语义文本相似性(STS)。它处理确定两段文本有多相似。这将不仅包括句法相似度,即两个句子中使用的单词有多相似或相同,还包括语义相似度,它捕捉了使用两个句子所传达的内容的相似度,即文本的含义在确定相似和不相似方面起着重要作用。
问题
问题。是的,这是我们的主要目标。来解决问题。我给你举个例子。比方说,你必须通过电子邮件向一群人发送非常有趣的笑话(你的笑话可以是一句话或一串话)。你的老板要求你确保人们不会收到同样的笑话。所以你必须确保你所有的笑话都是独一无二的,人们不会对其内容感到厌烦。
什么工作,认真?
作为一名出色的程序员,你决定自动完成这项任务。你有这个神奇的 API,可以免费给你很多笑话,你写一个脚本,把这些笑话发给你老板喜欢的那群人。但是,我们不能真的相信这个神奇的 API,不是吗?简直神奇。API 给你开类似的玩笑怎么办?你不能冒险惹恼你的老板。
这是你可以使用 重复数据删除引擎 的地方,确保发送的笑话不会与过去发送的笑话相似。
我在这里的主要目的不是谈论这些模型。而是为了帮助您在实际工作中使用它们,就像上面提到的那样。我承认,为了给你的老板留下深刻印象而向别人发送笑话并不实际。
在 STS 的空间里…
让我们试着把它分解成这种相似性度量是如何定义的,以及我们试图找出哪两个实体之间的相似性(字面上是文本本身,还是别的什么?).
首先是,说到相似性度量,可以使用的有不少。只是为了完整起见,列举几个:
1。 Jaccard 相似度2。余弦相似度3。推土机距离4。詹森-香农距离
但是为了切入正题,我们将使用余弦相似度。数学上,余弦相似度是内积空间的两个向量(非零)之间相似度的度量,度量它们之间角度的余弦。
如果两个文档相似,并且在欧几里得空间中相距很远,它们仍然可以彼此非常接近。这是由余弦距离捕获的,因此是有利的。
其次,这个余弦距离我们用在哪里?成对的句子串之间?没有。这就是我们利用自然语言处理和深度学习的力量。我们使用向量。
一个单词/句子向量是一行实数值 (与虚拟数字相反),其中 每个点捕捉单词/句子的一个维度的含义 和 ,其中语义相似的单词/句子具有相似的向量。
同样,有很多方法可以得到这些向量。举几个:
单词嵌入 : word2vec、GloVe、BERT 单词嵌入、ELMo 等等。
语句嵌入 : BERT 语句嵌入,通用语句编码器等。
我将直接进入我亲自试验过的方法,这些方法对我非常有效。
[word2vec](https://github.com/mmihaltz/word2vec-GoogleNews-vectors) + [Universal Sentence Encoder](https://tfhub.dev/google/universal-sentence-encoder-large/3)
为了避免这篇文章成为一篇纯粹的面向实现的文章(这正是我们想要的),我将试着简单地解释一下这些模型是什么。
word2vec
word2vec 有两种变体: Skip-Gram 和连续单词包模型(CBOW)。如果你想寻找详细的解释,关于这两种变体有大量的材料。我会很干脆的。skip-gram 模型速度稍慢,但通常在处理不常用的单词时效果更好。因此,这是经常使用的。这个我们简单说一下。
你会在几乎所有的 word2vec (Skip-Gram model)博客和教程中找到这个图表。在这种架构中,模型使用当前单词来预测上下文单词的周围窗口。它对附近的上下文单词的加权比对远处的上下文单词的加权更重。
这里,我们看一个上下文单词的窗口(在这种情况下,每边 2 个单词),并尝试预测中心单词。
The Skip-gram model architecture (https://arxiv.org/pdf/1301.3781.pdf)
考虑 w(t) 是输入字,通常权重矩阵和输入向量 w(t) 之间的点积是由单隐层完成的。我们将 softmax 函数应用于隐藏层的输出向量和权重矩阵之间的点积。这给出了单词在当前单词位置出现在 w(t) 的上下文中的概率。
隐藏层中的矢量成为了这个单词的矢量表示。但是这些都是'字'嵌入,和我们要找的相似的'句子'。那么,我们如何得到句子的向量表示而不仅仅是单词嵌入呢?
一种简单而琐碎的方法(我今天将展示的方法)是简单地对该句子的所有单词的单词嵌入进行平均。很简单,不是吗?
现在对于主要部分,让我们把它编码进去。
w2vmodel = **gensim.models.KeyedVectors.load_word2vec_format**(
'models/GoogleNews-vectors-negative300.bin.gz'), binary=True) **def** sent2vec**(s)**:
'''
Finding word2vec vector representation of sentences @param s : sentence
'''
words = **str**(s).**lower**()
words = **word_tokenize**(words)
words = [w **for** w **in** words **if** **not** w **in** stop_words]
words = [w **for** w **in** words **if** w.**isalpha**()]
featureVec = **np.zeros**((300,), dtype="float32")
nwords = 0
**for** w **in** words:
**try**:
nwords = nwords + 1
featureVec = **np.add**(featureVec, w2vmodel[w])
**except**:
**continue**
# averaging
**if** nwords > 0:
featureVec = **np.divide**(featureVec, nwords)
**return** featureVec **def** get_w2v_vectors**(list_text1, list_text2)**:
‘’’
Computing the word2vec vector representation of list of sentences
@param list_text1 : first list of sentences
@param list_text2 : second list of sentences
‘’’
**print**(“Computing first vectors…”) text1_vectors = **np.zeros**((len(list_text1), 300))
**for** i, q **in** tqdm(enumerate(list_text1)):
text1_vectors[i, :] = sent2vec(q) text2_vectors = **np.zeros**((len(list_text2), 300))
**for** i, q **in** tqdm(enumerate(list_text2)):
text2_vectors[i, :] = sent2vec(q) **return** text1_vectors, text2_vectors
就是这样!🤷♂你有你的句子嵌入使用 word2vec 。
通用句子编码器
谷歌展示了一系列用于将句子编码成向量的模型。作者特别针对下游任务,即迁移学习任务。STS 就是这样一个任务。
它有两种变体:
1。一个带有 变压器 编码器
2。一用一 深度平均网络
他们每个人都有不同的设计目标:
1。以更大的模型复杂性和资源消耗为代价来实现高精度。
2。目标是以稍微降低的准确度进行有效的推理。
我已经用我最喜欢的博客将这两种架构都做了超链接,这些博客对它们都做了很好的解释。让我们更关注如何实现它们。
usemodel = **hub.Module**('models/sentence_encoder')**def** get_use_vectors**(list_text1, list_text2)**:
'''
Computing the USE vector representation of list of sentences
@param list_text1 : first list of sentences
@param list_text2 : second list of sentences
'''
**print**("Computing second vectors...")
messages1 = list_text1
messages2 = list_text2 num_batches = **math.ceil**(len(messages1) / BATCH_SIZE) # Reduce logging output.
**tf.logging.set_verbosity**(tf.logging.ERROR) message_embeddings1 = []
message_embeddings2 = [] **with** tf.Session() **as** session:
session.**run**([tf.global_variables_initializer(),
tf.tables_initializer()]) **for** batch **in** range(num_batches):
**print**(batch * BATCH_SIZE, batch *
BATCH_SIZE + BATCH_SIZE)
batch_msgs1 = messages1[batch * BATCH_SIZE: batch *
BATCH_SIZE + BATCH_SIZE]
batch_msgs2 = messages2[batch * BATCH_SIZE: batch *
BATCH_SIZE + BATCH_SIZE] message_embeddings1_temp, message_embeddings2_temp = session.**run**([usemodel(batch_msgs1), usemodel(batch_msgs2)])
message_embeddings1.**append**(message_embeddings1_temp)
message_embeddings2.**append**(message_embeddings2_temp) all_embedding1 = **np**.**concatenate**(**tuple**(message_embeddings1))
all_embedding2 = **np**.**concatenate**(**tuple**(message_embeddings2)) **return** all_embedding1, all_embedding2
再说一遍,就是这样!🤷♂
现在我们有了来自两个不同模型的笑话的句子嵌入。
现在我们需要余弦相似度!
**def** cosine_similarity**(list_vec1, list_vec2)**:
'''
Computing the cosine similarity between two vector representation
[@param](http://twitter.com/param) list_text1 : first list of sentences
[@param](http://twitter.com/param) list_text2 : second list of sentences
'''
cosine_dist = [cosine(x, y) **for** (x, y) **in** **zip**(np.nan_to_num(list_vec1), np.nan_to_num(list_vec2))] cosine_sim = [(1 - dist) **for** dist **in** cosine_dist] **return** cosine_sim
当我在你之前做这份工作时,我有一堆不重复的笑话,很少有重复的。具体来说,我有 385K 非重复对和 10K 重复对。我仅使用 word2vec 模型绘制了这项任务的 AUC-ROC 。
AUC-ROC
不错!曲线看起来很漂亮。(我故意省略了混淆矩阵)。
TPR/召回率/敏感度:77%
FPR:2.2%
让我们看看通用句子编码器的表现如何。
AUC-ROC
曲线下的区域稍微好一点,不是吗?
TPR/召回/敏感度:77%
FPR:2.2%
让我们看看当我们把它们结合在一起时会发生什么。通过组合,我的意思是平均来自两种方法的余弦相似性,并检查度量。“一个平均的集合的模型”。
迄今为止最好的一个!
TPR/召回/敏感度:78.2%
FPR:1.5%
喔喔喔!🎉🎉我们有一个明确的赢家!
这是一种快速查找重复项的方法。无需培训,只需下载现有的优秀模型并将其用于您的 STS 任务!
有了这一块,您可以轻松构建您的重复数据删除引擎。只需存储你第一天发送到老板小组的所有笑话,然后对于每个新来的笑话,将它们与之前看到的所有笑话配对,并使用这个集合模型来确定它们是否重复。如果是,就扔掉。
通过这种方式,让你老板的朋友开心,老板开心,得到一份不错的薪水,让你自己开心:)
使用 spark 的 MLlib 进行数据集重复数据删除
原文:https://towardsdatascience.com/deduplication-using-sparks-mllib-4a08f65e5ab9?source=collection_archive---------10-----------------------
对于拥有大量数据的公司来说,重复数据删除过程始终非常重要。首先,重复数据删除最大限度地减少了存储业务数据所需的空间,并将为我们的管道带来更低的基础设施成本和更好的性能。另一方面,通过持续集成和持续交付 (CI/CD) ,减少重复的数量将降低管道的复杂性,并增加业务时间。
有时,重复数据删除过程由简单的文本到文本匹配组成,您可以简单地选择 CRC32 校验和或 MD5 匹配。然而,在一些情况下,数据集的行仅仅因为一些列上的一些小的文本差异而不同,即使它们表示相同的实体。因此,本文展示了一个实体识别和链接过程使用了两种不同的 spark 方法,对报废电子商务网站收集的特定产品数据集进行处理。
下面描述完整代码和过程可以在这里找到:
[## Ronald-Smith-angel/dataset _ 重复数据删除 _sparkml
使用 spark ML 库和 Scala-Ronald-Smith-angel/dataset _ de duplication _ spark ML 进行数据集重复数据删除
github.com](https://github.com/ronald-smith-angel/dataset_deduplication_sparkml)
一般的过程可以在这个特质上找到( …是的,我用 scala 做数据科学!!!):
package com.sample.utils
import org.apache.spark.sql.DataFrame
trait OperationsHelper {
def ds: DataFrame
def preparedDataSet()(df: DataFrame): DataFrame
def deduplicateDataSet()(df: DataFrame): DataFrame
def resultsDataFrame()(df: DataFrame): DataFrame
}
正如你将看到的,这个助手背后的想法将是有一个函数管道,从这里可以轻松地调用链数据帧 转换 。
预处理产品数据
数据科学界广泛使用降维技术来获得更小的特征集,以便在训练和评估模型时进行分析并获得更好的性能。PCA 方法允许降维,同时保留那些描述大量信息的特征。因此,该预处理阶段遵循以下步骤:
- 数据清洗: 清洗数据要有一个通用的刻度。对于产品的情况,数据集由一个简单的文本清理组成,包括大小写、空白、编码和符号。
- 特征选择:使用 PCA 技术选择一组特征。(“标题块”、“内容块”、“颜色”、“产品类型”)
上述特性中的内容包含候选重复产品的大部分差异。
1 —方法 A:区分位置的散列法(LSH)
位置敏感散列是一种用于实体解析的技术,然后将找到代表相同实体的记录。spark MLlib 有一个自定义的 LSH 实现,这里使用它来查找如下重复项:
- 首先,使用所选特征的串联来生成散列(上面的 PC)。对于真实世界的例子,可以生成每个特征的散列。但是,对于这个示例,为了更快地获得结果,使用了一个简单的串联列。
- 然后,该列用于生成 LSH 向量,如下所示:
—分词器使用 单词停止器 为记录生成单词列表。
—计数矢量模型为 LSH 算法创建带有哈希和桶(类似哈希)的矢量。
**val** pccTokenizer = **new** Tokenizer()
.setInputCol(OperationsHelperLSH.*ConcatComments*)
.setOutputCol(OperationsHelperLSH.*ColumnWordsArray*)
**val** wordsArrayDF = pccTokenizer.transform(df)
**val** remover = **new** StopWordsRemover()
.setCaseSensitive(**false**)
.setStopWords(OperationsHelperLSH.*stopWords*)
.setInputCol(OperationsHelperLSH.*ColumnWordsArray*)
.setOutputCol(OperationsHelperLSH.*ColumnFilteredWordsArray*)
**val** wordsFiltered = remover.transform(wordsArrayDF)
**val** validateEmptyVector = *udf*({ v: Vector => v.numNonzeros > 0 }, DataTypes.*BooleanType*)**val** vectorModeler: CountVectorizerModel = **new** CountVectorizer()
.setInputCol(OperationsHelperLSH.*ColumnFilteredWordsArray*)
.setOutputCol(OperationsHelperLSH.*ColumnFeaturesArray*)
.setVocabSize(*VocabularySHLSize*)
.setMinDF(10)
.fit(wordsFiltered)
**val** vectorizedProductsDF = vectorModeler.transform(wordsFiltered)
.filter(validateEmptyVector(*col*(OperationsHelperLSH.*ColumnFeaturesArray*)))
.select(*col*(OperationsHelperWindowStrategy.*ConcatComments*),
*col*(OperationsHelperLSH.*ColumnUniqueId*),
*col*(OperationsHelperLSH.*ColumnFilteredWordsArray*),
*col*(OperationsHelperLSH.*ColumnFeaturesArray*))
(vectorizedProductsDF, vectorModeler)
class:com . sample . products . operations helper LSH . Scala
- 为了完成训练步骤,使用 MinHashLSHModel 来训练产品数据,生成类似产品的最终桶。
- 最后,使用 KNN 相似的哈希可以找到一个类别。
*/**
* Uses the dataset to train the model.
*
*/* **def** deduplicateDataSet(df: DataFrame): (DataFrame, MinHashLSHModel) = {
**val** minLshConfig = **new** MinHashLSH().setNumHashTables(hashesNumber)
.setInputCol(OperationsHelperLSH.*ColumnFeaturesArray*)
.setOutputCol(OperationsHelperLSH.*hashValuesColumn*)
**val** lshModel = minLshConfig.fit(df)
(lshModel.transform(df), lshModel)
}
*/**
* Applies KNN to find similar records.
****/* **def** filterResults(df: DataFrame,
vectorModeler: CountVectorizerModel,
lshModel: MinHashLSHModel,
categoryQuery: (String, String)
): DataFrame = {
**val** key = Vectors.*sparse*(*VocabularySHLSize*,
*Seq*((vectorModeler.vocabulary.indexOf(categoryQuery._1), 1.0),
(vectorModeler.vocabulary.indexOf(categoryQuery._2), 1.0)))
**lshModel**.approxNearestNeighbors(df, key, nearNeighboursNumber).toDF()}
运行一个例子:转到测试com.sample.processor.products.ProcessorProductsLshTest
,你会看到一个完整的流程在运行。
输入参数:
类别 → color = 'negro '和产品类型 = 'tdi '。
近邻
散列数 → 3 (散列越多精度越高,但计算开销越大)。
3 products with almost the same text for selected features.
结果分析:
优点:
- 准确:如果使用了一组完整的字段(表示字符串),正确的哈希值和邻居值可以检测到几乎所有的重复值。
- 更快:与其他 ML 策略如项频反等相比。
缺点:
- 需要一个资源好的集群。
- 需要一个数据清理的过程。
2 —方法 B:使用 Levenshtein +火花窗口的模糊匹配:
Levenshtein 是一种用于字符串模糊匹配的算法。基本上,这个方法测量两个字符串之间的差异。此外,spark 窗口函数以简洁的方式允许数据集分析功能,避免了多个 groupBy 和 Join 操作。因此,该方法定义了一个 2 级窗口来分组相似的数据,然后将 Levenshtein 应用于相同窗口中的值以发现重复项。该过程描述如下:
- 首先选择一组描述为非模糊的记录。该列表包含代表类别的列,并且在 PCA 过程中大多数时候是没有错误的:(“产品类型”、“城市”、“国家”、“地区”、“年份”)。
此窗口表示用于分析的常规窗口哈希。
- 其次,应用第二个窗口来发现非常相似的记录。该列表表示既不是模糊列表(PCA) 中的零件,也不是非模糊列表中的零件的记录:(“门”、“燃料”、“制造”、“里程”、“型号”、“颜色”、“价格”)
注意:“日期”字段有助于仅订购和获取最新的。
- 然后,对于每个组,将 levenshtein (仅在第二个窗口中的字符串差异)应用于来自 PCA 结果的串接的最模糊字段: (“标题块”、“内容块”)。
如您所见,使用了列的 MD5 表示,而不是每个字符串,以获得更好的性能:
keyhash: MD5 为类别列集合。下图显示了同一类别的许多产品。
hashDiff :表示非模糊集合的 MD5 hash。下图显示了属于同一类别但具有不同描述(> levenshteinThreshold)的产品,以及具有相同 hashDiff 且 levenshtein(<levenshteinThreshold)差异较小的产品。
- 最后,hashes(两者)和 rank 相同的值只改变 row_num 。过滤 row_num == 1 有可能得到去重数据集。
*/**
* Applies windows functions and Levenshtein to group similar categories.
****/* **override def** deduplicateDataSet()(df: DataFrame): DataFrame = {
df
.withColumn(OperationsHelperWindowStrategy.*ColumnRank*, *dense_rank*().over(*windowProductKeyHash*))
.withColumn(OperationsHelperWindowStrategy.*ColumnHashWithDiff*,
*concat*(*col*(OperationsHelperWindowStrategy.*ColumnCategoryFieldsHash*),
*when*(*levenshtein*(
*first*(OperationsHelperWindowStrategy.*ConcatComments*).over(*windowProductsCategoryRank*),
*col*(OperationsHelperWindowStrategy.*ConcatComments*)) >= levenshteinThreshold, *lit*("1"))
.otherwise(*lit*(""))))
.withColumn(OperationsHelperWindowStrategy.*ColumnRowNum*, *row_number*().over(*windowProductsCategoryRank*))
}
class:com . sample . products . operationshelperwindowstrategy . Scala
运行一个例子:转到测试com.sample.processor.products.ProcessorProductsWindowsTest
,你会看到一个完整的流程在运行。
输入参数: levenshteinThreshold → 6
结果:
2 groups example with almost exact values.
过滤 rn == 1 后,会对结果进行重复数据删除。这将删除样本数据集中的 > 1/3 。
结果分析:
优点:
- 更多的控制在火花分割和功能。
缺点:
- 可能会有更多的假阳性。
最终结论
重复数据删除流程始终取决于公司需求和要分析的数据量。本文描述了两种不同的策略。因此,带有窗口函数的 Levenshtein 对于小维数问题已经足够好了;否则,LSH 永远是最好的选择
递归神经主动噪声消除
原文:https://towardsdatascience.com/deep-active-noise-cancellation-e364ce4562d4?source=collection_archive---------18-----------------------
RNN 预测一个结构化的噪音,以抑制它在复杂的声学环境
Flickr, CC BY-NC 2.0
在我的上一篇文章中,我讲述了我基于神经网络的主动噪声消除系统。在这里,我概述了我用递归神经网络进行声音预测的实验,这是我为了改进我的降噪器而做的。
噪声声音预测对于主动噪声消除系统可能变得重要,因为非平稳噪声难以通过诸如 FxLMS 的经典方法来抑制。这就是我之前尝试简单的两层感知器的原因,也是我这次尝试递归网络的原因。
工作很简单:我挑战预测未来样本的任务,我用莱瓦的波尔卡作为试验品。这项任务需要大量的计算能力,所以我将这首歌缩短到前 5 秒,以便能够在没有独立 GPU 的笔记本电脑上训练 RNN。
回传脉冲
Image from Magenta blog
网络架构的核心思想源自 Magenta 项目博客中的帖子。作者在 RNN 域中引入了多速率信号处理的思想。帖子完美地描述了这个想法,它甚至有清晰的插图,所以我不打算与之竞争。虽然,我在这里给出了这个想法的简短描述。
一般来说,音乐或音频具有长期的潜在过程,因此需要用这样长的例子来学习模型。在那个实验中,我制作了具有 400 个样本输入宽度的神经网络。只有 50 毫秒,其他信息 NN 从以前的输出。
RNN 在音乐预测(或生成)问题上的主要问题是学习的复杂性。截断反向传播将输入样本和输入状态的历史展开数十或数百次。这意味着前馈路径的计算速度比反馈路径快几十倍或几百倍。
主要思想是建立几层公共递归神经网络单元,通常包括获取前一级的状态和输入值并返回下一状态和输出的单元。
履行
与之前的实验一样,我使用了 python 3.4、tensorflow 1.0 和 Linux Mint 17.2,但由于大量的计算需求,没有进行实时实验。
我制作了一个由 GRU 细胞组成的三层深度神经网络。GRU 单元也是我自己实现的,因为它更容易集成到整个系统中。每一层都接受来自以下方面的输入:
- 下面一层的输出,它是更快的一层(更大的采样率);
- 本身以前的输出;
- 上一层的输出。
第一层以 8 kHz 的采样率获取原始样本,输入的宽度为 1 个样本。内部状态是 64 个值的向量。
Outline
我也尝试过我自己的由普通感知器组成的细胞,它也工作,但 GRU 细胞的性能更好,我停止了使用它们。最顶层在那个实验中没有给出任何足够的值,但我还是把它留下了。
结果
用于实验的歌曲部分:
原始和复制样品(上图)及其光谱:
另一部分:
目标范数是均方误差,第一个历元具有 0.0176689 的误差范数,最后第 800 个历元具有 0.000453576 的范数。
这个问题没有专利,到目前为止我也没有商业计划。然而,我希望有一份全职工作致力于这个主题,这就是为什么我不把源代码放在 github.com。然而,也许有一天我会释放他们。
深度偏见?修正艾无意的偏见
原文:https://towardsdatascience.com/deep-biases-fixing-ais-unintentional-prejudices-234893a40a3b?source=collection_archive---------27-----------------------
随着人工智能(AI)在这十年里引起了很大的轰动,这个生态系统中的算法模型无疑已经进入了我们日常生活的方方面面。无论它们是用来解决紧迫的社会问题,还是为你的通勤推荐新的歌曲播放列表,这些模型都很常见。随着研究和技术进步为更先进的系统让路成为常态,必须认真考虑偏见和成见的意外后果。如果系统建立在我们对种族、性别和文化多样性的偏见之上,人类真的能够创造出取代我们自己认知能力的人工超级智能吗?
过去的表现并不代表未来的表现
我不是第一个写这个的人,也不会是最后一个。我真的相信人工智能给社会带来的好处会超过它的成本。然而,过于信任当前的机器学习系统所带来的问题越来越明显。简单地说,监督机器学习算法采用现有的数据集,并学习从输入到输出的映射,以便做出未来的预测。如果这些现有的数据集有偏差,那么输出也会有偏差。去年这个时候,路透社宣布亚马逊放弃了一个潜在的人工智能招聘工具,许多人希望它成为招聘的“圣杯”。
“……亚马逊的计算机模型被训练成通过观察 10 年间提交给公司的简历模式来审查申请人。大多数来自男性,反映了男性在整个科技行业的主导地位。
同样,在过去五年里,也出现了许多错误的行业算法。例如,深色皮肤的人被错误地归类为 gorrilas,或者相机将亚洲人的特征误读为眨眼。其他形式的计算机视觉算法可能会给个人带来更严重的后果,特别是如果用于预测性分析、数据驱动的政策执行措施或就业推荐引擎。
金融界有一个非常典型的免责声明,警告投资者过去的表现并不代表未来的表现。这非常贴切。机器学习系统的好坏取决于所使用的训练数据。当我们进入 2020 年时,所有的“…主义”和“…恐惧症”都真正地爆发了。已知超过 180 种人类偏见,人类的这些负面倾向可能被认为是不可治愈的,但在人工智能模型中修复偏见可能要简单得多。人工智能的竞赛正在迫使人们就道德使用展开公开讨论,因为我们的先入之见可能会因数据驱动的模型对商业决策产生不利影响而加剧。
伦理框架?好吧,这是个开始。
从根本上说,这是一个数据问题。如果算法继续从有缺陷的数据中学习,输出将继续没有代表性。上面写的案例很有可能已经被纠正,但是规范和共享未来的训练数据库必须取得进展。自 2016 年以来,AI 上的伙伴关系无疑是朝着正确方向迈出的一步;世界科技巨头走向自我监管。PAI 寻求的一个解决方案是减少科技公司中的代表性不足,允许从数据收集到产品开发的更加多样化。
“这种持续的危机在设计下一代产品的技术团队中尤为明显,这些产品会影响来自各种背景的人,通常与开发它们的团队不同。”
个人与科技公司的关系在不断变化。尽管最近进行了监管,但持续的数据泄露和数据共享政策带来了一个话题:信任。数据是新的石油 ”用那句话来说,每个个体生产的商品应该带来新的公民权利,而不仅仅是消费者权利。
围绕减少无意识偏见建立法律伦理框架或文化,无疑是提高企业信任度的一个开端。围绕数据使用建立正确的公司文化框架将使企业脱颖而出,并创造出更具包容性的思维定势。例如,谷歌人工智能概述了他们的原则完全有益于社会,为安全和负责任而建造,并对此保持透明。其他公司如 T2 的 IBM T3 和 T4 的微软 T5 也这么做了。Alan Turing Institute 还提供了对待个人数据的全面价值观原则。
(Source: Leslie, D. 2019 - Alan Turing Institute)
过程也应该被监控。敏捷实践正在成为规范,随着企业经历产品开发生命周期,质疑新产品或新功能的影响也应该成为规范。
数据集会变得无偏吗?
“因为人工智能可以帮助揭示杂乱数据集内的真相,算法有可能帮助我们更好地理解我们尚未隔离的偏见。”
除了监管和监控之外,实际实现允许审查数据源的过程无疑是困难的。IBM 的 K. Varney 提出了一个有趣的解决方案,通过三个目标和约束条件:群体歧视控制、个体扭曲控制和效用保护,数据“与具有一个或多个属性(如种族或性别)的人有关”。学术研究也看这个问题。 Kleigr、Bahnik 和 Furnkranz (2019)也概述了一项关于如何减少算法系统中的偏差的研究。
“涵盖了 20 种认知偏差,以及机器学习算法和软件的设计者可能采用的去偏差技术。”
有许多科学方法,如确保选择的模型是合适的,加强监测以减少样本、排除、偏见和观察偏差。我们会有一个既有代表性又实用的人工智能设计,同时不降低程序的公平性,最终不需要任何人类治理吗?就我而言,我不能确定——但我们已经有了一个开始。
深度汽车 Pytorch 迁移学习
原文:https://towardsdatascience.com/deep-cars-transfer-learning-with-pytorch-3e7541212e85?source=collection_archive---------10-----------------------
完成 Hackathon Auto-matic 的逐步指南
Source: Honda Small Sports EV Concept Electric Car
你如何教计算机识别不同的汽车品牌?你想给任何一辆车拍照,然后你的手机自动告诉你这辆车的品牌吗?
如果这让你兴奋,那么你来对地方了。我们要写一个可以识别 196 种不同类型汽车的模型。
侧注
自动黑客马拉松是我和四位女士(来自世界各地)发起的组织周末黑客马拉松的第二个项目
作为 facebook 赞助的 Udacity 上的安全和私人 AI 奖学金挑战赛的 5000 名学生的一部分,我们决定组织周末黑客马拉松;用 Pytorch 解决一个问题的 48 小时,玩得开心,互相竞争。令我们惊讶的是,在我们的第一次黑客马拉松中,有 41 个团队参加了🙌。 黑客马拉松开花 是给第一届黑客马拉松起的名字。Hackathon Auto-matic和 Hackathon Blossom 一样也是基于图像分类。
我可以继续讲述这个机会是多么不可思议,以及我们在那里拥有的令人惊叹的社区。我最好就此打住,回到我们今天的目标:)
入门指南
我们将使用神经网络来实现我们的目标。更准确地说,我们将使用一个非常深的神经网络,因此命名为深车。****
本教程分为两部分:
第 1 部分:构建汽车分类器
第 2 部分:部署分类器(进行中…)
在本文中,我们将浏览第 1 部分
第 1 部分:构建汽车分类器
先决条件:
为了跟进,需要以下方面的一些知识:
- Python——uda city 提供了一个关于Python 简介的很棒的课程
- 卷积神经网络 — Adit 在 CNN 上提供了一个伟大的解释
- Pytorch 的基础知识
我们将使用一种叫做迁移学习的方法来训练我们的分类器。
什么是迁移学习?
迁移学习是深度学习中的一种方法,其中为解决一项任务而开发的模型被重新用作另一项任务的起点。比方说,你想建立一个网络来识别鸟类,而不是从头开始编写一个模型,这可能是一个非常复杂的任务,至少可以使用一个已经存在的模型来完成相同或类似的任务(在我们识别鸟类的情况下,我们可以使用一个识别其他动物的网络)。运用迁移学习的优势;学习过程更快、更准确,需要的训练数据更少。已经存在的模型被称为预训练模型。****
迁移学习中使用的大多数预训练模型都基于大型卷积神经网络。一些人预训练的模型有 VGGNet,ResNet,DenseNet,Google 的 Inception 等。这些网络中的大多数都是在 ImageNet 上训练出来的。ImageNet 是一个大规模数据集,包含 1000 个类别中超过 100 万个带标签的图像。
在 Pytorch 中,很容易加载基于 ImageNet 的预训练网络,这些网络可从 torchvision 获得。我们将使用这些预先训练好的模型来训练我们的网络。
我们的模型将使用以下步骤在 Google Colab 上构建(笔记本可在此处找到):
- 加载数据并执行转换
- 建立模型
- 训练模型
- 在看不见的数据上测试模型
导入库
在这里,我们只是加载库,并确保 GPU 是打开的。由于我们将使用预先训练的模型,这些模型是非常深的网络,所以 CPU 上的训练不是一个真正的选项,因为这将需要很长时间。GPU 并行执行线性代数计算,因此训练速度提高了 100 倍。
如果你的 GPU 是关闭的,并且你正在使用 Colab,在你的笔记本上进入编辑= >笔记本设置。确保运行时设置为 Python 3 并且在硬件加速器下选择 GPU。**
你会注意到我们正在检查 cuda 是否可用。大多数深度学习框架使用 CUDA 来计算 GPU 上的向前和向后传递。
1。执行转换并加载数据集
1.1 下载数据集
现在我们的库已经导入,我们从 Kaggle 加载数据集。该数据集包含 196 个汽车品牌。
在这里,我们下载数据集并使用 Pytorch 数据加载器加载它们。我们将数据直接下载到谷歌硬盘,因此我们必须获得授权访问。
*#Mounting google drive inorder to access data
from google.colab import drive
drive.mount('/content/drive')*
运行后:点击出现的链接,登录到你的帐户,点击允许,然后复制生成的文本并粘贴到你的笔记本上。查看这篇文章,这篇文章向您展示了如何轻松获得 API 密钥和下载数据集。我们加上这一行!解压缩*。zip 解压下载的文件。您的代码应该是这样的:**
注意我们有两个目录;培训和测试目录。稍后,我们将使用我们的模型来预测测试集的值。我们必须将训练数据分为训练数据和验证数据。在拆分之前,让我们了解什么是转换,并写出我们的转换。
1.2 数据转换
既然数据集已经下载,我们就对数据执行转换。转换是将数据从一种形式转换成另一种形式。我们将对我们的图像应用两个主要的变换:
- 数据增强
这是一种在不实际收集新数据的情况下增加用于训练的数据集的多样性和大小的策略。诸如调整大小、裁剪、水平翻转、填充甚至 GANs 等技术被应用于数据集上的图像,并且“新的”图像被创建。它有两个主要优点:从有限的数据中生成更多的数据,并防止过拟合。**
但是,不要期望在数据集中看到这些生成的图像。它们仅在批量生成期间创建,因此即使您没有看到数据集中的图像数量增加,训练期间的实际图像也会增加。
在我们的模型中,我们应用了 3 种增强策略;调整大小(RandomResize)、裁剪(RandomCrop)和水平翻转(HorizontalFlip)。**
请注意,对于测试数据,我们不执行 RandomResizedCrop、RandomRotation 和 RandomHorizontalFlip 转换。相反,我们只是将测试图像的大小调整为 256×256,并裁剪掉中心 224×224,以便能够将它们用于预训练的模型。
- 数据标准化
执行增强后,图像被转换为张量,并通过使用 ImageNet 中所有图像的平均值和标准偏差进行归一化。通常,对于非常大的数据集,使用数据集本身的平均值和标准差。鉴于我们的数据集不是太大,我们使用 ImageNet 的数据集:【0.485,0.456,0.406】,【0.229,0.224,0.225】**
执行这些转换后,我们使用 Pytorch 中的 ImageFolder 加载数据。但是首先我们需要验证数据,所以我们拆分了训练集。我们的数据中只有 1%被选择用于验证,其余的用于训练。
- 可视化标签
我们可视化我们的标签来查看文件的结构。
Output from printing names.csv
我们看到 0 上面出现了一个车名。因此,在读取 csv 文件时,我们必须添加一个头名,这样才能得到正确的输出。需要注意的是,我们的标签从 0 到 195 开始(非常重要)
3 可视化图像
我们现在可以加载和可视化我们的数据。创建了一个方法 imshow() (来自挑战课程)来显示我们的图像。
训练集中的图像如下所示。我们注意到其中一些已经翻转或旋转。
Images from train set after transformations
2。构建和训练模型
如前所述,我们将使用基于 ImageNet 的预训练模型。
我们将用于构建和培训的步骤是:
- 加载预训练模型
- 冻结卷积层中的参数
- 创建自定义分类器并定义超参数
- 训练自定义分类器
2.2 加载预训练模型
我们将尝试不同的架构; densenet161 、 inceptionv3 、 resnet121 和 vggnet 架构。在这里,我们加载不同的模型,并在模型的全连接层中指定输入要素的数量,因为我们在构建自定义分类器时将需要这一点。
2.3 冻结参数并创建自定义分类器
因为我们的预训练模型中的大多数参数已经为我们训练好了,所以我们不通过它们进行反向投影。这将允许我们保留早期卷积层的预训练权重(其目的是用于特征提取)。我们通过将 requires_grad 字段重置为 false 来实现这一点。
在此之后,我们替换完全连接的网络,该网络将具有与我们的预训练神经元相同的输入、自定义隐藏层和我们的输出。我们的build _ classifier方法很灵活,当我们不希望网络中有隐藏层,或者我们希望有多个隐藏层时,这种方法很有效。激活功能(在本例中为 relu )和漏失也被定义。**
现在我们指定我们的超参数和隐藏层。
我们指定了标准,不同的优化器,如 Adam,Adadelta,SGD,其中包含了学习率和动量。我们为不同的预训练网络使用这些超参数,并选择给我们最好结果的那些。我们为 resnet 和 vggnet 使用两种不同的调度程序。他们是这样做的:
torch.optim.lr_scheduler
提供了几种根据时期数调整学习率的方法。[torch.optim.lr_scheduler.ReduceLROnPlateau](https://pytorch.org/docs/stable/optim.html#torch.optim.lr_scheduler.ReduceLROnPlateau)
允许基于某些验证测量的动态学习率降低。更多阅读此处
2.4 培训和验证
为了用 PyTorch 训练我们的模型,我们通常在迭代每个时期时执行以下步骤:
- 使用 forward(images) 向前通过网络
- 使用标准功能中的网络输出来计算损耗**
- 使用 loss.backward() 对网络进行反向遍历,以计算梯度
- 与优化器一起更新权重 optimizer.step()
optimizer.zero_grad() 用于清除累积的梯度
称为提前停止的技术用于防止过度拟合。当验证数据集的性能开始下降时,它会导致训练停止。随着训练的进行,当我们获得最佳准确度时,我们也保存模型(检查点)。这样,如果断电或训练由于某种原因中断,可以恢复检查点并继续训练。**
该模型改编自 PyTorch 网站
现在我们训练我们的模型。
*Epoch 1/60
----------
train Loss: 0.5672 Acc: 0.8441
valid Loss: 0.6750 Acc: 0.8329
Epoch 2/60
----------
train Loss: 0.6184 Acc: 0.8357
valid Loss: 0.5980 Acc: 0.8415
Epoch 3/60
----------
train Loss: 0.5695 Acc: 0.8487
valid Loss: 0.5503 Acc: 0.8575
...*
这看起来很有希望。这个模型似乎在不断学习。此外,我们的模型似乎没有过度拟合(至少是过度拟合),因为训练和验证指标没有偏离太多。该模型的特定时期结果是通过 ResNet 架构获得的,这是第二次培训。精度开始很低,但随着时间的推移而提高。对我们得到的精度影响很大的超参数是优化器、调度器、历元数和架构。调整这些值要么给出非常低的精度(低至 0,甚至为负),要么以 0.013 这样的精度开始,该精度随着历元数的增加而增加(这里耐心是关键)。**
4。在看不见的数据上测试模型
一旦我们对我们的验证准确性感到满意,我们就加载我们保存的模型,并对测试数据进行预测。课堂竞赛要求我们以 csv 格式提交结果,格式为 Id,预测。 Id 这是我们图像文件的名称,不带扩展名。jpg 和预测的是我们的模型为每张图片预测的类(应该在 1 到 196 之间)。请记住,我们的标签从 0 到 195 开始,所以我们必须在预测的类中加 1 才能得到正确的值。**
我们加载我们保存的模型
*model.load_state_dict(torch.load('/content/drive/MyDrive/ResnetCars.pt'))
model.to(device)*
现在,我们加载测试数据集,并通过数据集传递我们的模型。因为我们只做预测,所以不需要计算梯度。我们通过 torch.no_grad() 并设置为 evaluation model.eval()来实现这一点。我们计算预测。
得到结果后,我们打印数据框,并将结果写入一个. csv 文件,然后在竞赛网站上提交。
CSV FIle to be submitted
看看 Khush Patel 的令人惊叹的内核,它以 99.18%的准确率赢得了黑客马拉松的冠军。他使用了 inceptionV3 架构,带有 CrossEntropyLoss 和一个 SGD 优化器。你的模型能打败这个吗?😃
你可以在 Kaggle 上参加的班级竞赛。
我们结束了。
恭喜👏这是一篇很长的文章,但你坚持到了最后。现在你可以用迁移学习建立你自己的模型。代码是可重用的,您也可以将它用于其他数据集。
感谢阅读!你可以随时在 Twitter 和 LinkedIn 上联系。
参考文献
[1] F. Zaidi,py torch 中的迁移学习,第 1 部分:如何使用数据加载器并构建完全连接的类 (2019)
[2] G. Adjei,用 PyTorch ,(2019),心跳
金融市场细分的深度聚类
原文:https://towardsdatascience.com/deep-clustering-for-financial-market-segmentation-2a41573618cf?source=collection_archive---------5-----------------------
一种无监督的信用卡客户聚类深度学习方法
无监督学习、监督学习和强化学习是机器学习方法的三大类。无监督学习有许多应用,如聚类、降维等。机器学习算法 K-means 和主成分分析 (PCA)分别广泛用于聚类和降维。与 PCA 类似,T-分布式随机邻居嵌入 (t-SNE)是另一种用于维数约简的无监督机器学习算法。t-SNE 通常用于在二维或三维空间中嵌入高维数据以进行数据可视化。
随着无监督深度学习的发展,自动编码器神经网络现在经常用于高维度(例如,具有数千或更多特征的数据集)的约简。Autoencoder 也可以与监督学习(如随机森林)相结合,形成半监督学习方法(见深度病人举例)。
最近发表了一个深度嵌入聚类 (DEC)方法【1】。它将 autoencoder 与 K-means 和其他机器学习技术相结合,用于聚类而不是降维。DEC 的原实现基于 Caffe 。在【2】中可以找到 MNIST 数据集的 Keras 中 DEC 的实现。
在本文中,与[2]类似,我在 Keras 中实现了 DEC 算法,并使用公共数据集 Kaggle 信用卡数据集进行聚类 [3]来展示如何使用新实现的 DEC 模型对信用卡数据集进行聚类以进行客户细分。本文其余部分安排如下:
- 数据准备
- 在 Keras 中实现 DEC 方法
- 摘要
1.数据准备
本节描述聚类所需的常见数据预处理步骤。
1.1 加载数据
将 Kaggle 信用卡数据集[3]下载到本地机器后,可以将其加载到 Pandas 数据框架中,如下所示:
import Pandas as pd
data = pd.read_csv('./data/CC_GENRAL.csv')
data.head()
1.2 选择功能
从上面的数据帧可以看出,CUST ID 字段对于每个客户数据记录都是唯一的。具有唯一值的该字段对聚类没有用,因此可以删除:
data_x = data.drop(['CUST_ID'], axis=1)
1.3 重缩放特征
从数据帧中还可以看出,对于不同的字段/特征,值的范围是非常不同的。众所周知,K-means 对特征值的尺度很敏感,因为它使用欧氏距离作为相似性度量。为了避免这个问题,所有要素的值都被重新调整到[0,1]的范围内:
from sklearn.preprocessing import MinMaxScaler
numeric_columns = data_x.columns.values.tolist()
scaler = MinMaxScaler()
data_x[numeric_columns] = scaler.fit_transform(data_x[numeric_columns])
data_x.head()
1.4 处理缺失数据
以下代码用于检查数据集中是否存在任何缺失的数据:
data_x.isnull().sum()
上表显示有一个缺失的信用限额记录和 313 个缺失的最低付款额。在这种情况下,用零填充缺失的数据是有意义的:
data_x.fillna(0, inplace=True)
2.在 Keras 中实现 DEC 方法
与[2]类似,[1]中的 DEC 算法在本文中用 Keras 实现如下:
- 步骤 1:估计聚类数
- 步骤 2:创建和训练 K 均值模型
- 步骤 3:创建和训练自动编码器
- 步骤 4:实施 DEC 软标签
- 步骤 5:创建一个新的 DEC 模型
- 步骤 6:训练新的 DEC 模型
- 步骤 7:使用训练好的 DEC 模型预测聚类类
- 第八步:共同细化 DEC 模型
- 步骤 9:使用改进的 DEC 模型预测聚类类
- 步骤 10:与 K 均值比较
2.1 估计聚类数
如前所述,DEC 方法将 Autoencoder 与 K-means 和其他机器学习技术相结合。为了训练 K-均值模型,需要估计的聚类数。本文通过研究不同 K-means 模型执行的剪影值来估计聚类的数量:
for num_clusters in range(2,10):
clusterer = KMeans(n_clusters=num_clusters, n_jobs=4)
preds = clusterer.fit_predict(x)
# centers = clusterer.cluster_centers_
score = silhouette_score (x, preds, metric='euclidean')
print ("For n_clusters = {}, Kmeans silhouette score is {})".format(num_clusters, score))
轮廓值衡量数据记录与其自己的分类(内聚力)相比与其他分类的相似程度。轮廓值的范围从 1 到+1,其中高值表示数据记录与其自己的分类匹配良好,而与其相邻的分类匹配较差。
上面的轮廓值表明聚类数的前两个选择是 2 和 3。本文选择了 3 个簇的数目。
2.2 创建和训练 K 均值模型
一旦确定了聚类的数量,就可以创建 K 均值模型:
n_clusters = 3
kmeans = KMeans(n_clusters=n_clusters, n_jobs=4)
y_pred_kmeans = kmeans.fit_predict(x)
2.3 创建和培训自动编码器
除了 K-means,DEC 算法中还需要一个自动编码器[1]。以下函数用于创建自动编码器:
def autoencoder(dims, act='relu', init='glorot_uniform'):
n_stacks = len(dims) - 1
input_data = Input(shape=(dims[0],), name='input')
x = input_data
# internal layers of encoder
for i in range(n_stacks-1):
x = Dense(dims[i + 1], activation=act, kernel_initializer=init, name='encoder_%d' % i)(x) # latent hidden layer
encoded = Dense(dims[-1], kernel_initializer=init, name='encoder_%d' % (n_stacks - 1))(x) x = encoded
# internal layers of decoder
for i in range(n_stacks-1, 0, -1):
x = Dense(dims[i], activation=act, kernel_initializer=init, name='decoder_%d' % i)(x) # decoder output
x = Dense(dims[0], kernel_initializer=init, name='decoder_0')(x)
decoded = x
autoencoder_model = Model(inputs=input_data, outputs=decoded, name='autoencoder')
encoder_model = Model(inputs=input_data, outputs=encoded, name='encoder')
return autoencoder_model, encoder_model
自动编码器模型创建如下:
n_epochs = 100
batch_size = 128
dims = [x.shape[-1], 500, 500, 2000, 10]
init = VarianceScaling(scale=1\. / 3., mode='fan_in',
distribution='uniform')
pretrain_optimizer = SGD(lr=1, momentum=0.9)
pretrain_epochs = n_epochs
batch_size = batch_size
save_dir = './results'autoencoder, encoder = autoencoder(dims, init=init)
如[1]中所述,层的大小[500,500,2000,10]被选择作为用于任何数据集的自动编码器神经网络的一般配置。
生成的编码器模型的图表可以创建如下:
from keras.utils import plot_model
plot_model(encoder, to_file='encoder.png', show_shapes=True)
from IPython.display import Image
Image(filename='encoder.png')
自动编码器的训练如下:
autoencoder.compile(optimizer=pretrain_optimizer, loss='mse')
autoencoder.fit(x, x, batch_size=batch_size, epochs=pretrain_epochs)
autoencoder.save_weights(save_dir + '/ae_weights.h5')
被训练的自动编码器的权重被保存以备后用:
autoencoder.save_weights(save_dir + '/ae_weights.h5')
autoencoder.load_weights(save_dir + '/ae_weights.h5')
2.4 实施 DEC 软标签
DEC 方法[1]中的一个关键组成部分是软标记,也就是说,为每个数据样本分配一个估计类,以使其可以迭代地改进。为此,与[2]类似,定义了一个新的 ClusteringLayer 类:
class ClusteringLayer(Layer): def __init__(self, n_clusters, weights=None, alpha=1.0, **kwargs):
if 'input_shape' not in kwargs and 'input_dim' in kwargs:
kwargs['input_shape'] = (kwargs.pop('input_dim'),)
super(ClusteringLayer, self).__init__(**kwargs)
self.n_clusters = n_clusters
self.alpha = alpha
self.initial_weights = weights
self.input_spec = InputSpec(ndim=2) def build(self, input_shape):
assert len(input_shape) == 2
input_dim = input_shape[1]
self.input_spec = InputSpec(dtype=K.floatx(), shape=(None, input_dim))
self.clusters = self.add_weight(name='clusters', shape=(self.n_clusters, input_dim), initializer='glorot_uniform')
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
self.built = True def call(self, inputs, **kwargs):
q = 1.0 / (1.0 + (K.sum(K.square(K.expand_dims(inputs, axis=1) - self.clusters), axis=2) / self.alpha))
q **= (self.alpha + 1.0) / 2.0
q = K.transpose(K.transpose(q) / K.sum(q, axis=1))
return q def compute_output_shape(self, input_shape):
assert input_shape and len(input_shape) == 2
return input_shape[0], self.n_clusters def get_config(self):
config = {'n_clusters': self.n_clusters}
base_config = super(ClusteringLayer, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
2.5 创建新的 DEC 模型
一旦定义了软标注图层,就可以使用它来形成 DEC 模型,如下所示:
clustering_layer = ClusteringLayer(n_clusters, name='clustering')(encoder.output)
model = Model(inputs=encoder.input, outputs=clustering_layer)
可以创建新 DEC 模型的图表,如下所示:
from keras.utils import plot_model
plot_model(model, to_file='model.png', show_shapes=True)
from IPython.display import Image
Image(filename='model.png')
新的 DEC 模型可以编译如下:
model.compile(optimizer=SGD(0.01, 0.9), loss='kld')
model.get_layer(name='clustering').set_weights([kmeans.cluster_centers_])
2.6 培训新的 DEC 模型
迭代训练新的 DEC 模型:
# computing an auxiliary target distribution
def target_distribution(q):
weight = q ** 2 / q.sum(0)
return (weight.T / weight.sum(1)).Tloss = 0
index = 0
maxiter = 1000
update_interval = 100
tol = 0.001 # tolerance threshold to stop trainingindex_array = np.arange(x.shape[0])
for ite in range(int(maxiter)):
if ite % update_interval == 0:
q = model.predict(x, verbose=0)
p = target_distribution(q) idx = index_array[index * batch_size: min((index+1) * batch_size, x.shape[0])]
loss = model.train_on_batch(x=x[idx], y=p[idx])
index = index + 1 if (index + 1) * batch_size <= x.shape[0] else 0
如[1]中所述,上述训练过程通过在辅助目标分布函数 target_distribution )的帮助下从高置信度分配中学习来迭代地改进聚类。具体而言,通过将软分配与目标分布相匹配来训练 DEC 模型。为此,在 DEC 模型中,目标/损失函数被定义为软分配和辅助分布之间的 Kullback-Leibler (KL)发散损失。
已训练模型的模型权重被保存以备后用:
model.save_weights(save_dir + '/DEC_model_final.h5')
model.load_weights(save_dir + '/DEC_model_final.h5')
2.7 使用训练的 DEC 模型来预测聚类类别
一旦 DEC 模型被定型,它就可以用于预测聚类类,如下所示:
q = model.predict(x, verbose=0)
p = target_distribution(q)
y_pred = q.argmax(1)
如下获得 0.291 的轮廓分数:
from sklearn.metrics import silhouette_score
score = silhouette_score(x, y_pred, metric='euclidean')
以下代码可用于使用 t-SNE 将数据集嵌入二维空间,然后使用预测聚类标签的颜色编码来可视化预测聚类结果:
import numpy as np
from sklearn.manifold import TSNEx_embedded = TSNE(n_components=2).fit_transform(x)vis_x = x_embedded[:, 0]
vis_y = x_embedded[:, 1]
plt.scatter(vis_x, vis_y, c=y_pred, cmap=plt.cm.get_cmap("jet", 256))
plt.colorbar(ticks=range(256))
plt.clim(-0.5, 9.5)
plt.show()
图 1: 剪影得分为 0.291 的新 DEC 模型的聚类。
2.8 联合提炼 DEC 模型
DEC 方法[1]背后的主要思想是使用深度神经网络同时学习特征表示和聚类分配。为此,以下代码使用预训练的 autoencoder 和 K-means 模型来定义一个新模型,该模型将预处理的信用卡数据集作为输入,并输出预测的聚类分析类和解码的输入数据记录。
autoencoder, encoder = autoencoder(dims, init=init)
autoencoder.load_weights(save_dir + '/ae_weights.h5')
clustering_layer = ClusteringLayer(n_clusters, name='clustering')(encoder.output)
model = Model(inputs=encoder.input, outputs=[clustering_layer, autoencoder.output])
可以按如下方式创建连接模型的图表:
from keras.utils import plot_model
plot_model(model, to_file='model.png', show_shapes=True)
from IPython.display import Image
Image(filename='model.png')
DEC 模型的优化执行如下:
kmeans = KMeans(n_clusters=n_clusters, n_init=20)
y_pred = kmeans.fit_predict(encoder.predict(x))
model.get_layer(name='clustering').set_weights([kmeans.cluster_centers_])
y_pred_last = np.copy(y_pred)model.compile(loss=['kld', 'mse'], loss_weights=[0.1, 1], optimizer=pretrain_optimizer)for ite in range(int(maxiter)):
if ite % update_interval == 0:
q, _ = model.predict(x, verbose=0)
p = target_distribution(q)
y_pred = q.argmax(1) # check stop criterion
delta_label = np.sum(y_pred != y_pred_last).astype(np.float32) / y_pred.shape[0]
y_pred_last = np.copy(y_pred)
if ite > 0 and delta_label < tol:
print('delta_label ', delta_label, '< tol ', tol)
print('Reached tolerance threshold. Stopping training.')
break
idx = index_array[index * batch_size: min((index+1) * batch_size, x.shape[0])]
loss = model.train_on_batch(x=x[idx], y=[p[idx], x[idx]])
index = index + 1 if (index + 1) * batch_size <= x.shape[0] else 0
保存联合细化的模型权重:
model.save_weights(save_dir + '/b_DEC_model_final.h5')
model.load_weights(save_dir + '/b_DEC_model_final.h5')
2.9 使用改进的 DEC 模型预测聚类类别
以下代码将使用改进的 DEC 模型来预测聚类分析类:
q, _ = model.predict(x, verbose=0)
p = target_distribution(q)
y_pred = q.argmax(1)
下面的代码可用于重用 t-SNE 嵌入的二维空间( vis_x , vis_y ),并使用新的预测聚类标签的颜色编码来可视化新的预测聚类结果:
plt.scatter(vis_x, vis_y, c=y_pred, cmap=plt.cm.get_cmap("jet", 256))
plt.colorbar(ticks=range(256))
plt.clim(-0.5, 9.5)
plt.show()
图 2: 轮廓得分为 0.318 的细化 DEC 模型的聚类。
2.10 与 K 均值比较
图 3 显示了 K-means 的聚类结果。通过比较图 3 和图 2,我们可以看到 K-means 取得了相对较高的轮廓得分。然而,可以看出,改进的 DEC 模型预测了具有更清晰可分边界的聚类。
图 3:轮廓得分为 0.372 的 K 均值模型的聚类。
摘要
在本文中,与[2]类似,我基于[1]中的原始 DEC 算法在 Keras 中实现了一个新的 DEC 模型,然后将新模型应用于公共数据集 Kaggle 信用卡数据集进行聚类【3】。
模型评估结果表明,与 K-means 方法相比,新的改进的 DEC 模型更清楚地预测了信用卡数据集的可分离聚类。这种新的 DEC 模型具有用于信用卡客户细分、其他金融市场细分等的潜力。
Github [4]中提供了一个 Jupyter 笔记本,其中包含了本文中使用的所有源代码。
参考
[1] J .谢,r .吉希克,a .,聚类分析的无监督深度嵌入,2016 年 5 月 24 日
[2]程维,如何用 Keras 做无监督聚类
[3] Kaggle 用于聚类的信用卡数据集
[4] Y. Zhang, Github 中的 Jupyter 笔记本
披露声明:2019 首创一。观点是作者个人的观点。除非本帖中另有说明,否则 Capital One 不隶属于所提及的任何公司,也不被这些公司认可。使用或展示的所有商标和其他知识产权是其各自所有者的财产。
深度压缩
原文:https://towardsdatascience.com/deep-compression-7b771b3aa773?source=collection_archive---------17-----------------------
在目前的形式下,深度神经网络需要巨大的内存来支持其大规模的过度参数化。AlexNet 和 VGG-16 等经典神经网络分别需要大约 240 和 552 MB。已经进行了许多努力来减小神经网络的文件大小,通常依赖于诸如权重修剪或量化或者权重矩阵的 SVD 分解之类的技术。这篇名为 Deep Compression 的论文将剪枝、量化和霍夫曼编码结合到一个三级流水线中,将 AlexNet 的大小减少了 35 倍,将 VGG-16 的大小减少了 49 倍。这导致 AlexNet 从 240 兆字节减少到 6.9 兆字节,VGG-16 从 552 兆字节减少到 11.3 兆字节。
管道由三个阶段组成:
Pruning, Quantization, and Huffman Encoding
修剪
修剪描述了在深度神经网络中屏蔽掉某些权重的过程。这需要在神经网络层上实现一个掩码,以便它们通过 y = Wx + b 运算进行不同的迭代。权重修剪不同于简单地将某些权重设置为 0。在论文中实现的修剪操作屏蔽了低于某个阈值的权重。例如,如果权重位于区间[-0.5,0.5]之间,它将被屏蔽掉。
修剪后,权重以压缩的稀疏行格式表示。这样做是为了不浪费稀疏权重矩阵的空间。下图描述了这种 CSR 格式:
量化
量化是一种通过权重共享来减少在神经网络中存储每个权重所需的位数的技术。深度神经网络中的权重通常由 32 位浮点表示,采取例如“2.70381”的形式。在量化中,使用 k-Means 算法来搜索描述网络中权重的聚类。如果权重用 3 比特表示,这将导致 2 = 8 个质心用于聚类权重。然后,每个权重被映射到其各自的质心。比如‘2.70381’→‘2’。因此,这 8 个质心形成了用于将原始权重映射到相应的 3 比特权重的“码本”。然后,在训练期间对该码本进行微调。
码本通过与经典 backprop / SGD 类似的机制进行微调。计算每个权重的偏导数,并对每个离散的 3 位权重进行合计。例如,一系列“2”3 位权重可以具有“0.2”、“0.1”、“0.2”和“0.3”的相应偏导数更新。这些导数被聚合,并且“2”被优化为“2.2”。
这个过程描述如下:
霍夫曼编码
霍夫曼编码是一种流行的压缩技术,它利用了值的偏斜/有偏分布。例如,如果 20 个权重映射到“2”,10 个权重映射到“3”,3 个权重映射到“8”,则将 2 编码为“00”,将 3 编码为“10”,将 8 编码为类似“1110”的内容是有意义的。在这种情况下,使用霍夫曼编码来减少表示量化码本中的权重所需的比特数量。
放在一起
我发现剪枝和权重量化如何在不破坏网络准确性的情况下协同工作非常有趣。我希望通过使用分布式同步 SGD 等机制,使用这种技术来改善元学习算法的周转时间。我希望其他人发现这很有用,并可以找到移动和嵌入式系统的深度学习应用。请查看下面的视频以了解更多关于深度压缩的信息,感谢阅读!
深度压缩:推理和效率的优化技术
原文:https://towardsdatascience.com/deep-compression-optimization-techniques-for-inference-efficiency-615252c18f18?source=collection_archive---------24-----------------------
随着技术迎合摩尔定律的物理极限,计算越来越受到散热的限制,而不是在给定的硅面积上可以封装的晶体管数量。现代芯片已经经常闲置其区域的整个部分,形成所谓的“暗硅”,指的是在危险地超过热设计限制之前,限制芯片可以长时间通电的比例的设计。因此,对于任何机器学习加速器,包括经过试验的和真正的通用图形处理单元(GPU ),一个重要的度量是设备在大约 250 W 功耗下的训练或推理性能。
正是这种对效率的驱动力促使谷歌开发了他们自己的张量处理单元(TPU) ,用于提高模型推理的效率,以及在其数据中心的 v2 单元中的培训。过去几年已经出现了过多的深度学习硬件创业公司,它们寻求生产高能效的深度学习芯片,这些芯片专门从事当前流行的深度学习架构所需的有限混合操作。如果深度学习主要由矩阵乘法和卷积组成,为什么不建造一个芯片来做这些,用通用计算能力换取专用效率?但是这种权衡比看起来要复杂得多。
深度学习的能源成本
包括大规模机器学习在内的现代高性能计算的主要动力来源不是计算,而是通信。对 32 位数据执行乘法运算通常需要不到 4 pJ 的,而从 DRAM 中读取相同数量的数据需要大约 640 pJ,这使得片外存储器读取比常用的数学运算符多消耗大约 160 倍的能量。当我们考虑发送超过几厘米的数据时,这种不平衡的功耗变得更糟(导致数据中心用光纤取代中等长度的数据通信线)。突然之间,将你的深度学习推理需求外包到谷歌云平台的 TPUs 上运行,似乎并不像它本来可以做到的那样环保。
几乎不用说,鉴于人工智能和机器学习的创新步伐,在投资 2 年开发周期开发仅限于卷积和矩阵乘法高性能的专用硬件后,无法保证主导架构将保持不变足够长的时间,以充分获得回报。就在过去的几个月里,我们已经看到了有前途的神经微分方程网络的演示,它的操作与我们备受尊敬的 conv 网络截然不同,这十年来对深度学习的兴趣增加只能意味着更多的创新和新型模型。任何专门为加速当前一代顶级机型而开发的专用硬件都有迅速过时的风险。
深度压缩:受生物启发的效率提升
深度学习卷积神经网络,顾名思义,以其深度和宽度而闻名,其中一些例外的例子是大约有 1000 层的 resnets。在训练结束时,所有这些参数中的所有精度都可能是过度的,只不过是浪费了对电力有着贪婪胃口的计算资源。这是 Nvidia 可变精度张量内核背后的一个主要原因,它支持最新一代图灵架构 GPU中低至 8 位整数的计算。
因此,用更小的模型(如恰当命名的 SqueezeNet )实现最先进的性能是一个活跃的研究领域。经过充分训练的较小模型非常适合在自动驾驶汽车、物联网设备和智能手机中进行移动部署,但当参数搜索量很大时,训练仍然是最有效的。幸运的是,在人类大脑的发展过程中有一种生物模拟。使用突触修剪,随着人们从童年进入成年,人类大脑变得更加有效。正是哺乳动物神经发育的这一特征,激发了一套深度学习模型的压缩技术。
据估计,在儿童早期发育期间,突触的最大数量高达 1000 万亿个,但在突触修剪后,成年人的突触数量减少了约 10 倍,约为 100 万亿个。这不仅降低了组织的代谢需求,而且有助于学习对世界更复杂的结构理解。同样在深度学习中,在 GPU 上的广泛训练出现之前,修剪权重源于一种用于改善模型泛化的正则化 技术。将参数剪枝、参数量化、参数编码结合在一个被称为深度压缩的模型压缩优化过程中,获得了宋瀚等2016 年 ICLR 最佳论文奖。深度压缩不仅使模型尺寸缩小了 35-50 倍,运行速度更快,所需能源更少(非常适合部署在电池供电的应用中),而且这些模型通常比原始的未压缩模型具有更好的性能。
密集-稀疏-密集训练
就像新生儿多变的思维一样,典型的多层感知器架构以神经元之间密集的互连为特征,如下图所示:
训练之后,如果我们要探索定义每个加权连接的参数值,我们会发现两个重要的特征。首先,许多权重值非常接近于零,因此我们应该能够丢弃它们,而不会显著影响网络的整体性能。第二,权重所代表的许多信息实际上是多余的。丢弃几乎无关紧要的权重并在多次迭代中重新训练网络减少了网络学习的冗余,这很像优雅有效的丢失正则化技术。在所谓的密集-稀疏-密集训练中反复修剪和重新训练模型可以移除高达 90%的参数,而不会损失测试精度(PDF) 。
参数量化
参数减少 90%相当不错,但此时仍有充分的机会来优化模型,它可能仍然太小,无法挤入片内 SRAM。在训练过程中,我们通常会使用高精度数据类型,如 64 位浮点数,但在一天结束时,我们通常会发现,无论权重值是正还是负 1e-33,在测试时都不会有太大的差异。通过量化其余参数,我们可以利用 Nvidia 的 INT8 推理精度等功能的效率和加速,并进一步减小模型大小。如果我们正在为自动驾驶汽车或物联网设备部署空中更新,较小的型号相当于为我们的客户和我们自己节省了通信成本和时间,同时避免了常规功能的设备外云计算的一些陷阱。
霍夫曼编码(额外学分)
在密集-稀疏-密集训练和参数量化后停止已经足以将标志性的 AlexNet 的存储需求减少超过 26 倍,而没有任何明显的性能损失。要实现深度压缩的全部优势,还有一个步骤,那就是重量分担。您应该还记得,在从完全连接到卷积神经网络架构的过程中,我们已经受益于显著的权重共享优势,因为每个卷积内核中的每个权重都作为滑动窗口应用于整个前一层。这将给定模型中的参数总数减少了几个数量级,仅次于可比的密集连接的多层感知器。但是,我们可以通过将 k 均值聚类应用于权重群体,使用质心值作为每个组的参数值,并将这些值放在查找表中,来实现进一步的权重共享优势。
在漫画中,这个概念看起来像这样:
结论
深度压缩是一种鼓励深度学习模型更智能地工作而不是更困难的方法,并能够提高能效、推理速度和移动部署。此外,在灵活的通用 GPU 上训练大模型,然后压缩它们以进行推理和部署,这结合了深度和广度模型的一些最佳功能,主要是在学习过程中在参数搜索方面撒下一张大网,并能够部署小得多的成品模型以用于设备上部署。设备上的机器学习增强了隐私,并为自动驾驶等应用的基本功能提供了更高的可靠性。深度压缩等模型优化技术缩小了科技巨头周围的护城河,使其有资源雇佣半导体工程师团队来开发内部机器学习硬件,并减少了对云服务上运行大模型的依赖。
原载于 2019 年 2 月 12 日【blog.exxactcorp.com。
解释了深层确定性策略梯度
原文:https://towardsdatascience.com/deep-deterministic-policy-gradients-explained-2d94655a9b7b?source=collection_archive---------2-----------------------
连续动作空间中的强化学习
这篇文章是对 Deepmind 的出版物“深度强化学习的连续控制” (Lillicrap 等人,2015 年)的彻底的回顾,其中提出了深度确定性政策梯度(DDPG),并且是为希望理解 DDPG 算法的人写的。如果你只对实现感兴趣,你可以跳到本文的最后一节。
本文假设读者熟悉基本的强化学习概念、价值&政策学习和行动者评论方法。如果你不完全熟悉这些概念,我还写过关于政策梯度和演员评论方法的文章。
熟悉 python 和 PyTorch 对阅读这篇文章也很有帮助。如果您不熟悉 PyTorch,请尝试按照代码片段进行操作,就像它们是伪代码一样。
浏览报纸
网络示意图
DDPG 使用四种神经网络:Q 网络、确定性策略网络、目标 Q 网络和目标策略网络。
Q 网络和策略网络非常类似于简单的优势行动者-批评家,但是在 DDPG,行动者直接将状态映射到行动(网络的输出直接是输出),而不是输出跨离散行动空间的概率分布
目标网络是其原始网络的延时副本,缓慢地跟踪已学习的网络。使用这些目标值网络大大提高了学习的稳定性。原因如下:在不使用目标网络的方法中,网络的更新方程依赖于网络本身计算的值,这使得它容易发散。例如:
因此,我们有了确定性策略网络和 Q 网络的标准参与者和批评家架构:
我们将网络和目标网络初始化为:
学问
这是我们想要实现的算法的伪代码:
Taken from “Continuous Control With Deep Reinforcement Learning” (Lillicrap et al, 2015)
我们将把它分解为:
- 体验回放
- 演员和评论家网络更新
- 目标网络更新
- 探测
重放缓冲器
正如在深度 Q 学习(和许多其他 RL 算法)中使用的那样,DDPG 也使用重放缓冲区对经验进行采样,以更新神经网络参数。在每次轨迹推出期间,我们保存所有的体验元组(状态、动作、奖励、下一个状态),并将它们存储在一个有限大小的缓存中——一个“重放缓冲区”然后,当我们更新值和策略网络时,我们从重放缓冲器中随机抽取小批量的经验。
以下是重放缓冲区的样子:
我们为什么要用经验回放?在优化任务中,我们希望数据独立分布。当我们以一种基于策略的方式优化一个连续的决策过程时,情况就不是这样了,因为那时的数据不会是相互独立的。当我们将它们存储在重放缓冲区中并随机进行批量训练时,我们克服了这个问题。
行动者(政策)和批评家(价值)网络更新
价值网络的更新类似于 Q-learning 中所做的。更新的 Q 值通过贝尔曼方程获得:
然而,在 DDPG,下一状态 Q 值是用目标值网络和目标策略网络计算的。然后,我们将更新后的 Q 值与原始 Q 值之间的均方损耗降至最低:
*注意原 Q 值是用价值网计算的,不是目标价值网。
在代码中,这看起来像:
对于保单功能,我们的目标是最大化预期收益:
为了计算保单损失,我们取目标函数相对于保单参数的导数。请记住,参与者(策略)函数是可微的,因此我们必须应用链式法则。
但是,由于我们是通过批量经验以非策略方式更新策略,因此我们采用从小批量计算的梯度总和的平均值:
在代码中,这看起来像:
其中优化器使用自适应矩估计(ADAM):
目标网络更新
我们复制目标网络参数,并让它们通过“软更新”缓慢跟踪已学习网络的参数,如下所示:
这可以非常简单地实现:
探测
在离散动作空间的强化学习中,探索是通过概率性地选择随机动作来完成的(例如ε-贪婪或玻尔兹曼探索)。对于连续动作空间,探索是通过向动作本身添加噪声来完成的(也有参数空间噪声,但我们现在将跳过它)。在 DDPG 的论文中,作者使用奥恩斯坦-乌伦贝克过程将噪声添加到动作输出中(乌伦贝克&奥恩斯坦,1930):
奥恩斯坦-乌伦贝克过程产生与先前噪声相关的噪声,以防止噪声抵消或“冻结”整体动态【1】。维基百科对奥恩斯坦-乌伦贝克过程提供了详尽的解释。
下面是 Pong 等人编写的 python 实现:
于是我们把演员网络产生的动作输入到get_action()
函数中,得到一个新的动作,在这个动作中加入了时间相关噪声。
我们现在都准备好了!
把它们放在一起
我们在这里有重放缓冲区,奥恩斯坦-乌伦贝克过程,以及 OpenAI Gym 连续控制环境的规范化动作包装器,在 utils.py 中:
以及 models.py 中的演员&评论家网络:
以及 ddpg.py 中的 DDPG 代理:
以及 main.py 中的测试:
我们可以看到 DDPG 代理是否学习到经典倒立摆任务的最优策略:
这就是 DDPG!
点击此处查看完整实施:
[## 基督教 08/强化学习
用 Python 和 PyTorch 实现强化学习算法的模块化…
github.com](https://github.com/thechrisyoon08/Reinforcement-Learning)
参考
Timothy P. Lillicrap,Jonathan J. Hunt,Alexander Pritzel,Nicolas Heess,Tom Erez,Yuval Tassa,David Silver 和金奎大·威斯特拉,深度强化学习的持续控制,CoRR abs/1509.02971 (2015)。
【1】Edouard leu rent 对 Quora post 的回答“我们为什么要在 DDPG 的探索中使用奥恩斯坦乌伦贝克过程?”
索尼 NNabla 的深度确定性策略梯度
原文:https://towardsdatascience.com/deep-deterministic-policy-gradients-with-sonys-nnabla-24357a0a87bb?source=collection_archive---------23-----------------------
你好,我是一名研究深度强化学习的研究生。我之前写过一篇关于用 NNabla 实现 Deep Q-Network 的博文。
[## 利用索尼的 NNabla 实现深度 Q 网络
NNABLA 是什么?
towardsdatascience.com](/deep-q-network-implementation-with-sonys-nnabla-490d945deb8e)
在这里,我将通过 NNabla 引入深度确定性策略梯度(DDPG)。完整实现是这里。
DDPG
DDPG 是一种用于连续控制任务的策略梯度方法。
[## 具有深度强化学习的连续控制
我们将深度 Q 学习成功背后的思想应用于持续行动领域。我们提出一个…
arxiv.org](https://arxiv.org/abs/1509.02971)
在 DDPG,有两个网络:一个政策网络(行动者)和一个行动价值网络(批评家)。这种算法被称为“行动者-评论家”,因为行动者学习政策函数以最大化累积回报,评论家学习(行动)价值函数以正确预测回报。
让我们用 NNabla 制作这两个神经网络。
import nnabla as nn
import nnabla.functions as F
import nnabla.parametric_functions as PFdef q_network(obs_t, action_t):
with nn.parameter_scope('critic'):
out = PF.affine(obs_t, 64, name='fc1')
out = F.tanh(out)
out = F.concatenate(out, action_t, axis=1)
out = PF.affine(out, 64, name='fc2')
out = F.tanh(out)
out = PF.affine(out, 1, name='fc3')
return outdef policy_network(obs, action_size):
with nn.parameter_scope('actor'):
out = PF.affine(obs, 64, name='fc1')
out = F.tanh(out)
out = PF.affine(out, 64, name='fc2')
out = F.tanh(out)
out = PF.affine(out, action_size, name='fc3')
return F.tanh(out)
相当简单!NNabla 基于由nn.parameter_scope()
声明的类似 TensorFlow 的命名空间系统来管理权重和偏差。
批评家的流失
用一步时差(TD)误差训练评论家:
from the original paper.
这可以用 NNabla 写成如下形式:
# N is a batch size
# state_size is a size of input vectors
# action_size is a size of the policy output
obs_t = nn.Variable((N, state_size)) # observation at t
act_t = nn.Variable((N, action_size)) # take action at t
rew_tp1 = nn.Variable((N, 1)) # reward value at t+1
obs_tp1 = nn.Variable((N, state_size)) # observation at t+1
ter_tp1 = nn.Variable((N, 1)) # 1.0 if terminal statewith nn.parameter_scope('trainable'):
q_t = q_function(obs_t, act_t)with nn.parameter_scope('target'):
act_tp1 = policy_function(obs_tp1, action_size)
q_tp1 = q_function(obs_tp1, act_tp1)y = rew_tp1 + gamma * q_tp1 * (1.0 - ter_tp1)
critic_loss = F.mean(F.squared_error(q_t, y))
上面的代码构造了计算 TD 误差平方的计算图。
演员的损失
相比之下,地面实况操作不是直接可用的。因此,演员被训练来最大化评论家的价值估计。策略网络的梯度计算如下。
from the original paper
这个梯度计算也可以写成 NNabla。
with nn.parameter_scope('trainable'):
policy_t = policy_function(obs_t, action_size)
q_t_with_actor = q_function(obs_t, policy_t)actor_loss = -F.mean(q_t_with_actor) # gradient ascent
-
有必要更新行动者以最大化价值估计。最终,行动者被引导到在行动-价值函数中获得的高价值空间。
目标更新
与 DQN 不同,DDPG 的目标更新是逐步将目标功能与最新参数同步。
with nn.parameter_scope('trainable'):
trainable_params = nn.get_parameters()with nn.parameter_scope('target'):
target_params = nn.get_parameters()update_ops = []
for key, src in trainable_params.items():
dst = target_params[key]
update_ops.append(F.assign(dst, (1.0 - tau) * dst + tau * src)))
target_update = F.sink(*update_ops)
F.assign
和tf.assign
差不多。F.sink
是同时运行所有输入的终端节点。
放在一起
结论
我介绍了索尼深度学习框架 NNabla 的 DDPG 实现。如果你用 GPU 尝试这个实现,你会发现它的训练速度很快。
如果您需要更多关于 NNabla 的信息,请访问此处。
深潜 AUC
原文:https://towardsdatascience.com/deep-dive-auc-e1e8555d51d0?source=collection_archive---------18-----------------------
Jheison Huerta photograph of the via lactea reflecting in the salt desert
将机器学习指标转化为现实世界
在本帖中,我们将解释如何将统计数据和机器学习指标转化为对业务团队的更接近的解释。让我们从解释 AUC 的值开始,然后回来解释如何计算它,这将为我们提供一个更好的背景,并帮助您理解它的优势。
上一篇文章(深入困惑矩阵)
如何解读 AUC
AUC 被计算为范围从 0 到 1 的面积,但是对 AUC 值的解释是一种可能性。如果我们从预测中选取任意两个观察值,它们将会以正确的方式排序的可能性。也就是说,AUC 为。90(其面积为 90%)的解释是,如果对任何预测值进行两次观察,它们被正确排序的概率是 AUC 本身,90%。这就解释了为什么最小 AUC 是. 50,因为如果你的模型是完全随机的,两个观测值被正确排序的概率是 50%,即随机。正如最大 AUC 为 1。
Source of gif: https://www.spectrumnews.org/opinion/viewpoint/quest-autism-biomarkers-faces-steep-statistical-challenges/
但毕竟这是什么这样的 AUC。
ROC 曲线的每一端由选定的阈值形成。下面的例子有助于我们理解。想象一下,我们从 20%的削减开始,注意假阴性率和假阳性率,我们在不同的阈值上移动以形成曲线。实际上,当我们要求 sklearn 绘制 ROC 曲线时,它通过如下观察进行观察:
- 计算类为真的几率。P (y = 1)
- 从最高概率到最低概率排序。
- 它从左角开始,如果最可能的观察是正确的,它就向上,如果是错误的,它就向右。
- 对所有的观察重复这个过程后,我们就有了 ROC 曲线。
- 我们将 AUC 计算为 ROC 曲线下的面积。
AUC 只不过是在 ROC 曲线下形成的面积。但是它带来了非常有趣的解释。
Source of gif: https://www.spectrumnews.org/opinion/viewpoint/quest-autism-biomarkers-faces-steep-statistical-challenges/
AUC 曲线给出了类别分离程度的概念
一个好的模型是一个可以很好地分离两个类别的模型,所以我们的模型在两个类别之间的交集越少,它就越好,因此 AUC 就越大。
AUC 对患病率不敏感
我们在混淆矩阵中遇到的一个非常恼人的问题是,普遍性(即类别之间的比率)极大地影响了这些指标,但 AUC 不受此影响,在下面的 gif 中,我们有一个真实的例子。AUC 曲线在右边的绿色部分,我们注意到它没有移动到任何患病率水平。
Source of gif: https://www.spectrumnews.org/opinion/viewpoint/quest-autism-biomarkers-faces-steep-statistical-challenges/
解释曲线的形状
当我们有两条不同的 AUC 曲线时,我们必须在每种情况下决定哪一条最适合我们。在下图的情况下,很明显模型 3 是最好的,模型 1 是最差的。这个决定不仅来自于 AUC 值更高,而且曲线形状显示模型 3 对于任何选择的阈值都更好。请注意,在曲线的开始(最容易预测的地方),三条曲线几乎相同,随着我们向更困难的预测移动,模型越向右开始区分。
现在一个更难的问题,如果曲线有相同的面积,但形状不同,如下图所示?这两种型号哪个更好?在这种情况下,曲线 A 对于疾病检测等问题会更好,因为它比曲线 b 更敏感
一个有趣的特征是,如果这两条曲线具有相同的 AUC 为 80,并且我们组装了这两个模型,则很可能最终模型将优于两个初始模型,因为它们可以结合两个模型的优点并获得两条曲线的最佳效果。
将 AUC 与人类专家进行比较
一个经过训练的机器学习模型有一个完整的 ROC 曲线,但在实践中,我们只能使用曲线上的单个点,并选择与该点相关的比率。在一个比较检测皮肤癌的模型(蓝色曲线)和多个医生(红点)的例子旁边,注意每个医生是一个单点。有些医生更敏感,有些更准确,但他们仍然选择单个切口,所以他们用点来表示,因为我们的模型有所有点的曲线。
以前的帖子
[## 困惑矩阵——深度探究
将机器学习指标转化为现实世界
medium.com](https://medium.com/@marcos.silva0/confusion-matrix-deep-dive-8a028b005a97)
参见:
- 数据科学的范围是什么;
- 为数据科学家推荐书籍、课程和电影。
- 解释机器学习;
- 统计学简史;
深入研究用于模型解释的 Catboost 功能
原文:https://towardsdatascience.com/deep-dive-into-catboost-functionalities-for-model-interpretation-7cdef669aeed?source=collection_archive---------2-----------------------
我们真的了解我们构建的 ML 模型内部发生了什么吗?我们来探索一下。
在我之前的博客中,我们看到了 XGBoost 和 LightGBM 的对比研究。通过分析,我们可以得出结论,catboost 在速度和准确性方面都优于其他两个。在这一部分中,我们将深入研究 catboost,探索 catboost 为高效建模和理解超参数提供的新特性。
对于新读者, catboost 是 Yandex 团队在 2017 年开发的开源梯度提升算法。这是一种机器学习算法,允许用户快速处理大型数据集的分类特征,这与 XGBoost & LightGBM 不同。Catboost 可以用来解决回归、分类、排序问题。
作为数据科学家,我们可以轻松地训练模型并做出预测,但是,我们经常无法理解那些花哨的算法内部发生了什么。这也是为什么我们看到离线评测和最终生产的模型性能存在巨大差异的原因之一。我们早就应该停止将 ML 作为一个【黑箱】来对待,并在提高模型准确性的同时重视模型解释。这也将帮助我们识别数据偏差。在本部分中,我们将了解 catboost 如何通过以下功能帮助我们分析模型并提高可见性:
特征重要性
为什么要知道?
除了选择要素重要性的类型之外,我们还应该知道要使用哪些数据来确定要素的重要性——训练、测试或完整数据集。选择一个比另一个有利也有弊,但是最终,您需要决定您是否想要知道模型在多大程度上依赖每个特征来进行预测(使用训练数据)或者该特征在多大程度上有助于模型在看不见的数据上的性能(使用测试数据)。我们将在本博客的后面看到,只有一些方法可以用来发现不用于训练模型的数据的特征重要性。
如果你关心第二个,并假设你有所有的时间和资源,找到特性重要性的最粗略和最可靠的方法是训练多个模型,一次留下一个特性,并在测试集上比较性能。如果性能相对于基线(当我们使用所有特性时的性能)变化很大,这意味着该特性很重要。但是由于我们生活在一个需要优化准确性和计算时间的现实世界中,这种方法是不必要的。以下是 catboost 让您找到模型最佳功能的几种智能方法:
预测值变化
对于每个要素,PredictionValuesChange 显示了当要素值发生变化时,预测的平均变化量。重要性的值越大,如果该特征被改变,则预测值的平均改变越大。
优点:计算成本很低,因为你不必进行多次训练或测试,也不用存储任何额外的信息。您将得到作为输出的标准化值(所有的重要性加起来为 100)。
缺点:它可能会给排名目标带来误导性的结果,它可能会将 groupwise 功能放在顶部,即使它们对最终的损失值有一点影响。
LossFunctionChange
为了获得该特征的重要性,catboost 简单地采用在正常情况下(当我们包括该特征时)使用模型获得的度量(损失函数)和没有该特征的模型(该模型近似地使用原始模型构建,该特征从集合中的所有树中移除)之间的差异。差异越大,该特征越重要。catboost 文档中没有明确提到我们如何找到没有特征的模型。
优点&缺点:这适用于大多数类型的问题,不像
*predictionvalueschange*
那样,在排序问题时会得到误导性的结果,同时,它的计算量很大。
形状值
https://github.com/slundberg/shap
SHAP值将预测值分解成每个特征的贡献。与基线预测(训练数据集的目标值的平均值)相比,它测量特征对单个预测值的影响。
shap 值的两个主要用例:
- 特征的对象级贡献
https://github.com/slundberg/shap
2。整个数据集的摘要(整体特征重要性)
shap.summary_plot(shap_values, X_test)
虽然我们可以通过 shap 获得准确的特征重要性,但它们在计算上比 catboost 内置的特征重要性更昂贵。关于 SHAP 值的更多细节,请阅读这个内核。
加成
另一个基于相同概念但不同实现的特征重要性是——基于排列的特征重要性 。尽管 catboost 不使用这个,但这纯粹是与模型无关的并且易于计算。
我们如何选择一个呢?
虽然PredictionValuesChange
& LossFunctionChange
都可用于所有类型的指标,但建议使用LossFunctionChange
对指标进行排名。除了PredictionValuesChange
之外,其他所有方法都可以使用测试数据,使用在训练数据上训练的模型来发现特征重要性。
为了更好地理解差异,下面是我们讨论的所有方法的结果:
****
Results of catboost feature imp. to predict if people will report over $50k of income from the classic “adult” census dataset (using log-loss)
****
从上面的图中,我们可以看到大多数方法在顶部特性上是一致的。看起来LossFunctionChange
最接近 shap(更可靠)。然而,直接比较这些方法是不公平的,因为predictionvalueschange
是基于列车数据,而所有其他方法都是基于测试数据。
我们还应该看到运行所有这些应用程序所需的时间:
互动
使用此参数,可以找到一对特征的强度(两个特征加在一起的重要性)。
在输出中,您将获得每对要素的列表。该列表将有 3 个值,第一个值是该对中第一个要素的索引,第二个值是该对中第二个要素的索引,第三个值是该对的要素重要性分数。有关实现细节,请查看嵌入式笔记本。
有趣的是,单个特征重要性中的前两个特征不一定是最强的一对。
笔记本
笔记本中使用的数据集
对象重要性
你为什么要知道?
- 从训练数据中移除最无用的训练对象
- 根据哪些对象被认为是最“有帮助”的,对一批新对象进行优先排序,类似于主动学习
利用这个功能,您可以计算每个对象对测试数据的优化指标的影响。正值反映优化指标增加,负值反映优化指标减少。这个方法是在[这篇文章](http://This mode is an implementation of the approach described in the Finding Influential Training Samples for Gradient Boosted Decision Trees paper)中描述的方法的一个实现。这些算法的细节超出了本博客的范围。
对象重要性的 Catboost 教程
** [## catboost/教程
CatBoost 教程存储库。在 GitHub 上创建一个帐户,为 catboost/教程开发做贡献。
github.com](https://github.com/catboost/tutorials/blob/master/model_analysis/object_importance_tutorial.ipynb)
cb.get_object_importance
中有三种类型的update_method
:
- 单点:最快和最不精确的方法
- TopKLeaves:指定叶子的数量。该值越高,计算越精确,速度越慢
- AllPoints:最慢也是最准确的方法
例如,以下值将方法设置为 TopKLeaves,并将叶子数限制为 3:
TopKLeaves:top=3
模型分析图
Catboost 最近在其最新更新中推出了这一功能。有了这个功能,我们将能够直观地看到算法如何分割每个特征的数据,并查看特定于特征的统计数据。更具体地说,我们将能够看到:
- 每个条柱(条柱用于连续要素)或类别(当前仅支持 OHE 要素)的平均目标值
- 每个箱/类别的平均预测值
- 每个箱中的对象数量
- 不同特征值的预测:对于每个对象,特征值是变化的,以使其落入某个箱中。然后,该模型根据该特征的新值来预测目标,并在一个箱(由红点给出)中取预测的平均值。
该图将为我们提供信息,如我们的分割有多均匀(我们不希望所有对象都在一个容器中),我们的预测是否接近目标(蓝色和橙色线),红线将告诉我们我们的预测对某个特征有多敏感。
数字特征分析
一键编码特征分析
感谢您阅读本文。希望下次您能够利用这些工具来更好地理解您的模型。
在机器学习社区对我之前关于CatBoost vs . Light GBM vs . XGBoost的博客做出积极回应后,CatBoost 团队联系我,看我是否有兴趣报道关于该库的更深入的主题。感谢 CatBoost 团队帮助回答我的问题!
关于我:我目前是优步地图团队的一名数据科学家。如果你有兴趣在优步解决具有挑战性的问题,请通过 LinkedIn 联系我。你可以在这里阅读我的其他博客。
参考
- Catboost 文档
- SHAP 价值观
- Catboost 官网
- CatBoost 纸
- 笔记本
- 关于寻找有影响力的训练样本的论文
- Catboost 教程**
深入了解卷积网络
原文:https://towardsdatascience.com/deep-dive-into-convolutional-networks-48db75969fdf?source=collection_archive---------10-----------------------
Visualization from http://terencebroad.com/convnetvis/vis.html
从积木到最先进的架构,触及可解释性和偏见。
By the end of this post you will understand this diagram. Image courtesy of FloydHub.
介绍
卷积网络(ConvNets)是一类高效的神经网络,在感知任务(如对象识别)中实现了令人印象深刻的性能。他们的建筑是由视觉皮层松散地启发而来的。2012 年 AlexNet ,一种 ConvNet,以较大优势赢得了 ILSVRC 2012 竞赛,引发了对深度学习的巨大兴趣,这种兴趣一直持续到今天。2019 年,对象检测的最先进架构是 ResNet,这是一种 ConvNet。
在本文中,我假设对标准的全连接神经网络(或多层感知器,MLP)有所了解。在概述了 ConvNets 激活之后,我将深入了解卷积的概念和其他构建模块(池化、批处理规范化、1x1 过滤器等)。接下来,我将简要说明一些实现最先进结果的高级架构(Inception、ResNet)。在最后部分,我将触及可解释性和偏见的话题。每个部分都包含一个参考文献和链接列表,以供进一步研究。一些概念通常适用于深度神经网络,但我将在 ConvNets 的上下文中说明它们。
如果您是 ConvNets 的新手,需要花一些时间来消化这些材料,慢慢来,阅读许多资料。你可以用这篇文章作为围绕 ConvNets 的想法的快速参考。如果您发现任何错误,或者如果您认为我错过了其他主题,请在评论部分告诉我。
目录
- 一个 ConvNets 的概述
- 卷积步骤
- 感受野
- 参数数量
- 小批量
- 批量正常化
- 其他标准化
- 联营
- 1x1 卷积
- 盗梦空间
- ResNet
- 可解释性
- 偏向
- 参考文献
一个网络的概述
卷积神经网络(ConvNets)是一类专门用于图像处理的神经网络。与其他神经网络一样,它们通过许多层将输入转换为输出。在 ConvNets 中,层有一个卷积步骤,一个汇集步骤(可选)和一个非线性激活。神经网络中的每一层通过线性和非线性运算将输入张量转换为输出张量。所有这些中间张量(包括网络输入和输出)被称为激活,它们都是输入的不同表示。
Figure 1. Activation tensors in a convolutional neural net.
当我们从输入到输出时,我喜欢通过可视化激活的形状来开始说明 ConvNets(参见图 1 )。每一层都通过线性和非线性操作来转换激活(我们将在下一节的中看到细节)。当我们穿过这些层时,激活的空间维度会缩小,而深度会增加。ConvNet 的最后一部分将 3D 激活转换为 1D,通常通过平均池化(参见池化部分)。最后,1 或 2 个完全连接的层将激活投射到最终分类的输出空间。在这篇文章中,我用分类作为最终任务的例子。一些架构通过直接生成长度与类别数量匹配的 1D 激活来避免最终的密集层。
激活的流程显示了输入是如何在一个越来越“丰富”的特征空间(增加的深度)中表示的,同时牺牲了空间信息(降低的高度/宽度)。最后完全连接的层放弃任何空间信息,以实现最终的分类任务。当我们经过各层时,特征不仅在数量上(深度大小)增加,而且复杂性也增加,是前一层特征的组合。换句话说,网络构建输入的层次表示:第一层根据基本特征(如边)表示输入,第二层根据更复杂的特征(如角等)表示输入。更深的一层可以识别抽象的特征,如眼睛甚至人脸。引人注目的是,ConvNet 将在训练过程中自主学习这一特征层次。
在训练过程中,网络将学习一种有利于解决指定任务的表示法。对于像 ImageNet(数百万张图像,分为 1000 个类别)这样的大型和多样化的数据集,学习到的表示将足够通用,可用于许多其他视觉感知任务,即使是在不同或非常特定的领域。这是迁移学习的基础:在大数据集上训练一次模型,然后在新的特定领域(可能很小)数据集上微调模型。这允许快速调整预先训练的网络,以快速和高精度地解决新问题。
卷积步骤
现在让我们放大到一个卷积层。请记住,我们在神经网络中所说的卷积与信号处理中的经典 2D 卷积有点不同。虽然广义的想法是相似的,但在数学上并不相同。
Figure 1.1 Convolution of a 5x5 input (blue) with 3x3 kernel (grey) with a stride of 2 and padding of 1. The 3x3 output is in green (source).
经典卷积和深度学习卷积都是通过对输入数组应用核来计算输出的。每个输出像素是输入和内核之间的逐元素乘积之和(点积)。通过在输入上移动核,我们获得不同的输出像素。我们每步移动的像素数(1 或更多)称为步幅。
一个基本的区别是输入和输出张量的形状:在神经网络中,我们有额外的维度。
如果你不熟悉 2D 卷积,看看这个伟大的互动演示获得一些直觉。
- http://setosa.io/ev/image-kernels/
Figure 2. A single convolution layer. The convolution output is a tensor with increased depth. Each spatial position in the output (yellow “rod”, middle) depends on a portion of the input (the “receptive field”, left) and on a bank of filters (kernels).
与经典 2D 卷积的区别
在 2D 卷积网中,卷积具有以下性质:
- 输入和输出激活(也叫特征图 ) 是 3D 数组(高度、宽度、深度)。第一层输入深度为 3 (RGB)。我们越深入地层,深度就越大。注意,当考虑小批量时,输入实际上是 4D。
- 和输入和输出一样,内核也是 3D 的。空间大小通常为 3x3、5x5 或 7x7,深度等于输入深度。内核也被称为过滤器。
- 每层有多个内核 称为一个滤波器组。内核的数量决定了输出的深度(通常大于输入深度)。
- 与经典卷积不同,在 ConvNets 中,我们在单个步骤中计算多个卷积(一个卷积对应一层中的一个内核)。
- 与经典卷积不同,在乘法之前,核不沿空间维度翻转(这使得卷积不可交换,但该属性与神经网络无关)。
感受野
感受域是对输出像素有贡献的输入的 3D 区域(见图 2 中的黄色立方体)。注意,一个输出像素有许多“值”,每个内核一个(图 2 中的 64)。通过排列对应于不同感受野的所有输出向量,我们获得了完整的 3D 激活。
通常,两个相邻输出位置的感受野会部分重叠。只有当步幅等于内核大小时,才没有重叠。
参数数量
层中的所有核(图 2 中的 64)可以排列成单个 4-D 形状张量
(#内核,内核大小,内核大小,输入深度)
这些参数包括核中的所有权重加上 1D 偏移向量。
偏差为每个内核引入了一个额外的参数。像核一样,每个空间位置的偏差都是相同的,因此偏差参数与核的数量(或输出深度)一样多。
将偏差和权重放在一起,层中的总参数总计为:
(#内核数 x 内核大小 x 内核大小 x 输入深度)
内核
小批量
实际上,图 1 的激活不是针对单个图像计算的,而是针对小批量计算的。在这种情况下,所有激活都将有一个大小为 batch_size 的额外维度。必须考虑批量大小,因为它直接影响训练和评估模型所需的 RAM。通常,我们使用 GPU RAM 中能够容纳的最大批量。
批量标准化
批处理规范化(BatchNorm)是近年来深度学习领域最重要的进展之一。BatchNorm 可以在几乎任何神经网络架构上加速和稳定训练,包括 ConvNets。
Figure 3. The batch normalization algorithm from the original paper. Before entering the ReLU, each batch is normalized with zero mean and unit standard deviation. Then, each activation is scaled and shifted using two parameters (gamma and beta). This last addition turns out to be the critical step making BatchNorm so effective. The scale-shift transform allows the optimization to directly control the scale of each activation through one parameter (gamma). Without it, a change of scale can only be achieved with a coordinated change in multiple weights that contribute to the activation.
奇怪的是,最初的 BatchNorm 作者将性能的提高归因于“内部协方差偏移的减少。但最近发现,BatchNorm 反而平滑了优化前景,允许更大的学习率快速收敛到更准确的解决方案。只是提醒一下,理论,即使是令人信服的或“直觉的”,也必须经过经验验证。
- “批量标准化:通过减少内部协变量转移加速深度网络训练”,Sergey Ioffe,Christian Szegedy,arXiv:1502.03167(2015)
- 《批量归一化》,I. Goodfellow,J. Bengio,a .库维尔,深度学习书 Ch 8.7.1 ( 2016 )
- "批处理规范化如何帮助优化?"、桑图尔卡等人arXiv:1805.11604(2018)
其他标准化
BatchNorm 无疑是深度学习中最流行的规范化方法,但不是唯一的。这一领域的研究非常活跃,在不久的将来我们可能会看到新的进展。问题是双重的。一方面,BachNorm 难以应用于递归网络,因为它依赖于小批量均值和标准差。另一方面,BatchNorm 的效果是相当偶然的,对 BatchNorm 如何帮助优化的更多研究可以带来更好的规范化方法。
为了简洁起见,我将只提到一种替代的归一化方案:权重归一化。在该方案中,我们对权重进行归一化,而不是对激活进行归一化。特别地,我们将每个核(对单次激活有贡献的所有权重)归一化为具有单位范数。然后,为了保持模型的表现力,我们还为每个激活添加了一个比例参数。原则上,这应该有助于以类似于 BatchNorm 的方式进行训练,通过提供一个单一的直接“旋钮”来改变每个激活,从而提供一个通向最小值的“更容易”(即更平滑)的路径。
Figure 4. Different approaches to normalize of activations in a mini-batch. (source)
已经提出了许多其他的归一化方法,每种方法都有其利弊。要获得出色的概述,请参见 Keita Kurita 的“深度学习中的规范化方法概述”。
- “权重归一化:加速深度神经网络训练的简单重新参数化”,Tim Salimans,Diederik P. Kingma,arXiv:1602.07868(2016)
- 深度学习中归一化方法概述, Keita Kurita,(2018 年 11 月 30 日)
联营
Figure 5. Example of a max-pooling block.
卷积块之后通常是汇集块,以减少激活空间维度。池有助于减少更深层的内存消耗。这也是将空间信息转化为特征的重要步骤。根据伊恩·戈德费罗等人的深度学习书籍****
池化有助于使表示对于输入的小平移近似不变。
有不同的汇集策略。最常见的是最大轮询和平均池。在所有情况下,池化将输入“块”(感受野)减少为 1×1 输出块,同时保持深度不变。通过选择最大输入激活(max-pooling)或取平均值(average-pooling)来实现减少。与卷积类似,汇集块将感受野映射到输出中的单个“像素”。出于这个原因,我们可以定义一个轮询空间大小(2x2、3x3 等。)和大步走。通常,步幅被选择为具有不重叠的感受野,以实现空间尺寸的减小。通常,最后的汇集层是整个空间激活的平均值(全局平均汇集或间隙),导致 1x1 输出激活(图 1 中大小为 512 的 1D 激活)。与卷积不同,池化没有任何参数,输出要素(深度)的数量始终与输入相同。
具有“可学习结构”的池层已被提出,但迄今为止受欢迎程度有限(贾等人 2012 )。
- 网络中的网络,,,水城颜,arXiv:1312.4400(2013)
- "Ch 9.3:Pooling" I . good fellow,J. Bengio,a .库维尔,深度学习书Ch 9.3(2016)
- “超越空间金字塔:融合图像特征的感受野学习”,贾,黄畅,Trevor Darrell doi:10.1109/cvpr . 2012.6248076(2012)
1x1 卷积
一些架构使用 1x1 滤波器。在这种情况下,过滤器映射形状的输入
(数量 _ 过滤器 _i,高度 _i,宽度 _i)
到形状的输出:
(数量 _ 过滤器 _o,高度 _i,宽度 _i)
注意只有特征的数量发生变化,而高度和宽度保持不变。在这种情况下,每个输出像素是仅依赖于一个输入像素的 num_filters_o 特征的向量(大小为 num_filters_i 的向量)。每个输出特征是同一像素的输入特征的(不同)线性组合,该像素是大小为 1x1 的感受野。
1x1 滤波器用于减少输出要素的数量,从而在保持空间维度不变的同时降低计算成本。例如, inception network 使用 1x1 过滤器来减少功能并创建“瓶颈”,从而使架构在计算上更加经济实惠。然而,如果瓶颈太紧,可能会损害网络性能。
当卷积核的大小大于 1×1 时,
每个输出特征仍然是感受野中所有输入特征
的线性组合,在这种情况下是> 1 像素宽。
在林等人的原始论文中,1x1 卷积被称为网络中的网络原始论文将其描述为 1x1 输入和输出特性之间的“迷你”全连接层。请注意,使用相同的权重将相同的全连接层应用于每个空间位置。
- 网络中的网络,,,水城颜,arXiv:1312.4400(2013****
开始
ILSVRC 2014 获奖者是 Szgedy 等人的 GoogLeNet 架构。其中介绍了下面所示的初始模块。
Figure 6. Inception module, the building block of the GoogLeNet architecture.
在卷积网络中,一个重要的选择是卷积核的空间大小。第一层的大小通常为 7x7,后面所有层的大小通常为 3x3。初始模块并行执行许多卷积,而不是为卷积选择一个大小。图 5 显示了在 inception v1 论文中提出的 inception 块。对同一输入执行大小为 1x1、3x3 和 5x5 的卷积(蓝色块)以及最大池(红色块)。额外的 1x1 卷积(黄色块)减少了深度大小,从而大大降低了内存需求。这些平行路径产生输出张量(具有相同的空间大小),这些输出张量沿着深度被连接起来以形成层输出。
自第一篇论文以来,已经提出了对 inception 架构的许多更新,包括 inception v2、v3、v4 和 inception-resnet 。后者结合了多重卷积和跳跃连接的初始思想(参见下一节)。
- “用卷积更深入”,C. Szegedy 等人(2014)arXiv:1409.4842
- 《Inception-v4、Inception-ResNet 以及剩余连接对学习的影响》,克里斯蒂安·塞格迪、谢尔盖·约菲、文森特·范霍克、亚历克斯·阿莱米,(2016)arXiv:1602.07261
- 盗梦空间网络版本的简单指南,Bharath Raj(2018 年 5 月)****
雷斯内特
多层神经网络中的一个已知问题是消失梯度。本质上,在反向传播期间,导数乘以前一层的导数。所以,当我们到达第一层的时候,梯度会变得非常小或者爆炸(溢出)。这种效应使得很难训练深度神经网络,包括神经网络。为了解决这个问题,何等人引入了“跳过连接”这一构成 ResNet 架构的构建模块。**
Figure 7. Illustration of the skip-connection, the building block of the ResNet architecture. (source)
在 ResNet 中,一层的输出不仅被馈送到下一层,而且被馈送到前面两层的输入。输入被添加到层输出,然后被馈送到下一层。
自从赢得 ILSVRC 2015 竞赛以来,ResNet 仍然是最先进的 ConvNet 架构。预训练的 ResNet34 或 ResNet50 是迁移学习中事实上的标准,用于实现从医学成像到泰迪熊探测器的专业应用。
- 《深度残差学习用于图像识别》,,,,,任,,(2015)arXiv:1512.03385
- “ResNet 及其变种概述”,Vincent Fung ( 2017 )
可解释性
为了建立对智能系统的信任,并将其有意义地融入我们的日常生活,很明显,我们必须建立“透明”的模型,解释它们为什么预测它们所预测的东西。
来自Grad-CAMarXiv:1610.02391。
众所周知,理解神经网络如何做出决定是一项艰巨的任务。解释神经网络的结果不仅是重要的科学努力,也是许多应用所需要的。神经网络可解释性是一个活跃的研究课题,涉及多种网络可视化技术。
概括地说,有两种广义的可解释性技术。一个称为属性,旨在找到输入图像中用于做出决定的区域。第二种称为特征可视化,旨在可视化输入图像中的哪些特征激活了特定的神经元或神经元群。****
Figure 8. Two approaches in interpreting ConvNets: feature visualization and attribution. Source Olah et al. 2017.
在一些架构上,属性可以通过将隐藏层中的空间激活与输入图像叠加并绘制所谓的显著性图来完成(图 8,右图)。显著图具有与上一次 3D 激活相同的空间分辨率,这是低的,但通常是足够的。适用于任何架构的这种方法的扩展是 Grad-CAM,其中显著图是最后空间激活(具有 3D 形状的最后激活)的加权平均值。这个加权平均值中的权重是从关于每次激活的损失函数的梯度计算的。Grad-CAM 可以应用于任何网络,甚至非分类任务。****
Figure 9. Feature visualization. The top row shows the “optimization objective”: single neuron, channel, layer, a class before soft-max, a class after soft-max. The bottom row shows an input image resulting from optimizing the corresponding objective. Source Olah et al. 2017.
对于特征可视化,我们可以在每一层中绘制内核权重。每个内核显示在层输入中检测到的模式。在这种情况下,解释在第一层比较容易,但在更深的层变得更加困难。另一种简单的方法是绘制给定输入的激活。****
生成(通过优化)输入图像以最大限度地激活神经元、通道、层或类的更细致的方法(图 9)。这允许构建“特征”的地图集,其可视地表示网络在每一层中响应什么。这种方法的缺点是生成的图像缺乏多样性,可能无法代表网络所响应的全部空间特征。关于进一步的信息,Distill.pub 发表的论文既有深刻的见解,又有令人惊叹的图表。
- " Grad-CAM ",R. R. Selvaraju,M. Cogswell,A. Das,R. Vedantam,D. Parikh,D. Batra ( 2016 ), arXiv:1610.02391
- “理解 CNN ”,安德烈·卡帕西,CS231n 课程
- " 特征可视化 " ,克里斯奥拉,亚历山大莫尔德温采夫,路德维希舒伯特( 2017 ),distilt . pub,doi:10.23915/distilt . 00007****
- 《用激活图谱探索神经网络》,Shan Carte,Zan Armstrong,Ludwig Schubert,Ian Johnson,Chris Olah ( 2018 ),distilt . pub,doi:10.23915/distilt . 00015****
偏见
Figure 10. Bias in state-of-the-art face-recognition systems (source).
如果不提到偏倚问题,对 ConvNets 的讨论是不完整的。机器学习中的偏差来自数据集和/或算法中的偏差,这反过来反映了创建系统的人的偏差。虽然偏见是机器学习中的一个严重问题,但 ConvNets 应用程序提供了一些突出的例子,说明它如何影响人们的生活。
请记住,网络将“学习”对解决任务有用的表示。例如,如果我们的目标是识别人脸,理想的数据集应该尽可能多样化,以便以平衡的方式表示所有的种族、年龄和性别组。实际上,大多数流行的数据集都过度代表了白人男性。正如研究员 Joy Buolamwini 发现的那样,这导致了当前商业人脸识别系统的严重偏见。在这些系统中,有色人种女性的面部识别准确率比男性低个数量级(图 4)。例如,这些系统已经或将要被部署来识别犯罪嫌疑人。不幸的是,如果你是一个黑皮肤的女人,你会被误认为是一个比白人高一百倍的罪犯!
作为机器学习实践者,我们不能放弃我们的道德责任。我们知道我们创造的系统会以前所未有的规模扰乱人们的生活。因此,我们必须采取措施克服这种偏见。根据《福布斯》杂志,雷切尔·托马斯是“人工智能领域 20 位不可思议的女性”之一,她写了很多关于偏见问题的文章,她的帖子是一个极好的信息来源。
- 关于 AI 让我害怕的五件事,Rachel Thomas,fast.ai 博客( 2019 )
- 性别阴影,Joy Buolamwini,( 2018 )麻省理工学院媒体实验室
- AI 安全需要社会科学家,杰弗里欧文,阿曼达阿斯克尔,(2019doi:10.23915/distilt . 00014****
其他主题
这里涵盖的主题还远未完成。这里有几个我没有谈到的话题:
- ****优化:培训需要使用众多优化方法中的一种。
- 卷积运算:步幅和填充的效果形成一个题目叫做“卷积运算”。一个分数步距**定义了转置卷积(也称为不恰当的“去卷积”),其在生成模型中用于生成图像。
- 敌对攻击:网络很容易被微小的敌对干扰所欺骗。精心选择的图像扰动(人眼不可见)可以改变网络输出。使 ConvNets 对敌对例子具有鲁棒性的研究正在进行中。
结论
在这篇文章中,我谈到了 ConvNets 的几个基本方面。即使是最先进的架构也是基于卷积层的基本构建模块。
ConvNets 可能已经“解决”了图像识别问题,但许多问题仍然存在。尽管最近取得了进展,解释结果仍然是一个挑战,一个阻碍某些领域应用的问题。用更小的数据集进行更好的泛化也将极大地扩展可处理问题的类别。但是,最重要的是,我们需要承认并努力克服社会偏见。鉴于对个人和社区的巨大影响,在这些系统中争取更多的公平是至关重要的。
参考
在这里你可以找到关于 ConvNets 的一般参考资料。具体主题的参考资料在每一节的末尾。
- Ch。9.卷积网络》,I. Goodfellow,J. Bengio,a .库维尔,深度学习著作 (2016)。****
- “第六课:正规化;盘旋;数据伦理、 Fast.ai 程序员实用深度学习、v3"
- 谓 Ch。6:深度学习、神经网络与深度学习,迈克尔·尼尔森(2015)https://neuralnetworksanddeeplearning.com/****
- 用于视觉识别的 CS231n 卷积神经网络安德烈·卡帕西斯坦福 CS231n 讲座****
- 《深度学习的卷积算法指南》,文森特·杜穆林,弗朗切斯科·维辛( 2016 ), arXiv:1603.07285 (另见他们的动画)
其他博文:
- Adit Deshpande 的《理解卷积神经网络的初学者指南》
- Irhum Shafkat 的“直观理解用于深度学习的卷积”
来自卷积神经网络拓扑可视化的标题图像。
深入探究科幻犯罪
原文:https://towardsdatascience.com/deep-dive-into-sf-crime-cb8f5870a9f6?source=collection_archive---------33-----------------------
生成数据可视化以分析旧金山的犯罪率
旧金山因许多事情而闻名:它充满活力的科技环境、标志性的金门大桥、迷人的缆车和(可以说是)世界上最好的餐馆。它也是 LGBT 和潮人文化的中心,这使它成为极具吸引力的旅游和移民目的地。然而,随着旅游业的蓬勃发展,财富不平等的加剧,以及成千上万的无家可归者,这个城市并不缺少犯罪。在本帖中,我邀请您深入研究旧金山的犯罪数据,以获得对旧金山犯罪环境的一些见解,并为您自己的犯罪分类模型设计特征。
探索性分析
你可以从 Kaggle 下载旧金山犯罪分类数据。该数据集包含 2003 年至 2015 年来自该市所有社区的近 800,000 份犯罪报告。它包括以下变量:
San Francisco Crime Rates Dataset Variable Description
让我们首先探索我们的目标变量,并找出旧金山最常见的 10 种犯罪类型。我们将根据事件数量对类别进行排序,然后使用水平条形图展示我们的调查结果:
*# Get 10 most common crimes*
most_common_cat = train['Category'].value_counts()[0:9].sort_values()
most_common_cat.values
categs = most_common_cat.index
y_pos = np.arange(len(categs))
counts = most_common_cat.values
plt.barh(y_pos, counts, align='center', alpha=0.5)
plt.barh(y_pos, counts, align='center', alpha=0.5)
plt.yticks(y_pos, categs)
plt.xlabel('Number of Incidences')
plt.show()
Most Common Crime Types
得知暴力犯罪不在犯罪发生率之首,令人颇感欣慰。然而,财产犯罪似乎相当普遍。现在让我们来看看哪些区的登记犯罪数量最高。
为此,我们将使用叶,这是一个易于使用的工具,创建交互式地图。要运行下面的代码块,你需要在你的终端上运行pip install folium
来安装 Folium,或者直接在笔记本上添加“!”在司令部前面。然后,您需要下载这个单元格中指定的 JSON 文件:
by_zone = train.apply(pd.Series.value_counts).reset_index()
*# Load SF data*
!wget --quiet https://cocl.us/sanfran_geojson -O sf_neighborhoods.json
sf_zones = r'sf_neighborhoods.json'
SF_COORDINATES = (37.76, -122.45)
*# Create an empty map zoomed in on San Francisco*
sf_crime_map = folium.Map(location=SF_COORDINATES, zoom_start=12)
sf_crime_map.choropleth(
geo_data=sf_zones,
data=by_zone,
columns=['index', 'PdDistrict'],
key_on='feature.properties.DISTRICT',
fill_color='YlOrRd',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='San Fransisco Crime by Neighborhood'
)
sf_crime_map
该单元的输出是一个交互式地图,其中包含按警察局辖区分类的犯罪率:
San Francisco Crime Rate by Neighborhood
您可以通过绘制单个犯罪类别或检查分布随时间的变化来随意试验这个情节。
接下来,我们来看看犯罪在工作日的分布。我首先构建了一个交叉表来获取每个工作日的犯罪数量。之后,我使用 seaborn library 中的热图对计数进行了标准化和可视化:
*# Extract the most common crimes from the data*
most_commons = train[train['Category'].apply(**lambda** x: x **in** categs)]
*# Build a cross table to get the number of each crime type per day of week*
cat_per_week_common = pd.crosstab(most_commons['Category'], most_commons['DayOfWeek'])
*# Calculate percentages of crimes*
cat_per_week_common = cat_per_week_common.div(cat_per_week_common.sum(axis=1), axis=0)
*# Rearrange columns*
cat_per_week_common = cat_per_week_common[['Monday',
'Tuesday', 'Wednesday',
'Thursday', 'Friday',
'Saturday','Sunday']]
*# Transform into a heat map*
fig = plt.figure(figsize=(10,10))
ax = sns.heatmap(cat_per_week_common,
cmap="BuPu", linewidths=.5)
plt.xticks(fontsize=12,rotation=45,ha='right')
plt.yticks(fontsize=12)
plt.xlabel("")
plt.ylabel("")
Most Common Crimes per Day of Week
如上图所示,大多数犯罪类型,如袭击和破坏行为,都发生在周末人们外出的时候。一些其他类型的犯罪更经常发生在工作日,这可能与警察工作时间有关。
最后,我们来看看 SF 警察局的成功率。具体来说,有多少暴力犯罪得到解决。让我们先从类别列表中划分出暴力犯罪的子集。我选择了我认为有趣的,但也可以随意探索其他类别!之后,我们可以创建逮捕变量,将所有可能的决议分为两类:起诉或不起诉。我假设“未被起诉”和“无”是仅有的两个对应于负面类别的决议。我们将计算已解决案件的比例,并使用水平图绘制它们。这一次,我们将绘制比例图,而不是绝对计数:
*# Pick crime types of interest*
violent = train[train.Category.isin(['ASSAULT', 'BURGLARY',
'KIDNAPPING', 'ROBBERY',
'SEX OFFENSES FORCIBLE'])].copy()
*# Create Arrest variable*
violent['Arrest'] = np.where(violent['Resolution'].isin(['NONE', 'NOT PROSECUTED']), 0,1)
*# Calculate counts*
arrest_counts = violent['Category'][violent.Arrest==1].value_counts()[0:9]
total_counts = violent['Category'].value_counts()[0:9]
arrest_counts = arrest_counts/(total_counts).sort_index()
total_counts = total_counts/(total_counts).sort_index()
*# Plot values*
total_counts.plot.barh(color='crimson', label= 'Unsolved')
arrest_counts.plot.barh(color='mediumseagreen', label='Solved')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.xlabel('Proportion')
plt.show()
Solved and unsolved violent crimes in SF
我们可以看到,在我们挑选的所有暴力犯罪中,警方的成功率都在 50%以下。在入室盗窃案中,这一比例仅为 17%。
特征工程
我们的数据集有许多观测值,但只有有限数量的要素。在本节中,我们将创建两组要素:时间要素和空间要素。时态特征可以从日期变量中提取。除了月、日和小时等明显的特征之外,我还提取了营业时间、周末和国定假日。要访问所有的美国假日,只需从 pandas.tseries.holiday 导入 USFederalHolidayCalendar。下面的函数将帮助您提取所有的功能:
**def** time_engineer(data):
*'''*
*Extract temporal features from dates.*
*'''*
*# Turn strings into timestamp objects*
data.Dates = pd.to_datetime(data.Dates)
*# Extract years, months, times of the day, and weeks of year*
data['Year'] = data['Dates'].dt.year
data['Month'] = data['Dates'].dt.month
data['Day'] = data['Dates'].dt.day
data['Hour'] = data['Dates'].dt.hour
data['WeekOfYear'] = data['Dates'].dt.weekofyear
*# Add a dummy for public holidays*
cal = calendar()
holidays = cal.holidays(start=data['Dates'].min(), end=data['Dates'].max())
data['Holiday'] = data['Dates'].dt.date.astype('datetime64').isin(holidays).astype('bool')
*# Add times of a day*
data['Night'] = np.where((data['Hour']< 6), 1, 0)
data['Morning'] = np.where((data['Hour']>=6) & (data['Hour']<12), 1, 0)
data['Afternoon'] = np.where((data['Hour']>= 12) & (data['Hour']<18), 1, 0)
data['Evening'] = np.where((data['Hour']>= 18) & (data['Hour']<24), 1, 0)
data['BusinessHour'] = np.where((data['Hour']>= 8) & (data['Hour']<18), 1, 0)
*# Add seasons*
data['Spring'] = np.where((data['Month']>=3) & (data['Month']<6), 1, 0)
data['Summer'] = np.where((data['Month']>=6) & (data['Month']<9), 1, 0)
data['Autumn'] = np.where((data['Month']>=9) & (data['Month']<12), 1, 0)
data['Winter'] = np.where((data['Month']<=2) | (data['Month']==12), 1, 0)
*# Encode weekdays*
data_dummies = pd.get_dummies(data['DayOfWeek'])
data = pd.concat([data, data_dummies], axis=1)
*# Create a dummy for weekends*
data['Weekend'] = np.where((data['DayOfWeek']=='Saturday') & (data['DayOfWeek']=='Sunday'), 1, 0)
*# Encode districts*
data_dummies = pd.get_dummies(data['PdDistrict'])
data = pd.concat([data, data_dummies], axis=1)
data = data.drop(columns=['PdDistrict'])
*# Drop categorical variables and variables that are not in test set*
*# School valiables contain too many NaNs*
data.drop(columns=(['Address', 'Dates', 'Descript', 'DayOfWeek',
'Resolution', 'Enrolled In Public School',
'Enrolled In Private School', 'Not Enrolled In School']))
**return** data
Word Cloud of Temporal Features
提取空间特征有点复杂,因为它们基于可以作为包加载的uszipcode
数据库。在笔记本中,您将找到清理邮政编码数据和提取相关人口统计特征所需的所有功能。请注意,要素工程过程需要花费大量时间(几个小时),主要是因为需要输入每个纬度和经度的邮政编码。
您的最终数据集应包括 89 个变量,这些变量包含犯罪发生率的时间和空间方面的信息。现在,您可以随意使用这些数据并训练自己的模型,它将在 Kaggle 排行榜上名列前茅!首先,这里有一个简单的函数,它训练一个模型,对测试集进行预测,并计算挑战中指定的 logloss:
# Try out different models
models = [LogisticRegression, RandomForestClassifier, KNeighborsClassifier]def run_model(model, X_train, y_train, X_test, y_test):
model = model()
model.fit(X_train, y_train)
y_preds = model.predict(X_test)
return (log_loss(y_test, y_preds))
results = [run_model(model) for model in models]
结论
在这篇文章中,我们研究了旧金山犯罪分类数据集,并了解了如何制作数据可视化来探索数据的不同方面。我们还使用地理位置和日期来设计空间和时间特征。在另一篇文章中(希望如此),我们将探索模型和特征选择技术、超参数调整和一些流行的降维方法!敬请期待:)
完整笔记本:https://github . com/ritakurban/Practical-Data-Science/blob/master/SF _ crime . ipynb
深入了解计算机视觉世界:第 1 部分
原文:https://towardsdatascience.com/deep-dive-into-the-computer-vision-world-f35cd7349e16?source=collection_archive---------15-----------------------
从 VGG、ResNet、GoogLeNet 和 MobileNet 开始
在完成了神经网络的基础知识之后,下一步将是学习这个领域中的一些“著名摇滚明星模型”。ResNet,Inception Net,Faster R-CNN,YOLO 等等。研究这些模型可以分为三个部分:这些架构背后的应用程序、实现和直觉。关于如何使用预训练模型以及如何构建它们,已经有大量的资源。但抓住模型背后真正的直觉有时会被忽略。研究人员用这种结构建立模型的意图是什么?是什么促使他们采取这样的方法?我们能从结果中推断出什么?
本文是下一个系列 最直观最简单的指南 教程,该系列的完整设置如下:
- 从 VGG 开始,ResNet,Inception Network 和 MobileNet
- CNN 地区,让我们开始物体探测吧!
- YOLO,SSD 和 RetinaNet,比较统一的
- 从对象检测到实例分割(TBU)
本文假设你已经熟悉了卷积神经网络的基本概念。除此之外,我们还将深入了解 VGG、ResNet、Inception Network 和 MobileNet 的各种卷积变换和修改。一个接一个地浏览它们,我们将回答上面提到的问题,这样我们才能真正理解这些架构的潜在含义。
VGG
ImageNet 是一个用于计算机视觉领域研究的大型数据集。自 2010 年以来,每年都举办名为 ImageNet 大规模视觉识别挑战赛 (ILSVRC)的比赛。VGGNet 是 2014 年 ILSVRC 竞赛的获胜者。尽管与其他复杂的网络相比,它的体系结构简单,但它仍然是最受欢迎的网络之一。
这个网络的一个有趣的部分是,即使在第一层中,它也只使用了 3×3 滤波器。如果和之前的比较, AlexNet ,2012 年的赢家,在前两层使用了 11x11 和 5x5 滤镜。还有 ZFnet ,2013 年的冠军,用的是 7x7 滤镜。代替在第一卷积层中使用相对大尺寸的滤波器,所使用的 VGG 网络滤波器的尺寸仅为 3×3。
那么尝试这个的意图是什么呢?答案是减少参数的数量。让我们在这里做一些计算。通道尺寸为 C 的单个 7x7 卷积层需要多少个参数?是 49C 。现在,通道尺寸相同的 3 层 3x3 卷积层的数量是多少?(9C )x3 = 27C 。看看有多少参数减少了。减少权重的数量可以通过降低网络的复杂性来处理过拟合。此外,由于我们可以为每个卷积层设置一个激活层,这也有助于模型的学习。
The architecture of VGG-19
与 VGG 网络或 AlexNet 一样,大多数卷积网络都遵循基本结构:一系列卷积层、一个汇集层和一个带有一些规范化的激活层。但是越来越深入,人们遇到了一些严重的问题,并开始重新设计这种方法。
雷斯内特
直觉上,我们希望“越深越好”然而,研究人员发现事实并非如此。随着网络变得越来越深,性能越来越差。原因之一是消失/爆炸梯度问题。虽然我们已经有几种方法来解决这个问题,如梯度裁剪,有一个退化问题,不是由于过度拟合。ResNet 的诞生就是从这里开始的。 为什么会这样?
让我们假设我们有一个具有理想精确度的良好网络。现在,我们将复制这个网络,只添加 1 层,但没有额外的功能。这被称为身份映射,这意味着获得与输入完全相同的输出。与其他具有许多参数的复杂层相比,这对于我们的“智能”模型来说是小菜一碟。所以对网络的性能应该没有什么危害吧?
那么如果我们附加越来越多的身份层会有什么结果呢?由于身份层对输出没有影响,因此性能不会下降。这似乎是一个合理的猜测,但这个实验的结果与我们的预期不同。该模型的性能比没有身份层的较浅模型差。
这个结果表明“越深越好”不适用于神经网络,即使有身份映射。仅仅将身份层直接附加到网络上就很难训练。好吧,那么把身份层作为一个附加层怎么样?
现在,这就是 ResNet 发挥作用的地方。假设 H(x) 是网络的结果。而如果我们放一条额外的路径,原来的函数就变成了 F(x) + x 其中 F(x) 是主分支的函数如上图。身份层也被称为快捷连接或跳过连接。这就给网络带来了“剩余学习”的概念。现在主分支被训练为逼近 H(x) — x 并使 F(x) 更接近零。这意味着给予各层一定的学习方向,从而使培训更容易。此外,网络可以通过身份层跳过一些层。这允许我们有更深的层,但仍然具有高性能。
你可能会问,当两层的大小不同时,怎么可能把 F(x) 和 x 相加。我们可以通过在快捷连接处进行零填充或线性投影来解决这个问题。所以 ResNet 中有两种快捷连接,一种是没有权重的,一种是有权重的。
上图是 ResNet 50 层的卷积块。它有一个具有 3 个回旋层的主分支和一个 1x1 回旋的快捷连接。这里我们可能需要问, 为什么要 1x1–3x 3–1x1 卷积?
要回答这个问题,需要了解数据的维度是如何根据过滤器大小而变化的。请看看右边的图片。如果我们说输入的形状是(32,32,256),那么与上一步相比,当它通过 3x3 过滤器时,维数会减小。当它通过第二个 1x1 滤波器时,它再次增加。这是一个瓶颈。通过强制数据适应更小的维度,我们可以获得更有效的特征表示。
The comparison of a plain network and ResNet
用更少的滤波器、更少的计算量和更高的精度来容易地优化深度神经网络。这种简单而新颖的重构带来了如此美丽的成就,这就是 ResNet 在 2015 年如何震撼人们的心灵。带着 ResNet 上的这种根本直觉,我想让你从 原论文 开始探索网络。而 这里的 是实验残块变体研究的第二部分。或者你可以在 ResNet 这里 找到一个简单的解释。
谷歌网
高性能越深入越好。我们需要深度神经网络来执行复杂而具有挑战性的任务。但是,当我们评估网络时,还有一个因素需要考虑。想想我们什么时候必须在移动应用程序中嵌入模型。肯定不希望有一个“太重”的模型。但除此之外,还有一个在实际应用中非常关键的计算成本问题。所以现在的问题就变成了, 怎样才能以更高的效率深入?
Know your meme
研究人员发现低效计算发生的一个地方是完全连接的架构。在卷积方法中,全连接架构表示层 l 从层l-1馈入,并连接到下一层 l+1 ,如下左图所示。研究人员发现,过滤器数量的任何均匀增加都会使计算加倍。所以他们建议从密集连接的架构转移到稀疏连接的架构。
不是实现一个 类型 的卷积,稀疏架构执行具有多个滤波器大小的多个卷积,如上所示。并且来自这些层的输出的维度可以与“相同的”填充相匹配。
这里有几个不同尺寸的过滤器有一个重要的意义。在训练过程中,网络检测到的特征的规模起初是小的和局部的,并且随着其深入而变大。例如,假设模型检测到一只猫。该模型看到小比例的特征,例如猫的皮毛图案,然后它移动到更大比例,例如它的耳朵形状,然后是腿的数量。
**
因此,即使图片中的猫处于不同的比例,模型仍然处理相同比例的特征映射。这是低效的,并且会损害性能。因此,拥有多个过滤器表明它现在知道如何根据输入图像“放大和缩小”。它使模型能够一次检测不同比例的图像。通过这样做,我们还可以处理选择参数的工作以及减少无效的计算。这是《盗梦空间》的第一脚。
因此,Inception 模块看起来就像上图左边的那个。但是有一个问题。 但是计算成本呢? 无论如何,稀疏连接的架构仍然需要相同或更多的计算量!研究人员解决这个问题的方法是实现 1x1 卷积,如上图右侧所示。这里的 1x1 卷积的目的是降维,就像我们在 ResNet 中讨论的那样。考虑到输入图像的(N,N,C)形状,计算时间减少了。如果图像的大小是 32×32,有 129 个通道,我们可以将参数的数量减少 9 倍!
The architecture of Inception Network
GoogleNet 的最终架构如上图所示。这些模块串联在一起,总共形成 22 层。这是一个相当深的网络,它也无法避免臭名昭著的消失梯度问题。所以研究人员处理这个问题的方法是制造侧枝。
“渐变消失”是什么意思它表明梯度的值随着深度的增加而变得越来越小,这意味着梯度没有多少信息可以学习。所以我们可以说,从早期阶段的梯度携带更多的信息。换句话说,我们可以通过在中间层添加辅助分类器来获得额外的信息。此外,正如我们上面讨论的,检测到的特征随着层的不同而不同。因此,“中间产品”也有利于标签的分类。我们将这些支路的损耗加到加权网络的总损耗中。
MobileNet
受我们上面讨论的网络的启发,“更深入和更复杂”是 CNN 研究的高度趋势。虽然这些网络带来了更高的准确性,但对于现实世界的应用来说,它们不够高效或“轻便”。为了在计算有限的平台上及时执行,它们需要更小更快。
研究人员提出的一个解决方案是形成分解卷积。分解卷积表示将标准卷积分解成深度卷积和点态卷积。这被称为深度方向可分卷积。
在深度方向可分离卷积中,我们首先分离输入和滤波器的每个通道,然后用相应的滤波器或以深度方向的方式对输入进行卷积。然后将输出连接在一起。这是 深度方向的卷积 。之后我们做 逐点卷积 ,和 1x1 卷积一样。现在看最后的结局。和标准的 3x3 卷积不一样吗?如果是,那么这样做有什么意义?
答案是计算。我们来比较一下两者的计算成本。当输入的波形为( N 、 N 、 C1 ),输出通道为 C2 ,滤波器大小为 F 时,两者的总运算量应该如左图所示。如你所见,深度方向可分离卷积降低了计算成本。根据原始论文中的所述,与采用标准卷积的相同架构相比,MobileNet 所需的计算量减少了 8 到 9 倍,精确度仅略有下降。
The applications of MobileNet
深度方向可分卷积也用于 Xception,其论文发表早于 MobileNet。但是我发现 MobileNet 论文对深度方向可分离卷积的概念给出了更直接的解释。
减去
现在,架构对你来说变得更简单和有形了吗?如我所说,理解结构背后的论点是至关重要的。所以我想再回顾一下电视网的一些亮点。
首先,卷积层的滤波器大小不仅仅具有特征映射的意义。它可以像 VGG 一样改变参数的数量。我们还可以创建瓶颈来提取有意义的数据表示。 1x1 卷积不仅仅是线性变换。它可以作为一个有用的技巧,在不显著影响输入数据的情况下,给出更多的非线性,改变维度,并减少计算。
为了获得更高的性能,ResNet 通过快捷连接来利用残差。这一层通过跨层有效地传递权重来更好地促进优化。另一方面,初始网络的策略是通过构建稀疏架构来使用多个过滤器。这是为了应对训练中音阶的变化。最后,MobileNet 选择将卷积分解为两个步骤。利用深度方向可分离的卷积,MobileNet 可以显著减少计算量和模型大小。
参考
- 卡伦·西蒙扬和安德鲁·齐泽曼, 用于大规模图像识别的极深度卷积网络 ,2015
- 、何等 深度残差学习用于图像识别 ,2015
- Christian Szegedy 等人2014 年**
- Christian Szegedy 等人, Inception-v4,Inception-ResNet 以及剩余连接对学习的影响,2016
- Franc ois Chollet,异常:深度可分卷积深度学习,2017
- Andrew G. Howard 等人, MobileNets:面向移动视觉应用的高效卷积神经网络,2017
这个故事引起你的共鸣了吗?请与我们分享您的见解。我总是乐于交谈,所以请在下面留下评论,分享你的想法。我还在 LinkedIn 上分享有趣和有用的资源,所以请随时关注并联系我。下次我会带来另一个有趣的故事。一如既往,敬请期待!
深入计算机视觉世界:第 2 部分
原文:https://towardsdatascience.com/deep-dive-into-the-computer-vision-world-part-2-7a24efdb1a14?source=collection_archive---------21-----------------------
有 CNN 的地区,让我们开始物体检测!
这是“深入计算机视觉世界”的第二个故事,该系列的完整集如下:
- 从 VGG 开始,ResNet,Inception Network 和 MobileNet
- CNN 地区,让我们开始目标检测
- YOLO,SSD 和 RetinaNet,比较统一的那些
- 从对象检测到实例分割(TBU)
在前一篇文章中,我们讨论了五个流行的网络,VGG、ResNet、Inception Network、Xception 和 MobileNet。这些网络现在是高级网络的主要组成部分,因此有必要了解它们的架构。
现在,我们进入下一页。从图像分类到目标检测。到目前为止,我们讨论的是一个大型卷积神经网络。虽然它们有很多层,但最终是一个网络。但是 R-CNN 和它的变体将是我们的焦点,这个网络是它的一部分。CNN 现在是整个“系统”的一部分,处理更复杂的任务,如对象检测和图像分割。从 R-CNN 开始,我们将看到这些网络是如何转变的,以及这些变化背后的想法。
从图像分类到目标检测
在我们直接进入 R-CNN“家族”之前,让我们简单检查一下图像分类和图像检测的基本思想。两者有什么区别?为了检测图像中的物体,我们还需要做哪些额外的工作?
首先,无论我们有多少个班级,都会有一个额外的班级-背景。需要一个对象检测器来回答这个问题,“有对象吗?”,这不是图像分类的情况。第二,当有一个对象时,仅仅说“是的,有”还是不够的(想象起来相当可笑..😅)它还应该告诉我们,“物体位于哪里?”我们需要探测到的物体的位置。这听起来可能很简单,但实现起来并不容易。当我们考虑速度和效率挑战时,事情变得更加复杂。
因此,物体检测就像..寻找一个物体的区域,定位它并对它进行分类。有了这个基本概念,我们现在准备开始 R-CNN 的第二个话题。
R-CNN
R-CNN 回答问题,“在 ImageNet 上的 CNN 分类结果能在多大程度上概括为物体检测结果?”所以这个网络可以说是物体检测家谱的开始,在神经网络的应用中有很大的重要性。基本结构由三个步骤组成:提取区域建议、计算 CNN 和分类。
首先,我们从输入图像中提取一些看起来有希望有物体的区域。R-CNN 使用选择性搜索来获得那些感兴趣的区域(ROI)。选择性搜索是一种基于像素强度分割图像的区域提议算法。如果你想深入了解选择性搜索,这里有 原文 。基本思路如下图。它首先从过度分割的图片开始,并在每个片段周围绘制一个边界框。并且基于它们在颜色、纹理、大小和形状兼容性方面的相似性,它不断将相邻的分组并形成更大的片段。R-CNN 通过这种方法提取了大约 2000 个地区提案,并将它们提供给 CNN。这也是它被命名为 R-CNN 的原因,具有 CNN 特色的区域。
Selective Search for Object Recognition
得到候选后,第二步是进入一个大型卷积神经网络。每个提议都被调整为固定大小,并分别输入 CNN。R-CNN 用的是 AlexNet(那是 2014 年,当时还没有 ResNet 和 InceptionNet)我们从每一个提案中得到 4096 维的特征向量。
并且在最后一步,从 CNN 提取的输出被馈送到一组类特定的线性 SVM 模型。我们为每个类优化一个线性 SVM,并且我们得到具有得分高于阈值的边界框的输出图像。在具有重叠框的情况下,通过应用非最大抑制,只需要一个。
值得一提的一个有趣部分是它如何克服数据稀缺问题。研究人员面临的挑战是,仅用少量的标记数据训练如此庞大的网络。解决方案是用不同的标签数据对 CNN 进行预训练(这是监督学习),然后用原始数据集进行微调。
R-CNN architecture
您可能已经注意到了一些可以改进的低效部分。选择性搜索是计算密集型的。并且为每个 ROI 处理 CNN 是重复的工作,这再次需要大量的计算成本。对预训练过程和分离的分类器的需要是没有吸引力的。而且这些机型的存储量太大。虽然 R-CNN 是一个里程碑式的成就,但它有几个缺点需要改进。
快速 R-CNN
快速 R-CNN 是上一部作品的下一个版本。这里发生了什么变化?重复处理卷积映射得到了改进。第一个变化发生在重复卷积层。
假设计算一个卷积网络需要 N 秒。由于 R-CNN 分别向网络输入 2000 个 RoI,总处理时间将为 2000N 秒。现在,我们不再单独处理 CNN,而是通过与所有建议共享卷积,只处理一次。*
正如您在上面看到的,这个网络接受两个数据输入,一个原始图像和一组区域建议作为输入。整个图像通过网络前馈产生特征图。有了这个特征地图,每个区域提议通过一个汇集层和完全连接的层来创建一个特征向量。因此,卷积计算是一次完成的,而不是针对每个建议。
并且用两个兄弟层替换多个分类器。一个是 softmax 函数,用于利用每一类的可能性估计对对象进行分类,另一个是边界框回归器,用于返回检测到的对象的坐标。所以得到的特征向量被送入这两层,我们从这两层得到结果。
Fast R-CNN architecture
现在,这个模型进行了更改,以共享卷积并分离附加的分类器。通过将“多个主体”合并为一个并去掉“沉重的尾巴”,我们可以实现更少的计算和存储。这种架构允许我们一起训练所有权重,甚至包括 softmax 分类器和多元回归器的权重。这意味着传播将来回更新所有的权重。惊人的进步!然而,我们仍然有机会获得更好的表现。
更快的 R-CNN
然而,快速 R-CNN 很难用于实时检测。造成这种时间延迟的主要原因是选择性搜索。它存在计算瓶颈,需要用更有效的方法来替代。但是如何?如果没有选择性搜索,我们如何获得区域提案?如何最大限度地利用 ConvNet 呢?研究人员发现,Fast R-CNN 中的特征地图也可用于生成区域提议。因此,通过避免选择性搜索,可以开发更高效的网络。
快速 R-CNN 由两个模块组成,区域提议网络(RPN)和快速 R-CNN。我们首先输入一幅图像到一个“迷你网络”,它将输出特征图。通过在特征图上滑动小窗口,我们提取区域提议。并且每个提议被馈送到两个兄弟层,softmax 分类器和包围盒回归器。
这两层可能看起来类似于快速 R-CNN 的最后几层,但它们是为了不同的目的而衍生的。对于每个提议,分类器估计图像中对象存在的概率。回归器返回边界框的坐标。所以它们是用来产生候选者的,而不是预测实际的物体。
我们只取得分高于某个阈值的建议,将它们与特征图一起输入到快速 R-CNN。以下步骤相同。它们被输入到卷积网络和 RoI 池层。最后一层将是分类器和回归器,最终预测图像中的真实对象。
Faster R-CNN architecture (left) and Region Proposal Network (right)
这个网络的一个重要属性是平移不变量,这是通过锚和它计算相对于锚的提议的方式来实现的。 什么是平移不变? 简单来说,就是不管物体旋转、移位、大小变化什么的,我们都能检测到。图像中的对象可以位于中心或左上角。根据视角不同,同一物体可以是宽的或长的。为了防止模型因为平移而无法定位物体,我们制作了多种比例和纵横比的锚框,如上图所示。这些盒子放在推拉窗的中央。所以如果在某个位置有 K 个盒子,我们得到 2K 个盒子的分数和 4K 坐标。
总之,在区域提议网络,我们在特征图上滑动具有多个锚框的窗口,并通过分类器和回归器评估每个框。低于阈值的建议被拒绝,因此,只有有希望的建议进入下一步。
不仅如此,该模型通过分别微调 RPN 和 Fast R-CNN 特有的层,同时修复共享层,优化了 4 步交替训练。这允许模型共享权重,形成统一的网络,并在效率和准确性方面带来更高的性能。为了比较性能,建议更快的 R-CNN 的时间是每幅图像 10 毫秒(整个过程每秒 5 帧),而使用 CPU 进行选择性搜索的时间是 2 秒。
减去
从 R-CNN 到更快的 R-CNN,网络得到了转变,不再依赖其他组件。R-CNN 可以通过丢弃线性支持向量机和共享卷积计算来增强。而快速 R-CNN 也改为共享卷积去除选择性搜索。通过将整个过程集成到一个网络中,我们可以实现更高的精度和更快的速度。
参考
- J.R.R. Uijlings 等人, 物体识别的选择性搜索 ,2012
- Ross Girshick 等人, 用于精确对象检测和语义分割的丰富特征层次 ,2014 年
- 何等, [视觉识别深度卷积网络中的空间金字塔池](http://Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition) ,2015
- 罗斯·吉希克, 快速 R-CNN ,2015
- 任等, 更快的 R-CNN:面向实时目标检测的区域提议网络 ,2015
- 何等 面具 R-CNN ,2018
这个故事引起你的共鸣了吗?请与我们分享您的见解。我总是乐于交谈,所以请在下面留下评论,分享你的想法。我还在 LinkedIn上分享有趣和有用的资源,所以请随时关注并联系我。下次我会带来另一个有趣的故事。一如既往,敬请期待!
深入计算机视觉世界:第 3 部分
原文:https://towardsdatascience.com/deep-dive-into-the-computer-vision-world-part-3-abd7fd2c64ef?source=collection_archive---------13-----------------------
YOLO,SSD,FPN 和 RetinaNet,比较统一的
刚开始看论文会很不舒服,很恐怖。克服这一点的一个方法是以更轻松的语气阅读一篇写得很好的文章。如果你选择的一篇论文难以消化,从解密视频或博客中获得一些直觉(比如这个😉).在你得到网络的核心概念后,再用原来的再试一次。读起来会变得更舒服,也更有趣,而不仅仅是一头扎进难读的书里。
这是“深入计算机视觉世界”的第三个故事,该系列的完整集如下:
- 从 VGG 开始,ResNet,Inception Network 和 MobileNet
- CNN 地区,让我们开始物体探测
- YOLO,SSD,FPN 和 RetinaNet,比较统一的
- 从对象检测到实例分割(TBU)
在前一篇文章中,我们讨论了对象检测网络——R-CNN、快速 R-CNN 和更快 R-CNN。这些都是基于两级架构。在第一阶段生成对象位置的候选,在第二阶段定位对象并对检测到的对象进行分类。
现在,下一个要探索的网络是 SSD、YOLO、FPN 和 RetinaNet。这些网络基于一级架构。最大的变化是,这些不再需要区域提案,从而形成一个更统一和完全卷积的网络,从而带来更快的性能。现在让我们一个一个地看看这是如何实现的。
(同 solid-statedisk)固态(磁)盘
SSD 代表,,其架构有三个要点。首先,这个网络可以在多个尺度进行检测。随着图层在基础网络之后出现,它产生了具有不同分辨率的多个特征地图,这使得网络能够在多尺度下工作。
第二,这些预测是以卷积的方式做出的。一组卷积过滤器对物体的位置和类别分数进行预测。这就是“单拍”这个名字的由来。取代了额外的分类器和回归器,现在检测是在一个单一的镜头!
最后,有固定数量的默认框与这些特征地图相关联。类似于更快的 R-CNN 的锚点,默认框应用于每个特征地图单元。
The architecture of SSD
网络的整体架构如上图所示。它使用 VGG-16 作为其基础网络,并有额外的功能层,规模逐渐减少。这个乍一看可以认为是相当复杂的,所以我们把它分成两部分。
在左图中,基础网络的特征层通过卷积滤波器进行检测。当要素图层的维度大小为 N x N 带 P 个通道时,这里的滤镜大小为 3x3xP 。现在,正如我上面所说的,每个单元格都有一组默认的边界框。因此,如果我们有 K 个盒子和 C 个类(包括“背景”类),我们计算原始默认盒子的四个偏移值,以及每个盒子的类分数。因此,滤波器的总数变为 (NxN)K(4+C) 。
SSD 使用卷积过滤器一次对边界框位置和类别分数进行所有预测。它不再需要区域提案网络。在不同比例的额外要素图层上执行相同的过程,从而显著提高精度。回想一下不同分辨率的特征地图,在一幅图像中看到不同大小的图形或物体(我用盗梦空间解释过这个)。因此,跨尺度预测在检测任务中变得至关重要。
在我们从所有这些层中获得结果后,我们将它们与地面真相框进行匹配,并选择最佳的一个。由于大部分的盒子会严重重叠,我们可以使用 非最大抑制 来选择一个。但是,仍然有一个相当具有挑战性的问题,阶级不平衡。当我们使用区域提案时,它们是有对象的合理候选。但在这里,网络从每个位置的一组默认框开始,具有多种比例和形状。结果是,大多数盒子的结果都是负面的。这就造成了阶层的不平衡。例如,“背景”类变成了一个简单的例子,而真正的“对象”类变成了困难的例子。简单的反例会淹没类的分布并使模型退化。(注意,这个问题将在 RetinaNet 中再次讨论)
为了补救这一点,SSD 只取一些负匹配,因此正匹配和负匹配之间的比率可以是 3:1。这叫硬负采。硬否定挖掘是对象检测中的一个经典问题,这意味着一个否定类很难被认为是否定的。一个模型应该把它归类为负面的,但是它给出了很高的可信度,因为负面的情况比正面的情况要多得多。我们只将正匹配输入到目标函数中,以便它计算地面真实和预测边界框之间的损失。
The Experiment Results of SSD
一件有趣的事情是,大约 80%的转发时间花在基础网络上,这表明更快的基础网络甚至可以进一步提高速度。并且数据扩充对于更高的准确性也起着重要的作用。与仅使用原始图像和水平翻转的更快的 R-CNN 相比,输入大小、形状和随机采样的变化提高了性能。此外,观察到各种默认的盒子形状对于准确性也是更好的。
YOLO
YOLO 是你只看一次的缩写。与 SSD 类似,YOLO 不使用区域提案,以“单次”方式工作。YOLO 有三种主要的变体。我不会涵盖所有的转换过程,而是将所有内容打包,并探索最终版本。如果你想知道所有的详细过程,请查看Jonathan Hui的这篇优秀文章。(从字面上看,这是我见过的最好的 YOLO 教程)。
The architecture of YOLO Ver.3. Let’s start from its tail where the predictions are made!
整个网络架构如上图。圆圈中的数字是层数。它使用 Darknet-53 作为它的基础网络,还有检测物体的附加层。让我们首先把注意力放在做出预测的尾部。YOLO 也是一个完全卷积网络,因此它通过卷积预测检测。经过几层后,对三种不同尺度的特征图进行 1x1 卷积检测。
Figures from Ver.1 (on the left) and Ver.3 (on the right)
当具有 P 个通道的特征图的大小为 N×N 时,应用 1x1xP 大小的滤波器。YOLO 也有默认的包围盒(原文中称之为 锚点 )。对于每个单元的每个框,预测 4 个边界框偏移值、对象性得分和类得分。客观性分数反映了该框包含一个对象的置信度。所以现在每个网格的预测数变成了 5+C 。所以如果盒子的数量是 K ,那么每一个音阶的滤镜总数就是 (NxN)K(5+C) 。
Now let’s see the main branch line. YOLO also operates in multi-scales like SSD, yet in a way a little bit different.
正如我所说的,随着深度的增加,特征地图的分辨率越来越小,当特征地图看到物体时,这会对比例产生影响。因此,为了实现多种比例,YOLO 只需通过一个穿透图层即可从上一个图层中获取更高分辨率的要素。ResNet 的快捷连接也是如此。
因此,在第 84 层,我们从前两层获取特征图,并将其向上采样 2 倍。然后,我们从第 36 层获得一个特征图,并将其与上采样特征连接起来。相同的过程在第 96 层重复一次,以得到最终的标度。通过这样做,我们可以在预测中添加更精细、更有意义的特征。
Figures from Ver.3 (on the left) and Ver. 2 (on the right)
第 1 版的基础网络是 AlexNet,第 2 版首次使用 Darknet,有 19 个卷积层。正如你在上面看到的,在第 3 版,这变成了 53 层。另一个值得一提的重要事情是,默认框是从 K-means 聚类中提取的,而不是手动选择的。网络在训练期间学会调整盒子,但是从一开始就有更好的先验知识肯定有助于网络。所以 YOLO 3 版通过聚类提取了 9 个默认框。通过连接前一层和一个穿透层的更高分辨率特征,与 SSD 相比,YOLO 可以更好地检测小物体。
FPN
FPN 代表特征金字塔网络。在此之前已经研究并使用了具有金字塔结构的网络。而且 SSD 也是类似金字塔的结构(垂直旋转试试)。但不能说是严格如图所示的金字塔式特征层次。因为它是从更高的层次开始形成金字塔,而不是从低层次开始。(记得 VGG Conv5_3 是用于检测的第一层)
Figures from FPN
有这种架构有什么意义?可以在网络的更深层次中检测到物体的精确位置信息。相反,语义在较低的级别变得更强。(我们将在下一个系列中讨论这个问题)。当一个网络有一种更深入的方式时,没有多少语义数据可以用来在像素级别上对对象进行分类。因此,通过实现特征金字塔网络,我们可以产生来自所有级别的多尺度特征地图,并且来自所有这些级别的特征在语义上是强的。
The architecture of FPN
FPN 的建筑如上图所示。有三个方向,自下而上,自上而下,横向。自底向上路径是原始论文中使用的主干 ConvNet 和 ResNet 的前馈计算。有 5 个阶段,并且每个阶段的特征图的大小具有 2 的缩放步长。他们按尺寸区分,我们称他们为 C1、C2、C3、C4 和 C5 。图层越高,沿自下而上路径的特征地图的大小就越小。
现在在级别 C5 ,我们移动到自上而下的路径。上采样应用于每个级别的输出贴图。和具有来自自下而上路径的相同空间大小的对应地图,通过横向连接进行合并。在相加之前应用 1x1 卷积以匹配深度大小。然后,我们在合并的贴图上应用 3×3 卷积,以减少上采样的混叠效应。通过这样做,我们可以将低分辨率和语义强的特征(来自自顶向下路径)与高分辨率和语义弱的特征(来自自底向上路径)相结合。这意味着我们可以在所有尺度上拥有丰富的语义。如图所示,同样的过程被迭代并产生 P2,P3 P4 和 P5 。
现在网络的最后一部分是一个实际的分类。事实上,FPN 本身并不是一个物体探测器。探测器不是内置的,所以我们需要在这个阶段插入一个探测器。RPN 和 Fast R-CNN 在原图中使用,上图中只描绘了 RPN 情况下的 FPN。在 RPN 中,对象分类器和边界框回归器有两个兄弟层。所以在 FPN,这部分是附在 P2、P4、 P5 每一级的尾部。我在这里不会涉及太多,因为我选择 FPN 的原因是为了解释 RetinaNet。
RetinaNet
RetinaNet 更多的是提出一个新的损失函数来处理类不平衡,而不是发布一个新颖的新网络。让我们再把阶层失衡带回来。SSD 和 YOLO 等一级检测器明显更快,但与两级检测器相比,精度仍然落后。而阶层失衡问题是造成这一弊端的原因之一。
Focal Loss
因此,作者通过对简单的例子进行加权,提出了一个新的损失函数,称为焦点损失。数学表达式如上图。这是交叉熵损失乘以一个调节因子。调节因子减少了简单例子对损失的影响。
比如比较 Pₜ = 0.9 和 γ = 2 时的损耗。如果我们说交叉熵损失为 CE,那么焦点损失变成-0.01CE。损失变成低 100 倍。而如果 Pₜ 变大,比如说 0.968,用常数 γ ,焦损就变成了-0.001 ce(as(1–0.968)=(0.032)≈0.001)。因此,它把简单的例子写得更难,并调整不平衡作为回报。而当 γ 增加时,如右图所示,当 Pₜ 不变时,损耗随着重量的增加而变小。
The architecture of RetinaNet
RetinaNet 的架构如上图。正如我们现在知道的 ResNet,RPN 的更快的 R-CNN 和 FPN,这里没有什么新的东西。网络可以分为两部分,一个主干网(a)和(b),两个子网用于分类和盒回归。主干网由雷斯内特和 FPN 组成,金字塔有 P3 到 P7 级。
与 RPN 一样,也有先前的锚盒。锚的大小根据它的级别而变化。在 P3 处,锚区域为 3232,在 P7 处为 512512。锚有三种不同的比例和三种不同的大小,所以每个等级的锚 A 的数量为 9。因此,盒回归子网的输出维数为(N×N)x 4A。当数据集中的类别数为 K 时,分类子网的输出变为(N×N)x KA。
Speed vs Accuracy on COCO dataset
结果相当引人注目。RetinaNet 在准确性和速度上都超过了以前的所有网络。retina net-101–500 表示具有 ResNet-101 和 500 像素图像比例的网络。与所有两阶段方法相比,使用更大的规模可以获得更高的精度,同时也足够快。
减去
有两种对象检测网络,一级和两级。各有利弊。两级网络,比如更快的 R-CNN,虽然准确,但是对于实际应用来说不切实际。一级网络,如 SSD、YOLO,速度够快但准确率相对较低。这就是 RetinaNet 的动机,开发一个一阶段网络实现两个兔子。
对象检测应该在多尺度上工作,因为对象的尺度不是恒定的。我们看到了网络使用什么策略进行尺度不变检测。固态硬盘有多层,在某种程度上缩小了分辨率。YOLO 在多尺度中有 3 个层,具有上采样和直通层。FPN 和 RetinaNet 制作了一个自上而下和横向工作的金字塔。
类别不平衡是物体探测任务中的另一个问题。有几种方法可以解决这个问题。SSD 使用了硬负挖掘但是有一个主要的缺点,那就是我们只能使用收集到的一些例子。RetinaNet 提出的另一个解决方案是聚焦损失。通过添加权重参数,我们可以抑制简单示例的贡献,并且有效地使用所有示例。
参考
- 刘威等人[ SSD:单次多盒探测器 ],2016
- Joseph Redmon 等人[ 你只看一次:统一的实时对象检测 ],2016
- 约瑟夫·雷德蒙等人[ YOLO9000:更好、更快、更强 ],2016
- 聪-林逸等[ 特征金字塔网络用于物体检测 ],2017
- 约瑟夫·雷德蒙等人[ 约洛夫 3:增量改进 ],2018 年
- 聪-林逸等人[ 密集物体探测的焦损失 ],2018 年
这个故事引起你的共鸣了吗?请与我们分享您的见解。我总是乐于交谈,所以请在下面留下评论,分享你的想法。我还在 LinkedIn上分享有趣和有用的资源,欢迎随时关注并联系我。下次我会带来另一个有趣的故事。一如既往,敬请期待!
使用 Git 深入研究版本控制
原文:https://towardsdatascience.com/deep-dive-into-version-control-using-git-f0f3018d10f9?source=collection_archive---------10-----------------------
掌握 Git 实现高效的代码开发和协作
Git 是一个免费的工具,它通过提供一个分布式版本控制系统来实现高效的代码修改。这是我开始学习编程时学到的最有用的工具之一。无论我是在从事我的业余项目、与朋友合作,还是在专业环境中工作,Git 都证明了自己非常有用。我能给你的最好的类比是在 Google Doc 这样的平台上为一个小组项目写一份报告。您的同事可以同时处理他们自己的报告部分,而不必直接修改您的部分。Git 通过允许您从主分支创建分支并让多人在一个项目上协作来实现这个目标。在完成安装过程后,我将解释什么是 Git 分支。如果您刚刚开始或只是独自编写项目代码,Git 仍然可以帮助您跟踪您的编码历史,恢复变更,并维护一个高效的工作流。
使用 Git 时,您有多种选择。我是在本科学习期间作为学生开始 Github 之旅的。注册成为学生的好处是可以在 Github Education 获得一个免费的私人 Github 帐户。如果你是学生,请点击这里查看的交易。除了 Github,我还使用 Gitlab 进行项目合作。你可以选择 Github 或 Gitlab,因为它们都提供相似的功能。本教程将重点介绍如何设置 Github。如果你想将库从一个平台迁移到另一个平台,请参考迁移文档这里或者下面的评论,我很乐意写一个关于它的教程。
装置
Linux 操作系统
$ sudo apt install git-all
如果您有问题或者需要安装其他基于 Unix 的发行版,请访问这里的。
马科斯
首先,通过运行以下命令检查您是否已经安装了 Git:
$ git --version
如果您没有最新版本,应该会出现安装提示。否则,可以通过这里的获取最新版本的安装链接。
Windows 操作系统
对于 windows,请点击此处,下载将自动开始。这是 Git for windows,根据 Git 官方文档,Git for windows 不同于 Git 本身。Git windows 附带了 Git BASH,它有 BASH 模拟器,所以 Git 可以使用命令行特性在 windows 上轻松运行。这样,如果需要的话,您从在 windows 上运行 git 命令中获得的经验可以很容易地转移到其他系统。另一个安装选项是安装 Github 桌面。
创建 Github 帐户
进入注册流程并创建一个账户:【https://github.com/join?source=header-home
一旦你创建了一个 Github 帐户并登录,你现在可以创建库。存储库是您放置项目的地方。您可以决定每个存储库拥有一个项目,或者您可以拥有一个包含许多分支的存储库。对于后者,您的分支可以是相关的,但我见过用户在同一个存储库中创建不相关的分支,也称为孤儿分支。
分支
如果您是版本控制和 Git 的新手,这一切听起来会有点混乱。我喜欢把仓库想象成一顿饭。让我们把它当作感恩节晚餐。你的盘子里有火鸡、填料、蔓越莓酱和土豆泥。你将为自己提供各种食物的盘子就是储藏室。你可以选择拿起四个小盘子(四个储存库),把每样食物放在相应的盘子里。你的另一个选择可能是在一个更大的盘子(储存库)里为你自己提供四种食物中的每一种。分支是主分支的快照(主分支类似于我的项目的最接近的远景)。您获取这个特定的快照,并在不影响主分支的情况下添加额外的更改/特性。无论您喜欢哪种方法,您都可以选择使用 Git 以简洁明了的方式组织项目。我个人更喜欢用一个单一的存储库来代表一个项目,然后在这个项目的存储库中,我会创建一些分支来为我的项目添加特性。
一旦理解了 Git 数据存储的概念,Git 分支就更好理解了。当您做出更改并提交它们时,Git 将信息存储为一个对象,该对象保存了更改的快照。这是 Git 作为版本控制系统的一个特殊属性,因为其他版本控制系统将更改保存为基于文件的更改列表。
其他版本控制系统
Other Version Control Systems — Image taken from git-scm
Git 存储数据
Git storing data as a stream of snapshots — image taken from git-scm
这意味着,一旦您初始化了本地存储库,Git 就会知道其中的任何和所有更改(下面将详细介绍初始化)。
州
在给定的分支中,您有文件,并且在任何给定的时间,您的文件可能处于以下三种状态之一:
- 修改
- 上演
- 坚定的
已修改状态是指已经进行了更改,但没有任何更改被保存为其对应的快照。挑选修改过的文件,并将它们标识为您希望在下一个保存的快照中使用的项目,这被称为暂存。提交状态是指预期的更改安全地存储在本地数据库中。理解任何给定文件在本地存储库中的不同状态非常重要,这样才能安全地将更改推送到远程存储库。
创建您的第一个存储库
现在我们有了关于存储库和分支的背景知识,让我们创建我们的第一个存储库。点击右上角,打开“新建存储库”链接。
给存储库一个新名称,并选择隐私设置。此设置页面上的第三个选项使您能够使用自述文件初始化存储库。我们现在可以跳过它,但是 README.md 文件非常重要。这是一个文本文件,用户使用它来提供项目概述、功能、安装说明、许可证和学分。Github 将使用这个文件,如果可用的话,在主目录页面上为任何给定的存储库创建一个项目摘要。
一旦您创建了一个存储库,这就是所谓的远程存储库。Git 通常为您提供在本地创建新存储库或使用本地文件夹并将其初始化为存储库所涉及的选择和命令。对于本教程,假设已经有一个包含代码和文档的文件夹。您希望将内容添加到这个新创建的存储库中。
用本地文件填充远程存储库
$ git init
上面的命令在本地文件夹中创建一个空存储库,其中包含您要添加到远程存储库的文件。在将当前本地目录初始化为 git 存储库之后,如果您有文件存在于这个本地文件夹中,那么它们将处于修改过的状态(参见前面关于状态的讨论)。为了暂存这些修改过的文件,我们需要标记想要的文件。
因为我们是第一次添加到这个远程存储库中,所以您需要添加以下内容:
git remote add origin https://github.com/<username>/<your_repository_name>.git
对于此初始过程之后的提交,您可以使用以下命令之一添加文件:
$ git add <file_path>
# commit all files
$ git add .
此时,文件位于“暂存区”。
$ git commit -m “write your commit message here.”
文件现在应该安全地提交并记录到本地数据库。现在,提交最终可以通过以下方式推送到远程存储库:
$ git push
对于您的初始提交, git push 应该会毫无问题地推送您当前的更改。但是,可能会有多个分支的情况。您希望将所有本地分支推到一个特定的远程存储库。在这种情况下,请使用:
$ git push <remote> — all
随着你对 Git 的经验积累和项目的进展,你可能需要在 git 推送上使用 — force 标志。强烈建议只有在你对你的建议有绝对把握的时候才使用 — force 标志。
$ git push <remote> — force
当您推送您的更改时,Git 希望验证将更改推送至远程存储库的用户,并将要求您提供您在注册时创建的用户名和密码。如果您是全局用户,在全局 git 配置设置中配置用户名和密码,如下所示。
从远程存储库制作本地副本
上面的例子关注于这样一个场景,您在本地机器上完成了开发工作,然后您将这些工作推送到远程存储库。当您需要使用远程存储库的内容来开始本地开发时,情况正好相反。在这种情况下,您需要克隆感兴趣的存储库,为此,请确保您拥有访问权限。例如,您想使用 bootstrap 进行开发。你访问 bootstrap github 库:https://github.com/twbs/bootstrap。单击存储库上的克隆或下载按钮,复制远程存储库链接。
克隆存储库
$ git clone [https://github.com/twbs/bootstrap.git](https://github.com/twbs/bootstrap.git)
用远程中的更改更新本地副本
假设您已经提交了您的更改,但就在您的同事向同一分支机构提交更改之后。为了确保您的本地分支与这些变更保持同步,您需要将这些变更拉下来。
$ git pull <remote>
Git pull 通过使用(1) git fetch 和(2) git merge 从远程存储库中获取信息。获取从本地存储库与主分支发生分歧的节点开始。如果需要跟踪,您可以随时使用 git fetch 。Git fetch 下载本地存储库中没有的信息,然后 git merge 将这些信息集成到本地存储库中。另一个与 git merge 非常相似的命令是 git rebase 。使用 git rebase 优于 git merge 的主要优势在于,新信息的集成发生在分支上最后一次提交的末尾。这导致了更加线性的提交历史,而当使用 git merge 时,情况并非总是如此。在 git pull 的情况下,合并变更的第二个步骤也可以使用下面的代码与 rebase 交换:
$ git pull --rebase <remote>
当您对本地存储库进行更改时,您需要从远程存储库获取新的更改,切换到不同的分支,等等。您不希望您的本地更改受到直接影响,但是您希望有一个干净的工作树。在这种情况下,
# 1 - stash local changes
$ git stash
# 2 - pull remote changes
$ git pull
# 3 - view stashed list
$ git stash list
# 4 - access what you JUST stashed
$ git stash apply
# 5 - access an older stash from the stashed list on #3
$ git stash apply <stashed-id-from-list>
在这一点上,你可能会问我们在 git clone 和 git pull 中试图实现的目标有什么不同?第一,他们的目的不同。 Git 克隆获取远程存储库中的信息并制作本地副本。这是一次性操作。 Git pull 是一个命令,用于在远程分支更新时更新您的本地变更库。这将不止一次使用,最好是在您的本地分支落后的情况下提交变更的任何时候使用。
Git 配置
我们提到,在提交期间,Git 想要验证用户将变更提交到存储库的细节。每次提交时总是输入用户名和密码,这可能会变得重复。使用 Git 全局配置文件,您可以执行一些修改来减少重复性。
- 用户名:
$ git config — global user.name <username>
2.电子邮件:
$ git config — global user.email <email>
3.错认假频伪信号
$ git config --global alias.<alias> <git-command>
例如,将 git 状态别名化为 git s:
$ git config --global alias.s status
可能需要查看和手动编辑 git 用来保存上述指令的配置文件。
4.访问全局配置文件
$ git config --global --edit
查看历史记录
Git 最有用的特性之一是能够方便地查看您的提交历史,并不断地总结您的工作。工作日中,干扰时有发生。能够简单地运行 commit log 命令并查看整个提交历史有助于您获得所有更改的摘要。
$ git log
如果您只是运行 git log 命令,人眼可能会有点难以理解结果。但是,我们有修饰日志、传递单行提交消息和添加图形元素的选项。
# --all shows you the log history in its entirety
# --oneline compresses the commit messages to a single line.
# --decorate adds branch names and tags from commits
# --graph is a textual graph representation$ git log --all --decorate --oneline --graph
按模式搜索提交日志是另一个有用的特性。如果您想在一个有许多协作者的项目中找到您自己提交的特定变更,请执行以下操作:
$ git log — authors=<username>
如果是包含特定短语或模式的提交消息,请使用以下内容进行搜索:
$ git log --grep=”<pattern>”
每次提交的特定文件的更改可以用 stat:
$ git log --stat
改变历史
重定…的基准
使用 rebase,您也可以更改提交时间线。通常建议不要对已经被推送到公共存储库的提交进行重新排序。只传递 git rebase 将从当前分支获取提交,并自动将它们应用到传递的分支。我个人很欣赏交互式的基础特性,在这里你可以决定如何将提交转移到一个新的基础上。
# rebase current branch onto base(tag, commit ID, branch name, etc.)
$ git rebase <base>
# interactive changes
$ git rebase -i <base>
更改最后一次提交
历史最频繁的修改与更改最后的提交有关。在临时环境中,您可以决定不希望添加某个:
# change last commit message
$ git commit --amend
根据 Git 文档,建议您小心使用这个命令,并像对待一个小的 rebase 一样对待它。如果你已经推动了你的改变,就不要修改了。
从提交历史记录中删除文件
假设你养成了用 git add 添加所有变更的习惯。不小心添加了一个您想从所有提交历史中删除的敏感文件。使用分支过滤器流程,您可以实现以下目标:
$ git filter-branch --tree-filter 'rm -f sensitive_file.txt' HEAD
添加. gitignore
如果您创建了一个名为的文件,上述场景就不会发生。gitignore 并将你的“sensitive_file.txt”列为该文件中的一项。在您的本地目录中创建这个文件,然后添加备份文件、配置等。将使您免于将混乱推送到您的远程存储库。除了特定的文件名,您还可以指定模式。比如你有 *。txt 在你的。gitignore 文件,它将忽略所有文本文件。
观察差异
当前工作目录中的更改可以直接与远程分支上的最后一次提交进行比较:
$ git diff HEAD
HEAD 是指您所在的分支中的最后一次提交。
撤消更改
到目前为止,我们已经彻底讨论了 git 文件的三种不同状态。其中一个状态是 staging。如果您想要撤消暂存文件,请使用
$ git reset
# to reset specific files use a file path
$ git reset <file>
一旦分支被推送,我们仍然可以通过使用 revert 更改特定的提交来撤销。下面显示的<提交>参数是一个具体的提交参考。用 git log(如上所述)观察您的提交日志,然后对下面的命令使用 commit ref。
$ git revert <commit>
结论
从学习创建 Git 库到理解如何撤销我们的“错误”,我们已经走过了漫长的道路。理解 Git 并习惯本文中的命令列表可能需要一段时间,但这只是时间和实践的问题。如果有特定的命令无法记住,使用我们讨论过的别名方法(参见 Git 配置一节)。即使您目前没有使用 Git 的项目,也可以创建一个模拟存储库,并使用文本文件进行练习。确保你的项目用 README.md (参见创建你的第一个存储库一节)很好地记录,并且经常提交。有了这个教程,你就有足够的知识来进行项目合作,改变你的项目历史,并保持一个完美的投资组合。
计算机视觉中的深度域适应
原文:https://towardsdatascience.com/deep-domain-adaptation-in-computer-vision-8da398d3167f?source=collection_archive---------6-----------------------
在过去的十年中,计算机视觉领域取得了巨大的进步。这一进步主要是由于卷积神经网络(CNN)不可否认的有效性。如果用高质量的带注释的训练数据进行训练,CNN 允许非常精确的预测。例如,在分类设置中,您通常会使用标准网络架构之一(ResNet、VGG 等)。)并使用您的数据集对其进行训练。这可能会带来非常好的性能。
另一方面,如果您没有针对您的特定问题的大量人工注释数据集,CNN 还允许通过迁移学习来利用已经针对类似问题训练了网络的其他人。在这种情况下,您可以采用一个在大型数据集上进行预训练的网络,并使用您自己的小型带注释的数据集来调整它的一些上层。
这两种方法都假设您的训练数据(无论大小)代表了基本分布。但是,如果测试时的输入与定型数据显著不同,则模型的性能可能不会很好。例如,让我们假设你是一名自动驾驶汽车工程师,你想分割汽车摄像头拍摄的图像,以便了解前方的情况(建筑物、树木、其他汽车、行人、交通灯等)。).您的 NYC 数据集有很好的人工生成的注释,并且您使用这些注释训练了一个大型网络。你在曼哈顿的街道上测试你的自动驾驶汽车,一切似乎都很好。然后你在巴黎测试同样的系统,突然事情变得非常糟糕。汽车不再能够检测交通灯,汽车看起来非常不同(巴黎没有黄色出租车),街道也不再笔直。
您的模型在这些场景中表现不佳的原因是问题域发生了变化。在这种特殊情况下,输入数据的域发生了变化,而任务域(标签)保持不变。在其他情况下,您可能希望使用来自同一域的数据(为同一基础分布绘制)来完成一项新任务。类似地,输入和任务域可以同时不同。在这些情况下,领域适应会帮助你。领域自适应是机器学习的一个子学科,处理场景,其中在源分布上训练的模型被用于不同(但相关)目标分布的上下文中。一般来说,领域自适应使用一个或多个源领域中的标记数据来解决目标领域中的新任务。因此,源域和目标域之间的相关程度通常决定了适配的成功程度。
领域适应有多种方法。在“浅”(非深)域适应中,通常使用两种方法:重新加权源样本并对重新加权的样本进行训练,并尝试学习共享空间以匹配源和目标数据集的分布。虽然这些技术也可以应用于深度学习的环境中,但深度神经网络学习的深度特征( DNNs )通常会产生更多可转移的表示(通常在较低层中学习高度可转移的特征,而在较高层中可转移性急剧下降,参见例如 Donahue 等人的这篇论文)。在深度域适配中,我们尝试利用 DNNs 的这一特性。
领域适应类别
以下总结主要基于Wang 等人的这篇综述论文和Wilson 等人的这篇综述。在该工作中,作者根据任务的复杂性、可用的标记/未标记数据的数量以及输入特征空间的差异来区分不同类型的领域适应。他们特别将领域适应定义为一个问题,其中任务空间相同,差异仅在于输入领域发散。基于该定义,域自适应可以是同质的(输入特征空间是相同的,但是具有不同的数据分布)或者异质的(特征空间及其维度可以不同)。
域适配也可以在一个步骤中发生(一步域适配),或者通过多个步骤,在过程中遍历一个或多个域(多步域适配)。在这篇文章中,我们将只讨论一步域适应,因为这是最常见的域适应类型。
根据您从目标领域获得的数据,领域适应可以进一步分为监督的(您确实有来自目标领域的标记数据,尽管这个数量对于训练整个模型来说太小了)、半监督的(您有标记和未标记的数据),以及非监督的(您没有来自目标领域的任何标记数据)。
任务相关性
我们如何确定在源领域中训练的模型是否可以适应我们的目标领域?事实证明,这个问题并不容易回答,任务相关性仍然是一个活跃的研究课题。如果两个任务使用相同的特征进行决策,我们可以将它们定义为相似的。另一种可能性是,如果两个任务的参数向量(即分类边界)接近,则将这两个任务定义为相似的(参见薛等人的本文)。另一方面, Ben-David 等人提出,如果两个任务的数据可以使用一组变换 F 从固定的概率分布中生成,则这两个任务是 F 相关的
尽管有这些理论上的考虑,但在实践中,可能有必要在您自己的数据集上尝试域适应,看看您是否可以通过使用来自源任务的模型来为您的目标任务获得一些好处。通常,任务相关性可以通过简单的推理来确定,例如来自不同视角或不同照明条件的图像,或者在医学领域中,来自不同设备的图像等等。
一步域自适应技术及其应用
一步域适配有三种基本技术:
- 基于散度的域自适应,
- 使用生成模型(GANs)或使用领域混淆损失的基于对抗的领域适应,以及
- 使用堆叠自动编码器(SAE)或 GANs 的基于重构的域自适应。
基于散度的领域适应
基于散度的域自适应通过最小化源和目标数据分布之间的一些散度标准来工作,从而实现域不变特征表示。如果我们找到这样的特征表示,分类器将能够在两个域上同样好地执行。这当然假设这样的表示存在,这又假设任务以某种方式相关。
四种最常用的差异度量是最大平均差异(MMD)相关比对(CORAL)对比域差异 (CCD)和 Wasserstein 度量。
MMD 是一种假设检验,在将两个样本映射到再生核希尔伯特空间(RKHS)后,通过比较特征的平均值来检验这两个样本是否来自同一分布。如果均值不同,分布也可能不同。这通常通过使用内核嵌入技巧和使用高斯内核比较样本来实现。这里的直觉是,如果两个分布是相同的,则来自每个分布的样本之间的平均相似性应该等于来自两个分布的混合样本之间的平均相似性。在域自适应中使用 MMD 的一个示例是 Rozantsev 等人的这篇论文在这篇论文中,使用了双流架构,其权重不共享,但通过使用分类、正则化和域差异(MMD)损失的组合来产生相似的特征表示,如下图所示。
Two-stream architecture by Rozantsev et al.
因此,该设置可以是监督的、半监督的或者甚至是无监督的(在目标域中没有分类损失)。
CORAL ( 链接)类似于 MMD,但是它试图对齐源和目标分布的二阶统计量(相关性),而不是使用线性变换的平均值。Sun 等人的论文通过使用源和目标协方差矩阵之间的 Frobenius 范数构造可微分的 CORAL 损失,在深度学习的上下文中使用 CORAL。
CCD 也是基于 MMD,但也通过查看条件分布来利用标签分布。这确保了联合域特征仍然保持对标签的预测性。最小化 CCD 最小化类内差异,同时最大化类间差异。这需要源和目标域标签。为了摆脱这种约束, Kang 等人提出在联合优化目标标签和特征表示的迭代过程中使用聚类来估计丢失的目标标签。因此,通过聚类找到目标标签,然后最小化 CCD 以适应这些特征。
最后,源和目标域中的特征和标签分布可以通过考虑最优传输问题及其相应的距离,即 Wasserstein 距离来对齐。这是在 DeepJDOT (Damodaran 等人)中提出的。作者建议通过最佳传输来最小化联合深度特征表示和标签之间的差异。
基于对抗的领域适应
这种技术试图通过使用对抗训练来实现领域适应。
一种方法是使用生成对抗网络 (GANs)生成与源域有某种关联的合成目标数据(例如通过保留标签)。这些合成数据然后用于训练目标模型。
CoGAN 模型 试图通过为源和目标分布使用两个生成器/鉴别器对来实现这一点。生成器和鉴别器的一些权重被共享以学习域不变特征空间。以这种方式,可以生成标记的目标数据,其可以进一步用于诸如分类的任务中。
CoGAN architecture by Liu et al.
在另一个装置中, Yoo 等人试图通过使用两个鉴别器来学习源/目标转换器网络:一个用于确保目标数据是真实的,另一个用于保持源和目标域之间的相关性。发生器在此以源数据为条件。这种方法只需要目标域中未标记的数据。
除了用于当前任务的分类损失之外,如果我们使用所谓的域混淆损失,我们还可以完全去除生成器,并且一次执行域适应。域混淆损失类似于 GANs 中的鉴别器,因为它试图匹配源和目标域的分布,以便“混淆”高级分类层。这种网络最著名的例子可能是 Ganin 等人的域对抗神经网络 (DANN)。该网络包括两个损失,分类损失和域混淆损失。它包含一个梯度反转层来匹配特征分布。通过最小化源样本的分类损失和所有样本的域混淆损失(同时最大化特征提取的域混淆损失),这确保了样本对于分类器是相互不可区分的。
Domain-adversarial neural network architecture by Ganin et al.
基于重构的域适应
这种方法使用辅助重建任务来为每个域创建共享表示。例如, 深度重建分类网络【DRCN】试图同时解决这两个任务:(I)源数据的分类,和(ii)未标记目标数据的重建。这确保了网络不仅学会了正确区分,而且还保存了关于目标数据的信息。在该论文中,作者还提到重建管道学习将源图像转换成类似于目标数据集的图像,这表明为两者学习了共同的表示。
The DRCN architecture by Ghifary et al.
另一种可能性是使用所谓的循环杆。Cycle GANs 的灵感来源于机器翻译中双重学习的概念。这个概念同时训练两个相反的语言翻译者(A-B,B-A)。循环中的反馈信号由相应的语言模型和相互 BLEU 分数组成。使用 im2im 框架可以对图像进行同样的处理。在本文的中,从一个图像域到另一个图像域的映射是在不使用任何成对图像样本的情况下学习的。这是通过同时训练分别在两个域中生成图像的两个 gan 来实现的。为了确保一致性,引入了周期一致性损失。这确保了从一个域到另一个域的变换,以及从一个域到另一个域的变换,会产生与输入大致相同的图像。因此,两个配对网络的全部损耗是两个鉴别器的 GAN 损耗和周期一致性损耗的总和。
最后,通过对来自另一个域的图像的输入进行调节,GANs 也可以用于编码器-解码器设置。在 Isola 等人的论文中, 条件 GANs 用于通过在输入端调节鉴别器和发生器的输出,将图像从一个域转换到另一个域。这可以使用简单的编码器-解码器架构或者使用具有跳跃连接的 U-Net 架构来实现。
Several results from the conditional GAN by Isola et al.
结论
深度领域适应允许我们将特定 DNN 在源任务上学习的知识转移到新的相关目标任务。它已成功应用于图像分类或风格转换等任务中。在某种意义上,深度领域适应使我们能够在特定的新计算机视觉任务所需的训练数据量方面更接近人类水平的表现。因此,我认为这一领域的进展对整个计算机视觉领域至关重要,我希望它最终将引领我们在视觉任务中实现有效而简单的知识重用。
深度双重下降:当更多的数据是一件坏事
原文:https://towardsdatascience.com/deep-double-descent-when-more-data-and-bigger-models-are-a-bad-thing-3a3f108d5538?source=collection_archive---------13-----------------------
解决经典统计学和现代 ML 建议之间的根本冲突
Photo by Franki Chamaki on Unsplash
最近偶然看到一篇非常有意思的论文写于 OpenAI,题目是深度双下降。该论文触及了训练机器学习系统和模型复杂性的本质。我希望在这篇文章中以一种可接近的方式总结本文中的观点,并推进对模型大小、数据量和正则化之间权衡的讨论。
问题是
统计学习和现代最大似然理论之间存在着根本的冲突。经典统计学认为太大的模型是不好的。这是因为复杂的模型更容易过度拟合。事实上,经典统计学中经常应用的一个强有力的定理是奥卡姆剃刀,其本质是说 t 最简单的解释通常是正确的。
这可以用一个可视化来清楚地解释。
The green line is an example of a model overfitting the training data, while the black line is a simpler model that approximates the true distribution of the data.
尽管复杂性和可推广性之间存在明显的权衡,但你经常会看到现代 ML 理论认为更大的模型更好。有趣的是,这种说法在很大程度上似乎奏效了。来自世界上一些顶级人工智能研究团队的研究,包括来自谷歌和微软的团队,表明更深层次的模型尚未饱和。事实上,通过实施仔细的正则化和早期停止,似乎通常情况下,将您的模型的性能提高几个点的最佳方法是简单地添加更多的层或收集更多的训练数据。
深度双重下降
OpenAI 论文的焦点提供了经典统计学和现代 ML 理论之间的矛盾的实际调查。
Empirical evidence shows that the truth of how modern machine learning systems work is a mixture of both classical statistics and modern theory.
深度双下降是指性能提高,然后随着模型开始过度拟合而变得更差,最后随着模型大小、数据大小或训练时间的增加而进一步提高的现象。上图以图形方式说明了这种行为。
深度双下降现象在模型的复杂性、数据量和训练时间方面有多种含义。
有时,更大的型号更糟糕
Before the model hits the interpretation threshold, there is a bias-variance tradeoff. Afterwards, the current wisdom of “Larger models are better” is applicable
在对 ResNet18 进行实验时,OpenAI 的研究人员发现了一个关于偏差和方差之间权衡的有趣笔记。在模型的复杂性超过插值阈值之前,或者模型刚好大到足以适合训练集的点之前,较大的模型具有较高的测试误差。然而,在模型的复杂性允许它适合整个训练集之后,具有更多数据的更大模型开始表现得更好。
似乎有一个复杂的区域,在那里模型更容易过度拟合,但是如果在模型中捕捉到足够的复杂性,模型越大越好。
有时,样本越多越糟糕
There’s a point where models with more data actually perform worse on the test set. Again, however, there is a point near the interpolation threshold at which this reverses.
有趣的是,对于低于插值阈值的模型,似乎更多的训练数据实际上会在测试集上产生更差的性能。然而,随着模型变得更加复杂,这种权衡发生了逆转,现代智慧“数据越多越好”开始再次适用。
一个有效的假设是,不太复杂的模型可能无法捕获太大训练集中所需的一切,因此无法很好地推广到看不见的数据。然而,随着模型变得足够复杂,它能够克服这个限制。
有时,训练时间越长,过度适应就会消失
在上面关于被训练的时期数的图表中,训练和测试误差首先随着时期数的增加而急剧下降。最终,随着模型开始过度拟合,测试误差开始增加。最后,随着过度拟合奇迹般地被消除,测试误差再次减小。
在论文中,研究人员称之为划时代的双重下降。他们还注意到,测试误差的峰值正好在插值阈值处。这里的直觉是,如果一个模型不是非常复杂,那么只有一个模型最适合训练数据。如果模型符合噪声数据,其性能将大幅下降。但是,如果模型复杂到足以通过插值阈值,则有几个模型适合训练集和测试集,并且随着训练时间的延长,可以近似这些模型中的一个。发生这种情况的原因是一个公开的研究问题,并且对训练深度神经网络的未来非常重要。
如果你对这个研究问题感兴趣,看看启发了这篇文章的论文和相关总结。
CNN 内心深处:是不是听起来太复杂了?让我们用热图来观察体重吧!
原文:https://towardsdatascience.com/deep-down-in-cnn-does-it-sound-too-complicated-lets-observe-weights-with-a-heatmap-ef666b4954f2?source=collection_archive---------14-----------------------
Source: Freepik
大家好!
我们都使用一些深度学习工具为我们的项目创建应用程序。因为在我们的时代,构建计算机视觉应用非常容易,不像过去的时代,有时这些工具会阻止我们学习算法的工作机制。
我们相信理解它如何工作的最好方法,就是在它工作的时候观察它!
因此,我们将实验 CNN 如何工作,以及它如何使用热图进行分类。这将使我们更好地理解神经网络中使用的卷积,以及权重在我们算法中的重要性。
在这个例子中,我们将遵循 Fastai DL-1 课程中的说明。多亏了他们的 让神经网络再次变得不酷 !
帖子的上下文:
- 选择数据集
- 探索性数据分析和数据扩充
- 创建模型和学习者
- 培训
- 使用热图分析结果
1。选择数据集
当尝试新事物时,最好的方法是使用预清洗数据集。因为我们不想在为模型清理和准备数据时失去动力。寻找高质量数据集以尝试新事物的最佳地点是!
在这个例子中,我使用了一个名为 植物幼苗分类 的图像分类数据集。我想简单解释一下我为什么选择这个数据集;因为这是一个平衡的分类问题,而且竞赛的目的也适合我的算法。
在这次比赛中,我们被要求创建一个模型,成功地完成属于 12 个不同物种的图像的分类任务。该数据集包含 960 幅图像。
Images from different species in the dataset.
我选择这个数据集的另一个原因是,对我来说,从这些图像中分类植物类型似乎是一项艰巨的任务。它们看起来非常熟悉,而且有着相同的背景(土壤),我认为这种算法不会真正成功地识别植物类别。我真的很想知道卷积在这个特定问题中是如何工作的。
2。探索性数据分析和数据扩充
在决定库、架构和其他项目需求之前,最重要的步骤是探索数据集。虽然 Kaggle 竞争数据集确实准备充分,但作为一名数据科学家,在创建解决方案之前,您始终需要首先了解问题。
*tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)
data = ImageDataBunch.from_folder(
path = path,
valid_pct = 0.2,
bs = 16,
size = 224,
ds_tfms = tfms,
).normalize(imagenet_stats)
data
print(data.classes)
data.show_batch()*
因此,在观察了来自我们数据集的图像后,我准备了一个数据模型用于训练。在这里,我想简单解释一下我在这篇代码博客中所做的事情:
- 首先,我决定了数据增强规格。我应用了垂直翻转和一些扭曲来增强图像。另外,由于一些图像比较暗,而且有微小的植物,我使用了一些灯光效果和缩放。
- 为了观察我的训练,我留出了 20%的数据集作为验证。
- 我在这个任务中使用了迁移学习,所以用 imagenet 统计数据对图像进行了标准化。也像原始 imagenet 数据集一样调整它们的大小。
3。创建模型和学习者
Fastai 是一个非常棒的深度学习库,具有易于使用和理解的特点。在这个实验中,我使用了一个 CNN 学习器来训练我的模型。所以我们在图书馆有一个很棒的功能叫做 cnn_learner() 。但我们不仅仅是复制和粘贴代码的工具用户;我们想深入了解桥下到底发生了什么。我们的库中还有另一个名为 doc() 的函数。那么让我们用它来理解 cnn_learner()函数:
*doc(cnn_learner)Result:cnn_learner(**data**:[DataBunch](https://docs.fast.ai/basic_data.html#DataBunch), **base_arch**:Callable, **cut**:Union[int, Callable]=***None***, **pretrained**:bool=***True***, **lin_ftrs**:Optional[Collection[int]]=***None***, **ps**:Floats=***0.5***, **custom_head**:Optional[[Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module)]=***None***, **split_on**:Union[Callable, Collection[ModuleList], NoneType]=***None***, **bn_final**:bool=***False***, **init**=***'kaiming_normal_'***, **concat_pool**:bool=***True***, ********kwargs**:Any)*
所以现在我们可以研究这个函数中的每个变量了!
之后,我们可以创建我们的学习者。在这个问题中,我并不关注准确性。我想要一个好的结果,但不会花太多时间进行微调和其他步骤。我选择了一个预先训练好的模型,它是 resnet34。该模型有 34 层,在 imagenet 数据集上进行训练。由于我的任务中有植物,我相信结果对我来说足够了。
让我们创建学习者:
*learn = cnn_learner(data, models.resnet34, metrics=accuracy)*
4.培养
我们准备了模型和学习者。现在是决定学习速度的时候了。为此,我们将使用另一个强大的函数:
*learn.recorder.plot()*
Learning rate plot.
让我们来训练这个模型:
*lr = 0.01
learn.fit_one_cycle(5, slice(lr))*
Training result.
我们有 93%的准确率,这对我来说足够了。如果我参加这次比赛,我会使用一个更复杂的架构,并进行微调,还会进行一些数据预处理,但因为我们专注于了解正在发生的事情,所以这个结果已经足够了。
5。使用热图分析结果
为了准备热图函数,我们使用了另一个很棒的 Fastai 规范。在库中,我们有回调和钩子库,用它们我们可以研究训练,如反向传播,并对它们进行评估。
*def show_heatmap(hm):
_,ax = plt.subplots()
xb_im.show(ax)
ax.imshow(hm, alpha=0.6, extent=(0,224,224,0),
interpolation='bilinear', cmap='magma')*
我使用 0.6 alpha 值和 magma 方法为我们的 224–224 像素大小的图像创建了热图函数。让我们在一张图片上试试:
*show_heatmap(avg_acts)*
Heatmap on an example image.
结果比我想的要好。图像左上方的土壤对结果几乎没有影响。这很好,因为在那个区域没有植物的任何部分。此外,我们可以清楚地看到,植物的中心对结果的影响最大。之后,位于图像右上方和左下方的植物外部对结果有很大影响。
热图是了解卷积函数内部情况的绝佳可视化工具。我们可以将它们应用到其他研究领域。
这篇文章旨在用一种有趣的方法来解释卷积中的权重。我会继续写其他的例子。请和我分享你的想法!
分类变量的深度嵌入(Cat2Vec)
原文:https://towardsdatascience.com/deep-embeddings-for-categorical-variables-cat2vec-b05c8ab63ac0?source=collection_archive---------3-----------------------
对表格数据使用深度学习
在这篇博客中,我将带你了解在 keras 上使用深度学习网络创建分类变量嵌入的步骤。这个概念最初是由杰瑞米·霍华德在他的 fastai 课程中提出的。更多详情请看链接。
传统嵌入
在我们使用的大多数数据源中,我们会遇到两种主要类型的变量:
- 连续变量:通常是整数或十进制数,有无限多的可能值,如计算机存储单元,如 1GB、2GB 等..
- 分类变量:这些是离散变量,用于根据某些特征分割数据。例如计算机存储器的类型,即 RAM 存储器、内部硬盘、外部硬盘等。
当我们建立一个最大似然模型的时候,在我们能够在算法中使用它之前,我们需要转换分类变量。所应用的转换对模型的性能有很大的影响,尤其是当数据具有大量高基数的分类要素时。应用的一些常见转换示例包括:
One-Hot encoding: 这里我们将每个类别值转换成一个新列,并为该列分配一个1
或0
(True/False)值。
二进制编码:这创建了比一个热点更少的特性,同时保留了列中值的一些唯一性。它可以很好地处理高维有序数据。
然而,这些通常的变换并不能捕捉分类变量之间的关系。有关不同类型的编码方法的更多信息,请参见以下链接。
数据
为了演示深度嵌入的应用,让我们以 Kaggle 的自行车共享数据为例。这里的也链接到 git 回购。
Data — Bike Sharing
正如我们所看到的,数据集中有许多列。为了演示这个概念,我们将只使用来自数据的 date_dt、cnt 和 mnth 列。
Selected Columns
传统的一键编码会产生 12 列,每个月一列。然而,在这种类型的嵌入中,一周中的每一天都具有同等的重要性,并且每个月之间没有关系。
One hot encoding of the mnth column
我们可以在下图中看到每个月的季节性模式。正如我们所见,第 4 到 9 个月是高峰期。0 月、1 月、10 月和 11 月是自行车租赁需求较低的月份。
Monthly Seasonality
此外,当我们用不同的颜色表示每个月的日使用量时,我们可以看到每个月内的一些周模式。
Daily usage trends
理想情况下,我们期望通过使用嵌入来捕获这种关系。在下一节中,我们将使用构建在 keras 之上的深层网络来研究这些嵌入的生成。
深度编码
代码如下所示。我们将建立一个具有密集层网络和“relu”激活功能的感知器网络。
网络的输入,即' x '变量是月份号。这是一年中每个月的数字表示,范围从 0 到 11。因此,input_dim 被设置为 12。
网络的输出,即' y '是' cnt '的缩放列。然而,可以增加“y”以包括其他连续变量。这里我们使用一个连续变量,我们将输出密集层的最后一个数字设置为 1。我们将为 50 个迭代或时期训练模型。
embedding_size = 3model = models.Sequential()
model.add(Embedding(input_dim = 12, output_dim = embedding_size, input_length = 1, name="embedding"))
model.add(Flatten())
model.add(Dense(50, activation="relu"))
model.add(Dense(15, activation="relu"))
model.add(Dense(1))
model.compile(loss = "mse", optimizer = "adam", metrics=["accuracy"])
model.fit(x = data_small_df['mnth'].as_matrix(), y=data_small_df['cnt_Scaled'].as_matrix() , epochs = 50, batch_size = 4)
网络参数
Model Summary
嵌入层:我们在这里指定分类变量的嵌入大小。在本例中,我使用了3****,如果我们增加这个值,它将捕获分类变量之间关系的更多细节。杰瑞米·霍华德建议采用以下方法来选择嵌入尺寸:
# m is the no of categories per featureembedding_size = min(50, m+1/ 2)
我们使用一个具有均方误差损失函数的“adam”优化器。Adam 优于 sgd(随机梯度下降),因为它的自适应学习速率更快更优化。你可以在这里找到关于不同类型优化器的更多细节。
结果
每个月的最终嵌入结果如下。这里“0”代表一月,“11”代表十二月。
Embedding Table
当我们用一个 3D 图将它可视化时,我们可以清楚地看到月份之间的关系。具有相似“计数”的月份更接近地分组在一起,例如,第 4 个月到第 9 个月彼此非常相似。
Embeddings — Months of the year
结论
总之,我们已经看到,通过使用 Cat2Vec(类别变量到向量),我们可以使用低维嵌入来表示高基数类别变量,同时保留每个类别之间的关系。
在接下来的几篇博客中,我们将探讨如何使用这些嵌入来构建具有更好性能的监督和非监督机器学习模型。
Python 中基于深度 CNN 的图像质量盲预测器
原文:https://towardsdatascience.com/deep-image-quality-assessment-with-tensorflow-2-0-69ed8c32f195?source=collection_archive---------10-----------------------
介绍
在本教程中,我们将实现 Jongio Kim、Anh-Duc Nguyen 和 Sanghoon Lee [1]提出的基于深度 CNN 的盲图像质量预测器(DIQA) 方法。此外,我将介绍以下 TensorFlow 2.0 概念:
- 使用 tf.data.Dataset 构建器下载并准备数据集。
- 使用 tf.data API 定义一个 TensorFlow 输入管道来预处理数据集记录。
- 使用 tf.keras 函数 API 创建 CNN 模型。
- 为客观误差图模型定义自定义训练循环。
- 训练客观误差图和主观评分模型。
- 使用训练好的主观评分模型进行预测。
注:部分功能在utils . py中实现,不在本指南讨论范围内。
迪迦是什么?
DIQA 是一项原创提案,专注于解决将深度学习应用于图像质量评估(IQA)的一些最受关注的挑战。相对于其他方法的优势是:
- 该模型不限于专门处理自然场景统计(NSS)图像[1]。
- 通过将训练分为两个阶段(1)特征学习和(2)将学习到的特征映射到主观分数,防止过度拟合。
问题
生成 IQA 数据集的成本很高,因为它需要专家的监督。因此,基本的 IQA 基准仅由几千条记录组成。后者使深度学习模型的创建变得复杂,因为它们需要大量的训练样本来进行归纳。
例如,让我们考虑最频繁使用的数据集来训练和评估 IQA 方法 Live , TID2008 , TID2013 , CSIQ 。下表包含每个数据集的总体摘要:
其中任何一个样本的总量都不超过 4,000 条记录。
资料组
IQA 基准只包含有限数量的记录,可能不足以训练 CNN。然而,出于本指南的目的,我们将使用实时数据集。它由 29 幅参考图像和 5 种不同的失真组成,每种失真有 5 种严重程度。
Fig 1. An example of a reference image in Live dataset.
第一项任务是下载和准备数据集。我为图像质量评估创建了几个 TensorFlow 数据集构建器,并在图像质量包中发布了它们。构建器是由 tensorflow-datasets 定义的接口。
注意:由于数据集的大小(700 兆字节),这个过程可能需要几分钟。
下载并准备好数据后,将构建器转换成数据集,并对其进行洗牌。请注意,批次等于 1。原因是每个图像都有不同的形状。增加批量大小将导致错误。
输出是发电机;因此,使用括号运算符访问样本会导致错误。有两种方法可以访问发生器中的图像。第一种方法是将生成器转换成迭代器,并使用 next 函数提取单个样本。
输出是包含失真图像、参考图像和主观分数(dmos)的张量表示的字典。另一种方法是通过 for 循环从生成器中提取样本:
方法学
图像标准化
DIQA 的第一步是预处理图像。图像被转换成灰度,然后应用低通滤波器。低通滤波器定义为:
其中低频图像是以下算法的结果:
- 模糊灰度图像。
- 将它缩小 1 / 4。
- 把它放大到原来的大小。
这种标准化的主要原因是(1)人类视觉系统(HVS)对低频带的变化不敏感,以及(2)图像失真几乎不影响图像的低频分量。
Fig 2. On the left, the original image. On the right, the image after applying the low-pass filter.
客观误差图
对于第一个模型,使用客观误差作为代理,以利用数据增加的影响。损失函数由预测误差图和地面真实误差图之间的均方误差定义。
而 err( ) 可以是任何误差函数。对于这种实现,作者建议使用
用 p=0.2 。后者是为了防止误差图中的值很小或接近零。
Fig 3. On the left, the original image. In the middle, the pre-processed image, and finally, the image representation of the error map.
可靠性地图
根据作者的说法,该模型很可能无法预测具有同质区域的图像。为了防止它,他们提出了一个可靠性函数。假设模糊区域比纹理区域可靠性低。可靠性函数定义为
其中α控制可靠性图的饱和特性。sigmoid 的正部分用于将足够大的值分配给低亮度的像素。
之前的定义可能会直接影响预测得分。因此,使用平均可靠性图来代替。
对于 Tensorflow 函数,我们只需计算可靠性图,并除以其均值。
Fig 4. On the left, the original image, and on the right, its average reliability map.
损失函数
损失函数被定义为可靠性图和客观误差图之间的乘积的均方误差。误差是预测误差图和地面实况误差图之间的差异。
损失函数要求将误差乘以可靠性图;因此,我们不能使用默认的 loss 实现TF . loss . meansquaerror。
创建自定义损耗后,我们需要告诉 TensorFlow 如何区分它。好的一面是我们可以利用自动微分使用 tf。梯度胶带。
【计算机】优化程序
作者建议使用学习速率为 2e-4 的那达慕优化器。
培养
客观误差模型
对于训练阶段,利用 tf.data 输入管道来生成更清晰易读的代码是很方便的。唯一的要求是创建应用于输入的函数。
然后,将 tf.data.Dataset 映射到 calculate_error_map 函数。
几乎很快就可以应用转换。原因是处理器还没有对数据执行任何操作,它是按需发生的。这个概念通常被称为懒惰评估。
到目前为止,已经实施了以下组件:
- 预处理输入并计算目标的生成器。
- 定制训练循环所需的损失和梯度函数。
- 优化器功能。
唯一缺少的是模型的定义。
Fig 5. The architecture for the objective error map prediction. The red and blue arrows indicate the flows of the first and stage. Source: http://bit.ly/2Ldw4PZ
在上图中,描述了如何:
- 预处理后的图像进入卷积神经网络(CNN)。
- 它用 Relu 激活函数和“相同”填充进行 8 次卷积变换。这被定义为 f()。
- f()的输出通过与线性激活函数的最后卷积来处理。这被定义为 g()。
对于自定义训练循环,有必要:
- 定义度量标准来衡量模型的性能。
- 计算损耗和梯度。
- 使用优化器更新权重。
- 印刷精度。
注意:使用斯皮尔曼的等级相关系数(SRCC)或皮尔逊的线性相关系数(PLCC)作为准确性指标是一个好主意。
主观评分模型
为了创建主观评分模型,让我们使用 f()的输出来训练回归变量。
使用 tf.keras.Model 的 fit 方法训练模型需要返回两个参数的数据集。第一个是输入,第二个是目标。
然后,拟合主观评分模型。
预言;预测;预告
使用已经训练好的模型进行预测很简单。在模型中使用预测方法即可。
结论
在本文中,我们学习了如何利用 tf.data 模块来创建易于阅读且节省内存的数据管道。此外,我们使用功能性 Keras API 实现了基于深度 CNN 的盲图像质量预测器(DIQA)模型。该模型通过使用 TensorFlow 的自动微分功能的自定义训练循环进行训练。
下一步是找到最大化 PLCC 或 SRCC 准确性度量的超参数,并评估模型相对于其他方法的整体性能。
另一个想法是使用更大的数据集来训练客观误差图模型,并查看最终的整体性能。
Jupyter 笔记本
更新 2020/04/15: 包图像质量和笔记本更新修复了 LiveIQA 和 Tid2013 TensorFlow 数据集的一个问题。现在一切正常,检查一下!
[## o import/图像质量
Image quality 是一个用于自动图像质量评估(IQA)的开源软件库。该包是公共的…
github.com](https://github.com/ocampor/image-quality.git)
文献学
[1] Kim,j .,Nguyen,A. D .,& Lee,S. (2019)。基于深度 CNN 的图像质量盲预测器。神经网络和学习系统汇刊。https://doi.org/10.1109/TNNLS.2018.2829819
深入到端到端的神经共指模型
原文:https://towardsdatascience.com/deep-into-end-to-end-neural-coreference-model-58c317cfdb83?source=collection_archive---------7-----------------------
Credit to Victor Vasarely
在之前关于端到端神经共指模型的文章中,我们已经看到了结果及其在 chatbot 上的应用。您想更深入地了解模型的工作原理吗?这篇文章将满足你的好奇心。
这篇文章包含了更详细的公式,但是我已经尽力使论文中理论部分的描述更容易理解。Medium 不支持上标、下标或类似 latex 的语法,这给阅读本文带来了一些不便。
在我们开始了解这个模型之前,关于共指的几个概念有助于我们的理解。
1.共指消解研究
一些重要的共指模型被建立起来,如提及对模型和提及排序模型。
1.1 提及对模型
提及对模型是受监督的。根据共指数据集,对名词短语共指进行标注。该模型提出了一个二元分类器来预测两个名词短语是否相关。然而,就以下问题而言,该模型并不实用。首先,不能保证共指关系中的传递性。然后,对于大多数非共指名词短语,非共指标签的数量远远多于共指标签。因此,带标签的数据集可能具有偏斜的类分布。为了实现该模型,需要特征、训练实例创建方法和聚类算法。
1.2 提及排名模型
给定一个要解决的 NP,提及排序模型考虑最可能的候选先行词。对于每个提及,计算该提及和先行候选项的成对共指得分。将选择得分最高的先行词来匹配该提及。成对共指得分由提及得分和先行得分组成。提及分数意味着表达式被提及的可能性。类似地,先行词得分表明先行候选词是该提及的真实先行词的可能性。机器学习方法从数据集中训练一些标准。这允许我们训练一个提及排序器,而不是对所有候选人的经历进行排序。提及排序模型优于提及对模型。但是,它不能利用集群级别的功能。
Rahman 和 Ng (2009)提出了另一种改进的聚类排序模型。不是仅对候选前因进行排序,而是对前面的聚类进行排序。提及排名模型的一个缺省是只对候选先行词进行排名,所以如果提及实际出现在某些候选先行词之前,非回指 NP 就会被错误解析。这不是我们所期望的。模型本身不能决定提及是否是回指。其他几个决议被提出来识别非照应名词短语。
1.3 最先进的共指消解模型
该论文(Clark 和 Manning,2016a)提出了一种基于神经网络的基于实体的模型,该模型为共指聚类对产生高维向量表示。该系统通过使用从学习到搜索的算法来学习如何使聚类合并,从而提供高分的最终共指划分。因为真实的观察依赖于先前的动作,所以在这种情况下不能支持共同的 i.i.d .假设。学习搜索算法可以通过优化策略分数来解决这个问题。最终结果是 F1 得分的平均值为 65.29%。
在 Clark 和 Manning (2016b)的论文中,通过两种方法优化了提及排名模型,即强化学习和奖励重标度最大利润目标。应用了 Clark 和 Manning (2016a)的论文中描述的相同提及排名模型。代替从学习到搜索的算法,强化学习被提议作为学习算法,以直接针对共指度量来优化模型。最后,使用奖励重标最大间隔目标的模型优于增强算法,也优于 Clark 和 Manning 的先前论文,在英语任务中给出 65.73%。
2.端到端神经共指模型
第一个端到端共指消解模型优于以前的最先进的模型,这些模型使用手动提及检测、语法分析器和大量特征工程。它将所有跨度(即表达式)视为潜在提及,并为每个跨度找出可能的前因。通过结合上下文相关的边界表示和头部寻找注意机制来表示跨度。对于每个跨度,跨度排序模型提供了前一个跨度是一个好的前因的决定。训练一个剪枝函数来消除较少可能的提及。最终模型是具有不同参数的 5 模型集合。与提及排序模型相比,跨度排序模型具有更大的发现提及空间。跨度由单词嵌入来表示。这些表示考虑了两个重要部分:围绕提及区间的上下文和区间内的内部结构。LSTMs 和字符上的一维卷积神经网络(CNN)由向量表示组成。代替通常在共指消解中使用的句法分析器,对每个区间中的词应用了一种寻找中心的注意机制。在学习过程中,黄金聚类中所有正确前件的边际对数似然被优化。在优化目标的过程中,跨度被修剪。设置跨度的长度、要考虑的前提的数量。并且对跨度进行排序,并且仅取那些具有最高提及分数的跨度。
集成模型的最终结果是 68.8%,优于以往的所有论文。现在,更好的结果是通过由粗到细推理的高阶共指消解给出的(Lee 等人,2018)。出于实际考虑,我们实现了端到端模型,而不是最新的模型。
2.1 任务介绍
端到端共指消解是为文档中每个可能的跨度构建的。任务是为每个跨度找出最可能的先行词 yi 。可能的前件集合是一个虚拟前件ε和所有前面的跨度。两种情况导致虚拟先行词ε: (1)跨度不是实体提及或(2)跨度是实体提及,但它不与任何先前的跨度共指。我们假设文档是 D ,它包含 T 个单词以及用于特性的元数据。文档中可能的
跨度数为 N = T(T + 1) / 2 。我们用 START(i) 和 END(i) 、 1≤i≤N 来表示 D 中一个区间 i 的开始和结束索引。
2.2 跨度表示
跨度表示是端到端神经共指模型的核心。强大的跨度表示可以提取提及跨度周围的上下文和跨度内部结构的语义和句法信息。该模型可以根据跨度表示提供的单词相似性来理解单词之间的关系。首先,矢量嵌入是至关重要的。每个单词都有它的向量嵌入。向量表示, {x1,…,xT} ,由固定的预训练单词嵌入(300 维手套嵌入和 50 维图瑞安嵌入)和字符上的 1 维卷积神经网络(CNN)组成。
2.3 双向 LSTMs
单向 LSTMs 只能感知来自过去的信息。但是,以前的词不能提供表达的所有信息或它所指的内容,这将造成歧义。而双向 LSTMs 可以获得过去和未来的信息。这对于共指消解来说是一个很大的优势,因为对单词之间关系的理解很大程度上依赖于周围的上下文。
除了具有两个 lstm 之外,双向 lstm 具有与 lstm 几乎相同的组件。其中一个接受正向序列,而另一个接受反向序列作为输入。该架构如图所示。
Bi-LSTMs — Credit to Colah’s Blog
双向 LSTMs 的每一层都是独立的 LSTMs。而输出是两个输出向量的连接。因此,双向 lstm 的公式不同于 lstm,因为它也取决于方向。我们假设方向由方向指示器δ= {-1,1}表示。
formulas of Bi-LSTMs
2.4 注意机制
句法中心是一段时间内最重要的句法信息,由注意机制检测。在以往的研究中,句法中心被表示为特征。注意机制的基本思想是决定一段时间内最重要的部分,即一段时间内最重要的信息。注意机制的输入是双向 LSTMs 的输出。通过前馈神经网络,向量表示被转化为单词得分 αt 。接下来,每个单词 ai,t 的权重由对齐模型计算,该模型测量该单词在该跨度中的重要性。单词向量的加权和是一个区间的注意机制的最终结果。
formulas of Attention Mechanism
最终的跨度表示是边界表示、软头词向量和特征向量的组合。
formula of the final span representation
2.5 评分和修剪策略
我们提醒,任务是为每个跨度找到最可能的前因。根据由提及分数 sm 和前因分数 sa 组成的成对共指分数 s 对前因候选项进行排序。提及分数暗示了 span 是否是提及。而先行词得分表示 span 是否是先行词。提及得分 sm 和前因得分 sa 都是通过标准的前馈神经网络计算的。
formulas of the scores sm and sa
成对共指分数考虑一对跨度,跨度 i 和跨度 j :
formula of the coreference score
虚拟先行词ε用于两种情况。第一,span 不是一个实体。第二个是跨度是一个实体提及,但它不与任何先前的跨度共指。一旦我们有了共指得分,即输出层,softmax 将决定哪一个先行词更有可能用于区间 i 。
在训练和评估期间,模型不会保留第一步中生成的所有跨度。原因是模型的记忆复杂度高达 O(T4) 。应用修剪策略可以删除不太可能包含在共指聚类中的区间。span 是否会被修剪取决于提及分数 sm 。我们只考虑宽度不超过 10 的跨度,并计算它们的提及分数 sm 。仅保留提及分数最高的 λT 个区间。对于每个跨度,只考虑最多 K 个前件。根据这篇论文,即使我们使用这些积极的剪枝策略,当 λ = 0.4 时,我们仍然保持高提及召回率,超过 92%。
2.6 学习和优化步骤
在学习过程中,gold 聚类所隐含的所有正确前因的边际对数似然性:
formula of the marginal log-likelihood for the learning process
该模型的输出层是一个 softmax,它依赖于成对共指得分。我们将学习一个条件概率分布 P(y1,…,yN|D) ,这意味着这个分布的配置可以找到正确的聚类。对于每个区间,寻找其前因的过程独立于其他区间,我们可以将该分布分解为每个区间的多项式的乘积:
formula of the distribution of the coreference clustering
2.7 模型的架构
现在我们知道这个模型是如何工作的了。至于模型的架构,由两部分组成。一部分是跨度,另一部分是乐谱架构。
The Architecture of Generating Span Representations
拿一句话来说,“通用电气说是邮政联系了公司。”首先,这个句子中的每个单词将被表示为一个向量嵌入,它由一个单词嵌入和一个 CNN 字符嵌入组成。在下一步中,向量嵌入作为双向 LSTMs 的输入,lst ms 为每个单词输出另一个向量嵌入。注意机制将双向 LSTMs 的输出作为其在跨度级的输入,并提供向量嵌入。此外,嵌入特定维度的特征也将在跨度表示中发挥作用。
The Score Architecture
最后,我们利用区间的边界信息、由注意机制生成的表示和特征嵌入来实现区间表示。我们只考虑一定数量的单词来计算提及分数。通过应用修剪策略,我们可以保持一定数量的跨度。
然后我们计算前因得分和共指得分。softmax 输出层将决定为每个跨度选择哪个先行项。
参考资料:
[1]凯文·克拉克和克里斯托弗·曼宁。通过学习实体级分布式表示提高共指消解。计算语言学协会第 54 届年会论文集(第 1 卷:长篇论文),2016。
[2]凯文·克拉克和克里斯托弗·曼宁。提及排序共指模型的深度强化学习。2016 自然语言处理经验方法会议论文集,2016。
[3] Kenton Lee,Luheng He,,和 Luke Zettlemoyer。端到端的神经共指消解。2017 自然语言处理经验方法会议论文集,2017。
我对数据科学、人工智能和区块链方面的商业合作机会感兴趣:
https://www.linkedin.com/in/lingjin2016/
如果你觉得我的文章有用,请用可爱的比特币多鼓励我:
3 ay dni 2 tocphslr 9 pdb 3 hcxkdcuxpdz 4h
感谢阅读和支持!
深度 Java 库(DJL)——面向 Java 开发人员的深度学习工具包
原文:https://towardsdatascience.com/deep-java-library-djl-a-deep-learning-toolkit-for-java-developers-55d5a45bca7e?source=collection_archive---------24-----------------------
现实世界中的数据科学
亚马逊发布深度 Java 库(DJL ),为 Java 开发者提供深度学习的快速入门
Deep Java Library (DJL) ,是亚马逊创建的开源库,用于在 Java 中本地开发机器学习(ML)和深度学习(DL)模型,同时简化深度学习框架的使用。
我最近用 DJL 开发了一个鞋类分类模型,发现这个工具包超级直观和易用;很明显,在设计和 Java 开发人员将如何使用它上花了很多心思。DJL API 抽象出常用的功能来开发模型和编排基础设施管理。我发现用于训练、测试和运行推理的高级 API 允许我使用 Java 和 ML 生命周期的知识,用最少的代码在不到一个小时的时间内开发一个模型。
鞋类分类模型
鞋类分类模型是使用监督学习训练的多类分类计算机视觉(CV)模型,它将鞋类分类为四类标签之一:靴子、凉鞋、鞋子或拖鞋。
Image 1: footwear data (source UT Zappos50K)
关于数据
开发精确的 ML 模型最重要的部分是使用来自可靠来源的数据。鞋类分类模型的数据源是由德克萨斯大学奥斯汀分校提供的数据集,可免费用于学术和非商业用途。鞋子数据集由从Zappos.com收集的 50,025 张带标签的目录图片组成。
训练鞋类分类模型
训练是通过给学习算法训练数据来产生 ML 模型的过程。术语模型是指在训练过程中产生的工件;该模型包含在训练数据中发现的模式,并可用于进行预测(或推断)。在开始培训过程之前,我设置了本地开发环境。你将需要 JDK 8(或更高版本),IntelliJ,一个用于训练的 ML 引擎(像 Apache MXNet ),一个指向你的引擎路径的环境变量和 DJL 的构建依赖。
dependencies **{**compile "org.apache.logging.log4j:log4j-slf4j-impl:2.12.1"compile "ai.djl:api:0.2.0"compile "ai.djl:basicdataset:0.2.0"compile "ai.djl:examples:0.2.0"compile "ai.djl:model-zoo:0.2.0"compile "ai.djl.mxnet:mxnet-model-zoo:0.2.0"runtimeOnly "ai.djl.mxnet:mxnet-native-mkl:1.6.0-a:osx-x86_64"**}**
通过成为引擎和深度学习框架不可知者,DJL 忠于 Java 的座右铭,“编写一次,在任何地方运行(WORA)。开发人员可以编写一次运行在任何引擎上的代码。DJL 目前提供了 Apache MXNet 的实现,这是一个简化深度神经网络开发的 ML 引擎。DJL API 使用 JNA,Java 原生访问,来调用相应的 Apache MXNet 操作。从硬件的角度来看,培训是在我的笔记本电脑上使用 CPU 进行的。然而,为了获得最佳性能,DJL 团队建议使用至少带有一个 GPU 的机器。如果你没有可用的 GPU,总有一个选项可以在亚马逊 EC2 上使用 Apache MXNet。DJL 的一个很好的特性是,它提供了基于硬件配置的自动 CPU/GPU 检测,以始终确保最佳性能。
从源加载数据集
鞋类数据保存在本地,并使用 DJL ImageFolder
数据集加载,该数据集可以从本地文件夹中检索图像。用 DJL 的术语来说,一个Dataset
只是保存训练数据。有些数据集实现可用于下载数据(基于您提供的 URL)、提取数据以及自动将数据分成定型集和验证集。自动分离是一个有用的功能,因为绝不使用训练模型所用的相同数据来验证模型的性能是很重要的。训练验证数据集用于在数据中查找模式;验证数据集用于在训练过程中估计鞋类模型的准确性。
*//identify the location of the training data*String trainingDatasetRoot = **"src/test/resources/imagefolder/train"**;*//identify the location of the validation data*String validateDatasetRoot = **"src/test/resources/imagefolder/validate"**;//create training ImageFolder dataset
ImageFolder trainingDataset = initDataset(trainingDatasetRoot);//create validation ImageFolder dataset
ImageFolder validateDataset = initDataset(validateDatasetRoot);**private** ImageFolder initDataset(String datasetRoot) **throws** IOException { ImageFolder dataset = **new** ImageFolder
.Builder()
.setRepository(**new** SimpleRepository(Paths.get(datasetRoot))).optPipeline( *// create preprocess pipeline* **new** Pipeline()
.add(**new** Resize(NEW_WIDTH, NEW_HEIGHT))
.add(**new** ToTensor()))
.setSampling(BATCH_SIZE,**true**)
.build(); dataset.prepare();
**return** dataset;
}
当在本地构建数据时,我没有深入到 UTZappos50k 数据集确定的最细粒度级别,如脚踝、膝盖高、小腿中部、膝盖以上等。靴子的分类标签。我的本地数据保存在最高级别的分类中,只包括靴子、凉鞋、鞋子和拖鞋。
Image 2: structure of local training data
训练模型
现在,我已经将鞋类数据分为训练集和验证集,我将使用神经网络来训练模型。
**public** final class **Training** extends **AbstractTraining** { . . . **@Override**
**protected** **void** **train**(Arguments arguments) **throws** IOException {
. . . **try** (Model model = Models.getModel(NUM_OF_OUTPUT,
NEW_HEIGHT, NEW_WIDTH)) { TrainingConfig config = setupTrainingConfig(loss); **try** (Trainer trainer = model.newTrainer(config)) {
trainer.setMetrics(metrics);
trainer.setTrainingListener(**this**);
Shape inputShape = **new** Shape(1, 3, NEW_HEIGHT,
NEW_WIDTH);
*// initialize trainer with proper input shape* trainer.initialize(inputShape); *//find the patterns in data* fit(trainer, trainingDataset,
validateDataset, **"build/logs/training"**); *//set model properties* model.setProperty(**"Epoch"**,
String.valueOf(EPOCHS));
model.setProperty(**"Accuracy"**,
String.format(**"%.2f"**,
getValidationAccuracy())); *//save the model after done training for
//inference later model saved
//as shoeclassifier-0000.params* model.save(Paths.get(modelParamsPath),
modelParamsName); }
}
}
通过将训练数据输入到模块开始训练。用 DJL 的术语来说,Block
是形成神经网络的可组合单元。你可以组合积木(就像乐高积木一样)形成一个复杂的网络。在训练过程的最后,一个Block
代表一个完全训练好的模型。第一步是通过调用Models.getModel(NUM_OF_OUTPUT, NEW_HEIGHT, NEW_WIDTH)
获得一个模型实例。getModel()
方法创建一个空模型,构造神经网络,将神经网络设置到模型上。
*/*
Use a neural network (ResNet-50) to train the model**ResNet-50 is a deep residual network with 50 layers; good for image classification
*/***public class** Models {
**public static** ai.djl.Model getModel(**int** numOfOutput,
**int** height, **int** width)
{
*//create new instance of an empty model* ai.djl.Model model = ai.djl.Model.newInstance(); *//Block is a composable unit that forms a neural network;
//combine them like Lego blocks to form a complex network* Block resNet50 = **new** ResNetV1.Builder()
.setImageShape(**new** Shape(3, height, width))
.setNumLayers(50)
.setOutSize(numOfOutput)
.build(); *//set the neural network to the model* model.setBlock(resNet50);
**return** model; }
}
下一步是通过调用model.newTrainer(config)
方法来设置和配置一个Trainer
。config 对象是通过调用setupTrainingConfig(loss)
方法初始化的,该方法设置训练配置(或超参数)来确定如何训练网络。
**private static** TrainingConfig setupTrainingConfig(Loss loss) {
*// epoch number to change learning rate* **int**[] epoch = {3, 5, 8}; **int**[] steps = Arrays
.stream(epoch)
.map(k -> k * 60000 / BATCH_SIZE).toArray(); *//initialize neural network weights using Xavier initializer* Initializer initializer = **new** XavierInitializer(
XavierInitializer.RandomType.UNIFORM,
XavierInitializer.FactorType.AVG, 2); *//set the learning rate
//adjusts weights of network based on loss* MultiFactorTracker learningRateTracker = LearningRateTracker
.multiFactorTracker()
.setSteps(steps)
.optBaseLearningRate(0.01f)
.optFactor(0.1f)
.optWarmUpBeginLearningRate(1e-3f)
.optWarmUpSteps(500)
.build(); *//set optimization technique
//minimizes loss to produce better and faster results
//Stochastic gradient descent* Optimizer optimizer = Optimizer
.sgd()
.setRescaleGrad(1.0f / BATCH_SIZE)
.setLearningRateTracker(learningRateTracker)
.optMomentum(0.9f)
.optWeightDecays(0.001f)
.optClipGrad(1f)
.build(); **return new** DefaultTrainingConfig(initializer, loss)
.setOptimizer(optimizer)
.addTrainingMetric(**new** Accuracy())
.setBatchSize(BATCH_SIZE);
}
为训练设置了多个超参数:
**newHeight**
和**newWidth**
—图像的形状。**batchSize**
—用于训练的批量;根据你的模型选择合适的尺寸。**numOfOutput**
—标签的数量;鞋类分类有 4 个标签。**loss**
—损失函数根据衡量模型好坏的真实标签评估模型预测。**Initializer**
—标识初始化方法;在这种情况下,Xavier 初始化。**MultiFactorTracker**
—配置学习率选项。**Optimizer**
:最小化损失函数值的优化技术;在这种情况下,随机梯度下降(SGD)。
下一步是设置Metrics
,一个训练监听器,并用正确的输入形状初始化Trainer
。Metrics
在培训期间收集和报告关键绩效指标(KPI ),这些指标可用于分析和监控培训绩效和稳定性。接下来,我通过调用fit(trainer, trainingDataset, validateDataset, **“build/logs/training”**)
方法开始训练过程,该方法迭代训练数据并存储在模型中找到的模式。
**public void** fit(Trainer trainer, Dataset trainingDataset, Dataset validateDataset,String outputDir) **throws** IOException { *// find patterns in data* **for** (**int** epoch = 0; epoch < EPOCHS; epoch++)
{
**for** (Batch batch : trainer.iterateDataset(trainingDataset))
{
trainer.trainBatch(batch);
trainer.step();
batch.close();
}
*//validate patterns found* **if** (validateDataset != **null**) {
**for** (Batch batch:
trainer.iterateDataset(validateDataset)){
trainer.validateBatch(batch);
batch.close();
}
} *//reset training and validation metric at end of epoch* trainer.resetTrainingMetrics(); *//save model at end of each epoch* **if** (outputDir != **null**) {
Model model = trainer.getModel();
model.setProperty(**"Epoch"**, String.valueOf(epoch));
model.save(Paths.get(outputDir), **"resnetv1"**);
}
}
}
在训练的最后,使用model.save(Paths.get(modelParamsPath), modelParamsName)
方法,一个运行良好的经验证的模型工件及其属性被保存在本地。培训过程中报告的指标如下所示。
Image 3: metrics reported during training
运行推理
现在我有了一个模型,我可以用它对我不知道分类(或目标)的新数据进行推断(或预测)。在设置了模型和要分类的图像的必要路径之后,我使用Models.getModel(NUM_OF_OUTPUT, NEW_HEIGHT, NEW_WIDTH)
方法获得一个空的模型实例,并使用model.load(Paths.get(modelParamsPath), modelParamsName)
方法初始化它。这将加载我在上一步中训练的模型。接下来,我使用model.newPredictor(translator)
方法,用指定的Translator
初始化一个Predictor
。你会注意到我将一个Translator
传递给了Predictor
。在 DJL 术语中,Translator
提供模型预处理和后处理功能。例如,对于 CV 模型,需要将图像重塑为灰度;a Translator
可以帮你做到这一点。Predictor
允许我使用predictor.predict(img)
方法对加载的Model
进行推理,传入图像进行分类。我做的是单个预测,但是 DJL 也支持批量预测。推理存储在predictResult
中,其中包含每个标签的概率估计。一旦推理完成,模型自动关闭,使得 DJL 记忆有效。
**private** Classifications predict() **throws** IOException, ModelException, TranslateException {
*//the location to the model saved during training* String modelParamsPath = **"build/logs"**; *//the name of the model set during training* String modelParamsName = **"shoeclassifier"**; *//the path of image to classify* String imageFilePath = **"src/test/resources/slippers.jpg"**; *//Load the image file from the path* BufferedImage img =
BufferedImageUtils.fromFile(Paths.get(imageFilePath)); *//holds the probability score per label* Classifications predictResult; **try** (Model model = Models.getModel(NUM_OF_OUTPUT, NEW_HEIGHT, NEW_WIDTH)) { *//load the model* model.load(Paths.get(modelParamsPath), modelParamsName); *//define a translator for pre and post processing* Translator<BufferedImage, Classifications> translator =
**new** MyTranslator(); *//run the inference using a Predictor* **try** (Predictor<BufferedImage, Classifications> predictor =
model.newPredictor(translator)) {
predictResult = predictor.predict(img);
}
} **return** predictResult;
}
推论(每张图片)及其相应的概率得分如下所示。
Image 4: Inference for boots
Image 5: Inference for sandals
Image 6: Inference for shoes
Image 7: Inference for slippers
外卖和后续步骤
我从 90 年代末开始开发基于 Java 的应用程序,并在 2017 年开始了我的机器学习之旅。如果当时 DJL 在的话,我的旅程会容易得多。我强烈建议希望过渡到机器学习的 Java 开发人员给 DJL 一个机会。在我的例子中,我从头开始开发了鞋类分类模型;然而,DJL 也允许开发人员以最小的努力部署预先训练好的模型。DJL 还提供了现成的流行数据集,允许开发人员立即开始使用 ML。在开始学习 DJL 之前,我建议你对 ML 生命周期有一个牢固的理解,并且熟悉常见的 ML 术语。一旦你对 ML 有了一个基本的理解,你就可以很快熟悉 DJL API。
亚马逊有开源的 DJL,在那里可以在 DJL 网站和 Java 库 API 规范页面找到关于该工具包的更多详细信息。鞋类分类模型的代码可以在 GitLab 上找到。祝您的 ML 之旅好运,如果您有任何问题,请随时联系我。
深层潜在变量模型:揭示隐藏结构
原文:https://towardsdatascience.com/deep-latent-variable-models-unravel-hidden-structures-a5df0fd32ae2?source=collection_archive---------7-----------------------
source: Unsplash
理解真实世界数据的底层结构是机器学习中最引人注目的任务之一。但是随着深度生成模型的出现,研究者和实践者有了一个强有力的方法来解开它。
真实世界的数据通常是复杂和高维的。传统的数据分析方法在大多数情况下是无效的,并且只能模拟非常简单的数据分布。现在,我们可以使用机器学习模型来直接学习我们数据的结构。机器学习中最常见的方法是监督学习 ,其中我们要求模型学习从输入到输出变量的映射,例如图像 x 到标签 y。然而,带标签的数据是昂贵的,并且容易被人类注释者产生错误或偏见。并且监督模型仅能够根据训练数据的质量来概括其映射函数。为了测试其推广性,使用了来自相同分布的验证集,该验证集将具有相同的误差。使用这种模型,可以执行分类或回归任务,但我们无法了解数据的实际基本组织。
机器学习社区开始关注 无监督学习 模型的开发。通过结合概率建模和深度学习,最近取得了一些进展。我们称这类模型为 生成型模型 。根据这句名言,
"我不能创造的东西,我不明白。"—理查德·费曼
生成模型应该能够发现底层结构,例如数据的有趣模式、聚类、统计相关性和因果结构,并生成类似的数据。
目前,该领域中的一个著名模型是生成式广告网络(GANs)【1】,例如,它能够从学习到的数据分布中生成人脸的真实图像。这一类的另一个模型被称为变分自动编码器(VAE)【2】,它也用于复杂高维分布的无监督学习,将是本文的重点。甘的训练仍然是实验性的,因为他们的训练过程缓慢且不稳定。但是他们也在进步,请看这篇关于 Wasserstein GANs 的博客文章。
一般来说,非监督学习比监督学习困难得多,因为这些模型不是预测给定输入的标签或值,而是学习数据分布本身的隐藏结构。本文将介绍我们如何实现这一点的概念,重点是静态数据,如没有序列性质的图像。学习顺序数据的底层结构是一个更困难的问题,我打算将来写一篇关于这个问题的后续文章。
在第一部分中,我们将定义潜在变量模型,在第二部分中,我们将了解如何使用深度神经网络来学习它们的参数。我试图尽可能保持一切直观,但一些概率论和深度学习的先验知识肯定是有帮助的。
潜在变量模型
机器学习中的一个中心问题就是学习一个复杂的概率分布p(x),只需要从这个分布中抽取有限的一组高维数据点 x 。例如,为了学习猫的图像的概率分布,我们需要定义一个分布,该分布可以模拟形成每个图像的所有像素之间的复杂相关性。直接模拟这种分布是一项具有挑战性的任务,甚至在有限的时间内是不可行的。
与其直接建模p(x),我们可以引入一个不可观测的潜在变量 z 并为数据定义一个条件分布p(x|z,这就叫做可能性用概率术语 z 可以解释为连续的随机变量。对于猫图像的例子, z 可以包含猫的类型、颜色或形状的隐藏表示。
有了 z ,我们可以进一步引入潜在变量的先验分布p(z)来计算观察变量和潜在变量的联合分布:
Joint distribution over observed and latent variables; Equation (1)
这种联合分布让我们可以用更易处理的方式来表达复杂的分布p(x)。其组成部分,p(x|z)和p(z)的定义通常要简单得多,例如通过使用中的分布
为了获得数据分布p(x)我们需要对潜在变量进行边缘化
Marginalized data distribution p(x); Equation (2)
此外,利用贝叶斯定理我们可以计算后验分布p(z|x)为
Posterior distribution p(z|x); Equation (3)
后验分布允许我们推断给定观测值的潜在变量。注意,对于我们处理的大多数数据,方程(2)中的积分没有解析解,我们必须应用某种方法来推断方程(3)中的后验概率,这将在下面解释。
为什么我们要做这个练习并引入一个潜在变量?优势在于,具有潜在变量的模型可以表达数据被创建的生成过程(至少这是我们的希望)。这被称为生成模型。一般来说,这意味着如果我们想要生成一个新的数据点,我们首先需要获得一个样本【z】~p(z),然后使用它从条件分布x|中采样一个新的观察值在这样做的同时,我们还可以评估该模型是否为数据分布p()x)提供了良好的近似。******
根据定义,包含潜在变量的数学模型是潜在变量模型。这些潜在变量的维数比观察到的输入向量低得多。这产生了数据的压缩表示。您可以将潜在变量视为一个瓶颈,生成数据所需的所有信息都必须通过这个瓶颈。从 流形假设 中我们知道,高维数据(例如真实世界的数据)位于嵌入在这个高维空间中的低维流形上。这证明了低维潜在空间的合理性。
后验推断
后验分布p(z|x),是概率推理中的一个关键组成部分,在观察到一个新的数据点后,更新我们对潜在变量的信念。然而,真实世界数据的后验常常是难以处理的,因为它们对于出现在方程(3)分母中的方程(2)中的积分没有解析解。有两种方法可以近似这种分布。一种是叫做 马尔可夫链蒙特卡罗方法的抽样技术。然而,这些方法在计算上是昂贵的,并且不能很好地扩展到大型数据集。第二种方法是确定性近似技术。在这些技术中,VAE 使用的是所谓的(VI)【4】。注意,这种方法的缺点是,即使在无限的计算时间内,它们也不能产生精确的结果。
VI 的总体思路是从一个易处理的分布族(例如多元高斯)中取一个近似值q(z),然后使这个近似值尽可能接近真实的后验p(z|x)。这通常通过最小化两个分布之间的 Kullback-Leibler (KL)散度来实现,定义为**
Kullback-Leibler Divergence; Equation (4)
这减少了对优化问题的推断[5]。越相似的q()p(z|x)KL 的散度越小。请注意,这个量不是数学意义上的距离,因为如果我们交换分布,它就不是对称的。此外,在我们的例子中,交换分布意味着我们需要获取关于p(z|x)的期望,这被认为是难以处理的。
现在,方程(4)在对数内的分子中仍然有难以处理的后验概率。使用(3),我们可以将(4)改写为:
****
Evidence Lower Bound (ELBO) F(q); Equation (5)
边际可能性log p(x)可以从期望中取出,因为它不依赖于 z 。量F(q)就是所谓的证据下界 (ELBO)。KL 总是≥ 0,因此它表示对证据日志 p(x)的下限。ELBO 越接近边际似然,变分近似就越接近真实的后验分布。因此,复杂的推理问题被简化为更简单的优化问题。
变分自动编码器
我们还没有提到它,但是可能性和先验属于依赖于一些未知参数的分布族。为了使这一点更清楚,请看等式(1)的参数联合分布:
Parametric joint distribution; Equation (6)
θ表示模型的未知参数,可以使用深度神经网络(或使用传统方法,如 期望最大化 算法)来学习。
VAE 使用这种深度神经网络来参数化定义潜在变量模型的概率分布。此外,它提供了一个有效的近似推理过程,规模大的数据集。它由一个生成模型(潜在变量模型)、一个推理网络(变分近似)和一种如何学习 VAE 参数的方法来定义。关于 VAE 在 Keras 的非常好的介绍和实现,你可以访问这个漂亮的博客帖子。
生成模型由等式(6)给出,这里 z 是具有 K- 维的连续潜变量。它的先验通常是具有零均值和单位协方差矩阵的高斯,
Gaussian prior with zero mean and identity covariance; Equation (7)
这种可能性被称为解码器,它通常是连续数据的高斯分布,其参数θ通过将潜在状态 z 传递通过深度神经网络来计算。这种可能性看起来如下,
Likelihood as continuous Gaussian distribution; Equation (8)
均值和方差由两个深度神经网络参数化,其输出向量的维数为 D ,即观测值的维数xT5。参数θ是解码器神经网络的权重和偏差。****
推理网络被称为编码器,允许我们计算后验近似的参数。变分参数φ在所有数据点上共享,而不是每个数据点都有一组参数。同样,在 VAE 设置中,我们使用深度神经网络,该网络获取输入数据点并输出相应高斯变分近似的均值和对角协方差矩阵,
Posterior approximation of VAE; Equation (9)
共享的变分参数φ是编码器神经网络的权重和偏差。
参数学习和 VAE 的目标函数
如上所述,边际分布p(x)(由θ参数化)在很多情况下是难以处理的,需要近似。使用 ELBO 可以获得一个近似值。为了明确 ELBO 依赖于某个参数,我们可以将它重写为
ELBO parametized by theta; Equation (10)
为了学习参数,我们可以使用期望最大化(EM)使 ELBO 相对于其参数最大化。对于 VAE 设置来说,最大化反而是超过参数φ的 q 。因此,我们可以将 ELBO 分解为两项:
Objective Function. The left term represents the reconstruction loss and the right term represents the regularization loss; Equation (11)
F 的第一项是重构损失,鼓励似然和推理网络准确重构数据。第二项是正则化损失并惩罚与先验相差太远的后验近似。具有参数φ和θ的两个神经网络都可以通过具有反向传播的梯度下降来有效地计算。此外,参数是联合更新的,而不是像 EM 那样迭代更新。
结论
在这篇文章中,我介绍了潜在变量模型的概念,以及用深度神经网络来参数化定义潜在变量模型的概率分布。在这里,我们关注了变分自动编码器(一种生成模型)所使用的对后验分布p(z|x)的近似的变分推断。VAE 的真正力量在于,它们可以在完全无人监督的情况下接受训练,并学习捕捉数据自然特征的潜在空间。
如果我们能够将复杂的高维数据嵌入到一个潜在空间中,从这个潜在空间中我们能够生成与原始数据非常相似的新数据,我们可以假设我们的模型捕捉到了数据的主要特征。这可以给研究人员和从业人员提供许多有用的信息来研究感兴趣的数据,并确定模式、相关性甚至因果结构。
参考
[1] Goodfellow,Ian,et al. “生成性对抗性网络”,NIPS (2014)
[2]迪德里克·p·金马,马克斯·韦林。自动编码变分贝叶斯,arXiv 预印本 arXiv:1312.6114 (2014)。
[3] Martin Arjovsky、Soumith Chintala 和 Léon Bottou。《瓦瑟斯坦甘》,arXiv 预印本 arXiv:1701.07875 (2017)。
[4]戴维·布莱、阿尔普·库库尔比尔、乔恩·麦考利夫。"变分推断:统计学家回顾,arXiv 预印本 arXiv:1601.00670
[5]凯文·p·墨菲,“机器学习:概率观点”,麻省理工学院出版社(2012 年)
关于变分自动编码器的进一步阅读
阿古斯蒂斯·克里斯蒂的博客 : 变分自动编码器:直觉与实现
JAAN ALTOSAAR 博客 : 教程——什么是变分自动编码器?
关于转录因子-DNA 结合的“深度学习”
原文:https://towardsdatascience.com/deep-learning-about-transcription-factor-dna-binding-1d9753eabcc2?source=collection_archive---------9-----------------------
使用卷积神经网络测量转录因子-DNA 结合
如果我们能解开基因表达的秘密,我们就能真正解开自己的秘密。
我们淹没在基因信息中。
Except, imagine the coins as DNA nucleotides.
事实上,你现在就可以花大约 100 美元(如果你再等一段时间,这个价格会更低)去获取你的整个基因组序列。
你可以自己解开背后的密码。每一个特性、特征、不好的突变都是从你的曾曾祖父那里传下来的,但不知何故在你之前跳过了几代人(遗传统计学万岁)。
但是有个问题。
我们连一半是什么意思都不知道。
(一半很可能是高估)。
这就像试图学习一种可以编码生物生命的编码语言。你只知道这些位是四个碱基对:A,C,T,g。
对于所谓的“经典数据”,我们已经进入了一个疯狂兴奋的阶段,试图建立机器学习模型,从中提取模式。现在,如果我们用机器来尝试理解基因组数据会怎么样?
如果我们尝试使用机器学习来解开基因表达的秘密会怎么样?
我们拥有的每一个行为或特征最终都可以归结为某些基因的开启和关闭。基因表达几乎控制着我们身体的一切。我们的细胞执行什么功能。你头发的颜色。它还决定了你何时、如何或是否患有致命疾病。我们可以黑掉我们自己。根除疾病。增进我们的健康。改变我们的特征。
如果基因表达是一部电影,那么转录因子(TF),一种类型的蛋白质,将是导演。哪些基因开启或关闭由与调控元件(启动子、增强子等)结合的转录因子决定。)——这在不同的细胞类型中是不同的。
让我们进一步分析一下。
转录因子- DNA 结合
转录因子直接转录— 将遗传信息从 DNA 复制到信使 RNA 。把信使 RNA 想象成邮差。它将信息(遗传密码)从 DNA 传递到核糖体,以翻译成蛋白质。
Transcription and translation of proteins. Source: Khan Academy
因此,转录因子控制着哪些信息被复制并转化为蛋白质,从而影响细胞的功能或特性。
好吧,酷。但是实际上有成千上万不同的变体。我们如何知道一个组织因子是否会与某个 DNA 序列结合?或者如果另一个 TF 会结合同样的 DNA 序列?或者说TF 与该序列的结合有多好?
等等…不是也有上百种不同的 TF 吗?我们究竟该如何预测呢?猜猜看?
没错。
Excuse me?
但是不要担心,我们从现在开始不会再做猜测和检查……我们会让机器学习来帮我们做这件事 😉
Take a deep breath. The hard stuff is coming soon.
如果我们可以使用机器学习来预测转录因子与特定 DNA 序列结合的可能性有多大呢?
基于过去预测 TF-DNA 相互作用的深度学习尝试,如 DeepSEA,我想看看我是否可以建立自己的算法,该算法可以预测给定转录因子与特定 DNA 序列结合的可能性。然而,我想更进一步,用量化这个值。
如何量化转录因子与 DNA 的结合?“非常好”或“不太好”可能不是最好的标签。
和芯片序列来拯救!
ChIP-seq 代表与下一代测序相结合的染色质免疫沉淀** (ChIP)分析。如果你不知道这意味着什么,这里有一个复习。**
基本上,芯片测序 ( 芯片 - 序列)是识别转录因子和其他蛋白质的全基因组 DNA 结合位点的有力方法。它告诉我们 TF 将结合在 DNA 的什么位置。
Notice the “peaks” or spikes on the graph = lot of gene activity in that area
现在,峰值区域是图上的黑色/彩色部分,本质上意味着在那个特定区域有大量的基因表达。每个峰都有一个信号值(来自该基因组位置的序列读数)。
信号值量化了 TF 与 DNA 的结合程度。
我们能用 ChIP-seq 做什么?
如果我们比较患病和非患病细胞的 ChIP-seq 峰区域,我们可以确定导致或促成该疾病的遗传变异!
我们可以使用它的另一种方式是确定基因表达如何从一种细胞类型变化到另一种细胞类型——这可以给我们一个巨大的洞察力,让我们知道如何区分诱导多能干细胞!
我们将如何使用机器学习?
如果给定一个特定的基因序列,我们可以预测特定转录因子的信号值,会怎么样?
基本上:
输入:原始 DNA 序列(没有关于变体的先验知识)
输出:实值码片序列信号值
机器将通过深度学习来学习这些。
所以今天,我们将应用一个卷积神经网络算法。你已经看到他们擅长图像分类,但现在看到他们擅长基因组数据分析。如果图像只是一个数字矩阵,从技术上来说,基因组数据只是一个 A、T、C 和 Gs 的矩阵。他们擅长模式识别。
深度学习模型概述
首先,原始 DNA 序列被输入到模型中。每个输入序列被转换成一个具有 4 行 300 列的独热矩阵。4 行代表 4 个碱基对(A、C、T、G ),而序列长度为 300 b.p(核苷酸)。
因为 DNA 是双螺旋,TFs 可以识别给定位置的任何一条 DNA 链,所以模型被输入正向序列和反向互补序列。
It would be a more accurate representation if one of the spidermen were flipped upside down.
同样,因为 TFs 可以在给定的位置识别 DNA 的任意一条链,所以两个序列的卷积层共享同一套过滤器。使用 DeFine 提出的体系结构,该体系结构看起来像这样:
The convolutional neural network architecture in DeFine.
- 首先,我们有两个卷积层,它们将自动从数据中提取特征
- 接下来是 ReLU 层,过滤高于阈值的结果(在训练中学习到的)
- 然后,它们同时通过最大池和平均池层。最大池为每个滤波器输出序列中最显著的激活信号,而平均池通过取序列中每个位置的滤波器扫描结果的平均值来考虑整个序列上下文
- 两个输出被组合成一个向量
- 然后经过批量归一化
- 然后是全连接层
- 然后应用删除层(概率为 0.5)——帮助减轻过度拟合
- 又一个最终完全连接的层
- 以及最后的回归层——其预测芯片序列信号强度
现在让我们回到我们如何预处理数据。(我知道,大家最喜欢的关于机器学习的部分)。
数据预处理!
牛逼的ENCODE(DNA 元素百科)项目编译了一个开源的数据库,里面有很多细胞系,各种测序。
他们有几个细胞系有 ChIP-seq 和全基因组测序。我将使用 K562 细胞系(有 79 个转录因子)。整个基因组测序从这里的开始。参考基因组是 GRCh37。注意:模型必须对每个转录因子分别进行训练。
为了准备用于训练的数据,从峰调用结果中提取每个转录因子的峰区域(信号值)。所以现在我们有了显示基因活性的每个区域的 TF 信号值。
- 每个 TF 的前 1%信号值被丢弃(异常值具有极高的信号值)
- 然后对信号值进行对数变换,并通过 0-1 之间的最小-最大标度进行归一化。我们这样做是为了让我们的数字更容易使用!
- 然后,根据峰区域从参考基因组中提取峰的基因组序列
- 通过添加 Ns(代表任何核苷酸)或删除核苷酸,将峰序列固定在 300 bp(然后我们可以将其输入到我们的模型中)
最后,为了帮助数据扩充,我们做最后一步:
- 从与已知 TF 没有结合的区域中随机取出序列,并将它们的信号值设置为零****
- 具有零值的随机选择序列的数量应该等于具有信号强度值的码片序列峰值序列的数量
最后,数据分成 70%用于训练,15%用于验证和调整超参数,15%用于测试。
评估准确性
对于这个模型,一个简单的百分比精度是不够的。我们将引入一些统计相关性测量!
该模型将基于皮尔逊相关系数和斯皮尔曼相关系数进行评估。它们都衡量两个数字是如何相互关联的。相关性越高=两者关系越强! 这里有一个链接快速回顾这两个术语。
你刚刚“深度学习”了如何预测转录因子-DNA 结合!
简单回顾一下…
- 基因表达控制着我们身体里发生的一切
- 基因表达受转录因子结合调节元件(DNA)** 的调节**
- 深度学习可以帮助我们预测转录因子与 DNA** 结合的可能性——通过**预测芯片序列强度值****
- 比较 ChIP-seq 值(或总的来说 TFs 与 DNA 的结合亲和力)可以帮助我们了解导致疾病的不同变体,帮助我们了解干细胞分化,并总的来说教会我们更多关于基因表达的知识!****
这个项目背后的代码将很快发布在我的 GitHub 上,敬请关注!
有什么问题吗?
如果您有任何问题,请随时联系:
- 电子邮件:gracelyn@gracelynshi.com
- **领英:【https://www.linkedin.com/in/gracelynshi/ **
- **推特:【https://twitter.com/GracelynShi **
- 网站:gracelynshi.com
来源
[1] M. Wang,C. Tai,L. Wei,定义:深度卷积神经网络精确量化转录因子-DNA 结合的强度,并促进功能性非编码变体的评估(2018)
动态跨网格深度学习—第 1 部分:无人机
原文:https://towardsdatascience.com/deep-learning-across-mesh-on-the-fly-part-1-the-drones-8bf3d7c9b4f?source=collection_archive---------21-----------------------
深度学习无人机
AI 会飞会怎么样?
L et 创造了一个微型无人机群,它利用人工智能和网状网络来模仿自然界中常见的群体行为。
坚持住!不要走!听我说完这个概念。通过利用这些时髦的技术,我们可以创造出非常酷,而且我敢说,非常有用的东西?
当然,小型无人机有可怕的飞行时间(以及其他事情),是的,微处理器可能不是人工智能处理的最佳解决方案。然而,如果我们保持项目的小范围,那么我们可能能够完成它。比如用装有传感器阵列的多架四轴飞行器在室内环境中模仿群体行为。
还觉得我满口胡言吗?如果我告诉你我已经造出了第一个原型呢?
让我们开始吧!
无人机是怎么做出来的?
当开始任何需要硬件的项目时,你应该做的第一件事就是确定你想要使用什么组件。
在这种情况下,我选择使用 PCB 作为四轴飞行器的底座。这将最大限度地减少项目所需的零件数量。它还可以让我快速原型化各种设计并做出改变,而不必制作多个零件。
四轴飞行器的上述底座尺寸为 100 毫米乘 100 毫米。它被印刷在一个两层的 PCB 上,包含了让四轴飞行器飞行所需的一切!
是时候决定飞行控制器、惯性测量单元以及如何控制马达了。
对于我的概念无人机,我选择了 ESP32 作为主飞行控制器。我选择 ESP32 是因为它的多功能性、多核、大量 PWM 引脚(用于控制螺旋桨速度的脉宽调制)和网状网络功能。ESP32 还可以针对最低功耗进行优化,同时为给定任务提供足够的功率。
如果您还没有使用过 ESP32 模块,那您就错过了。
对于我的惯性测量单元,我选择了 MPU6050 。MPU6050 是一个六轴陀螺仪和加速度计 IC 。MPU6050 非常适合确定无人机的俯仰、偏航、滚动和加速度。该芯片还通过一个双线接口(不能说是 I2C,因为它是有商标的),并且非常容易从 ESP32 访问。
最后,我们需要一个电压调节器和电机电路。
稳压器是德州仪器的超低压差稳压器,具体来说就是 TLV117LV33DCYR (Yikes!那是一个很长的数字)。
对于电机控制器,我采用二极管/MOSFET/电阻设置。我还附加了一个 100uf 电容用于平滑。
- 二极管:621–1n 5819 HW-F
- 电容器: 581-F980J107MSA
- MOSFET: 781-SI2302CDS-E3
- 电阻器:1K 电阻器
Circuit diagram for the drone’s motors
上面的配置是最佳的,因为它允许 ESP32(3.3V 芯片)控制从电池接收全部 3.7V 电压的电机。电容器将有助于防止电池上的过电流保护由于突然的电流尖峰而触发。这些电流尖峰通常会在电机首次启动时或速度急剧上升时出现。
示意图,示意图,示意图!
零件清单做好了,无人机的基本概念也有了,是时候开始组装了!
我首先关注的是将 ESP32 连接到 MPU6050 和电机。由于许多在线参考,MPU6050 相当容易连接。然而,我犯了一个致命的错误,阻止了 ESP32 与 MPU6050 的通信-..我在 3.3V 线上使用了 10K 上拉电阻。这导致线路低于信号阈值,被视为高电平,ESP32 无法与我的概念无人机上的 MPU6050 通信。我已经修复了错误,并使用 2.2K 电阻代替,但它引起了一个主要问题,我们将在稍后讨论。
这是飞行控制器的示意图:
很酷,对吧?这是无人机最复杂的部分(到目前为止)。
在我完成了飞行控制器之后,我开始研究电源电路。它只是连接到输入线路的 3.3V 超低压差稳压器和两个 0.1uF 电容。
然后是电机控制器。
最后,连接到四轴飞行器每个臂上的发光二极管。
所有这些电路不可避免地成为第一个概念四轴飞行器。
有趣的部分是设计四轴飞行器本身和路由所有的组件。
Slimmed-down version of the 100x100mm drone to reduce weight
组装无人机
无人机完成后,一切都被送去生产,并在两周内回来。我花了大约 40 美元买了一架无人机(不是很好,但也不可怕)。
Baby steps…..
经过一个漫长的夜晚焊接所有的东西,一次测试一个转子,我让一切正常工作!MPU6050 除外..力量..稳定性到此为止了吧。
即使没有工作的 MPU6050 -..我能够让所有四个马达都运转起来,并动态调整速度,看看无人机是否能离开地面。
下面是我使用的测试代码。
超级简单的代码片段。在这里,我只是配置所需的引脚使用 PWM,然后慢慢调整功率输出,直到电池因过流保护而断电。
这是因为我使用了锂离子电池,而不是锂聚合物。锂聚合物电池通常比锂离子轻得多,可以输出更大的电流。虽然它们更轻,但锂电池的外壳通常也更厚。
第一次飞行
在充满期待之后,我上传了测试代码,并检查了无人机是否会飞。
First…flight?
剧透警报:它没飞起来。
还记得我之前提到的 MPU6050 的问题吗?没有稳定,我们不会走得很远。
我们在这里学到了什么?这些四轴飞行器太重了,飞行控制器需要一个合适的控制回路来稳定自身和悬停。
无人机的下一次迭代将被印刷在更薄更小的 PCB 上,我将使用锂电池代替。这将允许四轴飞行器利用发动机的全油门,获得相当大的升力。与此同时,我将创建一个更合适的控制环路,它可以与 MPU6050 接口,并调整四轴飞行器的俯仰、偏航和滚动,以保持稳定。
所有这些修复将允许建立一个工作的四轴飞行器,并让我继续这个项目的深度学习和网状网络方面。
深度学习和群体行为
我知道,我知道,我没有在这篇文章中详细介绍这个项目的深度学习方面。
那只是因为我还没有走到那一步。这是一个多次迭代的项目,因此,我们必须从小处着手,逐步推进。
我概述的当前步骤是:
- 原型一个能飞的 PCB 微型无人机
- 将网状网络与无人机上的 ESP32 模块结合在一起
- 创造第二代带距离传感器的微型无人机
- 训练神经网络以允许在模拟环境中的群体行为
- 将经过训练的模型应用于微型无人机
这将是一个真正的深度学习项目,即使四轴飞行器必须连接到更强大的基站进行数据处理。然而,我们的目标是看看利用分布式网络方法,我们能把这些微处理器推进到什么程度。
我希望最终产品看起来像下面显示的英特尔无人机灯光秀:
Credit: Intel
当然,规模要小得多,而且可能只是在室内环境中。
对于深度学习部分,无人机将利用深度强化学习来即时做出关于如何在周围环境中机动的决定。
深层加固网络将在模拟环境中使用 Unity3D 进行训练。通过这种方式,丢失无人机或手指的风险可以通过预先训练的模型来减轻。
增强模型将在连接到无人机网状网络的基站上运行,或者在每个无人机上运行。该网络将依靠网状网络中所有无人机的传感器读数来计算单个无人机的最佳可能行动。通过这种方式,他们要么能够根据其他人正在做的事情进行协调,要么网络中的中央管理器将监视无人机并指挥它们。
单一基站是这个项目的一个有吸引力的选择,但会挫败将 ESP32 推向绝对边缘的目的。然而,如果没有基站来提供神经网络所需的广泛计算能力,无人机的能力将受到明显的限制。
下一步是什么?
无人驾驶飞机、控制回路和网格功能。
本系列的下一篇文章将关注如何让无人机真正飞行。它还将介绍一个 ESP32 网状网络的基本实现,作为概念验证,在节点之间传递数据。
所有代码和原理图将很快可用!在传给你们之前,我想确保我有一个可行的设计!
深度学习算法和脑机接口
原文:https://towardsdatascience.com/deep-learning-algorithms-and-brain-computer-interfaces-7608d0a6f01?source=collection_archive---------18-----------------------
作为研究团队的一员,我想解释近年来深度学习(DL)如何显著提升了脑机接口系统(BCI)的性能。
对于那些不熟悉脑机接口的人来说,BCI 是一个将人脑的活动模式翻译成消息或命令以与其他设备通信的系统。
可以想象,设计 BCI 是一项复杂的任务,需要计算机科学、工程学、信号处理、神经科学等多学科知识。
要使用 BCI,通常需要两个阶段:
在 BCI 进行校准很有挑战性,因为信噪比(SNR)不理想,而且受试者之间的差异很大。根据所选范式的类型,校准所需的时间可能不同。尽管如此,校准时间可以部分减少。
BCI 的关键挑战是在大脑信号信噪比很低的情况下准确识别人类的意图。事实是低分类精度和低泛化能力限制了 BCI 的实际应用。
为了克服上述挑战,在过去几年中,深度学习技术已经被用于处理大脑信息。与传统的机器学习算法不同,深度学习可以从大脑信号中学习特定的高级特征,而无需人工选择特征,其准确性与训练集的大小成正比。此外,深度学习模型已经应用于几种类型的 BCI 信号(例如,自发 EEG、ERP、fMRI)。
为什么要深度学习?
首先,大脑信号容易被各种生物(例如,眨眼、肌肉伪影、疲劳和注意力水平)和环境伪影(例如,环境噪声)破坏。
使用脑电图有许多困难。由于 BCI 的主要任务是脑信号识别,因此区分性深度学习模型是最流行和最强大的算法。
一个 BCI 可以通过多种方式监控大脑活动,大致可以分为侵入式和非侵入式 - 侵入式。大多数非 - 有创 BCI 系统使用脑电信号;即从放置在头皮上的电极记录的脑电活动。
很难理解大脑活动的意义,这种活动从神经元相互交流,通过头骨,通过头皮,勉强进入 EEG 传感器。一般来说,EEG 数据是非常嘈杂的,因为很难获得特定事物的清晰信号。
因此,从受损的大脑信号中提取有用的数据并建立一个在不同情况下都能工作的健壮的 BCI 系统是至关重要的。
此外,由于电生理脑信号的非平稳特性,BCI 具有低信噪比。
在脑机接口(BCI)中对脑电图(EEG)数据进行分类的准确性取决于测量通道的数量、用于训练分类器的数据量以及信噪比(SNR)。在所有这些因素中,信噪比是现实应用中最难调整的。
虽然已经开发了几种预处理和特征工程方法来降低噪声水平,但是这些方法(例如,时域和频域中的特征选择和提取)非常耗时,并且可能导致提取的特征中的信息丢失。
第三,特征工程高度依赖于人类在特定领域的专业知识。人类经验可能有助于捕捉某些特定方面的特征,但在更普遍的情况下证明是不够的。因此,需要一种算法来自动提取代表性特征。
深度学习为自动提取可区分特征提供了更好的选择。
此外,当前大多数机器学习研究都专注于静态数据,因此无法准确地对快速变化的大脑信号进行分类。在 BCI 系统中,通常需要新的学习方法来处理动态数据流。
到目前为止,深度学习已经在 BCI 应用中得到广泛应用,并在解决上述挑战方面显示出成功。
深度学习有三个优势。首先,它通过直接在原始脑信号上工作来通过反向传播学习可区分的信息,从而避免了耗时的预处理和特征工程步骤。此外,深度神经网络可以通过深度结构捕捉代表性的高级特征和潜在的依赖性。
最后,深度学习算法被证明比支持向量机(SVM)和线性判别分析(LDA)等传统分类器更强大。这是有道理的,因为几乎所有的 BCI 问题都可以被视为一个分类问题。
BCI 使用的 DL 算法
CNN 是 BCI 研究中最流行的 DL 模型,可以用来挖掘输入脑信号(如 fMRI 图像、自发脑电等)之间潜在的空间相关性。
CNN 在一些研究领域取得了巨大的成功,这使得它非常“可扩展”和可行(通过可用的公共代码)。因此,BCI 的研究人员有更多的机会了解 CNN 并将其应用到他们的工作中。
生成式深度学习模型主要用于生成训练样本或数据扩充。换句话说,生成式深度学习模型在 BCI 地区起到了辅助作用,提高了训练数据的质量和数量。在 BCI 范围内,生成算法主要用于重建或生成一批脑信号样本来增强训练集。BCI 常用的生成模型包括变分自动编码器(VAE)、生成对抗网络(GANs)等。
深度信念网络也在 BCI 用于特征提取。尽管越来越多的出版物关注于采用 CNN 或混合模型来进行特征学习和分类。
RNN 和 CNN 都具有很好的时间和空间特征提取能力,将它们结合起来进行时间和空间特征学习是很自然的。
未来的挑战
基于深度学习的 BCI 的一个有前景的研究领域是开发一个通用框架,该框架可以处理各种 BCI 信号,而不管用于信号收集的通道数量、样本维度和刺激类型(视觉或听觉刺激)等。
总体框架需要两种关键能力:
- 注意机制
- 捕捉潜在特征的能力。
前者保证该框架能够集中于输入信号的最有价值的部分,而后者使该框架能够捕获独特的和信息丰富的特征。
到目前为止,大多数 BCI 分类任务都集中在与人相关的场景,其中训练集和测试集来自同一个人。未来的方向是实现与人无关的分类,使测试数据永远不会出现在训练集中。高性能的独立于个人的分类对于 BCI 系统在现实世界中的广泛应用是必不可少的。
实现这一目标的一个可能的解决方案是建立一个具有迁移学习的个性化模型。
BCI 的未来
当谈到更先进的想法时,我们可能仍然需要几年的时间,因为大脑的功能更加复杂,不容易理解。我们仍在学习大脑如何创造这些复杂的功能,尽管有些人已经在非人类物种中进行了非常初步的尝试,但结果并没有达到我们的预期。
根据一些研究,目前只有不到 100 人在使用这项技术的一些早期形式。
就方法论而言,复杂网络理论现在正处于早期阶段...它需要达到成熟,我们才能看到对我们理解复杂网络(如大脑)的内在机制的影响。目前的技术只能让我们接触到神经系统的某些部分。
在计算机科学中,在用更有效的算法和数据结构以省时的方式解码神经数据方面还有许多事情要做。
要了解更多信息,我推荐你阅读这项出色的研究,它对我写这篇文章帮助很大:
-“基于深度学习的脑机接口调查:最新进展和新前沿”
使用大模型支持的深度学习分析
原文:https://towardsdatascience.com/deep-learning-analysis-using-large-model-support-3a67a919255?source=collection_archive---------19-----------------------
借助 IBM 大型模型支持,优化您的深度学习模型内存消耗。
(Source: https://miro.medium.com/max/3512/1*d-ZbdImPx4zRW0zK4QL49w.jpeg)
介绍
内存管理现在是机器学习中一个非常重要的话题。由于内存限制,使用 Kaggle 和谷歌 Colab 等云工具训练深度学习模型变得非常普遍,这要归功于它们免费的 NVIDIA 图形处理单元(GPU)支持。尽管如此,在云中处理大量数据时,内存仍然是一个巨大的限制。
在我的上一篇文章中,我解释了如何加速机器学习工作流的执行。相反,本文旨在向您解释如何在实现深度学习模型时有效地减少内存使用。通过这种方式,你可能能够使用相同数量的内存来训练你的深度学习模型(即使之前因为内存错误而无法训练)。
模型导致内存不足的主要原因有三个:
- 模型深度/复杂度 =神经网络的层数和节点数。
- 数据大小 =使用的数据集中样本/特征的数量。
- 批量大小 =通过神经网络传播的样本数量。
这个问题的一个解决方案传统上是通过在预处理阶段试图去除不太相关的特征来减小模型大小。这可以使用特征重要性或特征提取技术(如 PCA、LDA)来完成。
使用这种方法可能会降低噪声(减少过度拟合的机会)并缩短训练时间。不过这种方法的一个缺点是准确性会持续下降。
如果模型需要很高的复杂度来捕捉数据集的所有重要特征,那么减少数据集的大小实际上不可避免地会导致更差的性能。在这种情况下,大模型支持可以解决这个问题。
大型模型支持
大型模型支持(LMS)是 IBM 最近推出的一个 Python 库。这个库的构想是为了训练无法容纳在 GPU 内存中的大型深度学习模型。事实上,与中央处理器(CPU)相比,GPU 通常具有更小的内存空间。
当使用 Tensorflow 和 PyTorch 等库实现神经网络时,会自动生成一组数学运算来构建该模型。这些数学运算可以用计算图来表示。
计算图是一个有向图,其中节点对应于操作或变量。变量可以将它们的值提供给操作,操作可以将它们的输出提供给其他操作。这样,图中的每个节点都定义了变量的函数。
—深刻的想法[1]
计算图中进出节点的值称为张量(多维数组)。
图 1 给出了一个简单的例子,说明如何使用计算图形(z =(x+y)∫(X5))来表示数学运算:
Figure 1: Computational Graph [2]
LMS 能够通过重新设计神经网络计算图来缓解 GPU 内存问题。这是通过在 CPU(而不是 GPU)上存储中间结果来实现张量运算的。
IBM 文档概述了使用 Tensorflow 库支持大型模型的三种不同方法:
- 基于会话的培训。
- 基于估计器的训练。
- 基于 Keras 的培训。
在本文中,我将提供一个使用基于 Keras 的培训的例子。如果您有兴趣了解其他两种方法的更多信息,IBM 文档是一个很好的起点[3]。
使用 LMS 时,我们可以调整两个主要参数来提高模型效率。目标是能够找出我们需要交换的最少数量的张量,而不会导致内存错误。
要调整的两个主要参数是:
- n_tensors =交换张量的数量(例如,刷出比所需更多的张量,会导致通信开销)。
- lb =张量在使用前多久换回(例如,使用较低的 lb 值会使 GPU 训练暂停)。
示范
现在,我将通过一个简单的例子向您介绍 LMS。这个练习使用的所有代码都可以在这个 Google 协作笔记本和我的 GitHub 上找到。
在这个例子中,我将训练一个简单的神经网络,首先使用具有大模型支持的 Keras,然后只使用普通的 Keras。如果是这两种情况,我将记录培训所需的内存使用情况。
预处理
为了按照这个例子安装所有需要的依赖项,只需在您的笔记本上运行以下单元,并启用您的 GPU 环境(例如 Kaggle、Google Colab)。
! git clone [https://github.com/IBM/tensorflow-large-model-support.git](https://github.com/IBM/tensorflow-large-model-support.git)
! pip install ./tensorflow-large-model-support
! pip install memory_profiler
一旦一切就绪,我们就可以导入所有必要的库了。
为了记录内存使用情况,我决定使用 Pythonmemory _ profiler。
随后,我定义了将在培训中使用的 LMS Keras 回调。根据 Keras 文档,回调的定义是:
回调是在训练过程的给定阶段应用的一组函数。在训练期间,您可以使用回调来查看模型的内部状态和统计数据。
— Keras 文档[4]
回调通常用于通过在每个训练迭代期间自动化某些任务来控制模型训练过程(在这种情况下,通过添加大型模型支持优化)。
然后,我决定使用由三个特征和两个标签(0/1)组成的高斯分布来构建一个 200000 行的简单数据集。
已经选择了分布的平均值和标准偏差值,以便使这个分类问题相当容易(线性可分数据)。
Figure 2: Dataset Head
创建数据集后,我将其分为要素和标注,然后定义一个函数对其进行预处理。
现在我们有了训练/测试集,我们终于准备好开始深度学习了。因此,我为二元分类定义了一个简单的序列模型,并选择了 8 个元素的批量大小。
Keras 和大型模型支持
使用 LMS 时,使用 Keras fit_generator 函数训练 Keras 模型。这个函数需要的第一个输入是一个生成器。生成器是一种功能,用于在多个内核上实时生成数据集,然后将其结果输入深度学习模型[5]。
为了创建本例中使用的生成器函数,我参考了这个实现。
如果你对 Keras 发电机的更详细的解释感兴趣,可以在这里找到。
一旦定义了我们的生成器函数,我就使用之前定义的 LMS Keras 回调来训练我们的模型。
在上面的代码中,我在第一行额外添加了 %%memit 命令来打印出运行这个单元的内存使用情况。结果如下所示:
Epoch 1/2 200000/200000 [==============================]
- 601s 3ms/step - loss: 0.0222 - acc: 0.9984 Epoch 2/2 200000/200000 [==============================]
- 596s 3ms/step - loss: 0.0203 - acc: 0.9984 peak memory: 2834.80 MiB, increment: 2.88 MiB
使用 LMS 训练此模型的注册峰值内存等于 2.83GB,增量为 2.8MB
最后,我决定测试我们的训练模型的准确性,以验证我们的训练结果。
Model accuracy using Large Model Support: 99.9995 %
克拉斯
使用普通 Keras 重复相同的程序,获得以下结果:
Epoch 1/2 1600000/1600000 [==============================]
- 537s 336us/step - loss: 0.0449 - acc: 0.9846 Epoch 2/2 1600000/1600000 [==============================]
- 538s 336us/step - loss: 0.0403 - acc: 0.9857 peak memory: 2862.26 MiB, increment: 26.15 MiB
使用 Keras 训练该模型的注册峰值内存等于 2.86GB,增量为 26.15MB
测试我们的 Keras 模型反而导致 98.47%的准确性。
Model accuracy using Sklearn: 98.4795 %
估价
比较使用 Keras + LMS 与普通 Keras 获得的结果,可以注意到,使用 LMS 可以减少内存消耗,并提高模型精度。如果给予更多的 GPU/CPU 资源(可用于优化训练)并使用更大的数据集,LMS 的性能甚至可以得到改善。
除此之外,IBM 和 NVIDIA 还决定创建一个由 27000 个 NVIDIA TESLA GPU组成的深度学习计算机集群,以进一步发展这方面的研究人员。如果你有兴趣了解更多,你可以在这里找到更多信息。
联系人
如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:
- 领英
- 个人博客
- 个人网站
- 中等轮廓
- GitHub
- 卡格尔
文献学
[1]从零开始的深度学习 I:计算图——深度思想。访问网址:http://www . deep ideas . net/deep-learning-from scratch-I-computational-graphs/
[2] TFLMS:通过图重写在张量流中支持大模型。董丁乐,今井春树等访问:https://arxiv.org/pdf/1807.02037.pdf
TensorFlow 大型模型支持(TFLMS)入门— IBM 知识中心。访问地址:https://www . IBM . com/support/knowledge center/en/ss5sf 7 _ 1 . 5 . 4/navigation/pai _ TF LMS . html
[4] Kears 文件。文档->回调。访问地点:【https://keras.io/callbacks/?source=post_page -
[5]如何将数据生成器用于 Keras 的详细示例。
谢尔文·阿米迪。访问地址:https://Stanford . edu/~ sher vine/blog/keras-how-to-generate-data-on-the-fly
深度学习和碳排放
原文:https://towardsdatascience.com/deep-learning-and-carbon-emissions-79723d5bc86e?source=collection_archive---------6-----------------------
由 Emma Strubell、Ananya Ganesh 和 Andrew McCallum 撰写的一篇颇具争议的论文《NLP 中深度学习的能源和政策考虑》最近正在流传。虽然论文本身是深思熟虑和有分寸的,但标题和推文一直具有误导性,比如“深度学习模型有大量的碳足迹”。一篇特别是不负责任的文章将该发现总结为“一个普通的现成深度学习软件可以排放超过 626,000 磅的二氧化碳”,这是一个惊人的误解。
作为一个非常关心深度学习和环境的人,我很高兴看到机器学习从业者写的一篇关于这个主题的深思熟虑的文章,但很遗憾看到它在媒体上被严重歪曲。
我开了一家公司,Weights and Biases,帮助机器学习从业者跟踪他们的模型和实验。我已经直接看到了冗余模型训练的代价,我希望权重和偏见可以在帮助机器学习从业者更明智地使用他们的资源方面发挥作用。
结论
- 模型训练的实际碳足迹可能不是什么大问题,但在未来可能是。
- 模型推理的碳足迹现在是一个更大的问题。
- 快速增长的 CPU/GPU 培训成本是今天的一个问题,原因有几个,我预计它会变得更糟。
- 机器学习从业者在冗余训练上浪费了大量资源。
如今,模型训练可能不是碳排放的重要来源(但它正呈指数增长)
论文中的示例模型“具有神经架构搜索的变压器”在 2019 年几乎任何人真正做的计算成本方面都遥遥领先。例如,一个更具代表性的任务,在 imagenet 上训练一个标准的神经网络初始,以 95%的准确率识别图片中的对象,需要大约 40 个 GPU 小时,这将消耗大约 10 千瓦时并产生大约 10 磅的二氧化碳,这相当于运行一个中央空调大约 2-3 个小时。
我们看到的使用 Weights & Biases 的典型机器学习实践者可能有八个 GPU 可供其使用,它们的利用率不会接近 100%。即使他们这样做,能源消耗将在 2kW 左右。如果有 100,000 名机器学习从业者(可能很慷慨),总的培训消耗将是 200 兆瓦。这并不比让一架 747 飞机停留在空中多多少能源,也可能更少碳排放。
另一种看待深度学习影响的方式是看英伟达的销售额,因为英伟达提供了大多数人用于培训的处理器。在 Q1 2019 年,他们的数据中心收入为 7.01 亿美元,这意味着他们为数据中心销售了大约 100,000 个 GPU。即使所有这些 GPU 都是训练模型(同样,不太可能),我们也会得出类似的结论。
为什么机器学习可能成为未来碳排放的重要组成部分
仅仅因为模型训练可能不是今天的主要碳生产者,并不意味着我们不应该关注它在未来可能产生的影响。
尽管典型的机器学习实践者可能只使用八个 GPU 来训练模型,但在谷歌、脸书、OpenAI 和其他大型组织中,使用率可能会高得多。
美国能源部为他们的橡树岭超级计算机购买了 27,648 个 Volta GPU ,他们计划用于深度学习,在 100%利用率的情况下将消耗大约 1 兆瓦。
深度学习的最近趋势显然是计算量增加几个数量级。这意味着更多数量级的能源和气候影响。因为今天的影响可能很小,如果趋势继续下去,它可能会迅速改变。OpenAI 有一篇出色的博客文章, AI 和 Compute 展示了构建最先进模型的计算成本的快速增长。
来源:人工智能和计算
GPU 性能功耗比也呈指数级增长,但它似乎更像是每 10 年增长 10 倍,而先进模型性能所需的计算每年增长 10 倍。
https://github.com/karlrupp/cpu-gpu-mic-comparison
模型推理比模型训练消耗更多的能量(现在如此,可能永远如此)
模型不仅仅在训练时消耗能量,今天更大的能量消耗来源于它们被部署之后。Nvidia 估计,在 2019 年,一款机型80–90%的成本都在推论中。目前还不清楚神经网络进行自动驾驶需要多少功率,但一些原型需要多达 2500 瓦,如果在世界上的每辆汽车上部署,将产生相当大的影响,尽管这比实际移动汽车要小一个数量级。
一个更直接的能源使用问题是数据中心今天使用超过 200 瓦,而且这个数字还在增长。谷歌在数据中心的能源使用足以激励他们设计自己的处理器,用于被称为 TPU 的推理,他们现在也将它作为谷歌云的一部分提供。
经济激励大多与模特培训的环境激励一致
模特培训变得极其昂贵。在云中运行模型,单个 GPU 的成本约为 1 美元/小时,产生约 0.25 磅的二氧化碳——以 10 美元/吨的声誉良好的碳抵消计算,抵消这些二氧化碳将花费约 0.1 美分,仅增加我的账单 0.1%。为碳中和模型培训支付的小额增量价格。
对于深度学习中快速增长的计算需求来说,环境影响甚至可能不是最糟糕的事情
Ananya 的论文提到了这一点,但它值得强调:训练艺术模型的高成本有许多令人担忧的影响。如今,研究人员和初创公司很难与谷歌和脸书等公司竞争,甚至复制它们的工作,因为培训成本太高。
直到最近,模型通常被认为是数据绑定的,许多人担心大公司在拥有最多数据方面具有不容置疑的优势。但是研究人员仍然能够在像 ImageNet 这样的高质量开放数据集上取得进展。创业公司能够在他们可用的数据上建立最好的机器学习应用程序。
在一个研究人员和公司都受限于计算的世界里,很难想象他们将如何与大公司竞争甚至合作。如果最先进的模型花费数百万美元来训练,还会有人试图复制彼此的结果吗?
即使在研究人员中,更高知名度的实验室也拥有不成比例的资金和资源,导致他们发表更令人兴奋的结果,这反过来增加了他们的计算能力。这可能导致极少数机构成为唯一能够进行基础深度学习研究的机构,
大量浪费和冗余的计算正在不断增加
这篇文章有几个极好的结论,我都同意。第一个是“作者应该报告训练时间和对超参数的敏感性”。为什么这如此重要?一个非从业者可能不会从这篇文章中意识到的一件事是,相同的深度学习模型是如何被一遍又一遍地训练的。从业者通常从现有的艺术模型开始,并尝试训练它。
例如,像脸书的 mask rcnn 视觉模型这样受欢迎的机器学习知识库已经被标星超过 5000 次,分叉超过 1500 次。很难说有多少人使用这种模式进行了训练,但我认为合理的估计可能是恒星数量的十倍,也就是说,有 25,000 名不同的人尝试过这种模式。有人会对模型做的第一件事就是训练它,看看它表现如何。然后他们通常会训练它更多次,尝试不同的超参数。但是所有这些信息都丢失了,而且大多数训练都是多余的。
这是我创办公司《重量与偏见》的原因之一。我们会保存您运行的所有实验,这样您就不必再次运行它们,而那些接手您工作的人也不必再次运行它们。当我看到研究人员在我们的系统中跟踪他们的实验时,我真的很兴奋。
论文中提出的另一个要点是“NLP 和机器学习软件开发人员可以帮助减少与模型调整相关的能量的另一个途径是通过提供易于使用的 API 来实现更有效的替代超参数调整的强力网格搜索,例如随机或贝叶斯超参数搜索技术。”
换句话说,研究人员不用尝试所有可能的超参数集,而是通过让算法智能地挑选有前途的超参数来节省资金、时间和环境影响。我们真的试图让做更智能的超参数搜索变得非常简单。
考虑抵消你的模特训练对环境的影响
与在亚马逊上购买 GPU 小时相比,购买碳补偿是便宜的。那么为什么不碳中和呢?有些人不认为碳补偿真的有效,但这超出了我的专业领域。非营利的碳基金对此进行了大量的思考,并提供了我认为大多数人会认为是高质量的碳补偿,即使他们可能会对确切的“补偿”吹毛求疵。向像地球正义这样的组织捐款可能不那么直接,但可能更有影响力。如果你左右为难,也许可以两者兼而有之。
一个简单的公式是,2019 年在加利福尼亚州的 Nvidia GPU 上训练一小时产生大约 0.25 磅二氧化碳当量的排放。
如果你想帮助计算你的模型训练碳足迹,我很乐意帮助你。
感谢
感谢詹姆斯·查姆、埃德·麦卡洛、克里斯·范·代克、布鲁斯·比沃德、斯泰西·斯维特拉奇尼亚和诺加·莱维纳的有益反馈。
神经网络的自然同伦
原文:https://towardsdatascience.com/deep-learning-and-doughnuts-c2f0f7b7c598?source=collection_archive---------9-----------------------
流形学习
在流形假设下,现实世界的高维数据集中在一个非线性的低维流形附近【2】。换句话说,数据大致位于一个比输入空间维度低得多的流形上,一个可以被检索/学习的流形【8】
为了应对维数灾难,流形假设是至关重要的:如果我们期望机器学习算法学习在高维空间中有有趣变化的函数,许多机器学习模型问题似乎是没有希望的【6】
幸运的是,经验证明,人工神经网络由于其分级、分层的结构【3】,能够捕捉普通数据的几何规律。[3] 展示了证明处理位于低维流形上或附近的数据的能力的实验。
然而,ANN 层如何识别原始数据空间到合适的低维流形之间的映射(表示)?
同胚线性嵌入
根据【10】提供的定义,一个同胚,也叫连续变换,是两个几何图形或拓扑空间中的点之间在两个方向上连续的等价关系和一一对应关系。
- 同样保持距离的同胚叫做等距。
- 仿射变换是另一种常见的几何同胚。
A continuous deformation between a coffee mug and a doughnut (torus) illustrating that they are homeomorphic. But there need not be a continuous deformation for two spaces to be homeomorphic — only a continuous mapping with a continuous inverse function [4]
【1】看 tanh 图层。tanh 层 tanh(Wx+b) 包括:
- 通过“权重”矩阵 W 进行线性变换
- 甲由矢乙翻译
- tanh 的逐点应用
虽然流形学习方法明确地学习低维空间,但是神经网络层是到不一定是低维空间的非线性映射。实际情况就是这样:我们来看具有 N 个输入和 N 个输出的双曲正切层。
在这样的 tanh-layers 中,每一层都拉伸和挤压空间,但它从不切割、破坏或折叠空间。直观上,我们可以看到它保留了拓扑性质[..如果权矩阵 W 是非奇异的,则具有 N 个输入和 N 个输出的 Tanh 层是同胚的。(尽管需要注意领域和范围)【1】。
A four-hidden-layers tanh ANN discriminates between two slightly entangled spirals by generating a new data representation where the two classes are linearly separable [1]
同胚和可逆的概念与可解释性深深交织在一起:理解特征空间中的变换如何与相应的输入相关是迈向可解释深度网络的重要一步,可逆深度网络可以在这种分析中发挥重要作用,因为例如,人们可以潜在地从特征空间回溯属性到输入空间【11】
An example of problems that arise in mapping manifolds not diffeomorphic to each other. The “holes” in the first manifold prevent a smooth mapping to the second [12]. It is a good idea to characterize the learnability of different neural architectures by computable measures of data complexity such as persistent homology [13]
不幸的是,并不总是可能找到同胚映射。如果数据集中在具有非平凡拓扑的低维流形附近,则不存在到斑点状流形(先验质量集中的区域)的连续可逆映射【12】
让我们回到描述 ANN 层中发生的事情的目标。通过构造同伦,我们可以分析激活函数中非线性程度的增加如何改变 ANN 层将数据映射到不同空间的方式。
自然同伦
两个映射 f0 和 f1 是同伦的,f0 ≃ f1,如果存在一个映射,同伦 F : X × I → Y 使得 f0(x) = F(x,0)和 f1(x) = F(x,1)对于所有的 x∈x【9】
【6】通过将单层感知器中的节点传递函数从线性映射转换为 s 形映射来构造同伦:
通过使用将线性网络变形为非线性网络的自然同伦,我们能够探索通常用于分析线性映射的几何表示如何受到网络非线性的影响。具体地,输入数据子空间被网络转换成曲线嵌入数据流形“【6】
The data manifold for L=3, s=2 and three weights at 𝜏=1 [6]
An intuition of how curvature relates to the existence of multiple projections of y on Z [6]
An example data manifold Z with boundaries Pa,b = Z ± (1/ |k|max)n where n is the normal to the surface. For all desired vectors y in the region between Pa and Pb, there exists only one solution. It is important to remark that the mapping is not homeomorphic: the mapping is not invertible and Z folds on itself, infinitely [6]
结论
在流形假设下,学习相当于发现一个非线性的、低维的流形。在这篇简短的博客中,我试图提供一个简短的、直观的、当然不完全全面的直觉,来说明人工神经网络如何将原始数据空间映射到一个合适的低维流形。
对于不同的人工神经网络体系结构和分类问题,在层级别可视化映射(表示)的一个很好的工具是可用的这里【15】它是令人敬畏的。
免责声明:本博客中的观点是我的,可能的错误和误解也是我的
参考
【1】http://colah.github.io/posts/2014-03-NN-Manifolds-Topology/
【2】劳伦斯·凯顿。流形学习算法。“加州大学圣地亚哥分校。代表 12.1–17(2005 年):1。()
【3】巴斯里,罗嫩,大卫雅各布。"使用深度网络有效表示低维流形。arXiv 预印本 arXiv:1602.04723 (2016)。
【4】https://en.wikipedia.org/wiki/Homeomorphism
库切、弗兰斯·m 和弗吉尼亚·l·斯通尼克。“关于线性和非线性单层网络之间的自然同伦。”神经网络汇刊 7.2(1996):307–317。
【6】Coetzee,Frans Martin,“神经网络和其他非线性方程组的分析和求解的同伦方法。博士论文,卡耐基·梅隆大学,5 月 (1995)。
【7】阿迪卡里,玛希玛·兰詹。基本代数拓扑及其应用。斯普林格,2016。
【8】Pierre Geurts,Gilles Louppe,Louis Wehenkel,迁移学习及相关协议,讲义,2018
【9】杰斯珀·莫勒,初学者同伦理论,课堂讲稿
http://mathworld.wolfram.com/Homeomorphism.html
雅各布森、约恩-亨里克、阿诺德·斯默德斯和爱德华·奥雅伦。i-revnet:深度可逆网络。“arXiv 预印本 arXiv:1802.07088 (2018)。
****【12】法洛西,卢卡等.同胚变分自动编码的探索。“arXiv 预印本 arXiv:1807.04689 (2018)。
古斯、威廉·h 和鲁斯兰·萨拉胡季诺夫。关于用代数拓扑来表征神经网络的能力。“arXiv 预印本 arXiv:1802.04443 (2018)。
【14】**古德菲勒、伊恩、约舒阿·本吉奥和亚伦·库维尔。深度学习。麻省理工学院出版社,2016 年。
****【15】https://cs . Stanford . edu/people/karpathy/convnetjs//demo/classify 2d . html
fastai 用于疟疾检测的深度学习和医学图像分析
原文:https://towardsdatascience.com/deep-learning-and-medical-image-analysis-for-malaria-detection-with-fastai-c8f08560262f?source=collection_archive---------24-----------------------
学习使用高级深度学习环境对血液涂片图像进行分类
Jimmy Chan/Pexels free images
在国家医学图书馆(NLM)的一部分 Lister Hill 国家生物医学通信中心(LHNCBC)提供了一个健康和受感染的血液涂片疟疾图像的注释数据集之后,各种帖子和论文已经发表,展示了如何使用卷积神经网络的图像分类来学习和分类这些图像。
该数据集中的图像看起来像我们下面收集的图像:寄生的涂片将显示一些彩色点,而未感染的涂片将倾向于均匀着色。
对这些涂片进行分类应该不是一件非常困难的事情。下面列出的帖子中描述的结果表明,96%到 97%的分类准确率是可行的。
在这篇文章中,我们将展示如何使用 fast.ai CNN 图书馆来学习分类这些疟疾涂片。Fast.ai 是一个库,基于 PyTorch 构建,使得编写机器学习应用程序变得更快更简单。Fast.ai 还提供了一门在线课程,涵盖了 fast.ai 和深度学习的一般使用。与较低级别的“高级”库相比,如 Keras 、 TensorFlow 。无论是 Keras 还是 pure PyTorch ,fast.ai 都极大地减少了制作最先进的神经网络应用程序所需的样板代码数量。
本公告基于以下材料:
- PyImagesearch::深度学习和医学图像分析与 Keras —以疟疾图像为例,作者 Adrian Rosebrock,2018 年 12 月 3 日;
- 来自 NIH 的疟疾数据集——来自疟疾筛查者研究活动的薄血涂片图像的分割细胞库;
- TowardsDataScience::利用深度学习检测疟疾——人工智能造福社会——医疗保健案例研究——Dipanjan(DJ)Sarkar 对上述内容的评论;
- PeerJ::Sivaramakrishnan Raja Raman 等人的预训练卷积神经网络作为特征提取器,用于改进薄血涂片图像中的疟原虫检测 —上述帖子的作者基于其工作的原始科学论文。
我已经改编了这个材料,以便在 2019 年 5 月与 PyTorch/fast.ai 一起使用。被评论的代码作为谷歌合作笔记本免费提供。
我们去看代码吧…
初始化
每次运行此笔记本时,请执行以下部分中的操作一次…
%reload_ext autoreload
%autoreload 2
%matplotlib inline
在 Google Colab 上测试您的虚拟机…
只是为了确定,看看哪一个 CUDA 驱动和哪一个 GPU Colab 已经为你提供了。GPU 通常是:
- 一个 11 GB 内存的 K80 或者(如果你真的幸运的话)
- 一个 14 GB 内存的特斯拉 T4
如果谷歌的服务器很拥挤,你最终只能访问 GPU 的一部分。如果您的 GPU 与另一台 Colab 笔记本共享,您将看到可供您使用的内存量减少。
小贴士:避开美国西海岸的高峰期。我住在 GMT-3,我们比美国东海岸早两个小时,所以我总是试图在早上进行繁重的处理。
!/opt/bin/nvidia-smi
!nvcc --version
当我开始运行这里描述的实验时,我很幸运:我有一个 15079 MB RAM 的完整 T4!我的输出如下所示:
Thu May 2 07:36:26 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 410.79 Driver Version: 410.79 CUDA Version: 10.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |
| N/A 63C P8 17W / 70W | 0MiB / 15079MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Sat_Aug_25_21:08:01_CDT_2018
Cuda compilation tools, release 10.0, V10.0.130
图书馆进口
在这里,我们导入所有必需的包。我们将使用 fast.ai V1 库,它位于 Pytorch 1.0 之上。fast.ai 库提供了许多有用的功能,使我们能够快速轻松地建立神经网络并训练我们的模型。
from fastai.vision import *
from fastai.metrics import error_rate
from fastai.callbacks import SaveModelCallback# Imports for diverse utilities
from shutil import copyfile
import matplotlib.pyplot as plt
import operator
from PIL import Image
from sys import intern # For the symbol definitions
实用功能:导出和恢复功能
导出用于部署的网络并创建副本
def exportStageTo(learn, path):
learn.export()
# Faça backup diferenciado
copyfile(path/'export.pkl', path/'export-malaria.pkl')
#exportStage1(learn, path)
恢复部署模型,例如为了继续微调
def restoreStageFrom(path):
# Restore a backup
copyfile(path/'export-malaria.pkl', path/'export.pkl')
return load_learner(path)
#learn = restoreStage1From(path)
下载疟疾数据
我上面列出的作者使用了 NIH 疟疾数据集。让我们做同样的事情:
!wget --backups=1 -q [https://ceb.nlm.nih.gov/proj/malaria/cell_images.zip](https://ceb.nlm.nih.gov/proj/malaria/cell_images.zip)
!wget --backups=1 -q [https://ceb.nlm.nih.gov/proj/malaria#/malaria_cell_classification_code.zip](https://ceb.nlm.nih.gov/proj/malaria/malaria_cell_classification_code.zip)
# List what you've downloaded:
!ls -al
wget 的 backups=1 参数将允许您在下载失败的情况下多次重复命令行,而无需创建大量新版本的文件。
最后一行应该产生以下输出:
total 345208
drwxr-xr-x 1 root root 4096 May 2 07:45 .
drwxr-xr-x 1 root root 4096 May 2 07:35 ..
-rw-r--r-- 1 root root 353452851 Apr 6 2018 cell_images.zip
drwxr-xr-x 1 root root 4096 Apr 29 16:32 .config
-rw-r--r-- 1 root root 12581 Apr 6 2018 malaria_cell_classification_code.zip
drwxr-xr-x 1 root root 4096 Apr 29 16:32 sample_data
现在解压缩 NIH 疟疾细胞图像数据集:
!unzip cell_images.zip
这将产生一个非常大的详细输出,如下所示:
Archive: cell_images.zip
creating: cell_images/
creating: cell_images/Parasitized/
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_162.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_163.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_164.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_165.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_166.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_167.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_168.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_169.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_170.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144104_cell_171.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_138.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_139.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_140.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_141.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_142.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_143.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144348_cell_144.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144823_cell_157.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144823_cell_158.png
extracting: cell_images/Parasitized/C100P61ThinF_IMG_20150918_144823_cell_159.png
....
....
....
...and so on...
准备您的数据
将 cell_images 文件夹的名称改为 train ,然后将 mv 放在一个新的 data 文件夹上面,这样 fast.ai 就可以用它来自动生成 train,验证和测试集合,而不用再大惊小怪了…
!mv cell_images train
!mkdir data
!mv train data
看看你的文件夹
如果还没有安装 tree 命令,使用来安装 tree :
!apt install tree
现在运行它:
!tree ./data --dirsfirst --filelimit 10
这将显示文件树的结构:
./data
└── train
├── Parasitized [13780 exceeds filelimit, not opening dir]
└── Uninfected [13780 exceeds filelimit, not opening dir]3 directories, 0 files
不要忘记设置一个文件限制,否则你会有大量的输出…
初始化一些变量
bs = 256 # Batch size, 256 for small images on a T4 GPU...
size = 128 # Image size, 128x128 is a bit smaller than most
# of the images...
path = Path("./data") # The path to the 'train' folder you created...
创建您的培训和验证数据集
在使用 Keras 的 PyImagesearch 的原始资料中,有一个很长的例程从数据中创建训练、验证和测试文件夹。有了 fast.ai 就没必要了:如果你只有一个‘train’文件夹,你可以在创建 DataBunch 时通过简单地传递几个参数来自动分割它。我们将把数据分成一个训练集 (80%)和一个验证集 (20%)。这是通过imagedatabunch . from _ folder()构造函数方法中的 valid_pct = 0.2 参数完成的:
# Limit your augmentations: it's medical data!
# You do not want to phantasize data...
# Warping, for example, will let your images badly distorted,
# so don't do it!
# This dataset is big, so don't rotate the images either.
# Lets stick to flipping...
tfms = get_transforms(max_rotate=None, max_warp=None, max_zoom=1.0)
# Create the DataBunch!
# Remember that you'll have images that are bigger than 128x128
# and images that are smaller, o squish them all in order to
# occupy exactly 128x128 pixels...
data = ImageDataBunch.from_folder(path, ds_tfms=tfms, size=size, resize_method=ResizeMethod.SQUISH, **valid_pct = 0.2**, bs=bs)
#
print('Transforms = ', len(tfms))
# Save the DataBunch in case the training goes south...
# so you won't have to regenerate it..
# Remember: this DataBunch is tied to the batch size you selected.
data.save('imageDataBunch-bs-'+str(bs)+'-size-'+str(size)+'.pkl')
# Show the statistics of the Bunch...
print(data.classes)
data
print() 将输出转换和类:
Transforms = 2
['Parasitized', 'Uninfected']
最后一行, data 将简单地输出 ImageDataBunch 实例的返回值:
ImageDataBunch;Train: LabelList (22047 items)
x: ImageList
Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128)
y: CategoryList
Uninfected,Uninfected,Uninfected,Uninfected,Uninfected
Path: data;Valid: LabelList (5511 items)
x: ImageList
Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128)
y: CategoryList
Parasitized,Uninfected,Parasitized,Uninfected,Uninfected
Path: data;Test: None
查看您的数据集群,看看增加是否可以接受…
data.show_batch(rows=5, figsize=(15,15))
培训:resnet34
如果你不知道用什么,从 34 层的剩余网络开始是一个好的选择。不要太小也不要太大…在上面列出的教程中,作者使用了:
- 一个自定义的小 ResNet (PyImagesearch)
- VGG19(面向数据科学)
我们将采用现成的 fast.ai 残差网络(ResNets)。让我们创建我们的第一个网络:
learn = cnn_learner(data, models.resnet34, metrics=error_rate)
learn.model
最后一行将以文本流的形式输出网络的架构。它看起来会像这样:
Sequential(
(0): Sequential(
(0): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace)
(3): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(4): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(1): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(2): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
....and so on....
即使像 ResNet34 这样的“小”网络也仍然非常大。不要费心去理解输出。你可以稍后阅读更多关于剩余网络的内容。有许多关于 ResNets 的介绍性帖子。
培训策略
fast.ai 的一大区别就来了:易用的 HYPOs(超参数优化策略)。超参数优化是 CNN 的一个有点神秘的分支学科。这是因为 CNN 有如此多的参数,试图通过设置一些非标准值来选择我们将改变的参数,以便为我们的网络提供更好的性能,这是一个非常复杂的问题,也是一项研究本身。fast.ai 库提供了一些非常先进但易于使用的 HYPOs,它们对快速实现更好的 CNN 有很大的帮助。
我们将采用 Leslie N. Smith 开发的 fit1cycle 方法,详情如下:
- https://docs.fast.ai/callbacks.one_cycle.html
- 神经网络超参数的训练方法:第一部分——学习速率、批量大小、动量和权重衰减——https://arxiv.org/abs/1803.09820
- 超级收敛:使用大学习率快速训练残差网络—https://arxiv.org/abs/1708.07120
- 有一篇来自 Nachiket Tanksale 的非常有趣的文章,名为寻找好的学习率和单周期政策,其中讨论了周期学习率和动量。
由于这种方法很快,我们将在第一个迁移学习阶段仅使用 10 个时期。如果性能变得更好,我们也将在每个时期保存网络:https://docs.fast.ai/callbacks.html#SaveModelCallback
learn.fit_one_cycle(10, callbacks=[SaveModelCallback(learn, every='epoch', monitor='accuracy', name='malaria-1')])
# Save it!
learn.save('malaria-stage-1')
# Deploy it!
exportStageTo(learn, path)
这将生成一个如下所示的表作为输出:
上表显示,验证集的准确率为 96.4%,而且这仅仅是在迁移学习的情况下! error_rate fast.ai 显示您将始终看到与训练集相关联的那个。作为比较,Adrian Rosebrock 在 PyImagesearch 帖子中使用他的自定义 ResNet 实现了 97%的搜索率。
ResNet34 的结果
让我们看看我们得到了什么额外的结果。我们将首先查看哪些是模型相互混淆的实例。我们将尝试看看模型预测的结果是否合理。在这种情况下,错误看起来是合理的(没有一个错误看起来明显幼稚)。这表明我们的分类器工作正常。
此外,我们将绘制混淆矩阵。这在 fast.ai 中也很简单。
interp = ClassificationInterpretation.from_learner(learn)losses,idxs = interp.top_losses()len(data.valid_ds)==len(losses)==len(idxs)
看看你的 9 个最差结果(首先不使用热图):
interp.plot_top_losses(9, figsize=(20,11), heatmap=False)
现在,进行同样的操作,但使用热图突出显示导致错误分类的原因:
interp.plot_top_losses(9, figsize=(20,11), heatmap=True)
显示混淆矩阵
fast.ai 的ClassificationInterpretation类有一个高级实例方法,允许快速轻松地绘制混淆矩阵,以更好的方式向您显示 CNN 的表现有多好。只有两个类并没有多大意义,但我们还是要这么做:它生成了漂亮的图片…你可以设置结果图的大小和分辨率。我们将 5x5 英寸设置为 100 dpi。
interp.plot_confusion_matrix(figsize=(5,5), dpi=100)
展示你的学习曲线:
观察学习和验证曲线是很有趣的。它将向我们显示网络是否以稳定的方式学习,或者它是否振荡(这可能表明质量差的数据),以及我们是否有一个好的结果,或者我们是否过度拟合或欠拟合我们的网络。
再说一次 fast.ai 有高级方法可以帮助我们。每个 fast.ai cnn_learner 都有一个自动创建的记录器实例。记录器记录训练期间的历元、损失、最优和度量数据。plot _ loss()方法将创建一个带有训练和验证曲线的图形:
learn.recorder.plot_losses()
这个结果看起来真的太好了,网络微调没有意义。如果我们仔细观察,我们会发现在大约 500 个批次时,验证损失比训练损失更严重,这表明网络可能在这一点上开始过度拟合。这表明我们已经接受了足够的培训,至少对于这个 ResNet 模型是如此。
我们观察到的过度拟合可能表明我们采用的网络模型对于数据的复杂性来说是过度的,这意味着我们正在训练一个学习单个实例而不是数据集泛化的网络。测试这一假设的一个非常简单实用的方法是尝试用一个更简单的网络学习数据集,看看会发生什么。
让我们使用一个更小的网络,再试一次…
ResNet18
这个网络简单多了。让我们看看它是否有效。
ResNet18 要小得多,所以我们会有更多的 GPU RAM。我们将再次创建数据群发,这一次批量更大…
# Limit your augmentations: it's medical data!
# You do not want to phantasize data...
# Warping, for example, will let your images badly distorted,
# so don't do it!
# This dataset is big, so don't rotate the images either.
# Lets stick to flipping...
tfms = get_transforms(max_rotate=None, max_warp=None, max_zoom=1.0)
# Create the DataBunch!
# Remember that you'll have images that are bigger than 128x128
# and images that are smaller, so squish them to occupy
# exactly 128x128 pixels...
data = ImageDataBunch.from_folder(path, ds_tfms=tfms, size=size, resize_method=ResizeMethod.SQUISH, valid_pct = 0.2, **bs=512**)
#
print('Transforms = ', len(tfms))
# Save the DataBunch in case the training goes south... so you won't have to regenerate it..
# Remember: this DataBunch is tied to the batch size you selected.
data.save('imageDataBunch-bs-'+str(bs)+'-size-'+str(size)+'.pkl')
# Show the statistics of the Bunch...
print(data.classes)
data
注意,我们坚持使用我们的 valid_pct = 0.2 :我们仍然让 fast.ai 随机选择数据集的 20%作为验证集。
上面的代码将输出如下内容:
Transforms = 2
['Parasitized', 'Uninfected']
并且:
ImageDataBunch;Train: LabelList (22047 items)
x: ImageList
Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128)
y: CategoryList
Uninfected,Uninfected,Uninfected,Uninfected,Uninfected
Path: data;Valid: LabelList (5511 items)
x: ImageList
Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128),Image (3, 128, 128)
y: CategoryList
Parasitized,Uninfected,Parasitized,Uninfected,Parasitized
Path: data;Test: None
现在,创建学习者:
learn18 = cnn_learner(data, models.resnet18, metrics=error_rate)
如果您的 Colab 环境没有 ResNet18 的预训练数据,fast.ai 会自动下载它:
Downloading: "https://download.pytorch.org/models/resnet18-5c106cde.pth" to /root/.torch/models/resnet18-5c106cde.pth
46827520it [00:01, 28999302.58it/s]
看模型:
learn18.model
这将列出你的网的结构。它比 ResNet34 小得多,但仍然有很多层。输出将如下所示:
Sequential(
(0): Sequential(
(0): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace)
(3): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
(4): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(1): BasicBlock(
(conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(5): Sequential(
(0): BasicBlock(
(conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace)
(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(downsample): Sequential(
(0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
...and so on...
让我们训练它
我们将再次使用 fit_one_cycle HYPO 训练策略。将训练限制在 10 个时期,以观察这个较小网络的行为:
learn18.fit_one_cycle(10, callbacks=[SaveModelCallback(learn, every='epoch', monitor='accuracy', name='malaria18-1')])
# Save the network
learn18.save('malaria18-stage-1')
# Deploy it also
exportStageTo(learn18, path)
该表显示网络学习到大约 96.1%的准确度,并且建议网络不应该被进一步训练:时段#8 和#9 之间的损失显示出 0.005 的减少,但是准确度保持不变,这表明网络已经开始过拟合。
让我们生成一个分类解释并查看混淆矩阵和损失曲线。
interp = ClassificationInterpretation.from_learner(learn18)
losses,idxs = interp.top_losses()interp.plot_confusion_matrix(figsize=(5,5), dpi=100)
这个混淆矩阵比我们为 ResNet34 生成的稍微差一点,但只是非常差一点。ResNet18 是否不太适合这个问题?
让我们来看看损失:
该图显示,ResNet18 在大约 290 批次后开始有点过度拟合。记住我们的 bs 在这里是 512,在 ResNet34 是 256。
让我们看看我们能否更好地微调网络。
微调一下!
这里我们将介绍另一个 fast.ai HYPO:自动选择的可变学习率。我们将让 fast.ai 为每个历元和每个层选择使用哪个学习速率,提供一个我们认为足够的学习速率范围。我们将训练 30 个纪元的网络。
# Unfreeze the network
learn18.unfreeze()
# Learning rates range: max_lr=slice(1e-4,1e-5)
learn18.fit_one_cycle(30, **max_lr=slice(1e-4,1e-5)**,
callbacks=[SaveModelCallback(learn,
every='epoch', monitor='accuracy',
name='malaria18')])
# Save as stage 2...
learn18.save('malaria18-stage-2')
# Deploy
exportStageTo(learn18, path)
97%的准确率!这正是 Adrian Rosebrock 在 PyImagesearch 帖子中使用他的定制 Keras ResNet 实现所实现的,该帖子在上述三篇参考文献中提供了最佳的准确性结果。
然而,验证失败在过去的时代变得更糟。这表明我们从大约第 20 纪元开始就已经过度拟合。如果你想部署这个网络,我建议你从 epoch 20 加载结果并生成一个部署网络。它似乎没有变得更好,没有这个网络。
看看结果
interp = ClassificationInterpretation.from_learner(learn18)
losses,idxs = interp.top_losses()interp.plot_confusion_matrix(figsize=(5,5), dpi=100)
这比我们以前吃过的要好。让我们看看损失曲线:
在这里,我们看到网络似乎在 500 批次后开始过度拟合,这将证实我们从上面的结果表中推断的怀疑。如果你看上面的曲线,你会看到验证损失在训练的最后三分之一开始增加,表明这部分训练只是过度拟合了网络。
如果培训中途中断,我该怎么办?
如果你的训练被打断了,你会怎么做?这可能是因为你在 Google Colab 笔记本上达到了连续 12 小时的“免费”操作时间,或者因为你的计算机由于某种原因停止了。我住在巴西,电力短缺是常事…
fit_one_cycle 方法适用于变化的自适应学习速率,遵循速率先增大后减小的曲线。如果您在第 10 个时期(比如说 20 个时期)中断训练,然后重新开始 9 个时期以上的训练,您将不会得到与不间断训练 20 个时期相同的结果。您必须能够记录您停止的位置,然后从该点重新开始训练周期,并使用该周期部分的正确超参数。
A fit_one_cycle training session divided into three subsessions. Image by PPW@GitHub
你要做的第一件事就是保存你的网络:
learn.fit_one_cycle(20, max_lr=slice(1e-5,1e-6),
callbacks=[SaveModelCallback(learn, every='epoch',
monitor='accuracy', name=***<callback_save_file>***)])
这将使您的网络在每个时期都被保存,您提供的名称后跟_ #时期。所以在纪元#3,文件 saved_net_3.pth 将被写入。您可以在完成以下操作后加载此文件:
- 重新创建了数据束和
- 用它重新实例化了网络。
重新加载后。pth 文件,你可以重新开始你的训练,只是你要告诉 fit_one_cycle 考虑 20 个历元,但是要从历元#4 开始训练。
要了解这是如何做到的,请看这里:
- 将一个长周期政策分成几个小周期——PPW 的 GitHub
你是怎么做到的?
fast.ai 中的 fit_one_cycle 方法已经开发出来,允许您告诉它从周期的哪个部分恢复中断的训练。恢复培训的代码如下所示:
# Create a new net if training was interrupted and you had to
# restart your Colab sessionlearn = cnn_learner(data, models.<your_model_here>,
metrics=[accuracy, error_rate])# If you're resuming, only indicating the epoch from which to
# resume, indicated by ***start_epoch=<epoch#>*** will load the last
# saved .pth, it is not necessary to explicitly reload the last
# epoch, you only should **NOT** change the name given in
# name=<callback_save_file>:
# when resuming fast.ai will try to reload
# ***<callback_save_file>_<previous_epoch>.pth***
# Unfreeze the network
learn50.unfreeze()# Use start_epoch=<some_epoch> to resume training...
learn.fit_one_cycle(20, max_lr=slice(1e-5,1e-6),
***start_epoch=<next_epoch#>***,
callbacks=[SaveModelCallback(learn,
every='epoch', monitor='accuracy',
***name=<callback_save_file>***)])
fast.ai 会告诉你“已加载<回调 _ 保存 _ 文件> _ <上一个 _ 纪元# > ”,恢复训练。
您可以在此查看 fit_one_cycle 方法支持的所有参数:
- https://docs.fast.ai/train.html#fit_one_cycle
我们学到了什么?
与其他方法相比,作者分别使用纯 Keras 和 TensorFlow。Keras 为了解决这个问题,借助 fast.ai 我们能够使用更少的代码解决同样的疟疾血液涂片分类问题,同时使用高级超参数优化策略,使我们能够更快地进行训练。同时,一组高级功能也允许我们以表格和图形的形式轻松检查结果。
利用 fast.ai 提供的现成残差网络模型,在 ImageNet 上进行预训练,我们获得的精度结果比上面三篇文章中的两篇(包括发表在 PeerJ 上的科学论文)高出 1%,相当于上面文章的最佳表现。这表明 fast.ai 是更传统的 CNN 框架的一个非常有前途的替代方案,特别是如果手头的任务是一个“标准”的深度学习任务,如图像分类、对象检测或语义分割,可以通过微调现成的预训练网络模型来解决。
想看看更有野心的例子吗?
用 fast.ai 看我们的皮肤癌检测教程:
- towards data science:利用 fastai 进行皮肤图像诊断的深度学习——学习从皮肤镜图像中识别皮肤癌和其他病症 作者 Aldo von Wangenheim
在本例中,我们将向您展示如何处理更大的数据集并调整最佳学习率。
深度学习和动量投资
原文:https://towardsdatascience.com/deep-learning-and-momentum-investing-2273e8db5b86?source=collection_archive---------4-----------------------
了解如何以规范和可解释的方式将深度学习模型应用于金融数据
在这篇文章中,我概述了我关于深度学习和美国股票动量的新工作论文。我从论文的简短摘要开始,强调研究问题和主要结果,然后我故意戴上我的实践者的帽子(买方 quant / PM,目前在工作和新机会之间转换,提示提示),并专注于纪律量化研究的以下实际方面:
- 主动选择特性和特性工程
- 选择最佳网络架构和构建集成的系统方法
- 模型预测的解释
该论文可在 SSRN网站上获得,论文摘要可在这里找到。我们欢迎并热切期待您的评论、建议和反馈。
这篇文章相当长,所以这里是关键的要点:
- 我在深度学习框架中调查了一系列动量相关变量的预测能力,并记录了丰富的非线性时变结构对预期回报的影响。建立在深度学习模型预测基础上的投资策略积极利用非线性和互动效应,产生高且具有统计显著性的回报,具有稳健的风险特征,其表现实际上与既定的风险因素不相关。
- 对模型输入的深思熟虑的方法是至关重要的:金融数据的常见问题,例如稀缺性、非平稳性和状态依赖性,可以通过主动选择功能和功能工程来缓解。
- 自动化超参数优化非常重要,不仅因为它可以带来更好的模型架构,还因为它增加了一层额外的建模规则,增强了结果的可重复性。
- 机器学习模型预测的可解释性至关重要。将预测与资产行为的既定事实联系起来的能力是对结果的健全性检查。
一.导言和总结
在金融学中,动量指的是通过过去的价格数据对横截面收益的可预测性。一个标准的例子是,在过去 1 至 12 个月中有高回报的股票继续跑赢同期表现不佳的股票。买入过去的赢家,卖出过去的输家,从而获得正回报,这是金融研究中长期存在的市场异常现象,记录了几乎每一种资产类别,实际上已经有几百年了。请注意,由于股票是与同类股票相比较的,我们谈论的是横截面的可预测性,而不是时间序列动量或趋势跟踪,在时间序列动量或趋势跟踪中,买卖股票的决定仅取决于其过去的表现。在过去的四分之一世纪里,金融文献提出了许多衡量动量的方法,例如从回望视野的角度,并确定了许多令人困惑的变量,如市场波动性,作为一种投资策略来预测其表现。新兴的金融机器学习领域进一步发现,过去的价格数据是未来回报的最强预测因素之一,主导着账面市值比等基本变量。
在本文中,我在深度学习框架中,在不同的时间范围内,研究了一系列基于价格的特征的预测能力。我的成果和贡献如下:
- 实证:我记录了这些特征对美国股票市场预期回报的影响中丰富的非线性结构。冲击的大小和符号表现出显著的时间变化,并受特征间相互作用的影响。预期回报的非线性程度也会随着时间的推移而发生很大变化,在不景气的市场中这种程度最高。
- 方法论:我利用神经网络输出相对于输入的可微性来研究特征对模型预测的方向性影响、它们随时间的演变以及与其他变量的相互作用。这种分析允许明确地将预测与动量的程式化事实联系起来,从而增加结果的透明度,并展示臭名昭著的黑盒算法的可解释性。我进一步展示了如何利用超参数优化和集成构建方法,以系统的方式选择性能最佳的模型。
- 实用:建立在深度学习模型的样本外预测基础上的投资策略积极利用非线性和交互效应,产生高且具有统计意义的回报,具有稳健的风险特征,其表现实际上与既定的风险因素无关,包括动量和来自当前文献的机器学习投资组合。
该员额的其余部分组织如下:
二。特性工程
III 的重要性。型号和数据T5 IV。超参数优化与集成构建
五、测试集结果与预测的可解释性
六、测试集结果与预测的可解释性。结束语
二。为什么特性选择和特性工程很重要?
财务数据是特殊的,需要深思熟虑的方法。首先,与机器学习应用的数据集标准相比,它在范围和可用性方面相当有限——事实上,对于绝大多数市场,我们在 20 世纪 90 年代之前没有高质量的数据。其次,金融数据不是平稳的,这进一步加剧了这个问题。概括地说,管理数据生成过程的规则可以随着时间的推移而改变,例如,三十年前的交易成本比现在高一个数量级,尤其是对于较小的股票,因此保持其他一切都相同,相对于较大和流动性更好的股票,预期回报更高。此外,驱动回报的许多重要变量可能会从模型中忽略,或者在训练集上无法体验到它们的全部值。这个问题的一个具体例子是资产价格在高市场波动期和低市场波动期的截然不同的行为,或制度— 在覆盖仅对应于其中一个制度的时间段的数据子集上训练模型会削弱模型在测试集上进行概括的能力。当然,不仅是市场波动,还有其他变量,如宏观经济统计数据、货币政策声明情绪等。可以概括市场的整体状态。第三,金融数据表现出非常低的信噪比。鉴于像神经网络这样最强大的模型是低偏差和高方差的学习器,这意味着模型将过度适应数据中的噪声。总而言之,在金融领域,我们没有几十亿张猫图片来训练模型;金融猫也大多看起来像噪音,如果环境温度低于零度,它们可以在每个闰年的第三个星期四以未知的概率变成绦虫或猫头鹰。
上述所有问题意味着,我们不能依赖绞肉机方法,简单地插入所有可用的原始数据,希望算法将拾取重要的特征,而不会严重过度拟合固有噪声。幸运的是,我们在回报可预测性方面有几十年的研究,基本上是在做功能工程。更重要的是,这些工程特征在它们预测回报的能力背后有一些理论或经验上的正当理由。
例如,帖子顶部的数字显示了 2009 年初多空标准动量策略(即买入过去的赢家,卖出过去的输家)的回报率暴跌。标准的动量交易是根据股票在过去 12 个月的表现来买卖股票,跳过最近一个月,它通常被称为 12-1 动量交易。崩盘的机制很好理解:单个股票回报率的大部分差异都可以归因于一个因素——市场。当市场上涨时,表现出与市场高度同步的股票表现优于与市场相关性较低的股票。在市场低迷时期,情况正好相反。我们可以通过估计斜率系数来衡量共同运动的规范化程度,或在以下股票收益率对市场收益率的简单线性回归中估计β、T3,也称为市场模型:
其中回归的截距,或 alpha,衡量股票 i 收益中与市场正交的部分。到 2007 年底,美国股市进入低迷期,到 2009 年初市值损失了一半以上,因此 12-1 momentum 策略投资于低贝塔股票,这些股票在 2008 年市场崩溃中相对未受影响,并做空损失最大的高贝塔股票。请注意,策略或投资组合是其组成部分的线性组合:多头头寸的低贝塔减去空头头寸的高贝塔导致投资组合的总体贝塔为负。换句话说,在 2009 年初,12 比 1 的势头与市场背道而驰。当市场迅速反弹时,这一势头遭受了大萧条后历史上第二次最严重的崩溃,在此期间,12 比 1 的势头踩在同一耙子上。图 1 通过绘制标准普尔 500 指数(顶部面板)的值以及单个股票过去的赢家和输家之间的平均一年市场贝塔值的差异,提供了一个直观的说明。动量策略的平均贝塔值在 2009 年 6 月才再次变为正值,当时市场已经比最低点回升了约 25%。
Figure 1: S&P 500 and market beta of momentum strategy
参见丹尼尔和莫斯科维茨(2016) 了解更多关于动量碰撞的信息。
参见这篇文章的第 2.1 节,作者 Boris B 举例说明为什么某些特征作为 ML 算法的输入变量是有意义的
事实上,现有的研究可以为一个好的模型应该能够解释什么提供有力的见解。几段推理立刻给我们一种直觉,市场回报、贝塔系数及其相互作用可能是至关重要的特征。事实上,上面看似简单的单变量回归提供了两个具有经验和理论支持的额外特征:截距或 alpha 的估计值,以及衡量特质波动率的残差的标准差。这里的关键点是,我们可以利用我们对预测回报的特性及其转换的先验知识,设计一组更简洁和可解释的变量,而不是将回报的整个时间序列输入模型,希望它能够自己计算出估计值,并冒着遇到本节开头概述的问题的风险。
我甚至没有触及数据质量问题,这本身是一个重要的话题,但对于动量研究来说是一个较小的问题,因为价格数据与基本会计比率相比相当干净,例如,基本会计比率可以滞后报告,并受到数据提供商的修订,这意味着我们用于训练模型的数据可能与我们在实际应用中的数据有很大不同。
我向对机器学习应用中金融数据的警告感兴趣的读者推荐阿诺特、哈维和马科维茨(2019) 。
三。模型和数据
A .型号
我将回报预测任务指定为一个分类问题,并估计股票下个月的回报高于和低于整个横截面的中值回报的概率。股票 i 的预测目标或标签定义如下:
给定股票 i 在 t,X(i,t),的特征向量,预测概率是特征和权重的函数:
我选择最简单的架构——多层感知器——并通过使用 Adam optimizer 最小化二进制交叉熵来训练模型。我进一步在每个迷你批次中执行了类的平等表示,发现这极大地提高了训练的稳定性。为了正规化,我采用提前停止和辍学。
分类提供了几个优于回归的优势,回归是实证资产定价的主要方法。首先,通过构造,标签在时间上具有相同的分布和相同的幅度,从而通过减轻收益率的横截面分布中的时间变化问题来简化训练。第二,由于二元分类覆盖了整个样本空间,假设测量误差是随机的,则高于某个常数(在我们的情况下是横截面中值)的估计回报率与预期回报率成正比。第三,在实践中,我们往往更关心一项资产相对于其同行的预期表现,而不是对其未来回报的点估计。
B .数据
我使用的是 1965 年 1 月至 2018 年 12 月期间美国股票的标准 CRSP 数据集。在应用数据可用性过滤器后,样本中只剩下大约 20,000 只不同的股票。我还特意将分析的主要部分集中在最大股票的子样本上,每月选择市值最高的 500 只股票,将其余股票作为稳健性检查。由此得出的子样本平均覆盖了美国股票市场总资本的四分之三,在每日回报方面与标准普尔 500 在统计上没有区别。关注大盘股的主要原因是,最近的重复研究提供了令人信服的证据,表明预测回报的绝大多数变量的预测能力都集中在小盘股和小盘股上,这在交易成本和交易价格影响是现实的实践中非常重要。
我将预测范围设置为一个月,并将样本划分如下:训练集涵盖了从 1965 年 1 月到 1982 年 12 月的时间,包括 105,177 个股票月样本;验证集是从 1983 年 1 月到 1989 年 12 月(41,408 个例子);并且测试集是从 1990 年 1 月到 2018 年 12 月(170385)。包括所有股票的附加测试集包含超过 1,200,000 个示例。
根据上一节的讨论,我构建了一组特征,这些特征是由先前研究中的发现激发的,并具有一些为什么或如何与预期回报相关联的基本原理。例如,我包括了 10 天、1、2、3、6、12、18、24 个月的市场回报和波动性,或者上一节中估计的 10 天到 12 个月的市场模型回归的 alpha 和 beta。在论文的第二部分可以找到特征的完整列表、它们背后的基本原理以及相应研究的参考文献。
为了便于训练,我将特定股票的变量标准化,即股票的过去收益、贝塔系数、阿尔法系数等。,通过计算每个时间段的 z 分数。对于市场波动和回报的时间序列,我计算了相对于他们自己的历史到估计日期的 z 分数,以避免前瞻偏差。
四。选择最佳神经网络结构并构建集成
A .超参数优化
深度学习模型对决定模型架构和指导估计过程的超参数的选择非常敏感。模型的性能通常更多地取决于超参数,而不是特定模型的复杂程度。 Bergstra 等人(2013) 认为超参数调整应该是模型评估的正式、量化和可重复的一部分。 Bergstra 等人(2011) 介绍了 TPE 算法——一种允许将超参数调整任务形式化为外部优化问题的顺序贝叶斯优化技术。他们证明 TPE 优于手动和随机搜索。该算法的思想是从超参数 θ 的先验分布开始,将损耗建模为 θ 的随机函数,然后从与低于某个阈值的损耗值相对应的“良好”分布中采样超参数,并挑选最大化下一个优化步骤的预期损耗改善的超参数值。随着优化的进行,采样的超参数收敛到它们的真实值。算法的正式数学描述可以在我论文的附录中找到。以下是几个链接,其中举例说明了如何在 Python 中使用 TPE 和其他超参数优化算法:
一个教程由 Vooban
应用一个密切相关的方法——高斯过程由 Boris B
贝叶斯优化算法由 Yurii Shevchuk 在纽皮
一个教程由 Dawid Kopczyk
我将超参数优化目标函数定义如下:对于一组超参数值,我首先估计模型五次,并挑选每个模型实现的验证损失的五个最佳值,目标值是这 25 个值的平均验证损失。由于训练在很大程度上是随机的,我明确地寻找能够在每次评估运行中和不同运行之间持续实现较低损失的架构。表 1 报告了超参数的先验分布:
Table 1: Hyperparameter priors
我使用随机搜索对目标进行 25 次评估来初始化算法,然后执行 700 次 TPE 迭代。图 2 描绘了 TPE 优化过程中的平均损失:蓝点是最佳 50%评估的损失;红色实线是扩大的第一个十分位数的损失,黑色虚线表示每个 TPE 步骤达到的最小损失。
Figure 2: TPE optimization progress
随着时间的推移,该算法不断提出更好的超参数配置。下图显示了 TPE 如何在迭代过程中调整超参数的分布,绘制了 TPE 优化的前半部分(蓝色)和后半部分(红色)的学习率(左侧图)和辍学率(右侧图)的十进制对数的先验(黑色虚线)和经验密度:分布向学习率的低值和辍学率的高值收敛。
Figure 3: Distributions of hyperparameters during TPE optimization
B .最优系综
神经网络是低偏差和高方差算法,因此像模型集成这样的方差减少技术提供了巨大的优势,同时计算成本低廉。更重要的是,我们可以以简单的方式为集合的每个成分的预测分配最优的权重,而不是简单地平均几个模型的预测。我挑选了在超参数优化过程中实现最低验证损失的 20 个模型规范作为集成的初始候选,然后遵循卡鲁阿纳等人(2004) 算法:从具有最佳模型的大小为 1 的集成开始,每次迭代我从模型池中添加一个新模型(带有替换),使得集成的平均预测产生最低的验证损失。图 4 绘制了算法迭代过程中的集合验证损失:黑色虚线对应于最佳模型的损失,蓝色实线绘制了优化过程中的集合损失。
Figure 4: Validation loss during ensemble optimization
在大约 12 次迭代之后,该算法停止考虑新的模型,而是继续调整现有成分的权重。由于集成优化在计算上是廉价的,所以我在测试集上的每次预测之前,使用新的可用信息重新优化集成。
动词 (verb 的缩写)测试集结果和预测的可解释性
答:样本外结果
首先,为了衡量模型对看不见的数据进行归纳的能力,让我们看一下测试集损失。图 5 绘制了总体损失相对于其验证损失的曲线(黑色虚线归一化为 1)。红线表示测试集的平均损失,灰线表示每个月所有股票的平均损失,蓝线表示这个平均值的 12 个月的滚动平均值。就损失而言,与验证集相比,模型的测试集性能平均下降了约三分之一个百分点。这并不奇怪,因为我使用相同的验证数据估计了数百个规范:在验证集上尝试的规范越多,最好的模型偶然超过验证集的可能性就越大——这一点要永远记住。尽管如此,差异还是很小。更重要的是,随着时间的推移,测试损失是稳定的,围绕其长期均值波动。
Figure 5: Test set loss
回想一下,该模型输出了下个月的回报率高于横截面中值回报率的估计概率。因此,我们可以直接将预测转化为投资策略,在给定的预测概率范围内购买股票。表 2 报告了最大的 500 只股票样本的等权重投资组合的回报(超过无风险利率)的描述性统计数据。例如,第一组三列报告中位数排序的统计数据:投资于预测概率低于中位数预测概率的股票的投资组合(第一列);高于这个概率(第二列);多空投资组合卖出第一个投资组合中的股票,买入第二个投资组合(第三列)中的股票。类似地,第二个和第三个三元组报告最低和最高预测概率组合的统计数据,概率分别分成五分位数和十分位数。均值、中值回报及其标准差以百分比表示。夏普比率衡量每单位风险的回报,按年计算;最大提现(一项投资经历过的最差回报),最大单月亏损和平均月成交量以百分比表示。括号中的数字是均值回报等于零的零假设的 HAC t 统计量。
Table 2: Descriptive statistics of ensemble portfolios: 500 largest stocks
有效做空一半标准普尔 500 成份股并投资另一半的投资组合平均年收益率为 7.2%,这在任何传统水平上都具有显著的统计意义。随着极端十分位数投资组合之间的差异越来越大,高投资组合和低投资组合之间的差距扩大到每年 17.7%。这种增长同时来自“高”和“低”投资组合的较高(较低)回报,为模型捕捉预期回报的横截面分布提供了证据。中位数和十分位数的年度夏普比率分别从 1.11 升至 1.34。对于更集中的种类,投资组合的回报也变得更加正偏。相比之下,同期美国股市的超额收益率为 7.1%,夏普比率为 0.48,最大提取率超过 50%。
下图描绘了投资于整体投资组合的 1 美元的价值(以自然对数表示)。顶部和底部的子图分别显示最大的 500 只股票和所有股票的结果。左图描绘了根据预测概率中值(蓝色实线和虚线)排序的高低投资组合的回报,以及整个股票市场的超额回报(黑色)。右边的面板显示了多空投资组合的回报:中位数、五分位数和十分位数分别用蓝色、红色和灰色绘制。关于“所有股票”样本,表现甚至进一步改善:例如,十分位数投资组合(右下角面板中的灰线)之间的平均收益率差增加到每年 22.3%(t 统计值为 10.5),夏普比率上升到 2 以上。然而,这些原始数据是根据 g̵r̵a̵i̵n 的一卡车盐得出的,没有仔细分析交易成本和可交易性问题。
Figure 6.a: Out-of-sample performance of ensemble portfolios: 500 largest stocks
Figure 6.b: Out-of-sample performance of ensemble portfolios: all stocks
现有的风险因素能解释整体投资组合的回报吗?
不,他们不能。表 3 报告了时间序列跨度测试的结果,即 Fama 和 French (2015) plus momentum 投资组合的五个因素对总体投资组合超额收益的回归(关于 Fama-French 因素的简要讨论可参见此处)。这些回归的目标是确定测试资产(在我们的例子中是神经网络投资组合)的回报是否可以表示为因素(通常是以前建立的非零回报投资策略,如市场风险溢价)的线性组合。在零假设下,测试资产被因子跨越,回归中的截距或 alphas 为零;斜率估计值衡量测试资产的回报与给定因素的回报的相关程度。
Table 3: Spanning tests, 6-factor model
对于表 3 中的每个测试资产(跨行),第一列报告了估计截距α,单位为百分比 p.a,接下来的六列报告了因子的系数,最后一列显示了回归的调整 R。从这一练习中得出的关键结论是,整体投资组合的回报不能被其他风险因素捕捉到,从而产生大量具有统计显著性的阿尔法值。P2-P1 的长短结合投资组合的回报基本上与任何解释变量都不相关。在论文中,我进一步表明,这一结果适用于其他投资组合类别,并且当这组因素包括对冲基金回报和当前金融机器学习文献中其他投资组合的回报时,这一结果是稳健的。
c .哪些特征推动了绩效?
让我们回顾一下目前我们所掌握的信息:
1.该模型很好地概括了样本外的情况,并捕捉到了预期回报的横截面分布。
2。基于整体预测的投资组合会产生高回报,且具有统计学意义。
3。整体投资组合的表现与其他投资策略和既定风险因素无关。
跳过头寸规模和交易成本的重要话题,让我们关注哪些特征推动了预测,它们是如何做到的,以及它是否有意义。
图 7 显示了相对于模型输入,股票回报高于下个月横截面中值回报的预测概率的偏导数。根据平均梯度排列的顶部和底部 10 个输入变量横跨纵轴。对于给定的特征,彩色条和晶须分别代表测试集上所有梯度评估的四分位数和 5–95%范围。每个条形内的黑色实线和圆点表示梯度的中值和平均值。由于变量被标准化为均值为零,标准差为一,解释如下:在其他条件不变的情况下,一只股票的一年 alpha 相对于横截面增加一个小的δ,会使股票收益在下个月高于横截面中位数的预测概率增加大约 100×δ%。
Figure 7: Gradients of predicted probabilities w.r.t. inputs
本质上,上图报告了无条件的预期收益预测值。预测正回报的最显著的横截面特征是 9 个月到 1 年的市场模型 alpha,以及 6 个月和 1 年的价格动量。事实上,一年的 alpha 非常稳健:在超过 170,000 个观察值中,只有两个相对于该变量具有负梯度。在无条件预测因素中,唯一的市场状态变量是 2 年的市场回报。除了与短期反转和信息离散性一致的短期价格特征外, fip (旨在衡量回报是以几次大的跳跃还是以许多小的增量累积的特征),价格动量和市场模型 alpha 在 7 至 8 个月的时间范围内是低预期回报的主要预测因素。事实上,价格动量对预测概率的最大积极贡献出现在 6 个月和 12 个月的回望期,下图(图 8)显示了预测概率相对于价格动量(左图)和市场模型 alpha(右图)对回望期的平均偏导数。少于一个月的跨度被聚集到一个月的仓位中。另一方面,在短于 9 个月的时间范围内,alpha 的贡献恢复为负值。一个特殊的特征是,在六个月的时间范围内,两个变量的梯度都比周围回望期的高得多。总的来说,上面概述的影响与金融文献中的经验证据一致(我在文中提供了参考相关研究的详细讨论)。
Figure 8: Gradients of predicted probabilities w.r.t. to inputs by lookback horizon
如果预测更高预期回报的主要特征是 alpha 和动量,那么为什么多空组合投资与使用这些变量的投资策略无关,例如使用过去回报的动量,以及当动量在 2008-2009 年期间受到压制时,这些投资组合如何设法表现出非凡的表现?答案是:功能与市场状态变量的相互作用。
图 9 显示了根据预测概率排序的长短十分位数投资组合的 10 个最大和最小平均梯度。梯度的解释变得有点麻烦,例如:在其他条件相同的情况下,10 天市场回报的一个小的δ变化平均会将股票在投资组合长线中的预测概率增加 0.2×100×δ%。尽管许多变量是回报的相当强的无条件预测器,但多空神经网络投资组合并不简单地买入一年的 alpha 并卖出短期动量。事实上,该投资组合并未表现出任何系统性的横截面特征风险,其幅度与仅做多案例中的风险相似。当然,平均而言,投资组合倾向于押注于贝塔系数、信息离散性和短期特质波动性,但大约有 25%的股票月押注相反。平均而言,投资组合也具有长期市场波动性和市场回报,但这些梯度的变化也是显著的。市场状态变量的优势以及梯度方面的分散赌注使得表 3 中的时间序列测试中的经典静态资产定价因子在捕捉神经网络投资组合回报的变化方面几乎没有解释力,这并不令人惊讶。
Figure 9: Gradients of predicted probabilities of long-short portfolio
为了证明市场状态特征如何调节横截面特征的重要性,我绘制了长-短十分位数投资组合的 Hessian 分割图,包括 alpha(图 10)、beta(图 11)和市场状态特征(横轴)。随着市场波动性上升,长期衡量的阿尔法值(以及价格动量,因为两者高度相关)的重要性下降,而短期阿尔法值的梯度上升。最长三个月的市场回报正好相反。换句话说,在不景气的市场中,当回报率低而波动性高时,该模型会动态地将更多的重要性分配给近期表现。
Figure 10: Second order effects, impact of market state features on alphas
Figure 11: Second order effects, impact of market state features on betas
对贝塔系数来说,市场波动性增加的影响总体上是积极的,除了短期。如果类似期限的市场回报高于其长期平均水平,则贝塔系数在更长的期限内获得更高的梯度。短期市场回报非常积极地调节贝塔系数,例如,允许直接利用第二节中讨论的病态动量行为:当市场趋势恢复向上时,即短期市场回报增加时,关于贝塔系数的预测梯度也增加,这对于 10 天市场回报尤为突出。
不及物动词结束语
当然,拥有将传统金融预测方法打得落花流水的模型是件好事,但《邮报》的信息更加微妙:
首先,正确处理数据在金融机器学习中至关重要:除了确保数据集的质量,提出关于哪些功能应该工作以及为什么工作的假设或心理模型也是有用的。这至少有两个目的:(I)通过消除主导原始数据的噪声,工程特征使得算法更容易学习输入和预测之间的关联;(二)缓解了倾听的问题——在结果已知后的假设——人类非常擅长愚弄自己。
其次,自动化超参数优化不仅允许以系统的方式搜索性能最佳的架构,更重要的是,它还有助于结果的再现性。
第三,预测的可解释性对于理解模型如何工作以及结果是否通过健全性检查至关重要。此外,掌握模型在什么条件下会失效也很关键。
欢迎评论和反馈。感谢您的阅读。
参考
r .阿诺特、C. R .哈维和 h .马科维茨(2019 年)。机器学习时代的回溯测试协议。《金融数据科学杂志》, 1 (1),64–74。在 https://ssrn.com/abstract=3275654有售
伯格斯特拉、J. S .、巴登内特、r .、本吉奥、y .、凯格尔、B. (2011 年)。超参数优化算法。在神经信息处理系统的进展(第 2546–2554 页)。
伯格斯特拉,j .,亚明斯,d .,,考克斯,D. D. (2013)。创建模型搜索的科学:视觉架构的数百维超参数优化。
Caruana,r .,Niculescu-Mizil,a .,Crew,g .,& Ksikes,A. (2004 年 7 月)。模型库中的集成选择。在第二十一届机器学习国际会议论文集(第 18 页)。ACM。
丹尼尔,k .,&莫斯科维茨,T. J. (2016)。动量崩溃。财经杂志, 122 (2),221–247。在https://ssrn.com/abstract=2371227有售
Fama,E. F .,& French,K. R. (2015 年)。五因素资产定价模型。财经杂志, 116 (1),1–22。
深度学习和 SAR 应用
原文:https://towardsdatascience.com/deep-learning-and-sar-applications-81ba1a319def?source=collection_archive---------3-----------------------
地球观测应用的进展和挑战概述
High resolution (25cm) SAR data from F-SAR, a DLR airborne system. Image courtesy of DLR, the German Aerospace Center
介绍
虽然深度学习的炒作周期似乎正在消退一点(神经网络人工智能很简单!),神经网络和计算机视觉的复兴正在成为常态,在过去五年中,这些技术在遥感领域出现了许多有用的应用。目标检测和土地覆盖分类似乎是深度学习在遥感中研究最多和商业化程度最高的应用,但还有许多其他领域也受益于,如数据融合、3D 重建和图像配准。深度学习在遥感中日益广泛的使用是由于两个趋势:1)无处不在、易于使用的云计算基础设施,包括 GPUs2)易于使用的机器学习工具的开发和越来越多的采用,如谷歌的 Tensorflow、AWS SageMaker 和许多其他的开源框架;以及 3)一个不断扩大的服务生态系统,用于创建带标签的训练数据(规模、数字 8)以及开放的带标签数据集,如 AWS 上的SpaceNet。
深度学习、神经网络和计算机视觉近年来也越来越频繁地用于合成孔径雷达(SAR)数据。大多数领先的卫星地球观测分析公司,如 Orbital Insight 、笛卡尔实验室和 Ursa 已经在其分析工作流程中扩大了 SAR 数据的使用。据我所见,从这些技术的使用中受益最大的领域是:目标检测(自动目标识别)、土地覆盖分类、变化检测和数据扩充。最近似乎也有一些关于深度学习的应用如何有利于干涉 SAR 分析的调查。然而,使用 SAR 数据进行深度学习存在一些挑战。其中,明显缺乏大的标记训练数据集,并且因为 SAR 数据具有斑点噪声,并且比光学数据稍不直观,所以对于人类标记器和模型来说,正确地对特征进行分类可能是一个挑战。
我将重点介绍一些将受益于深度学习和高重访、高分辨率 SAR 数据的应用,比如来自五车二星座的数据。我还将概述一些挑战,五车二希望帮助更广泛的 SAR 用户群体解决这些挑战。
目标检测
Automated target recognition with a CNN and the MSTAR dataset.
SAR 深度学习应用的大多数研究和开发都是针对对象检测和土地覆盖分类的。在合成孔径雷达领域,目标检测通常被称为自动目标识别(ATR)。ATR 的研究在 90 年代获得了动力,起源于军事应用,但后来扩展到广泛的民用商业用途。文献中已经研究了一系列 ATR 问题,从在已知地形和杂波中找到一个很好理解的目标,到根据视角和其他目标的遮挡识别可能具有明显不同的 SAR 响应的目标。一般来说,这个问题涉及到寻找相对较小的目标(车辆、船只、电力基础设施、石油和天然气基础设施等)。)在杂乱主导的大场景中。
最近,卷积神经网络(CNN)的使用提高了各种目标的目标识别模型的性能。CNN 在 SAR ATR 中的首次出现似乎是在最近的 2015 年,当时证明了 CNN 的使用与当时被认为是最先进的其他方法具有竞争力。其他人已经扩展了这项工作,并且展示了 MSTAR 数据集中特征的> 99%的分类准确率,其中包括军用车辆。近年来,更多使用 CNN 的民用和商用例子不断涌现,包括一个绘制电网图的项目,一个辨别船只和冰山的竞赛,以及一些识别浮油钻井平台的研究。到目前为止,我接触到的大部分工作都集中在雷达反向散射图像上,但一些论文强调了使用相位数据获得额外目标信息的潜力。
土地覆盖分类
Classifying sea ice depth from Sentinel-1 data using a CNN.
较大特征和土地覆盖的分类也受益于深度学习方法和独立于天气的可靠 SAR 监测的应用。虽然使用神经网络进行 SAR 数据分类并不新鲜,但自 2015 年引入完全卷积神经网络以来,深度学习用于土地覆盖分类的使用似乎大大增加了。已经有很多研究在探索使用 CNN 对常见土地覆盖进行分类的可行性,比如道路、建筑、洪水、城市区域和农作物。深度学习还被用于一些有趣的非典型土地覆盖(或水覆盖)应用,如识别石油泄漏和对不同厚度的海冰进行分类。通常,深度学习的使用优于经典方法,尽管它在时间和计算成本上可能不会更有效。然而,与所有监督学习技术一样,性能高度依赖于标记训练数据的质量。
变化检测
Detecting urban change in UAVSAR data using stacked autoencoders.
高分辨率、高节奏的 SAR 数据非常适合变化检测应用,因为它能够看穿云层并捕捉反射能量振幅和相位相干性的变化。我惊讶地发现,对于深度神经网络在 SAR 数据变化检测中的应用,已经有了如此多的研究。与主要使用 CNN 的目标检测不同,已经有多种神经网络方法用于解决识别 SAR 数据中表面变化的问题。一般来说,这些方法要么依赖于对多时相叠加的土地覆盖进行分类,然后比较分类后的结果,要么对多时相数据之间的辐射差异或相位差进行分类。有使用受限玻尔兹曼机器、 PCANet 、堆叠自动编码器和多层感知器、监督收缩自动编码器(sCAE)和聚类、 sCAEs 和模糊 c 均值以及 CNNs 的后一种方法的例子。还有另一类有趣的方法,使用 SAR 和光学图像作为输入,并使用深度卷积耦合网络来识别异构数据的变化。大多数研究得出结论,深度学习方法比以前使用马尔可夫随机场和主成分分析的方法表现出更好的性能(更低的假阳性和假阴性率)。
变形监测和 InSAR
在使用深度学习方法分析干涉图或支持 InSAR 处理方面,似乎迄今为止还没有太多的研究。然而,有证据表明人们对这一领域感兴趣,一些早期研究使用 CNN 识别包裹阶段的变形模式,以及资助的项目将深度学习方法集成到 InSAR 处理链中。在将深度学习方法应用于相位展开方面,也有一些更广泛适用的工作。我们很可能会在未来几年看到更多关于这些主题的公开研究,因为各种机构都有公开的博士职位,专注于将机器学习应用于 InSAR 工作流。
数据扩充
Generating High Quality Visible Images from SAR Images Using a GAN.
已经有一些有趣的研究将 CNN 和生成对抗网络(GANs)应用于 SAR 数据增强和数据融合。一个有益于目标探测的研究领域是使用CNN 来估计和减少 SAR 振幅数据中的斑点噪声。结果是通过单个前馈过程产生“干净”的 SAR 图像。还可以使用 GANs 提高 SAR 数据的表观分辨率。在文献中,有从 Sentinel-1 分辨率到 TerraSAR-X 分辨率的图像转换的例子。虽然这些方法似乎不能很好地保持特征结构,但它们对 SAR 的超分辨率和风格转换的未来是一个有趣的观点。还可以使用 GANs通过去斑点和彩色化使高分辨率 SAR 数据看起来更像光学图像,这可以帮助 SAR 图像的视觉解释。现在有新的数据集可用,这将有助于推进这种类型的工作和其他需要 SAR 和光学数据融合的应用。
挑战
当我回顾关于这些应用的文献时,一个共同的挑战是显而易见的:缺乏高质量的标注 SAR 训练数据,特别是在高分辨率下。与所有监督学习方法一样,模型的性能和结果高度依赖于训练数据输入。最常用的高质量训练数据集是 MSTAR 数据集,但它只包含有限数量的军事特征。其他研究人员已经求助于创建他们自己的带注释的训练数据集,但是组装大型全球数据集可能会非常昂贵,因为高分辨率源数据的选项有限,并且很少有开放许可证(例如 UAVSAR )。有一些方法可以通过模拟和迁移学习来增强训练数据,但您仍然需要一个合理的数据集作为起点。我计划在以后的博客文章中讨论这一挑战、一般的搜救训练数据以及五车二的设想。
五车二致力于通过支持为各种商业和政府用例创建大型高分辨率标记 SAR 训练数据集的工作,为使用 SAR 数据开发深度学习应用的社区做出贡献。如果您正在使用航空或卫星 SAR 数据进行对象检测、变化检测和其他深度学习应用, 我们希望收到您的来信 ,了解更多关于您的工作和您面临的挑战。
深度学习和土壤科学—第 3 部分
原文:https://towardsdatascience.com/deep-learning-and-soil-science-part-3-c793407e4997?source=collection_archive---------17-----------------------
土壤光谱学和迁移学习
这是我致力于深度学习在土壤科学中的应用的系列文章的第二篇。这是一个正在进行的系列,到目前为止还包括:
[## 深度学习和土壤科学—第 1 部分
预测土壤性质的土壤光谱学。根据光谱图预测多种土壤特性的多任务卷积神经网络。
towarsdatascience.com](https://medium.com/@spadarian/deep-learning-and-soil-science-part-1-8c0669b18097) [## 深度学习和土壤科学—第二部分
使用上下文空间信息的数字土壤制图。从点信息生成土壤图的多任务 CNN。
towardsdatascience.com](/deep-learning-and-soil-science-part-2-129e0cb4be94)
其他与地球科学相关的文章:
[## 用 SHAP 解释 CNN 生成的土壤地图
使用 SHAP 来证实数字土壤制图 CNN 捕捉到了合理的关系。
towardsdatascience.com](/explaining-a-cnn-generated-soil-map-with-shap-f1ec08a041eb) [## GeoVec:用于地球科学的单词嵌入
词语嵌入的类比、分类、关联和空间插值。
towardsdatascience.com](/geovec-word-embeddings-for-geosciences-ac1e1e854e19)
在系列的第一部分中,我介绍了一个多任务卷积神经网络(CNN ),用于从光谱数据中同时预测多种土壤特性。我们观察到,与传统方法相比,预测误差显著降低,这要归功于 a)CNN 处理复杂信号的卓越能力,以及 b)多任务学习的协同效应。
在这篇文章中,我将谈论土壤光谱学背景下的迁移学习。这是之前工作的延伸,所以我将跳过土壤光谱数据、光谱图和多任务学习等概念。
语境
规模问题
据信,在特定区域或土壤范围内生成的模型在该区域表现最佳,而在应用于其他对比土壤类型时表现不佳。在土壤学中,土壤属性的高度空间依赖性意味着为特定区域生成的模型应在该空间域之外小心使用,因为它们可能会失去有效性。反过来,将全球、大陆或国家光谱库应用于局部地区或区域也会有问题。国家模型在该国的局部地区应用时往往表现不佳。当在国家一级应用全球模式时,观察到同样的情况。这是可以理解的,因为全球或国家模型通常能够捕捉到跨越不同土壤类型的更广泛的总体趋势。另一方面,局部区域可能具有全球模型无法捕捉的短尺度变化。
本文使用的术语“全球”模型是指基于大规模光谱库(本系列第一部分的中使用的同一欧洲光谱库)校准的模型,而“本地”是指“全球”数据集(国家)内的一个区域。全局和局部模型都是有价值的,理想情况下,我们希望将从更一般的全局模型中学到的一些规则转移到局部领域。在机器学习中,这种共享域内信息的过程被称为迁移学习。
这项工作旨在评估迁移学习的有效性,将通用土壤光谱校准模型“本地化”到一个国家的背景下,模拟全球数据集对当地用户不可用的情况。据我们所知,这是迁移学习首次应用于土壤光谱建模。
迁移学习
“我手上的一幅连环漫画是关于制造专家系统的公司之间的工业间谍活动的。一家公司通过开发超级专家系统获得了市场领先地位,另一家公司雇佣了一名间谍来了解他们是如何做到的。这名间谍闯入另一家公司,却发现他们正在捕获人类专家,取走他们的大脑,将他们切成薄片,然后将这些薄片插入他们最畅销的模型中。”
哈利·柯林斯。人类、机器和知识结构。
Original image: https://pixabay.com/photo-1787622/
作为人类,我们能够将之前获得的知识应用到具有相似特征的任务中。迁移学习,也称为归纳学习,是 ML 的一个分支,试图模拟这一过程。在我们的特殊情况下,给定一个全局数据域 G 和一个局部数据域 L ,以及 L ⊂ G ,传统的 ML 方法认为两个域是不同的,生成两个独立的模型, f ( G )和 f ( L )。相比之下,承认 G 和 L 在某种程度上相关,迁移学习能够使用由 f ( G )结合数据域l’、⊆l所学习的部分概括来生成模型f(l’)。值得注意的是,在实践中,有可能|L '|<|<|L|,这给迁移学习带来了相当大的优势,尤其是在数据收集和分析有限的情况下。
Global and local domains.
该过程背后的逻辑是,在第一次训练中(在全局数据集上),算法生成光谱数据性质的内部表示。为了成功地学习这种表示,模型需要大量的观察,这正是全局数据集所提供的。在随后的训练(在本地数据集上)中,模型已经“知道”光谱数据如何表现,只需要足够的观察来微调模型并将其调整到本地条件。
模型
我们使用多任务 CNN 同时预测有机碳含量、阳离子交换容量、粘土含量和 pH 值。我们比较了 3 种类型的模型:
- 本地:仅利用相应国家的数据。从可用数据中,我们随机保留了 10%作为测试数据集。其余数据中,90%用于训练,10%用于验证和超参数选择。
- 全球:从整个 LUCAS 数据集(约 20000 个来自欧洲各地的样本)中,排除了对应国家的数据。其余数据中,90%用于训练,10%用于验证和超参数选择。
- 转移:相应国家的训练集用于“本地化”先前用全球数据训练的全球模型。相应国家的验证集用于超参数选择。
整个转移过程可总结如下图:
“Localisation” of a global model. Coloured Layers represent trained weight, which are not modified after being learned.
结果
逐国
在 21 个国家中的 18 个国家,与当地和全球模型相比,迁移学习显示至少一种土壤特性有显著改善。四个国家在所有四个方面都有显著改善。即使在没有发现显著变化的情况下,转移模型也有降低平均 RMSE 的明显趋势。在 14 个国家中,所有四项资产的平均 RMSE 都有所下降,在总共 84 项国家和资产组合中,有 76 项(90.5%)有所下降。与第二个表现最好的模型相比,转移模型产生的平均 RMSE 减少量分别为 OC、CEC、粘土和 pH 值的 10.5%、11.8%、12.0%和 11.5%。
在少数情况下,转移模型的性能比全局或局部模型差。原因是全局模型的误差远大于局部,产生负迁移。在实践中,当开发局部模型时,通过在训练期间跟踪模型的性能来确定源模型(全局)是否有益,或者是否需要更积极的转移总是有用的。理想情况下,当正转移发生时,转移模型的误差应显示较低的初始和最终量值,如下所示。
最后的话
迁移学习被证明是有效的本地化一个通用的土壤光谱校准模型产生的大陆数据集。对于本研究中考虑的大多数国家而言,与使用全球模型(一般模型)或地方模型(仅使用各自国家的数据生成)相比,都有所改善。
我们的发现也强调了全球数据库的重要性。它们对于理解行星尺度的过程至关重要,但对于补充我们在局部尺度的知识也很重要。合作对每个人都有好处,甚至对数据丰富的国家或组织也是如此。
迁移学习模型不要求全局数据集可用于本地培训。一旦校准了全局模型,就只能共享需要重新训练的模型。这是数据隐私问题的潜在解决方案。重要的是要记住,如果全局数据集对本地用户可用,则所提出的方法也是适用的。
引用
关于这项工作的更多细节可以在相应的论文中找到。
Padarian,j .,Minasny,b .和 McBratney,A.B .,2019。迁移学习定位大陆土壤 vis-NIR 校准模型。Geoderma(出版中)。
https://www . research gate . net/publication/330145641 _ Transfer _ learning _ to _ localise _ a _ continental _ soil _ vis-NIR _ calibration _ model
用于分离快分量和慢分量的深度学习方法
原文:https://towardsdatascience.com/deep-learning-approach-for-separating-fast-and-slow-components-2e6142d041dc?source=collection_archive---------19-----------------------
一些背景
(这项工作的幻灯片可以在 https://speaker deck . com/jchin/decompositing-dynamics-from-different-time-scale-for-time-lapse-image-sequences-with-A-deep-CNN 找到)
在经历了 9 年帮助单分子测序对科学界变得有用的冒险后,我辞去了在 PacBio 的研究员工作(见我在 PacBio 头几年的故事)。我的大部分技术/科学工作都与 DNA 序列有关。虽然有一些令人兴奋的深度学习方法可以解决一些有趣的问题,但我确实喜欢探索 DNA 测序空间之外的一些东西。
我不久前加入了 DNAnexus。该公司已成为生物数据/测序数据处理云计算平台的领导者。我认为用该平台演示开发除 DNA 序列之外的生物数据的深度学习模型是有用的。怀着这样的目标,前首席安全官 Andrew Carroll 和我决定看看我们能为一些生物成像相关的工作做些什么。
当我们在寻找一些例子的时候, Gene Myers (是的,第一个完成全人类基因组鸟枪法组装的人)发表了一个工具 CSBdeep 来自德国德累斯顿马普分子细胞生物学和遗传学研究所(MPI-CBG) 的他的实验室用于从光片共焦图像中创建超分辨率图像,用于研究生物发育过程。
Example of using CSBDeep to archive super-resolution: Left: the original images. Right: the super-resolution images generated by CSBdeep. The image is provided by Ying Gu Lab.
受 CSBDeep 论文的启发,Andrew 联系了一位正式的合作者, Ying Gu ,看看她是否有一些有趣的图片让我们在我们的平台上演示使用 CSBDeep。利用 DNAnexus 云计算平台,重现 CSBDeep 结果并将其应用于新图像相对容易。尽管如此,我在想我们是否可以做一些不同的,新的事情,至少对我来说。
一部电影不仅仅是静态图像,它更有趣
原来,英古的研究工作是跟踪涉及纤维素合成的特定蛋白质,解决生物能源的重要问题。我们得到的图像是追踪细胞内分子的延时电影。最初,我认为我们可能能够通过使用多帧的深度学习来实现超分辨率。虽然我们在这个问题上取得了一些初步的成功,但我却“分心”去解决另一个不同的问题。
In the image stack, the slow changing background contributes to the non-zero auto-correlation at longer timescales.
当我看延时电影时,很难不注意到一些背景成分(例如,植物细胞的主干微管),以及以不同速度移动的不同斑点或粒子。我认为可以使用深度学习(作为一种无监督的学习方法)来分离背景,慢速组件和激活组件。
在这样的延时电影中,我们怎样才能把运动部分和静止部分分开呢?
第一,背景图的获取其实并不太难。我们可以对堆栈中的所有图像的每个像素取平均值或中值来获得背景。为了得到前景图像,我们可以从每幅图像中减去平均背景。如果背景真的是静态的,这应该是最容易做到的事情。然而,这种方法也假设只有一个有趣的“前景”事实上,潜在的生物过程可能具有不同的组件,这些组件具有不同的动态范围,我们可能能够使用深度学习架构来分解不同的组件。
From (T — ∆t) to T: If ∆t is longer than the typically “faster” components, then we can
catch the slow component using such autoencoder architecture.
使用多个自动编码器预测不同时间尺度的未来
这样的延时电影有什么背景?在深度学习神经网络架构中,自动编码器可以学习具有隐藏层的简化表示,以再现输入。训练期间的损失函数通常是输出和输入之间的 L2 差。如果我们认为背景是电影的不变部分,我们应该希望我们可以使用这样的自动编码器来学习简化的表示,该表示可以从早期的输入预测后期的输出。图像的不变部分在不同的时间点应该可以被自动编码器学习。
我们可以认为,一幅特定时间的图像可以从更早时间不同尺度的特征或成分中重建出来。我们使用自动编码器从(t-∆t)预测时间 t 的图像。如果 t 很大,那么我们希望自动编码器能够学习背景部分。我们可以用更小的 t 来学习更快的部分等等。例如,我们可以将时间 t 的图像构建为 t-8(帧)、t-4(帧)、t-2(帧)和 t-1(帧)的图像的预测组合,以捕捉不同时间尺度的贡献。
沿着这一思路,我们测试了下面的一个建筑展示,用于分解英姑小组生成的延时电影。我认为我们得到了相当好的结果。
From left to right: (a) Original (b) Slow Components (c ) Fast Component (d) Pseudo-color composition from the slow and fast components
其他相关作品
虽然我认为我们提出的方法很有趣,并且很容易用 PyTorch 实现,但肯定有一些以前的工作解决了类似的问题。例如,Mikael Henaff、Junbo Zhao 和 Yann LeCun 的论文“使用误差编码网络 (EEN)在不确定性下的预测”使用从预测误差到潜在空间的反馈机制来获得更好的预测结果。
ENN Model Architecture
视频背景去除是图像处理领域的一个重要研究课题,对此我们并不感到奇怪。我要感谢来自 Grail 的 Earl Hubbell ,当我在 2018 年末的一次当地生物信息学会议上介绍这项工作时,他向我指出了用于视频背景去除的鲁棒 PCA 方法。
利用 DNAnexus 云平台构建深度学习模型
我在这里的一部分练习也是为了作为 DNAnexus 平台的新手练习“吃自己的狗粮”。下面是一个原型的截图,我和我的同事在 DNAnexus 平台上开发了一个支持云的 Jupyter 实验室工作站的集成解决方案。通过这样的集成,我们可以无缝集成数据管理、模型构建和评估。
我们学到了许多关于在 GPU 实例上使用 Jupyter Lab 和 Docker 后端的利弊的经验,并希望我们学到的经验可以帮助我们尽快更好地改进 DNAnexus 产品。
承认
我要感谢小然·辛和应谷与我们分享了他们的研究成果来验证这个想法。我也要感谢安德鲁·卡罗尔把我们连接到英姑的实验室。当然,对于我在 DNAnexus 的同事们帮助我快速入门,以便我可以开始利用这个平台进行有趣的 ML/AI 工作,我永远不会足够感谢。
基于深度学习的超分辨率,不使用 GAN
原文:https://towardsdatascience.com/deep-learning-based-super-resolution-without-using-a-gan-11c9bb5b6cd5?source=collection_archive---------1-----------------------
本文描述了用于图像改善、图像恢复、修复和超分辨率的技术和训练深度学习模型。这利用了 Fastai 课程中教授的许多技术,并利用了 Fastai 软件库。这种训练模型的方法是基于非常有才华的人工智能研究人员的方法和研究,我已经在信息和技术方面归功于他们。
据我所知,我在训练数据中应用的一些技术在这些学习方法中是独一无二的(截至 2019 年 2 月),只有少数研究人员将所有这些技术结合在一起使用,他们大多数可能是 Fastai 的研究人员/学生。
超分辨率
超分辨率是放大和/或改善图像细节的过程。通常,低分辨率图像被作为输入,并且同一图像被放大到更高的分辨率,这是输出。高分辨率输出中的细节在细节基本未知的地方被填充。
超分辨率本质上是你在电影和连续剧中看到的东西,比如 CSI,有人放大图像,图像质量提高,细节就出现了。
我第一次听说“人工智能超级分辨率”是在去年 2018 年初的优秀 YouTube 2 分钟论文中,该论文以对最新人工智能论文的简短精彩评论为特色(通常长于 2 分钟)。当时这看起来像是魔法,我不明白这怎么可能。绝对符合阿瑟·C·克拉克的名言“任何先进的技术都与魔法无异”。我没有想到,不到一年的时间,我就可以训练自己的超分辨率模型,并撰写相关文章。
这是我正在撰写的一系列文章的一部分,作为我在人工智能和机器学习方面正在进行的学习和研究的一部分。我是一名软件工程师和分析师,我的日常工作是成为一名人工智能研究员和数据科学家。
我写这些部分是为了加强我自己的知识和理解,希望这也能对其他人有所帮助和兴趣。我试图用尽可能简单的英语来讲述大部分内容,希望它对任何熟悉机器学习的人来说都有意义,并有一些更深入的技术细节和相关研究的链接。这些主题和技术很难理解,我花了好几个月的时间进行实验和写作。如果你不同意我所写的,或者认为它是错误的,请联系我,因为这是一个持续的学习过程,我会感谢你的反馈。
下面是一个低分辨率图像的示例,对其进行了超分辨率处理以提高其分辨率:
Left low resolution image. Right super resolution of low resolution image using the model trained here.
基于深度机器学习的超分辨率试图解决的问题是,基于传统算法的放大方法缺乏细节,无法消除缺陷和压缩伪像。对于手动执行这些任务的人来说,这是一个非常缓慢和艰苦的过程。
好处是从从未存在或已丢失的图像中获得更高质量的图像,这在许多领域甚至在医学应用中挽救生命都是有益的。
另一个用例是计算机网络间传输的压缩。想象一下,如果您只需要发送一个 256x256 像素的图像,而实际上需要的是一个 1024x1024 像素的图像。
在下面的一组图像中,有五幅图像:
- 要放大的低分辨率输入图像
- 通过最近邻插值放大的输入图像
- 通过双线性解释放大的输入图像,这是您的互联网浏览器通常需要的
- 通过该模型的预测,输入图像被升级和改进
- 目标影像或地面实况,其被缩小以创建较低分辨率的输入。
目标是将低分辨率图像改进为与目标一样好(或更好),称为地面实况,在这种情况下,地面实况是我们缩小为低分辨率图像的原始图像。
Comparing the low resolution image, with conventional upscaling, a deep learning model prediction and the target/ground truth
为了实现这一点,数学函数采用缺少细节的低分辨率图像,并在其上产生细节和特征的幻觉。在这样做的过程中,该功能找到了原始摄像机可能从未记录的细节。
这个数学函数被称为模型,放大的图像是模型的预测。
一旦这个模型和它的训练被解释了,在这篇文章的结尾提到了潜在的伦理问题。
图像修复和修补
为超分辨率而训练的模型对于修复图像中的缺陷(jpeg 压缩、撕裂、折叠和其他损坏)也应该是有用的,因为模型对某些特征应该看起来像什么有概念,例如材料、毛发甚至眼睛。
图像修复是修饰图像以移除图像中不需要的元素(如铁丝网)的过程。对于训练来说,常见的是剪切图像的一些部分,并训练模型来替换丢失的部分,这是基于应该有什么的先验知识。当由熟练人员手动执行时,图像修复通常是一个非常缓慢的过程。
Left an image with holes punched into it and text overlayed. Middle deep learning based model prediction of repaired image. Right the target or Ground truth without defects.
超分辨率和修复似乎经常被认为是分开的和不同的任务。然而,如果一个数学函数可以被训练来创建图像中没有的额外细节,那么它也应该能够修复图像中的缺陷和缺口。这假设这些缺陷和缺口存在于训练数据中,以便模型学习它们的恢复。
超分辨率的 GANs
大多数基于深度学习的超分辨率模型是使用生成对抗网络(GANs)训练的。
GANs 的局限性之一是,它们实际上是一种懒惰的方法,因为它们的损失函数,即 critical,是作为过程的一部分来训练的,而不是专门为此目的而设计的。这可能是许多模型只擅长超分辨率而不擅长图像修复的原因之一。
普遍适用
许多深度学习超分辨率方法不能普遍适用于所有类型的图像,几乎都有其弱点。例如,为动物的超分辨率训练的模型可能不适合人脸的超分辨率。
用本文中详细描述的方法训练的模型似乎在包括人类特征在内的各种数据集上表现良好,这表明在任何类别的图像上有效放大的通用模型是可能的。
X2 超分辨率的例子
以下是在 Div2K 数据集上训练的同一模型的 X2 超分辨率(图像大小加倍)的十个示例,该数据集是各种主题类别的 800 幅高分辨率图像。
例子一来自一个在不同种类的图像上训练的模型。在早期的训练中,我发现改善人类图像的效果最差,而且呈现出更艺术的平滑效果。然而,在通用类别数据集上训练的这个版本的模型已经设法很好地改善了这张图像,仔细观察面部、头发、衣服褶皱和所有背景中添加的细节。
Super resolution on an image from the Div2K validation dataset, example 1
例子二来自一个在不同种类的图像上训练的模型。该模型为树木、屋顶和建筑窗户添加了细节。再次令人印象深刻的结果。
Super resolution on an image from the Div2K validation dataset, example 2
例子三来自一个在不同类别的图像上训练的模型。在不同数据集上训练模型的过程中,我发现人脸的结果最不令人满意,但是在不同类别的图像上训练的模型已经成功地改善了面部的细节,并查看了添加到头发上的细节,这令人印象深刻。
Super resolution on an image from the Div2K validation dataset, example 3
例子四来自一个在不同种类的图像上训练的模型。添加到镐轴、冰、夹克褶皱和头盔上的细节令人印象深刻:
Super resolution on an image from the Div2K validation dataset, example 4
例子五来自一个在不同种类的图像上训练的模型。花卉的改进令人印象深刻,鸟眼、鸟嘴、皮毛和翅膀的细节也是如此:
Super resolution on an image from the Div2K validation dataset, example 5
例子六来自一个在不同种类的图像上训练的模型。这个模型成功地给人的手、食物、地板和所有的物体添加了细节。这真是令人印象深刻:
Super resolution on an image from the Div2K validation dataset, example 6
例子七来自一个在不同种类的图像上训练的模型。该模型将毛发聚焦,并保持背景模糊:
Super resolution on an image from the Div2K validation dataset, example 7
例八来自一个在不同类别的图像上训练的模型。该模型很好地锐化了窗口之间的线条:
Super resolution on an image from the Div2K validation dataset, example 8
例子九来自一个在不同种类的图像上训练的模型。皮毛的细节真的好像是模特想象出来的。
Super resolution on an image from the Div2K validation dataset, example 9
例 10 来自在不同类别的图像上训练的模型。这似乎真的令人印象深刻的锐化周围的结构和灯光。
Super resolution on an image from the Div2K validation dataset, example 10.
示例 11 来自在不同类别的图像上训练的模型。羽毛的改进和变尖非常明显。
Super resolution on an image from the Div2K validation dataset, example 11.
示例 12 来自在不同类别的图像上训练的模型。这种内部图像几乎在所有地方都得到了微妙的改善。
Super resolution on an image from the Div2K validation dataset, example 12.
示例 13 来自在不同类别的图像上训练的模型。这是本节的最后一个例子,一个复杂的图像已经被锐化和改进。
Super resolution on an image from the Div2K validation dataset, example 13.
该模型的预测具有超高的分辨率
以上所有图像都是在训练期间或训练结束时对验证图像集进行的改进。
经过训练的模型已用于创建超过 100 万像素的放大图像,以下是一些最佳示例:
在该第一示例中,以高 JPEG 质量(95)保存的 256 像素正方形图像被输入到模型中,该模型将图像放大到 1024 像素正方形图像,执行 X4 超分辨率:
Super resolution using deep learning, example 1
上面的图片集不一定能准确预测,查看我的公共 Google drive 文件夹中的完整 PDF:
https://drive.google.com/open?id = 1g 0 o7 ul 7 zllxki _ 0 gsz 2 C4 qo 4 f 71 S6 F5 I
在下一个例子中,以低 JPEG 质量保存的 512 像素图像(30)被输入到模型中,该模型将图像放大到 1024 像素的正方形图像,对较低质量的源图像执行 X2 超分辨率。在这里,我相信模型的预测看起来比目标地面真实图像更好,这是惊人的:
Super resolution using deep learning, example 2
上面的图片集不一定能准确预测,请查看我的公共 Google drive 文件夹中的全尺寸 PDF:
【https://drive.google.com/open? id = 1 fro 6n 7d qfh qzw 5-oTGTMgjUTMQGsGeaD
用最基本的术语来说,这个模型:
- 接受图像作为输入
- 让它通过一个训练有素的数学函数,这是一种神经网络
- 输出与输入尺寸相同或更大的图像,这是对输入尺寸的改进。
这建立在杰瑞米·霍华德和雷切尔·托马斯在 Fastai 课程中建议的技术之上。它使用 Fastai 软件库、PyTorch 深度学习平台和 CUDA 并行计算 API。
Fastai 软件库打破了很多复杂深度学习入门的障碍。因为它是开源的,所以如果需要的话,很容易定制和替换你的架构的元素来适应你的预测任务。这个图像生成器模型是建立在 Fastai U-Net 学习器之上的。
该方法使用以下内容,下面将进一步解释其中的每一项:
- 一种交叉连接的 U-Net 架构,类似于 DenseNet
- 基于 ResNet-34 的编码器和基于 ResNet-34 的解码器
- 用 ICNR 初始化进行像素混洗放大
- 从预训练的 ImageNet 模型进行迁移学习
- 基于来自 VGG-16 模型的激活、像素损失和克矩阵损失的损失函数
- 区别学习率
- 渐进调整大小
这个模型或数学函数有超过 4000 万个参数或系数,允许它尝试执行超分辨率。
剩余网络
ResNet 是一种卷积神经网络(CNN)架构,由一系列残差块(ResBlocks)组成,如下所述,通过跳跃连接将 ResNet 与其他 CNN 区分开来。
当最初设计 ResNet 时,它以显著的优势赢得了当年的 ImageNet 竞争,因为它解决了渐变消失的问题,即随着层数的增加,训练速度变慢,准确性没有提高,甚至变得更差。正是网络跳过连接完成了这一壮举。
这些在下面的图表中显示,并在描述 ResNet 中的每个 ResBlock 时进行更详细的解释。
Left 34 Layer CNN, right 34 Layer ResNet CNN. Source Deep Residual Learning for Image Recognition: https://arxiv.org/abs/1512.03385
残余块(ResBlocks)和密集块
如果卷积网络在靠近输入的层和靠近输出的层之间包含较短的连接,则卷积网络可以训练得更深入、更准确、更有效。
如果您将损失面(模型预测的变化损失的搜索空间)可视化,这看起来就像下图中左侧图像所示的一系列山丘和山谷。最低的损失就是最低点。研究表明,一个较小的最优网络可以被忽略,即使它是一个较大网络的一部分。这是因为损失面太难导航。这意味着向模型中添加层会使预测变得更糟。
Loss surface with and without skip connections. Source: Visualising loss space in Neural networks: https://arxiv.org/abs/1712.09913
一个非常有效的解决方案是在网络各层之间增加交叉连接,允许在需要时跳过大部分。这创建了一个损失表面,看起来像右边的图像。这对于用最佳权重训练模型以减少损失要容易得多。
A ResBlock within a ResNet. Source: Deep Residual Learning for Image Recognition: https://arxiv.org/abs/1512.03385
每个 ResBlock 从其输入有两个连接,一个经过一系列卷积、批量规格化和线性函数,另一个连接跳过这一系列卷积和函数。这些被称为身份连接、交叉连接或跳过连接。两个连接的张量输出相加在一起。
稠密连接的卷积网络和稠密块
在 ResBlock 提供张量相加的输出的情况下,这可以被改变为张量连接。随着每个交叉/跳跃连接,网络变得更加密集。然后,ResBlock 变成 DenseBlock,网络变成 DenseNet。
这允许计算跳过架构中越来越大的部分。
DenseBlocks within a DenseNet. Source: Densely Connected Convolutional Networks: https://arxiv.org/pdf/1608.06993.pdf
由于串联,DenseBlocks 与其他架构相比会消耗大量内存,非常适合较小的数据集。
u 型网
U-Net 是为生物医学图像分割开发的卷积神经网络架构。已经发现 u-网对于输出与输入大小相似并且输出需要该量的空间分辨率的任务非常有效。这使得它们非常适合于创建分割蒙版和图像处理/生成,如超分辨率。
当卷积神经网络通常与用于分类的图像一起使用时,使用一系列每次减小网格大小的两个步长的卷积,图像被获取并向下采样到一个或多个分类中。
为了能够输出与输入大小相同或更大的生成图像,需要有一个上采样路径来增加网格大小。这使得网络布局类似于 U 形,U 形网络下采样/编码器路径形成 U 形的左侧,上采样/解码器路径形成 U 形的右侧
对于上采样/解码器路径,几个转置卷积实现这一点,每个卷积在现有像素之间和周围添加像素。基本上执行下采样路径的相反过程。上采样算法的选项将在后面进一步讨论。
请注意,该模型的基于 U-Net 的架构也有交叉连接,这将在后面详细说明,这些不是原始 U-Net 架构的一部分。
A U-Net network architecture. Source: http://deeplearning.net/tutorial/_images/unet.jpg
原来的研究可在这里:https://arxiv.org/abs/1505.04597
上采样/转置卷积
网络的解码器/上采样部分(U 的右手部分)中的每个上采样需要在现有像素周围以及现有像素之间添加像素,以最终达到期望的分辨率。
这个过程可以从论文“深度学习卷积算法指南”中可视化如下,其中在像素之间添加零。蓝色像素是原始的 2x2 像素扩展到 5x5 像素。在外部添加 2 个像素的填充,并在每个像素之间添加一个像素。在这个例子中,所有新像素都是零(白色)。
Adding pixels around and between the pixels. Source: A guide to convolution arithmetic for deep learning: https://arxiv.org/abs/1603.07285
这可以通过使用像素的加权平均(使用双线性插值)对新像素进行一些简单的初始化来改善,否则会不必要地使模型更难学习。
在这个模型中,它使用了一种改进的方法,称为像素混洗或带有 ICNR 初始化的亚像素卷积,这导致像素之间的间隙被更有效地填充。这在论文“使用高效亚像素卷积神经网络的实时单幅图像和视频超分辨率”中有所描述。
Pixel shuffle. Source: Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network, source: https://arxiv.org/abs/1609.05158
像素混洗以因子 2 放大,使图像的每个通道中的维度加倍(在网络的该部分的当前表示中)。然后执行复制填充以在图像周围提供额外的像素。然后,执行平均池以平滑地提取特征并避免由许多超分辨率技术产生的棋盘图案。
在添加了这些新像素的表示之后,随着路径继续通过网络的解码器路径,随后的卷积改善了这些像素内的细节,然后再进行另一个步骤并使维度加倍。
u 网和精细图像细节
当使用唯一的 U-Net 架构时,预测往往缺乏细节,为了帮助解决这个问题,可以在网络的块之间添加交叉或跳过连接。
不是像在 ResBlock 中那样每两个卷积添加一个跳过连接,而是跳过连接从下采样路径中相同大小的部分跨越到上采样路径。这些是上图中显示的灰色线条。
原始像素通过跳过连接与最终的 ResBlock 连接,以允许在知道输入到模型中的原始像素的情况下进行最终计算。这导致输入图像的所有细节都在 U-Net 的顶部,输入几乎直接映射到输出。
U-Net 块的输出被连接起来,使它们更类似于 DenseBlocks 而不是 ResBlocks。但是,有两个跨距卷积可以减小网格大小,这也有助于防止内存使用量增长过大。
ResNet-34 编码器
ResNet-34 是一个 34 层 ResNet 架构,它被用作 U-Net(U 的左半部分)的下采样部分中的编码器。
在将 ResNet-34 编码器转换为具有交叉连接的 U-Net 的情况下,Fastai U-Net 学习器在配备有编码器架构时将自动构建 U-Net 架构的解码器端。
为了使图像生成/预测模型知道如何有效地执行其预测,如果使用预训练的模型,将大大加快训练时间。然后,该模型具有需要检测和改进的特征种类的初始知识。当照片被用作输入时,使用在 ImageNet 上预先训练的模型和权重是一个很好的开始..用于 pyTorch 的预训练 ResNet-34 可从卡格尔:https://www.kaggle.com/pytorch/resnet34获得
损失函数
损失函数基于论文《实时风格传输和超分辨率的损失》中的研究以及 Fastai 课程(v3)中所示的改进。
本文重点研究特征损失(文中称为感知损失)。这项研究没有使用 U-Net 架构,因为当时机器学习社区还不知道它们。
Source: Convolutional Neural Network (CNN) Perceptual Losses for Real-Time Style Transfer and Super-Resolution: https://arxiv.org/abs/1603.08155
此处使用的模型使用与论文相似的损失函数进行训练,使用 VGG-16,但也结合了像素均方误差损失和克矩阵损失。Fastai 团队发现这非常有效。
VGG-16
VGG 是 2014 年设计的另一个 CNN 架构,16 层版本用于训练该模型的损失函数。
VGG-16 Network Architecture. Source: https://neurohive.io/wp-content/uploads/2018/11/vgg16-1-e1542731207177.png
VGG 模式。在 ImageNet 上预先训练的网络用于评估发电机模型的损耗。通常这将被用作分类器来告诉你图像是什么,例如这是一个人,一只狗还是一只猫。
VGG 模型的头部被忽略,损失函数使用网络主干中的中间激活,其代表特征检测。网络的头部和主干将在后面的培训部分进一步介绍。
Different layers in VGG-16. Source: https://neurohive.io/wp-content/uploads/2018/11/vgg16.png
这些激活可以通过查看 VGG 模型找到所有的最大池层。这些是检测网格大小变化和特征的地方。
在下图中可以看到可视化各种图像激活的热图。这显示了在网络的不同层中检测到的各种特征的例子。
Visualisation of feature activations in CNNs. Source: page 4 of https://arxiv.org/pdf/1311.2901.pdf
该超分辨率模型的训练使用基于 VGG 模型激活的损失函数。损失函数在整个训练过程中保持固定,不像 GAN 的关键部分。
特征图有 256 个 28×28 的通道,用于检测毛发、眼球、翅膀和类型材料等特征以及许多其他类型的特征。使用基本损失的均方误差或最小绝对误差(L1)误差来比较(目标)原始图像和生成图像在同一层的激活。这些是特征损失。该误差函数使用 L1 误差。
这使得损失函数能够了解目标地面真实影像中的特征,并评估模型预测的特征与这些特征的匹配程度,而不仅仅是比较像素差异。
培训详情
训练过程从如上所述的模型开始:使用基于在 ImageNet 上预训练的 VGG-16 架构的损失函数结合像素损失和 gram 矩阵,在 ImageNet 上预训练的基于 ResNet-34 架构的 U-Net。
培训用数据
幸运的是,在大多数应用程序中,可以创建几乎无限量的数据作为训练集。如果采集了一组高分辨率图像,可以将这些图像编码/调整大小为较小的图像,这样我们就有了具有低分辨率和高分辨率图像对的训练集。然后,我们的模型预测可用于评估高分辨率图像。
低分辨率图像最初是一半尺寸的目标/地面真实图像的副本。然后,使用双线性变换对低分辨率图像进行初始放大,以使其与目标图像具有相同的尺寸,从而输入到基于 U-Net 的模型中。
在这种创建训练数据的方法中采取的操作是模型学习适应的操作(颠倒该过程)。
可以通过以下方式进一步扩充训练数据:
- 在一定范围内随机降低图像质量
- 随机选择农作物
- 水平翻转图像
- 调整图像的照明
- 添加透视扭曲
- 随机添加噪声
- 在图像上随机打孔
- 随机添加覆盖的文本或符号
下面的图像是数据扩充的一个例子,所有这些都是从同一个源图像生成的:
Example of data augmentation
将每个图像的质量降低和噪声改变为随机的改进了结果模型,允许它学习如何改进所有这些不同形式的图像退化,并更好地概括。
功能和质量改进
基于 U-Net 的模型增强了放大图像中的细节和特征,通过包含大约 4000 万个参数的函数生成了改进的图像。
训练模特的头部和骨干
这里使用的三种方法特别有助于训练过程。这些是渐进调整大小、冻结然后解冻主干中权重的梯度下降更新和区别学习率。
该模型的架构分为两部分,主干和头部。
主干是 U-Net 的左侧部分,是基于 ResNet-34 的网络的编码器/下采样部分。头部是 U-Net 的右侧部分,即网络的解码器/上采样部分。
主干已经基于在 ImageNet 上训练的 ResNet34 预先训练了权重,这就是迁移学习。
头部需要训练其权重,因为这些层的权重被随机初始化以产生期望的最终输出。
在最开始,网络的输出基本上是像素的随机变化,而不是使用 ICNR 初始化的像素混洗子卷积,其被用作网络的解码器/上采样路径中每个升级的第一步。
一旦经过训练,骨架顶部的头部允许模型学习用骨架中预先训练的知识做一些不同的事情。
冻住脊梁,练好脑袋
网络主干中的权重被冻结,因此最初只训练头部中的权重。
学习率查找器运行 100 次迭代,并绘制损失与学习率的关系图,选择最陡斜率附近朝向最小损失的点作为最大学习率。可选地,可以使用比最低点小 10 倍的速率来查看是否表现得更好。
Learning rate against loss, optimal slope with backbone frozen
“适合一个周期”政策用于改变学习速度和动力,在 Leslie Smith 的论文中有详细描述
https://arxiv.org/pdf/1803.09820.pdf和西尔万·古格的https://sgugger.github.io/the-1cycle-policy.html
渐进调整大小
首先在大量较小的映像上进行训练,然后扩展网络和训练映像,这样会更快。将图像从 64px 乘以 64px 放大并改善为 128px 乘以 128px 比在更大的图像上执行该操作要容易得多,在更大的数据集上也要快得多。这被称为渐进式调整大小,它也有助于模型更好地概括,因为它看到更多不同的图像,不太可能过度拟合。
这种渐进式调整大小的方法是基于 Nvidia 与 progressive GANs 的出色研究:https://research . Nvidia . com/sites/default/files/pubs/2017-10 _ Progressive-Growing-of/karras 2018 iclr-paper . pdf。这也是 Fastai 用来在 ImageNet 上击败科技巨头的方法:https://www.fast.ai/2018/08/10/fastai-diu-imagenet/
该过程是在较大的批次中用小图像进行训练,然后一旦损失降低到可接受的水平,则创建新的模型,该模型接受较大的图像,从在较小的图像上训练的模型转移学习。
随着训练图像大小的增加,批次大小必须减小以避免耗尽内存,因为每个批次包含更大的图像,每个图像中的像素是四倍。
请注意,输入图像中的缺陷是随机添加的,以提高模型的恢复属性,并帮助它更好地概括。
从训练集中分离出来的验证集的示例以一些渐进的大小显示在这里:
在每个图像尺寸下,执行 10 个时期的一个循环的训练。这是冷冻的骨干重物。
图像尺寸被加倍,并且对于通过网络的较大图像的路径,用额外的网格尺寸来更新模型。重要的是要注意砝码的数量不会改变。
步骤 1:从 32 像素乘 32 像素放大到 64 像素乘 64 像素。使用 1e-2 的学习率。
Super resolution to 64px by 64px on a 32px by 32px image from the validation set. Left low resolution input, middle super resolution models prediction, right target/ground truth.
步骤 2:从 64 像素乘 64 像素放大到 128 像素乘 128 像素。使用 2e-2 的学习速率。
Super resolution to 128px by 128px on a 64px by 64px image from the validation set. Left low resolution input, middle super resolution models prediction, right target/ground truth
步骤 3:从 128 像素乘 128 像素放大到 256 像素乘 256 像素。使用了 3e-3 和 1e-3 之间的区别学习率。
Super resolution to 256px by 256px on a 128px by 128px image from the validation set. Left low resolution input, middle super resolution models prediction, right target/ground truth
步骤 4:从 256 像素乘 256 像素放大到 512 像素乘 512 像素。使用 1e-3 和之间的区别学习率。
Super resolution to 512px by 512px on a 256px by 256px image from the validation set. Left low resolution input, middle super resolution models prediction, right target/ground truth
解冻主干
主干被分成两层组,头部是第三层组。
然后,整个模型的权重被解冻,并且该模型用判别学习率来训练。这些学习率在第一层组中要小得多,然后在第二层组中增加,最后一层组在头部再次增加。
在脊柱和头部解冻的情况下,再次运行学习率查找器。
Learning rate against loss with backbone and head unfrozen
使用 1e-6 和 1e-4 之间的区别学习率。头部的学习速率仍然比先前的学习周期低一个数量级,在先前的学习周期中,只有头部被解冻。这允许对模型进行微调,而不会有损失已有精度的风险。这被称为学习率退火,当我们接近最佳损失时,学习率降低。
在更大的输入图像上继续训练将提高超分辨率的质量,但是批量大小必须保持缩小以适应内存限制,并且训练时间增加,并且达到了我的训练基础设施的极限。
所有训练都是在 Nvidia Tesla K80 GPU 上进行的,内存为 12GB,从开始到结束不到 12 个小时,逐步调整大小。
结果
训练的渐进调整大小部分中的以上图像显示了基于深度学习的超分辨率在改善细节、去除水印、缺陷和赋予缺失的细节方面是多么有效。
接下来的三个基于来自 Div2K 数据集的图像的图像预测都通过相同的训练模型对其执行了超分辨率,这表明深度学习超分辨率模型可能能够普遍应用。
注意:这些来自实际的 Div2K 训练集,尽管该集被分成我自己的训练和验证数据集,并且模型在训练期间没有看到这些图像。后面还有来自实际 Div2K 验证集的更多示例。
左:256 x 256 像素输入。中间:来自模型的 512 x 512 预测。右:512 x 512 像素地面真实目标。看着火车前面的通风口,细节改进很清楚,非常接近地面真实目标。
256 by 256 pixel super resolution to 512 by 512 pixel image, example 1
左:256 x 256 像素输入。中间:来自模型的 512 x 512 预测。右:512 x 512 像素地面真实目标。下面这个图像预测中的特征改进是相当惊人的。在我早期的训练尝试中,我几乎得出结论,人类特征的超分辨率将是一项过于复杂的任务。
256 by 256 pixel super resolution to 512 by 512 pixel image, example 2
左:256 x 256 像素输入。中间:来自模型的 512 x 512 预测。右:512 x 512 像素地面真实目标。请注意白色的“安全出口”文字和镶板线是如何改进的。
256 by 256 pixel super resolution to 512 by 512 pixel image, example 3
Div2K 验证集上的超分辨率
来自官方 Div2K 验证集的超分辨率示例。这里有 PDF 版本:https://drive.google.com/open?id = 1 ylselpp _ _ emdywihpmlhw 4 fxjn _ LybkQ
Model prediction comparison on the Div2K validation dataset
牛津 102 Flowers 数据集上的超分辨率
超分辨率来自于花的图像数据集上的单独训练模型,我认为这非常出色,许多模型预测实际上看起来比在验证集上真正执行超分辨率的地面事实更清晰(训练期间看不到的图像)。
Validation results upscaling images from the Oxford 102 Flowers dataset consisting of 102 flower categories
牛津-IIIT Pet 数据集上的超分辨率
下面的例子来自一个单独的训练模型,放大了狗的低分辨率图像,令人印象深刻,同样来自验证集,创建了更精细的皮毛细节,锐化了眼睛和鼻子,并真正改善了图像中的特征。大多数放大的图像接近地面真实情况,当然比双线性放大的图像好得多。
Validation results upscaling images from Oxford-IIIT Pet dataset, a 37 category pet dataset with roughly 200 images for each class.
我相信这些结果是令人印象深刻的,模型必须发展出一种“知识”,即照片/图像的原始主题中的一组像素必须是什么。
它知道某些区域是模糊的,并且知道重建模糊的背景。
如果模型在损失函数的特征激活上表现不佳,它就无法做到这一点。实际上,该模型已经逆向工程了匹配这些像素的特征,以匹配损失函数中的激活。
限制
对于要由模型学习的恢复类型,它必须作为要解决的问题存在于训练数据中。当在一个训练过的模型的输入图像上打孔,而这个模型不知道如何处理它们,就让它们保持不变。
需要在图像上产生幻觉的特征,或者至少是相似的特征,必须存在于训练集中。如果模型是在动物上训练的,那么模型不太可能在完全不同的数据集类别上表现良好,例如房间内部或花。
在特写人脸上训练的模型的超分辨率结果不是特别令人信服,尽管在 Div2K 训练集中的一些例子上确实看到了特征上的良好改进。特别是在 X4 超分辨率中,虽然特征比最近邻插值更加锐化,但是特征呈现出几乎是绘制的/艺术的效果。对于分辨率非常低的图像或有很多压缩伪像的图像,这可能仍然是更好的选择。这是我打算继续探索的一个领域。
结论
使用损失函数训练的基于 U-Net 深度学习的超分辨率可以很好地执行超分辨率,包括:
- 将低分辨率图像放大到更高分辨率的图像
- 提高图像质量并保持分辨率
- 移除水印
- 从图像中消除损坏
- 移除 JPEG 和其他压缩伪像
- 给灰度图像着色(另一项正在进行的工作)
对于要由模型学习的恢复类型,它必须作为要解决的问题存在于训练数据中。在经过训练的模型的输入图像中打孔,模型不知道如何处理它们,就让它们保持不变,而当打孔被添加到训练数据中时,经过训练的模型可以很好地恢复它们。
这里展示的所有图像超分辨率的例子都是来自我训练的模型的预测。
下面有五个例子,我认为模型的预测(中间)与目标(右边)一样好或非常接近,目标是来自验证集的原始地面真实图像。该模型适用于动物特征,如毛皮和眼睛,眼睛是一个非常困难的任务,以锐化和增强。
Super resolution concluding example 1
Super resolution concluding example 2
Super resolution concluding example 3
Super resolution concluding example 4
Super resolution concluding example 5
还有最后一个来自验证集的例子,在我看来,模型的预测(中间)比目标(右边)更好,即来自验证集的原始地面真实图像。
Super resolution concluding example 6, model prediction possibly better than the ground truth target?
后续步骤
我热衷于将这些技术应用于不同主题的图像和不同的领域。如果你认为这些超分辨率技术可以帮助你的行业或项目,那么请联系我们。
我计划将这个模型转移到一个生产 web 应用程序中,然后可能转移到一个移动 web 应用程序中。
我正在对 Image Net 数据集的较大子集进行训练,该数据集包含许多类别,以产生一个有效的通用超分辨率模型,该模型对任何类别的图像都表现良好。我还在训练我在这里训练的相同数据集的灰度版本,其中模型正在给图像着色。
我计划尝试像 ResNet-50 这样的模型架构,以及一个带有初始主干的 ResNet 主干。
伦理问题
通过产生在诸如安全镜头、航空摄影或类似的类别中不存在的幻觉细节,然后从低分辨率图像生成图像可能会使其远离原始的真实主题。
想象一下,如果面部特征被细微地改变,但足以通过面部识别来识别一个实际上不在那里的人,或者航拍照片被改变,足以通过另一种算法将一座建筑物识别为另一个样子。多样化的训练数据应该有助于避免这种情况,尽管随着超分辨率方法的改进,这是一个问题,因为缺乏机器学习研究社区历史上使用的多样化训练数据。
法斯泰
感谢 Fastai 团队,没有你们的课程和软件库,我怀疑我是否能够进行这些实验并了解这些技术。