169it科技资讯


当前位置:  编程技术>软件工程/软件设计
本页文章导读:
    ▪机器学习理论与实战(二)决策树               电影《无耻混蛋》里有一幕游戏,在德军小酒馆里有几个人在玩20问题游戏,游戏规则是一个设迷者在纸牌中抽出一个目标(可以是人,也可以是物),而猜谜者可以.........
    ▪Hibernate(四)——全面解析一对多关联映射      一对多和上文讲的多对一两种映射关系,其实就是站在相反的角度考虑同样的事情。 一对多和多对一映射原理是一样的,都在多的一端加入一个外键指向一的一端。也就是说,在关系数据.........
    ▪我所理解的设计模式(C++实现)——解释器模式(Interpreter Pattern)      概述:         未来机器智能化已然成为趋势,现在手机都能听懂英语和普通话,那我大中华几万种方言的被智能化也许也是趋势,我们的方言虽然和普通话相似,但是还是.........

[1]机器学习理论与实战(二)决策树
    来源: 互联网  发布时间: 2013-11-19

         电影《无耻混蛋》里有一幕游戏,在德军小酒馆里有几个人在玩20问题游戏,游戏规则是一个设迷者在纸牌中抽出一个目标(可以是人,也可以是物),而猜谜者可以提问题,设迷者只能回答是或者不是,在几个问题(最多二十个问题)之后,猜谜者通过逐步缩小范围就准确的找到了答案。这就类似于决策树的工作原理。(图一)是一个判断邮件类别的工作方式,可以看出判别方法很简单,基本都是阈值判断,关键是如何构建决策树,也就是如何训练一个决策树。


(图一)

构建决策树的伪代码如下:

Check if every item in the dataset is inthe same class:

       If so return the class label

       Else

             find the best feature to split the data

             split the dataset

             create a branch node

             for each split

                    call createBranch and add the result to the branch node

            return branch node

         注意上面伪代码中一句说:find the best feature to split the data,那么如何find thebest feature?一般有个准则就是尽量使得分支之后节点的类别纯一些,也就是分的准确一些。如(图二)中所示,从海洋中捞取的5个动物,我们要判断他们是否是鱼,先用哪个特征?


(图二)

         为了提高识别精度,我们是先用“能否在陆地存活”还是“是否有蹼”来判断?我们必须要有一个衡量准则,常用的有信息论、基尼纯度等,这里使用前者。我们的目标就是选择使得分割后数据集的标签信息增益最大的那个特征,信息增益就是原始数据集标签基熵减去分割后的数据集标签熵,换句话说,信息增益大就是熵变小,使得数据集更有序。熵的计算如(公式一)所示:

(公式一)

       有了指导原则,那就进入代码实战阶段,先来看看熵的计算代码:

def calcShannonEnt(dataSet):
    numEntries = len(dataSet)
    labelCounts = {}
    for featVec in dataSet: #the the number of unique elements and their occurance
        currentLabel = featVec[-1]
        if currentLabel not in labelCounts.keys(): labelCounts[currentLabel] = 0
        labelCounts[currentLabel] += 1  #收集所有类别的数目,创建字典
    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key])/numEntries
        shannonEnt -= prob * log(prob,2) #log base 2  计算熵
    return shannonEnt

         有了熵的计算代码,接下来看依照信息增益变大的原则选择特征的代码:


def splitDataSet(dataSet, axis, value):
    retDataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]     #chop out axis used for splitting
            reducedFeatVec.extend(featVec[axis+1:])
            retDataSet.append(reducedFeatVec)
    return retDataSet
    
