2013-04-18 7 views
10

Ich habe einige Daten und ich möchte es in kleinere Gruppen aufteilen, die ein gemeinsames Verhältnis beibehalten. Ich schrieb eine Funktion, die eine Eingabe von zwei Array und berechnen Sie das Größenverhältnis und dann sagen mir die Optionen für wie viele Gruppen kann ich es teilen (wenn alle Gruppen die gleiche Größe haben), hier ist die Funktion:Aufrechterhaltung eines Verhältnisses beim Teilen von Daten in Python-Funktion

Also meine Frage ist, wie kann ich es so machen, dass ein dritter Eingang für die Funktion, die Anzahl der Falten und ändern Sie die Funktion um, so dass nicht durchlaufen, um sicherzustellen, dass jede Gruppe den gleichen Betrag hat mit dem richtigen Verhältnis, es wird nur das richtige Verhältnis haben, aber unterschiedliche Größen?

Zusatz für @JamesHolderness

So ist Ihre Methode fast perfekt, aber hier ist ein Problem:

mit Längen 357 und 143 mit 9 Falten, ist dies die Rückkehr Liste:

[(39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16), (39, 16)] 

jetzt, wenn Sie die Spalten addieren, Sie diese: 351 144

die 3 51 ist in Ordnung, weil es weniger als 357 ist, aber die 144 funktioniert nicht, weil es größer als 143 ist! Der Grund dafür ist, dass 357 und 143 Längen von Arrays sind, so dass die 144. Zeile dieses Arrays nicht existiert ...

+0

Meinen Sie, dass Sie mit einem variierenden Trainingssatz eine Kreuzvalidierung durchführen möchten? Das hört sich statistisch fragwürdig an? Wird es normalerweise in der Praxis gemacht? – thebigdog

+0

ja das ist für die Kreuzvalidierung. Nein, dies soll die Ähnlichkeit zwischen einem Test und einem Trainingssatz testen, um zu prüfen, ob in den Testdaten etwas enthalten sein könnte, das nicht in den Trainingsdaten enthalten ist. Normalerweise wird die Kreuzvalidierung nur für diesen einen Trainingssatz durchgeführt, und dies könnte auch für sie gelten. Statt zwei Arrays würden Sie die Spalte im Trainings-Array und im Trainings-Array angeben, und das würde es auch tun. –

+1

Wenn Ihre zwei Arrays die Größen "m" und "n" haben und der irreduzible Anteil von "m" geteilt durch "n" ist "p/q", dann sind "m = k * p" und "n = k * q '. Sobald Sie "k" haben, führt eine beliebige Partition (http://en.wikipedia.org/wiki/Partition_ (number_theory)) dazu, dass Sie Ihre Originaldaten teilen, die das Verhältnis der Elemente beibehalten. Lass es mich wissen, wenn du mich zur Ausarbeitung brauchst. – Jaime

Antwort

3

Hier ist ein Algorithmus, der meiner Meinung nach für Sie arbeiten könnte.

Sie nehmen die test_length und train_length und dividieren durch ihre GCD, um das Verhältnis als eine einfache Fraktion zu erhalten. Sie nehmen den Zähler und Nenner und Sie addieren sie zusammen, und das ist der Größenfaktor für Ihre Gruppen.

Zum Beispiel, wenn das Verhältnis 3: 2, die Größe jeder Gruppe muss ein Vielfaches von 5.

Sie sich dann die total_length nehmen und teilen sie durch die Anzahl der Falten die ideale Größe für das bekommen erste Gruppe, die eine Gleitkommazahl sein kann. Sie finden das größte Vielfache von 5, das kleiner oder gleich ist, und das ist Ihre erste Gruppe.

Diesen Wert von Ihrer Summe subtrahieren und durch falten-1 dividieren, um die ideale Größe für die nächste Gruppe zu erhalten. Finden Sie wieder das größte Vielfache von 5, subtrahieren Sie das Ergebnis vom Gesamtwert und fahren Sie fort, bis Sie alle Gruppen berechnet haben.

Einige Beispiel-Code:

total_length = test_length + train_length   
divisor = gcd(test_length,train_length) 
test_multiple = test_length/divisor 
train_multiple = train_length/divisor 
total_multiple = test_multiple + train_multiple 

# Adjust the ratio if there isn't enough data for the requested folds 
if total_length/total_multiple < folds: 
    total_multiple = total_length/folds 
    test_multiple = int(round(float(test_length)*total_multiple/total_length)) 
    train_multiple = total_multiple - test_multiple 

groups = [] 
for i in range(folds,0,-1): 
    float_size = float(total_length)/i 
    int_size = int(float_size/total_multiple)*total_multiple 
    test_size = int_size*test_multiple/total_multiple 
    train_size = int_size*train_multiple/total_multiple 
    test_length -= test_size # keep track of the test data used 
    train_length -= train_size # keep track of the train data used 
    total_length -= int_size 
    groups.append((test_size,train_size)) 

