¿Cómo puedo usar KNN / K-medias para agrupar series de tiempo en un dataframe?

Supongamos un dataframe que contiene 1000 filas. Cada fila representa una serie de tiempo.

Luego construí un algoritmo DTW para calcular la distancia entre 2 filas.

No sé qué hacer a continuación para completar una tarea de clasificación no supervisada para el dataframe.

¿Cómo etiquetar todas las filas del dataframe?

Definiciones

Algoritmo KNN = algoritmo de clasificación K-vecino más cercano

K-means = algoritmo de agrupamiento basado en centroide

DTW = Dynamic Time Warping un algoritmo de medición de similitud para series de tiempo

A continuación, muestro paso a paso cómo se pueden construir las dos series de tiempo y cómo se puede calcular el algoritmo Dynamic Warping (DTW). Puede crear un clúster k-means sin supervisión con scikit-learn sin especificar el número de centroides, luego scikit-learn sabe utilizar el algoritmo denominado auto .

Construyendo las series de tiempo y computando el DTW.

Tiene dos series de tiempo y calcula el DTW de tal manera que

introduzca la descripción de la imagen aquí introduzca la descripción de la imagen aquí

 import pandas as pd import numpy as np import random from dtw import dtw from matplotlib.pyplot import plot from matplotlib.pyplot import imshow from matplotlib.pyplot import cm from sklearn.cluster import KMeans from sklearn.preprocessing import MultiLabelBinarizer #About classification, read the tutorial #http://scikit-learn.org/stable/tutorial/basic/tutorial.html def createTs(myStart, myLength): index = pd.date_range(myStart, periods=myLength, freq='H'); values= [random.random() for _ in range(myLength)]; series = pd.Series(values, index=index); return(series) #Time series of length 30, start from 1/1/2000 & 1/2/2000 so overlap myStart='1/1/2000' myLength=30 timeS1=createTs(myStart, myLength) myStart='1/2/2000' timeS2=createTs(myStart, myLength) #This could be your dataframe but unnecessary here #myDF = pd.DataFrame([x for x in timeS1.data], [x for x in timeS2.data])#, columns=['data1', 'data2']) x=[xxx*100 for xxx in sorted(timeS1.data)] y=[xx for xx in timeS2.data] choice="dtw" if (choice="timeseries"): print(timeS1) print(timeS2) if (choice=="drawingPlots"): plot(x) plot(y) if (choice=="dtw"): #DTW with the 1st order norm myDiff=[xx-yy for xx,yy in zip(x,y)] dist, cost, acc, path = dtw(x, y, dist=lambda x, y: np.linalg.norm(myDiff, ord=1)) imshow(acc.T, origin='lower', cmap=cm.gray, interpolation='nearest') plot(path[0], path[1], 'w') 

Clasificación de las series de tiempo con KNN

¿No es evidente en la pregunta sobre qué se debe etiquetar y con qué tags? Así que por favor proporcione los siguientes detalles

  • ¿Qué debemos etiquetar en el dataframe? La ruta calculada por el algoritmo DTW?
  • ¿Qué tipo de etiquetado? ¿Binario? Multiclases

después de lo cual podemos decidir nuestro algoritmo de clasificación, que puede ser el llamado algoritmo KNN. Funciona de tal manera que tiene dos conjuntos de datos separados: conjunto de entrenamiento y conjunto de prueba. Con el conjunto de entrenamiento, usted enseña el algoritmo para etiquetar las series de tiempo, mientras que el conjunto de pruebas es una herramienta con la cual podemos medir qué tan bien funciona el modelo con herramientas de selección de modelos, como el AUC.

Pequeño rompecabezas dejado abierto hasta que se proporcionen detalles sobre las preguntas

 #PUZZLE #from tutorial (#http://scikit-learn.org/stable/tutorial/basic/tutorial.html) newX = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]] newY = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]] newY = MultiLabelBinarizer().fit_transform(newY) #Continue to the article. 

El artículo de comparación de Scikit-learn sobre clasificadores se proporciona en el segundo elemento de enumeración a continuación.

Agrupación con medios K (no es lo mismo que KNN)

K-means es el algoritmo de agrupación en clúster y su versión no supervisada que puede usar de tal manera que

 #Unsupervised version "auto" of the KMeans as no assignment for the n_clusters myClusters=KMeans(path) #myClusters.fit(YourDataHere) 

que es un algoritmo muy diferente al algoritmo KNN: aquí no necesitamos tags. Le proporciono más material sobre el tema a continuación en el primer elemento de enumeración.

