Tengo un pandas dataframe con pocas columnas.

Ahora sé que ciertas filas de los valores atípicos sobre la base de un valor de la columna.

Por ejemplo columnas – ‘Vol’ tiene todos los valores alrededor de 12xx y un valor es de 4000 (Outlier).

Ahora me gustaría excluir aquellas filas que se han ‘Vol’ Columna como esta.
Así que, básicamente tengo que poner un filtro en el marco de datos de tal manera que podamos seleccionar todas las filas donde los valores de una determinada columna de decir dentro de 3 desviaciones estándar de la media.

¿Qué es una elegante manera de lograr esto.

InformationsquelleAutor AMM | 2014-04-21

17 Comentarios

  1. 161

    Si usted tiene varias columnas en su dataframe y quisiera eliminar todas las filas que tienen valores extremos en al menos una columna, la siguiente expresión hacerlo en una sola toma.

    df = pd.DataFrame(np.random.randn(100, 3))
    
    from scipy import stats
    df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]

    descripción:

    • Para cada columna, en primer lugar se calcula el puntaje Z de cada valor en el
      columna, relativa a la columna media y la desviación estándar.
    • A continuación, se toma el absoluto de Z-score porque la dirección no
      importa, sólo si está por debajo del umbral.
    • todos(eje=1) asegura que para cada fila, columna de satisfacer la
      la restricción.
    • Finalmente, el resultado de esta condición se utiliza para indexar el dataframe.
    • Puede usted explicar lo que este código está haciendo? Y tal vez proporcione una idea de cómo podría eliminar todas las filas que tienen un valor atípico en una sola columna especificada? Sería de gran ayuda. Gracias.
    • Para cada columna, en primer lugar se calcula el puntaje Z de cada valor de la columna, relativa a la columna media y la desviación estándar. A continuación, se toma el absoluto de Z-score porque la dirección no importa, sólo si está por debajo del umbral. .todos(eje=1) asegura que para cada fila, columna cumple la restricción. Finalmente, el resultado de esta condición se utiliza para indexar el dataframe.
    • Todavía la solución más elegante aquí.
    • Cómo iba a manejar la situación cuando hay valores Nulos/Nan en las columnas. ¿Cómo podemos tener ignoraron ?
    • ¿cómo lidiar con la str columnas para esta solución? Si algunas de las columnas no son numéricos y de que desea eliminar los outliers basado en todas las columnas numéricas.
    • ¿Cuál es el significado de 3 en el código anterior, se puede explicar eso?
    • suponiendo que la distribución de X con mu media y la desviación estándar sigma, la puntuación z mide cuántos sigmas un valor de mu. algebraicamente: z-score = (x – mu) / sigma. el 3 es el umbral en el número de desviaciones estándar de distancia de la media.
    • Conciso y elegante para todo el conjunto de datos de los atributos. Me gusta. Me he tomado la libertad de extender su respuesta (ver más abajo) para manejar una base de datos-marco de lo que podría contener también valores no numéricos. La esperanza puede ayudar a alguien.
    • Ha obtenido un error: «TypeError: no admitidos operando tipo(s) para el /: ‘str’ y ‘int'»

  2. 127

    Uso boolean de indización, como haría en numpy.array

    df = pd.DataFrame({'Data':np.random.normal(size=200)})
    # example dataset of normally distributed data. 
    
    df[np.abs(df.Data-df.Data.mean()) <= (3*df.Data.std())]
    # keep only the ones that are within +3 to -3 standard deviations in the column 'Data'.
    
    df[~(np.abs(df.Data-df.Data.mean()) > (3*df.Data.std()))]
    # or if you prefer the other way around

    Para una serie es similar:

    S = pd.Series(np.random.normal(size=200))
    S[~((S-S.mean()).abs() > 3*S.std())]
    • su es un DataFrame.abs() FYI, también DataFrame.clip()
    • En el caso de clip(), Jeff, los contornos no son removidos: df.SOME_DATA.clip(-3std,+3std) asignar el outliners a +3std o -3std
    • oh, estoy de acuerdo; sólo señalándolo.
    • Lo que si necesito hte mismo en un ep.De la serie?
    • Que es casi lo mismo, @AMM
    • ¿Cómo podemos hacer la misma cosa si nuestros pandas marco de datos tiene más de 100 columnas?
    • Impresionante, gracias por la respuesta @CTZhu. @DreamerP sólo puede aplicar a todo el DataFrame con: df_new = df[np.abs(df - df.mean()) <= (3 * df.std())]. Pero en contraste con la aplicación de la misma a una Serie o de una sola columna, esto reemplazará los valores atípicos con np.nan y mantener la forma de la DataFrame, por lo que la interpolación puede ser necesaria para completar los valores que faltan.

  3. 69

    Para cada uno de sus dataframe columna, usted puede obtener los cuantiles con:

    q = df["col"].quantile(0.99)

    y luego filtrar con:

    df[df["col"] < q]
  4. 27

    Esta respuesta es similar a la proporcionada por @tanemaki, pero utiliza una lambda expresión en lugar de scipy stats.

    df = pd.DataFrame(np.random.randn(100, 3), columns=list('ABC'))
    
    df[df.apply(lambda x: np.abs(x - x.mean()) / x.std() < 3).all(axis=1)]

    Para filtrar el DataFrame donde sólo UNA columna (por ejemplo, ‘B’) es dentro de tres desviaciones estándar:

    df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]
  5. 16
    #------------------------------------------------------------------------------
    # accept a dataframe, remove outliers, return cleaned data in a new dataframe
    # see http://www.itl.nist.gov/div898/handbook/prc/section1/prc16.htm
    #------------------------------------------------------------------------------
    def remove_outlier(df_in, col_name):
        q1 = df_in[col_name].quantile(0.25)
        q3 = df_in[col_name].quantile(0.75)
        iqr = q3-q1 #Interquartile range
        fence_low  = q1-1.5*iqr
        fence_high = q3+1.5*iqr
        df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)]
        return df_out
    • Estoy recibiendo el error «ValueError: No índice multidimensional clave» en línea » df_out = df_in.loc[(df_in[col_name] > fence_low) & (df_in[col_name] < fence_high)] » Va a ayudar
  6. 12

    Para cada serie en el dataframe, usted podría utilizar between y quantile para eliminar los valores extremos.

    x = pd.Series(np.random.normal(size=200)) # with outliers
    x = x[x.between(x.quantile(.25), x.quantile(.75))] # without outliers
    • Aquí usted está seleccionando sólo los datos dentro del rango intercuartil (IQR), pero tenga en cuenta que puede haber valores fuera de este rango, que no son valores atípicos.
    • Por ejemplo, la elección de 0.1 y 0.9 sería bastante seguro, creo. El uso de y entre los cuantiles como este es un muy sintaxis.
  7. 9

    Ya que no he visto una respuesta que lidiar con numérico y no numéricos atributos, aquí es un complemento de la respuesta.

    Usted puede ser que desee eliminar los valores atípicos sólo en atributos numéricos (variables categóricas difícilmente puede ser outliers).

    Definición de la función

    He extendido @tanemaki sugerencia para manejar los datos cuando no los atributos numéricos también están presentes:

    from scipy import stats
    
    def drop_numerical_outliers(df, z_thresh=3):
        # Constrains will contain `True` or `False` depending on if it is a value below the threshold.
        constrains = df.select_dtypes(include=[np.number]) \
            .apply(lambda x: np.abs(stats.zscore(x)) < z_thresh, reduce=False) \
            .all(axis=1)
        # Drop (inplace) values set to be rejected
        df.drop(df.index[~constrains], inplace=True)

    Uso

    drop_numerical_outliers(df)

    Ejemplo

    Imaginar un conjunto de datos df con algunos valores acerca de las casas: callejón de tierra, el contorno, el precio de venta, … E. g: La Documentación De Los Datos

    Primero, usted desea visualizar los datos en un diagrama de dispersión (con z-score Thresh=3):

    # Plot data before dropping those greater than z-score 3. 
    # The scatterAreaVsPrice function's definition has been removed for readability's sake.
    scatterAreaVsPrice(df)

    Detectar y excluir los valores extremos en los Pandas marco de datos

    # Drop the outliers on every attributes
    drop_numerical_outliers(train_df)
    
    # Plot the result. All outliers were dropped. Note that the red points are not
    # the same outliers from the first plot, but the new computed outliers based on the new data-frame.
    scatterAreaVsPrice(train_df)

    Detectar y excluir los valores extremos en los Pandas marco de datos

    • Trabajó para mí, gracias 🙂
    • Gran solución! Como un heads up reduce=False ha quedado obsoleta desde pandas versión 0.23.0
  8. 7

    scipy.stats tiene métodos trim1() y trimboth() para cortar los valores atípicos en una sola fila, según el ranking y una introdujo el porcentaje de la quita de los valores.

    • trimboth fue más fácil para mí.
  9. 4

    Otra opción es transformar los datos de modo que el efecto de los valores atípicos se mitiga. Usted puede hacer esto mediante la winsorizing sus datos.

    import pandas as pd
    from scipy.stats import mstats
    %matplotlib inline
    
    test_data = pd.Series(range(30))
    test_data.plot()

    Detectar y excluir los valores extremos en los Pandas marco de datos

    # Truncate values to the 5th and 95th percentiles
    transformed_test_data = pd.Series(mstats.winsorize(test_data, limits=[0.05, 0.05])) 
    transformed_test_data.plot()

    Detectar y excluir los valores extremos en los Pandas marco de datos

  10. 2

    Si te gusta el método de encadenamiento, usted puede conseguir que su condición booleana para todas las columnas numéricas como este:

    df.sub(df.mean()).div(df.std()).abs().lt(3)

    Cada valor de cada columna será convertido a True/False basa en si sus menos de tres desviaciones estándar de distancia de la media o no.

    • Este debe ser le(3) desde su eliminar los valores atípicos. De esta manera se consigue True para los valores atípicos. Además de que +1 y esta respuesta debería ser de más arriba
  11. 1

    Ya que estoy en una etapa muy temprana de mi ciencia de datos de viaje, yo soy el tratamiento de los valores atípicos con el código de abajo.

    #Outlier Treatment
    
    def outlier_detect(df):
        for i in df.describe().columns:
            Q1=df.describe().at['25%',i]
            Q3=df.describe().at['75%',i]
            IQR=Q3 - Q1
            LTV=Q1 - 1.5 * IQR
            UTV=Q3 + 1.5 * IQR
            x=np.array(df[i])
            p=[]
            for j in x:
                if j < LTV or j>UTV:
                    p.append(df[i].median())
                else:
                    p.append(j)
            df[i]=p
        return df
  12. 0

    un ejemplo completo con datos y 2 grupos de la siguiente manera:

    Importaciones:

    from StringIO import StringIO
    import pandas as pd
    #pandas config
    pd.set_option('display.max_rows', 20)

    De datos de ejemplo con 2 grupos: G1:Grupo 1. G2: Grupo 2:

    TESTDATA = StringIO("""G1;G2;Value
    1;A;1.6
    1;A;5.1
    1;A;7.1
    1;A;8.1
    
    1;B;21.1
    1;B;22.1
    1;B;24.1
    1;B;30.6
    
    2;A;40.6
    2;A;51.1
    2;A;52.1
    2;A;60.6
    
    2;B;80.1
    2;B;70.6
    2;B;90.6
    2;B;85.1
    """)

    Leer datos de texto a los pandas dataframe:

    df = pd.read_csv(TESTDATA, sep=";")

    Definir los valores atípicos mediante desviaciones estándar

    stds = 1.0
    outliers = df[['G1', 'G2', 'Value']].groupby(['G1','G2']).transform(
               lambda group: (group - group.mean()).abs().div(group.std())) > stds

    Definir los datos filtrados valores y los valores atípicos:

    dfv = df[outliers.Value == False]
    dfo = df[outliers.Value == True]

    Imprimir el resultado:

    print '\n'*5, 'All values with decimal 1 are non-outliers. In the other hand, all values with 6 in the decimal are.'
    print '\nDef DATA:\n%s\n\nFiltred Values with %s stds:\n%s\n\nOutliers:\n%s' %(df, stds, dfv, dfo)
  13. 0

    Mi función, para dejar a los valores atípicos

    def drop_outliers(df, field_name):
        distance = 1.5 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25))
        df.drop(df[df[field_name] > distance + np.percentile(df[field_name], 75)].index, inplace=True)
        df.drop(df[df[field_name] < np.percentile(df[field_name], 25) - distance].index, inplace=True)
  14. 0

    Prefiero clip en lugar de caer. el siguiente clip directamente en la 2ª y 98º pecentiles.

    df_list = list(df)
    minPercentile = 0.02
    maxPercentile = 0.98
    
    for _ in range(numCols):
        df[df_list[_]] = df[df_list[_]].clip((df[df_list[_]].quantile(minPercentile)),(df[df_list[_]].quantile(maxPercentile)))
  15. 0

    Obtener el 98º y 2º percentil como los límites de nuestros valores atípicos

    upper_limit = np.percentile(X_train.logerror.values, 98) 
    lower_limit = np.percentile(X_train.logerror.values, 2) # Filter the outliers from the dataframe
    data[‘target’].loc[X_train[‘target’]>upper_limit] = upper_limit data[‘target’].loc[X_train[‘target’]<lower_limit] = lower_limit
  16. 0

    Puede utilizar booleano máscara:

    import pandas as pd
    
    def remove_outliers(df, q=0.05):
        upper = df.quantile(1-q)
        lower = df.quantile(q)
        mask = (df < upper) & (df > lower)
        return mask
    
    t = pd.DataFrame({'train': [1,1,2,3,4,5,6,7,8,9,9],
                      'y': [1,0,0,1,1,0,0,1,1,1,0]})
    
    mask = remove_outliers(t['train'], 0.1)
    
    print(t[mask])

    de salida:

       train  y
    2      2  0
    3      3  1
    4      4  1
    5      5  0
    6      6  0
    7      7  1
    8      8  1
  17. -3

    Eliminar y colocar los valores atípicos creo que está mal estadísticamente.
    Esto hace que los datos sean diferentes de los datos originales.
    También hace que los datos de manera desigual en forma de y, por tanto, la mejor manera es reducir o evitar el efecto de los valores atípicos por el registro de transformar los datos.
    Esto funcionó para mí:

    np.log(data.iloc[:, :])
    • No puede hacer suposiciones acerca de por qué el OP quiere hacer algo.

Dejar respuesta

Please enter your comment!
Please enter your name here