R语言到底可以用来做什么?
在生物信息学领域,大数据、机器学习等方向,和Python一比,我感觉已经相形见绌,
所以为什么还要学习R语言?
1)ggplot2的绘图体系非常完美
2)R base能够完成我日常小数据的分析
有很多人说,tidyverse
给了R二次生命,但是在我看来它的编程思维,稍显奇怪,不太能够适应,
但是我属于一个钻牛角尖的人,既然学了,而且R我也没有完全丢掉,也是有一定必要学习一些重获新生的R语言。
因此这篇文章就是针对我在最近的R语言刷题中的总结。
数据读入 / 写出
从R base的角度看问题
read.table()
read.csv()
write.table()
write.csv()
从readr
的角度看问题
read_csv()
read_delim()
read_table()
write_delim(df, 'filename.csv')
write_csv(df, 'filename.csv')
write_excel_csv(df, 'filename.csv')
write_tsv(df, 'filename.csv')
data.frame
从R base的角度看问题
如何随心所欲的操作data.frame
?
使用data.frame()
创建数据库,
1)给定colname
,再给定该变量对应的element(一般是vector格式),即
<center>colname=c(elements)</center>
2)依此类推,增添每一列
# 1. 数据框的创建
df <- data.frame(
"grammer" = c("Python","C","Java","GO",NA,"SQL","PHP","Python"),
"score" = c(1,2,NA,4,5,6,7,10)
)
从tidyr
的角度看问题
library(tidyr)
df <- tibble(
"grammer" = c("Python","C","Java","GO",NA,"SQL","PHP","Python"),
"score" = c(1,2,NA,4,5,6,7,10)
)
# # A tibble: 8 x 2
# grammer score
# <chr> <dbl>
# 1 Python 1
# 2 C 2
# 3 Java NA
# 4 GO 4
# 5 NA 5
# 6 SQL 6
# 7 PHP 7
# 8 Python 10
dplyr
的衔接
dplyr
提供了一系列用C++重新编写过的函数,能够加快我们处理数据的速度。
主要包含的函数如下,
select()
filter()
mutate()
group_by()
arrange()
1)数据框列名的重新命名:names()
, colnames()
, rename()
R base对列名进行修改的话,使用如下格式,
# R base
names(df)[2] <- c('popularity')
# dplyr
df <- df %>% rename(popularity = score)
2)数据过滤:which()
, filter()
# R base
df[which(df$popularity > 3), ]
# dplyr
df %>%
filter(popularity > 3)
# 按照范围也是一样的,
df %>%
filter(popularity > 3 & popularity <7)
3)选择某一列数据:$
, select()
# R base
df$popularity
# dplyr
df <- df %>%
select(popularity, everything())
Note:
tidyverse::everything()
的作用,为选择数据框中的所有变量。与
select()
函数一起使用,可以改变数据框中变量的排列顺序(e.g. 将变量A从变量B后移动到变量B前),以iris数据集为例,select(iris, everything()) # A tibble: 150 x 5 # Sepal.Length Sepal.Width Petal.Length Petal.Width Species # <dbl> <dbl> <dbl> <dbl> <fct> # 1 5.1 3.5 1.4 0.2 setosa select(iris, Species, everything()) # # A tibble: 150 x 5 # Species Sepal.Length Sepal.Width Petal.Length Petal.Width # <fct> <dbl> <dbl> <dbl> <dbl> # 1 setosa 5.1 3.5 1.4 0.2
可以看到
Species
被提前了。
4)将一行/多行数据添加到数据框中:rbind()
row <- data.frame(
"grammer" = c("Perl"),
"popularity" = c(6.6)
)
df <- rbind(df, row)
5)分组:aggregate()
, group_by
- R base:
aggregate()
- dplyr:
group_by
+summarise
# R base
# 使用aggregate对df进行分组计算
library(flipAPI)
data = DownloadXLSX("https://wiki.q-researchsoftware.com/images/1/1b/Aggregation_data.xlsx", want.row.names = FALSE, want.data.frame = TRUE)
data.agg = aggregate(df,
by = list(data$Role),
FUN = mean)
# dplyr
# 使用group_by()分组,并进行相关计算
library(readr)
df <- read_csv('pandas120.csv')
df %>%
group_by(education) %>% # 设置用于分组的变量,此处为education
summarise(mean = mean(salary))
6)构建新的一列变量:mutate()
# R base
# 使用cbind()函数
# dplyr
df <- df %>%
mutate(test = paste0(df$education, df$createTime))
Note:
paste0
,先将变量转换为字符类型
7)将某一列的设置为索引:rownames()
, column_to_rownames()
# R base
rownames(df) <- df$createTime
# dplyr
# 使用column_to_rownames,该函数将某一列设置为行名后得到
df %>%
tibble::column_to_rownames('createTime')
8)数据排序
# R base
# sort(): 返回的是排序后的结果
# order()
df <- df[order(df$popularity), ]
# dplyr
# 使用arrange()
df <- df %>%
arrange(popularity)
df <- df %>%
arrange(desc(popularity))
9)数据的总结:summary()
, summarize()
略
与data.frame
有关的实例
1)填补NA
1)使用R包Hmisc
中的impute()
函数
2)<u>使用impute函数的一般模式</u>,一为输入的向量,二为如何填充NA值所定义的<font color='yellow'>FUN</font>
Note:下列代码中的
unlist
,只是为了安全作用
library(Hmisc)
index <- which(is.na(df$popularity))
df$popularity <- impute(df$popularity,
(unlist(df[index-1, 2] +
df[index+1, 2]))/2)
2)将宽数据转换为长数据
使用tidyr
中的pivot_longer()
函数,
一般的使用模式如下,
pivot_longer(data,
cols, names_to = "name", # cols,定义一个vector用于选择df中的列并进行合并
values_to = "value", # 每一行对应的元素
values_drop_na = FALSE)
举个例子,
library(tidyr)
df %>%
select(日期,`开盘价(元)`,`收盘价(元)`) %>%
pivot_longer(c(`开盘价(元)`,`收盘价(元)`),
names_to='type',values_to='price') %>%
ggplot(aes(日期,price,color=type)) +
geom_line(size=1.2) +
scale_color_manual(values=c('steelblue','orange')) +
theme_bw() +
theme(
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
legend.title = element_blank(),
legend.position = c(0.86, 0.9)
)
3)读入数据的测试
假设现在有一个非常大的数据集,但是可以用read.csv
等函数进行读入,然后后续用到的数据实际上只占了df的2列,
1)如何找到这两列?
2)如何在后续的分析中只读取到这两列?
res <- read.csv('数据1.csv',encoding = 'GBK',nrows = 3) # 测试读入3行数据
# 获取每一列的数据类型(e.g. integer、character)
classes <- sapply(res, class)
classes[-match(c('positionName','salary'), names(classes))] <-
rep('NULL', length(classes) - 2) # 保留只想要选择的列
df <- read.csv('数据1.csv', encoding = 'GBK', nrows = 10,
colClasses = classes) # 使用"colClasses="指定列
代码的解读,
1)测试读入数据,即读取3行
2)使用sapply
获取每一列的数据类型
3)去除不想要的列的数值类型,即 ->None
4)重新使用read.csv(, colClasses=)
,对目的数据进行读取
4)使用sapply()
创建一个数据框
df1 <- sapply(20, function(n){
replicate(n, sample(1:100, 1))
}) %>%
as.data.frame(.) %>%
dplyr::rename(`0` = V1)
R tips
str()
:查看对象每一个子对象的类型
R中有非常多的对象,比如
- data.frame中的每一个变量都是一个子对象,
- 列表中的每一个
$
,均为一个子对象
str(df)
# 'data.frame': 8 obs. of 2 variables:
# $ grammer: Factor w/ 6 levels "C","GO","Java",..: 5 1 3 2 NA 6 4 5
# $ score : num 1 2 NA 4 5 6 7 10
.
:既是占位符,也是通配符
.
在一些情况下,可以充当占位符,比如下列代码的含义为过滤掉salary
小于10000的行,且查看过滤后的数据的行数,
Note:可以类比为Shell中的
-
df <- read_csv('pandas120.csv')
df %>%
filter(salary > 10000) %>%
dim(.) %>%
.[1]
.
的另一种含义为通配符,但是在此处不做过多赘述。
"["
:索引的另一种方式
直接举例说明,
"["(c(123, 12, 3), 1)
# 123
"["(c(123, 12, 3), 2)
# 12
基于glue
的格式化输出
1)使用R包glue
(集合于tidyverse
中),即可以直接理解为C、Pytohn中的格式化输出(e.g. sprintf
)
2)paste(, collapse=)
-> .join()
# library(readr)
# df <- read_csv('600000.SH.csv')
library(glue)
for (i in names(df)){
if(sum(is.na(df[,'日期'])) != 0){
res1 <- which(is.na(df[,i]))
res2 <- paste(res1, collapse = ',')
print(glue('列名:"{i}", 第[{res2}]行有缺失值'))
}
}
参考资料
[1] R语言数据处理120题