Hsinyan写字的地方 - 人工智能
type: channel
link: https://www.hsinyan.cn/index.php/category/ai/
items: D2L学习笔记03：从零实现一个线性回归
items: D2L学习笔记02：线性回归
items: D2L学习笔记01：线性代数
items: D2L学习笔记00：Pytorch操作
items: Word2vec理论基础——词向量
items: Tokenize
items: 梯度下降法
items: 多元线性回归
items: 线性回归算法
items: 数值归一化

D2L学习笔记03：从零实现一个线性回归
type: item
date: 2022-04-30T15:06:07+08:00
description: 接下来将从零开始实现线性回归整个方法，包括数据流水线、模型、损失函数和小批量随机梯度下降优化器。虽然现代的深度学习框架几乎可以自动化地进行所有这些工作，但从零开始实现可以确保你真正知道自己在做什么。同时，了解更细致的工作原理将方便我们自定义模型、自定义层或自定义损失函数。在这一节中，我们将只使用张量和自动求导。%matplotlib inline import random import torch from d2l import torch as d2l生成数据集为了简单起见，将根据带有噪声的线性模型构造一个人造数据集，我们的任务是使用这个有限样本的数据集来恢复这个模型的参数。我们将使用低维数据，这样可以很容易地将其可视化。在下面的代码中，我们生成一个包含1000个样本的数据集，每个样本包含从标准正态分布中采样的2个特征。我们的合成数据集是一个矩阵$\textbf{X}\in \textbf{R}^{1000 \times 2}$。使用线性模型参数$\textbf{w} = [2, -3.4]^\top$、$b = 4.2$和噪声项$\epsilon$生成数据集及其标签：$$ \textbf{y}= \textbf{X} \textbf{w} + b + \epsilon. $$可以将$\epsilon$视为模型预测和标签时的潜在观测误差，在这里我们认为标准假设成立，即$\epsilon$服从均值为0的正态分布。为了简化问题，将标准差设为0.01，下面的代码生成合成数据集。def synthetic_data(w, b, num_examples): #@save """生成y=Xw+b+噪声""" X = torch.normal(0, 1, (num_examples, len(w))) y = torch.matmul(X, w) + b y += torch.normal(0, 0.01, y.shape) return X, y.reshape((-1, 1))true_w = torch.tensor([2, -3.4]) true_b = 4.2 features, labels = synthetic_data(true_w, true_b, 1000) print('features:', features[0],'\nlabel:', labels[0]) #features: tensor([-0.0575, 0.6582]) #label: tensor([1.8422])画出散点图可以看出两者之间的线性关系d2l.set_figsize() d2l.plt.scatter(features[:, (1)].detach().numpy(), labels.detach().numpy(), 1);读取数据集训练模型时要对数据集进行遍历，每次抽取一小批量样本，并使用它们来更新我们的模型。 由于这个过程是训练机器学习算法的基础，所以有必要定义一个函数， 该函数能打乱数据集中的样本并以小批量方式获取数据。在下面的代码中，定义一个data_iter函数， 该函数接收批量大小、特征矩阵和标签向量作为输入，生成大小为batch_size的小批量。 每个小批量包含一组特征和标签。def data_iter(batch_size, features, labels): num_examples = len(features) indices = list(range(num_examples)) # 这些样本是随机读取的，没有特定的顺序 random.shuffle(indices) for i in range(0, num_examples, batch_size): batch_indices = torch.tensor( indices[i: min(i + batch_size, num_examples)]) yield features[batch_indices], labels[batch_indices]通常，利用GPU并行运算的优势，处理合理大小的“小批量”。 每个样本都可以并行地进行模型计算，且每个样本损失函数的梯度也可以被并行计算。 GPU可以在处理几百个样本时，所花费的时间不比处理一个样本时多太多。直观感受一下小批量运算：读取第一个小批量数据样本并打印。 每个批量的特征维度显示批量大小和输入特征数。 同样的，批量的标签形状与batch_size相等。batch_size = 10 for X, y in data_iter(batch_size, features, labels): print(X, '\n', y) break #tensor([[ 0.9458, -0.0361]…

