R語言編程藝術(2)R中的資料結構

來源:互聯網
上載者:User

標籤:bug   cas   not   mina   中間   查詢   相同   資料類型   性問題   

本文對應《R語言編程藝術》第2章:向量;第3章:矩陣和數組;第4章:列表;第5章:資料框;第6章:因子和表

 

=========================================================================

R語言最基本的資料類型就是向量(vector),單個數值和矩陣都是向量的一種特例。

 

聲明:R中不需要聲明變數,但是注意函數式語言的特性,如果讀寫向量中的元素時,R事先不知道對象是向量的話,則函數沒有執行的對象。如下代碼是無法工作的:

y[1] <- 5y[2] <- 12

  


迴圈補齊: 

在對兩個向量使用運算子時,如果要求這兩個向量具有相同的長度,R會自動迴圈補齊(recycle),即重複較短的向量,直到它與另一個向量長度相匹配。

需要注意的是,矩陣實際上是一個長向量,(1, 2, 3, 4, 5, 6)轉成矩陣形式則是:

[   1   4

    2   5

    3   6    ]

 

常用的向量運算:

向量運算和邏輯運算:注意到R是函數式語言,每一個運算子都是函數,因此不管+-*/都是元素與元素逐一運算,特別注意*與線性代數中的矩陣運算不同,也是元素和元素逐一相乘。

向量索引:索引格式為:向量1[向量2],返回的結果為向量1中索引為向量2的那些元素,注意元素允許重複。負數下標代表想把相應元素剔除。

用:運算子建立向量:產生指定範圍內數值構成的向量。注意:運算子的優先順序高於一般運算子,具體的優先順序情況可以在命令視窗中輸入?Syntax查看。

用seq()建立向量:產生等差序列

x <- c()#比較下面兩句代碼for(i in 1:length(x))for(i in seq(x))#第一句返回的i = c(0, 1),顯然與希望中的不同#第二句返回的i為NULL

  

 使用rep()重複向量常數:通過調用rep(x, times),即可建立times*length(x)個元素的向量,由x重複times次構成;或者通過調用rep(x, each),可建立each*length(x)個元素的向量,由x交替重複each次構成。

> rep(c(5, 12, 13), 3)> [1]  5  12  13  5  12  13  5  12  13> rep(c(5, 12, 13), each = 2)> [1]  5  5  12  12  13  13

  

使用all()和any()

這兩個函數分別報告其參數是否至少有一個或全部為TRUE

 

向量化運算子:

向量輸入,向量輸出:很多函數與運算子都是向量化的,注意靈活應用以提高代碼效率。這種沒有標量的語言(標量實際上是長度為1的向量)因此帶來一些代碼安全性問題:自訂的函數在需要輸入為標量的時候,輸入的是向量也會有傳回值,但是卻沒有任何提示。這就需要在設計函數時考慮這個問題,進行輸入是否非法的判斷。

f <- function(x, c){                    if (length(c) != 1) stop(“vector c not allowed”)                    return((x + c) ^ 2)}

  


 向量輸入,矩陣輸出:當使用的函數在輸入一個值的傳回值本身就是向量時,輸入一個向量時返回的就應該是矩陣了。而直接使用函數進行運算,得到的只是一個一維向量,需要對結果使用matrix()函數進行重新整合。但是有另一種方法可以用,就是sapply()函數(simplify apply的縮寫),調用格式為sapply(x, f)輸入向量x對其中的每一個元素應用f()函數,並將結果轉化為矩陣。

NA與NULL值:

NA存在但未知的值;NULL表示不存在的值,是R的一種特殊對象,沒有模式。

 

篩選(filtering):

產生篩選索引:條件,最終靠布爾值

使用subset()函數篩選:與靠條件產生篩選索引的區別在於處理NA值的方式,普通處理會保留NA值,subset()函數會移除NA值

選擇函數which():與subset()函數類似,但是傳回值是符合條件值的位置(即索引編號)

 

向量化的ifelse()函數:

調用形式:ifelse(b, u, v),其中b為布爾值向量,u, v為向量。函數傳回值為向量,如果b[i]為真,則傳回值的第i個元素為u[i]如果b[i]為假,則傳回值的第i個元素為v[i]。

可以利用ifelse()函數對向量進行重編碼,對於2種以上的編碼方式,可以考慮嵌套:

