R语言编程-Tidyverse 书籍-第二章(1)

本章节主要讲数据操作

三个关键点

  1. 向量化编程思维和函数式编程思维, 应用在数据框或更高级的数据结构中
  2. 将复杂数据操作分解为若干基本数据操作的能力
    :数据连接、数据重塑(长宽变换/拆分合并列)、筛选行、排序行、选择列、修改列、分组汇总
  3. 接受数据分解的操作思维

1 管道操作

magrittr 包引入了管道操作,能够通过管道将数据从一个函数传给另一个函数,从而用若干函数
构成的管道依次变换你的数据。
例如
x %>% f() %>% g()
依次对数据进行若干操作:先对x 进行f 操作, 接着对结果数据进行g 操作

常用管道操作

管道默认将数据传给下一个函数的第1 个参数,且它可以省略。

c(1, 3, 4, 5, NA) %>%
    mean(na.rm = TRUE)
数据可以在下一个函数中使用多次

数据经过管道默认传递给函数的第1 个参数(通常直接省略);若在非第1 个参数处使用该数据,
必须用“.” 代替(绝对不能省略),这使得管道作用更加强大和灵活.
同时用于拼接成字符串给main 参数用于图形标题

c(1, 3, 4, 5) %>%
   plot(main = str_c(., collapse=","))

"." 用于管道操作中代替数据;".x" 用于purrr 风格公式(匿名函数)。

2 数据读入

readr 包

read_csv() 和read_tsv();
专门的欧式: read_csv2() 和read_tsv2();欧式格式数据以“;” 为分隔符,“,” 为小数位.
写出数据到文件:write_csv(), write_tsv(), write_csv2(), write_tsv2()
转化数据类型:parse_number(), parse_logical(), parse_factor()

readxl 包

专门读取Excel 文件,包括同一个工作簿中的不同工作表:
read_excel(): 自动检测xls 或xlsx 文件
read_xls(): 读取xls 文件
read_xlsx(): 读取xlsx 文件
读写Excel 文件好用的包,还有openxlsx

haven 包

读写SPSS, Stata, SAS 数据:

  • 读:read_spss(), read_dta(), read_sas()
  • 写:write_spss(), write_stata(), write_sas()

保存与载入rds 数据

除了save() 和load() 函数外,以下函数也可以:
write_rds(iris, "my_iris.rds")
dat = read_rds("my_iris.rds")

连接数据库

将大数据存放在远程数据库(远程服务器或本地硬盘),然后建立与R 的连接,再从R 中执行查
询、探索、建模等。
dplyr 是tidyverse 操作数据的最核心包,而dbplyr 包是用于数据库的dplyr 后端,让您能够
操作远程数据库中的数据表,就像它们是内存中的数据框一样。安装dbplyr 包时,还会自动安装DBI
包,它提供了通用的接口,使得能够使用相同的代码与许多不同的数据库连用。
常见的主流数据库软件:SQL Server, MySQL, Oracle 等都能支持,但还需要为其安装特定的驱
动,比如
RMariaDB 包:连接到MySQL 和MariaDB

这里不详细写,因为很少使用。

中文编码

中文乱码是让很多编程者头痛的问题。
ASCII最通用, 是UTF8与GBK两者之间的交集
UTF8目前具有更加通用的形式
每个读取函数都有自己读入的设置参数
readr 包和rvest 包(爬虫)都提供了函数guess_encoding(),可检测文本和网页的编码
方式;python 有一个chardet 库在检测文件编码方面更强大。

3 数据连接

合并行:下方堆叠新行,根据列名匹配列,注意列名相同,否则作为新列(NA 填充);
合并列:右侧拼接新列,根据位置匹配行,行数必须相同

purrr 包中map_dfr() 和map_dfc() 函数可以在批量读入数据的同时做合并行/合并列。

根据值匹配合并数据框

左连接:left_join(), 保留x 所有行,合并匹配的y 中的列, 没有的使用NA补充

x  %>% 
   left_join(y, by = c("var1"="var2")) 
或者多个变量: by=c("var1", "var2")

