R是進行運算、清洗、匯總及生成概率統(tǒng)計等數(shù)據(jù)處理的一個絕佳選擇。此外,由于它獨立于平臺、短期內不會消失,所以生成的程序可以在任何地方運行。并且,它具備非常棒的輔助資源。
本文摘錄自James D.Miller撰寫的《數(shù)據(jù)科學統(tǒng)計學》(Statistics for Data Science)一書,該書由Packt Publishing出版。
R是一種易上手的語言和環(huán)境,它本身很靈活且專注于統(tǒng)計計算,因此成為運算、清洗、匯總及生成概率統(tǒng)計等數(shù)據(jù)處理的一個絕佳選擇。
此外,以下是用R進行數(shù)據(jù)清洗的其他原因:
由于大量數(shù)據(jù)科學家都在使用R,所以它短時間內不會消失。
R獨立于平臺,因此可以在任意地方運行程序。
R有絕佳的輔助資源---Google一下,你就可以看到。
注:盡管作者將示例數(shù)據(jù)命名為“賭博數(shù)據(jù)”(Gamming Data),它只是用來演示代碼的賭博數(shù)據(jù)。
離群點
對離群點最簡單的解釋是:離群點是和其余數(shù)據(jù)不匹配的數(shù)據(jù)點。按照慣例,任何過高、過低或者異常(基于項目背景)的數(shù)據(jù)都是離群點。作為數(shù)據(jù)清洗的一部分,數(shù)據(jù)科學家通常要識別出離群點并用通用的方法解決它:
刪除離群點的值,甚至是離群點對應的實際變量。
轉換變量值或變量本身。
讓我們來看一下實際案例中如何用R識別并解決數(shù)據(jù)離群點。
老虎機在賭博界十分流行(老虎機的操作方法是把硬幣投入到機器中,并拉動把手來決定回報)。如今大部分老虎機都電子化了,編程使它們的所有活動都能被持續(xù)追蹤。在本文的案例中,賭場的投資者希望利用這些數(shù)據(jù)(以及各種補充數(shù)據(jù))來調整盈利策略。換句話說,什么能讓老虎機賺更多錢?是機器的主題還是類型?新機器比舊機器或老式機器更有利可圖嗎?機器的位置會產(chǎn)生怎樣的影響?低面額的機器會賺更多錢嗎?我們嘗試用離群點來找到答案。
給定一個集合或賭博數(shù)據(jù)庫(格式為逗號分隔或CSV文本文件),其中包括的數(shù)據(jù)如老虎機的位置、錢的面額、月份、日、年、機器類型、機器的年齡、促銷、優(yōu)惠券、天氣和投幣量(投幣量是放入機器的錢幣總額減去支付的數(shù)額)。
作為一個數(shù)據(jù)科學家,第一步要對數(shù)據(jù)進行綜評(有時稱為概述),此時我們要確定是否存在異常值,第二步是解決這些離群點。
步驟一 數(shù)據(jù)概述
R使這一步驟變得非常簡單。盡管可以通過很多方式編程求解,但我們要嘗試用最少的程序代碼或腳本來解決問題。將CSV文件定義為R的變量(命名為MyFile)并將文件讀入為數(shù)據(jù)框(命名為Mydata):
MyFile《-“C:/GammingData/SlotsResults.csv” MyData《- read.csv(file=MyFile, header=TRUE, sep=“,”)
在統(tǒng)計學上,箱型圖是一種簡單的方式以得到統(tǒng)計數(shù)據(jù)集的分布、變異性和中心(或中位數(shù))相關信息,所以我們將用箱型圖來研究我們能否識別出中位數(shù)Coin-in以及能否找到離群點。為了達成這些,我們可以讓R畫出文件中每個老虎機的Coin-in值,繪制箱型圖的函數(shù)如下:
boxplot(MyData[11],main=‘GammingData Review’, ylab = “Coin-in”)
注:Coin-in是文件中的第11列,所以直接將它作為boxplot函數(shù)的參數(shù)。此外還添加了一個可選擇的參數(shù)(再次強調,本文已盡量保持代碼的簡潔度),以便在可視化圖中添加標題。
執(zhí)行前文的代碼可以得到下圖效果,包括中位數(shù)(中位數(shù)在箱型圖中是中間橫穿的線)以及四個離群點:
步驟2-處理離群點
現(xiàn)在我們發(fā)現(xiàn)數(shù)據(jù)中確實存在離群點,我們要解決這些點以保證它們不會對本研究產(chǎn)生負面影響。首先,我們知道Coin-in有負值是不合理的,因為機器輸出的錢幣一定不會比投入到機器中的硬幣多?;谶@個原則,我們可以從文件中刪除Coin-in為負值的記錄。此外,R可以幫助我們用subset生成一個新的數(shù)據(jù)框,新數(shù)據(jù)集中只有Coin-in中的非負值。
我們要將subset數(shù)據(jù)框命名為noNegs:
noNegs《- subset(MyData, MyData[11]》0)
接下來,我們要再一次畫圖以確定已經(jīng)刪除負值離群點:
boxplot(noNegs[11],main=‘GammingData Review’, ylab = “Coin-in”)
這就產(chǎn)生了新的箱型圖,如下圖中所示:
我們可以用同樣的方法去除Coin-in中極端的正值(大于1500美元)得到另一個數(shù)據(jù)子集并再次畫圖:
noOutliers《-subset(noNegs, noNegs[11]《1500) boxplot(noOutliers[11],main=‘GammingData Review’, ylab = “Coin-in”)
當你對數(shù)據(jù)進行不同的迭代后,建議你保存大部分版本的數(shù)據(jù)(如果不是最重要的)。你可以用write.csv這個R函數(shù):
write.csv(noOutliers,file=“C:/GammingData/MyData_lessOutliers.csv”)
注:大部分數(shù)據(jù)科學家在整個項目中采取通用的命名規(guī)律。文件的名字應該盡可能清晰以便今后幫助你節(jié)省時間。此外,特別是在處理大量數(shù)據(jù)時,你需要注意內存空間的問題。
以上代碼的輸出結果如下:
領域知識
接下來,另一個數(shù)據(jù)清洗的技術是基于領域知識清理數(shù)據(jù)。這并不復雜,這種技術的關鍵是使用數(shù)據(jù)中無法察覺的信息。例如,當我們知道Coin-in不可能有負值時,我們排除了Coin-in負值的情況。另一個案例是颶風Sandy襲擊美國東北部的時間。在這段時間內,機器的Coin-in值都很低(非零)。數(shù)據(jù)科學家應該基于信息判斷是否要移除某段特定時期內的數(shù)據(jù)。
有效性檢查
交叉驗證是一種幫助數(shù)據(jù)科學家在數(shù)據(jù)庫中使用規(guī)則的技術。
注:有效性檢查是統(tǒng)計數(shù)據(jù)清洗中最普遍的形式,并且是數(shù)據(jù)開發(fā)者和數(shù)據(jù)科學家都非常熟悉的流程。
數(shù)據(jù)清洗時可以設定任意數(shù)量的有效性原則,這些原則要遵循數(shù)據(jù)科學家的意圖或目標。例如有如下原則:數(shù)據(jù)類型(例如,某個字段一定要是數(shù)值型),范圍限制(數(shù)據(jù)或日期要在一個特定范圍內),要求(某個字段不能為空或沒有值),唯一性(一個字段,或字段的結合,一定是數(shù)據(jù)庫中唯一的),組成員(這個值一定是列表中的值),外鍵(案例中一定要被定義的明確的值或滿足特殊規(guī)則),正則表達式模式(簡單地說就是這個值的格式滿足預設的格式),交叉字段驗證(案例中的字段組合要滿足特定標準)。
按照前文提到的內容,我們來看一些案例,從數(shù)據(jù)類型開始(也稱為強制原則)。R提供的六個強制函數(shù)如下:
as.numeric
as.integer
as.character
as.logical
as.factor
as.ordered
as.Date
這些函數(shù),結合一些R的知識,使得在數(shù)據(jù)庫中轉換數(shù)據(jù)變得簡單。例如,以前文的賭博數(shù)據(jù)為例,我們可以生成新的賭博結果文件,其中年齡值被存為字符型(或文本值)。為清理它,我們需要將其轉化為數(shù)據(jù)型。我們可以運用以下R代碼完成快速轉化:
noOutliers[“Age”]《-as.numeric(noOutliers[“Age”])
一個需要注意的地方:用這種簡單方法時,如果有數(shù)據(jù)不能轉化,需要將其設定為NA值。在類型轉換中,最大的工作是理解需要輸入什么數(shù)據(jù)以及哪些數(shù)據(jù)類型是合法的;R有很廣泛的數(shù)據(jù)類型,包括標量、向量(數(shù)值型,字符型,邏輯型),矩陣,數(shù)據(jù)框及列表。
數(shù)據(jù)清洗中我們要關注的另一個領域是正則表達式。在實踐中,特別是當處理的數(shù)據(jù)來源于很多渠道時,數(shù)據(jù)科學家確實面對如下問題:字段不是理想的格式(對于當下目標而言)或者字段值的格式不一致(可能會引發(fā)錯誤的結果)。例如日期、社會安全號碼(SSN)以及手機號碼?;跀?shù)據(jù)的來源,你不得不重新輸入(如前文描述),但是通常情況下,你需要基于目標將數(shù)據(jù)重新定義為可以使用的模式。
注:重新輸入數(shù)據(jù)是很重要的,這樣R就知道將值作為目前的數(shù)據(jù)并且你可以正確使用各種R數(shù)據(jù)函數(shù)。
一個常見的案例是當數(shù)據(jù)包括形式為YYYY/MM/DD的日期數(shù)據(jù)時,你想按每周匯總的形式呈現(xiàn)出時間序列分析,或者其他需要日期值的操作但是可能需要重新定義日期格式,或者你需要將其變?yōu)镽日期類型。所以,假定一個新的賭博文件——只有兩列數(shù)據(jù):日期和投幣量,這個文件是一個老虎機每天的投幣量。
新的文件記錄如下截圖所示:
數(shù)據(jù)科學家可以用各種數(shù)據(jù)清洗的案例。從驗證每個數(shù)據(jù)點的數(shù)據(jù)類型入手,我們可以用R函數(shù)class來驗證文檔的數(shù)據(jù)類型。首先(如我們在前文案例中所作),讀入CSV文件存為數(shù)據(jù)框:
MyFile《-“C:/GammingData/SlotsByMachine.csv” MyData《- read.csv(file=MyFile, header=TRUE, sep=“,”)
隨后,我們可以使用class函數(shù),如下圖截圖所示:
從上圖中可以看到用class來顯示數(shù)據(jù)類型。
MyData是用來保存賭博數(shù)據(jù)的數(shù)據(jù)框,日期Date是向量類型,投幣量Coinin是一個整數(shù)。所以,數(shù)據(jù)框和整數(shù)是有意義的,但是要注意R將日期設置為向量(factor)類型。向量是分類變量,在匯總統(tǒng)計、繪圖和回歸中非常有用,但它不是非常適用日期型。為了解決這個問題,我們可以使用R函數(shù)substr和paste,如下所示:
MyData$Date《-paste(substr(MyData$Date,6,7),substr(MyData$Date,9,10), substr(MyData$Date,1,4),sep=“/”)
以上代碼重新定義了日期字段的格式。它將數(shù)據(jù)字段值分成三部分(月、日和年)然后按照理想的順序(/分隔符(sep))粘貼在一起,如下截圖所示:
我們發(fā)現(xiàn)這一行腳本將日期字段轉換為字符類型,最后我們可以用as.Date函數(shù)將值重設為日期(Date)類型:
稍微嘗試一下,就可以重新格式化來得到理想的字符串或字符數(shù)據(jù)點。
改善數(shù)據(jù)
通過改善進行數(shù)據(jù)清理是另一種常見的技術,添加相關信息、事實或數(shù)據(jù)使得數(shù)據(jù)變得完整(可能更有價值)。這些附加數(shù)據(jù)的來源可以是用數(shù)據(jù)中現(xiàn)有信息或從其他來源添加信息進行計算。數(shù)據(jù)科學家花費時間完善數(shù)據(jù)的原因有很多。
基于當前的目的或目標,數(shù)據(jù)科學家補充的信息可能用于參考、比較、對比或發(fā)現(xiàn)趨勢。
典型的用例包括:
衍生事實計算
對比日歷與財政年度的使用
轉換時區(qū)
貨幣轉換
添加當前和前期指標
計算價值,如每天總出貨量
保持緩慢變化的維度
注:作為數(shù)據(jù)科學家,你要經(jīng)常用腳本來改善數(shù)據(jù),這個方法要比直接編輯數(shù)據(jù)文檔好得多,因為這樣出錯的可能性更低并且可以維持原始文件的完整性。此外,建立腳本可讓你將改善的過程重復應用于多個文件或收到的新版文件中,不需要重做同樣的工作。
回到我們的賭博數(shù)據(jù)中,假定我們在接收老虎機的投幣量文檔,同時公司在美國大陸外的地方設立賭場。這些新地點正在向我們發(fā)送文件,并且數(shù)據(jù)將納入到我們的統(tǒng)計分析中。我們發(fā)現(xiàn)這些國際文件是以當?shù)刎泿庞嬎愕耐稁帕俊榱苏_地對數(shù)據(jù)建模,我們要將數(shù)據(jù)轉化為美元。
場景如下:
文件來源:英國
使用貨幣:英鎊
將英鎊轉化為美元的公式十分簡單,只要用數(shù)額乘以匯率即可。所以,在R中:
MyData$Coinin《-MyData$Coinin* 1.4
以上代碼可以完成我們想要的轉換;然而,數(shù)據(jù)科學家要決定那種貨幣將被轉化(英鎊)以及匯率應當是多少。這并不是什么大問題,但是我們可以嘗試創(chuàng)建一個用戶定義的函數(shù)來確定要使用的匯率,如下所示:
getRate《- function(arg){ if(arg==“GPB”) { myRate 《- 1.4 } if(arg==“CAD”) { myRate 《-1.34 } return(myRate) }
盡管之前的代碼更簡單,但以上代碼說明了創(chuàng)建邏輯的要點,以便我們今后可以重復使用:
最終,為了使整個過程更完美,我們要將函數(shù)儲存(在R文檔中)以便將來使用:
source(“C:/GammingData/CurerncyLogic.R”)
隨后:
MyFile《-“C:/GammingData/SlotsByMachine.csv” MyData《- read.csv(file=MyFile, header=TRUE, sep=“,”) MyData$Coin《- MyData$Coinin * getRate(“CAD”)
注:當然,在最理想的情況下,我們可改進函數(shù)以便在表或文件中根據(jù)國家代碼查找匯率,這樣匯率能夠隨即時價值而改變并且可以從程序中解耦數(shù)據(jù)。
數(shù)據(jù)調和
基于研究分析的整體目標,數(shù)據(jù)科學家可以通過數(shù)據(jù)調和來轉換、翻譯、或將數(shù)據(jù)值映射到其他理想值。最普遍的案例是性別或國家代碼。例如,如果你的文檔中將性別編碼為0和1或M和F,你想將數(shù)據(jù)轉化為一致的MALE或FEMALE。
關于國家代碼,數(shù)據(jù)科學家想要繪制地區(qū)的匯總:北美、南美和歐洲,而不是分開的美國、加拿大、墨西哥、巴西、智利、英國、法國和德國。在這種情況下,將產(chǎn)生合計值如下:
北美=美國+加拿大+墨西哥
南美=巴西+智利
歐洲=英國+法國+德國
需要強調的是,數(shù)據(jù)科學家可能會將所有包括性別的調查文檔合并在一起,稱為gender.txt,但是文檔中的性別編碼不同(1,0,M,F(xiàn),Male和Female)。如果我們嘗試用R函數(shù)表,我們會看到如下可理解的結果:
如果在最理想的狀態(tài)下進行可視化分析:
lbs= c(“Male”, “Female”) pie(table(MyData),main=“Gambling by Gender”)
我們看到如下截圖:
為了解決性別數(shù)據(jù)編碼不一致的問題,我借用了前文案例中的概念并生成簡單的函數(shù)來幫助我們重新編碼:
setGender《- function(arg){ if(substr(arg,1,1)==“0”| toupper(substr(arg,1,1))==“M”) { Gender 《- “MALE” } if(substr(arg,1,1)==“1”| toupper(substr(arg,1,1))==“F”) { Gender 《- “FEMALE” } return(Gender) }
此次,我加入了toupper函數(shù),因此我們不必擔憂大小寫,并且有substr來控制長度大于一個字符的值。
注:假定參數(shù)的值是0,1,m,M,f,F(xiàn),Male或Female,否則將會引發(fā)報錯。
由于R將性別作為向量類型,我發(fā)現(xiàn)很難應用簡單的函數(shù),所以我決定生成新的R數(shù)據(jù)框來容納調和后的數(shù)據(jù)。并且用一個循環(huán)來讀入文檔中的記錄并將其轉化為Male 或Female:
MyFile《-“C:/GammingData/Gender.txt” MyData《- read.csv(file=MyFile, header=TRUE, sep=“,”) GenderData《-data.frame(nrow(MyData)) for(iin 2:nrow(MyData)) { x《-as.character(MyData[i,1]) GenderData[i,1] 《-setGender(x) }
現(xiàn)在我們將通過以下語句得到更適合的可視化結果:
lbls= c(“Male”, “Female”) pie(table(GenderData),labels=lbls, main=“Gambling by Gender”)
以上代碼的輸出結果如下所示:
標準化
大多數(shù)主流數(shù)據(jù)科學家都已經(jīng)注意到在開始統(tǒng)計研究或分析項目之前,將數(shù)據(jù)標準化作為數(shù)據(jù)清理過程一部分的重要性。這是很重要的,如果沒有標準化,量綱不同的數(shù)據(jù)點對分析的貢獻會不均等。
如果你認為在0到100之間的數(shù)據(jù)點比0到1范圍內的變量影響更大,你可以理解數(shù)據(jù)標準化的重要性。使用這些未經(jīng)過標準化的變量,事實上在分析中賦予較大范圍的變量更多的權重。為了解決這一問題并均衡這些變量,數(shù)據(jù)科學家試圖將數(shù)據(jù)轉化為可比的量綱。
數(shù)據(jù)點的中心化是數(shù)據(jù)標準化中最常見的例子(盡管還有很多)。為了使數(shù)據(jù)點中心化,數(shù)據(jù)科學家把文件中的每個數(shù)據(jù)點減去所有數(shù)據(jù)的平均值。
R不是做運算,它提供了scale函數(shù),其默認方法可以通過一行代碼將文件中的數(shù)值中心化或縮減。讓我們來看一個簡單的例子。
回到老虎機的案例中!在我們的賭博文件中,你可能還記得有一個字段叫投幣量(Coinin),它是一個表示投入到機器中美元總額的值,這被看作衡量機器盈利能力的指標。這似乎是我們盈利能力分析中使用的一個重要的數(shù)據(jù)點。然而這些金額可能是誤導性的,因為不同的機器有不同面額(換句話說,一些機器接受美分,而其他機器接受一角硬幣或美元)。也許機器面值的差別造成了不同的量綱,我們可以使用scale函數(shù)來解決這種情況。首先,我們在下面的截圖中看到,Coin.in的值:
我們可以通過以下語句對數(shù)據(jù)點Coin.in進行中心化處理:
scale(MyData[11],center = TRUE, scale = TRUE)
center的值決定了如何行中心化。center為TRUE是需要對應的行減去Coin.in均值(省略NA)。scale的值決定了如何行縮放(在中心化之后)。如果scale的值是TRUE且center值是TRUE,那么縮放是通過除以(中心化后的)Coin.in的標準差來進行的。如果center值是False,將得到均方根值。
在下圖截屏中看到了差別:
評論
查看更多