1 R Markdown

什么是R Markdown?

  • .Rmd文件:在单个文档中同时阐述你的代码和想法。将代码作为单独的块或整个文档运行。

  • 动态文档:将图、表格和结果与叙述性文本结合在一起。渲染为多种格式,如 HTML、PDF、Word 或 PowerPoint。

  • 可重复的研究:上传、分享你的报告。任何人都可以阅读或运行你的代码来重现你的工作。

整体的Workflow是怎样的?

  • 通过“文件”>“新建文件”>“R Markdown”,在 RStudio 中打开一个新的 .Rmd 文件。

  • 将代码嵌入块中。按行、按块或一次全部运行代码。

  • 编写文本并添加表格、图形、图像等元素。使用 Markdown 语法或 RStudio Visual Markdown 编辑器进行格式化。

  • 在 YAML 元数据中设置输出格式,自定义主题或添加参数。

  • 保存并渲染整个文档。定期编织以在写作时实时预览你的作品。

  • 分享你的作品!

R Markdown备忘录可见网站 rmarkdown :: Cheatsheet,其中全面的介绍了rmarkdown包的具体用法。

R Markdown三元素:元数据文本代码

1.1 元数据(Metadata)

元数据写在一对三个破折号之间。 元数据的语法是YAML(YAML Ain’t Markup Language),所以有时也称为YAML元数据。

在文档的YAML区域设置输出格式,并使用输出选项对其进行自定义。一个简单的例子:

---
title: "Hello R Markdown"
author: "Me"
date: "2018-02-14"
output: html_document
---

每种输出格式通常都带有格式选项,这些选项都记录在 R 包帮助页面上。 例如,你可以在R中输入 ?html_document 来打开 html_document 格式的帮助页面,从中可以看到 html_document 格式文档可以设置的所有参数。

注意!YAML中的缩进很重要,在设置各种选项时一定要注意控制缩进。

例如,本文档的元数据:

---
title: "R与R Markdown"
date: "最后编译于09/11/2024"
output:
  html_document:
    toc: TRUE
    toc_float:
      collapsed: TRUE
      smooth_scroll: TRUE
    number_sections: TRUE
---
本文件的html_document选项及功能
选项 作用
toc: TRUE 在输出中包含目录
toc_float: TRUE 将目录浮动到主文档的左侧。除了TRUE,你还可以传递控制浮动目录行为的选项列表
collapsed: TRUE (默认为TRUE)控制目录是否仅显示顶级标题。折叠时,目录会在必要时自动展开
smooth_scroll: TRUE (默认为TRUE)控制当通过鼠标单击导航到目录项时是否为页面滚动设置动画
number_sections: TRUE 对章节标题进行编号

1.2 文本

R Markdown 文档中的文本是使用 Markdown 语法编写的。

如果文本被星号包围,例如*text*,则文本将为斜体粗体文本是使用一对双星号 (**text**) 生成的。一对波浪号 (~) 将文本转换为下标(例如,H~3~ 呈现 H3)。 一对插入符 (^) 产生一个上标(例如,A^2^ 呈现 A2)。

要将文本高亮标记为文本,请使用一对反引号,例如,`code`。 要包含 \(n\) 个反引号,请在外部至少使用 \(n+1\) 个反引号,例如,你可以使用四个反引号以在内部保留三个反引号:```` ```代码``` ````,呈现为```代码```

超链接是使用语法<link>[text](link)创建的。例如,<https://www.rstudio.com>[RStudio](https://www.rstudio.com) 分别呈现 https://www.rstudio.comRStudio

本文档中的各种元素(章节名、列表等)也都是基于Markdown语法,大家可以对照Cheatsheeet和本文档的源代码学习。

1.3 代码

代码块

你可以使用 RStudio 工具栏(插入按钮)或键盘快捷键Ctrl + Alt + I(macOS 上的Cmd + Option + I)插入 R 代码块。 当你运行.Rmd 文件时,R Markdown将运行每个代码块并将结果嵌入到代码块下方。 你可以在代码块中做很多事情:生成文本输出、表格或图形。例如:

text <- "hello world!"
text
## [1] "hello world!"
x <- 1
x
## [1] 1
knitr::kable(iris[1:5, ])
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa
plot(cars, pch = 19)

可以使用代码块选项自定义输出方式,在块头的 {} 中设置参数。

代码块输出自定义选项
选项 默认值 作用
eval TRUE 是否运行代码块
echo TRUE 是否在输出文档中显示源代码(有人可能不喜欢阅读你的代码而只想看结果)
warning TRUE 是否显示警告
message TRUE 是否显示信息
error FALSE TRUE:在文档中显示错误消息,FALSE:发生错误时停止运行
include TRUE 是否在输出文档中包含代码块。如果 include=FALSE,R Markdown 仍然运行块,其结果可以被其他块使用。
collapse FALSE 将所有源代码和输出折叠到一个块中

要设置适用于文件中每个块的全局选项,在代码块中调用 knitr::opts_chunk$set。R Markdown会将你传递给 knitr::opts_chunk$set 的每个选项视为全局默认值。

