TowardsDataScience 博客中文翻译 2019(三百一十九)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

Keras 深层网络中的注意力

原文:https://towardsdatascience.com/light-on-math-ml-attention-with-keras-dc8dbc1fad39?source=collection_archive---------0-----------------------

点亮数学机器学习

将所有错综复杂的注意力转移到喀拉斯的一条优雅的线上

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Courtesy of Pixabay

这个故事向您介绍了一个 Github 存储库,其中包含一个使用 Keras 后端操作实现的原子最新关注层。可在 关注 _keras 获得。

要访问本系列中我以前的文章,请使用以下信件。

ABCD* E F G H I J**K**L*****M****

[ 🔈🔥最新文章🔥🔈**:M—矩阵分解******

为什么是 Keras?

随着 TensorFlow 2.0 的推出,很难忽视引人注目的关注(没有双关语!)送给 Keras。有更多的重点是倡导 Keras 实施深度网络。TensorFlow 2.0 中的 Keras 将提供三个强大的 API 来实现深度网络。

  • 顺序 API——这是最简单的 API,首先调用model = Sequential()并不断添加层,例如model.add(Dense(...))
  • 功能 API —高级 API,您可以在其中创建具有任意输入/输出的自定义模型。定义一个模型需要非常小心,因为在用户端有很多事情要做。可以使用model = Model(inputs=[...], outputs=[...])定义模型。
  • 子类化 API——另一个高级 API,可以将模型定义为 Python 类。在这里,您可以在类中定义模型的向前传递,Keras 会自动计算向后传递。那么这个模型可以像使用任何 Keras 模型一样正常使用。

更多信息,从 TensorFlow 团队获得第一手信息。然而,请记住,虽然选择高级 API 为实现复杂模型提供了更多的“回旋空间”,但它们也增加了出现错误和各种兔子洞的机会。

为什么发这个帖子?

最近,我正在为我正在做的一个项目寻找一个基于 Keras 的注意力层实现或库。我处理了几个已经引起关注的回复。然而,我的努力是徒劳的,试图让他们与以后的 TF 版本。由于几个原因:

  • 实现注意力的方式缺乏模块化(对整个解码器而不是解码器的各个展开步骤实现注意力
  • 使用早期 TF 版本中不推荐使用的函数

他们做出了巨大的努力,我尊重所有做出贡献的人。但是我想我会介入并实现一个 AttentionLayer ,它适用于更多的原子级别,并随着新的 TF 版本而更新。这个库在这里可用。

:这是数学机器学习 A-Z 上 光系列的一篇文章。你可以在下面的信中找到以前的博客文章。

A BCD* E F G H I J**KL* M**NO P Q R S T U V********

介绍

在这篇文章中,首先你会探究什么是序列对序列模型,然后是为什么注意力对序列模型很重要?接下来,你将学习注意力机制的本质。这篇博文将以解释如何使用注意力层来结束。

序列到序列模型

Sequence to sequence 是一个强大的深度学习模型家族,旨在解决 ML 领域中最疯狂的问题。举个例子,

  • 机器翻译
  • 聊天机器人
  • 文本摘要

有着非常独特和独特的挑战。比如机器翻译要处理不同的语序拓扑(即主语-动词-宾语顺序)。因此它们是解决复杂 NLP 问题的必备武器。

让我们看看如何将序列对序列模型用于英法机器翻译任务。

序列对序列模型有两个组件,一个编码器和一个解码器。编码器将源句子编码成一个简洁的向量(称为上下文向量),解码器将上下文向量作为输入,并使用编码的表示来计算翻译。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sequence to sequence model

这种方法有问题吗?

这种方法有一个巨大的瓶颈。上下文向量负责将给定源句子中的所有信息编码成一个包含几百个元素的向量。现在给出一点背景,这个向量需要保持:

  • 关于主语、宾语和动词的信息
  • 这些实体之间的相互作用

这可能是相当令人生畏的,尤其是对于长句。因此,需要一种更好的解决方案来突破极限。

输入关注!

如果解码器能够访问编码器的所有过去状态,而不是仅仅依赖于上下文向量,会怎么样?这正是注意力在做的事情。在每个解码步骤中,解码器都会查看编码器的任何特定状态。这里我们将讨论 Bahdanau 注意力。下图描绘了注意力的内部运作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sequence to sequence with attention

因此,如图所示,上下文向量已经成为所有过去编码器状态的加权和。

介绍 attention_keras

由于我前面解释的原因,让一些注意力层在那里工作可能会很麻烦。

使用注意力层

您可以将它用作任何其他层。举个例子,

**attn_layer = AttentionLayer(name='attention_layer')([encoder_out, decoder_out])**

我还提供了一个玩具神经机器翻译器(NMT)的例子,展示了如何在 NMT ( nmt/train.py )中使用注意力层。但是让我带你了解一些细节。

用心实施 NMT

在这里,我将简要介绍一下实现 NMT 的步骤。

首先定义编码器和解码器输入(源/目标字)。两者都是形状(batch_size,timesteps,vocabulary_size)。

**encoder_inputs = Input(batch_shape=(batch_size, en_timesteps, en_vsize), name='encoder_inputs')
decoder_inputs = Input(batch_shape=(batch_size, fr_timesteps - 1, fr_vsize), name='decoder_inputs')**

定义编码器(注意return_sequences=True)

**encoder_gru = GRU(hidden_size, return_sequences=True, return_state=True, name='encoder_gru')
encoder_out, encoder_state = encoder_gru(encoder_inputs)**

定义解码器(注意return_sequences=True

**decoder_gru = GRU(hidden_size, return_sequences=True, return_state=True, name='decoder_gru')
decoder_out, decoder_state = decoder_gru(decoder_inputs, initial_state=encoder_state)**

定义关注层。注意层的输入是encoder_out(编码器输出序列)和decoder_out(解码器输出序列)

**attn_layer = AttentionLayer(name='attention_layer')
attn_out, attn_states = attn_layer([encoder_out, decoder_out])**

连接attn_outdecoder_out作为 softmax 层的输入。

**decoder_concat_input = Concatenate(axis=-1, name='concat_layer')([decoder_out, attn_out])**

定义TimeDistributed Softmax 层并提供decoder_concat_input作为输入。

**dense = Dense(fr_vsize, activation='softmax', name='softmax_layer')
dense_time = TimeDistributed(dense, name='time_distributed_layer')
decoder_pred = dense_time(decoder_concat_input)**

定义完整模型。

**full_model = Model(inputs=[encoder_inputs, decoder_inputs], outputs=decoder_pred)
full_model.compile(optimizer='adam', loss='categorical_crossentropy')**

就是这样!

甚至支持注意力可视化…

这不仅实现了注意力,也给了你一个很容易窥视注意力机制的方法。这是可能的,因为这一层返回两者,

  • 注意上下文向量(用作解码器的 Softmax 层的额外输入)
  • 注意能量值(注意机制的 Softmax 输出)

对于每个解码步骤。因此,通过可视化注意力能量值,你可以完全了解注意力在训练/推理过程中在做什么。下面,我来说说这个过程的一些细节。

从 NMT 推断并获得关注权重

从 NMT 推断是繁琐的!因为你必须这么做,

  • 获取编码器输出
  • 定义一个执行解码器的单个步骤的解码器(因为我们需要提供该步骤的预测作为下一步的输入)
  • 使用编码器输出作为解码器的初始状态
  • 执行解码,直到我们得到一个无效字/ 作为输出/或固定步数

我不打算讨论模型定义。详情请参考examples/nmt/train.py。让我们来看看如何利用这一点来获得关注权重。

**for i in range(20):

    dec_out, attention, dec_state = decoder_model.predict([enc_outs, dec_state, test_fr_onehot_seq])
    dec_ind = np.argmax(dec_out, axis=-1)[0, 0]

    ...

    attention_weights.append((dec_ind, attention))** 

如你所见,我们正在为每个解码步骤收集注意力权重。

然后,您只需将这个注意力权重列表传递给plot_attention_weights ( nmt/train.py ),以便获得带有其他参数的注意力热图。绘图后的输出可能如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2022 年 6 月更新

最近有一个关于 AttentionLayer 在 TensorFlow 2.4+版本上不工作的 bug 报告。这导致了如下的神秘错误,

**TypeError: Exception encountered when calling layer "tf.keras.backend.rnn" (type TFOpLambda).

You are passing KerasTensor(type_spec=TensorSpec(shape=(None, 101), dtype=tf.float32, name=None), name='tf.compat.v1.nn.softmax_1/Softmax:0', description="created by layer 'tf.compat.v1.nn.softmax_1'"), an intermediate Keras symbolic input/output, to a TF API that does not allow registering custom dispatchers, such as `tf.cond`, `tf.function`, gradient tapes, or `tf.map_fn`. Keras Functional model construction only supports TF API calls that *do* support dispatching, such as `tf.math.add` or `tf.reshape`. Other APIs cannot be called directly on symbolic Kerasinputs/outputs. You can work around this limitation by putting the operation in a custom Keras layer `call` and calling that layer on this symbolic input/output.

Call arguments received:
  • step_function=<function AttentionLayer.call.<locals>.energy_step at 0x7f1d5ff279e0>
  • inputs=tf.Tensor(shape=(None, None, 256), dtype=float32)
  • initial_states=['tf.Tensor(shape=(None, 101), dtype=float32)']
  • go_backwards=False
  • mask=None
  • constants=None
  • unroll=False
  • input_length=None
  • time_major=False
  • zero_output_for_mask=False**

该错误是由于基于图形的KerasTensor对象和渴望的tf.Tensor对象之间的混淆造成的。即将合并的 https://github.com/thushv89/attention_keras/tree/tf2-fix 分公司正在进行调整。

结论

在本文中,我向您介绍了 AttentionLayer 的一个实现。注意力对于序列模型甚至其他类型的模型都是非常重要的。然而,当前的实现要么不是最新的,要么不是非常模块化。所以我稍微挖了一下,用 Keras 后端操作实现了一个注意力层。所以我希望你能在这一层做得很好。如果您有任何问题/发现任何 bug,请随时在 Github 上提交问题。

欢迎贡献者

我将非常感谢有贡献者,修复任何错误/实施新的注意机制。所以欢迎投稿!

如果你喜欢我分享的关于数据科学和机器学习的故事,考虑成为会员吧!

**** [## 通过我的推荐链接加入媒体

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

thushv89.medium.com](https://thushv89.medium.com/membership)****

想在深度网络和 TensorFlow 上做得更好?

检查我在这个课题上的工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[1] (书)TensorFlow 2 在行动——曼宁

[2] (视频课程)Python 中的机器翻译 — DataCamp

[3] (书)TensorFlow 中的自然语言处理 1 — Packt

新的!加入我的新 YouTube 频道

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你渴望看到我关于各种机器学习/深度学习主题的视频,请确保加入 DeepLearningHero

理解手套嵌入的直观指南

原文:https://towardsdatascience.com/light-on-math-ml-intuitive-guide-to-understanding-glove-embeddings-b13b4f19c010?source=collection_archive---------1-----------------------

点亮数学机器学习

理解 GloVe 和 Keras 实现背后的理论!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Jelleke Vanooteghem on Unsplash

;(太久没发工资了?不用担心,您仍然可以通过以下链接访问代码)

带 Keras 的手套实现:【此处为

在本文中,您将了解 GloVe,这是一种非常强大的单词向量学习技术。本文将重点解释为什么 GloVe 更好,以及 GloVe 的成本函数背后的动机,这是算法中最关键的部分。。该代码将在后面的文章中详细讨论。

要访问本系列中我以前的文章,请使用以下信件。

ABCD E F G H I J**KL*****M***

[ 🔈🔥最新文章🔥🔈:M—矩阵分解****

GloVe 是一种词向量技术,它在短暂的沉寂之后驾驭了词向量的浪潮。只是为了刷新,单词向量将单词放入一个很好的向量空间,相似的单词聚集在一起,不同的单词相互排斥。GloVe 的优势在于,与 Word2vec 不同,GloVe 不仅仅依赖于局部统计(单词的局部上下文信息),而是融入了全局统计(单词共现)来获取单词向量。但是请记住,手套和 Word2vec 之间有相当多的协同作用。

听到使用全局统计数据来推导单词之间的语义关系的想法可以追溯到很久以前,不要感到惊讶。第一回,潜在语义分析 (LSA)。这只是一个有趣的事实。我们继续吧。

Word2vec 复习

Word2vec 背后的根本思想是什么?

从一个人交的朋友你就可以知道他说了什么——j·r·弗斯

单词向量就是建立在这个想法上的。基本上,你得到一个大型语料库,并制作一个元组数据集,其中每个元组包含(某个单词 x,x 的上下文中的一个单词)。然后你会使用你的老朋友,一个神经网络,学习预测 x 的上下文单词,给定单词 x。如果你想了解更多关于 Word2vec 的信息,请参考我的文章这里

那么是什么在拉回呢?

鉴于 Word2vec 的显眼性能,为什么不坚持使用呢?原因不在于性能,而在于解决方案制定的根本。记住,Word2vec 只依赖于语言的 本地信息 。也就是说,对于一个给定的单词所学习的语义,只受周围单词的影响。

例如,以这个句子为例,

那只猫坐在垫子上

如果你使用 Word2vec,它不会捕捉这样的信息,

“the”是“cat”和“mat”这两个词的特殊语境吗?

或者

“the”只是一个停用词吗?

这可能是次优的,尤其是在理论家的眼中。

回车,手套

GloVe 代表“全局向量”。如前所述,GloVe 捕获语料库的全局统计数据和局部统计数据,以便得出单词向量。但是,我们需要全球和地方统计数据吗?

两个比一个好吗?

事实证明,每种类型的统计都有自己的优势。例如,捕获局部统计数据的 Word2vec 在类比任务中表现非常好。然而,像 LSA 这样只使用全局统计的方法在类比任务中做得不好。然而,由于 Word2vec 方法由于仅使用局部统计而受到某些限制(如我们上面讨论的)。

手套介绍

手套方法建立在一个重要的理念上,

你可以从共现矩阵中推导出单词之间的语义关系。

给定一个含有 V 词语的语料库,共现矩阵 X 将是一个 V x V 矩阵,其中第行和第 j 列为 XX_ij 一个示例共现矩阵可能如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The co-occurrence matrix for the sentence “the cat sat on the mat” with a window size of 1. As you probably noticed it is a symmetric matrix.

我们如何从中获得一个度量词之间语义相似性的指标呢?为此,你需要一次说三个词。让我具体记下这句话。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The behavior of P_ik/P_jk for various words (Source [1])

考虑实体

P _ ik/P _ JK其中P _ ik = X _ ik/X _ I****

这里的 P_ik 表示同时看到单词 ik 的概率,通过除以同时出现 ik**(X _ ik)的次数来计算****

你可以看到,给出两个词,即,如果第三个词(也叫“探针词”),******

  • 与冰很相似但与蒸汽无关(如k=固体) P_ik/P_jk 会很高(> 1),******
  • 与蒸汽很相似但与冰无关(如k*=气体)P _ ik/P _ JK会很小(< 1),*****
  • 与任一单词相关或不相关,那么P _ ik/P _ JK将接近 1****

因此,如果我们能够找到一种方法将P _ ik/P _ JK结合到计算单词向量中,我们将实现在学习单词向量时使用全局统计的目标。****

从度量到词向量

如果你喜欢到目前为止,系好安全带。就要变得粗暴了!我们如何能得到一个字向量算法并不是很明显,

  • 我们没有方程,例如 F(i,j,k) = P_ik/P_jk ,只是一个表达式。
  • 词向量是高维向量,然而 P_ik/P_jk 是标量。所以存在维度不匹配。
  • 涉及三个实体( i,j ,和 k )。但是用三个元素计算损失函数可能会很麻烦,需要减少到两个。

回答这三个问题是 GloVe 的主要贡献。现在让我们一步一步地浏览 GloVe,看看回答这三个问题如何给我们一个词向量算法。

我使用下面的符号,由于在介质上渲染乳胶的困难,它与论文略有不同。

  • wu —两个独立的嵌入层
  • *******w —w 的转置
  • X —共生矩阵
  • bwbu —分别为 w 和 u 的偏差

让我们假设一个等式

回答第一个问题很容易。假设一下。假设有一个函数 F,它接受字向量 ijk ,输出我们感兴趣的比率。

F(w _ I,w_j,u _ k)= P _ ik/P _ JK

现在你应该有点好奇了,因为我们看到两个嵌入层在播放( wu)。为什么是两个?该论文称,通常这两层的性能相当,只是随机初始化不同。然而,有两层有助于模型减少过度拟合****

现在回到函数。词向量是线性系统。例如,您可以在嵌入空间中执行算术运算,例如

w _ {国王}—w _ {男性}+w _ {女性} = w _ {女王}

因此,让我们将上面的等式改为下面的等式,

F(w_i — w_j,u_k) = P_ik/P_jk

为什么 w_i — w_j 适合这里?其实你可以在嵌入空间中推导出你观察到的关于 P_ik/P_jk 的美好性质。我来详细说明一下。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Behaviour of vector distances to a probe word w.r.t. w_i — w_j

所以你可以看到当考虑不同的单词时,距离(虚线)是如何变化的。以及两个给定词 ik 之间的距离,与 P_{ik} 的倒数相关。为什么会这样呢?因为我们总是计算距离 w.r.t 字向量 w_i — w_j (即红线)。所以从 w_i — w_j. 开始也未尝不可

向量到标量…

一个问题解决了,我们继续下一个问题。我们如何使 LHS 成为标量?对此有一个非常直接的答案。也就是用下面的方法在两个实体之间引入一个转置和一个点积。

*F((w_i — w_j)。u_k) = P_ik/P_jk 或者,

*如果假设一个字向量为一个 Dx1 矩阵, (w_i — w_j) 将被 1xD 整形,从而在与 u_k 相乘时给出一个标量。

F 能是什么?

接下来,如果我们假设 F 有某个性质(即 加法群和乘法群之间的同态 )给出

F(w _ I * u _ k—w _ j * u _ k)= F(w _ I * u _ k)/F(w _ j * u _ k)= P _ ik/P _ JK

换句话说,这种特殊的同态确保了减法【A-B】也可以表示为除法 F(A)/F(B) 并得到相同的结果。因此,

F(w _ I * u _ k)/F(w _ j * u _ k)= P _ ik/P _ JK

F(w _ I * u _ k)= P _ ik

我对你耍了点小花招…

好吧,我是偷偷摸摸的。仅仅因为 F(A)/F(B) = G(A)/G(B)你不能说 F(A) = G(A)。因为 F(A)/F(B)=2F(A)/2F(B),不代表 F(A)=2F(A)。从最初的论文来看,并不清楚(至少对我来说)为什么这样假设。但是让我给你一些直觉,为什么这是一个安全的假设。如果我们要正确定义上述关系,它应该是,

F(w _ I * u _ k)= c P _ ik对于某些常数 c

但有了这个,你也得到了 F(w_j u_k) = c P_jk 对于任意的 j 。所以如果 ik 之间的相似度按 c 增长,那么 jk (对于任意一个jc之间的相似度也将按 增长。这意味着(在某种程度上)所有的单词向量将按系数 c 放大/缩小,这不会有任何损害,因为相对的拓扑被保留了。***

继续,如果我们假设 F=exp, 满足上述同态性质。那么让我们开始吧,

Exp(w _ I * u _ k)= P _ ik = X _ ik/X _ I

w _ I * u _ k = log(X _ ik)—log(X _ I)

接下来, X_i 独立于 k ,我们把 log(X_i) 移到 LHS,

w _ I * u _ k+log(X _ I)= log(X _ ik)

注意,如果没有项 log(X_i) ,即 ik 可以互换,则上述等式将具有对称性。我们可以添加一个 bias b_i 来吸收 log(X_i) 并添加另一个 b_k 来恢复对称性。所以,我们会有点创意,用神经网络的说法来表达 log(X_i)

w_i u_k + b_i +b_k= log(X_ik)*

或者,

w_i u_k + b_i +b_k — log(X_ik) = 0*

其中b _ Ib _ k是网络的偏差。**

定义成本

在一个理想的设置中,你有完美的词向量,上面的表达式将是零。换句话说,这就是我们的目标。所以我们将把 LHS 表达式作为我们的成本函数。

J(w_i,w _ J)=(w _ I * u _ J+b _ I+b _ J—log(X _ ij))

注意,平方使其成为均方成本函数。对最初的发现没有损害。k 也被 j 代替了。

最终成本函数

但是你的工作并没有到此为止,你还需要解决一个重要的理论问题。思考一下如果 X_ik = 0 会发生什么。如果你对上面的成本函数做一个小实验,你会看到一个 ML 从业者最讨厌的 3 个字母,即【NaN】。因为 log(0)未定义。简单的解决方法是使用被称为拉普拉斯平滑的 log(1+X_ik) 。但是手套纸背后的杰出人物提出了一种更时髦的方法。即引入一个加权函数。**

j = f(x_ij)(w_i^t u _ j+b _ I+b _ j—log(x _ ij))

其中f(x _ ij)=(x/x_{max})^aifx<x _ { max }else0******

结论

一切都结束了。GloVe 是一种利用语料库的全局和局部统计的词向量技术,以便提出使用这两者的原则性损失函数。GloVe 通过解决三个重要问题来做到这一点。

  • 我们没有方程,例如 F(i,j,k) = P_ik/P_jk ,只是一个表达式(即 P_ik/P_jk )。
  • 单词向量是高维向量,然而 P_ik/P_jk 是标量。所以存在维度不匹配。
  • 涉及三个实体( i,j ,和 k )。但是用三个元素计算损失函数可能会很麻烦,需要减少到两个。

提供了用 Keras 实现手套的代码【此处为

如果你喜欢我分享的关于数据科学和机器学习的故事,考虑成为会员吧!

**** [## 通过我的推荐链接加入媒体

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

thushv89.medium.com](https://thushv89.medium.com/membership)****

想在深度网络和 TensorFlow 上做得更好?

检查我在这个课题上的工作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

[1] (书)TensorFlow 2 在行动——曼宁

[2] (视频教程)Python 中的机器翻译 — DataCamp

[3] (书)TensorFlow 中的自然语言处理 1 — Packt

新的!加入我的新 YouTube 频道

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你渴望看到我关于各种机器学习/深度学习主题的视频,请确保加入 DeepLearningHero

参考:

[1] GloVe:单词表示的全局向量(原文

XGBOOST vs LightGBM:哪种算法赢得了比赛!!!

原文:https://towardsdatascience.com/lightgbm-vs-xgboost-which-algorithm-win-the-race-1ff7dd4917d?source=collection_archive---------3-----------------------

这篇文章是关于在人口普查收入数据集上对 LightGBM 和 XGBoost 进行基准测试。我注意到 XGBoost 的执行时间比 LightGBM 慢。下面我们来深挖更多细节,了解一下各种参数对比时哪个更胜一筹。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Tim Gouw on Unsplash

增压机的发展从 AdaBoost 开始,到今天被大肆炒作的 XGBOOST。XGBOOST 已经成为在 Kaggle 赢得比赛的事实上的算法,仅仅是因为它非常强大。但是考虑到大量的数据,即使 XGBOOST 也需要很长时间来训练。

来了…轻 GBM 入图。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Timeline

你们中的许多人可能对灯光渐变很熟悉,但是读完这篇文章后你会有一个坚实的理解。你会想到的最自然的问题是——为什么是另一个助推机器算法?比 XGBOOST 快吗?

嗯,你猜对了!!!在本文中,我们将通过一个例子来比较 Light GBM 和 XGBoost 及其性能。

本故事中要讨论的副主题:

  1. 什么是轻 GBM?
  2. 轻型 GBM 的优势
  3. 结构差异
  4. 了解参数
  5. 数据集上的实现
  6. 每种算法的性能
  7. 参数调整
  8. 结束注释

什么是轻 GBM?

Light GBM 是一个基于决策树算法的快速、分布式、高性能梯度提升框架,用于排序、分类和许多其他机器学习任务。

由于它是基于决策树算法的,所以它以最佳拟合的方式分裂树的叶子,而其他 boosting 算法以深度或级别方式分裂树,而不是以叶子方式。因此,当在轻量级 GBM 中生长在同一片叶子上时,逐叶算法可以比逐级算法减少更多的损失,从而导致更好的准确性,这是任何现有的 boosting 算法都很少能达到的。

之前是轻型 GBM 制造商的示意图,以清楚地解释差异。

轻型 GBM 的优势

  1. 更快的训练速度和更高的效率 : Light GBM 使用基于直方图的算法,即将连续的特征值放入离散的箱中,加快了训练过程。
  2. **更低的内存使用率:**将连续值替换为离散值,从而降低内存使用率。
  3. **比任何其他 boosting 算法更高的准确性:**它通过遵循逐叶分裂方法而不是逐层方法来生成更复杂的树,逐层方法是实现更高准确性的主要因素。但是,有时会导致过度拟合,这可以通过设置 max_depth 参数来避免。
  4. **与大型数据集的兼容性:**与 XGBOOST 相比,它能够以显著减少的训练时间在大型数据集上表现得同样好。

LightGBM 和 XGBoost 的结构差异

LightGBM 使用一种新颖的基于梯度的单侧采样(GOSS)技术来过滤数据实例,以找到拆分值,而 XGBoost 使用预先排序的算法&基于直方图的算法来计算最佳拆分。这里的实例是观察/样本。

简而言之,基于直方图的算法将一个特征的所有数据点分割成离散的仓,并使用这些仓来找到直方图的分割值。虽然它在训练速度上比列举预排序特征值上所有可能的分裂点的预排序算法更有效,但是在速度上它仍然落后于 GOSS。

那么是什么让这种高斯方法变得高效呢?
GOSS(Gradient Based One Side Sampling)是一种基于梯度对实例进行下采样的新型采样方法。正如我们所知,梯度小的实例训练良好(训练误差小),梯度大的实例训练不足。一种简单的下采样方法是通过只关注具有大梯度的实例来丢弃具有小梯度的实例,但是这将改变数据分布。简而言之,GOSS 保留具有大梯度的实例,同时对具有小梯度的实例执行随机采样。

轻型 GBM 的重要参数:

*num_leaves*:要使用的叶节点数。拥有大量的叶片会提高精度,但也会导致过度拟合。

*min_child_samples*:分组到一个叶中的样本(数据)的最小数量。该参数可以大大有助于过度拟合:每片叶子较大的样本大小将减少过度拟合(但可能导致欠拟合)。

*max_depth*:明确控制树的深度。较浅的树减少过度拟合。

不平衡数据的调优

说明不平衡或偏斜数据的最简单方法是增加正面类别示例的权重:

*scale_pos_weight*:可以根据正反例的数量计算权重:*sample_pos_weight = number of negative samples / number of positive samples*

过拟合调谐

除了上述参数之外,以下参数可用于控制过度拟合:

*max_bin*:存放特征值的最大箱数。较小的*max_bin*减少了过度配合。

*min_child_weight*:一片叶子的最小和麻。结合*min_child_samples,*,较大的值可减少过度拟合。

*bagging_fraction**bagging_freq*:对训练数据进行打包(子采样)。这两个值都需要设置,以便装袋使用。频率控制使用(迭代)装袋的频率。较小的分数和频率减少了过度拟合。

*feature_fraction*:控制用于训练的特征的二次抽样(与装袋情况下对实际训练数据的二次抽样相反)。较小的分数减少了过度拟合。

*lambda_l1**lambda_l2*:控制 L1 和 L2 的正规化。

精确调谐

通过调整以下参数可以提高精度:

*max_bin*:较大的*max_bin*增加精度。

*learning_rate*:使用较小的学习率,增加迭代次数,可能会提高精度。

*num_leaves*:增加叶片数可以提高精度,但过度拟合的风险很高。

XGBoost 的重要参数:

XGBoost 作者将总体参数分为 3 类:

  1. **通用参数:**引导整体运行
  2. **助推器参数:**在每一步引导单个助推器(树/回归)
  3. **学习任务参数:**指导优化执行

一般参数

这些定义了 XGBoost 的整体功能。

1。booster [default=gbtree]

选择每次迭代运行的模型类型。它有两个选项:

gbtree:基于树的模型

gblinear:线性模型

2。无声[默认值=0]:

静音模式激活设置为 1,即不打印任何运行消息。

通常最好保持为 0,因为这些消息可能有助于理解模型。

3。n thread[如果未设置,则默认为最大可用线程数]

这用于并行处理,应输入系统中的内核数量

如果您希望在所有内核上运行,则不应输入值,算法将自动检测。

助推器参数

虽然有两种类型的助推器,我在这里只考虑树助推器,因为它总是优于线性助推器,因此后者很少使用。

1。eta[默认值=0.3]

类似于 GBM 中的学习率

通过缩小每一步的权重,使模型更加健壮

要使用的典型最终值:0.01–0.2

2。最小 _ 子 _ 体重[默认值=1]

定义子代中所需的所有观察的最小权重和。

这类似于 GBM 中的 min_child_leaf ,但不完全相同。这是指观察值的最小“权重和”,而 GBM 具有最小“观察值数”。

用于控制过度拟合。较高的值会阻止模型学习可能高度特定于为树选择的特定样本的关系。

过高的值会导致拟合不足,因此应该使用 CV 进行调整。

3。max_depth [default=6]

树的最大深度,与 GBM 相同。

用于控制过度拟合,因为较高的深度将允许模型学习特定样本的特定关系。

应使用 CV 进行调整。

典型值:3–10

4。max_leaf_nodes

树中的最大终端节点或叶子数。

可以代替 max_depth 进行定义。由于二叉树被创建,深度“n”将产生最大的 2^n 叶。

如果这样定义,GBM 将忽略 max_depth。

5。伽玛[默认值=0]

只有当产生的分裂给出损失函数的正减少时,节点才被分裂。Gamma 指定进行分割所需的最小损失减少量。

使算法保守。这些值可能因损失函数而异,应该进行调整。

6。max _ delta _ step[默认值=0]

在最大增量步骤中,我们允许每棵树的重量估计为。如果该值设置为 0,则表示没有约束。如果将其设置为正值,则有助于使更新步骤更加保守。

通常,这个参数是不需要的,但是当类别极度不平衡时,它可能有助于逻辑回归。

这通常不被使用,但是如果你愿意,你可以进一步探索。

7。子样本[默认值=1]

同 GBM 子样本。表示每棵树随机抽样的观察分数。

较低的值使算法更加保守,并防止过度拟合,但太小的值可能会导致拟合不足。

典型值:0.5–1

8。λ[默认值=1]

关于权重的 L2 正则化项(类似于岭回归)

这用于处理 XGBoost 的正则化部分。虽然许多数据科学家不经常使用它,但应该探索它以减少过度拟合。

9。alpha[默认值=0]

权重上的 L1 正则化项(类似于套索回归)

可以在非常高的维数的情况下使用,使得算法在实现时运行得更快

10。scale _ pos _ weight[default = 1]

在高等级不平衡的情况下,应该使用大于 0 的值,因为它有助于更快收敛

学习任务参数

这些参数用于定义每一步要计算的指标的优化目标。

  1. 目标[default=reg:linear]

这定义了要最小化的损失函数。最常用的值有:

二进制:逻辑回归–二进制分类的逻辑回归,返回预测概率(非类别)

multi:softmax–使用 soft max 目标的多类分类,返回预测的类(不是概率)

multi:soft prob–与 softmax 相同,但返回属于每个类别的每个数据点的预测概率。

2。eval_metric [根据目标的默认值]

  • 用于验证数据的指标。
  • 对于回归,默认值为 rmse,对于分类,默认值为 error。
  • 典型值包括:

rmse —均方根误差

mae —平均绝对误差

对数损失 —负对数可能性

错误 —二值分类错误率(0.5 阈值)

误差 —多类分类误差率

mlogloss —多类 logloss

auc: 曲线下面积。

数据集上的实现:

现在让我们比较 LightGBM 和 XGBoost,将这两种算法应用于人口普查收入数据集,然后比较它们的性能。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Dataset Information

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Loading the data

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Data Description

在上面的数据集上运行 Light GBM 和 XGboost 之后。结果是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Evaluation metrics: Accuracy, auc_score & execution time (Model 1)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Evaluation metrics: Accuracy, rsme_score & execution time (Model 2)

与 LightGBM 相比,XGBoost 在准确性、AUC 评分和 rsme 评分方面仅略有增加,但在训练程序的执行时间方面存在显著差异。与 XGBOOST 相比,Light GBM 非常快,并且在处理大型数据集时是一种更好的方法。

当你在有限时间的比赛中处理大型数据集时,这是一个巨大的优势。

参数调整:

对于 XGBOOST

这些是为模型 1 设置的参数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Parameters for XGBoost — Model 1

模型 1 的精确度:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这些是模型 2 的参数:正在调整参数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Parameters Tuning for XGBoost — Model 2

模型 2 的精确度:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们可以看到的,随着参数的调整,我们的模型的准确性几乎没有增加。

对于 LightGBM:

这些是为模型 1 设置的参数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Parameters for LightGBM — Model 1

模型 1 的精确度:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这些是模型 2 的参数:正在调整参数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Parameters for LightGBM — Model 2

模型 2 的精确度:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们可以看到的,随着参数的调整,我们的模型的准确性几乎没有增加。

结束注释

在本文中,我试图比较 Light GBM 和 XGBoost 的性能。使用这种 LightGBM 的一个缺点是用户基础狭窄——但这种情况正在迅速改变。这种算法除了比 XGBOOST 更精确、更省时之外,由于可用的文档较少,它的使用受到了限制。然而,该算法已经显示出好得多的结果,并且已经胜过现有的提升算法。

您可以在我的 GitHub 资源库中找到完整的代码。

[## nikhileshorg/light GBM-vs-XGBoost

在 GitHub 上创建一个帐户,为 Nikhileshorg/light GBM-vs-XGBoost 开发做出贡献。

github.com](https://github.com/Nikhileshorg/LightGBM-vs-XGBoost)

关于 LightGBM,XGBoost 或者与本帖相关的有什么问题吗?留下评论,提出你的问题,我会尽力回答。

感谢阅读!❤

不平衡数据集中焦点损失的 LightGBM

原文:https://towardsdatascience.com/lightgbm-with-the-focal-loss-for-imbalanced-datasets-9836a9ae00ca?source=collection_archive---------3-----------------------

焦损失(以下简称 FL)是由宗-林逸等人在他们 2018 年的论文*“密集物体探测的焦损失”* [1]中引入的。它被设计成解决具有极端不平衡类别的情况,例如前景和背景类别之间的不平衡可以是例如 1:1000 的一阶段对象检测。

在这篇文章中,我将展示如何为light GBM【2】(以下简称 LGB)编写 FL,并演示如何使用它。配套的 github repo 可以在这里找到。不幸的是,我找不到公开的真正具有挑战性的不平衡数据集。python 中的不平衡学习 [3]包附带的数据集相对容易,LGB 不需要任何技术来处理不平衡数据集就能产生良好的结果。另一个选择是 Kaggle 的信用卡欺诈检测数据集。然而,这也是一个非常容易的数据集,LGB 产生了非常好的结果“开箱即用”。

尽管如此,因为这篇文章的目标是展示 LGB 的 FL 代码以及如何使用它,所以我简单地挑选了两个众所周知的数据集,然后继续。这些是成人普查数据集和已经提到的信用卡欺诈检测数据集。

我们需要遵循这个代码中的代码的小数学是这个帖子可以写成如下。考虑二元分类问题,我们可以将 p_t 定义为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Eq 1 (Eq 2 in Tsung-Yi Lin et al., 2018 paper)

其中,y ∈ { ∓ 1}指定地面实况类,p ∈ [0,1]是标注 y = 1 的类的模型估计概率。那么交叉熵可以写成:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Eq2. Binary Cross Entropy

根据该公式,焦点损失定义为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Eq3 (Eq 5 in their paper)

让我们看看它的行为,如图 1 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Figure 1 (Figure 1 in their paper). The figure shows the Focal Loss plotted against pt. Note that for γ=0 the FL is equal to the CE. We can see that the factor (1 − pt) γo the standard cross entropy criterion. Setting γ > 0 reduces the relative loss for well-classified examples (pt > .5).

正如我们在图中看到的,设置γ > 0 减少了分类良好的例子的相对损失(pt > .5),把更多的注意力放在困难的、错误分类的例子上。引用作者的话:“当γ = 2 时,与 CE 相比,pt = 0.9 的示例的损耗低 100 倍,pt ≈ 0.968 的示例的损耗低 1000 倍”。

这就是我们现在需要的所有数学知识。

光焦度损失

使用 LGB 时,为了编写您自己的损失函数,您需要损失数学表达式及其梯度和 hessian(即一阶和二阶导数)。光 GBM焦损可以简单编码为:

Focal Loss implementation to be used with LightGBM

如果只有一段代码可以从这篇文章中“拯救”出来,那就是上面的代码片段。

如果你要将 FL 和 LGB 一起使用,你可能需要编写相应的评估函数。在这种情况下,该函数需要返回名称、目标函数的值以及一个布尔值,该值指示值越高越好:

Evaluation Focal Loss function to be used with LightGBM

例如,如果不使用 F1 作为目标函数,您更喜欢 F1 分数这样的指标,您可以使用以下代码:

f1 score with custom loss (Focal Loss in this case)

注意第 2 行中的 sigmoid 函数。这是因为当使用您自己的损失函数时,直接来自算法的原始预测不会通过 sigmoid 来表示概率。

要将 FL 与 LGB 一起用于训练,只需:

How to use the Focal Loss for training with LightGBM

或者通过 F1 分数和交叉验证:

How to use the Focal Loss for LightGBM with cv and F1 as the evaluation metric

结果

如前所述,我使用了两个数据集,人口普查数据集和信用卡欺诈检测数据集。对于每个数据集,我运行两个实验:1)使用设置为Trueis_unbalance参数(如果少数类是正类,这相当于使用scale_pos_weight)和 2)使用 FL。我使用 Hyperopt 进行超参数优化,针对 F1 分数进行优化,每个实验运行 100 次迭代,每次迭代都进行交叉验证(3 次,即每个实验 300 次拟合)。我根本没有使用过/欠采样。本文引用的所有代码都可以在这里找到。

Table 1. Performance metrics for the experiments run in this post with and without Focal Loss

结果如表 1 所示。需要强调的是,正如本文前面提到的, 这两个数据集都不适合这里的 练习。事实上,成人人口普查数据甚至没有不平衡。因此,先验地,人们不会期望在有和没有 FL 的情况下获得的度量之间有大的变化。然而,表中的结果说明了 FL 的潜力。例如,两个数据集的 F1 分数都增加了 2%。此外,在信用卡欺诈检测数据集的情况下,所有的 F1、精度召回提高了 2%或更多。

对此,我可以补充一点,我已经在几个真实数据集和相关的改进中使用了 FL,在不平衡率为 2:100 的数据集上,所有性能指标都一致提高了约 5%。我的一些同事告诉我,他们看到了更大的改善。

为了结束这一部分,让我们来看看聚焦损耗中的α和γ参数:

Table 2. Focal loss α and γ parameters

较高的γ值将较大地减少分类良好的样本的相对损失,将更多的注意力放在难以分类的样本上。因此,这些结果可以解释如下。成人数据集虽然不是不平衡的,但对于算法来说,它比信用卡欺诈数据集*【更具挑战性】*。为了获得最好的 F1 分数,我们需要较大的γ值,将大量的“焦点放在硬的、错误分类的样本上。

**is_unbalance**参数

到目前为止,当使用 FL 时,我已经将is_unbalance 参数设置为False. ,注意也可以同时使用 FL 和is_unbalance=True。为了理解使用两者的含义,让我们首先假设树集成方法的目标函数的一般形式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Eq 4. This is actually Eq 3 in Tianqi Chen & Carlos Guestrin 2016 XGBoost paper [4].

其中 f _t 是树在第 t 次迭代时的函数, gh 分别是梯度和 Hessian。

如果我们看一下 c++代码的这里的,我们可以看到设置is_unbalance = True仅仅意味着,当计算损失时,少数类的标签权重将是两个类之间的比率(count _ majority/count _ minority)。如果我们再看这里的,在 sklearns API 中,我们看到在计算目标函数时,这些权重直接乘以梯度和 Hessian。

现在假设我们有一个不平衡比率为 1:9 的数据集,我们取两个样本,一个正(少数)样本和一个负(多数)样本,预测概率 p=0.9。现在假设α和γ分别为 1.0 和 2.0。如前所述,在这种情况下,FL 中的因子α(1-p)^γ会将这两个样本的相应损耗值减少 100 倍。换句话说,FL 试图把重点放在更难的、错误分类的样本上。

假设,为了计算目标,LGB 使用类似于等式 3 的表达式,并且我们设置is_unbalanced=True, 相应的梯度和焦点损失的 Hessian 将仅对于正(少数)样本乘以因子 9。换句话说,设置is_unbalanced=True将增加少数类样本对目标的贡献,而不管它们是否被很好地分类。

因此,在我看来,焦点损失和is_unbalance=True对于分类良好且属于少数类的样本是竞争效应。尽管如此,我已经使用 FL 和设置is_unbalance=True对 2 个数据集进行了实验,结果与表 1 中的几乎相同。

替代方法

在这篇文章中,我只是想展示如何为 LGB 编写 FL 并演示如何使用它。然而,让我简单地提一下我在这里没有探讨的一些替代技术。

使用 LGB 时,您可以直接传递与每个观察相关的权重。这也是一个值得你公司探索的好方法。也许你有一些启发,或使用一些无监督的技术,导致你的结论是,一些样本比其他的更重要。在这种情况下,您可以考虑为每个观察传递一个权重来反映这一先验知识。这可以通过简单地使用lightgbm.Dataset类中的参数weight 来实现。使用 FL 或使用weight参数都被称为成本敏感学习技术。

另一种技术是重新采样。正如我提到的,我没有使用任何欠采样/过采样。如果你想探索重采样技术,你可以在著名的 python 包 unbalanced-learn 中找到相当全面的资料。另一种我觉得特别有趣的更近期、更有前途的欠采样技术在 Ehsan Montahaei 等人 2018[5]中讨论过,如果你想更深入地了解重采样技术的话。

仅此而已。有什么想法,在这里评论或者发邮件给我:jrzaurin@gmail.com

参考资料:

[1]宗-林逸,普里亚·戈亚尔,罗斯·吉斯克等人,2018: 密集物体探测的焦损失arXiv:1708.02002 v2

[2]郭林·柯,,托马斯·芬利等,2017: LightGBM: 一种高效的梯度推进决策树

[3]纪尧姆·勒迈特,费尔南多·诺盖拉,克里斯特斯·k·阿里达斯 2017:不平衡学习:一个 Python 工具箱,解决机器学习中不平衡数据集的诅咒。

[4]陈天琦,Carlos Guestrin 2016: XGBoost:一个可扩展的树提升系统。arXiv:1603.02754 v3

[5] Ehsan Montahaei,Mahsa Ghorbani,Mahdieh Soleymani Baghshah,Hamid R. Rabiee 2018:不平衡问题的对抗性分类器。arXiv:1811.08812 v1

莱姆:解释机器学习模型的预测(1/2)

原文:https://towardsdatascience.com/lime-explaining-predictions-of-machine-learning-models-1-2-1802d56addf9?source=collection_archive---------17-----------------------

在我之前的博客中,我提到了以下理解模型预测的基本技术。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Alex Bertha on Unsplash

  1. 使用基尼指数的特征重要性
  2. 使用排列重要性的特征重要性
  3. 部分相关图

首先,我想问一个问题:“我们可以仅仅因为模型在测试数据上的表现令人信服地高,就相信模型的预测吗?”许多人可能会回答这个问题为【是的】。但这并不总是正确的。高模型性能不应被视为信任模型预测的指标,因为模型拾取的信号可能是随机的,可能没有商业意义。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这篇博客中,我将谈论 LIME,一种在实例层面上帮助理解预测背后的原因的方法。这是一种与模型无关的技术,也就是说,你可以将它用于任何模型,无论是神经网络、基于树的模型、支持向量机等等。

LIME 代表LocalIn interpretableModel-AgnosticE解释。对许多人来说,本地这个词似乎是最令人困惑的。所以我先来解释一下为什么这个词本地

目标和自变量之间的关系在全局水平上可能变得非常复杂,例如参考下图。查看这个全局视图并不能提供太多关于独立特征和目标之间关系的洞察,所以 LIME 放大在非常非常局部的水平上进行。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们假设被解释的实例用绿色星号标记。LIME 背后的主要直觉是,在放大和局部分析目标和独立特征之间的关系之后,我们可以使用线性模型来近似这种关系。

现在,让我们了解石灰的工作步骤:

  • 对原始数据中靠近绿色星号的实例进行采样和 SMOTE 处理(正在解释实例)
  • 计算采样实例和被解释实例之间的距离
  • 对于这些合成生成的实例,使用原始全局模型进行预测
  • 对此数据集拟合一个简单的线性模型
  • 基于在步骤 2 中计算的相似性指数对该线性模型进行加权。这是为了确保最接近原始实例的实例上的错误比其他实例更有价值

现在让我们进入例子来解释石灰的结果。我已经使用了来自 Kaggle 的数据集。目标是确定拖欠信用卡付款的最强预测因素。我安装了一个 Scikit-learn 实现的梯度增强树。

Correctly classified *‘Non Default Payment’* instance:

橙色表示贡献给*‘违约金’,蓝色表示贡献给‘非违约金’。*全局模型对此实例的预测是 0.072,而局部模型的预测是 0.066。所以,对于这个特殊的例子,全局模型和局部模型的预测非常接近。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上面的例子表明,这个被标记为*‘非违约付款’*的特定实例的主要贡献者是上个月的还款状态( PAY_0 = 1 )。这意味着在前一个月付款是按时完成的。其他变量的解释也类似( PAY_2,PAY_3 等)。).这表明,如果前几个月的付款按时完成,那么这个人下个月不违约的可能性很高。

LIMIT_BAL 的高金额也促成了非违约付款。这也是有意义的,因为高 LIMIT_BAL 意味着剩余补充信用低。因此,下个月的账单有可能会很低,因此违约的几率会更小。现在,对于连续要素,LIME 的输出提供了更多详细信息,因为它指定了导致该要素产生影响的一系列特征值。例如’限额 _ 余额> 24 万’

我个人认为分析错误预测的实例是非常有见地的。这有助于理解哪些特征实际上导致了预测不正确。

Incorrectly classified *‘Non Default Payment’* instance (Actual: *‘Default Payment’*):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于表示先前付款历史的特征( PAY_0PAY_2PAY_3 ),上述实例被错误地预测为非违约付款。在这种情况下,以前的付款是按时完成的。这可能使预测变得不正确。

根据上面的例子,石灰的一般概念听起来是合理的,但是石灰也有一些潜在的缺点。

**1\. Local linear behavior**

LIME 目前在本地实现线性模型来获得解释。而这种假设对于正在解释的实例周围的小区域是有效的。但是对于更复杂的数据集,随着我们增加局部区域的面积,这个假设可能不成立。因此,来自局部可解释模型的解释可能无法解释全局线性模型的行为。

**2\. Number of features**

需要优化选择用于解释的特征的数量。应该选择特征的数量,以便保持模型的复杂性和解释的简单性。在 LIME 的 python 实现中,它提供了以下选项:‘forward _ selection’,‘lasso _ path’,‘none’或‘auto’

**3\. Models without probability scores**

LIME 目前不支持没有概率分数的分类器模型。

**4\. No aggregated view**

LIME 实现不提供特性解释的聚合视图。用户必须依次分析各个实例。

**5\. Similarity score**

对于表格数据,LIME 通过单独扰动每个要素来创建新样本,从正态分布中提取该要素的平均值和标准差。对于连续特征,LIME 提供了一个选项,用于从以被解释的实例为中心的法线或从以特征数据集的平均值为中心的法线扰动样本。越靠近感兴趣的实例,样本的石灰权重越高。现在,在高维空间中,每个特征具有不同范围的值,计算相似性指数具有挑战性,并且可能不会产生清晰的结果。

**6\. Definition of the neighborhood**

定义一个正确的邻域来运行局部可解释模型是一个困难的问题。那么,为什么我们需要沿着被解释的实例定义一个局部邻域呢?解释模型对原始模型的准确性是通过在由局部核加权的简化输入空间中的一组样本上的损失函数来加强的。目前,LIME 使用指数平滑内核。这个内核的宽度决定了对正在解释的实例的局部模型的影响,同样,没有确定内核宽度的最佳方法。

**7\. Consistency of the model explanations**

由于采样偏差、相似性得分的计算和邻域的定义,石灰解释有时可能缺乏一致性。

结论:

LIME 提供了非常简单的可解释的解释,并且是分析每个特征的贡献的快速方法。LIME 也可以用于文本和图像数据,与其他可解释的技术(如 SHAP)相比,LIME 的执行时间更少。我喜欢 LIME 的另一个特性是,局部代理模型实际上可以使用独立的特性,而不是全局模型中使用的特性。

其他阅读资源:

  1. https://www . KDD . org/KDD 2016/papers/files/RFP 0573-ribeiroa . pdf
  2. 【https://github.com/marcotcr/lime
  3. https://christophm . github . io/interpretable-ml-book/lime . html

下一步是什么?

在下一篇博客中,我将解释另一种流行的技术:用于解释模型预测的 SHAP。

这个可解释的人工智能领域正在迅速发展,在工具和框架方面有很多新的发展。请在评论区写下你对博客的反馈,以及你在这个领域使用的最新工具。此外,如果你想让我写任何特定的主题,请发表评论。

这些内容最初发表在我的个人博客网站:http://datascienceninja.com/。点击此处查看并订阅即时接收最新博客更新。

Limericking 第 1 部分:背景和俳句。

原文:https://towardsdatascience.com/limericking-part-1-context-and-haikus-3eb057c8154f?source=collection_archive---------23-----------------------

石灰工程

使用自然语言处理产生诗歌

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Watson: Jeopardy champ and future poet laureate?

机器学习和数据科学中最令人兴奋的领域之一是自然语言处理。让一台机器能够解析并生成听起来像人类的语言,这既有巨大的实用价值,也是众所周知的困难。人类的语言是混乱的,充满了计算机无法处理的那种不规则性。即使是相对简单的任务,比如标记一个给定单词的词性,也可能很难,并且依赖于上下文(permit 是名词还是动词?).

即使是最强大、最成功的 NLP 实现也会让人感觉有些不舒服。我仍然非常清楚地记得观看 IBM 的沃森与全明星肯·詹宁斯和布拉德·鲁特一起玩 Jeopardy。沃森的表现确实令人印象深刻,在两天的比赛中,沃森最终轻松获胜,但有时它感觉机器并没有真正执行它被设计来做的任务——正确解释自然语言——一点也不出色。在一场最后的危险游戏中,沃森在“美国城市”类别中找不到正确答案,他猜是多伦多:

如果沃森真的能够理解这项任务,它大概至少会猜对一个国家的城市,尽管我不完全相信它不是在故意开玩笑。我还记得在常规播放中的一个线索,询问了甲壳虫乐队的歌曲“挥舞银锤”的名字麦克斯韦尔,沃森回答了整个短语“麦克斯韦尔的银锤”。他们给沃森的回答加分,但也许他们不应该这样。沃森可以建立足够的联系来判断线索在问哪首歌,但不知道线索实际上在问什么。

这一切只是为了重申自然语言处理是辛苦的!将维基百科的全部内容输入一台最先进的超级计算机是很容易的。即使是最先进的超级计算机也能理解基本英语,这需要极大的创造力。

我对计算机生成文本的能力特别感兴趣。沃森相对容易,因为危险反应遵循严格的模式。让计算机生成更长更复杂的段落,尤其是那些需要恰当的变化和一致的段落,怎么样?在这篇文章中,也可能在未来的一系列文章中,我想探索如何生成这样的文本,着眼于创作热门打油诗。

这篇文章的灵感来自 twitter 账户 Limericking 。打油诗背后的匿名天才在新闻报道后写打油诗。出于我无法完全说清楚的原因,我认为利默瑞金的打油诗中最好的确实非常出色,是我所知道的最好的现代诗歌中的一些:

A brilliant limerick about rising tensions with Iran

我一直在考虑将 Limericking 的输出自动化的所有事情。你能输入一篇新闻文章,让计算机产生一首热门打油诗吗?其他尝试产生像这样的样式化文本的方法是使用递归神经网络,该网络在输入语料库上被训练,它们将试图模仿该输入语料库。例如,这位数据科学家用莎士比亚训练了一个 RNN,在超过 19 个小时的大约 35000 个训练步骤之后,计算机产生了这个文本片段:

泰特斯·安德洛尼克斯:

现在,我的安全和死亡是什么?

国王理查德二世:

你认为会有什么结果?

这是什么?

结果是非常令人印象深刻的,完全缺乏。这篇课文无疑是莎士比亚的,但毫无意义。这种不直接的方式擅长模仿风格,但不擅长产生“意义”。你可以想象用足够多的打油诗来训练 RNN,让它对格式有所了解,但是这个网络需要有多深才能创造出清晰的内容呢?或者让它把新闻文本处理成一首易读的摘要打油诗?

直觉上,更好的过程应该更程序化。您可以想象一个函数或一系列函数按顺序执行以下步骤:

  1. 分析新闻文本的含义,提取关键词或中心人物
  2. 用两三句话总结一下
  3. 搜索同义词库和押韵词典,找到符合押韵方案的备选单词
  4. 重新调整新的押韵句子,以正确扫描打油诗的形式。

问题是,每一个步骤本身都是一个棘手的数据科学问题。第一步:阅读文本,找到主题或中心人物。计算机如何知道如何将文本分配给特定主题?通常,这可以通过类似于朴素贝叶斯分类器的东西来完成,该分类器查看任何给定主题中特定单词的频率(例如,包含单词“gigabyte”的文本更可能来自关于技术的文章,而提到联合国的文章更可能是关于世界事务的)。这需要一个大的、标记良好的数据集来训练你的模型,这意味着,像许多大数据问题一样,这不仅仅是一个数据科学问题,也是一个数据生产问题。(也有无人监督的文本聚类方法,尽管让计算机决定分组方式会有风险)。

也许,你认为,有一个更简单的方法。你可能会稍微欺骗一下,认为一篇文章的主题会用一个在文章中相对频繁出现的名字或名词来表示。通过将文本中最常出现的专有名词集合起来,并猜测其中一个是主题,你会比随机选择做得更好。这本身也是一个复杂的分类问题,因为虽然计算机很容易计算实例,但计算机很难区分什么是专有名词。

幸运的是,如果你像我一样,突然对打油诗产生了热情,想要一头扎进去,那么大量的资源已经存在了。自然语言工具包( NLTK )是一个强大的 Python 文本操作和分析工具库,除了许多其他东西之外,它还包含一个已经相当不错的词性标记器(如果您认为自己可以做得更好,还可以使用其他工具来构建自己的标记器)。在一系列的文章中,我想探究解析和产生文本的每一项任务,看看我是否能慢慢地建立起类似自动缩词法的功能。

为此,我决定从简单开始。而不是从头开始构建必要的工具,而是开始使用 NLTK 自带的一些工具,并致力于产生一种更简单的文本类型。与其写一首带有韵律和语法要求的打油诗,不如写一首只需要韵律的俳句。鉴于俳句如此简短,当它们是印象式的时侯,似乎效果最好,所以没有必要太关注语法。正如比利·穆雷告诉我们的,如果俳句没有意义也没关系:

以下是我的入门俳句生成器的工作原理:

  1. 它接受一个来自 NPR 的新闻文章的 id 号。为什么是 NPR?因为他们有一个非常方便的纯文本版本的网站,这应该是一个练习语言处理而不是网络抓取
  2. 检索文本并对其进行“标记”——将其转换为机器可以逐段评估的单词列表
  3. 通过为每个文本标记词性并查看最常出现的专有名词,尝试确定文本的主题——这实际上非常有效。(我的函数还通过查看文本的二元模型来检查专有名词是否是名称的一部分,也就是说,作为一个集合紧挨着出现的一组单词,并将返回完整的名称。)
  4. 它通过从集合中移除“停用词”——像“a”、“the”、“is”等常见词——并收集形容词、名词和动名词(再次感谢 NLTK 词性标记器)来收集要使用的词
  5. 单词的语料库被“词条化”——像那些标记复数的屈折词尾被删除
  6. 然后它组合俳句:如果少于 5 个音节,它将主题放在第一行,如果有 6 或 7 个音节,它将主题放在第二行。然后,它用从语料库中随机抽取的词来填充俳句的其余部分,但倾向于在文本中出现频率更高的词。

这个简单的程序产生了一些令人惊讶的暗示性结果,这证明了语言的灵活性和人类思维的创造性暗示性。鉴于这篇文章关于亚马逊考虑使用送货无人机提供家庭监控,它正确地收集了这篇文章的主题是“亚马逊”,并创作了这首俳句:

亚马逊报告

计划监督部

无人机安全

这种方式触及了问题的核心,而且看起来像人类。事实上,我认为只要在“plan”这个词后面加上一个“s ”,结果看起来甚至会合乎语法。鉴于这篇关于埃尔多拉多度假村收购凯撒赌场名气的文章,结果不太令人信服,但也不可怕:

投机运动

凯撒娱乐新闻

品牌公司名称

当然,形体短小,印象深刻的时候很容易显得印象深刻。即使是一首不太好的打油诗,要写出更长、更符合语法的作品也要困难得多。

Limericking 第 2 部分:用 LDA 进行主题建模

原文:https://towardsdatascience.com/limericking-part-2-topic-modeling-with-lda-45476ab9af15?source=collection_archive---------27-----------------------

石灰工程

没有监督的情况下找话题

欢迎来到我构建自动打油诗生成器的第 2 部分。正如我在第 1 部分中详述的,我受到了令人难以置信的 twitter 账户 Limericking 的启发,该账户根据新闻事件制作热门打油诗。我发现我更喜欢阅读打油诗形式的新闻;这些天的新闻是如此沉闷,以至于我发现越来越难以任何其他方式阅读新闻。

Why contemplate concentration camps on the border without a poem at Mike Pence’s expense?

不幸的是,Limericking twitter 帐户背后的孤独天才只能产生这么多。毕竟,每首诗都必须根据节拍、韵律和喜剧性来精心制作,所以 Limericking 每周只创作几首诗也就不足为奇了。我赞扬该账户对质量的奉献,并拒绝出版任何不到一个辉煌的打油诗,但我哀叹内容的匮乏。有没有一种方法可以自动化主题五行打油诗的制作过程(从而让我在继续阅读轻松诗的同时也能合理地了解时事)?

也许有,但不幸的是,首先需要解决一系列棘手的数据科学问题。我们的打油诗生成器需要能够接收文本并解析其含义,得出一两个总结句子(或至少一个主题和关键词/数字),然后生成有意义的文本,这些文本经过调整以适应打油诗的形式,而不会失去其连贯性。我想最重要的是,你会希望打油诗是幽默的,尽管这可能超出了我的能力。

为了支持我的第一篇文章,我把这个任务分解了,最后得到了一系列基于新闻文章的俳句。我的程序试图通过查看文本中最常出现的专有名词来确定文本的主题(这种策略通常会产生合理的结果),但在其他情况下会半随机地将单词放入俳句中:选择单词的概率由该单词在文本中出现的频率来加权。改进该计划的第一步是什么?limerick 生成器需要采取的第一步是解析文本的含义,所以这篇文章的主题是主题建模,特别是一种叫做潜在 Dirichlet 分配的方法。

主题建模本质上是一个复杂的分类问题,它提出了两个挑战。首先,虽然计算机可以对文本做一些事情,比如计算字数,但文本信息对计算机来说并没有内在的意义。人类在文本中看到的意义既有单个单词的层面,也有来自句法和句子中单词之间关系的更高层次(“猫咬了狗”和“狗咬了猫”的意思非常不同,尽管都是相同的单词)。这些意义的形式对计算机来说是困难的;第一个原因是单词的意思从定义上来说是抽象的,是基于人类的语境,第二个原因是人类语言的语法结构复杂得令人难以置信。

有一些自然语言处理的方法完全避免了意义,但仍然可以获得强有力的结果。所谓的“单词袋”模型忽略了所有的语法或词序,只是将文本表示为单词的集合,然后可以进行概率比较。像朴素贝叶斯分类器这样的概率模型查看不同单词在不同上下文中出现的相对频率。在主题检测用例中,您可以想象特定领域的词汇在一些主题中比在其他主题中使用得更多:技术文章可能有技术词汇,如“处理器”或“千兆字节”,而政治文章可能有政治词汇,如“选举”或“勾结”。假设你有一个标记良好且足够大的数据集,这样的模型可能非常强大,即使是在相对微妙的问题上:一个训练有素的贝叶斯分类器可以以 98%的准确率区分合法的新闻故事和来自洋葱等来源的讽刺文章。

不幸的是,这给我们带来了第二个挑战,数据标注。为了训练一个分类器,你需要一个训练数据集,这个数据集已经被很好地标记,并被分成适当的组。对于讽刺分类器这样的东西来说,这不会是一个挑战——任何来自洋葱这样的来源的东西都将是讽刺,而任何来自路透社的东西都不是,所以数据几乎被默认标记。对于像主题这样的东西,就有点难了,特别是当文章被发布它们的新闻机构标记为不同的主题部分时,不同的组织可能使用不同的分类方案。例如,想象一下“政治”新闻和“国际”栏目中的英国退出欧盟新闻之间的区别。

手动标注一大堆新闻文章会非常麻烦。幸运的是,也有无监督的主题建模方法,包括潜在的狄利克雷分配,不需要良好标记的训练数据。LDA 和类似的方法可能更好地称为“主题聚类”,而不是主题建模。使用 LDA 的计算机不能准确地“命名”一个主题,它不能接受一篇文章并明确地说它来自报纸的艺术部分。毕竟,我们考虑使用 LDA 的全部原因是它不需要预先标记的数据,所以计算机无法知道它收到的文章来自艺术部分。

相反,LDA 和类似方法试图做的是将文章组合在一起,返回未命名的“主题”,代表它认为相似的文章簇。希望该模型将艺术部分的文章分组在一起,而不需要被告知哪些文章在艺术部分开始。这种方法的两个怪癖是:a)计算机不会,也不能直接返回它所找到的群体的可解释信息(这需要人工干预), b)没有真正的方法来验证它所识别的群体,因为它是以一种无人监督的方式找到这些群体的。

LDA 是一个“单词包”模型,因为它将每个文档或文本视为本质上只是一个没有任何语法或词序的单词集合。它基本上将“主题”概念化为单词的概率分布,将单个文档/文本概念化为主题的概率分布。在这个视图中,任何给定的文本本质上都是通过从某些主题中随机抽取单词来生成的。一个带有 LDA 功能的统计软件包(比如我使用的 scikit learn 的)试图在给定文本数据集和一些预期主题的情况下,找到主题中最合理的单词分组。

您可以想象 LDA 模型的工作方式,如下所示:该模型基于一组似乎有许多共同词汇的文章来识别主题。人类翻译可能会给这个话题贴上“政治”的标签:像“参议院”、“政党”和“投票”这样的词在这个话题中很常见,而像“薄饼”或“血红蛋白”这样的词不常出现。由模型识别的另一个主题可以与电影评论一致,并且对应于诸如“电影”、“动作”和“电影摄影”之类的词。当呈现一篇新文章时,比如说,一篇政治惊悚片的评论,该模型将有希望能够识别出它与这两个主题最强烈地对应。

LDA 实际上如何找到主题聚类的数学基础稍微复杂一些,尽管像许多数据科学工具一样,使用广泛可用的 python 库来实现它是很容易的。我决定尝试使用 LDA 来改进我的俳句生成器。第一步是建立一个文本训练语料库。我一直在与 NPR 的文章,因为 NPR 有一个方便,容易刮,纯文本版本的网站,其网址都是相同的保存一篇文章的 id 号。不幸的是,id 不是连续的,也没有一个容易访问的列表。比我有更多网络抓取技能的人会找到更好的方法来自动抓取 NPR 网站,我手工从最近的文章中编辑了大约 250 个文章 id 号。这是一个足够大的语料库,但远没有你想要的那么大。

下一步是对数据进行“矢量化”,将每篇文章从计算机无法真正处理的字符串转换成它可以处理的数学对象。我使用了一个简单的“计数矢量器”,它的功能和听起来差不多:整个文本语料库中的所有独特单词都被表示为一个大矩阵中的列。对应于任何给定文本的向量就像这个矩阵中的一行,每一列中的值对应于该列在文本中出现的单词的计数。因此,矩阵是“稀疏的”:因为大多数可能的单词不会出现在任何给定的文本中,所以有许多零。简单计数矢量化的一种替代方法可能是词频-逆文档频率(TF-IDF ),它实质上是与相应单词在整个语料库中出现的频率成反比地对文本向量中的条目进行加权。因此,在多个主题中常见的单词,如“good”或一周中各天的名称,将具有较低的权重,而相对罕见的单词则具有较高的权重。

最后,使用 scikit learn 运行 LDA 模型是一个简单的两行代码。我选择运行 10 个主题的模型,并打印出每个主题中最重要的单词,以直观地检查它们的连贯程度。

在某些情况下,该模型在将相关术语组合在一起方面做得非常好,特别是对于与当前事件相关的这些组,我认为不需要任何解释:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

News articles from the border

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

News article about business as usual

其他主题表面上看不太清楚,不过,拥有较小数据集的一个意想不到的好处是,很容易找到一些联系。第七个话题起初看起来很奇怪,热门词汇大多与健康和医学有关,但也包含像“气候变化”这样的内容。这种联系是由一篇文章建立的,这篇文章讨论了炎热的夏天和其他与全球变暖相关的压力对健康造成的一些后果:你的医生和你谈过气候变化吗。因为这是一个相对较小的训练集,所以像这样的一篇文章可以在模型中不同的主题之间建立重要的联系。有了更大的文本集和更多的主题,LDA 模型可能会将医学和气候变化文章作为单独的主题进行分组,并认为链接这两个主题的文章是这两个主题的混合。

一旦模型被训练,它可以评估新文本,并根据它认为它属于哪个主题簇来对它们进行分类。例如,给定这篇关于飓风巴里在路易斯安那州登陆的文章,该模型认为它最有可能属于主题#4,这是一个具有大量政府和政治相关单词的主题。考虑到这篇文章讨论的是联邦政府对飓风的反应,这个猜测不错。为了更好地说明实际情况,我编写了一个函数来返回文本中在所选主题中权重最大的单词,因此这些单词对与该主题分组的文章贡献最大:

这个函数在我的测试文章中的输出有助于阐明为什么它被归入那个主题:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试文章与其他新闻文章的分组是正确的,如果你仔细阅读与它所识别的主题群最相关的单词,你会看到“新闻演讲”的明显例子:“居民”、“报道”、“官员”等。不过,也有一些怪癖:一方面,它把“星期四”定为重要的一天。也许这真的有道理!也许新闻文章(而不是艺术部分的文章)更可能指定一周中的某一天。在我看来,有些词可能会出于“错误”的原因将模型指向某个特定的主题群。例如,“水”这个词。稍微了解一下进入这一模式的文章,我并不感到意外的是,水可能会聚集特朗普和其他与新闻相关的词:今年夏天,有许多关于南部边境拘留中心的文章,包括讨论被可耻地关押在那里的人是否能获得干净的水。然而,在本文的上下文中,它是一种不同的水,雨/洪水,被用来将本文链接到这个主题集群。

当然,整个练习的目的是提高我的打油诗写作能力。您如何将此用于该目的?两种方式。第一,这提供了一种从文章中过滤掉不太“有用”的单词的方法:您需要确定哪些单词是“内容”单词,并比所有主题的文章中常见的单词更频繁地使用它们。第二,这可能会释放文章文本中找不到的额外词汇。如果你正在创作一首打油诗,你可能需要寻找没有出现在文本中的单词,以便找到押韵或生成新的句子,并正确扫描。计算机怎么知道哪种词有意义呢?这可能是对单词进行分组的一种方式:“我看到本文属于这个主题组,与这个组相关的其他单词是……”

我试着调整我的俳句生成器,以便在组合俳句时使用输出的、高度加权的单词作为单词字典。在之前关于飓风巴里的文章中,我的新俳句生成器产生了这首诗:

路易斯安那

新应急水

中央报告日

鉴于这篇关于新任白宫新闻秘书斯蒂芬妮·格里沙姆的文章,它产生了以下内容:

Grisham 发言人

最大的政府

白色中等好

这个过程能提高我的俳句创作吗?不完全是。如果说有什么不同的话,那就是有几个原因让情况变得更糟。我以前的生成器按照单词在文本中的出现频率使用单词,除了停用词之外,没有丢弃任何单词。然而,现在,文本单词通过矢量器传递,该矢量器丢弃在语料库的所有文本中出现频率不够高的单词,并使用受模型/语料库整体影响的权重。因此,对于给定的文章来说相对特殊的单词可能不会出现在要使用的单词列表中,即使这些正是你想要出现在摘要俳句中的单词!从项目的长期来看,可能需要一个策略来打开一个更广泛的单词字典。然而,对我来说很明显,为了使用这种策略,你只需要更多:更多的文本,更多样化的文本,可以被分组到更多的主题群中。

Limericking 第 3 部分:文本摘要

原文:https://towardsdatascience.com/limericking-part-3-text-summarization-f715841a8765?source=collection_archive---------21-----------------------

石灰工程

从文本中识别关键的摘要句子

欢迎来到我正在进行的 Limericking 系列的第 3 部分,在这里我将探索自然语言处理在解析新闻文本和写诗方面的巨大潜力。正如我在系列文章的第一部分中解释的那样,我是 Twitter 账户 Limericking 的狂热粉丝,该账户能够消化新闻并创作出精彩的打油诗。

So much more pleasant that watching the Democratic primary debate

唯一的问题是 Limericking 只是一个帐户。到目前为止,其他主流媒体都无视我的要求,用押韵诗报道所有新闻,让我们的大部分新闻消费处于危险的非多样化状态。我希望通过创造一个自动计算程序,利用自动化的强大力量来解决这个问题,从而帮助弥合这一鸿沟。一个函数能接受一篇新闻文本,恰当地解释它的意思,并把它改写成一首打油诗吗?我相信答案是肯定的,尽管我可能需要更多的博客文章来解决所有的问题。然而,我已经自动生成了一些非常成功的俳句。

第一大任务是找到一种方法,让计算机“阅读”给定的新闻文本,并返回某种摘要或一组关键词。稍后,我们将不得不考虑如何让计算机生成自己的文本,该文本扫描正确且押韵(并有适当的喜剧性转折),但目前,简单地从文本中提取主题已被证明足够困难。我在这个系列中的最后一篇文章讨论了使用潜在的狄利克雷分配来尝试将文章分组到“主题”中,并识别与这些主题相关联的有意义的单词。结果不是很好。

不过,也许我对这部分挑战想得太多了。尽管主题建模是一个困难的问题,但我在第 1 部分中最初的俳句写作功能令人惊讶地做得很好的事情之一是识别新闻文章是关于什么的。我只是推断这篇文章可能是关于一个专有名词,比如一个人或一家公司,并且这个主题可能会在文章的正文中出现多次。简单地找到专有名词,并计算出哪些是最常出现的,对确定文章的内容大有帮助。像这样的策略的关键之一是它完全基于规则:它不需要在一组标记良好的文章样本上训练模型,也不需要计算机“理解”给定单词的意思,或者为什么它可能是文章的主题。更重要的是,该函数只是识别并返回原始文本的一个元素,所以您还不需要处理文本生成。

也许有一种方法可以做类似的事情,但它可以在更大的文本块上工作:比如说,一个函数可以根据一些容易计数的特征比较文本中的不同句子,然后返回一个似乎最重要的句子,就像最常重复的专有名词似乎“重要”一样。事实证明,有一种方法可以做到这一点,这种方法很容易实现,而且效果很好。关键的洞见是弄清楚如何衡量一个给定句子的“中心”或“主题”程度。寻找最常用的专有名词的句子长度是多少?

解决这个问题的一种方法是,根据文本中包含的单词来比较这些句子之间的相似程度。想象一下,例如,一个关于你所在城镇的市长的当地新闻故事。哪些单词最有可能出现在故事中,出现在最多的句子中?当然,你会期望城镇的名字和市长的名字会出现很多次,出现在很多不同的句子中。文章可能会有一个更具体的主题,比如某个特定的事件或市长工作的某个方面,这也会在文章中多次出现。其他事情可能在文本中出现得不太频繁,也许有一句话可能会提到市长的前任或邻镇正在发生的事情。

根据我们对这些单词分布的预期,你如何教计算机识别哪些句子看起来最重要?一种方法是简单地找出与文章中其他句子有最多共同点的句子。如果句子中有像市长的名字或城镇的名字这样的词,它看起来会和文章中包含这些词的许多其他句子相似。如果一个句子在谈论下一个城镇,而那个城镇的名字只被提到过一次,那么这个句子看起来就不像文章中的其他句子。举个具体的例子,考虑一篇关于纽约地铁糟糕状况的文章。像“纽约人指责白思豪造成地铁灾难”这样的句子可能会与文章中的其他句子相似,只是基于单词数:“纽约”、“地铁”等。像“彭博治下的情况没那么糟”这样的句子看起来不太相似,包含了像“彭博”这样的新词。

为了实现这个策略,首先我们需要将每个句子转换成计算机更容易处理的东西,比如一个向量,其中不同列中的值对应于给定单词在句子中出现的次数。然后计算机可以很容易地用余弦相似度这样的方法比较任意两个给定句子对应的向量。幸运的是,sklearn 很容易处理矢量化和相似性。考虑下面的实现,除了两个小问题之外,它非常简单:1)我使用优秀的 NLP 包 spaCy 将一大块文本分割成句子,但随后必须将句子转换回字符串对象(而不是 spaCy 标记), 2)我在第一个函数中有一个小循环,它将排除完全重复的句子。我之所以包括这个,是因为根据文本的来源,我发现我会重复使用类似“点击此处订阅”的短语,我想排除这些短语:

这在实践中是如何运作的?好吧。考虑到它的简单性,甚至可能出乎意料地好。例如,这篇关于农业对气候变化影响的文章有 23 个句子。我的函数将这些定义为最有用的 5:

The panel of scientists looked at the climate change effects of agriculture , deforestation and other land use , such as harvesting peat and managing grasslands and wetlands . The new report adds weight and detail to a warning put out by the same panel of scientists last fall , in which they sounded the alarm about the inadequacy of the pledges countries have made so far to reduce greenhouse gas emissions. At that time, the panel broadly suggested that farmland would need to shrink and forests would need to grow to keep Earth from getting more than 1.5 degrees Celsius hotter than it was in the preindustrial era. Scientists say the only way to achieve that reduction is to significantly increase the amount of land that ‘s covered in trees and other vegetation and significantly reduce the amount of methane and other greenhouse gases that come from raising livestock such as cows , sheep and goats. The U.N. panel is the latest group of experts to grapple with a global conundrum: how to reduce greenhouse gas emissions from agriculture , deforestation and other land use without creating food shortages or displacing people whose livelihoods rely on practices that are unsustainable globally.

一点都不差!整篇文章中有几个奇怪的遗留部分(比如以“当时”开头的句子没有明确的指代),但这篇文章的主旨很容易理解。

我想将实际的诗歌生成留到本系列的后续文章中,但我认为一个简单的系统将文本压缩成一个摘要有一些明显的好处。我们未来的五行打油诗生成器不必凭空创造文本,它会识别出重要的句子,只需要将它们恰当地塑造成五行打油诗的形式。它将能够借用整块的文本,而不需要担心词法或词序。

我的俳句生成器的含义也很清楚。这提供了一种非常有用的方法来识别要插入到俳句中的主题(所识别的句子之一的字面、语法主题),以及一种方法来识别应该选择的一组单词(从摘要句子中派生的词汇,而不是整个文本本身)。我将这些变化应用到我的俳句生成器中,它立即返回了这篇来自气候变化文章的精彩文章:

Sheep global need food,The panel of scientists,New effects countries.

从这个关于发现一只巨大史前鹦鹉的令人愉快的故事中,我们得到了这个相当贴切的金块:

Scientists small lint,Bird fauna island story,Ornithology.

但是,我想,当你的出发点是发现一只古老的儿童大小的鹦鹉的好消息时,结果一定会很有趣。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Artist’s rendering of the bird in question

协同推荐系统的局限性

原文:https://towardsdatascience.com/limitations-of-collaborative-recommender-systems-9801036941b3?source=collection_archive---------16-----------------------

从一个小杂志发行版的角度来看

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Zines on display at the Stay Kind! table at Pioneer Valley Zine Fest in April 2018. (Source: Stay Kind! Instagram)

本文包括一些关于 Stay Kind 的背景!zine 发行版,构建基于购买的协作推荐系统的过程,对推荐的评估,对该系统的局限性的讨论,以及对未来发展的想法。

背景

我记不清的确切历史了,保持善良!锌发行版。它开始是一个非常非正式的附带项目,经历了几次迭代,从来没有严肃或重要到足以记录。也许这是杂志本质的恰当反映。作为“杂志”的简称,这些自行出版的作品本身就是一种文档——但也可能是有限的、短暂的,并且容易消失。

我没有开始记录任何事情,直到 2016 年年中发生了两个重大变化:

  1. 我开始拿别人的杂志。
  2. 我承诺将所有销售额的 20%捐赠给有益于我们社区的组织。

这两个改变意味着除了我自己之外,还要对其他人负责。这意味着要跟踪销售和交易情况,而不是随便就把东西送人。

决定建立一个推荐系统

制作一个简单推荐系统的最初动力来自几个地方:

  • 人们经常向我寻求建议,我不知道该怎么回答他们。
  • MovieLens data 很有趣,但我也想建立一个推荐器,为我提供新的信息和实际应用。
  • 我认为这将是超级快速和容易的,因为我已经有了所有的数据。(大部分都很快很容易——但是没有什么比你想象的更快更容易。)

该计划是建立一个推荐系统,使用基于购买的协同过滤。你可以在任何时候看到这样的系统,你可以看到“买这个的人也买了…”听这个的人也听…”等等。

构建协同推荐系统

数据收集

我计划从 Square 和 Stay Kind 上提取交易记录!网站。Square transactions 记录了活动期间面对面的销售和交易。该网站由 WooCommerce 提供支持,由于其报告选项,最终变得有点棘手。我最终从一个单独的电子表格中获取了网上销售信息,这个电子表格是我为跟踪交易而创建的。

Tabling at New Zineland in April 2018.

数据探索和预处理

在这两个数据集之间,我有从 2016 年春天到现在(可能)所有销售和交易的记录。有一次,一家图书馆购买了我当时库存的全部 48 本书的两本。我从最终数据中排除了这次销售。

正如所料,大部分事务来自事件,并在 Square 报告中捕获。这里的挑战是,这些购买大多是用现金进行的。虽然我可以对一起购买的物品进行分组,但我无法对同一个人在不同场合购买的物品进行分组,除非他们用一张卡支付,并且每次都使用同一张卡。一个人在三个不同的活动上用至少两张不同的卡从网站上购买杂志。我能够对这些购买进行分组,因为这个人的所有卡上都有相同的名字,但它们是规则的例外。

(在这个过程中,我还注意到有一个人的名片上有埃玛·戈尔德曼这个名字。虽然有可能这是这个人的真名,但我更倾向于相信这是对活动家的致敬,他经常被错误地引用说,“如果我不能跟着它跳舞,那就不是我的革命。”不管怎样,我都笑得很开心。)

总之,在组合、清理和匿名化数据集之后,我最终得到了类似这样的东西:

从这个片段中,我们可以看到客户#544 和#527 都购买了 2015 年 6 月和 7 月的 Ima Eat You!

协同推荐器

现在我们有了一个单一的数据框架,表明哪些客户拥有哪些商品,我们准备好根据购买情况构建推荐器了。我采取的步骤是:

  1. 添加一个名为Purchased的新列,所有值都设置为1
  2. index='Item', columns='Customer', values='Purchased'处创建一个数据透视表。
  3. 0填充缺失值,创建一个稀疏矩阵。
  4. 使用pairwise_distances计算余弦相似度。
  5. 将距离放入数据帧中,使其易于阅读。

以下是最终数据帧一部分:

(Scroll to the right to view more.)

一个值越接近0,这两件商品就是否被同一个人购买而言就越相似。因此与其自身交叉引用的项目将始终等于0

同时,1的值表示这两件商品从未被同一个人购买过。看上面的一个例子,这意味着已经买了 1 周半的人,没有一个还买了 9 的爱情药水

估价

让我们看几个例子来了解这个推荐器实际上做得有多好。

Ang Pangalawang Pagtatapat:第二部告白

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ang Pangalawang Pagtatapat(Source: Stay Kind!)

售出数量:23

以下是网站上的描述:

杂志系列的第二期《自白》讲述了不安全感、菲律宾政治的本质以及菲律宾人的心态。作者:苏迈.夏琳。

16 页,5.5 x 8.5 英寸

这些建议是基于购买了这个产品的人也买了什么:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

People who got Ang Pangalawang Pagtatapat: The Second Confessions also got these zines by the same creator. (Source: Stay Kind!)

前两个推荐,自白Kulay Ng Balat ,实际上是提供种族反思的同一系列杂志的一部分。如果你讨厌一个人… 是同一作者的另一本杂志。《活着的南方人》是由另一位创作者制作的系列节目,他也专门谈论种族问题。总的来说,这一套建议还是不错的。

焦虑工具包

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Anxiety Toolkit (Source: Stay Kind!)

售出数量:26

来自网站的描述:

焦虑工具包是我在 48 小时内专门为 2014 年布鲁克林杂志节制作的一次性杂志。这是一个可以用来缓解焦虑的 15 个工具的列表(以及这些工具如何/为什么对我有用的描述)。安妮·h。

28 页,4.25 x 5.5 英寸

这些建议是基于购买了这个产品的人也买了什么:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

People who got Anxiety Toolkit also got these zines by other creators. (Source: Stay Kind!)

这个的结果有点复杂。虽然这本杂志的标题中有“工具包”,并包括降级策略,但作者以非常随意的语气写作,并分享个人故事。这样看来,其实类似于 Kulay Ng Balat 和 *Fixer Eraser #2 这样的推荐书目。*其他标题更明显。心理收缩如何爱我马上变得无忧无虑一切都会好起来这些都是关于心理健康、正念或自我保健的策略。

我要吃了你!2011 年 6 月

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ima Eat You! June 2011 (Source: Stay Kind!)

售出数量:5

来自网站的描述:

Dawn“Zilla”Graham 撰写的杂志,主要涵盖日常经历、观察和思考。2011 年 6 月包括寻找一个新的公寓,成为一个容易被说服的人,波士顿之旅,治疗,课程,寓言,食谱,去法院,性暴力,等等。

32 页,5.5 x 8.5 英寸

以及基于购买的推荐:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

People who got Ima Eat You! June 2011 also got these other items created by me. (Source: Stay Kind!)

在这种情况下,根据人们的购买情况,只推荐五种商品。所有其他项目都有一个1的距离,这意味着——根据记录——没有人得到这个问题的我吃你!除了上面提到的物品,还有其他物品吗?五个项目中有三个也是我做的。

同样值得注意的是,售出的总数量是 5 台,远远少于前两个示例中售出的 20 多台。这一期的大部分份数我吃了你!早在我开始追踪这些东西之前,它们就已经被送走了。虽然Ang pangala Wang Pagtatapat焦虑工具包*都被它们的创作者多次重新进货,但这一期的所有副本 *Ima 吃了你!已被认领,绝不转载。

限制

最后一个例子暴露了这种推荐系统在应用于 zine 发行版时的一些局限性。让我们更深入地探讨一下:

杂志通常限量供应。有些用完了也不一定能补上。正因为如此,一份杂志上市的时间也是有限的。根据某本杂志第一次被添加到发行版的时间,或者它脱销的时间,它将与网站上列出的其他杂志中的一部分同时可用。这引发了两个问题。当第一次添加杂志时,存在“冷启动问题,这意味着没有以前的购买历史来通知推荐。人们不是从相同的总体选择中进行选择。

同样,由于有限的桌子空间,并非所有可用的杂志都会在活动中展示。因为人们从《保持友好》中获得了大部分杂志!在活动中而不是通过网站,这很重要。当杂志卖光后,我会用其他杂志取代它们在桌子上的位置。一天开始时的显示通常与一天结束时完全不同。焦虑工具包在之前的一次活动的第一个小时内就已经销售一空。如果那本杂志还能买到的话,很有可能那些随后过来并得到其他杂志的人也会对那本感兴趣。

另一方面,有些人在活动开始时收到几份杂志,后来又收到更多,因为他们看到新的杂志在展出。这将我们带回另一个限制。由于大多数销售是面对面进行的,使用现金,由同一个人进行的购买通常不能归在一起,即使是在同一天进行的。

最后,虽然这个推荐系统确实提供了关于一起购买的物品的准确信息,但它并不能很好地表明人们实际上喜欢什么。大多数面对面交易的好处在于,人们有机会先浏览一下。这意味着他们非常喜欢他们所看到的东西,并愿意去得到它。我带的大多数杂志都是文字内容丰富的。虽然有些人会站在那里阅读整本杂志,但大多数人直到后来才知道他们对新杂志的感觉。也有这样的情况,人们既给自己买了东西,也给别人买了礼物——所以一起购买的杂志不一定反映一个人的喜好。

(在列举了所有这些限制之后,我觉得有必要列举这个小项目的一个优点:基于购买的协作推荐器构建起来既快又容易。写这篇文章花费的时间比数据收集、预处理和创建推荐系统的时间加起来还要长。)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Zines on display at the Stay Kind! table at Not Another Punk Rock Flea Market in July 2018. (Source: Stay Kind! Instagram)

未来发展

有很多方法可以为发行版建立一个更好的推荐系统。一些想法包括:

  • 使用基于内容的过滤和协作过滤创建一个混合系统。这就意味着要包含各个项目的信息,包括主题、页面大小、彩色与黑白、创作者姓名、文字与图像的比例、成本等。
  • 该网站已经允许人们留下评分和评论。我可以更有意识地鼓励人们留下反馈,这样我就可以包括基于评级的协同过滤。
  • 如果我在网站上实现这个推荐系统,我会对它进行调整,这样登录的人就不会收到对他们已经拥有的商品的推荐。

感谢阅读!想法、问题和反馈总是很受欢迎。还可以查看本项目 GitHub 回购。

线检测:让自动驾驶汽车看到道路线

原文:https://towardsdatascience.com/line-detection-make-an-autonomous-car-see-road-lines-e3ed984952c?source=collection_archive---------10-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过计算机视觉,你可以一步一步地将视频流转换成线状探测器

动机

全自动驾驶乘用车并非“指日可待”。埃隆·马斯克声称特斯拉将在 2020 年年底具备“完全自动驾驶”能力。特别是,他说特斯拉的硬件已经为自动驾驶做好了准备,剩下的只是对他们当前软件的更新,许多杰出的科学家正在为此努力。

我们人类作为司机的第一本能,很可能是看着前方,决定车该往哪里开;在哪个方向,在哪些线之间,等等。由于每辆自动驾驶汽车前面都有一个摄像头,因此一项非常重要的任务是决定汽车应该在其间移动的边界。对人类来说,我们在道路上画线。现在我们将教一辆自动驾驶汽车看到这些线。我保证会很好玩:)

鸣谢—参考文献

这些项目大部分是由麻省理工学院的 自动驾驶汽车深度学习 课程和 Udacity 的 自动驾驶汽车工程师 激发的。后者是学习和扩展你的领域技术知识的良好开端。

议程

我们将一步一步地设计孔管道,其中我们将激励我们为什么这样做。
灰度变换
高斯模糊
Canny 边缘检测
遮蔽感兴趣区域
霍夫线检测器
寻找道路线

完整的代码可以在这里找到。

在这里,我们将一步一步,提供整个代码的快照。然而,一些部分被省略了,因为这将使邮件非常沉重,并分散我们的目标。因此,如需更多信息,请参考上述知识库。

步骤 0:读取图像

matplotlib的帮助下,我们可以轻松地将 python 脚本中的任何图像加载为三维张量 C-H-W(颜色通道,图像的高度和宽度)

import matplotlib.image as mpimgimg_path = 'test_images/solidWhiteCurve'
img = mpimg.imread(img_path)
plt.imshow(img)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第一步:灰度

首先,我们要把图像变成灰度图像;只有一个颜色通道。这将有助于我们识别棱角。
我们可以通过opencv轻松做到这一点

import cv2gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
plt.imshow(gray_img, *cmap*='gray')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第二步:高斯模糊

将高斯噪声添加到图像中,这非常有用,因为它平滑了像素之间的插值,并且是一种超越噪声和伪梯度的方法。kernel越高,结果图像越模糊。

kernel_size = 5
gauss_img = cv2.GaussianBlur(gray_img,(kernel_size, kernel_size), 0)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第三步: Canny 边缘检测

Canny 边缘检测提供了一种检测图像边界的方法。这是通过图像的渐变来完成的。

后者只不过是一个函数,其中每个像素的亮度对应于梯度的强度。

我们将通过追踪沿着最强梯度的像素来找到边缘!一般来说,梯度显示函数变化有多快,像素之间强烈的密度变化将指示边缘。

low_threshold, high_threshold = [200, 300]
canny_img = cv2.Canny(gauss_img, low_threshold, high_threshold)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如你所看到的,我们现在可以清楚地识别道路线!(我们甚至可以看到汽车的外形!)

步骤 4:遮蔽感兴趣的区域

上图中,有一些离群值;来自道路的其他部分、来自风景(山脉)等的一些边缘。由于我们的相机是固定的,我们可以在图像上加一个遮罩,只保留那些我们感兴趣的线条。因此,画一个梯形是非常自然的,目的是只保留一个区域,在那里我们应该期望道路线。cv2再次为我们而来;)

