R語言學習之第五章——高級數據管理

本章內容

1.數學和統計函數

2.字元處理函數

3.循環和條件執行

4.自編函數

5.數據整合與重塑

第一部分,我們將快速瀏覽R中的多種數學、統計和字元處理函數。為了讓這一部分的內容相互關聯,我們先引入一個能夠使用這些函數解決的數據處理問題。在講解過這些函數以後,再為這個數據處理問題提供一個可能的解決方案。

第二部分,我們將講解如何自己編寫函數來完成數據處理和分析任務。首先,我們將探索控制程序流程的多種方式,包括循環和條件執行語句。然後,我們將研究用戶自編函數的結構,以及在編寫完成後如何調用它們。

第三部分,我們將了解數據的整合和概述方法,以及數據集的重塑和重構方法。在整合數據時,你可以使用任何內建或自編函數來獲取數據的概述,所以你在本章前兩部分中學習的內容將會派上用場。

5.1 利用R中的數值和字元處理函數處理解決實際問題

5.2 數值和字元處理函數

R中數據處理函數,它們可分為數值(數學、統計、概率)函數和字元處理函數。

本例將展示如何將函數應用到矩陣和數據框的列(變數)和行(觀測)上。

01 數學函數

參考書籍表5-2,表中列出了常用的數學函數和簡短的用例。表中共計13類常用的數學函數,主要作用是對數據進行變換和運算。表中函數被應用於數值向量、矩陣或數據框時,它們會作用於每一個獨立的值。例如,

sqrt(c(4, 16, 25)) 的返回值為 c(2,4, 5)。n

02 統計函數

常用的統計函數參考書籍表5-3,表中許多函數參數都是可選的,參數不同,結果亦不同,比如求平均數、中位數、標準差、方差等。

#實戰應用如下。均值和標準差計算如下,上面的代碼是簡潔方式,下面的冗長方式。n> x <- c(1,2,3,4,5,6,7,8)n> mean(x) #直接用函數求平均數n[1] 4.5n> sd(x) #直接用函數求標準差n[1] 2.449490n

> n <- length(x) #x中的數量n> meanx <- sum(x)/n #先求和,在算平均數n> css <- sum((x - meanx)^2) # (x – meanx)^2從 x 的每個元素中減去了4.5,然後每個元素求平方,最後計算出平方的和n> sdx <- sqrt(css / (n-1)) #平方和除以數量減1,等於42/7=6,然後求出6的平方根,即為標準差n> meanxn[1] 4.5n> sdxn[1] 2.449490n

數據標準化具體使用scale()函數,默認對矩陣或數據框的指定列進行均值為0、標準差為1的標準化。

03 概率函數

概率函數通常用來生成特徵已知的模擬數據,以及在用戶編寫的統計函數中計算概率值。

在R中,概率函數形如 :

[dpqr]distribution_abbreviation()n

其中第一個字母表示其所指分布的某一方面:

d = 密度函數(density)

p = 分布函數(distribution function)

q = 分位數函數(quantile function)

r = 生成隨機數(隨機偏差)

常用的概率函數列於表5-4中。

x <- pretty(c(-3,3), 30) ny <- dnorm(x) nplot(x, y,n type = "l",n xlab = "Normal Deviate",n ylab = "Density",n yaxs = "i"n) #繪製正態曲線n

x <- pretty(c(-3,3), 30) nz<-pnorm(x)nplot(x, z,n type = "l",n xlab = "Normal Deviate",n ylab = "Distribution",n yaxs = "i"n) #繪製分布函數n

> pnorm(1.96) #位於z=1.96左側的標準正態曲線下方面積是多少?n[1] 0.9750021n> qnorm(.9,mean = 500,sd=100)# 均值為 500,標準差為 100的正態分布的0.9分位點值為多少?n[1] 628.1552n> rnorm(50,mean = 50,sd=10) #生成 50個均值為 50,標準差為 10的正態隨機數n [1] 51.87839 45.35005 59.93238 55.93086 60.02875 45.77850n [7] 40.00659 43.05473 66.34199 53.04694 55.62084 60.13278n[13] 39.26552 44.50102 65.56196 67.33899 44.08626 50.22214n[19] 41.26078 40.60966 54.02655 53.23637 49.32678 42.60044n[25] 66.34560 61.51955 51.37980 56.66308 56.71551 53.26159n[31] 50.68065 52.63917 38.80761 51.67646 50.47654 73.45159n[37] 49.58523 57.85701 40.33247 49.27015 48.60540 52.38546n[43] 42.89752 67.62153 45.24686 44.32443 42.24713 41.93737n[49] 46.12039 48.04349n

