zoukankan      html  css  js  c++  java
  • 最大最小距离算法


    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
    
  • 相关阅读:
    .net core读取appsettings.config中文乱码问题
    vs2017错误:当前页面的脚本发生错误
    VS Code中无法识别npm命令
    Visual Studio报错/plugin.vs.js,行:1074,错误:缺少标识符、字符串或数字
    记录一次在生成数据库服务器上出现The timeout period elapsed prior to completion of the operation or the server is not responding.和Exception has been thrown by the target of an invocation的解决办法
    Java集合框架
    java hash表
    Java Dictionary 类存储键值
    java数据结构 栈stack
    java封装
  • 原文地址:https://www.cnblogs.com/lepeCoder/p/8047174.html
Copyright © 2011-2022 走看看