1. 数据结构

本节介绍 R 的数据类型,包括 data.frame 相关的重要命令;也给出了转换数据类型的函数。

1.1. 数据类型

R 中标志的数据类型有(部分在下文详细介绍):

  • 数字:numeric

  • 字符:character

  • 向量:vector

  • 矩阵:matrix

  • 数据框:data.frame

  • 因子:factor

  • 逻辑:logical

1.1.1. 类型判断与转换

对于上述的每个类型的缩写 abbr,对应的判断与转换函数:

  • 判断:is.{abbr}(),例如判断是否是数字 is.numeric()

  • 转换:as.{abbr}()

[1]:
tmp <- c(1:4)
tmp.ch <- as.character(tmp)
print(list(tmp, tmp.ch))
[[1]]
[1] 1 2 3 4

[[2]]
[1] "1" "2" "3" "4"

此外,还有 class() 与 typeof() 函数可以参考:

[2]:
print(c(class(tmp),
        typeof(tmp)))
[1] "integer" "integer"

1.1.2. 经典的数据类型

由一系列数据组成的变量,按照通常数据处理的分类,有:

  • 数值变量(或定量变量,quantitative):

    • 连续型(continuous):又称定比。比如试卷在班级的及格率,其可以是 \([0,1]\) 之间的任意值。连续型变量内各数据间的大小(或优劣)关系是显然的。

    • 离散型(discrete):又称定距。比如班级的同学个数。这类变量常常是通过计数得到的,其任两个数据之间的差值必定为某基础值的整数倍,如不可能有 16.5 个同学。

  • 非数值变量(或定性变量,qualitative):

    • 类别型(categorical):又称定类。比如同学的主修专业。这类变量中各数据点往往是字符,互相之间无优劣关系。

    • 有序型(ordinal):又称定序。比如成绩的等级,ABCD。互相之间有优劣顺序。

对于一般的二维数据集,其行与列在不同领域的称呼不同:

领域

统计学(本文)

观测(observation)

变量(variable)

数据库

记录(record)

字段(field)

数据挖掘/机器学习

示例(example)

属性(attribute)

1.2. 因子(factor)

在 R 中,将非数值变量统称为因子(factor),并分为有序因子与无序因子两种。例如,我们有主修专业数据:

[3]:
prog <- c("Math", "Engineering", "Social Science", "Math")
tmp <- factor(prog)

print(levels(tmp))  # 返回因子的类别
[1] "Engineering"    "Math"           "Social Science"
[4]:
str(tmp)  # 显示因子类别数。str 是 structure 的缩写
 Factor w/ 3 levels "Engineering",..: 2 1 3 2

从上面的 str(tmp) 中可以看到,Level 1对应 Engineering,2对应Math,3对应Social Science。因为这是根据字符串首字母顺序编号的。

如果你想从数值记录的变量生成一个因子,使用参数 levels 与 labels :

[5]:
tmp <- factor(c(1, 2, 3, 1), levels=c(1,2,3),
              labels=c("Math", "Engineering", "Social Science"))
str(tmp)
 Factor w/ 3 levels "Math","Engineering",..: 1 2 3 1

如果想把有序型变量转成因子,并指定顺序,可以使用参数 order= :

[6]:
tmp <- factor(c("A", "B", "C", "B", "C", "A"), order=TRUE,
             levels=c("B", "A", "C"))
str(tmp)
 Ord.factor w/ 3 levels "B"<"A"<"C": 2 1 3 1 3 2

还有一点需要注意:在我们对数据框进行了合并、筛选等处理后,因子可能不再含有全部水平对应的值(比如原有3个水平,但其中一个水平的值都被筛除了)。这时候需要使用 droplevels() 命令来抛弃多余的水平:

dt["factor"] <- droplevels(dt["dactor"])

1.3. 同类元素集:向量、矩阵与数组

同类型元素的一维堆叠叫向量,二维堆叠叫矩阵。更高维的叫数组。

1.3.1. 向量

如果向量只有一个元素,称为标量。

[7]:
vector <- c(1:3)
print(vector)
[1] 1 2 3

1.3.2. 矩阵

矩阵的建立方法就复杂一些:

[8]:
# matr <- matrix(d, nrow=N, ncol=N, byrow=T/F, [dimnames=list(rownamestr,colnamestr)])

