2016-10-23 1 views
1

frage ich mich, ob es für dieses Problem eine bessere Lösung gibt.Erfassen aller Daten in nicht ganzem Zug, Testen und Validieren von Splits

Wir wissen, dass für eine X/Y prozentuale Aufteilung einer geraden Zahl wir eine genaue Aufteilung der Daten erhalten können - zum Beispiel für die Datengröße 10:

10 * .6 = 6 
10 * .4 = 4 
      10 

Splitting Daten so einfach ist, und wir können garantieren, dass wir alle Daten haben und nichts verloren geht. Aber wo ich kämpfen werde auf weniger freundliche Zahlen - nehmen 11

11 * .6 = 6.6 
11 * .4 = 4.4 
      11 

Allerdings können wir nicht Index in ein Array an i = 6.6 zum Beispiel. Also müssen wir entscheiden, wie wir das machen sollen. Wenn wir nur den ganzzahligen Teil nehmen wir verlieren 1 Datenpunkt -

First set = 0..6 
Second set = 6..10 

Dies wäre der gleiche Fall sein, wenn wir die Zahlen platt.

Wenn wir jedoch die Obergrenze der Zahlen nehmen:

First set = 0..7 
Second set = 7..12 

Und wir haben über das Ende unserer Array gelesen.

Dies wird noch schlimmer, wenn wir einen dritten oder vierten Split (30,30,20,20 zum Beispiel) werfen.

Gibt es ein Standard-Splitting-Verfahren für diese Art von Problemen? Wird Datenverlust akzeptiert? Es scheint, als wäre ein Datenverlust für abhängige Daten wie Zeitreihen inakzeptabel.

Danke!

EDIT: Die Werte .6 und .4 werden von mir gewählt. Sie könnten zwei beliebige Zahlen sein, die zu 1 summieren.

+0

@anonymous im Fall von zwei Splits, ja, Sie könnten Boden und nehmen Sie den Rest als der zweite Satz. In einem Fall, wo wir 3 Splits haben, können Sie das nicht so einfach tun. – rec

+0

Im Falle von 3 Split, nehmen Sie den Rundenwert von zwei Split und nehmen Sie den Wert von 3rd Split als Wert von len (my_list) - val_split_1 - val_split2 wobei len() gibt die Länge der Liste. Hinzugefügte Antwort –

Antwort

1

Zunächst einmal bemerken, dass Ihr Problem nicht auf ungeradee große Arrays beschränkt ist, wie Sie behaupten, aber alle großen Arrays. Wie würden Sie die Aufteilung von 56% -44% eines 10-Elemente-Arrays machen? Oder eine 60% -40% Aufteilung eines 4 Elemente Arrays?

Es gibt kein Standardverfahren. In vielen Fällen interessieren sich Programmierer nicht so sehr für eine exakte Aufteilung, und sie tun es entweder, indem sie eine Fläche abrunden oder runden (die Größe der ersten Menge), während sie die komplementäre (Array - Länge - gerundete Größe) für die andere verwenden Größe der Sekunde).

Dies kann in den meisten Fällen in Ordnung sein, wenn es sich um eine einmalige Berechnung handelt und Genauigkeit nicht erforderlich ist. Sie müssen sich fragen, was Ihre Anforderungen sind. Zum Beispiel: Nehmen Sie Tausende von 10-dimensionalen Arrays und jedes Mal, wenn Sie sie teilen, 56% -44%, machen Sie einige Berechnungen und geben Sie ein Ergebnis zurück? Sie müssen sich fragen, welche Genauigkeit Sie wollen. Interessiert es Sie, wenn Ihr Ergebnis der 60% -50% Split oder der 50% -50% Split ist?

Als ein anderes Beispiel stellen Sie sich vor, dass Sie einen 4-Wege-gleichen Split von 25% -25% -25% -25% machen. Wenn Sie 10 Elemente haben und Sie die Rundungstechnik anwenden, erhalten Sie 3,3,3,1 Elemente. Sicher wird dies Ihre Ergebnisse durcheinander bringen.

Wenn Sie über all diese Ungenauigkeiten egal dann ist der erste Schritt prüfen, ob Sie können entweder die Array-Größe und/oder das Split-Verhältnis (s) einzustellen.

Wenn diese in Stein gemeißelt sind, ist der einzige Weg, um eine genaue Aufteilung aller Verhältnisse von jeder Größe Array zu machen es probabilistic. Sie müssen mehrere Arrays aufteilen, damit dies funktioniert (das bedeutet, dass Sie dasselbe Aufteilungsverhältnis mehrmals auf Arrays gleicher Größe anwenden müssen). Je mehr Arrays, desto besser (oder Sie können das gleiche Array mehrmals verwenden).

