返回介绍

DataModel

发布于 2025-02-22 11:29:55 字数 8831 浏览 0 评论 0 收藏 0

DataModel 类用于对推荐算法所使用的数据进行准备. 主要完成对不同类型数据的读取,组织结构 ,分割数据集,根据配置项对数据进行二值化处理等. 相应的,定义为 DataModel 类型的变量在指向子类的方法时,需要传出 Configuration 类型的对象. 其中读取文件路径等配置项可以使用 setConf 来设置. 相应的,在 Java 代码中,可以根据读取数据类型直接生成对应的 DataModel. 生成构造器的参数为 Configuration 的对象. 之后调用 buildDataModel 进行读取和分割.具体的数据读取过程与分割过程需要在调用 buildDataModel 之前通过 setConf 的方式传入对象中. 具体 java 代码如下

DataModel dataModel = new TextDataModel(conf);
dataModel.buildDataModel();

1. Convertor

Convertor 读取的数据集文件夹路径通过 dfs.data.dir 配置项读取,数据集名称通过 data.input.path 指定. 之后根据数据类型配置项读取文件夹下所有数据,并以 SparseTensor 形式保存. data.column.path 用于指定数据集每一列的含义.data.convertor.binarize.threshold 为而值化时所采用的阈值,即当数值大于阈值时为 1, 小于阈值时为 0. 当阈值小于 0 时,默认不进行二值化处理. 相关配置项示例:

dfs.data.dir=../data
data.input.path=filmtrust # dataset name
data.column.format=UIR # user-item-rating
data.convert.binarize.threshold=-1.0
data.model.format=text

LibRec 还可以读取 UIRT 格式的数据,示例配置项如下:

dfs.data.dir=../data
data.input.path=filmtrust
data.column.format=UIRT
data.convertor.binarize.threshold=-1.0
data.model.format=text

当数据列大于 4 时,需要使用 arff 格式的数据来进行存储. 相应的推荐配置项为

dfs.data.dir=../data
data.input.path=arffsetname
data.model.format=arff

在 Java 中的需要使用 Configuration 类的 set 方法来依次写入对象。

Configuration conf = new Configuration();

conf.set("dfs.data.dir","../data");
conf.set("data.input.path","filmtrust");
conf.set("data.column.format","UIRT");
conf.set("data.conver.binariza.threshold","-1.0");

实现时可以使用 DataModel 完成全部操作操作,也可以单独实例出 Convertor 对象用于读取数据. 进行读取以及获取相应数据的示例代码如下

Configuration conf = new Configuration();

conf.set(Configured.CONF_DATA_COLUMN_FORMAT, "UIR");
conf.set("inputDataPath", conf.get("dfs.data.dir") + "/test/matrix4by4.txt");
textDataConvertor = new TextDataConvertor(conf.get("inputDataPath"));
textDataConvertor.processData();

SparseMatrix preference = textDataConvertor.getPreferenceMatrix();
SparseMatrix datetimeMatrix = textDataConvertor.getDatetimeMatrix();

相对应的,对 Arff 格式的数据进行读取需要实例 ArffDataConvertor 对象. 进行读取以及获取相应数据的示例代码如下:

Configuration conf = new Configuration();
conf.set("dfs.data.dir","../data");
conf.set("inputDataPath", conf.get("dfs.data.dir") + "/path/to.arff");
ArffDataConvertor arffLoder = new ArffDataConvertor(conf.get("inputDataPath"));
arffLoder.readData();
SparseTensor sparseTensor = arffLoder.getSparseTensor();
ArrayList<ArffInstance> instances = arffLoder.getInstances();
String s1 = arffLoder.getRelationName();
String s2 = arffLoder.getAttributes().get(0).getName();

2. Splitter

LibRec 中含有数据的划分方式共五类,将数据集根据一定比例划分为训练集与测试集(及验证集), 留出其中一个作为验证,给定 N 个作为验证, K 折交叉验证,以及测试数据集与训练数据集等五种方式. 其中部分分割方式又含有基于 user 或 item 等其他分割方式。

2.1 ratio

根据比例来进行划分数据集。

data.model.splitter=ratio
data.splitter.ratio=rating # by rating
data.splitter.trainset.ratio=0.8 # resting data used as test set

在 Java 中示例代码如下:

conf.set("data.splitter.ratio", "rating");
conf.set("data.splitter.trainset.ratio", "0.8");

// TextDataConvertor convertor = new TextDataConvertor(args)
convertor.processData();
RatioDataSplitter splitter = new RatioDataSplitter(convertor, conf);
splitter.splitData();

其中 data.splitter.ratio 的配置可以使用 rating, user, userfixed, item, valid, ratingdate, userdate, itemdate. userfixed 在数据量较小时可以获得更精确的划分结果. 使用 valid 时还需要指定 data.splitter.validset.ratio. 附带有 date 的方法为根据数据量在 date 序列上进行划分. 在时间数值上较大的划分为 testset, 时间数值较小的划分为 trainset.

2.2 loocv

随机留出一位或者留出最后一位 user 或者 item 来作为测试数据,剩下的数据作为训练数据

data.model.splitter=loocv
data.splitter.loocv=user

在 Java 中示例代码如下:

conf.set("data.splitter.loocv", "user");
convertor.processData();

LOOCVDataSplitter splitter = new LOOCVDataSplitter(convertor, conf);
splitter.splitData();

其中 data.splitter.loocv 的配置可以使用 user, item, userdate, itemdate. 附带 date 的配置会先按时间顺序进行排序,选取每个 user 或 item 最新的评分记录组成测试集。

2.3 givenn

