聚类的概念:一种无监督的学习,事先不知道类别,自动将相似的对象归到同一个簇中。
K-Means算法是一种聚类分析(cluster analysis)的算法,其主要是来计算数据聚集的算法,主要通过不断地取离种子点最近均值的算法。
K-Means算法主要解决的问题如下图所示。我们可以看到,在图的左边有一些点,我们用肉眼可以看出来有四个点群,但是我们怎么通过计算机程序找出这几个点群来呢?于是就出现了我们的K-Means算法
这个算法其实很简单,如下图所示:
从上图中,我们可以看到,A,B,C,D,E是五个在图中点。而灰色的点是我们的种子点,也就是我们用来找点群的点。有两个种子点,所以K=2。
然后,K-Means的算法如下:
- 随机在图中取K(这里K=2)个种子点。
- 然后对图中的所有点求到这K个种子点的距离,假如点Pi离种子点Si最近,那么Pi属于Si点群。(上图中,我们可以看到A,B属于上面的种子点,C,D,E属于下面中部的种子点)
- 接下来,我们要移动种子点到属于他的“点群”的中心。(见图上的第三步)
- 然后重复第2)和第3)步,直到,种子点没有移动(我们可以看到图中的第四步上面的种子点聚合了A,B,C,下面的种子点聚合了D,E)。
这个算法很简单,重点说一下“求点群中心的算法”:欧氏距离(Euclidean Distance):差的平方和的平方根
import sklearn.datasets as datasets
rs = np.random.RandomState(seed = 10)
# np.random.randint(0,10,size = 5)
rs.randint(0,10,size = 5)
输出
array([9, 4, 0, 1, 9])
data,target = datasets.make_blobs()
plt.scatter(data[:,0],data[:,1],c = target)
<matplotlib.collections.PathCollection at 0x7fd1ead24da0>
target
输出
array([1, 0, 2, 2, 0, 2, 0, 1, 2, 1, 1, 2, 1, 1, 1, 0, 1, 2, 1, 2, 0, 1,
1, 2, 1, 1, 0, 1, 2, 0, 0, 0, 1, 1, 0, 2, 1, 2, 1, 0, 1, 1, 1, 2,
2, 2, 2, 2, 2, 1, 0, 0, 0, 2, 1, 0, 0, 0, 2, 2, 0, 0, 2, 2, 2, 1,
0, 2, 2, 2, 2, 2, 1, 1, 1, 2, 0, 0, 1, 0, 0, 2, 1, 0, 2, 1, 1, 2,
0, 0, 1, 0, 2, 0, 0, 0, 1, 0, 0, 0])
建立模型,训练数据,并进行数据预测,使用相同数据
无监督的情况下进行计算,预测
现在机器学习没有目标
绘制图形,显示聚类结果kmeans.cluster_centers
# Kmeans在进行机器学习,如果分类的种类不同,导致结果非常不同,
# 需要我们了解数据
kmeans = KMeans(5)
X_train = data
kmeans.fit(X_train)
# y_ 机器学习预测出来的类别
y_ = kmeans.predict(X_train)
plt.scatter(X_train[:,0],X_train[:,1],c = y_)
<matplotlib.collections.PathCollection at 0x7fd1eac4e9b0>
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
# K-Means k均值聚类 cluster
from sklearn.cluster import KMeans
/usr/lib/python3.5/importlib/_bootstrap.py:222: RuntimeWarning: numpy.dtype size changed, may indicate binary incompatibility. Expected 96, got 88 return f(*args, **kwds) 列名修改为:”国家”,”2006世界杯”,”2010世界杯”,”2007亚洲杯”
data = pd.read_csv('../data/Asiafootball.txt',header = None)
data.columns = ["国家","2006世界杯","2010世界杯","2007亚洲杯"]
data
国家 | 2006世界杯 | 2010世界杯 | 2007亚洲杯 | |
---|---|---|---|---|
0 | 中国 | 50 | 50 | 9 |
1 | 日本 | 28 | 9 | 4 |
2 | 韩国 | 17 | 15 | 3 |
3 | 伊朗 | 25 | 40 | 5 |
4 | 沙特 | 28 | 40 | 2 |
5 | 伊拉克 | 50 | 50 | 1 |
6 | 卡塔尔 | 50 | 40 | 9 |
7 | 阿联酋 | 50 | 40 | 9 |
8 | 乌兹别克斯坦 | 40 | 40 | 5 |
9 | 泰国 | 50 | 50 | 9 |
10 | 越南 | 50 | 50 | 5 |
11 | 阿曼 | 50 | 50 | 9 |
12 | 巴林 | 40 | 40 | 9 |
13 | 朝鲜 | 40 | 32 | 17 |
14 | 印尼 | 50 | 50 | 9 |
X_train = data.iloc[:,1:]
X_train
2006世界杯 | 2010世界杯 | 2007亚洲杯 | |
---|---|---|---|
0 | 50 | 50 | 9 |
1 | 28 | 9 | 4 |
2 | 17 | 15 | 3 |
3 | 25 | 40 | 5 |
4 | 28 | 40 | 2 |
5 | 50 | 50 | 1 |
6 | 50 | 40 | 9 |
7 | 50 | 40 | 9 |
8 | 40 | 40 | 5 |
9 | 50 | 50 | 9 |
10 | 50 | 50 | 5 |
11 | 50 | 50 | 9 |
12 | 40 | 40 | 9 |
13 | 40 | 32 | 17 |
14 | 50 | 50 | 9 |
k_means = KMeans(n_clusters=3)
# !!! 之前的算法,不同了,没有目标值
# y_target,算法会根据数据特征,自动将这15个球队分成3类
k_means.fit(X_train)
输出
KMeans(algorithm=’auto’, copy_x=True, init=’k-means++’, max_iter=300,
n_clusters=3, n_init=10, n_jobs=1, precompute_distances=’auto’,
random_state=None, tol=0.0001, verbose=0)
使用K-Means进行数据处理,对亚洲球队进行分组,分三组
# 3类
y_ = k_means.predict(X_train)
y_
输出
array([1, 2, 2, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1], dtype=int32)
for循环打印输出分组后的球队,argwhere()
np.argwhere(y_ == 0).ravel()
输出
array([ 3, 4, 8, 12, 13])
country = data['国家']
for i in range(3):
county_index = np.argwhere(y_ == i).ravel()
print(country[county_index])
print('\n')
3 伊朗
4 沙特
8 乌兹别克斯坦
12 巴林
13 朝鲜
Name: 国家, dtype: object
0 中国
5 伊拉克
6 卡塔尔
7 阿联酋
9 泰国
10 越南
11 阿曼
14 印尼
Name: 国家, dtype: object
1 日本
2 韩国
Name: 国家, dtype: object
绘制三维立体图形,ax = plt.subplot(projection = ‘3d’)
ax.scatter3D()
X_train.shape
输出
(15, 3)
type(X_train)
输出
pandas.core.frame.DataFrame
cluster_centers_ = k_means.cluster_centers_
cluster_centers_
输出
array([[34.6, 38.4, 7.6],
[50. , 47.5, 7.5],
[22.5, 12. , 3.5]])
plt.figure(figsize=(12,8))
axes3d = plt.subplot(projection = '3d')
axes3d.scatter3D(X_train.iloc[:,0],X_train.iloc[:,1],X_train.iloc[:,2],c = y_,cmap = 'rainbow',s = 50)
axes3d.scatter3D(cluster_centers_[:,0],cluster_centers_[:,1],cluster_centers_[:,2],
s = 300,c = k_means.predict(cluster_centers_),cmap = 'rainbow')
# 下课修改坐标刻度,应用matplotlib中知识
<mpl_toolkits.mplot3d.art3d.Path3DCollection at 0x7fca2068c978>
3、聚类实践与常见错误
导包,使用make_blobs创建样本点
import numpy as np
from sklearn.cluster import KMeans
import sklearn.datasets as datasets
import matplotlib.pyplot as plt
# RandomState 随机化状态
a = np.random.RandomState(seed = 10)
a.randint(0, 10, size=100)
输出
array([9, 4, 0, 1, 9, 0, 1, 8, 9, 0, 8, 6, 4, 3, 0, 4, 6, 8, 1, 8, 4, 1,
3, 6, 5, 3, 9, 6, 9, 1, 9, 4, 2, 6, 7, 8, 8, 9, 2, 0, 6, 7, 8, 1,
7, 1, 4, 0, 8, 5, 4, 7, 8, 8, 2, 6, 2, 8, 8, 6, 6, 5, 6, 0, 0, 6,
9, 1, 8, 9, 1, 2, 8, 9, 9, 5, 0, 2, 7, 3, 0, 4, 2, 0, 3, 3, 1, 2,
5, 9, 0, 1, 0, 1, 9, 0, 9, 2, 1, 1])
data, target = datasets.make_blobs()
plt.scatter(data[:,0], data[:,1],c=target)
<matplotlib.collections.PathCollection at 0xb3c9710>
第一种错误,k值不合适,make_blobs默认中心点三个
# 要使用k-means 那就需要对数据有一定的了解,如果是3类,就一定不能给其他类
km = KMeans(n_clusters=3)
km.fit(data)
输出
KMeans(algorithm=’auto’, copy_x=True, init=’k-means++’, max_iter=300,
n_clusters=3, n_init=10, n_jobs=1, precompute_distances=’auto’,
random_state=None, tol=0.0001, verbose=0)
cluster_centers = km.cluster_centers_
plt.scatter(data[:,0], data[:,1],c=target)
plt.scatter(cluster_centers[:,0], cluster_centers[:,1],c=km.predict(cluster_centers),s=200)
<matplotlib.collections.PathCollection at 0xb6c2ba8>
第二种错误,数据偏差
trans = [[0.6,-0.6],[-0.4,0.8]]
X2 = np.dot(X,trans)
# 对数据动了手脚,数据清洗
trans = [[0.6,-0.6],[-0.4,0.8]]
x = np.dot(data,trans)
plt.scatter(x[:,0], x[:,1],c=target)
<matplotlib.collections.PathCollection at 0xb835da0>
第三个错误:标准偏差不相同cluster_std
data, target = datasets.make_blobs(cluster_std=[1, 5, 10])
plt.scatter(data[:,0], data[:,1],c=target)
<matplotlib.collections.PathCollection at 0xb579978>
km = KMeans(n_clusters=3)
km.fit(data)
输出
KMeans(algorithm=’auto’, copy_x=True, init=’k-means++’, max_iter=300,
n_clusters=3, n_init=10, n_jobs=1, precompute_distances=’auto’,
random_state=None, tol=0.0001, verbose=0)
cluster_centers = km.cluster_centers_
plt.scatter(data[:,0], data[:,1],c=target)
plt.scatter(cluster_centers[:,0], cluster_centers[:,1],c=km.predict(cluster_centers), s=200, cmap='rainbow')
<matplotlib.collections.PathCollection at 0xbfa0320>
第四个错误:样本数量不同
# 样本量500个: A:10 B:100 C:390
# 样本严重不平衡
# 在使用KM算法的时候,预测中,A类会变多, B也会变多, c会变少
# 聚类的结果会非常不准确
4、图片压缩
使用聚类压缩图片
img = plt.imread('../data/bird_small.png')
img_shape = img.shape
img_shape
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
bird = plt.imread('./data/bird_small.png')
plt.imshow(bird)
<matplotlib.image.AxesImage at 0xc00a860>
bird.shape
输出
(128, 128, 3)
# 机器学习
X_train = bird.reshape(-1, 3)
# 实例,将颜色分四类
km = KMeans(n_clusters=4)
km.fit(X_train)
输出
KMeans(algorithm=’auto’, copy_x=True, init=’k-means++’, max_iter=300,
n_clusters=4, n_init=10, n_jobs=1, precompute_distances=’auto’,
random_state=None, tol=0.0001, verbose=0)
y_ = km.predict(X_train)
# 找到聚类的中心点(4个均值)
cluster_centers = km.cluster_centers_
# 压缩颜色最好使用png
# jpg 0-255 一种256种 uint8
# png 0-1 float32
# 选取了4个最具有代表性的颜色,将这4个颜色,按照分类索引,重新生成一张照片
new_bird = cluster_centers[y_]
plt.imshow(new_bird.reshape(128,128,3))
plt.imsave(fname='./data/new_bird.png', arr = new_bird.reshape(128,128,3))
<matplotlib.image.AxesImage at 0xc06ceb8>
5.K-Means图片颜色分类
导包 from sklearn.metrics import pairwise_distances_argmin
import sklearn.datasets as datasets
image = datasets.load_sample_image('china.jpg')
plt.figure(figsize=(12, 9))
plt.imshow(image)
<matplotlib.image.AxesImage at 0xc93d400>
image.shape
输出
(427, 640, 3)
X_train = image.reshape(-1,3)
# pandas
# unique()
from pandas import Series, DataFrame
df = DataFrame(X_train)
# 查看重复的颜色值
df.duplicated().sum()
输出
176665
# 不重复的颜色
df.drop_duplicates().shape
输出
(96615, 3)
# 分成64类
km = KMeans(64)
# 因为根据欧式距离,点又多
km.fit(X_train)
输出
KMeans(algorithm=’auto’, copy_x=True, init=’k-means++’, max_iter=300,
n_clusters=64, n_init=10, n_jobs=1, precompute_distances=’auto’,
random_state=None, tol=0.0001, verbose=0)
y_ = km.predict(X_train)
加载图片/创建模型/训练数据
# 64组颜色
cluster_centers = km.cluster_centers_
# 生成一张新的图片
new_china = cluster_centers[y_]/255
plt.imshow(new_china.reshape(427,640,3))
<matplotlib.image.AxesImage at 0xf3b01d0>
plt.imsave(fname='./data/new_china.png', arr=new_china.reshape(427,640,3))
压缩长和宽
# 压缩尺寸
# cv2
# ndimage.zoom()
import scipy.ndimage as ndimage
china = new_china.reshape(427,640,3) * 255
china = china.astype('uint8')
china_small = ndimage.zoom(china, zoom=(0.5, 0.5, 1))
C:\Users\Administrator\Anaconda3\lib\site-packages\scipy\ndimage\interpolation.py:616: UserWarning: From scipy 0.13.0, the output shape of zoom() is calculated with round() instead of int() - for these inputs the size of the returned array has changed.
"the returned array has changed.", UserWarning)
plt.imshow(china_small)
<matplotlib.image.AxesImage at 0xf10c390>
plt.imsave('./data/small1_china.jpg', china_small)