2017-02-17 1 views
1

Ich habe eine große (ish) Reihe experimenteller Daten, die Wertepaare enthalten, die einem bestimmten Barcode zugeordnet sind. Im Idealfall sollte jedes Paar einen eindeutigen Barcode haben. Leider stellt sich heraus, dass ich während des Experiments etwas vermasselt habe und mehrere Paare einen einzigen Barcode teilen. Ich muss diese Paare/Barcodes aus meiner Analyse ausschließen.Auswählen von Zeilen, die nur einen gemeinsamen Wert haben, aber keine gemeinsamen Werte im Pandas-Datenrahmen

Meine Daten wie diese Art von aussehen:

Die Paare sind in den Spalten 'A' und 'B' - ich gerade enthalten 'X' etwas willkürlich zugeordneten Daten zu repräsentieren:

df = pd.DataFrame({'Barcode' : ['AABBCC', 'AABBCC', 'BABACC', 'AABBCC', 'DABBAC', 'ABDABD', 'DABBAC'], 
       'A' : ['v', 'v', 'x', 'y', 'z', 'h', 'z'], 
       'B' : ['h', 'h', 'j', 'k', 'l', 'v', 'l'], 
       'X' : np.random.randint(10, size = 7)}) 
df = df[['Barcode', 'A', 'B', 'X']] 
df 

    Barcode A B X 
0 AABBCC v h 8 
1 AABBCC v h 7 
2 BABACC x j 2 
3 AABBCC y k 3 
4 DABBAC z l 8 
5 ABDABD h v 0 
6 DABBAC z l 4 

Ich möchte die mit dem Barcode 'AABBCC' beschriebenen Zeilen loswerden, da dieser Barcode zwei verschiedenen Paaren zugeordnet ist (die Zeilen 0 und 1 sind beide das gleiche Paar - was gut ist - aber Zeile 3 ist ein anderes Paar) .

df.loc[df.Barcode != 'AABBCC'] 

    Barcode A B X 
2 BABACC x j 6 
4 DABBAC z l 0 
5 ABDABD h v 7 
6 DABBAC z l 5 

Meine Lösung so weit:

def duplicates(bar): 
    if len(df.loc[df.Barcode == bar].A.unique()) > 1 or len(df.loc[df.Barcode == bar].B.unique()) > 1: 
     return 'collision' 
    else: 
     return 'single' 

df['Barcode_collision'] = df.apply(lambda row: duplicates(row['Barcode']), axis = 1) 
df.loc[df.Barcode_collision == 'single'] 

    Barcode A B X Barcode_collision 
2 BABACC x j 6 single 
4 DABBAC z l 0 single 
5 ABDABD h v 7 single 
6 DABBAC z l 5 single 

Leider ist dies sehr langsam mit einem großen Datenrahmen (~ 500.000 Zeilen) meine zarten Computer. Ich bin mir sicher, dass es einen besseren/schnelleren Weg geben muss. Vielleicht mit der groupby Funktion?

df.groupby(['Barcode', 'A', 'B']).count() 

       X 
Barcode A B 
AABBCC v h 2 
     y k 1 
ABDABD h v 1 
BABACC x j 1 
DABBAC z l 2 

Dann Zeilen filtern, die mehr als einen Wert im zweiten oder dritten Index haben? Aber mein Gehirn und mein googeln Fähigkeiten kann nicht scheinen, um mich weiter als diese ...

Antwort

1

Sie filter verwenden können:

print(df.groupby('Barcode').filter(lambda x: ((x.A.nunique() == 1) or (x.B.nunique() == 1)))) 

    Barcode A B X Barcode_collision 
2 BABACC x j 4   single 
4 DABBAC z l 9   single 
5 ABDABD h v 3   single 
6 DABBAC z l 9   single 

Eine andere Lösung mit transform und boolean indexing:

g = df.groupby('Barcode') 
A = g.A.transform('nunique') 
B = g.B.transform('nunique') 

print (df[(A == 1) | (B == 1)]) 
    Barcode A B X Barcode_collision 
2 BABACC x j 2   single 
4 DABBAC z l 6   single 
5 ABDABD h v 1   single 
6 DABBAC z l 3   single 
+0

fantastisch ! das ist wesentlich schneller. Vielen Dank! – Ben

+0

Nicht 100% sicher, aber zweite Lösung kann schneller sein, bitte testen Sie es. – jezrael

+0

auf meiner Maschine sieht es aus wie die erste Lösung ist etwa 30% schneller – Ben

Verwandte Themen