4.3 基于dplyr包的数据描述性统计

我们将在本节学习6个dplyr核心函数,它们可以解决在数据处理中遇到的大部分问题。接下来我们将结合global-superstore数据集对这6个函数进行详细介绍。

4.3.1 使用filter()函数筛选行

filter() 函数可以基于观测的值筛选出一个观测子集,例如我们筛选出type(订单类型)为办公用品并且subtype(细分类型)为装订机的行。
filter(orders,type == '办公用品'&subtype == '装订机')
## # A tibble: 6,152 x 24
##       id orderid purchasedate        shipdate            shipway custid custname
##    <dbl> <chr>   <dttm>              <dttm>              <chr>   <chr>  <chr>   
##  1     4 MX-201~ 2012-10-15 00:00:00 2012-10-20 00:00:00 标准级  KW-16~ 郝立勤  
##  2    11 MX-201~ 2013-09-27 00:00:00 2013-10-01 00:00:00 标准级  DP-13~ 邹凤    
##  3    24 US-201~ 2014-10-03 00:00:00 2014-10-08 00:00:00 标准级  DW-13~ 万刚    
##  4    28 US-201~ 2013-05-24 00:00:00 2013-05-31 00:00:00 标准级  SC-20~ 张升    
##  5    64 MX-201~ 2014-03-14 00:00:00 2014-03-17 00:00:00 一级    BT-11~ 宋忠    
##  6    65 MX-201~ 2014-03-14 00:00:00 2014-03-17 00:00:00 一级    BT-11~ 宋忠    
##  7    75 MX-201~ 2012-02-17 00:00:00 2012-02-22 00:00:00 标准级  FM-14~ 葛欢    
##  8    91 MX-201~ 2012-12-28 00:00:00 2013-01-01 00:00:00 标准级  SC-20~ 楚宣    
##  9   134 US-201~ 2014-09-29 00:00:00 2014-10-04 00:00:00 标准级  TT-21~ 庄伟    
## 10   137 MX-201~ 2014-10-29 00:00:00 2014-11-03 00:00:00 标准级  FW-14~ 何惠    
## # ... with 6,142 more rows, and 17 more variables: segment <chr>, city <chr>,
## #   state <chr>, country <chr>, zipcode <lgl>, market <chr>, area <chr>,
## #   productid <chr>, type <chr>, subtype <chr>, productname <chr>, sales <dbl>,
## #   quantity <dbl>, discount <dbl>, profit <dbl>, shipcost <dbl>,
## #   priority <chr>
filter()函数中,第一个参数是数据框名称,第二个参数以及随后的参数是用来筛选数据框的表达式。这行代码会返回一个新的数据框,如果你想保存结果,需要对这行代码赋值。R要么输出结果,要么将结果保存在一个变量中。如果想同时完成这两种操作,那么你可以用括号将赋值语句括起来:

这行代码还使用了比较运算符和逻辑运算符。R提供了标准的比较运算符和逻辑运算符,如果有遗忘的读者,可以返回第三章进行查阅。

4.3.2 使用arrange()函数对观测值进行排序

arrange()函数的工作方式与filter()函数非常相似,但前者不是选择行,而是改变行的顺序。例如,我们按照sales(销售量)进行排序。为了数据更加的直观,我们首先将进行排序的部分列筛选出来:
orders4 <- orders %>% 
    select(type:profit) %>% 
    arrange(sales)
orders4 
## # A tibble: 51,290 x 7
##    type     subtype productname                   sales quantity discount profit
##    <chr>    <chr>   <chr>                         <dbl>    <dbl>    <dbl>  <dbl>
##  1 办公用品 电器    Hoover Replacement Belt for ~ 0.444        1      0.8 -1.11 
##  2 办公用品 装订机  Acco Suede Grain Vinyl Round~ 0.556        1      0.8 -0.945
##  3 办公用品 装订机  Avery Durable Slant Ring Bin~ 0.836        1      0.8 -1.34 
##  4 办公用品 装订机  Avery Round Ring Poly Binders 0.852        1      0.7 -0.596
##  5 办公用品 装订机  Acco 3-Hole Punch             0.876        1      0.8 -1.40 
##  6 办公用品 装订机  Avery Non-Stick Binders       0.898        1      0.8 -1.57 
##  7 办公用品 装订机  Avery Triangle Shaped Sheet ~ 0.984        2      0.8 -1.48 
##  8 技术     配件    Maxell 4.7GB DVD-R 5/Pack     0.99         1      0    0.436
##  9 办公用品 装订机  Acco Economy Flexible Poly R~ 1.04         1      0.8 -1.83 
## 10 办公用品 装订机  Wilson Jones Easy Flow II Sh~ 1.08         3      0.8 -1.73 
## # ... with 51,280 more rows
arrange()接受一个数据框和一组作为排序依据的列名(或者更复杂的表达式)作为参数。如果列名不只一个,那么就使用后面的列在前面排序的基础上继续排序。另外,arrange()默认进行升序排列,使用desc()可以进行降序排列:
orders4 <- orders %>% 
    select(type:profit) %>% 
    arrange(desc(profit))
