模式識別課作業
C均值聚類步驟:
- 選取隨機類心
- 根據集合中點與各類心最小距離,對集合每個元素分類
- 將分類後各類元素的均值作爲新的類心
- 若類心不再更新,則結果收斂,算法結束
#include<bits/stdc++.h>
using namespace std;
int N; //輸入數據個數
int C; //類別個數
struct Node {
double x, y;
Node (double x = 0, double y = 0) : x(x), y(y) {
}
}centers[100], preCenters[100], datas[1000];
vector<Node> cluster[100]; //當前聚類結果
bool equals(Node x, Node y) //判斷兩點是否相等
{
return fabs(x.x-y.x) < 0.0001 && fabs(x.y-y.y) < 0.0001;
}
bool check() //判斷聚類結果是否收斂
{
for (int i = 0; i < C; i++) {
if (!equals(preCenters[i], centers[i]))
return false;
}
return true;
}
void updateCluster() //更新聚類集合
{
for (int i = 0; i < C; i++)
cluster[i].clear();
for (int i = 0; i < N; i++) {
double minDis = 1e9;
int index = 0;
for (int j = 0; j < C; j++) {
double dis = sqrt(pow(datas[i].x-centers[j].x, 2)+pow(datas[i].y-centers[j].y, 2));
if (dis < minDis) {
minDis = dis;
index = j;
}
}
cluster[index].push_back(datas[i]);
}
}
void updateCenter() //更新類心集合
{
for (int i = 0; i < C; i++) {
double sumX = 0, sumY = 0;
int len = cluster[i].size();
for (int j = 0; j < len; j++) {
sumX += cluster[i][j].x;
sumY += cluster[i][j].y;
}
if (len != 0)
centers[i] = Node(sumX/len, sumY/len);
}
}
int main() {
freopen("Iris.txt", "r", stdin);
C = 3;
N = 0;
double x, y;
while (cin >> x >> y) {
datas[N++] = Node(x, y); //讀取數據
}
for (int i = 0; i < C; i++)
centers[i] = datas[i]; //隨機初始化類心
while (true) {
updateCluster();
updateCenter();
printf("當前類心:(%f, %f)、(%f, %f)、(%f, %f)\n", centers[0].x, centers[0].y, centers[1].x, centers[1].y, centers[2].x, centers[2].y);
if (check()) {
break;
}
memcpy(preCenters, centers, sizeof(centers));
}
freopen("C均值聚類結果.txt", "w", stdout);
for (int i = 0; i < C; i++) {
printf("第%d類類心:(%f, %f),該類中數據個數:%d\n", i, centers[i].x, centers[i].y, cluster[i].size());
for (int j = 0; j < cluster[i].size(); j++) {
printf("(%f, %f)\n", cluster[i][j].x, cluster[i][j].y);
}
}
return 0;
}
感知器算法步驟:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 500+10;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int N; //總樣本個數
int C; //類別個數
int D; //樣本維度
int p; //增量
int w[maxn][maxn]; //權矢量
int x[maxn][maxn]; //訓練樣本
int getDis(int k, int x[]) //求解判別函數
{
int dis = 0;
for (int i = 0; i <= D; i++)
dis += w[k][i]*x[i];
return dis;
}
void updateWeight(int k, int x[], int mod) //更新權矢量
{
for (int i = 0; i <= D; i++) {
if (mod == 1)
w[k][i] += p*x[i];
else
w[k][i] -= p*x[i];
}
}
int main()
{
freopen("感知器算法.txt", "r", stdin);
cin >> C >> D >> p; //輸入類別個數、樣本維度、增量
for (int i = 0; i < C; i++) {
for (int j = 0; j < D; j++) {
cin >> x[i][j]; //輸入各類樣本
}
x[i][D] = 1; //分量增廣化
}
for (int i = 0; i < C; i++)
for (int j = 0; j <= D; j++)
w[i][j] = 0; //增廣權矢量賦初值
int cnt = 0;
while (true) {
bool ok;
for (int i = 0; i < C; i++) {
cnt++;
ok = true;
int maxD = getDis(i, x[i]);
for (int j = 0; j < C; j++) {
if (j != i) {
int d = getDis(j, x[i]);
if (d >= maxD) { //錯分
ok = false;
updateWeight(j, x[i], 2);
}
}
}
if (!ok)
updateWeight(i, x[i], 1);
printf("第%d次遍歷權矢量求解結果:\n", cnt);
for (int i = 0; i < C; i++) {
for (int j = 0; j <= D; j++)
printf("%d ", w[i][j]);
cout << "\n";
}
}
if (ok) {
cout << "所求解矢量爲:\n";
for (int i = 0; i < C; i++) {
for (int j = 0; j <= D; j++)
printf("%d ", w[i][j]);
cout << "\n";
}
break;
}
}
return 0;
}
Fisher線性判別步驟:
x1 = importdata('x1.txt');
x2 = importdata('x2.txt');
x = importdata('x.txt');
m1 = mean(x1);
m2 = mean(x2);
len1 = length(x1);
len2 = length(x2);
n = 4;
S1 = 0;
S2 = 0;
for i = 1:len1
xk = x1(i,:)-m1;
S1 = S1 + xk*xk';
end
for i = 1:len2
xk = x2(i,:)-m2;
S2 = S2 + xk*xk';
end
Sw = S1 + S2;
u = inv(Sw)*(m1-m2);
M1 = u'*m1;
M2 = u'*m2;
yt = (M1+M2)/2;