脚本库

序列 PCA 定秩

对时间/空间序列 flattened 谱做 SVD,打印特征值,判断独立组分数。

pythonlarchpca

python xanes_pca.py series.prj --emin -20 --emax 60

xanes_pca.py
#!/usr/bin/env python3
import argparse
import numpy as np
from larch.io import read_athena
from larch.xafs import pre_edge, find_e0
from larch.math import interp

def flat_window(g, emin, emax):
    e0 = find_e0(g.energy, g.mu)
    pre_edge(g, e0=e0, pre1=-150, pre2=-30, norm1=150, norm2=800, nvict=2)
    e, y = np.asarray(g.energy), np.asarray(g.flat)
    m = (e >= e0 + emin) & (e <= e0 + emax)
    return e[m] - e0, y[m]

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("prj")
    ap.add_argument("--emin", type=float, default=-20)
    ap.add_argument("--emax", type=float, default=60)
    args = ap.parse_args()

    groups = list(read_athena(args.prj)._athena_groups.items())
    rel0, y0 = flat_window(groups[0][1], args.emin, args.emax)
    M = [y0]
    for _, g in groups[1:]:
        rel, y = flat_window(g, args.emin, args.emax)
        M.append(interp(rel, y, rel0))
    A = np.vstack(M)
    _, s, _ = np.linalg.svd(A - A.mean(0), full_matrices=False)
    tot = s.sum() or 1
    print(f"{'comp':>6} {'singular':>12} {'frac':>8} {'cum':>8}")
    cum = 0.0
    for i, si in enumerate(s, 1):
        cum += si / tot
        print(f"{i:6d} {si:12.4f} {si/tot:8.3f} {cum:8.3f}")

if __name__ == "__main__":
    main()