Ik heb een data.frame
en ik moet het gemiddelde per groep berekenen (d.w.z. per Month
, hieronder).
Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32
Mijn gewenste output is zoals hieronder, waarbij de waarden voor Rate1
en Rate2
de groepsgemiddelden zijn. Negeer de waarde, ik heb het verzonnen voor het voorbeeld.
Name Rate1 Rate2
Aira 23.21 12.2
Ben 45.23 43.9
Cat 33.22 32.2
Antwoord 1, autoriteit 100%
Dit type bewerking is precies waarvoor aggregate
is ontworpen:
d <- read.table(text=
'Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32', header=TRUE)
aggregate(d[, 3:4], list(d$Name), mean)
Group.1 Rate1 Rate2
1 Aira 16.33333 47.00000
2 Ben 31.33333 50.33333
3 Cat 44.66667 54.00000
Hier voegen we kolommen 3 en 4 van data.frame d
samen, groeperen we op d$Name
en passen we de functie mean
toe.
Of, met behulp van een formule-interface:
aggregate(. ~ Name, d[-2], mean)
Antwoord 2, autoriteit 23%
Of gebruik group_by
& summarise_at
van de dplyr
pakket:
library(dplyr)
d %>%
group_by(Name) %>%
summarise_at(vars(-Month), funs(mean(., na.rm=TRUE)))
# A tibble: 3 x 3
Name Rate1 Rate2
<fct> <dbl> <dbl>
1 Aira 16.3 47.0
2 Ben 31.3 50.3
3 Cat 44.7 54.0
Zie ?summarise_at
voor de vele manieren om de variabelen te specificeren waarop moet worden gereageerd. Hier zegt vars(-Month)
alle variabelen behalveMonth
.
Antwoord 3, autoriteit 14%
Je kunt ook het pakket plyr
gebruiken, dat op de een of andere manier veelzijdiger is:
library(plyr)
ddply(d, .(Name), summarize, Rate1=mean(Rate1), Rate2=mean(Rate2))
Name Rate1 Rate2
1 Aira 16.33333 47.00000
2 Ben 31.33333 50.33333
3 Cat 44.66667 54.00000
Antwoord 4, autoriteit 7%
Een derde geweldig alternatief is het gebruik van het pakket data.table
, dat ook de klasse data.frame heeft, maar bewerkingen zoals u zoekt, worden veel sneller berekend.
library(data.table)
mydt <- structure(list(Name = c("Aira", "Aira", "Aira", "Ben", "Ben", "Ben", "Cat", "Cat", "Cat"), Month = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Rate1 = c(15.6396600443877, 2.15649279424609, 6.24692918928743, 2.37658797276116, 34.7500663272292, 3.28750138697048, 29.3265553981065, 17.9821839334431, 10.8639802575958), Rate2 = c(17.1680489538369, 5.84231656330206, 8.54330866437461, 5.88415184986176, 3.02064294862551, 17.2053351400752, 16.9552950199166, 2.56058000170089, 15.7496228048122)), .Names = c("Name", "Month", "Rate1", "Rate2"), row.names = c(NA, -9L), class = c("data.table", "data.frame"))
Nu om het gemiddelde van tarief1 en prijs te nemen2 voor alle 3 maanden, voor elke persoon (naam):
Bepaal eerst welke kolommen u het gemiddelde van
wilt nemen
colstoavg <- names(mydt)[3:4]
Nu gebruiken we LAPPLY om het gemiddelde te nemen over de kolommen die we willen (Colstoavg)
mydt.mean <- mydt[,lapply(.SD,mean,na.rm=TRUE),by=Name,.SDcols=colstoavg]
mydt.mean
Name Rate1 Rate2
1: Aira 8.014361 10.517891
2: Ben 13.471385 8.703377
3: Cat 19.390907 11.755166
Antwoord 5, Autoriteit 3%
Hier zijn verschillende manieren om dit in de basis te doen R
inclusief een alternatief aggregate
Applate. De voorbeelden onder Retourmiddelen per maand, waarvan ik denk dat het is wat u heeft aangevraagd. Hoewel, dezelfde aanpak kan worden gebruikt om middel per persoon terug te keren:
met ave
:
my.data <- read.table(text = '
Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
Rate1.mean <- with(my.data, ave(Rate1, Month, FUN = function(x) mean(x, na.rm = TRUE)))
Rate2.mean <- with(my.data, ave(Rate2, Month, FUN = function(x) mean(x, na.rm = TRUE)))
my.data <- data.frame(my.data, Rate1.mean, Rate2.mean)
my.data
Gebruik by
:
my.data <- read.table(text = '
Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
by.month <- as.data.frame(do.call("rbind", by(my.data, my.data$Month, FUN = function(x) colMeans(x[,3:4]))))
colnames(by.month) <- c('Rate1.mean', 'Rate2.mean')
by.month <- cbind(Month = rownames(by.month), by.month)
my.data <- merge(my.data, by.month, by = 'Month')
my.data
Gebruik lapply
en split
:
my.data <- read.table(text = '
Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
ly.mean <- lapply(split(my.data, my.data$Month), function(x) c(Mean = colMeans(x[,3:4])))
ly.mean <- as.data.frame(do.call("rbind", ly.mean))
ly.mean <- cbind(Month = rownames(ly.mean), ly.mean)
my.data <- merge(my.data, ly.mean, by = 'Month')
my.data
met sapply
en split
:
my.data <- read.table(text = '
Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
my.data
sy.mean <- t(sapply(split(my.data, my.data$Month), function(x) colMeans(x[,3:4])))
colnames(sy.mean) <- c('Rate1.mean', 'Rate2.mean')
sy.mean <- data.frame(Month = rownames(sy.mean), sy.mean, stringsAsFactors = FALSE)
my.data <- merge(my.data, sy.mean, by = 'Month')
my.data
Gebruik aggregate
:
my.data <- read.table(text = '
Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
my.summary <- with(my.data, aggregate(list(Rate1, Rate2), by = list(Month),
FUN = function(x) { mon.mean = mean(x, na.rm = TRUE) } ))
my.summary <- do.call(data.frame, my.summary)
colnames(my.summary) <- c('Month', 'Rate1.mean', 'Rate2.mean')
my.summary
my.data <- merge(my.data, my.summary, by = 'Month')
my.data
EDIT: 28 juni 2020
Hier gebruik ik aggregate
om de kolom te verkrijgen means
van een volledige matrix
per groep waar groep wordt gedefinieerd in een externe vector
:
my.group <- c(1,2,1,2,2,3,1,2,3,3)
my.data <- matrix(c( 1, 2, 3, 4, 5,
10, 20, 30, 40, 50,
2, 4, 6, 8, 10,
20, 30, 40, 50, 60,
20, 18, 16, 14, 12,
1000, 1100, 1200, 1300, 1400,
2, 3, 4, 3, 2,
50, 40, 30, 20, 10,
1001, 2001, 3001, 4001, 5001,
1000, 2000, 3000, 4000, 5000), nrow = 10, ncol = 5, byrow = TRUE)
my.data
my.summary <- aggregate(list(my.data), by = list(my.group), FUN = function(x) { my.mean = mean(x, na.rm = TRUE) } )
my.summary
# Group.1 X1 X2 X3 X4 X5
#1 1 1.666667 3.000 4.333333 5.000 5.666667
#2 2 25.000000 27.000 29.000000 31.000 33.000000
#3 3 1000.333333 1700.333 2400.333333 3100.333 3800.333333
Antwoord 6, Autoriteit 3%
Ik beschrijf twee manieren om dit te doen, een op basis van data.tableen de andere op basis van het pakket reshape2. De data.table-manier heeft al een antwoord, maar ik heb geprobeerd het schoner en gedetailleerder te maken.
De gegevens zijn als volgt:
d <- structure(list(Name = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L,
3L, 3L), .Label = c("Aira", "Ben", "Cat"), class = "factor"),
Month = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Rate1 = c(12L,
18L, 19L, 53L, 22L, 19L, 22L, 67L, 45L), Rate2 = c(23L, 73L,
45L, 19L, 87L, 45L, 87L, 43L, 32L)), .Names = c("Name", "Month",
"Rate1", "Rate2"), class = "data.frame", row.names = c(NA, -9L
))
head(d)
Name Month Rate1 Rate2
1 Aira 1 12 23
2 Aira 2 18 73
3 Aira 3 19 45
4 Ben 1 53 19
5 Ben 2 22 87
6 Ben 3 19 45
library("reshape2")
mym <- melt(d, id = c("Name"))
res <- dcast(mym, Name ~ variable, mean)
res
#Name Month Rate1 Rate2
#1 Aira 2 16.33333 47.00000
#2 Ben 2 31.33333 50.33333
#3 Cat 2 44.66667 54.00000
Data.table gebruiken:
# At first, I convert the data.frame to data.table and then I group it
setDT(d)
d[, .(Rate1 = mean(Rate1), Rate2 = mean(Rate2)), by = .(Name)]
# Name Rate1 Rate2
#1: Aira 16.33333 47.00000
#2: Ben 31.33333 50.33333
#3: Cat 44.66667 54.00000
Er is een andere manier om dit te doen door te vermijden veel argumenten voor j in data.table te schrijven met een .SD
d[, lapply(.SD, mean), by = .(Name)]
# Name Month Rate1 Rate2
#1: Aira 2 16.33333 47.00000
#2: Ben 2 31.33333 50.33333
#3: Cat 2 44.66667 54.00000
Als we alleen Rate1 en Rate2 willen hebben, kunnen we de .SDcolsals volgt gebruiken:
d[, lapply(.SD, mean), by = .(Name), .SDcols = 3:4]
# Name Rate1 Rate2
#1: Aira 16.33333 47.00000
#2: Ben 31.33333 50.33333
#3: Cat 44.66667 54.00000
Antwoord 7, autoriteit 2%
Je zou ook de generieke functie cbind()
en lm()
kunnen gebruiken zonder het intercept:
cbind(lm(d$Rate1~-1+d$Name)$coef,lm(d$Rate2~-1+d$Name)$coef)
> [,1] [,2]
>d$NameAira 16.33333 47.00000
>d$NameBen 31.33333 50.33333
>d$NameCat 44.66667 54.00000
Antwoord 8, autoriteit 2%
U kunt dit ook bereiken met behulp van het sqldf
pakket zoals hieronder getoond:
library(sqldf)
x <- read.table(text='Name Month Rate1 Rate2
Aira 1 12 23
Aira 2 18 73
Aira 3 19 45
Ben 1 53 19
Ben 2 22 87
Ben 3 19 45
Cat 1 22 87
Cat 2 67 43
Cat 3 45 32', header=TRUE)
sqldf("
select
Name
,avg(Rate1) as Rate1_float
,avg(Rate2) as Rate2_float
,avg(Rate1) as Rate1
,avg(Rate2) as Rate2
from x
group by
Name
")
# Name Rate1_float Rate2_float Rate1 Rate2
#1 Aira 16.33333 47.00000 16 47
#2 Ben 31.33333 50.33333 31 50
#3 Cat 44.66667 54.00000 44 54
Ik ben een recente bekeerling naar dplyr
zoals getoond in andere antwoorden, maar sqldf
is leuk omdat de meeste data-analisten/datawetenschappers/ontwikkelaars op zijn minst enige kennis van SQL hebben . Op deze manier denk ik dat het zorgt voor meer universeel leesbare code dan dplyr
of andere oplossingen die hierboven zijn gepresenteerd.
UPDATE:in reactie op de onderstaande opmerking heb ik geprobeerd de code bij te werken zoals hierboven weergegeven. Het gedrag was echter niet zoals ik had verwacht. Het lijkt erop dat de kolomdefinitie (d.w.z. int
vs float
) alleen wordt doorgevoerd als de kolomalias overeenkomt met de oorspronkelijke kolomnaam. Wanneer u een nieuwe naam opgeeft, wordt de aggregatiekolom geretourneerd zonder afronding.