ITPub博客

首页 > > > R语言ETL系列:过滤(filter)

R语言ETL系列:过滤(filter)

作者:浪花小雨滴 时间:2018-12-28 16:56:14 0 删除 编辑

作者:黄天元,复旦大学博士在读,热爱数据科学与R,热衷推广R在业界的应用。邮箱:huang.tian-yuan@qq.com.欢迎合作交流

本章节介绍如何根据条件对表格进行过滤,主要使用filter函数进行实现。
首先加载需要的包和数据,我们会用到R语言自带的mtcars数据集。首先我们把行的名称转化为一列数据,名为rownams。然后,把数据库转化为tibble格式,存在mtcars1变量中。

library(tidyverse)

mtcars %>%
rownames_to_column() %>%
as_tibble() -> mtcars1

mtcars1

## # A tibble: 32 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4
## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4
## 3 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4
## 4 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3
## 5 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3
## 6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3
## 7 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3
## 8 Merc 2~ 24.4 4 147. 62 3.69 3.19 20 1 0 4
## 9 Merc 2~ 22.8 4 141. 95 3.92 3.15 22.9 1 0 4
## 10 Merc 2~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4
## # ... with 22 more rows, and 1 more variable: carb <dbl>

条件过滤:filter

实际工作中,经常会需要用到把一定条件的记录调出来的情况。比如,如果我是超市的数据分析师,我需要查看单次消费超过500元的购物清单,就需要用到条件过滤。 在我们的例子中,比如我们需要提取cyl为4的记录(cyl代表汽车气缸的数量),就可以这么操作:

mtcars1 %>%
filter(cyl == 4)

## # A tibble: 11 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4
## 2 Merc 2~ 24.4 4 147. 62 3.69 3.19 20 1 0 4
## 3 Merc 2~ 22.8 4 141. 95 3.92 3.15 22.9 1 0 4
## 4 Fiat 1~ 32.4 4 78.7 66 4.08 2.2 19.5 1 1 4
## 5 Honda ~ 30.4 4 75.7 52 4.93 1.62 18.5 1 1 4
## 6 Toyota~ 33.9 4 71.1 65 4.22 1.84 19.9 1 1 4
## 7 Toyota~ 21.5 4 120. 97 3.7 2.46 20.0 1 0 3
## 8 Fiat X~ 27.3 4 79 66 4.08 1.94 18.9 1 1 4
## 9 Porsch~ 26 4 120. 91 4.43 2.14 16.7 0 1 5
## 10 Lotus ~ 30.4 4 95.1 113 3.77 1.51 16.9 1 1 5
## 11 Volvo ~ 21.4 4 121 109 4.11 2.78 18.6 1 1 4
## # ... with 1 more variable: carb <dbl>

结果中我们可以看到,气缸数量为4的记录都被我们调出来了。 相关SQL代码如下:

<SQL> SELECT *
FROM `mtcars1`
WHERE (`cyl` = 4.0)

如何定义条件?

什么是条件?很简单,是或不是。比如上面的例子,如果cyl等于4,就符合条件,否则不符合条件。因此只要我们的语句能够返回一个逻辑值(也就是计算机能够读懂的TURE或者FALSE),那么就能够构成一个条件。基本的条件操作符如下所示:

操作符

说明

操作符

说明

==

等于

<

小于

!=

不等于

<=

小于等于

>

大于

is.na()

是否为缺失值

>=

大于等于



下面我们再举一个实际例子,比如我们需要除了4个气缸以外的数据,可以这么写:

mtcars1 %>%
filter(cyl != 4)

## # A tibble: 21 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4
## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4
## 3 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3
## 4 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3
## 5 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3
## 6 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3
## 7 Merc 2~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4
## 8 Merc 2~ 17.8 6 168. 123 3.92 3.44 18.9 1 0 4
## 9 Merc 4~ 16.4 8 276. 180 3.07 4.07 17.4 0 0 3
## 10 Merc 4~ 17.3 8 276. 180 3.07 3.73 17.6 0 0 3
## # ... with 11 more rows, and 1 more variable: carb <dbl>

SQL代码如下:

<SQL> SELECT *
FROM `mtcars1`
WHERE (`cyl` != 4.0)

过滤缺失值

现实生产或商务活动中,总会有一些数据采集不到,这时候就会出现缺失值。作分析的时候,如果有缺失值,就无法进行正确计算,比如计算均值的时候,就不容许数据中包含缺失值。如何去除掉缺失值呢?这里我们可以使用drop_na函数。
下面我们先构造一个3*2的数据框,并在里面设置缺失值。例子如下:

