dplyr包-列变换的方法
专题介绍:R是一种广泛用于数据分析和统计计算的强大语言,于上世纪90年代开始发展起来。得益于全世界众多 爱好者的无尽努力,大家继而开发出了一种基于R但优于R基本文本编辑器的R Studio(用户的界面体验更好)。也正是由于全世界越来越多的数据科学社区和用户对R包的慷慨贡献,让R语言在全球范围内越来越流行。其中一些R包,例如MASS,SparkR, ggplot2,使数据操作,可视化和计算功能越来越强大。R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个自由、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。R作为一种统计分析软件,是集统计分析与图形显示于一体的。它可以运行于UNIX、Windows和Macintosh的操作系统上,而且嵌入了一个非常方便实用的帮助系统,相比于其他统计分析软件,R的学术性开发比较早,适合生物学和医学等学术学科的科研人员使用。
【R语言】已开通R语言社群,五湖四海,天南地北,各行各业,有缘相聚,共享R事,雕刻数据,求解问题,以创价值。喜乐入群者,请加微信号luqin360,或扫描文末二维码,添加为好友,同时附上R-入群。有朋自远方来,不亦乐乎,并诚邀入群,以达相互学习和进步之美好心愿。
这是dplyr包系列第二篇文章。第一篇文章《dplyr包-列选择的方法》总结了如何使用dplyr包有效地选择感兴趣的列。本文会总结列变换的方法,以实现按着需求对列做合理处理,例如:衍生新的列,列的离散化,列的拆分与合并等。
列的变换操作,会介绍如下内容:
-
增加一列
-
增加多列
-
列的离散化操作
-
列的拆分
-
列的合并
-
列的集成
-
数据重塑
我们以R自带数据,采用管道的操作,演示列变换的具体操作和实现。
第一步:加载R包和数据集
1library(pacman)
2p_load(tidyverse)
3# 使用msleep数据集做示例
4msleep %>% glimpse
第二步:列变换操作实例
1 增加一列,使用mutate()函数
1# 1 增加一列
2msleep %>%
3 select(name, sleep_total) %>%
4 mutate(sleep_total_min = sleep_total * 60) %>%
5 head
增加的新列,也可使用聚合函数,计算平均值、中位数、最大值、最小值、标准差等。
1msleep %>%
2 select(name, sleep_total) %>%
3 mutate(sleep_total_vs_AVG = sleep_total - round(mean(sleep_total), 1)) %>%
4 head
若要基于两列或者多列的值按着行来做聚合以生成新的列,可以参照如下方法实现。
1# 方法1 使用rowwise 指定按着每行做聚合计算
2msleep %>%
3 select(name, contains("sleep")) %>%
4 rowwise() %>%
5 mutate(avg1 = mean(c(sleep_rem, sleep_cycle))) %>%
6 head
7# 方法2
8msleep %>%
9 select(name, contains("sleep")) %>%
10 mutate(avg1 = (sleep_rem + sleep_cycle)/2) %>%
11 head
思考题:
1)若要增加一列,记录brainw大于4,就为NA,否则为原值,请问如何实现?
2)请问下面这个代码片段实现了什么功能?
1# ?这个代码片段的作用是什么
2msleep %>%
3 select(name) %>%
4 mutate(name_last_word = tolower(str_extract(name, pattern = "w+$"))) %>%
5 head
2 增加多列,使用mutate_all(),mutate_if()和mutate_at()函数
2.1 mutate_all(),对所有列操作
1)把所有列小写化
1msleep %>%
2 select(name, genus, vore) %>%
3 mutate_all(tolower) %>%
4 head
2)对所有列做数据清洗工作
1msleep_ohno <- msleep %>%
2 select(name, genus, vore) %>%
3 mutate_all(~paste(., " /n "))
4msleep_ohno %>% head
5msleep_corr <- msleep_ohno %>%
6 mutate_all(~str_replace_all(., "/n", "")) %>%
7 mutate_all(str_trim)
8msleep_corr %>% head
2.2 mutate_if(),对布尔值为真的列进行操作
常用的布尔值判断函数
is.numeric,is.integer,is.double,is.logical,is.factor,lubridate::POSIXt或者lubridate::is.Date
例如,对所有数值型变量取一位小数
1# 自定义函数
2my_func <- function(x){
3 return(round(x,1))
4}
5msleep %>%
6 select(name, sleep_total:bodywt) %>%
7 mutate_if(is.numeric, my_func) %>%
8 head
9
2.3 mutate_at(), 在vars()参数中指定要操作的列
具体使用方法,第一步,在vars指定需要操作的列,第二步,使用波浪线引入所需操作的函数。
1msleep %>%
2 select(name, sleep_total:awake) %>%
3 mutate_at(vars(contains("sleep")), ~(.*60)) %>%
4 rename_at(vars(contains("sleep")), ~paste0(.,"_min")) %>%
5 head
3 列的离散化操作
1) 重编码操作,使用recode()函数或者recode_factor()函数
1msleep %>%
2 mutate(conservation2 = recode(conservation,
3 "en" = "Endangered",
4 "lc" = "Least_Concern",
5 "domesticated" = "Least_Concern",
6 .default = "other")) %>%
7 count(conservation2)
8msleep %>%
9 mutate(conservation2 = recode_factor(conservation,
10 "en" = "Endangered",
11 "lc" = "Least_Concern",
12 "domesticated" = "Least_Concern",
13 .default = "other",
14 .missing = "no data",
15 .ordered = TRUE)) %>%
16 count(conservation2)
2) 创建新的离散列(二元情形),使用ifelse()函数
1msleep %>%
2 select(name, sleep_total) %>%
3 mutate(sleep_time = ifelse(sleep_total > 10, "long", "short")) %>%
4 head
3) 创建新的离散列(多元情形),使用case_when()函数
1msleep %>%
2 select(name, sleep_total) %>%
3 mutate(sleep_total_discr = case_when(
4 sleep_total > 13 ~ "very long",
5 sleep_total > 10 ~ "long",
6 sleep_total > 7 ~ "limited",
7 TRUE ~ "short")) %>%
8 mutate(sleep_total_discr = factor(sleep_total_discr,
9 levels = c("short", "limited",
10 "long", "very long"))) %>%
11 head
12
4 列的拆分
使用separate()函数
1(conservation_expl <- read_csv("./datasets/conservation_explanation.csv"))
2(conservation_table <- conservation_expl %>%
3 separate(`conservation abbreviation`,
4 into = c("abbreviation", "description"), sep = " = "))
5 列的合并
使用unite()函数
1conservation_table %>%
2 unite(united_col, abbreviation, description, sep=": ")
6 列的集成
使用关联函数,左连接left_join(),内连接inner_join()等。
1msleep %>%
2 select(name, conservation) %>%
3 mutate(conservation = toupper(conservation)) %>%
4 left_join(conservation_table, by = c("conservation" = "abbreviation")) %>%
5 mutate(description = ifelse(is.na(description), conservation, description)) %>%
6 head
7 数据重塑
使用gather()函数把宽表转换成长表,使用spread()函数把长表转换成宽表。
1)gather()示例
1# 1)宽表变为长表
2msleep %>%
3 select(name, contains("sleep")) %>%
4 gather(key = "sleep_measure", value = "time", -name) %>%
5 head
思考题:下面这个代码片段,有什么作用?
1(msleep_g <- msleep %>%
2 select(name, contains("sleep")) %>%
3 gather(key = "sleep_measure", value = "time", -name, factor_key = TRUE))
2)spread()示例
1# 2) 长表变为宽表
2msleep_g %>%
3 spread(sleep_measure, time) %>%
4 head
完整代码:
1# dplyr包列变换的方法
2
3# 第一步:加载R包和数据集
4library(pacman)
5p_load(tidyverse)
6# 使用msleep数据集做示例
7msleep %>% glimpse
8
9# 第二步:列变换操作实例
10# 1 增加新的一列
11msleep %>%
12 select(name, sleep_total) %>%
13 mutate(sleep_total_min = sleep_total * 60) %>%
14 head
15
16msleep %>%
17 select(name, sleep_total) %>%
18 mutate(sleep_total_vs_AVG = sleep_total - round(mean(sleep_total), 1)) %>%
19 head
20
21# 方法1 使用rowwise 指定按着每行做聚合计算
22msleep %>%
23 select(name, contains("sleep")) %>%
24 rowwise() %>%
25 mutate(avg1 = mean(c(sleep_rem, sleep_cycle))) %>%
26 head
27# 方法2
28msleep %>%
29 select(name, contains("sleep")) %>%
30 mutate(avg1 = (sleep_rem + sleep_cycle)/2) %>%
31 head
32
33msleep %>%
34 select(name, brainwt) %>%
35 mutate(brainwt2 = ifelse(brainwt > 4, NA, brainwt)) %>%
36 head
37
38
39msleep %>%
40 select(name) %>%
41 mutate(name_last_word = tolower(str_extract(name, pattern = "w+$"))) %>%
42 head
43
44# 2 增加多列
45# mutate_all函数
46msleep %>%
47 select(name, genus, vore) %>%
48 mutate_all(tolower) %>%
49 head
50
51msleep_ohno <- msleep %>%
52 select(name, genus, vore) %>%
53 mutate_all(~paste(., " /n "))
54msleep_ohno %>% head
55msleep_corr <- msleep_ohno %>%
56 mutate_all(~str_replace_all(., "/n", "")) %>%
57 mutate_all(str_trim)
58msleep_corr %>% head
59
60# mutate_if函数
61my_func <- function(x){
62 return(round(x,1))
63}
64msleep %>%
65 select(name, sleep_total:bodywt) %>%
66 mutate_if(is.numeric, my_func) %>%
67 head
68
69# mutate_at函数
70msleep %>%
71 select(name, sleep_total:awake) %>%
72 mutate_at(vars(contains("sleep")), ~(.*60)) %>%
73 head
74
75msleep %>%
76 select(name, sleep_total:awake) %>%
77 mutate_at(vars(contains("sleep")), ~(.*60)) %>%
78 rename_at(vars(contains("sleep")), ~paste0(.,"_min")) %>%
79 head
80
81# 3 列的离散化操作
82msleep %>%
83 mutate(conservation2 = recode(conservation,
84 "en" = "Endangered",
85 "lc" = "Least_Concern",
86 "domesticated" = "Least_Concern",
87 .default = "other")) %>%
88 count(conservation2)
89
90msleep %>%
91 mutate(conservation2 = recode_factor(conservation,
92 "en" = "Endangered",
93 "lc" = "Least_Concern",
94 "domesticated" = "Least_Concern",
95 .default = "other",
96 .missing = "no data",
97 .ordered = TRUE)) %>%
98 count(conservation2)
99
100msleep %>%
101 select(name, sleep_total) %>%
102 mutate(sleep_time = ifelse(sleep_total > 10, "long", "short")) %>%
103 head
104
105msleep %>%
106 select(name, sleep_total) %>%
107 mutate(sleep_total_discr = case_when(
108 sleep_total > 13 ~ "very long",
109 sleep_total > 10 ~ "long",
110 sleep_total > 7 ~ "limited",
111 TRUE ~ "short")) %>%
112 mutate(sleep_total_discr = factor(sleep_total_discr,
113 levels = c("short", "limited",
114 "long", "very long"))) %>%
115 head
116
117msleep %>%
118 mutate(silly_groups = case_when(
119 brainwt < 0.001 ~ "light_headed",
120 sleep_total > 10 ~ "lazy_sleeper",
121 is.na(sleep_rem) ~ "absent_rem",
122 TRUE ~ "other")) %>%
123 count(silly_groups)
124
125# 4 列的拆分
126(conservation_expl <- read_csv("./datasets/conservation_explanation.csv"))
127(conservation_table <- conservation_expl %>%
128 separate(`conservation abbreviation`,
129 into = c("abbreviation", "description"), sep = " = "))
130
131# 5 列的合并
132conservation_table %>%
133 unite(united_col, abbreviation, description, sep=": ")
134
135# 6 列的集成
136# 使用连接函数
137msleep %>%
138 select(name, conservation) %>%
139 mutate(conservation = toupper(conservation)) %>%
140 left_join(conservation_table, by = c("conservation" = "abbreviation")) %>%
141 mutate(description = ifelse(is.na(description), conservation, description)) %>%
142 head
143
144# 7 列重塑
145# 1)宽表变为长表
146msleep %>%
147 select(name, contains("sleep")) %>%
148 gather(key = "sleep_measure", value = "time", -name) %>%
149
150
151(msleep_g <- msleep %>%
152 select(name, contains("sleep")) %>%
153 gather(key = "sleep_measure", value = "time", -name, factor_key = TRUE))
154
155# 2) 长表变为宽表
156msleep_g %>%
157 spread(sleep_measure, time) %>%
158 head
参考资料:
1https://suzan.rbind.io/2018/02/dplyr-tutorial-2/
你在阅读过程中,遇到什么问题,或者有什么心得与收获,可以扫描我的微信号,备注“R-入群”。我会邀请你加入R语言群,和大家一起讨论与学习。
推荐阅读:
1 R语言机器学习3本经典书籍集合本,提高你的R语言和机器学习能力!(可供下载)
2 R语言实战英文书籍,配套源代码,帮助你学习R语言!(可下载)
推荐公众号:数据科学与人工智能
数据科学与人工智能公众号推广Python语言,数据科学与人工智能的知识和信息。扫码下方二维码关注我,一起学习Python语言和数据科学与人工智能。
请关注“恒诺新知”微信公众号,感谢“R语言“,”数据那些事儿“,”老俊俊的生信笔记“,”冷🈚️思“,“珞珈R”,“生信星球”的支持!