def chooseBestFeatureToSplit(dataSet):
    numFeatures = len(dataSet[0]) - 1      #the last column is used for the labels
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0; bestFeature = -1
    for i in range(numFeatures):        #iterate over all the features
        featList = [example[i] for example in dataSet]#create a list of all the examples of this feature
        uniqueVals = set(featList)       #get a set of unique values
        newEntropy = 0.0
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet, i, value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)     
        infoGain = baseEntropy - newEntropy     #calculate the info gain; ie reduction in entropy
        if (infoGain > bestInfoGain):       #compare this to the best gain so far    #选择信息增益最大的代码在此
            bestInfoGain = infoGain         #if better than current best, set to best
            bestFeature = i
    return bestFeature                      #returns an integer

        从最后一个if可以看出,选择使得信息增益最大的特征作为分割特征,现在有了特征分割准则,继续进入一下个环节,如何构建决策树,其实就是依照最上面的伪代码写下去,采用递归的思想依次分割下去,直到执行完成就构建了决策树。代码如下:

def majorityCnt(classList):
    classCount={}
    for vote in classList:
        if vote not in classCount.keys(): classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

def createTree(dataSet,labels):
    classList = [example[-1] for example in dataSet]
    if classList.count(classList[0]) == len(classList): 
        return classList[0]#stop splitting when all of the classes are equal
    if len(dataSet[0]) == 1: #stop splitting when there are no more features in dataSet
        return majorityCnt(classList)
    bestFeat = chooseBestFeatureToSplit(dataSet)
    bestFeatLabel = labels[bestFeat]
    myTree = {bestFeatLabel:{}}
    del(labels[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)
    for value in uniqueVals:
        subLabels = labels[:]       #copy all of labels, so trees don't mess up existing labels
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),subLabels)
    return myTree                        

      用图二的样本构建的决策树如(图三)所示:


(图三)

有了决策树,就可以用它做分类咯,分类代码如下:

def classify(inputTree,featLabels,testVec):
    firstStr = inputTree.keys()[0]
    secondDict = inputTree[firstStr]
    featIndex = featLabels.index(firstStr)
    key = testVec[featIndex]
    valueOfFeat = secondDict[key]
    if isinstance(valueOfFeat, dict): 
        classLabel = classify(valueOfFeat, featLabels, testVec)
    else: classLabel = valueOfFeat
    return classLabel

最后给出序列化决策树(把决策树模型保存在硬盘上)的代码:

def storeTree(inputTree,filename):
    import pickle
    fw = open(filename,'w')
    pickle.dump(inputTree,fw)
    fw.close()
    
def grabTree(filename):
    import pickle
    fr = open(filename)
    return pickle.load(fr)
    


作者:cuoqu 发表于2013-7-5 23:18:40 原文链接
阅读:5 评论:0 查看评论

    
[2]Hibernate(四)——全面解析一对多关联映射
    来源: 互联网  发布时间: 2013-11-19

一对多和上文讲的多对一两种映射关系,其实就是站在相反的角度考虑同样的事情。


一对多和多对一映射原理是一样的,都在多的一端加入一个外键指向一的一端。也就是说,在关系数据库的表中,他们的表及表字段都是一样的。

他们的不同在于维护的关系:

          多对一维护的关系——多指向一的关系,如果维护了多指向一的关系,那么加载多的时候会把一加载上来。

         一对多维护的关系——一指向多的关系,如果维护了一指向多的关系,那么加载多的时候,会把一加载上来。


现在假如要用一对多映射描述学生和班级的关系。


1、hibernate单向一对多关联映射(Classes----->Student)


实体Classes。一对多关系,加载时需要在一的一端(classes端)加载上来多的一端(Student),所以实体Classes中需包含实体Student的引用。

package com.lzq.hibernate;
import java.util.Set;
public class Classes {
	private int id;
	private String name;
	private Set student;
	此处省略getter和setter方法
}	


实体Student

package com.lzq.hibernate;
public class Student {
	private int id;
	private String name;
	此处省略getter和setter方法
}


映射文件Classes.hbm.xml。一对多关系中,需要在多的一端维护关系,所以在Classes端加入“one-to-many”标签维护关系。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.lzq.hibernate.Classes" table="t_classes">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name" />
                <!-- 集合映射set-->
                <set name="student">
                        <!-- 设置classesid外键为非空字段-->
                        <key column="classesid" not-null="true"/>
			<one-to-many class="com.lzq.hibernate.Student"/>
		</set>
	</class>