#ifelse()函數的嵌套,將g中M, F, I分別重編碼為1, 2, 3g <- c(“M”, “F”, “F”, “I”, “M”, “M”, “F”)ifelse(g == “M”, 1, ifelse(g == “F”, 2, 3))

  


測試向量相等: 

考慮如下代碼:

x <- 1:2y <- c(1, 2) x == y#傳回值:TRUE  TRUE  因為“==”是函數,返迴向量化的結果all(x == y)#傳回值:TRUE 因為all判斷向量是否都為TRUEidentical(x, y)#傳回值:FALSE 因為identical()函數判斷兩個對象是否完全一樣typeof(x) #integertypeof(y) #double

  


向量元素的名稱: 

name()函數可以指定或查詢向量元素的名稱:

x <- c(1, 2, 4)#命名names(x) <- c(“a”, “b”, “ab”)#查詢name(x)#傳回值 “a”  “b”  “ab”

  


 名稱可以用於索引向量中的元素

關於c()函數的一些需要注意事項:

如果傳遞到c()函數中的參數有不同類型,則它們將被降級為同一類型,該類型最大限度地保留它們的共同特性;

c()函數對向量有扁平化的效果:

c(5, 2, c(1.5, 6))# [1]  5.0  2.0  1.5  6.0

  

=========================================================================

向量的特例:矩陣與數組

矩陣是一種特殊的向量,與向量相比,包含了兩個附加的屬性:行數和列數;而數組是更一般的矩陣,高維數組包含了不止行數和列數兩個屬性。

 

建立矩陣:

考慮以下代碼:

> y <- matrix(c(1, 2, 3, 4), nrow = 2, ncol = 2)> y      [, 1] [, 2][1, ]    1     3[2, ]    2     4> m <- matrix(c(1, 2, 3, 4), nrow = 2, byrow = TRUE)> m      [, 1] [, 2][1, ]     1     2[2, ]     3     4

  


 需要注意的是,在產生矩陣m的時候,資料按行填充(即資料輸入順序),而R在儲存時仍然是按列儲存。

一般矩陣運算:

線性代數運算:注意矩陣乘法使用”%*%”

矩陣索引:類似於向量索引用法,可以對子矩陣進行提取、賦值以及刪除。

矩陣元素篩選:與向量的篩選類似,通過條件計算布爾值進行篩選,需要注意避免意外降維。

 

對矩陣的行和列調用函數:

使用apply()函數:調用一般格式:

apply(m, dimcode, f, fargs)

  


apply()函數調用的函數返回的是一個包含k個元素的向量,那麼預設返回的結果就有k行,必要時可以使用轉置函數t()對結果進行處理。m是矩陣;dimcode是維度編號:1對行應用函數,2對列應用函數;f是應用的函數;fargs是f的選擇性參數集。

注意apply()函數不一定能使程式運行加快。其優點在於使程式緊湊,便於閱讀和修改,並且避免產生使用迴圈語句時可能帶來的bug。

 

增加或刪除矩陣的行或列:

若要刪除,將對應行或列賦值為NULL即可,或者使用”-”加索引(參考向量的用法);若要增加行或列,使用rbind()函數或者cbind()函數。

注意不要在迴圈中使用rbind()函數或者cbind()函數,因為重複建立新矩陣會減低程式速度,所以這種做法不可取。較好的解決辦法是在迴圈開始前建立一個大矩陣,迴圈過程中逐行逐列對矩陣進行賦值,這樣就避免了迴圈過程中每次進行耗時的矩陣記憶體配置。

 

向量與矩陣的差異:

矩陣也是向量,因此可以用length()函數求長度。另一方面,從物件導向編程的角度來說,矩陣類(matrix class)是實際存在的。可以用dim()函數訪問矩陣類的屬性(行數和列數),可以用nrow()和ncol()函數分別訪問矩陣的行數和列數(實際上都是對dim()函數的簡單封裝)。這兩個函數一般用於寫以矩陣為參數的通用庫函數,可以不需額外參數輸入矩陣的行數和列數。

 

避免意外降維:

兩種方式:若使用索引方式提取子矩陣,設定參數drop = FALSE即可(注意”[”實際上也是函數,drop是這個函數的一個參數);若選擇先提取子矩陣再處理,可以使用as.matrix()函數將被降維成向量的對象轉成矩陣對象。

z <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8), nrow = 4)#索引方式設定drop參數防止降維r <- z[2, , drop = FALSE]#使用as.matrix()函數u <- z[2, ]v <- as.matrix(u)

  


