简介:面向 MATLAB 初学者以及需要开展数据分析的科研人员和工程师,这份文档围绕 Statistics and Machine Learning Toolbox 展开,讲解工具箱的安装检查、常用函数与两个完整案例,帮助解决统计建模无从下手的问题。压缩包仅含 1 个 doc 文件,大小约 33KB,为纯文档型资料,便于随查随用。内容从 ver 命令确认工具箱是否安装讲起,梳理 mean、std、ttest、fitlm、kmeans 等函数的用途与调用方式,并给出房屋面积与价格线性回归、二维数据 K 均值聚类两个可复现实例,涵盖数据准备、模型建立与结果可视化全流程,读者可据此改写数据完成自己的分析任务。目前已有 1426 人学习,适合作为统计与机器学习方法在 MATLAB 中应用的入门参考。
1. 一台不联网的节点:Statistics and Machine Learning Toolbox 装在哪一层
某实验室有一台不连外网的计算节点,MATLAB 主程序装好快一年,Statistics and Machine Learning Toolbox 一直没人碰过。直到有人要跑fitlm做一组回归,命令窗口甩回来一句Undefined function 'fitlm'。跑去敲ver,产品列表里这个名字又明明躺着。翻车的根源很反直觉:这个工具箱不是独立软件,它只是主程序安装树里的一层产品目录加一组许可证 feature,装没装、装得全不全、许可能不能取到,是三件不同的事。装不干净的后果不是报个错就完,而是ver说有、which说没有,排查方向一开始就跑偏。这篇记录适合两类人:在离线机器上补装工具箱的,和接手一台别人装过的 MATLAB 想确认环境到底齐不齐的。
2. 装前对齐版本:主程序、工具箱与许可证的三方核对
装工具箱这件事,九成的返工都发生在动手之前——主程序是哪个发布批次、安装介质是哪个批次、许可证里含不含对应 feature,这三样没对上,后面点多少次 Next 都是白搭。先说结论:工具箱的版本必须和主程序同批次,不能拿一个新批次的.mlpkginstall往老主程序上怼,也不能指望主程序升级之后旧工具箱自动跟着走。我一般把核对拆成三步,每步都有对应的命令,做完再决定走哪条安装路径。
2.1 先读主程序的发布批次,别读产品名
很多人只知道自己是“MATLAB 2021 版”或者“MATLAB 2023 版”,这种描述在装工具箱时没有任何用。安装介质和 Add-On 包认的是四位发布批次号,ver输出的Version字段里就带着它。
% 内部版本号,用来和安装介质根目录 release notes 里的编号比对 disp(version) % 结构体数组,每个元素是一个已注册产品 v = ver; % 只打产品名,快速确认目标工具箱在不在列表里 disp({v.Name}') % 定位到目标那一行,看它的 Version 字段是否与主程序同批次 idx = contains({v.Name}, 'Statistics and Machine Learning'); if any(idx) disp(v(idx).Version) else disp('产品列表里没有这个工具箱') endversion返回的是内部编号,ver返回的是产品清单,两者不是一回事。判断兼容性要看ver里目标项Version字段的批次部分,和主程序那一行是否一致。如果idx全为 0,说明产品根本没注册,走第 3 章的安装路径;如果注册了但批次和主程序对不上,别急着用,先卸掉再装同批次的,混批次最容易出“函数能调但结果带 warning”这种玄学问题。
还有一种情况是老机器上升级过主程序、工具箱没跟着升。这时候ver里两行产品的批次号会明显不同,肉眼就能看出来。判断标准很简单:主程序那一行的批次号,应该和工具箱那一行完全相同。
2.2 版本对不上的三种表现,认出哪一种决定怎么救
版本错配不会给你一条明确的报错,它有三种很不一样的表现,认错了就会往错的方向修。
第一种是函数完全找不到,报Undefined function。这种最常见,本质是产品目录没注册进路径,或者注册了但目录是空的。
第二种是函数能调,但结果和文档对不上,或者跑出一堆Warning: Behavior changed之类的提示。这种最坑,因为脚本不报错,你会以为是自己数据的问题,实际上是新旧批次在默认参数上的差异。K 均值聚类这块尤其明显,默认的距离度量、初始化的重复次数在不同批次里调整过,同一份数据、同一个k,换台机器跑出来的簇编号都可能不一样。
第三种是启动时弹产品版本不一致的提示,或者ver里同一个产品出现两行。这是典型的残留注册,旧批次的目录还在,新批次的又装了进来。
对应的处理方式也不同:第一种重装,第二种显式写全参数并固定随机种子,第三种清残留。分辨方法就是which加exist:
% 查函数实际解析到哪个文件,-all 会把所有同名实现都列出来 which fitlm -all % 只判断能不能解析到,返回 2 表示找到了 .m 文件 e = exist('kmeans', 'file'); disp(e) % 打印工具箱根目录,确认这个目录真实存在 root = fullfile(matlabroot, 'toolbox', 'stats'); disp(root) disp(isdir(root))which -all输出多行是危险信号,说明路径里有重复实现,谁排在前面谁生效。exist返回 0 而ver里有名字,基本可以判定是产品注册了但目录缺失,直接跳到第 3 章重装。
2.3 磁盘、内存和依赖的底线清单
装之前先看一眼机器,这一步花两分钟,能省掉一次装到一半空间不足的返工。工具箱本身不算大,但安装过程会解压临时文件,主程序目录、临时目录、安装介质所在分区三处都要留余量。
| 检查项 | 底线要求 | 怎么查 |
|---|---|---|
| 主程序分区剩余空间 | 安装介质体积的 1.5 倍以上 | Linux 下df -h $MATLAB_ROOT,Windows 下看盘符属性 |
| 临时目录剩余空间 | 同上,且必须有写权限 | tempdir打印路径,再确认当前用户可写 |
| 内存 | 跑聚类和回归建议 8 GB 起 | memory命令,看MaxPossibleArrayBytes |
| 主程序可写 | 安装目录当前用户可写,否则要用管理员权限 | 尝试在matlabroot下建一个空文件再删掉 |
| 许可证可达 | 能连到许可证服务,或本地许可证文件路径正确 | 见 2.1 与 4.1 的license检查 |
memory命令在 Linux 上返回的字段和 Windows 略有差异,但MaxPossibleArrayBytes这个字段是通用的,它告诉你当前能分配的最大连续内存块。跑 K 均值聚类时数据量大一点就会撞到这个上限,撞上了不是工具箱的问题,是数据该分块或者该降维了。临时目录权限这条最容易被忽略,在线安装卡在下载阶段十有八九是tempdir不可写,第 5 章会单独讲。
3. 三条安装路径:在线 Add-On、离线包与静默部署怎么选
同一个工具箱,在线装、离线装、静默批量装,走的是三套完全不同的流程,适用的场景也不一样。选错路径的代价不是装不上,而是装到一半卡住、装完了发现只装了一半、或者一批机器装出三种不同状态。我一般按机器的网络条件和使用人数来分:能上网的单机走在线,完全不联网的走离线包,一次要铺十台以上的走静默。
先看整体对比,再逐条展开。
| 路径 | 适用场景 | 前置条件 | 耗时量级 | 主要风险 |
|---|---|---|---|---|
| 在线 Add-On | 单机、能访问外网、有账户 | 已登录账户、临时目录可写 | 十几分钟 | 下载中断、装到一半超时 |
| 离线包 | 内网机器、无外网出口 | 一台能下载的机器加一个 U 盘 | 十几分钟 | 包与主程序批次不一致 |
| 静默部署 | 批量铺机、机房统一镜像 | 安装介质加一份响应文件 | 按机器数量线性增长 | 响应文件里产品名写错 |
3.1 在线安装:入口不止图形界面一个
图形界面的路径是主页选项卡里的附加功能入口,搜索产品全称,进详情页点安装,一路下一步。这条路谁都会走,问题在于它不可复现——下次换台机器还得重新点一遍,也没法写进部署脚本。所以我更习惯用命令入口,效果一样,但能留下记录。
% 列出当前已安装的附加功能,返回一个 table a = matlab.addons.installedAddons; disp(a) % 按名称安装,需要当前会话已登录账户且能访问外网 matlab.addons.install('Statistics and Machine Learning Toolbox') % 装完复查,确认状态列是 installed 而不是 pending a2 = matlab.addons.installedAddons; disp(a2)matlab.addons.install的第一个参数可以是附加功能名称,也可以是本地包文件路径,这一点很关键——同一条命令既能在线装也能离线装,区别只在参数。这个 API 在老批次里不存在,如果报未定义,就退回图形界面走一遍,或者直接用 3.2 的离线包方式。
装完必须复查installedAddons的状态列。我见过装完了但状态停在 pending 的,原因是下载完成但解压阶段被中断,这种状态下函数照样调不到,ver里却已经有名字了。
图形界面那条路补一句:详情页里有个把包下载到本地的入口,这是给离线机器准备包的唯一正道,比到处找别人拷的包安全得多,因为批次一定和当前主程序匹配。
3.2 离线安装:包拷过去,一条命令落地
无外网的机器只有这一条路。流程分两段:在能上网的机器上用附加功能详情页把包下载成本地文件,格式一般是.mlpkginstall;再用 U 盘拷到目标机器,用matlab.addons.install指向文件路径。
% 包放在挂载点上,路径里别带中文和空格 pkg = '/media/usb/Statistics_and_Machine_Learning_Toolbox.mlpkginstall'; % 先确认文件存在且大小正常,避免拷了个 0 字节的残包 d = dir(pkg); if isempty(d) || d.bytes < 1024 error('包文件缺失或体积异常,重新拷一次'); end % 指向本地文件安装,第二个参数在部分批次支持自动接受许可 matlab.addons.install(pkg, 'autoAcceptLicense', true) % 复查安装结果 disp(matlab.addons.installedAddons)autoAcceptLicense这个名值对不是所有批次都认,老批次会直接忽略它,然后弹一个交互式许可确认框。如果脚本是在无人值守的批处理里跑,弹框等于卡死,所以老批次上这一行要改成先手动装一次、把许可确认过掉。
拷包之前有个必须做的动作:核对包和主程序的批次。包文件名里通常带批次号,ver里主程序那一行也带批次号,两个对不上就别装了,装上去也是第 2.2 节说的第二种表现。这一点吃过亏,拷来一个别人机器上下载的包,装完函数能调、结果全偏,查了半天才发现批次差了两级。
离线机器还有个隐藏依赖:有些功能会用到主程序里自带的编译组件,如果主程序装的是精简安装(没勾全部产品),这些组件可能缺。表现是安装过程本身成功,一跑kmeans就报底层库找不到。这种情况只能回到主程序安装介质,把精简安装补成完整安装。
3.3 静默部署:一份响应文件铺一批机器
机器数量上十以后,一台台点图形界面不现实,也没法保证一致性。静默安装依赖主程序的安装程序和一份响应文件,工具箱作为产品列表里的一项被勾上。
响应文件长这样,关键字段逐条说明:
# 安装目标目录,多批次共存时建议带批次号后缀 destinationFolder=/opt/MATLAB/R20xx # 许可方式:安装密钥或指定许可证文件路径,二选一 fileInstallationKey=xxxxx-xxxxx-xxxxx-xxxxx-xxxxx # licensePath=/opt/license/network.lic # 必须显式同意,否则静默模式直接退出 agreeToLicense=yes # 要装的产品,产品名必须写全称,写错会静默跳过且不报错 product=Statistics_and_Machine_Learning_Toolbox调用方式:
# -mode silent 走无人值守,-inputFile 指向上面那份响应文件 ./install -mode silent \ -inputFile /tmp/installer_input.txt \ -outputFile /tmp/install.log # 装完立刻用批处理模式验证,不启动图形界面 /opt/MATLAB/R20xx/bin/matlab -batch "v=ver; disp({v.Name}')"-outputFile这个参数别省。静默安装失败时终端上什么都不打印,全靠日志文件定位,日志里会明确写哪一行产品名无效、哪个目录没权限。-batch是验证阶段最省事的入口,它跑完自动退出,适合塞进部署脚本的最后一步。
产品名这一项是本条路径最大的坑。响应文件里写简称、写带空格的变体、大小写不一致,安装程序不会报错,它会认为这一项不存在然后安静跳过,最后你得到一台“装完了但没有工具箱”的机器。稳妥做法是先在任意一台机器上ver一次,把产品名原样复制进响应文件。
4. 配置与路径:让 fitlm 和 kmeans 真的被解析到
装完不等于能用。这一层最容易出问题的地方不在安装本身,而在许可证 feature 的取用和搜索路径的状态。前者决定函数能不能跑,后者决定函数找不找得到,两件事分开排查,别混在一起。
4.1 许可证先过一遍:test 和 checkout 不是一回事
license函数有两个动作,很多人只知道前一个。
% test 只判断这个 feature 在当前配置下能不能取到,不占用席位 ok = license('test', 'Statistics_Toolbox'); disp(ok) % checkout 是真的去占用一个席位,用完记得 checkin [ok2, errmsg] = license('checkout', 'Statistics_Toolbox'); if ~ok2 disp(errmsg) end % 看当前会话已经占用了哪些 feature disp(license('inuse'))第一个坑在 feature 名上。这个工具箱的许可证 feature 名沿用的是它的旧称Statistics_Toolbox,不带后面那半截产品名。写全称Statistics_and_Machine_Learning_Toolbox去查,返回一定是 0,然后你会误判成许可证里没有这个产品。这个命名差异属于历史遗留,ver里是新产品名,license里是老 feature 名,两边对不上是正常的。
第二个坑是test和checkout的语义差别。test返回 1 只代表“这台机器有资格取”,不代表现在取得到了;并发席位被同事占满的时候test照样返回 1,真正调函数时才报License checkout failed。所以排查许可证问题不能止步于test,要接着跑checkout并看license('inuse')里的实际占用情况。
网络许可证的环境变量也要确认。客户端的许可证服务地址一般靠环境变量或者license.dat指定,这两个地方配错了,test会在启动时先卡几十秒再返回 0,卡顿本身就是症状。
4.2 路径问题:别手工把整个 toolbox 根目录 addpath 进去
函数找不到的时候,最常见的错误操作是把工具箱根目录整条addpath进去。这一步看起来能立刻解决问题,实际上是给后面埋雷。
% 查看当前搜索路径,重点看有没有重复或陈旧的工具箱条目 p = path; disp(strsplit(p, pathsep)') % 看某个函数解析到了几个实现 which fitlm -all % 清回默认路径,注意:这一步会清掉所有自定义路径 restoredefaultpath % 清完必须立刻存盘,否则下次启动又回到老状态 savepath工具箱有自己的路径注册机制,ver读的是产品注册表,函数解析读的是搜索路径,这两份数据可以不一致。手工addpath改的是后者,产品注册表没动,于是出现ver有名字、which找不到、手工加了路径又能跑的怪状态。
restoredefaultpath是把路径拉回出厂状态的后悔药,但它会一并清掉你自己加的路径,跑之前先把path输出存一份。清完不savepath等于白清,下次重启 MATLAB 又恢复原样,这个细节很容易漏。
还有一种情况是同一台机器装了多个批次,matlabroot指向的和path里的不一致。判断方法是把matlabroot打出来,和启动脚本里写的安装路径比一比。
4.3 随机种子和并行池:让案例结果能复现
回归和聚类的案例要能复现,靠两件事:固定随机种子,固定并行配置。聚类的初始化是随机的,不固定种子,同一份数据跑两次簇编号就变了,看起来像程序有 bug。
% 固定全局随机数流,'twister' 是默认且跨批次行为最一致的算法 rng(1, 'twister') % 检查并行池是否存在,不存在就建,规模按本机核数来 p = gcp('nocreate'); if isempty(p) parpool('local', 4); end % 确认并行池规模,规模过大在小数据集上反而更慢 disp(p.NumWorkers)rng的第二个参数指定生成算法,不写也能跑,但写了批次之间行为差异更小。gcp('nocreate')这个写法很关键——不带参数直接gcp会在池不存在时自动建一个,你以为在查询,实际上已经改了环境状态。带上'nocreate'才是纯查询。
并行池规模不是越大越好。K 均值聚类在几百个点这个量级上,四个 worker 的启动开销可能比计算本身还长。数据量小的时候直接串行跑,别开池。
5. 避坑与排查:ver 能看见名字但函数报未定义的五个现场
这一节按现象、原因、解决三段来写,五条都是实际遇到过的,顺序按出现频率排。
5.1 现象:ver 列出工具箱,which fitlm 返回 not found
原因基本是两个。一是产品注册在,但matlabroot/toolbox/stats这个目录不存在或为空,属于典型的部分安装——在线安装下载完成、解压阶段被中断,注册表写了,文件没落地。二是路径被改过,restoredefaultpath之后没savepath,或者启动脚本里有addpath覆盖了顺序。
解决分两步。先确认目录真实存在,isdir(fullfile(matlabroot,'toolbox','stats'))返回 0 就是文件缺失,直接重装,别在路径上折腾。返回 1 再查路径,which fitlm -all看有没有输出、输出几条,然后restoredefaultpath加savepath重置一遍。重装时优先用离线包,在线装在弱网环境下反复中断的概率不低。
5.2 现象:函数能调,但报 License checkout failed
原因不在安装,在许可。三种可能:许可证文件里根本不含Statistics_Toolbox这个 feature;并发席位被别人占满;客户端指向的许可证服务地址配错了。
解决顺序是先license('test','Statistics_Toolbox'),返回 0 说明配置层面就取不到,去查许可证文件和服务地址;返回 1 再license('checkout','Statistics_Toolbox')并打印errmsg,这时多半是并发数用完,找管理员看license('inuse')或者服务端日志释放席位。注意查的时候 feature 名不要写全称,这是 4.1 里讲过的坑。
5.3 现象:在线安装卡在下载阶段,进度条不动或者报网络错误
原因通常是tempdir不可写,或者这台机器没有到外网的出口。前者在共享机器和容器环境里特别常见,临时目录被挂成了只读。
解决是先disp(tempdir)打出临时目录,手动在里面建个文件试试写权限,不可写就改环境变量把临时目录指到用户目录下。确认可写还是卡,就说明没出口,别在在线安装上耗时间,换一台能下载的机器把包取下来,走 3.2 的离线路径。这条路上我花的时间最多,后来统一改成先判断网络条件再决定走哪条路径。
5.4 现象:换了主程序批次之后,老脚本跑出来的聚类结果对不上
原因是默认参数变了。K 均值的默认距离度量、初始化的重复次数、初始中心点的选法,在不同批次之间有过调整;rng的默认算法也调过。脚本里只写kmeans(data, k),等于把这一堆默认值交给版本决定。
解决是把参数显式写全,把随机种子固定,并且把主程序批次记录在脚本头部。
% 显式指定距离度量、重复次数和初始中心选法,避免吃默认值 rng(1, 'twister') [idx, C, sumd] = kmeans(data, 3, ... 'Distance', 'sqeuclidean', ... 'Replicates', 5, ... 'Start', 'plus'); % sumd 是点到各自中心的距离和,用来比较不同参数下的聚类质量 disp(sumd)Replicates设成 5 表示用不同初始中心跑五遍取最优,代价是耗时翻五倍,小数据集上值得,大数据集上要权衡。Start设成'plus'是 K 均值++ 的初始点选法,比纯随机更不容易陷进局部最优。把这几项写死之后,跨机器跨批次的结果差异基本能压住。
5.5 现象:命令行启动 MATLAB 时调到了另一个批次
一台机器上装了两个批次,命令行里敲matlab启动的可能是老的那个。原因是 PATH 顺序,或者 shell 里有别名。表现是图形界面里一切正常,脚本跑起来却报函数不存在,因为在老批次上那个功能还没进工具箱。
解决是启动时写绝对路径,别依赖 PATH:
# 绝对路径启动,避免 PATH 里有多个批次时调错 /opt/MATLAB/R20xx/bin/matlab -batch "disp(version); disp(matlabroot)" # 确认 shell 里没有残留别名 type matlab-batch模式下打印matlabroot是最快的验证手段,输出路径和你以为的一致才算对。部署脚本里所有matlab调用我都改成绝对路径,虽然难看,但省掉了排查“为什么这台机器结果不一样”的时间。
6. 装完怎么验证跑通:三份十分钟自检脚本和一张对照表
装完不验证等于没装。我习惯按三层来验:产品层看注册,许可层看取用,功能层看结果。三层全过,这台机器的环境才算交付。
第一层,产品和路径:
% 产品层自检:注册在、目录在、函数能解析到 v = ver; hasProd = any(contains({v.Name}, 'Statistics and Machine Learning')); hasDir = isdir(fullfile(matlabroot, 'toolbox', 'stats')); hasFun = exist('fitlm', 'file') == 2; fprintf('产品注册:%d 目录存在:%d 函数可解析:%d\n', hasProd, hasDir, hasFun)三个都返回 1 才继续往下走。任何一个为 0,回第 5 章对应条目。
第二层,许可和回归链路。用正文里那组房屋面积和价格的数据跑一遍,重点不是看结果多准,是看整条链路通不通:
% 许可层:feature 名用旧称,不带后半截产品名 ok = license('test', 'Statistics_Toolbox'); assert(ok == 1, '许可证未包含该 feature') % 功能层:最小回归,确认 fitlm 和 predict 都能走通 X = (1500:100:2400)'; y = (300000:20000:480000)'; mdl = fitlm(X, y); % R-squared 接近 1 说明链路正常,数值本身不作精度结论 fprintf('R2=%.4f 截距=%.1f 斜率=%.1f\n', ... mdl.Rsquared.Ordinary, mdl.Coefficients.Estimate(1), mdl.Coefficients.Estimate(2))fitlm的返回值是个对象,Rsquared.Ordinary是普通决定系数,Coefficients.Estimate第一项是截距、第二项是斜率。这组数据是严格线性的,R2应该非常接近 1,如果不是,说明装的批次或者路径有问题,不是数据问题。
第三层,聚类链路,重点验证随机性和并行不出岔子:
% 固定种子,保证两次运行簇编号一致 rng(1, 'twister') data = [randn(100,2)+1; randn(100,2)+5; randn(100,2)+10]; % 显式写全参数,避免吃批次默认值 [idx, C] = kmeans(data, 3, 'Distance', 'sqeuclidean', 'Replicates', 5); % 三个簇应该各有约 100 个点,严重偏离说明初始化有问题 counts = accumarray(idx, 1); disp(counts') disp(size(C))accumarray按簇编号统计点数,counts三个数应该都在 100 上下;C应该是 3 行 2 列。如果某个簇点数接近 0 或者 300,说明初始中心选崩了,把Replicates调大再试。
把三层自检压成一张对照表,交付前逐项打勾:
| 层 | 命令 | 通过标准 | 失败先看 |
|---|---|---|---|
| 产品 | ver | 产品名在列表里,批次与主程序一致 | 第 5.1 条 |
| 路径 | which fitlm -all | 只输出一条,路径在matlabroot下 | 第 4.2 节 |
| 许可 | license('test','Statistics_Toolbox') | 返回 1 | 第 5.2 条 |
| 回归 | fitlm加predict | 无报错,R2接近 1 | 第 2.2 节 |
| 聚类 | kmeans加accumarray | 三簇点数均衡,中心矩阵 3×2 | 第 5.4 条 |
| 启动 | matlab -batch "disp(matlabroot)" | 输出路径与预期批次一致 | 第 5.5 条 |
这套自检跑下来十分钟不到,但能挡住后面几周里最难查的那类问题——环境看着是好的,结果就是不对。从那以后我每次交付一台装过工具箱的机器,都强制把这三层脚本跑一遍再走人,哪怕对方催得再急。省下的那十分钟,往往要在别人机器上花两个小时找回来。希望帮到你。
本文还有配套的精品资源,点击获取