《Using OpenRefine》翻譯~12

上一篇:《Using OpenRefine》翻譯~11

4:單元格值轉換

第二章:分析和修改數據中,我們學習到OpenRefine可以自動修改一列的單元格內容,比如去除多餘空格。上一點中,我們學習到聚類是另一種修改列單元格內容的方法。然而,以上方法都僅僅是單元格值轉換通用方法的一部分。你可以通過不同的稍顯複雜的方式修改單元格值。雖然這看起來像是EXCEL公式,但是你會驚訝於其功能的強大。

舉個例子,假如你不喜歡使用管道符作爲Categories列單元格值得分隔符,你想替換成爲逗號後面加個空格作爲分隔符。當然你可以先把多值單元格拆分然後再組合實現,但其實我們可以一步完成上述操作,點擊Categories列下拉菜單選擇Edit cells | Transform…. 會出現如下的轉換對話框:


以上界面中最重要的部分是Expression(表達式), 這裏可以輸入小腳本,用來修改值。Language 項可以讓我們選擇表達式的語言,現在支持的語言有General Refine Expression Language(GREL), Jython (Java環境的Python語言), 和Clojure(函數型語言,類似Lisp語言),如果你對後兩種語言較熟悉,你會發現書寫表達式十分簡單。但是,GREL是設計特別用來作簡單轉換的,所以本書我們將使用GREL。

Preview頁,我們能夠同時看到初始值和轉換後的值,這可以讓你實時的調試轉換表達式,能夠立即看到效果。History頁保存了你曾經用過的表達式,這樣你後續可以直接重用原來的公式。History頁還可以對公式打上星標,這樣你還可以在Starred頁找到它們。最後Help頁對大多數表達式做了簡介。

對話框底部,我們可以確定如果表達式在某個特定單元格中運行結果出錯時怎麼辦。你可以選擇保持原值、置空、使用錯誤值。另外,你也可以選擇將轉換表達式對單元格進行重複應用的次數,這個很有用,可以對處理結果再進行處理。比如,如果你有一個表達式,用來將首字母大寫的單詞刪除,那麼就可以利用這個重複功能將單元格中所有大寫單詞均刪除。

回到我們的任務:將管道符修改爲逗號後面加個空格。表達式處默認值是value,就像你猜到的那樣,這代表原始值。讓我們做個小實驗看看會發生什麼:輸入1234作爲新單元格值 。預覽界面會更新,顯示所有單元格值變爲1234。這當然沒什麼意義,但對於你理解功能肯定有用。我們真正要做的是對原值按照我們的意願進行替換。在Help頁,我們找到實現上面意圖的GREL函數叫做replace。因爲我們想把管道符替換成逗號,所以我們輸入value.replace("|", ", ")。這裏我們對字符加了雙引號,因爲它們是字符串而非數字。預覽界面會刷新單元格值,我們發現就是我們想要的結果,所以點擊OK。只需要很短的時間,OpenRefine就轉換好了Categories列的單元格內容,所有的管道符已經被替換。

在修改分隔符時需要特別小心,因爲有可能分隔符恰恰是值內容中的一部分。比如:分類Cup, saucer and plate sets中包含逗號,所以如果對這個字段進行替換則很有可能導致錯誤。但是,我們這裏舉例的時候還是會用逗號。

爲了讓我們更加熟練值轉換操作,我們再嘗試下,這次假設我們想把Provenance列中的分號修改爲逗號。點擊Provenance(Production)下拉菜單Edit cells, Transform…,然後輸入表達式value.replace(";", ",")。表達式本身並沒有錯,但是我們在預覽窗口中發現有許多錯誤提示。這剛剛可以讓我們試着設置On error參數設定(我也建議你試試看),當然更重要的是我們要知道究竟出了什麼問題。錯誤信息如下:Error: replace expects 3 strings, or 1 string, 1 regex, and 1 string。所以錯誤的原因是我們傳遞replace參數時出錯了。如果我們檢查下出現錯誤的單元格,我們發現是有些單元格爲null所導致。確實,因爲null並不是字符串,所以我們並不能對其中的字符進行操作。所以我們需要告訴OpenRefine只轉換非空的單元格。點擊Cancel,關閉對話框,再點擊Provenance(Production)列下拉菜單選擇Text filter.雖然我們可以選擇Facet by blank功能,但是我們可以通過直接選擇包含分號的單元格來節省時間,在文本過濾中輸入”;”就能夠篩選出我們需要的內容。現在再試着進行單元格轉換,我們發現篩選出的單元格內容都進行了替換,並且沒有任何出錯提示。

最後,爲了展示單元格值轉換的強大功能。我們將做一些複雜點的操作。雖然管道符已經被替換成了逗號,但是Categories列還有一些其他問題存在。確實,有一些值內容中就包含重複內容,比如14條記錄:Didactic displays, Pearl hells, Buttons,Didactic displays。我們無法採用上面的重複項處理來解決,因爲這裏的重複是在一個單元格內的。幸運的是,我們可以使用GREL來解決。打開Categories列的值轉換窗口,輸入如下表達式:value.split(", ").uniques().join(", ")。這個表達式看起來有點複雜,但是分開解讀還是比較容易理解的。首先第一個我們將值按照“,”分割(逗號後面跟一個空格),然後使用uniques函數去重,最後再把內容重新連接到一起。當你點擊OK後,OpenRefine會完成操作並且提示你有多少單元格進行了該項操作。

掌握GREL是簡單的

本小點介紹了一些例子,如果這裏還無法滿足你的要求,那麼附錄:正則表達式和GREL將完整的介紹GREL,學習後你將可以自己書寫表達式。

 

 

