R语言系列1:数据结构、数据导入和常用函数

R语言系列1:数据结构、数据导入和常用函数


此文内容为《R语言实战》的笔记,人民邮电出版社出版。

从高中电脑课学VB开始,大一课内开始学习C++,到后来大二为了数模学习Matlab,到大三为了搞深度学习自学Python,到研究生之初学习Stata——选择一门语言对我来说就像是小时候玩冒险岛,到10级的时候是转战士好还是弓箭手好一般的纠结。我查阅了很多B乎的文章,最后觉得可能R比较合适现在的我。

作为从Python转进来R的新手,我把可能会用经常需要用到或经常需要查阅的代码贴上来,主要是为了日后方便查找,就像“字典”一样。推文的顺序与教材不同,为了简洁,我还会删除一些我个人认为不太重要的章节。我还会按照自己的学习进度发布文章,请读者见谅。

本文章仅供学习参考,请勿转载,侵删!


目录

  • 第2章 创建数据集
    • 2.1 数据集的概念
    • 2.2 数据结构
      • 2.2.1 向量
      • 2.2.2 矩阵
      • 2.2.3 数组
      • 2.2.4 数据框
        • A. attach(), detach(), with()
        • B. 实例标识符
      • 2.2.5 因子
      • 2.2.6 列表
    • 2.3 数据的输入
      • 2.3.1 从分隔符文件导入数据
      • 2.3.2 导入Excel数据
      • 2.3.3 导入Stata数据
    • 2.5 处理对象的常用函数

第2章 创建数据集

按照个人要求的格式创建含有研究信息的数据集。在R中,这个任务包括两步:

  • 选择一种数据结构来储存数据
  • 将数据输入或导入到这个数据结构中

2.1 数据集的概念

数据集是由数据构成的一个矩形数组,行表示观测,列表示变量。

2.2 数据结构

R拥有的数据结构有:

  • 标量
  • 向量
  • 矩阵
  • 数组
  • 数据框
  • 列表

在R中,对象(object)是指可以赋值给变量的任何事物;数据框(data frame)是R中用于储存数据的一种结构:列表示标量,行表示观测;因子(factor)是名义型标量或有序变量。

2.2.1 向量

向量是用于储存数值型、字符型或逻辑型数据的一维数组。执行组合功能的函数c()可以用来创建向量:

a <- c(1, 2, 5, 3, 6, -2, 4)
b <- c("one", "two", "three")
c <- c(TRUE, TRUE, TRUE, FALSE, TRUE, FALSE)

标量是只含一个元素的向量,例如

f <- 3
g <- "US"
h <- TRUE

通过在方括号中给定元素所处的位置的数值,可以访问向量中的元素,例如:

a <- c("k", "j", "h", "a", "c", "m")
a[3]
## [1] "h"

最后一个语句中使用的冒号用于生成一个数值序列,例如a <- c(2:6)等价于a <- c(2, 3, 4, 5, 6)


2.2.2 矩阵

矩阵是一个二维数组,只是每个元素都有相同的模式(数值型、字符型或逻辑型)。可以通过matrix()创建矩阵,一般使用格式为:

mymatrix <- matrix(vector, nrow=number_of_rows, ncol=number_of_columns,
                   byrow=logical_value, dimnames=list(char_vector_rownames, char_vector_colnames))

其中,vector包含了矩阵的元素,nrowncol用以指定行和列的维数,dimnames包含了可选的、以字符型向量表示的行名和列名。选项byrow则表明矩阵以行填充还是以列填充,默认情况下按行填充(TRUE)

y <- matrix(1:20, nrow = 5)
y
##      [,1] [,2] [,3] [,4]
## [1,]    1    6   11   16
## [2,]    2    7   12   17
## [3,]    3    8   13   18
## [4,]    4    9   14   19
## [5,]    5   10   15   20
cells <- c(1,26,24,28)
rnames <- c("R1", "R2")
cnames <- c("C1", "C2")
mymatrix <- matrix(cells, nrow = 2, dimnames = list(rnames, cnames))
mymatrix
##    C1 C2
## R1  1 24
## R2 26 28

我们可以用下标和方括号来选择矩阵中的行和列。X[i,]指定X中的第i行,X[,j]指定X中的第j列。X[i,j]指定第i行第j列个元素。选择多个行和列时,下标i和j可以为数值型向量。

x <- matrix(1:10, nrow = 2, ncol = 5)
x
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10
x[2,]
## [1]  2  4  6  8 10
x[,3]
## [1] 5 6
x[1, c(4,5)]
## [1] 7 9

矩阵都是二维的,和向量类似,矩阵也只能包含一种数据结构。当维度超过2时,可以考虑使用数组;当数据类型超过1种时,可以考虑使用data frame。


2.2.3 数组

数组与矩阵类似,但维度可以大于2,可以通过array创建一个数组:

myarray <- array(vector, dimensions, dimnames)