#生成0~1區間上服從正態分布的偽隨機數:n> runif(5)n[1] 0.8923759 0.2876101 0.2292473 0.7666098 0.8240967n> runif(5)n[1] 0.29292497 0.04201844 0.96997523 0.21433377 0.41058722n> set.seed(1234)#顯示並指定函數使用的種子n> runif(5)n[1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154n> set.seed(1234)#目的為讓重複上次的結果n> runif(5)n[1] 0.1137034 0.6222994 0.6092747 0.6233794 0.8609154n>n

#生成多元正態數據,使用MASS 包中的 mvrnorm() 函數,其格式為mvrnorm(n, mean, sigma),n其中 n 是你想要的樣本大小, mean 為均值向量,而 sigma 是方差—協方差矩陣(或相關矩陣)nn#生成服從多元正態分布的數據nlibrary(MASS)noptions(digits = 3)nset.seed(1234)#設定隨機數種子nmean<-c(230.7,146.7,3.6)#均值向量nsigma<-matrix(c(15360.8, 6721.2, -47.1, 6721.2,n 4700.9, -16.5, -47.1, -16.5, 0.3),n nrow = 3,ncol = 3)#協方差陣nmydata<-mvrnorm(500,mean,sigma)#生成多元正態數據nmydata<-as.data.frame(mydata)#矩陣轉換為數據框nnames(mydata)<-c("y","x1","x2")#對變數進行重命名ndim(mydata)#確認觀測的結果nhead(mydata,n=10)#輸出前十個觀測結果nndim(mydata)n[1] 500 3n> head(mydata,n=10)n y x1 x2n1 98.8 41.3 3.43n2 244.5 205.2 3.80n3 375.7 186.7 2.51n4 -59.2 11.2 4.71n5 313.0 111.0 3.45n6 288.8 185.1 2.72n7 134.8 165.0 4.39n8 171.7 97.4 3.64n9 167.2 101.0 3.50n10 121.1 94.5 4.10n

04. 字元處理函數

數學和統計函數是用來處理數值型數據的,而字元處理函數可以從文本型數據中抽取信息,設定隨機數種子指定均值向量、協方差陣生成數據查看結果或者為列印輸出和生成報告重設文本的格式。

一些最有用的字元處理函數見表5-6。

05.其他實用函數

06.將函數應用於矩陣和數據框

舉例如下:

> a<-5n> sqrt(a)n[1] 2.236068n> b<-c(1.243,5.654,2.99)n> round(b)n[1] 1 6 3n> c<-matrix(runif(12),nrow = 3)n> cn [,1] [,2] [,3] [,4]n[1,] 0.96359936 0.2160280 0.2890082 0.9128172n[2,] 0.20676238 0.2396466 0.8041144 0.3533918n[3,] 0.08619744 0.1971609 0.3782496 0.9314871n> log(c)n [,1] [,2] [,3] [,4]n[1,] -0.03707967 -1.532347 -1.2413001 -0.09121962n[2,] -1.57618505 -1.428590 -0.2180137 -1.04017797n[3,] -2.45111479 -1.623735 -0.9722009 -0.07097292n> mean(c) #對c中12個元素進行求均值n[1] 0.4648719n

R中提供了一個apply()函數,可將一個任意函數「應用」到矩陣、數組、數據框的任何維度上。 apply() 函數的使用格式為:apply(x, MARGIN, FUN, ...) 其中, x為數據對象, MARGIN是維度的下標, FUN是由你指定的函數,而...則包括了任何想傳

遞給FUN的參數。在矩陣或數據框中,MARGIN=1表示行,MARGIN=2表示列。

舉例如下:將一個函數應用到矩陣的所有行(列)

