CCCPaste

6447fe0b5ef7e

import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import cdist
from sklearn.datasets import load_iris
from sklearn.preprocessing import MinMaxScaler
from sklearn.decomposition import PCA

def are_neighbors(grid2d, i, j):
    """
    odleglosc Chebyshev = 1 (8-neighborhood)
    """
    di = abs(grid2d[i, 0] - grid2d[j, 0])
    dj = abs(grid2d[i, 1] - grid2d[j, 1])
    return max(di, dj) == 1  # true jesli sasiaduja

def movmean(data, window):
    """
    srednia ruchoma
    """
    result = np.zeros_like(data)
    half = window // 2
    for i in range(len(data)):
        start = max(0, i - half)
        end = min(len(data), i + half + 1)
        result[i] = np.mean(data[start:end])
    return result

def som_iris_ex4():
    rng = np.random.default_rng(7)
    R, C = 12, 12  # wieksza siatka
    M = R * C
    iters = 4000  # wiecej iteracji dla wiekszych siatek
    eta0 = 0.12
    sigma0 = max(R, C) / 2  # poczatkowe sasiedztwo (globalne porzadkowanie)
    sigma_final_list = [1, 2, 3]  # koncowe rozmiary sasiedztwa do testowania
    
    iris = load_iris()
    X = iris.data
    scaler = MinMaxScaler()
    X = scaler.fit_transform(X)  # 150x4, kazda cecha do [0,1]
    S = X.shape[0]
    
    print(f"loaded iris: {S} samples, {X.shape[1]} features")
    print(f"grid: {R}x{C} = {M} neurons")
    print(f"testing sigma_final: {sigma_final_list}")
    
    gx, gy = np.meshgrid(np.arange(1, C+1), np.arange(1, R+1))
    grid2d = np.column_stack([gx.ravel(), gy.ravel()])
    
    fig1 = plt.figure(figsize=(10, 6), facecolor='white')
    ax1 = fig1.add_subplot(111)
    ax1.set_xlabel('Iteration')
    ax1.set_ylabel('Topographic Error')
    ax1.set_title(f'R={R}, C={C} — Effect of final σ in {{1,2,3}}')
    ax1.grid(True)
    ax1.box(True)
    
    results = []
    
    for k, sigma_final in enumerate(sigma_final_list):
        print(f'\n=== Testing sigma_final = {sigma_final} ===')
        
        W = rng.random((M, X.shape[1]))  # w [0,1], ten sam skala co X
        
        topoErr = np.zeros(iters)
        
        tau = iters  # jedna stala czasowa przez caly przebieg
        
        for t in range(1, iters + 1):
            sigma_t = sigma_final + (sigma0 - sigma_final) * np.exp(-t / tau)
            eta_t = eta0 * np.exp(-t / tau)
            
            x = X[rng.integers(S), :]
            
            dists = np.sum((W - x) ** 2, axis=1)
            idx = np.argsort(dists)
            bmu1 = idx[0]
            bmu2 = idx[1]
            
            dgrid2 = np.sum((grid2d - grid2d[bmu1, :]) ** 2, axis=1)
            h = np.exp(-dgrid2 / (2 * sigma_t ** 2))
            h = h / np.max(h)
            
            W = W + eta_t * (h[:, np.newaxis] * (x - W))
            
            topoErr[t-1] = 0 if are_neighbors(grid2d, bmu1, bmu2) else 1
            
            if t % 1000 == 0:
                print(f"  iteration {t}/{iters}, sigma={sigma_t:.3f}, eta={eta_t:.5f}")
        
        win = 50
        topoErr_s = movmean(topoErr, win)
        
        results.append({
            'sigma_final': sigma_final,
            'W': W.copy(),
            'topoErr': topoErr.copy(),
            'topoErr_s': topoErr_s.copy()
        })
        
        # rysuj krzywą TE
        ax1.plot(range(1, iters + 1), topoErr_s, 
                label=f'σ_final={sigma_final}', linewidth=1.5)
    
    ax1.legend(loc='northeast')
    plt.tight_layout()
    plt.show()
    
    fig2 = plt.figure(figsize=(15, 5), facecolor='white')
    
    for k, result in enumerate(results):
        W = result['W']
        
        pca = PCA(n_components=2)
        W2 = pca.fit_transform(W)
        
        ax = fig2.add_subplot(1, len(sigma_final_list), k + 1)
        ax.set_aspect('equal')
        ax.set_title(f'σ_final={result["sigma_final"]}')
        ax.box(True)
        
        WX = W2[:, 0].reshape((R, C))
        WY = W2[:, 1].reshape((R, C))
        
        # linie poziome
        for r in range(R):
            ax.plot(WX[r, :], WY[r, :], '-', linewidth=1.0, color='blue', alpha=0.6)
        
        # linie pionowe
        for c in range(C):
            ax.plot(WX[:, c], WY[:, c], '-', linewidth=1.0, color='blue', alpha=0.6)
        
        # male znaczniki dla neuronow
        ax.plot(W2[:, 0], W2[:, 1], 'ko', markersize=2, markerfacecolor='k')
    
    plt.suptitle('Final Lattices Projected by PCA', fontsize=14)
    plt.tight_layout()
    plt.show()
    
    print('\n== Summary (lower TE is better) ==')
    for result in results:
        te_mean = np.mean(result['topoErr'][-500:])  # srednia z ostatnich 500 
        print(f'sigma_final={result["sigma_final"]} -> mean TE (last 500 iters): {te_mean:.4f}')

if __name__ == '__main__':
    som_iris_ex4()