D2L学习笔记02：线性回归
type: item
date: 2022-04-28T20:26:00+08:00
description: 回归（regression）是能为一个或多个自变量与因变量之间关系建模的一类方法。在自然科学和社会科学领域，回归经常用来表示输入和输出之间的关系。在机器学习领域中的大多数任务通常都与预测（prediction）有关。当我们想预测一个数值时，就会涉及到回归问题。常见的例子包括：预测价格（房屋、股票等）、预测住院时间（针对住院病人等）、预测需求（零售销量等）。线性回归的基本元素线性回归（linear regression）可以追溯到19世纪初，它在回归的各种标准工具中最简单而且最流行。线性回归基于几个简单的假设：首先，假设自变量$x$和因变量$y$之间的关系是线性的，即$y$可以表示为$x$中元素的加权和，这里通常允许包含观测值的一些噪声；其次，我们假设任何噪声都比较正常，如噪声遵循正态分布。为了解释线性回归，举一个实际的例子：我们希望根据房屋的面积（平方英尺）和房龄（年）来估算房屋价格（美元）。为了开发一个能预测房价的模型，我们需要收集一个真实的数据集。这个数据集包括了房屋的销售价格、面积和房龄。在机器学习的术语中，该数据集称为训练数据集（training data set）或训练集（training set）。每行数据（比如一次房屋交易相对应的数据）称为样本（sample），也可以称为数据点（data point）或数据样本（data instance）。我们把试图预测的目标（比如预测房屋价格）称为标签（label）或目标（target）。预测所依据的自变量（面积和房龄）称为特征（feature）或协变量（covariate）。通常，我们使用$n$来表示数据集中的样本数，对索引为$i$的样本，其输入表示为$\textbf{x}^{(i)} = [x_1^{(i)}, x_2^{(i)}]^\top$，其对应的标签是$y^{(i)}$。线性模型线性假设是指目标（房屋价格）可以表示为特征（面积和房龄）的加权和，如下面的式子：$$ \textbf{price} = w_{\textbf{area}} \cdot \textbf{area} + w_{\textbf{age}} \cdot \textbf{age} + b. $$其中中的$w_{area}$和$w_{age}$称为权重（weight），权重决定了每个特征对我们预测值的影响，$b$称为偏置（bias）、偏移量（offset）或截距（intercept）。偏置是指当所有特征都取值为0时，预测值应该为多少。即使现实中不会有任何房子的面积是0或房龄正好是0年，我们仍然需要偏置项。如果没有偏置项，我们模型的表达能力将受到限制。严格来说，是输入特征的一个仿射变换（affine transformation）。仿射变换的特点是通过加权和对特征进行线性变换（linear transformation），并通过偏置项来进行平移（translation）。给定一个数据集，我们的目标是寻找模型的权重$\textbf{w}$和偏置$b$，使得根据模型做出的预测大体符合数据里的真实价格。输出的预测值由输入特征通过线性模型的仿射变换决定，仿射变换由所选权重和偏置确定。而在机器学习领域，我们通常使用的是高维数据集，建模时采用线性代数表示法会比较方便。当我们的输入包含$d$个特征时，我们将预测结果$\hat{y}$（通常使用“尖角”符号表示$y$的估计值）表示为：$$ \hat{y} = w_1 x_1 + ... + w_d x_d + b. $$将所有特征放到向量$\textbf{x} \in \mathbb{R}^d$中，并将所有权重放到向量$\textbf{w} \in \mathbb{R}^d$中，我们可以用点积形式来简洁地表达模型：$$ \hat{y} = \textbf{w}^\top \textbf{x} + b. $$向量$\textbf{x}$对应于单个数据样本的特征。用符号表示的矩阵$\textbf{X} \in \mathbb{R}^{n \times d}$可以很方便地引用我们整个数据集的$n$个样本。其中，$\textbf{X}$的每一行是一个样本，每一列是一种特征。对于特征集合$\textbf{X}$，预测值$\hat{\textbf{y}} \in \mathbb{R}^n$可以通过矩阵-向量乘法表示为：${\hat{\textbf{y}}} = \textbf{X} \textbf{w} + b$这个过程中的求和将使用广播机制，给定训练数据特征$\textbf{X}$和对应的已知标签$\textbf{y}$，线性回归的目标是找到一组权重向量$\textbf{w}$和偏置$b$：当给定从$\textbf{X}$的同分布中取样的新样本特征时，这组权重向量和偏置能够使得新…