# Setting the corners of the trapezium
vertices = np.array([[(0, img_line.shape[0]), (img_line.shape[1], img_line.shape[0]), (400, 260), (600, 260)]])# make a blank/white image
mask = np.zeros_like(img)
mask_channels = (255,) * img.shape[2]# Fill the area of interest with 0 and 255 these
# which lie outside of it, thoughout all color channels
cv2.fillPoly(mask, vertices, mask_channels)# Keep only the pixels with 0 value of the canny_img
masked_img = cv2.bitwise_and(canny_img, mask)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Left: Selected Region Right: After applying the mask

第五步:霍夫线检测器

上面的图像只代表了边缘的点。剩下的就是把边缘连接起来。在这种情况下,我们正在寻找直线,我们将通过将图像传输到称为霍夫空间的参数空间来实现这一点。我们现在将处理极坐标 (rho 和 theta),其中我们将搜索相交线。

import mathlines = cv2.HoughLinesP(img, rho=1, theta=math.pi/180,
                        threshold=15, np.array([]),        
                        *minLineLength*=30,
                        *maxLineGap*=40)line_img = np.zeros((img.shape[0], img.shape[1], 3), *dtype*=np.uint8)

以上将返回许多小车道(最小长度是一个超参数 minLineLength )。 line_img 将是一个列表,其中它的元素是一个列表,由图像空间{(x1,y1),(x2,y2)}中的两个点组成。众所周知,在 2D 空间中,只有一条直线经过两点。

