R与RStudio
R是一种统计学编程语言,在科学计算领域非常流行。它是由Ross Ihaka和Robert Gentleman开发的,是 "S "编程语言的开源实现。R也是使用这种语言进行统计计算的软件的名字。它有一个庞大的在线支持社区和专门的软件包,可以为几乎所有的应用和研究领域提供丰富的功能,几乎没有什么事情是你在R中做不到的。
如果你已经熟悉了像Minitab
或SPSS
这样的统计软件,那么主要的区别在于R
没有图形化的用户界面
(graphical user interface),这意味着没有可以点击的按钮,也没有下拉菜单。R
可以完全通过在文本界面中输入命令来运行。这似乎有点让人望而生畏,但这也意味着更多的灵活性,因为你不需要依赖预先设定的各种软件进行分析。
如果你觉得说服力还不够强,为什么我们要用R,而不是 MATLAB
、Minitab
、甚至是Microsoft Excel
等众多统计软件中的一个?好吧,R非常好,因为以下三点:
- R是免费和开放源代码的,而且永远都是免费的!任何人都可以使用它的代码,并且可以看到它的数据。任何人都可以使用这些代码,并且可以看到它到底是如何工作的。
- 因为R是一种编程语言而不是图形界面,用户可以很容易地将脚本保存为小的文本文件,以便将来使用,或者与合作者分享。
- R有一个非常活跃和有帮助的在线社区--通常情况下,只要快速搜索一下,就会发现有人已经解决了你的问题。
下载R和RStudio
正如我们之前所说,R本身并没有图形化的界面,但大多数人都是通过图形化平台与R进行交互,这些平台提供了额外的功能。我们将使用一个叫RStudio的IDE作为R的图形化前端,这样我们就可以在一个地方访问我们的脚本和数据,找到帮助,预览图和输出。
你可以从CRAN(The Comprehensive R Archive Network)下载R。选择适合你的操作系统的版本。
然后,从RStudio网站下载RStudio(选择免费的开源桌面版)。
打开RStudio。依次选择左上角的File
→ New File
→ R script
。
你现在会看到一个像上面这样的窗口。你可以直接在左下角的控制台(console)中输入代码。在代码行的最后按回车键就可以运行代码(试着输入2+2
并运行它)。你也可以在左上方窗口的脚本文件中写下你的代码。要从脚本中运行一行代码,在Windows上按Ctrl+Enter
,或在Mac上按Cmd+Enter
。在右上角的环境窗口(environment window)中,你可以看到当前工作区(workspace)的概览。你会看到你已经导入的数据,已经创建的对象,已经定义的函数等。最后,右下角的面板有多个标签页,会预览你的绘图,并允许你在文件夹中进行导航,查看你当前已经安装和加载的软件包。
关于脚本的注意事项:请记住,如果你直接在控制台中输入代码,它不会被R保存:它会运行并消失(尽管你可以通过键盘上的 "up "键来访问最后的几个操作)。相反,通过将代码输入到脚本文件中,你将创建一个可重现的分析记录。在脚本中写代码就像在Word中写论文一样:它可以保存你的进度,而且你可以随时从头开始,或者对它做一些修改。(记得经常点击保存(Ctrl+S
),这样你就能真正的保存你的脚本了!)
在编写脚本时,通过在一行文字前插入井号#
来添加注释,描述你正在做的事情是很有用的。R 会把任何以#
开头的东西看成是文本,而不是代码,所以它不会尝试运行它,但这些文本将为阅读你脚本的人(包括未来的你!)提供有价值的代码信息。就像任何文章一样,脚本将从结构和清晰度中受益。关于工作区的快速说明:工作区会在电脑内存中存储一个会话使用过的所有内容。当你退出时,R会问你是否要保存当前工作区。通常你几乎不需要保存工作区,最好是每次都点击 "不",然后下次打开时可以从头开始运行脚本。(一定要确保保存你的脚本!)
控制台 (console) 中的操作
当我们在使用R工作时,经常会使用命令行(command line)来完成我们的任务。在命令行中我们输入命令,它就会对这些命令做出响应。在最简单的情况下,如果我们只要输入一个数字,它就会简单的用这个数字来响应。进入RStudio左下角的控制台,输入数字3。你应该会看到这样的结果。
> 3
[1] 3
>
符号是命令提示符(command prompt),提示你输入一些东西。下一行([[1] 3
)是R的答案。让我们试试更复杂一点的东西。
> 3 + 4
[1] 7
只要R能够明白你输入了什么,它就能回应任何你的输入。现在,让我们试着输入一个单词。
> hello
Error: object 'hello' not found
为什么会报错呢?因为当R遇到一个字母或单词时,会假定它指的是一个变量(variable)的名字--想想高中代数中的X。我们稍后再讲变量,但如果我们想让R打印出hello这个词,那么我们需要用引号来包含它,告诉R它是一个字符串(character string)。
> "hello"
[1] "hello"
R中的变量有很多类型,你已经看到了两个例子:整数(如数字3)和字符串(如 "hello "一词)。另一个重要的是实数(real numbers),也就是我们在统计学中要处理的最常见的一种数。实数没有整数的限制,包括了整数之间的空间,举个例子:
> 1/3
[1] 0.33
在现实中,结果应该是0.33,后面接着无数的3,但R在这个例子中只向我们展示了两位小数。
另一种变量被称为逻辑变量(logical variable),因为它基于逻辑学中的思想,即一个语句可以是真或假。在R中,这些变量都是大写的(TRUE
和FALSE
)。
为了判断一个语句是否为真,我们使用逻辑运算符(logical operators)。你已经熟悉其中的一些运算符,如大于(>
)和小于(<
)运算符。
> 1 < 3
[1] TRUE
> 2 > 4
[1] FALSE
通常情况下,我们想知道两个数字是否相等或不相等。在R中,有一些特殊的运算符可以做到这一点:==
表示等号,和 !=
表示不等号。
> 3 == 3
[1] TRUE
> 4 != 4
[1] FALSE
开始写你的脚本
现在,我们可以在RStudio左上角的文本编辑器内编辑自己的脚本了。先记录谁在写,日期和主要目标--在我们的例子中,确定在爱丁堡有多少个不同分类群的物种被记录下来。这里有一个例子,你可以复制,粘贴和编辑到你的新脚本。
# Coding Club Workshop 1 - R Basics
# Learning how to import and explore data, and make graphs about Edinburgh's biodiversity
# Written by Gergana Daskalova 06/11/2016 University of Edinburgh
接下来的几行代码通常会加载你的分析所需要的包。包(package)是一个可以加载到R中的程序集,以提供额外的功能。例如,你可能会加载一个用于格式化数据,或者制作地图的包。
要安装一个包,键入install.package("package-name")
。你只需要安装一次包,所以在这种情况下,你可以直接在控制台框中输入,而不是在脚本中保存这一行,然后每次重新安装包。
安装完成后,你只需要使用library(package-name)
加载包就可以了。今天我们将使用dplyr包来提供额外的命令来格式化和处理数据。
接下来的代码行应该定义你的工作目录(working directory)。这是你计算机上的一个文件夹,R将在其中寻找数据,保存你的作图等。为了使你的工作流程更容易,将所有与一个项目相关的东西都保存在同一个地方是很好的做法,因为这将为你节省大量的时间,输入计算机路径或寻找被R-know-where保存的文件。例如,你可以将你的脚本和本教程的所有数据保存在一个名为 "Intro_to_R "的文件夹中(避免文件名中的空格是很好的做法) 。对于较大的项目,可以考虑用项目名称的根目录(例如 "My_PhD")作为你的工作目录,其他的文件夹也可以嵌套在其中,将数据、脚本、图像等分开(例如:My_PhD/Chapter_1/data、My_PhD/Chapter_1/plots、My_PhD/Chapter_2/data等)。
要知道你现在的工作目录在哪里,请运行代码getwd()
。如果你想改变它,可以使用setwd()
。将你的工作目录设置为你刚才从GitHub上下载的文件夹。
install.packages("dplyr")
library(dplyr)
# 注意,安装包的时候有引号,但加载包的时候没有引号,记住#可以让你在代码中添加有用的注释! setwd("C:/User/CC-1-RBasics-master")
# 这是一个示例的文件路径,请修改成你自己的文件路径。
注意,在Windows电脑上,复制粘贴的文件路径会用反斜杠分隔文件夹("C:folderdata"
),但在R中输入的文件路径应该使用正斜杠(forward slashes)("C:/folder/data"
)。
导入和检查数据
练习是学习任何新语言的最好方法,所以让我们直接开始,用一个公开的动物、植物和真菌物种发现记录的数据集来做一些自己的统计分析。我们下载了2000-2016年的记录(从NBN Gateway中下载),并保存为edidiv.csv
。首先,你需要下载数据。
按照链接,点击 "下载Zip",然后保存并解压到你电脑上的某个文件夹。
你可以在这个Github仓库中找到完成本教程所需的所有文件。
R处理的是.csv
(逗号分隔的值)文件,如果你在Excel中输入数据,你需要点击另存为并选择csv
作为文件扩展名。在Excel中输入数据时,不要在行名中加上空格,因为它们会使R以后混淆(例如:使用像height_meters
这样的东西而不是height (m)
。有些计算机在保存.csv
文件时,会用分号 ;
而不是逗号 ,
作为分隔符。这通常发生在你的计算机上的第一种或唯一的语言不是英语的情况下。如果你的文件被分号分隔,请使用read.csv2
代替read.csv
,或者在read.csv
函数中使用参数 "sep"(用于分隔符):read.csv("your-file-path", sep = ";")
。
edidiv <- read.csv("C:/Users/user/Desktop/Intro_to_R/edidiv.csv") # 这是基于我保存数据的文件路径,你的文件路径会有所不同。
记得偶尔保存一下你的脚本! 如果你还没有保存,尝试着把它保存在和其他教程文件一样的目录下,并给它起一个有意义的名字。
关于对象的说明:R是一种基于对象的语言--这意味着你导入的数据,以及以后创建的任何值,都存储在你命名的对象中。上面的代码中的箭头<-
代表赋值操作 。这里,我们将csv文件分配给对象edidiv
。我们可以将其命名为mydata
或hello
或biodiversity_recorded_around_Edinburgh_Scotland
,但最好选择一个独特的、信息量大且简短的名称。在RStudio的右上角窗口中,你可以看到当前加载到R中的任何对象的名称,看到你的edidiv
对象了吗?
当你把数据导入到R中时,它很可能会变成一个叫做数据框
(dataframe)的对象。数据框就像一个表格,或电子表格--它有行和列,包含不同的变量和观察结果。
一个真正重要的步骤是检查你导入了的数据是否没有任何错误。好的做法是始终运行这段代码,并检查控制台中的输出--你是否看到任何缺失的值,数字/名称是否合理?如果你直接进入分析,你就有可能在以后发现R没有正确读取你的数据而不得不重新做,或者更糟糕的是,在不知不觉中分析出错误的数据。要想预览更多的数据,你也可以在环境面板中点击对象,在你打开的脚本旁边的新选项卡中以电子表格的形式显示。大的文件可能不会完全显示,所以请记住你可能会丢失行或列。
head(edidiv) # 展示开始的几行
tail(edidiv) # 展示最后的几行
str(edidiv) # 告诉你变量是连续的、整数的、分类的还是字符的。
str(object.name)
是一个很好的命令,可以显示你的数据结构。R运行过程中经常出现的错误是:R确定了一个变量是某种类型的数据,而它实际上不是。比如说,你可能有四个研究组,你把它们简单地称为 "1、2、3、4",虽然你知道它应该是一个分类分组变量(即因子(factor)),但R可能认为这是一列包含数字(numeric)(数字)或整数(integer)(整数)数据。如果你的研究组被称为 "一、二、三、四",R可能会认为它是一个字符(character)变量(单词或单词字符串),如果你想比较组间的均值,这不会让你的分析顺利走下去!
你会注意到taxonGroup
变量显示为一个字符变量,但它应该是一个因子(分类变量),所以我们将强制把它变成因子。当你只想访问一个数据框中的一列时,你会在对象名后面附加一个$
标志的变量名。这个语法可以让你查看、修改和/或重新分配这个变量。
head(edidiv$taxonGroup) # 只显示该列的前几行
class(edidiv$taxonGroup) # 告诉你我们要处理的是什么类型的变量:它现在是字符,但我们希望它是一个因子。edidiv$taxonGroup <- as.factor(edidiv$taxonGroup) # 转换某一列的数据类型
在最后一行代码中,as.factor()
函数把你在里面输入的任何值都变成了一个因子(这里,我们指定了要从edidiv
对象中转换taxonGroup
列中的字符值)。然而,如果你只运行箭头右侧的代码,它将会工作一次,但不会修改存储在对象中的数据。通过用箭头将函数的输出赋值给变量,原来的edidiv$taxonGroup
实际上被覆盖了:转换后被存储在对象中。再试着运行class(edidiv$taxonGroup
)--你发现了什么?
# 更多的解释
dim(edidiv) # 展示行数和列数
summary(edidiv) # 关于数据的总结
summary(edidiv$taxonGroup) # 为您提供数据集中的特定变量(列)的总结
计算物种丰富度
我们的edidiv
对象有2000年至2016年在爱丁堡收集的各种物种的发现记录。 为了探索爱丁堡的生物多样性,我们将创建一个图表,显示每个分类组中记录了多少物种。 你可以在Excel中计算物种丰富度,但这有几个缺点,尤其是在处理像我们这样的大数据集时--你没有办法记录你点击了什么,如何排序数据,以及你复制/删除了什么--错误可能会在你不知不觉中发生。而在R中,你有保存的脚本,所以你可以回去检查所有的分析步骤。
物种丰富度是指在一个给定的地方或群体中不同物种的总数量。要知道我们在爱丁堡有多少鸟类、植物、哺乳动物等物种,我们首先需要将edidiv
分成多个对象,每个对象只包含一个分类组的行。我们用dplyr
程序包中的filter()
函数来完成。
Beetle <- filter(edidiv, taxonGroup == "Beetle")
# 函数的第一个参数是数据框,第二个参数是你要过滤的条件。因为我们在这里只想要甲虫,所以我们说:变量 taxonGroup 必须严格等于 (==) Beetle - 丢弃数据集中的其他东西。(R是区分大小写的,所以注意拼写很重要! "beetle "或 "Beetles "在这里是行不通的。)Bird <- filter(edidiv, taxonGroup == "Bird") # 你可以为剩下的分类群创建对象。如果你忘记了物种的名字和拼写,请输入 summary(edidiv$taxonGroup)
你需要对数据中的所有分类群进行这些步骤,这里我们给出了前两个的例子。如果你看到一个错误,说R
无法找到Beetle
或类似的对象,那么很可能是你没有安装和/或加载dplyr
包。返回并使用install.packages("dplyr")
安装它,然后使用 library(dplyr)
加载它。
一旦你为每个分类群创建了对象,我们就可以计算物种丰富度,也就是每个组中不同物种的数量。为此,我们将把两个函数嵌套在一起: unique()
,用于识别不同的物种,和 length()
,用于计数。你可以在控制台中分别尝试一下它们,看看它们返回的结果是什么!
a <- length(unique(Beetle$taxonName))
b <- length(unique(Bird$taxonName))
# 你可以为你的对象选择任何你想要的名字,这里我用了a、b、c、d......为了简洁起见,我用了a、b、c、d......
如果你在控制台中键入a
(或者无论你如何命名你的计数变量),它会返回什么?它是什么意思呢?它应该代表记录中独特的甲虫物种的数量。
再次,计算数据集中其他分类群的物种丰富度。你可能注意到这是相当枯燥的,并且使用了大量的复制和粘贴!-- 在数据集中,这不是特别有效的方法。
创建一个变量并画出它
现在我们有了每个分类群的物种丰富度,我们可以把所有这些值组合成一个向量(vector)。向量是R对象的另一种存储值的类型。相对于数据框,数据框有两个维度(行和列),向量只有一个。当你调用数据框中的一个列时,就像我们之前用edidiv$taxonGroup
调用数据框中的一个列时,你基本上就是在产生一个向量--但你也可以从头开始创建它们。
我们使用c()
函数(c代表的是聚合(concatenate))。我们还可以用names()
函数来添加标签,这样就可以知道数值的来源。
biodiv <- c(a,b,c,d,e,f,g,h,i,j,k) # 我们正在将所有的值串联在一起;注意你计算出的对象名称和它们的名称。
names(biodiv) <- c("Beetle","Bird","Butterfly","Dragonfly","Flowering.Plants","Fungus","Hymenopteran","Lichen","Liverwort","Mammal","Mollusc")
请注意。
<-
和,
后面的空格是为了方便阅读代码而添加的。- 所有的标签都已经缩进到了新的行中--否则这行代码会变得很长,很难读懂。
- 注意检查你的矢量值和标签是否匹配正确--你不会想把甲虫的数量标注为地衣类的数量!你可以在此基础上再加上一个新的标签。保存一个脚本的好处是,我们可以回过头来检查我们确实把甲虫的数量分配给了
a
。更好的做法是给我们的对象起更有意义的名字,比如beetle_sp
、bird_sp
等。 - 如果你用鼠标突出显示一个括号
)
,RStudio
会在你的代码中突出显示其匹配的括号。缺少括号,特别是当你开始像我们之前用length(unique())
之类的嵌套函数时,缺失的括号是你开始写代码时最常见的挫折和错误的来源之一!
我们现在可以用barplot()
函数来可视化物种丰富度。在RStudio中的右下角窗口中显示出图。
barplot(biodiv)
但是有一些不太正确的地方需要修正--没有轴标题,不是所有的列标签都是可见的,而且植物种类的值(n = 521)超过了y轴上的最高值,所以我们需要扩展它。R的好处在于,你不需要自己想出所有的代码--你可以使用help()
函数,看看需要添加哪些参数。看一下帮助的输出,你需要添加哪些代码?
help(barplot) # 关于barplot()函数的帮助
help(par) # 对于一般绘图的帮助
我们还想保存我们的作图。要做到这一点,请单击 "Plots "窗口中的导出。如果你不更改目录,文件将保存在你的工作目录中。你可以调整尺寸以使条形图看起来像你喜欢的那样,你还应该添加一个有意义的文件名--如果它叫Rplot01.png
,当你以后试图找到该文件时,它将无法提供有效信息。
你也可以通过将代码封装在png()
和dev.off()
函数中来保存你的文件,这两个函数分别表示打开和关闭绘图设备。
png("barplot.png", width=1600, height=600) # 查看此功能的帮助:你可以自定义图像的大小和分辨率
barplot(biodiv, xlab="Taxa", ylab="Number of species", ylim=c(0,600), cex.names= 1.5, cex.axis=1.5, cex.lab=1.5)
dev.off()
# cex代码在大于1时增加字体大小(小于1时减小)
图1 爱丁堡几个分类群的物种丰富度。记录基于2000-2016年期间国家生物资源网门户的数据。
创建一个数据框并且画出它
在上一节中,我们创建了向量,即一系列的值,每个值都有一个标签。这种对象类型适用于只处理一类值的时候。但是,通常情况下,你会有多个变量,并且有多个数据类型--例如,有些是连续的,有些是分类的。在这种情况下,我们使用数据框架对象。数据框架是数值的表:它们有行和列的二维结构,其中每一列可以有不同的数据类型。 例如,一个名为 "Wingspan "的列将有不同鸟类上测量的数值(21.3,182.1,25.1,8. 9),而 "物种 "一列中的 "物种 "将包含有物种名称的字符值("麻雀"、"金鹰"、"欧亚翠鸟"、"红喉蜂鸟")。比如说它们都是数值型的,并且在行数上长度相同。
关于良好数据管理的注意事项:永远保留一份原始数据的副本,就像你第一次收集的那样。在R脚本中操作一个文件的好处是,修改是在脚本上,而不是在数据中。对于精通Photoshop的人来说,这就像在图片上添加图层一样:你并没有改变原始照片,只是在上面创建新的东西。话虽如此,但如果你写了一长段代码来整理一个大数据集并准备好分析,你可能不想每次需要访问干净的数据时都要重新运行整个脚本。因此,最好将你的新对象保存为一个新的csv文件,只需一个命令就可以加载,准备就绪。现在,我们将用我们的物种丰富度数据创建一个数据框,然后使用write.csv()
保存它。
我们将使用data.frame()
函数,但首先我们将创建一个包含所有分类群名称的对象(一列)和另一个包含每个分类群的物种丰富度的所有值的对象(另一列)。
# 创建一个名为 "taxa "的对象,该对象包含所有的taxa名称。
taxa <- c("Beetle","Bird","Butterfly","Dragonfly","Flowering.Plants","Fungus","Hymenopteran","Lichen","Liverwort","Mammal","Mollusc")
# 把这个对象变成一个因子,即分类变量
taxa_f <- factor(taxa)# 将一个对象中的物种数量的所有值合并起来,称为丰富度。
richness <- c(a,b,c,d,e,f,g,h,i,j,k)# 从两个向量中创建数据框
biodata <- data.frame(taxa_f, richness)# 保存文件
write.csv(biodata, file="biodata.csv") # 它将被保存在你的工作目录中
如果我们想使用数据框创建并保存一个条形图,我们需要稍微改变一下代码--因为数据框可以包含多个变量,所以我们需要告诉R我们希望它绘制的是哪个变量。就像之前一样,我们可以使用 $
指定数据框中的列。
png("barplot2.png", width=1600, height=600)
barplot(biodata$richness, names.arg=c("Beetle","Bird","Butterfly","Dragonfly","Flowering.Plants","Fungus","Hymenopteran","Lichen","Liverwort","Mammal","Mollusc"),xlab="Taxa", ylab="Number of species", ylim=c(0,600))
dev.off()
几个重要术语
- 参数(argument): 函数的一个元素,可以是必需的,也可以是可选的,它可以是函数的一个元素,它可以是告知或改变函数的工作方式。例如,它可以是函数应该从哪个文件路径导入或保存到哪个文件路径:
file = "file-path"
。它可以修改绘图中的颜色:col = "blue"
。你可以通过在命令行中键入?function-name
来查找函数的参数。 - 类型(class): 变量中包含的数据类型:通常是字符(文本/文字),数字(数字),整数(整数),或因子(分组值,当你的数据中包含多个观测点或治疗方法时,非常有用)。
- 命令(command):执行一个动作的代码块,通常包含一个或多个函数。您可以通过按 "运行 "或使用键盘快捷键如
Cmd+Enter
、Ctrl+Enter
或Ctrl+R
来运行命令。 - 注释(comment):脚本中以
#
开头的文本,不是作为命令来读的。注释使你的代码可以被其他人阅读:用它们来创建你的脚本中的章节,并对分析的每一步进行注释。 - 控制台(console): 你可以直接在命令行中输入代码的窗口(
2+2
跟着Enter
会返回4
),你运行的命令的输出会在这里显示。 - 数据框(data frame):R对象的一种类型,由许多行和列组成,类似于Excel电子表格。通常情况下,列是不同的变量(如年龄、颜色、体重、翼展),行是这些变量的观测值(如鸟类1、鸟类2、鸟类3)。
- csv文件(csv file):一种常用于在R中导入数据的文件类型,不同变量的值被压缩在一起(一个字符串,或每行的值行),并且只用逗号分隔(表示列)。R也可以接受Excel(.xlsx)文件,但我们不建议使用,因为格式化错误比较难避免。
- 函数(function):执行一个动作的代码,也就是你在R中做任何事情的方式,通常是接收一个输入,对它做一些事情,然后返回一个输出(一个对象,一个测试结果,一个文件,一个绘图)。有用于导入、转换和处理数据的函数,有用于执行特定计算的函数(你能猜到min(10,15,5)和max(10,15,5)会返回什么吗?
- 对象(object):R的构件。如果R是一种口语化的语言,函数是动词(动作),对象是名词(这些动作的主体或对象!)。对象是通过键入它们的名字来调用的,没有引号。对象存储数据,可以采取不同的形式。最常见的对象是数据框和向量,但还有很多,比如列表和矩阵。
- 包(package):为R提供功能的函数包,很多包都是R自动附带的,其他的包你可以根据特定的需要下载。
- 脚本(script):是一种脚本。类似于文本编辑器,这是你编写和保存代码的地方,以便将来参考。它包含了代码和注释的混合,并以简单的文本文件的形式保存,你可以方便地分享,这样任何人都可以复制你的工作。
- 向量(vector):R对象的一种类型,有一个维度:它存储的是一行的值,可以是字符、数字等。
- 工作目录(working directory):你的计算机上与当前R会话链接的文件夹,你从那里导入数据并保存文件。你可以在会话开始时用setwd()函数设置它。
- 工作空间(workspace):这是你的虚拟工作环境,它包含了你所加载的包的所有函数,你所导入的数据以及你所创建的对象等等。通常情况下,最好是以一个干净的工作空间开始一个工作会话。