保留 n 个 user 或 item 作为测试数据,剩下的数据作为训练数据。

data.model.splitter=givenn
data.splitter.givenn=user
data.splitter.givenn.n=10

在 Java 中,示例代码如下

conf.set("data.splitter.givenn", "user");
conf.set("data.splitter.givenn.n", "1");
convertor.processData();

GivenNDataSplitter splitter = new GivenNDataSplitter(convertor, conf);
splitter.splitData();

其中 data.splitter.givenn 的配置可以使用 user, item, userdate, itemdate.

2.4 kcv

K 折交叉验证. 即将数据集划分为 K 份,每次选择其中一份作为测试数据集,余下数据作为验证数据集,共进行 K 次.每次会进行一次评估,在 K 折结束之后会再次对 K 折计算结果进行一次评估。

data.model.splitter=kcv
data.splitter.cv.number=5 # K-fold

在 Java 中,示例代码如下

convertor.processData();
KCVDataSplitter splitter = new KCVDataSplitter(convertor, conf);

for (int i = 1; i <= 6; i++) {
  // split into 5 parts by default
  splitter.splitFolds();
  splitter.splitData(i);
}

2.5 testset

预留出部分数据集作为测试数据集. 这里需要设置配置项 data.testset.path 也就是指定预留出测试数据的路径. 这个路径要在训练数据的路径之下. 也就是说,在读取所有数据时,预留出的测试数据也应该被读取到。

data.model.splitter=testset
data.testset.path=nameoftestfile/dir

其中 Java 示例代码如下

conf.set("inputDataPath", conf.get("dfs.data.dir") + "/given-testset");
conf.set(Configured.CONF_DATA_COLUMN_FORMAT, "UIR");
conf.set("data.testset.path", "/given-testset/test/ratings_0.txt");
convertor = new TextDataConvertor(conf.get(Configured.CONF_DATA_COLUMN_FORMAT), conf.get("inputDataPath"));
convertor.processData();
GivenTestSetDataSplitter splitter = new GivenTestSetDataSplitter(convertor,conf);
splitter.splitData();

3. Appender

部分算法(如 rste 算法) 需要引入不同 user 或者不同 item 之间的关系矩阵,因此在 LibRec 中实现了针对于 user-user-relation 或者 item-item-relation 的数据读取类.在配置文件中需要增加对配置项 data.appender.classdata.appender.path 的配置。

通过文件的示例配置如下

data.appender.class=social
data.appender.path=directory/to/relationData

在 Java 中,示例代码如下:

String inputPath = conf.get("dfs.data.dir") + "/" + conf.get("data.input.path");
TextDataConvertor textDataConvertor = new TextDataConvertor(inputPath);
textDataConvertor.processData();
conf.set("data.appender.path", "test/datamodeltest/trust.txt");
SocialDataAppender dataFeatrue = new SocialDataAppender(conf);
dataAppender.setUserMappingData(textDataConvertor.getUserIds());
dataAppender.processData();

4. Java code Snippet

如果用于 LibRec 中的算法,直接通过 conf 来设定参数并用于生成相应的 DataModel 是比较合理的做法. 对于 Text 与 Arff 格式的数据可以分别实例相应的 DataModel 来进行读取.具体实现方式如下:

Configuration conf = new Configuration();

conf.set("dfs.data.dir","../data");
conf.set("data.input.path","filmtrust");
conf.set("data.column.format","UIRT");
conf.set("data.convertor.binariza.threshold","-1.0");

conf.set("data.model.splitter","ratio");
conf.set("data.splitter.ratio","rating");
conf.set("data.splitter.trainset.ratio","0.8");

DataModel dataModel = new TextDataModel(conf);
dataModel.buildDataModel();

arff 格式的实例如下:

Configuration conf = new Configuration();

conf.set("dfs.data.dir","../data");
conf.set("data.input.path","filmtrust");
conf.set("data.column.format","UIR");
conf.set("data.convertor.binariza.threshold","-1.0");

conf.set("data.model.splitter","ratio");
conf.set("data.splitter.ratio","rating");
conf.set("data.splitter.trainset.ratio","0.8");

DataModel dataModel = new ArffDataModel(conf);
dataModel.buildDataModel();

如果分割方式采用 KCV 或者 Loocv 等方式,在分割数据集之前,还需要设置测试集的索引. 示例如下

Configuration conf = new Configuration();

conf.set("dfs.data.dir","../data");
conf.set("data.input.path","filmtrust");
conf.set("data.column.format","UIR");
conf.set("data.convertor.binariza.threshold","-1.0");

conf.set("data.model.splitter","kcv");
conf.set("data.splitter.cv.number","5")
conf.set("data.splitter.cv.index","1")
DataModel dataModel = new TextDataModel(conf);
dataModel.buildDataModel();

其中配置项 data.splitter.cv.index 的取值范围为 1 到 data.splitter.cv.number. 之后执行算法时,只是针对于当前这次训练集测试集合进行计算. 因此如果要统计所有次的结果,还需要实现循环来分别设置配置项 "data.splitter.cv.index" 并进行分割执行算法。

相应的引入 Appender 矩阵的,只用加上相应的配置项即可. 不再单独列出。

在数据读取过程中,会检测是否已经进行的数据读取,如果已经读取则不再进行读取和分割. 因此在同一次运行多次执行 buildDataModel 会重新索引训练集和测试集但是不会重新读取和分割。

目前针对于 DataModel 没有设置以 Convertor 和 Splitter 为参数的构造器以及 set 方法,因此单独生成的 Convertor, Splitter, 与 Appender 实例不能传入到 DataModel 中。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文