TowardsDataScience-博客中文翻译-2020-九十二-
TowardsDataScience 博客中文翻译 2020(九十二)
原文:TowardsDataScience Blog
协议:CC BY-NC-SA 4.0
绘制熊猫和 PPP 贷款数据
原文:https://towardsdatascience.com/plotting-w-pandas-and-ppp-loan-data-2d8d1995a626?source=collection_archive---------25-----------------------
查看我在 Python 字典、列表和字符串上的其他帖子
探索性数据分析初学者指南。
图片由 Mikio Harman 提供
数据帧
在深入研究数据之前,理解什么是数据帧及其用途是很重要的。了解这一点将有助于我们理解熊猫的数据是如何被操纵的。
熊猫数据框是表格,就像你在 Excel 中看到的一样。它们由列和行组成,并以表格格式排列我们的数据,以便更容易使用数据进行推断或预测。
数据应整齐,即每个变量形成一列,每个观察值形成一行,每种类型的观察单位形成一个表格。图片由 Mikio Harman 拍摄
更具体地说,DataFrame 可以使用一个[dictionary](https://docs.python.org/3/tutorial/datastructures.html#dictionaries)
、[lists](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists)
、[pd.Series](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.html#pandas-series)
、n[umpy.ndarrays](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.html)
或另一个DataFrame
来填充 DataFrame 对象。让我们使用前四种方法创建数据框架,并展示查看数据的四种不同方法。
如果你还没有,你需要下载 Pandas 和 NumPy 最简单的方法就是使用[pip](https://pypi.org/project/pip/)
。
pip install pandas numpy
用熊猫创建数据框很容易。根据您处理的数据和数据结构,能够以不同的方式创建它们给了您很大的灵活性。您还可以将一个列名列表传入到columns
参数中,并使用index
参数将哪个列用于索引。
查看数据也很简单,Pandas 提供了许多从数据中提取行的方法。笔记本中涵盖的五种方式是:
[head()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.head.html#pandas-dataframe-head)
——看看前 5 行[tail()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.tail.html#pandas-dataframe-tail)
—查看最后 5 行[sample(x)](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html#pandas-dataframe-sample)
—看 x 随机行[shape](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.shape.html#pandas-dataframe-shape)
返回一个元组:(行,列)[df[start:stop:step]](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sample.html)
—数据帧切片
截断
您经常会遇到数据集太大而无法在屏幕上完整显示的情况。当有太多的数据以列或行的方式显示时,Pandas 会自动截断你的数据,这就是为什么你会看到一个交叉的…
穿过你的数据,就像上面的例子中看到的那样。这可以通过使用以下方法访问[pd.options](https://pandas.pydata.org/pandas-docs/stable/user_guide/options.html#options-and-settings)
方法来解决:
**# Changing these settings as seen in the notebook above will let you view your desired amount of rows and columns.**
pd.options.display.max_rows
pd.options.display.max_columns**# View up to 100 rows and columns**
pd.options.display.max_rows = 100
pd.options.display.max_columns = 100
警告显示比需要更多的行和列将会增加查看代码输出的时间。
现在我们已经了解了什么是数据帧以及与数据帧相关的一些基本功能,让我们加载一些数据并进行一些初步的 EDA。
EDA 是什么?
"探索性数据分析(EDA)是一种利用各种技术(主要是图形技术)进行数据分析的方法/理念. "
- NIST/SEMATECH 统计方法电子手册
对于什么样的技术可以用于 EDA 没有硬性规定,但是通常使用可视化和简单的统计来帮助探索数据。这可以包括使用:
- 散点图
- 箱线图
- 直方图
- 线形图
- 条形图
工资保障计划贷款数据集
将鼠标悬停在某个状态上可查看更多详细信息。
对于这个例子,我们将使用小企业管理局工资保障计划贷款水平数据。2020 年 3 月,美国立法者同意了一项价值 2 万亿美元的刺激法案。该套餐包括
- 成人 1,200 加元,家庭收入不超过 75,000 加元的每个儿童 500 加元
- 为美国企业提供 5000 亿美元的基金贷款,每笔贷款都要公开
- 失业救济金连续四个月增加了 600 美元
- 航空公司 250 亿美元
- 航空货运公司 40 亿美元
- 30 亿美元用于航空承包商
- 3670 亿美元的小型企业贷款和补助计划
- 州政府和地方政府 1500 亿美元
- 1300 亿美元用于医院、医疗保健系统和供应商
我们将使用分配给小企业的 3670 亿美元的数据,看看 EDA 是否能帮助我们得出任何假设。
“工资保护计划是一项贷款,旨在为小企业提供直接激励,以保持他们的工人在工资单上。”
-sba.gov
汇总统计数据
Pandas 有许多用于返回汇总统计数据的内置方法。我最喜欢的一些包括[describe()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.describe.html#pandas-dataframe-describe)
和[info()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html#pandas-dataframe-info)
。
describe()
将返回两组不同的描述性统计数据,具体取决于是对分类列还是数字列执行该操作。
分类列(离散值):
**count**
—列中非缺失值的数量**unique**
—列中有多少个唯一值**top**
—列中最常见的值**freq**
—最大**top**
值在列中出现多少次
数字列(连续值):
**count**
—列中非缺失值的数量**mean**
—列中找到的平均值**std**
—列的标准偏差**min**
—列中的最小值**25%**
—列的第 25 个百分点值**50%**
—列的第 50 个百分位(中值)的值**75%**
—列的第 75 百分位的值**max**
—列中的最大值
info()
告诉我们关于索引数据类型、列数据类型、存在多少非空值以及数据帧使用的内存量的信息。
让我们来看看一些运行中的代码。
加载数据
Pandas 可以加载多种文件类型,这取决于你使用哪种文件类型。我使用的数据是一个 CSV 文件,Pandas 方便地提供了一个[read_csv()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html#pandas-dataframe-info)
方法,当给定正确的文件路径时,该方法会自动将数据读入 DataFrame。Pandas 还提供了许多参数,在加载数据时可以包含这些参数,这可以减少数据清理过程中的大量繁重工作。
想学习加载不同的文件类型吗?检查这里的和。
楠策
缺失值在数据中普遍存在,处理它们将是一项常见的任务。Pandas 以NaN
的形式表示缺失值,意思是“不是一个数字”。这些不是表示缺失值的唯一方式,您的工作是确定在生成数据时如何处理缺失值。当您使用 Pandas 读入数据时,您可以指定哪些值代表缺失值。
默认情况下,Pandas 在加载数据时会将以下值解释为缺失,并会自动将它们转换为一个NaN
:' '、' #N/A '、' #N/A N/A '、' #NA '、'-1。#IND ','-1。#QNAN ','-nan ','-NaN ',' 1。#IND ',' 1。' #QNAN ','< NA >','不适用',' NA ',' null ',' NAN ','不适用',' NaN ',' NULL '。
我通过将两个方法链接在一起来确定每一列中有多少缺失值。
df.isna().sum()
[isna()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.isna.html#pandas-dataframe-isna)
为数据帧中的每个值返回一个布尔值,如果它丢失或不丢失,[sum()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.sum.html#pandas-dataframe-sum)
对布尔值进行合计,以确定每列中有多少个丢失的值。这是一种简便的方法,可以知道哪些列可以立即删除,哪些列需要进一步分析,以了解应该如何处理缺失的值。
熊猫策划
对 Pandas 使用[plot()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html#pandas-dataframe-plot)
方法可以很容易地快速可视化您的数据。让我们试着使用方法来理解一些可用的特性。在本例中,我们将使用熊猫创建以下地块。
- 直方图—非常适合查看数据的频率
- 箱线图—非常适合查看数据的分布
- 水平条形图—非常适合检查离散类型
- 堆积图——非常适合比较多个推论。
列选择和分组依据
Pandas 通过简单地在[]
中传递列名和列名就可以很容易地选择一个列。如果您想选择多个列,只需传递一个名称列表即可。默认情况下,当您选择一个包含索引标签和值的列时,Pandas 将返回一个pd.Series
对象,如果您想返回一个DataFrame
对象,只需传递列表中的单个列名即可。点击了解更多信息。
**# Make the DataFrame**
data = {chr(65+x):[x+1] for x in range(3)}
df = pd.DataFrame(data)**# Getting a single column**
print(df["C"])
print(type(df["C"]))*# Output
0 3
<class 'pandas.core.series.Series'>***# Returning a DataFrame from a single column**
print(df[["C"]])
print(type(df[["C"]]))*# Output
0 3
1 4
Name: C, dtype: int64
<class 'pandas.core.frame.DataFrame'>***# Passing a list of column names**
print(df[["B", "A"]])*#Output
B A
0 2 1
1 3 2
<class 'pandas.core.frame.DataFrame'>*
有时,您会希望按某个变量对数据进行分组,并对其余数据执行聚合(平均值、总和、计数等)。).这可以通过使用[groupby()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.groupby.html#pandas-dataframe-groupby)
方法来实现。groupby()
的基本语法是这样的:
df.groupby(<Column Name to group by>).<aggregation function>
我强烈推荐阅读相关文档,groupby()
是熊猫经常使用的方法,也是我最喜欢使用的方法之一。下面的代码示例更详细地说明了如何使用它。
柱状图
df["JobsRetained"].plot(
kind="hist",
title="Frequency of JobsRetained",
bins=30,
alpha=0.3 **#adjusts the transperancy**
)
图片由 Mikio Harman 提供
直方图显示了装箱值的出现频率。
当查看“JobsRetained”列时,我们看到数据中可能存在异常值。我们希望看到正态分布,但显然,从 x 轴上看,单个企业可以保留的工作岗位数量在 0-500 之间。这个直方图告诉我们,我们的数据是右偏的,这意味着我们的大部分数据值出现在 0-100 个保留的工作之间。
箱线图
df["JobsRetained"].plot(
kind="box",
vert=False, **#makes the box plot horizontal**
title="Distribution of JobsRetaimed"
);
图片由 Mikio Harman 提供
箱线图向我们更精确地展示了连续数据的分布。图表上的方框代表从第 25 个百分位数到第 75 个百分位数的四分位数范围,红线代表中位数。离开盒子的线被称为须,从一个须的末端到另一个须的末端的距离代表 99.3%的数据。另外 0.7%显示在胡须外。
在我们的例子中,异常值看起来就像是紧密排列在一起的数据点的黑色粗线。箱线图看起来与直方图相似,因为它也被推到了图表的左侧。我们希望看到这一点,因为我们的直方图已经显示,大多数值都在 0-100 个保留的工作岗位之间。
条形图
df["LoanRange"].value_counts(normalize=True).plot(
kind="barh",
title="Normazlized Loan Distribution",
legend=True,
alpha=0.3
)
图片由 Mikio Harman 提供
条形图有助于可视化离散变量的分布。在我们的例子中,我们在“LoanRange”列中绘制了五个不同的值。这些值代表每个批准属于哪一类贷款。
x 轴是归一化的,这意味着它显示了每个离散值与整个数据集相比所占的比例。看起来最常批准的贷款在 0-350,000 美元之间,占总数据的 50-60%。数据需要在绘图前汇总,这就是为什么在代码中使用了[value_counts()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.value_counts.html#pandas-series-value-counts)
。
平均值和中位数
df.groupby("State")["JobsRetained"].mean().sort_values().plot(
kind="bar",
title = "Mean Jobs Retained In Each State",
alpha = 0.3,
legend=True,
)df.groupby("State")["JobsRetained"].median().sort_values().plot(
kind="line",
title = "Mean Jobs Retained In Each State",
legend=True,
color="red",
rot=90,
alpha=.8,
figsize=(12,5) **#determines the size**
)
plt.ylabel("Jobs Retained")
plt.legend(["Median", "Mean"])
图片由 Mikio Harman 提供
只要具有相同的 x 轴,就可以在彼此的顶部绘制多个图。您还可以在代码之外使用一些 matplotlib 语法来微调图表的外观。
在这里,我们看到数据中每个州的“保留的工作”的中值和平均值相互叠加。由于数据的偏斜,预计会看到一个非常高的平均值。中位数只是整个数据集中的中间数字。由于保留了 0-100 个工作岗位之间的大量数据,以及保留了约 0-500 个工作岗位的数据范围,因此中值远低于平均值是有意义的。
熊猫简介
一个为 Pandas 中的任何数据集自动生成 EDA 的包。
没有提到熊猫简介,关于熊猫的 EDA 讨论就不完整。Pandas Profiling 将自动执行各种 EDA 技术,并创建一个交互式报告。它非常容易上手,我已经包含了一个交互式报告,可以使用相同的数据来查看它的运行情况。参见互动报道 此处 。
感谢阅读🎉
我希望你现在能够自己完成一些简单的 EDA!
在这里找到这个博客的代码。
plt.subplot()还是 PLT . subplot()?了解 Pyplot 中基于状态的编程与面向对象的编程
原文:https://towardsdatascience.com/plt-subplot-or-plt-subplots-understanding-state-based-vs-object-oriented-programming-in-pyplot-4ba0c7283f5d?source=collection_archive---------6-----------------------
如何驯服 Matplotlib 的双头怪兽,达到你想要的数据可视化效果
当我学习如何使用 Python 编程语言编码时,Pyplot 模块(Matplotlib 库的一部分,在这里别名为plt
)的介绍特别不直观…老实说,有点让人迷惑。例如,功能plt.subplot()
和plt.subplot**s**()
可能看起来被一个字母**s**
关闭,但通常前者后面是一个形式为**plt**.plot(data_x, data_y)
的绘图功能,而后者后面通常是**ax[0,0]**.plot(data_x, data_y)
。更令人困惑的是,尽管“旅程”可能不同,但输出的“目的地”往往是相同的,这让任何人都想知道最终的实际差异是什么。
在 Matplotlib 的 Pyplot 模块中,双头龙 Uroboros 吃着自己的尾巴,试图模仿一个饼图,而不理解基于状态和面向对象编程之间的微妙区别。[来源:维基共享资源
在对 Pyplot 文档进行了更深入的研究之后,在网络普通用户的帮助下,我了解到在这些产生错误的细微差异背后,有两种完全不同的编程方法,Pyplot 接口支持这两种方法:第一种是“基于状态的”,第二种是“面向对象的”。
虽然 Matplotlib 学习者从“面向对象”方法开始并坚持使用它被认为是最佳实践,但是花点时间使用“基于状态”的方法对于更好地理解计算机科学中一个更大的概念争论来说是一个很好的迷你课程。像我这样没有花时间去理解这些细微差别的 Pyplot 用户可能会发现自己与一个模块的双头兽进行了无休止的斗争,永远无法驯服它以获得他们所设想的数据可视化。
对于学习 Pyplot 的 Matplotlib 新手来说,下面是一个简短的历史注释,说明为什么“基于状态”和“面向对象”编程哲学存在,以及它们如何试图在一个模块中同时存在。换句话说,当我第一次试图理解这个看似奇怪又矛盾的工具时,这就是我希望拥有的洞察力。
为什么有两种不同的方法?
更具 Pythonic 风格但也更复杂的方法“面向对象编程”在 20 世纪 60 年代的挪威计算中心有着历史渊源,在那里克利斯登·奈加特和奥利·约翰·达尔创建了 Simula 编程语言的第一个版本,该语言设计用于编程计算机模拟,其中不同的参与者和未知因素以复杂但可重复的方式相互作用(例如,如果核反应堆要在 10,000 个平行宇宙中建造,其中有多少个宇宙会发生严重事故?).几十年后,互联网和其他计算机网络的兴起普及了“面向对象编程”。Python 是采用这种常见方法的许多语言之一,其他主流语言如 Java、C++和 Ruby 也是如此。
达尔和尼加德在开发 Simula,un ivac[来源:cs-exhibitions . uni-klu . AC . at]期间。
随着 Python 的普及,2003 年创建了 Matplotlib 库,以使 Python 成为 20 世纪 70 年代末首次开发的专有软件 MATLAB 的开源替代品。然而,MATLAB 的方法更接近于所谓的“基于状态的编程”,而不是“面向对象”。这种更简单的方法通过已建立的过程运行变量,产生一系列状态,最终以期望的结果结束。这与使用基本计算器时的情况没有什么不同。例如:
来源:吉菲
- 计算器从初始状态“0”开始
- 我们输入常量变量“1”。这用新状态“1”替换了初始状态。
- 我们现在添加加法过程“+”和一个新的常量变量,在这种情况下,它也恰好是“1”。
- 我们用等号“=”将状态、过程和变量结合起来。
- 这给了我们一个新的状态,“2”。我们可以使用更多的过程来修改这种状态(“+”、“-”、“×”、“”、“√”或“%”)。
(🤦🏼♂️我有时会不小心把基于状态的编程写成“基于阶段的”,因为在我的想象中,我把这个过程看作是一系列阶段,每个阶段都朝着最终目标前进。但是正确的术语是基于状态的。)
虽然 MATLAB 和其他基于状态的语言非常简单,但它们的缺点是不容易封装对象和抽象函数,导致更复杂程序的代码更长、更混乱。
Matplotlib 的本意是作为 MATLAB 用户进入 Python 的桥梁,因此它最初的设计是为了适应基于状态的编程和面向对象的编程。尽管一些基于状态的编程特性(尤其是 Pylab )现在已经被弃用,以缓解混乱,但基于状态的 MATLAB 遗产通过 Pyplot 模块继续存在。
并排看到基于状态和面向对象的编程
这些不同的编程理念汇聚在 Pyplot 模块中。做考古挖掘的数字版本,有可能对比两者,通过比较两组不同的代码,将这些历史带入生活,最终得到相同的结果。
在这个例子中,我们将尝试创建一个有三个支线剧情的人物,如下所示。
注意,下面的代码假设 Pyplot 已经导入,并且已经定义了data_x
和data_y
。你可以在 GitHub 上找到这个初步代码。
首先,我们使用基于状态的方法创建这个图。
plt.figure(facecolor='lightgrey')
plt.subplot(2,2,1)
plt.plot(data_x, data_y, 'r-')
plt.subplot(2,2,2)
plt.plot(data_x, data_y, 'b-')
plt.subplot(2,2,4)
plt.plot(data_x, data_y, 'g-')
我发现一个有助于理解这里发生的事情的窍门是 【支线剧情】是名词,“情节”是动词 。也就是说,plt.subplot(2,2,1)
在一个 2×2 的网格中创建并聚焦于第一个子情节(从左到右,从上到下)。然后plt.plot(data_x, data_Y, 'r-')
使用第一个子情节中提供的数据主动绘制红线。
(🕵🏽♀️细心的观察者可能还会注意到,第三个次要情节已经被上面代码中的省略了。)
第二,同样的图形可以通过面向对象的方法实现:
fig, ax = plt.subplots(2,2)
fig.set_facecolor('lightgrey')
ax[0,0].plot(data_x, data_y, 'r-')
ax[0,1].plot(data_x, data_y, 'b-')
fig.delaxes(ax[1,0])
ax[1,1].plot(data_x, data_y, 'g-')
这里,plt.subplot**s**(2,2)
(注意附加的**s**
)已经生成了一个可比较的人物对象(fig
),它包含一个 2×2 的子情节数组(或“轴”对象)。然而,现在,面向对象的方法首先从ax
数组中检索“axes”对象,而不是将程序集中在一个子情节上,然后在该子情节中绘图。然后,axes 方法中的参数负责绘图。
(🕵🏽♀️注意到,在上面的代码中,第三个子情节(在这里以数组形式表示为ax[1,0]
)是创建的,然后又删除了,而不是像基于状态的方法中那样简单地省略掉。)
除了在面向对象的方法中节省一行代码之外,这些细微的差别似乎无关紧要。但是,对于那些仍在学习 Pyplot 的人来说,应该警告他们,不知不觉地混合这些方法可能会导致看似无法解释的编码混乱。下面的动画逐行展示了基于状态的过程与面向对象的过程的根本区别。只需要一点点想象力,就可以看出试图混合搭配这些流程会造成多么令人头痛的问题!
自己的作品。在知识共享署名许可下可重复使用[ CC BY 4.0 ]。
轮到你了!
为了进一步实验这些方法如何彼此不同,但却达到相同(或至少相似)的结果,即插即用 Pyplot 代码的这些片段来添加轴标签和图形标题:
基于状态的方法
plt.suptitle("Your Title Here")
plt.xlabel("X Axis")
plt.ylabel("Y Axis")
面向对象的方法
fig.suptitle("Your Title Here")
ax[1,1].set_xlabel("X Axis")
ax[1,1].set_ylabel("Y Axis")
(💡提示:当试验上述方法时,请注意代码相对于plt.subplot()
的位置如何在基于状态的方法中产生差异,以确定哪个轴被命名,而面向对象的方法由于 axes 对象的数组而与位置无关。)
为了方便起见,GitHub上提供了一个 Jupyter 笔记本,其中包含用于生成上述图形的代码。
更深入
到目前为止,您应该对理解 Pyplot 接口的双重性有了一个坚实的基础,并且对编码语言的 DNA 有了一个小小的了解。
如果你想更多地了解 Pyplot 的双重性质,我发现有一些在线阅读资料特别有帮助,包括“一个情节的生命周期”和“有效地使用 Matplotlib ”。关于面向对象编程的更多内容,“如何向一个六岁的孩子解释面向对象编程””尤其具有启发性。最后,Ankit Gupta 有有用的资源,将 Matplotlib 的最新版本放在它们的历史开发环境中。
我撰写的内容广泛,可能会引起初露头角的数据科学家的兴趣。请务必查看我的 Airtable API-Python 教程和我的列表“非营利数据管理的 5 个最佳实践”。如果你觉得这篇文章有帮助,如果你给我买一杯咖啡或者通过这个推荐链接成为一个媒体订阅者来帮助支持我更多的写作,我会非常感激。
恭喜你。你现在已经驯服了 Pyplot 的双头怪物,你可以开始狂欢了![来源:吉菲
这篇文章的早期草稿是作为 2019 年 数据科学与熨斗学校华盛顿 DC 校区 奖学金的一部分完成的。特别感谢我的同事和导师提供的反馈。
如果您有兴趣了解更多关于熨斗学校数据科学项目的信息并欣赏这篇文章, 使用此推荐链接了解更多信息,并支持更多类似您在此处看到的内容 。
plt.xxx()还是 ax.xxx(),那是 Matplotlib 里的问题
原文:https://towardsdatascience.com/plt-xxx-or-ax-xxx-that-is-the-question-in-matplotlib-8580acf42f44?source=collection_archive---------5-----------------------
学习 matplotlib 的初学者建议
作为一个最近从使用 R 转换到 Python 的新手,通过标准 Python 可视化库matplotlib
进行数据可视化是学习过程中不可避免的一部分。最开始的时候,在看了几个容易找到的matplotlib
教程后,有一种“恩,没我想的那么难”的印象。在import matplotlib.pyplot as plt
之后,我基本上可以通过调用plt.xxx(…)
(如plt.plot(…)
、plt.scatter(…)
、plt.bar(…)
、plt.xlabel(…)
、plt.ylabel(…)
、plt.legend(…)
等)来剧情一切。).当涉及到一些具体的调整时,Stackoverflow 是可以找到答案的地方。很多时候,我只需要复制粘贴解决方案,甚至不需要阅读问题描述,人们称之为 Stackoverflow 综合症。然而,随着剧情变得复杂,我发现在matplotlib
中总是有许多不同的方法来解决一个特定的问题。例如,您可能会发现,plt.title(…)
、ax.set_title(…)
和ax.title.set_text(…)
这些功能都可以为一个情节设置一个标题。每次遇到这种情况,我都不知所措。plt.xxx()
不是一刀切的方法吗?ax.xxx()
从哪里来?
plt.xxx(),还是 ax.xxx(),就是这个问题。
因此,我意识到复制粘贴的方法永远不会让我精通matplotlib
。我需要知道matplotlib
的架构和剧情。如果你是一个matplotlib
的初学者,并且和我一样经历过类似的情况,这是给你的帖子。在这篇文章中,我将分享我的笔记:
matplotlib
中plt.xxx()
与ax.xxx()
的区别,- 在
matplotlib
中,figure
不仅是一个图形,axes
也不是轴的复数, - 分别用这两种方法画一个例图。
我希望这篇文章能解答你长期以来的困惑,并节省你学习的时间。
plt.xxx()
和ax.xxx()
的区别
如图 1 所示,matplotlib
架构中有三个主要层。从上到下分别是脚本层 ( matplotlib.pyplot
模块)、美工层 ( matplotlib.artist
模块)、和后端层 ( matplotlib.backend_bases
模块)。
图 1,Matplotlib 架构
让我们从底层开始,后端层通过与你机器中的工具箱如 wxPython 或绘图语言如 PostScript 通信来处理所有繁重的工作。这是最复杂的一层。在这一层中,FigureCanvas
是绘制图形的区域,Renderer
是知道如何在FigureCanvas
上绘制的对象。像你我这样的普通用户几乎不需要处理这一层。
然后是中间层,艺术家层,这里是ax.xxx()
的来源。顾名思义,使用该层,您可以控制和微调尽可能多的元素(例如,脊线、刻度方向、刻度标签大小、刻度标签字体、刻度颜色等。)就像艺术家在画布上作画一样。与脚本层(见下文)相比,这一层允许你做更多的定制,对于高级剧情来说更方便。特别是当处理多个图形/轴时,你不会混淆哪个是当前活动的,因为每个子图都被分配给一个ax
。这就是为什么ax.xxx()
有时被称为基于对象的绘图。在编写 web 应用程序、UI 应用程序或者与其他开发人员共享的脚本时,我们肯定会更多地使用这一层。
顶层,脚本层,plt.xxx()
驻留于此,旨在使matplotlib
像 MATLAB 脚本一样工作。换句话说,这一层被认为是所有三层中最轻的脚本接口,它包括一组命令风格的函数,用于快速轻松地生成图形和绘图。这也是为什么很多matplotlib
教程更喜欢从这一层介绍。这是最容易开始和使用的部分,你基本上是在figure
的顶部添加对象(如线条、文本、矩形)。脚本层绘图有时也称为程序绘图。
图 2,脚本层绘制
Matplotlib 中的“图形”和“轴”
在matplotlib
中,figure
和axes
是一个图形的层(请注意,我并没有引用这个“图形”作为脚本)。这里让我们用 matplotlib 网站的一张图来解释这些概念。
图 3,Matplotlib 中的部分图形
从图 3 中我们可以看到,整个figure
(标记为外部红色方框)是一个图形的基础。其上一层是axes
(标记为内部蓝色方框)。一个figure
至少可以有一个axes
。从这里我们知道,axes
指的是图形的一部分,而不是一个以上轴的复数。例如,如果在figure
上有一个图,那么这个图就是axes
。如果你在一个figure
上有多个支线剧情,那么每个支线剧情就是一个axes
。为了能够制作一个情节,我们通常在开始时调用fig = plt.figure()
。我们通过调用ax1 = fig.add_subplot(2, 1, 1)
在figure
中创建一个axes
对象。这创建了 2 行 1 列的第一个支线剧情figure
。因此,所有的ax1.xxx(…)
都是专用于ax1
的功能。例如,要访问子情节ax1
中的 x 轴和 y 轴,我们调用ax1.xaxis(…)
和ax1.yaxis(…)
。同样,我们可以通过调用ax2 = fig.add_subplot(2, 1, 2)
来添加另一个子情节,并通过调用ax2.xxx(…)
来操纵它的元素。这样,在不弄乱代码的情况下,我们清楚地知道我们正在处理哪个子情节(当然,还有许多其他方法来调用两个axes
,例如,fig, ax = plt.subplots(2)
,那么每个轴都可以通过调用ax[0]
和ax[1]
来访问)。
使用两种方法的示例图
好了,在明确了plt.xxx()
和ax.xxx()
的概念后,让我们用一个改编自 matplotlib 文档的简单例子来演示它们在绘制带有支线剧情的人物时的区别。
脚本层绘图
艺术家图层绘图
如果一切顺利,你会得到如下图。
图 4,一个示例图
从这两个脚本中可以看出(脚本层出图 vs. 美工层出图),虽然美工层出图的代码比脚本层出图的代码更冗长,但是更容易读懂。这是一个非常重要的实践,可以让您生成高质量的代码并增加代码的可读性。当情节变得复杂时,艺术家分层绘图的力量就会越来越明显。
综上所述,我们可以使用plt.xxx()
来快速获得用于探索性数据分析的图表,然而,当您的代码是一个严肃项目的一部分并且需要与其他人共享时,ax.xxx()
是一种常用的风格。另外,作为一名matplotlib
的学习者,我强烈建议从艺术家图层绘制开始,从中你会对matplotlib
绘制有一个更全面的了解,对你在数据可视化方面的长远发展肯定更有好处。
以下是我发现非常有用的材料(持续更新列表)
- Matplotlib 剖析——为 SciPy 会议开发的教程
- 用于数据可视化的 Python 工具
- 如何浏览 PyViz 景观
- Matplotlib 画廊
- Matplotlib API 概述
和往常一样,我欢迎反馈、建设性的批评以及倾听您的数据科学项目。你可以在 Linkedin 上找到我,现在也可以在我的网站上找到我。
推荐系统的 PMF
原文:https://towardsdatascience.com/pmf-for-recommender-systems-cbaf20f102f0?source=collection_archive---------15-----------------------
概率矩阵分解和协同过滤
自动推荐系统通常用于基于关于偏好的现有数据向用户提供他们感兴趣的产品建议。文献描述了不同类型的推荐系统。但是,我们将强调两个主要类别,然后进一步扩展第二个类别:
基于内容的过滤:这些利用用户偏好来进行新的预测。当用户提供关于他/她的偏好的明确信息时,这被系统记录并用于自动提出建议。我们日常常用的许多网站和社交媒体都属于这一类。
协同过滤:当用户提供的信息不足以进行商品推荐时会发生什么?在这种情况下,我们可以使用其他有类似偏好的用户提供的数据。这类方法利用一组用户过去选择的历史来引出推荐。
在第一种情况下,期望给定的用户建立一个明确陈述偏好的简档,而在第二种情况下,该信息可能不完全可用,但是我们期望我们的系统仍然能够基于相似用户提供的证据来做出推荐。一种被称为概率矩阵分解,或者简称为 PMF 的方法,通常用于协同过滤,并且将是我们在本文剩余部分讨论的主题。现在让我们深入研究这个算法的细节以及它的直觉。
概率矩阵分解解释
假设我们有一组用户 u 1, u 2, u 3 … u N,他们对一组项目 v 1, v 2, v 3 … v M 进行评级。然后我们可以将评级构造为矩阵 R
评级映射。它可以被认为是一个矩阵,其中每个用户(行)对许多项目(列)进行评级
R 矩阵的一个重要特点是稀疏。也就是说,只有一些单元格具有非空的等级值,而其他单元格则没有。对于给定的用户 A ,系统应该能够根据他/她的偏好以及类似用户的选择提供商品推荐。然而,对于用户 A 来说,没有必要明确地对要推荐的特定项目进行评级。具有相似偏好的其他用户将弥补关于用户 A 的缺失数据。这就是为什么概率矩阵分解属于协同过滤推荐系统的范畴。
让我们考虑一下电影推荐系统。想象一下,如果我们被要求观看并评价在特定季节放映的每一部电影,情况会是怎样。那将是非常不切实际的,不是吗?我们只是缺少这样做的时间。
鉴于并非所有用户都能够对所有可用商品进行评级,我们必须找到一种方法来填补 R 矩阵中的信息空白,并且仍然能够提供相关的建议。PMF 通过利用类似用户提供的评级来解决这个问题。从技术上来说,它利用了贝叶斯学习的一些原则,这些原则也适用于我们拥有稀缺或不完整数据的其他场景。
可以使用两个低秩矩阵和 V 来估计 R 矩阵,如下所示:
R 矩阵的分量
这里,T33UT 是一个 N x D 矩阵,其中 N 是注册用户数, D 是排名。 V 是一个 D x M 矩阵,其中 M 是要评定的项目数。因此, N x M 额定值矩阵 R 可通过以下方式近似计算:
等式 1: R 表达式
我们从现在开始的工作是找到T 和 V ,它们将依次成为我们模型的参数。因为 U 和 V 是低秩矩阵,所以 PMF 又称为低秩矩阵因式分解问题。此外,和 V 矩阵的这一特殊特性使得 PMF 即使对于包含数百万条记录的数据集也是可伸缩的。**
PMF 从贝叶斯学习中获得参数估计的直觉。一般来说,我们可以说,在贝叶斯推断中,我们的目标是通过诉诸贝叶斯规则来找到模型参数的后验分布:
等式 2:参数推断的贝叶斯规则
这里, X 是我们的数据集,θ是分布的参数或参数集。α是分布的超参数。p(θ| X ,α)是后验分布,也称为后验。p( X |θ,α)为似然,p(θ|α)为在先。训练过程的整体思想是,随着我们获得更多关于数据分布的信息,我们将调整模型参数θ以适应数据。从技术上讲,后验分布的参数将被插入到先验分布中,用于训练过程的下一次迭代。也就是说,给定训练步骤的后验分布将最终成为下一步骤的先验。将重复该过程,直到各步之间的后验分布 p(θ| X ,α)变化很小。
现在让我们回到我们对 PMF 的直觉。如前所述,我们的模型参数将是和 V ,而 R 将是我们的数据集。一旦经过训练,我们将最终得到一个经过修改的 R 矩阵,该矩阵还将包含对最初在 R 中为空的用户项目单元格的评级。我们将使用修改后的评分矩阵进行预测。考虑到这些因素,我们将:*
其中,σ是零均值球形高斯分布的标准偏差。然后,通过替换等式 2 中的这些表达式,我们将得到:
既然 U 和 V 矩阵是相互独立的(用户和项目独立发生),那么这个表达式也可以这样写:
等式 3:PMF 的后验分布
现在是时候找出这个等式的每一个组成部分等同于什么了。首先,似然函数由下式给出:
等式 4:观察评级的分布[1]
这里, I { ij }是一个指示器,当第 i 行和第 j 列的等级存在时,其值为 1,否则为零。正如我们所看到的,该分布是具有以下参数的球形高斯分布:
反过来,和 V 的先验分布由下式给出:
等式 5 和 6:U 和 v 的先验分布。
这是两个零均值球面高斯函数。然后,将 4、5 和 6 替换为 3,我们将得到:
为了训练我们的模型,我们将通过使参数和 V 的导数等于零来寻求最大化该函数。然而,这样做将非常困难,因为高斯函数中有 exp 函数。为了解决这个问题,我们应该将对数应用到前面等式的两边,然后应用所需的导数。因此,通过将对数应用于前面等式的两边,我们将得到:
这是一个更容易区分的表达式。我们还知道,根据定义,高斯 PDF 由下式给出:
因此,对数后验概率的表达式如下所示(注意:为了简单起见,我们去掉了常数):
这里,后缀的表示 Frobenius 范数,由下式给出:
最后,通过引入一些附加符号来识别模型的超参数,我们将得到:
等式 7:PMF 的对数后验概率
其中:
然后,通过对方程 7 的参数求导,并使导数等于零,我们将得到:
从这里我们可以推导出更新 U i 和 V j 的表达式:
等式 8 和 9:更新 U 和 V 的表达式
假设 λU 和 λV 都不为零,则所涉及的逆矩阵保证存在。作为训练过程的一部分,我们将迭代更新I和 V j 。一旦我们找到这些的最佳值,我们将能够通过使用等式 7 获得 log-MAP(最大后验概率)的值。正如我们将在 Python 实现中看到的,我们可以使用这个值来监控训练收敛。**
用 Python 实现
注意:实现的完整源代码可在 https://bit.ly/35Cr5kl获得
出于训练的目的,我们利用了 IMDB 电影数据库的子集,然后将它分成两部分,分别用于训练和验证。
****初始化:为了初始化 V ,我们从一个标准差为 1/ λV 的零均值高斯中抽取随机数此外,秩值 D 被设置为相对较小的值 10。
初始化代码
更新参数:**为了更新和 V ,我们使用等式 8 和 9:
对应的 Python 代码如下:
更新参数
****计算对数后验概率:对数后验概率由等式 7 给出:
使用以下 Python 代码:
对数后验计算
****训练循环:为了训练模型,我们调用先前的函数,并监控在训练和测试集上评估的对数后验以及 RMSE(均方根误差):
训练循环
我们运行训练循环 150 次迭代,结果如下:
训练图
在左边,我们可以看到当我们训练模型时对数后验概率是如何演变的。在右侧,我们可以看到在训练集和测试集上评估的 RMSE 值。考虑到 R 预测值可能超出 0–5 的评级范围,我们使用线性插值来确保 R 值在此区间内。原始论文[1]提出了其他方法,如使用逻辑函数和线性插值。对于训练,还建议使用带动量的梯度下降来处理较大的数据集。
最后,以下是数据库中用户 id 为 45 的一些电影推荐:
结论
PMF 是一个强大的协同过滤算法。它利用具有相似偏好的用户提供的数据向特定用户提供推荐。它也称为低秩矩阵分解方法,因为它使用低秩矩阵来估计评级 R 矩阵,然后进行有用的预测。
我希望你喜欢这篇文章!如果你有任何问题,请随时来找我。我会继续写更多这样的材料。敬请关注。
参考
[1]萨拉赫胡季诺夫、鲁斯兰&姆尼赫、安德烈。概率矩阵分解。NIPS’07:第 20 届神经信息处理系统国际会议论文集,第 1257-1264 页,2007。
**[2]布鲁克斯-巴特利特·乔尼。概率概念讲解:参数估计的贝叶斯推断。地点:【https://bit.ly/3bajPNC **
肺炎检测:利用深度学习拓展人类能力的边界
原文:https://towardsdatascience.com/pneumonia-detection-pushing-the-boundaries-of-human-ability-with-deep-learning-ce08dbd0dc20?source=collection_archive---------35-----------------------
看看我是如何构建一个卷积神经网络(CNN)来从胸部 x 光片中检测肺炎的
通过 Shutterstock.com 沉浸成像成像
在进入我们如何使用人工神经网络来检测肺炎之前,让我们了解一点关于肺炎的知识,因为这将为建立模型铺平道路。
首先,什么是肺炎?
肺炎是一种严重的肺部感染,它会导致肺部的小气囊发炎,并充满液体或脓。肺炎患者可能需要住院或入住重症监护室(ICU)。
通过 Shutterstock.com 的魔法矿图片
关于肺炎的一些事实
- 肺炎是世界上 5 岁以下儿童死亡的主要原因。
- 肺炎是美国儿童住院的最常见原因。
- 对于我们成年人来说,肺炎是除女性分娩之外最常见的住院原因。
如何检测肺炎?
现在我们知道肺炎是一种常见疾病,每年在美国和世界各地都会影响许多人。我们平时怎么检测这种病?
事实证明,胸部 x 光一直被认为是检测任何形式肺炎的最佳工具。然而,研究表明,即使是经验丰富的放射科医生也常常很难正确识别 X-Ray⁴.上的某种物质是否是渗透物(比空气密度大的物质,如脓或液体)这导致诊断延误,增加了疾病的严重性和相关的死亡率。
图片由 OneStockPhoto 通过 Shutterstock.com 提供
如果人类不能早期正确诊断疾病,也许…深度学习可以有所帮助!
目标
建立一个深度学习模型,可以从患者的胸部 x 光图像中检测出肺炎。
幻灯片演示模板 go
方法
下面是我如何创建深度学习模型的高级方法。我首先从 Kaggle 收集数据,这些是来自中国的病人的胸部 x 光图像。在一些简单的探索性数据分析后,我通过重新调整像素和图像放大对图像进行预处理。然后,我开始创建卷积神经网络(CNN)模型的架构,这是一种深度学习模型。
Slidesgo 的演示模板| Freepik 的信息图表
数据收集
从 Kaggle 获得的数据包含来自中国广州一家医疗中心的 5,856 名 5 岁以下儿童患者的胸部 x 光照片。
中国广州某医疗中心患者的胸部 x 光图像(数据集: Kaggle
简单探索性数据分析(EDA)
重做列车试运行
当我开始训练我的神经网络时,我犯了一个大错误,它只有一个非常小的验证数据集。来自 Kaggle 的数据实际上已经被分成 3 个文件夹:训练、验证和测试。每个文件夹然后被分成两类:正常和肺炎。然而,验证集只包含 16 个图像,每个类有 8 个图像。虽然常用的分割比例是:70%训练,15%验证,15%测试,但我的验证集是整个数据的 0.27%。毫无疑问,无论我对我的模型应用什么样的正则化技术,我的模型表现仍然和我饥饿和睡眠不足时的情绪一样不稳定。
经验教训— 始终确保您的训练、验证和测试数据集处于适当的比率,并且包含足够的数据,使模型具有预测能力。后来,我重新安排了我的数据集,得到了这个比例:70%训练,19%验证,11%测试。
阶级分布
我们的训练数据集分布有 79%的肺炎患者图像和 21%的非肺炎患者图像。
幻灯片演示模板 go
图像预处理
接下来,通过像素归一化和数据扩充对这些图像进行预处理。
像素归一化
对于大多数图像数据,像素值是 0 到 255 之间的整数。由于神经网络使用小的权重值处理输入,具有较大值的输入会减慢学习过程。归一化像素会将整数缩小到 0 到 1 之间的值,因此归一化像素是一个很好的做法,可以确保高效的计算。
数据扩充
此外,我们还对图像进行了一些增强:水平翻转、放大和剪切。数据扩充是一种很好的做法,不仅可以向现有数据集添加更多数据,还可以添加微小的改变,也称为多样性,以避免模型过度适应训练数据。
建模
深度学习真的是一门工艺艺术,你真的可以按照你喜欢的方式构建你的模型。虽然有一些通用的模型架构,但是您仍然可以尝试不同的配置来为您的模型获得最佳结果。
从 RGB 转换为灰度图像
因为我们用于二元分类问题的图像是 X 射线,它通常显示从白色到各种灰度到黑色的密度范围。否则,它们会有不同的色调,但仍然侧重于颜色的密度。对我来说,这听起来就像灰度图像,只有灰色阴影,有或没有黑色或白色。
很自然地,我决定将我们的图像从 RGB(三维)转换成灰度(一维)。这可以降低模型的复杂性,因为模型需要学习图像的许多属性,例如边缘、形状、图案、纹理、阴影、亮度、对比度等。,同时还要考虑颜色。
模型架构
我已经训练了至少 30 个模型,这些模型具有不同的激活、特征图数量、退出和批量标准化的组合。这是我表现最好的模型的架构。
幻灯片演示模板 go
概括地说,我们有 3 个卷积 2D 层,每个层后面都有一个最大池层。展平后,它被馈入一个具有 ReLU 激活的完全连接的层。最后,由于这是一个二元分类,我们让输出图层使用 sigmoid softmax 激活来预测输出概率,该概率可以根据我们的阈值转换为类值。
我还尝试了添加和组合不同的技术,如批量标准化和退出,但是验证损失和验证 AUC 分数波动很大,它们几乎不收敛(如果根本不收敛的话)。因此,我决定带他们出去。
结果
我们将通过下面的图表来看看我们的深度学习模型在每个时期是如何被训练的。
对于左侧的图表,随着历元数的增加,验证损失和训练损失的线彼此接近,这意味着我们的模型似乎没有太多的过拟合或欠拟合。我们还可以在右侧的图表中看到,训练线和验证 AUC 分数最终收敛到几乎相等的点。
对于检测肺炎的情况,我们的目标是高召回率,因为任何延迟诊断都意味着某人可能会真的生病,并可能失去生命。我们首先让我们的模型为 AUC 分数优化,专注于为我们的二元分类提供良好的可分性度量。然后,如果企业对更高或更低的误报或漏报感到更舒服,我们可以调高或调低阈值(从 0.5 开始)。
幻灯片演示模板 go
我们的测试集产生了 97.98%的 AUC 分数,表明我们的 CNN 模型在按测试集中的类别对数据进行排序方面做得很好。当我们有一个类不平衡时,优化 AUC 也是有帮助的,因为我们不想过度适应一个类。
幻灯片演示模板 go
我们的模型达到了 98.72%的召回率。从混淆矩阵中,我们看到,在右上角,模型有 8.49%为假阳性,然后在左下角,模型有 0.80%为假阴性。
幻灯片演示模板 go
密码
既然我们已经解释了一切。让我们看看实际运行的代码。
导入必要的库
设置随机种子
通过数据扩充生成批量图像数据(训练、验证和测试)
训练模型
创建一个输出指标和图表的函数
- 指标:准确度、精确度、召回率、特异性和 F1 分数
- 图表: 1)训练与验证损失
2)训练与验证 AUC
3)混淆矩阵
通过指标和图表输出结果
[Summary Statistics]
Accuracy = 90.71% | Precision = 87.90% | Recall = 98.72% | Specificity = 77.35% | F1 Score = 93.00%
最终模型的指标和图表
未来的工作
幻灯片演示模板 go
我们的模型似乎具有较高的召回率和 AUC 值,但由于数据集的限制,仍然可能存在盲点。如果有更多的时间和资源,我愿意探索以下内容:
1。根据患者居住地和年龄在数据集中包含更多多样性 我们当前的模型是用仅包含居住在中国的 5 岁以下患者的 X 射线图像的数据集进行训练的。这就带来了一个问题,如果患者不在中国居住或处于不同的年龄组,我们的模型是否可以准确地检测到肺炎?为了使模型更加稳健,我希望在数据集中包括更多的多样性,即包括来自世界不同地区和不同年龄的患者的 x 射线图像,例如老年人,因为研究也表明老年人更容易感染 pneumonia⁶.
幻灯片演示模板 go
2。使用在条件复杂性方面更能代表患者人群分布的数据集训练模型 到目前为止,我们已经建立了一个二元分类模型,用于识别患者是否患有肺炎。在现实中,患者可能患有不同类型的肺部疾病(有时一次不止一种),他们仍然会在 X 射线上显示为浸润。我希望将我们当前的数据集与来自 NIH 临床中心的数据集相结合,该数据集由超过 30,000 名患者的超过 110,000 张胸部 x 光图像组成,具有 14 种常见胸部疾病标签。NIH 团队认为,该数据集将“更能代表真实的患者群体分布和现实的临床诊断挑战”。⁵
[1]:美国肺脏协会。(2020 年 5 月 27 日)。了解肺炎。https://www . lung . org/lung-health-diseases/lung-disease-lookup/pneumonia/learn-about-pneumonia
[2]:美国胸科学会。2019 年 20 大肺炎事实。https://www . thoracic . org/patients/patient-resources/resources/top-pneumonia-facts . pdf
[3]: GE 医疗保健。(2019 年 2 月 25 日)。人工智能可能掌握 X 线诊断肺炎的关键。https://www . gehealthcare . com/feature-article/ai-could-hold-the-key-to-identifying-pneumonia-via-x-ray #:~:text = Chest % 20X % 2 ray % 20 have % 20 long,via % 20X % 2Dray % 20a % 20challenge。
[4]:爱德华·道尔。(2006 年 2 月)。需要更多关于肺炎患者的信息吗?试试这些策略。https://www . todays hospitalist . com/Need-more-information-about-the-pneumonia-patient-Try-these-strategies/
[5]:美国国立卫生研究院。(2017 年 9 月 27 日)。 NIH 临床中心向科学界提供最大的公开胸部 x 光数据集之一。https://www . NIH . gov/news-events/news-releases/NIH-clinical-center-provides-one-large-public-available-胸部 x-ray-datasets-scientific-community
[6]:,,和尹。(2015 年 8 月 15 日)。老年重症肺炎:危险因素的多变量分析。https://ncbi.nlm.nih.gov/pmc/articles/PMC4612842/
使用卷积神经网络的肺炎检测
原文:https://towardsdatascience.com/pneumonia-detection-using-convolutional-neural-network-12b94aeb1206?source=collection_archive---------43-----------------------
介绍
随着 AIML 课程的完成,我想把我新学到的知识用于一些兼职项目,这些项目既可以帮助我在该领域获得一些实践经验,又可以解决一个有趣的现实生活问题,或者对它有一些实际用处。在寻找一个符合我需要的项目的过程中,我最终决定建立一个卷积神经网络,通过查看胸部 x 光图像来检测肺炎。
什么是肺炎?
肺炎是一种影响肺部的急性呼吸道感染。肺由称为肺泡的小囊组成,当健康人呼吸时,肺泡中充满空气。当一个人患肺炎时,肺泡中充满了脓和液体,这使得呼吸疼痛,并限制了氧气的摄入。
肺炎是全球儿童死亡的单一最大传染性原因。肺炎在 2017 年导致 808 694 名 5 岁以下儿童死亡,占所有 5 岁以下儿童死亡的 15%。肺炎影响世界各地的儿童和家庭,但在南亚和撒哈拉以南非洲最为普遍。
项目概述
有了这些事实作为灵感,我开始着手我的项目:
首先,我需要弄清楚我可以在哪里构建和运行代码,因为我的系统规格不足以处理构建模型所需的计算能力,所以我使用了谷歌的 Colab。Colab 允许您在浏览器中编写和执行 Python,使用
- 不需要配置
- 免费访问 GPU
- 轻松分享
无论你是一名学生、一名数据科学家还是一名人工智能研究员,Colab 都能让你的工作变得更简单。
注意:需要 API
在下面的代码中,我也提到了如何从 Kaggle 访问数据集,但需要注意的重要事项是:
- 准备好您的 API 密钥文件,即' kaggle.json'
- 使用这种方法,每次在 google collab 中重置运行时,您都将丢失所有文件和生成的模型,因此一旦完成,请始终下载您的模型文件,并在每次重置后记得重新导入数据集
我在努力实现什么?
当你提交一个 5 岁孩子胸部的 x 光图像时,算法应该能够以很高的准确度预测病人是否患有肺炎。
代码
- 首先,你必须把你的 API 密匙文件上传到你在 Colab 的 Jupyter 笔记本上:
- 接下来,从 Kaggle 导入数据集并解压缩:
**from** **google.colab** **import** files
files.upload()!pip install -q kaggle
!mkdir -p ~/.kaggle
!cp kaggle.json ~/.kaggle/
!kaggle datasets download -d paultimothymooney/chest-xray-pneumonia
!unzip /content/chest-xray-pneumonia.zip
- 我使用了 Paul Mooney 的胸部 X 射线图像(肺炎)数据集,因为数据已经方便地分为训练、测试和 val:
- train-包含用于教授我们的模型的训练数据/图像。
- Val —包含我们将用来验证模型的图像。这个数据集的目的是防止我们的模型过度拟合。当模型学习训练数据中的细节和噪声达到对新数据的模型性能产生负面影响的程度时,就会发生过度拟合。这意味着训练数据中的噪声或随机波动被模型拾取并学习为概念。问题是这些概念不适用于新数据,并对模型的概括能力产生负面影响。
- 测试—这包含我们在模型学习了图像与其标签(肺炎/非肺炎)之间的关系后用于测试模型的数据
- 现在,让我们从导入所有需要的库开始:
**from** **keras.models** **import** Sequential
**from** **keras.layers** **import** Conv2D
**from** **keras.layers** **import** MaxPooling2D
**from** **keras.layers** **import** Flatten
**from** **keras.layers** **import** Dense
**from** **keras.preprocessing.image** **import** ImageDataGenerator
**import** **numpy** **as** **np**
**from** **keras.preprocessing** **import** image
**import** **os**
**import** **matplotlib.pyplot** **as** **plt**
**import** **cv2**
- Keras Python 库使创建深度学习模型变得快速而简单。顺序 API 允许您为大多数问题逐层创建模型。它的局限性在于,它不允许您创建共享层或具有多个输入或输出的模型。
- Keras Conv2D 是一个 2D 卷积层,这一层创建一个卷积核,这是风与层输入,这有助于产生输出张量。(注意:-内核:在图像处理中,内核是卷积矩阵或遮罩,可以通过在内核和图像之间进行卷积来用于模糊、锐化、浮雕、边缘检测等。)
- keras.layers 中的 MaxPooling2D,用于池化操作。为了建立这个特殊的神经网络,我们使用最大池函数,存在不同类型的池操作,如最小池、平均池等。在 MaxPooling 中,我们需要各个感兴趣区域的最大值像素。
- 从 keras.layers 展平,用于展平。展平是将所有生成的二维数组转换成一个长的连续线性向量的过程。
- 来自 keras.layers 的 Dense,用于执行神经网络的完全连接
- ImageDataGenerator,它获取一批图像,并对批中的每个图像应用一系列随机变换(包括随机旋转、调整大小、剪切等。)然后用新的随机转换的批次替换原始批次来训练 CNN。
- 我首先定义了两个变量,它们包含我要使用的图像尺寸值和我要使用的批量大小:
img_dims = 64
batch_size = 32
- 然后,我创建了一个 sequential 类的对象,并开始对卷积步骤进行编码:
classifier = Sequential()
classifier.add(Conv2D(32, (3, 3), input_shape = (img_dims, img_dims, 3), activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))
classifier.add(Flatten())
classifier.add(Dense(units = 128, activation = 'relu'))
classifier.add(Dense(units = 1, activation = 'sigmoid'))
- 然后我使用“Conv2D”函数添加了一个卷积层。Conv2D 函数有 4 个参数:
- 第一个是滤波器,这是一个强制性的 Conv2D 参数,定义卷积层将学习的滤波器数量,即 32 个。这里,滤波器用于对图像进行切片,并逐个映射,学习输入图像的不同部分。想象一下,一个小滤镜从左到右从上到下滑过图像,移动的滤镜正在寻找,比如说,一个黑色的边缘。每次找到一个匹配,它就被映射到输出图像上。
- 第二个参数是每个滤波器的形状,这里是 3x3,
- 第三个是每个图像的输入形状和图像类型(RGB 或黑白),即我们的 CNN 将要拍摄的输入图像的分辨率为 64x64”代表 RGB,这是一个彩色图像
- 第四个参数是我们要使用的激活函数,这里“relu”代表一个校正的线性单位函数。激活函数是一个帮助决定神经元是否会触发的节点。Relu 将矩阵 x 中的所有负值设置为零,所有其他值保持不变。
- 现在,我对一幅图像进行卷积运算后得到的合成特征图进行合并运算。池操作的主要目的是尽可能减小图像的大小。
- 接下来,我通过展平将所有汇集的图像转换成一个连续的矢量。展平是理解的一个非常重要的步骤。我们在这里所做的基本上是采用二维数组,即汇集图像像素,并将其转换为一维单一向量。
- 现在,为了创建一个完全连接的层,我已经连接了展平步骤后得到的一组节点,这些节点将作为这些完全连接的层的输入层。“密集”是添加完全连接层的功能,“单位”是我们定义应该出现在此隐藏层中的节点数量的地方。
- 然后我初始化了输出层,它由一个节点组成,给我相应的输出
- 一旦 CNN 模型构建完成,就该编译它了:
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])
- 这里我们使用了以下参数:
- Adam 是一种优化算法,可以用来代替经典的随机梯度下降过程,以基于训练数据迭代地更新网络权重。
- 交叉熵损失或对数损失衡量分类模型的性能,其输出是 0 到 1 之间的概率值。交叉熵损失随着预测概率偏离实际标签而增加。
- 最后,指标参数是选择性能指标。
- 在我们开始将 CNN 拟合到图像数据集之前,我们需要预处理图像以防止过度拟合:
input_path = '/content/chest_xray/'
train_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = **True**)
test_datagen = ImageDataGenerator(rescale = 1./255)
training_set = train_datagen.flow_from_directory(directory=input_path+'train',
target_size = (img_dims, img_dims),
batch_size = batch_size,
class_mode = 'binary')
test_set = test_datagen.flow_from_directory(directory=input_path+'test',
target_size = (img_dims, img_dims),
batch_size = batch_size,
class_mode = 'binary')
- 对于此任务,我们使用了 Keras 的 ImageDataGenerator,并传递了以下参数:
- 重新标度:重新标度因子。默认为无。如果无或为 0,则不应用重缩放,否则我们将数据乘以所提供的值(在应用所有其他变换之后)。
- 剪切 _ 范围:浮动。剪切强度(逆时针方向的剪切角度,单位为度)。用于变换图像方向的剪切。
- zoom_range :浮动或【下,上】。随机缩放的范围。
- 水平 _ 翻转:布尔型。随机水平翻转输入。
- flow_from_directory :获取一个目录的路径,生成批量的扩充/规范化数据。
- 现在让数据符合 CNN 模型:
epochs = 10
hist = classifier.fit_generator( training_set, steps_per_epoch=training_set.samples // batch_size, epochs=epochs, validation_data=test_set, validation_steps= test_set.samples)
- 在上面的代码中,“steps_per_epoch”保存训练图像的数量,即 training_set 文件夹包含的图像的数量。
- 和“时期”,单个时期是训练神经网络的单个步骤;换句话说,当一个神经网络只在一遍中对每个训练样本进行训练时,我们说一个时期结束了。所以训练过程应该由多个时期组成。
- 一旦您最终建立并训练了您的模型,您就可以将图像传递给 classifier.predict()(即[modelname])。predict())函数并获得预测。
- 您还可以使用 classifier.save()(即[modelname])保存您的模型以供将来使用。save())
结果呢
如果你对代码感兴趣,可以去看看 GitHub
我能够实现:
通过改变网络中使用的层数可以获得更高的精度。另一种提高精度的方法是相应地改变超参数。
结论
对于任何具有良好编程技能的开发人员来说,创建一个对数百万人有用的机器学习模型都是相当容易的。
专业人士已经取得了更好的结果。作为一个初学者,我能够达到 89%的准确率,这显然是不错的。但为了在现实世界中被数百万人使用,89%的准确率意味着它将误诊大约 100,000 例病例。
随着未来的发展,ML 技术的改进,但最重要的是——越来越多的人参与其中——我们将能够解决更多这样的问题。
使用深度学习的肺炎检测
原文:https://towardsdatascience.com/pneumonia-detection-using-deep-learning-5dc66468eb9?source=collection_archive---------27-----------------------
使用 PyTorch 的端到端深度学习项目
由 Unsplash 上的融合医学动画拍摄的照片
现代的疫情
随着最近新冠肺炎病毒的爆发,历史似乎正在重演,我们将回到 20 世纪西班牙流感时期。冠状病毒是一种致命的病毒,已经在世界各国夺去了成千上万人的生命。老年人和患有严重基础疾病或先前患有肺炎的人似乎更有可能出现更严重的病毒并发症。随着死亡人数的上升和有限的医疗资源,世界各地的医生和医疗专业人员正在夜以继日地治疗患者和防止病毒传播。病毒的严重形式会导致肺炎,导致更大的死亡风险。快速准确地检测肺炎至关重要,以便患者能够及时接受治疗,尤其是在贫困地区。
随着我们在这个时代不断发展的技术进步,有可能使用基于深度学习框架的工具来根据胸部 x 光图像检测肺炎。这里的挑战将是帮助诊断过程,允许加快治疗和更好的临床结果。
数据
该项目将使用的数据集是来自 Kaggle 的胸部 x 光图像(肺炎)。数据集由训练数据、验证数据和测试数据组成。训练数据包括 5,216 个胸部 x 射线图像,其中 3,875 个图像显示为患有肺炎,1,341 个图像显示为正常。验证数据相对较少,只有 16 幅图像,其中有 8 个肺炎病例和 8 个正常病例。测试数据包括在 390 个肺炎病例和 234 个正常病例之间分割的 624 个图像。
从训练数据可以看出,数据非常不平衡。肺炎病例似乎比正常病例多三倍,这是有道理的,因为这是医学数据。由于验证数据是一个小样本,所以我将在应用训练/验证拆分之前,将它与训练数据合并,并混洗新的数据集。
在研究了数据集中的一些图像后,我注意到一些图像是灰度 1 通道的,而另一些是 3 通道的。在进行任何转换和数据加载之前,数据需要保持一致,所以我决定将所有单通道图像转换为 3 通道图像。这可以简单地通过重复单通道值 3 次来完成,如下面我的代码中针对 PneumoniaDataset 类所示。
对于训练集和验证集,我决定进行 80/20 的划分。对于数据转换,我选择将图像大小调整为(256,256)大小,并使用 90 度仿射转换。数据转换或扩充是一种强大的技术,在几乎所有情况下都有助于提高模型的稳健性。当数据集不平衡时,这种技术甚至会更有帮助。您可以生成欠采样类的不同样本,以便尝试平衡总体分布。为了简单起见,我将只使用原始数据集。对于批量大小,我将使用 16 的大小,因为较低的批量大小将有助于防止我们的模型过度拟合。让我们快速浏览一下训练和验证集中的一些图片。
在仔细观察这些图像后,除了医疗专业人员,任何人都很难区分正常病例和肺炎病例。如果我们能够建立一个强大的模型,这肯定会对医疗专业人员的工作有很大帮助,最终有望帮助他们节省时间和金钱。
模型
我们的初始模型将是一个简单的 8 层卷积神经网络,具有最大池和 ReLU 激活功能。让我们看看模型在验证和测试集上表现如何。
我们可以看到,我们的模型在训练和验证数据集上做得很好,但未能正确分类测试集中的一半以上的图像。我们的模型肯定是过度拟合,所以我们需要引入一些正则化技术,可以帮助解决这个问题。让我们定义一个新的模型,它具有批处理规范化和丢弃,这两种常见的规范化技术在防止过度拟合方面非常有用。
随着批量标准化、丢弃和几个更多层的引入,这个模型被证明比以前的模型好得多。它现在能够正确分类测试数据集中超过一半的图像。然而,这仍然不足以在现实世界中舒适地使用。到目前为止,我们使用的模型还不够复杂,不足以捕捉错综复杂的图像。为了解决这个问题,我们使用迁移学习的优化技术,我们将为一个目的训练的复杂模型重新用于另一个目的。在这种情况下,我们将使用在 ImageNet 数据集上训练的预训练残差网络,并将该模型重新用于我们的胸部 x 射线数据集。我们将使用一个 34 层剩余网络,最后一层有漏失,看看它与以前的模型相比有多好。
测试精度约为 83%,这无疑是对前两种模型的改进。这显示了使用迁移学习来解决一般图像问题的能力和有效性。虽然测试的准确性已经显著提高,但这是否足以部署到现实世界中仍然是个问题。让我们在一些测试图像上尝试该模型。
这个模型显然不是很好,但它的功能仍然令人印象深刻。在分类上面两张图是有病还是正常方面肯定比我强。
最后的话
在这个项目中,我们发现了迁移学习的力量,以及它如何改善深度学习模型的性能。最终的模型当然可以通过进一步添加正则化和优化技术以及调整超参数得到更多的改进。此外,在不平衡的数据集上进行训练并不是最佳的,因此在这种情况下,生成新的图像来平衡分布也将被证明是有用的。
参考
- 胸部 x 光数据集
- 源代码
使用深度学习和 swagger 的肺炎检测。
原文:https://towardsdatascience.com/pneumonia-detection-using-deep-learning-and-swagger-18aa5e8af576?source=collection_archive---------34-----------------------
深度学习| Swagger API
在这个故事中,我们将通过使用深度学习检测肺炎的步骤,并使用 swagger 部署模型。
来自突发的莎拉普夫卢格的照片
在本文中,我们将借助胸部 X 射线进行肺炎检测。此外,我们还将使用 swagger API 为它添加一个 GUI。这里需要注意的重要一点是,创建 GUI 所需的时间将会大大减少。由于本文有两个主要部分,我们将讨论深度学习在肺炎检测中的使用,然后使用 swagger 创建一个快速前端。
深度学习在肺炎检测中的应用:
在任何深度学习用例中,可以开始的第一个术语是数据。在这次检测中,我们将使用正常和肺炎胸部 x 光片的数据集这里。数据集包含训练、测试和验证三个目录。这三个子目录中的子目录是:normal 和 pneumonia,其中包含用于训练、测试和验证模型的图像。我们总共有 5856 张图片。理解了数据集之后,现在让我们进入训练部分。首先,我们将导入所有有用的库
**import os
import pandas as pd
import numpy as np****from** **keras.layers** **import** Input, Lambda, Dense, Flatten
**from** **keras.models** **import** Model
**from** **keras.applications.vgg16** **import** VGG16
**from** **keras.applications.vgg16** **import** preprocess_input
**from** **keras.preprocessing** **import** image
**from** **keras.preprocessing.image** **import** ImageDataGenerator
**from** **keras.models** **import** Sequential
**from** **glob** **import** glob
**import** **matplotlib.pyplot** **as** **plt**
在上面的代码片段中,我们导入了像 NumPy 这样的库,用于数组处理,pandas,用于数据帧创建和操作,OS,用于路径和目录相关的操作。当我们在代码中使用它时,其他目录将被讨论。
在这个问题中,我们将保持所有图像的大小相同。因此,调整所有图像的大小。
IMAGE_SIZE = [224, 224]
我们将在变量中声明训练和测试路径。之后,在我们的例子中,我们使用迁移学习技术,如 VGG16,以获得更好的准确性。为此,我们必须导入 VGG16 模型。
vgg = VGG16(input_shape=IMAGE_SIZE + [3], weights='imagenet', include_top=**False**)
由于有三个 RGB 通道,输入形状参数为正 3。权重取自 imagenet 竞赛。此外,include_top 保持为 False,因为我们只需要在两个类之间进行分类。
为了不重新训练预训练层,我们必须将所有可训练层设为假。
**for** layer **in** vgg.layers:
layer.trainable = **False**
为了获得列表中 train 文件夹路径下的所有类别,我们使用了一个 glob 方法。
folders = glob('/chest-xray-pneumonia/chest_xray/chest_xray/train/*')
通过将 include_top 保持为 False,我们没有指定模型中的最后一层。在这里,我们将添加我们定制的最后一层。
x = Flatten()(vgg.output)*#this removes the last layers*
prediction = Dense(len(folders), activation='softmax')(x)
在预测中,当添加一个密集层时,我们传递了参数 len(folders ),它表示正常和肺炎这两个类别。所以,len(文件夹)是两个。指定最后一层后,我们现在将创建一个对象模型。其具有标准的 VGG 输入(我们在上面已经定义)和作为输出的预测。
model = Model(inputs=vgg.input, outputs=prediction)
现在我们将编译已定义的模型对象。
model.compile(
loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy']
)
在编译之后,加载带有一些预处理和图像增强的数据集,以便我们的模型获得更多可以学习的图像。我们使用图像数据生成器。这有助于通过对给定图像执行水平翻转、剪切和缩放来重新缩放图像并生成更多图像。
**from** **keras.preprocessing.image** **import** ImageDataGenerator
#for test datatest_datagen = ImageDataGenerator(rescale = 1./255)#For train datatrain_datagen = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = **True**)
现在,我们将创建一个训练集,用于模型训练。这个目标是通过使用来自目录函数的流来实现的。
training_set = train_datagen.flow_from_directory('/chest-xray-pneumonia/chest_xray/chest_xray/train',
target_size = (224, 224),
batch_size = 32,
class_mode = 'categorical')# for test datatest_set = test_datagen.flow_from_directory('/chest-xray-pneumonia/chest_xray/chest_xray/test', target_size = (224, 224), batch_size = 32, class_mode = 'categorical')
现在,我们将用 5 个历元训练模型,如果你愿意,你也可以增加历元。
r = model.fit_generator(
training_set,
validation_data=test_set,
epochs=5,
steps_per_epoch=len(training_set),
validation_steps=len(test_set)
)
在成功训练了五个时期的模型后,它给出了大约 95%的验证准确度,这在任何情况下都足够好了。之后,我们将把模型保存在“h5”表单中。
通过 swagger 部署保存的模型
这一部分展示了我们如何快速制作前端来演示我们的模型输出。这将需要不到 10 分钟的时间来执行。这将在另一个名为 app.py 的文件中完成
首先,导入所需的库,如 Flask、flassger 和 swagger
from flask import Flask
import flasgger
from flasgger import Swagger
之后,我们将加载保存的“h5 模型”。
from keras.models import load_model
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
import numpy as np
MODEL_PATH="model_vgg19.h5"
model = load_model(MODEL_PATH)
model._make_predict_function()
在这之后,创建了一个简单的 flask 应用程序,其中 swagger API 用于创建一个易于使用的前端页面。flask 应用程序有两个函数 welcome,当我们点击本地主机链接时会被重定向到这两个函数。另一个功能是 predict_note_file,通过将“/predict_file”添加到本地主机链接来显示在浏览器中。
以下代码描述了 flassger 附带的 flask app 功能。
from flask import Flask, request
import flasgger
from flasgger import Swaggerapp=Flask(__name__)
Swagger(app)[@app](http://twitter.com/app).route('/')
def welcome():
return "Welcome All"[@app](http://twitter.com/app).route('/predict_file',methods=["POST"])
def predict_note_file():
"""Let's Predict Pneumonia
This is using docstrings for specifications.
---
parameters:
- name: file
in: formData
type: file
required: true
responses:
200:
description: The output values
"""
img = image.load_img(request.files.get("file"),target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
img_data = preprocess_input(x)
classes = model.predict(img_data)
A = np.squeeze(np.asarray(classes))
if(A[1]==1):
return "PNEUMONIA"
else:
return "NORMAL"
if __name__=='__main__':
app.run()
在函数 predict_note_file 中,图像数据以 post 方法的形式传输。docstring 包含属性、参数和响应。docstring 中描述的参数被合并到使用 swagger API 生成的页面中。此外,要激活 swagger API,我们必须将“/apidocs”添加到本地主机链接的末尾。当你观看下面的输出演示视频时,你会更加清楚。获得图像后,我们对其进行预处理,使其与我们的模型输入形式兼容,并相应地预测输出。
此图描述了在 swagger API 和其他相关分类器的帮助下进行肺炎检测的逐步过程。
整个系统流程图。
输出:
输出演示
结论
在本文中,我们看到了如何用一个非常简单的前端 UI 实现肺炎检测,而不需要前端做太多工作。这个 flassger 代码可以被视为一个模板,您可以在这个前端的帮助下轻松部署任何机器学习模型。这对没有任何 web 开发知识的人很有帮助。此外,这也有助于他们轻松地在各种数据上测试他们的模型。因此,本文指出了肺炎检测背后的深度学习技术,并使用 swagger API 来可视化本地服务器上模型的工作。
如果你有任何疑问,那么你可以 ping 我这里的。
对于所有的源代码,你可以访问这里。
肺炎检测的 Web 应用程序
原文:https://towardsdatascience.com/pneumonia-detection-with-keras-and-fastapi-6c10dab657e0?source=collection_archive---------14-----------------------
使用 Keras 和 FastAPI 构建一个简单的 web 应用程序,在 x 光图像中检测肺炎。
所有使用的 Python 3.7 代码都可以在这里找到。本文详细介绍了每个步骤,但是您也可以按照 repo 的自述文件中的说明启动本地服务器。Github repo 还带有预先训练的重量,以防您想跳过训练过程。
本文的目标是用一个简单的模型建立框架。有大量的改进可以提高模型的性能!
肺炎检测
我们将使用标记的胸部 x 光图像来训练肺炎检测模型。数据集托管在 Kaggle 上,由 5863 张 x 光图像组成。肺炎图像被进一步分类为病毒性或细菌性。忽略这个二级分类,我们的模型将图像分类为肺炎或正常。
数据集限制
使用 AI 进行疾病诊断的最大挑战之一是缺乏标记数据。数据不容易获得,只有医疗专业人员有资格标记数据。此外,数据收集通常偏向于特定的人口统计数据和用于收集数据的医院设备。
肺炎数据集中的图像来自广州妇女儿童医疗中心 1-5 岁的儿科患者。由“两位专家医生”对这些图像的诊断进行分级。
每个医院使用的影像工具和不同种族、性别和年龄的患者之间的生物因素有很大的差异。有了这些限制,很难理解我们的模型在一般情况下对肺炎的检测有多好。
属国
码头工人
我们可以在没有 Docker 的情况下启动模型服务器,因此安装 Docker 是完全可选的。如果你想使用 Docker,但还没有安装,请点击这里并按照你正在使用的操作系统的说明进行操作。
Kaggle API
Kaggle API 使得以编程方式/通过命令行界面下载 Kaggle 数据集变得很容易。
- 如果您还没有 Kaggle 帐户,请创建一个
- 在
kaggle.com/USERNAME/accounts.
生成新令牌这将提示您下载一个kaggle.json
文件,其中包含访问 API 的凭证 - 将 json 文件中的凭证作为环境变量导出。最简单的方法是运行:
export KAGGLE_USERNAME = [kaggle username]
export KAGGLE_KEY = [generated_key]
Github 上的代码使用了 direnv ,这是一个用于管理环境变量的 shell 扩展。如果您喜欢使用direnv
来管理 Kaggle 凭证,那么填充.envrc
文件并在目录中运行direnv allow
来接收变量。
安装 Python 依赖项
运行传统的pip install -r requirements.txt
来下载 Python 依赖项。
训练分类器
记录与打印
您将在代码库中找到几个日志记录实例。日志的使用类似于 print 语句,因为它们提供信息、警告并有助于调试。在生产环境中,日志记录优于打印,因为日志更易于配置(可以将日志发送到目的地进行存储/监控),并提供堆栈跟踪来确定其来源。
加载所需的库并设置配置
用于数据处理和模型构建的代码将包含在一个名为Train
的类中。
从 Kaggle 下载数据
当force_download
参数设置为 true 时(或者没有找到数据文件夹时),脚本从 Kaggle 下载并解压数据。
当我们认证 Kaggle API 时,它会在我们的环境变量中搜索凭证。下一行下载数据集,它从self.dataset_name
(paultimothymooney/chest-x-ray-pneumonia)中识别数据集,并将其保存到指定路径。
数据集名称并不总是直观的。我们可以在 Kaggle UI 上通过点击右边的三个垂直点然后Copy API command
找到名字。该名称可以从复制的命令中推断出来。
将数据载入内存
Kaggle 数据集下载到以下 jpeg 图像目录中:
├──火车
│ ├──正常
│ ├──肺炎
├──测试
│ ├──正常
│ ├──肺炎
├──瓦尔
│ ├──正常
│ ├──肺炎
我们将使用 Keras 的 ImageDataGenerator 将这些图像加载到内存中。数据生成器对象使得将数据加载到内存变得容易,并且通过批量加载数据克服了 RAM 的限制。
我们为训练、测试和验证集定义了一个单独的生成器。ImageDataGenerators 附带了一整套可以应用于图像的预处理步骤。为简单起见,我们将只应用 1/255.0 的重新标度因子。
在生成器中,我们指定每个图像的目标尺寸为 64×64 像素,颜色模式为灰度。数据生成器将根据文件夹名推断出类别标签。
用计算机视觉表示图像
彩色图像通常使用三个通道(红色、绿色和蓝色)来表示,而灰度图像使用一个通道来表示。这些表示存储在嵌套数组中,其中每个值代表特定通道的像素色调。像素值范围从 0(黑色)到 255(白色)。
为什么要除以 255?
将每个像素除以 255.0 是归一化数据的常用方法。这允许分类器更快地收敛(较小的值=更快的计算)。缩放的另一种标准化技术是定心。我们可以通过将数据转换成标准的正态分布来集中我们的数据。
定义模型
对于这个应用程序,我们将从头开始训练我们的模型。然而,对于少于 6000 个图像,这并不理想。图像分类的复杂性与高维特征空间相结合,使得在小数据集上训练的分类器容易过拟合。
因此,对于小数据集,从预训练模型进行迁移学习是一种非常受欢迎的方法。
迁移学习
在迁移学习中,我们采用一个复杂的预训练模型(如 VGG 或 ResNet),该模型从大型数据集学习复杂的标准对象检测。我们冻结(实质上删除)最后几个层,并根据较小的数据集重新训练这些层。这允许复杂模型理解胸部 X 射线之间的区别。
训练模型
我们使用fit_generator
批量拟合模型。
“部署”模型
部署步骤将模型权重保存在同一目录中的特定位置。对于一个较大规模的项目,这个位置将是集中的,可能托管在一个云存储服务,如 S3。在下一部分中,应用程序将使用这些权重进行推理来恢复模型。
模型性能
第 3 行显示测试准确率为 76%。测试集中有 624 个 x 射线图像(390 个肺炎,234 个正常)。f1 的分数是 72%。
根据记录,我为模型架构创建了一个通用的 CNN,所以提高这个性能应该很容易。
部署应用程序
我们将使用 FastAPI 和 Docker 来部署这个应用程序。在本节中,我将大量引用我以前关于 FastAPI 的一篇文章。
创建路由器
路由器用于将复杂的 API 分解成更小的部分。每台路由器都有自己的前缀来标记这种分离。虽然这不是立即需要的,但我决定使用路由器,以防我们的 API 变得更加复杂。
创建一个名为routers
的文件夹来存放我们的路由器。在routers
文件夹中,定义接收 x 光图像后输出分类结果的 API 端点。
向应用程序发送数据
我们不应该要求客户端应用程序发送 numpy 数组来接收分类输出。对于大多数应用程序来说,这将是非常乏味的。
方便的是,FastAPI 接受File
对象,在这种情况下是图像的二进制表示。使用PILLOW
库,我们可以将字节转换成 numpy 数组。
定义应用程序
在与routers
文件夹相同的目录下,创建另一个脚本app.py
。在此脚本中,定义应用程序并指定路由器。
我们还定义了一个healthcheck
函数。健康检查 API 返回应用程序的运行状态。当应用程序健康时,我们的健康检查返回文本 Good to go 。注意,这调用了一个200
状态代码。
在本地运行应用程序
我们可以通过在命令行中运行以下代码来本地启动我们的应用程序:
uvicorn --host 0.0.0.0 --port 5000 classifier.app:app
日志通知我们服务器正在运行于 http://0.0.0.0:5000
我们可以通过编程向服务器发送 POST 请求,但这需要将图像的字节再现作为参数传递。
方便的是,我们可以去http://0 . 0 . 0:5000/docs获得更友好的 UI。
点击绿色的 POST 按钮,它会把你带到这个页面。
在右侧,单击尝试一下。
这将提示您上传图像。在 Github repo 的 fixtures 文件夹中,您可以找到我从训练集中提取的几张图片(不用于判断模型性能!).该名称表示类别。
我上传了pneumonia_1.jpeg
,收到了以下结果:
很好,我们为肺炎检测构建了一个漂亮的本地应用程序!
repo 更进一步,添加了一个Dockerfile
来用 Docker 构建应用程序。Dockers 将构建和运行应用程序所需的一切封装在一个地方,使得通过公共 URL 共享和部署变得更加容易。
如果您克隆了 repo,您可以按照 README 中的说明构建并运行 Docker 容器。
感谢您的阅读!
如果你喜欢这篇文章,可以看看我关于数据科学、数学和编程的其他文章。请通过媒体关注我的最新消息。😃
作为一个业余爱好项目,我还在www.dscrashcourse.com建立了一套全面的免费数据科学课程和练习题。
如果你想支持我的写作,下次你报名参加 Coursera 课程时,可以考虑使用我的会员链接。完全公开—我从每一次注册中获得佣金,但不会对您产生额外费用。
再次感谢您的阅读!📕
使用深度学习的肺炎诊断
原文:https://towardsdatascience.com/pneumonia-diagnosis-using-cnns-bfd71e3c05?source=collection_archive---------20-----------------------
用卷积神经网络对胸部 x 光片进行分类
简介
在医疗保健领域,医疗专业人员面临的主要问题之一是正确诊断患者的病情和疾病。不能正确诊断病情对病人和医生来说都是一个问题。如果医生误诊了病人,那么医生就没有以适当的方式使病人受益。这可能会导致医疗事故诉讼,并从整体上损害医生的业务。患者因得不到适当的治疗而遭受痛苦,并因病情未被发现而面临更大的健康损害风险;此外,患者经受不必要的治疗并服用不必要的药物,耗费患者的时间和金钱。
如果我们能够正确诊断患者的病情,我们就有可能解决上述问题。如果我们可以产生深度学习模型,可以对患者是否患有某种疾病进行分类,可以确定患者患有哪种特定疾病,并可以确定疾病的严重程度,那么医疗专业人员将能够使用这些模型来更好地诊断他们的患者。通过允许对患者进行及时治疗,准确的诊断也是有用的;被误诊会导致延误接受适当的治疗。
在本文中,我们将对代表来自广州市妇女儿童医疗中心的儿科患者的胸部 x 射线的数据集进行深度学习。
我想应用一个卷积神经网络(CNN)并尝试将一个病人分为肺炎或没有肺炎。这是一个二元分类问题。我还想用 CNN 来给病人分类,要么是细菌性肺炎,要么是病毒性肺炎,要么是没有肺炎。这是一个三级分类问题。
这是 x 光的一个样本:
来源【CC BY 4.0】
[正常的胸部 x 光片(左图)描绘了清晰的肺部,图像中没有任何异常浑浊区域。细菌性肺炎(中)典型地表现为局灶性肺叶实变,在本例中为右上叶(白色箭头),而病毒性肺炎(右)表现为双肺弥漫性“间质”样改变。(克马尼等人,2018 年)]
显然,细菌性肺炎的不透明区域更集中在一个肺叶,而病毒性肺炎的不透明区域更分散在两个肺。右肺分为三叶,左肺分为两叶。对我来说,如何区分这两者当然不是很明显。希望深度学习可以帮助我们区分这两者。
数据准备
数据集可以在这里找到:https://www . ka ggle . com/paultimothymooney/chest-x ray-pneumonia # IM-0007-0001 . JPEG
数据来自两个文件夹,一个用于训练集,一个用于测试集。训练集文件夹包含用于肺炎病例的图像文件夹和用于正常病例的图像文件夹。训练集总共包括 5216 幅图像。测试集文件夹包含一个肺炎病例图像文件夹和一个正常病例图像文件夹。测试集总共由 624 幅图像组成,约占总图像集的 10.68%。与经典机器学习中的情况不同,我们不必担心数据集的各种属性;在卷积神经网络的情况下,我们只有一组图像。
卷积神经网络
然而,在应用人工神经网络之前,需要对图像进行一些准备。需要在称为卷积的过程中使用卷积层来准备图像。这个过程有几个阶段——卷积运算、ReLU 运算、汇集、展平;最终结果是一个向量,我们可以将其输入到人工神经网络中。
这是一个通用 CNN 架构的图像:
图片来源【By aphex 34—自己的作品,CC BY-SA 4.0】
在卷积操作期间,各种特征检测器被应用于图像,创建一堆特征图-这一堆特征图被称为卷积层。ReLU 被应用于每个特征图以增强非线性。在汇集阶段,也称为子采样,我们将最大汇集(或一些其他类型的汇集)应用于每个特征图,创建较小的特征图,保留图像的相关特征。合并的专题地图的最终堆叠构成了合并图层。
一旦我们到达由汇集的特征地图组成的汇集层,每个汇集的特征地图被展平成一个向量,并且产生的向量被顺序地组合成一个向量。这个向量的输入被送入人工神经网络的输入单元。因此,对应于一个图像的展平向量的条目被馈送到 ANN 的输入单元中。(这与传统数据集上使用的人工神经网络形成对比,在传统数据集上,单个实例的属性被输入到人工神经网络的输入单元中)。然后,人工神经网络在训练集上被训练,并在测试集上被测试。这是安将军的图像:
在 CNN 架构图中,人工神经网络从“完全连接”开始。如您所见,卷积神经网络是卷积和人工神经网络的结合。
用 Python 构建 CNN
为了构建 CNN,我们导入 Keras 库和包:
#Importing the Keras libraries and packagesfrom keras.models import Sequentialfrom keras.layers import Convolution2Dfrom keras.layers import MaxPooling2Dfrom keras.layers import Flattenfrom keras.layers import Dense
顺序包用于初始化 CNN。Convolution2D 包用于创建卷积层。MaxPooling2D 包用于创建汇集的要素地图。展平包用于将汇集的要素地图的堆叠展平为一个可输入人工神经网络的矢量。密集包用于向人工神经网络添加层。
接下来,我们通过创建一个 Sequential 类的对象来初始化 CNN。这个对象我们称之为“分类器”:
#Initialising the CNNclassifier = Sequential()
我们将通过对输入图像应用 32 个 3x 3 维度的过滤器(特征检测器)来添加一个 32 个过滤器映射的卷积层。我们希望我们的输入图像具有 64 乘 64 的尺寸,并被视为具有 3 个通道的彩色图像。我们还使用激活函数“relu”将 ReLU 应用于每个特征图:
#Step 1 - Convolutionclassifier.add(Convolution2D(32,(3,3),input_shape=(64,64,3),activation = 'relu'))
既然我们在卷积层中有了我们的特征图,我们使用一个 2×2 的网格将最大池应用于每个特征图。
#Step 2 - Poolingclassifier.add(MaxPooling2D((2,2)))
现在,我们有了一个由汇集的要素地图组成的汇集图层,我们将每个汇集的要素地图展平成一个矢量,并将所有生成的矢量按顺序组合成一个巨大的矢量。
#Step 3 - Flatteningclassifier.add(Flatten())
接下来,我们将添加我们的人工神经网络。首先,我们添加一个隐藏层的 128 个单位,并使用激活功能' relu '。其次,我们添加由一个输出单元组成的输出层,并使用 sigmoid 函数作为激活函数;我们使用一个输出单位,因为我们的输出是二进制的(正常或肺炎)。
#Step 4 - Full connectionclassifier.add(Dense(units=128,activation='relu'))classifier.add(Dense(units=1, activation='sigmoid'))
现在,我们需要编译 CNN。我们将使用“adam”作为随机梯度下降中的优化器,使用二进制交叉熵作为损失函数,使用准确性作为性能指标。
#Compiling the CNNclassifier.compile(optimizer = 'adam',loss='binary_crossentropy',metrics=['accuracy'])
我们的训练集和测试集加起来总共有 5840 幅图像;因此,我们将应用图像增强来增加我们的训练集和测试集的大小,同时减少过度拟合。然后,我们将 CNN 拟合到我们的增强训练集,并在我们的增强测试集上对其进行测试:
#Fitting the CNN to the imagesfrom keras.preprocessing.image import ImageDataGeneratortrain_datagen = ImageDataGenerator(rescale=1./255,shear_range=0.2,zoom_range=0.2,horizontal_flip=True)test_datagen = ImageDataGenerator(rescale=1./255)training_set = train_datagen.flow_from_directory('chest_xraybinary/train',target_size=(64, 64),batch_size=32,class_mode='binary')test_set = test_datagen.flow_from_directory('chest_xraybinary/test',target_size=(64,64),batch_size=32,class_mode='binary')classifier.fit_generator(training_set,epochs=25,validation_data=test_set)
经过 25 个时期后,我在训练集和测试集上分别获得了 95%和 89%的准确率。
评估、改进和调整 CNN
以前,我们建立了一个 CNN,有一个卷积层和一个隐藏层。这一次,我们将添加第二个卷积层,看看它是否能提高性能。我们只需在步骤 2 —池化之后添加以下代码:
#Adding a second convolutional layerclassifier.add(Convolution2D(32,(3,3),activation = 'relu'))classifier.add(MaxPooling2D((2,2)))
经过 25 个时期后,我们在训练集和测试集上分别获得了 96%和 91.5%的准确率。
接下来,除了第二个卷积层之外,我们还将添加第二个隐藏层,看看它是否能提高性能。要添加第二个隐藏层,我们只需复制添加一个隐藏层的代码:
#Step 4 - Full connectionclassifier.add(Dense(units=128,activation='relu'))classifier.add(Dense(units=128,activation='relu'))classifier.add(Dense(units=1, activation='sigmoid'))
经过 25 个时期后,我们在训练集和测试集上分别获得了 96%和 91.5%的准确率。添加第二个隐藏层不会提高性能。
区分细菌性和病毒性肺炎
我们不仅要区分正常和肺炎 x 射线,还要区分细菌性和病毒性肺炎 x 射线。为此,我们将包含肺炎病例的文件夹分成两个文件夹,一个用于细菌病例,另一个用于病毒病例。现在,我们有一个三类分类问题,其中类是正常、细菌和病毒。就像我们用一个 CNN 解决二分类问题一样,我们可以用一个 CNN 解决三分类问题。除了少数例外,代码保持不变。在 CNN 的人工神经网络阶段,我们将输出单元的数量从 1 更改为 3,并将输出激活函数从“sigmoid”更改为“softmax”。在编译 CNN 时,损失函数从‘二元 _ 交叉熵’变为‘分类 _ 交叉熵’。当将 CNN 拟合到图像时,不使用文件夹“chest_xraybinary ”,而是使用文件夹“chest_xray ”,该文件夹包含训练和测试集文件夹,每个文件夹具有对应于三个类别的三个文件夹。class_mode 从“二进制”更改为“分类”。
经过 25 个纪元,我在训练集上获得了 80.64%的准确率,在测试集上获得了 83.33%的准确率。
添加了第二个卷积层;经过 25 个时期后,我在训练集和测试集上分别获得了 81.33%和 85.9%的准确率。这在性能上是一个微小的改进。
除了第二个卷积层,还增加了第二个隐藏层;经过 25 个时期后,我在训练集和测试集上分别获得了 80.25%和 86.7%的准确率。在测试集上,这是一个轻微的性能改进。
除了第二个卷积层和第二个隐藏层,我还将第二个卷积层的特征检测器数量从 32 个改为 64 个。经过 25 个时期后,我在训练集和测试集上分别获得了 81%和 87%的准确率。这是具有两个卷积层和两个隐藏层的 CNN 的测试集性能的微小改进。然而,这是一个体面的改善测试集的性能从 CNN 的一个卷积层和一个隐藏层。然后,我将输入 CNN 的图像尺寸从 64×64 增加到 128×128;这导致在训练集上的准确率为 80.85%,在测试集上的准确率为 85.74%,比我们迄今为止达到的性能要差。
我将输入图像的尺寸降低到 64 乘 64,并添加了第三个由 128 个特征检测器组成的卷积层。这使得训练集和测试集的准确率分别达到了 81.54%和 87.34%,比我们目前所取得的成绩有了很小的提高。给定当前设置,我运行 CNN 200 个纪元;训练集的准确率稳步上升到 96.32%,而训练集的准确率在 80%和 80%之间波动,最终为 86.54%。
保留三个卷积层,我增加了更多的隐藏层,总共 10 个隐藏层;经过 25 个时代,我得到了 79.54%的训练集准确率和 83.33%的测试集准确率。所以,增加更多的隐藏层并没有带来改善。
结论
在本文中,我们将卷积神经网络应用于确定胸部 x 光片属于两个类别(正常或肺炎)中的哪一个的二元分类问题。我们发现,具有一个卷积层和一个隐藏层的 CNN 在训练集上实现了 95%的准确率,在测试集上实现了 89%的准确率。然后,我们在 CNN 中添加了第二个卷积层,并在训练集和测试集上分别获得了 96%和 91.5%的准确率;这稍微提高了性能。接下来,除了有第二个卷积层,我们还增加了第二个隐藏层,并在训练集和测试集上分别达到了 96%和 91.5%的准确率;这并没有提高性能。
我们还将卷积神经网络应用于三类分类问题,以确定胸部 x 光片属于三类中的哪一类——正常、细菌或病毒。我们发现,具有一个卷积层和一个隐藏层的 CNN 在训练集上达到了 80.64%的准确率,在测试集上达到了 83.33%的准确率。然后,我们向 CNN 添加了第二个卷积层,并在训练集和测试集上分别实现了 81.33%和 85.9%的准确率,这是一个微小的改进。接下来,除了有第二个卷积层之外,我们还添加了第二个隐藏层,并在训练集上实现了 80.25%的准确率,在测试集上实现了 86.7%的准确率,这在测试集上的性能略有改善,但在训练集上的改善有所下降。除了第二卷积层和第二隐藏层之外,将第二卷积层中的特征检测器的数量从 32 改变为 64,在 25 个时期之后,在训练集上的准确率为 81%,在测试集上的准确率为 87%。添加 128 个特征检测器的第三卷积层导致训练集的准确率为 81.54%,测试集的准确率为 87.34%。
因为我们的总数据集中只有有限数量的图像,所以使用图像增强来提供更多的图像来训练 CNN 是很重要的;这种缺乏足够数量的医学图像似乎是除肺炎之外的其他医学问题的共同问题。因此,在图像数量不足的情况下,图像增强有望成为一种有用的工具。
考虑到在世界的某些地区,可能缺乏能够阅读和解释 x 射线的训练有素的专业人员,因此有可能根据患者的 x 射线进行自动诊断。
在经典机器学习技术的情况下,有时我们能够识别在确定机器学习模型的输出中有意义的特定属性。另一方面,在卷积神经网络的情况下,没有我们可以识别为在确定 CNN 模型的输出中有意义的属性集;我们有的只是图像和它们的像素。此外,很难直观地理解 CNN 模型是如何进行分类的。
我们培训的 CNN 使用了来自中国广州的 1-5 岁儿童患者的胸部 x 光片。我们的 CNN 能否适用于其他年龄段的孩子,适用于中国以外的孩子,甚至适用于成年人?深度学习如何用于检测特定肺炎病例的严重程度?这些都是值得探讨的开放性问题,以进一步了解如何将图像分类用于医学诊断。
该数据集可在以下位置找到:
https://www . ka ggle . com/paultimothymooney/chest-x ray-pneumonia # IM-0007-0001 . JPEG
承认
资料:【https://data.mendeley.com/datasets/rscbjbr9sj/2
执照: CC BY 4.0
引用:http://www . cell . com/cell/full text/s 0092-8674(18)30154-5
参考文献
肺炎患者胸部 X 线的示例。确定医疗诊断和可治疗的疾病
基于图像的深度学习疾病, Cell 172,1122–1131,2018 年 2 月 22 日,爱思唯尔公司,https://doi.org/10.1016/j.cell.2018.02.010
位置数据的点模式分析
原文:https://towardsdatascience.com/point-pattern-analysis-of-location-data-1346f318865d?source=collection_archive---------25-----------------------
用于测量密度、距离、热点等的空间统计和点模式分析
克里斯·劳顿在 Unsplash 上的照片
你可能听说过“位置智能”——应用地理空间和数据科学工具&技术将位置数据转化为商业价值。2018 年发表的一项研究显示,所有公司都在某种程度上收集和维护位置数据。然而,他们中只有少数人能够利用这些有价值的信息进行决策,要么是因为他们不知道如何在业务决策中使用这些信息,要么是因为他们不具备分析地理空间数据的适当技术能力。事情变化很快,每个行业现在都更加重视位置数据的广泛应用。
图:纽约市犯罪地图[ 来源 ]
什么是位置数据?
当我们在智能手机和 GPS 时代提到“位置数据”时,人们往往会认为它们是手机和导航设备产生的数据。相反,我这里指的是静态对象和事件的位置。静态对象的一个例子是位于美国的每一家星巴克店,而事件的位置可以是城市中所有车祸发生的地方。这种位置数据通常与其他数据集结合使用,用于各种各样的应用,我们将在下面看到。
如何使用位置数据?
在公共服务或商业中,没有一个领域的位置数据是无用的。下面是这些应用案例中的几个例子。
- 公共政策:大部分市县收集并记录犯罪地点的数据(例如)。这些犯罪地点数据随后被用于了解哪里是热点,这有助于有效地分配有限的资源,以改善公共安全。
- 流行病学:科技公司手中有一个用户位置信息的宝库,可以通过研究来了解正在进行的疫情新冠肺炎的传播。匿名追踪 30 多万名感染者的位置有助于回答流行病学家仍在思考的许多问题。它可以帮助理解社会距离是否有任何影响。美国政府和科技巨头正在谈判来解决这个难题。
- 商业:位置数据正在改变零售商业。它使他们能够了解自己的客户群,有效地储备库存,并根据需求优化仓库位置。同样,通过使用周围地区的位置数据,企业可以找到做生意的最佳地点(参见 WeWork 如何利用位置智能进行业务扩展)。
- 房地产:当人们寻找房子或其他房地产时,位置可能是最重要的标准。它帮助购房者找到符合他们搜索标准的房产,如学区、社区、到办公室的距离等。
- 环境管理:地理空间分析和位置数据是大部分环境管理的核心。康奈尔鸟类学实验室管理的 eBird 平台就是一个例子,观鸟者可以上传他们遇到的鸟的信息。这个公开的数据集被广泛用于科学研究和保护管理。
位置数据是如何分析的?
分析位置数据是地理信息系统(GIS)的一个成熟分支,称为“点模式分析(PPA)”。PPA 无非是对二维空间中数据点(纬度/经度)的空间排列的分析。就像统计数据分析一样,在 PPA,位置数据使用探索性数据分析(EDA)技术进行分析。一旦你画出物体和事件的地理坐标,就可以进行各种 EDA 来回答特定的问题或测试假设。分析位置数据的最常用技术如下:
图:点数据在空间中的不同排列方式[ 来源
中心图
中心图测量位置数据的基本描述性统计数据,如中心趋势(如平均中心)、离散度(如标准偏差椭圆)和空间方差,它告诉我们数据在空间中是如何聚集或分散的。
图:空间数据的集中趋势[ 来源
密度分析
一般来说,密度是指单位面积内的观测次数。例如,如果在 4 平方英里的城市区域有 20 家咖啡店,那么我们会说这个城市每平方英里有 5 家。这是一个计算密度的简单方法,但是“内核密度”可能是所有密度分析中最广为人知的。
密度对于理解观测热点非常有价值。它还用作数据驱动决策的进一步分析的输入(例如,给定车祸热点时部署的交通警察数量)。
图:数据点的核密度
距离分析
在基于密度的技术中,数据点的分布与研究区域相关。相比之下,基于距离的方法显示数据点在空间中的相对分布。有一些技巧可以做到这一点:
- 平均最近邻(ANN) 测量给定观测值的相邻数据点的平均距离。它能告诉我们数据点是聚集的还是分散的。
图:左侧最近邻的平均距离较短
- K 函数测量空间中所有点之间的距离,而不是像 ANN 那样只测量邻居之间的距离。这也有助于理解数据在距其中心(质心)不同距离处是如何聚集或分散的。有一种标准化的方法来实现 K 函数以增加可解释性——L 函数。
图:K 函数描述了从中心开始的不同扫描范围内聚类是如何发生的
建模
不仅仅是测量数据点的空间统计数据。您可以进行许多其他分析,例如观察值(例如犯罪地点)如何与基础协变量(例如人口密度)相关以及它们如何随时间变化等的空间相关性分析。有很多方法可以使用复杂的模型来处理点数据,例如泊松模型,但是我将这一点放在另一个讨论中。
快速交互式可视化
现在我们知道了什么是位置数据、它们的用途以及如何分析它们,下面简单介绍一下如何用几行代码创建一个交互式地图来可视化位置数据。
数据只有两列——经度和纬度——代表马里兰州 Montgomery 县一些随机选择的犯罪事件的位置。您可以从官方的空间数据仓库中找到并下载这些数据。
# libraries needed
library(sf)
library(mapview)# download data from the link shown above# import data
df = read.csv("../filename.csv", sep = ",", stringsAsFactors = FALSE )
# randomly sample few datapoints from this big dataset
d = df[sample(nrow(df), 500), ]# create a dataframe of latitude and longitude columns
latlong = d[, c(27,28)]# convert the dataset to sf object
point <- st_as_sf(x = latlong,
coords = c("Longitude", "Latitude"),
crs = "+proj=longlat +datum=WGS84")
# create an interactive map:
mapview(point, cex = 1.0)# There!!!
图:犯罪地点随机选择的数据点
结束注释
一旦您了解了空间统计的基础知识以及如何处理相关的库,点数据分析就会变得非常有趣。在以后的文章中,我将深入研究真实世界数据集的实际应用,所以请保持联系。
最后,大家要坚强,照顾好自己和家人。非常时期需要非常措施,希望我们能尽快度过这一难关。
一些有用的资源
- 使用
[spatstats](https://cran.r-project.org/web/packages/spatstat/vignettes/shapefiles.pdf)
包处理 shapefiles - Manuel Gimond 的《地理信息系统和空间分析简介》开放访问书
- 打开 access book: 带 R 的空间数据科学
- 数据点的非空间可视化示例
把你的相机对准事物,听听它们用另一种语言怎么说
原文:https://towardsdatascience.com/point-your-camera-at-things-to-hear-how-to-say-them-in-another-language-fa6e9f3621a5?source=collection_archive---------59-----------------------
通过 Google Cloud Vision 和 Translate API 引入事物翻译器
资料来源:github.com/dmotz
当你去那些你不说他们语言的国家旅行时,谷歌翻译已经成为一个无价的工具。在大多数情况下,你会对着应用说话或输入单词来获得翻译。如今,有了谷歌翻译的相机功能,你就可以把相机对准用另一种语言写的文本,然后翻译成你的母语。
当我想知道我是否可以把这样的相机翻译功能带到网上时,我看到了这个网络应用程序“东西翻译器”。它是作为谷歌人工智能实验项目的一部分开发的,它可以让你将手机(或笔记本电脑)指向某些东西,然后听到用不同的语言说出来。
东西翻译演示
点击下面的链接亲自尝试一下:
[## 事物翻译器
把你的相机对准事物,听听它们用不同的语言怎么说
thing-translator.appspot.com](https://thing-translator.appspot.com/)
履行
在幕后,Thing Translator 正在使用谷歌的云视觉和翻译API。在本文中,我将进一步探索代码,请跟随我,这样您也可以自己构建这个很酷的应用程序。
#第一步:注册谷歌云 API
因为这个 web 应用程序使用的是 Google 的云 API,所以要开始使用,你需要在 Google 中设置一个项目来使用它的 2 个 API。
你可能害怕谷歌会对你的实验收费,请不要担心,你的实验是免费的:
- 谷歌提供了 300 美元的信用额度来免费使用 GCP
- 视觉 API 的第一个1000请求和翻译 API 的第一个500000字符每月免费
- 你可以限制你的 API 使用
谷歌提供了如何设置的一步一步的指导,更多细节可以在谷歌云 API 入门中找到
在 GCP(谷歌云平台)中设置好 API 后,复制并保存 API 密匙,以便在 web 应用中使用。
#步骤 2:克隆和构建存储库
接下来,从 GitHub 克隆或下载 Thing Translator 库
git clone [https://github.com/dmotz/thing-translator.git](https://github.com/dmotz/thing-translator.git)
您需要在src/config.js
中设置您的 API 密钥
要在9966
上启动一个监视代码变更的开发服务器,只需运行:
npm start
要优化生产输出,请运行:
npm run build
现在,你可以玩这个摄像头翻译网络应用程序,学习如何用另一种语言说一些事情。
如果你也很好奇它在幕后是如何工作的,请跟随我在下面深入研究代码。
谷歌云视觉应用编程接口的使用
通过使用 Google Cloud Vision API,我们希望传递快照图像,并获得图像中有哪些对象的响应。
在src/effects/snap.js
中,你可以在snap
函数中找到调用谷歌云视觉 API 的代码。Vision API 可以对图像文件执行LABEL_DETECTION
,方法是将图像文件的内容作为 base64 编码的字符串发送到请求体中。
xhr.post(
apiUrls.cloudVision,
{
json: {
requests: [
{
**image: {
content: state.canvas
.toDataURL('image/jpeg', 1)
.replace('data:image/jpeg;base64,', '')
},
features: {type: 'LABEL_DETECTION', maxResults: 10}**
}
]
}
}
如果请求成功,服务器返回一个200 OK
HTTP 状态代码和 JSON 格式的响应。LABEL_DETECTION
响应包括检测到的标签、它们的分数、话题性和不透明标签 ID:
{
"responses": [
{
"labelAnnotations": [
{
"mid": "/m/0838f",
**"description": "Water",
"score": 0.9388793**,
"topicality": 0.9388793
},
{
"mid": "/m/039jq",
"description": "Glass",
"score": 0.85439134,
"topicality": 0.85439134
},
......
]
}
]
}
现在,它通过检测快照中的内容完成了一半的工作。接下来,它会把它翻译成另一种语言。
谷歌云翻译 API 的使用
通过使用 Google Cloud Translate API,我们希望传递英语单词,并获得另一种语言的翻译结果。
在src/effects/translate.js
中,可以在translate
函数中找到调用 Google Cloud Translate API 的代码。下面是我们传递的查询参数:
- q —要翻译的输入文本。
- 源—源文本的语言。
- 目标—用于翻译输入文本的语言
xhr.get(
**${apiUrls.translate}&q=${term}&source=en&target**=${
langMap[state.activeLang]
}
如果成功,响应正文包含具有以下结构的数据:
{
"data": {
"translations": [
{
**"translatedText": "水"**
}
]
}
}
一旦它在文本中获得翻译,最后一步是知道如何在选定的语言中发音。
浏览器语音合成 API 的使用
它利用浏览器的语音合成 API 将文本转换成语音,并朗读译文。
const msg = new SpeechSynthesisUtterance();
msg.text = text;
msg.lang = voices[voiceMap[lang]].lang;
speechSynthesis.speak(msg);
语音合成 API 将正常语言文本转换成人工语音,现在大多数现代浏览器都支持它
来源:caniuse.com/#search=speech-synthesis
GitHub 知识库
您可以通过下面的链接下载上述演示的完整代码:
[## dmotz/事物翻译器
东西翻译是一个网络应用程序,让你把手机(或笔记本电脑)指向东西,听它用不同的方式说…
github.com](https://github.com/dmotz/thing-translator)
图片来自 Pixabay
结论
这是一个例子,说明你可以使用谷歌的机器学习 API,而不需要深入机器学习的细节。毫无疑问,谷歌是在机器学习和人工智能领域领先的全球公司之一。站在巨人的肩膀上,你可以看到更远的未来。
感谢您的阅读。如果你喜欢这篇文章,请在脸书或推特上分享。如果你有任何问题,请在评论中告诉我。在 GitHub 和 Linkedin 上关注我。
Poke-Agent:口袋妖怪战斗和机器学习
原文:https://towardsdatascience.com/poke-agent-pokemon-battling-reinforcement-learning-27ef10885c5c?source=collection_archive---------11-----------------------
机器学习模型已经在许多游戏中击败了人类——但不是口袋妖怪。让我们解决这个问题。
杰伦在 Unsplash 上的照片
定义问题
口袋妖怪战斗包括选择每个回合的最佳移动,给定两个队的当前状态。最好的方法是使用超级有效的方法,或者换成另一个口袋妖怪(如果你希望自己的口袋妖怪有超级有效的方法)。
学习玩口袋妖怪是一项复杂的任务,即使对人类来说也是如此,所以我们将在本文中关注一个机制:类型有效性。
场景:我们会给模型 Poke-Agent 一个杰尼龟,让它试着打败一个小火龙。杰尼龟将会知道抓伤、咆哮和水枪,做出最佳策略只是垃圾水枪,因为,作为一个水型招式,它对像小火龙这样的火型口袋妖怪是超级有效的。
还有其他策略可以赢,比如发 Scratch 或者综合使用这三种策略,但是,由于这些策略的风险,这些策略会导致更多的损失。最佳策略将在 3 个回合中获胜。
学习
由于 Poke-Agent 正在进行口袋妖怪战斗,我们可以将它的经历分为状态和动作。游戏的状态(剩余的血量,场上有什么口袋妖怪等等。)将通知 Poke-Agent 将采取什么行动。因此,我们可以让 Poke-Agent 为每个状态-动作配对分配一个值,以指示某个动作对于特定状态有多好:值越高,该动作对于该状态越好。当它需要做出决定时,它可以只选择价值最高的动作。
这个过程是一种叫做 Q-Learning 的强化学习,前面提到的值叫做 Q-values。当我们想要更新这些 Q 值时,我们使用这个函数:
q-学习更新功能
这可能看起来令人生畏,但它的直觉很简单。体验之后,我们会根据模型是否表现出想要的行为给予奖励。我们将更新模型经历的状态-动作对的 Q 值,方法是给它加上我们期望在下一个状态得到的奖励。
因此,如果模型执行了一个导致预期结果的动作,例如使用水枪赢得口袋妖怪战斗,我们期望在执行该动作后获得奖励,因此该状态和动作的 Q 值增加。对于消极的结果来说,情况正好相反,比如输掉一场战斗:我们会期待消极的回报,因此该状态和行动的 Q 值会降低。
我们将使用 MSE ( 均方差)作为我们的损失函数:
均方误差
其中 Yᵢ是旧的 q 值,ŷᵢ是新的 q 值。
架构
通常,Q 值保存在内存中的一个表中,然而,口袋妖怪战斗有太多不同的状态-动作对,难以处理。相反,我们将使用神经网络来学习游戏的表示,它可以用来计算好的 Q 值。
戳代理体系结构
我决定保持 Poke-Agent 的架构简单,直到它看起来需要更复杂。
输入:首先,每个回合的事件将被转换成向量,并用作模型的输入。
嵌入:回合信息将被传递到一个嵌入层,以便模型可以创建口袋妖怪战斗中概念的表示(口袋妖怪名称、招式、状态条件等。)希望这种表示将相似的概念组合在一起:杰尼龟和水枪的表示应该相似。
线性:这一层将是实际计算 Q 值的地方——它封装了模型的决策过程。
输出:线性层将为模型可以采取的每个动作生成 Q 值。我们将把最高值解释为它想要做出的决定。
PyTorch 代码如下:
vocab_size
是口袋妖怪中的概念数。这是一个口袋妖怪,移动,状态条件和战斗事件名称的汇编。
[nn.ReLU](https://en.wikipedia.org/wiki/Rectifier_(neural_networks))
是一个激活函数,允许模型学习复杂的概念。
环境
口袋妖怪对决
口袋妖怪摊牌是一个在线口袋妖怪战斗模拟器,我们将用它来模拟战斗。
培养
我们将有两个代理:扑克代理,和一个随机代理,它只选择随机移动。
以下是培训过程:
- 举例说明两个代理之间的战斗
- 随着时间的推移,随着双方代理人做出决策,让接下来的战斗展开
- 使用最后 2 个回合作为 Poke-Agent 的输入来更新其 Q 值
- 重复
我们只使用最后两轮,因为那时我们可以根据模型是否获胜来分配奖励。
大约 80 场战斗后,训练损失如下:
起初,由于随机代理人和扑克代理人基本上都是随机选择移动,所以很公平。在大约 50 场战斗中,这个模型了解到水枪会带来快速的胜利。每场战斗的平均回合数从 10 到 3,每次都是扑克玩家获胜。
不幸的是,我没有一个关于~ 58 战发生了什么导致训练损失如此之大的解释。也许那是它得知水枪的时候!
最终想法
看到损失下降,扑克经纪人开始持续赢钱,真是令人鼓舞!就概念和架构而言,要与人类进行一场真正的口袋妖怪战斗还有很长的路要走。
现在,这个模型只对当前的游戏状态做出决定,但是给这个模型一系列的转折来做决定可能是有用的。让它从一系列动作中学习,而不是像目前的训练模式那样只从一个动作中学习,这也是很有趣的。
仍然有许多研究需要深入和实施,还有许多实验需要尝试。我将教 Poke-Agent 更高级的策略,比如如何切换— 在 twitter 上关注我关注下一篇文章。
[## 凯勒·刘易斯
凯勒·刘易斯的最新推文(@caleb_dre)。我烘焙&写代码,方程(有时候),还有@fold_app 的手机…
twitter.com](https://twitter.com/caleb_dre)
基于策略的方法
原文:https://towardsdatascience.com/policy-based-methods-8ae60927a78d?source=collection_archive---------17-----------------------
深度强化学习讲解— 18
爬山算法
这是一个新的帖子,专门介绍深度强化学习讲解系列。这里我们将介绍一类算法,允许我们近似策略函数π,而不是值函数(V 或 Q)。记住,我们将策略**定义为告诉我们在每个状态下做什么的实体。也就是说,我们将训练一个输出行动值的网络,而不是训练一个输出行动(的概率)的网络,正如我们在第 6 篇文章中用一个例子推进的那样。****
基于价值的方法综述
在以前的帖子中介绍的值迭代和 Q-learning 的中心主题是状态的值(用 V 表示)或状态-动作的值(用 Q 表示)。请记住,价值被定义为我们可以从一个州或通过从该州发布一个特定的行动收集的贴现总奖励。如果价值是已知的,每一步的决定就变得简单而明显:贪婪地考虑价值,这保证了在一集结束时有一个好的总回报。为了获得这些值,我们使用了贝尔曼方程,它通过下一步的值来表达当前步的值(它根据预测进行预测)。
基于政策的方法
强化学习最终是关于从与环境的交互中学习最优策略,用π表示。到目前为止,我们一直在学习基于价值的方法,其中我们首先找到最佳行动价值函数 q的估计,从中我们可以获得最佳策略π。***
对于小的状态空间,像文章 1 中介绍的冰湖例子,这个最优值函数 q可以用一个表来表示,Q-table,每个状态一行,每个动作一列。在每一个时间步,对于一个给定的状态,我们只需要从表中拉出其对应的行,最优的动作就是具有最大值条目的动作。*
但是对于具有更大状态空间的环境,比如前几篇文章中介绍的 Pong 环境,该怎么办呢?有大量的可能状态,这使得表格太大,在实践中没有用。因此,我们提出了如何用神经网络来表示最佳动作值函数 q。在这种情况下,神经网络将环境状态作为输入,并将每个可能动作的值作为输出返回。*
但重要的是要注意,在这两种情况下,无论我们使用表格还是神经网络,我们都必须首先估计最佳行动值函数,然后才能处理最佳策略π。然后,一个有趣的问题出现了:我们能直接找到最优策略,而不必首先处理一个价值函数吗?答案是肯定的,完成这一任务的算法被称为基于策略的方法。*
使用基于价值的方法,代理人利用其对环境的经验来维持对最佳行动价值函数的估计。然后从最佳动作值函数估计中获得最佳策略(例如,使用 e-greedy)。
基于价值的方法
相反,基于策略的方法直接从与环境的交互中学习最优策略,而不必维护单独的价值函数估计。
基于政策的方法
基于策略的方法的一个例子,在本系列的开始已经介绍过了,在第 6 篇文章中介绍了交叉熵方法。我们介绍了一个策略,用𝜋(𝑎|𝑠表示),表示代理应该对每个观察到的状态采取什么动作。在实践中,策略通常表示为动作(代理在给定状态下可以采取的动作)的概率分布,类的数量等于我们可以执行的动作的数量。我们称之为随机策略,因为它返回动作的概率分布,而不是返回单个确定性动作。
与价值预测方法相比,基于政策的方法有一些优势,比如 DQN 在之前的三篇文章中提到的方法。一是,正如我们已经讨论过的,我们不再需要担心设计一个像ϵ一样的行动选择策略——贪婪政策;相反,我们直接从策略中抽取动作。这很重要。请记住,我们浪费了大量的时间来修正方法,以提高我们的 DQN 训练的稳定性。例如,我们必须使用经验回放和目标网络,在学术文献中还有其他几种方法可以帮助我们。政策网络有助于简化这种复杂性。
用神经网络逼近策略函数
在深度强化学习中,用神经网络来表示策略是很常见的(就像我们在 Post 6 中第一次做的那样)。让我们以本系列第 12 期文章中的推车平衡问题为例,介绍我们如何用神经网络来表示策略。
请记住,在本例中,一辆小车位于沿水平轴的无摩擦轨道上,一根柱子固定在小车顶部。目标是通过向左或向右移动小车来防止杆倒下,并且不要从轨道上掉下来。
通过对手推车施加+1(左)或-1(右)的力来控制该系统。钟摆开始直立,目标是防止它翻倒。柱子保持直立的每个时间步提供+1 奖励,包括该集的最后一步。当柱子偏离垂直方向超过 15 度,或者手推车偏离中心超过 2.4 个单位时,该集结束。
该环境在每个时间点的观察空间是 4 个数字的阵列。在每个时间步,你可以观察它的位置,速度,角度和角速度。这些是这个世界的可观察状态。你可以在这份文件中查找这些数字分别代表什么。请注意小车速度和尖端极点速度的最小值(-Inf)和最大值(Inf)。由于数组中对应于这些索引的条目可以是任何实数,这意味着状态空间是无限的!
在任何状态下,小车只有两种可能的动作:向左移动或向右移动。换句话说,车极的状态空间有四维连续值,动作空间有一维两个离散值。****
我们可以构建一个神经网络来逼近以一个状态作为输入的策略。在本例中,输出层将有两个节点,分别返回每个动作的概率。一般来说,如果环境具有离散的动作空间,如本例所示,输出层对于每个可能的动作都有一个节点,并且包含代理应该选择每个可能的动作的概率。
来源: torres.ai
使用网络的方法是代理提供当前的环境状态,然后代理从动作的概率(在本例中是左或右)中进行采样,以选择其下一个动作。
然后,目标是确定由θ(θ)表示的网络权重的适当值。 θ 对我们传入网络的每个状态进行编码,它返回最有可能选择最优行动的行动概率。所选择的行动会影响用来获得回报的回报。**
记住代理人的目标永远是期望收益最大化。在我们的例子中,让我们将预期收益表示为 J 。主要思想是可以把预期收益 J 写成 θ的函数。 稍后我们将看到如何表达这种关系, J(θ), 用一种更“数学”的方式来寻找使预期收益最大化的权重值。
无导数方法
在上一节中,我们已经看到了神经网络如何表示策略。这个神经网络中的权重最初被设置为随机值。然后,代理在与环境交互时更新权重。本节将概述优化这些权重的方法,即无导数方法,也称为零阶方法。
无导数方法直接在参数空间中搜索权重向量,以最大化通过策略获得的回报;通过仅评估参数空间的一些位置,而没有计算梯度的导数。让我们解释一下这一类别中最简单的算法,这将有助于我们稍后理解政策梯度方法如何工作,即爬山法。
爬山
爬山是一种迭代算法,可用于找到最优策略的权重 θ 。它是一个相对简单的算法,代理可以使用它在与环境交互的同时逐渐提高其策略网络中的权重 θ 。
顾名思义,直观地说,我们可以看到算法制定了一个到达一座山的最高点的策略,其中 θ 表示我们在给定时刻所处的坐标,G 表示我们在该点的高度:
爬山例子:代理的目标是最大化期望收益 j,这个例子的神经网络中的权重是 θ = (θ1,θ2)。
这个可视化的例子表示两个参数的函数,但是相同的思想可以扩展到两个以上的参数。该算法从对【θ】***(随机权重集)的值的初始猜测开始。我们收集具有对应于那些权重 θ 的策略的单个剧集,然后记录返回 G 。*****
这个返回是对表面在θ值的估计。这不会是一个完美的估计,因为我们刚刚收集的回报不太可能等于预期回报。这是因为由于环境中的随机性(以及政策,如果它是随机的),如果我们收集第二集的 θ 值相同,我们很可能会得到不同的回报值g,但在实践中,即使(采样)回报不是预期回报估计的完美估计,但它通常证明是足够好的。****
在每一次迭代中,我们稍微扰动权重 θ 的当前最佳估计值(添加一点随机噪声),以产生一组我们可以尝试的新的候选权重。这些新的权重然后被用于收集一集。为了看看这些新的权重有多好,我们将使用它们给我们的策略,再次与一集的环境进行交互,并累加回报。
在增加新的权重,给我们比当前最佳估计更多的回报时,我们将注意力集中在新的价值上,然后我们只是重复迭代地提出新的政策,希望它们优于现有的政策。如果他们做得不好,我们就回到上一次对最优策略的最佳猜测,反复迭代,直到得到最优策略。
现在我们对爬山算法应该如何工作有了直观的理解,我们可以用下面的伪代码来总结它:
- 用随机权重 θ 初始化策略 π
- 初始化 θbest (我们对权重的最佳猜测 θ )
- 初始化 Gbest (我们目前得到的最高回报 G )
- 用 θbest、 收集单集并记录返回的 G
- 如果 G > Gbest 那么θ最好 ← θ** 和 Gbest ← G****
- 给 的θbest 添加一点随机噪声,得到一组新的权重 θ
- 重复步骤 4–6,直到解决环境问题。
在我们的例子中,我们假设一个表面只有一个最大值,其中爬山算法非常适合。注意, 而不是 保证总是在具有多个局部最大值的曲面上产生最优策略的权重。这是因为如果算法开始于一个差的位置,它可能会收敛到较低的最大值。**
编码爬山
本节将基于前面的伪代码探索应用于 小车环境的爬山实现。这里的神经网络模型非常简单,只使用了最简单的形状矩阵**[4x2]**
(state _ space x action _ space),不使用张量(不需要 PyTorch,甚至也不需要 GPU)。**
本节介绍的代码可以在 GitHub 上找到(而可以使用这个链接作为 Colab google 笔记本运行)。
在这篇文章中,由于它重复了我们一直在使用的许多东西,我们将不详细描述代码;我认为这是不言自明的。
和往常一样,我们将从导入所需的包开始,并创建环境:
****import** **gym**
**import** **numpy** **as** **np**
**from** **collections** **import** deque
**import** **matplotlib.pyplot** **as** **plt**env = gym.make('CartPole-v0')**
策略π(及其用随机权重 θ 初始化)可以编码为:
****class** **Policy**():
**def** __init__(self, s_size=4, a_size=2):
*# 1\. Initialize policy π with random weights*
self.θ = 1e-4*np.random.rand(s_size, a_size)
**def** forward(self, state):
x = np.dot(state, self.θ)
**return** np.exp(x)/sum(np.exp(x))
**def** act(self, state):
probs = self.forward(state)
action = np.argmax(probs) *# deterministic policy*
**return** action**
为了可视化训练的效果,我们绘制了训练前后的权重 θ ,并呈现了代理如何应用策略:
****def** watch_agent():
env = gym.make('CartPole-v0')
state = env.reset()
rewards = []
img = plt.imshow(env.render(mode='rgb_array'))
**for** t **in** range(2000):
action = policy.act(state)
img.set_data(env.render(mode='rgb_array'))
plt.axis('off')
display.display(plt.gcf())
display.clear_output(wait=**True**)
state, reward, done, _ = env.step(action)
rewards.append(reward)
**if** done:
print("Reward:", sum([r **for** r **in** rewards]))
**break**
env.close()policy = Policy()
print ("Policy weights θ before train:**\n**", policy.θ)
watch_agent()Policy weights θ before train:
[[6.30558674e-06 2.13219853e-05]
[2.32801200e-05 5.86359967e-05]
[1.33454380e-05 6.69857175e-05]
[9.39527443e-05 6.65193884e-05]]
Reward: 9.0**
运行 collab 中的代码,您将能够看到代理如何处理横拉杆。
以下代码定义了训练代理的函数:
****def** hill_climbing(n_episodes=10000, gamma=1.0, noise=1e-2):
*"""Implementation of hill climbing.*
*Params*
*======*
*n_episodes (int): maximum number of training episodes*
*gamma (float): discount rate*
*noise(float): standard deviation of additive noise*
*"""*
scores_deque = deque(maxlen=100)
scores = []
*#2\. Initialize θbest* Gbest = -np.Inf
*#3\. Initialize Gbest*
θbest = policy.θ **for** i_episode **in** range(1, n_episodes+1):
rewards = []
state = env.reset()
**while** **True**:
*#4.Collect a single episode with θ,and record the return G*
action = policy.act(state)
state, reward, done, _ = env.step(action)
rewards.append(reward)
**if** done:
**break**
scores_deque.append(sum(rewards))
scores.append(sum(rewards))
discounts = [gamma**i **for** i **in** range(len(rewards)+1)]
G = sum([a*b **for** a,b **in** zip(discounts, rewards)])
**if** G >= Gbest: *# 5\. If G>Gbest then θbest←θ & Gbest←G*
Gbest = G
θbest = policy.θ
*#6\. Add a little bit of random noise to θbes
* policy.θ = θbest + noise * np.random.rand(*policy.θ.shape)
**if** i_episode % 10 == 0:
print('Episode {}\tAverage Score:
{:.2f}'.format(i_episode,
np.mean(scores_deque)))
*# 7\. Repeat steps 4-6 until Environment solved.*
**if** np.mean(scores_deque)>=env.spec.reward_threshold:
print('Environment solved in {:d} episodes!\tAverage
Score: **{:.2f}**'.format(i_episode,
np.mean(scores_deque)))
policy.θ = θbest
**break**
**return** scores**
代码不需要太多的解释,因为它非常清楚,并且用相应的伪代码步骤进行了注释。也许要注意一些细节。例如,该算法寻求最大化累积折扣奖励、和它在 Python 中看起来如下:****
**discounts = [gamma**i **for** i **in** range(len(rewards)+1)]
G = sum([a*b **for** a,b **in** zip(discounts, rewards)])**
请记住,爬山是一个简单的无梯度算法(即,我们不使用梯度上升/梯度下降方法)。我们试图通过仅改变目标函数 G 的自变量,权重矩阵 θ 来达到曲线的顶端,使用某个噪声来确定我们模式中的神经网络:
**policy.θ = θbest + noise * np.random.rand(*policy.θ.shape)**
与前面的一些例子一样,我们试图超过某个阈值来考虑解决的环境。对于 Cartpole-v0 ,该阈值分数为**195**
,用env.spec.reward_threshold
表示。在我们用来写这篇文章的例子中,我们只需要 215 集来解决环境问题:
**scores = hill_climbing(gamma=0.9)Episode 10 Average Score: 59.50
Episode 20 Average Score: 95.45
Episode 30 Average Score: 122.37
Episode 40 Average Score: 134.60
Episode 50 Average Score: 145.60
Episode 60 Average Score: 149.38
Episode 70 Average Score: 154.33
Episode 80 Average Score: 160.04
Episode 90 Average Score: 163.56
Episode 100 Average Score: 166.87
Episode 110 Average Score: 174.70
Episode 120 Average Score: 168.54
Episode 130 Average Score: 170.92
Episode 140 Average Score: 173.79
Episode 150 Average Score: 174.83
Episode 160 Average Score: 178.00
Episode 170 Average Score: 179.60
Episode 180 Average Score: 179.58
Episode 190 Average Score: 180.41
Episode 200 Average Score: 180.74
Episode 210 Average Score: 186.96Environment solved in 215 episodes! Average Score: 195.65**
使用下面的代码,我们可以绘制训练期间每集获得的分数:
**fig = plt.figure()
plt.plot(np.arange(1, len(scores)+1), scores)
plt.ylabel('Score')
plt.xlabel('Episode #')
plt.show()**
现在,在培训之后,我们再次绘制权重 θ 以及代理如何应用这一策略并显得更聪明:
**print ("Policy weights θ after train:\n", policy.θ)
watch_agent()Policy weights θ after train:
[[0.83126272 0.83426041]
[0.83710884 0.86015151]
[0.84691878 0.89171965]
[0.80911446 0.87010399]]Reward: 200.0**
运行 collab 中的代码,您将能够看到代理如何处理横拉杆
虽然在这个例子中,为了简单起见,我们编码了确定性策略,但是基于策略的方法可以学习随机或确定性策略,并且它们可以用于解决具有有限或连续动作空间的环境。
无梯度策略优化
爬山算法不需要可微或者甚至是连续的,但是因为它采取随机的步骤,这可能不会产生最有效的上山路径。在文献中有许多对这种方法的改进:自适应噪声缩放、最速上升爬山、随机重启、模拟退火、进化策略或交叉熵方法(在帖子 6 中介绍了)。
然而,这个问题的通常解决方案考虑政策梯度方法,该方法通过梯度上升来估计最优政策的权重。策略梯度方法是基于策略方法的一个子类,我们将在下一篇文章中介绍。
帖子摘要
在这篇文章中,我们介绍了基于策略的方法的概念。我们之所以考虑基于策略的方法,而不是基于价值的方法,有几个原因,因为基于价值的方法看起来工作得很好,就像我们在上一篇文章中看到的那样。主要是因为基于策略的方法直接解决手边的问题(估计最佳策略),而不必存储额外的数据,即可能没有用的动作值。与基于值的方法相比,基于策略的方法的另一个优点是非常适合连续的动作空间。正如我们将在未来的帖子中看到的,与基于价值的方法不同,基于政策的方法可以学习真正的随机政策。
下一篇见!
深度强化学习讲解系列
由 UPC 巴塞罗那理工 和 巴塞罗那超级计算中心
一个轻松的介绍性系列以一种实用的方式逐渐向读者介绍这项令人兴奋的技术,它是人工智能领域最新突破性进展的真正推动者。
**** [## 深度强化学习解释-乔迪托雷斯。人工智能
本系列的内容](https://torres.ai/deep-reinforcement-learning-explained-series/)
关于这个系列
我在五月份开始写这个系列,那是在巴塞罗那的封锁期。老实说,由于封锁,在业余时间写这些帖子帮助了我 #StayAtHome 。感谢您当年阅读这份刊物;它证明了我所做的努力。
免责声明 —这些帖子是在巴塞罗纳被封锁期间写的,目的是分散个人注意力和传播科学知识,以防对某人有所帮助,但不是为了成为 DRL 地区的学术参考文献。如果读者需要更严谨的文档,本系列的最后一篇文章提供了大量的学术资源和书籍供读者参考。作者意识到这一系列的帖子可能包含一些错误,如果目的是一个学术文件,则需要对英文文本进行修订以改进它。但是,尽管作者想提高内容的数量和质量,他的职业承诺并没有留给他这样做的自由时间。然而,作者同意提炼所有那些读者可以尽快报告的错误。****
多任务/元学习中的策略梯度
原文:https://towardsdatascience.com/policy-gradient-in-multi-task-meta-learning-2aeeaf23817d?source=collection_archive---------47-----------------------
这个故事介绍了多任务强化学习问题和策略梯度&它们的多任务/元对应物。第二部分介绍 Q-学习和多任务 Q-学习。这个故事是对课程'斯坦福 CS330:多任务和元学习,2019 |第六讲—强化学习入门'的简短总结。
via 艺术字
什么时候不需要顺序决策?当您的系统正在做出一个单独的决策(例如分类、回归),并且该决策不影响未来的输入或决策时,您不需要进行顺序决策。常见的应用领域包括机器人、语言和对话、自动驾驶、商业运营和金融。
这个故事将涵盖
- 多任务强化学习问题
- 策略梯度及其多任务/元对应物
这个故事的第二部分将涵盖 Q-学习和多任务 Q-学习。这个故事是课程' Stanford CS330:多任务和元学习,2019 |第六讲—强化学习入门'的简短总结。
多任务强化学习问题
在监督学习中,数据是 iid,我们需要一个大的带标签的、精选的数据集,而在顺序决策中,操作影响下一个状态而不是 iid,对于数据集,如何收集数据?有哪些标签?
监督学习
RL 设置。来源:课程幻灯片
对于监督学习,我们有一个由θ参数化的函数π,它接受 o 并生成输出 a。例如,输入可以是图像,而输出可以是图像类(s.t. tiger)。在 RL 中,我们使用将采取行动的策略,这些行动将影响下一个状态。这将是一个从行动到观察的反馈循环,我们的类(a)将是行动,比如“逃跑”、“忽视”或“抚摸老虎”。o 表示代理(系统)作为输入接收的观察值,a 表示动作,π表示由θ参数化的策略。 通常我们假设世界 s 存在某种潜在状态,在完全观测的情况下,s 被观测到。在部分观察设置中,观察到 o。
o 和 s 的具体区别是什么?例如,你试图追逐一只鬣狗,如果给你一张图像,那么这些图像将是一个观察 o,而相反,如果给你相应动物的姿势,那么这些姿势将是 s。你基本上能够完全观察到系统的潜在状态以及世界上对决策有影响的事情。
模仿学习。来源:课程幻灯片
解决顺序决策问题的一个基本方法是将其视为监督学习(SL)问题。 比如你想模仿某些专家。也许您可以收集一组驾驶数据,收集人们看到的观察结果,并收集他们在这些状态下采取的行动,将其放入一些大的训练数据集中,然后在监督学习期间从这些训练数据集中采样 iid,以训练您的策略根据观察结果预测行动。如果您有大量关于执行正确操作的专家数据,这种方法在某些情况下很有效。但是这些系统不以任何方式推理结果,而只是模仿数据在做什么。
在 RL 中,需要奖励函数。这些奖励函数应该捕捉什么样的状态和行为对系统更好或更坏。它通常接受状态和动作(r(s,a)
),并告诉我们哪些状态和动作更好。例如,如果我们在开车,如果我们开得平稳,我们可能会得到很高的奖励,如果我们发生车祸,我们会得到很低的奖励。
总的来说,状态s
、行动a
和回报r(s,a)
,以及系统的动态p(s'|s,a)
定义了一个马尔可夫决策过程,因为这包含了顺序决策问题的概念。
RL 示例。来源:课程幻灯片
因此,强化学习的目标通常是学习作为输入的策略参数。 在这种情况下,我们将把完全观察到的设定值作为输入状态,并对动作做出预测。目标是了解政策的参数。在深度 RL 设置中,您的策略可能会被参数化为神经网络,其中状态作为输入被处理,动作作为输出。行动反馈给世界,然后世界给你下一个状态,反馈给你的政策。
RL 图形模型。来源:课程幻灯片
实际上,我们可以将系统描述为图形模型,其中我们有一个策略,它接受观察并产生一个动作(部分观察的设置),动态接受当前状态,当前动作产生下一个状态的分布。 动态函数独立于前一状态,这就是所谓的马尔可夫性质。 基本上一个 马尔可夫决策过程 中的一个状态的定义就是 你可以从那个状态变量中的信息独立于之前的状态来完全定义奖励函数和动力学。 你看这里的图,只取决于 St 和 at,不取决于 st-1。
无限/有限视野情况下的 RL 目标。来源:课程幻灯片
RL 的具体目标是最大化政策下的期望报酬。在无限期的情况下,我们希望在平稳分布下最大化回报函数,平稳分布在政策产生的状态和行动上。在有限范围的情况下,我们可能有一些范围资本 T,当推出我们的政策时,您希望最大化州和行动的回报。
SL 任务和 RL 任务
我们已经讨论了 RL 问题,那么 RL 的任务是什么呢?如果将 RL 与监督学习设置进行比较,初始状态分布和动态基本上与数据生成分布相同。回报函数对应于损失函数,状态和行为空间只是告诉你,你的状态和行为所处的一般集合。所以这只是作为一个马尔可夫决策过程。但是如果不同的 MDP 是不同的任务,那么这就不仅仅是任务的语义意义了。因为不同的任务可能有相同的确切奖励函数,但有不同的行动空间或不同的动态。因此,我们不严格地使用术语“任务”来描述这些不同的马尔可夫决策过程。
个性化推荐和跨策略。来源:课程幻灯片
如何在元学习中应用 RL?的一个应用是个性化推荐,不同的人有不同的任务。动力对应于那个人将如何对你采取的特定行动作出反应,奖励函数对应于你是否在一个好的状态下向结果推荐一些东西。在某些情况下,初始状态分布也可能因人而异,这取决于你如何表述你的问题。另一个应用是跨机动,例如,跨不同机动在计算机图形中制作不同角色的动画。如果你把这当成一个多任务学习问题,不同的任务在环境中会有不同的奖励函数,但是动力是一样的,状态和动作空间也是一样的。
RL 的另类观点。来源:课程幻灯片
查看多任务 RL 的另一种方法如下。 我们通常有某种任务标识符,它是状态的一部分,这是使它成为完全可观察的设置或完全可观察的 MDP 所必需的。s 条表示原始状态,zi 表示任务标识符。基本上,任务被视为标准的马尔可夫决策过程,其中状态空间和动作空间是原始任务中的状态空间和动作空间的并集。初始状态分布恰好对应于初始状态分布上的混合分布。对于这些任务中的每一个,动态和奖励函数是单个动态和单个奖励函数,其将任务标识符作为输入,并产生下一个状态或奖励。所以你基本上可以应用标准的单任务 RL 算法来解决多任务问题。
以目标为条件的强化学习的奖励函数
多任务 RL 与单任务 RL 问题相同,除了任务标识符是状态的一部分(s = (s bar,zi))。例如,任务标识符可以是一次性任务 ID、任务的语言描述或您想要达到的目标状态。这个 目标状态 会被称为 目标制约 RL 其中你把它限制在你希望将来能够达到的特定状态。奖励函数可以与之前的相同 w 这里,它将任务 id 作为输入,并输出对应于该状态的任务的奖励函数,或者对于像目标条件 RL 这样的事情,它可以简单地对应于您的(原始)当前状态和目标状态之间的负距离。距离函数的一些例子可以是某个潜在空间中的欧几里德距离或稀疏 0/1,其中 1 表示 s 条等于 sg,0 表示不相等。如果这仍然是标准的马尔可夫决策过程,那么为什么不应用标准的 RL 算法呢?你可以,但这将比单独的任务更具挑战性,因为你将有更广泛的事情要做。
策略梯度及其多任务/元对应项
强化学习算法的剖析。来源:课程幻灯片
您通常可以在下面的流程图中查看 RL 算法,我们首先在环境中生成样本,这通常只是向前运行策略,然后我们拟合一些模型来估计回报,然后我们使用该模型来改进策略。 不同的算法通常只对应这个绿框和这个蓝框的差异。例如,拟合模型的一个例子可能是估计经验回报,如使用蒙特卡罗政策梯度。估计回报的另一个例子可能是尝试拟合 Q 函数,例如使用动态编程算法。拟合模型的另一个例子是估计模拟动态的函数。例如,一旦我们有了这些模型,我们就可以将策略梯度应用于我们的策略参数,我们可以通过取当前 Q 函数的最大 Q 值来改进策略,或者在基于模型的算法的情况下,我们可以通过将模型反向传播到策略中来优化策略。
评估目标。来源:课程幻灯片
所以先说政策梯度。以上是我们在 RL 中的目标,所以我们希望能够从我们的策略中采样轨迹并估计回报。我们将这个目标称为θ的 J。我们可以重写θ的 J。例如,您可以将此视为或估计为滚动和轨迹,如右图所示,这是计算每个轨迹的奖励,可能第一个轨迹的奖励高,中间轨迹的奖励中等,最后一个轨迹的奖励差。 第一个总和是我们策略中样本的总和,第二个总和是一段时间的总和。
直接政策分化。来源:课程幻灯片
我们能否将这一目标直接转化为我们的政策? 所以如果我们的目标是预期收益,我们可以用轨迹的收益来估计。你可以把这个期望看作π θ上的积分,因为这个期望是关于τ的π θ的。如果您想要计算该目标相对于我们的政策参数的梯度,您可以将梯度移入积分中,因为这是一个线性操作,然后您基本上就有了政策乘以回报函数的梯度在轨迹上的积分。我们如何评估这个梯度呢?我们不需要对所有可能的轨迹进行积分。所以我们打算 使用似然比技巧。两个π被抵消,它等于π的梯度或策略的梯度与策略参数的比值。在应用方便的恒等式之后, 我们可以简单地评估梯度,或者通过对从我们的策略中采样的轨迹进行期望来估计梯度,并使用这些样本来评估我们的策略的对数概率的梯度,该对数概率由该轨迹的回报进行加权。π的完整轨迹可以分解为初始态密度乘以一个随时间乘积的政策概率和动力学概率。经过计算,最终的梯度是我们可以评估的。
评估政策梯度。来源:课程幻灯片
我们基本上可以排除我们的策略来获得轨迹,然后通过在 log π乘以奖励函数的时间内对这些轨迹进行平均来估计策略梯度,然后将梯度应用于我们的策略参数。如果我们回到图中,收集数据对应于橙色框(对应于右侧公式中的橙色下划线部分),评估回报对应于绿色框(对应于绿色下划线部分),在最后一步中实际使用它来改进策略对应于蓝色框(对应于蓝色下划线部分)。 增强算法是从您的策略中显式采样轨迹,然后使用这些轨迹计算梯度,然后使用估计的梯度更新您的策略参数。然后你可以重复这一步来迭代改进你的策略 。
与最大似然比较。来源:课程幻灯片
这与模仿学习,如专家行动的最大可能性相比如何? 最大似然目标看起来非常类似于 的策略形式。特别是,区别在于右边的奖励项。所以基本上政策梯度将对应于最大化有高回报的行动的概率。如果他们有一个低回报,那么你将试图最大化它本质上更少。因为它基本上是一种梯度下降算法,所以很容易将多任务学习算法应用于它。
来源:课程幻灯片
如果我们进行最大似然模仿学习,我们只是试图模仿最佳轨迹,而在政策梯度中,我们在这些轨迹上有一些分布,然后我们将试图增加具有高回报的行动的概率,并在具有低回报的行动上放置较少的概率质量。因此,我们基本上只是让好的东西更有可能,让坏的东西得到坏的回报的可能性更小,并使“试错”的概念正式化。
这就是政策梯度。这很容易与多任务学习结合起来。它也很容易与元学习结合起来。元学习算法(如 MAML 和黑盒方法)假设你可以得到你的目标的一些梯度。因此,我们可以很容易地将这些算法与策略梯度算法结合使用。
例如,让我们把 MAML 和政策梯度结合起来。有两个任务:向前跑和向后跑。我们不以任何方式评价泛化。我们只是要看看它是否能学会用一个单一的梯度步长来适应这两个任务中的一个。
在元学习结束时,但在对其中一个任务采取梯度步骤之前,我们得到了一个看起来正确的策略:原地运行,准备向两个方向中的任何一个方向运行。来源:课程幻灯片
如果我们对具有向后/向前运行的奖励函数的任务取一个梯度,我们得到在相应方向上运行的策略。来源:课程幻灯片
上面的例子表明,存在一种表示,在这种表示下,RL 是快速和有效的。
我们还可以结合黑盒元学习和政策梯度。这是迷宫的例子。这个实验是学习走迷宫,它在 1000 个小迷宫上训练,在伸出的小迷宫和大迷宫上测试。
在这种情况下,它不知道任务,它需要在迷宫中导航。左边是代理人的观点,右边是迷宫。在它获得经验之后,它就能够学习如何用基本上只有一条轨迹的方法来解决迷宫。所以首先在迷宫中导航探索,然后在这一集结束时,建筑的记忆不会被重置。来源:课程幻灯片
MAML 在监督学习环境中很有表现力,但由于策略梯度,它在 RL 中实际上不是很有表现力。基本上,如果你所有轨迹的回报函数都是 0,那么你的梯度将永远是 0。因此,即使它在零回报的情况下获得了大量丰富的环境经验,它实际上也无法将这些经验融入到政策的更新中。因此, 带有政策梯度的 MAML 实际上并不是很有表现力。 一般来说,这些针对 RL 设置的元学习算法很容易与策略梯度相结合,将它们与 Q-learning 和 actor-critic 算法等方法相结合则更具挑战性。
汇总策略梯度
政策梯度。来源:课程幻灯片
策略梯度方法简单且易于与现有的多任务和元学习算法相结合。但是它产生了一个高方差梯度,它可以用基线或信赖域来减轻。政策梯度的另一个缺点是它需要政策数据。你可以看到对ωθ的期望,ωθ是你当前的政策。因此,为了改进您的策略,您需要来自您当前策略的数据。这真的很重要,因为这意味着你不能重复使用以前政策中的任何数据来试图改进你的政策。结果,这些算法往往比能够重用来自先前策略和其他经验等的数据的其他算法的样本效率低。像重要性权重这样的东西可以对此有所帮助。因此,您基本上可以添加一个权重,该权重对应于您当前的策略与您用来收集数据的策略之间的比率。但是这些重要性权重也给了你很高的方差,特别是当这两个策略非常不同时。
参考
- 斯坦福 CS330:多任务和元学习,2019 |讲座 6 —强化学习入门’。
- T 他航向滑梯
- 自动驾驶汽车的端到端学习
- 用于深度网络快速适应的模型不可知元学习
- 一个简单的神经注意力元学习者
政策梯度方法
原文:https://towardsdatascience.com/policy-gradient-methods-104c783251e0?source=collection_archive---------2-----------------------
深度强化学习讲解— 19
强化算法
这是一个新帖子,专门介绍的【梯度法】、、、、深度强化学习讲解、、、系列。策略梯度方法是基于策略方法的一个子类,通过梯度上升来估计最优策略的权重。****
本系列中介绍的强化学习方法的总结。分类是基于我们是否想要对价值或策略建模(来源: https://torres.ai )
直观地说,梯度上升始于对使预期回报最大化的政策权重值的初步猜测,然后,算法评估指示预期回报函数最陡增长方向的点处的梯度,因此我们可以在该方向上迈出一小步。我们希望最终得到一个新的政策权重值,这个值的预期收益函数值会稍微大一点。然后,该算法重复评估梯度和采取步骤的过程,直到它认为最终达到了最大预期回报。
本出版物的西班牙语版本
[## 10.梅托多斯基于政策:加强
获得第 10 版图书介绍
medium.com](https://medium.com/aprendizaje-por-refuerzo/10-métodos-policy-based-reinforce-2f13c11b290f)
介绍
尽管我们在之前的文章中编写了确定性策略,但是基于策略的方法可以学习随机或确定性策略。对于随机策略,我们的神经网络的输出是表示概率分布的动作向量(而不是返回单个确定性动作)。
在这篇文章提出的新方法中,我们将遵循的策略是从这个概率分布中选择一个动作。这意味着,如果我们的代理两次处于相同的状态,我们可能不会每次都采取相同的行动。将动作表示为概率有许多优点,例如平滑表示的优点:如果我们稍微改变我们的网络权重,神经网络的输出就会改变,但可能只是一点点。
在确定性策略的情况下,利用离散数字输出,即使对权重进行小的调整也可能导致跳转到不同的动作。但是,如果输出是概率分布,则权重的小变化通常会导致输出分布的小变化。这是一个非常重要的属性,因为梯度优化方法都是关于调整模型的参数来改善结果。
但是如何改变网络的参数来改进策略呢?如果你还记得第 6 篇的文章,我们使用交叉熵方法解决了一个非常相似的问题:我们的网络将观察结果作为输入,并返回行动的概率分布。事实上,交叉熵方法在某种程度上是我们将在本文中介绍的方法的初级版本。
政策梯度背后的关键思想是强化好的行为:提高导致更高回报的行为的概率,降低导致更低回报的行为的概率,直到你达到最优政策。策略梯度方法将迭代地修改策略网络权重(平滑更新),以使导致正回报的状态-动作对更有可能,并使导致负回报的状态-动作对更不可能。
为了介绍这个想法,我们将从政策梯度方法的一个普通版本(基本版本)开始,称为强化算法 ( 原文)。该算法是基本的策略梯度算法,几乎所有的高级策略梯度算法都基于该算法。
强化:数学定义
让我们来看看算法的更数学的定义,因为这将有助于我们在后面的文章中理解最先进的算法。
轨道
我们需要定义的第一件事是一个轨迹,只是一个状态-行动-奖励序列(但是我们忽略了奖励)。轨迹比一集更灵活一点,因为它的长度没有限制;它可以对应于完整的一集或只是一集的一部分。我们用大写 H 表示长度,其中 H 代表视界,用 τ 表示轨迹:
加强方法建立在轨迹而不是事件上,因为最大化轨迹(而不是事件)上的预期回报使该方法能够为事件和连续任务搜索最佳策略。
虽然对于绝大多数情节任务来说,只有在情节结束时才会给予奖励,但仅仅使用完整的情节作为轨迹是有意义的;否则,我们没有足够的回报信息来有意义地估计预期收益。
轨迹的返回
我们用(τ)、 来表示轨迹 τ 的返回 ,并将其计算为该轨迹 τ: 的总回报
参数 Gk 称为总收益,或未来收益,在时间步长 k 为过渡 k
这是我们期望从时间步 k 直到轨迹结束时收集的回报,并且可以通过使用 gamma γ: 将剧集中某个状态直到剧集结束时的回报相加来近似得到
预期收益
请记住,该算法的目标是找到使我们用【θ】表示的预期收益最大化的神经网络的权重 θ ,并且可以定义为:
为了查看它如何对应于预期回报,请注意,我们已经将回报 R ( τ )表示为轨迹 τ 的函数。然后,我们计算加权平均值,其中权重由P( τ 给出; θ ),每个可能轨迹的概率,返回 R ( τ )可以取的所有可能值。请注意,概率取决于神经网络中的权重 θ ,因为 θ 定义了用于选择轨迹中的动作的策略,这也在确定代理观察的状态中起作用。
梯度上升
正如我们已经介绍的,确定最大化【θ】函数的 θ 值的一种方法是通过梯度上升。
相当于上一篇文章中介绍的爬山算法,我们可以直观地看到,梯度上升制定了一个到达一座山的最高点的策略,【θ】,只是在梯度的方向上迭代地迈出小步:
来源: https://torres.ai
数学上,我们的梯度上升的更新步骤可以表示为:
其中 α 是一般允许随时间衰减的步长(相当于深度学习中的学习率衰减)。一旦我们知道如何计算或估计这个梯度,我们可以重复应用这个更新步骤,希望 θ 收敛到使 U ( θ )最大化的值。
梯度上升与梯度下降密切相关,不同之处在于梯度下降旨在寻找函数的最小值(朝负梯度方向的步长),而梯度上升将寻找最大值(朝梯度方向的步长)。我们将在 PyTorch 的代码中使用这种方法。
抽样和估计
为了应用这种方法,我们将需要能够计算梯度∇u(θ);然而,我们将无法计算出梯度的精确值,因为这在计算上过于昂贵,因为为了精确计算梯度,我们将不得不考虑每一个可能的轨迹,这在大多数情况下成为一个棘手的问题。
该方法不是这样做,而是使用该策略对轨迹进行采样,然后仅使用这些轨迹来估计梯度。这种抽样相当于本系列文章第 13 篇中介绍的蒙特卡洛方法,因此,方法强化也被称为蒙特卡洛策略梯度。
伪代码
总之,更详细地描述该方法行为的伪代码可以写成:
梯度估计公式
让我们更仔细地看看伪代码中步骤 3 的等式,以便理解它。我们首先做一些简化的假设,例如,假设这对应于一个完整的情节。
记住 R ( τ )只是每个时间步从轨迹 τ (唯一一条轨迹)得到的累计奖励。假设在时间步 t 的奖励信号和我们正在处理的样例游戏,如果我们赢了游戏,给代理一个正 1 的奖励( Gt =+1),如果我们输了,给代理一个负 1 的奖励( Gt =-1)。另一方面,这个术语
查看代理在时间步长中从状态st** 选择动作的概率。记住带下标 θ 的 π 是指由 θ 参数化的策略。然后,完整的表达式取该概率的对数的梯度为**
这将告诉我们,如果我们想要增加从状态【ST】在 选择动作 的日志概率,我们应该如何改变策略 θ 的权重。具体来说,假设我们通过朝着这个梯度的方向迈出一小步来推动政策权重。在这种情况下,它将增加从该状态选择动作的 log 概率,如果我们向相反的方向前进,将降低 log 概率。**
以下等式将为每个状态-动作对一次完成所有这些更新,轨迹中的 处的 和 处的 ,处的每个时间步长:**
要看到这种行为,假设代理赢得了该集。然后, Gt 只是一个正的(+1),sum 做的是把我们应该介入的所有梯度方向加起来,以增加选择每个状态-动作对的 log 概率。这相当于只采取 H+1 个同步步骤,其中每个步骤对应于轨迹中的一个状态-动作对。
相反,如果代理丢失, Gt 变为负值,这确保了该方法不是在对数概率最陡增加的方向上步进,而是在最陡减少的方向上步进。
如何推导近似梯度的方程的证明可以安全地跳过,我们更感兴趣的是这个表达式的意义。
为什么优化对数概率而不是概率
在梯度法中,我们可以制定一些应该最大化的概率 𝑝 ,实际上我们将优化对数概率 log𝑝 而不是概率 p 用于一些参数𝜃.
原因是,一般来说,更好地优化 log𝑝(𝑥)比𝑝(𝑥)由于 log𝑝(𝑥)的梯度一般更良好。请记住,根据定义,概率受 0 和 1 的限制,因此优化器可以操作的值的范围有限且很小。
在这种情况下,有时概率可能非常小或非常接近于 1,当在数值精度有限的计算机上进行优化时,这会遇到数值问题。如果我们改为使用替代目标,即 log p (自然对数),我们有一个比原始概率空间具有更大“动态范围”的目标,因为概率空间的 log 范围从(-∞,0),这使得 log 概率更容易计算。
编码增强
现在,我们将探索一个增强的实现来解决 OpenAI 健身房的 侧翻环境。
这篇文章的完整代码可以在 GitHub 上找到,并且可以使用这个链接作为一个 Colab google 笔记本运行。
初始化
首先,我们将用下面几行代码导入所有必需的包:
***import** **numpy** **as** **np**
**import** **torch**
**import** **gym**
**from** **matplotlib** **import** pyplot **as** plt*
还有露天健身房的钢管舞环境:
*env = gym.make('CartPole-v0')*
政策网络
我们将建立一个神经网络作为政策网络。策略网络将接受状态向量作为输入,并且它将在可能的动作上产生(离散的)概率分布。
*obs_size = env.observation_space.shape[0]
n_actions = env.action_space.n
HIDDEN_SIZE = 256model = torch.nn.Sequential(
torch.nn.Linear(obs_size, HIDDEN_SIZE),
torch.nn.ReLU(),
torch.nn.Linear(HIDDEN_SIZE, n_actions),
torch.nn.Softmax(dim=0)
)*
该模型只有两个线性层,第一层是 ReLU 激活函数,最后一层是 Softmax 函数。默认情况下,初始化使用随机权重)。
*print (model)*
根据神经网络的结果,代理从概率分布中采样,以采取将在环境中执行的动作。
*act_prob = model(torch.from_numpy(curr_state).float())
action = np.random.choice(np.array([0,1]),p=act_prob.data.numpy())
prev_state = curr_state
curr_state, _, done, info = env.step(action)*
这段代码的第二行从第一行获得的策略网络产生的概率分布中抽取一个动作。然后在这段代码的最后一行,代理采取了行动。
训练循环
训练循环通过更新参数 θ 来训练策略网络,以遵循上一节中描述的伪代码步骤。
首先,我们定义优化器并初始化一些变量:
*learning_rate = 0.003
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)Horizon = 500
MAX_TRAJECTORIES = 500
gamma = 0.99
score = []*
其中learning_rate
是步长 α ,Horizon
是前面伪代码中的 H ,gamma
是 γ 。使用这些变量,迭代次数由MAX_TRAJECTORIES
定义的主循环编码为:
***for** trajectory **in** range(MAX_TRAJECTORIES):
curr_state = env.reset()
done = **False**
transitions = []
**for** t **in** range(Horizon):
act_prob = model(torch.from_numpy(curr_state).float())
action = np.random.choice(np.array([0,1]),
p=act_prob.data.numpy())
prev_state = curr_state
curr_state, _, done, info = env.step(action)
transitions.append((prev_state, action, t+1))
**if** done:
**break**
score.append(len(transitions))
reward_batch = torch.Tensor([r **for** (s,a,r) **in**
transitions]).flip(dims=(0,)) batch_Gvals =[]
**for** i **in** range(len(transitions)):
new_Gval=0
power=0
**for** j **in** range(i,len(transitions)):
new_Gval=new_Gval+
((gamma**power)*reward_batch[j]).numpy()
power+=1
batch_Gvals.append(new_Gval)
expected_returns_batch=torch.FloatTensor(batch_Gvals)
expected_returns_batch /= expected_returns_batch.max() state_batch = torch.Tensor([s **for** (s,a,r) **in** transitions])
action_batch = torch.Tensor([a **for** (s,a,r) **in** transitions]) pred_batch = model(state_batch)
prob_batch = pred_batch.gather(dim=1,index=action_batch
.long().view(-1,1)).squeeze()
loss= **-**torch.sum(torch.log(prob_batch)*expected_returns_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()*
使用score
列表,我们将跟踪训练时间内的轨迹长度。对于当前轨迹的事务,我们跟踪列表transactions
中的动作和状态。
接下来,我们计算每笔交易的预期回报(前面清单中的代码片段):
*batch_Gvals =[]
**for** i **in** range(len(transitions)):
new_Gval=0
power=0
**for** j **in** range(i,len(transitions)):
new_Gval=new_Gval+((gamma**power)*reward_batch[j]).numpy()
power+=1
batch_Gvals.append(new_Gval)
expected_returns_batch=torch.FloatTensor(batch_Gvals)
expected_returns_batch /= expected_returns_batch.max()*
列表batch_Gvals
用于计算每笔交易的预期收益,如前面的伪代码所示。列表expected_return
存储当前轨迹所有交易的预期收益。最后,这段代码将奖励归一化到[0,1]区间内,以提高数值稳定性。
损失函数需要一系列行动概率,prob_batch
,用于已采取的行动和贴现回报:
*loss = **-** torch.sum(torch.log(prob_batch) * expected_returns_batch)*
为此,我们重新计算轨迹中所有状态的动作概率,并使用以下两行代码对与实际采取的动作相关联的动作概率进行子集划分:
*pred_batch = model(state_batch)
prob_batch = pred_batch.gather(dim=1,index=action_batch
.long().view(-1,1)).squeeze()*
一个重要的细节是这个代码的损失函数中的负号:
*loss= **-**torch.sum(torch.log(prob_batch)*expected_returns_batch)*
为什么我们在log_prob
中引入了*-*
?总的来说,我们更喜欢将目标函数最小化,而不是最大化,因为这与 PyTorch 的内置优化器(使用随机梯度下降)配合得很好。我们应该告诉 PyTorch 最小化 1-π。当π接近 1 时,该损失函数接近 0,因此我们鼓励梯度使我们采取的行动的π最大化。
此外,让我们记住,我们使用一个替代目标,即–logπ(其中 log 是自然对数),因为我们有一个比原始概率空间(根据定义以 0 和 1 为界)具有更大动态范围的目标,因为概率空间的对数范围从(–∞,0),这使得对数概率更容易计算。
最后,提到我们在代码中包含了以下代码行来控制训练循环的进度:
***if** trajectory % 50 == 0 **and** trajectory>0:
print('Trajectory **{}\t**Average Score: **{:.2f}**'
.format(trajectory, np.mean(score[-50:-1])))*
我们可以看到运行以下代码的结果:
***def** running_mean(x):
N=50
kernel = np.ones(N)
conv_len = x.shape[0]-N
y = np.zeros(conv_len)
**for** i **in** range(conv_len):
y[i] = kernel @ x[i:i+N]
y[i] /= N
**return** y score = np.array(score)
avg_score = running_mean(score)plt.figure(figsize=(15,7))
plt.ylabel("Trajectory Duration",fontsize=12)
plt.xlabel("Training Epochs",fontsize=12)
plt.plot(score, color='gray' , linewidth=1)
plt.plot(avg_score, color='blue', linewidth=3)
plt.scatter(np.arange(score.shape[0]),score,
color='green' , linewidth=0.3)*
你应该能够得到一个轨迹持续时间趋势增加很好的图。
我们还可以使用以下代码呈现代理如何应用策略:
***def** watch_agent():
env = gym.make('CartPole-v0')
state = env.reset()
rewards = []
img = plt.imshow(env.render(mode='rgb_array'))
**for** t **in** range(2000):
pred = model(torch.from_numpy(state).float())
action = np.random.choice(np.array([0,1]),
p=pred.data.numpy()) img.set_data(env.render(mode='rgb_array'))
plt.axis('off')
display.display(plt.gcf())
display.clear_output(wait=**True**) state, reward, done, _ = env.step(action)
rewards.append(reward)
**if** done:
print("Reward:", sum([r **for** r **in** rewards]))
**break**
env.close()watch_agent()*
基于策略的方法与基于价值的方法
现在我们知道了这两类方法,它们之间的主要区别是什么?
- 这种强化的政策方法直接优化了政策。价值方法,如 DQN,间接地做同样的事情,首先学习价值,然后根据这个价值得到政策。
- 策略方法是基于策略的,并且需要来自环境的新鲜样本(通过策略获得)。相反,价值方法可以受益于从旧政策中获得的旧数据。
- 政策方法通常样本效率较低,这意味着它们需要与环境进行更多的交互。请记住,值方法可以从大的重放缓冲区中受益。
在某些情况下,政策方法将是更自然的选择,而在其他情况下,价值方法将是更好的选择。在任何情况下,正如我们将在下一篇文章中看到的,这两类方法可以结合起来实现混合方法,利用它们各自的特性。
摘要
在这篇文章中,我们已经详细解释了加固算法,并编写了代码。作为一种随机梯度方法,加强法适用于简单问题,并具有良好的理论收敛性。
正如 R. Sutton 和 G. Barton 在教科书强化学习:介绍中指出的,通过构建,轨迹上的预期更新与性能梯度方向相同。这保证了对于足够小的期望性能的改善,并且在标准随机近似条件下收敛到局部最优。然而,作为蒙特卡罗方法,强化可能具有高方差,因此产生缓慢的学习。
但是因为我们使用完全蒙特卡罗返回来计算梯度,所以该方法可能具有很高的方差,并且对于学习来说是一个问题。
此外,还有一些与增强算法相关的限制:
- 更新过程非常低效。我们运行一次策略,更新一次,然后扔掉轨迹。
- 梯度估计很吵。所收集的轨迹有可能不代表策略。
- 没有明确的信用分配。一个轨迹可能包含许多好的/坏的行为,这些行为是否被加强只取决于最终的总产出。
总的来说,对于像 CartPole 这样的小问题,REINFORCE 工作得很好,但是对于更复杂的环境,例如 Pong 环境,它会非常慢。加固可以改进吗?是的,研究界创造了许多训练算法: A2C、A3C、DDPG、TD3、SAC、PPO 等等。然而,对这些算法进行编程需要更复杂的数学处理,并且其编程变得比 REINFORCE 更复杂。正因如此,在下期中,我们将介绍 强化学习框架 简化了这些高级方法的使用,以上,均为分布式算法。
下一期在见!
深度强化学习讲解系列
由 UPC 巴塞罗那理工 和 巴塞罗那超级计算中心
一个轻松的介绍性系列以一种实用的方式逐渐向读者介绍这项令人兴奋的技术,它是人工智能领域最新突破性进展的真正推动者。
* [## 深度强化学习解释-乔迪托雷斯。人工智能
本系列的内容](https://torres.ai/deep-reinforcement-learning-explained-series/)
关于这个系列
我在五月份开始写这个系列,那是在巴塞罗那的封锁期。老实说,由于封锁,在业余时间写这些帖子帮助了我 #StayAtHome 。感谢您当年阅读这份刊物;它证明了我所做的努力。
免责声明 —这些帖子是在巴塞罗纳封锁期间写的,目的是分散个人注意力和传播科学知识,以防对某人有所帮助,但不是为了成为 DRL 地区的学术参考文献。如果读者需要更严谨的文档,本系列的最后一篇文章提供了大量的学术资源和书籍供读者参考。作者意识到这一系列的帖子可能包含一些错误,如果目的是一个学术文件,则需要对英文文本进行修订以改进它。但是,尽管作者想提高内容的数量和质量,他的职业承诺并没有留给他这样做的自由时间。然而,作者同意提炼所有那些读者可以尽快报告的错误。*
RL 中的策略迭代:一步一步的说明
原文:https://towardsdatascience.com/policy-iteration-in-rl-an-illustration-6d58bdcb87a7?source=collection_archive---------1-----------------------
强化学习
策略迭代算法指南
来源:图片由来自 Pixabay 的 Annalise Batista 提供
策略迭代是“强化学习”中的一种算法,它有助于学习使长期贴现回报最大化的最优策略。当有多个选项可供选择,并且每个选项都有自己的回报和风险时,这些技术通常是有用的。
在本文中,我们将把“策略迭代”算法应用到一个简单的游戏中,这个游戏涉及一些海盗,他们必须在冒险和有利的情况下到达目的地。
游戏概述:
让我们考虑一艘海盗船,它现在停泊在一个岛上,必须安全到达它的祖国。有两条路线可供选择。
如果它走向北的路线,那么它可以到达一个满是黄金的岛屿,它可以收集黄金,然后向南移动到达家园。然而,在黄金岛的北面有一个重力非常高的区域(像百慕大三角)。如果船误到了那里,那么它就会被吸进去,船就永远失去了。
如果它走向南的路线,那么它可以到达一个满是白银的岛屿,它可以收集这些白银,然后向北移动到达家园。在银岛的南面有一个监狱岛。如果船误落在那里,那么船将被捕获,船员将被监禁。
到目前为止,一切看起来都很好,然而,游戏中有一个转折。如果我们的生活是确定的,那就没有乐趣。让我们在游戏中引入随机性。
还记得电影《加勒比海盗》中的杰克·斯派洛吗?!。假设我们的船长有一个破罗盘,类似于杰克的罗盘。所以,每次,船长向北移动,他向北移动的概率是 0.8,然而,他可能会错过标记,以 0.2 的概率到达南方。同样,如果他往南走,有 0.8 的概率往南走,有 0.2 的概率往北走。
奖励(正面和负面):
让我们给每一次登陆的船只分配一些奖励。
- 到达家园将允许海盗船收集+1 点。
- 登陆金岛将允许海盗船收集+2 点积分。
- 登陆银岛将允许海盗船收集+1 点。
- 如果船被吸进百慕大三角,那么船得-2 分。
- 如果这艘船是在监狱岛被捕获的,那么这艘船得-0.5 分。
在这种情况下,我们的目标是找到最优策略,使船只安全到达其祖国,并获得最大回报。
快速回顾“策略迭代”算法:
策略迭代有三个步骤:
- 初始化随机策略
- 政策评价
- 政策改进
什么是政策?
策略是动作到系统中每个可能状态的映射。最优策略是使长期回报最大化的策略。因此,对于这个例子,我们可以有多个策略。即,在每个州(岛)有多组动作,然而,可能只有一个策略给我们最终的最大回报。我们的目标是找到最佳策略。
第一步:
随机初始化策略。在系统的每个状态下随机初始化动作。
第二步:
步骤 2 基于贝尔曼方程,该方程如下:
政策评价
获取策略中每个状态的动作,并使用上面的等式评估值函数。这里 p 是转移概率,也用 t 表示。
第三步:
对于每个状态,使用以下公式从价值函数中获得最佳行动:
政策改进
如果最佳操作优于当前策略操作,则用最佳操作替换当前操作。
策略迭代:
重复步骤 2 和 3,直到收敛。如果策略在整个迭代过程中没有改变,那么我们可以认为算法已经收敛。
状态转换图:
首先要做的是理解状态和动作,并构建一个状态转换图。在我们的例子中,每个岛屿是一个州,有两个动作,“北”和“南”。每个州的奖励如上图所示。基于这些事实,我们可以构建如下的状态转换图:
有六个州,包括起始州和目的地州,以及四个中间岛屿,他们可以在那里上车。让我们将从 S1 到 S6 的状态标记如下:
- S1:开始状态
- S2:黄金岛登陆状态
- S3:登陆银岛的状态
- S4:登陆百慕达三角岛的状态
- S5:目的岛的着陆状态
- S6:在监狱岛登陆的状态
状态转移图
转移概率矩阵:
由于游戏是随机的,我们需要计算每个状态/动作对的转移概率。基于上面提供的概率和状态转移图,我们可以绘制如下图。注意,有两个动作,我们需要这两个动作的转移概率矩阵。注意,在应用贝尔曼方程时,T(S,a,S’)指的是在采取动作‘a’之后从状态 S 移动到状态 S’的转移概率。
北部行动的转移概率矩阵
南方行动的转移概率矩阵
策略迭代算法:
有了这些信息,让我们一步一步地应用上述算法。我们可以假设贴现因子(γ)为 1。
初始随机策略:
让我们随机初始化策略(状态到动作的映射),对于所有的状态都是向北移动。
P = {N,N,N,N,N,N}
如果我们观察状态转换图,状态 S4、S5、S6 在这些状态中没有任何支持的动作,因为这些是结束状态。因此,让我们缩减我们的政策,仅适用于我们可以采取行动的前三个州。
P = {N,N,N}
第一次迭代:
让我们假设所有状态的初始值 V(s)为 0。因此,贝尔曼方程将简化为 V(s) = R(s),其中 R(s)是进入一种状态的回报。
首次迭代的策略评估:
v[S1]= 0;V[S4] = -2
v[S2]= 2;V[S5] = 1
v[S3]= 1;V[S6] = -0.5
首次迭代的策略改进:
让我们应用上面提供的公式来改进政策。
I 迭代:政策改进
根据上表获得的策略如下:
P = {N,S,N}
第二次迭代:
第二次迭代的策略评估:
II 迭代:策略评估
每个状态的值可以总结如下:
v[S1]= 3;V[S4] = -2
v[S2]= 1;V[S5] = 1
v[S3]= 1.5;V[S6] = -0.5
第二次迭代的策略改进:
二次迭代:政策改进
基于上表获得的策略如下:
P = {S,S,N}
第三次迭代:
第三次迭代的策略评估:
III 迭代:策略评估
每个状态的值可以总结如下:
v[S1]= 2.5;V[S4] = -2
v[S2]= 1;V[S5] = 1
v[S3]= 1.5;V[S6] = -0.5
第三次迭代的策略改进:
III 迭代:政策改进
基于上表获得的策略如下:
P = {S,S,N}
如果我们将此策略与我们在第二次迭代中获得的策略进行比较,我们可以观察到策略没有改变,这意味着算法已经收敛,这是最优策略。
结论:
通过应用该算法,我们得到了最优策略为{南,南,北}。如果我们观察这个例子,最初可能会很想去北方,因为金岛有更多的奖励,但它充满了风险,因为我们可能会失去 2 分,并结束游戏。因此,最好是牺牲短期回报,选择最终能让我们的长期回报最大化的南线。
我希望这个例子有助于更好地理解这个算法。
参考文献:
- 萨顿和巴尔托(2018 年)。强化学习:导论。麻省理工出版社。
- 翁,莉莲。(2018 年 2 月 19 日)。对强化学习的(长)窥视。检索自https://lilian Weng . github . io/lil-log/2018/02/19/a-long-peek-into-reinforcement-learning . html
通过了解招聘人员在寻找什么来提高你的数据科学能力
原文:https://towardsdatascience.com/polish-your-data-science-competencies-by-knowing-what-recruiters-are-looking-for-6f9ceafe8413?source=collection_archive---------26-----------------------
招聘人员提出的 17 个数据科学面试问题
是什么造就了伟大的数据科学家?答案取决于所讨论的数据科学分支和您的具体需求,但所有数据科学家都不可避免地拥有一套核心技能。这本全面的招聘指南,从招聘人员的角度撰写,概述了关键技能,并解释了如何为工作挑选合适的数据科学家。
如果你读这篇文章只是为了了解招聘人员在下次面试时可能会问你什么问题,那就去“问正确的问题”吧。
如何雇佣一名优秀的数据科学家
数据科学是一个飞速发展的领域。根据 Linkedin 劳动力报告,2018 年对数据科学家的需求超出了图表。
数据科学是一个多学科领域,使用科学方法、流程、算法和系统从结构化和非结构化数据中提取知识和见解。 (维基百科)
该行业正朝着人工智能和数据科学的民主化方向发展。这意味着现在比以往任何时候都更容易掌握相关技能,越来越多的人试图进入这一领域。这是一个积极的趋势,但同时也是一把双刃剑。由于高需求和不断涌入该领域的新人,雇佣数据科学家变得更加困难。
这份数据科学招聘指南应该能帮助你为这份工作选择合适的人。
数据科学家是你真正需要的吗?
在我们深入研究如何之前,你确实需要回答为什么。数据科学家真的是你需要的吗?随着数据科学的民主化,出现了大量可以用作黑盒的工具和解决方案。像 Google Vision API 和 Cloud AutoML 这样的工具可以帮助你实现很多目标,而不必担心幕后发生的事情。
在您开始全面寻找数据科学家之前,了解您的需求,并搜索是否有办法使用现有的 API 和工具来获得与内部定制解决方案相同(在某些情况下甚至更好)的结果。古老的格言“不要重新发明轮子”在这种情况下非常适用。
雇佣数据科学家的挑战
雇用数据科学家的挑战之一是判断候选人是否有深入的知识,或者只是依赖于为你做所有工作的黑盒库。这些工作,但如果候选人不知道它是如何工作的,调试任何问题都将是一个问题。
另一个挑战是知道你需要数据科学家做什么,因为在数据科学的保护伞下有许多问题(例如,自然语言处理(NLP),计算机视觉(CV)等)。).雇佣数据科学家之前的第一步是定义你试图解决的问题的范围。
显然,寻找候选人的传统方式仍然存在——比如口口相传或在 LinkedIn 或 Stack Overflow 等各种网站上发帖——但找到优秀数据科学家的一个新地方是 Kaggle 。
Kaggle 是一个面向数据科学家和 ML 从业者的在线社区。然而,这并不是一个适合所有人的建议。有些候选人很擅长 Kaggle,但可能不适合你的公司。另一方面也是如此,因为有些候选人是伟大的数据科学家,但却不在 Kaggle 上。
你需要做的第一件事是定义一个数据科学家将为你解决的问题,然后尝试找到它所属的数据科学领域。如果你有一个语言任务,比如关键词分类或者构建一个文本摘要器,你需要一个 NLP 专家。如果任务更多的是处理图片和照片,你需要一个计算机视觉专家。同样,如果工作涉及处理标记数据(面部识别、垃圾邮件分类等。),你需要在监督学习方面有专长的人。如果工作更符合统计学,比如 A/B 测试或分析受控试验的结果,你需要一个非常擅长统计学的人(理想情况下,所有数据科学候选人都应该具备统计学知识)。
该图很好地概括了数据科学的不同分支:
平心而论,这是一种概括;实际上,这些线是模糊的,并且有一些重叠,所以技能图表看起来像这样:
注: 一个优秀的数据科学家应该了解所有这些技能和分支,并在其中一个或多个方面有专长。
数据科学家的硬技能和经验
任何数据科学家都应该具备统计学知识,并理解他们所使用的算法背后的数学原理。除此之外,Python、R、MATLAB 或 Octave 的编码经验是必须的。
如果你想雇佣一个 NLP 专家,候选人应该理想地使用过 NLTK,斯坦福 NLP 等 NLP 包。
对于计算机视觉,他们应该有使用 CNN(卷积神经网络)、OpenCV 等的经验。
随机森林、决策树、朴素贝叶斯、线性回归或 SVM(支持向量机)等算法的经验也是必要的。
如果工作更多的是在使用深度学习和神经网络方面,他们应该有使用 TensorFlow,PyTorch,Theano,Torch,Sonnet,Keras 和 MXNet 构建神经网络的经验。
问正确的问题
1)有监督和无监督的机器学习有什么区别?
在监督的机器学习中,算法在带标签的数据集上训练,任务是算法将在给定新数据的情况下找到标签。
在无监督学习中,数据是无标签的。
2)能否提供一些有监督和无监督 ML 算法的例子?
有监督:随机森林、决策树、朴素贝叶斯、线性回归、SVM、KNN (K 近邻)。
无监督 : K 均值聚类,自动编码器,DBSCAN,层次聚类。
3)什么是“爆炸渐变”?
梯度是在训练神经网络时计算的更新的幅度和方向。
爆炸梯度是当梯度累积并且值变得太大而导致溢出时发生的问题,并且梯度变成 NaN,导致训练停止。
4)什么是混淆矩阵?
混淆矩阵是一个 2×2 的表格,包含了判断二元分类器性能的度量。
- 真阳性:属于阳性类的值,分类器标记正确。
- 假阴性:属于阳性类的值,但分类器将它们标记为阴性。
- 假阳性:属于阴性类别但分类器将其标记为阳性的值。
- 真阴性:属于阴性类的值,分类器标记正确。
什么是 ROC 曲线,它是如何工作的?
ROC 曲线是一个图表,它告诉我们在不同阈值下的真阳性率(TPR)和假阳性率(FPR)。它用于说明 TPR(灵敏度)和 FPR(1-特异性)之间的权衡。
什么是决策树,它是如何工作的?
决策树是一种分类/回归算法,它使用类似树的结构来学习数据中的结构。
树中的每个节点代表一个测试。例如,一个节点可以是资产的输入是否低,根据答案(是或否),决策树将输出坏风险或好风险。
7)随机森林算法是如何工作的?
随机森林算法是一种集成学习技术,它创建多个决策树,并根据给定的数据对它们进行训练。在分类问题的情况下,最终预测是决策树预测的所有类的模式,在回归问题的情况下,是所有值的平均值。
8)什么是过度拟合和欠拟合?
过拟合是一种机器学习算法与训练数据集过于拟合的现象,这导致训练集的高精度/低损失,但测试/验证集的低精度/高损失。
欠拟合是一种机器学习算法无法学习数据集结构的现象,因此这会导致低精度/高损失。
如何在决策树中防止过度拟合?
有两种方法可以防止决策树中的过拟合现象:预修剪和后修剪。
在预修剪中,我们在决策树变成一棵成熟的树之前停止它。
以下是节点的典型停止条件:
- 如果所有实例属于同一个类,则停止。
- 如果所有属性值都相同,则停止。
在后期修剪中,我们让决策树增长到全长,然后以自下而上的方式修剪树的节点。
什么是正态分布?
数据的分布通常偏向平均值的左边或右边。当数据围绕平均值对称时,即在平均值附近更频繁,远离平均值时更少,则数据遵循正态分布。
深度神经网络中过高的学习率会产生什么问题,为什么?
如果学习率太高,损失会在最小值附近跳跃。由于学习率决定了网络权重的更新量有多大,因此高学习率会导致大量更新,进而导致发散行为。
处理数据集时,您发现两个变量的皮尔逊相关值可以忽略不计。这是否意味着这两个变量是相互独立的?为什么/为什么不?
相关性定义为两个变量之间的关系。正相关是当一个变量增加时,促使另一个变量也增加。同样,负相关是指一个变量减少,而另一个变量增加。
皮尔逊相关是两个变量之间线性关系的量度。仅仅因为两个变量具有接近零的皮尔逊相关性并不意味着它们是独立的;只是说明两者之间没有线性关系,但是更高阶的关系还是可以存在的。
13)有一个 15 个隐层的深度神经网络,所有的神经网络都有相同的激活函数,即 tanh。训练时,你注意到训练损失保持不变。问题出在哪里?解决这个问题最简单的方法是什么?
这是一个消失梯度问题。通常使用基于梯度的训练方法和反向传播来训练神经网络。本质上,我们向每个权重发送与相对于当前权重的误差偏导数成比例的更新。有时,当误差反向传播时,这种更新变得如此之小,以至于权重不变,因此,训练损失保持不变。
要修复这个问题,可以减少层数,用 ReLU 激活函数代替 tanh。
14)您正在训练一个简单的 RNN 网络来预测句子中的新单词,但在训练时,准确性并不好。经过调试后,您发现 RNN 除了几个词之外无法理解上下文。你用哪个深度学习模型来修复这个?
递归神经网络(RNN) 是一种深度神经网络,其结构使得它们能够使用其内部状态来记忆先前的输入。与前馈神经网络不同,在 RNN 中,前一步骤的输出作为输入被馈送到当前步骤。这形成了一个允许信息持续的循环。
这幅图展示了一个简单的 RNN 的样子。
由于结构简单,rnn 存在不能“记住”大量数据的问题。使用类似 LSTM(长短期记忆)的东西可以帮助解决这个问题。
LSTMs 是一种能够学习长期依赖性的特殊 rnn。
在 LSTM,有一个明确的记忆状态,可以由 LSTM 细胞使用精心控制的门来更新。这种存储器状态允许 LSTM 保留存储器更长的时间,因此,它可以跟随上下文更长的序列。
15)在对二进制数据集进行训练的过程中,您发现您的算法的准确性很高,但是在分析数据集时,您发现一个类别的样本之间存在非常高的不平衡。例如,阳性样本几乎占了数据集的 99%。你还能相信准确性指标吗?如果不是,您应该使用什么指标?
当处理不平衡数据集时,准确性不是性能的最佳衡量标准,因为如果在这种情况下,算法将所有数据标记为正,它仍将获得 99%的正确答案,因此将具有 99%的准确性。在这种情况下,会使用平衡准确度、f1 分数等指标。
- 精度:真阳性值/(真阳性+假阳性)
- 回忆:真阳性/(真阳性+假阴性)的值
- F1 得分:精确度和召回率的调和平均值
- 平衡精度:数据集中每个类的平均召回率
16)你正在处理一个聚类问题,你有一个高维数据集。在对数据训练基本的 k-means 聚类算法时,您会注意到,无论您对超参数做了多少调整,聚类都会在运行之间不断变化。你觉得为什么会这样?你能做什么来克服这个问题?
K-means 聚类使用基于距离的度量。在处理高维数据集时,由于维数灾难,基于距离的度量变得几乎无用,因为数据集中的所有数据点由于维数很大而看起来是等距的。因此,在多次运行中,该算法无法获得一致的结果。要解决这个问题,您应该尝试应用 PCA/t-SNE 或其他一些降维算法。
17)在一个有大量参数的优化问题上使用随机梯度下降时,你发现算法是振荡的,无法达到全局最优。这是为什么呢?你将如何修理它?
随机梯度下降(SGD)的最大缺点之一是所有参数的学习速率都是相同的。因此,如果其中一个参数需要较小的学习速率,而另一个参数需要较大的学习速率,那么 SGD 在这种情况下就不能很好地运行。
这个问题随着具有许多参数的优化问题而被放大,因为出现这种情况的概率也很大。在这种情况下,您应该使用 Adam optimizer 等具有自适应学习率的算法。
不要
这是雇佣数据科学家的一些常见问题,你应该尽可能避免它们。
不要问“抓住你的问题”
疑难问题是很难解决的问题,除非你知道一种特殊的技巧。这些问题看起来很诱人,但是要避免它们,因为知道或不知道这类问题的答案并不能很好地反映候选人的知识水平。
不要以表面价值来看待项目。
项目是伟大的,但现在,比以往任何时候都更容易只用几行代码来进行机器学习。虽然这是一个好消息,但这也意味着一些候选人可能只是使用预构建的 Python 库,而没有真正理解其工作原理。你必须提出问题,让候选人解释他们所做的工作。
不要坚持让候选人知道你的确切技术水平。
你应该调查候选人学习新技术和新方法的意愿和能力,而不是坚持让他们知道你一直在使用什么。你可能会找到一个很棒的候选人,他不了解你的技术,但能很快学会。
包扎
组织中不断增长的数据量创造了对数据科学家不断增长的需求。
随着机器学习的民主化,现在比以往任何时候都更容易获得该领域的相关技能。但是为你的团队寻找合适的候选人也是一个挑战——就像大海捞针一样。
我们选择的提示和问题有助于为您的团队雇佣合适的数据科学家;然而,这是你整体招聘策略的一个补充,因为只有你知道谁是你团队的合适人选。本指南旨在帮助您做出决定,我们希望上述问题和提示能够帮助您为您的组织和项目找到合适的候选人。
原载于 https://www.toptal.com**和 https://www.stratascratch.com
政治数据科学:推特的故事
原文:https://towardsdatascience.com/political-data-science-a-tale-of-tweets-75b762224e56?source=collection_archive---------31-----------------------
分析对新苏格兰独立公投的情绪
关键词:Twitter,tweepy,Bayes 情操论,nltk,scikit learn,keras,机器学习,深度学习,LSTM,RNN,SVM,朴素贝叶斯,geoplot,geopy,nominatim,folium,pygeocoder。
推特上的文字云
我们都很熟悉数据驱动的政治竞选在选民中的巨大力量。我们只要看看 2016 年美国总统大选,希拉里·克林顿和唐纳德·特朗普针锋相对,最终彻底改变了美国政治家赢得选举的方式。
他们的竞选活动没有使用传统策略,而是利用数据,这些数据赋予了他们微观锁定选民的能力。耶鲁大学教授艾坦·赫什(Eitan Hersh)在他的著作《黑掉选民中总结道,如果你有足够的数据,你就可以预测人们会如何表现,甚至他们会如何投票。竞选团队已经发展出复杂的方式来做到这一点。
尽管选民最终会支持与他们的优先事项最相符的政治家或想法,但重要的是要知道数据给了我们发现这些优先事项是什么的方法。
照片由元素 5 数码在 Unsplash 上拍摄
在英国,事情进行得并不容易,英国退出欧盟的支持者从川普的竞选中吸取了很多经验教训并加以利用。快进到 2020 年,英国退出欧盟的主要人物鲍里斯·约翰逊现在是分裂的“联合”王国新当选的保守党首相。
英国退出欧盟投票后,以及最近鲍里斯·约翰逊在 2019 年冬季大选中获胜后,苏格兰当前的政治局势非常激烈。
苏格兰选民在 2014 年 9 月的公投中首次被问及是否希望苏格兰成为独立国家;结果是 55%对 45%反对独立。
FT 蒙太奇/Getty/PA
苏格兰民族党(SNP)2019 年大选宣言称,该党打算在 2020 年举行第二次公投;他们赢得了苏格兰在英国下议院 59 个席位中的 48 席。因此,很自然地,首席部长尼古拉·斯特金现在声称苏格兰大多数人期望的未来与英国其他大部分人喜欢的非常明显不同。本月早些时候,她正式要求在 2020 年底前举行独立公投,但不久后被鲍里斯·约翰逊(Boris Johnson)否认。****
所有这些在鲍里斯约翰逊(Boris Johnson)领导下的英国制造了一个复杂的环境,这个国家似乎处于非常困难(也不是非常有利)的境地。
内容
- 提问
- 为什么是推特?
- ETL:提取、加载、转换
- 特色工程
- 模型定义和训练
- 模型评估
- 未知建模:公投推特数据。
- 地理空间分析
- 结论
提问
鉴于这种情况,我想知道我们是否能了解苏格兰人民在这个动荡时期的反应。尤其是在鲍里斯·约翰逊(Boris Johnson)获胜并拒绝允许苏格兰人再次公投之后。
所以我的问题是:
英国人民如何应对当前关于苏格兰独立公投的政治气候?鲍里斯·约翰逊拒绝允许吗?
苏格兰、英格兰、威尔士和北爱尔兰人的反应有何不同?对苏格兰特别感兴趣。
于是,我用关键词*“indyref 2”“苏格兰独立”“scot ref”*下载了 2020 年 1 月 8 日至 1 月 15 日一周的推文。我收集数据和分析情绪的过程可以在任何 twitter 账户或媒体页面上重复。
使用 情感分析 (也称为意见挖掘),一个自然语言处理子领域,我把推特作为苏格兰独立的一种政治晴雨表。我训练了两个有监督的机器学习模型:支持向量机** (SVM)和朴素贝叶斯分类器。然后,我与一个被称为长短期记忆(LSTM)网络的深度学习递归神经网络 (RNN)进行了系统的比较。在对模型进行评估后,我选择并使用 LSTM 模型来预测 twitter 数据集中的情绪。**
您可以在 Github 库中查看完整的项目及其技术细节。
乔治·帕甘三世在 Unsplash 上的照片
为什么是 twitter?
我选择关注 Twitter 是因为它——以及一般的社交媒体——正日益成为日常生活的一部分,这在政治领域也是如此。此外,情感分析项目主要使用 Twitter 数据,因为这些数据(几乎)是公开的,而从脸书收集任何有用的数据(几乎)是不可能的。
ETL:提取、加载、转换
****训练数据是从感知 140 中获得的,由大约 160 万条随机推文组成,相应的二进制标签“0”表示负面情绪,“4”表示正面情绪。原始数据集由 80k 条标注为正面的推文和 80k 条标注为负面的推文组成。推文真多。所以我从更大的训练数据集中抽取了一个样本,以避免长时间的等待。最后,我用 25160 条标注为负面的推文和 24840 条标注为正面的推文进行训练。
按字数统计的训练数据集中正面和负面推文的分布。
一个非常平衡的训练数据集,如上图直方图所示。
在任何自然语言处理任务中,清理原始文本数据都是重要的一步。它有助于去掉不需要的单词和字符,从而有助于获得更好的特征。对于这一步,我使用了一个类似于管道的预处理步骤,使用一些辅助函数来去除 tweets 中不需要的噪声:
预处理流水线
经过这一步,你可以非常清楚地看到原始推文和干净推文之间的差异。只有推文中的重要单词被保留,噪音(数字、标点符号和特殊字符)被删除。
对于测试数据,我使用 twitter 的 API 下载了数据集,并用它来测试模型的真实性能。我使用了tweepy
,这是 Twitter API 的一个 python 包装器库,可以让你更好地控制如何查询它。为了获得测试数据集的大量数据,我通过 API 搜索函数使用关键字'indyref2'
、'scottish independence'
和'scotref'
下载了数据。不过 Twitter 的 REST API 在其免费版本中有一个限制。它搜索过去 7 天内发布的推文样本。所以我只能收集到 636 条推文的样本。尽管如此,我还是从他们身上提取了一些有趣的信息。
要了解这一部分的详细步骤,请查看我的 Github 中的笔记本。
特征工程
为了分析预处理过的数据,需要将其转换成特征。根据使用情况,可以使用各种技术构建文本特征,如单词包(BoG)TF-IDF和单词嵌入。
为了使项目简单,我去找了一大堆单词。但是,一种基本的方法无法捕捉到像“我喜欢你”这样的短语之间的差异,其中“喜欢”是一个带有积极情绪的动词,而“我喜欢你”,其中“喜欢”是一个表达不同情绪的介词。
为了改进这项技术,我使用维达的极性分数和词性(POS)标签提取特征。****
维达情绪分析工具 产生四个情绪指标。前三个,积极的,中性的和消极的,这是不言自明的。最后一个指标,复合得分,是所有词汇等级的总和,然后标准化为-1 到 1 之间的范围。我使用这些分数来创建基于推文情感指标的特征,这些特征被用作建模的附加特征。如果你想对一个给定的句子进行多维度的情感测量,这些是非常有用的指标。我用下面的辅助函数提取并创建了新特性:
Vader 情操助手功能
【词性标注(POS) 是使用上下文线索将词性分配给列表中的每个单词。这很有用,因为同一个词有不同的词性,可能有两种完全不同的意思。是根据上下文和定义将语料库(一串文本)中的单词标记为语音标签的相应部分的过程。这项任务并不简单,因为一个特定的单词根据其使用的上下文可能有不同的词性。对于这个项目,我使用了一个简单的基于词汇的方法,将 POS 标签分配给训练语料库中最频繁出现的单词,并将标签作为特征添加到我们的模型中。关于助手功能,请参见下文:
POS 助手功能
查看我的 Github 中的笔记本,了解这一部分的分步操作。
模型定义和培训
监督机器学习
在完成所有的预建模阶段后,我们构建模型,训练它们并测试它们。对于这项任务,我首先定义并训练了两个有监督的机器学习算法:
- 朴素贝叶斯分类器
- 支持向量机分类器
它们可以说是任何分类任务中最常用的两种技术。
****朴素贝叶斯是一种利用贝叶斯定理的分类器。它预测每个类的成员概率,例如给定记录或数据点属于特定类的概率。具有最高概率的类被认为是最可能的类。
版权克里斯·阿尔邦,2020。
****SVM 分类器的工作原理是将数据映射到一个高维特征空间,这样即使数据不是线性可分的,也可以对数据点进行分类。找到类别之间的分隔符,然后对数据进行转换,使得分隔符可以绘制为超平面。在此之后,新数据的特征可以用于预测新记录应该属于哪个组。
版权克里斯·阿尔邦,2020。
定义模型后,我使用 Scikit Learn GridSearchCV 进行交叉验证,同时选择最佳的超参数配置。使用网格搜索,您可以设置超参数值的网格,并为每个组合训练一个模型,并根据验证数据进行评分。在这种方法中,尝试了超参数值的每一个组合。
我为每个分类器将组合的超参数传递给 GridsearchCV 对象,并为交叉验证传递 10 个折叠,这意味着对于每个参数组合,网格每次都用不同的测试集运行 10 次不同的迭代(这需要一段时间……)。
交叉验证
在尝试了不同的模型参数组合之后,GridsearchCV 返回了每个分类器的最佳性能模型。然后,我保存模型进行评估。如果我们计划部署模型,这是一个必要的步骤。
深度学习
为了比较,我还实现了一个递归神经网络(RNN)** ,称为**长短期记忆(LSTM)。****
为了快速描述它,想想我们是如何思考的。我们不是每秒钟都从零开始思考。我们以此为基础。就在你读这篇文章的时候,你在阅读的过程中增加了对它的理解。
传统神经网络做不到这一点。
如果我们想要一个神经网络来理解我们的推文,我们需要一个可以从它读取的内容中学习并建立在其上的神经网络。rnn 解决了这个问题。它们是带有环路的网络,允许信息持续存在。但是我们也需要我们的网络使用一些推文中的上下文来学习。也就是说,我们需要它比其他 RNN 兄弟姐妹能记住更长时间的信息。
进入 LSTMs!他们是我们需要的孩子。
我使用的网络架构如下:
- 首先,我们将单词传递给一个嵌入层,我们的第一个隐藏层。****
- 在输入单词被传递到嵌入层之后,新的嵌入被传递到 LSTM 单元,我们的第二个隐藏层。
- 最后,LSTM 输出到 softmax 输出层。
来源:https://colah.github.io/posts/2015-08-Understanding-LSTMs/
为了让推文准备好进入 LSTM 网络,需要做大量的数据准备。我必须将推特上的文字编码成整数。因此,我不得不使用 Keras 中的Tokenizer
将 tweets 转换成整数序列。然后,编码后的推文可以传入网络。
使用 Keras 构建网络相当容易。您可以简单地将多层堆叠在一起:
LSTM 网络与 Keras
我运行了 10 个时期的模型,并观察到验证数据的损失在时期 1 之后开始增加,这表明过度拟合。在助手函数eval_metric
和optimal_epoch
的帮助下,我稍微调整了一下模型,解决了这个问题。
在时段 1 中达到最小验证损失
我们从图表中观察到两件事:
- 训练损失在每个时期之后保持减少。我们的模型正在学习识别训练集中的特定模式。
- 验证损失在每个时期之后持续增加。我们的模型在验证集上不够通用。
训练损失继续下降,在第 10 个时期几乎为零。这是正常的,因为模型被训练以尽可能好地适应训练数据。
所以,我们是过度训练(又称,模型过度拟合)。****
为了解决这个问题,我应用了正则化,这可以归结为对大权重的损失函数增加一个成本。
在时段 2 中达到最小验证损失
我们可以看到,它在第二个时期开始过拟合,之后验证损失增加较慢。
乍一看,简化的模型似乎是概括的最佳模型。但后来我使用test_model
辅助函数检查了测试集,它给出了第一个 LSTM 的测试准确率为 74.81%,LSTM 的测试准确率为 74.47%。
因此,应用正则化有助于过度拟合,但对模型在测试数据上的准确性没有太大影响。
查看我的 Github 中的笔记本,了解这一部分的分步操作。
模型评估
模型评估是模型开发过程不可或缺的一部分。它有助于找到代表我们的数据的最佳模型,以及所选模型在未来的工作情况。对于此分类任务,我使用了以下评估指标:
- 混淆矩阵
- 准确度、召回率、精确度和 F1 分数
****混淆矩阵显示了与数据中的实际结果(目标值)相比,分类模型做出的正确和错误预测的数量。
我们的监督机器学习模型的混淆矩阵
从上面可以看出:
- ****朴素贝叶斯分类器:该模型正确预测 76%的标签为阴性,73%正确预测为阳性。该模型预测 27%的标签为阴性,但它们是阳性的(假阴性)。当它们是阴性(假阳性)时,该模型预测 24%的标记为阳性。
- ****SVM 分类器:模型正确预测 75%的标签为阴性,75%正确预测为阳性。该模型预测 25%的标签为阴性,但它们是阳性的(假阴性)。当它们是阴性(假阳性)时,该模型预测 25%的标记为阳性。
我们的 LSTM 递归神经网络的混淆矩阵
从上面可以看出:
- ****LSTM 神经网络:该模型预测 76%的标签正确为阴性,73%正确为阳性。该模型预测 27%的标签为阴性,但它们是阳性的(假阴性)。当它们是阴性(假阳性)时,该模型预测 24%的标记为阳性。
- ****具有正则化的 LSTM 神经网络:该模型正确预测 74%的标签为阴性,73%正确预测为阳性。该模型预测 25%的标签为阴性,但它们是阳性的(假阴性)。当标签为阴性(假阳性)时,该模型预测 26%的标签为阳性,这比第一个 RNN 模型在准确性上有一点提高。
接下来,我们查看分类报告中的准确度、召回率、精确度和F1-分数。这些指标之间的差异以及我们为什么不简单地依赖准确性得分在这篇文章中有很好的解释。
对于朴素贝叶斯和 SVM:
监督机器学习模型的分类报告
对于 LSTM 车型:
LSTM 车型的分类报告
从上述指标来看,我们的模型似乎表现得相对较好。请注意,在所有四个模型中,宏观和微观平均得分相同。这意味着我们的数据非常平衡,也就是说,我们训练数据集中的类分布是对称的。但是我们已经知道了。关键是,一个平衡的数据集允许我们依靠整体准确性指标来选择模型。
相比之下,在这篇论文中,研究人员发现人类评分者通常在 80%的情况下会同意。
因此,一个 75%准确的模型几乎和人类评分员一样好。
没有正则化的 SVM 和 LSTM 网络分类器都优于其他模型 1%,实现了 75%的总准确率。
下一步我选择了 LSTM 而不是 SVM 模型,因为一般来说,深度学习在处理复杂问题时真的很出色,比如自然语言处理。另一个优势是,当涉及到模型部署时,我们不太担心特性工程部分。
最终,真正的测试是在看不见的真实世界数据上使用模型。
查看我的 Github 中的笔记本,了解模型评估部分的详细步骤。
未知建模:公投推特数据。
最后,我们到了有趣的部分。我们的话题相关的 twitter 数据!
让我们先浏览一下数据,看看数据集中最常见的单词是什么:
理解推文中的常用词
我们可以看到,“indyref2”、“scottish”、“independent”和“scotland”这几个词出现的频率高得不成比例。他们当然是。它们是我下载推文的关键词的一部分!所以我把它们排除在外,再看一看:
理解没有关键词的推文中使用的常用词
三月?为什么这个词是用得最多的?
啊!如果你住在英国,你可能会注意到 1 月 11 日, 数千名苏格兰独立支持者游行穿过格拉斯哥,这是计划于 2020 年举行的一系列抗议活动的第一场。并且该日期落在下载的推文的时间范围内。
图片来源:罗伯特·佩里
所以是的…三月。
让我们用单词云图来形象化所有的单词,因为它们很酷:
词频词云
你可以看到,像“格拉斯哥”、“snp”、“人民”、“今天”、“工会”、“游行”、“公投”这些词是出现频率最高的。然而,它并没有给我们任何关于推文相关情绪的想法。所以让我们继续预测吧。
我使用 LSTM 训练模型来创建推文数据集的预测。我必须强调的是这个模型通常检测消极或积极情绪。它不会检测某人是否在推特上发布了反对或支持该话题的内容。
我还必须做一些清理,使它对神经网络友好。基本上相同的预处理应用于训练数据。
预测之后,正面标签推文的数量是 263 条
,负面标签推文的数量是 373 条:
twitter 数据集中正面和负面推文的字数分布。
与被标记为正面的推文相比,被标记为负面的推文数量更多,尤其是当推文的字数更高时。对于我们的数据来说,推文越长,越有可能是负面的。
快速查看推文和它们的标签也很好。
以下推文被标记为负面:
@anninnis @BBCPolitics 投票反对留在欧盟他们在 2014 年说过。世事变迁,因缘际会
对于@BorisJohnson 拒绝了@NicolaSturgeon 持有#Indyref2 的请求,我一点也不感到意外。
他们读起来确实有点生气或不安,尽管这取决于读者的视角。
以下内容被我们的模型标记为阳性:
@CoyJudge 因为那次投票已经结束并且失败了,所以我继续前进,现在我们有了英国退出欧盟,我是获胜的一方。
我是工党,在这一点上我完全同意鲍里斯。SNP 整理出他们在苏格兰创造的所有 sh*t。Indyref2 死了。
没错。所以第二条推特预测对我来说有点奇怪,我不会把它归类为积极情绪。
唉,为了这个项目的目的,我继续用这个模型预测。
地理空间分析
因为我喜欢地图,我不得不创建地理可视化来探索它们在苏格兰和英国的分布情况,因为推文围绕着苏格兰和英国的新闻。
值得一提的是,我们的数据集在发展过程中存在局限性。大多数 twitter 用户不广播他们的地理位置,但我的搜索标准只提取了一些信息,让我可以得到它。
因此,我可能错过了很多没有地理标签的推文,这些推文描绘的画面可能与我在地图上绘制的画面不同。
了解这一点不仅对解释结果至关重要,而且对理解我们如何在未来的分析中使模型更加稳健也至关重要。
策划这一切并不容易。数据有几个问题,缺少形状文件和其他问题。例如,一个位置被指示为位于格拉斯哥的 Kelvingrove 公园,因此它应该被替换为格拉斯哥标签。或者一些推文展示了小城镇,比如属于法夫地区的巴尔戈尼镇。为了保持一致,我还得重新命名它。
在这之后,我终于为一些地块和地质地块做好了准备。
首先,让我们看看大多数推文来自哪里。
来源国推文统计直方图
按国家/州划分的推文统计直方图
来源城市的推文统计直方图
大多数推文来自苏格兰,具体来说,来自格拉斯哥,不是首都,而是苏格兰最大的城市,以其高比例的独立支持者而闻名。然而,相当一部分来自英国。
接下来,我提取了英国每个城市的总体情绪,将正面情绪与负面情绪相加,最终的数字是一个+/-指标。
总情绪直方图
从直方图中可以清楚地看出,大多数值位于-5
和5
之间,总体情绪稍微偏向负面。平均情绪是负面情绪(-1
)。与数据框架中的其他城市相比,还有几个城市的总体负面情绪值较大。
然后,我生成了下面的地图,通过这些消极和积极的情绪维度来可视化数据框架中城市的空间分布。点击此处查看互动地图。
情感分布图
提醒一下,所用的总情绪是通过对每个城市的积极和消极因素求和得出最终数字。
我设置了一个颜色等级,其中任何低于-1
的情绪都被标记为红色和消极,在-1
和1
之间的情绪是浅蓝色和中性,最后,高于1
的情绪被认为是积极的,并被涂上蓝色。
总体而言,似乎来自苏格兰城市的推文比来自英格兰和威尔士的推文有更多的负面情绪。北爱尔兰有一个城市的推文总体上给人一种中性的感觉。总体负面情绪最高的城市(-19
)是格拉斯哥,其次是苏格兰北部的因弗戈登(-13
)。
总之,来自爱丁堡、格拉斯哥、邓迪和斯特灵的推文显示负面情绪,阿伯丁是唯一一个正面情绪的主要城市。对于英格兰来说,我们可以看到更多的蓝点而不是红色。然而,来自曼彻斯特、伦敦和布里斯托尔等大城市的推文总体上有负面情绪。来自威尔士首府卡迪夫的推文总体上情绪积极。没有足够的发自北爱尔兰的推文来了解整体情绪。
接下来,我生成了一个热图,以查看数据集中来自各自地理位置数据的每条推文,并观察推文的密度。点击这里查看互动地图。
带有的热图英国地图数据集中的所有推文来源
热图显示,正如预期的那样,许多推文来自人口密度高的城市地区。这些地区是格拉斯哥、爱丁堡、伦敦、利物浦、曼彻斯特和卡迪夫。这是可以预料的。很可能大多数 twitter 用户都居住在城市地区。
查看我的 Github 中的完整笔记本和代码。
结论
在这篇文章的开始,我开始回答两个问题:
英国人对当前要求苏格兰独立公投的政治气候有何反应?鲍里斯·约翰逊拒绝允许吗?
发自苏格兰的推文告诉我们,总的来说,人们的反应是消极的。鲍里斯·约翰逊宣布拒绝在 1 月 14 日举行全民公决。因此,可以解释为这些反应与该公告有关,因为它在我们下载的推文的时间范围内。
苏格兰、英格兰、威尔士和北爱尔兰人的反应有何不同?对苏格兰特别感兴趣。
与来自英格兰城镇的推文相比,来自苏格兰的推文的情绪似乎有明显的差异。来自威尔士和北爱尔兰的信息不多。
一个有趣的步骤可能是在地图上添加一个时间维度,以可视化时间序列中的推文,并观察宣布前后推文情绪的变化。
现在,这些结果并不意味着苏格兰发推文的人对第二次苏格兰独立公投持负面看法,而英格兰发推文的人持正面看法。
重要的是要记住,在最基本的形式下,情感分析算法是一种根据文本包含的被分类为正面或负面的单词的相对数量来确定文本内容正面或负面程度的方法。
我使用了一个超越基础的 LSTM 网络,因为它已经显示出在给定足够的训练数据的情况下,它可以有效地学习社交媒体环境中的单词用法。
但它在确定推文是否对正在讨论的话题持负面态度方面是有限的。更像是,推文的意图是消极的还是积极的。
格拉斯哥的整体负面情绪可以解释为格拉斯哥人在推特上发布了很多负面词汇。当我们看一些推文时,非常愤怒的话。
图片:https://cinismoilustrado.com/
利益相关者可能对苏格兰独立的具体情绪感兴趣,而不是极性本身。他们可能想了解人们对这个话题的感受,意识到与之相关的日益增长的愤怒、恐惧或失望。
在这篇论文中,研究人员能够训练一个模型来学习三种类型的推文情绪指标:标签、标签模式和五种情绪之一的短语:喜爱、愤怒/愤怒、恐惧/焦虑、快乐或悲伤/失望。
用情感短语和它们的上下文来训练我们的分类器将是非常有益的。特别是用特殊的社区行为和特定区域的情感词汇来训练它。单词 soft 在很多情况下可能会唤起温暖的积极含义,但称橄榄球运动员 soft 是一种侮辱。
一个使用了反映愤怒、快乐、失望和其他情绪的苏格兰特有单词和短语的训练数据集可能会帮助我们了解苏格兰人对当前事态的真实看法。
仅此而已。我对政治非常有热情,所以这是一个非常令人兴奋的项目。
如果你设法看完了整本书,并且正在阅读这篇文章,感谢你的时间!非常感谢任何反馈。
2019 年英国媒体的政治情绪
原文:https://towardsdatascience.com/political-sentiment-of-british-media-in-2019-5c94fca7112f?source=collection_archive---------30-----------------------
图片来自皮克斯拜的马赫什·帕特尔
将 VADER 情感分析应用于政治观点
情感分析(意见挖掘)是自然语言处理(NLP)的一个分支,它评估给定文本的基本情感。它检测它是否有积极或消极的内涵。 VADER (Valence Aware 字典和情感推理器)是一个情感分析工具,旨在确定社交媒体上发布的短文本的情感。你可以在 GitHub 上找到 VADER 项目的完整文档。VADER 的主要优势在于,它不仅基于单词本身来评估情感,还会考虑大小写、标点符号和表情符号。帕鲁尔·潘迪写了一本非常好的 VADER 指南。
在这篇文章中,我将根据英国媒体在 2019 年发布的推文内容,用 VADER 来预测英国媒体的政治情绪。该项目的想法是,当将情感分析应用于包含某些词的文本时,例如,对立政党领导人的名字,我们可以测量不同媒体对不同政治家表达的情感的差异。通过将这些政客与他们的政治阵营联系起来,我们可以评估媒体的政治倾向。
方法
在分析中,我简化了什么是对的、左的、自由的或专制的定义。我完全明白这一点。然而,我的主要目的是测试 VADER 方法是否可以用来识别政治倾向,而不是精确地定义它们。然而,我认为我用来划分政治场景的方法很好地反映了现实生活中的分歧。
我将这种情绪分析为二维景观:左/右和威权/自由主义观点。在英国,两个主要政党是:保守党(又名托利党,右翼)和工党(左翼)。保守党和工党的领袖分别是:鲍里斯·约翰逊和杰里米·科尔宾。提到“鲍里斯·约翰逊的推文被用来评估右翼情绪,包括“杰里米·科尔宾的推文被用来评估左翼情绪。
杰里米·科尔宾和鲍里斯·约翰逊在他们自己的政治阵营中都被认为是有争议的人物。正因为如此,甚至来自左翼媒体的关于杰里米·科尔宾的推文也可能带有负面情绪。然而,来自同一家出版商的关于鲍里斯·约翰逊的推文可能会更加负面。为了解释这种相对消极性,我计算了每个出版商的左右情绪,从鲍里斯·约翰逊的情绪中减去杰里米·科尔宾的情绪。
例如,如果鲍里斯·约翰逊的情绪是-0.15,杰里米·科尔宾的情绪是-0.05,那么左右情绪= -0.1。任何低于 0 的都被归类为左翼情绪,任何高于 0 的都是右翼情绪。我还假设在-0.05 到 0.05 之间的任何值都是中性的。
识别威权-自由主义情绪更加困难。经过深思熟虑,我决定用对欧盟(欧盟)的态度作为自由主义观点的代理。我认为亲欧盟的观点更接近于亲自由主义的观点。另一方面,反欧盟的观点更有可能是更亲威权主义观点的结果。它可能不反映每个人的意见,但让我们接受它纯粹是为了测试的目的。
为了识别与 EU-相关的推文,我将提到让-克洛德·容克(欧盟委员会 2014-2019主席)、唐纳德·图斯克(欧洲理事会 2014-2019 主席)、迈克尔·巴尼耶(欧盟首席英国退出欧盟谈判代表)或简称为“欧盟”的推文分类为关于欧盟的推文。
为了评估政治情绪,我选取了 2019 年由 10 家媒体发布的推文(按字母顺序排列): BBC ,每日快报,每日邮报,每日镜报,(The)经济学人,金融时报,(The)卫报,(The)独立报,(Daily)电讯报和 (The)时报。
从历史的左右角度来看,英国媒体的政治倾向如下:
右:每日快报、每日邮报、电讯报和泰晤士报、经济学人、金融时报 左:卫报、镜报
中间派 : BBC、独立报
如果你想了解英国的政治光谱,有一份关于政治同情的好报告,涵盖了一些用于分析的媒体。
我发现,当涉及到自由主义/威权主义的分裂时,很难判断这些标题。然而,我认为《每日快报》、《每日邮报》和《每日电讯报》更倾向于威权主义,而《经济学人》、《金融时报》和《独立报》则倾向于自由主义。其他头衔通常混合了自由主义者和权威主义者的观点。
数据准备
为了提取推文,我使用了 GetOldTweets3 库。似乎你不能一次抽出太多,因此,对于每个用户名(媒体标题),我分别提取了每个月的推文,并在过程结束时合并它们。下面是 BBC 2019 年 9 月的一个例子。
保存到数据框中的推文如下所示(BBC 示例)。
最后,我把所有的媒体合并成一个文件。我做了一点清理,从正文中删除了 http 链接。此外,我已经删除了相同文本的重复推文。我没有做任何额外的文本清理,因为 VADER 更好地处理带有感叹号、大写字母、表情符号等的文本。你可以在这里找到最终文件。
VADER 产生积极的、中立的和消极的分数,这些分数代表属于每个类别的文本的比例。它还产生复合得分,这是推文单词的所有词典评级的标准化总和。复合评估文本的整体色调,范围从-1(负)到 1(正),介于-0.05 和 0.05 之间的值归类为中性。
VADER 的伟大之处在于,分数不仅能告诉你文章是正面还是负面,还能告诉你文章是正面还是负面。我曾用复合分数来评价情感,作为四个中最全面的一个。
这个化合物的初始标度在-1 和 1 之间。正如我之前提到的,为了计算左右情绪,我从约翰逊的得分中扣除了科尔宾的得分。通过这样做,我已经将情绪得分的整体范围更改为-2 到 2。然而,我想比较一下左右派情绪和威权-自由主义情绪(等级为 1 比 1)。为了让这两个尺度可以直接比较,我使用了一个 tanh 变换,将左右情绪重新调整回-1 到 1 之间的值。
我还调整了欧盟情绪的最终得分,将它除以-1。用这种方法,我把积极的一面转化为消极的一面,反之亦然。我这样做是为了让我的图表与互联网上的其他政治罗盘图表兼容,这些图表在 Y 轴的顶端是专制主义,底部是自由主义。
我们现在可以创建最终图表了…
结果
VADER 准确地预测了政治情绪的走向。我们可以争论相对比例(例如,一个标题是否比另一个更右翼)。尽管如此,总的来说,左翼头衔在左边,右翼头衔在右边。唯一的两个潜在的奇怪之处(在我看来)是:《独立报》似乎比《卫报》更左翼,此外,在独裁主义方面。另一个奇怪的是《经济学人》,它可能更接近中间立场。
- 图表上显示的名称是 Twitter 账户的名称。
4 个最重要的发现是:
- 英国媒体偏向于威权主义观点——大多数人坐在图表的顶部。
- 他们也更倾向于右翼而不是左翼
- 小报(《每日快报》、《每日邮报》和《每日镜报》)倾向于呈现不均衡的观点——它们位于图表的外围
- 《金融时报》是最平衡的标题——几乎是一个完美的中心!
结论
使用非常简单的标准(“约翰逊”、“科尔宾”和“欧盟”),我可以创建一个政治同情地图,这可能离现实不远。通过对左右派和威权-自由派分裂的一些额外研究,VADER 方法可以成为评估政治情绪的有力工具。
参考
[1]克莱顿·j·休顿,埃里克·吉伯特, VADER:一种基于简约规则的社交媒体文本情感分析模型(2014 年 7 月),美国安阿伯 AAAI 网络日志和社交媒体国际会议
[2]帕鲁尔·潘迪,使用 Python 中的 VADER 简化情感分析(在社交媒体文本上),【2018 年 9 月】分析 Vidhya
[3]马丁·贝克,如何从推特上抓取推文(2019 年 1 月),走向数据科学
附加说明
分析中使用的推特账号:
@TheEconomist、@TheTimes、@guardian、@FT、@BBCpolitics、@DailyMailUK、@Daily_Express、@Independent、@DailyMirror、@Telegraph
多边形:实时股票,外汇和加密数据。
原文:https://towardsdatascience.com/polygon-real-time-stocks-forex-and-crypto-data-3cbf9159e0c7?source=collection_archive---------50-----------------------
一个激动人心的历史和实时财务数据平台
你可能听过这句名言“数据是新的石油”太多次了。不管你对这一论断的看法如何,人们普遍认为数据对每个行业的创新过程都至关重要。特别是金融行业,鉴于该行业的高度动态性,访问高质量和最新数据是至关重要的。最近,我一直在研究一个需要实时数据(股票、外汇和加密货币数据)的交易机器人,我碰巧选定了一个名为 Polygon 的非常好的平台,它以一种漂亮、实惠和记录良好的服务提供了我所需要的一切。
引入多边形
我从事的项目需要在一段时间内实时加密货币数据。在谷歌搜索并询问了各种平台后,我最终选择了 Polygon。我发现这项服务价格有竞争力,稳定,文档也很好。由于我对这个平台的积极体验,我决定通过这篇文章分享我的经验和代码给任何可能有同样遭遇的人。
Polygon 通过 WebSockets 或 RESTful APIs 提供流客户端,用于访问大多数流行编程语言 Python to Go 中的实时数据。他们甚至有一个专用的 Python 包,用于更直接的访问。因为这个项目需要 Python,所以我选择了他们的 Python 包。
说够了,让我们进入正题,在安装了这个 python 包之后,开始玩一些实时加密货币数据:
**pip install polygon-api-client**
注意:为了简洁起见,这篇文章将专注于加密货币,但代码将包括对实时股票/股票、外汇数据感兴趣的读者的评论。访问需要一个 API 密钥,所以请前往https://polygon.io/signup获取密钥。
实时加密数据
该项目的目标是在特定时期内收集一些选定加密货币的实时数据。在下面相对简单的脚本中,我演示了如何使用 Polygon 的 Python 客户端与实时流数据进行交互。
该脚本的设计考虑了平台支持的其他类型的资产,因此应该很容易针对各种用例进行调整。该平台提供的广泛且用户友好的文档将比每个定制场景所需要的更多。
摘要
在这篇短文中,我介绍了 Polygon,它是一个可行的优秀平台,适用于需要使用 Python 客户端的各种实时财务数据的项目或产品。我推荐对这类服务感兴趣的读者访问他们关于 WebSockets 和RESTful API的文档,探索他们为加密货币/股票/外汇数据提供的大量产品。直到下一个帖子,编码快乐!
一如既往的期待反馈(好的坏的)!这篇文章的代码和所有其他文章一样,可以在这个 GitHub 库上找到。
Python 中的多态性:数据科学家的基础
原文:https://towardsdatascience.com/polymorphism-in-python-fundamentals-for-data-scientists-9dc19071da55?source=collection_archive---------34-----------------------
用一个具体的例子来理解基础!
在 Unsplash 上拍摄的 ThisisEngineering RAEng
多态是面向对象编程中的另一个重要概念。
当这些类包含具有不同实现但名称相同的方法时,它们就是多态的。在这种情况下,我们可以使用这些多态类的对象,而不用考虑这些类之间的差异。它允许我们有一个界面来以许多不同的方式执行类似的任务。
多态性通过增加灵活性使代码易于更改、维护和扩展。
这篇文章将向你介绍在 Python 中实现多态性的基础知识。
让我们编写一个 Python3 代码,其中包含简单的多态例子;
函数和对象的多态性
*class* **CSVColumnOne:** *def* **col_count**(*self*):
print(“Column One — count function is called.”)*def* **col_mean**(*self*):
print(“Column One — mean function is called.”)*def* **col_std**(*self*):
print(“Column One — std function is called.”)*class* **CSVColumnTwo:** *def* **col_count**(*self*):
print(“Column Two — count function is called.”)*def* **col_mean**(*self*):
print(“Column Two — mean function is called.”)*def* **col_std**(*self*):
print(“Column Two — std function is called.”)
上面你可以看到我们有两个不同的类, CSVColumnOne 和 CSVColumnTwo。 而它们之间没有任何联系,它们有三个同名的方法。虽然它们的名字相同,但每个类中的方法执行类似任务的方式不同。
*def* **func**(*obj*):
obj.col_count()
obj.col_mean()
obj.col_std()**obj_col_one** = CSVColumnOne()
**obj_col_two** = CSVColumnTwo()func(**obj_col_one**)
func(**obj_col_two**)**Output:**
Column One - count function is called.
Column One - mean function is called.
Column One - std function is called.
Column Two - count function is called.
Column Two - mean function is called.
Column Two - std function is called.
由于 Python 中的多态性,我们可以通过将每个类的对象传递给函数来创建调用方法的函数,而不用考虑不同类的对象如何不同地执行任务。
照片由 Louan García 在 Unsplash 上拍摄
Python 内置的多态函数
Python 中有很多内置的多态函数。举个例子,就拿 len() 函数来说吧;
**# len() being used for a string**
print(len("Data Science"))**# len() being used for a list**
print(len([1, 2, 3, 4]))**Output:** 12
4
从上面可以看出,我们可以对不同类型的对象使用 len() 函数,而无需考虑该函数将如何处理基于对象类型差异的任务。这使得代码直观易读。
具有类方法和继承的多态性
继承允许我们从其他类中派生出函数和数据定义,以增加代码的可重用性。下面可以看到 CSVColumnSub 类是 CSVColumn 的子类。
CSVColumnSub 类通过重写 col_mean() 方法来继承基类的 col_count() 和 col_mean() 方法,以具有特定于子类的不同实现。
*class* **CSVColumn**:
*def* **col_count**(*self*):
print("Count function is called for all columns.") *def* **col_mean**(*self*):
print("Mean function is called for all columns.")*class* **CSVColumnSub**(*CSVColumn*):
*def* **col_mean**(*self*):
print("Mean function is called for only sub-columns.")
由于多态,我们可以调用基类和子类中同名的方法,而不用考虑每个类中方法的不同实现。
**obj_col_all** = CSVColumn()
**obj_col_sub** = CSVColumnSub()**obj_col_all.col_count()
obj_col_all.col_mean()****obj_col_sub.col_count()
obj_col_sub.col_mean()****Output:**
Count function is called for all columns.
Mean function is called for all columns.
Count function is called for all columns.
Mean function is called for only sub-columns.
照片由诺亚·博耶在 Unsplash 上拍摄
关键要点
- 多态性允许我们用一个接口以多种不同的方式执行相似的任务。
- 多态性通过增加灵活性使代码易于更改、维护和扩展。
结论
在这篇文章中,我解释了 Python 中多态性的基础。
这篇文章中的代码可以在我的 GitHub 库中找到。
我希望这篇文章对你有用。
感谢您的阅读!
Python 中从头开始的多项式回归
原文:https://towardsdatascience.com/polynomial-regression-from-scratch-in-python-1f34a3a5f373?source=collection_archive---------18-----------------------
照片由雷德查理在 Unsplash 上拍摄
学习用一些简单的 python 代码从头开始实现多项式回归
线性回归的改进版本中的多项式回归。如果你知道线性回归,对你来说就简单了。如果没有,我将在本文中解释这些公式。还有其他更先进、更有效的机器学习算法。但是学习基于线性的回归技术是一个好主意。因为它们简单、快速,并且与众所周知的公式一起工作。尽管它可能无法处理复杂的数据集。
多项式回归公式
只有当输入变量和输出变量之间存在线性相关性时,线性回归才能表现良好。正如我之前提到的,多项式回归建立在线性回归的基础上。如果你需要复习线性回归,这里有线性回归的链接:
[## Python 中的线性回归算法
学习线性回归的概念,并使用 python 从头开始开发一个完整的线性回归算法
towardsdatascience.com](/basic-linear-regression-algorithm-in-python-for-beginners-c519a808b5f8)
多项式回归可以更好地找到输入特征和输出变量之间的关系,即使这种关系不是线性的。它使用与线性回归相同的公式:
Y = BX + C
我确信,我们在学校都学过这个公式。对于线性回归,我们使用这样的符号:
这里,我们从数据集中得到 X 和 Y。x 是输入要素,Y 是输出变量。θ值是随机初始化的。
对于多项式回归,公式如下:
我们在这里添加了更多的术语。我们使用相同的输入特征,并采用不同的指数来产生更多的特征。这样,我们的算法将能够更好地学习数据。
幂不必是 2、3 或 4。它们也可以是 1/2、1/3 或 1/4。那么该公式将如下所示:
成本函数和梯度下降
成本函数给出了预测的假设离值有多远的概念。公式是:
这个等式可能看起来很复杂。它正在做一个简单的计算。首先,从原始输出变量中扣除假设。取一个正方形来消除负值。然后将该值除以训练样本数量的 2 倍。
什么是梯度下降?它有助于微调我们随机初始化的θ值。我不想在这里讲微积分。如果对每个θ取成本函数的偏导数,我们可以导出这些公式:
这里,α是学习率。你选择α的值。
多项式回归的 Python 实现
下面是多项式回归的逐步实现。
- 在这个例子中,我们将使用一个简单的虚拟数据集来给出职位的工资数据。导入数据集:
import pandas as pd
import numpy as np
df = pd.read_csv('position_salaries.csv')
df.head()
2.添加θ0 的偏移列。这个偏置列将只包含 1。因为如果你用一个数乘以 1,它不会改变。
df = pd.concat([pd.Series(1, index=df.index, name='00'), df], axis=1)
df.head()
3.删除“职位”栏。因为“位置”列包含字符串,而算法不理解字符串。我们用“级别”栏来表示职位。
df = df.drop(columns='Position')
4.定义我们的输入变量 X 和输出变量 y。在本例中,“级别”是输入特征,“薪金”是输出变量。我们想预测工资水平。
y = df['Salary']
X = df.drop(columns = 'Salary')
X.head()
5.取“级别”列的指数,得到“级别 1”和“级别 2”列。
X['Level1'] = X['Level']**2
X['Level2'] = X['Level']**3
X.head()
6.现在,将数据标准化。将每列除以该列的最大值。这样,我们将得到每一列的值,范围从 0 到 1。即使没有归一化,该算法也应该工作。但它有助于更快地收敛。此外,计算数据集长度 m 的值。
m = len(X)
X = X/X.max()
7.定义假设函数。会用 X 和θ来预测 y。
def hypothesis(X, theta):
y1 = theta*X
return np.sum(y1, axis=1)
8.用上面的成本函数公式定义成本函数:
def cost(X, y, theta):
y1 = hypothesis(X, theta)
return sum(np.sqrt((y1-y)**2))/(2*m)
9.写出梯度下降的函数。我们将不断更新θ值,直到找到最佳成本。对于每一次迭代,我们将计算未来分析的成本。
def gradientDescent(X, y, theta, alpha, epoch):
J=[]
k=0
while k < epoch:
y1 = hypothesis(X, theta)
for c in range(0, len(X.columns)):
theta[c] = theta[c] - alpha*sum((y1-y)* X.iloc[:, c])/m
j = cost(X, y, theta)
J.append(j)
k += 1
return J, theta
10.所有函数都已定义。现在,初始化θ。我正在初始化一个零数组。您可以采用任何其他随机值。我选择α为 0.05,我将迭代 700 个时期的θ值。
theta = np.array([0.0]*len(X.columns))
J, theta = gradientDescent(X, y, theta, 0.05, 700)
11.我们得到了最终的θ值和每次迭代的成本。让我们用最终的θ找到工资预测。
y_hat = hypothesis(X, theta)
12.现在绘制原始工资和我们预测的工资水平。
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure()
plt.scatter(x=X['Level'],y= y)
plt.scatter(x=X['Level'], y=y_hat)
plt.show()
我们的预测不完全符合工资的趋势,但也很接近。线性回归只能返回一条直线。但是在多项式回归中,我们可以得到这样的曲线。如果直线不是一条漂亮的曲线,多项式回归也可以学习一些更复杂的趋势。
13.让我们在梯度下降函数中绘制我们在每个时期计算的成本。
plt.figure()
plt.scatter(x=list(range(0, 700)), y=J)
plt.show()
成本在开始时急剧下降,然后下降缓慢。在一个好的机器学习算法中,成本应该保持下降,直到收敛。请随意用不同的历元数和不同的学习率(alpha)来尝试。
下面是数据集:薪资 _ 数据
点击此链接获取完整的工作代码:多项式回归
推荐阅读:
[## Python 中的交互式地理空间数据可视化
绘制世界特定地区的地图,在地图上展示活动,并四处导航
towardsdatascience.com](/interactive-geospatial-data-visualization-in-python-490fb41acc00) [## 用几行代码在 Python 中搜索相似的文本:一个 NLP 项目
使用 Python 中的计数矢量器和最近邻法查找类似的维基百科简介,这是一个简单而有用的…
medium.com](https://medium.com/towards-artificial-intelligence/similar-texts-search-in-python-with-a-few-lines-of-code-an-nlp-project-9ace2861d261) [## Python 中用于检测心脏病的逻辑回归
发展逻辑回归演算法的重要方程式和如何发展逻辑回归演算法
towardsdatascience.com](/logistic-regression-in-python-to-detect-heart-disease-2892b138d0c0) [## 用 Python 从头开始构建神经网络
神经网络的详细说明和逐步实现
medium.com](https://medium.com/towards-artificial-intelligence/build-a-neural-network-from-scratch-in-python-f23848b5a7c6) [## 使用 Python 中的简单代码构建一个推荐系统
如何用 Python 构建电影推荐系统
medium.com](https://medium.com/towards-artificial-intelligence/build-a-simple-recommendation-system-in-python-7747be06a2f2)
多项式回归:你需要的唯一介绍
原文:https://towardsdatascience.com/polynomial-regression-the-only-introduction-youll-need-49a6fb2b86de?source=collection_archive---------19-----------------------
一名学生对 Python 中机器学习算法背后的理论和应用的深入探究
Python 多项式回归代码(所有照片由作者提供)
介绍
在我看来,多项式回归是机器学习过程中自然的第二步。在现实世界中比线性回归有用得多,但仍然易于理解和实现。
作为一名学生,我觉得自己处于一个独特的位置,可以向你们解释这个概念,因为我希望有人向我解释这个概念。
我在这里的目标是在理论和实现之间取得平衡,不遗余力地解释这种算法的内部工作原理、术语、它所基于的数学,最后是编写它的代码,以一种完全全面但对初学者友好的方式。 一个学生对另一个学生。
因此,欢迎阅读我希望在构建第一个多项式回归模型时能够读到的文章。
重要提示:
如果你是初学者,我建议你先阅读我关于线性回归的文章,我在下面有链接。在这本书里,我讲述了一些基本的回归知识和术语,我将在整篇文章中以这些知识和术语为基础,例如:
- 回归分析概述。
- 回归工作原理的解释。
- 重要术语包括 R、均方误差和方差。
- 一个详细的线性回归例子。
如果你不熟悉我上面提到的任何东西,请先阅读这篇文章,因为我不会再详细解释这些概念,它们是至关重要的。
[## 线性回归:(实际上)完全介绍
一位同学用 Python 对这个简单的机器学习算法进行了全面、深入的解释
towardsdatascience.com](/linear-regression-the-actually-complete-introduction-67152323fcf2)
该理论
P 多项式回归是一种回归分析形式,其中自变量 x 和因变量 y 之间的关系被建模为n 次多项式在 x 中。
那么是什么意思呢?
你可能还记得,从高中开始,以下功能:
Degree of 0 —> Constant function —> f(x) = a
Degree of 1 —> Linear function (straight line) —> f(x) = mx + c
Degree of 2 —> Quadratic function (parabola) —> f(x) = ax^2 + bx+ c
Degree of 3 —> Cubic function —> f(x) = ax^3 + bx^2 + cx + d
当编写多项式回归脚本时,在某个阶段,我们必须选择我们想要绘制图形的次,我将在后面演示。现在,让我们看看这对我们的函数意味着什么:
什么是度?
嗯,你可能已经注意到上面的模式:一个多项式的次数就是它的任何一项的最高次幂。因此,我们选择的程度将决定我们用哪个函数来拟合数据。
0–5 次多项式函数
以上都是多项式。
多项式的简单意思是【多项】,在技术上定义为由变量和系数组成的表达式,只涉及变量的加、减、乘和非负整数指数的运算。
值得注意的是,虽然线性函数确实符合数学中多项式的定义,但在机器学习的背景下,我们可以将它们视为回归分析的两种不同方法。
实际上,多项式回归在技术上是一种线性回归。尽管多项式回归将非线性模型拟合到数据,但作为统计估计问题,它是线性的,因为回归函数 E(y|x) 在根据数据估计的未知参数中是线性的。因此,多项式回归被认为是多元线性回归的特例。
简而言之:把多项式回归想成包含二次和三次函数,把线性回归想成线性函数。
术语
让我们快速浏览一些重要的定义:
单变量/双变量
- 一个单变量数据集只涉及一个量,如倍数或权重,从中我们可以确定均值、中值、众数、范围和标准差等,并可以表示为条形图、饼图和直方图。
- 一个双变量数据集有两个量,例如一段时间内的销售额,我们可以用它来比较数据和寻找关系,并且可以用散点图、相关性和回归来表示。
装配不足/过度装配
- 当我们的统计模型不能充分捕捉数据的基本结构时,就会出现欠拟合。
- 相反,过度拟合会产生与特定数据集过于接近的分析,因此可能无法拟合额外的数据或可靠地预测未来的观察结果。
欠装配(左)和过装配(右)的示例
该算法
那么,我们什么时候会选择多项式而不是线性回归呢?
在 3 种主要情况下,多项式回归会超过线性回归:
- 理论上的原因。研究者(你)可能会假设数据是曲线,在这种情况下,你显然应该用曲线来拟合它。
- 对数据进行目视检查后,可能会发现一种曲线关系。这可以通过简单的散点图来实现(这就是为什么在应用回归分析之前,您应该始终对您的数据进行单变量和双变量检查)。
- 检查模型的残差。试图用线性模型拟合曲线数据会导致高正负残差和低 R 值。
让我们更进一步。我们如何选择多项式的次数?
你可以做各种数学分析来决定你的模型的最佳程度,但归结起来就是要确保你不会低估或过度拟合数据。出于我们的目的,简单地检查散点图将揭示合适的选项。
记住,我们执行回归分析的方法是通过确定最小化残差平方和的系数。
这个例子
首先,进口:
- 熊猫——创建一个数据框架
- numpy——做科学计算
- Matplotlib (pyplot 和 RC params)-创建我们的数据可视化
- Skikit-Learn(线性回归、train_test_split 和多项式特征)-执行机器学习
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rcParams
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
在这个例子中,我创建了自己的数据集,代表了中国 30 天内记录的新冠肺炎新增病例数量,并将其存储在一个 csv 文件中。该文件如下所示:
x,y
1,59
2,77
3,93
...,...
接下来,我们使用 pandas 将 x an y 值读入两个数组。你也可以用 pandas 的 iloc 来做这件事,甚至在没有 pandas 的情况下,手动从文件中读取数据。这个 pandas 方法非常方便,因为我们可以通过名称来访问列。
data = pd.read_csv('china_cases.csv')x = data['x'].values
y = data['y'].values
我们现在有两个如下所示的数组:
[1 2 3 4 5 ...]
[59 77 93 149 131 ...]
让我们将数据分成训练集和测试集。为此,我们将使用 Skikit-Learn 方便的 train_test_split 函数。我们将数组 x 和 y 值作为参数传递给它,此外还有一个测试大小(您希望测试部分包含多少数据)和一个随机状态(一个整数,表示数据在被分割之前如何被混洗。如果您忽略它,每次运行回归时,您的结果都会略有不同,因此保留它以重现您的结果,但您可以将其删除以用于生产)。
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=42)
现在是通过散点图对数据进行双变量检验的好时机。我将使用 rcParams 和图例添加一些样式,使它在视觉上更具吸引力。
rcParams['axes.spines.top'] = False
rcParams['axes.spines.right'] = Falseplt.scatter(x_test, y_test, c='#edbf6f', label='Testing data')
plt.scatter(x_train, y_train, c='#8acfd4', label='Training data')
plt.legend(loc="upper left")
plt.show()
下面,您可以清楚地看到,线性模型不会精确地适合该数据集,但看起来二次或三次函数会很好地工作。
训练和测试数据的散点图
在这一点上,我们想增加我们的数组的维数到 2D,因为这是多项式特征类所要求的必要的矩阵格式。我们可以简单地通过调用 reshape() 函数来实现这一点,在这里我们定义我们希望我们的数据如何被整形。
x_train = x_train.reshape(-1, 1)
y_train = y_train.reshape(-1, 1)
我们的数组现在看起来像这样(这是 x_train ):
[[22]
[ 1]
[27]
[14]
[16]
...]
然而,正如你所看到的, train_test_split 打乱了我们的数据,所以不再排序。Matplotlib 将按照接收到的顺序绘制点,所以如果我们像现在这样给它输入数组,我们会得到一些非常奇怪的结果。为了对数组重新排序,我们按照 x_train 的索引对 y_train 进行排序,并对 x_train 本身进行排序。
y_train = y_train[x_train[:,0].argsort()]
x_train = x_train[x_train[:, 0].argsort()]
正如我前面提到的,我们必须设置多项式的次数。我们通过创建一个 PolynomialFeatures 类的 object poly 来实现这一点,并将我们需要的能力作为参数传递给它。
poly = PolynomialFeatures(degree=2)
此外,我们必须将输入数据矩阵转换成给定阶数的新矩阵。
x_poly = poly.fit_transform(x_train)
我们剩下要做的就是训练我们的模型。我们创建一个 LinearRegression 类的对象 poly_reg (记住多项式回归在技术上是线性的,所以它属于同一个类),并使我们转换的 x 值和 y 值适合模型。
poly_reg = LinearRegression()
poly_reg.fit(x_poly, y_train)
现在我们简单地绘制我们的线:
plt.title('Disease cases regressed on days')
plt.xlabel('Days')
plt.ylabel('Cases')
plt.plot(x_train, poly_reg.predict(x_poly), c='#a3cfa3', label='Polynomial regression line')
plt.legend(loc="upper left")
plt.show()
二次多项式回归
这就是了,一个符合我们数据的二次函数。
如果我们把度数设为 3 呢?
三次多项式回归
这个三次函数似乎更适合我们的数据。让我们通过使用线性回归类来检查他们各自的 R 分数,以更清楚地了解他们的准确性。score() 功能:
print(poly_reg.score(x_poly, y_train))
我们二次函数的 R 值是 0.81,而三次函数的 R 值是 0.93。在这种情况下,我会说第三度是一个更合适的选择。
注意:如果您选择 1 作为度数,您将执行线性回归,但这将是一种非常迂回的方式。
如果你想了解另一个有用的最大似然算法,K-Means,看看这篇文章:
[## 适用于初学者的 k-均值聚类
一个深入的解释和一步一步的指导这个有趣和有用的机器学习算法在 Python 中,由…
towardsdatascience.com](/k-means-clustering-for-beginners-ea2256154109)
结论
这就结束了对机器学习的第二简单算法多项式回归的全面介绍。我希望,作为一名学生,我能够相关而全面地解释这些概念。
让我们来复习一下我们学过的内容:
- 提醒一下什么是二次函数。
- 一些重要的术语。
- 对算法的解释,包括何时使用多项式回归以及如何选择次数。
- 实际例子。
- 对我们的模型使用不同程度的比较。
如果你觉得这篇文章有帮助,我很乐意与你合作!关注我 Instagram 了解更多机器学习、软件工程和创业内容。
编码快乐!
订阅 📚为了不错过我的一篇新文章,如果你还不是中等会员,请加入 🚀去读我所有的,还有成千上万的其他故事!
资源
分析因子 回归模型:https://www . The Analysis Factor . com/Regression-model show-do-you-know-you-need-a-polynomial/
维基 过度拟合:https://en.wikipedia.org/wiki/Overfitting
数学很好玩 单变量和双变量数据:https://www.mathsisfun.com/data/univariate-bivariate.html
堆栈溢出 随机状态:https://Stack Overflow . com/questions/28064634/Random-State-pseudo-Random-number-in-scikit-learn
sci kit-Learnsk Learn . preprocessing . polynomial features:https://sci kit-Learn . org/stable/modules/generated/sk Learn . preprocessing . polynomial features . html # sk Learn . preprocessing . polynomial features . fit _ transform
Scikit-Learnsk Learn . linear _ model。线性回归:https://sci kit-learn . org/stable/modules/generated/sk learn . linear _ model。LinearRegression.html
Scikit-Learnsk Learn . model _ selection . train _ test _ split:https://Scikit-Learn . org/stable/modules/generated/sk Learn . model _ selection . train _ test _ split . html
栈溢出 O 排序点:https://Stack Overflow . com/questions/31653968/matplotlib-connecting-error-Points-in-line-graph
堆栈溢出 根据另一个列表的索引对一个列表排序:https://Stack Overflow . com/questions/6618515/Sorting-list-based-on-values-from-other-list
堆栈溢出 按第二列排序 2D 数组:https://Stack Overflow . com/questions/22698687/how-to-sort-2d-array-numpy-ndarray-based-to-the-second-column-in-python
ML 从零开始-使用 PyTorch 的多项式回归
原文:https://towardsdatascience.com/polynomial-regression-using-pytorch-from-scratch-500b7887b0ed?source=collection_archive---------26-----------------------
来自 Pexels 的 Lukas Rodriguez 摄影
如何编写多项式回归模型及其背后的数学的完整指南
说到预测分析,回归模型被证明是最具成本效益的方法之一。虽然线性回归模型可以提供一些很好的预测,但在某些情况下,多项式回归模型可以大大优于简单的线性模型。在下面的项目中,我们将看看如何在 PyTorch 中从头开始创建多项式回归模型。
项目目标
- 在 PyTorch 中实现机器学习模型,使用多项式回归算法进行预测。
我们将使用基本的 PyTorch 张量运算,完全从头开始创建模型。
- 利用该模型对汽车价格进行预测分析。在项目的最后,我们的目标是开发一个高效的 ML 模型,它可以根据汽车的特征预测汽车的价格。
- 对数据进行可视化和描述性分析,以预测哪些功能在确定汽车价格时起着关键作用。
导入项目依赖关系
在我们开始这个项目之前,让我们导入所有必要的库和函数。
现在,让我们导入数据集。
如果你打算自己动手,这里有数据集的链接。
我还会在本文末尾将 GitHub repo 与项目笔记本和数据集链接起来。
在我的笔记本中看到的数据框
由于多项式回归模型对于初学者来说已经有点太难了,因此,为了简单起见,我们将在项目中只使用连续变量。
我们将着手更新数据框
数据争论
现在,让我们分析数据,看看是否需要清理或修改。首先,让我们检查数据帧中每一列的数据类型。
*需要注意的一点是,数据集没有空值。
不同列的数据类型
正如我们所看到的,一些数据是' int64 ',类型,而一些数据是' float64' 类型。由于我们将使用张量,我们可能希望在我们的特征集中有一个统一的数据类型。因此,我们将在后面的步骤中将整个数据帧转换为' float64' 。
现在,我们将看看数据框的描述性分析。
显示我们的数据框的描述性分析的表格
正如我们所看到的,不同列中的数据在规模上有很大差异。在我们的数据集中,在较低范围上有顺序为 1e+0 的元素,在较高范围上有顺序为 1e+3 的元素。我们可能想要将数据标准化。我们将在项目的后续步骤中处理这个问题。
特征选择
让我们首先绘制每个独立变量相对于目标变量(质量)的曲线图。
所有情节的截图
现在,让我们看看数据集的相关值。
从上面的直观分析中,我们可以清楚地看到发动机尺寸 (++0.87)、整备质量 (+0.84)和马力 (+0.81)与因变量价格呈现出非常强的相关性。
车宽 (0.76)、城市 mpg (-0.69)、公路 mpg (-0.70)和汽车长度 (0.68)表现出相对较强的相关性。因此,在本例中,我们将选择这 7 项作为我们的培训功能。
特征测向和目标系列的形状
现在,我们将研究我们的模型。但在此之前,首先让我们再一次观察目标的特征图。
我们的自变量对因变量的图表
如果我们仔细观察图表,我们会注意到特征发动机尺寸、整备重量、马力、车长和车宽具有类型 y = x2 的图表。
另一方面, citympg 和 highwaympg 具有类型 y = 1 / x2 的图形。
因此,我们将相应地处理这些特性。
从头开始构建模型
下面给出了我们的多项式回归模型将工作的公式。
根据我们的特征集的多项式回归公式
正如我们所看到的,多项式回归函数可以替换为线性回归函数
这里,
- ŷ -目标变量的预测值
- W -这是一个(1 x m)矩阵,包含与每个多项式变换的因变量相关的所有权重
- X -包含所有多项式变换特征变量的矩阵转置
- B - A (1 x m)矩阵,其中每个元素都是我们函数的偏差值。
- m——训练/测试集中的行数
- n -多项式变换特征的数量
现在让我们将特征(Pandas Dataframe 对象)和目标(Pandas Series 对象)转换为张量对象,这样我们就可以用它们来训练 PyTorch 的模型。
张量特征 _x2 和特征 _ 1byX2 的大小
现在,对于激活函数类型为 y = x2 的特征,我们首先创建 x2 特征,然后将其连接到我们的张量对象。
现在,对于激活函数类型为 y = 1/x2 的特征,我们首先创建 1/x2 特征,然后将其连接到我们的张量对象。
有了这个,我们已经多项式变换了我们的特征。
最后,我们将把所有转换后的特征张量连接成一个单一的张量对象。
特征缩放
由于我们将使用随机梯度下降(SGD)算法作为我们模型的优化算法,缩放可以显著改善优化过程和我们模型的性能。
在这个项目中,我们将执行最小-最大缩放。最小-最大归一化转换数据,使所有值都在[0,1]之间。
最小-最大归一化的数学公式如下:
这里,
- X =观察值
- X min =在列中观察到的最小值
- X max =列中观察到的最大值
- X 比例值 =比例值
现在,让我们对我们的特征集执行最小-最大归一化。
所有值都在[0,1]之间的缩放特征集
现在,我们将创建一个张量对象,它保存与多项式变换的归一化特征相关联的权重。这些权重是随机生成的,非常小。
现在,让我们为我们的模型初始化一个随机偏差。
最后,将目标数组转换成张量。
目标张量的屏幕截图
现在,让我们定义回归函数。
为我们的特征集运行多元回归函数
现在,我们将定义我们的均方差( MSE )函数。MSE 是计算总模型损耗最常用的方法之一。下面给出了 MSE 的计算公式。
在为我们的模型运行 MSE 函数时-
正如我们所见,我们的模型目前给出了一个非常大的 MSE。因此,我们需要优化我们的模型权重和偏差,以提高其性能。
优化模型
为了优化我们的模型,我们将使用随机梯度下降(SGD)算法。下面给出了与 SGD 优化器算法相关的数学。
有关 SGD 的更多信息,请访问此链接。
在我们的模型中,我们将使用 PyTorch 内置的梯度计算函数来计算和更新权重和偏差。
完成所有这些后,我们将最终为我们的模型运行优化器函数。
通过为我们的模型运行优化器函数获得的结果
现在,为了检查我们模型的准确性,我们将计算它的 r 平方得分。以下是 r2 得分的公式-
现在,让我们检查模型的性能。我们将使用通过优化函数获得的更新模型和权重。
我们模型的 r 平方分数
正如我们所见,我们的多项式回归模型可以解释因变量约 83–84%的方差。这是一个相当有效的模型。
这里需要注意的一点是,我们在同一个数据集上执行了训练和测试,这是一种糟糕的做法。相反,您应该将数据集分为测试集和训练集。然而,在这个例子中,当从头开始创建模型时,我跳过了这一步,以使事情简单易懂。
在项目的最后,让我们为模型的所有多项式变换特征绘制回归图。
从上面的图表中,我们可以看到我们的模型表现得相当好。
这样,我们的项目就结束了。更多像这样有趣的项目,请查看我的简介。
我只是机器学习和数据科学领域的新手,所以任何建议和批评都将真正帮助我提高。
点击以下链接,继续关注更多 ML 内容!
数据集和 Jupyter 笔记本的 GitHub repo 链接-
[## aman Sharma 2910/多项式回归 _ 从头开始 _ 使用 _PyTorch
repo 包含我的项目的 Jupyter 笔记本,在那里我从头开始创建了一个多项式回归模型,使用…
github.com](https://github.com/amansharma2910/PolynomialRegression_from_scratch_using_PyTorch)
多项式回归-使用哪个 python 包?
原文:https://towardsdatascience.com/polynomial-regression-which-python-package-to-use-78a09b0ac87b?source=collection_archive---------21-----------------------
用 numpy、scipy、sklearn、tensorflow 表达的“Hello world”。
“协同捕鱼”。葡萄牙 2019 。(作者私人收藏)
介绍
多项式回归是数据分析和预测中最基本的概念之一。不仅任何(无限可微的)函数至少在一定区间内可以通过泰勒级数表示为多项式,这也是机器学习初学者首先面临的问题之一。它被用于各种学科,如金融分析、信号处理、医学统计等。
虽然多项式回归是一个相对简单的概念,但它成为了机器学习中的一种“hello world”问题,因为它涉及到许多核心概念。尽管如此,有些部分可能听起来令人困惑,尤其是因为:
- 它一次引入了几个东西,尽管只有一些是多项式回归特有的。
- 它通常以多种不同的方式实现。
在这篇博文中,我们将使用这两个方程从头构建它,并通过代码来表达它们。然后,我们将我们的实现与数据科学中最广泛使用的四个 python 库进行比较:
- numpy,
- 暴躁,
- scikit-learn,
- 张量流,
并讨论它们之间的差异,同时指出基本层面上的相似之处。
问题是
先讨论数学基础。
从数学上讲,回归的问题是试图对自变量 x 和因变量 y 之间的关系进行建模。假设 y' s 依赖于 x 用以下形式表示:
我们称之为多项式回归(ε表示噪声项)。自然,如果最大值 n = 1 ,问题就变成了线性回归。
解决问题意味着确定所有和 ₙ's 的值来很好地表示数据。它可以归结为以下步骤的要素:
- 关于 y 形式的一个“猜想”。它叫做一个假设函数 h(x) 。
- 在给定真实数据值的情况下,衡量假设有多“差”的一种方法。使用所谓的损失函数 J 来量化这种“不良”。
- 关于我们如何潜在地“调整”假设,使我们更好地逼近数据点的想法。换句话说,我们需要有某种最小化 J 的方法。
选择假设
说到多项式回归,我们首先需要假设的是我们将用作假设函数的多项式的次。如果我们选择成为度,假设将采取以下形式:
成本函数和均方误差
接下来,我们选择用来表示成本函数的度量。对于回归问题,选择所谓的均方误差(MSE) 是有意义的,它衡量单个点与我们的预测之间的平均距离,达到二次幂。
这里 m 与数据点个数相关,为了方便引入 1 /2 因子(见后)。我们还将所有参数表示为参数向量 θ = (θ₁、θ₂、……、θₙ) 。
MSE 指标只是一种选择,但由于以下原因,它是合理的:
- MSE 在误差方向上是不可知的(例如不像平均误差在一次幂中只与 h-y 成比例)。
- MSE 会因二次幂而严重惩罚较大差异(异常值)(例如,与 abs 成比例的平均绝对误差(h-y))不同。
- 对于均方误差,更容易获得梯度(例如不像均方根误差那样为ìMSE)。
梯度下降
一旦我们建立了成本函数并设置了一些随机的初始值 θ ,我们就希望最小化 J 。其中一个可能的选择是梯度下降优化算法。顾名思义,它要求我们计算 ∇J 并随后相应地更新所有 θ 。
换句话说,我们需要计算每一个 θ ₖ的 J 的导数,并用它们来改变 θ 的值:
从而使得假设越来越好地表示数据。
幸好 d J/d θ 很容易计算:
最后一项是假设函数相对于 θ 的导数。因为我们假设它是一个多项式:
整个梯度变成:
如果我们把所有的 x 组织成一个例子向量,我们可以用向量矩阵乘法来表示上面的公式:
或者以更紧凑的形式
这里、 X 、表示由上升到连续幂的示例向量组成的矩阵 j = 0、1、…、n 。
基本实现(幼稚)
我们称这种实现方式为幼稚的,因为它并没有针对性能进行优化。相反,重点是强调代码和基本方程之间的对应关系。
首先,我们将使用符号多项式的自定义实现(参见要点)。Polynomial
类基于多项式表达式(第一个等式)定义了一个可调用对象。它实现了许多类似于我们的四元数例子的代数方法,但是现在最重要的部分是初始化。
我们从创建一个具有随机系数 θ 的Polynomial
对象开始。
import numpy as np
from nppoly import Polynomial
np.random.seed(42)
def hypothesis(degree):
return Polynomial(*np.random.rand(degree + 1))
此方法接受并返回一个具有随机系数的多项式。接下来,我们定义我们的 MAE 成本函数:
def cost(h, X, y):
return 0.5 / len(y) * ((h(X) - y) ** 2).sum()
这里的len(y)
相当于和h
、X
和y
是假设,那么 x 和y——自变量和值的向量。请注意,大写X
更多的是一种传统,以强调其类似矩阵的特征。然而,在我们的例子中,X
只与一维数据相关联。
接下来,我们需要表达 J 的梯度。多亏了这个推导,我们已经知道了这个表达式:
def grad_theta(h, X, y):
diff = (h(X) - y).reshape(-1, 1)
X = X.reashape(1, -1)
X = list(map(lambda i: x ** i, reversed(range(h.shape))))
X = np.concatenate(X)
return 1 / len(y) * (X @ (diff)).reshape(1, -1)
在这个函数中,我们需要执行几次整形,以确保我们可以将矩阵乘以一个向量。第 4-6 行负责构造 X ,reversed
函数用于遵守 θ ₙ站在 θ ₙ₋₁.之前的约定
最后,使用以下函数完成优化例程:
def optimize(h, X, y, epochs=5000, lr=0.01):
theta = h._coeffs.reshape(1, -1)
for epoch in range(epochs):
theta -= lr * grad_theta(h, X, y)
h = Polynomial(*theta.flatten())
return h
这里,第 2 行只是假设的初始化。然后,在 for 循环内部,我们执行 θ ←θ - α∇J ,其中 α 是所谓的学习率lr
,重复周期传统上称为“epochs”。
可以通过执行一个小脚本来验证优化:
# fake data
X = np.linspace(0, 10, num=5)
y = 4 * X - 2 + np.random.randn(len(X))
h = hypothesis(1)
h = optimize(h, X, y)
# prediction
X_test = np.linspace(-5, 25, num=31)
y_pred = h(X_test)
Python 库
Numpy
第一个实现多项式回归的库是 numpy 。它使用numpy.polyfit
函数来执行此操作,该函数给出数据(X
和y
)以及度数,执行该过程并返回系数数组 θ 。
import numpy as np
from numpy import polyfit
# fake data
X = np.linspace(0, 10, num=5)
y = 4 * X - 2 + np.random.randn(X)
u = polyfit(X, y, deg=1)
# prediction
X_test = np.linspace(-5, 25, num=31)
y_pred = u[0] * X_test + u[1]
如果full
设置为True
,该功能将提供额外的诊断,为我们提供与不确定性相关的信息。
Scipy
解决多项式回归问题的另一个“配方”是 scipy 中的curve_fit
。与polyfit
相比,该函数更加通用,因为它不需要我们的“模型”采用多项式形式。它的界面也不一样。
import numpy as np
from scipy.optimize import curve_fit
def linear_function(x, a, b):
return a * x + b
def quadratic_function(x, a, b, c):
return a * x**2 + b * x + c
# fake data
X = np.linspace(0, 10, num=5)
y1 = 4 * X - 2 + np.random.randn(len(X))
y2 = 5 * X ** 2 - 3 * X + 10 + np.random.randn(len(X))
u = curve_fit(linear_function, X, y1)[0]
v = curve_fit(quadratic_function, X, y2)[0]
# prediction
X_test = np.linspace(-5, 25, num=31)
y_pred_1 = linear_function(X_test, u[0], u[1])
y_pred_2 = quadratic_function(X_test, v[0], v[1], v[2])
与polyfit
相反,这个函数首先需要一个模型函数作为参数传入。它可以是任何参数化的数学公式,然而,curve_fit
强加了一个条件:模型函数本身接受数据x
作为它的第一个参数。最后,它返回优化的系数,类似于polyfit
,尽管它也返回诊断信息(因此在最后用[0]
来抑制它)。
sci kit-学习
就机器学习而言,Scikit-learn (或 sklearn)是一个“首选”库。它非常注重接口的一致性,这意味着它试图使用相同的方法(如.fit
、.transform
、.fit_transform
和.predict
)来统一对不同特性和算法的访问。求解线性回归解是相当容易的,然而,多项式回归的情况需要一点思考。
让我们从线性回归开始。
import numpy as np
from sklearn.linear_model import LinearRegression
# fake data
X = np.linspace(0, 10, num=5).reshape(-1, 1)
y = 4 * X - 2 + np.random.randn(len(X))
linreg = LinearRegression()
linreg.fit(X, y)
# prediction
X_test = np.linspace(-5, 25, num=31).reshape(-1, 1)
y_pred = linreg.predict(X_test)
这里,解决方案是通过LinearRegression
对象实现的。按照 scikit-learn 的逻辑,我们首先使用.fit
方法将对象调整到我们的数据,然后使用.predict
呈现结果。注意X
需要被重新整形为一个(m, 1)
向量列。
为了解决更一般的多项式回归情况,我们需要将LinearRegression
与PolynomialFeatures
对象结合起来,因为没有直接的解决方案。事实上,sklearn 的构建意图是处理与数据相关的问题,而不是成为一个方程求解器。更多的差异可以在这个帖子中找到。
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import make_pipeline
# fake data
X = np.linspace(0, 10, num=5).reshape(-1, 1)
y = 5 * X ** 2 - 3 * X + 10 + np.random.randn(len(X))
polyreg = make_pipeline(
PolynomialFeatures(degree=2),
LinearRegression()
)
polyreg.fit(X, y)
# prediction
X_test = np.linspace(-5, 25, num=31).reshape(-1, 1)
y_pred = polyreg.predict(X_test)
起点是 PolynomialFeatures 类,它基于通用变量和创建“混合”术语。这里,我们把这个变换应用到,这个获得一个特征向量(矩阵)(1, x , x ),因为 n = 2 ,并且 x 是一维的。然后,使用 sklearn 的管道,我们将 x 与线性系数 θ 结合起来,基本上将每个 x 视为一个单独的变量。最后,我们解决它,就像我们面对标准的线性回归问题,获得 θ 。
我们可以看到这里采用的方法与 numpy 和 scipy 都有很大的不同。因为 sklearn 更多地从连续调整(fit
)、数据转换(这里不需要)和预测(predict
)的角度“看待”问题。无论哪种方式,结果都是一样的。
张量流
我们在这里介绍的最后一个软件包是 Tensorflow 2.0 。由于在 2.0 版本中引入的 API 已经有了实质性的变化,我们不打算呈现 1.x 版本中提供的解决方案。但是,如果你感兴趣,请参考 trần ngọc·明的这篇精彩的帖子。
流程的外观与我们最初的实现非常相似。事实上,在引擎盖下,它非常不同。我们先来看看下面的片段:
import numpy as np
import tensorflow as tf
LEARNING_RATE = 0.0001
N_EPOCHS = 100000
DEGREE = 2
X = np.linspace(0, 10, num=5).reshape(-1, 1)
y = 5*X**2 - 3*X + 10 + np.random.randn(len(X))
theta = tf.Variable([0.0] * (DEGREE + 1), name='parameters')
def hypothesis(x):
return sum([theta[i] * x**i for i in range(DEGREE + 1)])
def cost(y_pred, y):
return tf.reduce_mean(tf.square(y_pred - y))
for epoch in range(N_EPOCHS):
with tf.GradientTape() as tape:
y_predicted = h(X)
cost_value = cost(y_predicted, y2)
gradients = tape.gradient(cost_value, theta)
theta.assign_sub(gradients * LEARNING_RATE)
X_test = np.linspace(-5, 25, num=31)
y_test = hypothesis(X_test).numpy()
与假设和成本函数相关的逻辑是相同的。此外,使用相同的方法执行训练,只有函数名称不同。然而,事实是 tensorflow 试图通过构建所谓的图来象征性地解决问题。该图是所有数学依赖关系的表示,以便导数可以很容易地计算出来。例如,theta.assign_sub(...)
转化为用梯度更新 θ ,而tf.
前缀函数是 numpy 已知函数的张量流符号对应物。
结论
在本文中,我们从数学和编程的角度重新审视了多项式回归问题。此外,我们使用数据项目中常用的四个 python 库比较了它的实现。我们还将它们与一个定制的、面向演示的实现进行了比较,讨论了它们的异同。
如果你仍然不知道该选择哪一个,这里是我们的建议:
- 除非你想拟合一个非多项式函数,否则就用 numpy。您的项目可能无论如何都需要它。
- 如果您确实有一个更奇特的函数或不容易转换成多项式的函数,请使用 scipy。它的界面非常清晰,安装速度也非常快。
- 如果你用 sklearn 做一个更大的机器学习项目,并且你的一个步骤需要某种多项式回归,这里也有一个解决方案。尽管如此,仅仅为了进行回归而安装这个库是没有意义的。
- 这同样适用于 tensorflow。除非这不是一个需求,否则不要把事情复杂化。
- 最后,说到复杂性,不要在你的实现上浪费时间——当然,除非你正在学习。
如果这篇文章已经帮助你抓住了一个更大的画面,加深了你的理解,那是很好的。这意味着它的主要目标已经实现。无论哪种方式,欢迎评论或分享!
还会有更多…
我计划把文章带到下一个层次,并提供简短的视频教程。
如果您想了解关于视频和未来文章的更新,订阅我的 简讯 。您也可以通过填写表格让我知道您的期望。回头见!
原载于https://zerowithdot.com。
具有机器学习流水线的多项式回归
原文:https://towardsdatascience.com/polynomial-regression-with-a-machine-learning-pipeline-7e27d2dedc87?source=collection_archive---------19-----------------------
依次应用多个转换器和一个最终回归器来构建您的模型
约书亚·索蒂诺在 Unsplash 上拍摄的照片
欢迎回来!应用我们已经拥有的知识,用一些真实的数据建立机器学习模型,这是非常令人兴奋的。 多项式回归 ,我们今天讨论的主题,就是这样一个模型,它可能需要一些复杂的工作流程,这取决于问题陈述和数据集。
今天我们讨论如何建立多项式回归模型,以及在做模型之前如何对数据进行预处理。实际上,我们按照特定的顺序应用一系列步骤来构建完整的模型。Python Scikit-learn 机器学习库中提供了所有必要的工具。
先决条件
如果你不熟悉 Python、numpy、pandas、机器学习和 Scikit-learn,请阅读我以前的文章,这些是本文的先决条件。
- 使用 Scikit-learn 进行主成分分析(PCA)
- 带梯度下降的线性回归
- 数据科学的数字:第一部分
- 数据科学的熊猫:第一部分
不再拖延,让我们进入问题定义。
问题定义
我们有一个数据集,其中包含 71 人的年龄、身高和体重信息。我们希望建立一个回归模型,根据年龄和身高捕捉一个人的体重,并评估其性能。然后我们用这个模型来预测新病例。
事实上,在我们绘制数据之前,我们不知道数据的性质或复杂性。有时候,我们可以很容易地拟合出一条直线来描述模型。但大多数时候,现实世界的数据并非如此。数据可能很复杂,您需要考虑不同的方法来解决问题。
数据集
我们有一个名为person _ data . CSV(在此下载)的数据集,其中包含 71 个人的年龄、身高和体重信息。让我们使用 pandasread _ CSV()函数加载它,并将其存储在 df 变量中。
让我们检查一下数据是否有缺失值。
太好了!这 3 列的所有值都有 71 个非空值,这意味着没有缺失值。
让我们定义我们的特征矩阵和目标向量。根据问题定义,特征矩阵— X 包含年龄和身高的值。目标向量— y 包含权重值。构建回归模型是一项监督学习任务,因此我们将输入 X 映射到输出 y=f(X) 。
我们数据的维数是 2,因为 X 是二维的。那么,我们如何用 y 绘制出 X 的二维数据呢?显然,我们需要创建一个 3D 图。但是还有另一种方法。我们可以将年龄和身高组合成一个变量,称为 Z ,然后用 Z 和 y 绘制 2D 图。通过减少 X 中的特征数量将年龄和身高组合成一个变量,称为降维,我们用来执行降维的技术是利用这两个变量相关性的【PCA】。
我们在建立模型之前执行降维有两个优点:
- 这对于在 2D 图中可视化我们的数据是非常有用的,这样可以更容易地看到重要的模式
- 去除特征矩阵 X 中的相关变量极其有用。这样做可以避免误导性的预测
让我们检查年龄和身高是否相关。
**
这两个特征似乎高度相关。自变量(特征矩阵中的变量 X )之间存在显著相关性或关联性的情况称为。多重共线性会导致误导性预测。**
在制作模型之前,我们的下一个任务是移除这些相关变量。正如我前面所说的,我们使用主成分分析(PCA)来做这件事。但是,在运行 PCA 之前,如果数据集的要素之间的比例存在显著差异,则有必要执行要素缩放。这是因为 PCA 对原始特征的相对范围非常敏感。因此,我们通过使用 Scikit-learn 中预处理子模块中的 Scikit-learnstandard scaler()类,应用 z 分数标准化 以将所有特征纳入相同的尺度。
****注意:我们仅对特征矩阵 X 应用特征缩放。我们不需要将它应用于我们的目标向量 y 。
因此,构建我们的模型的工作流程如下。它包含一系列应该按照给定顺序应用的步骤。建立一个机器学习模型不是一次性的任务,你可能会回到前面的步骤并做一些修改,然后你会再次经历接下来的步骤。
一般的工作流程是:
- 对特征矩阵 X 应用特征缩放[使用 Scikit-learnstandard scaler()class]。
- 运行 PCA 算法[使用 Scikit-learnPCA()class]。
- 创建散点图并确定关系的性质[使用 Seaborn 散点图()函数]。
- 我们可以用直线拟合数据吗?还是需要添加多项式要素来精确拟合模型?
- 如果我们可以对我们的数据拟合一条直线,然后运行线性回归算法[使用 Scikit-learnLinear Regression()class]
- 如果我们不能用直线拟合我们的数据,那么我们需要添加多项式特性[使用 Scikit-learnpolynomial features()class]
- 添加多项式特性后,运行线性回归算法[使用 Scikit-learnLinear Regression()类]
作者图片
应用要素缩放
我们通过使用 Scikit-learnstandard scaler()应用 z-score 标准化 将所有特征纳入同一尺度。所有特征都根据以下公式进行缩放。
****
X 的缩放值存储在 X_scaled 变量中,该变量是一个二维 numpy 数组。
让我们检查缩放后的 X 值的平均值和标准偏差。
现在,您可以看到在 X_scaled 矩阵中,每个变量的均值为零,标准差为 1。
现在,我们的数据可以运行 PCA 了。
运行 PCA 算法
现在,我们准备对数据集应用 PCA。我们需要将 X_scaled 矩阵中的二维数据缩减为一维数据。
在 Scikit-learn 中,使用 PCA() 类来应用 PCA。该类中最重要的超参数是 n_components 。由于我们对获取一维数据感兴趣,所以 n_components 的值为 1。
我们对 X_scaled 值应用了 PCA,输出值存储在 X_pca 变量中,该变量现在是一维数组。
我们降低了数据的维度,与原始数据集相比,也损失了一些信息。在 PCA 中,算法找到数据的低维表示,同时尽可能多地保留变化。
让我们检查算法在运行时保留了多少变化。
哇!超值!可以看到,第一个主成分保留了数据集中约 97.36%的可变性,同时减少了数据集中的 1(2–1)个特征。所以 X_pca 的值更准确地表示特征矩阵 X 的值。
让我们把我们的数据绘制成散点图。
绘制数据
现在我们有了一维数据( X_pca ),分别代表 X 。现在我们可以用我们在 2D 图中的 y (权重)值绘制 X_pca 。
****
很明显,一条直线永远不会完全符合这些数据。让我们看看,如果我们试图用一条直线来拟合我们的数据,会发生什么。
其中 θ 1 和 𝛼 是在训练过程中学习的模型参数。
****
拟合如此之差,以至于直线法永远不会为我们的数据提供最佳模型。
我们的模型只能解释或捕捉到约 61%的重量变化。RMSE 值为 10.99。这意味着平均而言,模型的预测值与实际值相差 10.99 个单位。
让我们尝试一种称为 多项式回归 的不同方法,以获得最适合我们的数据。
多项式回归
您可以使用线性模型来拟合非线性数据。一种简单的方法是将每个特征的幂作为新特征添加,然后在这个扩展的特征集上训练线性模型。这种技术叫做 多项式回归 。
因此,使用多项式的多项式回归在参数方面仍然是线性的。这是因为你只需将各项相加就能建立方程。因此,像 R 平方(R 决定系数)这样的性能指标对于多项式回归仍然有效。不要混淆多项式回归和非线性回归,其中 R 是无效的!
为每个变量添加幂
在我们的模型中,唯一的变量是T5 X _ PCAT7。为该变量增加幂后,模型变为:****
其中 θ 1 , θ 2 , θ 3 和 𝛼 是在训练过程中学习的模型参数。
让我们使用 Scikit-learnpolynomial features()类将多项式特征添加到我们的数据中。
多项式 Features() 类中最重要的超参数是 次 。我们设置 degree=4 ,这样当输入(x _ PCA, X_pca , X_pca⁴ )是一维时,它创建了 3 个额外的特征,称为x _ PCA。 X_poly 变量保存特征的所有值。****
运行算法
现在,我们已经将数据转换为多项式特征。所以,我们可以再次使用 LinearRegression() 类来构建模型。
**
哇!似乎多项式方法给了我们一个更好的模型。
我们的模型解释或捕获了重量中观察到的约 90%的可变性。RMSE 值为 5.526。这意味着平均而言,模型的预测值与实际值相差 5.526 个单位。
因此,我们通过多项式回归显著提高了模型的性能。
让我们检查残差(误差)的分布。
**
通过查看直方图,我们可以验证残差近似正态分布,平均值为 0。
超参数调谐
模型参数与超参数
模型参数是在训练过程中学习的参数。我们不手动设置参数值,它们从我们提供的数据中学习。比如 θ 1 , θ 2 , θ 3 和 𝛼 都是我们多项式回归模型中的参数。
相反,模型超参数是不从数据中学习的参数。因此,我们必须手动为它们设置值。我们总是在创建特定模型时和开始训练过程之前设置模型超参数的值。例如,在从 PCA() 类创建 pca 对象时,我们已经手动设置了 n_components= 1。我们还在从 PolynomialFeatures() 类创建poly _ features对象时手动设置了 degree=4 。
在大多数情况下,为模型超参数设置正确的值是最具挑战性的任务之一。这背后没有什么神奇的公式。您可以尝试不同的值,并获得可视化表示来验证您的选择。有时,您可能会尝试不同的值,评估模型性能并选择最佳值。有时,问题的领域知识将帮助您推导出超参数的正确值。
让我们为超参数尝试一些不同的值(2–9)(最初,我将此设置为 degree=4 )并获得一些可视化表示和模型评估指标。**
作者图片
度数过高会导致 过拟合 。过拟合问题是指统计模型开始描述数据中的随机误差,而不是变量之间的关系。在过度拟合中,该模型非常适合训练数据,但无法对不在我们的数据集中的新输入数据进行归纳。
降低度数会导致 欠配合 。在欠拟合中,模型不能很好地拟合训练数据和新数据。
当我们设置 度 超参数的值时,我们应该总是尽量避免过拟合和欠拟合的情况
通过查看可视化表示和性能指标的值,我们可以确定 degree=4 或 degree=5 是 degree 超参数的理想值。
根据新数据做出预测
假设我们有 5 个新的观察值,我们想使用我们的模型预测权重。新的输入数据存储在二维的 X_new 数组中。第一列是年龄,第二列是身高。
新输入数据
当我们构建模型时,我们已经对原始数据进行了 3 次缩放和转换。因此,当我们使用我们的模型对新数据进行预测时,有必要使用相同的方法对新数据进行缩放和转换。所以,我们必须调用 fit_transform() 方法 3 次,然后调用 predict() 方法 1 次。所以,这对我们来说很烦人。为了克服这个问题,我们可以为我们的多项式回归模型建立一个机器学习管道。
构建机器学习管道
Scikit-learn 将机器学习算法称为估计器。有三种不同类型的估计器:分类器、回归器和变压器。分类器和回归器被称为预测器。
随着我们的分析和工作流变得越来越复杂,您可能需要在数据准备好用于受监督的机器学习模型之前对其进行多次转换。管道依次应用一系列转换器和最终预测器(分类器或回归器)。管道的中间步骤必须是“transformers”,即它们必须实现 fit( )和 transform() 方法。最终预测器只需要实现 fit() 方法。
在我们的工作流程中:
- StandardScaler() 是变压器。
- PCA() 是变压器。
- ****多项式特性()是变压器。
- LinearRegression() 是预测器。
因此,我们可以使用 Scikit-learnPipeline()类为我们的模型构建一个管道。它依次应用上面的变压器列表和最终预测值。这是代码。
通过使用管道,我们可以用更少的代码轻松构建复杂的模型!
让我们调用我们管道的 fit() 方法。
当调用 poly_reg_model.fit(X,y) 时,会发生以下过程:
- X_scaled = sc.fit_transform(X)
- X _ PCA = PCA . fit _ transform(X _ scaled)
- X _ poly = poly _ features . fit _ transform(X _ PCA)
- lin_reg.fit(X_poly,y)
让我们调用我们管道的 predict() 方法。
当调用poly _ reg _ model . predict(X _ new)时,发生以下过程:
- X_new_scaled = sc.transform(X)
- X _ new _ PCA = PCA . transform(X _ scaled)
- X _ new _ poly = poly _ features . transform(X _ PCA)
- lin_reg.predict(X_new_poly)
所以,poly _ reg _ model . predict(X _ new)返回对我们新数据的预测。
保存我们的模型
让我们用 Python dill 包保存我们的模型。
运行完这段代码后,poly _ reg _ model . dill(此处下载)文件会出现在你当前的工作目录下。
让我们加载我们的模型。
就是这样。您可以与他人共享poly _ reg _ model . dill文件,他们可以使用该模型而无需重新构建。它在内存中只有 743 字节!
本教程由 鲁克山·普拉莫迪塔数据科学 365 博客作者设计创作。
本教程中使用的技术
- Python (高级编程语言)
- numPy (数值 Python 库)
- 熊猫 (Python 数据分析与操纵库)
- matplotlib (Python 数据可视化库)
- seaborn (Python 高级数据可视化库)
- Scikit-learn (Python 机器学习库)
- Jupyter 笔记本(集成开发环境)
本教程中使用的机器学习
- 主成分分析
- 多项式回归
2020–10–12
用 Scikit 学习多项式回归:你应该知道什么
原文:https://towardsdatascience.com/polynomial-regression-with-scikit-learn-what-you-should-know-bed9d3296f2?source=collection_archive---------2-----------------------
一个奇怪的结果让我更好的理解了多项式回归…
多项式回归的一个简单例子
多项式回归是一种众所周知的算法。这是线性回归的一个特例,因为我们在创建线性回归之前创建了一些多项式特征。或者可以认为是具有 特征空间映射 (又名多项式核)的线性回归。使用这个内核技巧,在某种程度上,可以创建一个次数无限的多项式回归!
在本文中,我们将处理经典的多项式回归。通过 scikit learn,可以结合这两个步骤在流水线中创建一个(多项式特性和线性回归)。我将展示下面的代码。让我们看一个例子,一些简单的玩具数据,只有 10 分。我们也考虑一下度数是 9。你可以在下面看到最终的结果。
你看出什么不对了吗?
嗯,理论上,这是错误的!对于 10 个点,一个 9 次多项式应该可以完美拟合!
或者,我确信你们中的一些人在想:为什么你说这是错的?这可能是正确的模式。你认为模型应该是完美拟合的,但不是,你被多项式插值搞糊涂了!
首先,您可以自己尝试使用下面的代码来创建模型。
创建一些玩具数据
import pandas as pdxdic={'X': {11: 300, 12: 170, 13: 288, 14: 360, 15: 319, 16: 330, 17: 520, 18: 345, 19: 399, 20: 479}}ydic={'y': {11: 305000, 12: 270000, 13: 360000, 14: 370000, 15: 379000, 16: 405000, 17: 407500, 18: 450000, 19: 450000, 20: 485000}}X=pd.DataFrame.from_dict(xdic)y=pd.DataFrame.from_dict(ydic)import numpy as npX_seq = np.linspace(X.min(),X.max(),300).reshape(-1,1)
创建模型
from sklearn.preprocessing import PolynomialFeaturesfrom sklearn.pipeline import make_pipelinefrom sklearn.linear_model import LinearRegressiondegree=9polyreg=make_pipeline(PolynomialFeatures(degree),LinearRegression())polyreg.fit(X,y)
创造情节
import matplotlib.pyplot as pltplt.figure()plt.scatter(X,y)plt.plot(X_seq,polyreg.predict(X_seq),color="black")plt.title("Polynomial regression with degree "+str(degree))plt.show()
你不应该这样做!
先说多项式回归和多项式插值的区别。先说一个我从 scikit learn 团队得到的答案:你不应该这样做,展开到 9 次多项式是扯淡。scikit learn 是为实际用例构建的,它使用有限精度的表示,而不是理论表示。
是的,他们完全正确!看看这些数字,它们有多大:1e24!
但是如果他们不能处理大数字,他们不应该抛出一个错误或警告吗?如果没有任何信息,人们会认为这个模型是正确的,然而,它实际上是错误的。
好吧好吧,我知道,你们中的一些人不相信结果是错误的,或者也许是不可能处理大的数字,让我们看看另一个包,numpy!
但是 polyfit 做得很好
对于同一个示例,numpy 的 polyfit 找到模型没有问题。你可以看到下面的情节和代码。
coefs = np.polyfit(X.values.flatten(), y.values.flatten(), 9)plt.figure()plt.plot(X_seq, np.polyval(coefs, X_seq), color="black")plt.title("Polyfit degree "+str(degree))plt.scatter(X,y)plt.show()
现在我知道你们中的一些人在想: polyfit 是一个非常不同的东西,它是一个插值而不是回归。
因为在四处打听的时候,我得到了一些这样的答案(但并不准确,或者说是错误的):
polyfit 正在做一件完全不同的事情。它对某个向量 X 到向量 y 执行单变量多项式拟合。这里,我们对某个特征空间 X 执行多项式展开,以便为多变量拟合表示高阶交互项(相当于用多项式核学习)。
好了,什么是多项式插值?
什么是多项式插值?
嗯,对于这种问题,维基百科是一个很好的来源。
在数值分析中,多项式插值是通过穿过数据集点的最低可能次数的多项式对给定数据集的插值。
并且我们有这样的结果被证明:给定 n+1 个不同的点 x_0,x_0,…,x_n 和相应的值 y_0,y_1,…,y_n,存在一个至多 n 次的唯一多项式来插值数据(x_0,y_0),…,(x_n,y_n)。
回到我们的例子:有 10 个点,我们试图找到一个 9 次多项式。所以从技术上讲,我们是在做多项式插值。而 polyfit 找到了这个唯一的多项式!对于 scikit learn 的多项式回归管道,情况并非如此!
这正是为什么你们中的一些人会想: polyfit 不同于 scikit learn 的多项式回归管道!
现在,等等!
在 polyfit 中,有一个自变量,叫做度。所以可以修改度数,我们用 5 试试。
是的,用polyfit
,可以选择多项式的次数,我们正在用它做多项式回归。而用户选择的 9 次是多项式插值的特例。
这是令人放心的,因为线性回归试图最小化平方误差。而且我们知道,如果有 10 个点,我们试着求一个 9 次多项式,那么误差可以是 0(不能再低了!)因为多项式插值的定理。
对于那些还在怀疑的人,polyfit 有一个官方文档:最小二乘多项式拟合。将一个度的多项式p(x) = p[0] * x**deg + ... + p[deg]
拟合到点 (x,y) 。按照度、度-1 、… 0 的顺序返回最小化平方误差的系数矢量 p 。
好了,是时候回到我们的 scikit learn 的多项式回归管道了。那么现在,为什么会有区别呢?真的有两种不同的多项式回归(或拟合),都使用最小二乘法,但使用方式不同吗?
我找到了这个答案,但我还没有得到它。
两个模型都使用最小二乘法,但是使用这些最小二乘法的方程是完全不同的。polyfit 将其应用于 vandemonde 矩阵,而线性回归则不能。
特征比例效应
在深入研究的同时,应该提到另一个重要的特性转换:特性缩放。
在几本关于机器学习的书中,当执行多项式回归时,特征被缩放。也许从一开始,你们中的一些人就在说应该这样做。
而且没错, scikit learn 的多项式回归管道带特征缩放,好像相当于 polyfit!根据剧情(我没有真的去查,但是目测他们是一样的)。
您可以使用下面的代码:
from sklearn.preprocessing import PolynomialFeaturesfrom sklearn.pipeline import make_pipelinefrom sklearn.linear_model import LinearRegressionfrom sklearn import preprocessingscaler = preprocessing.StandardScaler()degree=9polyreg_scaled=make_pipeline(PolynomialFeatures(degree),scaler,LinearRegression())polyreg_scaled.fit(X,y)
现在,我们没有回答之前的问题,我们有更多的问题:特征缩放对线性回归有影响吗?
答案是否定的。
为了讨论这一点,可以写另一篇文章,对于我们关于多项式回归效果的讨论,我们可以只做另一个变换。
X=pd.DataFrame.from_dict(xdic)/1000
没错,你只是把预测值除以 1000。现在,你知道对线性回归模型的影响只是成比例的,但实际上,差别是巨大的。
这就是为什么我们可以得出结论,对于 scikit learn 来说,初始数字太大了。
结论
最后我们可以说 scikit learn 的多项式回归管道(有无缩放),应该和 numpy 的 polyfit 是等价的,只是在大数处理方面的区别可以产生不同的结果。
我个人认为,在这种情况下,scikit learn 应该抛出一个错误或至少一个警告。
我真的很想知道你的意见!
如果你想了解更多关于多项式回归与其他监督学习算法的关系,你可以阅读这篇文章:
[## 监督机器学习算法综述
大图如何通过连接点给我们洞察力和对 ML 的更好理解
towardsdatascience.com](/overview-of-supervised-machine-learning-algorithms-a5107d036296)
你会看到多项式回归是一种特殊的特征空间映射。
Pomodoro 命令行定时器
原文:https://towardsdatascience.com/pomodoro-command-line-timer-439b1b07161f?source=collection_archive---------35-----------------------
@carlheyerdahl Unsplash
用 python 提高生产力
在本文中,您将了解到
- 番茄工作法
- 如何使用 python 对番茄工作法建模
- 如何在命令行中创建动态计时器
- 如何用 python 播放声音
番茄工作法简介
番茄工作法是用来把工作分成几个间隔,中间有短暂的休息。它是由弗朗西斯科·西里洛在 20 世纪 80 年代末创建的,在过去的 40 年里,它已经为那些想要提高连续几个小时有效学习而不感到明显疲劳的能力的人取得了巨大的成功。
这项技术的关键是间隔时间不要太长,以免疲劳,但也不要太短,以便进行深度工作。传统上,工作间隔是 25 分钟,之后有 5 分钟的休息时间。这些间隔和休息循环进行,直到任务完成。
这项技术的目的是减轻对成为的焦虑,提高你的注意力,改善你的工作/学习过程。
欲了解更多信息,请参见弗朗西斯科的文件。
在这篇文章中,我们将使用 python 实现一个番茄定时器。我们不需要上发条或者重置计时器。我们可以改变时间间隔来适应我们个人的需要。我们开始吧!
规划阶段
让我们获取关于技术信息,并开始计划我们想要创建的程序。
这是我们需要的:
- 倒计时的计时器
- 优选地,定时器应该是动态的。也就是说,它在屏幕上变化,而不是程序在倒计时的每一秒钟打印新的行
- 播放声音的能力,以适应学习时间和休息时间,所以我们知道什么时候回去学习
- 能够指定我们打算进行的研究时间间隔、休息时间和番茄工作法的次数。
进口货
import time
import sysfrom playsound import playsound
让我们一次分解一个。
时间模块是一个内置的 python 模块,具有与时间相关的功能,我们将使用它来暂停程序的执行。
sys 模块是 python 解释器的另一个内置 python 模块。在这种情况下,我们将使用它来创建计时器的动态部分,以不断更新命令行。
最后导入的是包播放声音。这是一个第三方模块,允许我们使用 python 来指导播放我们选择的特定声音文件。
现在,我们对将要使用的模块有了全面的了解,并且我们知道开始分解代码需要什么。
指定学习和休息的时间间隔
大多数程序的开始是初始化变量。这没有什么不同,第一步是指定我们希望程序运行的间隔、休息和总时间的长度。Python 有 input 函数,它允许我们将用户输入存储到变量中。
interval = int(input('Please Enter duration (mins) of interval: '))break_duration = int(input('Please Enter break duration(mins) of interval: '))total_duration = int(input('Please enter number of sessions: '))
笔记
- 我们指定了
interval
、break_duration
、total_duration
- 使用
int()
我们将用户输入转换成一个数字
计时器
我们希望能够使用 python 指定倒计时分钟和秒。我们可以很容易地使用 for 循环倒数秒。但是分分秒秒都倒计时呢?为此,我们需要一个嵌套的 For 循环。
一个很好的类比是时钟。钟的秒针每分钟移动 60 次。每走 60 步,分针就换一次。这正是嵌套 for 循环所做的。对于外部循环的每一次迭代,内部循环完全迭代。让我们看看这在代码中是什么样子的。
interval = 5
for i in range(interval,-1,-1): for j in range(59,-1,-1):
time.sleep(1)
笔记
- 出于说明的目的,我们指定 5 分钟的研究间隔。
内部循环:
2.内部循环我们使用range
函数从 60 秒向下迭代到 0 秒。
3.range(59,-1,-1)
第一个(start)参数从 59 开始,但令人困惑的是第二个(stop)参数是上限,在这种情况下是-1,它不包括这个数字,因此 I 停止在 0。最后一个参数叫做步长参数,我们希望 59 减少 1,因此是-1。这都意味着i
从 59 倒数到 0。
4.该函数暂停执行一秒钟。在下一次 for 循环迭代之前。
外部循环:
5.对于一个几秒钟的完整循环,我们指定我们的外部循环range(interval,-1,-1)
这里我们取我们指定的间隔,因此迭代将从 5 开始到我们想要的 0 结束。
这段代码将倒数每分钟的秒数,从 5 分钟开始倒数到 0。厉害!现在让我们让它出现在终端输出上,每秒都在变化。
@veri_ivanova Unsplash
使计时器动态化
到目前为止,我们已经讨论了嵌套循环来倒计时秒和分钟。但是我们还没有在命令行中显示这些,在这里我们可以利用 python 的内置模块让我们的计时器在屏幕上倒计时。但重要的是,我们指定我们不希望为每秒钟的倒计时创建一个新行,我们希望终端输出出现在同一行上,并且每秒钟都发生变化。
为此,我们使用了sys.stdout.write
函数。这将打印出一个终端输出,但与 print 函数不同,我们可以清除输出,而不用换到新的一行。
让我们修改上面的代码来做到这一点
for i in range(interval,-1,-1):
for i in range(59,-1,-1):
sys.stdout.write(f'\rDuration: Minutes {j} Seconds {i} to go')
time.sleep(1)
sys.stdout.flush()
笔记
- 我们有和以前一样的嵌套 for 循环,但是做了一些修改
sys.stdout.write()
功能是在终端屏幕上打印信息的另一种方式,但有所不同。与打印功能不同,我们可以在屏幕上更改信息,而无需另起一行。这是我们计划的关键!- 我们使用 f 字符串打印出一个字符串,但是 f 字符串允许我们根据
i
和j
的值改变字符串。 - 注意在我们的写函数中,
\r
。这是一个转义字符,用于将输出重置到行首。这对于保持我们在终端行的相同部分输出的字符串是必要的,这是我们如何使我们的定时器动态的一部分。字符串中唯一改变的部分是 I 和 j 的值,它们对应于我们的分和秒。 sys.stdout.flush()
清除之前打印的行,准备打印另一个报表。这意味着我们可以动态地改变计时器,对于屏幕上的每一秒钟,只要一秒钟的时间过去,我们就刷新它。
我们做到了!我们现在有一种方法来创建每秒钟动态变化的命令行计时器。
Python 和声音文件
Python 有很多播放声音的模块。最简单的一个是名为playsound
的第三方模块。使用playsound
功能允许我们指定要播放的文件。
playsound(r'c:\windows\media\alarm02.wav')
笔记
- 我们正在播放一个标准的 Windows 声音文件。注意,我们使用的是被称为原始字符串的
r
,因为我们希望将\
包含在字符串中。通常\
不会包含在字符串输出中,因为它被称为转义字符,可以用于在字符串中打印换行符,例如\n
。
@feelfarbig Unsplash
设置程序
在编写脚本时,如果合适的话,从函数或类的角度来考虑是一个好习惯。我们几乎拥有了创建这个脚本的所有部分。但是我们需要协调所有我们想要添加的潜在功能和声音。
让我们一次创建一个函数。如果你对函数不熟悉,可以在这里看到这篇详细的文章。
用于设置时间的功能
def user_input():
interval = int(input('Please Enter duration (mins) of interval: ')) break_duration = int(input('Please Enter break duration(mins) of interval: ')) total_duration = int(input('Please enter number of sessions: '))
return interval, duration, break_session
这里我们设置了制作番茄定时器的用户输入。我们已经看到了更简单格式的代码。
倒计时定时器
def countdown(interval):
for i in range(interval,-1,-1):
for j in range(59,-1,-1):
sys.stdout.write(f'\rDuration: \
Minutes {j} Seconds {i} to go')
time.sleep(1)
sys.stdout.flush()
这是我们在上一节中看到的代码,但是不同之处在于我们封装到了一个函数中!
设置
这个脚本的最后一部分是协调这些功能。我们想设置一种方法来打印我们当前正在进行的会话以及何时停止。所以设置这些,并使用 while 循环继续运行,直到满足一个条件,这就是我们如何保持计时器连续运行。
if __name__ == "__main__": session_count = 0 interval, total_duration, break_duration = user_input() while session_count < total_duration: playsound(r'c:\windows\media\alarm02.wav') countdown(interval) playsound(r'c:\windows\media\alarm02.wav') print('\nBreak time!') countdown(break_duration) session_count += 1 print('\nsession number: ',session_count) print('\nEnd of Session!')
笔记
- 如果你不熟悉
if __name__ = "__main__"
,请看这里的。这是维护代码只在这个脚本中运行的一种方式。 - 我们设置了
session_count
的初始值,它将在 while 循环的每次迭代中改变 - 我们允许用户定义间隔的长度,休息时间以及我们想要做多少番茄大战
- 我们在间隔开始和结束时播放声音
- 然后我们在 while 循环的每一次迭代中把
session_count
加 1。+=
是session_count + 1
的简写,它被称为增广算子。然后我们打印session_count
,这样我们就可以看到我们正在进行哪个会话。 - 当会话计数大于持续时间时,while 循环完成,我们打印会话已经结束。
轻微修改
在测试这个脚本时,当倒计时从 10 秒切换到 9 秒时,终端中出现的文本有一个小问题。
10 秒钟后,终端输出如下所示
Duration: Minute 1 Seconds 10 to go
在 9 秒钟时,终端输出如下所示
Duration: Minute 1 seconds 9 seconds to goo
这是因为我们在同一行上不断刷新终端输出。但是屏幕上的字符数变了。下到 9 秒就少了一个字符。因此,尽管大部分字符会刷新,但 10 秒后输出的最后一个字符(在本例中为“0”)会保留在终端输出中。
为了解决这个问题,我们必须稍微改变计时器,当计时器倒数到 9 秒或更少时。
def countdown(interval):
for j in range(interval-1,-1,-1):
for i in range(59,-1,-1):
if i <= 9:
sys.stdout.write \
(f'\rDuration: Minutes {j} Seconds 0{i} to go') else:
sys.stdout.write \
(f'\rDuration: Minutes {j} Seconds {i} to go')
time.sleep(1)
sys.stdout.flush()
我们包含了一个 if 语句,当 I 小于或等于 9 时,我们将秒计数的终端输出从 9 秒改为 09 秒。对于每次循环迭代,终端输出的字符数与倒数 10 秒时的终端输出的字符数相同。
完整代码请见这里
摘要
我们已经用 python 创建了一个自动化的生产力黑客!我们已经学习了如何在终端中创建一个动态计时器,以及如何在编码之前开始考虑构建脚本。
希望,这将有助于你的学习,并保持你在使用番茄工作法的轨道上!
其他文章
[## 学习 Python 的方法
今天如何最大限度地学习 python
towardsdatascience.com](/approach-to-learning-python-f1c9a02024f8) [## 如何从脚本运行 Scrapy
忘记 scrapy 的框架,全部用使用 scrapy 的 python 脚本编写
towardsdatascience.com](/how-to-run-scrapy-from-a-script-ff07fd6b792b) [## 使用 Scrapy 进行有效的网页抓取
Scrapy 的新功能使您的刮削效率
towardsdatascience.com](/efficient-web-scraping-with-scrapy-571694d52a6)
关于作者
我是一名执业医师和教育家,也是一名网站开发者。
请点击此处查看我的博客和其他帖子中关于项目的更多细节。更多技术/编码相关内容,请点击这里订阅我的时事通讯
我将非常感谢任何评论,或者如果你想与 python 合作或需要帮助,请联系我。如果你想和我联系,请在这里或者在推特上联系我。
Python 中的池限制队列处理
原文:https://towardsdatascience.com/pool-limited-queue-processing-in-python-2d02555b57dc?source=collection_archive---------6-----------------------
如何使用预定义数量的线程并行处理数据
我最近遇到了一个问题:我需要构建大量(大约 100 个)Docker 容器,然后将它们推送到注册中心。Docker SDK for Python 提供了一个很好的处理方法,再加上“多重处理”库,可以非常有效地并行处理任务。然而,经过一些初步测试后,我发现将多个图像推送到注册表可能由于同时上传的过载而停止。在我的测试中,我只能同时运行 2-3 个docker push
命令,直到我添加的所有新命令都停止。在这一点上,我决定将同步上传限制在少量的并行线程上,同时仍然利用大量的线程来促进映像构建。将工作从构建线程传递到推进线程的队列(multiprocessing.Queue
)和线程池(multiprocessing.Pool
)的组合看起来是一个最佳选择。然而,文档中有一些细微差别和空白,这让我花了一些时间去理解(尤其是在 Windows 上使用multiprocessing
的时候)。下面,我提供了一个关于如何使用这些数据结构和对象的小教程。
问题公式化
算法设计
在这个玩具问题中,我们有大量并行进程将结果写入队列。除了它们之外,还有一个单线程读取器进程检查队列中的新项目,并将它们分配给池中的新进程,这样,只有一小部分固定数量的进程同时运行。让我们看一下下面的所有元素。
Process
弗兰克·麦肯纳在 Unsplash 上拍摄的照片
对于左侧的大量并行线程,我们将使用multithreading.Process()
。来自官方参考:
Process
对象表示在独立进程中运行的活动。
启动一个进程需要两件事:调用目标函数和**Process**
调用本身。让我们来看看:
from multiprocessing import Processdef proc(i):
print(f'I am Process {i}')if __name__ == '__main__':
for i in range(10):
Process(target=proc, args=(i,)).start()
在上面的例子中,我们创建了 10 个Process
es 并同时启动它们。每个进程都运行一个proc()
函数的实例,其参数来自arg
。因为执行的顺序没有得到保证,所以当我们运行它时,我们会得到类似这样的结果:
I am Process 6
I am Process 2
I am Process 0
I am Process 3
I am Process 7
I am Process 4
I am Process 8
I am Process 1
I am Process 5
I am Process 9
还要注意args=(i,)
有趣的语法。Process
要求args
是可迭代的,所以把它改成args=(i)
或者args=i
就会产生一个TypeError
。
长队
照片由哈尔·盖特伍德在 Unsplash 上拍摄
现在,是时候介绍一个multithreading.Queue()
了。根据参考:
Queue()
返回一个使用管道和一些锁/信号量实现的进程共享队列。
队列允许我们将对象放入队列,并在别处异步处理它们。重要的是,队列是线程和进程安全的。让我们修改前面的例子,添加Queue
对象,并将其传递给我们的并行Process
es:
from multiprocessing import Process, Queuedef writer(i,q):
message = f'I am Process {i}'
q.put(message)if __name__ == '__main__':
# Create multiprocessing queue
q = Queue()
# Create a group of parallel writers and start them
for i in range(10):
Process(target=writer, args=(i,q,)).start() # Read the queue sequentially
for i in range(10):
message = q.get()
print(message)
记住Queue.get()
是一个阻塞方法,所以我们不会错过队列中的任何消息。
解决我们问题的下一步是切换到从队列中并行读取。我们可以像产生写进程一样产生读进程,但是这将允许 10 个线程并行运行。如果像原问题描述中那样受限于较小的读者数量,该怎么办?
泳池
李中清在 Unsplash 上的照片
输入[multithreading.Pool()](https://docs.python.org/3.7/library/multiprocessing.html#multiprocessing.pool.Pool)
:
"一个进程池对象,它控制一个可以提交作业的工作进程池。它支持带有超时和回调的异步结果,并具有并行映射实现”。
使用Pool
,我们可以分配尽可能多的并行进程,但是在任何给定的时刻,只有“进程”数量的线程是活动的。
让我们看看,如果我们把所有的读者都扔到“池子”里,情况会怎样:
from multiprocessing import Process, Queue, Pooldef writer(i,q):
message = f’I am Process {i}’
q.put(message)def reader(i,q):
message = q.get()
print(message)if __name__ == ‘__main__’:
# Create multiprocessing queue
q = Queue() # Create a group of parallel writers and start them
for i in range(10):
Process(target=writer, args=(i,q,)).start() # Create multiprocessing pool
p = Pool(10) # Create a group of parallel readers and start them
# Number of readers is matching the number of writers
# However, the number of simultaneously running
# readers is constrained to the pool size
for i in range(10):
p.apply_async(reader, (i,q,))
然而,如果我们运行上面的代码,我们将不会得到任何输出。发生了什么事?当我们调用apply_async
时,代码执行立即继续,因为主函数中没有留下任何东西,所以退出。谢天谢地,multiprocessing
提供了一种等待执行结果的参考方式:
from multiprocessing import Process, Queue, Pooldef writer(i,q):
message = f’I am Process {i}’
q.put(message)def reader(i,q):
message = q.get()
print(message)if __name__ == ‘__main__’:
# Create multiprocessing queue
q = Queue() # Create a group of parallel writers and start them
for i in range(10):
Process(target=writer, args=(i,q,)).start() # Create multiprocessing pool
p = Pool(10) # Create a group of parallel readers and start them
# Number of readers is matching the number of writers
# However, the number of simultaneously running
# readers is constrained to the pool size readers = []
for i in range(10):
readers.append(p.apply_async(reader, (i,q,))) # Wait for the asynchrounous reader threads to finish
[r.get() for r in readers]
这一次,如果我们运行代码,我们将得到下面的错误:RuntimeError: Queue objects should only be shared between processes through inheritance
。multiprocessing.Manager
将使我们能够管理队列,并使不同的工作人员也可以访问它:
from multiprocessing import Process, Queue, Pool, Managerdef writer(i,q):
message = f’I am Process {i}’
q.put(message)def reader(i,q):
message = q.get()
print(message)if __name__ == ‘__main__’:
# Create manager
m = Manager() # Create multiprocessing queue
q = m.Queue() # Create a group of parallel writers and start them
for i in range(10):
Process(target=writer, args=(i,q,)).start() # Create multiprocessing pool
p = Pool(10) # Create a group of parallel readers and start them
# Number of readers is matching the number of writers
# However, the number of simultaneously running
# readers is constrained to the pool size readers = []
for i in range(10):
readers.append(p.apply_async(reader, (i,q,))) # Wait for the asynchrounous reader threads to finish
[r.get() for r in readers]
最后,我们能够得到我们期望的结果:
> python pl.pyI am Process 1
I am Process 4
I am Process 9
I am Process 8
I am Process 0
I am Process 5
I am Process 7
I am Process 2
I am Process 6
I am Process 3
与 Windows 相关的怪癖
我最初在基于 Linux 的机器上着手解决这个问题,但后来在 Windows 上继续。不幸的是,许多事情并没有立即见效。以下是你需要知道的事情:
1.对于上面的代码,中断程序执行(Ctrl+C)不会立即生效。解决方法是添加初始化器工人:
def init_worker():
"""
Pool worker initializer for keyboard interrupt on Windows
""" signal.signal(signal.SIGINT, signal.SIG_IGN)p = Pool(num_readers, init_worker)
2.我无法在 Windows 上运行 Jupyter 笔记本中的代码,除非我将工人函数移动到单独的.py
文件中,并将它们导入我的笔记本。与此相关,如果不将主代码打包到if __name__ == ‘main':
中,您将无法运行上面的脚本。
决赛成绩
作为收尾工作,让我们添加以下内容:
延迟以模拟读取器和写入器上 CPU 受限的工作
等待读取线程完成时的异常处理
可配置的写入器和读取线程数量
一些函数文档
以下是最终结果:
from multiprocessing import Pool, Queue, Process, Manager
import random
import signal
import timenum_writers = 10
num_readers = 3def writer(i,q):
# Imitate CPU-bound work happening in writer
delay = random.randint(1,10)
time.sleep(delay)
# Put the result into the queue
t = time.time()
print(f’I am writer {i}: {t}’)
q.put(t)def init_worker():
"""
Pool worker initializer for keyboard interrupt on Windows
"""
signal.signal(signal.SIGINT, signal.SIG_IGN)def reader(i, q):
"""
Queue reader worker
"""
# Read the top message from the queue
message = q.get()
# Imitate CPU-bound work happening in reader
time.sleep(3)
print(f’I am reader {i}: {message}’)if __name__ == ‘__main__’:
# Create manager
m = Manager()
# Create multiprocessing queue
q = m.Queue() # Create a group of parallel writers and start them
for i in range(num_writers):
Process(target=writer, args=(i,q,)).start()
# Create multiprocessing pool
p = Pool(num_readers, init_worker) # Create a group of parallel readers and start them
# Number of readers is matching the number of writers
# However, the number of simultaneously running
# readers is constrained to the pool size
readers = []
for i in range(10):
readers.append(p.apply_async(reader, (i,q,)))
# Wait for the asynchrounous reader threads to finish
try:
[r.get() for r in readers]
except:
print(‘Interrupted’)
p.terminate()
p.join()
如果您运行它,您将得到类似如下的结果:
python final.pyI am writer 8: 1580659076.783544
I am writer 3: 1580659076.783544
I am reader 0: 1580659076.783544
I am reader 1: 1580659076.783544
I am writer 7: 1580659079.7990372
I am writer 2: 1580659080.7971141
I am writer 1: 1580659081.785277
I am writer 4: 1580659082.7955923
I am reader 2: 1580659079.7990372
I am reader 3: 1580659080.7971141
I am writer 6: 1580659083.800029
I am writer 0: 1580659084.7862694
I am reader 4: 1580659081.785277
I am writer 9: 1580659085.7819643
I am writer 5: 1580659085.7919443
I am reader 5: 1580659082.7955923
I am reader 6: 1580659083.800029
I am reader 7: 1580659084.7862694
I am reader 8: 1580659085.7819643
I am reader 9: 1580659085.7919443
这篇文章最初发表在[我的博客](https://taletskiy.com/posts/python-pool-limited-queue-processing/)上。
# 爆米花数据——分析电影院座位模式(上)
> 原文:<https://towardsdatascience.com/popcorn-data-analysing-cinema-seating-patterns-part-1-a0b2a5c2c19a?source=collection_archive---------44----------------------->
## 数据分析能揭示你的观影习惯的哪些方面?
诺埃尔·马修·艾萨克和[万什卡·阿格拉瓦尔](https://medium.com/u/19e9504cf53f?source=post_page-----a0b2a5c2c19a--------------------------------)
*在* [*第二部分*](https://medium.com/popcorndata/popcorn-data-analysing-cinema-seating-patterns-part-ii-987fbde9d363) *中,我们分析数据,将其可视化,然后为我们的发现建立一个网站。*

*作者图片*
# 第一部分——获取分析数据
## 发现你最喜欢的剧院座位已经被预订时,你有没有感到极度失望?
## 你最喜欢的座位到底有多受欢迎?
我们想更多地了解新加坡的电影趋势——人们喜欢从哪个座位观看不同的电影。所以我们创建了[PopcornData](https://popcorn-data.herokuapp.com/)——一个通过搜集数据、发现有趣的见解并将其可视化来一窥新加坡电影趋势的网站。

照片由 [Krists Luhaers](https://unsplash.com/@kristsll?utm_source=medium&utm_medium=referral) 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 拍摄
在网站上,你可以看到人们如何在不同的大厅、剧院和时间观看不同的电影!一些独特的方面包括**热图**显示**最受欢迎的座位**和**动画**显示购买座位的顺序**。这两篇文章详细阐述了我们是如何获得网站数据的,以及我们对数据的分析。**
# **抓取数据**
**为了实现我们的想法,第一步,也许是最关键的一步是收集数据。我们决定删除新加坡最大的连锁影院之一**邵氏影院**的网站。**
**从 python 中抓取的基础知识开始,我们最初尝试使用 python 的 **requests** 库来获取网站的 HTML,并使用 **BeautifulSoup** 库来解析它,但很快意识到我们需要的数据在我们请求的 HTML 中并不存在。这是因为网站是动态的— ***它使用 Javascript 从外部来源请求数据,并动态呈现 HTML***。当我们直接请求 HTML 时,网站的动态部分没有被呈现,因此丢失了数据。**
**为了解决这个问题,我们使用了**Selenium**——一种 web 浏览器自动化工具,它可以在获取 HTML 之前首先呈现网站的动态内容。**
## **硒的问题**
**让 selenium 驱动程序工作并解决一些小问题是一个很大的学习过程。在无数次 StackOverflow 搜索和多次“放弃”后,我们设法勉强通过(双关语)并让它工作。**
**我们面临的主要问题是:**
1. **滚动到屏幕的特定部分单击按钮,以便在 HTML 中找到数据。**
2. **弄清楚如何在云上运行 headless Selenium。**
3. **在 Heroku 上部署脚本后,当脚本在本地机器上正常运行时,一些数据没有被擦除。绞尽脑汁之后,我们发现 Selenium 加载的一些页面默认为移动版本的页面。我们通过明确提到屏幕尺寸来解决这个问题。**
*****有了 Selenium 和 BeautifulSoup,我们终于能够获得某一天所有可用电影会话的数据了!*****
## **电影会话数据示例:**
{
"theatre":"Nex",
"hall":"nex Hall 5",
"movie":"Jumanji: The Next Level",
"date":"18 Jan 2020",
"time":"1:00 PM+",
"session_code":"P00000000000000000200104"
}
**我们已经成功了一半!现在,我们需要收集每个电影时段的座位数据,以查看哪些座位被占用以及何时被购买。在开发者工具中浏览了网站的网络选项卡后,我们发现 Shaw 的 API 正在请求座位数据。**
**可以通过请求 URL*https://www.shaw.sg/api/SeatingStatuses?recordcode=<session _ code>*来获得数据,其中 session code 是我们之前已经搜集的每个电影会话的唯一代码。**
**我们得到的数据是 JSON 格式的,我们对其进行解析,并按照座位购买时间的升序对座位进行重新排序,以获得一个 JSON 对象数组,其中每个对象都包含关于电影厅中每个座位的信息,包括 seat_number、seat_buy_time 和 seat_status。**
## **样本座位数据:**
[
{
"seat_status":"AV",
"last_update_time":"2020-01-20 14:34:53.704117",
"seat_buy_time":"1900-01-01T00:00:00",
"seat_number":"I15",
"seat_sold_by":""
},
...,
{
"seat_status":"SO",
"last_update_time":"2020-01-20 14:34:53.705116",
"seat_buy_time":"2020-01-18T13:12:34.193",
"seat_number":"F6",
"seat_sold_by":""
}
]
* ****座位号**:大厅座位的唯一标识符**
* ****seat_status** :表示有座位可用(**SO**-座位已被占用,**AV**-可用)**
* ****seat_buy_time** :客户购买座位的时间**
* ****last_update_time:** 座位数据最后被删除的时间**
**大厅有 28 到 502 个座位,每个座位对应于数组中的一个 JSON 对象。此外,一天之内有超过 350 个电影时段,产生的数据量相当大。存储一天的数据大约需要 10MB。电影会话数据与座位数据相结合,并存储在 MongoDB 数据库中。**
****我们设法从肖那里收集了 2020 年 1 月的所有电影数据。****
## **数据库中的单个文档**
{
"theatre":"Nex",
"hall":"nex Hall 5",
"movie":"Jumanji: The Next Level",
"date":"18 Jan 2020",
"time":"1:00 PM+",
"session_code":"P00000000000000000200104"
"seats":[
{
"seat_status":"AV",
"last_update_time":"2020-01-20 14:34:53.704117",
"seat_buy_time":"1900-01-01T00:00:00",
"seat_number":"I15",
"seat_sold_by":""
},
...,
{
"seat_status":"SO",
"last_update_time":"2020-01-20 14:34:53.705116",
"seat_buy_time":"2020-01-18T13:12:34.193",
"seat_number":"F6",
"seat_sold_by":""
}
]
}
**要查看完整文档,请点击此链接:[https://gist . github . com/noelmathewisac/31 a9d 20 a 674 f 6 DD 8524 ed 89d 65183279](https://gist.github.com/noelmathewisaac/31a9d20a674f6dd8524ed89d65183279)**
**收集的完整原始数据可在此下载:**
**[## 原始电影数据. zip
drive.google.com](https://drive.google.com/file/d/1K7Vv88SnmWarf6rOre2ijA-Qq7Dv2sNp/view?usp=sharing)**
# **是时候把手弄脏了**
****
**由[马库斯·斯皮斯克](https://unsplash.com/@markusspiske?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄**
***现在是通过**清理数据**并提取相关信息来弄脏*我们的手的时候了。使用 pandas,我们解析了 JSON,清理了它,并用数据制作了一个 DataFrame,以提高可读性并方便过滤。**
**由于座位数据占用了大量内存,我们无法将所有数据包含在数据帧中。相反,我们使用 python 聚合座位数据,以获得以下内容:**
1. ****总座位数** : 电影时段的总座位数**
2. ****售出座位数**:一场电影的售出座位数**
3. ****座位购买顺序**:显示座位购买顺序的二维数组**
[['A_10', 'A_11'], ['A_12'], ['B_4', 'B_7', 'B_6', 'B_5'], ['C_8', 'C_10', 'C_9'], ['B_1', 'B_2'], ['C_6', 'C_7'], ['C_5', 'C_4'], ['B_8', 'B_10', 'B_9'], ['D_8'], ['A_15', 'A_14', 'A_13']]
**数组中的每个元素代表同时购买的座位,元素的顺序代表座位购买的顺序。**
**4.**座位分布**:显示一起购买的座位数量的字典(1、2、3 或更多组)**
{
'Groups of 1': 8,
'Groups of 2': 30,
'Groups of 3': 9,
'Groups of 4': 3,
'Groups of 5': 1
}
**5.座位频率:显示大厅中每个座位在一个月内被购买的次数的字典**
{'E_7': 4, 'E_6': 5, 'E_4': 11, 'E_5': 9, 'E_2': 2, 'E_1': 2, 'E_3': 7, 'D_7': 15, 'D_6': 17, 'C_1': 33, 'D_2': 15, 'D_1': 14, 'B_H2': 0, 'B_H1': 0, 'D_4': 45, 'D_5': 36, 'D_3': 32, 'C_3': 95, 'C_4': 94, 'A_2': 70, 'A_1': 70, 'B_2': 50, 'B_1': 47, 'C_2': 37, 'C_6': 53, 'C_5': 61, 'B_4': 35, 'B_3': 40}
**6.**购买率** : 两个字典,第一个字典显示电影放映的剩余时间(以天为单位),第二个字典显示相应的累积购票数。**
{“1917”: [4.1084606481481485..., 2.566423611111111, 2.245578703703704, 2.0319560185185184, 1.9269907407407407, 1.8979513888888888....],
...}
{“1917”: [1, 3, 8, 10, 11, ...],
...}
**可以在此处查看清理的数据:**
**[](https://docs.google.com/spreadsheets/d/1pLNbwfnrmfpyA7sxtRyB1P6iHuSFyUPEerwW7f3fEWU/edit?usp=sharing) [## 清理的电影数据
docs.google.com](https://docs.google.com/spreadsheets/d/1pLNbwfnrmfpyA7sxtRyB1P6iHuSFyUPEerwW7f3fEWU/edit?usp=sharing)**
# **最后,我们完成了!(完成 20%的工作)**
**我们的数据被收集和清理后,我们现在可以进入有趣的部分了— *分析数据*在爆米花垃圾中寻找模式。**
**要找到我们对数据的分析和我们发现的有趣模式,请查看本文的第二部分:**
**[](https://medium.com/popcorndata/popcorn-data-analysing-cinema-seating-patterns-part-ii-987fbde9d363) [## 爆米花数据——分析电影院座位模式(下)
### 数据分析能揭示你的观影习惯的哪些方面?
medium.com](https://medium.com/popcorndata/popcorn-data-analysing-cinema-seating-patterns-part-ii-987fbde9d363)**
**刮刀的代码可以在下面的 GitHub repo 中找到:**
**[](https://github.com/PopcornData/shaw-scraper) [## PopcornData/肖氏刮刀
### 在 GitHub 上创建一个帐户,为 PopcornData/shaw-scraper 的开发做出贡献。
github.com](https://github.com/PopcornData/shaw-scraper)
**别忘了查看我们的网站:http://popcorn-data.herokuapp.com**[](http://popcorn-data.herokuapp.com/)****!******
# Windows 上的 Poppler
> 原文:<https://towardsdatascience.com/poppler-on-windows-179af0e50150?source=collection_archive---------7----------------------->
## Python、pdf 和 Window 的 Linux 子系统

Windows 上的 Poppler
# 简介:
[可移植文档格式(pdf)](https://en.wikipedia.org/wiki/PDF)无处不在,导入一个流行的 python 包,如 [PDF2Image](https://pypi.org/project/pdf2image/) 、[pdf text](https://pypi.org/project/pdftotext/)或 [PopplerQt5](https://pypi.org/project/python-poppler-qt5/) 是处理它们的常用方法。不幸的是,除非您使用的是 Linux 机器,否则许多用户都报告说这些包返回了错误,因为它们依赖于 Poppler。
没听说过[波普勒](https://en.wikipedia.org/wiki/Poppler_(software))?
Poppler 是一个用于渲染 pdf 的工具,在 Linux 系统中很常见,但在 Windows 中并不常见。因此,自然地,如果您想使用 Poppler 及其相关的包,我们需要弥补这个差距。
让我们访问谷歌,看看我们有什么选择…
在谷歌上快速搜索一下,就会发现还有很多人有这个问题,他们仍在寻找解决方案。
* [PDF 到 JPG(波普勒)](https://stackoverflow.com/questions/46184239/extract-a-page-from-a-pdf-as-a-jpeg)
* [在 Windows 上安装 Poppler?](https://stackoverflow.com/questions/18381713/how-to-install-poppler-on-windows)
* [无法在 Windows (Poppler)上安装“PDFtoText”](https://stackoverflow.com/questions/52336495/cannot-install-pdftotext-on-windows-because-of-poppler)
* [在 Windows 上运行 PyPDFOCR 需要 Poppler?](https://stackoverflow.com/questions/31817070/running-pypdfocr-on-windows-via-python-requiring-poppler)
* [ModuleNotFoundError —没有名为‘SipDistUtils’(Poppler)的模块](https://stackoverflow.com/questions/51420803/modulenotfounderror-no-module-named-sipdistutils-while-install-python-poppler)
# 问题是:
Poppler 和 Python 的 PDF 库利用了 Linux 实用程序,但不能很好地与 Windows 兼容。
当我们寻找解决方案时,许多方案已经过时、无效、太难了,等等…
# **解决方案:**
在提出的解决方案中,有一个解决方案似乎效果不错。
**Windows Linux 子系统(WSL)。**
实际上,由于 Linux 的 Windows 子系统是如此强大,它对于需要在 Windows 机器上使用 Linux 工具的其他问题是一个很好的解决方案。
# **那么,WSL 是什么?**
Windows Subsystem for Linux 是 Windows 10 上的 Linux 二进制可执行文件的兼容层。它最近进入了版本二(WSL 2)并引入了真正的 Linux 内核。简单地说,WSL 让你感觉像是在一台真正的 Linux 机器上工作(你确实是)。
# **安装和使用指南— WSL**
[**参考**](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
在本节中,我们将通过五个简短的步骤来安装和设置 WSL。之后,我们将通过几个简单的步骤来安装和设置 Poppler。
## **第一步:**
以管理员身份运行 Window 的 Powershell。

## **第二步:**
通过执行“Enable-WindowsOptionalFeature”命令启用 WSL:

启用 WSL
## **第三步:**
通过重新启动计算机来激活更改。
注意,微软说,“为了确保 WSL 能够启动一个可信的执行环境,这个重启是必需的”
## **第四步:**
现在,您从重启中回来了,您的系统的 WSL 已经启用,并且您已经准备好安装 Linux 发行版了。
去橱窗商店搜索 WSL。

从 Windows 应用商店获取 WSL
## **第五步(最终):**
点击 Ubuntu,选择安装。注意,我的已经安装了,所以你必须在这里做一些想象。

安装 Ubuntu
# **安装和使用指南— Poppler:**
## 第一步:
在 VS 代码中,通过类似这样的终端输入 WSL。注意,一旦输入 WSL,终端提示符将会改变。您现在正在 Linux 机器中操作!激动人心!

输入 WSL
## **第二步:**
在 WSL-prompt 中执行以下命令。请注意,您可以忽略一些处理 Tesseract-OCR 和 PyTesseract 的步骤。这些是我在文章结尾分享的演示项目。
## **步骤 3——测试(最终):**
使用新获得的现成 Poppler 实用程序运行程序。
我已经创建了这个**演示脚本**,所以如果你没有自己的也可以用。虽然你需要一个 PDF 文件来处理。
这段代码的工作原理是将 PDF 转换成 JPG。然后,它进行 OCR,并将 OCR 结果写入输出文件。
# **结论:**
就是这样。你通过了 Windows 上的 Poppler 认证。
享受战利品吧!你已经获得了一些全新而强大的技能。你正在成为一个更灵活的开发人员(如果你还没有的话)。
**新获得的技能:**
* 用 Python 成功操作 pdf 的能力。
* 访问 PDF2Image、PDFToText 或其他 Poppler-utils。
* Linux 的 Windows 子系统。**非常强大的开发工具**
# 现在,你能建造什么?
尝试这些新技能并巩固你的理解是非常重要的。真正的理解来自经验。
## 我的 Poppler-On-Windows 项目:
我构建了一个 OCR 应用程序来帮助记录退休教授和著名计算机科学家【Kenneth E. Batcher 博士的历史工作。它使用一个 PDF 到图像的 JPEG 转换工具。然后,它对图像进行 OCR,并将结果写入输出文件。由于这种概念证明工作得足够好,它最终将被用于文档扫描,而不是 pdf。
你可以在这里找到[的项目。](https://github.com/matmill5/KenBatcherPP-OCR)

OCR 应用程序—开发中
# 流行的 NumPy 函数以及在哪里可以找到它们
> 原文:<https://towardsdatascience.com/popular-numpy-function-and-where-to-find-them-6d170b7e6ba1?source=collection_archive---------31----------------------->

最流行的 NumPy 函数(图片由作者提供)
探索,还是剥削?
如果有用,那就足够了。如果你能把事情做好,为什么要寻找其他方法来解决同样的问题呢?这是看待事物的一种方式。反对这种做法的理由是,这样你会错过更有效、更易读的选择。
即使在与 NumPy、Pandas 和其他相关库一起工作了近三年之后,我仍然经常找到解决问题的替代方法,至少可以说,这些方法大大减少了运行时间或者可读性更好。
那么,在开始工作之前,我们应该努力探索其他功能吗?绝对不行!浏览整个文档会花很多时间。
那我们该怎么办?
我决定看看最常用的函数,看看我是否知道它们。假设是**最有用的功能可能会被大多数人使用**。
让我们来了解一下这些功能是什么!我们将分三步走。
1. 使用 Github 搜索 API 来查找使用 NumPy 的存储库
2. 从这些存储库中,下载相关的文件
3. 浏览代码库,找到最常用的函数
## 使用 Github 搜索 API 来查找使用 NumPy 的存储库
要使用 Github API,首先需要创建一个 [API 令牌](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token)。我们将把这个令牌放入请求的头部。
I put the API token in a txt file, which I read in the next line
with open('../../api_keys/github.txt', "r") as f:
API_KEY = f.read()
headers = {'Authorization': 'token %s' % API_KEY}
现在我们来声明一些变量。
We will look for python codebases that use the NumPy library
LIBRARY = ‘numpy’
LANGUAGE = ‘python’# This is how the basic search URL looks like. We need to append the page number with it in order to get the paginated search results
URL = 'https://api.github.com/search/repositories?q=%s+language:%s&sort=stars&order=desc&page=' % (LIBRARY, LANGUAGE)
现在,我们将使用请求库发送一个 GET 请求,然后检查响应。
r = requests.get(URL + '1', headers=headers)
json_response = r.json()print(json_response.keys())
print('Total Repositories:', json_response['total_count'])
print('Total number of items in a page:', len(json_response['items']))print('Keys in a item:', json_response['items'][0].keys())
输出:
dict_keys(['total_count', 'incomplete_results', 'items'])
Total Repositories: 10853
Total number of items in a page: 30
Keys in a item: dict_keys(['id', 'node_id', 'name', 'full_name', 'private', 'owner', 'html_url', 'description', 'fork', 'url', 'forks_url', 'keys_url', 'collaborators_url', 'teams_url', 'hooks_url', 'issue_events_url', 'events_url', 'assignees_url', 'branches_url', 'tags_url', 'blobs_url', 'git_tags_url', 'git_refs_url', 'trees_url', 'statuses_url', 'languages_url', 'stargazers_url', 'contributors_url', 'subscribers_url', 'subscription_url', 'commits_url', 'git_commits_url', 'comments_url', 'issue_comment_url', 'contents_url', 'compare_url', 'merges_url', 'archive_url', 'downloads_url', 'issues_url', 'pulls_url', 'milestones_url', 'notifications_url', 'labels_url', 'releases_url', 'deployments_url', 'created_at', 'updated_at', 'pushed_at', 'git_url', 'ssh_url', 'clone_url', 'svn_url', 'homepage', 'size', 'stargazers_count', 'watchers_count', 'language', 'has_issues', 'has_projects', 'has_downloads', 'has_wiki', 'has_pages', 'forks_count', 'mirror_url', 'archived', 'disabled', 'open_issues_count', 'license', 'forks', 'open_issues', 'watchers', 'default_branch', 'permissions', 'score'])
我们看到响应是一个包含三个键的字典:total_count、incomplete_results 和 items。
我们观察到有 10853 个存储库匹配我们的查询。但是我们不会深入研究这么多的存储库!假设我们将只研究 N 个最流行的。怎样才能找到最受欢迎的?嗯,我们已经在我们的 **URL** 中指定了根据**星星**对结果进行排序,按照**降序**的顺序。
URL = 'https://api.github.com/search/repositories?q=%s+language:%s&sort=stars&order=desc&page=' % (LIBRARY, LANGUAGE)
现在我们只需要这些存储库的 URL,这样我们就可以克隆它们了。你可以看到每一项都有一个“ **clone_url** ”键,它服务于这个目的。我们将为每个存储库保留一些额外的密钥,以防我们以后需要它们。现在,我们将迭代前 35 页。
keys = ['name', 'full_name', 'html_url', 'clone_url', 'size', 'stargazers_count']
NUMBER_OF_PAGES_TO_ITERATE = 35# We will declare a dictionary to store the items
repo_dict = dict([(key, []) for key in keys])
我们需要发送每个页面的请求,并保存结果!不要忘记在每个请求之间等待几秒钟,以免 API 不堪重负。
for page_num in tqdm(range(0, 35)):
r = requests.get(URL + str(page_num))
contents = r.json()
for item in contents['items']:
for key in keys:
repo_dict[key].append(item[key])
if page_num % 5 == 0:
time.sleep(60)
现在我们已经有了存储库信息,让我们把它保存在一个数据帧中,我们稍后会用到它。
repo_df = pd.DataFrame(repo_dict)
repo_df.to_csv('../../data/package_popularity/numpy/repo_info.csv')repo_df.head()
在下面的要点中,您可以查看搜索查询返回的存储库。
## 从这些存储库中下载相关文件
如果您运行下面的命令,您将会看到一些存储库不止一次出现在那里。我还没有发现为什么会发生这种情况。如果你知道任何关于这件事的情况,请让我知道。
repo_df[‘full_name’].value_counts()
现在,我们将只考虑这些存储库中的一个,最先出现的那个。
您可以编写一个 bash 脚本来克隆这些存储库,或者使用 Github 库。要使用 Github 库,您必须提供 Github API。
with open('../../api_keys/github.txt', "r") as f:
API_KEY = f.read()
g = Github(API_KEY)
在这些文件中,我们将只下载那些带有。py 或者。ipnyb 扩展。
ext_set = set(['ipnyb', 'py'])
The directory where we will store the repositories
REPO_DIR_PARENT = ‘../../data/package_popularity/numpy/clones/’
接下来,我们将只考虑至少有 100 颗星的存储库。
repo_df = repo_df[repo_df['stargazers_count'] >= 100]
要获得回购的文件,我们可以使用下面的代码片段。这将返回目录中的所有文件,作为 int get_contents 函数的参数。例如,下面的代码片段将返回根目录中的文件。
repo = git_client.get_repo(full_name)
contents = repo.get_contents("")
我们需要从目录结构中递归收集所有文件。让我们编写一个助手函数来处理这个问题。
def get_relevant_files (full_name, git_client, ext_set):
repo = git_client.get_repo(full_name)
contents = repo.get_contents("")
files = []
while contents:
file_content = contents.pop(0)
if file_content.type == "dir":
contents.extend(repo.get_contents(file_content.path))
elif file_content.name.split('.')[-1] in ext_set:
files.append((file_content.name, file_content.download_url))
return files
让我们调用存储库,看看会发生什么。
files = get_relevant_files('ddbourgin/numpy-ml', git_client, ext_set)
print(len(files))
print(files[0])
输出:
89
('setup.py', 'https://raw.githubusercontent.com/ddbourgin/numpy-ml/master/setup.py')
存储库中有 89 个文件。py 或者。ipnyb 扩展。该列表包含文件的 URL,我们可以使用请求库轻松下载这些文件。
for name, download_url in files:
r = requests.get(download_url, allow_redirects=True)
最后,我们需要将文件的内容保存在本地目录中。我们将简单地使用存储库的全名来创建一个目录,然后将所有文件放在这个特定的目录中。
os.path.join(REPO_DIR_PARENT, '_'.join(full_name.split('/')))
你可以在下面的要点中找到完整的代码。
## 探索仓库
现在我们将深入挖掘下载的文件。首先,让我们看看 import 语句,了解 NumPy 库通常是如何导入的。我们已经知道流行的“import numpy as np”语句。但是有没有人把它进口当 pd,甚至熊猫?🤔
查看导入语句,我发现有三种最常用的类型。
1. import numpy
处理这个问题非常简单。我们将只看形式为 **numpy 的语句。***
2. import numpy.abc
这个也很直接。
3. 从 numpy 导入 abc
我们将通过处理每个实例 **abc 来处理这个问题。*** 为 **numpy.abc.***
4. 从 numpy.abc 导入 xyz
我们将处理 **xyz。*** 为 **numpy.xyz.abc.***
所有这些语句都可以用“as”来修改,如“import numpy as np”或“from numpy import abc as def”我们也需要解决这个问题!
我们将保留一本字典,在那里我们将记录这些缩写以及它们代表什么。然后看到 def,就用 numpy.abc 代替,以此类推。
导入的模块实例可以有两种类型。
1. 它们可以是函数,我们可以通过寻找左括号来识别。
2. 它们可以是类,我们可以通过检查它们的属性是否被访问来识别它们。
我们现在非常接近最终解决方案。
对于每个文件,我们将首先构建一组导入的实例。
然后我们将遍历每一行,并检查“numpy.xyz.abc.*(”,这是一个简单的正则表达式,其中星号可以由任意数量的字符替换。
如果我们找到一行包含“numpy.xyz.abc.*(”,我们就知道这一行使用的是“numpy.xyz.abc.*()”函数。
**限制**:我们只看单行语句。如果一个函数调用或导入语句跨越多行,这段代码不会计算在内。我没处理过一些边缘案件。如果你想的话,可以随意修改代码!
现在我们有了 20 个最常用的函数!
1. numpy.array()
2. numpy.arange()
3. numpy.zeros()
4. numpy.ones()
5. numpy . testing . assert _ array _ equal()
6. numpy.dtype()
7. numpy.random.uniform()
8. numpy.asarray()
9. numpy.empty()
10. numpy.testing.assert_equal()
11. numpy.linspace()
12. numpy.all()
13. numpy.sum()
14. numpy.random.randint()
15. numpy.random.rand()
16. numpy.allclose()
17. numpy.random.random()
18. numpy . testing . assert _ almost _ equal()
19. numpy.dot()
20. numpy.testing.assert_allclose()

图一。最常用的 NumPy 函数(图片由作者提供)
结果,我用了 18 个。我不知道 [numpy.all_close()](https://numpy.org/doc/stable/reference/generated/numpy.allclose.html) 函数和它的断言变量。看起来很有帮助!
你知道多少?
感谢阅读!
# 我附近的热门地点—使用 Python 和 FourSquare API 的数据可视化
> 原文:<https://towardsdatascience.com/popular-places-near-me-data-visualization-using-python-and-foursquare-api-4d1683cd62d1?source=collection_archive---------43----------------------->
## 本文教你如何使用 python 和 FourSquare API 可视化你所在位置附近指定半径范围内的所有热门地点,在本文结束时,你将能够创建如下所示的地图

作者图片
# A.介绍
人们往往倾向于从一个地方旅行到另一个地方,探索新事物,在旅途中,他们需要了解周围所有受欢迎的地方,这样他们就不会错过任何地方。所以这个应用程序是为那些需要知道他们周围所有人口密集地区的人准备的。
这个模型的输入是你当前的位置和你需要的推荐地点的搜索半径。我们使用 FourSquare API,它给出了给定位置周围所有受欢迎的地方,并用 python 来可视化这些东西。
# B.数据要求:
为了构建这个应用程序,我们采用了 FourSquare API 的帮助,所以你需要在 FourSquare 开发者门户有一个开发者帐户,不要担心它是免费使用的。
下面是如何获得 FourSquare API 证书的方法
1. 访问 [FourSquare 开发者网站](https://developer.foursquare.com/places)。
2. 创建一个帐户,它是免费使用的(你可以找到一步一步的指南[这里](https://docs.mageplaza.com/social-login-m2/how-to-configure-foursquare-api.html)
3. 因此,最终您将拥有一个**客户端 ID** 和**客户端秘密**凭证,它们将在后续步骤中使用。
因此,为了探索一个位置,我们使用 FourSquare API 提供的 URL
https://api.foursquare.com/v2/venues/explore?client_id={CLIENT ID}&client_secret={CLIENT SECRET}&ll={Latitude},{Longitude}&v={VERSION}&radius={RADIUS}&limit={LIMIT}
1. 您将从您的 FourSquare 开发者帐户获得客户 ID 和客户密码。
2. 纬度和经度是您当前的位置坐标,您可以使用 python **geopy** 库获得这些坐标,该库将位置转换为坐标。
3. 半径是用户给出的输入之一。
4. LIMIT 是您希望从 API 获取的结果数
现在我们已经准备好了我们的需求,所以让我们开始编码…
# C.模型开发
## 1.导入所有重要的 python 库
## 2.定义四方 API 凭证
## 3.从用户处读取当前位置,并将其转换为坐标
.
## 4.从 FourSquare API 获取数据,结果是一个 JSON 数据
## 5.从 JSON 文件中获取相关数据,
原始数据是从 FourSquare API 获取的,如下所示

作者图片
## 6.清洗数据并转换成数据帧
终于!我们的数据已经可以可视化了,看看吧...

作者图片
## 7.我附近的热门地点的可视化
万岁!我们成功了,这是我们的最终输出
1. 位置的名称
2. 它以什么类别而闻名
3. 位置的地址
4. 离当前位置的距离
**注**:红色标记显示当前位置,而蓝色标记显示附近的著名地点

作者图片
# 摘要
1. 我们创建了一个 FourSquare API 帐户,并获得了我们唯一的凭证。
2. 我们将用户提供的地址转换为位置坐标。
3. 我们从 FourSquare API 获取数据,并将其转换为数据帧。
4. 最后将数据框可视化在地图上。
# 结论
本文展示了找到您附近所有热门地点的最佳和明智的方法,这可能是初学者开始数据科学项目的最佳方法之一。
你可以在这里获得完整的源代码
## **感谢阅读😃**
[](/impact-of-covid-19-data-visualization-using-python-6f8e3bdc860b) [## 新冠肺炎的影响-使用 Python 进行数据可视化
### 使用 python 在印度地图上可视化冠状病毒爆发的初级方法。当你到达…的终点时
towardsdatascience.com](/impact-of-covid-19-data-visualization-using-python-6f8e3bdc860b)
# 编程语言流行度排名
> 原文:<https://towardsdatascience.com/popularity-ranking-of-programming-languages-72bcf697ea20?source=collection_archive---------36----------------------->
## Python 和 JavaScript 争夺桂冠

图片由 [ILLUSTRIS](https://illustris.ca/)
对于什么是最流行的编程语言,从来没有一致的意见,也许永远也不会有一致的意见。然而,我们认为,尝试找出对编程语言的流行程度进行排名的方法是有价值的。它有助于我们看到一段时间内的趋势,并提示我们应该关注什么。在不断变化的技术世界中,保持领先是非常重要的。
接下来的分析是关于堆栈溢出(SO)的数据。SO 网站可以说是开发者社区中最大、最受欢迎的问答网站(“开发者”是任何写代码的人的一般意义)。目前,该网站每天的访问量约为 1,000 万次,除了简单的访问外,还有 1,260 万用户活跃在该网站上(例如,张贴问题/答案或发表评论/编辑)。我们相信基于编程语言在 SO 上的受欢迎程度来对它们的实际受欢迎程度进行排名是一个很好的估计。
我们已经为编程语言计算了一个**流行指数**,它是三个因素的平均值:每天问的问题数量、每天不同用户的数量和问题的查看次数。为了识别一种语言,我们考虑分配给帖子的标签。例如,对于 JavaScript,我们考虑以下标签:
tags like ‘%javascript%’
or tags like ‘%jquery%’
or tags like ‘%js>%’ — tag ends with ‘js’ e.g. ‘node.js’
or tags like ‘%extjs%’ — includes ‘extjs4’ and others
对于每日问题计数,我们计算每种编程语言每天被问到的问题数量。
为了计算不同用户数,我们计算每天针对每种编程语言提问/回答问题、发表评论或编辑问题/答案的不同用户的数量。
SO 中的每个帖子都有一个属性,显示该帖子被查看了多少次。我们通过将这个数字除以帖子可见的天数来标准化这个数字。这为我们提供了该帖子的归一化视图计数。然后,我们对每种编程语言每天的视图计数求和。请注意,由于最近帖子的标准化视图计数的方差很高,我们没有将这些帖子包括在计算中。因此,这项措施比其他两项措施晚了两个月。
关于指数如何计算的更多细节,请参见 [GitHub 知识库](https://github.com/vvaezian/Popularity-of-Programming-Languages)。
现在让我们使用一些折线图来探索趋势。请注意,您可以使用这个 [**交互式仪表板**](http://metabase.intellimenta.com/public/dashboard/f9b5e04b-9755-489d-9f5d-6adc3e3806fd) (从右上角选择所需的过滤器。)

人气指数仪表板(作者图片)
*注:以下分析基于截至 2020 年 7 月底的 SO 数据。交互式仪表盘背后的数据将每季度更新一次。*
# 前五名
从最受欢迎的五种编程语言(基于我们的指数)开始,如果我们看一下年度数据,我们会发现 JavaScript 在过去 10 年中一直占据冠军宝座,尽管 Python 现在紧随其后,正在迅速赶上。其他三个,即 Java、SQL 和 HTML/CSS,在过去的七年中受欢迎程度略有下降。

当前年度前五名(图片由作者提供)
如果从季度数据来看,JavaScript 虽然与 Python 并驾齐驱,但仍然位居榜首。有趣的部分是月度数据。【2020 年 6 月是过去 10 年来 JavaScript 第一次失去榜首位置。鉴于 Python 的发展速度,Python 似乎将在一段时间内成为顶级竞争者。

当前前五名—每月(图片由作者提供)
# 数据科学
数据科学是近年来的热门话题。在下面的图表中,我们可以看到 Python 和 R 在过去几年中有了很高的增长率。Scala 或多或少保持了它的受欢迎程度,而 Julia 的受欢迎程度到目前为止微乎其微。注意,为了进行公平的比较,本次比较只考虑了 Python 的数据科学部分(更多细节请参见 GitHub 资源库)。

数据科学(作者图片)
# 关系型数据库管理系统
在关系数据库管理系统(RDBMS)中,MySQL 仍然是最受欢迎的,尽管它的受欢迎程度一直在下降。这同样适用于 SQL Server。另一方面,PostgreSQL 的受欢迎程度在过去十年中不断增加。甲骨文的受欢迎程度没有太大变化。

RDDMS(图片由作者提供)
# 移动开发
关于移动开发语言,我们看到了一些相当大的变化。Swift 于 2014 年 6 月推出,对 Objective-C 的受欢迎程度造成了重大打击。类似的故事也发生在 Kotlin 和 Java(移动)上。2017 年,谷歌将 Kotlin 纳入 Android Studio,自 2019 年 5 月以来,它是 Android 应用程序开发者的首选编程语言。

移动开发(图片由作者提供)
# 我们比赛吧!
要查看计算出的过去 10 年的流行指数,请点击下方图表左下角的播放按钮。您也可以使用底部的滑块移动到特定的时间范围。
*注意:图表将在每个季度开始后一个月用新数据更新(如上所述,ViewCount 指标落后于其他两个指标两个月,这导致指数也落后两个月,因为它是三个指标的平均值)。*
(用繁荣条形图比赛创建)
如果你有改进索引的建议,请让我知道,或者在评论中或者在 GitHub 库中创建一个问题。
* [交互式仪表盘](http://metabase.intellimenta.com/public/dashboard/f9b5e04b-9755-489d-9f5d-6adc3e3806fd)
* [GitHub 资源库](https://github.com/vvaezian/Popularity-of-Programming-Languages)
# 用命名实体填充网络图
> 原文:<https://towardsdatascience.com/populating-a-network-graph-with-named-entities-fb8e3d2a380f?source=collection_archive---------31----------------------->
## 数据科学/ Python NLP 片段
## 使用 networkx 可视化自然语言处理结果的早期尝试。

照片由 [Unsplash](https://unsplash.com/s/photos/news?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上的 [Utsav Srestha](https://unsplash.com/@utsavsrestha?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 拍摄
*我做了很多自然语言处理,通常结果看起来很无聊。当我了解网络图时,我开始思考,为什么不用关键词作为节点,把它们连接起来,创建一个网络图呢?*
*Yupp,有何不可!*
在这篇文章中,我们会做到这一点。我们将从关于冠状病毒的新闻文章中提取命名实体,然后使用它们的关系在网络图中将它们连接在一起。
# 简介
网络图是包含节点(顶点)和边(线)的很酷的视觉效果。它经常用于社交网络分析和网络分析,但数据科学家也将其用于自然语言处理。

安德斯·桑德伯格在[闪烁](https://www.flickr.com/photos/arenamontanus/268427309/in/photolist-pHL64-pHM2v-6tMfEz-4WFXny-869jFp-5RKqLt-cAT173-bWngsQ-5UT2bk-a1Jv37-a1Kpgb-22X1B-QmWPYi-c19Geu-2N9Z6h-6UVCQJ-pNWn9-44h6ju-btejyK-9M2QU4-7A9A3C-74oaKo-jR9gc-pNUDF-dHMZYj-t7tgKB-29KdY5-bkztuc-66JvbF-4CS4g3-5RKqMK-bWN8Sm-33Nf4C-7UYR2T-x9m1S-2N5zxK-bS9WnP-ciKZHy-5J95ED-n3DZZ-aFhJjH-THTRQG-SxKctc-btTTPU-TDNAMg-7yZcaX-29Kted-9pT4Ni-91471X-26ary2u)上拍摄的照片
自然语言处理或 NLP 是人工智能的一个分支,它处理编程计算机来处理和分析大量文本并从中获取意义。换句话说,就是教计算机如何理解人类语言……像个老板一样!

照片由 [brewbooks](https://www.flickr.com/photos/brewbooks/) 在 [Flickr](https://www.flickr.com/photos/brewbooks/10805411174/in/photolist-UKMdza-hsQyhE-2iCStmP-2iStoUE-2e5EAr1-2iw1pBb-2iUPEcB-2iXqdWL-PaWqhd-2iJbARo-2iNM3hT-FdCYsS-2iQNUxy-Jec8po-2iMvVpU-2iL4DjL-2iARgAa) 上拍摄
介绍够了,开始编码吧!
首先,让我们确保处理好所有的依赖关系。打开终端并执行以下命令:
pip install -U spacy
python -m spacy download en
pip install networkx
pip install fuzzywuzzy
这将安装 spaCy 并下载英语的训练模型。第三个命令安装 networkx。这应该适用于大多数系统。如果它对你不起作用,检查一下[空间](https://spacy.io/usage)和[网络 x](https://networkx.github.io/documentation/stable/install.html) 的文档。此外,我们使用 [fuzzywuzzy](https://pypi.org/project/fuzzywuzzy/) 进行一些文本预处理。
解决了这个问题,让我们启动 Jupyter 笔记本,开始行动吧!
# 进口
将下面的代码块运行到一个单元格中,以将所有必需的导入内容导入到我们的 Python 环境中。
import pandas as pd
import numpy as np
import pickle
from operator import itemgetter
from fuzzywuzzy import process, fuzz# for natural language processing
import spacy
import en_core_web_sm# for visualizations
%matplotlib inline
from matplotlib.pyplot import figureimport networkx as nx
# 获取数据
如果您想跟进,您可以在这里下载样本数据集。该文件是使用[报纸](https://newspaper.readthedocs.io/en/latest/)从[npr.org](https://www.npr.org/sections/coronavirus-live-updates)导入新闻文章而创建的。如果你喜欢冒险,可以使用下面的代码片段来构建你自己的数据集。
让我们得到我们的数据。
with open('npr_coronavirus.txt', 'rb') as fp: # Unpickling
corpus = pickle.load(fp)
# 提取实体
接下来,我们将从加载 spaCy 的英文模型开始:
nlp = en_core_web_sm.load()
然后,我们将提取实体:
entities = []for article in corpus[:50]:
tokens = nlp(''.join(article))
gpe_list = []
for ent in tokens.ents:
if ent.label_ == 'GPE':
gpe_list.append(ent.text)
entities.append(gpe_list)
在上面的代码块中,我们创建了一个名为`entities`的空列表来存储包含从每篇文章中提取的实体的列表。在 for 循环中,我们循环了语料库的前 50 篇文章。对于每一次迭代,我们将每篇文章转换成单词,然后遍历所有这些单词,得到国家、州和城市的标记为`GPE`的实体。我们使用`ent.text`来提取实际的实体,并将它们一个一个地附加到`entities`中。
结果如下:

请注意,北卡罗来纳州的名称有几种变体,有些名称中带有“the”前缀。让我们摆脱他们。
articles = []for entity_list in entities:
cleaned_entity_list = []
for entity in entity_list:
cleaned_entity_list.append(entity.lstrip('the ').replace("'s", "").replace("’s",""))
articles.append(cleaned_entity_list)
在上面的代码块中,我们简单地遍历列表列表`articles`并逐个清理实体。每次迭代,我们都去掉前缀“the ”,去掉`'s.`
# 可选:FuzzyWuzzy
在查看实体时,我注意到“美国”也有变化。存在着“美利坚合众国”,而有些只是“美国”。我们可以把这些精简成一个更标准的命名约定。
FuzzyWuzzy 可以帮助解决这个问题。
被[pypi.org](https://pypi.org/project/fuzzywuzzy/)描述为“像老板一样的字符串匹配”,FiuzzyWuzzy 使用 Levenshtein 距离来计算单词之间的相似度。关于如何使用 FuzzyWuzzy 的真正好的教程,请查阅 Thanh Huynh 的文章。
[](/fuzzywuzzy-find-similar-strings-within-one-column-in-a-pandas-data-frame-99f6c2a0c212) [## FuzzyWuzzy:用 Python 在一列中查找相似的字符串
### 令牌排序比率与令牌集比率
towardsdatascience.com](/fuzzywuzzy-find-similar-strings-within-one-column-in-a-pandas-data-frame-99f6c2a0c212)
下面是使用 FuzzyWuzzy 的可选代码:
在创建网络图之前的最后一步,让我们去掉列表中的空列表,这些列表是由没有任何`GPE`实体类型的文章生成的。
articles = [article for article in articles if article != []]
# 创建网络图
下一步,我们将创建图形存在的世界。
G = nx.Graph()
然后,我们将手动添加带有`G.add_nodes_from()`的节点。
for entities in articles:
G.add_nodes_from(entities)
让我们看看这个图表是什么样子的:
figure(figsize=(10, 8))
nx.draw(G, node_size=15)

接下来,让我们添加将连接节点的边。
for entities in articles:
if len(entities) > 1:
for i in range(len(entities)-1):
G.add_edges_from([(str(entities[i]),str(entities[i+1]))])
对于上面代码的每一次迭代,我们都使用了一个条件,该条件将只处理包含两个或更多实体的实体列表。然后,我们用`G.add_edges_from()`手动连接每个实体。
让我们看看现在的图表是什么样的:
figure(figsize=(10, 8))
nx.draw(G, node_size=10)

这张图让我想起了蜘蛛!LOL。
为了便于组织,我决定使用 shell 版本的网络图:
figure(figsize=(10, 8))
nx.draw_shell(G, node_size=15)

我们可以看出一些节点的连接比其他节点重。要查看哪些节点拥有最多的连接,让我们使用`G.degree()`。
G.degree()
这给出了以下度数视图:

让我们找出哪个节点或实体拥有最多数量的连接。
max(dict(G.degree()).items(), key = lambda x : x[1])

为了找出拥有最多连接数的其他节点,让我们来看看前 5 个:
degree_dict = dict(G.degree(G.nodes()))
nx.set_node_attributes(G, degree_dict, 'degree')sorted_degree = sorted(degree_dict.items(), key=itemgetter(1), reverse=True)
上面,`sorted_degrees`是一个包含所有节点及其度数值的列表。我们只希望前 5 名是这样的:
print("Top 5 nodes by degree:")
for d in sorted_degree[:5]:
print(d)

# 奖励回合:Gephi
Gephi 是一个开源的免费桌面应用程序,让我们可以可视化、探索和分析各种图形和网络。
让我们将图形数据导出到一个文件中,这样我们就可以将它导入到 Gephi 中。
nx.write_gexf(G, "npr_coronavirus_GPE_50.gexf")

酷豆!
# 后续步骤
这次,我们只处理了来自 npr.org[的 50 篇文章。如果我们处理数据集的所有 300 篇文章,会发生什么?如果我们将实体类型从`GPE`改为`PERSON`,会看到什么?还能怎么用网络图来可视化自然语言处理结果?](https://npr.org)
总是有更多的事情要做。可能性是无限的!
我希望你喜欢今天的帖子。代码并不完美,我们还有很长的路要走,才能从数据中获得洞察力。我鼓励你更深入地了解[空间](https://spacy.io/)、[网络](https://networkx.github.io/)、 [fuzzywuzzy](https://pypi.org/project/fuzzywuzzy/) ,甚至 [Gephi](https://gephi.org/) 。
*敬请期待!*
你可以通过 [Twitter](https://twitter.com/ecdedios) 或 [LinkedIn](https://www.linkedin.com/in/ednalyn-de-dios/) 联系我。
[1]:维基百科。(2020 年 5 月 25 日)。*自然语言处理*https://en.wikipedia.org/wiki/Natural_language_processing
[2]: Gephi。(2020 年 5 月 25 日)。*打开图 Viz 平台*[https://gephi.org/](https://gephi.org/)
# 用测试数据填充员工数据库
> 原文:<https://towardsdatascience.com/populating-the-employee-database-with-test-data-aa76419eebb6?source=collection_archive---------49----------------------->
## 从雇员数据库的例子开始,这一次我们将弄清楚如何用测试数据填充数据库。

图片来自 [Piqsels](https://www.piqsels.com/en/public-domain-photo-frpof) (CC0)
在本文中,我们将研究用虚拟数据填充雇员数据库的过程,我们在[的上一篇文章](/sql-database-design-basics-with-example-8dcce4b0c687)中设计了虚拟数据的模式。当我们想要运行一些测试时,用虚拟数据填充 SQL 数据库会非常有用。最方便的方法是借助可视化数据生成工具用随机数据填充 SQL 表。
# 借助 SQL Server 数据生成器生成数据
为此,我们将使用 SQL Server 的[数据生成器](https://www.devart.com/dbforge/sql/data-generator/)工具,它被集成到 SSMS 中,也包含在 [dbForge Studio](https://www.devart.com/dbforge/) 中。应该注意,真实的测试数据是基于列名、维度和数据类型生成的。除此之外,还考虑了表之间的关系,因为数据生成过程依赖于它们。
要打开该组件,在 [SSMS](https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-2017) 中的必要数据库上右击“新数据生成…”:

Img。1.在 SSMS 运行 SQL Server 工具的数据生成器
如果您使用的是 dbForge Studio,请在主菜单中选择工具\新数据生成…:

Img.2 .在 dbForge Studio 中运行 SQL Server 工具的数据生成器
在出现的窗口中,在“Connection”选项卡上,您可以看到当前的 MS SQL Server 实例和为数据生成选择的数据库,可以对其进行编辑(如果需要)。然后单击“下一步”按钮:

Img.3 .设置“连接”选项卡
接下来,在“选项”选项卡上,让我们设置数据库的数据生成选项:

Img.4 .设置数据生成选项
请注意,您可以在不同的模式下生成 SQL 测试数据:
1. 按指定的行数(默认为 1000 行)
2. 按现有数据在总量中所占的百分比(默认为 10 %)
3. 按时间生成数据(默认为 10 秒)
您也可以通过设置“生成前从表中截断数据”参数,在生成前清除数据。
您可以通过以下方式之一设置值分配模式:
1. 按时间戳随机
2. 按种子随机(默认为 1)
3. 连续的
此外,您可以设置列属性:
1. 将值设置为唯一
2. 包括空值(默认为 10%的行)
3. 包括空值(默认为 10%的行)
您可以按下位于数据生成设置窗口左下角的“保存命令行…”按钮,将设置保存到. bat 文件中。
完成设置后,在数据生成设置窗口的右下角,按下“打开”按钮。
然后,您将看到一个进度条,显示表元数据加载。之后,将出现一个窗口,其中包含每个选定表格的详细数据生成设置:

Img.5 .每个选定表格的详细数据生成设置
在左边,您应该选择想要填充的表和列,在右边,您应该为所选的表设置表生成模式。
同时,下面是生成数据的实例(注意代表真实姓名)。
在右上角,有一个上面描述的数据生成设置按钮。
要开始数据生成过程,请单击窗口顶部中间的绿色箭头。然后,您将看到用于选择附加设置的窗口。在这里,在 Output 选项卡上,您需要准确地选择生成数据的位置,以脚本的形式,将其保存到文件或数据库。让我们选择最后一个选项,然后按下一步:

Img。6.设置“输出”选项卡
然后,您可以在“选项”选项卡上设置其他参数。在这种情况下,您需要取消选中数据库备份选项,然后按“下一步”:

Img.7 .设置“选项”选项卡
在“附加脚本”选项卡上,您可以设置附加脚本。在我们的例子中,我们只需按“下一步”:

Img.8 .设置“附加脚本”选项卡
在“Summary”选项卡上,我们可以看到关于设置和警告的信息。在这里,您也可以将所有设置保存为. bat 文件,方法是按下左下角的“保存命令行…”按钮。要运行数据生成流程,您需要按“生成”按钮:

Img.9 .摘要选项卡上的一般信息和警告
出现数据生成过程窗口:

Img.10 .数据生成流程
然后,这些表将被数据填充。例如,Employee 表具有以下生成的数据:

Img.11 .雇员表中生成数据的示例
# 结论
总之,我们用真实的数据填充了数据库,用于测试功能和负载。可以为负载测试生成更多的随机数据。除此之外,测试的过程可以通过 dbForge 单元测试工具来加速。
此外,通过使用 SQL 数据生成,您不仅可以计算数据库增长率,还可以计算数据量增加导致的查询性能差异。
*原载于 2020 年 7 月 22 日 https://blog.devart.com*[](https://blog.devart.com/generate-test-data-with-sql-data-generator.html)**。**
# 基于 NumPy 的投资组合优化
> 原文:<https://towardsdatascience.com/portfolio-optimization-with-numpy-93e1428525a5?source=collection_archive---------15----------------------->

在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上由 [Austin Distel](https://unsplash.com/@austindistel?utm_source=medium&utm_medium=referral) 拍摄的照片
## 你所需要的只是一些矩阵代数来做出最优投资组合
***来自《走向数据科学》编辑的提示:*** *虽然我们允许独立作者根据我们的* [*规则和指导方针*](/questions-96667b06af5) *发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的* [*读者术语*](/readers-terms-b5d780a700a4) *。*
*如果你想看我的代码,* [*你可以在我的 GitHub 这里找到*](https://github.com/yiuhyuk/portfolio_optimization) *。*
上次我们讨论了投资组合优化的工作方式和原因:
[](/understanding-portfolio-optimization-795668cef596) [## 了解投资组合优化
### 从概念上理解优化投资组合意味着什么
towardsdatascience.com](/understanding-portfolio-optimization-795668cef596)
今天,我们将深入实际优化投资组合的技术细节。关于投资组合优化的冷静思考是,它可以完全用矩阵代数来完成,不需要优化软件。
开始之前,让我们重温一下我们的目标。引用我之前的帖子:
> 我们希望(尽可能)确定的是,对于特定的风险水平,我们投资的投资组合能够最大化我们获得正回报的机会。做到这一点的投资组合,也称为最优投资组合,是具有最高预期回报的**(或者用统计学术语来说,是具有最高 Z 值的投资组合)。**
For a given level of risk, solve for the weights, W, that:Maximize W.T @ E****Subject to:
W.T @ Cov @ W = (target risk)^2
and sum(W) = 1Where W is a vector representing the weights of the asset in our portfolio.
E is a vector representing the expected returns of the asset.
Cov is the covariance matrix of the asset's returns.
@ denotes matrix multiplication.
.T denotes the transpose operation.
1. W @ E 是投资组合的预期收益。
2. 投资组合的方差计算为 W.T @ Cov @ W)。方差是投资组合标准差的平方(也称为风险)。在我们的目标函数中,我们希望投资组合的方差等于目标方差(目标风险水平的平方)。
# 翻转问题
最小化问题通常比最大化问题更容易解决,所以让我们把问题反过来:
For a given level of risk, solve for the weights, W, that:Minimize W.T @ Cov @ W****Subject to:
W.T @ E = target return = mu
and sum(W) = 1Where W is a vector representing the weights of the asset in our portfolio.
E is a vector representing the expected returns of the asset.
Cov is the covariance matrix of the asset's returns.
@ denotes matrix multiplication.
.T denotes the transpose operation.
现在,我们不是最大化给定方差水平的收益(也就是风险的平方),而是最小化给定收益水平的方差。
为了解析地解决这个问题,我们可以利用[拉格朗日乘数](https://en.wikipedia.org/wiki/Lagrange_multiplier)并将我们的问题改写如下:
L(W,h1,h2)
= W.T@Cov@W + h1(W.T@E - mu) + h1(W.T@ones - 1)****ones denotes a vector of ones with the same length as W
请注意,我们现在有一个等式,其中包括我们想要最小化的东西( **W.T@Cov@W** )以及我们的两个约束条件——投资组合的预期回报必须等于目标回报( **W@E — mu** ),投资组合权重总和必须为 1 ( **W@ones — 1** )。
我们可以通过解决以下问题来解决这个问题:
gradient{L(W,h1,h2)} = 0
这基本上是梯度下降,我们想找到关于每个变量的偏导数(也叫斜率)为零的点。当我们到达那一点时,我们知道我们是最小的。
# 一些矩阵代数
我们可以用矩阵代数来解前面的方程。首先让我们写出每个偏导数:
gradient L with respect to W = 2Cov@W + h1mu + h2*ones = 0
gradient L with respect to h1 = W.T@E - mu = 0
gradient L with respect to h2 = W.T@ones - 1 = 0
我们可以将方程组改写为:
2Cov@W + h1mu + h2*ones = 0
W.T@E = mu
W.T@ones = 1
矩阵的好处在于,它让我们可以很容易地表示像这样的方程组(并且很容易求解)。在 Python 矩阵表示法中,前面的三个等式是:
[[2*Cov h1 h2], [[W ], [[0 ],
[E.T. 0 0 ], @ [h1], = [mu],
[ones.T 0. 0 ]] [h2]] [1 ]] A @ X = b
所以我们可以用三个矩阵 A、X 和 b,用矩阵方程 A@X=b,来解决整个问题。
现在我们需要做的就是解出 X,我们可以很容易地将 b 乘以 A 的倒数:
X = inverse(A)@bThe first n elements of X are the optimal weights where n is the number of different assets whose weights we are optimizing for.
# 用 Python 把它们放在一起
首先我们从一些回报开始。我通过 QUANDL API 从 Shardar 下载了我的。我的返回数据存储在名为 **final** 的数据帧中,如下所示:
S&P 500 Treasury Bonds TIPS Gold
date
2020-10-07 0.017407 -0.007293 -0.000080 -0.000451
2020-10-08 0.008863 0.005400 0.003977 0.003555
2020-10-09 0.008930 -0.000187 0.000317 0.018161
2020-10-12 0.016088 0.003186 0.000634 -0.002872
2020-10-13 -0.006526 0.007161 0.000000 -0.01572
有四种资产,我有每种资产几年的日收益。我们可以使用以下代码计算优化所需的输入:
final is a dataframe of daily returns for the assets# I use the historical mean return for my expected return
E = np.array(final.mean(axis=0)).reshape(-1,1)# Calculate the covariance matrix of the asset's returns
cov_matrix = np.array(final.cov())# Ones vector
ones = np.ones((E.shape[0],1))zeros = np.zeros((2,2))
接下来,我们根据等式(A@X=b)创建矩阵:
Put together the A matrix
A = 2*cov_matrix
A = np.append(A, E.T, axis=0)
A = np.append(A, ones.T, axis=0)
temp = np.append(E, ones, axis=1)
temp = np.append(temp, zeros, axis=0)
A = np.append(A, temp, axis=1)# Put together the b vector
b = np.array([[0],
[0],
[0],
[0],
E[0], # I set the target return to be
[1]]) # the expected return of stocks# So in essense, I am looking for an optimal portfolio
that is expected to give the same return as I get from
investing in stocks (but with lower risk)
这是他们每个人的样子:
A =
0.000237 -0.000096 -0.000015 0.000004 0.000555 1.0
-0.000096 0.000170 0.000046 0.000038 0.000371 1.0
-0.000015 0.000046 0.000024 0.000022 0.000154 1.0
0.000004 0.000038 0.000022 0.000200 0.000228 1.0
0.000555 0.000371 0.000154 0.000228 0.000000 0.0
1.000000 1.000000 1.000000 1.000000 0.000000 0.0b =
0.000000
0.000000
0.000000
0.000000
0.000555
1.000000# The 0.000555 number in b is the historical daily mean return of
the S&P 500
最后,我们可以通过对矩阵 A 求逆并将其乘以矩阵 b 来计算最佳权重:
Optimize using matrix algebrafrom numpy.linalg import invresults = inv(A)@b# Grab first 4 elements of results because those are the weights
Recall that we optimize across 4 assets so there are 4 weights
opt_W = results[:final.shape[1]]
让我们来看看我们的最佳体重。最佳投资组合主要包括股票和债券,做空 TIPS,少量配置黄金。解析解只能产生无约束权重(意味着允许短重)。如果我们只想要正的权重,我们将不得不使用梯度下降。
***这些权重是使用非常天真的假设和纯粹的历史数据计算出来的。这些绝对不应该作为投资建议!***
Optimal Weights
S&P 500 0.602329
Treasury Bonds 0.726293
TIPS -0.357301
Gold 0.028680
最后,让我们看看我们所谓的最优投资组合实际上是否是最优的。我们应该期望我们的最优投资组合的回报与股票(标准普尔 500)相似,但波动性更小。我们可以看到,我们的最优投资组合的回报(紫色线)比股票的回报(蓝色线)更高,波动性更小。
请记住,这个简单的分析是非常偏颇的。目的是向您展示如何用矩阵代数进行投资组合优化。**我优化了投资组合,并在相同的时间框架内对其进行了回溯测试**(没有训练测试分割),因此投资组合当然会看起来非常好。

最优投资组合与组成资产类别(来源:Sharadar,图形由作者创建)
# 结论
一旦你计算完最佳权重,还有更多工作要做。众所周知,投资组合优化过程对输入(尤其是预期回报)的微小变化非常敏感。
因此,震撼优化输入(通过重采样或甚至添加一些人工噪声)来查看权重如何变化是一个好主意。
最后,思考一下最优投资组合真正代表的是什么是有好处的。这是一个旨在长期持有(几年)的投资组合。这是因为我们用来估计投入的数据(回报的时间序列)需要覆盖尽可能多的时间,最好是多个商业周期。
这不是一个旨在帮助你在短期内把握市场时机的过程。短期内估计的预期收益和协方差矩阵会带来估计错误的巨大风险——记住,垃圾进垃圾出。干杯!
# 使用 SciPy 优化投资组合
> 原文:<https://towardsdatascience.com/portfolio-optimization-with-scipy-aa9c02e6b937?source=collection_archive---------7----------------------->

[活动发起人](https://unsplash.com/@campaign_creators?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
## 使用 Python 计算带约束的最优投资组合
***来自《走向数据科学》编辑的提示:*** *虽然我们允许独立作者根据我们的* [*规则和指导方针*](/questions-96667b06af5) *发表文章,但我们并不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的* [*读者术语*](/readers-terms-b5d780a700a4) *。*
*无意成为投资建议。你可以在我的 GitHub 上找到我的代码。*
是时候写另一篇关于投资组合优化的文章了,因为我最近一直在做这方面的工作。如果你需要复习,这里是我以前写的关于这个话题的文章:
[](/understanding-portfolio-optimization-795668cef596) [## 了解投资组合优化
### 从概念上理解优化投资组合意味着什么
towardsdatascience.com](/understanding-portfolio-optimization-795668cef596) [](/portfolio-optimization-with-numpy-93e1428525a5) [## 基于 NumPy 的投资组合优化
### 你所需要的只是一些矩阵代数来做出最优投资组合
towardsdatascience.com](/portfolio-optimization-with-numpy-93e1428525a5)
尽管仅仅用矩阵代数和 NumPy 来优化投资组合很有趣,但有时我们需要添加约束。例如,许多投资者不想或不被允许做空投资。我们不能保证使用矩阵代数产生的最优投资组合不包括空头头寸(负权重)。因此,我们转而求助于**优化**。
如果你没有阅读我以前关于优化的文章,**优化是指在给定风险水平下最大化回报(或最小化特定回报水平下的风险)的资产组合的求解过程**。优化的期望输出是一组能够产生最优投资组合的投资组合权重(针对每项资产)。
# 运行投资组合优化
投资组合优化的两个关键输入是:
1. **被考虑的每项资产的预期收益**。
2. 资产收益的**协方差矩阵**。嵌入其中的是关于 [**交叉资产相关性**](/understanding-correlation-and-diversification-661c19a26555) 和 [**每个资产的波动率**](/understanding-investment-risk-3882c58e00e0) y(对角线)的信息。
预期回报很难估计——有些人喜欢使用历史平均值(因为过去往往不代表未来,这很危险),其他人有自己的方法来估计回报预测。我计划写一整篇关于这个的文章,所以这次我不会详细讨论。今天我们将关注优化过程本身。因此,我们将假装我们从一个顾问那里得到了预期回报估计。顺便说一句, ***这些都是我非常粗略的估算,绝对不应该作为投资建议*** 。

我们优化的预期回报(图形由作者创建)
正如你从上面的图表中所看到的,我们有一个包含八种投资的投资组合,从股票、债券到大宗商品。对于那些不熟悉这个缩写的人来说,TIPS 是财政部通货膨胀保值证券——换句话说,是没有通货膨胀风险的国债。
以下是用过去 10 年的回报率估算的相关性。越低越好,所以蓝色阴影的单元格代表多样化的潜在机会。从技术上来说,优化需要协方差矩阵,但是相关矩阵提供的信息更多。

相关矩阵(图形由作者创建)
现在我们有了输入,让我们来看看代码。
# 编码投资组合优化
我使用了与我在[之前的优化文章](/portfolio-optimization-with-numpy-93e1428525a5)中相同的数据集,除了现在有八个资产而不是四个。每项资产的标签是:
factors = ['S&P 500','Emerging Markets','Small Cap',
'Treasury Bonds',
'High Yield','TIPS','Gold','Oil']
我将每日收益存储在一个名为 **factor_returns** 的熊猫数据框架中。计算我们资产的协方差矩阵非常简单:
cov = factor_returns.cov()
正如我上面提到的,我们将使用我创建的退货预测(退货的指定顺序与它们在因子中列出的顺序相同):
expected_returns = np.array([[ 0.080],
[ 0.092],
[ 0.092],
[-0.017],
[ 0.034],
[ 0.001],
[ 0.010],
[ 0.079]])
现在让我们导入优化所需的 Python 库:
from scipy.optimize import minimize, Bounds, LinearConstraint
我将稍微不按实际编码的顺序来解释,因为这样更容易理解。下一个代码块显示了一个名为 **optimize** 的函数,它使用 SciPy 的 **minimize** 函数运行优化。
看看调用 minimize 的地方(我加粗了)。第一个参数 **func** 是我们想要最小化的函数。第二个参数 **W** 是允许优化器改变的输入— **W 是我们正在求解的,对应于我们投资组合中资产的权重**。我们需要从猜测开始——没有任何强有力的先验,我只是对每项资产进行同等加权。
**args** 参数中的 **exp_ret** (预期回报)和 **cov** (协方差)变量是提供给优化器的不允许改变的输入。
**因此,优化器所做的是,在给定我们提供的预期回报和协方差矩阵的情况下,搜索使 func 最小化的投资组合权重向量(W)。**
在函数的最后,你会看到我返回了 **optimal_weights['x']** 。这是因为在优化器对象中,我们从 mimimize 返回的‘x’属于优化的权重 w。
W = np.ones((factor_moments.shape[0],1))*(1.0/factor_moments.shape[0])# Function that runs optimizer
def optimize(func, W, exp_ret, cov, target_return):
opt_bounds = Bounds(0, 1)
opt_constraints = ({'type': 'eq',
'fun': lambda W: 1.0 - np.sum(W)},
{'type': 'eq',
'fun': lambda W: target_return - W.T@exp_ret}) optimal_weights = minimize(func, W,
args=(exp_ret, cov),
method='SLSQP',
bounds=opt_bounds,
constraints=opt_constraints)
return optimal_weights['x']
您可能会注意到,minimize 还可以接受两个可选参数— **边界**和**约束**。这些很重要,所以让我们一个一个地看。界限很简单。我们希望 W 中的每个权重介于 0 和 1 之间,换句话说,没有负权重或杠杆:
opt_bounds = Bounds(0, 1)
对于约束条件,我们有两个——**我们希望我们的权重总和为 1** (为了使它成为一个合适的投资组合),以及**我们希望实现预先指定的目标回报**(你也可以将其设置为目标风险,或者完全不考虑)。我们设定回报目标的原因是为了避免这样的情况:我们优化并获得了一个甜蜜而多样化的投资组合,但该投资组合的预期回报是 3%或其他一些太低的值。
opt_constraints = ({'type': 'eq',
'fun': lambda W: 1.0 - np.sum(W)},
{'type': 'eq',
'fun': lambda W: target_return - W.T@exp_ret})
现在让我们来看看我之前跳过的那部分代码。一、什么是 **func** ?当我们求解最优投资组合时,我们试图找到每单位风险回报最高的投资组合(其中风险是投资组合的标准差)。
**所以我们要最大化回报率,我们可以计算为 W.T@exp_ret** (这将每项资产的回报率乘以其权重并求和)**和风险,我们可以计算为 W . T @ cov @ W .**@字符表示矩阵乘法。
由于我们使用了一个优化函数来最小化事物,我们需要在我们的风险回报率上加上一个负号——这样当我们最小化它时,我们实际上是在最大化它。
Function to optimize
def ret_risk(W, exp_ret, cov):
return -((W.T@exp_ret) / (W.T@cov@W)**0.5)
现在剩下要做的就是优化我们的产品组合:
x = optimize(ret_risk, W, expected_returns, cov,
target_return=0.055)
以下是最佳重量的样子:

最佳投资组合权重(作者制作的图表)
重量方面突出的几件事:
* 小型股和新兴市场的预期回报率最高,但权重不高。这是因为它们的波动性(又称风险)明显高于标准普尔 500(见下图)。此外,它们与标准普尔 500 高度相关,因此很少提供多样化。
* 美国国债的预期回报率为负,但却是权重第二高的资产类别。这是因为它也是与股票相关性最小的资产类别(负相关性约为-0.40)。因此,实际上,当股市崩盘时,投资组合的回报依赖于股票和高收益债券,保险依赖于美国国债。
* 尽管石油回报率相对较高,与其他资产的相关性较低,但它的波动性太大,因此权重较低。

每个资产类别的年化标准差(由作者创建的图表)
# 结论
这就是 SciPy 的优化。投资组合策略过程的下一步将是尽最大努力来衡量模型和估计误差的影响。也就是说,我们想知道哪些输入可能是错误指定的(测量误差),以及我们的模型输出对这种误差有多敏感。提示:预期收益是非常嘈杂的,优化的输出对预期收益的微小变化都非常敏感。下一次,我们将看看如何解决这个问题。干杯!
[***如果你总体上喜欢这篇文章和我的写作,请考虑通过我在这里的推荐链接注册 Medium 来支持我的写作。谢谢!***](https://tonester524.medium.com/membership)
# 将想法移植到数学:图形套索的逐步推导
> 原文:<https://towardsdatascience.com/porting-ideas-to-math-a-step-by-step-derivation-of-graphical-lasso-2e01f7165d95?source=collection_archive---------31----------------------->
TLDR:如果你像我一样对数学一无所知,你可能会发现大多数关于图形套索的教程文章第一眼看上去很难理解,而且推导步骤通常是不存在的。为了使它更容易理解,这篇文章将分解这个算法,带领读者通过可口的片段,并帮助发展对算法理论基础的直观理解。

JESHOOTS.COM 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上[的照片](https://unsplash.com/@jeshoots?utm_source=medium&utm_medium=referral)
正如诺姆·乔姆斯基所说,我解释说:人类的认知过程实际上是符号操作,以不同的方式发泄出来(想想语法)会产生不同的语言。数学只是另一种让我们简洁描述事物的语言。
以下部分将使用图形套索来说明如何直观地将您的想法转换为数学语言,作为我上一篇关于图形套索的文章的续篇([https://towardsdatascience . com/machine-learning-in-action-in-finance-using-graphical-lasso-to-identify-trading-pairs-in-fa 00d 29 c 71 a 7](/machine-learning-in-action-in-finance-using-graphical-lasso-to-identify-trading-pairs-in-fa00d29c71a7?source=your_stories_page---------------------------))。
# 问题是
假设我们有 p 个股票代号,每个代号都记录了 N 天的收盘价,我们希望计算出股票代号之间的部分相关性,用精度矩阵表示,并从中绘制出一个无向图。这是我们要解决的问题。
# 假设
所有的模型或算法都基于一组假设,这些假设往往会简化问题,使问题与我们已经有解决方案的问题相似。因此,几乎没有模型以像素完美的方式反映现实,但请记住这句老话:“所有的模型都是错的,但有些是有用的”。
因此,为了重新表述我们的问题,我们说有 N 个观测值,每个都是 p 维正态分布的;换句话说,现在我们有了一个 N*p 矩阵。
显然,我们这里的大假设是多维常态。对于那些好奇的人来说,这里有一些对常态普遍偏爱的理由/论据:
1. 它使数学变得简单——用你我这样的平民的话说,这意味着试图避开复杂/混乱的数学。是的,它导致更容易的几何解释和更容易的参数估计。
2. *还记得中心极限定理吗?许多独立统计分布的和最终收敛于正态分布。如今单子很难找到,我们所使用的功能(价格等)对 CLT 也不例外。*
3. *还记得热力学第二定律吗?孤立系统的总熵从来不会减少,在非理想条件下总是增加(读,在几乎所有现实世界的条件下)。正态分布是所有具有特定均值和协方差的实值分布中熵最大的一种分布。*
注意上面的 2 和 3 之间似乎有一些有趣的联系。一定要深入挖掘。

一条钟形曲线(来源:[https://en . Wikipedia . org/wiki/File:Standard _ deviation _ diagram . SVG](https://en.wikipedia.org/wiki/File:Standard_deviation_diagram.svg))
现在,我们已经制定了数据矩阵和数据的分布,我们如何从这里开始解决我们的问题?关键是从我们数据的精度(逆协方差)矩阵到我们想要的无向图有一个映射。
# 用精确矩阵连接无向图
让我们看一个假设的无向图:

重点放在顶点 A、B 和 c 上,通过无向图或马尔可夫场更正式的性质,它们的联合分布可以分解为:
*P(A,B,C) = P(A,B|C)P(C) = P(A|C)P(B|C)P(C)*
即给定 c,A 和 B 是条件独立的。
在无向图中,如果 C 阻塞 A 和 B,那么给定 C,A 和 B 是条件独立的。
注意,我们也有 P(A,B,C,D,E) = P(A|C,D,E)P(B|C,D,E)P(C,D,E),因为 C,D,E 可以看成是把 A 和 B 堵在一起。
关于精度矩阵,条件独立变量告诉我们什么?
结论首先:**我们可以说明,给定图中所有其他变量,两个变量条件独立对应精度矩阵中对应单元格的值 0。**
为了说明这一点,让我们首先回顾一下关于条件高斯分布的一些事实:

对角矩阵的逆也是对角的。现在我们已经表明,如果两个维度 I 和 j 是条件独立的,它们在精度矩阵中的对应项将是 0。
有了所有这些假设和事实,我们现在准备处理估计精度矩阵的问题。
# 数学公式
现在我们能够对这个问题进行数学表述了:

我们走了很长一段路才找到这种形式,它更容易使用,也更清晰。**现在让我们不要忘记我们最初的目标:估计精度矩阵**。为此,我们将首先尝试估计协方差矩阵,从中我们将最终得到精度矩阵。
# 更深入

# 解决方案
我们快到了。在制定算法之前,让我们再看一些东西。首先,请注意,如果我们在目标函数中对 X 取次梯度:

# 结束了
这就是我如何冗长地推导图形套索算法,我希望血淋淋的细节不会让我的读者感到厌烦,并实际上有助于消除一些疑虑,填补一些空白,而不是涵盖在这个主题的其他地方。如果你发现一些错误或对此有任何疑问,请务必告诉我。
最后,我为不得不从我自己的笔记中复制粘贴而道歉,因为 Medium 似乎不太支持数学方程。
# 使用 RNN 的词性标注
> 原文:<https://towardsdatascience.com/pos-tagging-using-rnn-7f08a522f849?source=collection_archive---------1----------------------->
## 了解如何使用 rnn 在英语语料库中使用词性(POS)标签来标记单词

安格尔·坎普在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
做**词性标注**的经典方式是使用**隐马尔可夫模型的某种变体。**在这里,我们将看到如何使用递归神经网络来实现这一点。最初的 RNN 建筑也有一些变化。它有一个新颖的 RNN 架构——**双向 RNN** ,能够以“逆序”读取序列,并已被证明可以显著提高性能。
然后是 RNN 的两个重要的前沿变体,它们使得在真实数据集上训练大型网络成为可能。尽管 rnn 能够解决各种序列问题,但是由于在 rnn 的训练期间出现的爆炸和消失梯度的问题,它们的架构本身是它们最大的敌人。这个问题由两个流行的**门控 RNN 架构**—**长、短时记忆(LSTM)** 和**门控递归单元(GRU)解决。**我们将在这里研究所有这些与词性标注相关的模型。
# 词性标注—概述
将单词分类到它们的**词性**并相应地标注它们的过程被称为**词性标注**,或者简称为**词性标注**。NLTK 库有许多包含单词及其词性标签的语料库。我将使用来自 NLTK 的带词性标记的语料库,即 **treebank** 、 **conll2000、**和 **brown** 来演示关键概念。为了直接进入代码,Kaggle 上发布了一个附带的[笔记本](https://www.kaggle.com/tanyadayanand/pos-tagging-using-rnn)。
[](https://www.kaggle.com/tanyadayanand/pos-tagging-using-rnn) [## 使用 RNN 的词性标注
### 使用 Kaggle 笔记本探索和运行机器学习代码|使用来自单词嵌入的数据
www.kaggle.com](https://www.kaggle.com/tanyadayanand/pos-tagging-using-rnn)
下表提供了一些主要标签的信息:

**位置标记**
# 文章布局
1. 预处理数据
2. 单词嵌入
3. 香草 RNN
4. LSTM
5. 苏军总参谋部情报总局
6. 双向 LSTM
7. 模型评估
# 导入数据集
让我们从导入必要的库和加载数据集开始。这是每一个数据分析过程中必不可少的一步(完整的代码可以在[这里](https://www.kaggle.com/tanyadayanand/pos-tagging-using-rnn)查看)。我们将首先使用三个著名的文本语料库加载数据,并对它们进行合并。
***# Importing and Loading the data into data frame
load POS tagged corpora from NLTK***
treebank_corpus = treebank.tagged_sents(tagset='universal')
brown_corpus = brown.tagged_sents(tagset='universal')
conll_corpus = conll2000.tagged_sents(tagset='universal')
# Merging the dataframes to create a master df tagged_sentences = treebank_corpus + brown_corpus + conll_corpus
# **1。预处理数据**
作为预处理的一部分,我们将执行各种步骤,例如将数据分成单词和标签,对 X 和 Y 进行矢量化,以及填充序列。
我们先来看数据。对于下面的每个单词,都有一个与之相关的标签。
# let's look at the data
tagged_sentences[7]

## 将数据分为单词(X)和标签(Y)
由于这是一个**多对多**问题,每个数据点将是语料库的不同句子。每个数据点在**输入序列**中都有多个字。这就是我们所说的 **X** 。每个单词在**输出序列**中都有相应的标签。这就是我们所说的 **Y** 。样本数据集:

X = [] # store input sequence
Y = [] # store output sequencefor sentence in tagged_sentences:
X_sentence = []
Y_sentence = []
for entity in sentence:
X_sentence.append(entity[0]) # entity[0] contains the word
Y_sentence.append(entity[1]) # entity[1] contains corresponding tag
X.append(X_sentence)
Y.append(Y_sentence)num_words = len(set([word.lower() for sentence in X for word in sentence]))
num_tags = len(set([word.lower() for sentence in Y for word in sentence]))print("Total number of tagged sentences: {}".format(len(X)))
print("Vocabulary size: {}".format(num_words))
print("Total number of tags: {}".format(num_tags))

***# let’s look at first data point
this is one data point that will be fed to the RNN***
print(‘sample X: ‘, X[0], ‘\n’)
print(‘sample Y: ‘, Y[0], ‘\n’)

***# In this many-to-many problem, the length of each input and output sequence must be the same.
Since each word is tagged, it’s important to make sure that the length of input sequence equals the output sequence***print(“Length of first input sequence : {}”.format(len(X[0])))
print(“Length of first output sequence : {}”.format(len(Y[0])))

我们需要解决的下一件事是,我们如何将这些输入提供给 RNN。如果我们必须把单词作为神经网络的输入,那么我们必须把它们转换成数字。我们需要创建一个单词嵌入或一个热点矢量,即每个单词的数字形式的矢量。首先,我们将首先对输入和输出进行编码,这将为输入数据的整个语料库中的每个单词提供一个盲唯一 id。另一方面,我们有 Y 矩阵(标签/输出数据)。我们这里有 12 个 pos 标签,将它们中的每一个视为一个类,每个 POS 标签都被转换为长度为 12 的独热编码。我们将使用 Keras 库中的 Tokenizer()函数将文本序列编码为整数序列。
## 向量化 X 和 Y
# encode X word_tokenizer = Tokenizer() # instantiate tokeniser
word_tokenizer.fit_on_texts(X) # fit tokeniser on data# use the tokeniser to encode input sequence
X_encoded = word_tokenizer.texts_to_sequences(X) # encode Y tag_tokenizer = Tokenizer()
tag_tokenizer.fit_on_texts(Y)
Y_encoded = tag_tokenizer.texts_to_sequences(Y)# look at first encoded data point print("** Raw data point ", "\n", "-"*100, "\n")
print('X: ', X[0], '\n')
print('Y: ', Y[0], '\n')
print()
print(" Encoded data point **", "\n", "-"*100, "\n")
print('X: ', X_encoded[0], '\n')
print('Y: ', Y_encoded[0], '\n')

确保每个输入和输出序列的长度相同。
## 填充序列
语料库中的句子长度不同。在我们输入 RNN 模型之前,我们需要确定句子的长度。我们不能动态分配处理语料库中每个句子所需的内存,因为它们的长度不同。因此,数据编码后的下一步是**定义序列长度**。我们需要要么填充短句,要么把长句截成固定长度。然而,这个固定长度是一个**超参数**。
***# Pad each sequence to MAX_SEQ_LENGTH using KERAS’ pad_sequences() function.
Sentences longer than MAX_SEQ_LENGTH are truncated.
Sentences shorter than MAX_SEQ_LENGTH are padded with zeroes.******# Truncation and padding can either be ‘pre’ or ‘post’.
For padding we are using ‘pre’ padding type, that is, add zeroes on the left side.
For truncation, we are using ‘post’, that is, truncate a sentence from right side.***# sequences greater than 100 in length will be truncated MAX_SEQ_LENGTH = 100X_padded = pad_sequences(X_encoded, maxlen=MAX_SEQ_LENGTH, padding=”pre”, truncating=”post”)
Y_padded = pad_sequences(Y_encoded, maxlen=MAX_SEQ_LENGTH, padding=”pre”, truncating=”post”)# print the first sequence
print(X_padded[0], "\n"*3)
print(Y_padded[0])

# 2.单词嵌入
你知道一种更好的表示文本的方式是**单词嵌入**。目前,每个单词和每个标签都被编码为一个整数。我们将使用一种更复杂的技术来表示输入单词(X ),这就是所谓的单词嵌入。
然而,为了表示 Y 中的每个标签,我们将简单地使用独热编码方案,因为数据集中只有 12 个标签,并且 LSTM 在学习这些标签的自己的表示时没有问题。
要使用单词嵌入,您可以使用以下任一模型:
1. [**word2vec 型号**](https://code.google.com/archive/p/word2vec/)
2. [**手套型号**](https://nlp.stanford.edu/projects/glove/)
我们使用 word2vec 模型没有特别的原因。这两者在表示单词方面都非常高效。你可以两个都试试,看看哪个效果更好。
**一个单词嵌入的维数是:(词汇 _ 大小,嵌入 _ 维数)**
## 对输入序列使用单词嵌入(X)
# word2vec path = ‘../input/wordembeddings/GoogleNews-vectors-negative300.bin’# load word2vec using the following function present in the gensim library
word2vec = KeyedVectors.load_word2vec_format(path, binary=True)***# assign word vectors from word2vec model
each word in word2vec model is represented using a 300 dimensional vector***EMBEDDING_SIZE = 300
VOCABULARY_SIZE = len(word_tokenizer.word_index) + 1# create an empty embedding matix
embedding_weights = np.zeros((VOCABULARY_SIZE, EMBEDDING_SIZE))# create a word to index dictionary mapping
word2id = word_tokenizer.word_index# copy vectors from word2vec model to the words present in corpus
for word, index in word2id.items():
try:
embedding_weights[index, :] = word2vec[word]
except KeyError:
pass
## 对输出序列使用一键编码(Y)
use Keras’ to_categorical function to one-hot encode Y
Y = to_categorical(Y)
所有的数据预处理现在都完成了。现在让我们通过**将数据分割为训练、验证和测试集**来跳转到建模部分。
在使用 RNN 之前,我们必须确保数据的维度是 RNN 所期望的。一般来说,RNN 人期望以下形状
**X 的形状:(#样本,#时间步长,#特征)**
**Y 的形状:(#样本,#时间步长,#特征)**
现在,根据建筑的类型,你可以用不同的形状来制作 RNN。由于我们正在研究的问题具有多对多的架构,输入和输出都包括时间步长的数量,而时间步长就是序列长度。但是注意张量 X 没有第三维度,也就是特征数。这是因为在将数据输入 RNN 之前,我们将使用单词嵌入,因此没有必要明确提到第三个维度。这是因为当您在 Keras 中使用 Embedding()图层时,训练数据将自动转换为( **#samples、#timesteps、#features** ),其中 **#features** 将是嵌入维度(请注意,嵌入图层始终是 RNN 的第一个图层)。使用嵌入层时,我们只需要将数据整形为我们已经完成的(#samples,#timesteps)。但是,请注意,如果不使用 Keras 中的 Embedding()层,您需要将其调整为(#samples、#timesteps、#features)。
# 3.香草 RNN
接下来,让我们建立 RNN 模型。我们将使用单词嵌入来表示单词。现在,在训练模型的同时,你也可以**训练单词嵌入**和网络权重。这些通常被称为**嵌入权重**。训练时,嵌入权重将被视为网络的正常权重,在每次迭代中更新。
在接下来的几节中,我们将尝试以下三种 RNN 模型:
* 具有任意初始化的**的 RNN,不可训练的嵌入**:在这个模型中,我们将任意初始化嵌入权重。此外,我们将**冻结嵌入**,也就是说,我们将不允许网络训练它们。
* RNN 与**任意初始化,可训练的嵌入**:在这个模型中,我们将允许网络训练嵌入。
* 具有**可训练 word2vec 嵌入的 RNN:**在这个实验中,我们将使用 word2vec 单词嵌入*和*也允许网络进一步训练它们。
## 未初始化的固定嵌入
让我们从第一个实验开始:一个普通的 RNN,带有任意初始化的、不可训练的嵌入。对于这个 RNN,我们不会使用预先训练的单词嵌入。我们将使用随机初始化的嵌入。此外,我们不会更新嵌入权重。
# create architecture rnn_model = Sequential()***# create embedding layer — usually the first layer in text problems
vocabulary size — number of unique words in data*** rnn_model.add(Embedding(input_dim = VOCABULARY_SIZE,
# length of vector with which each word is represented
output_dim = EMBEDDING_SIZE,
# length of input sequence
input_length = MAX_SEQ_LENGTH,
# False — don’t update the embeddings
trainable = False
))***# add an RNN layer which contains 64 RNN cells
True — return whole sequence; False — return single output of the end of the sequence*** rnn_model.add(SimpleRNN(64,
return_sequences=True
))# add time distributed (output at each sequence) layer
rnn_model.add(TimeDistributed(Dense(NUM_CLASSES, activation=’softmax’)))#compile model
rnn_model.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['acc'])# check summary of the model
rnn_model.summary()

#fit model
rnn_training = rnn_model.fit(X_train, Y_train, batch_size=128, epochs=10, validation_data=(X_validation, Y_validation))

我们可以在这里看到,在十个纪元之后,它给出了大约 95%的相当不错的**准确度。**此外,我们在下图中看到了一条健康的增长曲线。

## 未初始化的可训练嵌入
接下来,尝试第二种模型——带有任意初始化的**的 RNN,可训练的嵌入**。这里,我们将允许嵌入与网络一起训练。我所做的只是将参数**trainiable 改为 true,即 trainable = True。**其余一切同上。在检查模型摘要时,我们可以看到所有的参数都是可训练的。即可训练参数等于总参数。
# check summary of the model
rnn_model.summary()

在拟合模型时,精确度显著提高。通过允许嵌入权重训练,它已经上升到大约 98.95%。因此,嵌入对网络的性能有着重要的影响。

我们现在将尝试 word2vec 嵌入,看看它是否能改进我们的模型。
## 使用预先训练的嵌入权重
现在让我们尝试第三个实验——使用**可训练 word2vec 嵌入的 RNN。**回想一下,我们已经在一个名为‘embedding _ weights’的矩阵中加载了 word2vec 嵌入。使用 word2vec 嵌入就像在模型架构中包含这个矩阵一样简单。
网络架构与上面相同,但是我们将使用来自 word2vec 的预训练嵌入权重(**weights =【embedding _ weights】**),而不是从任意嵌入矩阵开始。在这种情况下,精确度进一步提高到了**大约 99.04%。**

在这种情况下,结果略有改善。那是因为这个模型已经表现得很好了。在没有如此好的模型性能的情况下,通过使用预先训练的嵌入,您将看到更多的改进。预训练的嵌入在许多应用中提供了真正的提升。
# 4.LSTM
为了解决渐变消失的问题,人们已经做了很多尝试来调整传统的 RNNs,使得当序列变长时,渐变不会消失。这些尝试中最受欢迎和最成功的是**长短期记忆网络**,或 **LSTM** 。LSTMs 被证明是如此有效,以至于它们几乎取代了普通的 rnn。
因此,RNN 和 LSTM 之间的一个根本区别是,LSTM 有一个**外显记忆** **单元**,它存储与学习某些任务相关的信息。在标准 RNN 中,网络记忆过去信息的唯一方式是随着时间的推移更新隐藏状态,但它没有显式的内存来存储信息。
另一方面,在 LSTMs 中,即使序列变得很长,存储单元也能保留信息片段。
接下来,我们将建立一个 LSTM 模型,而不是 RNN。我们只需要用 LSTM 层替换 RNN 层。
# create architecture lstm_model = Sequential()
***# vocabulary size — number of unique words in data
length of vector with which each word is represented*** lstm_model.add(Embedding(input_dim = VOCABULARY_SIZE,
output_dim = EMBEDDING_SIZE,
# length of input sequence input_length = MAX_SEQ_LENGTH,
# word embedding matrix weights = [embedding_weights],
# True — update embeddings_weight matrix trainable = True
))***# add an LSTM layer which contains 64 LSTM cells
True — return whole sequence; False — return single output of the end of the sequence***
lstm_model.add(LSTM(64, return_sequences=True))
lstm_model.add(TimeDistributed(Dense(NUM_CLASSES, activation=’softmax’)))#compile model
rnn_model.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['acc'])# check summary of the model
rnn_model.summary()

lstm_training = lstm_model.fit(X_train, Y_train, batch_size=128, epochs=10, validation_data=(X_validation, Y_validation))

LSTM 模式也提供了一些边际改进。然而,如果我们在其他任务中使用 LSTM 模型,如语言翻译、图像字幕、时间序列预测等。那么您可能会看到性能的显著提升。
# 5.苏军总参谋部情报总局
考虑到计算开销和过度拟合的问题,研究人员试图提出 LSTM 单元的替代结构。这些替代方案中最受欢迎的是**门控循环单元(GRU)。作为一个比 LSTM 更简单的车型,GRU 总是更容易训练。LSTMs 和 GRUs 在实践中几乎完全取代了标准的 RNNs,因为它们比普通的 RNNs 更有效,训练速度更快(尽管参数数量更多)。**
现在让我们建立一个 GRU 模型。然后,我们还将比较 RNN、LSTM 和 GRU 模型的性能。
# create architecture lstm_model = Sequential()
***# vocabulary size — number of unique words in data
length of vector with which each word is represented*** lstm_model.add(Embedding(input_dim = VOCABULARY_SIZE,
output_dim = EMBEDDING_SIZE,
# length of input sequence input_length = MAX_SEQ_LENGTH,
# word embedding matrix weights = [embedding_weights],
# True — update embeddings_weight matrix trainable = True
))***# add an LSTM layer which contains 64 LSTM cells
True — return whole sequence; False — return single output of the end of the sequence***
lstm_model.add(GRU(64, return_sequences=True))
lstm_model.add(TimeDistributed(Dense(NUM_CLASSES, activation=’softmax’)))#compile model
rnn_model.compile(loss = 'categorical_crossentropy',
optimizer = 'adam',
metrics = ['acc'])# check summary of the model
rnn_model.summary()

与 LSTM 相比,GRU 的参数有所减少。因此,我们在计算效率方面得到了显著的提高,而模型的性能几乎没有任何下降。
gru_training = gru_model.fit(X_train, Y_train, batch_size=128, epochs=10, validation_data=(X_validation, Y_validation))

该模型的精度与 LSTM 相同。但是我们看到 LSTM 花费的时间比 GRU 和 RNN 要长。这是意料之中的,因为 LSTM 和 GRU 的参数分别是正常 RNN 的 4 倍和 3 倍。
# 6.双向 LSTM
例如,当你想**给一段文字(比如一篇客户评论)分配一个情感分数**时,网络可以在给它们分配分数之前看到整个评论文字。另一方面,在给定先前几个键入的单词的情况下,在诸如**预测下一个单词**的任务中,在预测下一个单词时,网络不能访问未来时间步中的单词。
这**两类任务**分别称为离线**和在线**序列处理。
现在,你可以用一个巧妙的技巧来处理**离线任务**——既然网络在做出预测之前可以访问整个序列,为什么不使用这个任务来让网络在训练时“查看序列中的未来元素”,希望这将使网络学习得更好?
这就是所谓的**双向 RNNs** 所利用的想法。
通过使用双向 RNNs,几乎可以肯定你会得到更好的结果。然而,由于网络参数的数量增加,双向 rnn 花费几乎两倍的时间来训练。因此,您需要在训练时间和性能之间进行权衡。使用双向 RNN 的决定取决于您拥有的计算资源和您想要的性能。
最后,让我们再构建一个模型——一个**双向 LSTM** ,并与之前的模型在准确性和训练时间方面进行比较。
# create architecturebidirect_model = Sequential()
bidirect_model.add(Embedding(input_dim = VOCABULARY_SIZE,
output_dim = EMBEDDING_SIZE,
input_length = MAX_SEQ_LENGTH,
weights = [embedding_weights],
trainable = True
))
bidirect_model.add(Bidirectional(LSTM(64, return_sequences=True)))
bidirect_model.add(TimeDistributed(Dense(NUM_CLASSES, activation=’softmax’)))#compile model bidirect_model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['acc'])# check summary of model
bidirect_model.summary()

您可以看到参数的数量增加了。它确实大大提高了参数的数量。
bidirect_training = bidirect_model.fit(X_train, Y_train, batch_size=128, epochs=10, validation_data=(X_validation, Y_validation))

双向 LSTM 确实大大提高了精确度(考虑到精确度已经达到顶点)。这显示了双向 LSTMs 的威力。然而,这种精度的提高是有代价的。所花的时间几乎是普通 LSTM 网络的两倍。
# 7.模型评估
下面是我们尝试的四种模式的快速总结。当我们从一种模式转向另一种模式时,我们可以看到一种趋势。
loss, accuracy = rnn_model.evaluate(X_test, Y_test, verbose = 1)
print(“Loss: {0},\nAccuracy: {1}”.format(loss, accuracy))

loss, accuracy = lstm_model.evaluate(X_test, Y_test, verbose = 1)
print(“Loss: {0},\nAccuracy: {1}”.format(loss, accuracy))

loss, accuracy = gru_model.evaluate(X_test, Y_test, verbose = 1)
print(“Loss: {0},\nAccuracy: {1}”.format(loss, accuracy))

loss, accuracy = bidirect_model.evaluate(X_test, Y_test, verbose = 1)
print("Loss: {0},\nAccuracy: {1}".format(loss, accuracy))

如果你有任何问题、建议或批评,可以通过 LinkedIn 或评论区联系我。
# 合成媒体的正面使用案例(又名 Deepfakes)
> 原文:<https://towardsdatascience.com/positive-use-cases-of-deepfakes-49f510056387?source=collection_archive---------5----------------------->

从 [diego cervo](https://stock.adobe.com/contributor/38908/diego-cervo?load_type=author&prev_url=detail) 处获得许可——Adobe Stock
## Deepfakes 可以为所有人创造无数的可能性和机会,无论他们是谁,如何与周围的世界互动。
技术是一个很好的使能因素,可以赋予人很大的力量。由于数据科学和人工智能的进步,赋权的新想法和能力已经出现。人工智能可以为所有人创造可能性和机会,无论他们是谁,如何听、说或交流。
> [这本书现已在亚马逊上架——https://www . Amazon . com/deep fakes-aka-Synthetic-Media-Humanity-ebook/DP/b0b 846 ycnj/](https://www.amazon.com/Deepfakes-aka-Synthetic-Media-Humanity-ebook/dp/B0B846YCNJ/)
人工智能生成的合成媒体,也称为 deepfakes,有许多积极的用例。[人工智能生成的合成媒体,又名 Deepfakes](/ai-generated-synthetic-media-aka-deepfakes-7c021dea40e1) ,在某些领域取得了明显的进步,如可访问性、教育、电影制作、刑事取证和艺术表达。
在本文中,我将探索 deepfakes 的一些积极用例。我坚信,随着技术的发展和社会对 deepfake 现象的裁决,deepfakes 的大多数用例将会改善人们的生活,并赋予社区和机构权力。
> 科技可以给人们声音、目标和快速产生大规模影响的能力。
## 易接近
人工智能可以建立工具来听、看,并且很快用人工一般智能(AGI),推理越来越准确。人工智能生成的合成媒体可以帮助使辅助工具更加智能,在某些情况下,甚至可以负担得起和个性化,这可以帮助人们扩大他们的代理并获得独立性。技术,特别是基于人工智能的工具,可以为所有人带来无障碍的解决方案。
> **Deepfake 可以加速可访问性探索,从而提高公平性。**
微软的[seening . AI](https://www.microsoft.com/en-us/ai/seeing-ai)和谷歌的 [Lookout](https://www.blog.google/topics/accessibility/lookout-app-help-blind-and-visually-impaired-people-learn-about-their-surroundings/) 利用人工智能进行识别和合成语音来讲述物体、人和世界。人工智能生成的合成媒体可以为步行旅行的个性化辅助导航应用提供动力。
触觉手杖控制器 cane controller 可以通过模拟和手杖互动帮助视力障碍者在虚拟现实世界中导航。它可以使有视觉障碍的人通过将他们的手杖技能转移到虚拟世界中来导航虚拟环境。这项技术有助于实现平等和赋权。
对于[肌萎缩侧索硬化症](https://medlineplus.gov/amyotrophiclateralsclerosis.html) (ALS)患者来说,合成声音非常有力量,因为这种可怕的疾病影响了说话、交流和运动技能的能力。想象一下,即使失去了说话的能力,也能和你爱的人用自己的声音说话。[为 ALS 患者提供技术、设备和服务的 Gleason 团队](http://www.teamgleason.org/),正在与科技公司合作,为 ALS(卢·格里克病)患者实现和开发人工智能生成的合成媒体场景。
还有其他合成语音的使用案例。 [VOCALiD](https://vocalid.ai/) 利用 voicebank 和专有的语音混合技术为任何设备创建独特的人声角色,为有语言和听力障碍的人将文本转换为语音。合成声音也是使这些病人能够独立的必要条件。低沉的假声音也有助于天生的语言障碍。
## 教育
Deepfake 技术促进了教育领域的许多可能性。学校和老师在课堂上使用媒体、音频、视频已经有一段时间了。Deepfakes 可以帮助教育工作者提供比传统视觉和媒体形式更具吸引力的创新课程。
人工智能生成的合成媒体可以将历史人物带回生活,以实现更具吸引力和互动性的课堂。一个合成的重演视频或历史人物的声音和视频可能会更有影响力,更有吸引力,并且会是一个更好的学习工具。例如,JFK 结束冷战的决议是演讲,但从未发表过,是[重新创作的](https://www.cereproc.com/en/jfkunsilenced)使用合成声音,他的声音和演讲风格显然会让学生以一种创造性的方式学习这个问题。
合成人体解剖学、复杂的工业机械和复杂的工业项目可以在混合现实世界中建模和模拟,以便使用微软 [Hololens](https://www.microsoft.com/en-us/education/mixed-reality) 教授学生并进行合作。
> **创造性地使用合成语音和视频可以在规模和有限成本的情况下提高整体成功和学习成果。**
## 艺术
几十年来,好莱坞一直使用高端 CGI、VFX 和 SFX 技术来创造人工但可信的世界,以引人入胜地讲述故事。在 1994 年的电影《阿甘正传》中,主角遇到了 JFK 和其他历史人物。场景和效果的[创作](https://snippetofhistory.wordpress.com/portfolio/forrest-gump-with-president-john-f-kennedy-1994-movie/)是使用 CGI 和不同的技术完成的,耗资数百万美元。如今,复杂的 CGI 和 VFX 技术在电影中被用来生成合成媒体,以讲述一个迷人的故事。
> **Deepfakes 可以将昂贵的 VFX 技术大众化,成为独立故事讲述者的强大工具,而成本只是其一小部分。**
Deepfakes 是一个很好的工具,可以真实地实现喜剧或戏仿中真实事件的反映、延伸、扭曲和挪用。人工智能生成的合成媒体可以在娱乐业务中带来前所未有的机会,我们看到独立创作者或 YouTube 实现了很多机会。使用 GANS 的电影 deepfake 的一些很好的例子是 YouTube 的创作者,如 [ctrl shift face](https://www.youtube.com/channel/UCKpH0CKltc73e4wh0_pgL3g/videos) 和 [shamook](https://www.youtube.com/channel/UCZXbWcv7fSZFTAZV4beckyw/videos) 。
文化和娱乐企业可以出于艺术目的使用 deepfakes。佛罗里达州圣彼得堡的达利博物馆举办了一场名为[达利生活](https://www.theverge.com/2019/5/10/18540953/salvador-dali-lives-deepfake-museum)的展览,利用 deepfakes 让参观者与超现实主义画家萨瓦尔多·达利互动并自拍,让他重获新生。同样,三星在莫斯科的人工智能实验室通过使用 Deepfake 技术使[蒙娜丽莎](https://www.bbc.com/news/technology-48395521)栩栩如生。
在视频游戏行业,人工智能生成的图形和图像可以加快游戏创作的速度。Nvidia 演示了由 deepfakes 创建的混合游戏环境,并正在努力将其推向市场。
音频讲故事和书籍旁白是合成语音的另一个很好的用例。作者的合成声音字体可用于创建作者的书的音频格式。企业可以使用不同语言的同一演员的合成画外音来扩大其内容的覆盖范围。实现上述场景的创造性语音技术必须以道德和负责任的方式使用[ [1](https://medium.com/microsoft-design/responsible-innovation-the-next-wave-of-design-thinking-86bc9e9a8ae8) ],并有一个健全的同意框架,因为它对语音艺术家的生计和代理有直接影响。
## 自主与表达
合成媒体可以帮助人权活动家和记者在独裁和压迫政权中保持匿名。对于公民记者和活动人士来说,利用技术在传统或社交媒体上报道暴行是非常有力量的。Deepfake 可以用来匿名语音和面部,以保护他们的隐私。
Deepfakes 可用于为在线个人创建化身体验以进行自我表达。个人数字化身给予了自主权,可以帮助个人扩展他们的目的、想法和信念,并使自我表达成为可能,否则这对于一些人来说可能是困难的。患有某些身体或精神残疾的个人可以使用自己的合成化身进行在线自我表达。
> **Deepfakes 可以给个人在网络世界中自我表达和融入的新工具。**
联合国儿童基金会和麻省理工学院的项目“深度同理心”利用深度学习来了解受冲突影响的叙利亚社区的特征。然后,它模拟了世界各地的城市在类似的冲突中会是什么样子。该项目创建了波士顿、伦敦和世界其他主要城市的合成战争图像,以帮助增加对灾区受害者的同情。
有一些语音技术初创公司将创造合成语音作为一种新的丧亲疗法,或帮助人们记住死者并与他们联系。
## 延伸和信息放大
去年 4 月,一家健康慈善机构与大卫·贝克汉姆合作,制作了一个视频和语音宣传活动,以帮助终结疟疾。在“消灭疟疾”活动中,贝克汉姆无缝地讲了九种语言,以响应公众的呼吁。这场社会运动是一个很好的例子,它利用 deepfakes 来扩大公共信息的范围。[小贝视频背后的公司 Synthesia](https://www.synthesia.io/) 和语音初创公司 [VOCALiD](https://vocalid.ai/) 开发工具,将视频和音频内容本地化,用于学习工具、品牌营销、观众参与、客户服务和公共信息,以扩大信息的覆盖范围和传播范围。
文本到语音模型可以通过 podcaster 的声音字体帮助创建播客,以更少的错误和更快的速度从文本创建合成音频。
影响者可以利用 Deepfakes 来扩大他们的影响范围,增加他们的受众。使用 deepfakes,一个品牌可以通过高度针对性和个性化的信息接触到许多客户。Zalando 与 Cara Delevigne 一起执行了一项活动,该活动可以通过有影响力的视频镜头和声音字体变得更加个性化。19 岁的 CG“玉米卷卡车专家”和社交媒体名人 Lil Miquela 拥有 240 万粉丝。数字模型、人工智能生成的深度假货正在成为时尚和品牌营销的新趋势。
[人工智能基金会](https://aifoundation.com/)正在为有影响力的人和名人创建个人人工智能,征得他们的同意,以吸引和扩大他们与观众的接触,与粉丝建立更深层次的互动,并大规模提供个人体验。艾基金会最近推出了狄巴克·乔布拉的个人数字头像。
> **Deepfakes 将影响者营销带到了另一个高度。**
在德里选举的前几天,印度的一名政客创造了一个深度骗局来吸引不同语言的选民。这是第一次有记载的政党出于竞选目的使用深度造假。
## 公共安全与数字重建
重建犯罪现场是一门法庭科学和艺术,使用归纳和演绎推理和证据。人工智能生成的合成媒体可以帮助重建具有空间和时间人工制品相互关系的场景。2018 年,一组民事调查人员使用手机视频、尸检报告和监控录像重建了虚拟犯罪现场。
## 创新ˌ革新
数据和人工智能正在帮助许多行业的数字化转型和自动化。Deepfake 或人工智能生成的合成媒体正在成为吸引客户和提供个性化价值的基础。路透社展示了一个完全由人工智能生成的 deepfake [主持人领导的](https://www.synthesia.io/post/reuters)体育新闻摘要系统,以帮助大规模个性化新闻。在时尚零售行业,deepfakes 可以通过虚拟试用最新的服装和配饰来帮助客户成为模特。
一个令人兴奋的应用程序将捕捉顾客的面部、身体,甚至微小的习惯,以生成一个深度假货,并尝试最新的时尚趋势。[日本人工智能公司 Data Grid](https://datagrid.co.jp/) 创造了一个人工智能引擎,可以自动生成广告和时尚的虚拟模型。deepfake 的方法使品牌能够拥有一个虚拟的试衣间,让用户在购买之前体验产品。零售品牌也可以通过创建一个人工智能生成的混合现实世界来让顾客在家里尝试、布置和装饰他们的空间。
[微软 Hololens](https://dynamics.microsoft.com/en-us/mixed-reality/overview/) 开启企业和工业混合现实创新场景,提供价值。[产品可视化](https://dynamics.microsoft.com/en-us/mixed-reality/product-visualize/)让客户直观地探索工业产品。团队和技术人员可以通过混合现实协作工具[远程协助](https://dynamics.microsoft.com/en-us/mixed-reality/remote-assist/)在工业产品中一起工作。
人工智能技术也可以用来增强和提高低分辨率图像的分辨率。这些增强技术对于旧媒体或由低分辨率镜头创建的媒体非常有用。谷歌发表了一篇论文,利用潜在的对抗性生成器[创建](https://arxiv.org/pdf/2003.02365v1.pdf)高分辨率图像。微软研究院发表了一篇文章,使用三重域翻译网络来增强和[修复退化照片的缺陷](https://www.microsoft.com/en-us/research/publication/bringing-old-photos-back-to-life/)。
合成数据可以让医学研究人员在没有实际患者数据的情况下开发治疗疾病的新方法。他们可以将人工智能生成的合成数据用于训练模型,以产生类似的结果。英伟达、MGH & BWH 临床数据科学中心和梅奥诊所展示了他们如何使用 GANs——通过相互竞争来迭代和改进的算法——来创建带有肿瘤的合成大脑 MRI 图像。通过在合成医学图像上训练算法,并将它们与 10%的真实图像相结合,他们变得与只在真实图像上训练的算法一样擅长识别肿瘤。
> Deepfakes 还可以减轻一些患者的隐私担忧。
深度学习算法需要大量的训练数据来创建有效的模型,甚至开发 deepfake 检测模型。由于现实生活中的 deepfakes 不多,像脸书这样的公司不得不为脸书 Deepfake 检测挑战赛创造合成媒体和 deepfakes
## 结论
Deepfakes 提供了一个对我们的生活产生积极影响的绝佳机会。人工智能生成的合成媒体可以非常强大,是一个伟大的推动者。Deepfakes 可以给人们一个声音、目的和影响规模和速度的能力。从艺术、表达、公共安全到无障碍和商业,各行各业都出现了新的赋权理念和能力。Deepfakes 可以通过扩大他们的影响力为所有人创造可能性,而不管他们的局限性
然而,随着合成媒体技术的普及,被利用的风险也在增加。Deepfakes 可以用来损害名誉、伪造证据、欺骗公众和破坏对民主制度的信任。
[在下一篇帖子中,我将讨论 deepfakes 的一些恶意用例]。
*喜欢?* [*随便给我买本书*](https://www.buymeacoffee.com/ashishjaiman)
## 参考
[【1】](#_ftnref1)[https://medium . com/Microsoft-design/responsible-innovation-the-next-wave-of-design-thinking-86 BC 9e 9 A8 AE 8](https://medium.com/microsoft-design/responsible-innovation-the-next-wave-of-design-thinking-86bc9e9a8ae8)
【https://scholarship.law.bu.edu/cgi/viewcontent.cgi?】[context =教员 _ 奖学金](#_ftnref2)
[【3】](#_ftnref3)[https://www . Forbes . com/sites/Katie baron/2019/07/29/digital-doubles-the-deep fake-tech-nutrition-new-wave-retail/](https://www.forbes.com/sites/katiebaron/2019/07/29/digital-doubles-the-deepfake-tech-nourishing-new-wave-retail/)
[【4】](#_ftnref4)[https://arxiv.org/abs/1807.10225](https://arxiv.org/abs/1807.10225)
[【5】](#_ftnref5)[https://arxiv.org/pdf/2006.07397.pdf](https://arxiv.org/pdf/2006.07397.pdf)
# 后负油:1 年曲率作为远期曲线演变的度量
> 原文:<https://towardsdatascience.com/post-negative-oil-the-1-year-curvature-as-a-measure-of-forward-curve-evolution-a1013dcd6b2b?source=collection_archive---------50----------------------->
## 用单一指标量化前向曲线动态

WTI 期货市场历史上首次跌破 0 美元,5 月合约(CLK20)下跌 306%,4 月 20 日周一收于-37.63 美元/桶。交易量和持仓量一直在向 6 月合约(CLM20)转移,随着 5 月合约在 4 月 21 日(周二)到期,6 月合约成为了近月合约。6 月合约也下跌,因为它成为短期市场的代表,导致升水更大。
我很好奇期货溢价通常是如何计算的,因为我意识到有几篇文章使用了不同月份合约(9 月 20 日、12 月 20 日等)的价差。)来量化短期和长期市场动态之间的差异。我知道期货溢价通常是指远期曲线的向上形状,但我想找到一个单一的指标来代表曲率。我还想探索远期曲线如何随时间演变,而不必盯着[日期 x 合约]矩阵来寻找模式。
# 前向曲线的演变
现有的可视化要么只显示当前的实时前向曲线,要么在相同的轴上叠加大量不同日期的杂乱前向曲线。我知道每个人都讨厌 3D 绘图,除了艺术家自己,但我相信这个绘图实际上可以减轻对曲线形状演变的解释。

x 轴(CLM20。NYM 到 CLK21。NYM)代表从 2020 年 6 月到 2021 年 5 月的合约。y 轴(04–23 到 03–31)表示从 2020 年 4 月开始的最新日期。z 轴代表每份合约每天的收盘价。底部的等高线图表示顶部曲面图的展平表示。
从图中可以清楚地看出,月初的升水“变软”,然后在接近展期时明显变陡。
# 1 年曲率作为远期曲线演变的衡量标准
我想到了几种计算曲率的方法:
1. 由于 x 轴(周期)是统一的,因为每一步代表一个合约,如果每个合约之间的不同收盘价代表梯度,我们可以将这些差异相加得到总曲率。这显然是错误的,因为它只是从第一个合同到最后一个合同的梯度
2. 利用我在多变量微积分课上学到的知识,我想找到密切圆,这是逼近曲线某一点的“最佳拟合圆”。然而,很难找到这样一个点,如果曲线上有几个拐点,这可能是危险的。另一种方法是将曲线参数化,并考虑沿曲线运动的质点的加速度大小。

3.一种更简单的方法是计算并求和每条曲线的有限差分,因为 x 轴已经是离散的。这个想法是在每个点上累积“近似梯度”。使用内部点中的二阶精确中心差和边界处的一阶或二阶精确单侧(向前或向后)差来计算梯度。

如果这些值是等间距的,则中心差是向前和向后差的平均值。通过使用过去和未来的值进行比较,中心差给出了导数的更精确的近似值。然后,二阶中心差表示点与点之间梯度变化的程度。
# 结果

结果指标是 1 年曲率,它考虑了曲线上的波动,而不是简单的点对点测量。这个单一值能够捕捉到月初的期货溢价、“软化”阶段以及月末的最终陡峭化。这有望提供一个可以使用的更加一致和可量化的度量。
## 如果您想与 3D 绘图互动,并访问一个简短的 Jupyter 笔记本,其中包含供您自己使用的代码,请留下注释。
# 机器学习和深度学习模型的训练后分析和量化
> 原文:<https://towardsdatascience.com/post-training-analysis-and-quantization-of-machine-learning-and-deep-learning-models-a133231f6100?source=collection_archive---------24----------------------->
## [虚拟助理项目](https://towardsdatascience.com/tagged/virtual-assistant-project)
## 一个极其重要但有时被忽视的概念

[斯科特·格雷厄姆](https://unsplash.com/@sctgrhm?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍照
建立和探索机器学习以及深度学习模型是我喜欢做的事情。我选择一个项目并开始着手做。有些只是业余爱好者级别的项目,有些是具有真实用例和优势的项目。我有一个中等的 GPU 和一个中等的处理能力的系统。所以我所关注的只是训练和确保模型在我的电脑上工作和运行。然而,这并不是故事的结尾,有时我最终会错过一个极其重要的概念——模型的**训练后分析**。
这种培训后分析是什么,为什么如此重要?
训练后分析有时也称为事后分析,在模型优化中起着重要作用。构建和训练的业务模型需要优化,以便在低端设备和嵌入式系统(如 raspberry pi)上有效工作。构建和评估模型的主要组件之一是检查模型的预测能力和性能质量。一个更重要的概念是理解你的机器学习或深度学习模型的局限性。克服这些限制是成功模式的关键。
在本文中,我们将讨论如何针对特定用例有效地量化我们的模型。我们将主要关注深度学习模型的局限性、改进和量化的讨论。首先,我们将讨论使用 TensorFlow 的模型的训练后量化到底是什么。我们将学习如何在各种优化技术的帮助下,使我们的模型在所有平台上更加动态和有效,以达到更广泛的目标受众。然后,我们将了解可用于改进各种模型的限制和技术。我们对这个项目的主要参考将是 TensorFlow 博客的训练后量化和虚拟助理项目系列,这是我做的。你可以在下面提供的链接中查看这两个,尽管不是强制性的。
[](https://www.tensorflow.org/lite/performance/post_training_quantization) [## 训练后量化| TensorFlow Lite
### 训练后量化是一种转换技术,可以减少模型大小,同时还可以改善 CPU 和硬件…
www.tensorflow.org](https://www.tensorflow.org/lite/performance/post_training_quantization) [](https://towardsdatascience.com/tagged/virtual-assistant-project) [## 虚拟助手项目——走向数据科学
### 阅读《走向数据科学》中关于虚拟助手项目的文章。分享概念、想法和…
towardsdatascience.com](https://towardsdatascience.com/tagged/virtual-assistant-project)
> **注意:**虽然不是必要条件,但我强烈建议观众查看我以前在智能面部锁定系统、下一个单词预测和虚拟助手系列中创新的使用一维卷积层的聊天机器人项目上的项目,因为这将有助于以更直观的方式掌握一些概念。

由[迈克尔·泽兹奇](https://unsplash.com/@lazycreekimages?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片
## 训练后量化:
在您的系统上有效运行的模型可能无法在低端设备上有效运行相同的程序/模型。这可能是由于目标设备的硬件限制。在这里,训练后量化可以帮助改进目标设备的算法和模型的优化。训练后量化是一种转换技术,可以减少模型大小,同时还可以改善 CPU 和硬件加速器的延迟,而模型精度几乎不会下降。当您使用 [TensorFlow Lite 转换器](https://www.tensorflow.org/lite/convert/)将其转换为 TensorFlow Lite 格式时,您可以量化已训练的浮点 TensorFlow 模型。TensorFlow Lite 转换器在 Raspberry Pi 等设备上非常有用,可用于优化对象检测模型、人脸识别模型等。对象检测项目可以使用 TensorFlow Lite 进行优化,对 android 或 ios 设备也有很大的影响。你可以在这里查看这个很酷的项目。
下面是帮助您为模型选择最佳训练后量化和优化方法的框图:

[来源:](https://www.tensorflow.org/lite/performance/post_training_quantization)图片来自 tensorflow
简而言之,各种训练后量化方法如下:
## 动态范围量化
这种最简单的训练后量化形式。它只将权重从浮点静态量化为整数,精度为 8 位。
## 全整数量化
通过确保所有模型数学都是整数量化的,您可以进一步改善延迟,减少峰值内存使用,并与纯整数硬件设备或加速器兼容。
## 浮点量化
您可以通过将权重量化为 float 16(16 位浮点数的 IEEE 标准)来减小浮点模型的大小。
基本上,在这 3 种训练后优化方法中,我们确保我们的模型设计尽可能高效和优化。我们必须确保,一旦完成了必要的优化更改,该模型将保持高效的性能,同时在精度和损失等参数方面保持或多或少相同的有效性。

照片由 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的 [Dhru J](https://unsplash.com/@dhruj?utm_source=medium&utm_medium=referral) 拍摄
# 其他直观的例子来理解模型的局限性以及可以做出的重大改变和改进—
# **1。人脸识别模型:**
所以,你成功地建立了一个面部识别模型,使用了像迁移学习这样的深度学习技术,类似于这里的。整个模型在训练数据上表现得非常好。在对训练和验证数据进行测试时,产生的结果仍然非常好。该模型在大多数情况下都能按预期运行。然而,该模型存在一些局限性。让我们来理解和看待人脸识别模型的这些局限性。让我们也看看在以下方面可以作出的改进。
## 局限性:
1. 人脸识别模型不能在低质量的相机上表现得很好。摄像机质量必须至少一般,才能正确捕捉实时人脸并授予访问权限。
2. 周围的照明不能太暗。它至少需要适度的亮度。否则,该模型将在实时分析过程中出现检测和识别人脸的问题。
3. 我们使用 Haar cascode _ frontal face _ default . XML 来检测人脸。这对于在某些角度识别面部可能是有问题的,并且面部的检测可能不能如期望的那样工作。
## 改进:
1. 可以使用一次性学习和训练方法来减少每个面部的训练时间。由于当前模型只识别一张脸,如果我们想添加更多的脸,我们需要重新训练整个模型。因此,需要考虑一次性学习等方法来提高模型的质量和性能。
2. 可以找到 haarcascade _ frontal face _ default . XML 的替代方案来提高在任何特定角度检测面部的准确性。另一种方法是为正面和侧面创建一个定制的 XML 文件。
3. 为了使其在嵌入式设备上运行,可以对内存约束进行更改,如转换为 tf.float(32 ),也可以通过考虑使用 tflite 对模型进行更改。
# 2.下一个单词预测:
[下一个字预测](/next-word-prediction-with-nlp-and-deep-learning-48b9fe0a17bf)模型能够在模型上实现体面的损失。下一个单词模型是一种预测搜索类型的方法,可用于 google 搜索。这些也可以用来检测用户的某些模式,并可以用于电子邮件和短信的下一个单词预测任务。该模型尽管还不错,但仍有缺陷,并且存在改进下一个单词预测模型中存在的缺陷的方法。让我们看看所有的限制和可以改进整个模型的变化。
## 局限性:
1. 下一个单词预测仅限于几个单词,并且不能非常准确地对较长的句子进行预测。在这个行业工作时,这不是最好的情况,因为可能会有更长的刑期。
2. 由于使用了 LSTM 层,与其他模型相比,该模型需要更长的时间来训练和执行。在 ram 和 GPU 能力较低的小型嵌入式系统中,这种较长的训练可能是一种限制。然而,一旦在更好的系统上训练,部署就不是一个大问题了。
## 改进:
1. 对于自然语言处理,甚至存在零拍和一拍的学习方法。可以使用相同的方法来更好地训练模型,以提高整体性能,并避免重复的训练过程,这在一些现实生活的应用程序和场景中可能是一个真正的大障碍。因此,一次性学习是在其他培训能力较低的嵌入式系统中部署和工作的一个很好的选择。
2. 像 GPT-3 模型这样的高级训练算法对这些预测任务非常有效。
3. 可以使用更多预处理方法,也可以测试更多替代方法,以获得更好的精度、更低的损耗,并实现整体高性能。
# 3.聊天机器人模型:
[聊天机器人](/innovative-chatbot-using-1-dimensional-convolutional-layers-2cab4090b0fc)模型是一个基于文本分类的创新聊天机器人,可以实现整体良好的准确性和减少损失。聊天机器人模型能够在我们使用的整个数据集上表现得非常好。然而,即使是我们的聊天机器人也有一定的局限性和问题。我们将在下一节中介绍它们。但是基于 conv-1D 架构的整体预测系统和聊天机器人在 witty.txt 数据集上表现良好,可以用于类似的数据集。该模型对最常重复的问题的唯一值进行分类。
## 局限性:
1. conv-1D 聊天机器人模型的主要限制之一是,它是一种基于分类的聊天机器人,而不是一种生成式建模方法。这种分类方法可能会导致重大挫折,因为在某些语言中可能会有问题,比如当用户不太精通英语时的语义问题。这可能会产生误导,聊天机器人可能不会产生预期的结果。
2. 由于它不是一个完全完美的模型,所以有时会容易出错。它可以预测用户不满意的结果,这可能是工业应用的一个问题。
## 改进:
1. 可以使用更多的预处理和自然语言处理的方法来达到更高的精度和减少模型训练的损失。这也可以改善模型的整体预测。
2. 像 GPT-3 模型这样的高级训练算法甚至对对话型聊天机器人也非常有效,这是训练高质量聊天机器人的一个很好的替代方法。
3. 可以使用其他方法,如基于分类的迁移学习、注意的序列到序列模型,或者甚至用于训练的某些一次性学习方法。

威廉·艾文在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
## 结论:
体验机器学习和深度学习模型的乐趣总是很酷,也是它们最棒的部分。在探索这些模型时,如果您确实希望将它们转换成现实生活中的用例,使其能够惠及大量的人,那么模型的训练后分析和训练后量化对于提高效率、质量和紧凑性以将项目部署到更广泛的受众变得极其重要。训练后量化还使我们能够在量化模型上获得几乎相同的精度,类似于在原始模型中获得的精度。这简化并使我们的生活变得容易多了!
谢谢大家坚持到最后。祝你在机器学习和深度学习模型的探索和量化过程中度过愉快的时光。请随意查看我之前提到的所有项目,我希望你们都喜欢这篇文章,并祝你们有美好的一天!
# 今年,PostEra 正在使用机器学习制造一种新冠肺炎药物
> 原文:<https://towardsdatascience.com/postera-is-using-machine-learning-to-make-a-covid-19-drug-this-year-c7d70245bcd9?source=collection_archive---------41----------------------->
## 将谷歌翻译启发的机器学习应用于化学
*声明:我是* [*Cortex*](https://github.com/cortexlabs/cortex) *的维护者,这是一个开源的机器学习工程平台,用在下面提到的一些项目中。*
最近,一家名为 [PostEra](https://postera.ai/) 的初创公司宣布,他们打算“在年内”开发一种新冠肺炎疗法,作为开源 moonshot 的一部分。

自然,这一宣布引起了一些兴奋。虽然 PostEra 肯定不是第一家做出雄心勃勃声明的生物技术/机器学习初创公司,但这次有一些特别令人兴奋的事情。
虽然我们可能已经习惯于宣布公司 *X* 将做不可能的事 *Y* 因为“机器学习”——其细节从未得到解释——PostEra 的宣布是不同的,因为它:
* 分离出药物开发中的一个特殊瓶颈。
* 把阻断器设计成一个工程挑战。
* 提出了一种新颖的机器学习解决方案来应对这一挑战。
看他们的发布公告,感觉不像是 AI 福音或者炒作。感觉就像*工程,*机器学习只是堆栈的另一部分。
因此,PostEra 在一年内制造新冠肺炎治疗的目标,虽然可能是雄心勃勃的,但在某种程度上感觉是严肃的,这是许多登月者所没有的。PostEra 没有等待机器学习的突破,他们没有押注于投机性技术。他们正在推广一个流行产品——Google Translate——所使用的成熟方法,以解决一个新领域的类似问题。
为了更好地解释我的意思,让我们深入了解一下 PostEra 是如何工作的。
# 将化学合成理解为翻译
PostEra 在药物开发中解决的问题是分散的:
对于任何给定的化合物,都有许多不同的制造方法,并且没有严格的、确定性的模型来确定哪种方法是最好的。
为了给出更多的上下文,你可以简单地在白板上画出一个分子:

氧原子到这里,在那里插入几个键,瞧——分子。然而,在现实生活中,我们不能如此精确地剪切和粘贴原子。
为了创造一种新的分子,化学家采用更简单的分子,通过化学反应转化它们,这被称为“移动”然后,新分子通过额外的移动进行转化,直到最终产生目标分子。形成一个分子的一系列运动被称为“路线”
化学家主要通过有知识的试错法来预测移动的结果和路线的可行性。这很贵,因为化学。
PostEra 所做的是建立一个平台,使用机器学习来即时预测,给定一个拟议的分子,最可行的合成路线:

来源: [PostEra](https://postera.ai/demo)
为了理解该平台如何工作,将化学合成问题分解成更抽象的术语是有帮助的:
* 你需要将一组对象 A 转换成一个单独的对象 b。
* 您可以通过一组预定义的功能(化学/物理反应)组合对象来转换它们。
* 你需要创建一个模型来对许多理论上似乎合理的函数链的可行性进行评分。
如果你把这个问题的化学背景去掉,它就变成了工程师们熟悉的东西——一个翻译问题。
假设你的任务是设计谷歌翻译。您可以像这样确定问题的范围:
* 您需要将一组对象 A 转换成一个单独的对象 B,即一个等价的英语短语,在本例中,这个对象是法语单词“*乐惠·德·诺克斯·德·可可,*”。
* 您可以通过以多种不同方式应用翻译功能来转换对象。*乐惠·德·诺伊克斯·德·可可*可能是“椰子油”或“可可坚果油”
* 你必须给各种翻译打分,没有明显的基于规则的系统。“椰子油”是对的,但“椰子的坚果油”不是*不对*。

来源:[谷歌翻译](https://translate.google.com/)
从根本上说,这是同样的问题,Google Translate 中使用的相同的序列到序列方法应该适用于 PostEra。
经过适当的训练,PostEra 的模型应该能够生成分子之间可能的“翻译”树,为树中的每条路线分配可行性分数,然后在树中搜索最可行的翻译——这正是所发生的事情。
然后,可以将这一系列模型部署为单个 API,可从 PostEra 前端查询,以创建药物化学即服务平台。
# 波斯特拉正在努力实现登月,而不是创造奇迹
需要强调的是,PostEra 的 moonshot 唯一雄心勃勃的是它的时间线。
基本技术已经被证实。机器翻译作为一个领域已经建立了很长时间,PostEra 的创始团队甚至在公司成立之前就发布了第一个在预测化学反应结果方面胜过人类化学家的模型。
这也是为什么 ML 月球探测器如此令人兴奋的部分原因。底层产品不是推测性的——它是功能性软件,它是机器学习工程如何以真实、有形的方式改变技术的又一个例子。
***注来自《走向数据科学》的编辑:*** *虽然我们允许独立作者根据我们的* [*规则和指导方针*](/questions-96667b06af5) *发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的* [*读者术语*](/readers-terms-b5d780a700a4) *。*
# PostgreSQL 13 特性精华
> 原文:<https://towardsdatascience.com/postgresql-13-features-distilled-c0c0adcfa020?source=collection_archive---------39----------------------->

[南安](https://unsplash.com/@bepnamanh?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)在 [Unsplash](https://unsplash.com/s/photos/elephant?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 拍摄的照片
## 数据工程
## PostgreSQL 最新版本中的索引优化、增量排序、并行清空和更多最新特性
J 就在几周前,[我写了关于 MySQL 8.0 在 Google Cloud](https://linktr.ee/kovid) 上正式发布,在所有主要云平台上完成它的旅程。MySQL 8.0 已经问世一段时间了。开源数据库社区急切地等待 PostgreSQL 的主发布版本 13。PostgreSQL 是仅次于 MySQL 的第二大流行的开源数据库,由于其固有的可扩展特性,它在所有地区和行业都被越来越多的人采用。随着 AWS 红移走上 PostgreSQL 路线,PostGIS 中的世界级地理空间支持和令人惊叹的核心功能集,PostgreSQL 几乎不是一个可以忽略的数据库。
一周前,9 月 24 日,PostgreSQL 13 发布了。这个新版本有很多特性,但我们只介绍了 PostgreSQL 官方版本中列出的一些主要特性。
# 平行分度真空
清空是一个缓慢而乏味的过程,但与其他数据库不同,PostgreSQL 使用它来回收磁盘上任何未使用的空间。当 vacuum 在任何给定的表上运行时,在该表上创建的索引也会被清空。PostgreSQL 13 引入了一个特性,可以并行清空一个表上的多个索引。
可以使用名为`**max_parallel_maintenance_workers**`的数据库变量设置并行化的程度。这应该设置为表拥有的索引数。
这一点,再加上[许多其他索引改进](https://www.percona.com/blog/2020/09/10/index-improvements-in-postgresql-13/),使得这个版本的 PostgreSQL 13 更有吸引力。[也许优步终究会考虑搬回 PostgreSQL,开个玩笑](https://eng.uber.com/postgres-to-mysql-migration/)!
注:请注意,autovacuum 尚不支持此功能。这里列出了对 autovacuum 的一些其他改进。
# 为查询优化器和规划器提供更好的统计数据
我们所知道的关于优化器的一件事是,如果他们有更新和更好的关于表、索引、分区等的统计数据,他们会优化、计划和重写更好的查询。几年前,[随着 PostgreSQL 10 的发布,它引入了用户定义的自定义统计数据的概念,名为扩展统计数据](https://pganalyze.com/blog/postgres13-better-performance-monitoring-usability#extended-statistics-improvements-in-postgres-13)。使用扩展的统计数据,用户可以创建自己的统计数据来定义高级关系和依赖关系,以捕获行为统计数据并将其提供给优化器。
在 PostgreSQL 13 中,我们看到了更多的改进。以前,规划器只能使用一组定制的统计数据来规划和优化查询。用户可以通过`OR`、`IN`或`ANY`子句使用多个统计数据。
# 增量排序
在这个主要版本之前,如果您在一个表中有一个针对`(column_1, column_2)`的索引,它将自己具体化为一个 B 树,并且您发出一个使用`(column_1, column_2, column_3)`排序的查询,PostgreSQL 不会使用现有的索引,该索引已经对 where 子句中的前两列的数据进行了排序。
在这个新版本中,这个问题已经得到了解决。现在,PostgreSQL 不会对已经为列`column_1`和`column_2`排序的数据重新排序。在亚历山大·库兹曼科夫[的演讲中了解更多。](https://www.postgresql.eu/events/pgconfeu2018/sessions/session/2124/slides/122/Towards%20more%20efficient%20query%20plans%20(2).pdf)
# 使用重复数据删除的 b 树成本优化
考虑一个您想要索引的表列,但是它有许多重复的值。在该列上创建索引时,所有值都绘制在索引的 B 树结构上。很多重复出现在你的索引中。这导致索引很大,并且索引的处理时间也很长。
> ***主键或唯一索引*** *显然不会发生这种情况——请参考*[*Andrew Kozin*](https://medium.com/u/2790f889fe05?source=post_page-----c0c0adcfa020--------------------------------)*对这篇帖子的评论,了解为什么这句话不成立。*
非唯一列上的索引对于聚合查询非常重要。为了从这些查询和数据库中获得更好的性能,PostgreSQL 13 引入了一个新的重复值删除过程。PostgreSQL 现在只保存对列值的引用,而不是存储所有重复的值。
重复数据删除过程显然节省了大量空间,因为这是一个常见问题。节省空间的同时,也节省了在更大的索引上花费的额外处理时间。在这里了解更多关于 B 树实现的信息
[](https://www.postgresql.org/docs/13/btree-implementation.html#BTREE-DEDUPLICATION) [## PostgreSQL:文档:13: 63.4。履行
### 本节涵盖了可能对高级用户有用的 B 树索引实现细节。看…
www.postgresql.org](https://www.postgresql.org/docs/13/btree-implementation.html#BTREE-DEDUPLICATION)
# 聚合的性能优化
PostgreSQL 10 引入的另一个特性是散列聚合。Postgres 在聚合时有两个选项——散列或组。如果哈希表可以放在内存中,则使用哈希聚合。[在 PostgreSQL 13](https://info.crunchydata.com/blog/why-postgresql-13-is-a-lucky-release) 之前,如果哈希表不适合内存,PostgreSQL 只会选择组聚合。但是现在,在这个版本中,如果哈希表不适合内存,它将溢出到磁盘。
对于那些已经在使用 PostgreSQL 的人来说,如果你打算[迁移到 PostgreSQL 13](https://www.percona.com/blog/2020/07/28/migrating-to-postgresql-version-13-incompatibilities-you-should-be-aware-of/) ,这里有一篇关于 Percona 博客的好文章。
# PostgreSQL —出自马嘴
> 原文:<https://towardsdatascience.com/postgresql-from-the-horses-mouth-53e054b5ec83?source=collection_archive---------51----------------------->

在 [Unsplash](https://unsplash.com/s/photos/education?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上由[伊尼基·德尔·奥尔莫](https://unsplash.com/@inakihxz?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)拍摄的照片
## 阅读材料汇编 PostgreSQL 专家的书籍和博客
这篇文章的灵感来自于我一年多前写的这篇关于 MySQL 的广泛的[文章。在所有四个主要的关系数据库上工作过之后,我阅读了大量的官方文档、博客、白皮书和书籍。这个书籍和博客的集合是我在 PostgreSQL](https://medium.com/crowdbotics/mysql-from-the-horses-mouth-582dbfca2abb) 上读到的所有内容的精华**。它可能不像 MySQL 那样广泛和准确,因为我没有广泛地使用 PostgreSQL。但是,不管怎样,这就是了。**
# 要读的书
只有一本书是我广泛使用过的关于 PostgreSQL 的内容,所以我建议这样做。我的大部分知识来自博客和我在 PostgreSQL 领域关注的人——PostgreSQL:Up Running,第三版,作者 Regina Obe 和 Leo Hsu 。可能会有更多值得阅读的 Postgres 原创作者和开发者的书。
# 要关注的博客
## [戴夫的 Postgres 博客](https://pgsnake.blogspot.com/2010/05/comparing-voltdb-to-postgres.html)
作为 EnterpriseDB 的核心团队成员之一,Dave 对 Postgres 内部发生的事情有着深刻的见解。尽管他的博客自去年 7 月以来一直处于休眠状态,但如果你想深入了解 Postgres,还是有一些博客帖子可供使用。当 VoltDB 在 2010 年第一次出现时,Postgres 和 VoltDB 的比较见此。顺便说一下,戴夫被称为“T21”。
## 宰泽的博客
长期 Postgres 用户,Zaiste 博客作为一个技术用户,而不是来自内部团队的人。他的一系列名为《大忙人入门》的帖子非常棒。在这一点上,他确实有一本为忙碌的人准备的 Postgres 初级读本——只是为了让你开始使用 Postgres。没什么高级的。他是 [Nukomeet](https://nukomeet.com) 、 [RuPy Conf](http://polyconf.com) 和 [PolyConf](http://polyconf.com) 的创始人。
## [安德鲁·邓斯坦的 PostgreSQL 博客](http://adpgtech.blogspot.com/search/label/PostgreSQL/)
作为 PostgreSQL 的核心提交者,Andrew 发表了关于 PostgreSQL 的特性、问题和性能技巧的文章。这个博客已经不活跃很多年了,但是它仍然有非常有用的信息,这些信息来自真正了解内部的人。
## [Bruce Momijan 的 PostgreSQL 博客](http://momjian.us/main/blogs/pgblog.html)
他是 EnterpriseDB(商业 PostgreSQL)的副总裁,从 2008 年开始写作。如果你想专攻 PostgreSQL,他的文章简短扼要,非常有用。他每周发布几次帖子,主题涉及从理解预写日志的内部到复制再到 SQL 查询的方方面面。
## [乔希·伯克思的数据库汤](http://www.databasesoup.com/search/label/postgresql/)
他从事数据库工作已经超过 20 年了。他不怎么发表关于 PostgreSQL 的文章,但无论何时他发表,通常都是关于一些新特性或性能优化技巧。
## [米歇尔·帕奎尔的博客](https://paquier.xyz/)
作为一名 PostgreSQL 提交者,他已经为许多不同的项目做出了贡献。他在会议上发言,并不时在博客上发表关于数据库的文章。我很喜欢 PostgreSQL 12 中的新特性,可以选择是否实现 CTE。cte 广泛用于数据工程和分析领域。这无疑会对查询性能产生重大影响。
## [斯蒂芬·费科特的博客](https://pgstef.github.io)
这个博客主要是关于管理——备份、恢复、复制,特别是许多不同的 Postgres 扩展,如[pg _ back sleeve](https://pgstef.github.io/2019/07/19/pgbackrest_s3_configuration.html)。
## [Hubert Lubaczewski 的博客](https://www.depesz.com/tag/postgresql/)
除了 Postgres 内部的大量知识、新特性和最佳实践,这个博客还有最好的在线查询计划可视化工具。你可以去这里了解一下[。](https://explain.depesz.com)
## [克雷格·克斯廷斯的每周时事通讯](http://www.postgresweekly.com)
对于 Postgres 爱好者来说,这是一个阅读 Postgres 的好地方。这份时事通讯经过精心策划,涵盖了数据库的所有方面——软件开发、数据库管理、分析、扩展等等。查看最新一期的新闻简报[。](https://postgresweekly.com/issues/359)
## [德米特里·方丹的博客](https://tapoueh.org/blog/2018/07/postgresql-concurrency-isolation-and-locking/)
这篇博客来自《PostgreSQL 的艺术》一书的作者。我还没有抽出时间来读这本书,但打算很快读。Dmitri Fontaine 是 PostgreSQL 的长期撰稿人。
## 罗伯特·哈斯的博客
最后但同样重要的是,来自 EnterpriseDB 首席架构师、长期 Postgres 贡献者的关于 Postgres 的最全面的博客之一。数据库一点也不简单。它们是复杂的软件,需要指导和调整,这样你就可以充分利用它们。这个博客对任何想深入研究 Postgres 的人来说都是很好的文献。我已经断断续续关注这个博客很多年了。
我希望你发现这个信息有价值。虽然 PostgreSQL 文档非常简洁,但是光靠文档并不能教会你一切。这些博客中的大部分填补了精通 PostgreSQL 实际需要的东西和文档中提供的东西之间的空白。
# PostgreSQL:秩函数介绍。
> 原文:<https://towardsdatascience.com/postgresql-rank-function-introduction-c8ac008506dd?source=collection_archive---------50----------------------->
## 如果您尝试过分析一些应用程序数据库,您可能会看到如下内容。

卢克·切瑟在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片

每个用户都可以在应用程序中发布多个帖子,我想一个超级简化版的 twitter 数据库应该是这样的。
数据分析的问题来了。
我们如何才能发现每个用户第一次发帖的时间和内容?这种问题很常见,当你分析应用程序数据时,你想知道每个用户的第一个活动。通过实现这一点,我们应该得到如下表格。

您可以看到,现在我们提取了三个帖子,它们是用户从上一个表中首先创建的第一个帖子。该提取可以作为获得如下服务洞察的基础
1. 用户创建第一个帖子需要多长时间?
2. 用户倾向于在第一篇帖子中使用什么样的词?
增强用户采取主动是激活服务的关键,所以你应该知道如何做到这一点。
# 编写 SQL
我们可以将所需的程序总结如下。
1. 按`user_id`分组数据样本。
2. 按每组中的`id`降序排序。
3. 从每组中提取 id 最小的样本。
要仅使用 PostgreSQL 实现这一点,有一些可能的方法,但今天我们将使用其中实现的一个窗口函数, [RANK 函数](https://www.postgresqltutorial.com/postgresql-rank-function/)。使用这个,我们可以简单容易地完成这个分析。该函数将用于分组和排序方法的列作为参数,并给出每个组的排名。它的语法是这样的。
RANK() OVER (
[PARTITION BY partition_expression, ... ]
ORDER BY sort_expression [ASC | DESC], ...
)
如你所见,我们将“如何分组”交给`PARTITION BY`,将“如何排序”交给`ORDER BY`。似乎很简单,对吗?让我们把这个排序函数应用到我们的问题中。
select
*,
rank() over (partition by user_id order by id)
from
posts
`PARTITION BY`使用`user_id`将数据分组到每个用户中,`ORDER BY` `id`对每个用户组中的帖子进行排序。通过执行这个 SQL,我们可以获得下表。

您可以看到每个用户组的排名数字,为了从转换后的表格中只提取第一篇文章,我们可以利用`where`来约束`rank = 1`。
select
*
from
(
select
*,
rank() over (partition by user_id order by id)
from
posts
) as tmp
where
rank = 1
这个 SQL 最终给出了我们想要的东西。

我希望您现在可以看到,使用 PostgreSQL 的 RANK 函数提取数据库中每个用户的第一篇文章是多么容易。基于这些提取的信息,你可以运行大量的分析来更好地理解你的用户。
# 医疗人工智能的上市后责任
> 原文:<https://towardsdatascience.com/postmarket-responsibilities-for-medical-ai-56ba67fd8cc?source=collection_archive---------35----------------------->

metamorworks/Shutterstock.com
## 第二部分——在医疗人工智能商业化方面,行业应该做些什么
在本系列文章的第一部分中,我描述了 FDA 和行业之间关于 FDA 对医疗人工智能的适当监督程度的紧张关系。我解释说,目前看来 FDA 可能会要求国会给予更多的上市后权力,以便能够以更深入的方式监督医疗人工智能的商业化,尽管事实上 FDA 已经拥有相当大的权力。
在第二部分,我提出了另一种选择。我建议行业采用最佳实践来确保病人得到最好的护理,可以说是自我调节。在[第三部分](/postmarket-responsibilities-for-medical-ai-5cd43521f546),我将把 FDA 的监督限制在它现有的法定权限内。
在商业化阶段,行业应在四个方面积极采取措施,以确保其基于人工智能的医疗设备的安全性和有效性。
# A.追求增强的上市后警惕性
将自适应特别是自主的人工智能算法部署到市场上需要部署它们的公司大大提高上市后的警惕性。根据定义,自适应算法在使用时进行调整。作为质量保证和风险缓解的问题,也作为持续改进产品的方法的研究问题,公司应该密切监控其算法在市场上的性能。
应该怎么做?
在回答这个问题之前,重要的是要理解为什么监控很重要。识别可能出错的事情告诉我们什么样的监控是必要的。
这里我大量借用了奥姆·德什穆克的一篇优秀的[文章](https://www.analyticsvidhya.com/blog/2019/10/deployed-machine-learning-model-post-production-monitoring/)“部署你的机器学习模型?以下是你需要知道的后期制作监控”2019 年 10 月 7 日。
下面是几个不同的场景,它们会显著改变已训练算法的性能。
**在域中但看不见数据**。我们开始意识到每个人是多么的不同。个性化医疗基于我们对人类基因组的深入了解,以及种族、民族、性别等因素如何对诊断和治疗决策产生重大影响。这使得训练集具有来自算法最终将使用的所有群体的数据变得尤其重要。例如,很有可能一个训练有素的算法可能不包括美洲土著人口,当该算法用于这些人口时,其性能可能会下降。从某种意义上说,在这种情况下的训练会对美国土著人有偏见。
**输入数据不断变化的性质**。自适应算法必然需要新数据。并且很容易预测新数据可能不总是以与算法最初被训练的数据相同的方式被创建。如果自适应 AI 分析放射图像,如果产生图像的技术发生变化,这些变化可能会导致自适应算法以不同方式解释数据。很容易想象技术引发的变化,以及数据生产中的社会变化。医疗专业人员甚至患者自己或其护理人员收集数据的方式可能会改变,从而影响算法解释数据的方式。那些花大量时间清理数据的人明白,从字符串转换为整数这样的小事会对算法的运行产生深远的影响。
**数据解释的变化。**现有数据的含义会随着时间而变化。即使数据点本身不会改变,但它们的意义会因社会或环境因素而改变。在医疗环境中,可以想象电子健康记录中的单词的含义会随着医生和其他健康护理人员的实践的改变而逐渐改变。随着时间的推移,医生可能会使用相同的词语,但有了新的含义。这不同于上述数据发生变化的问题。
**部署在意想不到的环境中的机器学习系统。**这在医疗技术领域非常常见,因为医生和其他医疗保健专业人员会尝试现有技术的不同用途。你可以想象,原本打算用于追踪流感症状的软件,在某些医生的手中,可能会被用于追踪 COVID 19 症状。随着医疗专业人员决定探索其他领域的实用性,这意味着算法功能所基于的数据可能会发生变化,从而对产品的整体性能产生影响。
**缺失数据。**对于使用各种数据的算法,某些数据流可能会被切断或中断。
**模型漂移。**如果不关注原因,模型可能会因为各种原因而表现不佳。
**恶意的行为。**一旦人工智能设备处于“野生状态”,恶意行为者可能会故意引入数据集,故意扭曲设备的行为,这可能比传统的“黑客攻击”更难检测到(例如,“闯入”系统并改变参数)。
关键是我们需要明白,当一个算法在现实世界中使用时,会发生影响性能的事情。不难想象。
那么公司在上市后监管方面到底应该怎么做呢?也许我们都同意的一件事是,一种尺寸不适合所有人。然而,这些软件开发人员可以遵循一些通用原则,以确保他们能够充分地监控他们的产品。
概括地说,我们可以把监控分为两种不同的类型:主动的和被动的。先说主动。
# 1.主动模型监控
Deshmukh 先生建议我们根据一组关键指标持续跟踪机器学习模型的性能,并生成特定的基于事件的警报。虽然德什穆克先生笼统地谈到了这个问题,但我想重点谈谈医学背景。
这项技术的目标是“识别哪些输入样本明显偏离了训练数据中的模式,然后让人类专家仔细检查这些样本。”问题是,感兴趣的模式在很大程度上取决于数据的领域、问题的性质以及所使用的机器学习模型。
假设我们有一个算法,它正在观察医院里一个病人的 10 种不同的生命体征,着眼于识别这些生命体征何时达到表明病人正在变得败血症的程度。实现这种监控的一种方法是统计地查看这些生命体征如何正常流动,并设置统计分布或其他参数,如果超过这些参数,将向算法开发者发出警报。请注意,这些警报不同于用于确定特定患者何时需要医疗护理的警报。这些是基于统计数据的警报,表明算法正在分析的数据类型发生了一些变化。这样的警告将会给为开发人员工作的人一个机会去调查是否有需要更新或纠正的地方。
除了检查统计异常之外,我们可能会进行其他形式的实时数据检查,例如,确保模型仍然接收到它需要的所有不同的数据。这对于分类变量和数值变量都是正确的。该公司可以检查数据,以确定在活动模型中是否存在任何特征依赖性。
该公司还可以在客户的配合下进行模型预测和性能测试。在这种情况下,公司将需要从最终用户那里获得有关预测事件是否会发生的数据。如果软件开发人员可以协商访问这些数据,公司就可以不断地评估其模型的性能。这在医学上通常是困难的,因为后果可能是几个月甚至几年之后。然而,在某些情况下,预期事件很可能在短时间内发生(或不发生),因此可以持续评估性能。如果公司无法获得访问权限,那么简单地跟踪预测的总体分布以查看该分布是否会随时间而变化是很重要的。
# 2.反应式模型监控
反应式模型监控非常类似于医疗设备制造商已经在做的事情。根据法律要求,这些制造商拥有收集和分析用户向公司报告的问题的系统。然而,在人工智能环境中,反应式模型监控可以在更系统的基础上进行。
客户可能会报告不准确的结果。这些中的一定数量是可以预料的。很可能,在模型的训练和验证之后,该公司了解到该模型在一定的统计精度水平上表现得不够完美。因此,公司知道有时模型会产生不正确的预测。
虽然这些客户投诉在意料之中,但它们也创造了持续改进的机会。通过收集和分析这些报告,公司可以寻找系统的根本原因,以及在未来提高准确性的方法。
话虽如此,这也是很有可能的,公司需要注意这样一个事实,即他们不应该通过过度适应来追求业绩。很容易想象,一家公司可能会通过善意的行动,认为它正在根据对某一组不准确预测的反馈进行改进,但无意中它损害了算法的未来整体性能,降低了它在以前表现良好的领域的准确性。
毫无疑问,公司可以从失败中学到很多东西,持续分析失败的趋势以及失败的总体水平是一项富有成效的工作。挖掘根源非常重要,而且说起来容易做起来难。
如果需要对算法进行实质性的修改,该公司需要让 FDA 重新参与讨论,因为没有 FDA 的事先审查和批准,对通过某个阈值的产品的修改是不允许的。这可以包括,例如,算法的重要再训练。
# B.与用户共享信息
许多术语都涉及到人工智能可理解性的一般主题。人们谈论“透明度”、“黑盒”、“可解释性”、“可解释性”等等,而我自己的感觉是,这些词并没有被一致地使用。事实上,在我职业生涯的过去几年里,我在如何使用这些词上并不一致。所以我现在想用我自己的语言说得更清楚些。
关于 FDA 法律,我认为有两个密切相关的概念也是可以清楚区分的。我选择下面的词来描述这两种不同的想法有点武断,因为坦率地说,没有准确的英语标签可用。我将把这些区别建立在 FDA 法律中的重要原则上。
# 1.结构
# a.透明度
FDA 的法律关注的是在用户决定产品是否适合特定用途时提供给他们的信息。FDA 高度重视这一决定,因为正确使用 FDA 监管的产品是其安全性和有效性的关键决定因素。事实上,FDA 最常提起的执法行动之一是对标签外促销的索赔,这是一项法律指控,即销售者提供的信息鼓励产品的使用范围超过 FDA 授权的范围。
需要明确的是,医疗保健专业人员可以随心所欲地使用产品。FDA 的主要关注点是确保医疗保健专业人员从制造商处获得真实的、无误导性的信息。然而,在 FDA 的世界观中,这也意味着将制造商提供的信息限制在 FDA 合法授权的范围内。
我将把人工智能开发者分享公司与这一使用决策相关的信息的义务称为“透明度”。我在这里使用“透明”这个词,因为在这个上下文中,透明意味着分享你所知道的。我稍后会解释,这与开发新信息以解决知识缺口的义务形成对比。透明度在很大程度上是被动的,不需要难以收集的信息。字面意思是不要把信息留给自己。
与任何医疗设备一样,对于基于人工智能的医疗产品,产品的安全性和有效性信息是潜在用户在决定产品是否适合给定的计划用途时需要了解的重要信息。但与其他医疗设备不同的是,随着算法根据新数据进行调整以及性能的发展,这些信息将不断变化。因此,与传统医疗设备相比,人工智能开发人员需要保持这些公共信息最新。
# b.可解释性
除了使用前的适宜性决定,FDA 法律中还有一个相对较新的重点,即医疗保健专业人员是否能够理解软件生成的关于特定患者使用后的建议的基础。这一新的关注点来自 2016 年的一项法律,即《21 世纪治愈法案》。该法案的第 3060 条明确指出,任何授权医疗专业人员独立审查诊断或治疗建议的基础的软件,只要该专业人员不必主要依赖软件建议来做出关于单个患者的临床诊断或治疗决定,则不受监管。在这个世界上,FDA 的规定可能意味着几年的延迟和几十万美元的额外费用,这一条款创造了相当大的激励,以确保用户可以审查建议的基础,而不是依赖它。
我将通过确保用户能够充分理解特定建议的基础来称之为避免 FDA 监管的机会:“可解释性”正如我所使用的术语,可解释性不同于透明性,因为透明性是被动的,专注于使用前的适用性决策(实际上是共享已经存在的信息),可解释性在人工智能的情况下通常要求在算法产生结果后主动创建新的信息。我小心翼翼地措辞以关注结果,认识到可解释性的基础显然必须在软件使用之前就建立起来。
法令并不局限于利用人工智能的软件,对于专家系统来说,可解释性更容易实现,例如,仅仅应用临床指南形式的标准知识来提出建议。非人工智能中的可解释性通常意味着简单地构建软件,以便用户可以轻松地回到知识的原始来源,理解推荐的基础。不幸的是,在人工智能的世界里,解释是极其困难的。
换句话说,可解释性是事实之后的信息,我应该考虑评估我是否相信算法得到了正确的答案。如果算法说我 Brad 很可能有 COVID 19,我该相信吗?
患者和临床医生可能会有关于人工智能生成的建议的基础的具体问题,包括以下内容:
* 算法是如何得出这个结论的?
* 在我的特殊情况下,算法考虑了哪些信息?
* 该算法最依赖什么症状和生理测量作为其结论的基础?
* 为什么算法在得出关于我的结论时如此重视这些症状?
* 我有没有不符合诊断的症状,因为某些原因被忽略了?
* 算法以最终推荐的形式考虑并拒绝了哪些可能性?
重要的是要明白透明性和可解释性是表亲。良好的透明度为更有效的可解释性奠定了基础。但是,虽然它们是相关的,但它们显然是不同的。它们服务于不同的目的,具有不同的监管后果,并且以截然不同的方式产生。
当然,特别是在过去的五年里,在医学人工智能的可解释性方面有大量的研究。该研究面临的核心挑战是,人工智能算法不会像人类一样思考。人类寻找因果关系,而算法寻找关联。在这种意义上,仅仅叙述算法发现 X 和 y 之间的关联是不够的。人类需要更深入的解释,理想地解决因果关系或至少上述问题。
重要的是,法令不要求算法是可解释的。我注意到文献中围绕这一点有些混乱。一些评论家抱怨说,作为其监管过程的一部分,FDA 坚持可解释性。他们不是。相反,如上所述,实现可解释性的一个动机是人工智能开发者希望避免 FDA 的监管以及所有随之而来的成本和延迟。然而,如果一个软件开发者想制造一个不可解释的黑盒,它可能会。该公司只需通过 FDA 的流程,提供足够的证据来证明该算法的安全性和有效性,在这种算法中,用户将无法理解推荐的基础。因此,即使是受管制的产品,也有动机在标签或其他地方向用户提供至少一些解释,作为降低风险的工具,减少所需的安全性和有效性的证据。应该注意的是,尽管 FDA 可能不会坚持向最终用户解释,但作为一个科学机构,FDA 在没有对因果关系有所了解的情况下,将很难授权人工智能的上市。
# 2.选择最佳政策方案时需要平衡的因素
正如在本系列的第一部分中所解释的,找出什么对病人是最好的需要平衡许多因素,这些因素在某些情况下是相互冲突的。我们希望确保用户——通常是医疗保健专业人员(越来越多的患者)——能够在使用人工智能算法之前了解它的优势、劣势和适当使用,以便他们能够在正确的情况下将它用于正确的患者。为了确保知情同意,我们还需要确保患者了解算法的性质,如果有必要依赖黑盒算法,他们也了解风险。与此同时,在一个相互冲突的优先事项中,在我们共享的信息的透明度和可解释性方面,我们需要尊重那些其数据被算法训练的人的隐私利益。
还有其他领域会出现冲突。例如,我们需要平衡这种上市后警惕所带来的负担与创新和获得潜在救命人工智能技术的需求。这意味着不要求更多的监控和更多的纠正措施,但也意味着不要求开发商与公众分享更多不必要的信息,商业秘密信息可能会损害他们将产品商业化的竞争能力。医疗保健是一个行业,它遵循的经济规则与其他行业相同。这意味着如果我们强迫人工智能开发者分享他们的商业秘密,他们可能无法在竞争中生存,因此不愿意投资未来的发展。最后,所有的发展都需要以生产一种具有成本效益的产品的方式进行,这样我们的集体经济资源就能提供这种产品。
# 3.提议:活标签
基于这些竞争因素,我建议我们追求一个“活标签”的概念我所使用的“活标签”这个术语,意味着标签会不断地更新信息,包括透明度和可解释性。通常,对于医疗器械,标签是 FDA 在上市前审查中同意的一组固定的词语。随着时间的推移,有一定的灵活性来改变它们,但不是很多。有了这个活标签的概念,将会有一个与 FDA 的预许可协议,即开发者将更新标签以反映 ABC 区间上最新的 X、Y 和 Z,而不需要新的监管提交。
基于人工智能的医疗设备需要投入更多精力来持续更新标签信息。总的来说,对于一个不断进化的自适应算法,在透明性下跟踪的指标需要不断更新。虽然可解释性可能是静态的,因为软件必须在每次使用时被编程来解释它自己,但是如果可解释性包括动态元素,那么这些动态元素需要保持最新。
在我在第一部分引用的 FDA 报告中,你看到 FDA 提出了本质上相同的东西,即开发者不断共享更新的信息。所以这个概念对我来说并不新鲜,也不独特。然而,我确实有一个与 FDA 不同的实施方案。我们的观点似乎有两点不同。首先,FDA 似乎打算与该机构持续分享至少部分信息。第二,FDA 考虑的可能是更深入、更广泛的信息共享,而不是关键统计数据的汇总。
我建议软件开发人员以概要形式共享信息,而不(1)违反患者保密原则,(2)共享会损害其商业秘密地位的信息,或(3)需要过度昂贵的信息收集和处理。根据人工智能的类型和软件产品的预期用途,确切的方法会有很大的不同。这里有一些公司可以考虑的一般原则。
# a.透明度
市场上基于人工智能的医疗解决方案的开发者应该让现有和潜在的客户了解当前的性能。这意味着共享作为上述监控结果而跟踪的关键指标的适当摘要。这不仅仅是当公司认为发生了有趣的事情时的偶尔更新。这意味着,在适当的时间间隔内,通过某种机制(如公司网站)或更直接地通过产品本身更新关键信息是理所当然的。
这是除了与理解人工智能模型的适当使用相关的信息之外,这些信息可能不会改变,但仍然需要共享。不变的信息包括历史上算法是如何被训练的,这包括关于数据是如何被获取和使用的细节。这是关键,因为基于人工智能的产品的每个用户都需要判断原始训练集中是否存在潜在的任何偏差,这会影响给定的使用。例如,如果我清楚地认识到算法不是针对青少年训练的,我知道如果我想对青少年使用该产品,就会有一些无法量化的风险,即结果将是不准确的。
用户可能还想知道数据是如何清理的?模型训练的特征或维度是什么?数据增加了吗?虽然这些数据显然更具技术性,但一个有见识的用户很可能会对该算法对其特定用途的适用性得出结论。
同样重要的是,公司在质量上要透明,以监控和管理产品上市后的质量。用户会对公司如何允许算法适应、适应有什么限制以及公司正在进行什么质量检查和测试非常感兴趣。随着产品的发展,这些都提供了与使用产品相关的风险的洞察力。
例如,如果我知道该产品被标记为供成人使用,但我看到该公司在程序上没有将新数据仅限于成人,我知道随着时间的推移会有一些风险,即其他用户会添加青少年数据,这将改变产品的性能。再比如,允许算法多长时间适应一次?在像 COVID 19 这样的新传染病发作时,了解数据集受 COVID 患者影响的速度有多快,有助于我理解算法的性能在疫情期间可能会如何变化,或者至少变化有多快。
正如为《福布斯》杂志撰稿的评论员 Ron Schmelzer 所建议的那样,包含模型版本化可能也很重要。他建议“那些生产模型的人也应该清楚和一致地说明模型将如何版本化,模型版本化的频率,以及如果新模型开始表现不佳时使用旧模型版本的能力。”
为了支持正确使用算法的决策,FDA 已经规定了标签中要包含的大量信息,我在此不再赘述。但它包括开发者的预期用途以及在 FDA 批准前用于验证该技术的临床试验结果。
# b.可解释性
用于实现可解释性或 XAI 的确切机制因数据科学领域而异。例如,使用图像分析可能相对容易实现可解释性,软件可以被编程来突出显示感兴趣的区域,即使它不能精确地阐明为什么该区域是感兴趣的。
相比之下,对于利用电子健康记录数据的数据科学模型,XAI 方法可能有点困难,包括以下策略:
* 特征交互和重要性,包括对特征重要性和成对特征交互强度的分析。
* 注意机制,包括在序列中找到与预测任务最相关信息的一组位置的能力。
* 数据降维,正如你可能猜到的,它集中在最重要的特性上。
* 知识提炼和规则提取,将知识从复杂而精确的模型转移到更小、更简单、更快但仍然精确的模型。
* 本质上可解释的模型,它依赖于保留不太复杂的机器学习方法的可解释性,同时通过增强和优化技术来提高它们的性能。[【2】](#_ftn2)
指出关键的有统计学意义的特征类似于一个放射科医生指着图像上的一个地方说,“我以前见过那个,它是恶性的。”我们在医学上“知道”的很多东西只是联想,而没有对因果关系的更深入理解。创新的数据科学家也在开发全新的方法,如视觉模型,以更准确地解释数据科学的结果。
总而言之,为了帮助用户解释人工智能的输出,开发人员可以:
解释能解释的。不要把问题扩大化。如果该软件实际上是专家系统和机器学习的混合,如果某个特定的建议是基于专家系统的,例如简单地查找患者 EHR 中的药物过敏,遵循简单的计算模型或推荐一种治疗方法,因为它更便宜,那么该建议应该会揭示原因。
对于真正依赖于人工智能的软件输出,尽可能精确地陈述支持特定建议的特定关联。如前所述,根据新的研究,在某些情况下,可以确定哪些特性对推荐的影响最大。
传达特定建议的可信度。不确定性对于沟通以做出最佳决策和法律上的知情同意总是很重要的。
# C.向 FDA 报告符合法律可报告性测试的问题
销售 FDA 监管医疗器械的公司必须建立质量体系。该质量体系包括要求这些公司有投诉处理程序。用户投诉可能导致问题的识别。如果这些投诉导致确定了根据所谓的医疗器械医疗器械报告(MDR)法规(21 CFR Part 803)触发报告义务的情况,公司需要向 FDA 报告这些情况。
这种报告义务之所以存在,是因为在某种严重程度上,如果 FDA 认为需要比公司本身计划的更重大的补救措施,并监控同一法规或产品代码中规定的其他产品中类似问题的普遍性,则需要向 FDA 报告。美国食品和药物管理局在人工智能应用于医疗保健之前制定了 MDR 法规,因此可能需要更新指南,以明确在人工智能情况下何时触发报告义务。然而,正如我将在第三部分详细讨论的,FDA 不应该扩大 MDR 义务。
MDR 报告阈值反映了信号和噪声之间的谨慎平衡。软件开发人员有责任从噪音中提取信号,并向机构报告足够严重的信号。这有助于确保该机构接收足够的信息,但不要接收太多的信息,否则会使该机构的系统负担过重,坦率地说,会导致 FDA 错过信号。
如上所述,也有向 FDA 报告的商品化产品的重大变更,但没有上升到需要 FDA 上市前审查的水平。公司显然也应该做这些报告。
# D.允许 FDA 检查公司的数据和记录
除了报告之外,质量体系还要求制造商记录设备的每一项变更,并记录投诉调查和其他经验数据。事实上,几乎所有 FDA 感兴趣的信息都可以在质量体系的记录中找到。
《联邦食品、药品和化妆品法案》第 704 条授权 FDA 在合理的时间、合理的限度内,以合理的方式对生产医疗器械的组织进行检查。这些现场访问的范围允许机构检查质量系统信息以及物理制造和质量系统,以确保符合性。因此,FDA 可以对包含相关信息的质量体系记录进行物理检查。根据法律,医疗人工智能开发者需要允许这些现场 FDA 检查。然而,正如我将在第三部分中解释的那样,FDA 不应该试图扩大法令允许的范围。
在[第三部分](/postmarket-responsibilities-for-medical-ai-5cd43521f546),我将为允许 FDA 更多地参与人工智能商业化的监督所造成的损害陈述理由。FDA 当然是一个重要的监管机构,但作为一个天生保守的监管机构,FDA 并不打算参与人工智能商业化所需的日常决策。
[[1]](#_ftnref1) 我要指出的是,虽然我首先是作为一名律师来处理这个问题,其次才是作为一名数据科学家,但数据科学家能够独立地看到并理解这种差异。参见 Hlozinger 等人的《医学中人工智能的可因性和可解释性》第 4 页,教科书题为《有线数据挖掘知识发现 2019》
[【2】](#_ftnref2)Payrovnaziri,at L,Review,使用真实世界电子健康记录数据的可解释人工智能模型:系统范围审查,美国医学信息学协会杂志,2020 年
[【3】](#_ftnref3)Lamy 等,可解释的乳腺癌人工智能:一种可视化的基于案例的推理方法,人工智能在医学中,2019。
# 医疗人工智能的上市后责任
> 原文:<https://towardsdatascience.com/postmarket-responsibilities-for-medical-ai-5cd43521f546?source=collection_archive---------57----------------------->

production Perig/shutterstock . com
## **第三部分——FDA 不应扩大对商业化人工智能的监管**
在本系列的第一部分[中,我概述了 FDA 现有的监管医疗器械商业化的法定权力。这一权力是巨大的,几十年来一直很好地服务于该机构。它不知道技术的具体形式,并且很容易适应人工智能的需要。但是当涉及到医疗人工智能时,FDA 想要更多。FDA 希望不断了解医疗人工智能在市场上的表现。](/postmarket-responsibilities-for-medical-ai-part-i-fdas-plan-to-increase-its-oversight-dae6d840ffc6)
这不仅是不必要的;这对创新和重要的、可能挽救生命的技术的可获得性肯定是有害的。明确地说,我并不是建议我们简单地相信公司会做正确的事情,定义为每个公司自己认为是正确的事情。相反,我建议将[第二部分](/postmarket-responsibilities-for-medical-ai-56ba67fd8cc)中列出的原则嵌入到 FDA 将颁布的良好机器学习实践法规中。如果公司对上市后警惕性的要求明确,绝大多数开发医疗人工智能的公司都会遵循这些要求。
我所质疑的是,除了澄清医疗人工智能公司在从事上市后警戒时应该遵守的监管要求,我们还增加了这些公司的报告义务。我反对的是报道的增加。国会和 FDA 都不应该修改法律,以(1)要求公司在上市后与 FDA 分享更多信息,(2)允许 FDA 监督产品生命周期商业化阶段的日常决策,或(3)赋予 FDA 进行虚拟检查的能力。
在这第三部分,我将概述这三个反对扩大 FDA 对商业化医疗人工智能的报告义务的主要论点。
# A.林业发展局不应增加公司的报告义务
# 1.信息量将是巨大的
在未来几年,在医疗保健领域部署人工智能的公司将大量收集上市后数据。我们不会试图在这里预测到底有多少,但希望每个人都同意这将是一个巨大的数字。
如果 FDA 要求公司开始向该机构移交哪怕一小部分数据(包括性能数据和在主动监控下收集的其他数据),也会让该机构不堪重负。我们理解 FDA 目前受到人力资源的限制,特别是那些有人工智能软件背景的人。坦白地说,该机构没有配备人力或信息系统来阅读和解释上市后持续传递给它的数据。
即使 FDA 努力与医疗器械利益相关者合作建立国家卫生技术评估系统(NEST ),这也是事实。NEST 将永远没有必要的资源来确保为 NEST 将收集的所有真实证据提供适当的上下文。
如上所述,MDR 背后的整个理念是要求公司在向 FDA 报告时区分信号和噪音。该法规包括针对故障和严重伤害的特定相关性测试,公司将使用这些测试来评估信息是否需要报告给 FDA。事实上,FDA 过去曾表示,多报是违反 MDR 法规的,因为该机构担心多报会用噪音掩盖信号。因此,历史上传递给 FDA 的信息量已经过仔细的滴定,以确保它集中于相关信号,并排除干扰噪声。采用人工智能来改变这种精心制定的长期方法是没有依据的。
换句话说,我确实认为公司将不得不投入相当多的资源来监控他们的算法在上市后的表现,如上所述。但是,这并不意味着我们也应该考虑增加对 FDA 的报告,特别是因为该机构不太可能具备处理额外信息的能力。
# 2.原始信息对 FDA 没有什么价值
除了反对通过降低被认为重要的门槛来增加软件开发商必须提交的 MDR 报告的数量,开发商不应该被要求与 FDA 分享更多的原始信息流。我所使用的术语“原始信息”是指软件开发人员直接收集的信息,没有经过任何分析或语境化。
现有 MDR 法规的另一个目的是确保原始信息不会简单地转储到 FDA。来自市场的原始信息本身几乎没有任何信息。从市场上收集的所有信息都需要进一步的调查和重要背景的分析,以理解信息的临床和技术意义。公司自己也经常这样做。当他们发现一个潜在的信号时,他们会深入了解这个信号的含义。
在这方面,人工智能与其他任何医疗设备没有什么不同。它将产生大量的信息,比传统的医疗设备产生的信息要多得多。除非放在适当的上下文中,否则这些信息实际上是没有意义的。现有的质量体系条例(21 CFR Part 820)规定公司有责任对投诉和其他质量信号进行调查。然后是 MDR 法规,要求公司向 FDA 报告任何潜在的严重信号,以便该机构可以参与最终决策。
任何让公司与 FDA 分享原始信息的方法都可能只会增加该机构的负担,而不会有任何结果。如果没有适当的背景,即使假设 FDA 能够建立必要的信息技术和人力资源来分析信息,也会导致混乱。
现有的 MDR 义务,建立在质量体系义务之上,就潜在问题向 FDA 提供有意义的上下文报告。没有理由背离这种方法。
# B.FDA 不应该介入人工智能新产品商业化的日常决策
大多数人都听说过这样一个笑话:“我来自华盛顿,我是来帮助你的。”坦率地说,政府监管的介入几乎从来不会对被“帮助”的公司有所帮助。
# 1.食品和药物管理局可能会不必要地干预公司的运作
与 FDA 过度分享有一个明显的缺点,那就是过多的噪音会让该机构感到困惑。如果 FDA 有人力和计算机资源来读取数据,并且如果 FDA 能够理解原始数据,缺乏上下文可能会导致 FDA 反复询问报告公司问题,并可能在实际上不应该采取行动时要求采取行动。对数据的部分或不完全理解会产生潜在的风险,即该机构将采取不明智的行动,从而给公司带来巨大的负担。
# 2.FDA 会无意中伤害人工智能初创公司
一家小公司根本无法在美国食品和药物管理局每天向其提出大量问题的情况下运营。该机构的这种微观管理水平将对行动造成毁灭性打击。最终结果将是公司无法将足够的资源投入到包括质量保证在内的运营中。那么,病人将会因为公司的分心而遭受损失。
此外,FDA 要求公司提供的数据量会迫使公司花费额外的资源来满足 FDA 的要求。虽然大公司可以更容易地吸收这些额外的员工,但小公司,尤其是初创公司,却不能。长期来看,这将使初创公司更难创新重要的新的 FDA 监管的人工智能。
# 3.与 FDA 分享太多信息会产生公开披露的风险
正如已经解释过的,我同意,如果公司分享更多关于部署的自适应或自主人工智能的信息,这将符合每个人的最佳利益。但是正如我也说过的,FDA 和我可能在谈论完全不同的领域,哪些信息应该共享。
公司应该分享产品性能的适当总结。在一家公司的网站上分享几个段落,也许是总结产品当前性能的表格或图表,将有助于所有用户了解应该在多大程度上依赖(或不依赖)该产品。对所有人来说,理解算法输出的不确定性程度以及其他统计度量是很重要的。
然而,无论如何,公司都不应该与公众或 FDA 共享原始数据,甚至是带注释的数据,这样我们就可以期望接收者进行他们自己的分析。这将违背几乎所有其他领域的现有商业惯例。
人工智能开发者在竞争激烈的市场中运作。事实上,人工智能领域竞争激烈,因为它不需要大量资本进入,至少在早期阶段不需要。此外,专利保护不足以完全保护这些公司免受竞争威胁。
正如已经观察到的,如果我们希望人们在这些企业上冒险投入时间和金钱,他们必须能够保护这些投资。要求公司广泛而自由地分享原始数据供所有人分析只会导致公司在其他地方投资,而不是追求这些技术。这样的数据会让竞争对手对算法的机制有太多的了解。此外,如前所述,病人最终会失败。
美国法律体系一直要求公司诚实披露信息,并披露他们需要披露的任何信息。现有的产品责任法以及广告法中的真实性要求(1)肯定的披露和(2)披露的真实性。几十年来,美国的制度是建立在这样一个前提之上的,即我们将依赖公司的直率和诚实,但我们不会要求它们分享为其业务创造价值的机密商业信息和商业秘密。
即使只是向 FDA(一个像所有联邦机构一样受《信息自由法》约束的机构)披露信息,也会产生这样的风险,即如此共享的信息会进入公共领域。FDA 必须对其认为应该发布的产品做出判断,而这些判断决不是绝对可靠的。这里有两个独立的风险。
第一,FDA 只是犯了个错误,发布了不该发布的信息。这种情况并不经常发生,但重要的是要明白,上市后收集的可能以电子方式传输的数据可能会意外地被放在公开发布的数据集中。判断应该发布什么信息通常需要仔细的人工审查。目前,该系统对上市前申请中提交的数据工作得相当好,但上市后收集的数据则完全不同,而且更加复杂。FDA 获得的数据越多,他们在管理上就越难决定哪些是可以公开发布的,哪些是不可以公开发布的,从而更容易出错。
第二,也是更大的风险,是食品和药物管理局会简单地以不同于制造商的方式解释法律,并发布制造商不同意受 FOIA 发布条款约束的信息。有整本书都在讨论 FOIA 的范围,但是在一个高层次上,FDA 必须决定什么是不公开发布的,因为它是商业秘密或者机密的商业信息。这些定义不是很精确,关于人工智能的信息实际上是否属于这些受保护的类别,法律学者之间有很大的不同观点。例如,被清理或操纵的训练和验证数据集是机密商业信息还是商业秘密?关于算法考虑哪些特征的知识呢?或者算法的源代码、其规格和调整参数,以及将预测转化为行动的任何辅助计算机程序的编程细节?这些决定涉及许多法律判断。
一旦数据掌握在 FDA 手中,尽管公司可以通过行政程序为自己辩护,但最终信息的发布掌握在 FDA 手中,并受到司法监督。只有当一家公司事先得到通知并有机会反对时,这种情况才会发生。简而言之,增加公司所需的数据共享会不可接受地增加数据落入那些想要伤害公司的人手中的风险。
此外,这不仅仅是竞争威胁。外面有坏人。看看网络安全攻击就知道了。更进一步,还有人故意在社交媒体上散布误传,伤害他人。除了经济原因,他们还有各种各样的原因。然而,即使在经济领域,也不仅仅是竞争对手。人们会在负面新闻的帮助下进行投资押注(例如,卖空股票的人)。
复杂的原始信息,同样在没有重要背景帮助的情况下,可能会被误解并被用来伤害公司和影响市场。要求发布难以理解和复杂解释的未经语境化的原始数据不会带来公众的信任,反而会导致错误信息和混乱。
正如我在上面所说的,但是我要再说一遍,我确实同意公司对统计上重要的信息进行适当的总结将有助于利益相关者正确地使用技术。利益相关者必须理解技术的局限性,而这些局限性将随着时间的推移而演变。因此,更新这些总结将是重要的一步。
然而,期望公司分享原始的甚至是有背景的原始信息供公众分析是一个坏主意。竞争影响将过于消极,其他错误信息的风险也将过于巨大,因此这不是一个明智的做法。
# C.FDA 不应回避现场物理检查
FDA 不应通过强制要求公司以电子方式向该机构发送记录来绕过现场实物检查要求,因为这样做会有效地扩大报告义务,这与刚才陈述的论点相反。
为了将这一切结合在一起,我建议坚持 MDR 系统的现有框架,即公司在自己的上市后审查中保持警惕,寻找可能出现的信号,并将有问题的信号报告给 FDA。此外,如前所述,公司将收集广泛的信息,并在持续的基础上生成内部报告,以监控其产品的性能,这些信息作为质量系统的一部分,将在现场检查期间供 FDA 审查。
这并不是说我建议对 FDA 隐瞒这些信息。但是,我建议,除了明确要求报告的信息之外,这些信息只有在现场实际检查后才能提供给 FDA。正是实际检查访问的要求使 FDA 免于不必要的微观管理。如果 FDA 真的必须去该公司查看记录,FDA 只有在有足够的理由感兴趣时才会这样做。这个小小的措施,要求 FDA 进行现场视察,在确保 FDA 监督的实际水平方面产生了巨大的影响。
近年来,食品和药物管理局一直试图绕过明确的法定限制,他们进行实地考察。不难理解为什么。只需拿起电话,打电话给制造商,告诉他们将信息发送给代理商,就可以节省资金。尴尬的是,制造商非常关心 FDA 的权力,并希望让 FDA 满意。这种强制手段非常有效。它导致公司在不需要的时候以电子方式提交信息。
然而,这种情况必须停止。除非在非常特殊的情况下,如疫情,否则不应该允许食品和药物管理局进行实际的现场检查。虽然 FDA 很想这样做,但我认为 FDA 应该避免这样做。正如我在上面所说的,要求 FDA 在要求查看公司记录之前采取个人访问的肯定步骤是有明确逻辑的。这是对过度监管的一个微妙但非常重要的限制。
实际上,FDA 的行为违反了规定公司报告义务的 MDR 法规。应要求公司自行严格监控,向 FDA 报告符合法定 MDR 标准的可疑问题,然后在现场访问时向 FDA 提供所有数据。然而,这应该是它的极限了。
# 结论
一切从病人开始,也从病人结束。我的父亲在我之前是一名食品和药品律师,他总是告诉我,如果我面对一个含糊不清的法规,从有利于病人的角度去解释它,我就不会出错。政策制定也是如此。弄清楚什么对病人最好。
监管对病人有好处,但要适度。过度监管是很有可能的。对于像人工智能这样的新兴技术,我们需要特别敏感地正确对待这一点。由于监管太少,严厉的过度监管肯定会给患者带来不好的结果。不必要的阻碍新技术通过减少可及性伤害了患者。
谈到监管已经上市的产品,我们在医疗设备方面有几十年的经验,可以应用于新技术。虽然人工智能有一些使其不同于传统医疗设备的基本要素,例如它们在市场上随着时间的推移而变化,但这并不一定意味着需要一种新的范式。
如果人工智能开发者履行他们的责任,进行必要的上市后警戒,现有的上市后范式将会相当好地工作。并非所有的上市后产品监管决策都值得 FDA 首先参与。我们应该合理地相信公司会做正确的事情,而不是假设他们会做错误的事情。
与此同时,我做这行已经 35 年了,我没有幻想过行业中的每个人都是可敬的。可惜世界上总有坏人。
在这种情况下,平衡一切,法律中需要的改进是我理解的 FDA 已经在追求的,这是一套良好的机器学习实践。这些 GMLPs 需要尽可能明确,而不是规定具体的,关于上市后公司管理产品生命周期阶段的义务。这不是附加报告。这只是 GMLP 应该实施的标准,要求公司按照上述思路积极主动地保持足够的警惕,而不仅仅是被动地做出反应。有了这一点,监管专业人士可以帮助确保公司尽一切努力负责任地管理使用可适应人工智能的内在风险。
法律关于上市后警戒的明确性,而不是 FDA 的额外监督,将平衡患者安全与新产品开发中的创新需求。
詹姆斯·奥莱利,联邦信息公开,2020 年第一版。
# 医疗人工智能的上市后责任
> 原文:<https://towardsdatascience.com/postmarket-responsibilities-for-medical-ai-part-i-fdas-plan-to-increase-its-oversight-dae6d840ffc6?source=collection_archive---------69----------------------->

HeartBeat/Shutterstock.com
## 第一部分——FDA 加强监管的计划
房间里有一头大象。我们需要讨论的紧张气氛。FDA 正试图说服医疗保健领域的人工智能开发商,让该机构对上市产品拥有比目前更广泛的权力和权限,以换取更快的上市前审查时间。我对工业界的建议?不要这样做。不要同意会给 FDA 扩大上市后权力的监管变化。就不值得了。
需要说明的是,我给出这个建议并不仅仅是因为 FDA 未能量化任何上市前优势,无论是提交给该机构所需证据的减少还是更快的审查。相反,这是我的建议,仅仅是因为给予 FDA 扩大上市后授权的成本太高了。虽然我同意在将能够适应新数据的医疗人工智能商业化时,扩大警惕性确实是必要的,但我敦促医疗人工智能行业积极主动地接受自己的上市后监测和持续改进的责任,而不是增加 FDA 的监督。
这是一个很大的话题,所以我把它分成三个不同的部分,分别发表。这篇文章的第一部分,我提供了 FDA 计划要求国会给予更多法律权力来监管医疗人工智能市场的背景。此外,作为背景,我将描述食品和药物管理局现有的权力,我将提出我们应该评估扩大监管监督是否对病人最好的标准。第二部分将重点关注医疗 AI 开发者现在应该做什么,以承担营销医疗 AI 的责任。换句话说,我将谈论我希望行业采纳的最佳实践。然后,第三,在我的最后一篇文章中,我将说明为什么国会不应该给予 FDA 对医疗人工智能商业化的扩大监督。
# A.FDA 现有的上市后角色
就背景而言,理解 FDA 已经在监督医疗器械的商业化方面发挥了重要作用是很重要的,但这是一个受法律约束的角色。以下是 FDA 对市场上医疗产品的一些更重要、更相关的法律权威的高度概括:
如果一家公司想以实质性的方式改变一个上市的医疗器械,该公司通常需要在做出改变之前获得 FDA 的许可或批准。产品或标签的微小变化也有例外。此外,除非有重大更新,否则也可以提交中间报告,包括 II 类器械的“文件信函”以及 III 类器械随后可在年度报告中汇总和报告的报告。
制造商需要跟踪他们收到的投诉,以及他们根据质量体系进行的调查,以评估这些投诉的重要性。制造商保留所有这些记录,FDA 有权进行现场检查,允许他们访问包括这些记录在内的所有质量信息。
制造商有持续的义务向 FDA 报告其产品售后引进的问题。这些问题要么是产品以物质方式伤害了某人,要么是产品出现了故障,即使没有伤害任何人,如果故障再次发生,产品也有可能伤害到某人。FDA 可以惩罚没有报告这些事件的公司。
FDA 有权下令召回,尽管更典型的情况是 FDA 仅仅哄骗制造商开始召回。
如果通过法律程序,FDA 可以要求特定的制造商对其产品进行上市后监督。
FDA 可以启动任何数量的法律程序,如扣押行动,以追查它有理由相信正在生产不符合法律规定的产品的制造商。FDA 也可以提起惩罚性的法律诉讼,如在不良行为发生后处以巨额民事和刑事罚款。
FDA 还有其他几项法律权力,如禁止它认为不安全的某些产品,以及在没有法院的情况下行政性地扣留它担心的产品。
但是,在该机构看来,当涉及到人工智能的商业化时,这对 FDA 来说是不够的。
# B.房间里的大象
每次 FDA 提出其监管人工智能的新愿景的话题,除了讨论上市前审查流程和质量系统要求的变化,FDA 还在讨论结束时提出其扩大上市后权限的愿望。我分享两个例子。
# 1.软件预认证计划
FDA 似乎在 TSA 针对美国航空旅客的预检计划之后模拟了其拟议的预认证计划,这表明它将为愿意接受严格预认证的制造商提供更快的市场路径,以确保他们有可能生产安全有效的医疗软件的强大质量文化。这是一个大话题,坦率地说,FDA 的提议有很多优点和缺点。该计划仍在开发中,并处于试点阶段。
但具体到本文的目的,FDA 已经明确表示,它希望扩大与该拟议计划相关的上市后授权。在 2019 年 1 月发布的该计划的最后一次公开迭代中,[【1】](#_ftn1)FDA 观察到:
> 我们相信,优秀的组织不仅在开发[作为医疗设备的软件]产品时关注质量,而且在产品推出后,他们还会基于从其产品的真实使用中获得的经验教训而成长和发展。虽然具体的[真实世界绩效,或 RWP]数据元素和分析方法可能因组织和产品类别而异,但优秀的组织始终从不同来源收集和分析上市后数据,为其运营和决策提供信息,从质量控制到新细分市场的产品开发。
在这一点上我们意见一致。但在观察到该计划中的所有公司都应该收集此类数据后,FDA 表示这些公司应该:
> 允许 FDA 访问与组织卓越性和产品级安全性和有效性相关的数据元素分析。
至少在该计划的试点阶段,FDA 希望持续收到收集的上市后信息。
> 在 FDA 的交互式审查和双方同意提议的[真实世界性能分析,或 RWPA]计划足以监控[作为医疗设备的软件,或 SaMD]产品的安全性和有效性后,试点参与者将通过组织定义的流程和方法收集和分析 RWP 数据元素,并按照约定与 FDA 共享选定的 RWPA。
然后,FDA 通过解释为什么该机构希望访问公司的上市后数据来证明他们增加的共享上市后数据的要求是合理的:
> 预认证组织在上市后数据收集方面的稳健报告和增加的透明度也可能使 FDA 能够探索优化预认证组织现有上市后义务的机会,包括报告和检查要求。…选定的 RWPA 跟踪现实世界健康分析、用户体验分析和产品性能分析可以定期提交给 FDA 定期访问 RWPA 将增加 FDA 对收集的数据类型和由预先认证的组织监测的任何潜在信号的熟悉程度。该机构认为,当产品需要修改或更新时,这种增加的熟悉度将促进 FDA 和预认证组织之间的合作。旨在快速解决任何上市后安全或安保问题的合作参与,反过来可能会减少合规行动的需求,并简化对任何所需产品修改的审查。虽然进入 RWPA 将允许 FDA 与单个制造商合作,以保持产品质量并确保患者安全,但它还可能使 FDA 能够识别所有产品类别中潜在的或新出现的问题,并在产品质量受到影响之前通知制造商。
请注意,美国食品和药物管理局正非常努力地向工业界推销这个想法。我可以继续引用这份文件,但你明白了。FDA 很想看看上市后的数据。再加上他们要看周期,我们也不知道周期是什么意思。然而,从上下文中似乎可以清楚地看出,它必须相当频繁,否则那些所谓的好处就不会实现。
# 2.2019 年人工智能概念文件
虽然预认证计划将适用于所有用作医疗设备的软件,但 FDA 在其 2019 年 4 月的 AI/ML 概念文件中对人工智能的描述更加具体。[【2】](#_ftn2)首先,这里有两个定义,对于理解这种 AI/ML 监管方法的基本结构很重要。
> SaMD 预规范(SPS):SaMD 制造商对“性能”或“输入”的预期修改,或与基于 AI/ML 的 SaMD 的“预期用途”相关的更改。
>
> 算法变更协议(ACP):制造商为实现和适当控制 SPS 中描述的预期变更类型的风险而采用的特定方法。
使用该框架,该机构然后陈述其对上市后报告的期望。
> 通过这个框架,制造商将被期望致力于基于 AI/ML 的 SaMD 的透明性和真实世界性能监控的原则。FDA 还希望制造商定期向 FDA 报告作为批准的 SPS 和 ACP 的一部分而实施的更新,以及这些 SaMD 的性能指标。这一承诺可以通过各种机制来实现。
>
> 透明度可能包括对 FDA、器械公司和制造商合作者以及公众(如临床医生、患者和普通用户)的更新。…[M]制造商可能会考虑如何实现透明的独特机制——他们可能希望建立沟通程序,描述如何向用户通知更新(例如,信函、电子邮件、软件通知)以及可以提供哪些信息(例如,如何恰当地描述当前版本和以前版本之间的性能变化)。
>
> 真实世界的性能监测也可以通过各种建议的机制来实现,这些机制目前正在 FDA 使用或处于试点阶段,例如……通过 Pre-Cert 程序进行真实世界的性能分析。报告类型和频率可根据设备的风险、修改的数量和类型以及算法的成熟度进行调整(即,如果算法处于成熟阶段,季度性能变化极小,则季度报告不太可能有用)。
该机构似乎对自己的角色有着比许多外部人士所理解的更远大的愿景。底线是 FDA 想成为你的商业伙伴。他们想在产品的整个营销过程中监督你,对下一步应该发生什么做出自己的独立判断。
# C.了解 FDA 的行为
在本文的第三部分,我将提出反对扩大 FDA 上市后监管的理由,我想弄清楚为什么我认为这是一个如此糟糕的主意。我在第三部分中的许多论点都将基于组织行为,这是心理学的一个分支,它认为我们所有人在某种程度上都会对我们工作的组织结构、目的和文化做出反应。
学者们早就建议政府机构使用“理性-法律权威”领导框架来组织工作。[【4】](#_ftn4)大约 80 年前,马克斯·韦伯列举了许多政府组织的原则,包括:正式的组织等级制度,按规则管理,按职能专业组织,根据技能和技术资格选拔人才,以及有目的的非个人化环境(例如,对组织的所有成员应用相同的规则和结构)。作为一个拥有约 15,000 名员工的联邦机构,根据 FDA 的宗旨和组织结构,我们可以预测整个组织的某些行为风格。
为了理解 FDA 的文化,我们需要理解并真诚地同情 FDA 必须运作的环境。FDA 因为避免了问题而得到政治和公众的称赞,但更典型的是因为医疗产品造成的伤害而受到政治和公众的批评。机构领导人通常被传唤到国会作证,就国会声称 FDA 在审查中遗漏的问题作证。
不仅如此,FDA 还面临着一个巨大的挑战,那就是招募有才华的科学家为一个薪水跟不上工业发展的联邦机构工作。尽管这导致了巨大的人员流动,但更根本的是,这意味着该机构必须采取不同于悬空薪酬的招聘策略。FDA 的招聘策略非常简单:以任务为导向。来 FDA,有所作为。这吸引了许多人,但尤其吸引了那些想有所作为的人。FDA 的人通过阻止有害产品进入市场来改变现状。该机构的整个方向是围绕其监管任务。
部门主管等中低层员工拥有巨大的权力,可以根据自己的个人判断做出决策,而这些判断往往相当保守。FDA 的决定应该是科学驱动的,但科学往往不是决定性的,需要判断。虽然通情达理的人可能会不同意,但当高级官员试图否决低级官员时,低级别的 FDA 雇员有时会认为 FDA 经理的行为是出于错误的原因,例如,遵循可能来自白宫的广泛政策声明。FDA 的雇员向国会议员抱怨说,他们认为 FDA 的管理遵循政治冲动,而不是科学,因此,FDA 的领导不愿意否决他们的雇员。这给了那些一线员工巨大的权力去做出他们认为正确的决定。
因此,对于一家试图在医学领域创新人工智能的公司来说,FDA 作为一个机构可能是最糟糕的商业伙伴。虽然我下面解释的更多,但是我要明确的是,这是因为组织行为学和心理学;这与食品药品管理局的个人无关。事实上,FDA 的许多人都是我在全世界最喜欢的人。他们是典型的聪明、勤奋和充满激情的奉献者。大多数人都非常擅长自己的工作。此外,每天都有大量的 FDA 决定是有充分的事实、科学和法律依据的。但不是全部。
FDA 有工作要做,作为一个联邦执法机构,包括实际携带枪支的特工。[【6】](#_ftn6)重要的是要记住,就此而言,FDA 不是 NIH 或 CDC。药监局抓罪犯。他们通过威胁、正式的机构强制行动和司法强制,使任性的、有时是不诚实的行业成员回到正轨。代表各地消费者,我很高兴。
然而,有时 FDA 会使用其他不太正式的强制手段,如负面媒体,也许是当他们觉得自己的法律理由不充分,或者他们只是不想花费资源。这实际上是 FDA 的常用策略。以 1991 年为例,当时 FDA 专员大卫·凯斯勒(David Kessler)命令联邦代理人没收超过 12,000 加仑的 Citrus Hill 橙汁,指控这些果汁被错误地标注为“新鲜”。“今天的行动将发出一个明确的信息,即 FDA 不会容忍这样的违法行为,”FDA 专员大卫·凯斯勒在佛罗里达州棕榈滩花园的一次会议上说。他们试图公开羞辱公司以达到他们的目的。在橙汁事件中,宝洁公司(T2)坚信其使用“新鲜”一词是合法的。鉴于他们的责任,食品和药物管理局采取强硬手段。我当然不同意该机构使用的一些策略。
这些都没有让 FDA 成为一个好的商业伙伴。他们首先是一个监管执法机构,这是理所应当的。
# D.判断最佳政策方法的标准
在这一系列文章中,我提出了一种政策方法来管理人工智能在医疗保健领域的风险,同时这种产品已经上市。在考虑最佳政策方针时,我们需要把重点放在病人身上。无论是从行业、政府还是医疗保健提供商的角度来看,共同点是我们都是为了服务患者而存在的。我们必须把病人放在第一位。
在某些方面,说起来容易理解起来难。把患者利益放在第一位真的没那么简单。做对病人最好的事涉及到许多因素的平衡,其中一些因素经常是互相对立的。下面我将列出一些较大的因素,但我不会详细讨论每一个。关键是,即使患者是等式的中心,在这里找出最佳方法也不是基于一个简单的因素。
**患者安全性和有效性**。弄清楚如何实现对患者的安全性和有效性需要检查科学证据,但可接受的风险收益的实际水平最终仍是主观的。根据希波克拉底誓言,医生首先被要求不伤害任何人。但重要的是要理解安全性——通常被认为是预防伤害——通常包含有效性措施,从某种意义上说,使用一种不起作用的产品可能意味着患者没有使用其他有效的产品。因此,在设计人工智能时,与所有医疗设备一样,重要的是产品不仅要有适当的安全水平,还要有有效性的证据。对于随着时间的推移而适应的产品,这也意味着使用上市后的警惕性来确保产品继续有效,并且我们将继续在适当的患者中使用该产品,同时考虑到软件的培训。
**授权患者决策**。这是一个重要的哲学需要。在医学上,我们有知情同意的概念,强调“知情”这个词。患者必须对风险和益处有足够的了解,才能在知情的情况下决定是否需要某种医疗服务。坦率地说,这个问题也有经济含义,因为我们想确保患者和他们的护理人员做出适当的购买决定,以便好的产品在市场上占优势,坏的产品靠边站。这里还有一个消费者信心和信任的因素,如果购买者相信产品是高质量和有效的,市场的规模将会增加,这将会扩大市场准入以及产品研发。
**患者隐私。**就医疗人工智能而言,人们强烈要求透明——软件开发人员共享信息。当开发人员考虑共享这些信息时,他们必须确保这样做不会无意中危及已经接受治疗的患者的隐私。
**可用性/访问和结果**。显而易见,只有医疗专业人员和患者能够使用人工智能这样的技术,才能挽救生命。为了进入市场,显然产品必须首先被发明出来。创新依赖于足够的投资回报,这需要保护知识产权。所有这些听起来显而易见,但它在政策制定中往往被低估。开源技术和透明到不保护商业秘密的程度并不总是能给软件开发带来足够的激励。
**性价比。**同理,如果买不起,技术也没用。技术必须在更大的医疗经济学范围内考虑。此外,产品必须是可持续的,这可能取决于费用是由第三方支付还是由患者支付。同样,这似乎是显而易见的,但监管政策的成本后果往往被低估。
**法律责任。**医疗技术的联邦法规旨在让开发商和销售链中的其他人对他们销售给市场的技术负责。因此,该系统需要包括适当的政府监督和企业责任。
挑战在于找到所有这些因素的正确平衡,为患者优化人工智能的发展。这些因素并不都朝着同一个方向。它们需要在它们之间进行权衡。
## 结论
在这一系列文章中,我试图将这些因素考虑在内,在必要时平衡它们,在[第二部分](/postmarket-responsibilities-for-medical-ai-56ba67fd8cc)中提出最佳实践,以及在[第三部分](/postmarket-responsibilities-for-medical-ai-5cd43521f546)中解释 FDA 应该发挥的有限作用。
[【1】](#_ftnref1)[https://www.fda.gov/media/119722/download](https://www.fda.gov/media/119722/download)
[【2】](#_ftnref2)[https://www . FDA . gov/files/medical % 20 devices/published/US-FDA-人工智能-机器学习-讨论-论文. pdf](https://www.fda.gov/files/medical%20devices/published/US-FDA-Artificial-Intelligence-and-Machine-Learning-Discussion-Paper.pdf)
[【3】](#_ftnref3)史蒂文·麦克沙恩、玛丽·冯·格里诺,《组织行为学》,2018 年第 8 版。
[【4】](#_ftnref4)韦伯,马克斯,《社会经济组织论》。由 A.M .汉德森和塔尔科特·帕森斯翻译。伦敦:科利尔·麦克米伦出版社,1947 年。
[https://www . medpagetoday . com/Washington-watch/FDA general/30954](https://www.medpagetoday.com/washington-watch/fdageneral/30954)
[【6】](#_ftnref6)[https://www . Reuters . com/investigates/special-report/USA-FDA-cases/](https://www.reuters.com/investigates/special-report/usa-fda-cases/)
[【7】](#_ftnref7)[https://www . UPI . com/Archives/1991/04/24/FDA-seizes-orange-juice-in-labeling-battle/9056672465600/](https://www.upi.com/Archives/1991/04/24/FDA-seizes-orange-juice-in-labeling-battle/9056672465600/)
# 使用掩模 RCNN 训练定制对象检测模型
> 原文:<https://towardsdatascience.com/pothole-detection-with-mask-rcnn-b78d18a89915?source=collection_archive---------10----------------------->

照片由 Marc-Olivier Jodoin 在 Unsplash 上拍摄
> 从安装和培训到在 webapp 中部署定制的经过培训的对象检测模型的完整指南。
# 背景
根据维基百科,“坑洞是路面上的凹陷,通常是沥青路面,交通已经清除了路面的碎片”。据报道,截至 2015 年,加拿大阿尔伯塔省的埃德蒙顿“自称为坑洞之都”,每年花费 480 万美元用于 45 万个坑洞。在印度,每年大约有 1100 人死于由坑洞引起的事故。当当局不了解情况时,普通公民没有办法向有关当局传达或报告糟糕的道路。
因此,几个组织一直在尝试开发工具(如 web 应用程序),市民可以向有关当局报告坑洼。已经举办了几次黑客马拉松,把这个项目作为目标之一。鉴于这一问题日益受到关注,在这个项目中,解决这一问题的目标是**开发一个简单的界面,使用最先进的物体检测技术来实时检测坑洞,并使用谷歌地图报告它们**。这篇文章将带你完成建立你自己的坑洞探测系统的步骤。根据 Newzoo 的 2019 年全球移动市场报告,该项目的部署介质将是印度 5 亿多人使用的智能手机。
使用的工具:
* Python 3.6 以上版本
* Tensorflow 对象检测 API
* 像素注释工具
* Anaconda 包管理器
* 瓶
该项目的工作流程如下:
* 环境设置
* 数据集收集
* 模特培训
* 用烧瓶展开
* 结果
# Anaconda 环境设置
开始时,我们将建立一个新的 Anaconda 环境,并安装这个项目所需的所有必要的包。Anaconda 是和“pip”一起流行的 python 包管理器。如果您在此项目之前没有安装,请使用下面的链接进行安装。
这是一个相当简单的安装过程,应该不会花很长时间。如果你有使用命令行的经验,你可以安装 [Miniconda](https://docs.conda.io/en/latest/miniconda.html) ,但是如果你愿意,贵由可以安装带有所有附加软件包的 [Anaconda Navigator](https://www.anaconda.com/products/individual) (这将需要更长的安装时间)。
之后,从开始菜单中打开“Anaconda Prompt ”,并按照安装说明的其余部分进行操作:
1. 创造康达环境。
(base) C:\Users>conda create --name pothole python=3.6
2.激活环境并升级 pip。
(base) C:\Users>activate pothole
(pothole) C:\Users>python -m pip install --upgrade pip
3.通过发出以下命令安装其他必需的软件包:
(pothole) C:\Users>conda install -c anaconda protobuf
(pothole) C:\Users>pip install pillow
(pothole) C:\Users>pip install lxml
(pothole) C:\Users>pip install Cython
(pothole) C:\Users>pip install contextlib2
(pothole) C:\Users>pip install jupyter
(pothole) C:\Users>pip install matplotlib
(pothole) C:\Users>pip install opencv-python
(pothole) C:\Users>pip install labelme
(pothole) C:\Users>pip install tensorflow-gpu==1.15.2
4.从 Github 克隆或下载 tensorflow 对象检测 api 存储库。出于这个项目的目的,我们使用 tensorflow 版本 1.15.2。**注意始终确保安装的 tensorflow 版本和 tensorflow 对象检测 api 存储库版本相同**。运行下面的命令或者手动下载这个[库](https://github.com/tensorflow/models/tree/r1.13.0)。
(pothole) C:\Users>git clone https://github.com/tensorflow/models.git
将这些文件夹放在名为“模型”的文件夹中。您可以将这个“模型”文件夹放在您选择的目录中。
5.配置 PYTHONPATH 环境变量并安装 COCO api:
(pothole) C:\Users>set PYTHONPATH=C:\models;C:\models\research;C:\models\research\slim
(pothole) C:\Users>pip install git+https://github.com/philferriere/cocoapi.git#subdirectory=PythonAPI
6.编译 Protobufs 并运行 setup.py
在 Anaconda 提示符下,将目录更改为\models\research 目录
(pothole) C:\Users>cd C:\models\research
运行以下代码行:
protoc --python_out=. .\object_detection\protos\anchor_generator.proto .\object_detection\protos\argmax_matcher.proto .\object_detection\protos\bipartite_matcher.proto .\object_detection\protos\box_coder.proto .\object_detection\protos\box_predictor.proto .\object_detection\protos\eval.proto .\object_detection\protos\faster_rcnn.proto .\object_detection\protos\faster_rcnn_box_coder.proto .\object_detection\protos\grid_anchor_generator.proto .\object_detection\protos\hyperparams.proto .\object_detection\protos\image_resizer.proto .\object_detection\protos\input_reader.proto .\object_detection\protos\losses.proto .\object_detection\protos\matcher.proto .\object_detection\protos\mean_stddev_box_coder.proto .\object_detection\protos\model.proto .\object_detection\protos\optimizer.proto .\object_detection\protos\pipeline.proto .\object_detection\protos\post_processing.proto .\object_detection\protos\preprocessor.proto .\object_detection\protos\region_similarity_calculator.proto .\object_detection\protos\square_box_coder.proto .\object_detection\protos\ssd.proto .\object_detection\protos\ssd_anchor_generator.proto .\object_detection\protos\string_int_label_map.proto .\object_detection\protos\train.proto .\object_detection\protos\keypoint_box_coder.proto .\object_detection\protos\multiscale_anchor_generator.proto .\object_detection\protos\graph_rewriter.proto .\object_detection\protos\calibration.proto .\object_detection\protos\flexible_grid_anchor_generator.proto
如果出现找不到 protobuf 文件的错误,请在以下时间后运行:
protoc object_detection/protos/*.proto --python_out=.
最后,我们需要运行以下命令:
(pothole) C:\models\research> python setup.py build
(pothole) C:\models\research> python setup.py install
8.您可以通过运行名为“object_detection _ tutorial . ipynb”的 object _ detection 文件夹中的 IPython 笔记本来测试一切是否正常。
(pothole) C:\models\research>cd object_detection
(pothole) C:\models\research\object_detection>jupyter notebook object_detection_tutorial.ipynb
您可以使用我的存储库来获得本文的支持材料。
[](https://github.com/SamdenLepcha/Pothole-Detection-With-Mask-R-CNN) [## SamdenLepcha/带面罩的坑洞探测-R-CNN
### 这个存储库包含来自文章“用掩模 RCNN 检测坑洞”的项目。你可以找到关于…的文章
github.com](https://github.com/SamdenLepcha/Pothole-Detection-With-Mask-R-CNN)
# 数据集收集
与往常一样,在任何数据科学或人工智能项目的开始,在问题陈述被确定之后,我们继续收集数据,或者在这种情况下,收集用于训练的图像。
为了训练一个健壮的模型,我们需要使用大量的图片,但是也要有变化。这意味着坑洞必须以不同的角度或形状出现,这样我们的模型就不会倾向于一种变化,或者说过度拟合,也不会推广到其他图像。
你可以使用你自己拍摄的图片,或者像我一样从网上下载。对于这个项目,我们的想法是检测坑洼,这样我们就不会根据严重程度将它们分割出来,但这也为未来的范围留下了一些东西。以下数据源用于构建此项目:
* [卡格尔](https://www.kaggle.com/atulyakumar98/pothole-detection-dataset?select=potholes)
* [研究门](https://www.researchgate.net/publication/282807920_Dataset_of_images_used_for_pothole_detection)

按作者分类的数据集中的图像
我们需要调整图像的大小,以便可以使用这些调整后的图像(如本项目中的 800 x 600)来训练模型(除非你有无限的 GPU 计算能力)。使用命令提示符或 anaconda 提示符或任何其他 IDE 来运行这个脚本。例如,在 Anaconda 提示符下:
(pothole) C:\Users> python DatasetCreation.py
# 数据标记
现在我们已经收集了数据集,我们需要标记图像,以便模型了解什么是坑洞。为了给图像贴标签,我们需要一个贴标签软件。
为了这个项目的目的,我使用了 labelme,因为它使用起来相当简单。在您的 anaconda 环境中输入“labelme ”,软件应该会像下面这样打开。
(pothole) C:\Users>labelme
从你的目录中打开你的图像,点击创建多边形,开始给你的图像加标签。Labelme 将您的标签保存为与图像名称同名的 json 文件。将 json 放在与图像相同的目录中。Labelme(右)和像素注释工具(左)的示例如下所示。对于这个项目,我已经标记了 400 张图片。

像素注释工具(左)和 Labelme(右)的图像(作者提供的图像)
# 模特培训
1. 创建 TFRecords:
在标记了我们的整个数据集之后,我们现在必须生成 TFRecords,作为我们的模型训练的输入。但在此之前,我们需要将 json labelme 标签转换成 COCO 格式。我采用了 Gilber Tanner 在他的教程中提供的脚本来执行此操作。你也可以在我的标有“ [labelme2coco.py](https://github.com/SamdenLepcha/Pothole-Detection-With-Mask-R-CNN/blob/master/place_in_object_detection/images/labelme2coco.py) ”的 Github 存储库中找到它。下载并把它放到你的训练/测试图像所在的目录中。现在运行以下命令:
(pothole) C:\Users\models\research\object_detection\images>python labelme2coco.py train --output train.json
(pothole) C:\Users\models\research\object_detection\images>python labelme2coco.py test --output test.json
既然训练/测试数据是 COCO 格式的,我们现在可以使用同样由 Gilber Tanner 创建的 create_coco_tf_record.py 来创建 TFRecords。[这个脚本](https://github.com/SamdenLepcha/Pothole-Detection-With-Mask-R-CNN/blob/master/place_in_object_detection/create_coco_tf_record.py)也需要从 object_detection 文件夹中放置并运行。
python create_coco_tf_record.py --logtostderr --train_image_dir=images/train --test_image_dir=images/test --train_annotations_file=images/train.json --test_annotations_file=images/test.json --include_masks=True --output_dir=./
您应该在 object_detection 文件夹中找到 train.record 和 test.record。
2.正在创建标签映射
标签映射将类名链接到 ID 号。使用类似 Sublime Text 的文本编辑器创建一个“labelmap.pbtxt”并将其存储在 object_detection/training 文件夹中。在文件夹内写下以下内容:
item {
id: 1
name: 'Pothole'
}
您可以根据您想要检测的类别来定义您想要的数量,但对于这个项目的目的,我们只对检测坑洞感兴趣。
这个 id 应该与您的 train.json 和 test.json 文件中提到的 id 相匹配。请注意它是如何大了一个数字的,即这里是 id: 0,但我们在 labelmap 文件中提到了 id:1。
"categories": [
{
"supercategory": "Pothole",
"id": 0,
"name": "Pothole"
},
],
3.正在创建培训配置文件:
现在我们需要创建一个培训配置文件。从[张量流模型动物园](https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md)有各种各样的张量流模型可用于 Mask RCNN,但为了这个项目的目的,我们将使用[Mask _ RCNN _ inception _ v2 _ coco](http://download.tensorflow.org/models/object_detection/mask_rcnn_inception_v2_coco_2018_01_28.tar.gz),因为它的速度。下载该文件并将其放在 object_detection 文件夹中。您可以在 samples/config 文件夹中找到 mask _ rcnn _ inception _ v2 _ coco . config 文件。复制此文件夹并将其放入 object_detection/training 文件夹。现在,我们必须对这个配置文件进行以下更改:
* 第 10 行:将 num_classes 更改为您希望分类器检测的不同对象的数量。(在本项目中为 1)
* 第 126 行:将微调检查点更改为:
fine_tune_checkpoint: "
* 第 142 行:将 input_path 改为 train.records 文件的路径:
input_path: "
* 第 158 行:将 input_path 改为 test.records 文件的路径:
input_path: "
* 第 144 行和第 160 行:将 label_map_path 更改为标签映射的路径:
label_map_path: "
* 第 150 行:将 num_example 更改为测试文件夹中图像的数量。
4.训练模型:
运行以下命令,从 object_detection 文件夹开始模型的定型:
python legacy/train.py --train_dir=training --pipeline_config_path=training/mask_rcnn_inception_v2_coco.config
在每个间隔之后,模型将检查点保存在 training 文件夹中。让它训练到损失低于 0.05 是个好主意。花费的时间将取决于你的 GPU 有多强大。
您可以通过打开另一个 Anaconda 提示符窗口,将目录更改为 object_detection 文件夹,并键入以下命令来查看模型的进度:
(pothole) C:\models\research\object_detection>tensorboard --logdir=training
这将在您的本地计算机上创建一个网页,您可以通过 web 浏览器查看该网页。TensorBoard 页面提供了显示训练进度的信息和图表。

Tensorboard 示例(图片由作者提供)
在命令提示窗口中,可以通过按 Ctrl+C 来停止训练。我建议在它在你的文件夹中创建检查点后停止,这通常是每 5-10 分钟做一次,取决于你的计算能力。步骤数最高的检查点将用于生成冻结推理图。
5.导出推理图
在 object_detection 文件夹中创建一个名为“inference_graph”的文件夹。现在我们可以创建冻结的推理图(。pb 文件)放在这个文件夹中。要解决这个问题,请发出以下命令:
python export_inference_graph.py --input_type=image_tensor --pipeline_config_path=training/mask_rcnn_inception_v2_coco.config --trained_checkpoint_prefix=training/model.ckpt-2194 --output_directory=inference_graph
这个冻结的推理图是对象检测分类器。
6.测试新训练的分类器
为了测试新训练的分类器,您可以对我的 Github Repo 中已经存在的 [object_detection.ipynb](https://github.com/SamdenLepcha/Pothole-Detection-With-Mask-R-CNN/blob/master/place_in_object_detection/object_detection_tutorial.ipynb) 文件进行修改。
更改 labelmap,inference_graph,.配置文件和 test_images 目录。您应该得到以下输出:

测试图像的输出(作者提供的图像)
# 使用烧瓶展开
Flask 是一个用 Python 编写的微型 web 框架,由阿明·罗纳彻开发。我们将使用 Flask 来部署我们定制的经过训练的对象检测模型。你可以在他们的[官方文档](https://flask.palletsprojects.com/en/1.1.x/quickstart/#a-minimal-application)上找到初学者教程。
我们将在 Flask 应用程序中使用 object_detection.ipynb 文件中的代码。代码名为“ [app.py](https://github.com/SamdenLepcha/Pothole-Detection-With-Mask-R-CNN/blob/master/app.py) ”,也在我的 Github 库中。在我们的 app.py 文件的开始,我们导入我们的库,并在对象检测 api 所在的位置附加我们的 Python 路径。根据您放置该文件的位置进行更改。
Flask 应用程序的简单架构可以用下图来描述。

Flask Webapp 架构(图片由作者提供)
我们将图像作为定制训练的掩模 RCNN 模型的输入,该模型基于准确度分数来决定是否给出坐标。您可以通过运行以下命令来运行“app.py”。
python app.py

flask 应用程序在命令提示符下的输出(图片由作者提供)
运行上面的命令后,我们应该得到下面的输出。将它复制到您的浏览器中,以便 web 应用程序呈现 HTML 页面。这件事我做得很糟糕。你们可以通过修改 HTML 和 CSS 文件来为这个项目创建更好的界面或 UI。您可以在下面的结果部分找到所有的输出图像。
# 结果
这个部分只包含项目的各种输出图像。
* 这是将来自 Anaconda 提示符的 URL 复制到您选择的浏览器后的第一页。

Webapp 主页(图片由作者提供)
* )这是选择并上传您选择的图片后的页面。

加载后的 Webapp(图片由作者提供)
* 这是点击提交按钮后的页面。请注意,只有当分数高于 50%时,下方的按钮才会出现。

模型预测后的输出(图片由作者提供)
点击下方的按钮后,输出结果状态,得到当前位置。为了不暴露我的位置,我已经把地图缩小了不少,但是你可以非常精确地放大坐标。您可以尝试建立一个架构,其中您在线维护一个位置数据库,以便页面可以显示这些坐标,但对于这个项目的目的,我们只是显示图像上传的当前位置。所以图像必须在同一个地方拍摄和上传。

最终谷歌地图功能的输出(图片由作者提供)
感谢您阅读到本文结尾。这就是本教程的内容。我希望您喜欢这篇文章,并希望它对您的数据科学之旅有所帮助。你可以在我网站的博客部分找到更多这样的文章。
[](https://www.samdenlepcha.com/#blogs) [## 萨姆登·莱普查
### 在这次以“人工智能/机器学习”为主题的黑客马拉松中,我们为他们的……
www.samdenlepcha.com](https://www.samdenlepcha.com/#blogs)
# 参考
1. 3 年内超过 9300 人死亡,25000 人因路面坑洼受伤— [今日印度](https://www.indiatoday.in/india/story/over-9300-deaths-25000-injured-in-3-years-due-to-potholes-1294147-2018-07-24)
2. S & Booysen,M.J. (Thinus) & Kroon,RS(2015).[用于坑洞检测的图像数据集。10.13140/RG.2.1.3646.1520](https://www.researchgate.net/publication/282807920_Dataset_of_images_used_for_pothole_detection?channel=doi&linkId=561ccc7b08ae78721fa2b350&showFulltext=true)
3. 如何在 Windows 10 上使用 TensorFlow (GPU)训练一个针对多个物体的物体检测分类器— [Github](https://github.com/EdjeElectronics/TensorFlow-Object-Detection-API-Tutorial-Train-Multiple-Objects-Windows-10)
4. 使用 Tensorflow 对象检测 API 的自定义遮罩 RCNN—[介质](https://medium.com/@vijendra1125/custom-mask-rcnn-using-tensorflow-object-detection-api-101149ce0765)
5. 使用 Tensorflow 对象检测 API 训练 Mask R-CNN 模型— [Gilbert Tanner](https://gilberttanner.com/blog/train-a-mask-r-cnn-model-with-the-tensorflow-object-detection-api)
6. HTML 地理定位 API — [w3schools](https://www.w3schools.com/html/html5_geolocation.asp)
# 功耗分析变得简单
> 原文:<https://towardsdatascience.com/power-analysis-made-easy-dfee1eb813a?source=collection_archive---------20----------------------->
## 如此简单,你可以用手来做。

你已经重新设计了你网站的登陆页面,现在你需要对它进行 A/B 测试。您应该运行测试多长时间?本文将演示如何使用样本大小计算(“功效分析”)来回答这个问题。
统计学可能是一门令人望而生畏的学科,但也不尽然。这些指南的目的是让人们更容易使用统计工具。确保您熟悉抽样分布的概念(如果您需要复习,请参见此处的)和比例度量标准误差的计算(请参见此处的)。尽情享受吧!
# 1.计划 A/B 测试
您想要 A/B 测试您的登录页面的重新设计。目前的登录页面平均每天有 200 名访客,点击率为 5%。您认为重新设计将带来至少 7%的点击率。一旦我们平均分配流量,当前的登录页面(控制)每天应该看到 100 个访问者,重新设计(测试)每天也应该看到 100 个访问者:
测试和控制的预计流量和性能
为了验证测试确实优于控制,您应该运行测试多少天?
# 2.如果我们运行测试,比如说,7 天呢?
假设我们计划只运行我们的 A/B 测试 7 天,此时我们每组将收集 700 个访问者。让我们计算零假设(总体 CTR 无差异)和替代假设(总体 CTR 有真实差异)的抽样分布。
**第一步:计算汇集样本比例(p)。**

**第二步:用 *p* 计算标准误差( *se* )。**

**第三步:计算抽样分布。**
* ***H0(零假设)*** : 均值= 0,标准差= 0.013 的正态分布。
* ***HA(替代假设)*** : 一个均值= 0.02,标准差= 0.013 的正态分布。
让我们绘制这些分布图:

H0 和 HA 在 7 天数据收集后的抽样分布
在显著性水平(𝛂)为 0.05 时,临界值为 0.0249。这意味着:
## 1.如果样本 CTRs 的绝对差值>为 0.0249,我们将总是**拒绝**零假设(H0)。
* 如果 H0 是真的,那么拒绝它的决定将是不正确的(类型 1 错误)。这种情况的发生率为 100 次实验中有 5 次(𝛂).
* 如果哈确实是真的,那么拒绝 H0 的决定将是正确的。这将发生在 35/100 的实验中(1-𝛃).这种速率也被称为 ***功率*** 的一种测试。
## 2.如果样本 CTRs 的绝对差≤ 0.0249,我们总是 ***无法拒绝*** 零假设(H0)。
* 如果 H0 确实是真的,那么不拒绝它的决定将是正确的。这种情况的发生率为 95/100(1-𝛂).
* 如果 HA 为真,那么不拒绝 H0 的决定将是不正确的(类型 2 错误)。这种情况的发生率为 100 次实验中有 65 次(𝛃).
总结一下:
A/B 测试所有潜在结果的描述
我们决定仅运行 7 天的 A/B 测试,这将导致我们在 100 个实验中的 65 个实验中无法检测到测试组的升高。这个错误率太高了!通常,我们希望将该值降至 20%,相当于 80%的幂。我们可以通过增加样本量来实现这一点。
**重述:通过运行 7 天的 A/B 测试,因此,每组收集 700 个访问者的样本量,我们实验的功效只有 35%。为了达到 80%的功效,我们需要增加样本量,这意味着让 A/B 测试运行更长时间。**
# 3.手动计算 80%功率所需的样本大小
要获得 80%功率的测试,我们需要多大的样本量?
让我们将零假设下的采样分布转换为一个 ***标准正态分布*** 以使计算更简单:
* 显著性为 0.05 的临界值约为 1.96,可从[查找表](https://en.wikipedia.org/wiki/Standard_normal_table#Table_examples)中获得。
* 如果我们现在考虑给定替代假设的采样分布,那么我们希望-1.96 和 1.96 之间的曲线下面积等于 20%(对于 80%的功率)。因此,临界值必须距离平均值约 0.84(也可从查找表中获得)。
* 所以总的*标准化的*均值之间的差值一定是 1.96 + 0.84 = 2.8。
这可能更容易用图形来理解:

我们还知道,*真实的*均值之间的差值为 0.02,因此,*标准化的*差值等于 0.02 / se。所以我们可以构造一个等式并求解 n:

所以我们需要收集每组 2211 个观察值。按照每组每天 100 名访问者的速度,我们需要运行测试至少 23 天,以获得 80%功率的实验。在这种样本规模下,如果重新设计的页面确实提供了至少 7%的点击率,那么我们在 100 次实验中有 80 次可以检测到这种提升。
**概述:参考标准正态分布,我们能够确定平均值之间的标准化差值在 80%功率下应为 2.8 左右。然后,我们可以用标准误差来表示,然后求出 n。我们计算出 n = 2,211 次观察。**
# 4.R 中的统计分析
至此,您应该对样本大小计算(功效分析)的总体框架感到相当满意了。现在,让我们看看如何将上述所有步骤简化为几行代码。在 *R* 我们会写:
它产生:
[1] "absolute difference (Test — Control)"
0.02[1] "pooled sample proportion"
0.06[1] "standardized distance for requested power"
2.80158521811297[1] "solve for n"
2213.38408508644
# 电源分析——你从未听说过的最酷的东西。
> 原文:<https://towardsdatascience.com/power-analysis-the-coolest-thing-that-youve-never-heard-of-476d35c18161?source=collection_archive---------45----------------------->
## 从头做起
## 将权力投入到您的物流决策中。

> [笔记本](https://github.com/emmettgb/Emmetts-DS-NoteBooks/blob/master/Julia/using%20powerlog%20to%20our%20advantage.ipynb)
无论我说什么,T2
> “基本概率”
可能立即跳入你脑海的是统计学中的贝叶斯数学(可能是宗教的)。贝叶斯定理或条件概率定理都是很好的例子,说明为什么这是一个很好的假设。尽管条件概率与贝叶斯统计有很强的关系,但是,有很多独特而有趣的方法来进行推理。当你在一台计算机和程序机器学习算法(数据科学超级力量)后面时,尤其如此。)我主观地认为,统计学和统计学家这两个派别(很可能是宗教派别)实际上合作得非常好,或者可以互换。今天我将向你展示如何在 Julia 中使用简单的数学来操作逻辑概率。
逻辑回归功效分析的迷人之处在于,执行它的数学是相对基础的,不需要任何递归成本训练或任何类似的东西(甚至不需要 sigmoid 或 relu。)这不仅方便,而且性能很好,易于编程和操作。此外,您可以将这种分析重新应用到机器学习算法中,并将其用于您的优势。
# 说明
逻辑回归功效分析通常用于确定样本量。统计学家中一个常见的误解是,你的样本量是静态的;也就是说,对于每一种情况,没有一个特定的样本量。幸运的是,使用一个逻辑的决策模型将允许你为几乎任何场合计算一个精确的样本大小。作为一个额外的好处,功耗分析还可以做很多其他的事情。
# 该功能
为了执行功耗分析,我们需要一些输入变量。不要太担心这些简短的解释,因为如果您处于未知领域,它可能在函数的示例使用中更有意义。

首先,我们需要 p1 和 p2。这两个值中的 p 是一个概率,所以本质上,我们有
> 概率 1 和概率 2。
> 记住:这些不是 P 值,而是百分比。
我们还需要阿尔法。一个**阿尔法水平**是一个类型 I 错误的概率,所以当它为真时,你拒绝零假设。这是在 ***对比*** 到**贝塔水平**中,正好相反,会让你接受你的零假设。确保不要在这个问题上选边站,**你不能选择是接受还是拒绝你的空值**。有时候我喜欢用迷因来阐述观点,不久前我发现了这个:

(不是质量最好的)
我们的最后一个值是 rsq,rsq 是预测变量(y)和模型中所有其他变量(X('s))之间的多重相关的平方。我们需要在这个函数中获取的第一个值是 l1 和 l2:
pd = p2 - p1
l1 = p1/(1-p1)
l2 = p2/(1-p2)
如果 X 是一个未知变量,其概率分布为 f(x ),其特征为未知参数θ,随机样本 X1 的大小为 n,X2……..X2 XnX1……..Xn 然后统计ϕ=h(X1,X2,)是θ\左(\θ\右)的点估计量。我们也可以说ϕϕ是θ的参数空间。所以本质上,当我们声明 l1 和 l2 时,我们所做的是,用我们的两个概率来设置θ的参数空间。现在我们计算θ,就像用较高概率(p2)的参数(l2)除以较低概率(p1)的参数(l1)一样简单。
θ = l2 / l1
现在我们需要λ,我们可以通过简单地记录θ来得到。这可以在 julia 中用 log()方法完成(正如您可能已经想到的。)我们也可以继续做λ。
λ = log(θ)
λ2 = λ^2
接下来,我们需要一个正态分布,我们还想获得正态分布的分位数,在 Julia 中,我们将使用 Julia 基本统计库中的分位数函数:
za = quantile(Normal(),1-alpha)
这里我使用的是软件包“Distributions.jl”,这当然是一个很棒的软件包,可以在 Julia Pkg 注册表中找到,但是计算您自己的正态分布是相对简单的。如果你熟悉标准定标器,它就是**一样的东西。**您只需从 X 的迭代中减去样本均值,然后除以标准偏差。
f(x)=[I =(I-μ)/σfor I in x**)**
您可能已经注意到我使用了一个语法循环,这是有意为之的,因为 quantile()方法的语法不会采用单个规范化值,因为它依赖于分布和 1-alpha 来计算 za。
using Lathe.stats: mean, std
Function
function normald(array)
σ = std(array)
μ = mean(array)
v = [i = (i-μ) / σ for i in array]
return(v)
end# Syntactual expression
normald(x) = [i = (i-mean(x)) / o for i in x]
现在我不确定 Julia 是否真的使用了 syntactual 表达式,但是发行版中的 Normalize()方法很有可能也适用于这个特定的实例。
> 朱利安提示:分位数是通过点`((k-1)/(n-1), v[k])`之间的线性插值计算出来的,对于`k = 1:n`其中`n = length(v)`。
接下来,我们将打印出双尾检验的值。这一步当然是可选的,但对于这一特殊功能来说,这无疑是一个很有价值的步骤:
println("One-tailed test: alpha = ",alpha,", p1 = ",p1,", p2 = ",p2,", rsq = ",rsq,", odds ratio = ",or)
> 如果你还在继续,这就是我们现在的情况:

接下来,我们需要计算小写 delta。幸运的是,对于这个特定的操作,我们已经有了可用的值。它看起来是这样的:
δ = (1 + (1 + λ2)exp(5 * λ2/4))/(1 + exp(-1λ2/4))
我们将为样本大小和功效值创建两个空数组。
pwr = zeros(Float64,8)
nn = zeros(Int64,8)
然后,最重要的是,我们添加一个循环来迭代我们的幂和样本大小,并给出一个返回:
i = 1
for power = 0.6:.05:.95
zb = quantile(Normal(),power)N = ((za + zbexp(-1 * λ2/4))^2 * (1 + 2p1δ))/(p1λ2)
N /= (1 - rsq)
pwr[i] = power
nn[i] = ceil(Int64,N)
i += 1
end
return(pwr,nn)
最终结果看起来有点像这样:

# 例子
假设,让我们说我们正计划为我们的一个空缺职位招聘人员。在我们的带回家的面试中,我们给每个人都做了一个测试,他们必须通过这个测试才能被录用——但是那些分数较高的人更有可能被考虑。我们预计,只有大约 25%的人会在测试中取得高于样本平均值的分数。然后我们还会考虑多 15%的分数会比平均值高出一个标准差,或者
μ < p1 = .25 + .15 = p2 < σ
有了这个表达式,我们可以假设值 p2 将是那些测试的 15%+= P1,所以在我们的例子中,我们得到 0.40。现在如果我们把它代入公式:

现在我们可以用 zip 函数并行打印我们的幂和样本大小(或者成对连接它们,由您决定。)
for (i,w) in zip(pwr,nn)
println("Power: ", i, " n: ", w)
end

功率的技术定义是,它是检测到一个“真实”效应存在时的概率。在大多数情况下,功耗分析涉及许多简化假设,以使问题易于处理,并使用不同的变量多次运行功耗分析,以涵盖所有的意外情况。
# 描绘我们的力量
当然,为了完成这一切,我们必须将这些数据可视化。为此,我将使用我的包 Hone.jl。
using Hone

看起来我的系统上有 0.0.1 版本的 Hone.jl,但没关系,我可以忍受它…我们在这里可以观察到的是,随着功率的增加,nn 也会增加。我们可以利用这些数据做的另一件有趣的事情是回到那个迭代循环,记录更多的功率。
# 结论
坦白地说,我认为很多读者知道这种方法是可能的。话虽如此,我希望能从这篇文章中吸取一些东西。我在制作它的过程中获得了很多乐趣,我肯定会在 Julia、R 和——你猜对了,Python 中添加更多“从头开始”的机器学习模型(也许我会变得疯狂,做一些 Scala 或 C,谁知道呢。)
# Power BI 101 —简而言之的数据整形
> 原文:<https://towardsdatascience.com/power-bi-101-data-shaping-in-a-nutshell-1df4681bdfd3?source=collection_archive---------28----------------------->
## 在 Power BI 101 系列的第 2 部分中,了解什么是数据整形,以及为什么学习这个概念可以将您的 Power BI 数据模型提升到新的高度

马库斯·斯皮斯克在 Unsplash 上拍摄的照片
在这一系列 Power BI 101 文章中,我将尝试涵盖并解释与 Power BI 相关的不同基础概念,例如数据整形、数据剖析和数据建模。
*理解这些概念对于创建最佳商业智能解决方案至关重要。一旦您掌握了这些基本概念,您将能够构建可扩展且灵活的电力 BI 报告解决方案,为其现有环境增加真正的商业价值。*
在 Power BI 101 系列的[上一篇文章中,我解释了什么是数据概要分析,为什么您应该关注它,以及当您应用适当的技术来检查和增强您的数据质量时,您可以如何受益。](/go-getem-sherlock-doing-data-profiling-in-power-bi-like-a-pro-44f448730e6c)

照片由 Ash Edmonds 在 Unsplash 上拍摄
## 塑造它,塑造它,宝贝!
一旦您熟悉了您的数据,并意识到您计划在您的商业智能解决方案中使用的数据中可能存在的陷阱,您就应该执行数据整形阶段(我有意使用术语“商业智能”而不是“Power BI”,因为这是一个应该在 Power BI 解决方案之外使用的通用概念)。
简而言之,数据整形是数据整合的过程,**在**成为数据模型的一部分之前。关键要记住的是两个字:之前!因此,我们应该在数据进入报告本身之前进行数据整形。
数据整形可以在不同的地方进行,也可以在数据准备过程中的不同时间点进行,这取决于您应用数据整形技术的位置。
## 我应该在哪里执行数据整形?
首先,让我们看看可以在哪里进行数据整形:
* ***源数据库*** —这是最明显的选择,在大多数情况下也是最理想的场景。它基于传统的数据仓库原理,即 **E** 提取- **T** 转换- **L** 加载(ETL)数据。
在这个场景中,您定义想要提取的数据(并不需要数据库中的所有数据,并且通常导入所有数据并不是一个好主意)。然后,您决定是否需要在此过程中转换数据,以更好地满足您的报告需求,例如,您是否需要执行货币转换,或者您是否需要符合城市名称(纽约,NY,NYC)。
此外,您应该为列和属性指定用户友好的名称,并在将数据加载到数据模型之前决定是否需要聚合数据。
* ***Power Query***—Power BI 内置的工具,可以对数据进行[的各种变换](/power-query-tips-for-every-power-bi-developer-da9ebd3dcd93)。根据微软的官方文档,您可以应用 300 多种不同的转换,而且这个数字还在不断增加!
对于某些数据源(例如 Excel 文件),没有在源端转换数据的选项。因此,对于这种数据源和许多其他“非数据库”数据源,Power Query 是显而易见的选择。

帕特里克·亨德利在 Unsplash 上的照片
在 Power Query 中执行不同的数据整形步骤时,最重要的考虑是 ***如果查询折叠*** !我将在另一篇文章中讨论查询折叠,但是此时,了解什么是查询折叠是很重要的。
用最简单的话来说,查询折叠就是 Power Query 将您的请求“翻译”成数据源“理解”的单个语句的过程,从而使您的请求更高效地执行。
理解查询折叠的概念对于数据成形过程极其重要。如果您正在使用关系数据库的数据源,那么您应该考虑在源端执行所有的数据整形,并在一个单独的步骤中将您的数据加载到 Power BI 中(如果可能的话,从一个单独的数据库对象,如 database view),而不是在加载了 数据之后应用额外的转换 ***,因为这会破坏查询折叠并使您的数据加载/数据刷新效率低下!***
*根据经验,您应该将所有的数据整形和转换尽可能地推向数据源!*
* ***数据模型*** —最后一个,也肯定是最不想要的选项,是在数据模型本身上执行数据整形。这是您想要避免的情况,并且通常是不充分和糟糕的计划的后果。这意味着,例如,您可以使用 DAX 创建计算列,但是您应该知道这不是一个最佳的解决方案——计算列是后台表格引擎的额外开销,因为它们不能被最佳压缩。
## 强大的查询=强大的数据整形
现在,我们已经绘制了一幅大图,并对数据整形进行了总体概述,如果您阅读了这篇文章,我假设您对 Power BI 的数据整形特别感兴趣。因此,我想更深入地解释 Power BI 数据整形。

照片由 Aditya Joshi 在 Unsplash 上拍摄
正如我们之前所了解的,Power BI 为您提供了执行数据整形任务的强大工具。进入 Power BI Desktop 后,您可以单击“主页”选项卡下的“转换数据”来打开 Power Query 编辑器:

有一大堆可用的转换来使您的数据达到最佳状态,例如重命名列和表、更改数据类型、删除列、过滤行、替换值、将首行提升为标题、旋转/取消旋转列等。我们将把重点放在几个你可能会经常使用的地方。

在上图中,在左侧,您可以看到数据模型中所有表/查询/函数的列表,而在右侧,您可以看到应用于特定表/查询的所有转换步骤。转换步骤是按照您应用它们的顺序记录的,记住这一点很重要,因为您应该致力于在一个单独的步骤中应用类似的转换,而不是经常在转换之间切换。
例如,如果要从列中筛选数据,应该在一个步骤中应用所有筛选条件:

在上图中,我过滤了 DimCustomer 表,只保留了姓 Adams、性别为男性的客户。您可以看到,Power Query 在一个语句中应用了这两个过滤条件,因此在左边创建了一个转换步骤。
现在,假设我想从我的数据模型中删除一个列后缀,然后我想过滤掉所有年收入> 50.000 的男性 Adams 客户。

正如您所注意到的,我们现在有了一个额外的步骤来过滤 YearlyIncome 列。这是一种不好的做法,你应该避免。尽可能在一个步骤中应用所有类似的操作,因为这将提高数据加载/数据刷新过程的效率。
这里可以看到的另一个不好的实践是转换步骤的命名。如果你在 Power BI 中独立工作,并且你有不到 10 个转换步骤,看起来可能没那么糟糕。但是想象一下当您看到 30 多个转换步骤时的场景,这些步骤的名称有:删除的列 1、筛选的行 1、更改的类型 1、筛选的行 2、删除的列 2 等等。您需要打开每一个步骤来确定应用了哪些转换!
因此,不要偷懒,以人类可读的方式重命名每个步骤:

你必须承认现在看起来方便多了!
## 常用转换
正如我已经提到的,Power Query 为您提供了 300 多种方式来塑造您的数据。当然,你不可能把它们都用上。像任何其他工具一样,有一些特性您比其他的使用得更频繁。
因此,对于 Power Query,如果右键单击表中的特定列,可以看到“最常用”转换的列表:

这些选项将在 80–90%的情况下完成工作,但是如果您需要执行一些高级转换,或者甚至手写 M 代码来实现您的目标,这里有一个好消息:您也可以在 Power Query 中这样做!
“转换”选项卡提供了一系列全新的高级功能,包括数据内容操作(替换值、格式化值等)。),以及数据结构增强(旋转/取消旋转列、拆分列、转置表等)。):

让我们不要忘记 Add Column 选项卡,它为您提供了应用一整套不同技术的可能性,以便用新的列来增强您的数据模型,从而为您现有的数据模型带来额外的业务价值。

了解特定的 Power 查询转换在现实中如何执行的最好方法是——使用它们!测试、尝试并查看哪些技术和转换以最有效的方式满足了您的业务需求。
## 结论
为了能够创建最佳的数据解决方案,数据整形是需要理解的关键概念之一。理解这个概念并将其应用到实际项目中,坚持我们在本文中研究的一些最佳实践,将增强您的数据模型,并帮助它们变得更加健壮、可伸缩和可重用。
在数据分析和数据建模阶段的协同作用下,适当的数据整形为您的商业智能解决方案提供了实质性的质量,并作为其中的一部分增强了 BI 报告。
感谢阅读!
成为会员,阅读 Medium 上的每一个故事!
订阅[这里](http://eepurl.com/gOH8iP)获取更多有见地的数据文章!
# Power BI:向图表添加类别“其他”
> 原文:<https://towardsdatascience.com/power-bi-add-category-other-to-charts-354267ec1809?source=collection_archive---------1----------------------->

资料来源:Pexels.com
# 问题是
微软一直在以更快的速度改进 Power BI。每当我遇到缺点时,我的第一个想法是等待,并假设它会很快被新的更新解决。然而,等待仪表板的客户并不总是分享我的乐观和耐心,因此,我经常需要有创造力。
我前阵子遇到的一个问题是有一个分类太多的饼状图;当你有一个饼状图,比如说 20 个不同的百分比(显然总和为 100%)时,这个图表可能会变得难以阅读。当然,您可以使用 Power BI 的 top-N 特性,但是这将不可避免地排除剩余的数据。这意味着 100%将只包含可见的分区,这可能会造成混乱。
对此的解决方案是将某个百分比设置为阈值,并将低于该阈值的所有部分一起分组到名为“其他”的分区中。

将截止值设置为 10%之前和之后
更好的方法是添加一个可以动态改变阈值的切片器。在尝试了一些度量和查询之后,我想到了下面的解决方案。

结果呢
让我向您介绍一下我的方法,这样您就可以自己尝试了…
# 蓝图
## 数据
在动手之前,了解您的数据非常重要。对于这个例子,我使用了洛杉矶湖人队 2015-2016 赛季的统计数据,这是科比·布莱恩特的告别赛季。在本例中,我们将只使用两列图表;球员的名字和他们在整个赛季中的得分。

我们将使用的数据
既然你理解了数据,我们可以开始工作了。
## 添加类别“其他”
如果您想绘制一个功率 BI 值,应该有一行或一个度量值。假设在您的数据中没有名为“ *Other* ”的没有值的行,您有两个选择;创建新行或使用度量。度量看起来是最佳选择,但是这意味着您必须将它与您已经拥有的行结合起来。因此,添加新行对我来说似乎是最好的选择。
在 Power BI 中,您不能简单地向已经加载的表中添加新行,而是可以创建自己的表并追加新行。通过一些简单的步骤,你可以添加一个名为“*其他玩家*”的新玩家。因为他的分数会随着他所代表的玩家数量而变化,我们会给这个玩家零分,至少现在是这样。
1. 手动创建一个具有相同列标题的新表格(*‘输入数据’*)
2. 仅创建一行。该表应该如下所示:

为额外的“其他玩家”行创建表格。
3.将该表追加到包含分数的主表中。(*编辑查询/转换数据—主页—合并—追加查询*)
好了,数据准备好了。但是在我们开始衡量之前,我们需要做更多的准备。
## 创建动态阈值
**注意**:如果对动态百分比不感兴趣,可以跳过这一步。如果您想使用一个固定的阈值(例如 10%),您可以跳到下一节“编写度量”。如果您希望用户动态更改百分比,您必须遵循另一个步骤:
准备工作非常简单。您只需手动创建另一个表,如下所示:

为百分比切片器值创建一个表。
对于这个例子,我创建了 0 到 15%之间的值,但是您当然可以使用您喜欢的任何范围和步长。
注意:确保该表没有以任何方式连接到数据集中的其他表。设置好表格后,您可以向报告中添加一个切片器,从中可以选择所需的分界点。
## 写度量
准备工作到此为止。是时候写解决方案的核心了;衡量标准。
为了让我的代码更具可读性和可调整性,我倾向于使用很多变量。让我们从定义一些关键值开始:我们在切片器中选择的截止百分比和我们将要计算的玩家的名字。
Points_calculation =VAR percentage = MAX(Threshold[Percentage]) -- can also be fixed
VAR current_player = MAX(‘Season total’[Name])
注意:如果您不想要前面提到的动态百分比,您可以将百分比变量设置为 0 到 1 之间的固定值。
现在我们来计算一下球队的总得分。
VAR total_points = CALCULATE(
SUM(‘Season total’[PTS]),
ALL(‘Season total’)
)
根据上面的信息,我们可以计算出一个临界值。假设这个团队总共得了 2000 分,你将百分比设置为 10%,截止数将是 200。任何低于 200 分的玩家都应该被归类到分区“*其他玩家*”中。
VAR cutoff_number = total_points * percentage
使用这个截止点,我们现在可以计算阈值之上和之下的点的总和。
VAR sum_above_cutoff = SUMX(
FILTER(
ALL(‘Season total’),
‘Season total’[PTS] > cutoff_number),
(‘Season total’[PTS])
)VAR remainder = total_points-sum_above_cutoff
在代码的最后一部分,对于每个玩家,如果他通过了阈值,我们将返回他的点数,如果他没有通过阈值,我们将什么也不返回( *BLANK()* )。对于类别“*其他玩家*”我们将返回那些没有达到截止的玩家的总和(VAR 余数)。
VAR filter_points = IF(
MAX(‘Season total’[PTS]) < cutoff_number,
BLANK(),
MAX(‘Season total’[PTS])
)VAR result = IF(
current_player = “Other players”,
remainder,
filter_points)RETURN result
这就是你需要的所有代码。现在剩下的就是绘制结果了。但是首先,让我用一段代码总结一下整个措施:
Points_calculation =VAR percentage = MAX(Threshold[Percentage])
VAR current_player = MAX(‘Season total’[Name])VAR total_points = CALCULATE(
SUM(‘Season total’[PTS]),
ALL(‘Season total’)
)VAR cutoff_number = total_points * percentageVAR sum_above_cutoff = SUMX(
FILTER(
ALL(‘Season total’),
‘Season total’[PTS] > cutoff_number),
(‘Season total’[PTS])
)VAR remainder = total_points-sum_above_cutoffVAR filter_points = IF(
MAX(‘Season total’[PTS]) < cutoff_number,
BLANK(),
MAX(‘Season total’[PTS])
)VAR result = IF(
current_player = “Other players”,
remainder,
filter_points)RETURN result
## 剧情
绘制结果非常简单,您所要做的就是绘制一个饼图(或您选择的任何其他可视化工具),并像这样设置字段:
-Legend:' Season total '[Name]
-Values:Points _ calculation
结果应该是这样的:

决赛成绩

来源:[https://giphy.com/](https://giphy.com/)
# 结论
正如您所看到的,在您的可视化中创建一个动态的“ *other* ”分区是相当简单的。然而,我在这里写的手册实际上是我之前创建的包含类别选择、指示器和行聚合的更复杂版本的改编版本。
我非常有信心,微软将很快创造出一个解决方案,不需要一个 hacky 解决方案,以及他们目前可能有的其他缺点。但是只要我们发现了没有被解决的需求,除了保持创造力和自己写更多的代码之外,我们别无选择。
请随意查看我创建的一些其他工具或教程,以改进您的 Power BI 仪表盘或其他数据应用程序。
*关于我:我叫布鲁诺,是总部位于荷兰的人工智能技术纵向扩展公司* [*Dashmote*](http://www.dashmote.com/) *的数据科学家。我们的目标是借助基于人工智能的解决方案,弥合图像和数据之间的鸿沟。
查看我在* [上的其他作品 https://www.zhongtron.me](https://www.zhongtron.me/) 。
# Power BI:计算度量与计算列
> 原文:<https://towardsdatascience.com/power-bi-calculated-measures-vs-calculated-columns-9be012e9bff1?source=collection_archive---------7----------------------->

鲁珀特·布里顿在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
## 选择正确的
微软的 Power BI 在过去 3 年中有了很大的改进。起初,它在数据可视化领域是一个弱小的竞争对手,但每月的更新使它逐渐成为 Tableau、TIBCO 的 Spotfire 和 Qlik 的有力竞争者。然而,即使有了重大改进,一些令人困惑的特性仍然存在..我收到的关于 Power BI 的最常见问题之一涉及计算度量和计算列。
我们都在数据模型和可视化中利用计算。所以,这两个特征是前面和中间。正确理解后,它们将丰富您的数据模型以及您通过报告和仪表板分享的见解。
这两个功能听起来很相似,如果不是相同的话,并且都可以从 Power BI 中功能区的相同位置访问。它们经常被互换使用,随后的混乱也随之而来,因为它们不能互换。他们之间的差异是微妙的,但意义重大。
# 计算列
计算列是对每一行进行评估的表的扩展。计算列位于 Power BI 的 xVelocity 内存存储中,就像从数据源导入的所有其他数据一样。除了一个例外,计算列实际上与非计算列相同。它们的值是使用 DAX 公式和其他列中的值计算的。
由于计算列与表处于同一级别,因此只有在第一次定义它们时以及在数据集刷新期间才会对它们进行计算。计算列的一个示例是通过从产品价格中减去产品成本得出产品的单位利润。
> 单位利润=产品[价格] —产品[成本]
将对 Products 表中的每一行执行此计算。计算出的值将存储在新的单位利润字段中。
**如何:**
1. 在字段窗格中选择产品表。

2.从建模选项卡的计算部分中,选择新列。

3.在公式栏中,输入上面的公式。

也可以通过右键单击字段窗格中的表名并从上下文菜单中选择新列来创建计算列。您还可以从 Power BI 查询编辑器中创建计算列。
# 计算度量
计算度量值与任何其他表列的处理方式不同。与计算列不同,度量是随着上下文的每次变化而动态计算的。如果将日期筛选器从 2019 年更改为 2020 年,将会重新计算所有度量值。虽然这对于实时查看基于上下文的计算很好,但它对计算机的处理器要求很高。
度量值也可以用作聚合。每个计算度量值都必须包含一个聚合函数,如 AVG 或求和。如果没有聚合函数,度量的公式将显示错误。
如何:
1. 在字段窗格中选择产品表。

2.从建模选项卡的计算部分中,选择新度量。

3.在公式栏中,输入上面的公式。

# 何时使用计算列和度量
选择一个而不是另一个并没有硬性规定。在某些情况下,您可以使用计算列或度量值。然而,有些情况下只有一个选项有效。请记住,如果您可以使用其中任何一种,当您的用户与您的报表交互时,计算列将消耗较少的资源。每次用户更改筛选器时,度量都会重新计算,这会导致您的报表响应缓慢。
使用计算度量值时的另一个注意事项是计算列无法在公式中引用它们。由于度量被认为是动态的,并且在 xVelocity 表之外,因此计算列不应在其定义中使用它们。这经常会打乱新来者的努力。他们首先为高度上下文驱动的报告创建一个度量。随着对新报表功能需求的增加,需要更多的计算列。随着您意识到您的度量在一个独立的世界中,并且在计算列公式栏中毫无用处,挫败感袭来。
一种仅通过计算度量解决的场景是,需要在上下文变化时随时改变计算。如果我希望销售人员在所选地区的销售百分比发生变化,需要根据每个地区的总销售额重新计算。每当用户选择切片器中的另一个区域时,就会发生这种情况。
相反,有时您只能使用计算列。度量值不能用作切片器中的筛选器,也不能用作页和报表级别的筛选器。在这些情况下,如果使用计算作为筛选器的来源,则必须使用计算列。
我希望对 Power BI 中计算列和计算度量之间的差异的概述是有帮助的。即使有这种解释,适应它们并理解何时在适当的空间使用它们也需要时间。希望对你来说,这会发生得快一点。但是不要放弃。最后,你会对它们的能力和实用性感到满意。
***罗德蓖麻*** *帮助公司获得正确的分析!他与国际组织和小型企业合作,以改善他们的数据分析工作、数据科学、技术战略和技术领导力。除了咨询,Rod 还喜欢公开演讲、教学和写作。你可以在*[*rodcastor.com*](https://rodcastor.com/)*和*[*applied ai . us*](https://appliedai.us/)*了解更多关于罗德和他的作品。*
# 功率 BI 柱 vs 测量。我应该在什么时候使用哪一个?
> 原文:<https://towardsdatascience.com/power-bi-column-vs-measure-which-one-should-i-use-and-when-ed91fffcea1b?source=collection_archive---------26----------------------->
## …在我刚开始的时候,本可以使用这些说明。

罗伯特·阿纳奇在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
为什么有计算列,为什么有度量?我应该使用哪一个?哪个更快?我什么时候使用它?
这些都是好问题。我刚开始的时候也问过自己同样的问题。随着我更多地使用 Power BI,我意识到它们非常不同,工作方式也不同。越早知道这些区别越好。
怎么会?首先,它们在 Power BI 中的加载方式不同,对视觉效果的影响也不同,而且一个处理行上下文,另一个处理过滤上下文。
但是在我们深入研究之前,让我们先来看看它们到底是什么,我们还将浏览一个例子:)
# 计算列
计算列是在数据视图中逐行计算**的列。它们**占用计算空间并增加文件大小**。对于被认为属于**“缓慢变化”**类别的数据,应完成计算栏。**
工资等级就是一个很好的例子。一个人的工资每月不会有太大的变化,一个工资等级可以意味着与整个公司相比,他们是处于低端、中间还是更高的工资范围。
不过,根据个人的工资等级来看他们的表现可能很重要。此类别不能在度量中,因为您不能基于度量筛选报表。这将是一个用作计算列的好例子。然后,您可以根据这些括号过滤您 PBI 报告。
另一个很好的例子是工作地点——根据不同的地点,了解每个地点的表现非常重要。您可能需要将多个城市合并到区域中并筛选报表,因此您需要一个计算列来完成这项工作。
这里有两个主要问题要问自己是否应该使用计算列。
1. **我需要该列的结果来过滤我的报告吗?**
**2。这是一个“变化缓慢”的字段吗?例如,年龄、工资级别或工作地点?**
如果您回答“是”,您可能应该构建一个计算列。
# 措施
基于用户与报告的交互在现场计算测量值**。测量结果不会在刷新期间加载,而是在现场计算。**使用 CPU,不增加文件大小**。**
这方面的一个很好的例子是销售的产品,销售的产品应该是一个衡量标准,因为它将被工资等级和公司位置“切割”。
另一个例子是员工的社交媒体活动分数(一个基于他们登录公司网络论坛的次数和回答顾客问题的数量的分数。等等)。您可能希望根据年龄类别和地区了解员工在社交媒体上的活跃程度,然后与他们的表现进行比较。你可以为此建立一个衡量标准。
如果您想构建一个度量标准,需要问自己两个主要问题。
1. **我需要用户选择的数据结果快速变化吗?**
**2。这些数据会以某种方式被聚合、分割吗?**
如果你的答案是肯定的,你应该建立一个衡量标准。
让我们看一个简单的例子。

这里我有一个简单的模型,这个数据库按日期跟踪销售额,有多个销售人员 id 以多对一的关系连接到 staff 维度表。商店和日期表也是如此。
在这里,我想筛选按员工工资销售的产品。我应该用一个衡量标准吗?
嗯,那会相当困难。薪资栏有多种薪资。从 UX 的角度来看,最终用户很难仅仅为了过滤报告而选择多个薪金。(例如,他们必须选择 55001、55020、56000,以获得 55000–56000 的范围)。最好创建一个薪资等级列来过滤报告。我需要建立一个计算列。
我还想按城市进行筛选,看看员工的表现如何。由于有多个城市,最好将它们合并到区域中。我还需要为此建立一个计算列。
您可以通过 Power BI 中的宁滨函数构建这些列,或者选择在 Power Query 中构建一个条件列。最佳实践实际上是在 Power Query 中这样做,但是有时您可能想要快速完成,您也可以在 Power BI 中这样做作为测试。如果这是最终要保留的东西,你应该在 Power Query 上做。
那么这个模型中的度量是什么呢?
你想报道什么?想想这个问题——你打算汇总什么?在这里,我需要根据地区、工资等级等来比较销售的产品。我需要为此建立一个衡量标准。
如果你需要更多关于开始使用 power query 的信息,[这里有一篇关于它的文章](/joins-with-power-bi-bde7de3e2181?sk=91ebb5c4e4dca48f4e1d216fe86ffdc4)。

作者图片
以绿色突出显示的是计算列,以紫色突出显示的是用于构建度量的列。
在这个模型中,我现在可以根据工资级别、地区进行筛选,并比较产品销售和活动得分的衡量标准。
如果你仍然停滞不前,什么都没有意义,坐下来问自己这个问题。
您想报告什么内容,使用什么过滤器?
如果你能回答这个基本问题,你就会对什么应该是度量值,什么是计算列有一个大致的概念。
见下文—

作者图片
也许我过于一般化了,但是我已经用这个问题来帮助我思考各种各样的 Power BI 报告,我希望它也能帮助你。
请记住,关键是要有一个好的模型,一个有意义的模型,然后才能决定度量值和计算列。
拥有一个好的模型可以让你在未来免除很多头疼的事情!我一直在那里挑灯夜战,但模型仍然不工作。不要走那条路。
[这里有一篇文章可以帮助你建模](/power-bi-modelling-bcd4431f49f9?sk=1f054aeeeb14c96238fd6e4f8e192ee2)。
希望这有助于保持安全!:)
# Power BI 连接到 Azure 数据块
> 原文:<https://towardsdatascience.com/power-bi-connects-to-azure-databricks-44bea6731be7?source=collection_archive---------11----------------------->

在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上由 [Carlos Muza](https://unsplash.com/@kmuza?utm_source=medium&utm_medium=referral) 拍摄的照片
## 派生 Spark URL 并创建一个用户令牌,PowerBI 使用该令牌在 Azure Databricks 中进行身份验证
作为一种数据分析工具,微软的 PowerBI 最近变得越来越受欢迎。此外,对于一个公司来说,拥有一整桶包含 Azure 的微软产品是普遍存在的。
Azure Databricks 是 Azure 平台中最受欢迎的服务之一。它利用 Apache Spark 在分布式环境中处理数据,这可以显著提高性能。Azure Databricks 还支持 Delta Lake,这是一个分布式环境中的开源存储层。它的使用与大多数传统数据库管理系统非常相似,因为它支持 ACID 事务。
[https://delta.io](https://delta.io)
本文将展示如何使用内置连接器从 PowerBI 连接到 Azure Databricks 表(Delta Lake)。棘手的部分是“Spark URL ”,这将在后面强调。
# 样本数据表准备

照片由[米卡·鲍梅斯特](https://unsplash.com/@mbaumi?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
由于本教程的目的只是介绍将 PowerBI 连接到 Azure Databricks 的步骤,因此将创建一个示例数据表用于测试目的。首先,让我们创建一个包含几列的表。一个日期列可以用作“过滤器”,另一个列用整数作为每个日期的值。
我们先在 Azure Databricks 中创建一个笔记本,我愿意称之为“PowerBI_Test”。

为测试目的创建一个数据库。
%sql
CREATE DATABASE TEST_DB;
然后,导入必要的库,创建一个 Python 函数来生成包含上述列的 Pandas 数据帧。
from datetime import datetime, timedelta
import numpy as np
import pandas as pd# Create date df in pandas
def create_date_table(start='2020-01-01', end='2020-03-01'):
df = pd.DataFrame({"date": pd.date_range(start, end)})
df['day'] = df['date'].dt.weekday_name
df['date'] = df['date'].dt.date
df['value'] = np.random.randint(100, size=df.shape[0])
return df
现在,我们可以从熊猫数据帧中生成 Spark 数据帧,并将其保存到 Delta Lake 中。
date_pdf = create_date_table()
sample_table = spark.createDataFrame(date_pdf)
sample_table.write.format('delta').mode("overwrite").saveAsTable('TEST_DB.sample_table')
以下是表格的预览:

# Azure 数据块 URL 和用户令牌

苏珊·霍尔特·辛普森在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片
要从 PowerBI 连接到 Azure Databricks,我们需要两个重要的“密钥”,即 URL 和用户令牌。
## 如何获取 spark 网址?

1. 从左侧导航中,转到“Cluster”选项卡。
2. 从群集列表中,单击选择要使用的群集。这将把页面导航到集群编辑页面。
3. 在群集编辑页面中,单击“高级选项”以展开该部分。
4. 选择“JDBC/ODBC”选项卡。这里会有很多信息,但我们只需要关注“JDBC 网址”。
5.将整个 URL 复制到某个文本编辑器中。这个 URL **不能**直接使用,我们需要从中“派生”出正确的 URL。

以下是我从“JDBC 网址”文本字段中复制的网址:
jdbc:spark://australiasoutheast.azuredatabricks.net:443/default;transportMode=http;ssl=1;httpPath=sql/protocolv1/o//--**;AuthMech=3;UID=token;PWD=
方括号中显示了我们从该 URL 中需要的组件:
jdbc:spark[😕/australiasoutheast.azuredatabricks.net:443/]default;transportMode=http;ssl=1;httpPath=[sql/protocolv1/o//--**];AuthMech=3;UID=token;PWD=
我们还需要在前面加一个协议,就是`HTTPS`。因此,最终的 URL 将如下所示:
https://australiasoutheast.azuredatabricks.net:443/sql/protocolv1/o//--**
## 如何获取用户令牌?
我们需要创建一个用户令牌来进行身份验证。
首先,在右上角找到用户图标。单击图标,然后在下拉菜单中选择“用户设置”。

在“用户设置”页面中,单击“生成新令牌”按钮。在弹出窗口中,输入注释字段,该字段将用于提醒您该令牌的用途。
“生命周期”将决定多少天后令牌将被自动吊销。请注意,如果未指定令牌寿命,令牌将无限期存在。

点击“生成”按钮后,将生成一个令牌。
*** *重要提示** **一旦点击“完成”按钮,您将无法取回令牌。因此,请确保您现在复制令牌并将其保存到一个安全的地方。

# PowerBI 连接到 Azure 数据块

照片由[艾萨克·史密斯](https://unsplash.com/@isaacmsmith?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
现在,我们可以从 PowerBI 中的 Databricks 获取数据。
在 PowerBI 中,点击“获取数据”>搜索“Spark”>在列表中选择“Spark”>点击“连接”按钮。

在弹出窗口中,将 URL `[https://australiasoutheast.azuredatabricks.net:443/sql/protocolv1/o/***************/****-******-*******](https://australiasoutheast.azuredatabricks.net:443/sql/protocolv1/o/***************/****-******-*******)`填入“服务器”文本字段。
然后,选择“HTTP”作为协议。对于“数据连接模式”,我们选择“DirectQuery”。这是因为当我们在实践中需要 Azure Databricks 时,我们很可能会处理大型数据集,所以在这种情况下,将所有数据导入 PowerBI 并不是一个好主意。

点击“OK”按钮后,我们将能够看到当前 Azure Databricks 集群中的所有表。如果集群中有很多表,我们可以在导航器中搜索这些表。然后,单击“Load”按钮将该表添加为数据源。当然,在实践中可以一次导入多个表。

现在,我们可以从三角洲湖创建可视化。

# 摘要

照片由 [Aaron Burden](https://unsplash.com/@aaronburden?utm_source=medium&utm_medium=referral) 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)
本文展示了如何从 Microsoft PowerBI 连接到 Azure Databricks。最关键的步骤是从 Azure Databricks 获取 **Spark URL** 和**用户令牌**。
希望这篇文章可以帮助数据科学家/工程师直接从 Azure Databricks 创建可视化。
[](https://medium.com/@qiuyujx/membership) [## 通过我的推荐链接加入 Medium 克里斯托弗·陶
### 作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@qiuyujx/membership)
如果你觉得我的文章有帮助,请考虑加入 Medium 会员来支持我和成千上万的其他作者!(点击上面的链接)
# 为凡人嵌入的能量 BI
> 原文:<https://towardsdatascience.com/power-bi-embedded-for-mere-mortals-5478f2f1e58?source=collection_archive---------7----------------------->

[https://pix abay . com/photos/table-spanner-embedded-漆面-2584957/](https://pixabay.com/photos/table-spanner-embedded-lacquered-2584957/)
## 好人
Power BI 已经成为市场上最强大、最常用的数据可视化和分析工具之一。它有许多令人惊讶的功能,但我最喜欢的一个很酷的功能是嵌入功能。简而言之,Power BI Embedded 允许将任何发布的报告作为独立 web 应用程序的一部分呈现。我现在对 SharePoint 部件有些怀念😂。这意味着用户没有被限制或要求拥有 Power BI 许可证。这个用例对于开发由 Power BI 支持的 web 应用的 ISV 非常有用。
## 坏的和丑的
如果我没记错的话,Power BI Embedded 已于 2018 年左右推出。它最初被绑定到一个叫做工作空间集合的东西上,现在这个东西已经[退役了](https://azure.microsoft.com/en-us/updates/pbiwsc-retirement/)。自最初发布以来,API 发生了一些变化,而且像 Power BI Premium 这样的新服务已经发布,以服务于更多的企业场景。我已经使用旧的 workspace 集合完成了 Power BI Embedded,并希望尝试最新的 API,看看它是如何工作的。作为一个务实的人,我的动机是在 web 应用程序中嵌入优化问题解决方案的可视化。优化是使用 Google 或-Tools 完成的,我发现了很多很酷的视觉效果来展示这个解决方案,这比渲染 HTML 表格之类的东西更有吸引力。
但正如我们所知,生活并不总是彩虹和飞翔的独角兽。微软的文档总体来说相当不错,但是对于 Power BI Embedded 来说,有些地方有点模糊。因此,我想准备一个简单的说明手册,介绍如何使用 Power BI Embedded,其中一个常见案例有时被称为“[应用拥有数据](https://docs.microsoft.com/en-us/power-bi/developer/embedded/embed-sample-for-customers)”。这个概念很简单,应用程序拥有对报表和底层数据的完全访问权限,并且报表呈现在其中一个应用程序页面中。用户不需要使用 Power BI 进行身份验证。他们可以无缝地查看报告并与之交互。
所以如果你喜欢 Power BI,那就来看看怎么嵌入吧!
因为不是每个人都有有效的 Power BI 许可证,所以最好从免费的 Office 365 E3 试用订阅开始,并在该租户内注册一个月的 Power BI Pro 试用许可证。Office 365 和 Power BI Pro 都不需要信用卡信息。Office 365 租户附带了一个捆绑的 Azure Active Directory,这是这个过程中需要的。
本教程将使用以下工具:
* 超级商务智能桌面
* [。网芯 3.1 SDK](https://dotnet.microsoft.com/download)
* Visual Studio 代码
* NodeJs
## 1.准备要嵌入的报告
我们可以选择任何 Power BI 报告在这里使用,但我想使用一个带有**直接查询**数据源的报告。原因是直接查询对于嵌入场景可能非常有用,因为我们不需要担心数据刷新等问题。所以我首先创建了一个 Azure SQL 数据库,并用 **AdeventureWorksLT** 数据库初始化。我有一个 Azure 订阅,而不是之前提到的 Office 365 试用版,所以不要搞混了。使用**导入**模式的报告也可以很好地工作。因此,如果您无法访问 Azure SQL 数据库,请在 Power BI desktop 中创建任何报告,并跳过几个段落,直到创建工作区并发布报告的步骤。

一旦创建了数据库,我们必须配置防火墙规则(底层 SQL server 的)以允许来自其他 Azure 服务和我的本地机器的访问。

之后,我们可以创建一个新的 Power BI 报告(当然使用 Power BI desktop ),以可视化与我们的示例数据相关的任何内容,例如每个客户的销售额。正如我提到的,该报告设计有一个直接查询数据源,允许实时反映数据库状态。

要使用的报告没有什么特别的,对我来说,它类似于一个简单的`SELECT SUM(Amount) FROM Sales GROUP BY Customer`语句。

该报告必须发布,以便 Power BI Embedded 以后可以访问。但是要发布,我们得先有一个工作空间。使用 Office 365 租户的管理员帐户登录 Power BI,并创建如下所示的工作区来存放报告。

然后将报告从 Power BI desktop 发布到上述工作区。对于具有直接查询模式的报告,将要求您重新输入报告中数据集的凭据,但除此之外,报告在浏览器中应该工作正常。

## 2.创建嵌入服务主体
在我们的例子中,为了使嵌入尽可能无缝,我们将使用服务主体。可以把它想象成一个服务帐户,它被授予了对某个资源的足够的权限,这样应用程序就可以使用分配给这个服务主体的凭证对这个资源调用 API。
要创建服务主体,请打开与我们的 Office 365 租户链接的 Azure AD。只需打开[portal.azure.com](http://portal.azure.com)并使用相同的管理员凭证登录。从侧边菜单或搜索框中,找到 Azure Active Directory 并单击名为**应用注册**的链接。在此页面中点击**新注册**。只需提供一个名称,然后单击创建。

创建之后,我们需要记下应用程序和租户 id,因为我们以后会用到它们。有些两个标识符有时被称为客户端 Id 和租户 Id。

我提到过服务主体拥有某种凭证。在当前应用程序的同一个页面中,单击**证书&机密**,创建一个客户端机密并复制值,因为在此之后将无法访问该值。不过,对客户端机密的描述是任意的。

在 Azure AD 中要做的最后一步是创建一个组,并将新创建的服务主体添加为组成员。我们稍后会看到为什么需要这样做,但现在,在 Azure AD 主页中单击 **Groups** 链接,创建一个名为 **Power BI Embedding Users** 的新组(属于安全类型),并在创建页面中将之前创建的服务主体作为该组的成员。

## 3.配置 Power BI 以使用服务原则
现在我们已经完成了 Azure AD 并创建了一个服务主体,我们需要切换到我们的 Power BI 网站([https://app.powerbi.com](https://app.powerbi.com))来授予对之前创建的工作区上的服务主体的访问权限。但是要允许 Power BI 使用服务原则,必须首先对其进行配置。从 Power BI cog 按钮中,选择**管理门户**。

单击**租户设置**菜单项,然后确保启用开关**在应用程序中嵌入内容**并选择**指定安全组**并添加我们之前创建的安全组。

对**做同样的事情,允许服务主体使用 Power BI API**。

接下来,在 Power BI 中打开工作区页面,选择**工作区访问**。

然后搜索服务主体并将其添加为一个**管理员。**

## 4.将报表嵌入到 web 应用程序中
唷,为嵌入做准备要做很多家务,但是我们就快到了。剩余任务的一般模式如下:
* 使用后端 web API 开发 web 应用程序
* 后端 web API 负责使用存储在后端的服务原则信息/凭证来生成嵌入令牌
* 前端将使用嵌入令牌来呈现报告
听起来很容易,我们开始吧。
首先,用 dotnet 核心后端 web API 创建(实际上是搭建)一个 react web 应用程序。
dotnet new react -o EmbedWeb
cd .\EmbedWeb
cd .\ClientApp
npm install
npm install caniuse-lite@latest --save
`caniuse-lite`行是必需的,因为在编写时当前模板有一个过时的依赖关系,它阻止了应用程序的运行,因此需要升级这个 npm 依赖关系。
现在使用 Visual Studio 代码打开`EmbedWeb`文件夹,使用`Ctrl + ``打开一个终端窗口。在终端窗口中,执行`dotnet watch run`。

让我们点击 HTTPS 的网址,看看这个应用程序是否还活着。

很好,现在一切都好。在第二个终端窗口中,添加几个后端 nuget 包,负责与 Azure AD & Power BI REST API 交互。这将在第一个终端窗口中触发另一个构建,几秒钟后,如果您想确保没有任何损坏,网站应该会有响应。
dotnet add package Microsoft.Identity.Client
dotnet add package Microsoft.PowerBI.Api
在`EmbedWeb`文件夹的根目录下,添加一个名为`Embedder.cs`的新文件,并将以下内容复制到其中。
您需要更新客户端 Id、客户端密码和租户 Id 的值。这些值可以在 Azure AD 中创建的服务主体的主页中找到。用您自己的值保存文件,并确保它在`dotnet watch`的终端窗口中构建良好。
以下是该文件的简要说明:
1. `GetAppOnlyAccessToken`负责生成一个访问令牌来调用 Power BI REST API。此方法使用新的 Microsoft 身份验证库。NET(MSAL.NET)在 nuget 包`Microsoft.Identity.Client`中发现。
2. `GetPowerBiClient`使用这个访问令牌来实例化一个类,该类抽象了针对 Power BI API 的 REST 调用,这样我们就可以简单地调用方法并获得类型化的响应等等。这就是 nuget 包`Micorsoft.PowerBI.Api`中发现的 Power BI SDK 的全部要点。
3. `GetEmbedInfo`方法使用 Power BI SDK 客户端对象获取报表元数据并生成嵌入令牌。生成 embed token 的调用配置为顺便获取一个允许编辑的 token。关于 RBAC 和安全有很多要说的,但是现在,让我们假设如果我们想的话,我们可以有只查看模式或编辑模式的令牌。
这个`Embedder`类是一个助手类,可以从 web API 控制器调用,因此创建嵌入令牌是在后端完成的。此外,将服务主体细节直接硬编码到其中也很简单。
***旁注:*** 本文末尾的参考资料部分有几个 YouTube 视频,由 [Ted Pattison](https://twitter.com/tedpattison?lang=en) 制作,解释了许多其他有用的关于 Power BI 嵌入认证模式的细节。
我们已经完成了 helper 类,所以是时候拥有一个 web API 控制器了。添加一个名为`EmbeddingController.cs`的新文件,但这一次它必须进入 controllers 文件夹,并在其中粘贴以下代码片段。
您必须提供您的工作区和报告的 id。如果你想知道如何得到这些东西,有一个简单的窍门。只需打开 Power BI 上发布的报告,查看浏览器地址栏中的网址即可。
https://app.powerbi.com/groups/<GUID1>/reports/<GUID2>/ReportSection
GUID1 是工作区 ID,GUID2 是报告 Id。现在保存文件并确保构建成功。为了确保我们的后端部分正常工作,打开一个新的 PowerShell 窗口并*curl*web API 端点,它应该是[https://localhost:5001/embedding](https://localhost:5001/embedding)。

后端部分已经完成,所以下一步也是最终目标是在我们的 web 应用程序中有一个 HTML 页面来呈现与 Power BI 服务相同的报告。
同样,Power BI SDK nuget 包也有一个面向 JavaScript 世界的 npm 包。这个 npm 包可以用来做很多事情,但是我们将只讨论嵌入部分。
在终端窗口而不是构建/监视窗口中,添加 Power BI npm 包。
cd .\ClientApp
npm install --save powerbi-client
现在用以下内容替换`ClientApp\src\Components\Home.js` react 文件的内容。
上面的代码片段只做了两件事:
* 调用 web API 端点来获取嵌入令牌
* 使用 Power BI JavaScript 库,通过获得的嵌入令牌来嵌入报告。
此外,将下面的 CSS 片段添加到`custom.css`文件中,为呈现的报告添加一些真实属性。
.full-width
{
width: 100%;
height: 800px;
}
现在转到浏览器并刷新页面。

很好,嵌入是可行的,因为我们在前端和后端都支持编辑,我们甚至可以编辑报告并保存更改。
最后要测试的是直接查询模式。这不是与嵌入相关的核心问题,但也是可以尝试的。因此,让我们随机化每个客户订单的总到期金额(这是一个包含 sub total 列的计算列)。
UPDATE [SalesLT].[SalesOrderHeader]SET SubTotal = ABS(CHECKSUM(NewId())) % 120000
现在刷新页面,您将得到一个完全不同的模式来反映数据库的当前状态。直接查询非常酷,尤其是源数据几乎是预先聚合的或者很容易提取的。

## 包裹
我希望您现在了解 Power BI 嵌入工作流中涉及的核心活动部件。还有其他需要考虑的事项,下面的参考资料部分有一些提示。需要强调的另一点是,生产环境需要 Power BI 专用容量。
引用一点[文档](https://docs.microsoft.com/en-us/power-bi/developer/embedded/embed-sample-for-customers#development-testing):
> 将嵌入令牌与 Pro 许可证一起使用旨在进行开发测试,因此 Power BI 主帐户或服务主体可以生成的嵌入令牌数量是有限的。专用容量需要嵌入生产环境中。对于使用专用容量可以生成多少嵌入令牌,没有限制。
简而言之,拥有专用容量的最简单方法是创建 Azure Power BI 嵌入式资源。它按小时计费,可以暂停/重启以节省成本。

然后将它与包含要嵌入的报告的工作区链接起来。

快乐嵌入😀
## 资源
[](https://docs.microsoft.com/en-us/power-bi/developer/embedded/embed-sample-for-customers) [## 为您的客户在您的应用中嵌入内容- Power BI
### 了解如何使用 Power BI APIs for embedded 将报告、仪表板或图块集成或嵌入到应用程序中…
docs.microsoft.com](https://docs.microsoft.com/en-us/power-bi/developer/embedded/embed-sample-for-customers) [](https://docs.microsoft.com/en-us/power-bi/developer/embedded/embed-service-principal) [## 具有 Power BI 的服务主体- Power BI
### 服务主体是一种身份验证方法,可用于让 Azure AD 应用程序访问 Power BI 服务…
docs.microsoft.com](https://docs.microsoft.com/en-us/power-bi/developer/embedded/embed-service-principal)
# Power BI 考试— DA100
> 原文:<https://towardsdatascience.com/power-bi-exam-da100-91f98eb57297?source=collection_archive---------24----------------------->
## 一些传球的技巧

[天一马](https://unsplash.com/@tma?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍照
我今天早上做了 DA100 测试,通过了。我有大约 2 年的 Power BI 经验,但我仍然需要学习很多东西。
我写这篇文章是为了帮助你准备考试。
由于保密协议,我不打算在这里列出任何问题,但我可以说考试包括了[考试大纲上列出的所有内容。我甚至不认为有什么遗漏。微软的大纲非常准确,我没有学习大纲上没有的东西。](https://docs.microsoft.com/en-us/learn/certifications/exams/da-100)
有一些课程可以帮助你准备考试,但是说实话,微软的模块和学习路线已经非常简洁了。我做的所有测试都在大纲上。即使不是答案之一,也是出现的选项之一。
# 为考试做准备
运用概念——你需要运用你所学的知识。如果你在学习记忆不同连接的定义,或者课文内容。替换函数对你没有任何帮助。你当然需要知道它是什么,但更重要的是如何应用它。
举个例子,
你可能知道如何在可视范围内到达 TOPN,但在计算范围内呢?你可能知道什么是分解树,你如何在商业环境中使用它?
交叉过滤,什么时候用?
当然还有连接的类型,多对一,一对多,以及连接的类型。这里可以看[。](/joins-with-power-bi-bde7de3e2181?source=friends_link&sk=91ebb5c4e4dca48f4e1d216fe86ffdc4)
你知道使用 M 函数的基本知识吗?你也可以在这里阅读。在[考试大纲中的“利用 Power Query 中的高级编辑器编辑 M 代码”一节下。](https://docs.microsoft.com/en-us/learn/certifications/exams/da-100)
**问题风格** —转到[学习见解](https://www.learndatainsights.com/)并在那里做一些测验。我可以说那里的问题真的帮助了我。
当你不明白的时候,我知道这种感觉。我一遍又一遍地查找角色级安全性和直接与导入查询。直到我在 C [urbal](https://www.youtube.com/channel/UCJ7UhloHSA4wAqPzyi6TOkw) 上看到几个视频,它们才帮助了我。有时候,看个视频更好。另外,[微软指导文章](https://docs.microsoft.com/en-us/power-bi/guidance/overview)也有帮助。
**做** [**模块**](https://docs.microsoft.com/en-us/learn/modules/get-data/)**——**微软在他们的网站上提供模块,其中包括如何通过考试的学习途径。我做了模块。嗯——我已经尽我所能了。如果我已经知道如何做某些事情,我会跳过它。然而,如果有新的东西,我会花时间去学习和做。我不经常使用书签,我花时间在实验室里制作它,也在日常工作中使用它。
**使用** [**学习路径**](https://docs.microsoft.com/en-us/learn/certifications/exams/da-100)——它写得很好,很简洁,对考试有帮助。考试中学习路径的“知识检查”部分有什么问题吗?遗憾的是没有,看起来大多数问题都是基于应用你所学的概念。
测试你的系统— 学习的时候,别忘了做这件事!测试您系统的链接应该来自您注册的考试公司,并且应该在您注册考试后出现在您的电子邮件中。尽早进行系统测试,这样你就不会因为在。
# 考试前
提前喝你的咖啡——如果你正在远程写作,考试期间你不能喝咖啡或任何东西。为什么?我不知道。水?我不知道,但可能也不会。
整理你的工作空间——你需要整理一下。你不能有任何笔记本、铅笔或钢笔。你不能写下任何东西,你必须在头脑中建模。除了你的笔记本电脑和两张身份证,我什么都没有。您将被要求拍摄您的工作站和身份证的照片。如果考官(他们称之为监考人)同意,他们将开始考试。不要让书、文件和孩子跑来跑去,让他们的生活变得艰难。
摘下你的耳机——我想戴上我的降噪耳机去考试。不允许。

作者图片
# 考试期间
**调查** —你必须先完成一项调查。它会询问您对 Power BI 的总体体验。我只是实话实说,我有 2 年左右的经验,我和一个比我级别高的团队一起工作。没有必要假装比你实际上有更多的经验。不知道这个调查对考试有没有影响。
**仔细阅读—** 不要急着写下任何答案。仔细想想。有时候大声朗读会有帮助。加入多对一关系的 A 和 B 与加入一对多关系的 A 和 B 之间有一个巨大的**差异。**仔细阅读。**有时候考试就是要求**选择中的两个**答案。**仔细阅读。****
**技术问题**——我至少遇到过两次..你能相信吗?它发生了,我不知何故断开,只是重新加载,并让考官知道。你不会失去你所有的工作,所以不要担心。
**你被录下来了** —你被摄像头拍下来了,会被录下来了,所以不要做什么尴尬的事。
制定策略——也许这是常识,但在最紧要的时候你可能会忘记。如果不知道答案,不如慢慢看,缩小选择范围。当我慢慢读的时候至少有 2 个问题,当它对我有意义的时候再读一遍。有时候,这只是一个微小的措辞,会帮助你排除一个选择。
例如,您可能有 4 个选择,其中两个是关于表函数,另外两个是列表函数。如果你能首先找出哪个函数符合这个问题,你就已经排除了 50%的选择。
**复习** —如果有几个问题你有一定把握,但需要再思考一下,可以设置为“复习”,之后再复习。你不可能回答所有的问题,但是大多数问题。
# 考试结束后
结果立竿见影——一旦你提交了考试,你就会看到你是否通过了考试。说实话,太突然了,我都不知道自己已经过了!
事实上,我不得不发信息给考官,看看我是否还需要做其他事情,他们回复说“再见”。我想就这样吧。
**证书** —你会在你的学习仪表板上看到你的证书,这个考试两年内有效。

作者图片
祝你好运!
# 电源 BI 功能—(列表。包含,列表。包含任何,列表。包含所有)
> 原文:<https://towardsdatascience.com/power-bi-functions-list-contains-list-containsany-list-containsall-87ec48bdd68a?source=collection_archive---------6----------------------->
…数据之旅的有用工具。

马蒂亚斯·海尔在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片
本文将向您介绍包含列表的*函数。这是一个很好的功能,可以用在电源查询中。每一个都有细微的差别,但是我希望这篇文章能帮助你开始。*
幂查询中的列表用{}括号写。它们可以是{1,2,3},甚至是{1,“a”,123}。如果你喜欢实验,可以去 Power Query >创建空白查询>高级编辑器>替换源信息为> Source = {1," hello ",123}。
记住这一点很重要——Power query 中的列可以包装在{[Column A]}中以返回一个列表,这样就可以使用列表函数。您也可以参考表[A 列]返回一个列表。
但是两者有所不同——在下面的数据集中使用{ [ID] }创建一个新列会为每个“单元格”返回一个值。使用#"Previous Step"[ID]返回嵌套在"单元格"中的整个列表。

作者图片
在深入研究之前,先看看如何在本文中构建一个 [Power BI 数据模型](/power-bi-modelling-bcd4431f49f9?sk=1f054aeeeb14c96238fd6e4f8e192ee2)。Power BI 中的模型与 Access 和 SQL 数据库略有不同。
如果你想知道如何[应用 Power BI](/functions-in-power-bi-56e9e11e4669?sk=32f65f6e5196dbd96ed43a53584ad2fc) — [中的函数,这里有一篇好文章。](/functions-in-power-bi-56e9e11e4669?sk=32f65f6e5196dbd96ed43a53584ad2fc)
现在回到这个话题,为什么这些列表函数会有帮助呢?当您想要在数据集中的各个列中放置一个列表来检查条件时,这很有帮助。
当然,您可能可以在 Power Query 上使用条件列功能区,但是列出您希望检查的所有特定项目会非常繁琐。
您还可以对支持表进行各种连接,但之后的清理工作也会很繁琐。你可以写 if 语句,但是如果你的列表很大呢?
让我们一起来看看这些函数。
# 列表。包含任何
[**列表。ContainsAny**](https://docs.microsoft.com/en-us/powerquery-m/list-containsany) —下面是函数的分解。
找出列表{1,2,3,4,5}包含 3 还是 4。

作者图片
List.ContainsAny({1, 2, 3, 4, 5}, {3, 4})
返回 TRUE —因为{1,2,3,4,5}的列表中有任何 3 或 4
List.ContainsAny({"A", "B", "C", "D", "E"}, {"F", "G"})
返回 FALSE—“F”或“G”不在{“A”、“B”、“C”、“D”、“E”}列表中
# 列表。包含
[**列表。包含**](https://docs.microsoft.com/en-us/powerquery-m/list-contains)——这里是功能的细分。

作者图片
查找列表{1,2,3,4,5}是否包含 3。这里的函数将是
List.Contains({1, 2, 3, 4, 5}, 3)
返回 TRUE
然而,你可能需要小心你所观察的物品。您要查看的项目没有{}。与最后一个值进行比较的是**期望的是一个值而不是一个列表**,所以下面返回 false。
List.Contains({1, 2, 3, 4, 5}, {3})
返回 FALSE。
# 列表。包含所有
现在不是单个值— [列表。如果 ContainsAll](https://docs.microsoft.com/en-us/powerquery-m/list-containsall) 能够将列表中的所有项目与您想要比较的列表进行匹配,它将返回 True。
List.ContainsAll({1, 2, 3, 4, 5}, {4, 5})
返回 TRUE-4 和 5 都在列表中。
因为这个函数需要一个匹配的列表,并且在 Power Query 中是逐行布局的,所以您需要首先嵌套这个列表,这样才能工作。(下面有更多相关信息)
让我们看一个例子。
我在 power query 中有一个表,我将使用 add columns 特性添加额外的列来使用我们的 contain 函数。

作者图片
让我们添加使用列表的第一列。包含使用“添加列”按钮。

结果会是这一栏。
让我们创建我们的第一列。我想检查 Store_Number 1 是否在列中的任何位置。
这里,该列表示在商店编号列中有一个商店编号 1。

作者图片
我还想检查是否有商店编号 1,并且任何评论都包含“太棒了”这个词。

作者图片
最后一列,我想检查我的所有评审标准— {“很好”、“很好”、“嗯”} —是否都出现在该列中。

作者图片
这张特别的单子。ContainsAll 与其他的有些不同。
如果您像其他人一样使用定制列,那么由于 Power Query 中的行上下文,它将不起作用。
直觉上,如果你试着做—
List.ContainsAll({[Reviews]},{“Great”,”Good”,”Meh”})
实际上将返回 FALSE,即使您在此列出的项目都在列中。
这里的问题是行——如果您只是引用列,Power Query 会获取列的“单元格”,并对照列表{“Great”、“Good”、“Meh”}进行检查,然后返回 FALSE。这个特定的“单元格”不包含列表中的所有项目,所以它返回 FALSE。
当我们使用**列表时。包含任何**,**列表。包含**,它们返回正确的值,因为即使它对每个值进行检查,它仍然会得到我们想要的。这里的区别在于,我们希望在与列表进行比较之前,将整个列嵌套在一个“单元格”中。
这就是我们需要写作的原因。
List.ContainsAll( #PreviousStep[Reviews],{“Great”, ”Good”, “Meh”} )
这里,它将整个列作为一个列表引用——以对照另一个列表进行检查。
结果将返回 TRUE
另外,这两个函数也非常有用。AnyTrue 和**列表。AllTrue** 。
它们和其他的非常相似,你可以添加其他条件,而不仅仅是检查成员资格。

作者图片
这些函数的伟大之处在于,您可以用 and、or 运算符将它们串在一起,并在数据上创建检查,而不必恢复到连接和多个嵌套语句。
**TL:DR** ?这是所有这些问题的总结—
**列表。包含** —记住要排除搜索项目的{}。
**列表。ContainsAll** —记住对搜索列表使用上一步的[列名]。
**列表。包含任何** —最容易使用。我总是不得不用这个特别的。
**列表。任何事实,列表。AllTrue** —您可以向它们添加条件。整个条件语句需要用{}包装

作者图片
在 Power Query 中尝试这些功能会很有趣!注意安全!
# Power BI: M 与 DAX 以及测量值与计算值列
> 原文:<https://towardsdatascience.com/power-bi-m-vs-dax-vs-measures-4c77ae270790?source=collection_archive---------5----------------------->
## 刚开始学 Power BI 时希望知道的基础知识。
当我踏上我的权力 BI 之旅时,我几乎立即被一股外来的和令人困惑的术语打了耳光,这些术语似乎都做着相似但又有些不同的事情。
这里有一种叫做 M 的语言,但也有一种叫做 DAX 的语言?计算列和度量值有什么区别?我应该在什么时候使用超级查询?

[丹尼尔·延森](https://unsplash.com/@dallehj?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍照
在我的旅程中,我很早就陷入了试图理解一些关键概念的困境,这些概念使 Power BI 看起来更加困难和混乱。我几乎放弃了我的商业智能抱负,爬回到我熟悉的伙伴 Excel 身边。最好是你认识的恶魔,对吧?不对!
我是如此,如此,如此高兴,以至于我一直用头撞墙来克服最初的障碍。今天我几乎每天都在用 Power BI,而且是兴高采烈地用,*甚至是兴高采烈地*,很少用 Excel。但是来到这里很难,真的很难。这比想象的要难,因为很长一段时间以来,我对一些关键的 Power BI 概念没有清晰的概念性理解。
我会尽量让事情简单,只给你一个*提示*,一个*色调*,一个*味道*让你开始。
更有经验的 Power BI 用户可能会对我简化和减少这些概念的方式感到畏缩,但是你知道吗?在这一点上,所有的细微差别和细节真的无关紧要。你需要一个开始的地方。相信我,复杂性会来的。
所以,我无畏的战士,我的学徒,我未来的力量 BI 大师,这里有一个非常基本的概述:
1. **电量查询和 M**
2. **DAX**
3. **计算列和度量**
4. **Power Query vs. DAX**

照片由 [NeONBRAND](https://unsplash.com/@neonbrand?utm_source=medium&utm_medium=referral) 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
# 电源查询和 M
这到底是什么?这是一切的开始。Power Query 是将数据导入 Power BI 的地方。m 是 Powery Query 使用的编码语言。您可以通过点击来使用 Power Query,M 中的代码将会自动生成。也可以直接用 M 写自己的代码。
我什么时候使用它?清理和格式化你的数据。你可以做诸如删除和添加列、过滤数据、改变列格式等事情。
**我一定要用 M 吗?**:简而言之,没有,你可以通过指向和点击来完成 Power Query 中的大部分事情,完全不需要使用 M。然而,了解 M 确实有助于使您的过程更加灵活,并且在将来更容易复制。例如,当使用 M 时,您可以复制并粘贴想要重用的代码,并且可以对您的步骤进行注释。
***学习*** *提示:点击* [*打开*](https://docs.microsoft.com/en-us/power-bi/transform-model/desktop-query-overview) *高级编辑器,在电力查询中做你需要做的事情。M 代码将出现在您刚刚完成的操作中。通过这种方式,您可以开始熟悉这种语言,并在尝试从头开始编写自己的 M 代码之前做一些小的调整。*
[](/power-bi-understanding-m-5a3eb9e6c2da) [## 权力 BI:理解 M
### 足以让你变得危险。酷毙了。
towardsdatascience.com](/power-bi-understanding-m-5a3eb9e6c2da)
# 指数
**这到底是什么?** DAX 是数据分析表达式的缩写,一旦使用 Power Query/M 将您的数据提取到 Power BI 中,就可以使用它来创建度量和计算列。
我什么时候使用它?:使用 DAX 本质上就像在 Excel 中使用公式——它允许你根据你的数据进行计算。您可以使用 DAX 创建计算列或度量值。
# **计算列和度量**
这到底是什么?计算列和度量是 DAX 中编写表达式的两种方式。计算列将为表中的每一行创建一个包含值的附加列。度量是基于一个表或多个表中的多行的聚合表达式。
**什么时候应该对计算列进行度量?我很高兴你问了,因为我真的很纠结这个问题。这是一个棘手的问题,因为您通常可以使用度量值或计算列(但这并不意味着您应该这样做)。**
**关于度量和计算列要记住的事情:**
* 当你可以使用任何一个时,使用*测量*
* 当您希望将*计算列*用作筛选器或切片器时,或者如果您希望创建类别(例如,添加一个根据任期包含“新员工”、“员工”或“高级员工”的列),通常会使用该列。
* 如果您想根据用户选择的内容进行计算(例如,计算切片器中所选部门的总收入),您*需要*使用*度量值*
***如果计算列和度量之间的区别现在还不完全有意义,那也没关系。*** 尝试创建一个度量和一个计算列,看看它们是否都符合您的要求。如果是的话,很好,用这个方法。如果只有计算列有效,就用它吧!
# **幂查询(M)还是DAX?**
这里的事情也让我感到困惑,因为似乎我在 Power Query/M 中可以做的大部分事情,在 DAX 中也可以做。*我应该在什么时候使用哪一个?*
**简答**:在可能的情况下使用 Power Query/M。*(这里很少使用的一个大例外是,如果您试图创建一个引用不同表中的列的计算列。在这种情况下,使用 DAX 创建一个计算列)*
**长回答:** [看这个](https://www.sqlbi.com/articles/comparing-dax-calculated-columns-with-power-query-computed-columns/)。

照片由[陈京达](https://unsplash.com/@jingdachen?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
就这样,你做到了!您通过对*幂查询、M、DAX、measures、*和*计算列*的基本概念化完成了它。如果你现在不明白所有的区别和用途,那也没关系!你已经奠定了基础,这是朝着正确方向迈出的一大步。
# 要记住的事情:
* 超级查询是一切开始引入和清理您的数据的地方。
* M 是 Power Query *中使用的语言(不一定要直接使用 M,但是从长远来看让你的生活更轻松)。*
* DAX 是在 Power BI 中创建计算列和度量时使用的语言。
* 如果您 ***可以在 Power Query/M 中*** 做到,您 ***应该*** *(除了当您向引用不同表中的列的表添加列时)。*
* 如果一个计算列或一个度量可用, ***使用一个度量。***
# 后续步骤:
让这些概念在你的大脑中扎根的最简单、最快的方法就是接触和练习。以下是一些很好的入门资源:
* [SQLBI](https://www.sqlbi.com/)
* [微软 PBI 学习](https://docs.microsoft.com/en-us/power-bi/guided-learning/?WT.mc_id=sitertzn_learntab_guidedlearning-card-powerbi)
* [电力 BI 社区](https://community.powerbi.com/)
* 参加来自[锻炼的每周社区挑战周三](http://www.workout-wednesday.com/power-bi-challenges/)
[](https://jeagleson.medium.com/new-in-2021-learn-power-bi-with-weekly-challenges-8742db48a52) [## 2021 年新品:通过每周挑战学习 Power BI
### 最后,Power BI 用户的每周挑战。以下是我如何完成第一次每周挑战的分步指南…
jeagleson.medium.com](https://jeagleson.medium.com/new-in-2021-learn-power-bi-with-weekly-challenges-8742db48a52)
虽然我非常鼓励参与所有精彩的资源,但没有什么比自己尝试一些事情并看看会发生什么更能帮助你了。
**继续用你的头撞墙。会变得更好。**
# 功率 BI 建模
> 原文:<https://towardsdatascience.com/power-bi-modelling-bcd4431f49f9?source=collection_archive---------3----------------------->
## 一些提示。但愿我以前认识他们。

[田宽](https://unsplash.com/@realaxer?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍照
当你想到模特,你会想到什么?很多复杂的连接,查找,或者仅仅是挫折?
你以前经历过这种情况吗?你有一个度量,但它并没有给你正确的答案。你想知道为什么。您不确定原因,所以您调整了度量。也许是表中的某个东西,也许是数据问题,所以您也可以在 Power Query 中调整它。然后你会一无所有…

作者图片
嗯,我经历过。我已经尝试了几种解决问题的方法,但实际上这些方法并没有什么特别之处。
**更确切地说,大多数时候解决方案是模型本身。**
我能想到为什么建模很重要的三个原因。
1. 它简化了你的 DAX 公式。
2. 它让你明白了为什么权力查询很重要。
3. 它给你谈判的权力
## 它简化了你的 DAX 公式
…怎么做?这里有一个我以前遇到过的模型。

作者图片
在这里,城市以多对一的关系连接到县表。然后是县与地区的多对一关系。
该日期以多对一关系联接到月表。在多对一的关系中也是几个月到几年。
如果我想获得某个特定地区的销售额,我可以写 CALCULATE(SUM(FACT[Sales]),FILTER(REGION,REGION[Region] == "North "))。
现在,为什么区域表离它那么远?在这里,权力 BI 必须通过市、县并最终到达地区。
如果我想按月份和年份获取特定的销售额,我可以编写 CALCULATE(SUM(FACT[Sales]),FILTER(YEARS,YEARS[Year]==2000),FILTER(MONTH,MONTHS[month]==12
这不是完全错误的,你可能会得到结果。(想象一下,放置一个矩阵视图,向下拖动一个简单的 SUM(FACT[Sales])度量,其中的行是年、月或地区等)。
问题是功率 BI 必须经过两个独立的表才能得到测量值。如果是一个小表,这没什么大不了的,但是当你在处理一个大的数据集时,你自己去读和 Power BI 去过滤这些表以得到你的答案将是非常困难的。
对于 Power BI 类型的报告,最好将维度表放在一起。
考虑维度主题。

作者图片
我们现在使用的是星型模式,
蓝色=日期主题 —假期等应添加到此表中,而不是其他地方。
**绿色=员工数据主题** —个人信息和其他新字段应该在这里。
**橙色=位置主题** —任何新位置都应添加到此处。
如果您心中已经有了主题,那么您就可以确定哪些表应该属于彼此。
这种设置有助于您整理多个表,并帮助您理解模型。将来可能会添加其他维度表,但是现在您已经知道它们应该放在哪里了。
## 一个更简单的模型让你欣赏权力查询
现在您已经有了一个模型,是时候决定如何正确地连接这些表了。
是的,你可以在 DAX 中做一些映射,你可以写-RELATED(REGION[REGION])来引入列并隐藏区域表。会有用的,但为什么要这么做?
这就是微软所说的 Power Query 可以用来[“准备”或“塑造”](https://support.microsoft.com/en-us/office/shape-data-power-query-9b2dac2b-e13d-46a4-8940-7bc55f44597d)数据的意思。
在 Power Query 中,您可以执行这些连接。

作者图片
Power Query 中的 Shaping 也有一些优点,您可以轻松地进行反连接双重检查,查看是否有月份没有反映在 Years 表中。
这里有一篇文章,如果你想知道如何做这些[加入权力查询](/joins-with-power-bi-bde7de3e2181?source=friends_link&sk=91ebb5c4e4dca48f4e1d216fe86ffdc4)。我个人希望之前有人告诉我这些。这将使我从许多令人头痛的数据中解脱出来。
## 它给你谈判的权力
建模可以帮助你马上找出你能回答什么样的问题。(您的度量可以基于事实表构建,并根据维度或“主题”进行切割)。
这是你的底线。如果有人问你一个商业问题,你已经可以从你的模型中判断出你是否能为他们得到这个问题,与查看表格并计算出这个问题相比,你将对你能回答什么和不能回答什么有很好的感觉。
如果需要额外的见解,那么,您现在可以根据模型从其他单位获得更多的数据。如果需要其他维度,您已经知道如何在您的模型中连接它们。
**这是你应该追求的目标,它从未让我误入歧途。**
1. [明星模式](https://docs.microsoft.com/en-us/power-bi/guidance/star-schema) —爱明星
2. 目标 1:每个维度表到事实表的多种关系
3. 思考空间主题
4. 不同级别的详细信息—事实表中的天数与预算表中的月份?使用日期表格
5. 杠杆力量查询,值得等待。做连接以达到“主题”
我明白,有时候工作没那么简单。有时候你只需要尽快得到答案。做模特是你最不可能想到的事情。
但是请这样想——您需要花费大量的时间来制定措施和进行故障排除,您还不如一开始就投资一个合适的数据模型呢!:)
# 功率 BI 建模误差
> 原文:<https://towardsdatascience.com/power-bi-modelling-error-803856e373d1?source=collection_archive---------22----------------------->
## 当一个模型没有加载时,应该怎么做

里克·梅森在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
当你使用 Power BI 工作时,你不可避免地会经历这样的事情。

作者图片
那些话。“模型无法加载”——这让我…畏缩。
**如果你的模型没有加载,那是因为一个转换在幂查询中失败了。**
如果你需要了解如何建立一个模型,看看[这篇文章](/power-bi-modelling-bcd4431f49f9?source=friends_link&sk=1f054aeeeb14c96238fd6e4f8e192ee2)。谢谢大家看完。
如果你需要复习连接——这里有[第 1 条](https://medium.com/swlh/get-to-know-some-data-set-joins-42e2aa6f5785?source=friends_link&sk=d37f7db7a6c1473198ba89fe3acf1608)和[第 2 条](/joins-with-power-bi-bde7de3e2181?source=friends_link&sk=91ebb5c4e4dca48f4e1d216fe86ffdc4)。是的,它们也会导致错误,而且更微妙,代价更大。
让我们来看看这些错误信息。
# 其中一个表出现故障。

作者图片
在上图中,Power BI 表示它想要加载模型,但是由于“previous”表,它无法加载模型。
该错误由[表达式描述。Error]部分,这个错误所在的表就是您在 Power Query 中需要解决的问题。
## 【表情。错误]—错误的数据类型。
上面的错误消息表明我有一个空值,但是 Power Query 无法将其转换为逻辑值。
这里是如何修复它,并考虑它
1. **缺少值** —如果您正在使用的列需要转换为逻辑列,首先询问它们为什么缺少。在我的情况下,这是一个数据错误的来源。源中缺少的值突出显示了查询中的某些问题。
2. **删除错误或替换错误**。这些选项可以通过右击该栏上的**找到。由于某种原因,空值或缺失值没有正确加载,但我知道它们都应该是 0,所以我使用了**
3. 替换错误,它加载得很好。
## 【表情。错误] —数据类型再次出错
我试图做一个单位 x 价格,但价格栏是文本。因此出现了错误。

作者图片
错误消息非常清楚——不能将运算符*应用于数字和文本。
您可以通过在包含文本的列上**右键单击>更改类型>整数**来修复此错误。
## 【表情。错误]-缺少列
由于转换步骤失败,Power Query 无法加载此表。这种类型的误差被认为是[步级误差](https://docs.microsoft.com/en-us/power-query/dealing-with-errors)。这里有一个很好的例子。

作者图片
我已经从前面的步骤中删除了列,然后在接下来的步骤中,我开始引用以前删除的列。这将导致错误。
这种类型的错误很可能是由于在完成查询后对前面的步骤进行了更改而导致的。记住 M 使用逐步转换,所以如果您对一个步骤进行了更改,您将会影响另一个步骤。
以下是你可以修复它的方法。
1. 您可以通过再次加载缺少的列来修复此错误。Power Query 需要这个专栏来完成它的转换。
2. 您也可以选择添加一个[MissingField。我不确定最后一个参数,有时标记一个错误是为了让你看看需要修复什么。无论如何,我想我应该让你知道这个参数是存在的。
以下是在[missing]字段中添加内容时发生的情况。忽略]参数。

作者图片
它装载得很好。
如果你想知道更多关于这个参数的信息,这里有一个[链接](https://xxlbi.com/blog/safely-removing-columns-power-query/)。我最近发现了这个博客,它很棒。
## 数据格式。错误
这是一个转换错误。Power Query 希望为您加载表,但是有一个值无法转换为您指定的数据类型。

作者图片
这个错误有点令人困惑,因为列数据类型是 number,所以您会认为它已经成功地将列转换成了 number。
Power Query 通过前 1000 行检测列的数据类型。此错误表明在您的源中的某个地方,**在 1000 行**之后,有一个值“11A11”,而 Power Query 不知道如何将它转换成数字。
这里是如何解决和思考它
1. 用源代码中的正确数字替换错误。如果它在二进制文件中,你可以在你的文件中替换它。
2. 先问问为什么会发生。也许是更大的事情?这些数据错误有多少?请记住,您正在创建一个模型,度量和指标将建立在这个模型之上。越早抓越好。
3. 如果您选择排除这些行,您也应该能够解释为什么。(如果您建立了指标,有人问为什么某些指标不等于总人口)
4. 如果您知道这是一个奇怪的现象,并且您没有足够的时间加载二进制文件(太大了!)并对其进行更改,您可以利用 Power Query 的过滤器过滤掉这些值。(这是一个奇怪的现象,不要在意这种情况)。
## **数据源。错误**
超级查询指示无法加载数据源,因为它找不到文件。如果表无法加载,模型也无法加载。
用户拥有不同的驱动器访问权限可能会导致 It 错误。例如,您可以访问驱动器“A:”并且源代码保存在那里。您的同事无权访问此驱动器,因此他们无法加载它。
以下是你可以修复它的方法。
1. 您可以选择**编辑设置**来改变电源查询窗口中的源位置。如果只有你在使用 PBI 文件,这是一个快速的解决方法。
2.您还可以为数据源设置一个参数。

作者图片
在这里,我创建了一个可以访问源文件的用户名列表。

作者图片
我可以去**数据源设置>高级>选择目录中用户名类别上的参数**。
文件路径将根据您选择的用户名而改变。
如果你的文件路径因为任何原因而改变,你可以选择你的参数,你的文件路径也会随之改变。如果你需要,这里有更多关于 Curbal 的[细节](https://www.youtube.com/watch?v=ppM-mLckQfs)。这是一个很好的渠道。
## **防火墙。错误**
这种事不常发生在我身上,但一旦发生了,我花了很长时间才弄明白。基本上跟隐私设置不同有关。
例如,查询 A 的隐私级别设置为 Private,查询 B 的隐私级别设置为 Public。这可能会导致错误。
如果您合并 A 和 B 的结果,观众现在将能够看到什么是私人的。
你有两个选择来解决这个问题
1. 忽略**选项和设置**下的所有隐私设置
2. 将查询分成两个不同的查询
你可以在这里获得更多信息
# 连接错误
这个错误可能是代价最大的。
如果你之前没有读过任何内容,请阅读下面的内容。
这很重要,因为**您的查询将会运行,您的模型将会加载,但是数据不正确。**
让我展示给你看,
我有表 A 和表 B,它们都有相同的 ID 列。我正在做一个简单的内部连接。

作者图片
返回了不正确的连接结果,Power Query 也没有抛出任何错误。内部连接只匹配 5 行中的 3 行,尽管我们知道它应该返回 5 行。(所有 ID,1-5 都在两个表中)

很难发现这样的错误。您可能认为您的模型运行良好,但是经过进一步的检查,您意识到您实际上丢失了记录,这都是因为连接列中有一个空格。(这是 5 条记录,想象一下你有几千条?)
表连接但返回错误结果的原因是因为一些 ID 实际上在值后包含一个空格,所以 Power Query 将其作为一个全新的 ID。
如果我正在连接文本到文本,我会养成一个习惯,做一个修剪和清理,并确保所有的字符都降低。
在这个清洁过程之后,连接加载正常。

作者图片
我希望这篇文章能帮助你,错误是可以发生的。
我听过的最好的名言之一来自比利·穆雷。这也适用于工作。
> “你越放松,你在所有事情上都做得越好——你和你爱的人相处得越好,你和敌人相处得越好,你的工作越好,你和自己相处得越好。”
错误时有发生,有时模型无法加载。这只是数据之旅的一部分。
保持放松。注意安全,玩得开心。:)
希望你喜欢这篇文章。
# 权力 BI:理解 M
> 原文:<https://towardsdatascience.com/power-bi-understanding-m-5a3eb9e6c2da?source=collection_archive---------9----------------------->
## 足以让你变得危险。

酷毙了。来自[突发](https://burst.shopify.com/dj?utm_campaign=photo_credit&utm_content=Free+Stock+Photo+of+Finger+Pointing+At+You+%E2%80%94+HD+Images&utm_medium=referral&utm_source=credit)的 [Samantha Hurley](https://burst.shopify.com/@lightleaksin?utm_campaign=photo_credit&utm_content=Free+Stock+Photo+of+Finger+Pointing+At+You+%E2%80%94+HD+Images&utm_medium=referral&utm_source=credit) 摄影。
当开始使用 Power BI 时,我很难理解 M 和 DAX 以及 measures 和 calculated 列之间的区别(如果你也是这种情况,[这篇概述](/power-bi-m-vs-dax-vs-measures-4c77ae270790?sk=addcf863f61f67c895df4c0b92974536)可能会有所帮助)。
TL;DR: Power Query 是您在 Power BI 中用来加载数据集并清理和操作数据的工具。m 是幂查询中使用的语言。你和我在一起吗?Power Query 和 M 令人惊叹,是 Power BI 与其他商业智能工具的重要区别。然而,也可能有一点学习曲线,这可能会阻止新用户在接触到好东西之前采用 Power BI。
为了帮助你跳过这个常见的障碍,我想和你分享一下我到目前为止学到的东西。这绝不是 M 或幂查询的详尽指南,但它会给你一切你需要知道的东西,让你度过难关,然后继续有趣的事情。
1. 概念理解
2. 开始学习的步骤
3. 如何开始使用
对于那些想跟进的人,我将使用来自周一[改造](https://www.makeovermonday.co.uk/)第 43 周的[数据集](https://data.world/makeovermonday/2020w43-apparel-exports-to-us)。对于任何想在数据可视化方面有所发展的人来说,改造星期一是一个可怕的免费数据集每周挑战。
# 概念理解
当试图建立一个概念性的理解时,它帮助我思考 Power Query 和 M like 宏和 Excel 中的 VBA。
在 Excel 中,创建宏时,可以通过以下方式完成:
1. 使用“记录宏”功能,方法是在整个过程中点击鼠标
2. 使用 VBA 并自己编写代码
同样,在 Power Query 中,您可以通过点击来完成您想要完成的任何数据操作,或者您可以使用语言 M 为该过程编写代码。同样,M 是一种*语言*,在 Power Query 中用于加载和清理数据集。
*侧边栏:M* 与 DAX 完全分离。 *DAX 是您在使用 Power Query 完成诸如创建一个给定年份总销售额的度量值之类的事情之后使用的。好了,言归正传。*
## 我什么时候用 M?
当您将新的数据源加载到 Power BI 中时,步骤#1 应该总是进入 Power Query。*总*。即使您的数据是绝对完美的,并且您不必做任何清理或操作(必须很好),您仍然应该在 Power Query 中启动,以确保一切都按预期加载。
有两种方法可以访问电源查询。加载新数据源时,您可以单击“转换数据”而不是“加载”,也可以随时单击主页功能区中的“转换数据”。

在这个视图中,您将在左侧看到针对您添加的每个数据源的查询,在中间看到数据预览,然后在右侧看到应用的步骤。在您执行任何操作之前,您会看到 Power Query 已经为您完成了许多步骤:

您会注意到,每次您在 Power Query 中做一些事情(例如,过滤数据、删除列等。)您会注意到会自动为您添加一个步骤。非常漂亮,但是这里到底发生了什么呢?
每当你点击完成一个步骤,Power BI 就在后端用 M 语言为你编写命令。同样,这就像我们在 Excel 中记录一个宏,而 VBA 是为我们编写的。
需要明确的是,在大多数情况下,您不需要使用 M 也可以很好地工作。但是,了解一些 M 的基本原理会有很大的帮助,并在将来为你省去很多麻烦。下面找出具体方法。
# 学习 M
作为一个没有耐心的人,当我可以很快地用鼠标点击东西的时候,我并没有打算学习一门全新的语言。
我不能坐下来用 M 从头开始写一个完整的查询。你知道吗?我永远不需要。我发现只要知道得足够多,我就可以快速有效地做我需要的任何事情。我跟大家分享一下我是怎么走到这一步的。
*免责声明:对于那些想要深入探究本质并独立掌握这门语言的人来说,我保证你在这里找不到。你是一个比我更好的人,我祝你一切顺利。*
## 学习 M 的 3 个步骤:
1. 点击(没错,你听到了!)
2. 注释这些步骤
3. 进行调整
当学习 M 时,你也可以利用所有自动为你做的工作。所以从做一些指向和点击开始,只需几步。
我将筛选到 2020 年的数据,并删除月列。您将看到右边的 Applied Steps 面板中添加了两个步骤。
现在,我想看看引擎盖下面,看看 Power BI 为我创建的 M 代码。为此,我将从主页功能区中单击“高级编辑器”。触发警告:这将会看起来很恶心,让人不知所措,但请跟着我。

你会看到这样的东西:
let
Source = Excel.Workbook(File.Contents("C:\Users\jeagleson\Downloads\Week 43.xlsx"), null, true),
#"Week 43_Sheet" = Source{[Item="Week 43",Kind="Sheet"]}[Data],
#"Promoted Headers" = Table.PromoteHeaders(#"Week 43_Sheet", [PromoteAllScalars=true]),
#"Changed Type" = Table.TransformColumnTypes(#"Promoted Headers",{{"Country", type text}, {"Year", Int64.Type}, {"Month", type text}, {"Exports (USD Millions)", Int64.Type}}),
#"Filtered Rows" = Table.SelectRows(#"Changed Type", each ([Year] = 2020)),
#"Removed Columns" = Table.RemoveColumns(#"Filtered Rows",{"Month"})
in
#"Removed Columns"
我到底在看什么?欢迎来到 m 是的。看起来很恶心。但是,请听我说,我将向您展示如何快速使它更具可读性,更容易理解。
首先,我建议您在显示选项下启用自动换行。这将使你可以一次看到所有的文本,而不必从左向右滚动。

关于 M 需要注意的一点是,你会看到每一步都有一个#并且在引号中。我也花了一段时间才意识到,你在每一步输入的第一件事就是前一步的名称。让我告诉你我的意思。我将从#“提升的标题”开始更改每个步骤的名称同样重要的是要注意,如果您的步骤名称中有空格,那么您只需要#"。我发现如果我把每一步的名字都写成一个单词,阅读起来会容易 547 倍。

现在,您可能希望将每个步骤命名为比步骤 2 更有意义的东西(例如,ChangeDataTypes),但希望这有助于说明我所说的每个步骤引用前一个步骤的意思。
一旦我在高级编辑器中点击完成,有趣的事情发生了。我们有相同的应用步骤,但它们现在反映了我们的新名称。

很酷吧。
现在,让我们花更多的时间在 M 上,仔细思考每一个步骤在做什么。再说一次,我们并不试图去记忆任何公式,只是试图去理解每一步发生了什么,以防我们以后需要做出改变。
我在每个步骤上面添加了一个注释,简要说明该步骤在做什么。在注释的开头添加一个“//”,这样 Power Query 就知道您不会试图在 M 中键入某些内容并忽略它。“//”告诉编辑,你只是在自言自语,而不是试图用 m 告诉它什么。

您可以在高级编辑器和点击之间来回切换,这样您就可以在进行的过程中为每个步骤添加注释。但是现在,当我再次点击完成,你会看到另一件很酷的事情发生了。现在每个步骤都有一个信息图标,我可以将鼠标悬停在上面查看我的评论。我可以将鼠标悬停在每个步骤的图标上,查看它在做什么,而不必再次打开高级编辑器。

这越来越令人兴奋了,你说呢?
# 使用 M
现在我们已经了解了 M 是什么,并且我们已经习惯了在高级编辑器中导航,我们准备开始使用一些 M 来使我们的生活变得更加容易。再说一次,我支持从点击开始,然后在高级编辑器中做一些小的调整。以下是一些例子:
* **更新源文件位置** 假设我想用第 44 周的数据更新我的 Power BI 文件。我简单地打开我的高级编辑器,在第一个 Source =步骤中,我把我的文件路径从“C:\ Users \ jea gleson \ Downloads \**Week 43**。xlsx " to " C:\ Users \ jea gleson \ Downloads \**第 44 周**。xlsx "
* **处理源文件结构的更改** 我经常遇到的情况是,我想更新我的 Power BI 文件,但我的源文件已被更改。例如,更改了列名,或者添加或删除了列。Power BI 真的很不喜欢出现这种情况。没有办法通过指向和单击来处理这一点,但是在 m 中进行调整是轻而易举的。假设我的源文件现在在“国家”列之后有一个“地区”列。我需要做的就是进入我的高级编辑器,使用与其他列相同的格式添加区域列:
Step2 = Table。TransformColumnTypes(Step1,{{"Country ",type text}, **{"Region ",type text}** ,{"Year ",Int64。Type}、{"Month ",type text}、{ " Exports(USD million)",Int64。Type}}),
现在,我想说清楚,M 可以做很多很酷的东西。尤其是当你想开始创建和重用函数的时候。但是,当你开始的时候,过分沉迷于 M 的杂草中是有害的,它会不必要地减慢你的进度。我鼓励你首先在 Power Query 中点击鼠标,然后查看高级编辑器并做一些小的调整,以适应 m。然后,一旦你适应了,天空就是极限!
如果您想了解更多关于 Power Query 和 M 如何适应 DAX 和其他 Power BI 概念的信息,您可能会发现这很有帮助:
[](/power-bi-m-vs-dax-vs-measures-4c77ae270790) [## Power BI: M 与 DAX 以及测量值与计算值列
### 我希望我刚开始时就知道的基础知识。
towardsdatascience.com](/power-bi-m-vs-dax-vs-measures-4c77ae270790)
# 其他一些有用的 M 技巧:
* 每个查询都以“let”开头
* 每个查询都以“in”和 LastStepName 结尾
* 每一步后面都有一个逗号,除了最后一步,最后一步没有逗号
* 我通常是这样想每个步骤的:
NameOfStep = Function(NameOfPreviousStep,Function stuff),
* 如果您的列包含数字,您很可能会使用数据类型“Int64”。类型”——我不明白他们为什么不能制造这个“数字”
准备好测试你学到的东西了吗?请查看这一每周一次的 Power BI 挑战赛:
[](https://jeagleson.medium.com/new-in-2021-learn-power-bi-with-weekly-challenges-8742db48a52) [## 2021 年新品:通过每周挑战学习 Power BI
### 最后,Power BI 用户的每周挑战。以下是我如何完成第一次每周挑战的分步指南…
jeagleson.medium.com](https://jeagleson.medium.com/new-in-2021-learn-power-bi-with-weekly-challenges-8742db48a52)
继续用你的头撞墙,这样会好很多!

[***詹娜·伊格尔森***](https://medium.com/@jeagleson)*我的背景是工业组织心理学,我在人物分析中找到了自己的家。数据使我的作品变得生动。我主要使用 Power BI,但偶尔也会使用 Tableau 和其他工具。我很想听到更多关于你的旅程!在此评论或在*[*Linkedin*](https://www.linkedin.com/in/jenna-eagleson/)*或*[*Twitter*](https://twitter.com/JennaEagleson)*上留言联系我。*
# 权力 BI vs 画面 vs 知识 I
> 原文:<https://towardsdatascience.com/power-bi-vs-tableau-vs-knowi-fe3eb01dce33?source=collection_archive---------40----------------------->
## 比较三种功能强大的 BI 工具的特性和使用案例

由 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的 [Max Leveridge](https://unsplash.com/@maxleveridge?utm_source=medium&utm_medium=referral) 拍摄的照片
在当今围绕数据科学和机器学习的所有讨论中,人们可能会认为商业智能(BI)已经失去了它的重要性。但他们大错特错,因为大企业实际上比以往任何时候都更依赖商业智能和数据科学来增强决策。许多采用传统商业模式的公司正在向数字化转型迈进。根据[的一份报告](https://www.mordorintelligence.com/industry-reports/global-business-intelligence-bi-vendors-market-industry),2019 年商业智能市场规模为 205 亿美元,预计到 2025 年将增长至 405 亿美元,CAGR 为 12%。
Tableau 仍然是商业智能工具的市场领导者,而微软也通过几年前推出的 Power 阿碧扩展到了商业智能工具领域。我们也有像 Knowi 这样相对较新的初创公司,它们正试图拓展传统商业智能的边界。所有这些也表明,商业智能仍然是一个活跃的领域,在未来几年只会增长。
在 BI 工具中,由于 Power BI 和 Tableau 的广泛流行,我们看到了它们之间的许多比较。但是我们认为写一篇关于 Tableau 与 Power BI 与 Knowi 之间的三方面比较的文章会很有趣,并看看它们之间的关系。在开始比较之前,让我们先对它们进行一个介绍性的概述。
## (舞台上由人扮的)静态画面

Tableau 徽标
Tableau 软件于 2003 年[推出,从那以后经受住了时间的考验。如果我们纯粹从用户群的规模来判断,它显然是目前市场上所有 BI 工具中的赢家。在业务分析、报告和可视化功能中,Tableau 光鲜亮丽、极具吸引力的数据可视化在商业智能用户中赢得了最积极的反响,并帮助 Tableau 成为商业智能数据可视化工具的市场领导者。](https://en.wikipedia.org/wiki/Tableau_Software)
2019 年 6 月 10 日,Salesforce 以价值超过 150 亿美元的纯股票交易收购了 Tableau。
## 功率 BI

Power BI 徽标
微软在 [2015](https://en.wikipedia.org/wiki/Power_BI) 面向大众推出了其专有的商业智能工具 Power BI,作为一款独立产品。但在此之前几年,微软已经将 Power BI 的一些分析和可视化功能作为插件捆绑到 Excel 中。Power BI 与 Microsoft Office 生态系统无缝集成,并在 Office 用户群中迅速流行起来。事实上,Power BI 的一大卖点是,将顽固的 Excel 用户转移到真正的商业智能环境中是很自然的下一步。
## Knowi

Knowi 徽标
Knowi 是一个现代商业智能工具,它试图通过使用数据虚拟化来消除对 ETL 的需求,从而将自己与传统的 BI 工具区分开来。Knowi 还通过支持与 NoSQL 数据库的本地连接而脱颖而出,允许用户直接对非结构化数据进行分析——这在传统上是不可能的。它拥有任何传统 BI 工具的所有常规功能,但它最受欢迎的功能之一是由自然语言 BI 平台支持的搜索驱动的分析。虽然 knowi 是在 2015 年推出的(与 Power BI 同年),但在最初几年,他们一直处于相对隐形的模式,因为他们将所有精力集中在构建一个可以与一些大牌竞争对手正面交锋的 BI 工具上。早期的尽职调查得到了回报,正如 Knowi 吹嘘的那样,它的客户群中有一些大企业。
# 权力 vs 画面 vs 知识
在本文的剩余部分,我们将在 8 个核心领域对三者进行比较:
* 设置和产品
* 数据源
* 支持的数据
* 形象化
* 分析学
* 人工智能
* 定价
* 方便用户
# 设置和产品
Tableau 为用户提供了桌面客户端和在线云访问工具。桌面用户可以从 *Tableau 桌面、Tableau 桌面个人版、Tableau 桌面专业版的不同产品中进行选择。*云用户可以使用 T *ableau Public(免费)或 Tableau Online* 。企业公司也可以在内部安装 *Tableau 服务器*,但他们也需要桌面客户端来访问 *Tableau 服务器*上的报告。最后, *Tableau Mobile* 支持移动设备用户在移动中无缝访问 *Tableau 服务器或 Tableau Online* 上的报告。
Power BI 还分别通过其 *Power BI 桌面和 Power BI 服务*为桌面和云用户提供产品。可以使用 *Power BI 服务器*和 *Power BI 数据网关*为公司进行现场安装。 *Power BI Mobile* 允许用户在移动设备上访问云端报告。
Knowi 提供了支持云的平台和本地版本。根据设计,Knowi 不支持桌面安装,因为它已经过优化,可以作为 SAAS BI 平台在 web 浏览器中运行。对于企业用户,Knowi 提供了云/本地/混合部署的选项。Knowi 仪表盘和分析可以与移动用户共享,其嵌入式分析引擎可以添加到移动应用程序中。但 Knowi 平台本身没有移动应用程序版本,通常不允许用户从手机或平板电脑上进行新的分析查询。
就产品范围而言,Tableau 和 Power BI 都有类似的产品,两者之间几乎没有什么区别。另一方面,虽然桌面用户仍然是一个很大的细分市场,但 Knowi 只关注云用户,押注于整个软件市场的未来,继续朝着 SaaS 第一的生态系统发展。

动力 BI 的手机 app 流量(来源:microsoft.com)
# 数据源
[Tableau](https://www.tableau.com/en-in/products/techspecs) 和 [Power BI](https://docs.microsoft.com/en-us/power-bi/connect-data/power-bi-data-sources) 基本上都可以连接到任何结构化或基于 SQL 的数据源。对于不基于 SQL 的数据源,Tableau 和 PowerBI 用户仍然可以连接到它们,但是需要使用像 ODBC(开放式数据库连接)驱动程序这样的中介来翻译 SQL。他们也可以使用 ETL 过程将所有数据转移到基于 SQL 的数据仓库中,并应用模式。
Knowi 支持超过 36 个数据源,从结构化数据到非结构化数据(如 MongoDB、Couchbase、Apache Cassandra 和 Elasticsearch)。在商业智能工具中,Knowi 与众不同,它能够本地连接到 NoSQL 数据源。Knowi 最常用于涉及 MongoDB 分析或 Elasticsearch 分析的用例。
Tableau、Power BI 和 Knowi 的另一个常见功能是支持 REST API 和 REST API 分析。这为将第三方应用与这些 BI 工具无缝集成提供了更多可能性。
很明显,在连接基于 SQL 的数据源方面,Tableau 和 Power BI 并驾齐驱。尽管 Knowi 在其网站上明确列出了更少的数据源,但最终,它实际上可能会连接到更多的数据源,因为它对 NoSQL 数据的开放支持以及更灵活的 REST API 集成。也就是说,他们不同的关注点使得在数据源/集成上进行比较变得棘手。
# 支持的数据
虽然 Tableau 和 Power BI 都以用于分析大数据而闻名,但用户对 Power BI 大数据支持的反馈不如 Tableau。他们处理非结构化数据的能力有限,这也是在一些更复杂的用例中产生摩擦的原因。
Knowi 可以无缝处理任何类型的结构化、非结构化、大数据或小数据。这主要是因为它提供了一个数据虚拟化层。这种数据虚拟化使 it 能够处理任何类型的数据,而不必担心底层数据结构和任何 ETL 过程的需要。它还创建了一个灵活的环境,用户可以在其中执行跨数据库连接,甚至可以将 MySQL 等结构化数据库中的数据与 MongoDB 等非结构化数据库中的数据连接起来。
显然,这 3 个工具支持所有类型的数据,但是,由于内置的数据虚拟化,Knowi 确实带来了其他 BI 工具无法带来的额外和独特的东西。

Knowi 仪表板示例(来源:Knowi)
# 形象化
Tableau 因其制作商业智能世界中最令人惊叹和最复杂的可视化[的能力而广受欢迎。您可以创建功能强大的图表、图形、地图、信息图和仪表盘,并根据您的创造力进行大量设置。](https://www.tableau.com/learn/articles/data-visualization)
Power BI 还提供了您期望从微软产品中获得的大量数据可视化选择。你会发现几乎所有的标准和高级可视化类似于 Tableau。它还可以让你创建自己的自定义可视化,并把它们放在他们的应用源市场上。
Knowi 也不落后于上述大男孩,并提供丰富和高度可定制的可视化和仪表板选项。它支持 30+不同类型的简单和先进的可视化,应该照顾最常见的数据即需求。此外,Knowi 允许用户创建定制的可视化,以满足他们特定的数据需求。
毫无疑问,Tableau 是市场上数据可视化工具的黄金标准。另一方面,我们会说 Power BI 和 Knowi 都为您提供了所有标准的数据可视化,以及您需要的所有定制。但是,如果你正在寻找一个仅基于视觉美学的 BI 工具,并且你不需要连接到各种各样的复杂数据源,Tableau 可能是你的最佳选择。

Tableau 可视化示例(来源:维基百科)
# 分析学
尽管 Tableau 通常被视为数据可视化工具,但它也是执行高级分析的强大平台。它最近还推出了一个新功能 [Ask Data](https://www.tableau.com/en-in/products/new-features/ask-data) ,非技术用户可以简单地在搜索栏上提出一个问题,Tableau 将解释自然语言输入并给出问题的输出。
Power BI 提供了针对高级和初级用户的良好分析功能。与 Tableau 类似,它也支持[自然语言查询](https://powerbi.microsoft.com/en-us/blog/qna-december-2018-update/),用于对对话问题进行分析。
最后,Knowi 还因其由数据虚拟化支持的下一代分析平台而闻名,该平台使查询结构化和非结构化数据更加方便。它还支持由自然语言查询实现的搜索驱动的分析,就像上面两个工具一样。
最近,Knowi 在 Slack 中推出了基于搜索的分析。一个新功能,你可以在 Slack 中用简单的英语问你的 Knowi instance 问题,然后得到答案、图表和数据。

Knowi 基于搜索的 Slack 分析功能(来源:Knowi 基于搜索的分析)
# 人工智能
在上一节中,我们看到了所有三个工具如何利用自然语言处理来提供自然语言搜索驱动的分析。但这还不是全部,它们都提供了一些现成的集成机器学习功能。
Tableau 提供各种[机器学习](https://www.tableau.com/solutions/smart-analytics)功能,如聚类、预测分析、预测、智能推荐和模糊匹配。
由于与 Azure 平台的集成,Power BI 还提供了各种机器学习模型的创建。除此之外,它还通过认知服务 API 支持文本分析和计算机视觉。
Knowi 也内置了许多用于分类、回归、时序异常检测的机器学习算法。它还计划很快将集群和深度学习功能引入其平台。
# 定价
众所周知,Tableau 价格昂贵,对于个人或小团队来说不是一个口袋友好的选择。相比之下,Power BI 的起点价格较低,但如果你扩大许可证和插件的规模,价格将大幅上涨。尽管如此,Power BI 的起始价格较低,对于寻求因果数据可视化或分析的人来说是一个不错的选择。这与 Power BI 的起源如出一辙,它是微软 Office 的扩展,旨在供个人或企业用户使用。
像 Tableau 一样,Knowi 的定价点也是以中型公司或大型企业公司为目标,而不是针对个人的产品。然而,Knowi 定价保持灵活,以满足公司的特定需求,并根据需求和使用情况而变化。无论是部署在云上还是内部,这种灵活的定价模式都是根据每个客户的特定需求量身定制的。
随着规模的扩大,Tableau 和 Knowi 之间的价格差异变得更加明显。Tableau 的线性定价模式意味着每个新用户的额外费用,这些费用可能会很快增加。另一方面,Knowi 的定价基于大量用户。这意味着,随着用户群的增长,定价逐渐降低,实际上变得更具成本效益。
另一个要考虑的事情是,使用 Tableau 或 PowerBI 进行企业分析可能会带来无形的成本,即必须构建数据仓库基础设施,以将所有数据源纳入到绑定到模式的数据结构中。Knowi 的非 ETL 解决方案在大多数情况下可以避免这种成本。
在 Power BI 与 Tableau 和 Knowi 之间选择工具时,价格实际上是一个很大的区分因素,因为不同的应用程序会重视不同的功能。一家希望迅速扩大规模的初创公司可能会选择 Knowi,因为其早期的灵活启动定价和随规模扩大的分桶用户定价模型。需要廉价 BI 解决方案的小公司可能会选择 PowerBI,因为它的入门价格门槛较低。
# 用户友好性
这三个工具都有直观的界面,但如果我们对这三个工具进行比较,普通用户可能会发现 Tableau 的高级选项有点难用。非技术或不太高级的用户通常使用案例有限,他们会发现 Power BI 更容易使用——特别是如果他们有很强的 Microsoft Excel 背景的话。Knowi 使用了一个基于浏览器的 web 应用程序界面,这对于大多数用户来说是熟悉和有意义的,但与其他两个相比,他们的 UI 可能需要一点改进。
# 画面 vs 权力 BI vs 知识——最后的想法
正如我们看到的,在几乎所有的比较参数中,这三种工具都表现得相当不错。每种工具不仅有自己的优点和缺点,还带来了自己独特的产品。
如果你是个人,那么毫无疑问,你可能会选择 Power BI,因为其他任何东西都非常昂贵。
对于公司而言,如果您关注的是价格点,那么 Power BI 也是一个不错的选择,前提是您的团队未来不会扩大规模,或者您不需要高级选项。如果不是这样,那么 Tableau 可能是一个物有所值的好选择。如果你正在寻找灵活的定价选择,或者你是一家初创公司,那么你可能也想去 Knowi,因为他们也有针对小型初创公司的特殊定价选择。
如果您的组织正在处理大数据,那么与 Power BI 相比,Tableau 将是一个不错的选择,前提是您的预算允许。但是,如果您没有一个定义良好的 ETL 流程的大数据仓库,那么您也可以考虑 Knowi,因为由于它的数据虚拟化,它不需要您拥有所有这些基础设施,并且不需要从源移动。
在权力 BI、画面和知识之间做一个比较是很有趣的。由于大数据、人工智能的出现,以及企业越来越多地使用非结构化 NoSQL 数据,商业智能的前景在过去几年中发生了很大的变化。PowerBI 和 Tableau 都试图通过加入机器学习功能,从现在的商业分析工具转变为增强的分析工具。在这一点上,Knowi 与这两位有些不同。作为第三代商业智能平台,它从机器学习功能开始。但作为一家规模较小的初创公司,它仍有很大的增长空间,在市场的一些领域,它需要赶上其他两种解决方案。
看看这三个平台在接下来的几年里会有什么样的新特性会很有趣。
# 没有控制,权力什么都不是
> 原文:<https://towardsdatascience.com/power-is-nothing-without-control-aa43523745b6?source=collection_archive---------40----------------------->
## 不要和 Jupyter 笔记本分手。也用 Kedro 就好!
这篇文章适合那些发现自己被 Jupyter 笔记本的易用性所吸引的人。虽然它针对的是数据科学相对较新的读者,但它同样适用于更有经验的数据科学家&工程师,他们正在考虑如何改进他们的日常工作流程。
## Jupyter 笔记本的便利性与 Kedro 的软件最佳实践相结合
我将简要介绍一下我们喜欢和不喜欢 Jupyter 笔记本的原因,并描述一下[开源 Kedro 框架](https://kedro.readthedocs.io/en/stable/01_introduction/01_introduction.html)如何帮助您解决令众多数据专业人士头疼和心痛的一些问题。而且不涉及分手!如果你不能完全放弃,你仍然可以在 Kedro 旁边使用笔记本。

笔记本之恋:图片来自[达留什·桑科夫斯基](https://pixabay.com/users/dariuszsankowski-1441456)来自[皮克斯拜](https://pixabay.com/photos/paper-romance-symbol-valentine-1100254/)
如果你对笔记本不熟悉,或者想了解更多,这里有一个简短的历史题外话,总结自一篇名为[数据科学家喜欢 Jupyter 笔记本的 10 个原因](https://hub.packtpub.com/10-reasons-data-scientists-love-jupyter-notebooks/)的精彩文章。如果你已经知道所有你需要(或想要)的他们的历史,就跳到下一节“ ***为什么要用 Jupyter 笔记本*** ”。
早在 2011 年,IPython Notebook 作为交互式 Python 控制台的基于 web 的接口发布。它允许 Python 开发者在本地网页上操作代码、文本、数据图等等。IPython 笔记本迅速变得如此受欢迎,以至于它被扩展到包括其他编程语言,如 R 和 Julia。
2014 年,Jupyter 项目宣布以新的名称管理多种语言的 IPython 笔记本,而 IPython 继续作为 Python shell。
[维基百科解释了](https://en.wikipedia.org/wiki/Project_Jupyter)该项目的名称选择:
> “Project Jupyter 的名字是对 Jupyter 支持的三种核心编程语言的引用,这三种语言是 [Julia](https://en.wikipedia.org/wiki/Julia_(programming_language)) 、 [Python](https://en.wikipedia.org/wiki/Python_(programming_language)) 和 [R](https://en.wikipedia.org/wiki/R_(programming_language)) ,也是对伽利略记录木星卫星发现的笔记本的致敬。”
Project Jupyter 网站将自己描述为“一个非盈利、开源的项目……旨在支持跨所有编程语言的交互式数据科学和科学计算”。该项目自开始以来一直蓬勃发展,并于 2017 年获得了 [2017 ACM 软件系统奖](https://blog.jupyter.org/jupyter-receives-the-acm-software-system-award-d433b0dfe3a2)。
可以说,Jupyter 笔记本已经成为数据科学家工具箱中必不可少的一部分。
# 为什么要用 Jupyter 笔记本?
***❤️我们爱笔记本❤️*** 这是可以理解的
当你开始从事数据科学或数据工程时,有很多东西需要学习。有很多资源可以帮助你,包括在线课程。大多数都提供了示例项目,这些项目最有可能出现在笔记本中,因为它们对于初学者来说非常简单。它们使得获取代码、单步执行代码、绘制数据和实验变得特别容易。你一定会发现在笔记本上开始比设置一个 IDE 并通过脚本来使用它要简单得多。你只需要拿一个笔记本,只要你跑了`pip install Jupyter`就可以开始了。每次运行笔记本单元时,您都会立即看到代码的结果。不喜欢什么?
不可否认的是,无论你多么有经验,当你开始一个项目时,笔记本对于实验和想象都是有用的。随着你扩大生产规模或需要与他人合作,蜜月期会逐渐消失。即便如此,也有使用笔记本的方法:例如,[网飞数据团队](https://netflixtechblog.com/notebook-innovation-591ee3221233)已经描述了如何扩大笔记本的使用。但是,对许多人来说,一句谚语“没有控制,权力什么都不是”跃入脑海。
没有控制,权力什么都不是:来自倍耐力的视频
# 为什么不用 Jupyter 笔记本?
***💔这也可以理解为什么我们不再喜欢笔记本了💔***
在整个数据科学网站上,甚至仅在这个博客上,就有一系列[的](/5-reasons-why-jupyter-notebooks-suck-4dc201e27086) [的](/beyond-the-jupyter-notebook-how-to-build-data-science-products-50d942fc25d8) [文章](/5-reasons-why-you-should-switch-from-jupyter-notebook-to-scripts-cb3535ba9c95)详细介绍了 Jupyter 笔记本电脑在大型项目中成为问题的原因。一旦你到了需要使用软件最佳实践来控制你的复杂性的时候,很明显笔记本不支持那些理想。
作为一名前 C 程序员,我认识到这些缺陷来自一个强大而自由的开发环境。例如,随着代码变得越来越大,很难在单个笔记本中进行管理。大量的代码变得错综复杂。有时候,一个笔记本是不够的。假设您想一起运行多个模型,并比较结果?每个人都需要一个单独的笔记本。如何用相同的配置来设置它们,并随着实验的进展不断地改变它们呢?
假设您想要使用一组新数据进行测试,或者使用不同的方法处理现有数据,或者向您的算法输入不同的参数。你可以改变你的笔记本,但是你不能轻易地跟踪那些改变并回滚它们,如果你在你的笔记本中引入一个错误源,那就不简单了。笔记本格式不太适合源代码控制,调试也很棘手。
团队中的数据科学家遇到的另一个问题是环境再现性。假设您想与同事协作并共享您的笔记本。但是如果他们使用的是一个特定包的不同版本,比如已经随时间改变的`sklearn`,该怎么办呢?您如何向您的同事指定要设置什么环境,以便他们可以像您在自己的机器上一样运行笔记本电脑?你如何自动设置?更进一步:您希望将代码作为演示的一部分部署给团队中的许多人。但是如何管理配置和更新呢?甚至不要考虑如何发布和产品化您的笔记本电脑!
# 最佳实践:如何将 Jupyter 笔记本与优秀的工程技术相结合
与其完全扔掉你的笔记本,为什么不考虑用它们来做实验(例如探索性的数据分析),同时在一个框架内构建你的项目呢?
早在 2019 年,我曾在这个博客的[帖子中介绍过](/kedro-prepare-to-pimp-your-pipeline-f8f68c263466) [Kedro](https://github.com/quantumblacklabs/kedro) ,尽管从那以后我们在 [readthedocs.io](https://kedro.readthedocs.io) 上创造了一些更简单的了解 Kedro 的方式。
Kedro 由高级分析公司 [QuantumBlack](https://www.quantumblack.com/) 创建,并于 2019 年开源,以扩展其对第三方数据专业人士的使用。它是一个开发工作流工具,将软件工程最佳实践应用于您的数据科学代码,因此它是可复制的、模块化的和有良好文档记录的。如果你使用 Kedro,你可以少担心学习如何写生产就绪的代码(Kedro 为你做了繁重的工作),你将标准化你的团队合作的方式,让你们所有人更有效地工作。
虽然 Kedro 有一个学习曲线,因为您将使用 Python 脚本和命令行界面,但随着您获得有组织的代码和数据的好处,它会很快得到回报。当你开始一个新的项目时,这是一个很好的时机,但是你也可以将一个现有的笔记本转化为一个 Kedro 项目,正如最近来自 DataEngineerOne 的一个视频所展示的那样。
一旦你建立了一个 Kedro 项目,你可以[使用一个 Jupyter 笔记本来开发你的代码](https://kedro.readthedocs.io/en/latest/11_tools_integration/02_ipython.html#kedro-and-jupyter),如果你喜欢这种工作方式的话,然后把它转换成一个 Kedro `node`,这是一个 Python 函数,由 Kedro 框架在它管理`pipeline`的角色中调用。(该术语在文档中的 [Hello World 示例](https://kedro.readthedocs.io/en/latest/02_get_started/03_hello_kedro.html)中有进一步的解释,您将在设置 Kedro 安装的过程中学习该术语)。有一些简洁的扩展允许你在开发你的 Kedro 项目时在笔记本上工作,你可以找到一个视频如何使用[两个技巧使 Jupyter 笔记本在 Kedro](https://www.youtube.com/watch?v=ZHIqXJEp0-w&list=PLTU89LAWKRwEF1U28qtfPJXSPGZ8SVE2A&index=5&t=0s) 上更有用。
**总之**
> 阻力最小的道路可能很吸引人,但是一个训练有素的发展方法从长远来看是值得的。
虽然笔记本可以帮助您快速启动和运行,但当您尝试扩展项目时,可能会遇到问题,因为它们缺乏对版本、可再现性和模块化的支持。
Kedro 是一个构建代码的框架,它借鉴了大量数据科学家在一系列工业项目中的经验。它坚持让您与软件最佳实践保持一致,但它也允许您选择使用 Jupyter 笔记本进行实验,并简化代码从笔记本到 Kedro 项目的转移。
但是不要相信我的话。查看[团队使用它的原因](https://medium.com/quantumblack/beyond-the-notebook-and-into-the-data-science-framework-revolution-a7fd364ab9c4),如果你想了解更多,请前往 [kedro.readthedocs.io](https://kedro.readthedocs.io) 或查看[不断增长的关于 kedro 的文章、播客和讲座列表](https://kedro.readthedocs.io/en/stable/11_faq/01_faq.html#articles-podcasts-and-talks)!
衷心感谢 QuantumBlack Labs 的 [Yetunde Dada](https://medium.com/u/e5bc6f3d62b7?source=post_page-----aa43523745b6--------------------------------) 和 [Lais Carvalho](https://medium.com/u/3da399388ac7?source=post_page-----aa43523745b6--------------------------------) 在我写这篇文章时提供的宝贵见解,并感谢整个 Kedro 团队愿意分享他们所知道的东西💚
# 数据科学中并行处理的力量。
> 原文:<https://towardsdatascience.com/power-of-parallel-processing-in-data-science-ea64ec3dcd61?source=collection_archive---------28----------------------->
## 知道何时进入并行模式以及如何充分利用并行模式的艺术。

照片由[蒂尔扎·范·迪克](https://unsplash.com/@tirzavandijk?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
我们大多数人都有平行做事的习惯。想象一下,你去杂货店,接到一个朋友的电话,于是你们开始聊天,同时买东西。单词“**同时”**暗示了我们将注意力分配到不同任务的能力。但是注意力的分散经常会降低效率和表现,因为我们的大脑一次只能专注于一件事。
同样的概念是否适用于并行解决数据科学的问题?
答案是: ***取决于手头的问题和可用的计算资源*** 。
因此,让我们打开构建并行解决方案所需的组件
# 划分问题空间
默认情况下,并行问题需要被分割成块,以便每个块可以被馈送到不同的计算节点。这样,我们可以将它们分为两种类型:
* **按任务**:想到盖房子。您可以并行执行许多任务,例如,管道、电气、安装窗户等。
并行工作的工人
现在,在数据科学的背景下,考虑从相同的人口数据中导出的两个模型,一个用于理解*出生因素*,另一个用于*推理死亡*。
* **按数据**:相同的任务,但在不同的数据块上。例如,在同一栋房子里,所有的窗户都可以平行安装。在数据科学场景中,我们会遇到需要对不同的数据集/数据子集应用相同的建模函数的情况。例如,使用直方图绘制全球不同国家的温度分布。
了解划分技术只是解决并行问题的第一步。最重要的方面是了解您想要在其上训练或部署模型的系统。无论是在台式机、网络系统还是超级计算机上完成的工作都很重要,因为它构成了执行计算的骨干处理器。所以让我们解开它的建筑概念。
# **并行计算的标准**
1. 需要至少两个处理器(核心)或通过网络连接的单核/多核计算机集群。例如, [kaggle 内核](https://www.kaggle.com/notebooks)提供了四核功能,现在几乎所有系统都具备这种功能,甚至我们的手机也不例外。
2. [共享内存模型](https://en.wikipedia.org/wiki/Shared_memory)帮助进程共享相同的数据,从而节省时间。
3. [分布式内存](https://en.wikipedia.org/wiki/Distributed_memory):进程不能访问另一个进程的内存。称为消息传递系统,因为进程通过相互发送消息来进行通信。

共享内存和分布式内存
因此,为了使用编程语言构建模型,它们的大多数实例(会话)利用系统的单核。R 和 Python*就是这样的例子。默认情况下,它们运行在单核上,除非您明确指定和构建代码以适应并行环境。*
# 将并行问题融入编程环境
当构建并行代码**时,主从模型**用于描述并行工作场景
* 它用于主创建工人并在他们之间分配任务的情况。工作进程执行它们任务并将结果返回给主进程,主进程反过来执行

主工人模型
* 对于需要综合解决方案的问题,master 向工人交付第一批任务,然后等待结果。在收集完所有结果后,它发送第二批任务,再次等待结果,以此类推。
* 虽然主工人模式看起来很有益,但它缺乏处理负载平衡问题的能力。例如,假设有 4 个工人,主人给他们第一批任务。其中 2 名工人完成了任务,2 名工人仍在工作。现在,主人需要等待所有 4 名工人的结果,才能给第二批任务。因此,增加了两个空闲工人的等待时间。
# **令人尴尬的平行问题**
通常情况下,并行任务之间不存在依赖关系,因此使用术语“令人尴尬的并行问题”。例如,从目录中读取不同的文件。
这种并行问题倾向于很少或不需要任务之间的中间结果的通信,因此不同于需要任务之间通信的分布式计算问题。
# 结束注释
在这篇博客中,主要目标是理解并行处理的领域。不是所有的问题都可以用并行处理来解决,也不是所有的并行问题都可以节省时间。
对于较小的任务,使用并行任务的计算效果可能不那么富有成效,但是当处理依赖于多个数据源的复杂问题集时,将并行处理集成到解决方案中的能力可能是有益的。
要在编程环境中实现并行问题,请尝试浏览以下博客:
[](https://www.business-science.io/code-tools/2016/12/18/multidplyr.html) [## 加速您的代码:使用 multidplyr 进行并行处理
### 没有什么比等待长时间运行的 R 脚本迭代运行更令人沮丧的了。我最近遇到了…
www .商业科学. io](https://www.business-science.io/code-tools/2016/12/18/multidplyr.html) [](https://blog.dominodatalab.com/multicore-data-science-r-python/) [## 使用 R 和 Python 的多核数据科学
### 本文摘自 R 和 Python 中多核数据科学的完整视频。观看完整视频了解…
blog.dominodatalab.com](https://blog.dominodatalab.com/multicore-data-science-r-python/) [](https://www.kaggle.com/gravc91/introduction-to-parallel-programming-in-r) [## R 语言并行编程简介
### 使用 Kaggle 笔记本探索和运行机器学习代码|使用来自非数据源的数据
www.kaggle.com](https://www.kaggle.com/gravc91/introduction-to-parallel-programming-in-r)
# 面向每位 Power BI 开发人员的 Power 查询技巧
> 原文:<https://towardsdatascience.com/power-query-tips-for-every-power-bi-developer-da9ebd3dcd93?source=collection_archive---------28----------------------->
## 使用这些简单而强大的技术来加速您的 Power BI 开发
如果有人让你定义幂查询,你该怎么说?如果您曾经使用过 Power BI,那么即使您没有意识到,也不可能没有使用过 Power Query。因此,可以很容易地说,权力质询是权力 BI 的
**
*照片由 Amar Yashlaha 在 Unsplash 上拍摄*
*在更官方的措辞中,Power Query 是微软用于连接和转换来自多个来源的数据的技术。正如[微软的官方文档](https://docs.microsoft.com/en-us/power-query/power-query-what-is-power-query)所述,你可以连接到数百个不同的数据源,并对你的数据进行 300 多次转换。*
*Power Query 的关键优势在于,您只需很少或不需要任何编码技能就可以执行复杂的数据转换!此外,您在数据转换过程中应用的所有步骤都将被保存,因此每次刷新数据集时,这些步骤都将自动应用于形成您的数据,这是一种真正的时间节省。*
*在这 300 多种转换中,很难选择最有用的,但是我将分享我的与 Power Query(及其强大的 M 语言)相关的 3 个技巧。您还应该[学习与电源查询无关的技巧,以促进电源 BI 开发](/5-tips-to-boost-your-power-bi-development-a44d7e782037)。*
## *提示#1 —超级查询编辑器中的省时工具*
*我需要立即说明:通过巧妙使用 Power Query Editor,您可以执行大量节省时间的操作,因此我将把我的建议缩小到我最常用的几个。*
*我敢打赌,您几乎每次为 Power BI 报告准备数据时都会遇到这种情况。您导入了一个包含许多列的宽表,并且需要删除其中的一些列。您从左向右滚动,选择要保留的列和要删除的列。*
*但是,有一种更复杂的方法可以实现这一点:*
**
*正如你在上面的插图中看到的,不需要费力的滚动,只需要打开选择列下拉菜单,选择选择列,然后选择你想要保留的列!太方便了!*
*同一个下拉菜单下的另一个提示:选择 Go To Column,您将直接导航到该列,因此您可以对该特定列执行任何类型的转换,同样也不需要浪费时间试图在广泛的“30+列表”中找到它…*
*另一个隐藏的亮点是视图选项卡下的“查询依赖项”按钮。*
**
*这在处理复杂模型时非常有用,因为数据来自多个不同的来源,或者并非所有数据都加载到报表中。*
*使用查询依赖项将使您快速直观地了解数据模型:*
**
*不用点击数据模型中的每一个实体来检查其状态,您可以在一个地方得到所有这些,更好的是,它是可视化的!*
*想象一下,数据来自 CSV 文件、SQL Server 数据库和 Sharepoint 列表,而部分数据由于某种原因甚至没有加载到报告中。这是一个 huuuuge 时间节省!*
## *技巧# 2——使用 M 语言执行频繁的计算*
*最常见的业务请求之一是计算不同事件之间的时差。例如,我想知道我的客户的年龄结构,所以我需要在每次数据刷新时计算他们的年龄。*
*或者,我需要检查客户延迟付款的天数。正如您所想的那样,这些数字需要动态计算,所以 M 语言来了!*
*让我们演示一下如何计算客户的年龄。基本上,在 Power Query 中有两种方法可以实现这一点:第一种不需要任何编码,但需要应用多个步骤。所以,我更倾向于第二种方案,当你把整个计算一步到位!*
**
*上述方法需要三个独立的步骤。首先,我们插入一个新列,并在日期下拉菜单中选择年龄选项。但是,Power Query 计算从出生日期到今天的天数。因此,我们需要将这个笨拙的数字转换为年,这是在 Duration 下拉菜单下选择 Total Years 来完成的。同样,我们得到了一个尴尬的结果,因为年龄显示为一个有多个小数位的十进制数(这是正确的,但不直观)。最后一步是向下舍入该数字,这是在舍入下执行的。*
*现在,这种方法没有任何问题,但是如果您正在进行多个计算,您的 Power Query Applied Steps 窗格将会被许多不必要的步骤所污染。*
*这就是为什么我更喜欢另一个选项:在“添加列”选项卡下,选择一个自定义列并输入以下公式:*
Number.RoundDown(Duration.TotalDays(Date.From(DateTime.LocalNow()) - [BirthDate])/365)
**
*这样,我们在一次运行中执行了先前版本的所有迭代,并且我们只应用了一个步骤!以更优雅的方式完成任务…*
## *提示#3 —自定义弹性日期维度*
*这张是我最喜欢的!首先,我想为此写一个单独的帖子,但最终,我决定把它放在这里,因为我已经写了关于正确处理日期维度的整个系列。*
*我不会花太多时间来解释拥有单独的日期维度的重要性([那是另一篇文章](/tiq-part-1-how-to-destroy-your-power-bi-model-with-auto-date-time-8fec32b22aff)的主题)——我只会简单地说:从技术上讲,Power BI 允许您在没有单独的日期维度的情况下“生存”,但不要这样做!只是不要…*
*在您的数据模型中创建单独的日期维度有[多种解决方案,但是这里我将重点介绍使用 M 语言来实现这一点。](/tiq-part-1-how-to-destroy-your-power-bi-model-with-auto-date-time-8fec32b22aff)*
*网上有很多现成的脚本来创建一个全功能的日期维度,但是我选择了来自雷扎·拉德的[这个解决方案](https://radacad.com/create-a-date-dimension-in-power-bi-in-4-steps-step-1-calendar-columns)(顺便说一下,在他的博客上你可以学到很多有用的东西)。*
*打开新的 Power BI 文件,并选择“获取数据”下的“空白查询”:*
**
*这将引导您进入超级查询编辑器。为了获得高度定制的日期维度,下一步至关重要。*
*在“管理参数”下,选择“新参数”并将其格式化,如下图所示:*
**
*这样,您就可以定义日期维度从哪一年开始。对年末做完全相同的操作:*
**
*现在我们已经定义了两个参数,我们可以切换到高级编辑器并粘贴整个 Reza 脚本来创建日期维度的特定列(当然,可以根据您的需要随意包含/排除更多的列)。*
**
*这是整个脚本:*
let
StartDate = #date(StartYear,1,1),
EndDate = #date(EndYear,12,31),
NumberOfDays = Duration.Days( EndDate - StartDate ),
Dates = List.Dates(StartDate, NumberOfDays+1, #duration(1,0,0,0)),
#"Converted to Table" = Table.FromList(Dates, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
#"Renamed Columns" = Table.RenameColumns(#"Converted to Table",{{"Column1", "FullDateAlternateKey"}}),
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns",{{"FullDateAlternateKey", type date}}),
#"Inserted Year" = Table.AddColumn(#"Changed Type", "Year", each Date.Year([FullDateAlternateKey]), type number),
#"Inserted Month" = Table.AddColumn(#"Inserted Year", "Month", each Date.Month([FullDateAlternateKey]), type number),
#"Inserted Month Name" = Table.AddColumn(#"Inserted Month", "Month Name", each Date.MonthName([FullDateAlternateKey]), type text),
#"Inserted Quarter" = Table.AddColumn(#"Inserted Month Name", "Quarter", each Date.QuarterOfYear([FullDateAlternateKey]), type number),
#"Inserted Week of Year" = Table.AddColumn(#"Inserted Quarter", "Week of Year", each Date.WeekOfYear([FullDateAlternateKey]), type number),
#"Inserted Week of Month" = Table.AddColumn(#"Inserted Week of Year", "Week of Month", each Date.WeekOfMonth([FullDateAlternateKey]), type number),
#"Inserted Day" = Table.AddColumn(#"Inserted Week of Month", "Day", each Date.Day([FullDateAlternateKey]), type number),
#"Inserted Day of Week" = Table.AddColumn(#"Inserted Day", "Day of Week", each Date.DayOfWeek([FullDateAlternateKey]), type number),
#"Inserted Day of Year" = Table.AddColumn(#"Inserted Day of Week", "Day of Year", each Date.DayOfYear([FullDateAlternateKey]), type number),
#"Inserted Day Name" = Table.AddColumn(#"Inserted Day of Year", "Day Name", each Date.DayOfWeekName([FullDateAlternateKey]), type text)
in
#"Inserted Day Name"
*点击 Close & Apply,现在我们的数据模型中就有了全功能的日期维度!*
**
*我们可以通过管理参数和切换年份值来轻松改变时间框架。*
*现在蛋糕上有冰块,作为额外的提示:把你的文件保存为。pbit (Power BI 模板文件)。这样,当您开始 Power BI 项目时,您不需要从头开始创建日期维度,浪费您的时间和精力—它已经为您准备好了!*
**
*你还要吗?就在那里。打开模板文件后,系统会提示您输入起始年和结束年的值,这意味着您可以自定义报告之间的时间范围!多酷啊!*
**
*一旦您输入值,Power BI 将根据您定义的值自动为您创建日期维度!*
**
## *结论*
*当涉及到数据检索,尤其是数据转换时,Power Query 提供了一系列的特性。描述它们需要一两本书,所以我想摘录其中几个,我认为它们在我日常使用 Power BI 的工作中最有用。*
*你最喜欢的电量查询功能有哪些?欢迎在评论区分享它们。*
*[成为会员,阅读媒体上的每一个故事!](https://datamozart.medium.com/membership)*
*订阅[这里](http://eepurl.com/gOH8iP)获取更多有见地的数据文章!*
# 用人工智能增强 Windows 应用:用 Python 模型连接 C#应用
> 原文:<https://towardsdatascience.com/power-your-windows-app-with-ai-connect-c-application-with-python-model-c5f100ebc1fc?source=collection_archive---------13----------------------->
## 软件体系结构
## Windows 窗体界面与人工智能管道的共生

马里乌斯·马萨拉尔在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
这里不再介绍:
a)我们可能总是在控制台中运行我们的 ML 模型或神经网络管道;
b)我们没有理由不能在 Windows 上运行它,并添加一些点击按钮。
不过,这里我们面临一个问题。我们可以轻松地开发一些 Python 模型或 C# Windows 窗体应用程序。但在人工智能驱动的应用程序开发过程中,它们的连接可能是一个真正的痛苦。这就是为什么这篇文章关注项目的 C#和 Python 部分之间的中间通信的解决方案。
对于该项目,我们将使用来自 Kaggle 的 [loan lending club 数据集](https://www.kaggle.com/wendykan/lending-club-loan-data)。
## 1.假设我们已经有了一个很酷的模型
Loan lending club 数据集肯定是众所周知的数据积累,所以我们将跳过数据集准备、清理、特性选择、分析和其他工作人员的代码(因为这不是本文的主题)。如果你愿意,可以在我的 GitHub 上的例子[中查看。让我们用 Keras 库创建一个非常简单的神经网络,并训练它具有或多或少合适的精度:](https://github.com/Midvel/WindowsToPythonAI/blob/master/model_dataset_preperation/save-lending-club-model.ipynb)
因此,我们有最终准确率为 70%的 4 层神经网络。确实不是最好的,但对我们的目的来说已经足够了。顺便说一下,我们还从 sk-learn 创建了标签编码器和定标器的转储。我们使用了一个非常方便的 [**泡菜**模块](https://docs.python.org/3/library/pickle.html):
from pickle import dump
dump(scaler, open(‘scaler.pkl’, ‘wb’))
dump(grade_encoder, open(‘grade_encoder.pkl’, ‘wb’))
dump(ownership_encoder, open('ownership_encoder.pkl', 'wb'))
dump(purpose_encoder, open('purpose_encoder.pkl', 'wb'))
现在我们的任务是:
* 编写模型加载和预测的代码;
* 将这段代码包装在一个简单的类中;
* 添加接收 json 格式的输入参数的代码;
* 添加以 JSON 格式返回输出的代码。
所以,第一步是我们需要模型的目的,第二步只是为了方便。但是最后两个是我们的应用程序到模型连接的中间阶段:JSON 是在解决方案的不同层之间进行交换的一种非常方便的格式。嗯,空谈是廉价的,下面是我们的课:
## 2.添加一些按钮
Windows 窗体的 C#开发的好处是界面创建的速度:拖放一些元素,填充一些回调,检查编辑框是否被正确验证,瞧——原始应用程序已经准备好了。真的没有理由展示所有代码——它是 Visual Studio 2019 中的一个标准 Windows 窗体项目。不过,你可以在我的 GitHub 里查看[。看起来是这样的:](https://github.com/Midvel/WindowsToPythonAI/tree/master/LoanApp)

没什么特别的,但是我们可以输入上一步的神经网络的输入参数,然后得到结果。棘手的部分来了。
## 3.如何将信息传入 Python 脚本?
因此,我们需要一个 C#到 Python 通信的中间层解决方案。它由两部分组成:`PythonCaller`应用程序中的类和 Python 聚合器脚本。正如我们从名称中看到的,C#类收集应该传递给模型的参数,获取模型名称和位置,并将所有这些信息传递给调用聚合器脚本。聚合器脚本处理与模型相关的所有作业。
先说 C#部分。
正如我们所说的,所有的信息交换都是以 json 格式进行的。这就是为什么我们需要做的第一件事是连接 [Newtonsoft JSON 解析器](https://www.newtonsoft.com/json)库。它是免费的,可以很容易地通过市场添加到 Visual Studio 中。下载后将其包含到项目中:
using Newtonsoft.Json;
在备课之前,我们要想好从类内部的 GUI 部分传递输入参数的方式。因为我们决定将参数打包到 JSON 对象中,所以我们将准备参数容器类。你可能知道我对容器设计充满热情,所以你可以查看我关于构造它们的文章。
所以,回到容器:这是一个简单的字典包装,它收集参数并可以将它们作为包含一些元信息的 JSON 对象返回。当然,它会被传入调用者类本身。
现在是主要部分。首先,`PythonCaller`类的每个实例都将连接到具体的模型脚本。其次,它将使用`ProcessStartInfo`对象通过 Python 解释器调用聚合器脚本。之前创建的带有输入参数的 JSON 对象将作为聚合器脚本的参数。实现很简单:
* 创建一个连接到具体模型类的对象:
* 将对所选模型的类方法的调用(当然,准备了`PythonCallerArgs`容器)转移到聚合器脚本:
您可能会注意到,我们已经控制了脚本调用的输入输出流。这是我们从脚本中获得结果的方式。
仅此而已,解决方案真的很简单。稍后我们将把这个类集成到应用程序中。
## 4.脚本之间的对话
解决方案的最后一部分是呼叫聚合器本身。它被表示为 Python 脚本,该脚本从 Windows 应用程序获取所有 JSON 打包的信息,并联系所需的 AI 模型脚本。
实现很简单——从 Windows 应用程序中获取参数,并通过特定的方法调用将它们传递给模型。这里有两个技巧性的地方。第一个是将模型的类导入到脚本中,这样我们就可以访问所需的方法。我们将使用 [importlib 包](https://docs.python.org/3/library/importlib.html)来实现这些目的:它可以通过代码路径导入模块。
第二个技巧是将调用的结果返回给应用程序。但是,正如您所记得的,我们强迫`ProcessStartInfo`对象获得对标准输出的控制。这就是为什么我们只是在脚本的最后一行将结果打印到流中。
## 5.使其工作
最后一步是将设计的类集成到我们的应用程序中:
现在我们可以检查整个应用程序,并从人工智能模块获得结果

是的,这个解决方案并不完美,但一旦调整,它将把人工智能的力量连接到你的应用程序。这就是为什么你可以提出自己的工作替代方案。和往常一样,您可以在我的 GitHub 存储库中找到完整的工作示例:
[](https://github.com/Midvel/WindowsToPythonAI) [## Midvel/WindowsToPythonAI
### C#和 Python 项目的连接。WindowsForms 应用和 Python AI 模型共生的例子。二手贷款…
github.com](https://github.com/Midvel/WindowsToPythonAI)
# PowerBI 与 R Shiny:两种流行的 Excel 替代品的比较
> 原文:<https://towardsdatascience.com/powerbi-vs-r-shiny-two-popular-excel-alternatives-compared-b58d4ba1e0d1?source=collection_archive---------8----------------------->
## R Shiny 和 PowerBI 之类的拖拽可视化工具相比如何?

在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上由 [Carlos Muza](https://unsplash.com/@kmuza?utm_source=medium&utm_medium=referral) 拍摄的照片
选择合适的 dashboard/reporting/BI 工具从未像现在这样困难,因为有许多真正伟大的选项,如 R Shiny、PowerBI 和 Tableau。今天,我们将比较财富 500 强公司广泛使用的两种工具:
* power bi——一个软件服务、应用和连接器的集合,它们协同工作,将不相关的来源转化为连贯的、视觉上身临其境的交互式见解(*来源:* [*微软*](https://docs.microsoft.com/en-us/power-bi/fundamentals/power-bi-overview) )
* R Shiny——用 R 编写的 web 框架,广泛用于制作仪表板和交互式 web 应用程序
*有一点要记住:* R Shiny 不是一个报告/仪表板工具。相反,它是一个完整的 web 框架。由于大多数人使用它来制作仪表板,并且我们的许多客户在投资分析解决方案时会将 R Shiny 与 PowerBI 进行比较,我们可以认为这种比较是公平的。我们将从 PowerBI 的基本概述开始,然后在各个方面比较这两个工具,例如:
* 连通性
* 图表类型
* 易用性:简单的图表
* 易用性:简单的仪表盘
* 用户输入和交互性
* 视觉造型
* 结论
# PowerBI 概述
如前所述,PowerBI 用于可视化地表示来自各种数据源的交互式见解。它是一个完美的报告工具,这是一个只读操作,相对容易构建和维护。
PowerBI 也是最容易上手的工具之一,因为只需几门速成课程就能让你迅速上手。我们并不是说 R 很难学,但是拖放式 GUI 界面被认为比 R 更容易学,至少对商业人士来说是这样。
但这里有一个最重要的卖点— **PowerBI 开箱后看起来很好**。使用 PowerBI,您不必成为专家也能制作出好看的可视化效果。Shiny 需要更多的体力劳动来生产漂亮的仪表板。手工工作不一定不好,因为如果你愿意付出努力,你可以做的事情没有限制,但是简单的拖放工具在大多数时候已经足够了。
每个职业都有缺点,PowerBI 也不例外。PowerBI 最大的缺点之一是它是只读的。作为用户,不能使用图表/表格进行决策,直接保存在数据库中。
此外,PowerBI 没有可访问的源代码。您只能在 WYSIWYG 模式下编辑字段,这使得 PowerBI 易于启动,但难以维护。没有源代码,几乎不可能有适当的版本控制、自动测试逻辑或在大型项目上合作。
PowerBI 有几种不同的风格,如下所示:
* *PowerBI Desktop* —您可以下载并安装在电脑上的应用程序。仅适用于**的**窗口。它具有强大的数据分析能力,可以连接许多数据源。它用于执行分析、创建可视化和创建报告。
* *PowerBI Service (Pro)* — web 应用。它用于创建可视化和报告。最大的卖点是仪表盘——而且很容易制作。此外,由于协作模式,共享结果更加容易。
* *power bi Mobile*—Android 和 iOS 的移动应用。它仅用于从任何地方访问您的数据,而不是执行分析。
我们今天的大部分注意力将集中在 PowerBI 桌面版本上。
# 连通性
PowerBI 附带了许多内置的连接类型,分为*文件*、*数据库*、 *Power 平台*、 *Azure* 和*在线服务*,毫无疑问,它比我们的最后一个竞争者——Tableau 更加通用。截至 2020 年末,您会发现以下连接选项:

作者图片
简而言之,PowerBI 在连接性方面并不欠缺。在等式的另一边,R Shiny 使用 R 作为编程语言的选择,所以 Shiny 可以连接到 R 可以连接的任何源。
一个简单的 Google 搜索将会产生一个预制的库或者任何数据源类型的 API 调用示例。R Shiny 有时对特定领域的源有优势。尽管如此,我们还是发现了多个 PowerBI 处理特定领域数据源的例子,比如 [CAD 文件](https://www.bimservices.it/power-bi-integration-with-bim/)。
**胜者(连通性):平局**
# 图表类型
PowerBI 提供了基本的可视化选项——条形图、折线图、面积图、散点图和饼图,以及一些更好的类型,如地图、树状图、漏斗图和带状图。完整列表请参考下图:

作者图片
尽管如此,对于大多数用例来说,这可能已经足够了,因为更复杂的统计图表不会经常出现在生产仪表板中。此外,你可能已经注意到这些“R”和“Py”图标。这意味着您可以在 PowerBI 中使用 R 和 Python 图表,只有一点需要注意——这些图表的源代码不受版本控制。
在 R Shiny 中,您可以使用 R 中可用的任何可视化库,比如`ggplot2`和`plotly`。以下是您可以通过这两种方式实现的可视化类型的概述:

*GGplot2 选项;来源:【https://www.r-graph-gallery.com】[](https://www.r-graph-gallery.com)*
**
**Plotly 选项;来源:*[*https://plotly.com/r/*](https://plotly.com/r/)*
*在这个部门宣布获胜者是显而易见的。当然,Shiny 可以做很多事情,但是 PowerBI 可以做所有的事情,甚至更多。PowerBI 可以处理自己的图表和 Python 生成的图表。*
***赢家(图表类型):PowerBI***
# *易用性:简单的图表*
*现在,我们将尝试在 PowerBI 和 Shiny 中重新创建相同的可视化。出于演示的目的,我们将使用 [Gapminder 数据集](https://appsilon.com/wp-content/uploads/2020/10/gapminder.csv),因此如果您正在跟进,请确保下载它。目标是创建一个简单的折线图,比较各大洲的平均预期寿命。*
*先说 PowerBI。我们通过以下步骤导入了数据集并创建了可视化:*
**
*作者图片*
*PowerBI 旨在方便各种背景的人使用,使这个简单的图表易于实现。*
*在 R Shiny 中复制同样的东西是一个完全不同的故事,因为我们需要编写实际的代码。数据集可以通过`gapminder`包在 R 中获得,所以不需要下载和导入提供的 CSV。Shiny 引入了一些样板代码——这对于这个简单的图表来说是一个明显的缺点,但是对于更大的真实项目来说可以忽略不计。*
*代码如下:*
*结果如下:*
**
*作者图片*
*总之,使用 R Shiny 来生成单图表和非交互式仪表板是没有意义的。这是 PowerBI 占优势的领域之一,因为它使用起来简单直观。此外,R 中的图表需要一点定制,以看起来体面和可解释,这是 PowerBI 自带的。*
***赢家(简单图表):PowerBI***
# *易用性:简单的仪表盘*
*在 PowerBI 中制作一个简单的仪表板很容易——在这里和那里点击几下,几个过滤器,我们就可以开始了。目标是显示三个图表:*
* *一段时间内的平均预期寿命-折线图*
* *各大洲总人口—仅在最近一年(2007 年),以条形图表示*
* *预期寿命与人均国内生产总值——简单散点图,按大陆着色*
*然后,可以通过选择一个或多个洲来过滤整个仪表板。以下是我们在 PowerBI 中成功创建的内容:*
**
*作者图片*
*为了在 R Shiny 中实现大致相同的仪表板,我们需要编写一些 R 代码。再说一次,R 是一种相对容易学习的语言,所以我们不认为它对更精通技术的用户来说是个问题。*
*以下代码重新创建了我们在 PowerBI 中拥有的仪表板:*
*这是仪表盘的样子:*
**
*作者图片*
*我们稍后会处理视觉外观,所以不要太担心这个。在这里很难宣布一个明确的赢家,但 R Shiny 的仪表板感觉更坚实。*
*正如我们所看到的,使用 PowerBI 可以更快地制作一个简单的仪表板。出于这个原因,我们将宣布 PowerBI 是简单仪表板的赢家,但仅仅是为了易用性。如果你需要一个复杂的仪表板,R Shiny 就更通用了。*
***获胜者(简单仪表板):以微弱优势领先的 power bi***
# *用户输入和交互性*
*如概述部分所述,PowerBI 是只读的。当然,您可以点击各种过滤器来从图表中包含/排除一些数据,但这几乎是您所能做的全部。我们认为输入在创建交互式仪表板中是必不可少的,所以像 Shiny 这样的完整 web 框架消灭了它在这个部门的对手。*
*Shiny 有大量的输入——从文本字段和按钮到下拉菜单和模态。以下是 Shiny 提供的一切:*
**
*作者图片*
*有了所有这些选择,如果安排得当,对 Shiny 来说没有什么任务是难以解决的。如果你仍然不相信交互性的重要性,这里有几点会让你重新考虑:*
* **文件输入*组件允许我们上传自定义数据集并在浏览器中执行探索*
* **文本输入*和*密码输入*字段允许我们构建完整的 web 表单——想想认证*
* **变量选择输入*允许我们从数据集中快速选择感兴趣的列*
***赢家(用户输入和互动):R 闪亮***
# *视觉造型*
*在 PowerBI 甚至 Tableau 这样的拖放工具中调整视觉效果从来都不是他们的强项。默认情况下,这些工具设计得很好看。尽管如此,并不是每个人都同意什么是好的,所以有选择是好事。*
*我们发现你可以在 PowerBI 中调整很多东西。这里有一个粗略的概述:*
**
*作者图片*
*有了 R Shiny,故事就大不一样了。你可以通过创建一个`www`文件夹来嵌入定制的 CSS 样式。CSS 文件然后被存储在提到的文件夹中。*
*要连接两者,你必须将`theme = main.css`放入闪亮应用的`fluidPage`中。仅此而已。在使用 CSS 的短短几分钟内,我们已经成功地对我们的仪表板进行了一些改造:*
**
*作者图片*
*这里是完成的仪表板的源代码。这场战斗的赢家是显而易见的,再一次。当然,PowerBI 开箱后看起来很好,但你无法让它看起来完美。R Shiny 在视觉造型方面非常通用(在合适的开发人员手中)。*
***获胜者(视觉造型):R 闪亮***
# *结论*
*最终结果如下:*
* *PowerBI — 3 分*
* *r 闪亮— 2 分*
* *平局— 1 分*
*根据我们的统计,对于大多数一般用例,PowerBI 领先一个百分点。当然,选择合适的工具并不像数到 5 那么简单,所以需要进一步的澄清。当您需要相对简单的东西,并且不太担心仪表板的外观和整体感觉时,PowerBI 是非常好的。*
*对于任何更复杂的东西,R Shiny 推翻了 PowerBI。PowerBI 无法与 Shiny 提供的可定制性相比,尤其是当您需要创建企业应用程序时。*
**喜欢这篇文章吗?成为* [*中等会员*](https://medium.com/@radecicdario/membership) *继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。**
*[](https://medium.com/@radecicdario/membership) [## 通过我的推荐链接加入 Medium-Dario rade ci
### 作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)*
**原载于 2020 年 10 月 29 日 https://appsilon.com*[](https://appsilon.com/powerbi-vs-r-shiny/)**。***
# 使用 Sweetviz,仅两行代码即可实现强大的 EDA(探索性数据分析)
> 原文:<https://towardsdatascience.com/powerful-eda-exploratory-data-analysis-in-just-two-lines-of-code-using-sweetviz-6c943d32f34?source=collection_archive---------1----------------------->
## 借助这个新的 Python 库,更快地了解您的数据

仅用两行代码创建的 Sweetviz 报告
【2021 年 1 月更新:Sweetviz 现在支持笔记本集成(您可以内嵌插入报告)和新功能!
探索性数据分析(EDA)是大多数数据科学项目中必不可少的早期步骤,它通常包括采取相同的步骤来表征数据集(例如,找出数据类型、缺失信息、值的分布、相关性等)。).考虑到这些任务的重复性和相似性,有一些库可以自动化并帮助启动这个过程。
最新的一个是一个新的开源 Python 库,名为 Sweetviz ( [GitHub](https://github.com/fbdesignpro/sweetviz) ),是由一些贡献者和我自己为此目的创建的。它获取 pandas 数据帧并创建一个自包含的 HTML 报告。
**它具有强大的冲击力;**除了只用两行代码就能创建深刻而美丽的可视化效果,它还提供了手动生成需要更多时间的分析,包括其他库无法如此快速提供的分析,例如:
* **两个数据集的比较**(例如训练与测试)
* **目标值**相对于所有其他变量的可视化(例如,“男性与女性的存活率是多少”等)。)
[此处链接到 Sweetviz 为著名的样本泰坦尼克号幸存者数据集](http://cooltiming.com/SWEETVIZ_REPORT.html)生成的报告。我们将在本文中分析这份报告。
# 埃达制造了…乐趣?!
能够如此快速地获得关于目标值的如此多的信息,并比较数据集的不同区域,几乎可以立即将这一最初步骤从枯燥乏味转变为更快、更有趣,甚至在某种程度上…更有趣!(对这个数据怪胎来说,至少!)当然,EDA 是一个漫长得多的过程,但至少第一步要顺利得多。让我们看看它如何与众所周知的样本数据集一起工作。
# 分析泰坦尼克号数据集
在这篇文章中,我们将分析样本泰坦尼克号幸存者数据集,你可以在这里找到。
安装 Sweetviz(使用`pip install sweetviz`)后,只需像平常一样加载熊猫数据帧,然后根据需要调用`analyze()`、`compare()`或`compare_intra()`(更多内容见下文)。完整的文档可以在 [GitHub](https://github.com/fbdesignpro/sweetviz) 上找到。现在,让我们从手头的案例开始,按如下方式加载:
import sweetviz
import pandas as pd
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
我们现在有 2 个数据框架(训练和测试),我们想分析目标值“存活”。我想指出的是,在这种情况下,我们预先知道目标列的名称,但是指定目标列总是可选的。我们可以用这行代码生成一个报告:
my_report = sweetviz.compare([train, "Train"], [test, "Test"], "Survived")
运行此命令将执行分析并创建报告对象。要获得输出,只需使用`show_html()`命令:
my_report.show_html("Report.html") # Not providing a filename will default to SWEETVIZ_REPORT.html
生成文件后,它将通过您的默认浏览器打开它,看起来应该是这样的:

要解开的东西很多,还是一步一步来吧!
# 汇总显示

摘要向我们并排显示了两个数据帧的特征。我们可以立即识别出测试集的大小大约是训练集的一半,但是它包含相同的特性。底部的图例向我们展示了训练集确实包含“幸存”的目标变量,但是测试集不包含。
请注意,Sweetviz 将在确定每列的数据类型时做出最佳猜测,介于数字、类别/布尔和文本之间。这些可以被覆盖,下面会详细介绍。
# 联合
将鼠标悬停在摘要中的“Associations”按钮上,关联图将出现在右侧:

这张图是由来自[Drazen Zaric:Python 中更好的热图和相关矩阵图](/better-heatmaps-and-correlation-matrix-plots-in-python-41445d0f2bec)的视觉效果和来自 [Shaked Zychlinski:分类相关性搜索](/the-search-for-categorical-correlation-a1cf7f1888c9)的概念合成的。
基本上,除了显示传统的数值相关性之外,它还将数值相关性以及不确定性系数(分类-分类)和相关比率(分类-数值)统一在一个图表中。正方形代表分类特征相关变量,圆圈代表数值-数值相关性。注意,为了清楚起见,平凡的对角线是空的。
*重要提示:分类-分类关联(由不确定系数提供)是不对称的,这意味着每一行代表行标题(在左边)给出了每一列的多少信息。比如“性”、“Pclass”、“Fare”是给出“幸存”信息最多的元素。对于 Titanic 数据集,这些信息是相当对称的,但情况并非总是如此。*
最后,值得注意的是,这些相关/关联方法不应该被视为真理,因为它们对数据和关系的底层分布做出了一些假设。然而,它们可能是一个非常有用的起点。
# 目标变量

当一个目标变量被指定时,它会首先出现在一个特殊的黑框中。
**重要提示:目前只有数字和布尔特征可以作为目标。**
我们可以从这个总结中推断出,“幸存”在训练集中没有缺失数据(891,100%),有 2 个不同的可能值(占所有值的不到 1%),并且从图中可以估计出大约 60%没有幸存。
# 详细区域(分类/布尔型)
当您移动鼠标悬停在任何变量上时,右侧的区域将显示详细信息。细节的内容取决于被分析变量的类型。在分类(或布尔)变量的情况下,与目标的情况一样,分析如下:

*重要提示:此时需要一个“宽屏”显示器来看到整个细节区域。*
在这里,我们可以看到每个班级的准确统计数据,其中 62%没有幸存,38%幸存。您还可以获得每个其他特性的关联细节。
# 数据

数字数据在其摘要中显示了更多信息。在这里,我们可以看到,在这种情况下大约有 20%的数据丢失(测试数据中有 21%,这是非常一致的)。
**注意,目标值(在本例中为“幸存”)绘制成一条线,位于分布图的正上方。这使得能够针对其他变量对目标分布进行即时分析。**
有趣的是,我们可以从右边的图表中看到,除了年龄最小的存活率较高之外,所有年龄段的存活率都相当一致。看起来“妇女和儿童优先”不只是说说而已。
# 详细区域(数字)

与分类数据类型一样,数值数据类型在其细节区域显示一些额外的信息。值得注意的是图表顶部的按钮。这些按钮改变图表中显示的“箱子”数量。您可以选择以下选项:
* 汽车
* 5
* 15
* 30
**注:要使用这些按钮,您需要通过点击来“锁定”当前功能。然后,该特征会有一个红色轮廓,表示它已锁定到位,您可以访问详细信息区域。**
例如,选择“30”会生成一个更加精细的图表:

# 文本数据

目前,系统不认为是数字或分类的任何内容都将被视为“文本”。文本功能目前仅将计数(百分比)显示为统计数据。
# FeatureConfig:强制数据类型,跳过列
在许多情况下,您可能不想分析“标签”列(尽管目标分析可以基于标签提供关于目标值分布的见解)。在其他情况下,您可能希望强制将一些值标记为分类值,即使它们实际上是数值。
要做到这一切,只需创建一个 FeatureConfig 对象并将其传递给分析/比较函数。您可以为 kwargs `skip`、`force_cat`和`force_text`指定一个字符串或一个列表:
feature_config = sweetviz.FeatureConfig(skip="PassengerId", force_cat=["Ticket"])my_report = sweetviz.compare([train, "Train"], [test, "Test"], "Survived", feature_config)
# 比较亚人群(例如男性和女性)
即使您只查看单个数据集,研究该数据集中不同亚群的特征也会非常有用。为此,Sweetviz 提供了`compare_intra()`函数。要使用它,你需要提供一个布尔测试来分割人群(这里我们尝试`train["Sex"] == 'male'`,来了解不同性别的人群),并给每个子人群起一个名字。例如:
my_report = sweetviz.compare_intra(train, train["Sex"] == 'male', ["Male", "Female"], 'Survived')my_report.show_html() # Not providing a filename will default to SWEETVIZ_REPORT.html
产生以下分析:(对于这个截图,我使用 feature_config 来跳过对“Sex”特性的分析,因为它是多余的)

**注意,目标值(本例中为“存活”)现在绘制为单独的线条,每个对比数据集一条(例如,蓝色为男性,橙色为女性)。**
# 把所有的放在一起
EDA 是一个流动的、艺术化的过程,必须针对每一组数据和情况进行独特的调整。然而,像 Sweetviz 这样的工具可以帮助启动这一过程,并消除表征数据集的许多初始细节,从而立即提供见解。让我们浏览一下泰坦尼克号数据集的所有特征,看看它会是什么样子。
## 单个字段
**乘客 Id**

* ID 和生存能力的分布是均匀有序的,正如你所希望的那样,所以这并不奇怪。
* 没有丢失数据
**性**

* 男性大约是女性的两倍,但是…
* 女性比男性更有可能存活
* 从相关性来看,性别与票价相关,这并不奇怪…
* 训练和测试之间的相似分布
* 没有丢失数据
**年龄**

* 20%的缺失数据、一致的缺失数据以及培训和测试之间的分布
* 以年轻人为中心的人口,但 0-70 岁的人口比例较高
* 出人意料的均匀分布的生存能力,除了在最年轻的年龄峰值
* 使用详细信息窗口直方图中的 30 个柱,您可以看到这个生存性峰值实际上是针对最小的(大约< = 5 岁),因为在大约 10 岁时,生存性非常低。
* 年龄似乎与兄弟姐妹、阶级和费用有关,更令人惊讶的是与上船有关
**名称**

* 没有丢失数据,数据看起来很干净
* 所有的名字都不同,这并不奇怪
**Pclass**

* 生存能力紧随职业之后(第一职业最有可能生存,第三职业最不可能)
* 训练和测试之间的相似分布
* 没有丢失数据
**SibSp**

* 在 1 处似乎有一个生存峰值,在某种程度上在 2 处也有,但是(查看这里没有显示的细节窗格)在 3 处和更大处有一个急剧下降。大家庭做不到或者更穷?
* 训练和测试之间的相似分布
* 没有丢失数据
**炒制**

* 训练和测试之间的相似分布
* 没有丢失数据
**票**
* 约 80%的不同值,因此平均约有五分之一的共享票证
* 最高频率的票是 7,这与兄弟姐妹的最大数量(8)基本一致
* 没有丢失数据,数据看起来很干净
**票价**

* 正如预期的那样,与 Pclass 一样,较高的票价更好地保留了下来(尽管样本量在较高的水平变得相当少)
* “存活”的相关比率为 0.26,相对较高,因此倾向于支持这一理论
* 大约 30%的不同值感觉有点高,因为你会期望更少的设定价格,但看起来有很多粒度,所以这没问题
* 测试集中只有 1 条记录缺失,训练和测试之间的数据相当一致
**机舱**

* 大量缺失数据(高达 78%),但是在训练和测试之间是一致的
* 最大频率为 4,这意味着一个客舱最多容纳 4 人
**上船**

* 3 个不同的值(S,C,Q)
* 列车数据中只有 2 行缺失。训练和测试之间的数据似乎相当一致
* C 时的生存能力稍高一些;这里会是富人聚集的地方吗?
* 无论哪种方式,“已上船”显示“幸存”的不确定系数仅为 0.03,因此可能不太显著
## 一般分析
* 总的来说,大部分数据是存在的,似乎是一致的,有意义的;没有重大异常或巨大的惊喜
**测试对比训练数据**
* 测试的行数减少了大约 50%
* 训练和测试在缺失数据的分布上非常接近
* 训练和测试数据值在所有方面都非常一致
**关联/相关性分析**
* 性别、费用和阶级提供了关于幸存者的最多信息
* 不出所料,Fare 和 Pclass 高度相关
* 年龄似乎告诉了我们很多关于阶级、兄弟姐妹和某种程度上的费用的信息,这在某种程度上是意料之中的。它似乎告诉了我们很多关于“上船”的事情,这有点令人惊讶。
**缺失数据**
* 除了年龄(~20%)和客舱(~77%)之外,没有重要的缺失数据(在其他特征上也有一些奇怪的数据)
# 结论
所有这些信息都来自两行代码!
当我开始查看一个新数据集时,使用 Sweetviz 很容易给我一个重要的启动。值得指出的是,我还发现在分析过程的后期,例如在特性生成期间,快速了解新特性是如何发挥作用的。我希望你会发现它在你自己的数据分析中是一个有用的工具。
# 增强探索性数据分析性能的强大软件包
> 原文:<https://towardsdatascience.com/powerful-packages-to-boost-your-exploratory-data-analysis-performance-bb0db4744530?source=collection_archive---------39----------------------->
## 熊猫简介,Sweetviz,数据浏览器

SpaceX 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的
数据探索或探索性数据分析(EDA)是进行数据科学项目的一个重要阶段。这一步的目标是通过数据获得有价值的见解,以便人们可以知道数据发生了什么,需要清理哪个部分,可以构建哪些新功能,在模型创建/验证阶段构建要测试的假设,甚至只是知道一些关于数据的有趣事实。
> *“一张高质量的图表抵得上一千条真知”*
等等,什么是高质量的图表??是超高清画质的图表吗??—我所说的高质量图表是指从特定变量或 2 个或更多变量之间的相互作用中捕捉有趣故事的图表。问题是:
> 一个人怎么能制作出那种“超级”图表呢??
制作该图表听起来很难…即使已经制作了该图表,也会产生其他问题:
> 这张图表提供了足够的见解吗?有没有其他种类的图表提供完全不同的见解?我们必须生成图表才能从数据中获得洞察力吗?
在本文中,我将介绍 3 个非常棒的免费软件包,它们可以生成包含各种 EDA 的 HTML 报告,只需几行 Python 代码!
我将试着把重点放在每个包所提供的最佳特性上,以及它们是如何相互补充的。这里使用了 [Titanic 数据集](https://www.openml.org/d/40945)来做比较。
> 你可以在这里找到本文中使用的所有代码。
# 熊猫简介
> 这个软件包的主要卖点是在一个 HTML 报告中提供了广泛的分析和深入的单变量分析!
生成的报告有 5 个部分:**概述**,**变量**,**交互**,**相关性**,**缺失值**,**样本**

熊猫概况报告部分
生成报告的第一部分是**概述**部分。该部分有 3 个标签:*概述*、*再现*、*警告*。
*概述* —该选项卡提供数据的概述,包括变量数量、样本数量、缺失单元格、重复行、内存总大小、内存平均记录大小,以及基于类型的变量分布。

熊猫概况选项卡
*再现* —该选项卡提供了该软件包如何执行分析和生成报告的详细信息。

熊猫轮廓再现标签
*警告* —如果数据中的每个变量有错误或需要处理,该选项卡提供非常有用的信息。人们可以很容易地首先看到这个选项卡,对数据进行数据清理或一些特征工程。

熊猫概况警告选项卡
神奇的事情发生在第二节:**变量**。根据变量类型,可以看到对每个变量的深入单变量分析,范围从数值分析、Unicode 分析、URL 分析,甚至是图像分析。

熊猫概况单变量数值分析示例

Pandas 评测单变量 Unicode 分析示例
在我看来,熊猫概况报告中的**互动**部分并不真正有见地。因此,我们将进入下一部分:**相关性。**本节提供了 5 种不同方法的相关性分析!其中一种方法可以计算分类变量、顺序变量和区间变量之间的相关性。

熊猫概况相关分析,可以计算不同类型的变量之间的相关性
同样,在我看来,**缺失值**部分并不真正有见地,因为该信息已经在**变量**部分中提供了。最后,熊猫概况报告的最后一部分是**样本**部分。这一部分提供了数据的前 10 行和后 10 行,这对于了解数据的真实情况非常有用。

熊猫概况样本部分
> 一份很有见地的报告,对吧?好消息是,只需 10 行代码就可以轻松生成这份熊猫概况 HTML 报告!
# Sweetviz
> 这个包的主要卖点是目标分析,训练和测试集的比较,以及一个非常酷的用户界面,所有这些都在一个 HTML 报告中!

Sweetviz HTML 报告
Sweetviz 是一个新发布的包(2020 年 5 月),它提供了一个非常优雅的 HTML 报告。与 Pandas Profiling 不同的是,这个包生成的 HTML 报告不是按节划分的。在报告的顶部,可以看到列车和测试装置的**对比总结。为了更深入地比较训练集和测试集,以及强大的**目标分析,**用户可以浏览每个变量“卡”。**

Sweetviz 卡
在每张卡片上,人们还可以看到特定变量和其余变量之间的分类和数字关联。令人兴奋的是这个包可以处理不止一种类型的变量。例如,' *boat* '变量在分类关联表和数字关联表中被赋值。
> 又一份很酷的报告,对吧?即使现在只有 3 行代码,也可以很容易地生成这个 HTML 报告。
# 数据浏览器
> 这个软件包的主要卖点是在一个 HTML 报告中的目标分析和主成分分析!
供您参考,DataExplorer 是一个 R 包。然而,在 RPy2 的帮助下,人们可以很容易地使用 Python 中的任何 R 包。如果你对这个更感兴趣,你可以查看这个[奇库](https://github.com/louisowen6/RPy2)。

数据资源管理器 HTML 报表
与 Pandas Profiling 相同,使用这个包生成的报告也分为几个部分。在我看来,人们可以从这份报告中利用的最有用的特征是**主成分分析**和**双变量分布**部分。

DataExplorer PCA 分析

DataExplorer 二元分布分析示例
> 因为这是一个在 Python 中使用的 R 包,所以需要更多行代码来生成这个报告。
# 摘要
综上所述,在我看来,应该考虑使用所有这 3 个强大的软件包来提高 EDA 在时间效率和分析质量方面的性能。这些产品包各有千秋:
1. **Pandas Profiling** —分析的广度和单变量分析的深度。
2. **Sweetviz** —目标分析、训练和测试集的比较,以及非常酷的用户界面。
3. **DataExplorer** —目标分析和主成分分析。
真正重要的是:**所有的报告都可以很容易地生成,只需要几行代码!**
# 额外片段
以下是熊猫概况报告中图像和 URL 分析生成的片段。

熊猫轮廓图像分析

熊猫概况 URL 分析
# 关于作者
Louis Owen 是一名数据科学爱好者,他总是渴望获得新知识。他在印度尼西亚顶尖大学[*Institut Teknologi Bandung*](https://www.itb.ac.id/)攻读数学专业,并获得了最后一年的全额奖学金。
Louis 曾在多个行业领域担任分析/机器学习实习生,包括 OTA([](https://www.linkedin.com/company/traveloka-com/)*)、电子商务( [*Tokopedia*](https://www.linkedin.com/company/pt--tokopedia/) )、FinTech ( [*Do-it*](https://www.linkedin.com/company/doitglotech/) )、智慧城市 App ( [*Qlue 智慧城市*](https://www.linkedin.com/company/qluesmartcity/) ),目前在 [*世界银行*](https://www.linkedin.com/company/the-world-bank/) 担任数据科学顾问。*
*去路易斯的网站了解更多关于他的信息吧!最后,如果您有任何疑问或需要讨论的话题,请通过 LinkedIn 联系 Louis。*
# *参考*
*[](https://pandas-profiling.github.io/pandas-profiling/docs/master/rtd/) [## 简介-熊猫-剖析 2.8.0 文档
### 从熊猫生成档案报告。熊猫的 df.describe()函数很棒,但是对于严肃的……
pandas-profiling.github.io](https://pandas-profiling.github.io/pandas-profiling/docs/master/rtd/) [](https://github.com/fbdesignpro/sweetviz) [## fbdesignpro/sweetviz
### Sweetviz 是一个开源 Python 库,可以为 kickstart EDA 生成漂亮的高密度可视化效果…
github.com](https://github.com/fbdesignpro/sweetviz) [## DataExplorer 简介
### 这个文档介绍了 DataExplorer 包,并展示了它如何帮助你完成不同的任务…
cran.r-project.org](https://cran.r-project.org/web/packages/DataExplorer/vignettes/dataexplorer-intro.html)*
# 强大的终极二分搜索法模板和许多 LeetCode 问题
> 原文:<https://towardsdatascience.com/powerful-ultimate-binary-search-template-and-many-leetcode-problems-1f850ef95651?source=collection_archive---------10----------------------->
## 在几分钟内编写无 python 解决方案的伟大工具

[李·坎贝尔](https://unsplash.com/@leecampbell)在 [Unsplash](https://unsplash.com/photos/DtDlVpy-vvQ) 上的照片
# 介绍
二分搜索法在概念上很容易理解。基本上,它将搜索空间分成两半,只保留可能有搜索目标的一半,而丢弃可能没有答案的另一半。这样,我们在每一步都将搜索空间缩小一半,直到找到目标。二分搜索法帮助我们将搜索时间从线性 O(n)减少到对数 O(log n)。但是说到实现,要在几分钟内写出一个没有错误的代码是相当困难的。一些最常见的问题包括:
* 何时退出循环?应该用`left < right`还是`left <= right`作为 while 循环条件?
* 如何初始化边界变量`left`和`right`?
* 如何更新边界?如何从`left = mid`、`left = mid + 1`和`right = mid`、`right = mid — 1`中选择合适的组合?
对二分搜索法的一个相当普遍的误解是,人们通常认为这种技术只能用在简单的场景中,比如“给定一个排序的数组,从中找出一个特定的值”。事实上,它可以应用于更复杂的情况。
在 LeetCode 中做了大量的练习后,我制作了一个强大的二分搜索法模板,并通过稍微扭曲这个模板解决了许多难题。我会在这篇文章中与你们分享这个模板。**我不想只是炫耀代码就离开。最重要的是,我想分享逻辑思维:如何将这个通用模板应用于各种问题。希望看完这篇文章后,人们不会再因为听到“神圣的 sh*t!这个问题可以用二分搜索法来解决!我以前怎么没想到呢!”**
# 最广义的二分搜索法
假设我们有一个搜索空间。它可以是数组、范围等。通常是按升序排序的。对于大多数任务,我们可以将需求转换为以下通用形式:
**最小化 k,s.t .条件(k)为真**
以下代码是最通用的二分搜索法模板:
这个模板真正的好处是,对于大多数二分搜索法问题,我们只需要在复制粘贴这个模板后修改三个部分,再也不用担心代码中的死角和 bug 了:
* 正确初始化边界变量`left`和`right`。只有一个规则:设置边界使**包含所有可能的元素**;
* 决定返回值。是`return left`还是`return left — 1`?记住这个:**退出 while 循环后,** `**left**` **是满足** `**condition**` **函数**的最小 k;
* 设计`condition`功能。这是最难也是最美的部分。需要大量的练习。
下面我将向你们展示如何将这个强大的模板应用于许多 LeetCode 问题。
# 施基肥
[](https://leetcode.com/problems/first-bad-version/) [## 第一个错误版本- LeetCode
### 你是一名产品经理,目前正带领一个团队开发新产品。不幸的是,最新版本的…
leetcode.com](https://leetcode.com/problems/first-bad-version/)
首先,我们初始化`left = 1`和`right = n`以包含所有可能的值。然后我们注意到我们甚至不需要设计`condition`函数。它已经由`isBadVersion` API 给出了。找到第一个坏版本就相当于找到满足`isBadVersion(k) is True`的最小 k。我们的模板非常适合:
[](https://leetcode.com/problems/sqrtx/) [## Sqrt(x) - LeetCode
### 实现 int sqrt(int x)。计算并返回 x 的平方根,其中 x 保证为非负整数…
leetcode.com](https://leetcode.com/problems/sqrtx/)
相当简单的问题。我们需要搜索满足`k^2 <= x`的最大 k,因此我们可以很容易地得出解决方案:
有一件事我想指出来。记得我说过我们通常寻找满足特定条件的最小 k 值吗?但是在这个问题中,我们寻找的是最大的 k 值。感到困惑?不要这样。实际上,满足`isBadVersion(k) is False`的最大 k 正好等于满足`isBadVersion(k) is True`的最小 k 减一。这就是为什么我之前提到我们需要决定返回哪个值,`left`还是`left — 1`。
[](https://leetcode.com/problems/search-insert-position/) [## 搜索插入位置- LeetCode
### 给定一个排序数组和一个目标值,如果找到目标,则返回索引。如果没有,返回索引…
leetcode.com](https://leetcode.com/problems/search-insert-position/)
非常经典的二分搜索法应用。我们正在寻找满足`nums[k] ≥ target`的最小 k,我们可以复制粘贴我们的模板。注意,不管输入数组`nums`是否有重复,我们的解决方案都是正确的。还要注意,输入`target`可能比`nums`中的所有元素都大,因此需要放在数组的末尾。这就是为什么我们应该初始化`right = len(nums)`而不是`right = len(nums) — 1`。
# 高级应用
上述问题相当容易解决,因为它们已经给了我们要搜索的数组。乍一看,我们就知道应该用二分搜索法来解决这些问题。然而,更常见的情况是搜索空间和搜索目标不那么容易获得。有时我们甚至不会意识到问题应该用二分搜索法来解决——我们可能只是求助于动态编程或 DFS,然后陷入很长一段时间。
至于“什么时候可以用二分搜索法”这个问题,我的回答是,**如果我们能发现某种单调性,例如,如果** `**condition(k) is True**` **那么** `**condition(k + 1) is True**` **,那么我们可以考虑二分搜索法**。
[](https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/) [## 在 D 天内运送包裹的能力- LeetCode
### 传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。第 I 个包裹在…
leetcode.com](https://leetcode.com/problems/capacity-to-ship-packages-within-d-days/)
当我们第一次遇到这个问题时,可能不会想到二分搜索法。我们可能会自动将`weights`视为搜索空间,然后意识到在浪费了大量时间后,我们进入了一个死胡同。事实上,我们正在寻找所有可行容量中最小的一个。我们挖掘出这个问题的单调性:如果我们能在`D`天内用容量`m`成功装运所有包裹,那么我们就一定能把任何大于`m`的容量全部装运。现在我们可以设计一个`condition`函数,姑且称之为`feasible`,给定一个输入`capacity`,它返回是否有可能在`D`天内装运所有包裹。这可能以一种贪婪的方式运行:如果当前的包裹还有空间,我们将这个包裹放在传送带上,否则我们等待第二天放置这个包裹。如果需要的总天数超过了`D`,我们返回`False`,否则我们返回`True`。
接下来,我们需要正确初始化我们的边界。显然`capacity`至少应该是`max(weights)`,否则传送带运不出最重的包裹。另一方面,`capacity`不需要比`sum(weights)`多,因为这样我们就可以在一天之内把所有的包裹都发货了。
现在,我们已经获得了应用二分搜索法模板所需的所有信息:
[](https://leetcode.com/problems/split-array-largest-sum/) [## 分裂阵列最大和- LeetCode
### 给定一个由非负整数和一个整数组成的数组,你可以把数组分成非空的…
leetcode.com](https://leetcode.com/problems/split-array-largest-sum/)
如果你仔细观察,你可能会发现这个问题与上面的 LC 1011 有多么相似。类似地,我们可以设计一个`feasible`函数:给定一个输入`threshold`,然后决定是否可以将数组分成几个子数组,使得每个子数组的和小于或等于`threshold`。这样我们就发现了问题的单调性:如果`feasible(m)`是`True`,那么所有大于`m`的输入都能满足`feasible`函数。你可以看到解决方案代码与 LC 1011 完全相同。
但是我们很可能会有疑问:我们的解返回的`left`确实是满足`feasible`的最小值,但是我们怎么知道我们可以把原数组拆分为**实际得到这个子数组和**?比如说`nums = [7,2,5,10,8]`和`m = 2`。我们有 4 种不同的方法来分裂阵列,从而相应地得到 4 个不同的最大子阵列和:`25:[[7], [2,5,10,8]]`、`23:[[7,2], [5,10,8]]`、`18:[[7,2,5], [10,8]]`、`24:[[7,2,5,10], [8]]`。只有 4 个值。但是我们的搜索空间`[max(nums),sum(nums)]=[10,32]`不仅仅只有 4 个值。也就是说,无论我们如何分割输入数组,我们都无法获得搜索空间中的大多数值。
假设`k`是满足`feasible`函数的最小值。我们可以用反证法证明我们解决方案的正确性。假设没有子阵列的和等于`k`,即每个子阵列的和小于`k`。`feasible`函数中的变量`total`记录当前负载的总重量。如果我们的假设是正确的,那么`total`将总是小于`k`。因此,`feasible(k-1)`必须是`True`,因为`total`最多等于`k-1`并且永远不会触发 if 子句`if total > threshold`,因此`feasible(k-1)`必须具有与`feasible(k)`相同的输出,即`True`。但是我们已经知道`k`是满足`feasible`函数的最小值,那么`feasible(k-1)`就得是`False`,这是一个矛盾。所以我们的假设是不正确的。现在我们已经证明了我们的算法是正确的。
[](https://leetcode.com/problems/koko-eating-bananas/) [## 科科吃香蕉- LeetCode
### 科科喜欢吃香蕉。有 N 堆香蕉,第 I 堆有成堆的香蕉。警卫已经走了,而且…
leetcode.com](https://leetcode.com/problems/koko-eating-bananas/)
非常类似上面提到的 LC 1011 和 LC 410。让我们设计一个`feasible`函数,给定一个输入`speed`,确定科科是否能以每小时的进食速度`speed`在`H`小时内吃完所有香蕉。显然,搜索空间的下界是 1,上界是`max(piles)`,因为科科每小时只能选择一堆香蕉吃。
[](https://leetcode.com/problems/minimum-number-of-days-to-make-m-bouquets/) [## 制作 m 束鲜花的最少天数- LeetCode
### 给定一个整数数组 bloomDay,一个整数 m 和一个整数 k。我们需要做 m 个花束。要制作花束,你需要…
leetcode.com](https://leetcode.com/problems/minimum-number-of-days-to-make-m-bouquets/)
既然我们已经解决了上面的三个高级问题,这一个应该很容易做到。这个问题的单调性非常明显:如果我们能在等待`d`天后制作`m`花束,那么如果我们等待超过`d`天,我们肯定也能完成。
[](https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/description/) [## 乘法表中第 k 个最小的数- LeetCode
### 几乎每个人都用过乘法表。但是你能从…中快速找出第 k 个最小的数字吗?
leetcode.com](https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/description/)
对于像这样的最小问题,我们首先想到的是堆。通常,我们可以维护一个最小堆,并只弹出堆的顶部 k 次。然而,这在这个问题中是行不通的。我们没有整个乘法表中的每个数字,相反,我们只有表的高度和长度。如果我们要应用堆方法,我们需要显式地计算这些`m*n`值并将它们保存到堆中。这个过程的时间复杂度和空间复杂度都是 O(mn),效率相当低。这是二分搜索法进来的时候。还记得我们说设计`condition`功能是最难的部分吗?为了找到表中第 k 个最小值,我们可以设计一个`enough`函数,给定一个输入`num`,判断是否至少有 k 个值小于或等于`num`。**满足** `**enough**` **函数的最小 num 就是我们要找的答案**。回想一下,二分搜索法的关键是发现单调性。在这个问题中,如果`num`满足`enough`,那么当然任何大于`num`的值都可以满足。这种单调性是我们的二分搜索法算法的基础。
让我们考虑搜索空间。显然下界应该是 1,上界应该是乘法表中的最大值,也就是`m * n`,那么我们就有了搜索空间`[1, m * n]`。与堆解决方案相比,二分搜索法解决方案的压倒性优势在于,它不需要显式计算表中的所有数字,它只需要从搜索空间中选取一个值,并将`enough`函数应用于该值,以确定我们应该保留搜索空间的左半部分还是右半部分。这样,二分搜索法方案只需要恒定的空间复杂度,比堆方案好得多。
接下来让我们考虑如何实现`enough`功能。可以观察到,乘法表中的每一行都只是其索引的倍数。例如,第三行`[3,6,9,12,15...]`中的所有数字都是 3 的倍数。因此,我们可以逐行计数小于或等于输入`num`的条目总数。以下是完整的解决方案。
在上面的 LC 410 中,我们怀疑“二分搜索法的结果实际上是子阵列和吗?”。这里我们有一个类似的疑问:“**二分搜索法的结果真的在乘法表里吗?**”。答案是肯定的,我们也可以用矛盾来证明。将`num`表示为满足`enough`功能的最小输入。我们假设`num`不在表中,也就是说`num`不能被`[1, m]`中的任何一个`val`整除,也就是说`num % val > 0`。因此,将输入从`num`更改为`num - 1`对表达式`add = min(num // val, n)`没有任何影响。所以`enough(num)`也会返回`True`,就像`enough(num)`一样。但是我们已经知道`num`是满足`enough`函数的最小输入,所以`enough(num - 1)`必须是`False`。矛盾!与我们最初的假设相反的是正确的:`num`实际上在表中。
[](https://leetcode.com/problems/find-k-th-smallest-pair-distance/) [## 找到第 K 个最小的配对距离- LeetCode
### 提高你的编码技能,迅速找到工作。这是扩展你的知识和做好准备的最好地方…
leetcode.com](https://leetcode.com/problems/find-k-th-smallest-pair-distance/)
非常类似于上面的 LC 668,两者都是关于寻找第 k 个最小的。就像 LC 668 一样,我们可以设计一个`enough`函数,给定一个输入`distance`,确定是否至少有 k 对的距离小于或等于`distance`。我们可以对输入数组进行排序,并用两个指针(快指针和慢指针,指向一对)对其进行扫描。两个指针都从最左端开始。如果当前指向的指针对的距离小于或等于`distance`,则这些指针之间的所有指针对都是有效的(因为数组已经排序),我们将快速指针向前移动。否则,我们将慢速指针向前移动。当两个指针都到达最右端时,我们完成扫描,并查看总计数是否超过 k。实现如下:
显然,我们的搜索空间应该是`[0, max(nums) - min(nums)]`。现在我们准备复制粘贴我们的模板:
[](https://leetcode.com/problems/ugly-number-iii/) [## 丑陋的数字 III - LeetCode
### 提高你的编码技能,迅速找到工作。这是扩展你的知识和做好准备的最好地方…
leetcode.com](https://leetcode.com/problems/ugly-number-iii/)
没什么特别的。仍然在寻找最小的。我们需要设计一个`enough`函数,给定一个输入`num`,确定是否有至少 n 个丑数小于或等于`num`。由于`a`可能是`b`或`c`的倍数,或者反过来,我们需要最大公约数的帮助来避免计算重复数。
[](https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/) [## 给定一个阈值,找出最小的除数
### 给定一个整数数组 num 和一个整数阈值,我们将选择一个正整数除数,并将所有的
leetcode.com](https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/)
上面介绍了这么多问题,这个应该是小菜一碟。我们甚至不需要费心去设计一个`condition`函数,因为问题已经明确告诉我们需要满足什么条件。
# 结束
哇,非常感谢你坚持到最后,真的很感激。从上面的 python 代码中可以看出,它们看起来都非常相似。那是因为我一直在复制粘贴我的模板。没有例外。这是我的模板强大的有力证明。我相信每个人都可以获得这个二分搜索法模板来解决许多问题。我们所需要的只是更多的练习来建立我们发现问题单调性的能力,并设计一个漂亮的`condition`函数。
希望这有所帮助。
**参考**
* [【c++/快速/非常清晰的解释/干净的代码】贪婪算法和二分搜索法的解决方案](https://leetcode.com/problems/split-array-largest-sum/discuss/89819/C%2B%2B-Fast-Very-clear-explanation-Clean-Code-Solution-with-Greedy-Algorithm-and-Binary-Search)
* [使用“试错”算法解决问题](https://leetcode.com/problems/find-k-th-smallest-pair-distance/discuss/109082/Approach-the-problem-using-the-%22trial-and-error%22-algorithm)
* [二分搜索法 101 终极二进制搜索手册——leet code](https://leetcode.com/problems/binary-search/discuss/423162/Binary-Search-101-The-Ultimate-Binary-Search-Handbook)
* [丑女三号二分搜索法配图&二分搜索法模板— LeetCode](https://leetcode.com/problems/ugly-number-iii/discuss/387539/cpp-Binary-Search-with-picture-and-Binary-Search-Template)
# “启动”撒哈拉以南非洲的卫生设施
> 原文:<https://towardsdatascience.com/powering-up-health-facilities-in-ssa-fb626babddbe?source=collection_archive---------55----------------------->
## 使用开放存取数据的探索性方法& Python 中的空间分析

马丁·桑切斯在 [Unsplash](https://unsplash.com/) 上的照片
# 目录
[动机](#96a4)
[循序渐进指南](#0ec6)
[结束语](#5b80)
[链接到辅助材料](#72db)
# 动机
据估计,全球约有 7 . 89 亿人没有电力供应。绝大多数(约 75% )位于撒哈拉以南非洲。这是一个影响社会经济发展和人类福祉的关键服务差距,特别是在最不发达地区的贫困农村人口中。
与此同时,新冠肺炎突出强调了电力在卫生部门的重要性。在诊所和卫生站获得电力,使人们保持联系,便于信息管理、药品冷藏和其他服务,以保护弱势群体。因此,缺乏可靠的电力正在损害数百万人的医疗保健质量。
**这就迫切需要“加强”最不发达地区的卫生设施,以便及时应对新冠肺炎危机。**
本博客介绍了一种探索性的、基于 GIS 的方法,用于在缺乏这类详细数据的地区估算医疗机构的电力需求。它利用现有的开放访问数据集(和模型),以提供这些设施中年度电力需求的高水平画面,并随后指示如何作为最低成本电气化计划的一部分来满足这些需求。
下面的例子集中在莫桑比克的 [Mecanhelas](https://en.wikipedia.org/wiki/Mecanhelas_District) 区(任意选择)。然而,该代码可用于在任何行政级别(例如,国家和/或区域)扩大分析。
# 循序渐进的指南
# 第一步。设置 python 环境和导入数据集
## 导入必要的模块
作为 Jupyter 中任何建模练习的一部分,第一步需要导入必要的 python 模块。你可以参考 [requirements.txt](https://github.com/akorkovelos/gep_health_facilities/blob/master/requirements.txt) 来检查这个例子的依赖关系。
Import python modules
import geopandas as gpd
import pandas as pd
import pyproj
import numpy as np
from functools import reduce
from shapely.geometry import Point, Polygon, MultiPoint
from shapely.ops import nearest_pointsimport datapane as dp
!datapane login --token="yourpersonaltoken"import folium
from folium.features import GeoJsonTooltip
import branca.colormap as cm
import os
from IPython.display import display, Markdown, HTML
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
%matplotlib inline
## 导入数据集
在这里,我们导入将要使用的数据集。其中包括以下三种:
**1。行政边界(矢量多边形):**这定义了我们感兴趣区域的边界框。在这个例子中,我们使用的是莫桑比克西北部省份 Mecanhelas 的行政边界。你可以从 [GADM](https://gadm.org/) 那里取回这个。
**2。卫生设施的位置(向量点)**:在这种情况下,我们使用由 [Maina 等人](https://www.nature.com/articles/s41597-019-0142-2)提供的卫生设施的空间数据库。该数据集包括 98,745 个公共卫生机构,所有这些机构都有地理位置。
**3。人口集群(矢量多边形)**:这是指建成区的矢量化版本,如 [Korkovelos 等人](https://www.mdpi.com/1996-1073/12/7/1395)所述。撒哈拉以南非洲所有国家的人口集群都是开放的,可在 [PopClusters](https://data.mendeley.com/datasets/z9zfhzk8cr/6) 上获得。(在本练习中,我们使用 2020 年 9 月 1 日发布的版本 6)。
> **注 1** 。出于本练习的目的,在导入笔记本之前,( 2)和(3)都基于(1)进行了剪裁。你可以使用 [geopandas](https://geopandas.org/reference/geopandas.clip.html) 或 [Qgis](https://docs.qgis.org/2.8/en/docs/user_manual/processing_algs/gdalogr/ogr_geoprocessing/clipvectorsbypolygon.html) 来完成这项工作。
>
> **注 2** 。在导入之前,所有数据集都在 WGS84 坐标系中。请确保这是事实,否则请纠正。
## 将行政边界作为地理数据框架导入
Define path and name of the file
admin_path = r"input_data\Testing_Sample"
admin_name = "mecanhelas_admin.gpkg"# Create a new geo-dataframe
admin_gdf = gpd.read_file(admin_path + "\" + admin_name)# Create the axis first
fig, ax = plt.subplots(figsize=(10, 10))
admin_gdf.plot(ax=ax, edgecolor='black', alpha=0.2)
ax.set_aspect('equal', 'box')
txt = ax.set_title('Mecanhelas Administrative Boundary'.format(""))

莫桑比克 Mecanhelas 区的行政区域—图片由作者提供
## 进口卫生设施
> **注意**为了让下面的代码正常工作,这应该是一个“点”层;如果几何特征为“多点”,您应该将其转换为“点”以继续。你可以使用 Qgis 来完成这项工作。
Define path and name of the file
health_path = r"input_data\Testing_Sample"
health_name = "mec_health_index.gpkg"# Create a new geo-dataframe
health_gdf = gpd.read_file(health_path + "\" + health_name)health_gdf.head(3)

## …和可视化
fig, ax = plt.subplots(figsize=(10, 10))
admin_gdf.plot(ax=ax, edgecolor='brown', alpha=0.2)
health_gdf.plot(ax=ax, legend=True, markersize=3, figsize=(15, 15), alpha=0.5)
ax.set_aspect('equal', 'box')
txt = ax.set_title('Location of health facilities in Mecanhelas'.format(""))

莫桑比克 Mecanhelas 卫生机构的位置—图片由作者提供
## 导入人口聚类
Define path and name of the file
clusters_path = r"input_data\Testing_Sample"
clusters_name = "mecanhelas_clusters.gpkg"clusters_gdf = gpd.read_file(clusters_path + "\" + clusters_name)clusters_gdf.head(2)

## …并使用每个聚类的质心创建新的地理数据框
clusters_centroid = gpd.GeoDataFrame(clusters_gdf, geometry=clusters_gdf.centroid)fig, ax = plt.subplots(figsize=(10, 10))
admin_gdf.plot(ax=ax, edgecolor='brown', alpha=0.2)
clusters_centroid.plot(ax=ax, legend=True, markersize=3, figsize=(15, 15), alpha=0.5)
ax.set_aspect('equal', 'box')
txt = ax.set_title('Population cluster centroids in Mecanhelas'.format(""))

莫桑比克 Mecanhelas 区的“矢量化”建筑——图片由作者提供
输入的数据表明,Mecanhelas 有 **10,703 个人口集群**(或定居点),由 **19 个卫生设施**提供服务。
# 第二步。数据集的空间处理
一旦数据集成功导入,我们就可以为医疗机构计算简单的空间统计数据。也就是说,我们使用它们的位置并从附近的人口聚类中提取值。这里我们有两个选择。
## 选项 1-最近枢纽分析
部署最近中心分析,并计算与每个医疗机构的“集水区”相关的统计数据。
> **注意**下面的 NNA 代码是从 [shakasom](https://github.com/shakasom/NearestNeighbour-Analysis) 中检索出来的。
Simple function getting the nearest hub for a given set of points
def calculate_nearest(row, destination, val, col="geometry"):
dest_unary = destination["geometry"].unary_union
nearest_geom = nearest_points(row[col], dest_unary)
match_geom = destination.loc[destination.geometry == nearest_geom[1]]
match_value = match_geom[val].to_numpy()[0]
return match_value
## 为每个集群分配最近的医疗机构
clusters_centroid["index"] = clusters_centroid.apply(calculate_nearest, destination=health_gdf, val="index", axis=1)
## 基于医疗机构 id 分解聚类,并计算每个医疗机构的基本统计数据
stat_list = ['sum', 'mean', 'count']
HF_hub_stats = clusters_centroid.dissolve(by='index', aggfunc=stat_list)
> **注意!**这会产生一个多点矢量层;每个多点包含由同一医疗机构提供服务的聚类(质心)的位置。

## 将结果与初始医疗设施点图层合并
这是为了在原始医疗机构数据帧中附加新检索的统计数据。
HF_hub = health_gdf.merge(HF_hub_stats, on="index")
整理结果后,**选项 1** 生成以下地理数据框,其中根据聚类的最近距离计算每个医疗机构的基本统计数据。

## 选项 2 —基于缓冲区的统计
将缓冲区应用于每个医疗机构,并计算落入其中的集群的统计数据。这种方法计算量较小。
## 首先,我们需要将图层投影到正确的 CRS 中
在这种情况下,我们使用 [epsg.io](https://epsg.io/32737) 中为莫桑比克标识的“epsg:32737”。
admin_gdf_prj = admin_gdf.to_crs({'init': 'epsg:32737'})
health_gdf_prj = health_gdf.to_crs({'init': 'epsg:32737'})
clusters_gdf_prj = clusters_gdf.to_crs({'init': 'epsg:32737'})# Drop selected columns
clusters_gdf_prj.drop(["index"], axis=1, inplace=True)
clusters_gdf_prj.head(2)

## …我们重新生成了群集质心层,只是这次使用了投影的群集
clusters_centroid_proj = gpd.GeoDataFrame(clusters_gdf_prj, geometry=clusters_gdf_prj.centroid)
## 为每个卫生设施增加一个缓冲区
health_gdf_prj['geometry'] = health_gdf_prj.geometry.buffer(1000) # in meters
## 应用空间连接
Spatial join
health_gdf_prj_joined = gpd.sjoin(clusters_centroid_proj, health_gdf_prj, op='within', how='right')health_gdf_prj_joined.head(2)

## 基于索引对要素进行分组
Basic statistics to calculate
stat_list = ['sum', 'mean', 'count']
Apply groupby function
HF_buf_stats = health_gdf_prj_joined.dissolve(by='index', aggfunc=stat_list)
## 与初始医疗机构数据集合并
HF_buf = health_gdf_prj.merge(HF_buf_stats, on="index")
## 将结果转换为原始 CRS 中的地理数据框
Creating a geo-dataframe - appointing geometry attribute
HF_buf['geometry'] = list(zip(HF_buf['Lon'], HF_buf['Lat']))
HF_buf['geometry'] = HF_buf['geometry'].apply(Point)
HF_buf_gdf = gpd.GeoDataFrame(HF_buf, geometry='geometry', crs={'init': 'epsg:4326'})
整理结果后,**选项 2** 生成以下地理数据框,其中基于缓冲区计算每个医疗机构的基本统计数据。

## 描述性分析
无论选择何种方法(**选项 1** 或**选项 2** ),生成的地理数据框架都具有相似的格式。接下来,我们希望对结果进行描述性分析,以便了解数据类型和潜在的分类技术。
## **选项 1 的结果**
HF_hub_gdf.pop_sum.describe()count 19.000000
mean 26882.061818
std 10771.348988
min 5685.042735
25% 21419.189453
50% 25469.963919
75% 30545.254864
max 59730.107002
Name: pop_sum, dtype: float64bin_values = np.arange(start=0, stop=HF_hub_gdf.pop_sum.sum())
HF_hub_gdf['pop_sum'].hist(figsize=[14,6])
plt.title("Population served by each health facility")
plt.show()

按作者分类的图表
remove inconsistencies hospital type names
HF_hub_gdf["fctype"].replace("?", 'u', regex=True, inplace=True)
remove inconsistencies hospital type names
HF_hub_gdf["fcname"].replace("?", 'u',regex=True, inplace=True)ls_of_hf = HF_hub_gdf.fctype.unique()
print('\nThis administrative area has {} different types of hospitals:\n'.format(len(ls_of_hf)))
print(*ls_of_hf, sep = '\n')This administrative area has 2 different types of hospitals:
Centro de Saude Rural II
Centro de Saude Rural I
## **选项 2** 的结果
HF_buf_gdf.pop_sum.describe()count 19.000000
mean 4121.879924
std 6517.540750
min 253.035754
25% 819.507531
50% 991.796760
75% 2666.860946
max 20250.234550
Name: pop_sum, dtype: float64bin_values = np.arange(start=0, stop=HF_buf_gdf.pop_sum.sum())
HF_buf_gdf['pop_sum'].hist(figsize=[14,6])
plt.title("Population served by each health facility")
plt.show()

按作者分类的图表
ls_of_hf = HF_buf_gdf.fctype.unique()
print('\nThis administrative area has {} different types of hospitals:\n'.format(len(ls_of_hf)))
print(*ls_of_hf, sep = '\n')This administrative area has 2 different types of hospitals:
Centro de Saude Rural II
Centro de Saude Rural I
描述性统计提供了每个卫生机构(潜在)服务人数的概念。基于原始数据的属性,也可以检索其他特征(例如,我们在该区域确定的医疗机构的类型)。这些信息可用于帮助将健康诊所分类为不同的“能源使用”组(参见下面的步骤 3)。
## 第三步。描述卫生设施的类型并预测电力需求
您可以选择以上任何一种方法继续。
HF = HF_hub_gdf # you may change the input gdf here# Initialize a Health Facility Category column
HF['HF_Cat'] = 0
## 卫生设施的分类
下面介绍的分类过程是基于这样的想法,即卫生设施分为四个主要类别,即:
* **类型 4:** 地区/转诊医院(> 145 张床位)
* **类型 3:** 乡村医院(约 55 张床位)
* **类型 2:** 小型急病门诊(约 14 张床位)
* **类型 1:** 农村药房——无住院病人(约 4 张急诊床)
这种分类与文献中的类似方法一致(例如,参见 [Franco 等人](https://www.sciencedirect.com/science/article/pii/S2213138817301376))。它还被采用并用于[HOMER power Health Tool](https://poweringhealth.homerenergy.com/)。
在本例中,我们使用三个值(我们在上一步中已经计算过)来帮助对医疗机构进行相应的分类。其中包括:
1. **"urban_mean"** :这是与每个卫生设施相关的所有集群的平均城市状态{城市:1 或农村:0}。值>大于 0.5 表示医疗设施服务于更多的城市居民区,因此更有可能是更高级的类型。
2. **"pop_sum"** :这是与每个医疗机构相关的所有集群中的人口总数(基于上一步中最近的中心或缓冲区分析)。更高的潜在服务人群可能表明更高的类型。
3. **"elecpop_sum"** :这是与每个卫生设施相关的所有集群中通电人口的总和。这在一定程度上表明,附近的电气化状况可能与卫生设施的类型有关。
在缺乏更详细的(如调查)数据的情况下,目前很难对这种方法进行交叉验证。因此,方法的这一部分对用户输入是开放的。其想法是,建模者可以与当地的利益相关者密切合作,以便校准过程或在获得更多信息时添加“预测器”。
> **注意!**在我们的示例中,医疗机构确实包含一些属性,例如它们的类型(如 Centro de Saude Rural I 或 II)。如果可能的话,可以使用这一特性(或任何类似的特性)来帮助估计电力需求。然而,在接下来的步骤中,我们仅使用检索到的人口聚类数据统计,因此该方法可复制到其他地区。
District/Referral hospital with more than 145 beds
HF.loc[(HF['urban_mean'] >= 0.5) &
(HF['pop_sum'] >= 20000) &
(HF['elecpop_sum'] >= 0), 'HF_Cat'] = 4
Rural hospital - 50 beds
HF.loc[(HF['urban_mean'] <= 0.5) &
(HF['pop_sum'] >= 20000) &
(HF['elecpop_sum'] >= 0), 'HF_Cat'] = 3
Small impatient clinic - 14 beds
HF.loc[(HF['urban_mean'] <= 0.5) &
(HF['pop_sum'] < 20000) &
(HF['elecpop_sum'] > 0), 'HF_Cat'] = 2
Rural dispensary - no inpatient - 4 emergency beds
HF.loc[(HF['urban_mean'] <= 0.5) &
(HF['pop_sum'] < 20000) &
(HF['elecpop_sum'] == 0), 'HF_Cat'] = 1
## 分类的绘图结果
ax = HF['HF_Cat'].value_counts().plot(kind='bar',figsize=[12,7])
ax.yaxis.set_major_locator(MaxNLocator(integer=True))
plt.title("Categorization of Health facilities in the selected admin area")Text(0.5, 1.0, 'Categorization of Health facilities in the selected admin area')

莫桑比克 Mecanhelas 医疗机构的数量(y 轴)和类型(x 轴)——作者图表
## 根据类别类型分配电力需求
与分类(见上文)类似,考虑到缺乏定量的地面数据,估计每个医疗机构的电力需求并不是一件容易的事情。在本例中,我们使用 [HOMER 供电健康工具](https://poweringhealth.homerenergy.com/)界面来量化每种类型的健康机构的潜在电力需求(千瓦时/年)。建模者可以选择适当的设备并相应地定制电力目标。
HF.loc[(HF['HF_Cat'] == 1), 'HF_kWh'] = 5.7365
HF.loc[(HF['HF_Cat'] == 2), 'HF_kWh'] = 13.9365
HF.loc[(HF['HF_Cat'] == 3), 'HF_kWh'] = 37365
HF.loc[(HF['HF_Cat'] == 4), 'HF_kWh'] = 361.1365
基于上述假设,预计 Mecanhelas 医疗机构的电力需求为 **~225,314.5kWh/年**。
# 在地图上打印带有估计需求的医疗机构的位置
Vizualize result on an interactive map exported as html
Define limits for map rendering
x_ave = HF["Lon"].mean()
y_ave = HF["Lat"].mean()
Create the map using folium module
map_dem = folium.Map(location=[y_ave,x_ave], zoom_start=6, control_scale=True)
Definition of a function that returns different color names based on lcoe result categorization
Colors are in Hexa-code e.g. #RRGGBB
def colorvalue(x):
if x <= 0.5:
return "#ADFF2F"
elif x >= 1 and x < 5000:
return "#32CD32"
elif x >= 5000 and x < 10000:
return "#228B22"
elif x >= 10000 and x < 15000:
return "#008000"
elif x >= 15000 and x < 20000:
return "#006400"
else:
return "#000000"
Then we create a marker for each cluster;
We pass coordinates as attributes to appear on the rendered map
for index, row in HF.iterrows():
el_demand = row["HF_kWh"]
color_code = colorvalue(el_demand)
folium.CircleMarker([row["Lat"], row["Lon"]],
radius=2,
color=color_code,
popup="Name: {},
Type: {},
Demand: {} kWh/year,
".format(row["fcname"], row["fctype"], row["HF_kWh"]),
fill = True,
fill_opacity=0).add_to(map_dem)
We define the limits of the legend and fix its printout format
We use branca module to create a colormap legend and then add legend to the map
min_dem = HF["HF_kWh"].min()
max_dem = HF["HF_kWh"].max()
min_dem = float("{0:.2f}".format(min_dem))
max_dem = float("{0:.2f}".format(max_dem))
legend = cm.LinearColormap(['#ADFF2F','#32CD32','#228B22','#008000','#006400','#000000'],
index=None, vmin=min_dem, vmax=max_dem)
legend.add_to(map_dem)
expl_text = '#ADFF2F:1, #32CD32:2, #228B22:3, #008000:4, #006400:5'
iframe = folium.IFrame(expl_text, width=700, height=450)
popup = folium.Popup(iframe, max_width=3000)
Text = folium.Marker(location=[x_ave,y_ave], popup=popup,
icon=folium.Icon(icon_color='green'))
map_dem.add_child(Text)
Create a new directory where the map(s) can be saved
try:
os.makedirs('maps')
except FileExistsError:
pass
map_dem_output = 'maps/map_{}_{}.html'.format("Health_Facilities", "Mecanhelas")
map_dem.save(map_dem_output)# Publish map on datapane for easier rendering in websites
dp.Report(dp.Plot(map_dem)).publish(name='HF_elec_demand_Mecanhelas', visibility='PUBLIC')# Add the link that leads to the final map output
display(Markdown('Click here to render the map of electrification of health facilities '.format(map_dem_output)))
莫桑比克 Mecanhelas 卫生设施的位置和预计电力需求。作者地图—通过数据面板呈现—查看完整报告[此处](https://datapane.com/alexandros/reports/HF_elec_demand_Mecanhelas)。
# 第四步。将医疗机构目标电力需求分配回人口集群
每个医疗机构的电力需求被分配给最近的集群。
## 查找最近的聚类
HF["id"] = HF.apply(calculate_nearest, destination=clusters_centroid, val="id", axis=1)
## 将结果合并到初始聚类
clusters_gdf = gpd.read_file(clusters_path + "\" + clusters_name)final_clusters_HF_kWh = HF.merge(clusters_gdf, how="outer", on='id')

# 第五步。映射结果并导出更新的人口聚类数据集
final_clusters_HF_kWh_gdf = gpd.GeoDataFrame(final_clusters_HF_kWh, geometry='geometry', crs={'init': 'epsg:4326'})# Create the axis first
fig, ax = plt.subplots(figsize=(10, 10))
admin_gdf.plot(ax=ax, edgecolor='brown', alpha=0.2)
final_clusters_HF_kWh_gdf.sort_values('HF_kWh', ascending=True).plot(ax=ax, column='HF_kWh',
legend=True, markersize=3, cmap="viridis",
figsize=(10, 10), alpha=0.5)
ax.set_aspect('equal', 'box')
txt = ax.set_title('Electricity requirements (kWh/year) for HF in Mecanhelas'.format(""))

作者图片
## 将图层导出为地理包
final_clusters_HF_kWh_gdf.to_file("Mecanhelas_HF_kWh.gpkg", driver="GPKG")
> 请注意,本例中给出的方法和结果**仅是说明性的**;仅显示空间分析如何用于支持类似的规划活动。
# 结束语
这是一种探索性的方法,仅基于现有的开放访问数据集。因此,对于量化撒南地区卫生设施电力需求的尝试,它只能提供一个粗略的“第一步”,特别是在没有太多数据的偏远农村地区。
这种分析当然可以通过以下方式得到改进:
* 利用地理定位卫生设施的更好属性数据;此类数据集可能已经存在于国家机构中,如人口普查局/部门、公共统计局、国家调查和制图机构以及其他部门/部委。
* 与目标地区健康和能源实践的当地利益相关者密切合作,以便更好地校准和/或改进此处介绍的方法。
* 相应地,使用详细的调查数据(如果可用)和机器学习来改进分类和对卫生设施的类型和电力需求的预测。
如果结果令人满意,最终产品(包括卫生设施电力需求的人口集群)可用于地理空间电气化模型,以制定成本最低的投资计划。一个例子是[GEP-昂塞特模型](https://github.com/global-electrification-platform/gep-onsset),它最近被修改以允许包含电力的生产性使用。
作为参考,您可以查看以下地图,这些地图显示了莫桑比克医疗机构和/或相关人群的最低成本电气化方案。
> **注意!!**下面的结果是**只是说明性的**。
**地图 1** :莫桑比克医疗机构的位置,包括其成本最低的电气化技术(结果以弹出形式提供)。
作者地图—通过数据面板呈现—查看完整报告[此处](https://datapane.com/alexandros/reports/HF_elec_demand_Mozambique)。
**地图 2:** 与莫桑比克一个或多个医疗机构相关的人口集群的最低成本电气化计划(结果以医疗机构弹出窗口和集群工具提示的形式提供)。
作者地图—通过数据面板呈现—查看完整报告[此处](https://datapane.com/alexandros/reports/Clusters_elec_demand_Mozambique)。
# 支持材料的链接
要快速浏览支持这个博客的方法和代码,你可以看看 [nbviewer](https://nbviewer.jupyter.org/gist/akorkovelos/baef0f0377f24c60a540b78fbb1bf227) 。
或者你可以在 [GitHub](https://github.com/akorkovelos/gep_health_facilities) 上访问(并贡献)完整版本的代码。
这项工作是支持[全球电气化平台](https://electrifynow.energydata.info/)开发的多年研究工作的一部分。
感谢阅读!
> 特别感谢 Benjamin Stewart、Ashish Shrestha、Rhonda Lenai Jordan、Nicolina Erica Maria Lindblad、Babak Khavari、Andreas Sahlberg 和 Mark Howells,他们都支持这项工作。
# PP-YOLO 超越 yolov 4——物体探测技术的进步
> 原文:<https://towardsdatascience.com/pp-yolo-surpasses-yolov4-object-detection-advances-1efc2692aa62?source=collection_archive---------5----------------------->
## 注:我们也在博客上发表了 [PP-YOLO 超越约洛夫 4](https://blog.roboflow.ai/pp-yolo-beats-yolov4-object-detection/) 。百度发布 PP-YOLO,推送[物体检测研究](https://blog.roboflow.com/the-ultimate-guide-to-object-detection/)最新动态。

[PP-YOLO](https://arxiv.org/pdf/2007.12099.pdf) 评估显示更快的推断(x 轴)和更好的准确性(y 轴)
PP-YOLO 评估指标显示,其性能优于目前最先进的目标检测模型 [YOLOv4](https://blog.roboflow.ai/a-thorough-breakdown-of-yolov4/) 。然而,百度的作者写道:
> 本文不打算介绍一种新颖的目标检测器。它更像是一个食谱,告诉你如何一步一步地建造一个更好的探测器。
让我们打开它。
# YOLO 发展历史
《YOLO》最初是由 Joseph Redmon 创作的,用来探测物体。[对象检测](https://blog.roboflow.com/the-ultimate-guide-to-object-detection/)是一种计算机视觉技术,通过在对象周围绘制一个边界框并识别给定框所属的类别标签来定位和标记对象。与庞大的 NLP 变形金刚不同,YOLO 被设计得很小,使得在设备上部署[的](https://blog.roboflow.com/deploy-yolov5-to-jetson-nx/)[实时推理速度](https://blog.roboflow.com/deploy-yolov5-to-jetson-nx/)。
YOLO-9000 是 Joseph Redmon 发表的第二个“yolov 2”[物体探测器](https://blog.roboflow.com/object-detection/),改进了探测器并强调了探测器推广到世界上任何物体的能力。

PP-YOLO 正在接受训练,以识别照片中不同的果蝇。
YOLOv3 对探测网络做了进一步的改进,开始将[物体探测过程](https://blog.roboflow.com/the-ultimate-guide-to-object-detection/)主流化。我们开始发布关于[如何在 PyTorch](https://blog.roboflow.ai/releasing-a-new-yolov3-implementation/) 中训练 YOLOv3、[如何在 Keras](https://blog.roboflow.ai/training-a-yolov3-object-detection-model-with-a-custom-dataset/) 中训练 YOLOv3、[比较 YOLOv3 性能和 EfficientDet](https://blog.roboflow.ai/yolov3-versus-efficientdet-for-state-of-the-art-object-detection/) (另一种最先进的检测器)的教程。
然后,由于伦理问题,约瑟夫·雷德蒙退出了对象检测游戏。
自然,开源社区拿起了接力棒,继续推动 YOLO 技术向前发展。
YOLOv4 最近在今年春天由 Alexey AB 在他的 YOLO 暗网知识库中出版。YOLOv4 主要是其他已知计算机视觉技术的集合,通过研究过程进行组合和验证。点击这里深入了解 YOLOv4 。YOLOv4 纸读起来与 PP-YOLO 纸相似,我们将在下面看到。我们整理了一些关于如何在黑暗网络中训练 YOLOv4 的很棒的训练教程。
然后,就在几个月前 [YOLOv5 发布](https://blog.roboflow.ai/yolov5-is-here/)。YOLOv5 采用了 Darknet(基于 C 的)培训环境,并将网络转换为 PyTorch。改进的训练技术进一步推动了模型的性能,并创建了一个伟大的、易于使用的、开箱即用的对象检测模型。从那以后,我们一直鼓励使用 Roboflow 的开发人员通过本 [YOLOv5 培训教程](https://blog.roboflow.ai/how-to-train-yolov5-on-a-custom-dataset/)将他们的注意力转向 YOLOv5,以形成他们的自定义对象检测器。
输入 PP-YOLO。
# PP 代表什么?
PP 是百度写的深度学习框架 PaddlePaddle 的简称。

[PaddlePaddle](https://www.paddlepaddle.org.cn/) 在其网站上提供发行版。
如果 PaddlePaddle 对你来说是陌生的,那么我们是在同一条船上。PaddlePaddle 主要用 Python 编写,看起来类似于 PyTorch 和 TensorFlow。深入探究 PaddlePaddle 框架很有趣,但超出了本文的范围。
# PP-YOLO 捐款
PP-YOLO 的论文读起来很像 YOLOv4 的论文,因为它是已知在计算机视觉中工作的技术的汇编。新的贡献是证明这些技术的组合提高了性能,并提供了一个烧蚀研究,每个步骤在多大程度上有助于模型前进。
在我们深入研究 PP-YOLO 的贡献之前,回顾一下 YOLO 探测器的结构是很有用的。
# YOLO 探测器的剖析

[PP-YOLO](https://arxiv.org/pdf/2007.12099.pdf) 物体探测网络的图形描述
YOLO 探测器分为三个主要部分。
**YOLO 主干**——YOLO 主干是一个卷积神经网络,它汇集图像像素以形成不同粒度的特征。主干通常在分类数据集(通常为 ImageNet)上进行预训练。
**YOLO 颈—**YOLO 颈(上面选择的是 FPN)在传递到预测头之前,合并和混合了 ConvNet 层表示。
[**YOLO 头**](https://blog.roboflow.com/what-is-an-anchor-box/) —这是网络中做出包围盒和类预测的部分。它由类、盒和对象的三个 YOLO 损失函数指导。
# 现在让我们深入了解一下 PP YOLO 的贡献。

在 [PP-YOLO](https://arxiv.org/pdf/2007.12099.pdf) 中,每种技术的边际地图精度性能都有所提高
# 替换主干
第一种 PP YOLO 技术是用 Resnet50-vd-dcn ConvNet 主干替换 YOLOv3 Darknet53 主干。Resnet 是一个更受欢迎的主干,更多的框架为其执行进行了优化,并且它比 Darknet53 具有更少的参数。通过交换这个主干看到一个[地图](https://blog.roboflow.com/mean-average-precision/)的改进对 PP YOLO 来说是一个巨大的胜利。

[ResNet](https://arxiv.org/pdf/1603.05027.pdf) 中的图形描述
# 模型参数的 EMA
PP YOLO 跟踪网络参数的指数移动平均值,以在预测时间内保持模型权重的影子。这已被证明可以提高推断的准确性。
# 较大批量
PP-YOLO 将批量从 64 个增加到 192 个。当然,如果你有 GPU 内存限制,这是很难实现的。
# 丢弃块正则化
PP YOLO 在 FPN 颈部实施 DropBlock 正则化(在过去,这通常发生在主干中)。DropBlock 在网络中的给定步骤随机删除一块训练特征,以教导模型不依赖于关键特征进行检测。

[丢弃块](https://arxiv.org/pdf/1810.12890.pdf)正则化技术——特征不随机地隐藏在块中(b)
# 欠条损失
YOLO 损失函数不能很好地转化为[地图度量](https://blog.roboflow.ai/what-is-mean-average-precision-object-detection/),它在计算中大量使用联合上的交集。因此,考虑到这个最终预测,编辑训练损失函数是有用的。这个剪辑也出现在了《T4》中。
# IoU 感知
PP-YOLO 网络增加了一个预测分支,用于预测给定对象的模型估计 IOU。在决定是否预测对象时,包含这种 IoU 意识可以提高性能。
# 网格灵敏度
旧的 YOLO 模型在围绕锚盒区域的边界做出预测方面做得不好。为了避免这个问题,定义稍微不同的盒子坐标是有用的。这个技巧在 [YOLOv4](https://blog.roboflow.com/a-thorough-breakdown-of-yolov4/) 中也有。
# 矩阵 NMS
非最大值抑制是一种去除用于分类的候选对象的过多建议的技术。矩阵 NMS 是一种并行排序这些候选预测的技术,可以加快计算速度。
# CoordConv
CoordConv 的灵感来源于 ConvNets 在简单地将(x,y)坐标映射到一个热点像素空间时遇到的问题。CoordConv 解决方案允许卷积网络访问自己的输入坐标。CoordConv 干预用上面的黄色菱形标记。CordConv 论文中提供了更多详细信息。
# 中加国际学生合作计划
空间金字塔池是主干层之后的一个额外模块,用于混合和汇集空间要素。也在 [YOLOv4](https://blog.roboflow.com/a-thorough-breakdown-of-yolov4/) 和 [YOLOv5](https://blog.roboflow.com/yolov5-is-here/) 中实现。
# 更好的预训练脊柱
PP YOLO 的作者提炼出一个更大的 ResNet 模型作为主干。一个更好的预训练模型也能改善下游迁移学习。
# PP-YOLO 是最先进的吗?
PP-YOLO 胜过结果 [YOLOv4 发表于](https://arxiv.org/pdf/2004.10934.pdf)2020 年 4 月 23 日。
公平地说,作者指出这可能是一个错误的问题。作者的意图似乎不仅仅是“引入一种新的新型检测器”,而是展示仔细调整对象检测器以最大化性能的过程。这里引用论文的引言:
> 本文的重点是如何堆叠一些几乎不影响效率的有效技巧,以获得更好的性能……本文无意介绍一种新颖的对象检测器。它更像是一个食谱,告诉你如何一步一步地建造一个更好的探测器。我们发现了一些对 YOLOv3 检测器有效的技巧,可以节省开发人员试错的时间。**最终的 PP-YOLO 模型将 COCO 上的 mAP 从 43.5%提高到 45.2%,速度比 YOLOv4**
*(强调我们的)*
上面提到的 PP-YOLO 贡献将 YOLOv3 模型在 COCO 对象检测任务上的 mAP 从 38.9 提高到 44.6,并将推断 FPS 从 58 提高到 73。这些指标显示在论文中,以击败当前发布的 YOLOv4 和 EfficientDet 的结果。
在将 PP-YOLO 与 [YOLOv5](https://blog.roboflow.ai/yolov5-improvements-and-evaluation/) 进行对比时,似乎 [YOLOv5](https://blog.roboflow.ai/yolov5-improvements-and-evaluation/) 在 V100 上仍然具有最快的推理时间-精度性能(AP 与 FPS)权衡。然而,一篇 YOLOv5 论文仍有待发布。此外,已经表明,在 YOLOv5 Ultralytics 存储库上训练 YOLOv4 架构优于 YOLOv5,并且,使用 YOLOv5 贡献训练的 YOLOv4 将优于这里发布的 PP-YOLO 结果。这些结果仍有待正式发表,但可以追溯到[GitHub 讨论](https://github.com/ultralytics/yolov5/issues/6)。

[V100 GPU 上 COCO 数据集的 PP-YOLO 评估](https://arxiv.org/pdf/2007.12099.pdf)(注意 AP_50 列)

[V100 GPU 上 COCO 数据集的 YOLOv5 评估](https://blog.roboflow.ai/yolov5-improvements-and-evaluation/)(注意 AP_50 列)
值得注意的是,在 YOLOv4 中使用的许多技术(如架构搜索和数据扩充)并没有在 PP YOLO 中使用。这意味着,随着更多这些技术被组合和集成在一起,对象检测的技术水平仍有发展的空间。
不用说,实现计算机视觉技术是一个激动人心的时刻。
# 我应该从 YOLOv4 或者 YOLOv5 换成 PP-YOLO 吗?
PP-YOLO 模型展示了最先进的目标检测的前景,但是相对于其他目标检测器的改进是递增的,并且它是在一个新的框架中编写的。在这个阶段,最好的办法是通过在自己的数据集上训练 PP-YOLO 来得出自己的实证结果。(当您可以在数据集上轻松使用 PP-YOLO 时,我们会通知您,[订阅我们的新闻简报](https://roboflow.us5.list-manage.com/subscribe?u=26126ade12b1dd890dbd7b07e&id=3e926cf19a)。)
与此同时,我建议查看以下 YOLO 教程,让你的[物体探测器](https://blog.roboflow.com/the-ultimate-guide-to-object-detection/)离开地面:
* [如何在暗网训练 yolov 4](https://blog.roboflow.ai/training-yolov4-on-a-custom-dataset/)
* [如何在 PyTorch 中训练 yolov 5](https://blog.roboflow.ai/how-to-train-yolov5-on-a-custom-dataset/)
一如既往——快乐训练!
# 实用人工智能:使用 BERT Summarizer、Wordnet 和 Conceptnet 从任何内容中自动生成选择题
> 原文:<https://towardsdatascience.com/practical-ai-automatically-generate-multiple-choice-questions-mcqs-from-any-content-with-bert-2140d53a9bf5?source=collection_archive---------6----------------------->
> **如果你想在行动中尝试 MCQ 一代的现场演示,请访问 https://questgen.ai/**[](https://questgen.ai/)
****
**MCQs —图片来自 Pixabay**
**在本帖中,我们将看到如何从任何故事或文章中自动生成选择题。这是朝着自动生成你在初中/高中看到的 mcq 迈出的一步。**
****输入:**我们程序的**输入**将是一篇文章(下面 github 库中提供的示例文章),如下所示**
The Greek historian knew what he was talking about. The Nile River fed Egyptian civilization for hundreds of years. The Longest River the Nile is 4,160 miles long — the world’s longest river. It begins near the equator in Africa and flows north to the Mediterranean Sea ..............
****输出:****
- The Nile provided so well for _______ that sometimes they had surpluses, or more goods than they needed.
a ) Angolan
b ) Algerian
c ) Egyptians
d ) Bantu
More options: ['Basotho', 'Beninese', 'Berber', 'Black African', 'Burundian', 'Cameroonian', 'Carthaginian', 'Chadian', 'Chewa', 'Congolese', 'Djiboutian', 'Egyptian', 'Ethiopian', 'Eurafrican', 'Ewe', 'Fulani']
- As in many ancient societies, much of the knowledge of _______ came about as priests studied the world to find ways to please the gods.
a ) Malawi
b ) East Africa
c ) Somalia
d ) Egypt
More options: ['Togo', 'Zimbabwe', 'Gabon', 'Ghana', 'Lake Tanganyika', 'Ottoman Empire', 'Mozambique', 'Iran', 'Israel', 'Saudi Arabia', 'Lebanon', 'Turkey', 'Iraq', 'Levant', 'Syria', 'Jordan']
- The _______ provided so well for Egyptians that sometimes they had surpluses, or more goods than they needed.
a ) Nyala
b ) Omdurman
c ) Nile
d ) Port Sudan
More options: ['Khartoum', 'Nubian Desert', 'Darfur', 'Libyan Desert', 'Kordofan', 'Gulu', 'Buganda', 'Entebbe', 'Jinja', 'Lake Edward', 'entebbe', 'gulu', 'kayunga', 'Upper Egypt', 'Suez Canal', 'Aswan High Dam']
**让我们开始看看如何利用最新的自然语言处理技术构建自己的 MCQ 生成器。**
> *****如果您想现场试用先进的 MCQ 发电机,请访问***[](https://questgen.ai/)**
***所有的代码和 jupyter 笔记本都可以在-***
***[](https://github.com/ramsrigouthamg/Generate_MCQ_BERT_Wordnet_Conceptnet) [## ramsrigouthamg/Generate _ MCQ _ 伯特 _ 文字网 _ 概念网
### 使用 BERT 摘要、Wordnet 和…从任何内容或新闻文章中生成选择题
github.com](https://github.com/ramsrigouthamg/Generate_MCQ_BERT_Wordnet_Conceptnet)
首先在 jupyter 笔记本中安装必要的库。如果您遇到任何错误,只需修改版本并检查其他不兼容之处:
!pip install gensim
!pip install git+https://github.com/boudinfl/pke.git
!python -m spacy download en
!pip install bert-extractive-summarizer --upgrade --force-reinstall
!pip install spacy==2.1.3 --upgrade --force-reinstall
!pip install -U nltk
!pip install -U pywsdimport nltk
nltk.download('stopwords')
nltk.download('popular')
# 伯特萃取摘要器
这里我们使用一个简单的库 Bert-extract-summarizer 为我们完成这项工作。我们从 Github repo 中的 egypt.txt 文件加载全部文本,并请求库给我们摘要文本。您可以使用比率、最大和最小句子长度等参数进行总结
from summarizer import Summarizerf = open("egypt.txt","r")
full_text = f.read()model = Summarizer()
result = model(full_text, min_length=60, max_length = 500 , ratio = 0.4)summarized_text = ''.join(result)
print (summarized_text)
我们得到原始文本的摘要部分作为输出:
The Nile River fed Egyptian civilization for hundreds of years. It begins near the equator in Africa and flows north to the Mediterranean Sea. A delta is an area near a river’s mouth where the water deposits fine soil called silt.......................
# **提取关键词**
我们使用 python 关键字提取器(PKE)库,从原文中提取所有重要的关键字。然后只保留那些出现在摘要文本中的关键词。这里我只提取名词,因为它们更适合 mcq。此外,我只提取 20 个关键字,但你可以用这个参数(get_n_best)来玩。
**输出**为-
Original text keywords: ['egyptians', 'nile river', 'egypt', 'nile', 'euphrates', 'tigris', 'old kingdom', 'red land', 'crown', 'upper', 'lower egypt', 'narmer', 'longest river', 'africa', 'mediterranean sea', 'hyksos', 'new kingdom', 'black land', 'ethiopia', 'middle kingdom']Keywords present in summarized text: ['egyptians', 'nile river', 'egypt', 'nile', 'old kingdom', 'red land', 'crown', 'upper', 'lower egypt', 'narmer', 'africa', 'mediterranean sea', 'new kingdom', 'middle kingdom']
# 句子映射
对于每个关键词,我们将从摘要文本中提取出包含该词的相应句子。
样本**输出**为—
{'egyptians': ['The Nile provided so well for Egyptians that sometimes they had surpluses, or more goods than they needed.', 'For example, some ancient Egyptians learned to be scribes, people whose job was to write and keep records.', 'Egyptians believed that if a tomb was robbed, the person buried there could not have a happy afterlife.', 'nile river': ['The Nile River fed Egyptian civilization for hundreds of years.'], 'old kingdom': ['Historians divide ancient Egyptian dynasties into the Old Kingdom, the Middle Kingdom, and the New Kingdom.', 'The Old Kingdom started about 2575 B.C., when the Egyptian empire was gaining strength.'], } .....................
# **生成 MCQ**
在这里,我们从 Wordnet 和 Conceptnet 获得干扰物(错误答案选择),以生成我们的最终 MCQ 问题。
什么是干扰物(错误答案选择)?
如果让我们说*“历史学家将古埃及王朝分为旧王国、中王国和新王国。”*是我们的句子,我们希望将“埃及人”作为空白关键字,那么其他错误答案选项应该类似于埃及人,但不是埃及人的同义词。
Eg: Historians divide ancient __________ dynasties into the Old Kingdom, the Middle Kingdom, and the New Kingdoma)Egyptian
b)Ethiopian
c)Angolian
d)Algerian
在上述问题中,选项 b)、c)和 d)是干扰项。
我们如何自动生成这些干扰物?
我们采取两种方法一种是用 wordnet,另一种是用 conceptnet 来获取干扰物。
> **我们代码中使用的 Wordnet 方法:**
给定作为句子和关键字的输入,我们首先获得单词的“意义”。
我用一个例子用“感”来解释一下。如果我们有一个句子“蝙蝠飞入丛林并降落在树上”和一个关键字“蝙蝠”,我们会自动知道这里我们谈论的是有翅膀的哺乳动物蝙蝠,而不是板球拍或棒球棒。尽管我们人类擅长于此,但算法并不擅长区分两者。这被称为词义消歧(WSD)。在 wordnet 中,“蝙蝠”可能有几个意思,一个是指板球拍,一个是指会飞的哺乳动物等等。因此函数 **get_wordsense** 试图获得给定句子中单词的正确含义。这并不总是完美的,因此如果算法缩小到一个错误的意义上,我们会得到一些错误。那么干扰物(错误的答案选择)也会是错误的。
一旦我们确定了这个感觉,我们就调用 **get_distractors_wordnet** 函数来获取干扰物。这里发生的事情是,假设我们得到一个像“ **cheetah** ”这样的词,并确定它的意义,然后我们去它的上位词。一个**上位词**是一个给定单词的更高层次的类别。在我们的例子中,猫科动物是猎豹的上位词。
然后我们去寻找所有属于猫科动物的**猫科动物**的下位词(子类),可能是豹、老虎、狮子。因此,对于给定的 MCQ,我们可以使用豹子、老虎、狮子作为干扰物(错误答案选项)。
> **我们代码中使用的概念网方法:**
不是所有的单词都可以在 wordnet 中找到,也不是所有的单词都有上位词。因此,如果我们在 wordnet 上失败了,我们也会在 conceptnet 上寻找干扰物。**get _ distractors _ conceptnet**是用来从 concept net 中获取干扰项的主要函数。Conceptnet 并没有像我们在上面讨论 bat 的例子那样提供不同词义之间的区分。因此,当我们用一个给定的词进行查询时,我们需要继续使用 conceptnet 给我们的任何意义。
让我们看看如何在用例中使用 conceptnet。我们不安装任何东西,因为我们直接使用 conceptnet API。请注意,有一个每小时的 API 率限制,所以要小心。
给定一个像“California”这样的词,我们用它查询 conceptnet 并检索关系的“**部分。在我们的例子中,“加利福尼亚”是“美国”的一部分。**
现在我们去“美国”,看看它和其他什么事物有“部分”关系。那将是其他州,如“得克萨斯”、“亚利桑那”、“西雅图”等。因此,对于我们的查询词“加利福尼亚”,我们取出了干扰词“德克萨斯”、“亚利桑那”等
最后,我们生成如下输出:
#############################################################################
NOTE:::::::: Since the algorithm might have errors along the way, wrong answer choices generated might not be correct for some questions.
#############################################################################
- The Nile provided so well for _______ that sometimes they had surpluses, or more goods than they needed.
a ) Angolan
b ) Algerian
c ) Egyptians
d ) Bantu
More options: ['Basotho', 'Beninese', 'Berber', 'Black African', 'Burundian', 'Cameroonian', 'Carthaginian', 'Chadian', 'Chewa', 'Congolese', 'Djiboutian', 'Egyptian', 'Ethiopian', 'Eurafrican', 'Ewe', 'Fulani']
- As in many ancient societies, much of the knowledge of _______ came about as priests studied the world to find ways to please the gods.
a ) Malawi
b ) East Africa
c ) Somalia
d ) Egypt
More options: ['Togo', 'Zimbabwe', 'Gabon', 'Ghana', 'Lake Tanganyika', 'Ottoman Empire', 'Mozambique', 'Iran', 'Israel', 'Saudi Arabia', 'Lebanon', 'Turkey', 'Iraq', 'Levant', 'Syria', 'Jordan']
- The _______ provided so well for Egyptians that sometimes they had surpluses, or more goods than they needed.
a ) Nyala
b ) Omdurman
c ) Nile
d ) Port Sudan
More options: ['Khartoum', 'Nubian Desert', 'Darfur', 'Libyan Desert', 'Kordofan', 'Gulu', 'Buganda', 'Entebbe', 'Jinja', 'Lake Edward', 'entebbe', 'gulu', 'kayunga', 'Upper Egypt', 'Suez Canal', 'Aswan High Dam']
- It combined the red _______ of Lower Egypt with the white _______ of Upper Egypt.
a ) Capital
b ) Crown
c ) Masthead
d ) Head
More options: []
- It combined the red Crown of Lower Egypt with the white Crown of _______ Egypt.
a ) Upper Berth
b ) Lower Berth
c ) Upper
More options: []
请注意,由于从 Wordnet 词义消歧(WSD)算法中提取的单词的错误含义,或者由于其局限性 conceptnet 用不同的含义识别它,可能会有许多错误。
# **可以改进的东西?**
1. 就像关系中的**部分一样,在概念网中存在 **IsA** 关系,可以进一步探索以获得干扰物。**
您可以将这些用于 **IsA 关系-**
query URL = "[http://api.conceptnet.io/query?node=%s&rel =/r/IsA&end = % s&limit = 10](http://api.conceptnet.io/query?node=%s&rel=/r/IsA&end=%s&limit=10)"(link,link)
检索 URL = "[http://api.conceptnet.io/query?node=/c/en/%s/n&rel =/r/IsA&start =/c/en/% s&limit = 5](http://api.conceptnet.io/query?node=/c/en/%s/n&rel=/r/IsA&start=/c/en/%s&limit=5)"(word,word)
**2。**因为每个关键词有多个句子,所以使用所有句子进行词义消歧(WSD ),并选择具有最高计数的词义。
**3。**可以替代地使用单词向量(word2vec,glove)作为给定单词的干扰子的方式。
**4。**在将全文传递给 BERT summarizer 之前,可以对其使用代词消解(神经共指消解)。然后,任何带有代词的句子都应被解析,这样当以 MCQ 的形式呈现时,它看起来完整而独立。***
***祝 NLP 探索愉快,如果你喜欢它的内容,请随时在 Twitter 上找到我。***
***如果你想学习使用变形金刚的现代自然语言处理,看看我的课程[使用自然语言处理生成问题](https://www.udemy.com/course/question-generation-using-natural-language-processing/?referralCode=C8EA86A28F5398CBF763)***
# 实用人工智能:以一种新颖的方式使用 NLP 单词向量来解决本地化问题
> 原文:<https://towardsdatascience.com/practical-ai-using-nlp-word-vectors-in-a-novel-way-to-solve-the-problem-of-localization-9de3e4fbf56f?source=collection_archive---------43----------------------->
## 你将会看到单词嵌入(word2vec,glove 等)的最实际的用法。

作者图片
## 国王——男人+女人=王后
你可能见过传统的 **word2vec** 或 **Glove** word 嵌入示例,显示**国王+女人=王后**。这里 **Queen** 将从给定单词 **King** 、 **Man** 和 **Woman** 的单词嵌入算法中返回。今天我们将看看如何使用这种结构来解决现实世界中的问题。
# **1。问题定义:**

来自[Flaticon.com](https://www.flaticon.com/)的图标
美国**的一家 **edtech** 公司**在印度本土市场取得成功**后,想把业务扩展到印度**。在他们的**题库**中有一大套问题,它希望在进入印度市场时使用。****
但是有一个大问题。他们题库里的一个样本**三等**(年级)**数学题**是这样的——
> 弗兰克住在旧金山,伊丽莎白住在 T42。如果飞行时间是 **2 小时**如果早上**8 点**开始**伊丽莎白**什么时候到达**弗兰克**?
一个住在印度的三年级孩子**不会**回答这个问题,因为这个问题涉及到**的名字**和**的地点**他/她不太知道的- **弗兰克**、**旧金山**、**洛杉矶、**等等。
因此,如果我们改变这个问题以适应印度的环境,并重新表述它,那将是理想的
> 桑杰·维尔马住在班加罗尔,瑞哈住在孟买。如果飞行时间是 2 小时,那么如果瑞哈早上 8 点出发,她什么时候到达桑杰·维尔马?
这个概念叫做 [**汉化**](https://en.wikipedia.org/wiki/Language_localisation) 。这是**将**一种**产品**或想法带到不同的**国家或地区**的一般概念,尊重当地**规范**,习俗,以及任何其他**偏好**。我们的目标是与**目标受众**产生共鸣,因为内容是**本地化的**。

作者图片
# 2.单词嵌入法:
现在让我们看看如何将我们最初的美国数学问题本地化到印度的环境中。
> 弗兰克住在旧金山,伊丽莎白住在洛杉机。如果飞行时间是 **2 小时**如果早上**8 点**开始**伊丽莎白**什么时候到达**弗兰克**?
**步骤 2.1:** 我们的目标是提取所有需要**本地化**的**关键词**。我们将使用空间命名实体识别来实现这一点。

提取的命名实体
**步骤 2.2:** 过滤掉与**不相关的命名实体**。例如,像数字(基数)和时间这样的实体在我们的例子中不需要本地化。
**过滤后的实体:**弗兰克,旧金山,伊丽莎白,洛杉矶
最有趣的部分来了。我们将使用 **King-Man + Woman = Queen** 框架来转换每个实体。代码将出现在接下来的章节中,但这里我们只展示概念。
Frank-USA+India = Sanjay Verma
San Franciso-USA+India = Bangalore
Elizabeth-USA+India = Rekha
Los Angeles-USA+India = Mumbai
**第 2.4 步:**我们回过头来,用它们的替换物来改变实体,得到-
> 桑杰·维尔马住在班加罗尔,瑞哈住在孟买。如果飞行时间是 2 小时,如果瑞哈早上 8 点开始,她什么时候到达桑杰·维尔马?
# 3.说够了,给我看看代码:)
[](https://colab.research.google.com/drive/1oGqwDgDgtBeiXoeaq1uvX-_KxLY8FzXp?usp=sharing) [## 谷歌联合实验室
### 编辑描述
colab.research.google.com](https://colab.research.google.com/drive/1oGqwDgDgtBeiXoeaq1uvX-_KxLY8FzXp?usp=sharing)
查看完整干净的 [Google Colab 笔记本](https://colab.research.google.com/drive/1oGqwDgDgtBeiXoeaq1uvX-_KxLY8FzXp?usp=sharing),它展示了两个不同的本地化示例。**第一个例子**是**自动**第二个**有**简单 UI** 手动选择最佳**替换**。**
重要的部分再次在代码中显示(除了 Colab)
**步骤 3.1 提取需要本地化的实体**
import spacy
import pandas as pd
from spacy import displacy
from spacy.tokens import Span
nlp = spacy.load("en")original_input = "Frank lives in San Francisco and Elizabeth lives in Los Angeles. If the flight time is 2 hrs when will Elizabeth reach Frank if she starts at 8am in the morning?"
processed_input_text=nlp(original_input)
keyword_set = set()
entity_mapping = []
for token in processed_input_text.ents:
if token.text not in keyword_set:
keyword_set.add(token.text )
entity_mapping.append((token.text,token.label_))
print (entity_mapping)
displacy.render(processed_input_text, style='ent', jupyter=True)# Now all entities cannot be localized. Example no need to localize numbers. So keep only relevant entities that need to be localized.
keep_entities_list = ['PERSON','GPE','FAC','ORG','PRODUCT','NORP','MONEY','LOC','WORK_OF_ART','LAW','LANGUAGE','QUANTITY']
finalized_entity_mapping = {}
for ent in entity_mapping:
if ent[1] in keep_entities_list:
finalized_entity_mapping[ent[0]] = []print (finalized_entity_mapping)
上述步骤的**输出**为—
Unfiltered entities:
[('Frank', 'PERSON'), ('San Francisco', 'GPE'), ('Elizabeth', 'PERSON'), ('Los Angeles', 'GPE'), ('2', 'CARDINAL'), ('8am in the morning', 'TIME')]Entities after filtering: {'Frank': [], 'San Francisco': [], 'Elizabeth': [], 'Los Angeles': []}
**步骤 3.2 初始化来自 Gensim 的 Google 新闻词向量并执行本地化**
import gensim.downloader as api
model = api.load("word2vec-google-news-300")
word_vectors = model.wvOrigin_country='USA'
Target_country='India'final_mapping ={}for word in finalized_entity_mapping:
word = word.strip()
word = word.replace(" ","")
try:
similar_words_list= model.most_similar(positive=[Target_country,word],negative=[Origin_country],topn=10)
# Remove the scores for the retrieved choices
similar_words_list = [choices[0].replace(""," ") for choices in similar_words_list ]
final_mapping[word.replace("_"," ")] = similar_words_list
except:
similar_words_list = []
print (" Fetching similar words failed for ",word)
print (word," -- Replacement suggestions -- ",similar_words_list)
上述步骤的**输出**为—
Frank -- Replacement suggestions -- ['Sanjay Verma', 'Sabyasachi Sen', 'JK Jain', 'Sunil Chauhan', 'Don', 'Sudip', 'Ajay Shankar', 'Robert', 'V. Srinivasan', 'Kanwar Sain']San_Francisco -- Replacement suggestions -- ['Bangalore', 'Kolkata', 'Mumbai', 'Chennai', 'Delhi', 'Hyderabad', 'Calcutta', 'San Franciso', 'Bombay', 'Bengaluru']Elizabeth -- Replacement suggestions -- ['Rekha', 'Nandita', 'Meera', 'Margaret', 'Katharine', 'Bhagirath', 'Monica', 'Lakshmi', 'Manisha', 'Anita']Los_Angeles -- Replacement suggestions -- ['Mumbai', 'Los Angles', 'Kolkata', 'Chennai', 'Bangalore', 'LA', 'Delhi', 'Hyderabad', 'Ahmedabad', 'Calcutta']
您可以看到每个单词及其首选替换选项。
**步骤 3.3 打印替换输出**
def localize(sentence,mapping):
for k in mapping:
sentence = sentence.replace(k,mapping[k][0])
return sentenceprint('Original Sentence:')
print(original_input)localized_string = localize(original_input,final_mapping)print('\nLocalized Sentence:')
print(localized_string)
输出是—
Original Sentence:
Frank lives in San Francisco and Elizabeth lives in Los Angeles. If the flight time is 2 hrs when will Elizabeth reach Frank if she starts at 8am in the morning?Localized Sentence:
Sanjay Verma lives in Bangalore and Rekha lives in Mumbai. If the flight time is 2 hrs when will Rekha reach Sanjay Verma if she starts at 8am in the morning?
太好了!我们终于在附近**到达终点**。
但是如果显示的第一选择**不是给定单词的正确替换**呢?
为了解决这个问题,我们构建了一个小的 **UI** ,通过下拉菜单选择正确的选项。它显示在 Google Colab 笔记本的**示例 2 下。**

选择正确单词的用户界面
这个项目是由令人敬畏的实习生 Niharika Reddy 在我的指导下进行的,作为我的开源计划的一部分
## 基于群组的实时课程:自然语言处理的实用介绍
我正在和世界上最好的群组学习平台 Maven 一起进行为期 4 周的群组课程[“NLP 实用入门”](https://maven.com/ramsri/practical-introduction-to-nlp)。如果你希望在 4 周内将自己从一名 Python 开发人员转变为一名具有实际项目经验的初级 NLP 开发人员,[现在就抓住你的位置](https://maven.com/ramsri/practical-introduction-to-nlp)!
# 使用自然语言处理的问题生成——教程
我推出了一个非常有趣的 Udemy 课程,名为“使用 NLP 生成问题”,扩展了这篇博文中讨论的一些技术。如果你想看一看,这里是[链接](https://www.udemy.com/course/question-generation-using-natural-language-processing/?referralCode=C8EA86A28F5398CBF763)。
祝 NLP 探索愉快,如果你喜欢它的内容,请随时在[推特上找到我。](https://twitter.com/ramsri_goutham)
# 商业中的实用人工智能
> 原文:<https://towardsdatascience.com/practical-artificial-intelligence-in-business-a75066030692?source=collection_archive---------52----------------------->
## 商业可以通过了解 AI 是如何完成的来有效地使用 AI。
商业中的人工智能是实用的。当您考虑神经网络时,不要考虑抽象的数学结构,而是需要数据来学习业务流程以及如何在其中操作的计算机系统。

商业中的实用人工智能
# 商业中的数据科学和实用人工智能
数据科学不是一门真正的科学,它是一个实验领域,你需要不断地调整、测试、从头构建原型并重建你所拥有的。这是一个解决问题的框架,而不是一套特定的工具。这种使用神经网络的范例,类固醇上的统计数据,使得人工智能在实践和理论上都很复杂,具有如此广泛的应用,我们将在下一章中讨论。
那么数据科学或者人工智能目前是怎么做的呢?你可以将实际工作分成两部分,这两部分紧密相连:
* 履行
* 研究
实施阶段的重点是为特定的业务问题提供切实可行的解决方案。通过使用来自组织内部的数据,数据科学家实施机器学习模型来学习这些数据。这一阶段主要关注数据科学的工程方面:
* 清理数据
* 特征抽出
* 统计分析
* 训练神经网络
* 设置虚拟机和一般环境。
研究阶段是寻找可能的调整、改进或现有方法的全新方法。它可能包括阅读科学论文、其他组织的白皮书、浏览 Github 上的开源代码、与机器学习工程师同事交谈、参加会议。目标是拓宽视野,找到新的战略来实施。
一般来说,实现和研究哪个先来是不可能的,因为数据科学家的第一步通常是构建第一个简单的模型,看看它如何处理给定的数据,然后寻找其他方法和增强。对于更难和更有吸引力的项目,机器学习工程师可能会从研究开始,阅读在网络上可能找到的主题,然后选择几个模型来实现和尝试。
然而,数据科学家花在计算机前的大部分时间,无论是阅读、编写代码还是训练机器学习模型。**在企业中经常被误解的是,传统软件开发中通常的冲刺(精益启动方法)并不总是有利于找到需要深入思考的更复杂问题的解决方案**。这就是为什么谷歌的 20%规则,允许 20%的休息时间去做软件工程师自己的项目,是如此富有成效。数据科学家需要修补和摆弄想法,以提高他们的创造力。
# *人工智能研究*
人工智能研究社区可以分为三个部分:
* 机器学习社区
* 道德与社会团体
* 工商业界
机器学习社区主要关注与构建机器学习模型相关的研究问题:从架构、数据到实现。计算机科学或 STEM 领域的博士学位是积极参与的必要条件。
伦理与社会社区关注人工智能研究和实践中应用的社会分支:从立法到人工智能研究目标的重要问题或限制。这个社区的人经常在大学的社会系、智库或者公共机构工作。
商业社区专注于将前沿研究应用于商业问题。这些领域可能包括制造业、药物设计、网络安全、视频游戏等。这里的研究人员大多在大型机构的研究实验室工作。在这些领域找工作时,博士学位不是必须的,但往往是一个额外的优势。
# 人工智能的研究生涯
如果一个人想成为人工智能的研究人员,标准的道路是通过大学,攻读计算机科学博士学位,然后成为助理教授或研究员。由于最近研究工作方式的变化,例如亚马逊、脸书、谷歌和类似的大型科技公司如何参与研究,新鲜出炉的博士直接进入在他们的研究实验室工作的科技巨头之一的情况经常发生。也有可能他们同时攻读博士学位并在这些公司中的一家工作,这对双方都有利:一家公司赞助一名博士,大学免除了费用,一名博士生有一份工作并做一些与行业相关的事情。
PhD 本身是一部讨论和解决一个公开问题或某个案例的专著,在已经确定的问题中使用新的方法,或者发明与现有知识相关的新问题。有些话题在特定时间比其他话题更流行,这与特定教授的兴趣或市场兴趣(钱在哪里)有关。通常在攻读博士学位期间,一个学生发表几篇论文,这些论文构成了博士论文的主体。
**从一个博士生的角度来看,最重要的是找到一个能接触到有趣问题、资金和研究小组的好导师。**有趣的问题将使他进行有意义的研究,资金将使他能够参加会议并在基础设施上花费很多,研究小组将是研究讨论的无价之宝。
参加会议是与科学家同事联系的好方法。最受欢迎和最负盛名的机器学习会议是 NIPS,神经信息处理系统年会。向 NIPS 提交论文的科学家数量每年增长 30%,这也显示了机器学习社区目前有多么活跃。
# 吸引人工智能人才到企业
从与学术界争夺人才的商业角度来看,关键的方面是创造一个充满活力的研究环境。分配空闲时间做任何研究都是一个好的解决方案,但关键是围绕该领域的资深人物建立一个研究小组。通常情况下,大型组织会从机器学习系聘请一名教授和他的博士生,作为快速启动研究社区的一种方式。例如,这就是优步从卡耐基梅隆大学机器人系挖人的做法。
对于银行或保险公司这样的老牌机构来说,一个大问题是以一种有吸引力的方式向潜在的机器学习员工展示自己。这里最关键的是要理解,吸引研究人员的是能够创新,有思想自由,开放的氛围和手头要解决的难题。没有人想一直被线性回归困住。提出太难的问题往往比提出太容易的问题更能吸引人才。
在 Kaggle(【www.kaggle.com】)上可以看到一个好问题的很好的例子,在那里,公司为他们的业务问题举办数据科学挑战,并为最佳参赛作品设置奖项。通常这些比赛有成千上万的队伍参加。其中最著名的一次是由[网飞](https://www.kaggle.com/netflix-inc/netflix-prize-data)举办的一次竞赛,旨在改进他们的推荐算法。该竞赛的奖金为 100 万美元,吸引了大量观众,让网飞成为一家优秀科技公司的候选人,并为网飞提供了许多与他们的业务运营相关的新研究成果。
# *开源社区*
从商业角度来看,机器学习中的开源社区很重要,但仍未被商业充分利用。许多研究成果在 GitHub 上是免费的,这是一个代码库,你可以拿起它,和其他部分一起使用,来构建你需要的独特的东西。从来没有建造一个原型像现在这样快速和便宜。开源社区也是潜在雇员的一个很好的来源,因为它准确地显示了一个人的能力。
从商业的角度来看,支持开源社区有很多好处:获得人才库,了解当前的研究。此外,它还能带来商机。回想一下 Red Hat 的模式,它负责维护 Linux,然后通过支持和定制来赚钱。最终,Red Hat 被 IBM 收购,这是迄今为止最大的技术收购之一,2019 年以 340 亿美元的价格完成。
GitHub 本身在 2018 年被微软以 75 亿美元收购,Kaggle 在 2017 年被谷歌收购。这不仅显示了开源社区对商业的重要性,而且实际上,如果你能够交付一个伟大的产品,并围绕它建立一个参与用户社区,你就可以通过开源努力来做生意。
# *从研究到应用*
讨论了人工智能的研究是如何进行的,现在是时候关注应用了。假设您已经有了一个数据科学团队,并且对您想要解决的问题进行了初步研究,下一步就是收集和清理数据。如果您的大部分业务都是数字化的,可以方便地访问数据,那么这个过程可能会很短;如果您有许多来源要查看,并且数据远非干净(比如,以各种格式进行的客户调查),那么这个过程可能会很长而且很痛苦。如果是这样的话,预处理本身就是一项任务,需要一个单独的团队来完成。这对以后的所有工作都特别重要,所以**不要忽视清洗数据。**
将研究应用于业务应用意味着对来自您业务的数据使用机器学习模型,并衡量它们的表现与您通常解决手头问题的方式相比如何(例如,在业务流程、营销/销售、相关线索数量上花费的时间)。在收到数据后,你的机器学习工程师团队将制定衡量进展的指标,并开始实施(编码)机器学习算法,用你提供的数据填充它们。最终结果将是预测的准确性、自动化的业务流程或优化的计算。
**在实施阶段至关重要的是要有好的指标来比较模型(架构)、机器(基础设施)和用于培训和评估的数据。**理解结果为何如此与获得产生最佳结果的模型同等重要。
将解决方案扩展到更多数据并在生产中使用模型通常需要比机器学习人才更多的工程技术,因此需要雇用不同于研究阶段的人才库。然而,由于实施和研究是紧密结合的,最好是让研究人员和工程师一起密切合作。
**总结一下,商业中实用的人工智能是通过以下循环完成的:**
1. **研究可能的机器学习模型**
2. **收集数据**
3. **使用模型收集数据**
4. **改善基础设施、数据和规模**
在步骤 4 之后,我们再次回到步骤 1,有了关于模型在实践中如何工作以及哪些方面可以改进的反馈,研究人员可以寻找新的算法和方法来解决手头的问题。重复整个循环,直到满足流程开始时定义的指标。这就是为什么一开始就为机器学习实验建立一个框架是很重要的,即使它们后来会随着新的实验而改变。
这段文字摘自我即将出版的新书**人工智能商业**。[我之前的书关注的是找一份数据科学的工作](https://amzn.to/31jXMAS)。
# 用 Python 实现机器学习的特征工程
> 原文:<https://towardsdatascience.com/practical-code-implementations-of-feature-engineering-for-machine-learning-with-python-f13b953d4bcd?source=collection_archive---------23----------------------->

使用 Python 进行机器学习的特征工程—图片来自 [Pixabay](https://pixabay.com/de/photos/arbeit-eingabe-computer-notebook-731198/)
据 [Forbes](https://www.forbes.com/sites/gilpress/2016/03/23/data-preparation-most-time-consuming-least-enjoyable-data-science-task-survey-says/?sh=23cce0296f63) 报道,数据科学家和机器学习工程师花费大约 **60%** 的时间在训练机器学习模型**之前准备数据。大部分时间花在了特性工程上。**
特征工程是转换和创建可用于训练机器学习模型的特征的过程。特征工程对于训练精确的机器学习模型至关重要,但通常具有挑战性并且非常耗时。
特征工程包括输入缺失值、编码分类变量、转换和离散化数值变量、删除或审查异常值、缩放特征等。
在本文中,我将讨论机器学习的特征工程的 Python 实现。我比较了以下开源 Python 库:
* [Scikit-learn](https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing)
* [特征引擎](https://feature-engine.readthedocs.io/en/latest/)
* [类别编码器](https://pypi.org/project/category-encoders/)
我将展示要执行的代码:
* 缺失数据插补
* 分类编码
* 变量变换
* [数]离散化
# 特征工程管道
大多数特征工程技术从数据中学习参数。例如,为了用平均值估算数据,我们从训练集中获取平均值。为了对分类变量进行编码,我们还利用训练数据定义了字符串到数字的映射。
许多开源 Python 包具有学习和存储设计特性的参数的功能,然后检索它们来转换数据。
特别是, [Scikit-learn](https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing) 、 [Feature-engine](https://feature-engine.readthedocs.io/en/latest/) 和[类别编码器](https://pypi.org/project/category-encoders/)共享了从数据中学习参数的方法 *fit* 和修改数据的方法 *transform* 。
Pandas 也有很多功能工程和数据准备的工具。然而,它缺乏存储学习参数的功能。正因如此,本文就不谈论熊猫了。
# 用于要素工程的 Python 库
[Scikit-learn](https://scikit-learn.org/stable/modules/preprocessing.html#preprocessing) 、 [Feature-engine](https://feature-engine.readthedocs.io/en/latest/) 和[类别编码器](https://pypi.org/project/category-encoders/)共享 *fit* 和 *transform* 功能,从数据中学习参数,然后转换变量。
然而,这些软件包在 I)输出、ii)输入和 iii)通用性方面存在一些差异。

用于要素工程的 Python 包之间的主要差异-由作者创建
## 输出:NumPy 数组对 Pandas 数据帧
特征引擎和分类编码器返回熊猫数据帧。Scikit-learn 返回 NumPy 数组。
NumPy 数组针对机器学习进行了优化,因为 NumPy 的计算效率更高。熊猫数据框架更适合数据可视化。
通常,我们希望了解特征工程转换如何影响变量分布以及它们与其他变量的关系。Pandas 是一个很好的数据分析和可视化工具,因此,返回 Pandas 数据帧的库在本质上对数据分析更“友好”。
如果我们选择使用 Scikit-learn,我们可能需要添加一两行代码来将 NumPy 数组转换成 Pandas 数据帧,以便继续进行数据可视化。
## 输入:数据切片与完整数据集
数据科学家对不同的变量子集应用不同的特征工程方法。
例如,我们只估算缺失数据的变量,而不是整个数据集。我们将对数字变量采用某些插补方法,对类别变量采用其他方法。
Python 库提供了选择我们想要转换的变量的可能性。
使用[特征引擎](https://feature-engine.readthedocs.io/en/latest/)和[类别编码器](https://pypi.org/project/category-encoders/),我们选择要在转换器中转换的变量。
使用 Scikit-learn,我们需要使用一个特殊的转换器将数据集分割成所需的变量组。我们可以通过使用[的 ColumnTransformer](https://scikit-learn.org/stable/modules/generated/sklearn.compose.ColumnTransformer.html) 或者 Feature-engine 的 [SklearnWrapper](https://feature-engine.readthedocs.io/en/latest/wrappers/Wrapper.html) 来实现。使用 Feature-engine 的 [SklearnWrapper](https://feature-engine.readthedocs.io/en/latest/wrappers/Wrapper.html) 的美妙之处在于输出是一个熊猫数据帧!
## 多才多艺
有时,我们不知道哪种转换技术返回的预测变量最多。应该做等宽还是等频离散化?我们应该用平均值、中间值还是任意数来估算?
大多数 Scikit-learn 转换器是集中式的,这意味着一个转换器可以执行不同的转换。例如,我们可以通过简单地改变 Scikit-learn 中 KBinsDiscretizer()的参数来应用 3 种离散化技术。另一方面,特征引擎为离散化提供了 3 种不同的转换器。
插补也是如此;通过更改 SimpleImputer()的参数,我们可以使用 Scikit-learn 执行不同的插补技术,而 Feature-engine 有几个转换器,每个转换器最多可以执行 2 种不同的插补变量。
使用 Scikit-learn,我们可以轻松地对特征工程变压器的参数进行网格搜索。使用特征引擎,我们需要事先决定要使用哪种转换。
在博客的其余部分,我将比较 Scikit-learn、特征引擎和类别编码器中缺失数据插补、分类编码、数学转换和离散化的实现。
# 缺失数据插补
插补包括用缺失值的概率估计值替换缺失数据。缺失数据插补方法有多种,每种方法都有不同的用途。

缺少数据—图片由 [Willi Heidelbach](https://pixabay.com/de/users/wilhei-883152/) 从 [Pixabay](https://pixabay.com/de/photos/puzzle-passt-passen-fehlt-loch-693870/) 获得
如果你想了解更多关于这些技术,它们的优点和局限性,以及我们何时应该使用它们,请查看课程“[机器学习的特征工程](https://www.courses.trainindata.com/p/feature-engineering-for-machine-learning)”。
Scikit-learn 和 Feature-engine 支持许多数值和分类变量的插补程序。
两个库都包含最常见插补技术的功能:
* 均值和中位数插补
* 频繁类别插补
* 任意值插补
* 添加缺失的指标
特征引擎还可以执行:
* 随机样本插补
* 完整的案例分析
* 分布极值的插补
另一方面,Scikit-learn 在其功能中提供了链式方程 的 [**多元插补。**](https://scikit-learn.org/stable/modules/generated/sklearn.impute.IterativeImputer.html)
特征引擎转换器可以根据插补方法自动识别数值或分类变量。有了特征引擎,当我们估算数字变量或分类变量时,我们不会无意中添加一个字符串。使用 Scikit-learn,我们需要事先选择要修改的变量。
Scikit-learn 的 SimpleImputer(),只需调整*策略*和 *fill_value* 参数,即可执行所有插补技术。因此,我们可以自由地对插补技术进行网格研究,如 Scikit-learn 文档中的[代码实现所示。相反,特征引擎具有至少 5 个不同的插补转换器。](https://scikit-learn.org/stable/auto_examples/compose/plot_column_transformer_mixed_types.html)
在接下来的段落中,我们将首先进行中位数插补和最常见类别的插补。
# 均值/中位数插补
对于中位数插补,Feature-engine 提供了 MeanMedianImputer(),Scikit-learn 提供了 SimpleImputer()。
Feature-engine 的 MeanMedianImputer()自动选择训练数据集中的所有数值变量。另一方面,Scikit-learn 的 SimpleImputer()将转换数据集中的所有变量,如果在执行过程中有分类变量,它将产生一个错误。
## 特征引擎
下面,我们看到使用中位数作为插补的 [MeanMedianImputer()](https://feature-engine.readthedocs.io/en/latest/imputers/MeanMedianImputer.html) 的实现。简单地将*插补 _ 方法*的“中值”替换为“平均值”,即可实现平均值插补。
import pandas as pd
from sklearn.model_selection import train_test_split
from feature_engine.imputation import MeanMedianImputer
Load dataset
data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the imputer
median_imputer = MeanMedianImputer(
imputation_method='median',
variables=['LotFrontage', 'MasVnrArea']
)
fit the imputer
median_imputer.fit(X_train)
transform the data
train_t= median_imputer.transform(X_train)
test_t= median_imputer.transform(X_test)
特征引擎返回原始数据帧,其中只有数字变量被修改。欲了解更多详情,请访问 [MeanMedianImputer()文档](https://feature-engine.readthedocs.io/en/latest/api_doc/imputation/MeanMedianImputer.html#feature_engine.imputation.MeanMedianImputer)。
## sci kit-学习
使用[简单估算器()](https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html),我们还可以通过其参数指定均值或中值估算方法:
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
Load dataset
data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
Set up the imputer
median_imputer = SimpleImputer(strategy='median')
fit the imputer
median_imputer.fit(X_train[['LotFrontage', 'MasVnrArea']]) # transform the dataX_train_t = median_imputer.transform(
X_train[['LotFrontage', 'MasVnrArea']]
)X_test_t = median_imputer.transform(
X_test[['LotFrontage', 'MasVnrArea']]
)
如上所述,Scikit-learn 要求我们在将数据帧传递到插补转换器之前对其进行切片,而 Feature-engine 则不需要这一步。
前面代码块的结果是一个 NumPy 数组,其中有两个输入的数值变量。
# 频繁类别插补
频繁类别插补包括用变量的最频繁类别替换分类变量中的缺失值。
## 特征引擎
如果我们将插补方法参数设置为“频繁”,CategoricalImputer()会用其模式替换分类变量中的缺失数据。
我们可以指出要估算的变量,如下所示;否则,估算器将自动选择并估算训练数据集中的所有分类变量。
import pandas as pd
from sklearn.model_selection import train_test_split
from feature_engine.imputation import CategoricalImputer
Load dataset
data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the imputer
imputer = CategoricalImputer(
imputation_method=’frequent’,
variables=['Alley', 'MasVnrType']
)
fit the imputer
imputer.fit(X_train)
transform the data
train_t= imputer.transform(X_train)
test_t= imputer.transform(X_test)
结果是一个原始变量的数据框架,其中显示的变量是估算的。
## sci kit-学习
通过使用“最频繁”作为插补策略,[简单插补器()](https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html)也用于频繁类别插补。
请注意,SimpleImputer()的“最频繁”插补策略可以对数字变量和分类变量进行操作。所以我们需要非常小心。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
Load dataset
data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the imputer
mode_imputer = SimpleImputer(strategy='most_frequent')
fit the imputer
mode_imputer.fit(X_train[['Alley', 'MasVnrType']])
transform the data
X_train= mode_imputer.transform(
X_train[['Alley', 'MasVnrType']]
)X_test= mode_imputer.transform(
X_test[['Alley', 'MasVnrType']]
)
前面代码块的输出是一个 Numpy 数组,包含两列估算变量。
# 分类编码
机器学习模型需要数字格式的输入数据。因此,数据科学家需要将分类变量转换成数字变量。这些过程被称为分类变量编码。

分类变量以标签而不是数字作为值——来自 [Pixabay](https://pixabay.com/de/vectors/marke-weg-cartoon-label-holz-4802528/) 的 [Jozef Mikulcik](https://pixabay.com/de/users/jozefm84-10215106/) 举例说明。
有许多方法可以对分类变量进行编码。我们选择的编码方法完全是数据环境和业务问题驱动的;我们如何表示和设计这些特性会对模型的性能产生重大影响。
**Scikit-learn** 、**特征引擎**和**分类编码器**提供广泛的分类编码器。这三个库都提供了常用的编码器,比如一键编码和顺序编码,我们将在下面演示。
特征引擎和类别编码器还提供基于目标的编码方法,如目标均值编码和证据权重。
总的来说,分类编码器是分类编码领域的领跑者,提供了最广泛的编码技术。它们最初来源于大量的科学出版物。
分类编码器转换器支持 NumPy 数组和 pandas 数据帧输入格式,是完全兼容的 Scikit-learn 功能,可在管道中使用。除了上面提到的更普遍实现的编码器,类别编码器还提供一些特殊的用例编码器,包括:
* [向后差异](http://contrib.scikit-learn.org/category_encoders/backward_difference.html)
* [赫尔默特](http://contrib.scikit-learn.org/category_encoders/helmert.html)
* [多项式](http://contrib.scikit-learn.org/category_encoders/helmert.html)
* [总和编码](http://contrib.scikit-learn.org/category_encoders/sum.html)
* [离开](http://contrib.scikit-learn.org/category_encoders/leaveoneout.html)
* [二进制](http://contrib.scikit-learn.org/category_encoders/binary.html),与
* [BaseN](http://contrib.scikit-learn.org/category_encoders/basen.html)
在下面的段落中,我们将比较 3 个 Python 开源库中顺序编码的实现。
# 顺序编码
顺序编码用数字将类别标记为唯一类别的数量。对于具有 *n* 唯一类别的分类变量,序数编码会用从 *0* 到 *n-1* 的整数替换类别。
## 特征引擎
Feature-engine 的 OrdinalEncoder()仅适用于分类变量,其中可以指明变量列表,否则编码器将自动选择训练集中的所有分类变量。
如果我们选择“任意”作为编码方法,那么编码器将按照标签在变量中出现的顺序分配数字(即先来先服务)。
如果我们选择“有序”,编码器将按照该标签目标值的平均值分配数字。目标平均值较高的标签将被分配数字 0,而目标平均值最小的标签将被分配 n-1。
import pandas as pd
from sklearn.model_selection import train_test_split
from feature_engine.encoding import OrdinalEncoder
Load datasetdef load_titanic():
data = pd.read_csv(
'https://www.openml.org/data/get_csv/16826755/phpMYEkMl'
)
data = data.replace('?', np.nan)
data['cabin'] = data['cabin'].astype(str).str[0]
data['pclass'] = data['pclass'].astype('O')
data['embarked'].fillna('C', inplace=True)
return data
data = load_titanic()
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['survived', 'name', 'ticket'], axis=1),
data['survived'],
test_size=0.3,
random_state=0
)
set up the encoder
encoder = OrdinalEncoder(
encoding_method='arbitrary',
variables=['pclass', 'cabin', 'embarked']
)
fit the encoder
encoder.fit(X_train, y_train)
transform the data
train_t= encoder.transform(X_train)
test_t= encoder.transform(X_test)
前面代码块的输出是原始的 pandas 数据帧,其中选择的分类变量被转换成数字。
## sci kit-学习
Scitkit-learn 的 [OrdinalEncoder()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OrdinalEncoder.html) 要求对分类变量的输入进行切片。在编码过程中,数字只是按照标签的字母顺序进行分配。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OrdinalEncoder
Load datasetdef load_titanic():
data = pd.read_csv(
'https://www.openml.org/data/get_csv/16826755/phpMYEkMl'
)
data = data.replace('?', np.nan)
data['cabin'] = data['cabin'].astype(str).str[0]
data['pclass'] = data['pclass'].astype('O')
data['embarked'].fillna('C', inplace=True)
return data
data = load_titanic()
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['survived', 'name', 'ticket'], axis=1),
data['survived'],
test_size=0.3,
random_state=0
) # set up the encoder
encoder = OrdinalEncoder()
fit the encoder
encoder.fit(
X_train[['pclass', 'cabin', 'embarked']],
y_train
)
transform the data
train_t= encoder.transform(
X_train[['pclass', 'cabin', 'embarked']]
)test_t= encoder.transform(
X_test[['pclass', 'cabin', 'embarked']]
)
前面代码块的输出是一个有 3 列的 NumPy 数组,对应于估算变量。
## 类别编码器
分类编码器'[' OrdinalEncoder()](http://contrib.scikit-learn.org/category_encoders/ordinal.html)允许我们指定变量/列作为参数进行转换。如果我们知道类本身有某种真正的顺序,也可以传递一个可选的映射字典。否则,这些类被认为没有真正的顺序,数字被随机分配给标签。
import pandas as pd
from sklearn.model_selection import train_test_split
from category_encoders.ordinal import OrdinalEncoder
Load datasetdef load_titanic():
data = pd.read_csv(
'https://www.openml.org/data/get_csv/16826755/phpMYEkMl'
)
data = data.replace('?', np.nan)
data['cabin'] = data['cabin'].astype(str).str[0]
data['pclass'] = data['pclass'].astype('O')
data['embarked'].fillna('C', inplace=True)
return data
data = load_titanic()
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['survived', 'name', 'ticket'], axis=1),
data['survived'],
test_size=0.3,
random_state=0
)
set up the encoder
encoder = OrdinalEncoder(cols=['pclass', 'cabin', 'embarked'])
fit the encoder
encoder.fit(X_train, y_train)
transform the data
train_t= encoder.transform(X_train)
test_t= encoder.transform(X_test)
# 转换
数据科学家使用各种数学函数(如对数、幂和倒数)来转换数值变量,其总体目标是获得更“高斯”的分布。

数学变换——图片由 [Gerd Altmann](https://pixabay.com/de/users/geralt-9301/) 从 [Pixabay](https://pixabay.com/de/illustrations/geometrie-mathematik-lautst%C3%A4rke-1044090/) 获得
Scikit-learn 提供了 [FunctionTransformer()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.FunctionTransformer.html) ,原则上,它可以应用用户定义的任何函数。它将函数作为参数,或者作为 NumPy 方法,或者作为 lambda 函数。
相反,通过诸如 [LogTransformer()](https://feature-engine.readthedocs.io/en/latest/api_doc/transformation/LogTransformer.html) 和 R[eciprocalTransformer()](https://feature-engine.readthedocs.io/en/latest/api_doc/transformation/ReciprocalTransformer.html)之类的转换器,特征引擎支持使用单个特定转换器的数学转换。
说到“自动”转换,Scikit-learn 和 Feature-engine 都支持 Yeo-Johnson 和 Box-Cox 转换。虽然 Scikit-learn 通过改变“方法”参数将转换集中在 [PowerTransformer()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PowerTransformer.html) 中,但 Feature-engine 有两个单独的 [Yeo-Johnson](https://feature-engine.readthedocs.io/en/latest/api_doc/transformation/YeoJohnsonTransformer.html) 和 [Box-Cox](https://feature-engine.readthedocs.io/en/latest/api_doc/transformation/BoxCoxTransformer.html) 转换器。
如果转换在数学上不可行,例如 log(0)或 0 的倒数,Feature-engine 会返回一个错误,而 Scikit-learn 会引入 NaNs,这需要您在之后进行合理性检查。
在接下来的段落中,我们将比较对数转换和 Box-Cox 转换在两个包之间的实现。在演示中,我们使用来自 Kaggle 的[房价数据集。](https://www.kaggle.com/c/house-prices-advanced-regression-techniques)
# 对数变换
对数变换包括对变量进行对数变换。
## 特征引擎
功能引擎的 LogTransformer()将自然对数或以 10 为底的对数应用于数值变量。它只适用于数值,正值。如果变量包含 0 或负值,转换器将返回一个错误。
与所有功能引擎的转换器一样,LogTransformer()允许我们选择要转换的变量。变量列表可以作为参数传递,或者,转换器将自动选择并转换所有数字变量。
import pandas as pd
from sklearn.model_selection import train_test_split
from feature_engine.transformation import LogTransformer
Load dataset
data = data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the variable transformer
tf = LogTransformer(variables = ['LotArea', 'GrLivArea'])
fit the transformer
tf.fit(X_train)
transform the data
train_t = tf.transform(X_train)
test_t = tf.transform(X_test)
## sci kit-学习
Scikit-learn 通过其 [FunctionTransformer()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.FunctionTransformer.html) 将对数函数作为一个 NumPy 方法传递给转换器来应用对数转换,如下所示。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import FunctionTransformer
Load dataset
data = data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the variable transformer
tf = FunctionTransformer(np.log)
fit the transformer
tf.fit(X_train[['LotArea', 'GrLivArea']])
transform the data
train_t = tf.transform(X_train[['LotArea', 'GrLivArea']])
test_t = tf.transform(X_test[['LotArea', 'GrLivArea']])
# Box Cox 变换
Box-Cox 变换是一种通过使用变换参数λ来变换非正态变量的方法。
## 特征引擎
[BoxCoxTransformer()](https://feature-engine.readthedocs.io/en/latest/api_doc/transformation/BoxCoxTransformer.html) 将 Box-Cox 变换应用于数值变量,仅适用于非负变量。
要修改的变量列表可以作为参数传递,或者 [BoxCoxTransformer()](https://feature-engine.readthedocs.io/en/latest/api_doc/transformation/BoxCoxTransformer.html) 将自动选择并转换所有数值变量。
import pandas as pd
from sklearn.model_selection import train_test_split
from feature_engine.transformation import BoxCoxTransformer
Load dataset
data = data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the variable transformer
tf = BoxCoxTransformer(variables = ['LotArea', 'GrLivArea'])
fit the transformer
tf.fit(X_train)
transform the data
train_t = tf.transform(X_train)
test_t = tf.transform(X_test)
这个转换器实现的转换是 [scipy.stats.boxcox](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.boxcox.html) 的转换,并作为熊猫数据帧返回。
# sci kit-学习
Scikit-learn 通过其 [PowerTransformer()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.PowerTransformer.html) 提供了 Box-Cox 和 Yeo-Johnson 变换。Box-Cox 要求输入数据必须是严格的正值。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import PowerTransformer
Load dataset
data = data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the variable transformer
tf = PowerTransformer(method=”box-cox”)
fit the transformer
tf.fit(X_train[['LotArea', 'GrLivArea']])
transform the data
train_t = tf.transform(X_train[['LotArea', 'GrLivArea']])
test_t = tf.transform(X_test[['LotArea', 'GrLivArea']])
与所有 Scikit-learn 转换器一样,结果以 NumPy 数组的形式返回。
# [数]离散化
离散化将连续的数值变量划分为离散的和连续的区间,这些区间跨越了变量值的整个范围。离散化通常用于提高给定变量的信噪比,减少异常值的影响。

离散化意味着将连续变量分类为离散区间——由 [Polski](https://pixabay.com/de/users/krzysztof-m-1363864/) 从 [Pixabay](https://pixabay.com/de/vectors/graph-histogramm-statistiken-3149003/) 生成图像
Scikit-learn 提供了 KBinsDiscretizer()作为集中式转换器,通过它我们可以进行等宽、等频和 k 均值离散化。使用 KBinsDiscretizer(),我们可以通过在所有离散化技术上进行网格搜索来优化模型。
使用特征引擎,离散化过程通过单独的转换器实现。功能-引擎支持
* 等宽离散化
* 等频离散化
* 决策树离散化
* 任意离散化。
此外,Scikit-learn 允许我们只通过设置编码参数就可以直接对 bin 进行热编码。使用特征引擎,如果我们希望将容器视为类别,我们可以在离散化转换器的后端运行任何类别编码器。
在下面的段落中,我们将比较包之间的等频率离散化的实现。
# 等频率离散化
这种类型的离散化将变量分成预定义数量的连续区间。容器间隔通常是百分位数。
## 特征引擎
[EqualFrequencyDiscretiser()](https://feature-engine.readthedocs.io/en/latest/api_doc/discretisation/EqualFrequencyDiscretiser.html)将数值变量值分类为等比例观察值的连续区间,其中区间限制根据百分位数计算。
变量应被划分的区间数由用户决定。转换器可以将变量作为数字或对象返回(默认为数字)。
特征引擎所固有的,可以指示变量列表,或者离散化器将自动选择训练集中的所有数值变量。
import pandas as pd
from sklearn.model_selection import train_test_split
from feature_engine.discretisation import EqualFrequencyDiscretiser
Load dataset
data = data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the discretisation transformer
disc = EqualFrequencyDiscretiser(
q=10,
variables=['LotArea', 'GrLivArea']
)
fit the transformer
disc.fit(X_train)
transform the data
train_t = disc.transform(X_train)
test_t = disc.transform(X_test)
EqualFrequencyDiscretiser()首先找到每个变量的区间边界,因为它符合数据。然后,它通过将值排序到区间来转换变量,并返回一个 pandas 数据帧。
## sci kit-学习
Scikit-learn 可以通过其 [KBinsDiscretizer()](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.KBinsDiscretizer.html) 转换器,将“策略”参数设置为“分位数”来实现等频率离散化。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import KBinsDiscretizer
Load dataset
data = data = pd.read_csv('houseprice.csv')
Separate into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
data.drop(['Id', 'SalePrice'], axis=1),
data['SalePrice'],
test_size=0.3,
random_state=0
)
set up the discretisation transformer
disc = KBinsDiscretizer(n_bins=10, strategy='quantile')
fit the transformer
disc.fit(X_train[['LotArea', 'GrLivArea']])
transform the data
train_t = disc.transform(X_train[['LotArea', 'GrLivArea']])
test_t = disc.transform(X_test[['LotArea', 'GrLivArea']])
默认情况下,NumPy 数组输出被一次性编码到一个稀疏矩阵中。这可以进一步配置,例如使用“encode”参数将设置为序号编码方法。
# 包扎
特征工程是端到端数据科学和机器学习管道中的一个重要组成部分。这是一个迭代过程,每个数据科学家都应该掌握,以优化模型性能。特征工程是非常耗时的,通过了解每个 Python 库的优点和优势来获得这些小小的效率肯定会在你的工作流程中积累起来。
# 参考
* [机器学习的特征工程](https://www.courses.trainindata.com/p/feature-engineering-for-machine-learning) —在线课程
* [Python 特性工程食谱](https://packt.link/0ewSo) —书
* [特征引擎](https://feature-engine.readthedocs.io/en/latest/):用于特征工程的 Python 库
* [用 Scikit-learn 预处理数据](https://scikit-learn.org/stable/modules/preprocessing.html)
# 相关文章
本文是机器学习的特征工程系列文章的第八篇。您可以通过以下链接了解有关数据科学家如何预处理数据的更多信息:
1. [机器学习的特征工程](https://trainindata.medium.com/feature-engineering-for-machine-learning-a-comprehensive-overview-a7ad04c896f8)
2. [变量转换](https://www.blog.trainindata.com/variance-stabilizing-transformations-in-machine-learning/)
3. [学习特征工程的优秀资源](https://trainindata.medium.com/best-resources-to-learn-feature-engineering-for-machine-learning-6b4af690bae7)
# 实用 cy thon——音乐检索:短时傅里叶变换
> 原文:<https://towardsdatascience.com/practical-cython-music-retrieval-short-time-fourier-transform-f89a0e65754d?source=collection_archive---------20----------------------->
## 你想知道更多关于 Cython 的事情吗?在本系列中跟随我,我将向您展示 C-Cython-Python 实现的实际例子

《时间的压缩》声谱图,最终幻想 8【https://www.youtube.com/watch?v=l75zjpDpAWs
[](https://medium.com/@stefanobosisio1/membership) [## 通过我的推荐链接加入 Medium-Stefano Bosisio
### 作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@stefanobosisio1/membership)
我非常喜欢 Cython,因为它吸取了两个主要编程领域的精华:C 和 Python。这两种语言可以以一种简单明了的方式结合在一起,以便为您提供计算效率更高的 API 或脚本。此外,用 Cython 和 C 编写代码有助于您理解常见 python 包(如`sklearn`)下的内容,让数据科学家更进一步,这与简单的`import torch`和预定义算法用法相去甚远。
在这个系列中,我将向你展示如何用 C 和 Cyhton 算法来分析音乐,下面是相应的`sklearn`和`scipy`软件包作为参考。
这一课讲的是[短时傅立叶变换](https://en.wikipedia.org/wiki/Short-time_Fourier_transform)或 STFT。这种算法广泛用于分析信号的频率及其随时间的演变。代码存储在以下存储库中:
[](https://github.com/Steboss/music_retrieval/tree/master/stft) [## ste boss/音乐 _ 检索
### 用于检索音乐信息的 python-c-cython 工具小套件
github.com](https://github.com/Steboss/music_retrieval/tree/master/stft)
这些代码对于理解如何构建 Cython 项目、在文件夹中细分代码以及安装最终的包非常有用。
此帖子包含亚马逊联盟计划的外部链接。
# 外行理论
如果您想立即接触这些代码,可以跳过这一部分。这只是对 STFT 及其理论的简单介绍。
傅立叶变换的主要方面是将信号映射(或者说绘制)到频域,指出构成信号本身的最重要频率。这种映射在许多领域具有广泛的含义:在生物医学工程(例如,研究心电图(ECG)中的频率贡献,以检测可能的疾病或心脏功能障碍 [](https://onlinelibrary.wiley.com/doi/full/10.1002/jmri.1160) [](https://www.sciencedirect.com/science/article/abs/pii/S0010482516302104)[](https://www.scirp.org/html/4708.html))、计算科学(例如,压缩算法,如`mp3, jpeg`[【⁴](https://www.roe.ac.uk/japwww/teaching/fourier/compression.html))或金融(例如,研究股票价格、债券价格行为[、⁵](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.307.8732&rep=rep1&type=pdf) )。这种映射也有利于研究音乐信号,因为可以检索和分析主要频率内容,例如,创建流派分类器或类似 Shazam 的应用程序(例如[检查我的帖子](https://www.instagram.com/p/BWh54ImAg4a/))。然而,了解频率在时间和幅度上的演变有时是有趣和有帮助的,以便找到特定的噪声或在记录会话中均衡频率,或创建神经网络算法来将语音信号转换为文本(例如 [DeepPavlov](https://github.com/deepmipt/DeepPavlov) )。
在实践中,STFT 将时间信号分成等长的小段(`window_length`),然后计算每段的傅立叶变换。由此产生的分段频率内容可以相对于时间绘制,它被称为*频谱图。*
实际上,STFT 可以概括为以下几个步骤:
* 获取一个输入信号(例如 mp3 文件)
* 将信号乘以窗口函数(例如[汉明函数](https://en.wikipedia.org/wiki/Window_function))。这将有助于在每个片段的极端处计算傅立叶变换,以避免信号中可能的不连续性,这种不连续性可能会阻碍傅立叶变换计算
* 沿着信号/时间滑动一个窗口和一个跳跃大小的窗口,并计算傅立叶变换
图 1 有助于更好地理解 STFT 做了什么。具有定义的幅度(以分贝为单位)和时间(以秒为单位)的输入信号被封装在大小为*窗口大小的 *N* 个窗口中。*每个 *HopSize,*窗口定义一个信号段,该信号段被傅立叶变换。输出频率(单位:赫兹)可以绘制成时间的函数。

图 1: STFT 的缩影。定义了窗口大小和跳跃大小。对于每个窗口段,计算傅立叶变换。频率内容可以显示为时间的函数
最后要记住的是[奈奎斯特频率](https://en.wikipedia.org/wiki/Nyquist_frequency#:~:text=The%20Nyquist%20frequency%20is%20half,cycles%20per%20second%20(hertz).)。如果查看频谱图,您会发现最大绘制频率是信号采样频率的一半,以避免傅立叶变换中的*混叠*问题。这意味着从信号中检索的 *N* 个复傅立叶系数中,具有采样频率 *fs* (例如,音频文件通常具有 44100 Hz 的采样频率)的只有一半是有用的,代表从 0 到 *fs/2* 的频率
要了解更多信息,我强烈推荐这些非常有价值和有用的书籍:
* [振荡和波的物理学:使用 Matlab 和 Python(物理学本科教材)](https://www.amazon.co.uk/gp/product/3319723138/ref=as_li_tl?ie=UTF8&camp=1634&creative=6738&creativeASIN=3319723138&linkCode=as2&tag=stefanobosisi-21&linkId=dcd9dc69686225384e98e26930e49fe5)
* [信息论、符号、信号和噪声介绍(多佛数学书籍)](https://www.amazon.co.uk/gp/product/0486240614/ref=as_li_tl?ie=UTF8&camp=1634&creative=6738&creativeASIN=0486240614&linkCode=as2&tag=stefanobosisi-21&linkId=b41d92ad0c7c671cead4ff5d8b27423c)
* [傅立叶变换(多佛数学书籍)](https://www.amazon.co.uk/gp/product/0486685225/ref=as_li_tl?ie=UTF8&camp=1634&creative=6738&creativeASIN=0486685225&linkCode=as2&tag=stefanobosisi-21&linkId=549a77575f734559f132ad217c0a3e13)
# 塞顿的 STFT:让我们玩得开心
## 行动(或活动、袭击)计划

图 2:从 Python 到 Cython 和 C 的实现示意图
图 2 显示了在 Cython 和 C 中实现 STFT 的行动计划。整个过程可以分为三个部分,分别使用 Python、Cython 和 C:
1. Python 接口处理信号的输入/输出和操作:
* 用`scipy`或`pydub`打开 mp3/wav 输入文件
* 左声道和右声道被隔离,只分析`channel[:,0]`
* 对信号进行填充,因此元素总数是 2 的幂,这提高了傅立叶变换库的性能`fftw`
2.Cython 接口将 Cython 输入转换为 memoryviews,然后可以很容易地将 memoryviews 作为指向 C 套件的指针传递:
* 为了有一个具体的概念,图 3 展示了一个例子,它从一个长度为`n_elements`的零数组`np.zeros`中创建一个内存视图
图 3:在 Cython 中创建 memoryview 的例子
3.C 接口执行核心的 STFT 操作。简而言之:
* 用`fftw`元素定义`fftw3`库域并进行规划。该计划是执行快速傅立叶变换所必需的:
图 4:用 C 语言初始化 fftw 元素和计划
* 创建一个汉明窗口
* 执行 STFT 循环:将输入块乘以汉明窗口,计算输出的快速傅立叶变换,存储一半结果。
需要强调的是,当前的结构确保计算最密集的操作在 C 代码中执行,然后所有信息返回给 Python。这可以降低计算成本——因为许多算法仅由 Python 实现,而不是用 C 语言实现——并提高 Python 代码的整体性能。
## Python 脚本
代码:[https://github . com/ste boss/music _ retrieval/blob/master/STFT/installer/tester . py](https://github.com/Steboss/music_retrieval/blob/master/stft/installer/tester.py)
Python 脚本处理输入音频文件,并为将要执行的 STFT 准备所有信息。
首先,`pydub`可以用来打开和读取 mp3 文件,而`scipy`提供了一个内置功能来读取 wav 扩展名:
图 5:如何打开 mp3 和 wav 文件
然后,我们可以在代码中定义所有的“常数”,并调用 STFT:
图 Python 中关键参数的定义,准备 stft 调用
在图 6 中,定义了`windowSize`和`hopSize`。如图 1 所示,这两个量可以重叠。一般来说,随着时间的推移,重叠越多,分析点越多,结果越平滑,但代价是更高的计算成本。总的来说,对于本教程,我们可以达到相同的大小,但尽可能自由地尝试。
## Cython 代码
代码:[https://github . com/ste boss/music _ retrieval/blob/master/STFT/installer/STFT . pyx](https://github.com/Steboss/music_retrieval/blob/master/stft/installer/stft.pyx)
Cython 代码通常有两个扩展名:`pyx`和`pxd`。前者是编写主代码的地方,而后者用于声明。在本教程中,我们将只使用`pyx`扩展,以便更熟悉 Cython,并且只需处理一段代码。
第一步是在 Cython 中导入我们的 c 代码——稍后我们将看到 c 代码是如何构造的:
图 7:在 Cython 中导入 c 代码
使用`cdef extern from YOUR_C_CODE:`声明导入 c 代码。接下来,我们要使用的 C 函数的名字,必须和所有类型一起声明,就像我们在 C 代码中一样。因此,函数`stft`返回一个数组作为指针,所以`double*`为`stft` C 函数。参数是输入音频通道`double *wav_data`,最终 STFT 信号内的样本数量`int samples`,窗口和跳跃大小`int windowSize, int hop_Size`,采样频率和音频通道长度`int sample_freq, int length`。`samples`可以计算为:
samples = int((length/windowSize/2))*((windowSize/2)+1))
下一步是创建和声明我们的主函数。,它将在我们的 python 脚本中被调用(这里它的名字是`play`):
`cpdef play(audData, rate, windowSize, hopSize):`
`cpdef`声明下面的函数将包含 C 和 Python 代码和类型。如果我们想直接调用一个 Python 函数和用于声明一个纯 C 函数的`cdef`,进一步的选项是按照普通 Python 的`def`。
第二个重要的概念是将所有参数传递给主`stft` C 函数,如图 8 所示
图 8:调用 c 函数 stft 传递 Cython 参数
基本上,内存视图可以很容易地传递给 C 函数,它们将被视为 1D 数组。首先,要创建 memoryview,必须定义类型和大小。图 8 的第 2 行和第 6 行显示了如何创建 1D 内存视图:`cdef double[:] name_of_memory_view = content`其中`[:]`定义了一个 1D 内存视图。最后,内存视图可以像第 8 行中对`&audData_view[0]`和`&magnitude[0]`所做的那样作为`&name_of_memory_view[0]`传递给 C 函数。在接下来的教程中,我将更详细地向你展示如何处理 2D 内存视图并将它们传递给 C,因为这必须处理内存缓冲区。值得注意的是,在第 8 行中`&magnitude[0]`作为 0 的向量传递给 C。这允许处理 C 中已经初始化的指针,并用 STFT 值填充它们。
## c 代码
code:[https://github . com/ste boss/music _ retrieval/blob/master/STFT/c _ code/STFT . c](https://github.com/Steboss/music_retrieval/blob/master/stft/c_code/stft.c)
第一步是导入必要的库:
图 9:用于 STFT 算法的 C 库
`fftw3`是最重要的库,它允许计算快速傅立叶变换,以及余弦变换等等。
其次,我们需要定义一些常数,如 *pi* 值和汉明窗函数,来创建汉明窗值。这可以通过以下方式轻松实现:
图 10:为 PI 定义一个常量值和一个函数来创建汉明窗口
至此,我们可以开始玩`fftw3`了。如图 11 所示,我们需要为大小为`windowSize`的输入数据`stft_data`创建一个`fftw_complex`数组;一个与`stft_data`具有相同尺寸的输出数组`fft_result`用于存储傅立叶变换加窗信号,最后一个`storage`数组用于存储所有变换后的窗口,其尺寸为`samples`。为了允许`fftw`计算窗口输入信号的傅立叶变换,我们需要一个傅立叶平面对象,该对象在第 17 行以这种方式创建:
fftw_plan plan_forward;plan_forward = fftw_plan_dft_1d(number_of_elements_in_output,
input_data_to_be_transformed,
output_transformed_data,
flag_for_forward_transform,
flag_for_inverse_transform);
图 11:玩 fftw
最后一步是实现真正的 STFT 算法:
图 12: STFT 在实践中的 C
图 12 帮助您理解 STFT 是如何实现的。首先,用当前窗口大小的信号幅度值填充`stft_data`数组(第 10 行)。然后对这一段进行傅立叶变换,称为`fftw_execute(plan_forward)`。实际上,`fftw_execute`将触发上面定义的傅立叶变换计划的执行,以便变换当前输入并将结果保存在输出数组`fft_result`中。最后,一半的傅立叶样本保存在`storage`阵列中,稍后将返回给 Cython,并且`chunkPosition`由`hop_size/2`更新,因此可以继续下一个窗口——还记得奈奎斯特频率吗?
此时,可以用来自`storage`的傅立叶变换信号填充`magnitude`数组,该数组是在 Cython 中创建的内存视图
图 13:填充内存视图大小并将其返回给 Cython
因此,量值将从 C 转移到 Cython。在 Cython 中,可以操作`magnitude`数组来返回一个 numpy 数组,可以用 Python 读取:
图 14: Cython 零件。magnitude memoryview 被转换成一个 numpy 数组,经过整形后返回给 Python
## 准备 setup.py 并安装所有东西
这是享受分析 STFT 之前的最后一步。为了在 Cython 中安装 create Python 包,我通常将我的代码分成两个文件夹:`c_code`,其中存储了`stft.c`和`installer`,其中保存了`pyx`和 Python 文件。在`installer`文件夹中,我创建了`setup.py`文件,这是一个 Python 文件,用于安装和编译 Cython 和 C 代码。代码非常简单:
图 15:编译 Cython 和 C 代码的 setup.py 脚本
在图 15 的代码中,我们可以看到编译代码的主要元素是`Extension`和`setup`。前者定义了当前扩展的名称`stft.stft`、`pyx`文件列表`[stft.pyx]`、库列表和编译 C 代码所需的额外参数。特别是,在这种情况下,我们需要将`fftw3`和`m` 指定为附加库,其中一个声明使用快速傅立叶变换库,另一个声明使用数学库(编译 C 代码时,通常将`m`添加为`-lm`,将`fftw3` 添加为`-lfftw3`)。额外的参数确保我们在编译 C 时有一个`O3`优化过程,而`std=C99`是通知编译器我们正在使用标准版本 C99。最后,`setup`存储包信息,即最终模块的名称——因此 Python 将当前模块作为`import stft`导入——版本控制、C 的扩展和 Cython 的任何指令。关于 Cython 指令,我建议你看一下[指南](https://cython.readthedocs.io/en/latest/src/userguide/source_files_and_compilation.html#compiler-directives)。
一旦代码准备好,我们就可以像下面这样运行`setup.py`:
python setup.py build_ext --inplace
`build_ext`是构建当前扩展的命令,`--inplace`允许在工作目录中安装当前包。
# STFT 的有趣例子
代码:[https://github . com/ste boss/music _ retrieval/tree/master/STFT/examples](https://github.com/Steboss/music_retrieval/tree/master/stft/examples)
研究 STFT 的一个很好的例子是 Aphex 双胞胎“方程式”音乐
如果我们分析 300 到 350 秒之间的声谱图:
start = 300rate
end = 350rate channel1 = audData[:,0][start:end]
设置`windowSize=4096`和`hopSize=4096`音乐谱图中会出现一张恶魔的脸:

图 16:Aphex Twin 的“方程式”中隐藏的恐怖脸(30-40 岁之间)
我希望你喜欢这第一次对 Cython 的介绍:)如果有任何问题或意见,请发邮件给我,地址是:stefanobosisio1@gmail.com
# 文献学
1. [https://onlinelibrary.wiley.com/doi/full/10.1002/jmri.1160](https://onlinelibrary.wiley.com/doi/full/10.1002/jmri.1160)
2. [https://www . science direct . com/science/article/ABS/pii/s 0010482516302104](https://www.sciencedirect.com/science/article/abs/pii/S0010482516302104)
3. https://www.scirp.org/html/4708.html
4. [https://www . roe . AC . uk/jawww/teaching/Fourier/compression . html](https://www.roe.ac.uk/japwww/teaching/fourier/compression.html)
5. [http://citeseerx.ist.psu.edu/viewdoc/download?doi = 10 . 1 . 1 . 307 . 8732&rep = re P1&type = pdf](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.307.8732&rep=rep1&type=pdf)
# 熊猫实用数据分析指南:直接营销
> 原文:<https://towardsdatascience.com/practical-data-analysis-guide-with-pandas-direct-marketing-dfc2977a559d?source=collection_archive---------25----------------------->
## 如何洞察你的营销努力

[活动发起人](https://unsplash.com/@campaign_creators?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)在 [Unsplash](https://unsplash.com/s/photos/marketing?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上的照片
Pandas 为数据分析和操作提供了许多功能和方法。在本帖中,我们将使用熊猫来深入了解直销数据集。
[数据集](https://www.kaggle.com/yoghurtpatil/direct-marketing)可在 Kaggle 上获得。它包含通过直邮完成的营销活动的相关数据。我们将研究这个数据集,并试图了解哪些客户可能会花更多的钱。
让我们从将数据集读入数据帧开始。
import numpy as np
import pandas as pddf = pd.read_csv("/content/DirectMarketing.csv")
print(df.shape)
df.head()

(图片由作者提供)
数据由 1000 个观察值(即行)和 10 个特征(即列)组成。重点是“AmountSpent”列,它显示了客户到目前为止已经花了多少钱。
在我们开始分析之前,最好确保没有丢失值。
df.isna().sum()
Age 0
Gender 0
OwnHome 0
Married 0
Location 0
Salary 0
Children 0
History 303
Catalogs 0
AmountSpent 0
dtype: int64
“历史”列包含 303 个缺失值。这些用于表示客户尚未购买。我们可以检查列中的其他值,然后决定如何处理缺少的值。
df.History.value_counts()
High 255
Low 230
Medium 212
Name: History, dtype: int64
由于这是一个分类列,我们可以用单词“Nothing”替换缺失的值,表示还没有购买。
df.History.fillna("Nothing", inplace=True)df.isna().sum().sum()
0
## 花费的金额
我们首先检查“AmountSpent”列的统计数据。
print(f'The average money spent is {df.AmountSpent.mean()}. The median is {df.AmountSpent.median()}')The average money spent is 1216.77. The median is 962.0
平均值远高于中值,这表明该列不具有正态分布。存在高值的异常值。因此,我们期望“花费金额”列具有右偏分布。
让我们用直方图来检查一下。
df['AmountSpent'].plot(kind='hist', figsize=(10,6))

花费金额柱状图(按作者分类的图片)
它与统计数据重叠。大多数观察值都在低位部分,少数异常值达到了高位。
## 年龄
年龄可能是一个重要的特征,因为直邮营销往往吸引老年人。groupby 函数将为我们提供一个概览。
df[['Age','AmountSpent']].groupby('Age').mean()

(图片由作者提供)
中老年人的平均消费金额比年轻人高得多。
我还想看看这场运动是否更侧重于老年人。我们可以检查发送到每个组的目录数量以及平均花费的金额。
df[['Age','Catalogs','AmountSpent']].groupby('Age').agg(['mean','count'])

(图片由作者提供)
计数显示了一个组中的观察次数。我们看到越来越多的中年人参与到这场运动中来。发送给年轻客户的平均目录数量略少于老年客户。
正如您所注意到的,我们可以通过向聚合函数传递一个列表来对组值应用多个聚合。
## 数值变量之间的相关性
在计算相关性之前,我将简单解释一下相关性对于变量的意义。
相关性是每个变量的标准差对协方差的归一化。协方差是一种定量度量,表示两个变量的变化彼此匹配的程度。更简单地说,相关性和协方差表示值是否倾向于以相似的方式变化。
协方差的标准化消除了单位。因此,在正相关的情况下,相关值总是在 0 和 1 之间,在负相关的情况下,相关值总是在 0 和-1 之间。
为了计算数值变量之间的相关性,我们将使用 pandas 的 corr 函数,并用热图可视化结果。
importing visualization libraries
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inlineplt.figure(figsize=(10,6))
corr = df.corr()
sns.heatmap(corr, annot=True)

热图(图片由作者提供)
薪水和花费之间有很强的相关性。商品目录的数量也与消费金额成正相关。
另一方面,孩子的数量和花费的数量有一个小的负相关。
## 儿童
相关矩阵显示,子女人数和花费金额之间呈负相关。因此,随着儿童数量的增加,我们预计支出会减少。
我们也用 groupby 函数检查一下。我还将包括年龄栏。groupby 函数接受多列,并为每组类别创建一个组。
df[['Age','Children','AmountSpent']]
.groupby(['Age','Children']).agg(['mean','count'])

(图片由作者提供)
总的来说,平均花费随着孩子数量的增加而减少。不过也有一些例外。
## 性别与婚姻
我们将检查性别和婚姻列中的几个指标。groupby 函数允许对不同的列应用不同的聚合函数。此外,我们可以重命名聚合的列。
用这个例子会更清楚。我想创建基于性别和婚姻栏的小组。然后我会计算:
* 发送给每个组的平均目录数(平均值)
* 每组购买的总数量(总和)
我还想适当地重命名这些列。下面是执行此操作的 groupby 语法:
df[['Gender','Married','AmountSpent','Catalogs']]
.groupby(['Gender','Married'])
.agg(
Average_number_of_catalogs = pd.NamedAgg('Catalogs','mean'),
Total_purchase_amount = pd.NamedAgg('AmountSpent','sum')
)

(图片由作者提供)
NamedAgg 方法用于重命名列。更改列名的另一种方法是 Pandas 的重命名功能。
这家零售商绝对应该把重点放在已婚人士身上。
## 位置
位置也可能是一个重要的指标。让我们根据位置检查“花费金额”列。
df[['Location','AmountSpent']].groupby('Location')
.agg(['mean','count','sum'])

(图片由作者提供)
住在附近的顾客数量是住在远处的顾客数量的两倍多。然而,他们比住在附近的顾客平均花费更多。
零售商可能想多关注住在远处的人。
## 结论
我们可以更深入地挖掘数据集,并试图获得更多的洞察力。我们还没有检查一些功能。然而,技术是非常相似的。
这篇文章的主要目的是介绍在数据探索中使用的不同技术和方法。当然,熊猫提供了更多的功能和方法。学习和掌握它们的最好方法是大量练习。
我建议研究样本数据集,并尝试探索它们。有免费的资源可以让你找到样本数据集。例如,[杰夫·黑尔](https://medium.com/u/451599b1142a?source=post_page-----dfc2977a559d--------------------------------)在[这篇文章](/the-top-10-best-places-to-find-datasets-8d3b4e31c442)中列出了 10 个寻找数据集的好地方。
感谢您的阅读。如果您有任何反馈,请告诉我。
# 熊猫 EDA 实用指南
> 原文:<https://towardsdatascience.com/practical-eda-guide-with-pandas-3463ea637609?source=collection_archive---------34----------------------->
## 学生在不同考试中的表现分析

由[杰斯温·托马斯](https://unsplash.com/@jeswinthomas?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)在 [Unsplash](https://unsplash.com/s/photos/student-test?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上拍摄的照片
Pandas 是一个广泛使用的数据分析库,它提供了许多函数和方法来处理表格数据。易于使用的功能的丰富选择使得探索性数据分析(EDA)过程相当容易。
在本帖中,我们将探索 Kaggle 上可用的[学生表现数据集](https://www.kaggle.com/spscientist/students-performance-in-exams)。该数据集包含一些关于学生及其在某些测试中的表现的个人信息。
让我们从将数据集读入熊猫数据帧开始。
import numpy as np
import pandas as pddf = pd.read_csv("/content/StudentsPerformance.csv")df.shape
(1000,8)df.head()

(图片由作者提供)
有 5 个分类特征和 3 个不同测试的分数。目标是检查这些特征如何影响考试分数。
我们可以从检查考试分数的分布开始。熊猫的`plot`功能可用于创建核密度图(KDE)。
df['reading score'].plot(kind='kde', figsize=(10,6), title='Distribution of Reading Score')

(图片由作者提供)
阅读测试的分数呈正态分布。其他考试成绩和阅读考试差不多。
“种族/民族”栏包含 5 个群体。我想看看各组的平均考试成绩。`groupby`函数可以执行这项任务。最好也统计一下每组的学生人数。
df[['race/ethnicity','math score','reading score','writing score']].groupby('race/ethnicity').agg({'math score':'mean', 'reading score':'mean', 'writing score':['mean','count']})
.round(1)

(图片由作者提供)
如果想对不同的列应用不同的聚合函数,可以将字典传递给`agg`函数。因为所有测试的计数都是相同的,所以只对一列应用`count` 函数就足够了。
结果表明,从 A 组到 e 组,平均分稳步上升。
我们可以使用相同的逻辑来概括分类变量和测试分数之间的关系。
更进一步,可以创建嵌套组。让我们使用“性别”、“备考课程”和“数学成绩”列来做一个例子。学生将按性别分组,参加预备课程。然后,将计算每组的平均数学成绩。
df[['gender','test preparation course','math score']].groupby(['gender','test preparation course']).agg(['mean','count']).round(1)

(图片由作者提供)
备考课程对男性和女性的数学成绩都有积极的影响。总的来说,男性在数学考试中表现比女性好。
你可能已经注意到了代码末尾的`round` 函数。它只是将浮点数向上舍入到所需的小数点位数。
我们还可以检查两个分类变量中的组是如何相关的。考虑“种族/民族”和“父母教育水平”栏。每个种族群体的教育水平分布可能不同。
我们将首先创建一个数据框架,其中包含每个种族群体-教育水平组合的人数。
education = df[['race/ethnicity','parental level of education','lunch']].groupby(['race/ethnicity','parental level of education']).count().reset_index()education.rename(columns={'lunch':'count'}, inplace=True)education.head()

(图片由作者提供)
第三列可以是任何列,因为它仅用于对属于特定种族-教育水平组合的观察值(即行)进行计数。这就是我们将列名从“午餐”改为“计数”的原因。
“A 组”除“硕士”外,教育水平接近均匀分布。有许多选项可以将我们刚刚创建的教育数据框架可视化。我将 plotly 库的极线图。
import plotly.express as pxfig = px.line_polar(education, r='count', theta='parental level of education',color='race/ethnicity', line_close=True, width=800, height=500)fig.show()

(图片由作者提供)
它让我们了解了不同群体的教育水平分布情况。需要注意的是,这个极坐标图不能用来直接比较不同群体的教育水平,因为每个群体的学生人数并不相同。

(图片由作者提供)
C 组包含的学生最多。因此,我们使用这个极坐标图来检查每个组内的教育水平分布。
例如,“大专学历”是 c 组中最主要的教育水平。我们可以使用`value_counts`函数来确认结果。

(图片由作者提供)
另一个方便的比较类别的函数是`pivot_table`。它创建一个由类别组合组成的交叉表。让我们使用“写作分数”上的“午餐”和“父母教育水平”列来做一个例子。
pd.pivot_table(df, values='writing score',index='parental level of education', columns='lunch',aggfunc='mean')

(图片由作者提供)
分类变量(即列)被传递给索引和列参数,数值变量被传递给值参数。根据所选的聚合函数(aggfunc 参数),将计算这些值。
数据透视表显示,吃一顿标准午餐可能会提高写作考试分数。同样,随着父母教育水平的提高,学生的成绩往往会更好。
# **结论**
我们发现了一些影响学生考试成绩的因素。当然,您可以检查许多不同的方法。然而,技术是非常相似的。
取决于你寻找什么,你使用的技术倾向于一个特定的方向。然而,一旦你习惯了使用熊猫,你就可以完成表格数据的任何任务。
感谢您的阅读。如果您有任何反馈,请告诉我。
# 实用的可解释人工智能:贷款审批用例
> 原文:<https://towardsdatascience.com/practical-explainable-ai-loan-approval-use-case-f06d2fba4245?source=collection_archive---------49----------------------->
## explainx 概述:开源、快速和可扩展的可解释人工智能 python 库

实用可解释的人工智能——构建可信、透明和公正的 ML 模型
# 黑盒人工智能
在负责执行关键任务的系统中,可解释性极其重要。例如,在医疗保健领域,如果科学家依赖人工智能模型来帮助他们判断病人是否会患癌症,他们需要 100%确定他们的诊断,否则这可能导致死亡,大量诉讼和信任方面的大量损害。本质上,这个问题是如此激烈,以至于可解释性位于这个问题的核心:数据科学家和人类操作员,在这种情况下,医生需要理解机器学习系统是如何表现的,以及它是如何做出决定的。
可解释的人工智能在金融或金融科技领域也很重要,特别是由于在信用评分、贷款审批、保险、投资决策等领域越来越多地采用机器学习解决方案。在这里,机器学习系统的错误决策也是有代价的:因此非常需要了解模型实际上是如何工作的。
使用黑盒人工智能增加了商业风险,并使企业面临严重的负面影响——从信用卡申请到确定疾病到刑事司法。
当我们从整体上看业务如何运作时,黑盒模型不可取的原因就变得更加清楚了:
对于业务决策者,数据科学家需要回答为什么他们可以信任我们的模型的问题,对于 IT 和运营,数据科学家需要告诉他们如果出现错误,他们如何监控和调试,对于数据科学家,他们需要知道他们如何进一步提高他们模型的准确性,最后,对于监管者和审计者,他们需要能够得到我们的人工智能系统是否公平的答案?
# 进入可解释的人工智能
可解释的人工智能旨在提供清晰透明的预测。一个端到端的系统,为用户提供决策和解释,并最终提供自动反馈,以不断改进人工智能系统。请记住,xAI 是由反馈高度驱动的,因此是人类和 AI 系统之间的双向交互。
最后要明白模型背后的原因,模型的影响,模型在哪里失效,提供什么建议。
# Explainx:一个开源、快速、可扩展的可解释人工智能平台。
explainx 是由[explainex . AI](https://www.explainx.ai)打造的开源可解释 AI 平台。用 python 编写的 Explainx 旨在帮助数据科学家解释、监控和调试黑盒 AI 模型——目的是帮助构建健壮、无偏见和透明的 AI 应用。

explainx 高级架构
在 explainex 架构中,explainex 在我们的 Jupyter 笔记本中的一行代码中提供了对最先进的可解释性技术的访问。
对于这个例子,我们将使用 FICO 提供的 HELOC 数据集。该数据集中的客户要求的信用额度在 5,000-150,000 美元之间。我们的工作是预测他们是否会在两年内按时付款。这个预测可以用来决定房主是否有资格获得信贷额度。

贷款申请审批— explainx.ai
对于此示例,我们将训练 CatBoost 分类器模型。培训完成后,我们将使用 explainx xAI 模块来解释我们的模型,并为业务用户构建一个便于理解的叙述!
让我们从打开我们的 Jupyter 笔记本并安装 explainx 库开始。您也可以通过下面的链接克隆存储库:
【https://github.com/explainX/explainx
pip install explainx
让我们导入相关的包:
from explainx import *
import catboost
from sklearn.model_selection import train_test_split
让我们加载并预处理数据集以进行模型构建。该数据集在 explainx 库中已经可用。
X, y = explainx.dataset_heloc()#split data into train and test
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=0
开始训练。为了这个教程,我们打算保持简单!
Run catboost model
model = CatBoostClassifier(iterations=500,
learning_rate=.3,
depth=2)# Fit model
model.fit(X_train.to_numpy(), y_train)
训练完成后,我们可以简单地将测试数据传入 explainx 函数,并获得我们的解释!
explainx.ai(X_test, y_test, model, model_name="catboost")
一旦 explainx 开始运行,你需要做的就是将你的浏览器指向 [http://127.0.0.1:8050](https://127.0.0.1:8050/) ,你会看到一个非常漂亮的用户界面,叫做**explainex . dashboard .**
App running on https://127.0.0.1:8050/
*注意:如果您想以内联方式查看它,只需将* `*mode="inline”*` *参数传递到 explainx 函数中。*
对于本教程,我们不会深入模型构建、模型度量和评估的本质。相反,我们将直接进入解释部分,这是本教程的主要目的。所以让我们开始打开黑匣子吧!
我们将在四个层面上处理该模型:
> 全局级别解释
>
> 局部预测解释
>
> 情况分析
>
> 功能交互和分布
## 全局级别解释
我们将使用总体特性重要性和总体特性影响图来给出模型的基本底层逻辑。

全局特征重要性
解释:这说明根据 CatBoost 模型,`ExternalRiskEstimate, MSinceMostRecentInq and PercentTradesNeverDelq`是对`RiskPerformance.`影响最大的前三个变量,这三个变量代表风险估计、信用查询和债务水平信息:评估风险时极其重要的类别。
这些信息让我们对特性的贡献有了一个大致的了解,但是要了解这些特性对`RiskPerformance`有正面还是负面的影响,我们需要参考特性影响图。

全球功能影响
这个图表让我们对模型逻辑有了更多的了解。我们可以清楚地观察到`ExternalRiskEstimate`对预测变量产生了积极的影响——将它推向“良好的信用风险表现”,这也符合我们的直觉。为此,我们必须使用一点我们在金融领域的知识:`ExternalRiskEstimate`是一些风险标记的合并版本(越高越好),因此我们自动了解到这个变量将总是积极地影响预测。然后我们有`NumSatisfactoryTrades:`“满意”账户(“交易”)的数量对良好信用的预测概率有显著的积极影响。
然而,在低端,拖欠变量将整体预测推向 0(在这种情况下,申请被拒绝)。这很有趣,我们甚至可以更深入地挖掘,看看这种不良行为的负面影响什么时候会消失?(要自己尝试的东西!)
现在,我们已经了解了每个特性如何影响预测,我们可以继续解释针对特定客户的单个预测。为此,我们将使用影响图或决策图来帮助我们获得特定预测的归因分数。为了进一步支持我们的分析,我们将计算最接近我们试图预测的相似轮廓。
## 局部预测解释
让我们为数据中第 9 行的客户解释一下。对于这个特定的客户,申请被批准是因为`RiskPerformance`是“好的”,并且我们的模型也对其进行了正确的分类!

客户编号 9 —本地预测解释
让我们探索一下模型逻辑:

对客户# 9 的本地功能影响
这张图表清楚地显示了三个积极的和三个消极的影响变量。根据该模型,`MSinceMostRecentInq`对变量有最积极的影响。这告诉我们,这个变量的值越大,就意味着自最近一次查询以来超过一个月没有惩罚。然后我们有了`ExternalRiskEstimate`,它再次在将预测推向“良好信用行为”方面发挥了积极作用。然而,`PercentTradesNeverDelq`对预测产生了负面影响:如果该变量的值非常小,可能会出现这种情况,因为该变量的值越小,获得良好信用评分的可能性就越低。
简而言之,这些发现符合我们的心理模型,因为每个变量的归因分数都是正确分配的。为了进一步支持我们的分析,我们将找到类似的客户!
Explainx 带有一个内置的原型分析功能,该功能提供了一个更加全面和综合的视图,说明为什么申请人的决定可能是合理的。

上表描述了与所选申请人最接近的五个用户概况。基于该方法分配给每个简档的重要性权重,我们看到零列下的原型是迄今为止最具代表性的用户简档。这从特征相似性中(直观地)得到了证实,其中该原型的超过 50%的特征(23 个中的 12 个)与我们想要解释其预测的所选用户的特征相同。此外,银行员工在查看原型用户及其特征时,会推测被批准的申请人属于 ExternalRiskEstimate 值较高的组。这个理由让银行员工在批准用户的申请时更有信心。
## 情况分析
现在,让我们探索不同的场景,看看模型的表现如何。我们可以在数据表中应用数据过滤器(不需要编写 SQL 查询来过滤您的数据),并非常容易地解释多个实例和场景。
当您试图理解特定集群或数据组的行为时,这是非常有用的。例如,我们想看看当`ExternalRiskEstimate`是> 60 而`MSinceOldestTradeOpen`大于 200 时,模型是否赋予用户相同的权重。

应用的数据过滤器—解释 x
从下面的图表中,我们可以清楚地看到外部风险估计的优势。

RiskEstimate > 60 和 TradeOpen > 200 时的功能影响
当外部风险估计值大于 60 时,它被视为一个积极的信号,也符合我们的内部心理模型:外部风险估计值实际上是单调递减的,这意味着随着外部风险估计值的增加,不良信用评分的概率下降!因此,在这个风险估计值大于 60 的集群中,我们将拥有更多获得信贷额度的优质客户。我们可以通过使用特征相互作用图,特别是部分相关性图来证实这一点:
## 特征交互和分布
部分相关图验证了我们的假设。在下图中,红色=良好的风险表现(信用额度扩大),银色=不良的风险表现(信用额度被拒绝)。

我们可以清楚地看到,随着外部风险评估值的增加,其对输出的影响也增加,我们有更多良好风险表现的实例。随着外部风险估计值的上升,我们看到红点的浓度越来越高,这很有意义!
# 结论
数据科学家可以使用 explainx 通过查看不同变量之间的交互以及它们如何影响整体预测来进一步探索模式。最后,让我们总结一下我们的发现,以便业务用户理解:
* 根据 CatBoost 模型,`ExternalRiskEstimate, MSinceMostRecentInq and PercentTradesNeverDelq`是对`RiskPerformance.`影响最大的前三个变量
* `ExternalRiskEstimate`对预测变量产生积极影响——将其推向“良好信用风险”,但违约变量将整体预测推向“不良信用风险”(在这种情况下,申请被拒绝)。
* 对于我们的客户# 9,RiskPerformance = Good,`ExternalRiskEstimate`在将预测推向“良好信用行为”方面发挥了积极作用。然而,`PercentTradesNeverDelq`对预测产生了负面影响:如果该变量的值非常小,可能会出现这种情况,因为该变量的值越小,获得良好信用评分的可能性就越低。
* 我们发现客户与我们的客户# 9 有着非常相似的行为和可变的价值观:这进一步加强了我们的假设。
* 我们能够通过进一步研究 PDP 来验证模型的逻辑,PDP 清楚地向我们展示了增加`ExternalRiskEstimate`的值如何增加贷款批准的概率。
* 数据科学家可以进一步探索类似的过程,并构建任何人都可以轻松理解的更全面的数据叙述。
我希望你们都喜欢这个案例研究。可解释性是极其重要的,在今天更是如此——因此,对数据科学家来说,展示你对人工智能如何工作的理解的能力是一项至关重要的技能。这才是人类真正的本质——AI 理解,AI 民主化。
下载[讲解](https://www.explainx.ai):[https://github.com/explainX/explainx](https://github.com/explainX/explainx)文档:[https://explainx-documentation.netlify.app/](https://explainx-documentation.netlify.app/)
# Python 中数据清理的实用指南
> 原文:<https://towardsdatascience.com/practical-guide-to-data-cleaning-in-python-f5334320e8e?source=collection_archive---------25----------------------->
## 了解如何为机器学习算法准备和预处理数据

Ashwini Chaudhary 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片
在你进入机器学习(ML)算法的奇妙世界之前,有一个小问题,你可以通过它来预测未来:**数据准备**或**数据预处理**。
*数据准备是臭名昭著的*[*21 世纪最性感的工作*](https://hbr.org/2012/10/data-scientist-the-sexiest-job-of-the-21st-century) *中不性感的部分。*
由于 Python 和 r 中提供了各种专用的库和包,训练 ML 算法并利用它们来预测目标变量是很容易的事情。然而,在数据科学和 ML 世界中,垃圾进,垃圾出(GIGO)的古老格言仍然适用。
数据准备活动将原始数据转换成能够被 ML 算法有效和高效使用的形式、形状和格式。它是 ML 流程的重要组成部分,可以决定 ML 流程的成败。
> 从业者一致认为,构建机器学习管道的绝大部分时间都花在了特征工程和数据清理上。然而,尽管这个话题很重要,却很少被单独讨论。
**数据清理**只是数据准备活动的一个组成部分,数据准备活动还包括特征选择、数据转换、特征工程和降维。
根据定义,数据处理活动和数据清理对于每组原始数据都是独一无二的,因为实际的 ML 项目都有其固有的特性。尽管如此,某些活动是标准的,应该应用,或者至少在模型训练之前检查原始数据。
> 不管要修复的数据错误的类型如何,数据清理活动通常包括两个阶段:(1)错误检测,其中各种错误和违规被识别并可能由专家验证;以及(2)错误修复,其中应用对数据库的更新(或向人类专家建议)以将数据带到适合于下游应用和分析的更干净的状态。
# 警告!
在我们探索各种标准数据清理活动之前,需要注意一点。正如我在[之前的一篇文章](/how-to-avoid-potential-machine-learning-pitfalls-a08781f3518e)中提到的:在将你的整个数据分割成训练/测试/验证子集之后,应该对数值训练数据集执行以下所有操作,以避免数据泄露。只有这样,一旦您有了一个干净的训练数据集,如果需要,在测试(和验证)数据集和目标变量上重复相同的活动集。
在下面的所有代码片段中,按照常规符号,`X_train`指的是训练输入数据集。
# 基本数据清理
下面的操作应该成为你的 ML 项目的起点,应用到你得到的每一个数据。
## 识别并删除零方差预测值
零方差预测值是指在整个观测范围内包含单个值的输入要素。因此,它们不会给预测算法增加任何值,因为目标变量不受输入值的影响,这使得它们是多余的。一些 ML 算法也可能遇到意外的错误或输出错误的结果。
Pandas 提供了一个简短的函数来计算和列出 Pandas 数据帧中每一列的唯一值的数量:
X_train.nunique()
当要删除的列不多时,通过`X_train.drop(columns=['column_A', 'column_B'], inplace=True)`从 Pandas 数据帧中删除特定的列非常简单。使用多个零方差列实现相同结果的更可靠的方法是:
X_train.drop(columns = X_train.columns[X_train.nunique() == 1],
inplace = True)
上面的代码将删除所有只有一个值的列,并更新`X_train`数据帧。
## 评估具有很少唯一值的列
对于唯一值很少的列(即低方差或接近零的方差),应该给予特别的考虑。这样的列不是要从数据集中删除的自动候选列。例如,按照设计,[序数](https://en.wikipedia.org/wiki/Ordinal_data)或[分类](https://en.wikipedia.org/wiki/Categorical_variable)列不应该有大量的唯一值。
直觉上,我们可以天真地删除低方差列,但如果这样的预测器实际上对模型学习有帮助呢?例如,假设分类问题中的二元特征有许多 0 和几个 1(接近零的方差预测值)。当这个输入特征等于 1 时,目标变量总是相同的;然而,在该特征为零的情况下,它可以是任何一个可能的目标值。保留这个专栏作为我们的预测指标之一当然是有道理的。
因此,应该利用上下文考虑和领域知识来评估是否应该从我们的数据集中删除这样的低方差列。例如:
* 考虑将它们编码为序数变量
* 考虑将它们编码为分类变量
* 考虑通过一些降维技术(如主成分分析(PCA ))来组合这些低方差列
我们可以手动计算每列中唯一值的数量占观察总数的百分比,如下所示:
from numpy import uniquefor i in range(X_traain.shape[1]):
num = len(unique(X_train.iloc[:, i]))
percentage = float(num) / X_train.shape[0] * 100
print('%d, %d, %.1f%%' % (i, num, percentage))
上面的代码将打印出所有列的列表,以及唯一值的计数及其占观察总数的百分比。
或者,我们可以利用 scikit-learn 库的`[VarianceThreshold](https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.VarianceThreshold.html)` 类来识别**并删除**低方差列。使用`VarianceThreshold`类时要格外小心,因为它被设计用来删除低于参数化阈值的列。
## 处理重复数据
最有可能的是,应该从数据中删除重复的行,因为它们很可能是多余的。
Pandas 提供了一个简单的函数来检查数据帧中的重复行。请注意,这将只显示第二行(以及任何更高一级的行),因为被复制的第一行不被认为是重复的。
X_train[X_train.duplicated()]
如果在分析完重复记录后,您想继续删除它们,一行代码就可以实现:
X_train.drop_duplicates(inplace = True)
# 离群点检测
离群值是在给定数据集的上下文中看起来很少或不太可能的任何数据点。领域知识和主题专业知识对于识别异常值很有用。尽管考虑到异常值的上下文性质,没有标准的异常值定义,但是可以使用各种统计和绘图方法来识别和适当地处理它们。
与低方差列类似,异常值观察值不会自动删除。相反,这些应该进一步分析,以确定它们是否真的是异常的。
盒须图是直观显示数据框架中数值异常值的简单而基本的方法:
X_train.boxplot()
现在让我们来看看一些识别异常值的统计技术。
## 使用标准偏差(SD)
用于异常值检测的 SD 技术可以应用于呈现高斯或类高斯分布的所有数值特征。作为复习,回想一下:
* 68%的正态分布观测值位于平均值的±1 SD 范围内
* 95%的正态分布观测值位于平均值的±2sd 范围内
* 99.7%的正态分布观测值位于平均值的±3 SD 范围内
以下代码行将选择并删除值大于每个数字列的指定 SDx 的所有行。3 SDs 是标准阈值;然而,2 个 SDs 可用于小数据集,4 个 SDs 可用于相对大的数据集。
## 使用四分位数间距(IQR)
我们可以使用 [IQR](https://en.wikipedia.org/wiki/Interquartile_range) 来识别输入要素中不符合正态或类正态分布的异常值。超出指定阈值的值(通常,高于第 75 百分位但低于第 25 百分位的 1.5 倍 IQR)将被过滤掉,以供进一步分析。
下面的代码片段将过滤掉阈值为 1.5 的所有数值列中的异常值。
## 本地异常因素(LOF)
从 scikit-learn 的[文档](https://scikit-learn.org/stable/auto_examples/neighbors/plot_lof_outlier_detection.html),“LOF 算法是一种无监督的异常检测方法,它计算给定数据点相对于其邻居的局部密度偏差。它将密度远低于其相邻样本的样本视为异常值。”。原文可以在这里找到[。](https://www.dbs.ifi.lmu.de/Publikationen/Papers/LOF.pdf)
`[LocalOutlierFactor](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.LocalOutlierFactor.html)`的`fit_predict`方法预测数据帧中的每一行是否包含数值异常值(-1)或(1)。有异常值的行标记为-1,否则标记为 1。下面是一个简单实用的例子:
关于 LOF 有一点需要注意:它不允许在传递给 predict 方法的数据中有空值或缺失值。
# 统计估算缺失值
只是重申一个显而易见的事实,丢失值在现实生活中并不少见。大多数 ML 算法无法处理缺失值,并且会在模型训练期间抛出错误。因此,数据集中这种丢失的值应该被丢弃(最天真的方法,并且要尽可能避免——数据是新的货币!)或以某种方式进行逻辑上的估算。
通常用于此类插补的某些有效描述性统计数据包括:
* 列的平均值
* 列的中值
* 列的模式值
* 其他一些共同的价值观
查找和检测缺失值或空值的一些简单方法是执行以下函数之一:
display the count of non-null values in each column of a DF
df.info()# display the count of null values in each column of a DF
df.isnull().sum()
使用 Python 的内置函数统计输入缺失值非常简单。以下函数计算每一列的描述性统计数据,并使用计算出的统计数据填充该特定列中的所有空值:
using mean to fill missing values
df.fillna(df.mean(), inplace = True)# using median to fill missing values
df.fillna(df.median(), inplace = True)# using mode to fill missing values
df.fillna(df.mode().iloc[0], inplace = True)# using a specific constant to fill missing values
df.fillna(0, inplace = True)
但是,请记住,描述性统计数据只能在训练数据集上计算;然后应该使用相同的统计来估算训练和测试数据中的任何缺失值。上述方法适用于简单的训练/测试分割;然而,当使用 k-fold 交叉验证评估模型时,这实际上变得不可能——因为分裂是在单个函数调用中多次完成和重复的。
Scikit-learn 的`Pipeline`和`SimpleImputer`来拯救我们了。
## `SimpleImputer`的独立实现
`[SimpleImputer](https://scikit-learn.org/stable/modules/generated/sklearn.impute.SimpleImputer.html)`类通过以下步骤进行数据转换:
* 使用要使用的描述性统计类型定义分类。均支持均值、中值、众数和特定的常数值
* 拟合定型数据集,根据定型数据计算每列的统计信息
* 将拟合的估算值应用于训练和测试数据集,以将第二步中计算的统计值分配给这两个数据集中的缺失值
下面是一个简单的演示:
## 用管道实现简单输入
Scikit-learn 的[管道](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html)允许我们在单个步骤中应用最终估计器模型之前顺序执行多个数据转换。通过确保使用相同的样本来训练变压器和预测器,这可以防止数据“在交叉验证中从测试数据泄漏到训练模型中”(来自[文档](https://scikit-learn.org/stable/modules/compose.html#pipeline-chaining-estimators))。
最佳实践是在使用交叉验证时利用 Pipeline,如下所示:
一个简单的`for`循环也可用于分析`SimpleImputer`中所有四种不同的插补策略:
上面列出了每种估算策略的平均准确度分数。
使用 Pipeline,通过新的、具有潜在缺失值的实时数据来预测目标变量,如下所示:
define pipeline
pipeline = Pipeline(steps=['i', SimpleImputer(strategy='mean')),
('m', RandomForestClassifier())])# fit the model
pipeline.fit(X, y)# predict on new data using the fitted model
pipeline.predict(new_data)
# kNN 缺失值插补
除了使用描述性统计来估算缺失值,还可以使用 ML 算法来预测缺失值。简单的回归模型可用于预测缺失值;然而,k-最近邻(kNN)模型在实践中也被发现是有效的。
Scikit-learn 的`[KNNImputer](https://scikit-learn.org/stable/modules/generated/sklearn.impute.KNNImputer.html)`类支持 kNN 插补——其用法与`SimpleImputer`非常相似。就像`SimpleImputer`一样,在管道中实现之前,我将首先演示`KNNImputer`的独立使用。
## 用流水线实现 KNNImputer
现在,让我们看看如何在管道中实现它以进行有效的验证:
我们还可以应用一个`for`循环来检查多个`k_neighbors`参数,以根据我们的精度指标确定最佳参数:
使用包含缺失值的新实时数据来预测目标变量的方法与上述`SimpleImputer`中的方法相同。
# 结论
这就是我这次在 Python 中针对机器学习项目的具体数据清理任务。
如果您想讨论任何与数据分析和机器学习相关的问题,请随时联系 [me](http://www.finlyticshub.com) 。
下次见——摇滚起来!
## 灵感和参考
[机器学习大师](https://machinelearningmastery.com/)的杰森·布朗利
[1]郑,a .,&卡萨里,A. (2018)。前言。在*机器学习的特征工程:数据科学家的原则和技术*(第 vii 页)。塞瓦斯托波尔,加利福尼亚州:奥赖利。
[2],国际货币基金组织,&楚,X. (2019)。引言。在*数据清理*(第 1 页)中。纽约:计算机协会。
# 实体解析实用指南—第 1 部分
> 原文:<https://towardsdatascience.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e?source=collection_archive---------13----------------------->
## [理解大数据](https://towardsdatascience.com/tagged/making-sense-of-big-data)
## *这是关于实体解析的小型系列文章的第 1 部分*

照片由[亨特·哈里特](https://unsplash.com/@hharritt?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 拍摄
**什么是实体解析(ER)?**
实体解析(ER)是在缺少连接键的情况下,在代表现实中同一事物的不同数据记录之间创建系统链接的过程。例如,假设您有一个在 Amazon 上销售的产品数据集,和另一个在 Google 上销售的产品数据集。它们可能有稍微不同的名称、稍微不同的描述、可能相似的价格和完全不同的唯一标识符。人们可能会查看这两个来源的记录,并确定它们是否涉及相同的产品,但这并不适用于所有记录。我们需要查看的潜在对的数量是 x G,其中 A 是亚马逊数据集中的记录数量,G 是谷歌数据集中的记录数量。如果每个数据集中有 1000 条记录,那么就有 100 万对要检查,而这只是针对 2 个相当小的数据集。随着数据集越来越大,复杂性会迅速增加。实体解析是解决这一挑战的算法,并以系统和可扩展的方式导出规范实体。
**我为什么要关心 ER?**
从数据中释放价值通常依赖于数据集成。通过整合关于感兴趣的实体的不同数据片段而创建的整体数据图,在为决策提供信息方面比部分或不完整的视图有效得多。例如,如果汽车制造商的保修分析师能够通过运行过程中产生的传感器读数,从供应链开始,到装配到车辆中,全面了解与相关零件相关的所有数据,她就可以更有效地诊断索赔。类似地,如果风险投资者对潜在公司的所有数据有一个综合的看法,从团队的质量到其在市场上的吸引力和围绕它的传言,她可以更有效地选择最佳投资。执法、反恐、反洗钱等众多工作流也需要集成的数据资产。然而,数据(尤其是第三方数据)的不幸现实是,它通常是特定应用程序或流程的耗尽物,并且它从未被设计为与其他数据集结合使用来为决策提供信息。因此,包含关于同一现实世界实体的不同方面信息的数据集通常存储在不同的位置,具有不同的形状,并且没有一致的连接键。这就是 ER 特别有用的地方,它可以系统地集成不同的数据源,并提供感兴趣的实体的整体视图。
我怎么呃?
概括来说,ER 有 5 个核心步骤:
1. [源规范化](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-2-ab6e42572405) —清理数据并将不同的源协调到一个通用的要素(列)模式中,该模式将用于评估潜在的匹配
2. [特征化和块密钥生成](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-3-1b2c262f50a7) —为块密钥创建特征,块密钥是可能在匹配记录之间共享的目标令牌,以将搜索空间从 N 限制为在计算上更易于管理的空间
3. [生成候选对](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-4-299ac89b9415)——使用阻塞连接键创建潜在的候选对。这本质上是块键上的自连接,通常使用图形数据结构来实现,单个记录作为节点,潜在的匹配作为边
4. [匹配评分和迭代](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-5-5ecdd0005470) —通过匹配评分功能决定哪些候选对实际匹配。这可以是基于规则的,但是通常更好地实现为学习算法,其可以在非线性决策边界上适应和优化
5. [生成实体](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-6-e5d969e72d89) —消除图形中不匹配的边,并生成已解析的实体和到各个源记录的关联映射
在接下来的几篇文章中,我将深入研究上面的每一个步骤,通过一个具体的例子,提供深入的解释,以及如何大规模实现它们的 PySpark 代码示例。
希望这是一次有益的讨论。如果您有任何意见或问题,请随时联系我们。[Twitter](https://twitter.com/yifei_huang)|[Linkedin](https://www.linkedin.com/in/yifeihuangdatascience/)|[Medium](https://yifei-huang.medium.com/)
查看第 2 部分[源标准化](/practical-guide-to-entity-resolution-part-2-ab6e42572405)
# 实体解析实用指南—第 2 部分
> 原文:<https://towardsdatascience.com/practical-guide-to-entity-resolution-part-2-ab6e42572405?source=collection_archive---------17----------------------->
## *源归一化*

规范化数据就像锻造金属一样,需要精确和小心。照片由[乔尼·古铁雷斯——乔尼博士多媒体](https://unsplash.com/@dr_joni_multimedia?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
这是关于实体解析的小型系列的第 2 部分。如果你错过了,请查看 [*第一部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e)
*本系列的第 2 部分将重点关注实体解析的源规范化步骤,并将使用在这里获得的[Amazon-Google products 数据集作为示例来说明思路和实现。本系列的其余部分也将参考这个例子。该数据集包含两个不同的产品目录,其中包含引用同一物理产品的记录。目标是系统地找出哪些记录是重复的,并且实际上是同一个实体。](https://dbs.uni-leipzig.de/research/projects/object_matching/benchmark_datasets_for_entity_resolution)*
*这是示例数据的样子*
**谷歌产品**
**
**亚马逊产品**
**
*并且,具体来说,我们希望能够系统地将谷歌数据集中类似于 ***apple shake 4.1 数字合成软件 for mac os x effects 软件*** 的记录匹配到亚马逊数据集中的****apple shake 4.1 视觉效果(mac)*** 。但首先,我们必须从源代码规范化开始。**
****什么是源规范化,为什么它对 er 很重要?****
**在 ER 的上下文中,源规范化意味着**
1. **创建包含所有不同来源的统一数据集-这一点很重要,因为它允许您扩展到任意数量的输入来源,同时仍然保持一致的下游处理和匹配。**
2. **通过标准化数据类型(例如,确保空值实际上是空值而不是字符串空值)、统一格式(例如,所有内容都是小写)和删除特殊字符(例如,括号和圆括号)来清理数据,这消除了无关的差异,并可以显著提高匹配的准确性。**
**下面是为两个产品目录实现规范化的 PySpark 代码示例。注意,这是说明性的,而不是穷举的。**
**这种情况下的模式已经非常相似,因此创建统一的模式相对简单。请注意,您可能希望包含一个源和源 id 列来唯一标识记录,以防输入源之间存在 ID 冲突。**
**清理和标准化数据稍微复杂一点,具体的预处理方法在很大程度上取决于数据类型和所需的比较算法。在这个特殊的例子中,因为可用的元数据主要是文本和自然语言,所以比较可能需要依靠字符串相似性和 NLP 技术。因此,规范化像`name, description` 这样的字符串列并删除无关的字符是很重要的。**
**为了说明标准化过程,这里有一个清洗步骤前后产品名称的比较示例**
compaq comp. secure path v3.0c-netware wrkgrp 50 lic ( 231327-b22 )
**相对**
compaq comp secure path v3 0c netware wrkgrp 50 lic 231327 b22
**随着我们的数据集规范化,我们已经准备好解决[特征化和阻塞](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-3-1b2c262f50a7)。**
# 实体解析实用指南—第 3 部分
> 原文:<https://towardsdatascience.com/practical-guide-to-entity-resolution-part-3-1b2c262f50a7?source=collection_archive---------12----------------------->
## *特征化和阻塞密钥生成*

照片由 [Honey Yanibel Minaya Cruz](https://unsplash.com/@honeyyanibel?utm_source=medium&utm_medium=referral) 在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄
*这是关于实体解析的小型系列的第 3 部分。查看* [*第一部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e) *,* [*第二部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-2-ab6e42572405) *如果你错过了*
**什么是特征化和阻塞,为什么它很重要?**
在 ER 的上下文中,特征化意味着将现有的列转换为派生的特征,这些派生的特征可以通知不同的记录是否引用同一事物。分块意味着选择一个目标特征子集作为自连接键,以有效地创建潜在的匹配候选对。在我们的讨论中将这两个步骤分组的原因是块密钥通常是从特征中派生出来的。
良好的特征化能够实现高效的阻塞以及下游良好的匹配精度,因此它是 ER 过程的关键部分。这也是定义最少的一步,在这个过程中可以注入大量的创造力。
良好的分块可以极大地提高 ER 过程的效率,并且可以扩展到许多输入源和大型数据集。正如我们在 [*第一部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e) 中所讨论的,潜在候选对的论域是 N 与记录数。然而,并不是所有的候选对都值得评估。比如`learning quickbooks 2007`和`superstart fun with reading writing`显然不是一回事,不应该包含在候选对中。解决这个问题的一种方法是使用更具体的阻塞键,例如产品的确切字符串名称,来创建候选对。这样,只有具有完全相同的标准化名称字符串的产品才会包含在候选对中。然而,这显然限制太多,会错过像`learning quickbooks 2007`和`learning qb 2007`这样的潜在匹配。好的阻塞键选择对于有效地平衡好的效率和低的假阴性率之间的折衷是至关重要的。
**如何实现特征化和模块化?**
特征化,也许比 ER 中前面的步骤更重要,取决于源数据的类型和所需的下游比较算法。在这里,我们不会尝试提供一组详尽的可能技术,而是专注于 Amazon vs Google 产品的示例用例的说明性实现。在规范化的数据集中,我们有 4 列要处理,它们的特征是`name, description, manufacturer, price`。4 列中有 3 列是基于文本的,大部分识别信息都存储在其中。因此,我们将在这里集中大部分的特性化工作。有许多方法来特征化文本数据,但是在高层次上,它们通常归结为
1. 标记化——例如[将句子分解成单词](https://nlp.stanford.edu/IR-book/html/htmledition/tokenization-1.html)
2. 令牌标准化——例如[词干](https://en.wikipedia.org/wiki/Stemming)或[词汇化](https://en.wikipedia.org/wiki/Lemmatisation)
3. 嵌入——例如 [TF-IDF](https://en.wikipedia.org/wiki/Tf%E2%80%93idf) 、[单词嵌入](https://en.wikipedia.org/wiki/Word_embedding)、[句子嵌入](https://en.wikipedia.org/wiki/Sentence_embedding)
对于我们的特定示例,我们将使用一个基本的 TF-IDF 模型,在该模型中,我们对文本进行标记,删除英语停用词,并应用 TF-IDF 矢量化。我们还将使用 Tensorflow 的 U [通用语句编码器](https://tfhub.dev/google/universal-sentence-encoder/4)模型,将名称和描述字符串转换成 512 维向量。
通过将这两个转换应用到`name, description, manufacturer`中的文本列,我们最终得到了许多丰富的特性,可以用来评估候选对之间的潜在匹配,以及帮助选择阻塞键。具体来说,TF-IDF 向量和句子编码向量在生成良好的块密钥方面非常有用。
正如我们上面讨论的,一个好的阻塞键是平衡特异性和假阴性率的东西。一个产品的全称是特定的,但也有非常高的假阴性率。我们可以通过在产品名称或描述中选择单个单词来解决这个问题。但是,重要的是要注意,就阻塞的目的而言,有些标记比其他标记更好。例如在`learning quickbooks 2007`中,`quickbooks`直观上是最好的阻挡键,其次是`2007`,再其次是`learning`。这是因为`quickbooks`是定义产品最有意义的关键词,`2007`是特定于产品版本的,而`learning`是一个非常通用的描述符。方便的是,这也正是 TF-IDF 试图系统测量的,并且`learning quickbooks 2007`的归一化 TF-IDF 令牌权重是`quickbooks` : 0.7,`2007` : 0.51,`learning` : 0.5。如您所见,令牌的 TF-IDF 权重是一个不错的代理指标,可用于区分优先级和选择良好的阻塞密钥。
类似地,句子编码向量权重也告诉我们潜在向量空间中的哪个维度对句子的意义最显著,并且可以用于选择分块密钥。然而,在句子编码的情况下,具有最高权重的维度不直接映射到单词标记,因此可解释性较低。
实现上述内容的 PySpark 代码示例如下
上面的代码利用`pyspark.ml`库来
1. 将 TF-IDF 变换应用于`name`、`description`和`manufacturer`
2. 根据 TF-IDF 令牌权重挑选出前 5 个令牌作为阻止密钥
3. 使用通用语句编码器将`name`和`descriptions`转换为 512 维向量表示。我们在这里省略了`manufacturer`,因为它是稀疏的,并且作为一个英语句子也没有太多的语义意义。请注意,我们实际上并没有从编码中生成块密钥,但是类似于 TF-IDF 令牌的方法也可以很容易地应用到这里
4. 将 top name 标记、top description 标记和 top manufacturer 组合成每个记录的一个块键数组。请注意,每条记录可以有一个以上的阻止键。这也是为了减少潜在匹配的假阴性率。
应用通用语句编码器的用户定义函数值得快速解包
magic function to load model only once per executor
MODEL = None
def get_model_magic():
global MODEL
if MODEL is None:
MODEL = hub.load("https://tfhub.dev/google/universal-sentence-encoder/4")
return MODEL@udf(returnType=VectorUDT())
def encode_sentence(x):
model = get_model_magic()
emb = model([x]).numpy()[0]
return Vectors.dense(emb)
这到底是在做什么,为什么有必要?Tensorflow hub 提供了一个预训练的模型,可以帮助用户将文本转换为矢量表示。这个模型不是分布式的,这意味着为了利用 Spark 这样的分布式计算框架,我们必须将它封装在一个用户定义的函数中,并使它在每个执行器节点上都可用。然而,我们不希望每次转换一段文本时都执行昂贵的`load`调用。我们只希望每个执行器加载一次,然后在分配给该节点的所有任务中重用。`get_model_magic`方法本质上是实现这一点的技巧。
现在我们已经有了我们的特征和阻塞键,我们准备好处理[候选对生成和匹配评分](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-4-299ac89b9415)。
# 实体解析实用指南—第 4 部分
> 原文:<https://towardsdatascience.com/practical-guide-to-entity-resolution-part-4-299ac89b9415?source=collection_archive---------19----------------------->
## *候选配对生成和初始匹配评分*

照片由[艾莉娜·格鲁布尼亚](https://unsplash.com/@alinnnaaaa?utm_source=medium&utm_medium=referral)在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 拍摄
*这是关于实体解析的小型系列的第 4 部分。查看* [*第一部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e)*[*第二部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-2-ab6e42572405)*[*第三部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-3-1b2c262f50a7) *如果你错过了***
**候选对生成是 ER 的一个相当简单的部分,因为它本质上是阻塞键上的自连接。但是,为了确保实现的高效性和可伸缩性,需要注意一些实际问题:**
1. **由阻塞连接产生的数据结构可以被建模为图,其中每个记录是节点,候选对连接是边。与更传统的表格结构相比,将它建模为图形对于下游计算来说更有性能,在传统的表格结构中,您将创建相同数据的更多副本。**
2. **给单个块的大小设定一个上限是个好主意。这可以防止具有非常低特异性的阻塞键创建高度连接的节点,从而导致对性能产生负面影响的非常不对称的分区。阈值取决于特定的应用程序和数据集,但粗略的心理模型是应该解析为单个实体的合理记录数量。在这个产品目录的特殊例子中,我们选择了 100 个,因为很难想象会有超过 100 个不同的产品列表实际上指的是同一个物理产品。**
3. **对块键执行自连接时,节点的顺序不会改变对,因此所有顺序相反的对都应进行重复数据消除。类似地,自配对也应该被移除,因为没有必要将节点与其自身进行比较。**
**下面是实现候选对生成的 PySpark 代码示例,请注意`GraphFrame`包的使用**
**候选对生成后的下一步是对候选对匹配可能性进行评分。这对于删除不匹配项和创建最终解析的实体至关重要。这一步也是相当开放的,人们可以对要实现的特定评分功能和特征非常有创意。这也是需要迭代来逐步提高特征和匹配精度的地方。通常,这看起来像创建一个简单的第一得分函数,并使用该函数的输出分布来通知迭代的方向。**
**对于示例用例,初始评分功能利用以下指标**
1. **TF-IDF 和`name, description, manufacturer`的句子编码向量之间的点积或余弦距离**
2. **`name, description, manufacturer`的规范化字符串之间的 Levenshtein 距离**
3. **`prices`之间的相似性**
4. **标记重叠作为标记化的较短字符串长度的一部分`name, description, manufacturer`**
**粗略的第一评分函数是简单地将这些单独的相似性度量相加。下面是实现这个的 PySpark。请注意,这只是起点,我们将详细讨论如何利用机器学习模型来迭代提高匹配精度。将产生的 PySpark 数据帧与单独的相似性度量保持一致是一个好主意,这样可以减少下游迭代的开销。**
**查看第 5 部分的[匹配分数迭代](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-5-5ecdd0005470)**
# 实体解析实用指南—第 5 部分
> 原文:<https://towardsdatascience.com/practical-guide-to-entity-resolution-part-5-5ecdd0005470?source=collection_archive---------21----------------------->
## 匹配评分迭代

劳拉·奥克尔在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
这是关于实体解析的小型系列的第 5 部分。如果你错过了,请查看[第 1 部分](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e)、[第 2 部分](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-2-ab6e42572405)、[第 3 部分](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-3-1b2c262f50a7)、[第 4 部分](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-4-299ac89b9415)
在大多数真实的 ER 用例中,没有关于哪个候选对应该匹配,哪个不应该匹配的基本事实。获得良好匹配精度的唯一方法是在迭代学习循环中引入人工判断,并逐步改进评分算法。在这篇文章中,我们将讨论如何建立这个学习循环。
概括地说,这个过程看起来像
1. 初始朴素得分函数输出的示例
2. 手动检查并标记采样的候选对
3. 通过比较手动标签和分数分布来评估分数准确性
4. 通过在有保证和适当的情况下引入额外的比较功能来改进决策标准
5. 将标签和特征输入分类算法,以学习最佳评分函数
6. 重复进行,直到达到可接受的精度水平

分数迭代学习循环
从初始评分函数中取样并手动检查输出相当简单,但是有一些实际的东西值得注意
1. 完全匹配和完全不匹配不值得研究。实际上,这意味着得分为 0(没有任何特征匹配)和 1(所有特征完全匹配)的对应该被过滤掉。
2. 值得思考的是通过最佳的视觉布局,让人工审核和标注尽可能的容易。有像[通气管](https://snorkel.readthedocs.io/en/v0.9.3/packages/labeling.html)这样的工具来帮助这种类型的工作流程。在我们的示例中,我们选择了一种相对较低的方法,即将候选对之间的对应特征堆叠到一个组合的字符串值中,以便更容易比较它们。
3. 可能会有需要使用分层抽样的用例。例如,您可能希望更多地关注来自不同源系统的记录之间的候选对,而花费较少的时间来审查来自相同源的候选对。您可能还想对相似性得分的不同范围进行不同的加权。我们在示例代码中没有这样做,但是使用 PySpark 方法`sampleBy`实现并不困难

来自采样候选对的示例输出
通过查看采样输出,我们可以立即看到,我们使用的简单评分函数远非完美。`adobe creative suite cs3 web standard upsell`
和`adobe creative suite cs3 web standard [mac]`之间的最高分候选对之一显然不匹配。事实上,有很多这种不匹配的例子,产品的升级版本看起来与原始产品非常相似。解决这个问题的一个潜在方法是引入另一个特征,该特征指示产品是否是扩展/升级/追加销售而不是全功能版本。
然而,在此之前,我们可以将现有的特征和手动输入的`human_label`输入到 ML 分类算法中,该算法可以学习如何以最佳方式将各个相似性度量组合到评分函数中。下面是实现这一点的 PySpark 代码示例。
几件值得注意的实际事情
1. 即使有好的阻挡策略,大部分候选对也可能是明显的不匹配。在应用模型之前将它们过滤掉是有用的。这减少了匹配与非匹配类的不平衡,这种不平衡会对模型的功效产生负面影响。在我们的示例中,我们这样做是为了过滤掉低于阈值 0.06 的任何对。这是通过手动检查采样的候选对来任意选择的,并且可以根据需要进行调整。
2. 在可能的情况下,使用基于编程规则的附加标签来补充人工标签是很有帮助的。算法需要学习的标签数据越多,它的表现就越好。在我们的例子中,我们选择将`overall_sim`为 1 或者`name_tfidf_sim`为 1 的候选对标记为程序化匹配。这里的直觉是,如果名称完全匹配,我们可以很有把握地认为这两个列表是同一产品。另一方面,我们已经选择标记具有小于 0.12 的`overall_sim`的候选对。这也是根据采样输出任意选择的。这些阈值可以而且应该作为迭代的一部分进行调整。
3. 对于我们的示例用例,我们选择使用 [Scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html) 的随机森林分类器实现,因为它提供了围绕超参数调整和评估的更灵活的 API。但是对于单个节点上的内存无法容纳的大规模用例,可能有必要使用 [PySpark ML 库](https://spark.apache.org/docs/latest/api/python/pyspark.ml.html#module-pyspark.ml.classification),它实现了许多分类算法,可以很好地与 PySpark 生态系统的其余部分集成。
一旦模型得到调整,我们有了适当的交叉验证指标,我们将希望应用该模型对更广泛的领域进行评分,并检查输出匹配概率与人类判断的对比。PySpark 代码示例如下。
值得注意的是`pandas_udf`的使用,它可以通过 Apache Arrow 实现更高效的序列化,通过 numpy 实现更高效的矢量化计算,从而获得比标准 UDF 更好的性能。要了解更多关于`pandas_udf`的信息,我推荐阅读中的[示例。](https://spark.apache.org/docs/latest/sql-pyspark-pandas-with-arrow.html)

基于匹配概率建模的采样输出
从新的样本中,我们可以看到模型在挑选匹配对方面做得更好,即使初始天真评分函数给出的相似性较低。这样,我们通过更新的评分函数和来自新评分分布的更新样本,有效地结束了学习循环。基于与人类判断的进一步比较的结果,我们可能想要添加额外的特征,以标记工作为目标,更新模型/评分函数,并且再重复该过程几次,直到达到期望的准确度水平。
查看[实体生成](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-6-e5d969e72d89)的最后部分
# 实体解析实用指南—第 6 部分
> 原文:<https://towardsdatascience.com/practical-guide-to-entity-resolution-part-6-e5d969e72d89?source=collection_archive---------39----------------------->
## 生成实体

迈克尔·泽兹奇在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的照片
*这是关于实体解析的迷你系列的最后一部分。查看* [*第一部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-1-f7893402ea7e)*[*第二部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-2-ab6e42572405)*[*第三部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-3-1b2c262f50a7)*[*第四部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-4-299ac89b9415)*[*第五部分*](https://yifei-huang.medium.com/practical-guide-to-entity-resolution-part-5-5ecdd0005470) *如果你错过了*****
**ER 的最终输出是一个数据结构,它具有每个解析实体的唯一标识符,以及唯一实体标识符和不同源系统中解析数据记录的相应标识符之间的映射。这样做相对简单**
1. **使用调整的基于模型的评分函数来消除不匹配的候选对。这通常意味着在计分迭代之后选择匹配概率的截止阈值。基于手动检查,我们为我们的示例用例选择了 0.5,但是该值可以根据数据集、功能、模型和用例而变化**
2. **仅使用超过匹配概率阈值的“强”边来重新生成图**
3. **通过连接组件算法创建组件(或实体)映射**
**就是这样!我们现在有了一个映射表,将不同的数据记录连接成统一的实体。由此,通过基于对来自每个连接记录的各个元数据值进行优先排序或组合来选择或生成规范元数据(例如,名称、描述等)来创建规范实体表通常是有益的。这里的具体方法将在很大程度上取决于所需的应用程序和工作流,所以我们不会深入研究它。**
**关于实体解析的迷你系列到此结束。无论如何,这都不是一个详尽的研究,但是希望提供核心概念和实现步骤的实用概述,以帮助您开始自己的应用程序。我欢迎你的任何意见和建议。**
# 用 OpenCV 实现实用的图像处理
> 原文:<https://towardsdatascience.com/practical-image-process-with-opencv-8405772c603e?source=collection_archive---------31----------------------->
图像处理基本上是为我们提供从图像中获取特征的过程。图像处理适用于图像和视频。这些是为了使深度学习结构中的训练更成功而经常使用的程序。
# 图像处理
图像处理始于计算机对数据的识别。首先,为图像格式的数据创建矩阵。图像中的每个像素值都被处理到这个矩阵中。例如,为大小为 200x200 的图片创建大小为 200x200 的矩阵。如果此图像是彩色的,此尺寸将变为 200x200x3 (RGB)。事实上,图像处理中的每一个操作都是矩阵运算。假设希望对图像进行模糊操作。特定的过滤器在整个矩阵上移动,从而改变所有矩阵元素或部分矩阵元素。作为这个过程的结果,图像的所需部分或全部变得模糊。
在很多情况下都需要对图像进行处理[1]。通常,这些操作应用于将在深度学习模型中使用的图像格式数据。例如,在某些项目中,数据带有颜色并不重要。在这种情况下,使用彩色图像进行训练会导致性能损失。图像处理中使用最广泛的深度学习结构之一是卷积神经网络。该网络确定了用图像上的卷积层进行训练所需的属性。此时,可能只需要处理将用于训练的图像的某些部分。突出更圆的线条,而不是图片中的尖锐线条,有时可以提高训练的成功率。
在这种情况下,使用图像处理技术。您可以[点击](https://neptune.ai/blog/image-processing-python)获取更多关于图像处理的信息【9】。
除了上述情况之外,相同的逻辑基于日常生活中使用的图像优化程序的操作。在图像处理中有许多过程,如提高图像质量、图像复原、去噪、直方图均衡化等。
# **OpenCV**
OpenCV 是用于图像处理的最流行的库之一[2]。使用 OpenCV 的公司有很多,比如微软、英特尔、谷歌、雅虎。OpenCV 支持多种编程语言,如 Java、C++、Python 和 Matlab。本书中的所有样本都是用 Python 编写的。
import cv2
from matplotlib import pyplot as plt
import numpy as np
首先,库被导入。OpenCV 中有一些函数并不是每个版本都能稳定运行。其中一个功能是“imshow”。该功能使我们能够看到操作后图像的变化。在这项工作中,matplotlib 库将作为有此类问题的人的替代解决方案。

图一。标准图像
要执行的过程将应用于上面显示的图像(图 1)。首先读取图像,以便对其进行处理。
img_path = "/Users/..../opencv/road.jpeg"
img = cv2.imread(img_path)
print(img.shape)>>>(960, 1280, 3)
在图 2 中,图像的尺寸为 960 x 1280 像素。当我们在读取过程后想要打印尺寸时,我们看到 960x1280x3 的结果。因此创建了一个矩阵,直到图像的尺寸,并且这个矩阵被赋予图像的每个像素的值。因为图像是彩色的,所以从 RGB 有 3 个维度。
如果我们想把图像转换成黑白,就使用 cvtColor 函数。
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
如果我们希望看到作为这个函数的结果发生的变化,我们使用 matplotlib 中的 imshow 函数。
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray_image)
plt.show()
print(gray_image.shape)>>>(960, 1280)

图二。黑白图像
如图 2 所示,我们已经将图像转换为黑白。当我们检查它们的尺寸时,由于 RGB,不再有三维。当你查看图像的矩阵值时,我们看到它由 0 到 255 之间的值组成。在某些情况下,我们可能希望这个矩阵只包含值 0 和 255 [3]。在这种情况下使用阈值函数。
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 20, 255, cv2.THRESH_BINARY)
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 80, 255, cv2.THRESH_BINARY)
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 160, 255, cv2.THRESH_BINARY)
(thresh, blackAndWhiteImage) = cv2.threshold(gray_image, 200, 255, cv2.THRESH_BINARY)
plt.imshow(blackAndWhiteImage)
plt.show()

图 3。应用了阈值函数的图像
OpenCV 中 threshold 函数需要的第一个参数是要处理的图像。以下参数是阈值。第三个参数是我们希望分配给超过阈值的矩阵元素的值。图 3 显示了四种不同阈值的效果。在第一幅图像(图像 1)中,阈值被确定为 20。所有大于 20 的值都被赋值为 255。其余值设置为 0。这使得只有黑色或非常暗的颜色是黑色,所有其他色调直接是白色。图像 2 和图像 3 的阈值分别为 80 和 160。最后,在图像 4 中阈值被确定为 200。与图像 1 不同,白色和非常浅的颜色被指定为 255,而图像 4 中所有剩余的值被设置为 0。必须为每幅图像和每种情况专门设置阈值。
图像处理中使用的另一种方法是模糊。这可以通过一个以上的功能来实现。
output2 = cv2.blur(gray_image, (10, 10))
plt.imshow(output2)
plt.show()

图 4。具有模糊功能的模糊图像
output2 = cv2.GaussianBlur(gray_image, (9, 9), 5)
plt.imshow(output2)
plt.show()

图 5。高斯模糊函数模糊图像
如图 4 和图 5 所示,黑白图像使用指定的模糊滤镜和模糊度进行模糊处理。这个过程通常用于去除图像中的噪声。此外,在某些情况下,训练会因图像中的清晰线条而受到严重影响。在出于这个原因使用它的情况下,它是可用的。
在某些情况下,数据可能需要旋转以进行扩充,或者用作数据的图像可能会有偏差。在这种情况下,可以使用以下功能。
(h, w) = img.shape[:2]
center = (w / 2, h / 2)
M = cv2.getRotationMatrix2D(center, 13, scale =1.1)
rotated = cv2.warpAffine(gray_image, M, (w, h))
plt.imshow(rotated)
plt.show()

图 6。使用 getRotationMatrix2D 函数旋转图像
首先,确定图像的中心,并以该中心进行旋转。getRotationMatrix2D 函数的第一个参数是计算的中心值。第二个参数是角度值。最后,第三个参数是旋转后要应用的缩放值。如果该值设置为 1,它将只根据给定的角度旋转相同的图像,而不进行任何缩放。
## 样本 1
上面提到的方法经常在项目中一起使用。为了更好地理解这些结构和过程,让我们制作一个示例项目。
假设我们想为车辆培训自动驾驶驾驶员[4]。当针对这个问题检查图 1 中的图像时,我们的自动驾驶仪应该能够理解路径和车道。我们可以用 OpenCV 来解决这个问题。因为颜色在这个问题中无关紧要,所以图像被转换成黑白的。矩阵元素通过确定的阈值设置值 0 和 255。如上文在阈值函数的解释中所提到的,阈值的选择对于该函数是至关重要的。对于这个问题,阈值设置为 200。我们可以澄清其他细节,因为只关注路边和车道就足够了。为了去除噪声,采用高斯模糊函数进行模糊处理。从图 1 到图 5 可以详细检查到这里为止的部分。
在这些过程之后,应用 Canny 边缘检测。
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(thresh, output2) = cv2.threshold(gray_image, 200, 255, cv2.THRESH_BINARY)
output2 = cv2.GaussianBlur(output2, (5, 5), 3)
output2 = cv2.Canny(output2, 180, 255)
plt.imshow(output2)
plt.show()

图 7。Canny 函数结果图像
Canny 函数采用的第一个参数是操作将应用到的图像。第二个参数是低阈值,第三个参数是高阈值。逐像素扫描图像以进行边缘检测。一旦有低于低阈值的值,就检测到边沿的第一侧。当发现比较高阈值更高的值时,确定另一边并创建边。为此,为每个图像和每个问题确定阈值参数值。为了更好地观察高斯-布朗效应,我们这次不模糊地做同样的动作。
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(thresh, output2) = cv2.threshold(gray_image, 200, 255, cv2.THRESH_BINARY)
output2 = cv2.Canny(output2, 180, 255)
plt.imshow(output2)
plt.show()

图 8。无模糊图像
当不实现 GaussianBlur 函数时,噪声在图 8 中清晰可见。这些噪音对我们的项目来说可能不是问题,但在不同的项目和情况下,会对训练成功产生很大的影响。在这个阶段之后,基于所确定的边缘对真实(标准)图像执行处理。HoughLinesP 和 line 函数用于此。
lines = cv2.HoughLinesP(output2, 1, np.pi/180,30)
for line in lines:
x1,y1,x2,y2 = line[0]
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),4)
plt.imshow(img)

图 9。应用 HoughLinesP 函数的图像
如图 9 中的图片所示,道路边界和车道很好地实现了。然而,当仔细检查图 9 时,会注意到一些问题。虽然确定车道和道路边界没有问题,但云也被视为道路边界。应该使用掩蔽方法来防止这些问题[5]。
def mask_of_image(image):
height = image.shape[0]
polygons = np.array([[(0,height),(2200,height),(250,100)]])
mask = np.zeros_like(image)
cv2.fillPoly(mask,polygons,255)
masked_image = cv2.bitwise_and(image,mask)
return masked_image
我们可以用 mask_of_image 函数进行蒙版处理。首先,将待遮罩的区域确定为多边形。参数值完全是特定于数据的值。

图 10。确定的掩蔽区域
遮罩(图 10)将应用于真实图片。没有对与真实图像中的黑色区域相对应的区域进行处理。然而,所有上述过程都应用于对应于白色区域的区域。

图 11。掩蔽应用的图像
如图 11 所示,作为屏蔽过程的结果,我们已经解决了我们在云中看到的问题。
## 样本 2
我们用 HougLinesP 解决了车道识别问题。让我们假设这个问题适用于圆形[6]。

[图 12。](https://www.mathworks.com/help/examples/images/win64/GetAxesContainingImageExample_01.png)硬币图像【8】
让我们创建一个识别图 12 中硬币的图像处理。在这种情况下,车道识别项目中使用的方法也将在这里使用。
img = cv2.imread("/Users/.../coin.png")
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
(thresh, output2) = cv2.threshold(gray_image, 120, 255, cv2.THRESH_BINARY)
output2 = cv2.GaussianBlur(output2, (5, 5), 1)
output2 = cv2.Canny(output2, 180, 255)
plt.imshow(output2, cmap = plt.get_cmap("gray"))circles = cv2.HoughCircles(output2,cv2.HOUGH_GRADIENT,1,10, param1=180,param2=27,minRadius=20,maxRadius=60)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(img,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(img,(i[0],i[1]),2,(0,0,255),3)
plt.imshow(img)

图 13。最终硬币图像
作为图像处理的结果,可以在图 13 中得到它。
图像转换为黑白。然后应用阈值函数。使用 GaussianBlur 和 Canny 边缘检测函数。
最后用 HoughCircles 函数画圆。
图像处理也适用于图像格式的文本。

图 14。图像格式的文本
假设我们想要用图 14 中的文本来训练我们的系统。作为训练的结果,我们希望我们的模型能够识别所有的单词或一些特定的单词。我们可能需要将单词的位置信息教给系统。这类问题也用 OpenCV。首先,图像(在图 14 中)被转换成文本。一个叫做 Tesseract 的光学字符识别引擎被用于此[7]。
data = pytesseract.image_to_data(img, output_type=Output.DICT, config = "--psm 6")
n_boxes = len(data['text'])
for i in range(n_boxes):
(x, y, w, h) = (data['left'][i], data['top'][i], data['width'][i], data['height'][i])
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)plt.imshow(img)
plt.show()

图 15。单词位置信息的处理
通过将借助 Tesseract 获得的信息与 OpenCV 相结合,获得了如图 15 所示的图像。每个单词和每个单词块都被圈起来。也有可能通过操作来自 Tesseract 的信息来只操作帧中的某些字。此外,可以应用图像处理来清除文本中的噪声。但是,当其他示例中使用的 GaussianBlur 函数应用于文本时,它将对文本的质量和易读性产生不利影响。因此,将使用 medianBlur 函数代替 GaussianBlur 函数。
img = cv2.imread(img_path)
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
output2 = cv2.medianBlur(gray_image, ksize=5)
plt.imshow(output2)
plt.show()

图 16。medianBlur 函数应用图像
当在图 14 中检查图像时,一些单词下面的虚线清晰可见。在这种情况下,光学字符识别引擎可能会误读一些单词。作为图 16 中 medianBlur 过程的结果,可以看到这些虚线消失了。
*注意:必须检查黑白图像矩阵的尺寸。大部分时候都有 RGB 维度,哪怕是黑白的。这可能会导致 OpenCV 中的某些函数出现尺寸错误。*
侵蚀和扩张功能也可用于去除图像格式中文本的噪声。
kernel = np.ones((3,3),np.uint8)
output2 = cv2.dilate(gray_image,kernel,iterations = 3)
plt.imshow(output2)
plt.show()

图 17。由膨胀函数产生的图像
当查看图 14 中的文本时,会看到有一些点状噪声。可以看出,使用图 17 中的扩展函数可以显著消除这些噪声。通过更改创建的筛选器和迭代参数值,可以更改项目的稀疏率。为了保持文本的可读性,必须正确确定这些值。侵蚀功能,与扩张功能相反,提供文本的增厚。
kernel = np.ones((3,3),np.uint8)
output2 = cv2.erode(gray_image,kernel,iterations = 3)
plt.imshow(output2)
plt.show()

图 18。腐蚀函数产生的图像
字体粗细随着侵蚀功能而增加,如图 18 所示。这是一种用来提高文章质量的方法。这里还要注意的一点是,我们的文章是黑色的,背景是白色的。如果背景是黑色的,文本是白色的,这些功能的过程就会发生位移。
OpenCV 用于提高某些图像的质量。例如,对比度差的图像的直方图值分布在狭窄的区域上。
为了提高该图像的对比度,有必要将直方图值扩展到一个较宽的区域。均衡器函数用于这些操作。让我们对图 19 中的图像进行直方图均衡化。

图 19。直方图值未修改的图像(原始图像)

图 20。原始图像的直方图分布
原始图像的直方图(图 19)可以在图 20 中看到。
图像中物体的可见度较低。
equ = cv2.equalizeHist(gray_image)
plt.imshow(equ)

图 21。直方图均衡图像

图 22。直方图均衡化图像的直方图分布
图 21 显示了使用均衡器函数均衡直方图的图像。图像的质量和清晰度提高了。此外,直方图均衡化后的图像直方图如图 22 所示。可以看出,在直方图均衡化之后,在图 20 中的一个区域中收集的值分布在更大的区域中。可以对每个图像检查这些直方图值。必要时可以通过直方图均衡化来提高图像质量。
github:【https://github.com/ademakdogan
领英:[https://www.linkedin.com/in/adem-akdo%C4%9Fan-948334177/](https://www.linkedin.com/in/adem-akdo%C4%9Fan-948334177/)
# **参考文献**
[1]P .鲍尔,Z .郭彤,“在线螺纹加工的图像处理技术研究”,2012 年未来电力与能源系统国际会议,2012 年 4 月。
[2]H.Singh,**实用机器学习与图像处理,**第 63–88 页,2019 年 1 月。
[3]R.H.Moss,S.E.Watkins,T.Jones,D.Apel,“高分辨率目标运动监视器中的图像阈值处理”,《国际光学工程学会 SPIE 会议录》,2009 年 3 月。
[4]Y.Xu,L.Zhang,“基于 OPENCV 的车道线检测技术研究”,会议:2015 年第三届机械工程与智能系统国际会议,2015 年 1 月。
[5]F.J.M.Lizan,F.Llorens,M.Pujol,R.R.Aldeguer,C.Villagrá,“使用 OpenCV 和英特尔图像处理库。处理图像数据工具”,工业和人工智能信息,2002 年 7 月。
[6]张庆瑞,彭鹏,金耀明,“基于 OpenCV 的樱桃采摘机器人视觉识别系统”,MATEC 网络会议,2016 年 1 月。
[7]R.Smith,“Tesseract OCR 引擎概述”,会议:文档分析和识别,2007 年。ICDAR 2007。第九届国际会议,第 2 卷,2007 年 10 月。
[8][https://www . mathworks . com/help/examples/images/win 64/GetAxesContainingImageExample _ 01 . png](https://www.mathworks.com/help/examples/images/win64/GetAxesContainingImageExample_01.png)
[https://neptune.ai/blog/image-processing-python](https://neptune.ai/blog/image-processing-python)
# 自动化音乐转录实用介绍
> 原文:<https://towardsdatascience.com/practical-introduction-to-automation-music-transcription-3ad8ad40eab6?source=collection_archive---------15----------------------->
## [实践教程](https://towardsdatascience.com/tagged/hands-on-tutorials)

## 1.介绍
FindYourRhythm(【https://www.findyourrhythm.us/home】)是我们团队在 MIDS 项目顶点设计期间开发的 MVP。它采用用户提供的音频,使用开源 Python 库进行处理,并通过我们的双向长短期记忆(BLSTM)神经网络为多达 13 种鼓组和音乐打击乐器常见的乐器生成开始预测。预测被转换成 MuseScore 格式(。mscx)乐谱文件并作为可下载文件提供给用户。如果您对我们的产品感兴趣,请访问我们的网站并试用该产品。

图 1 数据管道。(图片由作者提供)
在这里,我希望与任何对音频分析、自动音乐转录或 LSTM 模型感兴趣的人分享我从这个项目中获得的以下实践经验和知识:
1. 音频转换(预处理),
2. 递归神经网络(LSTM 和比尔斯特姆模型),
3. 和事件分段(峰值拾取方法)
## 2.音频转换
我没有任何音频处理或语音识别的经验。所以对我来说,第一个挑战是理解我们听到的声音是如何存储在内存中的,以及机器如何识别不同的声音(鼓乐器)?
你和我一样有问题吗?你很想知道答案吗?
我将试着一步一步地解释我是如何得到这些问题的答案的?所以我们走吧!
当有人打鼓时,你可以听到声音,但你看不到任何东西。因此,模拟波被用来以声音频率和振幅的信息形象化这种声音。下面是鼓混合音频与声音模拟波。它表明,在视频中,声波随着声音而变化,而且,当几个鼓乐器一起演奏时,声波变得更加复杂。
如果只有一种鼓乐器在演奏,声波会显示出统一的频率和振幅,如下图中的粉红色和黄色实线所示。例如,粉红色实线代表频率为 2 Hz 的声音,意思是每秒两个波。然而,如果这两个声音(粉红色和黄色的线)重叠,声波就结合了。对于组合声波(绿色实线),很难提取声音及其频率的信息。这就是傅立叶变换填补这一空白的地方。利用组合声波的傅立叶变换,很容易获得如图所示的具有尖峰的两个声音的频率。

图二。声波和声波的傅立叶变换(图片来源:[https://www.youtube.com/watch?v=spUNpyF58BY&t = 626s](https://www.youtube.com/watch?v=spUNpyF58BY&t=626s)
限于时间和篇幅,我就不深究傅里叶变换背后的原理,以及如何通过傅里叶变换得到声音频率了。如果你对这个话题感兴趣,并希望更好地理解它,下面的视频肯定会帮助你。
回到图 2。,你会意识到一个非常重要的特征,因为音频在傅立叶变换后消失在声波中。 ***这个特征就是时间!*** 所以应用声谱图来组合图 2 中的两种图形,如下图。这是以前的鼓混合音频的短期傅立叶变换(STFT)频谱图,包括 y 轴上的频率、x 轴上的时间和用颜色编码的振幅。

图三。鼓混合音频的短时傅立叶变换谱图(图片由作者提供)。
到目前为止,我们已经将音频信息可视化。以下步骤用于将此信息转换为模型输入:
**第一步:**使用 [Librosa](https://librosa.org/doc/latest/index.html) 将音频转换为 STFT 声谱图(打开 python 库进行音频和音乐分析)。选择作为馈入 RNN 模型的输入的固定时间窗口的片段长度。这将在模拟会议中进一步讨论。
**第二步:**将声谱图转移到数组:数组中的每一行代表频率级别,列是时间帧。数组中的值代表振幅。为了避免两首歌曲连接成一个片段,值为 0 的静音会根据音频的大小填充在歌曲的结尾。
**步骤 3:** 每首歌曲将具有相同数量的频率级别,但总时间不同。因此,该数组被转置,以便每首歌曲都有相同的列数。
**步骤 4:** 使用这种数组形状,可以很容易地将开放数据库中可用歌曲的频谱图连接在一起,并输入到模型中。

图 4 从光谱图到模型输入(图片由作者提供)
## 3.1 基本递归神经网络(RNN)
Rnn 代表 DNNs 的扩展,其特征在于与每层的额外连接。递归连接为单层提供了前一时间步的输出作为附加输入,因此在对序列相关行为(如语音识别、股票市场事件和自动音乐转录)进行建模时,它表现得更好。
图 5 示出了在鼓自动转录(DAT)上应用 RNN 的步骤:
**步骤 a)** 将图 4 中说明的连接的 STFT 频谱图(X)输入到 RNN 模型中
**步骤 b)** 根据定义的段长度(本项目使用 5 秒)将输入分割成小时间窗口(段)。这意味着声谱图帧(X *t* )被分割成 5 秒的片段,并依次作为输入特征,与前一时间步的输出(h *t-1* )一起馈入隐含层。
**步骤 c)** 图 5 c 和 d 显示了带有 tanh 激活函数的隐藏层的输出。
**步骤 d)** 图 5 e 是来自未折叠 RNN 的乙状结肠神经元的输出。参见图 6 中折叠和展开的 RNN 之间的差异。基本上,展开的 RNN 将提供整个时间的所有输出,而折叠的 RNN 将只输出一个片段中的最后一个时间步长。

图 5 RNN 在自动鼓转录中的应用(图片来源:DOI 10.1109/taslp . 2830113)

图 6 RNN 折叠和展开时的区别(图片来源:[https://adventuresinmachinehlearning . com/keras-lstm-tutorial/](https://adventuresinmachinelearning.com/keras-lstm-tutorial/))
*然而*香草 RNN 在实践中有渐变消失的问题。对 RNN 来说,我们希望有长久的记忆,这样网络就能在理解音乐或语言如何工作方面取得真正的进展。然而,随着时间的推移,我们实际上是在我们的网络中添加越来越深的层。如图 7 所示,当输出(f)接近 0 和 1 时,s 形梯度(f’)变得非常小。图 7 中的等式是随时间反向传播的粗略近似。很明显,当在反向传播期间将许多 sigmoid 梯度(图 7 中的等式)与非常小的值相乘时,会出现消失梯度。处理梯度消失问题最流行的方法是使用长短期记忆(LSTM)网络。

图 7 Sigmoid 激活函数及其梯度(图片来源:[https://adventuresinmachine learning . com/recurrent-neural-networks-lstm-tutorial-tensor flow/](https://adventuresinmachinelearning.com/recurrent-neural-networks-lstm-tutorial-tensorflow/))
## 3.2 LSTM 和比尔斯特姆网络
为了减少消失梯度问题,并且同样允许更深的网络和长记忆更好地理解音乐/语言,需要一种方法来减少在通过时间反向传播期间具有小值的梯度的乘法。
LSTM 模型是专门为解决消失梯度问题而设计的,它通过创建一个内存状态来解决消失梯度问题,该内存状态通过遗忘门简单地对*进行过滤*,并通过*将*添加到已处理的输入中。遗忘门决定哪些先前状态应该被记住(遗忘门输出= 1),哪些应该被遗忘(遗忘门输出=0)。这允许 LSTM 细胞只学习有用的上下文。此外,遗忘门滤波状态被添加到输入,而不是乘以它,这大大降低了小梯度的乘法效应。LSTM 模型非常灵活,用门控函数来控制什么是输入,什么是在内存状态中记忆的,以及什么是最终从 LSTM 单元输出的。由于这些原因,LSTM 模型目前被广泛用于依赖于时间的行为预测。这里我只分享我从 LSTM 模型中学到的一些要点,如果你对 LSTM 模型以及它如何帮助解决消失梯度问题感兴趣,博客[“Python 和 TensorFlow 中的递归神经网络和 LSTM 教程”](https://adventuresinmachinelearning.com/recurrent-neural-networks-lstm-tutorial-tensorflow/)非常有用,将是对 LSTM 网络的一个很好的介绍。

图 8 LSTM 细胞图(图片来源:[https://adventuresinmachine learning . com/recurrent-neural-networks-lstm-tutorial-tensor flow/](https://adventuresinmachinelearning.com/recurrent-neural-networks-lstm-tutorial-tensorflow/))
最后,我们采用双向 LSTM (BiLSTM)模型,该模型通过保留过去和未来的信息来进一步提高模型性能。这是通过以两种方式运行输入来实现的,一种是从过去到未来,另一种是从未来到过去,如图 9 所示。

图 9 BiLSTM 模型(图片来源:colah 的博客)
## 3.3 使用 Keras 创建 LSTM 网络
> ***LSTM 模型的尺寸输入***
该项目使用了三个数据库:
1. **IDMT-SMT-鼓:**超过 2 小时的音频,包括 104 首歌曲,只有 3 种鼓的音高,分别为小军鼓、踢鼓和踩镲。开始和乐器都包含在音乐 XML 转录中。
2. **MDB 鼓:** > 20 分钟音频,23 首独特歌曲,15 种鼓点。音乐标签与开始和乐器一起呈现。
3. **电子 GMD:** 超过 400 小时的鼓乐歌曲,20 种鼓点和标签,包括开始,持续时间,速度,MIDI 音高,时间信号,风格和套件。

图 10 数据来源(图片由作者提供)
来自这三个数据库的音频被转换和连接,如图 4 所示。LSTM 模型训练成功的重要步骤是理解图 11 所示的模型输入形状。
1. **浴槽尺寸:**使用梯度下降来训练神经网络,其中基于训练数据集的子集来计算用于更新权重的误差估计。用于估计误差梯度的训练数据集中的样本数称为批量。它是影响学习算法动态的一个重要的超参数。
2. **片段长度:**内存大小对 LSTM 模型的性能至关重要,由片段长度决定,片段长度是输入我们展开的 LSTM 网络的音频的子序列(时间窗口)。
3. **频段数:**输入我们 LSTM 网络的每一帧音频将是 1025(代表声谱图的频率级数)长度向量。
**综上**,我们这里的模型输入是多维的,大小为(批量大小,段长度,频率仓数量)。

图 11 模型输入形状的图示(作者提供的图片)
> ***区别 Keras。适合和。Keras 中的 fit _ generator***
Keras 深度学习库包括两个独立的函数,可用于训练我们的模型(。适合和。fit_generator)。下面列出了这两种功能之间的区别:
***注意:*** *在未来的版本中,Model.fit_generator 将被移除。这可以通过使用同样支持生成器的 Model.fit 来实现。*
1. **配合**
Keras 拟合函数在以下情况下效果更好:
* 原始数据本身将适合内存——我们不需要将旧的数据批次移出 RAM,并将新的数据批次移入 RAM
* 我们不会使用数据扩充(填充、裁剪和水平翻转)来操作训练数据
与 fit_generator 函数相比,Keras fit 函数要简单得多,尽管它需要很大的内存空间来保存模型训练期间的全部原始数据。当使用拟合函数时,我们只需要将我们的级联音频频谱图(图 4)转换为 LSTM 模型形状(批量大小、分段长度、频率仓数量),如前所述。这里,我们创建一个函数来为训练、验证和测试数据执行这种数据转换。
Python 代码 1:将音频分割成 5 秒窗口的分段函数
2.fit_generator
Keras fit_generator 函数在以下情况下工作得更好
* 真实世界的数据集通常太大而无法放入内存。fit_generator 使用用户创建的生成器函数将成批数据移入和移出 RAM。
* 需要数据扩充来避免过度拟合,并提高我们模型的泛化能力
Keras fit_generator 函数能够从用户创建的预定义 Python 生成器对象中自动提取训练和验证数据,并将其输入到模型中。下面是本项目中使用的生成器对象的示例:
Python 代码 2:生成函数来提取训练批次以输入到模型中
> ***Keras BiLSTM 型号***
Keras 是一个强大的 API,非常容易应用于深度学习。下面是 Keras 中的 BiLSTM 网络,使用 Keras.model.fit 函数进行模型训练。每一步都有注释。*现在模型已经准备好了!*
Python 代码 Keras 中的 BiLSTM 网络
在上面 Keras.model.fit 函数的 callbacks 参数中,有一个自己创建的名为 plot _ losses 的函数,用于绘制每个历元之后的训练和验证损失。通过绘图评估每个时期的模型性能比检查每个时期的度量更容易。下面是 plot _ losses 函数的代码。
Python 代码 4:在模型训练期间创建动态损失图的函数
如果使用大型数据集和有限的内存大小来训练模型,建议使用 Keras.model.fit_generator 函数。下面是用 fit_generator 代替 fit 函数的方法。Keras fit_generator 函数与 python 迭代函数(上一节中介绍的 python 代码 2 中的 generate 函数)的第一次增强将每次提取一批数据,执行小批量梯度下降法以更新权重,记录每个批量训练和验证数据集的度量(如准确度、MSE、混淆矩阵),并执行回调。
函数中的 steps_per_epoch 参数用于定义每个时期的迭代次数,以终止上一节中介绍的生成函数中的无限循环,并在达到步数时开始新的时期(与 validation_steps 相同)。
Python 代码 5:使用 Keras.model. fit_generator 函数的 BiLSTM 模型训练
在模型讨论的最后,我希望简单说一下神经网络(NN)的注意事项。对于 NN,通过大量的训练,它可以容易地记忆训练数据集,具有高方差和低偏差,如图 12 所示,但是记忆不是学习。所以在这项研究中,我们应用了以下方法来避免记忆:
* 通过减少层和隐藏节点的数量来简化模型
* 添加漏失层并评估最佳漏失率,以获得高精度的概化模型
* 当验证损失增加时,应用提前停止来停止培训
* 收集更多数据
这些是广泛用于减少 NN 模型方差并确保训练模型平衡的通用方法。

图 12 模型欠拟合和过拟合(作者图片,灵感来源:[https://subscription . packtpub . com/book/data/9781838556334/7/ch 07 lvl 1 sec 82/欠拟合和过拟合](https://subscription.packtpub.com/book/data/9781838556334/7/ch07lvl1sec82/underfitting-and-overfitting)
## 4.峰值拾取方法和模型评估
图 13a 示出了三种鼓乐器的来自 BiLSTM 模型的 sigmoid 神经元的输出。应该应用峰值拾取方法来检测每个仪器的开始。传统的方法是对乙状结肠神经元的输出应用阈值函数(如果输出>阈值,则为 1,否则为 0)。然而,这种方法的问题在于,如图 14b 所示,基于各种歌曲类型、架子鼓类型以及鼓乐器,开始峰值显示不同的值。如果使用这种常规方法,它将在高概率峰值周围提供许多值为 1 的开始,并以低概率错过真正的峰值,从而导致高 FPs 和 FNs。因此,使用图 15 中的峰值拾取方法。在应用这种峰值拾取方法之后,我们可以成功地将乙状结肠神经元的输出转移到图 13b 中的发作。

图 13 (a)来自 BiLSTM 模型的乙状结肠神经元的输出(b)使用峰值拾取方法的发作检测(作者提供的图像)

图 14 (a)阈值函数和(b)Sigmoid 概率输出的示意图,峰值代表仪器开始(由来源[https://www . vojtech . net/img/machine-learning/Sigmoid-Function . png](https://www.vojtech.net/img/machine-learning/sigmoid-function.png)成像)

图 15 峰值拾取方法的等式(图片由作者提供)
图 16 示出了文献中的模型和我们的 BiLSTM 模型对于各种鼓乐器的 f1 分数。对于这个项目,我们的模型不仅为大多数 ADT 文献中发现的三种常见乐器(底鼓、小军鼓和踩镲)提供了准确的开始检测,而且还专注于对涵盖鼓转录中各种音符的 10 多种鼓乐器进行建模。

图 16 模型评估(数据来源:R.S .,J.H .和 C.S .,“使用双向递归神经网络的自动鼓转录”dblp,2016。图片作者)
## 5.结论
[这里](https://docs.google.com/presentation/d/1NehI9P8tiGj2s54kRSn7hcAxPuIaepOsx3iZemTDkkc/edit?usp=sharing)是我们最终的 FindYourRhythm 应用程序的演示和介绍,为所有鼓手提供免费的鼓点转录,无论音乐品味、熟练程度或预算如何。所有资源(如 GitHub 库和顶点页)都可以在我们的[网站](https://www.findyourrhythm.us/home)上找到。最后,我要感谢[我的 FindYourRhythm 团队和指导老师](https://www.findyourrhythm.us/team)一起致力于这个奇妙的项目。
感谢您的关注。如果你有任何问题,你可以打电话给我:[https://www.linkedin.com/in/yue-hu-69883469/](https://www.linkedin.com/in/yue-hu-69883469/)
# 在自动气象站上为数据科学建立 Kubernetes 的实际问题
> 原文:<https://towardsdatascience.com/practical-issues-setting-up-kubernetes-for-data-science-on-aws-6e009f045f65?source=collection_archive---------51----------------------->
## Kubernetes 提供了大量有用的原语来建立自己的基础设施。然而,供应 Kubernetes 的标准方式并不适合数据科学工作流。这篇文章描述了这些问题,以及我们是如何看待它们的。

艾米·埃尔廷在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上拍摄的照片
声明:我是[土星云](https://www.saturncloud.io/s/)的首席技术官——我们构建了一个企业数据科学平台,专注于利用 Dask 和 RAPIDS 获得巨大的性能收益。
# 多个 AZ(可用性区域)与 EBS(弹性块存储)和 Jupyter 交互不佳
不管你喜不喜欢,Jupyter 是当今最常见的数据科学工具 IDE。如果您为数据科学家提供 Kubernetes 集群,他们肯定会希望运行 Jupyter 笔记本电脑。如果他们运行的是 Jupyter 笔记本,他们将需要持久存储——在 IDE 中工作,无论何时关机,文件系统都会被删除,这是一种非常糟糕的体验!。这与传统的 Kubernetes 工作负载非常不同,后者通常是无状态的。
这也意味着,如果您支持多个 AZ,您需要确保 Jupyter 实例总是在同一个 AZ 中启动,因为您的持久性存储(EBS)不能自动迁移到其他区域。一种选择是使用 EFS,而不是 EBS。我们在土星没有这样做,因为大多数数据科学家也想在他们的驱动器上存储数据,一旦你开始进入大规模并行集群计算,EFS 是不可靠的。在 Saturn,我们将所有 Jupyter 实例路由到同一个 AZ,并设置特定于该 AZ 的 ASG(自动缩放组)。您牺牲了高可用性,但无论如何,您从未真正拥有过高可用性,除非您将快照备份到多个 AZ,并准备在主服务器宕机时将 EBS 快照恢复到另一个 AZ。
# 标准 VPC 遇到 EIP(弹性 IP)限制
标准的 Kubernetes 设置将工作人员保持在私有子网中。大多数人最终会使用 CIDR 块创建私有子网,分配大约 256 个 IP 地址。这似乎是合理的,因为您可能不需要超过 256 台机器,对吗?不对!通过 EKS,实例类型决定了每个实例分配的默认(和最大)数量的 [IP 地址。默认情况下,一些较大的实例(例如 512 GB ram 的 r5.16xlarge)消耗 50 个 IP 地址。这意味着一个由 5 名数据科学家组成的团队,每个人使用 1 个 r5.16xlarge,可以轻松耗尽您的私有子网中的 IP 地址数量。我们建议分配非常大的子网(我们的默认配置在 CIDR 块中有 8000 个可用子网)](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI)
# Calico 的标准安全网络配置随着节点的扩展而变得不稳定。
许多数据科学工具没有提供太多内置安全性。这对于 OSS 项目来说是完全合理的,但是对于企业部署来说却是一个大问题。例如,默认情况下,Dask 集群不保护调度程序,这意味着任何可以访问集群的人都可以向任何 Dask 集群提交作业(Dask 有其他方法来减轻这种情况,但是对我们来说,在网络级别处理这种情况是最灵活的)。即使您正在保护对 Kubernetes 集群的访问,通过使用 Kubernetes 网络策略来控制锁定资源来保护数据科学工具也是一个好主意。
EKS 目前的安全网络标准是 Calico。标准 Calico 设置将根据节点数量水平自动扩展元数据存储,这对于大多数数据科学工作负载来说过于激进,因为我们通常每台机器运行 1 个用户单元(稍后将详细介绍)。这种水平自动缩放行为导致 Calico 不稳定,从而导致节点无法通信。我们通过手动控制元数据存储中副本的数量来解决这一问题,这对于我们的数据科学工作负载来说非常稳定。
# ASG(自动缩放组)和集群自动缩放器
数据科学工作负载与普通的 Kubernetes 工作负载非常不同,因为它们几乎总是受内存限制。EC2 定价主要由内存决定,数据科学工作负载的多租户不会带来太多价值。数据科学工作负载通常是长期运行的(许多数据科学家会提供一个 jupyter 实例,并让它运行一整个月)。您最好为每个 data science pod 分配一个完整的节点。如果您不这样做,很可能最终会在一个每月花费 3000 美元的节点上安排一个每月只花费 30 美元的 pod。
在 Saturn,我们创建了许多 ASG(4GB/16GB/64GB/128 GB/256 GB/512 GB ),以尽可能少地浪费内存。
数据科学工作负载也非常高。有一天,一名数据科学家可能需要在一个 4GB 的实例上编辑代码,每月花费 30 美元。第二天,他们可能想要一个 512 GB 的 jupyter 实例(3000 美元/月),该实例连接到一个 10 节点 Dask 集群(总共 5TB /ram)。能够自动缩放 Kubernetes 非常重要。
# Kubernetes 星团-自动定标器
Kubernetes cluster-autoscaler 是一个复杂的天才,它可以计算出最佳的旋转节点以容纳新的 pod,以及应该调整哪些 pod 以释放可以旋转的节点。然而,如果您已经接受了每个实例一个 pod 的配置,这种复杂性会增加很多复杂性,几乎总是会导致问题。
## 问题— ASG 选择
Kubernetes 集群自动缩放器配置有扩展器,扩展器决定如何分配新的 EC2 实例。成本意识用户的标准是`least-waste`,然而`least-waste`扩展器以百分比计算浪费。这意味着,如果您创建了一个 pod,但忘记指定任何 CPU 或 RAM 请求(您请求 0),集群自动缩放器将确定每种节点类型都会导致 100%的浪费。当一个扩展器判断它有一个平局时,一切都被路由到`random`扩展器。恭喜你!您每月 30 美元的 pod 现在每月花费 3000 美元。
## 问题—浪费的容量
Kubernetes pods 是基于在退回到集群自动缩放之前当前有哪些节点的容量来调度的。一旦 pod 腾出一个节点,10 分钟后该节点就会被拆除。对于活动集群,我经常看到小型 pods (4GB)被意外地安排在大型节点(512 GB)上。数据科学家认为他们正在消耗 4GB 的内存,所以他们很乐意让这个 pod 永远运行下去。恭喜你!您每月 30 美元的 pod 现在每月花费 3000 美元。
## 解决方案——具体到助理秘书长。
数据科学工作负载几乎总是受内存限制,应该独占整个实例。数据科学工作负载也非常高,因此 Kubernetes 中的自动伸缩非常重要。在 Saturn,我们通过明确标记每个 pod 的节点选择器来解决这个问题,这样它只能被安排在正确的 ASG 上。
# 实例配置
本节假设您正在使用 terraform 配置 EKS。
用户应该能够建立 docker 图像吗?如果你想运行 [binderhub](https://binderhub.readthedocs.io/en/latest/) ,这可能是必要的。在 Saturn,我们允许某些 pod 构建 docker 映像,因为我们希望从标准数据科学配置文件中启用我们的 docker 映像构建服务。如果是这样的话,您将需要使用以下内容来配置您的助理秘书长
bootstrap_extra_args = "--enable-docker-bridge true"
# 但不是针对 GPU 机器!
docker 桥不能在 GPU 节点上工作,所以您应该设置
bootstrap_extra_args = "--enable-docker-bridge false"
`terraform-aws-eks`默认 ASG 使用 CPU AMI。如果您正在配置 GPU 节点,您必须找到您所在地区的 GPU ami ID,并将其传递给 terraform。下面是我们用来做这件事的 Python 代码
def get_gpu_ami(region):
eks_owner = "602401143452"
client = boto3.client("ec2", region_name=region_name)
images = client.describe_images(Owners=eks_owner)["Images"]
ami_prefix = f"amazon-eks-gpu-node-{settings.kubernetes_version}"
images = [x for x in images if x["Name"].startswith(ami_prefix)]
images = sorted(images, key=lambda x: x["CreationDate"])
image = images[-1]
return image["ImageId"]
如果您配置了错误的 AMI,您的节点将会正常运行,但是您昂贵的 GPU 将不会在 Kubernetes pods 中可用。
# 不要忘记集群-自动缩放。
你需要标记 ASG 来表明有多少 GPU 可用,否则 autoscaler 不会知道你需要 4 个 V100s 的深度学习 pod 可以安排在这个盒子上。
{
key = "k8s.io/cluster-autoscaler/node-template/resources/nvidia.com/gpu"
value = "4"
propagate_at_launch = true
}
# 现在怎么办?
如果您已经读到这里,那么您一定在考虑为您的数据科学团队建立自己的 Kubernetes 集群。我只有一个问题要问你。
这真的是对你时间的最好利用吗?
您的公司可能会在 Kubernetes 部署中偷工减料,设置一堆 ASG,部署 jupyterhub,然后找出如何部署 dask 集群,然后确保将您需要的依赖项构建到 docker 映像中,以便 jupyter 和 dask 都能很好地工作,然后确保您正确配置 EBS 卷,以便数据科学家不会丢失他们的工作,并确保您配置 Calico、nginx-ingress 和负载平衡器,以便您的应用程序流量是安全的。您是否计划部署仪表板?还是模特?那里有什么敏感信息吗?您是否需要在它们周围提供访问控制和安全性?不要忘记设置 jupyter-server-proxy,这样在 Jupyter/Lab 工作的数据科学家就需要使用 dask dashboard,并使用 bokeh/plotly/voila 进行实验,对吗?你记得为每个 GPU 绑定一个 dask worker 吗?您正在配置 RMM 吗?您是否配置了适当的 GPU 到主机内存溢出?
这真的是对你时间的最佳利用吗?
[我们的定价](https://www.saturncloud.io/s/pricing/)是按需付费,通过 AWS marketplace 计费。我建议租用我们的软件,而不是自己开发。
# 实用机器学习基础
> 原文:<https://towardsdatascience.com/practical-machine-learning-basics-5d81a22f188?source=collection_archive---------21----------------------->
## 我第一次探索机器学习是在 Kaggle 上用泰坦尼克号比赛

路易斯&萝拉,泰坦尼克号灾难的幸存者(照片来自[国会图书馆印刷品和照片](https://www.loc.gov/item/2014691309/),没有已知的出版限制)
这篇文章描述了我在 [Kaggle](https://www.kaggle.com/c/titanic) 上参加泰坦尼克号机器学习竞赛的尝试。我一直在尝试研究机器学习,但从未达到能够解决现实世界问题的程度。但是在我看了两本新发行的关于实用 AI 的书之后,我有足够的信心参加泰坦尼克号比赛。
文章的第一部分描述了如何准备数据。第二部分展示了我如何使用支持向量机(SVM)。我用 SVM 创造了一个模型来预测泰坦尼克号乘客的生存。
该模型的得分为 0.779907,这使我进入了比赛的前 28%。我对结果非常满意。你可以在 Github 中找到一个带有解决方案和文档[的 Jupiter 笔记本。](https://github.com/PatrickKalkman/Kaggle/blob/master/Titanic/Kaggle_Titanic.ipynb)
# 介绍
以前,我曾试图通过阅读书籍和参加在线课程来学习人工智能。我从未走远。这些书籍和在线课程大多过于理论化。
在过去的几个月里,我再次尝试用机器学习和人工智能来思考问题。原因是我订了两本关于机器和深度学习的新书。这些书包括许多实用知识和例子。
我看到一条推文提到了这本书*《fastai 和 PyTorch 的程序员深度学习:没有博士学位的 ai 应用》*。这个标题引起了我的注意,因为它明确针对程序员。向我推荐的另一本书是“*用 Scikit-Learn、Keras 和 TensorFlow 进行动手机器学习。”*

[使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习,第二版,作者 Aurélien Géron](https://www.oreilly.com/library/view/hands-on-machine-learning/9781492032632/) 和[深度学习,作者 fastai 和 PyTorch,作者杰瑞米·霍华德和西尔万·古格](https://www.oreilly.com/library/view/deep-learning-for/9781492045519/)
## **用 fastai 为编码人员进行深度学习& PyTorch**
这本书和我看的过去的机器学习书不一样。从一开始就直接展示了深度学习的真实实用代码示例。作为一名程序员,源代码有助于我理解这些概念。
两位作者还提供与该书内容相同的视频讲座。这些视频讲座是免费的。除此之外,还有一个提问和讨论的论坛。
## *使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习*
这也是一本实用的书。它展示了许多实际的例子。这本书使用了 Scikit-Learn、Keras 和 Tensorflow 等机器学习策略。很多人用这本书来准备 [TensorFlow 开发者认证](https://www.tensorflow.org/certificate)。
我浏览了两本书中的各种例子。这既有趣又有启发性。但对我来说,真正的挑战是看我能否从头到尾独立解决一个真正的问题。
两本书都提到 [Kaggle](https://www.kaggle.com/) 是有趣的数据集和机器学习问题的来源。
# 卡格尔
Kaggle 是一个由数据科学家和机器学习实践者组成的在线社区。Kaggle 是谷歌的子公司。
Kaggle 允许您搜索和发布数据集,探索和建立模型。您可以在基于 web 的环境中做到这一点。Kaggle 还提供有真题的机器学习竞赛,并为游戏的获胜者提供奖品。
现在,如果我可以参加一个比赛,并且能够使用我当前的机器学习知识来创建一个提交内容,那该有多酷?
Kaggle 上有一个名为“泰坦尼克号:机器从灾难中学习”的比赛。这是一个帮助用户熟悉 Kaggle 平台如何工作的比赛。
这听起来对我来说是开始和实验机器学习的完美竞争。
# 泰坦尼克号:机器从灾难中学习

图为 1912 年 4 月 11 日在科布港拍摄的泰坦尼克号(图片来自[维基共享资源](https://commons.wikimedia.org/wiki/File:Titanic-Cobh-Harbour-1912.JPG),版权已过期)
1912 年 4 月 15 日,泰坦尼克号在撞上冰山后的第一次航行中沉没。机上 2224 名乘客中有 1500 多名乘客因此死亡。虽然幸存有一些运气成分,但似乎某些群体比其他群体更有可能幸存。
*泰坦尼克号比赛的目标是创造一个可以预测哪些乘客在灾难中幸存的模块。*
竞赛提供了两个数据集。具有乘客数据的训练集,例如姓名、年龄、性别、状态以及乘客是否幸存。
第二组包含相同的数据,但没有生存符号。你必须把第二组测试返回给 Kaggle,并附上你对乘客是否幸存的预测。
在建立机器学习模型之前,我们必须回答的第一个问题是,我们将使用什么类型的机器学习?
# 用什么类型的机器学习?
我还不知道如何回答这个问题。即便如此,我知道我们首先需要确定这是一个回归还是分类的问题。这有助于我们选择合适的机器学习方法。
分类模型试图从一组离散的可能性中进行预测。回归模型试图陈述一个或多个数字量。
我们需要预测一名乘客是否幸存。这在我听来是一个分类问题。所以我们需要一个机器学习类型,可以创建这样的分类模型。
现在,我对这个问题的了解还不足以选择最佳的机器学习策略。但我知道如何建立分类模型——例如,使用逻辑回归或支持向量机。
我决定使用支持向量机(SVM)。
# 为机器学习准备训练数据
在阅读书籍和 Kaggle 论坛时,我了解到在你可以创建机器学习模型之前,你必须准备数据集。为了准备数据,我遵循了以下五个步骤。
1. 加载数据
2. 将文本值转换为数字
3. 使用相关性选择相关参数
4. 删除或填充缺少的值
5. 移除异常值
## 1.加载泰坦尼克号乘客数据
为了加载和操作数据,我使用 pandas 库。Pandas 提供数据结构和操作来控制数字表和时间序列。
我从 Kaggle 下载了`train.csv` 和`test.csv`,并将它们存储在一个文件夹 datasets 中。熊猫提供了方便的方法来读取 CSV 文件。
使用 pandas 加载数据
当您执行这个 Python 脚本时,它会加载数据并显示训练数据集的前五行。
训练数据集中的前五行数据
下面是 Kaggle 给出的每个字段的描述。
训练集中数据的说明
## 2.将文本转换为数字
为了能够在机器学习策略中使用这些字段,我们必须将它们转换为数字。此外,为了能够计算字段之间的相关性,字段必须是数字。
列中的值应该是数字,以便能够计算相关性。除此之外,大多数机器学习算法更喜欢与数字打交道。因此,我们需要将性别和着手列转换为数字。
Scikit-Learn 库包含一个名为`OrdinalEncoder`的类,可以用于这个目的。下面的代码展示了如何将`Sex`列转换成数字。
使用 OrdinalEncoder 将性别列转换为数字
同样,我也将`Embarked`列转换为数字。
## 3.通过相关性选择相关参数
在我开始删除记录或添加缺失值之前,我想知道哪些值最有可能影响乘客的生存。有些字段可能是显而易见的,如性别列。由于“妇女和儿童优先”的行为准则,性别栏是乘客生存机会的一个很好的指示器。
但我想有一个更具战略性的方法来确定这一点。您可以使用数据框的`corr()`方法计算幸存列和其他列之间的相关性。
计算相关矩阵
这导致下面的相关矩阵。
不同列和幸存列之间的关联
我们看到`Sexenc`列,正如预期的那样,与存活有最强的相关性。列`Pclass`、`Fare`、`Embarkedenc`也有不错的关联。其余列之间的相关性很小。因此,我从训练集中删除了这些列,因为它们对机器学习模型没有影响或影响很小。
使用数据框上的`drop`方法可以轻松删除列。
## 4.删除或添加缺少的值
加载数据后,我们可以调查训练集中是否有数据缺失。用方法`read_csv`我们创建了一个名为 titanic 的数据帧。
这个数据框有一个名为`isna()`的方法,它创建一个与数据框大小相同的二维数组。数组中填充了布尔值,这些值指示原始数据框中的值是否不可用(an)。通过将`isna`与`sum`、`titanic.isna().sum()`结合起来,我们可以很好地了解数据帧中有多少缺失值。
我们看到在`Age`列中缺少 177 条记录,在`Cabin`列中缺少 687 条记录,在`Embarked`中缺少两条记录。添加缺失值有几种可能性。您可以删除缺少值的记录。您还可以添加缺少的值。例如,使用`Age`,您可以计算平均值或中值,并将其添加到缺失值中。
当你查看机器学习预测的结果时,你可以评估什么表现最好。
我决定从用平均值填充缺失的年龄值开始。
我决定用最常见的值来填充`Embarked`中缺失的两个值。使用行`titanic[‘Embarked’].value_counts()`,您可以获得列内值的概述。该命令产生了以下输出。
S 644
C 168
Q 77
我们看到 S (Southhampton)是最常见的值。所以我们可以使用`fillna`方法来填充缺失的两个值。
`titanic[“Embarked”] = titanic[“Embarked”].fillna(‘S’)`
**机舱立柱**
尽管 Cabin 列中缺少许多值,但您仍然可以从中提取相关信息。B96、G6、C23、E101 等舱号的第一个字母表示舱的甲板。
在我看来,甲板是重要的信息,因为下层甲板上的乘客生还的可能性较低。

RMS *泰坦尼克号*的剖面图,船中部(1917),(图片来自[维基共享](https://commons.wikimedia.org/wiki/File:Titanic_cutaway_diagram.png),C *版权已过期*)
我们可以使用下面的语句`titanic[‘Deck’] = titanic[‘Cabin’].str[:1]`创建一个名为 Deck 的新列。请注意,我们还必须将该列转换为数字,就像我们之前看到的那样。
通过使用领域知识在数据中引入新特征被称为**特征工程**。
## 5.移除异常值
数据准备的最后一步是识别和剔除异常值。异常值是超出预期的极端值,与其他数据不同。通常,机器学习模型可以通过移除这些异常值来改进。
有多种方法可以检测和移除异常值。我使用`quantile`方法来检测并删除高于 99%或低于 1%的数据值。
使用 quantile()检测和移除异常值
您必须小心移除异常值,因为您无法确定这些值是否确实是错误的。我试图建立有离群值和无离群值的机器学习模型,并查看模型的性能是提高还是下降。
随着数据的清理,离群值的移除,以及缺失值的填充,我们最终可以开始训练机器学习模型。
# 创建和训练支持向量机(SVM)
如前所述,我为机器学习策略选择了 SVM。Scikit-Learn 库包含一个 SVM 的实现。
在将数据输入 SVM 之前,我们还需要做一件事,**特征缩放**。当数字输入特征具有不同的尺度时,大多数机器学习算法表现不佳。泰坦尼克号的数据就是这种情况。
我们使用 Scikit-Learn 的`scale()`函数来缩放数据。“缩放”是一种快速简便的值缩放方法,通过这种方法,所有要素都以零为中心,并且具有相同顺序的方差。
我做的另一件事是在第三行将训练集分成训练集和测试集。这允许我们使用测试集来验证训练模型的性能。
在第七行,我们在 Scikit-Learn 中创建了名为 SVC 的 SVM。使用第八行中的`fit`方法执行模型的实际训练。
为了评估模型的性能,我们使用 Scikit-Learn 的`plot_confusion_matrix`函数创建了一个混淆矩阵。混淆矩阵函数使用测试集来可视化性能。

SVM 的困惑矩阵,图片由作者提供
该矩阵表明模型正确预测了 123 名乘客的生存(黄色)。此外,该模型正确预测了 62 名乘客,他们没有生存(蒂尔)。另一方面,模型错误地预测 27 名乘客幸存,而他们没有(蓝色)。此外,它错误地预测了 11 名乘客没有幸存,而他们实际上幸存了下来(紫色)。
因此,我们的模型是可行的,但并不完美。
# 预测测试集的生存并提交给 Kaggle
比赛的最后一部分是使用经过训练的模型,使用 Kaggle 的测试集来预测乘客的存活率。与训练集一样,测试集也需要清理。
因为我创建了加载和清理数据的函数,所以这就像用测试集调用函数一样简单。
在第七行中,先前训练的 SVM 用于预测测试集中乘客的存活率。剩下的代码是将结果转换成可用于提交给 Kaggle 的格式。

泰坦尼克号排行榜截图,图片由作者提供
完整的木星笔记本可以在 Github 的这里[找到。](https://github.com/PatrickKalkman/Kaggle/blob/master/Titanic/Kaggle_Titanic.ipynb)
# 结论
《程序员的深度学习》和《动手机器学习》这本书实际上解释了机器学习。它们包含许多展示如何解决真实世界机器学习问题的示例。
使用机器学习解决问题的最重要的部分是准备数据,以便机器学习算法可以使用它。我查看了数据集中字段之间的相关性,以确定保留哪些字段。这些值的中值替换了缺失的值。我们将非数字字段转换为数字,以便在机器学习中使用它们。
在这两本书的帮助下,我参加了 Kaggle 泰坦尼克号比赛,获得了 0.779907 的分数。我会继续学习这两本书,并努力提高我的分数。
我将参加的下一个 Kaggle 竞赛是[数字识别器](https://www.kaggle.com/c/digit-recognizer)。这使用 MNIST(“修改后的国家标准与技术研究所”)数据集。这是计算机视觉事实上的“hello world”数据集。
感谢您的阅读。
# 实用机器学习教程:第 1 部分(探索性数据分析)
> 原文:<https://towardsdatascience.com/practical-machine-learning-tutorial-part-1-data-exploratory-analysis-c13d39b8f33b?source=collection_archive---------16----------------------->
## 多类分类问题:地球科学示例(相)
虽然外面有大量伟大的书籍和论文来练习机器学习,但我总是想看一些简短、简单、带描述性手稿的东西。我一直想看到一个对手术过程进行适当解释并附有详细结果解释的例子。模型评估指标也需要被清楚地阐述。
在这项工作中,我将尝试包括 ML 建模的所有重要步骤(即使有些步骤对该数据集来说不是必需的),以制作一个一致且切实的示例,尤其是对地球科学家而言。八个重要的最大似然算法将被检查和结果将被比较。我会试着做一个议论文式的模型评估讨论。我不会深入算法的基础。
要访问数据集和 jupyter 笔记本,请找到我的 [Git](https://github.com/mardani72/Practical_ML_Tutorial_Facies_examp) 。
***注 1*** :本手稿中嵌入的代码是为了理解工作程序而给出的。如果你想自己锻炼,我强烈推荐使用 [jupyter 笔记本文件](https://github.com/mardani72/Practical_ML_Tutorial_Facies_examp/blob/main/Part1_practical_Tut_ML_facies.ipynb)。
***注 2:*** 混洗数据会导致您的跑步记录与此处显示的内容有所不同。
本教程有四个部分:
第一部分:探索性数据分析,
第二部分:建立模型&验证,
第三部分:模型评估-1,
第四部分:模型评估-2
## 1-探索性数据分析
***1–1 数据可视化*** *1–1 对数图
1–1–2 柱状图
1–1–3 交会图* ***1–2 特征工程*** *1–2–1 NaN 插补
1–2–2 特征提取
1–2–3 过采样*
## **2-构建模型并验证**
*****2–1 基线模型******2–2 超参数*** *2–2–1 网格搜索***
## **3-模型评估-1**
*****3–1 模型度量图******3–2 混淆矩阵*****
## **4-模型评估-2**
*****4–1 学习曲线
4–2 ROC 图
4–3 盲井预测与评价*****
**如果你对 python 和 ML 概念完全陌生,你需要熟悉一些基础知识才能从本教程中获益。由于我们将在这里处理的数据集是一个包括测井记录和相类的表格 CSV 文件,我之前的两篇文章(熊猫中的 [10 个步骤,熊猫](/10-steps-in-pandas-to-process-las-file-and-plot-610732093338)中的 [5 个步骤)可能对测井记录数据处理、加工和绘图有所帮助。所有实现都基于 scikit-learn 库。](/5-steps-in-pandas-to-process-petrophysical-well-logs-de6c8d03d9b1)**
# ****数据汇总****
**本研究的数据集([phase _ vectors . CSV](https://github.com/mardani72/Practical_ML_Tutorial_Facies_examp/blob/main/facies_vectors.csv))来自北美的 Hugoton 和 Panoma 油田,在堪萨斯大学(Dubois et。阿尔,2007)。它由九口井的测井数据(岩石物理性质的测量)组成。我们将使用这些测井数据来训练监督分类器,以便预测离散相组。更多细节,你可以看看[这里](https://github.com/mardani72/Facies-Classification-Machine-Learning/blob/master/Facies_Classification_Various_ML_Final.ipynb)。这七个特征是:**
1. **GR :这种电缆测井工具测量伽马辐射**
2. ****ILD_log10** :这是电阻率测量**
3. ****PE** :光电效应测井**
4. ****δφ**:φ是岩石物理学中的孔隙度指标。**
5. ****PNHIND** :中子和密度测井的平均值。**
6. **NM_M :非海相-海相标志**
7. ****RELPOS** :相对位置**
**九个离散相(岩石类别)是:**
1. ****(SS)** 陆相砂岩**
2. ****(CSiS)** 非海相粗粉砂岩**
3. ****(FSiS)** 非海相粉细砂岩**
4. ****(SiSH)** 海相粉砂岩和页岩**
5. ****(MS)** 泥岩(石灰岩)**
6. ****(WS)** 瓦克斯通(石灰岩)**
7. ****(D)** 白云石**
8. ****(PS)** 细粒砂岩(石灰岩)**
9. ****(BS)** 叶状藻障石(石灰岩)**
**使用 Pandas 将数据读入 python 后,我们可以将其可视化,以便更好地理解数据。在绘制之前,我们需要定义一个颜色图(这一步应该在特征工程部分,但我们需要在这里为相类绘制颜色),并为每个相指定颜色代码。**
*****1–1 数据可视化*** *1–1–1 对数图***
**这是一个创建情节的功能。**
**和井的图*施林普林:***
****
***1–1–2 条形图***
**我们可以使用计数器函数来定量评估每个类的贡献。为了查看相频率分布,我们可以使用柱状图,如下所示:**
****
**这是一个不平衡的数据集。白云石的会员参与度最低。与粗粉砂岩相比,白云石比粗粉砂岩少 8 倍。**
***1–1–3 交会图***
**为了可视化数据集中的多个成对二元分布,我们可以使用 seaborn 库中的 pairplot()函数。它以矩阵形式显示了数据集中变量组合的关系,并在对角线上显示了单变量分布图。很明显,PE 测井与平均孔隙度呈非线性关系。其他对没有显示出清晰的模式。对角线上的分布模式显示,尽管各种类别有很强的重叠,但每个特征的每个标签类别(相)都有可接受的分离。理想模式可以假设为高钟形正态分布图中分布图的清晰分离。**
****
****高亮显示**:共线特征是彼此高度相关的特征。在机器学习中,由于高方差和较低的模型可解释性,这些会导致测试集上的泛化性能下降。在这个数据集中,我们没有面临共线性。使用 data.corr()命令:**
****
*****1–2 特征工程*** *1–2–1 特征插补***
**数据集中缺少值是很常见的。要查看每列要素的空值总和:**
DataFrame.isna().sum()# to find out which wells do not have PE
df_null = data_fe.loc[data_fe.PE.isna()]
df_null['Well Name'].unique()#Categories (3, object): [ALEXANDER D, KIMZEY A, Recruit F9]
****
**这里,PE 有 917 个空值。
有几种方法可以处理数据集中的空值。最简单的方法是删除至少包含一个空值的行。对于较大的数据集,这可能是合理的,但在小数据框中,单点非常重要。我们可以用平均值或从列中相邻的数据点估算空值。用平均值填充不会影响数据方差,因此不会影响预测精度,但会产生数据偏差。如果我们有地质上均质的介质,如大量纯碳酸盐岩,则用列值的相邻单元填充可能是合适的。**
**我将在这里实现的另一种方法是使用机器学习模型来预测缺失值。这是处理该数据集的最佳方式,因为我们的数据集中只缺少一个要素,PE。另一方面,用最大似然预测填充比单个平均值好得多,因为我们能够通过将数据划分为训练集和测试集来查看最大似然相关性和准确性。**
**这里,我将使用 scikit-learn 的多层感知器神经网络来预测目标值。我不打算深入研究这种方法,并简单地使用它来预测缺失值。**
****
**ALEXANDER D 井的预测 PE 显示了正常范围和变化。预测准确率为 77%。**
***1–2–2 特征提取***
**在该数据集中拥有有限的一组要素可以让我们考虑从现有数据集中提取一些数据。首先,我们可以将地层分类数据转换成数值数据。我们的背景知识可以帮助我们猜测某些相可能更多地出现在特定地层中,而不是其他地层中。我们可以使用 LabelEncoder 函数:**
data_fe[‘Formation_num’] = LabelEncoder().fit_transform(data_fe[‘Formation’].astype(‘str’)) + 1
**我们将地层类别数据转换为数值,用作预测值,并从 1 而不是零开始增加 1 作为预测值。为了查看新特征提取是否有助于预测改进,我们应该定义一个基线模型,然后将其与提取的特征模型进行比较。**
*****基线模型性能*****
**为简单起见,我们将使用逻辑回归分类器作为基线模型,并用交叉验证概念来检查模型性能。数据将被分成 10 个小组,该过程将重复 3 次。**
**在这里,我们可以探讨特征提取是否可以提高模型性能。有许多方法,我们将使用一些变换来链接输入变量的分布,如分位数变换器和 KBins 离散化器。然后,将使用 PCA 和 TruncatedSVD 移除输入变量之间的线性相关性。要了解更多信息,请参考此处的。
使用特征联合类,我们将定义一个转换列表,以执行聚合在一起的结果。这将创建一个包含许多特征列的数据集,而我们需要降低维数以获得更快更好的性能。最后,递归特征消除或 RFE 技术可用于选择最相关的特征。我们选择了 30 个特征。**
**精确度的提高表明,当我们处理数据集中有限的特征时,特征提取是一种有用的方法。**
***1–2–3 过采样***
**在不平衡数据集中,我们可以使用重采样技术来添加更多的数据点,以增加少数群体的成员。每当少数民族标签目标具有特殊重要性时,如信用卡欺诈检测,这可能是有帮助的。在这个例子中,欺诈可能发生在不到 0.1%的交易中,而检测欺诈非常重要。
在这项工作中,我们将为数量最少的白云石类添加伪观测值**
****合成少数过采样技术,SMOTE** :该技术用于在特征空间中选择最近的邻居,通过添加一条线来分离样本,并沿着该线产生新的样本。该方法不仅从数量上超过的类生成副本,而且应用 K-最近邻生成合成数据。**
**精度提高了 3 %,但在多类分类中,精度不是最佳的评估指标。我们将在本部分中介绍其他内容**
## **1–3 功能重要性**
**一些机器学习算法(并非全部)提供重要性分数,以帮助用户选择最有效的特征进行预测。**
***1–3–1 特征线性相关***
**概念很简单:与目标值相关系数较高的特征对于预测很重要。我们可以提取这些系数,比如:**
****
***1–3–2 决策树***
**该算法基于用于在每个节点中分裂的标准(例如熵或基尼)的减少来提供重要性分数。**
****
***1–3–3 排列特征重要性***
**[排列特征重要性](https://scikit-learn.org/stable/modules/permutation_importance.html)是一种模型检验技术,当数据为表格形式时,可用于任何拟合的估计量。这对于非线性或不透明的估计器尤其有用。置换特征重要性被定义为当单个特征值被随机打乱时模型得分的减少。**
****
**在所有这些特征重要性图中,我们可以看到 6 号预测器(PE log)在标签预测中最重要。基于我们选择来评估结果的模型,我们可以根据它们的重要性来选择特征,并忽略其余的以加速训练过程。如果我们的特征数量丰富,这是很常见的,尽管在我们的示例数据集中,我们将使用所有特征作为预测器是有限的。**
# **摘要**
**数据准备是机器学习中最重要也是最耗时的步骤之一。数据可视化可以帮助我们理解数据的性质、边界和分布。特征工程是必需的,尤其是当我们有空值和分类值时。在小型数据集中,特征提取和过采样有助于提高模型性能。最后,我们可以分析数据集中的要素,以了解要素对于不同模型算法的重要性。**
**如果您有任何问题,请通过我的 LinkedIn 联系我: [Ryan A. Mardani](https://www.linkedin.com/in/amardani/)**
# 实用机器学习教程:第 2 部分(构建模型和验证)
> 原文:<https://towardsdatascience.com/practical-machine-learning-tutorial-part-2-build-model-validate-c98c2ddad744?source=collection_archive---------34----------------------->
## 多类分类问题:地球科学示例(相)
在这一部分中,我们将建立不同的模型,验证它们,并使用网格搜索方法找出最佳的超参数。本帖是 [part1](/practical-machine-learning-tutorial-part-1-data-exploratory-analysis-c13d39b8f33b) 的第二部分。你可以在这里找到这部分[的 jupyter 笔记本文件。](https://github.com/mardani72/Practical_ML_Tutorial_Facies_examp/blob/main/part2_practical_Tut_ML_facies.ipynb)
scikit-learn 库的 ML 项目中模型构建的概念很简单。首先,您选择您喜欢的模型类型,其次,**使用目标和预测器(特征)将模型拟合**到数据,最后,**使用可用的特征数据预测**未知标签。
在这个项目中,我们将使用这些分类器来拟合特征数据,然后预测相类。这里,我们不会深入这些算法的基本概念。你可以在 scikit-learn 网站上学习。
1 —逻辑回归分类器
2 — K 邻居分类器
3 —决策树分类器
4 —随机森林分类器
5 —支持向量分类器
6 —高斯朴素贝叶斯分类器
7 —梯度推进分类器
8 —额外树分类器
## 2–1 基线模型
构建基线模型的原理很简单:我们需要一个基本而简单的模型,来看看对数据和模型参数的调整是如何提高模型性能的。其实这就像一个比较的标尺。
在这个代码脚本中,我们首先定义了我们最喜欢的模型分类器。然后,建立 *baseline_model* 函数。在这个函数中,我们使用了管道函数来实现数据标准缩放的分步操作(便于模型更有效地运行)和模型对象调用交叉验证。我喜欢管道,因为它使代码更整洁,可读性更好。
[](https://en.wikipedia.org/wiki/Cross-validation_(statistics)#:~:text=Cross%2Dvalidation%2C%20sometimes%20called%20rotation,to%20an%20independent%20data%20set.)**交叉验证有时称为轮换估计或样本外测试,是各种类似的模型**验证**技术中的任何一种,用于评估统计分析的结果如何推广到独立的数据集。当训练数据的准确度分数远高于测试数据时,模型通常会过度拟合。检验模型性能的一种方法是随机保留数据集的一部分。这可能是小数据集的一个弱点。另一种方法是将数据集分成多个部分并运行,每个部分有一组不同的测试折叠,如下图所示。在这种交叉验证方法中,模型可以检查所有数据,而不会过度拟合。然而,对于这个项目,我们将保留一口井作为保留井,以便在所有优化之后检查模型性能。**
****
**图片来自 [scikit-learn](https://scikit-learn.org/stable/modules/cross_validation.html)**
**在交叉验证中,我们对已经分成 10 等份(折叠)的数据集重复了 3 次每个操作。事实上,我们打算用不同的训练集和测试集的组合将模型暴露给所有的数据,而没有重叠。**
**在这里,我们使用平均精确度作为衡量各种模型性能的标准(精确度和其他评估标准将在下一篇文章中详细阐述)。它用于简单性,而对于多类分类问题,准确性是最弱的模型评估方法。我们将在接下来的文章中讨论多类分类问题的模型评估指标。**
**额外树和随机森林分类器显示了相标签预测的最佳准确度分数,而高斯朴素贝叶斯分类器表现不佳。**
## **2–2 个超参数**
**在机器学习中,模型参数可以分为两大类:
**A-** **可训练参数**:如训练算法学习到的神经网络中的权值,且用户不干预过程,
**B-** **超参数:**用户可以在训练操作前设置,如学习率或模型中的密集层数。**
**如果您手动尝试,选择最佳超参数可能是一项繁琐的任务,如果您处理两个以上的参数,几乎不可能找到最佳超参数。**
**一种方法是*随机搜索*方法。事实上,它不是使用有组织的参数搜索,而是遍历参数的随机组合,寻找优化的参数。您可能会估计,对于较大的超参数调整,成功的机会会降低到零。**
**另一种方法是使用 *skopt* ,它是一个 scikit-learn 库,使用贝叶斯优化构建另一个参数搜索空间模型。*高斯过程*就是这些模型中的一种。这将生成模型性能如何随超参数变化而变化的估计。如果你对这种方法感兴趣,我已经为这个数据集做了一个例子,[这里](/bayesian-hyper-parameter-optimization-neural-networks-tensorflow-facies-prediction-example-f9c48d21f795)。我不会在这里重复这个过程,因为它几乎是一个大项目。**
***2–2–1 网格搜索***
**这种方法是将每个参数分成一个有效的均匀范围,然后简单地要求计算机循环参数组合并计算结果。该方法称为*网格搜索*。虽然是机器做的,但会是一个耗时的过程。假设您有 3 个超参数,每个超参数有 10 个可能的值。在这种方法中,您将运行 1⁰模型(即使有一个合理的训练数据集大小,这个任务也很大)。**
**您可以在下面的块代码中看到,没有涉及高斯朴素贝叶斯,因为该分类器没有能够强烈影响模型性能的超参数。**
**上面代码的运行时间几乎是一个小时(取决于您的计算机配置)。为了节省操作时间,我没有扩大网格搜索范围。您可以扩展超过 2 乘 2 的参数进行搜索,但预计运行时间将呈指数级增长。**
**从代码的第 69 行,您可以看到为每个分类器选择的最佳超参数。使用这些参数,我们可以建立具有最佳超参数的模型,并进行精度测试。**
****
**与基线模型性能(本文第一组代码的结果)相比,超参数调整有助于提高模型性能。似乎对于集合模型来说,超参数不如其余参数有效。与基线相比,超参数模型中的一些缺点意味着我们没有正确设计搜索范围。**
# **结论:**
**在这一部分,我们用默认参数构建了八个模型,进行了交叉验证。然后,我们使用网格搜索方法寻找超参数。采用最佳超参数重新建立模型,并与基本模型进行比较,可以看出模型性能有所提高。**
# 实用机器学习教程:第 3 部分(模型评估-1)
> 原文:<https://towardsdatascience.com/practical-machine-learning-tutorial-part-3-model-evaluation-1-5eefae18ec98?source=collection_archive---------37----------------------->
## 多类分类问题:地球科学示例(相)
在这一部分中,我们将详细阐述一些专门针对多类分类问题的模型评估度量。对于我们的相问题,下面讨论准确度、精确度、回忆和混淆矩阵。这篇文章是第一部分、[第二部分](/practical-machine-learning-tutorial-part-2-build-model-validate-c98c2ddad744)的第三部分。你可以在这里找到这部分[的 jupyter 笔记本文件。](https://github.com/mardani72/Practical_ML_Tutorial_Facies_examp)
当我刚接触机器学习时,我一直认为构建模型是 ML 任务中最重要的一步,而现在,我有了另一个概念;模型评估技巧是建模成功的关键。我们需要确保我们的模型能够很好地处理新数据。另一方面,我们必须能够解释各种评估指标,以了解我们的模型的优点和缺点,引导我们对模型进行改进。因为我们在本教程中处理多类问题,所以我们将关注相关的评估指标,但在此之前,我们需要熟悉一些定义。
## **3–1 模型指标**
当我们处理分类问题时,我们将有 4 种可能的模型结果:
**A)** **真正** ( **TP** )是模型的结果*正确*预测了*正*类。在我们的数据集中,正类是我们专门为标签预测寻找的标签。例如,如果我们正在分析“白云石”类预测,TP 是模型测试数据的真实预测白云石样本的数量。
**B)真阴性** ( **TN** )是模型*正确*预测*阴性*类的结果。白云石预测数据集中的负类是那些真正预测为非白云石的相类(预测为其余类,且确实不是白云石)。
**C)** **假阳性** ( **FP** )是模型*错误地*预测*阳性*类别的结果。在我们的数据集中,当我们评估白云岩类预测时,所有被错误预测为白云岩的相类。
**D** ) **假阴性** ( **FN** )是模型*错误地*预测*阴性*类的结果。同样对于白云石预测,FN 是将白云石预测为非白云石类。
**1。准确度**:它只是被计算为正确预测占预测总数的百分比。
准确度= (TP+TN) / (TP+TN+FP+FN)
**2。精度**:这个指标回答了这个问题:*完全正确的正面预测比例是多少?*
Precision = TP / (TP+FP)
看等式,我们可以看到,如果一个模型的假阳性预测为零,那么精度将为 1。同样,在白云石预测中,该指标显示了所预测的白云石真正是白云石的比例(而不是其他相被归类为白云石)。
**3。回忆**:回忆回答这个问题:*实际阳性有多少比例是正确分类的?*
召回率= TP / (TP+FN)
看等式,我们可以看到,如果一个模型的假阴性预测为零,那么召回率将为 1。在我们的例子中,回忆显示了被模型正确识别的白云石类的比例。
**注**:评估模型效率需要同时考虑精度和召回率。不幸的是,这两个参数相互作用,提高一个会导致降低另一个。理想的情况是两者都显示接近 1 的值。
**4。f1 _ score:**F1 分数可以解释为精度和召回率的加权平均值,其中 F1 分数在 1 处达到其最佳值,在 0 处达到其最差分数。精确度和召回率对 F1 分数的相对贡献是相等的。F1 分数的公式为:
F1 = 2 *(精度*召回)/(精度+召回)
让我们看一个逻辑回归分类器性能的例子:
运行:
from sklearn.metrics import precision_recall_fscore_support
model_log=LogisticRegression(C = 10, solver = ‘lbfgs’, max_iter= 200 )
model_log.fit(X_train, y_train)
y_pred_log = model_log.predict(X_test)
print(classification_report(y_test, y_pred_log, target_names= facies_labels))

为了评估逻辑回归分类器的性能,让我们看看第一相类砂岩(ss)。当这个模型预测一个相为 SS 时,它在 75%的时间内是正确的(精度)。另一方面,该模型正确识别了所有 SS 相成员的 89%(回忆)。我们可以猜测 f1_score 介于这两个指标之间。支持是指用于测试的单个类成员。
让我们用一些代码块来实现上述步骤,以便对所有模型进行排序,并绘制出结果的平均值。到第 15 行,我们用已经从网格搜索方法中获得的超参数定义了模型对象。然后(第 16 行到第 25 行)模型被添加到一个列表中,当我们想要按顺序拟合和交叉验证时,这个列表是可迭代的。在交叉验证之后,我们将每个模型的度量结果存储在列表中。第 37 到 52 行,我们建立了一个 for 循环来计算每个模型的每个指标的平均值。代码的其余部分是一个绘图任务。

该图显示了各个采用模型的每个评估指标(y 轴)的平均值。在这里,我们想从整体上比较所有型号的性能。看起来额外树和随机森林做了最好的预测,而高斯朴素贝叶斯不是那么有效的预测模型。
如果我们关心一个单独的相预测,我们应该考虑从“结果”列表中删除剩余的指标,并再次运行程序。
## 3–2 混淆矩阵
混淆矩阵显示了相对于原始真实标签数据的预测类别标签。这是一个奇妙的可视化工具,我们可以看到每一类相被正确或错误地预测到其他类中。
在下面的一行代码中,我们首先定义了一个函数,来花式利用 sklearn 开发的混淆矩阵函数。在函数定义之后,我们拟合并运行逻辑回归分类器。现在,我们已经用测试数据的真实相标签预测了相标签。使用所需的输入参数调用函数将创建混淆矩阵图。

看一下图(第一行),我们认识到该算法可以正确地预测 151 个 ss 类别,而 18 个真实 SS 被错误地分类为 CSI。从上一节中,我们熟悉了召回的概念。从 SS(169)的所有真实类成员中,分类器可以正确地识别 151;151/169 是 89%(上图我们在班级报告里看到过这个数字)。因此,我们可以得出结论,如果我们在行的方向上移动我们的评估(真实标签),我们正在处理召回。
你可能会猜测,如果我们走列方向,我们将处理精度。对于 SS,精度为 149/201 的 75%。
在下面的图片中,我们看到朴素贝叶斯分类器如何表现不佳的预测。这个分类器在预测上完全高估了 BS 类。

到目前为止,我们有一些帮助我们评估模型性能的指标,但是我们仍然不能保证哪一个是最好的。由于一些模型可以记忆训练数据,并严格遵循数据复杂性,当它面对一个新的数据集时,它的性能将会很差。这就是所谓的**过拟合**(高方差模型)。具有高方差的模型会随着训练数据集的小变化而发生很大变化。
另一方面,当模型过于一般化预测时,它将无法捕捉数据集的复杂性,这被称为**欠拟合**(高偏差模型)。我们的理想模型介于这两个模型之间,让我们进行偏差-方差权衡。
*问题是*:我们如何识别我们的模型是过拟合还是欠拟合?
我们将在本教程的下一部分讨论。
# 结论:
模型评估是 ML 模型制作中最重要的任务。我们主要从简单的评估指标开始,然后缩小到具体和更详细的指标,以了解我们模型的优势和劣势。
如果您有任何问题,请通过我的 LinkedIn 联系我: [Ryan A. Mardani](https://www.linkedin.com/in/amardani/)
**参考资料:**
1)[https://jakevdp . github . io/python datascience handbook/index . html](https://jakevdp.github.io/PythonDataScienceHandbook/index.html)
2)[https://scikit-learn.org/stable](https://scikit-learn.org/stable/supervised_learning.html#supervised-learning)
3)[https://machinelearningmastery.com](https://machinelearningmastery.com/)
4)[布伦顿霍尔](https://github.com/brendonhall/facies_classification/blob/master/Facies%20Classification%20-%20SVM.ipynb)
# 用 Prometheus & Grafana 进行实际监控(第三部分)
> 原文:<https://towardsdatascience.com/practical-monitoring-with-prometheus-grafana-part-iii-81f019ecee19?source=collection_archive---------14----------------------->
## 使用 Prometheus 应用简单统计学进行异常检测。

克里斯·利维拉尼在 Unsplash[上的照片](https://unsplash.com?utm_source=medium&utm_medium=referral)
在 Prometheus 和 Grafana 系列的[第一部分](https://medium.com/@yitaek/practical-monitoring-with-prometheus-grafana-part-i-22d0f172f993)和[第二部分](https://medium.com/@yitaek/practical-monitoring-with-prometheus-grafana-part-ii-5020be20ebf6)的实际监控中,我们安装了 Prometheus blackbox exporter 来探测 HTTP 端点,并通过 Helm 将我们的监控堆栈部署到 Kubernetes。在本帖中,我们将用白盒监控技术来补充我们的黑盒监控,即使用 z 分数的异常检测。
虽然有很多关于监控 Kubernetes 指标或使用 Prometheus 客户端库收集应用程序数据的教程,但很少有帖子涉及常见指标(如 HTTP 请求和消息队列大小)的异常检测技术。这篇文章将介绍一个示例场景,涉及一个 web 服务器通过消息队列与其他微服务通信。我们将尝试检测 HTTP 请求中的异常和消息队列大小的峰值,以创建智能警报规则。
*注意:对于预配置的普罗米修斯指标和预警规则,可以使用*[*Awesome Prometheus Alerts*](https://awesome-prometheus-alerts.grep.to/)*或者修改*[*Prometheus Operator*](https://coreos.com/tectonic/docs/latest/tectonic-prometheus-operator/user-guides/default-alerts.html)*的默认预警。如果你有灭霸设置,想更深入地钻研 ML 模型,还可以看看* [*AlCoE 的普罗米修斯异常探测器*](https://github.com/AICoE/prometheus-anomaly-detector) *项目。*
# 快速和堆叠驱动程序设置
要运行异常检测,我们首先需要数据。我将使用 NodeJS/Express 服务器作为示例,但是您可以根据自己选择的语言找到相应的 Prometheus 客户机。
npm i express-prometheus-middleware
我们将只使用默认设置(即向`/metrics`端点公开 Prometheus 指标并收集[默认 NodeJS 指标](https://github.com/siimon/prom-client#default-metrics))并指定 HTTP 请求持续时间桶。
const express = require('express')
const promMid = require('express-prometheus-middleware')const app = express();// ... other express setup hereapp.use(promMid({
metricsPath: '/metrics',
collectDefaultMetrics: true,
requestDurationBuckets: [0.1, 0.5, 1, 5, 10]
}));app.listen(8080)
现在,服务器将收集`http_requests_total`(接收到的带有路由、方法和状态标签的请求总数的计数器)和`http_request_duration_seconds`(带有路由、方法和状态标签的 HTTP 持续时间,以秒为单位)。制作一个 Docker 图像,添加 Prometheus scrape 注释,并在 Kubernetes 上部署舵图。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Chart.Name }}
labels:
app: {{ .Chart.Name }}
spec:
selector:
matchLabels:
app: {{ .Chart.Name }}
template:
metadata:
labels:
app: {{ .Chart.Name }}
annotations:
prometheus.io/port: "8080"
prometheus.io/scrape: 'true'// ... rest of deployment.yaml
对于消息队列,我将通过 Stackdriver 使用 Google Pub/Sub 和 monitor,但是您可以用 Prometheus exporters for Kafka、RabbitMQ 或您选择的其他队列实现来替换它。
要部署 Stackdriver 导出器,首先创建一个`stackdriver.yaml`文件来指定要监控的 GCP 项目 ID 和 Stackdriver 度量。我使用了一些 PubSub 指标,但是你也可以在这里找到可用的 GCP(和 AWS)指标的完整列表[。](https://cloud.google.com/monitoring/api/metrics_gcp)
stackdriver:
projectId: "
metrics:
typePrefixes: 'pubsub.googleapis.com/subscription/num_undelivered_messages,pubsub.googleapis.com/subscription/streaming_pull_ack_request_count,pubsub.googleapis.com/topic/message_sizes'annotations:
prometheus.io/port: "9255"
prometheus.io/scrape: "true"
现在部署图表,等待指标开始显示:
helm install -f stackdriver.yaml stackdriver-exporter stable/stackdriver-exporter// or Helm 2
// helm upgrade --install stackdriver-exporter stable/stackdriver-exporter -f stackdriver.yaml
# 异常检测
> “在正确的时间完美地检测异常是不可能的”
> —[John Allspaw 致监控/指标/警报公司的公开信](https://www.kitchensoap.com/2015/05/01/openlettertomonitoringproducts/)
使用 Prometheus 对时间序列数据执行异常检测的棘手部分是为数据设置合理的聚合。对于我们的 HTTP 请求和 PubSub 度量示例,我们有两个选择:
1. 我们用什么标签来分组数据?应该按服务,路线,还是环境?
2. 我们用什么时间段来确定费率值?1m,5m,10m?
如果聚合跨越太多数据,数据集子集内的异常可能会被整体趋势混淆。另一方面,如果聚合太细,那么我们的模型容易出现误报。聚合的级别将取决于您的用例,但在大多数情况下,以 5m 为间隔使用服务(即 HTTP 请求的服务器和发布/订阅的主题/订阅)似乎是最佳的。
## 应用简单统计:z 分数
高级时间序列异常检测技术,如状态空间模型(ARIMA,霍尔特-温特斯),分解(STL),或降维(RPCA,SOM)是不切实际的,只使用普罗米修斯。要尝试那些流行的模型,你可以用灭霸导出你的数据,用 R (Twitter 的 [AnomalyDetection](https://github.com/twitter/AnomalyDetection) )或者 Python (LinkedIn 的 [Luminol](https://github.com/linkedin/luminol) )。但对我们来说,假设我们的流量大部分是正态分布的,简单的 z 分数将让我们开始。
z 分数是由标准差(σ)数确定的统计测量值,原始分数来自平均值。z 分数为 0 意味着我们的分数与数据集的平均值相匹配。使用标准正态分布,我们就知道 95%的数据在平均值的 2σ以内,99.7%的数据在 3σ以内。

由英文维基百科的 Heds 1 提供——由 Abdull 从 en.wikipedia 转到 Commons。、公共领域、【https://commons.wikimedia.org/w/index.php?curid=2799839
现在,假设我们的 HTTP 请求计数和 PubSub 指标呈正态分布,我们可以使用 z 分数将 3σ之外的数据标记为异常并触发警报。
## 创建录制规则
定义了聚合级别后,我们需要创建记录规则来保存预先计算的值,以便进行更快的 z 分数分析。例如,我们可以创建一个以 5m 为间隔捕获 HTTP 请求率的指标,按应用程序分组,如下所示:
- record: job:http_requests:rate5m
expr: sum by (app) (rate(http_requests_total[5m]))
同样,对于 PubSub 指标,我们可以跟踪按主题分组的 5m 间隔的消息大小:
- record: job:pubsub_message_size:rate5m
expr: sum by (topic_id) (rate (stackdriver_pubsub_topic_pubsub_googleapis_com_topic_message_sizes_count[5m]))
要应用记录规则,在舵图中的`serverFiles`下添加`recording_rules.yml`部分:
serverFiles:
recording_rules.yml:
groups:
- name: PubSubRules
rules:
- record: job:pubsub_message_size:rate5m
expr: sum by (topic_id) (rate(stackdriver_pubsub_topic_pubsub_googleapis_com_topic_message_sizes_count[5m]) )
- name: HTTPRules
rules:
- record: job:http_requests:rate5m
expr: sum by (app) (rate(http_requests_total[5m]))
现在你应该看到普罗米修斯/格拉夫纳上的记录规则了:

PubSub 消息大小速率 5m 规则
## 计算 z 分数
为了计算 z 分数,我们需要计算特定时间段的平均值和标准差。因为我们处理的是 web 服务,所以使用一周的数据是计算每周平均值的合理时间段:
*注意:为了简洁起见,我将只包括 PubSub 规则,但这同样适用于 HTTP 请求。添加新规则后,不要忘记部署新的 Prometheus 服务器配置来查看更改。*
现在让我们来计算周平均值和标准偏差值:
- record: job:pubsub_message_size:rate5m:avg_over_time_1w
expr: avg_over_time(job:pubsub_message_size:rate5m[1w])- record: job:pubsub_message_size:rate5m:stddev_over_time_1w
expr: stddev_over_time(job:pubsub_message_size:rate5m[1w])
Z-score 是我们的样本数据点减去平均值除以标准差:

Z 分数的公式
z-score calculation
(job:pubsub_message_size:rate5m - job:pubsub_message_size:rate5m:avg_over_time_1w) /
(job:pubsub_message_size:rate5m:stddev_over_time_1w)
一旦我们绘制了 z 分数,就很容易发现超出+/- 3σ范围的异常情况:

发布/订阅主题的 z 分数
需要注意的一点是:只有当我们的基本假设是正确的(即我们的聚合数据是正态分布的)时,使用 z 分数来确定异常值才有效。有多种方法[来测试正态分布,但是您可以简单地绘制聚合记录规则来直观地确定。](/6-ways-to-test-for-a-normal-distribution-which-one-to-use-9dcf47d8fa93)

一周的交通趋势(周末较小的颠簸)
如果你的数据看起来不是正态分布,你可以计算 z 分数,看看范围是否保持在~-3.5 到+3.5 之间。如果您看到非常高或非常低的值,则数据过于倾斜,可能需要借助数据转换来规范化数据集。
## 设置警报
最后,我们可以使用这些数据来创建警报,以便在检测到异常时发出通知。只需在 z 得分超出 3σ时添加一条警报规则:
- name: AnomalyDetection
rules:- alert: PubSubSizeAnomalyDetected
expr: abs( (job:pubsub_message_size:rate5m - job:pubsub_message_size:rate5m:avg_over_time_1w) /
(job:pubsub_message_size:rate5m:stddev_over_time_1w) ) > 3
for: 10m
labels:
severity: warning
annotations:
summary: "Anomaly detected in queue {{ $labels.topic }}"
description: "The queue size saw a huge spike or drop off - check the corresponding logs for that service"
- alert: PubSubSizeAnomalyDetected
我们可以通过简单的阈值检查(例如,当未送达邮件数量超过 500 时发出警报)来补充此警报,以减少误报,并仅在检测到真正的异常时发出警报。您还可以添加其他统计方法,如季节性,以说明一周与周末的交通水平。
在 Prometheus 和 Grafana 系列实际监控的[下一个也是最后一个帖子](https://medium.com/@yitaek/practical-monitoring-with-prometheus-grafana-part-iv-d4f3f995cc78)中,我们将使用 GCP 的 IAP 服务来保护 Grafana 仪表板,以保护我们的入口。
你可以在这里找到这个系列的其他文章:
* 第一部分:[5 分钟后通过头盔安装普罗米修斯+格拉夫纳](https://medium.com/@yitaek/practical-monitoring-with-prometheus-grafana-part-i-22d0f172f993)
* 第二部分:[使用 Prometheus blackbox exporter 进行免费正常运行时间检查](https://medium.com/@yitaek/practical-monitoring-with-prometheus-grafana-part-ii-5020be20ebf6)
* 第三部分:[使用 Prometheus 对异常检测应用简单统计](/practical-monitoring-with-prometheus-grafana-part-iii-81f019ecee19)
* 第四部分:[用身份认证代理保护 Grafana】](https://medium.com/@yitaek/practical-monitoring-with-prometheus-grafana-part-iv-d4f3f995cc78)
# 实用的自然语言处理:用拥抱脸的管道总结长短演讲
> 原文:<https://towardsdatascience.com/practical-nlp-summarising-short-and-long-speeches-with-hugging-faces-pipeline-bc7df76bd366?source=collection_archive---------60----------------------->
## 与情感分析或分类相比,文本摘要是一项不太普遍的自然语言处理任务,因为它需要时间和资源来很好地执行。拥抱脸的变形金刚管道改变了这一点。这里有一个快速演示,教你如何简单地总结简短和冗长的演讲。

来自【PAP.org.sg】(左)和 [WP.sg](https://www.wp.sg/message-for-voters/) (右)的截图。
一些人可能会说,总结演讲更像是一门艺术,而不是科学。但 NLP 的最新进展可以很好地检验这一论点的正确性。
特别是,拥抱脸(HF)的变压器[总结管道](https://huggingface.co/transformers/_modules/transformers/pipelines.html#SummarizationPipeline)已经使这项任务更容易,更快,更有效地执行。不可否认的是,目前的结果仍然存在不确定性。但是,随着语言模型变得越来越复杂,也有一些闪光点暗示着未来的可能性。
这篇文章将向你展示如何使用 HF 的管道来总结简短和长篇演讲。由于管道中使用的模型的最大序列限制,对于长演讲需要一个小的解决方案。我还包含了一个简单的文本摘要 web 应用程序的代码,您可以在本地机器上运行它。
# 1.数据、笔记本和注意事项
这是这篇文章的 Github 报告。本帖中使用的[玩具数据集基于 2020 年 7 月新加坡大选期间发表的一小部分政治演讲/声明。执政的人民行动党(PAP)和反对党的政治家们的演讲字数从 236 字到 3746 字不等。](https://github.com/chuachinhon/practical_nlp/blob/master/data/ge2020_speeches.csv)

我的笔记本[中概述的简单工作流程应该适用于你想放在一个 CSV 文件中的任何其他演讲集。据我所知,高频总结管道对非英语演讲不起作用。](https://github.com/chuachinhon/practical_nlp/blob/master/notebooks/2.0_speech_summary_cch.ipynb)
我使用现成的管道,这意味着结果来自默认的 [bart-large-cnn](https://huggingface.co/facebook/bart-large-cnn) 模型。请随意测试其他为这个任务调整的[模型](https://huggingface.co/models?filter=pipeline:summarization)。
# 2.总结简短的演讲
不太可能有人需要一口气批量运行几十个或几百个简短发言的摘要。但是如果你真的这么做了,HF 管道的易用性是一个救命稻草。
在这里,我整理了七篇 800 字以下的演讲。根据您使用的计算机和 transformers 库的版本,结果和时间可能会有所不同。
这是在 2018 年的 Mac Mini 上运行的,64Gb 内存,2.11.0 版本的[变形金刚库](https://pypi.org/project/transformers/)。您可以在此下载结果[,并将摘要与原文进行比较:](https://www.dropbox.com/s/bgdi2p7vs2d8igy/short_results.csv)

在这里下载这个 CSV 文件[。](https://www.dropbox.com/s/bgdi2p7vs2d8igy/short_results.csv)
有些总结一般。这个模型明显倾向于使用演讲中的第一句和第二句。这对于新闻故事的摘要来说可能很有效,但是对于那些涉及政治/公司演讲的就不那么有效了。
但是这个模型出现了一个精彩的总结,第五个总结中,工人党(WP)领导人普里塔姆·辛格向选民展示了他的政党的主要观点。此处见原语句[,此处通过 Bart 模型与摘要进行并列对比。](https://www.wp.sg/message-for-voters/)

左图:来自 [WP.sg](https://www.wp.sg/message-for-voters/) 的屏幕截图。
在短短的 59 个字里,Bart 模型完美地从 627 个字的声明中提炼出了 WP 竞选信息的精髓。那些熟悉新加坡政治的人会理解这一总结有多尖锐,尤其是考虑到该模型并未根据涉及新加坡新闻或政治的数据进行调整。
要问这个总结是侥幸还是开心的巧合,也不是没有道理。我通过最新版本的变形金刚(3.0.2 版)运行了相同的一组演讲,得到了一个不太令人印象深刻的翻译:“工人党为新加坡人提供了一个选择和议会中的另一个声音。wp 为我国的民主进程做出了重大贡献。后撰写回忆录的前人民行动党议员帮助揭露了由人民行动党主导的议会的局限性”。
在这一点上,质量的一致性似乎是个问题。不幸的是,更全面的测试超出了本文的范围。
# 3.总结一篇长篇演讲
这可能是大多数人的用例:总结一篇长达数千字的演讲。为了绕过管道/模型中的序列长度限制,我使用了一个函数将文本分解成许多固定字符长度的块。
为了保持这篇文章的简洁,我决定对玩具数据集中最长的讲话——3746 个单词——运行 HF 管道。我把演讲稿分成 9 大块,每块 2500 字。
该功能允许您轻松设置您喜欢的字符长度。诚然,这种方法很笨拙,但我发现它有助于更仔细地检查结果。详细情况在我的[笔记本](https://github.com/chuachinhon/practical_nlp/blob/master/notebooks/2.0_speech_summary_cch.ipynb)里。
这是[到原演讲](https://www.pap.org.sg/news/ge2020-news/ge2020-lunch-time-rally/)的链接,比较原文和小摘要的 CSV 文件可以在[这里](http://A CSV file comparing the original text with the mini-summaries can be dowloaded here)下载。这是一个模型如何概括它的并列比较:

左图:来自[Pap.org.sg](https://www.pap.org.sg/)的截屏。点击下载长篇演讲总结[的 CSV 结果文件。](https://www.dropbox.com/s/uqs14olj69mzntq/long_speech_results.csv)
536 个字的“综合总结”没有我上面强调的 WP 例子那么精彩,但对于初稿来说,它相当不错(除了用红色突出显示的部分,我稍后会讨论)。如果我处于紧要关头,这是我可以迅速编辑成更有用形式的东西。
新加坡用户很容易在第六部分的摘要中发现一个明显的错误:“人民行动党李光耀寻求的不仅仅是你的授权,而是你领导新加坡度过这场危机的强大授权。”
原文是:“投资者将仔细审查选举结果,并根据他们的结论采取行动。其他人也会如此,包括新加坡的朋友和敌人。这就是为什么在这次选举中,人民行动党寻求的不仅仅是你们的授权,而是你们强有力的授权,来领导新加坡度过这场危机。”
新加坡开国总理李光耀[于 2015 年 3 月](https://en.wikipedia.org/wiki/Lee_Kuan_Yew)去世。然而,那些对新加坡政治稍有了解的人可能会轻率地争辩说,这个模型实际上是正确的,与上述提到李光耀的总结没有任何错误。但这是另一天的讨论;页(page 的缩写)
# 4.WEB 应用程序
我试图部署一个简单的 web 应用程序,让非笔记本用户尝试 summarisation pipeline,但发现 Pythonanywhere.com 的[免费帐户没有足够的存储空间](https://www.pythonanywhere.com/forums/topic/26685/)来存储所需的库,尤其是 pytorch。
所以我上传了一个在本地机器上运行的[版本](https://github.com/chuachinhon/practical_nlp/blob/master/apps/summary_app_local.py),如果你想让同事们在工作场所试用的话。web 应用程序的代码改编自两个来源:Github 的主代码[和使用 DistilBart 的 Plotly](https://github.com/Csmith715/Summarizer) 的第二个代码[。](https://github.com/plotly/dash-sample-apps/blob/master/apps/dash-summarize/app.py)

如果应用程序返回错误,这意味着您复制的文本已超过最大令牌数。试着以更小的块进行总结,或者使用笔记本中的功能来分解文本。如果 Pythonanywhere.com 将 pytorch 作为预装包的一部分,我将尝试在未来在线部署该应用程序。
# 5.结论
随着更多语言模型的加入,有足够的空间进行实验,并对 HF 管道的总结输出进行更健壮的测试。到目前为止,我自己的经验是,使用不同的模型不一定会转化为更好的结果。
在我的笔记本快结束时,我切换到 T [5 模式](https://huggingface.co/transformers/model_doc/t5.html) l 进行试用,但发现三个简短演讲的总结并不比默认的 Bart 模式产生的总结好。
但是,随着像拥抱脸和 OpenAI 这样的公司继续推进 NLP 信封,我们肯定会看到未来的可能性。我当然很好奇 GPT 3 号在这项任务上表现如何,鉴于它迄今为止在各种任务上取得的令人印象深刻的结果。
与此同时,那些想用自己的数据集微调变压器模型的人可以查看这两本笔记本[这里](https://github.com/abhimishra91/transformers-tutorials/blob/master/transformers_summarization_wandb.ipynb)和[这里](https://github.com/ohmeow/ohmeow_website/blob/master/_notebooks/2020-05-23-text-generation-with-blurr.ipynb)。然而,为您的用例找到一个好的数据集可能比您想象的更具挑战性。
如果您在这篇文章或笔记本中发现错误,请联系我:
推特:[蔡振鸿](https://medium.com/u/b3d8090c0aee?source=post_page-----aad7f2e1d0a0----------------------)
领英:[www.linkedin.com/in/chuachinhon](http://www.linkedin.com/in/chuachinhon)
# 实用熊猫指南
> 原文:<https://towardsdatascience.com/practical-pandas-guide-b3eedeb3e88?source=collection_archive---------59----------------------->
## 举例说明各种功能和方法。

照片由[恒电影](https://unsplash.com/@hengfilms?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)在 [Unsplash](https://unsplash.com/s/photos/style?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 拍摄
Pandas 是一个非常强大和通用的 Python 数据分析库,它加速了数据分析和探索过程。学习熊猫提供的功能和方法的最好方法是练习。
> 熟能生巧。
在本帖中,我们将通过大量的例子来探索熊猫的各种能力。我们将通过简单和高级的例子来看看熊猫的能力。
一如既往,我们从进口熊猫开始。
import pandas as pd
import numpy as np
让我们首先创建一个样本数据框架。我们可以将字典传递给熊猫的**数据帧**函数。
df = pd.DataFrame({'num_1':np.random.random(100),
'num_2':np.random.random(100),
'num_3':np.random.randint(0,5,100),
'num_4':np.random.randint(0,100,100)})df.head()

我们使用 numpy 数组来创建数字列。让我们也添加分类列到我们的数据框架。
from random import samplename = ['Linda','John','Ashley','Xavi','Betty','Mike'] * 100
cat = ['A','B','C','D'] * 100names = sample(name, 100)
cats = sample(cat, 100)
列表“姓名”和“猫”包含从更长的列表“姓名”和“猫”中随机选择的 100 个样本。我们使用了 python 的**随机**模块中的**样本**函数。
是时候将这两个分类特征添加到数据框架中了。
df.insert(0, 'names', names)
df['cats'] = catsdf.head()

我们用两种不同的方式添加了两个新列。df['col'] = col 在末尾添加新列。我们可以使用 **insert** 函数指定新列的位置,就像我们对“names”列所做的那样。
假设我们对“数量 1”大于“数量 2”的行感兴趣。下面两行代码完成了这项任务,并显示了前五行。
df[df.num_1 > df.num_2][:5]df.query('num_1 > num_2')[:5]

你可以使用任何一个,但我更喜欢**查询**功能。我认为在更复杂的过滤器的情况下更简单。如果我们希望看到基于不同类别(“cats”)的“num_1”和“num_2”的比较,我们可以对过滤后的数据帧应用 **groupby** 函数。
df1 = df.query('num_1 > num_2') [['cats','names']].groupby('cats').count().reset_index()
df1

“names”列在这里是不相关的,只是为了能够计算行数而选择的。似乎类别 C 和 D 有更多的行,其中“num_1”比“num_2”高。但是,除非我们知道每个类别在整个数据帧中有多少行,否则这些数字没有意义。
ser = df['cats'].value_counts()df2 = pd.concat((df1,ser), axis=1)df2.rename(columns={'names':'num_1>num_2', 'cats':'total'}, inplace=True)df2

我们使用 **value_counts** 创建了一个包含 cats 列中每个类别的计数的序列。然后,我们将 df1 和 ser 与 **concat** 函数结合起来,并重命名这些列。最终的 dataframe df2 显示了每个类别的总行数以及符合过滤参数的行数。
假设我们希望在“num_4”中看到“cats”中每个类别的平均值,但是我们只希望看到几个名字的平均值。在这种情况下,我们可以使用 **isin** 方法进行过滤,然后应用 **groupby** 。
name = ['Ashley','Betty','Mike']df[df.names.isin(name)][['cats','num_4']].groupby('cats').mean()

如果还需要出现的次数,我们可以在 groupby 上应用多个聚合函数。
name = ['Ashley','Betty','Mike']df[df.names.isin(name)][['cats','num_4']].groupby('cats').agg(['mean','count'])

我们在 4 个不同的列中存储了 4 个不同的测量值。我们可以将它们合并在一列中,并在另一列中指明测量的名称。这是原始数据帧:

**融化**功能可以用来实现我刚才描述的功能。
df_melted = df.melt(id_vars=['names','cats'])df_melted.head()

当处理宽数据帧(即大量特征)时,Melt 特别有用。例如,如果我们有 100 个不同的测量值(num_1 到 num_100),那么在一个熔化的数据帧上进行分析就容易多了。
我们的数据帧包含测量值,因此我们很可能通过添加新的测量值来更新数据帧。假设我们用下面的 new_row 更新了 dataframe。
new_row = {'names':'Mike', 'num_1':0.678, 'num_2':0.345,
'num_3':3, 'num_4':[68,80], 'cats':'C'}df_updated = df.append(new_row, ignore_index=True)
df_updated.tail()

new_row 已添加,但存在一个问题。它包含“num_4”中的几个值。我们应该让他们分开坐。熊猫的**爆炸**功能可以用来做这个任务。
df_updated = df_updated.explode('num_4').reset_index(drop=True)
df_updated.tail()

我们已经将“num_4”中的值分开了。可能会有这样的情况,一列在许多行中包含许多组合值。在这些情况下,分解功能可能会派上用场。
在某些情况下,我们可能需要替换一些值。熊猫**替换**功能让它变得非常简单。我们甚至可以通过传递一个字典来替换多个值。
replacement = {'D':'F', 'C':'T'}
df.cats.replace(replacement, inplace=True)df.head()

假设我们需要根据一个条件替换一些值。条件被指定为“num_1 中低于 0.5 的值将被替换为 0”。在这种情况下,我们可以使用 **where** function。
df['num_1'] = df['num_1'].where(df['num_1'] >= 0.5, 0)df.head()

“where”的工作方式是选择符合条件的值,并用指定的值替换剩余的值。**其中(df['num_1']≥0.5,0)** 选择“num_1”中所有大于 0.5 的值,其余值替换为 0。
数据帧包含 4 个数值特征和 2 个分类特征。我们可能需要看到一个关于数值如何基于类别变化的快速总结。Pandas **pivot_table** 函数可以提供这种汇总,并且在显示选项方面非常灵活。
df.pivot_table(index='names', columns='cats', values='num_2', aggfunc='mean', margins=True)

此表显示了 num_2 值如何根据名称-类别组合而变化。最好将 **margin** 参数设置为 True,以查看与整体值的比较。 **aggfunc** 参数有许多选项,如计数、最小值、最大值。
数据帧的一个常见任务是处理缺失值。我们创建的数据帧没有任何缺失值。我们先随机添加一些缺失值。
a = np.random.randint(0,99,20)
df.iloc[a, 3] = np.nan
我们用 0 到 99 之间的 20 个随机整数创建了一个数组。然后我们在 iloc 中使用它作为索引。第四列(列索引为 3)中的 20 行被替换为 np.nan,这是熊猫的一个缺失值表示。
df.isna()。sum()返回每列中缺失值的数量。

虽然我们传入了 20 个索引,但是缺少的值的数量似乎是 15 个。这是因为数组 a 中的重复值。
len(np.unique(a))
15
我们可以用 **fillna** 函数替换缺失值。我们可以使用一个常数来替换缺失值或列的统计数据,如平均值或中值。
df['num_3'].fillna(df['num_3'].mean(), inplace=True)
df.isna().sum()

这只是你能为熊猫做的一小部分。你用它做得越多,你就会发现越多有用和实用的方法。我建议用不同的方法处理问题,永远不要给自己设限。
当你努力寻找一个问题的解决方案时,你学到的东西几乎总是比手头问题的解决方案要多。您将逐步提高自己的技能,以建立一个强大而高效的数据分析流程。
感谢您的阅读。如果您有任何反馈,请告诉我。
# 实用熊猫:合成商店销售分析
> 原文:<https://towardsdatascience.com/practical-pandas-synthetic-store-sales-analysis-110e904a84fc?source=collection_archive---------26----------------------->
## 练习完成数据分析任务的技巧

伯纳德·赫曼特在 [Unsplash](https://unsplash.com/s/photos/store?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上的照片
我跳过了我提到熊猫在数据科学领域的伟大特征和优势的部分。
这篇文章更像是一个实践指南,展示了如何在数据分析中使用熊猫。我还将尝试为数据分析任务提供一种半结构化的方法。
我称之为“合成的”,因为这些数据是随机产生的。让我们从创建商店销售数据集开始。
import numpy as np
import pandas as pdstores = pd.Series(['A','B','C','D']125).sample(500)cities = pd.Series(['Rome','Madrid','Houston']200).sample(500). reset_index(drop = True)
我们使用熊猫的**样本**功能创建了两个随机系列的商店和城市。样本大小必须等于或小于原始系列的大小。这就是我们通过乘以常数来扩展列表的原因。
是时候将它们与日期和销售额一起放在一个数据框架中了。
df = pd.DataFrame({
'day':np.random.randint(1,30, size=500), 'month':np.random.randint(1,12, size=500),
'year':2020,
'store':stores,
'city':cities,
'product1':np.random.randint(50, size=500),
'product2':np.random.randint(40, size=500),
'product3':np.random.randint(30, size=500)}
)df.head()

(图片由作者提供)
基于商店-城市-日期组合列出了 3 种产品的销售量。最好也有一个“日期”列,将单独的日、月和年组合在一起。我们将在“年份”列之后放置新的“日期”列,这可以通过**插入**函数来完成。
df.insert(3, 'date', pd.to_datetime(df[['day','month','year']]))df.head()

(图片由作者提供)
index 函数的第一个参数指示新列的位置。
**注意**:由于我们随机生成数据,因此可能会产生一个不存在的日期 2 月 30 日。在这种情况下,to_datetime 函数将引发一个错误,指出“日期超出了该月的范围”。你可以把你的天数限制在 29 天,或者重新运行随机函数。
我们现在有了合成数据。开始分析的一个方法是检查销售量是否有季节性。我们可以使用 **groupby** 函数按月对销售额进行分组,然后绘制结果。
df[['month','product1','product2','product3']].groupby('month')
.mean().plot(figsize=(10,6), fontsize=12, title='Monthly Sales of Products')

(图片由作者提供)
产品 1 和 2 似乎具有季节性,而产品 3 更稳定。我们已经检查了月平均销售额。
不同商店-城市组合的销售量可以提供有价值的信息,这也可以通过 groupby 函数来实现。我们将使用 pandas 的 Style 属性使结果比普通数字更有吸引力,而不是绘制结果。
df[['store','city','product1','product2','product3']]
.groupby(['store','city'])
.mean().style.highlight_max(color='lightgreen', axis=0)
.highlight_min(color='orange', axis=0)

(图片由作者提供)
除了商店-城市平均销售额之外,还突出显示了每列中的最小值和最大值。在报告中使用它肯定比简单的数字更有吸引力。
还有其他可用的样式选项。我们再做一个。
df[['store','city','product1','product2','product3']]
.groupby(['store','city'])
.mean().style.bar(color='lightgreen')

(图片由作者提供)
条形的大小与列中的值成比例。
原始数据集将“日”、“月”和“年”作为单独的列。我们将它们组合成一个具有适当数据类型的“日期”列。

(图片由作者提供)
在典型的分析中,我们可能有很多列,所以消除冗余或重复的列是一个好的做法。因此,我们可以删除“日”、“月”和“年”列,因为它们提供的数据存储在“日期”列中。
df.drop(['day','month','year'], axis=1, inplace=True)df.head()

(图片由作者提供)
我们在分析中使用了“月”列。我们仍然可以通过使用 **dt** 访问器来使用日期的各个部分。
df['date'].dt.month[:5]
0 8
1 11
2 8
3 4
4 11
一开始,我们检查月平均销售量。在某些情况下,月平均值可能不够详细。熊猫在选择频率方面非常灵活。
下面的代码将绘制 product1 的 10 天平均销售额。
df[['date','product1']].groupby('date').mean()
.resample('10D').mean().plot(figsize=(10,6), fontsize=12,
title="10-Day Average Sales")

(图片由作者提供)
我们首先按日期对销售额进行分组,这给出了每日的平均值。然后使用重采样功能将日期下采样到 10 天周期。用于取 10 天期间平均值的平均值。最后,绘制结果。
我们也可以用熊猫来创建密度图。例如,我们可以使用 kde 函数来绘制销售量的密度分布。KDE(核密度估计)是一种估计随机变量概率密度函数的非参数方法。
subset = df[['store','city','product1','product2','product3']]subset.plot.kde(figsize=(12,6), alpha=1, fontsize=12)

(图片由作者提供)
请注意,KDE 是一个估计,而不是实际的概率分布。这就是我们在图中看到负值的原因。
让我们更具体地分析一下。例如,您可能希望看到连续两天的平均销售额之间的最大增加或减少。例如,我们将在商店 a 中进行检查。
df[df.store == 'A'].groupby('date').mean()

(图片由作者提供)
这些是商店 a 中销售量的日平均值。 **diff** 函数返回连续两行之间的差异。
df[df.store == 'A']
.groupby('date').mean().diff().sort_values(by='product1')[:5]

(图片由作者提供)
我们已经按产品 1 对值进行了升序排序,以查看产品 1 销售量的最大降幅。2020 年 10 月 28 日,产品 1 的销售量比前一天减少了 37。
类似地,我们可以发现 product2 中的增幅最大。
df[df.store == 'A'].groupby('date').mean().diff().
sort_values(by='product2', ascending=False)[:5]

(图片由作者提供)
我们已经介绍了一些可以在典型的数据分析任务中使用的技术。熊猫的能力远远超出了这里讨论的技术。当你需要完成任务时,你会发现更多。
感谢您的阅读。如果您有任何反馈,请告诉我。
# 统计学习(一):房价数据的假设检验
> 原文:<https://towardsdatascience.com/practical-practice-of-hypothesis-testing-on-house-price-dataset-1fb169bc04ee?source=collection_archive---------13----------------------->

布鲁克·卡吉尔在 [Unsplash](https://unsplash.com/collections/9506121/computer-science%2C-math-%26-statistics-?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上的照片
H 你有没有想过什么因素会对房价产生重大影响?
我们将深入研究爱荷华州埃姆斯市的住宅区价格数据集。
(数据集[从 kaggle 下载)在美国的埃姆斯市,有 1460 所房子,来自不同的 25 个社区。作为一个拥有 65,000 多人口的小镇,只有地块面积是影响房价的主要原因吗?是否有其他因素会将相对影响置于与地块面积相同的位置?基于以上的假设,我们就知道什么对房价有如此大的影响。](https://www.kaggle.com/c/house-prices-advanced-regression-techniques/overview)
也许你正在埃姆斯寻找一个新的住处。你一直在房产网站上搜索房源,但基于你的住房偏好,你不知道什么价格更合理。1460 套房子的数据集对显示最大因子是否显著?
这就是假设检验的用武之地。
# 一些专业术语的定义:
## **——零假设(H0)**
零假设是被认为是真实的初始假设。
## -替代假设(H1)
另一个假设与零假设正好相反。如果计算结果推断无效假设应被拒绝,则支持替代假设。
## - P 值
p 值是作为检查点的给定统计模型接受或拒绝零假设的概率。如果 p 值小于或等于显著性水平,则应推翻零假设。
## -显著性水平:
这是观察证据有多强的可能性。当 p 值高于阈值时,零假设不会被拒绝。否则,当 p 值低于阈值时,替代假设将被拒绝。

## 单边假设检验:
当 **α** 设为 0.05 时,置信度为 90%。这意味着分布图左侧和右侧的 p 值都可以是 0.05。
## 双边假设检验:
当 **α** 设为 0.05 时,置信度为 95%。这意味着 p 值将在右侧或左侧被分成两半。
# 方法:
## 指定无效假设和替代假设
**H0:** 房屋建成日期早导致房价低
**H1:** 房屋建成日期早并不导致房价低
## 选择重要性级别
将α设为 0.05,相当于 95%的置信水平。
## 确定概率
> 我们选择计算一个 **Pearson 相关系数**和来自 scipy 包的用于测试相关性的 p 值。
> Pearson 相关系数衡量两个数据集之间的线性关系,其取值范围从-1 到 1。
> -1 表示负线性关系,+1 表示正线性关系,0 表示无相关性。
下面粘贴的是**皮尔逊相关系数**测量的代码!首先,我把数据集转移到熊猫的数据框架中。将 Pandas Dataframe 列转换为数组,并将其传递给 Pearson scipy 包以获取 p_value。
## 决定是拒绝还是不拒绝零假设,并做出决定
如皮尔逊相关检验所示,p 值远低于 0.05 的显著性水平。因此,我们将**基于皮尔逊检验的 p 值输出拒绝零假设**。
> 根据皮尔逊双尾值,当 p 值落在绿区、**外的区域**时,应拒绝**零假设。另一方面,当 p 值**落入绿色区域**,**时,零假设将被接受**。**

95%置信水平的概率分布图
## 结论
在进行皮尔逊相关假设检验后,我们知道房价和年建成量之间不存在强相关关系。稍后,我将通过生成两个特征的散点图来运行分析,并查看结果是否与相关性的假设测试相匹配。
## 建议:
在对 2 个特征进行假设检验之前,建议对数据集做一些简单的分析。例如,我查看了这栋房子最早的建造日期,从 1872 年到 2010 年。并且,房价从 3.49 万到 75.5 万不等。然后,我绘制了一个散点图来查看这两个特征的相关性。散点图显示,在这两个特征上没有**强相关线**,**我们可以得出结论,在艾姆斯越早建房子并不会导致房价越高**。

## 额外分析:
**平均**房价为**180921**,**中位数**为**163000**。
我们想看看从 1882 年到 2009 年建造的**房屋的价格在这个范围内。**

房价在平均值和中值范围内的年建成房屋箱线图
从箱线图中,我们可以看到房子的平均建造年份是 1982 年,房价从 163,000 到 180,921 不等。此外,根据以上分析,我们知道该房屋的平均房价属于 **22 年**的范围。
感谢阅读!
请在下面的评论区分享您的反馈。
# 实用 Python:类与实例变量
> 原文:<https://towardsdatascience.com/practical-python-class-vs-instance-variables-431fd16430d?source=collection_archive---------3----------------------->
## 如何定义它们并与之互动

(图片由作者提供)
类是 Python 最基础的部分,因为它是面向对象编程的本质。
Python 中的一切都是对象比如整数、列表、字典、函数等等。每个对象都有一个类型,对象类型是使用类创建的。
实例是属于一个类的对象。例如,list 是 Python 中的一个类。当我们创建一个列表时,我们有一个 list 类的实例。
在本文中,我将重点关注类和实例变量。我假设您对 Python 中的类有基本的了解。如果没有,您仍然可以理解什么是类和实例变量,但是语法可能看起来有点让人不知所措。
如果你想重温基础知识,我还写了一篇关于 Python 类的介绍性文章。
让我们从类和实例变量开始。
类变量是在类内部而不是在任何函数外部声明的。实例变量是在构造函数 _ _ init _ _ 方法中声明的。
考虑下面的类定义:
class Book():
fontsize = 9
page_width = 15 def init(self, name, writer, length):
self.name = name
self.writer = writer
self.length = length
假设 Book 类被一家出版公司使用。fontsize 和 page_width 是类变量。创建的每个 book 实例的 fontsize 为 9,page_width 为 15 cm。

[NMG 网](https://unsplash.com/@nmgnetwork?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)在 [Unsplash](https://unsplash.com/s/photos/book-publishing?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上的照片
name、writer 和 length 变量是在 __init__ 方法中声明的,因此它们是实例变量。这些变量的值在创建实例时确定。
这是有意义的,因为 fontsize 和 page_width 通常是标准的。但是,名称、作者和长度是特定于每本书的(即实例)。
将 fontsize 和 page_width 声明为类变量节省了我们大量的时间和精力。假设出版公司决定改变书籍中使用的字体大小。如果它是一个实例变量,我们将需要为每个实例(如 book)更改它。然而,由于它是一个类变量,一个赋值就可以完成每本书的工作。
让我们创建 Book 类的一个实例:
book1 = Book("Intro to Python", "John Doe", 50000)print(book1.writer)
"John Doe"print(book1.page_width)
15
尽管我们没有显式地将 page_width 变量分配给我们的实例,但它在默认情况下具有这个属性。
我们可以为任何实例更改类变量的值(即覆盖它们)。假设我们想让 book1 宽一点,那么我们将改变这个实例的 page_width。
book1.page_width = 17print(book1.page_width)
17print(Book.page_width)
15
如您所见,我们只更改了 book1 实例的值。类变量的值保持不变。
我们定义的方法可以访问类变量,但是我们需要小心。我将在下面的例子中说明原因。
我们为 Book 类定义了一个方法,该方法根据长度(字数)、字体大小和 page_width 计算页数:
def number_of_pages(self):
pages = (self.length * fontsize) / (page_width * 100)
return pages
此方法将引发一个 NameError,表明未定义“fontsize”。“页面宽度”也是如此。虽然这些是类变量,但我们需要告诉方法从哪里获取它们。
我们可以从实例本身或从类中获取它们。
Using the instance
def number_of_pages(self):
pages = (self.length * self.fontsize) / (self.page_width * 100)
return pages#Using the class
def number_of_pages(self):
pages = (self.length * Book.fontsize) / (Book.page_width * 100)
return pages
这两种方法都行得通。我们来做一个例子:
book1 = Book("Intro to Python", "John Doe", 50000)book1_pages = book1.number_of_pages()print(book1_pages)
300
更新类变量将影响该类的所有实例。这是一个节省我们时间和精力的好功能。然而,我们也需要小心变化的程度。
这里有一个例子。
book1 = Book("Intro to Python", "John Doe", 50000)
book2 = Book("Intro to Pandas", "Jane Doe", 40000)print(book1.fontsize, book2.fontsize)
(9, 9)Book.fontsize = 11print(book1.fontsize, book2.fontsize)
(11, 11)
实例通过它们所属的类来访问类变量。让我们做一个例子来说明我的意思。
__dict__ 方法可用于查看实例或类的属性。
book1 = Book("Intro to Python", "John Doe", 50000)
print(book1.dict)
{'name': 'Intro to Python', 'writer': 'John Doe', 'length': 50000}print(book1.fontsize)
9
当我们打印出 book1 的数据属性时,我们看不到 fontsize 或 page_width。但是,我们可以通过打印出来看到 book1 有 fontsize 属性。
实例(book1)通过类访问类变量。让我们也在 Book 类上应用 __dict__ 方法。
print(Book.dict)
__module__': '__main__ ', **'fontsize': 9,' page _ width ':15【T1],' __init__': <功能本。__init__ at 0x7f6cc5f54620 >,' number_of_pages': <函数 Book . number _ of _ at 0x 7 F6 cc 5 f 548 c8>,' __dict__': <属性' __dict__' of 'Book '对象>,' __weakref__': <属性' _ _ weak ref _ _ '' Book '对象>,' __doc__': None}**
类变量以及方法和其他一些东西都打印出来了。
## 结论
类变量影响整个类。因此,当一个类变量被更新时,所有的实例也被更新。这非常方便,但我们也需要小心。如果使用不慎,可能会出现不良后果。
实例变量为每个实例取唯一的值。我们在创建实例时为它们赋值。
所有的实例一开始都为类变量取相同的值,但是我们可以在以后为一个实例更新它们。我们对一个实例所做的更改不会影响其他实例的类变量的值。
感谢您的阅读。如果您有任何反馈,请告诉我。
# 实用 Python: Try、Except 和 Assert
> 原文:<https://towardsdatascience.com/practical-python-try-except-and-assert-7117355ccaab?source=collection_archive---------7----------------------->
## 综合实践指南

威廉·戴尼奥在 [Unsplash](https://unsplash.com/s/photos/try?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上拍摄的照片
每个软件程序员的梦想都是写一个运行流畅的程序。然而,开始时通常不是这样。如果出现错误,代码的执行将会停止。
意外情况或条件可能会导致错误。Python 将这些情况视为异常,并根据异常的类型引发不同种类的错误。
ValueError、TypeError、AttributeError 和 SyntaxError 是这些异常的一些示例。好在 Python 还提供了处理异常的方法。
考虑下面的代码,它要求用户输入一个数字,并打印该数字的平方。
a = int(input("Please enter a number: "))print(f'{a} squared is {a*a}')
只要输入的是数字,它就能正常工作。但是,如果用户输入一个字符串,python 将引发一个 ValueError:

(图片由作者提供)
我们可以在代码中实现一个 try-except 块来更好地处理这个异常。例如,我们可以向用户返回一个更简单的错误消息,或者要求他们再输入一次。
try:
a = int(input("Please enter a number: "))
print(f'{a} squared is {a*a}')
except:
print("Wrong input type! You must enter a number!")
在上面的例子中,代码更清楚地通知用户错误。
如果由于 try 块中的代码引发了异常,则执行将继续 except 块中的语句。因此,如何处理异常取决于程序员。
普通的 try-except 块将捕捉任何类型的错误。但是,我们可以更具体一些。例如,我们可能只对特定类型的错误感兴趣,或者希望以不同的方式处理不同类型的错误。
可以用 except 语句指定错误的类型。考虑下面的代码,它要求用户从列表中输入一个数字。然后,它根据输入从字典中返回一个名字。
dict_a = {1:'Max', 2:'Ashley', 3:'John'}number = int(input(f'Pick a number from the list: {list(dict_a.keys())}'))
如果用户输入一个不在给定列表中的数字,我们将得到一个 KeyError。如果输入不是一个数字,我们将得到一个 ValueError。我们可以使用两个 except 语句来处理这两种情况。
try:
dict_a = {1:'Max', 2:'Ashley', 3:'John'}
number = int(input(f'Pick a number from the list:
{list(dict_a.keys())}'))
print(dict_a[number])
except KeyError:
print(f'{number} is not in the list')
except ValueError:
print('You must enter a number!')

(图片由作者提供)
Python 还允许引发自己的异常。这有点像定制默认异常。raise 关键字和错误类型一起用于创建您自己的异常。
try:
a = int(input("Please enter a number: "))
print(f'{a} squared is {a*a}')
except:
raise ValueError("You must enter a number!")
以下是非数字输入情况下的错误消息。
ValueError: You must enter a number!
让我们再做一个例子,展示如何在函数中使用 try-except 块。
avg_value 函数返回一组数字的平均值。
a = [1, 2, 3]def avg_value(lst):
avg = sum(lst) / len(lst)
return avgprint(avg_value(a))
2
如果我们传递一个空列表给这个函数,它会给出一个 ZeroDivisionError,因为空列表的长度是零。
我们可以在函数中实现一个 try-except 块来处理这个异常。
def avg_value(lst):
try:
avg = sum(lst) / len(lst)
return avg
except:
print('Warning: Empty list')
return 0
如果列表为空,该函数将打印一条警告并返回 0。
a = []print(avg_value(a))
Warning: Empty list
0
try 和 except 块用于处理异常。断言用于确保条件符合函数的要求。
如果断言为假,则函数不继续。因此,断言可以是防御性编程的一个例子。程序员正在确保一切都如预期的那样。
让我们在 avg_value 函数中实现 assert。我们必须确保该列表不为空。
def avg_value(lst):
assert not len(lst) == 0, 'No values'
avg = sum(lst) / len(lst)
return avg
如果列表的长度为零,函数立即终止。否则,它会一直持续到结束。
如果 assert 语句中的条件为 false,将引发 AssertionError:
a = []
print(avg_value(a))
AssertionError: No values
assert 对于发现代码中的错误非常有用。因此,它们可以用来支持测试。
## 结论
我们已经介绍了如何在代码中实现 try、except 和 assert。它们在很多情况下都派上了用场,因为很可能会遇到不符合预期的情况。
Try、except 和 assert 为程序员提供了对代码的更多控制和监督。他们能很好地发现和处理异常。
感谢您的阅读。如果您有任何反馈,请告诉我。
# 学习数据科学数学的实际原因
> 原文:<https://towardsdatascience.com/practical-reasons-to-learn-mathematics-for-data-science-1f6caec161ea?source=collection_archive---------19----------------------->
## 揭秘作为一名 ML 从业者学习数学以应对现实世界挑战的必要性

图片来自 [Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=433560) 的 [sandid](https://pixabay.com/users/sandid-356019/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=433560)
> 数据科学和机器学习中的数学不是关于处理数字,而是关于正在发生什么,为什么会发生,以及我们如何通过尝试不同的事情来获得我们想要的结果。
基于此博客发布的视频
围绕为数据科学学习数学的误解已经被诸如“没有数学的数据科学”、“开发人员的数据科学”、“没有数学的机器学习”等标题的课程、视频和博客帖子所扩大。这样的帖子存在是因为有这样的问题:
* 当我可以简单地调用`.fit()`来训练和`.predict()`来测试我的模型时,为什么我需要学习数学?
* 机器学习是关于掌握 Sci-kit learn 和 tensorflow 等库的使用。为什么要浪费时间去理解下面的数学?
* 掌握数据科学需要了解多少数学知识?
* 我害怕数学,可以从事数据科学吗?
这些问题没有唯一正确的答案,因为**数据科学包含不同的角色**,从数学角度来看,每个角色都有不同的要求。部分原因是许多教育工作者利用的术语数据科学的宽泛性质。
如果你更倾向于数据的工程(设计 ETL 管道,创建和处理数据基础设施)方面,你可能不需要理解数学。对于想掌握机器学习,尤其是深度学习的人来说,你绝对应该至少熟悉线性代数、向量微积分、概率论等数学概念。
这篇文章旨在回答为什么有必要学习数学来掌握数据科学,以便更好地发挥机器学习的作用。我们将讨论您可能遇到的真实世界场景,在这些场景中,您将利用您对算法的深刻理解。
但是,让我们首先了解机器学习的核心组件,以及它们与数学的直接关系。
# 数学和机器学习的核心
ML 有 3 个核心组件:
## **1。数据**
ML 本质上是数据驱动的;数据是机器学习的核心。最终目标是从数据中提取有用的隐藏模式。虽然数据并不总是数字,但当它被视为数字时更有用。我们可以把数据想象成**向量—** 一个遵守算术规则的对象。这让我们理解了线性代数的规则是如何操作数据数组的。
## **2。型号**
模型是某些信念和假设的数学表示。据说它首先学习(近似)如何提供数据、如何生成数据的过程(线性、多项式等),然后基于所学习的过程进行预测。
根据应用数学的一般思想,我们定义了许多**变量**的函数,这些变量从**概率角度**代表了某些假设。在回归示例中,模型近似于将输入映射到实值输出的函数。
## **3。学习**
为了解释机器学习中的术语“自动”,每个模型都以成本函数**为特征,我们设计该函数来衡量我们在开发模型时所做的假设与现实(尚未看到的数据或测试数据)的对应程度。我们使用数值优化方法(偏导数,SVD)来最小化这个成本函数。**
以这种方式定义这三个概念的主要目的是帮助你理解它们所基于的数学。
# 需要理解数学基础的真实场景
你可能会争辩说,所有这些概念在库中都被抽象了,为什么不直接在它们之上构建呢?为了反驳这一点,让我们看看这些真实世界的场景,作为一个有抱负的机器/深度学习实践者,你每天都会遇到这些场景。
## **建立高效的学习系统**
作为一名数据科学家,你不仅需要知道机器学习算法,还需要利用你的知识,建立更有效的模型。一个很简单的例子就是为你的问题选择性能指标,性能指标让你知道你的系统在预测时会犯多大的错误。
以房价预测的一个回归问题为例,数据集包含很多离群值。对于那些只知道均方根误差(RMSE)是回归模型的首选性能测量方法的人来说,即使异常值会增加很大的误差,作为公式中平方项的含义,他们也会简单地评估模型。
现在,RMSE 测量预测向量(下面公式中的 h(x(i))和目标标签向量(y(i))之间的距离。它是这些距离的平方和的根。我们如何在大型数据阵列上做到这一点?这都要归功于**向量和线性代数的魔力。**

从公式中可以看出,在这种情况下,一种更有效的性能测量方法是平均绝对误差(MAE ),因为与 RMSE 相比,平均绝对误差对异常值不太敏感。

## **用机器学习解决特定领域的挑战**
任何基于产品的公司的数据科学家都需要用他的分析和模型结果来支持关键决策,因此需要精通研究领域。无论是金融、电子商务、生物信息学还是疾病诊断。金融、银行等计算密集型领域。需要很强的数学背景。
例如,一名在对冲基金中担任定量分析师的数据科学家正在开发一个衍生品证券定价模型,他应该知道对数回报、正态分布和微积分是如何促进其模型开发的。
传统的统计分析仍然大量用于所有以研究为导向的数十亿美元的领域,如药物发现,这需要你理解统计概念,如均值、标准差、抽样、自举、峰度、偏斜度等。
不仅仅是这些,数学还是所有主要行业的基础。
## **理解并调试 ML 算法**
调试一个软件程序是很容易的,因为你只需要考虑两个方面,算法或者它的实现。对问题可能在哪里建立直觉更容易,但在机器学习的情况下,调试变得非常困难,因为以数据和所选模型的形式增加了维度。你的算法要么不起作用,要么不够好。

[https://ai . Stanford . edu/~ zayd/why-is-machine-learning-hard . html](https://ai.stanford.edu/~zayd/why-is-machine-learning-hard.html)
幸运的是,我们有其他指标来找出问题所在。对于那些很好地理解基础数学**多元微积分**的人来说,他们会更好地理解如何优化**梯度下降**的成本函数。熟悉了数学,你就能更好地调试你的学习系统(模型)。
## 基于其固有限制的模型选择
很多时候,一个模型工作得很好,但是由于它的可伸缩性和计算复杂性,它并不用于生产(实际的产品)。了解您的训练算法的固有限制有助于您为您的用例选择正确的模型,即使它不是最佳模型。
这里要讲的一个很好的例子是我们对成本函数的理解。例如,线性回归模型的均方误差(MSE)成本函数恰好是一个凸函数。该凸函数是连续的,并且其斜率从不突然改变,这导致我们使用梯度下降,因为它保证任意接近全局最小值,这是成本函数的目标。
了解成本函数背后的形状和数学也有助于我们定义模型的参数。例如,在使用梯度下降时,我们应确保缩放要素,因为它收敛到全局最小值的速度非常慢,如下右图所示:

缩放要素(左)和不缩放要素(右)时收敛到全局最小值
## 工作面试
申请数据科学家的职位不仅仅需要你知道 Sci-kit learn 或 Tensorflow,你需要知道决策树如何计算每个节点的`gini`杂质,如何优化线性回归模型的成本函数,或者线性 SVM 分类器的决策函数是什么。
谷歌的数据科学家职位描述是这样的:
> 擅长统计数据分析,如线性模型,多元分析,随机模型,抽样方法。
## ML 四个分支下的数学基础

机器学习的支柱及其数学基础
上图显示了位于四个分支(即回归、分类、维数减少和密度估计)基础上的数学概念的有力分解。
从职业角度来看,如果你真的想从事数据科学,你至少必须熟悉一些主题,如覆盖向量和矩阵的线性代数,量化不确定性的概率分布,标量和解释梯度下降的向量微积分。
# 摘要
我们需要了解数据科学的数学基础对以下方面非常重要:
* 理解机器学习的基本原理,使我们能够建立更复杂和有效的学习系统。
* 创建新的特别机器学习解决方案,以应对特定领域问题中的不同复杂性和挑战。
* 理解和调试现有的算法方法。
* 了解模型的内在假设和局限性。
# Harshit 的数据科学
通过这个渠道,我计划推出几个覆盖整个数据科学领域的[系列。以下是你应该订阅](/hitchhikers-guide-to-learning-data-science-2cc3d963b1a2?source=---------8------------------)[频道](https://www.youtube.com/channel/UCH-xwLTKQaABNs2QmGxK2bQ)的原因:
* 该系列将涵盖每个主题和子主题的所有必需/要求的高质量教程,如 [Python 数据科学基础](/python-fundamentals-for-data-science-6c7f9901e1c8?source=---------5------------------)。
* 解释了为什么我们在 ML 和深度学习中做这些事情的数学和推导。
* 与谷歌、微软、亚马逊等公司的数据科学家和工程师以及大数据驱动型公司的首席执行官的播客。
* [项目和说明](/building-covid-19-analysis-dashboard-using-python-and-voila-ee091f65dcbb?source=---------2------------------)实施到目前为止所学的主题。
你可以在 [Twitter](https://twitter.com/tyagi_harshit24) 、 [LinkedIn](https://www.linkedin.com/in/tyagiharshit/) 或 [Instagram](https://www.instagram.com/upgradewithharshit/?hl=en) 上与我联系(在那里我谈论健康和福祉。)
# 数据科学家的实用火花技巧
> 原文:<https://towardsdatascience.com/practical-spark-tips-for-data-scientists-145d85e9b2d8?source=collection_archive---------13----------------------->

图片由[安德鲁·马丁](https://pixabay.com/users/aitoff-388338/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1984421)来自 [Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=1984421)
## 与 pySpark 一起工作时,让您的生活更加舒适
我知道——Spark 有时令人沮丧。
***虽然有时候我们可以使用***[***Rapids***](/minimal-pandas-subset-for-data-scientist-on-gpu-d9a6c7759c7f?source=---------5------------------)***或*** [***并行化***](/add-this-single-word-to-make-your-pandas-apply-faster-90ee2fffe9e8?source=---------11------------------)*等工具来管理我们的大数据,但是如果您正在处理数 TB 的数据,就无法避免使用Spark。*
*在我关于 Spark 的最后几篇文章中,我解释了如何使用 PySpark RDDs 和 T42 数据帧。尽管这些帖子解释了很多关于如何使用 rdd 和 Dataframe 操作的内容,但它们仍然不够。*
*为什么?因为 spark 经常出现内存错误,而且只有当您真正使用 Spark 处理大数据集时,您才能真正使用 Spark。*
***这篇文章的主题是“数据科学家实用的火花和内存管理技巧”***
# *1.地图端连接*
**
*连接数据框架*
*Spark 中的连接语法与 pandas 非常相似:*
df3 = df1.join(df2, df1.column == df2.column,how='left')
*但是我面临一个问题。`df1`大约有 10 亿行,而`df2`大约有 100 行。当我尝试上述连接时,它不起作用,并在运行 20 分钟后出现内存耗尽错误。*
*我在一个非常大的集群上编写这段代码,这个集群有 400 多个执行器,每个执行器都有 4GB 以上的 RAM。当我尝试使用多种方案对数据帧进行重新分区时,我被难住了,但似乎没有任何效果。*
*那我该怎么办呢?Spark 不能处理仅仅十亿行吗?不完全是。我只需要使用 Spark 术语中的地图端连接或广播。*
from pyspark.sql.functions import broadcast
df3 = df1.join(broadcast(df2), df1.column == df2.column,how='left')
*使用上面简单的广播代码,我能够将较小的`df2`发送到所有节点,这并没有花费很多时间或内存。后端发生的事情是将`df2`的副本发送到所有分区,每个分区使用该副本进行连接。这意味着 df1 没有数据移动,它比 df2 大很多。*
# *2.火花簇构型*
**
*根据您的任务大小设置并行度和工作节点*
*当我开始使用 Spark 时,让我的生活变得困难的还有 Spark 集群需要配置的方式。基于您想要运行的作业,您的 spark 集群可能需要大量定制配置和调优。*
*一些最重要的配置和选项如下:*
## *a.spark.sql.shuffle.partitions 和 spark.default.parallelism:*
*`spark.sql.shuffle.partitions`配置为连接或聚合而重排数据时要使用的分区数量。`spark.default.parallelism`是 rdd 中由`join`、`reduceByKey`和`parallelize`等转换返回的默认分区数量,当用户没有设置时。这些值的默认值是 200。*
****简而言之,这些设置了您想要在集群中拥有的并行度。****
*如果您没有很多数据,值 200 没问题,但是如果您有大量数据,您可能希望增加这些数字。也要看你有多少遗嘱执行人。我的集群相当大,有 400 个执行者,所以我把它保持在 1200。一个经验法则是保持它是执行人数量的倍数,这样每个执行人最终都有多个工作。*
sqlContext.setConf( "spark.sql.shuffle.partitions", 800)
sqlContext.setConf( "spark.default.parallelism", 800)
## *b.spark . SQL . parquet . binaryasstring*
*我在 Spark 中处理`.parquet`文件,我的大部分数据列都是字符串。但不知何故,每当我在 Spark 中加载数据时,字符串列都会被转换成二进制格式,在这种格式下,我无法使用任何字符串操作函数。我解决这个问题的方法是使用:*
sqlContext.setConf("spark.sql.parquet.binaryAsString","true")
*上述配置在加载拼花文件时将二进制格式转换为字符串。现在这是我在使用 Spark 时设置的默认配置。*
## *c.纱线配置:*
*您可能需要调整其他配置来定义您的集群。但是这些需要在集群启动时设置,不像上面的那些那样动态。我想放在这里的几个是用于管理 executor 节点上的内存溢出。有时,执行程序核心会承担大量工作。*
* *spark . yarn . executor . memory overhead:8192*
* *yarn . node manager . vmem-check-enabled:False*
*在设置 spark 集群时,您可能需要调整很多配置。你可以在[官方文件](https://spark.apache.org/docs/latest/configuration.html)里看看。*
# *3.分配*
**
*让员工处理等量的数据,让他们满意*
*如果在处理所有转换和连接时,您觉得数据有偏差,您可能需要对数据进行重新分区。最简单的方法是使用:*
df = df.repartition(1000)
*有时,您可能还希望按照已知的方案进行重新分区,因为该方案可能会在以后被某个连接或聚集操作使用。您可以使用多个列通过以下方式进行重新分区:*
df = df.repartition('cola', 'colb','colc','cold')
*您可以使用以下公式获得数据框中的分区数量:*
df.rdd.getNumPartitions()
*您还可以通过使用`glom`函数来检查分区中记录的分布。这有助于理解在处理各种转换时发生的数据偏差。*
df.glom().map(len).collect()
# *结论*
*有很多事情我们不知道,我们不知道。这些被称为未知的未知。只有通过多次代码失败和读取多个堆栈溢出线程,我们才明白我们需要什么。*
*在这里,我尝试总结了一些我在使用 Spark 时遇到的内存问题和配置问题,以及如何解决这些问题。Spark 中还有很多其他的配置选项,我没有介绍,但是我希望这篇文章能让你对如何设置和使用它们有所了解。*
*现在,如果你需要学习 Spark 基础知识,看看我以前的帖子:*
*[](/the-hitchhikers-guide-to-handle-big-data-using-spark-90b9be0fe89a) [## 使用 Spark 处理大数据的指南
### 不仅仅是介绍
towardsdatascience.com](/the-hitchhikers-guide-to-handle-big-data-using-spark-90b9be0fe89a)
还有,如果你想了解更多关于 Spark 和 Spark DataFrames 的知识,我想调出这些关于 [**大数据精要的优秀课程:Coursera 上的 HDFS、MapReduce 和 Spark RDD**](https://coursera.pxf.io/4exq73) 。
谢谢你的阅读。将来我也会写更多初学者友好的帖子。在 [**中**](https://medium.com/@rahul_agarwal?source=post_page---------------------------) 关注我或者订阅我的 [**博客**](http://eepurl.com/dbQnuX?source=post_page---------------------------) 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter[**@ mlwhiz**](https://twitter.com/MLWhiz?source=post_page---------------------------)联系
此外,一个小小的免责声明——这篇文章中可能会有一些相关资源的附属链接,因为分享知识从来都不是一个坏主意。*
# merge、join 和 concat 的实际使用
> 原文:<https://towardsdatascience.com/practical-uses-of-merge-join-and-concat-8f011bbac241?source=collection_archive---------64----------------------->
## 在 pandas 中组合数据框:使用哪些函数以及何时使用?

图片来自 [Pixabay](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=873818) 的[jenő·萨博](https://pixabay.com/users/szjeno09190-702158/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=873818)
## 介绍
在本文中,我们将讨论数据框的组合。您可能非常熟悉 pandas 中的 load 函数,它允许您访问数据以便进行一些分析。
但是,如果您的数据不在一个文件中,而是分散在多个文件中,会发生什么情况呢?在这种情况下,您需要逐个加载文件,并使用 pandas 函数将数据合并到一个数据框中。
我们将向您展示如何做到这一点,以及根据您想要如何组合数据以及想要实现的目标来使用哪些函数。我们将了解:
> concat(),
>
> merge(),
>
> 并加入()。
阅读完本文后,您应该能够使用这三种工具以不同的方式组合数据。
我们开始吧!
## concat()
如果您有多个具有相同列名的数据文件,我们建议使用这个函数。它可以是一家连锁供应商的销售额,每年都保存在一个单独的电子表格中。
为了说明这一点,我们将使用一些虚假数据创建两个独立的数据框。让我们从创建 2018 年销售数据框架开始:
import pandas as pd
import numpy as np
sales_dictionary_2018 = {'name': ['Michael', 'Ana'],
'revenue': ['1000', '2000'],
'number_of_itmes_sold': [5, 7]}sales_df_2018 = pd.DataFrame(sales_dictionary_2018)sales_df_2018.head()

这是一个非常简单的数据框,其中的列总结了 2018 年的销售额。我们有一个供应商名称、他们售出的数量以及他们创造的收入。
现在让我们创建一个数据框,它具有完全相同的列,但覆盖了一个新的时间段:2019 年。
sales_dictionary_2019 = {'name': ['Michael', 'Ana', 'George'],
'revenue': ['1000', '3000', '2000'],
'number_of_itmes_sold': [5, 8, 7]}sales_df_2019 = pd.DataFrame(sales_dictionary_2019)sales_df_2019.head()

你可以看到,2019 年,除了 2018 年销售部门的迈克尔和安娜之外,我们有了新的销售代表乔治。除此之外,数据结构与我们 2018 年的数据结构相同。
那么,如何将这两个数据框组合在一起,以便将它们放在一个数据框中呢?您可以使用 contact()函数:
pd.concat([sales_df_2018, sales_df_2019], ignore_index=True)

您可以看到,在此操作之后,我们所有的数据现在都在一个数据框中!
Concat()函数获取一列数据帧,并将它们的所有行相加,得到一个数据帧。我们在这里设置 *ignore_index=True* 否则,结果数据帧的索引将取自原始数据帧。就我们而言,我们不希望这样。请注意,您可以在列表表单中传递任意数量的数据框。
以我们介绍的方式添加数据可能是使用 concat()函数的最常见方式。您还可以使用 concat()函数通过设置 *axis=1* 来添加列,但是在列中添加新数据有更好的方法,比如 join()和 merge()。这是因为当添加新列时,通常需要指定一些条件来连接数据,而 concat()不允许这样做。
## 合并()
我们将从学习 merge()函数开始,因为这可能是根据一些常见条件向数据框添加新列的最常见方式。
为了说明 merge()的用法,我们将回到我们的商店示例,其中有 2018 年和 2019 年销售的数据框。
假设您有另一个文件,其中包含每个销售代表的个人数据。现在,您想将这些数据添加到销售数据框中。
让我们首先为个人代表信息创建一个数据框。
rep_info_dictionary = {'name': ['Ana', 'Michael', 'George'],
'location': ['New York', 'San Jose', 'New York']}rep_info_df = pd.DataFrame(rep_info_dictionary)rep_info_df.head()

如您所见,只有两列:名称和位置。这个名字也出现在我们的年度销售数据中。假设您希望将代表的位置添加到 2019 年的数据中。
您可以使用“名称”作为链接这两个数据框的列,将 rep_info_df 合并到 sales_df_2019:
sales_df_2019.merge(rep_info_df, on='name')

您可以看到,我们包含 2019 年销售数据的原始数据框现在有了另一列,位置。是合并 *rp_info_df* 和 *sales_df_2019* 的结果。
默认情况下,pandas merge 使用'*内部连接'*'来执行合并操作。我们不打算在这里讨论连接的类型,但是如果您熟悉 SQL 连接,它们的工作方式是完全一样的。
如果你不熟悉*内、左、右和外连接*的概念,我建议你找一些解释这些 SQL 概念的文章。一旦你理解了 SQL 连接,你将能够在 pandas merge()函数中使用它们,因为它们的工作方式完全相同。
## 加入()
这是合并的一种特殊情况,即您要联接的列中至少有一列是索引。让我们修改 2019 年的数据,将名称作为索引:
sales_df_2019.set_index('name', inplace=True)sales_df_2019.head()

正如你所看到的,*名称*不是一个列,而是我们对其使用 set_index()函数后的数据框的索引。
现在,让我们对代表信息数据框进行同样的操作:
rep_info_df.set_index('name', inplace=True)
rep_info_df.head()

现在 *rep_info_df* 和 *sales_df_2019* 都有名称作为索引。现在我可以使用 join()代替 merge()来组合数据,就像我们在上一节中使用 merge()一样。
sales_df_2019.join(rep_info_df)

如您所见,我不需要像 merge()那样在参数上指定*。这是因为 join()函数将数据框的索引作为默认值来组合两个表中的数据。*
通过指定 *how* 参数,可以修改类似于 merge()的 Join()函数以使用不同类型的 SQL 连接。默认的连接是一个*‘左’*连接,这就是我们在例子中使用的。
## 摘要
让我们总结一下我们的发现。
当我们试图添加多个具有相同结构的数据块并将它们一个接一个地放在一个数据帧中时,我们使用了 **concat()** 。
为了将列数据添加到现有条目中,我们使用了 **merge()。****数据是根据正在合并数据帧的列的相同值添加的。**
****Join()** 是 merge()的一个特例,至少有一个条目是索引。**
**我希望您喜欢这篇文章,并且已经学会了如何使用这些基本的数据框操作来组合数据。**
***最初发表于 about datablog . com:*[merge,join,concat 的实际用途](https://www.aboutdatablog.com/post/practical-uses-of-merge-join-and-concat),*2020 年 6 月 18 日。***
***PS:我正在 Medium 和*[***aboutdatablog.com***](https://www.aboutdatablog.com/)*上撰写深入浅出地解释基本数据科学概念的文章。你可以订阅我的* [***邮件列表***](https://medium.com/subscribe/@konkiewicz.m) *每次我写新文章都会收到通知。如果你还不是中等会员,你可以在这里加入*[](https://medium.com/@konkiewicz.m/membership)**。****
***下面还有一些你可能喜欢的帖子***
***[](/9-pandas-visualizations-techniques-for-effective-data-analysis-fc17feb651db) [## 9 熊猫有效数据分析的可视化技术
### 学习如何使用折线图、散点图、直方图、箱线图和其他一些可视化技术
towardsdatascience.com](/9-pandas-visualizations-techniques-for-effective-data-analysis-fc17feb651db) [](/what-are-lambda-functions-in-python-and-why-you-should-start-using-them-right-now-75ab85655dc6) [## python 中的 lambda 函数是什么,为什么你现在就应该开始使用它们
### 初学者在 python 和 pandas 中开始使用 lambda 函数的快速指南。
towardsdatascience.com](/what-are-lambda-functions-in-python-and-why-you-should-start-using-them-right-now-75ab85655dc6) [](/jupyter-notebook-autocompletion-f291008c66c) [## Jupyter 笔记本自动完成
### 数据科学家的最佳生产力工具,如果您还没有使用它,您应该使用它…
towardsdatascience.com](/jupyter-notebook-autocompletion-f291008c66c)***
# 练习 Python 理解
> 原文:<https://towardsdatascience.com/practice-with-python-comprehensions-af6f484a6e1e?source=collection_archive---------60----------------------->
## 用于数据准备和特征提取

在 [Unsplash](https://unsplash.com/s/photos/python?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 上由 [Hitesh Choudhary](https://unsplash.com/@hiteshchoudhary?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) 拍摄的照片
在这篇文章中,我们在数据准备和特征提取的各种例子上练习 Python 理解。我们希望让读者了解使用这种 Python 机制可以完成的各种任务。这篇文章也会引起数据科学新手的兴趣。
首先,我们先列举两个在数据科学建模中重复出现的核心数据模式。在数据准备和特征提取中。即使在机器学习算法中,尤其是对向量和矩阵进行操作的算法中。
图案是*聚合器*和*变压器*。两者都在 python 集合上操作。
一个聚合器从一个集合中计算一个标量,这个集合概括了它的某些方面。例子包括对列表中的值求和、查找列表中的最大值、查找列表的长度等。
转换器将一个集合映射到另一个集合。一个例子是将计数向量转换成概率向量。变换器模式在特征提取中是有用的。
虽然这些模式在概念上看起来很简单,但是用 Python 练习编码将帮助读者认识到何时应用它们,然后轻松地实现它们。
Python 理解在实现转换器时尤其有用。
让我们开始吧。首先,让我们做好准备。我们将关注三种类型的数据。
1. 一个特征向量。
2. 代表文本文件的一包单词。
3. 一种二进制图像的表示。
特征向量只是一个集合,它捕获了我们希望建模的一些固定属性的值。比方说我们要用三个特征来描述一个房子:*卧室数量*,*卫生间数量*,*面积*。我们可以将其建模为一个 python 列表,其元素是三个特性的值。因此[4,2,2000]代表一栋有四间卧室、两间浴室的房子,其面积为 2000 平方英尺。
文本文档的单词包表示捕获每个单词在其中出现的次数。在 python 中,用字典表示一袋单词很方便。这里有一个例子。
bag = { ‘the ’: 5, ‘art’ : 2, ‘of’ : 2, … }
我们将通过二维 python 列表来表示二进制图像。这里有一个例子。
image = [[1,1,1],[1,0,1],[1,1,1]]
**聚合器示例**
假设我们想从文档的包中知道文档的总字数。在 python 中,我们就是这样做的
sum(bag.values())
假设我们想计算图像中黑色像素的数量。在 python 中,我们会做
import numpy as np
np.sum(image)
我们使用 NumPy,因为它支持任意形状数组上的聚合器。我们的图像是二维的。
**变压器实例**
假设我们想要将文档的单词包表示转换为单词的概率分布。后者是长度规范化的,这一特性在某些用例中很有吸引力。在 python 中,我们会做
denom = sum(bag.values())
pbag = { word : float(count)/denom for word, count in bag.items() }
第二行使用了*字典理解*。
考虑我们的图像,想象它是灰度的。这只是意味着 image[i][j]是一个介于 0 和 1 之间的值,而不仅仅是它的极值。对于下游处理,我们可能希望将此图像转换为二进制图像。在 python 中,我们可以
def binarize(x):
if x >= 0.5:
return 1
else:
return 0binarized_image = [[binarize(pixel) for pixel in pixel_row] for pixel_row in image]
在最后一行,我们正在做的可能被称为*二维列表理解*。
**特征提取作为一种变换**
假设我们有一个输入向量数组。我们想把它转换成一组特征向量。
以我们的房子为例。有理由推测各个维度是相互关联的。也就是说,更大的房子会有更多的卧室、更多的浴室和更大的面积。我们可能对从这三个特征中派生出一个特征感到好奇。或许,它可以很好地区分大小房屋。
首先,让我们将我们的特征定义为输入向量中三个值的乘积。所以我们正在从三维空间向一维空间转变。(有时候,少可以多。)在 python 中,我们可以将输入向量数组转换为特征向量数组,如下所示。
feature_vectors = [x[0]x[1]x[2] for x in input_vectors]
一般来说,特征提取比我们在简单例子中看到的要复杂得多。我们可以将所有的复杂性抽象成一个函数`to_feature_vector(x)`,它将输入向量 x 作为一个参数。然后我们在理解中简单地使用这个函数
feature_vectors = [to_feature_vector(x) for x in input_vectors]
接下来,让我们看一个涉及缺失数据的例子
**特征向量的相似度(有缺失数据)**
假设我们有两个相同维数的数值向量 X 和 Y,并且缺少一些值。在 python 中,X 和 Y 可能是长度相同的列表,有些值是`None`。我们想要计算两个向量的相似性度量,考虑它们的缺失值。
下面我们将在忽略 X 或 Y 的值为 None 的维度后计算所谓的点积。
def dp(x,y):
return sum([x[i]*y[i] for i in range(len(x)) if x[i] and y[i]])
让我们看一个数字例子。让我们看看我们的房屋示例中的三个特征向量:
X = [4,2,2000]
Y = [4,None,1800]
Z = [None,1,500]
dp(X,Y)和 dp(X,Z)分别是 3600016 和 1000002。这表明 X 和 Y 比 X 和 z 更相似。这有直观的意义。
也就是说,如果输入向量没有被适当地归一化,dp 会给出非常误导的结果。这是因为矢量的分量处于不同的尺度。在我们的例子中,卧室的数量和浴室的数量通常在 0 到 6 之间,而面积可能在 100 到 1000 之间。
**规格化一个数字特征的列**
以我们的房子为例。正如上一段所讨论的,平方英尺与前两个(卧室的数量,浴室的数量)有很大的不同。让我们看一个这种规模差异导致的问题的例子。
认为
X = [4,2,2000]
Y = [1,0,2000]
Z = [4,2,1800]
dp(X,Y),dp(X,Z),dp(Y,Z)分别约为 400K,360K,360K。x 和 Z 像 Y 和 Z 一样相似没有意义。
好了,正常化吧!这种规范化将对要素列进行操作,每个要素一列。我们将特征列中的值除以该列的 L2 范数。什么是 L2 规范?您在下面包含`denom`的行的 rhs 上看到的内容。
import math
def normalize(fc):
denom = math.sqrt(sum([v**2 for v in fc]))
return [v/denom for v in fc]
`normalize(fc)`输入一个特征列,并将其标准化。
接下来,让我们准备三个特性列,以便可以使用 normalize(fc)。
fcs = [[xyz[i] for xyz in [X,Y,Z]] for i in range(3)]
我们看到 fcs 等于
[[4, 1, 4], [2, 0, 2], [2000, 2000, 1800]]
所以 fcs[i]是特性 I 的值列表。
好了,现在让我们正常化
nfcs = [normalize(fc) for fc in fcs]
让我们看看 NFC。
[
[0.6963106238227914, 0.17407765595569785, 0.6963106238227914], [0.7071067811865475, 0.0, 0.7071067811865475],
[0.5965499862718936, 0.5965499862718936, 0.5368949876447042]
]
这三栋房子的标准平方英尺大致相同。第二所房子的卧室和浴室的标准数量远远低于第一所和第三所房子。理应如此。
下一步是在标准化的特征向量上使用 dp。为此,我们首先需要将规范化的特征列转换成规范化的特征向量。
XYZ = list(zip(nfcs[0],nfcs[1],nfcs[2])
X,Y,Z = [list(XYZ[i]) for i in range(3)]
x、Y 和 Z 现在是三个房屋的特征向量的归一化版本。
X = [0.6963106238227914, 0.7071067811865475, 0.5965499862718936]
Y = [0.17407765595569785, 0.0, 0.5965499862718936]
Z = [0.6963106238227914, 0.7071067811865475, 0.5368949876447042]
我们看到 dp(X,Y),dp(X,Z),dp(Y,Z)分别是 0.477,1.30,0.44。好多了。X 和 Z 比 Y 和 Z(或者 Y 和 X)更相似。
**结论**
在这篇文章中,我们用简单的例子讨论了在数据表示、准备和特征提取中反复出现的一些核心问题。我们讨论了涉及数字特征向量的例子,以及如何归一化它们,考虑丢失的数据。我们还介绍了单词示例和二进制图像操作。
所有这些例子的共同点是我们使用了 Python 理解。从中得出的信息是,在 Python 中学习和实践这一机制在数据科学环境中非常有帮助。
# 你必须知道的预提交钩子
> 原文:<https://towardsdatascience.com/pre-commit-hooks-you-must-know-ff247f5feb7e?source=collection_archive---------2----------------------->
## 在 5 分钟内提高您的生产力和代码质量

图片作者:马丁·托马斯
预提交钩子是版本控制系统 git 的一种机制。他们让你在提交之前执行代码。令人困惑的是,还有一个叫做`pre-commit`的 Python 包,它允许你用一种更简单的接口创建和使用预提交钩子。Python 包有一个插件系统来自动创建 git 预提交钩子。它不仅适用于 Python 项目,也适用于任何项目。
看完这篇文章,你就知道我最喜欢的专业软件开发插件了。我们开始吧!
# 提交前基础知识
通过以下方式安装预提交
pip install pre-commit
在您的项目中创建一个`.pre-commit-config.yaml`文件。这个文件包含每次提交前要运行的预提交钩子。看起来是这样的:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:- id: trailing-whitespace
- id: mixed-line-ending- repo: https://github.com/psf/black
rev: 20.8b1
hooks: - id: black
`pre-commit`将在这两个带有指定 git 标签的存储库中查找名为`.pre-commit-hooks.yaml`的文件。在这个文件中可以任意定义许多钩子。它们都需要一个`id`,这样你就可以选择你想用的。上面的 git-commit 配置将使用 3 个钩子。
最后,您需要运行`pre-commit install`来告诉预提交总是为这个存储库运行。
在我使用它之前,我担心会失控。我想确切地知道我提交了哪些更改。如果它改变了什么,将中止提交。所以你还是可以看一下代码,检查一下改动是否合理。您也可以选择不运行预提交,方法是
git commit --no-verify

图片由 CC-BY-3.0 下的 [geek-and-poke](http://geek-and-poke.com/geekandpoke/2010/11/1/how-to-make-a-good-code-review.html) 提供
# 文件格式
以类似的方式格式化文件通过提高一致性来帮助可读性,并保持 git 提交的整洁。例如,您通常不想要尾随空格。您希望文本文件恰好以一个换行符结尾,这样一些 Linux 命令行工具就能正常工作。您希望 Linux ( `\n`)、Mac ( `\r` — [Mac 之间的换行符一致,将](https://superuser.com/questions/439440/did-mac-os-lion-switch-to-using-line-feeds-lf-n-for-line-breaks-instead-of#:~:text=Nowadays%20Mac%20OS%20uses%20Unix%20style%20(LF)%20line%20breaks.&text=Command%2Dline%20tools%20in%20Mac,Mac%2Dstyle%E2%80%9D%20line%20endings.)改为`\n`🎉)和 windows ( `\r\n`)。我的配置是
pre-commit run --all-files
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:- id: check-byte-order-marker # Forbid UTF-8 byte-order markers
Check for files with names that would conflict on a case-insensitive
filesystem like MacOS HFS+ or Windows FAT.
- id: check-case-conflict
- id: check-json
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace
- id: mixed-line-ending

由马丁·托马斯通过 imgflip.com[创建](https://imgflip.com/i/4dqpwf)
# 代码风格
我们可以用很多不同的方式编写代码。它们中的许多在运行时几乎没有区别,但在可读性方面有所不同。
## 代码自动格式器

当你的代码看起来丑陋的时候,不要浪费时间学习风格指南和手工应用它。运行代码格式化程序。图片由兰道尔·门罗( [XKCD](https://xkcd.com/1513/) )拍摄
自动代码格式化与文件格式化具有相同的优点。此外,它还能防止无意义的讨论。因此,它让你和你的团队专注于重要和复杂的部分。
我喜欢 Pythons 自动格式化程序 black,在关于静态代码分析的文章中已经提到过:
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:- id: black
- repo: https://github.com/asottile/blacken-docs
rev: v1.8.0
hooks:- id: blacken-docs
additional_dependencies: [black==20.8b1]
- id: blacken-docs
第一个是 black 本身,第二个是一个将黑色格式应用于 docstrings 中的代码字符串的项目。
此外,我希望我的导入被排序:
- repo: https://github.com/asottile/seed-isort-config
rev: v2.2.0
hooks:- id: seed-isort-config
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.4.2
hooks:- id: isort
许多语言都有带预提交挂钩的自动套用格式器:
* [更漂亮的](https://prettier.io/docs/en/precommit.html#option-3-pre-commithttpsgithubcompre-commitpre-commit) : HTML、CSS、JavaScript、GraphQL 等等。
* [Clang-format](https://github.com/andrewseidl/githook-clang-format) : C,C++,Java,JavaScript,Objective-C,Protobuf,C#
* [生锈:生锈](https://github.com/doublify/pre-commit-rust)
## 现代 Python
[pyupgrade](https://github.com/asottile/pyupgrade) 运行您的 Python 代码,并自动将旧式语法更改为新式语法。请看一些例子:
dict([(a, b) for a, b in y]) # -> {a: b for a, b in y}
class C(object): pass # -> class C: pass
from mock import patch # -> from unittest.mock import patch
你想要吗?给你:
- repo: https://github.com/asottile/pyupgrade
rev: v2.7.2
hooks:- id: pyupgrade
args: [--py36-plus]
- id: pyupgrade
# 测试您的代码
我考虑过通过预提交自动运行单元测试。我决定不这样做,因为这可能需要一段时间。但是,有一些快速测试可以每次自动运行:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:- id: check-ast # Is it valid Python?
Check for debugger imports and py37+ breakpoint() calls
in python source.
- id: debug-statements- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.782
hooks: - id: mypy
args: [--ignore-missing-imports]- repo: https://gitlab.com/pycqa/flake8
rev: '3.8.3'
hooks: - id: flake8
# 安全性
签入凭证是一个非常常见的错误。以下是防止这种情况的方法:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:- id: detect-aws-credentials
- id: detect-private-key
# 杂项提交前挂钩
有些挂钩不属于上述类别,但仍然有用。例如,这可以防止提交大文件:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:- id: check-added-large-files
# 在团队中工作
预提交挂钩安装在本地,因此每个开发人员都可以自己决定是否需要预提交挂钩以及需要哪些挂钩。但是,我认为提供一个`.pre-commit-config.yaml`有你推荐执行的插件是有帮助的。
# 所有的钩子!
如果您正在寻找一个现成的完整的`.pre-commit-config.yaml`,这里就是:
Apply to all files without commiting:
pre-commit run --all-files
Update this file:
pre-commit autoupdate
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:- id: check-ast
- id: check-byte-order-marker
- id: check-case-conflict
- id: check-docstring-first
- id: check-executables-have-shebangs
- id: check-json
- id: check-yaml
- id: debug-statements
- id: detect-aws-credentials
- id: detect-private-key
- id: end-of-file-fixer
- id: trailing-whitespace
- id: mixed-line-ending
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.782
hooks:- id: mypy
args: [--ignore-missing-imports]
- id: mypy
- repo: https://github.com/asottile/seed-isort-config
rev: v2.2.0
hooks:- id: seed-isort-config
- repo: https://github.com/pre-commit/mirrors-isort
rev: v5.4.2
hooks:- id: isort
- repo: https://github.com/psf/black
rev: 20.8b1
hooks:- id: black
- repo: https://github.com/asottile/pyupgrade
rev: v2.7.2
hooks:- id: pyupgrade
args: [--py36-plus]
- id: pyupgrade
- repo: https://github.com/asottile/blacken-docs
rev: v1.8.0
hooks:- id: blacken-docs
additional_dependencies: [black==20.8b1]
- id: blacken-docs
# 摘要
我喜欢预提交,因为它非常适合我的工作流程。我只是像往常一样提交,预提交会做我有时会忘记的所有检查。它加快了开发速度,因为 CI/CD 管道比在本地执行同样的步骤要慢得多。特别是对林挺来说,快速运行代码而不是提交,等待 CI/CD 管道,找到错误,在本地修复错误,推送,然后再次等待 CI/CD 管道,可以节省大量时间。
如果有你喜欢的其他预提交挂钩,请通过评论或电子邮件(info@martin-thoma.de)告诉我!
# 选举前情绪分析
> 原文:<https://towardsdatascience.com/pre-elections-sentiment-analysis-880bc5ad1db0?source=collection_archive---------62----------------------->
## 单词云和条形图中的新加坡#GE2020SG

由 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上的 [Swapnil Bapat](https://unsplash.com/@deadlyvyper?utm_source=medium&utm_medium=referral) 拍摄的照片
我们是两个对数据科学充满热情的新加坡本科生。
随着即将到来的新加坡大选的临近,我们决定借此机会利用我们的数据科学技能在这一领域进行分析,截至 2020 年 6 月 28 日。**这绝不是为了影响选举,也不暗示任何人或任何党派。这只是一些好的、干净的、数据科学的乐趣。**
# 介绍
**我们试图调查的问题陈述有:**
1. 各政党的公众情绪分布如何?
2. 与公众情绪相比,报纸上表达的情绪有统计学上的显著差异吗?

堆积条形图显示了对 Twitter 上各方的不同看法
我们使用 Twitter 情绪分析作为量化公众情绪的方法,并在《海峡时报》上进行了单独的情绪分析。此外,我们可以比较双方在两个平台上的情绪。
通过我们的工作,我们能够看到对每一方的正面和负面情绪的明显差异,尽管这在 0.05α值时在统计上是不显著的。
在α值为 0.05 时,我们发现总体主观性和对 PAP 的主观性之间存在统计学显著差异。
# 方法学
使用 python:
1. 我们针对 Twitter 和《海峡时报》进行了一系列的网络清理。
2. 使用 *Textblob 库*对每个平台进行**情感分析**
3. **通过 *matplotlib* 和 *wordclouds* 将结果**可视化。
4. 进行了一个简单的**假设检验**来评估主观性和极性的差异。
**假设&限制**
1. 情感分析是通过 *TextBlob* 完成的,它使用自己的标准来确定积极、消极和中性的词语。这些标准可能并不代表实际使用的单词,也没有考虑到讽刺、音调和单词使用的上下文,因此可能会出现单词分类错误的情况。
2. 由于某个主题可能有大量的标签,我们假设每个想要发布某个主题(例如 PAP)的人都会使用相同的标签(" #PAPSingapore ")。
3. Twitter 被选为删除我们数据的平台之一,因为我们认为这是一个社区中任何人都可以发表评论、发表观点的免费平台,而海峡时报被选为另一个平台,因为我们认为它是通用电气相关新闻的官方渠道。
4. 一些新加坡政党在 Twitter 和《海峡时报》上的影响力相对较小,因此在本研究中不予考虑。
5. 一个很大的限制是,这项研究采用了 6 月 26 日至 6 月 29 日的数据,这不是完整的“选举前”时间长度。

在 [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral) 上由 [Dane Deaner](https://unsplash.com/@danedeaner?utm_source=medium&utm_medium=referral) 拍摄的照片
# **刮削过程**
## ***推特***
使用#PAP、#wpsg、#ProgressSgParty、#GE2020SG 这四个标签,包含每个标签的推文可以很容易地使用 *twitterscraper* 库抓取并整理到一个 *csv* 文件中。
## ***海峡时报***
通过使用*请求*库,《海峡时报》被反复废弃。与“政治”相关的网址根据它们所属的党派被贴上标签,并被编译成 csv 格式。这些政党是 WP,PSP,PAP,我们将性别作为一般新闻文章,包含了大选的行政信息。
# **刮削结果**
# ***1。word cloud***
我们能够为 Twitter 和海峡时报生成*文字云*,如下所示。*单词云*用于可视化最常见的相关单词,分别对应标签(Twitter)和过滤器(海峡时报)。
***1.1。推特***
我们可以看到,它们有相似的常用词,如“新加坡”和“GE2020”,而在其他“较小”的词上有所不同。

Twitter wordcloud
***1.2 海峡时报***
我们可以观察到与 twitter wordcloud 类似的结果,如下所示。

海峡时报词汇云
# **2。极性与主观性**
极性指的是情绪化的、判断性的词语出现的频率更高。
主观性指的是更倾向于一种观点,而不是事实信息。
我们将这些指标可视化,y 轴表示主观性,x 轴表示极性。这些已绘制在下面的散点图中。
## **2.1*。极性 vs 主观性(推特)***

***【极性 vs 主观性(推特)***
## **2.2*。极性 vs 主观性(海峡时报)***

***【极性 vs 主观性(海峡时报)***
## **2.3。*推特和《海峡时报》的对比***
我们在这里使用了*双样本 t 检验*来确定是否有足够的证据来拒绝零假设。我们的无效假设是不同媒介的情感是相同的,相反,另一个假设是不同媒介的情感是不同的。
## **假设检验(主观性和极性)**

主观性和极性双样本 t 检验结果
当 alpha 值为 0.05 时,我们发现当来自 Twitter 的观点与来自海峡时报的观点相比较时,在 *General* 和 *PAP* 中的**主观性**之间存在**统计显著差异**。
这表明,关于*一般*和 *PAP,两个来源之间的信息的主观性存在显著差异。*
通过参考 *#GE2020SG* vs *GEN,*的散点图,我们确实可以看到 *#GE2020SG* 中的主观推文数量明显多于《海峡时报》( *GEN)。*
从*# PAP Singapore*vs*PAP*散点图*的对比也可以看出这个趋势。*我们可以看到,与 Twitter 相比,《海峡时报》的主观信息数量要多得多。
# **3。情绪点分析**
在生成每方每种媒体各自的情绪后,我们将这些指标在堆积条形图上进行比较,如下所示。然后,我们进行了*双样本 t 检验*,类似于上面的主观性和极性。
## **3.1 推特**

堆积条形图显示了对 Twitter 上各方的不同看法
使用以下积极和消极情绪的数字,我们能够生成上面的条形图。

用于生成上述堆积条形图的情感点数
**观察结果**
1)只有 4.0%带有#PAPSingapore 标签的推文是负面的,比#GE2020SG 的平均 18.3%低 14.3%
2)标签为#ProgressSgParty 的推文有 50%是正面的,这表明正面评价比平均水平高 12.5%
## **3.2 海峡时报**

堆积条形图显示了对 Twitter 上各方的不同看法
## *观察结果*
1)《海峡时报》上关于葛的文章大多是以非常正面的方式写的,没有太多负面或中性的词语。
## **3.3 *推特和海峡时报*的对比**
**假设检验(感性分析)**

情感分析双样本 t 检验结果
当 alpha 值为 0.05 时,我们发现 Twitter 和《海峡时报》的观点没有显著差异。有趣的是,所有缔约方都是如此。
# **4。结论**
回到最初的问题陈述:
> **公众情绪在各个党派中的分布情况如何?**
由于《海峡时报》的情绪分析似乎在各方中相当平均,我们决定 Twitter 情绪分析(如下)能够最好地回答这个问题。请参考下面的堆积条形图。

新加坡政党间的情感分布
> **报纸和公众的情绪有统计学上的显著差异吗?**
在 alpha 值为 0.05 时,我们发现一般信息和 PAP 在这两种媒介之间的主观性存在**统计上的显著差异。**除此之外,其余政党的媒介在主观性和极性方面没有显著差异。也许这些政党的支持者在某种程度上更加“热情”地支持他们。
此外,我们发现,在两种媒体上,各方的情绪在统计上没有显著差异。这可能是因为每个政党的支持者似乎都使用 Twitter,并以类似的语气为《海峡时报》撰稿。
# 5.未来的改进
对于未来的研究,我们肯定会建议对整个选举前时期进行研究;这项研究是在 6 月 26 日至 6 月 29 日进行的,也许 6 月 26 日至 7 月 10 日会随着时间的推移揭示一些更深刻的见解。
我们还建议进一步深入了解脸书和 Instagram 等替代社交媒体平台。
# 感谢你的阅读!
为了给数据科学从业者提供免费的开源信息,请在这里找到代码!
如果您对这个项目有任何疑问,请随时通过 Linkedin[或 Linkedin](https://www.linkedin.com/in/feng-wei-wan-44336b180/)或 Linkedin[联系我们,我们希望能友好地讨论!](https://www.linkedin.com/in/dehan-c-948045177/)
我们希望我们能够以某种方式帮助您使用数据科学方法!
[](https://www.linkedin.com/in/feng-wei-wan-44336b180/) [## 冯伟万-数据分析实习生- Aon | LinkedIn
### 我是倒数第二名本科生,正在攻读会计和商业双学士学位(专业是…
www.linkedin.com](https://www.linkedin.com/in/feng-wei-wan-44336b180/) [](https://www.linkedin.com/in/dehan-c-948045177/) [## 韩德-大数据实习生-雷蛇公司| LinkedIn
### 我是 SMU 的倒数第二名学生,读经济学(数量轨道),第二专业是数据科学…
www.linkedin.com](https://www.linkedin.com/in/dehan-c-948045177/)
# 这里还有一篇文章给你!
[](/predicting-energy-production-d18fabd60f4f) [## 预测能源产量
### 使用深度学习神经网络模型
towardsdatascience.com](/predicting-energy-production-d18fabd60f4f)
# 浓缩咖啡的预浸泡:更好的浓缩咖啡的视觉提示
> 原文:<https://towardsdatascience.com/pre-infusion-for-espresso-visual-cues-for-better-espresso-c23b2542152e?source=collection_archive---------11----------------------->
## 根据预输注时间覆盖过滤器,而不是恒定时间
当用手动机器拉球时,我发现预输注是必要的,但是预输注应该持续多长时间?几年来,我用 10 秒,在过去的几个月里,我把它提高到接近 30 秒。这改善了味道和提取,但仍有一些可变性。大部分参数相同的两次注射有不同的提取,一旦我开始用一个额外的参数跟踪预输注,我发现了一种确定适当预输注量的方法。该度量是覆盖过滤器(TCF)的时间。

在这种情况下,TCF 是 13 岁
当我踏上浓缩咖啡之路时,我没有意识到并非所有的机器都生而平等。我碰巧发现了一台便宜的手动浓缩咖啡机(Kim Express),但这台机器比一般的浓缩咖啡机需要更多的关注。从手动机器中抓拍看起来像是一门艺术,但随着时间的推移,我已经能够看到这种努力中的科学。在手动机器上造成差异的一个变量是预注入,更昂贵的热泵机器也允许预注入。
人们一直在争论预注入的必要性,但通常对于手动杠杆式机器来说,预注入是必要的,因为水从圆筒的侧面进入腔室。预浸泡是让水以 1 到 2 巴的低压进入咖啡罐,这对于开水器来说是典型的。一段时间后,你拉下杠杆,提取咖啡。
# 初始预输注程序
当我开始收集浓缩咖啡的数据时,我没有收集太多与时间相关的数据。通常,我会做 10 秒钟的预注入,推动直到过滤器被覆盖,让它开花 5 秒钟,然后提取,无论需要多长时间。
我在脑子里算了一下预输液和开花,什么都没记录。一旦我开始录像我所有的镜头来回放,我就开始更明确地跟踪这些时间。大约在那个时候,我也停止了绽放,只专注于预输注。我不记得为什么,但我想这是因为当我开始提取时,我的预输注已经延伸到过滤器已经被覆盖的地方,所以开花似乎无关紧要。
我想我发现了一些关于开花的东西。我不是第一个做 bloom 的人,但我认为它没有被很好地研究过,也没有作为浓缩咖啡的标准做法。然而,开花迫使咖啡从过滤器的大部分出来,确保冰球是饱和的。
# 该盖上过滤器了(TCF)
直到我开始进行更长时间的预注射,我才开始跟踪 TCF。我有更多的时间进行实验,我注意到稍长一点会导致提取量增加。所以我就顺其自然了。我甚至尝试了整个注射作为预灌注,但它缺少一些东西。根据咖啡出来的速度,我到达了 20 到 40 岁的范围。

我有每个镜头的视频,我开始注意到有些镜头比其他镜头更快地覆盖了滤镜,所以我开始跟踪这个变量。此外,我开始注意到这里和那里的镜头覆盖过滤器越快出来越好。我开始考虑将预输注的时间长短与 TCF 联系起来。
# 达到 10 毫升的时间(T10)
另一个度量是输出量或重量,其可以用作应该结束预输注的指示器。我检查了一组较小的数据来收集 10 毫升(T10)的时间,因为我用作子弹杯的量杯上有 10 毫升的标记。虽然这种测量不像秤那样精确,但它是查看预输注的另一种方式。如果我有使用秤的数据,我会使用该数据(即,我不喜欢体积测量,但可以免费获得)。
我目前的建议是在 TCF 或 T10 后的一定时间结束预输注。我希望在决定什么是确定适当指标的最佳方式时,能够以数据为导向。所以我收集了一些数据。
使用我为每个镜头收集的视频,我找到了视频中我可以看到咖啡从每个过滤孔流出的时间,以记录为 TCF,然后我寻找杯子上达到 10 毫升的线,以记录为 T10。

# 绩效指标
我使用了两个指标来评估过滤器之间的差异:[最终得分](https://link.medium.com/uzbzVt7Db7)和[咖啡萃取](https://link.medium.com/EhlakB9Db7)。
最终得分是 7 个指标(强烈、浓郁、糖浆、甜味、酸味、苦味和余味)记分卡的平均值。当然,这些分数是主观的,但它们符合我的口味,帮助我提高了我的拍摄水平。分数有一些变化。我的目标是保持每个指标的一致性,但有时粒度很难,会影响最终得分。
使用折射仪测量总溶解固体(TDS ),该数字与一杯咖啡的输出重量和输入重量相结合,用于确定提取到杯中的咖啡的百分比,称为提取率(EY)。
# 数据
在拍摄的时候,我有大约 60 个 TCF 的镜头,但我有其余的视频。所以我回去注释了 392 张照片的数据。这些数据跨越了烤肉、机器、新技术,比如辣味研磨和断续捣实。也许他们会讲一个故事。
从这个初始数据集来看,与预灌输(PI)有一些相关性,但对于 TCF 本身,EY 或味道(最终得分)似乎没有太大的趋势。然而,当观察圆周率- TCF 时,这一趋势变得更加明显。这个度量实际上是圆盘完全湿润时 PI 持续发生的时间。

## 聚焦数据集
为了查看 T10,我想将数据集缩小一些,因为为 TCF 做标注非常耗时。另一个问题是,在 6 个多月的时间里,我做的技术发生了很多变化。在那段时间里,我研究了在研磨之前加热咖啡豆,在酿造之前冷却咖啡渣,夯实压力,以及圆盘分层(即断续夯实)。
这个更小的集合有 62 个样本,变化的变量更少。这是我收集的数据的一部分,用来比较两个过滤篮,这也是我开始关注 TCF 的原因。
EY 和 taste(最终得分)的数据趋势更加清晰:
* PI 越长,拍摄效果越好,但由于定时 PI 的原因,数据中没有粒度。
* 对于 TCF,趋势线的 R^2 为 0.69,这意味着绘制的趋势线相当不错。
* π-TCF 的度量也很强。
* 与 TCF 相比,T10 的趋势较弱,但它仍然是一个变量,我将继续收集数据。
* TCF/圆周率似乎是良好业绩的最强指标。

然后我做了几个变量的相关矩阵。相关性并不意味着因果关系,但它让我们更清楚地知道如何找到根本原因,在这种情况下,如何更好地利用圆周率。相关性衡量两个变量的相互趋势:
* 更接近 1 意味着两个变量彼此成比例。
* 更接近-1 意味着这两个变量彼此成反比。
* 更接近 0 意味着这两个变量彼此没有关系。
* 相关矩阵是沿对角线的一面镜子。

仅关注最终得分(口味),EY、TCF 和皮- TCF 与 EY 的相关性较好,最终得分略低。另一个有趣的变量是 TCF/π或π中滤波器未覆盖的部分。

当观察总提取时间的比例时,PI/总时间之间没有相关性,但是 TCF/总时间和(PI-TCF)/总时间之间有相关性。这两个指标非常简单,易于衡量。

走进那个兔子洞,看看 TCF/圆周率给出了一个比 TCF/总时间稍微好一点的度量,在拍摄过程中也更容易调整和控制。这允许你扩展圆周率,直到你达到某个比率。

为了获得更多可操作的数据,我们需要看看 PI/TCF。由此,一个好的比例是 3 比 1,所以圆周率需要是 TCF 长度的 3 倍。

总的来说,这个分析让我知道了下一步该怎么走。在过去的六个月里,我的 PI 例行程序是通过达到某个时间数字来驱动的,而不是达到与圆盘饱和度更相关的东西。展望未来,我打算以 TCF 为基础做事:
1. TCF 衡量成功
2. 当它是 TCF 长度的 3 倍时,结束预灌注(PI ),但是这将在太多环形通道的情况下变化。
我的希望是,通过使预输注时间可变,我将能够为预 I 融合的优化公式做进一步的分析。
如果你愿意,可以在 Twitter 和 YouTube 上关注我,我会在那里发布不同机器上的浓缩咖啡视频和浓缩咖啡相关的东西。你也可以在 [LinkedIn](https://www.linkedin.com/in/robert-mckeon-aloe-01581595?source=post_page---------------------------) 上找到我。
# 我的进一步阅读:
[咖啡的形状](/the-shape-of-coffee-fa87d3a67752)
[搅拌还是旋转:更好的浓缩咖啡体验](https://towardsdatascience.com/p/8cf623ea27ef)
[香辣浓缩咖啡:热磨,冷捣以获得更好的咖啡](/spicy-espresso-grind-hot-tamp-cold-36bb547211ef)
[断续浓缩咖啡:提升浓缩咖啡](https://towardsdatascience.com/overthinking-life/staccato-espresso-leveling-up-espresso-70b68144f94)
[用纸质过滤器改进浓缩咖啡](/the-impact-of-paper-filters-on-espresso-cfaf6e047456)
[浓缩咖啡中咖啡溶解度的初步研究](/coffee-solubility-in-espresso-an-initial-study-88f78a432e2c)
[断奏捣固:不用筛子改进浓缩咖啡](/staccato-tamping-improving-espresso-without-a-sifter-b22de5db28f6)
浓缩咖啡模拟:计算机模型的第一步
[更好的浓缩咖啡压力脉动](/pressure-pulsing-for-better-espresso-62f09362211d)
[咖啡数据表](https://link.medium.com/AF6V2y5MT7)
[工匠咖啡价格过高](https://towardsdatascience.com/overthinking-life/artisan-coffee-is-overpriced-81410a429aaa)
被盗浓缩咖啡机的故事
[浓缩咖啡过滤器分析](/espresso-filters-an-analysis-7672899ce4c0)
[便携式浓缩咖啡:指南](https://towardsdatascience.com/overthinking-life/portable-espresso-a-guide-5fb32185621)
克鲁夫筛:一项分析
# 预处理和训练数据
> 原文:<https://towardsdatascience.com/pre-processing-and-training-data-d16cc12dfbac?source=collection_archive---------22----------------------->
## 转变数据和训练模型以获得最佳性能是一个整体过程。

图片由[皮克斯拜](https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=3706562)的 Gerd Altmann 提供
# 预处理
那么,什么是预处理呢?常见的例子包括
* 输入缺失值
* 转换数值(线性或非线性)
* 编码分类变量
## 输入缺失值
你的数据中经常有漏洞。有人没有回答调查问题。传感器故障。数据丢失了。价值缺失及其原因多种多样。缺少的值可以用一个特殊的“值”NaN(在 Python 中,来自 NumPy)或 NA(在 R 中)来表示。但是思念并不总是由这些特殊的标记来表示。负值表示缺少数据,例如-999 表示某人的年龄。这可能取决于原始系统或软件,以及在您收到数据之前数据是如何处理的。在您的上下文中,空字符串可能被归类为“丢失”,也可能不被归类为“丢失”。
你现在应该已经解决的一个重要问题是,在丢失的数据中是否有任何模式。您在之前的 EDA 阶段确实探索过这一点,对吗?这些河流水位传感器读数丢失是因为站点被淹没吗?或者,丢失的值是随机散布在数据中的,暗示着一些更无害的原因,比如间歇性的无线电干扰?如果是前者,那么我希望您已经添加了一个新特性来捕获值丢失的事实。无论如何,大多数机器学习算法不喜欢丢失值,所以你需要采取措施,比如,坦白地说,猜测值可能是多少。这是归罪。
有许多输入缺失值的方案。您可以使用剩余值的平均值。或者中间值。或者取最后一个已知值。是的,选择最佳策略需要反复试验。
## 转变价值观
有几个原因需要转换要素的值。您可能有高度偏斜的分布,而非线性变换可以使这些分布正常化,这有助于许多算法。您可能有一组以非常不同的比例测量的要素,例如以英尺为单位的土地高程和以英亩为单位的面积。或者以磅为单位的体重和以华氏度为单位的体温,与以千克为单位的体重和以摄氏度为单位的体温。事实上,这些单位并没有太大的不同,但是这让我们有了另一个理由去转换特性值;计算点与点之间距离的算法和正则化(惩罚)它们的系数的算法可以任意产生非常不同的结果,因为这种单位上的差异。缩放要素将所有要素置于同等地位。
## 编码分类变量
像数字这样的算法。他们对字符串(文本)不太感兴趣。可以说,大部分数据科学都是寻求将数据转换成机器学习算法可以处理的适当数字表示。与其让名为“Animal”的列具有“Cat”或“Dog”的值,不如创建一个“Cat”列,用值 0 或 1 表示“not a cat”或“is a cat”,用值 0 或 1 表示“not a dog”或“is a dog”。即使这种相对简单的方案也有一些微妙之处,比如需要为包含截距的线性回归等模型删除其中一列。这是为了避免[虚拟变量陷阱](https://www.algosome.com/articles/dummy-variable-trap-regression.html)。
# 列车测试分离
如果在训练机器学习模型之前有这么多可能的决定要做,我们如何决定使用哪个?我们可以使我们的预处理和模型变得越来越复杂,以适应数据中越来越多的任意结构。我们如何知道我们的预处理决策是正确的,而不仅仅是适应数据中的噪声?这就是所谓的过度拟合。评估一个模型是否过度拟合它所知道的数据的基础是,在训练它时不要给它所有的数据,保留一些数据,然后观察它的表现。
一个巧妙的变化是将训练数据进一步分割成多个部分,除了一个部分之外,对所有部分进行训练,并对剩下的部分进行测试。通过旋转这样保留的分区,我们最终得到了对一个验证集的许多性能估计(其中验证集每次都是不同的)。这是交叉验证,在执行模型选择时特别有用。当然,我们仍然可以保留一组数据,以确保我们有一些我们的模型从未见过的数据。在对多个模型进行测试的多个交叉验证回合之后,这样的最终测试集是对预期未来性能的有用的最终检查。
# 韵律学
但是我们如何衡量绩效呢?有许多可能的度量或指标,最合适的一个取决于用例。如果我们正在执行分类,例如“猫”或“狗”,那么一个能捕捉我们得到正确答案的次数与我们得到错误答案的次数的指标是合适的。但如果我们在做回归,我们试图预测一个连续变量,如某人的工资,或房价,那么反映我们倾向于接近真实值的平均水平的度量是最好的。这里一个常见的度量是平均绝对误差,顾名思义,它是误差大小的平均值。
# 齐心协力
现在我们实际上已经有了所有需要的材料。对于我们特定类型的机器学习问题,我们可以选择一个度量标准。有了度量标准,我们就可以衡量成功(或失败)的程度。拥有一个训练测试分割给了我们一种方法,可以将这个度量应用到算法不知道的数据分区。这些共同允许我们尝试许多不同类型的模型和预处理步骤,并评估哪一个执行得最好。
嘿,很快!如果您已经尝试了各种预处理步骤和算法,并且应用了适当的度量标准,并且根据测试集评估了您的整个过程(例如,通过交叉验证),那么您已经获得了一个训练好的模型。具体来说,您已经建立了预处理步骤和算法性质的组合。
# 关于这篇文章
这是一个链接系列的第五篇文章,旨在简单介绍如何开始数据科学过程。你可以在这里找到简介[,在这里](https://medium.com/@guymaskall/the-data-science-method-dsm-35200eb4984)找到上一篇文章[,在这里](https://medium.com/@guymaskall/exploratory-data-analysis-86eb12060eac)找到系列文章[。](https://medium.com/@guymaskall/modelling-e096495d8d70)
# 使用预先训练的单词嵌入来检测真实的灾难推文
> 原文:<https://towardsdatascience.com/pre-trained-word-embedding-for-text-classification-end2end-approach-5fbf5cd8aead?source=collection_archive---------8----------------------->
## 端-2-端方法

[https://unsplash.com/](https://unsplash.com/)
在这篇文章中,我们将经历整个文本分类流程,尤其是数据预处理步骤,我们将使用一个[手套](https://nlp.stanford.edu/projects/glove/)预先训练的单词嵌入。
文本特征处理比线性或分类特征稍微复杂一点。事实上,机器学习算法更多的是关于标量和向量,而不是字符或单词。因此,我们必须将文本输入转换成标量,而 **keystone** 🗝元素在于**如何找出输入单词**的最佳表示。这是自然语言处理背后的主要思想
我们将使用一个名为[的 Kaggle 竞赛的数据集,真实与否?灾难推文 NLP](https://www.kaggle.com/c/nlp-getting-started/data)。这项任务在于预测一条推文是否是关于一场真正的灾难。为了解决这个文本分类任务,我们将使用单词嵌入变换,然后是递归深度学习模型。其他不太复杂但仍然有效的解决方案也是可能的,比如结合 tf-idf 编码和朴素贝叶斯分类器(查看我上一篇[帖子](https://medium.com/prevision-io/automated-nlp-with-prevision-io-part1-naive-bayes-classifier-475fa8bd73de))。
此外,我将包括一些方便的 Python 代码,可以在其他 NLP 任务中重现。整个源代码可以在这个 [kaggle 笔记本](https://www.kaggle.com/schopenhacker75/eda-text-cleaning-glove?scriptVersionId=46794932)中获得。
# 简介:
LSTM 或 CNN 等模型在捕捉词序和它们之间的语义关系方面更有效,这通常对文本的意义至关重要:来自我们数据集的一个样本被标记为真正的灾难:
> #RockyFire 更新= >加州高速公路。20 个双向关闭,由于莱克县火灾-# CAfire #野火'
很明显,单词顺序在上面的例子中很重要。
另一方面,我们需要将输入文本转换成机器可读的格式。它存在许多技术,如
* **one-hot encoding** :每个序列文本输入在 d 维空间中表示,其中 d 是数据集词汇的大小。如果每个术语出现在文档中,则该术语将得到 1,否则将得到 0。对于大型语料库,词汇表将大约有数万个标记,这使得一次性向量非常稀疏和低效。
* **TF-IDF 编码**:单词被映射成使用 TF-IDF 度量生成的数字。该平台集成了快速算法,使得保持**所有**单元和二元 tf-idf 编码成为可能,而无需应用降维
* **单词嵌入变换**:单词被投影到一个密集的向量空间,在这个空间中,单词之间的语义距离被保留:(见下图):

[https://developers . Google . com/machine-learning/crash-course/images/linear-relationships . SVG](https://developers.google.com/machine-learning/crash-course/images/linear-relationships.svg)
**什么是预训练单词嵌入?**
嵌入是表示一个单词(或一个符号)的密集向量。默认情况下,嵌入向量是**随机**初始化的,然后将在训练阶段逐渐改进,在每个反向传播步骤使用梯度下降算法,以便相似的单词或相同词汇域中的单词或具有共同词干的单词…将在新向量空间中的距离方面以**接近**结束;(见下图):

作者:Zeineb Ghrib
预训练单词嵌入是**迁移学习的一个例子。**其背后的主要思想是使用已经在大型数据集上训练过的公共嵌入。具体来说,我们将**将这些预训练的嵌入设置为初始化权重**,而不是随机初始化我们的神经网络权重。这个技巧有助于加速训练和提高 NLP 模型的性能。
# 步骤 0:导入和设置:
首先,让我们导入所需的库和工具,它们将帮助我们执行 NLP 处理和
import pandas as pd
import numpy as np
from nltk.corpus import stopwords
from nltk.util import ngrams
from sklearn.feature_extraction.text import CountVectorizer
from collections import defaultdict
from collections import Counter
stop=set(stopwords.words('english'))
import re
from nltk.tokenize import word_tokenize
import gensim
import string
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
from tqdm import tqdm
from keras.models import Sequential
from keras.layers import Embedding,LSTM,Dense,SpatialDropout1D
from keras.initializers import Constant
from sklearn.model_selection import train_test_split
from keras.optimizers import Adam
# 第一步:文本清理:🧹
不考虑 EDA 步骤可以带出未清理的元素并帮助我们自定义清理代码,我们可以应用一些在 tweeters 中反复出现的基本数据清理,如删除标点符号,html 标签 URL 和表情符号,拼写纠正,..
下面是一段 python 代码,可以在其他类似的用例中重现😉
然后,我们将数据集拆分为:
* 一个**训练数据集**(训练数据集的 80%)
* 一个**验证数据集**:剩余 20%的训练数据集将用于验证每个时期的模型性能
* **测试数据集**(此处可选) :由 kaggle 提供,用于进行预测
train = df[~df['target'].isna()]
X_train, X_val, y_train, y_val = train_test_split(train, train['target'], test_size=0.2, random_state=42)
# 第二步:文本预处理🤖
如前所述,机器学习算法将数字作为输入,而不是文本,这意味着我们需要将文本转换为数字向量。
我们进行如下操作:
## 1.标记化
它包括将文本划分为单词或更小的子文本,允许我们确定数据集的“词汇”(数据中存在的一组唯一标记)。通常我们使用单词级表示。对于我们的例子,我们将使用 NLTK `Tokenizer()`
## 2.单词索引:
基于词频构建一个词汇索引映射器:索引将与整个数据集中的词频成反比。最频繁的世界的索引=1..每个单词都会有一个唯一的索引。
这两个步骤分解如下:
关于 NLTK 标记器的一些解释:
1. `fit_on_texts()`方法🤖:它根据词频创建词汇索引。
例:"*外壳中的幽灵*"会生成 word _ index[" the "]= 1;word_index["ghost"] = 2..
- >所以每个单词都得到一个唯一的整数值。从 1 开始(0 保留用于填充),单词越频繁,对应的索引越低。
(PS 往往前几个是停用词,因为出现很多但是建议在数据清理的时候去掉)。
2. `textes_to_sequences()`法📟:将每个文本转换为整数序列:每个单词都映射到 word_index 字典中的索引。
3. `pad_sequences()`方法🎞:为了使输出的形状标准化,我们定义了一个唯一的向量长度(在我们的例子中`MAX_SEQUENCE_LENGTH`将其固定为 50):任何更长的序列都将被截断,任何更短的序列都将用 0 填充。
# 步骤 3:构建嵌入矩阵🧱
首先,我们将从官方网站下载[手套预训练嵌入](https://nlp.stanford.edu/projects/glove/)(由于一些技术限制,我必须通过代码下载:
然后,我们将创建一个嵌入矩阵,将每个单词索引映射到其对应的嵌入向量:

[https://developers . Google . com/machine-learning/guides/text-classification/images/embedding layer . png](https://developers.google.com/machine-learning/guides/text-classification/images/EmbeddingLayer.png)
# 步骤 4:创建和训练模型:

[whatsapp 机器人](https://emojipedia.org/whatsapp/2.20.198.15/robot/)
我们将使用顺序 keras 模型创建一个递归神经网络,该模型将包含:
1. 以嵌入矩阵为初始权重的**嵌入层**
2. 一个**脱落层**以避免过度拟合(查看这篇关于神经网络中脱落层及其效用的优秀[帖子](https://machinelearningmastery.com/use-dropout-lstm-networks-time-series-forecasting/#:~:text=Dropout%20is%20a%20regularization%20method,overfitting%20and%20improving%20model%20performance.)
3. 一个 **LSTM 层**:包括长短期存储单元
4. 使用*二元交叉熵*损失函数的**激活层**
如果我们想要计算我们的二元 keras 分类器模型的准确度、精确度、召回率和 F1 分数,我们必须手动计算它们,因为自 [2.0 版本](https://github.com/keras-team/keras/wiki/Keras-2.0-release-notes)以来,Keras 不支持这些指标。
(解决方案来自[此处](https://datascience.stackexchange.com/questions/45165/how-to-get-accuracy-f1-precision-and-recall-for-a-keras-model))
现在编译和训练模型:
要获得验证性能结果,使用`evaluate()`方法:
loss, accuracy, f1_score, precision, recall = model.evaluate(tokenized_val, y_val, verbose=0)
让我们检查结果:

由 Zeineb Ghrib 从[这里](https://www.kaggle.com/schopenhacker75/eda-text-cleaning-glove?scriptVersionId=46794932)
这些结果似乎相当不错,但当然可以通过微调神经网络超参数或使用 auto-ml 工具(如 [prevision](https://cloud.prevision.io/) )来增强,除了 wor2vec 之外,这些工具还应用了许多其他转换,如 ngram 令牌化、tf-idf 或更先进的技术(如 [BERT](https://huggingface.co/transformers/model_doc/bert.html) transformers)。
# 结论:
在这篇文章中,我一步一步地向您展示了如何从 Glove 预训练的单词嵌入应用 wor2vec 变换,以及如何使用它来训练一个递归神经网络。请注意,该方法和代码可以在其他类似的用例中重用。整体源代码可以在这个 [kaggle 笔记本](https://www.kaggle.com/schopenhacker75/eda-text-cleaning-glove?scriptVersionId=46794932)中找到。
我还在同一个数据集上应用了完全不同的方法:我使用了 tf-idf 朴素贝叶斯分类器,如果你想获得更多信息,请访问[我的上一篇文章](https://medium.com/prevision-io/automated-nlp-with-prevision-io-part1-naive-bayes-classifier-475fa8bd73de)。
我打算写一篇关于如何使用名为 Bert 的突破性算法的文章,并将其与其他 NLP 算法进行比较
感谢您阅读我的帖子🤗!!如果您有任何问题,可以在 [prevision cloud instance](https://cloud.prevision.io/) 的聊天会话中找到我,或者发送电子邮件至:zeineb.ghrib@prevision.io
# 精准医疗和机器学习
> 原文:<https://towardsdatascience.com/precision-medicine-and-machine-learning-11060caa3065?source=collection_archive---------47----------------------->
## [数据科学](https://towardsdatascience.com/data-science/home)
## 数据科学可能是个人医学的未来

[马塞洛·里尔](https://unsplash.com/photos/6pcGTJDuf6M)上 [Unsplash](https://unsplash.com/)
长期以来,个性化或精确的药物一直是未来治疗的试金石。它包括使用特定于患者的知识**,如生物标记、人口统计学或生活方式特征,来最好地治疗他们的疾病,而不是一般的平均最佳实践。在最好的情况下,它可以利用数千名从业者的专业知识和数百万其他患者的成果来提供经过验证的有效护理。**
**精准医疗对患者和医生都有很多好处(改编自[frh lich](https://bmcmedicine.biomedcentral.com/articles/10.1186/s12916-018-1122-7)):**
1. **提高治疗效果**
2. **减少副作用**
3. **降低患者和提供商的成本**
4. **使用生物标志物的早期诊断**
5. **改进的预后估计**
**实现个性化治疗所需的原始数据量需要机器学习。我之前的一篇文章[涉及了这一点,特别是机器学习在肿瘤学中的其他应用,因为这可能是最接近实现精确医疗结果的领域。](/machine-learning-ai-applications-in-oncology-73a8963c4735)**
**药物基因组学是一个完整的领域,致力于研究病人的基因如何影响他们对药物的反应。这主要用于限制由于长期暴露或敏感性增加而产生的药物副作用,但一些药物需要特定基因表达才能达到其靶点。例如,赫赛汀(曲妥珠单抗)靶向 HER2/ *neu* 受体,因此该基因必须在患者的癌症中过表达,才能开出赫赛汀处方。**
****
**[图片](https://commons.wikimedia.org/w/index.php?curid=29720528)来源:[西蒙·考尔顿](https://commons.wikimedia.org/wiki/User:Simoncaulton)带 [CC BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0?ref=ccsearch&atype=rich) 牌照**
**一个成功的[模型](https://www.forbes.com/sites/insights-intelai/2019/02/11/how-machine-learning-is-crafting-precision-medicine/#1d9a17b25941)使用了来自梅奥诊所 800 名患者超过 10 年的基因数据来确定各种药物缓解抑郁症状的功效。该模型能够达到 85%的准确率,相比之下,精神病学家的准确率只有 55%,他们经常不得不通过对患者进行反复试验来找到最有效的药物。**
**改善护理的其他潜在途径包括识别致病基因、了解患者之间的表型和基因型差异、基因-基因相互作用和新药发现。由普林斯顿大学开发的深度学习模型 DeepSEA 已经成功预测了 DNA 中单核苷酸畸变的染色质效应。诸如此类的模型在预测成功方面具有巨大的潜力,但它们也应该阐明基因型、疾病诊断、治疗方案等之间的机制关系。**
## **挑战**
**虽然这些不同的精准医疗方法令人兴奋,并正在积极探索,但仍有许多挑战需要克服。你应该阅读这篇[文章](https://bmcmedicine.biomedcentral.com/articles/10.1186/s12916-018-1122-7)进行更深入的研究,但是下面总结了一些要点。**
**首先,我们经常听到“啊,如果我们有更多的数据,那么我们的模型会更好”,但这并没有抓住现实,特别是在医学中,数据质量往往被忽略,而有利于数据数量。通俗点说,垃圾进,垃圾出。虽然经常需要大量数据,但是这些数据必须具有能够将噪声从信号中分离出来的基本模式。正如 Frö hlich 所指出的,一些噪音是来自采样的误差(没有用),一些是生物变异(非常有用),但我们和我们的模型都无法区分它们。**
**其次,虽然我们的模型可以发现数据中的新模式,甚至可以对新的例子做出非常准确的预测,但它们无法证明因果关系。正是这种特殊的品质使它们成为非常有用的工具,而不是科学方法的真正替代品。现代媒体喜欢将“人工智能”描述为任何工作或任务的替代品,当它根本不可能的时候。看看 IBM 的沃森在[的不太理想的实现。](https://www.statnews.com/2017/09/05/watson-ibm-cancer/)**
**第三,预测模型依赖于它在看不见的数据上的表现。这是训练/测试分割、交叉验证、数据扩充等背后的基本原理。如果一个模型不能很好地概括,那么它就没有多大用处。部署精确医疗模型的原因是,绩效不佳的影响可能很大。我们必须意识到用不知情的病人的健康来验证我们的模型的伦理陷阱。因此,仍然需要昂贵的临床试验来证实该模型,并向**展示**它如何改善护理(如果有的话)。**
## **未来**
**精准医疗在根据患者的特定表型和基因组改善护理方面有着令人兴奋的未来。特定模型在药物发现、治疗效果、指导诊断等方面取得了成功。 [IBM 的沃森](https://www.statnews.com/2017/09/05/watson-ibm-cancer/)通用人工智能甚至已经被纳入世界各地的少数肿瘤部门,尽管结果喜忧参半。事实上,机器学习在精准医疗方面面临的挑战是多种多样且难以应对的。但是,创造未来从来都不容易。**
## **来源**
**[1]福布斯洞察团队,[机器学习如何打造精准医疗](https://www.forbes.com/sites/insights-intelai/2019/02/11/how-machine-learning-is-crafting-precision-medicine/#6dfd63a65941) (2019),福布斯洞察。**
**[2] G.Z. Papadakis,A.H. Karantanas,M. Tsiknakis 等,[深度学习开启个性化医疗新视野](https://www.spandidos-publications.com/10.3892/br.2019.1199) (2019),《生物医学报告》10(4):215–217。**
**[3] M. Uddin,Y. Wang 和 M. Woodbury-Smith,[神经发育障碍精准医疗的人工智能](https://www.nature.com/articles/s41746-019-0191-0.pdf) (2019),npj 数字医学 2: 112。**
**[4] J. Zhou 和 O.G. Troyanskaya,[用基于深度学习的序列模型预测非编码变体的效果](https://www.nature.com/articles/nmeth.3547) (2015),Nature Methods 12:941–934。**
# 机器学习在宫颈癌预测中的应用
> 原文:<https://towardsdatascience.com/precision-recall-and-predicting-cervical-cancer-with-machine-learning-367221e70538?source=collection_archive---------12----------------------->
## OSEMN 代表什么?

从 Adobe Stock 获得许可的图像
机器学习通常被描述为人工智能的一个子集,通常涉及创建能够以各种方式分析数据以做出预测的“模型”。它已经在无数领域证明了自己的用处,包括像“推荐引擎”这样众所周知的应用程序,它根据“学习”用户过去的行为来推荐用户喜欢的内容。作为我进入数据科学之旅的一部分,我编写并测试了几个机器学习模型,以使用关于女性的数据集进行预测,以及在哪里进行活检以确定是否存在宫颈癌。
数据集是从加州大学欧文分校(UCI)的机器学习库中获得的,位于这个[链接](https://archive.ics.uci.edu/ml/datasets/Cervical+cancer+%28Risk+Factors%29#)。这些信息是在委内瑞拉加拉加斯的“加拉加斯大学医院”收集的,由 35 个因素组成,包括 858 名患者的人口统计信息、习惯和历史医疗记录。由于隐私问题(缺少值),一些患者选择不回答一些问题。我之前写过一篇关于处理丢失数据的简短文章[这里](/dealing-with-missing-data-17f8b5827664?source=friends_link&sk=5ecf67f2141e50bcd47dc37b33e96deb)。该数据集来自于 2017 年 5 月首次在线发表的一篇研究论文。
**目标、挑战和‘目标’**
这个项目的目标是开发一个机器学习模型,该模型可以使用每个妇女可能的风险因素的 35 个变量尽可能好地预测宫颈癌的存在。使用这种类型的数据开发预测模型时面临的一个挑战是精确度和召回率之间的平衡:
* 精度表示模型预测的癌症中实际存在癌症的比例。
* 回忆表示模型准确预测的所有癌症病例的比例。

图片由沃尔伯提供—自己的作品,CC BY-SA 4.0
[## Precisionrecall.svg
### 来自维基共享,自由媒体仓库
commons.wikimedia.org](https://commons.wikimedia.org/w/index.php?curid=36926283)
因为不“捕捉”甚至一个癌症病例都可能导致死亡,所以模型应该强调回忆分数。更可取的做法是不“遗漏”任何癌症患者,即使这意味着将一些实际上没有患病的患者“标记”为患有癌症。
使用此类数据创建预测模型的另一个挑战是,阳性病例(存在癌症)通常只占数据集中患者总数的一小部分。这就产生了所谓的“不平衡”数据集,即。在我们试图预测的两个类别中,个体的数量是不相等的。不平衡的数据使得机器学习模型的预测更加困难,因为与阴性(没有癌症)病例相比,可以学习的“阳性”(存在癌症)病例更少。有了这样不平衡的数据,预测模型可以很容易地以牺牲精度为代价获得很高的召回率,反之亦然。例如,想象一个包含 1,000 名患者的数据集,其中 10 人患有癌症,这是一个非常现实的场景:
* 一个预测每个人都患有癌症的模型的召回率为 100%,但精确度为 1%。像这样的预测模型没有任何价值。然后,所有的病人都要接受活组织检查,记录所有的癌症病例,但对 990 名妇女进行不必要的检查。
在这种情况下,预测模型的目标是以尽可能少的“假阳性”(预测有癌症,但实际上没有癌症)识别尽可能高百分比的癌症病例。
每个模型 I 测试将首先通过查看召回率进行评估,然后是 F1 分数,F1 分数是反映精确度和召回率同等平衡权重的衡量标准:

我开发模型的方法遵循 OSEMN 协议:
* 获得
* 矮树
* 探索
* 模型
* 口译
该项目是在 Jupyter 笔记本中开发的,使用了 scikit-learn 的数据科学包以及笔记本中记录的其他一些资源。笔记本和运行它所需的所有文件可以在我的 GitHub 库[这里](https://github.com/giorosati/dsc-3-final-project-online-ds-pt-100118)获得。
# **获得&磨砂**
在初始化笔记本并将数据集加载到 Pandas 数据框架后,我查看了它包含的值的类型以及哪些因素缺少信息。在 dataframe 导入阶段,我用 NumPy“NaN”填充了所有缺失的值。以下是用红色显示缺少值的变量的数据概述:

**创造一些新的因素**
尽管某些因素中缺失值的百分比相对较小,但我不想丢失这些因素中可能存在的任何信息:
* 性伴侣数量
* 第一次性交
* 怀孕数量
我创建了新的布尔因子来区分已知信息的记录和未给出数据的记录。如果记录有值,则这些新因子的值为 true (1),如果记录缺少该因子的数据,则这些新因子的值为 false (0):
* 已知有 _ number _ partners _ 吗
* 第一次性交是已知的
* 已知怀孕次数吗
为此,我编写了一个从现有列创建新列的函数:
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
以下是如何使用此函数创建每个新因子(列)的示例:
create new factor ‘is_number_partners_known’
df[‘is_number_partners_known’] = new_bool(df, ‘Number of sexual partners’)
这三个原始因子也有缺失值,我稍后会将它们与所有其他缺失值一起处理。
**处理数据中的“漏洞”**
我创建了一个函数来显示给定因子的计数图、箱线图和一些汇总统计数据,这样我可以更好地了解这些因子的分布情况:
def countplot_boxplot(column, dataframe):
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:’, df2[column].min())
print(‘Mean:’, df2[column].mean())
print(‘Median:’, df2[column].median())
print(‘Mode:’, df2[column].mode()[0])
print(‘Max:’, df2[column].max())
print(‘*********************’)
print(‘% of values missing:’, (df2[column].isna().sum() / len(df2))100)
在评估了每个因素后,我决定如何最好地处理缺失的值。这里有一个“第一次性交”因素的流程示例,它代表女性第一次经历性交的年龄。我运行了上面的函数,传递了列名:
countplot_boxplot('First sexual intercourse', df2)
以下是输出结果:

Min: 10.0
Mean: 16.995299647473562
Median: 17.0
Mode: 15.0
Max: 32.0
% of values missing: 0.8158508158508158
通过观察这两个图,很明显,分布是有点正常的,在范围的高端有一个长“尾巴”。同样重要的是,这个因子只有不到 1%的值丢失,所以无论我用什么来填充丢失的值,对模型的影响都是最小的。我选择用中间值来填充这里缺失的值。
我继续检查每个因子,用零、平均值或中值替换缺失值,但有几个因子需要一些额外的思考:
* STDs:自首次诊断以来的时间
* STDs:自上次诊断以来的时间
超过 90%的患者对这些因素没有价值。我可以简单地删除这些因素——机器学习模型无法处理缺失值——但我不想丢失 10%患者的信息,这些信息对这些因素有价值。我注意到“父”因子“STDs:Number of diagnostics”也缺少相同数量的值。我的假设是,这些女性拒绝回答这个问题和这两个相关的问题。我选择用零填充所有三个因子中缺失的值:
* 性传播疾病:诊断数量
* STDs:自首次诊断以来的时间
* STDs:自上次诊断以来的时间
我在“STD's (number)”因素上遇到了类似的情况。我再次运行我的函数来可视化数据:
countplot_boxplot('STDs (number)', df2)

Min: 0.0
Mean: 0.17662682602921648
Median: 0.0
Mode: 0.0
Max: 4.0
% of values missing: 12.237762237762238
这里的值几乎为零,大约有 12%的数据丢失。由于零在这个因子的分布中占主导地位,我觉得用零代替缺失值是最好的选择。此外,12 个单独的布尔因子中的每一个都有大约 12%的缺失值。我还用零替换了所有单个布尔“STD”因子中缺失的值。
# **探索**
填充所有缺失值后,关联热图显示两个因素完全没有信息:
* 性病:宫颈湿疣
* 性病:艾滋病
我从数据库中删除了这些因素,然后运行了一个关联热图,显示每个因素如何单独与目标变量“活检”相关。

这张热图表明**自身**的因素:
* 席勒
* 欣塞尔曼
* 城市学
是最有用的。
# **型号**
下一步是将数据分成训练集和测试集:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state= 10)
我使用 80%的数据进行训练,并指定一个 random_state 以确保可重复性。
该数据集中的非布尔因子:
* 年龄
* 性伴侣数量
* 第一次性交
* 怀孕数量
* 吸烟(年)
* 烟(包/年)
* 激素避孕药(年)
* 宫内节育器(年)
* 性传播疾病(数量)
* STD(诊断数量)
* STDs:自首次诊断以来的时间
* STDs:自上次诊断以来的时间
有非常不同的范围。我标准化了每个因素的值(使每个因素的范围从 0 到 1),以便机器学习算法不会仅仅因为它的范围较大而偏向任何因素。对于给定的因素,每个患者的值之间的关系保持不变,但现在每个因素都有相同的尺度。这防止了不同因素之间的不同等级,从而使模型对该因素的重要性的评估产生偏差。值得注意的是,标准化(或规范化)是对训练和测试数据集分别进行的。我不想让模型对将要测试的数据有任何了解。模型必须只从测试集中学习。
如前所述,这是一个“不平衡”的数据集,只有大约 10%的记录具有目标变量的“真”值。一些机器学习模型具有内置功能来补偿这一点,而一些没有。我测试了来自不平衡学习的一个名为 SMOTE(合成少数过采样技术)的包,以创建一个平衡的数据集——其中有相等数量的真和假目标变量记录。这只在训练数据上进行,而不在测试数据上进行。下面是创建这种重采样训练数据的语法:
sm = SMOTE(sampling_strategy='auto', random_state=10)X_train_res, y_train_res = sm.fit_resample(X_train, y_train)
查看原始数据和重采样数据的差异:
X_train.shape #the original data(686, 36) X_train_res.shape #the resampled data(1294, 36)
创建了 608 条“虚构”记录(1,294 减去 686)来“平衡”数据集。这些新记录被创建为与目标变量为真的现有记录相似。
现在,我可以用原始的“不平衡”数据集或重新采样的“平衡”数据集来测试任何模型。我发现,当给定这种重新采样的训练数据时,逻辑回归和 KNN 模型表现得更好,但是决策树、随机森林和支持向量机(SVM)模型在使用原始不平衡数据但实现它们自己的内置类权重参数时表现得更好。
为了方便测试每个模型,我创建了一个函数来返回我想了解的每个模型的性能信息:
def analysis(model, X_train, y_train):
model.fit(X_train, y_train)# predict probabilities
probs = model.predict_proba(X_test)# keep probabilities for the positive outcome only
probs = probs[:, 1]# predict class values
preds = model.predict(X_test)# calculate precision-recall curve
precision, recall, thresholds = precision_recall_curve(y_test, probs)# calculate average precision
average_precision = average_precision_score(y_test, probs)
# recall score for class 1 (Predict that Biopsy is True)
rs = recall_score(y_test, preds)# calculate F1 score
f1 = f1_score(y_test, preds)# calculate precision-recall AUC
auc_score = auc(recall, precision)# create chart
# In matplotlib < 1.5, plt.fill_between does not have a 'step' argument
step_kwargs = ({'step': 'post'}
if 'step' in signature(plt.fill_between).parameters
else {})
plt.step(recall, precision, color='b', alpha=0.2, where='post')
plt.fill_between(recall, precision, alpha=0.2, color='b', **step_kwargs)# plot a "no skill" line
plt.plot([0, 1], [0.5, 0.5], linestyle='--')plt.xlabel('Recall')
plt.ylabel('Precision')
plt.ylim([0.0, 1.05])
plt.xlim([0.0, 1.0])
plt.title('Precision-Recall curve: Average Precision={0:0.3f}'.format(average_precision))
plt.show()# print(confusion_matrix(y_test, preds))
print('Classification Report:')
print(classification_report(y_test, preds))print('f1=%.3f auc=%.3f recall=%.3f' % (f1, auc_score, rs))
GridSearchCV 方法用于搜索我测试的大多数模型的最佳参数。下面是一个使用 GridSearchCV 和随机森林分类器的示例:
forest = RandomForestClassifier(random_state=10, n_jobs=-1)forest_param_grid = {
'class_weight': ['balanced'],
'criterion': ['gini', 'entropy' ],
'max_depth': [2, 3, 4, 5, 6, 7, 8],
'n_estimators': [20, 40, 50, 60, 80, 100, 200]}forest_grid_search = GridSearchCV(forest,
param_grid = forest_param_grid,
scoring = 'recall',
cv=3,
return_train_score=True)
在本例中,“class_weight”被设置为“balanced ”,以让随机森林实现其内置方法,这些方法针对其正在接受训练的不平衡数据进行调整。然后,我使用测试数据拟合模型:
forest_grid_search.fit(X_train, y_train)
GridSearchCV 发现以下参数值效果最佳:
Optimal Parameters: {'class_weight': 'balanced', 'criterion': 'gini', 'max_depth': 2, 'n_estimators': 20}
基于这些信息,我重新运行了另一个 GridSearchCV 来进一步细化参数值:
forest_param_grid = {
'class_weight': ['balanced'],
'criterion': ['gini'],
'max_depth': [2, 3, 4],
'n_estimators': [10, 15, 20, 25, 30]}forest_grid_search = GridSearchCV(forest,
param_grid = forest_param_grid,
scoring = 'recall',
cv=3,
return_train_score=True)
找到的最佳值是:
Optimal Parameters: {'class_weight': 'balanced', 'criterion': 'gini', 'max_depth': 2, 'n_estimators': 10}
使用这些值创建了一个新的随机林,然后使用测试数据进行预测:
# 口译
以下是优化随机森林的结果:

Classification Report:
precision recall f1-score support
0 0.99 0.96 0.97 156
1 0.67 0.88 0.76 16
accuracy 0.95 172
macro avg 0.83 0.92 0.86 172
weighted avg 0.96 0.95 0.95 172
f1=0.757 auc=0.555 recall=0.875
该模型能够“找到”88%的癌症女性(回忆),并且其 67%的癌症预测是正确的(精确度)。
为了查看这个模型使用了什么特性,我使用了一个特性重要性图表。红色条代表每个特征的重要性,每个红色条顶部的黑线代表该特征在所有树中重要性的标准偏差。

有趣的是,“年龄”因素和“性学”因素——一种诊断测试——一样重要。
决策树和随机森林的一个优点是它们的可解释性。下图显示了该项目中表现最佳的单一决策树是如何工作的:

该树仅使用这些因素:
* 席勒
* Dx:CIN
* 年龄
对每个病人进行分类。随机森林模型在 10 种不同的树中使用了 15 个因子,以获得稍好的性能。(查看 Jupyter 笔记本以查看所有的树)。
在对我研究的所有模型进行调优和测试之后,以下是每种模型的最佳结果:

使用原始不平衡数据的随机森林模型表现最好,其次是决策树模型。
在未来的帖子中,我打算探索神经网络预测模型是否可以改善这些 F1 和回忆分数。
感谢阅读。我一直对了解数据科学如何让世界更好地为每个人服务很感兴趣。如果您知道数据科学“发挥作用”的情况,请分享!
# 数据集引用:
凯尔温·费尔南德斯、海梅·卡多佐和杰西卡·费尔南德斯。具有部分可观察性的迁移学习应用于宫颈癌筛查。伊比利亚模式识别和图像分析会议。斯普林格国际出版公司,2017 年。[https://archive . ics . UCI . edu/ml/datasets/子宫颈+癌症+% 28 风险+因素%29#](https://archive.ics.uci.edu/ml/datasets/Cervical+cancer+%28Risk+Factors%29)