2016-09-19 1 views
0

Ich habe eine kontinuierliche Variable, die ich in Bins aufteilen möchte und einen numerischen Vektor (mit der Länge meines ursprünglichen Vektors) zurückgibt, dessen Werte sich beziehen zu den Werten der Behälter. Jeder Behälter sollte ungefähr die gleiche Anzahl von Elementen haben. Diese Frage: splitting a continuous variable into equal sized groups beschreibt eine Reihe von Techniken für verwandte Situationen. Zum Beispiel, wenn ich anfangen miteine kontinuierliche Variable in Gruppen mit gleicher Anzahl von Elementen aufteilen - numerischen Vektor aus Bin-Werten zurückgeben

x = c(1,5,3,12,5,6,7) 

ich cut() können erhalten:

cut(x, 3, labels = FALSE) 
[1] 1 2 1 3 2 2 2 

Dies ist unerwünscht, weil die Werte des Faktors nur sequenzielle ganze Zahlen sind, haben sie keine direkte Beziehung zu dem zugrunde liegenden ursprüngliche Werte in meinem Vektor.

Eine andere Möglichkeit ist cut2: zum Beispiel:

library(Hmisc) 
cut2(x, g = 3, levels.mean = TRUE) 
[1] 3.5 3.5 3.5 9.5 3.5 6.0 9.5 

Dieses besser, weil jetzt die Rückgabewerte auf die Werte der Bins beziehen. Es ist immer noch weniger als ideal, obwohl seit:

  • (a) es einen Faktor ergibt, die dann in numerischem konvertiert werden muss (siehe e.g.), die wiesen beide langsam und umständlich Code ist.
  • (b) Idealerweise würde ich gerne wählen können, ob die oberen oder unteren Endpunkte der Intervalle verwendet werden, anstatt nur die Mittel.

Ich weiß, dass es auch Optionen regex auf die Faktoren, Erträge aus cut oder cut2 mit den oberen oder unteren Punkte der Intervalle zu erhalten. Auch diese scheinen übermäßig schwerfällig.

Ist dies nur eine Situation, die einige nicht so elegante Hacking erfordert? Oder gibt es eine einfachere Funktionalität, um dies zu erreichen?

Mein aktueller Best-Effort ist wie folgt:

MyDiscretize = function(x, N_Bins){ 
    f = cut2(x, g = N_Bins, levels.mean = TRUE) 
    return(as.numeric(levels(f))[f]) 
} 

Mein Ziel ist es, etwas schneller zu finden, die mehr elegant und leicht anpassbar entweder der Endpunkte zu verwenden, anstatt nur die Mittel.


Edit:

Zur Klarstellung: meine gewünschte Ausgabe wäre:

  • (a) ein Äquivalent zu dem, was ich jetzt im Beispiel mit cut2 erreichen können, aber ohne Sie müssen den Faktor in numerisch konvertieren.

  • (b) Wenn möglich, können Sie auch einfach einen der Endpunkte des Intervalls anstelle des Mittelpunkts verwenden.

Antwort

1

Verwenden ave wie folgt aus:

Gegeben:

x = c(1,5,3,12,5,6,7) 

Mittelwert:

ave(x,cut2(x,g = 3), FUN = mean) 
[1] 3.5 3.5 3.5 9.5 3.5 6.0 9.5 

Min:

ave(x,cut2(x,g = 3), FUN = min) 
[1] 1 1 1 7 1 6 7 

Max:

ave(x,cut2(x,g = 3), FUN = max) 
[1] 5 5 5 12 5 6 12 

oder Standardabweichung:

ave(x,cut2(x,g = 3), FUN = sd) 
[1] 1.914854 1.914854 1.914854 3.535534 1.914854  NA 3.535534 

Notiere die NA für nur einen Datenpunkt im Intervall führen.

Hoffe, das ist, was Sie brauchen.

HINWEIS:
Parameter g in cut2 ist die Anzahl der Quantilgruppen. Gruppen haben möglicherweise nicht die gleiche Anzahl an Datenpunkten und die Intervalle haben möglicherweise nicht die gleiche Länge.
Auf der anderen Seite teilt das Intervall in mehrere gleiche Länge.

+0

Ok, danke, das ist hilfreich, sowohl die Funktion als auch die Notiz. Ich mag schlampig in meiner Terminologie gewesen sein, - 'cut2' ist eine Möglichkeit, Bins mit * relativ * gleichen Zahlen von Elementen zu erhalten, oder? –

+1

Nicht wirklich, wenn Sie sich das Ergebnis von 'cut2' ansehen, enthält die erste Gruppe vier Elemente, das zweite nur eins und die letzten zwei. Funktion 'cut' garantiert nicht, dass jede Gruppe die gleiche Anzahl von Elementen hat. –

+0

Wenn Sie die gleiche Anzahl an Elementen haben möchten, sollten Sie sie bestellen und dann in gleich große Gruppen aufteilen. –

1

Vielleicht nicht viel elegant, aber sollte effizient sein.Versuchen Sie, diese Funktion:

myCut<-function(x,breaks,retValues=c("means","highs","lows")) { 
    retValues<-match.arg(retValues) 
    if (length(breaks)!=1) stop("breaks must be a single number") 
    breaks<-as.integer(breaks) 
    if (is.na(breaks)||breaks<2) stop("breaks must greater than or equal to 2") 
    intervals<-seq(min(x),max(x),length.out=breaks+1) 
    bins<-findInterval(x,intervals,all.inside=TRUE) 
    if (retValues=="means") return(rowMeans(cbind(intervals[-(breaks+1)],intervals[-1]))[bins]) 
    if (retValues=="highs") return(intervals[-1][bins]) 
    intervals[-(breaks+1)][bins] 
} 
x = c(1,5,3,12,5,6,7) 
myCut(x,3) 
#[1] 2.833333 6.500000 2.833333 10.166667 6.500000 6.500000 6.500000 
myCut(x,3,"highs") 
#[1] 4.666667 8.333333 4.666667 12.000000 8.333333 8.333333 8.333333 
myCut(x,3,"lows") 
#[1] 1.000000 4.666667 1.000000 8.333333 4.666667 4.666667 4.666667 
Verwandte Themen