我有一个数据重组任务,我认为可以由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]])
}
答案 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)
该命令可以做两件事:
data.frame
转换为data.table
而无需复制。 你提及&#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