orders4 
## # A tibble: 51,290 x 7
##    type     subtype productname                   sales quantity discount profit
##    <chr>    <chr>   <chr>                         <dbl>    <dbl>    <dbl>  <dbl>
##  1 技术     复印机  Canon imageCLASS 2200 Advan~ 17500.        5      0    8400.
##  2 技术     复印机  Canon imageCLASS 2200 Advan~ 14000.        4      0    6720.
##  3 技术     复印机  Canon imageCLASS 2200 Advan~ 10500.        3      0    5040.
##  4 办公用品 装订机  GBC Ibimaster 500 Manual Pr~  9893.       13      0    4946.
##  5 办公用品 装订机  Ibico EPK-21 Electric Bindi~  9450.        5      0    4630.
##  6 办公用品 电器    Hoover Stove, Red             7959.       14      0    3979.
##  7 技术     复印机  Canon imageCLASS 2200 Advan~ 11200.        4      0.2  3920.
##  8 办公用品 装订机  Fellowes PB500 Electric Pun~  6355.        5      0    3177.
##  9 技术     电话    Samsung Smart Phone, VoIP     6999.       11      0    2939.
## 10 技术     电话    Apple Smart Phone, with Cal~  5752.        9      0    2818.
## # ... with 51,280 more rows

4.3.3 使用select()函数选择需要的列

在大数据时代,数据集有几百甚至几千个变量已经司空见惯。这种情况下,找出真正有用的变量经常是我们面临的第一个挑战。通过基于变量名的操作,select()函数快速生成你需要的变量子集。本数据集只有24个字段,使用select()的效果不是非常明显,但是可以通过本数据集了解select()的用法:
orders4 <- orders %>% 
    filter(type == "办公用品" , subtype=="装订机") %>% 
    select(type,subtype) 
orders4 
## # A tibble: 6,152 x 2
##    type     subtype
##    <chr>    <chr>  
##  1 办公用品 装订机 
##  2 办公用品 装订机 
##  3 办公用品 装订机 
##  4 办公用品 装订机 
##  5 办公用品 装订机 
##  6 办公用品 装订机 
##  7 办公用品 装订机 
##  8 办公用品 装订机 
##  9 办公用品 装订机 
## 10 办公用品 装订机 
## # ... with 6,142 more rows

select()函数上文中已经多次提及,相信读者对它的用法已经有了基本了解:它接受两个参数,第一个为数据框,第二个则为要筛选的变量,可以一次筛选多个变量,变量之间用逗号分隔,也可以使用type:profit这种形式,筛选type到profit之间的所有变量。或者可以使用-(type:profit)筛选除type到profit的所有变量:

select(orders,-(type:profit))
## # A tibble: 51,290 x 17
##       id orderid purchasedate        shipdate            shipway custid custname
##    <dbl> <chr>   <dttm>              <dttm>              <chr>   <chr>  <chr>   
##  1     1 MX-201~ 2014-10-02 00:00:00 2014-10-06 00:00:00 标准级  SC-20~ 常松    
##  2     2 MX-201~ 2012-10-15 00:00:00 2012-10-20 00:00:00 标准级  KW-16~ 郝立勤  
##  3     3 MX-201~ 2012-10-15 00:00:00 2012-10-20 00:00:00 标准级  KW-16~ 郝立勤  
##  4     4 MX-201~ 2012-10-15 00:00:00 2012-10-20 00:00:00 标准级  KW-16~ 郝立勤  
##  5     5 MX-201~ 2012-10-15 00:00:00 2012-10-20 00:00:00 标准级  KW-16~ 郝立勤  
##  6     6 MX-201~ 2012-10-15 00:00:00 2012-10-20 00:00:00 标准级  KW-16~ 郝立勤  
##  7     7 MX-201~ 2013-09-27 00:00:00 2013-10-01 00:00:00 标准级  DP-13~ 邹凤    
##  8     8 MX-201~ 2013-09-27 00:00:00 2013-10-01 00:00:00 标准级  DP-13~ 邹凤    
##  9     9 MX-201~ 2013-09-27 00:00:00 2013-10-01 00:00:00 标准级  DP-13~ 邹凤    
## 10    10 MX-201~ 2013-09-27 00:00:00 2013-10-01 00:00:00 标准级  DP-13~ 邹凤    
## # ... with 51,280 more rows, and 10 more variables: segment <chr>, city <chr>,
## #   state <chr>, country <chr>, zipcode <lgl>, market <chr>, area <chr>,
## #   productid <chr>, shipcost <dbl>, priority <chr>
同时,select()还可以配合一些辅助函数来使用。例如:和start_with(‘abc’)(end_with)配合,匹配以abc开头或者结尾的变量;和contains()配合筛选变量名包含某些字段的变量;使用matches()进行正则匹配;或者和everything()配合将变量移动到数据框的开头:
select(orders,type:profit,everything())
## # A tibble: 51,290 x 24
##    type     subtype productname     sales quantity discount profit    id orderid
##    <chr>    <chr>   <chr>           <dbl>    <dbl>    <dbl>  <dbl> <dbl> <chr>  
##  1 办公用品 标签    Hon File Folde~  13.1        3        0   4.56     1 MX-201~
##  2 家具     用具    Tenex Clock, D~ 252.         8        0  90.7      2 MX-201~
##  3 家具     书架    Ikea 3-Shelf C~ 193.         2        0  54.1      3 MX-201~
##  4 办公用品 装订机  Cardinal Binde~  35.4        4        0   4.96     4 MX-201~
##  5 办公用品 美术    Sanford Canvas~  71.6        2        0  11.4      5 MX-201~
##  6 办公用品 信封    GlobeWeis Mail~  56.1        2        0  21.3      6 MX-201~
##  7 办公用品 信封    GlobeWeis Mail~  56.1        2        0  21.3      7 MX-201~
##  8 技术     设备    Konica Card Pr~ 345.         3        0 165.       8 MX-201~
##  9 办公用品 用品    Elite Box Cutt~  97.4        4        0  19.4      9 MX-201~
## 10 技术     配件    Enermax Router~ 342.         2        0  13.6     10 MX-201~
## # ... with 51,280 more rows, and 15 more variables: purchasedate <dttm>,
## #   shipdate <dttm>, shipway <chr>, custid <chr>, custname <chr>,
## #   segment <chr>, city <chr>, state <chr>, country <chr>, zipcode <lgl>,
## #   market <chr>, area <chr>, productid <chr>, shipcost <dbl>, priority <chr>