文字中代码

通过用 `r ` 将代码括起来,可以将代码结果直接插入到 .Rmd 文件的文本中。R Markdown 总是会显示代码的结果,而不是显示代码本身。

例如,1+1等于2。

练习1

  1. 通过 RStudio 中的新建文档的方式编译你的第一个 .Rmd 文件,熟悉常用的 R Markdown 技巧和 RStudio 操作。

  2. 通过创建一个简短的简历练习你所学。要求:title必须是你的名字;应该包含章节主题(headings),例如教育背景和工作经历,每一部分应该包括工作/学历的项目列表(bulleted list)。


2 R

2.1 R帮助

函数的帮助可用help(cor)?cor,??cor.

2.2 R Package

R程序包是多个函数的集合,具有详细的说明和实例,每个程序包包括R函数,数据,帮助文件,描述文件等。

#install.packages('praise')
library(praise)
praise()
## [1] "You are astonishing!"

2.3 数据类型与结构

要高效地使用 R 语言编程,你需要深入了解基本的数据类型和数据结构,以及如何对它们进行操作。最常用的数据类型包括:

  • 字符型:"RStudio", "R is so good!"
  • 数值型:24, 24.8
  • 逻辑型:TRUE, FALSE
  • 因子型:用来表示分类数据。稍后介绍。

这些数据类型的元素可以组合形成数据结构,包括:向量vector矩阵matrix数据框data frame列表list

列出当前所有对象,删除对象

ls() #当前工作空间中所有对象
## [1] "text" "x"
rm(list='x') # 删除名为x的对象
rm(list=ls()) # 删除一切对象

每次与R的会话,都建立了一个工作空间workspace, 可用save.image(),save(object list, file="xxx.Rdata").

向量

向量是 R 中最常见和最基本的数据结构。

最简单的方式,你可以使用logical()character()numeric() 创建对应数据类型的向量。

logical(5)
## [1] FALSE FALSE FALSE FALSE FALSE
character(5)
## [1] "" "" "" "" ""
numeric(5)
## [1] 0 0 0 0 0

你还可以通过直接指定其内容来创建向量, R会自动猜测向量的存储格式。该函数是 c()(用于 combine),括号内的任何元素(用逗号隔开)都会拼接成一个向量。

x <- c(1, 2, 3,4,5,6)
x
## [1] 1 2 3 4 5 6
y <- c(TRUE, TRUE, FALSE, FALSE)
y
## [1]  TRUE  TRUE FALSE FALSE
y <- c(TRUE, TRUE, FALSE, FALSE,3)
y
## [1] 1 1 0 0 3
z <- c("机器学习", "人工智能")
z
## [1] "机器学习" "人工智能"

c()也可以对一个向量继续增加元素。

z <- c(z, "深度学习")
z
## [1] "机器学习" "人工智能" "深度学习"
z <- c("数据科学", z)
z
## [1] "数据科学" "机器学习" "人工智能" "深度学习"

你可以使用seq()rep()将向量创建为有规律的数字向量。

x <- 1:10
x
##  [1]  1  2  3  4  5  6  7  8  9 10
y <- seq(1,10)
y
##  [1]  1  2  3  4  5  6  7  8  9 10
z <- seq(from = 1, to = 2, by = 0.1)
z
##  [1] 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0
z1 <- rep(0, 10)
z1
##  [1] 0 0 0 0 0 0 0 0 0 0

R 支持向量中的缺失数据。 它们表示为 NA(Not Available),可用于所有向量类型。 函数is.na()指示代表缺失数据的向量元素,如果向量包含任何缺失值,函数anyNA()返回 TRUE。

x <- c("a", NA, "c", "d", NA)
is.na(x)
## [1] FALSE  TRUE FALSE FALSE  TRUE
anyNA(x)
## [1] TRUE

可以使用数字索引从向量、矩阵或数据框中提取元素。有很多方法可以做到这一点。

x <- c(1,4,4,NA,2,2,3)
x[1]
## [1] 1
x[1:3]
## [1] 1 4 4
x[c(5,7)]
## [1] 2 3
x[-7]
## [1]  1  4  4 NA  2  2
x[!is.na(x)]
## [1] 1 4 4 2 2 3

可以利用cbind()进行列向量合并,利用rbind()合并行向量,同样适用于矩阵。

x <- 1:3
y <- 10:12
cbind(x, y)
##      x  y
## [1,] 1 10
## [2,] 2 11
## [3,] 3 12
rbind(x, y)
##   [,1] [,2] [,3]
## x    1    2    3
## y   10   11   12

一些有用的向量函数:

x1 <- x[!is.na(x)]
x1
## [1] 1 2 3
which(x1==4)
## integer(0)
sort(x1)
## [1] 1 2 3
order(x1)
## [1] 1 2 3
rev(x1)
## [1] 3 2 1
unique(x1)
## [1] 1 2 3
table(x1)
## x1
## 1 2 3 
## 1 1 1

因子: 因子用于表示分类数据。因子可以是有序的或无序的。对于统计分析和绘图很重要。

