之前我们已经了解了如何去提取行、列数据。这部分我们讲讲如何筛选自己想要的数据。生统常见的一个数据提取问题就是,提取某某处理的那部分数据进行一些检验。比如,在有3种种子的数据中,提取出1号种子对应的数据。这时候,尽管我们可以根据1号种子的数字索引来提取,但这终归不是一个好的方法,因为一旦数据是打乱的,我们就无法知道正确的数字索引,从而进行提取了。所以,这时候,我们就应该使用我们之前讲过的逻辑运算符来进行操作。
顺便提下,我们之前在介绍数据框的时候,把行叫做观测,而把列叫做变量。所以我们在提取行的时候,就是在提取我们感兴趣的观测,而在提取列的时候,就是在提取我们感兴趣的变量。为什么我要翻来覆去地说这个呢,是因为我觉得以行作为观测,列作为变量是一个比较好的呈现数据的方式,也是后面很多我们生统要用到的包需要的格式。也是后面我们在说长宽数据转换时候要再次提到的一点。我们再来看一下糖尿病人的例子。
> patientID <- c(1, 2, 3, 4)
> age <- c(25, 34, 28, 52)
> diabetes <- c("Type1", "Type2", "Type1", "Type1")
> status <- c("Poor", "Improved", "Excellent", "Poor")
> patientdata <- data.frame(patientID, age, diabetes, status)
> patientdata
patientID age diabetes status
1 1 25 Type1 Poor
2 2 34 Type2 Improved
3 3 28 Type1 Excellent
4 4 52 Type1 Poor
这里是 4 行,就是 4 个观测值,4 个病人。这里有 4 列,4 个变量,就是用 4 个不同地指标去衡量了这些病人。当然,我们也会遇见不是这样格式的数据,比如我们在第五次生统作业上遇见的那个用药的数据集
> test2 <- read.table("rawdata/test2.txt",header = T)
> head(test2)
control low middle high
1 20.79 22.22 28.56 31.93
2 22.91 24.74 28.67 37.94
3 27.21 21.53 25.28 39.76
4 19.34 19.66 30.28 27.94
5 17.85 25.89 23.13 29.65
6 23.79 29.10 23.47 34.23
这个数据集是 15 行,4 列。但我们并不能说我们做了 15 个观测,应用了 4 个变量。实际上,我们根据题目可知,总共是 60 只小鼠,只用了 1 个变量,即用药的浓度。你会发现这个数据集的每一行都不是同一只老鼠,但前面的糖尿病人数据集,每一行都是同一个病人,所以我们可以说每一行都是一个观测。
初次学 R 的人,对于这种数据的结构可能会感到困惑。不过不要紧,数据处理多了,就会慢慢清晰起来。
顺便提一下,现在生物学的数据跟传统社会学的数据有一个很大的不同就是,社会学的数据往往是低维度,高观测,而生物学的数据则恰好相反,是高维度,低观测的。这里的维度指的就是变量。举个例子,比如你要分发问卷给别人来统计大家对你的产品感不感兴趣,你可能在问卷上只有 2 个问题(2个变量,2个维度),但你却分发给了 1w 个人(1w 个 观测)。生物学的例子就好比,你对 100 个植株进行了 50w 个SNP位点的分析,这里就是 100 个观测,50w 的维度。数据结构的不同,就会导致分析方法的不同。
由于生统的数据列数最多也就 4,5 列,加上整列的提取并不需要逻辑运算符,所以后面的提取不涉及到列的提取。同时,为了让大家加深印象,我会交叉地用行以及观测这两个名词。
利用 [] 来提取感兴趣的观测
我们之前在向量里面提到过,如何提取符合条件的数据,这里运用的方法也是一样的,也是利用 which
或者 TRUE
来提取。不过在提取数据框数据的时候,我有一个小建议,就是分步完成你的提取任务。我们还是拿糖尿病人的数据集为例子。比如我们希望提取出年龄大于 30 岁的糖尿病人的数据。
# 先得到索引
> patientdata$age > 30
[1] FALSE TRUE FALSE TRUE
> which(patientdata$age > 30)
[1] 2 4
# 把索引输入 [] 里面
> patientdata[patientdata$age > 30,]
patientID age diabetes status
2 2 34 Type2 Improved
4 4 52 Type1 Poor
> patientdata[which(patientdata$age > 30),]
patientID age diabetes status
2 2 34 Type2 Improved
4 4 52 Type1 Poor
# 有时候嫌得到索引那步比较长,就可以把索引结果存为一个变量
> result <- patientdata$age > 30
> patientdata[result,]
patientID age diabetes status
2 2 34 Type2 Improved
4 4 52 Type1 Poor
patientdata$age > 30
提取出来的索引值顺利能够放入数据框 [] 的逗号前面是因为我们之前提到过,数据框每列是等长的。想象下,我们有 4 个观测,我们我们用patientdata$age
提取出来的,实际上是一串有 4 个值的向量,我们对向量进行了逻辑运算符,然后得到了 4 个 TRUE 或者 FALSE值,然后我们就可以把这些 TRUE 或者 FALSE 值和我们的观测一一对应。从而提出我们想要的观测。
事实上,在利用索引提取的时候,我还犯了个小错误,就是把索引输入到了错误的数据框里面,但并没有报错。
> test2[result,]
control low middle high
2 22.91 24.74 28.67 37.94
4 19.34 19.66 30.28 27.94
6 23.79 29.10 23.47 34.23
8 18.53 18.64 29.62 29.13
10 20.14 25.49 34.64 36.15
12 19.36 22.69 29.22 24.07
14 24.13 20.36 35.12 35.24
这个故事告诉我们的是,索引得到的只是一串数字,他并不跟你产生这个索引结果的数据集有一毛钱的关系。
不要认为 R 的命令是黑箱,一步步地去拆解命令,你就可以很清晰地理解。
如果我们想要两个条件呢,即年龄大于30岁,且犯的是 Type I 型糖尿病呢。年龄大于 30 用的是 >
,I 型糖尿病用的是等于 ==
,那且是什么呢。就是我们之前提到的与或非了。
运算符 | 描述 |
---|---|
x | y | x或y |
x & y | x和(且)y |
非的话是
!
,不等于是!=
。不过我们估计是用不到的,所以我这里也就不讲了。
再次来提取我们想要的观测
# 先得到索引
> patientdata$age > 30
[1] FALSE TRUE FALSE TRUE
> patientdata$diabetes == "Type1"
[1] TRUE FALSE TRUE TRUE
> patientdata$age > 30 & patientdata$diabetes == "Type1"
[1] FALSE FALSE FALSE TRUE
# 提取
> patientdata[patientdata$age > 30 & patientdata$diabetes == "Type1",]
patientID age diabetes status
4 4 52 Type1 Poor
我们还可以在提取我们想要的观测的同时,提取一部分变量(列)出来
> patientdata[patientdata$age > 30,c("age","status")]
age status
2 34 Improved
4 52 Poor
利用subset来提取
前面的那番操作大家可能会感觉写的有点长,那有没有一些简写呢,事实上是有的。你可以利用 R 基本包的 subset
函数来进行跟上面一模一样的操作。
别忘了用 ? 来看看这个函数
有些人可能会提到用
attach
这个函数把数据框添加到 R 的搜索路径中,但实际上我不太推荐这样,因为一旦你要完成有许多个数据框的作业,而你又忘了detach,那么很有可能造成你不同数据框的不同变量之间的混淆。
subset
第一个要输入的参数是你的数据框,第二个要输入的参数是你对于观测(行)的筛选,可以用逻辑运算符串联,第三个可选择输入的是你要选择的列(变量)。跟之前一样的筛选条件,不过这次用的是 subset
函数。
# 年龄大于30岁
> subset(patientdata, age > 30)
patientID age diabetes status
2 2 34 Type2 Improved
4 4 52 Type1 Poor
# 年龄大于30,且 I 型糖尿病
> subset(patientdata, age > 30 & diabetes == "Type1")
patientID age diabetes status
4 4 52 Type1 Poor
# 年龄大于30,且 I 型糖尿病的病人的年龄和病情
> subset(patientdata, age > 30 & diabetes == "Type1",c("age","status"))
age status
4 52 Poor
网友评论