4.3.4 使用mutate()新增变量

在数据分析中,分析两变量或者多变量之间的函数关系是我们经常要进行的操作。mutate()函数可以对现有列进行函数操作,并将结果保存为新的变量。例如,我们需要想要获得单位商品的价格,就需要sales列除以quanlity(商品数量)列:

orders5 <- orders %>% 
    mutate(unitprice=sales/quantity ) %>% 
    select(sales,quantity, unitprice)
mutate()函数默认将新增列添加到数据框末尾,所以我们仍然对数据进行了列筛选。mutate()的接受两个参数:数据框和新增变量,新增变量可以为多个。而且新增变量在创建之后就可以使用,例如我们在获取价格之后想要获取成本:
orders5 <- orders %>% 
    mutate(unitprice=sales/quantity,
    unitcost = unitprice-(profit/quantity)) %>% 
    select(sales,quantity, unitprice,unitcost)
orders5
## # A tibble: 51,290 x 4
##    sales quantity unitprice unitcost
##    <dbl>    <dbl>     <dbl>    <dbl>
##  1  13.1        3      4.36     2.84
##  2 252.         8     31.5     20.2 
##  3 193.         2     96.6     69.6 
##  4  35.4        4      8.86     7.62
##  5  71.6        2     35.8     30.1 
##  6  56.1        2     28.1     17.4 
##  7  56.1        2     28.1     17.4 
##  8 345.         3    115.      59.7 
##  9  97.4        4     24.3     19.5 
## 10 342.         2    171.     164.  
## # ... with 51,280 more rows
我们在上述代码块中选择了进行操作的变量和新增变量,如果我们只需要保存新增变量,可以使用transmute()函数:
transmute(orders,unitprice=sales/quantity,
            unitcost = unitprice-(profit/quantity))
## # A tibble: 51,290 x 2
##    unitprice unitcost
##        <dbl>    <dbl>
##  1      4.36     2.84
##  2     31.5     20.2 
##  3     96.6     69.6 
##  4      8.86     7.62
##  5     35.8     30.1 
##  6     28.1     17.4 
##  7     28.1     17.4 
##  8    115.      59.7 
##  9     24.3     19.5 
## 10    171.     164.  
## # ... with 51,280 more rows

4.3.5 使用group_by()对数据进行分组

R语言的group_by()函数按照某个变量分组,数据集本身并不会发生什么变化,只有在与dplyr包中的其它函数结合使用时才会体现出它的作用。例如,我们将数据中的订单按区域进行分组并且使用tally()函数统计订单数量:

orders5 <- orders %>% 
    group_by(area) %>% 
    tally()

group_by()的基本用法很简单:第一个参数为数据框,第二个参数为进行分组的变量。通过上面几行代码,我们就可以得到不同区域的订单数量。不过,通过与其它函数的配合,才能真正体现group_by()的强大。

4.3.6 使用summarize()汇总数据

summarize()函数可以将数据框折叠成一行。
summarise(orders,avg_sales=mean(sales))
## # A tibble: 1 x 1
##   avg_sales
##       <dbl>
## 1      246.
summarize()函数通常与group_by()函数一起使用。group_by()函数可以将整个数据集划分为不同的组,接下来,在分组后的数据框上使用dplyr函数时,它们会自动的每个组进行操作。summarize()返回值一般为新的一个数据框,且该数据框一般情况下和原始的数据框长度一定不相同,列数应该是group_by参数+summarize参数,例如:
orders5 <- orders %>% 
    group_by(type) %>% 
    summarise(avg_sales=mean(sales)) %>% 
    head()
orders5
## # A tibble: 3 x 2
##   type     avg_sales
##   <chr>        <dbl>
## 1 办公用品      121.
## 2 技术          468.
## 3 家具          416.