Otras lecturas

  1. ¿K-medias incorpora el algoritmo K-vecino más cercano?

  2. Comparacion sobre clasificadores en scikit aprender aqui

Puede utilizar DTW . De hecho, tuve el mismo problema para uno de mis proyectos y escribí mi propia clase para eso en Python.

Aquí está la lógica;

  1. Crea tus combinaciones de todos los clústeres. k es para el conteo de conglomerados y n es para el número de series. El número de artículos devueltos debe ser n! / k! / (nk)! n! / k! / (nk)! . Estos serían algo así como centros potenciales.
  2. Para cada serie, calcule las distancias para cada centro en cada grupo de grupos y asígnelo al mínimo.
  3. Para cada grupo de grupos, calcule la distancia total dentro de grupos individuales.
  4. Elige el mínimo.

Y el código;

 import numpy as np import pandas as pd from itertools import combinations import time def dtw_distance(x, y, d=lambda x,y: abs(xy), scaled=False, fill=True): """Finds the distance of two arrays by dynamic time warping method source: https://en.wikipedia.org/wiki/Dynamic_time_warping Dependencies: import numpy as np Args: x, y: arrays d: distance function, default is absolute difference scaled: boolean, should arrays be scaled before calculation fill: boolean, should NA values be filled with 0 returns: distance as float, 0.0 means series are exactly same, upper limit is infinite """ if fill: x = np.nan_to_num(x) y = np.nan_to_num(y) if scaled: x = array_scaler(x) y = array_scaler(y) n = len(x) + 1 m = len(y) + 1 DTW = np.zeros((n, m)) DTW[:, 0] = float('Inf') DTW[0, :] = float('Inf') DTW[0, 0] = 0 for i in range(1, n): for j in range(1, m): cost = d(x[i-1], y[j-1]) DTW[i, j] = cost + min(DTW[i-1, j], DTW[i, j-1], DTW[i-1, j-1]) return DTW[n-1, m-1] def array_scaler(x): """Scales array to 0-1 Dependencies: import numpy as np Args: x: mutable iterable array of float returns: scaled x """ arr_min = min(x) x = np.array(x) - float(arr_min) arr_max = max(x) x = x/float(arr_max) return x class TrendCluster(): def __init__(self): self.clusters = None self.centers = None self.scale = None def fit(self, series, n=2, scale=True): ''' Work-flow 1 - make series combination with size n, initial clusters 2 - assign closest series to each cluster 3 - calculate total distance for each combinations 4 - choose the minimum Args: series: dict, keys can be anything, values are time series as list, assumes no nulls n: int, cluster size scale: bool, if scale needed ''' assert isinstance(series, dict) and isinstance(n, int) and isinstance(scale, bool), 'wrong argument type' assert n < len(series.keys()), 'n is too big' assert len(set([len(s) for s in series.values()])) == 1, 'series length not same' self.scale = scale combs = combinations(series.keys(), n) combs = [[c, -1] for c in combs] series_keys = pd.Series(series.keys()) dtw_matrix = pd.DataFrame(series_keys.apply(lambda x: series_keys.apply(lambda y: dtw_distance(series[x], series[y], scaled=scale)))) dtw_matrix.columns, dtw_matrix.index = series_keys, series_keys for c in combs: c[1] = dtw_matrix.loc[c[0], :].min(axis=0).sum() combs.sort(key=lambda x: x[1]) self.centers = {c:series[c] for c in combs[0][0]} self.clusters = {c:[] for c in self.centers.keys()} for k, _ in series.items(): tmp = [[c, dtw_matrix.loc[k, c]] for c in self.centers.keys()] tmp.sort(key=lambda x: x[1]) cluster = tmp[0][0] self.clusters[cluster].append(k) return None def assign(self, serie, save=False): ''' Assigns the serie to appropriate cluster Args: serie, dict: 1 element dict save, bool: if new serie is stored to clusters Return: str, assigned cluster key ''' assert isinstance(serie, dict) and isinstance(save, bool), 'wrong argument type' assert len(serie) == 1, 'serie\'s length is not exactly 1' tmp = [[c, dtw_distance(serie.values()[0], self.centers[c], scaled=self.scale)] for c in self.centers.keys()] tmp.sort(key=lambda x: x[1]) cluster = tmp[0][0] if save: self.clusters[cluster].append(serie.keys()[0]) return cluster 

Si desea verlo en acción, puede consultar mi repository sobre Clustering de series de tiempo .