R语言

Lecture02 : R数据结构

罗益民

2024-08-23

本节内容一览

  • R编程必知
    • 工作空间
    • 控制台、终端和编辑器
    • 基本语法
  • R数据类型
    • 向量(Vector)
    • 矩阵(Matrix)
    • 数组(Array)
    • 数据框(Data frame)
      • tibble数据框(Tibble)
    • 因子(Factor)
    • 列表(List)

Part01 R编程必知

工作空间

R的工作空间(workspace)是指R语言中的当前工作环境,它存储了所有用户定义的对象,包括向量、矩阵、函数、数据框和列表等。当你在R中创建一个对象或者运行一个函数时,这些对象就会被存储在工作空间中。工作空间中的对象可以在R会话期间随时访问和修改。

如果使用RStudio,一般会针对每个项目在RStudio中单独建立一个“项目”(.RStudio)。 不同项目使用不同的工作空间。

你可以选择将当前的工作空间保存到一个文件中,通常这个文件的扩展名为.RData。这样,你可以在下次启动R时加载这个文件,恢复之前的工作环境。

工作空间

工作目录:在进行数据分析时一般把不同的数据分析项目放在不同的文件夹中,并且设定这个文件夹为当前工作目录。可以使用getwd()函数来查看当前的工作目录,或者使用setwd()函数来改变当前的工作目录。

管理工作空间的常用R命令包括:

getwd() #显示当前的工作目录。
setwd("mydirectory") #将当前的工作目录修改为指定的目录。
ls() #列出当前工作空间中的对象。
dir() #列出当前工作路径下的文件和文件夹
rm(objectlist) #移除(删除)一个或多个对象。
save.image("myfile.RData") #保存工作空间数据到文件中,RData文件又被称为镜像文件。
load("myfile") #从文件中读取工作空间到当前R会话中。
q() #退出R。

以上绝大部分操作也可以通过RStudio用户界面来完成,但推荐大家使用这种命令方式。尽量少用图形界面。

控制台、终端和编辑器

  • 控制台(Console):
    • 显示代码运行结果
    • 快速验证代码和执行命令
    • 输入的代码无法保存
  • 终端(Terminal)
    • 操作系统的终端,一般不用
  • 编辑器(Editor)
    • 编写代码的主要窗口
    • 输入的代码永久保存

基本语法

四则运算

5 + (2.3 - 1.125)*pi/1.1 + 1.23E3
[1] 1238.356
5/3 
[1] 1.666667
5%%3 #取余
[1] 2

算数运算

2^10 #幂运算
[1] 1024
sqrt(6.25) #平方根
[1] 2.5
exp(1) #指数
[1] 2.718282
log(2)#自然对数
[1] 0.6931472
log2(8)#以2为底的对数
[1] 3
log10(2)#以10为底的对数
[1] 0.30103

三角函数

sin(pi/2) 
[1] 1
cos(pi/2) 
[1] 6.123032e-17
tan(pi/4)
[1] 1
asin(1)
[1] 1.570796
acos(0)
[1] 1.570796
atan(1)
[1] 0.7853982

取整

round(1.1234, 2) #四舍五入
[1] 1.12
floor(1.1234) #向下取整
[1] 1
ceiling(1.1234)#向上取整
[1] 2
abs(-3.556632)#绝对值
[1] 3.556632

其它

factorial(5)#阶乘
[1] 120

随机数

runif(1)  # 生成一个[0,1)区间的随机数
[1] 0.4303841
rnorm(10)  # 生成10个均值为0,标准差为1的正态分布随机数
 [1]  1.95663806  0.85523929 -0.52562467  1.54763301 -0.11563081 -1.14099187
 [7] -0.73630351  0.69478471  0.08262082  0.89860668
x <- seq(0.001, 5, length.out = 20)
df(x^2, 1, 5)
 [1] 3.796065e+02 1.378817e+00 6.121583e-01 3.374182e-01 1.975073e-01
 [6] 1.180706e-01 7.133984e-02 4.351240e-02 2.683191e-02 1.676130e-02
[11] 1.062378e-02 6.839344e-03 4.474326e-03 2.974714e-03 2.009360e-03
[16] 1.378361e-03 9.596234e-04 6.776066e-04 4.849362e-04 3.514877e-04

常量

常量是指直接写在程序中的值,包括数值、字符串等。

  • 数值型常量包括整型、单精度、双精度等: 如123, 123.45, -123.45, -0.012, 1.23E2, -1.2E-2等
  • 字符型常量用两个双撇号或两个单撇号包围,如”R”或’RStudio’。 字符型支持中文,如”李明”或’数据’
    • 中文编码主要有GBK编码和UTF-8编码, 有时会遇到编码错误造成乱码的问题, RStudio软件默认采用UTF-8编码
  • 逻辑型常量只有TRUE和FALSE,表示真值和假值。(注意是大写)
  • 缺失值用NA表示,统计计算中经常会遇到缺失值