D2L学习笔记01：线性代数
type: item
date: 2022-04-24T21:51:00+08:00
description: 这里略去了课程中部分线性代数基础笔记，只记录了自己理解得不够深刻的部分张量算法的基本性质标量、向量、矩阵和任意数量轴的张量（本小节中的“张量”指代数对象）有一些实用的属性。例如，你可能已经从按元素操作的定义中注意到，任何按元素的一元运算都不会改变其操作数的形状。同样，给定具有相同形状的任意两个张量，任何按元素二元运算的结果都将是相同形状的张量。例如，将两个相同形状的矩阵相加，会在这两个矩阵上执行元素加法。A = torch.arange(20, dtype=torch.float32).reshape(5, 4) B = A.clone() # 通过分配新内存，将A的一个副本分配给B A, A + B #(tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19.]]), # tensor([[ 0., 2., 4., 6.], # [ 8., 10., 12., 14.], # [16., 18., 20., 22.], # [24., 26., 28., 30.], # [32., 34., 36., 38.]]))具体而言，两个矩阵的按元素乘法称为Hadamard积（Hadamard product）（数学符号$\odot$）。对于矩阵$\textbf{B} \in \textbf{R}^{m \times n}$，其中第$i$行和第$j$列的元素是$b_{ij}$。矩阵$\textbf{A}$和$\textbf{B}$的Hadamard积为：$$ \textbf{A} \odot \textbf{B} = \begin{bmatrix} a_{11} b_{11} & a_{12} b_{12} & \dots & a_{1n} b_{1n} \\ a_{21} b_{21} & a_{22} b_{22} & \dots & a_{2n} b_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} b_{m1} & a_{m2} b_{m2} & \dots & a_{mn} b_{mn} \end{bmatrix}. $$A * B # tensor([[ 0., 1., 4., 9.], # [ 16., 25., 36., 49.], # [ 64., 81., 100., 121.], # [144., 169., 196., 225.], # [256., 289., 324., 361.]])将张量乘以或加上一个标量不会改变张量的形状，其中张量的每个元素都将与标量相加或相乘。a = 2 X = torch.arange(24).reshape(2, 3, 4) a + X, (a * X).shape #(tensor([[[ 2, 3, 4, 5], # [ 6, 7, 8, 9], # [10, 11, 12, 13]], # # [[14, 15, 16, 17], # [18, 19, 20, 21], # [22, 23, 24, 25]]]), # torch.Size([2, 3, 4]))降维我们可以对任意张量进行的一个有用的操作是计算其元素的和。在数学表示法中，我们使用$\sum$符号表示求和。为了表示长度为$d$的向量中元素的总和，可以记为$\sum_{i=1}^dx_i$。在代码中，我们可以调用计算求和的函数：x = torch.arange(4, dtype=torch.float32) x, x.sum() # (tensor([0., 1., 2., 3.]), tensor(6.))我们可以表示任意形状张量的元素和。例如，矩阵$\textbf{A}$中元素的和可以记为$\sum_{i=1}^{m} \sum_{j=1}^{n} a_{ij}$。A.shape, A.sum() # (torch.Size([5, 4]), tensor(190.))默认情况下，调用求和函数会沿所有的轴降低张量的维度，使它变为一个标量。我们还可以指定张量沿哪一个轴来通过求和降低维度。以矩阵为例，为了通过求和所有行的元素来降维（轴0），我们可以在调用函数时指定axis=0。由于输入矩阵沿0轴降维以生成输出向量，因此输入轴0的维数在输出形状中消失。A # tensor([[ 0., 1., 2., 3.], # [ 4., 5., 6., 7.], # [ 8., 9., 10., 11.], # [12., 13., 14., 15.], # [16., 17., 18., 19…

