使用R的plyr包重新排序数据帧中的组

时间:2015-02-03 01:59:08

标签: r loops plyr dplyr

我有一个数据重组任务,我认为可以由R的{​​{1}}包处理。我有一个数据框,其数字数据按组进行组织。在每个组中,我需要将数据从最大到最小排序。

数据如下所示(下面要生成的代码)

plyr

我想要的是这个。

group     value
2     b 0.1408790
6     b 1.1450040   #2nd b is smaller than 1st
1     c 5.7433568
3     c 2.2109819
4     d 0.5384659
5     d 4.5382979

所以,我需要group value b 1.1450040 #1st b is largest b 0.1408790 c 5.7433568 c 2.2109819 d 4.5382979 d 0.5384659 做的就是通过每个小组&在数字数据上应用类似plyr的内容,按顺序重新组织,保存重新排序的数据子集,&把它们放在一起最后。

我可以用手册“手动”处理这个列表&一些循环,但需要很长时间。这可以由order在几行中完成吗?

示例数据

plyr

使用循环的低效方法:

我目前的方法是将数据框df.sz <- 6;groups <-c("a","b","c","d") df <- data.frame(group = sample(groups,df.sz,replace = TRUE), value = runif(df.sz,0,10),stringsAsFactors = FALSE) df <- df[order(df$group),] #order by group letter 按组分成列表,将df应用于列表的每个元素,并用重新排序的元素覆盖原始列表元素。然后我使用循环来重新组装数据帧。 (作为一项学习练习,我也对如何使这些代码更有效感兴趣。特别是,使用order base函数将列表转换为数据帧的最有效方法是什么? )

数据框中唯一组的向量

R

创建空列表

groups.u <- unique(df$group)

my.list <- as.list(groups.u); names(my.list) <- groups.u df分解为列表

$group

使用for(i in 1:length(groups.u)){ i.working <- which(df$group == groups.u[i]) my.list[[i]] <- df[i.working, ] }

对列表中的元素进行排序
order

最后从列表中重建df。 1,为循环制作种子

for(i in 1:length(my.list)){
  order.x <- order(my.list[[i]]$value,na.last = TRUE, decreasing = TRUE)
  my.list[[i]] <- my.list[[i]][order.x, ] 
}

删除种子

new.df <- my.list[[1]][1,];; new.df[1,] <- NA
for(i in 1:length(my.list)){
  new.df <- rbind(new.df,my.list[[i]])
}

2 个答案:

答案 0 :(得分:4)

您可以使用dplyr,这是plyr的较新版本,专注于数据框:

library(dplyr)
arrange(df, group, desc(value))

答案 1 :(得分:3)

包含一个&#34; data.table&#34;几乎是亵渎神圣的。在标记的问题中回答&#34; plyr&#34;或者&#34; dplyr&#34;,但您的评论表明您正在寻找快速紧凑的代码。

在&#34; data.table&#34;中,您可以使用setorder,如下所示:

 setorder(setDT(df), group, -value)

该命令可以做两件事:

  1. 它会将您的data.frame转换为data.table而无需复制。
  2. 按引用对列进行排序(同样,不进行复制)。
  3. 你提及&#34;&gt; 50k行&#34;。这实际上并不是很大,甚至基地R应该能够很好地处理它。在&#34; dplyr&#34;和&#34; data.table&#34;,你在几毫秒内查看测量结果。当输入数据集变大时,这可能会有所不同。

    set.seed(1)
    df.sz <- 50000
    groups <- c(letters, LETTERS)
    df <- data.frame(
      group = sample(groups, df.sz, replace = TRUE),
      value = runif(df.sz,0,10), stringsAsFactors = FALSE)
    library(data.table)
    library(dplyr)
    library(microbenchmark)
    dt1 <- function() as.data.table(df)[order(group, -value)]
    dt2 <- function() setorder(as.data.table(df), group, -value)[]
    dp1 <- function() arrange(df, group, desc(value))
    microbenchmark(dt1(), dt2(), dp1())
    # Unit: milliseconds
    #   expr       min        lq      mean    median        uq       max neval
    #  dt1()  5.749002  5.981274  7.725225  6.270664  8.831899 67.402052   100
    #  dt2()  4.956020  5.096143  5.750724  5.229124  5.663545  8.620155   100
    #  dp1() 37.305364 37.779725 39.837303 38.169298 40.589519 96.809736   100