1. 程式人生 > >R語言實現迴圈loop的函式解讀(帶練習)

R語言實現迴圈loop的函式解讀(帶練習)

迴圈在處理資料的時候非常重要,但不得不說寫function的時候還是得繞不少彎路,好在現在R語言有非常多函式可以直接使用,帶來不少便利。在學習寫looping function 的時候,可以先熟練掌握了以下向量化操作apply、tapply、lapply、sapply、mapply的函式,然後再自己嘗試寫自己的:

lapply lapply(X,FUN,...) ,注意:若X不是列表,但會被強制as.list
sapply sapply(X, FUN,..., simplify = TRUE, USE.NAMES = TRUE) ;與Lapply相似,或者說是lapply的衍生
apply apply(X, MARGIN, FUN, ...),把FUN用到array的特定margins
tapply tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE),專門用來處理分組資料的
mapply mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE,USE.NAMES = TRUE)
,mapply是sapply的變形
#下面使用R自帶的資料來實踐:
> library(datasets)
> data(iris)
#在使用這個iris之前,建議大家可以先看看這個資料的具體情況
> ?iris

lapply:

lapply(list, function)
function (X, FUN, ...) 
{
    FUN <- match.fun(FUN)
    if (!is.vector(X) || is.object(X)) 
        X <- as.list(X)
    .Internal(lapply(X, FUN))
}
<bytecode: 0x000000000263dea8>
<environment: namespace:base>

        lapply的返回值是和一個和X有相同的長度的list物件,這個list物件中的每個元素是將函式FUN應用到X的每一個元素。其中X為List物件(該list的每個元素都是一個向量),其他型別的物件會被R通過函式as.list()自動轉換為list型別。

        lappy()的處理物件是向量、列表或其它物件,它將向量中的每個元素作為引數,輸入到處理函式中,最後生成結果的格式為列表。在R中資料框是一種特殊的列表,所以資料框的列也將作為函式的處理物件。

試一下lapply來求'Sepal.Length'的平均值(mean)

 lapply(iris, mean)

返回的是

$Sepal.Length
[1] 5.843333

$Sepal.Width
[1] 3.057333

$Petal.Length
[1] 3.758

$Petal.Width
[1] 1.199333

$Species
[1] NA

sapply

> sapply
function (X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE) 
{
    FUN <- match.fun(FUN)
    answer <- lapply(X = X, FUN = FUN, ...)
    if (USE.NAMES && is.character(X) && is.null(names(answer))) 
        names(answer) <- X
    if (!identical(simplify, FALSE) && length(answer)) 
        simplify2array(answer, higher = (simplify == "array"))
    else answer
}
<bytecode: 0x0000000015568688>
<environment: namespace:base>

       sapply和lapply返回值是一樣的。但引數simplify=T,其返回值就不是list,而是matrix;相反,simplify=F,其返回值還是list。

       仍用求iris每個量的mean來看一下區別:

> sapply(iris,mean)
Sepal.Length  Sepal.Width 
    5.843333     3.057333 
Petal.Length  Petal.Width 
    3.758000     1.199333 
     Species 
          NA 
> sapply(iris,mean,simplify = F)
$Sepal.Length
[1] 5.843333

$Sepal.Width
[1] 3.057333

$Petal.Length
[1] 3.758

$Petal.Width
[1] 1.199333

$Species
[1] NA

apply

> apply
function (X, MARGIN, FUN, ...) 

其中X是array;MARGIN是向量(表示要將函式FUN應用到X的行還是列),若為1表示取行,為2表示取列,為c(1,2)表示行、列都計算。apply()函式的處理物件是矩陣或陣列,它逐行或逐列的處理資料,其輸出的結果將是一個向量或是矩陣。下面的例子即對一個隨機矩陣求每一行的均值。要注意的是apply與其它函式不同,它並不能明顯改善計算效率,因為它本身內建為迴圈運算。

為了方便理解 ,舉個函式的例子:

rowSums = apply(x, 1, sum)
rowMeans = apply(x, 1, mean)
colSums = apply(x, 2, sum)
colMeans = apply(x, 2, mean)

或者大家可以直接使用iris3來嘗試一下不同的結果:

tapply

> tapply
function (X, INDEX, FUN = NULL, ..., default = NA, simplify = TRUE) 

用於分組統計(index)

其中X通常是一向量;INDEX是一個list物件,且該list中的每一個元素都是與X有同樣長度的因子;FUN是需要計算的函式;simplify是邏輯變數,若取值為TRUE(預設值),且函式FUN的計算結果總是為一個標量值,那麼函式tapply返回一個數組;若取值為FALSE,則函式tapply的返回值為一個list物件。需要注意的是,當第二個引數INDEX不是因子時,函式 tapply() 同樣有效,因為必要時 R 會用 as.factor()把引數強制轉換成因子。

tapply()的功能則又有不同,它是專門用來處理分組資料的,其引數要比sapply多一個。我們以iris資料集為例,可觀察到Species列中存放了三種花的名稱,我們的目的是要計算三種花瓣萼片寬度的均值。其輸出結果是陣列格式。

> tapply(1:17, fac, sum)
 1  2  3  4  5
51 57 45 NA NA
> tapply(1:17, fac, sum, simplify = FALSE)
$`1`
[1] 51


$`2`
[1] 57


$`3`
[1] 45


$`4`
NULL


$`5`
NULL
> tapply(1:17, fac, range)
$`1`
[1]  1 16


$`2`
[1]  2 17


$`3`
[1]  3 15


$`4`
NULL


$`5`
NULL