R:首次出现分组变量的唯一计数

时间:2015-08-18 19:41:14

标签: r plyr

我想创建一个新变量“Count”,它是一个因子“Period”的唯一值的计数,通过对变量“ID”进行分组。以下数据包括一个列,其中包含我想要的值“Count”:

structure(list(ID = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L
), .Label = c("a", "b"), class = "factor"), Period = c(1.1, 1.1, 
1.2, 1.3, 1.2, 1.3, 1.5, 1.5), Count = c(1L, 1L, 2L, 3L, 1L, 
2L, 3L, 3L)), .Names = c("ID", "Period", "Count"), class = "data.frame", row.names = c(NA, 
-8L))

我尝试将mutate与Count = 1:length(Period)一起使用,但它创建了“Period”的每个值的累积计数,而我想要的累积计数仅为唯一值。这就是我试过的:

library(plyr)
samp1<-ddply(samp, .(ID, Period), mutate, Count = 1:length(Period))

有人能提供正确的功能吗?

3 个答案:

答案 0 :(得分:6)

编辑 - 新答案

现在再考虑一下,如果每个组元素没有组合在一起,我的初始方法不会返回正确的结果,例如

v <- c(1, 3, 2, 2, 1, 2)

我的功能会将非连续的12放在不同的组

myrleid(v)
## [1] 1 2 3 3 4 5

因此,最佳方法似乎是

match(v, unique(v))
## [1] 1 2 3 3 1 3

保留外观顺序保持同一组中的未排序值

因此,我建议只做

library(data.table)
setDT(df)[, Count2 := match(Period, unique(Period)), by = ID]

或(与基地R)

with(df, ave(Period, ID, FUN = function(x) match(x, unique(x))))

旧答案

data.table devel版GH上看rleid函数的合适人选

### Devel version installation instructions
# library(devtools)
# install_github("Rdatatable/data.table", build_vignettes = FALSE)

library(data.table) # v 1.9.5+
setDT(df)[, Count2 := rleid(Period), by = ID]
df
#    ID Period Count Count2
# 1:  a    1.1     1      1
# 2:  a    1.1     1      1
# 3:  a    1.2     2      2
# 4:  a    1.3     3      3
# 5:  b    1.2     1      1
# 6:  b    1.3     2      2
# 7:  b    1.5     3      3
# 8:  b    1.5     3      3

或者,如果您不想加载外部包,我们可以自己定义此功能

myrleid <- function(x) {
  temp <- rle(x)$lengths 
  rep.int(seq_along(temp), temp)
}

with(df, ave(Period, ID, FUN = myrleid))
## [1] 1 1 2 3 1 2 3 3

或者,如果这些组的顺序递增,您也可以尝试对它们进行排名

library(data.table) ## V1.9.5+
setDT(df)[, Count2 := frank(Period, ties.method = "dense"), by = ID]

或者

library(dplyr)
df %>% 
   group_by(ID) %>% 
   mutate(Count2 = dense_rank(Period))

答案 1 :(得分:1)

samp <- structure(list(ID = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L
), .Label = c("a", "b"), class = "factor"), Period = c(1.1, 1.1, 
1.2, 1.3, 1.2, 1.3, 1.5, 1.5), Count = c(1L, 1L, 2L, 3L, 1L, 
2L, 3L, 3L)), .Names = c("ID", "Period", "Count"), class = "data.frame", row.names = c(NA, 
-8L))

select(samp, -Count) %>%
  arrange(ID, Period) %>%
  group_by(ID) %>%
  mutate(dup = !duplicated(Period),
         Count = cumsum(dup))

关键步骤是按IDPeriod排列,然后将Period的第一个新表示标识为“不重复”。

答案 2 :(得分:1)

基础R中的transform

的解决方案
transform(df, Count2 =  unlist(
                               tapply(df$Period, df$ID, function(x)       
                                       as.numeric(factor(x))) 
                              ))

   ID Period Count Count2
a1  a    1.1     1      1
a2  a    1.1     1      1
a3  a    1.2     2      2
a4  a    1.3     3      3
b1  b    1.2     1      1
b2  b    1.3     2      2
b3  b    1.5     3      3
b4  b    1.5     3      3

正如大卫所说,如果数据Period不是单调增加的话,这个解决方案就不能正常工作。