2013-11-26 29 views
14

Ho un dataframe che può avere o meno colonne con lo stesso valore. Per esempiopanda dataframe rimuovi colonna costante

row A B 
    1  9 0 
    2  7 0 
    3  5 0 
    4  2 0 

mi piacerebbe tornare solo

row A 
    1  9  
    2  7  
    3  5  
    4  2 

C'è un modo semplice per identificare se uno qualsiasi di queste colonne esistono e poi rimuoverli?

risposta

20

Credo che questa opzione sarà più veloce rispetto alle altre risposte qui come sarà attraversare il frame di dati una sola volta per il confronto e il corto circuito se viene trovato un valore non univoco.

>>> df 

    0 1 2 
0 1 9 0 
1 2 7 0 
2 3 7 0 

>>> df.loc[:, (df != df.iloc[0]).any()] 

    0 1 
0 1 9 
1 2 7 
2 3 7 
+2

Aargh a: '<>'. –

+0

@AndyHayden Le abitudini Pascal sono dure a morire. L'ho cambiato – chthonicdaemon

+0

+1 grazie per il cambio. Questo cortocircuito sul any, dopo che ha già fatto il confronto! = Su ogni elemento, quindi la soluzione del DSM sarà probabilmente più efficiente ... chiedo se la migliore soluzione di corto circuito. –

13

Ignorando come al solito NaN, una colonna è costante se nunique() == 1. Quindi:

>>> df 
    A B row 
0 9 0 1 
1 7 0 2 
2 5 0 3 
3 2 0 4 
>>> df = df.loc[:,df.apply(pd.Series.nunique) != 1] 
>>> df 
    A row 
0 9 1 
1 7 2 
2 5 3 
3 2 4 
+0

'df.apply (pd.Series.nunique)' è più semplicemente 'df.nunique()', in Pandas 0.20.3 almeno. – EOL

+0

E se vogliamo che NaN sia considerato come un valore univoco, 'df.nunique (dropna = False)' funziona bene (gestisce il fatto che NaN ≠ NaN come ci aspettiamo, contando tutti i valori NaN come lo stesso valore anche se essi non sono uguali). – EOL

2

Supponendo che la dataframe è completamente di tipo numerico:

si può provare:

>>> df = df.loc[:, df.var() == 0.0] 

che rimuoverà costante colonne (cioè varianza = 0.).

Se la dataframe è di tipo sia numerica e oggetto, quindi si dovrebbe provare:

>>> enum_df = df.select_dtypes(include=['object']) 
>>> num_df = df.select_dtypes(exclude=['object']) 
>>> num_df = num_df.loc[:, num_df.var() == 0.0] 
>>> df = pd.concat([num_df, enum_df], axis=1) 

che cadrà colonne continue di solo tipo numerico.

Se anche voi volete ignorare/eliminare colonne enum costanti, si dovrebbe provare:

>>> enum_df = df.select_dtypes(include=['object']) 
>>> num_df = df.select_dtypes(exclude=['object']) 
>>> enum_df = enum_df.loc[:, [True if y !=1 else False for y in [len(np.unique(x, return_counts=True)[-1]) for x in enum_df.T.as_matrix()]]] 
>>> num_df = num_df.loc[:, num_df.var() == 0.0] 
>>> df = pd.concat([num_df, enum_df], axis=1) 
+0

Probabilmente vorrai 'df = df.loc [:, ~ df.var() == 0.0]' altrimenti stai selezionando le 0 colonne. Probabilmente vale anche la pena di fare 'np.isclose (0, df.var())' per possibili errori in virgola mobile – jeremycg

0

Ecco la mia soluzione in quanto avevo bisogno di fare entrambe le cose oggetto e colonne numeriche. Non rivendicare il suo super efficiente o altro, ma ottiene il lavoro fatto.

def drop_constants(df): 
    """iterate through columns and remove columns with constant values (all same)""" 
    columns = df.columns.values 
    for col in columns: 
     # drop col if unique values is 1 
     if df[col].nunique(dropna=False) == 1: 
      del df[col] 
    return df 

Caveat supplementare, non funzionerà su colonne di elenchi o matrici poiché non sono lavabili.

Problemi correlati