tablas - hacer parcelas de dispersión matplotlib a partir de marcos de datos en pandas de Python
python graficos 2d (2)
¿Cuál es la mejor manera de hacer una serie de diagramas de dispersión usando matplotlib
desde un matplotlib
de matplotlib
de pandas
en Python?
Por ejemplo, si tengo un marco de datos df
que tiene algunas columnas de interés, normalmente me encuentro convirtiendo todo en matrices:
import matplotlib.pylab as plt
# df is a DataFrame: fetch col1 and col2
# and drop na rows if any of the columns are NA
mydata = df[["col1", "col2"]].dropna(how="any")
# Now plot with matplotlib
vals = mydata.values
plt.scatter(vals[:, 0], vals[:, 1])
El problema con la conversión de todo a la matriz antes de trazar es que te obliga a salir de los marcos de datos.
Considere estos dos casos de uso donde tener el marco de datos completo es esencial para el trazado:
Por ejemplo, ¿qué pasaría si ahora quisiera ver todos los valores de
col3
para los valores correspondientes que trazó en la llamada parascatter
y colorear cada punto (o tamaño) en ese valor? Tendría que retroceder, extraer los valores nocol1,col2
decol1,col2
y comprobar cuáles son sus valores correspondientes.¿Hay alguna manera de trazar preservando el marco de datos? Por ejemplo:
mydata = df.dropna(how="any", subset=["col1", "col2"]) # plot a scatter of col1 by col2, with sizes according to col3 scatter(mydata(["col1", "col2"]), s=mydata["col3"])
Del mismo modo, imagine que desea filtrar o colorear cada punto de forma diferente según los valores de algunas de sus columnas. Por ejemplo, ¿qué pasaría si quisieras trazar automáticamente las etiquetas de los puntos que cumplen un determinado límite en
col1, col2
junto a ellas (donde las etiquetas están almacenadas en otra columna de df) o colorear estos puntos de forma diferente, como hacen las personas con marcos de datos en R. Por ejemplo:mydata = df.dropna(how="any", subset=["col1", "col2"]) myscatter = scatter(mydata[["col1", "col2"]], s=1) # Plot in red, with smaller size, all the points that # have a col2 value greater than 0.5 myscatter.replot(mydata["col2"] > 0.5, color="red", s=0.5)
¿Cómo puede hacerse esto?
EDITAR Responder a crewbum:
Usted dice que la mejor manera es trazar cada condición (como subset_a
, subset_b
) por separado. ¿Qué sucede si tiene muchas condiciones, por ejemplo, desea dividir las dispersiones en 4 tipos de puntos o incluso más, trazando cada uno en diferentes formas / colores. ¿Cómo se puede aplicar elegantemente la condición a, b, c, etc. y asegurarse de trazar "el resto" (cosas que no están en ninguna de estas condiciones) como el último paso?
De manera similar, en su ejemplo, donde traza col1,col2
diferente en función de col3
, ¿qué col1,col2
si hay valores de NA que rompen la asociación entre col1,col2,col3
? Por ejemplo, si desea trazar todos los valores de col2
función de sus valores de col3
, algunas filas tienen un valor NA en col1
o col3
, lo que le obliga a utilizar dropna
primero. Entonces lo harías:
mydata = df.dropna(how="any", subset=["col1", "col2", "col3")
luego puedes trazar utilizando mydata
como lo muestras, trazando la dispersión entre col1,col2
usando los valores de col3
. Pero a mydata
le col1,col2
algunos puntos que tienen valores para col1,col2
pero son NA para col3
, y los que aún tienen que trazarse ... entonces ¿cómo se col1,col2
básicamente "el resto" de los datos, es decir, los puntos que no son en el conjunto filtrado mydata
?
Hay poco que agregar a la gran respuesta de Garrett, pero los pandas también tienen un método de scatter
. Usando eso, es tan fácil como
df = pd.DataFrame(np.random.randn(10,2), columns=[''col1'',''col2''])
df[''col3''] = np.arange(len(df))**2 * 100 + 100
df.plot.scatter(''col1'', ''col2'', df[''col3''])
Intente pasar columnas del DataFrame
directamente a matplotlib, como en los ejemplos a continuación, en lugar de extraerlos como matrices numpy.
df = pd.DataFrame(np.random.randn(10,2), columns=[''col1'',''col2''])
df[''col3''] = np.arange(len(df))**2 * 100 + 100
In [5]: df
Out[5]:
col1 col2 col3
0 -1.000075 -0.759910 100
1 0.510382 0.972615 200
2 1.872067 -0.731010 500
3 0.131612 1.075142 1000
4 1.497820 0.237024 1700
Variar el tamaño del punto de dispersión según otra columna
plt.scatter(df.col1, df.col2, s=df.col3)
# OR (with pandas 0.13 and up)
df.plot(kind=''scatter'', x=''col1'', y=''col2'', s=df.col3)
Variar el color del punto de dispersión según otra columna
colors = np.where(df.col3 > 300, ''r'', ''k'')
plt.scatter(df.col1, df.col2, s=120, c=colors)
# OR (with pandas 0.13 and up)
df.plot(kind=''scatter'', x=''col1'', y=''col2'', s=120, c=colors)
Diagrama de dispersión con leyenda
Sin embargo, la forma más fácil que he encontrado para crear un diagrama de dispersión con leyenda es llamar a plt.scatter
una vez para cada tipo de punto.
cond = df.col3 > 300
subset_a = df[cond].dropna()
subset_b = df[~cond].dropna()
plt.scatter(subset_a.col1, subset_a.col2, s=120, c=''b'', label=''col3 > 300'')
plt.scatter(subset_b.col1, subset_b.col2, s=60, c=''r'', label=''col3 <= 300'')
plt.legend()
Actualizar
Por lo que puedo decir, matplotlib simplemente saltea puntos con coordenadas NA x / y o configuraciones de estilo NA (por ejemplo, color / tamaño). Para encontrar puntos omitidos debido a NA, pruebe el método isnull
: df[df.col3.isnull()]
Para dividir una lista de puntos en muchos tipos, eche un vistazo a numpy select
, que es una implementación vectorizada if-then-else y acepta un valor predeterminado opcional. Por ejemplo:
df[''subset''] = np.select([df.col3 < 150, df.col3 < 400, df.col3 < 600],
[0, 1, 2], -1)
for color, label in zip(''bgrm'', [0, 1, 2, -1]):
subset = df[df.subset == label]
plt.scatter(subset.col1, subset.col2, s=120, c=color, label=str(label))
plt.legend()