寫在前面
本系列推文為《R for Data Science (2)》的中文翻譯版本。所有內容都通過開源免費的方式上傳至Github,歡迎大家參與貢獻,詳細信息見:
Books-zh-cn 項目介紹:
Books-zh-cn:開源免費的中文書籍社區
r4ds-zh-cn Github 地址:
https://github.com/Books-zh-cn/r4ds-zh-cn
r4ds-zh-cn 網站地址:
https://books-zh-cn.github.io/r4ds-zh-cn/
目錄
-
3.1 介紹
-
3.2 行
-
3.3 列
3.1 介紹
可視化是生成洞察力的重要工具,但很少有數據以完全符合你所需的形式提供,以制作你想要的圖形。通常情況下,你需要創建一些新的變量或摘要統計信息來回答你的問題,或者你可能只是想重命名變量或重新排序觀測結果,以便更輕松地處理數據。在本章中,你將學習如何使用 dplyr 包進行數據轉換(data transformation),并使用關于 2013 年從紐約市出發的航班的新數據集來介紹這些內容,并且你還將學習更多相關的知識!
本章的目標是為你提供轉換數據框的所有關鍵工具的概述。我們將從對數據框的行和列進行操作的函數開始,然后再回到管道操作符的討論,這是一個重要的工具,用于組合操作。然后,我們將介紹如何使用分組進行操作。最后,我們將通過一個案例研究展示這些函數的實際應用,并在后續章節中更詳細地討論這些函數,以便深入研究特定類型的數據 (e.g., numbers, strings, dates)。
3.1.1 先決條件
在本章中,我們將關注 dplyr 包,它是 tidyverse 的另一個核心成員。我們將使用 nycflights13 包中的數據說明關鍵思想,并使用 ggplot2 幫助我們理解數據。
library(nycflights13)
library(tidyverse)
#>?──?Attaching?core?tidyverse?packages?─────────────────────?tidyverse?2.0.0?──
#>???dplyr?????1.1.4???????readr?????2.1.5
#>???forcats???1.0.0???????stringr???1.5.1
#>???ggplot2???3.5.2???????tibble????3.3.0
#>???lubridate?1.9.4???????tidyr?????1.3.1
#>???purrr?????1.0.4?????
#>?──?Conflicts?───────────────────────────────────────?tidyverse_conflicts()?──
#>???dplyr::filter()?masks?stats::filter()
#>???dplyr::lag()????masks?stats::lag()
#>???Use?the?conflicted?package?(<http://conflicted.r-lib.org/>)?to?force?all?conflicts?to?become?errors
請仔細注意加載 tidyverse 時打印的沖突消息(conflicts message)。它告訴你 dplyr 覆蓋了 base R 中的一些函數。如果你想在加載 dplyr 后使用這些函數的 base 版本,你需要使用它們的全名:stats::filter()
和 stats::lag()
。到目前為止,我們大多忽略了一個函數來自哪個包,因為大多數時候它并不重要。但是,了解包可以幫助您找到幫助并找到相關函數,因此當我們需要準確了解某個函數來自哪個包時,我們將使用與 R 相同的語法:packagename::functionname()
。
3.1.2 nycflights13
為了探索基本的 dplyr 動詞(verbs),我們將使用 nycflights13::flights
。該數據集包含 2013 年從紐約市起飛的所有 336,776 航班。數據來自美國 Bureau of Transportation Statistics,記錄在 ?flights
中。
flights
#>?#?A?tibble:?336,776?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???336,770?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
flights
是一個 tibble,一種特殊類型的 data frame,tidyverse 使用它來避免一些常見的問題。tibbles 和 data frame 之間最重要的區別是 tibbles 的打印方式;它們是為大型數據集設計的,因此它們只顯示前幾行,并且只顯示適合一個屏幕的列。有幾個選項可以查看所有內容。如果您使用的是 RStudio,最方便的可能是 View(flights)
,它將打開一個交互式的可滾動和可過濾的視圖。另外,您可以使用 print(flights, width = Inf)
來顯示所有列,或使用 glimpse()
:
glimpse(flights)
#>?Rows:?336,776
#>?Columns:?19
#>?$?year???????????<int>?2013,?2013,?2013,?2013,?2013,?2013,?2013,?2013,?2013…
#>?$?month??????????<int>?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1…
#>?$?day????????????<int>?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1,?1…
#>?$?dep_time???????<int>?517,?533,?542,?544,?554,?554,?555,?557,?557,?558,?55…
#>?$?sched_dep_time?<int>?515,?529,?540,?545,?600,?558,?600,?600,?600,?600,?60…
#>?$?dep_delay??????<dbl>?2,?4,?2,?-1,?-6,?-4,?-5,?-3,?-3,?-2,?-2,?-2,?-2,?-2,…
#>?$?arr_time???????<int>?830,?850,?923,?1004,?812,?740,?913,?709,?838,?753,?8…
#>?$?sched_arr_time?<int>?819,?830,?850,?1022,?837,?728,?854,?723,?846,?745,?8…
#>?$?arr_delay??????<dbl>?11,?20,?33,?-18,?-25,?12,?19,?-14,?-8,?8,?-2,?-3,?7,…
#>?$?carrier????????<chr>?"UA",?"UA",?"AA",?"B6",?"DL",?"UA",?"B6",?"EV",?"B6"…
#>?$?flight?????????<int>?1545,?1714,?1141,?725,?461,?1696,?507,?5708,?79,?301…
#>?$?tailnum????????<chr>?"N14228",?"N24211",?"N619AA",?"N804JB",?"N668DN",?"N…
#>?$?origin?????????<chr>?"EWR",?"LGA",?"JFK",?"JFK",?"LGA",?"EWR",?"EWR",?"LG…
#>?$?dest???????????<chr>?"IAH",?"IAH",?"MIA",?"BQN",?"ATL",?"ORD",?"FLL",?"IA…
#>?$?air_time???????<dbl>?227,?227,?160,?183,?116,?150,?158,?53,?140,?138,?149…
#>?$?distance???????<dbl>?1400,?1416,?1089,?1576,?762,?719,?1065,?229,?944,?73…
#>?$?hour???????????<dbl>?5,?5,?5,?5,?6,?5,?6,?6,?6,?6,?6,?6,?6,?6,?6,?5,?6,?6…
#>?$?minute?????????<dbl>?15,?29,?40,?45,?0,?58,?0,?0,?0,?0,?0,?0,?0,?0,?0,?59…
#>?$?time_hour??????<dttm>?2013-01-01?05:00:00,?2013-01-01?05:00:00,?2013-01-0…
在這兩個視圖中,變量名稱后跟縮寫,告訴您每個變量的類型:<int>
是整數(integer)的縮寫,<dbl>
是雙精度(double)(又名實數)的縮寫,<chr>
用于字符(character)(也稱為字符串),<dttm>
用于日期時間(date-time)。這些很重要,因為您可以對列執行的操作在很大程度上取決于其”類型”。
3.1.3 dplyr 基礎
您將學習主要的 dplyr verbs(functions),這將使您能夠解決絕大多數數據操作挑戰。但在我們討論它們的個體差異之前,有必要先說明一下它們的共同點:
-
第一個參數始終是一個 data frame。
-
隨后的參數通常使用變量名稱(不帶引號)描述要對哪些列進行操作。
-
輸出總是一個新的 data frame。
因為每個 verb 都擅長做一件事,解決復雜問題通常需要組合多個 verbs,我們將使用豎線 |>
來實現。我們將在 Section 3.4
中更多地討論管道,但簡而言之,管道將其左側的東西傳遞給右側的函數,因此 x |> f(y)
等價于 f(x, y)
,而 x |> f(y) |> g(z)
等價于 g(f(x, y), z)
。管道的最簡單發音是 “then”。即使您尚未了解詳細信息,也可以了解以下代碼:
flights?|>filter(dest?==?"IAH")?|>?group_by(year,?month,?day)?|>?summarize(arr_delay?=?mean(arr_delay,?na.rm?=?TRUE))
dplyr 的 verbs 根據操作對象分為四組:rows, columns, groups, or tables。在接下來的部分中,您將學習 rows、columns 和 groups 最重要的 verbs,然后我們將回到 Chapter 19
中用于 tables 的連接動詞。讓我們開始吧!
3.2 行
對數據集的行進行操作的最重要的 verbs 是 filter()
,它改變了哪些行存在而不改變它們的順序,以及 arrange()
,它改變了行的順序而不改變存在的行。這兩個函數只影響行,列保持不變。我們還將討論 distinct()
,它可以找到具有唯一值的行,但與 arrange()
和 filter()
不同的是,它還可以選擇性地修改列。
3.2.1 filter()
filter()
允許您根據列的值保留行。第一個參數是 data frame。第二個和后續參數是必須為真才能保留該行的條件。例如,我們可以找到所有晚點超過 120 分鐘(兩小時)的航班:
flights?|>?filter(dep_delay?>?120)
#>?#?A?tibble:?9,723?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????848???????????1835???????853?????1001???????????1950
#>?2??2013?????1?????1??????957????????????733???????144?????1056????????????853
#>?3??2013?????1?????1?????1114????????????900???????134?????1447???????????1222
#>?4??2013?????1?????1?????1540???????????1338???????122?????2020???????????1825
#>?5??2013?????1?????1?????1815???????????1325???????290?????2120???????????1542
#>?6??2013?????1?????1?????1842???????????1422???????260?????1958???????????1535
#>?#???9,717?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
除了 >
(大于),您還可以使用 >=
(大于或等于)、<
(小于)、<=
(小于或等于)、==
(等于)和 !=
(不等于)。您還可以將條件與 &
或 ,
結合起來以指示 “and”(檢查兩個條件)或與 |
結合以指示 “or”(檢查任一條件):
#?Flights?that?departed?on?January?1
flights?|>?filter(month?==?1?&?day?==?1)
#>?#?A?tibble:?842?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???836?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…#?Flights?that?departed?in?January?or?February
flights?|>?filter(month?==?1?|?month?==?2)
#>?#?A?tibble:?51,955?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???51,949?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
組合 |
和 ==
時有一個有用的快捷方式:%in%
。它保留變量等于右側值之一的行:
#?A?shorter?way?to?select?flights?that?departed?in?January?or?February
flights?|>?filter(month?%in%?c(1,?2))
#>?#?A?tibble:?51,955?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???51,949?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
我們將在 Chapter 12
中更詳細地回到這些比較和邏輯運算符。
當你運行 filter()
時,dplyr 執行過濾操作,創建一個新的數據框,然后打印它。它不會修改現有的 flights
數據集,因為 dplyr 函數從不修改其輸入。要保存結果,您需要使用賦值運算符,<-
:
jan1?<-?flights?|>?filter(month?==?1?&?day?==?1)
3.2.2 常見錯誤
當您開始使用 R 時,最容易犯的錯誤是在測試相等性時使用 =
而不是 ==
。filter()
會在發生這種情況時通知您:
flights?|>?filter(month?=?1)
#>?Error?in?`filter()`:
#>?!?We?detected?a?named?input.
#>???This?usually?means?that?you've?used?`=`?instead?of?`==`.
#>???Did?you?mean?`month?==?1`?
另一個錯誤是你像用英語那樣寫 “or” 語句:
flights?|>?filter(month?==?1?|?2)
這個能夠工作,因為它不會拋出錯誤,但它不會得到你想要的結果,因為 |
首先檢查條件 month == 1
然后檢查條件 2
,這不是一個明智的檢查條件。我們將在 Section 12.3.2
中詳細了解這里發生的事情以及原因。
3.2.3 arrange()
arrange()
根據列(columns)的值更改行(rows)的順序。它接受一個 data frame 和一組要按順序排列的列名(column names)(或更復雜的表達式)。如果提供多個列名(column names),每個額外的列將用于解決前面列的值相等的情況。例如,下面的代碼按照出發時間排序,該時間跨越了四列。我們首先獲取最早的年份(years),然后在一年內獲取最早的月份(months),以此類推。
flights?|>?arrange(year,?month,?day,?dep_time)
#>?#?A?tibble:?336,776?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???336,770?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
在 arrange()
內部,您可以對列使用 desc()
函數,以便按降序(從大到小)重新排序數據框。例如,以下代碼按延誤時間從最長到最短的順序排序航班:
flights?|>?arrange(desc(dep_delay))
#>?#?A?tibble:?336,776?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????9??????641????????????900??????1301?????1242???????????1530
#>?2??2013?????6????15?????1432???????????1935??????1137?????1607???????????2120
#>?3??2013?????1????10?????1121???????????1635??????1126?????1239???????????1810
#>?4??2013?????9????20?????1139???????????1845??????1014?????1457???????????2210
#>?5??2013?????7????22??????845???????????1600??????1005?????1044???????????1815
#>?6??2013?????4????10?????1100???????????1900???????960?????1342???????????2211
#>?#???336,770?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
請注意,行的數量沒有改變 – 我們只是重新排列了數據,而沒有對其進行篩選。
3.2.4 distinct()
distinct()
函數用于在數據集中查找所有唯一的行,因此從技術上講,它主要操作行。然而,大多數情況下,您希望獲取某些變量的唯一組合,因此您也可以選擇性地提供列名:
#?Remove?duplicate?rows,?if?any
flights?|>?distinct()
#>?#?A?tibble:?336,776?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???336,770?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…#?Find?all?unique?origin?and?destination?pairs
flights?|>?distinct(origin,?dest)
#>?#?A?tibble:?224?×?2
#>???origin?dest?
#>???<chr>??<chr>
#>?1?EWR????IAH??
#>?2?LGA????IAH??
#>?3?JFK????MIA??
#>?4?JFK????BQN??
#>?5?LGA????ATL??
#>?6?EWR????ORD??
#>?#???218?more?rows
另外,如果您在篩選唯一行時想要保留其他列,可以使用 .keep_all = TRUE
選項。
flights?|>?distinct(origin,?dest,?.keep_all?=?TRUE)
#>?#?A?tibble:?224?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???218?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
并非巧合,所有這些唯一的航班都是在 1 月 1 日:distinct()
函數將找到數據集中唯一行的第一個出現,并丟棄其余的重復行。
如果您想找到每個唯一行的出現次數,最好將 distinct()
替換為 count()
函數,并使用 sort = TRUE
參數按出現次數的降序排列它們。您可以在 Section 13.3
中了解更多關于 count()
函數的內容。
flights?|>count(origin,?dest,?sort?=?TRUE)
#>?#?A?tibble:?224?×?3
#>???origin?dest??????n
#>???<chr>??<chr>?<int>
#>?1?JFK????LAX???11262
#>?2?LGA????ATL???10263
#>?3?LGA????ORD????8857
#>?4?JFK????SFO????8204
#>?5?LGA????CLT????6168
#>?6?EWR????ORD????6100
#>?#???218?more?rows
3.2.5 練習
-
在每個條件的單個管道中,找到滿足條件的所有航班(flights):
-
到達延遲了兩個或更長時間
-
Flew 到 Houston (
IAH
orHOU
) -
由 United, American, 或 Delta 運營
-
在夏天離開 (July, August, and September)
-
遲到了超過兩個小時,但沒有晚出發
-
被延遲至少一個小時,但在飛行中彌補了30分鐘以上
-
對
flights
進行排序以查找起飛延誤(departure delays)時間最長的航班。查找早上最早起飛的航班。 -
對
flights
進行排序以找到最快的航班。(提示:嘗試在你的函數中包含一個數學計算。) -
2013 年每天都有航班嗎?
-
哪些航班飛行距離最遠?哪個航班飛行距離最短?
-
如果同時使用
filter()
和arrange()
,那么使用它們的順序有什么關系嗎?為什么/為什么不?考慮結果以及功能必須完成的工作量。
3.3 列
有四個重要的 verbs 可以在不更改行的情況下影響列:mutate()
創建從現有列派生的新列,select()
更改存在的列,rename()
更改列的名稱,relocate()
更改列的位置。
3.3.1 mutate()
mutate()
的工作是添加根據現有列計算的新列。在轉換(transform)章節中,您將學習大量可用于操作不同類型變量的函數。現在,我們將堅持使用基本代數,它允許我們計算 gain
、延遲航班在空中補足的時間以及以英里/小時為單位的 speed
:
flights?|>?mutate(gain?=?dep_delay?-?arr_delay,speed?=?distance?/?air_time?*?60)
#>?#?A?tibble:?336,776?×?21
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???336,770?more?rows
#>?#???13?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
默認情況下,mutate()
會在數據集的右側添加新列,這使得很難看出這里發生了什么。我們可以使用 .before
參數將變量添加到左側:
flights?|>?mutate(gain?=?dep_delay?-?arr_delay,speed?=?distance?/?air_time?*?60,.before?=?1)
#>?#?A?tibble:?336,776?×?21
#>????gain?speed??year?month???day?dep_time?sched_dep_time?dep_delay?arr_time
#>???<dbl>?<dbl>?<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>
#>?1????-9??370.??2013?????1?????1??????517????????????515?????????2??????830
#>?2???-16??374.??2013?????1?????1??????533????????????529?????????4??????850
#>?3???-31??408.??2013?????1?????1??????542????????????540?????????2??????923
#>?4????17??517.??2013?????1?????1??????544????????????545????????-1?????1004
#>?5????19??394.??2013?????1?????1??????554????????????600????????-6??????812
#>?6???-16??288.??2013?????1?????1??????554????????????558????????-4??????740
#>?#???336,770?more?rows
#>?#???12?more?variables:?sched_arr_time?<int>,?arr_delay?<dbl>,?…
.
表示 .before
是函數的參數,而不是我們正在創建的第三個新變量的名稱。您還可以使用 .after
來在變量之后添加,并且在 .before
和 .after
中都可以使用變量名而不是位置。例如,我們可以在 day
之后添加新變量:
flights?|>?mutate(gain?=?dep_delay?-?arr_delay,speed?=?distance?/?air_time?*?60,.after?=?day)
或者,您可以使用 .keep
參數控制保留哪些變量。一個特別有用的參數是 "used"
,它指定我們只保留在 mutate()
步驟中涉及或創建的列。例如,以下輸出將僅包含變量 dep_delay
, arr_delay
, air_time
, gain
, hours
, and gain_per_hour
。
flights?|>?mutate(gain?=?dep_delay?-?arr_delay,hours?=?air_time?/?60,gain_per_hour?=?gain?/?hours,.keep?=?"used")
請注意,由于我們尚未將上述計算的結果分配回 flights
,因此新變量 gain
、hours
、gain_per_hour
只會被打印出來,而不會存儲在數據框中。如果我們希望它們在數據框中可用以供將來使用,我們應該仔細考慮是否要將結果分配回 flights
,用更多變量覆蓋原始數據框,或者分配給一個新對象。通常,正確的答案是一個新對象,該對象以信息性命名以指示其內容,例如 delay_gain
,但您也可能有充分的理由覆蓋 flights
。
3.3.2 select()
獲取包含數百甚至數千個變量的數據集并不少見。在這種情況下,第一個挑戰通常只是關注您感興趣的變量。select()
允許您使用基于變量名稱的操作快速放大有用的子集:
-
按名稱選擇列:
flights?|>?select(year,?month,?day)
-
選擇 year 和 day(含)之間的所有列:
flights?|>?select(year:day)
-
選擇除了 year 到 day(含)以外的所有列:
flights?|>?select(!year:day)
您也可以使用 -
代替 !
(您很可能會在野外看到它);我們推薦 !
因為它讀起來像 “not”,并且與 &
和 |
結合得很好。
-
選擇所有 characters 列:
flights?|>?select(where(is.character))
您可以在 select()
中使用許多輔助函數:
-
starts_with("abc")
: 匹配以 “abc” 開頭的名稱。 -
ends_with("xyz")
: 匹配以 “xyz” 結尾的名稱。 -
contains("ijk")
: 匹配包含 “ijk” 的名稱。 -
num_range("x", 1:3)
: 匹配x1
、x2
和x3
。
有關詳細信息,請參閱 ?select
。一但你了解正則表達式(the topic of Chapter 15
),您還可以使用 matches()
來選擇與模式匹配的變量。
您可以在使用 =
在 select()
時重命名變量。新名稱出現在 =
的左側,舊變量出現在右側:
flights?|>?select(tail_num?=?tailnum)
#>?#?A?tibble:?336,776?×?1
#>???tail_num
#>???<chr>???
#>?1?N14228??
#>?2?N24211??
#>?3?N619AA??
#>?4?N804JB??
#>?5?N668DN??
#>?6?N39463??
#>?#???336,770?more?rows
3.3.3 rename()
如果你想保留所有現有變量并且只想重命名一些變量,你可以使用 rename()
而不是 select()
:
flights?|>?rename(tail_num?=?tailnum)
#>?#?A?tibble:?336,776?×?19
#>????year?month???day?dep_time?sched_dep_time?dep_delay?arr_time?sched_arr_time
#>???<int>?<int>?<int>????<int>??????????<int>?????<dbl>????<int>??????????<int>
#>?1??2013?????1?????1??????517????????????515?????????2??????830????????????819
#>?2??2013?????1?????1??????533????????????529?????????4??????850????????????830
#>?3??2013?????1?????1??????542????????????540?????????2??????923????????????850
#>?4??2013?????1?????1??????544????????????545????????-1?????1004???????????1022
#>?5??2013?????1?????1??????554????????????600????????-6??????812????????????837
#>?6??2013?????1?????1??????554????????????558????????-4??????740????????????728
#>?#???336,770?more?rows
#>?#???11?more?variables:?arr_delay?<dbl>,?carrier?<chr>,?flight?<int>,?…
如果你有一堆命名不一致的列,并且手動修復它們會很痛苦,請查看 janitor::clean_names()
,它提供了一些有用的自動清理。
3.3.4 relocate()
使用 relocate()
移動變量。您可能希望將相關變量收集在一起或將重要變量移到前面。默認情況下,relocate()
將變量移動到前面:
flights?|>?relocate(time_hour,?air_time)
#>?#?A?tibble:?336,776?×?19
#>???time_hour???????????air_time??year?month???day?dep_time?sched_dep_time
#>???<dttm>?????????????????<dbl>?<int>?<int>?<int>????<int>??????????<int>
#>?1?2013-01-01?05:00:00??????227??2013?????1?????1??????517????????????515
#>?2?2013-01-01?05:00:00??????227??2013?????1?????1??????533????????????529
#>?3?2013-01-01?05:00:00??????160??2013?????1?????1??????542????????????540
#>?4?2013-01-01?05:00:00??????183??2013?????1?????1??????544????????????545
#>?5?2013-01-01?06:00:00??????116??2013?????1?????1??????554????????????600
#>?6?2013-01-01?05:00:00??????150??2013?????1?????1??????554????????????558
#>?#???336,770?more?rows
#>?#???12?more?variables:?dep_delay?<dbl>,?arr_time?<int>,?…
您還可以使用 .before
和 .after
參數指定放置它們的位置,就像在 mutate()
中一樣:
flights?|>?relocate(year:dep_time,?.after?=?time_hour)
flights?|>?relocate(starts_with("arr"),?.before?=?dep_time)
3.3.5 練習
-
比較
dep_time
,sched_dep_time
, 和dep_delay
。您認為這三個數字之間有何關聯? -
盡可能多地集思廣益,從
flights
中選擇dep_time
、dep_delay
、arr_time
和arr_delay
。 -
如果您在
select()
調用中多次指定同一個變量的名稱,會發生什么情況? -
any_of()
函數有什么作用?為什么將它與該載體結合使用會有所幫助?
variables?<-?c("year",?"month",?"day",?"dep_delay",?"arr_delay")
-
運行以下代碼的結果是否讓您感到驚訝?默認情況下,select helpers 如何處理大寫和小寫?你怎么能改變這個默認值?
flights?|>?select(contains("TIME"))
-
將
air_time
重命名為air_time_min
以指示測量單位并將其移至數據框的開頭。 -
為什么以下不起作用,錯誤是什么意思?
flights?|>?select(tailnum)?|>?arrange(arr_delay)
#>?Error?in?`arrange()`:
#>???In?argument:?`..1?=?arr_delay`.
#>?Caused?by?error:
#>?!?object?'arr_delay'?not?found
?
--------------- 未完待續 ---------------
?
本期翻譯貢獻:
-
@TigerZ生信寶庫
?