虽然因子经常看起来像字符型向量,但它们实际上是整数,在将它们视为字符时需要非常小心。

创建后,因子只能包含预定义的设定值,称为水平(levels)。 默认情况下,R 始终按首字母顺序对水平进行排序。

factor()函数用于在 R 中创建和修改因子:

sex <- factor(c("male", "female", "female", "male"))
sex
## [1] male   female female male  
## Levels: female male

有时,因子的顺序并不重要。但有时你希望指定顺序,因为它有意义(例如,“低”、“中”、“高”)。此外,指定水平的顺序可以帮助我们比较水平:

food <- factor(c("low", "high", "medium", "high", "low", "medium", "high"))
levels(food)
## [1] "high"   "low"    "medium"
food <- factor(food, levels = c("low", "medium", "high"))
levels(food)
## [1] "low"    "medium" "high"
min(food)
## Error in Summary.factor(structure(c(1L, 3L, 2L, 3L, 1L, 2L, 3L), .Label = c("low", : 'min' not meaningful for factors
food <- factor(food, levels = c("low", "medium", "high"), ordered = TRUE)
min(food)
## [1] low
## Levels: low < medium < high

随机数生成: 可以利用rnorm() 函数生成一个服从正态分布的随机向量,第一个参数 n 即为样本大小。

x <- rnorm(5)
x
## [1] -0.40960694 -1.12764458  0.12067781 -0.08370293  0.11162651

每次我们调用这个函数,都会得到不同的随机数。 有时我们希望我们的代码重现完全相同的结果。 我们可以使用 set.seed() 函数来做到这一点。

set.seed(2024)
x <- rnorm(5)
set.seed(NULL)
x
## [1]  0.9819694  0.4687150 -0.1079713 -0.2128782  1.1580985

默认情况下,rnorm() 创建标准正态随机变量,均值为 0,标准差为 1。可以使用 meansd 参数更改均值和标准差。

x <- rnorm(5, mean = 10, sd=2)
x
## [1]  7.472027 10.784922 12.011800 11.085119 11.641709
x <- rnorm(10, -10, 5)
x
##  [1]  -8.1439462  -4.5078629  -6.7802389 -17.4799380 -13.7136552  -4.7502033
##  [7]  -8.7626431 -17.0858539  -0.4567072  -4.3239468

mean()var() 函数可用于计算数字向量的均值和方差。 sd() 函数可以计算标准差。

y <- rnorm(100)
mean(y)
## [1] 0.1045968
var(y)
## [1] 0.9228385
sd(y)
## [1] 0.9606448

同样,你可以使用 rt()runif() 从t分布、均匀分布等其他分布生成随机数。

随机抽样函数sample(x, size, replace=FALSE, prob=NULL): 从x中随机取样,取样size个,默认无放回,等概率。

sample(1:10, 4) #从1到10中取样,并从中不放回地抽取4个数字
## [1] 8 6 5 7
sample(1:10) #从1到10中进行无放回地取10个数字
##  [1]  1  3  2  8  5  7  4 10  9  6
sample(1:10, replace=T) #从1到10中进行有放回地取10个数字
##  [1]  5  1  1 10  5 10  1  5  5  9
sample(1:10,10,replace=TRUE) 
##  [1]  9  8  9  6  5 10  7  2  1  8
sample(letters, 5) 
## [1] "u" "g" "e" "a" "x"
sample(c("H","T"),10,prob=c(0.5,0.5),replace=TRUE)
##  [1] "H" "H" "H" "T" "H" "H" "H" "T" "T" "T"
sample(c("H","T"),10,prob=c(0.8,0.2),replace=TRUE)
##  [1] "H" "H" "H" "H" "H" "H" "T" "H" "H" "H"

在电脑上生成随机数字时,生成的数字并不是真正的随机数,设置随机数字生成器种子(seed)是非常重要的 课重复结果,set.seed(一个整数)

rnorm(10)
##  [1] -0.1227425  0.1571038 -1.2431847  1.0254386  0.6832730 -0.7305534
##  [7]  1.2609388  1.0576906  0.6672359  0.9098757
rnorm(10)
##  [1] -0.35195837 -0.47336419  0.08025396 -0.18289575 -1.46264301  0.59397928
##  [7] -1.39544955  0.81349122 -1.32241957 -0.83179092
set.seed(1)
rnorm(10)
##  [1] -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078 -0.8204684
##  [7]  0.4874291  0.7383247  0.5757814 -0.3053884
rnorm(10)
##  [1]  1.51178117  0.38984324 -0.62124058 -2.21469989  1.12493092 -0.04493361
##  [7] -0.01619026  0.94383621  0.82122120  0.59390132
set.seed(1)
rnorm(10)
##  [1] -0.6264538  0.1836433 -0.8356286  1.5952808  0.3295078 -0.8204684
##  [7]  0.4874291  0.7383247  0.5757814 -0.3053884
rnorm(10)
##  [1]  1.51178117  0.38984324 -0.62124058 -2.21469989  1.12493092 -0.04493361
##  [7] -0.01619026  0.94383621  0.82122120  0.59390132

