Contents

20250513 meeting

Introduction

The following uses the same training approach as last week, except that the training method has been changed to the forecast method.

Each combination also shows the MSPE of CO, NOx, O3, PM2.5, and SO2 in the dataset.

Original Program (test with no missing values)

200

rm

MSPE: 0.2670296334605754

MSPE (per polluant): [0.24853024 0.2530521 0.26650984 0.29022381 0.27683218]

gallery_made_with_nanogallery2-original-200-rm

bm

MSPE: 0.028377005098096042

MSPE (per polluant): [0.05570757 0.00931698 0.00982079 0.01584567 0.05119401]

gallery_made_with_nanogallery2-original-200-bm

mnr

MSPE: 0.031035673202506362

MSPE (per polluant): [0.04832559 0.01763471 0.01713394 0.05337523 0.01870889]

gallery_made_with_nanogallery2-original-200-mnr

forecast

MSPE: 0.01983729877681366

MSPE (per polluant): [0.02048197 0.01991615 0.02261555 0.01805628 0.01811654]

gallery_made_with_nanogallery2-original-200-tf

24

rm

MSPE: 0.00619986746721049

MSPE (per polluant): [0.00633583 0.00567932 0.00643217 0.00653991 0.0060121 ]

gallery_made_with_nanogallery2-original-24-rm

bm

MSPE: 0.014311867730900778

MSPE (per polluant): [0.05506475 0.00345052 0.00333255 0.00523976 0.00447176]

gallery_made_with_nanogallery2-original-24-bm

mnr

MSPE: 0.018981540433120517

MSPE (per polluant): [0.00333461 0.03810891 0.00481243 0.00331675 0.04533501]

gallery_made_with_nanogallery2-original-24-mnr

forecast

MSPE: 0.0070626912237513545

MSPE (per polluant): [0.00720427 0.00756547 0.00656687 0.00792716 0.00604968]

gallery_made_with_nanogallery2-original-24-tf

12

rm

MSPE: 0.002616900708467343

MSPE (per polluant): [0.00300699 0.0035922 0.00263202 0.00171722 0.00213607]

gallery_made_with_nanogallery2-original-12-rm

bm

MSPE: 0.038285284933024764

MSPE (per polluant): [0.02292427 0.06918261 0.0394378 0.02133293 0.03854882]

gallery_made_with_nanogallery2-original-12-bm

mnr

MSPE: 0.04627111620176548

MSPE (per polluant): [0.0442022 0.04389888 0.04129601 0.04729015 0.05466834]

gallery_made_with_nanogallery2-original-12-mnr

forecast

MSPE: 0.027468193901030315

MSPE (per polluant): [0.03450684 0.02567697 0.02923344 0.01771871 0.030205 ]

gallery_made_with_nanogallery2-original-12-tf

Prediction (test with missing values allowed)

200

rm

MSPE for all: 0.26359314172785486

MSPE for all (per polluant): [0.26905376 0.25574947 0.28052578 0.25100442 0.26163227]

MSPE only for missing: 0.266999942757196

MSPE for all (per polluant): [0.28228508 0.27145088 0.29145757 0.23416063 0.25510918]

gallery_made_with_nanogallery2-predict-200-rm

bm

MSPE for all: 0.03627450973249119

MSPE for all (per polluant): [0.03418577 0.03615802 0.03825413 0.03674731 0.03602732]

MSPE only for missing: 0.09063353972406932

MSPE for all (per polluant): [0.08541148 0.09034198 0.09558279 0.09181558 0.09001587]

gallery_made_with_nanogallery2-predict-200-bm

rbm

MSPE for all: 0.18872160069272334

MSPE for all (per polluant): [0.1245216 0.23241761 0.27848055 0.17466932 0.13351893]

MSPE only for missing: 0.1529691304212167

MSPE for all (per polluant): [0.31117033 0.05161114 0.09800657 0.07323075 0.23082686]

gallery_made_with_nanogallery2-predict-200-rbm

forecast

MSPE for all: 0.021272910649979906

MSPE for all (per polluant): [0.02169129 0.0203196 0.02180517 0.02046255 0.02208595]

MSPE only for missing: 0.05313452497446276

MSPE for all (per polluant): [0.05418063 0.05075108 0.05446552 0.05110837 0.05516703]