> mean(c)n[1] 0.4648719n> mydata<-matrix(rnorm(30),nrow = 6)n> mydatan [,1] [,2] [,3] [,4] [,5]n[1,] 0.4585260 1.2031271 1.2338845 0.5905186 -0.2806204n[2,] -1.2611491 0.7688732 -1.8913847 -0.4351408 0.8120776n[3,] -0.5274652 0.2383510 -0.2226513 -0.2507699 -0.2077037n[4,] -0.5568142 -1.4150281 0.7681275 -0.9262694 1.4507573n[5,] -0.3744387 2.9337744 0.3879537 1.0874358 0.8414932n[6,] -0.6044000 0.9350258 0.6091330 -1.9439592 -0.8657378n> apply(mydata,1,mean)n[1] 0.6410872 -0.4013448 -0.1940478 -0.1358454 0.9752437 -0.3739876n> apply(mydata,2,mean)#對每列進行求均值n[1] -0.4776235 0.7773539 0.1475105 -0.3130308 0.2917110n> apply(mydata,2,mean,trim=0.2)#求每列的截尾均值,最低和最高的20%均值被忽略n[1] -0.5157795 0.7863443 0.3856407 -0.2554154 0.2913117n>n

5.3 數據處理難題的一套解決方案

代碼清單5-6針對本章開始提出的問題給出了的解決方案。

> options(digits = 2)#限定小數點後兩位n> Student<-c("John Davis","Angela Williams","Bullwinkle Moose",n+ "David Jones","Janice Markhamer","Cheryl Cushing",n+ "Reuven Ytzrhak","Greg Knox","Joel England","Mary Rayburn")n> Math<-c(502,600,412,358,495,512,410,625,573,522)n> Science<-c(95,99,80,82,75,85,80,95,89,86)n> English<-c(25,22,18,15,20,28,15,30,27,18)n> roster<-data.frame(Student,Math,Science,English,n+ stringsAsFactors = FALSE)#生成花名冊n> roster#輸出花名冊n Student Math Science Englishn1 John Davis 502 95 25n2 Angela Williams 600 99 22n3 Bullwinkle Moose 412 80 18n4 David Jones 358 82 15n5 Janice Markhamer 495 75 20n6 Cheryl Cushing 512 85 28n7 Reuven Ytzrhak 410 80 15n8 Greg Knox 625 95 30n9 Joel England 573 89 27n10 Mary Rayburn 522 86 18n

> z<-scale(roster[,2:4])#用scale函數把成績全部用單位的標準差來表示n> zn Math Science Englishn [1,] 0.013 1.078 0.587n [2,] 1.143 1.591 0.037n [3,] -1.026 -0.847 -0.697n [4,] -1.649 -0.590 -1.247n [5,] -0.068 -1.489 -0.330n [6,] 0.128 -0.205 1.137n [7,] -1.049 -0.847 -1.247n [8,] 1.432 1.078 1.504n [9,] 0.832 0.308 0.954n[10,] 0.243 -0.077 -0.697nattr(,"scaled:center")n Math Science English n 501 87 22 nattr(,"scaled:scale")n Math Science English n 86.7 7.8 5.5n

> score<-apply(z,1,mean)#計算list各行的均值n> roster<-cbind(roster,score)#把各行均值score添加到roster中n> rostern Student Math Science English scoren1 John Davis 502 95 25 0.56n2 Angela Williams 600 99 22 0.92n3 Bullwinkle Moose 412 80 18 -0.86n4 David Jones 358 82 15 -1.16n5 Janice Markhamer 495 75 20 -0.63n6 Cheryl Cushing 512 85 28 0.35n7 Reuven Ytzrhak 410 80 15 -1.05n8 Greg Knox 625 95 30 1.34n9 Joel England 573 89 27 0.70n10 Mary Rayburn 522 86 18 -0.18n

> y<-quantile(score,c(.8,.6,.4,.2)) #使用分位數函數求學生的綜合得分的百位分數n> yn 80% 60% 40% 20% n 0.74 0.44 -0.36 -0.89n