其中,vector包含了数组中的数据;dimensions是一个数值型向量,给出了维度下标的最大值;dimnames是可选的:

dim1 <- c("A1", "A2")
dim2 <- c("B1", "B2", "B3")
dim3 <- c("C1", "C2", "C3", "C4")
z <- array(1:24, c(2,3,4), dimnames = list(dim1, dim2, dim3))
z
## , , C1
## 
##    B1 B2 B3
## A1  1  3  5
## A2  2  4  6
## 
## , , C2
## 
##    B1 B2 B3
## A1  7  9 11
## A2  8 10 12
## 
## , , C3
## 
##    B1 B2 B3
## A1 13 15 17
## A2 14 16 18
## 
## , , C4
## 
##    B1 B2 B3
## A1 19 21 23
## A2 20 22 24

可见,数组只是矩阵的自然推广,而且数据结构也只能有一种。


2.2.4 数据框

由于不同列可以包含不同模式的数据,数据框的概念比矩阵更为一般。数据框是你会在R中最常见的数据结构。、

数据框可以通过命令data.frame()创建:

mydata <- data.frame(col1, col2, col3,...)

其中的列向量col1col2col3可以为任何类型(字符、数值、逻辑)。每一列的列名可以用函数names指定:

patientID <- c(1, 2, 3, 4)
age <- c(24, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improve", "Excellent", "Poor")
patientdata <- data.frame(patientID, age, diabetes, status)
patientdata
##   patientID age diabetes    status
## 1         1  24    Type1      Poor
## 2         2  34    Type2   Improve
## 3         3  28    Type1 Excellent
## 4         4  52    Type1      Poor

其中,每一列的数据类型必须一样,但不同列的可以不一样。为了方便讨论,数据框的有时候被称为变量

选取数据框的元素有很多种。你可以使用前面提到的方括号的方法,也可以直接指定列名:

patientdata[1:2,]
##   patientID age diabetes  status
## 1         1  24    Type1    Poor
## 2         2  34    Type2 Improve
patientdata[,1:2]
##   patientID age
## 1         1  24
## 2         2  34
## 3         3  28
## 4         4  52
patientdata[c("diabetes", "status")]
##   diabetes    status
## 1    Type1      Poor
## 2    Type2   Improve
## 3    Type1 Excellent
## 4    Type1      Poor

你也可以使用记号 $ 来选取一个给定数据框中的某个特定的变量:

patientdata$age
## [1] 24 34 28 52

如果想生成糖尿病类型diabetes和病情status的列联表,可以使用下面的命令:

table(patientdata$diabetes, patientdata$status)
##        
##         Excellent Improve Poor
##   Type1         1       0    2
##   Type2         0       1    0
A. attach()、detach()和with()

每个变量名前面都键入一次patientdata非常麻烦,所以可以使用attach()detach()with()来简化你的代码。

1. attach 函数。 attach() 可以将数据框添加到R的搜索路径中。R遇到一个变量名后,会检查搜索路径中的数据框,例如:

summary(patientdata$age)
plot(patientdata$patientID, patientdata$age)

就等同于

attach(patientdata)
  summary(age)
  plot(patientID, age)
detach(patientdata)

其中,detach()用于将搜索框从搜索路径中移除。需要注意的是,detach()是可以省略的,但在写程序的时候加上是良好的习惯。

重要的是,如果原始文件中已经存在名为age或者patientID的变量,那么原变量会优先于数据框中的列取得优先权

2. with 函数。另外一种方法是使用with()函数。可以这么写:

with(patientdata, {
  print(summary(age))
  plot(patientID, age)
})

这种情况下,{}之间的语句都针对patientdata运行,就不许担心变量名和列名冲突了。

with()的局限性在于,赋值仅在函数的括号内生效。例如:

with(patientdata, {
  stats <- summary(age)
  stats
})
stats

是会报错的,因为stats仅仅存在于with()环境中。这时候需要使用特殊赋值 <<- 代替标准的赋值符 <-,就可以把对象保存到 with() 外:

with(patientdata, {
  stats <<- summary(age)
  stats
})
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    24.0    27.0    31.0    34.5    38.5    52.0
stats
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    24.0    27.0    31.0    34.5    38.5    52.0

相对于attach(),更多的教材推荐使用with(),这只是个人习惯问题。

B. 实例标识符

在数据框中,病人编号(patientID)用于区分不同的个体。在R中,实例标识符(case identifier)可通过数据框操作函数中的rowname选项指定,例如:

patientdata <- data.frame(patientID, age, diabetes, status, row.names = patientID)

那么R就会将patientID作为R标记各类打印输出所用的变量。


2.2.5 因子

变量了可以归结为名义型有序型连续型

  • 名义型变量是没有顺序之分的类别变量,例如糖尿病类型Diabetes(Type1, Type2),即使在数据中前者编码为1、后者编码为2,也不意味着二者是递进关系。

  • 而病情Status(poor, improved, excellent)则是顺序型的。

  • 连续型变量可以呈现为一种某个范围的任意值。

在R中,类别(名义型)变量有序类别(有序型)变量均称为因子(factor)。因子非常重要,它决定了数据的分析方式和视觉呈现效果。

函数factor()以一个整数向量的形式存储类别值,整数的取值范围为[1,...,k],同时一个由字符串组成的内部向量将映射到这些整数上。例如:

diabetes <- c("Type1", "Type2", "Type1", "Type1")
diabetes <- facor(diabetes)

将此向量储存为(1,2,1,1),并在内部将其关联为“Type1=1”、“Type2=2”。针对diabetes的任何分析都会将其作为名义型变量对待。

要表示有序变量,则需要使用factor()函数内的ordered=TRUE,例如:

status <- c("Poor", "Improve", "Excellent", "Poor")
status <- c(status, ordered=TRUE)

会把status编码为(3, 2, 1, 3)。对于字符型向量,因子水平默认按照字母顺序创建,即“Poor=3”、“Improved=2”、“Excellent=1”。你也可以通过levels改变因子的顺序:

status <- c("Poor", "Improve", "Excellent", "Poor")
status <- c(status, ordered=TRUE, levels=c("Poor", "Improved", "Excellent"))

那么就会将status编码为:“Poor=1”、“Improved=2”、“Excellent=3”

数值型变量可以用levelslabels来编码因子,例如男性编码为1,女性编码为2,那么:

sex <- facotr(sex, levels=c(1,2), labels=c("Male", "Female"))

把变量了转换成一个无序因子。

总的来说:

patientID <- c(1, 2, 3, 4)
age <- c(24, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improve", "Excellent", "Poor")
diabetes <- factor(diabetes)
status <- factor(status, ordered = TRUE, levels = c("Poor", "Improved", "Excellent"))
patientdata <- data.frame(patientID, age, diabetes, status)
str(patientdata)
## 'data.frame':    4 obs. of  4 variables:
##  $ patientID: num  1 2 3 4
##  $ age      : num  24 34 28 52
##  $ diabetes : Factor w/ 2 levels "Type1","Type2": 1 2 1 1
##  $ status   : Ord.factor w/ 3 levels "Poor"<"Improved"<..: 1 NA 3 1

2.2.6 列表

列表(list)是R数据类型中最为复杂的一种。列表就是一些对象的有序结合,允许你整合若干对象到单个对象名下。可以使用list()创建列表:

mylist <- list(object1, object2, ...)

其对象可以是目前为止提到的任何结构。还可以为列表中的对象命名:

mylist <- list(name1=object1, name2=object2, ...)

例如:

g <- "My First List"
h <- c(25:30)
j <- matrix(c(1:10), nrow = 2)
k <- c("one", "two", "three")
mylist <- list(title=g, h, matrix=j, English=k)
mylist
## $title
## [1] "My First List"
## 
## [[2]]
## [1] 25 26 27 28 29 30
## 
## $matrix
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10
## 
## $English
## [1] "one"   "two"   "three"

可以通过双重括号指明某个成分的数字或名称来访问列表中的元素,例如mylist[[3]]mylist[["matirx"]]均表示mylist的第三个元素。对于命名的成分,也可以用mylist$matrix来进行引用,例如:

mylist[[3]]
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10
mylist[["matrix"]]
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10
mylist$matrix
##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8   10

R中有很多函数的运行结果都是以列表的形式返回的,这是一个十分重要的数据结构。


2.3 数据的输入


2.3.1 从带分隔符的文本文件中导入数据

可以使用read.table()从带分隔符的文本中导入数据。此函数可以读入一个表格格式的文件并将其保存为一个数据框,语法为:

mydataframe <- read.table(file, options)

其中,options是控制如何处理数据的选项,请查看help。

2.3.2 导入Excel数据

使用xlsx包可以读取Excel数据,首先在Console运行:

install.packages("xlsx")

然后运行:

library(xlsx)
read.xlsx(file, sheetIndex, header=TRUE)

其中,file是对应的xlsx文件路径;sheetIndex指定第几张工作表;header指定第一行是否为变量名。详细见help。

2.3.3 导入Stata数据

可以使用readstata13包,然后运行:

library(readstata13)
read.dta13(file)

即可。具体的选项请看help。


2.5 处理对象的实用函数

处理对象的常用函数有:

length(object)        # 显示对象中元素/成分的数量
dim(object)           # 显示对象的维度
str(object)           # 显示某个对象的结构
class(object)         # 显示对象的类或类型
mode(object)          # 显示对象的模式
names(object)         # 显示对象中各成分的名称
c(object1,...)        # 将对象合并为一个向量
cbind(object1,...)    # 按列合并对象
rbind(object1,...)    # 按行合并对象
object                # 输出某个对象
head(object)          # 列出某个对象的开始部分
tail(object)          # 列出某个对象的最后部分
ls()                  # 显示当前对象列表
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343