【问题标题】:Creating groups using data.table使用 data.table 创建组
【发布时间】:2016-04-22 20:43:58
【问题描述】:

工作数据集如下所示:

library('data.table')
df <- data.table(Name = c("a","a","b","b","c","c","d","d","e","e","f","f"),
                 Y = sample(1:30,12),
                 X = sample(1:30,12))

df
    Name  Y  X
 1:    a 14 23
 2:    a 19 18
 3:    b 10 16
 4:    b 23 11
 5:    c  2 12
 6:    c 12 24
 7:    d  8 14
 8:    d 26  2
 9:    e 16 26
10:    e  6  4
11:    f 29 28
12:    f 28 30

我最终想要的是按组制作图表(基于Name)进行比较:

library(ggplot2)
ggplot(df, aes(X, Y)) + geom_point() + facet_grid(. ~ Name)

由于实际数据集包含更多观察结果和grp。我正在创建的 ggplot 需要花费太多时间来处理,并且最终的图表不可读(grp > 300)。我计划用有限数量的观察对数据重新分组并分别绘制图表(例如,每次绘制 10 个组)。

所以最终的数据集应该是这样的:

    Name  Y  X grp level
 1:    a 14 23   1     1
 2:    a 19 18   1     1
 3:    b 10 16   2     1
 4:    b 23 11   2     1
 5:    c  2 12   3     1
 6:    c 12 24   3     1
 7:    d  8 14   4     2
 8:    d 26  2   4     2
 9:    e 16 26   5     2
10:    e  6  4   5     2
11:    f 29 28   6     2
12:    f 28 30   6     2

然后我可以根据新组level进行绘图:

ggplot(df, aes(X, Y)) + geom_point() + facet_grid(. ~ level)

在上图中,我通过以下方式创建了grp

df[, grp := .GRP, by = Name]

现在的问题是如何根据grp自动创建level组(我必须创建grp而不是直接使用Name作为基础,因为在原始数据集中,没有模式Name)?

我尝试了类似的方法:

setkey(df, grp)
i <- 1
j <- 1
while(i < 4 ) {
  df[levels(factor(grp)) == (i:i+2), level := j]
  i <- i + 2
  j <- j + 1
}

它不能很好地满足我的需要。谁能给我一些建议如何解决这个问题?我真的被困在这里了。我想可能有一种简单的方法可以做到这一点,也许我什至不需要创建level 组并且可以通过其他方式直接创建单独的图形?

【问题讨论】:

  • level 只是 grp ?cut 分成 3 个块,对吧?
  • @rawr 是的,我只是举个例子。图中grp有6个层级,我只是想把它减少到2个层级,每个levelgrp中包含1~3个层级。
  • 所以df[, level := as.numeric(cut(grp, breaks = 2))] ?
  • 好吧...它可以按我的意愿工作!想要!我第一次知道cut 命令。如果您想将其作为答案发布,我将为您的答案投票。非常感谢!

标签: r ggplot2 data.table graphing


【解决方案1】:

如果只有几个组,可以使用forcats 包中的fct_collapse() 函数。它允许轻松地将因子级别折叠到手动定义的组中。

通过,这个新变量level 可以直接创建而无需绕行组号和cut()。并且,可以为级别分配有意义的标签。

library('data.table')
df <- data.table(Name = rep(letters[1:6], each = 2),
                 Y = sample(1:30,12),
                 X = sample(1:30,12))
df[, level := forcats::fct_collapse(Name, "a-c" = letters[1:3], "d-e" = letters[4:6])]
df
#    Name  Y  X level
# 1:    a 11 13   a-c
# 2:    a 29 12   a-c
# 3:    b 16  5   a-c
# 4:    b 12  6   a-c
# 5:    c 25 28   a-c
# 6:    c 27 11   a-c
# 7:    d  5  9   d-e
# 8:    d 23 20   d-e
# 9:    e 13 26   d-e
#10:    e 17 19   d-e
#11:    f 19  8   d-e
#12:    f 22  3   d-e

但是,OP提到有很多组 (df[, uniqueN(Name)] &gt; 300) 并且他希望用有限的观察次数重新分组数据。以this comment 中提出的方式使用cut() 可能会导致不满意的结果。

为了证明这一点,我们需要创建一个包含 100 行的更大样本数据集:

N <- 100
set.seed(1234)
df <- data.table(Name = sample(letters, N, replace = TRUE),
                 Y = sample(seq.int(3*N), N),
                 X = sample(seq.int(3*N), N))
df

请注意,set.seed() 用于使数据可重现。

现在,Name(对应于 OP 的 grp)的唯一值的数量被分成 6 个级别并绘制在多个方面(在 this comment 之后):

n_lvls <- 6
df[, level := as.numeric(cut(as.integer(factor(Name)), breaks = n_lvls))] 
ggplot(df, aes(X, Y)) + geom_point() + facet_grid(. ~ level)

在这里,方面 3 只包含几个数据点,而其他方面显得非常拥挤。


为了克服这个问题,可以安排水平以包含大约相同数量的数据点,而不是相同数量的因子水平:

lvls <- df[, .N, by = Name][order(-N), level := cut(cumsum(N), n_lvls, labels = FALSE)]
df <- lvls[df, on = "Name"]

ggplot(df, aes(X, Y)) + geom_point() + facet_grid(. ~ level)

现在,观察结果更均匀地分布在各个方面。

代码计算每个Name 的观察次数,按N 的降序排序,使用cut() 对观察的累积总和创建新级别的data.table lvls。最后,新的层级与原始数据集df右连接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多