</hibernate-mapping>


映射文件Student.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.lzq.hibernate.Student" table="t_student">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name" />
	</class>
</hibernate-mapping>


尽管我们完成映射,但是这样映射还存在一定的问题,看下面的加载:

public void testOne2ManyAdd() throws Exception {
		Session session=null;
		Transaction tx=null;
		try {
			session=HibernateUtils.getSession();
			tx=session.beginTransaction();
			Student student1=new Student();
			student1.setName("张三");
			session.save(student1);
			Classes classes=new Classes();
			classes.setName("提高班");
			Set students=new HashSet();
			students.add(student1);
			classes.setStudent(students);
			session.save(classes);
			tx.commit();
		} catch (Exception e) {
			e.printStackTrace();
			HibernateUtils.closeSession(session);
		}
	}


结果会抛PropertyValueException异常。原因很简单:我们在多的一端(Student)没有维护关系,也就是说,Student不知道自己是哪一个班的,所以我们在保存Student的时候关系字段classesid为null。这就限制了外键必须为允许非空,如果外键设置为“不能为空”,则无法进行保存。而我们这里对外键设置,所以才会抛出此异常。


那怎么解决该问题呢?当然,我们可以在Classes.hbm.xml配置中去掉“ not-null='true' ”,这样也可以保存,但是我们可以观察生成的SQL语句,此时进行了一条insert和update语句,显然,它实现插入了student信息,然后在更新的classesid字段。这种方式显然不友善。那么除了这种方式,还能不能用别的方式解决?

这应为此问题,才产生了双向的一对多的关联映射:


2、hibernate双向一对多关联映射(Classes<----->Student)


既然是双向一对多关联映射,那么一定要在多的一端(Student)加入一的一端(Classes)的引用,这样才能在多的一端(Student)进行存储和加载。

package com.lzq.hibernate;
public class Student {
	private int id;
	private String name;
	
	private Classes classes;
	此处省略getter/setter方法
}


对应配置更改:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.lzq.hibernate.Student" table="t_student">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name" />
                <!-- 此处需要与classes端的配置的字段保持一致-->
                <many-to-one name="classes" column="classesid" />
	</class>
</hibernate-mapping>


此外,既然双向一对多关联映射的产生是为了弥补单向一对多关联映射的缺陷,那么避免程序员编写程序仍然在一的一端(Classes)加载,我们可以采用反转技术,设置从Classes端加载失效:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.lzq.hibernate.Classes" table="t_classes">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name" />
		<!--反转:设置从Classes端加入数据失效-->
		<set name="student" inverse="true">
			<key column="classesid" />
			<one-to-many class="com.lzq.hibernate.Student"/>
		</set>
	</class>
</hibernate-mapping>


为什么多对一关联映射不存在单向一对多中的问题呢?如果你明白了上面所讲的,这个问题将很好回答。在多对一关联映射里面,由于关系是在多的一端进行维护的,加载的时候从多的一

    
[3]我所理解的设计模式(C++实现)——解释器模式(Interpreter Pattern)
    来源: 互联网  发布时间: 2013-11-19
概述:

        未来机器智能化已然成为趋势,现在手机都能听懂英语和普通话,那我大中华几万种方言的被智能化也许也是趋势,我们的方言虽然和普通话相似,但是还是不一样的。这可能需要一个新的语法分析器来帮助我们。

        我们的解释器模式就是描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。

        但是解释一门自然语言是复杂的过程,我们以加减运算为例子来详细解释解释器模式。

 类图和实例:

抽象表达式角色(AbstractExpression): 声明一个抽象的解释操作,这个接口为所有具体表达式角色都要实现的.
终结符表达式角色(TerminalExpression): 实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例对应不同的终结符.
终结符就是语言中用到的基本元素,一般不能再被分解,如: x -> xa, 这里a是终结符,因为没有别的规则可以把a变成别的符号,不过x可以变成别的符号,所以x是非终结符.
非终结符表达式角色(NonterminalExpression): 文法中的每条规则对应于一个非终结表达式, 非终结表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式.
环境角色(Context): 包含解释器之外的一些全局信息.

