據(jù)挖掘?qū)崙?zhàn):從CSV到ARFF的完整預處理與避坑指南)
簡介這份文檔面向數(shù)據(jù)挖掘與機器學習初學者系統(tǒng)講解WEKA這一公開數(shù)據(jù)挖掘工作平臺的操作入門知識幫助讀者快速理解平臺的數(shù)據(jù)組織方式與核心功能。內(nèi)容圍繞WEKA的數(shù)據(jù)格式與術(shù)語展開涵蓋實例、屬性、關(guān)系等基本概念并詳細說明ARFF文件的頭信息與數(shù)據(jù)信息結(jié)構(gòu)包括關(guān)系聲明、屬性聲明及numeric、nominal、string、date四種數(shù)據(jù)類型同時介紹從CSV、Excel、Matlab等格式準備數(shù)據(jù)的思路。資源包為1個doc文檔大小約172KB便于下載后離線閱讀與查閱。WEKA集合了數(shù)據(jù)預處理、分類、回歸、聚類、關(guān)聯(lián)規(guī)則與可視化等算法接口開放可集成自定義算法或借鑒其方法實現(xiàn)可視化工具曾獲ACM SIGKDD數(shù)據(jù)挖掘與知識探索最高服務(wù)獎。目前已有791人學習適合希望以WEKA為工具入門數(shù)據(jù)挖掘?qū)嵺`、需要一份簡明操作指引的讀者參考。1. 從一份 weather.arff 說起WEKA 到底能幫你把數(shù)據(jù)挖到什么程度很多人第一次打開 WEKA看到那個鳥標和一堆按鈕心里是發(fā)懵的。我當年也是手里攥著一份 CSV想跑個分類看看效果結(jié)果卡在“數(shù)據(jù)怎么進去”這一步整整一個下午。WEKA 的全稱是懷卡托智能分析環(huán)境Waikato Environment for Knowledge Analysis由新西蘭懷卡托大學開發(fā)2005 年在第 11 屆 ACM SIGKDD 國際會議上拿了數(shù)據(jù)挖掘和知識探索領(lǐng)域的最高服務(wù)獎算下來發(fā)展歷史已經(jīng)超過二十年。它把分類、回歸、聚類、關(guān)聯(lián)規(guī)則、數(shù)據(jù)預處理和可視化全部塞進一個圖形界面里而且接口開放你能看它的接口文檔也能把自己的算法集成進去。這篇文章不講空泛的“數(shù)據(jù)挖掘概論”只講一件事拿到一份 CSV 或 Excel怎么一步步變成 WEKA 能吃的 ARFF怎么在 Explorer 里做預處理怎么避開那些讓人想砸鍵盤的坑。適合手里有數(shù)據(jù)、想快速驗證想法、又不想一上來就寫幾百行 Python 的從業(yè)者。2. ARFF 文件結(jié)構(gòu)拆解從 relation 到 data 的每一行2.1 頭信息與數(shù)據(jù)信息的分界線WEKA 處理的數(shù)據(jù)集在邏輯上就是一張二維表格一行叫一個實例Instance一列叫一個屬性Attribute整張表呈現(xiàn)的關(guān)系叫 Relation。它存儲數(shù)據(jù)的格式是 ARFFAttribute-Relation File Format本質(zhì)是一個 ASCII 文本文件。以 WEKA 安裝目錄data子目錄下的weather.arff為例去掉以%開頭的注釋行之后整個文件被data標記切成兩半上半部分是頭信息Head information負責聲明關(guān)系名稱和屬性定義下半部分是數(shù)據(jù)信息Data information就是逗號分隔的實際數(shù)值。關(guān)系聲明必須是第一個有效行格式是relation relation-name。如果名稱里帶空格必須用英文單引號或雙引號包起來否則 WEKA 解析直接報錯。屬性聲明用attribute開頭每個屬性一行順序極其重要——它決定了數(shù)據(jù)部分每一列對應(yīng)哪個屬性。比如humidity是第三個被聲明的屬性那數(shù)據(jù)部分每行用逗號切開后的第三個數(shù)就是 humidity 的值。最后一個聲明的屬性默認被當作 class 屬性在分類或回歸任務(wù)里就是目標變量。2.2 四種數(shù)據(jù)類型與日期格式的寫法WEKA 支持的屬性類型有四種numeric數(shù)值型、nominal-specification分類型用花括號列出所有可能取值、string字符串型、date [date-format]日期時間型。分類型的寫法是attribute outlook {sunny, overcast, rainy}花括號里的值區(qū)分大小寫。日期型稍微特殊格式是attribute name date [date-format]默認格式是 ISO-8601 的yyyy-MM-ddTHH:mm:ss。如果你數(shù)據(jù)里的日期是2024/01/15這種斜杠分隔的寫法就必須在聲明里顯式指定date yyyy/MM/dd否則 WEKA 會把它當成字符串或者直接解析失敗。下面是一個最小可用的 ARFF 模板你可以直接抄去改relation my_dataset attribute age numeric attribute income numeric attribute student {yes, no} attribute credit_rating {fair, excellent} attribute buys_computer {yes, no} data 25,50000,yes,fair,no 30,80000,no,excellent,yes 35,60000,yes,fair,yes這段聲明里age和income是數(shù)值型student、credit_rating、buys_computer是分類型。buys_computer放在最后自動成為目標變量。數(shù)據(jù)部分每行五個值順序必須和屬性聲明完全一致少一個逗號或者多一個空格都可能讓 WEKA 讀出一堆問號。注意ARFF 文件里不要用中文標點逗號必須是英文逗號花括號和引號也必須是英文半角。我見過有人從 Word 里復制屬性名結(jié)果引號是彎的WEKA 直接報Unable to determine structure as arff。3. 把 CSV 和 Excel 喂給 WEKA轉(zhuǎn)換命令與 Explorer 預處理實操3.1 CSV 轉(zhuǎn) ARFF 的兩條路WEKA 原生支持 CSV但有個硬性要求CSV 第一行必須是屬性名。很多從 Matlab 導出的 CSV 沒有表頭Excel 另存為 CSV 時也可能丟掉表頭這時候直接丟給 WEKA它會把第一行數(shù)據(jù)當成變量名后面全亂套。常見做法是先用 UltraEdit 或 VS Code 打開 CSV手工補一行屬性名屬性個數(shù)必須和數(shù)據(jù)列數(shù)一致用英文逗號隔開。補好表頭之后轉(zhuǎn)換最快的方式是走 WEKA 的 Simple CLI。啟動 WEKA 主程序點下方Simple CLI按鈕在窗口最下方的輸入框里敲java weka.core.converters.CSVLoader bank-data.csv bank-data.arff這條命令調(diào)用CSVLoader類讀取bank-data.csv把標準輸出重定向到bank-data.arff。注意路徑問題如果 CSV 不在 WEKA 當前工作目錄下要么寫絕對路徑要么先cd過去。轉(zhuǎn)換完成后用文本編輯器打開 ARFF 檢查一下重點看attribute的類型是不是合理——WEKA 會自動推斷數(shù)值列給numeric文本列給nominal但有時候會把本該是分類的列推斷成string那就需要手動改。另一條路是在 Explorer 里操作打開 WEKA進Explorer點Open file選 CSVWEKA 會彈窗問你是否轉(zhuǎn)換確認后直接加載。然后點Save按鈕在保存類型里選.arff就能存成 ARFF。這條路適合不習慣命令行的新手但批量轉(zhuǎn)換時還是 CLI 更省事。3.2 Explorer 界面八個區(qū)域的分工Explorer 是 WEKA 用得最多的模塊界面可以分成八個區(qū)域來理解。區(qū)域 1 是頂部選項卡切換 Preprocess、Classify、Cluster、Associate、Select attributes、Visualize 等不同任務(wù)面板。區(qū)域 2 是常用按鈕包括打開數(shù)據(jù)、保存、編輯、Undo。區(qū)域 3 是 Filter 選擇區(qū)點Choose會彈出一棵 Filter 樹數(shù)據(jù)預處理主要靠它。區(qū)域 4 顯示數(shù)據(jù)集的基本情況比如實例數(shù)、屬性數(shù)。區(qū)域 5 列出所有屬性勾選后點Remove可以刪列刪錯了用區(qū)域 2 的Undo找回。區(qū)域 6 顯示選中屬性的摘要數(shù)值屬性和分類屬性的摘要形式不一樣。區(qū)域 7 是直方圖如果最后一個屬性是分類變量直方圖會按類別比例分色。區(qū)域 8 是狀態(tài)欄右邊的 WEKA 鳥在動說明正在執(zhí)行任務(wù)右鍵狀態(tài)欄可以觸發(fā) Java 內(nèi)存垃圾回收。以bank-data.csv為例這個數(shù)據(jù)集有 id、age、sex、region、income、married、children、car、save_acct、current_acct、mortgage、pep 這些列。id 是唯一標識對挖掘任務(wù)沒用在區(qū)域 5 勾選id然后點Remove刪掉。刪完后保存一次用文本編輯器打開 ARFF你會看到 WEKA 已經(jīng)為每個屬性自動選好了類型。3.3 數(shù)值屬性離散化Discretize Filter 的參數(shù)怎么設(shè)有些算法只能處理分類型屬性比如 Apriori 關(guān)聯(lián)規(guī)則。bank-data里有三個數(shù)值型變量age、income、children。其中children只有 0、1、2、3 四個取值直接在 ARFF 文件里把attribute children numeric改成attribute children {0,1,2,3}就行改完在 Explorer 里重新打開選中children看區(qū)域 6 的 Type 是不是變成了Nominal。age和income的離散化用DiscretizeFilter。在區(qū)域 3 點Choose逐級找到weka.filters.unsupervised.attribute.Discretize點擊后 Choose 旁邊的文本框會顯示Discretize -B 10 -M -0.1 -R first-last。點這個文本框彈出參數(shù)窗口把attributeIndices改成1,4對應(yīng) age 和 income 在屬性列表里的位置把bins改成3其他不動點 OK 回到 Explorer再點Apply。區(qū)域 5 里 age 和 income 就變成分類屬性了取值形如(-inf-34.333333]。如果嫌這種區(qū)間標識太晦澀保存 ARFF 后用文本編輯器把所有(-inf-34.333333]替換成0_34其他區(qū)間類似處理。替換時注意引號ARFF 里帶特殊字符的 nominal 值需要用單引號包起來。attribute age {0_34,34_50,50_inf} attribute income {0_30k,30k_60k,60k_inf}這樣改完可讀性提升一大截后續(xù)看規(guī)則輸出也舒服得多。提示Discretize 的-M參數(shù)是useEqualFrequency默認-M -0.1表示不啟用等頻分箱。如果你希望每個區(qū)間樣本數(shù)盡量均勻把-M勾上-0.1改成-1。4. 避坑與排查ARFF 讀取失敗、類型推斷錯誤和內(nèi)存溢出4.1 現(xiàn)象打開 ARFF 報 “Unable to determine structure as arff”原因通常有三個文件里有中文標點或不可見字符屬性聲明順序和數(shù)據(jù)列數(shù)對不上data后面有空行或者行尾有多余逗號。解決方法是先用文本編輯器的“顯示不可見字符”功能檢查一遍確保所有分隔符都是英文半角。然后數(shù)一下attribute的行數(shù)和數(shù)據(jù)部分每行的逗號數(shù)屬性數(shù)應(yīng)該等于逗號數(shù)加一。如果數(shù)據(jù)行末尾多了一個逗號WEKA 會認為多了一列直接報錯。4.2 現(xiàn)象CSV 轉(zhuǎn)換后第一行變成了屬性名數(shù)據(jù)少了一行原因就是 CSV 沒有表頭WEKA 把第一行數(shù)據(jù)當成了屬性名。解決方法是手工補一行屬性名或者在轉(zhuǎn)換時用-H參數(shù)指定不把第一行當表頭但這樣屬性名會變成att1、att2這種默認名后續(xù)還得改。我一般直接補表頭雖然多一步但屬性名可控。4.3 現(xiàn)象數(shù)值列被推斷成 nominal或者 nominal 列被推斷成 stringWEKA 的自動推斷基于采樣數(shù)據(jù)量小或者取值特殊時容易翻車。比如income列如果前幾行都是整數(shù)WEKA 給numeric但如果中間混了一個N/A就可能變成string。解決方法是轉(zhuǎn)換后打開 ARFF 手動改attribute的類型聲明。改完保存在 Explorer 里重新加載驗證。4.4 現(xiàn)象Explorer 跑算法時卡死狀態(tài)欄的鳥一直動但不出結(jié)果大概率是 Java 堆內(nèi)存不夠。WEKA 默認堆內(nèi)存可能只有 512MB數(shù)據(jù)量稍大就撐不住。解決辦法是啟動 WEKA 時加-Xmx參數(shù)比如java -Xmx4g -jar weka.jar把最大堆內(nèi)存調(diào)到 4GB。Windows 下可以改RunWeka.ini里的maxheap值。另外右鍵狀態(tài)欄觸發(fā)垃圾回收只能臨時緩解根治還是得加內(nèi)存。4.5 現(xiàn)象Discretize 之后屬性值變成All或者只有一個區(qū)間原因通常是attributeIndices設(shè)錯了或者選中的屬性本身就是 nominal 類型。Discretize 只對 numeric 屬性生效如果屬性已經(jīng)是 nominalFilter 會把它所有值歸到一個區(qū)間。解決方法是先確認屬性類型只對 numeric 列做離散化并且attributeIndices用屬性在列表里的序號不是屬性名。5. 進階技巧用 UltraEdit 批量改 ARFF 與交叉驗證的實操細節(jié)5.1 批量替換 nominal 區(qū)間標識的腳本化思路手工替換幾十個區(qū)間標識很痛苦我一般用 UltraEdit 的“在文件中替換”功能或者寫個簡單的 Python 腳本處理。思路是讀入 ARFF 文件用正則匹配\(-inf-([\d.])\]這種模式替換成可讀的區(qū)間名。下面是一個示例腳本import re def simplify_arff_intervals(filepath): with open(filepath, r, encodingutf-8) as f: content f.read() # 匹配形如 (-inf-34.333333] 的區(qū)間標識 pattern r\(-inf-([\d.])\] def repl(match): upper float(match.group(1)) return f0_{int(upper)} content re.sub(pattern, repl, content) # 匹配形如 (34.333333-50] 的中間區(qū)間 pattern2 r\(([\d.])-([\d.])\] def repl2(match): lower int(float(match.group(1))) upper int(float(match.group(2))) return f{lower}_{upper} content re.sub(pattern2, repl2, content) with open(filepath, w, encodingutf-8) as f: f.write(content) simplify_arff_intervals(bank-data.arff)這段代碼先處理(-inf-上限]形式的下界無窮區(qū)間再處理(下限-上限]形式的中間區(qū)間。替換后的值不帶引號因為0_34這種字符串不包含特殊字符ARFF 解析器能直接識別。注意替換前備份原文件正則匹配不到的情況要人工檢查。5.2 在 Explorer 里跑交叉驗證與查看規(guī)則輸出預處理完的數(shù)據(jù)可以直接在 Explorer 的 Classify 面板跑分類。選一個算法比如trees.J48Test options 里選Cross-validationFolds 設(shè) 10點Start。右側(cè) Classifier output 會顯示準確率、混淆矩陣和決策樹。如果跑的是 Associate 面板的 Apriori輸出的是關(guān)聯(lián)規(guī)則這時候之前離散化并簡化過的區(qū)間名就派上用場了規(guī)則像age0_34 income0_30k buys_computerno這樣讀起來一目了然。我自己的習慣是每次拿到新數(shù)據(jù)先補表頭轉(zhuǎn) ARFF再刪 ID 列然后對數(shù)值列做 Discretize最后用腳本簡化區(qū)間名。這套流程走完再跑算法基本不會在數(shù)據(jù)格式上翻車。從那以后我每次處理新數(shù)據(jù)集都強制走一遍這個檢查清單省下來的調(diào)試時間夠跑好幾輪實驗了。希望幫到你。本文還有配套的精品資源點擊獲取