#花名冊中添加grade級別n> roster$grade[score>=y[1]]<-"A"n> roster$grade[score<y[1]&score>=y[2]]<-"B"n> roster$grade[score<y[2]&score>=y[3]]<-"C"n> roster$grade[score<y[3]&score>=y[4]]<-"D"n> roster$grade[score<y[4]]<-"Fn> rostern Student Math Science English score graden1 John Davis 502 95 25 0.56 Bn2 Angela Williams 600 99 22 0.92 An3 Bullwinkle Moose 412 80 18 -0.86 Dn4 David Jones 358 82 15 -1.16 Fn5 Janice Markhamer 495 75 20 -0.63 Dn6 Cheryl Cushing 512 85 28 0.35 Cn7 Reuven Ytzrhak 410 80 15 -1.05 Fn8 Greg Knox 625 95 30 1.34 An9 Joel England 573 89 27 0.70 Bn10 Mary Rayburn 522 86 18 -0.18 Cn

> roster#加入級別變數後的花名冊,並根據y的值進行排序n Student Math Science English score graden1 John Davis 502 95 25 0.56 Bn2 Angela Williams 600 99 22 0.92 An3 Bullwinkle Moose 412 80 18 -0.86 Dn4 David Jones 358 82 15 -1.16 Fn5 Janice Markhamer 495 75 20 -0.63 Dn6 Cheryl Cushing 512 85 28 0.35 Cn7 Reuven Ytzrhak 410 80 15 -1.05 Fn8 Greg Knox 625 95 30 1.34 An9 Joel England 573 89 27 0.70 Bn10 Mary Rayburn 522 86 18 -0.18 Cn

> name<-strsplit((roster$Student)," ")#進行字元串分割n> namen[[1]]n[1] "John" "Davis"nn[[2]]n[1] "Angela" "Williams"nn[[3]]n[1] "Bullwinkle" "Moose" nn[[4]]n[1] "David" "Jones"nn[[5]]n[1] "Janice" "Markhamer"nn[[6]]n[1] "Cheryl" "Cushing"nn[[7]]n[1] "Reuven" "Ytzrhak"nn[[8]]n[1] "Greg" "Knox"nn[[9]]n[1] "Joel" "England"nn[[10]]n[1] "Mary" "Rayburn"n

> Lastname<-sapply(name,"[",2)#提取列表中每個成分的第二個元素,放入一個儲存名字n的向量Lastname n> Firstname<-sapply(name,"[",1)#提取列表中每個成分的第一個元素,放入一個儲存名字n的向量Firstname n> roster<-cbind(Firstname,Lastname,roster[,-1])#把Firstname,Lastname列添加到花名冊n> rostern Firstname Lastname Math Science English score graden1 John Davis 502 95 25 0.56 Bn2 Angela Williams 600 99 22 0.92 An3 Bullwinkle Moose 412 80 18 -0.86 Dn4 David Jones 358 82 15 -1.16 Fn5 Janice Markhamer 495 75 20 -0.63 Dn6 Cheryl Cushing 512 85 28 0.35 Cn7 Reuven Ytzrhak 410 80 15 -1.05 Fn8 Greg Knox 625 95 30 1.34 An9 Joel England 573 89 27 0.70 Bn10 Mary Rayburn 522 86 18 -0.18 Cn

> roster<-roster[order(Lastname,Firstname),]#對數據集按照姓和名進行排序n> rostern Firstname Lastname Math Science English score graden5 Janice Markhamer 495 75 20 -0.63 Dn6 Cheryl Cushing 512 85 28 0.35 Cn2 Angela Williams 600 99 22 0.92 An4 David Jones 358 82 15 -1.16 Fn10 Mary Rayburn 522 86 18 -0.18 Cn8 Greg Knox 625 95 30 1.34 An9 Joel England 573 89 27 0.70 Bn7 Reuven Ytzrhak 410 80 15 -1.05 Fn1 John Davis 502 95 25 0.56 Bn3 Bullwinkle Moose 412 80 18 -0.86 Dn

5.4 控制流

請牢記以下概念:

語句( statement )是一條單獨的R語句或一組複合語句(包含在花括弧 { } 中的一組R語句,使用分號分隔);

條件( cond )是一條最終被解析為真( TRUE )或假( FALSE )的表達式;

表達式( expr )是一條數值或字元串的求值語句;

序列( seq )是一個數值或字元串序列。

01.重複和循環

