R 數(shù)據(jù)處理(八)

前言

通常,我們讀取的數(shù)據(jù)不可能完全滿足我們后續(xù)的分析需求,因此需要對(duì)讀取進(jìn)來的數(shù)據(jù)進(jìn)行處理。

比如,創(chuàng)建一些新的變量或總結(jié),或者只是想重命名變量或重新排列觀察結(jié)果,以便使數(shù)據(jù)更易于使用。

在本節(jié)及后續(xù)幾節(jié),我們將介紹如何使用 tidyverse 中的 dplyr 包來對(duì)數(shù)據(jù)進(jìn)行操作。

我們使用的數(shù)據(jù)是 2013 年從紐約出發(fā)的航班信息。

1 介紹

1.1 準(zhǔn)備

在這里我們的重點(diǎn)是介紹 dplyr 包的使用,并使用的 nycflights13 包中的數(shù)據(jù)來說明 dplyr 的核心思想,同時(shí)會(huì)加入一些 ggplot2 展示數(shù)據(jù)的示例,幫助我們理解。

ggplot2 包的詳細(xì)介紹將會(huì)放在后續(xù)的 R 繪圖系列中。

# 安裝 nycflights13 包
install.packages("nycflights13")
# 導(dǎo)入
library(nycflights13)
# 導(dǎo)入 tidyverse
> library(tidyverse)
─ Attaching packages ─────────────────────────────── tidyverse 1.3.0 ─
? ggplot2 3.3.3     ? purrr   0.3.4
? tibble  3.0.4     ? dplyr   1.0.2
? tidyr   1.1.2     ? stringr 1.4.0
? readr   1.4.0     ? forcats 0.5.0
─ Conflicts ───────────────────────────────── tidyverse_conflicts() ─
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
# 或者只導(dǎo)入 dplyr
> library(dplyr)

請(qǐng)注意導(dǎo)入 tidyverse 時(shí)打印的沖突信息,它告訴你 dplyr 會(huì)覆蓋基本 R 中的某些函數(shù)。

如果要在加載 dplyr 后使用這些函數(shù)的基本版本,則需要使用其全名 stats::filter()stats::lag()

1.2 nycflights13

為了探索 dplyr 的基本數(shù)據(jù)操作,我們將使用 nycflights13::flights

此數(shù)據(jù)包含 2013 年從紐約起飛的所有 336776 架次航班,這些數(shù)據(jù)來自美國交通統(tǒng)計(jì)局。

> flights
# A tibble: 336,776 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int>
 1  2013     1     1      517            515         2      830            819        11 UA        1545
 2  2013     1     1      533            529         4      850            830        20 UA        1714
 3  2013     1     1      542            540         2      923            850        33 AA        1141
 4  2013     1     1      544            545        -1     1004           1022       -18 B6         725
 5  2013     1     1      554            600        -6      812            837       -25 DL         461
 6  2013     1     1      554            558        -4      740            728        12 UA        1696
 7  2013     1     1      555            600        -5      913            854        19 B6         507
 8  2013     1     1      557            600        -3      709            723       -14 EV        5708
 9  2013     1     1      557            600        -3      838            846        -8 B6          79
10  2013     1     1      558            600        -2      753            745         8 AA         301
# … with 336,766 more rows, and 8 more variables: tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

從打印信息可以看出是一個(gè) tibble 類型,而不是 data.frame 類型

每列的類型代表的含義是:

  • int: 代表整數(shù)

  • dbl: 代表 double 或者實(shí)數(shù)

  • chr: 代表字符向量或字符串

  • dttm: 代表日期-時(shí)間

還有另外三種沒在這些數(shù)據(jù)中出現(xiàn)的類型

  • lgl: 代表邏輯值

  • fctr: 代表因子,即分類變量

  • date: 代表日期

1.3 dplyr 基礎(chǔ)

在這里,我們將介紹五個(gè)關(guān)鍵的 dplyr 動(dòng)詞函數(shù),這些函數(shù)可幫助您解決絕大多數(shù)的數(shù)據(jù)處理難題

  • filter(): 對(duì)值進(jìn)行篩選
  • arrange(): 對(duì)行進(jìn)行重排
  • select(): 根據(jù)變量名提取變量
  • mutate(): 使用現(xiàn)有變量創(chuàng)建新變量
  • summarise(): 將許多值匯總成一個(gè)摘要

