Dis que j'ai un data.frame
objet:
df <- data.frame(name=c('black','black','black','red','red'),
type=c('chair','chair','sofa','sofa','plate'),
num=c(4,5,12,4,3))
Maintenant, je veux compter le nombre d'observations de pour chaque combinaison de name
et type
. Cela peut être fait comme suit:
table(df[ , c("name","type")])
ou peut-être aussi avec plyr
, (mais je ne sais pas trop comment).
Cependant, comment puis-je obtenir les résultats incorporés dans la trame de données d'origine? Pour que les résultats ressemblent à ceci:
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
où count
stocke désormais les résultats de l'agrégation.
Une solution avec plyr
pourrait également être intéressante à apprendre, bien que j'aimerais voir comment cela se fait avec la base R.
en utilisant plyr
:
plyr::ddply(df, .(name, type), transform, count = length(num))
En utilisant data.table
:
library(data.table)
dt = data.table(df)
# using setkey or setkeyv to set the key
setkeyv(dt, c('name', 'type'))
# self
dt[dt[ , count = length(num), 'name, type']]
MODIFIER (mnel)
En utilisant data.table
la version 1.8.2 ou supérieure a :=
par groupe. Il y a aussi la valeur .N
(introduit la version 1.6.2), qui est le nombre de lignes du groupe), donc c'est aussi simple que
dt[ , count := .N, by = list(name, type)]
en utilisant dplyr
:
library(dplyr)
df %>%
group_by(name, type) %>%
mutate(count = n())
Ou simplement:
add_count(df, name, type)
Vous pouvez utiliser ave
:
df$count <- ave(df$num, df[,c("name","type")], FUN=length)
Tu peux le faire:
> 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
ou peut-être plus intuitivement,
> 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
Cela devrait faire votre travail:
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)
La fonction de base R
aggregate
obtiendra les décomptes avec une ligne, mais en rajoutant ces décomptes à l'original data.frame
semble prendre un peu de traitement.
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
Utilisation de sqldf package:
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
Vous n'étiez qu'à un pas de l'incorporation du nombre de lignes dans l'ensemble de données de base.
À l'aide de la fonction tidy()
du package broom
, convertissez la table de fréquences en un bloc de données et une jointure interne avec 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
Une alternative sur deux lignes consiste à générer une variable de 0, puis à la remplir avec split<-
, split
et lengths
comme ceci:
# 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")]))
Cela renvoie le résultat souhaité
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
Essentiellement, le RHS calcule les longueurs de chaque combinaison nom-type, renvoyant un vecteur nommé de longueur 6 avec 0 pour "red.chair" et "black.plate". Celui-ci est envoyé au LHS avec split <-
Qui prend le vecteur et ajoute de manière appropriée les valeurs à leurs emplacements donnés. C'est essentiellement ce que fait ave
, car vous pouvez voir que la deuxième à la dernière ligne de ave
est
split(x, g) <- lapply(split(x, g), FUN)
Cependant, lengths
est une version optimisée de sapply(list, length)
.