类似的有
右连接:right_join(), 保留所有的y,
全连接:full_join(), 保留所有的行
内连接:inner_join(), 只保留共有的行
半连接:semi_join(),根据在y 中,来筛选x 中的行。
反连接:anti_join(), 根据不在y 中,来筛选x 中的行

多个数据表连接,使用purrr包中的reduce()

需要批量读取它们,再依次做全连接(做其他连接也是类似的)。reduce() 可以实现先将前两个
表做全连接,再将结果表与第三个表做全连接(更多表就依次这样做下去):

files = list.files("datas/achieves/", pattern = "xlsx", full.names = TRUE)
map(files, read_xlsx) %>%
reduce(full_join, by = " 人名") # 读入并依次做全连接

若还是上述数据,但是在一个工作簿的多个工作表中,批量读取并依次做全连接:

path = "datas/3-5 月业绩.xlsx"
map(excel_sheets(path),~ read_xlsx(path, sheet = .x)) %>%
reduce(full_join, by = " 人名")

集合运算

intersect(x, y) # 返回x 和y 共同包含的观测;
union(x, y) # 返回x 和y 中所有的(唯一) 观测;
setdiff(x, y) # 返回在x 中但不在y 中的观测。

数据重塑

整洁的数据:是变量为一列, 观测值为一行,组成数据框。
如果不整洁,需要首先重塑数据。
数据重塑主要包括长宽表转化、拆分/合并列。
使用函数tidyr包的 pivot_longer() 和pivot_wider().

宽表变长表

宽表的特点是:表比较宽,本来该是‘‘值” 的,却出现在‘‘变量(名)” 中。
用tidyr 包中的pivot_longer() 函数来实现宽表变长表,其基本格式为:
pivot_longer(data, cols, names_to, values_to, values_drop_na, ...)

  • data: 要重塑的数据框
  • cols: 用选择列语法选择要变形的列
  • names_to: 为存放变形列的列名中的’’ 值’’,指定新列名
  • values_to: 为存放变形列中的’’ 值’’,指定新列名
  • values_drop_na: 是否忽略变形列中的NA
  • 若变形列的列名除了’’ 值’’ 外,还包含前缀、变量名+ 分隔符、正则表达式分组捕获模式,则可
    以借助参数names_prefix, names_sep, names_pattern 来提取出‘‘值’’。
宽变长
每行有一个观测值
df %>% 
  pivot_longer(-var, names_to = "year", values_to = "GDP")
每行有多个观测值
df %>%  
  pivot_longer(-var, 
               names_to = c(".value", "child"),
               names_sep = "_",
               values_drop_na = T
               )

df %>% 
  pivot_longer(everything(),
               names_to = c("number", ".value"),
               names_pattern = "(.*\\d)(.*)")

长表变宽表

用tidyr 包中的pivot_wider() 函数来实现长表变宽表,其基本格式为:

pivot_wider(data, id_cols, names_from, values_from, values_fill, ...)

  • data: 要重塑的数据框
  • id_cols: 唯一识别观测的列,默认是除了names_from 和values_from 指定列之外的列
  • names_from: 指定列名来自哪个变量列
  • values_from: 指定列’’ 值’’ 来自哪个变量列

另外还有若干帮助修复列名的参数:names_prefix, names_sep, names_glue.

长变宽时,经常会遇到两个问题:

  • 长变宽正常会压缩行,为什么行数没变呢?
    回答:长变宽时要注意,是不能带着类似x 列这种唯一识别各行的ID 列的
  • 值不能被唯一识别,输出将包含列表列
df = df %>%
group_by(y) %>%
mutate(n = row_number())
df

拆分列与合并列

用separate() 函数来拆分列,其基本语法为:
** separate(data, col, into, sep, ...)**

  • col: 要拆分的列
  • into: 拆开的新列,
  • sep: 指定根据什么分隔符拆分
    separate_rows() 函数,可对不定长的列进行分列,并按行堆叠放置

用unite() 函数来合并列,其基本语法为:
unite(data, col, sep, ...)

  • col: 要合并的列
  • sep: 指定合并各列添加的分隔符