這些函數(shù)都可以與 groupby() 一起使用,groupby() 將每個(gè)函數(shù)的作用域從對(duì)整個(gè)數(shù)據(jù)集進(jìn)行操作改為對(duì)其分組進(jìn)行操作

所有動(dòng)詞的工作方式相似:

  1. 第一個(gè)參數(shù)是數(shù)據(jù)框
  2. 后面的參數(shù)使用變量名描述如何處理數(shù)據(jù)框
  3. 返回的結(jié)果是一個(gè)新的數(shù)據(jù)框

將這些屬性結(jié)合在一起,可以輕松地將多個(gè)簡單步驟連接在一起,以獲得復(fù)雜的結(jié)果。讓我們深入看看這些動(dòng)詞是如何工作的

2 filter

filter() 允許您根據(jù)觀察值對(duì)其進(jìn)行篩選子集

第一個(gè)參數(shù)是數(shù)據(jù)框的名稱。第二個(gè)和隨后的參數(shù)是過濾數(shù)據(jù)框的表達(dá)式

例如,我們可以通過以下方式選擇 11 日的所有航班

> filter(flights, month == 1, day == 1)
# A tibble: 842 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int>
 1  2013     1     1      517            515         2      830            819        11 UA        1545
 2  2013     1     1      533            529         4      850            830        20 UA        1714
 3  2013     1     1      542            540         2      923            850        33 AA        1141
 4  2013     1     1      544            545        -1     1004           1022       -18 B6         725
 5  2013     1     1      554            600        -6      812            837       -25 DL         461
 6  2013     1     1      554            558        -4      740            728        12 UA        1696
 7  2013     1     1      555            600        -5      913            854        19 B6         507
 8  2013     1     1      557            600        -3      709            723       -14 EV        5708
 9  2013     1     1      557            600        -3      838            846        -8 B6          79
10  2013     1     1      558            600        -2      753            745         8 AA         301
# … with 832 more rows, and 8 more variables: tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

當(dāng)您運(yùn)行上面這行代碼時(shí),dplyr 執(zhí)行過濾操作并返回一個(gè)新的數(shù)據(jù)框。

dplyr 函數(shù)不會(huì)修改其輸入,因此如果要保存結(jié)果,則需要使用賦值運(yùn)算符

jan1 <- filter(flights, month == 1, day == 1)

R 要么打印出結(jié)果,要么將其保存到變量中。如果你想同時(shí)做這兩件事,你可以用圓括號(hào)括起來

> (dec25 <- filter(flights, month == 12, day == 25))
# A tibble: 719 x 19
    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight
   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int>
 1  2013    12    25      456            500        -4      649            651        -2 US        1895
 2  2013    12    25      524            515         9      805            814        -9 UA        1016
 3  2013    12    25      542            540         2      832            850       -18 AA        2243
 4  2013    12    25      546            550        -4     1022           1027        -5 B6         939
 5  2013    12    25      556            600        -4      730            745       -15 AA         301
 6  2013    12    25      557            600        -3      743            752        -9 DL         731
 7  2013    12    25      557            600        -3      818            831       -13 DL         904
 8  2013    12    25      559            600        -1      855            856        -1 B6         371
 9  2013    12    25      559            600        -1      849            855        -6 B6         605
10  2013    12    25      600            600         0      850            846         4 B6         583
# … with 709 more rows, and 8 more variables: tailnum <chr>, origin <chr>, dest <chr>,
#   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>

2.1 比較

要有效地使用過濾,您必須知道如何使用比較運(yùn)算符來選擇需要的值

>, >=, <, <=, != ,  ==

注意,上面的篩選參數(shù)用的是 == 而不是 =,如果你用錯(cuò)了

> filter(flights, month = 1)
錯(cuò)誤: Problem with `filter()` input `..1`.
x Input `..1` is named.
? This usually means that you've used `=` instead of `==`.
? Did you mean `month == 1`?
Run `rlang::last_error()` to see where the error occurred.

就會(huì)產(chǎn)生錯(cuò)誤。

使用 == 時(shí)可能會(huì)遇到的另一個(gè)常見問題是: 浮點(diǎn)數(shù)。

> sqrt(2) ^ 2 == 2
[1] FALSE
> 1 / 49 * 49 == 1
[1] FALSE

