一、前期准备

1、加入依赖

百度搜索 maven,找到 maven 的 repository 仓库,寻找 weka 的依赖包:

找到稳定版本(我下载 weka 软件的时候就是这个版本,没有犹豫,就是它了),点击进去选择对应版本,依然是和自己软件版本一致:

点击进去可以看到对应的依赖语句代码了,当然也可以下载 jar 包,不过能偷懒就偷懒一下吧:

<dependency><groupId>nz.ac.waikato.cms.weka</groupId><artifactId>weka-stable</artifactId><version>3.8.5</version>
</dependency>

2、新建 spring 项目,加入 weka 依赖

这里我创建的是 SpringBoot 项目,具体过程就不说了,超级简单。

创建一个 test 包,在建一个相关类就可以开始搞起了。

3、初步尝试

在网上找了半天,发现 weka 的实例代码比较少,搜关键词一大半网页都是软件 weka 的介绍,不得不说 java 搞 weka 实在是太过于小众了。

最终,皇天不负有心人,还是找到了一个代码实例:

public class test {public static void main(String[] args) {Instances ins = null;Classifier cfs = null;try {// read the training setFile file = new File("D:\\weka\\Weka-3-8-5\\data\\weather.numeric.arff");ArffLoader loader = new ArffLoader();   //ArffLoader类是weka.core.converters下的loader.setFile(file);ins = loader.getDataSet();System.out.println(ins.numAttributes());ins.setClassIndex(ins.numAttributes() - 1);// 初始化分类器cfs = (Classifier) Class.forName("weka.classifiers.bayes.NaiveBayes").newInstance();// 使用训练集对数据集训练cfs.buildClassifier(ins);// 使用测试数据集测试分类器的性能Instance testInst;Evaluation testingEvaluation = new Evaluation(ins);int length = ins.numInstances(); //得到数据集样本个数for (int i = 0; i < length; i++) {testInst = ins.instance(i);testingEvaluation.evaluateModelOnceAndRecordPrediction(cfs, testInst);}// print the classifying resultsSystem.out.println("分类正确率:" + (1 - testingEvaluation.errorRate()));} catch (Exception e) {e.printStackTrace();}}
}

有了代码实例,接下来就相对容易一些,至少有一个大体框架的实例可供参考。

二、逐步提升

1、任务:加载 arff 文件、csv 与 arff 文件之间转换

加载 arff 的两种方法:

//方法一:使用DataSource类的read方法来加载arff文件
Instances data1=DataSource.read("data/weather.nominal.arff");//方法二:使用直接制定加载器的方法来加载Arff文件
ArffLoader arffLoader=new ArffLoader();//创建ArffLoader实例
arffLoader.setSource(new File("data/weather.nominal.arff"));
Instances data2=arffLoader.getDataSet();

将 arff 保存为 csv 文件:

//方法一
Instances data=new Instances(DataSource.read("data/weather.nominal.arff"));
DataSink.write("data/weather.csv", data);//方法二:明确指定转换器,保存为csv文件
CSVSaver saver=new CSVSaver();
saver.setInstances(data);
saver.setFile(new File("data/weather2.csv"));
saver.writeBatch();

将 csv 文件保存为 arff 文件:

Instances allData = DataSource.read("E:\\dataset\\clusterData\\wine.csv");
ArffSaver saver = new ArffSaver();
saver.setInstances(allData);
saver.setFile(new File("E:\\dataset\\clusterData\\wine.arff"));
saver.writeBatch();
System.out.println("已经转化为arrf文件");

2、任务:切分数据集

代码例子中训练集和测试集用的都是同一个数据,这个就有点搞笑了,第一步认为暂定为学习切分数据集,至少也要有合适的训练集和测试集。

切分代码如下:

//读取Instances trainingSet = DataSource.read(path);
//打乱顺序,因为后面要进行截取
trainingSet.randomize(new Random(0));
//训练集:测试集=4:1
int trainSize = (int) Math.round(trainingSet.numInstances() * 0.80);
int testSize = trainingSet.numInstances() - trainSize;
//从数据集中进行截取
Instances train = new Instances(trainingSet, 0, trainSize);
Instances test = new Instances(trainingSet, trainSize, testSize);

3、任务:修改测试数据一条一条进行测试

划分好了训练数据和测试数据,本打算将这个测试数据一起进行评估,结果报错如下:

查看源代码,找到原因在于 evaluateModelOnceAndRecordPrediction 函数本身只接受一条记录:

public double evaluateModelOnceAndRecordPrediction(double[] dist, Instance instance) throws Exception {return this.m_delegate.evaluateModelOnceAndRecordPrediction(dist, instance);
}

通过查看源代码,找到了一个可以一次性评估整个数据集的:

public double[] evaluateModel(Classifier classifier, Instances data, Object... forPredictionsPrinting) throws Exception {return this.m_delegate.evaluateModel(classifier, data, forPredictionsPrinting);
}

除了查看源代码,也可以通过输入 Evaluation 加点的方式查看评估器对象有哪些函数,主要看函数参数里面有 classifier 同时还有 Instances 的,如果有,再看看函数名,基本上就可以确定。

最终原代码中的 for 循环测试,修改如下:

testingEvaluation.evaluateModel(cfs,test);

测试了一下,准确率和一条条测试一模一样。

4、任务:测试模型几种模式

如上图所示,在 weka 软件上,测试模型分为四种方法,那么对应的使用 java 代码也可以还原上面四种方法。

(1)Use traning set

第一种方法就是从网上搬运过来的原版代码——使用训练数据测试模型:

for (int i = 0; i < length; i++) {testInst = ins.instance(i); //ins是数据集,既是训练数据也是测试数据testingEvaluation.evaluateModelOnceAndRecordPrediction(cfs, testInst);
}
(2)Supplied test set

也就是重新加载一个新的数据集作为测试集,这个比较简单,仿照着数据集加载模式再来一次即可:

File file = new File("你的测试数据集所在目录");
ArffLoader loader = new ArffLoader();   //ArffLoader类是weka.core.converters下的
loader.setFile(file);
Instances test = loader.getDataSet();
(3)Cross-validation

也就是交叉验证,这个原理大概说一下:

将整个数据集分为 k 份(也叫 k 折),做 k 次试验,每次取其中 k-1 份作为训练数据,另外一份作为测试数据,最后综合 k 次试验的结果来验证模型。

要进行交叉验证,要使用 Evaluation 类,该类就是用来评估测试机器学习模型的。

Evaluation 评估器有两种评估方法:

  • 如果测试集和训练集没有分开,可以使用 crossValidateModel 方法,Evaluation 中crossValidateModel方法的四个参数分别为:

    • 第一个是分类器
    • 第二个是整个数据集(前面提到了测试集和训练集没有分开才使用这个)
    • 第三个参数是交叉检验的次数(10 是比较常见的)
    • 第四个是一个随机数对象。
  • 如果有训练集和测试集,可以使用 Evaluation 类中的 evaluateModel 方法,方法中的参数为:第一个为一个训练过的分类器,第二个参数是测试数据集。

注意:如果采用crossValidateModel方法,是不能进行训练的,因为这个方法本身包含训练过程。

我们所说的交叉验证就是指第一种方法,也就是采用 crossValidateModel 方法进行测试,先看一下源代码:

//创建分类器
J48 classifier = new J48();Evaluation eval = new Evaluation( m_instances );
eval.crossValidateModel( classifier, m_instances, 10, new Random(1));
System.out.println(eval.toClassDetailsString());
System.out.println(eval.toSummaryString());
System.out.println(eval.toMatrixString());

问题一

这里有一个疑问的地方,就是评估器在构建对象的时候,需要一个数据集,那么这个数据集有什么用?必须是训练数据,还说什么数据集都可以?

我查看了一下源代码(在安装目录 Weka-3-8-5/doc/index.html):

大家可以看到,data 参数的目的是为了获取信息的头部(估计是第一行信息,也就是特征名称)还有先验标签分布信息。

所有说,只要有这两个特征数据集即可,不过最好还是训练集为佳,毕竟这个先验标签分布信息不好说。

问题二

在网上查找代码的时候,发现一部分人在使用交叉验证的时候,用了 for 循环,而有的则没有使用,我上面的代码实例是后者,使用 for 循环的代码如下:

//直接调用Evaluation即可完成
Evaluation eval = null;
for (int i = 0; i < 10; i++) {eval = new Evaluation(Train);eval.crossValidateModel(m_classifier, Train, 10, new Random(i),
args);// 实现交叉验证模型
}
System.out.println(eval.toSummaryString());// 输出总结信息
System.out.println(eval.toClassDetailsString());// 输出分类详细信息
System.out.println(eval.toMatrixString());// 输出分类的混淆矩阵

到底用不用 for 循环,我特意查看了一下 crossValidateModel 函数的源代码(按住 Ctrl+点击鼠标),有这么一段代码:

for(int i = 0; i < numFolds; ++i) {Instances train = data.trainCV(numFolds, i, random);this.setPriors(train);Classifier copiedClassifier = AbstractClassifier.makeCopy(classifier);copiedClassifier.buildClassifier(train);if (classificationOutput == null && forPrinting.length > 0) {((StringBuffer)forPrinting[0]).append("\n=== Classifier model (training fold " + (i + 1) + ") ===\n\n" + copiedClassifier);}Instances test = data.testCV(numFolds, i);if (classificationOutput != null) {this.evaluateModel(copiedClassifier, test, forPrinting);} else {this.evaluateModel(copiedClassifier, test);}
}

可以看到,crossValidateModel 方法中本身进行了一个 for 循环,每次循环生成一次训练集和测试集(基于第二个参数),还有分类器,在评估分类器时,本质还是调用的 evaluateModel 方法。

问题三

交叉验证的目的是什么?很多帖子都说是用来测试模型的,但是交叉验证中本身是有训练过程的,你测试模型过程中,又训练了模型(会使模型参数发生变化),那么交叉验证完后的模型还是原来的模型吗?或者说你测试的模型还是原来的模型吗?

这个问题,在一个帖子上找到了答案:

交叉验证本身不是用来选择模型的,或者说它不单单是用来选择模型的,它集成了训练、测试和选择模型三个过程。

(4)percentage split

这个就是按照比例切分了,代码如下:

//打乱顺序,保证切分样本的随机性
dataSet.randomize(new Random(0));
//训练集:测试集=4:1
int trainSize = (int) Math.round(dataSet.numInstances() * 0.80);
int testSize = dataSet.numInstances() - trainSize;
//从数据集中进行截取
Instances train = new Instances(dataSet, 0, trainSize);
Instances test = new Instances(dataSet, trainSize, testSize);

5、任务:初始化分类器与配置参数

初始化分类器:

// 初始化分类器,以下三种方法都可以
cfs = (Classifier) Class.forName("weka.classifiers.bayes.NaiveBayes").newInstance();
J48 cfs = new J48(); //推荐使用该种方法,因为简单,而且配置参数也容易
cfs = new weka.classifiers.trees.J48();

分类器说好了,再来说一下配置参数问题,这个折腾了半天,主要是网上的资料太少了,找到一个源代码,还是错误的:

String[] options ={"-B true"};
J48 classifier = new J48();
classifier.setOptions(options);

运行上述代码会报错如下:

根据错误提示,显然是配置参数格式有问题,于是开始查看 setOptions 方法源代码:

public void setOptions(java.lang.String[] options)throws java.lang.Exception
Parses a given list of options. Valid options are:-U:Use unpruned tree.-O:Do not collapse tree.-C <pruning confidence>Set confidence threshold for pruning.(default 0.25)-M <minimum number of instances>Set minimum number of instances per leaf.(default 2)-R:Use reduced error pruning.-N <number of folds>Set number of folds for reduced errorpruning. One fold is used as pruning set.(default 3)-B:Use binary splits only.-S:Don't perform subtree raising.-L:Do not clean up after the tree has been built.-A:Laplace smoothing for predicted probabilities.-J:Do not use MDL correction for info gain on numeric attributes.-Q <seed>Seed for random data shuffling (default 1).-doNotMakeSplitPointActualValueDo not make split point actual value.Specified by:
setOptions in interface OptionHandler
Overrides:
setOptions in class AbstractClassifier
Parameters:
options - the list of options as an array of strings
Throws:
java.lang.Exception - if an option is not supported

可以看到,只有参数含义,并没有我们想要的实例,后来,看到分类器还有一个 getOptions 方法,眼睛一亮,想到可以查看一下默认参数的格式是怎么样的,源代码如下:

String[] options=cfs.getOptions();
for(int i=0;i<options.length;i++){System.out.println(options[i]);
}

输出打印如下:

看到打印结果,果断知道了网上的实例为什么错误了,人家一个设置要分两个字符串来写,于是修改如下:

String[] options ={"-B","true"};
J48 classifier = new J48();
classifier.setOptions(options);

结果还是报错,也是佛了,最后的最后,想到了 weka 软件的参数设置:

看到上面 J48 后面出现的字符和通过 getOptions 打印出来的一样,点击进去,修改二分叉的属性(将 binarySplits 的 False 修改为 True),再看看果然发生了变化:

看到这里我才明白,根部不需要什么 true,对于这种非数值型参数设置只要一个字符串就可以,于是再次修改参数设置:

String[] options ={"-B"};
J48 classifier = new J48();
classifier.setOptions(options);

再次运行,没有报错,完美运行。

建议:先使用weka软件设置完参数,然后将参数复制粘贴过来就行了。

问题一

有一问题是,除了 J48 classifier = new J48();创建的对象能够使用 setOptions 方法,其他两种创建对象方式都不能使用该方法,不知道哪里有问题,查看源代码,三种方式指向的类都是同一个类,这个后续有时间再解决一下。

6、任务:从数据库读取数据生成 Instances

从 oracle 数据库读取:

public static Instances oracleInput() throws Exception{InstanceQuery query = new InstanceQuery();String sql = "SELECT to_char(z.cydate,'yyyy/mm') AS d,sum(z.bcmoney) as c FROM zybc z"
+ " WHERE to_char(z.cydate,'yyyy/mm') IS NOT NULL"
+ " GROUP BY to_char(z.cydate,'yyyy/mm') ORDER BY to_date(to_char(z.cydate,'yyyy/mm'),'yyyy/mm') ASC";//System.out.println(sql);query.setCustomPropsFile(new File("weka/weka_oracle.props"));query.setDatabaseURL("jdbc:oracle:thin:@192.168.2.133:1521/XE");query.setUsername("***");query.setPassword("***");query.setQuery(sql);Instances data = query.retrieveInstances();
return data;
}

从 mysql 数据库读取:

public static Instances mysqlInput() throws Exception{InstanceQuery query = new InstanceQuery();String sql = "SELECT * FROM iris";//System.out.println(sql);query.setCustomPropsFile(new File("weka/weka_mysql.props"));query.setDatabaseURL("jdbc:mysql://localhost:3306/test");query.setUsername("***");query.setPassword("***");query.setQuery(sql);Instances data = query.retrieveInstances();return data;}

6、任务:保存模型与加载模型

这个相对简单一下:

//保存模型,参数一为模型保存文件,cfs为要保存的模型
SerializationHelper.write("J48.model", cfs);//加载模型
Classifier cfs = (Classifier) weka.core.SerializationHelper.read("J48.model");

说实话,这一顿搞后,还是觉得通过 java 使用 weka 远没有软件方便,建议可以使用 weka 软件生成模型,再通过 java 直接调用模型即可,感觉会方便很多。

OK,今天就到这里,更多精彩内容关注我的个人网站:蓝亚之舟博客。

学习weka(3):idea中集成weka相关推荐

  1. 使用Weka进行数据挖掘(Weka教程一)Weka初识之在你的代码中使用Weka

    转眼使用Weka已经大半年了,自己在学习过程中走了很多弯路,使用过程中我最大的感觉就是国内没有对Weka一个完善的整理和相关的学习论坛.为了避免其他人走我走过的弯路,相关的从本篇开始,我将持续更新使用 ...

  2. maven mybatis mysql_Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问...

    标签: 本篇内容还是建立在上一篇Java Web学习系列--Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Ja ...

  3. MATLAB中调用Weka设置方法(转)及示例

    本文转自: http://blog.sina.com.cn/s/blog_890c6aa30101av9x.html MATLAB命令行下验证Java版本命令 version -java 配置MATL ...

  4. 如何在电子学习 e-learning 平台学习管理系统 LMS 中集成使用 ONLYOFFICE

    如何在电子学习 e-learning 平台学习管理系统 LMS 中集成使用 ONLYOFFICE 重大消息!我也咩咩咩了! 真的是,浑身不舒服,没想到啊没想到,我这样高颜值的人,居然也会咩咩咩了 套用 ...

  5. java weka包_在Eclipse中调用weka包实现分类

    1.如题. 最近写了一个FCM的聚类算法,希望能够可视化结果,因此一个想法是调用weka中的包,使自己的程序可以可视化.这里参考了网络上的方法,首先实现在Eclipse中调用weka包实现分类的功能. ...

  6. 【直播】李祖贤:集成学习答疑直播之五 -- 常用集成思路

    集成学习答疑直播之五 – 常用集成思路   集成学习 是首个横跨3个周期的长期组队学习,在 第24期组队学习 中进行到"第二期-模型集成思路"阶段.组队学习期间,课程设计者每周针对 ...

  7. 《强化学习周刊》第35期:强化学习在智能交通中的最新应用

    No.35 智源社区 强化学习组 强 化 学  习 研究 观点 资源 活动 关于周刊 强化学习作为人工智能领域研究热点之一,其研究进展与成果也引发了众多关注.为帮助研究与工程人员了解该领域的相关进展和 ...

  8. 深度学习在目标视觉检测中的应用进展与展望

    作者:张慧,王坤峰,王飞跃 来源:王飞跃科学网博客 摘要:目标视觉检测是计算机视觉领域的一个重要问题,在视频监控.自主驾驶.人机交互等方面具有重要的研究意义和应用价值.近年来,深度学习在图像分类研究中 ...

  9. laravel+vue.js的学习以及为什么浏览器中要有井号“#”

    一.前言 一直想找机会学一下vue,但是go还没来得及学,laravel的源码还没看完,学习vue更是遥遥无期.幸好新公司的项目是用laravel+vue编写的,这才有幸接触到vue. 但是我在观看项 ...

最新文章

  1. 使用 PEAR的Text_CAPTCHA保护Web表单[翻译]
  2. LAMP服务搭建详解
  3. 【项目经验】在填写表单时,首先添加一个失去焦点事件,将数据库中信息自动填充信息到表单,其余信息手动填写然后提交表单。
  4. 【python asyncio 运行报错】:raise RuntimeError(‘There is no current event loop in thread %r‘)
  5. python pygame模块_python中pygame模块用法实例
  6. css 列表相关的属性 列表前的小点点 0302
  7. C语言 select
  8. java CopyOnWriteArrayList的使用
  9. 大学计算机应用基础教程pdf,最新大学计算机应用基础教程
  10. Windows10应用磁贴如何显示
  11. Emulex公司介绍
  12. Android 权限适配 从此第三方系统新增的权限无法判断状态的问题得到解决! 如MIUI自启动, 后台弹出界面权限等
  13. kaggle猫狗大战数据集集(百度云)
  14. 各种快递API接口—爱快递
  15. show和shown区别
  16. matlab中自相关函数
  17. 贾扬清分享_深度学习框架caffe
  18. UE4-控制音效空间效果及衰减效果技巧
  19. Aop 自动装配Autowired时,不装配接口而是实现类而报错 切面配置 satisfiedDependencyException|BeanNotOfRequiredTypeException
  20. glyphicon 字体在 bootstrap4 中默认不支持了

热门文章

  1. http://www.dewen.net.cn/q/16222/C++排序中的sort函数第三个参数的疑问
  2. 唤醒手腕Python全栈工程师学习笔记(网络爬虫篇)
  3. Vs错误:One of the identified items was in an invalid format.
  4. 什么是离线浏览,有哪些常用的离线浏览器
  5. 互联网金融风控面试业务知识
  6. 常用实验报告LaTex 模板
  7. 科研实习 | 南方科技大学魏鸿鑫老师机器学习课题组招收访问学生/全职RA
  8. 内网渗透|红日安全团队靶场渗透笔记|Mimikatz|MSF跳板
  9. android 连笔记本无线上网,[转载]android手机通过笔记本无线wifi上网
  10. 【图像语义分割】主题必读论文合集推荐丨跨图像语义挖掘、分层图像压缩等