矩陣的行和列的命名問題: 

rownames()函數與colnames()函數

 

高維數組:

以一個簡單的三維數組為例:

#先產生兩個矩陣,作為數組的第一層和第二層firsttest <- matrix(c(46, 21, 50, 30, 25, 50), nrow = 3)secondtest <- matrix(c(46, 41, 50, 43, 35, 50), nrow = 3)#產生一個三維數組,dim參數的三個數字分別代表行數、列數和層數tests <- array(data = c(firsttest, secondtest), dim = c(3, 2, 2))

  

=========================================================================

資料框與物件導向編程的基礎:列表

R中的列表與Python中的字典、Perl中的雜湊表、C中的結構體(struct)類型類似。

 

建立列表:

#建立一個簡單的列表j <- list(name = “Joe”, salary = 55000, union = TRUE)#使用標籤的時候,在不引起歧義的情況下,可以簡寫j$sal#列表實際也是向量,可以使用vector()函數建立z <- vector(mode = “list”)z[[“abc”]] <- 3

  


列表的常規操作: 

清單索引:注意以下代碼:

#提取列表組件三種方法j1 <- j$salaryj2 <- j[[“salary”]]j3 <- j[[2]]#以上方法效果相同,都是提取列表j中的第二個組件,傳回值的類型是組件本身的類型#提取子列表j4 <- j[salary]j5 <- j[2]#以上兩種方法效果相同,提取了列表j的一個子列表,傳回值的類型是列表

  


增加或刪除列表元素: 

增加列表元素:直接使用索引即可增加列表組件,具體有5種方式見上面代碼,既可以添加單個組件,也可以添加子列表分別作為列表的多個組件。

刪除列表元素:直接將待刪除的組件賦值為NULL即可。注意刪除中間組件的時候,後面的組件的索引全部減1

 

擷取列表長度:

length()函數可以得到列表組件的個數。因為列表是向量。

 

訪問列表元素和值:

函數names()可以擷取列表各元素的標籤;

函數unlist()可以擷取列表的值,傳回值是一個向量,類型最大程度保留所有元素的共同特性。一般來說,各種類型的優先順序排序是NULL<raw<邏輯類型<整型<實數類型<複數類型<列表<運算式(把配對列表(pairlist)當作普通列表)

 

在列表上使用apply系列函數:

lapply()函數和sapply()函數的使用:

lapply()(代表list apply)函數與矩陣的apply()函數用法類似,對列表(或強制轉換成列表的向量)的每個組件執行給定的函數,並返回另一個列表。

在某些情況下,lapply()函數返回的列表可以轉化為矩陣或向量的形式。這時候可以選擇使用sapply()(代表simplified [l]apply)

 

遞迴型列表:

列表是遞迴的(recursive),即列表的組件也可以是列表。

拼接函數c()有一個選擇性參數recursive,決定在拼接列表的時候,是否吧原列表“壓平”,就是把所有組件的元素都提取出來,組合成一個向量。

> c(list(a = 1, b = 2, c = list(d = 5, e = 9)))$a[1]  1 $b[1]  2$c$c$d[1]  5 $c$e[1]  9 > c(list(a = 1, b = 2, c = list(d = 5, e = 9)), recursive = TRUE)a   b  c.d   c.e1   2    5    9

  

=========================================================================

資料框

從直觀上看,資料框類似矩陣,有行和列兩個維度,然而資料框與矩陣不同的是,資料框的每一列可以是不同模式。就技術層面而言,資料框是每個組件長度都相等的列表。

 

建立資料框:

注意參數stringsAsFactors = FALSE的使用。

訪問資料框:三種方式:

#類似列表的方式訪問組件d[[1]]d$kids#類似矩陣的方式按列訪問d[, 1]

  


str()函數可以查看資料框的內部結構。注意以上三種方式的返回一致,都是對資料框的某列進行訪問。

一般來說,採用名稱索引的方式更加安全,但是在寫R包時常常採用矩陣式記號。

 

其他矩陣式操作:

提取子資料框:資料框可以看做是行和列組成的,因此可以按行或列提取子資料框。同樣的,如果需要避免意外降維,需要設定drop = FALSE

