如何将Weka的Instance实例关联绑定到自定义业务对象
Weka K近邻结果关联原始业务对象的实现方法
Weka本身没有提供直接给Instance绑定外部自定义业务对象的原生挂载接口,不用魔改源码,有两种成熟方案可以解决关联问题:
方案1:新增独立ID属性(最推荐,全场景兼容)
这是Weka用户最常用的标准做法,完全走框架原生能力,不会有兼容问题:
- 构建
Instances属性集的时候,在属性列表最前面加一个专门存唯一标识的属性(数值、字符串类型都可以),存每个业务对象的主键,或者原始对象列表里的顺序序号 - 配置距离函数的时候把这个ID属性排除在计算范围外就行,完全不会影响KNN的距离计算结果。你现在写的
EuclideanDistance配置里setAttributeIndices("2-last")刚好适配这个方案——只要把ID属性放在第0位,距离计算就会自动跳过这个字段,和你现有配置无缝衔接 - 拿到KNN返回的近邻实例之后,直接读实例里存的ID值,就能和你原始的Ticket列表做匹配。
修改后的数据集构建核心代码:
public static Instances createWekaInstances(List<Ticket> tickets, String name) { // 首位加ID属性,不参与距离计算 Attribute id = new Attribute("ticket_id"); Attribute x = new Attribute("x"); //sqrt of row pos Attribute y = new Attribute("y"); // section cv ArrayList<Attribute> attributes = new ArrayList<Attribute>(); attributes.add(id); attributes.add(x); attributes.add(y); Instances ticketInstances = new Instances(name, attributes, 0); ticketInstances.setClassIndex(ticketInstances.numAttributes() - 1); for (Ticket ticket : tickets) { Instance inst = new DenseInstance(ticketInstances.numAttributes()); inst.setDataset(ticketInstances); // 写入业务对象的唯一标识 inst.setValue(id, ticket.getId()); inst.setValue(x, Math.sqrt(ticket.getRowPosition())); inst.setValue(y, ticket.getSectionCVS()); ticketInstances.add(inst); } return ticketInstances; }
方案2:通过实例索引映射(零属性侵入)
如果不想给数据集加额外字段,可以直接靠实例位置做映射:
- 构建
Instances的时候,实例插入的顺序和传入的原始tickets列表顺序是严格一一对应的 - 拿到KNN返回的近邻实例后,别直接用它在返回的
neighbors结果集里的索引,要调用原始数据集的ticketInstances.indexOf(neighborInst)方法,查到这个实例在原始数据集里的位置,这个位置和tickets列表里的元素位置是一一对应的,直接取同位置的Ticket对象就行 - 注意这个方案只适合数据集构建完之后不做删改、重排、过滤的场景,一旦对原始
Instances做过排序、删实例操作,索引映射关系就会失效。
踩坑提醒:别想着继承
DenseInstance加自定义字段来挂业务对象,Weka在构建BallTree、计算距离的流程里会做实例拷贝,自定义的非框架字段不会被复制,运行过程中会出现数据丢失问题。
你现在用的BallTree配置本身没问题,配合上面任意一种映射方案,就能解决近邻结果没法关联原始业务对象的问题。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

