File indexing completed on 2024-11-16 09:01:36
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include "FuzzyKClusters.h"
0012 #include <exception>
0013 #include <iostream>
0014 #include <cmath>
0015
0016
0017 using namespace fkc;
0018 using namespace Eigen;
0019
0020
0021
0022
0023
0024
0025 KMeans::KMeans() = default;
0026 KMeans::~KMeans() = default;
0027
0028 MatrixXd KMeans::Fit(const MatrixXd &data, int k, double q, double epsilon, int max_iters)
0029 {
0030 auto res = Initialize(data, k, q);
0031
0032 for (n_iters = 0; n_iters < max_iters; ++n_iters) {
0033 auto old_mems = mems;
0034 Distances(res, data);
0035 Memberships(q);
0036 FormClusters(res, data, q);
0037
0038 if ((old_mems - mems).cwiseAbs().maxCoeff() < epsilon) {
0039 break;
0040 }
0041 }
0042
0043 return res;
0044 }
0045
0046
0047 MatrixXd KMeans::Initialize(const MatrixXd &data, int k, double q)
0048 {
0049
0050 dists.resize(k, data.rows());
0051
0052
0053 mems = MatrixXd::Random(k, data.rows());
0054 for (int j = 0; j < mems.cols(); ++j) {
0055 auto csum = mems.col(j).sum();
0056 for (int i = 0; i < mems.rows(); ++i) {
0057 mems(i, j) = mems(i, j)/csum;
0058 }
0059 }
0060
0061 MatrixXd clusters(k, data.cols());
0062 FormClusters(clusters, data, q);
0063 return clusters;
0064 }
0065
0066
0067 void KMeans::Distances(const MatrixXd ¢roids, const MatrixXd &data)
0068 {
0069 for (int i = 0; i < centroids.rows(); ++i) {
0070 for (int j = 0; j < data.rows(); ++j) {
0071 dists(i, j) = (centroids.row(i) - data.row(j)).cwiseAbs2().sum();
0072 }
0073 }
0074 }
0075
0076
0077 void KMeans::Memberships(double q)
0078 {
0079
0080 auto d = dists.array().pow(-1.0/(q - 1.0)).matrix();
0081
0082 for (int j = 0; j < d.cols(); ++j) {
0083 auto dsum = d.col(j).sum();
0084 for (int i = 0; i < d.rows(); ++i) {
0085 mems(i, j) = d(i, j)/dsum;
0086 }
0087 }
0088 }
0089
0090
0091 void KMeans::FormClusters(MatrixXd &clusters, const MatrixXd &data, double q)
0092 {
0093 auto weights = mems.array().pow(q).matrix();
0094 for (int i = 0; i < clusters.rows(); ++i) {
0095 clusters.row(i) *= 0;
0096 for (int j = 0; j < data.rows(); ++j) {
0097 clusters.row(i) += data.row(j)*weights(i, j);
0098 }
0099 clusters.row(i) /= weights.row(i).sum();
0100 }
0101 }
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 KRings::KRings() = default;
0114 KRings::~KRings() = default;
0115
0116 MatrixXd KRings::Fit(const MatrixXd &data, int k, double q, double epsilon, int max_iters)
0117 {
0118 auto res = Initialize(data, k, q);
0119
0120 for (n_iters = 0; n_iters < max_iters; ++n_iters) {
0121 auto old_mems = mems;
0122 Distances(res, data);
0123 Memberships(q);
0124 FormRadii(res, q);
0125 FormClusters(res, data, q);
0126
0127 if ((old_mems - mems).cwiseAbs().maxCoeff() < epsilon) {
0128 break;
0129 }
0130 }
0131
0132 return res;
0133 }
0134
0135
0136 MatrixXd KRings::Initialize(const MatrixXd &data, int k, double q)
0137 {
0138 MatrixXd clusters(k, data.cols() + 1);
0139 auto centers = clusters.leftCols(data.cols());
0140
0141
0142 KMeans fkm;
0143 centers = fkm.Fit(data, k, q, 1e-4, 5);
0144
0145 dists.resize(k, data.rows());
0146 dists_euc = fkm.GetDistances().cwiseSqrt();
0147 mems = fkm.GetMemberships();
0148 FormRadii(clusters, q);
0149 return clusters;
0150 }
0151
0152
0153 void KRings::Distances(const MatrixXd ¢roids, const MatrixXd &data)
0154 {
0155 auto const centers = centroids.leftCols(centroids.cols() - 1);
0156 auto const radii = centroids.rightCols(1);
0157
0158 for (int i = 0; i < centroids.rows(); ++i) {
0159 for (int j = 0; j < data.rows(); ++j) {
0160 dists_euc(i, j) = std::sqrt((centers.row(i) - data.row(j)).cwiseAbs2().sum());
0161 dists(i, j) = std::pow(dists_euc(i, j) - radii(i, 0), 2);
0162 }
0163 }
0164 }
0165
0166
0167 void KRings::FormRadii(MatrixXd &clusters, double q)
0168 {
0169 auto radii = clusters.rightCols(1);
0170 auto weights = mems.array().pow(q).matrix();
0171
0172 for (int i = 0; i < weights.rows(); ++i) {
0173 radii(i, 0) = 0;
0174 for (int j = 0; j < weights.cols(); ++j) {
0175 radii(i, 0) += weights(i, j)*dists_euc(i, j);
0176 }
0177 radii(i, 0) /= weights.row(i).sum();
0178 }
0179 }
0180
0181
0182 void KRings::FormClusters(MatrixXd &clusters, const MatrixXd &data, double q)
0183 {
0184 auto centers = clusters.leftCols(data.cols());
0185 const auto &radii = clusters.rightCols(1);
0186 auto weights = mems.array().pow(q).matrix();
0187
0188 for (int i = 0; i < weights.rows(); ++i) {
0189 MatrixXd icenter = centers.row(i);
0190 centers.row(i) *= 0;
0191 for (int j = 0; j < weights.cols(); ++j) {
0192 double scale = radii(i, 0)/dists_euc(i, j);
0193 centers.row(i) += weights(i, j)*(data.row(j) - (data.row(j) - icenter)*scale);
0194 }
0195 centers.row(i) /= weights.row(i).sum();
0196 }
0197 }
0198
0199
0200
0201
0202
0203
0204
0205
0206