Rilascia le righe contenenti celle vuote da un DataFrame panda


92

Ho un pd.DataFrameche è stato creato analizzando alcuni fogli di calcolo Excel. Una colonna di cui ha celle vuote. Ad esempio, di seguito è riportato l'output per la frequenza di quella colonna, 32320 record hanno valori mancanti per Tenant .

>>> value_counts(Tenant, normalize=False)
                              32320
    Thunderhead                8170
    Big Data Others            5700
    Cloud Cruiser              5700
    Partnerpedia               5700
    Comcast                    5700
    SDP                        5700
    Agora                      5700
    dtype: int64

Tuttavia, sto tentando di eliminare le righe in cui manca Tenant .isnull() opzione non riconosce i valori mancanti.

>>> df['Tenant'].isnull().sum()
    0

La colonna ha il tipo di dati "Oggetto". Cosa sta succedendo in questo caso? Come posso rilasciare record in cui manca Tenant ?

Risposte:


179

Pandas riconoscerà un valore come null se si tratta di un np.nanoggetto, che verrà stampato come NaNnel DataFrame. I tuoi valori mancanti sono probabilmente stringhe vuote, che Pandas non riconosce come nulle. Per risolvere questo problema, puoi convertire le punture vuote (o qualsiasi cosa si trovi nelle tue celle vuote) in np.nanoggetti usando replace()e quindi chiamaredropna() il tuo DataFrame per eliminare le righe con tenant nulli.

Per dimostrare, creiamo un DataFrame con alcuni valori casuali e alcune stringhe vuote in una Tenantscolonna:

>>> import pandas as pd
>>> import numpy as np
>>> 
>>> df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
>>> df['Tenant'] = np.random.choice(['Babar', 'Rataxes', ''], 10)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239         
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214         
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640         

Ora sostituiamo eventuali stringhe vuote nella Tenantscolonna con np.nanoggetti, in questo modo:

>>> df['Tenant'].replace('', np.nan, inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239      NaN
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214      NaN
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640      NaN

Ora possiamo eliminare i valori nulli:

>>> df.dropna(subset=['Tenant'], inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes

Grazie mille, proverò e tornerò!
Amrita Sawant

2
@mcmath, un po 'curioso. Perché importi numpy e usi np.nanquando puoi farlo pd.np.nan?
propjk007

3
@ propjk007, come per molte cose nella vita, ci sono molti modi per fare molte cose
andrew

Dai miei test , sembra che df[df['Tenant'].astype(bool)](assumendo che non ci siano caratteri di spazio vuoto - solo stringa vuota) è più veloce didf.replace('', np.nan).dropna(subset=['Tenant'])
cs95

53

Pythonic + Pandorable: df[df['col'].astype(bool)]

Le stringhe vuote sono false, il che significa che puoi filtrare i valori bool in questo modo:

df = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})
df
   A    B
0  0  foo
1  1     
2  2  bar
3  3     
4  4  xyz
df['B'].astype(bool)                                                                                                                      
0     True
1    False
2     True
3    False
4     True
Name: B, dtype: bool

df[df['B'].astype(bool)]                                                                                                                  
   A    B
0  0  foo
2  2  bar
4  4  xyz

Se il tuo obiettivo è rimuovere non solo le stringhe vuote, ma anche le stringhe che contengono solo spazi bianchi, usa in str.stripanticipo:

df[df['B'].str.strip().astype(bool)]
   A    B
0  0  foo
2  2  bar
4  4  xyz

Più veloce di quanto pensi

.astypeè un'operazione vettorizzata, è più veloce di ogni opzione presentata finora. Almeno, dai miei test. YMMV.

Ecco un confronto temporale, ho inserito altri metodi a cui potrei pensare.

inserisci qui la descrizione dell'immagine

Codice di benchmarking, per riferimento:

import pandas as pd
import perfplot

df1 = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})

perfplot.show(
    setup=lambda n: pd.concat([df1] * n, ignore_index=True),
    kernels=[
        lambda df: df[df['B'].astype(bool)],
        lambda df: df[df['B'] != ''],
        lambda df: df[df['B'].replace('', np.nan).notna()],  # optimized 1-col
        lambda df: df.replace({'B': {'': np.nan}}).dropna(subset=['B']),  
    ],
    labels=['astype', "!= ''", "replace + notna", "replace + dropna", ],
    n_range=[2**k for k in range(1, 15)],
    xlabel='N',
    logx=True,
    logy=True,
    equality_check=pd.DataFrame.equals)

34

value_counts omette NaN per impostazione predefinita, quindi molto probabilmente hai a che fare con "".

Quindi puoi semplicemente filtrarli come

filter = df["Tenant"] != ""
dfNew = df[filter]

1
La soluzione di @Bobs non ha funzionato per me. df.dropna (subset = ['tenant'], inplace = True) funziona.
Amrita Sawant

1
Mi dispiace per quello. Pensavo avessi a che fare con "" s. Dovresti pubblicare la tua soluzione come risposta
Bob Haffner

9

C'è una situazione in cui la cella ha uno spazio bianco, non puoi vederlo, usa

df['col'].replace('  ', np.nan, inplace=True)

per sostituire lo spazio bianco come NaN, quindi

df= df.dropna(subset=['col'])

5

Puoi usare questa variazione:

import pandas as pd
vals = {
    'name' : ['n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7'],
    'gender' : ['m', 'f', 'f', 'f',  'f', 'c', 'c'],
    'age' : [39, 12, 27, 13, 36, 29, 10],
    'education' : ['ma', None, 'school', None, 'ba', None, None]
}
df_vals = pd.DataFrame(vals) #converting dict to dataframe

Questo produrrà (** - evidenziando solo le righe desiderate):

   age education gender name
0   39        ma      m   n1 **
1   12      None      f   n2    
2   27    school      f   n3 **
3   13      None      f   n4
4   36        ba      f   n5 **
5   29      None      c   n6
6   10      None      c   n7

Quindi, per eliminare tutto ciò che non ha un valore di "istruzione", utilizza il codice seguente:

df_vals = df_vals[~df_vals['education'].isnull()] 

('~' indica NON)

Risultato:

   age education gender name
0   39        ma      m   n1
2   27    school      f   n3
4   36        ba      f   n5

0

Se non ti interessano le colonne dove si trovano i file mancanti, considerando che il dataframe ha il nome Newe si vuole assegnare il nuovo dataframe alla stessa variabile, basta eseguire

New = New.drop_duplicates()

Se si desidera rimuovere specificamente le righe per i valori vuoti nella colonna, Tenantquesto farà il lavoro

New = New[New.Tenant != '']

Questo può anche essere usato per rimuovere righe con un valore specifico: basta cambiare la stringa con il valore che si desidera.

Nota : se invece di una stringa vuota si ha NaN, allora

New = New.dropna(subset=['Tenant'])
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.