[PYTHON] Verwalten Sie die Überlappung, wenn Sie ein Streudiagramm mit einer großen Datenmenge zeichnen (Matplotlib, Pandas, Datashader).

Wenn Sie ein Streudiagramm mit einer großen Anzahl von Datenpunkten zeichnen, ist es zu voll und Sie können nicht verstehen, wie viele Daten in einem bestimmten Bereich vorhanden sind.

Betrachten Sie als Beispiel die folgenden Daten, die durch Komprimieren des handgeschriebenen numerischen Bilddatensatzes (MNIST) in zwei Dimensionen mit UMAP erhalten wurden.

import pandas as pd

df = pd.read_csv('./mnist_embedding.csv', index_col=0)
display(df)
x y class
0 1.273394 1.008444 5
1 12.570375 0.472456 0
2 -2.197421 8.652475 4
3 -5.642218 -4.971571 1
4 -3.874749 5.150311 9
... ... ... ...
69995 -0.502520 -7.309745 2
69996 3.264405 -0.887491 3
69997 -4.995078 8.153721 4
69998 -0.226225 -0.188836 5
69999 8.405535 -2.277809 6

70000 rows × 3 columns

x ist die X-Koordinate, y ist die Y-Koordinate und class ist die Bezeichnung (welche Zahl von 0 bis 9 geschrieben wird).

Zeichnen Sie wie gewohnt ein Streudiagramm mit matplotlib. Übrigens, obwohl dies nicht der Hauptpunkt ist, erleichtert die kürzlich hinzugefügte Funktion `` `legend_elements``` das Erstellen einer Legende für ein Streudiagramm mit mehreren Kategorien, ohne die for-Anweisung zu drehen.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(12, 12))

sc = ax.scatter(df['x'], df['y'], c=df['class'], cmap='Paired', s=6, alpha=1.0)

ax.add_artist(ax.legend(*sc.legend_elements(), loc="upper right", title="Classes"))
plt.axis('off')
plt.show()

output_3_0.png

Es werden 70.000 Punkte gezeichnet. Es ist schön, separate Cluster für jede Zahl zu haben, aber bei einer so großen Datengröße sind die Punkte so dicht, dass sie sich überlappen und ausfüllen, wodurch die Struktur innerhalb jeder Klasse fast unsichtbar wird. Ich möchte etwas dagegen tun.

Lösung 1: Passen Sie Größe und Alpha an und geben Sie Ihr Bestes

Um Überlappungen zu vermeiden, reduzieren Sie die Größe der Punkte oder passen Sie die Transparenz der Punkte an, damit die Dichte besser sichtbar ist. Es erfordert Versuch und Irrtum und ist nicht immer leicht zu erkennen.

fig, ax = plt.subplots(figsize=(12, 12))

sc = ax.scatter(df['x'], df['y'], c=df['class'], cmap='Paired', s=3, alpha=0.1)

ax.add_artist(ax.legend(*sc.legend_elements(), loc="upper right", title="Classes"))
plt.axis('off')
plt.show()

output_7_0.png

Lösung 2: Sechseckiges Binning

Dies ist auch ein guter Weg, dies zu tun. Die Leinwand ist mit einem sechseckigen Raster angeordnet, und die Anzahl der Datenpunkte in jedem wird aggregiert und in Farbtiefe ausgedrückt. Einfach zu bedienende Pandas-Plotfunktion.

fig, ax = plt.subplots(figsize=(12, 12))

df.plot.hexbin(x='x', y='y', gridsize=100, ax=ax)

plt.axis('off')
plt.show()

output_10_0.png

Lösung 3: Verwenden Sie Datashader

Es ist vielseitig und einfach zu bedienen. Solange du dich daran gewöhnt hast.

Datashader ist eine Bibliothek, die schnell "gerasterte Diagramme" für große Datenmengen generiert.

Nachdem die Auflösung (Anzahl der Pixel) der zuerst auszugebenden Figur festgelegt wurde, werden die Daten für jedes Pixel aggregiert und als Bild ausgegeben, und das Zeichnen erfolgt in drei Schritten. Da jeder Schritt fein eingestellt werden kann, ist der Freiheitsgrad hoch.

Jeder Schritt wird später beschrieben, aber wenn Sie alle mit den Standardeinstellungen schreiben, ist dies wie folgt.

import datashader as ds
from datashader import transfer_functions as tf