計(jì)算機(jī)使用有限精度算法(顯然是不能存儲(chǔ)無限多的數(shù)字)所以你看到的每個(gè)數(shù)字都是近似值

我們使用 near() 函數(shù)代替 ==

> near(sqrt(2) ^ 2,  2)
[1] TRUE
> near(1 / 49 * 49, 1)
[1] TRUE

2.2 邏輯運(yùn)算

filter() 的多個(gè)參數(shù)會(huì)以邏輯與的方式連接,而對(duì)于其他類型的組合,您需要自己使用布爾操作符:& | !

我們用下面的代碼查找所有在 11 月或 12 月起飛的航班

filter(flights, month == 11 | month == 12)

你不能寫成

filter(flights, month == (11 | 12))

它會(huì)找到等于 11 | 12 的所有月份,這個(gè)表達(dá)式的結(jié)果是 TRUE

在一個(gè)數(shù)字上下文中(如這里),TRUE 會(huì)變成 1,因此它會(huì)查找 1 月份的所有航班,而不是 11 月或 12 月。這真是太讓人困惑了.

解決這一問題的一個(gè)有用的簡寫就是

x %in% y

返回一個(gè)長度等于 x 的邏輯值向量,即 x 中的每一個(gè)元素是否出現(xiàn)在 y 中。

我們重寫上面的代碼

nov_dec <- filter(flights, month %in% c(11, 12))

有時(shí)你可以通過摩根定律來簡化復(fù)雜的子集,如

!(x & y) => !x | !y
!(x | y) => !x & !y

例如,如果您想查找延遲(到達(dá)或離開時(shí))不超過兩小時(shí)的航班,可以使用下面兩個(gè)過濾器中的任何一個(gè)

filter(flights, !(arr_delay > 120 | dep_delay > 120))
filter(flights, arr_delay <= 120, dep_delay <= 120)

R 中也有 &&||,但是不要在這里使用它們

2.3 缺失值

R 的一個(gè)重要特性是缺失值,也就是 NA

NA 表示一個(gè)未知值,幾乎任何涉及未知值的操作也將是未知的

> NA > 5
[1] NA
> 10 == NA
[1] NA
> NA + 10
[1] NA
> NA / 2
[1] NA

最令人困惑的結(jié)果是這個(gè)

> NA == NA
[1] NA

是不是想不明白,看看下面的例子,也許可以幫助你理解這是為什么

# Let x be Mary's age. We don't know how old she is.
x <- NA

# Let y be John's age. We don't know how old he is.
y <- NA

# Are John and Mary the same age?
x == y
#> [1] NA
# We don't know!

可以使用 is.na() 判斷一個(gè)值是不是缺失值

> is.na(NA)
[1] TRUE

filter() 僅包含條件為 TRUE 的行;它不包括 FALSENA 值。如果要保留缺失值,需要明確指定

> df <- tibble(x = c(1, NA, 3))
> filter(df, x > 1)
# A tibble: 1 x 1
      x
  <dbl>
1     3
> filter(df, is.na(x) | x > 1)
# A tibble: 2 x 1
      x
  <dbl>
1    NA
2     3

2.4 思考練習(xí)

  1. 提取下面所有的航班信息
  • 遲到兩個(gè)或兩個(gè)多小時(shí)
  • 飛往休斯敦(IAHHOU)
  • United, American,或 Delta 經(jīng)營的航班
  • 夏季出發(fā)(July, August, September)
  • 延遲到達(dá)超過兩小時(shí),但未延遲起飛
  • 至少晚點(diǎn)了一小時(shí),其中飛行時(shí)間占了超過 30 分鐘
  • 午夜至凌晨 6 點(diǎn)之間出發(fā)(0-6
  1. 另一個(gè)有用的 dplyr 過濾函數(shù)是 between(),它有什么作用?您可以使用它來簡化解決前面問題的代碼嗎?

  2. 有多少航班缺失了 dep_time?同時(shí)缺少哪些其他變量?想想這些行代表什么?

  3. 為什么 NA ^ 0 不是缺失值?為什么 NA | TRUE 不是缺失值?為什么 FALSE & NA 不是缺失值?你能弄清楚一般規(guī)則嗎?(NA * 0 是一個(gè)棘手的反例)

感謝花花同學(xué)的上期參考答案
http://note.youdao.com/s/DPASe3xt

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容