R语言||干货!tidyverse包-数据转换dplyr包进阶

R-tidyverse包-数据转换dplyr包进阶

R语言||干货!tidyverse包-数据转换dplyr包进阶

目录

[TOC]

简介

Dplyr(https://dplyr.tidyverse.org/)是一种数据操作语法,提供了一组一致的动词,帮助我们解决最常见的数据操作,比如行操作(filter、slice、arrange)、列操作(slelect、rename、mutate、relocate)、折叠操作(summarise)、合并table(left_join、right_join、inner_join)。查看包中的所有函数:

library(dplyr)
ls('package:dplyr')
  • mutate:添加新列或者修改已存在列
  • select:选择列变量
  • filter:依据值过滤行
  • summarise:将多个值降为单个summary
  • arrange:行排序
  • left_join:合并两个数据框
image.png

mutate函数介绍

常规用法

library(tidyverse) # or library(dplyr)

# 创建新列,一列或多列
starwars %>%
  select(name, mass) %>%
  mutate(
    mass2 = mass * 2,
    mass2_squared = mass2 * mass2, .before=name, # .before和.after设置新列插入的位置
    test = 'test'
  )
  
# 创建新列,按行进行统计
starwars %>% select(name, height, mass) %>%rowwise() %>% mutate(m = mean(c(height, mass)))

# 创建新列,根据数值排名创建列
starwars %>%
  select(name, mass, homeworld) %>%
  group_by(homeworld) %>%
  mutate(rank = min_rank(desc(mass)))
  
# 删除列,设置NULL删除
starwars %>%
  select(name, height, mass, homeworld) %>%
  mutate(
    mass = NULL
  )

# 修改列,通过运算符修改
starwars %>%
  select(name, height, mass, homeworld) %>%
  mutate(
    height = height * 0.0328084 # convert to feet
  )

# 修改多列,利用across函数将多列字符串数据转换为因子
starwars %>%
  select(name, homeworld, species) %>%
  mutate(across(!name, as.factor))

# 保留或删除列,默认保留所有列
df <- tibble(x = 1, y = 2, a = "a", b = "b")
df %>% mutate(z = x + y, .keep = "all") # the default
df %>% mutate(z = x + y, .keep = "used")
df %>% mutate(z = x + y, .keep = "unused")
df %>% mutate(z = x + y, .keep = "none")

特殊用法

# 增加列列名为变量
col_name <- "new_column"
starwars %>% mutate(!!col_name := mass * height)

# 操作列名为变量
col_names <- c("height", "mass")
starwars %>% mutate(across(all_of(col_names), ~ .x * 2))

# 根据条件增加列
starwars %>% mutate(
  gender = case_when(
    sex == "male" ~ "Male",
    sex == "female" ~ "Female",
    TRUE ~ "Unknown"
  )
)

# 根据条件增加列,针对所有以height开头的列,值乘10
starwars %>% mutate(across(starts_with("height"), ~.x*10), .keep='used')

# 根据条件修改列
starwars %>% mutate(
  mass = if_else(mass > 100, "Yes", "No")
)

# 根据多列条件创建列
starwars %>% mutate(
  special_condition = if_else(mass > 100 & height > 200, "Yes", "No")
, .keep='used')

select函数介绍

常规用法

library(tidyverse)

# For better printing
iris <- as_tibble(iris)

# 选择列,单列或者多列
starwars %>% select(homeworld, height, mass)

# 按索引选择列
starwars %>% select(1:3)

# 按范围选择列
starwars %>% select(name:mass)

# 反选,使用!或者-反选
starwars %>% select(!(name:mass))

iris %>% select(-c(Sepal.Length, Petal.Length))

# 按条件反选
iris %>% select(!ends_with("Width"))

# 按照多个条件选择,交集
iris %>% select(starts_with("Petal") & ends_with("Width"))

# 按照多个条件选择,并集
iris %>% select(starts_with("Petal") | ends_with("Width"))

# 按照多个条件选择,并集,其中一个条件反选
iris %>% select(starts_with("Petal") & !ends_with("Width"))

特殊用法

# 选择列为变量
col_names <- c("Sepal.Length", "Sepal.Width")
iris %>% select(all_of(col_names))

col_names <- c("Sepal.Length", "Sepal.Width", "test") # test不在iris数据中
iris %>% select(one_of(col_names))

filter函数介绍

常规用法

# 根据单个条件选择行
filter(starwars, species == "Human")
filter(starwars, mass > 1000)

# 根据多个条件选择行
filter(starwars, hair_color == "none" & eye_color == "black")
filter(starwars, hair_color == "none" | eye_color == "black")
filter(starwars, hair_color == "none", eye_color == "black")

# 取反
filter(starwars, !(hair_color == "none" & eye_color == "black"))

# 根据运算结果选择行
starwars %>% filter(mass > mean(mass, na.rm = TRUE))
starwars %>% group_by(gender) %>% filter(mass > mean(mass, na.rm = TRUE))

# 列名为变量
vars <- c("mass", "height")
cond <- c(80, 150)
starwars %>%
  filter(
    .data[[vars[[1]]]] > cond[[1]],
    .data[[vars[[2]]]] > cond[[2]]
  )

特殊用法

# 列名为变量
col_name <- "Species"
value_to_filter <- "setosa"
filtered_iris <- iris %>% filter(!!sym(col_name) == value_to_filter)

summarise函数介绍

常规用法

# 统计平均值和总行数
mtcars %>%
  summarise(mean = mean(disp), n = n())

# 统计分组后平均值和总行数
mtcars %>%
  group_by(cyl) %>%
  summarise(mean = mean(disp), n = n())

# 列名是变量
var <- "mass"
summarise(starwars, avg = mean(.data[[var]], na.rm = TRUE))

summarise(starwars, avg = mean(!!sym(var), na.rm = TRUE))

特殊用法

# 分组,合并多行为一行
iris %>%
  group_by(Species) %>% summarise(test=paste(Petal.Length, collapse=','))

# 多个函数
min_max <- list(
  min = ~min(.x, na.rm = TRUE), 
  max = ~max(.x, na.rm = TRUE)
)
starwars %>% summarise(across(where(is.numeric), min_max))

starwars %>% summarise(
  tibble(
    across(where(is.numeric), ~min(.x, na.rm = TRUE), .names = "min_{.col}"),
    across(where(is.numeric), ~max(.x, na.rm = TRUE), .names = "max_{.col}")  
  )
)

arrange函数介绍

常规用法

# 依据多行进行排序
arrange(mtcars, cyl, disp)

# 降序排序
arrange(mtcars, desc(disp))

# 先升序,再降序
arrange(mtcars, mpg, desc(hp))

# <p style="color: red;">分组排序,必须设置.by_group参数为TRUE</p>
mtcars %>% group_by(cyl) %>% arrange(desc(wt),.by_group = TRUE) %>% print(n=32)

# 列名是变量
var <- 'mpg'
arrange(mtcars, !!sym(var))
arrange(mtcars, .data[[var]])

# 选择多列进行排序
iris %>% arrange(pick(starts_with("Sepal")))
iris %>% arrange(across(starts_with("Sepal"), desc))

left_join函数介绍

install.packages('nycflights13')
library(nycflights13)
flights2 <- flights %>% select(year:day, hour, origin, dest, tailnum, carrier)

# 向左合并,指定按某列合并
flights2 %>% left_join(planes, by = "tailnum")

# 按照交集合并
df1 <- tibble(x = c(1, 2), y = 2:1)
df2 <- tibble(x = c(3, 1), a = 10, b = "a")
df1 %>% inner_join(df2)

# 向右合并
df1 %>% right_join(df2)

# 按照并集合并
df1 %>% full_join(df2)

其它常用函数介绍

rename重命名列

# 修改列名
iris <- as_tibble(iris)
rename(iris, petal_length = Petal.Length)

# 修改多列列名
lookup <- c(pl = "Petal.Length", sl = "Sepal.Length")
rename(iris, all_of(lookup))

# 修改多列列名,如果列名不存在,使用any_of
lookup <- c(lookup, new = "unknown")
try(rename(iris, all_of(lookup)))
rename(iris, any_of(lookup))

# 切换列名大小写,替换字符
rename_with(iris, toupper)
rename_with(iris, toupper, starts_with("Petal"))
rename_with(iris, ~ tolower(gsub(".", "_", .x, fixed = TRUE)))

# 使用paste修改列名时,设置recycle0 = TRUE防止空选
rename_with(
  iris,
  ~ paste0("prefix_", .x, recycle0 = TRUE),
  starts_with("nonexistent")
)

# rlang包中的set_names
set_names(head(mtcars), paste0(colnames(mtcars), "_foo"))
set_names(head(mtcars), paste0, "_foo")

relocate调整列顺序

df <- tibble(a = 1, b = 1, c = 1, d = "a", e = "a", f = "a")

# 默认最前
df %>% relocate(f)

# 指定顺序
df %>% relocate(a, .after = c)
df %>% relocate(f, .before = b)
df %>% relocate(a, .after = last_col())

# 指定顺序并改名
df %>% relocate(ff = f)

# 条件选择列
df %>% relocate(where(is.character))
df %>% relocate(any_of(c("a", "e", "i", "o", "u")))

slice选择行

# 选择第一行
mtcars %>% slice(1)
# 选择尾部一行或多行
mtcars %>% slice(n())
mtcars %>% slice(5:n())
# 去除指定行
slice(mtcars, -(1:4))

# 选择头部或尾部指定行
mtcars %>% slice_head(n = 5)
mtcars %>% slice_tail(n = 5)

# 排序后选择指定行
mtcars %>% slice_min(mpg, n = 5)
mtcars %>% slice_max(mpg, n = 5)

# slice_min()和slice_max()可能返回多行,因为排序后值相同,设置with_ties = FALSE,输出指定行
mtcars %>% slice_min(cyl, n = 1)
mtcars %>% slice_min(cyl, n = 1, with_ties = FALSE)

# 随机选择行
mtcars %>% slice_sample(n = 5)
mtcars %>% slice_sample(n = 5, replace = TRUE)

# 随机选择行,并设置权重
mtcars %>% slice_sample(weight_by = wt, n = 5)

across选择列

# 选择列,并用函数处理
iris %>% mutate(across(c(Sepal.Length, Sepal.Width), round))

iris %>%
       group_by(Species) %>%
       summarise(across(starts_with("Sepal"), ~ mean(.x, na.rm = TRUE)))

# 选择列,并用函数处理,并定义列名。.col表示原来的列名,.fn表示函数名
iris %>%
       group_by(Species) %>%
       summarise(across(starts_with("Sepal"), list(mean, sd), .names = "{.col}.fn{.fn}"))

# 选择列,只要某一行满足条件即保留行
iris %>%
       filter(if_any(ends_with("Width"), ~ . > 4))

case_when条件语句

# 单列
x <- 1:70
     case_when(
       x %% 35 == 0 ~ "fizz buzz",
       x %% 5 == 0 ~ "fizz",
       x %% 7 == 0 ~ "buzz",
       .default = as.character(x)
     )

# 多列
starwars %>%
       mutate(type = case_when(
         height > 200 | mass > 200 ~ "large",
         species == "Droid" ~ "robot",
         .default = "other"
       )) %>%
       pull(type)

pull选择列

# 选择列,适用于一列,生成vector,和select函数最大的不同
mtcars %>% pull(cyl)

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

推荐阅读更多精彩内容