Also stellen Sie sich vor, dass Sie eine 56% -44% Teilung von einem 10 großen Array machen müssen. Dies bedeutet, dass Sie es in 5,6 Elemente und 4,4 Elemente im Durchschnitt teilen müssen.

Es gibt viele Möglichkeiten, wie Sie einen Durchschnitt von 5,6 Elementen erreichen können. Der einfachste (und derjenige mit der geringsten Varianz in der Abfolge von Versuchen) ist es, 60% der Zeit eine Menge mit 6 Elementen und 40% der Zeit eine Menge mit 5 Elementen zu haben.

0,6 * 6 + 0,4 * 5 = 5,6

In Bezug auf die Code das ist, was Sie auf der Größe des Satzes jedes Mal zu entscheiden, tun können:

import random 

arraySize = 10 
firstSplit = 0.56 
avgSplitSize = arraySize * firstSplit 
flooredSplitSize = int(avgSplitSize) 

if avgSplitSize > flooredSplitSize: 
    if random.uniform(0,1) > avgSplitSize - flooredSplitSize: 
     thisSplitSize = flooredSplitSize 
    else: 
     thisSplitSize = flooredSplitSize + 1  
else: 
    thisSplitSize = avgSplitSize 

Sie den Code machen könnte kompakter, habe ich hier nur einen Überblick gemacht, damit Sie die Idee bekommen. Ich hoffe das hilft.

+0

Obwohl ich denke, die Antwort von anonym passt zu der Problemdomäne, nach der ich gesucht habe (ganzzahlige Aufteilungen wie 60/40, 70/30 und eingeschränkt auf 3 Sätze) Ich denke, deine Antwort ist ALLGEMEINER und als Ergebnis werde ich gehen voraus und vergeben Sie die Punkte. Das probabilistische Argument scheint der vollständigere Weg zu sein, dieses Problem zu behandeln, wenn es verallgemeinert wird. – rec

+0

Um weiter auf meinen Punkt zu erweitern, ich denke, es wäre akzeptabel, etwas Verlust in "Vollständigkeit" zu haben, wenn ein Benutzer fragt, ein 7-Element-Set 4 Wege, jeweils 25% zu teilen. Ich denke, das ist implizit in dem Problem, dass Sie _enugh_ Daten haben müssen, um mit zu beginnen. Wenn Sie also 3 Wege teilen und _enugh_ Daten in jedem haben möchten, sollten Sie das berücksichtigen. – rec

+0

Danke @rec. Ich bin mir nicht sicher, was Sie mit ganzzahliger Teilung meinen. In Ihrer Frage begrenzen Sie die Teilungsquoten nicht. Und selbst wenn Sie Einschränkungen bei den Teilungsverhältnissen vorgenommen haben, können Sie nicht ganzzahlige Teilstriche erhalten, da die Länge des Arrays beliebig sein kann. Ob ein Genauigkeitsverlust akzeptabel ist oder nicht, hängt von den Anforderungen Ihrer Anwendung ab, wie ich in meiner Antwort geschrieben habe. Um schließlich genug Daten zu haben: Sie benötigen nicht viele Daten, Sie können die exakte (d. H. Durchschnittliche) Aufteilung durchführen, indem Sie das gleiche Array mehrmals verwenden. – Thanassis

0

Statt ciel() oder floor() verwenden Sie stattdessen round(). Zum Beispiel:

>>> round(6.6) 
7.0 

Der Rückgabewert wird von float Typ sein. Für den ganzzahligen Wert bekommen, werfen Typ es int als:

>>> int(round(6.6)) 
7 

Dies wird der Wert Ihrer ersten aufgeteilt. Um den zweiten Split zu erhalten, berechne ihn mit len(data) - split1_val. Dies gilt im Falle eines 2-Split-Problems.

Bei 3 geteilt, nehmen rund Wert von zwei aufgeteilt und nehmen den Wert des 3. Split als der Wert von len(my_list) - val_split_1 - val_split2

in allgemeiner Weise, Für N aufgeteilt:

Nehmen Sie die round() Wert von N-1 Split.Und für den letzten Wert, tun len(data)-„Wert von N round() Werte“.

wobei len() die Länge der Liste angibt.

+0

Take n = 15; Dann .7 * 15 = 10.5, .3 * 15 = 4.5; aber rund (10,5) + rund (4,5) = 11 + 5 = 16 – tenCupMaximum

+0

Es scheint fast so, als ob Sie einen Spezialfall haben müssen, dass wenn die Rundung übergeht, stattdessen die Datengröße verwendet wird (in diesem Fall 15). Dies scheint jedoch schlampig und fehleranfällig zu sein. – rec