这里自然会出现一个问题:我们如何连接这些线,并导致只有两条,他们将是道路吗?这可能是这篇文章中最具挑战性的部分。

第六步:找到道路线路

我们的策略如下:
。参照 x 轴将图像分成两半
。用线性回归模型拟合这些点,以找到一条平滑的线。
由于离群值,我们想要一个可以有效处理它们的回归模型。我们将使用HuberRegressor。然后,我们将图像限制在 y 轴的某个范围内,并在cv2.polylines的帮助下绘制直线。请记住,为了有一条平滑的线,我们将通过给定的回归量绘制给定的 **x****y** 的预测。

import mathdef draw_lines(line_img, lines):
   # CODE HERE
   passlines = cv2.HoughLinesP(img, rho=1, theta=math.pi/180,
                        threshold=15, np.array([]),        
                        *minLineLength*=30,
                        *maxLineGap*=40)line_img = np.zeros((img.shape[0], img.shape[1], 3), *dtype*=np.uint8)
draw_lines(line_img, lines)plt.imshow(line_img)
plt.show()

此时,鼓励读者编写上述函数。如果你卡住了或者只是想看看我的版本是什么样子,请在这里看。

我们的结果会是…

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

步骤 7:将线条与原始图像连接起来

通过对两幅图像进行加权,我们可以将它们相加。记住img_lines的黑色区域有值0,因此相加不会改变输出值。

