首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Java入门系列-14-深入类和对象

这篇文章用大量的代码帮你搞懂:值传递和引用传递、构造方法、方法重载、static关键字的使用 方法参数传递-值传递和引用传递 1.值传递 敲一敲: /** * 使用方法交换两个变量的值 * @author Jack * */ public class Swap { public static void main(String[] args) { int a=10; int b=8; Swap swap=new Swap(); swap.swap(a, b); System.out.println("调用方法后:a="+a+",b="+b); } public void swap(int a,int b) { int temp=a; a=b; b=temp; System.out.println("交换后:a="+a+",b="+b); } } 在上面这段代码中我们发现在方法内部对这两个参数进行交换成功,但是在调用方法后外部变量并没有任何变化。参数的类型为值类型,使用值类型作为参数称为值传递。 值传递方法内部修改外部不保留,参数内的变量是实参的副本。 2.引用传递 敲一敲: import java.util.Arrays; public class Swap2 { public static void main(String[] args) { int[] ages= {1,2,3}; Swap2 swap=new Swap2(); System.out.println("调用change前:"+Arrays.toString(ages)); swap.change(ages); System.out.println("调用change后:"+Arrays.toString(ages)); } public void change(int[] ages) { ages[0]=100; } } 在方法内部对参数变量进行修改后,方法的外部打印后也进行了修改,数组、类都是引用类型,使用引用类型作为参数传参被称为引用传递。 引用传递方法内部修改外部保留,参数内的变量是对实参的引用。 构造方法 在创建对象的时候,我们使用过这样的代码 类名 对象名=new 类名(); ,其实这时就是在调用此类的构造方法 public 类名(){}。 构造方法又称构造函数,是类中一种特殊的方法。构造方法名与类名相同,不返回任何值,主要完成对象的初始工作。 语法: 访问修饰符 构造方法(可以指定参数){ //初始化代码 } 敲一敲:无参构造方法 public class Student { String name; int age; public Student() { name="张三"; age=18; } public static void main(String[] args) { Student stu=new Student(); System.out.println(stu.name); System.out.println(stu.age); } } 这样就能在 new 时给对象的属性初始化值,但是在每一次 new 的时候都是相同的值。能不能在 new 的同时指定值呢?那就是使用有参的构造方法。 敲一敲:有参构造方法 public class Student { String name; int age; public Student(String name,int age) { this.name=name; this.age=age; } public static void main(String[] args) { Student stu=new Student("张三",12); System.out.println(stu.name); System.out.println(stu.age); } } this 代表当前对象的引用,在有参构造方法中使用时区分属性和参数 上面的这段代码,能不能这样创建对象 Student stu=new Student(); 答案是不可以的 不显式编写构造方法,系统将默认提供无参构造方法 一旦提供编写构造方法,系统便不再提供无参构造方法 所以这时我们可以同时编写有参构造方法和无参构造方法,使我们创建对象的时候更加的灵活。 敲一敲:同时提供有参和无参构造方法 public class Student { String name; int age; //无参构造方法 public Student() {} //有参构造方法 public Student(String name,int age) { this.name=name; this.age=age; } public static void main(String[] args) { //使用有参构造方法 Student stu1=new Student("张三",12); System.out.println(stu1.name); System.out.println(stu1.age); //使用无参构造方法 Student stu2=new Student(); stu2.name="李四"; } } 方法重载 在上一部分中,我们使用了有参和无参的方法,为什么在一个类中可以定义多个类名相同的方法呢?因为实现了方法重载。只不过构造方法重载是一种特殊的重载。 重载的条件(两同两不同) 在同一个类中,方法名相同,参数类型不同,参数个数不同 敲一敲:实现普通方法的重载 public class Teacher { public void teach(String project) { System.out.println("教授科目:"+project); } public void teach(String project1,String project2) { System.out.println("教授科目:"+project1+" 和 "+project2); } public static void main(String[] args) { Teacher t=new Teacher(); t.teach("语文"); t.teach("语文","数学"); } } 在生活中有很多活动就属于重载,比如 表演 ,给表演者剧本就是在表演戏剧,给表演者乐器,就是表演演奏,给表演者话筒,就是表演相声。 在代码中使用重载也有很多好处,比如 System.out.println(); 这个方法也有很多重载形式,可以传入 int string object 作为参数,减少了书写和记忆的成本。你肯定不希望打印每种数据类型时都单独定义一个方法,像后面这样 printIntln(int out) printDoubleln(double out) printLongln(long out) …… this 关键字的用法 在使用构造函数时使用了 this 关键字用于区分属性和参数,那只是第一种用法,除此之外还可以调用方法、调用构造方法。 调用属性:this.health=100; 调用方法:this.print(); 调用构造方法:this(); this("张三",18); 必须用在构造方法中的第一行 static 关键字的用法 如何通过类名直接访问类中的成员,像之前用过的 Arrays.toString(),查看源码部分代码如下。 public static String toString(int[] a) { if (a == null) return "null"; int iMax = a.length - 1; if (iMax == -1) return "[]"; StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { b.append(a[i]); if (i == iMax) return b.append(']').toString(); b.append(", "); } } 当前这个方法使用了 static 关键字进行了修饰 还可以修饰成员变量: public class Teacher { static final String SEX_MALE="男"; static final String SEX_FEMALE="女"; String sex; public static void main(String[] args) { Teacher teacher=new Teacher(); teacher.sex=Teacher.SEX_FEMALE; System.out.println(teacher.sex); } } final 修饰后的变量都将变成常量 常量的值不能修改,只能使用 可以修饰代码块: public class Teacher { static final String SEX_MALE="男"; static final String SEX_FEMALE="女"; String sex; //代码块 static { System.out.println("静态代码块"); } public static void main(String[] args) { Teacher teacher=new Teacher(); teacher.sex=Teacher.SEX_FEMALE; System.out.println(teacher.sex); } } static 关键字使用注意事项 1.static 修饰了属性和代码块后,会先初始化静态属性,再执行静态代码块 public class TakeCare1 { static String name="aa"; static { System.out.println(name); System.out.println("静态代码块执行"); } public TakeCare1() { System.out.println("构造函数执行"); } public static void main(String[] args) { TakeCare1 t=new TakeCare1(); } } 2.static 关键字不能修饰局部变量 public class TakeCare2 { public static void main(String[] args) { static int a=10; } } 3.同一个类中的静态方法可以互相通过方法名直接调用 public class TakeCare2 { public static void test1() { System.out.println("method test1"); test2(); TakeCare2.test2(); } public static void test2() { System.out.println("method test2"); } public static void main(String[] args) { test1(); } } 4.不同类中的静态成员调用需要通过 类名.成员 调用 public class TakeCare4 { public static void main(String[] args) { Test.test(); System.out.println(Test.name); //test();//去掉前面注释试试 } } class Test{ static String name="Test"; public static void test() { System.out.println("method test"); } } 5.同一个类中非静态方法可以直接通过 属性名或方法名 调用 public class TakeCare5 { static String name="static property"; public static void st() { System.out.println("static method"); } public void test() { System.out.println("instance method"); System.out.println(name); st(); } } 6.静态方法不能直接使用实例成员,需要通过对象调用 public class TakeCare6 { public static void st() { System.out.println("static method"); TakeCare6 tc=new TakeCare6(); tc.test(); //test();//去掉注释后报错 Cannot make a static reference to the non-static method test() from the type TakeCare6 } public void test() { System.out.println("instance method"); } } 总结:static 修饰后的成员就像万能的 O 型血,在任何地方都能 类名.成员 调用(private 修饰除外),实例方法除了本类中的方法,只能 对象.成员 调用 搜索关注公众号「享智同行」,第一时间获取技术干货

优秀的个人博客,低调大师

Elastic Search 新手笔记(1)——入门

前言 之前写过一个关于Elastic Search的文章,当时的我还不会使用markdown,还不知道怎么好好把自己所想的,总结成一个有条理的文章,所以我就想写下了这一篇新文章,帮助自己消化所学的东西,也可以把知识分享给大家。 使用 版本 操作系统 MacOS ES版本 6.3.0 可视化插件 Head 安装 1.单实例安装 elasticSearch 的安装我觉得相对简单一些,我们可以在官网或者是别的途径,下载到它,官网的下载地址为https://www.elastic.co/downloads/elasticsearch,当前最新的版本为6.4.2。而我使用的版本是6.3.0,如果想要下载到原来版本的ES,可以进入以下网址进行下载https://www.elastic.co/downloads/past-releases。 下载好后,执行bin目录下的elasticsearch即可。 启动后,在浏览器输入http://localhost:9200/即可,效果如下: image.png 2.Head插件安装 Head插件是依托于node环境的,我们在使用插件之前需要先下载node.js。node.js下载好后,通过node -v 查看是否安装成功,然后就可以通过以下网址下载Head插件。Head 插件地址。下载好Head插件以及elasticsearch后,需要修改在elasticsearch 中的config的elasticsearch.yml中加上以下配置内容: http.cors.enabled: true http.cors.allow-original: "*" 保证了Es以及Head插件的连通性。 Head插件的启动 1.npm install phantomjs-prebuilt@2.1.15 --ignore-scripts(之所以不使用npm install 是因为这个包,一直都取不到,但是它也不怎么影响使用。) 2.npm install 3.npm run start 启动后,在浏览器输入http://localhost:9100,如果显示了相关内容即可。 3.分布式安装 分布式的安装和单实例安装大同小异,把下载下来的ElasticSearch复制两个副本,放在新创建的目录ES_slave(slave为随从奴隶的意思,在这里把我们之前安装好的当做一个master,然后其他的slave配合master形成一套分布式)中,如下图所示: image.png 这里是创建了两个,如果有需求,可以根据需求继续拓展。 然后把两个slave中的elasticsearch.yml文件进行修改,加入以下配置: #配置ElasticSearch的集群名称 cluster.name: harry #节点的名称(另一个节点名称可以使用slave2) node.name: slave1 #设置绑定的IP地址 network.host: 127.0.0.1 #设置对外服务的端口号,默认情况下为9200(这里只要使用没被使用的端口号即可) http.port: 8200 #设置是否打开多播发现节点,如果不进行配置,不会被主节点发现。 discovery.zen.ping.unicast.hosts: ["127.0.0.1"] 配置好后,启动slave的elasticsearch即可。 Tips:我启动的时候报了一个错误。 [2018-10-07T11:57:44,907][INFO ][o.e.d.z.ZenDiscovery ] [slave1] failed to send join request to master [{master}{dLNpAPsSTvCFgzow1nuM6g} {lZIG2Xm3Sx-4Y4eHU5x9CA}{127.0.0.1}{127.0.0.1:9300} {ml.machine_memory=8589934592, ml.max_open_jobs=20, xpack.installed=true, ml.enabled=true}], reason [RemoteTransportException[[master][127.0.0.1:9300] [internal:discovery/zen/join]]; nested: IllegalArgumentException[can't add node {slave1}{dLNpAPsSTvCFgzow1nuM6g}{4NUyj79cSxuaJL8BMtGejw}{127.0.0.1} {127.0.0.1:9301}{ml.machine_memory=8589934592, ml.max_open_jobs=20, xpack.installed=true, ml.enabled=true}, found existing node {master} {dLNpAPsSTvCFgzow1nuM6g}{lZIG2Xm3Sx-4Y4eHU5x9CA}{127.0.0.1} {127.0.0.1:9300}{ml.machine_memory=8589934592, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true} with the same id but is a different node instance]; ] 因为我是把master的Es复制过来,作为slave,但是data中还有原来的数据,所以报了这个错,只要把,Es中的data文件夹中的东西都删除就行。 我们现在把master 的ES启动,slave1的ES启动,slave2的ES启动,最后把Head也启动起来,然后浏览器输入http://localhost:9100,效果如下,证明成功。 image.png 基本概念 1.索引,类型,文档 Elastic Search 与关系型数据库对比 Elastic Search 关系型数据库 索引 数据库 类型 表 文档 行 这里的Elastic Search 泛指的是全文检索。一个索引中,包含多个类型,一个类型中包含着多个文档。 在刚接触的时候,我想过这样一个问题,在关系型数据库mysql的like进行模糊查询的效果,与Elastic Search这样的全文检索,效果几乎就是一样的,那为什么还要用全文检索呢? 原因我觉得一共有两个: 第一个是查询的速度特别快。在关系型数据库中,数据是结构化的,我们当要进行模糊查询的时候,会从想要查询的表的第一条数据开始比对,如果不是,继续下一条,如果再不是,继续去查,就这样一直查下去,直到查到了,自己想要的那条数据。而Elastic Search呢?它其实使用了倒排索引。大概意思其实是这样的:现在一个有三篇文章 id content 文章1 Java是世界上最好的 . 文章2 人生苦短,快学python 文章3 C++是世界上最难的 . 这也是存储在关系型数据库中的存储形式,查询的话,他会一行行的进行查询。而如果存在了Elastic Search 中会变成什么样子呢?在全文检索中存在这分词器这么个东西,分词器会把输入的句子自动的进行一定规律进行分割,例如过空格分割,下划线分割,等等。如果是中文,也有插件可以对其进行语义分割。分割后的效果如下所示(只是举例子,真实情况未必如此) 关键词 文章号 世界 1,3 人生苦短 2 . Java 1 . python 2 C++ 3 当我们输入世界,立刻就知道出现在了第一个,和第三个文章中。 第二个是因为我们在做全文检索的时候,根本用不到那么复杂的逻辑,我们用到基础的增删改查就行,使用了Elastic Search 之后,我们在也不用折腾数据库那么多的数据了。 2.分片与索引 每一个索引包含了多个分片,每个分片是一个lucene索引(lucene是Elasticsearch的底层引擎。)只需要将分片拷贝一份,就完成了分片的备份。 3.集群和节点 每一个集群都有一个集群的名字,一个集群包含多个节点。我们只需要知道集群的名称,便可以拓展集群中的节点。 4.elasticsearch.yml 我上面在启动head插件和设置分布式集群的时候,有修改过这个文件,但是这个文件还有别的可配置属性,我在这里说明一下,以备不时之需。 cluster.name: elasticsearch #设置集群名称,一个集群只可以有一个名称,ElasticSearch会自己去查找同一个网段下的所有节点 node.name: node-1 #设置节点名称 node.master: true #设置该节点是否是master节点,默认为true node.data: true #设置该节点,是否存储索引数据,默认为true index.number_of_shards: 5 #设置分片的数量,默认为5个,这个配置只在5.0版本之前好用 index.number_of_replicas: 1 #设置索引副本数量,默认为一个,同样也是只在5.0之前好用。 path.data: /path/to/data #设置索引数据的存储路径,默认在data文件夹下,可以设置多个文件存储路径,用逗号分隔。 path.logs: /path/to/logs #设置log日志的存储路径,默认情况下是在logs文件夹下。 bootstrap.mlockall: true #设置为true来锁住内存 network.host: 0.0.0.0 #设置绑定的Ip地址,默认为0.0.0.0 http.port: 9200 #设置对外服务的HTTP端口号 transport.tcp.port: 9300 #设置节点间交互的TCP端口号,也是给Java API使用的端口号,默认是9300。 transport.tcp.compress: false #是否压缩TCP传输的数据,默认为false http.cors.enabled:true #是否使用http提供对外的服务,默认为true http.max_content_length: 100mb #http传输内容的最大容量。 discovery.zen.minimum_master_nodes: 1 #发现master节点的数量,默认为1个。 discovery.zen.ping.timeout: 3s #发现其他节点,超时的时间。 discovery.zen.ping.multicast.enabled:true #是否打开多播发现节点。 discovery.zen.ping.unicast.hosts:["host1","host2:port","host3:[portX-portY]"] #设置集群master几点的初始列表。 script.engine.groovy.inline.update: on #开启groovy脚本的支持 script.inline: true #开始所有脚本语言行内执行所有的操作。 基本用法 Elastic Search 我们可以使用REST API与其进行交互,说白了就是使用url地址,通过不同的method(get,post,put,delete)传入不同的json数据。 head插件虽然很好,但是也并不是万能的,我比较习惯用Post man进行api交互。下面讲讲具体的操作。1.创建索引 url地址 method 用途 localhost:9200/索引名称 put 创建索引 在创建索引之前,我要先说两个概念分别是静态映射和动态映射。 动态映射是在创建索引之初,不添加索引的类型和文档中属性的格式,而是在添加文档的时候,格式会被自动转化。两种不同映射的设置,是由dynamic参数来决定的一共有三个可选值: true 动态映射自动添加字段 false 静态映射,不会自动添加字段 strict 静态映射,如果添加了新字段会报错 动态转换内容如下: JSON格式的数据 自动推测的字段类型 null 没有字段被添加 true or false boolean 浮点类型数字 float 数字 long JSON对象 object 数组 有数组中第一个非空值决定 string 有可能是date类型(开启日企检测),double,long,text,keyword 动态映射json体: { "settings":{ "number_of_shards":3, "number_of_replicas":1 } } number_of_shards是用来设置分片数量的 number_of_replicas是用来设置副本数量的 静态映射Json体: { "settings":{ "number_of_shards":3, "number_of_replicas":1 }, "mappings":{ "it": { "dynamic":"strict", "properties":{ "title":{ "type":"text" }, "content":{ "type":"text" }, "create_date":{ "type":"date" } } } } } 这里的it指的就是类型,在properties中添加自己的字段,并且指定属性的类型。 另外发送请求的content-type一定得是application/json,这个值得注意,成功后,会返回一个属性acknowledged 是true的,就说明创建成功,其他的如下图(Tips:几个更换 json体,这里的截图只是一个示范): image.png 查看head插件,如下图 image.png 我们可以看到这里创建了三个分片(细线为粗线的副本)。 2.插入文档 url地址 method 用途 localhost:9200/索引名称/类型名称/文档id put 创建文档(指定文档id) localhost:9200/索引名称/类型名称 post 创建文档(随机文档id) 3.修改文档 url地址 method 用途 localhost:9200/索引名称/类型名称/文档id/_update post 修改文档 json体: { "doc":{ "修改字段名称": "想要修改成的值" } } 4.删除文档 url地址 method 用途 localhost:9200/索引名称/类型名称/文档id delete 删除文档 5.查询文档 这里先介绍简单的查询,复杂的地方,会在后面说到。 url地址 method 用途 localhost:9200/索引名称/类型名称/文档id get 查询文档通过文档id localhost:9200/索引名称/类型名称/_search post 查询所有数据 简单查询数据结构体为 { "query":{ "match_all":{},(通过该属性查询所有数据) "match":{ "需要查询的字段名称":"查询的值" } }, "from": "从第几个开始"(可选), "size": "要查询多少个"(可选) , "sort": [ {"字段名称":{"order": "desc 或者是 asc"}}(自定义排序,默认通过score元字段进行排序) ] } 聚合查询结构体为: (可以定义多个聚合条件,放在不同的聚合名称中) { "aggs":{ "聚合名称1(自定义)": { "terms":{ "field": "通过该字段进行聚合" }, "status":{ "field": "通过该字段进行聚合"(status key可以计算这个聚合的相关参数) } }, "聚合名称2(自定义)": { "terms":{ "field": "通过该字段进行聚合" } } } } 后记 这篇文章是学习了慕课网上瓦力老师的教程并参考《从lucene到Elasticsearch全文检索实战》所写,课程地址为https://www.imooc.com/learn/889,在此感谢你们的分享,我会在后续的文章中继续总结elasticsearch的更多查询语法,以及Spring Boot 集成 Elastic Search 的相关知识。

优秀的个人博客,低调大师

深度学习优化算法入门:二、动量、RMSProp、Adam

编者按:DRDO研究人员Ayoosh Kathuria深入浅出地介绍了牛顿法、动量法、RMSProp、Adam优化算法。 本系列的上一篇文章介绍了随机梯度下降,以及如何应对陷入局部极小值或鞍点的问题。在这篇文章中,我们将查看另一个困扰神经网络训练的问题,病态曲率。 局部极小值和鞍点会使训练停滞,而病态曲率则会减慢训练速度,以至于机器学习从业者可能会觉得搜索收敛到了一个次优极小值。让我们深入了解下什么是病态曲率。 病态曲率 考虑下面的损失曲面。 如你所见,我们从随机点开始,渐渐进入蓝色的沟壑区。(颜色表示损失函数在特定点的值是高是低,红色表示高值,蓝色表示低值。) 在到达最小值之前,我们需要首先穿过沟壑区,也就是病态曲率。让我们放大一下这一区域,看看为什么称病态? 如上图所示,梯度下降在沟壑区的脊间反复振荡,极其缓慢地向最小值处移动。这是因为w1方向要陡峭得多。 考虑下图中A点的梯度,可以分解为w1、w2方向的两个分量。w1方向的梯度要大很多,因此梯度的方向大为偏向w1,而不是w2(但w2才是能够更快到达最小值处的梯度方向)。 通常情况下,我们使用低学习率来应对这样的反复振荡,但在病态曲率区域使用低学习率,可能要花很多时间才能达到最小值处。事实上,有论文报告,防止反复振荡的足够小的学习率,也许会导致从业者相信损失完全没有改善,干脆放弃训练。 大概,我们需要找到一种方法,首先缓慢地进入病态曲率的平坦底部,然后加速往最小值方向移动。二阶导数可以帮助我们做到这一点。 牛顿法 梯度下降是一阶优化方法。它只考虑损失函数的一阶导数,不考虑高阶函数。基本上这意味着它对损失函数的曲率一无所知。梯度下降可以告诉我们损失是否下降,下降得有多快,但无法区分曲线的的弯曲程度。 上图三条曲线,红点处的梯度都是一样的,但曲率大不一样。解决方案?考虑二阶导数,或者说梯度改变得有多快。 使用二阶导数解决这一问题的一个非常流行的技术是牛顿法(Newton's Method)。为了避免偏离本文的主题,我不会过多探究牛顿法的数学。相反,我将尝试构建牛顿法的直觉。 牛顿法可以提供向梯度方向移动的理想步幅。由于我们现在具备了损失曲面的曲率信息,步幅可以据此确定,避免越过病态曲率的底部。 牛顿法通过计算Hessian矩阵做到这一点。Hessian矩阵是损失函数在所有权重组合上的二阶导数的矩阵。 Hessian提供了损失曲面每一点上的曲率估计。正曲率意味着随着我们的移动,损失曲面变得不那么陡峭了。负曲率则意味着,损失曲面变得越来越陡峭了。 注意,如果这一步的计算结果是负的,那就意味着我们可以切换回原本的算法。这对应于下面梯度变得越来越陡峭的情形。 然而,如果梯度变得越来越不陡峭,那么我们也许正向病态曲率的底部移动。这时牛顿算法提供了一个修正过的学习步幅,和曲率成反比。换句话说,如果损失曲面变得不那么陡峭,学习步幅就下降。 为何我们不常使用牛顿法? 你已经看到公式中的Hessian矩阵了。Hessian矩阵需要我们计算损失函数在所有权重组合上的梯度。也就是说,需要做的计算的数量级是神经网络所有权重数量的平方。 现代神经网络架构的参数量可能是数亿,计算数亿的平方的梯度在算力上不可行。 虽然高阶优化方法在算力上不太可行,但二阶优化关于纳入梯度自身如何改变的想法是可以借鉴的。虽然我们无法准确计算这一信息,但我们可以基于之前梯度的信息使用启发式算法引导优化过程。 动量 搭配SGD使用的一个非常流行的技术是动量(Momentum)。动量法不仅使用当前的梯度,同时还利用之前的梯度提供的信息。 上面的第一个等式就是动量,动量等式由两部分组成,第一项是上一次迭代的动量,乘以“动量系数”。 比如,假设我们将初始动量v设为0,系数定为0.9,那么后续的更新等式为: 我们看到,后续的更新保留了之前的梯度,但最近的梯度权重更高。(致喜欢数学的读者,这是梯度的指数平均。) 下面我们来看看动量法如何帮助我们缓解病态曲率的问题。下图中,大多数梯度更新发生在之字形方向上,我们将每次更新分解为w1和w2方向上的两个分量。如果我们分别累加这些梯度的两个分量,那么w1方向上的分量将互相抵消,而w2方向上的分量得到了加强。 也就是说,基于动量法的更新,积累了w2方向上的分量,清空了w1方向上的分量,从而帮助我们更快地通往最小值。从这个意义上说,动量法也有助于抑制振荡。 动量法同时提供了加速度,从而加快收敛。但你可能想要搭配模拟退火,以免跳过最小值。 在实践中,动量系数一般初始化为0.5,并在多个epoch后逐渐退火至0.9. RMSProp RMSProp,也就是均方根传播的历史很有趣。它是传奇人物Geoffrey Hinton在Coursera授课时初次提出的。 RMSProp也试图抑制振荡,但采取的方法和动量不同。此外,RMSProp可以自动调整学习率。还有,RMSProp为每个参数选定不同的学习率。 在第一个等式中,类似之前的动量法,我们计算了梯度平方的指数平均。由于我们为每个参数单独计算,这里的梯度gt表示正更新的参数上的梯度投影。 第二个等式根据指数平均决定步幅大小。我们选定一个初始学习率η,接着除以平均数。在我们上面举的例子中,w1的梯度指数平均比w2大得多,所以w1的学习步幅比w2小得多。这就帮助我们避免了脊间振荡,更快地向最小值移动。 第三个等式不过是权重更新步骤。 上面的等式中,超参数ρ一般定为0.9,但你可能需要加以调整。等式2中的ε是为了确保除数不为零,一般定为1e-10. 注意RMSProp隐式地应用了模拟退火。在向最小值移动的过程中,RMSProp会自动降低学习步幅,以免跳过最小值。 Adam Adam,即Adaptive Moment Optimization算法结合了动量和RMSProp的启发式算法。 这里,我们计算了梯度的指数平均和梯度平方的指数平均(等式1和等式2)。为了得出学习步幅,等式3在学习率上乘以梯度的平均(类似动量),除以梯度平方平均的均方根(类似RMSProp)。等式4是权重更新步骤。 超参数β1一般取0.9,β2一般取0.99. ε一般定为1e-10. 结语 本文介绍了三种应对病态曲率同时加速训练过程的梯度下降方法。 在这三种方法之中,也许动量法用得更普遍,尽管从论文上看Adam更吸引人。经验表明这三种算法都能收敛到给定损失曲面的不同的最优局部极小值。然而,动量法看起来要比Adam更容易找到比较平坦的最小值,而自适应方法(自动调整学习率)倾向于迅速地收敛于较尖的最小值。比较平坦的最小值概括性更好。 尽管这些方法有助于我们驯服深度网络难以控制的损失平面,随着网络日益变深,它们开始变得不够用了。除了选择更好的优化方法,有相当多的研究试图寻找能够生成更平滑的损失曲面的架构。批量归一化(Batch Normalization)和残差连接(Residual Connections)正是这方面的两个例子。我们会在后续的文章中详细介绍它们。但这篇文章就到此为止了。欢迎在评论中提问。 原文发布时间为:2018-10-07 本文作者: weakish 本文来自云栖社区合作伙伴“深度学习自然语言处理”,了解相关信息可以关注“深度学习自然语言处理"

优秀的个人博客,低调大师

CodeMirror 代码渲染神器的极简入门实例

效果: image.png HTML: <script src="https://codemirror.net/lib/codemirror.js"></script> <script src="https://codemirror.net/mode/javascript/javascript.js"></script> <link rel="stylesheet" href="https://codemirror.net/lib/codemirror.css"> <div id="fn"></div> <button class="btn btn-sm btn-success offset2" id="fn-save-btn">保存</button> <button class="btn btn-sm btn-success" id="fn-eval-btn">运行</button> <div id="eval-result" class="eval-result"></div> JS 代码示例: // 渲染代码: var editor = CodeMirror.fromTextArea(document.getElementById("fnBody"), { lineNumbers: true, mode: "javascript", matchBrackets: true }); // 获取代码的文本值 var fnBody = editor.doc.getValue(); // 运行脚本,预览结果 $('#fn-eval-btn').unbind().bind('click', () => { console.dir(editor); var fnBody = editor.doc.getValue(); var postData = { js: fnBody }; $.ajax({ url: '/datafactory/evalJs.json' , data: postData , type: 'POST' , success: (result) => { if (result.success == true) { $('#eval-result').html(`<div>运行结果:</div><code>${result.data}</code>`) } else { alert(result.errorMessage) } } , error: (err) => { alert(JSON.stringify(err)) } }); });// fn-eval-btn 后端代码 Kotlin: @PostMapping("/evalJs.json") @ResponseBody fun evalJs(js: String): ResultVo<String> { println("js=${js}") val result = ResultVo( data = "", isSuccess = false, errorCode = "1", errorMessage = "", state = "1" ) try { val data = NashornUtil.evalJs(js) result.data = data result.isSuccess = true result.errorCode = "0" result.errorMessage = "" result.state = "" } catch (e: Exception) { result.errorMessage = e.message ?: "" } return result } 其中,evalJs() 的函数实现如下: package com.alibaba.xxpt.qa.adt.util import javax.script.ScriptEngineManager object NashornUtil { private val scriptEngineManager = ScriptEngineManager() private val nashorn = scriptEngineManager.getEngineByName("nashorn") fun evalJs(js: String): String { try { return nashorn.eval(js).toString() } catch (e: Exception) { e.printStackTrace() return "" } } } 使用的是 Java 8 中的nashorn 引擎(支持 ES5 的语法)。 参考文档:https://codemirror.net/

优秀的个人博客,低调大师

全面入门jQuery最佳实践(一)-选择器

1 初识JQuery 1.1 简介 1.2 环境搭建 进入官方网站获取最新的版本 http://jquery.com/download/ ,这里需要注意 jQuery 分 2 个系列版本 1.x 与 2.x,主要的区别在于 2.x 不再兼容 IE6、7、8浏览器,这样做的目的是为了兼容移动端开发。由于减少了一些代码,使得该版本比 jQuery 1.x 更小、更快。 如果开发者比较在意老版本 IE 用户,只能使用 jQuery 1.9 及之前的版本了。为了兼容性问题,使用的是 1.9 版本。jQuery 每一个系列版本分为:压缩版(compressed) 与 开发版(development),我们在开发过程中使用开发版(开发版本便于代码修改及调试),项目上线发布使用压缩版(因为压缩版本体积更小,效率更快)。 jQuery是一个JavaScript脚本库,不需要特别的安装,只需要我们在页面 <head> 标签内中,通过 script 标签引入 jQuery 库即可。 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <script type="text/javascript" src="https://www.imooc.com/static/lib/jquery/1.9.1/jquery.js"></script> <title>环境搭建</title> </head> <body> <script type="text/javascript"> alert($) </script> </body> </html> 验证成功 1.3 jQueryHelloWorld体验 当页面加载完成后,在页面中以居中的方式显示“您好”字样。 代码分析$(document).ready 的作用是等页面的文档(document)中的节点都加载完毕后,再执行后续的代码,因为我们在执行代码的时候,可能会依赖页面的某一个元素,我们要确保这个元素真正的的被加载完毕后才能正确的使用。 1.4 jQuery对象与DOM对象 jQuery对象与DOM对象是不一样的 可能一时半会分不清楚哪些是jQuery对象,哪些是DOM对象,下面重点介绍一下jQuery对象,以及两者相互间的转换。 通过一个简单的例子,简单区分下jQuery对象与DOM对象: <p id=”sss”></p> 我们要获取页面上这个id为sss的p元素,然后给这个文本节点增加一段文字:“您好”,并且让文字颜色变成红色。 普通处理,通过标准JavaScript处理: var p = document.getElementById('sss'); p.innerHTML = '您好'; p.style.color = 'red'; 通过原生DOM模型提供的document.getElementById(“sss”) 获取的DOM元素就是一个DOM对象,再通过innerHTML与style属性处理文本与颜色。 jQuery的处理: var $p = $('#sss'); $p.html('您好').css('color','red'); 通过$('#sss')会得到一个$p的jQuery对象,$p是一个类数组对象。 这个对象里面包含了DOM对象的信息,然后封装了很多操作方法,调用自己的方法html与css,得到的效果与标准的JavaScript处理结果是一致的 通过标准的JavaScript操作DOM与jQuery操作DOM的对比,我们不难发现: 通过jQuery方法包装后的对象,是一个类数组对象。它与DOM对象完全不同,唯一相似的是它们都能操作DOM 通过jQuery处理DOM的操作,可以让开发者更专注业务逻辑的开发,而不需要我们具体知道哪个DOM节点有那些方法,也不需要关心不同浏览器的兼容性问题,我们通过jQuery提供的API进行开发,代码也会更加精短。 1.5 jQuery对象转化成DOM对象 jQuery库本质上还是JavaScript代码,它只是对JavaScript语言进行包装处理,为的是提供更好更方便快捷的DOM处理与开发中经常使用的功能。 我们使用jQuery的同时也能混合JavaScript原生代码一起使用。在很多场景中,我们需要jQuery与DOM能够相互的转换,它们都是可以操作的DOM元素,jQuery是一个类数组对象,而DOM对象就是一个单独的DOM元素。 如何把jQuery对象转成DOM对象? 利用数组下标的方式读取到jQuery中的DOM对象 用jQuery找到所有的div元素(3个),因为jQuery对象也是一个数组结构,可以通过数组下标索引找到第一个div元素,通过返回的div对象,调用它的style属性修改第一个div元素的颜色 通过jQuery的get() 允许我们直接访问jQuery对象中相关的DOM节点,get方法中提供一个元素的索引: 其实我们翻开源码,看看就知道了,get方法就是利用的第一种方式处理的,只是包装成一个get让开发者更直接方便的使用。 1.6 DOM对象转化成jQuery对象 $(参数)是一个多功能的方法 参数是一个DOM对象,jQuery方法会把这个DOM对象给包装成一个新的jQuery对象 通过$(dom)将普通的dom对象加工成jQuery对象之后,我们就可以调用jQuery的方法了 JavaScript代码 通过 getElementsByTagName获取到所有div节点的元素,结果是一个dom集合对象,不过这个对象是一个数组集合(3个div元素) 通过$(div)方法转化成jQuery对象,通过调用jQuery对象中的first与css方法查找第一个元素并且改变其颜色 2 jQuery选择器 2.1 id选择器 id选择器:一个用来查找的ID,即元素的id属性$( "#id" ) id选择器也是基本的选择器,jQuery内部使用JS函数document.getElementById()来处理ID的获取。 原生语法的支持总是非常高效的,所以在操作DOM的获取上,如果能采用id的话尽然考虑用这个选择器 id是唯一的,每个id值在一个页面中只能使用一次。如果多个元素分配了相同的id,将只匹配该id选择集合的第一个DOM元素 2.2 类选择器 通过class样式类名来获取节点$( ".class" ) 相对id选择器来说,效率相对会低一点,但是优势就是可以多选 同样的jQuery在实现上,对于类选择器,如果浏览器支持,jQuery使用JavaScript的原生getElementsByClassName()函数来实现的 右边实现一个原生getElementsByClassName()函数的实现代码与jQuery实现代码的比较 jQuery除了选择上的简单,而且没有再次使用循环处理 不难想到$(".SSS").css()方法内部肯定是带了一个隐式的循环处理,所以使用jQuery选择节点,不仅仅只是选择上的简单,同时还增加很多关联的便利操作 2.3 元素选择器 根据给定(HTML)标记名称选择所有的元素$( "element" ) 搜索指定元素标签名的所有节点,这个是一个合集的操作,原生方法getElementsByTagName() 第一组:通过getElementsByTagName得到页面所有的<div>var divs = document.getElementsByTagName('div'); divs是dom合集对象,通过循环给每一个合集中的<div>元素赋予新的border样式 第二组:同样的效果,$("p")选取所有的<p>元素,通过css方法直接赋予样式 2.4 全选择器(*选择器) 在CSS中,经常会在第一行写下这样一段样式 * {padding: 0; margin: 0;} 通配符意味着给所有的元素设置默认的边距。jQuery中我们也可以通过传递选择器来选中文档页面中的元素$( "*" ) 抛开jQuery,如果要获取文档中所有的元素,通过document.getElementsByTagName()中传递"*"同样可以获取到 id、class、tag都可以通过原生的方法获取到对应的节点,但还需考虑一个兼容性问题,这里顺便提及一下,比如 IE会将注释节点实现为元素,所以在IE中调用getElementsByTagName会包含注释节点,这个通常是不应该的 getElementById的参数在<=IE8不区分大小写 <=IE7中,表单元素中,如果表单A的name属性名用了另一个元素B的ID名并且A在B之前,那么getElementById会选中A <=IE8,浏览器不支持getElementsByClassName 幸好有jQuery的出现,让我们省了很多功夫 2.5 层级选择器 文档中的所有的节点之间都是有这样或者那样的关系 我们可以把节点之间的关系可以用传统的家族关系来描述,把文档树当作一个家谱,那么节点与节点直接就会存在父子,兄弟,祖孙的关系了。 选择器中的层级选择器就是用来处理这种关系 对比层级选择器的区别 层级选择器都有一个参考节点 后代选择器包含子选择器的选择的内容 一般兄弟选择器包含相邻兄弟选择的内容 相邻兄弟选择器和一般兄弟选择器所选择到的元素,必须在同一个父元素下 2.6 基本筛选选择器 筛选选择器很多都不是CSS的规范,而是jQuery自己为了开发者的便利延展出来的选择器 筛选选择器的用法与CSS中的伪元素相似 :eq(), :lt(), :gt(), :even, :odd 用来筛选他们前面的匹配表达式的集合元素,根据之前匹配的元素在进一步筛选,注意jQuery合集都是从0开始索引 gt是一个段落筛选,从指定索引的下一个开始,gt(1) 实际从2开始 2.7 内容筛选选择器 基本筛选选择器针对的都是元素DOM节点 如果我们要通过内容来过滤,jQuery也提供了一组内容筛选选择器 :contains与:has都有查找的意思,但是contains查找包含“指定文本”的元素,has查找包含“指定元素”的元素 如果:contains匹配的文本包含在元素的子元素中,同样认为是符合条件的。 :parent与:empty是相反的,两者所涉及的子元素,包括文本节点 2.8 可见性筛选选择器 元素可见性依赖于适用的样式 我们有几种方式隐藏一个元素 CSS display的值是none。 type="hidden"的表单元素。 宽度和高度都显式设置为0。 一个祖先元素是隐藏的,该元素是不会在页面上显示 CSS visibility的值是hidden CSS opacity的指是0 如果元素中占据文档中一定的空间,元素被认为是可见的。 可见元素的宽度或高度,是大于零。 元素的visibility: hidden 或 opacity: 0被认为是可见的,因为他们仍然占用空间布局 不在文档中的元素是被认为是不可见的,如果当他们被插入到文档中,jQuery没有办法知道他们是否是可见的,因为元素可见性依赖于适用的样式 2.9 属性筛选选择器 基于属性来定位一个元素 可只指定该元素的某个属性,这样只需使用该属性而不管它的值,这个元素都将被定位,也可以更加明确并定位在这些属性上使用特定值的元素 浏览器支持 [att=val]、[att]、[att|=val]、[att~=val] 属于CSS 2.1规范 [ns|attr]、[att^=val]、[att*=val]、[att$=val] 属于CSS3规范 [name!="value"] 属于jQuery 扩展的选择器 CSS选择器无论CSS2.1版本还是CSS3版本,IE7和IE8都支持,webkit、Gecko核心及Opera也都支持,只有IE6以下浏览器才不支持 在这么多属性选择器中[attr="value"]和[attr*="value"]是最实用的 [attr="value"]能帮我们定位不同类型的元素,特别是表单form元素的操作,比如说input[type="text"],input[type="checkbox"]等 [attr*="value"]能在网站中帮助我们匹配不同类型的文件 2.10 元素筛选选择器 子元素筛选选择器不常使用,其筛选规则比起其它的选择器稍微要复杂点 :first只匹配一个单独的元素,但:first-child可匹配多个:为每个父级元素匹配第一个子元素。相当于:nth-child(1) :last 只匹配一个单独的元素,:last-child 选择器可以匹配多个元素:为每个父级元素匹配最后一个子元素 如果子元素只有一个的话,:first-child与:last-child是同一个 :only-child匹配某个元素是父元素中唯一的子元素,就是说当前子元素是父元素中唯一的元素,则匹配 jQuery实现:nth-child(n)是严格来自CSS规范,所以n值是“索引”,也就是说,从1开始计数,:nth-child(index)从1开始的,而eq(index)是从0开始的 nth-child(n) 与:nth-last-child(n)的区别是前者从前往后计算,后者从后往前 2.11 表单元素选择器 jQuery中专门加入了表单选择器,从而能够极其方便地获取到某个类型的表单元素 除了input筛选选择器,几乎每个表单类别筛选器都对应一个input元素的type值 大部分表单类别筛选器可以使用属性筛选器替换 比如 $(':password') == $('[type=password]') 2.13 表单对象属性筛选选择器 附加在其他选择器的后面,主要功能是对所选择的表单元素进行筛选 选择器适用于复选框和单选框,对于下拉框元素, 使用 :selected 在某些浏览器中,:checked可能会错误选取到<option>,所以保险起见换用input:checked,确保只会选取<input> 2.14 特殊选择器this $(this)和this有什么区别呢? this是JavaScript中的关键字,指的是当前的上下文对象,简单的说就是方法/属性的所有者 下面例子中,imooc是一个对象,拥有name属性与getName方法,在getName中this指向了所属的对象imooc var imooc = { name:"慕课网", getName:function(){ //this,就是imooc对象 return this.name; } } imooc.getName(); //慕课网 this是动态的,这个上下文对象都是可以被动态改变的(可以通过call,apply等方法) 同样的在DOM中this就是指向了这个html元素对象,因为this就是DOM元素本身的一个引用 假如给页面一个P元素绑定一个事件: p.addEventListener('click',function(){ //this === p //以下两者的修改都是等价的 this.style.color = "red"; p.style.color = "red"; },false); 通过addEventListener绑定的事件回调中,this指向的是当前的dom对象,所以再次修改这样对象的样式,只需要通过this获取到引用即可 this.style.color = "red" 但是这样的操作其实还是很不方便的,这里面就要涉及一大堆的样式兼容,如果通过jQuery处理就会简单多了,我们只需要把this加工成jQuery对象 换成jQuery的做法: $('p').click(function(){ //把p元素转化成jQuery的对象 var $this= $(this) $this.css('color','red') }) 通过把$()方法传入当前的元素对象的引用this,把这个this加工成jQuery对象,我们就可以用jQuery提供的快捷方法直接处理样式了 总体: this,表示当前的上下文对象是一个html对象,可以调用html对象所拥有的属性和方法。 $(this),代表的上下文对象是一个jquery的上下文对象,可以调用jQuery的方法和属性值。 2.12 综合案例 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>jQuery标签切换效果</title> <link rel="stylesheet" href="imooc.css" type="text/css"> <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script> </head> <body> <!--代码部分begin--> <div id="menu"> <!--tag标题--> <div id="menu_female"> <h3>女装</h3> <div class="tag" style="display: block;"> <dl> <dd> <p>第一类</p> <a>1.衬衫</a> <a>2.T恤</a> <a>3.雪纺衫</a> <a>4.针织衫</a> <a>5.短外套</a> <a>6.卫衣</a> <a>7.小西裤</a> <a>8.风衣</a> <a>9.吊带背心</a> <a>10.连衣裙</a> <a name="setColor">11.蕾丝连衣裙</a> <a>12.复古连衣裙</a> <a>13.印花连衣裙</a> <a>14.真丝连衣裙</a> <a>更多</a> </dd> </dl> </div> <div class="tag_More" style="display:block"> <dl> <dd> <p>第二类</p> <a>1.背带裤</a> <a>2.哈伦裤</a> <a>3.牛仔裤</a> <a>4.休闲裤</a> <a>5.小脚裤</a> <a>6.西装裤</a> <a>7.打底裤</a> <a>8.阔脚裤</a> <a>9.短裤</a> <a>10.马甲/背心</a> <a>11.羽绒服</a> <a>12.棉服</a> <a>13.夹克</a> <a>14.POLO衫</a> <a>更多</a> </dd> </dl> </div> > </div> <div id="menu_con"> <h3>男装</h3> <div class="tag" style="display:block"> <dl> <dd> <p>第一类</p> <a>1.衬衫</a> <a>2.T恤</a> <a>3.牛仔裤</a> <a>4.休闲裤</a> <a>5.短裤</a> <a>6.针织衫</a> <a>7.西服</a> <a>8.西裤</a> <a>9.嘻哈裤</a> <a>10.西服套装</a> <a>11.马甲/背心</a> <a name="setColor">12.羽绒服</a> <a>13.棉服</a> <a>14.夹克</a> <p>更多</p> </dd> </dl> </div> <div class="tag_More" style="display:block"> <dl> <dd> <p>第二类</p> <a>1.衬衫</a> <a>2.T恤</a> <a>3.牛仔裤</a> <a name='setColor'>4.休闲裤</a> <a>5.短裤</a> <a>6.针织衫</a> <a>7.西服</a> <a>8.西裤</a> <a>9.嘻哈裤</a> <a>10.西服套装</a> <a>11.马甲/背心</a> <a>12.羽绒服</a> <a>13.棉服</a> <a>14.夹克</a> <p>更多</p> </dd> </dl> </div> > </div> </div> <script type="text/javascript"> //找到男装下第一类衣服中的第一个p元素,并改变颜色 //可以通过子类选择器 p:first-child 筛选出第一个p元素 $("#menu_con .tag p:first").css('color', '#9932CC'); </script> <script type="text/javascript"> //找到男装下第一类衣服把a元素从顺序1-4加上颜色 //可以通过基本筛选器lt,选择匹配集合中所有索引值小于给定index参数的元素 //注意了index是从0开始计算,所以选在1-4,为对应的index就是4 $("#menu_con .tag a:lt(4)").css('color', 'red'); </script> <script type="text/javascript"> //找到男装所有a元素中属性名name="setColor"的元素,并设置颜色 //这里用的属性选择器[attribute='value']选择指定属性是给定值的元素 $("#menu_con a[name='setColor']").css('color', 'blue'); </script> <script type="text/javascript"> //不分男女,选中第一类衣服中第9个a元素,并改变颜色 //这里用了nth-child 选择的他们所有父元素的第n个子元素 $("#menu .tag a:nth-child(10)").css('color', '#66CD00'); </script> <script type="text/javascript"> //找到女装下第一类衣服,把a元素中包含文字"更多"的节点,改变颜色 $("#menu_female .tag a:contains('更多')").css('color', '#C71585'); </script> </body> </html>

优秀的个人博客,低调大师

10分钟大数据Hadoop基础入门

前言 目前人工智能和大数据火热,使用的场景也越来越广,日常开发中前端同学也逐渐接触了更多与大数据相关的开发需求。因此对大数据知识也有必要进行一些学习理解。 基础概念 大数据的本质 一、数据的存储:分布式文件系统(分布式存储)二、数据的计算:分部署计算 基础知识 学习大数据需要具备Java知识基础及Linux知识基础 学习路线 (1)Java基础和Linux基础(2)Hadoop的学习:体系结构、原理、编程第一阶段:HDFS、MapReduce、HBase(NoSQL数据库)第二阶段:数据分析引擎 -> Hive、Pig 数据采集引擎 -> Sqoop、Flume第三阶段:HUE:Web管理工具 ZooKeeper:实现Hadoop的HAOozie:工作流引擎(3)Spark的学习 第一阶段:Scala编程语言 第二阶段:Spark Core

优秀的个人博客,低调大师

【从入门到放弃-PHP】foreach 引用的坑

背景描述 先看一段代码。 $arr = [ 'jack' => '20', 'tom' => '21', 'marry' => '54', 'less' => '23' ]; foreach ($arr as &$val) { echo $val; } foreach ($arr as $val) { echo $val; } print_r($arr); 想一下应该输出什么呢? 运行一下脚本,真实结果和你想的是否一致呢?在foreach中使用了引用后再次foreach发现$arr['less']的值变成了54,常规理解应该是23才对。 猜测可能是因为使用引用导致该值变为54 但本着知其然更要知其所以然 我们一起追一下php源码 是什么原因导致的 环境

优秀的个人博客,低调大师

爬虫入门之绘图matplotlib与词云(七)

1 绘制条形图 import matplotlib # 数据可视化 from matplotlib import pyplot as plt # 配置字体 matplotlib.rcParams["font.sans-serif"] = ["simhei"] # 黑体 matplotlib.rcParams["font.family"] = "sans-serif" ''' left, x轴 height, y轴 width=0.8 ,轴宽 ''' # .bar(x轴, y轴, label=u"标签名", color="颜色") plt.bar([1], [123], label="广州", color="r") plt.bar([2], [141], label=u"北京") plt.bar([3], [11], label=u"上海") plt.bar([4], [41], label=u"深圳") plt.bar([5], [181], label=u"香港") plt.legend() # 绘图 # plt.show() plt.savefig("1.jpg") # 保存图片 2 绘制智联招聘职位岗位数量图 import urllib.request import urllib.parse import re import matplotlib import matplotlib.pyplot as plt # 数据可视化 matplotlib.rcParams["font.sans-serif"] = ["simhei"] # 配置字体 matplotlib.rcParams["font.family"] = "sans-serif" header = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"} def getnumberbyname(searchname): searchname = {"kw": searchname} searchname = urllib.parse.urlencode(searchname) url = "http://sou.zhaopin.com/jobs/searchresult.ashx?jl=%E6%B7%B1%E5%9C%B3&" + searchname + "&p=1&isadv=0" print(url, '==========') req = urllib.request.Request(url, headers=header) pagesource = urllib.request.urlopen(req).read().decode('utf-8', 'ignore') restr = "<em>(\\d+)</em>" # 正则表达式,()只要括号内的数据 regex = re.compile(restr, re.IGNORECASE) mylist = regex.findall(pagesource) return mylist[0] # 岗位列表 pythonlist = ["python", "python 运维", "python 测试", "python 数据", "python web"] num = 0 for pystr in pythonlist: num += 1 print(pystr, eval(getnumberbyname(pystr))) # 绘制柱状图 plt.bar([num], eval(getnumberbyname(pystr)), label=pystr) plt.legend() # 绘制 plt.show() # 显示 3 词云 “词云”这个概念由美国西北大学新闻学副教授、新媒体专业主任里奇·戈登(Rich Gordon)提出。“词云”就是对网络文本中出现频率较高的“关键词”予以视觉上的突出,形成“关键词云层”或“关键词渲染”,从而过滤掉大量的文本信息,使浏览网页者只要一眼扫过文本就可以领略文本的主旨。 词频 分词 语句切割 import jieba mystr = "小姐姐,我看你挺能睡的,睡我还不好" wordsplitList = jieba.cut(mystr, cut_all=True) # 切割, 全部切割 print(wordsplitList) # 返回一个生成器对象 print('/'.join(wordsplitList)) wordsplitListforSearch = jieba.cut_for_search(mystr) # 按搜索方式切割 print(wordsplitListforSearch) print('/'.join(wordsplitListforSearch)) 制作python岗位需求词云 import wordcloud 导入词云 from wordcloud import STOPWORDS # 停止词 import jieba import numpy as np # 科学计算 import matplotlib # 数据可视化 from matplotlib import pyplot as plt from PIL import Image # 图片处理 # 读取文本 pythonInfo = open('pythonworkinfo.txt', 'r', encoding='utf-8', errors='ignore').read() # print(pythonInfo) # 切割 pythonCut = jieba.cut(pythonInfo, cut_all=True) pythonInfoList = ' '.join(pythonCut) # 返回一个生成器对象 print(pythonInfoList) backgroud = np.array(Image.open('pig.jpg')) # 将图片格式化成RBG数组 myCloudword = wordcloud.WordCloud(font_path='simkai.ttf', # 字体路径 width=400, height=200, mask=backgroud, # 字体颜色 scale=1, # 比例 max_words=200, # 最大字数 min_font_size=4, # 最小字体 stopwords=STOPWORDS, # 默认停止词 random_state=50, # 随机角度 background_color='black', # 背景颜色 max_font_size=100 # 最大字体 ).generate(pythonInfoList) #plt.imshow(myCloudword) #plt.show() 图片展示 plt.figimage(mywordCloud) #绘制图片 plt.imsave('python.png',mywordCloud) #保存图片 精简生成词云 import matplotlib.pyplot as plt from wordcloud import WordCloud import jieba text_from_file_with_apath = open('pythonworkinfo.txt',encoding='utf-8',errors='ignore').read() print(text_from_file_with_apath) wordlist_after_jieba = jieba.cut(text_from_file_with_apath, cut_all=True) wl_space_split = " ".join(wordlist_after_jieba) my_wordcloud = WordCloud().generate(wl_space_split) plt.imshow(my_wordcloud) plt.axis("off") plt.show() #注:碰到utf-8的编码问题时候,可以去源码wordcloud.py文件中新增路径,前提下好中文字体库simkai.ttf FONT_PATH = os.environ.get("FONT_PATH", os.path.join(os.path.dirname(__file__), "simkai.ttf")) 覆盖掉默认的DroidSansMono.ttf 4 Matplotlib 绘图 1 多个subplot # subplot.py import matplotlib.pyplot as plt import numpy as np data = np.arange(100, 201) plt.subplot(2, 1, 1) plt.plot(data) data2 = np.arange(200, 301) plt.subplot(2, 1, 2) plt.plot(data2) plt.show() 2 线形图 # plot.py import matplotlib.pyplot as plt plt.plot([1, 2, 3], [3, 6, 9], '-r') plt.plot([1, 2, 3], [2, 4, 9], ':g') plt.show() 这段代码说明如下: plot函数的第一个数组是横轴的值,第二个数组是纵轴的值,所以它们一个是直线,一个是折线; 最后一个参数是由两个字符构成的,分别是线条的样式和颜色。前者是红色的直线,后者是绿色的点线。 3 散点图 # scatter.py import matplotlib.pyplot as plt import numpy as np N = 20 plt.scatter(np.random.rand(N) * 100, np.random.rand(N) * 100, c='r', s=100, alpha=0.5) plt.scatter(np.random.rand(N) * 100, np.random.rand(N) * 100, c='g', s=200, alpha=0.5) plt.scatter(np.random.rand(N) * 100, np.random.rand(N) * 100, c='b', s=300, alpha=0.5) plt.show() 这段代码说明如下: 这幅图包含了三组数据,每组数据都包含了20个随机坐标的位置 参数c表示点的颜色,s是点的大小,alpha是透明度 4 饼状图 # pie.py import matplotlib.pyplot as plt import numpy as np labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] data = np.random.rand(7) * 100 plt.pie(data, labels=labels, autopct='%1.1f%%') plt.axis('equal') plt.legend() plt.show() 这段代码说明如下: data是一组包含7个数据的随机数值 图中的标签通过labels来指定 autopct指定了数值的精度格式 plt.axis('equal')设置了坐标轴大小一致 plt.legend()指明要绘制图例(见下图的右上角) 5 条形图 # bar.py import matplotlib.pyplot as plt import numpy as np N = 7 x = np.arange(N) data = np.random.randint(low=0, high=100, size=N) colors = np.random.rand(N * 3).reshape(N, -1) labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] plt.title("Weekday Data") plt.bar(x, data, alpha=0.8, color=colors, tick_label=labels) plt.show() 这段代码说明如下: 这幅图展示了一组包含7个随机数值的结果,每个数值是[0, 100]的随机数 它们的颜色也是通过随机数生成的。np.random.rand(N * 3).reshape(N, -1)表示先生成21(N x 3)个随机数,然后将它们组装成7行,那么每行就是三个数,这对应了颜色的三个组成部分。如果不理解这行代码,请先学习一下Python 机器学习库 NumPy 教程 title指定了图形的标题,labels指定了标签,alpha是透明度 6 直方图 # hist.py import matplotlib.pyplot as plt import numpy as np data = [np.random.randint(0, n, n) for n in [3000, 4000, 5000]] labels = ['3K', '4K', '5K'] bins = [0, 100, 500, 1000, 2000, 3000, 4000, 5000] plt.hist(data, bins=bins, label=labels) plt.legend() plt.show() 上面这段代码中,[np.random.randint(0, n, n) for n in [3000, 4000, 5000]]生成了包含了三个数组的数组,这其中: 第一个数组包含了3000个随机数,这些随机数的范围是 [0, 3000) 第二个数组包含了4000个随机数,这些随机数的范围是 [0, 4000) 第三个数组包含了5000个随机数,这些随机数的范围是 [0, 5000)

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册