ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

WEKA中文详细教程:274页PPT讲透ARFF格式、数据预处理与分类聚类全流程

WEKA中文详细教程:274页PPT讲透ARFF格式、数据预处理与分类聚类全流程

简介:这份《WEKA中文详细教程PPT》面向数据挖掘与机器学习初学者、高校课程学习者及需要快速熟悉WEKA操作的读者,围绕开源工具WEKA的中文入门与系统梳理展开,帮助建立从数据集导入、预处理到建模评估的完整认知。压缩包内共1个PPT文件,约14.29MB,以课件形式集中呈现核心内容,并保留较清晰的章节层次,便于课堂讲授、自学查阅和复习归档。内容覆盖WEKA简介、数据集与ARFF文件格式、数据准备、数据预处理、分类、聚类、关联规则、属性选择、数据可视化及知识流界面,并详细拆解Explorer环境的八大功能区域与数据集管理方式,对课程作业、实验演示和算法对比具有直接参考价值。已有168人学习,适合不同基础读者按需查阅,也可供研究者在算法选择与结果解释时对照参考。

1. 一份 PPT 版的 WEKA 中文详细教程,解决的是“菜单认识字但流程跑不动”的问题

做数据挖掘课设那阵子最难受的不是算法不会,是打开一个全英文界面,几十个下拉框不知道先点哪个。这份 WEKA 中文详细教程就是针对这个场景的课程资源:一份 274 页的 PPT,从 WEKA 简介、数据集、数据准备、数据预处理,一路铺到分类、聚类、关联规则、选择属性、数据可视化,最后落到知识流界面。它不讲公式推导,讲的是每个面板点哪里、参数填什么、输出框里那几行数字怎么读。适合三类人:第一次碰 WEKA 的学生、带实验课的助教、以及想拿现成工具给一份表格跑个基线模型再谈结果的工程师。把它当操作手册翻,比当教材读有用得多。

2. 拆解教程的九个模块:先跑通一条主线,再回头补细节

拿到一份 274 页的 PPT,最常见的错误是从第一页顺着往下翻。翻到分类那一章(第 63 页)时,前面的数据预处理已经忘得差不多了,而聚类(184 页)、关联规则(225 页)、选择属性(244 页)这三块加起来占了将近一半篇幅,顺着读会陷在细节里出不来。合理的做法是先看清各模块的体量和依赖关系,再按自己的目标挑一条主线走。

2.1 九个模块的真实工作量分布

把目录页码换算成页数,能直接看出作者的用力方向。分类和聚类两章合计 120 多页,是整个教程的重心;数据准备和预处理不到 40 页,但这两块没弄明白,后面所有算法都会跑出莫名其妙的结果。

模块起始页大致页数依赖关系建议投入
WEKA 简介29无快速浏览
数据集1113简介精读,格式是地基
数据准备2412数据集精读
数据预处理3627数据准备精读,Filters 全在这里
分类63121预处理重点,选两三个算法吃透
聚类18441预处理重点,配合可视化看
关联规则22519数据准备按需
选择属性2449预处理按需,写论文常要
数据可视化25322数据集快速过
知识流界面275剩余全部做批量实验时再回来看

这张表最有价值的信息是“分类一章 121 页”这个数字。它意味着教程把绝大部分篇幅给了监督学习,如果你的任务是聚类或者找关联规则,别指望在对应章节里找到同等深度的参数讲解,得自己补。反过来,如果你的目标是用 WEKA 跑一次对比实验写进报告,那第 63 页往后的分类章节就是主战场,前面几百页都是为它服务的。

教程里给的下载入口是 3.6 系列那个自带 JRE 的 Windows 安装包。这个版本号的安装包好处是装完双击就能用,不用自己配 Java 环境;代价是它绑定的 JRE 版本比较老,如果你机器上已经装了新版本 JDK,可能会遇到两个 Java 并存导致的启动异常。我一般的做法是装不带 JRE 的 zip 包,然后在启动脚本里显式指定 java 路径,环境干净,出问题也好定位。

2.2 三条学习路径,对应三种完全不同的用法

同一份 PPT,不同人该走的路完全不一样。下面三条路径是我见过最省时间的三种切法。

