在 Ignite 中使用 k- 均值聚类算法

2018 年 12 月 24 日 开源中国

在本系列前面的文章中,简单介绍了一下Ignite的k-最近邻(k-NN)分类算法,下面会尝试另一个机器学习算法,即使用泰坦尼克数据集介绍k-均值聚类算法。正好,Kaggle提供了CSV格式的数据集,而要分析的是两个分类:即乘客是否幸存。

为了将数据转换为Ignite支持的格式,前期需要做一些清理和格式化的工作,CSV文件中包含若干个列,如下:

  • 乘客Id

  • 幸存(0:否,1:是)

  • 船票席别(1:一,2:二,3:三)

  • 乘客姓名

  • 性别

  • 年龄

  • 泰坦尼克号上的兄弟/姐妹数

  • 泰坦尼克号上的父母/子女数

  • 船票号码

  • 票价

  • 客舱号码

  • 登船港口(C=瑟堡,Q=皇后镇,S=南安普顿)

因此首先要做的是,删除任何和特定乘客有关的、和生存无关的列,如下:

  • 乘客Id

  • 乘客姓名

  • 船票号码

  • 客舱号码

接下来会删除任何数据有缺失的行,比如年龄或者登船港口,可以对这些值进行归类,但是为了进行初步的分析,会删除缺失的值。

最后会将部分字段转换为数值类型,比如性别会被转换为:

  • 0:女

  • 1:男

登船港口会被转换为:

  • 0:Q(皇后镇)

  • 1:C(瑟堡)

  • 2:S(南安普顿)

最终的数据集由如下的列组成:

  • 船票席别

  • 性别

  • 年龄

  • 泰坦尼克号上的兄弟/姐妹数

  • 泰坦尼克号上的父母/子女数

  • 票价

  • 登船港口

  • 幸存

可以看到,幸存列已被移到最后。

下一步会将数据拆分为训练数据(80%)和测试数据(20%),和前文一样,还是使用Scikit-learn来执行这个拆分任务。

准备好训练和测试数据后,就可以编写应用了,本文的算法是:

  1. 读取训练数据和测试数据;

  2. 在Ignite中保存训练数据和测试数据;

  3. 使用训练数据拟合k-均值聚类模型;

  4. 将模型应用于测试数据;

  5. 确定含混矩阵和模型的准确性。

读取训练数据和测试数据

通过下面的代码,可以从CSV文件中读取数据

private static void loadData(String fileName, IgniteCache<Integer, TitanicObservation> cache)
        throws FileNotFoundException {

   Scanner scanner = new Scanner(new File(fileName));   int cnt = 0;   while (scanner.hasNextLine()) {
      String row = scanner.nextLine();
      String[] cells = row.split(",");      double[] features = new double[cells.length - 1];      for (int i = 0; i < cells.length - 1; i++)
         features[i] = Double.valueOf(cells[i]);      double survivedClass = Double.valueOf(cells[cells.length - 1]);

      cache.put(cnt++, new TitanicObservation(features, survivedClass));
   }
}

该代码简单地一行行的读取数据,然后对于每一行,使用CSV的分隔符拆分出字段,每个字段之后将转换成double类型并且存入Ignite。

将训练数据和测试数据存入Ignite

前面的代码将数据存入Ignite,要使用这个代码,首先要创建Ignite存储,如下:

IgniteCache<Integer, TitanicObservation> trainData = getCache(ignite, "TITANIC_TRAIN");
IgniteCache<Integer, TitanicObservation> testData = getCache(ignite, "TITANIC_TEST");
loadData("src/main/resources/titanic-train.csv", trainData);
loadData("src/main/resources/titanic-test.csv", testData);

getCache()的实现如下:

private static IgniteCache<Integer, TitanicObservation> getCache(Ignite ignite, String cacheName) {

   CacheConfiguration<Integer, TitanicObservation> cacheConfiguration = new CacheConfiguration<>();
   cacheConfiguration.setName(cacheName);
   cacheConfiguration.setAffinity(new RendezvousAffinityFunction(false, 10));

   IgniteCache<Integer, TitanicObservation> cache = ignite.createCache(cacheConfiguration);   return cache;
}

使用训练数据拟合k-NN分类模型

数据存储之后,可以像下面这样创建训练器:

KMeansTrainer trainer = new KMeansTrainer()
        .withK(2)
        .withDistance(new EuclideanDistance())
        .withSeed(123L);

这里k的值配置为2,表示有2个簇(幸存和未幸存),对于距离测量,可以有多个选择,比如欧几里得、海明或曼哈顿,在本例中会使用欧几里得,另外,种子值赋值为123。

然后拟合训练数据,如下:

KMeansModel mdl = trainer.fit(
        ignite,
        trainData,
        (k, v) -> v.getFeatures(),        // Feature extractor.

        (k, v) -> v.getSurvivedClass()    // Label extractor.);

Ignite将数据保存为键-值(K-V)格式,因此上面的代码使用了值部分,目标值是Survived类,特征在其它列中。

将模型应用于测试数据

下一步,就可以用训练好的分类模型测试测试数据了,可以这样做:

int amountOfErrors = 0;
int totalAmount = 0;
int[][] confusionMtx = {{0, 0}, {0, 0}};

try (QueryCursor<Cache.Entry<Integer, TitanicObservation>> cursor = testData.query(new ScanQuery<>())) {  
for (Cache.Entry<Integer, TitanicObservation> testEntry : cursor) {      TitanicObservation observation = testEntry.getValue();      

double groundTruth = observation.getSurvivedClass();      
double prediction = mdl.apply(new DenseLocalOnHeapVector(observation.getFeatures()));      totalAmount++;      

if ((int) groundTruth != (int) prediction)         amountOfErrors++;      

int idx1 = (int) prediction;      
int idx2 = (int) groundTruth;      confusionMtx[idx1][idx2]++;      System.out.printf(">>> | %.4f\t | %.0f\t\t\t|\n", prediction, groundTruth);   } }

确定含混矩阵和模型的准确性

下面,就可以通过对测试数据中的真实分类和模型进行的分类进行对比,来确认模型的真确性。

代码运行之后,输出如下:

>>> Absolute amount of errors 56

>>> Accuracy 0.6084

>>> Precision 0.5865

>>> Recall 0.9873

>>> Confusion matrix is [[78, 55], [1, 9]]

这个初步的结果可不可以改进?可以尝试的是对特征的衡量,在Ignite和Scikit-learn中,可以使用MinMaxScaler(),然后会给出如下的输出:

>>> Absolute amount of errors 29

>>> Accuracy 0.7972

>>> Precision 0.8205

>>> Recall 0.8101

>>> Confusion matrix is [[64, 14], [15, 50]]

作为进一步分析的一部分,还应该研究幸存与否和年龄和性别之间的关系。

总结

通常来说,k-均值聚类并不适合监督学习任务,但是如果分类很容易,这个方法还是有效的。对于本例来说,关注的就是是否幸存。

开源中国征稿开始啦!


开源中国 www.oschina.net 是目前备受关注、具有强大影响力的开源技术社区,拥有超过 200 万的开源技术精英。我们传播开源的理念,推广开源项目,为 IT 开发者提供一个发现、使用、并交流开源技术的平台。


现在我们开始对外征稿啦!如果你有优秀的技术文章想要分享,热点的行业资讯需要报道等等,欢迎联系开源中国进行投稿。投稿详情及联系方式请参见:我要投稿

推荐阅读

伯克利开源 Confluo,吞吐量是 Kafka 的 4 到 10 倍

C++ GUI 开发框架 Qt 已支持 Python!

OpenJDK 中脏话太多,开发者看不下去了

MIPS 指令集将在近期开源,RISC-V 阵营慌吗?

2018 年度最受欢迎中国开源软件 TOP20 正式揭晓

更多详情请查看阅读原文↓↓↓↓↓

登录查看更多
1

相关内容

【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
258+阅读 · 2020年6月10日
【ICML2020】小样本目标检测
专知会员服务
90+阅读 · 2020年6月2日
干净的数据:数据清洗入门与实践,204页pdf
专知会员服务
160+阅读 · 2020年5月14日
【干货】大数据入门指南:Hadoop、Hive、Spark、 Storm等
专知会员服务
95+阅读 · 2019年12月4日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
84+阅读 · 2019年11月25日
R语言机器学习:xgboost的使用及其模型解释
R语言中文社区
10+阅读 · 2019年5月6日
实战 | 用Python做图像处理(三)
七月在线实验室
15+阅读 · 2018年5月29日
【干货】Python无监督学习的4大聚类算法
新智元
14+阅读 · 2018年5月26日
图解机器学习的常见算法
机器学习算法与Python学习
5+阅读 · 2018年4月2日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
动手写机器学习算法:K-Means聚类算法
七月在线实验室
5+阅读 · 2017年12月6日
机器学习(28)【降维】之sklearn中PCA库讲解与实战
机器学习算法与Python学习
8+阅读 · 2017年11月27日
机器学习(27)【降维】之主成分分析(PCA)详解
机器学习算法与Python学习
9+阅读 · 2017年11月22日
一文详解聚类和降维(附实例、代码)
数据派THU
7+阅读 · 2017年9月3日
Arxiv
12+阅读 · 2018年1月12日
VIP会员
相关资讯
R语言机器学习:xgboost的使用及其模型解释
R语言中文社区
10+阅读 · 2019年5月6日
实战 | 用Python做图像处理(三)
七月在线实验室
15+阅读 · 2018年5月29日
【干货】Python无监督学习的4大聚类算法
新智元
14+阅读 · 2018年5月26日
图解机器学习的常见算法
机器学习算法与Python学习
5+阅读 · 2018年4月2日
Python 爬虫实践:《战狼2》豆瓣影评分析
数据库开发
5+阅读 · 2018年3月19日
动手写机器学习算法:K-Means聚类算法
七月在线实验室
5+阅读 · 2017年12月6日
机器学习(28)【降维】之sklearn中PCA库讲解与实战
机器学习算法与Python学习
8+阅读 · 2017年11月27日
机器学习(27)【降维】之主成分分析(PCA)详解
机器学习算法与Python学习
9+阅读 · 2017年11月22日
一文详解聚类和降维(附实例、代码)
数据派THU
7+阅读 · 2017年9月3日
Top
微信扫码咨询专知VIP会员