R:分组变量第一次出现的唯一计数
R: Unique count by first occurrence of grouping variable
我想通过分组变量 "ID" 创建一个新变量 "Count",它是因子 "Period" 的唯一值的计数。以下数据包括一列,其中包含我想要的值 "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))
谁能提供正确的函数来使用?
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))
关键步骤是按ID
和Period
排列,然后将Period
的第一个新表示识别为"not duplicated"。
编辑-新答案
现在仔细想想,如果每个组的元素没有组合在一起,我最初的方法将不会 return 正确结果,例如
v <- c(1, 3, 2, 2, 1, 2)
我的函数会将不连续的 1
和 2
放在不同的组中
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))))
旧答案
看起来很适合 GHdata.table
devel 版本的 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))
基于 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
正如 David 所建议的那样,如果数据 Period
不是单调递增,则此解决方案效果不佳。
我想通过分组变量 "ID" 创建一个新变量 "Count",它是因子 "Period" 的唯一值的计数。以下数据包括一列,其中包含我想要的值 "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))
谁能提供正确的函数来使用?
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))
关键步骤是按ID
和Period
排列,然后将Period
的第一个新表示识别为"not duplicated"。
编辑-新答案
现在仔细想想,如果每个组的元素没有组合在一起,我最初的方法将不会 return 正确结果,例如
v <- c(1, 3, 2, 2, 1, 2)
我的函数会将不连续的 1
和 2
放在不同的组中
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))))
旧答案
看起来很适合 GHdata.table
devel 版本的 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))
基于 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
正如 David 所建议的那样,如果数据 Period
不是单调递增,则此解决方案效果不佳。