📅  最后修改于: 2020-04-22 11:42:39             🧑  作者: Mango
我们获得了具有某些特征的项目数据集,以及这些特征的值(如矢量)。任务是将这些项目归类。为了达到这个目的,我们将使用kMeans算法。一种无监督的学习算法。
总览
(如果您将项目视为n维空间中的点,它将很有帮助)。该算法会将项目分类为k个相似度组。为了计算相似度,我们将使用欧式距离作为度量。
该算法的工作原理如下:
上面提到的“点”之所以称为均值,是因为它们拥有归类于其中的项目的平均值。初始化的方法,我们有很多选择。一种直观的方法是在数据集中的随机项目处初始化均值。另一种方法是在数据集边界之间的随机值处初始化均值。
上面的算法采用伪代码:
用随机值初始化k均值
对于给定的迭代次数:
遍历项目:
查找最接近该项目的均值
将项目分配为均值
更新均值
读取数据
我们接收输入为文本文件(‘data.txt’)。每行代表一个项目,并且包含数值(每个要素一个),并用逗号分隔。您可以在此处找到样本数据集。
我们将从文件中读取数据,并将其保存到列表中。列表的每个元素都是另一个列表,其中包含要素的项目值。我们使用以下函数来做到这一点:
def ReadData(fileName):
# 读取文件,按行分割
f = open(fileName, 'r');
lines = f.read().splitlines();
f.close();
items = [];
for i in range(1, len(lines)):
line = lines[i].split(',');
itemFeatures = [];
for j in range(len(line)-1):
v = float(line[j]); # 将要素值转换为浮点
itemFeatures.append(v); # 将特征值添加到字典
items.append(itemFeatures);
shuffle(items);
return items;
初始化手段
我们要在项目的特征值范围内初始化每个均值。为此,我们需要找到每个项的最小值和最大值。我们通过以下函数来实现:
def FindColMinMax(items):
n = len(items[0]);
minima = [sys.maxint for i in range(n)];
maxima = [-sys.maxint -1 for i in range(n)];
for item in items:
for f in range(len(item)):
if (item[f] < minima[f]):
minima[f] = item[f];
if (item[f] > maxima[f]):
maxima[f] = item[f];
return minima,maxima;
变量最小值minima,最大值maxima分别包含项的最小值和最大值列表。我们在以上两个列表的相应最小值和最大值之间随机初始化每个均值的特征值:
def InitializeMeans(items, k, cMin, cMax):
# 初始化方法以在每列的最小值和最大值之间随机数
f = len(items[0]); # 特征数量
means = [[0 for i in range(f)] for j in range(k)];
for mean in means:
for i in range(len(mean)):
# 将值设置为随机浮点数(添加+ -1以避免平均值的大范围放置)
mean[i] = uniform(cMin[i]+1, cMax[i]-1);
return means;
欧氏距离
我们将使用欧几里德距离作为数据集的相似性度量(注意:根据您的项目,您可以使用其他相似性度量)。
def EuclideanDistance(x, y):
S = 0; # 元素的平方差之和
for i in range(len(x)):
S += math.pow(x[i]-y[i], 2);
return math.sqrt(S); # 和的平方根
更新方式
要更新均值,我们需要为均值/集群中的所有项目找到其特征的平均值。我们可以通过将所有值相加然后除以项目数来做到这一点,或者可以使用更优雅的解决方案。通过执行以下操作,我们将无需重新添加所有值即可计算新的平均值:
m =(m *(n-1)+ x)/ n
其中,m是特征的平均值,n是群集中的数量,x是添加项的特征值。我们对每个feature执行上述操作以获取新的均值。
def UpdateMean(n,mean,item):
for i in range(len(mean)):
m = mean[i];
m = (m*(n-1)+item[i])/float(n);
mean[i] = round(m, 3);
return mean;
分类项目
现在,我们需要编写一个函数来将项目分类为组/集群。对于给定的项目,我们将计算它与每个均值的相似性,并将该项目分类为最接近的项目。
def Classify(means,item):
# 用最小距离将项目分类为均值
minimum = sys.maxint;
index = -1;
for i in range(len(means)):
# 查找项目到均值的距离
dis = EuclideanDistance(item, means[i]);
if (dis < minimum):
minimum = dis;
index = i;
return index;
寻找手段
为了真正找到均值,我们将遍历所有项目,将它们分类到最近的聚类,并更新聚类的均值。我们将以固定的迭代次数重复该过程。如果两次迭代之间没有项目更改分类,我们将停止该过程,因为该算法已找到最佳解决方案。
下面的函数将项,k(所需聚类的数量),和最大迭代次数作为输入,并返回均值和聚类。
def CalculateMeans(k,items,maxIterations=100000):
# 查找列的最小值和最大值
cMin, cMax = FindColMinMax(items);
# 在随机点初始化均值
means = InitializeMeans(items,k,cMin,cMax);
# 初始化集群,该数组容纳一个类中的项数
clusterSizes= [0 for i in range(len(means))];
# 一个数组,用于保存项目所在的集群
belongsTo = [0 for i in range(len(items))];
# 计算均值
for e in range(maxIterations):
# 如果集群没有发生变化,请停止
noChange = True;
for i in range(len(items)):
item = items[i];
# 将项目分类为集群并更新
index = Classify(means,item);
clusterSizes[index] += 1;
cSize = clusterSizes[index];
means[index] = UpdateMean(cSize,means[index],item);
# 项变更集群
if(index != belongsTo[i]):
noChange = False;
belongsTo[i] = index;
# 没什么改变,返回
if (noChange):
break;
return means;
最后,我们希望找到具有均值的聚类。我们将遍历所有项,并将每个项分类为最接近的类。
ef FindClusters(means,items):
clusters = [[] for i in range(len(means))]; # 初始化集群
for item in items:
# 将项目分类为集群
index = Classify(means,item);
# 将项目添加到集群
clusters[index].append(item);
return clusters;
其他常用的相似性度量是:
1. 余弦距离:它确定n维空间中两个点的点向量之间的夹角的余弦值
2. 曼哈顿距离:它计算两个数据点的坐标之间的绝对差之和。
3. Minkowski距离:也称为广义距离度量。它可以用于序数和定量变量。