循環結構重複地執行一個或一系列語句,直到某個條件不為真為止。循環結構包括 for 和while 結構。

  • for 結構

    for 循環重複地執行一個語句,直到某個變數的值不再包含在序列 seq 中為止。語法為:

    for (var in seq) statement

    比如:

    > for(i in 1:10)n> print("Hello")n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n

  • while 結構

    while 循環重複地執行一個語句,直到條件不為真為止。語法為:

    while (cond) statement

    比如:

    > i<-10n> while(i>0){print("Hello");i<-i-1}n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n[1] "Hello"n

    值得注意的是確保while括弧內的語句在某個時刻不為真,否則循環將永不停止。建議聯用R中的內建數值/字元處理函數和 apply 族函數。

2 條件執行

在條件執行結構中,一條或一組語句僅在滿足一個指定條件時執行。條件執行結構包括if-else 、 ifelse 和 switch 。

  • if-else 結構

    控制結構 if-else 在某個給定條件為真時執行語句。也可以同時在條件為假時執行另外的語句。語法為:

    if (cond) statement

    if (cond) statement1 else statement2
  • ifelse 結構

    ifelse 結構是 if-else 結構比較緊湊的向量化版本,其語法為:

    ifelse(cond, statement1, statement2)

    ifelse(score > 0.5, print("Passed"), print("Failed"))

    outcome <- ifelse (score > 0.5, "Passed", "Failed")

    在程序的行為是二元時,或者希望結構的輸入和輸出均為向量時,請使用 ifelse。

  • switch 結構

    switch 根據一個表達式的值選擇語句執行。語法為:

    switch(expr, ...)

    舉例如下:

> feelings<-c("sad","afraid")n> for(i in feelings)n+ print(switch(i,happy="I am glad you are happy",n+ afraid="There is nothing to fear",n+ sad="Cheer up",angary="Calm down now"))n[1] "Cheer up"n[1] "There is nothing to fear"n

5.5 用戶自編函數

R的最大優點之一就是用戶可以自行添加函數。R中的許多函數都是由已有函數構成的。一個函數的結構看起來大致如此:

myfunction <- function(arg1, arg2, ... ){

statements

return(object)

}

函數中的對象只在函數內部使用。返回對象的數據類型是任意的,從標量到列表皆可。

比如:一個使用了 switch 結構的用戶自編函數,此函數可讓用戶選擇輸出當天日期的格式。

> mydate<-function(type="long"){n+ switch(type,n+ long=format(Sys.time(),"%A %B %d %Y"),n+ short=format(Sys.time(),"%m-%d-%y"),n+ cat(type,"is not a recognized typen")n+ )n+ }n> mydate("long")n[1] "星期二 三月 14 2017"n> mydate("short")n[1] "03-14-17"n> mydate("medium")nmedium is not a recognized typen>n

Warning:可以使用warning()來生成一條錯誤信息,用message()來生成一條診斷信息,或者用stop()來停止當前表達式的執行並提示錯誤。上面的例子中,cat()函數僅會在輸入的日期格式類型不匹配時,用一個表達式來捕獲用戶給出的錯誤參數值。這是針對自編函數的一個錯誤捕獲和調試的方法。

5.6 整合與重構

R中提供了許多用來整合(aggregate)和重塑(reshape)數據的強大方法。在整合數據時,往往將多組觀測替換為根據這些觀測計算的描述性統計量。在重塑數據時,則會通過修改數據的結構(行和列)來決定數據的組織方式。

在接下來我們將使用已包含在R基本安裝中的數據框mtcars 。這個數據集描述了34種車型的設計和性能特點(汽缸數、排量、馬力、每加侖汽油行駛的英里數等等)。

01 轉置

轉置即反轉行和列。使用函數 t() 即可。

數據集的轉置如下示例:

> cars<-mtcars[1:5,1:4]n> carsn mpg cyl disp hpnMazda RX4 21.0 6 160 110nMazda RX4 Wag 21.0 6 160 110nDatsun 710 22.8 4 108 93nHornet 4 Drive 21.4 6 258 110nHornet Sportabout 18.7 8 360 175nn> t(cars)#進行轉置n Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive Hornet Sportaboutnmpg 21 21 22.8 21.4 18.7ncyl 6 6 4.0 6.0 8.0ndisp 160 160 108.0 258.0 360.0nhp 110 110 93.0 110.0 175.0n>n

