如何按组计算计数,然后每组只保留一个
How to calculate count by group, then keep only one per group
说我有这个 data.frame, data
:
data <- data.frame(val=c(rep(6,10), rep(7, 15), rep(8, 20), rep(9, 25), rep(10, 100), rep(11, 20), rep(12, 15), rep(13, 10)))
data$plus <- data$val + 100
我的目标是创建一个新的 data.frame
,其中包含每个 val
的频率以及关联的 plus
值。
我目前的策略是创建一个table(称为table
),然后合并频率。然后只保留每组中的第一个观察值:
table <- table(data$val)
df1 <- data.frame(val = as.integer(names(table)[1:length(table)]), N = table[1:length(table)])
df2 <- merge(data, df1)
df3 <- do.call(rbind, by(df2, list(df2$val), FUN=function(x) head(x, 1)))
这行得通,但看起来很笨重。
例如,在 Stata 中,代码会更少、更简单。类似于:
bys val plus: egen max = _N
bys val plus: gen first = _n==1
keep if first==1
有没有办法简化或使 R 代码更优雅?
这是一种使用 "data.table" 的方法:
library(data.table)
as.data.table(data)[, N := .N, by = val][, .SD[1], by = val]
# val plus N
# 1: 6 106 10
# 2: 7 107 15
# 3: 8 108 20
# 4: 9 109 25
# 5: 10 110 100
# 6: 11 111 20
# 7: 12 112 15
# 8: 13 113 10
## Or (@RicardoSaporta)
as.data.table(data)[, list(.N, plus=plus[1]), by = val]
## Or (@DavidArenburg)
unique(as.data.table(data)[, N := .N, by = val], by = "val")
有了"dplyr",你可以试试:
library(dplyr)
data %>%
group_by(val) %>%
mutate(N = n()) %>%
slice(1)
在 base R 中,我想你可以尝试类似的东西:
do.call(rbind, lapply(split(data, data$val),
function(x) cbind(x, N = nrow(x))[1, ]))
已编辑
或者您可以使用 aggregate()
data$N = 0
out = aggregate(N ~ val + plus, data = data, length)
否则
out = aggregate(plus ~val, data = data,function(x) c(unique(x), N = length(x)))
do.call(data.frame, out)
或使用ddply
library(plyr)
out = ddply(data, .(val,plus), summarize, N = length(plus))
#> out
# val plus N
#1 6 106 10
#2 7 107 15
#3 8 108 20
#4 9 109 25
#5 10 110 100
#6 11 111 20
#7 12 112 15
#8 13 113 10
说我有这个 data.frame, data
:
data <- data.frame(val=c(rep(6,10), rep(7, 15), rep(8, 20), rep(9, 25), rep(10, 100), rep(11, 20), rep(12, 15), rep(13, 10)))
data$plus <- data$val + 100
我的目标是创建一个新的 data.frame
,其中包含每个 val
的频率以及关联的 plus
值。
我目前的策略是创建一个table(称为table
),然后合并频率。然后只保留每组中的第一个观察值:
table <- table(data$val)
df1 <- data.frame(val = as.integer(names(table)[1:length(table)]), N = table[1:length(table)])
df2 <- merge(data, df1)
df3 <- do.call(rbind, by(df2, list(df2$val), FUN=function(x) head(x, 1)))
这行得通,但看起来很笨重。
例如,在 Stata 中,代码会更少、更简单。类似于:
bys val plus: egen max = _N
bys val plus: gen first = _n==1
keep if first==1
有没有办法简化或使 R 代码更优雅?
这是一种使用 "data.table" 的方法:
library(data.table)
as.data.table(data)[, N := .N, by = val][, .SD[1], by = val]
# val plus N
# 1: 6 106 10
# 2: 7 107 15
# 3: 8 108 20
# 4: 9 109 25
# 5: 10 110 100
# 6: 11 111 20
# 7: 12 112 15
# 8: 13 113 10
## Or (@RicardoSaporta)
as.data.table(data)[, list(.N, plus=plus[1]), by = val]
## Or (@DavidArenburg)
unique(as.data.table(data)[, N := .N, by = val], by = "val")
有了"dplyr",你可以试试:
library(dplyr)
data %>%
group_by(val) %>%
mutate(N = n()) %>%
slice(1)
在 base R 中,我想你可以尝试类似的东西:
do.call(rbind, lapply(split(data, data$val),
function(x) cbind(x, N = nrow(x))[1, ]))
已编辑
或者您可以使用 aggregate()
data$N = 0
out = aggregate(N ~ val + plus, data = data, length)
否则
out = aggregate(plus ~val, data = data,function(x) c(unique(x), N = length(x)))
do.call(data.frame, out)
或使用ddply
library(plyr)
out = ddply(data, .(val,plus), summarize, N = length(plus))
#> out
# val plus N
#1 6 106 10
#2 7 107 15
#3 8 108 20
#4 9 109 25
#5 10 110 100
#6 11 111 20
#7 12 112 15
#8 13 113 10