• R实战 第七篇:plyr包


    在数据分析中,整理数据的本质可以归纳为:对数据进行分割(Split),然后应用(Apply)某些处理函数,最后将结果重新组合(Combine)成所需的格式返回,简单描述为:Split - Apply - Combine,各个步骤的作用是:

    • Split:把要处理的数据分割成小片断,常用的函数是split(),subset();
    • Apply:对每个小片断独立进行操作,常用的是apply家族函数,plyr包核心函数;
    • Combine:把片断重新组合,常用的函数是unlist()函数。

    这个过程可以通过Base包的apply家族函数来实现,apply家族函数包括了apply、sapply、lapply、tapply、aggregate等,可以应用于数据分析的各个阶段。 

    plyr包是apply家族函数的升级版本,使用plyr包可以实现:在一个函数内同时完成“Split - Apply - Combine”,并且,plyr包实现R类型(vector, list, data.frame)之间的分组变换,基本上可以取代Base包中的apply家族函数。

    plyr包对核心函数的命名采用统一的格式:**ply,所有的函数名都由5个字符组成,且最后三个字符是ply,函数名的第一个字符代表输入数据的类型,第二个字符代表输出数据的类型,R类型的简写是:

    • d:data.frame
    • l:list
    • a:array,vector,matrix
    • r:代表replicate,重复多次
    • m:多输入
    • _:舍弃输出结果

    这种统一的命名格式,使得plyr包的函数更容易记忆和使用,但是,plyr包不是预装于R语言中,使用之前,需要加载和引用plyr包:

    install.packages("plyr")
    library(plyr)

    一,plyr包函数

    plyr包用于在R中实现split-apply-combine的模式,这中模式在数据分析中是极其常见的,通过把数据分解为小的分片,然后在分片上做操作,最后把结果组合在一起,以解决复杂的分析问题。因此,当遇到复杂的数据分析问题时,一般都需要把复杂的问题分组,然后在每个分组上做操作,最终把每个分组上的结果组合到一起。plyr包的函数很多,除了**ply的核心函数之外,还有一些辅助函数,在处理数据时,都十分有用。

    1,ddply

    plyr包中最常用的函数是ddply()函数,该函数对数据框进行操作,对每一行调用一个函数,并返回数据框类型:

    ddply(.data, .variables, .fun = NULL, ...)

    参数注释:

    • .data:函数处理的数据框;
    • .variables:要进行拆分的变量名称,传递变量的格式是: .(col_name),就是把进行分组的变量名包含在.()中;
    • .fun:应用到每行的函数
    • ...:传递到fun的其他参数

    对于参数fun,有两种赋值方式:

    第一种: 如果使用colwise()函数,那么这使ddply函数把参数fun应用于每一列,除了参数.variable指定的数据列之外,例如:

    ddply(diamonds,.(color),colwise(mean))

    第二种: 使用summarize函数对指定的列执行操作,更为灵活,例如:

    > ddply(diamonds,.(color),summarize,avg_price=mean(price),avg_carat=mean(carat))
      color avg_price avg_carat
    1     D  3169.954 0.6577948
    2     E  3076.752 0.6578667
    .....

    2,each函数

    plyr包的each()函数,能够把多个函数整合到一个函数中,每一个函数必须只能返回一个数值:

    each(...)

    使用each()函数,可以使函数aggregate()同时调用多个函数:

    > aggregate(cbind(price,carat)~cut+color,diamonds,each(mean,sum))
             cut color   price.mean    price.sum   carat.mean    carat.sum
    1       Fair     D     4291.061   699443.000    0.9201227  149.9800000
    2       Good     D     3405.382  2254363.000    0.7445166  492.8700000
    ......

    3,rename函数

    按照名字对变量重命名:

    rename(x, replace, warn_missing = TRUE, warn_duplicated = TRUE)

    参数注释:

    • x: 重命名的对象
    • replace:命名的向量,格式是:c(new_name=old_name,...)

    使用rename函数对数据框的变量进行重命名,例如:

    rename(mtcars, c("disp" = "displacement"))

    4,arrange函数

    按照数据框的变量对数据框排序,注意,arrange()函数不会保留行名称(row.names)

    arrange(df, ...)

    例如,按照变量cyl和disp,对数据框mtcars进行排序:

    # sort mtcars data by cylinder and displacement
    mtcars[with(mtcars, order(cyl, disp)), ]
    # Same result using arrange: no need to use with(), as the context is implicit
    arrange(mtcars, cyl, disp)

    5,mutate函数

    对数据框进行转换,或增加新的变量,或替换已经存在的变量,该函数和transfrom函数十分相似,不过,mutate()函数是递进式的,这使得后期的转换可以使用早期创建的变量。

    # Things transform can't do
    mutate(airquality, Temp = (Temp - 32) / 1.8, OzT = Ozone / Temp)

    6,name_rows函数

    在设计时,没有plyr函数会保留行名称(row names)。如果想保留行名称,可以使用name_rows()把行名称转换为显式的列值,在执行为相应的plyr操作之后,再使用name_rows把列值转换为行名称。

    name_rows(df)

    参数df :数据框对象,拥有 rownames,或者显式的列名 .rownames

    二,拆分-应用-组合

    在R语言中,分组聚合可以通过三步实现:拆分-应用-合并(Split-Apply-Combine)。例如,对玩家的游戏成绩进行统计和分析,创建示例数据:

    > players_scores <- data.frame(
         player=rep(c('Tom','Dick','Jim'),times=c(2,5,3)),
         score=round(runif(10,1,100),-1)
     )

    1,分组数据

    计算每个玩家的平均得分,首先对玩家分组,需要用到split()函数,按照特定的字段对数据进行分组:

    split(x, f, drop = FALSE, ...)

    参数注释:

    • x:数据框或向量,是被分组的数据;
    • f:因子类型,按照f对x进行分组;

    函数的返回值是一个列表对象,每一个列表项都是包含分组数据的向量。

    例如,split(score,player)函数的作用是按照player字段把数据框中的score拆分成一组,也就是说,player 相同的score是同一个分组,填充到同一个列表项中:

    > (scores_by_player <- with(players_scores,split(score,player)))
    $Dick
    [1] 70 20 30 70 70
    
    $Jim
    [1] 80 90 50
    
    $Tom
    [1] 80 90

    2,应用函数

    当数据分割之后,对每个分组计算平均分。使用lapply()函数,对于每个列表项,应用mean()函数,计算单个列表项的平均值,例如:

    list_mean_by_player <- lapply(scores_by_player,mean)

    3,组合数据

    组合数据是为了显示数据,在显示最终的数据时,通常把列表转换为向量。lapply()函数返回的结果是一个列表对象,每一个列表项都是一个向量,因此可以使用unlist()函数,把列表转换为向量,例如:

    > unlist(list_mean_by_player)
        Dick      Jim      Tom 
    52.00000 73.33333 85.00000 

    三,使用apply家族函数实现分组聚合

    在apply家族函数中,每个函数都用于特定的数据类型:

    • apply函数只能用于矩阵,
    • lapply函数能够用于向量和列表(list),其工作原理是把一个函数应用于一个列表中的每个元素上,并且把结果作为列表返回;
    • sapply处理列表,返回向量。
    • mapply函数,把调用的函数应用到多个列表的每一个元素中。
    • tapply函数用于分组聚合运算,在研究数据时,有时需要对数据按照特定的字段进行分组,然后统计各个分组的数据,这就是SQL语法中的分组聚合。

    在数据分析中,使用Base包实现”拆分-应用-合并“ 显得十分繁琐,可以使用tapply()函数一次完成所有的三个步骤,一气呵成:

    with(players_scores,tapply(score,player,mean))

    tapply()函数常用的参数共有三个,第一个参数是数据框对象或向量,第二个参数是因子列表,也就是分组字段,第三个参数是指对单个分组应用的函数:

    tapply(X, INDEX, FUN = NULL, ...)

    by()函数和aggregate()函数是tapply()函数的包装函数,功能相同,接口稍微不同。

    by(data, INDICES, FUN, ..., simplify = TRUE)
    aggregate(x, by, FUN, ..., simplify = TRUE, drop = TRUE)

    四,使用plyr包实现分组聚合

    函数daply的作用是分割数据框,对每个分组应用聚合函数,最后把每个分组的聚合值组合起来,以数组的形式返回:

    daply(.data, .variables, .fun = NULL, ...)

    参数注释:

    • .data:数据框,存储用于分析的数据;
    • .variables:分组字段,指定分组字段的格式是  .(col_name);
    • .fun:应用于每个分组的函数,有两种方式,上文有详细介绍。

    为了计算每个player的平均得分,可以使用daply()函数,例如,

    unlist(daply(players_scores,.(player),summarize,varScore=mean(score)))

    在示例中,daply()函数返回的类型是list,通过unlist()函数转换为向量。至于为什么返回的是list,而不是数组,我也很疑惑。

    参考文档:

    plyr reference manual

    R语言-数据整形之plyr包 R语言中plyr包

  • 相关阅读:
    21.错误和异常
    20.装饰器相关
    19.装饰器
    18.函数编程的练习
    Remove Duplicates from Sorted List II
    Ubuntu 12.04输入密码登陆后又跳回到登录界面
    Remove Linked List Elements
    Populating Next Right Pointers in Each Node *
    Convert Sorted Array to Binary Search Tree
    Flatten Binary Tree to Linked List *
  • 原文地址:https://www.cnblogs.com/ljhdo/p/4907570.html
Copyright © 2020-2023  润新知