【问题标题】:Group by a column and sort by another column in R按列分组并按R中的另一列排序
【发布时间】:2016-09-13 12:59:15
【问题描述】:

我正在用 R 检查 kaggle 中的 imdb 电影数据集。

这是一个最小的重现数据集:

> movies <- data.frame(movie = as.factor(c("Movie 1", "Movie 2", "Movie 3", "Movie 4")), director = as.factor(c("Dir 1", "Dir 2", "Dir 1", "Dir 3")), director_rating =  c(1000, 2000, 1000, 3000))

> movies
    movie director director_rating
1 Movie 1    Dir 1            1000
2 Movie 2    Dir 2            2000
3 Movie 3    Dir 1            1000
4 Movie 4    Dir 3            3000

请注意,具有相同导演的每一行都具有相同的导演评级值。

我想列出董事,按评级排序,每个董事一行。以下代码有效:

> library(dplyr)
> movies %>% 
  group_by(director) %>%
  summarize(director_rating = mean(director_rating)) %>%
  arrange(desc(director_rating))

    # A tibble: 3 x 2
  director director_rating
    <fctr>           <dbl>
1    Dir 3            3000
2    Dir 2            2000
3    Dir 1            1000

但是当我知道单个导演的所有评分都相同时,计算平均值似乎很浪费。在 R 中执行此操作的更惯用/有效的方法是什么?

【问题讨论】:

  • 只用first而不是mean返回第一评分?
  • @aichao - 是的,这行得通 - 我忘了 first 在 R 中可用 :-)
  • “具有相同导演的每一行都具有相同的导演评级值”——仅供参考,这是一种糟糕的数据结构方式。您应该有单独的 moviesdirectors 表,并相应地拆分属性。您可能想阅读 Hadley 对“整洁”数据的看法:jstatsoft.org/article/view/v059i10
  • 是的,我同意这一点。在我自己的工作中,我至少会从它们分开开始,只在必要时合并,尽管在你的情况下也可能是这样(只是在这个问题的背景下)。
  • 是的,这可能是真的。通常,我从大约五张表开始(来自各种来源:人口普查、客户、一些第三方……从事经济学工作);然后进行各种合并,根据“单位”(人、地点、公司等)将其分解为一组不同的〜五张表;并且只有在最后一步合并模型需要的东西。我发现它更清晰地捕捉错误和思考模型,并且占用更少的内存。不过,就您而言,您所描述的听起来很合理。您只需要跟踪哪些变量是由哪些其他变量决定的。

标签: r dplyr kaggle


【解决方案1】:

实际上没有必要进行分组和总结,因为您只是在寻找不同/独特的条目。因此,一个 dplyr 选项是:

select(movies, -movie) %>% 
  distinct() %>% 
  arrange(desc(director_rating))
#  director director_rating
#1    Dir 3            3000
#2    Dir 2            2000
#3    Dir 1            1000

或者如果您想保留其他列:

distinct(movies, director, .keep_all = TRUE) %>%   # for dplyr >= 0.5.0
  arrange(desc(director_rating))
#    movie director director_rating
#1 Movie 4    Dir 3            3000
#2 Movie 2    Dir 2            2000
#3 Movie 1    Dir 1            1000

【讨论】:

  • 在 dplyr 0.5.0 中,您的第二种方式不起作用。 distinct 中的默认设置是删除除director 之外的列。得做distinct(movies, director, .keep_all = TRUE) %&gt;% arrange(desc(director_rating))也许我的版本落后了什么的...
  • @Frank 谢谢你。我还没有升级到 0.5
【解决方案2】:

这是一个base R 选项:

unique(movies[,2:3])[order(-unique(movies[,2:3])[,2]),]
#  director director_rating
#4    Dir 3            3000
#2    Dir 2            2000
#1    Dir 1            1000

【讨论】:

  • 总是很好地展示一个基本的 R 替代方案。在这种情况下,您可以考虑将unique(movies[,2:3]) 存储在一个新对象中,这样您就不需要计算两次(在较大数据集的情况下)
【解决方案3】:

我们可以使用data.table

library(data.table)
setDT(movies)[, .(director_rating = director_rating[1]), director][order(-director_rating)]
#    director director_rating
#1:    Dir 3            3000
#2:    Dir 2            2000
#3:    Dir 1            1000

或者使用setorder/unique,其中来自data.tableunique 也有by 选项。

unique(setorder(setDT(movies), -director_rating), by = "director")

【讨论】:

  • 是的,这行得通 - 谢谢。仍然想知道如何以 dplyr 的方式惯用地做到这一点。
  • @Anand 在group_by 步骤之后使用summarise(director_rating = first(director_rating))
猜你喜欢
  • 2014-06-17
  • 1970-01-01
  • 2015-11-21
  • 1970-01-01
  • 2022-01-11
  • 2018-10-23
  • 2020-12-14
  • 2021-05-16
  • 2017-04-01
相关资源
最近更新 更多