草庐IT

编程笔记6-dplyr常用语法

江湾青年 2023-03-28 原文

引言

一直以来都听闻tidy-r是使R语言起死回生的存在,尽管没有系统学习过,但已经在coding中潜移默化的使用了许多tidy语法,例如管道符%>%ggplot2等等。最近在处理bed文件时遇到了很多base-r解决起来非常复杂的问题,网上一查都是用dplyr包解决的。因此本文记录一下dplyr的常用语法,希望以后逐渐由base-r向tidy-r过渡。

tidyverse家族


dplyr函数特征

  1. 第一个参数是一个数据框。
  2. 随后的参数描述了如何处理第一个参数中指定的数据框,你可以直接引用数据框中的列,而无需使用 $ 运算符(只需使用列名)。
  3. 函数的返回结果是一个新的数据框
  4. 数据框必须经过正确格式化和注释才能发挥作用。尤其是数据必须整齐。简而言之,每一行应该有一个样本,每一列应该代表那个样本的特征。

筛选行:filter()

  • 例如,筛选出 1 月 1 日的所有航班
filter(flights, month == 1, day == 1)

这里,flights是数据框,“month == 1, day == 1”是筛选条件,默认是且的关系,还可以用其他条件进行筛选:

filter(flights, month == 1 | day == 1)

排序行:arrange()

  • 按year, month, day的优先级排列数据框flights
arrange(flights, year, month, day)
  • 如果有多个列名,那么就先按前面的列名排,然后在此基础上排后面的列名
  • 默认按升序排(从小到大)
  • 用 desc() 降序排,如
arrange(flights, desc(arr_delay))
# 按arr_delay降序,对观测进行重排
  • 缺失值总是排在最后

筛选列:select()

  • 选择数据框flights中的year, month, day这几列
select(flights, year, month, day)
  • 选择“year”和“day”之间的所有列(包括“year”和“day”)
select(flights, year:day)
  • 选择不在“year”和“day”之间的所有列,记得带括号
select(flights, -(year:day))
  • 可以在 select () 函数中使用一些辅助函数,这些跟Excel中选择名称的规则类似
    starts_with("abc"):匹配 开头是“abc” 的名称。
    ends_with("xyz"):匹配 结尾是“xyz” 的名称。
    contains("ijk"):匹配 包含“ijk” 的名称。
    matches("(.)\\1"):选择匹配正则表达式的那些变量。这个正则表达式会匹配名称中有重复字符的变量。
    num_range("x", 1:3):匹配 x1、 x2 和 x3。

  • 把 time_hour 和 air_time 移到数据框的开头,其余按原来的顺序呈现

select(flights, time_hour, air_time, everything())

重命名列:rename()

  • 将变量tailnum重命名为tail_num
rename(flights, tail_num = tailnum)

添加新列:mutate()

  • 添加新列:gain 和 speed,并排在数据集的最后
mutate(flights,gain = arr_delay - dep_delay,speed = distance / air_time * 60) 
  • 新列一旦创建,就可立即使用。如在创建新列 gain_per_hour 的时候,用到了刚创建的新列 gain 和 hours
mutate(flights_sml,gain = arr_delay - dep_delay,hours = air_time / 60,gain_per_hour = gain / hours)
  • 如果只想保留新变量,可以使用 transmute() 函数,如下代码输出结果中只有3列:gain 、 hours 和 gain_per_hour
transmute(flights,gain = arr_delay - dep_delay,hours = air_time / 60,gain_per_hour = gain / hours)
  • 辅助运算符
    • 算术运算符:+、 -、 *、 /、 ^

    • 模运算符:%/%(求整) 和 %%(求余),可以拆分整数。

    • 对数函数:log()、 log2() 和 log10()。

    • 偏移函数:lead() 返回序列领先值、 lag() 返回序列滞后值。

    • 累加和滚动聚合:cumsum() 累加和、 cumprod() 累加积、commin() 累加最小值、 cummax() 累加最大值、cummean() 累加均值,这几个函数对于绘图非常重要

    • 逻辑比较:<、 <=、 >、 >= 和 !=

    • 排秩:最常用的是min_rank() ,升序排,输出结果是名次,如1 2 3 ... n。


分组分析:group_by() 和 summarize()

  • 可以将数据框折叠成一行,如下代码输出为一个值,即所有航班的平均起飞延误时间
summarize(flights, delay = mean(dep_delay, na.rm = TRUE))
  • 与 group_by() 联用,即在分组基础上进行摘要统计。group_by() 和 summarize() 联用是 dplyr 包最常用的操作之一。
  • 如:将所有结果按method和benchmark分组,计算新分组的每组平均值,并用 n() 函数计数,返回当前分组的大小
> group_by(fig2a,method,benchmark) %>% 
+   summarise(mean = mean(value),
+             num = n()) 

# 输出:
`summarise()` has grouped output by 'method'. You can override using the `.groups` argument.
# A tibble: 28 × 4
# Groups:   method [7]
   method       benchmark          mean   num
   <fct>        <fct>             <dbl> <int>
 1 scMAGIC-atac Accuracy          0.806     3
 2 scMAGIC-atac Average Recall    0.783     3
 3 scMAGIC-atac Average Precision 0.754     3
 4 scMAGIC-atac Mean F1           0.752     3
 5 GLUE         Accuracy          0.822     3
 6 GLUE         Average Recall    0.727     3
 7 GLUE         Average Precision 0.765     3
 8 GLUE         Mean F1           0.725     3
 9 Seurat       Accuracy          0.776     3
