查看原文
其他

21 天从入门到掌握 R 语言第 3 天|上手 R 语言(二)

RStata RStata 2023-10-24

为了让大家更好的理解本文的内容,欢迎各位培训班会员参加明天晚上 9 点的直播课:「入手 R 语言(二)」,学习过程中遇到的问题可以随时提问!

该课程是「R 语言数据科学」的第 2 课时,课程主页(点击文末的阅读原文即可跳转):

https://rstata.duanshu.com/#/brief/course/229b770183e44fbbb64133df929818ec


为什么你应该使用 R 语言

一般回答这个问题就容易被人怼,所以我们说的缓和点。

  1. R 语言有个非常好用的 IDE —— RStudio;
  2. 跨平台。R 语言可以在各种系统上使用,无论是 Windows 、OSX 或者 Linux,你甚至可以在你的服务器上搭建 RStudio Server,这样你就可以从任何终端登陆使用了,我体验过,非常棒!如果大家没有服务器,可以在 https://posit.cloud/ 上注册个账户体验下;
  3. 启动速度快。不同于动辄几十 G 的 MATLAB 和 SAS,R 语言更加轻便,在 1~2 秒内即可启动投入使用。
  4. 运行速度更快。这个我主要是指和 Stata 比较。GitHub 上有个仓库:benchmark-stata-r: Speed benchmark of Stata and R on common data manipulations,这个项目比较了在同一台电脑上运行 Stata 和 R 中类似的程序需要的时间,结果如下:

这里面作者使用的是 Stata 的 ftools、gtools 和 R 的 data.table、fst (这些都是两个软件处理数据最快的方式)。上图的结果是在我的电脑上运行得到的结果(Stata 我使用的是 4 核的 StataMP 17.0),可以看到 R 比 Stata 快的有 18 个操作,Stata 比 R 快的仅有 11 个操作。R 完胜 Stata。

  1. 更精美的绘图效果。熟练掌握 R 语言你就可以制作出颜色绚丽、构图精巧的各种统计图表。

  2. 更活跃的社区。R 的社区相比 Stata 的更加活跃,第三方开发者更多,你可以从社区中发现更好有用的资源。

工作空间和工作目录

设定工作目录可以让我们更为高效的使用 R:

# 设定工作目录
setwd("~/Desktop")
# 查看当前工作目录
getwd()
#> [1] "/Users/ac/Desktop"
# 返回当前工作空间中的所有对象
ls()
#> [1] "cnfont" "enfont" "pars"
# 移除一个或者多个对象
rm()
# 查看 lm 函数的帮助文档
help(lm)
# 保存工作空间当 myfile.RData 中:
save.image("myfile.RData")
# 加载某个工作空间
load("myfile.RData")
# 无损的保存某个对象
i <- 1
save(i, file = "i.RData")
rm(i)
# 从文件加载某个对象
load("i.RData")

R 包

R 语言的各种函数是按照包的方式组织的。R 自带了一系列的基础包,但是这些包可能并不能满足我们的需要,甚至可能会妨碍我们的工作效率,这个时候我们就需要第三方开发者开发的 R 包了,可以去哪里获取呢?CRAN 和 GitHub 是两个很好的途径:

  1. CRAN: https://mirrors.tuna.tsinghua.edu.cn/CRAN/web/packages/
  2. GitHub: https://github.com/
# 安装 CRAN 上的 R 包
install.packages('ggplot2')
# 安装 GitHub 上的 R 包
devtools::install_github('tidyverse/ggplot2')
# 安装 GitHub 上的 R 包(使用 git,需要电脑上预先安装了 Git,可以百度下如何下载安装)
devtools::install_git('https://github.com/tidyverse/ggplot2.git')

为了更快的从 CRAN 上安装 R 包,你可以使用国内的镜像源,这个可以在 RStudio 的 Tools -> Globals Options 里面的 Packages 界面进行选择和设置。