D2L学习笔记00：Pytorch操作
type: item
date: 2022-04-24T21:50:30+08:00
description: 导入包import torch虽然被称为Pytorch，但是代码中使用torch张量张量表示由一个数值组成的数组，这个数组可能有多个维度。具有一个轴的张量对应数学上的向量（vector）；具有两个轴的张量对应数学上的矩阵（matrix）；具有两个轴以上的张量没有特殊的数学名称。可以使用 arange 创建一个行向量 x。这个行向量包含以0开始的前12个整数，它们默认创建为整数。也可指定创建类型为浮点数。张量中的每个值都称为张量的 元素（element）。例如，张量 x 中有 12 个元素。除非额外指定，新的张量将存储在内存中，并采用基于CPU的计算。x = torch.arange(12) x # tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) # 可以通过张量的shape属性来访问张量（沿每个轴的长度）的形状 x.shape # torch.Size([12]) x.numel() # 12要想改变一个张量的形状而不改变元素数量和元素值，可以调用reshape函数。我们不需要通过手动指定每个维度来改变形状。 也就是说，如果我们的目标形状是（高度,宽度）， 那么在知道宽度后，高度会被自动计算得出，不必我们自己做除法。 在上面的例子中，为了获得一个3行的矩阵，我们手动指定了它有3行和4列。 幸运的是，我们可以通过-1来调用此自动计算出维度的功能。 即我们可以用x.reshape(-1,4)或x.reshape(3,-1)来取代x.reshape(3,4)。X = x.reshape(3, 4) X # tensor([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) X.reshape(2,-1) # tensor([[ 0, 1, 2, 3, 4, 5], # [ 6, 7, 8, 9, 10, 11]])有时，我们希望使用全0、全1、其他常量，或者从特定分布中随机采样的数字来初始化矩阵。# 创建一个形状为（2,3,4）的张量，其中所有元素都设置为0 torch.zeros((2, 3, 4)) # tensor([[[0., 0., 0., 0.], # [0., 0., 0., 0.], # [0., 0., 0., 0.]], # # [[0., 0., 0., 0.], # [0., 0., 0., 0.], # [0., 0., 0., 0.]]]) # 同理，所有元素设置为1 torch.ones((2, 3, 4)) # tensor([[[1., 1., 1., 1.], # [1., 1., 1., 1.], # [1., 1., 1., 1.]], # # [[1., 1., 1., 1.], # [1., 1., 1., 1.], # [1., 1., 1., 1.]]]) # 创建一个形状为（3,4）的张量。 其中的每个元素都从均值为0、标准差为1的标准高斯分布（正态分布）中随机采样。 torch.randn(3, 4) # tensor([[ 1.1704, -0.4649, -1.1481, -2.0655], # [-0.1964, 0.3888, 0.2516, -0.5367], # [-0.3829, -0.0578, 0.8739, -1.4293]])还可以用Python的嵌套数组来为所需张量中每个元素赋予确定值torch.tensor([[2, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]]) # tensor([[2, 1, 4, 3], # [1, 2, 3, 4], # [4, 3, 2, 1]])运算符x = torch.tensor([1.0, 2, 4, 8]) y = torch.tensor([2, 2, 2, 2]) x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算 # (tensor([ 3., 4., 6., 10.]), # tensor([-1., 0., 2., 6.]), # tensor([ 2., 4., 8., 16.]), # tensor([0.5000, 1.0000, 2.0000, 4.0000]), # tensor([ 1., 4., 16., 64.])) torch.exp(x) # tensor([2.7183e+00, 7.3891e+00, 5.4598e+01, 2.9810e+03])也可以把多个张量连结（concatenate）在一起，把它们端对端地叠起来形成一个更大的张量。只需要提供张量列表，并给出沿哪个轴连结。下面的例子分别演示了当沿行（轴-0…

