#r #count #aggregate
#r #граф #агрегировать #r-часто задаваемые вопросы
Вопрос:
Допустим, у меня есть data.frame
объект:
df <- data.frame(name=c('black','black','black','red','red'),
type=c('chair','chair','sofa','sofa','plate'),
num=c(4,5,12,4,3))
Теперь я хочу подсчитать количество строк (наблюдений) для каждой комбинации name
и type
. Это можно сделать следующим образом:
table(df[ , c("name","type")])
или, возможно, также с plyr
, (хотя я не уверен, как именно).
Однако как мне получить результаты, включенные в исходный фрейм данных? Так что результаты будут выглядеть примерно так:
df
# name type num count
# 1 black chair 4 2
# 2 black chair 5 2
# 3 black sofa 12 1
# 4 red sofa 4 1
# 5 red plate 3 1
где count
теперь хранятся результаты агрегирования.
Решение с plyr
помощью которого также может быть интересно изучить, хотя я хотел бы посмотреть, как это делается с помощью base R.
Ответ №1:
Использование data.table
:
library(data.table)
dt = as.data.table(df)
# or coerce to data.table by reference:
# setDT(df)
dt[ , count := .N, by = .(name, type)]
Информацию о предварительной data.table 1.8.2
альтернативе см. в разделе История изменений.
Использование dplyr
:
library(dplyr)
df %>%
group_by(name, type) %>%
mutate(count = n())
Или просто:
add_count(df, name, type)
Использование plyr
:
plyr::ddply(df, .(name, type), transform, count = length(num))
Комментарии:
1. Вам нужен «setkeyv(dt, c(‘name’, ‘type’))»?
Ответ №2:
Вы можете использовать ave
:
df$count <- ave(df$num, df[,c("name","type")], FUN=length)
Комментарии:
1. Также можно было бы сделать это немного чище, возможно, используя
transform(df, count = ave(num, name, type, FUN = length))
илиwith
2. Если у вас много данных , эта команда выполняется ОЧЕНЬ МЕДЛЕННО
Ответ №3:
Вы можете сделать это:
> ddply(df,.(name,type),transform,count = NROW(piece))
name type num count
1 black chair 4 2
2 black chair 5 2
3 black sofa 12 1
4 red plate 3 1
5 red sofa 4 1
или, возможно, более интуитивно,
> ddply(df,.(name,type),transform,count = length(num))
name type num count
1 black chair 4 2
2 black chair 5 2
3 black sofa 12 1
4 red plate 3 1
5 red sofa 4 1
Ответ №4:
Это должно выполнить вашу работу :
df_agg <- aggregate(num~name type,df,FUN=NROW)
names(df_agg)[3] <- "count"
df <- merge(df,df_agg,by=c('name','type'),all.x=TRUE)
Ответ №5:
Базовая R
функция aggregate
получит подсчеты с помощью однострочной строки, но добавление этих подсчетов обратно к оригиналу data.frame
, по-видимому, требует некоторой обработки.
df <- data.frame(name=c('black','black','black','red','red'),
type=c('chair','chair','sofa','sofa','plate'),
num=c(4,5,12,4,3))
df
# name type num
# 1 black chair 4
# 2 black chair 5
# 3 black sofa 12
# 4 red sofa 4
# 5 red plate 3
rows.per.group <- aggregate(rep(1, length(paste0(df$name, df$type))),
by=list(df$name, df$type), sum)
rows.per.group
# Group.1 Group.2 x
# 1 black chair 2
# 2 red plate 1
# 3 black sofa 1
# 4 red sofa 1
my.summary <- do.call(data.frame, rows.per.group)
colnames(my.summary) <- c(colnames(df)[1:2], 'rows.per.group')
my.data <- merge(df, my.summary, by = c(colnames(df)[1:2]))
my.data
# name type num rows.per.group
# 1 black chair 4 2
# 2 black chair 5 2
# 3 black sofa 12 1
# 4 red plate 3 1
# 5 red sofa 4 1
Ответ №6:
Использование пакета sqldf:
library(sqldf)
sqldf("select a.*, b.cnt
from df a,
(select name, type, count(1) as cnt
from df
group by name, type) b
where a.name = b.name and
a.type = b.type")
# name type num cnt
# 1 black chair 4 2
# 2 black chair 5 2
# 3 black sofa 12 1
# 4 red sofa 4 1
# 5 red plate 3 1
Ответ №7:
Альтернативой из двух строк является создание переменной, равной 0s, а затем заполнение ее с split<-
помощью , split
, и lengths
вот так:
# generate vector of 0s
df$count <-0L
# fill it in
split(df$count, df[c("name", "type")]) <- lengths(split(df$num, df[c("name", "type")]))
Это возвращает желаемый результат
df
name type num count
1 black chair 4 2
2 black chair 5 2
3 black sofa 12 1
4 red sofa 4 1
5 red plate 3 1
По сути, RHS вычисляет длины каждой комбинации типов имен, возвращая именованный вектор длиной 6 с 0 для «red.chair» и «black.plate». Это передается в LHS, с split <-
помощью которого берется вектор и соответствующим образом добавляются значения в заданных местах. Это, по сути, то, что ave
делает, поскольку вы можете видеть, что предпоследняя строка ave
split(x, g) <- lapply(split(x, g), FUN)
Тем не менее, lengths
это оптимизированная версия sapply(list, length)
.
Ответ №8:
Вы были всего в одном шаге от включения количества строк в базовый набор данных.
Используя tidy()
функцию из broom
пакета, преобразуйте таблицу частот в фрейм данных и внутреннее соединение с df
:
df <- data.frame(name=c('black','black','black','red','red'),
type=c('chair','chair','sofa','sofa','plate'),
num=c(4,5,12,4,3))
library(broom)
df <- merge(df, tidy(table(df[ , c("name","type")])), by=c("name","type"))
df
name type num Freq
1 black chair 4 2
2 black chair 5 2
3 black sofa 12 1
4 red plate 3 1
5 red sofa 4 1
Ответ №9:
Одна простая строка в базе R:
df$count = table(interaction(df[, (c("name", "type"))]))[interaction(df[, (c("name", "type"))])]
То же самое в двух строках, для ясности / эффективности:
fact = interaction(df[, (c("name", "type"))])
df$count = table(fact)[fact]
Ответ №10:
Другой вариант с использованием add_tally from dplyr
. Вот воспроизводимый пример:
df <- data.frame(name=c('black','black','black','red','red'),
type=c('chair','chair','sofa','sofa','plate'),
num=c(4,5,12,4,3))
library(dplyr)
df %>%
group_by(name, type) %>%
add_tally(name = "count")
#> # A tibble: 5 × 4
#> # Groups: name, type [4]
#> name type num count
#> <chr> <chr> <dbl> <int>
#> 1 black chair 4 2
#> 2 black chair 5 2
#> 3 black sofa 12 1
#> 4 red sofa 4 1
#> 5 red plate 3 1
Создано 2022-09-11 с помощью reprex v2.0.2
Ответ №11:
Другой способ, который обобщает больше:
df$count <- unsplit(lapply(split(df, df[c("name","type")]), nrow), df[c("name","type")])
Комментарии:
1. Пожалуйста, объясните, как это обобщает больше?