2016-03-21 22 views
1

Ich habe einen großen Pandas-Datenrahmen (> 1 Million Zeilen), den ich aus einer SQL Server-Datenbank abgerufen habe. In einigen wenigen Fällen enthalten einige Datensätze doppelte Einträge. Alle Zellen sind bis auf ein einzelnes Textfeld identisch. Es sieht so aus, als wäre der Datensatz in die Datenbank eingegeben worden, und zu einem späteren Zeitpunkt wurde dem Feld zusätzlicher Text hinzugefügt und der Datensatz als separater Eintrag in der Datenbank gespeichert. Im Grunde möchte ich nur den Datensatz mit der längsten Textzeichenfolge behalten. Eine vereinfachte Version der Datenbank kann wie folgt erstellt werden:Löschen von Zeilen aus Pandas-Datenrahmen basierend auf groupby-Werten

tempDF = pd.DataFrame({ 'recordID': [1,2,3,3,4,5,6,6,6,7,7,8,9,10], 
         'text': ['abc', 'def', 'ghi', 'ghijkl', 'mto', 'per', 'st', 'stuvw', 'stuvwx', 'yz', 'yzab', 'cde', 'fgh', 'ijk']}) 

die wie folgt aussieht: Bisher hat ich identifiziere die Zeilen mit doppelter recordID und berechnet die Länge des Textes

recordID text 
0   21  abc 
1   22  def 
2   23  ghi 
3   23 ghijkl 
4   24  mno 
5   25  pqr 
6   26  st 
7   26 stuvw 
8   26 stuvwx 
9   27  yz 
10  27 yzab 
11  28  cde 
12  29  fgh 
13  30  ijk 

Feld:

tempDF['dupl'] = tempDF.duplicated(subset = 'recordID',keep=False) 
tempDF['texLen'] = tempDF['text'].str.len() 
print(tempDF) 

Zur Herstellung:

recordID text dupl texLen 
0   21  abc False  3 
1   22  def False  3 
2   23  ghi True  3 
3   23 ghijkl True  6 
4   24  mno False  3 
5   25  pqr False  3 
6   26  st True  2 
7   26 stuvw True  5 
8   26 stuvwx True  6 
9   27  yz True  2 
10  27 yzab True  4 
11  28  cde False  3 
12  29  fgh False  3 
13  30  ijk False  3 

kann ich alle dupl == Wahre Aufzeichnungen GROUPBY basierend auf recordID mit:

tempGrouped = tempDF[tempDF['dupl']==True].groupby('recordID') 

und separat aus jeder Gruppe drucken:

for name, group in tempGrouped: 
    print('n',name) 
    print(group) 

23 
    recordID text dupl texLen 
2  23  ghi True  3 
3  23 ghijkl True  6 

26 
    recordID text dupl texLen 
6  26  st True  2 
7  26 stuvw True  5 
8  26 stuvwx True  6 

27 
    recordID text dupl texLen 
9   27 yz True  2 
10  27 yzab True  4 

ich die letzte Datenrahmen dieser Datensätze bestehen wollen, wo dupl == False und, wenn dupl == True, sollte nur das Replikat mit dem längsten Textfeld beibehalten werden. So sollte die letzte Datenrahmen wie folgt aussehen:

recordID text dupl texLen 
0   21  abc False  3 
1   22  def False  3 
3   23 ghijkl True  6 
4   24  mno False  3 
5   25  pqr False  3 
8   26 stuvwx True  6 
10  27 yzab True  4 
11  28  cde False  3 
12  29  fgh False  3 
13  30  ijk False  3 

Wie kann ich aus dem ursprünglichen Datenrahmen löschen nur die Zeilen, in denen recordID dupliziert und wo TEXLEN ist kleiner als das Maximum?

Antwort

1

Sie versuchen Indizes mit max Werte von idxmax, concat mit False Werte in dupl Spalte und letzte sort_index finden:

idx = tempDF[tempDF['dupl']==True].groupby('recordID')['texLen'].idxmax() 

print tempDF.loc[idx] 
    recordID text dupl texLen 
3   23 ghijkl True  6 
8   26 stuvwx True  6 
10  27 yzab True  4 

print pd.concat([tempDF[tempDF['dupl']==False], tempDF.loc[idx]]).sort_index(0) 
    recordID text dupl texLen 
0   21  abc False  3 
1   22  def False  3 
3   23 ghijkl True  6 
4   24  mto False  3 
5   25  per False  3 
8   26 stuvwx True  6 
10  27 yzab True  4 
11  28  cde False  3 
12  29  fgh False  3 
13  30  ijk False  3 

Die simplier Lösung Gebrauch sort_values und first, weil Reihen mit False einzigartigen haben recordID (sind NICHT doppelt):

df=tempDF.sort_values(by="texLen", ascending=False).groupby("recordID").first().reset_index() 
print df 
    recordID text dupl texLen 
0  21  abc False  3 
1  22  def False  3 
2  23 ghijkl True  6 
3  24  mto False  3 
4  25  per False  3 
5  26 stuvwx True  6 
6  27 yzab True  4 
7  28  cde False  3 
8  29  fgh False  3 
9  30  ijk False  3 
+0

Mit sort_values ​​() und zuerst() ist eine wirklich nette Lösung. Ich habe vorher nicht() benutzt, also ist das ein großartiger Fund. Vielen Dank. – user1718097

Verwandte Themen