矩阵

matrix() 函数可用于创建数字矩阵。 在使用 matrix() 函数之前,我们可以通过 ?matrix 了解更多信息。 首先,我们创建一个简单的矩阵。

A <- matrix(data = 1:16, nrow = 4, ncol = 4) 
A
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16

如前所述,我们可以省略键入 data=nrow=ncol= 并键入 matrix(1:16, 4, 4),这会产生相同的效果。

如本例所示,默认情况下 R 通过填充列来创建矩阵。可以使用 byrow = TRUE 按行的顺序填充矩阵。

mdat <- matrix(c(1,2,3, 11,12,13), nrow = 2, ncol = 3, byrow = TRUE)
mdat
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]   11   12   13

dim() 函数输出给定矩阵的行数和列数。

dim(mdat)
## [1] 2 3
nrow(mdat)
## [1] 2
ncol(mdat)
## [1] 3

要索引 A 中的元素,键入 A[2,3] 将选择对应于第二行和第三列的元素。

A <- matrix(1:16, 4, 4) 
A
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
## [3,]    3    7   11   15
## [4,]    4    8   12   16
A[2,3]
## [1] 10
A[1,]
## [1]  1  5  9 13
A[,1]
## [1] 1 2 3 4

我们还可以一次选择多行和多列,方法是提供向量作为索引。

A[c(1, 3), c(2, 4)]
##      [,1] [,2]
## [1,]    5   13
## [2,]    7   15
A[1:3, 2:4]
##      [,1] [,2] [,3]
## [1,]    5    9   13
## [2,]    6   10   14
## [3,]    7   11   15
A[1:2, ]
##      [,1] [,2] [,3] [,4]
## [1,]    1    5    9   13
## [2,]    2    6   10   14
A[, 1:2]
##      [,1] [,2]
## [1,]    1    5
## [2,]    2    6
## [3,]    3    7
## [4,]    4    8
A[-c(1, 3), ]
##      [,1] [,2] [,3] [,4]
## [1,]    2    6   10   14
## [2,]    4    8   12   16

可以应用于标量的函数通常也可以应用于向量和矩阵。例如,sqrt() 函数返回向量或矩阵的每个元素的平方根。 命令 x^2 将 x 的每个元素求平方。

x <- matrix(c(1, 2, 3, 4), 2, 2, byrow = TRUE)
sqrt(x)
##          [,1]     [,2]
## [1,] 1.000000 1.414214
## [2,] 1.732051 2.000000
x^2
##      [,1] [,2]
## [1,]    1    4
## [2,]    9   16
x+2
##      [,1] [,2]
## [1,]    3    4
## [2,]    5    6
t(x) #转置
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
x*x #对应元素相乘
##      [,1] [,2]
## [1,]    1    4
## [2,]    9   16
x%*%x #矩阵运算
##      [,1] [,2]
## [1,]    7   10
## [2,]   15   22
rowSums(x) # 按行加和
## [1] 3 7
colSums(x)# 按列加和
## [1] 4 6
rowMeans(x) #按行平均
## [1] 1.5 3.5
colMeans(x) #按列平均
## [1] 2 3

apply(X, margin, Fun), margin为1时对行,2对列

apply ( x,1,sum ) #按行求和
## [1] 3 7

apply ( x,2,sum ) #按列求和
## [1] 4 6

score1 <- c(100,90,80,100,80) 
score2 <- c(98,85,70,80,90) 
z<-cbind(score1,score2)
### 练习:给出两次考试的均值 apply(z,?,?)
### 练习:给出每个人的平均成绩 apply(z,?,?)

列表

在 R 中,列表充当容器。列表的功能十分强大,内容可以包含任何数据类型的混合。

使用 list() 创建列表:

x <- list(1, "a", TRUE)
x
## [[1]]
## [1] 1
## 
## [[2]]
## [1] "a"
## 
## [[3]]
## [1] TRUE

也可以使用as.list()将向量转换为列表:

x <- 1:3
x <- as.list(x)
x
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 3

列表的元素可以命名

x <- list(name = "小明", data=c(177,67))
x
## $name
## [1] "小明"
## 
## $data
## [1] 177  67

笔记: 列表在函数内部非常有用。 因为 R中的函数只能返回一个对象,所以你可以将许多不同类型的结果拼接,并通过函数可以返回的单个对象输出。

元素由双括号索引。如果列表的元素已命名,则可以通过$符号(即x$data)引用它们。

x[[1]]
## [1] "小明"
x$data
## [1] 177  67
x$data[1]
## [1] 177

数据框

数据框是 R 中非常重要的数据类型。它几乎是大多数表格数据的数据结构,也是我们用于统计的数据结构。

数据框是一种特殊类型的列表,其中列表的每个元素都具有相同的长度(即数据框是一个”矩形”列表)。

有关数据框的一些附加信息:

  • 通常由read.csv()read.table()创建,即将数据导入 R 时。后续讨论
  • 如果数据框中的所有列都是相同类型,可以使用as.matrix()将数据框转换为矩阵。
  • 可以使用 data.frame() 函数创建一个新的数据框。
  • 行名通常是自动生成的,看起来像1, 2,..., n
