【问题标题】:Python: how to put initial centroids on specific data points in k-means?Python:如何将初始质心放在 k-means 中的特定数据点上?
【发布时间】:2018-05-09 05:55:08
【问题描述】:

我有以下数据:

import pandas as pd
import random
import matplotlib.pyplot as plt

df = pd.DataFrame()
df['x'] = [3, 2, 4, 3, 4, 6, 8, 7, 8, 9]
df['y'] = [3, 2, 3, 4, 5, 6, 5, 4, 4, 3]
df['val'] = [1, 10, 1, 1, 1, 8, 1, 1, 1, 1]

k = 2
centroids = {i + 1: [np.random.randint(0, 10), np.random.randint(0, 10)] for i in range(k)}

plt.scatter(df['x'], df['y'], color='blue')
for i in centroids.keys():
    plt.scatter(*centroids[i], color='red', marker='^')
plt.show()

我想将初始质心放在具有最高值的数据点上。那么,在这种情况下,质心应该位于坐标为 (2, 2) 和 (6, 6) 的数据点上。

   x  y  val
0  3  3    1
1  2  2   10
2  4  3    1
3  3  4    1
4  4  5    1
5  6  6    8
6  8  5    1
7  7  4    1
8  8  4    1
9  9  3    1

【问题讨论】:

  • 你在使用来自 scikit learn 的 KMeans 估计器吗?如果是这样,您可以传递一个给出初始中心的数组。请参阅init 参数here。或者您是在问如何首先构建该数组?
  • @MarkDickinson 是的,我在问如何编写 python 代码让我将质心放在具有最高值的节点上,因为我在这里没有使用 scikit learn。我为 kmeans 编写了自己的代码。

标签: python pandas machine-learning k-means centroid


【解决方案1】:

您可以按val 列对数据框进行排序以获取顶部k 值的索引,然后使用df.iloc 对数据框进行切片。


降序排列:

df = df.sort_values('val', ascending=False)
print(df)

   x  y  val
1  2  2   10
5  6  6    8
0  3  3    1
2  4  3    1
3  3  4    1
4  4  5    1
6  8  5    1
7  7  4    1
8  8  4    1
9  9  3    1

切片数据框:

k=2 # Number of centroids
highest_points_as_centroids = df.iloc[0:k,[0,1]]

print(highest_points_as_centroids )

   x  y
1  2  2
5  6  6

您可以通过highest_points_as_centroids.values 将 x,y 值作为 numpy 数组获取

array([[2, 2],
       [6, 6]], dtype=int64)

编辑1:

或者,更简洁(如@sharatpc 建议的那样)

df.nlargest(2, 'val')[['x','y']].values
array([[2, 2],
   [6, 6]], dtype=int64)

EDIT2:

正如 OP 所说,他们希望质心在字典中:

centroids = highest_points_as_centroids.reset_index(drop=True).T.to_dict('list')
print(centroids)
{0: [2L, 2L], 1: [6L, 6L]}

如果严格要求字典键从1开始:

highest_points_as_centroids.reset_index(drop=True, inplace=True)
highest_points_as_centroids.index +=1
centroids = highest_points_as_centroids.T.to_dict('list')
print(centroids)
{1: [2L, 2L], 2: [6L, 6L]}

【讨论】:

  • 您不需要对数据帧进行切片。只需使用 nlargest 获得前 2 名:df.nlargest(2, 'val');或df.sort_values('val',ascending=False).head(2)
  • 如果您想要输出中的 x 和 y,则:df.nlargest(k, 'val')[['x','y']]df.sort_values('val',ascending=False)[['x','y']].head(k)
  • 谢谢!不知道nlargest。我将其添加到答案中。
  • centroids=df.nlargest(k, 'val')[['x','y']] plt.scatter(df['x'], df['y'], color='blue') plt.scatter(centroids.x, centroids.y, color='red', marker='^') plt.show() 红色标记将叠加在蓝色上
  • @arizamoona 编辑了答案以在没有 for 循环的情况下在字典中获取质心
【解决方案2】:

只是为了在一个地方回答 @arzamoona 的其他问题:

import pandas as pd
import random
import matplotlib.pyplot as plt

df = pd.DataFrame()
df['x'] = [3, 2, 4, 3, 4, 6, 8, 7, 8, 9]
df['y'] = [3, 2, 3, 4, 5, 6, 5, 4, 4, 3]
df['val'] = [1, 10, 1, 1, 1, 8, 1, 1, 1, 1]

k = 2
centroids=df.nlargest(k, 'val')[['x','y']]

plt.scatter(df['x'], df['y'], color='blue')
plt.scatter(centroids.x, centroids.y, color='red', marker='^')
plt.show()

然后将质心值添加到字典中:

{i:v for i,v in enumerate(centroids.values.tolist())}
{0: [2, 2], 1: [6, 6]}

【讨论】:

  • 您可以使用to_dict 将质心转换为没有for循环的字典。
  • 但这会分散:{'x': {1: 2, 5: 6}, 'y': {1: 2, 5: 6}}
  • 您必须更改 orient 参数。检查我的答案的Edit2
  • 不错的熊猫方式。 :)
  • @sharatpc 抱歉,我想将for i in centroids.keys(): plt.scatter(*centroids[i], color='red', marker='^'){i:v for i,v in enumerate(centroids.values.tolist())} 一起使用,但出现错误。我该怎么办?
猜你喜欢
  • 2019-05-14
  • 2016-06-27
  • 2014-01-25
  • 2019-11-26
  • 2019-02-03
  • 2017-07-04
  • 2017-02-09
  • 2020-02-21
相关资源
最近更新 更多