路径一:四小时跑通全流程。数据集(11 页)→ 数据准备(24 页)→ 预处理里的缺失值和离散化两节(36 页起)→ 分类章节里挑一个 J48 决策树跑通(63 页起)→ 看结果里的混淆矩阵。这条路线的目标是建立“数据进去、模型出来”的完整直觉,中间所有算法原理都可以先跳过。跑完之后你对 Explorer 界面的八个区域会有一个肌肉记忆级别的熟悉度,后面再看别的算法就是换个分类器名字的事。

路径二:为课程实验或报告做准备。走完整的数据准备和预处理,然后在分类章里挑三到四个算法做横向对比,重点看教程里关于评估方法的段落——交叉验证折数怎么设、为什么准确率在小样本上不可信、ROC 面积在哪看。这条路径要多花一倍时间在预处理上,因为报告里最容易被问住的问题永远是“你为什么这么处理缺失值”。

路径三:工程落地。直接跳到知识流界面那一章,把前面学的面板操作翻译成可保存、可复用的流程文件。知识流环境的价值在于它把一次性的鼠标点击变成了一个能反复跑的图,换数据集只要改输入端。这条路对 PPT 的依赖其实最低,但教程里那部分截图能帮你少走很多弯路——尤其是组件之间的连线规则,自己摸索挺费时间。

提示:不管走哪条路,先把教程自带的 weather.arff 跑一遍。这个 14 实例 5 属性(outlook、temperature、humidity、windy、play)的小数据集是所有操作的最小验证集,任何参数改动都能立刻看出效果差异,比拿真实数据调试快十倍。

2.3 用 Explorer 的八个区域建立心智模型

教程把 Explorer 界面切成八个区域来讲,这个切法很实用,值得单独记一下,因为后面所有操作都是在这八个格子里打转。

区域 1 是顶部那排选项卡,Preprocess、Classify、Cluster、Associate、Select Attributes、Visualize,对应六类任务。区域 2 是打开、编辑、保存、撤销那一排按钮。区域 3 是 Filter 选择区,数据预处理全部在这里完成,也就是教程第 36 页之后的内容。区域 4 显示当前数据集的关系名、属性数、实例数。区域 5 是属性列表,勾选后点 Remove 可以删列,删错了用区域 2 的 Undo 找回来——这个 Undo 是很多人不知道的后悔药。区域 6 是选中属性的统计摘要,数值属性给最小值、最大值、均值、标准差,标称属性给每个类别的计数。区域 7 是直方图,默认按最后一个属性(也就是类标)分色。区域 8 是底部状态栏,右键能看内存占用和强制垃圾回收,那个会动的鸟图标表示任务正在跑。

这里有个细节教程讲得比较轻:区域 7 的分色依据可以在直方图上方下拉框里换。当你想看某个特征在另一个类别维度上的分布时,这个下拉框比重新画图快得多。另外,如果最后一个属性不是类别型而是数值型,直方图会变成黑白的,这时候要么在下拉框里手动指定一个分类属性,要么承认你的数据不适合直接做分类任务。

理解这八个区域之后,整个 WEKA 的操作逻辑就收敛成一句话:在区域 3 选一个 Filter 改变数据形态,在区域 1 切到对应任务页,在区域 3 下方选一个算法,点 Start,去结果区读数字。剩下的全是参数细节。

3. ARFF 格式吃透:手写一份 WEKA 认得的表

WEKA 只认 ARFF,这是绕不过去的。教程从第 11 页开始讲数据集,第 15 页给出完整的 weather.arff 示例,这部分内容看着琐碎,但它是后面所有操作的前提。实际项目里我见过太多人卡在“文件导入报错”上,九成以上是 ARFF 的头信息写错了,而不是数据本身有问题。

3.1 头信息的三段结构:relation、attribute、data

一个 ARFF 文件去掉以%开头的注释行之后,结构只有两段:头信息和数据信息。头信息里第一行有效内容必须是关系声明@relation <关系名>,关系名带空格要加引号。紧接着是若干个@attribute声明,每个属性一行,格式是@attribute <属性名> <数据类型>。数据部分从单独一行的@data开始,之后每一行是一条记录,字段之间用逗号分隔。

