python

python源码解析0:趣事

About 两处python源码的趣味解读。 The Zen of Python 我们知道,import this会打印如下“蟒蛇之禅”: 123456789101112131415161718192021 The Zen of Python, by Tim PetersBeautiful is better than ugly.Explicit is better than implicit.Simple is better than complex.Complex is better than complicated.Flat is better than nested.Sparse is better than dense.Readability counts.Special cases aren't special enough to break the rules.Although practicality beats purity.Errors should never pass …

python源码解析0:趣事 Read More »

数据挖掘流程:数据可视化与预处理

数据挖掘的第一步,当我们手中拿到一份数据,当然是对数据进行观察与预处理了。本文主要对这两个方面做一个个人的总结。 import 掉包? 第0步,调包。。 通常numpy、pandas、scipy、seaborn已经matplotlib是必须的 为防止烦人的warning,还需要 12 import warningswarnings.filterwarnings('ignore') 因为我们不管warning只管error,哈哈 seaborn的设置颜色格式 1 sns.set_style('whitegrid') 以及 1 %matplotlib inline 观察与可视化 一般来说,我们应该首先观察标签的分布以及特征的分布,对于前者通常使用pandas Dataframe的columns,对于后者则是value_counts()和describe()来展示。如 1 df_train.columns 1 int_level = train_df['interest_level'].value_counts() 1 df_train['SalePrice'].describe() describe()会给出标签的各种数值信息,如 123456789 count 1460.000000mean 180921.195890std 79442.502883min 34900.00000025% 129975.00000050% 163000.00000075% 214000.000000max 755000.000000Name: SalePrice, dtype: float64 同时也可以借助于seaborn图来显示 1 sns.distplot(df_train['SalePrice']); 接下来可以看看标签的偏度和峰度(skewness and kurtosis) 12 print("Skewness: %f" % df_train['SalePrice'].skew())print("Kurtosis: %f" % …

数据挖掘流程:数据可视化与预处理 Read More »

Devide and Conquer Counting Inversions with Python

本文主要内容关于python归并排序求逆序数的算法。 解决问题:给定有限长度的无重复乱序数组,求其逆序数个数。简单来说我们可以用两个循环来解决,但是复杂度为$O(N^2)$,若利用归并排序,复杂度就降为了$O(N log(N))$。以下给出一个实现, 123456789101112131415161718192021222324252627282930313233343536373839404142 class Ivrs_num(object): def __init__(self, filename): self.count = 0 self.filename = filename def load_txt(self): '''载入txt文件保存为list''' int_list = [] with open(self.filename) as f: for line in f: int_list.append(int(line)) return int_list def merge(self, ListA, ListB): '''将两个已经排序好的数组合并成新的排序好的数组 顺便计算逆序数''' newList = [] while ListA and ListB: if int(ListA[0]) > int(ListB[0]): self.count += len(ListA) newList.append(ListB.pop(0)) else: newList.append(ListA.pop(0)) …

Devide and Conquer Counting Inversions with Python Read More »

Understanding EM algorithm

本文主要内容为用一个简短的例子解释EM算法。 EM算法是聚类中常用的机器学习算法,但是相比喜闻乐见的k-means算法,大家可能对于EM算法的了解可能没有那么直观深入,所以本文主要利用一个简单的例子,在对比k-means算法的过程中,帮助大家建立一个清晰明确的对EM算法的理解。 当我们在聚类的领域谈论k-means算法时,分组的概念是非常清晰直观的–每个样本点只属于它离得最近的那个中心点所属的分组。如果给出一些样本点和中心,那么我们很容易给这些点打标签。 但是对于EM算法而言,分组的概念就么那么直观了(因为EM算法考虑每个样本点都有一定的概率属于所有的分组)。在我们介=引入EM算法之前,我们先复习一下k-means里面的分组概念。 k-means里面的分组概念 假设我们有如下的三个样本点(2D平面情况下的点): 数据集 X Y 点0 10 5 点1 2 1 点2 3 7 如果在上面的数据集上跑k-means算法,假定中心点如下: 中心 X Y A 3 4 B 6 3 C 4 6 使用欧几里得距离,可以分配聚类如下 距离 群组A中心 群组B中心 群组C中心 群组分配 点0 7.071 4.472 6.083 群组B 点1 3.162 4.472 5.385 群组A 点2 3.000 5.000 1.414 群组C 到此,我们可以给出一个回答:到底把一个点归类到一个群组意味着什么?举例来说,点1只被分配到分组A,也就是点1的100%属于群组A并且0%属于群组B和群组C。那么根据这个定义,我们可以得到如下表格, 群组A 群组B …

Understanding EM algorithm Read More »

RECURRENT NEURAL NETWORK TUTORIAL, PART 4 – IMPLEMENTING A GRU/LSTM RNN WITH PYTHON AND THEANO

本文中,我们将学习关于LSTM (Long Short Term Memory)网络和 GRUs (Gated Recurrent Units)的知识。LSTM最初由Sepp Hochreiter and Jürgen Schmidhuber于1997年提出,如今是深度学习自然语言处理领域最流行的模型。GRU,出现于2014年,是LSTM的简化版,与LSTM有许多相似的特性。 ##LSTM 网络 在第三部分我们提到了梯度消失问题妨碍了标准的RNN学习长期依赖问题。LSTM被设计于用gate结构解决梯度消失问题。为了理解这个机制,我们来看看LSTM如何计算隐藏状态$$s_t$$(其中小圆圈代表Hadamard product,即同型矩阵各元素对应相乘,不同于矩阵点乘)。 式子看起来复杂,一步一步来理解实则简单。首先,LSTM的一层代表的只是另一种计算隐藏层的方法。之前我们计算了隐藏状态$$s_t = tanh(Ux_t + WS_{s-1})$$。对于当前的单元,输入是$$t$$时刻的$$x_t$$,而$$s_{t-1}$$是之前的隐藏状态,输出是新的隐藏状态$$s_t$$。其实,LSTM做的事情是完全一样的,只不过换了种方式,这也是理解LSTM的核心。我们可以把LSTM单元看作是黑盒子,给予其当前输入和之前的隐藏状态,它可以输出下一个隐藏状态。 把这个牢记于心,我们开始来阐述LSTM如何计算隐藏状态。关于这一点,详细可看这篇文章,这里我们只作简短描述: $$i,f,o$$分别被称为输入门、遗忘门和输出门。注意到,它们具有相同的等式,只是参数矩阵不同。它们之所以被称为“门”,是因为sigmoid函数将向量值压缩到0和1之间,再与另一个向量相乘,我们因此决定向量的多少“通过”。输入门决定当前输入计算出来的状态的多少成分被通过,遗忘门决定之前的状态有多少可以被保留到之后,输出门决定当前的状态有多少被传送到外层的网络(高层网络和下一时刻)。这些门的维度都是$$d_s$$,即隐藏层的大小。 $$g$$是一个候选的隐藏状态,基于当前的输入和之前的隐藏状态计算而出。其与vanilla RNN的计算等式相同,只是把参数$$U,W$$改名为$$U^g,W^g$$。和RNN的直接将$$g$$作为心的隐藏状态不同,我们将其通过一个输入门来决定保留它的多少成分。 $$c_t$$是单元的内部的记忆,它由之前的记忆$$c_{t-1}$$通过遗忘门再加上新计算出来的隐藏状态$$g$$通过输入门计算得出。因此,它代表了旧的记忆与新的输入的结合。我们可以选择全部忽略旧的记忆(遗忘门全部置零),或者忽略全部的计算出的新状态(输入门全部置零),但是通常来说,我们可能更希望介于两者之间。 给定记忆$$c_t$$,我们最终通过让记忆和输出门相乘计算出输出隐藏层状态$$s_t$$。在网络内,不是所有的内部记忆都与其他单元使用的隐藏状态有关。 换一种说法,我们可以将标准的RNN看作是特殊的LSTM,如果我们将遗忘门全部置零,输入门全部置一,输出门全部置一,我们就几乎得到一个标准的RNN。通过门机制,LSTM可以操作记忆从而解决长期依赖问题。 注意到,还有许多的LSTM变种,一种添加上“猫眼”结构,它的门同时取决于之前的隐藏状态$$s_{t-1}$$和之前的内部状态$$c_{t-1}$$。 LSTM: A Search Space Odyssey 实验观察了许多不同的LSTM机制。 ##GRU网络 GRU的理念类似于LSTM,其等式如下: GRU拥有两个门,称为重置门$$r$$和更新门$$z$$。直观来说,重置门决定如何联合新的输入和之前的记忆,而更新门决定留下多少之前的记忆。如果将重置门全部置一并且更新门全部置零,那么我们又得到了我们原始的RNN了。GRU的解决长期依赖的理念和LSTM基本类似,以下是一些不同之处: 两个门VS三个门 GRU不处理内层记忆$$c_t$$ 输入门和遗忘门被组合成更新门$$z$$,重置门$$r$$直接连接之前的隐藏状态。因此, 计算输出是不加上第二个非线性变换 ##GRU VS LSTM 如今你认识了两个对抗梯度消失的模型  

RECURRENT NEURAL NETWORKS TUTORIAL, PART 3 – BACKPROPAGATION THROUGH TIME AND VANISHING GRADIENTS

在之前的部分我们实现了RNN,但是并未深入探究时间反向传播算法,本文将对这一点作详细说明。我们将了解关于梯度消失问题的知识,它促使了LSTM和GRU的出现,而这两者都是NLP领域非常常见的模型。 ##BACKPROPAGATION THROUGH TIME (BPTT) 首先我们回顾一下RNN的基本等式: 我们也定义了损失函数(交叉熵): 在这里,$$y_t$$是 $$t$$时刻的正确的词语, $$tilde{y_t}$$ 是我们的预测。因为我们把一整个序列(句子)当做是输入,那么错误等同于每个时间step(词语)的错误的和。 ![](/images/2016/06/rnn-bptt1.png) 需要注意,我们的目标是计算基于参数$$U, V, W$$错误的梯度,并且通过SGD来学习到好的参数。类似于我们将错误相加的做法,对于一个训练样本,我们将各个时间点的梯度相加。 $$frac{partial{E}}{partial{W}} = sum_{t} frac{partial{E_t}}{partial{W}}$$ 我们使用链式求导法则来计算这些梯度,这就是反向传播算法:从错误处反向计算。以下我们使用$$E_3$$作为例子。 其中,$$z_3 = V s_3$$,并且$$otimes$$指的是向量外积。在这里我们需要注意到,$$frac{partial{E_3}}{partial{V}}$$只取决于当前时刻的值$$tilde{y_3}, y_3, s_3$$。如果你明确了这一点,那么计算$$V$$的梯度只是矩阵计算罢了。 但是,对于$$frac{partial{E_3}}{partial{W}}$$和$$V$$就不一样了。我们写出链式法则: 可以看到,$$s_3 = tanh(U x_t + W s_2)$$取决于$$s_2$$,而$$s_2$$又取决于$$W$$和$$s_1$$,以此类推。所以我们计算$$W$$的偏导,我们不能把$$s_2$$当做一个常量,相反我们需要一遍遍的应用链式法则: 我们把每个时间点对于梯度贡献综合起来。换句话说,因为$$W$$在直到我们需要输出的时刻都被用到,所以我们需要计算$$t=3$$时刻直到$$t=0$$时刻: 这其实和深度前馈神经网络里的标准的反向传播算法是类似的。主要的不同点在于我们把每个时间点的$$W$$的梯度综合起来。传统的神经网络的不同层之间不共享参数,于是我们也不需要综合什么。但是在我看来,BPTT只不过是在没有展开的RNN上的标准BP算法的别名罢了。类似于标准的BP算法,你也可以定义一个徳塔项来表示反向传播的内容。例如:$$delta_{2}^{(3)} = frac{partial{E_3}}{partial{z_2}} = frac{partial{E_3}}{partial{s_3}} frac{partial{s_3}}{partial{s_2}} frac{partial{s_2}}{partial{z_2}}$$,其中$$z_2 = Ux_2 + Ws_1$$。以此类推。 代码实现BPTT如下: 123456789101112131415161718192021222324 def bptt(self, x, y): T = len(y) …

RECURRENT NEURAL NETWORKS TUTORIAL, PART 3 – BACKPROPAGATION THROUGH TIME AND VANISHING GRADIENTS Read More »

RECURRENT NEURAL NETWORKS TUTORIAL, PART 2 – IMPLEMENTING A RNN WITH PYTHON, NUMPY AND THEANO

本文将用Python实现完整的RNN,并且用Theano来优化。 语言模型 我们的目标是使用RNN建立一个语言模型。以下我们举例说明什么是语言模型。例如,你说了一句包括$$m$$个词语的句子,语言模型可以为这句话出现的概率打分: $$P(w_1,cdots,w_m) = prod_{i=1}^m P(w_i mid w_1,cdots,w_{i-1})$$ 每一个词语的概率都取决于它之前的所有的词的概率。 这样的模型有什么用处呢? 可以用于机器翻译或者语音识别中的正确句子打分 以概率生成新的句子 注意到在上面的公式内,我们使用了所有的之前的词的概率,实际上这在计算和存储时的耗费都是巨大的,通常而言只会取2~4个词左右。 预处理并训练数据 1.标记化 原始的文本需要被标记化,例如需要把文本标记为句子,句子标记为词语,并且还需要处理标点符号。我们将使用NLTK的word_tokenizesent_tokenize方法。 2.移除低频词 移除低频词不管是对于训练和预测都是有帮助的。这里我们设置一个上限vocabulary_size为8000,出现次数少于它的词都会被替换为UNKNOWN_TOKEN输入,而当输出是UNKNOWN_TOKEN时,它将被随机替换为一个不在词表内的词,亦或者持续预测直到不出现UNKNOWN_TOKEN为止。 3.放置句子开始和结束标记 为了解句子的开始和结束,我们把SENTENCE_START放置在句子开头,并且把SENTENCE_END放置在句子结尾。 4.建立训练数据的矩阵 RNN的输入和输出都是向量而不是字符串,我们需要把词与向量一一对应,通过index_to_word和word_to_index。比如一个训练的例子$$x$$为[0, 179, 341, 416](注意到其中每个元素都是长度为vocabulary_size的one-hot向量,所以$$x$$实际上是一个矩阵),那么其label-$$y$$为[179, 341, 416, 1],注意到我们的目标是预测下一个词,所以$$y$$就是$$x$$移动一位,并添加上最后的一个元素(预测词)的结果,其中SENTENCE_START和SENTENCE_END分别为0和1. 123456789101112131415161718192021222324252627282930313233343536373839404142 vocabulary_size = 8000unknown_token = "UNKNOWN_TOKEN"sentence_start_token = "SENTENCE_START"sentence_end_token = "SENTENCE_END"# Read the data and append SENTENCE_START and SENTENCE_END tokensprint "Reading CSV file…"with open('data/reddit-comments-2015-08.csv', 'rb') as f: …

RECURRENT NEURAL NETWORKS TUTORIAL, PART 2 – IMPLEMENTING A RNN WITH PYTHON, NUMPY AND THEANO Read More »