a <- examquiz[2:5, 2]b <- examquiz[2:5, 2, drop = FALSE]class(a)# "numeric"class(b)# "data.frame"

  


使用rbind()和cbind()等函數:添加新行的時候,添加的行可以是資料框也可以是列表,要求行數相同。添加新列,可以利用資料框的列表屬性添加,注意如果新增列長度與資料框不同會自動迴圈補齊。缺失值的處理:有時需要顯式地設定na.rm = TRUE明確處理缺失值,否則會使函數返回結果也是NA。靈活使用subset()函數進行條件式篩選,預設na.rm = TRUE。另外如果只是刪除缺失值,使用complete.cases()函數可以作為條件式篩選完整觀測。

使用apply()函數:如果資料框的每一列的資料類型相同,可以對資料框使用apply()函數(此時可以將資料框看作是矩陣)。

 

合并資料框:

merge()函數,可以將兩張表根據某個共同變數的值組合到一起。

需要注意的是,選擇匹配變數時要小心,當一個變數內有重複值的時候,很有可能產生錯誤的結果(相當於原本的一對一變成了一對多)。

 

應用於資料框的函數:

在資料框上應用lapply()和sapply()函數:資料框是列表的特例,資料框的列構成了列表的組件。在資料框上應用lapply()函數,指定的函數是f()。f()函數會作用於資料框的每一列,然後將傳回值置於一個列表中。

 

 

=========================================================================

因子和表

因子(factor)的設計思想來源於統計學中的名義變數(nominal variables),或稱之為分類變數(categorical variables),這種變數的值本質不是數字,而是對應為分類。

本章的表是頻數表和列聯表的總稱,將探討一些常用運算。

 

因子與水平:

R中,因子可以簡單地看作一個附加了更多資訊的向量。這額外的資訊包括向量中不同值的記錄,稱為“水平”(level)。

因子的長度定義為資料的長度,而不是水平的個數。

如果預測到未來有其他水平,需要提前插入,否則後面通過插入新的資料來插入新的水平是行不通的。

 

因子的常用函數:

tapply()函數:調用方式:tapply(x, f, g)。其中x為因子向量;f為因子或因子列表;g為函數。tapply()函數執行的操作是:(暫時)將x分組,每組對應一個因子水平(或在多重因子的情況下對應一組因子水平的組合),得到x的子向量,然後這些子向量應用函數g()。

> #tapply()應用樣本> ages <- c(25, 26, 55, 37, 21, 42)> affils <- c(“R”, “D”, “D”, “R”, “U”, “D”)> tapply(ages, affils, mean) D    R    U41   31   21

  

以上是一種簡單的形式,只靠一組因子進行分類。如果需要兩種以上的因子組合作為控制條件,只需要把f替換成由因子組合成的列表:

#假設資料框d中含有三列,income, gender, over25,以後兩者為控制條件對income應用mean函數tapply(d$income, list(d$gender, d$over25), mean)

  

split()函數:將向量分割為組,相當於tapply()函數的第一步,而省略了後續的應用函數操作。基本調用形式:split(x, f),其中x可以是向量或資料框(tapply()函數中不可以是資料框),f為因子或因子列表。傳回值是一個列表。

 

by()函數:與tapply()函數在某種程度上類似,都是先分組,再對每組調用函數。tapply()函數要求輸入資料必須為向量,而by()函數可以是資料框或矩陣。

#以Gender為控制條件,分別對第2列和第3列進行迴歸分析aba <- read.csv(“abalone.data”, header = TRUE)by(aba, aba$Gender, function(m) lm(m[, 2] ~ m[, 3]))

  


表的操作:通常使用table()函數建立表(頻數表與列聯表) 

計算邊界值:addmargins()函數

獲得維度名稱和水平值:dimnames()函數

表也可以採用資料框的形式表達,使用as.data.frame()函數即可

 

其他與因子和表有關的函數:

aggregate()函數:對分組中的每一個變數調用tapply()函數

cut()函數:是產生因子的一種常用方法,尤其是常用於表的操作。調用方式:cut(x, b, labels = FALSE)輸入向量x,由向量b定義一組區間,返回x每個元素落入區間組成的向量。簡單來說,就是重編碼,這裡區間b一般是左開右閉區間。

 

R語言編程藝術(2)R中的資料結構

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.