原文地址: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