属性声明的顺序极其重要,它决定了数据部分每一列对应哪个属性。教程里举的例子很到位:humidity 是第三个被声明的属性,那么数据行里第 3 个字段(按人的习惯数)就是 humidity 的值。另外,最后一个声明的属性会被当作 class 属性,在分类和回归任务里它就是默认的目标变量。这意味着你调整列顺序时,必须把类标列放在最后,否则分类器会拿错目标——这个坑后面还会细说。

属性名必须以字母开头,可以包含字母、数字和下划线。这个限制在实际使用中经常被忽略,尤其是从数据库导出的字段名带数字前缀时(比如1st_click),WEKA 会直接拒绝加载。解决办法是在生成 ARFF 时统一加一个字母前缀。

3.2 四种数据类型与那个容易翻车的大小写规则

WEKA 支持四种数据类型:numeric 数值型、标称型(花括号里列举类别)、string 字符串型、date 日期型。教程特别提到 integer 和 real 也会被当成 numeric 处理,这个兼容性设计挺贴心。

真正容易踩的是大小写。教程里明确写了:integer、real、numeric、date、string这些类型关键字是区分大小写的,而relation、attribute、data这三个标记不区分。也就是说@ATTRIBUTE能正常工作,但@attribute age Numeric会报错,因为Numeric首字母大写不被识别。这类错误在报错信息里往往只说“problems parsing”,看得人一头雾水。

标称型的写法是@attribute 属性名 {类别1, 类别2, 类别3},数据里该字段的值必须严格等于花括号里的某一个,包括大小写和空格。如果类别名里带空格,要加引号。我处理过一份数据,类别标签在源文件里写的是Yes和No,迁移到 ARFF 时手写成{yes, no},结果整个文件加载后类别全是缺失值——WEKA 不报错,只在摘要里把缺失数显示得很高,很容易漏看。

3.3 从 CSV 到 ARFF:两种转换方式

真实场景里没人手写 ARFF,数据一般躺在 CSV 或 Excel 里。这里给两条路,按数据规整程度选。

第一条是 WEKA 自带的转换器,适合列名干净、没有奇怪字符的 CSV。命令行一行搞定:

# CSVLoader 负责读 CSV 并输出 ARFF 到标准输出 # -i 指定输入文件,重定向到目标 .arff java -cp weka.jar weka.core.converters.CSVLoader \ data/orders.csv > data/orders.arff

这条命令做的事很直白:CSVLoader 读入 CSV,自动推断每列类型为 numeric 或 nominal,然后序列化成 ARFF 写到标准输出。参数上它支持-H表示第一行不是列名、-N后面跟类型名列表强制指定各列类型(比如-N 4-8表示第 4 到第 8 列按标称处理)。逻辑上它只看前若干行做类型推断,所以如果 CSV 里某列前一百行都是整数、第一百零一行出现N/A,推断结果会是 numeric 然后在加载时报错。数据集不大时建议先扫一遍每列取值。

第二条是自己写一段转换脚本,适合要控制类型、要处理缺失值、要重排列顺序的场景。下面是 Python 版本:

import csv # 配置区:按业务需要改这三处 INPUT_CSV = "raw/churn.csv" # 源文件 OUTPUT_ARFF = "data/churn.arff" # 输出文件 RELATION = "churn" # 关系名 # 列定义:(列名, 类型, 额外信息) # 类型为 numeric / nominal / string / date COLUMNS = [ ("age", "numeric", None), ("tenure", "numeric", None), ("contract", "nominal", ["month", "year", "two_year"]), ("has_card", "nominal", ["TRUE", "FALSE"]), ("churn", "nominal", ["yes", "no"]), # 类标必须放最后 ] MISSING_TOKEN = "?" # WEKA 的缺失值标记,不能是空字符串 def fmt(value): """把 Python 值转成 ARFF 合法文本,缺失统一写成 ?""" v = (value or "").strip() if v == "" or v.upper() == "NA" or v == "NULL": return "?" return v with open(INPUT_CSV, newline="", encoding="utf-8-sig") as fin, \ open(OUTPUT_ARFF, "w", encoding="utf-8") as fout: fout.write(f"@relation {RELATION}\n\n") for name, dtype, spec in COLUMNS: if dtype == "nominal": fout.write(f"@attribute {name} {{{','.join(spec)}}}\n") elif dtype == "date": fout.write(f'@attribute {name} date "{spec}"\n') else: fout.write(f"@attribute {name} {dtype}\n") fout.write("\n@data\n") # csv.DictReader 按列名取值,源文件列顺序变了也不影响 reader = csv.DictReader(fin) for row in reader: fout.write(",".join(fmt(row.get(name)) for name, _, _ in COLUMNS) + "\n")