gallery_made_with_nanogallery2-predict-200-tf

24

rm

MSPE for all: 0.006075528992989291

MSPE for all (per polluant): [0.00671391 0.00600151 0.00490925 0.00661012 0.00614285]

MSPE only for missing: 0.02425226355592921

MSPE for all (per polluant): [0.00531567 0.00777571 0.10396352 0.00475068 0.00439044]

gallery_made_with_nanogallery2-predict-24-rm

bm

MSPE for all: 0.002255499816708605

MSPE for all (per polluant): [0.00236381 0.00218572 0.00243353 0.00219861 0.00209583]

MSPE only for missing: 0.0458826803307174

MSPE for all (per polluant): [0.04814393 0.04443191 0.04959418 0.04469903 0.04254436]

gallery_made_with_nanogallery2-predict-24-bm

rbm

MSPE for all: 0.0075089527580064555

MSPE for all (per polluant): [0.00872188 0.00656201 0.00420567 0.01047179 0.00758342]

MSPE only for missing: 0.01891713509648322

MSPE for all (per polluant): [0.03741054 0.00052717 0.00024734 0.05448549 0.00191513]

gallery_made_with_nanogallery2-predict-24-rbm

forecast

MSPE for all: 0.007943497468487118

MSPE for all (per polluant): [0.00652371 0.00969486 0.00874908 0.0077423 0.00700754]

MSPE only for missing: 0.16438706211646267

MSPE for all (per polluant): [0.13480245 0.20087991 0.18117356 0.16019934 0.14488005]

gallery_made_with_nanogallery2-predict-24-tf

12

rm

MSPE for all: 0.0024877418248716965

MSPE for all (per polluant): [0.00212427 0.00400996 0.00201409 0.00214242 0.00214798]

MSPE only for missing: 0.002110897565069707

MSPE for all (per polluant): [0.00154594 0.0008708 0.00047257 0.00196384 0.00552956]

gallery_made_with_nanogallery2-predict-12-rm

bm

MSPE for all: 0.023524741195117407

MSPE for all (per polluant): [0.01595404 0.02913753 0.02277857 0.02257204 0.02718153]

MSPE only for missing: 0.9778849302630097

MSPE for all (per polluant): [0.66240434 1.21178666 0.94678264 0.93818589 1.13026512]

gallery_made_with_nanogallery2-predict-12-bm

rbm

MSPE for all: 0.0028292502494105744

MSPE for all (per polluant): [0.0027832 0.0033312 0.00269622 0.00275 0.00258563]

MSPE only for missing: 0.004499003182155347

MSPE for all (per polluant): [1.84505694e-02 3.92772396e-04 5.71754454e-05 2.03783543e-03 1.55666327e-03]

gallery_made_with_nanogallery2-predict-12-rbm

forecast

MSPE for all: 0.028298511239477558

MSPE for all (per polluant): [0.02675121 0.02386053 0.03320219 0.02575034 0.03192828]

MSPE only for missing: 1.1767571661660086

MSPE for all (per polluant): [1.11228154 0.99181863 1.38109155 1.07055341 1.3280407 ]

gallery_made_with_nanogallery2-predict-12-tf

Results

Test without missing values

Time WindowModelMSPECONOxO3PM2.5SO2
200rm0.267030.248530.253050.266510.290220.27683
bm0.028380.055710.009320.009820.015850.05119
mnr0.031040.048330.017630.017130.053380.01871
forecast0.019840.020480.019920.022620.018060.01812
24rm0.006200.006340.005680.006430.006540.00601
bm0.014310.055060.003450.003330.005240.00447
mnr0.018980.003330.038110.004810.003320.04534
forecast0.007060.007200.007570.006570.007930.00605
12rm0.002620.003010.003590.002630.001720.00214
bm0.038290.022920.069180.039440.021330.03855
mnr0.046270.044200.043900.041300.047290.05467
forecast0.027470.034510.025680.029230.017720.03021

Test with missing values

MSPE for All

