2017-10-31 1 views
2

I-Daten habe, die wie folgt aussehen:halten alle Zeilen in der Gruppe, wenn eine Zeile einen angegebenen Teil Pandas enthält

ID#  DATE  TEXT 
    1  1/1/2017 ENTERED BY A 
    1  1/1/2017 BLAH BLAH BLAH 
    1  1/2/2017 ENTERED BY B 
    1  1/2/2017 BLAH BLAH BLAH 
    1  1/2/2017 BLAH BLAH BLAH 
    2  1/4/2017 SUPPLEMENTAL PAYMENT BY A 
    2  1/4/2017 BLAH BLAH BLAH 
    3  1/1/2017 ENTERED BY C 
    3  1/2/2017 CHANGED COMPANY NAME 
    3  1/2/2017 BLAH BLAH BLAH 

Ich versuche, die Daten von ID # und DATE und kehre alle Zeilen Gruppe Wenn eine Gruppe (in diesem Fall gruppiere ich die Groß-/Kleinschreibung ID und DATE) eine Textübereinstimmung hat.

Hier ist, was ich bisher habe. Der folgende Code versucht, jede Zeile in dem TEXT-Feld für die Teilzeichenfolge "ENTER BY" zu durchsuchen und alle Zeilen zurückzugeben, die dieser Gruppe zugeordnet werden.

notes[notes.groupby('ID#','DATE',as_index=False).apply(lambda x: x['TEXT'].str.contains('ENTERED BY'))] 

Ich habe auch Variationen von group.filter versucht() mit ähnlichen Ergebnissen. Wer kann mich in die richtige Richtung weisen? Mein Ausgabesatz sollte so aussehen:

ID#  DATE  TEXT 
    1  1/1/2017 ENTERED BY A 
    1  1/1/2017 BLAH BLAH BLAH 
    1  1/2/2017 ENTERED BY B 
    1  1/2/2017 BLAH BLAH BLAH 
    1  1/2/2017 BLAH BLAH BLAH 
    3  1/1/2017 ENTERED BY C 

Danke!

Antwort

2

können Sie verwenden groupby + transform mit any und dann filtern, indem boolean indexing:

df=df[df['TEXT'].str.contains('ENTERED BY').groupby([df['ID#'],df['DATE']]).transform('any')] 
print (df) 
    ID#  DATE   TEXT 
0 1 1/1/2017 ENTERED BY A 
1 1 1/1/2017 BLAH BLAH BLAH 
2 1 1/2/2017 ENTERED BY B 
3 1 1/2/2017 BLAH BLAH BLAH 
4 1 1/2/2017 BLAH BLAH BLAH 
7 3 1/1/2017 ENTERED BY C 

Detail:

print (df['TEXT'].str.contains('ENTERED BY')) 
0  True 
1 False 
2  True 
3 False 
4 False 
5 False 
6 False 
7  True 
8 False 
9 False 
Name: TEXT, dtype: bool 

print(df['TEXT'].str.contains('ENTERED BY').groupby([df['ID#'],df['DATE']]).transform('any')) 
0  True 
1  True 
2  True 
3  True 
4  True 
5 False 
6 False 
7  True 
8 False 
9 False 
Name: TEXT, dtype: bool 

Eine weitere schnellere Lösung ist Filter alle ID# und DATE mit drop_duplicates und merge:

df=df.loc[df['TEXT'].str.contains('ENTERED BY'), ['ID#','DATE']].drop_duplicates().merge(df) 
print (df) 
    ID#  DATE   TEXT 
0 1 1/1/2017 ENTERED BY A 
1 1 1/1/2017 BLAH BLAH BLAH 
2 1 1/2/2017 ENTERED BY B 
3 1 1/2/2017 BLAH BLAH BLAH 
4 1 1/2/2017 BLAH BLAH BLAH 
5 3 1/1/2017 ENTERED BY C 

Detail:

print (df.loc[df['TEXT'].str.contains('ENTERED BY'), ['ID#','DATE']].drop_duplicates()) 
    ID#  DATE 
0 1 1/1/2017 
2 1 1/2/2017 
7 3 1/1/2017 

Timings:

np.random.seed(123) 
N = 100000 

L = ['AV','DF','SD','RF','F','WW','FG','SX'] 
dates = pd.date_range('2015-01-01', '2015-02-20') 
df = pd.DataFrame({'TEXT': np.random.choice(L, N), 
        'ID#':np.random.randint(3000, size=N), 
        'DATE': np.random.choice(dates, N)}) 
     .sort_values(['ID#','DATE']).reset_index(drop=True) 
#print (df) 

In [375]: %timeit df.loc[df['TEXT'].str.contains('A'), ['ID#','DATE']].drop_duplicates().merge(df) 
10 loops, best of 3: 96.1 ms per loop 

In [376]: %timeit df[df['TEXT'].str.contains('A').groupby([df['ID#'],df['DATE']]).transform('any')] 
1 loop, best of 3: 6.56 s per loop 

#Wen solution 
In [377]: %timeit df.groupby(['ID#','DATE'],as_index=False).filter(lambda x : x.TEXT.str.contains('A').sum().any()) 
1 loop, best of 3: 30.1 s per loop 
Verwandte Themen