按组添加唯一/不同值的计数到原始数据

87

我希望通过对第二个变量进行分组来计算唯一值的数量,然后将计数添加到现有的数据框中作为新列。例如,如果现有的数据框看起来像这样:

  color  type
1 black chair
2 black chair
3 black  sofa
4 green  sofa
5 green  sofa
6   red  sofa
7   red plate
8  blue  sofa
9  blue plate
10 blue chair

我希望能够为每种颜色添加独特类型的数量,这些类型都存在于数据中:

  color  type unique_types
1 black chair            2
2 black chair            2
3 black  sofa            2
4 green  sofa            1
5 green  sofa            1
6   red  sofa            2
7   red plate            2
8  blue  sofa            3
9  blue plate            3
10 blue chair            3

我希望能够使用ave,但似乎找不到不需要多行代码的简单方法。我的数据有超过10万行,所以我不确定效率有多重要。

这与以下问题有些类似:计算每个组的观测/行数并将结果添加到数据框中

3个回答

88

这里提供了一个用dplyr包的解决方案 - 它有一个n_distinct()函数作为length(unique())的封装。

df %>%
  group_by(color) %>%
  mutate(unique_types = n_distinct(type))

1
感谢你的dplyr解决方案,Sam。假设我想进一步“子集”df,只包括“颜色”和“相应的不同类型数量”。我记得有一个很棒的函数可以实现这些,但我想不起来了,你有什么建议吗? - Prince M

80

使用ave(因为您特别要求):

within(df, { count <- ave(type, color, FUN=function(x) length(unique(x)))})

请确保type是字符向量而不是因子。


由于您说数据很大,速度/性能可能成为一个因素,我建议使用data.table解决方案。

require(data.table)
setDT(df)[, count := uniqueN(type), by = color] # v1.9.6+
# if you don't want df to be modified by reference
ans = as.data.table(df)[, count := uniqueN(type), by = color]

uniqueN是在v1.9.6中实现的,它是length(unique(.))的更快等效版本。此外,它还适用于数据框和数据表。


其他解决方案:

使用plyr:

require(plyr)
ddply(df, .(color), mutate, count = length(unique(type)))

使用 aggregate

agg <- aggregate(data=df, type ~ color, function(x) length(unique(x)))
merge(df, agg, by="color", all=TRUE)

1
plyr 版本中使用 length(unique(type)) 只有在没有 NA 值的情况下才等同于 data.table::uniqueN(type)。对于空组,uniqueN 将报告 0,而 length(unique(type)) 将报告 1!dplyr(不确定 plyr)中 data.table::uniqueN(x, na.rm = TRUE) 的等效方法是 dplyr::n_distinct(x, na.rm = TRUE) - Daniel

9

通过将uniquetabletabulate结合使用,可以在不进行分组操作的情况下实现向量化。

如果df$colorfactor类型,则:

要么

table(unique(df)$color)[as.character(df$color)]
# black black black green green   red   red  blue  blue  blue 
#    2     2     2     1     1     2     2     3     3     3 

或者
tabulate(unique(df)$color)[as.integer(df$color)]
# [1] 2 2 2 1 1 2 2 3 3 3

如果df$colorcharacter类型,则只需
table(unique(df)$color)[df$color]

如果 df$color 是一个 整数(integer),那就直接…
tabulate(unique(df)$color)[df$color]

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