dat <- data.frame(id = letters[1:10], x = 1:10, y = 11:20)
dat
##    id  x  y
## 1   a  1 11
## 2   b  2 12
## 3   c  3 13
## 4   d  4 14
## 5   e  5 15
## 6   f  6 16
## 7   g  7 17
## 8   h  8 18
## 9   i  9 19
## 10  j 10 20

一些有用的数据框函数:

  • head() - 显示前六行
  • tail() - 显示后六行
  • dim() - 返回数据框的维度(即行数和列数)
  • nrow() - 行数
  • ncol() - 列数
head(dat)
##   id x  y
## 1  a 1 11
## 2  b 2 12
## 3  c 3 13
## 4  d 4 14
## 5  e 5 15
## 6  f 6 16
dim(dat)
## [1] 10  3
nrow(dat)
## [1] 10
ncol(dat)
## [1] 3

由于数据框也是列表,因此可以使用列表符号来引用列(此类列表的元素),即[[ ]]$

dat[[1]]
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
dat$id
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
dat[,1]
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
dat[1,]
##   id x  y
## 1  a 1 11

2.3.1 数据属性判断与转化

每个元素都有自己的属性,查看属性

x <- c(0.5, 0.6)      ## numeric 
mode(x)
## [1] "numeric"
x <- c(TRUE, FALSE)   ## logical 
mode(x)
## [1] "logical"
x <- c(T, F)          ## logical 
mode(x)
## [1] "logical"
x <- c("M", "F")      ## character 
mode(x)
## [1] "character"

属性的判断与转化

x = 0:6
is.numeric(x)
## [1] TRUE
is.character(x)
## [1] FALSE
as.logical(x)
## [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE
as.character(x)
## [1] "0" "1" "2" "3" "4" "5" "6"
is.character(x)
## [1] FALSE
x = c("a","b","c")
as.numeric(x)
## Warning: 强制改变过程中产生了NA
## [1] NA NA NA
as.logical(x)
## [1] NA NA NA

练习2

  • 使用rep()函数创造向量 1,1,1,1,1,2,2,2,2,2 并将其命名为 x1

  • 使用rep()函数创造向量 1,2,1,2,1,2,1,2,1,2 并将其命名为 x2

  • x1x2 按列组合成矩阵 x.col,即 x1x2x 的两列。

  • x1x2 按行组合成矩阵 x.row,即 x1x2x 的两行。

  • 找到两种方法来计算 x.row 的每一列的总和。

  • 1,2,..., 20 构成两个4*5的矩阵,其中矩阵A是按列输入,矩阵B是按行输入,并基于A和B生成如下矩阵C-H并输出:

    1. C=A+B;
    2. D=AB^T (矩阵相乘:A乘以B的转置矩阵,提示:转置矩阵用t()函数);
    3. E:第一列全为1,后面几列等于A矩阵;
    4. F1由A的前3行和前3列构成;(思考:为什么命名为F1而不是F?)
    5. G是由矩阵B去除第3列构成的矩阵;
    6. H是与A具有相同对角元素的对角阵。(提示:使用diag()函数)

2.4 数据的输入与输出

工作目录:读取外部文件和保存结果到外部文件夹的默认路径

getwd()
## [1] "/Users/liting/Documents/SUFE/课程/机器学习/2024/课件/Ch_R语言介绍"
#setwd()
mydata <- read.table("Rreaddata.txt")
mydata
##   V1 V2  V3
## 1  M 65 168
## 2  M 70 172
## 3  F 54 156
## 4  F 58 163
mydata <- read.csv("Rreaddata.txt",header=FALSE, sep=" ")
mydata
##   V1 V2  V3
## 1  M 65 168
## 2  M 70 172
## 3  F 54 156
## 4  F 58 163
mydata <- read.csv("Rreaddata.csv",header=T, sep=",")
mydata
##   Gender Weight Height
## 1      M     65    168
## 2      M     70    172
## 3      F     54    156
## 4      F     58    163
mydata <- read.csv("Rreaddata.csv")
mydata
##   Gender Weight Height
## 1      M     65    168
## 2      M     70    172
## 3      F     54    156
## 4      F     58    163

数据输出

d <- data.frame(obs = c(1, 2, 3), treat = c("A", "B", "A"),weight = c(2.3, NA, 9))
write.table(d, file = "foo.txt",row.names = F)
write.csv(d, file = "foo.csv",row.names = F)
save(d, file = "foo.Rdata")

2.5 控制语句

当我们使用 R 进行编程时,我们通常希望控制代码的特定部分何时以及如何执行。可以使用 if-else 语句、for 循环和 while 循环等控制结构来做到这一点。

if-else

控制结构是代码块,它们根据指定的参数确定其他代码段的执行方式。 你可以把这些想成有点像父母在离开家之前给孩子的指示:

“如果我晚上 8 点之前没回家,你自己做晚饭吧。”