Word2vec理论基础——词向量
type: item
date: 2020-08-02T22:28:00+08:00
description: NLP 处理方法传统：基于规则现代：基于统计机器学习HMM、CRF、SVM、LDA、CNN …“规则”隐含在模型参数里我们希望词编码能够做到什么词编码需要保证词的相似性我们希望类似青蛙、蟾蜍这些词在词编码之后保持相似性向量空间分布的相似性从一个向量从一种语系转化成另一种语系的时候能够保持分布向量空间子结构$$ V_{king}-V_{Queen}=V_{Man}-V_{Women} \\ V_{Paris}-V_{France}=V_{German}-V_{Berlin} $$我们希望原始文本信息能够得到保留，例如国王和女王之间的关系和男人与女人之间的关系应是特别接近的，法国和巴黎之间关系与德国和巴黎的关系也是接近的。最终目标词向量表示作为机器学习、特别是深度学习的输入和表示空间在计算机中表示一个词WordNetWordNet是由Princeton大学的心理学家，语言学家和计算机工程师联合设计的一种基于认知语言学的英语词典。它不是光把单词以字母顺序排列，而且按照单词的意义组成一个“单词的网络”。它是一个覆盖范围宽广的英语词汇语义网。名词，动词，形容词和副词各自被组织成一个同义词的网络，每个同义词集合都代表一个基本的语义概念，并且这些集合之间也由各种关系连接。WordNet 存在的问题不能分别细节的差别需要大量的人为劳动主观无法发现新词难以精确计算词之间的相似度离散表示：One-hot表示假设有这么一个语料库John likes to watch movies. Mary likes too.John also likes to watch football games.按照这个语料库可以构建出一个词典{"John": 1, "likes": 2, "to": 3, "watch": 4, "movies'": 5,"also":6, "football": 7, "games": 8, "Mary": 9, "too": 10}可以看到这个词典里包含了10个单词，每个单词都有一个唯一的索引，在词典的顺序和在句子的顺序没有关联。John的One-hot表示为$$ [1,0,0,0,0,0,0,0,0,0] $$同理likes的One-hot表示为$$ [0,1,0,0,0,0,0,0,0,0] $$离散表示：Bag of Words文档的向量表示可以直接将各词的词向量表示加和John likes to watch movies. Mary likes too.可表示为$$ [1,2,1,1,1,0,0,0,1,1] $$词权重TF-IDF(Term Frequency - Inverse Document Frequency)词$t$的IDF weight计算方式为$$ log(1+\frac{N}{n_t}) $$其中$N$为文档总数，$n_t$为含有词$t$的文档数John likes to watch movies. Mary likes too.经过TF-IDF计算后文档向量可表示为$$ [0.693,1.386,0.693,0.693,1.099,0,0,0,0.693,0.693] $$Binary Weighting只统计是否出现过，出现为1不出现为0，不统计出现次数John likes to watch movies. Mary likes too.的向量记为$$ [1,1,1,1,1,0,0,0,1,1] $$离散表示：Bi-gram和N-gramJohn likes to watch movies. Mary likes too.John also likes to watch football games.依旧以上面两句作为语料库，为了能够考虑到顺序的影响因素，为2-gram建立索引，得到词典如下wordindexJohn likes1likes to2to watch3watch movies4Mary likes5likes too6John also7also likes8watch football9football games10John likes to watch movies. Mary likes too.的文档向量可表示为$$ [1,1,1,1,1,1,0,0,0,0] $$John also likes to watch football games.的文档向量可以表示为$$ [0,1,1,0,0,0,1,1,1,1] $$2-gram以每相邻的两个词建立词典，可以考虑到词的顺序对文档的影响，但是这样带来的问题是造成此表的膨胀。语言模型判断一句话（词组合）出现的概率$$ P(w_1,\cdots,w_m)=\prod_{i=0}^mP(w_i|w_1,\cdots,w_{i_1}) $…

Tokenize
type: item
date: 2020-08-02T02:40:00+08:00
description: Tokenize进行nlp任务都需要进行Tokenize，Tokenize可以理解为是把长句子拆分成有”意义"的小部件，这里的有"意义"是指最终能够使得计算机理解。使用nltk进行tokenizeimport nltk sentence = = 'hello,world' tokens = nltk.word_tokenize(sentence) print(tokens) #['hello',',','world']中英文NLP的区别区别1：分词方式不同，中文更难英文有天然的空格作为分隔符，但是中文没有。所以如何切分是一个难点，再加上中文里一词多意的情况非常多，导致很容易出现歧义。下文中难点部分会详细说明。区别2：英文单词有多种形态英文单词存在丰富的变形变换。为了应对这些复杂的变换，英文NLP相比中文存在一些独特的处理步骤，我们称为词形还原（Lemmatization）和词干提取（Stemming）。中文则不需要词性还原：does，done，doing，did 需要通过词性还原恢复成 do。词干提取：cities，children，teeth 这些词，需要转换为 city，child，tooth”这些基本形态区别3：中文分词需要考虑粒度问题例如「中国科学技术大学」就有很多种分法：中国科学技术大学中国 \ 科学技术 \ 大学中国 \ 科学 \ 技术 \ 大学粒度越大，表达的意思就越准确，但是也会导致召回比较少。所以中文需要不同的场景和要求选择不同的粒度。这个在英文中是没有的。社交网络上文本数据的Tokenize有时候Tokenize没那么简单，在社交网络上，乱七八糟的不合语法不合正常逻辑的语言很多：比如@某人，表情符号，URL，#话题符号这种情况下应该使用正则表达式辅助进行文本的预处理参考资料一文看懂NLP里的分词（中英文区别+3 大难点+3 种典型方法）

