Summe mehrerer Spalten, die der Gruppe mit tapply
Wollte ich die Summe der einzelnen Spalten durch die Gruppe und mein Erster Gedanke war der Einsatz von tapply
.
Jedoch, ich kann nicht tapply
zu arbeiten. Kann tapply
verwendet werden, um die Summe mehrerer Spalten?
Wenn nicht, warum nicht?
Suchte ich im internet ausgiebig und fanden zahlreiche ähnliche Fragen gepostet
so weit zurück wie 2008. Jedoch, keiner dieser Fragen wurden direkt beantwortet.
Statt die Antworten immer empfehlen die Verwendung in einer anderen Funktion.
Unten ist ein Beispiel-Datensatz für die ich Wünsche, um die Summe der äpfel durch den Staat, Kirschen vom Staat
und die Pflaumen durch den Staat. Unten, dass ich zusammengestellt haben zahlreiche alternativen, um tapply
dass
arbeiten.
Unten zeige ich eine einfache änderung der tapply
source-code, ermöglicht,
tapply
um den gewünschten Vorgang durchzuführen.
Trotzdem, vielleicht bin ich mit Blick auf eine einfache Weise zu den gewünschten Vorgang durchzuführen
mit tapply
. Ich bin nicht auf der Suche nach alternativen Funktionen, obwohl weitere alternativen sind willkommen.
Angesichts der Einfachheit meiner änderung der tapply
source code ich Frage mich, warum es, oder
etwas ähnliches, noch nicht umgesetzt worden.
Danke für jeden Rat. Falls meine Frage ist eine doppelte, die ich gerne nach meinen
Frage, als eine Antwort auf die andere Frage.
Hier ist das Beispiel-Datensatz:
df.1 <- read.table(text = '
state county apples cherries plums
AA 1 1 2 3
AA 2 10 20 30
AA 3 100 200 300
BB 7 -1 -2 -3
BB 8 -10 -20 -30
BB 9 -100 -200 -300
', header = TRUE, stringsAsFactors = FALSE)
Funktioniert nicht:
tapply(df.1, df.1$state, function(x) {colSums(x[,3:5])})
Den Hilfe-Seiten erklärt:
tapply(X, INDEX, FUN = NULL, ..., simplify = TRUE)
X an atomic object, typically a vector.
Ich war verwirrt durch den Satz typically a vector
was mich Wunder ob
ein Daten-frame verwendet werden könnten. Ich war noch nie klar, was atomic object
bedeutet.
Hier sind mehrere alternativen zu tapply
arbeiten. Die erste alternative ist ein work-around, kombiniert tapply
mit apply
.
apply(df.1[,c(3:5)], 2, function(x) tapply(x, df.1$state, sum))
# apples cherries plums
# AA 111 222 333
# BB -111 -222 -333
with(df.1, aggregate(df.1[,3:5], data.frame(state), sum))
# state apples cherries plums
# 1 AA 111 222 333
# 2 BB -111 -222 -333
t(sapply(split(df.1[,3:5], df.1$state), colSums))
# apples cherries plums
# AA 111 222 333
# BB -111 -222 -333
t(sapply(split(df.1[,3:5], df.1$state), function(x) apply(x, 2, sum)))
# apples cherries plums
# AA 111 222 333
# BB -111 -222 -333
aggregate(df.1[,3:5], by=list(df.1$state), sum)
# Group.1 apples cherries plums
# 1 AA 111 222 333
# 2 BB -111 -222 -333
by(df.1[,3:5], df.1$state, colSums)
# df.1$state: AA
# apples cherries plums
# 111 222 333
# ------------------------------------------------------------
# df.1$state: BB
# apples cherries plums
# -111 -222 -333
with(df.1,
aggregate(x = list(apples = apples,
cherries = cherries,
plums = plums),
by = list(state = state),
FUN = function(x) sum(x)))
# state apples cherries plums
# 1 AA 111 222 333
# 2 BB -111 -222 -333
lapply(split(df.1, df.1$state), function(x) {colSums(x[,3:5])} )
# $AA
# apples cherries plums
# 111 222 333
#
# $BB
# apples cherries plums
# -111 -222 -333
Hier ist der Quellcode für tapply
außer, dass ich geändert habe ist die Zeile:
nx <- length(X)
:
nx <- ifelse(is.vector(X), length(X), dim(X)[1])
Diese modifizierte version der tapply
führt die gewünschte operation:
my.tapply <- function (X, INDEX, FUN = NULL, ..., simplify = TRUE)
{
FUN <- if (!is.null(FUN)) match.fun(FUN)
if (!is.list(INDEX)) INDEX <- list(INDEX)
nI <- length(INDEX)
if (!nI) stop("'INDEX' is of length zero")
namelist <- vector("list", nI)
names(namelist) <- names(INDEX)
extent <- integer(nI)
nx <- ifelse(is.vector(X), length(X), dim(X)[1]) # replaces nx <- length(X)
one <- 1L
group <- rep.int(one, nx) #- to contain the splitting vector
ngroup <- one
for (i in seq_along(INDEX)) {
index <- as.factor(INDEX[[i]])
if (length(index) != nx)
stop("arguments must have same length")
namelist[[i]] <- levels(index)#- all of them, yes !
extent[i] <- nlevels(index)
group <- group + ngroup * (as.integer(index) - one)
ngroup <- ngroup * nlevels(index)
}
if (is.null(FUN)) return(group)
ans <- lapply(X = split(X, group), FUN = FUN, ...)
index <- as.integer(names(ans))
if (simplify && all(unlist(lapply(ans, length)) == 1L)) {
ansmat <- array(dim = extent, dimnames = namelist)
ans <- unlist(ans, recursive = FALSE)
} else {
ansmat <- array(vector("list", prod(extent)),
dim = extent, dimnames = namelist)
}
if(length(index)) {
names(ans) <- NULL
ansmat[index] <- ans
}
ansmat
}
my.tapply(df.1$apples, df.1$state, function(x) {sum(x)})
# AA BB
# 111 -111
my.tapply(df.1[,3:4] , df.1$state, function(x) {colSums(x)})
# $AA
# apples cherries
# 111 222
#
# $BB
# apples cherries
# -111 -222
InformationsquelleAutor der Frage Mark Miller | 2013-07-27
Du musst angemeldet sein, um einen Kommentar abzugeben.
tapply
arbeitet auf einem Vektor, für ein Daten.frame, den Sie verwenden könnenby
(was ist ein wrapper fürtapply
werfen Sie einen Blick auf den code):InformationsquelleAutor der Antwort EDi
Du suchst
by
. Es verwendet dieINDEX
in der Weise, dass Sie davon ausgegangentapply
würde, durch die Reihe.Sich das problem mit dem verwenden von
tapply
ist, dass du die Indizierung derdata.frame
durch Spalte. (Weildata.frame
ist wirklich nur einlist
Spalten). Alsotapply
beschwert, dass der index nicht mit der Länge Ihrerdata.frame
5.InformationsquelleAutor der Antwort nograpes
Sah ich den source code für
by
als EDi vorgeschlagen. Das war der code wesentlich komplexer ist, als mein Wechsel zu der eine Zeile intapply
. Ich habe jetzt festgestellt, dassmy.tapply
funktioniert nicht mit dem komplexeren Szenario unten, woapples
undcherries
werden summiert, indemstate
undcounty
. Wenn ichmy.tapply
arbeiten mit diesem Fall, ich poste den code später hier:InformationsquelleAutor der Antwort Mark Miller