变量

程序语言中的变量用来保存输入的值或者计算得到的值。 在R中,变量可以保存所有的数据类型, 比如标量、向量、矩阵、数据框、函数等。

变量必需有变量名,程序员必需给变量起名(这是一门艺术)

  • R变量名必须以字母、数字、下划线和句点组成
  • 变量名的第一个字符不能取为数字
  • 变量名区分大小写, q和Q是两个不同的变量名。
  • 变量名举例: x, x1, X, cancer.tab, clean_data, diseaseData

变量的赋值

R用<-符号赋值变量。<-也可以写成=,但是推荐大家用<-

  • R语言的前身S语言就使用了 <- 作为赋值操作符,R继承了这一传统
  • 在R社区中,使用 <- 进行赋值是一种广泛接受的习惯
  • 在函数定义中,使用 <- 而不是 = 可以减少错误,因为 = 在某些上下文中可能会被解释为参数赋值,而不是变量赋值

Part02 R数据类型

向量(Vector)

在R语言中,向量是最基本的数据结构,它是相同类型的元素的集合。

向量是一维的,并且每个元素在向量中都有一个唯一的位置或索引。

使用c()函数来创建向量

#数值型向量
marks <- c(10, 6, 4, 7, 8)
x <- c(1:3, 10:13)
x1 <- c(1, 2)
x2 <- c(3, 4)
x3 <- c(x1, x2) #也可以直接整个两个向量
#字符型向量
chars <- c("R","is","awesome")
#逻辑型向量
booleans <- c(TRUE,FALSE,TRUE,TRUE,FALSE)
marks
[1] 10  6  4  7  8
x
[1]  1  2  3 10 11 12 13
x3
[1] 1 2 3 4
chars
[1] "R"       "is"      "awesome"
booleans
[1]  TRUE FALSE  TRUE  TRUE FALSE

1:3 10:13表示一个连续区间,这是R的一个惯例

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

在R中,位置索引从1开始,和绝大多数语言都不同(从0开始)。