这段脚本的关键点在三处。utf-8-sig编码是为了吃掉 Windows 导出的 BOM 头,否则第一列列名会带个不可见字符导致取值为空。MISSING_TOKEN用?是 ARFF 的强制约定,空串会让解析器把后面的字段全部错位一列,这是最隐蔽的一类错误。列的写出顺序严格按COLUMNS走,源 CSV 列顺序怎么变都不影响输出,同时保证类标在最后一位。

注意:写 ARFF 时字段值里不能出现未转义的逗号、花括号和百分号。标称值里的逗号要用引号包住,字符串属性里的反斜杠要转义。源数据里如果有中文全角逗号,WEKA 会当成普通字符处理,但屏幕上看起来和半角逗号几乎一样,排查起来很费眼。

3.4 缺失值、稀疏格式和那个被忽视的类标位置

缺失值在 ARFF 里统一写成?,教程里没展开讲,但这是预处理阶段绕不开的东西。WEKA 大部分算法对缺失值有默认处理策略,比如决策树在分枝时会把缺失样本按比例分到各个子节点,朴素贝叶斯直接跳过缺失维度。默认策略能跑通,不代表结果可信。我的习惯是在预处理阶段先用 ReplaceMissingValues 这个 Filter 把数值列的缺失补成均值、标称列补成众数,把补全情况和分布变化记下来,再决定要不要保留。

稀疏数据(大量取值为 0 或缺失)可以用稀疏 ARFF 格式,数据部分每一行写成{0 值, 3 值}这种形式,只列非零字段的下标和值。文本挖掘类数据用这个格式能省下大量磁盘和加载时间。代价是可读性差,调试阶段别用。

类标位置这一点值得再说一遍,因为它同时牵扯 ARFF 和界面两个环节。ARFF 里最后一个@attribute默认是类标,Explorer 也是按这个规则认的。如果你做完预处理后某个 Filter 在末尾追加了新列,类标就不再是最后一列,分类器会拿错目标去训练,而界面上不会给出任何提示,结果只会表现为准确率莫名其妙地接近随机。在 Preprocess 面板上方有一个 Class 下拉框,用来显式指定哪一列是类标,很多人从来不动它。做完任何改变列数或列序的操作之后,去那个下拉框确认一眼,能省掉一整晚的困惑。

4. 预处理与建模:Filter 链、测试选项和那些默认值

教程的预处理章节从第 36 页开始,分类从第 63 页开始,中间这二十多页是整套流程里性价比最高的部分。原因很简单:算法选错了顶多效果差一点,数据形态错了会让所有算法一起失效,而且失效的方式往往很安静——没有报错,只有一个好看得可疑的准确率。

4.1 Filter 的选择链与无监督离散化的参数

Filter 在 Explorer 的 Preprocess 面板里通过 Choose 按钮选,选完之后点它右侧的输入框可以改参数。读 PPT 里的截图时容易忽略一点:Filter 是可以串联的,每次 Apply 之后数据集就变了,接着选下一个 Filter 再 Apply,形成一个处理链。教程里的示例大多是单个 Filter 操作,实际用起来基本都是三到五步串联。

一个典型的链是这样的:先用 Remove 删掉 ID 类和明显无关的列,用 ReplaceMissingValues 补缺失,用 Discretize 把连续值分箱,用 Normalize 归一化,最后用 NumericToNominal 把某些数值列转成类别。顺序不能随便调,比如 Normalize 必须在 Discretize 之前或者干脆二选一,先分箱再归一化是没有意义的。

