Redis高可用架构

Redis高可用架构 前言 Redis是一个高性能的key-value数据库,现时越来越多企业与应用使用Redis作为缓存服务器。楼主是一枚JAVA后端程序员,也算是半个运维工程师了。在Linux服务器上搭建Redis,怎么可以不会呢?下面楼主就带着大家从0开始,依次搭建:Redis单机服务器 -> Redis主从复制 ->Redis-Sentinel高可用。逐步搭建出高可用的Redis缓存服务器。 搭建Redis 1. 下载并解压 首先从Redis官网下载Redis并解压,楼主使用的版本是4.0.2。依次执行如下命令: cd /opt wget http://download.redis.io/releases/redis-4.0.2.tar.gz tar -zcvf redis-4.0.2.tar.gz 如果没有安装gcc依赖包,则安装对应依赖包 yum install -y gcc-c++ tcl 2. 编译并安装 下载并解压完毕后,则对源码包进行编译安装,楼主的Redis安装路径为/usr/local/redis,同学们可以自行修改语句:make install PREFIX=你想要安装的路径 cd /opt/redis-4.0.2 make install PREFIX=/usr/local 复制Redis相关命令到/usr/sbin目录下,这样就可以直接执行这些命令,不用写全路径 cd /usr/local/redis/bin sudo cp redis-* /usr/sbin 3. 建立Redis配置文件 安装完成之后将 Redis 配置文件拷贝到系统配置目录/etc/下,redis.conf 是 Redis 的配置文件,redis.conf 在 Redis 源码目录,port默认 6379。 cp /usr/local/redis-4.0.2/redis.conf /etc/ Redis配置文件主要参数解析参考 daemonize no#redis进程是否以守护进程的方式运行,yes为是,no为否(不以守护进程的方式运行会占用一个终端) pidfile /var/run/redis.pid#指定redis进程的PID文件存放位置 port 6379#redis进程的端口号 bind 127.0.0.1#绑定的主机地址 timeout 300#客户端闲置多长时间后关闭连接,默认此参数为0即关闭此功能 loglevel verbose#redis日志级别,可用的级别有debug.verbose.notice.warning logfile stdout#log文件输出位置,如果进程以守护进程的方式运行,此处又将输出文件设置为stdout的话,就会将日志信息输出到/dev/null里面去了 databases 16#设置数据库的数量,默认为0可以使用select <dbid>命令在连接上指定数据库id save <seconds><changes>#指定在多少时间内刷新次数达到多少的时候会将数据同步到数据文件; rdbcompression yes#指定存储至本地数据库时是否压缩文件,默认为yes即启用存储; dbfilename dump.db#指定本地数据库文件名 dir ./#指定本地数据问就按存放位置; slaveof <masterip><masterport>#指定当本机为slave服务时,设置master服务的IP地址及端口,在redis启动的时候他会自动跟master进行数据同步 masterauth <master-password>#当master设置了密码保护时,slave服务连接master的密码; requirepass footbared#设置redis连接密码,如果配置了连接密码,客户端在连接redis是需要通过AUTH<password>命令提供密码,默认关闭 maxclients 128#设置同一时间最大客户连接数,默认无限制;redis可以同时连接的客户端数为redis程序可以打开的最大文件描述符,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息 maxmemory<bytes>#指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区 appendonly no#指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no appendfilename appendonly.aof#指定跟新日志文件名默认为appendonly.aof appendfsync everysec#指定更新日志的条件,有三个可选参数no:表示等操作系统进行数据缓存同步到磁盘(快),always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全), everysec:表示每秒同步一次(折衷,默认值); 3.1 设置后端启动: 由于Redis默认是前端启动,必须保持在当前的窗口中,如果使用ctrl + c退出,那么Redis也就退出,不建议使用。 ...

September 5, 2017 · 6 min · 1085 words · Jimmy

我眼中规范的开发流程