02 整合數據

在R中使用一個或多個by變數和一個預先定義好的函數來摺疊(collapse)數據是比較容易的。

調用格式為:

aggregate(x, by, FUN)

其中 x 是待摺疊的數據對象, by 是一個變數名組成的列表,這些變數將被去掉以形成新的觀測,而 FUN 則是用來計算描述性統計量的標量函數,它將被用來計算新觀測中的值。

示例如下,我們將根據汽缸數和擋位數整合 mtcars 數據,並返回各個數值型變數的均值。

> options(digits = 3)n> attach(mtcars)n> aggdata<-aggregate(mtcars,by=list(cyl,gear),FUN = mean,n+ na.rm=TRUE)n> aggdatan Group.1 Group.2 mpg cyl disp hp drat wt qsec vs am gear carbn1 4 3 21.5 4 120 97 3.70 2.46 20.0 1.0 0.00 3 1.00n2 6 3 19.8 6 242 108 2.92 3.34 19.8 1.0 0.00 3 1.00n3 8 3 15.1 8 358 194 3.12 4.10 17.1 0.0 0.00 3 3.08n4 4 4 26.9 4 103 76 4.11 2.38 19.6 1.0 0.75 4 1.50n5 6 4 19.8 6 164 116 3.91 3.09 17.7 0.5 0.50 4 4.00n6 4 5 28.2 4 108 102 4.10 1.83 16.8 0.5 1.00 5 2.00n7 6 5 19.7 6 145 175 3.62 2.77 15.5 0.0 1.00 5 6.00n8 8 5 15.4 8 326 300 3.88 3.37 14.6 0.0 1.00 5 6.00nnn>n

03 reshape2包

使用install.packages("reshape2")安裝reshape2包。

  • 融合

    數據集的融合是將它重構為這樣一種格式:每個測量變數獨佔一行,行中帶有要唯一確定這個測量所需的標識符變數。

    舉例如下:

    > ID<-c(1,1,2,2)n> Time<-c(1,2,1,2)n> X1<-c(5,3,6,2)n> X2<-c(6,5,1,4)n> mydata<-data.frame(ID,Time,X1,X2)n> mydatan ID Time X1 X2n1 1 1 5 6n2 1 2 3 5n3 2 1 6 1n4 2 2 2 4n> library(reshape2)n> md<-melt(mydata,id=c("ID","Time")) #融合,每個X1、X2需要各佔一行,共計八行n> mdn ID Time variable valuen1 1 1 X1 5n2 1 2 X1 3n3 2 1 X1 6n4 2 2 X1 2n5 1 1 X2 6n6 1 2 X2 5n7 2 1 X2 1n8 2 2 X2 4n>n

  • 重鑄

newdata <- dcast(md, formula, fun.aggregate) 其中的 md 為已融合的數據, formula 描述了想要的最後結果,而 fun.aggregate 是(可選的)數據整合函數。

比如:

> my<-dcast(md,ID~variable,mean)# 每個觀測所有Time中在X1和X2上的均值n> myn ID X1 X2n1 1 4 5.5n2 2 4 2.5nn>n

總結一下

本章主要學習了數學和統計函數(數學函數、統計函數、概率函數)、字元處理函數以及其它的使用函數,最後將函數應用於矩陣和數據框,解決了本章前面提出問題。同時學了控制流——循環和條件執行,同時簡單介紹了如何進行自編函數,最後學習了摺疊、整合以及重鑄數據的方法。

以上這些基本具備了進行複雜數據分析的基礎,通過一些案列和代碼的實踐,較好的熟悉了基本工具,但是距離掌握這些工具需要更多的實踐練習和深入學習,尤其是相關函數的用法,極為重要。


推薦閱讀:

初探密碼破譯:Metropolis-Hastings演算法破解密文
R語言可視化——數據地圖離散百分比填充(環渤海)
學習與實踐筆記—第三講簡單數據處理
R語言分析告訴你應避開哪個國家以躲避空難
[數據分析與可視化 25] R會議筆記:原理篇

TAG:R编程语言 | 数据分析 | R |