numbers <- c(1:100)
numbers
  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
 [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
 [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
 [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
 [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
 [91]  91  92  93  94  95  96  97  98  99 100
# 取单个元素
numbers[50]
[1] 50
# 取区间
numbers[12:35]
 [1] 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
# 取多个元素
numbers[c(55,78)]
[1] 55 78

矩阵(Matrix)

矩阵是一个二维数组,其中的元素通常是同一数据类型,并且以行和列的形式组织。

矩阵一般用于数值计算, 所以其元素一般是数值。

使用matrix()函数创建矩阵

# data: 矩阵的元素,一般是一个向量
# nrow:行数
# ncol:列数
# byrow:是否按行填充
# dimnames:字符型向量表示的行名和列名
matrix(data = NA, nrow = 1, ncol = 1, byrow = FALSE,
       dimnames = NULL)

举例:

mdat <- matrix(1:20, nrow = 4, ncol = 5, byrow = TRUE,
               dimnames = list(c("row1", "row2","row3","row4"),
                               c("col1", "col2", "col3","col4","col5")))
mdat
     col1 col2 col3 col4 col5
row1    1    2    3    4    5
row2    6    7    8    9   10
row3   11   12   13   14   15
row4   16   17   18   19   20

除了必须的第一个参数外,其余的参数均为可选

matrix(1:4)
     [,1]
[1,]    1
[2,]    2
[3,]    3
[4,]    4
matrix(1:100,nrow = 10)
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    1   11   21   31   41   51   61   71   81    91
 [2,]    2   12   22   32   42   52   62   72   82    92
 [3,]    3   13   23   33   43   53   63   73   83    93
 [4,]    4   14   24   34   44   54   64   74   84    94
 [5,]    5   15   25   35   45   55   65   75   85    95
 [6,]    6   16   26   36   46   56   66   76   86    96
 [7,]    7   17   27   37   47   57   67   77   87    97
 [8,]    8   18   28   38   48   58   68   78   88    98
 [9,]    9   19   29   39   49   59   69   79   89    99
[10,]   10   20   30   40   50   60   70   80   90   100

注意:当使用 matrix()函数创建矩阵时,需要确保提供的数据长度(即向量的长度)是行数和列数乘积的倍数。

如果向量的长度小于行数×列数,则剩余的位置会从头开始循环填充:

matrix(1:5,nrow=2,ncol=4)
     [,1] [,2] [,3] [,4]
[1,]    1    3    5    2
[2,]    2    4    1    3

如果向量的长度大于行数×列数,则剩余的数值会被丢弃:

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

nrow()ncol()函数可以访问矩阵的行数和列数

my_matrix <- matrix(1:100,nrow = 10,byrow = TRUE)
nrow(my_matrix)
[1] 10
ncol(my_matrix) 
[1] 10

dim()函数同时显示行数和列数(dim()可用于任何数据结构)

dim(my_matrix) 
[1] 10 10

矩阵取子集:

my_matrix[1:10] # 1-10个元素
 [1]  1 11 21 31 41 51 61 71 81 91
my_matrix[c(45,67,89)] # 第45,67,89个元素 
[1] 45 67 89

矩阵指定行和列取子集(重要):

my_matrix[1,] # 取第一行
 [1]  1  2  3  4  5  6  7  8  9 10
my_matrix[,1] # 取第一列
 [1]  1 11 21 31 41 51 61 71 81 91
my_matrix[-1,] # 取除了第一行外的所有数值
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]   11   12   13   14   15   16   17   18   19    20
 [2,]   21   22   23   24   25   26   27   28   29    30
 [3,]   31   32   33   34   35   36   37   38   39    40
 [4,]   41   42   43   44   45   46   47   48   49    50
 [5,]   51   52   53   54   55   56   57   58   59    60
 [6,]   61   62   63   64   65   66   67   68   69    70
 [7,]   71   72   73   74   75   76   77   78   79    80
 [8,]   81   82   83   84   85   86   87   88   89    90
 [9,]   91   92   93   94   95   96   97   98   99   100
my_matrix[2:3,c(1,2,3)] # 取2-3行和1-3列
     [,1] [,2] [,3]
[1,]   11   12   13
[2,]   21   22   23
my_matrix[1,1] # 取第一行的第一列的数值
[1] 1

colnames()函数可以给矩阵每列命名,也可以访问矩阵列名,用rownames()函数可以给矩阵每行命名,也可以访问矩阵行名。

my_matrix <- matrix(1:12,ncol = 3,nrow=4 )
colnames(my_matrix) <- c("col1","col2","col3") # 赋值
rownames(my_matrix) <- c("row1","row2","row3","row4") # 赋值
colnames(my_matrix) # 取值
[1] "col1" "col2" "col3"
rownames(my_matrix) # 取值
[1] "row1" "row2" "row3" "row4"

dimnames()函数返回一个列表,包含行名和列名

dimnames(my_matrix)
[[1]]
[1] "row1" "row2" "row3" "row4"

[[2]]
[1] "col1" "col2" "col3"

当有了行名和列名后,就可以使用它们取子集

my_matrix["row1",]
col1 col2 col3 
   1    5    9 
my_matrix[,"col2"]
row1 row2 row3 row4 
   5    6    7    8 

数组(Array)

数组是一种多维数据结构,存储相同类型数据的集合。

实际上,数组可以被视为向量和矩阵的自然扩展,只不过数组中的数据可以有更高维度。向量和矩阵也可以视作数组的特例(一维、二维)

数组相对用的比较少,作为了解

# 创建一个3x3x2的三维数组
my_array <- array(1:18, dim = c(3, 3, 2))

dim = c(3, 3, 2)指定了数组的维度和每个维度的长度: 3、3、2

访问数组元素

# 访问数组的第一个元素
my_array[1, 1, 1]
[1] 1
# 访问第二维度的
my_array[, , 2]
     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17
[3,]   12   15   18
# 访问第二维度,但保留数组结构
my_array[, , 2, drop = FALSE]
, , 1

     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17
[3,]   12   15   18

drop = FALSE是取子集时的常用选项,默认为TRUE。设想取矩阵的一行或一列,不加这个选项将取到向量。这里不加的话将取到一个矩阵。

数据框

统计分析中最常见的原始数据形式是类似于数据库表或Excel数据表的形式。 这样形式的数据在R中叫做数据框(data.frame)。

数据框可以理解为矩阵的扩展,有n个横行、p个纵列, 但各列允许有不同类型:如数值型向量、因子、字符型向量、日期时间向量。同一列的数据类型相同。

数据框是R中最常用的数据结构

使用data.frame()函数创建数据框

data.frame(..., row.names = NULL, check.rows = FALSE,
           check.names = TRUE, fix.empty.names = TRUE,
           stringsAsFactors = FALSE)
           
  • ... : 传递任意数量的向量、列表或其它数据框作为参数。每个参数代表数据框中的一列。

  • row.names = NULL: 用于指定数据框的行名。

    • 默认情况下,data.frame() 会将输入向量或列表的第一个元素作为行名。如果你设置 row.names = NULL,则不会使用任何列作为行名,行名将默认为从1开始的连续整数。
  • check.rows = FALSE:用于控制是否检查输入的每一行是否具有相同的列数。

    • 如果设置为 TRUE,则 data.frame() 会检查每一行,确保它们的长度相同。
  • check.names = TRUE:是否检查列名是否有效。

    • 如果设置为 TRUE(默认值),R会检查所有列名是否是有效的变量名,并且会修改任何非法的列名(例如,包含空格或特殊字符的名称)。如果设置为 FALSE,则不会进行这种检查。
  • fix.empty.names = TRUE:用于控制当输入数据没有列名时,data.frame() 是否会自动生成列名。

  • stringsAsFactors = FALSE:用于控制字符串类型的列是否自动转换为因子类型。

    • 在早期版本的R中,默认值是 TRUE,这意味着所有字符列会自动转换为因子。从R 4.0.0开始,默认值变为 FALSE,这意味着字符列将保持为字符串类型,除非显式指定为因子。因子是一种特殊的数据类型,用于表示分类变量。

创建数据框

# 创建向量
name <- c("Alice", "Bob", "Charlie")
age <- c(25, 30, 35)
height <- c(165, 180, 175)
gender <- factor(c("Female", "Male", "Male"))
is_member <- c(TRUE, FALSE, TRUE)

# 使用data.frame()创建数据框
df <- data.frame(name, age, height,gender,is_member)
print(df)
     name age height gender is_member
1   Alice  25    165 Female      TRUE
2     Bob  30    180   Male     FALSE
3 Charlie  35    175   Male      TRUE

指定列名1

df <- data.frame("姓名" = name, "年龄" = age, "身高" = height)
print(df)
     姓名 年龄 身高
1   Alice   25  165
2     Bob   30  180
3 Charlie   35  175

使用行名

df <- data.frame(name, age, height,gender,is_member, row.names = c("R1", "R2", "R3"))
print(df)
      name age height gender is_member
R1   Alice  25    165 Female      TRUE
R2     Bob  30    180   Male     FALSE
R3 Charlie  35    175   Male      TRUE
d <- data.frame(
    name=c("李明", "张聪", "王建"), 
    age=c(30, 35, 28), 
    height=c(180, 162, 175),
    stringsAsFactors=FALSE) # 4.0.0以上默认就是FALSE
print(d)
  name age height
1 李明  30    180
2 张聪  35    162
3 王建  28    175

nrow()求行数,ncol()length()求列数

nrow(d)
[1] 3
ncol(d)
[1] 3
length(d)
[1] 3

rownames()可以显示/修改行名,names()colnames()可以显示/修改列名

rownames(d) <- c("r1","r2","r3")
rownames(d) 
[1] "r1" "r2" "r3"
colnames(d) <- c("c1","c2","c3")
colnames(d)
[1] "c1" "c2" "c3"
names(d)
[1] "c1" "c2" "c3"

用as.data.frame(x)可以把x转换成数据框。

  • 如果x是一个向量, 转换结果是以x为唯一一列的数据框。
  • 如果x是一个列表并且列表元素都是长度相同的向量,转换结果中每个列表变成数据框的一列。
  • 如果x是一个矩阵,转换结果把矩阵的每列变成数据框的一列。
a <- c(1:10)
b <- list(
  name=c("Alice","Bob","Charlie"),
  age = c(25, 30, 35),
height = c(165, 180, 175)
  )
c <- matrix(1:20,nrow = 4)
 [1]  1  2  3  4  5  6  7  8  9 10
$name
[1] "Alice"   "Bob"     "Charlie"

$age
[1] 25 30 35

$height
[1] 165 180 175
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    5    9   13   17
[2,]    2    6   10   14   18
[3,]    3    7   11   15   19
[4,]    4    8   12   16   20
# 转换为数据框
a.dt <- as.data.frame(a)
b.dt <- as.data.frame(b)
c.dt <- as.data.frame(c)
    a
1   1
2   2
3   3
4   4
5   5
6   6
7   7
8   8
9   9
10 10
     name age height
1   Alice  25    165
2     Bob  30    180
3 Charlie  35    175
  V1 V2 V3 V4 V5
1  1  5  9 13 17
2  2  6 10 14 18
3  3  7 11 15 19
4  4  8 12 16 20

数据框取子集

使用行号和列号

df <- data.frame(
  Name = c("Alice", "Bob", "Charlie"),
  Age = c(25, 30, 35),
  Salary = c(50000, 60000, 65000)
)

# 选择特定的行和列
df[1:2, 1:3]
   Name Age Salary
1 Alice  25  50000
2   Bob  30  60000
df[, c(1, 3)]
     Name Salary
1   Alice  50000
2     Bob  60000
3 Charlie  65000
df[c(-1), c(1, 2)]
     Name Age
2     Bob  30
3 Charlie  35

使用$符号选择列

df$Name
[1] "Alice"   "Bob"     "Charlie"

使用 [[]]选择列

df[["Age"]]
[1] 25 30 35

使用逻辑条件

df[df$Age > 30, ]
     Name Age Salary
3 Charlie  35  65000

使用 subset() 函数

subset(df,Age>30)
     Name Age Salary
3 Charlie  35  65000

with()允许你对数据框(或列表)的子集进行操作,而无需重复它们的名字1

下面我们使用mtcars数据来进行演示2

mtcars[1:4,]
                mpg cyl disp  hp drat    wt  qsec vs am gear carb
Mazda RX4      21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag  21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
Datsun 710     22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
with(mtcars, mpg * 2) #相当于mtcars$mpg*2
 [1] 42.0 42.0 45.6 42.8 37.4 36.2 28.6 48.8 45.6 38.4 35.6 32.8 34.6 30.4 20.8
[16] 20.8 29.4 64.8 60.8 67.8 43.0 31.0 30.4 26.6 38.4 54.6 52.0 60.8 31.6 39.4
[31] 30.0 42.8

当后续操作不止一步时要用花括号括起来

with(mtcars, {
 summary(mpg)
 plot(disp,mpg)
}) 

#相当于
# summary(mtcars$mpg)
# plot(mtcars$mpg,mtcars$disp)

within() 函数用于在数据框或列表内执行一系列操作,这些操作可以改变数据框或列表本身。可以使用 within() 来添加新列、修改现有列或执行其他变换,而不需要重复数据框的名称。

df <- within(df, {
  Double_Age = Age * 2
})
df
     Name Age Salary Double_Age
1   Alice  25  50000         50
2     Bob  30  60000         60
3 Charlie  35  65000         70
with() within()
返回值 返回操作的结果,而不会改变原始数据框 直接在原始数据框或列表上进行修改,不返回值
用途 通常用于数据子集选择或应用函数 用于在数据框或列表上执行一系列变换

数据框与矩阵

数据框不能作为矩阵参加矩阵运算。需要时,可以用as.matrix()函数转换数据框或数据框的子集为矩阵:

car_matrix <- as.matrix(mtcars[,c("mpg","cyl","disp")])
head(car_matrix)
                   mpg cyl disp
Mazda RX4         21.0   6  160
Mazda RX4 Wag     21.0   6  160
Datsun 710        22.8   4  108
Hornet 4 Drive    21.4   6  258
Hornet Sportabout 18.7   8  360
Valiant           18.1   6  225
class(car_matrix)
[1] "matrix" "array" 

tibble

数据框是一个随着R语言前身S语言继承下来的概念, 现在已经有一些不足之处, tibble包提供了tibble类, 这是数据框的一个现代改进版本。

tibble 的一些特点包括:

  • 不会自动改变变量名或类型。
  • 当变量不存在时会给出更多错误提示。
  • 增强的 print() 方法使得处理大型数据集更加方便。
  • 支持非法列名,只需用反引号括起来即可。
  • 输出时自动根据窗口大小调整,排版更加美观。
  • 使用 [] 选取列子集,即使只选取一列,返回结果仍为 tibble,而不自动转成向量。

由于tidyverse1也包含了tibble,也可以一次性安装tidyverse

if(!require('tidyverse')){
  install.packages('tidyverse')
}
library(tibble)

as.tibble(mtcars)
# A tibble: 32 × 11
     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
 2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
 3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1
 4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
 5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
 6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
 7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
 8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2
 9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2
10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4
# ℹ 22 more rows

data.table(高性能数据操作包)

类似数据框这样的二维表格数据是R中最为重要的数据类型,随着时间的发展,逐步出现了data.tabletibble这样的第三方包,以弥补R自带的dataframe的不足。

data.table是一个高性能数据管理包。可以以极快的速度处理大规模数据集(100GB规模)。

library(data.table)

三者的语法、适用场景都不一样,具体见附录3

因子(factor)

在统计学和数据分析中,变量的类型决定了数据分析的方法和可以应用的统计测试。

  • 连续性变量(Continuous Variables):可以取任意值,通常是数值型的,并且在两个数值之间可以有无限多个可能的值。它们通常用于量化测量,如长度、重量、时间、温度等。

  • 分类变量

    • 名义变量(Nominal Variables):代表的是不同的类别或名称,它们之间没有内在的顺序或等级关系。如性别、种族、血型、品牌名称等

    • 顺序变量(Ordinal Variables):是分类变量的一种,它们的类别有明确的顺序或等级关系,例如,教育水平(小学、中学、大学)、满意度评分(不满意、一般、满意)、社会经济地位等级等。

名义变量和顺序变量(分类变量)在R中被称为因子

因子由以下几个部分组成:

  • 水平(Levels):因子的所有可能取值。例如,性别因子的水平可能是”男”和”女”。

  • 内部表示(Internal Representation):因子在计算机中的存储方式,通常是一个整数向量,每个整数代表一个水平。

  • 标签(Labels):水平的文本描述,用于提高可读性。例如,水平1可能被标记为”男”,水平2被标记为”女”。如果不指定标签,那么默认标签就是水平本身。

使用factor()函数创建因子,它可以将一个字符向量或数值向量转换为因子类型

factor(x = character(), levels = as.character(x), labels = levels,
       exclude = NA, ordered = is.ordered(x), nmax = NA)
  • x:是向量,通常是由少量唯一值的字符向量
  • levels:水平,字符类型,用于设置x可能包含的唯一值,默认值是x的所有唯一值。如果x不是字符向量,那么使用as.character(x)把x转换为字符向量,然后获取x向量的水平。x向量的取值跟levels有关。
  • labels:是水平的标签,字符类型,用于对水平添加标签,相当于对因子水平重命名;
  • exclude:排除的字符
  • ordered:逻辑值,用于指定水平是否有序;
  • nmax:水平的上限数量

在实际使用中,最常见的参数是 x 和 levels,而其他参数根据特定需求进行设置

下面的例子中,x是一个无序向量,在不指定任何参数时,factor(x)返回一个无序因子。而指定ordered = TRUE后则返回了一个有序因子

x <- c("low", "medium", "high", "medium", "low")
factor(x)
[1] low    medium high   medium low   
Levels: high low medium
factor(x,ordered = TRUE)
[1] low    medium high   medium low   
Levels: high < low < medium

如果不指定levels,则factor()函数会自动判断。

我们也可以手动指定levels。但是如果指定的levels数量少于元素的种类,则结果会排除这些值

factor(x,levels = c("low", "medium", "high"))
[1] low    medium high   medium low   
Levels: low medium high
factor(x,levels = c("low", "medium"))
[1] low    medium <NA>   medium low   
Levels: low medium
factor(x,levels = c("low", "medium", "high", "extreme"))
[1] low    medium high   medium low   
Levels: low medium high extreme

创建一个因子并排除特定的水平

factor(c("low", "medium", "high", "medium", "low"), exclude = "medium")
[1] low  <NA> high <NA> low 
Levels: high low
sex=factor(c('f','m','f','f','m'),levels=c('f','m'),labels=c('female','male'),ordered=TRUE)
#返回因子的水平(由于指定了labels,所以返回的是labels)
levels(sex)
[1] "female" "male"  
#返回因子水平的标签
labels(sex)
[1] "1" "2" "3" "4" "5"
#返回每个水平(level)的频数v
summary(sex)
female   male 
     3      2 
#检查对象是否是因子
is.factor(sex)
[1] TRUE
#将其他类型的数据转换为因子
as.factor(c(1,2,3))
[1] 1 2 3
Levels: 1 2 3
#将因子转换为字符串,获取因子中每个元素的标签
as.character(sex)
[1] "female" "male"   "female" "female" "male"  

总结

  • 不要使用 labels() 来获取因子的标签,因为它并不适用于因子对象。
  • 使用 levels() 来获取因子的所有水平(标签)。
  • 使用 as.character() 来获取因子中每个元素的标签。

R中为什么有因子这个概念

因子作为R语言中内置的原生数据结构对象,它的出现就是来解决分类变量的分组、计数问题。

问题1:一个14亿人的身份证号组成的向量,如果把它变成因子,有意义吗?

没有,因为14亿人的身份证号都是不相同的,因子对这个向量作分组计数的结果,就是每个人的身份证号作为一组,计数的结果也就是一个。

问题2:一个超市的售货记录,1亿条商品出售记录的向量,商品类别数量为1W,把它变成因子,有意义吗

有,通过把这个向量变成因子,我们可以快速对这1W种商品进行分组、计数。可以很快看出,哪种商品卖得好,这样因子的作用:分组、计数的效果就出来了。而且节省了存储空间

列表(List)

在R语言中,列表(list)是一种复杂的数据结构,它可以包含各种类型和长度的数据元素。列表是R中非常灵活和强大的数据类型之一,因为它可以容纳不同类型的数据,如数值、字符、逻辑值、甚至是其他列表或数据框。列表通常用于存储和操作具有不同属性或维度的数据集。

  • 异质性:列表可以包含不同类型的数据,每个元素可以是数值、字符、逻辑值、向量、矩阵、数据框或其他列表。

  • 命名元素:列表中的每个元素可以有一个名称,这使得访问和操作列表中的特定元素更加方便。

  • 索引:可以通过元素的名称或位置来访问列表中的元素。

  • 动态长度:列表的长度可以根据需要动态变化,可以随时添加或删除元素。

  • 递归结构:列表可以包含其他列表,形成嵌套结构。

创建一个简单列表

my_list <- list(
  name = "Alice",
  age = 25,
  scores = c(90, 92, 85),
  personal_info = list(height = 165, weight = 55)
)
my_list
$name
[1] "Alice"

$age
[1] 25

$scores
[1] 90 92 85

$personal_info
$personal_info$height
[1] 165

$personal_info$weight
[1] 55

使用$访问列表元素

print(my_list$name)             
[1] "Alice"
print(my_list$age)             
[1] 25
print(my_list$scores)          
[1] 90 92 85
print(my_list$personal_info)    
$height
[1] 165

$weight
[1] 55

通过索引访问列表元素

print(my_list[["name"]])         
[1] "Alice"
print(my_list[["scores"]])     
[1] 90 92 85

访问嵌套列表中的元素

print(my_list$personal_info$height) 
[1] 165

with()依然可用

with(my_list,print(age))
[1] 25

附录1

R中自带了很多个数据集,这些数据集覆盖了各种领域,包括经济学、生物学、医学、工程学等,它们是学习数据分析和统计方法的宝贵资源。这些数据集通常已经预加载在R会话中,可以直接通过调用它们的名字来访问。以下是一些R中自带的著名数据集:

名称 说明 使用
mtcars 包含1973-1974年间32款汽车的燃油消耗和其他10种汽车属性的数据 直接使用
iris 包含3种不同鸢尾花的150个样本数据,每个样本有4个特征 直接使用
lung 包含肺癌患者和健康人的肺活量数据,用于生存分析 library(survival) data(lung)
ChickWeight 记录了不同饮食组的小鸡在不同周龄的体重数据 直接使用
AirPassengers 提供了1949-1960年间每个月的国际航空旅客数量 直接使用
LifeCycleSavings 记录了不同月份和不同日子的英国驾驶员死亡人数 直接使用
UKDriverDeaths 包含3种不同鸢尾花的150个样本数据,每个样本有4个特征 直接使用
PlantGrowth 包含了不同肥料处理下植物的生长高度数据 直接使用
ToothGrowth 记录了豚鼠牙齿生长的实验数据,包括不同剂量和类型的维生素C补充 直接使用
OrchardSprays 包含了苹果园喷洒不同类型杀虫剂的效果数据 直接使用

这些数据集可以直接用于数据分析练习,如数据探索、可视化、建模和统计测试。使用这些数据集可以帮助你理解数据结构,学习如何提出问题,以及如何使用R的各种函数和包来寻找答案。例如,你可以使用 summary() 函数来获取数据集的描述性统计信息,使用 plot() 函数来进行数据可视化,或者使用 lm() 函数来构建线性模型。

要查看R中所有自带数据集的列表,可以在R控制台输入 data(),这将显示所有可用的内置数据集。

附录2

tidyverse 是由 Hadley Wickham 和其他贡献者开发的 R 语言包集合,它旨在提供一套一致且高效的工具来处理和分析数据。tidyverse 中的包都遵循相同的设计哲学,使得它们可以无缝协作。以下是 tidyverse 中包含的一些核心包及其主要功能:

  1. ggplot2:一个强大的数据可视化包,基于语法的图形系统,允许用户通过添加图层来构建复杂的图表。

  2. dplyr:提供了一系列函数来操作数据框,包括过滤、选择、排序、汇总和分组等。

  3. tidyr:用于数据整理的包,可以帮助用户将数据转换为“整洁”格式,即每个变量构成一列,每个观测构成一行,每种观测单位构成一个表格。

  4. readr:提供了一系列函数来读取和写出文件,特别是文本文件、CSV 文件和固定宽度的文件。

  5. purrr:增强了 R 的函数式编程能力,使得用户可以更有效地使用列表和函数。

  6. tibble:提供了 tibble 数据结构,它是对传统数据框的现代化改进,提供了更好的打印方法和更严格的类型检查。

  7. stringr:用于字符串操作的包,提供了一系列函数来搜索、替换、分割和连接字符串。

  8. forcats:专注于因子变量的包,提供了工具来创建、转换和操作因子,这是 R 中用于分类数据的数据类型。

  9. lubridate:用于处理日期和时间的包,它提供了一套易于理解和使用的函数来解析、操作和格式化日期和时间。

  10. broom:将统计模型的结果转换为整洁的数据框,方便进行进一步的分析和可视化。

  11. haven:用于读取和写入统计软件(如 SPSS、Stata 和 SAS)文件的包。

  12. readxl:专门用于读取 Excel 文件的包。

  13. writexl:专门用于将数据写入 Excel 文件的包。

  14. modelr:用于构建和操作统计模型的包,它提供了一种在管道操作中构建模型的一致方法。

  15. hms:用于处理时间数据的包,特别是小时、分钟和秒。

  16. pillar:用于改善 R 控制台中的列数据的显示。

  17. cli:用于创建命令行界面的包。

  18. crayon:用于在 R 中进行颜色文本输出的包。

  19. fansi:用于处理 ANSI 字体样式的包。

  20. utf8:用于处理 UTF-8 编码的字符串的包。

tidyverse 包的安装非常简单,只需在 R 中运行以下命令:

install.packages("tidyverse")

加载 tidyverse 包会加载上述所有核心包,使得用户可以方便地进行数据处理和分析。通过 tidyverse 的一致性和高效性,数据分析变得更加直观和易于管理。

附录3

data.frame(Base R) vs tibble vs data.table

使用场景 推荐的R生态系统 理由
初学者学习 Base R → Tidyverse 从Base R开始可以帮助掌握R的基本概念和操作;之后转向Tidyverse能够加快数据分析和可视化的上手速度。
日常数据分析和可视化 Tidyverse Tidyverse具有简洁的语法和强大的功能,适合提升数据分析和可视化的生产力。
处理大型数据集 data.table data.table提供卓越的性能和内存管理能力,虽然学习曲线较陡,但其高效的处理能力值得付出额外的学习成本。

Base R是R语言的基础,包含了核心的函数和操作。它的优势在于:

  • 无依赖性:使用Base R不需要额外安装其他包,这在某些环境下(如生产环境或有严格依赖管理要求的项目中)尤其重要。
  • 广泛的支持和文档:Base R是R的核心部分,几乎所有的R用户都能使用其基本功能,同时R的文档和社区支持也很强大。
  • 灵活性:Base R提供了极大的灵活性,允许用户以不同的方式实现同一功能。

然而,Base R的劣势在于其相对较低的可读性和代码简洁性。对于新手来说,Base R的语法可能显得繁琐,且在处理复杂的数据操作时,其代码往往较长且不直观。

Tidyverse是一个由Hadley Wickham及其团队开发的R包集合,包含了如dplyr、ggplot2和tibble等工具。Tidyverse的主要优势包括:

  • 易学易用:Tidyverse包采用了统一且简洁的语法,使得数据操作和可视化变得更为直观。dplyr和ggplot2的管道操作符(%>%)和链式编程风格,降低了学习曲线。
  • 代码可读性高:Tidyverse的函数名和操作符设计符合自然语言的习惯,使得代码更易于理解和维护。 强大的功能:Tidyverse在数据处理、可视化和统计分析方面提供了丰富的功能,使得许多数据科学任务变得高效且简洁。

然而,Tidyverse也有其局限性。例如,在处理非常大的数据集时,Tidyverse的性能可能不如data.table。此外,Tidyverse的依赖性较强,可能会导致包版本冲突问题。

data.table是一个高性能的数据操作包,特别适合大数据集的处理。其主要优点包括:

  • 卓越的性能:data.table在处理大型数据集时表现出色,其计算速度和内存效率远超Base R和Tidyverse。
  • 高效的内存管理:data.table在内存管理和数据处理方面非常高效,适合需要高性能的数据操作场景。
  • 灵活的查询功能:data.table的语法支持复杂的查询操作,能够高效地进行数据聚合和变换。

然而,data.table的缺点在于其语法复杂性和学习曲线。对于新手来说,data.table的语法相对较难理解和掌握,而且其独特的操作方式可能导致代码的可读性降低。

课后练习(exercises)

练习02-1:基础数据类型操作

说明: 创建一个包含以下内容的R脚本,并将结果打印到控制台。

  1. 创建一个名为 numbers 的向量,包含数字 1 到 10。
  2. 创建一个名为 mat 的 3x3 矩阵,其元素是从 11 到 19。
  3. 创建一个名为 array1 的数组,使用 mat 矩阵的数据。
  4. 创建一个名为 df 的数据框,包含三列:Numbers(来自 numbers 向量),Letters(来自 大写字母表),Booleans(来自TRUE/FALSE的随机值)。
  5. 将 df 转换为名为 tb 的 tibble 数据框,并打印。

要求:

  • 使用 print() 函数打印每个对象,以验证创建是否成功。
  • 确保 tibble 数据框的行名和列名清晰明了。

练习02-2:数据类型转换和操作

说明: 给定以下代码,完成练习题。

# 假设我们有以下向量
char_vec <- c("one", "two", "three", "four")
num_vec <- c(1, 2, 3, 4)

# 假设我们有以下数据框
df <- data.frame(
  Character = as.factor(char_vec),
  Numbers = num_vec
)
  1. 创建一个名为 lst 的列表,包含 char_vec 和 num_vec 向量。
  2. 使用 df 数据框中的数据,创建一个因子类型的列,名为 FactorNum,其水平与 Numbers 列的数值相对应。
  3. 从列表 lst 中提取 num_vec 向量,并计算其平均值。

要求:

  • 使用 print() 或者直接调用变量来打印每个步骤的结果。
  • 确保因子类型的列正确地反映了数值向量的水平。