tf.shade(ds.Canvas().points(df,'x','y'))

output_13_0.png

Einstellung jedes Schrittes

In Datashader

  1. Stellen Sie die Leinwand ein

  2. Aggregierte Funktionseinstellungen und Berechnungen

  3. In Bild konvertieren

Machen Sie eine Handlung in drei Schritten. Jedes wird unten erklärt.

1. Stellen Sie die Leinwand ein

datashader.Stellen Sie verschiedene Leinwände mit Leinwand ein. Vertikale und horizontale Auflösung (Pixel), logarithmische Achse oder nicht, numerischer Bereich (xlim in matplotlib),ylim) etc.




```python
canvas = ds.Canvas(plot_width=600, plot_height=600, #Vertikal und horizontal 600 Pixel
                   x_axis_type='linear', y_axis_type='linear', # 'linear' or 'log'
                   x_range=(-10,15), y_range=(-15,10))

2. Aggregierte Funktionseinstellungen und Berechnungen

Ich habe oben eine Leinwand mit (600 x 600) Pixeln gemacht. Hier legen wir fest, wie die Daten für jedes dieser Pixel aggregiert werden. Ändern Sie beispielsweise die Farbdichte entsprechend der Anzahl der Datenpunkte, die in ein Pixel eintreten, oder machen Sie daraus einen Binärwert, unabhängig davon, ob auch nur ein Datenpunkt enthalten ist oder nicht.

Geben Sie beispielsweise für die oben festgelegte Zeichenflächenvariable den Datenrahmen, die x-Achsenkoordinaten (Spaltenname), die y-Achsenkoordinaten und die Aggregatfunktion wie unten gezeigt ein und führen Sie die Berechnung aus. Die Funktion `` `datashader.reductions.count``` zählt die Anzahl der Datenpunkte, die in ein Pixel gehen.

canvas.points(df, 'x', 'y', agg=ds.count())
<xarray.DataArray (y: 600, x: 600)>
array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ...,
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]], dtype=int32)
Coordinates:
  * x        (x) float64 -9.979 -9.938 -9.896 -9.854 ... 14.85 14.9 14.94 14.98
  * y        (y) float64 -14.98 -14.94 -14.9 -14.85 ... 9.854 9.896 9.938 9.979

Auf diese Weise wurden Zeichnungsdaten durch Zählen der Anzahl von Datenpunkten in einer Matrix mit einer Größe (600 x 600) erzeugt.

Wenn Sie anhand des Binärwerts aggregieren möchten, ob Datenpunkte eingegeben werden, anstatt zu zählen, verwenden Sie die Funktion `` `datashader.reductions.any``` und gehen Sie wie folgt vor.

canvas.points(df, 'x', 'y', agg=ds.any())
<xarray.DataArray (y: 600, x: 600)>
array([[False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       ...,
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False],
       [False, False, False, ..., False, False, False]])
Coordinates:
  * x        (x) float64 -9.979 -9.938 -9.896 -9.854 ... 14.85 14.9 14.94 14.98
  * y        (y) float64 -14.98 -14.94 -14.9 -14.85 ... 9.854 9.896 9.938 9.979

3. Konvertierung in Bild

Verwenden Sie zum Konvertieren in ein Bild die Funktion `shadow``` von` datashader.transfer_functions. Übergeben Sie die oben berechneten aggregierten Matrixdaten an das Argument der Funktion "Schatten". Zusätzlich werden verschiedene "Übertragungsfunktionen" vorbereitet, und Sie können die Bildausgabe optimieren. Hier wird das Ergebnis des Zählens und Summierens mit der Funktion `` `set_background in einen weißen Hintergrund gebracht und abgebildet.

tf.set_background(tf.shade(canvas.points(df,'x','y', agg=ds.count())), 'white')

output_26_0.png

Die Schattierung wird entsprechend der Dichte der Datenpunkte ausgedrückt, wodurch die Struktur viel einfacher zu sehen ist.

Versuchen Sie auf die gleiche Weise, mit zwei Werten zu summieren, ob Datenpunkte enthalten sind oder nicht.

tf.set_background(tf.shade(canvas.points(df,'x','y', agg=ds.any())), 'white')

output_28_0.png

Aggregieren Sie mit anderen Hilfsdaten

Bisher wurden nur die Koordinateninformationen der Daten für die Aggregation verwendet, aber es ist häufig der Fall, dass jeder Datenpunkt eine Bezeichnung einer Kategorie hat oder ein kontinuierlicher Wert zugewiesen wird.

Da solche Informationen nicht durch einfaches Zählen der Datenpunkte, die in das Pixel eintreten, wiedergegeben werden, gibt es für jeden eine spezielle Aggregationsfunktion.

Aggregation, wenn Hilfsdaten eine kategoriale Variable sind

Im Fall von MNIST gibt es eine Beschriftung für die richtige Antwortklasse, daher möchte ich sie richtig farblich kennzeichnen und zeichnen. Als Aggregatfunktion dafür gibt es `` `datashader.reductions.count_cat```. Diese Funktion zählt die Anzahl der Datenpunkte, die für jedes Etikett in ein Pixel eingehen. Mit anderen Worten, im Fall von MNIST werden 10 (600 x 600) Aggregatmatrizen erstellt.

Um count_cat verwenden zu können, müssen die Etikettendaten vom Kategorietyp Pandas (nicht vom Typ int) sein. Konvertieren Sie daher zuerst die Etikettenzeichenfolge des Datenrahmens in den Kategorietyp.

df['class'] = df['class'].astype('category')

Aggregieren Sie mit count_cat. Im Gegensatz zu den Aggregatfunktionen von `count``` und any``` müssen Sie den Spaltennamen angeben, dessen Spalte im Datenrahmen die Bezeichnung darstellt.

