前言
通常,我們讀取的數(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)詞的工作方式相似:
- 第一個(gè)參數(shù)是數(shù)據(jù)框
- 后面的參數(shù)使用變量名描述如何處理數(shù)據(jù)框
- 返回的結(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á)式
例如,我們可以通過以下方式選擇 1 月 1 日的所有航班
> 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 的行;它不包括 FALSE 和 NA 值。如果要保留缺失值,需要明確指定
> 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í)
- 提取下面所有的航班信息
- 遲到兩個(gè)或兩個(gè)多小時(shí)
- 飛往休斯敦(
IAH或HOU) -
United,American,或Delta經(jīng)營的航班 - 夏季出發(fā)(
July,August,September) - 延遲到達(dá)超過兩小時(shí),但未延遲起飛
- 至少晚點(diǎn)了一小時(shí),其中飛行時(shí)間占了超過
30分鐘 - 午夜至凌晨
6點(diǎn)之間出發(fā)(0-6)
另一個(gè)有用的
dplyr過濾函數(shù)是between(),它有什么作用?您可以使用它來簡化解決前面問題的代碼嗎?有多少航班缺失了
dep_time?同時(shí)缺少哪些其他變量?想想這些行代表什么?為什么
NA ^ 0不是缺失值?為什么NA | TRUE不是缺失值?為什么FALSE & NA不是缺失值?你能弄清楚一般規(guī)則嗎?(NA * 0是一個(gè)棘手的反例)
感謝花花同學(xué)的上期參考答案
http://note.youdao.com/s/DPASe3xt