我眼中规范的开发流程 基于自建SVN的信息存储 存放开发文档 存放测试用例 存放三方对接文档 存放同事的学习记录与分享 存放会议纪要 基于git的开发流程 代码全部托管于git服务上 完善的分支规范,区分开发,测试,生产分支 基于gitflow的开发流程,区分feature,bugfix,hotfix等分支创建规则 完善的测试流程 产品出文档测试即开始编写测试用例 测试版本开发完成开始测试 使用bugout进行记录与跟踪bug 开发处理bug,在bugout上提交 测试再次测试直到通过 基于持续构建工具的构建流程 使用jenkin持续构建,单元测试,Sonar代码分析 每个项目至少3个分支,dev,master,release分支 测试在dev分支,预发布在master分支,线上使用release分支 dev分支自动提交构建 平台架构 分布式的微服务架构 保证单机宕机对整体服务没有影响,做到自动切换主备 统一开发环境与工具 后端开发统一Jetbrains全家桶 接口调试使用Postman 文档使用showdoc 代码管理使用git 统一使用邮件沟通 致谢:

July 22, 2017 · 1 min · 32 words · Jimmy

Spring Cloud 之actuator模块简介

Spring Cloud 之actuator模块简介 此模块提供监控与采集功能,通过在pom中引用此依赖,可以方便地使用其功能 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 原生端点 应用配置类:获取应用程序中加载的应用配置,环境变量,自动化配置报告等与SpringBoot应用密切相关的配置类信息 度量指标类:获取应用程序运行过程中用户监控的度量指标,比如内存信息,线程池信息,HTTP请求统计等 操作控制类:提供了对应用的关闭操作类功能 应用配置类 /autoconfig:该端点用来获取应用的自动化配置报告.包括条件匹配成功以及不成功的配置 positiveMatches中返回是条件匹配成功的自动化配置 negativeMatches中返回的是条件匹配不成功的自动化配置 /beans:该端点用来获取应用上下文中创建的所有Bean [ { "context":"application", "parent":null, "beans":[ { "bean":"helloApplication", "aliases":[ ], "scope":"singleton", "type":"com.jimersylee.hello.HelloApplication$$EnhancerBySpringCGLIB$$d3ebe421", "resource":"null", "dependencies":[ ] }, 每个Bean中都包含了下面这些信息 bean:Bean的名称 scope:Bean的作用域 type:Bean的Java类型 resource:class文件的具体路径 dependencies:依赖的Bean名称 /configprops:该端点用来获取应用中配置的属性信息报告,可以通过使用endpoints.configprops.enabled=false来关闭 env:该端点与/configprops不同,它用来获取应用所有可用的环境属性报告 { "profiles":[ ], "server.ports":{ "local.server.port":8080 }, "servletContextInitParams":{ }, "systemProperties":{ "java.runtime.name":"Java(TM) SE Runtime Environment", "awt.useSystemAAFontSettings":"gasp", "sun.boot.library.path":"/opt/jdk1.8.0_144/jre/lib/amd64", "java.vm.version":"25.144-b01", "maven.multiModuleProjectDirectory":"/home/jimersylee/projects/java/spring-cloud-action/hello", ... /mappings:该端点用来返回所有Spring MVC的控制器映射关系报告. ...

April 29, 2017 · 1 min · 179 words · Jimmy

Spring Cloud 入门

Spring Cloud 入门 Spring Cloud Config:配置管理工具 Spring Cloud Netflix:核心组件 Eureka:服务治理组件 Hystrix:容错管理组件 Ribbon:客户端负载均衡的服务调用组件 Feign:基于Ribbon和Hystrix的生命是服务调用组件 Zuul:网关组件 外部化配置组件 Spring Cloud Bus:事件,消息总线 Spring Cloud Cluster:针对Zookeeper,Redis,Hazelcast,Consul的选举算法和通用状态模式的实现 Spring Cloud CloudFoundry:与Pivatal Cloudfoundy的整合支持 Spring Cloud Consul:服务发现与配置管理工具 Spring Cloud Stream:通过Redis,RabbitMQ和Kafka实现的消费微服务,可以通过简单的声明式模型来发送和接收消息 Spring Cloud AWS:用于简化整合Amazon Web Service的组件 Spring Cloud Security:安全工具包,提供在Zuul代理中对OAuth2客户端请求的中继器 Spring Cloud Sleuth:Spring Cloud的应用分布式跟踪系统,可以完美整合Zipkin Spring Cloud Zookeeper:基于Zookeeper的服务发现与配置管理组件 Spring Cloud Starters:Spring Cloud的基础组件,它是基于Spring Boot风格项目的基础依赖模块 Spring Cloud CLI:用于在Groovy中快速创建Spring Cloud应用的Spring Boot CLI的插件

April 28, 2017 · 1 min · 57 words · Jimmy

<深入理解Java虚拟机>学习笔记-第三章

<深入理解Java虚拟机>学习笔记-第三章 项目地址: http://github.com/jimersylee/javaStudy 3.1概述 垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物,事实上,1960年诞生于MIT的Lisp蚕食第一门真正使用内存动态分配和垃圾收集技术的语言 GC的3件事情 那些内存需要回收 什么时候回收 如何回收 目前GC的技术已经相当成熟,为什么我们要了解 当需要排查各种内存溢出,内存泄露问题时 当垃圾收集成为系统达到更高并发量瓶颈时 3.2对象已死吗 Java堆中存在对象实例,垃圾收集器在对堆进行回收前,第一件事就是要确定哪些对象还"活着",哪些已经"死去" 3.2.1 引用计数算法 给对象中添加一个引用计数器:每当有一个地方引用它时,计数器加1;当引用失效时,计数器减1;任何时刻计数器为0的对象就是不可能再被使用的 引用计数算法(Reference Counting)的实现简单,判定效率也高,例如FlashPlayer,Python都使用引用计数算法了内存管理,但是Java虚拟机中没有选用引用计数算法来管理内存,其实最重要的原因是它很难解决对象之间相互循环引用的问题 testGC()方法,虽然两个对象已经不可能被访问,但是因为互相引用着,导致他们计数器都不为0,于是引用计数算法无法通知GC收集器来回收它们 GC日志中包含了6747K->416K(51200K),意味着虚拟机并没有因为这两个对象互相引用就不回收它们,这也从侧面说明虚拟机并不是通过引用计数算法来判断对象是否是存活的 3.2.2 可达性分析算法 在主流的商用程序语言(Java,C#,甚至古老的Lisp)的主流实现中,都是通过可达性分析(Reachability Analysis)来判定对象是否存活的.这个算法的基本思路就是通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链(用图论的话来说,就是从GC Root到这个对象不可达),则证明此对象是不可用的. 在Java语言中,可作为GC Roots的对象包括下面几种: 虚拟机栈(栈帧中的本地变量表)中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中JNI(Native方法)引用的对象 3.2.3 再谈引用 jdk1.2后,对引用的概念进行了扩充 强引用 类型Object obj=new Object();这类的,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象 软引用 软引用用来描述一些还有用但并非必需的对象.在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围内进行二次回收.如果这次回收还没有足够的内存,才会抛出内存溢出异常.在JDK1.2后,提供了SoftReference类来实现软引用. 弱引用 弱引用也是用来描述非必需对象.当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象.在JDK1.2后,提供了WeakReference类实现弱引用. 虚引用 虚引用也称为幽灵引用或者幻影引用.一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对象实例.为一个对象设置虚引用是为了能在这个对象被回收时能收到系统通知.在JDK1.2后,提供了PhantomReference类实现虚引用 3.2.4 生存还是死亡 即使在可达性分析算法中不可达的对象,也并非是"非死不可"的,要宣告一个对象死亡,至少经历两次标记过程 代码清单3-2 一次对象自我拯救的演示 /** * 此代码演示了两点 * 1.对象可以在被GC时自我拯救 * 2.这个自救机会只有一次 * * @author jimersylee */publicclassFinalizeEscapeGC { publicstatic FinalizeEscapeGC SAVE_HOOK =null; publicvoidisAlive() { System.out.println("yes,i am still alive"); } @Override protectedvoidfinalize() throws Throwable { super.finalize(); System.out.println("finalize method executed"); FinalizeEscapeGC.SAVE_HOOK =this; } publicstaticvoidmain(String[] args) throws Throwable { SAVE_HOOK =new FinalizeEscapeGC(); //对象第一次成功拯救自己演示//释放对象 SAVE_HOOK =null; System.gc(); //因为finalize方法优先度低,所以暂停0.5秒等待它 Thread.sleep(500); if (SAVE_HOOK !=null) { SAVE_HOOK.isAlive(); }else { System.out.println("no,i am dead :("); } //下面这段代码与上面的完全相同,但是这次自救却失败了 SAVE_HOOK =null; System.gc(); //因为finalize方法优先度低,所以暂停0.5秒等待它 Thread.sleep(500); if (SAVE_HOOK !=null) { SAVE_HOOK.isAlive(); }else { System.out.println("no,i am dead :("); } } } 3.2.5 回收方法区

August 20, 2016 · 1 min · 138 words · Jimmy

深入理解Java虚拟机 学习笔记-第二章

<深入理解Java虚拟机>学习笔记-第二章 项目地址: http://github.com/jimersylee/javaStudy 2.1 概述 内存管理领域 c,c++开发人员拥有最高权利,可以操作每一个对象,又需要维护每个对象的开始与销毁 java开发人员不需要为每一个对象写配对的delete/free代码,不容易出现内存泄露与内存溢出问题,不过,出现内存方面的问题,排查又是一项异常艰难的工作 2.2运行时数据区域 方法区Method Area 虚拟机栈VM Stack 本地方法栈Native Method Stack 堆 Heap 程序计数器 program Counter Register 2.2.1 程序计数器 java虚拟机通过线程轮换来分配处理器执行时间,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,为线程私有内存 2.2.2 Java虚拟机栈 与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同. 2.2.3 本地方法栈 本地方法栈为虚拟机使用到的Native方法服务 2.2.4 Java堆 Java堆(Heap)是Java虚拟机所管理的 内存中最大的一块,Java对是被所有线程共享的一块内存区域,在虚拟机启动时创建.此内存区域的唯一目的就是存放对象实例. Java堆是垃圾收集器管理的主要区域 现在的收集器基本采用分代收集算法 Java堆 新生代 老年代 更细致 Eden空间 From Survivor空间 To Survivor空间 Java堆可以处于物理上不连续的空间中,只要逻辑上连续即可,既可以实现成固定大小的,也可以是可扩展的,通过 -Xmx 和 -Xms控制,如果堆中没有足够的内存完成实例分配,则报 OutOfMemory 异常 2.2.5 方法区与Java堆一样,是各个线程共享的内存区域,用于存放已被虚拟机加载的类信息,敞亮,静态变量,即时编译器编译后的代码等数据 HotSpot上,方法区习惯性称为 永久代(Permanent Generation) 永久代有 -XX:MaxPermSize 上限 2.2.6 运行时常量池 运行时常量池(Runtime Constant Pool)是方法区的一部分.用于存放编译期生成的各种字面量和符号引用. 当常量池无法申请到内存报OutOfMemory异常 直接内存 JDK1.4中新加入NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用记性操作. 作用:提高性能 直接内存不收Java堆大小的限制,但是受本机总内存限制.除了设置 -Xmx等参数信息,也要注意直接内存 ...

August 11, 2016 · 2 min · 380 words · Jimmy

我的Linux桌面环境配置与必备软件

我的Linux桌面环境配置与必备软件 Idea 主题 Monokai_2 字体 YaHei Consolas Hybrid phpstorm sublime jdk 设置环境变量 vim /etc/profile JAVA_HOME=/opt/jdk1.8.0_141 PATH=$JAVA_HOME/bin:$PATH CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export JAVA_HOME export PATH export CLASSPATH source /etc/profile mysql workbench apt install mysql-workbench maven java包管理软件 shadowsocks,必备梯子 sudo apt install shadowsocks-qt5 tomcat redis-desktop-manager redis跨平台客户端 下载地址 配置lamp环境 安装xammp 到/opt 将bin路径加入path vim /etc/profile export $PTAH=$PATH:/opt/lampp/bin 这样就可以直接使用pecl来安装扩展了 pecl search redis pecl install redis nodejs npm apt install nodejs apt install npm 设置淘宝镜像 npm config set registry https://registry.npm.taobao.org 编译环境组件 sudo apt install build-essential Nginx 编译安装nginx 下载源码 tar zxvf nginx-x.tar cd nginx ./configure \ --prefix=/usr \ --sbin-path=/usr/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --pid-path=/var/run/nginx/nginx.pid \ --user=jimersylee \ --group=jimersylee \ --with-http_ssl_module \ --with-http_flv_module \ --with-http_gzip_static_module \ --http-log-path=/var/log/nginx/access.log \ --http-client-body-temp-path=/var/tmp/nginx/client \ --http-proxy-temp-path=/var/tmp/nginx/proxy \ --http-fastcgi-temp-path=/var/tmp/nginx/fcgi \ --with-http_stub_status_module

July 5, 2016 · 1 min · 114 words · Jimmy

为域名配置免费SSL证书

为域名配置免费SSL证书 Nginx配置ssl 腾讯云申请证书 阿里云域名解析验证证书 安装证书 下载证书 上传配置证书 #将本地的jenkins.jimersylee.com.zip上传至jimersylee.com这个机子上的/data/ssl_cert目录scp jenkins.jimersylee.com.zip root@jimersylee.com:/data/ssl_cert #登录主机解压文件 ssh root@jimersylee.com cd /data/ssl_cert unzip jenkins.jimersylee.com.zip #各种web服务器的证书就解压完成了,然后去配置Nginx [root@VM_77_132_centos ssl_cert]# tree . ├── Apache │ ├── 1_root_bundle.crt │ ├── 2_blog.jimersylee.com.crt │ ├── 2_jenkins.jimersylee.com.crt │ ├── 2_jimersylee.com.crt │ ├── 3_blog.jimersylee.com.key │ ├── 3_jenkins.jimersylee.com.key │ └── 3_jimersylee.com.key ├── blog.jimersylee.com.cert.zip ├── IIS │ ├── blog.jimersylee.com.pfx │ ├── jenkins.jimersylee.com.pfx │ ├── jimersylee.com.pfx │ └── keystorePass.txt ├── jenkins.jimersylee.com.zip ├── jimersylee.com.cert.zip ├── Nginx │ ├── 1_blog.jimersylee.com_bundle.crt │ ├── 1_jenkins.jimersylee.com_bundle.crt │ ├── 1_jimersylee.com_bundle.crt │ ├── 2_blog.jimersylee.com.key │ ├── 2_jenkins.jimersylee.com.key │ └── 2_jimersylee.com.key └── Tomcat ├── jenkins.jimersylee.com.jks └── keystorePass.txt nginx配置 ...

May 8, 2016 · 1 min · 160 words · Jimmy

机器学习实战-学习笔记之Logistic

项目地址:http://github.com/jimersylee/MachineLearningAction Logistic回归 本章内容 Sigmoid函数和Logistic回归分类器 最优化理论初步 梯度下降最优化算法 数据中的缺失项处理 最优化算法 比如如何在最短时间内从A点到B点?如何投入最少的工作量获得最大的收益 Logistic回归的一般过程 收集数据:采用任意方法收集数据 准备数据:由于需要进行距离计算,因此要求数据类型为数值型.另外,结构化数据格式则最佳 分析数据:采用任意方法对数据进行分析 训练算法:大部分时间将将用于测试,训练的目的是为了找到最佳的分类回归系数 测试算法:一旦训练步骤完成,分类将会很快 使用算法:首先,我们需要输入一些数据,并将其转换成对应的结构化数值;接着,基于训练好的回归系数就可以对这些数值进行简单的回归计算,判定他们属于那个类别了;在这之后,我们就可以在输出的类别上做一些其他分析工作 基于Logistic回归和Sigmoid函数的分类 优点:计算代价不高,易于理解和实现 缺点:容易欠拟合,分类精度可能不高 适用数据类型:数值型和标称型数据 我们想要的函数,能够接受所有的输入然后预测出类别. 使用单位阶跃函数 Sigmoid函数 f(z)=1/(1+e^-z) 训练算法:随机梯度上升 梯度上升算法在每次更新回归系数时都需要遍历整个数据集,当数据集增加时,计算复杂度就太高了. 改进方法是一次禁用一个样本点来更新回归系数,该方法成为随机梯度上升算法. 报错,未解决 weights = weights + alpha error dataMatIn[i] ValueError: operands could not be broadcast together with shapes (3,) (0,) 示例:从疝气病预测兵马的死亡率 本节使用Logistic回归来预测患有疝气病的马的存货问题 样本数据包含368个样本和28个特征 有30%的数据的值是缺失的.下面将介绍如何处理数据集中的数据确实问题,然后再用Logistic回归和随机梯度上升算法来预测病马的生死 准备数据 数据缺失是个麻烦的问题.如何解决 使用可用特征的均值来填补缺失值 使用特殊值来填补缺失值,如-1 忽略有缺失值的样本 使用相似样本的均值填补缺失值 使用另外的机器学习算法来预测缺失值 from numpyimport * import matplotlib.pyplotas plt defloadDataSet(): """ 载入测试数据 :return: """ dataMat = [] labelMat = [] fr = open('testSet.txt') for linein fr.readlines(): lineArr = line.strip().split() dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])# 为了计算方便,将X0设置为1.0 labelMat.append(int(lineArr[2])) return dataMat, labelMat defsigmoid(inX): """ Sigmoid函数,单位阶跃函数 :param inX: :return: """ return 1.0 / (1 + exp(-inX)) defgradAscent(dataMatIn, classLabels): """ 梯度上升算法 :param dataMatIn: 输入的数据矩阵,存放的100*3的矩阵 :param classLabels: 输入的数据类别矩阵 :return:返回训练好的迭代次数 """ # 转换为NumPy矩阵类型 dataMatrix = mat(dataMatIn) labelMat = mat(classLabels).transpose()# 初始为1*100的行向量,为了便于矩阵运算,使用transpose转置为列向量100*1 m, n = shape(dataMatrix)# 得到矩阵大小 alpha = 0.001# 目标移动的步长 maxCycles = 500# 最大迭代次数 weights = ones((n, 1)) for kin range(maxCycles): # 矩阵相乘,下面两行,计算真实类别与预测类别的差值,接下来就是按照该差值的方向调整回归系数 h = sigmoid(dataMatrix * weights)# 代表的不是一次乘积计算,事实上该运算包含了300次的乘积,变量h不是一个数,而是一个列向量,100 error = (labelMat - h) weights = weights + alpha * dataMatrix.transpose() * error return weights defstocGradAscent0(dataMatIn, classLabels): m, n = shape(dataMatIn) alpha = 0.01 weights = ones(n) for iin range(m): h = sigmoid(sum(dataMatIn[i] * weights))# h是向量 error = classLabels[i] - h# error是向量 weights = weights + alpha * error * dataMatIn[i] return weights defstocGradAscent1(dataMatIn, classLabels, numIter=150): """ 改进的随机梯度上升算法 :param dataMatIn: :param classLabels: :param numIter: :return: """ m, n = shape(dataMatIn) weights = ones(n) for jin range(numIter): dataIndex = range(m) for iin range(m): alpha = 4 / (1.0 + j + i) + 0.01# alpha每次迭代时需要调整 randIndex = int(random.uniform(0, len(dataIndex)))# 随机选取更新 h = sigmoid(sum(dataMatIn[randIndex] * weights)) error = classLabels[randIndex] - h weights = weights + alpha * error * dataMatIn[randIndex] del (dataIndex[randIndex]) return weights defplotBestFit(weights): """ 画出数据集和Logistic回归最佳拟合直线的函数 :param weights:系数 :return: """ weights = weights.getA() dataMat, labelMat = loadDataSet() dataArr = array(dataMat) n = shape(dataArr)[0] xcord1 = [] ycord1 = [] xcord2 = [] ycord2 = [] for iin range(n): if int(labelMat[i]) == 1: xcord1.append(dataArr[i, 1]) ycord1.append(dataArr[i, 2]) else: xcord2.append(dataArr[i, 1]) ycord2.append(dataArr[i, 2]) fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(xcord1, ycord1, s=30, c='red', marker='s') ax.scatter(xcord2, ycord2, s=30, c="green") x = arange(-3.0, 3.0, 0.1) y = (-weights[0] - weights[1] * x) / weights[2] ax.plot(x, y) plt.xlabel("X1") plt.ylabel("X2") plt.show() defclassifyVector(inX, weights): prob = sigmoid(sum(inX * weights)) if prob > 0.5: return 1.0 else: return 0.0 defcolicTest(): """ 疝气病马死亡分类测试 :return: """ frTrain = open('horseColicTraining.txt') frTest = open('horseColicTest.txt') trainingSet = [] trainingLabels = [] for linein frTrain.readlines(): currLine = line.strip().split('\t') lineArr = [] for iin range(21): lineArr.append(float(currLine[i])) trainingSet.append(lineArr) trainingLabels.append(float(currLine[i])) trainWeights = stocGradAscent1(array(trainingSet), trainingLabels, 500) errorCount = 0 numTestVec = 0.0 for linein frTest.readlines(): numTestVec += 1.0 currLine = line.strip().split('\t') lineArr = [] for iin range(21): lineArr.append(float(currLine[i])) if int(classifyVector(array(lineArr), trainWeights)) != int(currLine[21]): errorCount += 1 errorRate = (float(errorCount / numTestVec)) print "the error rate of this test is: %f" % errorRate return errorRate defmultiTest(): numTests = 10 errorSum = 0.0 for kin range(numTests): errorSum += colicTest() print "after %d iterations the average error rate is: %f" % (numTests, errorSum / float(numTests)) deftestCal(): dataArr, labelMat = loadDataSet() weights = gradAscent(dataArr, labelMat) print weights """ 得到一组回归系数,它确定了不同类别数据之间的分割线 [[ 4.12414349] [ 0.48007329] [-0.6168482 ]] """ deftestGradAscent(): """ 测试梯度上升算法,画图 :return: """ dataArr, labelMat = loadDataSet() weights = gradAscent(dataArr, labelMat) plotBestFit(weights) deftestStocGradAscent0(): """ 测试随机梯度上升算法,画图 :return: """ dataArr, labelMat = loadDataSet() weights = stocGradAscent0(dataArr, labelMat) plotBestFit(weights) deftestStocGradAscent1(): """ 测试随机梯度上升算法,画图 :return: """ dataArr, labelMat = loadDataSet() weights = stocGradAscent1(dataArr, labelMat) plotBestFit(weights) # testCal()#testGradAscent()# testStocGradAscent0() multiTest()

May 5, 2016 · 3 min · 553 words · Jimmy

机器学习实战 学习笔记之KNN-约会数据识别

<机器学习实战>学习笔记之KNN-约会数据识别 项目地址:http://github.com/jimersylee/MachineLearningAction # -*- coding: utf-8 -*-""" 约会数据kNN """ from numpyimport * import matplotlib.pyplotas plt import operator defclassify0(inX, dataSet, labels, k): dataSetSize = dataSet.shape[0] diffMat = tile(inX, (dataSetSize, 1)) - dataSet sqDiffMat = diffMat ** 2 sqDistances = sqDiffMat.sum(axis=1) distances = sqDistances ** 0.5 sortedDistIndicies = distances.argsort() classCount = {} for iin range(k): voteIlabel = labels[sortedDistIndicies[i]] classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1 sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True) return sortedClassCount[0][0] deffile2matrix(filename): fr = open(filename) numberOfLines = len(fr.readlines())# get the number of lines in the file returnMat = zeros((numberOfLines, 3))# prepare matrix to return classLabelVector = []# prepare labels return fr = open(filename) index = 0 for linein fr.readlines(): line = line.strip() listFromLine = line.split('\t') returnMat[index, :] = listFromLine[0:3] classLabelVector.append(int(listFromLine[-1])) index += 1 return returnMat, classLabelVector defautoNorm(dataSet): """ 归一化数值 因为计算距离的时候,差值最大的属性对计算结果的影响最大,如果对于此数据,我们认为权重一样,则需要将数据进行处理,将数值归一化 将属性的取值范围处理为0到1或者-1到1,使用下面的公式 newValue=(oldValue-min)/(max-min) :param dataSet:矩阵 :return:normDataSet:归一化后的矩阵 range:取值范围 minVals:最小值 """ minVals = dataSet.min(0)# 0代表第一列,取得第一列最小值 maxVals = dataSet.max(0)# 取得第一列最大值 ranges = maxVals - minVals# 可能的取值范围 normDataSet = zeros(shape(dataSet))# 创建新的返回矩阵 m = dataSet.shape[0] normDataSet = dataSet - tile(minVals, (m, 1)) normDataSet = normDataSet / tile(ranges, (m, 1))# element wise dividereturn normDataSet, ranges, minVals defdatingClassTest(): hoRatio = 0.50# hold out 10% datingDataMat, datingLabels = file2matrix('datingData/datingTestSet2.txt')# load data setfrom file normMat, ranges, minVals = autoNorm(datingDataMat) m = normMat.shape[0] numTestVecs = int(m * hoRatio) errorCount = 0.0 for iin range(numTestVecs): classifierResult = classify0(normMat[i, :], normMat[numTestVecs:m, :], datingLabels[numTestVecs:m], 3) print "the classifier came back with: %d, the real answer is: %d" % (classifierResult, datingLabels[i]) if (classifierResult != datingLabels[i]): errorCount += 1.0 print "the total error rate is: %f" % (errorCount / float(numTestVecs)) print errorCount defshowNormal(): """ 最基本散点图 没有样本类别标签的约会数据散点图.难以辨识途中的点究竟属于那个样本分类 :return: """ datingDataMat, datingLables = file2matrix('datingData/datingTestSet2.txt') fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2]) plt.xlabel("Percentage of Time Spent Playing Video Games") plt.ylabel("Liters of Icc Cream Consumed Per Week") plt.show() defshowLable(): """ 带有样本分类标签的约会数据散点图 虽然能够比较容易区分数据点丛书类别,但依然很那根据这张图得出结论性信息 :return: """ datingDataMat, datingLables = file2matrix('datingData/datingTestSet2.txt') fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(datingDataMat[:, 1], datingDataMat[:, 2], 15.0 * array(datingLables), 15.0 * array(datingLables)) ax.axis([-2, 25, -0.2, 2.0]) plt.xlabel("Percentage of Time Spent Playing Video Games") plt.ylabel("Liters of Icc Cream Consumed Per Week") plt.show() defshowClass(): """ 显示不同的分类 标识了三个不同的样本分类区域,具有不同爱好的人其类别区域也不同 每年赢得的飞行常客里程数与玩游戏视频游戏所占百分比的约会数据散点图 约会数据有三个分类标签,通过途中展示的两个特征更容易区分数据点从属的类别 :return: """ n = 1000# number of points to create xcord1 = []; ycord1 = [] xcord2 = []; ycord2 = [] xcord3 = []; ycord3 = [] markers = [] colors = [] fw = open('datingData/datingTestSet.txt', 'w') for iin range(n): [r0, r1] = random.standard_normal(2) myClass = random.uniform(0, 1) if (myClass <= 0.16): fFlyer = random.uniform(22000, 60000) tats = 3 + 1.6 * r1 markers.append(20) colors.append(2.1) classLabel = 1# 'didntLike' xcord1.append(fFlyer); ycord1.append(tats) elif ((myClass > 0.16)and (myClass <= 0.33)): fFlyer = 6000 * r0 + 70000 tats = 10 + 3 * r1 + 2 * r0 markers.append(20) colors.append(1.1) classLabel = 1# 'didntLike'if (tats < 0): tats = 0 if (fFlyer < 0): fFlyer = 0 xcord1.append(fFlyer); ycord1.append(tats) elif ((myClass > 0.33)and (myClass <= 0.66)): fFlyer = 5000 * r0 + 10000 tats = 3 + 2.8 * r1 markers.append(30) colors.append(1.1) classLabel = 2# 'smallDoses'if (tats < 0): tats = 0 if (fFlyer < 0): fFlyer = 0 xcord2.append(fFlyer); ycord2.append(tats) else: fFlyer = 10000 * r0 + 35000 tats = 10 + 2.0 * r1 markers.append(50) colors.append(0.1) classLabel = 3# 'largeDoses'if (tats < 0): tats = 0 if (fFlyer < 0): fFlyer = 0 xcord3.append(fFlyer); ycord3.append(tats) fw.close() fig = plt.figure() ax = fig.add_subplot(111) # ax.scatter(xcord,ycord, c=colors, s=markers) type1 = ax.scatter(xcord1, ycord1, s=20, c='red') type2 = ax.scatter(xcord2, ycord2, s=30, c='green') type3 = ax.scatter(xcord3, ycord3, s=50, c='blue') ax.legend([type1, type2, type3], ["Did Not Like", "Liked in Small Doses", "Liked in Large Doses"], loc=2) ax.axis([-5000, 100000, -2, 25]) plt.xlabel('Frequent Flyier Miles Earned Per Year') plt.ylabel('Percentage of Time Spent Playing Video Games') plt.show() showNormal() showLable() showClass() datingClassTest()

May 4, 2016 · 3 min · 602 words · Jimmy