Come filtrare le righe nei panda per regex


169

Vorrei filtrare in modo pulito un dataframe usando regex su una delle colonne.

Per un esempio inventato:

In [210]: foo = pd.DataFrame({'a' : [1,2,3,4], 'b' : ['hi', 'foo', 'fat', 'cat']})
In [211]: foo
Out[211]: 
   a    b
0  1   hi
1  2  foo
2  3  fat
3  4  cat

Voglio filtrare le righe su quelle che iniziano con l' fuso di una regex. Primo passo:

In [213]: foo.b.str.match('f.*')
Out[213]: 
0    []
1    ()
2    ()
3    []

Non è molto utile. Tuttavia, questo mi farà ottenere il mio indice booleano:

In [226]: foo.b.str.match('(f.*)').str.len() > 0
Out[226]: 
0    False
1     True
2     True
3    False
Name: b

Quindi potrei quindi fare la mia limitazione:

In [229]: foo[foo.b.str.match('(f.*)').str.len() > 0]
Out[229]: 
   a    b
1  2  foo
2  3  fat

Questo però mi fa mettere artificialmente un gruppo nella regex e sembra che forse non sia la strada pulita da percorrere. C'è un modo migliore per farlo?


5
Se non sei sposato con le regex, foo[foo.b.str.startswith("f")]funzionerà.
DSM

Penso che foo[foo.b.str.match('(f.*)').str.len() > 0]sia una soluzione abbastanza buona! Più personalizzabile e utile di startwith perché racchiude in sé la versatilità di regex.
tumultous_rooster,

3
questo potrebbe essere un po 'tardi, ma nelle versioni più recenti di Panda, il problema è stato risolto. la linea foo[foo.b.str.match('f.*')]funziona in panda 0.24.2 per me.
Behzad Mehrtash,

Risposte:



24

Esiste già una funzione di gestione delle stringhe Series.str.startswith(). Dovresti provare foo[foo.b.str.startswith('f')].

Risultato:

    a   b
1   2   foo
2   3   fat

Penso a cosa ti aspetti.

In alternativa puoi usare contiene con l'opzione regex. Per esempio:

foo[foo.b.str.contains('oo', regex= True, na=False)]

Risultato:

    a   b
1   2   foo

na=False è prevenire errori nel caso ci siano valori nan, null ecc


L'ho modificato e ha funzionato per medf[~df.CITY.str.contains('~.*', regex= True, na=False)]
Patty Jula il

Grazie! questa è un'ottima soluzione
Kedar Joshi il

20

Ricerca in più colonne con dataframe:

frame[frame.filename.str.match('*.'+MetaData+'.*') & frame.file_path.str.match('C:\test\test.txt')]

2
frame? e 'C:\test\test.txt'? Sembra che tu stia rispondendo a una domanda diversa.
tumultous_rooster il

il frame è df. è correlato alla stessa domanda, ma risponde come filtrare più colonne ("nomefile" e "percorso_file") in un codice di riga.
lakshman senathirajah,

12

Questo potrebbe essere un po 'in ritardo, ma ora è più facile da fare in Panda. Puoi chiamare match with as_indexer=Trueper ottenere risultati booleani. Questo è documentato (insieme alla differenza tra matche contains) qui .


11

Grazie per l'ottima risposta @ user3136169, ecco un esempio di come ciò potrebbe essere fatto anche rimuovendo i valori di NoneType.

def regex_filter(val):
    if val:
        mo = re.search(regex,val)
        if mo:
            return True
        else:
            return False
    else:
        return False

df_filtered = df[df['col'].apply(regex_filter)]

Inoltre puoi anche aggiungere regex come arg:

def regex_filter(val,myregex):
    ...

df_filtered = df[df['col'].apply(res_regex_filter,regex=myregex)]

1
grazie, per questo ho escogitato un modo per filtrare una colonna per predicato arbitrario.
Jman

9

Scrivi una funzione booleana che controlla il regex e usa applica sulla colonna

foo[foo['b'].apply(regex_function)]

1

Usando la str fetta

foo[foo.b.str[0]=='f']
Out[18]: 
   a    b
1  2  foo
2  3  fat
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.