国内用户安装 GitHub 上的 R 包是个非常困难的事情,可以选择先将包下载下来再安装的方式,也可以先将包 fork 到 Gitee 上再从 Gitee 上安装,例如我昨天安装 bayestestR 的时候就采用了这一方法:

devtools::install_git('https://gitee.com/tidyfriday/bayestestR.git')

如何使用一个新的 R 包呢?当然是看帮助文档了。

# 搜索某个关键词
??ggplot2
# 单个函数的帮助文档
?ggplot2::geom_point()
# 小品文
vignette("extending-ggplot2")

实际工作中可以根据自己的需要载入合适的 R 包:

library(tidyverse)

R 语言中的数据结构

在进行 tidyverse 系列的 R 包学习之前,了解一些 R 的基本元素很有必要。

标量

# 数值型
a <- 1
a
#> [1] 1
typeof(a)
#> [1] "double"
class(a)
#> [1] "numeric"
attributes(a)
#> NULL
# 字符型
b <- "2"
b
#> [1] "2"

typeof(b)
#> [1] "character"
class(b)
#> [1] "character"
attributes(b)
#> NULL
# 其他类
library(lubridate)
c <- ymd(Sys.Date())
typeof(c)
#> [1] "double"
class(c)
#> [1] "Date"
attributes(c)
#> $class
#> [1] "Date"

向量

# 数值型
v <- c(123)
v
#> [1] 1 2 3
typeof(v)
#> [1] "double"
class(v)
#> [1] "numeric"
attributes(v)
#> NULL
# 字符型
vc <- as.character(v)
vc
#> [1] "1" "2" "3"
typeof(vc)
#> [1] "character"
class(vc)
#> [1] "character"
attributes(vc)
#> NULL
# 其他类
vd <- ymd(c("2020-01-01""2020-01-02""2020-01-03"))
vd
#> [1] "2020-01-01" "2020-01-02" "2020-01-03"
typeof(vd)
#> [1] "double"
class(vd)
#> [1] "Date"
attributes(vd)
#> $class
#> [1] "Date"

向量的一些运算:

a <- c(123)
b <- c(234567)

# 基本运算
a + b
#> [1]  3  5  7  6  8 10
a * b
#> [1]  2  6 12  5 12 21

可以注意到直接对向量进行的元素实际上是对应元素上的运算。如果两个向量的长度不一样,比较短的向量中的元素会被循环使用。

# 整除
a %/% 2
#> [1] 0 1 1
# 求余
a %% 2
#> [1] 1 0 1
# 排序
c <- c(231)
sort(c)
#> [1] 1 2 3
# 最大值、最小值、均值、标准差等:
mean(a)
#> [1] 2
# 内积
a %*% c
#>      [,1]
#> [1,]   11
# 累加和累乘
cumsum(a)
#> [1] 1 3 6
cumprod(a)
#> [1] 1 2 6
# 长度
length(a)
#> [1] 3

字符型向量:

d <- as.character(a)
paste0(d, collapse = " ")
#> [1] "1 2 3"
length(d)
#> [1] 3
e <- as.character(b)
paste0(d, e)
#> [1] "12" "23" "34" "15" "26" "37"

矩阵

矩阵要求矩阵内部的每个元素拥有相同的模式(例如都是数值型的):

matrix(1:20, nrow = 5, byrow = T, dimnames = list(c("r1""r2""r3""r4""r5"), c("c1""c2""c3""c4"))) -> m
m
#>    c1 c2 c3 c4
#> r1  1  2  3  4
#> r2  5  6  7  8
#> r3  9 10 11 12
#> r4 13 14 15 16
#> r5 17 18 19 20
m[12]
#> [1] 2
m["r1""c2"]
#> [1] 2
m[c(12), 3]
#> r1 r2 
#>  3  7

数组

数组的特点是可以容纳高维数据,例如我们之前的「使用 R 语言处理 netCDF 格式的数据(二)」教程中从 netCDF 里面提取的数据就是个多维数组。

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

arr[,,1]
#>    B1 B2 B3
#> A1  1  3  5
#> A2  2  4  6

class(arr[,,1])
#> [1] "matrix" "array"

