用python写一个我们自己的k-means和PCA

k均值:

import numpy as np

In [2]:

def loadDataSet(filename):
    """
    读取数据集

    Args:
        filename: 文件名
    Returns:
        dataMat: 数据样本矩阵
    """
    dataMat = []
    with open(filename, 'rb') as f:
        for line in f:
            eles = map(float,line.strip().split('\t'))
            dataMat.append(eles)
    return dataMat

In [3]:

def distEclud(vecA, vecB):
    """
    计算两向量的欧氏距离

    Args:
        vecA: 向量A
        vecB: 向量B
    Returns:
        欧式距离
    """
    return np.sqrt(np.sum(np.power(vecA - vecB, 2)))

In [4]:

def randCent(dataSet, k):
    """
    随机生成k个聚类中心

    Args:
        dataSet: 数据集
        k: 簇数目
    Returns:
        centroids: 聚类中心矩阵
    """
    m, _ = dataSet.shape
    # 随机从数据集中选几个作为初始聚类中心
    centroids = dataSet.take(np.random.choice(80,k), axis=0)
    return centroids

In [5]:

def kMeans(dataSet, k, maxIter = 5):
    """
    K-Means

    Args:
        dataSet: 数据集
        k: 聚类数
    Returns:
        centroids: 聚类中心
        clusterAssment: 点分配结果
    """
    # 随机初始化聚类中心
    centroids = randCent(dataSet, k)
    init_centroids = centroids.copy()
    
    m, n = np.shape(dataSet)
    
    # 点分配结果: 第一列指明样本所在的簇,第二列指明该样本到聚类中心的距离
    clusterAssment = np.mat(np.zeros((m, 2)))
    
    # 标识聚类中心是否仍在改变
    clusterChanged = True
    
    # 直至聚类中心不再变化
    iterCount = 0
    while clusterChanged and iterCount < maxIter:
        iterCount += 1
        clusterChanged = False
        # 分配样本到簇
        for i in range(m):
            # 计算第i个样本到各个聚类中心的距离
            minIndex = 0
            minDist = np.inf
            for j in range(k):
                dist = distEclud(dataSet[i, :],  centroids[j, :])
                if(dist < minDist):
                    minIndex = j
                    minDist = dist
            # 任何一个样本的类簇分配发生变化则认为变化
            if(clusterAssment[i, 0] != minIndex):
                clusterChanged = True
            clusterAssment[i, :] = minIndex, minDist**2
            
        # 刷新聚类中心: 移动聚类中心到所在簇的均值位置
        for cent in range(k):
            # 通过数组过滤获得簇中的点
            ptsInCluster = dataSet[np.nonzero(
                clusterAssment[:, 0].A == cent)[0]]
            if ptsInCluster.shape[0] > 0:
                # 计算均值并移动
                centroids[cent, :] = np.mean(ptsInCluster, axis=0)
    return centroids, clusterAssment, init_centroids

In [6]:

import matplotlib.pyplot as plt

In [7]:

%matplotlib inline

In [8]:

dataMat = np.mat(loadDataSet('data/testSet.txt'))
m,n = np.shape(dataMat)

In [9]:

set_k = 2
centroids, clusterAssment, init_centroids = kMeans(dataMat, set_k)

clusterCount = np.shape(centroids)[0]
clusterCount

Out[9]:

2

In [10]:

# 注意,我们这里只设定了最多四个簇的样式,所以前面如果set_k设置超过了4,后面就会出现index error
patterns = ['o', 'D', '^', 's']
colors = ['b', 'g', 'y', 'black']

In [11]:

fig = plt.figure()
title = 'kmeans with k={}'.format(set_k)
ax = fig.add_subplot(111, title=title)
for k in range(clusterCount):
    # 绘制聚类中心
    ax.scatter(centroids[k, 0], centroids[k, 1], color='r', marker='+', linewidth=20)
    # 绘制初始聚类中心
    ax.scatter(init_centroids[k,0], init_centroids[k,1], color='purple', marker='*', linewidths=10)
    for i in range(m):
        # 绘制属于该聚类中心的样本
        ptsInCluster = dataMat[np.nonzero(clusterAssment[:, 0].A==k)[0]]
        ax.scatter(ptsInCluster[:, 0].flatten().A[0], ptsInCluster[:, 1].flatten().A[0], marker=patterns[k], color=colors[k])

In [ ]:

PCA:

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn import metrics
import matplotlib.pyplot as plt
from sklearn.datasets import load_wine
from sklearn.pipeline import make_pipeline

In [2]:

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

In [3]:

%matplotlib inline

In [4]:

features, target = load_wine(return_X_y=True) # 三分类的酒数据集
features.shape, target.shape

Out[4]:

((178, 13), (178,))

In [5]:

RANDOM_STATE = 42
# 将数据切分成7:3分别作为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(features, target,
                                                    test_size=0.30,
                                                    random_state=RANDOM_STATE)

In [6]:

# 不使用PCA
raw_clf = make_pipeline(StandardScaler(), LogisticRegression())
raw_clf.fit(X_train, y_train)
pred_test_raw = raw_clf.predict(X_test)

In [7]:

# 使用PCA但不做数据预处理
unscaled_clf = make_pipeline(PCA(n_components=2), LogisticRegression())
unscaled_clf.fit(X_train, y_train)
pred_test = unscaled_clf.predict(X_test)

In [8]:

# 使用PCA,同时做数据预处理
std_clf = make_pipeline(StandardScaler(), PCA(n_components=2), LogisticRegression())
std_clf.fit(X_train, y_train)
pred_test_std = std_clf.predict(X_test)

In [9]:

# 查看各情况下的分类准确率
print u'\n不使用PCA,预测准确率:', '{:.2%}'.format(metrics.accuracy_score(y_test, pred_test_raw))
print u'\n使用PCA但不预处理,预测准确率:', '{:.2%}'.format(metrics.accuracy_score(y_test, pred_test))
print u'\n使用PCA且预处理,预测准确率:', '{:.2%}'.format(metrics.accuracy_score(y_test, pred_test_std))
不使用PCA,预测准确率: 98.15%

使用PCA但不预处理,预测准确率: 74.07%

使用PCA且预处理,预测准确率: 98.15%

In [10]:

# 将pca信息抽取出来
pca = unscaled_clf.named_steps['pca']
pca_std = std_clf.named_steps['pca']

In [11]:

# 打印最主要的主成分。注意,它是特征空间中的主成分轴,表达了数据中具有最大方差的方向
print u'\n未预处理第一主成分:\n', pca.components_[0]
print u'\n预处理第一主成分:\n', pca_std.components_[0]
未预处理第一主成分:
[ 1.76342917e-03 -8.35544737e-04  1.54623496e-04 -5.31136096e-03
  2.01663336e-02  1.02440667e-03  1.53155502e-03 -1.11663562e-04
  6.31071580e-04  2.32645551e-03  1.53606718e-04  7.43176482e-04
  9.99775716e-01]

预处理第一主成分:
[ 0.13443023 -0.25680248 -0.0113463  -0.23405337  0.15840049  0.39194918
  0.41607649 -0.27871336  0.33129255 -0.11383282  0.29726413  0.38054255
  0.27507157]

In [12]:

# 对训练数据进行PCA降维以备绘图
X_train_nostd = pca.transform(X_train)
scaler = std_clf.named_steps['standardscaler']
X_train_std = pca_std.transform(scaler.transform(X_train))

FIG_SIZE = (10, 7)

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=FIG_SIZE)

# 不预处理的PCA
for l, c, m in zip(range(0, 3), ('blue', 'red', 'green'), ('^', 's', 'o')):
    ax1.scatter(X_train_nostd[y_train == l, 0], X_train_nostd[y_train == l, 1],
                color=c,
                label='class %s' % l,
                alpha=0.5,
                marker=m
                )

# 预处理后的PCA
for l, c, m in zip(range(0, 3), ('blue', 'red', 'green'), ('^', 's', 'o')):
    ax2.scatter(X_train_std[y_train == l, 0], X_train_std[y_train == l, 1],
                color=c,
                label='class %s' % l,
                alpha=0.5,
                marker=m
                )

ax1.set_title(u'PCA降维后的训练集')
ax2.set_title(u'特征放缩+PCA降维后的训练集')

for ax in (ax1, ax2):
    ax.set_xlabel(u'第一主成分')
    ax.set_ylabel(u'第二主成分')
    ax.legend(loc='upper right')
    ax.grid()

plt.tight_layout()
/Users/sunkepeng/anaconda2/lib/python2.7/site-packages/matplotlib/font_manager.py:1331: UserWarning: findfont: Font family [u'sans-serif'] not found. Falling back to DejaVu Sans
  (prop.get_family(), self.defaultFamily[fontext]))

In [ ]:

 
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值