[PYTHON] Ich habe versucht, EKG-Daten mit der K-Shape-Methode zu gruppieren

Diese Artikelzusammenfassung

Datensatz

  • Dieses Mal verwenden wir das UCR Time Series Classification Archive der University of California, Riverside.

  • EKG fördert bekanntermaßen die Erkennung von Herzerkrankungen

  • Der zu verwendende Inhalt von ** ECGFiveDays_TRAIN.tsv ** lautet wie folgt.

DataFrame


df = pd.read_table("ECGFiveDays_TRAIN.tsv",header=None)
df.head(10)

image.png

Klicken Sie hier für eine Datenübersicht

Summary


import numpy as np
import matplotlib.pyplot as plt
from tslearn.utils import to_time_series_dataset

data_train = np.loadtxt("ECGFiveDays_TRAIN.tsv")
X_train = to_time_series_dataset(data_train[:,1:])
print("Gesamtzahl der Zeitreihendaten: ",len(data_train))
print("Anzahl der Klassen: ", len(np.unique(data_train[:,0])))
print("Zeitreihenlänge: ",len(data_train[0,1:]))

----------------------
#Gesamtzahl der Zeitreihendaten:  23
#Anzahl der Klassen:  2
#Zeitreihenlänge:  136

Insgesamt sind 23 Zeitreihendaten mit 136 Schnappschüssen enthalten. Es fehlen keine Werte.

Vizualize


%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
for i in range(0,3):
    if data_train[i,0]==2.0:
        plt.figure(figsize=(18, 8))
        print("Plot",i,"Class",data_train[i,0])
        plt.plot(data_train[i],c='r')
        plt.show()

image.png

image.png

Da diese Etiketten von EKG-Experten angebracht werden, sind sowohl Klasse 1.0 als auch Klasse 2.0 für die Augen eines Amateurs kaum zu unterscheiden. Als Ergänzung enthält dieses Elektrokardiogramm laut Readme.md, das mit ECGFiveDays_TRAIN.tsv heruntergeladen wird, EKG-Daten eines 67-jährigen Mannes, die 1990 gemessen wurden.

Vorverarbeitung

Normalisieren Sie alle Zeitreihendaten so, dass sie einen Durchschnitt von 0 und eine Standardabweichung von 1 haben, um sie in die K-Form zu bringen. Hier werde ich das EKG von Plot0, Klasse 1.0, normalisieren, grafisch darstellen und vergleichen.

Normalisierung


from tslearn.preprocessing import TimeSeriesScalerMeanVariance
from tslearn.utils import to_time_series_dataset
X_train = to_time_series_dataset(data_train[:,1:])
X_train = TimeSeriesScalerMeanVariance(mu=0.,std=1.).fit_transform(X_train)
plt.figure(figsize=(18, 8))
plt.plot(X_train[1],c='magenta',alpha=0.8,label="normalized")
plt.plot(data_train[1],c='blue',alpha=0.8,label="original")
plt.legend(fontsize=17)

image.png

  • Verglichen mit dem normalisierten roten Diagramm der Klasse 2.0 sieht es wie in der folgenden Abbildung aus. image.png

Informationen zur K-Shape-Methode

