按组筛选数据框中每个组的前n行,并按变量排序。

8
我想对一个数据框进行子集操作,只保留按照某个变量分组并且按照另一个变量降序排序的前n行数据。以下是一个例子:
    d1 <- data.frame(Gender = c("M", "M", "F", "F", "M", "M", "F", 
  "F"), Age = c(15, 38, 17, 35, 26, 24, 20, 26))

我想获取每个性别年龄降序排列的2行数据。期望的输出结果如下:
Gender  Age  
F   35  
F   26  
M   38  
M   26  

我在这里寻找了关于排序和其他问题的解决方案,但是无法找到适合解决此问题的方法。感谢您的帮助。


1
你只需要每个性别中最大的两个年龄吗? - kmm
6个回答

13

使用plyr中的ddply()函数是一种解决方法

require(plyr)
ddply(d1, "Gender", function(x) head(x[order(x$Age, decreasing = TRUE) , ], 2))

在我发帖之前,我没有看到你的回答!好多了。 - Manoel Galdino
那个工作得很好!我甚至可以修改“n”值。谢谢。 - karlos
@brandon,即使您的n大于组中实际行数,它也可以正常工作。因此,如果您有6个女性和5个男性,并将n更改为5,则会获得前5行的女性和所有男性。这正是我想要的。 - karlos

6
使用data.table包
require(data.table)
dt1<-data.table(d1)# to speedup you can add setkey(dt1,Gender)
dt1[,.SD[order(Age,decreasing=TRUE)[1:2]],by=Gender]

7
可以使用order(-Age)代替order(Age,decreasing=TRUE)。这样可以按不同方向对多列进行排序,例如:order(-Age,+Height,-Weight)。请注意,负号表示以降序排序,而正号表示以升序排序。 - Matt Dowle

1

我相信还有更好的答案,但这是一种方法:

require(plyr)
ddply(d1, c("Gender", "-Age"))[c(1:2, 5:6),-1]

如果您有比您提供的更大的数据框,并且不想视觉检查要选择哪些行,只需使用以下方法:
new.d1=ddply(d1, c("Gender", "-Age"))[,-1]
pos=match('M',new.d1$Gender) # pos wil show index of first entry of M
new.d1[c(1:2,pos:(pos+1)),]

1
谢谢你的解决方案,Manoel,但是我没有尝试它,因为chase的解决方案对我有用。 - karlos
@karlos,当然了。他的解决方案比我的好。事实上,昨天他刚帮我解决了一个问题,他也使用了plyr。毫不奇怪,他使用'ddply'比我更好。 - Manoel Galdino

0

如果你只想进行排序,那么这甚至比那更容易:

d1 <- transform(d1[order(d1$Age, decreasing=TRUE), ], Gender=as.factor(Gender))

然后您可以调用:

require(plyr)
d1 <- ddply(d1, .(Gender), head, n=2)

对每个性别子组进行前两项子集。


0
d1 = d1[order(d1$Gender, -d1$Age),]  
d1 = d1[ave(d1$Age, d1$Gender, FUN = seq_along) <= 2, ]

有一个类似的问题,发现在包含150万个记录的数据框上使用这种方法非常快速。

0

如果你需要,我有一个建议:例如,获取前2个女性和前3个男性:

library(plyr)
m<-d1[order(d1$Age, decreasing = TRUE) , ] 
h<-mapply(function(x,y) head(x,y), split(m$Age,m$Gender),y=c(2,3)) 
ldply (h, data.frame)

你只需要更改最终数据框的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接