+0

Die Antwort wurde aktualisiert. Grundsätzlich Für N-Split müssen Sie den 'round()' -Wert von N-1 split nehmen. Und für den letzten Wert, 'len (Daten)' - "N runde Werte". –

0

Betrachten wir zuerst das Aufteilen des Sets in zwei Teile.

Lassen n die Anzahl der Elemente, die wir Spaltung sind, und p und q die Proportionen, so dass

p+q == 1

ich behaupten, dass die Teile nach dem Komma wird immer entweder Summe 1 oder 0, so sollten wir floor auf einem und ceil auf dem anderen verwenden, und wir werden immer Recht haben.

Hier ist eine Funktion, die das zusammen mit einem Test tut. Ich habe die Print-Statements bei mir gelassen, aber sie sind auskommentiert.

def simpleSplitN(n, p, q): 
    "split n into proportions p and q and return indices" 
    np = math.ceil(n*p) 
    nq = math.floor(n*q) 
    #print n, sum([np, nq]) #np and nq are the proportions 
    return [0, np] #these are the indices we would use 

#test for simpleSplitN 
for i in range(1, 10): 
    p = i/10.0; 
    q = 1-p 
    simpleSplitN(37, p, q); 

Für die mathematisch geneigt, hier ist der Beweis, dass die Dezimalzahl Proportionen 1

-----------------------

Summe werden wir p*n als n/(1/p) zum Ausdruck bringen können, und so durch den Divisionsalgorithmus erhalten wir ganze Zahlen k und r

n == k*(1/p) + r mit 0 <= r < (1/p)

So r/(1/p) == p*r < 1

Wir genau für q das gleiche tun, bekommen

q*r < 1 (das ist eine andere r)

Es ist wichtig zu beachten, dass q*r und p*r sind die Teil nach die Dezimalzahl, wenn wir unsere n teilen.

Jetzt können wir sie zusammen addieren

0 <= p*(r_1) < 1 0 <= q*(r_2) < 1

=> 0 < p*r + q*r == p*n + q*n + k_1 + k_2 == n + k_1 + k_2 < 2

Aber durch Schließung der ganzen Zahlen (wir haben jetzt Indizes hinzugefügt), n + k_1 + k_2 eine ganze Zahl ist und so

0 < n + k_1 + k_2 < 2

bedeutet, dass p*r + q*r muss sei entweder 0 oder 1. Es wird nur 0 für den Fall sein, dass unser n gleichmäßig geteilt wird.

Sonst können wir jetzt sehen, dass unsere Nachkommastellen immer zu 1 summieren werden.

-----------------------

Wir haben einen sehr ähnlichen tun können (aber komplizierter leicht) Beweis n in eine beliebige Anzahl (etwa N) Teile zur Aufspaltung, sondern von ihnen 1 Summieren, werden sie auf eine ganze Zahl Summe weniger als N.

Hier ist die allgemeine Funktion, es hat unkommentierte Druckanweisungen für Verifikationszwecke.

import math 
import random 

def splitN(n, c): 
    """Compute indices that can be used to split 
    a dataset of n items into a list of proportions c 
    by first dividing them naively and then distributing 
    the decimal parts of said division randomly 
    """ 
    nc = [n*i for i in c]; 
    nr = [n*i - int(n*i) for i in c] #the decimal parts 
    N = int(round(sum(nr)))   #sum of all decimal parts 
    print N, nc 
    for i in range(0, len(nc)): 
     nc[i] = math.floor(nc[i]) 
    for i in range(N):     #randomly distribute leftovers 
     nc[random.randint(1, len(nc)) - 1] += 1 
    print n,sum(nc);     #nc now contains the proportions 
    out = [0]       #compute a cumulative sum 
    for i in range(0, len(nc) - 1): 
     out.append(out[-1] + nc[i]) 
    print out 
    return out 

#test for splitN with various proportions 
c = [.1,.2,.3,.4] 
c = [.2,.2,.2,.2,.2] 
c = [.3, .2, .2, .3] 
for n in range(10, 40): 
    print splitN(n, c) 

Wenn wir Reste haben, werden wir nie eine noch Split bekommen, so dass wir verteilen sie nach dem Zufall, wie gesagt @Thanassis. Wenn Sie die Abhängigkeit von random nicht mögen, dann können Sie sie einfach am Anfang oder in gleichen Intervallen hinzufügen.

Beide meiner Funktionen geben Indizes aus, aber sie berechnen Proportionen und können daher leicht geändert werden, um diese stattdessen pro Benutzerpräferenz auszugeben.

Verwandte Themen