2016-12-24 5 views
3

Ich habe die folgende Funktion:sapply auf data.frame vs Vektor (COLNAMES, rownames)

func <- function(scores, labels, thresholds) { 
    labels <- if (is.data.frame(labels)) labels else data.frame(labels) 
    sapply(thresholds, function(t) { sapply(labels, function(lbl) { sum(lbl[which(scores >= t)]) }) }) 
} 

Ich habe auch die folgenden, dass ich in func bestehen werden.

> scores 
[1] 0.187 0.975 0.566 0.793 0.524 0.481 0.005 0.756 0.062 0.124 

> thresholds 
[1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 

> var1 
[1] 1 1 0 0 0 1 0 1 1 1 

> df 
    var1 var2 
1  1 0 
2  1 1 
3  0 0 
4  0 0 
5  0 0 
6  1 1 
7  0 1 
8  1 1 
9  1 1 
10 1 0 

Hier sind zwei verschiedene Anrufe zwei func, eines mit labels als Vektor und die andere mit labels als data.frame:

> func(scores, var1, thresholds) 
labels labels labels labels labels labels labels labels labels labels labels 
6  5  3  3  3  2  2  2  1  1  0 

> func(scores, df, thresholds) 
    [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] 
var1 6 5 3 3 3 2 2 2 1  1  0 
var2 5 3 3 3 3 2 2 2 1  1  0 

Warum bedeutet „Etiketten“, wie angewandt erhalten ein Spaltenname in der Vektorversion und "var1" und "var2" werden als rowname in der dat.frame-Version angewendet?

Was ich suche ist der Vektor-Version mehr wie zu sein:

> func(scores, var1, thresholds) 
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] 
    labels 6 5 3 3 3 2 2 2 1  1  0 

Um die oben genannten Variablen zu erstellen:

scores <- sample(seq(0, 1, 0.001), 10, replace = T) 
thresholds <- seq(0, 1, 0.1) 
var1 <- sample(c(0, 1), 10, replace = T) 
var2 <- sample(c(0, 1), 10, replace = T) 
df <- data.frame(var1, var2) 
+0

Wenn Sie konvertieren möchten 'labels' zu einem' data.frame' Verwendung 'as.data.frame' statt und sehen, ob das hilft –

+0

Danke für Ihre Daten in dieser Frage einschließlich, aber das Format ist ein wenig schwer zu lesen. Wenn Sie Ihre Variablen haben, anstatt die einfache Konsolenausgabe anzuzeigen, zeigen Sie die Ausgabe von 'dput (varName)' oder einfach etwas wie 'scores <- c (0.187, 0.975, 0.566, 0.793, 0.524 , 0,481, 0,005, 0,756, 0,062, 0,124). Dies macht es einfacher, Ihr Problem zu replizieren und eine Lösung zu finden. – Barker

+0

@ CarlesMitjans danke für den Vorschlag; Ich habe es versucht, aber das gleiche Ergebnis. – user451151

Antwort

4

Versuchen Sie, die Reihenfolge der verschachtelten sapply s Schalt:

func <- function(scores, labels, thresholds) { 
    labels <- if (is.data.frame(labels)) labels else data.frame(labels) 
    t(sapply(labels, function(lbl) { 
    sapply(thresholds, function(t) sum(lbl[which(scores >= t)])) 
    })) 
} 

Von ?sapply:

'sapply' ist eine benutzerfreundliche Version und Wrapper von 'lapply' von Standard einen Vektor, Matrix oder, wenn 'vereinfachen = "Array"', ein Array falls zurückkehrt, durch Anwenden von 'simplify2array()'.

Um zu verstehen, was in Ihrer ursprünglichen Funktion vor sich geht, ist es vielleicht nützlich, über jede sapply der Reihe nach nachzudenken.

Die inneresapply(labels, ...) schafft einen benannten Vektor der Länge k (wobei k die Anzahl der Spalten in labels ist - so ist k 1 in dem Vektor Fall und 2 im Datenrahmen Beispiel), in dem der Namen der Vektorelemente werden durch die Spaltennamen (labels im Vektorfall und var1/var2 im Datenrahmenbeispiel) angegeben.

