如何在 R 中使用 Group By 和排序函数

How do I use Group By with order function in R

我有一个包含 120000 条记录和 19 个变量的数据框,其中 2 个是 state 和 MonthlyIncome。

我必须创建一个新数据集,其中包含每个州的前 10 名(按月收入计算)客户。

我尝试了很多选项,包括 data.table 和 dplyr 和 base,但总是缺少一些东西。

data.table :

 x <- customer_any_360[,order(-dense_rank(MonthlyIncome))[1:10], by = state]

--- 我试过的例子

有人可以帮忙吗,我对 R 还是个新手,真的在为这个问题苦苦挣扎。提前致谢!!

在令人惊叹的 data.table 包中寻找答案,您就走在了正确的轨道上。这里我只是编造了一些状态 1 到 50 的数据,并从正态分布 N(50000, 20000^2) 中提取收入。

根据@Arun 的 评论进行编辑,并从 OP 请求所有列(使用 .SD 隐藏变量):

require(data.table)
set.seed(123)
mydata <- data.table(state = 1:50, 
                     monthlyIncome = round(rnorm(120000, 50000, 20000)),
                     anothervar = 1:120000)
selecteddata <- mydata[order(-monthlyIncome), head(.SD, 10), by = state]

# just to verify
selecteddata <- selecteddata[order(state, -monthlyIncome)]
mydata <- mydata[order(-monthlyIncome)]
identical(selecteddata[1:10], mydata[state==1][1:10])  # state 1
identical(selecteddata[11:20], mydata[state==2][1:10]) # state 2

如果您想使用 rank 函数,一个选项是 data.table 中的 frank,您可以在 ties.method 中指定选项。

library(data.table)#v1.9.5+
setDT(customer_any_360)[, .SD[frank(-MonthlyIncome, 
               ties.method='dense') %in% 1:10], by = state]

甚至 order 就足够了

setDT(customer_any_360)[order(-MonthlyIncome), .SD[1:10], by = state]

使用dplyr,有多个选项,dense_rankmin_ranktop_n,这取决于你想要什么。此外,对于过滤,可以使用 slicefilter

library(dplyr)
customer_any_360 %>%
           group_by(state) %>%
           slice(dense_rank(-MonthlyIncome)[1:10])

或使用sqldf

 library(sqldf)
 sqldf('select * from customer_any_360 i
          where rowid in 
          (select rowid from customer_any_360 
           where state = i.state 
           order by MonthlyIncome desc 
           limit 10)
  order by i.state, i.MonthlyIncome desc')

或使用 base R

中的 ave
indx <- with(customer_any_360, ave(-MonthlyIncome, state,
       FUN=function(x) rank(x, ties.method='first')) %in% 1:10)
customer_any_360[indx,]

编辑:frank 选项根据@Arun

的建议进行了编辑

数据

set.seed(24)
customer_any_360 <- data.frame(cust=1:120000, state= sample(state.abb,
  120000, replace=TRUE), MonthlyIncome= sample(1000:6500, 120000, 
     replace=TRUE), stringsAsFactors=FALSE)

使用 plyr 包中的 ddply:

data(iris)
ddply(iris, "Species", function(x) head(x[order(x$Sepal.Length, decreasing = TRUE) , ], 2))
  Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1          5.8         4.0          1.2         0.2     setosa
2          5.7         4.4          1.5         0.4     setosa
3          7.0         3.2          4.7         1.4 versicolor
4          6.9         3.1          4.9         1.5 versicolor
5          7.9         3.8          6.4         2.0  virginica
6          7.7         3.8          6.7         2.2  virginica