matr <- matrix(1:12, nrow=3, ncol=4, byrow=T)
print(matr)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    5    6    7    8
[3,]    9   10   11   12
[9]:
# 按列填充,并加上行名与列名
rowname <- c('A', 'B', 'C')
colname <- c(as.character(1:4))  # 转为字符串
matr <- matrix(1:12, nrow=3, ncol=4, byrow=F, dimnames=list(rowname, colname))
print(matr)
  1 2 3  4
A 1 4 7 10
B 2 5 8 11
C 3 6 9 12

下标的使用很简单。

[10]:
print(matr[2,])  # 第二行
 1  2  3  4
 2  5  8 11
[11]:
matr[2:3,c(1,3)]  # 第2、3行,第1、3列
13
B28
C39
[12]:
matr[,-c(1:2)]  # 除前2列外所有列
34
A7 10
B8 11
C9 12

几个注意点:

  • 矩阵的对应元素乘法是“*”。如果要使用线性代数中的矩阵乘法,使用 “%*%”。

  • 矩阵的转置:t(matr)

  • 矩阵的逆:solve(matr)。该函数 solve(a, b) 是用于求解线性方程组 aX=b 的,b 缺省时求逆。

1.3.3. 数组

array() 语法类似于 matrix() 。

[13]:
# arr <- array(vector, dimensions, dimnames)
# dimensions: 指定数组有几维,以及各维的长度

arr <- array(1:24, c(2, 3, 4),
             dimnames=list(c('A1', 'A2'), c('B1', 'B2','B3'), c('C1', 'C2', 'C3', 'C4')))
print(arr)
, , 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

1.4. 列表

列表是一系列变量的有序组合。声明方式:

lst <- list(name1=obj1, name2=obj2, ...)
[14]:
lst <- list(prog=c("Math", "Engineering"), gender=c(1, 2), grade="No grade")
print(lst)
$prog
[1] "Math"        "Engineering"

$gender
[1] 1 2

$grade
[1] "No grade"

你可以通过美元符来调用它们,如:

[15]:
print(lst$prog)
[1] "Math"        "Engineering"

1.5. 数据框:data.frame

数据框是多个等长向量的按列堆叠。这是 R 中最常用的数据结构。由于此内容的重要性,我将其提升了一级大纲。

[16]:
# df <- data.frame(<col1, col2, ...>, [row.names=])

name <- c('Allen', 'Bruth', 'Chris', 'Daisy')
age <- c(20:23)
gender <- c('Male', 'Male', 'Male', 'Female')

df <- data.frame(name, age, gender)
print(df)
   name age gender
1 Allen  20   Male
2 Bruth  21   Male
3 Chris  22   Male
4 Daisy  23 Female
[17]:
# 指定唯一标识的一列作为行名
df <- data.frame(name, age, gender, row.names=name)
print(df)
       name age gender
Allen Allen  20   Male
Bruth Bruth  21   Male
Chris Chris  22   Male
Daisy Daisy  23 Female

数据框默认按照列进行选取:

[18]:
df[c(1,3)]
namegender
AllenAllen Male
BruthBruth Male
ChrisChris Male
DaisyDaisy Female
[19]:
# 可以按列名选取
df[c("name", "gender")]
namegender
AllenAllen Male
BruthBruth Male
ChrisChris Male
DaisyDaisy Female
[20]:
# 可以通过标识符 '$' 选取
print(df$age)
[1] 20 21 22 23
[21]:
# 双参数时,先行后列
print(df[1:3,"gender"])
[1] Male Male Male
Levels: Female Male

1.5.1. 临时环境:attach() 与 with()

df$age 从语法上说很清晰,但是可读性却不高。因为我们一般总是在处理一个数据集,因此‘df’显得多余。这里可以借助 attach()/detach() 命令组:

*请注意:此命令出于容错性、可读性考虑,在任何情况下均__不建议__使用。*

[22]:
# 删除原有的全局变量,否则 age 会覆盖 df$age
rm(age, gender, name)

attach(df)
print(age)
detach(df)
[1] 20 21 22 23

或者使用 with() 命令:

[23]:
tmp <- 1
with(df, {
    print(name)
    tmp <<- 2  # 特殊赋值符可以传值到 with() 之外
})
print(tmp)
[1] Allen Bruth Chris Daisy
Levels: Allen Bruth Chris Daisy
[1] 2

1.5.2. 更多内容

更多关于数据管理和 data.frame 处理的内容在本系列文章的 数据管理 一文中可以找到。