写论文的间隙换换脑子继续学习R4ds这本书。对R语言中的数据格式有了更加系统的认识。这一章值得反复多看几遍。
- 英文原版在线https://r4ds.had.co.nz/index.html
- 中文翻译版已有售,建议纸质版书籍随时翻翻。电子版网盘分享 https://pan.baidu.com/s/1fkpqYahQHPkwx66XD2gGGg 提取码: akct
- 最近才公布的课后习题参考答案https://jrnold.github.io/r4ds-exercise-solutions/
- Rstudio的一些便捷CheetSheetshttps://www.rstudio.com/resources/cheatsheets/
- 另外在写代码过程中Rstudio操作时的方便快捷键:赋值<-
Alt+“减号”
;管道符%>%Ctrl+Shift+M
十五章, 向量vectors
一. 向量概括
向量vectors包括两种:源自向量(atomic vectors)和列表(list)
- 原子向量 :包括6种:logical,numeric(integer, double), character, complex, raw。向量种的各个值都是同种类型的;
- 列表: 递归列表(recrusive list),
- 拓展向量:向量中任意添加额外的元数据。
二. 原子向量
逻辑型(logical)包括三种:TRUE, FALSE, NA
-
数值型(numeric):默认数值为双精度型double;
- 注意双精度型double是近似值(approximations),所有的双精度值都当做是近似值处理,表示浮点数(floating point)
- interger的特殊数据
NA
,double的特殊数据NA, NaN,Inf,-Inf
需要以is.finite()
等判断
字符串(character):可以包含任意数量的数据。
三. 原子向量的操作
- 强制转换:将一种原子强制转化为另一种;或者系统自动转化
- 显示型强制转化:
as.numeric
,as.character
等; - 隐式强制转化:联系上下文context自动转化,如logical———>numeric;
- 显示型强制转化:
x <- sample(x = 20,size = 100,replace = T)
y <- x>10
mean(y);sum(y)
检验是否为某一原子向量:利用purrr包中的函数
is_
:is_logical(), is_character
等标量与循环的规则:处理不同长度的向量会遵循 向量循环规则
向量命名:所有类型的向量都是可以命名的.向量完成后利用:
purrr::set_names(x,nm=c("q","w","e"))
命名。-
向量的取子集:
filter()
函数对tibble使用,对于向量的筛选则使用[]。- 整数型数值向量进行筛选:
x[c(1,2,2,4)]
,x[c(-1,-2,-3)]
- 使用逻辑向量取子集,提取出TRUE值对应的元素。可利用比较函数
- 对命名向量可用字符取子集
- x[] 代表选取x中的全部元素,对于矩阵十分重要
x[2,]
,x[,-3]
;特殊的,[[]] 代表只提取单个元素。明确表示需要提取单个元素时使用。对于矩阵/dataframe来说,x[,c(2)]返回的仍然是一个df(特殊的list),而x[[,2]]返回的才是真正的原子向量
- 整数型数值向量进行筛选:
四. 列表(递归向量recrusive vectors)
- 列表保存层级结构,树形结构。
str()
,重点关注列表的结构。 - 列表取子集 :
-
[]
提取子列表,返回的是一个子列表;可用逻辑向量,整数向量,字符向量提取。 - 使用
[[]]
从列表中提取单个元素,并非子列表。 - 直接使用
$
,作用相同于[[]]
。综合使用。x[[1]][[1]] - 注意于tibble之间使用的异同点,tibble[1], tibble[[1]]
-
a <- list(a=1:3,b="a string",c=pi,d=list(-1,-5))
a[c(1:2)]
a["a"]
a[["a"]][1:2]
五. 特性:
- 任何向量都可以通过其特性来附加任意元数据。
泛型函数:可以根据不同类型的输入而进行不同的操作。面向对象编程的关键。
六. 拓展向量:
利用基础的原子向量和列表构建出的另外一些重要的向量类型,称为拓展向量,其具有类的附加特性。
- 因子,表示有次序的分类数据
factor(c("ef","cd","ab"),levels=c("ab","cd","ef"))
- 日期和日期时间。
Charpter16_purrr
一. For循环
- 需为输出结果分配出足够的空间。对循环效率十分重要。
- 涉及的函数包括
vector("double",ncol(df))
,seq_along(df)
,[[]]
###16.2 for循环
require(tidyverse)
df <- tibble(a=rnorm(10),
b=rnorm(10),
c=rnorm(10),
d=rnorm(10))
output <- vector("double",ncol(df))
output
for (i in seq_along(df)) {
output[i] <- median(df[[i]])
}
output
### exercise Alice the Camel
humps <- c("five", "four","three","two","one","no")
for (i in humps) {
cat(str_c("Alice the camel has",rep(i,3),"horse",collapse = "\n"),"\n")
}
二. for循环的变体
-
修改现有对象:与自定义的函数function()一起使用。
- 注意再循环loop中,所有for循环使用的都是
[[]]
,明确表示是要处理单个元素。
- 注意再循环loop中,所有for循环使用的都是
-
循环模式:
- 通过对数值索引进行循环,再通过x[[i]]提取相应的值。
- 通过对元素element索引。
- 通过使用名称索引:
for (i in names(x))
,需要使用元素的名称时使用。
-
未知的输出长度。
- 应该将loop每次的结果保存再一个列表中,循环结束后再利用
unlist()
或者purrr::flatten_dbl()
组合成一个向量 - 当遇到类似的问题,如生成一个很长的字符串
paste(out,collapse="")
,或是个很大的数据框rbind_rows()。应首先使用一个更复杂的对象来保存每次迭代的结果,最后再一次性的组合起来。
- 应该将loop每次的结果保存再一个列表中,循环结束后再利用
means <- c(0,1,2)
output <- double()
for (i in seq_along(means)) {
n <- sample(100,1)
output <- c(output,rnorm(n,mean = means[[i]])) ### 十分不高效,这里会复制上一次的所有数据。
}
##高效法
out <- vector("list",length = length(means))
for (i in seq_along(means)){
n <- sample(100,1)
out[[i]] <- rnorm(n,mean = means[[i]])
}
unlist(out)
- 未知的输入序列长度。利用while循环来实现。
####exercises
# 1.读取文件,保存在大的数据框中
files <- dir(path = ".",pattern = "tsv$",full.names = F) ###匹配某一路径下所有的文件。
data_list <- vector("list",length = length(files))
for (i in seq_along(files)) {
data_list[[i]] <- read_delim(files[[i]],delim = "\t")
}
bind_rows(data_list)
#2.输出所有df中数值列的均值及名称show_mean(iris)
iris <- as_tibble(iris)
show_means <- function(df,digits=2){
maxstr <- max(str_length(names(df)))
for (i in names(df)) {
if (is.numeric(df[[i]])) {
cat(
str_c(str_pad(str_c(i,":"),maxstr+1L,side = "right"),
format(mean(df[[i]]),digits=2,nsmall=2),
sep=" "
),
sep = "\n"
)
}
}
}
三. for循环与函数式编程
- 函数式编程语言意味着可以先将for循环包装在函数中。即将函数名作为参数传入到另一个函数中
- 利用purrr函数,可以将复杂问题解决成子问题,然后再通过管道操作将这些问题的结果组合起来。
col_summary <- function(x,fun){
out <- vector("double",length(x))
for (i in seq_along(x)) {
out[[i]]=fun(x[[i]])
}
out
}
四. 映射函数 mapping function
purrr包函数map()
(返回的是列表),map_lgl()
,map_dbl()
,map_chr()
。map()第二个参数可以是公式,字符向量,整型向量,第三个参数为第二个函数中的附加参数。
- 快捷方式(shortcuts):对某个数据集中的每个分组都拟合一个线性模型。类似于factor中的一些功能。
-
map(df,function(xxx) length(unique(xxx))
——》map(df, ~ length(unique(.)))
因为需要一些更复杂的函数去实现一些功能
models <- mtcars %>%
split(.$cyl) %>%
map(function(df) lm(mpg ~ wt,data=df)) ## df是一个匿名函数,可任意命名。
- 在对列表中的各个子集内部进行筛选
out ###str(out)
map(out, ~ .[. > 0.8]) ###筛选每一列中大于0.8的数据。
- exercises中涉及的一些函数:
map(-2:2,rnorm, n=5)
,map(1:3,rnorm,mean=10)
.
五. 多参数映射mapping over multiple arguments
-
map2(), pmap()
对每一列的功能操作会涉及到多个参数时,就需要利用此函数。注意每次发生变化的参数放在函数功能的前面位置,值保持不变的参数放在函数的后面
mu <- list(5,10,-3)
map(mu, rnorm, n=5)
### map2 的应用
sigma <- list(1,5,10)
map2(mu,sigma,rnorm,n=5)
### pmap()应用,多个参数都未定,就将参数保存到大列表中
n <- list(3,5,8)
args <- list(n=n,sd=sigma,mean=mu)
pmap(args,rnorm)
多个参数 对于
pmap()
函数,可以将多个输入列表作为参数。且多个列表的长度一样**可以转换为tibble,确保每列都有名称,且与其它列具有相同的长度 **多个参数,且多个映射函数,利用
invoke_map()
函数。(invoke 调用)
六. 游走函数,预测函数,归纳与累计
- 游走函数walk,输出保存多个文件时非常实用。
walk(), pwalk
library(ggplot2)
plots <- mtcars %>% split(.$cyl) %>%
map( ~ ggplot(data = .,mapping = aes(mpg,wt))+geom_point())
path=stringi::stri_c(names(plots),".pdf")
pwalk(list(path,plots),ggsave,path=tempdir())
预测函数
keep(), discard()
函数可以保留输入中预测值为TRUE和FALSE的元素。some(), every()
分别用来确定预测值是否对某个元素为真。detect()
找出预测值为真的第一个元素,detect_index()
返回找到的元素的位置。归纳约简与累计 reduce/accumulate:复杂列表简化为一个简单列表。
vs <- list(c(1,2,3,4,5),
c(1,2,3,4),
c(1,2,3))
reduce(vs,intersect)
charpter21_ggplot2(graphics for communication)
- 标签labels:
labs()
-
title=""
主标题 -
subtitle=""
副标题,添加附加信息; -
caption= " "
描述数据来源 右下角添加信息 -
x=" ", y=" "
坐标轴信息 -
color= ""
图例中的标题 -
x= quote()
坐标轴上使用数学公式
-
library(ggplot2)
require(tidyverse)
ggplot(mpg,aes(displ,hwy))+geom_point(aes(color=class))+labs(title = "aaaaa",subtitle = "bbbbb",caption = "cccc ",x="HWY",y="DISPL")
- 注释Annotation:为单个或分组的观测值添加标签。
-
filter(row_number(desc(hwy))==1)
筛选每个组中hwy数值最高的观测observation。 geom_point() + geom_text(aes(label= ),data=)
- 利用ggrepel包可以自动调整注释标签的位置
geom_label_repel(aes(label=))
- 将标题加在图形里的右上角角落上
- 添加参考线
geom_hline()
,geom_vline(size=2,color=white)
- 感兴趣的点周围添加个矩形
geom_rect()
- 绘制箭头,指向关注的数据点
geom_segment()
-
library(ggplot2)
library(ggrepel)
best_in_class <- mpg %>% group_by(class) %>% filter(row_number(desc(hwy))==1)
ggplot(mpg,aes(displ,hwy))+geom_point(aes(color=class))+geom_text(mapping = aes(label=model),data = best_in_class)
### 利用ggrepel用较大的空心圆来强调
ggplot(mpg,aes(displ,hwy))+geom_point(aes(color=class))+geom_point(size=4,shape=1,data = best_in_class)+geom_label_repel(aes(label=model),data = best_in_class)
### 将标题加在图形里的右上角角落上。
label <- mpg %>% summarise(displ=max(displ),hwy=max(hwy),label="AAAA\nbbbbbbbb")
ggplot(mpg,aes(displ,hwy))+geom_point()+geom_text(aes(label=label),data = label,vjust="top",hjust="right")
- 标度scale:控制从数据值到图形属性的映射。scale_x(图形属性名称)_continuous()(连续型/离散型/时间/日期时间型)
- 调整坐标轴axis ticks: 刻度
scale_y_continuous(breaks=seq(1,40,by=5))
,坐标轴图例项目scale_y_continuous(labels=NULL)
- 图例legend:
theme(legend.position="none/right/left/top/bottom")
, 控制图例的显示guides(guide_legend()) - 标度替换:对标度进行数学转换。
- 颜色的转换:利用RColorBrewer/ggsci包,对于数量少的legend,可以添加形状映射。
- 调整坐标轴axis ticks: 刻度
ggplot(mpg,aes(displ,hwy))+geom_point(aes(color=class))+geom_smooth(se=F,color="darkgrey")+theme(legend.position = "bottom")+guides(color=guide_legend(nrow = 1,override.aes = list(size=4)))
library(ggsci)
library(RColorBrewer)
ggplot(mpg,aes(displ,hwy))+geom_point(aes(color=drv))+scale_color_brewer(palette = "Set1")
ggplot(mpg,aes(displ,hwy))+geom_point(aes(color=drv,shape=drv))+scale_color_aaas()
- 缩放,控制图形范围。
coord_cartesian()
函数设置xlim和ylim的参数值。 - 主题(themes):定制图形中的非数据元素。
theme_bw()
,theme_grey()(默认)
,theme_classic()
,theme_light()
- 保存图形
ggsave()