Ich werde kurz mit 3 Punkten zusammenfassen.

  • Eine formbasierte Clustering-Methode für Zeitreihendaten
  • Grundsätzlich das gleiche wie k-means, aber die Art und Weise, den Abstand zu messen, ist unterschiedlich
  • Das Folgende ist ein K-förmiges Papier. Der 2015 geschriebene Algorithmus selbst ist relativ neu ( https://dl.acm.org/doi/10.1145/2723372.2737793)

Nun zum Training

Führen Sie 2 Cluster, 100 maximale Iterationen und 100 Trainings aus.

Train


from tslearn.clustering import KShape
ks = KShape(n_clusters=2,max_iter=100,n_init=100,verbose=0)
ks.fit(X_train)
y_pred = ks.fit_predict(X_train)
print(y_pred)

---
#[0 1 0 0 1 0 0 1 0 1 1 1 1 0 0 0 1 0 1 1 1 0 1]

Für insgesamt 23 Zeitreihen konnten wir ein Vorhersageetikett anbringen, auf welche der beiden Klassen klassifiziert werden würde. Informationen zu Hyperparametern in Bezug auf K-Shape finden Sie unter der folgenden URL. https://tslearn.readthedocs.io/en/stable/gen_modules/clustering/tslearn.clustering.KShape.html

Auswertung

Der ** angepasste Landindex ** wird als Bewertungsskala für die Zeitreihenclusterung verwendet. Kurz gesagt, diese Metrik misst, "wie gut die Clusterzuordnungen zwischen vorhergesagtem Clustering und echtem Clustering übereinstimmen".

Hier wird der angepasste_Rand_score von Scikit-learn verwendet. https://scikit-learn.org/stable/modules/generated/sklearn.metrics.adjusted_rand_score.html

Auswertung(Für Trainingsdaten)


from sklearn.metrics import adjusted_rand_score
ars = adjusted_rand_score(data_train[:,0],y_pred)
print("Angepasster Landindex: ",ars)
---
#Angepasster Landindex:  0.668041237113402

Als nächstes finden Sie die Ars für die Testdaten.

Auswertung(Für Testdaten)


import numpy as np
import matplotlib.pyplot as plt
from tslearn.utils import to_time_series_dataset

data_test = np.loadtxt("ECGFiveDays_TEST.tsv")
X_test = to_time_series_dataset(data_test[:,1:])
pred_test = ks.predict(X_test)
ars = adjusted_rand_score(data_test[:,0],pred_test)
print("Angepasster Landindex: ",ars)
---
#Angepasster Landindex:  0.06420517898316379

Ich habe eine sehr niedrige Punktzahl.

Punktzahl nahe 0=Punktzahl bei zufälliger Zuordnung

Aufgrund der Logik kann niemals gesagt werden, dass es sich um ein gutes Modell handelt. Der Grund, warum die Punktzahl für die Testdaten niedrig ist, wird angenommen, dass die Anzahl der Daten überwiegend gering ist. Erhöhen Sie also die Anzahl der Daten und versuchen Sie es gleich.

Schulung / Bewertung anhand von EKG5000-Daten

Im Folgenden werden ** ECG5000_TRAIN.tsv ** und ** ECG500_TEST.tsv ** verwendet, die im UCR-Archiv enthalten sind.

EKG5000-Datensatz


import numpy as np
import matplotlib.pyplot as plt
from tslearn.utils import to_time_series_dataset
from sklearn.model_selection import train_test_split

data_test_ = np.loadtxt("ECG5000_TEST.tsv")
data_train_ = np.loadtxt("ECG5000_TRAIN.tsv")
data_joined = np.concatenate((data_train_,data_test_),axis=0)
data_train_,data_test_ =train_test_split(data_joined,test_size=0.2,random_state=2000) 

X_train_ = to_time_series_dataset(data_train_[:,1:])
X_test_ = to_time_series_dataset(data_test_[:,1:])

print("Gesamtzahl der Zeitreihendaten: ",len(data_train_))
print("Anzahl der Klassen: ", len(np.unique(data_train_[:,0])))
print("Zeitreihenlänge: ",len(data_train_[0,1:]))

---
#Gesamtzahl der Zeitreihendaten:  4000
#Anzahl der Klassen:  5
#Zeitreihenlänge:  140

Klicken Sie hier, um die Anzahl der zum Cluster gehörenden Daten anzuzeigen

Clusterdetails


print("Klasse 1.Anzahl der zu 0 gehörenden Daten",len(data_train_[data_train_[:,0]==1.0]))
print("Klasse 1.Anzahl der zu 0 gehörenden Daten",len(data_train_[data_train_[:,0]==2.0]))
print("Klasse 1.Anzahl der zu 0 gehörenden Daten",len(data_train_[data_train_[:,0]==3.0]))
print("Klasse 1.Anzahl der zu 0 gehörenden Daten",len(data_train_[data_train_[:,0]==4.0]))
print("Klasse 1.Anzahl der zu 0 gehörenden Daten",len(data_train_[data_train_[:,0]==5.0]))
---
#Klasse 1.Anzahl der Daten zu 0 2342
#Klasse 1.Anzahl der Daten zu 0 1415
#Klasse 1.Anzahl der Daten zu 0 74
#Klasse 1.Anzahl der zu 0 153 gehörenden Daten
#Klasse 1.Anzahl der Daten zu 0 16

In einem Diagramm sieht es so aus

Visualisierung jedes Clusters


%matplotlib inline
import matplotlib.pyplot as plt

for j in np.unique(data_train_[:,0]):
    plt.figure(figsize=(28,2))
    dataPlot = data_train_[data_train_[:,0]==j]
    cnt = len(dataPlot) 
    dataPlot = dataPlot[:,1:].mean(axis=0)
    print(" Class ",j," Count ",cnt)
    plt.plot(dataPlot,c='b')
    plt.show()

image.png

Wir werden wie bisher trainieren und bewerten

Ausbildung/Auswertung(Für Testdaten)


from tslearn.preprocessing import TimeSeriesScalerMeanVariance
from tslearn.utils import to_time_series_dataset
from tslearn.clustering import KShape
from sklearn.metrics import adjusted_rand_score
X_train_ = to_time_series_dataset(data_train_[:,1:])
X_train_ = TimeSeriesScalerMeanVariance(mu=0.,std=1.).fit_transform(X_train_)
X_test_ = to_time_series_dataset(data_test_[:,1:])
X_test_ = TimeSeriesScalerMeanVariance(mu=0.,std=1.).fit_transform(X_test_)

ks = KShape(n_clusters=5,max_iter=100,n_init=100,verbose=1,random_state=2000)
ks.fit(X_train_)
preds_test = ks.predict(X_test_)
ars_ = adjusted_rand_score(data_test_[:,0],preds_test)
print("Angepasster Landindex: ",ars_)
---
#Angepasster Landindex:  0.4984050982000773

Der Bewertungslandindex betrug bei Anwendung auf die Testdaten etwa 0,498 </ font>. Im Vergleich zur vorherigen Datenanwendung ist es ein Unterschied im Wolkenschlamm. Durch Erhöhen der Größe des Trainingssatzes von 23 auf 4000 wurde ein viel genaueres Modell erstellt.

Schauen wir uns zum Schluss die Testdaten an

Visualisierung der Klassifizierungsergebnisse


for yi in range(5):
    plt.figure(figsize=(20,35))
    plt.subplot(5, 1, 1 + yi)
    for xx in X_test_[preds_test == yi]:
        plt.plot(xx.ravel(), alpha=0.1,c='blue')
    cnt = len(X_test_[preds_test == yi]) 
    
    plt.plot(ks.cluster_centers_[yi].ravel(), "red")
    print(" Class ",yi," Count ",cnt)
    plt.title("Cluster %d" % (yi + 1) )

plt.tight_layout()
plt.show()

Hier ist eine Visualisierung der Klassifizierungsergebnisse der Testdaten (rote Linie ist Centroid) image.png

image.png

image.png

image.png

image.png

Zusammenfassung

  • Dieses Mal habe ich versucht, Zeitreihen mit formbasierten K-Form- und EKG-Daten zu gruppieren.
  • Durch Erhöhen der Anzahl der Daten ist die Punktzahl des angepassten Landindex explodiert.
  • Zusätzlich zu K-Shape können Sie auch Cluster mit k-means und DBSCAN erstellen, sodass ich sie in Zukunft vergleichen möchte.

Ergänzung

K-Form-Abstandsmessung

SBD(\vec{x},\vec{y})=1-\underset{w}{max}\frac{CC_w(\vec{x},\vec{y})}{\sqrt{R_0(\vec{x},\vec{x})}\sqrt{R_0(\vec{y},\vec{y})}}
  • Einführung von Ähnlichkeit und gegenseitiger Korrelation $ CC_w $, die gut zu Zeitreihendaten passt
  • $ SBD $ bedeutet die Entfernung von $ \ vec {x}, \ vec {y} $

Was ist tslearn?

tslearn ist ein Python-Paket für die Zeitreihenanalyse mit maschinellem Lernen. Neben K-Shape sind verschiedene Algorithmen zur Zeitreihenanalyse enthalten.

Verweise

  • https://www.slideshare.net/kenyanonaka/k-shapes-zemiyomi
  • https://dl.acm.org/doi/10.1145/2723372.2737793

Recommended Posts