out_img = cv2.addWeighted(img, 0.9, img_lines, 1.0, 0.0)
plt.imshow(out_img)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

备注

瞧啊。我们已经成功探测到道路了!视频只是一个图像序列,因此,在moviepy的帮助下,我们为每一帧绘制上述管道!视频管道将看起来像:

from moviepy.editor import VideoFileClipin_video = 'test_videos_output/solidWhiteCurve.mp4'
output_video = 'test_videos_output/out.mp4'clip = VideoFileClip(in_video).subclip(0, 8)
empty_clip = clip.fl_image(YOUR PIPELINE AS A FUNCTION THAT 
                           RETURNS THE WEIGHTED IMAGE)out_clip.write_videofile(output_video, *audio*=False)

如前所述,完整的代码可以在这里找到。随意摆弄参数,想出新的方法来检测道路线。

下次再见,保重!

基于 CNN 的直线跟随机器人

原文:https://towardsdatascience.com/line-follower-robot-using-cnn-4bb4f297c672?source=collection_archive---------8-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image by author

在本教程中,我们将学习如何制作一个线跟随机器人。虽然,有大量的线追随者教程,因为这个概念本身是相当古老的。然而,这里我们将学习如何使用卷积神经网络(CNN)来检测直线。基本上,我们将使用我们的 Raspberry Pi 相机以预定的间隔捕捉一系列图像,然后我们将使用预先训练的 CNN 来预测我们的机器人应该移动的方向,即向前、向右或向左。本教程需要以下内容:-

  1. 树莓 Pi 板,
  2. Pi 相机,
  3. 跳线
  4. 底盘、电机、轮胎
  5. 电机控制 IC (L293d)

