2016-07-24 12 views
0

Ich habe es mit einer Vorverarbeitungsstufe einer Datentabelle zu tun. Mein aktueller Code funktioniert, aber ich frage mich, ob es einen effizienteren Weg gibt.Gibt es eine effizientere Möglichkeit, diesen Python-Code zu schreiben?

Meine Datentabelle sieht wie folgt aus

object A object B  features of A  features of B 
    aaa   w   1     0 
    aaa   q   1     1 
    bbb   x   0     0 
    ccc   w   1     0 

für die X wäre es

sein
[ (aaa, aaa, bbb, ccc), (w, q, x, w), (1, 1, 0, 1), (0, 1, 0, 0)] 

Jetzt schreibe ich einen Code, um eine Tabelle zu machen, die alle die Kombination von allen möglichen Spiel beinhaltet Objekt A & Objekt B (iteriere die Kombination von Objekt A & Objekt B ohne Wiederholung), während A & B ihre Eigenschaften behält. Die Tabelle würde aussehen wie die folgende: (Zeilen mit einem Sternchen sind die zusätzlichen Reihen)

object A object B  features of A  features of B 
    aaa   w   1     0 
    aaa   q   1     1 
* aaa   x   1     0 
--------------------------------------------------------- 
    bbb   x   0     0 
* bbb   w   0     0 
* bbb   q   0     1 
--------------------------------------------------------- 
    ccc   w   1     0 
* ccc   x   1     0 
* ccc   q   1     1 

Die ganzen Daten namens X den Tisch zu bekommen: Mein Code ist wie folgt, aber es läuft sehr langsam:

----------------------------------------- 
#This part is still fast 

#to make the combination of object A and object B with no repetition 

def uprod(*seqs): 
    def inner(i): 
     if i == n: 
      yield tuple(result) 
      return 
     for elt in sets[i] - seen: 
      seen.add(elt) 
      result[i] = elt 
      for t in inner(i+1): 
       yield t 
      seen.remove(elt) 

    sets = [set(seq) for seq in seqs] 
    n = len(sets) 
    seen = set() 
    result = [None] * n 
    for t in inner(0): 
     yield t 

#add all possibility into a new list named "new_data" 

new_data = list(uprod(X[0],X[1])) 

X_8v = X[:] 
y_8v = y[:] 

----------------------------------------- 
#if the current X_8v(content equals to X) does not have the match of object A and object B 
#in the list "new_data" 
#append a new row to the current X_8v 
#Now this part is super slow, I think because I iterate a lot 

for i, j in list(enumerate(X_8v[0])): 
    for k, w in list(enumerate(X_8v[1])): 
      if (X_8v[0][i], X_8v[1][k]) not in new_data: 
       X_8v[0] + (X_8v[0][i],) 
       X_8v[1] + (X_8v[1][k],) 
       X_8v[2] + (X_8v[2][i],) 
       X_8v[3] + (X_8v[3][k],) 
       X_8v[4] + (X_8v[4][i],) 
       X_8v[5] + (0,) 
       X_8v[6] + (0,) 
       y_8v.append(0) 

Gibt es eine mögliche Verbesserung für den obigen Code?

Vielen Dank!

+0

@ Loïc nicht einmal. –

+0

Dies wäre viel einfacher mit einem Beispiel, wie die Datenstruktur aussieht (d. H. 'X = ...'). – smarx

+0

Ich werde OP gestartet: http://pastebin.com/Acu5ZQND –

Antwort

2

In relationalen Algebra ausgedrückt, es klingt wie Sie

π[features of A, features of B] ((object A) X (object B))

dh Projektfelder ‚Eigenschaften von A‘ wollen, ‚Eigenschaften von B‘ aus dem Kreuzprodukt von „Objekt A“ und „Objekt B ".

Dies ist sehr natürlich in SQL auszudrücken.

Für Python, möchten Sie wahrscheinlich Ihre Daten in ein paar Wörterbücher laden, dh object_a_to_features = {"aaa": 1, "bbb": 0} object_b_to_features = {"w": 0, "q": 1}