梯度下降法
type: item
date: 2020-04-06T03:48:00+08:00
description: 算法简介梯度下降法(Gradient Descent)不是一种机器学习算法，而是是一种基于搜索的最优化方法，作用是最小化一个损失函数，例如在线性回归过程中，可以用梯度下降法来最小化损失函数，同样的，也可以用梯度上升法来最大化一个效用函数。定义一个损失函数$J$，损失函数$J$的取值受$\theta$的影响，这里为了推导的方便，假设他是一个二次函数，如下图：我们知道曲线$J$中某个点处的导数$\frac{dJ}{d\theta}$代表$\theta$单位变化时，$J$增大的方向，为了能够向减小的方向前进，则可以定义$$ -\eta\frac{dJ}{d\theta} $$$\eta$有着如下的定义：$\eta$ 称为学习率(learning rate)$\eta$ 的取值影响获得最优解的速度$\eta$ 取值如果不合适，可能得不到最优解$\eta$ 是梯度下降法的一个超参数如果$\eta$ 太小，会减慢收敛学习的的速度，如果$\eta$ 太大，甚至导致不收敛。同时有一个问题需要注意的，上述方法找到的极值点可能只是局部最优解，但并不是所有函数都有唯一的极值点，针对这个问题，解决方案是多次运行程序，初始化随机点，使用不同的随机点。从这里我们可以看到，梯度下降法中初始点也是一个超参数。在简单线性回归中使用梯度下降法首先使用模拟的数据import numpy as np import matplotlib.pyplot as plt np.random.seed(666) x = 2* np.random.random(size=100) y = x * 3. + 4. + np.random.normal(size=100) X = x.reshape(-1,1) X.shape # (100, 1) y.shape # (100,) plt.scatter(x,y) plt.show()# 使用梯度下降法训练 def J(theta,X_b,y): try: return np.sum((y -X_b.dot(theta))**2) / len(X_b) except: return float('inf') def dJ(theta, X_b, y): res = np.empty(len(theta)) res[0] = np.sum(X_b.dot(theta) - y) for i in range(1,len(theta)): res[i] = (X_b.dot(theta) - y).dot(X_b[:,i]) return res * 2 / len(X_b) def gradient_depcent(X_b, y, initial_theta, eta, n_iters=1e4,psilon=1e-8): theta=initial_theta i_iter = 0 while i_iter < n_iters: gradient=dJ(theta,X_b,y) last_theta=theta theta = theta-eta * gradient if(abs(J(theta,X_b,y)-J(last_theta,X_b,y ))<epsilon): break i_iter += 1 return theta X_b = np.hstack([np.ones((len(X),1)),X]) initial_theta = np.zeros(X_b.shape[1]) eta = 0.01 theta = gradient_depcent(X_b,y,initial_theta,eta) theta # array([4.02145786, 3.00706277])在多元线性回归中使用梯度下降法推导在前面我们知道多元线性回归问题中损失函数$J=\sum\limits_{i=1}^m(y^{(i)}-\hat{y}^{(i)})^2$，参数为$\theta = (\theta_0,\theta_1,\theta_2,...,\theta_n)$，在前面$-\eta\frac{dJ}{d\theta}$在此处应该写成$-\eta\nabla J$的形式，其中$$ \nabla J = (\frac{\partial J}{\partial \theta_0},\frac{\partial J}{\partial \theta_1},\ldots,\frac{\partial J}{\partial \theta_n}) $$在多元线性回归中，目标是为了使得$\sum\limits_{i=1}^m(y^{(i)}-\hat{y}^{(i)})^2$尽可能的小，又因为$$ \hat{y}^{(i)}=\theta_0…

