第二章 工作流:基礎(chǔ)
2.1 代碼基礎(chǔ)
首先,我們可以將R當(dāng)做計(jì)算器使用
> 1 / 200 * 30
[1] 0.15
> (59 + 73 + 2) / 3
[1] 44.66667
> sin(pi / 2)
[1] 1
使用<- 來(lái)創(chuàng)建新對(duì)象:
x <- 3 * 4
創(chuàng)建對(duì)象的所有R 語(yǔ)句(即賦值語(yǔ)句)都有同樣的形式:
object_name <- value
在閱讀這行代碼時(shí),你可以在腦海中默念“某個(gè)對(duì)象名得到了某個(gè)值”。如果你覺(jué)得“<-”太繁瑣你可以使用RStudio 快捷鍵:Alt+-(Alt 加上減號(hào))。
2.2 對(duì)象名稱(chēng)
對(duì)象名稱(chēng)必須以字母開(kāi)頭,并且只能包含字母、數(shù)字、_ 和.。如果想讓對(duì)象名稱(chēng)具有描述性,那么就應(yīng)該在使用多個(gè)單詞時(shí)遵循某種命名慣例。我推薦使用snake_case 命名法,也就是使用小寫(xiě)單詞,并用_ 分隔:
i_use_snake_case
otherPeopleUseCamelCase
some.people.use.periods
And_aFew.People_RENOUNCEconvention
可以通過(guò)輸入對(duì)象名稱(chēng)來(lái)查看這個(gè)對(duì)象:
> x
[1] 12
再進(jìn)行一次賦值:
r_rocks <- 2 ^ 3
## 查看一下這個(gè)對(duì)象
r_rock
#> Error: object 'r_rock' not found
R_rocks
#> Error: object 'R_rocks' not found
2.3 函數(shù)調(diào)用
R中有大量?jī)?nèi)置函數(shù)。調(diào)用方式如下:
function_name(arg1 = val1, arg2 = val2, ...)
我們嘗試使用seq() 函數(shù),輸入?yún)?shù)1, 10:
> seq(1,10)
[1] 1 2 3 4 5 6 7 8 9 10
輸入以下代碼,你會(huì)發(fā)現(xiàn)RStudio 也會(huì)自動(dòng)完成一對(duì)雙引號(hào)以方便輸入:
x <- "hello world"
引號(hào)和括號(hào)必須一直成對(duì)出現(xiàn)。RStudio 會(huì)盡力幫助我們,但還是有出錯(cuò)并導(dǎo)致不匹配的可能。如果出現(xiàn)不匹配,R 會(huì)顯示一個(gè)+ 號(hào):
> x <- "hello
+
+號(hào)表明R 在等待繼續(xù)輸入;它認(rèn)為你還沒(méi)有完成輸入。這通常意味著你漏掉了一個(gè)" 或者)。
如果進(jìn)行了一次賦值,R 不會(huì)顯示出賦值結(jié)果。你最好立刻檢查一下:
> y <- seq(1, 10, length.out = 5)
> y
[1] 1.00 3.25 5.50 7.75 10.00
## 或者采取簡(jiǎn)化方式
> (y <- seq(1, 10, length.out = 5))
[1] 1.00 3.25 5.50 7.75 10.00
第三章 使用dplyr進(jìn)行數(shù)據(jù)轉(zhuǎn)換
3.1 簡(jiǎn)介
本章將用dplyr 包來(lái)轉(zhuǎn)換數(shù)據(jù),并介紹一個(gè)新的數(shù)據(jù)集:2013 年從紐約市出發(fā)的航班信息。
3.1.1 準(zhǔn)備工作
本章將重點(diǎn)討論如何使用tidyverse 中的另一個(gè)核心R 包——dplyr 包。我們使用nycflights13 包中的數(shù)據(jù)來(lái)說(shuō)明dplyr 包的核心理念,并使用ggplot2 來(lái)幫助我們理解數(shù)據(jù)。
3.1.2 nycflights13
使用nycflights13::flights。這個(gè)數(shù)據(jù)框包含了2013 年從紐約市出發(fā)的所有336 776 次航班的信息。該數(shù)據(jù)來(lái)自于美國(guó)交通統(tǒng)計(jì)局,可以使用?flights 查看其說(shuō)明文檔:
> flights
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay
<int> <int> <int> <int> <int> <dbl>
1 2013 1 1 517 515 2
2 2013 1 1 533 529 4
3 2013 1 1 542 540 2
4 2013 1 1 544 545 -1
5 2013 1 1 554 600 -6
6 2013 1 1 554 558 -4
7 2013 1 1 555 600 -5
8 2013 1 1 557 600 -3
9 2013 1 1 557 600 -3
10 2013 1 1 558 600 -2
# ... with 336,766 more rows, and 13 more variables:
# arr_time <int>, sched_arr_time <int>, arr_delay <dbl>,
# carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
# dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
# minute <dbl>, time_hour <dttm>
列名下面有一行3 個(gè)或4 個(gè)字母的縮寫(xiě)。它們描述了每個(gè)變量的類(lèi)型。
? int 表示整數(shù)型變量。
? dbl 表示雙精度浮點(diǎn)數(shù)型變量,或稱(chēng)實(shí)數(shù)。
? chr 表示字符向量,或稱(chēng)字符串。
? dttm 表示日期時(shí)間(日期+ 時(shí)間)型變量。
還有另外3 種常用的變量類(lèi)型,雖然沒(méi)有在這個(gè)數(shù)據(jù)集中出現(xiàn),但很快就會(huì)在本書(shū)后面遇到。
? lgl 表示邏輯型變量,是一個(gè)僅包括TRUE 和FALSE 的向量。
? fctr 表示因子,R 用其來(lái)表示具有固定數(shù)目的值的分類(lèi)變量。
? date 表示日期型變量。
3.1.3 dplyr基礎(chǔ)
5 個(gè)dplyr 核心函數(shù):
? 按值篩選觀測(cè)(filter())。
? 對(duì)行進(jìn)行重新排序(arrange())。
? 按名稱(chēng)選取變量(select())。
? 使用現(xiàn)有變量的函數(shù)創(chuàng)建新變量(mutate())。
? 將多個(gè)值總結(jié)為一個(gè)摘要統(tǒng)計(jì)量(summarize())。
這些函數(shù)都可以和group_by() 函數(shù)聯(lián)合起來(lái)使用,group_by() 函數(shù)可以改變以上每個(gè)函數(shù)的作用范圍,讓其從在整個(gè)數(shù)據(jù)集上操作變?yōu)樵诿總€(gè)分組上分別操作。這6 個(gè)函數(shù)構(gòu)成了數(shù)據(jù)處理語(yǔ)言的基本操作。
前面5 個(gè)函數(shù)的工作方式都是相同的。
(1) 第一個(gè)參數(shù)是一個(gè)數(shù)據(jù)框。
(2) 隨后的參數(shù)使用變量名稱(chēng)(不帶引號(hào))描述了在數(shù)據(jù)框上進(jìn)行的操作。
(3) 輸出結(jié)果是一個(gè)新數(shù)據(jù)框。
利用以上這些屬性可以很輕松地將多個(gè)簡(jiǎn)單步驟鏈接起來(lái),從而得到非常復(fù)雜的結(jié)果。接下來(lái)我們將深入了解,看看如何使用這些操作。
3.2 使用filter()篩選行
filter() 函數(shù)可以基于觀測(cè)的值篩選出一個(gè)觀測(cè)子集。第一個(gè)參數(shù)是數(shù)據(jù)框名稱(chēng),第二個(gè)參數(shù)以及隨后的參數(shù)是用來(lái)篩選數(shù)據(jù)框的表達(dá)式。例如,我們可以使用以下代碼篩選出1月1 日的所有航班:
> jan1 <-filter(flights, month == 1, day == 1)
> jan1
# A tibble: 842 x 19
year month day dep_time sched_dep_time dep_delay
<int> <int> <int> <int> <int> <dbl>
1 2013 1 1 517 515 2
2 2013 1 1 533 529 4
3 2013 1 1 542 540 2
4 2013 1 1 544 545 -1
5 2013 1 1 554 600 -6
6 2013 1 1 554 558 -4
7 2013 1 1 555 600 -5
8 2013 1 1 557 600 -3
9 2013 1 1 557 600 -3
10 2013 1 1 558 600 -2
# ... with 832 more rows, and 13 more variables:
# arr_time <int>, sched_arr_time <int>, arr_delay <dbl>,
# carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
# dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
# minute <dbl>, time_hour <dttm>
3.2.1 比較運(yùn)算符
R 提供了一套標(biāo)準(zhǔn)的比較運(yùn)算符:>、>=、<、<=、!=(不等于)和==(等于)。當(dāng)開(kāi)始使用R 時(shí),最容易犯的錯(cuò)誤就是使用= 而不是 == 來(lái)測(cè)試是否相等。
在使用== 進(jìn)行比較時(shí),你可能還會(huì)遇到另一個(gè)常見(jiàn)問(wèn)題:浮點(diǎn)數(shù)。
> sqrt(2)^2==2
[1] FALSE
> 1/49*49==1
[1] FALSE
3.2.2 邏輯運(yùn)算符
filter() 中的多個(gè)參數(shù)是由“與”組合起來(lái)的:每個(gè)表達(dá)式都必須為真才能讓一行觀測(cè)包
含在輸出中。如果要實(shí)現(xiàn)其他類(lèi)型的組合,你需要使用布爾運(yùn)算符:& 表示“與”、| 表示
“或”、! 表示“非”。
以下代碼可以找出11 月或12 月出發(fā)的所有航班:
filter(flights, month == 11 | month == 12)
不能寫(xiě)成filter(flights, month == 11 |12) 這種形式。這種形式的文字翻譯確實(shí)是“找出11 月或12 月出發(fā)的所有航班”,但在代碼中則不是這個(gè)意思,代碼中的含義是找出所有出發(fā)月份為11 | 12 的航班。11 | 12 這個(gè)邏輯表達(dá)式的值為T(mén)RUE,在數(shù)字語(yǔ)境中(如本例),TRUE 就是1,所以這段代碼找出的不是11 月或12 月出發(fā)的航班,而是1 月出發(fā)的所有航班。
這種問(wèn)題有一個(gè)有用的簡(jiǎn)寫(xiě)形式:x %in% y。這會(huì)選取出x 是y 中的一個(gè)值時(shí)的所有行。
我們可以使用這種形式重寫(xiě)上面的代碼:
nov_dec <- filter(flights, month %in% c(11, 12))
可以使用德摩根定律將復(fù)雜的篩選條件進(jìn)行簡(jiǎn)化:!(x & y) 等價(jià)于!x | !y、!(x |y) 等價(jià)于!x & !y。例如,如果想要找出延誤時(shí)間(到達(dá)或出發(fā))不多于2 小時(shí)的航班,那么使用以下兩種篩選方式均可:
filter(flights, !(arr_delay > 120 | dep_delay > 120))
filter(flights, arr_delay <= 120, dep_delay <= 120)
filter() 函數(shù)中使用的是復(fù)雜的、包含多個(gè)部分的表達(dá)式,就需要考慮用一個(gè)明確的變量來(lái)代替它。這樣檢查代碼會(huì)容易很多。我們很快就會(huì)介紹如何創(chuàng)建新變量。
3.2.3 缺失值
R 的一個(gè)重要特征使得比較運(yùn)算更加復(fù)雜,這個(gè)特征就是缺失值,或稱(chēng)NA(not available,不可用)。如果運(yùn)算中包含了未知值,那么運(yùn)算結(jié)果一般來(lái)說(shuō)也是個(gè)未知值:
> NA + 10
[1] NA
> NA / 2
[1] NA
如果想要確定一個(gè)值是否為缺失值,可以使用is.na() 函數(shù):
> x <- NA
> is.na(x)
[1] TRUE
filter() 只能篩選出條件為T(mén)RUE 的行;它會(huì)排除那些條件為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
3.3 使用arrange()排列行
arrange() 函數(shù)的工作方式與filter() 函數(shù)非常相似,但前者不是選擇行,而是改變行的順序。它接受一個(gè)數(shù)據(jù)框和一組作為排序依據(jù)的列名(或者更復(fù)雜的表達(dá)式)作為參數(shù)。如果列名不只一個(gè),那么就使用后面的列在前面排序的基礎(chǔ)上繼續(xù)排序:
> arrange(flights, year, month, day)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay
<int> <int> <int> <int> <int> <dbl>
1 2013 1 1 517 515 2
2 2013 1 1 533 529 4
3 2013 1 1 542 540 2
4 2013 1 1 544 545 -1
5 2013 1 1 554 600 -6
6 2013 1 1 554 558 -4
7 2013 1 1 555 600 -5
8 2013 1 1 557 600 -3
9 2013 1 1 557 600 -3
10 2013 1 1 558 600 -2
# ... with 336,766 more rows, and 13 more variables:
# arr_time <int>, sched_arr_time <int>, arr_delay <dbl>,
# carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
# dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
# minute <dbl>, time_hour <dttm>
使用desc() 可以按列進(jìn)行降序排序:
> arrange(flights, desc(arr_delay))
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay
<int> <int> <int> <int> <int> <dbl>
1 2013 1 9 641 900 1301
2 2013 6 15 1432 1935 1137
3 2013 1 10 1121 1635 1126
4 2013 9 20 1139 1845 1014
5 2013 7 22 845 1600 1005
6 2013 4 10 1100 1900 960
7 2013 3 17 2321 810 911
8 2013 7 22 2257 759 898
9 2013 12 5 756 1700 896
10 2013 5 3 1133 2055 878
# ... with 336,766 more rows, and 13 more variables:
# arr_time <int>, sched_arr_time <int>, arr_delay <dbl>,
# carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
# dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
# minute <dbl>, time_hour <dttm>
缺失值總是排在最后:
> df <- tibble(x = c(5, 2, NA))
> arrange(df, x)
# A tibble: 3 x 1
x
<dbl>
1 2
2 5
3 NA
3.4 使用select()選擇列
如今,數(shù)據(jù)集有幾百甚至幾千個(gè)變量已經(jīng)司空見(jiàn)慣。這種情況下,如何找出真正感興趣的那些變量經(jīng)常是我們面臨的第一個(gè)挑戰(zhàn)。通過(guò)基于變量名的操作,select() 函數(shù)可以讓你快速生成一個(gè)有用的變量子集。
# 按名稱(chēng)選擇列
> select(flights, year, month, day)
# A tibble: 336,776 x 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ... with 336,766 more rows
# 選擇“year”和“day”之間的所有列
> select(flights, year:day)
# A tibble: 336,776 x 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# ... with 336,766 more rows
# 選擇不在“year”和“day”之間的列
> select(flights, -(year:day))
# A tibble: 336,776 x 16
dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <dbl> <int> <int>
1 517 515 2 830 819
2 533 529 4 850 830
3 542 540 2 923 850
4 544 545 -1 1004 1022
5 554 600 -6 812 837
6 554 558 -4 740 728
7 555 600 -5 913 854
8 557 600 -3 709 723
9 557 600 -3 838 846
10 558 600 -2 753 745
# ... with 336,766 more rows, and 11 more variables:
# arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
# distance <dbl>, hour <dbl>, minute <dbl>,
# time_hour <dttm>
還可以在select () 函數(shù)中使用一些輔助函數(shù)。
? starts_with("abc"):匹配以“abc”開(kāi)頭的名稱(chēng)。
? ends_with("xyz"):匹配以“xyz”結(jié)尾的名稱(chēng)。
? contains("ijk"):匹配包含“ijk”的名稱(chēng)。
? matches("(.)\1"):選擇匹配正則表達(dá)式的那些變量。這個(gè)正則表達(dá)式會(huì)匹配名稱(chēng)中有重復(fù)字符的變量。你將在第10 章中學(xué)習(xí)到更多關(guān)于正則表達(dá)式的知識(shí)。
? num_range("x", 1:3):匹配x1、x2 和x3。
使用select() 函數(shù)的變體rename() 函數(shù)來(lái)重命名變量,以保留所有未明確提及的變量:
> rename(flights, tail_num = tailnum)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay
<int> <int> <int> <int> <int> <dbl>
1 2013 1 1 517 515 2
2 2013 1 1 533 529 4
3 2013 1 1 542 540 2
4 2013 1 1 544 545 -1
5 2013 1 1 554 600 -6
6 2013 1 1 554 558 -4
7 2013 1 1 555 600 -5
8 2013 1 1 557 600 -3
9 2013 1 1 557 600 -3
10 2013 1 1 558 600 -2
# ... with 336,766 more rows, and 13 more variables:
# arr_time <int>, sched_arr_time <int>, arr_delay <dbl>,
# carrier <chr>, flight <int>, tail_num <chr>,
# origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
另一種用法是將select() 函數(shù)和everything() 輔助函數(shù)結(jié)合起來(lái)使用。當(dāng)想要將幾個(gè)變量移到數(shù)據(jù)框開(kāi)頭時(shí),這種用法非常奏效
> select(flights, time_hour, air_time, everything())
# A tibble: 336,776 x 19
time_hour air_time year month day dep_time
<dttm> <dbl> <int> <int> <int> <int>
1 2013-01-01 05:00:00 227 2013 1 1 517
2 2013-01-01 05:00:00 227 2013 1 1 533
3 2013-01-01 05:00:00 160 2013 1 1 542
4 2013-01-01 05:00:00 183 2013 1 1 544
5 2013-01-01 06:00:00 116 2013 1 1 554
6 2013-01-01 05:00:00 150 2013 1 1 554
7 2013-01-01 06:00:00 158 2013 1 1 555
8 2013-01-01 06:00:00 53 2013 1 1 557
9 2013-01-01 06:00:00 140 2013 1 1 557
10 2013-01-01 06:00:00 138 2013 1 1 558
# ... with 336,766 more rows, and 13 more variables:
# sched_dep_time <int>, dep_delay <dbl>, arr_time <int>,
# sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
# flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
# distance <dbl>, hour <dbl>, minute <dbl>
3.5 使用mutate()添加新變量
除了選擇現(xiàn)有的列,我們還經(jīng)常需要添加新列,新列是現(xiàn)有列的函數(shù)。這就是mutate() 函數(shù)的作用。
mutate() 總是將新列添加在數(shù)據(jù)集的最后,因此我們需要先創(chuàng)建一個(gè)更狹窄的數(shù)據(jù)集,以便能夠看到新變量。記住,當(dāng)使用RStudio 時(shí),查看所有列的最簡(jiǎn)單的方法就是使用View()函數(shù):
flights_sml <- select(flights,
year:day,
ends_with("delay"),
distance,
air_time
)
mutate(flights_sml,
gain = arr_delay - dep_delay,
speed = distance / air_time * 60
)
# A tibble: 336,776 x 9
year month day dep_delay arr_delay distance air_time
<int> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 2013 1 1 2 11 1400 227
2 2013 1 1 4 20 1416 227
3 2013 1 1 2 33 1089 160
4 2013 1 1 -1 -18 1576 183
5 2013 1 1 -6 -25 762 116
6 2013 1 1 -4 12 719 150
7 2013 1 1 -5 19 1065 158
8 2013 1 1 -3 -14 229 53
9 2013 1 1 -3 -8 944 140
10 2013 1 1 -2 8 733 138
# ... with 336,766 more rows, and 2 more variables:
# gain <dbl>, speed <dbl>
一旦創(chuàng)建,新列就可以立即使用:
> mutate(flights_sml,
+ gain = arr_delay - dep_delay,
+ hours = air_time / 60,
+ gain_per_hour = gain / hours
+ )
# A tibble: 336,776 x 10
year month day dep_delay arr_delay distance air_time
<int> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 2013 1 1 2 11 1400 227
2 2013 1 1 4 20 1416 227
3 2013 1 1 2 33 1089 160
4 2013 1 1 -1 -18 1576 183
5 2013 1 1 -6 -25 762 116
6 2013 1 1 -4 12 719 150
7 2013 1 1 -5 19 1065 158
8 2013 1 1 -3 -14 229 53
9 2013 1 1 -3 -8 944 140
10 2013 1 1 -2 8 733 138
# ... with 336,766 more rows, and 3 more variables:
# gain <dbl>, hours <dbl>, gain_per_hour <dbl>
如果只想保留新變量,可以使用transmute() 函數(shù):
> transmute(flights,
+ gain = arr_delay - dep_delay,
+ hours = air_time / 60,
+ gain_per_hour = gain / hours
+ )
# A tibble: 336,776 x 3
gain hours gain_per_hour
<dbl> <dbl> <dbl>
1 9 3.78 2.38
2 16 3.78 4.23
3 31 2.67 11.6
4 -17 3.05 -5.57
5 -19 1.93 -9.83
6 16 2.5 6.4
7 24 2.63 9.11
8 -11 0.883 -12.5
9 -5 2.33 -2.14
10 10 2.3 4.35
# ... with 336,766 more rows
3.5.1 常用創(chuàng)建函數(shù)
創(chuàng)建新變量的多種函數(shù)可供你同mutate() 一同使用。最重要的一點(diǎn)是,這種函數(shù)必須是向量化的:它必須接受一個(gè)向量作為輸入,并返回一個(gè)向量作為輸出,而且輸入向量與輸出向量具有同樣數(shù)目的分量。我們無(wú)法列出所有可能用到的創(chuàng)建函數(shù),但可以介紹一下那些比較常用的。
算術(shù)運(yùn)算符:+、-、、/、^*
它們都是向量化的,使用所謂的“循環(huán)法則”。如果一個(gè)參數(shù)比另一個(gè)參數(shù)短,那么前者會(huì)自動(dòng)擴(kuò)展到同樣的長(zhǎng)度。當(dāng)某個(gè)參數(shù)是單個(gè)數(shù)值時(shí),這種方式是最有效的:air_time / 60、hours * 60 + minute 等。
算術(shù)運(yùn)算符的另一用途是與我們后面將很快學(xué)到的聚集函數(shù)結(jié)合起來(lái)使用。例如,x /sum(x) 可以計(jì)算出各個(gè)分量在總數(shù)中的比例,y – mean(y) 可以計(jì)算出分量與均值之間的差值。
模運(yùn)算符:%/% 和%%
%/%(整數(shù)除法)和%%(求余)滿(mǎn)足x == y * (x %/% y) + (x %% y)。模運(yùn)算非常好用,因?yàn)樗梢圆鸱终麛?shù)。例如,在航班數(shù)據(jù)集中,你可以根據(jù)dep_time 計(jì)算出hour和minute:
> transmute(flights,
+ dep_time,
+ hour = dep_time %/% 100,
+ minute = dep_time %% 100
+ )
# A tibble: 336,776 x 3
dep_time hour minute
<int> <dbl> <dbl>
1 517 5 17
2 533 5 33
3 542 5 42
4 544 5 44
5 554 5 54
6 554 5 54
7 555 5 55
8 557 5 57
9 557 5 57
10 558 5 58
# ... with 336,766 more rows
對(duì)數(shù)函數(shù):log()、log2() 和log10()
? 在處理取值范圍橫跨多個(gè)數(shù)量級(jí)的數(shù)據(jù)時(shí),對(duì)數(shù)是特別有用的一種轉(zhuǎn)換方式。它還可以將乘法轉(zhuǎn)換成加法,我們將在本書(shū)的第四部分中介紹這個(gè)功能。
? 其他條件相同的情況下,我推薦使用log2() 函數(shù),因?yàn)楹苋菀讓?duì)其進(jìn)行解釋?zhuān)簩?duì)數(shù)標(biāo)度的數(shù)值增加1 個(gè)單位,意味著初始數(shù)值加倍;減少1 個(gè)單位,則意味著初始數(shù)值減半。
偏移函數(shù)
? lead() 和lag
() 函數(shù)可以返回一個(gè)序列的領(lǐng)先值和滯后值。它們可以計(jì)算出序列的移動(dòng)差值(如x – lag(x))或發(fā)現(xiàn)序列何時(shí)發(fā)生了變化(x != lag(x))。它們與group_by()組合使用時(shí)特別有用,你很快就會(huì)學(xué)到group_by() 這個(gè)函數(shù):
> (x <- 1:10)
[1] 1 2 3 4 5 6 7 8 9 10
> lag(x)
[1] NA 1 2 3 4 5 6 7 8 9
> lead(x)
[1] 2 3 4 5 6 7 8 9 10 NA
**累加和滾動(dòng)聚合 **
R 提供了計(jì)算累加和、累加積、累加最小值和累加最大值的函數(shù):cumsum()、cumprod()、commin() 和cummax();dplyr 還提供了cummean() 函數(shù)以計(jì)算累加均值。
> x
[1] 1 2 3 4 5 6 7 8 9 10
> cumsum(x)
[1] 1 3 6 10 15 21 28 36 45 55
> cummean(x)
[1] 1.000000 1.000000 1.333333 1.750000 2.200000 2.666667
[7] 3.142857 3.625000 4.111111 4.600000
邏輯比較:<、<=、>、>= 和!=
如果需要進(jìn)行一系列復(fù)雜的邏輯運(yùn)算,那么最好將中間結(jié)果保存在新變量中,這樣就可以檢查是否每一步都符合預(yù)期。
排秩
排秩函數(shù)有很多,但你應(yīng)該從min_rank() 函數(shù)開(kāi)始,它可以完成最常用的排秩任務(wù)(如第一、第二、第三、第四)。默認(rèn)的排秩方式是,最小的值獲得最前面的名次,使用desc(x) 可以讓最大的值獲得最前面的名次
> y <- c(1, 2, 2, NA, 3, 4)
> min_rank(y)
[1] 1 2 2 NA 4 5
> min_rank(desc(y))
[1] 5 3 3 NA 2 1
如果min_rank() 無(wú)法滿(mǎn)足需要,那么可以看一下其變體row_number()、dense_rank()、percent_rank()、cume_dist() 和ntile()。
> row_number(y)
[1] 1 2 3 NA 4 5
> dense_rank(y)
[1] 1 2 2 NA 3 4
> percent_rank(y)
[1] 0.00 0.25 0.25 NA 0.75 1.00
> cume_dist(y)
[1] 0.2 0.6 0.6 NA 0.8 1.0
3.6 使用summarize()進(jìn)行分組摘要
最后一個(gè)核心函數(shù)是summarize(),它可以將數(shù)據(jù)框折疊成一行。group_by() 可以將分析單位從整個(gè)數(shù)據(jù)集更改為單個(gè)分組。接下來(lái),在分組后的數(shù)據(jù)框上使用dplyr 函數(shù)時(shí),它們會(huì)自動(dòng)地應(yīng)用到每個(gè)分組。例如,如果對(duì)按日期分組的一個(gè)數(shù)據(jù)框應(yīng)用與上面完全相同的代碼,那么我們就可以得到每日平均延誤時(shí)間:
> by_day <- group_by(flights, year, month, day)
> summarize(by_day, delay = mean(dep_delay, na.rm = TRUE))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day delay
<int> <int> <int> <dbl>
1 2013 1 1 11.5
2 2013 1 2 13.9
3 2013 1 3 11.0
4 2013 1 4 8.95
5 2013 1 5 5.73
6 2013 1 6 7.15
7 2013 1 7 5.42
8 2013 1 8 2.55
9 2013 1 9 2.28
10 2013 1 10 2.84
# ... with 355 more rows
3.6.1 使用管道組合多種操作
假設(shè)我們想要研究每個(gè)目的地的距離和平均延誤時(shí)間之間的關(guān)系。使用已經(jīng)了解的dplyr
包功能,你可能會(huì)寫(xiě)出以下代碼:
by_dest <- group_by(flights, dest)
delay <- summarize(by_dest,
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
)
delay <- filter(delay, count > 20, dest != "HNL")
這樣做不得不對(duì)每個(gè)中間數(shù)據(jù)框命名,會(huì)影響我們的分析速度。解決這個(gè)問(wèn)題的另一種方法是使用管道,%>%
delays <- flights %>%
group_by(dest) %>%
summarize(
count = n(),
dist = mean(distance, na.rm = TRUE),
delay = mean(arr_delay, na.rm = TRUE)
) %>%
filter(count > 20, dest != "HNL")
使用這種方法時(shí),x %>% f(y) 會(huì)轉(zhuǎn)換為f(x, y),x %>% f(y) %>% g(z) 會(huì)轉(zhuǎn)換為g(f(x,y), z),以此類(lèi)推。你可以使用管道重寫(xiě)多種操作,將其變?yōu)槟軌驈淖蟮接一驈纳系较麻喿x。
3.6.2 缺失值
在前面使用了參數(shù)na.rm,如果沒(méi)有設(shè)置這個(gè)參數(shù),會(huì)發(fā)生什么情況呢?
>by_day <- group_by(flights, year, month, day)
>summarize(by_day, delay = mean(dep_delay))
## 使用管道
> flights %>%
+ group_by(year, month, day) %>%
+ summarize(mean = mean(dep_delay))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day mean
<int> <int> <int> <dbl>
1 2013 1 1 NA
2 2013 1 2 NA
3 2013 1 3 NA
4 2013 1 4 NA
5 2013 1 5 NA
6 2013 1 6 NA
7 2013 1 7 NA
8 2013 1 8 NA
9 2013 1 9 NA
10 2013 1 10 NA
# ... with 355 more rows
這是因?yàn)榫酆虾瘮?shù)遵循缺失值的一般規(guī)則:如果輸入中有缺失值,那么輸出也會(huì)是缺失值。好在所有聚合函數(shù)都有一個(gè)na.rm 參數(shù),它可以在計(jì)算前除去缺失值:
> flights %>%
+ group_by(year, month, day) %>%
+ summarize(mean = mean(dep_delay,na.rm= TRUE))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day mean
<int> <int> <int> <dbl>
1 2013 1 1 11.5
2 2013 1 2 13.9
3 2013 1 3 11.0
4 2013 1 4 8.95
5 2013 1 5 5.73
6 2013 1 6 7.15
7 2013 1 7 5.42
8 2013 1 8 2.55
9 2013 1 9 2.28
10 2013 1 10 2.84
# ... with 355 more rows
在這個(gè)示例中,缺失值表示取消的航班,我們也可以通過(guò)先去除取消的航班來(lái)解決缺失值
問(wèn)題。保存這個(gè)數(shù)據(jù)集,以便我們可以在接下來(lái)的幾個(gè)示例中繼續(xù)使用:
not_cancelled <- flights %>%
filter(!is.na(dep_delay), !is.na(arr_delay))
> not_cancelled %>%
+ group_by(year, month, day) %>%
+ summarize(mean = mean(dep_delay))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day mean
<int> <int> <int> <dbl>
1 2013 1 1 11.4
2 2013 1 2 13.7
3 2013 1 3 10.9
4 2013 1 4 8.97
5 2013 1 5 5.73
6 2013 1 6 7.15
7 2013 1 7 5.42
8 2013 1 8 2.56
9 2013 1 9 2.30
10 2013 1 10 2.84
# ... with 355 more rows
3.6.3 計(jì)數(shù)
聚合操作中包括一個(gè)計(jì)數(shù)(n())或非缺失值的計(jì)數(shù)(sum(!is_na()))是個(gè)好主意。這樣你就可以檢查一下,以確保自己沒(méi)有基于非常少量的數(shù)據(jù)作出結(jié)論。例如,我們查看一下具有最長(zhǎng)平均延誤時(shí)間的飛機(jī)(通過(guò)機(jī)尾編號(hào)進(jìn)行識(shí)別):
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarize(
delay = mean(arr_delay)
)
ggplot(data = delays, mapping = aes(x = delay)) +
geom_freqpoly(binwidth = 10)
接下來(lái),畫(huà)一張航班數(shù)量和平均延誤時(shí)間的散點(diǎn)圖,以便獲得更深刻的理解:
delays <- not_cancelled %>%
group_by(tailnum) %>% #--根據(jù)tailnum對(duì)not_cancelled分組
summarize(
delay = mean(arr_delay, na.rm = TRUE),
n = n() #--根據(jù)每個(gè)組求arr_delay的平均值并計(jì)數(shù)
)
# A tibble: 4,037 x 3
tailnum delay n
<chr> <dbl> <int>
1 D942DN 31.5 4
2 N0EGMQ 9.98 352
3 N10156 12.7 145
4 N102UW 2.94 48
5 N103US -6.93 46
6 N104UW 1.80 46
7 N10575 20.7 269
8 N105UW -0.267 45
9 N107US -5.73 41
10 N108UW -1.25 60
# ... with 4,027 more rows
ggplot(data = delays, mapping = aes(x = n, y = delay)) +
geom_point(alpha = 1/10)
當(dāng)航班數(shù)量非常少時(shí),平均延誤時(shí)間的變動(dòng)特別大。這張圖的形狀非常能夠說(shuō)明問(wèn)題:當(dāng)繪制均值(或其他摘要統(tǒng)計(jì)量)和分組規(guī)模的關(guān)系時(shí),你總能看到隨著樣本量的增加,變動(dòng)在不斷減小。
查看此類(lèi)圖形時(shí),通常應(yīng)該篩選掉那些觀測(cè)數(shù)量非常少的分組,這樣你就可以避免受到特
別小的分組中的極端變動(dòng)的影響,進(jìn)而更好地發(fā)現(xiàn)數(shù)據(jù)模式。
> delays %>%
+ filter(n > 25) %>%
+ ggplot(mapping = aes(x = n, y = delay)) +
+ geom_point(alpha = 1/10)
3.6.4 常用的摘要函數(shù)
只使用均值、計(jì)數(shù)和求和是遠(yuǎn)遠(yuǎn)不夠的,R 中還提供了很多其他的常用的摘要函數(shù)。
位置度量
我們已經(jīng)使用過(guò)mean(x),但median(x) 也非常有用。均值是總數(shù)除以個(gè)數(shù);中位數(shù)則
是這樣一個(gè)值:50% 的x 大于它,同時(shí)50% 的x 小于它。
> not_cancelled %>%
+ group_by(year, month, day) %>%
+ summarize(
+ # 平均延誤時(shí)間:
+ avg_delay1 = mean(arr_delay),
+ # 平均正延誤時(shí)間:
+ avg_delay2 = mean(arr_delay[arr_delay > 0])
+ )
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 5
# Groups: year, month [12]
year month day avg_delay1 avg_delay2
<int> <int> <int> <dbl> <dbl>
1 2013 1 1 12.7 32.5
2 2013 1 2 12.7 32.0
3 2013 1 3 5.73 27.7
4 2013 1 4 -1.93 28.3
5 2013 1 5 -1.53 22.6
6 2013 1 6 4.24 24.4
7 2013 1 7 -4.95 27.8
8 2013 1 8 -3.23 20.8
9 2013 1 9 -0.264 25.6
10 2013 1 10 -5.90 27.3
# ... with 355 more rows
分散程度度量:sd(x)、IQR(x) 和mad(x)
均方誤差(又稱(chēng)標(biāo)準(zhǔn)誤差,standard deviation,sd)是分散程度的標(biāo)準(zhǔn)度量方式。四分位距IQR() 和絕對(duì)中位差mad(x) 基本等價(jià),更適合有離群點(diǎn)的情況:
> # 為什么到某些目的地的距離比到其他目的地更多變?
> not_cancelled %>%
+ group_by(dest) %>%
+ summarize(distance_sd = sd(distance)) %>%
+ arrange(desc(distance_sd))
`summarise()` ungrouping output (override with `.groups` argument)
# A tibble: 104 x 2
dest distance_sd
<chr> <dbl>
1 EGE 10.5
2 SAN 10.4
3 SFO 10.2
4 HNL 10.0
5 SEA 9.98
6 LAS 9.91
7 PDX 9.87
8 PHX 9.86
9 LAX 9.66
10 IND 9.46
# ... with 94 more rows
秩的度量:min(x)、quantile(x, 0.25) 和max(x)
分位數(shù)是中位數(shù)的擴(kuò)展。例如,quantile(x, 0.25) 會(huì)找出x 中按從小到大順序大于前25% 而小于后75% 的值:
> # 每天最早和最晚的航班何時(shí)出發(fā)?
> not_cancelled %>%
+ group_by(year, month, day) %>%
+ summarize(
+ first = min(dep_time),
+ last = max(dep_time)
+ )
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 5
# Groups: year, month [12]
year month day first last
<int> <int> <int> <int> <int>
1 2013 1 1 517 2356
2 2013 1 2 42 2354
3 2013 1 3 32 2349
4 2013 1 4 25 2358
5 2013 1 5 14 2357
6 2013 1 6 16 2355
7 2013 1 7 49 2359
8 2013 1 8 454 2351
9 2013 1 9 2 2252
10 2013 1 10 3 2320
# ... with 355 more rows
定位度量:first(x)、nth(x, 2) 和last(x)
這幾個(gè)函數(shù)的作用與x[1]、x[2] 和x[length(x)] 相同,只是當(dāng)定位不存在時(shí)(比如嘗試從只有兩個(gè)元素的分組中得到第三個(gè)元素),前者允許你設(shè)置一個(gè)默認(rèn)值。例如,我們可以找出每天最早和最晚出發(fā)的航班:
> not_cancelled %>%
+ group_by(year, month, day) %>%
+ summarize(
+ first_dep = first(dep_time),
+ last_dep = last(dep_time)
+ )
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 5
# Groups: year, month [12]
year month day first_dep last_dep
<int> <int> <int> <int> <int>
1 2013 1 1 517 2356
2 2013 1 2 42 2354
3 2013 1 3 32 2349
4 2013 1 4 25 2358
5 2013 1 5 14 2357
6 2013 1 6 16 2355
7 2013 1 7 49 2359
8 2013 1 8 454 2351
9 2013 1 9 2 2252
10 2013 1 10 3 2320
# ... with 355 more rows
計(jì)數(shù)
已經(jīng)使用過(guò)n(),它不需要任何參數(shù),并返回當(dāng)前分組的大小。如果想要計(jì)算出非缺失值的數(shù)量,可以使用sum(!is.na(x))。要想計(jì)算出唯一值的數(shù)量,可以使用n_distinct(x):
> # 哪個(gè)目的地具有最多的航空公司?
> not_cancelled %>%
+ group_by(dest) %>%
+ summarize(carriers = n_distinct(carrier)) %>%
+ arrange(desc(carriers))
`summarise()` ungrouping output (override with `.groups` argument)
# A tibble: 104 x 2
dest carriers
<chr> <int>
1 ATL 7
2 BOS 7
3 CLT 7
4 ORD 7
5 TPA 7
6 AUS 6
7 DCA 6
8 DTW 6
9 IAD 6
10 MSP 6
# ... with 94 more rows
因?yàn)橛?jì)數(shù)太常用了,所以dplyr 提供了一個(gè)簡(jiǎn)單的輔助函數(shù),用于只需要計(jì)數(shù)的情況:
> not_cancelled %>%
+ count(dest)
# A tibble: 104 x 2
dest n
<chr> <int>
1 ABQ 254
2 ACK 264
3 ALB 418
4 ANC 8
5 ATL 16837
6 AUS 2411
7 AVL 261
8 BDL 412
9 BGR 358
10 BHM 269
# ... with 94 more rows
還可以選擇提供一個(gè)加權(quán)變量。例如,你可以使用以下代碼算出每架飛機(jī)飛行的總里程數(shù)(實(shí)際上就是求和):
> not_cancelled %>%
+ count(tailnum, wt = distance)
# A tibble: 4,037 x 2
tailnum n
<chr> <dbl>
1 D942DN 3418
2 N0EGMQ 239143
3 N10156 109664
4 N102UW 25722
5 N103US 24619
6 N104UW 24616
7 N10575 139903
8 N105UW 23618
9 N107US 21677
10 N108UW 32070
# ... with 4,027 more rows
邏輯值的計(jì)數(shù)和比例:sum(x > 10) 和mean(y == 0)
當(dāng)與數(shù)值型函數(shù)一同使用時(shí),TRUE 會(huì)轉(zhuǎn)換為1,F(xiàn)ALSE 會(huì)轉(zhuǎn)換為0。這使得sum() 和mean()非常適用于邏輯值:sum(x) 可以找出x 中TRUE 的數(shù)量,mean(x) 則可以找出比例。
> # 多少架航班是在早上5點(diǎn)前出發(fā)的?(這通常表明前一天延誤的航班數(shù)量)
> not_cancelled %>%
+ group_by(year, month, day) %>%
+ summarize(n_early = sum(dep_time < 500))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day n_early
<int> <int> <int> <int>
1 2013 1 1 0
2 2013 1 2 3
3 2013 1 3 4
4 2013 1 4 3
5 2013 1 5 3
6 2013 1 6 2
7 2013 1 7 2
8 2013 1 8 1
9 2013 1 9 3
10 2013 1 10 3
# ... with 355 more rows
> # 延誤超過(guò)1小時(shí)的航班比例是多少?
> not_cancelled %>%
+ group_by(year, month, day) %>%
+ summarize(hour_perc = mean(arr_delay > 60))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day hour_perc
<int> <int> <int> <dbl>
1 2013 1 1 0.0722
2 2013 1 2 0.0851
3 2013 1 3 0.0567
4 2013 1 4 0.0396
5 2013 1 5 0.0349
6 2013 1 6 0.0470
7 2013 1 7 0.0333
8 2013 1 8 0.0213
9 2013 1 9 0.0202
10 2013 1 10 0.0183
# ... with 355 more rows
3.6.5 按多個(gè)變量分組
當(dāng)使用多個(gè)變量進(jìn)行分組時(shí),每次的摘要統(tǒng)計(jì)會(huì)用掉一個(gè)分組變量。這樣就可以輕松地對(duì)數(shù)據(jù)集進(jìn)行循序漸進(jìn)的分析
> daily <- group_by(flights, year, month, day)
> (per_day <- summarize(daily, flights = n()))
`summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
# A tibble: 365 x 4
# Groups: year, month [12]
year month day flights
<int> <int> <int> <int>
1 2013 1 1 842
2 2013 1 2 943
3 2013 1 3 914
4 2013 1 4 915
5 2013 1 5 720
6 2013 1 6 832
7 2013 1 7 933
8 2013 1 8 899
9 2013 1 9 902
10 2013 1 10 932
# ... with 355 more rows
> (per_month <- summarize(per_day, flights = sum(flights)))
`summarise()` regrouping output by 'year' (override with `.groups` argument)
# A tibble: 12 x 3
# Groups: year [1]
year month flights
<int> <int> <int>
1 2013 1 27004
2 2013 2 24951
3 2013 3 28834
4 2013 4 28330
5 2013 5 28796
6 2013 6 28243
7 2013 7 29425
8 2013 8 29327
9 2013 9 27574
10 2013 10 28889
11 2013 11 27268
12 2013 12 28135
#可以發(fā)現(xiàn)day分組已經(jīng)消失
3.6.6 取消分組
如果想要取消分組,并回到未分組的數(shù)據(jù)繼續(xù)操作,那么可以使用ungroup() 函數(shù):
> daily %>%
+ ungroup() %>% # 不再按日期分組
+ summarize(flights = n()) # 所有航班
# A tibble: 1 x 1
flights
<int>
1 336776
3.7 分組新變量
雖然與summarize() 函數(shù)結(jié)合起來(lái)使用是最有效的,但分組也可以與mutate() 和filter()函數(shù)結(jié)合,以完成非常便捷的操作。
找出每個(gè)分組中最差的成員:
> flights_sml %>%
+ group_by(year, month, day) %>%
+ filter(rank(desc(arr_delay)) < 10)
# A tibble: 3,306 x 7
# Groups: year, month, day [365]
year month day dep_delay arr_delay distance air_time
<int> <int> <int> <dbl> <dbl> <dbl> <dbl>
1 2013 1 1 853 851 184 41
2 2013 1 1 290 338 1134 213
3 2013 1 1 260 263 266 46
4 2013 1 1 157 174 213 60
5 2013 1 1 216 222 708 121
6 2013 1 1 255 250 589 115
7 2013 1 1 285 246 1085 146
8 2013 1 1 192 191 199 44
9 2013 1 1 379 456 1092 222
10 2013 1 2 224 207 550 94
# ... with 3,296 more rows
找出大于某個(gè)閾值的所有分組:
> popular_dests <- flights %>%
+ group_by(dest) %>%
+ filter(n() > 365)
> popular_dests
# A tibble: 332,577 x 19
# Groups: dest [77]
year month day dep_time sched_dep_time dep_delay
<int> <int> <int> <int> <int> <dbl>
1 2013 1 1 517 515 2
2 2013 1 1 533 529 4
3 2013 1 1 542 540 2
4 2013 1 1 544 545 -1
5 2013 1 1 554 600 -6
6 2013 1 1 554 558 -4
7 2013 1 1 555 600 -5
8 2013 1 1 557 600 -3
9 2013 1 1 557 600 -3
10 2013 1 1 558 600 -2
# ... with 332,567 more rows, and 13 more variables:
# arr_time <int>, sched_arr_time <int>, arr_delay <dbl>,
# carrier <chr>, flight <int>, tailnum <chr>, origin <chr>,
# dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
# minute <dbl>, time_hour <dttm>
對(duì)數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化以計(jì)算分組指標(biāo):
> popular_dests %>%
+ filter(arr_delay > 0) %>%
+ mutate(prop_delay = arr_delay / sum(arr_delay)) %>%
+ select(year:day, dest, arr_delay, prop_delay)
# A tibble: 131,106 x 6
# Groups: dest [77]
year month day dest arr_delay prop_delay
<int> <int> <int> <chr> <dbl> <dbl>
1 2013 1 1 IAH 11 0.000111
2 2013 1 1 IAH 20 0.000201
3 2013 1 1 MIA 33 0.000235
4 2013 1 1 ORD 12 0.0000424
5 2013 1 1 FLL 19 0.0000938
6 2013 1 1 ORD 8 0.0000283
7 2013 1 1 LAX 7 0.0000344
8 2013 1 1 DFW 31 0.000282
9 2013 1 1 ATL 12 0.0000400
10 2013 1 1 DTW 16 0.000116
# ... with 131,096 more rows