如何按组计算,然后每组只保留一个

时间:2021-03-02 15:21:59

Say that I have this data.frame, data:

假设我有这个data.frame,数据:

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

My goal is to create a new data.frame that has the frequencies of each val, and the associated plus value.

我的目标是创建一个新的data.frame,其中包含每个val的频率和相关的加号值。

My current strategy is to create a table (called table), then merge the frequencies. Then to keep only the first observation within each group:

我目前的策略是创建一个表(称为表),然后合并频率。然后只保留每组中的第一个观察:

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)))

This works, but it seems clunky.

这有效,但看起来很笨重。

In Stata, for example, it would be less and simpler code. Something like:

例如,在Stata中,代码将更简单。就像是:

bys val plus: egen max = _N
bys val plus: gen first = _n==1
keep if first==1

Is there a way to simplify or make more elegant the R code?

有没有办法简化或使R代码更优雅?

2 个解决方案

#1


Here's an approach using "data.table":

这是一种使用“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")

With "dplyr", you can try:

使用“dplyr”,您可以尝试:

library(dplyr)

data %>%
  group_by(val) %>%
  mutate(N = n()) %>%
  slice(1)

In base R, I guess you can try something like:

在基地R,我想你可以尝试类似的东西:

do.call(rbind, lapply(split(data, data$val), 
                      function(x) cbind(x, N = nrow(x))[1, ]))

#2


Edited

Or you can use aggregate()

或者你可以使用aggregate()

data$N = 0
out = aggregate(N ~ val + plus, data = data, length)

or else

out = aggregate(plus ~val, data = data,function(x) c(unique(x), N = length(x)))
do.call(data.frame, out)

or using ddply

或使用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

#1


Here's an approach using "data.table":

这是一种使用“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")

With "dplyr", you can try:

使用“dplyr”,您可以尝试:

library(dplyr)

data %>%
  group_by(val) %>%
  mutate(N = n()) %>%
  slice(1)

In base R, I guess you can try something like:

在基地R,我想你可以尝试类似的东西:

do.call(rbind, lapply(split(data, data$val), 
                      function(x) cbind(x, N = nrow(x))[1, ]))

#2


Edited

Or you can use aggregate()

或者你可以使用aggregate()

data$N = 0
out = aggregate(N ~ val + plus, data = data, length)

or else

out = aggregate(plus ~val, data = data,function(x) c(unique(x), N = length(x)))
do.call(data.frame, out)

or using ddply

或使用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