import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.cluster.hierarchy import dendrogram, linkage, fcluster
from scipy.spatial.distance import squareform
import pandas as pd

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 定义14个身体测量变量
variables = [
    'X1:上体长', 'X2:手臂长', 'X3:胸围', 'X4:颈围', 'X5:总肩宽', 'X6:前胸宽',
    'X7:后背宽', 'X8:前腰背高', 'X9:后腰背高', 'X10:总体长', 'X11:身高',
    'X12:下体长', 'X13:腰围', 'X14:臀围'
]

# 相关系数矩阵R (14x14)
R = np.array([
    [1, 0.366, 0.242, 0.280, 0.360, 0.282, 0.245, 0.448, 0.486, 0.648, 0.679, 0.486, 0.133, 0.376],
    [0.366, 1, 0.233, 0.194, 0.324, 0.263, 0.265, 0.345, 0.367, 0.662, 0.681, 0.636, 0.153, 0.252],
    [0.242, 0.233, 1, 0.590, 0.476, 0.483, 0.540, 0.452, 0.365, 0.216, 0.243, 0.174, 0.732, 0.676],
    [0.280, 0.194, 0.590, 1, 0.433, 0.470, 0.478, 0.404, 0.357, 0.316, 0.313, 0.243, 0.477, 0.581],
    [0.360, 0.324, 0.476, 0.433, 1, 0.452, 0.535, 0.431, 0.429, 0.429, 0.430, 0.375, 0.339, 0.441],
    [0.282, 0.263, 0.483, 0.470, 0.452, 1, 0.663, 0.322, 0.283, 0.283, 0.302, 0.290, 0.392, 0.447],
    [0.245, 0.265, 0.540, 0.478, 0.535, 0.663, 1, 0.266, 0.287, 0.263, 0.294, 0.255, 0.446, 0.440],
    [0.448, 0.345, 0.452, 0.404, 0.431, 0.322, 0.266, 1, 0.820, 0.527, 0.520, 0.403, 0.266, 0.424],
    [0.486, 0.367, 0.365, 0.357, 0.429, 0.283, 0.287, 0.820, 1, 0.547, 0.558, 0.417, 0.241, 0.372],
    [0.648, 0.662, 0.216, 0.316, 0.429, 0.283, 0.263, 0.527, 0.547, 1, 0.957, 0.857, 0.054, 0.363],
    [0.679, 0.681, 0.243, 0.313, 0.430, 0.302, 0.294, 0.520, 0.558, 0.957, 1, 0.852, 0.099, 0.376],
    [0.486, 0.636, 0.174, 0.243, 0.375, 0.290, 0.255, 0.403, 0.417, 0.857, 0.852, 1, 0.055, 0.321],
    [0.133, 0.153, 0.732, 0.477, 0.339, 0.392, 0.446, 0.266, 0.241, 0.054, 0.099, 0.055, 1, 0.627],
    [0.376, 0.252, 0.676, 0.581, 0.441, 0.447, 0.440, 0.424, 0.372, 0.363, 0.376, 0.321, 0.627, 1]
])

# 验证矩阵是否对称
print("相关系数矩阵是否对称:", np.allclose(R, R.T))
print("矩阵形状:", R.shape)

# 计算距离矩阵 D = 1 - R
D = 1 - R

# 将距离矩阵转换为上三角形式（scipy要求）
distance_vector = squareform(D, checks=False)

print(f"\n距离向量长度: {len(distance_vector)}")
print(f"理论长度: {14*13//2} = {14*13//2}")

# (1) 最长距离法（完全连接）聚类
def perform_clustering_and_plot(distance_vector, variables, method_name, method_code):
    """执行聚类分析并绘制谱系图"""
    
    # 执行层次聚类
    linkage_matrix = linkage(distance_vector, method=method_code)
    
    # 创建图形
    plt.figure(figsize=(12, 8))
    
    # 绘制谱系图
    dendrogram(
        linkage_matrix,
        labels=variables,
        orientation='top',
        distance_sort='descending',
        show_leaf_counts=True
    )
    
    plt.title(f'{method_name}聚类谱系图', fontsize=16, fontweight='bold')
    plt.xlabel('变量', fontsize=12)
    plt.ylabel('距离', fontsize=12)
    plt.xticks(rotation=45, ha='right')
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()
    
    # 打印聚类信息
    print(f"\n=== {method_name}聚类结果 ===")
    print("聚类步骤:")
    for i, step in enumerate(linkage_matrix):
        cluster1, cluster2, distance, count = step
        print(f"步骤 {i+1}: 合并簇 {int(cluster1)} 和 {int(cluster2)}, 距离: {distance:.4f}, 样本数: {int(count)}")
    
    # 在不同距离阈值下的聚类结果
    thresholds = [0.3, 0.4, 0.5, 0.6, 0.7]
    print(f"\n不同距离阈值下的聚类数量:")
    for threshold in thresholds:
        clusters = fcluster(linkage_matrix, threshold, criterion='distance')
        n_clusters = len(set(clusters))
        print(f"阈值 {threshold}: {n_clusters} 个聚类")
        
        # 显示聚类成员
        cluster_dict = {}
        for i, cluster_id in enumerate(clusters):
            if cluster_id not in cluster_dict:
                cluster_dict[cluster_id] = []
            cluster_dict[cluster_id].append(variables[i])
        
        for cluster_id, members in cluster_dict.items():
            print(f"  聚类 {cluster_id}: {', '.join(members)}")
        print()
    
    return linkage_matrix

# 执行最长距离法聚类
print("=" * 50)
print("(1) 最长距离法（完全连接）聚类分析")
print("=" * 50)

linkage_complete = perform_clustering_and_plot(
    distance_vector, variables, "最长距离法（完全连接）", "complete"
)

print("\n" + "=" * 50)
print("(2) 类平均距离法聚类分析")
print("=" * 50)

# 执行类平均距离法聚类
linkage_average = perform_clustering_and_plot(
    distance_vector, variables, "类平均距离法", "average"
)

# 比较两种方法
print("\n" + "=" * 50)
print("两种聚类方法比较")
print("=" * 50)

# 在相同阈值下比较聚类结果
threshold = 0.5
clusters_complete = fcluster(linkage_complete, threshold, criterion='distance')
clusters_average = fcluster(linkage_average, threshold, criterion='distance')

print(f"在距离阈值 {threshold} 下:")
print(f"最长距离法: {len(set(clusters_complete))} 个聚类")
print(f"类平均距离法: {len(set(clusters_average))} 个聚类")

# 创建比较表
comparison_df = pd.DataFrame({
    '变量': variables,
    '最长距离法': clusters_complete,
    '类平均距离法': clusters_average
})

print("\n聚类结果对比:")
print(comparison_df.to_string(index=False))

# 可视化相关系数矩阵
plt.figure(figsize=(12, 10))
mask = np.triu(np.ones_like(R, dtype=bool))
sns.heatmap(R, annot=True, fmt='.3f', cmap='coolwarm', center=0,
            xticklabels=variables, yticklabels=variables,
            mask=mask, cbar_kws={'label': '相关系数'})
plt.title('身体测量变量相关系数矩阵', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()

# 分析高相关性变量对
print("\n高相关性变量对 (|r| > 0.7):")
high_corr_pairs = []
for i in range(14):
    for j in range(i+1, 14):
        if abs(R[i,j]) > 0.7:
            high_corr_pairs.append((variables[i], variables[j], R[i,j]))

for var1, var2, corr in high_corr_pairs:
    print(f"{var1} - {var2}: {corr:.3f}")

print(f"\n总共发现 {len(high_corr_pairs)} 对高相关性变量")