Gegeben ist eine Punktewolke, die offensichtlich 6 Gruppen enthält, die sich jeweils um ein inneres Zentrum gruppiert haben. Wie kann man jetzt herausfinden, wo die einzelnen Gruppen ihr Zentrum haben, wie viele Punkte sich in der Gruppe befinden und welchen Durchmesser ein Kreis um die Gruppe haben muss, wenn mindestens 85 % alle Gruppenpunkte umschlossen sein sollen.
Punktewolke.csv Wichtig! Der Delimiter ist hier jedoch kein Komma, sondern ein Simikolon ";"
Zunächst habe ich eine Funktion: find_cluster_circle(cluster_data,accuracy) erstellt und als GruppenAuswahlFunktion.py gespeichert.
from typing import Tuple
import pandas as pd
from scipy.spatial.distance import euclidean
import numpy as np
def find_cluster_circle(cluster_data: pd.DataFrame, accuracy: float = 0.85) -> Tuple[pd.Series, float, int]:
"""
Findet den Kreis, der eine gegebene Genauigkeit der Punkte in einem Cluster umfasst.
Parameter:
- cluster_data: DataFrame mit den Datenpunkten im Cluster. Sollte zwei Spalten für x und y haben.
- accuracy: Der Anteil der Punkte, die im Kreis enthalten sein sollen (zwischen 0 und 1).
Rückgabewert:
- Ein Tupel mit drei Elementen:
1. Das Zentrum des Kreises als Pandas Series.
2. Der Radius des Kreises als Float.
3. Die Anzahl der Punkte im Kreis als Integer.
"""
# Berechnung des Zentrums des Clusters
cluster_center = cluster_data.mean()
# Berechnung der euklidischen Entfernungen zum Zentrum
distances = cluster_data.apply(lambda row: euclidean(row, cluster_center), axis=1)
# Finden des Perzentils der Entfernungen entsprechend der gewünschten Genauigkeit
radius = np.percentile(distances, accuracy * 100)
# Anzahl der Punkte im Kreis
points_in_circle = sum(distances <= radius)
return cluster_center, radius, points_in_circle
Im Anschluss habe ich das Hauptprogramm erstellt, hier wird die Punktewolke mit der Hilfe von sklearn.Cluster analysiert und die einzelnen Cluster werden ermittelt. Einfache kann man es sich nicht machen!
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import DBSCAN
from sklearn.cluster import KMeans
from GruppenAuswahlFunktion import find_cluster_circle
import matplotlib.patches as patches
accuracy = 0.85
# Daten laden
data = pd.read_csv('Punktewolke.csv', delimiter=';')
# Datentypen auf int setzen
data = data.astype(int)
kmeans = KMeans(n_clusters=6, n_init=10)
data['cluster_kmeans'] = kmeans.fit_predict(data)
# DBSCAN
dbscan = DBSCAN(eps=5, min_samples=15)
data['cluster_dbscan'] = dbscan.fit_predict(data)
# Code-Vorbereitung für die Ausführung in der lokalen Umgebung
# Iterieren Sie durch die eindeutigen Cluster-IDs und sammeln Sie die Informationen für jeden Cluster.
cluster_info = {}
unique_clusters = data['cluster_kmeans'].unique()
for cluster_id in unique_clusters:
cluster_data = data[data['cluster_kmeans'] == cluster_id]
cluster_center, radius, points_in_circle = find_cluster_circle(cluster_data, accuracy)
cluster_info[cluster_id] = {'center': cluster_center, 'radius': radius, 'points': points_in_circle}
# Erstellen Sie einen Plot mit allen Punkten und Kreisen
plt.figure(figsize=(10, 10))
# Zeichnen Sie die Punkte für jedes Cluster in einer eigenen Farbe
for cluster_id in unique_clusters:
cluster_data = data[data['cluster_kmeans'] == cluster_id]
plt.scatter(cluster_data.iloc[:, 0], cluster_data.iloc[:, 1], label=f'Cluster {cluster_id}')
# Zeichnen Sie die Kreise und Zentren
for cluster_id, info in cluster_info.items():
center = info['center']
radius = info['radius']
points_in_circle = info['points']
plt.scatter(center.iloc[0], center.iloc[1], color='red', zorder=5) # Zentrum
circle = patches.Circle((center.iloc[0], center.iloc[1]), radius, fill=False, linestyle='dashed') # Kreis
plt.gca().add_patch(circle)
# Hinzufügen von Cluster_ID und der Anzahl der Punkte im Kreis als Kommentar über dem Kreis
plt.annotate(f"Cluster_ID: {cluster_id}\n{points_in_circle} Punkte\n{int(radius) * 2} Durchmesser",
(center.iloc[0], center.iloc[1]),
textcoords="offset points",
xytext=(0, radius),
ha='center',
va='bottom')
plt.xlabel('X')
plt.ylabel('Y')
plt.title(f'Clusteranalyse mit K-Means und {accuracy * 100}% Kreisen')
plt.legend()
plt.axis('equal')
plt.show()
# Erstellen einer Zusammenfassungstabelle
summary_table = pd.DataFrame(
columns=['Cluster_ID', 'Anzahl_Punkte_im_Kreis', 'Mittelpunkt_x', 'Mittelpunkt_y', 'Radius'])
for cluster_id, info in cluster_info.items():
center = info['center']
radius = info['radius']
points_in_circle = info['points']
new_row = {
'Cluster_ID': cluster_id,
'Anzahl_Punkte_im_Kreis': points_in_circle,
'Mittelpunkt_x': center.iloc[0],
'Mittelpunkt_y': center.iloc[1],
'Radius': radius
}
summary_table = summary_table.append(new_row, ignore_index=True)
# Sortieren der Tabelle nach 'Cluster_ID'
summary_table = summary_table.sort_values(by='Cluster_ID')
print(summary_table)
Cluster_ID | Anzahl_Punkte_im_Kreis | Mittelpunkt_x | Mittelpunkt_y | Radius |
---|---|---|---|---|
0.0 | 38.0 | 52.33 | 235.48 | 77.01 |
1.0 | 23.0 | 497.44 | 379.77 | 44.35 |
2.0 | 19.0 | 234.34 | 109.13 | 39.84 |
3.0 | 18.0 | 519.19 | 125.71 | 42.80 |
4.0 | 18.0 | 271.00 | 394.00 | 44.69 |
5.0 | 12.0 | 376.50 | 203.85 | 35.49 |