数据框

这就是 R 语言最大的特色了。自此我们也将进入 tidyverse 的世界。

library(tidyverse)
data(mpg)
class(mpg)
#> [1] "tbl_df"     "tbl"        "data.frame"
attributes(mpg)

#> $class
#> [1] "tbl_df"     "tbl"        "data.frame"
#> 
#> $row.names
#>   [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 101 102 103 104 105 106 107 108
#> [109] 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
#> [127] 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
#> [145] 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#> [163] 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
#> [181] 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
#> [199] 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
#> [217] 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
#> 
#> $names
#>  [1] "manufacturer" "model"        "displ"        "year"         "cyl"         
#>  [6] "trans"        "drv"          "cty"          "hwy"          "fl"          
#> [11] "class"

数据框的操作是本系列课程讲解的重点。

数据框的一些操作:

mpg

#> # A tibble: 234 × 11
#>    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
#>    <chr>        <chr>      <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
#>  1 audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
#>  2 audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
#>  3 audi         a4           2    2008     4 manu… f        20    31 p     comp…
#>  4 audi         a4           2    2008     4 auto… f        21    30 p     comp…
#>  5 audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
#>  6 audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
#>  7 audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
#>  8 audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
#>  9 audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
#> 10 audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
#> # … with 224 more rows

unique(mpg$manufacturer)
#>  [1] "audi"       "chevrolet"  "dodge"      "ford"       "honda"     
#>  [6] "hyundai"    "jeep"       "land rover" "lincoln"    "mercury"   
#> [11] "nissan"     "pontiac"    "subaru"     "toyota"     "volkswagen"

head(mpg)
#> # A tibble: 6 × 11
#>   manufacturer model displ  year   cyl trans      drv     cty   hwy fl    class 
#>   <chr>        <chr> <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr> 
#> 1 audi         a4      1.8  1999     4 auto(l5)   f        18    29 p     compa…
#> 2 audi         a4      1.8  1999     4 manual(m5) f        21    29 p     compa…
#> 3 audi         a4      2    2008     4 manual(m6) f        20    31 p     compa…
#> 4 audi         a4      2    2008     4 auto(av)   f        21    30 p     compa…
#> 5 audi         a4      2.8  1999     6 auto(l5)   f        16    26 p     compa…
#> 6 audi         a4      2.8  1999     6 manual(m5) f        18    26 p     compa…

tail(mpg)
#> # A tibble: 6 × 11
#>   manufacturer model  displ  year   cyl trans      drv     cty   hwy fl    class
#>   <chr>        <chr>  <dbl> <int> <int> <chr>      <chr> <int> <int> <chr> <chr>
#> 1 volkswagen   passat   1.8  1999     4 auto(l5)   f        18    29 p     mids…
#> 2 volkswagen   passat   2    2008     4 auto(s6)   f        19    28 p     mids…
#> 3 volkswagen   passat   2    2008     4 manual(m6) f        21    29 p     mids…
#> 4 volkswagen   passat   2.8  1999     6 auto(l5)   f        16    26 p     mids…
#> 5 volkswagen   passat   2.8  1999     6 manual(m5) f        18    26 p     mids…
#> 6 volkswagen   passat   3.6  2008     6 auto(s6)   f        17    26 p     mids…

glimpse(mpg)
#> Rows: 234
#> Columns: 11
#> $ manufacturer <chr> "audi", "audi", "audi", "audi", "audi", "audi", "audi", "…
#> $ model        <chr> "a4", "a4", "a4", "a4", "a4", "a4", "a4", "a4 quattro", "…
#> $ displ        <dbl> 1.8, 1.8, 2.0, 2.0, 2.8, 2.8, 3.1, 1.8, 1.8, 2.0, 2.0, 2.…
#> $ year         <int> 1999, 1999, 2008, 2008, 1999, 1999, 2008, 1999, 1999, 200…
#> $ cyl          <int> 4, 4, 4, 4, 6, 6, 6, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 8, 8, …
#> $ trans        <chr> "auto(l5)", "manual(m5)", "manual(m6)", "auto(av)", "auto…
#> $ drv          <chr> "f", "f", "f", "f", "f", "f", "f", "4", "4", "4", "4", "4…
#> $ cty          <int> 18, 21, 20, 21, 16, 18, 18, 18, 16, 20, 19, 15, 17, 17, 1…
#> $ hwy          <int> 29, 29, 31, 30, 26, 26, 27, 26, 25, 28, 27, 25, 25, 25, 2…
#> $ fl           <chr> "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p", "p…
#> $ class        <chr> "compact", "compact", "compact", "compact", "compact", "c…

