這是我自己在PTT PO的文,詳細介紹dplyr,以下是正文~~
這篇重點放在dplyr
plyr與dplyr有不少函數是重疊的
不過都會以dplyr為主
plyr跟dplyr有一些名字不同,但功能相似的函數
我會一併介紹
先列一下這章要介紹的函數 (沒標註的就是來自dplyr)
A. 基本整理的函數:arragnge, filter, mutate, select, group_by, summarise, n
B. 增併rownames為變數:add_rownames, plyr:::name_rows
C. list to data.frame:as_data_frame
D. by var 合併函數:join, plyr:::join, data.table:::merge, base:::merge
E. col/row 合併函數:bind_rows, data.table:::rbindlist, bind_cols
F. 取唯一列:distinct, data.table:::unique
G. 列行運算:rowwise, plyr:::colwise
H. 值映射(對應修改):plyr:::mapvalues, plyr:::revalue
I. 其他函數:summarise_each, mutate_each
J. 特殊函數:plyr:::here
- 基本整理函數
arrange: 根據你選定的變數做排列 (可以是多個變數)
filter: 根據你設定的條件做row 篩選(or selection)
mutate: 根據你給定的值賦予新變數,或是變更舊變數
select: 根據給定的變數名稱做選擇,也可以做刪除變數
group_by: 根據給定變數做group,以銜接summarise
summarise: 資料整併
n: 計算資料個數
用一個簡單例子來展示用法:
1 | set.seed(100) |
上面的例子是一些簡單運用的範例
先介紹一下tbl_df, tbl_dt的class
tbl_df跟tbl_dt只會列出一部分的資料
做操作時比較不會因為太多資料的輸出造成當機
要更改列出的資料量,可以這樣做
1 | set.seed(100) |
再介紹一些這些函數的其他用法
1 | dt = data.table(V1 = rpois(20, 3), V2 = sample(c("g1", "g2"), 20, 1), |
- 增併rownames為變數
如標題所示,直接看範例
1 | dat = data.frame(A = 1:5, row.names = paste0("City_", LETTERS[1:5])) |
- list to data.frame
as_data_frame提供比as.data.frame有效率的轉換方法
我之前也沒用過,不過看到manual寫到這個函數,就忍不住想分享一下
不過這個函數強迫list的element要有name,使用上要注意一下
1 | library(microbenchmark) |
看起來是沒差很多啦(汗顏,可能資料不夠大
- by var 合併函數
先介紹base的merge,這個函數是用來合併兩個data.frame
除了input的兩個data.frame,還有其他五個input (其他input之後再提)
a. by - 合併根據的變數
b. by.x - 合併根據的變數 於第一個data.frame的名稱
c. by.y - 合併根據的變數 於第二個data.frame的名稱
d. all.x - 是否保留來自第一個data.frame的values
e. all.y - 是否保留來自第一個data.frame的values
註:還有一個input是 all 可以一次控制all.x跟all.y
我用簡單的範例去介紹這幾個選項
1 | ## 產生資料 |
all.x跟all.y這四種組合分別對應到dplyr的四種join
a. inner_join - merge(…, all.x = FALSE, all.y = FALSE)
b. left_join - merge(…, all.x = TRUE , all.y = FALSE)
c. right_join - merge(…, all.x = FASLE, all.y = TRUE)
d. full_join - merge(…, all.x = TRUE , all.y = TRUE)
但是merge跟dplyr的join還是有些微不同
dplyr的join不會去比對by variable都是NA的情況
給一個例子就好
1 | inner_join(x, y, by = c("cat1","cat2")) |
PS: If you use dplyr 0.4.1, there is something wrong. You’re gonna find the
output do not contain the line: 3
to 0.4.2 or higher version.
至於plyr:::join就沒有這個問題
1 | join(x, y, by = c("cat1","cat2"), 'inner') |
plyr:::join用法其實大同小異,它是用type去控制join方式
最後是data.table:::merge
1 | setDT(x) |
其實用法跟merge一模一樣,不贅述
介紹完by, all.x, 跟all.y之後,我們來介紹by.x跟by.y
用一個簡單例子:
1 | set.seed(75) |
我想這個例子已經很好說明了by.x跟by.y了
接著是再dplyr怎麼做?
1 | inner_join(x, y, by = c("cat1" = "cat3", "cat2" = "cat4")) |
至於plyr:::join跟data.table:::merge就沒有支援這種功能了
dplyr還提供兩種join: semi_join跟anti_join
簡單說明一下,semi_join就是只保留第一個data.frame變數的inner_join
anti_join則semi_join沒有配對的組合
這兩個有興趣再去玩玩看,這裡就不提供例子了
最後是一個實際問題
我如果要merge超過三個的df怎麼辦?
可以參考一下 #1LaHm_aH (R_Language)
這裡完整介紹一下使用這幾個套件要怎麼解決
1 | DF_list = replicate(5, data.frame(cat1 = sample(c("A", "B"), 5, 1), |
其實這樣每一個方法的結果都會很混亂,非常不建議,除非你知道你目標是什麼
- col/row 合併函數
bind_rows跟rbindlist其實就是在做 do.call(rbind, .)或是 Reduce(rbind, .)
只是這兩個function更加有效率
如果還不懂do.call(rbind, .)跟Reduce(rbind, .)再做什麼
剛好可以利用這個機會去弄懂他們在幹嘛
1 | DF_list = replicate(5, data.frame(cat1 = sample(c("A", "B"), 5, 1), |
bind_cols等同於 do.call(cbind, .)
1 | DT_list = lapply(1:5, function(x) data.table(rnorm(5)) %>% |
此為下半部部分,下部分要介紹的function如下:
A. 取唯一列:distinct, data.table:::unique
B. 列行運算:rowwise, plyr:::colwise
C. 值映射(對應修改):plyr:::mapvalues, plyr:::revalue
D. 其他函數:summarise_each, mutate_each
E. 特殊函數:plyr:::here
F. function with underscore suffix
- 取唯一列
我在第一章 data.table提過 unique
distinct是一樣的方法
就從data.table:::unique的例子開始
1 | DT = data.table(A = rbinom(5, 1, 0.5), B = rbinom(5, 1, 0.5)) |
但是如mutate, filter等函數
distinct也可以給由變數組成的其他條件來做取唯一列的動作
給個簡單例子:
1 | distinct(DT, A*B) |
- 列行運算
mutate提供了列運算的函數 rowwise
雖然沒有apply好寫,不過效率確實好上不少
至少在chain上可以比較輕易地套用了
要介紹rowwise,還需要介紹do這個函數
do提供一些廣泛的運算方式
像是你可以根據不同變數設立模型如範例所示
1 | set.seed(100) |
data.table出來的結果不會自動group_by row
要自己手動加入rowwise,這點需要注意
do應該有更多應用,需要各位好好開發。
再來,給一個rowwise的應用:
1 | set.seed(100) |
colwise提供每一行的做一個動作的方法
其實等同於你用sapply做
只是它還可以讓你選擇你要做的column去做
簡單例子如下:
1 | set.seed(100) |
- 值映射(對應修改)
這一節要介紹兩個很好用的函數 plyr:::mapvalues, plyr:::revalue
這兩個函數再處理資料時一定很常用到
我們再整理資料時,有時候會遇到奇異值
我們要把它改成我們想要的值時
大部分人應該都會遇到這個問題
或是有時候我們需要組別整併時也會遇到
給一個簡單的example
1 | DT = data.table(col1 = sample(c("A", "B", "N"), 30, TRUE), |
最後提示幾個重點,
revalue可以用在factor跟character上面,不能用在數值上
mapvalues可以用在integer, double跟character上面,factor要先轉chr
- 其他函數
這兩個函數 summarise_each, mutate_each,我自己也很少用
我提供一些例子做操作,先用簡單的例子
1 | DT = data.table(X = rnorm(100), Y = rnorm(100)) |
這例子只是很簡單的介紹他們的功能
可能需要時間來累積看看是否有什麼好方法去用這兩個函數
- 特殊函數
介紹一個我覺得很有趣的函數 here
here可以幫助你再使用sapply系列時
可以使用mutate等
提一個簡單的例子
1 | DTs = resplicate(5, data.table(A = rnorm(5)), simplify = FALSE) |
- function with underscore suffix
本章最後一個重點
怎麼使用像是filter_, select_, mutate_, …這些以_結尾的function
這些以_結尾的function提供使用者使用string作為input
中間執行的過程透過 lazyeval 來執行
(其實dplyr大部分函數都透過這個套件)
來看幾個簡單的例子
1 | DT = data.table(A = rnorm(5), B = rnorm(5)) |
這幾個例子應該可以很簡單的解釋有_的函數要怎麼使用
最後給個.dots的用法,這個代表說你可以製作適當的string放入
1 | DT = data.table(x = rnorm(100), y = rnorm(100)) |
再給一個簡單的例子
1 | DT = data.table(x1 = rnorm(100), x2 = rnorm(100)) |