import pandas as pd
import numpy as np
import math
import random
from numpy import *
from openpyxl import Workbook
# 导入数据集
def LoadDataSet(filename):
    E = pd.read_excel(filename,sheet_name=0,header=None)
    E = np.array(E)
    return E

# 初始化特征权重矩阵
def initializefeature_weightMatrix():
    feature_weight_mat = np.full((k, number_attribute), (1/number_attribute))
    return feature_weight_mat

# 初始化隶属度矩阵
def initializeMembershipMatrix():
    membership_mat = list()
    for i1 in range(n):
        random_num_list = [random.random() for q in range(k)]
        summation = sum(random_num_list)
        temp_list = [x / summation for x in random_num_list]  # 归一化，保证和等于1
        membership_mat.append(temp_list)
    return membership_mat  # 返回隶属度矩阵

# 计算聚类中心
def calculateClusterCenter(X, Z,Membership_mat):
    cluster_centers = np.zeros((k,number_attribute))
    cluster_centers_z = np.zeros((k, n))
    centers_z = []
    centers = []
    mem_mat = np.zeros((n,k))
    for i2 in range(n):
        for j2 in range(k):
            mem_mat[i2][j2] = np.power(Membership_mat[i2][j2], m)  # 计算隶属度^m 的值
    # 计算样本集的中心
    for kkk in range(k):
        temp_num = list()
        for i10 in range(n):
            data_point = list(X[i10,:])
            prod = [mem_mat[i10][kkk] * val for val in data_point]
            temp_num.append(prod)
        numerator = map(sum,zip(*temp_num))
        center = [x / sum(mem_mat[:,kkk]) for x in numerator]
        centers.append(center)
    cluster_centers = np.array(centers)
    # 计算判别矩阵的中心
    for kk in range(k):
        temp_num_z = list()
        for i6 in range(n):
            data_point_z = list(Z[i6,:])  # 读取稀疏自表示的第i行
            prod_z = [mem_mat[i6][kk] * val_z for val_z in data_point_z]
            temp_num_z.append(prod_z)
        numerator_z = map(sum, zip(*temp_num_z))
        center_z = [z / sum(mem_mat[:,kk]) for z in numerator_z]
        centers_z.append(center_z)
    cluster_centers_z = np.array(centers_z)
    return cluster_centers, cluster_centers_z

# 更新隶属度
def updateMembershipValue(Membership_mat, cluster_centers, cluster_centers_z):
    for i4 in range(n):
        for c in range(k):
            up = np.power((np.linalg.norm(X[i4,:]-cluster_centers[c,:])),2) + alpha * np.power(np.linalg.norm(Z[i4,:] - cluster_centers_z[c,:]),2)
            down = 0
            down_attr = 0
            for l in range(k):
                down_attr += 1 / (np.power((np.linalg.norm(X[i4,:]-cluster_centers[l,:])),2) + alpha * np.power(np.linalg.norm(Z[i4,:] - cluster_centers_z[l,:]),2))
            # print(i4,c,up,down,up/down)
            Membership_mat[i4][c] = 1 / (up * down_attr)
    return Membership_mat

# 得到聚类结果
def getclusters(Membership_mat):
    cluster_labels = list()
    # Membership_mat = list(Membership_mat)
    for i in range(n):
        max_val, idx = max((val, idx) for (idx, val) in enumerate(Membership_mat[i]))
        cluster_labels.append(idx)
    return cluster_labels

# 聚类指标
def xie_beni(membership_mat, center, center_z, data, data_z):
    sum_cluster_distance = 0
    min_cluster_center_distance = inf
    membership_mat = np.array(membership_mat)
    data = np.array(data)
    data_z = np.array(data_z)
    for i in range(k):
        for j in range(n):
            sum_cluster_distance = sum_cluster_distance + membership_mat[j][i] ** 2 * ((math.pow(np.linalg.norm(data[j, :] - center[i, :]), 2)) + alpha * (math.pow(np.linalg.norm(data_z[j, :] - center_z[i, :]), 2)))  # 计算类一致性
    for i in range(k - 1):
        for j in range(i + 1, k):
            cluster_center_distance = math.pow(np.linalg.norm(center[i, :] - center[j, :]), 2) + alpha * math.pow(np.linalg.norm(center_z[i, :] - center_z[j, :]), 2)  # 计算类间距离
            if cluster_center_distance < min_cluster_center_distance:
                min_cluster_center_distance = cluster_center_distance
    return sum_cluster_distance / (n * min_cluster_center_distance)


if __name__ == '__main__':
    X = LoadDataSet('NLF_A_(90).xlsx')
    Z = LoadDataSet('distance_NLF_A(90).xlsx')
    print(Z.shape)
    # Z2 = LoadDataSet('distanceF_1.xlsx')
    # Z = np.hstack((Z1,Z2))
    # print(Z2.shape)
    # X = np.random.rand(6,3)
    # print(X)
    # Z = [[0.1, 0.02, 0.6, 0.5, 0.9, 0.0001],
    #      [0.02, 0.8, 0.4, 0.04, 0.003, 0.05],
    #      [0.6, 0.4, 0.008, 0.1, 0.06, 0.0],
    #      [0.5, 0.004, 0.008, 0.02, 0.4, 0.000001],
    #      [0.9, 0.003, 0.1, 0.06, 0.4, 0.2],
    #      [0.0001, 0.05, 0.00, 0.000001, 0.2, 0.6]]
    # Z = np.array(Z)
    n = len(X)  # 样本数
    number_attribute = len(X[0])  # 特征数
    m = 5  # 模糊系数
    k = 3  # 聚类数
    alpha = 0.8  # 判别矩阵的影响系数
    step = 0
    max_step = 10000
    membership_mat_old = np.zeros((n, k))
    Membership_mat = initializeMembershipMatrix()
    print(Membership_mat)
    # Feature_weight_mat = initializefeature_weightMatrix()
    while step <= max_step:
        print('step', step)
        cluster_centers, cluster_centers_z = calculateClusterCenter(X, Z, Membership_mat)
        Membership_mat = updateMembershipValue(Membership_mat, cluster_centers, cluster_centers_z)
        # Feature_weight_mat = updatefeatureweight(Membership_mat,X,cluster_centers)
        cluster_labels = getclusters(Membership_mat)
        membership_mat_new = np.array(Membership_mat)
        print('error', abs(np.sum(membership_mat_new - membership_mat_old)))
        if abs(np.sum(membership_mat_new - membership_mat_old)) < 0.0000000000000001:
            print('隶属度', Membership_mat)
            break
        else:
            step += 1
        membership_mat_old = membership_mat_new
    labels = getclusters(Membership_mat)
    labels = np.matrix(labels)
    label = np.array(labels).T
    print(label.shape)
    book = Workbook()
    sheet = book.create_sheet('Sheet', index=0)
    [w, r] = label.shape
    for i in range(w):
        for j in range(r):
            sheet.cell(row=i + 1, column=j + 1, value=label[i][j])
    book.save('labelD_NLF_A(90).xlsx')
    print(labels)
    XB = xie_beni(Membership_mat,cluster_centers,cluster_centers_z,X,Z)
    print('聚类有效性',XB)



