☰
WEKA数据预处理实战:ARFF格式、CSV转ARFF与离散化避坑
2026/10/27 11:50:43 网站建设 项目流程

简介:这份文档面向刚接触数据挖掘、希望快速上手 WEKA 的读者,围绕 WEKA 平台的基础操作与数据准备展开,适合课程实验、入门练习和算法初探场景。压缩包内共 1 个 doc 文件,约 172KB,篇幅集中,便于按主题通读或随查随用。内容从 WEKA 的开放接口与主要功能切入,介绍数据预处理、分类、回归、聚类、关联规则及可视化等模块,说明实例、属性、关系等核心术语,并重点梳理 ARFF 文件的头信息、属性声明、数据类型与数据区结构;同时提及 CSV 等外部数据的转换准备,可帮助读者理解 WEKA 的数据组织方式并完成基础操作。已有 792 人学习,说明其对入门者具有较稳定的参考价值;对于需要建立数据挖掘工具使用框架、后续开展分类聚类实验的读者,这份文档可作为轻量级起步材料。

1. 搜「weak 操作入门」的人,最后装的都是 WEKA

十有八九是拼错了:想找的是 WEKA,不是 weak。这个跑数据挖掘的老家伙是一套开源机器学习工作台,界面朴素,但预处理、分类、回归、聚类、关联规则、可视化这些活它都能接,而且不用写一行代码就能把一份 CSV 从头跑到出结果。刚上手数据挖掘、手上只有 Excel 和一份业务表的人最适合从它切入:不用先折腾环境,打开就能看见数据长什么样、分布偏不偏、离散化之后分箱落在哪。它把「数据挖掘」这件事拆成了看得见的按钮和参数,代价是它对数据格式有洁癖——喂进去的东西不合规,界面就直接报错给你看。

2. ARFF 文件格式:三段结构、四种类型和三条硬规矩

WEKA 只认一种原生格式,ARFF(Attribute-Relation File Format),本质是一份 ASCII 文本。它把所有数据集都看成二维表:一行是一个实例(Instance),相当于统计里的一个样本、数据库里的一条记录;一列是一个属性(Attribute),相当于一个变量或一个字段;整张表叫一个关系(Relation)。这套术语听着绕,落到文件里其实就是三段结构,看懂之后你手改数据都不慌。

2.1 头信息、属性声明、数据体:三段各管什么

一份合法 ARFF 去掉%开头的注释行之后,只剩两大部分:头信息(Head information)和数据信息(Data information)。头信息里第一行有效内容声明关系名,接着每个属性一行@attribute,最后用@data标记把数据体切开。拿 WEKA 自带的 weather 数据集举例,结构是这样的:

% 这是一个注释行,WEKA 读取时会整行忽略 @relation weather @attribute outlook {sunny, overcast, rainy} @attribute temperature real @attribute humidity real @attribute windy {TRUE, FALSE} @attribute play {yes, no} @data sunny,85,85,FALSE,no sunny,80,90,TRUE,no overcast,83,86,FALSE,yes rainy,70,96,FALSE,yes rainy,68,80,FALSE,yes rainy,65,70,TRUE,no overcast,64,65,TRUE,yes sunny,72,95,FALSE,no sunny,69,70,FALSE,yes rainy,75,80,FALSE,yes sunny,75,70,TRUE,yes overcast,72,90,TRUE,yes overcast,81,75,FALSE,yes rainy,71,91,TRUE,no

@relation后面跟关系名,字符串里如果有空格,必须用单引号或双引号包起来,比如@relation 'bank data'。声明顺序不是装饰:@attribute出现的先后顺序,直接决定了@data区里逗号分隔的每一列对应哪个字段。weather 里 humidity 是第三个声明的属性,所以数据区第三列 85、90、86、96 就是 humidity 的值,你把两条@attribute行调换位置,整份数据的语义就全错了,而且 WEKA 不会报错,它只会安静地算出一堆垃圾结果。

还有一条容易被忽略的规则:最后一个声明的属性被当作 class 属性,也就是分类或回归任务默认的目标变量。weather 里 play 排在最后,所以它自动成为类别列。你把标签列放在第一列,Explorer 打开后分类面板的目标变量就是空的,得手动去设,凡是流程里写死了「最后一列是 class」的脚本都会跟着崩。

2.2 四种数据类型:numeric、nominal、string、date

WEKA 支持的属性类型只有四种,认清它们比记命令重要,因为后面 90% 的报错都源于类型判断错了。

