web-dev-qa-db-fra.com

faire des diagrammes de dispersion matplotlib à partir de données dans Python pandas

Quel est le meilleur moyen de créer une série de diagrammes de dispersion en utilisant matplotlib à partir d'un fichier de données pandas en Python?

Par exemple, si j'ai un cadre de données df qui a quelques colonnes d'intérêt, je me trouve généralement à 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 avec la conversion de tout en tableau avant de tracer, c'est que cela vous oblige à sortir des cadres de données.

Pensez à ces deux cas d’utilisation où la trame de données complète est essentielle au traçage:

  1. Par exemple, si vous vouliez maintenant examiner toutes les valeurs de col3 pour les valeurs correspondantes que vous avez tracées dans l'appel à scatter, et coloriez-vous chaque point (ou taille) par cette valeur? Vous devez revenir en arrière, extraire les valeurs non-na de col1,col2 et vérifiez 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. Et si vous vouliez tracer automatiquement les étiquettes des points qui rencontrent un certain seuil sur col1, col2 à côté d’eux (où les étiquettes sont stockées dans une autre colonne de la df), ou coloriez ces points différemment, comme le font les gens avec des images 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:

Vous dites que le meilleur moyen est de tracer chaque condition (comme subset_a, subset_b) séparément. Et si vous avez plusieurs conditions, par exemple vous voulez diviser les dispersés en 4 types de points ou même plus, en traçant chacun sous une forme/couleur différente. Comment pouvez-vous appliquer avec élégance la condition a, b, c, etc. et vous assurer de tracer ensuite "le reste" (ce qui n'est pas le cas dans ces conditions) comme dernière étape?

De même dans votre exemple où vous tracez col1,col2 différemment en fonction de col3, que se passe-t-il s’il existe des valeurs NA qui rompent l’association entre col1,col2,col3? Par exemple, si vous voulez tracer tous les col2 valeurs basées sur leur col3 valeurs, mais certaines lignes ont une valeur NA dans col1 ou col3, vous obligeant à utiliser dropna en premier. Alors tu ferais:

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

alors vous pouvez tracer en utilisant mydata comme vous le montrer - traçant la dispersion entre col1,col2 en utilisant les valeurs de col3. Mais il manquera à mydata des points ayant des valeurs pour col1,col2 mais sont NA pour col3, et ceux-ci doivent encore être tracés ... Alors, comment voulez-vous essentiellement tracer "le reste" des données, c'est-à-dire les points qui sont et non dans le jeu filtré mydata?

66
user248237

Essayez de passer les colonnes de 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 du point de dispersion en fonction d'une autre colonne

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)

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)
# OR (with pandas 0.13 and up)
df.plot(kind='scatter', x='col1', y='col2', s=120, c=colors)

enter image description here

Nuage de points avec légende

Cependant, le moyen le plus simple que j'ai trouvé de créer un nuage de points avec une 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

Mettre à jour

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

Pour fractionner une liste de points en plusieurs types, jetez un oeil à numpy select , qui est une implémentation vectorisée du type if-then-else 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

96
Garrett

Il n’ya pas grand chose à ajouter à la réponse de Garrett, mais pandas a aussi une scatter méthode En utilisant ça, c'est aussi simple que

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

plotting sizes in col3 to col1-col2

5
serv-inc

Je recommanderai d'utiliser une méthode alternative en utilisant seaborn qui est un outil plus puissant pour le traçage des données. Vous pouvez utiliser seaborn scatterplot et définissez la colonne 3 comme hue et size.

Code de travail:

import pandas as pd
import seaborn as sns
import numpy as np

#creating sample data 
sample_data={'col_name_1':np.random.Rand(20),
      'col_name_2': np.random.Rand(20),'col_name_3': np.arange(20)*100}
df= pd.DataFrame(sample_data)
sns.scatterplot(x="col_name_1", y="col_name_2", data=df, hue="col_name_3",size="col_name_3")

enter image description here

0
Dr. Arslan