• 最大最小距离算法



    title: 最大最小距离算法
    date: 2017-12-16 17:36:54
    tags: 聚类算法
    categories: Algorithms


    课程设计

    使用最大最小距离算法做聚类分析

    /*
    使用最大最小距离法做聚类分析
    1. 任选一个样本作为聚类中心z1
    2. 选择离z1距离最大的样本作为第二个聚类中心z2
    3. 计算其余样本与{z1,z2}之间的距离,Di1=|Xi-z1|, Di2=|Xi-z2|,Di=min(Di1,Di2)
    4. 若max(Di,{i=1..2..}) >
    θ|z1-z2|,即样本离两个中心太远,则取max(Di)中的Xi为新的聚类中心z3,
        若没有新的聚类中心,则找聚类中心过程结束,直接将样本分到最近的中心。
    5. 重新回到第3步计算最小距离,
    */
    
    /*
    距离测度:
    欧式距离 绝对值距离 切氏距离 闵氏距离
    */
    
    /*
    类内距离
    */
    
    /*
    二值特征还有匹配测度
    
    */
    
    /*
    1. 输入比例系数
    2. 输入样本数和样本维度
    3. 输入样本
    4. 确定距离测度
    5. 第一个样本作为第一个聚类中心
    6. 找到离第一个样本最远的样本作为第二个聚类中心
    7. 找到离这两个聚类中心都很远的样本作为其他可能的中心
    8. 将所有样本分到最近的聚类中心
    9. 计算类间距离
    
    */
    #include "algorithm"
    #include "cmath"
    #include "cstring"
    #include "iostream"
    #include "vector"
    using namespace std;
    
    int    z[30];    //聚类中心
    int    zn;       //聚类中心的个数
    double a[30][6]; //样本,最多30个样本,每个样本最多6个维度
    double d[33];    //样本到z1的距离
    double mind[33]; //样本到最近聚类中心的距离
    int    n;        //样本数量
    int    D;        //样本维数
    //初始化分类向量,最多30个类
    vector<vector<int>> v(30);
    int                 DistanceMeasure; //距离测度
    
    //计算两点间欧式距离
    double Euclidean(double x[], double y[]) {
        int sum = 0;
        for (int i = 1; i <= D; i++)
            sum = sum + (x[i] - y[i]) * (x[i] - y[i]);
        return sqrt(sum);
    }
    
    //绝对值距离
    double Manhattan(double x[], double y[]) {
        int sum = 0;
        for (int i = 1; i <= D; i++)
            sum += abs(x[i] - y[i]);
        return sum;
    }
    
    //切氏距离
    double Chebyahev(double x[], double y[]) {
        double ans = 0;
        for (int i = 1; i <= D; i++) {
            ans = max(ans, abs(x[i] - y[i]));
        }
        return ans;
    }
    
    //闵氏距离
    double Minkowski(double x[], double y[], int m) {
        int sum = 0;
        for (int i = 1; i <= D; i++) {
            sum += pow(abs(x[i] - y[i]), m);
        }
        return pow(sum, 1.0 / m);
    }
    
    //用DistanceMeasure选择不同的距离测度
    double Distan(double x[], double y[]) {
        if (DistanceMeasure == 1) //欧式距离
            return Euclidean(x, y);
        else if (DistanceMeasure == 2) //绝对值距离
            return Manhattan(x, y);
        else if (DistanceMeasure == 3) //切氏距离
            return Chebyahev(x, y);
        else if (DistanceMeasure == 4) { //闵氏距离
            static int m;
            if (!m) {
                cout << "请输入闵氏距离的参数m: ";
                cin >> m;
            }
            return Minkowski(x, y, m);
        } else {
            cout << "参数错误!!
    ";
            return -1;
        }
    }
    
    /*
    类间距离:
    最近距离法 最远距离法 中间距离法 重心距离法 平均距离法
    */
    
    //最近距离
    //计算第x个类别和第y个类别的元素间的最小距离
    double ClusterMin(int x, int y) {
        double MinDistan = 1 << 30;
        for (auto i = v[x].begin(); i != v[x].end(); i++) {
            for (auto j = v[y].begin(); j != v[y].end(); j++) {
                double tempd = Distan(a[*i], a[*j]);
                MinDistan    = min(MinDistan, tempd);
            }
        }
        return MinDistan;
    }
    
    //最远距离
    double ClusterMax(int x, int y) {
        double MaxDistab = 0;
        for (auto i = v[x].begin(); i != v[x].end(); i++)
            for (auto j = v[y].begin(); j != v[y].end(); j++) {
                double tempd = Distan(a[*i], a[*j]);
                MaxDistab    = max(MaxDistab, tempd);
            }
        return MaxDistab;
    }
    
    //重心距离
    //以样本均值作为类的重心
    double ClusterCentroid(int x, int y) {
        double CenterX[33], CenterY[33];
        memset(CenterX, 0, sizeof(CenterX));
        memset(CenterY, 0, sizeof(CenterY));
        for (auto i = v[x].begin(); i != v[x].end(); i++) {
            for (int j = 1; j <= D; j++) {
                CenterX[j] += a[*i][j];
            }
        }
        for (auto i = v[y].begin(); i != v[y].end(); i++) {
            for (int j = 1; j <= D; j++) {
                CenterY[j] += a[*i][j];
            }
        }
        //求得中心位置
        for (int i = 1; i <= D; i++) {
            CenterX[i] /= v[x].size();
            CenterY[i] /= v[y].size();
        }
    
        //计算中间距离
        double ans = Distan(CenterX, CenterY);
    
        return ans;
    }
    
    //中心距离
    // double ClusterMedian(int x, int y) { return 0; }
    
    //平均距离
    double ClusterAverage(int x, int y) {
        double sum = 0, tempd;
        for (auto i = v[x].begin(); i != v[x].end(); i++) {
            for (auto j = v[y].begin(); j != v[y].end(); j++) {
                tempd = Distan(a[*i], a[*j]);
                sum += tempd;
            }
        }
        sum /= (v[x].size() * v[y].size());
    
        return sqrt(sum);
    }
    
    //类内距离
    //输入x为类别,z[x]为x的类心,v[x]为类内样本
    double ClusterInDistance(int x) {
        //定义为类内样本到类中心的距离和
        double sum = 0;
        int    t   = z[x];
        double d;
        for (auto i = v[x].begin(); i != v[x].end(); i++) {
            d = Distan(a[t], a[*i]);
            sum += d;
        }
        return sum;
    }
    
    int main() {
        freopen("in.txt", "r", stdin);
    
        double k; //阈值
    
        cout << "请输入阈值:
    ";
        cin >> k;
        cout << "请输入样本数量和样本维数:
    ";
        cin >> n >> D;
        cout << "输入样本:
    ";
    
        int i, j;
        //录入样本
        for (i = 1; i <= n; i++)
            for (j = 1; j <= D; j++)
                cin >> a[i][j];
        // 选择距离测度
        cout << "选择距离测度: 
    ";
        cout << "1. 欧氏距离
    ";
        cout << "2. 绝对值距离
    ";
        cout << "3. 切氏距离
    ";
        cout << "4. 闵氏距离
    ";
        cin >> DistanceMeasure;
        //选择第一个样本点为初始聚类中心
        z[1] = 1;
    
        //选择距离z1最远的样本作为第2个聚类中心
    
        double t = 0; //最大距离
    
        for (i = 2; i <= n; i++) {
            d[i] = Distan(a[1], a[i]); //样本i距z1的距离
            // cout << i << "到x1距离: " << d[i] << endl;
            if (d[i] > t) {
                t    = d[i];
                z[2] = i;
            }
        }
        zn = 2;
        //查找聚类中心
        while (1) {
            //计算其余样本到最近聚类中心的距离
            //聚类中心数量>=2
            for (i = 1; i <= n; i++) {
                double t = 1 << 30; //临时作为最小距离
                for (j = 1; j <= zn; j++) {
                    t = min(t, Distan(a[z[j]], a[i]));
                }
                mind[i] = t;
            }
            //选出最小距离中的最大距离
            int    tempZ;     //可能的新聚类中心
            double tempD = 0; //最小距离中的最大距离
            for (int i = 1; i <= n; i++) {
                if (mind[i] > tempD) {
                    tempD = mind[i];
                    tempZ = i;
                }
            }
            if (tempD > k * Distan(a[1], a[z[2]])) { //增加新聚类中心
                z[++zn] = tempZ;
            } else {
                //查找聚类中心结束
                break;
            }
        }
    
        //输出聚类中心
    
        /*  cout << "聚类中心: 
    ";
          for (i = 1; i <= zn; i++)
              cout << z[i] << ' ';
          cout << endl;*/
    
        //将样本分配到最近的聚类中心
    
        for (i = 1; i <= n; i++) { //遍历所有的样本
            vector<int> v1;
            double      d;              //距离
            t = 1 << 30;                //最小距离
            int tempNo;                 //临时分组
            for (j = 1; j <= zn; j++) { //遍历所有的中心
                d = Distan(a[z[j]], a[i]);
                if (d < t) { //距离更近,更新分组
                    t      = d;
                    tempNo = j;
                }
            }
            // cout << "push" << tempNo << endl;
            v[tempNo].push_back(i); //将样本i加到第tempNo个分组中
        }
    
        //for (auto x = v[3].begin(); x != v[3].end(); x++)
            //cout << *x;
        //cout << endl;
    
        //输出分组信息
    
        for (i = 1; i <= zn; i++) {
            cout << "分组中心:  " << z[i] << endl;
            cout << "分组成员:  ";
            for (auto x = v[i].begin(); x != v[i].end(); x++)
                cout << *x << ' ';
            cout << endl;
        }
    
        //计算类间距离
        cout << "类间距离: 
    ";
        for (i = 1; i <= zn; i++) {
            for (j = i + 1; j <= zn; j++) {
                cout << "   " << i << " --- " << j << endl;
                cout << "最近距离: " << ClusterMin(i, j) << endl;
                cout << "最远距离: " << ClusterMax(i, j) << endl;
                // cout << "中间距离: " << ClusterMedian(i, j) << endl;
                cout << "重心距离: " << ClusterCentroid(i, j) << endl;
                cout << "平均距离: " << ClusterAverage(i, j) << endl;
            }
        }
    
        //类内距离
        //定义为类内样本到类心的距离和
        cout << "
    类内距离: 
    ";
        for (i = 1; i <= zn; i++) {
            cout << "第" << i << "类:  ";
            cout << ClusterInDistance(i) << endl;
        }
    
        return 0;
    }
    

    测试输入文件
    in.txt

    0.5
    10 2
    0 0
    3 8
    2 2
    1 1
    5 3
    4 8
    6 3
    5 4
    6 4
    7 5
    1
    
  • 相关阅读:
    Java 接口
    Java 数据结构
    Java 包(package)
    一步步学习SPD2010--第四章节--创建和修改网页(9)--附上母版页
    一步步学习SPD2010--第四章节--创建和修改网页(8)--插入Web部件区域
    一步步学习SPD2010--第四章节--创建和修改网页(7)--创建ASP.NET页面
    一步步学习SPD2010--第四章节--创建和修改网页(6)--创建和修改列表表单页面
    一步步学习SPD2010--第四章节--创建和修改网页(5)--创建列表视图页面
    一步步学习SPD2010--第四章节--创建和修改网页(4)--修改列表视图页面
    一步步学习SPD2010--第四章节--创建和修改网页(3)--改变网站的首页
  • 原文地址:https://www.cnblogs.com/lepeCoder/p/8047174.html
Copyright © 2020-2023  润新知