顯示具有 lapply 標籤的文章。 顯示所有文章
顯示具有 lapply 標籤的文章。 顯示所有文章

2023年1月5日 星期四

2022年2月4日 星期五

R資料框操作20技巧 (20 Tips for data.frame)

主題:

R語言中資料框的處理是重要技術之一,本篇文章說明資料框的常用處理技巧。



關鍵字:

  • 列(Row),行(Column)篩選
  • 類別 class
  • 維度 dim
  • 列名稱 row.names
  • 行可稱 colnames, names
  • 結構 str
  • 摘要 summary
  • 屬性 attributes
  • apply
  • lapply
資料框操作20技巧:

> # 技巧1 篩選行,結果為 vector

> iris$Sepal.Length

  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9

 [11] 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1 

...

> # 技巧2 篩選行,結果為 vector(二個單引號)

> iris[, 'Sepal.Length']

  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9

 [11] 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1

...

> # 技巧3 篩選行,結果為 vector(二個雙單引號)

> iris[, "Sepal.Length"]

  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9

 [11] 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1

...

> # 技巧4 篩選行,結果為 vector

> iris[, 1]

  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9

 [11] 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1

...

> # 技巧5 篩選行,結果為 vector

> iris[['Sepal.Length']]

  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9

 [11] 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1

...

> # 技巧6 篩選行,結果為 vector