类型写法含义典型场景常见误用
numeric或real连续数值年龄、收入、温度把编码当数值算均值
{a,b,c}分类(nominal)性别、是否已婚取值里有逗号没加引号
string自由文本备注、地址拿去跑分类器
date [format]日期时间交易时间格式串和实际值对不上

日期类型的声明是@attribute <name> date [<date-format>],方括号里是解析和显示格式,省略时默认按yyyy-MM-dd'T'HH:mm:ss这种 ISO-8601 组合解析。格式串本身要用单引号包住内部的字符,比如@attribute ts date 'yyyy-MM-dd HH:mm:ss'。这里有个血泪经验:数据区里的日期字符串必须严格符合声明里的格式,多一个空格、少一个前导零,整行就会解析失败,报出来的错还只说「line N: 无法解析」,不告诉你到底哪一位对不上。稳妥做法是先把日期列当string读进来,用 Filter 转成 date,转成功了再回去改声明。

nominal 属性的坑更隐蔽。取值列表里只要出现逗号、空格、花括号、引号这类字符,单个取值就得加引号,写成{'New York','Los Angeles'}。不加引号的话 WEKA 会把一个值切成两个,于是你得到一列取值数翻倍的 nominal 属性,而且不报错。

2.3 缺失值与稀疏格式:?和花括号两种写法

数据体里的缺失值统一写?,不要写 NULL、NA、空字符串,WEKA 只认问号这一个符号。空字段和?在语义上不同,前者会被当成空字符串,后者才是真正的 missing。

当你的数据极度稀疏——比如几千个商品 ID 做列、每行只有十几个非零值——用常规的逗号分隔会写出一堆零,文件体积爆炸。这时用稀疏格式,一行写成{0 1, 5 3.5, 12 yes},花括号里是「属性下标 值」的键值对,下标从 0 开始,没列出来的属性一律视为 0 或缺失。稀疏格式和普通格式不能在同一份文件里混用,@data之后要么全是普通行,要么全是花括号行。

2.4 手工修改 ARFF 的三条硬规矩

实际项目里改 ARFF 是家常便饭,尤其是把children这种只取 0、1、2、3 的数值列改成 nominal。改之前记住三条:

第一,改类型声明之前先确认这一列所有取值都在新取值集合里。声明成{0,1,2,3}但数据里冒出一个 4,WEKA 直接报「value not declared」,整份文件打不开,你得回去数哪一行越界了。

第二,改 nominal 的取值列表顺序会影响内部编码。WEKA 内部把 nominal 值映射成 0、1、2 的索引,顺序一变,之前训好的模型里那些阈值就全错位了。要么一次定死不再改,要么改了之后重训。

第三,改完一定要重新打开验证。Explorer 里选中那一列,区域 6 的 Type 从 Numeric 变成 Nominal,说明改对了;如果还是 Numeric,多半是你改的是副本,或者文件编码带了 BOM 导致第一行@relation没被识别,整份头信息被当成了数据。

提示:ARFF 用 UTF-8 保存,别用带 BOM 的 UTF-8。BOM 藏在文件开头,肉眼看不见,WEKA 读到之后会把第一个@relation当成非法行跳过,然后属性数量对不上,报错信息驴唇不对马嘴。

3. CSV 转 ARFF 的三条路线:命令行、GUI 和 Java API

现实里的数据几乎不会是 ARFF。业务系统导 Excel、统计脚本吐 CSV、数值计算环境存矩阵,这些格式 WEKA 都能接,但都得先转一道。转换本身不难,难在转换过程中类型判断错了你还不知道,等到建模阶段才发现某一列被当成了字符串。下面三条路线按使用频率排,各有各的适用边界。

3.1 路线一:Simple CLI 里的一行命令

启动 WEKA 主程序,GUI 下方有一排按钮,点进 Simple CLI 模块,窗口最下方是输入框(上方那块是只读输出区,敲不进去字)。直接输入:

java weka.core.converters.CSVLoader bank-data.csv > bank-data.arff

回车执行,输出区会打印转换过程中的信息。这行命令干的事情是:调用weka.core.converters.CSVLoader读入 CSV,默认把第一行当表头解析成属性名,把每个字段自动推断成 numeric 或 nominal,然后把结果以 ARFF 格式打到标准输出,重定向到文件。因为是在 WEKA 运行时内部执行,不用额外指定 classpath。

