2017-03-06 4 views
-1

Ich verbinde zwei Tabellen mit Daten von zwei Systemen. Eine einfache Pandas Merge zwischen zwei df wird nicht kompliziertere Regeln zu ehren (es sei denn, ich verwende es falsch, verstehe nicht, die Prozess-Merge implementiert - sehr möglich).Was ist eine effizientere Möglichkeit, Zeilen aus DataFrames Zeile für Zeile mit Bedingungen zusammenzuführen?

Ich habe zusammengeschustert eine Spielzeug Lösung, die mich zwei df die mit itertuples entpacken können, validieren Einstimmungen basierend auf Werten, und dann einpacken in einem Datenrahmen:

df1:   df2: 
    A X   B Y 
0 1 10  0 2 10 
1 5 15  1 4 15 
       2 6 15 

.

df1 = pd.DataFrame(data1,columns=['A','X']) 
df2 = pd.DataFrame(data2,columns=['B','Y']) 
df3 = pd.DataFrame(index=['A','X','B','Y']) 
i = -1 

for rowA in df1.itertuples(index=False): 
    i += 1 
    for rowB in df2.itertuples(index=False): 
     A,X = rowA 
     B,Y = rowB 
     if (B > A) & (X==Y): 
      df3[i] = list(rowA+rowb) 
     else: 
      continue 

print(df3.transpose()) 

.

A X B Y 
0 1 10 2 10 
1 5 15 6 15 

Mein naiver Ansatz ist ineffizient

Die verschachtelte for() Schleife ineffizient ist, weil ich für jeden Eintrag von data1 über Daten2/df2 Iterieren bin. Sobald ich eine gute Übereinstimmung mit data2/df2 gefunden habe, sollte die Zeile entfernt werden.

// UPDATE (zeigt den Ursprung meiner Frage)

Ein Beispiel für die Art von Daten, die ich mit verschmilzt zwei unabhängigen Systemen gerade arbeitete, die keine Schlüssel oder andere serialisierten IDs gemeinsam nutzen. Da ich keine exakte Übereinstimmung herstellen kann, muss ich mich auf logische/arithmetische Operationen und den Eliminierungsprozess verlassen.

Im folgenden Beispiel schlägt eine einfache pandas.merge auf Line3, weil die Time1 < Time2.

Time1,    Total1 ... Time2,    Total2, error 
1, 2017-02-19 08:03:00, 15.00 ... 2017-02-19 08:02:00, 15.00, 0 
2, 2017-02-19 08:28:00, 33.00 ... 2017-02-19 08:27:00, 33.00, 0 
3, 2017-02-19 08:40:00, 20.00 ... 2017-02-19 10:06:00, 20.00, 1 
4, 2017-02-19 10:08:00, 20.00 ... 2017-02-19 10:16:00, 20.00, 1 
[...] 

Was passieren soll, ist so etwas wie dieses:

Time1,    Total1 ... Time2,    Total2, error 
1, 2017-02-19 08:03:00, 15.00 ... 2017-02-19 08:02:00, 15.00, 0 
2, 2017-02-19 08:28:00, 33.00 ... 2017-02-19 08:27:00, 33.00, 0 
3, 2017-02-19 08:40:00, 20.00 ... NaN,     NaN, NaN 
4, 2017-02-19 10:08:00, 20.00 ... 2017-02-19 10:06:00, 20.00, 0 
[...] 

// UPDATE2 ich auf mehrere Permutationen von merge_asof() und join() in Antworten empfohlen gearbeitet habe. Jede Methode wurde auch so sortiert, wie es von Dokumenten angewiesen wurde. Angenommen, ich habe jede korrekt implementiert sind folgende Prozent True Streichhölzer der Regeln ((time1> = time2) & (Total1 == Total2) von 53 Datensätze) in meinem Test-Set jeweils drei Methoden:

| type     | 'date' | 'total' | both | 
|-----------------------|----------|-----------|--------| 
| merg_asof sort (time) | .7924 | .9245  | .7169 | 
| merg_asof (time,total)| .7735 | .6981  | .6226 | 
| intertup (time,total) | .8301 | .8301  | .8301 | 
| join ind (time)  | na  | na  | na  | 

