Erstellen von Matplotlib-Streudiagrammen aus Datenrahmen in Pythons Pandas

77

Was ist der beste Weg, um eine Reihe von Streudiagrammen mithilfe matplotlibeines pandasDatenrahmens in Python zu erstellen?

Wenn ich beispielsweise einen Datenrahmen dfmit einigen interessanten Spalten habe, konvertiere ich normalerweise alles in Arrays:

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

Das Problem beim Konvertieren von allem in ein Array vor dem Plotten besteht darin, dass Sie gezwungen sind, aus Datenrahmen auszubrechen.

Betrachten Sie diese beiden Anwendungsfälle, in denen der vollständige Datenrahmen für das Plotten unerlässlich ist:

  1. Was wäre zum Beispiel, wenn Sie jetzt alle Werte col3für die entsprechenden Werte anzeigen möchten, die Sie im Aufruf gezeichnet haben scatter, und jeden Punkt (oder jede Größe) mit diesem Wert färben möchten? Sie müssten zurückgehen, die Nicht-Na-Werte von herausziehen und die col1,col2entsprechenden Werte überprüfen.

    Gibt es eine Möglichkeit zum Plotten unter Beibehaltung des Datenrahmens? Zum Beispiel:

    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. Stellen Sie sich vor, Sie möchten jeden Punkt abhängig von den Werten einiger Spalten unterschiedlich filtern oder färben. Was wäre beispielsweise, wenn Sie die Beschriftungen der Punkte, die einen bestimmten Grenzwert treffen, automatisch neben sich zeichnen col1, col2möchten (wobei die Beschriftungen in einer anderen Spalte des df gespeichert sind) oder diese Punkte anders färben möchten, wie dies bei Datenrahmen in R der Fall ist Beispiel:

    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)
    

Wie kann das gemacht werden?

EDIT Antwort crewbum:

Sie sagen, dass der beste Weg ist, jede Bedingung (wie subset_a, subset_b) separat zu zeichnen . Was ist, wenn Sie viele Bedingungen haben, z. B. wenn Sie die Streuungen in 4 Arten von Punkten oder sogar mehr aufteilen möchten, wobei Sie jede in unterschiedlicher Form / Farbe zeichnen möchten. Wie können Sie die Bedingungen a, b, c usw. elegant anwenden und sicherstellen, dass Sie als letzten Schritt "den Rest" (Dinge, die in keiner dieser Bedingungen enthalten sind) zeichnen?

Ähnlich verhält es sich in Ihrem Beispiel, in dem Sie je nach Darstellung col1,col2unterschiedlich darstellen, mit col3NA-Werten, die die Zuordnung zwischen diesen Werten aufheben col1,col2,col3? Zum Beispiel, wenn Sie alle col2Werte basierend auf ihren col3Werten zeichnen möchten , aber einige Zeilen einen NA-Wert in entweder col1oder haben col3, was Sie dazu zwingt, zuerst zu verwenden dropna. Also würden Sie tun:

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

Dann können Sie mit mydatawie gezeigt zeichnen - die Streuung zwischen col1,col2den Werten von col3. Es mydatafehlen jedoch einige Punkte, für die Werte col1,col2vorliegen col3, für die jedoch NA angegeben sind , und die noch gezeichnet werden müssen. Wie würden Sie also im Grunde "den Rest" der Daten darstellen, dh die Punkte, die nicht in der gefilterten Menge enthalten sind mydata?

Michael Currie
quelle
2
Die Dinge ändern sich in der Zwischenzeit, siehe Plotten - Plotten - Streudiagramm aus der offiziellen Dokumentation.
Piotr Migdal

Antworten:

114

Versuchen Sie, Spalten der DataFramedirekt an matplotlib zu übergeben, wie in den folgenden Beispielen, anstatt sie als numpy-Arrays zu extrahieren.

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

Variieren Sie die Streupunktgröße basierend auf einer anderen Spalte

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)

Geben Sie hier die Bildbeschreibung ein

Variieren Sie die Streupunktfarbe basierend auf einer anderen Spalte

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)

Geben Sie hier die Bildbeschreibung ein

Streudiagramm mit Legende

Der einfachste Weg, ein Streudiagramm mit Legende zu erstellen, besteht darin, plt.scatterfür jeden Punkttyp einmal aufzurufen .

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

Geben Sie hier die Bildbeschreibung ein

Aktualisieren

Nach allem, was ich sagen kann, überspringt matplotlib einfach Punkte mit NA x / y-Koordinaten oder NA-Stileinstellungen (z. B. Farbe / Größe). Versuchen Sie die folgende isnullMethode , um aufgrund von NA übersprungene Punkte zu finden :df[df.col3.isnull()]

Um eine Liste von Punkten in viele Typen aufzuteilenselect , werfen Sie einen Blick auf numpy , eine vektorisierte Wenn-Dann-Sonst-Implementierung, die einen optionalen Standardwert akzeptiert. Zum Beispiel:

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

Geben Sie hier die Bildbeschreibung ein

Garrett
quelle
1
gute Antwort! Ich wusste nichts davon. Normalerweise bekomme ich meine Daten in das gewünschte Format und sende sie für ggplot an R. Mit diesen Beispielen kann ich viel mehr in pandas / python tun - danke.
Zach
Wie kann ich einen einzelnen Kreis mit einer bestimmten Größe in der Legende erstellen?
Nbsrujan
6

Garretts großartiger Antwort kann wenig hinzugefügt werden, aber Pandas haben auch eine scatterMethode . Damit ist es so einfach wie

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

Auftragen der Größen in col3 bis col1-col2

serv-inc
quelle
3

Ich werde empfehlen, eine alternative Methode zu verwenden, mit der seaborndas leistungsstärkere Tool zum Zeichnen von Daten verwendet wird. Sie können seaborn scatterplotSpalte 3 als hueund verwenden und definieren size.

Arbeitscode:

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

Geben Sie hier die Bildbeschreibung ein

Dr. Arslan
quelle