1.R语言基础知识

目录

一、R语言的介绍

R语言的下载与按照

Rstudio

R包的安装

工作空间管理

基本运算

二、R的数据结构

1. 数据类型

2. 数据类型的转换和判断

3.数据结构

三、导入/导出数据

获取内置数据集

获取其他格式的数据

四、数据框的常用操作

1.处理数据框的基本函数

2. 筛选行和列

3. arrange()排列行

4.添加新的变量

5. 拆分数据框

6. 数据框的合并

7. %>%的传递操作

8. 数据框长宽格式转换

9. 缺失值处理

10. 条件循环语句

11. 分割列数据和合并列数据

12. 字符串常用函数

13. 大型数据集的处理策略


一、R语言的介绍

R语言的下载与按照

R语言的下载网址:R: The R Project for Statistical Computing

建议下载最新版本,避免有些R包无法运行。 此外选择镜像下载,下载速度会快很多。

 国内的镜像比较多,所以可以根据自己的所在位置选择合适的镜像。因为笔者在北京,就选择了北大镜像下载。安装的话建议直接默认,点击下一步,装在C盘的位置。

Rstudio

Rstudio下载网站:Posit | The Open-Source Data Science Company

Rstudio界面介绍:

 1.脚本编辑器:这个区域主要是用来撰写代码,编辑器写的代码不会直接执行,并且可以保存成为.R格式的文件,保存既往的代码。可以直接打开,修改,运行。

2.控制台:是R的运算执行区域,可以直接写代码,但是由于不利于保存,较少在控制台写代码。二、控制台还可以显示运算的结果。

3.环境:该区域主要是存储目前的数据内容,包括任何数据格式

4.其他菜单栏:file默认是当前的工作路径,plot输出的图片结果展示,package是R中已经安装的R包。

R包的安装

R包:可以理解成为多个函数的打包存放,包含函数、数据、帮助文档、描述文档等

R包分为3类:1.基础包,在R启动的时候自动调入内存,以满足基础的数据处理和统计分析需要。2.备用包,随着R安装而安装,但是需要使用函数library()或require()调入内存后才能使用。3.捐赠包,由统计专家发布,用户需要单独下载,然后用函数library()或require()调入内存后才能使用。

1. 查看当前内存中调用的R包。

search() #目前工作状态下有哪些R包被加载
require("strings")#strings包是否安装,输出为逻辑值T或者F

2. R包的安装

包使用的顺序:安装——加载——调用函数

R包是否安装成功评价:library加载时是否会报错

方法一:install.packages("R包名称" )

install.packages("epiDisplay")
install.packages("BiocManager")

上面的命令安装了名为“epiDisplay”的包,凡是CRAN的R包,都统一使用install.package()

方法二:bioconductor中的R包,统一使用BiocManager::install()安装

BiocManager::install("limma")

因为在安装limma包时会同时安装一些其他包,如果这些包某些已经被安装,则会提示是否更新这些包?一般情况选择none,只需要在控制台回复n。

 方法三:github上的R包,使用devtools::install_github()

install.packages("devtools")#第一次需要先安装devtools包
devtools::install_github("jmzeng1314/idmap1")

发布在github上的包,需要在包的名字前面包含作者名字。

已经安装的包,可以用::快速调用里面的函数

!!!!!更新R包,重新安装,先删除后重新安装。建议不用update()

常见的报错:

  • 关键词connection,internet,url、404、http,download往往是网络限制,或者镜像没有选择合适
  • not writable/permission denied 权限问题:管理员方式重新打开Rstudio,重新安装
  • ????中文用户名惹的祸,修改环境变量
  • package not available 四种问题:1.包的名字拼写错误;2.命令用错;3.R包过时;4.版本不匹配
  • 是否更新,是否:先拒绝no,不可以在更新
  • 依赖包报错或者版本就,单独装依赖包/更新

3. 条件语句来安装R包

if(FALSE) 则后面的代码被跳过
if(TRUE) 则后面的代码执行

if(!require(strings))install.packages("strings")
if(!require(feather))install.packages("feather")

4. 其他R包知识(不重要)

  • 查看包中存在的函数:ls("package:stringr")

R包的如何使用:1、快速查看函数帮助文档?包的名字;2、浏览器搜索:R包名字 package,找到bioconductor官网的介绍;3、加载Vignettes,利用函数browseVignettes("stringr")
文件名称在代码中出现必然以字符串形式存在,并存在于实际参数的位置上

工作空间管理

        工作空间是R语言的工作环境,所有创建的对象都被临时保存在工作空间中,可以用函数ls()列出当前工作空间中的所有对象:

 也即是Rstudio中资源环境中的所有对象。在退出R时,如果选择保存工作空间,R将会在工作空间所在的文件夹中创建两个新的文件。之前在R中输入的任何命令都将保存到一个名为.Rhistory的文件中,而当前的工作空间中的所有对象将保存在.Rdata的文件中。两个文件都没有前缀

工作目录:是R用来读取文件和保存结果的一个文件夹。

getwd()能展示目前的工作目录。

setwd()设定当前的工作目录

getwd()

想要把当前的工作空间保存到一个指定的文件:

save("myfile.Rdata")

myfile.Rdata将会保存在当前的工作目录下。下次调用只需要直接load(“文件名.Rdata”)即可。

