R Select()、Filter()、Arrange()、Pipeline 及示例
⚡ 智能摘要
R 语言中的 select、filter 和 Arrange 是 dplyr 包中的三个动词,它们可以将数据框简化为所需的列、行和顺序。本教程将演示如何将它们与管道运算符结合使用,处理一个包含 205 行的旅行时间数据集。
R 语言中的 dplyr 是什么?
dplyr 是 tidyverse 的数据操作包。它取代了基础包中的方括号表示法。 R 使用一组简短的动词,每个动词都以其执行的动作命名,并且每个动词都以数据框作为其第一个参数。这种一致的结构使得动词可以串联起来。
| 动词 | 法案 | 它做什么 |
|---|---|---|
| 选择() | 列 | 保留或删除变量 |
| 过滤() | 行 | 保留符合条件的行 |
| 安排() | 行 | 按一列或多列重新排列行 |
| 变异() | 列 | 创建或修改变量 |
| 总结() | 整桌 | 将多行数据合并为单个统计信息 |
| group_by() | 整桌 | 将数据拆分,以便后续动词按组运行。 |
本教程涵盖前三个动词以及竖笛。 聚合函数教程 深入介绍 group_by() 和 summarise() 函数。
本教程中使用的数据集
dplyr 库包含用于在数据集中导航的实用动词。在本教程中,您将使用“出行时间”数据集。该数据集记录了驾驶员往返于家和工作地点之间的行程。数据集中包含十四个变量,其中包括:
- DayOfWeek:确定司机使用汽车的星期几
- 距离:旅程总距离
- MaxSpeed:行程的最大速度
- 总时间:旅程的长度(分钟)
该数据集包含 205 个观测值,骑行活动发生在 Monday 到星期五。
首先,您需要:
- 加载数据集
- 检查数据的结构。
dplyr 中一个很实用的函数是 glimpse()。它的作用与 R 基础函数 str() 相同,但它会为每个变量打印一行,包含变量类型和前几个值,这样在处理大型数据集时更容易浏览。
library(dplyr) PATH <- "https://raw.githubusercontent.com/guru99-edu/R-Programming/master/travel_times.csv" df <- read.csv(PATH) glimpse(df)
输出:
## Observations: 205 ## Variables: 14 ## $ X <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ... ## $ Date <fctr> 1/6/2012, 1/6/2012, 1/4/2012, 1/4/2012, 1/3/20... ## $ StartTime <fctr> 16:37, 08:20, 16:17, 07:53, 18:57, 07:57, 17:3... ## $ DayOfWeek <fctr> Friday, Friday, Wednesday, Wednesday, Tuesday,... ## $ GoingTo <fctr> Home, GSK, Home, GSK, Home, GSK, Home, GSK, GS... ## $ Distance <dbl> 51.29, 51.63, 51.27, 49.17, 51.15, 51.80, 51.37... ## $ MaxSpeed <dbl> 127.4, 130.3, 127.4, 132.3, 136.2, 135.8, 123.2... ## $ AvgSpeed <dbl> 78.3, 81.8, 82.0, 74.2, 83.4, 84.5, 82.9, 77.5,... ## $ AvgMovingSpeed <dbl> 84.8, 88.9, 85.8, 82.9, 88.1, 88.8, 87.3, 85.9,... ## $ FuelEconomy <fctr> , , , , , , -, -, 8.89, 8.89, 8.89, 8.89, 8.89... ## $ TotalTime <dbl> 39.3, 37.9, 37.5, 39.8, 36.8, 36.8, 37.2, 37.9,... ## $ MovingTime <dbl> 36.3, 34.9, 35.9, 35.6, 34.8, 35.0, 35.3, 34.3,... ## $ Take407All <fctr> No, No, No, No, No, No, No, No, No, No, No, No... ## $ Comments <fctr> , , , , , , , , , , , , , , , Put snow tires o...
显然需要仔细检查“评论”变量:第一个观测值全部为空。
sum(df$Comments =="")
Code 说明
- sum(df$Comments == ""): 统计数据框 df 中 Comments 列值为空字符串的观测值数量
输出:
## [1] 181
数据加载完毕后,首先执行修剪列的操作。
选择()
我们将从 select() 动词开始。我们不一定需要所有变量,一个好的做法是只选择您认为相关的变量。
我们有 181 个缺失的观测值,几乎占数据集的 90%。如果您决定排除它们,您将无法继续分析。
另一种可能性是使用 select() 动词删除变量 Comment。
我们可以使用 select() 以不同的方式选择变量。请注意,第一个参数是数据集。
- `select(df, A, B ,C)`: Select the variables A, B and C from df dataset. - `select(df, A:C)`: Select all variables from A to C from df dataset. - `select(df, -C)`: Exclude C from the dataset from df dataset.
您可以使用第三种方法来排除 Comments 变量。
step_1_df <- select(df, -Comments) dim(df)
输出:
## [1] 205 14
dim(step_1_df)
输出:
## [1] 205 13
原始数据集有 14 个特征,而 step_1_df 有 13 个。
R语言中的select()辅助函数
当数据集包含数十个变量时,为每一列命名就变得不切实际。dplyr 提供了一些辅助函数,可以按模式或类型选择列。
| 帮手 | 选择列 | 例如: |
|---|---|---|
| starts_with() | 以字符串开头 | select(df, starts_with(“Avg”)) |
| ends_with() | 以字符串结尾 | select(df, ends_with(“Time”)) |
| 包含() | 在任意位置包含字符串 | 选择(df,包含(“速度”)) |
| 火柴() | 匹配正则表达式 | select(df, matches(“^Max|^Avg”)) |
| 在哪里() | 满足类型测试要求 | select(df, where(is.numeric)) |
| 一切() | 尚未命名 | select(df, TotalTime, everything()) |
# Keep only the timing columns df %>% select(ends_with("Time")) # Keep every numeric column df %>% select(where(is.numeric)) # Move TotalTime to the front, keep the rest in place df %>% select(TotalTime, everything())
还有两个动词可以与 select() 函数自然搭配使用。使用 rename(new_name = old_name) 可以在不删除列的情况下重命名列。ping 其他列,以及 relocate() 来移动列,而无需列出所有列。
过滤()
`filter()` 函数会保留满足特定条件的观测值。`filter()` 的工作方式与 `select()` 完全相同,您需要先传入数据框,然后再传入一个用逗号分隔的条件:
filter(df, condition)
arguments:
- df: dataset used to filter the data
- condition: Condition used to filter the data
一个标准
首先,您可以计算因子变量每个级别内的观测值数量。
table(step_1_df$GoingTo)
Code 说明
- table():统计每个级别的观测值数量。它接受一个因子或字符变量。
- 表(step_1_df$GoingTo): 统计前往每个目的地的行程次数
输出:
## ## GSK Home ## 105 100
函数 table() 指示有 105 次行程去往 GSK,还有 100 次行程去往家。
我们可以过滤数据以返回一个包含 105 个观测值的数据集和另一个包含 100 个观测值的数据集。
# Select observations where GoingTo == Home select_home <- filter(df, GoingTo == "Home") dim(select_home)
输出:
## [1] 100 14
# Select observations where GoingTo == GSK (work) select_work <- filter(df, GoingTo == "GSK") dim(select_work)
输出:
## [1] 105 14
多项标准
我们可以使用多个条件来筛选数据集。例如,您可以……trac观察结果显示,目的地为家,出行日期为星期三。
select_home_wed <- filter(df, GoingTo == "Home" & DayOfWeek == "Wednesday") dim(select_home_wed)
输出:
## [1] 23 14
23 个观察结果符合该标准。
常用筛选条件和 OperaR 中的
filter() 函数会保留所有条件为 TRUE 的行。条件为 NA 的行会被删除,这种行为常常让初学者感到意外。
| Opera器 | 意 | 例如: |
|---|---|---|
| == | 等于 | filter(df, GoingTo == “Home”) |
| != | 不等于 | filter(df, DayOfWeek != “Monday“) |
| & | 而且,两者都必须满足 | filter(df, Distance > 50 & MaxSpeed > 130) |
| | | 或者,两者都可能成立。 | filter(df, DayOfWeek == “Monday” | DayOfWeek == “星期五”) |
| %在% | 匹配向量中的任何值 | filter(df, DayOfWeek %in% c(“Monday“, “星期五”)) |
| 之间() | 落在某个数值范围内 | filter(df, between(Distance, 48, 52)) |
| 是.na() | 缺失值 | filter(df, is.na(FuelEconomy)) |
养成三个习惯可以避免大部分 filter() 函数的错误。
- 使用 %in% 代替链式 OR。 filter(df, DayOfWeek %in% c(“Monday”, “星期五”)) 比两个用竖线连接的 == 比较更短,也更不容易打错。
- 永远不要用 == 来判断缺失值。 表达式 x == NA 返回的是 NA 而不是 TRUE,因此该行会被静默删除。请改用 is.na(x)。
- 逗号表示“和”。 filter(df, a, b) 与 filter(df, a & b) 完全相同,这就是为什么本教程前面的示例两种方式都能正常工作的原因。
管道 Operator 在 dplyr
数据集的创建需要很多操作,例如:
- 输入
- 合并
- 选择
- 过滤
- 等等
dplyr 库带有一个实用运算符 %>%,称为 管它使数据处理更干净、更快捷、更不容易出错。
此运算符是一种执行步骤而不将中间步骤保存到硬盘的代码。如果您回到上面的示例,您可以选择感兴趣的变量并对其进行过滤。我们有三个步骤:
- 步骤 1:导入数据:导入 GPS 数据
- 步骤 2:选择数据:选择 GoingTo 和 DayOfWeek
- 步骤 3:筛选数据:仅返回主页和星期三
我们可以用困难的方法来做这件事:
# Step 1 step_1 <- read.csv(PATH) # Step 2 step_2 <- select(step_1, GoingTo, DayOfWeek) # Step 3 step_3 <- filter(step_2, GoingTo == "Home", DayOfWeek == "Wednesday") head(step_3)
输出:
## GoingTo DayOfWeek ## 1 Home Wednesday ## 2 Home Wednesday ## 3 Home Wednesday ## 4 Home Wednesday ## 5 Home Wednesday ## 6 Home Wednesday
这不是串联多个操作的便捷方式。每个中间结果都会保留在环境中,名称很快就会失去意义。
请改用管道运算符 %>%。只需在开始时命名一次数据框,后续所有步骤都将以此为基础。
管道基本语法
New_df <- df %>% step 1 %>% step 2 %>% ... arguments - New_df: Name of the new data frame - df: Data frame used to compute the step - step: Instruction for each step - Note: the last instruction does not need a trailing `%>%`, because nothing follows it - Note: assigning the result to a new object is optional. Without it, the output prints in the console.
您可以按照上面列举的步骤创建您的第一个管道。
# Create the data frame filter_home_wed.It will be the object return at the end of the pipeline filter_home_wed <- #Step 1 read.csv(PATH) %>% #Step 2 select(GoingTo, DayOfWeek) %>% #Step 3 filter(GoingTo == "Home",DayOfWeek == "Wednesday") identical(step_3, filter_home_wed)
输出:
## [1] TRUE
这两个对象是相同的,因此管道操作用一条可读的语句产生了完全相同的结果。
安排()
在 先前的教程中,您将学习如何使用函数 sort() 对值进行排序。库 dplyr 具有其排序函数。它与管道配合得天衣无缝。arrange() 动词可以对一行或多行重新排序,可以按升序(默认)或降序排列。
- `arrange(A)`: Ascending sort of variable A - `arrange(A, B)`: Ascending sort of variable A and B - `arrange(desc(A), B)`: Descending sort of variable A and ascending sort of B
我们可以按照目的地对距离进行排序。
# Sort by destination and distance step_2_df <- step_1_df %>% arrange(GoingTo, Distance) head(step_2_df)
输出:
## X Date StartTime DayOfWeek GoingTo Distance MaxSpeed AvgSpeed ## 1 193 7/25/2011 08:06 Monday GSK 48.32 121.2 63.4 ## 2 196 7/21/2011 07:59 Thursday GSK 48.35 129.3 81.5 ## 3 198 7/20/2011 08:24 Wednesday GSK 48.50 125.8 75.7 ## 4 189 7/27/2011 08:15 Wednesday GSK 48.82 124.5 70.4 ## 5 95 10/11/2011 08:25 Tuesday GSK 48.94 130.8 85.7 ## 6 171 8/10/2011 08:13 Wednesday GSK 48.98 124.8 72.8 ## AvgMovingSpeed FuelEconomy TotalTime MovingTime Take407All ## 1 78.4 8.45 45.7 37.0 No ## 2 89.0 8.28 35.6 32.6 Yes ## 3 87.3 7.89 38.5 33.3 Yes ## 4 77.8 8.45 41.6 37.6 No ## 5 93.2 7.81 34.3 31.5 Yes ## 6 78.8 8.54 40.4 37.3 No
R 语言中的 dplyr 动词:快速参考
下表列出了本教程中使用的每个动词,包括语法和每次调用的返回值:
| 动词 | 目的 | Code | 说明 |
|---|---|---|---|
| 一瞥 | 检查 df 的结构 |
glimpse(df)
|
与 str() 函数用途相同,更易于阅读。 |
| 选择() | 选择/排除变量 |
select(df, A, B ,C)
|
选择变量 A、B 和 C |
select(df, A:C)
|
选择从 A 到 C 的所有变量 | ||
select(df, -C)
|
排除 C | ||
| 过滤() | 保持行符合一个或多个条件 |
filter(df, condition1)
|
一个条件 |
filter(df, condition1 & condition2)
|
两个条件与 AND 结合 | ||
| 安排() | 使用一个或多个变量对数据集进行排序 |
arrange(A)
|
变量 A 升序排序 |
arrange(A, B)
|
对变量 A 和 B 进行升序排序 | ||
arrange(desc(A), B)
|
对变量 A 进行降序排序,对变量 B 进行升序排序 | ||
| %>% | 在每个步骤之间创建管道 |
step 1 %>% step 2 %>% step 3 |

