ggplot2是R語言最流行的第三方擴展包,是RStudio首席科學家Hadley Wickham讀博期間的做品,是R相比其餘語言一個獨領風騷的特色。包名中「gg」是grammar of graphics的簡稱,是一套優雅的繪圖語法。Wickham Hadley將這套語法詮釋以下:html
一張統計圖形就是從數據到幾何對象(geometric object,縮寫geom)的圖形屬性(aesthetic attribute,縮寫aes)的一個映射。此外,圖形中還可能包含數據的統計變換(statistical transformation,縮寫stats),最後繪製在某個特定的座標系(coordinate system,縮寫coord)中,而分面(facet)則能夠用來生成數據不一樣子集的圖形。python
這個解釋讀起來仍是有點抽象。咱們舉個具體的例子來解讀這個概念。假設如今咱們要對一批連續取值的數據繪製直方圖。首先,要定義清楚須要幾個分組或者每一個分組的區間,根據分組定義統計落在這個分組裏的個數,這個步驟就是把data變爲stats。而後,須要選定表達數據的幾何對象,這個例子選用的是條塊bar,這個步驟就是選geom。geom有一堆屬性須要設定,好比x、y、顏色等,稱爲aes,哪一個aes由哪一個stats指定,須要指定一個映射關係mapping,即指定誰對誰。知道誰對誰後,還須要知道怎麼個對法,須要由scale決定,好比stats的color字段取值爲1應該對到什麼顏色上,取值爲2應該對到什麼顏色上。這些完成了之後,統計圖形的主體部分就成形了,可是假如咱們但願在直方圖上,再畫一個機率密度曲線圖,怎麼辦?ggplot2的思想很是精妙,把上面的主體部分稱爲一個圖層layer,一個統計圖形能夠擁有多個圖層,每一個圖層疊加起來造成咱們要的效果。接下來,再選定一個座標系統coord,一張統計圖形plot就作好了。假如咱們有多組數據,每組數據都要按照相同的方法畫一張圖,每張圖重複敲代碼很繁瑣,就可使用分面facet快速繪製多張統計圖形。這個過程用圖形總結以下:spring
咱們能夠看到ggplot2相比其餘繪圖系統的幾個特性:編程
標準化:任何一個統計圖形遵循相同的繪圖流程,因此語法高度統一;segmentfault
面向數據:上面的繪圖流程只與數據有關,與數據無關的繪圖細節封裝在單獨的theme()
方法裏,數據相關繪圖與數據無關繪圖分離;app
這兩大特性解放了數據分析師的思惟,作到繪圖時所思即所見,很是優雅高效。下面咱們來逐步剖析每一個元素的內容。編程語言
ggplot2接受的輸入數據通常是data.frame
,這是一個表格型結構,每一行是一個觀測(observation),每一列是一個變量(variable)。R語言內置了許多著名的數據集,本文選取其中的iris進行講解。iris中文名是鳶尾花,有四個屬性,分別是Sepal.Length(花萼長度),Sepal.Width(花萼寬度),Petal.Length(花瓣長度),Petal.Width(花瓣寬度),以及一個類別標籤Species。我在網上找了一個圖片,作個標註,方便朋友理解。ide
咱們可使用str()
查看數據集的結構,用summary()
對每個變量進行統計。函數
str(iris)
summary(iris)
Hadley對data.frame
提出了一個是否tidy的概念,抽象來說就是一個變量必須有本身獨立的一列,一個觀測必須有本身獨立的一行,每一個取值必須有本身獨立的一個單元格。爲了便於理解,咱們從R for Data Science這本書截取出這個圖進行解釋:oop
左邊的數據是tidy的,右邊的數據是不tidy的,經過另外一個包tidyr能夠輕鬆完成兩者的轉換。ggplot2的數據要求是tidy的。
幾何對象,說的直觀一些,就是你選擇什麼幾何圖形來表示這組數據。ggplot2提供了衆多幾何對象geom_xyz()
供你們選擇。舉兩個常見的例子,geom_point()
用於表示兩個連續變量之間的關係,幾何形狀是點;geom_bar()
用於表示x軸爲離散變量,y軸爲連續連續變量之間的關係,幾何形狀是條塊。完整的幾何對象請下載RStudio公司總結的ggplot2 cheetsheet。
幾何對象須要解決一個問題,即相同數據的幾何對象位置相同,是放在一個位置相互覆蓋仍是用別的排列方式。ggplot2的幾何對象有一個position
選項,用於指定如何在空間內佈置相同取值的集合對象。dodge
爲並排模式;fill
爲堆疊模式,並歸一化爲相同的高度;stack
爲純粹的堆疊模式;jitter
會在X和Y兩個方向增長隨機的擾動來防止對象之間的覆蓋。
在ggplot2裏,幾何對象與統計變換每每是一一對應的。每一個統計變換須要經過一個幾何對象來展示;每一個幾何對象的展示依賴統計變換的結果。舉個簡單例子,如下兩行代碼的效果是同樣的:
ggplot(iris) + geom_bar(aes(x=Sepal.Length), stat="bin", binwidth = 3) ggplot(iris) + stat_bin(aes(x=Sepal.Length), geom="bar", binwidth = 3)
每一個幾何對象都有本身的屬性,這些屬性的取值須要經過數據提供。數據與圖形屬性之間的映射關係稱爲mapping,在ggplot2中用aes()
進行定義。常見的圖形屬性有:x
,y
,size
,color
,group
。圖形屬性的任意一項均可以用數據的某一個變量來表示。
前面提到aes()
設定了數據與圖形屬性的映射關係,可是數據怎麼映射爲屬性,這就是標尺(Scales)的功能。對於任何一個圖形屬性,如x
,y
,alpha
,color
,fill
,linetype
,shape
,size
,ggplot2都提供如下四種標尺:
scale_*_continuous()
:將數據的連續取值映射爲圖形屬性的取值
scale_*_discrete()
:將數據的離散取值映射爲圖形屬性的取值
scale_*_identity()
:使用數據的值做爲圖形屬性的取值
scale_*_mannual()
:將數據的離散取值做爲手工指定的圖形屬性的取值
舉個例子
group_iris <- iris %>% group_by(Species) %>% dplyr::summarise(avg_sepal_length=mean(Sepal.Length)) str(group_iris) p <- ggplot(group_iris) + geom_bar(aes(x=Species, weight=avg_sepal_length, fill=Species)) p
p + scale_fill_manual( values = c("skyblue", "royalblue", "navy"), # mannual類scale特有的選項,指定圖形屬性的取值範圍 limits = c("setosa", "versicolor", "virginica"), # 數據的取值範圍 breaks = c("setosa", "versicolor", "virginica"), # 圖例和軸要顯示的分段點 name = "Species", # 圖例和軸使用的名稱 labels = c("set", "ver", "vir") # 圖例使用的標籤 )
除了上述四大類通用的標尺,特定的圖形屬性還有一些專門的標尺類型。對於x
和y
類圖形屬性,有以下幾種特殊的標尺:
scale_x_date(labels=date_format("%m/%d"), breaks=date_breaks("2 weeks"))
scale_x_datetime()
scale_x_log10()
scale_x_reverse()
scale_x_sqrt()
對於color
和fill
類的圖形屬性,有以下幾類特殊標尺:
scale_fill_brewer(palette="Blues")
:根據調色盤生成顏色標尺,可用的調色盤能夠經過RColorBrewer::display.brewer.all()
命令查看;對於具體的一個調色盤,能夠經過RColorBrewer::brewer.pal(n=4, name="Blues")
查看具體某個名字調色盤的n
個配色值。
`scale_fill_grey(start=0.2, end=0.8, na.value="red"):灰度標尺
scale_fill_gradient(low="red", high="yellow")
:雙色漸變標尺
scale_fill_gradient2(low="red", high="blue", mid="white", midpoint=25)
:三色漸變標尺
scale_fill_gradientn(colours=terrain.colors(6))
:n色漸標尺,其餘的調色盤有rainbow()
,heat.colors()
,topo.colors()
,cm.colors()
以及RColorBrewer包的調色盤。
對於shape
類的圖形屬性,咱們能夠手工指定形狀:scale_shape_manual(values=c(3:7)
。每一個形狀用數字表示,根據下圖能夠選擇本身須要的形狀。
ggplot2的繪圖過程有點像Photoshop,有一個圖層的理念,每一個圖層能夠有本身的圖形對象和圖形屬性,經過+
將不一樣圖層疊加起來生成最後的統計圖形。若是將數據定義在ggplot()
中,那麼全部圖層均可以共用這個數據;若是將數據定義在geom_xyz()
中,那麼這個數據就只供這個幾何對象使用。
ggplot2默認的座標系是笛卡爾座標系,能夠用以下方法指定取值範圍:coord_cartesian(xlim=c(0,5), ylim=c(0,3))
。若是想要讓x軸和y軸換位置,好比將柱形圖換成條形圖,可使用coord_flip()
函數。coord_polar(theta="x", direction=1)
是角度座標系,theta指定角度對應的變量,start指定起點離12點鐘方向的偏離值,direction若爲1表示順時針方向,若爲-1表示逆時針方向。
掌握了數據、幾何對象、圖形屬性、圖層和座標系的概念後,咱們就能夠開始繪製常見的統計圖形了。
Kaggle數據挖掘競賽裏有一個經典的探索性分析例子,對iris數據集進行了各類形式的可視化,幫助人經過直觀的圖形更深地理解特徵與label的關係。Kaggle官網給出了Python版本的實現。本節用R對該notebook的代碼進行重現。
library(ggplot2) # Make scatter plot of Sepal.Length and Sepal.Width p.scatter <- ggplot(iris) + geom_point(aes(x=Sepal.Length, y=Sepal.Width)) p.scatter
# One piece of information missing in the plots above is what species each plant is p.scatter <- ggplot(iris) + geom_point(aes(x=Sepal.Length, y=Sepal.Width, color=Species)) p.scatter
# Boxplot to explore numeric variable p.box <- ggplot(iris) + geom_boxplot(aes(x=Species, y=Petal.Length)) p.box
# One way we can extend this plot is adding a layer of individual points on top of it p.box.jitter <- p.box + geom_jitter(aes(x=Species, y=Petal.Length)) p.box.jitter
# A violin plot combines the benefits of the previous two plots and simplifies them # Denser regions of the data are fatter, and sparser thiner in a violin plot p.violin <- ggplot(iris) + geom_violin(aes(x=Species, y=Petal.Length)) p.violin
# A final plot useful for looking at univariate relations is the kdeplot, p.density <- ggplot(iris) + geom_density(aes(x=Petal.Length, colour=Species)) p.density
分面,就是分組繪圖,根據定義的規則,將數據分爲多個子集,每一個子集按照統一的規則單獨製圖,排布在一個頁面上。ggplot2提供兩種分面模式:facet_grid()
和facet_wrap()
。
咱們先來看一下facet_grid()
的效果。
library(tidyr) library(dplyr) # 將數據變爲tidy的 tidy_iris <- iris %>% gather(feature_name, feature_value, one_of(c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"))) p.box.facet <- ggplot(tidy_iris) + geom_boxplot(aes(x=Species, y=feature_value)) + facet_grid(feature_name~Species) p.box.facet
能夠看到facet_grid()
是一個二維的矩形佈局,每一個子集的位置由行位置變量~列位置變量
的決定,在上面的例子中就是每個Species的取值做爲一行,每個feature_name的取值做爲一列。
再來看一下facet_wrap()
的效果。
p.box.facet <- ggplot(tidy_iris) + geom_boxplot(aes(x=Species, y=feature_value)) + facet_wrap(~feature_name+Species, scales="free") p.box.facet
facet_wrap()
生成一個動態調整的一維佈局,根據~位置變量1+位置變量2+...
來肯定每一個子集的位置,先逐行排列,放不下了移動到下一行。scales="free"
讓每一個子圖的座標系適合本身的數據,便於在有限的空間裏充分展現子圖的細節,但也失去了不一樣子圖之間比較的做用,須要謹慎使用。
分面的特色是能夠快速生成多個子圖,每一個子圖的生成方式是同樣的,所以只須要指定分組的規則便可。可是有時候咱們但願繪製多個子圖,每一個子圖的生成方法卻不同,這個時候分面就不起做用了,須要使用grid包提供的佈局功能。下面咱們用ggplot2和grid的佈局實現一個較爲複雜的統計圖形效果:
library(grid) # Show bivariate scatter plot and univariate histogram p.hist.len <- ggplot(iris) + geom_histogram(aes(x=Sepal.Length)) p.hist.wid <- ggplot(iris) + geom_histogram(aes(x=Sepal.Width)) + coord_flip() grid.newpage() pushViewport(viewport(layout = grid.layout(3, 3))) print(p.scatter, vp=viewport(layout.pos.row=2:3, layout.pos.col=1:2)) print(p.hist.len, vp=viewport(layout.pos.row=1, layout.pos.col=1:2)) print(p.hist.wid, vp=viewport(layout.pos.row=2:3, layout.pos.col=3))
在作數據分析時,咱們常常須要觀察變量自身與變量之間的兩兩關係。這個過程當中須要繪製大量的圖表,且每一個業務的數據分析都須要這麼作,所以算是一種重複性比較大的工做。咱們可使用GGally包來快速完成這個探索性分析的任務。
library(GGally) # Another useful seaborn plot is the pairplot, which shows the bivariate relation # between each pair of features # # From the pairplot, we'll see that the Iris-setosa species is separataed from the other # two across all feature combinations ggpairs(iris, aes(colour=Species), alpha=0.4) # R could be better!!
Kaggle數據挖掘競賽剩下的例子是繪製Parallel coordinate graph、Andrews Curve、radviz,前兩個的實現參考以下,最後一個暫時沒找到對應的方法。
# Parallel coordinate graph & Andrews Curve # 修改自:http://cos.name/2009/03/parallel-coordinates-and-andrews-curve/ # 輪廓圖的思想很是簡單、直觀,它是在橫座標上取n個點,依次表示各個指標(即變量);橫座標上則對應各個指標的值(或者通過標準化變換後的值),而後將每一組數據對應的點依次鏈接便可 # 調和曲線圖的思想和傅立葉變換十分類似: # 根據三角變換方法將 n 維空間的點映射到二維平面上的曲線上,其中x取值範圍爲[-pi,pi]。 # Another multivariate visualization technique pandas has is parallel_coordinates # Parallel coordinates plots each feature on a separate column & then draws lines # connecting the features for each data sample p.paral <- ggplot(cbind(iris %>% gather(feature_name, feature_value, one_of(c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"))), id=1:nrow(iris))) + geom_line(aes(x=feature_name, y=feature_value, group=id, colour=Species)) p.paral
# One cool more sophisticated technique pandas has available is called Andrews Curves # Andrews Curves involve using attributes of samples as coefficients for Fourier series # and then plotting these andrews_curve <- function(data, x_col, y_col, step=pi/30){ x = as.matrix(data[, x_col]) t = seq(-pi, pi, pi/30) m = nrow(x) n = ncol(x) f = matrix(0, m, length(t)) for(i in 1:m) { f[i,] = x[i,1]/sqrt(2) for(j in 2:n) { if (j%%2 == 0) f[i, ] = f[i, ] + x[i, j] * sin(j/2 * t) else f[i, ] = f[i, ] + x[i, j] * cos(j%/%2 * t) } } colnames(f) <- t label <- data[, y_col] id <- c(1:nrow(f)) res <- cbind(as.data.frame(f), label, id) %>% gather(x, y, -label, -id, convert = TRUE) } iris.andrew <- andrews_curve(iris, x_col=c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width"), y_col="Species") p.andrew <- ggplot(iris.andrew) + geom_line(aes(x, y, group=id, color=label)) p.andrew
# A final multivariate visualization technique pandas has is radviz # Which puts each feature as a point on a 2D plane, and then simulates # having each sample attached to those points through a spring weighted # by the relative value for that feature # 暫時沒能力實現
全部與數據不相關的圖形控制細節都放在theme()
這個函數裏。ggplot2內置了一些常見的主題:theme_bw()
,theme_classic()
,theme_grey()
,theme_minimal()
。若是須要更多的主題能夠安裝ggthemes
包,也能夠自定義主題。
ggplot2能夠設定圖例的位置:theme(legend.position="bottom")
,其餘選項有top、left和right。
每一個圖形屬性都會有一個圖例,圖例的類型共有三種:colorbar爲顏色條,適合連續變量;legend爲鍵值對,適合有限取值的變量;none,將一個圖形屬性的圖例設置爲none,則不顯示這個圖形屬性的圖例。
經常使用的繪圖標籤有:
ggtitle("New Plot Title")
:指定圖形名稱
xlab("New X label")
:指定x軸標籤
ylab("New Y label")
:指定y軸標籤
圖例標籤須要使用scale_*()
的name
和labels
選項進行指定
關於做者:丹追兵,數據分析師一枚,編程語言python和R,使用Spark、Hadoop、Storm、ODPS。本文出自丹追兵的pytrafficR專欄,轉載請註明做者與出處:https://segmentfault.com/blog...