10 Seurat       Average Recall    0.666     3
# … with 18 more rows
  • 只使用均值、计数和求和是远远不够的, dplyr还提供了常见的摘要函数,如:

    1. 位置度量:median(x) 中位数
    2. 分散程度度量:sd(x) 标准误差、 IQR(x) 四分位距 和 mad(x) 绝对中位差
    3. 秩的度量:min(x)、max(x) 和 quantile(x, 0.25) 找出 x 中按从小到大顺序大于前25% 而小于后 75% 的值
    4. 定位度量:first(x)、 nth(x, 2) 和 last(x)
    5. 计数:n() 返回当前分组的大小, sum(!is.na(x)) 计算出非缺失值的数量, n_distinct(x) 计算出唯一值的数量,count()返回指定组合的计数
    6. 逻辑值的计数和比例:sum(x > 10) 找出 x 中 TRUE 的数量, mean(y == 0) 找出x 中 TRUE 的比例。
  • 用 ungroup() 函数取消分组,并回到未分组的数据继续操作


处理双表格

  • 左链接left_join():以左边的表的by变量为准合并,如果有数据缺失则显示NA。
  • 右链接right_join():以右边的表的by变量为准合并,如果有数据缺失则显示NA。
  • 内链接inner_join():返回两个表中的交集部分。
  • 外链接full_join():返回两表中的并集部分。

其他函数

  • add_count():给最后一列添加某列的counts数
  • distinct(col, .keep_all = T):只保留col不重复的行

实战

  • 计算单细胞矩阵的TPM
mm10_gene <- read.table('/mdshare/node10/xyx/projects/RNA-editing/reference/genome_bed/mm10/mm10_gene.bed')
mm10_gene %>% 
  as_tibble() %>%                                       # df转tibble
  transmute(gene_name = V6,                             # 新建一个tibble包含列gene_name
            length = V3 - V2) %>%                       # 包含列length为end - start
  group_by(gene_name) %>%                               # 按gene_name分组
  summarise(meanlen = round(mean(length))) %>%          # 计算每组的平均长度
  filter(gene_name %in% rownames(counts_mtx)) ->        # 筛选在query_mtx中的基因名
  counts_mtx_gene_len
counts_mtx_gene_len
counts_mtx <- counts_mtx[counts_mtx_gene_len$gene_name,]
counts_mtx_TPM <- apply(counts_mtx,2,function(col){col/counts_mtx_gene_len$meanlen}) %>% 
  NormalizeData()

总结

初次接触tidyr会感觉函数的形参比较随意,除了第一个参数必须是数据框本身,后续参数都没有严格要求,有的参数还是函数名(例如之前一直不太理解的ggplot2中的aes())。但实际上,这是因为tidyr的语法更多的是面向操作,而我之前使用的基于which()的筛选方法更多的是面向结果。想想网上的tidyr代码头几行为什么通常使用的是df %>% filter() %>% ...,而不是filter(df, ...)?如果使用管道符,就可以感受到最初的df只是一个输入的对象,而后续则是对数据框内的元素进行花式操作。如果这样理解的话就会发现tidyr代码的优雅和易读了。


参考

http://www.360doc.com/content/21/0805/12/73394596_989613319.shtml
https://bookdown.org/rdpeng/rprogdatascience/managing-data-frames-with-the-dplyr-package.html#dplyr-grammar
https://blog.csdn.net/m0_52406014/article/details/123823476

有关编程笔记6-dplyr常用语法的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  3. 网络编程套接字 - 2

    网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识

  4. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  5. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  6. ruby - 如何以编程方式删除实例上的 "singleton information"以使其编码(marshal)? - 2

    我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。

  7. Ruby 元编程问题 - 2

    我正在查看Ruby日志记录库Logging.logger方法并从sourceatgithub提出问题与这段代码有关:logger=::Logging::Logger.new(name)logger.add_appendersappenderlogger.additive=falseclass我知道类 最佳答案 这实际上删除了方法(当它实际被执行时)。这是确保close不会被调用两次的保障措施。看起来好像有嵌套的“class 关于Ruby元编程问题,我们在StackOverflow上找到一

  8. ruby - Paperclip:以编程方式分配图像并设置其名称 - 2

    使用Paperclip,我想从这样的URL抓取图像:require'open-uri'user.photo=open(url)问题是我最后得到一个像“open-uri20110915-4852-1o7k5uw”这样的文件名。有什么方法可以更改user.photo上的文件名?作为一个额外的变化,Paperclip将我的文件存储在S3上,所以如果我可以在初始分配中设置我想要的文件名就更好了,这样图像就会上传到正确的S3key。像这样:user.photo=open(url),:filename=>URI.parse(url).path 最佳答案

  9. ruby - 如何以编程方式检查证书是否已被吊销? - 2

    我正在开发一个xcode自动构建系统。在执行一些预构建验证时,我想检查指定的证书文件是否已被撤销。我了解securityverify-cert验证其他证书属性但不验证吊销。我如何检查撤销?我正在用Ruby编写构建系统,但我对任何语言的想法都持开放态度。我阅读了这个答案(Openssl-Howtocheckifacertificateisrevokedornot),但指向底部的链接(DoesOpenSSLautomaticallyhandleCRLs(CertificateRevocationLists)now?)进入的Material对我的目的来说有点过于复杂(用户上传已撤销的证书是一

  10. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

随机推荐