df <- tibble(x = c(1, 2, NA), y = c("a", NA, "b"))
df #原始数据框

## # A tibble: 3 x 2
## x y
## <dbl> <chr>
## 1 1 a
## 2 2 <NA>
## 3 NA b

df %>% drop_na() #去掉含有缺失值的行

## # A tibble: 1 x 2
## x y
## <dbl> <chr>
## 1 1 a

df %>% drop_na(x) #去掉x列含有缺失值的行

## # A tibble: 2 x 2
## x y
## <dbl> <chr>
## 1 1 a
## 2 2 <NA>

我们可以看到,使用drop_na函数,我们可以轻松地去掉包含缺失值的行,而且还可以指定去除某列中含有缺失值的行。那么,我们怎么找到这些具有缺失值的行呢?非常简单,利用is.na函数即可,例子如下:

df %>%
filter(is.na(x))

## # A tibble: 1 x 2
## x y
## <dbl> <chr>
## 1 NA b

SQL代码如下:

<SQL> SELECT *
FROM `df`
WHERE (((`x`) IS NULL))

组合过滤

如果只有一个条件,也许非常简单。但是条件很多的时候,我们就需要使用逻辑操作符来把条件组合起来,一起进行过滤。经典的逻辑操作符包括&(与)、|(或)、!(非),有的编程语言会用英语AND/OR/NOT来表示这些逻辑关系,但是在逻辑层面上表达是一致的。下面通过一个例子来说明这些逻辑关系:

  • &:如果顾客最近一周买了东西且(&)买的东西超过100元,那么我们把这些顾客的交易记录调出来;
  • |:如果顾客最近一周买了东西或者(|)购买东西的频率维持在一周一次,那么我们把这些顾客的交易记录调出来;
  • !:我们只考虑女性客户,因此男性客户都剔除(!)掉。

上面提到的是做RFM模型的一些业务逻辑,现在我们依据mtcars的数据集来给大家举例。

&操作符

我们想要筛选气缸(cyl)为4,而且马力(hp)大于100的汽车。

mtcars1 %>%
filter(cyl == 4 & hp > 100)

## # A tibble: 2 x 12
## rowna~ mpg cyl disp hp drat wt qsec vs am gear carb
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Lotus~ 30.4 4 95.1 113 3.77 1.51 16.9 1 1 5 2
## 2 Volvo~ 21.4 4 121 109 4.11 2.78 18.6 1 1 4 2

#等价于
mtcars1 %>%
filter(cyl == 4,hp > 100)

## # A tibble: 2 x 12
## rowna~ mpg cyl disp hp drat wt qsec vs am gear carb
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Lotus~ 30.4 4 95.1 113 3.77 1.51 16.9 1 1 5 2
## 2 Volvo~ 21.4 4 121 109 4.11 2.78 18.6 1 1 4 2

SQL代码如下:

<SQL> SELECT *
FROM `mtcars1`
WHERE ((`cyl` = 4.0) AND (`hp` > 100.0))

|操作符

我们想要筛选气缸(cyl)为4,或者马力(hp)大于100的汽车。

mtcars1 %>%
filter(cyl == 4 | hp > 100)

## # A tibble: 32 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4
## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4
## 3 Datsun~ 22.8 4 108 93 3.85 2.32 18.6 1 1 4
## 4 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3
## 5 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3
## 6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3
## 7 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3
## 8 Merc 2~ 24.4 4 147. 62 3.69 3.19 20 1 0 4
## 9 Merc 2~ 22.8 4 141. 95 3.92 3.15 22.9 1 0 4
## 10 Merc 2~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4
## # ... with 22 more rows, and 1 more variable: carb <dbl>

SQL代码如下:

<SQL> SELECT *
FROM `mtcars1`
WHERE (`cyl` = 4.0 OR `hp` > 100.0)

!操作符

我们想要筛选除了4个气缸以外的汽车记录。

mtcars1 %>%
filter(!cyl == 4)

## # A tibble: 21 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4
## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4
## 3 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3
## 4 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3
## 5 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3
## 6 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3
## 7 Merc 2~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4
## 8 Merc 2~ 17.8 6 168. 123 3.92 3.44 18.9 1 0 4
## 9 Merc 4~ 16.4 8 276. 180 3.07 4.07 17.4 0 0 3
## 10 Merc 4~ 17.3 8 276. 180 3.07 3.73 17.6 0 0 3
## # ... with 11 more rows, and 1 more variable: carb <dbl>