方形化

方形化(Rectangling)是将一个深度嵌套的列表(通常来自JSON 或XML)驯服成一个整齐的行 和列的数据集

  • unnest_longer():提取列表列的每个元,再按行存放(横向展开)
  • unnest_wider():提取列表列的每个元,再按列存放(纵向展开)
  • unnest_auto():提取列表列的每个元,猜测按行或按列存放
  • hoist():类似unnest_wider(),但只取出选择的组件,且可以深入多个层
    或者改用hoist() 直接从内层提取想要的列,再对列表列title 做纵向展开:

2.5 操作数据

用dplyr 包实现各种数据操
共有5 种基本数据操作:


  • select()—— 选择列用:
    用“:”选择连续的若干列
    用"!"选择变量集合的余集(反选)
    "&" 和"|" 选择变量集合的交或并
    "c()" 合并多个选择
    everything(): 选择所有列
    last_col(): 选择最后一列
    starts_with(): 以某前缀开头的列名
    ends_with(): 以某后缀结尾的列名
    contains(): 包含某字符串的列名
    matches(): 匹配正则表达式的列名
    num_range(): 匹配数值范围的列名,如num_range("x", 1:3) 匹配x1, x2, x3
    where(): 应用一个函数到所有列,选择返回结果为TRUE 的列,比如与is.numeric 等函数连用
根据正则表达式匹配选择列:
df %>%
   select(matches("m.*a"))

根据条件(逻辑判断)选择列,例如选择所有数值型的列:
df %>%
     select(where(is.numeric))

也可以自定义返回TRUE 或FALSE 的判断函数,支持purrr 风格公式写法。例如,选择列和>3000 的列:
df[, 4:8] %>%
select(where(~ sum(.x, na.rm = TRUE) > 3000))


  • filter()/slice()——筛选行
  • arrange()——对行排序
  • mutate()—— 修改列/创建新列
  • summarize()—— 汇总
    这些函数都可以与
  • group_by()——分组
  • across() - 选择多列
  • if_any(), if_all()
    连用,以改变数据操作的作用域:作用在整个数据框,或数据框的每个分组。
调整列的顺序

列是根据被选择的顺序排列
everything() 返回未被选择的所有列,将某一列移到第一列时很方便:

df %>%
   select(var5, everything())

用relocate() 函数,将选择的列移到某列之前或之后,基本语法为:
relocate(.data, ..., .before, .after)

例如,将数值列移到name 列的后面:
df %>%
relocate(where(is.numeric), .after = name)
set_names() 为所有列设置新列名
rename() 只修改部分列名,格式为:新名= 旧名

rename_with(.data, .fn, .cols) (最好用)

  • .col 支持用选择列语法选择要重命名的列,
  • .fn 是对所选列重命名的函数,将原列名的字符向量变成新列名的字符向量。

比如,将包含”m’’ 的列名,都拼接上前缀”new_“:

df %>%
    rename_with(~ paste0("new_", .x), matches("m"))

across()

函数across() 人如其名,让零个/一个/多个函数穿过所选择的列,即同时对所选择的多列应用若干函数,基本格式为
across(.cols = everything(), .fns = NULL, ..., .names)

  • .cols 为根据选择列语法选定的列范围;
  • .fns 为应用到选定列上的函数,它可以是:
    NULL:不对列作变换;
    一个函数,如mean;
    一个purrr 风格的匿名函数,如~ .X * 10
    多个函数或匿名函数构成的列表
  • .names 用来设置输出列的列名样式,默认为{col}_{fn}

across() 支持各种选择列语法,与mutate() 和summarise() 连用,产生非常强大的同时修改/(多种) 汇总多列效果;
across() 也能与group_by(), count() 和distinct() 连用,此时.fns 为NULL,只起选择列的作用。
新组合:

  • across(everything(), .fns): 在所有列范围内,代替后缀_all
  • across(where(), .fns): 在满足条件的列范围内,代替后缀_if
  • across(.cols, .fns):在给定的列范围内,代替后缀_at
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容