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