File size: 5,077 Bytes
216004d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env python3
"""LM4 数据分析: 为什么 WFR 能救活 D2/D3? 各特征/频段携带多少密度信息?"""
import sys, os
import numpy as np
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from run_lm4_wave import build_feature_matrix

CACHE = "/tmp/lm4_feat_cache.npz"
BANDS = 13
FREQ = [6.4, 17.1, 28.6, 50.2, 90.7, 161.0, 285.8, 508.4, 903.4, 1610.0, 2862.0, 5086.0, 9036.0]
MAG_NAMES = ["logMag", "log rms", "delta", "lambda"]

if os.path.exists(CACHE):
    z = np.load(CACHE)
    dens, F = z["dens"], z["F"]
    print(f"[cache] 载入 {F.shape}")
else:
    t, dens, F, ok = build_feature_matrix("data/wave", bands=BANDS, use_wfr=True)
    dens, F = dens[ok], F[ok]
    np.savez_compressed(CACHE, dens=dens, F=F)
    print(f"[built] {F.shape}")

valid = np.isfinite(dens) & (dens > 0) & np.isfinite(F).all(axis=1)
dens, F = dens[valid], F[valid]
y = np.log10(dens)
print(f"样本 {len(y)}, 特征 {F.shape[1]} 维")

# 6 个分位数域
qs = np.quantile(y, np.linspace(0, 1, 7)); qs[0] -= 1e-6; qs[-1] += 1e-6
dom = np.digitize(y, qs[1:-1])

names = MAG_NAMES + [f"B@{f:g}Hz" for f in FREQ] + [f"E@{f:g}Hz" for f in FREQ]
assert len(names) == F.shape[1], (len(names), F.shape)

# ---------- A. 单特征判别力: ANOVA F 统计量 ----------
print("\n=== A. 单特征判别力 (跨 6 个密度域, F 越大越有信息) ===")
Fs, MI = [], []
for j in range(F.shape[1]):
    v = F[:, j]
    gm = v.mean()
    ssb = sum(len(v[dom == d]) * (v[dom == d].mean() - gm) ** 2
              for d in range(6) if (dom == d).sum() > 0)
    ssw = sum(((v[dom == d] - v[dom == d].mean()) ** 2).sum()
              for d in range(6) if (dom == d).sum() > 0)
    dfb, dfw = 5, len(v) - 6
    Fs.append((ssb / dfb) / (ssw / dfw + 1e-30))
    # MI (20 bins)
    hb = np.histogram(v, bins=20)[0].astype(float); hb /= hb.sum() + 1e-30
    hd = np.bincount(dom, minlength=6).astype(float); hd /= hd.sum()
    H_d = -(hd[hd > 0] * np.log(hd[hd > 0])).sum()
    H_dv = 0.0
    for d in range(6):
        m = dom == d
        if m.sum() == 0: continue
        h2 = np.histogram(v[m], bins=20)[0].astype(float); h2 /= h2.sum() + 1e-30
        H_dv += hd[d] * (-(h2[h2 > 0] * np.log(h2[h2 > 0])).sum())
    MI.append(H_d - H_dv)

order = np.argsort(Fs)[::-1]
print(f"{'feature':<14}{'F':>12}{'MI':>8}")
for j in order[:14]:
    print(f"{names[j]:<14}{Fs[j]:>12.1f}{MI[j]:>8.4f}")
print("  ...")
print(f"{'最弱5个:':<14}" + ", ".join(f"{names[j]}({Fs[j]:.0f})" for j in order[-5:]))

# ---------- B. 各域的平均磁场波谱 (揭示物理机制) ----------
print("\n=== B. 各密度域的平均磁功率谱 (log10, 每格=该域该频段均值) ===")
bpow = F[:, 4:4 + BANDS]
print(f"{'freq(Hz)':>10}" + "".join(f"{'D'+str(d):>9}" for d in range(6)) + f"{'D5-D0':>9}")
for i, fr in enumerate(FREQ):
    row = [bpow[dom == d, i].mean() for d in range(6)]
    print(f"{fr:>10.1f}" + "".join(f"{v:>9.2f}" for v in row) + f"{row[5]-row[0]:>9.2f}")

# ---------- C. D2 vs D3 二分类可解性 ----------
def auc_score(scores, labels):
    """Mann-Whitney AUC. labels: 1=正类。"""
    order = np.argsort(scores, kind="mergesort")
    ranks = np.empty(len(scores), dtype=np.float64)
    ranks[order] = np.arange(1, len(scores) + 1)
    n1 = int(labels.sum()); n0 = len(labels) - n1
    if n1 == 0 or n0 == 0:
        return float("nan")
    return (ranks[labels == 1].sum() - n1 * (n1 + 1) / 2) / (n1 * n0)


print("\n=== C. D2 vs D3 二分类 (最难的相邻域) ===")
m23 = (dom == 2) | (dom == 3)
y23 = (dom[m23] == 3).astype(int)
print(f"  样本数: D2={int((dom==2).sum())}, D3={int((dom==3).sum())}")

for tag, cols in [("MAG 4 维", [0, 1, 2, 3]),
                  ("WFR 磁 13 维", list(range(4, 4 + BANDS))),
                  ("WFR 电 13 维", list(range(4 + BANDS, 4 + 2 * BANDS))),
                  ("全部 30 维", list(range(30)))]:
    Xs = F[m23][:, cols]
    mu, sd = Xs.mean(0), Xs.std(0) + 1e-9
    Xn = (Xs - mu) / sd
    c0, c1 = Xn[y23 == 0].mean(0), Xn[y23 == 1].mean(0)
    w = c1 - c0
    proj = Xn @ w
    a = auc_score(proj, y23)
    print(f"  {tag:<14} 线性判别 AUC = {a:.4f}  (0.5=无信息)")

# ---------- D. 单个频段对 D2/D3 的区分力 ----------
print("\n=== D. 各频段单独区分 D2/D3 的能力 (AUC, 只列 |AUC-0.5|>0.05 的) ===")
rowsd = []
for j in range(F.shape[1]):
    a = auc_score(F[m23][:, j], y23)
    rowsd.append((names[j], a))
rowsd.sort(key=lambda t: -abs(t[1] - 0.5))
for n_, a in rowsd[:12]:
    print(f"  {n_:<14} AUC={a:.4f}  ({'高密度→更强' if a > 0.5 else '高密度→更弱'})")

# ---------- E. 波谱形状 vs 密度 (整体相关) ----------
print("\n=== E. 各频段功率 vs log10(density) 的相关系数 (只列 |r|>0.15) ===")
cor = []
for j in range(4, 4 + 2 * BANDS):
    v = F[:, j]
    if np.std(v) < 1e-9:
        continue
    r = float(np.corrcoef(v, y)[0, 1])
    cor.append((names[j], r))
cor.sort(key=lambda t: -abs(t[1]))
for n_, r in cor[:12]:
    print(f"  {n_:<14} r={r:+.3f}")