自动推断的规则是:整列都能解析成数字就当 numeric,否则当 nominal。这条规则在两种情况下会翻车。一是 ID 列,1001, 1002, 1003全数字,被当成 numeric,于是 WEKA 认为这个变量有连续取值,算均值算方差,毫无意义。二是本该是 nominal 的数字编码列,比如sex列存的是 0/1,被推断成 numeric,后面所有只接受 nominal 的算法全用不了。这两种情况都要在转换后手工改声明,或者用后面 3.3 的 API 显式指定。

CSVLoader 还支持几个实用参数,值得记一下:

参数作用什么时候用
-H声明文件没有表头数据第一行就是记录
-M <符号>指定缺失值标记源文件用\N、NA表示空
-F <列号>强制某些列按 nominal 读数字编码的分类列
-D <格式>指定日期解析格式带时间戳的日志表
-S输出稀疏格式高维稀疏矩阵

-F的参数写法是逗号分隔的列索引,支持区间,比如-F 2,5,7-10。注意列号从 1 开始数,和 Explorer 里属性列表左边显示的数字一致。

3.2 路线二:Explorer 打开再另存

不想碰命令行的话,在 Explorer 的 Preprocess 面板点 Open file,文件类型下拉框选 CSV,选中文件打开,WEKA 会走同一套推断逻辑。打开之后点 Save,类型选 ARFF,另存即可。这条路的额外价值是你能立刻在区域 5 看到每一列被推断成了什么类型,在区域 6 看到选中列的摘要(Type、Missing 数量、Distinct 数量、Min/Max、均值标准差),类型错了当场就能发现。

前置环节也有讲究。Excel 的 xls 文件可以放多张工作表,而 WEKA 一次只认一张表,所以必须切到目标工作表,另存为 CSV,遇到「只保存当前工作表」的提示点确定。数值计算环境里存的矩阵用csvwrite('bank-data.csv', matrixname)这类命令导出,导出的文件通常没有属性名,得先用文本编辑器手工补一行表头,属性名个数必须和列数严格一致,用逗号分隔,少一个多一个都会让后面的解析整体错位。

补表头这件事看着琐碎,它是新手最容易翻车的一步。源文件没有表头时,WEKA 会把第一行数据当成属性名,于是你的属性名变成25,43,1这种非法字符串,属性声明直接失败;更糟的情况是第一行恰好能解析,于是第一条样本静默消失,你拿 999 条数据训练却以为是 1000 条。

3.3 路线三:Java API 批量转换并锁定类型

数据集一多,命令行一行行敲就不现实了。用 Java API 写个小工具,把类型判断规则固化下来,以后每次转换都跑同一套逻辑,口径才不会漂。下面这段可以直接编译运行,把weka.jar加进 classpath:

import java.io.File; import weka.core.Instances; import weka.core.converters.ArffSaver; import weka.core.converters.CSVLoader; public class Csv2Arff { public static void main(String[] args) throws Exception { File in = new File(args[0]); File out = new File(args[1]); CSVLoader loader = new CSVLoader(); loader.setSource(in); loader.setFieldSeparator(','); // 分隔符,分号表改成 ';' loader.setNoHeaderRowPresent(false); // 第一行是表头 loader.setMissingValue("?"); // 源文件的缺失标记 loader.setNominalAttributes("2,5,7-10"); // 强制这些列按分类读 Instances data = loader.getDataSet(); // 一次性读入内存 ArffSaver saver = new ArffSaver(); saver.setInstances(data); saver.setFile(out); saver.setDestination(out); // 3.6 之后必须显式设置 saver.writeBatch(); System.out.println(data.numInstances() + " 条 / " + data.numAttributes() + " 列"); } }

编译运行两行命令:

javac -cp weka.jar Csv2Arff.java java -cp .:weka.jar Csv2Arff bank-data.csv bank-data.arff

逻辑很直白:CSVLoader负责读,setNominalAttributes把「看起来像数字但其实是编码」的列钉死成 nominal,getDataSet()一次性把整份数据装进Instances对象,ArffSaver负责写。三处参数最值得改:setFieldSeparator遇到分号或制表符分隔的表必须换;setMissingValue要和源文件一致,源文件用\N你就写\N;setNominalAttributes的列号列表是从业务语义出发的,写完最好回头看一眼生成的 ARFF 头信息确认无误。

getDataSet()是批量读取,整份数据驻留内存,百万行级别的表需要调大堆内存:java -Xmx4g -cp .:weka.jar Csv2Arff ...。如果你的数据真到了这个量级,更合适的是用增量转换,边读边写,但那需要自己实现Loader和Saver的流式接口,日常项目一般用不上。

3.4 转换之后必须做一次列数校验

不管走哪条路线,转完都别急着建模。写个十几行的校验脚本,把每行的字段数和@attribute声明数对一遍,能挡掉绝大多数低级问题:

import csv, sys def check(path): n_attr, in_data, bad = 0, False, [] with open(path, encoding='utf-8-sig') as fh: # utf-8-sig 顺手吃掉 BOM for lineno, raw in enumerate(fh, 1): line = raw.strip() if not line or line.startswith('%'): # 空行与注释跳过 continue low = line.lower() if low.startswith('@attribute'): n_attr += 1 elif low.startswith('@data'): in_data = True elif in_data and not line.startswith('{'): cols = next(csv.reader([line], skipinitialspace=True)) if len(cols) != n_attr: bad.append((lineno, len(cols))) return n_attr, bad n, bad = check(sys.argv[1]) print(f"属性数 {n},错行列数 {len(bad)}") for lineno, cnt in bad[:10]: # 只打印前 10 条 print(f" 第 {lineno} 行有 {cnt} 列")

这段脚本按行扫,遇到@attribute计数,遇到@data之后开始比对列数,csv.reader负责处理引号包裹的取值。有个已知局限:它按双引号规则解析,而 ARFF 允许单引号,遇到含逗号的单引号取值可能误判,所以报出来的错行要人工复核一眼。跑通之后你会拿到一个很实在的数字——如果有错行,说明源 CSV 里有未转义的逗号藏在字段内部,那才是真正要修的地方。

4. Explorer 八大区域实战:删列、改类型、离散化

Explorer 是 WEKA 里用得最多的模块,界面初看密密麻麻,按功能切成八块之后就清楚了。区域 1 是一排选项卡,切换 Preprocess、Classify、Cluster、Associate、Select attributes、Visualize 六类任务面板,日常九成时间待在 Preprocess。区域 2 是常用按钮组:打开文件、打开 URL、连数据库、生成随机数据、撤销、编辑、保存。区域 3 是 Filter 选择区,Choose旁边那个文本框显示当前选中的过滤器及其参数,点它弹窗改参数。区域 4 显示数据集概况:关系名、实例数、属性数。区域 5 列出所有属性,左边数字是列下标,前面有勾选框,上方一排按钮做批量勾选(All、None、Invert、Pattern)。区域 6 是选中属性的摘要,数值型和分类型的摘要项目不同。区域 7 是直方图,默认按 class 着色。区域 8 是状态栏,右侧那只鸟在动就说明任务还在跑,右键可以手动触发垃圾回收。

4.1 删掉 ID 列和明显无用的字段

业务表里通常有一两列是纯标识符,比如客户编号、订单流水号。这类列对挖掘任务毫无贡献,数值型还会把均值方差算歪,第一步就该删。

在区域 5 勾选id,点区域 2 的Remove,列就没了。误删了按Undo能找回来,但 Undo 只回退一步,连续删三列就找不回第一列了,所以删之前先 Save 一份。

同样的效果用 Filter 也能做,而且可复现:

java -cp weka.jar weka.filters.Filter \ -F "weka.filters.unsupervised.attribute.Remove -R 1" \ -i bank-data.arff -o bank-data-no-id.arff

-R 1表示删第 1 列。要删多列写-R 1,5,7-9;反过来保留指定列用-V。weka.filters.Filter这个入口是通用的,-F后面跟任意过滤器的完整类名加参数,所有预处理都能这么串。

4.2 类型纠偏:把只有四个取值的数值列改成 nominal

bank-data 数据集里有三个数值列:age、income、children。其中children只取 0、1、2、3 四个值,本质上是分类变量。有些算法(比如只处理 nominal 的朴素贝叶斯变体)要求所有属性都是分类型,这时候就得改声明。

最简单的改法是在文本编辑器里把这一行:

@attribute children numeric

改成:

@attribute children {0,1,2,3}

保存,回 Explorer 重新打开,选中children,区域 6 里 Type 显示 Nominal 就说明改对了。这一步看着粗糙,但比走 Discretize 过滤器更精确——你明确知道应该分成几类、边界在哪,而不是让算法替你猜。

4.3 Discretize 的参数:-B、-M、-R 到底怎么定

age和income这种真正连续的变量,要变成分类型就得靠离散化。区域 3 点Choose,在过滤器树里逐级找到weka.filters.unsupervised.attribute.Discretize,点中后文本框会显示类似Discretize -B 10 -M -0.1 -R first-last的默认参数串(不同小版本显示略有差异)。点这个文本框弹出参数窗口,逐项改。

参数含义默认建议
-B分箱数量10业务可解释的段数,3~6
-M用 MDL 准则自动决定箱数关样本量大时开
-R作用的属性范围first-last明确写列号
-D等频分箱而非等宽关分布严重偏斜时开

-R这一项一定要改。默认first-last会把所有数值列都离散化,包括你不想动的列;而且如果 class 属性恰好是数值型,它也会被一起切碎,后面的分类任务直接失效。bank-data 里需要离散化的是第 1 列和第 4 列(区域 5 属性名左边的数字就是列号),所以-R填1,4。计划各分 3 段,-B改成 3,其余不动,点 OK 回到主界面,再点Choose右边的Apply,区域 5 里age和income的 Type 立刻变成 Nominal。

等宽和等频的差别值得单独说一句。等宽是把数值范围均分成若干段,遇到收入这种长尾分布,可能 95% 的样本全落在第一个箱里;等频是让每个箱里的样本数大致相等,分布再偏也能切匀,代价是箱的边界变成难看的浮点数,业务上不好解释。选哪个取决于下游是给业务看还是给模型用。

4.4 把(-inf-34.333333]换成看得懂的标签

Discretize 生成的 nominal 取值是区间表达式,形如(-inf-34.333333],看着头疼,而且到报告里没法交差。改法是保存 ARFF 之后用文本编辑器打开,把每一处区间字符串统一替换成业务语义的标签,比如(-inf-34.333333]全部替换成0_34,(34.333333-56.666667]替换成35_56,依次类推。

替换要注意两点。一是区间表达式里含有括号、减号、点号,某些文本编辑器会把这些当正则元字符,务必用「纯文本替换」而不是正则替换,否则可能只替换掉一部分。二是替换后的标签不能重名,也不能和别的 nominal 属性的取值冲突——虽然 ARFF 不禁止,但做可视化时图例会糊成一片。

5. 避坑与排查:五条反复出现的翻车记录

预处理这条链路上,报错信息普遍不友好,WEKA 经常只丢一句「Problem reading file」就没了。下面五条是反复出现、且每次都要重新想一遍的问题,记下来能省不少时间。

5.1 现象:实例数比预期少一条,属性名变成了一堆数字

原因:源 CSV 没有表头,CSVLoader 默认把第一行当属性名解析,于是第一条样本被吃掉,属性名变成25、43、1这种非法字符串。

解决:转换前给源文件补一行表头,或者在命令行加-H让加载器自己生成Attribute0、Attribute1。补表头更推荐,属性名有意义,后面看摘要和建模型都省事。补完之后重新跑一遍 3.4 的校验脚本,确认实例数对得上。

5.2 现象:分类面板里找不到目标变量,或者目标变量选错了列

原因:WEKA 默认把最后一个声明的属性当 class,而源数据里标签列放在了中间,或者干脆没有标签列。

解决:两个方向。要么在 ARFF 里把标签列挪到最后(同时调整@data区每一列的逗号顺序,这一步很容易漏),要么在 Preprocess 面板底部那个None下拉框里手动指定 class 属性。手动指定更安全,因为它不改文件结构。要提醒的是,手动指定的设置不会自动保存到 ARFF 里,下次重新打开又变回默认,所以脚本化流程里最好显式写data.setClassIndex(n)。

5.3 现象:Apply 之后报「attribute is not numeric」,或者离散化没生效

原因:-R指定的列里混进了 nominal 属性,Discretize 只处理数值列,遇到分类型直接抛异常。另一种情况是你选的过滤器并不是 Discretize,Choose树点偏了一格,参数看着像但类名不对。

解决:先看区域 3 文本框里的完整类名是不是weka.filters.unsupervised.attribute.Discretize,再对照区域 5 的数字确认-R里列的每一列 Type 都是 Numeric。改完之后记得点Apply才真正作用到数据集上,只改参数不点 Apply,界面不会有任何变化,很容易误以为参数没生效。

5.4 现象:设了-B 3,结果分出来 5 个箱

原因:-M打开了 MDL 准则,此时-B不再是固定箱数,而是箱数的上限,MDL 会在这个上限内自己挑一个它认为最优的数量。

解决:要固定箱数就把-M关掉。反过来,如果你希望算法自己决定切几段,就别纠结-B的实际效果,接受它给出的结果,然后在业务层面检查每个箱的样本量是否够——某个箱里只有两三条样本,说明这个分箱对模型没有任何信息量。

5.5 现象:大文件读到一半抛 OutOfMemoryError,或者中文列名变乱码

原因:前者是整份数据一次性载入内存,默认堆内存不够;后者是文件编码不是 UTF-8,或者带了 BOM。

解决:内存问题加-Xmx参数,命令行写成java -Xmx4g -cp weka.jar ...,图形界面则改启动脚本里的 JVM 参数。真要处理超出内存的数据,就得换增量加载的路子,或者先在数据库侧做聚合。编码问题用不带 BOM 的 UTF-8 重新保存,然后把属性名里的中文尽量换成英文短名——不是 WEKA 不支持中文,而是中文列名在导出报告、跨工具传递时到处是坑,早换早省心。

6. 把预处理固化成流水线:命令行串起来 + FilteredClassifier

图形界面点着顺手,但它有个致命问题:不可复现。同一个人隔一周再点一遍,-R可能填成1-4,-B可能顺手改成 5,最后模型效果对不上,你还得回头猜是哪一步不一样。我的做法是先用 Explorer 把参数试出来,试好之后立刻翻译成命令行,固化成脚本。

#!/usr/bin/env bash set -euo pipefail # 任何一步失败立刻停,别带着错数据往下跑 JAR=/opt/weka/weka.jar # 换成你本机的路径 # 1) CSV 转 ARFF,先把编码列钉成 nominal java -cp "$JAR" weka.core.converters.CSVLoader \ -F 2,5,7-10 bank-data.csv > step1.arff # 2) 删掉 ID 列 java -cp "$JAR" weka.filters.Filter \ -F "weka.filters.unsupervised.attribute.Remove -R 1" \ -i step1.arff -o step2.arff # 3) 只对第 1、4 列做等宽离散化,各分 3 箱 java -cp "$JAR" weka.filters.Filter \ -F "weka.filters.unsupervised.attribute.Discretize -B 3 -R 1,4" \ -i step2.arff -o step3.arff

三步各自独立、每步落一个中间文件,出问题时能精确知道是哪一步坏的,这比一步到位的长管道好排查得多。set -euo pipefail那行别省,WEKA 的过滤器在某些情况下返回码是 0 但输出文件是空的,光靠返回码判断不住,所以脚本末尾最好再加一句产物检查——文件存在且非空才算过。

更值得花时间的是第二件事:把预处理和模型绑在一起。很多人先在 Preprocess 面板把数据离散化,再切到 Classify 面板训练,训练完保存模型,上线时拿一份新的原始数据直接丢给模型打分。这里有个隐蔽的不一致——模型是在离散化之后的数据上训的,而新数据没走同一个离散化,箱的边界对不上,打出来的分数全是错的,而且不会报错,只是效果莫名其妙地差。

WEKA 给的解法是FilteredClassifier:把过滤器包在分类器内部,训练和预测时自动走同一套预处理。

import weka.classifiers.meta.FilteredClassifier; import weka.classifiers.trees.J48; import weka.filters.unsupervised.attribute.Discretize; import weka.core.Instances; import weka.core.converters.ConverterUtils.DataSource; DataSource src = new DataSource("step2.arff"); Instances data = src.getDataSet(); data.setClassIndex(data.numAttributes() - 1); // 最后一列是标签 Discretize dis = new Discretize(); dis.setAttributeIndices("1,4"); dis.setBins(3); FilteredClassifier fc = new FilteredClassifier(); fc.setFilter(dis); // 预处理挂进模型 fc.setClassifier(new J48()); // 分类器本体 fc.buildClassifier(data);

这样保存下来的模型文件里带着过滤器参数,预测时喂原始数据进去,内部会先跑一遍离散化再分类。参数口径这件事,一旦落到代码里就不需要靠人的记忆维持了。

参数速查留一份,方便回来对:

环节参数我常用的取值
CSVLoader-F强制 nominal 列按业务语义手动列,不用自动推断
Remove-R删除列 /-V保留列删 ID 类字段
Discretize-B箱数、-R列范围、-MMDL-B 3~6,-R写死列号
FilteredClassifiersetFilter/setClassifier预处理与模型绑定保存

从那以后我每次做数据预处理,都强制自己走一遍「GUI 试参 → 命令行固化 → FilteredClassifier 打包」这三步,哪怕只是一个几十行的玩具数据集。因为踩过一次上线后分数全歪、排查两天才发现是新数据没走离散化的坑,那种感觉不想再体验第二次。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询