原文地址:https://suzan.rbind.io/2018/02/dplyr-tutorial-3/
作者:Suzan Baert
这是系列dplyr系列教程中的第三篇博客文章。 在这篇文章中,我们将介绍如何挑选您的数据。 除了filter的基础知识外,它还介绍了一些更好的方法,用near()
和between()
挑选数字列,或用正则表达式过滤字符串列。
The data
根据之前的博客文章,为了方便人们复制粘贴代码和实验,我使用的是内置数据集。 此数据集内置于ggplot2中,因此如果您加载tidyverse,您将获得它。 否则,只需添加一次msleep < - ggplot2 :: msleep
参数即可获得数据集。
library(dplyr)
library(stringr)
msleep <- ggplot2::msleep
glimpse(msleep)
## Observations: 83
## Variables: 11
## $ name <chr> "Cheetah", "Owl monkey", "Mountain beaver", "Grea...
## $ genus <chr> "Acinonyx", "Aotus", "Aplodontia", "Blarina", "Bo...
## $ vore <chr> "carni", "omni", "herbi", "omni", "herbi", "herbi...
## $ order <chr> "Carnivora", "Primates", "Rodentia", "Soricomorph...
## $ conservation <chr> "lc", NA, "nt", "lc", "domesticated", NA, "vu", N...
## $ sleep_total <dbl> 12.1, 17.0, 14.4, 14.9, 4.0, 14.4, 8.7, 7.0, 10.1...
## $ sleep_rem <dbl> NA, 1.8, 2.4, 2.3, 0.7, 2.2, 1.4, NA, 2.9, NA, 0....
## $ sleep_cycle <dbl> NA, NA, NA, 0.1333333, 0.6666667, 0.7666667, 0.38...
## $ awake <dbl> 11.9, 7.0, 9.6, 9.1, 20.0, 9.6, 15.3, 17.0, 13.9,...
## $ brainwt <dbl> NA, 0.01550, NA, 0.00029, 0.42300, NA, NA, NA, 0....
## $ bodywt <dbl> 50.000, 0.480, 1.350, 0.019, 600.000, 3.850, 20.4...
Basic row filters
在许多情况下,您不希望在分析中包括所有行,而只包括选择的行。 仅使用特定行的函数在dplyr中称为“filter()”。 过滤器的一般语法是:filter(dataset,condition)
。 如果您在管道内部进行过滤,则只会在数据集通过管道输入函数时看到条件参数。
Filtering rows based on a numeric variable
You can filter numeric variables based on their values. The most used operators for this are >
, >=
, <
, <=
, ==
and !=
.
msleep %>%
select(name, sleep_total) %>%
filter(sleep_total > 18)
## # A tibble: 4 x 2
## name sleep_total
## <chr> <dbl>
## 1 Big brown bat 19.7
## 2 Thick-tailed opposum 19.4
## 3 Little brown bat 19.9
## 4 Giant armadillo 18.1
如果要选择一系列值,可以使用两个逻辑要求。 例如,为了选择总休眠时间在15到18小时之间的所有动物,我可以使用:filter(sleep_total> = 16,sleep_total <= 18)
,但使用between()稍微短一些
。
msleep %>%
select(name, sleep_total) %>%
filter(between(sleep_total, 16, 18))
## # A tibble: 4 x 2
## name sleep_total
## <chr> <dbl>
## 1 Owl monkey 17.0
## 2 Long-nosed armadillo 17.4
## 3 North American Opossum 18.0
## 4 Arctic ground squirrel 16.6
可以派上用场的另一个函数是near()
,它将选择几乎给定值的所有代码。 您必须指定容差“tol”以指示值可以达到多远。 你可以添加一个特定的数字:filter(near(sleep_total,17,tol = 0.5))
例如将返回sleep_total
在16.5和17.5之间的任何行,或者你可以添加一个公式。
示例代码将返回一个标准差为17的所有行。
msleep %>%
select(name, sleep_total) %>%
filter(near(sleep_total, 17, tol = sd(sleep_total)))
## # A tibble: 26 x 2
## name sleep_total
## <chr> <dbl>
## 1 Owl monkey 17.0
## 2 Mountain beaver 14.4
## 3 Greater short-tailed shrew 14.9
## 4 Three-toed sloth 14.4
## 5 Long-nosed armadillo 17.4
## 6 North American Opossum 18.0
## 7 Big brown bat 19.7
## 8 Western american chipmunk 14.9
## 9 Thick-tailed opposum 19.4
## 10 Mongolian gerbil 14.2
## # ... with 16 more rows
Filtering based on a exact character variable matches
例如,如果要选择特定的动物组,可以使用==
比较运算符:
msleep %>%
select(order, name, sleep_total) %>%
filter(order == "Didelphimorphia")
## # A tibble: 2 x 3
## order name sleep_total
## <chr> <chr> <dbl>
## 1 Didelphimorphia North American Opossum 18.0
## 2 Didelphimorphia Thick-tailed opposum 19.4
同样,您可以使用其他运算符:
*filter(order!=“Rodentia”)
将选择除Rodentia行之外的所有内容。
*filter(name>“v”)
只会在字母v之后选择字母中带有名称的行。
如果要选择多个动物,可以使用%in%
运算符。 以下代码将仅选择具有属于Didelphimorphia和Diprotodontia顺序的动物的行。
msleep %>%
select(order, name, sleep_total) %>%
filter(order %in% c("Didelphimorphia", "Diprotodontia"))
## # A tibble: 4 x 3
## order name sleep_total
## <chr> <chr> <dbl>
## 1 Didelphimorphia North American Opossum 18.0
## 2 Didelphimorphia Thick-tailed opposum 19.4
## 3 Diprotodontia Phalanger 13.7
## 4 Diprotodontia Potoroo 11.1
您可以使用%in%
运算符来取消选择某些组,在这种情况下,您必须通过在filter
的开头添加感叹号来否定。 制作!%in%
似乎是逻辑但它不起作用。
remove <- c("Rodentia", "Carnivora", "Primates")
msleep %>%
select(order, name, sleep_total) %>%
filter(!order %in% remove)
## # A tibble: 37 x 3
## order name sleep_total
## <chr> <chr> <dbl>
## 1 Soricomorpha Greater short-tailed shrew 14.9
## 2 Artiodactyla Cow 4.00
## 3 Pilosa Three-toed sloth 14.4
## 4 Artiodactyla Roe deer 3.00
## 5 Artiodactyla Goat 5.30
## 6 Soricomorpha Star-nosed mole 10.3
## 7 Soricomorpha Lesser short-tailed shrew 9.10
## 8 Cingulata Long-nosed armadillo 17.4
## 9 Hyracoidea Tree hyrax 5.30
## 10 Didelphimorphia North American Opossum 18.0
## # ... with 27 more rows
根据正则表达式过滤行
只有在您可以使用完整变量内容时,上述选项才有效。 在某些情况下,虽然需要根据部分匹配进行过滤。 在这种情况下,我们需要一个函数来评估字符串上的正则表达式并返回布尔值。 每当语句为“TRUE”时,该行将被过滤。
这有两个主要选项:base R的grepl()
函数,或stringr
包中的str_detect()
。
无论何时寻找部分匹配,重要的是要记住R是区分大小写的。 通过使用filter(str_detect(name,pattern =“mouse”))
我们将遗漏任何名为Mouse的行。 在这种情况下,它没有什么区别,但它是一个很好的习惯创建。
我在下面使用了'str_detect(),因为它更容易理解。 对于那些感兴趣的人,替代方案是:
filter(grepl(pattern =“mouse”,tolower(name)))`。
msleep %>%
select(name, sleep_total) %>%
filter(str_detect(tolower(name), pattern = "mouse"))
## # A tibble: 5 x 2
## name sleep_total
## <chr> <dbl>
## 1 Vesper mouse 7.00
## 2 House mouse 12.5
## 3 Northern grasshopper mouse 14.5
## 4 Deer mouse 11.5
## 5 African striped mouse 8.70
基于多种条件的过滤
以上示例基于单个条件返回行,但filter选项还允许AND和OR样式过滤器:
*filter(condition1,condition2)
将返回满足两个条件的行。
*filter(condition1,!condition2)
将返回条件1为真但条件2不为的所有行。
*filter(condition1 | condition2)
将返回满足条件1和/或条件2的行。
*filter(xor(condition1,condition2)
将返回只满足其中一个条件的所有行,而不是满足两个条件时。
可以组合多个AND,OR和NOT条件。 示例代码将返回bodywt大于100的所有行,并且sleep_total大于15或者不是Carnivora订单的一部分。
msleep %>%
select(name, order, sleep_total:bodywt) %>%
filter(bodywt > 100, (sleep_total > 15 | order != "Carnivora"))
## # A tibble: 10 x 8
## name order sleep_total sleep_rem sleep_cycle awake brainwt bodywt
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Cow Artio~ 4.00 0.700 0.667 20.0 0.423 600
## 2 Asian el~ Probo~ 3.90 NA NA 20.1 4.60 2547
## 3 Horse Peris~ 2.90 0.600 1.00 21.1 0.655 521
## 4 Donkey Peris~ 3.10 0.400 NA 20.9 0.419 187
## 5 Giraffe Artio~ 1.90 0.400 NA 22.1 NA 900
## 6 Pilot wh~ Cetac~ 2.70 0.100 NA 21.4 NA 800
## 7 African ~ Probo~ 3.30 NA NA 20.7 5.71 6654
## 8 Tiger Carni~ 15.8 NA NA 8.20 NA 163
## 9 Brazilia~ Peris~ 4.40 1.00 0.900 19.6 0.169 208
## 10 Bottle-n~ Cetac~ 5.20 NA NA 18.8 NA 173
Example with xor()
msleep %>%
select(name, bodywt:brainwt) %>%
filter(xor(bodywt > 100, brainwt > 1))
## # A tibble: 5 x 3
## name bodywt brainwt
## <chr> <dbl> <dbl>
## 1 Cow 600 0.423
## 2 Horse 521 0.655
## 3 Donkey 187 0.419
## 4 Human 62.0 1.32
## 5 Brazilian tapir 208 0.169
Example with !
:
The sample code will select all rows where brainwt
is larger than 1, but bodywt
does not exceed 100.
msleep %>%
select(name, sleep_total, brainwt, bodywt) %>%
filter(brainwt > 1, !bodywt > 100)
## # A tibble: 1 x 4
## name sleep_total brainwt bodywt
## <chr> <dbl> <dbl> <dbl>
## 1 Human 8.00 1.32 62.0
过滤掉空行
要过滤掉空行,你可以否定过滤器中的is.na()
函数:
示例代码将删除conservation
为NA
的所有行。
msleep %>%
select(name, conservation:sleep_cycle) %>%
filter(!is.na(conservation))
## # A tibble: 54 x 5
## name conservation sleep_total sleep_rem sleep_cycle
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 Cheetah lc 12.1 NA NA
## 2 Mountain beaver nt 14.4 2.40 NA
## 3 Greater short-tailed sh~ lc 14.9 2.30 0.133
## 4 Cow domesticated 4.00 0.700 0.667
## 5 Northern fur seal vu 8.70 1.40 0.383
## 6 Dog domesticated 10.1 2.90 0.333
## 7 Roe deer lc 3.00 NA NA
## 8 Goat lc 5.30 0.600 NA
## 9 Guinea pig domesticated 9.40 0.800 0.217
## 10 Grivet lc 10.0 0.700 NA
## # ... with 44 more rows
Filtering across multiple columns
dplyr
包有一些强大的变体可以一次过滤多个列:
*filter_all()
将根据您的进一步说明过滤所有列
*filter_if()
需要一个返回布尔值的函数来指示要过滤的列。如果是这样,那么将对这些列执行过滤器指令。
*filter_at()
要求你在vars()
参数中指定要进行过滤的列。
在这些情况下,有一般语法:首先指定哪些列,然后提及过滤器的条件。在许多情况下,您需要一个.
运算符,该运算符指的是我们正在查看的值。
过滤所有
不可否认,msleep
并不是展示这种能力的最佳数据库,但想象一下,你有一个包含几列的数据库,并且你想要选择在任一列中都有某个单词的所有行。以一个财务数据框为例,你想要选择带有'food'的所有行,是否在主类别栏,子类别栏,评论栏或你花费的地方提到了食物。
您可以在OR语句中包含4个不同条件的长过滤器语句。或者您只是过滤所有列的字符串“food”。
在下面的示例代码中,我在所有列中搜索字符串“Ca”。我想保留在任何变量中出现字符串“Ca”的行,所以我将条件包装在any_vars()
中。
下面的代码基本上要求保留任何变量中包含模式“Ca”的行。
msleep %>%
select(name:order, sleep_total, -vore) %>%
filter_all(any_vars(str_detect(., pattern = "Ca")))
## # A tibble: 16 x 4
## name genus order sleep_total
## <chr> <chr> <chr> <dbl>
## 1 Cheetah Acinonyx Carnivora 12.1
## 2 Northern fur seal Callorhinus Carnivora 8.70
## 3 Vesper mouse Calomys Rodentia 7.00
## 4 Dog Canis Carnivora 10.1
## 5 Roe deer Capreolus Artiodactyla 3.00
## 6 Goat Capri Artiodactyla 5.30
## 7 Guinea pig Cavis Rodentia 9.40
## 8 Domestic cat Felis Carnivora 12.5
## 9 Gray seal Haliochoerus Carnivora 6.20
## 10 Tiger Panthera Carnivora 15.8
## 11 Jaguar Panthera Carnivora 10.4
## 12 Lion Panthera Carnivora 13.5
## 13 Caspian seal Phoca Carnivora 3.50
## 14 Genet Genetta Carnivora 6.30
## 15 Arctic fox Vulpes Carnivora 12.5
## 16 Red fox Vulpes Carnivora 9.80
对于数值值也可以这样做:此代码将保留任何值低于0.1的行:
msleep %>%
select(name, sleep_total:bodywt) %>%
filter_all(any_vars(. < 0.1))
## # A tibble: 47 x 7
## name sleep_total sleep_rem sleep_cycle awake brainwt bodywt
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Owl monkey 17.0 1.80 NA 7.00 1.55e-2 4.80e-1
## 2 Greater short~ 14.9 2.30 0.133 9.10 2.90e-4 1.90e-2
## 3 Vesper mouse 7.00 NA NA 17.0 NA 4.50e-2
## 4 Dog 10.1 2.90 0.333 13.9 7.00e-2 1.40e+1
## 5 Roe deer 3.00 NA NA 21.0 9.82e-2 1.48e+1
## 6 Guinea pig 9.40 0.800 0.217 14.6 5.50e-3 7.28e-1
## 7 Chinchilla 12.5 1.50 0.117 11.5 6.40e-3 4.20e-1
## 8 Star-nosed mo~ 10.3 2.20 NA 13.7 1.00e-3 6.00e-2
## 9 African giant~ 8.30 2.00 NA 15.7 6.60e-3 1.00e+0
## 10 Lesser short-~ 9.10 1.40 0.150 14.9 1.40e-4 5.00e-3
## # ... with 37 more rows
any_vars()
语句等价于OR,所以当然还有AND语句的等价句:all_vars()
。 以下代码将保留所有值均高于1的所有行。
msleep %>%
select(name, sleep_total:bodywt, -awake) %>%
filter_all(all_vars(. > 1))
## # A tibble: 1 x 6
## name sleep_total sleep_rem sleep_cycle brainwt bodywt
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Human 8.00 1.90 1.50 1.32 62.0
Filter if
filter_all()
函数有时会有点疯狂。 msleep
数据集有一组睡眠和体重测量,其中一些数据丢失 - 我无法在那里添加数据。 但是前几组专栏只包含动物信息。 Vesper Mouse的遗体缺失,但这是我仍然可以挖掘并添加到数据框的信息,如果我想要的话。
所以想象一下,我想找出前几列中我们NA的所有数据行。 filter_all(any_vars(is.na(。)))
将是非常无用的,因为它将返回27行,其中许多是测量部分中缺少的数据。
在这种情况下:filter_if()
派上用场。 描述列都是字符列,而测量数据是数字。 所以使用filter_if()
我可以指定我只想过滤字符变量。 在这种情况下,我只得到7行。
msleep %>%
select(name:order, sleep_total:sleep_rem) %>%
filter_if(is.character, any_vars(is.na(.)))
## # A tibble: 7 x 6
## name genus vore order sleep_total sleep_rem
## <chr> <chr> <chr> <chr> <dbl> <dbl>
## 1 Vesper mouse Calomys <NA> Rodentia 7.00 NA
## 2 Desert hedgehog Paraechinus <NA> Erinaceomorpha 10.3 2.70
## 3 Deer mouse Peromyscus <NA> Rodentia 11.5 NA
## 4 Phalanger Phalanger <NA> Diprotodontia 13.7 1.80
## 5 Rock hyrax Procavia <NA> Hyracoidea 5.40 0.500
## 6 Mole rat Spalax <NA> Rodentia 10.6 2.40
## 7 Musk shrew Suncus <NA> Soricomorpha 12.8 2.00
Similarly, you can add is.numeric
, is.integer
, is.double
, is.logical
, is.factor
. If you have data columns, you can load the lubridate package, and use is.POSIXt
or is.Date
.
Filter at
其中一个更强大的函数是filter_at()
:它不会过滤所有列,也不需要你指定列的类型,你可以通过`vars()选择要发生更改的列。 论据。 这个参数允许在select语句中完成任何事情:所以你可以通过名称来引用它们,也可以通过逻辑数字函数,正则表达式等来引用它们(请参阅我的第一篇博客文章中的选择选项)。
第二个参数是选择的条件。 与上面的示例类似,如果所有列都需要返回TRUE(AND等效),则可以使用all_vars()
;如果只需要一个变量返回TRUE(OR等效),则可以使用any_vars()
。
示例:按名称引用列:
msleep %>%
select(name, sleep_total:sleep_rem, brainwt:bodywt) %>%
filter_at(vars(sleep_total, sleep_rem), all_vars(.>5))
## # A tibble: 2 x 5
## name sleep_total sleep_rem brainwt bodywt
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Thick-tailed opposum 19.4 6.60 NA 0.370
## 2 Giant armadillo 18.1 6.10 0.0810 60.0
Example: using another select option:
msleep %>%
select(name, sleep_total:sleep_rem, brainwt:bodywt) %>%
filter_at(vars(contains("sleep")), all_vars(.>5))
## # A tibble: 2 x 5
## name sleep_total sleep_rem brainwt bodywt
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Thick-tailed opposum 19.4 6.60 NA 0.370
## 2 Giant armadillo 18.1 6.10 0.0810 60.0