#等价于
mtcars1 %>%
filter(cyl != 4)

## # A tibble: 21 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4
## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4
## 3 Hornet~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3
## 4 Hornet~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3
## 5 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3
## 6 Duster~ 14.3 8 360 245 3.21 3.57 15.8 0 0 3
## 7 Merc 2~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4
## 8 Merc 2~ 17.8 6 168. 123 3.92 3.44 18.9 1 0 4
## 9 Merc 4~ 16.4 8 276. 180 3.07 4.07 17.4 0 0 3
## 10 Merc 4~ 17.3 8 276. 180 3.07 3.73 17.6 0 0 3
## # ... with 11 more rows, and 1 more variable: carb <dbl>

SQL代码如下:

<SQL> SELECT *
FROM `mtcars1`
WHERE (NOT(`cyl` = 4.0))

文本过滤

数据表中的数据不都是数值型的,有的是字符串格式存在的文本。在我们的例子中,比如我们想了解Merc这个型号的车,那么我们就要从rowname列中个提取包含“Merc”的行。
R语言tidyverse包中,包含了stringr包,可以对字符串进行识别、替换、提取等高级操作。如果我们要根据字符串进行过滤,就需要用到str_detect函数,例子如下:

#提取rowname中包含“Merc”的记录

mtcars1 %>%
filter(str_detect(rowname,pattern = "Merc"))

## # A tibble: 7 x 12
## rowna~ mpg cyl disp hp drat wt qsec vs am gear carb
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Merc ~ 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
## 2 Merc ~ 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
## 3 Merc ~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
## 4 Merc ~ 17.8 6 168. 123 3.92 3.44 18.9 1 0 4 4
## 5 Merc ~ 16.4 8 276. 180 3.07 4.07 17.4 0 0 3 3
## 6 Merc ~ 17.3 8 276. 180 3.07 3.73 17.6 0 0 3 3
## 7 Merc ~ 15.2 8 276. 180 3.07 3.78 18 0 0 3 3

SQL代码为:

<SQL> SELECT *
FROM `mtcars1`
WHERE (INSTR('^Merc', `rowname`) > 0)

我们看到pattern参数中,我们赋予了“Merc”模式。事实上,pattern可以接受正则表达式的内容,比如我们要搜索以M开头的车型,那么就可以把pattern改为“^M”:

mtcars1 %>%
filter(str_detect(rowname,pattern = "^M"))

## # A tibble: 10 x 12
## rowname mpg cyl disp hp drat wt qsec vs am gear
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mazda ~ 21 6 160 110 3.9 2.62 16.5 0 1 4
## 2 Mazda ~ 21 6 160 110 3.9 2.88 17.0 0 1 4
## 3 Merc 2~ 24.4 4 147. 62 3.69 3.19 20 1 0 4
## 4 Merc 2~ 22.8 4 141. 95 3.92 3.15 22.9 1 0 4
## 5 Merc 2~ 19.2 6 168. 123 3.92 3.44 18.3 1 0 4
## 6 Merc 2~ 17.8 6 168. 123 3.92 3.44 18.9 1 0 4
## 7 Merc 4~ 16.4 8 276. 180 3.07 4.07 17.4 0 0 3
## 8 Merc 4~ 17.3 8 276. 180 3.07 3.73 17.6 0 0 3
## 9 Merc 4~ 15.2 8 276. 180 3.07 3.78 18 0 0 3
## 10 Masera~ 15 8 301 335 3.54 3.57 14.6 0 1 5
## # ... with 1 more variable: carb <dbl>

SQL代码为:

<SQL> SELECT *
FROM `mtcars1`
WHERE (INSTR('^M', `rowname`) > 0)

正则表达式是一个很有用的工具,如果能够写出高效的正则表达式,就能够对字符串进行更加高级的筛选。不过正则表达式超出了本系列的范围,因此不进行更多的介绍。

小结

本章介绍了如何用filter函数完成过滤,我们了解了如何通过构造条件来对数据表的记录进行筛选。此外,我们能够去掉表格中含有缺失值的数据,还能把这些缺失的记录单独提取出来。最后,我们学会了如何通过构造组合过滤来进行复杂的表格数据筛选,并知道如何利用str_detect函数对文本格式的数据进行筛选。

原文作者:;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2018-05-16

  • 博文量
    4259
  • 访问量
    39892