# If the test_length or train_length are negative, we need to adjust the groups 
# to "give back" some of the data. 
distribute_overrun(groups,test_length,0) 
distribute_overrun(groups,train_length,1) 

Dieser wurde aktualisiert Spur der Größe von jeder Gruppe verwendet zu halten (Test und Zug), aber keine Sorgen, wenn wir zu viel am Anfang verwenden.

Dann am Ende, wenn es Überlauf (d. H.test_length oder train_length sind negativ geworden), verteilen wir diesen Überlauf zurück in die Gruppen, indem wir die entsprechende Seite des Verhältnisses in so vielen Punkten dekrementieren, wie es nötig ist, um den Überlauf wieder auf Null zu bringen.

Die Funktion distribute_overrun ist unten enthalten.

def distribute_overrun(groups,overrun,part): 
    i = 0 
    while overrun < 0: 
     group = list(groups[i]) 
     group[part] -= 1 
     groups[i] = tuple(group) 
     overrun += 1 
     i += 1 

Am Ende dieser Gruppen wird eine Liste von Tupeln, die test_size train_size und für jede Gruppe enthält.

Wenn das klingt wie die Art von Dingen, die Sie wollen, aber Sie brauchen mich, um das Codebeispiel zu erweitern, lassen Sie es mich wissen.

+0

Fast perfekt !!! Es funktioniert gut in den meisten Situationen, die nur ich ssue ist, wenn der Bruch nicht vereinfacht werden kann, gibt es alle Tupel als '(0,0)' mit Ausnahme der letzten, die nur die ursprünglichen Zahlen sind. Gibt es etwas, das ich der Funktion hinzufügen könnte, um das Verhältnis leicht zu brechen, wenn das Verhältnis als solches nicht möglich ist? –

+0

fügen Sie auch 'total_length = train_length + test_length' am Anfang hinzu, Sie haben' total_length' nicht definiert. –

+0

Ich habe die 'total_length' von Ihrem ursprünglichen Code verwendet, aber ich habe das zum Beispiel zur Klärung hinzugefügt. Außerdem wurde die Antwort mit etwas zusätzlichem Code aktualisiert, um das Verhältnis anzupassen, wenn nicht genügend Daten vorhanden sind. Ich sollte hinzufügen, dass, wenn Ihre Daten nicht gleichmäßig durch die Anzahl der angeforderten Falten geteilt werden, Sie am Ende einige Daten übrig haben werden. –

3

In einer anderen Frage wollte der Autor eine ähnliche Kreuzvalidierung durchführen wie Sie. Bitte, take a look to this answer. Ausarbeiten die Antwort auf Ihr Problem, wäre es wie:

import numpy as np 
# in both train_data the first line is used for the cross-validation, 
# and the other lines will follow, so you can add as many lines as you want 
test_data = np.array([ 0., 1., 2., 3., 4., 5.]) 
train_data = np.array([[ 0.09, 1.9, 1.1, 1.5, 4.2, 3.1, 5.1], 
         [ 3, 4, 3.1, 10, 20, 2, 3]]) 

def cross_validation_group(test_data, train_data): 
    om1,om2 = np.meshgrid(test_data,train_data[0]) 
    dist = (om1-om2)**2 
    indexes = np.argsort(dist, axis=0) 
    return train_data[:, indexes[0]] 

print cross_validation_group(test_data, train_data) 
# array([[ 0.09, 1.1 , 1.9 , 3.1 , 4.2 , 5.1 ], 
#  [  3 , 3.1 ,  4 ,  2 , 20 ,  3 ]]) 

Sie die train_data entsprechend das Intervall in test_data definiert hat.

+0

das ist überhaupt nicht das, was ich will ... Meine Gruppierung funktioniert gut für so etwas, aber ich brauche meine Funktion, um eine andere Variable zu nehmen, die die Menge der Gruppen für das Array und die Größe der Arrays sein kann anders, solange sie das gleiche Verhältnis von Trainingsdaten zu Testdaten haben –

+0

so denke ich, dass ich Ihren Punkt verpasst habe. Dieser funktioniert für verschiedene Größen, aber es gibt keine Variable, die die Anzahl der Gruppen angibt (was durch die test_data gesteuert wird, die du gibst ... –

+0

im Grunde brauche ich eine andere Variable, x, wobei x = die Anzahl der Gruppen Zeilen können unterschiedlich sein, aber in jeder Gruppe muss das gleiche Verhältnis von Zeilen aus den test_data und den Zeilen aus den Trainingsdaten vorhanden sein, damit es keine Verzerrung in der Kreuzvalidierung gibt –

Verwandte Themen