Tengo un marco de datos que se ve de la siguiente manera:

 print(df.head(10))

 day         CO2
   1  549.500000
   2  663.541667
   3  830.416667
   4  799.695652
   5  813.850000
   6  769.583333
   7  681.941176
   8  653.333333
   9  845.666667
  10  436.086957

Luego uso la siguiente función y líneas de código para obtener los valores atípicos de la columna de CO2:

def estimate_gaussian(dataset):

    mu = np.mean(dataset)#moyenne cf mu
    sigma = np.std(dataset)#écart_type/standard deviation
    limit = sigma * 1.5

    min_threshold = mu - limit
    max_threshold = mu + limit

    return mu, sigma, min_threshold, max_threshold

mu, sigma, min_threshold, max_threshold = estimate_gaussian(df['CO2'].values)


condition1 = (dataset < min_threshold)
condition2 = (dataset > max_threshold)

outliers1 = np.extract(condition1, dataset)
outliers2 = np.extract(condition2, dataset)

outliers = np.concatenate((outliers1, outliers2), axis=0)

Lo que me da el siguiente resultado:

print(outliers)

[830.41666667 799.69565217 813.85       769.58333333 845.66666667]

Ahora me gustaría marcar esos valores atípicos con un color rojo en un diagrama de dispersión.

Puede encontrar debajo del código que he usado hasta ahora para marcar un solo valor atípico en rojo en el diagrama de dispersión, pero no puedo encontrar una manera de hacerlo para cada elemento de la lista de valores atípicos que es un numpy.ndarray:

y = df['CO2']

x = df['day']

col = np.where(x<0,'k',np.where(y<845.66666667,'b','r'))

plt.scatter(x, y, c=col, s=5, linewidth=3)
plt.show()

Esto es lo que obtengo, pero me gustaría el mismo resultado de todos los ouliers. ¿Me podría ayudar?

https://ibb.co/Ns9V7Zz

2
Synox 3 oct. 2019 a las 16:50

5 respuestas

La mejor respuesta

Posiblemente no sea la solución más eficiente, pero siento que es más fácil llamar a plt.scatter varias veces, pasando un solo par xy cada vez. Como nunca llamamos a una nueva figura (por ejemplo, usando plt.figure()), cada par xy se traza en la misma figura.

Luego, en cada iteración solo necesitamos verificar si el valor y es un valor atípico. Si es así, cambiamos el argumento de la palabra clave color en la llamada plt.scatter.

Prueba esto:

mu, sigma, min_threshold, max_threshold = estimate_gaussian(df['CO2'].values)

xs = df['day']
ys = df['CO2']

for x, y in zip(xs, ys):
    color = 'blue'  # non-outlier color
    if not min_threshold <= y <= max_threshold:  # condition for being an outlier
        color = 'red'  # outlier color
    plt.scatter(x, y, color=color)
plt.show()
0
jfaccioni 3 oct. 2019 a las 14:03

No estoy seguro de cuál es la idea detrás de su lista de col, pero puede reemplazar col con

col = ['red' if yy in list(outliers) else 'blue' for yy in y] 
0
Tarje Bargheer 3 oct. 2019 a las 14:07

Puede crear una columna adicional (booleana) en la que defina si el punto es un valor atípico (Verdadero) o no (Falso), y luego trabajar con dos diagramas de dispersión:

df["outlier"] = # your boolean np array goes in here
plt.scatter[df.loc[df["outlier"], "day"], df.loc[df["outlier"], "CO2"], color="k"]
plt.scatter[df.loc[~df["outlier"], "day"], df.loc[~df["outlier"], "CO2"], color="r"]
0
Sosel 3 oct. 2019 a las 14:01

Aquí hay una solución rápida:

Volveré a crear lo que ya tienes que comenzar. Solo compartió el encabezado de su marco de datos, pero lo que sea, acabo de insertar algunos valores atípicos aleatorios. ¿Parece que su función "estimar_gaussiano ()" solo puede devolver dos valores atípicos?

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([549.500000,
                50.0000000,
                830.416667,
                799.695652,
                1200.00000,
                769.583333,
                681.941176,
                1300.00000,
                845.666667,
                436.086957], 
                columns=['CO2'],
                index=list(range(1,11)))

def estimate_gaussian(dataset):

    mu = np.mean(dataset) # moyenne cf mu
    sigma = np.std(dataset) # écart_type/standard deviation
    limit = sigma * 1.5

    min_threshold = mu - limit
    max_threshold = mu + limit

    return mu, sigma, min_threshold, max_threshold

mu, sigma, min_threshold, max_threshold = estimate_gaussian(df.values)

condition1 = (df < min_threshold)
condition2 = (df > max_threshold)

outliers1 = np.extract(condition1, df)
outliers2 = np.extract(condition2, df)

outliers = np.concatenate((outliers1, outliers2), axis=0)

Luego tramaremos:

df_red = df[df.values==outliers]

plt.scatter(df.index,df.values)
plt.scatter(df_red.index,df_red.values,c='red')
plt.show()

enter image description here

¡Avísame si necesitas algo más matizado!

1
Robert Boscacci 3 oct. 2019 a las 14:23

Hay varias formas, una sería crear una secuencia de colores según su condición y pasarla al parámetro c.

df = pd.DataFrame({'CO2': {0: 549.5,
  1: 663.54166699999996,
  2: 830.41666699999996,
  3: 799.695652,
  4: 813.85000000000002,
  5: 769.58333300000004,
  6: 681.94117599999993,
  7: 653.33333300000004,
  8: 845.66666699999996,
  9: 436.08695700000004},
 'day': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}})

In [11]: colors = ['r' if n<750 else 'b' for n in df['CO2']]

In [12]: colors
Out[12]: ['r', 'r', 'b', 'b', 'b', 'b', 'r', 'r', 'b', 'r']

In [13]: plt.scatter(df['day'],df['CO2'],c=colors)

O use np.where para crear la secuencia

In [14]: colors = np.where(df['CO2'] < 750, 'r', 'b')
0
wwii 3 oct. 2019 a las 14:07
58220589