多元线性回归
type: item
date: 2020-04-05T02:03:00+08:00
description: 推导在广义的线性回归中，是可以有多个变量或者多个特征的，在上一篇文章线性回归算法中实现了一元线性回归，但在实际问题当中，决定一个label经常是由多个变量或者特征决定的。在一元线性回归当中，问题最终转化为使得误差函数最小的$a$和$b$，预测函数为$\hat{y}^{(i)}=ax^{(i)}+b$，也可以写成这种形式$\hat{y}=\theta_0+\theta_1x$，其中$\theta_0$为截距$b$，$\theta_1$为前面式子中的$a$那么对于在多元线性回归，我们也可以将预测函数函数表示为$$ \hat{y}^{(i)}=\theta_0+\theta_1X_1^{(i)}+\theta_2X_2^{(i)}+…+\theta_nX_n^{(i)} $$问题转化为求满足上述预测函数且误差函数最小的$$ \theta=(\theta_0,\theta_1,\theta_2,…,\theta_n)^T $$令$X_0^{(i)}\equiv1$,则有$$ \hat{y}^{(i)}=\theta_0X_0^{(i)}+\theta_1X_1^{(i)}+\theta_2X_2^{(i)}+…+\theta_nX_n^{(i)} $$其中$$ X^{(i)}=(X_0^{(i)},X_1^{(i)},X_2^{(i)},…,X_n^{(i)}) $$所以预测函数可以写成是$\hat{y}^{(i)}=X^{(i)}\cdot \theta$，对于这个预测函数，要使得损失函数$\sum\limits_{i=1}^m(y^{(i)}-\hat{y}^{(i)})^2$尽可能小，经过推导可以得到等价于使得$(y-X_b\cdot\theta)^T(y-X_b\cdot\theta)$尽可能小，则有$\theta$的正规方程解(Normal Equation)：$$ \theta = (X_b^TX_b)^{-1}X_b^Ty $$但是这种方法存在缺点，即计算的时间复杂度比较高，为$O(n^3)$，即便经过优化后可以达到$O(n^{2.4})$，但还是效率比较低。这种方法也有优点，那就是不用对数据做归一化处理。对于得到的$\theta=(\theta_0,\theta_1,\theta_2,…，\theta_n)^T$中，$\theta_0$为截距(intercept)，$\theta_1,\theta_2,…，\theta_n$为系数(coefficients)实现多元线性回归# 读取波士顿房价数据 boston = datasets.load_boston() x=boston.data y=boston.target # 去除边界点 x = x[y<50.0] y = y[y<50.0] x.shape # (490, 13) # 可以看到具有13个变量/特征值 from sklearn.model_selection import train_test_split from sklearn.linear_model import LinearRegression x_train,x_test,y_train,y_test = train_test_split(x,y,random_state = 666) lin_reg = LinearRegression() lin_reg.fit(x_train,y_train) # LinearRegression(copy_X=True, fit_intercept=True, n_jobs=None, normalize=False) # 参数 lin_reg.coef_ # array([-1.15625837e-01, 3.13179564e-02, -4.35662825e-02, -9.73281610e-02, # -1.09500653e+01, 3.49898935e+00, -1.41780625e-02, -1.06249020e+00, # 2.46031503e-01, -1.23291876e-02, -8.79440522e-01, 8.31653623e-03, # -3.98593455e-01]) # 截距 lin_reg.intercept_ # 32.59756158869959 # 评分 lin_reg.score(x_test,y_test) # 0.8009390227581041kNN回归from sklearn.neighbors import KNeighborsRegressor knn_reg = KNeighborsRegressor() knn_reg.fit(x_train,y_train) # KNeighbor…

