美文网首页R语言
【R语言】R包dplyr(一):数据转换

【R语言】R包dplyr(一):数据转换

作者: 巩翔宇Ibrahimovic | 来源:发表于2020-10-06 22:43 被阅读0次

    日常在工作中会碰到很多数据批量处理的问题,有的时候单独造轮子很费时间,这个时候我发现了dplyr这个R包,能帮助你解决数据处理中的绝大多数难题。dplyr是tidyverse中的一个核心包,用来进行数据操作。主要包括以下5个核心函数。

    filter() 按值筛选观测

    arrange() 对行进行重新排序

    select() 按名称选取变量

    mutate() 使用现有变量的函数创建新变量

    summarize()将多个值总结为一个摘要统计量

    这些函数都可以和group_by()函数联合起来使用,group_by()可以改变以上每个函数的作用范围,让其在整个数据集上的操作变为在每个分组上分别操作,这五个函数的工作方式都是相同的:

    1.第一个参数是一个数据框。

    2.随后的采纳数使用变量名称(不带引号)描述了在数据框上进行的操作。

    3.输出结果是一个新的数据框。

    Installation

    # The easiest way to get dplyr is to install the whole tidyverse:
    install.packages("tidyverse")
    
    # Alternatively, install just dplyr:
    install.packages("dplyr")
    

    Demo

    下面将以一个航班信息的数据集来演示一下dplyr这个包的用法。

    #安装并加载这个数据集
    install.packages('nycflights13')
    library(nycflights13)
    

    1.1 使用filter()筛选行

    filter()函数可以基于观测的值筛选出一个观测子集。第一个参数是数据框名称,第二个参数及随后的参数是用来筛选数据框的表达式。

    #筛选出1月1日出发的航班
    > a <- filter(flights,month==1,day==1)
    > head(a)
    # A tibble: 6 x 19
       year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
      <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
    1  2013     1     1      517            515         2      830            819        11 UA     
    2  2013     1     1      533            529         4      850            830        20 UA     
    3  2013     1     1      542            540         2      923            850        33 AA     
    4  2013     1     1      544            545        -1     1004           1022       -18 B6     
    5  2013     1     1      554            600        -6      812            837       -25 DL     
    6  2013     1     1      554            558        -4      740            728        12 UA     
    # ... with 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
    #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
    

    1.1.1 比较运算符

    R提供了一套标准的比较运算符:>,>=,<,<=,!=(不等于),==(等于)。

    1.1.2 逻辑运算符

    filter()中的多个参数是由“与”组合起来的:每个表达式都必须为真才能让一行观测包含在输出中。如果要实现其他类型的组合,你需要使用布尔运算符: &表示"与"(也就是交集), | 表示“或”, ! 表示"非"。

    #找出11月或12月出发的航班
    > b <- filter(flights,month==11 | month ==12)
    > head(b)
    # A tibble: 6 x 19
       year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
      <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
    1  2013    11     1        5           2359         6      352            345         7 B6     
    2  2013    11     1       35           2250       105      123           2356        87 B6     
    3  2013    11     1      455            500        -5      641            651       -10 US     
    4  2013    11     1      539            545        -6      856            827        29 UA     
    5  2013    11     1      542            545        -3      831            855       -24 AA     
    6  2013    11     1      549            600       -11      912            923       -11 UA     
    # ... with 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
    #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
    

    上述代码的简写形式为:

    c <- filter(flights,month %in% c(11,12))
    

    其中,x %in% y表示 选出x是y中的一个值时的所有行。

    filter()只能筛选出条件为TRUE的行;它会排除那些条件为FALSE和NA的行,如果想保留缺失值,可以明确指出:

    > df <- tibble(x=c(1,NA,3)) #tibble()用于构建一个数据框
    > head(df)
    # A tibble: 3 x 1
          x
      <dbl>
    1     1
    2    NA
    3     3
    > filter(df,x>1)
    # A tibble: 1 x 1
          x
      <dbl>
    1     3
    > filter(df,is.na(x) | x > 1)
    # A tibble: 2 x 1
          x
      <dbl>
    1    NA
    2     3
    

    1.2 使用arrange()排列行

    arrange()函数的工作方式与filter()函数非常相似,但前者不选择行,而是改变行的顺序。它接受一个数据框和一组作为排序依据的列名作为参数。如果列名不止一个,那么就使用后面的列在前面排序的基础上继续排序。

    #将flights按年月日排序
    > d <- arrange(flights,year,month,day)
    > head(d)
    # A tibble: 6 x 19
       year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
      <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
    1  2013     1     1      517            515         2      830            819        11 UA     
    2  2013     1     1      533            529         4      850            830        20 UA     
    3  2013     1     1      542            540         2      923            850        33 AA     
    4  2013     1     1      544            545        -1     1004           1022       -18 B6     
    5  2013     1     1      554            600        -6      812            837       -25 DL     
    6  2013     1     1      554            558        -4      740            728        12 UA     
    # ... with 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
    #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
    

    使用desc()可以按列进行降序排序。

    > e <- arrange(flights,desc(arr_delay))
    > head(e)
    # A tibble: 6 x 19
       year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
      <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
    1  2013     1     9      641            900      1301     1242           1530      1272 HA     
    2  2013     6    15     1432           1935      1137     1607           2120      1127 MQ     
    3  2013     1    10     1121           1635      1126     1239           1810      1109 MQ     
    4  2013     9    20     1139           1845      1014     1457           2210      1007 AA     
    5  2013     7    22      845           1600      1005     1044           1815       989 MQ     
    6  2013     4    10     1100           1900       960     1342           2211       931 DL     
    # ... with 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
    #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
    

    缺失值总是排在最后面。

    > df <- tibble(x=c(5,NA,2))
    > arrange(df,x)
    # A tibble: 3 x 1
          x
      <dbl>
    1     2
    2     5
    3    NA
    #将缺失值排在前面
    > arrange(df,desc(is.na(x)))
    # A tibble: 3 x 1
          x
      <dbl>
    1    NA
    2     5
    3     2
    

    1.3 使用select()选择列

    通过基于变量名的操作,select()可以让你快速生成一个有用的变量子集。

    #按名称选择列
    > f <- select(flights,year,month,day)
    > head(f)
    # A tibble: 6 x 3
       year month   day
      <int> <int> <int>
    1  2013     1     1
    2  2013     1     1
    3  2013     1     1
    4  2013     1     1
    5  2013     1     1
    6  2013     1     1
    # 选择‘year’和‘day’之间的所有列(包括year和day)
    > g <- select(flights,year:day)
    > head(g)
    # A tibble: 6 x 3
       year month   day
      <int> <int> <int>
    1  2013     1     1
    2  2013     1     1
    3  2013     1     1
    4  2013     1     1
    5  2013     1     1
    6  2013     1     1
    #选择不再‘year’和‘day’之间的所有列(不包括‘year’和‘day’)
    > h <- select(flights,-(year:day))
    > head(h)
    # A tibble: 6 x 16
      dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier flight tailnum
         <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>    <int> <chr>  
    1      517            515         2      830            819        11 UA        1545 N14228 
    2      533            529         4      850            830        20 UA        1714 N24211 
    3      542            540         2      923            850        33 AA        1141 N619AA 
    4      544            545        -1     1004           1022       -18 B6         725 N804JB 
    5      554            600        -6      812            837       -25 DL         461 N668DN 
    6      554            558        -4      740            728        12 UA        1696 N39463 
    # ... with 7 more variables: origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
    #   hour <dbl>, minute <dbl>, time_hour <dttm>
    

    还可以在select()函数中使用一些辅助函数。

    start_with("abc") 匹配以abc开头的名称

    ends_with("xyz") 匹配以xyz结尾的名称

    contains("ijk") 匹配包含ijk的名称

    matches("(.) \ \ 1") 选择匹配正则表达式的那些变量,这个正则表达式会匹配名称中含有重复字符的变量。

    num_range('x',1:3) 匹配x1,x2和x3

    select()函数和everything()辅助函数结合起来使用,从而将几个变量移到数据框的开头。

    > i <- select(flights,time_hour,air_time,everything())
    > head(i)
    # A tibble: 6 x 19
      time_hour           air_time  year month   day dep_time sched_dep_time dep_delay arr_time
      <dttm>                 <dbl> <int> <int> <int>    <int>          <int>     <dbl>    <int>
    1 2013-01-01 05:00:00      227  2013     1     1      517            515         2      830
    2 2013-01-01 05:00:00      227  2013     1     1      533            529         4      850
    3 2013-01-01 05:00:00      160  2013     1     1      542            540         2      923
    4 2013-01-01 05:00:00      183  2013     1     1      544            545        -1     1004
    5 2013-01-01 06:00:00      116  2013     1     1      554            600        -6      812
    6 2013-01-01 05:00:00      150  2013     1     1      554            558        -4      740
    # ... with 10 more variables: sched_arr_time <int>, arr_delay <dbl>, carrier <chr>,
    #   flight <int>, tailnum <chr>, origin <chr>, dest <chr>, distance <dbl>, hour <dbl>,
    #   minute <dbl>
    

    1.4 使用mutate()添加新变量

    mutate()总是能够添加新列到数据集的最后,查看所有列的最简单的方式就是使用view()函数。

    #先产生一个狭窄的数据集
    > flights_sml <- select(flights,year:day,ends_with("delay"),distance,air_time)
    > head(flights_sml)
    # A tibble: 6 x 7
       year month   day dep_delay arr_delay distance air_time
      <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl>
    1  2013     1     1         2        11     1400      227
    2  2013     1     1         4        20     1416      227
    3  2013     1     1         2        33     1089      160
    4  2013     1     1        -1       -18     1576      183
    5  2013     1     1        -6       -25      762      116
    6  2013     1     1        -4        12      719      150
    #添加新列
    > j <- mutate(flights_sml,gain=arr_delay - dep_delay,speed= distance/air_time * 60)
    > head(j)
    # A tibble: 6 x 9
       year month   day dep_delay arr_delay distance air_time  gain speed
      <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl> <dbl> <dbl>
    1  2013     1     1         2        11     1400      227     9  370.
    2  2013     1     1         4        20     1416      227    16  374.
    3  2013     1     1         2        33     1089      160    31  408.
    4  2013     1     1        -1       -18     1576      183   -17  517.
    5  2013     1     1        -6       -25      762      116   -19  394.
    6  2013     1     1        -4        12      719      150    16  288.
    

    创建新列后可以立马使用,如果只想保留新变量,可以使用transmute()函数。

    > k <- transmute(flights,gain=arr_delay-dep_delay,hours=air_time/60,gain_per_hour=gain/hours)
    > head(k)
    # A tibble: 6 x 3
       gain hours gain_per_hour
      <dbl> <dbl>         <dbl>
    1     9  3.78          2.38
    2    16  3.78          4.23
    3    31  2.67         11.6 
    4   -17  3.05         -5.57
    5   -19  1.93         -9.83
    6    16  2.5           6.4 
    

    1.5 使用summarize()进行分组摘要

    summarize()可以将数据框折叠成一行。

    > l <- summarise(flights,delay=mean(dep_delay,na.rm = T))
    > head(l)
    # A tibble: 1 x 1
      delay
      <dbl>
    1  12.6
    

    如果summarize()不与group_by()一起使用,那么它本身也没有大用。group_by()可以将分析单位从整个数据集更改为单个分组。

    #分组后就变成year,month,day相同的为一组,来计算它们的平均延误时间
    > by_day <- group_by(flights,year,month,day) 
    > m <- summarise(by_day,delay=mean(dep_delay,na.rm = T)) #通过设置na.rm=T,可以在计算前去除缺失值,否则会得到大量的缺失值。
    `summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
    > head(m)
    # A tibble: 6 x 4
    # Groups:   year, month [1]
       year month   day delay
      <int> <int> <int> <dbl>
    1  2013     1     1 11.5 
    2  2013     1     2 13.9 
    3  2013     1     3 11.0 
    4  2013     1     4  8.95
    5  2013     1     5  5.73
    6  2013     1     6  7.15
    

    使用管道%>%提高代码的可读性,重点在于转换的过程而不是转换的对象。在阅读代码的时候,%>%读作 然后。以下这个例子研究每个目的地的距离和平均延误时间之间的关系。

    > delay <- flights %>%
      group_by(dest) %>%
      summarise(
        count=n(), #对分组后的dest各元素个数进行计数
        dist=mean(distance,na.rm = T),
        delay=mean(arr_delay,na.rm = T)
      ) %>%
      filter(count > 20,dest != "HNL")
    > head(delay)
    # A tibble: 6 x 4
      dest  count  dist delay
      <chr> <int> <dbl> <dbl>
    1 ABQ     254 1826   4.38
    2 ACK     265  199   4.85
    3 ALB     439  143  14.4 
    4 ATL   17215  757. 11.3 
    5 AUS    2439 1514.  6.02
    6 AVL     275  584.  8.00
    

    寻找航班数量和平均延误时间之间的关系。

    > library(ggplot2)
    > not_cancelled <- flights %>%
      filter(!is.na(dep_delay),!is.na(arr_delay))
    > delays <- not_cancelled %>%
      group_by(tailnum) %>%
      summarise(
        delay=mean(arr_delay,na.rm = T),
        n=n
      )
    > ggplot(data = delays,mapping = aes(x=n,y=delay))+
      geom_point()
    
    

    查看上述图形时,通常应该筛选掉那些观测数量非常少的分组,这样就可以避免受到特别小的分组中极端变动的影响,进而更好的发现数据模式。

    delays %>%
      filter(n>25) %>%
      ggplot(mapping = aes(x=n,y=delay)) +
      geom_point()
    

    另一个案例:使用Lahman包中的数据来计算大联盟的每个棒球队员的打击率(安打数/打数)。

    #转换成tibble,以便输出更美观
    > install.packages("Lahman")
    > library(Lahman)
    > batting <- as_tibble(Lahman::Batting)
    > batters <- batting %>%
      group_by(playerID) %>%
      summarise(
        ba=sum(H,na.rm = T)/sum(AB,na.rm = T),
        ab=sum(AB,na.rm = T)
      )
    > batters %>%
      filter(ab>100) %>%
      ggplot(mapping = aes(x=ab,y=ba))+
      geom_point()+
      geom_smooth(se=F)
    

    1.6 常用的摘要函数

    只使用均值,计数和求和是远远不够的,R中还提供了很多其他的常用摘要函数。

    1.6.1 位置度量

    median(x)用来求中位数,50%的x大于它,同时50%的x小于它。

    将聚合函数和逻辑筛选组合起来使用。

    > not_cancelled %>%
    > group_by(year,month,day) %>%
      summarise(
        #平均延误时间
        avg_delay1=mean(arr_delay),
        #平均正延误时间
        avg_delay2=mean(arr_delay[arr_delay>0])
      )
    `summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
    # A tibble: 365 x 5
    # Groups:   year, month [12]
        year month   day avg_delay1 avg_delay2
       <int> <int> <int>      <dbl>      <dbl>
     1  2013     1     1     12.7         32.5
     2  2013     1     2     12.7         32.0
     3  2013     1     3      5.73        27.7
     4  2013     1     4     -1.93        28.3
     5  2013     1     5     -1.53        22.6
     6  2013     1     6      4.24        24.4
     7  2013     1     7     -4.95        27.8
     8  2013     1     8     -3.23        20.8
     9  2013     1     9     -0.264       25.6
    10  2013     1    10     -5.90        27.3
    # ... with 355 more rows
    
    1.6.2 秩的度量:min(x),quantile(x,0.25)和max(x)

    quantile(x,0.25)会找出x中从小到大顺序大于前25%而小于后75%的值。

    示例:找出每天最早和最晚的航班何时出发.

    > n <- not_cancelled %>%
      group_by(year,month,day) %>%
      summarise(
        first=min(dep_time),
        last=max(dep_time)
      )
    > head(n)
    # A tibble: 6 x 5
    # Groups:   year, month [1]
       year month   day first  last
      <int> <int> <int> <int> <int>
    1  2013     1     1   517  2356
    2  2013     1     2    42  2354
    3  2013     1     3    32  2349
    4  2013     1     4    25  2358
    5  2013     1     5    14  2357
    6  2013     1     6    16  2355
    
    1.6.3 计数

    前面已经使用过n()来返回当前分组的大小。如果想计算出非缺失值的数量,可以使用sum(!is.na(x))。如果想要计算出唯一值的数量,可以使用n_distinct(x)

    #查看哪个目的地具有最多的航空公司
    > o <- not_cancelled %>%
      group_by(dest) %>%
      summarise(carriers=n_distinct(carrier)) %>% #只计算唯一值
      arrange(desc(carriers))
    > head(o)
    # A tibble: 6 x 2
      dest  carriers
      <chr>    <int>
    1 ATL          7
    2 BOS          7
    3 CLT          7
    4 ORD          7
    5 TPA          7
    6 AUS          6
    
    ###关于n_distinct()的理解,可以运行一下代码,实际上是去除唯一值的重复值,只看唯一值的数量。
    > x <- sample(1:10, 1e5, rep = TRUE)
    > length(unique(x))
    > n_distinct(x) #与上一行代码相当
    

    因为计数太常用了,所以dplyr提供了一个简单的辅助函数,用于只需要计数的情况。

    > not_cancelled %>%
       count(dest)
    #计算每架飞机飞行的总里程,实际上就是求和。
    > not_cancelled %>%
        count(tailnum,wt=distance)
    
    1.6.4 逻辑值的计数和比例

    当与数值型函数一同使用时,TRUE会转换成1,FALSE会转换成0,这使得sum()mean()非常适用于逻辑值:sum(x)可以找出x中TRUE的数量,mean(x)则可以找出比例。

    #早上五点前出发的有多少架航班
    > not_cancelled %>%
    +   group_by(year,month,day) %>%
    +   summarise(n_nearly=sum(dep_time<500))
    `summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
    # A tibble: 365 x 4
    # Groups:   year, month [12]
        year month   day n_nearly
       <int> <int> <int>    <int>
     1  2013     1     1        0
     2  2013     1     2        3
     3  2013     1     3        4
     4  2013     1     4        3
     5  2013     1     5        3
     6  2013     1     6        2
     7  2013     1     7        2
     8  2013     1     8        1
     9  2013     1     9        3
    10  2013     1    10        3
    # ... with 355 more rows
    
    #延误超过1小时的航班比例是多少
    > not_cancelled %>%
    +   group_by(year,month,day) %>%
    +   summarise(hour_perc=mean(arr_delay>60))
    `summarise()` regrouping output by 'year', 'month' (override with `.groups` argument)
    # A tibble: 365 x 4
    # Groups:   year, month [12]
        year month   day hour_perc
       <int> <int> <int>     <dbl>
     1  2013     1     1    0.0722
     2  2013     1     2    0.0851
     3  2013     1     3    0.0567
     4  2013     1     4    0.0396
     5  2013     1     5    0.0349
     6  2013     1     6    0.0470
     7  2013     1     7    0.0333
     8  2013     1     8    0.0213
     9  2013     1     9    0.0202
    10  2013     1    10    0.0183
    # ... with 355 more rows
    
    1.7 分组新变量(和筛选器)

    虽然与summarize()函数结合起来使用是最有效的,但分组也可以与mutate()filter()函数结合,以完成非常便捷的操作。

    示例一:找出每个分组中最差的成员。

    > flights_sml %>%
    +   group_by(year,month,day) %>%
    +   filter(rank(desc(arr_delay))<5)
    # A tibble: 1,464 x 7
    # Groups:   year, month, day [365]
        year month   day dep_delay arr_delay distance air_time
       <int> <int> <int>     <dbl>     <dbl>    <dbl>    <dbl>
     1  2013     1     1       853       851      184       41
     2  2013     1     1       290       338     1134      213
     3  2013     1     1       260       263      266       46
     4  2013     1     1       379       456     1092      222
     5  2013     1     2       268       288     1092      203
     6  2013     1     2       334       323      937      150
     7  2013     1     2       337       368     2586      346
     8  2013     1     2       379       359     1620      228
     9  2013     1     3       174       176     1008      152
    10  2013     1     3       268       270     1069      158
    # ... with 1,454 more rows
    

    其中对rank()函数的使用做一个补充。

    rank()函数是对一维度数组、向量x 进行排序。若x 为数值,则按照小数在前大数在后的原则进行排序。

    rank() 将数据分为确定值与缺失值两种。缺失值可按先后排在确定值之前(na.last = FALSE);也可排在之后(na.last = TRUE),;也可保留,不参与排序(na.last = "keep")。

    "first" 是最基本的排序,小数在前大数在后,相同元素先者在前后者在后。

    "max" 是相同元素都取该组中最好的水平,即通常所讲的并列排序。

    "min" 是相同元素都取该组中最差的水平,可以增大序列的等级差异。

    "average" 是相同元素都取该组中的平均水平,该水平可能是个小数。

    "random" 是相同元素随机编排次序,避免了“先到先得”,“权重”优于“先后顺序”的机制增大了随机的程度。

    > rank(t <- c(6.8, 8.1, 7.2))
    [1] 1 3 2
    

    示例二:找出大于某个阈值的所有分组:

     > popular_dests <- flights %>%
    +   group_by(dest) %>%
    +   filter(n()>365)
    > head(popular_dests)
    # A tibble: 6 x 19
    # Groups:   dest [5]
       year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay carrier
      <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>     <dbl> <chr>  
    1  2013     1     1      517            515         2      830            819        11 UA     
    2  2013     1     1      533            529         4      850            830        20 UA     
    3  2013     1     1      542            540         2      923            850        33 AA     
    4  2013     1     1      544            545        -1     1004           1022       -18 B6     
    5  2013     1     1      554            600        -6      812            837       -25 DL     
    6  2013     1     1      554            558        -4      740            728        12 UA     
    # ... with 9 more variables: flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
    #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
    

    参考链接:
    1.https://dplyr.tidyverse.org/
    2.《R for Data Science》

    相关文章

      网友评论

        本文标题:【R语言】R包dplyr(一):数据转换

        本文链接:https://www.haomeiwen.com/subject/bssxpktx.html