为了使用控制结构,我们需要创建结果为 TRUE 或 FALSE 的语句。 在上面的孩子示例中,声明”现在是晚上 8 点。 我爸妈在家吗?” 产生 TRUE(“是”)或 FALSE(“否”)。在 R 中,评估某事物为 TRUE 或 FALSE 的最基本方法是通过比较运算符。

以下是在 R 中使用控制结构的六个基本比较运算符:

  • == 表示相等。x == a 表示:x的值等于a吗?

  • != 表示”不等于”。x != b 表示:x 的值不等于 b 吗?

  • < 表示”小于”。x < c 表示:x 的值是否小于 c?

  • <= 表示”小于等于”。x <= d 表示:x 的值是否小于或等于 d?

  • > 表示”大于”。x > e 表示:x 的值是否大于 e?

  • >= 表示”大于等于”。x >= f 表示:x 的值是否大于或等于 f ?

team_A <- 3 # A队进球数
team_B <- 1 # B队进球数
if (team_A > team_B){
  print ("A队获胜")
}
## [1] "A队获胜"

因为 A 队的进球比 B 队多,条件语句 (team_A > team_B) 的计算结果为 TRUE,所以它下面的代码块运行,输出”A 队赢得比赛”的消息。

如果B队进球数更多呢?

team_A <- 1 
team_B <- 3
if (team_A > team_B){
    print ("A队获胜")
} else {
    print ("B队获胜")
}
## [1] "B队获胜"

回顾一下:

  • if 语句的本质特征是它帮助我们在代码中创建分支路径。
  • R 中的 if 和 else 关键字后跟大括号 { },它们定义代码块。
  • 每个代码块代表一条路径。
  • R 不会同时运行两者,它使用比较运算符来决定运行哪个代码块。

如果有多于两条路径呢?

team_A <- 2 
team_B <- 2
if (team_A > team_B){
  print ("A队获胜")
} else if (team_A < team_B){
  print ("B队获胜")
} else {
  print("两队打成平手")
}
## [1] "两队打成平手"

for

现在我们已经在 R 中使用if-else来显示一场比赛的结果,如果我们想查找多场比赛的结果怎么办?假设我们有一个包含多场比赛结果的向量列表:

matches <- list(c(2,1),c(1,2),c(6,3))

假设 A 队的进球数列在第一位(向量的第一个索引),B 队的进球数列在第二位,我们可以在 R 中使用 if-else 找到结果:

if (matches[[1]][1] > matches[[1]][2]){
    print ("A队获胜")
} else {
    print ("A队战败")
}
## [1] "A队获胜"

if (matches[[2]][1] > matches[[2]][2]){
    print ("A队获胜")
} else {
    print ("A队战败")
}
## [1] "A队战败"

if (matches[[3]][1] > matches[[3]][2]){
    print ("A队获胜")
} else {
    print ("A队战败")
}
## [1] "A队获胜"

此代码有效,但我们很容易发现问题。三场比赛已经很麻烦了,如果我们有1000场比赛怎么办?

我们可以通过使用 R 中的 for 循环执行相同的操作来改进我们的代码。for 循环为对象中的每个元素重复一段代码多次。这使我们可以编写更少的代码(这意味着出错的可能性更小)并且可以更好地表达我们的意图:

for (value in sequence){
  code block
}

让我们看一个具体的例子。我们将编写一个快速循环来打印列表中项目的值:

teams <- c("A队","B队")
for (value in teams){
    print(value)
}
## [1] "A队"
## [1] "B队"

下面我们结合if-else语句和for循环来实现多场比赛的高效评估:

matches <- list(c(2,1),c(1,2),c(6,3))
for (match in matches){
    if (match[1] > match[2]){
        print("A队获胜")
    } else {
        print ("A队战败")
    }
}
## [1] "A队获胜"
## [1] "A队战败"
## [1] "A队获胜"

2.6 函数

R 使用函数来执行操作。 有了函数,你几乎可以做任何事。

要运行名为 func 的函数,我们键入 func(input1, input2, ...),其中参数 input1input2 告诉 R 如何运行该函数。

部分函数在预装包当中,可直接使用。 有些函数只有在使用 install.packages()library() 安装并加载相应的包后才能使用。

你也可以编写自己的函数以进行重复操作。 例如:

add1 <- function(a=1,b=2){
  c <- a+b
  return(c)
}
add1()
## [1] 3
add1(a=5,b=8)
## [1] 13

如果参数有默认值,不传入参数值就会按照默认值自动计算。

我们可以在上面的 add1() 命令中省略键入 a=b=:也就是说,我们可以只键入 add1(5,8),这会产生相同的效果。

但是,有时指定传入参数的名称可能很有用,因为否则R将假定函数参数以函数帮助文件中给出的相同顺序传递到函数中。此时,如果参数很多,不进行名称指定将很容易报错。

add1(5,8)
## [1] 13
add1(b=8,a=12)
## [1] 20
add1(a=1,b=2,g=3)
## Error in add1(a = 1, b = 2, g = 3): 参数没有用(g = 3)
add1(8,"a")
## Error in a + b: 二进列运算符中有非数值参数