TimeModelMSPE (All)CONOxO3PM2.5SO2
200rm0.26360.26910.25570.28050.25100.2616
bm0.03630.03420.03620.03830.03670.0360
rbm0.18870.12450.23240.27850.17470.1335
forecast0.02130.02170.02030.02180.02050.0221
24rm0.00610.00670.00600.00490.00660.0061
bm0.00230.00240.00220.00240.00220.0021
rbm0.00750.00870.00660.00420.01050.0076
forecast0.00790.00650.00970.00870.00770.0070
12rm0.00250.00210.00400.00200.00210.0021
bm0.02350.01600.02910.02280.02260.0272
rbm0.00280.00280.00330.00270.00280.0026
forecast0.02830.02680.02390.03320.02580.0319

MSPE only for missing

TimeModelMSPE (Missing)CONOxO3PM2.5SO2
200rm0.26700.28230.27150.29150.23420.2551
bm0.09060.08540.09030.09560.09180.0900
rbm0.15300.31120.05160.09800.07320.2308
forecast0.05310.05420.05080.05450.05110.0552
24rm0.02430.00530.00780.10400.00480.0044
bm0.04590.04810.04440.04960.04470.0425
rbm0.01890.03740.00050.00020.05450.0019
forecast0.16440.13480.20090.18120.16020.1449
12rm0.00210.00150.00090.00050.00200.0055
bm0.97790.66241.21180.94680.93821.1303
rbm0.00450.01850.00040.00010.00200.0016
forecast1.17681.11230.99181.38111.07061.3280

Embedding autoFRK into SSSDS4

Before embedding the basis functions of autoFRK, implement the basis functions in Python.

 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
class FRKBasis(nn.Module):
    def __init__(self, locs: torch.Tensor, num_centers: int = 64):
        """
        Multi-resolution spline basis function.
        Args:
            locs: [N, d] tensor of spatial locations
            num_centers: number of TPS centers to use
        """
        super().__init__()
        self.register_buffer("locs", locs)  # [N, d]
        self.N, self.d = locs.shape

        # Select centers from locs
        idx = torch.randperm(self.N)[:num_centers]
        self.register_buffer("centers", locs[idx])  # [K, d]

    def tps_phi(self, r: torch.Tensor) -> torch.Tensor:
        """
        Apply TPS radial basis based on input distance r
        """
        eps = 1e-10  # avoid log(0)
        if self.d == 1:
            return (r ** 3) / 12
        elif self.d == 2:
            return (r ** 2) * torch.log(r + eps) / (8 * torch.pi)
        elif self.d == 3:
            return -r / 8
        else:
            raise NotImplementedError(f"TPS not implemented for d={self.d}")

    def forward(self) -> torch.Tensor:
        # Step 1: Construct Φ (TPS basis)
        dists = torch.cdist(self.locs, self.centers)  # [N, K] (Euclidean distances)
        Phi = self.tps_phi(dists)  # [N, K]

        # Step 2: Construct X = [1, x1, x2, ..., xd]
        ones = torch.ones(self.N, 1, device=self.locs.device)
        X = torch.cat([ones, self.locs], dim=1)  # [N, d+1]

        # Step 3: Compute projection matrix Q = I - X(XᵗX)⁻¹Xᵗ
        XtX_inv = torch.inverse(X.T @ X)  # [(d+1), (d+1)]
        Q = torch.eye(self.N, device=self.locs.device) - X @ XtX_inv @ X.T  # [N, N]

        # Step 4: Compute QΦ
        QPhi = Q @ Phi  # [N, K]

        # Step 5: Eigen-decomposition of QΦ(QΦ)ᵗ
        #G = QPhi @ QPhi.T  # [N, N]
        G = Q @ Phi @ Q
        eigenvalues, eigenvectors = torch.linalg.eigh(G)  # ascending order

        # Step 6: Filter out near-zero eigenvalues and sort descending
        valid = eigenvalues > 1e-6
        eigenvalues = eigenvalues[valid]
        eigenvectors = eigenvectors[:, valid]
        idx_desc = torch.argsort(eigenvalues, descending=True)
        eigenvalues = eigenvalues[idx_desc]
        eigenvectors = eigenvectors[:, idx_desc]

        # Step 7: Construct basis functions
        sqrt_inv_lambda = torch.diag(1.0 / torch.sqrt(eigenvalues))  # [r, r]
        B_high = eigenvectors @ sqrt_inv_lambda  # [N, r]

        # Step 8: Concatenate [1, x1, ..., xd] and B_high
        B_low = X  # [N, d+1]
        F = torch.cat([B_low, B_high], dim=1)  # [N, d+1 + r]
        return F