Найти расстояние между центром тяжести и точками в одном фрейме данных объекта - KMeans - PullRequest
2 голосов
/ 10 июля 2019

Я работаю над задачей обнаружения аномалий, используя KMeans.
Используемый мною фрейм данных Pandas имеет одну особенность, похожую на следующую:

df = array([[12534.],
           [12014.],
           [12158.],
           [11935.],
           ...,
           [ 5120.],
           [ 4828.],
           [ 4443.]])

Я могу подгонять и прогнозировать значения с помощью следующих инструкций:

km = KMeans(n_clusters=2)
km.fit(df)
km.predict(df)

Чтобы выявить аномалии, я хотел бы рассчитать расстояние между центроидом и каждой отдельной точкой, но с кадром данных с одной особенностью я не уверен, что это правильный подход.

Я нашел примеры, которые использовали евклидово расстояние для вычисления расстояния.Пример следующий:

def k_mean_distance(data, cx, cy, i_centroid, cluster_labels):
    distances = [np.sqrt((x - cx) ** 2 + (y - cy) ** 2) for (x, y) in data[cluster_labels == i_centroid]]
    return distances

centroids = self.km.cluster_centers_
distances = []
for i, (cx, cy) in enumerate(centroids):
    mean_distance = k_mean_distance(day_df, cx, cy, i, clusters)
    distances.append({'x': cx, 'y': cy, 'distance': mean_distance})

Этот код не работает для меня, потому что центроиды в моем случае похожи на следующий, так как у меня есть один фрейм данных:

array([[11899.90692187],
       [ 5406.54143126]])

В этом случае, как правильно найти расстояние между центроидом и точками?Возможно ли это?

Спасибо и простите за тривиальный вопрос, я все еще учусь

Ответы [ 2 ]

2 голосов
/ 10 июля 2019

Есть scipy.spatial.distance_matrix, вы можете использовать:

# setup a set of 2d points
np.random.seed(2)
df = np.random.uniform(0,1,(100,2))

# make it a dataframe
df = pd.DataFrame(df)

# clustering with 3 clusters
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3)
km.fit(df)
preds = km.predict(df)

# get centroids
centroids = km.cluster_centers_

# visualize
plt.scatter(df[0], df[1], c=preds)
plt.scatter(centroids[:,0], centroids[:,1], c=range(centroids.shape[0]), s=1000)

дает

enter image description here

Теперь матрица расстояний:

from scipy.spatial import distance_matrix

dist_mat = pd.DataFrame(distance_matrix(df.values, centroids))

Вы можете подтвердить, что это правильно,

dist_mat.idxmin(axis=1) == preds

И, наконец, среднее расстояние до центроидов:

dist_mat.groupby(preds).mean()

дает:

          0         1         2
0  0.243367  0.525194  0.571674
1  0.525350  0.228947  0.575169
2  0.560297  0.573860  0.197556

где столбцы обозначают число центроидов, а строки - среднее расстояние между точками в кластере.

1 голос
/ 10 июля 2019

Вы можете использовать scipy.spatial.distance.cdist для создания матрицы расстояний:

from scipy.spatial.distance import cdist
dm = cdist(df, centroids)

Это должно дать вам двумерный массив, где каждая строка представляет наблюдение в вашем исходном наборе данных, а каждый столбец представляет центроид. X-я строка в y-м столбце показывает расстояние между вашим x-м наблюдением до вашего y-го кластерного центроида. cdist по умолчанию использует евклидово расстояние, но вы можете использовать другие метрики (не то, чтобы это имело большое значение для набора данных только с одной функцией).

...