2016-11-10 2 views
3

Das ist ein komischer: Ich habe 3 Datenrahmen, "prov_data" mit enthält eine Anbieter-ID und zählt auf Regionen und Kategorien (dh wie oft dieser Anbieter mit diesen Regionen und Kategorien interagiert) .Versuchen, Datenrahmen mit vielen Bedingungen zusammenzuführen

prov_data = DataFrame({'aprov_id':[1122,3344,5566,7788],'prov_region_1':[0,0,4,0],'prov_region_2':[2,0,0,0], 
        'prov_region_3':[0,1,0,1],'prov_cat_1':[0,2,0,0],'prov_cat_2':[1,0,3,0],'prov_cat_3':[0,0,0,4], 
        'prov_cat_4':[0,3,0,0]}) 

enter image description here

"tender_data", die die gleichen, aber für Angebote enthält.

tender_data = DataFrame({'atender_id':['AA12','BB33','CC45'], 
        'ten_region_1':[0,0,1,],'ten_region_2':[0,1,0], 
        'ten_region_3':[1,1,0],'ten_cat_1':[1,0,0], 
        'ten_cat_2':[0,1,0],'ten_cat_3':[0,1,0], 
        'ten_cat_4':[0,0,1]}) 

enter image description here

Und schließlich ein "NO_MATCH" DF Wich enthält zwischen Anbieter und zart verbotenen Spielen.

no_match = DataFrame({ 'prov_id':[1122,3344,5566], 
      'tender_id':['AA12','BB33','CC45']}) 

enter image description here

Ich brauche Folgendes zu tun: Erstellen Sie eine neue df, die die Reihen der prov_data & tender_data Datenrahmen anhängen, wenn sie (1) Spiel eine oder mehrere Kategorien (dh der gleichen Kategorie ist > 0) UND (2) stimmen mit einer oder mehreren Regionen überein UND (3) sind nicht in der no_match-Liste.

dass also würde mir diesen DF:

df = DataFrame({'aprov_id':[1122,3344,7788],'prov_region_1':[0,0,0],'prov_region_2':[2,0,0], 
        'prov_region_3':[0,1,1],'prov_cat_1':[0,2,0],'prov_cat_2':[1,0,0],'prov_cat_3':[0,0,4], 
        'prov_cat_4':[0,3,0], 'atender_id':['BB33','AA12','BB33'], 
        'ten_region_1':[0,0,0],'ten_region_2':[1,0,1], 
        'ten_region_3':[1,1,1],'ten_cat_1':[0,1,0], 
        'ten_cat_2':[1,0,1],'ten_cat_3':[1,0,1], 
        'ten_cat_4':[0,0,0]}) 

Antwort

2

Code

# the first columns of each dataframe are the ids 
# i'm going to use them several times 
tid = tender_data.values[:, 0] 
pid = prov_data.values[:, 0] 
# first columns [1, 2, 3, 4] are cat columns 
# we could have used filter, but this is good 
# for this example 
pc = prov_data.values[:, 1:5] 
tc = tender_data.values[:, 1:5] 
# columns [5, 6, 7] are rgn columns 
pr = prov_data.values[:, 5:] 
tr = tender_data.values[:, 5:] 

# I want to mave this an m x n array, where 
# m = number of rows in prov df and n = rows in tender 
nm = no_match.groupby(['prov_id', 'tender_id']).size().unstack() 
nm = nm.reindex_axis(tid, 1).reindex_axis(pid, 0) 
nm = ~nm.fillna(0).astype(bool).values * 1 

# the dot products of the cat arrays gets a handy 
# array where there are > 1 co-positive values 
# this combined with the a no_match construct 
a = pd.DataFrame(pc.dot(tc.T) * pr.dot(tr.T) * nm > 0, pid, tid) 
a = a.mask(~a).stack().index 

fp = a.get_level_values(0) 
ft = a.get_level_values(1) 

pd.concat([ 
     prov_data.set_index('aprov_id').loc[fp].reset_index(), 
     tender_data.set_index('atender_id').loc[ft].reset_index() 
    ], axis=1) 


    index prov_cat_1 prov_cat_2 prov_cat_3 prov_cat_4 prov_region_1 \ 