使用数据框绘图:

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy))

数据框这么好用,那我们如何把我们的数据转成数据框呢?

  • readr
  • haven
  • readxl / writexl

例如读取 csv 格式的:

# 把 mpg 导出为 csv 数据
write_csv(mpg, "mpg.csv")
# 再把 mpg.csv 文件读取进来
read_csv("mpg.csv") -> m2
m2
#> # A tibble: 234 × 11
#>    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
#>    <chr>        <chr>      <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <chr>
#>  1 audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
#>  2 audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
#>  3 audi         a4           2    2008     4 manu… f        20    31 p     comp…
#>  4 audi         a4           2    2008     4 auto… f        21    30 p     comp…
#>  5 audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
#>  6 audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
#>  7 audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
#>  8 audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
#>  9 audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
#> 10 audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
#> # … with 224 more rows

读取 dta 数据:

library(haven)
# 把 mpg 导出为 dta 数据
write_dta(mpg, "mpg.dta")
# 再把 mpg.dta 文件读取进来
read_dta("mpg.dta") -> m3
m3
#> # A tibble: 234 × 11
#>    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
#>    <chr>        <chr>      <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <chr>
#>  1 audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
#>  2 audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
#>  3 audi         a4           2    2008     4 manu… f        20    31 p     comp…
#>  4 audi         a4           2    2008     4 auto… f        21    30 p     comp…
#>  5 audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
#>  6 audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
#>  7 audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
#>  8 audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
#>  9 audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
#> 10 audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
#> # … with 224 more rows

读取 xlsx 数据:

library(readxl)
library(writexl)
# 把 mpg 导出为 xlsx 数据
write_xlsx(mpg, "mpg.xlsx")
# 再把 mpg.dta 文件读取进来
read_xlsx("mpg.xlsx") -> m4
m4
#> # A tibble: 234 × 11
#>    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
#>    <chr>        <chr>      <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <chr>
#>  1 audi         a4           1.8  1999     4 auto… f        18    29 p     comp…
#>  2 audi         a4           1.8  1999     4 manu… f        21    29 p     comp…
#>  3 audi         a4           2    2008     4 manu… f        20    31 p     comp…
#>  4 audi         a4           2    2008     4 auto… f        21    30 p     comp…
#>  5 audi         a4           2.8  1999     6 auto… f        16    26 p     comp…
#>  6 audi         a4           2.8  1999     6 manu… f        18    26 p     comp…
#>  7 audi         a4           3.1  2008     6 auto… f        18    27 p     comp…
#>  8 audi         a4 quattro   1.8  1999     4 manu… 4        18    26 p     comp…
#>  9 audi         a4 quattro   1.8  1999     4 auto… 4        16    25 p     comp…
#> 10 audi         a4 quattro   2    2008     4 manu… 4        20    28 p     comp…
#> # … with 224 more rows

其他的就不再一一举例了。

案例时间

我想,如果我一个个跟大家罗列数据框的各种操作无疑是非常枯燥的,我们不如通过一个案例来感受一下使用 tidyverse 系列的工具处理数据框是多么的方便。本节我将通过展示全球新冠疫情数据的处理来演示数据框的常用操作。