离散化这一步参数最值得细看。Discretize 的-B控制分箱数,默认 10;-M为真时使用等频分箱,默认是等宽。等宽分箱在长尾分布上会把 90% 的样本塞进第一个箱子,等频分箱每个箱子的样本数相近但切点位置依赖数据分布,换成测试集后切点会漂。教程的示例数据量小,看不出差别,真实数据上这个选择对结果影响很大。

Filter关键参数默认值什么时候改
Discretize-B分箱数10样本少时降到 3~5,否则每箱样本太少
Discretize-M等频开关关闭(等宽)分布严重偏斜时打开
Remove-R列索引无索引从 1 开始,按 Ctrl 可多选
ReplaceMissingValues无—数值补均值、标称补众数
Normalize-R列范围全部数值列距离类算法必须做,树模型可省

表里最后一行是个容易搞混的边界:归一化对 K 近邻、SVM、KMeans 这类基于距离的算法是必需项,对 J48 这类决策树则没有影响,因为树只看单列的切分点,和量纲无关。搞清楚这一点,能少做很多无用功。

提示:Filter 面板里 Apply 按钮旁边有个 Undo,可以撤销上一次 Filter 操作并退回上一步的数据状态。这个按钮只保留一步历史,所以做完一步关键变换之后,记得点 Save 存一个中间版本的 ARFF,别指望靠撤销来回退。

4.2 分类器面板:四个测试选项和一个代价矩阵

切到 Classify 面板,左上角 Choose 里是算法树,下面是 Test options 四选一。这四个选项决定了你看到的数字是什么含义,教程里讲得比较简略,值得补充。

Use training set 是最快的,也是最有欺骗性的。它拿训练集自己评估自己,任何稍微有点记忆能力的模型都能刷出 95% 以上的准确率。这个选项只适合验证代码跑没跑通,不适合写进任何报告。

Supplied test set 需要额外指定一个独立的 ARFF 文件,注意这个文件的属性声明必须和训练集完全一致——属性数量、顺序、类型、标称值的类别列表,全部要对得上。差一个类别名就会在预测时全部判错,而且报错信息很模糊。

Cross-validation 是默认选项,Folds 默认 10。小样本时要降低折数,比如 100 条样本用 10 折,每折只有 10 条,评估结果抖动会很大。经验做法是样本数低于 500 时用 5 折,低于 100 时用 leave-one-out。

Percentage split 按比例切分,默认 66%,也就是三分之二训练三分之一测试。这个选项的问题是切分是随机的,同一份数据跑两次结果不同。旁边有个 More options 里的随机种子可以固定,改完之后结果才可复现。

代价矩阵在 More options 的 Cost sensitive evaluation 里设。二分类任务里把少数类的误判代价调高,能让模型更偏向识别少数类而不是一味追求整体准确率。教程的示例数据类别均衡,用不上这个,真实业务里几乎一定会用到。

4.3 聚类和关联规则的指标,读法比参数更重要

聚类面板的操作和分类类似,但结果解读方式完全不同。SimpleKMeans 的关键参数是-N簇数和-I迭代次数。簇数没有客观标准,需要在结果里看簇内平方和(Within cluster sum of squared errors)随簇数变化的那条曲线,找拐点。教程里给了截图示例,但没强调一件事:KMeans 的初始中心是随机选的,同一个数据集跑两次结果可能差很多。要稳定就固定-S随机种子,要多跑几次取最优就设-init为多次尝试。

结果里的簇分配表会告诉你每个簇有多少实例、各属性的均值。真正有用的一步是右键结果列表里的那一行,选 Visualize cluster assignments,能看到样本在二维平面上的分布。如果两个簇在图上完全重叠,说明你选的属性组合区分不了它们,该回去做属性选择而不是继续调簇数。

关联规则这边,Apriori 的参数坑最深。-N是产出规则数量上限,默认 10;-C是最小度量阈值,默认 0.9;-M是最小支持度,默认 0.1。关键在于-T,它指定用哪个度量来筛选规则,默认值是 1,对应 lift 提升度,而不是大多数人以为的 confidence 置信度。这意味着如果你只调-C这个“看起来是置信度”的参数,实际在筛的是提升度,结果会和预期完全对不上。要按置信度筛,必须显式把-T设成 0。