线性回归算法
type: item
date: 2020-04-05T01:09:00+08:00
description: 算法简介解决回归问题思想简单，实现容易许多强大的非线性模型的基础结果具有很强的解释性蕴含机器学习中很多的重要思想线性回归算法可以简单概括为，寻找一条直线，最大程度地“拟合”样本特征和样本输出标记之间的关系。推导假设我们找到了最佳拟合的直线方程$y=ax+b$，则对于每个样本点$x^{(i)}$ ，根据我们的直线方程，预测值就为$\hat{y}^{(i)}=ax^{(i)}+b$，我们希望真值$y^{(i)}$与$\hat{y}^{(i)}$之间的差距尽量的小，可以用$(y^{(i)}-\hat{y}^{(i)})^2$来衡量真实值与预测值之间的差距，考虑到所有的样本，则是$$ \sum\limits_{i=1}^{m}(y^{(i)}-\hat{y}^{(i)})^2 $$其中$$ \hat{y}^{(i)}=ax^{(i)}+b $$我们想使得上述函数尽可能小，那么我们的问题可以转化为找到$a和b$使得$\sum\limits_{i=1}^{m}(y^{(i)}-\hat{y}^{(i)})^2$尽可能小，我们一般把这个函数称为损失函数(loss function)或者效用函数(utillity function)，通过分析问题，确定问题的损失函数或者效用函数，通过优化损失函数或者效用函数，可以获得机器学习的模型，对于几乎所有的参数学习的算法，都是这样的套路，比如线性回归、多项式回归、逻辑回归和SVM等。对于上述的式子，可以得到整理后的损失函数为：$$ \sum\limits_{i=1}^{m}(y^{(i)}-ax^{(i)}-b)^2 $$这是一个典型的最小二乘法问题，即最小化误差的平方，可以得到$$ a=\frac{\sum_\limits{i=1}^{m}\left(x^{(i)}-\bar{x}\right)\left(y^{(i)}-\bar{y}\right)}{\sum\limits_{i=1}^{m}\left(x^{(i)}-\bar{x}\right)^{2}} $$$$ b=\overline{y}-a\overline{x} $$了便于算法的运行效率，我们尝试转化成向量化计算的形式，即$\sum\limits_{i=1}^{m}w^{(i)}v^{(i)}$这种形式，对于分子，令$w^{(i)}=x^{(i)}-\bar{x}，v^{(i)}=y^{(i)}-\bar{y}$，令$w=(w^{(1)}),w^{(2)},....,w^{(n)})，v=(v^{(1)}),v^{(2)},....,v^{(n)})$,则$\sum\limits_{i=1}^{m}w^{(i)}v^{(i)}$可以看作是$w\cdot v $简单实现import numpy as np import matplotlib.pyplot as plt x = np.array([1.,2.,3.,4.,5.]) y = np.array([1.,3.,2.,4.,5.]) x_mean = np.mean(x) y_mean = np.mean(y) num = 0.0 d = 0.0 for x_i, y_i in zip(x,y): num += (x_i - x_mean)*(y_i - y_mean) d += (x_i - x_mean)**2 a = num/d b = y_mean - a * x_mean y_hat = a * x + b plt.scatter(x,y) plt.plot(x,y_hat,color = 'r') plt.axis([0,6,0,6]) plt.show()自己封装线性回归算法#SimpleLinearRegression.py import numpy as np from metrics import r2_score class SimpleLinearRegression: def __init__(self): """初始化Simple Linear Regression模型""" self.a_ = None self.b_ = None def fit(self, x_train, y_train): """根据训练数据集x_train, y_train训练Simple Linear Regression模型""" assert x_train.ndim == 1, \ "Simple Linear Regressor can only solve single feature training data." assert len(x_train) == len(y_train), \ "the size of x_train must be equal …

数值归一化
type: item
date: 2020-04-02T19:45:00+08:00
description: 最值归一化 Normalization最值归一化是将所有数据映射到0~1之间,适用于分布有明显边界的情况，受outlier影响很大。最值归一化的公式为$$ x_{\text {scale}}=\frac{x-x_{\min }}{x_{\max }-x_{\min }} $$X = np.random.randint(0,50,size=(50,2)) X = np.array(X,dtype =float) # 进行最值归一化 X[:,0] = (X[:,0] - np.min(X[:,0])) / (np.max(X[:,0]) - np.min(X[:,0])) X[:,1] = (X[:,1] - np.min(X[:,1])) / (np.max(X[:,1]) - np.min(X[:,1])) plt.scatter(X[:,0],X[:,1]); plt.show()均值方差归一化 Standardization对于数据没有明显的边界，或者是数据存在明显极端的数值，可以使用均值方差归一化将所有数据归一到均值为0，方差为1的分布当中，均值方差归一化的公式为$$ x_{\text {scale}}=\frac{x-x_{\text {mean}}}{s} $$X2 = np.random.randint(0,100,size = (50,2)) X2 = np.array(X2,dtype=float) X2[:,0] = (X2[:,0] - np.mean(X2[:,0])) / np.std(X2[:,0]) X2[:,1] = (X2[:,1] - np.mean(X2[:,1])) / np.std(X2[:,1]) plt.scatter(X2[:,0],X2[:,1]) plt.show() # 查看数据的均值和方差 np.mean(X2[:,0]) # 1.2434497875801754e-16 np.std(X2[:,0]) # 0.9999999999999998使用scikit-learn中的Scaler进行归一化上述操作都是自己手动实现，scikit-learn中也为我们封装好了归一化的函数使用自带的鸢尾花数据集，对数据进行预处理from sklearn import datasets iris = datasets.load_iris() x = iris.data y = iris.target from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(iris.data,iris.target, test_size=0.2, random_state=666)scikit-learn中的standardScalerfrom sklearn.preprocessing import StandardScaler standardScaler = StandardScaler() standardScaler.fit(X_train) # StandardScaler(copy=True, with_mean=True, with_std=True) standardScaler.mean_ # array([5.83416667, 3.08666667, 3.70833333, 1.17 ]) standardScaler.scale_ # array([0.81019502, 0.44327067, 1.76401924, 0.75317107]) X_train = standardScaler.transform(X_train) X_test_standard = standardScaler.transform(X_test)