agg = canvas.points(df, 'x', 'y', ds.count_cat('class'))

Die Farbe jedes Etiketts wird in einem Wörterbuch definiert, wobei das Etikett als Schlüssel verwendet wird. Extrahieren Sie die Farbe "Paired" aus matplotlib, um sie an die Farbe der Figur anzupassen, wenn Sie sie zu Beginn zeichnen. Einfache Verwendung mit einer Liste vom Typ Wörterbuch.

import matplotlib
color_key = {i:matplotlib.colors.rgb2hex(c[:3]) for i, c 
             in enumerate(matplotlib.cm.get_cmap('Paired', 10).colors)}
print(color_key)
{0: '#a6cee3', 1: '#1f78b4', 2: '#b2df8a', 3: '#fb9a99', 4: '#e31a1c', 5: '#fdbf6f', 6: '#cab2d6', 7: '#6a3d9a', 8: '#ffff99', 9: '#b15928'}

Versuchen Sie es sich vorzustellen. Es scheint, dass die Farbe jedes Pixels gezeichnet wird, indem jede Farbe gemäß der Anzahl der Beschriftungen von Datenpunkten gemischt wird, die in das Pixel eintreten.

tf.set_background(tf.shade(agg, color_key=color_key), 'white')

output_39_0.png

Aggregation, wenn Hilfsdaten ein kontinuierlicher Wert sind

Jedem Datenpunkt kann eine Art kontinuierlicher Wert zugeordnet sein. Wenn beispielsweise bei der Einzelzellanalyse dimensional komprimierte Zahlen von Zehntausenden von Zellen verwendet werden, wird die Farbtiefe für jede Zelle um ein bestimmtes Genexpressionsniveau geändert.

Da ein Pixel mehrere Datenpunkte enthält, muss auf irgendeine Weise ein repräsentativer Wert bestimmt werden. Als Aggregatfunktion dafür werden einfache Statistiken wie Max, Mean, Mode erstellt.

MNIST verfügt nicht über Hilfsdaten mit kontinuierlichem Wert. Versuchen Sie daher, diese entsprechend zu erstellen. Berechnen wir als leicht verständliche Menge die durchschnittliche Helligkeit des zentralen Bildbereichs. Null sollte dunkel sein (da die Linie selten in der Bildmitte verläuft) und 1 sollte hell sein.

data = pd.read_csv('./mnist.csv').values[:, :784]
data.shape
(70000, 784)
#Es ist ein Bild in der Größe 28 x 28.
upper_left = 28 * 13 + 14
upper_right = 28 * 13 + 15
bottom_left = 28 * 14 + 14
bottom_right = 28 * 14 + 15

average_center_area = data[:, [upper_left, upper_right, 
                               bottom_left, bottom_right]].mean(axis=1)

Versuchen Sie zunächst, normal mit matplotlib zu zeichnen.

fig, ax = plt.subplots(figsize=(12, 12))

sc = ax.scatter(df['x'], df['y'], c=average_center_area, cmap='viridis', 
                vmin=0, vmax=255, s=6, alpha=1.0)