我假设你已经知道如何使用你的 Raspberry Pi 的 GPIO 引脚来控制电机。如果你想提高你的技能,请浏览我之前的教程。此外,在继续下一步之前,请确保您的 Pi 上安装了 tensorflow 1.1 和 open CV。

我将把本教程分为三个部分

  1. 为 CNN 捕捉图像。
  2. 训练 CNN
  3. 在树莓派上部署 CNN

为 CNN 捕捉图像

我们需要三组图像用于三种条件中的每一种,即向前、向左和向右,来训练我们的 CNN。一旦我们训练了我们的 CNN,它将能够预测机器人在哪个方向移动,然后我们可以相应地采取纠正措施。例如,如果生产线左转,CNN 将预测机器人相对于生产线向右移动,因此,我们应该向左移动机器人。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Fig. depicting robot moving in various directions and the corresponding images captured by the camera

可以有各种方法来创建用于训练 CNN 的数据集。在我的例子中,我首先建造了一个轨道。然后,我使用下面提到的代码以 0.5 秒的间隔捕捉一系列图像。然后你把机器人放在轨道上的不同位置,捕捉一系列图像。例如,在第一个图像中,我放置了机器人,这样我希望 CNN 检测到机器人应该向左移动。同样,你在赛道的不同位置重复这个过程。一旦完成,你可以重复这个过程向前和向右。一旦你捕捉到三个方向的图像,将它们分别放入分别命名为向前、向左和向右的文件夹中。

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2

# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480) # set the resolution
camera.framerate = 32 # set the frame rate
rawCapture = PiRGBArray(camera, size=(640, 480))

# allow the camera to warm up
time.sleep(0.1)

# capture frames from the camera
start = 1for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
  # grab the raw NumPy array representing the image, then initialize the timestamp and occupied/unoccupied text
  image = frame.array
  # show the frame
  cv2.imshow("Frame", image)
  key = cv2.waitKey(1) & 0xFF
  cv2.imwrite(str(start) + ".jpg", image)
  start = start + 1

  # clear the stream in preparation for the next frame
  rawCapture.truncate(0)

  # if the `q` key was pressed, break from the loop
  if key == ord("q"):
    break
  time.sleep(.5)

训练 CNN

您可以在 raspberry PI 本身或不同的更强大的系统上训练 CNN,然后保存训练好的模型,PI 可以读取该模型。下面是训练 CNN 捕捉图像的代码。

首先,我们导入必要的库。

# import the necessary packages
from keras.models import Sequential
from keras.layers.convolutional import Conv2D, MaxPooling2D 
from keras.layers.core import Activation, Flatten, Dense
from keras import backend as K
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing.image import img_to_array
from keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from keras.utils import to_categorical
from imutils import paths
import numpy as np
import argparse
import random
import cv2
import os
import matplotlib

