笔记内容:
- 使用Rstudio的快捷键及tips
- 一些工作中常用、有用的packages及函数
- 各种日常备忘
- ... ...
Rstudio中批量注释
Ctrl + shift + C把list转化为vector
一些函数的input会要求数据格式必须为vector,比如需要将data.frame中跳出来一列(list)转化为vector, 且可以将其character分Levels,作为factor呈现。
vector = unlist(list, use.names = FALSE)
- 寻找重复值
duplicated()
在data.frame中寻找重复值, df[duplicated(df['ID']), ]
即返回df中ID列的重复值。duplicated()
本身返回一个Logic变量。
- ggrepel在使用ggplot画图中的应用
有时候画图plot上很多点,每个点都要加label或者text,密集的地方就都挤在一起看不清谁是谁。如果使用ggplot画图,可以使用ggrepel中的geom_text_repel()
,简单的+
在ggplot()
后面即可
install.packages('ggrepel')
library(vegan)
library(ggrepel)
mds <- cmdscale(unifrac, k=2)
mds_df <- data.frame(mds) # ggplot 只接受dataframe
ggplot(mds) +
geom_point(aes(mds_df['X1'], mds_df['X2'] )) +
geom_text_repel(aes(aes(mds_df['X1'], mds_df['X2']), label = row.names(mds_df))
如上图所示,label之间就可以互相隔开不重叠,且还有折线把label指向相应的点。
详情可以参考这个链接
- 连续型变量的分层(变为factor)
有些变量(年龄数值、血糖数值等)可能在作为连续型变量时难以发现规律,但是在分层为若干个数值范围后变得有规律可循,且可以作为分类型变量使用卡方检验。
在R中将连续型变量分为若干个层次,使用cut()
d$GC.binned <- cut(d$percent.GC, 5)
#将d的percent.GC列分为均等的5个层次,且作为新的一列GC.binned加入d
cut(d$percent.GC, c(0, 25, 50, 75, 100))
#也可以这样来分为(0,25] (25,50] (50,75] (75,100] 几个level
table()
#使用table()查看每个Level有多少样本落在里面
- package
ggplot2
的强大画图功能
ggplot2只能应用于dataframe格式的data
它存在两种用法:
(1)一种为geom_XXX, 作为几何学对象(geometric objects),常用于指定将input_data绘制成怎样的图。
(2)一种即为几何学对象添加设计类属性(aesthetic attributes),如指定图的x轴y轴为data的哪些部分,指定形状,label,颜色等属性。
plot使用基本数据集d:ggplot(d)
(用加号与后面的layer相连接)
plot出点,指定x和y的取值aes()
facet_wrap()
和facet_grid()
的用法:按照一个分类变量的column,将每个level画一个图。即按照某一个column的level分层画图。
d$time_point = factor(d$time_point)
ggplot(d, aes(x, y, colour = time_point)) + geom_point()
# aes()中指定了x,y轴的取值,直接使用dataframe d中的变量名称即可。作为分组显示不同颜色的变量time_point必须首先指定为factor
is.na()
is.na(i)
可以知道i中的缺失值。即为NA(not available)的值。其返回为Ture&False。使用table(is.na(i))
统计i中的缺失值有多少个。
!is.na()
即查看非缺失值read.table()
有时候直接使用read.table()
读取文档,R会在column names上加上X,比方说纯数字的column names3-1, 3-2, 3-3
这样,会变成X3-1, X3-2, X3-3
加上check.names = FALSE
即可subset data.frame
bar <- subset(foo, location == "there")
foo[foo$location == "there", ] #不要忘了逗号,逗号左边subset行,右边subset列
- 把data.frame中的两列string, 合并为一列,并以指定连接符连接:
paste
meta$detail <- paste(meta$sample_position,meta$treatment, sep = '_')
# meta中sample_position与treatment两列以下划线连接起来,成为新列detail
在linux系统上install.packages()的问题
有时候因为R版本不够新或者linux系统的各种问题,不能像windows那样直接用install.packages()安装需要的包。
比如说“devtools”,一个“可以让你install别人在github上做的包”的包:
先更新一下r-base:
$ sudo apt-get update
$ sudo apt-get install r-base
如果返回说“r-base is already the newest version(...)”, 那说明安装不上包不是R版本太旧的原因。
google一下发现在linux上装devtools需要一些build-essential的东西:
$ sudo apt-get install build-essential libcurl4-gnutls-dev libxml2-dev libssl-dev
安装好了之后,用root打开R shell
$ sudo -i R
install.packages('devtools')
然后会弹出来让你选择安装来源的窗口,选择0-Cloud
....装好了,可以打开R studio,library('devtools')
就可以使用了
参考这个链接使用
brewer.pal
,rainbow()
,colorRampPalette
调色作图
RColorBrewer
是很棒的调色板包,它的好处在提供各种服务于各种不同类型的数据(有序离散型,无序离散型,连续型变量等),用颜色的深浅表现循序渐进的关系。色彩饱和度较低不刺眼,又可以显著区分的颜色区分数据中不同的类别。但也存在调色板少,调色板中颜色也太少,不能在超多变量情况下使用的问题。这个问题可以用rainbow()
来解决。
主要有以下三种调色板:
(1)有序变量的调色板(sequential):从高到低,从小到大的数据,用从浅到深的颜色表示。需要注意的是每个调色板可用的颜色数目只有3-9个。也就是说要用不同颜色表示的类别,最少要有3个,最多只能有9个。
(2)两极分化的调色板(divergent):在热图的图例中常见,主要关注的是数据的两极分化情况。关注变量在哪些样本中富集,在哪些样本中稀疏。需要注意的是每个调色板可用的颜色数目只有3-11个。
(3)无序分类的调色板(qualitative):各类之间地位等同,没有顺序之分。需要注意的是每个调色板可用的颜色数目根据不同的Set有着不同的颜色上限,其下限均为3个,上限最高的为12个。
顺便一提Pastel1
和Pastel2
这两个调色盘颜色饱和度很低,可以说是马卡龙色和莫兰迪色了;Set1
,Set2
,Set3
这三个调色盘颜色饱和度从高到低。
Paired
调色板一半为冷色调一半为暖色调,可以为分为两类,又细分为若干小类的数据绘图,十分实用。
# 用display查看想用什么颜色,看帮助文档,有各种各样的set可供使用
display.brewer.pal(8, 'Blues')
display.brewer.pal(8, 'BrBG')
display.brewer.pal(8, 'Set3')
display.brewer.pal(8, 'Paired')
rainbow
虽说在帮助文件中说是为生成一系列连续型变量,但在超多变量或样本的数据中,为类别着色也十分管用。比如给80个样本绘制rarefaction curve, 可以用rainbow
生成80个不同的颜色。
col_rainbow <- rainbow(80, s=0.8, v=1)
# 80代表要生成的颜色数量,参数s和v用于设置颜色的饱和度
colorRampPalette使用方法:
colorcount <- length(unique(colnames(tax_ra))) # 比方说你想给tax_ra的每个column都安排一个颜色,column数量巨大
getPalette <- colorRampPalette(brewer.pal(9,"Set1"))
color <- getPalette(colorcount)
# color就是和tax_ra的column相对应起来的一众颜色了
- 按照factor中的levels,将levels用不同颜色区分开
虽说应该不会忘,但是还是记录一下:
比如要在meta
这个data.frame中,按照meta$treatment
这一分类变量,给样本上色。meta$treatment
在这里需要转化为具有Level的factor形式。
detail <- as.factor(meta$treatment) # 看到下面多了一行Levels: XXXX
length(levels(detail)) # 知道有多少个Levels,在Levels很多的时候可以用
plot_color <- rainbow(length(levels(detail)))[detail]
# print plot_color可以看到detail数目的颜色代码,按照levels标记了。
col1 <- brewer.pal(4,'Set1')
plot_color <- col1[detail]
# 或者用brewer.pal, 一样的道理
- 你有两个data.frame,df1的列是df2的行,但是排列顺序不一样。你想用把df2 reorder成df1列的顺序。
可是说是很拗口了,如下图所示举个例子:
如果sample的顺序可以直接正序或者倒序当然很方便,但是如果df是按照固定顺序排列的,你在某个热图中想用这种顺序展示结果。
使用match
来把顺序记录下来:
df2_ <- df2[,match(rownames(df1), colnames(df2))]
##df2行的顺序就变成df1列的顺序了
- 在R里改dataframe的列名称(colnames)
比方说上面的df2
,要把sample4改成S4。
colnames(df2)[2] <- c('S4') # 把第二个colname改成S4
colnames(df2)[colnames(df2) == 'Sample4'] <- "S4" # 把名为“sample4”的改为S4
colnames(df2) <- c('x1','x2','x3'...) # 批量修改colnames
- 分组求均值及标准差:mean(sd)
以data(ToothGrowth)
为例
library(plyr)
ddply(t, ~supp, summarise, mean = mean(len), sd = sd(len))
# 得到:
supp mean sd
1 OJ 20.66333 6.605561
2 VC 16.96333 8.266029
参考这个链接:how to summarize data by group in r
17. apply, sapply, lapply, tapply的用法
参考这个链接
apply:
apply的适用对象可以为matrix或者dataframe, 一个有行列的数据结构。
apply(matrix, x, fun())
x可以取值为1,2,或者c(1,2), 1即行,取值为1则会对每行行使fun()函数,取值为2则对每列行使fun()函数。
在对每行每列求均值,方差等,十分有用:apply(matrix, 1, mean) # 即对matrix的每行求均值
lapply及sapply:
laapy及sapply的适用对象为List,直接Input一个dataframe, 它会把每个value当作一个list来处理,估计不会得到你想要的结果。
lapply(lists, fun())
但是dataframe$coln
得到的是List,如果你想给多个列apply函数,则:
lapply(dataframe[, 1:80], fun(x) as.numeric(as.character(x)))
即对datafrmae的前80列,转化为数值型变量。这个可以用于:全部是factor的数值型变量转话为纯数值型变量(去Levels)。
sapply是lapply的参数simplify = FALSE的情况,将每个list输出结果合并成一个matrix
tapply:
适用于分组进行操作,比如分组求和,求均值方差等。类似于excel中的透视表功能。
但是需要注意它的Input是一个vector(即data.frame的一列,或者一个List),一个index(转化为factor的分组信息)。
group <- factor(dataframe$group)
gender <- factor(dataframe$gender)
tapply(dataframe[,3], list(dataframe$group, dataframe$gender), mean)
则输出一个以group和gender分组为行列的matrix, value为对应分组下的dataframe第三列value平均值。
- R的函数不能return超过一个对象:不能
return(a, b)
, 怎么办?
在function中写入:
...
list <- list("name1" = a, "name2" = b)
return (list)
# 在需要使用时用$
output <- fun()
a <- output$name1
b <- output$name2
- linux中更新R-base
$ sudo apt-get install r-base
$ sudo apt upgrade r-base r-base-dev
$ sudo apt update
$ sudo apt upgrade
在windows系统中
setwd()
设置路径
C:\Users\Usernames\Desktop\工作\项目A
-------> C:/Users/Usernames/Desktop/工作/项目Acbind()
的局限
cbind()
的output是一个matrix,这意味着它只能容忍一种类型的数据。要么全是数值型,要么全是分类型。如果你试图把一列factorcbind()
到另一个dataframe上,可能会出现factor全部变成数值(level个数)的情况。这种时候还是用data.frame()
(多么鸡肋,要你何用?=_=)
data.frame(df1, group = df2$factor)
函数中传参数用于dataframe的切片
如下所示,不能用dataframe$传参数切片,用dataframe[,]
test
s1 s2 s3 s4 tax
OTU1 1 3 5 2 p
OTU2 2 2 1 1 p
OTU3 3 0 2 0 g
OTU4 4 1 1 1 g
OTU5 1 8 0 0 g
OTU6 0 0 4 2 p
test_fun <- function(dataframe, col) {
a = dataframe$col
b = dataframe[col]
c = dataframe[, col]
return(a = a, b = b, c = c)
aa = test_fun(test, 'tax')
aa
$a
NULL
$b
tax
OTU1 p
OTU2 p
OTU3 g
OTU4 g
OTU5 g
OTU6 p
$c
[1] p p g g g p
Levels: g p
class(aa$b)
[1] "data.frame"
class(aa$c)
[1] "factor"
去除含有NA的行(把所有带NA的都去掉)
data <- data[complete.cases(data), ]
split的用法
split的Input可以是vector, list, data.frame,其返回值为list。split(x, f): x 为Input data, f为分层信息的数据,一般为一个factor
# split应用于vector及list,常常与lapply结合起来
lapply(split(iris$Sepal.Length, iris$Species), mean)
$`setosa`
[1] 5.006
$versicolor
[1] 5.936
$virginica
[1] 6.588
se <- iris[iris$Species == "setosa", "Sepal.Length"]
mean(se)
[1] 5.006
# split应用于data.frame,
a <- split(iris, iris$Species) # 得到一个list, 里面是按照不同species分好组的子data.frame
sapply(a, function(x) {colMeans(x[,c("Petal.Length", "Petal.Width")])})
setosa versicolor virginica
Petal.Length 1.462 4.260 5.552
Petal.Width 0.246 1.326 2.026
mean(iris[iris$Species == "setosa", "Petal.Length"])
[1] 1.462
write.table或write.csv后打开保存的table, 发现columns都向前移位了,把第一个本来因该空着的格子占了。检查sep没有问题。
write.table(...,col.names=NA)
用write.table或write.csv导入数据,但是部分数据有leading 0, 即存在“00001”, “00002”这样形式的ID,而且还是数值型的,这使导入的ID变成了“1”,“2”.
read.csv(...colClasses = c(rep("character",3)))
把你导入的file中全部3个columns都转化为字符串格式你想按照一个df_name给df的columns重新命名。df_name记录了两列,一列为df的columns names, 一列为要需要替换成的列(
df_name$names
)。
id <- match(colnames(df), df_name$names)
colnames(df) <- df_name$names[id]
ifelse() 太好用
e.g.colnames(df) <- ifelse(is.na(id), colnames(df), otherdf$test[id])
如果id是NA,那df的colnames不变。如果不是NA,那么按照id, 把df的colnames指定为otherdf中test列的对应值在R studio中换一种R version
在win中:在打开Rstudio的时候按住Ctrl
键,会出现让你选择使用哪个R version的界面,选择即可。
参考:https://support.rstudio.com/hc/en-us/articles/200486138-Changing-R-versions-for-RStudio-desktopdplyr的
group_by
和summarise
group_by
并没有改变数据本身,只是提示按照什么分了多少组,如下所示:
> group_by(ToothGrowth,supp, dose)
# A tibble: 60 x 3
# Groups: supp, dose [6]
len supp dose
<dbl> <fct> <fct>
1 4.2 VC 0.5
2 11.5 VC 0.5
3 7.3 VC 0.5
4 5.8 VC 0.5
summarise_all()
按照group_by
的分组来做数据描述,比方说'mean','sd'等
另外summarise_all()
是对传入的dataframe所有的columns(除了用于group_by的columns)做summarise,如果有的columns中不是数值型数据,则会报错,不会跳过。
library(dplyr)
data(ToothGrowth)
summarise_all(group_by(ToothGrowth,supp,dose),'mean')
> summarise_all(group_by(ToothGrowth,supp,dose),'mean')
# A tibble: 6 x 3
# Groups: supp [?]
supp dose len
<fct> <fct> <dbl>
1 OJ 0.5 13.2
2 OJ 1 22.7
3 OJ 2 26.1
4 VC 0.5 7.98
5 VC 1 16.8
6 VC 2 26.1
只选某一列数据做group_by的summary, 则如下所示:
gb = group_by(ToothGrowth,supp,dose)
summarise(gb, len_mean = mean(len),len_sd = sd(len))
> summarise(gb, len_mean = mean(len),len_sd = sd(len))
# A tibble: 6 x 4
# Groups: supp [?]
supp dose len_mean len_sd
<fct> <fct> <dbl> <dbl>
1 OJ 0.5 13.2 4.46
2 OJ 1 22.7 3.91
3 OJ 2 26.1 2.66
4 VC 0.5 7.98 2.75
5 VC 1 16.8 2.52
6 VC 2 26.1 4.80
-
merge
Outer join: merge(x = df1, y = df2, by = "CustomerId", all = TRUE)
Left outer: merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE)
Right outer: merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)
Cross join: merge(x = df1, y = df2, by = NULL)
如果是根据rownames来merge, 则by = 0
另外参考dplyr的方法:http://stat545.com/bit001_dplyr-cheatsheet.html - 按colname删掉column
df = df[,-which(names(df) == 'colname')]
-
as.character()
和paste(collaps = )
> as.character(c(1,2,3))
[1] "1" "2" "3"
> paste(c('1','2','3'), collapse = '_')
[1] "1_2_3"
-
strsplit()
用来split string
> strsplit("tax_report_A1_22",'_')
[[1]]
[1] "tax" "report" "A1" "22"
-
vegan
包adonis()
做permanova出现负值R2
注意这里虽然没有报错,但是有个warning():
Warning message: In vegdist(lhs, method = method, ...) : results may be meaningless because data have negative entries in method “bray”
大概是因为permanova的input需要距离矩阵,默认是使用BC距离。但是有些数据可能并不适合使用BC距离。换成adonis( method = "euclidean")
就没有负值R2存在了。
这是一个报错的源码,虽然没看明白怎么肥四,但是anyway问题得到了解决。
┑( ̄Д  ̄)┍
> adonis(formula = qd_shap ~ BMI, data=qd_meta, permutations = 99)
Call:
adonis(formula = qd_shap ~ BMI, data = qd_meta, permutations = 99)
Permutation: free
Number of permutations: 99
Terms added sequentially (first to last)
Df SumsOfSqs MeanSqs F.Model R2 Pr(>F)
BMI 1 -35009042 -35009042 -74.954 -0.15646 0.81
Residuals 554 258759663 467075 1.15646
Total 555 223750621 1.00000
Warning message:
In vegdist(lhs, method = method, ...) :
results may be meaningless because data have negative entries in method “bray”
> adonis(formula = qd_shap ~ BMI, data=qd_meta, permutations = 99, method = 'euclidean')
Call:
adonis(formula = qd_shap ~ BMI, data = qd_meta, permutations = 99, method = "euclidean")
Permutation: free
Number of permutations: 99
Terms added sequentially (first to last)
Df SumsOfSqs MeanSqs F.Model R2 Pr(>F)
BMI 1 2.04 2.0430 1.4336 0.00258 0.17
Residuals 554 789.50 1.4251 0.99742
Total 555 791.54 1.00000
-
get()
在formula,循环等中需要用到变量,但是不能直接传递变量,可以使用get(变量名称)传递。
data(ToothGrowth)
adonis(len ~ supp, data = ToothGrowth)
a = 'supp'
adonis(len ~ get(a), data = ToothGrowth) # 与上结果一样
grep()
data(ToothGrowth)
ToothGrowth[grep('^V',ToothGrowth$supp),]
# 把ToothGrowth$supp中以V开头的行捞出来
- 在string中替换字符
一般来说:
gsub('plant',"animal","a room filled with plants")
[1] "a room filled with animals"
对于dataframe整列的操作,最好用stringi
包:
stri_replace_all(df[,'colname'], 'new_string', fixed='old string')
> head(ToothGrowth)
len supp dose
1 4.2 VC 0.5
2 11.5 VC 0.5
3 7.3 VC 0.5
4 5.8 VC 0.5
5 6.4 VC 0.5
6 10.0 VC 0.5
> ToothGrowth$new = stri_replace_all(ToothGrowth[,'supp'],'.cc',fixed = 'C')
> head(ToothGrowth)
len supp dose new
1 4.2 VC 0.5 V.cc
2 11.5 VC 0.5 V.cc
3 7.3 VC 0.5 V.cc
4 5.8 VC 0.5 V.cc
5 6.4 VC 0.5 V.cc
6 10.0 VC 0.5 V.cc
merge list of dataframes
reshape
包的merge_all()
merge_all(list_of_dfs,...)
韦恩图
library(gplots)
test = venn(list(g1=c('a','b','c','d'),
g2=c('a','b','c','e','f','h'),
g3=c('a','b','c','o','r','h')))
> test
num g1 g2 g3
000 0 0 0 0
001 2 0 0 1
010 2 0 1 0
011 1 0 1 1
100 1 1 0 0
101 0 1 0 1
110 0 1 1 0
111 3 1 1 1
attr(,"intersections")
attr(,"intersections")$g1
[1] "d"
attr(,"intersections")$g2
[1] "e" "f"
attr(,"intersections")$g3
[1] "o" "r"
attr(,"intersections")$`g2:g3`
[1] "h"
attr(,"intersections")$`g1:g2:g3`
[1] "a" "b" "c"
attr(,"class")
[1] "venn"
筛选df中列非零个数>100的列:
df[,colSums(df!=0) > 100]
RStudio: 在Global环境里删掉某个特定变量
选中,然后点小扫帚删掉。
一个已经导入的dataframe, 要把第一行设置为header
colnames(df) <- as.character(unlist(df[1,]))
df = df[-1, ]
在ATOM中运行R,出现:
no kernel for grammar R found
需要安装一个juypter R kernel, 在R studio或者R base里运行:
install.packages('IRkernel')
IRkernel::installspec()
见 https://github.com/IRkernel/IRkernel关掉科学计数法(scientific natation)
options(scipen = 999)
再打开:
options(scipen = 0)
或者:
format(xxx,scientific=F)
按照df2的col2来sort df1的col1
df1[order(match(df2[,'col2'], df1[,'col1']),]
capture.output()
用于获取某个代码print出来的Output替换dataframe中某个value
df[df == '0'] = 'F'
one hot encoding: R base,不安装其他包
head(iris_env$species)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
oh = model.matrix(~0+iris_env$Species)
attr(oh,'dimnames')[[2]] <- levels(iris_env$Species)
head(oh)
setosa versicolor virginica
1 1 0 0
2 1 0 0
3 1 0 0
4 1 0 0
5 1 0 0
6 1 0 0
:::
调用某个包里封装好的函数,比如
vegan:::do_goffactor
setdiff()
setdiff(c(1,2,3,'a','b'), c(1,2,3))
得到:c('a','b')
setdiff(c(1,2,3), c(1,2,3,'a','b'))
则什么都没有 numeric(0), 要注意顺序。output为前者有后者没有的elementsstrsplit()和paste()
strsplit('a_b_c.def',"[.]")[[1]]
得到:
c('a_b_c', 'def')
paste(c('a_b_c', 'def')), collapse='.'
又回来了。long to wide / wide to long
library(tidyr)
specie <- c(rep("sorgho" , 3) , rep("poacee" , 3) , rep("banana" , 3) , rep("triticum" , 3) )
condition <- rep(c("normal" , "stress" , "Nitrogen") , 4)
value <- abs(rnorm(12 , 0 , 15))
data <- data.frame(specie,condition,value)
# long to wide
test <- data %>%
tidyr::spread(.,condition,value)
# wide to long
melt(test,id.vars = 'specie')
参考这个连接
warning:
Coercing LHS to a list
在df$id = c(xxxxx,xxx,xxx)
时出现这个warning, 而且赋值多半没有成功。
要检查df到底是不是个dataframe, 如果df是个matrix可能出现这种warning,要先data.frame(df)named vector和list有什么差别?
不论是named vector还是vector,都只能存储一种类型,比方说以下的a
,其中45和TRUE都变成了string. 但是在list中,他们可以保持原有输入的变量类型。
a = c(t1 = 'a', t2 = True, t3 = 45)
a
t1 t2 t3
"a" "TRUE" "45"
b = list(t1 = 'a', t2 = True, t3 = 45)
$t1
[1] "a"
$t2
[1] TRUE
$t3
[1] 45