Tengo un dataframe de pandas con pocas columnas.
Ahora sé que ciertas filas son valores atípicos basados en un determinado valor de columna.
Por ejemplo, las columnas: ‘Vol’ tiene todos los valores alrededor de 12xx y un valor es 4000 (valor atípico).
Ahora me gustaría excluir aquellas filas que tienen la columna ‘Vol’ como esta. Así que, esencialmente, necesito colocar un filtro en el dataframe de manera que seleccionemos todas las filas donde los valores de una determinada columna estén dentro de, por ejemplo, 3 desviaciones estándar de la media.
¿Qué es una manera elegante de lograr esto.
Si tiene varias columnas en su dataframe y desea eliminar todas las filas que tienen valores atípicos en al menos una columna, la siguiente expresión lo haría de una sola vez.
df = pd.DataFrame(np.random.randn(100, 3)) from scipy import stats df[(np.abs(stats.zscore(df)) < 3).all(axis=1)]
descripción:
Use la indexación boolean
como lo 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[~((SS.mean()).abs() > 3*S.std())]
Para cada una de las columnas de su dataframe, podría obtener cuantil con:
q = df["col"].quantile(0.99)
y luego filtrar con:
df[df["col"] < q]
Esta respuesta es similar a la proporcionada por @tanemaki, pero utiliza una expresión lambda
lugar de scipy stats
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 solo UNA columna (por ejemplo, 'B') está dentro de tres desviaciones estándar:
df[((df.B - df.B.mean()) / df.B.std()).abs() < 3]
#------------------------------------------------------------------------------ # 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
Para cada serie en el dataframe, puede usar between
y quantile
para eliminar valores atípicos.
x = pd.Series(np.random.normal(size=200)) # with outliers x = x[x.between(x.quantile(.25), x.quantile(.75))] # without outliers
scipy.stats
tiene los métodos trim1()
y trimboth()
para eliminar los valores atípicos en una sola fila, de acuerdo con la clasificación y un porcentaje introducido de valores eliminados.
Otra opción es transformar sus datos para mitigar el efecto de los valores atípicos. Puede hacer esto mediante la optimización de sus datos.
import pandas as pd from scipy.stats import mstats %matplotlib inline test_data = pd.Series(range(30)) test_data.plot()
# 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()
Si le gusta el encadenamiento de métodos, puede obtener su condición booleana para todas las columnas numéricas como esta:
df.sub(df.mean()).div(df.std()).abs().lt(3)
Cada valor de cada columna se convertirá en True/False
función de si sus menos de tres desviaciones estándar se alejan de la media o no.
A continuación se muestra un ejemplo completo con datos y 2 grupos:
Importaciones:
from StringIO import StringIO import pandas as pd #pandas config pd.set_option('display.max_rows', 20)
Ejemplo de datos 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 en el dataframe de pandas:
df = pd.read_csv(TESTDATA, sep=";")
Definir los valores atípicos utilizando 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
Defina valores de datos filtrados y los valores atípicos:
dfv = df[outliers.Value == False] dfo = df[outliers.Value == True]
Imprima 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)
Mi función para dejar 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)
Prefiero recortar en lugar de soltar. Lo siguiente se cortará en el lugar en el 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)))
Ya que estoy en una etapa muy temprana de mi viaje hacia la ciencia de los datos, estoy tratando los valores atípicos con el código a continuación.
#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
Suprimir estadísticamente el hecho de eliminar y eliminar los valores atípicos. Hace que los datos sean diferentes de los datos originales. También crea datos con formas desiguales y, por lo tanto, la mejor manera es reducir o evitar el efecto de los valores atípicos mediante la transformación de los datos en el registro. Esto funcionó para mí:
np.log(data.iloc[:, :])