实例:

#include <iostream>  
#include <map>  
#include <string>  
 
using namespace std;  

class Context
{
private:
	map<string, int> valueMap;

public:
	void addValue(string key,int value)
	{       
		valueMap.insert(std::pair<string,int>(key,value));
	}

	int getValue(string key)
	{
		return valueMap[key];
	}
};

class AbstractExpression
{
public :
	 virtual int interpreter(Context context) = 0;
};

class AddNonterminalExpression : public AbstractExpression
{
private :
	AbstractExpression *left;
	AbstractExpression *right;

public:
	AddNonterminalExpression(AbstractExpression *left, AbstractExpression *right)
	{
		this->left = left;
		this->right = right;
	}

	int interpreter(Context context)
	{
		return this->left->interpreter(context) + this->right->interpreter(context);
	}

};

class SubtractNonterminalExpression : public AbstractExpression
{
private :
	AbstractExpression *left;
	AbstractExpression *right;

public:
	SubtractNonterminalExpression(AbstractExpression *left, AbstractExpression *right)
	{
		this->left = left;
		this->right = right;
	}

	int interpreter(Context context)
	{
		return this->left->interpreter(context) - this->right->interpreter(context);
	}

};

class TerminalExpression : public AbstractExpression
{
private :
	int i;

public :
	TerminalExpression(int i)
	{
		this->i = i;
	}

	int interpreter(Context context)
	{
		return this->i;
	}
};

int main(){  
	//a-b+c
	Context context;
	context.addValue("a", 7);
	context.addValue("b", 8);
	context.addValue("c", 2);

	SubtractNonterminalExpression *subtractValue = new SubtractNonterminalExpression(new TerminalExpression(
		context.getValue("a")), new TerminalExpression(context.getValue("b")));

	AddNonterminalExpression *addValue = new AddNonterminalExpression(subtractValue, new TerminalExpression(
		context.getValue("c")));

	cout<< addValue->interpreter(context);

	return 0;  
}  
适用性:

在以下情况下可以考虑使用解释器模式:

      (1) 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。

      (2)  一些重复出现的问题可以用一种简单的语言来进行表达。

      (3) 一个语言的文法较为简单。

      (4) 执行效率不是关键问题。【注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。】

优缺点: 优点:        (1) 易于改变和扩展文法。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。

       (2) 每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

       (3) 实现文法较为容易。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。

       (4) 增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”。

缺点:        (1) 对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。

       (2) 执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

总论:

尽量不要在重要模块中使用解释器模式,因为维护困难。在项目中,可以使用脚本语言来代替解释器模式。


LCL_data原创于CSDN.NET【http://blog.csdn.net/lcl_data/article/details/9259905】

其他设计模式请参考:我所理解的设计模式


