[心得] 资料整理套件介绍-第二章 dplyr(上)

楼主: celestialgod (天)   2015-07-22 14:14:32
这章重点放在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
1. 基本整理函数
arrange: 根据你选定的变量做排列 (可以是多个变量)
filter: 根据你设定的条件做row 筛选(or selection)
mutate: 根据你给定的值赋予新变量,或是变更旧变量
select: 根据给定的变量名称做选择,也可以做删除变量
group_by: 根据给定变量做group,以衔接summarise
summarise: 资料整并
n: 计算资料个数
用一个简单例子来展示用法:
` R
set.seed(100)
(dt = data.table(V1 = rpois(5, 3),
V2 = sample(c("g1", "g2"), 5, 1), V3 = rnorm(5)))
# V1 V2 V3
# 1: 2 g1 0.3186301
# 2: 2 g2 -0.5817907
# 3: 3 g1 0.7145327
# 4: 1 g2 -0.8252594
# 5: 3 g1 -0.3598621
dt %>% arrange(V1, V2, V3)
# V1 V2 V3
# 1: 1 g2 -0.8252594
# 2: 2 g1 0.3186301
# 3: 2 g2 -0.5817907
# 4: 3 g1 -0.3598621
# 5: 3 g1 0.7145327
dt %>% filter(V1 <= 2, V3 < 0)
# V1 V2 V3
# 1: 2 g2 -0.5817907
# 2: 1 g2 -0.8252594
dt %>% mutate(V5 = V1 * V3, V6 = substr(V2, 2, 2),
V7 = round(V3), V8 = 1L, V3 = V3 **2)
# V1 V2 V3 V5 V6 V7 V8
# 1: 2 g1 0.1015251 0.6372602 1 0 1
# 2: 2 g2 0.3384804 -1.1635814 2 -1 1
# 3: 3 g1 0.5105570 2.1435981 1 1 1
# 4: 1 g2 0.6810531 -0.8252594 2 -1 1
# 5: 3 g1 0.1295008 -1.0795864 1 0 1
dt %>% select(V1, V2)
# V1 V2
# 1: 2 g1
# 2: 2 g2
# 3: 3 g1
# 4: 1 g2
# 5: 3 g1
dt %>% group_by(V2) %>% summarise(size_g = n(), m_V3 = mean(V3),
s_V1 = sum(V1))
# V2 size_g m_V3 s_V1
# 1 g1 3 0.2244336 8
# 2 g2 2 -0.7035251 3
`
上面的例子是一些简单运用的范例
先介绍一下tbl_df, tbl_dt的class
tbl_df跟tbl_dt只会列出一部分的资料
做操作时比较不会因为太多资料的输出造成当机
要更改列出的资料量,可以这样做
` R
set.seed(100)
(dt = data.table(V1 = rpois(50, 3), V2 = sample(c("g1", "g2"), 50, 1),
V3 = rnorm(50))) %>% tbl_dt(FALSE)
# V1 V2 V3
# 1 2 g1 -0.4470622
# 2 2 g1 -1.7385979
# 3 3 g1 0.1788648
# 4 1 g1 1.8974657
# 5 3 g2 -2.2719255
# 6 3 g1 0.9804641
# 7 4 g1 -1.3988256
# 8 2 g1 1.8248724
# 9 3 g2 1.3812987
# 10 1 g1 -0.8388519
# .. .. .. ...
print(dt, n = 5)
# V1 V2 V3
# 1 2 g1 -0.4470622
# 2 2 g1 -1.7385979
# 3 3 g1 0.1788648
# 4 1 g1 1.8974657
# 5 3 g2 -2.2719255
# .. .. .. ...
`
再介绍一些这些函数的其他用法
` R
dt = data.table(V1 = rpois(20, 3), V2 = sample(c("g1", "g2"), 20, 1),
V3 = rnorm(20), V4 = rgamma(20, 5, 3))
# 你可以直接用一个你想要使用的变量放入,不须先立变量
dt %>% arrange(V1*V3, V3)
dt %>% filter(abs(V1*V3) > 1)
# desc是dplyr的函数提供反向排列
dt %>% arrange(V1)
dt %>% arrange(desc(V1))
# 两种做变量删除的方式 (我偏好第二种)
dt %>% mutate(V4 = NULL)
dt %>% select(-V4)
# select 还有提供各种特别函数于select中使用
dt %>% select(starts_with("V"))
dt %>% select(ends_with("1"))
dt %>% select(contains("2"))
dt %>% select(matches("\\w\\d"))
dt %>% select(num_range("V", 1:2))
`
2. 增并rownames为变量
如标题所示,直接看范例
` R
dat = data.frame(A = 1:5, row.names = paste0("City_", LETTERS[1:5]))
dat %>% name_rows
dat %>% add_rownames
dat %>% add_rownames("city") # add_rownames可以改成你要的名称
`
3. list to data.frame
as_data_frame提供比as.data.frame有效率的转换方法
我之前也没用过,不过看到manual写到这个函数,就忍不住想分享一下
不过这个函数强迫list的element要有name,使用上要注意一下
` R
library(microbenchmark)
dat_list = lapply(rep(1e6, 200), rnorm)
names(dat_list) <- paste0("A", 1:200)
microbenchmark(
as_data_frame(dat_list),
as.data.frame(dat_list)
)
#Unit: milliseconds
# expr min lq mean median uq
# as_data_frame(dat_list) 1.22642 1.281156 1.418296 1.311944 1.339027
# as.data.frame(dat_list) 19.83196 20.199147 21.397833 20.350524 21.143335
# expr max neval
# as_data_frame(dat_list) 6.957693 100
# as.data.frame(dat_list) 33.307182 100
`
看起来是没差很多啦(汗颜,可能资料不够大
4. 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
我用简单的范例去介绍这几个选项
` R
## 产生资料
set.seed(75)
(x = data.frame(cat1 = sample(c("A", "B", NA), 5, 1),
cat2 = sample(c(1, 2, NA), 5, 1), v = rpois(5, 3),
stringsAsFactors = FALSE))
# cat1 cat2 v
# 1 A 1 4
# 2 A 2 3
# 3 <NA> NA 4
# 4 B NA 4
# 5 A 1 4
(y = data.frame(cat1 = sample(c("A", "B", NA), 5, 1),
cat2 = sample(c(1, 2, NA), 5, 1), v = rpois(5, 3),
stringsAsFactors = FALSE))
# cat1 cat2 v
# 1 A 2 1
# 2 A 1 8
# 3 <NA> NA 2
# 4 B 2 5
# 5 <NA> 1 3
## 两个data.frame的资料都不保留 (默认值)
merge(x, y, by = c("cat1","cat2"), all.x = FALSE, all.y = FALSE)
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 1 4 8
# 3 A 2 3 1
# 4 <NA> NA 4 2
## 保留第一个data.frame的全部资料
merge(x, y, by = c("cat1","cat2"), all.x = TRUE, all.y = FALSE)
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 1 4 8
# 3 A 2 3 1
# 4 B NA 4 NA
# 5 <NA> NA 4 2
## 保留第二个data.frame的全部资料
merge(x, y, by = c("cat1","cat2"), all.x = FALSE, all.y = TRUE)
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 1 4 8
# 3 A 2 3 1
# 4 B 2 NA 5
# 5 <NA> 1 NA 3
# 6 <NA> NA 4 2
## 保留两个data.frame全部的资料
merge(x, y, by = c("cat1","cat2"), all.x = TRUE, all.y = TRUE)
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 1 4 8
# 3 A 2 3 1
# 4 B 2 NA 5
# 5 B NA 4 NA
# 6 <NA> 1 NA 3
# 7 <NA> NA 4 2
`
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的情况
给一个例子就好
` R
inner_join(x, y, by = c("cat1","cat2"))
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 2 3 1
# 3 A 1 4 8
`
跟上面merge(x, y, all.x = FALSE, all.y = FALSE)相比
少了 4 <NA> NA 4 2,也就是inner_join忽略了by variable都是NA值的情况
关于这点,我不太清楚是dplyr设计本来就这样,还是有忽略到,我也不清楚
(我已经去github询问了,之后会再更新在这篇)
因此,使用上请注意这一点。
至于plyr:::join就没有这个问题
` R
join(x, y, by = c("cat1","cat2"), 'inner')
# cat1 cat2 v v
# 1 A 1 4 8
# 2 A 2 3 1
# 3 <NA> NA 4 2
# 4 A 1 4 8
`
plyr:::join用法其实大同小异,它是用type去控制join方式
最后是data.table:::merge
` R
setDT(x)
setDT(y)
merge(x, y, by = c("cat1","cat2"))
# cat1 cat2 v.x v.y
# 1: NA NA 4 2
# 2: A 1 4 8
# 3: A 1 4 8
# 4: A 2 3 1
`
其实用法跟merge一模一样,不赘述
介绍完by, all.x, 跟all.y之后,我们来介绍by.x跟by.y
用一个简单例子:
` R
set.seed(75)
x = data.frame(cat1 = sample(c("A", "B", NA), 5, 1),
cat2 = sample(c(1, 2, NA), 5, 1), v = rpois(5, 3),
stringsAsFactors = FALSE)
y = data.frame(cat3 = sample(c("A", "B", NA), 5, 1),
cat4 = sample(c(1, 2, NA), 5, 1), v = rpois(5, 3),
stringsAsFactors = FALSE)
merge(x, y, by.x = c("cat1","cat2"), by.y = c("cat3","cat4"))
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 1 4 8
# 3 A 2 3 1
# 4 <NA> NA 4 2
`
我想这个例子已经很好说明了by.x跟by.y了
接着是再dplyr怎么做?
` R
inner_join(x, y, by = c("cat1" = "cat3", "cat2" = "cat4"))
# cat1 cat2 v.x v.y
# 1 A 1 4 8
# 2 A 2 3 1
# 3 A 1 4 8
`
至于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)
这里完整介绍一下使用这几个套件要怎么解决
` R
DF_list = replicate(5, data.frame(cat1 = sample(c("A", "B"), 5, 1),
cat2 = sample(c(1, 2), 5, 1), v = rnorm(5)), simplify = FALSE)
# 下列两种会变成横表,每一个data.frame的v都会保留
Reduce(function(x, y) merge(x, y, by = c("cat1","cat2"), all=TRUE), DF_list)
Reduce(function(x, y) full_join(x, y, by = c("cat1","cat2")), DF_list)
# 只保留第一个data.frame的值
join_all(DF_list, by = c("cat1","cat2"), type = "full")
# 直表,保留全部的v,等同于全部做rbind
join_all(DF_list, by = c("cat1","cat2", "v"), type = "full")
`
其实这样每一个方法的结果都会很混乱,非常不建议,除非你知道你目标是什么
5. col/row 合并函数
bind_rows跟rbindlist其实就是在做 do.call(rbind, .)或是 Reduce(rbind, .)
只是这两个function更加有效率
如果还不懂do.call(rbind, .)跟Reduce(rbind, .)再做什么
刚好可以利用这个机会去弄懂他们在干嘛
` R
DF_list = replicate(5, data.frame(cat1 = sample(c("A", "B"), 5, 1),
cat2 = sample(c(1, 2), 5, 1), v = rnorm(5)), simplify = FALSE)
bind_rows(DF_list)
rbindlist(DF_list)
`
bind_cols等同于 do.call(cbind, .)
`
DT_list = lapply(1:5, function(x) data.table(rnorm(5)) %>%
setnames(paste0("V", x)))
bind_cols(DT_list)
`
还有一半,我们留到下一章再讨论。
[关键字]: dplyr
作者: MADNUG (1234567654321一下吧)   2015-07-22 14:48:00
第一章还没研究完,第二章又出来了>"< 感谢推推
作者: kokolotl (nooooooooooo)   2015-07-22 22:12:00
感谢~~
作者: squallscer (羽毛)   2015-07-22 23:07:00
推实用!dplyr爱好者+1

Links booklink

Contact Us: admin [ a t ] ucptt.com