基本运算

二、R的数据结构

1. 数据类型

1.数值型 numeric 1,2,3
2.字符型 character “a",'mm'
3.逻辑值 logical TRUE;FALSE;NA
NA表示存在但未知,NULL表示不存在

class()判断数据类型的函数:

常见的错误

class(a)

输出为没有object:a,表示没有定义数据a是什么。

calss("a")

class写错

class(true)

系统默认的逻辑值TRUE,一旦改变任何一个大小写,都会被认为是对象object,因此输出为找不到对象true

class(3)

使用了中文括号

R语言常见的报错:

function在R中表示函数;object表示对象;TRUE必须大写,R中严格区分大小写;括号必须用英文,unexpected input in "class("表示问题出现在(这里
#unepected出现表示代码写错了;找不到对象往往是没有引号或者没有定义对象

2. 数据类型的转换和判断

#is.numeric() 是否是数值型                                                                                              #is.logical() 是否是逻辑型
#is.character() 是否是字符型
#as.numeric()  转化为数值型
#as.character() 转化为字符型
#as.logical() 转化为逻辑型

is.numeric(3)
is.numeric("4")
as.numeric("jimmy")
class(as.numeric("jimmy"))  #s说明NA这里是数值型

3.数据结构

数据结构: 向量;数据框;矩阵;列表

3.1 向量

用于存储数值型、字符型、逻辑型数据的一维数组。函数c()可以用来创建向量。每一个向量中数据的类型必须一致,仅为一种数据类型。

修改向量中的元素 ,R语言中任何修改都要赋值,没有赋值就没有发生过

3.1.1 向量的生成

方法一:用 c() 结合到一起

c(2,5,6,2,9) 
c("a","f","md","b")

方法二:连续的数字用冒号“:”

x <- 1:5

方法三:有重复的用rep(),有规律的序列用seq(),随机数用rnorm()

rep("x",times=3)  
seq(from=3,to=21,by=3)  #从3开始到21,每3个数取一个数
rnorm(n=3) #生成3个随机数

方法四:通过组合,产生更为复杂的向量

paste0(rep("x",times=3),1:3) 
#表示将向量1与向量2联合在一起,如向量1是xxx,向量2是1,2,3,组合在一起为X1,X2,X3

3.1.2 向量的计算

max(x) #最大值
min(x) #最小值
mean(x) #均值
median(x) #中位数
var(x) #方差
sd(x) #标准差
sum(x) #总和
scale(x) #将x标准化
range(x) #求x的全距
quantile(x) #求x的分位数
length(x) #长度 向量中元素的个数
unique(x) #去重复,向量从左到右第二次或多次出现的取值去除。
duplicated(x) #对应元素是否重复,判断值为逻辑值,如果需要将重复的值结果为FALSE,需要在前面加入!函数
table(x) #重复值统计,计算每个取值的重复个数
sort(x) #排序,默认从小到大
sort(x,decreasing = F)
sort(x,decreasing = T)

3.1.3 向量的比较

x = c(1,3,5,1)
y = c(3,2,5,6)

(1)比较运算,生成等长的逻辑向量,对应位置的数据进行比较

x == y 
y == x

不同长度的向量比较

x = c(1,3,5,6,2)
y = c(3,2,5)
x == y #循环补齐,输出结果为最长的元素个数逻辑值。

 利用循环补齐简化代码:

paste0(rep("x",3),1:3)
paste0("x",1:3)

(2)数学计算

x + y

(3)连接

paste(x,y,sep=",")   #paste表示将两个元素连接在一起,seq表示分隔

 paste与paste0的区别

paste(x,y)
paste0(x,y)  #paste0两个元素之间无缝连接,paste默认有空格连接,或者设置相应空格
paste(x,y,sep = "")
paste(x,y,sep = ",")

paste可以连接两个或者多个对象,输出为字符型结果:

paste(rep("student",time=3),4:6,rep("class",time=3),sep="a")
paste(rep("student",time=3),4:6,rep("class",time=3),sep=",")
paste(rep("student",time=3),4:6,rep("class",time=3))
paste0(rep("student",time=3),4:6,rep("class",time=3))

(4)向量之间的交集、并集、差集

intersect(x,y) #交集
union(x,y) #并集
setdiff(x,y)  #差集 在x中有y中没有的
setdiff(y,x) #差集 在y中有x中没有的
setequal(x,y) #判断两个向量是否相等,输出为逻辑值
x %in% y #x的每个元素在y中存在吗
y %in% x #y的每个元素在x中存在吗

(5)向量取子集

核心思想:[ ]将TRUE对应的值挑选出来,FALSE丢弃

x <- 8:12

根据逻辑值取子集,[ ]内为逻辑值相关的运算,括号内只能是逻辑值

x[x==10] #第一个x表示从什么向量中挑选,括号内为挑选的条件,需要与x等长的逻辑值
x[x<12]
x[x %in% c(9,13)]

根据位置取子集,只支持数据,不支持逻辑值

x[4]
x[2:4]
x[c(1,5)]
x[-4] #-4不选第四个,保留剩下的,-表示反选
x[-(2:4)]
x[1,5] #错误:因为不是一个向量,2:4是向量,c(1,5)也是向量,所以[]内必须是X的下标组成的向量

补充:元素的名字

scores = c(100,59,73,95,45)
names(scores) = c("jimmy","nicker","Damon","Sophie","tony") #元素的名字,本质还是向量
scores
scores["jimmy"]
scores[c("jimmy","nicker")]

names(scores)[scores>60]

虽然score是向量,但是可以给向量赋予名字,再去取子集。

3.2 矩阵

矩阵是一个由行和列组成的二维数组。矩阵中每个元素具有相同的模式(数值型、字符型或逻辑型)。函数matrix()常用于创建矩阵。nrow指定行数,并自动计算出列数。byrow默认为FALSE,即是按列将数值进行排列,如果需要按行进行排列,着byrow=TRUE。

m <- matrix(1:9, nrow = 3)  #ncol是列,只需要写一个,另一个就默认了
colnames(m) <- c("a","b","c") #加列名

3.2.1 矩阵取子集:矩阵取子集不支持$,$只能用于数据框格式

m
m[2,]  #不支持$的使用
m[,1]
m[2,3]
m[2:3,1:2]
m

3.2.2 矩阵转置:把矩阵的行和列变换

t(m)

3.2.3 矩阵乘法:运算符号为%*%,需要第一个矩阵的列数等于第二个矩阵的行数

mat1 <- matrix(1:6,nrow=3)
mat2 <- matrix(5:10,nrow=2)
dim(mat1)#计算矩阵的维度,也即是行和列数
dim(mat2)
mat1%*%mat2

得到一个3x3的矩阵

3.2.4 矩阵的行列式和逆矩阵,可以使用函数det()和solve()实现

mat3 <- matrix(1:4,nrow=2)
det(mat3) #方阵的行列式
solve(mat3) #逆矩阵

3.2.5 对矩阵行列进行计算

rowSums(mat1)#对矩阵行进行求和
colSums(mat2)#对矩阵列进行求和
rowMeans(mat1)#对矩阵行进行求均值
colMeans(mat2)#对矩阵列进行求均值

3.3 数组

数组是多维数组,与矩阵相似,但是维度大于2。数组有一个特殊的维度属性dim。一个向量,加上维度属性后定义了一个数组。

A <- 1:24
dim(A) <- c(3,4,2)#3行4列,两个维度
A

除此之外还可以使用函数array()创建

3.4 列表

可以由不同类型的对象混合组成。

l <- list(m1 = matrix(1:9, nrow = 3),
          m2 = matrix(2:9, nrow = 2))
l

l[[2]] #提取出的是一个矩阵,l[2]则提取出的是列表
l$m1

3.5 数据框(重点)

数据框是一个由行和列构成的二维结构,行表示观测或记录,列表示变量或指标。与矩阵不同的是,数据框的不同列可以是不同的数据类型。使用data.frame()创建。

df1 <- data.frame(gene   = paste0("gene",1:4),
                  change  = rep(c("up","down"),each = 2),
                  score   = c(5,3,-2,-4))
df1 #每一列是一个向量,列名=列的内容

3.5.1 数据框的属性

dim(df1)  #显示数据框的维度,几行几列
nrow(df1)  #行数
ncol(df1) #列数

rownames(df1)  #提取df1行名
colnames(df1)  #提取df1列名

3.5.2 数据框取子集

按$列名提取

df1$gene

按坐标

df1[2,2] #第2行,第2列
df1[2,] #第2行,所有列
df1[,2] #所有行,第2列
df1[c(1,3),1:2] #第1,3行,第1,2列

按名字

df1[,"gene"]
df1[,c('gene','change')] #$只能提取一列,这种麻烦的方式可以同时取出多列

按条件(逻辑值)

df1[df1$score>0,]
df1[df1$change=="up",] #up是字符型,必须打上引号,不然会报错

如何取数据框的最后一列?

df1[,3] #只能取第三列,如果数据框存在多列,则不能用3取最后一列
df1[,ncol(df1)] #当不知道数据框最后一列时,只能用ncol()取数据框的最后一列

如何取数据框除了最后一列以外的其他列?
 

df1[,-ncol(df1)]  #减号只能用在数字,感叹号用在逻辑值

筛选score > 0的基因

df1[df1$score > 0,1]
df1$gene[df1$score > 0]  ##取子集的逻辑值向量,只需要与x对应,不必由x产生

3.5.3 数据框的修改

值的修改:

#改一个格
df1[3,3] <- 5
df1
#改一整列
df1$score <- c(12,23,50,2)     
df1
#新增一列p value
df1$p.value <- c(0.01,0.02,0.07,0.05) 
df1

行列名称的修改:

#改行名和列名,本质就是修改向量
rownames(df1) <- c("r1","r2","r3","r4")
#只修改某一行/列的名
colnames(df1)[2] <- "CHANGE" #对列名取子集第二列出来,改为“CHANGE”

数据框的连接:

test1 <- data.frame(name = c('jimmy','nicker','Damon','Sophie'), 
                    blood_type = c("A","B","O","AB"))
test1
test2 <- data.frame(name = c('Damon','jimmy','nicker','tony'),
                    group = c("group1","group1","group2","group2"),
                    vision = c(4.2,4.3,4.9,4.5))
test2

test3 <- data.frame(NAME = c('Damon','jimmy','nicker','tony'),
                    weight = c(140,145,110,138))
test3
merge(test1,test2,by="name")
merge(test1,test3,by.x = "name",by.y = "NAME")  
#merge默认是交集,其他需要查看帮助菜单?merge

三、导入/导出数据

获取内置数据集

library(MASS)#载入R包
data(bacteria)#使用data函数调出数据集

获取其他格式的数据

CSV格式(本质是纯文本格式)的打开方式:1.excel打开;2.记事本打开;3.sublime;4.R语言读取:read.csv()

分隔符:逗号,空格,制表符(\t)

  • CSV:comma separated values逗号分隔文件;
  • TSV:Tab separated values Tab分隔值文件

表格文件读入R语言中,就得到一个数据框,对数据框进行修改不会同步到表格中

1. 导入数据

read.csv() 读取CSV格式文件
read.table() 读取txt格式文件                                                                                                             

(1)行名和列名的正确识别

ex1 <- read.table("ex1.txt") 
#R语言不能识别到列名,重新分配了列名V1-V5,会将数字转化为了字符型
ex1 <- read.table("ex1.txt",header = T)

当原始表格存在列名时需要设置参数header=T,让系统识别列名

(2)行列名中特殊符号的处理

ex2 <- read.csv("ex2.csv") #1.行名不能正确识别;2.列名将-改为了,;

 R语言中原始默认不存在特殊字符,就将-改为了.

ex2 <- read.csv("ex2.csv",row.names = 1,check.names = F) 
#row.name是一个行名向量,定义行名的名字;check.names=T会自动识别特殊字符并改为规范符号,F则默认

 (3)重复行名

rod <- read.csv("rod.csv",row.names = 1) #数据框不允许存在重复行名

系统会自动报错!!!

 (4)缺失值的处理

soft <- read.table("soft.txt") 

在第二行之后只存在四个值,第五列的值缺失,系统不能识别,因此不能读取

soft <- read.table("soft.txt",header = T,fill = T)

一般情况fill=T,默认将空格内容填充为NA,但是不能识别几个空格,可能出现串行没比如两个空格建,R语言就会认为只有一个空格,出现错误

soft <- read.table("soft.txt",header = T,sep = "\t")

制表符\t的设置表示一个制表符就是一个空格

 为了避免空格错位的问题:

read.delim()#读取txt文件,能避免上述问题
soft1 <- read.delim("sotf.txt")

其他格式:

read.xlsx( )读取Excel格式的文件,需要加载第三方包(例如openxlsx包,readx1包和gdata包);第二种方法将excel文件另存为csv格式,使用read.csv( )读取。

#如果没有安装请先安装
#install.packages("openxlsx")
#install.packages("readxl")
#install.packages("gdata")
library(openxlsx)
patients.data <- read.xlsx("patients.xlsx",sheet=1)
#sheet=表示读取的excel表格中第几个sheet

read.spss( )读取SPSS文件,read.xport( )读取SAS文件,read.dta( )读取Stata文件,但需要使用借助拓展包foreign包。foreign包主要功能读写其他格式的统计软件数据。

library(foreign)
patients.data <- read.spss("patients.sav",to.data.frame = TRUE)

To.data.frame参数的默认值为FALSE,如果不设置为TURE,返回的将是一个列表形式的数据。

2. 导出数据

数据框导出:

write.csv(test(数据框名称),file=“example.csv(输出的文件名称)”)
txt格式:write.table() eg:write(test,file="example.csv")

write.csv(soft,file="soft.csv")#一定要加后缀名.csv

Rdata格式:是R语言特有的数据储存形式,保存的是变量,不是表格
save()保存,load()加载;save(test,file="example.csv"),load("example.Rdata")

save(soft,file="soft.Rdata")#一定要加后缀名.Rdata
rm(list=ls())
load(file="soft.Rdata")

易犯错误:

save(soft,file="soft2.csv")

系统不报错,但是决定文件性质的是函数不是后缀。所以用excel/read.csv打开就是乱码,但可以使用Rdata语言打开,使用load函数。

3.  其他包导入/导出数据

(1)用rio包导入和导出数据

rio包提供一个类似于万能工具的包为目标,用统一的import()和export()函数简化用户导入和导出数据,此外convert()函数可以实现不同文件格式之间的转换。

以数据集infert为例:

data(infert)
library(rio)
export(infert,file="infert.csv")
#可以在工作目录下找到新生成的文件infert.csv的数据文件。
convert("infert.csv","infert.sav")
#将csv文件转换成为sav文件
infert.data <- import("infert.sav")
#将生成的infert.sav文件导入R中,命名为infert.data

import() 集成函数,根据文件的后缀选择相应的读取文件。
import_list()可以用来读取excel中存在多个工作簿的列表,输出形式为列表。

(2)其他包导入或导出文件

用于读取和导出文件的R包

  • #base包
  • #readr包
  • #data.table包
library(data.table) #不认识行名
a=fread("soft.txt") 

 因为不能识别行名,自动将行名设置为第一列

class(a) #存在data table的数据结构会影响后续分析

b=fread("soft.txt",data.table = F)#data.table=F能纯化为数据框结构
class(b)

参数data.table=F,可以将读取的文件直接设置为数据框格式,不用data.table格式。现在需要将数据框的第一列设置为行名。

rownames(b)=b[,1]#b第一列为行名
b=b[,-1]#第一列与行名重复,因此删除第一列名字。用-1表示删除第一列

四、数据框的常用操作

1.处理数据框的基本函数

加载数据集epiDisplay包中的Familydata

rm(list = ls())
#install.packages("epiDisplay")
library(epiDisplay)
data(Familydata)

1.1 查看数据框的前几行和后几行,head( )和tail( )函数。

head(Familydata,5)#不设置行数的话,默认为6行
tail(Familydata,3)

1.2 查看数据框变量名,names( )函数

names(Familydata)

1.3 数据框按照某个变量的值排序,order( )函数

Familydata[order(Familydata$age),]
Familydata[order(Familydata$age,decreasing = T),]
Familydata[order(-Familydata$age),]

本质跟取子集一样,按照age年龄大小进行排序,默认从小到大,如果想要从大到小增加参数decreasing=T。也可以使用age取相反数,在从小到大排序。

1.4 查找和删除重复数据

duplicated(Familydata$code)

duplicated( ) 函数用于查找是否有重复,第二次出现就会表示为重复,输出的值为逻辑值。因为输出的值比较时,难以肉眼检查是否存在重复值,可以使用函数table()统计FALSE和TRUE出现的频数,或any()用于检测逻辑值是否含有TRUE

any(duplicated(Familydata$code))
#结果为FALSE表示没有TRUE,没有重复值
table(duplicated(Familydata$code)) 
#输出的结果只有FASLE的频数,说明没有TRUE

删除重复数据

Familydata1 <- Familydata
Familydata1[12,] <- Familydata[2,]#给数据框增加一列重复的值
table(duplicated(Familydata1$code))#结果TRUE表示存在重复值

使用函数which( )可以找到变量code( )重复值所在的行

which(duplicated(Familydata1$code))

删除重复的行:利用取子集的思维,将子集中的TRUE提取出来,因此需要将不重复的FASLE转变为TRUE,重复值TRUE转为FALSE不提取出来。

Familydata2 <- Familydata1[!duplicated(Familydata1$code),]
identical(Familydata2,Familydata)#说明两个数据框一致

除了取子集外,函数distinct(数据框,去重的列,.keep_all=T)数据框按照某一列去重复,unique是去重复向量

distinct(Familydata1,code,.keep_all=T)

1.5 在数据框中删除和添加变量

使用$添加变量:

Familydata$log10money <- log10(Familydata$money)

使用函数transform()函数

Familydata <- transform(Familydata,log10money=log10(money))

使用取子集负号删除变量,负号不能用名称取。

Familydata <- Familydata[,-7]

1.6 把数据框添加到搜索路径

搜索路径的目的时因为在变量名称前面加上数据框名和符合$,这种方式有时候比较繁琐,一次函数attach可以将搜索的路径限定在数据框xxx中,直接输入变量名称即可。

函数attach( )可以将数据框添加到搜索路径中,detach()退出搜索路径。

attach(Familydata)
detach(Familydata)

2. 筛选行和列

案例:MASS包中birthwt数据集中包含189个研究对象,10个变量,一项关于新生儿低体重危险因素的病例对照研究。

2.1 筛选行:

library(dplyr)
data(birthwt,package = "MASS")

筛选变量年龄age大于35岁的所有记录:

#取子集的方法
birthwt[birthwt$age>35,]
#filter函数
filter(birthwt,age>35)

filter()函数,第一个参数是数据框名字,第二个参数级随后的参数是筛选数据框的表达式。

筛选体重大于4000g或小于2500的所有记录

filter(birthwt,bwt>4000|bwt<2500)
birthwt[birthwt$bwt>4000|birthwt$bwt<2500,]

如果有多个条件,可以用逗号隔开,例如筛选体重大于4000g或小于2500,年龄age大于35岁的所有记录

birthwt[(birthwt$bwt>4000|birthwt$bwt<2500)&birthwt$age>35,]
filter(birthwt,bwt>4000|bwt<2500,age>35)

函数slice()可以按照行号选择指定的行,第二行到第五行的所有记录

slice(birthwt,2:5)

2.2 选择列

函数select()用于选择数据框中的列(变量)

select(birthwt,age,bwt,race,smoke)

注意:MASS包中也有函数select,为了避免混淆如果需要同时加载两个包,可以使用dplyr::select()的格式完成。

3. arrange()排列行

除了基础包中的order之外,arrange函数也是可以将数据框记录按照某个变量进行排序的。

arrange(birthwt,bwt)
birthwt[order(birthwt$bwt),]

将变量bwt从小到大进行排序。如果需要从大到小排序,order的参数descreasing=T,arrange()函数的可以使用desc()函数实现或相反数。

birthwt[order(birthwt$bwt,decreasing = T),]
arrange(birthwt,-bwt)
arrange(birthwt,desc(bwt))

当存在多个变量的排序时,按照顺序一次添加即可,首先排序的变量放在第一个,然后第二个

arrange(birthwt,bwt,age)

先按bwt从小到大排序,存在重复相同数字时,按照age年龄进行从小到大排序。

4.添加新的变量

除了基础方法中的$和transform之外,还可以使用函数mutate()。第一个参数就是数据框名称,第二个参数为定义的数据内容,类似于transform函数。

mutate(birthwt,lwt.kg=lwt*0.4536)
transform(birthwt,lwt.kg=lwt*0.4536)

5. 拆分数据框

函数group_by( )可以将数据框按照某一个或某几个分类变量拆分成为多个数据框。

输出的数据框虽然外观没有改变,但是已经按照race的三个值分为三个数据框,在进行dplyr包的后续计算会产生三个不同的值,比如:

summarise(group_by(birthwt,race),mean.bwt=mean(bwt),sd.bwt=sd(bwt))

按照race分类变量,计算各组中的出生体重的平均值和标准差。

summarise()函数可以用于计算数据框某个变量的指定统计量

格式:summarise(数据框,生成统计量名称=统计函数(变量))如果有多个可以用逗号隔开。

tibble是tidyberse系列包(dplyr包)提供的一种类似于数据框的格式。

6. 数据框的合并

1. 按照某个共有变量合并

数据框的连接除了merge()函数默认取交集外,还可以使用dplyr包中的jion()函数。

test1 <- data.frame(name = c('jimmy','nicker','Damon','Sophie'), 
                    blood_type = c("A","B","O","AB"))
test1
test2 <- data.frame(name = c('Damon','jimmy','nicker','tony'),
                    group = c("group1","group1","group2","group2"),
                    vision = c(4.2,4.3,4.9,4.5))
test2

  • inner_join( ) 取交集
  • right_join()右连接
  • left_join ()左连接
  • full_join ()全保留
  • semi_join ()半连接:一个表根据另一个表取子集,类似于交集,但是输出的数据框只有第一个数据框的变量,不是两个数据框的全部变量
  • anti_join ()反连接:根据一个表对另一个表中没有的对象取子集
library(dplyr)
inner_join(test1,test2,by="name")
right_join(test1,test2,by="name")
left_join(test1,test2,by="name")
full_join(test1,test2,by="name")
semi_join(test1,test2,by="name")
anti_join(test1,test2,by="name")

 注意两者的区别!

2. 纵向合并

要纵向合并两个数据框可以使用rbind()函数。前提:两个被合并的数据框必须拥有相同的变量,通常用于合并数据框中的观测。

data1 <- data.frame(id=1:5,
                    sex=c(0,1,1,0,1),
                    age=c(32,46,25,42,29))
data2 <- data.frame(id=6:10,
                    sex=c(1,0,1,1,0),
                    age=c(52,36,28,34,26))
rbind(data1,data2)

                                     

3. 横向合并

横向合并两个数据框,可以使用cbind()函数,前提:用于合并两个数据框必须拥有相同的行数。

data3 <- data.frame(days=c(28,57,15,7,19),
                    outcome=c("discharge","dead","discharge","dead","dead"))
cbind(data1,data3)

                              

7. %>%的传递操作

library(dplyr)
x1=filter(iris,iris$Sepal.Width>3) #筛选行
x2=select(x1,Sepal.Length,Sepal.Width) #筛选列
x3=arrange(x2,Sepal.Length) #从小到大排序
x4=arrange(x2,desc(Sepal.Length)) #从大到小排序

多次赋值,产生多个变量,x2和x1是中间变量,没有用容易让数据表格更加繁琐。

x=iris %>% 
  filter(Sepal.Width>3) %>%
  select(Sepal.Length,Sepal.Width) %>%
  arrange(Sepal.Length)

8. 数据框长宽格式转换

长格式:每次观测作为一条记录,所以一个观测对象可能占有多行。

宽格式:一个对象的多个不同时间点的观测都记录在同一行里,即是一个观测对象只占一行。

案例:以数据集Indometh,该数据集关于药物吲哚美辛的药物代谢动力学数据,一共6个试验对象,每名对象在连续8小时内定时测试血液中的药物浓度,一共测定了11次的值

这是一个典型的长数据格式,一个观测对象具有不同时间测试结果。

方法一:基础包中reshape()函数

#长数据转为宽数据
wide <- reshape(Indometh,
                v.names = "conc", #结果变量的值
                idvar = "Subject", #观测对象的id
                timevar = "time", #时间变量/也即是多次测量的变量
                direction = "wide")

#宽数据转为长数据
long <- reshape(wide,
                idvar = "Subject", #观测对象的id
                varying = list(2:12), #需要合并的列
                v.names = "conc", #合并后值得名称
                direction = "long")

time不能识别出具体的时间,只能以1,2,3这样进行分组。

方法二:tidyr包中pivot_wider()函数用于长格式转为宽格式,pivot_longer()用于把宽格式转换为长格式

library(tidyr)
wide <- pivot_wider(as.data.frame(Indometh),
                    names_from = time, #分组名称
                    values_from = conc) #变量值
wide

因为Indometh不是数据框格式,所以需要将转化为数据框格式,如果是数据框格式,直接输入数据名称。

long <- pivot_longer(wide,-Subject, #-观测ID名称
                     names_to = "time",#合并后的组名
                     values_to="conc") #变量值组的名称

一个整洁的数据集应该满足:每一行为一个观测,每一列代表一个变量。在对医学数据进行分析之前,通常情况下应先把数据集转换为长格式。

9. 缺失值处理

9.1 识别缺失值

判断是否是缺失值NA,is.na( )函数,当数量较多时,需要用table函数统计频数便于找到NA。

height <- c(100,150,NA,160)
is.na(height)
table(is.na(height))

 注意:任何包含NA的计算结果都是NA,如果需要计算统计量,需要将NA移除,一种方法是设置参数na.rm=T,一种是使用函数na.omit()把缺失值省略。

比如计算某变量的平均值

mean(height)
mean(height,na.rm = T)
mean(na.omit(height))

 函数summary()在计算向量的统计量时,会自动忽略缺失值,同时显示出缺失值的个数

summary(height)

9.2 探索数据框中的缺失值

案例:数据集iris,包含了150个鸢尾花样品,分为3个品种(species),每个品种各有50个样品,每个样品的四种属性,即花萼长度(Sepal.Length)、花萼宽度(Sepal.Width)、花瓣长度(Patal.Length)和花瓣宽度(Patal.Width)。数据集不含缺失值,missForest包中的prodNA随机生成缺失值。

#install.packages("missForest")
library(missForest)
set.seed(1234)  #设置随机数种子
iris.miss <-prodNA(iris) #默认生成数据10%的随机缺失值
summary(iris.miss)

 9.3 缺失值的处理

处理缺失值可以采用3种方法:1.删除,删除带有缺失值的变量或记录;2.替换,用均值、中位数、众数或其他值替代缺失值;3.补全,基于统计模型推测和补充缺失值。

删除:当缺失值的数量比较少,删除后对分析结果影响不大,可以使用函数na.omit()删除数据框中的缺失值。

#方法一:
iris.sub <- na.omit(iris.miss)
nrow(iris.sub)
#方法二:
iris.sub <- iris.miss[complete.cases(iris.miss),]

结果输出为97,也即是只有97列是完整的记录。complete.cases表示如果数据框种有一行有一个缺失值就输出FALSE,完整数据输出为TRUE,通过取子集的方法把TRUE提出出来,也即是完整数据。

使用特定数值替代缺失值:

以变量Spetal.Length为例,用忽略缺失值后的均值替代缺失值

Sepal.Length.Mean <- mean(iris.miss$Sepal.Length,na.rm = T)
Sepal.Length.Mean
iris.miss1 <- iris.miss#便于后面仍然可以使用iris.miss作为案例
iris.miss1$Sepal.Length[is.na(iris.miss1$Sepal.Length)] <- Sepal.Length.Mean
#提取出向量中缺失值,将其赋值给均值

多重插补:是一种基于重复模拟的处理缺失值的方法,常用于处理较为复杂的缺失值问题。R中有多个可以实现缺失值多重插补的包,Amelia包,mice包,mi包。

其中mice包使用链式方程的多变量补全法,被广泛用于数据清洗的过程。常用的方法有:(1)预测均值匹配(pmm)实质上就是线性回归,适用于数值型变量;(2)Logistic回归(logreg):适用于二分类变量;(3)多分类Logistic回归(ployreg),适用于无序多分类变量;(4)比例优势比模型(polr),适用于有序多分类变量。

#install.packages("mice")
library(mice)
imputed.data <- mice(iris.miss,seed=1234)
summary(imputed.data)

 在predictorMatrix中每一行代表含有缺失值的变量,如果该行对应的列元素为1,则代表该列变量被用于建模预测。mice输出的结果是一个列表,其中imp也是一个列表,存放着每个变量缺失值的插补值。

imputed.data$imp$Sepal.Length

 函数mice()默认进行5次随机抽样,得到的5次随机抽样的插补值。可以选择其中一组来进行插补。

complete.data <- complete(imputed.data,3)
complete.data

函数complete( )表示提取补全的数据,使用第三组数据补全缺失值。

10. 条件循环语句

10.1 条件语句

条件语句基本结构:

if(是一个逻辑值,不可是多个逻辑值组合成的向量){CODE1}else{CODE2}

if()里面的逻辑值是TRUE,后面大括号内的语句就会被执行,否则反正

i=-1
if(i<0){print("up")} #i=-1<0则为TURE,这运行print “up“
if(i>0){print("up")}
i=9
if(i<0){print("UP")}else{print("down")}

 ifelse()#具有三个重要参数:x逻辑值,yes逻辑值为TRUE时返回的值,no逻辑值为FALSE时返回的值

ifelse(i>0,"+","-")#如果i>0则输出+,否则输出-
x=rnorm(3)
ifelse(x>0,"+","-")
if(x>0{print("+")}else{print("-")})#报错

if只支持单个逻辑值,不支持逻辑值向量;ifelse既支持单个逻辑值,也支持多个逻辑值组合成为向量

非常重要的组合操作

ifelse()+str_detect(),王炸,可以实现分组

library(stringr)
samples = c("tumor1","tumor2","tumor3","normal1","normal2","normal3")
k1 = str_detect(samples,"tumor");k1 #逻辑值向量
ifelse(k1,"tumor","normal")
k2 = str_detect(samples,"normal");k2 #逻辑值向量
ifelse(k2,"normal","tumor")

如果有多个条件就逐一嵌套:

i = 0
if (i>0){
  print('+')
} else if (i==0) {
  print('0')
} else if (i< 0){
  print('-')
}

ifelse(i>0,"+",ifelse(i<0,"-","0"))

10.2 循环语句

10.2.1 For循环

模板:for(i in x){code}

x <- c(5,6,0,3)
s=0
for (i in x){
  s=s+i
  print(c(i,s))
}

 循环的保存:

s = 0
result = list()
for(i in 1:length(x)){
  s=s+x[[i]]
  result[[i]] = c(x[[i]],s)
}
result
do.call(cbind,result)#把result的结果按列拼接
do.call(rbind,result) #按行拼接

 

10.2.2 下标循环

x <- c(5,6,0,3)
s = 0
for (i in 1:length(x)){ #length(x)表示x的长度,i表示下标,1,2,3,4
  s=s+x[[i]] #直接用两个中括号,没有理由
  print(c(x[[i]],s))
}

11. 分割列数据和合并列数据

函数separate()将数据的一列分割为多列。

生信数据常用一些分隔符,比如chr1:pos1-pos2

method <- data.frame(coord=c("chr8:11666485-11666694","chr12:123215010-123215553","chr20:36148133-36149750")) %>%
separate(col=coord, #要分割的列
         into=c("chr","pos"), #分割成几列就写几列名字
         sep=":") #列的分隔符是什么
method

                                    

                 分割前                                                                     分割后

注意:%>%必须有不然,会报错

函数unite()将数据的多列分割为一列

iris %>%
  unite(col = "new col", #需要合成的列名
        Petal.Width:Species, #需要合成的列
        sep = "//") #分隔符符号

 

 

12. 字符串常用函数

  • str_length( ) 字符串长度
  • str_split( ) 字符串拆分
  • str_sub( ) 按位置提取字符
  • str_detect( ) 字符检测
  • str_replace/str_replace_all( ) 字符替换
  • str_remove/str_remove_all( ) 字符删除
x="my name is jimmy"
str_length(x) 
#str_length是计算字符串长度,包括空格,所以输出结果为16
length(x) 
#输出结果为1,因为x在引号内作为一个值

str_split(x," ")
#输出的结果为一个列表格式,需要用取子集的方式将字符串单独保存成一个向量
x2=str_split(x," ")[[1]];x2
x2[2]

当需要将拆分的字符串组合成一个表格

y=c("jimmy 150","Tom 148","Tina 146")
str_split(y," ")
str_split(y," ",simplify = T) #组合形成矩阵

                           

str_sub(x,4,8) #提取x中第4个到第8个字符

 

str_detect(x2,"y") #分别检测字符中是否含有y字母
#前面已经将x拆分成了多个字符串,并组合成为向量
str_starts(x2,"n")#以n开头
str_ends(x2,"e")#以e结尾

x2
str_replace(x2,"m","n") #只替换每一个字符串第一个检测到的字符
str_replace_all(x2,"m","n") #替换所有字符

x
str_remove(x," ")
str_remove_all(x," ")

13. 大型数据集的处理策略

13.1 清理工作空间

在启动任何新的分析项目时,首先清空工作空间,前提需要的内容保存成.Rdata

rm(list=ls())
rm(list=ls(all=T))

ls( )用于显示当前工作空间中的对象,all=T是为了清理包括隐藏对象在内的所有对象,默认值all=FALSE。

13.2 快速读取csv文件

read.csv在读取大型数据集时速度较慢,有时会报错,可以使用readr包中read_csv( )函数或者data.table包中的fread( )函数读取数据

13.3 剔除不需要的变量

bigdata <- as.data.frame(matrix(rnorm(5000*200),ncol=200))
varnames <- NULL
for (i in letters[1:20]) {
  for (j in 1:10) {
    varnames <- c(varnames,paste(i,j,sep = "_"))
    
  }
  
}
names(bigdata) <- varnames
names(bigdata)

创建了一个200个变量,5000个观测对象的数据集。利用两个for循环和R内置的字母数据设置变量名称。

在正式分析之前需要将用不上的变量暂时剔除,减少内存负担。

剔除的方法:联合dplyr包中的select( )函数和tidyselect包中的starts_with( )、end_with( )、contains( )等函数。

选择以a开头的变量:

subdata1 <- select(bigdata,starts_with("a"))

选择以2结尾的变量:

subdatda2 <- select(bigdata,ends_with("2"))

多个筛选条件时,可以使用函数vars()包括多个条件,select_at()筛选

subdata3 <- select_at(bigdata,vars(starts_with("a"),starts_with("b")))

选择变量中包含1的变量

subdata4 <- select(bigdata,contains("1"))
subdata4 <- select_at(bigdata,vars(contains("1")))

剔除以a开头的变量,2结尾的变量,包含1的变量

subdata5 <- select(bigdata,-starts_with("a"))
subdata5 <- select(bigdata,-ends_with("2"))
subdata5 <- select_at(bigdata,vars(-starts_with("a"),-starts_with("b")))
subdata5 <- select_at(bigdata,vars(-contains("1")))

 

13.4 选取数据集的一个随机样本

对大型数据集的全部记录进行处理往往会降低分析效率,在编写代码时,可以只抽取一部分记录对程序进行测试,以便优化代码并消除bug。

sampledata1 <- sample_n(subdata5,size = 500)
sampledata2 <- sample_frac(subdata5,size = 0.02)

函数sample_n()和sample_frac( )都用于从数据框中随机选取指定数量的行,前者中参数size用于指定行的个数,后者中的参数size用于指定所占行的比例。比如第一个表示,选取其中500例样本,第二个则表示选择其中2%的样本。

  • 8
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值