零基础学习Mahout

Mahout

Alt text

Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序。Mahout包含许多实现,包括聚类、分类、推荐过滤、频繁子项挖掘。此外,通过使用 Apache Hadoop 库,Mahout 可以有效地扩展到云中。

安装Maven

Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。
Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以常常用两三行 Maven 构建脚本就可以构建简单的项目。由于 Maven 的面向项目的方法,许多 Apache Jakarta 项目发文时使用 Maven,而且公司项目采用 Maven 的比例在持续增长。
Maven这个单词来自于意第绪语(犹太语),意为知识的积累,最初在Jakata Turbine项目中用来简化构建过程。当时有一些项目(有各自Ant build文件),仅有细微的差别,而JAR文件都由CVS来维护。于是希望有一种标准化的方式构建项目,一个清晰的方式定义项目的组成,一个容易的方式发布项目的信息,以及一种简单的方式在多个项目中共享JARs。

使用Maven构建Mahout项目

运行 IntelliJ IDEA,通过菜单 File > New > Project 新建项目,选择 Maven 勾上 Create from archetype 选择 maven-archetype-quickstart 再选择 Next 输入 GroupIdArtifactId,可以根据自己喜好随便命名

Alt text

Alt text

剩下的全部按键盘 Enter

工程创建完毕后,点击右下角的 Enable Auto-Import 开启自动导入

Alt text

下载完毕后,打开 pom.xml 替换 <properties><dependencies> 内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.aliatry.mahout</groupId>
<artifactId>practice</artifactId>
<version>1.0-SNAPSHOT</version>

<name>practice</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mahout.version>0.9</mahout.version>
<slf4j-log4j12.version>1.7.25</slf4j-log4j12.version>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.mahout</groupId>
<artifactId>mahout-core</artifactId>
<version>${mahout.version}</version>
</dependency>

<dependency>
<groupId>org.apache.mahout</groupId>
<artifactId>mahout-integration</artifactId>
<version>${mahout.version}</version>
</dependency>

<dependency>
<groupId>org.apache.mahout</groupId>
<artifactId>mahout-math</artifactId>
<version>${mahout.version}</version>
</dependency>

<dependency>
<groupId>org.apache.mahout</groupId>
<artifactId>mahout-examples</artifactId>
<version>${mahout.version}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j-log4j12.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j-log4j12.version}</version>
</dependency>
</dependencies>

</project>

修改 App.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package com.aliatry.mahout;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.EuclideanDistanceSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
* Hello world!
*/
public class App {
public static void main(String[] args) throws Exception {

// 初始化
// initial();

baseUser(); // 基于用户的协同过滤算法
baseItem(); // 基于物品的协同过滤算法


// TODO 基于用户的协同过滤算法
// 从文件加载数据
DataModel model = new FileDataModel(new File("D:\\data.csv"));
// 指定用户相似度计算方法,这里采用皮尔森相关度
UserSimilarity similarity = new PearsonCorrelationSimilarity(model);
// 指定用户邻居数量,这里为2
UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, model);
// 构建基于用户的推荐系统
Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);
// 得到指定用户的推荐结果,这里是得到用户1的两个推荐
List<RecommendedItem> recommendations = recommender.recommend(1, 2);
// 打印推荐结果
for (RecommendedItem recommendation : recommendations) {
System.out.println(recommendation);
}
}

public static void initial() {
FileOutputStream out = null;

try {
int[][] arg = {
{3, 1, 4, 4, 1, 0, 0},
{0, 5, 1, 0, 0, 4, 0},
{1, 0, 5, 4, 3, 5, 2},
{3, 1, 4, 3, 5, 0, 0},
{5, 2, 0, 1, 0, 5, 5}
};
out = new FileOutputStream(new File("D:\\data.csv"));
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 7; j++) {
if (arg[i][j] > 0) {
String a = i + "," + j + "," + arg[i][j] + "\n";
out.write(a.getBytes());
}
}
}
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