4.4 命令行与知识流:把一次点击变成可重复执行

在界面上点顺手之后,把所有操作搬到命令行是效率提升最明显的一步。WEKA 的每个算法类都有 main 方法,可以直接用 java 调用。

# 用 J48 在训练集上建模并在测试集上评估,-i 输出决策树本身 java -cp weka.jar weka.classifiers.trees.J48 \ -t data/churn_train.arff \ -T data/churn_test.arff \ -C 0.25 \ -M 2 \ -i # KMeans 聚类,-N 簇数 -I 迭代上限 -S 固定随机种子保证可复现 java -cp weka.jar weka.clusterers.SimpleKMeans \ -t data/churn_train.arff \ -N 4 -I 100 -S 42 # Apriori 关联规则,注意 -T 0 表示按置信度筛选,-C 0.8 是阈值 java -cp weka.jar weka.associations.Apriori \ -t data/basket.arff \ -N 30 -T 0 -C 0.8 -M 0.05

J48 的两个参数解释一下:-C是剪枝的置信度阈值,默认 0.25,调小会让树长得更谨慎、剪得更狠;-M是叶子节点的最小实例数,默认 2,样本少的时候调到 5 到 10 能明显抑制过拟合。-i让输出包含决策树文本,不加的话只有统计指标。

这三条命令的实际价值不只是省鼠标,更重要的是可以被 shell 脚本批量调用。把数据集列表和算法列表写成两个数组,双层循环套一下,一晚上能跑完几十组实验,结果输出到不同文件里再统一比对。用界面点的话,这个工作量是不可接受的手工活。

知识流界面走的是另一条路,它把流程画成图。组件从左边拖到画布上,数据源接 Filter,Filter 接分类器,分类器接评估器,用连线连起来,点开始就按图跑。好处是流程本身可以存成文件、可以给同事看、换了数据源只要改一个组件的路径。对于要反复跑同一个流程的场景,这比命令行脚本更直观;对于要穷举参数组合的场景,命令行更省事。两种方式都值得掌握,看任务决定。

5. 用这套教程时踩过的坑:五条排查记录

教程按功能模块组织,章节之间是并列的,真实使用中遇到的问题却往往横跨三四个模块。下面五条是我照着这份 PPT 走流程时实际撞上的,按现象、原因、解决三段记下来,方便对照排查。

5.1 数据与环境层面的三条

现象:用 Remove 删掉第 1 列和第 3 到 5 列之后,剩下的数据里少了一列本来该保留的属性。原因:把属性索引和数据列下标搞混了。WEKA 界面和 Filter 参数里的属性索引从 1 开始,而 ARFF 文件的数据行里字段下标从 0 开始,教程提到标称值位置时用的是 0 起算的说法,两套编号在同一份文档里并存,很容易照着一个用另一个。解决:在 Preprocess 面板里直接勾选属性再点 Remove,不手填索引;非要用参数就写成一个显式的映射表贴在脚本里,宁可多写几行也别心算。

现象:加载一个几十兆的训练集时弹出内存溢出错误,程序直接退出。原因:WEKA 默认的 JVM 堆内存上限比较小,读 ARFF 时整个数据集常驻内存,数据量一大就爆。教程里的示例都是几百行的小文件,不会触发这个问题。解决:启动时加参数-Xmx2g(按机器内存调整),或者在启动脚本里把 JAVA_OPTS 写死。另一个方向是先在预处理阶段做列裁剪和采样,把数据量降下来再进 WEKA。

现象:用训练集训练出来的模型,在测试集上预测结果几乎全是同一个类别,准确率和随机猜差不多。原因:训练集和测试集的标称属性类别列表不一致。前置转换脚本对训练集和测试集分别做了类别统计,某个类别在训练集里没出现,于是@attribute的花括号里少了一个值,测试集里出现该值的样本在加载时被设成缺失。解决:嵌在转换脚本里,把类别列表做成全局常量而不是从数据里推断;或者先用训练集的 ARFF 头信息覆盖测试集的头信息,只替换数据部分。

5.2 算法与评估层面的两条