练习3

  • 创建一个名为 func() 的函数,该函数有一个名为 lst 的参数。

    1. 该函数应该创建一个新的空向量,并添加 lst 中具有奇数索引的每个元素。然后该函数应该返回这个新向量。
    2. 例如,func(c(4, 3, 7, 10, 11, -2)) 应返回向量 c(4, 7, 11)
  • 回顾概率论与数理统计中正态样本的均值参数的区间估计, 设\(x_1, \dots, x_n\)是来自正态均值为\(\mu\),标准差为\(\sigma\)的正态分布的一个样本,则μ的置信度为\(1-\alpha\)的95%置信区间为\([\bar x-1.96 s/\sqrt{n}, \bar x+1.96 s/\sqrt{n}]\).

    (1). 按下列要求生成R函数: 函数名:takeCI; 输入: (1)数值型向量x,表示某正态样本的取值. 输出: 基于该样本得到的均值参数的置信度为95%的置信区间,以一个长度为2的向量输出。(提示:可用mean(),sd()函数)

    (2). 从均值为10,标准差为1的正态分布中随机生成样本量n=20的一个样本\(x\)。基于此样本,用(1)中函数计算均值参数的95%置信区间并输出

2.7 图形

plot() 函数是在 R 中绘制数据的主要方法。例如,plot(x, y) 生成 x 中的数字与 y 中的数字的散点图。 还有许多其他选项,例如,传入参数 xlab 将在 x 轴上产生一个标签。 要了解更多信息,请输入?plot

x <- rnorm(100)
y <- rnorm(100)
plot(x, y, xlab = "this is the x-axis", ylab = "this is the y-axis", main = "Plot of X vs Y")

plot(x,type='o',pch=2,lty=1,col='blue')

一个创建优雅图形的强大包是ggplot2。它通过将图形分解为多个层次来理解和构建图形。 例如:

library(ggplot2)
ggplot(mpg, aes(displ, hwy, colour = class)) + geom_point()

我们不会详细介绍 ggplot2。如果你对ggplot2感兴趣,建议你访问https://ggplot2.tidyverse.org/

2.8 加载数据

对于大多数数据分析来说,第一步是将数据集导入 R 中。read.table() 函数是执行此操作的主要方法之一。我们可以使用函数 write.table() 来从 R 中导出数据。

为了说明read.table() 函数,我们现在利用其加载文本文件 Auto.data。以下命令会将文件加载到 R 中并将其存储为名为 Auto数据框head() 函数也可用于查看数据的前几行。

Auto <- read.table("Auto.data")
Auto[c(1:5,34),]
##      V1        V2           V3         V4     V5           V6   V7     V8
## 1   mpg cylinders displacement horsepower weight acceleration year origin
## 2  18.0         8        307.0      130.0  3504.         12.0   70      1
## 3  15.0         8        350.0      165.0  3693.         11.5   70      1
## 4  18.0         8        318.0      150.0  3436.         11.0   70      1
## 5  16.0         8        304.0      150.0  3433.         12.0   70      1
## 34 25.0         4        98.00          ?  2046.         19.0   71      1
##                           V9
## 1                       name
## 2  chevrolet chevelle malibu
## 3          buick skylark 320
## 4         plymouth satellite
## 5              amc rebel sst
## 34                ford pinto

Auto 数据框有些不对劲。你注意到了吗?

R 假定变量名称是数据的一部分,因此将它们包含在第一行中。 在 read.table() 函数中使用选项 header = TRUE 告诉 R:文件的第一行是变量名。

该数据集还包括一些缺失值,用?表示。

缺失值在真实数据集中很常见。使用选项 na.strings告诉 R,任何时候它看到一个特定字符,都应将其视为数据矩阵的缺失元素。

Auto <- read.table("Auto.data", header = TRUE, na.strings = "?", stringsAsFactors = TRUE)
Auto[c(1:4,33),]
##    mpg cylinders displacement horsepower weight acceleration year origin
## 1   18         8          307        130   3504         12.0   70      1
## 2   15         8          350        165   3693         11.5   70      1
## 3   18         8          318        150   3436         11.0   70      1
## 4   16         8          304        150   3433         12.0   70      1
## 33  25         4           98         NA   2046         19.0   71      1
##                         name
## 1  chevrolet chevelle malibu
## 2          buick skylark 320
## 3         plymouth satellite
## 4              amc rebel sst
## 33                ford pinto

stringsAsFactors = TRUE告诉R,任何包含字符串的变量都应被解释为分类变量,并且每个不同的字符串代表该分类变量的不同水平。

将数据从 Excel 加载到 R 中的一种简单方法是将其保存为 csv(逗号分隔值)文件,然后使用 read.csv() 函数。

