按组排序变量(dplyr)

29

我有一个包含列 x1, x2, group 的数据框,我想生成一个新的数据框,其中包含一个额外的列rank,该列指示x1在其组中的顺序。

这里有一个相关的问题(链接),但是已被接受的答案似乎不再起作用。

到此为止,没问题:

library(dplyr)
data(iris)
by_species <- iris %>% 
              arrange(Species, Sepal.Length) %>% 
              group_by(Species)  

但是当我尝试通过分组获取排名时:

by_species <- mutate(by_species, rank=row_number())

错误提示为:

Error in rank(x, ties.method = "first", na.last = "keep") :
argument "x" is missing, with no default

更新

问题出在dplyrplyr之间的一些冲突。要重现此错误,请同时加载两个软件包:

library(dplyr)
library(plyr)
data(iris)
by_species <- iris %>% 
              arrange(Species, Sepal.Length) %>% 
              group_by(Species) %>% 
              mutate(rank=row_number())
# Error in rank(x, ties.method = "first", na.last = "keep") : 
# argument "x" is missing, with no default

卸载plyr,它的表现与预期一样:

detach("package:plyr", unload=TRUE)
by_species <- iris %>% 
              arrange(Species, Sepal.Length) %>% 
              group_by(Species) %>% 
              mutate(rank=row_number())

by_species %>% filter(rank <= 3)

##   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species  rank
##          (dbl)       (dbl)        (dbl)       (dbl)     (fctr) (int)
## 1          4.3         3.0          1.1         0.1     setosa     1
## 2          4.4         2.9          1.4         0.2     setosa     2
## 3          4.4         3.0          1.3         0.2     setosa     3
## 4          4.9         2.4          3.3         1.0 versicolor     1
## 5          5.0         2.0          3.5         1.0 versicolor     2
## 6          5.0         2.3          3.3         1.0 versicolor     3
## 7          4.9         2.5          4.5         1.7  virginica     1
## 8          5.6         2.8          4.9         2.0  virginica     2
## 9          5.7         2.5          5.0         2.0  virginica     3

1
你确定 by_species <- mutate(by_species, rank=row_number()) 这个命令是产生错误的吗?它在我的电脑上可以运行,并且你的错误提到的是 rank 函数,而不是正在使用的 row_number 函数。此外,如果你使用 rank 函数,你需要提供一个参数,比如 rank(x)(其中 x 是你想排名的对象)。row_number 函数不需要这样做。 - steveb
你的脚本已经按照预期产生了输出。我投票关闭此问题,因为无法重现。 - Pierre L
@steveb完成。没有错误,但排名仍然是全局的,而不是按组...我的dplyr版本是0.4.3。 - alberto
1
@steveb 加载 plyr 然后加载 dplyr 在我的电脑上似乎无法工作。 - alberto
1
我也发现为了让我的程序正常运行,我需要使用detach("package:plyr", unload=TRUE) - vb66
显示剩余17条评论
2个回答

41

如下代码将按照要求生成所需结果。

library(dplyr)

by_species <- iris %>% arrange(Species, Sepal.Length) %>%
    group_by(Species) %>% 
    mutate(rank = rank(Sepal.Length, ties.method = "first"))

by_species %>% filter(rank <= 3)
##Source: local data frame [9 x 6]
##Groups: Species [3]
##
##  Sepal.Length Sepal.Width Petal.Length Petal.Width    Species  rank
##         (dbl)       (dbl)        (dbl)       (dbl)     (fctr) (int)
##1          4.3         3.0          1.1         0.1     setosa     1
##2          4.4         2.9          1.4         0.2     setosa     2
##3          4.4         3.0          1.3         0.2     setosa     3
##4          4.9         2.4          3.3         1.0 versicolor     1
##5          5.0         2.0          3.5         1.0 versicolor     2
##6          5.0         2.3          3.3         1.0 versicolor     3
##7          4.9         2.5          4.5         1.7  virginica     1
##8          5.6         2.8          4.9         2.0  virginica     2
##9          5.7         2.5          5.0         2.0  virginica     3

by_species %>% slice(1:3)
##Source: local data frame [9 x 6]
##Groups: Species [3]
##
##  Sepal.Length Sepal.Width Petal.Length Petal.Width    Species  rank
##         (dbl)       (dbl)        (dbl)       (dbl)     (fctr) (int)
##1          4.3         3.0          1.1         0.1     setosa     1
##2          4.4         2.9          1.4         0.2     setosa     2
##3          4.4         3.0          1.3         0.2     setosa     3
##4          4.9         2.4          3.3         1.0 versicolor     1
##5          5.0         2.0          3.5         1.0 versicolor     2
##6          5.0         2.3          3.3         1.0 versicolor     3
##7          4.9         2.5          4.5         1.7  virginica     1
##8          5.6         2.8          4.9         2.0  virginica     2
##9          5.7         2.5          5.0         2.0  virginica     3

这个问题要求使用dplyr解决方案,所以我在这篇评论中提供一个data.table的解决方案,可能会有用。以下代码可以使用data.table实现: setDT(iris)[order(Species, Sepal.Length), .SD[1:3], by = Species] - steveb

4

未来读者可使用基本R语言实现按组排序的变量。例如,对于OP提供的iris数据集,按照Sepal.Length进行排序:

# ORDER BY SPECIES AND SEPAL.LENGTH
iris <- iris[with(iris, order(Species, Sepal.Length)), ]

# RUN A ROW COUNT FOR RANK BY SPECIES GROUP
iris$rank <- sapply(1:nrow(iris), 
                    function(i) sum(iris[1:i, c('Species')]==iris$Species[i]))

# FILTER DATA FRAME BY TOP 3
iris <- iris[iris$rank <= 3,]

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