【R语言】必学包之tidyr包

      tidyr用于数据处理,可以实现数据长格式和宽格式之间的相互转换,这里所指的长格式数据就是一个观测对象由多行组成,而宽数据格式则是一个观测仅由一行组成。除此之外,tidyr还可以对数据进行拆分和合并,同时也能够对缺失值进行简单的处理。tidyr的转换函数gather(宽到长)和spread(长到宽)所需参数少,逻辑上更易理解,自始至终都围绕着data,key、value三个参数来进行设定,对比其它R语言长宽格式互换的实现方式,个人认为tidyr操作性还是比较突出的。

1. gather实现wide 到 long 转换

tidyr中的gather函数类似于reshape2中的melt函数,可实现将宽格式数据转换为长数据格式。

gather(data, key, value, ..., na.rm = FALSE, convert = FALSE, factor_key = FALSE)

  • data:需要被转换的宽形data.frame
  • key:将原数据框中的所有列赋给一个新变量key
  • value:将原数据框中的所有值赋给一个新变量value
  • …:可以指定哪些列聚到同一列中,可用于选择两列之间的所有列col1:coln, 排除列-coln
  • na.rm:是否删除缺失值,默认为FALSE不删除
  • convert:为TRUE时会自动在key列上使用type.convert函数,默认值为FALSE
  • factor_key:FALSE时key值为字符向量,TRUE时key值为factor类型
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转换

tidyr中的spread函数类似于reshape2中的cast函数,可实现将长格式数据转换为宽数据格式。

spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)

  • data:为需要转换的长形data.frame
  • key:设置需要扩宽的类别变量
  • value:设置需要扩宽的变量的度量值
  • fill:对于缺失值,可将fill的值赋值给被转型后的缺失值
  • convert:为TRUE时会自动在新列上使用type.convert函数,其中as.is = TRUE,默认值为FALSE
  • drop: 为FALSE保留factor的level,使用fill的值填充missing的值
  • sep:为默认值NULL时,新列名使用key中的值,非NULL时,新列名为
require(dplyr)
mtcars$car <- rownames(mtcars)
longformat <- gather(mtcars, attr, value, -car)
#还原长格式为原宽格式数据
spread(longformat, attr, value)
longformat %>% spread(attr, value)
#设置sep,新的列名为的形式
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)

  • data:为数据框
  • col:被组合的新列名称
  • …:指定哪些列需要被组合, 可用于选择两列之间的所有列col1:coln, 排除列-coln
  • sep:组合列之间的连接符,默认为下划线
  • remove:是否删除被组合的列
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:是否删除被分割的列
  • convert:为TRUE时会自动在新列上使用type.convert函数,其中as.is = TRUE,默认值为FALSE
  • extra:当分割成的列多于length(into)时,"warn"(默认值) 发出警告并删除多余值,"drop"直接删除多余值,"merge"仅
  • 分割length(into)次
  • fill:当分割成的列少于length(into)时,"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或者不能匹配regex时,输出为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. 嵌套和嵌套还原

      所谓的嵌套函数可用于将指定列的对应元素‘折叠’为list,缩小原有数据框的大小。Tidyr提供两个函数进行嵌套合并操作,nest()将分组数据框转换为嵌套数据框,即包含列表列的数据框,转换后分组列只会保留每个值的唯一值,与之对应合并列中的所有值会合并为list对象生成新列,这里需要注意的是所有合并列都会合并在一起生成一列,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)))

与之相反,unnest()函数和unchop()可以进行数据框展开,把折叠的list对象展开。

#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, 排除列-coln
  • .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())

  • data:为数据框
  • …:指定需要扩展的列,每个输入列都作为一个独立的参数用于扩展数据框。其中使用crossing或者直接输入列作为参数时,会使用每个列中的元素进行扩展,即使生成的组合在原数据框中不存在;而使用nesting函数时,返回的每个列元素的组合必须在原数据框中存在。
  • fill:用于设置填充值以替换NA
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))

 

你可能感兴趣的:(R语言,数据处理,R必学包,r语言,数据整理)