引言
一直以來都聽聞tidy-r是使R語言起死回生的存在系枪,盡管沒有系統(tǒng)學(xué)習(xí)過,但已經(jīng)在coding中潛移默化的使用了許多tidy語法候生,例如管道符%>%
桑包、ggplot2
等等募壕。最近在處理bed文件時遇到了很多base-r解決起來非常復(fù)雜的問題调炬,網(wǎng)上一查都是用dplyr包解決的。因此本文記錄一下dplyr的常用語法舱馅,希望以后逐漸由base-r向tidy-r過渡缰泡。
dplyr函數(shù)特征
- 第一個參數(shù)是一個數(shù)據(jù)框。
- 隨后的參數(shù)描述了如何處理第一個參數(shù)中指定的數(shù)據(jù)框代嗤,你可以直接引用數(shù)據(jù)框中的列棘钞,而無需使用 $ 運(yùn)算符(只需使用列名)。
- 函數(shù)的返回結(jié)果是一個新的數(shù)據(jù)框
- 數(shù)據(jù)框必須經(jīng)過正確格式化和注釋才能發(fā)揮作用干毅。尤其是數(shù)據(jù)必須整齊宜猜。簡而言之,每一行應(yīng)該有一個樣本硝逢,每一列應(yīng)該代表那個樣本的特征姨拥。
篩選行:filter()
- 例如,篩選出 1 月 1 日的所有航班
filter(flights, month == 1, day == 1)
這里渠鸽,flights是數(shù)據(jù)框叫乌,“month == 1, day == 1”是篩選條件,默認(rèn)是且的關(guān)系徽缚,還可以用其他條件進(jìn)行篩選:
filter(flights, month == 1 | day == 1)
排序行:arrange()
- 按year, month, day的優(yōu)先級排列數(shù)據(jù)框flights
arrange(flights, year, month, day)
- 如果有多個列名憨奸,那么就先按前面的列名排,然后在此基礎(chǔ)上排后面的列名
- 默認(rèn)按升序排(從小到大)
- 用 desc() 降序排凿试,如
arrange(flights, desc(arr_delay))
# 按arr_delay降序排宰,對觀測進(jìn)行重排
- 缺失值總是排在最后
篩選列:select()
- 選擇數(shù)據(jù)框flights中的year, month, day這幾列
select(flights, year, month, day)
- 選擇“year”和“day”之間的所有列(包括“year”和“day”)
select(flights, year:day)
- 選擇不在“year”和“day”之間的所有列似芝,記得帶括號
select(flights, -(year:day))
可以在 select () 函數(shù)中使用一些輔助函數(shù),這些跟Excel中選擇名稱的規(guī)則類似
starts_with("abc")
:匹配 開頭是“abc” 的名稱额各。
ends_with("xyz")
:匹配 結(jié)尾是“xyz” 的名稱国觉。
contains("ijk")
:匹配 包含“ijk” 的名稱吧恃。
matches("(.)\\1")
:選擇匹配正則表達(dá)式的那些變量虾啦。這個正則表達(dá)式會匹配名稱中有重復(fù)字符的變量。
num_range("x", 1:3)
:匹配 x1痕寓、 x2 和 x3傲醉。把 time_hour 和 air_time 移到數(shù)據(jù)框的開頭,其余按原來的順序呈現(xiàn)
select(flights, time_hour, air_time, everything())
重命名列:rename()
- 將變量tailnum重命名為tail_num
rename(flights, tail_num = tailnum)
添加新列:mutate()
- 添加新列:gain 和 speed呻率,并排在數(shù)據(jù)集的最后
mutate(flights,gain = arr_delay - dep_delay,speed = distance / air_time * 60)
- 新列一旦創(chuàng)建硬毕,就可立即使用。如在創(chuàng)建新列 gain_per_hour 的時候礼仗,用到了剛創(chuàng)建的新列 gain 和 hours
mutate(flights_sml,gain = arr_delay - dep_delay,hours = air_time / 60,gain_per_hour = gain / hours)
- 如果只想保留新變量吐咳,可以使用 transmute() 函數(shù),如下代碼輸出結(jié)果中只有3列:gain 元践、 hours 和 gain_per_hour
transmute(flights,gain = arr_delay - dep_delay,hours = air_time / 60,gain_per_hour = gain / hours)
- 輔助運(yùn)算符
算術(shù)運(yùn)算符:+韭脊、 -、 *单旁、 /沪羔、 ^
模運(yùn)算符:%/%(求整) 和 %%(求余),可以拆分整數(shù)象浑。
對數(shù)函數(shù):log()蔫饰、 log2() 和 log10()。
偏移函數(shù):lead() 返回序列領(lǐng)先值愉豺、 lag() 返回序列滯后值篓吁。
累加和滾動聚合:cumsum() 累加和、 cumprod() 累加積蚪拦、commin() 累加最小值杖剪、 cummax() 累加最大值、cummean() 累加均值外盯,這幾個函數(shù)對于繪圖非常重要
邏輯比較:<摘盆、 <=、 >饱苟、 >= 和 !=
排秩:最常用的是min_rank() 孩擂,升序排,輸出結(jié)果是名次箱熬,如1 2 3 ... n类垦。
分組分析:group_by() 和 summarize()
- 可以將數(shù)據(jù)框折疊成一行狈邑,如下代碼輸出為一個值,即所有航班的平均起飛延誤時間
summarize(flights, delay = mean(dep_delay, na.rm = TRUE))
- 與 group_by() 聯(lián)用蚤认,即在分組基礎(chǔ)上進(jìn)行摘要統(tǒng)計米苹。group_by() 和 summarize() 聯(lián)用是 dplyr 包最常用的操作之一。
- 如:將所有結(jié)果按method和benchmark分組砰琢,計算新分組的每組平均值蘸嘶,并用 n() 函數(shù)計數(shù),返回當(dāng)前分組的大小
> 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
-
只使用均值陪汽、計數(shù)和求和是遠(yuǎn)遠(yuǎn)不夠的训唱, dplyr還提供了常見的摘要函數(shù),如:
- 位置度量:median(x) 中位數(shù)
- 分散程度度量:sd(x) 標(biāo)準(zhǔn)誤差挚冤、 IQR(x) 四分位距 和 mad(x) 絕對中位差
- 秩的度量:min(x)况增、max(x) 和 quantile(x, 0.25) 找出 x 中按從小到大順序大于前25% 而小于后 75% 的值
- 定位度量:first(x)、 nth(x, 2) 和 last(x)
- 計數(shù):n() 返回當(dāng)前分組的大小训挡, sum(!is.na(x)) 計算出非缺失值的數(shù)量澳骤, n_distinct(x) 計算出唯一值的數(shù)量,count()返回指定組合的計數(shù)
- 邏輯值的計數(shù)和比例:sum(x > 10) 找出 x 中 TRUE 的數(shù)量澜薄, mean(y == 0) 找出x 中 TRUE 的比例为肮。
用 ungroup() 函數(shù)取消分組,并回到未分組的數(shù)據(jù)繼續(xù)操作
處理雙表格
- 左鏈接
left_join()
:以左邊的表的by變量為準(zhǔn)合并表悬,如果有數(shù)據(jù)缺失則顯示NA弥锄。 - 右鏈接
right_join()
:以右邊的表的by變量為準(zhǔn)合并,如果有數(shù)據(jù)缺失則顯示NA蟆沫。 - 內(nèi)鏈接
inner_join()
:返回兩個表中的交集部分籽暇。 - 外鏈接
full_join()
:返回兩表中的并集部分。
其他函數(shù)
- add_count():給最后一列添加某列的counts數(shù)
- distinct(col, .keep_all = T):只保留col不重復(fù)的行
實(shí)戰(zhàn)
- 計算單細(xì)胞矩陣的TPM
mm10_gene <- read.table('/mdshare/node10/xyx/projects/RNA-editing/reference/genome_bed/mm10/mm10_gene.bed')
mm10_gene %>%
as_tibble() %>% # df轉(zhuǎn)tibble
transmute(gene_name = V6, # 新建一個tibble包含列g(shù)ene_name
length = V3 - V2) %>% # 包含列l(wèi)ength為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()
總結(jié)
初次接觸tidyr會感覺函數(shù)的形參比較隨意饭庞,除了第一個參數(shù)必須是數(shù)據(jù)框本身戒悠,后續(xù)參數(shù)都沒有嚴(yán)格要求,有的參數(shù)還是函數(shù)名(例如之前一直不太理解的ggplot2中的aes()
)舟山。但實(shí)際上绸狐,這是因為tidyr的語法更多的是面向操作,而我之前使用的基于which()的篩選方法更多的是面向結(jié)果累盗。想想網(wǎng)上的tidyr代碼頭幾行為什么通常使用的是df %>% filter() %>% ...
,而不是filter(df, ...)
符相?如果使用管道符,就可以感受到最初的df只是一個輸入的對象啊终,而后續(xù)則是對數(shù)據(jù)框內(nèi)的元素進(jìn)行花式操作。如果這樣理解的話就會發(fā)現(xiàn)tidyr代碼的優(yōu)雅和易讀了趟脂。
參考
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