上一節我們通過爬蟲工具爬取了近七萬條二手房數據,那么這一節就對這些數據進行預處理,也就是所謂的ETL(Extract-Transform-Load)
一.ETL工具的必要性
數據分析的前提是數據清洗。不論如何高大上的算法,遇到錯誤數據,一個異常拋出來,絕對屍橫遍野。而你不能指望核心算法為你處理錯誤或者短缺的數據。所以,數據清洗(ETL)就變得必不可少了。 如果數據分析是炒菜階段,那么清洗就是洗菜,絕對是非常重要的一環。
而實際上,ETL工具可以很簡單,也可以很復雜。簡單到只需要把字符串轉換為數字或者提供正則表達式。而復雜的ETL需要建立完整的錯誤日志機制,智能處理,自動匯總,還要做成工作流,腳本等復雜的形式。我決定做一個折中,提供最需要和差不多夠用的功能。如果真有對ETL特別強烈而復雜的需求,那就只能借助專業的ETL工具了。
二.ETL插件
在本系統中,ETL以插件的形式存在,可供系統進行調用。這些ETL工具包括了常見的場景:
- 正則表達式提取
- 數據類型轉換,包括時間格式等
- 隨機數和范圍數生成
- 數據分割,排序和篩選
- 噪聲生成
- 字符串轉數字編號
- 腳本數據
- 高級的模塊 如 分詞,文本情感分析等
同時所有的模塊都可以支持二次擴展。可為了新的場景增加新的模塊。 模塊分為兩類:
- 無監督工具:不需要之前的數據,直接生成新數據,如噪聲產生器
- 有監督工具:需根據之前的數據生成,如正則提取
這些ETL插件可以形成一個處理隊列,以隊列的形式依次處理數據,形成職責鏈。這樣就能應對絕大多數的ETL需求。
三. 使用介紹
下面,我們就以北京房價樣例數據為例,進行ETL清洗。這些數據爬蟲來自於網絡,具體的爬取過程可參考前一節內容。
1. 數據導入和觀察
首先在數據管理器上點擊“導入”按鈕,導入XML數據文件,如下圖所示:
之后可以普通列表的形式,查看這些數據:
會發現這些數據非常有規律。我們可制定如下方案:
- 篩選出正常的數據,因為有些數據是殘缺的,比如“面積”一欄是空的。
- 其價格是XXXXX元/平米,為了進行統計,需要通過正則進行提取
- “屬性3” 樓層數,可通過/ ,進行分割,取第二個項就好,最后一項是板樓或塔樓
- 在“屬性3”中,可通過正則匹配提取年份
- 可在“坐標”一項中,通過分割,方便地提取編號,地理位置,所在小區和其他信息。
- 其他…
2.編寫數據篩選腳本
首先進行數據篩選,將“數據篩選”插件拖入算法框中:
同時進行配置,為了方便,我們僅提取前1000條數據作為分析目標。
最重要的是,編寫篩選的自定義函數腳本。與C#的語法相同:
點擊開始處理,即可篩選出滿足條件的前1000條數據。
3.進行ETL配置:
與上一步類似,將“數據生成與預處理”模塊拖到算法管理器中。
將該模塊的數據源,選為“全部”:
點擊命令列,可對ETL所需的插件進行配置:
集合編輯器中,列舉了系統加載的所有ETL插件,我們首先將價格提取出來:
選擇原始列名,填入新列名,如果不勾選“添加到新列”,則原始數據就會被覆蓋。同時填寫正則表達式 \d+ ,用於提取價格中的房價。同時,將目標類型選擇為INT,轉換完成后,數據的類型就會變為INT
類似的,可提取建設年份。
由於轉換后,建設年份為STRING類型,可再添加一個字符串轉時間的工具,方便轉換為DateTime,直接將原有的數據覆蓋就好。
接下來提取地理坐標: 觀察這些坐標,同樣可以使用正則匹配,此處從略。
接下來是所在的片區,它位於“坐標”這一屬性中。使用正則匹配並不方便,因此采用數列分割的方法,即通過字符對該屬性進行分割,提取出固定位置的項。通過觀察, 可通過符號,進行分割,正好位於第4項
類似的,可以提取小區名稱,與所在行政區的唯一區別在於匹配編號,要填2
最終完成的ETL流程如下圖所示:
這些ETL插件會順次執行。如果一個插件的結果依賴於前一個插件,則一定要排在依賴插件的后邊。
之后點擊開始處理,ETL流程即可啟動,所有的錯誤日志都會保存到一個專門的數據集中,用於再次分析和處理。這次處理沒有錯誤,系統提示ETL流程成功結束,下面就是經過ETL后得到的新列:
為了保險起見,我們將這次加載的所有設置保存為一個任務,名字為”ETL清洗任務”,如果遇到同樣的數據,可以進行相同的任務,而無需進行再次配置。
可以在生成的系統配置文件中,看到此次任務所保存的XML文件:
<Doc Name="ETL數據清洗任務" Description="任務描述" Group=""> <Nodes> <Children X="-2.01" Y="0" Z="0" Group="0" Key="數據篩選_1" Weight="1"> <Data Collection="全部" Name="數據篩選" NewDataSetName="" ScriptCode="return String.IsNullOrEmpty(item['價格']) ; // 1表示篩選該數據,否則表示不篩選" CanRemove="True" Start="0" End="1000" Layer="0" /> </Children> <Children X="3" Y="0" Z="0" Group="1" Key="數據生成和預處理_2" Weight="1"> <Data Collection="全部" Name="數據生成和預處理" Size="1001" Layer="0"> <Children Type="正則過濾器" CollumName="價格" NewCollumName="新價格" IsAddNewCollum="True" TargetDataType="INT" ScriptCode="\d+" Index="0" /> <Children Type="正則過濾器" CollumName="屬性3" NewCollumName="年份" IsAddNewCollum="True" TargetDataType="STRING" ScriptCode="\d{4}" Index="0" /> <Children Type="字符串轉時間" CollumName="年份" NewCollumName="" IsAddNewCollum="False" TargetDataType="DATETIME" Format="yyyy" /> <Children Type="數列分割" CollumName="坐標" NewCollumName="片區" IsAddNewCollum="True" TargetDataType="STRING" SplitChar="," Index="3" SplitPause="SplitPause" /> <Children Type="數列分割" CollumName="坐標" NewCollumName="小區名" IsAddNewCollum="True" TargetDataType="STRING" SplitChar="," Index="2" SplitPause="SplitPause" /> <Children Type="正則過濾器" CollumName="坐標" NewCollumName="lag" IsAddNewCollum="True" TargetDataType="DOUBLE" ScriptCode="\d{2}.\d+" Index="0" /> <Children Type="正則過濾器" CollumName="坐標" NewCollumName="Lng" IsAddNewCollum="True" TargetDataType="DOUBLE" ScriptCode="\d{3}.\d+" Index="0" /> </Data> </Children> </Nodes> <Paths /> </Doc>
三.總結
本節主要介紹了如何使用該工具進行ETL清洗,下一節我們將正式進入數據分析的流程。敬請期待。