一、每個觀測變量構成一列
二、每個觀測對象構成一行
三、每個類型的觀測單元構成一個表
就像咱們最常接觸的鳶尾花數據:css
每一列就是觀測的指標:花瓣長度,花瓣寬度,萼片長度,萼片寬度,種類;每一行就是一株鳶尾花的觀測值,構成整張表的元素就是四個數值變量,一個分類分類變量。python
然而出於排版的考慮咱們抓下來的數據每每不是那麼的友好,好比說咱們能夠看到的數據一般是這樣的:git
而不是:數據庫
固然,除了這種把列表每一列表明一些數值這種狀況外,還有多個變量儲存爲一列(好比列表不只以"<10k","10k-50k","50k-100k"作表頭,甚至還加上性別信息"m<10k","m10k-50k","m50k-100k","f<10k","f10k-50k","f50k-100k",其中m表明男性,f表明女性),還有更過度的將列表的變量不只儲存在列中,行中也有統計變量。app
面對這些很差的table,咱們首先要作的就是數據管理,將數據整理爲一個乾淨的數據集。函數
按照en:DAMA的定義:「數據資源管理,致力於發展處理企業數據生命週期的適當的建構、策略、實踐和程序」。這是一個高層而包含普遍的定義,而並不必定直接涉及數據管理的具體操做(如關係數據庫的技術層次上的管理)。咱們這裏主要講述對於數據的變量命名與數據的合併,旨在方便數據共享。學習
數據管理首先要作的就是大體上了解你的數據,好比有什麼樣的變量,每一行大體長成什麼樣,最經常使用的就是head(),tail().
咱們要作的基本上就是這麼幾項工做:lua
給每個變量命名,而不是V1,V2,若是有必要能夠給出code book。spa
每一個變量名最好具備可讀性,除非過長,不然不要用縮寫,例如AgeAtDiagnosis這個命名遠好於AgeDx。code
一般來講,最好將數據放在一張表裏面,若是由於數據過多,項目過雜,分紅了幾張表。那麼必定須要有一列使得這些表之間可以鏈接起來,但儘可能避免這樣作。
咱們以UCI的Human Activity Recognition Using Smartphones Data Set 爲例來看看數據是如何變成一個基本符合要求的數據。這個數據咱們已經下載下來了,其中關於數據的詳細信息能夠參閱read me文檔,因爲UCI的數據一般都是一個基本合乎規範的數據集(主要是指它的數據集的變量名都是以V1,V2來命名的)加上一個code book。那麼咱們看看各個數據的名稱(在feature文件裏)
咱們能夠看到各個特徵的名稱直接標在數據上是很是不友善的,咱們爲了讓他具備可讀性,咱們以展現在咱們眼前的6個數據爲例:
variablename <- head(name)# 將標籤中的大寫字母轉爲小寫,咱們這裏沒有因此再也不賦值,若是須要全變爲大寫,可使用touppertolower(variablename$V2)
# 將變量名分離成3部分splitNames <- strsplit(variablename$V2, "-")splitNames[[1]]
## [1] "tBodyAcc" "mean()" "X"
# 將變量名合成有意的名稱named <- function(x) { rr <- paste(x[2], x[1], "-", x[3], sep = "") chartr("()", "of", rr) } sapply(splitNames, named)
用這樣的名字給數據集命名就感受舒服多了,咱們將一些R中對字符串經常使用的操做函數總結以下,方便咱們對數據名稱的修改:
sub:替換字符串中的第一個模式爲設定模式(pattern).
gsub:全局替換字符串中的相應模式
grep,grepl:這兩個函數返回向量水平的匹配結果,grep僅返回匹配項的下標,而grepl返回全部的查詢結果,並用邏輯向量表示有沒有找到匹配。
nchar:統計字符串單字數目
substr:取子串
paste:將字符串連接起來,sep參數能夠設置鏈接符
str_trim:去掉字符串空格
變量的名稱建議知足以下要求:
英文變量名儘量用小寫
儘量的描述清楚變量特徵 (Diagnosis versus Dx)
不要太複雜
不要有下劃線、點、空格
字符型變量應該知足:
是因子類型的應該轉化爲factor
因子儘量具備必定的描述性 (例如:若是0/1表示真假,那麼用TRUE/FALSE代替0/1;在表示性別時用Male/Female代替M/F)
接下來咱們討論數據集的合併,主要使用函數merge。
咱們如下面兩個數據集的合併爲例:
df1 <- data.frame(id = sample(1:10), reviewer_id = sample(5:14), time_left = sample(1321:1330), x = rnorm(10))df2 <- data.frame(id = sample(1:10), answer = rep("B", 10), time_left = sample(321:330), y = rnorm(10)) head(df1, n = 3)
head(df2, n = 3)
merge函數調用格式爲:
參數說明:
x,y:兩個數據框
by, by.x, by.y:指定用於合併的列的名稱。
all,all.x,all.y:默認的all = FALSE至關於天然鏈接, 或者說是內部連接. all.x = TRUE是一個左鏈接, all.y = TRUE是一個又鏈接, all = TRUE 至關於一個外部連接.
仔細觀察下面3個例子你就會發現其中的奧祕:
mergedData <- merge(df1,df2,by.x="reviewer_id",by.y="id",all=TRUE) head(mergedData)
mergedData <- merge(df1,df2,by.x="id",by.y="id",all=TRUE) head(mergedData)
mergedData2 <- merge(df1,df2,all=TRUE) head(mergedData2)
在plyr包中還提供了join,join_all,arrange等函數來實現表的鏈接,但我想merge這個函數已經足夠用了,因此咱們不在多說。固然,在極少數特別好的狀況下(好比列的變量是一致的,或者行的觀測個體是一致的時候)rbind,cbind也是有用的。
有些時候咱們會遇到一些特殊的字符串:日期。R中提供了各式各樣的函數來處理時間:
Sys.setlocale("LC_TIME", "C")
## [1] "C"
x <- c("1jan1960", "2jan1960", "31mar1960", "30jul1960")z <- as.Date(x, "%d%b%Y") format(z, "%a %b %d")
## [1] "Fri Jan 01" "Sat Jan 02" "Thu Mar 31" "Sat Jul 30"
weekdays(z)
## [1] "Friday" "Saturday" "Thursday" "Saturday"
julian(z)
transform(z, weekend = as.POSIXlt(z, format = "%Y/%m/%d")$wday %in% c(0, 6))
說到數據操做,這也是一個十分寬泛的話題,在這裏咱們就如下4個方面進行介紹:
數據的篩選,過濾:根據一些特定條件選出或者刪除一些觀測
數據的變換:增長或者修改變量
數據的彙總:分組計算數據的和或者均值
數據的排序:改變觀測的排列順序
然而在進行這一切以前首先要作的就是了解你的數據,咱們以世界銀行的數據Millennium Development Goals爲例,來一步步演示如何進行數據操做:
if (!file.exists("C:/Users/yujun/Documents/MDG_Data.csv")) { download.file("http://databank.worldbank.org/data/download/MDG_csv.zip","F:/MDG.zip") unzip("F:/MDG.zip") }MDstats<-read.csv("C:/Users/yujun/Documents/MDG_Data.csv")
首先先來看一部分數據:
head(MDstats)
tail(MDstats)
咱們顯然發現了這不是一個tidy data,那麼咱們先將其變換爲咱們喜歡的tidy data,以後再看看數據摘要及數據集各單元的屬性:
咱們能夠看看各個數值數據的分位數:
quantile(MDstatsMelt$value,na.rm=TRUE)
看看各個國家的統計數據有多少:
table(MDstatsMelt$countrycode)
看看缺失值:
sum(is.na(MDstatsMelt$value)) #總的缺失值
## [1] 495519
colSums(is.na(MDstatsMelt)) #每一列的缺失值
# 若是咱們用回tidy前的數據集,那麼這個函數會顯得比較有用colSums(is.na(MDstats))
# 等價的處理方式stat <- function(x) { sum(is.na(x)) } tapply(MDstatsMelt$value, MDstatsMelt$year, stat)
統計某個國家的統計數據佔總統計數目的多少
table(MDstatsMelt$countryname %in% c("China"))
prop <- table(MDstatsMelt$countryname %in% c("China"))[2]/sum(table(MDstatsMelt$countryname %in% c("China")))prop
看看數據集的大小:
object.size(MDstatsMelt)
## 22301832 bytes
print(object.size(MDstatsMelt),units="Mb")
## 21.3 Mb
至此,咱們能夠說咱們對數據有了必定的瞭解。另外值得一提的是,對於某些特定的數據,也許xtabs,ftable是有用的。
要提取相應內容的數據,最爲經常使用的就是提取相應元素,好比提取某個元素,提取某一行,某一列。咱們經過下面下面的例子來學習:
data<-data.frame(a=sample(1:10),b=rep(c("a","b"),each=5),cdf=rnorm(10))data
#提取相應元素data[2,1]
## [1] 10
data[[1]][[2]]
## [1] 10
data[[c(1,2)]]
## [1] 10
data$a[2]
## [1] 10
#提取某一列data[[3]]
data$cdf
data$c
data[["c"]]
## NULL
data[["c", exact = FALSE]]
數據的篩選還有一個最爲經常使用的的就是移除缺失值:
data<-data.frame(a=c(sample(1:5),NA,NA,sample(6:10)),b=c(rep(c("a","b"),each=5),NA,NA),cdf=rnorm(12))data
good <- complete.cases(data)data[good, ]
bad <- as.data.frame(is.na(data))data[!(bad$a|bad$b|bad$c),]
數據篩選有時是爲了得到符合條件的數據:
X <- data.frame("var1"=sample(1:5),"var2"=sample(6:10),"var3"=sample(11:15))X <- X[sample(1:5),]; X$var2[c(1,3)] = NAX
X[(X$var1 <= 3 & X$var3 > 11),]
subset(X,(X$var1 <= 3 & X$var3 > 11))
X[(X$var1 <= 3 | X$var3 > 15),]
X[which(X$var1 <= 3 | X$var3 > 15),]
對於取子集的函數subset,在幫助文檔中有一段warning是值得咱們注意的:「This is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like [, and in particular the non-standard evaluation of argument subset can have unanticipated consequences."
常見的數據變換函數有:
abs(x) 絕對值
sqrt(x) 開根號
ceiling(x) 求上線,例:ceiling(3.475) = 4
floor(x) 求下線,例:floor(3.475) = 3
round(x,digits=n) 四捨五入,例:round(3.475,digits=2) = 3.48
signif(x,digits=n) 四捨五入,例:signif(3.475,digits=2) = 3.5
cos(x), sin(x) etc.三角變換
log(x) 對數變換
log2(x), log10(x) 以二、10爲底的對數變換
exp(x) 指數變換
除此之外,咱們還常常對數據加標籤,以期在迴歸中測量其效應。咱們以MASS包的shuttle數據集爲例,想知道不一樣類型的風(wind)是否須要使用不一樣的裝載機(use),這裏咱們但願將head wind標記爲1,auto use也記爲1,咱們能夠按照以下辦法設置虛擬變量:
library(MASS)
data(shuttle) head(shuttle)
## Make our own variables just for illustrationshuttle$auto <- 1 * (shuttle$use == "auto")shuttle$headwind <- 1 * (shuttle$wind == "head") head(shuttle)
固然對於因子類型變量,relevel函數在線性模型的分析中也是能取得等價效果的。
有些時候,咱們還經常將連續數據離散化,這時咱們須要用到函數cut:
data <- rnorm(1000) table(cut(data, breaks = quantile(data)))
library(Hmisc)
table(cut2(data, g = 4))
detach("package:Hmisc", unload = TRUE)
得到分組區間後,咱們只須要將區間的因子重命名就成功的實現了數據的離散化。
對數據進行彙總,分類匯老是咱們也比較經常使用的,好比對行或列求和,求均值,求分位數:
data <- matrix(1:16, 4, 4)data
apply(data, 2, mean)
## [1] 2.5 6.5 10.5 14.5
apply(data, 1, sum)
## [1] 28 32 36 40
apply(data, 1, quantile, probs = c(0.25, 0.75))
apply(data, 2, quantile, probs = c(0.25, 0.75))
有時候,爲了更快些,咱們會用一些函數替代apply:
rowSums = apply(x, 1, sum)
rowMeans = apply(x, 1, mean)
colSums = apply(x, 2, sum)
colMeans = apply(x, 2, mean)
咱們有時也會處理一些列表,對列表的分類彙總咱們會用到sapply,lapply,不一樣的是前者返回一個向量或矩陣,後者返回一個列表,例:
x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE)) lapply(x, mean)
sapply(x, mean)
# median and quartiles for each list elementlapply(x, quantile, probs = 1:3/4)
sapply(x, quantile)
有時候咱們還會進行分類彙總,如統計男女工資均值,這時你能夠用tapply:
group <- (rbinom(32, n = 20, prob = 0.4))groups <- factor(rep(1:2,10)) tapply(group, groups, length)
tapply(group, groups, sum)
tapply(group, groups, mean)
數據的排序須要用到的函數常見的有sort和order,其中sort返回排序的結果,order返回對應數據的排名。例:
X <- data.frame("var1"=sample(1:5),"var2"=sample(6:10),"var3"=sample(11:15))X <- X[sample(1:5),]X$var2[c(1,3)] <- NAsort(X$var2,decreasing=TRUE)
## [1] 9 8 6
sort(X$var2,decreasing=TRUE,na.last=TRUE)
## [1] 9 8 6 NA NA
order(X$var2,decreasing=TRUE)
## [1] 2 5 4 1 3
order(X$var2,decreasing=TRUE,na.last=TRUE)
## [1] 2 5 4 1 3
X[order(X$var2),]
#deal with the linkX$var2[c(1)] <- sample(na.omit(X$var2),1)X[order(X$var2,X$var3),]
有些時候,更爲強大的aggregate函數是咱們須要的,咱們以R的內置數據集state.x77爲例:
aggregate(state.x77, list(Region = state.region, Cold = state.x77[,"Frost"] > 130), mean)
固然,這裏還有一個更爲基本與靈活的函數,split,能夠幫助你將數據分爲若干張知足分類條件的表,你能夠一張一張的處理它們:
library(datasets)
head(airquality)