作者:LCL_data 发表于2013-7-6 19:43:00 原文链接
阅读:17 评论:0 查看评论

    
最新技术文章:
▪主-主数据库系统架构    ▪java.lang.UnsupportedClassVersionError: Bad version number i...    ▪eclipse项目出现红色叉叉解决方案
▪Play!framework 项目部署到Tomcat    ▪dedecms如何做中英文网站?    ▪Spring Batch Framework– introduction chapter(上)
▪第三章 AOP 基于@AspectJ的AOP    ▪基于插件的服务集成方式    ▪Online Coding开发模式 (通过在线配置实现一个表...
▪观察者模式(Observer)    ▪工厂模式 - 程序实现(java)    ▪几种web并行化编程实现
▪机器学习理论与实战(二)决策树    ▪Hibernate(四)——全面解析一对多关联映射    ▪我所理解的设计模式(C++实现)——解释器模...
▪利用规则引擎打造轻量级的面向服务编程模式...    ▪google blink的设计计划: Out-of-Progress iframes    ▪FS SIP呼叫的消息线程和状态机线程
▪XML FREESWITCH APPLICATION 实现    ▪Drupal 实战    ▪Blink: Chromium的新渲染引擎
▪(十四)桥接模式详解(都市异能版)    ▪你不知道的Eclipse用法:使用Allocation tracker跟...    ▪Linux内核-进程
▪你不知道的Eclipse用法:使用Metrics 测量复杂度    ▪IT行业为什么没有进度    ▪Exchange Server 2010/2013三种不同的故障转移
▪第二章 IoC Spring自动扫描和管理Bean    ▪CMMI简介    ' ;&+"vHE' ;&+"ection)原理与实现(六)
▪值班总结(1)——探讨sql语句的执行机制    ▪第二章 IoC Annotation注入    ▪CentOS 6.4下安装Vagrant
▪Java NIO框架Netty1简单发送接受    ▪漫画研发之八:会吃的孩子有奶吃    ▪比较ASP和ASP.NET
▪SPRING中的CONTEXTLOADERLISTENER    ▪在Nginx下对网站进行密码保护    ▪Hibernate从入门到精通(五)一对一单向关联映...
▪.NET领域驱动设计—初尝(三:穿过迷雾走向光...    ▪linux下的块设备驱动(一)    ▪Modem项目工作总结
▪工作流--JBPM简介及开发环境搭建    ▪工作流--JBPM核心服务及表结构    ▪Eclipse:使用JDepend 进行依赖项检查
▪windows下用putty上传文件到远程Linux方法    ▪iBatis和Hibernate的5点区别    ▪基于学习的Indexing算法
▪设计模式11---设计模式之中介者模式(Mediator...    ▪带你走进EJB--JMS编程模型    ▪从抽象谈起(二):观察者模式与回调
▪设计模式09---设计模式之生成器模式(Builder)也...    ▪svn_resin_持续优化中    ▪Bitmap recycle方法与制作Bitmap的内存缓存
▪Hibernate从入门到精通(四)基本映射    ▪设计模式10---设计模式之原型模式(Prototype)    ▪Dreamer 3.0 支持json、xml、文件上传
▪Eclipse:使用PMD预先检测错误    ▪Jspx.net Framework 5.1 发布    ▪从抽象谈起(一):工厂模式与策略模式
▪Eclipse:使用CheckStyle实施编码标准    ▪【论文阅读】《Chain Replication for Supporting High T...    ▪Struts2 Path_路径问题
▪spring 配置文件详解    ▪Struts2第一个工程helloStruts极其基本配置    ▪Python学习入门基础教程(learning Python)--2 Python简...
▪maven springmvc环境配置    ▪基于SCRUM的金融软件开发项目    ▪software quality assurance 常见问题收录
▪Redis集群明细文档    ▪Dreamer 框架 比Struts2 更加灵活    ▪Maven POM入门
▪git 分支篇-----不断更新中    ▪Oracle非主键自增长    ▪php设计模式——UML类图
▪Matlab,Visio等生成的图片的字体嵌入问题解决...    ▪用Darwin和live555实现的直播框架    ▪学习ORM框架—hibernate(二):由hibernate接口谈...
▪(十)装饰器模式详解(与IO不解的情缘)    ▪无锁编程:最简单例子    ▪【虚拟化实战】网络设计之四Teaming
▪OSGi:生命周期层    ▪Javascript/Jquery——简单定时器    ▪java代码 发送GET、POST请求
▪Entity Framework底层操作封装(3)    ▪HttpClient 发送GET、POST请求    ▪使用spring框架,应用启动时,加载数据
▪Linux下Apache网站目录读写权限的设置    ▪单键模式的C++描述    ▪学习ORM框架—hibernate(一):初识hibernate
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2017,169IT.COM,E-mail:www_169it_com#163.com(请将#改为@)

浙ICP备11055608号