0 1122   0   1   0   0    0 
1 3344   2   0   0   3    0 
2 7788   0   0   4   0    0 

    prov_region_2 prov_region_3 atender_id ten_cat_1 ten_cat_2 ten_cat_3 \ 
0    2    0  BB33   0   1   1 
1    0    1  AA12   1   0   0 
2    0    1  BB33   0   1   1 

    ten_cat_4 ten_region_1 ten_region_2 ten_region_3 
0   0    0    1    1 
1   0    0    0    1 
2   0    0    1    1 

Erklärung

  • Verwendung Punktprodukte Streichhölzer
  • viele andere Dinge, um zu bestimmen, werde ich versuchen, mehr später
+0

danke! Dies funktionierte perfekt, die ursprünglichen dfs sind 600K x 75, also ist dies eine sehr gute Option. – castor

+0

Ich bekomme tatsächlich einen Exit-Code 137, nachdem ich ihn mit den ursprünglichen Datenframes ausgeführt habe. Ich denke, das Hauptproblem ist die no_match DF, die 600K Zeilen hat. Die Provider-Matrix hat 43K und die Ausschreibung Matrix 140K ... irgendwelche Ideen @piRSquared? – castor

+0

http: // Stapelüberlauf.com/a/1041309/2336654 Wenn dieser Link korrekt ist, vermute ich, dass Sie auf einem Server laufen, auf dem ein Administrator Ihr Skript beendet hat. – piRSquared

0

Einfache Lösung zu erklären, dass nur „Standard“ pandas Techniken verwendet.

prov_data['tkey'] = 1 
tender_data['tkey'] = 1 
df1 = pd.merge(prov_data,tender_data,how='outer',on='tkey') 
df1 = pd.merge(df1,no_match,how='outer',left_on = 'aprov_id', right_on = 'prov_id') 
df1['dropData'] = df1.apply(lambda x: True if x['tender_id'] == x['atender_id'] else False, axis=1) 
df1['dropData'] = df1.apply(lambda x: (x['dropData'] == True) or not(
            ((x['prov_cat_1'] > 0 and x['ten_cat_1'] > 0) or 
             (x['prov_cat_2'] > 0 and x['ten_cat_2'] > 0) or 
             (x['prov_cat_3'] > 0 and x['ten_cat_3'] > 0) or 
             (x['prov_cat_4'] > 0 and x['ten_cat_4'] > 0)) and(
             (x['prov_region_1'] > 0 and x['ten_region_1'] > 0) or 
             (x['prov_region_2'] > 0 and x['ten_region_2'] > 0) or 
             (x['prov_region_3'] > 0 and x['ten_region_3'] > 0))),axis=1) 
df1 = df1[~df1.dropData] 
df1 = df1[[u'aprov_id', u'atender_id', u'prov_cat_1', u'prov_cat_2', u'prov_cat_3', 
      u'prov_cat_4', u'prov_region_1', u'prov_region_2', u'prov_region_3', 
      u'ten_cat_1', u'ten_cat_2', u'ten_cat_3', u'ten_cat_4', u'ten_region_1', 
      u'ten_region_2', u'ten_region_3']].reset_index(drop=True) 

print df1.equals(df) 

Zuerst wir eine vollständige Kreuzprodukt beiden Datenrahmen und zusammenführen, dass mit dem no_match Datenrahmen, dann eine Boolesche Spalte hinzufügen alle Zeilen zu markieren, fallen gelassen werden.

Die boolesche Spalte wird von zwei booleschen Lambda-Funktionen mit allen notwendigen Bedingungen zugewiesen, dann nehmen wir einfach alle Zeilen, in denen diese Spalte ist False.

Diese Lösung ist aufgrund der Zusammenführungsvorgänge nicht sehr ressourcenschonend. Wenn Ihre Daten sehr groß sind, kann dies nachteilig sein.

+0

danke! Ja, mein ursprünglicher DF hat 600.000 Zeilen und 76 Spalten, also ist die erste Option praktikabler. Wie Sie gesagt haben, ist seine eine gute direkte Option. – castor

Verwandte Themen