/**
* 基于用户的协同过滤算法
*
* @throws IOException
* @throws TasteException
*/
public static void baseUser() throws IOException, TasteException {

final int NEIGHBORHOOD_NUM = 2; //用户邻居数量
final int RECOMMENDER_NUM = 3; //推荐结果个数

/*
准备数据 这里是电影评分数据
数据集,其中第一列表示用户id;第二列表示商品id;第三列表示评分,评分是5分制
*/
/*
将数据加载到内存中
基于文件的model,通过文件形式来读入,且此类型所需要读入的数据的格式要求很低,只需要满足每一行是用户id,物品id,用户偏好,且之间用tab或者是逗号隔开即可
*/
DataModel dataModel = new FileDataModel(new File("D:\\data.csv"));
/*
计算相似度,相似度算法有很多种,欧几里得、皮尔逊等等。
基于用户的协同过滤算法,基于物品的协同过滤算法,这里使用了EuclideanDistanceSimilarity
计算欧式距离,欧式距离来定义相似性,用s=1/(1+d)来表示,范围在[0,1]之间,值越大,表明d越小,距离越近,则表示相似性越大
*/
UserSimilarity similarity = new EuclideanDistanceSimilarity(dataModel);
/*
计算最近邻域,邻居有两种算法,基于固定数量的邻居和基于相似度的邻居,这里使用基于固定数量的邻居。
NEIGHBORHOOD_NUM指定用户邻居数量
*/
NearestNUserNeighborhood neighbor = new NearestNUserNeighborhood(NEIGHBORHOOD_NUM, similarity, dataModel);
/*
构建推荐器,协同过滤推荐有两种,分别是基于用户的和基于物品的,这里使用基于用户的协同过滤推荐
构建基于用户的推荐系统
*/
Recommender r = new GenericUserBasedRecommender(dataModel, neighbor, similarity);

//得到所有用户的id集合
LongPrimitiveIterator iter = dataModel.getUserIDs();
while (iter.hasNext()) {
long uid = iter.nextLong();
//获取推荐结果,获取指定用户指定数量的推荐结果
List<RecommendedItem> list = r.recommend(uid, RECOMMENDER_NUM);
System.out.printf("user : %s", uid);
//遍历推荐结果
for (RecommendedItem item : list) {
//获取推荐结果和推荐度
System.out.print(item.getItemID() + "[" + item.getValue() + "] ");
}
System.out.println();
}
}

/**
* 基于物品的协同过滤算法
*
* @throws IOException
* @throws TasteException
*/
public static void baseItem() throws IOException, TasteException {
DataModel dataModel = new FileDataModel(new File("D:\\data.csv"));
/*
计算相似度,相似度算法有很多种,欧几里得、皮尔逊等等。
这里使用的是皮尔逊PearsonCorrelationSimilarity
*/
ItemSimilarity itemSimilarity = new PearsonCorrelationSimilarity(dataModel);
//构建推荐器,协同过滤推荐有两种,分别是基于用户的和基于物品的,这里使用基于物品的协同过滤推荐
GenericItemBasedRecommender recommender = new GenericItemBasedRecommender(dataModel, itemSimilarity);
//给指定用户推荐若干个与指定商品相似的商品
List<RecommendedItem> recommendedItemList = recommender.recommendedBecause(1, 5, 2);
//打印推荐的结果
System.out.println("根据用户1当前浏览的商品5,推荐2个相似的商品");
for (RecommendedItem recommendedItem : recommendedItemList) {
System.out.println(recommendedItem);
}

}
}