Die Join benötigt einen gemeinsamen Schlüssel, richtig? Die on Klausel in der Dokumentation besagt, "Spalte (n) im Aufrufer, um auf den Index in anderen beizutreten, andernfalls verbindet Index-on-Index. Wenn mehrere Spalten angegeben, muss die übergebene DataFrame einen MultiIndex haben."

Ich versuchte join mit einem Multi-Index von (Zeit, insgesamt) und nur (Zeit). Das Problem ist, die Join Clobbers, was auch immer Sie beitreten. Es bleibt nichts mehr übrig, um die Fehleranalyse durchzuführen, da diese Indizes zu einem zusammengeführt werden.

Meine naive intertuple Lösung (oben) produziert nur perfekte Übereinstimmungen, aber die Lösung braucht noch einen Sammler für verpasste Übereinstimmungen.

+0

ich diese Frage mehrmals gelesen habe und ich versuche immer noch zu verstehen, wo Dinge wie "total" kommen von. Angesichts Ihrer ursprünglichen (vor dem Update) Frage würde ich einfach etwas tun wie 'pd.merge_asof (df1, df2, linkes_on = 'A', right_on = 'B', left_by = 'X', right_by = 'Y', allow_exact_matches = Falsch, Richtung = 'vorwärts') '. Beachten Sie, dass der 'direction' Parameter erst nach Pandas 0,20.0 erscheint, also müssen Sie Pandas aus der Quelle bauen oder für den Moment fest sitzen. – chrisaycock

+0

@chrisaycock, du musst deine Vorstellungskraft ein wenig benutzen, um die Beziehung zwischen meinem naiven Algorithmus und den ursprünglichen Daten zu verstehen, die ich oben kurz umschreibe. Total war genau das - die Summe einer einzelnen Transaktion, die sich zwischen nicht integrierten Transaktionssystemen ausbreitet. Um meinen Code zu vereinfachen, wählte ich A/B als geordnet und X/Y als Übereinstimmung. 'merge_asof()' kam bei meinen Suchen zuvor nicht vor. Der 'direction' Parameter ist sehr wichtig, und ich habe gerade den' tolerance' Parameter bemerkt, machen 'merge_asof' einen großen Kandidaten für eine Lösung. Weitere Tests – xtian

Antwort

0

df3 = df1.join (df2) macht nicht was du willst?

+0

Nein. Im obigen Beispiel würde ein einfacher Join (5,15) & (4,15) ergeben, aber das scheitert an der Regel 5 <4. – xtian

0

Wenn ich Ihre Logik richtig zu verstehen, dies sollte es tun:

time1 = pd.to_datetime(['2/19/17 8:03:00', '2/19/17 8:28:00', '2/19/17 8:40:00', '2/19/17 10:08:00']) 
time2 = pd.to_datetime(['2/19/17 8:02:00', '2/19/17 8:27:00', '2/19/17 10:06:00', '2/19/17 10:16:00']) 

df1 = pd.DataFrame({'Time1':time1, 'Total1':[15.00, 33.00, 20.00, 20.00]}) 
df2 = pd.DataFrame({'Time2':time2, 'Total2':[15.00, 33.00, 20.00, 20.00], 'error':[0,0,1,1]}) 

df3 = pd.merge_asof(df1, df2, left_on = 'Time1', right_on = 'Time2') 
df3.loc[df3['Time2'].duplicated(), ['Time2', 'Total2', 'error']] = None 

Ausgang:

   Time1 Total1    Time2 Total2 error 
0 2017-02-19 08:03:00 15.0 2017-02-19 08:02:00 15.0 0.0 
1 2017-02-19 08:28:00 33.0 2017-02-19 08:27:00 33.0 0.0 
2 2017-02-19 08:40:00 20.0     NaT  NaN NaN 
3 2017-02-19 10:08:00 20.0 2017-02-19 10:06:00 20.0 1.0 
+0

TLDR: Die Jury berät noch; Ich habe oben einige Fehlerüberprüfungsergebnisse hinzugefügt. Es ist ziemlich merkwürdig, wie 'merge_asof()' viele gute Gesamttreffer gemacht hat, aber die Fehler beim 'time'-Matching brachten insgesamt gute Treffer nach unten. Heute habe ich die schwere Arbeit geleistet, jeden Merge-Typ zum Laufen zu bringen. Ich muss später zu dem Projekt zurückkehren, um meine Methodik zu überprüfen - stellen Sie sicher, dass es keine Fehler gibt. – xtian

Verwandte Themen