Sie werden dann das Kreuzprodukt von object_a_to_features.keys() und object_b_to_features.keys() und dann für jede Zeile generieren möchten, schauen die Funktionen im entsprechenden Wörterbuch.

Werfen Sie einen Blick auf product() from itertools.

Etwas wie:

import itertools for pair in itertools.product(object_a_to_features.keys(), object_b_to_features.keys()): yield (pair[0], pair[1], object_a_to_features[pair[0]], object_b_to_features[pair[1]])

Beispielausgabe:

('aaa', 'q', 1, 1) ('aaa', 'w', 1, 0) ('bbb', 'q', 0, 1) ('bbb', 'w', 0, 0)

1

die Daten Unter der Annahme, sieht tatsächlich aus wie ich denke, es tut, sollte dies tun, was Sie sehr effizient wollen:

import itertools 

x = [('aaa', 'aaa', 'bbb', 'ccc'), ('w', 'q', 'x', 'w'), (1, 1, 0, 1), (0, 1, 0, 0)] 

a_list = set((x[0][i], x[2][i]) for i in range(len(x[0]))) 
b_list = set((x[1][i], x[3][i]) for i in range(len(x[1]))) 

for combination in itertools.product(a_list, b_list): 
    print(combination) 

# Output: 
# (('ccc', 1), ('w', 0)) 
# (('ccc', 1), ('x', 0)) 
# (('ccc', 1), ('q', 1)) 
# (('aaa', 1), ('w', 0)) 
# (('aaa', 1), ('x', 0)) 
# (('aaa', 1), ('q', 1)) 
# (('bbb', 0), ('w', 0)) 
# (('bbb', 0), ('x', 0)) 
# (('bbb', 0), ('q', 1)) 

Natürlich können Sie bequem die Daten wieder in der Reihenfolge umwandeln können Sie ursprünglich hatte:

reordered = [[a[0], b[0], a[1], b[1]] for a, b in itertools.product(a_list, b_list)] 

for row in reordered: 
    print(row) 

# ['ccc', 'w', 1, 0] 
# ['ccc', 'x', 1, 0] 
# ['ccc', 'q', 1, 1] 
# ['aaa', 'w', 1, 0] 
# ['aaa', 'x', 1, 0] 
# ['aaa', 'q', 1, 1] 
# ['bbb', 'w', 0, 0] 
# ['bbb', 'x', 0, 0] 
# ['bbb', 'q', 0, 1] 

EDIT

Basierend auf dem Kommentar unten, wenn Sie eine Spalte mit 1 angibt „Diese Zeile hinzufügen möchten war in der ursprünglichen Datenmenge "und 0" Diese Zeile war nicht in der ursprünglichen Datenmenge, "geben Sie einen Versuch:

existing_combinations = set(zip(x[0], x[1])) 
reordered = [ 
    [a[0], b[0], a[1], b[1], 
    1 if (a[0], b[0]) in existing_combinations else 0 
    ] for a, b in itertools.product(a_list, b_list) 
] 

# Output: 
# ['ccc', 'x', 1, 0, 0] 
# ['ccc', 'q', 1, 1, 0] 
# ['ccc', 'w', 1, 0, 1] 
# ['bbb', 'x', 0, 0, 1] 
# ['bbb', 'q', 0, 1, 0] 
# ['bbb', 'w', 0, 0, 0] 
# ['aaa', 'x', 1, 0, 0] 
# ['aaa', 'q', 1, 1, 1] 
# ['aaa', 'w', 1, 0, 1] 
+0

Wow, so schön hier zu fragen. Vielen Dank, –

+0

Sie sind der Gott. –

+0

Wenn ich einen Spaltennamen "existierte", haben die ursprünglichen Daten den Wert 1, und die hinzugefügten Daten haben den Wert 0, , was die Zeile wie ['ccc', 'w', 1, 0, 1], ['aaa ',' w ', 1, 0, 1] Wie gehe ich damit um, wenn ich die Daten identifizieren will, die hinzugefügt oder original sind? –

Verwandte Themen