plt.colorbar(sc)
plt.axis('off')
plt.show()

output_45_0.png

Immerhin ist es zerquetscht und ich verstehe nicht gut.

Übergeben Sie es an den Datashader und versuchen Sie, es gemäß dem "Maximalwert" der in jedem Pixel enthaltenen Datenpunkte zu malen. Es kann mit der Funktion `` `datashader.reductions.max``` aggregiert werden.

df['value'] = average_center_area
agg = canvas.points(df, 'x', 'y', agg=ds.max('value'))
tf.set_background(tf.shade(agg, cmap=matplotlib.cm.get_cmap('viridis')), 'white')

output_47_0.png

Es ist leichter zu sehen. Es unterscheidet sich möglicherweise nicht wesentlich von der Anpassung der Größe auf eine kleinere Größe mit Streuung von Matplotlib, aber es ist praktisch, ohne detailliertes Ausprobieren schön zeichnen zu können.

Auch wenn die Datengröße sehr groß ist, ist sie schnell, sodass es nicht stressig ist, verschiedene Anpassungen vorzunehmen, z. B. was passiert, wenn mit Durchschnittswerten summiert wird.

agg = canvas.points(df, 'x', 'y', agg=ds.mean('value'))
tf.set_background(tf.shade(agg, cmap=matplotlib.cm.get_cmap('viridis')), 'white')

output_49_0.png

Recommended Posts

Verwalten Sie die Überlappung, wenn Sie ein Streudiagramm mit einer großen Datenmenge zeichnen (Matplotlib, Pandas, Datashader).
Eine Sammlung von Methoden, die beim Aggregieren von Daten mit Pandas verwendet werden
Ich möchte das Problem des Speicherverlusts bei der Ausgabe einer großen Anzahl von Bildern mit Matplotlib lösen
Ein Memorandum of Method, das häufig bei der Analyse von Daten mit Pandas verwendet wird (für Anfänger)
Versuchen Sie, mit matplotlib aus den Daten von "Schedule-kun" eine Kampfaufzeichnungstabelle zu erstellen.
Beim Lesen einer CSV-Datei mit read_csv von Pandas wird die erste Spalte zum Index
Mit den Daten von COVID-19 wurde ein Netzwerkdiagramm erstellt.
Hinweise zum Umgang mit großen Datenmengen mit Python + Pandas
Einführung in das Potenzial von Plotlys Streudiagramm anhand praktischer Beispiele
Formatieren Sie die Zeitachse des Pandas-Zeitreihendiagramms mit matplotlib neu
Wenn ich mit matplotlib eine große Anzahl von Diagrammen generiere, möchte ich das Diagramm nicht auf dem Bildschirm anzeigen (Jupyter-Umgebung).
Wie erstelle ich eine große Menge an Testdaten in MySQL? ??
Zeigen Sie die Beschriftung jedes Elements an, wenn Sie ein Streudiagramm in Pandas zeichnen
Vielseitige Datenerfassung mit Pandas + Matplotlib
Ändern Sie nicht die Reihenfolge der Spalten, wenn Sie Pandas-Datenrahmen verketten.
Ich habe einen Fehler beim Abrufen der Hierarchie mit MultiIndex von Pandas gemacht
Das Ergebnis war besser, als die Trainingsdaten des Mini-Batches als Hybrid aus fest und zufällig mit einem neuronalen Netzwerk erstellt wurden.
Richten Sie die Größe der Farbleiste an der Matplotlib aus
Versuchen Sie, mit matplotlib eine Normalverteilung zu zeichnen
Beispiel für eine effiziente Datenverarbeitung mit PANDAS
Ein Memorandum über Probleme beim Formatieren von Daten
Einführung des Zeichnungscodes für Figuren mit einem gewissen Grad an Perfektion der Wetterdaten
[Überprüfung] Nimmt levelDB Zeit zum Registrieren von Daten, wenn die Datenmenge zunimmt? ??
Link zu den Datenpunkten des von jupyterlab & matplotlib erstellten Diagramms
Ändern Sie den Datenrahmen der Pandas-Kaufdaten (ID x Produkt) in ein Wörterbuch
Zeichnen Sie ein Faltlinien- / Streudiagramm mit Python Matplotlib für die CSV-Datei (2 Spalten).
[Einführung in Python] So erhalten Sie den Datenindex mit der for-Anweisung