Die äußerensapply(thresholds, ...) läuft das innere sapply 11 Mal, jedes Mal mit einem anderen Wert von t. Im Vektorfall erhalten Sie also 11 Vektoren der Länge 1, wobei der Name des einzigen Elements in jedem Vektor labels ist, das sapply als einen Vektor der Länge 11 zurückgibt ("vereinfacht").

Durch Umschalten der Reihenfolge der sapply s gibt der innere sapply jetzt einen unbenannten Vektor der Länge 11 zurück. Der äußere sapply führt dann das k-mal aus. Im Vektorfall ist k gleich 1 und der Name des zurückgegebenen Vektors ist labels. In dem Datenrahmenbeispiel ist k 2, und die Namen der 2 zurückgegebenen Vektoren sind var1 und var2.

(Es könnte auch eine nützliche Übung sein, um die Elemente in dem thresholds Vektor zu nennen, zB thresholds <- setNames(seq(0, 1, 0.1), LETTERS[1:11]) und re-run func, um zu sehen, was passiert.)

+0

DANKE. Genau das habe ich gebraucht. Schätzen Sie die ausführliche und gründliche Erklärung! – user451151

3

Hinweis: @ Weihuang-wong ‚s Antwort ist groß, und die Lösung ist in mancher Hinsicht besser als diese. Aber ich hatte den Großteil dieser Antwort bereits geschrieben, bevor diese Antwort gepostet wurde, also entschied ich mich, diese Antwort trotzdem zu posten.

Sie erhalten die Namen, die Sie tun, weil das die Namen der Dinge sind, über die Sie iterieren. Aber warum bekommst du im ersten Fall einen benannten Vektor und im zweiten Fall eine Matrix mit Rownames? Hier ist ein einfacherer Fall, der es einfacher macht, zu sehen.

sapply(1, function(x) sapply(c(a = 1), function(y) y)) 
# a 
# 1 
sapply(1, function(x) sapply(c(a = 1, b = 2), function(y) y)) 
# [,1] 
# a 1 
# b 2 

OK, was passiert hier? Lass es uns brechen, damit wir sehen können.

sapply(c(a = 1), function(y) y) 

gibt einen benannten Length-One-Vektor zurück.

sapply(c(a = 1, b = 2), function(y) y) 

gibt einen benannten length-two Vektor zurück.

Jetzt ist es die Aufgabe der äußeren sapply, diese Ergebnisse zu kombinieren. Wenn es sieht, dass der innere sapply einen length-one-Vektor zurückgibt, vereinfacht es ihn zu einem benannten Vektor. Diese Vereinfachung funktioniert nicht, wenn der Rückgabewert eine Länge> 1 hat, also vereinfacht sich sapply zu einer Matrix.

Also, wenn wir Konsistenz wollen, müssen wir , um eine Matrix zurückgeben, auch in der Länge ein Fall. Wie machen wir konsistent? Es ist überraschend schwierig. Am Ende würde ich es einfach in eine Matrix umwandeln.

Jetzt, wo wir verstehen, was passiert, können wir das, was wir gelernt haben, auf das ursprüngliche Problem anwenden.

func <- function(scores, labels, thresholds) { 
    labels <- if (is.data.frame(labels)) labels else data.frame(labels) 
    r <- sapply(thresholds, function(t) { sapply(labels, function(lbl) { sum(lbl[which(scores >= t)]) }) }) 
    if(!is.matrix(r)) r <- matrix(r, nrow = 1, dimnames = list(names(labels))) 
    r 
} 
func(scores, df, thresholds) 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] 
# var1 6 5 3 3 3 2 2 2 1  1  0 
# var2 5 3 3 3 3 2 2 2 1  1  0 
func(scores, var1, thresholds) 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] 
# labels 6 5 3 3 3 2 2 2 1  1  0 
+0

Danke für das Posten, das ist wirklich hilfreich um zu verstehen, was intern vorgeht! – user451151

Verwandte Themen