Frage

Dies kann als ein typisches plyr Problem sein, aber ich habe etwas anderes im Sinne. Hier ist die Funktion, dass ich optimieren möchten (überspringen Sie die for Schleife).

# dummy data
set.seed(1985)
lst <- list(a=1:10, b=11:15, c=16:20)
m <- matrix(round(runif(200, 1, 7)), 10)
m <- as.data.frame(m)


dfsub <- function(dt, lst, fun) {
    # check whether dt is `data.frame`
    stopifnot (is.data.frame(dt))
    # check if vectors in lst are "whole" / integer
    # vector elements should be column indexes
    is.wholenumber <- function(x, tol = .Machine$double.eps^0.5)  abs(x - round(x)) < tol
    # fall if any non-integers in list
    idx <- rapply(lst, is.wholenumber)
    stopifnot(idx)
    # check for list length
    stopifnot(ncol(dt) == length(idx))
    # subset the data
    subs <- list()
    for (i in 1:length(lst)) {
            # apply function on each part, by row
            subs[[i]] <- apply(dt[ , lst[[i]]], 1, fun)
    }
    # preserve names
    names(subs) <- names(lst)
    # convert to data.frame
    subs <- as.data.frame(subs)
    # guess what =)
    return(subs)
}

Und nun eine kurze Demonstration ... tatsächlich, ich bin zu erklären, was ich in erster Linie zu tun beabsichtigt. Ich wollte einen data.frame von Vektoren in list Objekt gesammelt Teilmenge. Da dies ein Teil des Codes aus einer Funktion, die Datenmanipulation in der psychologischen Forschung begleitet, können Sie m als Ergebnisse von Persönlichkeit Fragebogen betrachten (10 Probanden, 20 VARs). Vektoren in der Liste halten Spalte Indizes, die Fragebogen subscales definieren (zum Beispiel Persönlichkeitsmerkmale). Jede Subskala wird durch mehrere Elemente (Spalten in data.frame) definiert. Wenn wir, dass die Punktzahl auf jeder Subskala voraus ist nichts anderes als sum (oder eine andere Funktion) von Zeilenwerten (Ergebnisse auf diesem Teil des Fragebogens für jedes Fach), könnten Sie laufen:

> dfsub(m, lst, sum)
    a  b  c
1  46 20 24
2  41 24 21
3  41 13 12
4  37 14 18
5  57 18 25
6  27 18 18
7  28 17 20
8  31 18 23
9  38 14 15
10 41 14 22

habe ich einen Blick auf diese Funktion und ich muss zugeben, dass dieser kleine Schleife den Code überhaupt nicht zu verderben ... ABER, wenn es eine einfachere / effiziente Art und Weise, dies zu tun, bitte, lass es mich wissen!

War es hilfreich?

Lösung

würde ich einen anderen Ansatz und alles als Datenrahmen halten, so dass Sie merge und ddply verwenden können. Ich denke, Sie finden diese Vorgehensweise ein wenig allgemeiner ist, und es ist einfacher, zu überprüfen, dass jeder Schritt korrekt durchgeführt wird.

# Convert everything to long data frames
m$id <- 1:nrow(m)

library(reshape)
obs <- melt(m, id = "id")
obs$variable <- as.numeric(gsub("V", "", obs$variable))

varinfo <- melt(lst)
names(varinfo) <- c("variable", "scale")

# Merge and summarise
obs <- merge(obs, varinfo, by = "variable")

ddply(obs, c("id", "scale"), summarise, 
  mean = mean(value), 
  sum = sum(value))

Andere Tipps

nach dem plyr Paket laden, ersetzen

subs <- list()
    for (i in 1:length(lst)) {
            # apply function on each part, by row
            subs[[i]] <- apply(dt[ , lst[[i]]], 1, fun)
    }

mit

subs <- llply(lst,function(x) apply(dt[,x],1,fun))

@Hadley, ich habe Ihre Antwort überprüft, da es recht einfach ist und leicht für die Buchhaltung (neben der Tatsache, es ist mehr Allzweck-Lösung). Aber hier ist mein nicht so lange Skript, das die Sache tut und erfordert nur base Paket (das ist trivial, da ich plyr und reshape nur nach R Installation installieren). Nun, hier ist die Quelle:

dfsub <- function(dt, lst, fun) {
        # check whether dt is `data.frame`
        stopifnot (is.data.frame(dt))
        # convert data.frame factors to numeric
        dt <- as.data.frame(lapply(dt, as.numeric))
        # check if vectors in lst are "whole" / integer
        # vector elements should be column indexes
        is.wholenumber <- function(x, tol = .Machine$double.eps^0.5)  abs(x - round(x)) < tol
        # fall if any non-integers in list
        idx <- rapply(lst, is.wholenumber)
        stopifnot(idx)
        # check for list length
        stopifnot(ncol(dt) == length(idx))
        # subset the data
        subs <- list()
        for (i in 1:length(lst)) {
                # apply function on each part, by row
                subs[[i]] <- apply(dt[ , lst[[i]]], 1, fun)
        }
        names(subs) <- names(lst)
        # convert to data.frame
        subs <- as.data.frame(subs)
        # guess what =)
        return(subs)
}

Für Ihr spezielles Beispiel eine einzeilige Lösung ist sapply(lst,function(x) rowSums(m[,x])) (obwohl einige weiteren Zeilen hinzufügen möchte für gültige Eingabe zu überprüfen und in den Spaltennamen setzen).

Haben Sie andere haben, allgemeinere Anwendungen im Sinn? Oder ist dies möglicherweise ein Fall von YAGNI ?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top