薅羊毛了!阿里云服务器8核16G限时免费领,最高净省891元。
阿里云服务器到底好不好用,必须试试才知道!即日起,凡注册阿里云且通过实名认证的新用户,可30天免费试用阿里云服务器。最高可申请试用计算型C5实例8核16G5M配置云服务器。快来合理薅羊毛吧!阿里云服务器ECS是一种按需获取的云端服务器,为您提供高可靠、弹性扩展的计算资源服务,您可以根据需求选择不同规格的CPU、内存、操作系统、硬盘和网络来创建您的阿里云服务器,满足您的个性化业务需求。阿里云服务器从订购到开通使用仅需数分钟时间,助您快速灵活地构建企业应用。阿里云服务器可支持windows与linux等多种操作系统,支持公共镜像、自定义镜像、共享镜像、镜像市场、社区镜像,挂载云硬盘、VPC网络、虚拟网卡、VNC与远程登录等多种登录方式。与传统服务器相比,阿里云服务器不仅成本低廉、便捷易用,而且稳定可靠,可实现快速交付。个人认证:1核2G1M、2核4G3M,免费试用>>>企业认证:2核8G5M、4核16G5M、8核16G5M,免费试用>>>目前,阿里云服务器提供多种实例规格类型,包括通用共享型、计算型、通用型、大数据型、内存型、GPU型、计算网络优化型、高主频型、弹性裸金属,可适用于网站应用、企业核心业务、缓存类应用、图形渲染等多种应用场景。用户根据业务场景的需求,选择合适的阿里云服务器类型。
①机器学习分类算法之LightGBM(梯度提升框架)
走进LightGBM什么是LightGBM?在上一篇的文章里,我介绍了XGBoost算法,它是是很多的比赛的大杀器,但是在使用过程中,其训练耗时很长,内存占用比较大。在2017年年1月微软在GitHub的上开源了LightGBM。该算法在不降低准确率的前提下,速度提升了10倍左右,占用内存下降了3倍左右。LightGBM是个快速的,分布式的,高性能的基于决策树算法的梯度提升算法。可用于排序,分类,回归以及很多其他的机器学习任务中。GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型,其主要思想是利用弱分类器(决策树)迭代训练以得到最优模型,该模型具有训练效果好、不易过拟合等优点。GBDT不仅在工业界应用广泛,通常被用于多分类、点击率预测、搜索排序等任务;在各种数据挖掘竞赛中也是致命武器,据统计Kaggle上的比赛有一半以上的冠军方案都是基于GBDT。而LightGBM(Light Gradient Boosting Machine)是一个实现GBDT算法的框架,支持高效率的并行训练,并且具有更快的训练速度、更低的内存消耗、更好的准确率、支持分布式可以快速处理海量数据等优点。LightGBM是一个梯度提升框架,使用基于树的学习算法。常用的机器学习算法,例如神经网络等算法,都可以以mini-batch的方式训练,训练数据的大小不会受到内存限制。而GBDT在每一次迭代的时候,都需要遍历整个训练数据多次。如果把整个训练数据装进内存则会限制训练数据的大小;如果不装进内存,反复地读写训练数据又会消耗非常大的时间。尤其面对工业级海量的数据,普通的GBDT算法是不能满足其需求的。LightGBM提出的主要原因就是为了解决GBDT在海量数据遇到的问题,让GBDT可以更好更快地用于工业实践。XGBoost的缺点在LightGBM提出之前,最有名的GBDT工具就是XGBoost了,它是基于预排序方法的决策树算法。这种构建决策树的算法基本思想是:首先,对所有特征都按照特征的数值进行预排序。其次,在遍历分割点的时候用O(#data)的代价找到一个特征上的最好分割点。最后,在找到一个特征的最好分割点后,将数据分裂成左右子节点。这样的预排序算法的优点是能精确地找到分割点。但是缺点也很明显:首先,空间消耗大。这样的算法需要保存数据的特征值,还保存了特征排序的结果(例如,为了后续快速的计算分割点,保存了排序后的索引),这就需要消耗训练数据两倍的内存。其次,时间上也有较大的开销,在遍历每一个分割点的时候,都需要进行分裂增益的计算,消耗的代价大。最后,对cache优化不友好。在预排序后,特征对梯度的访问是一种随机访问,并且不同的特征访问的顺序不一样,无法对cache进行优化。同时,在每一层长树的时候,需要随机访问一个行索引到叶子索引的数组,并且不同特征访问的顺序也不一样,也会造成较大的cache miss。LightGBM的优化为了避免XGBoost的缺陷,并且能够在不损害准确率的条件下加快GBDT模型的训练速度,lightGBM在传统的GBDT算法上进行了如下优化:基于Histogram的决策树算法。单边梯度采样 Gradient-based One-Side Sampling(GOSS):使用GOSS可以减少大量只具有小梯度的数据实例,这样在计算信息增益的时候只利用剩下的具有高梯度的数据就可以了,相比XGBoost遍历所有特征值节省了不少时间和空间上的开销。互斥特征捆绑 Exclusive Feature Bundling(EFB):使用EFB可以将许多互斥的特征绑定为一个特征,这样达到了降维的目的。带深度限制的Leaf-wise的叶子生长策略:大多数GBDT工具使用低效的按层生长 (level-wise) 的决策树生长策略,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销。实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。LightGBM使用了带有深度限制的按叶子生长 (leaf-wise) 算法。直接支持类别特征(Categorical Feature)支持高效并行Cache命中率优化LightGBM的基本原理LightGBM树的生长方式是垂直方向的,其他的算法都是水平方向的,也就是说Light GBM生长的是树的叶子,其他的算法生长的是树的层次。LightGBM选择具有最大误差的树叶进行生长,当生长同样的树叶,生长叶子的算法可以比基于层的算法减少更多的loss。下面的图解释了LightGBM和其他的提升算法的实现在 Histogram 算法之上,LightGBM 进行进一步的优化。首先它抛弃了大多数 GBDT 工具使用的按层生长 (level-wise) 的决策树生长策略,而使用了带有深度限制的按叶子生长 (leaf-wise) 算法。Level-wise 过一次数据可以同时分裂同一层的叶子,容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但实际上 Level-wise 是一种低效的算法,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销,因为实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。 Leaf-wise 则是一种更为高效的策略,每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同 Level-wise 相比,在分裂次数相同的情况下,Leaf-wise 可以降低更多的误差,得到更好的精度。Leaf-wise 的缺点是可能会长出比较深的决策树,产生过拟合。因此 LightGBM 在 Leaf-wise 之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合。 数据的数量每天都在增加,对于传统的数据科学算法来说,很难快速的给出结果。LightGBM的前缀‘Light’表示速度很快。LightGBM可以处理大量的数据,运行时占用很少的内存。另外一个理由,LightGBM为什么这么受欢迎是因为它把重点放在结果的准确率上。LightGBM还支持GPU学习,因此,数据科学家广泛的使用LightGBM来进行数据科学应用的部署。既然可以提升速度,那么它可以在小数据集上面使用吗?不可以!不建议在小数据集上使用LightGBM。LightGBM对过拟合很敏感,对于小数据集非常容易过拟合。对于多小属于小数据集,并没有什么阈值,但是从我的经验,我建议对于10000+以上的数据的时候,再使用LightGBM。这也很明显,因为小的数据集使用XGBoost就可以了呀。实现LightGBM非常简单,复杂的是参数的调试。LightGBM有超过100个参数,但是不用担心,你不需要所有的都学。Histogram 算法直方图算法的基本思想是先把连续的浮点特征值离散化成k个整数,同时构造一个宽度为k的直方图。在遍历数据的时候,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。使用直方图算法有很多优点。首先,最明显就是内存消耗的降低,直方图算法不仅不需要额外存储预排序的结果,而且可以只保存特征离散化后的值,而这个值一般用 8 位整型存储就足够了,内存消耗可以降低为原来的1/8。 (内存消耗低) 然后在计算上的代价也大幅降低,预排序算法每遍历一个特征值就需要计算一次分裂的增益,而直方图算法只需要计算k次(k可以认为是常数),时间复杂度从O(#data*#feature)优化到O(k*#features)。 当然,Histogram 算法并不是完美的。由于特征被离散化后,找到的并不是很精确的分割点,所以会对结果产生影响。但在不同的数据集上的结果表明,离散化的分割点对最终的精度影响并不是很大,甚至有时候会更好一点。直方图加速 LightGBM 另一个优化是 Histogram(直方图)做差加速。一个容易观察到的现象:一个叶子的直方图可以由它的父亲节点的直方图与它兄弟的直方图做差得到。通常构造直方图,需要遍历该叶子上的所有数据,但直方图做差仅需遍历直方图的k个桶。利用这个方法,LightGBM 可以在构造一个叶子的直方图后,可以用非常微小的代价得到它兄弟叶子的直方图,在速度上可以提升一倍。实际上大多数机器学习工具都无法直接支持类别特征,一般需要把类别特征,转化到多维的0/1 特征,降低了空间和时间的效率。而类别特征的使用是在实践中很常用的。基于这个考虑,LightGBM 优化了对类别特征的支持,可以直接输入类别特征,不需要额外的0/1 展开。并在决策树算法上增加了类别特征的决策规则。在 Expo 数据集上的实验,相比0/1 展开的方法,训练速度可以加速 8 倍,并且精度一致。据我们所知,LightGBM 是第一个直接支持类别特征的 GBDT 工具。 LightGBM 的单机版本还有很多其他细节上的优化,比如 cache 访问优化,多线程优化,稀疏特征优化等等。优化汇总如下:LightGBM并行优化LightGBM 还具有支持高效并行的优点。LightGBM 原生支持并行学习,目前支持特征并行和数据并行的两种。 ? ?特征并行的主要思想是在不同机器在不同的特征集合上分别寻找最优的分割点,然后在机器间同步最优的分割点。 ? ?数据并行则是让不同的机器先在本地构造直方图,然后进行全局的合并,最后在合并的直方图上面寻找最优分割点。 LightGBM 针对这两种并行方法都做了优化: ? ?在特征并行算法中,通过在本地保存全部数据避免对数据切分结果的通信; ? ?在数据并行中使用分散规约 (Reduce scatter) 把直方图合并的任务分摊到不同的机器,降低通信和计算,并利用直方图做差,进一步减少了一半的通信量。基于投票的数据并行则进一步优化数据并行中的通信代价,使通信代价变成常数级别。在数据量很大的时候,使用投票并行可以得到非常好的加速效果。注意:当生长相同的叶子时,Leaf-wise 比 level-wise 减少更多的损失。高速,高效处理大数据,运行时需要更低的内存,支持 GPU不要在少量数据上使用,会过拟合,建议 10,000+ 行记录时使用。
反爬虫的重点:识别爬虫
我们在网站运营的时候,最大的问题就是:我们自己花费几个小时甚至是几天辛辛苦苦创作作的内容,被爬虫只需要 1s 就抓去了。为了保卫我们创作的成果,也为了网站的稳定运行,我们需要对爬虫说:No,我们在反爬虫的过程中最重要的就是如何识别爬虫。为了识别识别爬虫,常用的有以下几个方法:真人检测所谓的真人检测也就是出现一个验证码,让你输入验证码的内容,这些验证码对于人类来说很容易识别,但是对于机器来说却很难识别,例如这种验证码:这种验证码只有人类很轻易识别,爬虫却很难识别。滑块类验证码这里验证码对于人类来说也很友好,我们只需要将滑块移到一个阴影的位置,例如下面这种:这类验证码对于人来来说轻而易举,但是对于爬虫来说有一定难度,但是也是可以破解的。这些在一些特殊场合的确是可以防止爬虫对于你创作内容的抓取,但是你成功的防止了恶意爬虫,也成功的防止了搜索引擎爬虫来抓取你的内容。我们为什么要允许搜索引擎爬虫来抓取我们的内容?这个主要是由于搜索引擎可以给我带来流量,有了流量我们就可以想办法变现,有没有嗅到金钱的味道。例如我们在百度搜索:爬虫识别,并点击了我的网站,就有访客访问网站,就给网站带来了流量。那百度怎么知道我们网站上有什么内容呢?百度搜索引擎每天有成千上万的爬虫在互联网上抓取内容,并将百度爬虫抓取的内容存入自己的索引之中,在根据一定的算法为每个网页排名,之后用户搜索相应的关键词之后,有可能会到达你网站,就会给你带来流量。这就是为什么我们不能屏蔽搜索引擎爬虫的原因了,如果你像屏蔽其他爬虫一样屏蔽搜索引擎爬虫,那么搜索引擎爬虫将无法抓取你网站的内容,就不会在搜索结果中展示你的网站,也不会为你带来任何流量。那现在有一个问题就是,我们既要屏蔽一些恶意爬虫,又不能屏蔽搜索引擎爬虫,我真的好难呀!为了解决这个问题,我们可以使用爬虫识别这个网站来解决上面的问题。首先我们需要根据 User-agent 先过滤掉一部分恶意爬虫,搜索引擎的 User-agent 我们可以在这里查看:搜索引擎爬虫这里收集和整理了市面上大部分搜索引擎的 User-agent 与 IP 地址,例如下面是百度蜘蛛的 User-agent:通过比对 User-agent 我们可以初步判断是不是搜索引擎的爬虫,但是 User-agent 是可以轻易伪造的,所以我们还需要配合 IP 来识别爬虫是否是真实的。我们只需要到爬虫 IP 查询输入 IP 就可以知道这个是不是伪造爬虫了。总结这篇文章首先从验证码开始如何防止爬虫抓取我们网站,但是我们又不能屏蔽所有爬虫抓取我们网站,我们如何通过 User-agent 与 IP 结合的方式判断是搜索引擎爬虫,并让其抓取我们网站。
「第一期」宝藏5G消息应用号推荐:这种体验感真的不一般
在5G消息能力逐渐完善的今天,各类5G消息应用号层出不穷,前有各大企业共探应用场景,后有小众品牌创新服务方式,日益丰富的应用生态,让使用5G消息的用户不禁感叹一声“真好”!本期开始「中国移动5G消息开发者社区」将根据不同行业、不同场景、不同内容为广大用户挑选一些宝藏级5G消息应用号,快速了解,体验服务!一、“山西文旅年卡”5G消息应用号“山西文旅年卡”5G消息应用号作为山西专属地域的文化旅游服务应用,不仅推进本省智慧文旅产业的发展,丰富了山西省基层职工精神文化生活,还为广大市民游客搭建了一个可查询山西特色美景,获取当地民俗情况,购买山西文旅年卡的便捷通道,以5G消息新能力,带领用户进入“美丽山西”。5G消息应用号特色1、主题明确:个性化配置菜单栏山西文旅服务,划分功能类别,优化内容呈现方式,让用户一目了然。2、内容新颖:富媒体消息卡片代替传统文本消息,通过5G消息交互能力向用户主动推送山西旅游宣传视频、旅游攻略卡片消息、民俗风情卡片消息、商品服务消息等,有效增加内容趣味性及可读性。3、服务齐全:除了推送消息内容,还有接入“山西文旅年卡”商品服务,在短信里就可以直接下单购买,减少用户触达服务流程,提升服务转化效率。二、“太空搜索”5G消息应用号“太空搜索”5G消息应用号由中国搜索和中国国家天文台合作打造,以“太空”为主题,通过5G消息能力搭建了各种太空主题内容服务场景。化繁为简,将海量天文数据以可互动、可体验、可分享的方式展现给广大用户,激发人们探索浩瀚宇宙的兴趣。5G消息应用号特色1、趣味性强:在太空搜索5G消息应用号的菜单服务消息中,加入了有趣的“宇宙录音棚”互动游戏H5页,用户可以在互动游戏H5页把目前流行的歌曲转化太空脉冲信号,还能自己编曲,同时支持将歌曲分享好友或导出本地。2、内容新颖:作为相对小众的5G消息应用号,“太空搜索”的消息服务引人入胜,以“天眼fast”、“空间站”“脉冲星”三个知识点为内容基石,配置各种太空搜索富媒体消息卡片,有效提升用户的阅读观感,快速引导用户浏览太空知识消息。3、受众面广:针对部分消息服务,“太空搜索”5G消息应用号可提供中英文版本选择,满足不同人群的使用需求。三、“咪咕圈圈”5G消息应用号“咪咕圈圈”5G消息应用号以“华服文化”为核心,为华服资深爱好者打造的集“看、学、聚、购、游、拍”为一体的全场景服务应用,通过5G消息能力搭建各种华服主题内容服务场景,带领广大用户体验华服文化的传统魅力。5G消息应用号特色1、主题明确:“咪咕圈圈”5G消息应用号的配图精美,每个消息卡片都配有相应的华服图片,特色专题以及热门话题内容也环环相扣,用户阅读更加方便。2、内容新颖:“咪咕圈圈”5G消息应用号整体内容以“华服文化”为中心,策划“汉服百科”和“精美图鉴”两大消息内容,并通过富媒体消息卡片,将华服深厚的历史文化内容和色彩鲜明、独特时尚的图片设计以多种消息形式呈现,增加内容的观赏性,提升用户阅读兴趣。3、专区特设:“咪咕圈圈”5G消息应用号在消息服务中配置了萌新专区,以游戏的形式让萌新快速了解华服文化。本期所有5G消息应用号都可在支持5G消息手机终端上体验,如需查询具体型号,请在【中国移动5G消息开发者社区】进行查询。
Python监督学习之分类算法的概述
初入机器学习,无论是在书本上,还是在学习平台上,第一个介绍的就是监督学习,那么什么是监督学习呢?监督——顾名思义,把你“看着学习”,说的直白一点就是让你的计算机明白一种规律,并且按照这种规律进行大量的学习,最后通过该规律进行预测或者分类。生活中有垃圾分类,也有物品的好坏分类,在这个世界上凡事存在的东西,我们都会给它定义一个属性,人也不例外,有好人坏人之称,也有穷人富人之别,一个事物可以被定义多个属性。在监督学习里面,又分为:分类和回归,这里简单的介绍一下什么是分类,什么样的数据适合做分类,分类又分为多少种?分类:适用于目标列离散的数据,注意这里是目标列,也就是通过模型需要预测的列,它如果是一个离散的数据,那么适用于分类。分类又分为:二分类,多分类二分类就是一个目标列只有两种情况,一般的分类以二分类为主,比如在预测肿瘤是良性还是恶性,预测商品是否会被售卖成功,检测某样品是否合格。多分类就是一个目标列有多种情况,比如某信用等级有:A、B、C、D四种情况,那么这个时候就是一个多分类的情况,多分类得的算法和二分类差不多,在细节上有点不一样。分类方法的定义:分类分析的是根据已知类别的训练集数据,建立分类模型,并利用该分类模型预测未知类别数据对象所属的类别。分类方法的应用:1、模式识别(Pattern Recognition),就是通过计算机用数学技术方法来研究模式的自动处理和判读。模式识别的目标往往是识别,即分析出待测试的样本所属的模式类别。2、预测,从利用历史数据记录中自动推导出对给定数据的推广描述,从而能对未来数据进行类预测。现实应用案例1、行为分析2、物品识别、图像检测3、电子邮件的分类(垃圾邮件和非垃圾邮件等)4、新闻稿件的分类、手写数字识别、个性化营销中的客户群分类、图像/视频的场景分类等分类器分类的实现方法是创建一个分类器(分类函数或模型),该分类器能把待分类的数据映射到给定的类别中。创建分类的过程与机器学习的一般过程一致上一篇文章我们讲述了,机器学习的框架和以及相关的理论知识,也就是说在一个完整的模型训练当中,这些步骤是不可或缺的。分类器的构建标准 使用下列标准比较分类和预测方法预测的准确率:模型正确预测新数据的类编号的能力速度:产生和使用模型的计算花销健壮性:给定噪声数据或有空缺值的数据,模型正确预测的能力可伸缩性:对大量数据,有效的构建模型的能力可解释性:学习模型提供的理解和洞察的层次常见的分类算法逻辑回归(尽管是回归的算法但实际上是完成分类的问题)决策树(包括 ID3 算法、 C4.5 算法和 CART 算法)神经网络贝叶斯K-近邻算法支持向量机(SVM)这些分类算法适合的使用场景并不完全一致,需要根据实际的应用评价才能选对适合的算法模型。分类算法的常见应用包括:决策树方法在医学诊断、贷款风险评估等领域应用;神经网络在识别手写字符、语音识别和人脸识别等应用,贝叶斯在垃圾邮件过滤、文本拼写纠正方向的应用等。分类也是一个常见的预测问题,这个分类解决的问题与生活中分类问题基本一致,比如我们会根据天气的情况决定是否出行,这里面的天气情况就是因变量特征值,出行与否就是因变量标签值,分类算法是将我们思考的过程进行了自动化或半自动化。数据挖掘中的分类典型的应用是根据事物在数据层面表现的特征,对事物进行科学的分类。分类与回归的区别在于:回归可用于预测连续的目标变量,分类可用于预测离散的目标变量。在计算机语言中,分类你最容易想到的是什么逻辑语言,不错,答案就是:判断语句 这也是分类的底层思想,就像是决策树一样,一个条件下有很多的分支
②机器学习框架及评估指标详解
Python 绘制ROC曲线求解AUC模板代码# 预测正例的概率
y_pred_prob=model.predict_proba(X_test)[:,1]
# y_pred_prob ,返回两列,第一列代表类别0,第二列代表类别1的概率
#https://blog.csdn.net/dream6104/article/details/89218239
fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2)
#pos_label,代表真阳性标签,就是说是分类里面的好的标签,这个要看你的特征目标标签是0,1,还是1,2
roc_auc = metrics.auc(fpr, tpr) #auc为Roc曲线下的面积
# print(roc_auc)
plt.figure(figsize=(8,6))
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.plot(fpr, tpr, 'r',label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
# plt.plot([0, 1], [0, 1], 'r--')
plt.xlim([0, 1.1])
plt.ylim([0, 1.1])
plt.xlabel('False Positive Rate') #横坐标是fpr
plt.ylabel('True Positive Rate') #纵坐标是tpr
plt.title('Receiver operating characteristic example')
plt.show()错误率错误率(Error Rate):是分类错误的样本数占样本总数的比例。对样例集D,分类错误率计算公式如下所示:统计分类器预测出来的结果与真实结果不相同的个数,然后除以总的样例集D的个数。精度精度(Accuracy):是分类正确的样本数占样本总数的比例。对样例集D,精度计算公式这里的分类正确的样本数指的不仅是正例分类正确的个数还有反例分类正确的个数。查准率、查全率这里的查准率其实就是上面的真正例:TP/TP+FP查准率,它表示的是预测为正的样例中有多少是真正的正样例,相对于本来有样本有10个,正样本9个,负样本1个,预测出来TP:8.那么FP:0,所以查准率为100%。相对于是有一个本来是1的我们却预测为0,但是对于查准率来说,这是不会影响的。精确度(Accuracy),缩写表示用A。精确度则是分类正确的样本数占样本总数的比例。Accuracy反应了分类器对整个样本的判定能力(即能将正的判定为正的,负的判定为负的)。这里需要注意的就是精度和准确率是不一样的,准确率是查准率,这里的准是代表着正(1)的概率查全率(Recall),又叫召回率,缩写表示用R。查全率是针对我们原来的样本而言的,它表示的是样本中的正例有多少被预测正确。通过上述的介绍,我们发现查准率和查全率是有矛盾的 ? ? ? ?查准率和查全率是一对矛盾的度量。一般来说,查准率高时,查全率往往偏低;而查全率高时,查准率往往偏低。 ? ? ? ?为什么这么说呢?因为查准率是考虑的在预测结果为1的样本中,验证真正的为1的数量占比;而查全率是考虑的在本来就是1的样本中,有多少被预测为1的占比。 ? ? ? ?是不是有点绕了,这里举一个具体的例子,比如还是一共10个样本,其中有9个1,1个0;通过模型预测出来有8个1,2个0,那么它的查准率是100%,但是它的召回率,也就是9个里面只召回了8个。那么需要召回率高也就是说,就需要原本是1的都预测为1,不出现预测为0,但是都预测为1了,那么这个质量又无法保证,会出现本来是0的,却预测为1了。这里需要仔细的思考一下,不然真的容易混淆!!!! ? ? ? ?我们可以这样理解,在一个分类器中,你想要更高的查准率,那么你的阈值要设置的更高,只有这样才能有较高的把握确定我们预测是正例是真正例。 ? ? ? ?一旦我们把阈值设置高了,那我们预测出正例的样本数就少了,那真正例数就更少了,查不全所有的正样例。 ? ? ? ?举个例子来理解一下吧!例如,若希望将好瓜尽可能多地挑选出来,则可通过增加选瓜的数量来实现,如果将所有的西瓜都选上,那么所有的好瓜也必然都选上了,但这样查准率就会较低;若希望选出的瓜中好瓜比例尽可能高,则可只挑选最有把握的瓜,但这样就难免会漏掉不少好瓜,使得查全率较低。通常只有在一些简单任务中,才可能使查全率和查准率都很高。P-R曲线 ? ? ? ?在很多情形下,我们可根据学习器的预测结果对样例进行排序,排在前面的是学习器认为“最可能”是正例的样本,排在最后的是学习器认为“最不可能”是正例的样本。按此顺序设置不同的阈值,逐个把样本作为正例进行预测,则每次可以计算出当前的查准率、查全率。 ? ? ? ?以查准率为纵轴、查全率为横轴作图,就得到了查准率-查全率曲线,简称“P-R曲线”,显示该曲线的图称为“P-R图”。图1给出了一个示意图。 ? ? ? ?P-R图直观地显示出学习器在样本总体上的查全率、查准率。在进行比较时,若一个学习器的P-R曲线被另一个学习器的曲线完全“包住”,则可断言后者的性能优于前者。 ? ? ? ?例如图1中学习器A的性能优于学习器C;如果两个学习器的P-R曲线发生了交叉,例如图1中的A和B,则难以一般性地断言两者孰优孰劣,只能在具体的查准率或查全率条件下进行比较。然而,在很多情形下,人们往往仍然希望把学习器A与B比出个高低。 ? ? ? ?这时,一个比较合理的判断依据是比较P-R曲线下面积的大小,它在一定程度上表征了学习器在查准率和查全率上取得相对“双高”的比例。但这个值不太容易估算,因此,人们设计了一些综合考虑查准率、查全率的性能度量,比如BEP度量、F1度量。Python绘制P-R曲线模板代码import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import precision_recall_curve
# 预测正例的概率
y_pred_prob=model.predict_proba(X_test)[:,1]
plt.figure(1) # 创建图表1
plt.title('Precision/Recall Curve')# give plot a title
plt.xlabel('Recall')# make axis labels
plt.ylabel('Precision')
#y_true和y_scores分别是gt label和predict score
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
#fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2)
precision, recall, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=1)
plt.figure(1)
plt.plot(precision, recall)
plt.show()平衡点(BEP)“平衡点”(Break-Even-Point,简称BEP)就是这样一个度量,它是“查准率=查全率”时的取值,例如图1中学习器C的BEP是0.64,而基于BEP的比较,可认为学习器A优于B。F1度量越大越好BEP曲线还是过于简化了些,更常用的是F1度量。我们先来谈谈F1度量的由来是加权调和平均,计算公式如下所示。import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import precision_recall_curve
# 预测正例的概率
y_pred_prob=model.predict_proba(X_test)[:,1]
plt.figure(1) # 创建图表1
plt.title('Precision/Recall Curve')# give plot a title
plt.xlabel('Recall')# make axis labels
plt.ylabel('Precision')
#y_true和y_scores分别是gt label和predict score
y_true = np.array([0, 0, 1, 1])
y_scores = np.array([0.1, 0.4, 0.35, 0.8])
#fpr, tpr, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=2)
precision, recall, thresholds = metrics.roc_curve(y_test,y_pred_prob, pos_label=1)
plt.figure(1)
plt.plot(precision, recall)
plt.show() ? ? ? ?在一些应用中,对查准率和查全率的重视程度有所不同。例如在商品推荐系统中,为了尽可能少打扰用户,更希望推荐内容确实是用户感兴趣的,此时查准率更重要;而在逃犯信息检索系统中,更希望尽可能少漏掉逃犯,此时查全率更重要。F1度量的一般形式是能让我们表达出对查准率/查全率的不同偏好,它定义为公式如下: ? ? ? ?其中,β>0度量了查全率对查准率的相对重要性。β=1时,退化为标准的F1;β>1时查全率有更大影响;β<1时,查准率有更大影响Python求解F1_score代码from sklearn.metrics import f1_score
y_pred = [0, 1, 1, 1, 2, 2]
y_true = [0, 1, 0, 2, 1, 1]
#这里需要注意,如果是二分类问题则选择参数‘binary’(默认);如果考虑类别的不平衡性,需要计算类别的加权平均,则使用‘weighted’;如果不考虑类别的不平衡性,计算宏平均,则使用‘macro’。
print(f1_score(y_true, y_pred, average='macro'))
print(f1_score(y_true, y_pred, average='weighted'))
①机器学习框架及评估指标详解
?机器学习在生活中无处不在,你是否会疑问为什么你的某宝界面总是给你推荐一些商品,而这些商品还是你自己想要的东西,这就是电商平台利用大数据推荐算法,结合你的历史搜索记录和浏览记录,以及你的购买记录作为数据支撑,最终推荐给你心仪的商品。 ? ? ? ?某音视频也是如此,为什么每个人的视频刷的都不一样,小朋友的界面;年级人的界面;老年人的界面大不相同,那是因为会根据你的历史观看记录和关注人群做层次筛选,这样结合你的视频停留时间和用户发生的动作行为作为数据支撑,最终演化为一个符合人性化的推荐算法! ? ? ? ?每一次当你使用微信朋友圈,微博的相片分类功能,它能识别出哪些是你好友的照片,这也是机器学习算法。 ? ? ? ?每次当你使用百度搜索引擎时,它能给出如此满意的结果,原因之一就是使用了机器学习算法。 ? ? ? ?机器学习还可以实现图像的像素增强以及图像补全,同时还可以在图像识别方面具有较好的可塑性和重用性。 ? ? ? ?简单来说,机器学习就是让计算机从大量的数据中学习到相关的规律和逻辑,然后利用学习来的规律来预测以后的未知事物 ? ? ? ?如果要说到机器学习,不得不推荐一个Python的库:sklearn,它具有大量的模型算法,而且都已经封装好了,只需要我们自己去调用即可,就像科研神器R语言一样,拥有大量的宏包,Python也是如此。官方指导手册网址scikit-learn: machine learning in Python — scikit-learn 1.0.2 documentationtrain_x, train_y, test_x, test_y = getData()
model1 = somemodel()
model.fit(train_x,train_y)
predictions = model.predict(test_x)
score =score_function(test_y, predictions)
joblib.dump(knn, 'filename.pkl')机器学习的步骤?????? 机器学习初步可以分 ? ? ? 机器学习初步可以分为: ? ? ? ?数据导入,特征选取,数据分割,模型选择,模型训练,模型评分,模型调优 ? ? ? ?什么是特征选取呢? ? ? ? ?什么又是特征工程? ? ? ? ?这里只是简单的提一下,后续将会详细的介绍,特征工程就是将机器无法识别,无法运算的数据转换为数值类型的数据,用于模型的训练和测试。利用sklearn中分割函数train_test_split()函数去将数据分割为测试集和训练集train_test_split函数的详解在机器学习中,我们通常将原始数据按照比例分割为“测试集”和“训练集”从 sklearn.model_selection 中调用train_test_split 函数简单用法如下:X_train,X_test, y_train, y_test =sklearn.model_selection.train_test_split
(train_data,train_target,test_size=0.4, random_state=0,stratify=y_train)train_data:所要划分的样本特征集train_target:所要划分的样本结果test_size:样本占比,如果是整数的话就是样本的数量random_state:是随机数的种子随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。stratify:是为了保持split前类的分布。比如有100个数据,80个属于A类,20个属于B类。如果train_test_split(... test_size=0.25, stratify = y_all), 那么split之后数据如下:training: 75个数据,其中60个属于A类,15个属于B类testing: 25个数据,其中20个属于A类,5个属于B类。用了stratify参数,training集和testing集的类的比例是 A:B= 4:1等同于split前的比例(80:20)。通常在这种类分布不平衡的情况下会用到stratify。将stratify=X就是按照X中的比例分配将stratify=y就是按照y中的比例分配整体总结起来各个参数的设置及其类型如下:主要参数说明:*arrays 可以是列表、numpy数组、scipy稀疏矩阵或pandas的数据框test_size:可以为浮点、整数或None,默认为None①若为浮点时,表示测试集占总样本的百分比②若为整数时,表示测试样本样本数③若为None时,test size自动设置成0.25train_size:可以为浮点、整数或None,默认为None①若为浮点时,表示训练集占总样本的百分比②若为整数时,表示训练样本的样本数③若为None时,train_size自动被设置成0.75random_state:可以为整数、RandomState实例或None,默认为None①若为None时,每次生成的数据都是随机,可能不一样②若为整数时,每次生成的数据都相同stratify:可以为类似数组或None①若为None时,划分出来的测试集或训练集中,其类标签的比例也是随机的②若不为None时,划分出来的测试集或训练集中,其类标签的比例同输入的数组中类标签的比例相同,可以用于处理不均衡的数据集总之在遇到数据集不平衡的情况下可以使用该参数,来调节数据标签的不平衡的情况,我们可以该参数调节机器学习评估指标分类模型评估指标分类常用指标:准确率( accuracy):对于给定的测试数据集,分类器正确分类的样本数与总样本数之比混淆矩阵针对预测值和真实值之间的关系,我们可以将样本分为四个部分:真正例(True Positive,TP):预测值和真实值都为1假正例(False Positive,FP):预测值为1,真实值为0真负例(True Negative,TN):预测值与真实值都为0假负例(False Negative,FN):预测值为0,真实值为1很明显的得知,真正例和真负例越多,说明模型的效果就越好ROC曲线那么有了混淆矩阵,这样一个规则之后,我们需要一个评估指标可以直接的反映该情况的好坏,此时就引入了:真正例率上述公式,如果值越大那么说明真正例越多假正例率TPR也就是我们所说的召回率,通过TPR和FPR的相关性图,可以得到ROC曲线,如下图所示: ? ?图中的红色曲线和蓝色曲线分别表示了两个不同的分类器的TPR-FPR曲线,曲线上的任意一点都对应了一个特定的数值,也就是说如何看ROC曲线,从它的构造本质来看,真正例越大,假正例就越少,也就是说我们画出该曲线的时候,应该如何去看,怎样的曲线效果才是最好的,请看下面的解说:曲线越是“凸”向左上角,说明分类器效果越好最完美的分类器(完全区分正负样例):(0,1)点,即没有FP,全是TP ,根本不存在,如果存在应该思考是否出现错误?随机预测会得到(0,0)和(1,1)的直线上的一个点曲线上离(0,1)越近的点分类效果越好,对应着越合理的如此来看,上面的ROC曲线,红色的较好与蓝色的利用ROC的其他评估标准AUC:是一个概率值,当你随机挑选一个正样本以及一个负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值,而作为一个数值,对应AUC更大的分类器效果更好;这里需要注意的是,ROC曲线和AUC面积一般用于分类中的二分类情况,ROC曲线用在多分类中是没有意义的。只有在二分类中Positive和Negative同等重要时候,适合用ROC曲线评价。如果确实需要在多分类问题中用ROC曲线的话,可以转化为多个“一对多”的问题。即把其中一个当作正例,其余当作负例来看待,画出多个ROC曲线。EER:也就是FPR=FNR的值,由于FPR=1-TPR,可以画一条从(0,1)到(1,0)的直线,找到交点,图中的A、B两点。如果roc曲线绘制出来是一个对角线,那么就属于随机猜测模型,意义不大ROC曲线的意义及解释ROC曲线能很容易的查出任意阈值对学习器的泛化性能影响。有助于选择最佳的阈值。ROC曲线越靠近左上角,模型的查全率就越高。最靠近左上角的ROC曲线上的点是分类错误最少的最好阈值,其假正例和假反例总数最少。可以对不同的学习器比较性能。将各个学习器的ROC曲线绘制到同一坐标中,直观地鉴别优劣,靠近左上角的ROC曲所代表的学习器准确性最高。 ? ? ? ?该方法简单、直观、通过图示可观察分析方法的准确性,并可用肉眼作出判断。ROC曲线将真正例率和假正例率以图示方法结合在一起,可准确反映某种学习器真正例率和假正例率的关系,是检测准确性的综合代表。 ? ? ? ?此外,可以把多个模型(二分类)的ROC曲线绘制在一个平面图中,至于如何比较这个时候,就需要用到AUC面积了,面积越大说明该模型或者该算法下的分类效果较好
机器学习之Python开源教程——专栏介绍及理论知识概述
1??机器学习==人工智能??????????在人的大脑思维下,我们每看到一种事物,都会产生学习的记忆,这种记忆因人而异,可能是瞬间的,也可能是永久的?什么是机器学习?🧐 ? ? ? ?机器可以解决重复的工作,比如1+......+100=?如果是一个大脑,你可以在1秒钟立刻算出这些值吗?但是对于机器却是可以的,计算机程序针对大量的、重复的、具有规律的、可移植性的问题进行学习和求解,这一切的缘由都应该来自于“规律”——算法 ? ? ? ?机器是无法自己独立思考的,只有针对某种数学公式所设计的算法,让机器去重复的执行,最终遇到同等的问题,它会在大量的执行过程中,产生记忆,这种记忆我们称之为一种模型的记忆。你可以让机器去写一首诗句吗?答案是可以的! ? ? ? ?具体所要设计的是,首先针对用户所提出来的场景,机器会根据场景在语料库中自动化的寻找最佳匹配的汉字进行有效的筛选,然后按照古诗的语言和押韵进行整合,这些都是算法设计人员,提前将规则制定好,最后只是由程序进行匹配执行。什么又是人工智能?🧐 ? ? ? ?当然这只是一个简单的规则性、重复性的工作,真正的机器学习,乃至人工智能是不断的超越人的极限,最终逼近大脑思维的一种理性思维,未来机器学习和人工智能会结合人的感性思维,加入复杂的应对机制,让机器学会“思考” ? ? ? ?不管如何,机器想要达到和人的水平一样,可以独立思考那么必须要大量的学习,大量的输入输出,不断的迭代优化,目前的人工智能领域正在机器学习的基础上不断的升级和优化,相信在未来的互联网科技中,机器也可以达到人一样的智慧,但是真的可以吗?人类又会如何去设计,如何应用呢?我们将拭目以待!2??《机器学习之Python开源教程》专栏介绍 ? ? ? ?《机器学习之Python开源教程》将从机器学习的理论基础到实操案例,利用火热的编程语言——Python作为主要的编程语言工具,结合没一种算法的底层理论知识,全方位的剖析机器学习的原理,向着人工智能靠近!本专栏将从以下几个方面部署和搭建:详解机器学习的理论知识剖析并解读机器学习的算法构建实际案例进行进行机器学习的运用每一篇都有源码进行展示和解读,致力于打造开源项目提供更多的实操数据项目进行演示将机器学习应用到实际的生活当中来从监督学习到无监督学习最后在过渡到文本挖掘集成学习到推荐算法的实现最后探究图像处理的奥秘 ? ? ? ? 这里是机器学习从数据处理到数据挖掘的思维导图,包含Python的pandas与numpy的基本语法知识,同时涵盖了Python的第三方库sklearn的全部模块,从数据导入到特征工程,最后到标签选择再到模型部署和训练,最后到模型的评估,层层递进,如果有需要的小伙伴们点击下方即可下载!👇👇👇点击此处下载3??开启机器学习你需要准备什么? ? ? ? ?你知道“费曼学习法”吗?有一种东西就是,当你去学习一样新的知识的时候你不断的总结和探索,最终不断的输出,从输入到输出,在这个过程当中,你可以学到的不仅仅是知识,将会收获到更多的意外惊喜!所以开启机器学习的大门,你需要准备的是好奇心,探索欲和一种永不放弃的精神! ? ? ? ?如果你是初学者,初入机器学习的你需要准备的基础知识就是Python的基础语法,以及Python进阶的相关知识,如果你还是一个小白,建议先把Python的基础过一遍,然后再去上手,为了考虑到有些小伙伴,这里特意给你们准备了一套Python语法全套案例,点击下方链接👇👇👇【全网首发】言简意赅的Python全套语法,内附详细知识点和思维导图!【强烈建议收藏!】 ? ? ? ?学习好python的基础语法之后,你就可以看得懂这些代码的意思了,为了需要更进一步的入门机器学习,还需要了解Python的pandas和numpy库,这里也给大家准备了一份数据导入与科学计算的强大模块,Pandas 和 Numpy点击下方链接👇👇👇一文带你斩杀Python之Numpy??Pandas全部操作【全网最详细】??? ? ? ? ?准备好上述的理论基础和开发环境之后,你就可以开启机器学习的大门了,至于我们在学习的过程之中,会引入很多的实际的案例数据,这些数据博主均会上传到资源栏中,有需要的朋友可以下载之后 ,自己去练习。4?学完机器学习你可以做些什么? ? ? ? ?机器学习可以做什么,首先衡量一个东西的价值就需要考虑它的用途,如果它是一个用途不广泛的,受众度不高的东西,自然价值也就会收到削减。 ? ? ? ?机器学习可以适用于科研,同时也适用于商业,更适用于广大喜爱Python人员的必备技能,学习永无止境,你想要的都是自己去争取的。1、电子商务👀 ? ? ? ?机器学习在电商领域的应用主要涉及搜索、广告、推荐3个方面,在机器学习的参与下,搜索引擎能够更好地理解语义,对用户搜索的关键词进行匹配,同时它可以对点击率与转化率进行深度分析,更有利于用户选择符合自己需求的商品。2、医疗👀 ? ? ? ?普通医疗体系并不能永远保持精准且快速的诊断,在目前的研究阶段中,技术人员利用机器学习对上百万个病例数据库的医学影像进行图像识别及分析,并训练模型,帮助医生做出更为精准高效的诊断。3、金融👀 ? ? ? ?机器学习正在对金融行业产生重大的影响,在金融领域最常见的应用是过程自动化,该技术可以替代体力劳动,从而提高生产力。摩根大通推出了利用自然语言处理技术的智能合同的解决方案,该解决方案可以从文件合同中提取重要数据,大大节省了人工体力劳动成本。机器学习还可以应用于风控领域,银行通过大数据技术,监控账户的交易参数,分析持卡人的用户行为,从而判断该持卡人的信用级别。本专栏将开启五倍速更新,欢迎订阅!!!
启动MySQL如何加载Jemalloc
如何加载Jemalloc。有时候,我们想采用Jemalloc代替glibc自带的lib库,或者如果想启用TokuDB引擎,则就必须启用Jemalloc才行了。如果通过搜索引擎找到如何加载Jemalloc方法时,可能会看到像下面这种建议:#修改my.cnf文件 [mysqld_safe]配置区间,加上Jemalloc选项
[mysqld_safe]
thp-setting = never
malloc-lib = /usr/lib64/libjemalloc.so实际上这种做法现在已经不能用了。尤其是从MySQL 5.7版本开始,已经默认不使用mysqld_safe来启动了,可以改用下面的方法:#在启动mysqld之前,执行命令export LD_PRELOAD=/lib64/libjemalloc.so#然后再正常启动mysqld即可,例如/usr/local/mysql/bin/mysqld --default-file=/mysql/mysql-8.0/my.cnf &LD_PRELOAD是个环境变量,用于动态库的加载,动态库加载的优先级最高。一般情况下,其加载顺序为:LD_PRELOAD>LD_LIBRARY_PATH => /etc/ld.so.cache => /lib => /usr/lib然后执行下面的命令确认是否正确加载了:[
[email protected] ~]# lsof -p `pidof mysqld` | grep -i jemallocmysqld 21481 mysql mem REG 253,0 212096 1600 /usr/lib64/libjemalloc.so.1如果能看到类似上面的结果,就表示成功了。最后多说一句,也可以考虑采用Google的TCMalloc(Google Performance Tools项目),有同学测试过,其内存管理效率比Jemalloc还要略好些。延伸阅读Jemalloc项目:https://github.com/jemalloc/jemallocTCMalloc项目:https://github.com/gperftools/gperftools </div>
Javaweb复习资料(二)(下)
六、cookiehttps://yangyongli.blog.csdn.net/article/details/117912761七、sessionhttps://yangyongli.blog.csdn.net/article/details/117914643八、jsp(※)1 JSP基础1.1 JSP简介JSP全称是Java Server Page,它和Servlet一样,也是sun公司推出的一套开发动态web资源的技术,称为JSP/Servlet规范。JSP的本质其实就是一个Servlet。1.2 JSP和HTML以及Servlet的适用场景1.3 JSP简单入门创建JavaWeb工程在index.jsp中填写内容<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP的入门</title>
</head>
<body>
这是第一个JSP页面
</body>
</html>
部署项目沿用会话管理工程的部署方式即可。测试运行1.4 JSP说明写在之前: 明确JSP就是一个Servlet。是一个特殊的Servlet。JSP的原理: 客户端提交请求 ——Tomcat服务器解析请求地址 ——找到JSP页面 ——Tomcat将JSP页面翻译成Servlet的java文件 ——将翻译好的.java文件编译成.class文件 ——返回到客户浏览器上。1)执行过程分析图2)JSP的.java文件内容分析(看不懂跳过,反jsp本质就是servlet)当我们打开index.jsp翻译的java文件看到的就是public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase类的声明,然后我们在Tomcat的源码中找到类的声明,如下图:这张图一出场,就表明我们写的JSP它本质就是一个HttpServlet了。同时,我们在index_jsp.java文件中找到了输出页面的代码,并且在浏览器端查看源文件,看到的内容是一样的。这也就是说明,我们的浏览器上的内容,在通过jsp展示时,本质都是用out.write()输出出来的。讲到这里,我们应该清楚的认识到,JSP它是一个特殊的Servlet,主要是用于展示动态数据。它展示的方式是用流把数据输出出来,而我们在使用JSP时,涉及HTML的部分,都与HTML的用法一致,这部分称为jsp中的模板元素,在开发过程中,先写好这些模板元素,因为它们决定了页面的外观。2 JSP应用2.1 JSP语法1)Java代码块在jsp中,可以使用java脚本代码。形式为:<% 此处写java代码 %>但是,在实际开发中,极少使用此种形式编写java代码。同时需要注意的是:<%
在里面写java程序脚本需要注意:这里面的内容由tomcat负责翻译,翻译之后是service方法的成员变量
%>
示例:<!--Java代码块-->
<% out.println("这是Java代码块");%>
<hr/>2)JSP表达式在jsp中,可以使用特定表达式语法,形式为:<%=表达式%>jsp在翻译完后是out.print(表达式内容);所以:<%out.print("当前时间);%>和<%="当前时间"%>是一样的。在实际开发中,这种表达式语法用的也很少使用。示例:<!--JSP表达式-->
<%="这是JSP表达式"%><br/>
就相当于<br/>
<%out.println("这是没有JSP表达式输出的");%>
3)JSP声明在JSP中也可以声明一些变量,方法,静态方法,形式为:<%! 声明的内容 %>使用JSP声明需要注意:<%!
需要注意的是: 写在里面的内容将会被tomcat翻译成全局的属性或者类方法。
%>
示例:<!--JSP声明-->
<%! String str = "声明语法格式";%>
<%=str%>4)JSP注释在使用JSP时,它有自己的注释,形式为:<%–注释–%>需要注意的是: 在Jsp中可以使用html的注释,但是只能注释html元素,不能注释java程序片段和表达式。同时,被html注释部分会参与翻译,并且会在浏览器上显示 jsp的注释不仅可以注释java程序片段,也可以注释html元素,并且被jsp注释的部分不会参与翻译成.java文件,也不会在浏览器上显示。示例:<%--JSP注释--%>
<!--HTML注释-->
5)语法的示例JSP语法完整示例代码<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>JSP语法</title>
</head>
<body>
<!--Java代码块-->
<% out.println("这是Java代码块");%>
<hr/>
<!--JSP表达式-->
<%="这是JSP表达式"%><br/>
就相当于<br/>
<%out.println("这是没有JSP表达式输出的");%>
<hr/>
<!--JSP声明-->
<%! String str = "声明语法格式";%>
<%=str%>
<hr/>
<%--JSP注释--%>
<!--HTML注释-->
</body>
</html>
JSP语法运行结果2.2 JSP指令1)page指令language: 告知引擎,脚本使用的是java,默认是java,支持java。不写也行。extends:告知引擎,JSP对应的Servlet的父类是哪个,不需要写,也不需要改。import:告知引擎,导入哪些包(类)。注意:引擎会自动导入:java.lang.*,javax.servlet.*,javax.servlet.http.*,javax.servlet.jsp.*导入的形式: (用Eclipse:Alt+/ 自动导入)?<%@page import=”java.util.Date,java.util.UUID”%>
或者:
?<%@page import=”java.util.Date”%>
?<%@page import=”java.util.UUID”%>
session:告知引擎是否产生HttpSession对象,即是否在代码中调用request.getSession()。默认是true。buffer:JspWriter用于输出JSP内容到页面上。告知引擎,设定他的缓存大小。默认8kb。errorPage:告知引擎,当前页面出现异常后,应该转发到哪个页面上(路径写法:/代表当前应用)小贴士:当在errorpage上使用了isErrorPage=true之后,ie8有时候不能正常显示 配置全局错误页面:web.xml<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
当使用了全局错误页面,就无须再写errorPage来实现转到错误页面,而是由服务器负责跳转到错误页面。isErrorPage:告知引擎,是否抓住异常。如果该属性为true,页面中就可以使用exception对象,打印异常的详细信息。默认值是false。contentType:告知引擎,响应正文的MIME类型。contentType="text/html;charset=UTF-8"相当于response.setContentType("text/html;charset=UTF-8");pageEncoding:告知引擎,翻译jsp时(从磁盘上读取jsp文件)所用的码表。pageEncoding="UTF-8"相当于告知引擎用UTF-8读取JSPisELIgnored:告知引擎,是否忽略EL表达式,默认值是false,不忽略。2)include指令语法格式:<%@include file="" %>该指令是包含外部页面。属性:file,以/开头,就代表当前应用。使用示例在编译成的java servlet文件中是这样的,也就是说,include.jsp 后续 代码可以直接使用 included.jsp 中的 str变量。3)taglib指令语法格式:<%taglib uri="" prefix=""%>作用:该指令用于引入外部标签库。html标签和jsp标签不用引入。属性:uri:外部标签的URI地址。prefix:使用标签时的前缀。2.3 JSP细节1)九大隐式对象什么是隐式对象呢?它指的是在jsp中,可以不声明就直接使用的对象。它只存在于jsp中,因为java类中的变量必须要先声明再使用。其实jsp中的隐式对象也并非是未声明,只是它是在翻译成.java文件时声明的。所以我们在jsp中可以直接使用。也就是说下面的对象在jsp中可以直接使用。2)PageContext对象简介它是JSP独有的对象,Servlet中没有这个对象。本身也是一个域(作用范围)对象,但是它可以操作其他3个域对象中的属性。而且还可以获取其他8个隐式对象。生命周期?它是一个局部变量,所以它的生命周期随着JSP的创建而诞生,随着JSP的结束而消失。每个JSP页面都有一个独立的PageContext。常用方法在上图中,同学们发现没有页面域操作的方法,其实是定义在了PageContext的父类JspContext中,如下图所示:3)四大域对象4)四大域对象作用范围pageContext作用范围:当前jsp页面;作用:获取九大内置对象;常用方法:getAttribute()、setAttribute()、removeAttribute()、findAttribute()httpServletRequest作用范围:一次请求范围内,转发有效重定向失效;作用:将servlet中的数据通过request对象带到jsp页面;httpSession作用范围:存活时间内(默认30分钟),一次会话内有效,转发和重定向都有效;servletContext作用范围:整个web应用;在jsp的九大内置对象中,servletContext对应application;2.4 JSP最佳实战效果——MVC模型M:model ,通常用于封装数据,封装的是数据模型。V:view ,通常用于展示数据。动态展示用jsp页面,静态数据展示用html。C:controller ,通常用于处理请求和响应。一般指的是Servlet。Servlet:擅长处理业务逻辑,不擅长输出显示界面。在web开发中多用于控制程序逻辑(流程)。所以我们称之为:控制器。JSP:擅长显示界面,不擅长处理程序逻辑。在web开发中多用于展示动态界面。所以我们称之为:视图。例如:九、知识补充:JDK、JRE、JVM和SDK是啥啊都?JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib合起来就称为jre。JRE(Java Runtime Environment,Java运行环境),包含JVM标准实现及Java核心类库。JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。在安装目录下是这样的根据上面我们可以画成下面的关系图SDK是Software Development Kit 一般指软件开发包,可以包括函数库、编译程序等(可以效仿API去理解),是给java应用程序开发者使用的。Servlet编写三种方式我们在实现Servlet功能时,可以选择以下三种方式:1. 第一种:实现Servlet接口,接口中的方法必须全部实现。使用此种方式,表示接口中的所有方法在需求方面都有重写的必要。此种方式支持最大程度的自定义(我理解的就是真的个性化)。2. 第二种:继承GenericServlet,继承GenericServlet,service方法必须重写,其他方可根据需求,选择性重写。使用此种方式,表示只在接收和响应客户端请求这方面有重写的需求,而其他方法可根据实际需求选择性重写,使我们的开发Servlet变得简单。但是,此种方式是和HTTP协议无关的。比如说下面重写了 service方法public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException("non-HTTP request or response");
}
this.service(request, response);
}
service源码protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
long lastModified;
if (method.equals("GET")) {
lastModified = this.getLastModified(req);
if (lastModified == -1L) {
this.doGet(req, resp);
} else {
long ifModifiedSince;
try {
ifModifiedSince = req.getDateHeader("If-Modified-Since");
} catch (IllegalArgumentException var9) {
ifModifiedSince = -1L;
}
if (ifModifiedSince < lastModified / 1000L * 1000L) {
this.maybeSetLastModified(resp, lastModified);
this.doGet(req, resp);
} else {
resp.setStatus(304);
}
}
} else if (method.equals("HEAD")) {
lastModified = this.getLastModified(req);
this.maybeSetLastModified(resp, lastModified);
this.doHead(req, resp);
} else if (method.equals("POST")) {
this.doPost(req, resp);
} else if (method.equals("PUT")) {
this.doPut(req, resp);
} else if (method.equals("DELETE")) {
this.doDelete(req, resp);
} else if (method.equals("OPTIONS")) {
this.doOptions(req, resp);
} else if (method.equals("TRACE")) {
this.doTrace(req, resp);
} else {
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[]{method};
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(501, errMsg);
}
}
3. 第三种:继承HttpServle继承HttpServlet,它是javax.servlet.http包下的一个抽象类,是GenericServlet的子类。如果我们选择继承HttpServlet时,只需要重写doGet和doPost方法,不要覆盖service方法。使用第三种方式,表示我们的请求和响应需要和HTTP协议相关。也就是说,我们是通过HTTP协议来访问的。那么每次请求和响应都符合HTTP协议的规范。请求的方式就是HTTP协议所支持的方式(目前我们只知道GET和POST,而实际HTTP协议支持7种请求方式,GET POST PUT DELETE TRACE OPTIONS HEAD )。例如:import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//@WebServlet(name = "thirdServlet", urlPatterns = "/servlet")
//我们还可以进一步简化,因为我们发现其实name属性好像没啥用
//@WebServlet(urlPatterns = "/servlet")
//到这一步之后,还可以精简到底,如果括号里面只有一个值,那么默认表示的就是urlPattern
@WebServlet("/servlet")
public class ThirdServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
request获取请求参数HttpServletRequest对象获取请求参数的常用方法,以及把获取到的请求参数封装到实体类中的方式。首先,我们先来创建一个Servlet对象/**
* 封装请求正文到javabean(数据模型)
*/
public class RequestDemo3 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/*
* 把下面
* 1)获取请求参数
* 2)封装请求参数到实体类中
* 中定义的test1到test8逐个添加到此处来运行即可。
*/
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
接下来,我们在来准备一个表单页面:<html>
<head>
<title>login to request demo 3</title>
</head>
<body>
<form action="/day10_1122_requestresponse/RequestDemo3" method="post">
用户名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
性别:<input type="radio" name="gender" value="1" checked>男
<input type="radio" name="gender" value="0">女
<br/>
<input type="submit" value="注册" />
</form>
</body>
</html>
现在,我们开始分析HttpServletRequest对象用于获取请求参数的方法:1. 获取请求参数getParameter()方法的示例代码/**
* 获取请求正文,一个名称对应一个值。 没有使用确认密码
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");
System.out.println(username+","+password+","+gender);
}
getParameterValues()方法的示例代码/**
* 获取请求正文,一个名称可能对应多个值 使用了确认密码
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文
String username = request.getParameter("username");
String[] password = request.getParameterValues("password");//当表单中有多个名称是一样时,得到是一个字符串数组
String gender = request.getParameter("gender");
System.out.println(username+","+Arrays.toString(password)+","+gender);
}
<html>
<head>
<title>login to request demo 4</title>
</head>
<body>
<form action="/day10_1122_requestresponse/RequestDemo4" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="username" /><br/>
密码:<input type="password" name="password" /><br/>
确认密码:<input type="password" name="password" /><br/>
性别:<input type="radio" name="gender" value="1" checked>男
<input type="radio" name="gender" value="0">女
<br/>
<input type="submit" value="注册" />
</form>
</body>
</html>
getParameterNames()方法的示例代码/**
* 获取请求正文,一个名称一个值。但是先要获取正文名称的枚举(key的枚举) 没有使用确认密码
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test3(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文名称的枚举
Enumeration<String> names = request.getParameterNames();
//2.遍历正文名称的枚举
while(names.hasMoreElements()){
String name = names.nextElement();
String value = request.getParameter(name);
System.out.println(name+":"+value);
}
}
总结: 以上三个方法可以获取表单提交过来的请求参数。 参数的名称是一个字符串,参数的值可能是一个字符串,也可能是一个字符串数组。2. 封装请求参数到实体类中我们通过上面的方法可以获取到请求参数,但是如果参数过多,在进行传递时,方法的形参定义将会变得非常难看。此时我们应该用一个对象来描述这些参数,它就是实体类。这种类的定义,从基础阶段我们就开始使用了。在基础阶段,我们做过一个学生管理系统,用到了一个Student的类,它就是用于描述一个学生的实体类。我们现在要做的就是把表单中提交过来的数据填充到实体类中。第一种:最简单直接的封装方式/**
* 封装请求正文到User对象中 没有使用确认密码
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test4(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文
String username = request.getParameter("username");
String password = request.getParameter("password");
String gender = request.getParameter("gender");
//2.创建一个User对象
User user = new User();
System.out.println("封装前:"+user.toString());
//3.把请求正文封装到user对象中
user.setUsername(username);
user.setPassword(password);
user.setGender(gender);
System.out.println("封装后:"+user.toString());
}
第二种:使用反射方式封装此种封装的使用要求是,表单<input>标签的name属性取值,必须和实体类中定义的属性名称一致。/**
* 封装请求正文到javabean中 没有使用确认密码
* 使用反射+内省实现数据模型的封装
* 内省:是sun公司推出的一套简化反射操作的规范。把javabean中的元素都封装成一个属性描述器。
* 属性描述器中会有字段信息,get和set方法(取值或存值)
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test5(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文名称的枚举
Enumeration<String> names = request.getParameterNames();
User user = new User();
System.out.println("封装前:"+user.toString());
//2.遍历正文名称的枚举
while(names.hasMoreElements()){
String name = names.nextElement();
String value = request.getParameter(name);
try{
//1.拿到User对象中的属性描述器。是谁的属性描述器:是由构造函数的第一个参数决定的。第二个参数是指定javabean的字节码
PropertyDescriptor pd = new PropertyDescriptor(name, User.class);//参数指的就是拿哪个类的哪个属性的描述器
//2.设置javabean属性的值
Method method = pd.getWriteMethod();
//3.执行方法
method.invoke(user, value);//第一个参数是指的给哪个对象,第二个参数指的是赋什么值
}catch(Exception e){
e.printStackTrace();
}
}
System.out.println("封装后:"+user.toString());
}
第三种:使用反射封装,同时请求参数的值是一个数组此种方式其实就是针对请求参数中包含name属性相同的参数,例如:密码和确认密码,还有爱好。/**
* 获取请求正文的关系映射Map<String,String[]> 使用确认密码
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test6(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文的映射关系
Map<String,String[]> map = request.getParameterMap();
//2.遍历集合
for(Map.Entry<String,String[]> me : map.entrySet()){
String name = me.getKey();
String[] value = me.getValue();
System.out.println(name+":"+Arrays.toString(value));
}
}
当我们把请求参数获取出来之后,就要考虑如何针对数组的反射了,具体代码如下: /**
* 封装请求正文到javabean。使用的是反射+内省 使用了确认密码
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test7(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.获取请求正文的映射关系
Map<String,String[]> map = request.getParameterMap();
Users user = new Users();
System.out.println("封装前:"+user.toString());
//2.遍历集合
for(Map.Entry<String,String[]> me : map.entrySet()){
String name = me.getKey();
String[] value = me.getValue();
try{
//1.拿到User对象中的属性描述器。是谁的属性描述器:是由构造函数的第一个参数决定的。第二个参数是指定javabean的字节码
PropertyDescriptor pd = new PropertyDescriptor(name, Users.class);//参数指的就是拿哪个类的哪个属性的描述器
//2.设置javabean属性的值
Method method = pd.getWriteMethod();
//3.执行方法
//判断参数到底是几个值
if(value.length > 1){//最少有2个元素
method.invoke(user, (Object)value);//第一个参数是指的给哪个对象,第二个参数指的是赋什么值
}else{
method.invoke(user, value);//第一个参数是指的给哪个对象,第二个参数指的是赋什么值
}
}catch(Exception e){
e.printStackTrace();
}
}
System.out.println("封装后:"+user.toString());
}
当我们写完此种封装方式之后,同学们可以发现,我们绝大多数封装都可以使用这段代码来实现。并且,无论是谁来写这段通用的封装代码,其代码内容都是大同小异的。**那么,我们就可以得出一个很有趣的结论:一般遇到这种情况时,肯定有人帮我们写好了,我们只需要用就行了。**我们后面还会遇到类似这样的情况。此时,帮我们写好这段封装代码的是apache软件基金会,我们前面学习的tomcat也是它提供的。它里面有一个开源工具包集合commons,里面有很多开源工具类,今天我们就来讲解第一个:commons-beanutils。第四种:使用apache的commons-beanutils实现封装实现代码:/**
* 终极方法:使用beanutils实现请求正文封装到javabean中 使用了确认密码
* 要想使用beanutils,需要先导包
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
private void test8(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Users user = new Users();
System.out.println("封装前:"+user.toString());
try{
BeanUtils.populate(user, request.getParameterMap());//就这一句话
}catch(Exception e){
e.printStackTrace();
}
System.out.println("封装后:"+user.toString());
}