【R语言】必学包之tidyr包
改写说明
1. gather****实现wide 到 long 转换
在tidyr库中,gather函数与 reshape2 库中的 melt 函数等同于,在功能上能够实现将数据从宽格式转换为长格式。
| gather(data, key, value, ..., na.rm = FALSE, convert = FALSE, factor_key = FALSE) |
|---|
- 数据源:输入需要处理的数据框
- 键名:指定用于分组的关键列
- 值:指定用于汇总的结果列
- …:允许指定其他可选分组列(col1:coln),同时排除特定列(col1-coln)
- 缺失值处理:是否移除缺失值,默认为False
- 自动转换:为True时会自动在键列上应用type.convert函数,默认为False
- 因子类型:为True时将键设置为因子型变量
require(tidyr)
#将mtcars的所有列聚合成两列
gather(mtcars, attr, value)
#聚合mpg和gear之间的列
gather(mtcars, attr, value, mpg:gear)
#仅聚合mpg和wt变量,其余变量保持不变
gather(mtcars, attr, value, mpg, wt)
代码解读
require(dplyr)
#添加car列到mtcars中
mtcars$car <- rownames(mtcars)
#除了car列,将mtcars的所有列聚合成两列
gather(mtcars, attr, value, -car)
mtcars %>% gather(attr, value, -car)
#聚合mpg和gear之前的列
mtcars %>% gather(attr, value, mpg:gear)
mtcars %>% gather(mpg:gear, key = "attr", value = "value")
#仅聚合gear和carb变量,其余变量保持不变
mtcars %>% gather(attr ,value ,gear ,carb)
mtcars %>% gather(gear ,carb ,key = "attr", value = "value")
代码解读
2. spread实现long 到wide转换
改写说明
| spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL) |
|---|
- data: 长格式数据源
- key: 需要扩展的分类变量名
- value: 扩展使用的度量值
- fill: 当convert为TRUE时,在新增列中自动填入fill值替代缺失项
- convert: 当convert为TRUE时,在新增列中自动调用type.convert函数(默认as.is参数设为TRUE)
- drop: 当drop设为FALSE时保留factor类别,并用fill值填充缺失项
- sep: 若无指定,默认情况下将新列名设为key值;若指定则可表示为<key_name>
<key_value>
require(dplyr)
mtcars$car <- rownames(mtcars)
longformat <- gather(mtcars, attr, value, -car)
#还原长格式为原宽格式数据
spread(longformat, attr, value)
longformat %>% spread(attr, value)
#设置sep,新的列名为<key_name><sep><key_value>的形式
spread(longformat, attr, value, sep = '|')
#还原长格式为原宽格式数据,car列的值转换为每一个列
spread(longformat, car, value)
longformat %>% spread(car, value)
代码解读
df <- data.frame(x = c("a", "b"), y = c(3, 4), z = c(5, 6))
#转换为宽格式再转换为长格式,实际还原为原df,只是变量顺序不同
df %>% spread(x, y) %>% gather(x, y, a:b, na.rm = TRUE)
代码解读
df <- data.frame(row = rep(c(1, 51), each = 3),
var = c("Sepal.Length", "Species", "Species_num"),
value = c(5.1, "setosa", 1, 7.0, "versicolor", 2))
#对于混合类型的value列,默认convert = FALSE,转换的新列为factor类型
df %>% spread(var, value)
#设置convert = TRUE,保留原类型
df %>% spread(var, value, convert = TRUE)
代码解读
3. unite****合并多列为一列
tidyr中的unite函数可将多列按指定分隔符合并为一列。
| unite(data, col, ..., sep = "_", remove = TRUE) |
|---|
- dataset:表示数据框
- target_column:表示将要生成的新列名称
- …:用于指定需要合并的列集合(可选),该操作允许选择两个目标列之间的所有连续列为新特征,并跳过标有…-coln的特定特征
- separator:定义新特征之间分隔符,默认值为下划线 "_"
- keep_only_if:设置筛选条件以决定是否保留新特征(可选)
library(dplyr)
#使用默认的连接符“_”合并vs和am列为新列vs_am,并删除vs和am列
unite(mtcars, vs_am, vs, am)
mtcars %>% unite(vs_am, vs, am)
#使用默认的连接符“_”合并vs和am列为新列vs_am,保留vs和am列
unite(mtcars, vs_am, vs, am, remove = FALSE)
#使用连接符“|”合并vs和am列为新列vs_am,并删除vs和am列
unite(mtcars, vs_am, vs, am, sep = '|')
代码解读
4. separate****分割一列为多列
tidyr 提供的 separate 函数能够将单一列依据分隔符分割成多个列,并与 reshape2 包中的 colsplit 函数等同于功能。通常用于处理涉及日期时间的数据的合并与分解。
| separate(data, col, into, sep = "[^[:alnum:]]+", remove = TRUE, convert = FALSE, extra = "warn", fill = "warn", ...) |
|---|
data字段为数据框
目标col字段需要被拆分
新建字段名称为into参数指定
拆分依据是sep参数中的分隔符
remove参数决定是否删除原始col字段
当as.is设为TRUE时会自动将新字段根据type.convert函数进行数据转换,默认情况下不会执行此操作
当分割出的数据量超过指定数量时可以选择"warn"显示警告并移除多余的数据行或者选择"drop"直接移除多余的数据行或者选择"merge"将多余的数据与现有数据合并
当分割出的数据量少于指定数量时可以选择"warn"显示警告并从右侧填充缺失值或者选择"right"直接从右侧填充缺失值或者选择"left"直接从左侧填充缺失值以满足需求
library(dplyr)
df <- data.frame(x = c(NA, "a.b", "a.d", "b.c"))
#分割为两列,保留NA值
df %>% separate(x, c("A", "B"))
代码解读
df <- data.frame(x = c("a", "a b", "a b c", NA))
#分割为两列,发出warning并删除多余的列,缺失的列从右以NA填充
df %>% separate(x, c("a", "b"))
#分割为两列,直接删除多余的列,缺失的列从右以NA填充
df %>% separate(x, c("a", "b"), extra = "drop", fill = "right")
#分割两次(设置的列为两列),缺失的列从左以NA填充
df %>% separate(x, c("a", "b"), extra = "merge", fill = "left")
代码解读
df <- data.frame(date = c("2017-03-08 01:20:20", "2017-03-09 02:30:30", "2017-03-10 03:40:40"))
#分割为year,month,day,hour,minute,second六列
df %>%
separate(date, c("day", "time"), sep = " ") %>%
separate(day, c("year", "month", "day"), sep = "-") %>%
separate(time, c("hour", "minute", "second"), sep = ":")
代码解读
不同于separate的方法(extract)利用正则表达式(regex)来提取需要分割的列字段,在输入数据缺失或无法匹配正则表达式的情况下(即输入为NA),结果返回值将被视为缺失(NA)
| extract(data, col, into, regex = "([[:alnum:]]+)", remove = TRUE, convert = FALSE, ...) |
|---|
library(dplyr)
df <- data.frame(x = c(NA, "a.b", "a.d", "b.c"))
#分割为两列,regex匹配要分割的列
df %>% extract(x, c("a", "b"), regex = "([a-d]+).([a-d]+)")
df %>% extract(x, c("A", "B"), "([[:alnum:]]+).([[:alnum:]]+)")
#分割为两列,regex匹配要分割的列,不能匹配列的输出为NA
df %>% extract(x, c("a", "b"), regex = "([a-d]+).([a-c]+)")
#分割为一列
df %>% extract(x, c("a"), regex = "([a-d]+)")
df %>% extract(x, c("a"))
代码解读
该函数separate_rows的作用是将单个列拆分为多行,并通过指定参数来确定哪些列需要被分割。其中参数指定需要进行分割的列。特别地,在处理多个列时,请确保每一列被拆分后生成的行数保持一致。参数sep则决定了分隔使用的字符。
| separate_rows(data, ..., sep = "[^[:alnum:].]+", convert = FALSE) |
|---|
library(dplyr)
df <- data.frame(
x = 1:3,
y = c("a", "d,e,f", "g,h"),
z = c("1", "2,3,4", "5,6"),
stringsAsFactors = FALSE
)
#分割y和z列,转换为行
separate_rows(df, y, z, convert = TRUE)
代码解读
5. 嵌套和嵌套还原
嵌套函数可将指定列的数据元素按结构重组为列表形式,从而缩减数据框规模。Tidyr中的nest()函数可将分组数据框转换成包含列表形式的新结构,其中包含一个列表作为其单个列为特征。nest()后的分组部分仅保留各自唯一的标识,而对应的合并操作会生成一个新列表作为该位置的新字段。值得注意的是所有参与合并的操作最终会被整合到同一位置形成一个新字段。另一个相关函数chop()稍有不同,该方法允许各个独立的操作分别处理而不相互干扰。
| #所有合并列全部一起nest为新列 nest(.data, ..., .key = deprecated()) #合并列分别进行nest chop(data, cols) |
|---|
# 将除Species的列进行nest操作,生成的新列的元素都为list对象
# 其中nest()合并为一列,chop()分别对各列进行合并
iris %>% nest(data = -Species)
iris %>% chop(cols = -Species)
nest_vars <- names(iris)[1:4]
iris %>% nest(data = one_of(nest_vars))
iris %>% chop(cols = one_of(nest_vars))
# 分别组合多列进行合并,chop()不支持此操作
iris %>% nest(petal = starts_with("Petal"), sepal = starts_with("Sepal"))
# 先进行分组操作,分组变量之外的变量会进行nest合并
iris %>% group_by(Species) %>% nest()
# 对不同分组建立线性模型
mtcars %>%
group_by(cyl) %>%
nest() %>%
mutate(models = lapply(data, function(df) lm(mpg ~ wt, data = df)))
代码解读
与其相反,在pandas中存在两个功能相关的函数:unnest()和unchop()。这些函数能够实现数据框展开操作,并将嵌套的列表对象展平
| #unnest数据框对象 unnest(data, cols, ..., keep_empty = FALSE, ptype = NULL, names_sep = NULL, names_repair = "check_unique", .drop = deprecated(), .id = deprecated(), .sep = deprecated(), .preserve = deprecated()) unchop(data, cols, keep_empty = FALSE, ptype = NULL) |
|---|
df <- tibble(
x = 1:4,
y = list(NULL, 1:2, 3, NULL),
z = list('d', c('a', "b"), "c", NULL)
)
# 展开y和z列,并且删除值都为NULL的行,不全为NULL的行保留
df %>% unnest(c(y, z))
df %>% unchop(c(y, z))
# 展开y和z列,设置keep_empty = TRUE保留所有行
df %>% unnest(c(y, z), keep_empty = TRUE)
df %>% unchop(c(y, z), keep_empty = TRUE)
# 展开y和z列,设置展开后列的类型
df %>% unchop(c(y, z), ptype = tibble(y = character(), z = character()))
# 先使用y列展开,在使用z展开,和直接使用y,z展开不同,y和z会进行笛卡尔积
df %>% unchop(y) %>% unchop(z)
代码解读
6. 缺失值处理
tidyr包提供了简单的缺失值处理方法,包括替换,填充,删除等。
| #使用给定值替换每列的缺失值 replace_na(data, replace = list(), ...) |
|---|
- data:为数据框
- replace:替换值用于替换每个列中NA
library(dplyr)
df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b"))
#以0替换x中的NA,以unknown替换y中的NA
df %>% replace_na(list(x = 0, y = "unknown"))
代码解读
| #以前一个值填充缺失值,默认自上向下填充 fill(data, ..., .direction = c("down", "up")) |
|---|
- data字段用于表示数据框。
- …参数用于指定需填充的列。该参数支持选择两列之间的所有中间列(例如col1:coln),也可通过逗号分隔多选。此外可通过附加参数排除特定不需要处理的单个或多个特定列为colm。
- .direction参数设置填充方向,默认值为down(自上而下)填入。
df <- data.frame(x = 1:5, y = c(10, NA, 15, NA, 20))
#自上向下替换NA值
df %>% fill(y)
df %>% fill(y, .direction = "down")
#自下向上替换NA值
df %>% fill(y, .direction = "up")
代码解读
| #填充以创建完整的序列值向量 full_seq(x, period, tol = 1e-06) |
|---|
- 该变量表示为x:数值向量。
- period被定义为观测值之间的间隔,并用于检测现有数据是否与此间隔一致;如果不一致则会报错。
#返回序列1:6
full_seq(c(1, 2, 4, 6), 1)
#period值与原数据间隔不匹配,报错Error: `x` is not a regular sequence.
full_seq(c(1, 2, 4, 6), 2)
#返回序列1:13,间隔为2
full_seq(c(1, 5, 9, 13), 2)
代码解读
| #删除包含缺失值的行 drop_na(data, ...) |
|---|
- data代表数据框;
- ...用于指定需填充的字段,并可选择两字段间的所有中间字段col1:coln(跳过coln)。
df <- data_frame(x = c(1, 2, NA), y = c("a", NA, "b"))
#删除变量x中NA对应的行
df %>% drop_na(x)
#删除变量y中NA对应的行
df %>% drop_na(y)
#未设置列,删除变量x和y中NA对应的行
df %>% drop_na()
代码解读
| #转换隐式的缺失值为显式的 complete(data, ..., fill = list()) |
|---|
- dataFrame实例用于表示完整的表格结构。
- ...: 指定需扩展的数据字段。
- 各输入字段作为独立参数参与数据框扩展。
当采用笛卡尔积或直接传递各字段名作为参数时,
会基于各字段中的元素生成所有可能组合,
即便生成的所有组合不在原始表格中也允许生成。
返回的所有组合必须存在于原始表格中。 - 填充值: 用于代替缺失值。
df <- data_frame(
group = c(1:2, 1),
item_id = c(1:2, 2),
item_name = c("a", "b", "b"),
value1 = 1:3,
value2 = 4:6
)
#以item_id和item_name中的每个元素扩展原数据框, 组合后的缺失值以NA代替
df %>% complete(item_id, item_name)
df %>% complete(crossing(item_id, item_name))
#以item_id和item_name中的每个元素扩展原数据框, 并以给定值替换缺失值
df %>% complete(item_id, item_name, fill = list(group = 0, value1 = 0, value2 = 0))
#以item_id和item_name中的每个元素扩展原数据框,只返回原数据框中存在的组合
df %>% complete(nesting(item_id, item_name))
#保留group,以item_id和item_name中的每个元素扩展原数据框,只返回原数据框
#中item_id和item_name存在的组合
df %>% complete(group, nesting(item_id, item_name))
df %>% complete(group, nesting(item_id, item_name), fill = list(value1 = 0, value2 = 0))
#保留group,以item_id和item_name中的每个元素扩展原数据框,返回所有item_id
#和item_name存在的组合
df %>% complete(group, crossing(item_id, item_name))
df %>% complete(group, crossing(item_id, item_name), fill = list(value1 = 0, value2 = 0))
代码解读