Auto <- read.csv("Auto.csv", header=TRUE, na.strings = "?", stringsAsFactors = TRUE)
head(Auto)
##   mpg cylinders displacement horsepower weight acceleration year origin
## 1  18         8          307        130   3504         12.0   70      1
## 2  15         8          350        165   3693         11.5   70      1
## 3  18         8          318        150   3436         11.0   70      1
## 4  16         8          304        150   3433         12.0   70      1
## 5  17         8          302        140   3449         10.5   70      1
## 6  15         8          429        198   4341         10.0   70      1
##                        name
## 1 chevrolet chevelle malibu
## 2         buick skylark 320
## 3        plymouth satellite
## 4             amc rebel sst
## 5               ford torino
## 6          ford galaxie 500
dim(Auto)
## [1] 397   9

dim() 函数告诉我们:数据有 397 个观测或行,每个观测有九个变量。

有多种方法可以处理缺失值。在这个数据中,只有五行包含缺失的观察值,因此我们选择使用 na.omit() 函数来简单地删除这些行:

Auto <- na.omit(Auto) 
dim(Auto)
## [1] 392   9

正确加载数据后,我们可以使用names() 来检查变量名称:

names(Auto)
## [1] "mpg"          "cylinders"    "displacement" "horsepower"   "weight"      
## [6] "acceleration" "year"         "origin"       "name"

2.9 额外的图形和数值摘要

我们可以使用 plot() 函数来生成定量变量的散点图。 然而,简单地键入变量名称会产生错误消息,因为 R 不知道要在 Auto 数据集中查找这些变量。

plot(cylinders, mpg)
## Error in plot(cylinders, mpg): 找不到对象'cylinders'

要引用一个变量,我们必须键入数据集和用 $ 符号连接的变量名。

plot(Auto$cylinders, Auto$mpg) 

cylinders 变量存储为数字向量,因此 R 已将其视为定量变量。 但是,由于圆柱体的可能值很少,因此可能更愿意将其视为定性变量。 as.factor() 函数将定量变量转换为定性变量。

attach(Auto)
cylinders <- as.factor(cylinders)
plot(cylinders, mpg, col = "red", varwidth = TRUE, xlab = "cylinders", ylab = "MPG")

hist(mpg, col = "blue")

pairs(~mpg + displacement + horsepower + weight + acceleration, data = Auto
)

summary(Auto)
##       mpg          cylinders      displacement     horsepower        weight    
##  Min.   : 9.00   Min.   :3.000   Min.   : 68.0   Min.   : 46.0   Min.   :1613  
##  1st Qu.:17.00   1st Qu.:4.000   1st Qu.:105.0   1st Qu.: 75.0   1st Qu.:2225  
##  Median :22.75   Median :4.000   Median :151.0   Median : 93.5   Median :2804  
##  Mean   :23.45   Mean   :5.472   Mean   :194.4   Mean   :104.5   Mean   :2978  
##  3rd Qu.:29.00   3rd Qu.:8.000   3rd Qu.:275.8   3rd Qu.:126.0   3rd Qu.:3615  
##  Max.   :46.60   Max.   :8.000   Max.   :455.0   Max.   :230.0   Max.   :5140  
##                                                                                
##   acceleration        year           origin                      name    
##  Min.   : 8.00   Min.   :70.00   Min.   :1.000   amc matador       :  5  
##  1st Qu.:13.78   1st Qu.:73.00   1st Qu.:1.000   ford pinto        :  5  
##  Median :15.50   Median :76.00   Median :1.000   toyota corolla    :  5  
##  Mean   :15.54   Mean   :75.98   Mean   :1.577   amc gremlin       :  4  
##  3rd Qu.:17.02   3rd Qu.:79.00   3rd Qu.:2.000   amc hornet        :  4  
##  Max.   :24.80   Max.   :82.00   Max.   :3.000   chevrolet chevette:  4  
##                                                  (Other)           :365

练习4

本练习涉及波士顿住房数据集。 首先,加载波士顿数据集。 波士顿数据集是ISLR2库的一部分。 当然,您应该在使用前安装 ISLR2 包。 在 library(ISLR2) 之后,数据集包含在对象 Boston 中。 使用?Boston阅读有关数据集的信息。

  • 该数据集中有多少行? 多少列? 行和列代表什么?
  • 哪些变量是定量的,哪些是定性的?
  • 每个定量预测变量的范围是多少?可以使用range()函数来回答这个问题。
  • 为该数据集中的变量(列)制作一些成对散点图。描述你的发现。
  • 是否有任何与人均犯罪率相关的预测因素? 如果是,请解释这种关系。
  • 每个定量预测变量的均值和标准差是多少?
  • 该数据集中有多少人口普查区域位于查尔斯河沿岸?
  • 该数据集中各城镇的师生比中位数是多少?
  • 波士顿哪个人口普查区的自住房屋中位数最低?该人口普查区域的其他预测变量的值是多少,这些值与这些预测变量的总体范围相比如何? 描述你的发现。
  • 在此数据集中,有多少人口普查区平均每户住宅超过七个房间? 每个住宅超过八个房间? 评论每个住宅平均超过八个房间的人口普查区。

第一次作业

第一次作业即为本Rmd文档中所有的练习,请大家汇总到一个新的Rmd文档中,于下周日9.22晚24点前提交以HW2+学号+姓名.html/pdf文件至Canvas。