然后我们定义一个可以用来构建 CNN 的类LeNet。这里你可以看到这个类有一个函数build ,它接受参数widthheightdepthclasses。宽度和高度应该等于您将用作 CNN 输入的图像的宽度和高度。在我的例子中,我使用的是 28x28 的图像,因此宽度和高度分别是 28。深度定义输入图像中的通道数。单色的深度为 1,RGB 的深度为 3。类别定义了您希望 CNN 检测的不同类型图像的数量。在我们的例子中,我们想要区分 3 种类型的图像——前向、左向和右向。

class LeNet:
  [@staticmethod](http://twitter.com/staticmethod)
  def build(width, height, depth, classes):
    # initialize the model
    model = Sequential()
    inputShape = (height, width, depth)# first set of CONV => RELU => POOL layers
    model.add(Conv2D(20, (5, 5), padding="same",
      input_shape=inputShape))
    model.add(Activation("relu"))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# second set of CONV => RELU => POOL layers
    model.add(Conv2D(50, (5, 5), padding="same"))
    model.add(Activation("relu"))
    model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))# first (and only) set of FC => RELU layers
    model.add(Flatten())
    model.add(Dense(500))
    model.add(Activation("relu"))# softmax classifier
    model.add(Dense(classes))
    model.add(Activation("softmax"))# return the constructed network architecture
    return model

当您调用build 函数时,它将定义一个具有两个卷积层和一个两个密集层的神经网络。人们可以试验这些层的参数,或者甚至添加额外的层来提高模型的准确性。接下来,提供培训图像文件夹所在的路径。您必须已经创建了三个文件夹向前、向左和向右,并将上面捕获的相应图像放在各自的文件夹中。

dataset = '/home/pi/Desktop/tutorials/raspberry/trainImages/' # please change this path
# initialize the data and labels
print("[INFO] loading images...")
data = []
labels = []

# grab the image paths and randomly shuffle them
imagePaths = sorted(list(paths.list_images(dataset)))
random.seed(42)
random.shuffle(imagePaths)# loop over the input images
for imagePath in imagePaths:
    # load the image, pre-process it, and store it in the data list
    image = cv2.imread(imagePath)
    image = cv2.resize(image, (28, 28))
    image = img_to_array(image)
    data.append(image)# extract the class label from the image path and update the
    # labels list
    label = imagePath.split(os.path.sep)[-2]
    print(label)
    if label == 'forward':
        label = 0
    elif label == 'right':
        label = 1
    else:
        label =2
    labels.append(label)

然后,上面的代码获取子文件夹中每个图像的路径,存储在列表imagePaths中,并对它们进行重排。在训练模型时,随机提供来自每个类的数据是必要的。此外,每个图像然后被读取、调整大小、转换成 numpy 数组并存储在data中。现在,我们还必须给每个图像分配一个标签。为此,我们从每个图像的图像路径中提取文件夹名称。然后,我们比较文件夹名称是否为“转发”,我们指定标签为 0。类似地,标签 1 和 2 被分配给文件夹“右”和“左”中的图像。这就是为什么需要创建子文件夹,并将相似的图像放在不同的文件夹中。

# scale the raw pixel intensities to the range [0, 1]
data = np.array(data, dtype="float") / 255.0
labels = np.array(labels)

# partition the data into training and testing splits using 75% of
# the data for training and the remaining 25% for testing
(trainX, testX, trainY, testY) = train_test_split(data,
    labels, test_size=0.25, random_state=42)# convert the labels from integers to vectors
trainY = to_categorical(trainY, num_classes=3)
testY = to_categorical(testY, num_classes=3)

接下来,图像被归一化,使得每个像素的值在 0 和 1 之间。然后,将图像划分为训练集和测试集,以检查模型性能。在接下来的步骤中,我们使用 LeNet 类构建模型,根据训练数据训练模型,然后保存训练数据。

# initialize the number of epochs to train for, initial learning rate,
# and batch size
EPOCHS = 15
INIT_LR = 1e-3
BS = 32# initialize the model
print("[INFO] compiling model...")
model = LeNet.build(width=28, height=28, depth=3, classes=3)
opt = Adam(lr=INIT_LR, decay=INIT_LR / EPOCHS)
model.compile(loss="binary_crossentropy", optimizer=opt,
    metrics=["accuracy"])

# train the network
print("[INFO] training network...")
H = model.fit(trainX, trainY, batch_size=BS,
    validation_data=(testX, testY),# steps_per_epoch=len(trainX) // BS,
    epochs=EPOCHS, verbose=1)

# save the model to disk
print("[INFO] serializing network...")
model.save("model")

部署 CNN

一旦我们训练了我们的模型,我们就可以在我们的 Pi 上部署它。你可以使用下面提到的代码根据 CNN 的预测来控制机器人的方向。首先,我们从导入必要的库开始。这里我们也使用了motor_control.py文件,你可以在我之前的教程中找到。

# import the necessary packages
from keras.preprocessing.image import img_to_array
from keras.models import load_model
import numpy as np
import cv2, time, sys, imutils, argparse
import RPi.GPIO as GPIO
from picamera.array import PiRGBArray
from picamera import PiCamera
import motor_control as mc

接下来,定义您将用来控制电机的 raspberryPi 的引脚。

GPIO.setmode(GPIO.BCM)#choose the GPIO pins for mptor control
fwd1 = 23  # pin 16
bwd1 = 24 #pin 18
fwd2 = 16 # pin 36
bwd2 = 20 # pin 38# declare selected pin as output pin
GPIO.setup(fwd1, GPIO.OUT)
GPIO.setup(bwd1, GPIO.OUT)
GPIO.setup(fwd2, GPIO.OUT)
GPIO.setup(bwd2, GPIO.OUT)

接下来,我们定义一个函数control_robot,它将根据模型的预测控制机器人的方向。

#function to control direction of robot based on prediction from CNN
def control_robot(image):
  prediction = np.argmax(model.predict(image))
  if prediction == 0:
    print("forward")
    mc.forward()
  elif prediction == 2:
    print("left")
    mc.left()
  else:
    print("right")
    mc.right()

接下来,我们初始化相机,并开始在预定的时间间隔抓取图像。这些图像中的每一个都经过预处理,类似于我们对训练图像所做的那样。然后,该图像被传递给控制机器人方向的功能control_robot

model = load_model("model")if __name__ == "__main__":
  try:
    mc.stop()
    # initialize the camera and grab a reference to the raw camera capture
    camera = PiCamera()
    camera.resolution = (640, 480)
    camera.framerate = 32
    rawCapture = PiRGBArray(camera, size=(640, 480))
    # allow the camera to warmup
    time.sleep(0.1)
    # capture frames from the camerafor frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
     # grab the raw NumPy array representing the image, then initialize the timestamp
     # and occupied/unoccupied text
     image = frame.array
     # show the frame
     key = cv2.waitKey(1) & 0xFF image = cv2.resize(image, (28, 28))
     image = img_to_array(image)
     image = np.array(image, dtype="float") / 255.0
     image = image.reshape(-1, 28, 28, 3)
     #cv2.imshow("Frame", image[0]) control_robot(image) # clear the stream in preparation for the next frame
     rawCapture.truncate(0) except KeyboardInterrupt:
    mc.stop()
    GPIO.cleanup()
    sys.exit()

如果一切顺利,当您在 Raspberry Pi 上运行这段代码时,您将能够看到类似的结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我希望你喜欢这个教程。请随时评论和询问或提出一些建议。非常感谢 Adrian Rosebrock 关于 RaspberryPi 的精彩教程,我在这里以此为基础。做检查他的网站

ML 线性代数与概率论复习

原文:https://towardsdatascience.com/linear-algebra-and-probability-theory-review-for-ml-e3d2d70c5eb3?source=collection_archive---------30-----------------------

任何数据科学家都必须知道的矩阵、向量和概率论基础知识

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Oleg Magni from Pexels

矩阵

  • 按行和列组织的一组元素。
  • 行是水平线,列是垂直线,它们通常都是零索引的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Matrix Example

  • 矩阵维度: (行数)x(列数)
  • 矩阵加法和减法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Matrix summation/subtraction example

  • 矩阵乘法
    Mat A x Mat B
    (2,3) x (3,2)
    (Ai,Aj) x (Bi,Bj)内部尺寸(Aj & Bi)必须相等,以便能够执行具有外部尺寸(Ai,Bj)大小的输出矩阵的矩阵乘法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Matrix multiplication example

  • 矩阵转置
    一个(3x2)矩阵转置产生一个(2x3)矩阵

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Matrix transpose example

  • 矩阵的逆矩阵
    I 被称为单位矩阵,它全是 0,对角线上的 1 与 a 的维数相同

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

向量

  • 向量是 n×1 矩阵
  • 表示 n 维空间中的直线

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 向量幅度(范数):给出向量的长度

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 单位向量:范数= 1 的向量
  • 对于 n 维向量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 向量平方的范数等于

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 向量点积

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 对于 n 维向量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 点积可以表示为

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Dot product rule

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

The projection of the vector u on the vector v,

  • 如果 v 是一个单位向量,那么点积等于向量 u 在向量 v 上的投影
  • 如果两个向量都是单位向量,那么如果两个向量完全对齐,点积将最大
  • 如果两个向量正交,那么点积等于 0

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

概率论

概率论是我们处理世界不确定性的方式,它是一个数学框架,估计一个事件相对于其他可能事件发生的概率。概率是很多机器学习算法的非常深的层次。

我们来讨论一下解释概率论最著名的经验。掷两次公平硬币
在这个例子中,样本空间是所有可能结果的集合。
SS = { HH,TH,HT,TT }T 是反面, H 是正面。在大多数情况下,你会对所有可能结果的子集感兴趣,例如,你可能只对两次投掷都是正面的结果感兴趣 {HH} ,或者对两次投掷产生不同正面的事实感兴趣 {HT,TH}。
一个事件的概率是分配给一个事件的数 Pr(X)
>= 0
Pr(SS)= 1
(记住 SS 是样本空间)
Frequentists 统计:
Pr(X)= N(X)/N
—如果我们重复实验 X N 次。如果 n(X) 是我们观察 X. 的次数,那么 Pr(X) = n(X)/N

联合概率

对于两个事件 X 和 Y,联合概率是 X 和 Y 同时发生的概率,第一次掷是正面,第二次掷是反面的概率是多少。
Pr(1st 是 H,2nd 是 T) = Pr(1st 是 H) Pr(2nd 是 T) = 0.5 * 0.5 = 0.25。 如果 X 是*{ HH }**B*是 *{HT,TH},*联合概率 P(XY) 为 0,因为 XY 不可能同时发生。

独立性ˌ自立性

如果两个事件 X,Y 是独立的,那么

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

也就是说, X 发生,并没有说明 y 发生的概率。在硬币的例子中,如果第一次投掷产生了 H,这并不意味着第二次投掷也有可能是 H 和 T,仍然有 50%的机会。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

High Blood Pressure test results

在上图中,是对 30 岁以下的人和 30 岁以上的人进行高血压测试的结果。该表显示了一个样本的结果。
如果 X 是{受试者不到 30 岁}, Y 是{受试者没有高血压}

Pr(XY) 是 1800/4000,
Pr(X) 是 2000/4000,
Pr(Y) 是 2000/4000
由于 Pr(XY) 不等于 Pr(X)PR(Y) ,这就意味着 X

调节

如果 XY 都是 Pr(X) > 0 的事件,则 Y 给定 X 的条件概率为

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简单来说,这意味着如果我们知道 Y 发生了,那么 X 的概率是多少?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

High Blood Pressure test results

再次回到上图中的例子,如果 X 是{受试者不到 30 岁}, Y 是{受试者没有高血压}

Pr(X|Y) =?
在我们知道受试者没有高血压的情况下,他/她不到 30 岁的概率是多少?
Pr(X | Y)= Pr(XY)/Pr(X)=(1800/4000)/(2000/4000)= 0.9
Pr(Y | X)= Pr(XY)/Pr(Y)=(1800/4000)/(2000/4000)= 0.9
两者相同只是

如果我们知道 XY 是独立的,那么 Pr(A|B) = Pr(A) ,请记住掷硬币的例子,如果我们知道没有一个输出对另一个输出有特殊影响,那么任何输出发生的概率既不影响任何先前条件,也不受任何先前条件的影响。

贝叶斯法则

给定 2 个事件 X 和 Y,并假设 Pr(X) > 0,则

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Boxes example, a sketch made by skettchboard

*如果我们有两个盒子,其中一个是红色的,另一个是蓝色的,蓝色的盒子包含 3 个平面和 1 颗星,红色的盒子包含 6 颗星和 2 个平面。
让 *Pr(从蓝色盒子中挑选)*为 60%, *Pr(从红色盒子中挑选)为 40%。

形状是 S,盒子是 B
Pr(B = r)= 0.4
Pr(B = B)= 0.6

条件概率:
Pr(S = p | B = r)= 1/4
Pr(S = h | B = r)= 3/4
Pr(S = p | B = B)= 3/4
Pr(S = h | B = B)= 1/4

*挑平面的概率:
这可以解释为我们选蓝框就从蓝框里挑平面的概率,选蓝框就从蓝框里挑平面的概率。
*Pr(S = p)= Pr(S = p | B = r)p(B = r)+Pr(S = p | B = B)p(B = B)=1/4 * 4/10+3/4 * 6/10 = 11/20

这是你继续你的 ML 之旅所需要了解的基本知识,祝你好运!

Numpy 线性代数基础(第一部分)

原文:https://towardsdatascience.com/linear-algebra-essentials-with-numpy-part-1-af4a867ac5ca?source=collection_archive---------4-----------------------

啊,数学。你不可能永远回避它。你可以尝试,然后更努力地尝试,但迟早需要一些基本的直觉,前提是你认真努力推进你在数据科学领域的职业生涯。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Antoine Dautry on Unsplash

说到线性代数,我非常喜欢这句话:

如果数据科学是蝙蝠侠,线性代数就是罗宾。[1]

它以一种非技术性的方式巧妙地抓住了本质。

为什么要学习线性代数?

问得好。
简单来说,如果你理解了它,你将能够为机器学习和深度学习算法开发出更好的直觉,而不会把它们视为黑盒。此外,你还可以从头开始开发算法,并对它们进行自己的修改。

不仅如此,你还会被认为是一个很酷的孩子,就像这两个:

By GIPHY

太棒了。

我为什么要看这个帖子?

这篇文章当然不会教你关于这个话题的每一个细节,有太多的书涵盖了这些。这篇文章也不会深究证据,再说一遍,如果你对数学或科技感兴趣的话,就去读一本书吧。然而,这篇文章将为你提供 14 个不同领域的线性代数(和一些简单的计算)背后的基本直觉。

是的,你没看错。我计划在两篇文章中涵盖 14 个不同的主题。你会花一些时间去阅读(我也会花一些时间去写),但是如果你是新手,我强烈建议你每天最多阅读 2-3 个主题,然后在网上搜索更多的练习题。

文章结构如何?

