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

Schreibe einen Kommentar