read_dta('world-covid19.dta') -> df
df
#> # A tibble: 25,326 × 7
#>    iso   country country_en date       confirmed recovered deaths
#>    <chr> <chr>   <chr>      <date>         <dbl>     <dbl>  <dbl>
#>  1 BTN   不丹    Bhutan     2020-01-22         0         0      0
#>  2 BTN   不丹    Bhutan     2020-01-23         0         0      0
#>  3 BTN   不丹    Bhutan     2020-01-24         0         0      0
#>  4 BTN   不丹    Bhutan     2020-01-25         0         0      0
#>  5 BTN   不丹    Bhutan     2020-01-26         0         0      0
#>  6 BTN   不丹    Bhutan     2020-01-27         0         0      0
#>  7 BTN   不丹    Bhutan     2020-01-28         0         0      0
#>  8 BTN   不丹    Bhutan     2020-01-29         0         0      0
#>  9 BTN   不丹    Bhutan     2020-01-30         0         0      0
#> 10 BTN   不丹    Bhutan     2020-01-31         0         0      0
#> # … with 25,316 more rows
# 查看后 6 行
tail(df)

# 概览数据框
glimpse(df)

# 筛选出美国的
dplyr::filter(df, country == "美国") -> usdf
ggplot(data = usdf, aes(x = date, y = confirmed)) + 
  geom_line() + 
  geom_point(size = 0.1)

# 选择某几个变量
select(df, country, date, confirmed) -> sdf

ggplot(sdf) + 
  geom_line(aes(x = date, y = confirmed,
                color = country)) + 
  theme(legend.position = "none")

# 管道操作符
df %>% 
  select(country, date, confirmed) %>% 
  ggplot() + 
  geom_line(aes(x = date, y = confirmed,
                color = country)) + 
  theme(legend.position = "none")

# 生成一个新的变量:现存确诊人数
df %>% 
  select(country, date, confirmed, recovered, deaths) %>% 
  mutate(current_con = confirmed - recovered - deaths) %>% 
  arrange(desc(date)) %>% 
  select(date, everything()) %>% 
  group_by(date) %>% 
  summarise(con_sum = sum(confirmed)) %>% 
  ggplot() + 
  geom_line(aes(x = date, y = con_sum))

作业

仿照全球新冠疫情数据的处理流程处理中国新冠疫情的数据:

read_dta('china-covid19.dta') -> cndf
cndf
#> # A tibble: 50,790 × 8
#>    date       provcode prov  citycode city  confirmed recovered deaths
#>    <date>     <chr>    <chr> <chr>    <chr>     <dbl>     <dbl>  <dbl>
#>  1 2019-12-01 420000   湖北  420100   武汉          1         0      0
#>  2 2019-12-02 420000   湖北  420100   武汉          1         0      0
#>  3 2019-12-03 420000   湖北  420100   武汉          1         0      0
#>  4 2019-12-04 420000   湖北  420100   武汉          1         0      0
#>  5 2019-12-05 420000   湖北  420100   武汉          1         0      0
#>  6 2019-12-06 420000   湖北  420100   武汉          1         0      0
#>  7 2019-12-07 420000   湖北  420100   武汉          1         0      0
#>  8 2019-12-08 420000   湖北  420100   武汉          1         0      0
#>  9 2019-12-09 420000   湖北  420100   武汉          1         0      0
#> 10 2019-12-10 420000   湖北  420100   武汉          1         0      0
#> # … with 50,780 more rows

总结

本讲并未立即开始讲解 R 语言中的数据框的使用,而是先介绍了 R 和 RStudio 以及在学习数据框处理之前需要了解的一些基础 R 函数和运算方法。最后通过一个案例展示了 R 语言处理数据的常用操作。

直播信息

为了让大家更好的理解上面的内容,欢迎各位培训班会员参加明天晚上 9 点的直播课:「入手 R 语言(二)」

  1. 直播地址:腾讯会议(需要报名 RStata 培训班参加)
  2. 讲义材料:需要报名 RStata 培训班,详情可阅读:一起来学习 R 语言和 Stata 啦!学习过程中遇到的问题也可以随时提问!

更多关于 RStata 会员的更多信息可添加微信号 r_stata 咨询:


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存