现象:用 Apriori 跑关联规则,把-C从 0.9 调到 0.5 期望得到更多规则,结果规则数量几乎没变。原因:-C是“最小度量阈值”,具体筛哪个度量由-T决定,而-T的默认值是 1,也就是按 lift 提升度筛,不是置信度。改-C确实在改阈值,但改的是提升度的阈值,而提升度和支持度的联合约束下大多数候选项早就被支持度过滤掉了,所以看不出变化。解决:明确写出-T 0表示按置信度筛,再调-C;同时把-M最小支持度一起降下来,两个约束要匹配着设。

现象:十折交叉验证报告的准确率有 92%,换了一个月后的新数据上去跑,掉到 60% 多。原因:类别的分布随时间漂移,而交叉验证的每一折都是从同一份历史数据里随机切的,各折之间高度相关,给出的估计是历史分布下的内部一致性,不是泛化能力。教程里讲交叉验证时用的示例数据没有时间维度,不会暴露这个问题。解决:有时间的业务数据一律按时间切分,早期数据训练、近期数据测试;同时看混淆矩阵里每个类的精确率和召回率,别只看总准确率,类别不平衡时总准确率会严重高估效果。

6. 把 PPT 变成可复现实验:属性选择和结果导出的两个技巧

教程里选择属性那一章只有九页,是全书最薄的一章,但在实际项目里它的作用被严重低估。属性选择做完之后,模型训练时间能降一个数量级,可解释性也会明显变好,尤其是要给业务方解释哪些特征真正起作用时。

界面上操作很直观:切到 Select Attributes 面板,Evaluator 里选 CfsSubsetEval,Search 里选 GreedyStepwise,点 Start 就能看到被选中的属性编号。问题在于这个过程无法批量执行。要跑批处理,用 Java API 直调是最稳的方式:

import weka.attributeSelection.*; import weka.core.Instances; import weka.core.converters.ConverterUtils.DataSource; public class SelectDemo { public static void main(String[] args) throws Exception { Instances data = DataSource.read("data/churn_train.arff"); data.setClassIndex(data.numAttributes() - 1); // 手动指定类标,别依赖默认 AttributeSelection sel = new AttributeSelection(); CfsSubsetEval eval = new CfsSubsetEval(); // 特征子集相关性评估 GreedyStepwise search = new GreedyStepwise(); // 贪心前向搜索 search.setSearchBackwards(false); // false 为前向,true 为后向 sel.setEvaluator(eval); sel.setSearch(search); sel.SelectAttributes(data); // 输出选中的属性索引(从 0 开始,和 ARFF 数据列一致) System.out.println(sel.selectedAttributes().length + " 个属性被选中"); for (int idx : sel.selectedAttributes()) { System.out.println(idx + "\t" + data.attribute(idx).name()); } } }

这段代码有三个地方值得注意。setClassIndex必须显式调用,否则 CfsSubsetEval 会因为没有监督信号而报错,这个报错信息完全不提类标的事,只说评估器无法工作。setSearchBackwards(false)决定搜索方向,前向从空集开始逐个加特征,后向从全集开始逐个删,特征数少的时候前向更快,特征数多的时候后向偶尔能找到更优解。selectedAttributes()返回的是从 0 开始的索引,如果要把结果喂给 Remove 这种从 1 开始编号的 Filter,记得统一加一,我在这上面栽过一次,删错了列还不自知,直到模型效果突然变好才觉得不对。

第二个技巧是结果导出。Classify 面板右边有个 Result list,每次运行都会追加一条。右键某一条可以 Save model 保存训练好的模型,也可以 Save result buffer 把全部输出存成文本。批量实验时我会把每次的分类器配置、评估指标、混淆矩阵全部导成文本,再写个小脚本解析成表格——这比截图可靠得多,也方便后来人复现。

从那以后我每次跑出一版“效果不错”的模型,都强制走一遍:先看 Result list 里那条记录的完整配置串,确认参数确实是我以为的那些;再把模型文件和当时的数据集版本号一起归档。WEKA 的默认参数太多了,隔两周回来看,光凭记忆是说不清当时到底改了什么。希望帮到你。

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

返回列表