> iris[["Sepal.Length"]]

  [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9

 [11] 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1 5.7 5.1

...

> # 技巧7 篩選行,結果為 data.frame

> iris['Sepal.Length']

    Sepal.Length

1            5.1

2            4.9

3            4.7

...

> # 技巧8 篩選行,結果為 data.frame

> iris["Sepal.Length"]

    Sepal.Length

1            5.1

2            4.9

3            4.7

...

> # 技巧9 篩選列,結果為 data.frame

> iris[1, ]

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species

1          5.1         3.5          1.4         0.2  setosa

> # 技巧10 篩選列,使用數值轉換,再加數值1,省略as.numeric會有錯誤

> as.numeric(iris[1,-5]) + 1

[1] 6.1 4.5 2.4 1.2

> # 技巧11 類別

> class(iris)

[1] "data.frame"

> # 技巧12 維度,結果為150列,5行

> dim(iris)

[1] 150   5

> # 技巧13 列名稱

> row.names(iris)

  [1] "1"   "2"   "3"   "4"   "5"   "6"   "7"   "8"   "9"   "10" 

...

> # 技巧14 行名稱

> colnames(iris)

[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"     

> # 技巧15 行名稱

> names(iris)

[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"     

> # 技巧16 資料結構

> str(iris)

'data.frame': 150 obs. of  5 variables:

 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...

 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...

 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...

 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...

 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 ...

> # 技巧17 資料摘要

> summary(iris)

  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  

 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100   setosa    :50  

 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300   versicolor:50  

 Median :5.800   Median :3.000   Median :4.350   Median :1.300   virginica :50  

 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199                  

 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800                  

 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500                  

> # 技巧18 資料屬性

> attributes(iris)

$names

[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"     

$class

[1] "data.frame"

$row.names

  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20

 [21]  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40

> # 技巧19 各列或各行群組計算

> apply(iris[-5], 1, mean)

  [1] 2.550 2.375 2.350 2.350 2.550 2.850 2.425 2.525 2.225

 [10] 2.400 2.700 2.500 2.325 2.125 2.800 3.000 2.750 2.575

...

> # 技巧20 各行群組計算,回傳結果為串列(list)- lapply 以行運算為主

> lapply(iris[-5], mean)

$Sepal.Length

[1] 5.843333

$Sepal.Width

[1] 3.057333

$Petal.Length

[1] 3.758

$Petal.Width

[1] 1.199333

# end

2017年9月22日 星期五

R等差數列(前後二個元素相減)與條件式計算


主題: 如何計算數列的前後二個元素相減產生的新等差數列與不同條件式數值計算

# diff
# c
# lapply
# <<

分析:
  • 感謝R友 Bic Ton提供此問題
  • 考慮 x <- c(2,5,6,1,3,8,4,5,6), 計算數列中後面減前面之結果, 例: 5-2=3, 6-5=1,...., 此時可以使用 diff(x).  diff 函數預設會計算數列中第2個元素減第1個元素的結果. 參閱線上說明 ?diff 
  • 如果希望計算前面減後面之結果, 例: 2-5=33, 5-6=-1,...., 此時可以使用 -diff(x)
  • 本例考慮3種不同解法:
    (1). 使用 for 迴圈判斷等差數列每個元素為正數或負數, 再加總結果.
    (2). 使用 for 迴圈判斷等差數列每個元素為正數或負數, 將結果用 c() 向量組合成新向量, 此方法可儲存正數與負數之結果. 注意: 本方法因為要儲存新等差數列的結果, 因此執行時間須較久.
    (3). 使用 lapply 函數以進行不同條件式數值計算, 本例使用全域變數指派符號 << 以利回傳計算結果.
  • 本例第2種方法 c() 分別儲存正/負數結果, 如果資料量較大時, 例: 100萬筆資料以上, 其執行時間須很久, 此時須考量其他儲存方式, 例: 使用 list串列 以加速程式之進行.
R程式碼:

x <- c(2,5,6,1,3,8,4,5,6)
x.diff <- -diff(x)
x.diff
# method 1 using for loop
gain1 <- 0
loss1 <- 0
for (i in 1:length(x.diff)) {
 if (x.diff[i] >= 0) gain1 <- gain1 + x.diff[i]
 else if (x.diff[i] < 0) loss1 <- loss1 + x.diff[i]
}
gain1
loss1

# method 2 using for loop with c()
gain2 <- c()
loss2 <- c()
for (i in 1:length(x.diff)) {
 if (x.diff[i] >= 0) gain2 <- c(gain2, x.diff[i])
 else if (x.diff[i] < 0) loss2 <- c(loss2, x.diff[i])
}
sum(gain2)
sum(loss2)

# method 3
gain3 <- 0
loss3 <- 0
lapply(x.diff, function(x) {
 ifelse(x > 0, gain3 <<- gain3 + x, loss3 <<- loss3 + x)
 #return(c(gain, loss))
 })
gain3
loss3
# end

2017年7月26日 星期三

函數原始碼 source code

R是開放原始碼軟體, 以下說明查詢函數的原始碼的方法(參考 1, 2).

簡介

R函數許多原始檔案包括 C, Fortran等程式碼, 常用呼叫其他已編譯完成程式的函數包括: .C .Call, .Fortran, .External, .Internal, .Primitive 等函數. (參考3  R Internals, 2017).

C程式在編譯成R時,可直接經由 primitives(原生) 或 .Internal interface (.內部介面)來呼叫使用, 此方式與 .External interface (.外部介面)類似, 但使用語法不相同.

「.Internal」 和 「.Primitive」 一般用於呼叫 C 的介面:
  • .Internal 是標準的用法,在呼叫C之前可以檢查R程式碼中的參數 .
  • .Primitive 執行效能較高,但不允許在函數中使用R程式.
R的原始碼 R-3.4.1.tar.gz (參考4) 解壓縮之後在 \R-3.4.1.tar\R-3.4.1\src\main 目錄中存放約121個 *.c 原始碼.



查詢函數原始碼

# 1
使用 pryr 套件的 ftype 函數可檢視該函數的種類:

  • regular/primitive/internal function
  • internal/S3/S4 generic
  • S3/S4/RC method

    library(pryr)
    ftype(apply) # "function"

    # 2
    直接輸入函數名稱, 即可顯示原始檔.

    apply



    # 3
    在 RStuido 軟體的程式編輯視窗, 選取 apply , 按 CTRL +  滑鼠左鍵, 可開啟原始檔.



    #4
    getAnywhere {utils} 可查詢函數隸屬於哪些套件與內容. 使用 show_c_source {pryr}可檢視該函數原始檔.




    #5
    使用 methods 函數與 getAnywhere 函數.


    R程式碼


    library(pryr)
    ftype(apply) # "function"
    apply
    
    lapply
    ftype(lapply) # "internal"
    getAnywhere(lapply)
    show_c_source(.Primitive(lapply(x)))
    
    princomp
    ftype(princomp) # "s3" "generic"
    methods(princomp)
    getAnywhere(princomp.default)
    # end

    參考資料

    [1] https://stackoverflow.com/questions/19226816/how-can-i-view-the-source-code-for-a-function

    [2] https://stackoverflow.com/questions/3485228/view-source-code-in-r

    [3] R Core Team, R Internals - Version 3.4.1 (2017-06-30), URL:  https://cran.r-project.org/doc/manuals/r-release/R-ints.pdf.

    [4] R 原始碼, https://cran.r-project.org/src/base/R-3/R-3.4.1.tar.gz

    2016年9月16日 星期五

    中文網頁表格擷取,亂碼處理

    Problem:

    本篇文章討論如何使用R下載網頁的表格資料, 再進行後續處理.

    Analysis:

    # part 1 設定R語系為C, 以配合中文編碼使用

    本例考量 RWEPA 個人簡介(About) 網頁 (http://web.ydu.edu.tw/~alan9956/02person.htm), 該網頁包括專題演講表格, 該表格包括編號,日期,主題,單位/地點,時數等5個欄位, 在R環境中, 可使用 XML 套件的 readHTMLTable 函數讀取網頁表格, 另因中文編碼考量, 先設定 locate, R程式如下:

    Sys.setlocale(category="LC_ALL", locale="C")
    Sys.getlocale()

    # part 2 載入套件,讀取網頁資料

    準備使用 XML 套件的 readHTMLTable 函數, 使用時記得加上  encoding="big5", 結果有5個表格, 其中第1個表格是使用的資料集, 因此將 tmp串列的第1個元素取出, 設定 train <- tmp[[1]], R程式如下:

    library(XML) # readHTMLTable 函數
    # IE: F12 --> line 7: <meta http-equiv=Content-Type content="text/html; charset=big5"> 
    # 觀察原始網頁採用 big5, 因此encoding參數設定為 big5
    urls <- "http://web.ydu.edu.tw/~alan9956/02person.htm"
    tmp <- readHTMLTable(urls, stringsAsFactors = FALSE, encoding="big5")
    length(tmp) # length=5
    train <- tmp[[1]] # 139*5

    # part 3 資料整理

    train[1,2] # 顯示亂碼
    iconv(train[1,2], "UTF-8", "BIG-5") # 顯示正常

    # 中文編碼轉換
    train <- as.data.frame(lapply(train, function(x) iconv(x, "UTF-8", "BIG-5")))
    names(train) <- c("id", "traindate", "program", "location", "hours")
    head(train)

    # 匯出資料
    write.table(train, file="C:/rdata/train.txt", row.names=FALSE)
    # save(train, file="C:/rdata/train.RData") # 亦可儲存成 RData 格式

    # R程式:

    # title: RWEPA - 讀取網頁表格教育訓練
    # date: 2016.9.16

    # part 1 設定R語系為C, 以配合中文編碼使用
    Sys.setlocale(category="LC_ALL", locale="C")
    Sys.getlocale()

    # part 2 載入套件,讀取網頁資料
    library(XML) # readHTMLTable 函數

    # IE: F12 --> line 7: <meta http-equiv=Content-Type content="text/html; charset=big5"> 
    # 觀察原始網頁採用 big5, 因此encoding參數設定為 big5

    urls <- "http://web.ydu.edu.tw/~alan9956/02person.htm"
    tmp <- readHTMLTable(urls, stringsAsFactors = FALSE, encoding="big5")

    length(tmp) # length=5
    train <- tmp[[1]] # 139*5

    # part 3 資料整理
    train[1,2] # 顯示亂碼
    iconv(train[1,2], "UTF-8", "BIG-5") # 顯示正常

    # 中文編碼轉換
    train <- as.data.frame(lapply(train, function(x) iconv(x, "UTF-8", "BIG-5")))
    names(train) <- c("id", "traindate", "program", "location", "hours")
    head(train)

    # 匯出資料
    write.table(train, file="C:/rdata/train.txt", row.names=FALSE)

    # save(train, file="C:/rdata/train.RData") # 亦可儲存成 RData 格式

    R程式執行結果:


    # end