5:增加源列

有時候你可能希望在單元格值轉換的時候保留原單元格值。當然你可以在操作錯誤的時候通過Undo / Redo頁恢復原值。但是如果能夠同時顯示原值和轉換後的值得話一定會更好。因此,OpenRefine提供了增加一列,並且該列是基於其他列創建的功能。

假設我們希望增加一列,這一列是對應分類單元格中分類計數。點擊Categories列,選擇Edit column-> Add column based on this column…會彈出一個類似單元格轉換的對話框。不過,這次其提示需要一個列名。在New column name中輸入Category Count。現在我們可以創建分類計數的表達式了。因爲分類是被某個字符分隔的(管道符或者逗號,如果你學習過上一點的話),我們可以簡單的將它們拆分然後計數。表達式如下:value.split(",").length() ,Preview 面板會顯示結果,如果發現沒有問題,那麼點擊OK.確認。

OpenRefine增加了一列新列,這樣我們就可以使用Category Count列來分析我們的數據。比如,我們可以對Category Count列進行文本透視:Facet| Text facet. 因爲我們只是想對每個獨立的計數數量進行分析,而不是分析其值域。所以這裏使用文本透視比較簡單,雖然這列數據是數字格式。左側透視界面會顯示究竟分類數如何分佈,如下圖所示:


我們發現有一點比較奇怪:有一欄的值是(blank)。如果我們點擊下,我們發現所有的記錄Categories字段爲空,那麼爲什麼Category Count不顯示爲0呢?答案是對於空值單元格,這個轉換表達式會導致一個錯誤,因爲沒有值可以被分割。上一點的學習中,我們可能能夠做到在轉換前把這些行過濾掉了。不過我們這裏嘗試修復這些行。在透視界面中點擊blank),點擊Category Count 下拉菜單: Edit cells| Transform…. 如果我們在表達式窗口中輸入0並且點擊OK,那麼這些空值單元格就會變成0。那些行會消失,別奇怪,因爲我們在透視中還選中着blank,點擊過濾項 0(或者其他你像選擇的),你就能 得到你想要的數據。

從數據分析角度考慮,我們對於每條記錄中分類數計數中那些是最普遍的比較感興趣。在Category Count透視界面中,選擇Sort by:設置成 count.我們發現每條記錄中分類數爲2的最普遍,不過請注意只有這些值已經聚類和去重後纔是比較準確的,就像上一點所介紹的。有一次,我們感受到了GREL的強大。

6:拆分列

本章開始的時候,我們演示瞭如何將一個單元格中的多值內容拆分成多行。但是,有時候這並不能解決問題。現有例子中,單元格中的多個分類其實屬於同一個屬性:分類間比較相似,並且順序可以互換。但是如果多值單元格中的內容屬於不同的類別的話情況就不同了。比如,當一個clients表格包含電話字段但是沒有email字段,而某一個客戶卻同時又上面兩種信息。結果這個人的電話信息和email信息可能會被放在一起,用斜槓分隔。

Powerhouse Museum數據集中,我們也在很多列種發現這種情況。比如,在Provenance字段,我們能夠同時發現designers, makers等等信息。如果我們能夠把它們拆分成不同的列的話,我們分析就會更加有意義。我們可以點擊Provenance (Production)列下拉菜單: Edit column| Split into several columns….,我們能夠看到如下的拆分對話框:


我們可以選擇按照曾經介紹的by separator(按分隔符)分割, 還可以按照by field lengths.(按長度)分割。按長度分割在數據結構固定的時候特別有用,如1987 en-us,X/Y這樣的類型,其沒有固定的分隔符(或者根本沒有)。當然,本例中我們使用分隔符。一個有趣的選項是設置一個限制,因爲可能有分割成很多列,所以設置下限制比如5會比較明智。千萬不要忘記設置一個分隔符,比如這裏設置成“|”。你可以選擇讓OpenRefine猜測下分割後的單元格類型(比如分割後可能會出現數字),還可以讓OpenRefine刪除原來的列。

在你點擊OK後,你會發現OpenRefine將原來叫做Provenance (Production) 的列被替換成爲了很多叫做 Provenance(Production) 1, Provenance (Production) 2等等的列。這些列可以後續按照實際含義修改名稱。並不是所有列都有內容,只有那些至少含有5項的單元格分割後纔會所有單元格都有內容。雖然分割後不會超過你設置的最大列數目,但是還是會產生分割前的單元格分項較少,導致無法填滿所有的列的情況。

我們再對Object Title列進行分割,我們發現該列中有些單元格是以數字開頭的。如果把數字從中剝離出來應該十分有意義。首先,讓我們先過濾出這些數字開頭的項。點擊Object Title 下拉菜單中的Text filter.我們這裏寫上以數字開頭的正則表達式^\d.這個表達式告訴過濾器從開頭(^)進行查找並且尋找數字(\d)。別忘了勾選regular expression 。否則 OpenRefine 會把正則表達式當成字符查找。現在我們就得到了那些以數字開頭的項。

點擊Object Title下拉菜單,然後選擇Edit column |Split into several columns…. 現在我們使用一個空格作爲分隔符,設置我們最多要2列然後點擊OK. 數字和標題被分割成了兩列。

分割列比分割多值單元格功能更加強大,因爲其有很多配置選項。你甚至可以使用正則表達式來定義分隔符,這樣我們可以做到不同的內容應用不同的分隔符。另外,如果你對本小點中的正則表達式有些疑惑,別忘了參考附錄:正則表達式和GREL,那裏介紹的非常詳細。


下一篇:《Using OpenRefine》翻譯~13

發佈了15 篇原創文章 · 獲贊 16 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章