因此,每个主题分为 3 个部分:

  1. 理论解释
  2. 示例(手工计算)
  3. 用 Python 实现(用 Numpy)

我不骗你,这将是一个很大的工作量。这第一部分将涵盖向量,以下是主题列表:

  1. 添加
  2. 纯量乘法
  3. 点积
  4. 标准
  5. 单位向量
  6. 向量之间的角度

现在介绍完了,就不要推迟必然了。喝杯咖啡(或者更烈的东西),和我一起去线性代数的神奇世界吧。

You after finishing this article. By GIPHY

什么是向量?

是啊,如果你不知道向量是什么,就没有必要从向量加法开始。首先,把向量想象成空间中的箭头。这里你需要记住两个量:

  • 方向
  • 重要

我说的方向是指箭头指向的空间位置,而大小告诉你在那个方向上你应该走多远。如果你只有大小,没有方向,那么你说的就是标量。一旦给标量一个方向,它就变成了矢量。

我说你应该试着把向量想象成箭头——这是一个完美的术语,因为箭头既有明确的方向,也有明确的大小(长度)。

向量通常用小写字母和上面指向右边的箭头表示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简单,对吧?
现在让我们开始一些向量运算吧,我知道你一定很不耐烦(* *)。

1.向量加法

让我们开始第一个向量运算,这是向量加法(减法的工作方式是一样的,显然,只是你用减号代替了加号)。

这个基本操作真的没什么好说的,只说是通过添加相应的组件来执行的。如果你考虑向量会发生什么,而不仅仅是单纯的数字相加,这有助于理解这个观点。

看看这张来自维基共享的照片:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Vector Addition

简单来说,就是把矢量 b 加到矢量*(得到 a+b ),从原点画出矢量 a ,再从矢量 a 的尖端画出矢量 b 。现在要得到 a+b ,只需要将原点连接到矢量 b 的尖端。*

如果你第一次听到这个,可能会觉得有点夸张,但是只要拿起笔和纸画出来,你马上就会明白它的要点。

这是矢量加法的一般公式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我将手工做一个简单的例子,稍后我将用 Python 实现这个例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

再一次,拿一张纸来画这个——这非常直观。

Python 中的实现:

*v = np.array([3, 7])
u = np.array([2, 2])print(v + u)*

如您所见,Numpy 允许您使用加法运算符,非常简洁!

2.纯量乘法

让我引用我在本文前面说过的话:

如果你只有大小,没有方向,那么你说的就是标量。

这实质上意味着标量是一个单一的数字,它只能改变矢量的大小,而不能改变它的方向。这实际上意味着,乘以任何标量的矢量将保持在同一条“线上”,它将具有相同的方向,只是它的长度会改变。

太棒了,让我们看看标量乘法的公式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上, n 代表任意数字。让我们看一个例子。标量 n 将为 2,这意味着向量的每个分量都将乘以 2。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

*v = np.array([3, 7])print(2 * v)*

太棒了,我们进入下一个话题!

3.点积

要计算两个向量的点积,首先需要用乘以对应的元素 ( x1 乘以 y1x2 乘以 y2 等等),然后求和乘积项

当你看到通式时,这个概念实际上更容易理解,所以它是这样的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在我将写下一个二维空间中两个向量的基本例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

*v = np.array([3, 7])
u = np.array([2, 2])print(v.dot(u))*

是的,这就是关于点积的大部分内容——没什么可谈的。

4.向量范数

范数是向量长度或大小的另一个术语,用两边的双管(||)表示。它被定义为一个矢量的每个分量的平方和的平方根,你将在下面的公式中看到。

计算过程分为三步:

  1. 将每个组件平方
  2. 对所有平方求和
  3. 求平方根

你可以想象,这个公式简单得愚蠢:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个二维空间中向量的实际例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

*v = np.array([3, 2, 7])print(np.linalg.norm(v))*

5.单位向量

计算单位向量的主要原因是,你只关心方向,而不关心大小。这个标准化过程包括去除幅度,这样就不会影响其他计算。[2]

单位矢量通常用帽子符号(^)表示,通过计算范数,然后用该范数除矢量的每个分量来计算。

事不宜迟,公式如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作为一个例子,我将从一个任意的三维向量计算单位向量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

你不必做最后一步——除以平方根——但它使最终结果更有吸引力。

Python 中的实现在这里会有点不同。Numpy 中没有内置函数用于计算单位向量(至少我不知道),但是因为你知道公式,所以计算过程比较繁琐。我已经声明了一个函数,它将一个向量作为输入,然后返回这个向量除以它的范数:

*def unit_vector(v):
    return v / np.linalg.norm(v)u = np.array([3, 6, 4])
print(unit_vector(u))*

6.向量之间的角度

这可能是线性代数中我最感兴趣的话题。原因是我在日常工作中到处用它来做一些很酷的事情。

向量之间的角度计算有很多实际应用。在 NLP ( 自然语言处理 )中寻找非常相似的字符串时广泛使用。例如,当对一些文本数据使用 TF-IDF 时,每个输入(试着把输入想象成一个单独的电子邮件文本)都被转换成一个向量。

通过这样做,您将确保所有向量都是相同的维数,如果输入在某个位置包含某个单词,则向量的相应分量的值将是 1,否则为 0。如果你计算向量之间的角度,角度最小的向量会更相似(在电子邮件的例子中,就像两封邮件是关于同一个主题的)。

希望你能看到你的项目中潜在的用例,如果没有,不要担心,你最终会看到的。

这是计算角度的公式。没什么特别的,你把两个向量的点积除以范数的积:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是两个任意三维向量的简单例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与单位向量一样,Numpy 没有用于角度计算的内置函数。但是嘿,你知道这个公式,所以这能有多难呢?
这里唯一的“窍门”是将弧度转换成度数,因为 Numpy 默认情况下将以弧度返回结果。其他的一切都和你想象的一样简单。

代码如下:

*def angle_between(v1, v2):
    dot_pr = v1.dot(v2)
    norms = np.linalg.norm(v1) * np.linalg.norm(v2)

    return np.rad2deg(np.arccos(dot_pr / norms))v = np.array([1, 4, 5])
u = np.array([2, 1, 5])print(angle_between(v, u))*

这基本上结束了关于向量的讨论。没那么糟吧?

结论

这就是数据科学中线性代数的一些基本要素,至少对于向量来说是这样。下一篇文章将会隐藏矩阵,并且会比这篇文章长一点。

在你等待的时候,我强烈建议你去 YouTube 上看看这个精彩的频道,尤其是这个播放列表。它真正深入到线性代数的基本和高级概念背后建立直觉。如果你知道如何计算,但不知道为什么要计算,这个频道是我真诚的推荐。

3Blue1Brown — Essence of linear algebra playlist

感谢阅读。

第二部分:

* [## Numpy 线性代数基础(第二部分)

学习数据科学的基本线性代数技能—第 2/2 部分

towardsdatascience.com](/linear-algebra-essentials-with-numpy-part-2-d15717eebfd9)

By GIPHY*

喜欢这篇文章吗?成为 中等会员 继续无限制的学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

* [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)*

参考

[1]https://www . analyticsvidhya . com/blog/2019/07/10-应用-线性代数-数据-科学/

[2]https://stack overflow . com/questions/2304634/why-do-we-need-a-unit-vector-in-other-words-why-do-we-need-normalize-vector

Numpy 线性代数基础(第二部分)

原文:https://towardsdatascience.com/linear-algebra-essentials-with-numpy-part-2-d15717eebfd9?source=collection_archive---------12-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Photo by Markus Spiske temporausch.com from Pexels

几天前,我发表了数据科学线性代数系列的第一部分。它涵盖了 6 个关键概念和术语,因此如果您还没有阅读,我强烈建议您先阅读该部分:

[## Numpy 线性代数基础(第一部分)

学习数据科学的基本线性代数技能—第 1/2 部分

towardsdatascience.com](/linear-algebra-essentials-with-numpy-part-1-af4a867ac5ca)

由于前一部分已经讲述了为什么和这个故事是什么(例如为什么线性代数),这一部分将直接切入正题。文章的结构是一样的。每个主题分为 3 个部分:

  1. 理论解释
  2. 示例(手工计算)
  3. 用 Python 实现(用 Numpy)

关于主题,我想说的是:

  1. 矩阵加法
  2. 纯量乘法
  3. 矩阵乘法
  4. 矩阵的转置
  5. 单位矩阵
  6. 决定因素
  7. 矩阵求逆

是的,我知道,这将是一个很大的工作量,再次。你对此无能为力——拿起一杯咖啡(或苏格兰),让我们开始吧!

By GIPHY

什么是矩阵?

维基百科:

矩阵是数字或其他数学对象的矩形阵列,定义了加法和乘法等运算。[1]

作为一名数据科学家,你一直在使用矩阵,但你可能还不知道(只是还不知道)。您过去使用的任何数据集都可以被认为是一个矩阵——一个由数字组成的矩形阵列— 行和列更具体地说。

从数据科学家的角度来看,你可能想知道矩阵和向量有什么不同。简单来说,vector 是你数据集中的一个单列(属性),而 matrix 是所有列的集合。

矩阵通常用大写加粗字母表示,例如:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

和向量一样,掌握关键概念并不困难。

让我们深入一些例子。

1.矩阵加法

矩阵加法(或减法)和你之前用向量做的很相似。唯一的区别是有多列而不是只有一列。

整个想法保持不变,你只需要把相应的组件加起来。在通式中,我使用了 ab 作为占位符,你可以看到每个部分是如何相加的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虽然这很容易理解,但这里有一个简单的 2 矩阵加法的例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

矩阵加法在 Numpy 中实现非常简单。同样,与向量一样,您可以使用加号:

A = np.matrix([
    [3, 5],
    [1, 0]
])
B = np.matrix([
    [2, -3],
    [1, 2]
])print(A + B)

2.纯量乘法

这些概念与向量或多或少是一样的。矩阵中的每一个数字都会乘以一些标量 n

公式也很相似:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于这个例子,我选择使用一个任意的矩阵,并将标量 n 设置为 2:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

A = np.matrix([
    [3, 5],
    [1, 0]
])print(2 * A)

一切都和向量非常相似,对吗?

保持这种想法。

3.矩阵乘法

这里有一个话题,我想说的是,它比迄今为止遇到的其他话题要稍微复杂一些。这并不像一开始看起来那么难,但是你需要解决几个例子才能完全理解要点。

对于矩阵乘法部分的以下示例,声明了两个矩阵:

  1. 矩阵 A —尺寸为 mn ( m 行, n 列)
  2. 矩阵 B —尺寸为 np ( n 行, p 列)

AB 相乘将产生一个新矩阵,其尺寸为 m 乘以 p ( m 行乘以 p 列)。简单地说,得到的矩阵将具有矩阵 A 的行数和矩阵 B 的列数。

By GIPHY

在你完全理解最后一段之前,你可能需要读几遍,这没关系。为了帮助你,我现在所说的一切都是可视化的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

This helps, right?

如你所见,中间的两个 n 需要匹配。如果它们不相等,矩阵乘法不能被执行。大多数编程语言都会抛出一个关于尺寸不匹配的错误。

好了,现在当你理解了矩阵乘法的基本规则,你就为通式做好了准备:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用最普通的方式陈述(请把这个嵌入你的大脑):

通过计算矩阵 A 的相应行和矩阵 b 的相应列的点积来执行矩阵乘法

如果你理解了那句话,你就理解了矩阵乘法。如果没有,让我们用一个简单的例子来说明这一点:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

与向量一样,您可以使用 函数来执行与 Numpy 的乘法:

A = np.matrix([
    [3, 4],
    [1, 0]
])
B = np.matrix([
    [2, 2],
    [1, 2]
])print(A.dot(B))

如果第一次阅读后很难理解,不要担心。矩阵乘法对我来说也是一个很难理解的概念,但是真正有帮助的是在纸上手工做。网上有很多例子。

不想找例子就自己编,然后用 Numpy 验证——像个 boss

4.矩阵转置

现在来点简单的,让你的大脑休息一分钟。但就一分钟。

矩阵转置是其中一个听起来非常奇特的话题,特别是如果你不是以英语为母语的人,你不知道转置是什么意思。

这个想法非常简单——你只需要交换矩阵的行和列。转置运算符在大多数情况下用大写字母 T 表示,符号可以放在矩阵前或作为指数。无论哪种方式,下面是一般公式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如你所看到的,对角线元素保持不变,而非对角线元素改变了位置。

下面是一个 2x2 矩阵的简单示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用 Python 实现真的不能再简单了:

A = np.matrix([
    [3, 4],
    [1, 0]
])print(A.T)

5.单位矩阵

正如转置一样,单位矩阵也很容易掌握。这是一个矩阵,其中:

  1. 每个对角元素都是 1
  2. 所有其他元素都是 0

就是这样!通常用大写字母 I 表示,下标中的数字代表它的大小。

以下是大小为 3 的单位矩阵的样子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不会有任何单位矩阵的例子(目前),我将只向您展示如何用 Python 创建它们:

A = np.eye(3)print(A)

现在回到更难的事情上来。

6.决定因素

根据维基百科:

行列式是一个标量值,可以从方阵的元素中计算出来,并对矩阵所描述的线性变换的某些属性进行编码。
矩阵 A 的行列式表示为 det( A ),det A ,或| A |。从几何学上讲,它可以看作是矩阵所描述的线性变换的体积比例因子。[2]

为了更直观地了解行列式是什么,以及它的用途,请参考文章结论部分的视频播放列表。

对于 2x2 矩阵,计算过程很简单,对于 3x3 矩阵,get 有点困难,对于更大的矩阵,不应该手动计算。我是说如果你想的话你可以,但是为什么呢?这里的目标是发展直觉,计算机是用来做计算的。

下面是计算 2x2 矩阵行列式的一般公式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了说明问题,这里有一个最基本的手工计算的例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

A = np.matrix([
    [3, 2],
    [1, 6]
])print(np.linalg.det(A))

你做得很好。后面是最后一节,然后就大功告成了!

7.矩阵求逆

如果原矩阵与其逆矩阵相乘得到单位矩阵,则称方阵可逆(或非奇异*)。*

从这句话,你可以得出结论,不是所有的矩阵都有逆。对于可逆矩阵,它必须满足以下条件:

  • 必须是方形的
  • 行列式不能为 0

不可逆的矩阵称为奇异矩阵。从逻辑上讲,方阵要奇异,其行列式必须等于 0。让我们通过探索一般公式来看看为什么:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如你所见,矩阵的逆由上标中的这个 -1 项表示。这个公式你可能已经很熟悉了——之前见过ad——BCterm(行列式)。这里可以看出为什么行列式不能是 0 — 除以 0 是未定义的。**

这一项然后乘以稍微重新排列的原始矩阵。对角元素被交换,非对角元素被乘以负一(-1)。

下面是一个计算 2x2 矩阵逆矩阵的简单示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

**A = np.matrix([
    [4, 3],
    [5, 4]
])print(np.linalg.inv(A))**

现在让我们来验证一下先前的说法,即原始矩阵与其逆矩阵相乘产生单位矩阵:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个手工计算的例子,这些陈述是正确的!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Python 中的实现:

**print(A.dot(np.linalg.inv(A)))**

结论

花点时间祝贺自己坚持到了最后。我希望你已经阅读了文章的第一部分,如果你已经阅读了,谢谢你。

By GIPHY

也许并非所有讨论的术语都直接适用于数据科学(从你的角度来看),但线性代数通常是值得了解的——这可能会在你即将到来的数据科学面试中被问到,所以了解基础知识是必须的。

现在放松一下,看部电影,喝几杯啤酒,让一切都沉淀下来。大约一周后,我建议你自己进一步探索线性代数,当然,一定要看这个播放列表:

我可以强调这对你发展线性代数的直觉方法有多大的帮助。

感谢阅读…

喜欢这篇文章吗?成为 中等会员 继续无限制学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。

** [## 通过我的推荐链接加入 Medium-Dario rade ci

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

medium.com](https://medium.com/@radecicdario/membership)**

参考

[1]https://en . Wikipedia . org/wiki/Matrix _(数学)

https://en.m.wikipedia.org/wiki/Determinant

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值