67 votes

création de diagrammes de dispersion matplotlib à partir de cadres de données dans pandas de Python

quelle est la meilleure façon de faire une série de diagrammes de dispersion en utilisant matplotlib d'un pandas dataframe en Python ? Par exemple, si j'ai un dataframe df qui a quelques colonnes d'intérêt, je me retrouve typiquement à tout convertir en tableaux :

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])

Le problème de tout convertir en tableau avant de tracer est que cela vous oblige à sortir des cadres de données. Considérez ces deux cas d'utilisation où il est essentiel de disposer du cadre de données complet pour le traçage :

  1. Par exemple, que se passe-t-il si vous voulez maintenant regarder toutes les valeurs de col3 pour les valeurs correspondantes que vous avez tracées dans l'appel à scatter et colorier chaque point (ou le dimensionner) en fonction de cette valeur ? Il faudrait revenir en arrière, sortir les valeurs non-na de col1,col2 et vérifier quelles sont leurs valeurs correspondantes.

    Existe-t-il un moyen de tracer tout en préservant le cadre de données ? Par exemple :

    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"])
  2. De même, imaginez que vous souhaitiez filtrer ou colorer chaque point différemment en fonction des valeurs de certaines de ses colonnes. Par exemple, si vous voulez tracer automatiquement les étiquettes des points qui répondent à un certain seuil sur la colonne col1, col2 à côté d'eux (où les étiquettes sont stockées dans une autre colonne du df), ou colorer ces points différemment, comme on le fait avec les cadres de données dans R. Par exemple :

    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)

Comment cela peut-il être fait ?

EDIT Répondre à crewbum :

Merci. Vous dites que la meilleure façon est de tracer chaque condition (comme subset_a , subset_b ) séparément. Que se passe-t-il si vous avez plusieurs conditions, par exemple si vous voulez diviser les dispersions en 4 types de points ou même plus, en les traçant chacun dans une forme/couleur différente. Comment pouvez-vous appliquer élégamment la condition a, b, c, etc. et vous assurer que vous tracez ensuite "le reste" (les choses qui ne sont dans aucune de ces conditions) comme dernière étape ?

De même, dans votre exemple où vous tracez col1,col2 différemment en fonction de col3 Et s'il y avait des valeurs NA qui brisent l'association entre col1,col2,col3 ? Par exemple, si vous voulez tracer tous les col2 sur la base de leurs col3 mais certaines lignes ont une valeur NA dans l'une ou l'autre des catégories suivantes col1 ou col3 ce qui vous oblige à utiliser dropna premier. Donc vous le feriez :

mydata = df.dropna(how="any", subset=["col1", "col2", "col3")

alors vous pouvez tracer en utilisant mydata comme vous le montrez en traçant la dispersion entre col1,col2 en utilisant les valeurs de col3 . Mais mydata manquera certains points qui ont des valeurs pour col1,col2 mais sont NA pour col3 et ceux-ci doivent encore être tracés... alors comment tracer le "reste" des données, c'est-à-dire les points qui sont pas dans l'ensemble filtré mydata ? Merci encore.

98voto

Garrett Points 5477

Essayez de passer les colonnes du DataFrame directement à matplotlib, comme dans les exemples ci-dessous, au lieu de les extraire sous forme de tableaux 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

Varier la taille des points de dispersion en fonction d'une autre colonne

plt.scatter(df.col1, df.col2, s=df.col3)

enter image description here

Varier la couleur du point de dispersion en fonction d'une autre colonne

colors = np.where(df.col3 > 300, 'r', 'k')
plt.scatter(df.col1, df.col2, s=120, c=colors)

enter image description here

Diagramme de dispersion avec légende

Cependant, la manière la plus simple que j'ai trouvée pour créer un diagramme de dispersion avec légende est d'appeler plt.scatter une fois pour chaque type de point.

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()

enter image description here

Mise à jour

D'après ce que je peux dire, matplotlib saute simplement les points dont les coordonnées x/y sont NA ou les paramètres de style NA (par exemple, couleur/taille). Pour trouver les points ignorés à cause de NA, essayez la commande isnull méthode : df[df.col3.isnull()]

Pour diviser une liste de points en plusieurs types, il suffit de regarder numpy select qui est une implémentation if-then-else vectorisée et accepte une valeur par défaut facultative. Par exemple :

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()

enter image description here

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X