控制台输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"C:\Program Files\Java\jdk1.8.0_144\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1\lib\idea_rt.jar=61415:C:\Program Files\JetBrains\IntelliJ IDEA 2019.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_144\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar;D:\IdeaProjects\practice\target\classes;C:\Users\Simon\.m2\repository\org\apache\mahout\mahout-core\0.9\mahout-core-0.9.jar;C:\Users\Simon\.m2\repository\org\codehaus\jackson\jackson-core-asl\1.9.12\jackson-core-asl-1.9.12.jar;C:\Users\Simon\.m2\repository\org\codehaus\jackson\jackson-mapper-asl\1.9.12\jackson-mapper-asl-1.9.12.jar;C:\Users\Simon\.m2\repository\org\apache\commons\commons-lang3\3.1\commons-lang3-3.1.jar;C:\Users\Simon\.m2\repository\com\thoughtworks\xstream\xstream\1.4.4\xstream-1.4.4.jar;C:\Users\Simon\.m2\repository\xmlpull\xmlpull\1.1.3.1\xmlpull-1.1.3.1.jar;C:\Users\Simon\.m2\repository\xpp3\xpp3_min\1.1.4c\xpp3_min-1.1.4c.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-core\4.6.1\lucene-core-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-analyzers-common\4.6.1\lucene-analyzers-common-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\mahout\commons\commons-cli\2.0-mahout\commons-cli-2.0-mahout.jar;C:\Users\Simon\.m2\repository\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar;C:\Users\Simon\.m2\repository\org\apache\solr\solr-commons-csv\3.5.0\solr-commons-csv-3.5.0.jar;C:\Users\Simon\.m2\repository\org\apache\hadoop\hadoop-core\1.2.1\hadoop-core-1.2.1.jar;C:\Users\Simon\.m2\repository\commons-cli\commons-cli\1.2\commons-cli-1.2.jar;C:\Users\Simon\.m2\repository\com\sun\jersey\jersey-core\1.8\jersey-core-1.8.jar;C:\Users\Simon\.m2\repository\com\sun\jersey\jersey-json\1.8\jersey-json-1.8.jar;C:\Users\Simon\.m2\repository\org\codehaus\jettison\jettison\1.1\jettison-1.1.jar;C:\Users\Simon\.m2\repository\stax\stax-api\1.0.1\stax-api-1.0.1.jar;C:\Users\Simon\.m2\repository\com\sun\xml\bind\jaxb-impl\2.2.3-1\jaxb-impl-2.2.3-1.jar;C:\Users\Simon\.m2\repository\javax\xml\bind\jaxb-api\2.2.2\jaxb-api-2.2.2.jar;C:\Users\Simon\.m2\repository\javax\xml\stream\stax-api\1.0-2\stax-api-1.0-2.jar;C:\Users\Simon\.m2\repository\javax\activation\activation\1.1\activation-1.1.jar;C:\Users\Simon\.m2\repository\org\codehaus\jackson\jackson-jaxrs\1.7.1\jackson-jaxrs-1.7.1.jar;C:\Users\Simon\.m2\repository\org\codehaus\jackson\jackson-xc\1.7.1\jackson-xc-1.7.1.jar;C:\Users\Simon\.m2\repository\com\sun\jersey\jersey-server\1.8\jersey-server-1.8.jar;C:\Users\Simon\.m2\repository\asm\asm\3.1\asm-3.1.jar;C:\Users\Simon\.m2\repository\commons-httpclient\commons-httpclient\3.0.1\commons-httpclient-3.0.1.jar;C:\Users\Simon\.m2\repository\commons-logging\commons-logging\1.0.3\commons-logging-1.0.3.jar;C:\Users\Simon\.m2\repository\commons-codec\commons-codec\1.4\commons-codec-1.4.jar;C:\Users\Simon\.m2\repository\org\apache\commons\commons-math\2.1\commons-math-2.1.jar;C:\Users\Simon\.m2\repository\commons-configuration\commons-configuration\1.6\commons-configuration-1.6.jar;C:\Users\Simon\.m2\repository\commons-collections\commons-collections\3.2.1\commons-collections-3.2.1.jar;C:\Users\Simon\.m2\repository\commons-lang\commons-lang\2.4\commons-lang-2.4.jar;C:\Users\Simon\.m2\repository\commons-digester\commons-digester\1.8\commons-digester-1.8.jar;C:\Users\Simon\.m2\repository\commons-beanutils\commons-beanutils\1.7.0\commons-beanutils-1.7.0.jar;C:\Users\Simon\.m2\repository\commons-beanutils\commons-beanutils-core\1.8.0\commons-beanutils-core-1.8.0.jar;C:\Users\Simon\.m2\repository\commons-net\commons-net\1.4.1\commons-net-1.4.1.jar;C:\Users\Simon\.m2\repository\commons-el\commons-el\1.0\commons-el-1.0.jar;C:\Users\Simon\.m2\repository\org\apache\mahout\mahout-integration\0.9\mahout-integration-0.9.jar;C:\Users\Simon\.m2\repository\commons-io\commons-io\2.4\commons-io-2.4.jar;C:\Users\Simon\.m2\repository\org\apache\mahout\mahout-math\0.9\mahout-math-0.9.jar;C:\Users\Simon\.m2\repository\com\google\guava\guava\16.0\guava-16.0.jar;C:\Users\Simon\.m2\repository\org\apache\mahout\mahout-examples\0.9\mahout-examples-0.9.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-benchmark\4.6.1\lucene-benchmark-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-highlighter\4.6.1\lucene-highlighter-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-queries\4.6.1\lucene-queries-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-memory\4.6.1\lucene-memory-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-queryparser\4.6.1\lucene-queryparser-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-sandbox\4.6.1\lucene-sandbox-4.6.1.jar;C:\Users\Simon\.m2\repository\jakarta-regexp\jakarta-regexp\1.4\jakarta-regexp-1.4.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-facet\4.6.1\lucene-facet-4.6.1.jar;C:\Users\Simon\.m2\repository\org\apache\lucene\lucene-spatial\4.6.1\lucene-spatial-4.6.1.jar;C:\Users\Simon\.m2\repository\com\spatial4j\spatial4j\0.3\spatial4j-0.3.jar;C:\Users\Simon\.m2\repository\com\ibm\icu\icu4j\49.1\icu4j-49.1.jar;C:\Users\Simon\.m2\repository\net\sourceforge\nekohtml\nekohtml\1.9.17\nekohtml-1.9.17.jar;C:\Users\Simon\.m2\repository\org\apache\commons\commons-compress\1.4.1\commons-compress-1.4.1.jar;C:\Users\Simon\.m2\repository\xerces\xercesImpl\2.9.1\xercesImpl-2.9.1.jar;C:\Users\Simon\.m2\repository\org\slf4j\slf4j-log4j12\1.7.25\slf4j-log4j12-1.7.25.jar;C:\Users\Simon\.m2\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;C:\Users\Simon\.m2\repository\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar" com.aliatry.mahout.App
19/05/13 17:36:19 INFO file.FileDataModel: Creating FileDataModel for file D:\data.csv
19/05/13 17:36:19 INFO file.FileDataModel: Reading file info...
19/05/13 17:36:19 INFO file.FileDataModel: Read lines: 24
19/05/13 17:36:19 INFO model.GenericDataModel: Processed 5 users
user : 0
user : 16[3.6425023] 0[3.1900032] 3[2.3574977]
user : 21[1.0]
user : 35[5.0] 6[3.457395]
user : 42[4.0] 4[3.145341]
19/05/13 17:36:19 INFO file.FileDataModel: Creating FileDataModel for file D:\data.csv
19/05/13 17:36:19 INFO file.FileDataModel: Reading file info...
19/05/13 17:36:19 INFO file.FileDataModel: Read lines: 24
19/05/13 17:36:19 INFO model.GenericDataModel: Processed 5 users
根据用户1当前浏览的商品5,推荐2个相似的商品
RecommendedItem[item:2, value:2.0]
RecommendedItem[item:1, value:0.0]
19/05/13 17:36:19 INFO file.FileDataModel: Creating FileDataModel for file D:\data.csv
19/05/13 17:36:19 INFO file.FileDataModel: Reading file info...
19/05/13 17:36:19 INFO file.FileDataModel: Read lines: 24
19/05/13 17:36:19 INFO model.GenericDataModel: Processed 5 users
RecommendedItem[item:3, value:3.5]
RecommendedItem[item:4, value:3.0]

Process finished with exit code 0

项目gitee地址