3.总是值和标称值混合,有缺失数据集
@include_event_description_in=1,
协程
协程,又称微线程,纤程。英文名Coroutine。一句话表达怎样是协程,协程是一种用户态的轻量级线程。
协程拥有和谐的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到任哪里方,在切换回来的时候,复苏原先封存的寄存器上下文和栈。因而,协程能保留上三遍调用的事态(即具备片段情状的一个一定组合),每一回经过重入时,就一定于进入上五次调用的状态,换种说法,进入上四回离开时所处逻辑流的岗位。
子程序,或者叫做函数,在具备语言中都是层级调用,比如A调用B,B在执行进度中又调用了C,C执行已毕再次来到,B执行已毕重返,最后A执行完成。
所以子程序调用时经过栈完毕的,一个线程就是实施一个子主次。子程序调用总是一个输入,一回回到,调用顺序是肯定的。而协程的调用和子程序不一样。
协程看上去也是子程序,但推行进度中,在子程序内部可间歇,然后转而执行其余子程序,在适度的时候再重回来接着执行。
留神,在一个子顺序中暂停,去执行其他子程序,不是函数调用,有点类似CPU的刹车。比如子程序A、B:
-
def a():
-
print(“1”)
-
print(“2”)
-
print(“3”)
-
-
def b():
-
print(“x”)
-
print(“y”)
-
print(“z”)
一经由程序执行,在执行A的进度中,可以随时刹车,去执行B,B也恐怕在推行进度中暂停再去执行A,结果可能是:
-
1
-
2
-
x
-
y
-
3
-
z
不过在A中是没有调用B的,所以协程的调用比函数调用领悟起来要难一些。看起来A、B的实施有点像四线程,但协程的性状在是一个线程执行,和二十四线程比协程有啥优势?
最大的优势就是协程极高的施行效用。因为子程序切换不是线程切换,而是有先后自身控制,由此,没有线程切换的开发,和多线程比,线程数量更多,协程的特性优势就越明显。
第二大优势就是不须求三四线程的锁机制,因为唯有一个线程,也不设有同时写变量争辩,在协程中决定共享资源不加锁,只需求看清状态就好了,所以进行功用比三十二线程高很多。
因为协程是一个线程执行,那么怎么利用多核CPU呢?最简单易行的艺术是多进度加协程,既足够利用多核,有充裕发挥协程的高成效,可获得极高的特性。
协程的亮点:
无需线程上下文切换的开销。
不用原子操作锁定及一块的成本。原子操作(atomic
operation)是不必要synchronized,所谓原子操作是指不会被线程调度机制打断的操作;那种操作一旦起首,就径直运行到甘休,中间不会有别的context
switch(切换来另一个线程)。原子操作可以是一个手续,也得以是多少个操作步骤,但是其顺序是不得以被打乱,或者切割掉只进行部分。视作全部是原子性的中央。
福利切换控制流,简化编程模型。
高并发+高扩大性+低本钱。一个CPU协助上万的协程都小难题,所以很适合用于高并发处理。
协程的缺陷:
没辙选拔多核资源。协程的本来面目是个单线程,它无法而且将单个CPU的多个核用上,协程须求和进度协作才能运行在多CPU上。当然我们普通所编写的大举使用都不曾那个要求,除非是CPU密集型应用。
举行围堵(Blocking)操作(如IO时)会堵塞掉所有程序。
利用yield达成协程操作。
-
import time,queue
-
-
def consumer(name):
-
print(“–>starting eating xoxo”)
-
while True:
-
new_xo = yield
-
print(“%s is eating xoxo %s”%(name,new_xo))
-
-
def producer():
-
r = con.__next__()
-
r = con2.__next__()
-
n = 0
-
while n < 5:
-
n += 1
-
con.send(n)
-
con2.send(n)
-
print(“\033[32;1mproducer\033[0m is making xoxo
%s”%n) -
-
if
__name__ == “__main__”:
-
con = consumer(“c1”)
-
con2 = consumer(“c2”)
-
p = producer()
-
输出:
-
–>starting eating xoxo
-
–>starting eating xoxo
-
c1 is
eating xoxo 1 -
c2 is
eating xoxo 1 -
producer is making xoxo 1
-
c1 is
eating xoxo 2 -
c2 is
eating xoxo 2 -
producer is making xoxo 2
-
c1 is
eating xoxo 3 -
c2 is
eating xoxo 3 -
producer is making xoxo 3
-
c1 is
eating xoxo 4 -
c2 is
eating xoxo 4 -
producer is making xoxo 4
-
c1 is
eating xoxo 5 -
c2 is
eating xoxo 5 -
producer is making xoxo 5
协程的特性:
1、必须在唯有一个单线程里完结产出。
2、修改共享数据不需加锁。
3、用户程序里团结一心保持多少个控制流的左右文栈。
4、一个协程碰到IO操作自动切换来别的协程。
刚才yield已毕的无法算是合格的协程。
Python对协程的支撑是通过generator完毕的。在generator中,大家不但可以经过for循环来迭代,还足以不停调用next()函数获取由yield语句重返到下一个值。但是python的yield不但可以回到一个值,它可以接受调用者发出的参数。
ID3算法落成(纯标称值)
比方样本全体是标称值即离散值的话,会比较简单。
代码:
from math import log
from operator import itemgetter
def createDataSet(): #创建数据集
dataSet = [[1,1,'yes'],
[1,1,'yes'],
[1,0,'no'],
[0,1,'no'],
[0,1,'no']]
featname = ['no surfacing', 'flippers']
return dataSet,featname
def filetoDataSet(filename):
fr = open(filename,'r')
all_lines = fr.readlines()
featname = all_lines[0].strip().split(',')[1:-1]
print(featname)
dataSet = []
for line in all_lines[1:]:
line = line.strip()
lis = line.split(',')[1:]
dataSet.append(lis)
fr.close()
return dataSet,featname
def calcEnt(dataSet): #计算香农熵
numEntries = len(dataSet)
labelCounts = {}
for featVec in dataSet:
label = featVec[-1]
if label not in labelCounts.keys():
labelCounts[label] = 0
labelCounts[label] += 1
Ent = 0.0
for key in labelCounts.keys():
p_i = float(labelCounts[key]/numEntries)
Ent -= p_i * log(p_i,2)
return Ent
def splitDataSet(dataSet, axis, value): #划分数据集,找出第axis个属性为value的数据
returnSet = []
for featVec in dataSet:
if featVec[axis] == value:
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
return returnSet
def chooseBestFeat(dataSet):
numFeat = len(dataSet[0])-1
Entropy = calcEnt(dataSet)
DataSetlen = float(len(dataSet))
bestGain = 0.0
bestFeat = -1
for i in range(numFeat):
allvalue = [featVec[i] for featVec in dataSet]
specvalue = set(allvalue)
nowEntropy = 0.0
for v in specvalue:
Dv = splitDataSet(dataSet,i,v)
p = len(Dv)/DataSetlen
nowEntropy += p * calcEnt(Dv)
if Entropy - nowEntropy > bestGain:
bestGain = Entropy - nowEntropy
bestFeat = i
return bestFeat
def Vote(classList):
classdic = {}
for vote in classList:
if vote not in classdic.keys():
classdic[vote] = 0
classdic[vote] += 1
sortedclassDic = sorted(classdic.items(),key=itemgetter(1),reverse=True)
return sortedclassDic[0][0]
def createDecisionTree(dataSet,featnames):
featname = featnames[:] ################
classlist = [featvec[-1] for featvec in dataSet] #此节点的分类情况
if classlist.count(classlist[0]) == len(classlist): #全部属于一类
return classlist[0]
if len(dataSet[0]) == 1: #分完了,没有属性了
return Vote(classlist) #少数服从多数
# 选择一个最优特征进行划分
bestFeat = chooseBestFeat(dataSet)
bestFeatname = featname[bestFeat]
del(featname[bestFeat]) #防止下标不准
DecisionTree = {bestFeatname:{}}
# 创建分支,先找出所有属性值,即分支数
allvalue = [vec[bestFeat] for vec in dataSet]
specvalue = sorted(list(set(allvalue))) #使有一定顺序
for v in specvalue:
copyfeatname = featname[:]
DecisionTree[bestFeatname][v] = createDecisionTree(splitDataSet(dataSet,bestFeat,v),copyfeatname)
return DecisionTree
if __name__ == '__main__':
filename = "D:\\MLinAction\\Data\\西瓜2.0.txt"
DataSet,featname = filetoDataSet(filename)
#print(DataSet)
#print(featname)
Tree = createDecisionTree(DataSet,featname)
print(Tree)
View Code
解释一下多少个函数:
filetoDataSet(filename)
将文件中的数据整理成数据集
calcEnt(dataSet)
总括香农熵
splitDataSet(dataSet, axis, value)
划分数据集,选用出第axis个属性的取值为value的持有数据集,即D^v,并去掉第axis个特性,因为不需求了
chooseBestFeat(dataSet)
依据音讯增益,选拔一个最好的性质
Vote(classList)
若是属性用完,序列仍不均等,投票决定
createDecisionTree(dataSet,featnames)
递归创制决策树
用西瓜数据集2.0对算法举办测试,西瓜数据集见 西瓜数据集2.0,输出如下:
['色泽', '根蒂', '敲声', '纹理', '脐部', '触感']
{'纹理': {'清晰': {'根蒂': {'蜷缩': '是', '硬挺': '否', '稍蜷': {'色泽': {'青绿': '是', '乌黑': {'触感': {'硬滑': '是', '软粘': '否'}}}}}}, '稍糊': {'触感': {'硬滑': '否', '软粘': '是'}}, '模糊': '否'}}
为了可以反映决策树的优越性即决定方便,那里按照matplotlib模块编写可视化函数treePlot,对转移的决策树举行可视化,可视化结果如下:
出于数量太少,没有设置测试数据以表明其准确度,可是我前边会基于乳房棘球蚴病的例证进行准确度的测试的,上边进入下有些:
IO模式
对此一遍IO访问(以read为例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地方空间。当一个read操作暴发时,会经历五个级次:
1、等待数据准备(waiting for the data to be ready)。
2、将数据从基本拷贝到进度中(Copying the data from the kernel to the
process)。
幸亏因为那多少个等级,Linux系统暴发了上边四种网络情势的方案。
阻塞I/O(blocking IO)。
非阻塞I/O(nonblocking IO)
I/O多路复用(IO multiplexing)
信号驱动I/O(signal driven IO)
异步I/O(asynchronous IO)
是因为信号驱动I/O(signal driven
IO)在实际中并不常用,所以只剩余各种IO情势。
阻塞I/O(blocking IO)
在Linux中,默许景况下有所的Socket都是blocking,一个天下无双的读操作流程如下:
当用户进程调用了recvfrom,kernel就从头了IO的第二个阶段,准备数据。对于网络IO来说,很多时候数据在一方始还尚无到达。比如还尚无接到一个一体化的UDP包,这一个时候kernel就要等待丰富的多少来临。那么些进度必要拭目以待,也就是说数据被拷贝到操作系统内核的缓冲区中是索要一个经过的。而在用户进度那边,整个进度会被卡住。当kernel一向等到数量准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel重回结果,用户进度才解除block的动静,重新运行起来。
为此,blocking IO的特征就是在IO执行的八个阶段都被block了。
非阻塞I/O(nonblocking IO)
Linux下,可以透过安装Socket使其变为non-blocking。当对一个non-blocking
socket执行读操作时,流程如下:
当用户进度暴发read操作时,假若kernel中的数据还尚无备选好,那么它并不会block用户进程,而是马上回去一个error。从用户进度角度讲,它提倡一个read操作后,并不需求等待,而是马上就获得了一个结出。用户进程判断结果是一个error时,它就知道多少还尚未未雨绸缪好,于是它可以重新发送read操作。一旦kernel中的数据准备好了,并且又再一次接受了用户进度的system
call,那么它立时将数据拷贝到了用户内存,然后回到。
故此,nonblocking
IO的性状是用户进度必要持续的能动询问kernel数据好了并未。
I/O多路复用(IO multiplexing)
IO
multiplexing就是日常所说的select、poll、epoll,有些位置也称那种IO形式为event
driven
IO。select/epoll的利益就在于单个process就足以而且处理四个互联网连接的IO。它的基本原理就是select、poll、epoll那些function会不断的轮询所承担的所有socket,当某个socket有数据到达了,就通报用户进程。
当用户进度调用了select,那么所有进度会被block。而同时kernel会”监视”所有select负责的socket,当其他一个socket中的数据准备好了,select就会回到。那几个时候用户进度再调用read操作,将数据从kernel拷贝到用户进程。
为此,I/O多了复用的性状是经过一种体制一个经过能而且等待七个文本描述符,而那么些文件讲述符(套接字描述符)其中的肆意一个进入读就绪状态,select()函数就足以回来。
以此图和blocking
IO的图其实并从未太大的分化。事实上还更差一点,因为那里要求动用七个system
call(select和recvfrom),而blocking IO只调用了一个system
call(recvfrom)。可是用select的优势在于它可以同时处理多个connection。
实际在IO multiplexing
Model中,对于每一个socket一般都安装成为non-blocking。不过如上图所示整个用户的process其实是一贯被block的。只可是process是被select那几个函数block,而不是被socket
IO给block。
异步I/O(asynchronous IO)
Linux下的asynchronous IO其实用得很少。
用户进度发起read操作之后,离开就足以开始去做任何的事。而另一个方面,从kernel的角度,当它受到一个asynchronous
read之后,首先它会即时回去,所以不会对用户进度发生任何block。然后kernel会等待数据准备达成,然后将数据拷贝到用户内存,当那所有都成功之后,kernel会给用户进度发送一个signal,告诉它read操作完成了。
第三个算法参考了《机器学习实战》的半数以上代码,第二、多少个算法基于前面的落成举办模块的增添。
IF
NOT EXISTS(SELECT 1 FROM msdb.dbo.syscategories WHERE NAME=’DBA_MONITORING’ AND category_class=2)
I/O多路复用select、poll、epoll详解
select、poll、epoll都是IO多路复用的建制。I/O多路复用就是通过一种体制,一个经过可以监视八个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),可以布告顺序开展对应的读写操作。但select、poll、epoll本质上都是同步I/O,因为他俩都急需在读写事件就绪后自己承受举行读写,也就是说这些读写进程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的贯彻会担当把数量从基础拷贝到用户空间。
select
- select(rlist,wlist,xlist,timeout=None)
select函数监视的文件讲述符分3类,分别是writefds、readfds和execptfds。调用后select函数会阻塞,直到有描述符就绪(有数据可读、可写或有except)或者逾期(timeout指定等待时间,如若立即重临设为null即可)函数再次来到。当select函数重返后,能够经过遍历fdset,来找到就绪的讲述符。
select方今大概在颇具的平台上援助,其精良跨平台帮忙也是它的一个独到之处。select的一个欠缺在于单个进度可以监视的文本讲述符的数额存在最大范围,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的法门升高这一范围,但是如此也会促作用率的下跌。
poll
- int
poll(struct pollfd
*fds,unsigned,int nfds,int timeout)
select使用了多个位图来表示多个fdset的形式,poll使用一个pollfd的指针完毕。
-
struct
pollfd{ -
int fd; # 文件讲述符
-
short events; # 请求
-
short revents; # 响应
-
}
pollfd结构包含了要监视的event和爆发的event,不再使用select”参数-值”传递的艺术。同时pollfd并不曾最大数据限制(然而数量过多后品质也是会下降)。和select函数一样,poll重返后,必要轮询pollfd来得到就绪的讲述符。
从地点可以观看,select和poll都亟待在回到后经过遍历文件讲述符来获取已经就绪的socket。事实上,同时连接的豁达客户端在一整日或者唯有很少的处于就绪状态,因而随着监视的描述符数量的增加,其效用也会线性下跌。
epoll
epoll是在2.6基本中提议的,是事先的select和poll的增长版本。相对于select和poll来说,epoll越发灵敏,没有描述符限制。epoll使用一个文书讲述符管理多少个描述符,将用户关系的文书讲述符的轩然大波存放到根本的一个风云表中,那样在用户空间和水源空间的copy只需几回。
epoll操作进度须求四个接口。
-
int
epoll_create(int size); #
成立一个epoll的句柄,size用来报告内核监听的数码 -
int
epoll_ctl(int epfd,int op,int fd,struct epoll_event *event); -
int
epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout);
int epoll_create(int size);
创建一个epoll的句柄,size用来告诉内核监听的数量,那一个参数分化于select()中的第四个参数,给出最大监听的fd+1的值,参数size并不是限量了epoll所能监听的叙说符最大个数,只是对内核伊始分配内部数据结构的一个提议。
当创造好epoll句柄后,它就会占有一个fd值,在linux下假设查看/proc/进度id/fd/,是力所能及看到那一个fd的,所以在利用完epoll后,必须调用close()关闭,否则恐怕引致fd被耗尽。
int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
函数是对点名描述符fd执行op操作。
epfd:epoll_create()的再次来到值。
op:op操作,用多个宏来表示,添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分别拉长、删除和修改对fd的监听事件。
fd:需求监听的fd(文件讲述符)。
epoll_event:内核需求监听的对象。
int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int
timeout);
伺机epfd上的io事件,最多再次回到maxevents个事件。
参数events用来从基础得到事件的集纳,maxevents告之根本那些events有多大,这几个maxevents的值无法领先创造epoll_create()时的size,参数timeout是晚点时间(微秒,0会马上回去,-1将不确定)。该函数重返需要处理的风浪数量,如重回0表示已逾期。
2.一连值和标称值混合且无缺失数据集
概念表达
用户空间与基本空间
今昔操作系统都是运用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的主干是内核,独立于普通的应用程序,可以访问受保证的内存空间,也有访问底层硬件配备的富有权限。为了保证用户过程不可以直接操作内核(kernel),保险基础的平安,操作系统将虚拟空间划分为两部分,一部分为根本空间,一部分为用户空间。针对Linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供种种进程使用,称为用户空间。
经过切换
为了控制过程的施行,内核必须有力量挂起正在CPU上运行的长河,并回复原先挂起的某部进度的实践。那种行为被称之为进度切换。因而可以说,任何进度都是在操作系统内核的帮衬下运行的,是与基础紧密相关的。
从一个进度的运作转到另一个经过上运行,这几个进度中经过上边进度:
1、保存处理机上下文,包涵程序计数器和其他寄存器。
2、更新PCB信息。
3、把进程的PCB移入相应的队列,如就绪、在某事件阻塞等行列。
4、选用另一个进度执行,并更新其PCB。
5、更新内存管理的数据结构。
6、苏醒处理机上下文。
经过控制块(Processing Control
Block),是操作系统主旨中一种数据结构,主要代表经过情形。其功用是使一个在多道程序环境下无法独立运作的主次(含数据),成为一个能独立运转的要旨单位或与其他进度并发执行的经过。或者说,操作系统OS是基于PCB来对出现执行的长河展开控制和管理的。PCB经常是系统内存占用区中的一个老是存放区,它存放着操作系统用于描述过程景况及控制进度运行所需的任何消息。
进程的堵塞
正值执行的进度,由于期待的一些事件未发生,如请求系统资源战败、等待某种操作的姣好、新数据没有到达或无新职务履行等,则由系统活动执行阻塞(Block),使和谐由运行状态成为阻塞状态。可知,进度的阻隔是经过本身的一种积极行为,也因此唯有处于运行状态的长河(得到CPU),才能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的。
文件讲述符fd
文件讲述符(File
descriptor)是电脑科学中的一个术语,是一个用以表述指向文件的引用的抽象化概念。
文件讲述符在格局上是一个非负整数。实际上,它是一个索引值,指向内核为每一个经过所有限支撑的该进度打开文件的记录表。当程序打开一个存世文件或者制造一个新文件时,内核向经过再次回到一个文书讲述符。在先后设计中,一些部署底层的程序编制往往会围绕着公文讲述符展开。可是文件讲述符这一定义往往只适用于UNIX、Linux那样的操作系统。
缓存I/O
缓存I/O又被称作标准I/O,大部分文件系统的默许I/O操作都是缓存I/O。在Linux的缓存I/O机制中,操作系统会将I/O的数量缓存在文件系统的页缓存(page
cache)中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地方空间。
缓存I/O的缺点:
多少在传输进程中要求在应用程序地址空间和根本举行反复数码拷贝操作,那个数量拷贝操作所带来的CPU以及内存费用是非凡大的。
有一而再值的景色
有延续值的意况如 西瓜数据集3.0
一个属性有很三种取值,大家一定无法每个取值都做一个分层,这时候需求对连接属性举办离散化,有二种办法供选取,其中两种是:
1.对每一类其余数据集的连日值取平均值,再取种种的平均值的平均值作为划分点,将延续属性化为两类成为离散属性
2.C4.5施用的二分法,排序离散属性,取每多少个的当心作为划分点的候选点,计算以每个划分点划分数据集的音信增益,取最大的百般划分点将连接属性化为两类成为离散属性,用该属性进行划分的新闻增益就是刚刚统计的最大音讯增益。公式如下:
那边运用第二种,并在攻读前对连日属性进行离散化。增加拍卖的代码如下:
def splitDataSet_for_dec(dataSet, axis, value, small):
returnSet = []
for featVec in dataSet:
if (small and featVec[axis] <= value) or ((not small) and featVec[axis] > value):
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
return returnSet
def DataSetPredo(filename,decreteindex):
dataSet,featname = filetoDataSet(filename)
Entropy = calcEnt(dataSet)
DataSetlen = len(dataSet)
for index in decreteindex: #对每一个是连续值的属性下标
for i in range(DataSetlen):
dataSet[i][index] = float(dataSet[i][index])
allvalue = [vec[index] for vec in dataSet]
sortedallvalue = sorted(allvalue)
T = []
for i in range(len(allvalue)-1): #划分点集合
T.append(float(sortedallvalue[i]+sortedallvalue[i+1])/2.0)
bestGain = 0.0
bestpt = -1.0
for pt in T: #对每个划分点
nowent = 0.0
for small in range(2): #化为正类负类
Dt = splitDataSet_for_dec(dataSet, index, pt, small)
p = len(Dt) / float(DataSetlen)
nowent += p * calcEnt(Dt)
if Entropy - nowent > bestGain:
bestGain = Entropy-nowent
bestpt = pt
featname[index] = str(featname[index]+"<="+"%.3f"%bestpt)
for i in range(DataSetlen):
dataSet[i][index] = "是" if dataSet[i][index] <= bestpt else "否"
return dataSet,featname
第一是预处理函数DataSetPredo,对数据集提前离散化,然后再拓展学习,学习代码类似。输出的决策树如下:
@enabled=1,
一齐与异步的性质不一致
-
import gevent
-
-
def f1(pid):
-
gevent.sleep(0.5)
-
print(“F1 %s done”%pid)
-
-
def f2():
-
for i in
range(10): -
f1(i)
-
-
def f3():
-
threads = [gevent.spawn(f1,i)
for i in range(10)] -
gevent.joinall(threads)
-
-
print(“f2”)
-
f2()
-
print(“f3”)
-
f3()
-
输出:
-
f2
-
F1 0 done
-
F1 1 done
-
F1 2 done
-
F1 3 done
-
F1 4 done
-
F1 5 done
-
F1 6 done
-
F1 7 done
-
F1 8 done
-
F1 9 done
-
f3
-
F1 0 done
-
F1 4 done
-
F1 8 done
-
F1 7 done
-
F1 6 done
-
F1 5 done
-
F1 1 done
-
F1 3 done
-
F1 2 done
-
公海赌船网站,F1 9 done
上边程序的重大多数是将f1函数封装到格林let内部线程的gevent.spawn。起初化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall函数,后者阻塞当前流程,并执行所有给定的greenlet。执行流程只会在富有greenlet执行完后才会持续向下走。
ID3算法简介
音讯熵是新闻论中的一个重中之重概念,也叫“香农熵”,香农先生的事迹比较很四个人都听过,一个人创设了一门理论,牛的尤其。香农理论中一个很重大的特性就是”熵“,即”音讯内容的不确定性“,香农在拓展音讯的定量测算的时候,明确地把音讯量定义为随意不定性程度的削减。那就标明了她对信息的领会:音讯是用来压缩自由不定性的东西。或者公布为香农逆定义:新闻是满世界瞩目的加码。那也验证了决策树以熵作为划分选拔的襟怀标准的不利,即我们想更高速地从数量中获取越来越多音信,大家就相应急速回落不确定性,即缩减”熵“。
新闻熵定义为:
D表示数据集,连串总数为|Y|,pk代表D中第k类样本所占的百分比。依据其定义,Ent的值越小,信息纯度越高。Ent的范围是[0,log|Y|]
上面要选择某个属性进行私分,要挨个考虑每个属性,借使当前考虑属性a,a的取值有|V|种,那么我们愿意取a作为划分属性,划分到|V|个子节点后,所有子节点的音讯熵之和即划分后的新闻熵可以有很大的收缩,减小的最多的不胜属性就是我们选用的性能。
分割后的新闻熵定义为:
从而用属性a对样本集D举行分割的音信增益就是原本的音信熵减去划分后的新闻熵:
ID3算法就是这么每一趟选用一个特性对样本集举行分割,知道二种情景使这几个进度甘休:
(1)某个子节点样本全体属于一类
(2)属性都用完了,那时候要是实节点样本仍旧不雷同,那么只可以少数听从多数了
(图片源于互连网)
然后自己尝试用sa登录(sa已经被剥夺)了两回,可是本人只接受了一封邮件。特意查看了一晃sp_add_alert的法定文档,才领悟现身这几个缘故,是因为参数@delay_between_responses的值设置缘故,通过安装该值,可避防备在在长期内再也发送一些不要求的电子邮件。如上所示,一分钟内,固然不当日志里面出现了多量近乎的不当,也只会发送一封报警邮件。其实只是为了减小发送告警的功用,如果你想当错误日志里出现这几个级别的报警时,都不可以不发送告警邮件,可以将其值设置为0。可是有时,假设设置为0,你会吸纳多种的邮件。其实这么些小标题,只是因为原先尚未专门注意那些参数而已。存粹属于没有彻底驾驭那个成效罢了。
Python select
Python的select()方法间接调用操作系统的IO接口,它监控sockets、open
files、pipes(所有带fileno()方法的公文句柄)哪天变成readable和writeable或者通讯错误,select()使得同时监控多少个一而再变得不难,并且那比写一个长循环来等待和督察多客户端连接要急迅,因为select直接通过操作系统提供的C的网络接口举行操作,而不是通过Python的解释器。
注意:Using Python’s file objects with select() works for Unix, but is
not supported under Windows.
select_socket_server
-
__author__ = ‘Golden’
-
#!/usr/bin/env python3
-
# -*- coding:utf-8 -*-
-
-
import select,socket,sys,queue
-
-
server = socket.socket()
-
server.setblocking(0)
-
server_addr = (‘localhost’,6969)
-
print(‘starting up on %s port
%s’%server_addr) -
server.bind(server_addr)
-
server.listen(5)
-
-
# 监测自己,因为server本身也是个fd
-
inputs = [server,]
-
outputs = []
-
message_queues = {}
-
while
True: -
print(‘waiting for next event…’)
-
#
若是没有任何fd就绪,程序会一向不通在那里 -
readable,writeable,exeptional =
select.select(inputs,outputs,inputs) -
# 每个s就是一个socket
-
for s in
readable: -
#
上边server自己也作为一个fd放在了inputs列表里,传给了select,如若s是server代表server那个fd就绪了,即新的三番五次进来
-
if s is
server: -
# 接收那一个连接
-
conn,client_addr =
s.accept() -
print(‘new connection from’,client_addr)
-
conn.setblocking(0)
-
“””
-
为了不打断整个程序,不会立马在此间先河接到客户端发来的数码,把它放到inputs里,下五遍loop时,
- 那一个新连接就会被交给select去监听,即使这几个延续的客户端发来了数量,那么这么些一而再的fd在server端就会化为就绪的,
-
select就会把这一个数额重返到readable列表里,然后就足以loop
readable列表,取出那个连续,开头收取数据 -
“””
-
inputs.append(conn)
-
#
接收到客户端的数码后,不及时回到,暂存在队列里,未来发送 -
message_queues[conn] =
queue.Queue() -
#
s不是server那就只会是一个与客户端建立的总是的fd -
else:
-
# 接收客户端的数据
-
data = s.recv(1024)
-
if data:
-
print(‘收到来自【%s】的多少:’%s.getpeername()[0],data)
-
#
收到的数据先放入queue里,一会回来给客户端 -
message_queues[s].put(data)
-
if s not in outputs:
-
#
为了不影响处理与其他客户端的延续,那里不立刻回去数据给客户端 -
outputs.append(s)
-
#
假诺收不到data,代表客户端已断开 -
else:
-
print(‘客户端已断开…’,s)
-
if s in
outputs: -
# 清理已断开的一连
- outputs.remove(s)
- # 清理已断开的连日
- inputs.remove(s)
- # 清理已断开的连年
-
del
message_queues[s] -
for s in
writeable: -
try:
-
next_msg =
message_queues[s].get_nowait() -
except queue.Empty:
-
print(‘client
[%s]’%s.getpeername()[0],’queue is empty…’) -
outputs.remove(s)
-
else:
-
print(‘sending msg to
[%s]’%s.getpeername()[0],next_msg) -
s.send(next_msg.upper())
-
for s in
exeptional: -
print(‘handling exception for’,s.getpeername())
-
inputs.remove(s)
-
if s in
outputs: -
outputs.remove(s)
-
s.close()
-
del message_queues[s]
select_socket_client
-
__author__ = ‘Golden’
-
#!/usr/bin/env python3
-
# -*- coding:utf-8 -*-
-
-
import socket,sys
-
-
messages = [b’This is the message.’,
-
b’It will be sent’,
-
b’in parts.’,
-
]
-
-
server_address = (‘localhost’,6969)
-
# 创立一个TCP/IP连接
-
socks =
[socket.socket(socket.AF_INET,socket.SOCK_STREAM), -
socket.socket(socket.AF_INET,socket.SOCK_STREAM),
- socket.socket(socket.AF_INET,socket.SOCK_STREAM),]
-
print(‘connecting to %s port
%s’%server_address) -
for s
in socks: -
s.connect(server_address)
-
-
for
message in messages: -
# 发送数据
-
for s in
socks: -
print(‘%s:sending “%s”‘%(s.getsockname(),message))
-
s.send(message)
-
# 接收数据
-
for s in
socks: -
data = s.recv(1024)
-
print(‘%s:received “%s”‘%(s.getsockname(),data))
-
if not data:
-
print(sys.stderr,’closing
socket’,s.getsockname())
本文对表决树算法举行简要的下结论和梳理,并对闻名的裁决树算法ID3(Iterative
Dichotomiser
迭代二分器)进行落到实处,完毕采取Python语言,一句老梗,“人生苦短,我用Python”,Python确实能够省很多言语方面的事,从而得以让大家注意于难点和缓解难点的逻辑。
@delay_between_responses
=
] delay_between_responses
select、poll、epoll三者的界别
select
select最早于1983年面世在4.2BSD中,它通过一个select()系统调用来监视七个公文讲述符的数组,当select()再次回到后,该数组中原封不动的文本讲述符便会被基本修改标志位,使得进度可以拿走这一个文件讲述符从而举办持续的读写操作。
select近日大约在拥有的阳台上接济,其卓越跨平台支撑也是它的一个独到之处,事实上从后天总的来说,那也是它所剩不多的优点之一。
select的一个缺陷在于单个进度可以监视的公文讲述符的数目存在最大范围,在Linux上相似为1024,可是可以经过修改宏定义甚至重新编译内核格局升高这一限量。
其余,select()所有限支撑的积存多量文件描述符的数据结构,随着文件讲述符数量的增大,其复制的开销也线性增大。同时,由于互连网响应时间的延期使得多量TCP连接处于非活跃状态,但调用select()会对持有socket举行一次线性扫描,所以那也浪费了一定的成本。
poll
poll在1986年出生于System V Release
3,它和select在真相上尚无多大差异,可是poll没有最大文件讲述符数量的界定。
poll和select同样存在一个瑕疵就是,包罗大批量文件描述符的数组被完整复制与用户态和基本的地方空间之间,而不论是那几个文件讲述符是或不是妥善,它的成本随着文件讲述符数量的增多而线性增大。
除此以外,select()和poll()将就绪的文本讲述符告诉进程后,如果经过没有对其展开IO操作,那么下次调用select()和poll()的时候将重新告知这么些文件描述符,所以它们一般不会丢掉就绪的音信,那种艺术叫做水平触发(Level
Triggered)。
epoll
截止Linux
2.6才面世了由基础直接支持的完成情势,那就是epoll,它大概所有了事先所说的整整优点,被公认为Linux
2.6下质量最好的多路I/O就绪文告方法。
epoll可以同时支持水平触发和边缘触发(Edge
Triggered,只报告进度哪些文件讲述符刚刚变为就绪状态,它只说四遍,若是我们没有采用行动,那么它就不会再也告诉,这种办法叫做边缘触发),理论上边缘触发的特性要更高一些,但代码达成格外复杂。
epoll同样只报告那一个就绪的文本描述符,而且当我们调用epoll_wait()得到妥善文件讲述符时,再次来到的不是实在的描述符,而是一个代表就绪描述符数量的值,你只要求去epoll指定的一个数组中种种得到相应数据的公文讲述符即可,那里也应用了内存映射(mmap)技术,那样便彻底省掉了这个文件讲述符在系统调用时复制的费用。
另一个本色的修正在于epoll选取基于事件的服服帖帖公告方式。在select/poll中,进程唯有在调用一定的章程后,内核才对具备监视的文书讲述符举办描述,而epoll事先经过epoll_ctl()来注册一个文书描述符,一旦基于某个文件讲述符就绪时,内核会拔取类似callback的回调机制,飞速激活那一个文件描述符,当进度调用epoll_wait()时便得到关照。
决策树简介
决策树算法不用说我们应该都明白,是机械学习的一个满世界有名算法,由澳大哈利法克斯尽人皆知计算机数学家罗丝Quinlan揭橥。
决策树是一种监督学习的分类算法,目标是学习出一颗决策树,该树中间节点是数据特征,叶子节点是序列,实际分类时按照树的构造,一步一步依据近来多少特征取值选取进入哪一颗子树,直到走到叶子节点,叶子节点的种类就是此决策树对此数量的求学结果。下图就是一颗简单的决策树:
此决定树用来判断一个存有纹理,触感,密度的西瓜是不是是“好瓜”。
当有那样一个西瓜,纹理清晰,密度为0.333,触感硬滑,那么要你判定是还是不是是一个“好瓜”,那时假使由此决策树来判定,明显可以直接本着纹理->清晰->密度<=0.382->否,即此瓜不是“好瓜”,三次裁定就那样形成了。正因为决策树决策很便宜,并且准确率也较高,所以平日被用来做分类器,也是“机器学习十大算法”之一C4.5的大旨情维。
上学出一颗决策树主要考虑一个难题,即 依据数据集创设当前树应该接纳哪个种类特性作为树根,即划分标准?
考虑最好的场合,一早先拔取某个特征,就把数量集划分成功,即在该特征上取某个值的全是一类。
设想最坏的意况,不断选取特征,划分后的数额集总是一无可取,就二分类职务的话,总是有正类有负类,一贯到特征全部用完了,划分的数据集合依然有正有负,那时只好用投票法,正类多就选正类作为叶子,否则选负类。
为此得出了相似结论:
随着划分的进展,我们期望选取一个特性,使得子节点包涵的样本尽可能属于同一档次,即“纯度”越高越好。
据悉“纯度”的专业各异,有三种算法:
1.ID3算法(Iterative
Dichotomiser
迭代二分器),也是本文要贯彻的算法,基于音讯增益即音信熵来度量纯度
2.C4.5算法(Classifier
4.5),ID3 的后继算法,也是昆兰指出
3.CART算法(Classification
And Regression Tree),基于基尼指数度量纯度。
selectors
selectors模块可以兑现IO多路复用,它兼具按照平台选出最佳的IO多路机制,例如在windows上默许是select方式,而在linux上默许是epoll。常分为二种方式select、poll和epoll。
selector_socket_server:
-
__author__ = ‘Golden’
-
#!/usr/bin/env python3
-
# -*- coding:utf-8 -*-
-
-
import selectors,socket
-
-
sel = selectors.DefaultSelector()
-
-
def accept(sock,mask):
-
conn,addr = sock.accept()
-
print(‘accrpted’,conn,’form’,addr)
-
conn.setblocking(0)
-
sel.register(conn,selectors.EVENT_READ,read)
-
-
def read(conn,mask):
-
data = conn.recv(1024)
-
if
data: -
print(‘echoing’,repr(data),’to’,conn)
-
conn.send(data)
-
else:
-
print(‘closing’,conn)
-
sel.unregister(conn)
-
conn.close()
-
-
sock = socket.socket()
-
sock.bind((‘localhost’,6969))
-
sock.listen(100)
-
sock.setblocking(0)
-
sel.register(sock,selectors.EVENT_READ,accept)
-
-
while
True: -
events = sel.select()
-
for key,mask in events:
-
callback = key.data
-
callback(key.fileobj,mask)
据悉分化的数量,我完成了八个版本的ID3算法,复杂度逐步升级:
·
IO阻塞自动切换职分
-
from urllib import request
-
import gevent,time
-
from gevent import monkey
-
-
#
把当前先后的持有的id操作给单独的做上标记 -
monkey.patch_all()
-
def f(url):
-
print(“GET:%s”%url)
-
resp = request.urlopen(url)
-
data = resp.read()
-
f = open(“load.txt”,”wb”)
-
f.write(data)
-
f.close()
-
print(“%d bytes received from
%s.”%(len(data),url)) -
-
urls = [‘https://www.python.org/‘,
-
time_start = time.time()
-
for
url in urls: -
f(url)
-
print(“同步cost”,time.time() – time_start)
-
-
async_time_start = time.time()
-
gevent.joinall([
-
gevent.spawn(f,’https://www.python.org/‘),
-
gevent.spawn(f,’http://www.cnblogs.com/yinshoucheng-golden/‘),
-
gevent.spawn(f,’https://github.com/‘),
-
])
-
print(“异步cost”,time.time() –
async_time_start)
1.纯标称值无缺失数据集
@class=N’ALERT’,
事件驱动与异步IO
写服务器处理模型的顺序时,有弹指间二种模型:
(1)每收到一个呼吁,创设一个新的进程,来拍卖该请求。
(2)每收到一个呼吁,创设一个新的线程,来处理该请求。
(3)每收到一个伸手,放入一个风浪列表,让主程序通过非阻塞I/O格局来处理请求。
地点的二种办法,各有千秋。
首先种方法,由于创造新的历程,内存费用相比大。所以,会招致服务器质量相比较差,但贯彻比较不难。
其次种办法,由于要提到到线程的联手,有可能相会临死锁等题材。
其两种办法,在写应用程序代码时,逻辑比前边二种都复杂。
综合考虑各地点因素,一般普遍认为第三种艺术是一大半互连网服务器选用的点子。
在UI编程中,日常要对鼠标点击举办相应响应,首先怎么样得到鼠标点击呢?
格局一:创造一个线程,该线程一贯循环检测是还是不是有鼠标点击,那么这些格局有以下多少个毛病。
1、CPU资源浪费,可能鼠标点击的频率很是小,然而扫描线程如故会平素循环检测,那会招致众多的CPU资源浪费;倘诺扫描鼠标点击的接口是阻塞的吗?
2、假设是阻塞的,又会出现下边那样的标题。假如我们不仅要扫描鼠标点击,还要扫描键盘是还是不是按下,由于扫描鼠标时被堵塞了,那么可能永远不会去扫描键盘。
3、如若一个巡回需求扫描的装备相当多,那又会滋生响应时间的标题。
从而,这种措施越发糟糕。
格局二:事件驱动模型
当前多数的UI编程都是事件驱动模型。如很多UI平台都会提供onClick()事件,那几个事件就表示鼠标点击事件。事件驱动模型大体思路如下。
1、有一个轩然大波(音讯)队列。
2、鼠标按下时,往这么些行列中追加一个点击事件(音信)。
3、有一个循环往复,不断从队列取出事件。依据分裂的事件,调出分歧的函数,如onClick()、onKeyDown()等。
4、事件(音讯)一般都分别保存各自的处理函数指针,这样各样新闻都有独立的处理函数。
事件驱动编程是一种编程范式,那里先后的实践流由外部事件来支配。它的特征是富含一个事件循环,当外部事件爆发时行使回调机制来触发相应的处理。别的四个广大的编程范式是联合(单线程)以及三二十四线程编程。
相比单线程、三八线程以及事件驱动编程模型。下图表示随着时光的延迟,那三种格局下程序所做的行事。那几个程序有3个职分急需完毕,每个职责都在等候I/O操作时打断自身。阻塞在I/O操作上所消费的时光用红色框表示。
在单线程同步模型中,任务依据顺序执行。要是某个职分因为I/O而阻塞,其余具有的职务必须等待,直到它形成之后才能挨个执行别的操作。那种鲜明的施行顺序和串行化处理的一言一动可以看看,假若各义务之间并从未相互看重的关系,但各义务履行仍旧需求相互等待,就使得程序全体运行速度下跌了。
在三十二线程版本中,那3个任务分别在单身的线程中执行。那一个线程由操作系统来保管,在多处理器系统上可以并行处理,或者在单处理器系统上交替执行。那使得当某个线程阻塞在某个资源的同时其余线程得以继续执行。三八线程程序更为难以判定,因为这类程序不得不通过线程同步机制加锁、可重入函数、线程局地存储或者其他编制来拍卖线程安全难题,假如完成不当就会促成出现微妙且令人痛定思痛的BUG。
在事件驱动版本的主次中,3个职责交错执行,但依旧在一个独门的线程控制中。当处理I/O或其余等待操作时,注册一个回调到事件循环中,然后当I/O操作达成时继续执行。回调描述了该怎么处理某个事件。事件循环轮询所有的轩然大波,当事件来临时将它们分配给等待处管事人件的回调函数。那种方法让程序尽可能的可以实施而不须求用到额外的线程。事件驱动型程序比二十四线程程序更便于估量出作为,因为程序员不需求关怀线程安全题材。
在柏哲病数据集上的测试与表现
有了算法,我们本来想做一定的测试看一看算法的表现。那里自己选拔了威斯康辛女性宫颈息肉的数据。
数码总共有9列,每一列分别表示,以逗号分割
1 Sample
code number (病人ID)
2 Clump
Thickness 肿块厚度
3
Uniformity of Cell Size 细胞大小的均匀性
4
Uniformity of Cell Shape 细胞形状的均匀性
5
Marginal Adhesion 边缘粘
6 Single
Epithelial Cell Size 单上皮细胞的尺寸
7 Bare
Nuclei 裸核
8 Bland
Chromatin 乏味染色体
9 Normal
Nucleoli 正常核
10
Mitoses 有丝差距
11 Class:
2 for benign, 4 formalignant(恶性或良性分类)
[from
Toby]
共计700条左右的数目,选择最终80条作为测试集,前面作为磨练集,进行学习。
行使分类器的代码如下:
import treesID3 as id3
import treePlot as tpl
import pickle
def classify(Tree, featnames, X):
classLabel = "未知"
root = list(Tree.keys())[0]
firstGen = Tree[root]
featindex = featnames.index(root) #根节点的属性下标
for key in firstGen.keys(): #根属性的取值,取哪个就走往哪颗子树
if X[featindex] == key:
if type(firstGen[key]) == type({}):
classLabel = classify(firstGen[key],featnames,X)
else:
classLabel = firstGen[key]
return classLabel
def StoreTree(Tree,filename):
fw = open(filename,'wb')
pickle.dump(Tree,fw)
fw.close()
def ReadTree(filename):
fr = open(filename,'rb')
return pickle.load(fr)
if __name__ == '__main__':
filename = "D:\\MLinAction\\Data\\breastcancer.txt"
dataSet,featnames = id3.DataSetPredo(filename,[0,1,2,3,4,5,6,7,8])
Tree = id3.createDecisionTree(dataSet[:620],[1.0 for i in range(len(dataSet))],featnames)
tpl.createPlot(Tree)
storetree = "D:\\MLinAction\\Data\\decTree.dect"
StoreTree(Tree,storetree)
#Tree = ReadTree(storetree)
i = 1
cnt = 0
for lis in dataSet[620:]:
judge = classify(Tree,featnames,lis[:-1])
shouldbe = lis[-1]
if judge == shouldbe:
cnt += 1
print("Test %d was classified %s, it's class is %s %s" %(i,judge,shouldbe,"=====" if judge==shouldbe else ""))
i += 1
print("The Tree's Accuracy is %.3f" % (cnt / float(i)))
教练出的决策树如下:
末尾的正确率可以见到:
正确率约为96%左右,算是不差的分类器了。
本人的乳房神经纤维瘤数据见:http://7xt9qk.com2.z0.glb.clouddn.com/breastcancer.txt
迄今截至,决策树算法ID3的兑现得了,下边考虑基于基尼指数和消息增益率举行私分接纳,以及考虑已毕剪枝进程,因为我们得以看出上面陶冶出的决策树还留存敬重重冗余分支,是因为完成进度中,由于数据量太大,每个分支都不完全纯净,所以会创设往下的道岔,可是分支投票的结果又是一模一样的,而且数据量再大,特征数再多的话,决策树会万分大万分复杂,所以剪枝一般是必做的一步。剪枝分为先剪枝和后剪枝,如若细说的话可以写很多了。
此文亦可知:这里
参考资料:《机器学习》《机器学习实战》通过本次实战也发觉了这两本书中的一些不当之处。
lz初学机器学习不久,如有错漏之处请多担待提议依然各位有啥想法或意见欢迎评论去告诉自己:)
·
Gevent
Gevent是一个第三方库,可以轻松提供gevent已毕产出同步或异步编程,在gevent中用到的第一情势是Greenlet,它是以C伸张模块方式接入Python的轻量级协程。格林let全体运转在主程序操作系统进度的其中,但它们被同盟式地调度。
-
import gevent
-
-
def foo():
-
print(“Running in foo”)
-
gevent.sleep()
-
print(“Explicit contenxt switch to foo agin”)
-
-
def bar():
-
print(“Explicit context to bar”)
-
gevent.sleep(1)
-
print(“Implict context switch back to bar”)
-
-
def func3():
-
print(“running func3”)
-
gevent.sleep(0)
-
print(“running func3 again”)
-
-
gevent.joinall([
-
gevent.spawn(foo),
-
gevent.spawn(bar),
-
gevent.spawn(func3),
-
])
-
输出:
-
Running in foo
-
Explicit context to bar
-
running func3
-
Explicit contenxt switch to foo agin
-
running func3 again
-
Implict context switch back to bar
有缺失值的景况
多少有缺失值是普遍的场合,大家糟糕直接丢掉这几个多少,因为这么会损失大量数据,不划算,不过缺失值大家也不可以断定它的取值。怎么做呢,办法如故有的。
考虑四个难点:
1.有缺失值时怎么着开展剪切选用
2.已选用划分属性,有缺失值的样本划不分开,如何分割?
问题1:有缺失值时如何开展私分选择**
着力思想是拓展最优属性接纳时,先只考虑无缺失值样本,然后再乘以相应比例,拿到在任何样本集上的大概意况。连带考虑到首个难点的话,考虑给每一个样书一个权重,此时种种样本不再总是被看成一个独自样本,那样有利于首个难点的解决:即若样本在属性a上的值缺失,那么将其看做是所有值都取,只不过取每个值的权重不平等,每个值的权重参考该值在无缺失值样本中的比例,不难地说,比如在无缺失值样本集中,属性a取去八个值1和2,并且取1的权重和占全体权重和1/3,而取2的权重和占2/3,那么依据该属性对样本集举办剪切时,碰到该属性上有缺失值的范本,那么大家觉得该样本取值2的可能性更大,于是将该样本的权重乘以2/3归到取值为2的范本集中继续展开私分构造决策树,而乘1/3划到取值为1的样书集中继续协会。不亮堂自己说了解没有。
公式如下:
其中,D~表示数据集D在属性a上无缺失值的样书,根据它来判断a属性的优劣,rho(即‘lou’)表示属性a的无缺失值样本占所有样本的比例,p~_k表示无缺失值样本中第k类所占的比例,r~_v表示无缺失值样本在属性a上取值为v的范本所占的百分比。
在分割样本时,如果有缺失值,则将样本划分到所有子节点,在属性a取值v的子节点上的权重为r~_v
* 原来的权重。
更详尽的解读参考《机器学习》P86-87。
据悉权重法修改后的ID3算法完毕如下:
from math import log
from operator import itemgetter
def filetoDataSet(filename):
fr = open(filename,'r')
all_lines = fr.readlines()
featname = all_lines[0].strip().split(',')[1:-1]
dataSet = []
for line in all_lines[1:]:
line = line.strip()
lis = line.split(',')[1:]
if lis[-1] == '2':
lis[-1] = '良'
else:
lis[-1] = '恶'
dataSet.append(lis)
fr.close()
return dataSet,featname
def calcEnt(dataSet, weight): #计算权重香农熵
labelCounts = {}
i = 0
for featVec in dataSet:
label = featVec[-1]
if label not in labelCounts.keys():
labelCounts[label] = 0
labelCounts[label] += weight[i]
i += 1
Ent = 0.0
for key in labelCounts.keys():
p_i = float(labelCounts[key]/sum(weight))
Ent -= p_i * log(p_i,2)
return Ent
def splitDataSet(dataSet, weight, axis, value, countmissvalue): #划分数据集,找出第axis个属性为value的数据
returnSet = []
returnweight = []
i = 0
for featVec in dataSet:
if featVec[axis] == '?' and (not countmissvalue):
continue
if countmissvalue and featVec[axis] == '?':
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
if featVec[axis] == value:
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
returnweight.append(weight[i])
i += 1
return returnSet,returnweight
def splitDataSet_for_dec(dataSet, axis, value, small, countmissvalue):
returnSet = []
for featVec in dataSet:
if featVec[axis] == '?' and (not countmissvalue):
continue
if countmissvalue and featVec[axis] == '?':
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
if (small and featVec[axis] <= value) or ((not small) and featVec[axis] > value):
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
return returnSet
def DataSetPredo(filename,decreteindex): #首先运行,权重不变为1
dataSet,featname = filetoDataSet(filename)
DataSetlen = len(dataSet)
Entropy = calcEnt(dataSet,[1 for i in range(DataSetlen)])
for index in decreteindex: #对每一个是连续值的属性下标
UnmissDatalen = 0
for i in range(DataSetlen): #字符串转浮点数
if dataSet[i][index] != '?':
UnmissDatalen += 1
dataSet[i][index] = int(dataSet[i][index])
allvalue = [vec[index] for vec in dataSet if vec[index] != '?']
sortedallvalue = sorted(allvalue)
T = []
for i in range(len(allvalue)-1): #划分点集合
T.append(int(sortedallvalue[i]+sortedallvalue[i+1])/2.0)
bestGain = 0.0
bestpt = -1.0
for pt in T: #对每个划分点
nowent = 0.0
for small in range(2): #化为正类(1)负类(0)
Dt = splitDataSet_for_dec(dataSet, index, pt, small, False)
p = len(Dt) / float(UnmissDatalen)
nowent += p * calcEnt(Dt,[1.0 for i in range(len(Dt))])
if Entropy - nowent > bestGain:
bestGain = Entropy-nowent
bestpt = pt
featname[index] = str(featname[index]+"<="+"%d"%bestpt)
for i in range(DataSetlen):
if dataSet[i][index] != '?':
dataSet[i][index] = "是" if dataSet[i][index] <= bestpt else "否"
return dataSet,featname
def getUnmissDataSet(dataSet, weight, axis):
returnSet = []
returnweight = []
tag = []
i = 0
for featVec in dataSet:
if featVec[axis] == '?':
tag.append(i)
else:
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
i += 1
for i in range(len(weight)):
if i not in tag:
returnweight.append(weight[i])
return returnSet,returnweight
def printlis(lis):
for li in lis:
print(li)
def chooseBestFeat(dataSet,weight,featname):
numFeat = len(dataSet[0])-1
DataSetWeight = sum(weight)
bestGain = 0.0
bestFeat = -1
for i in range(numFeat):
UnmissDataSet,Unmissweight = getUnmissDataSet(dataSet, weight, i) #无缺失值数据集及其权重
Entropy = calcEnt(UnmissDataSet,Unmissweight) #Ent(D~)
allvalue = [featVec[i] for featVec in dataSet if featVec[i] != '?']
UnmissSumWeight = sum(Unmissweight)
lou = UnmissSumWeight / DataSetWeight #lou
specvalue = set(allvalue)
nowEntropy = 0.0
for v in specvalue: #该属性的几种取值
Dv,weightVec_v = splitDataSet(dataSet,Unmissweight,i,v,False) #返回 此属性为v的所有样本 以及 每个样本的权重
p = sum(weightVec_v) / UnmissSumWeight #r~_v = D~_v / D~
nowEntropy += p * calcEnt(Dv,weightVec_v)
if lou*(Entropy - nowEntropy) > bestGain:
bestGain = Entropy - nowEntropy
bestFeat = i
return bestFeat
def Vote(classList,weight):
classdic = {}
i = 0
for vote in classList:
if vote not in classdic.keys():
classdic[vote] = 0
classdic[vote] += weight[i]
i += 1
sortedclassDic = sorted(classdic.items(),key=itemgetter(1),reverse=True)
return sortedclassDic[0][0]
def splitDataSet_adjustWeight(dataSet,weight,axis,value,r_v):
returnSet = []
returnweight = []
i = 0
for featVec in dataSet:
if featVec[axis] == '?':
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
returnweight.append(weight[i] * r_v)
elif featVec[axis] == value:
retVec = featVec[:axis]
retVec.extend(featVec[axis+1:])
returnSet.append(retVec)
returnweight.append(weight[i])
i += 1
return returnSet,returnweight
def createDecisionTree(dataSet,weight,featnames):
featname = featnames[:] ################
classlist = [featvec[-1] for featvec in dataSet] #此节点的分类情况
if classlist.count(classlist[0]) == len(classlist): #全部属于一类
return classlist[0]
if len(dataSet[0]) == 1: #分完了,没有属性了
return Vote(classlist,weight) #少数服从多数
# 选择一个最优特征进行划分
bestFeat = chooseBestFeat(dataSet,weight,featname)
bestFeatname = featname[bestFeat]
del(featname[bestFeat]) #防止下标不准
DecisionTree = {bestFeatname:{}}
# 创建分支,先找出所有属性值,即分支数
allvalue = [vec[bestFeat] for vec in dataSet if vec[bestFeat] != '?']
specvalue = sorted(list(set(allvalue))) #使有一定顺序
UnmissDataSet,Unmissweight = getUnmissDataSet(dataSet, weight, bestFeat) #无缺失值数据集及其权重
UnmissSumWeight = sum(Unmissweight) # D~
for v in specvalue:
copyfeatname = featname[:]
Dv,weightVec_v = splitDataSet(dataSet,Unmissweight,bestFeat,v,False) #返回 此属性为v的所有样本 以及 每个样本的权重
r_v = sum(weightVec_v) / UnmissSumWeight #r~_v = D~_v / D~
sondataSet,sonweight = splitDataSet_adjustWeight(dataSet,weight,bestFeat,v,r_v)
DecisionTree[bestFeatname][v] = createDecisionTree(sondataSet,sonweight,copyfeatname)
return DecisionTree
if __name__ == '__main__':
filename = "D:\\MLinAction\\Data\\breastcancer.txt"
DataSet,featname = DataSetPredo(filename,[0,1,2,3,4,5,6,7,8])
Tree = createDecisionTree(DataSet,[1.0 for i in range(len(DataSet))],featname)
print(Tree)
View Code
有缺失值的图景如 西瓜数据集2.0alpha
试验结果:
透过gevent完成单线程下的多socket并发
server side
-
import sys,socket,time,gevent
-
-
from gevent import socket,monkey
-
monkey.patch_all()
-
-
def server(port):
-
s = socket.socket()
-
s.bind((“0.0.0.0”,port))
-
s.listen(500)
-
while True:
-
cli,addr = s.accept()
-
gevent.spawn(handle_request,cli)
-
-
def handle_request(conn):
-
try:
-
while True:
-
data = conn.recv(1024)
-
print(“recv:”,data)
-
if not data:
-
conn.shutdown(socket.SHUT_WR)
-
conn.send(data)
-
except Exception as ex:
-
print(ex)
-
finally:
-
conn.close()
-
-
if
__name__ == “__main__”:
- server(6969)
client side
-
import socket
-
-
HOST = “localhost”
-
PORT = 6969
-
s =
socket.socket(socket.AF_INET,socket.SOCK_STREAM) -
s.connect((HOST,PORT))
-
while
True: -
msg = bytes(input(“>>:”),encoding=”utf8″)
-
s.sendall(msg)
-
data = s.recv(1024)
-
# print(data)
-
print(“Received”,repr(data))
-
-
s.close()
socket并发
-
import socket,threading
-
-
def sock_conn():
-
client = socket.socket()
-
client.connect((“localhost”,6969))
-
count = 0
-
-
while True:
-
client.send((“hello %s”%count).encode(“utf-8”))
-
data = client.recv(1024)
-
print(“%s from
server:%s”%(threading.get_ident(),data.decode())) -
count += 1
-
client.close()
-
-
for i
in range(100): -
t =
threading.Thread(target=sock_conn) -
t.start()
GO
总结
blocking和non-blocking的区别
调用blocking IO会平素block,直到对应的进度操作落成。而non-blocking
IO在kernel还在备选数据的场地下就会立马回到。
synchronous IO和asynchronous IO的区别
在认证synchronous IO和asynchronous
IO的分别此前,须要先提交两者的概念。POSIX的概念:
synchronous IO会导致请求进度被打断,直到该输I/O操作完毕。
asynchronous IO不会导致请求进度被堵塞。
双面的区分就在于synchronous IO做”IO
operation”的时候会将process阻塞。根据这几个概念从前所述的blocking
IO、non-blocking IO、IO multiplexing都属于synchronous IO。
有人认为non-blocking
IO并没有被block,那里是格外简单误解的地方。定义中所指的”IO
operation”是指真实的IO操作,就是例证中的recvfrom那个system
call。non-blocking IO在执行recvfrom那些system
call的时候,如若kernel的数据没有未雨绸缪好,那时候不会block进程。可是当kernel中数量准备好的时候,recvfrom会将数据从kernel拷贝到用户内存中,这一个时候经过是被block了,那段时间内经过是被block的。
而asynchronous
IO则差距,当进度发起IO操作之后,就直接回到再也不理睬了,直到kernel发送一个信号,告诉进程说IO完毕。在这一切经过中经过完全没有被block。
逐一IO model的比较如下图:
由此地方的图纸可以窥见non-blocking IO和asynchronous
IO的区分依旧很扎眼的。在non-blocking
IO中,即便经过半数以上时日都不会被block,不过它仍然需要进度积极的check,并且当数码准备完毕之后,也急需进程积极的再一次调用recvfrom来讲数据拷贝到用户内存。而asynchronous
IO则完全两样,它就像用户进度将全部IO操作交给了客人(kernel)达成,然后kernel做完后发信号公告。在此期间用户进程不要求去反省IO操作的气象,也不必要积极的去拷贝数据。
GO
Greenlet
greenlet是一个用C已毕的协程模块,比较于Python自带的yield,它可以在任意函数之间自由切换,而不需把这一个函数注脚为generator。
-
from greenlet import greenlet
-
-
def f1():
-
print(11)
-
gr2.switch()
-
print(22)
-
gr2.switch()
-
-
def f2():
-
print(33)
-
gr1.switch()
-
print(44)
-
-
gr1 = greenlet(f1)
-
gr2 = greenlet(f2)
-
gr1.switch()
-
输出:
-
11
-
33
-
22
-
44
以上例子还有一个题材从未缓解,就是碰见IO操作自动切换。
I/O多路复用
同步I/O和异步I/O,阻塞I/O和非阻塞I/O分别是如何,到底有哪些分别?本文琢磨的背景是Linux环境下的network
I/O。
参考资料:
EXEC
msdb.dbo.sp_add_notification @alert_name=N’SQL Server Severity Event
14′,
@operator_name=N’YourSQLDba_Operator’, @notification_method
= 1
通过安装此值,
可避防患例如, 在长期内再一次爆发警报时发送不必要的电子邮件。
@message_id=0,
@delay_between_responses=60,
@name=N’DBA_MONITORING’ ;
@delay_between_responses
=] delay_between_responses
IF
EXISTS(SELECT name FROM msdb.dbo.sysalerts WHERE name= N’SQL Server Severity Event
14′)
要实施的学业。
EXEC
msdb.dbo.sp_add_category
END
@job_id=N’00000000-0000-0000-0000-000000000000′
·
A
job to execute.
透过电子邮件或寻呼机发送的一个或八个关照。
GO
@type=N’NONE’,
多年来意想不到意识大家布置在数据库方面的报警(Alert),当错误日志里面现身错误时,并不是每个错误日志都会发送邮件出来。如下所示,设置了报警“SQL
Server Severity 伊芙nt 14”
EXEC msdb.dbo.sp_delete_alert @name=N’SQL Server Severity Event
14′
GO
GO
警报响应时期的等候时间
(以秒为单位)。delay_between_responsesis int, 默许值为 0,
那意味在响应时期平昔不等待
(每一遍出现警报都会转变响应)。响应得以是在偏下三种格局中的一个,
或者都是:
USE
[msdb]
@severity=14,
The
wait period, in seconds, between responses to the alert.
delay_between_responsesis int, with a default of 0, which
means there is no waiting between responses (each occurrence of the
alert generates a response). The response can be in either or both of
these forms:
·
By
setting this value, it is possible to prevent, for example, unwanted
e-mail messages from being sent when an alert repeatedly occurs in a
short period of time.
@category_name=N’DBA_MONITORING’,
EXEC
msdb.dbo.sp_add_alert @name=N’SQL Server Severity Event
14′,
·
One
or more notifications sent through e-mail or pager.
BEGIN