flkit 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flkit/__init__.py +2 -0
- flkit/alg/__init__.py +68 -0
- flkit/alg/build_idx.py +9 -0
- flkit/alg/c_track.py +88 -0
- flkit/alg/collierydb.py +1217 -0
- flkit/alg/del2.py +421 -0
- flkit/alg/delaunay_triangulation.py +476 -0
- flkit/alg/finite_plane_distance.py +239 -0
- flkit/alg/get_up_low.py +32 -0
- flkit/alg/in_tin.py +139 -0
- flkit/alg/index.py +9 -0
- flkit/alg/inter/BasePredictor.py +69 -0
- flkit/alg/inter/Kriging.py +226 -0
- flkit/alg/inter/KrigingM.py +262 -0
- flkit/alg/inter/LossFuncs.py +164 -0
- flkit/alg/inter/__init__.py +178 -0
- flkit/alg/inter/idw.py +253 -0
- flkit/alg/inter/midw.py +145 -0
- flkit/alg/inter/nearest_neighbor.py +445 -0
- flkit/alg/inter/rbf.py +345 -0
- flkit/alg/inter/trilinear.py +572 -0
- flkit/alg/point_in_polygon.py +126 -0
- flkit/alg/point_in_volume.py +188 -0
- flkit/alg/point_in_volume_rs.pyi +7 -0
- flkit/alg/point_to_triangle.py +116 -0
- flkit/alg/point_to_triangle_mesh.py +309 -0
- flkit/alg/point_to_triangle_rs.pyi +9 -0
- flkit/alg/rotated_rect.py +184 -0
- flkit/db/__init__.py +17 -0
- flkit/db/db_model.py +724 -0
- flkit/db/duck_model.py +151 -0
- flkit/db/fileobj.py +72 -0
- flkit/db/path_utl.py +174 -0
- flkit/mtcli/__init__.py +18 -0
- flkit/mtcli/core.py +489 -0
- flkit/mtcli/parse.py +218 -0
- flkit/py.typed +0 -0
- flkit/tools/__init__.py +28 -0
- flkit/tools/del_key.py +13 -0
- flkit/tools/dict_to_list.py +10 -0
- flkit/tools/get_region.py +42 -0
- flkit/tools/max_key.py +7 -0
- flkit/tools/mongo.py +119 -0
- flkit/tools/mt_dash.py +121 -0
- flkit/tools/prase_type.py +27 -0
- flkit/typr/Res.py +21 -0
- flkit/typr/__init__.py +107 -0
- flkit/typr/c_grid.py +425 -0
- flkit/typr/console.py +283 -0
- flkit/typr/engine.py +59 -0
- flkit/typr/getenv.py +89 -0
- flkit/typr/result.py +81 -0
- flkit/typr/table.py +34 -0
- flkit/typr/utils.py +542 -0
- flkit/typr/verify.py +64 -0
- flkit/typr/webview.py +219 -0
- flkit/typr/wstask.py +344 -0
- flkit-0.1.0.dist-info/METADATA +186 -0
- flkit-0.1.0.dist-info/RECORD +60 -0
- flkit-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from .BasePredictor import Predictor
|
|
3
|
+
from .LossFuncs import ErrorMetrics
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class KrigingOpm(Predictor):
|
|
7
|
+
"""
|
|
8
|
+
普通克里金插值(Ordinary Kriging),遵循 IDWOpm 的设计模式:
|
|
9
|
+
- 通过 __call__(data) 传入训练样本(list/tuple,每个元素为 [x, y, z])
|
|
10
|
+
- 通过 predict(points) 预测多个查询点(list/tuple,每个元素为 [x, y])
|
|
11
|
+
- 可使用 add_params(params) 设置变差函数参数:
|
|
12
|
+
{
|
|
13
|
+
"variogram": "spherical" | "exponential" | "gaussian",
|
|
14
|
+
"range": float, # 影响范围 a
|
|
15
|
+
"sill": float, # 基台 s
|
|
16
|
+
"nugget": float # 块金 n(用于数值稳定,默认极小值)
|
|
17
|
+
}
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
class OKModel:
|
|
21
|
+
def __init__(self, x: list, y: list, value: list, params: dict | None = None):
|
|
22
|
+
self.x = np.asarray(x, dtype=float)
|
|
23
|
+
self.y = np.asarray(y, dtype=float)
|
|
24
|
+
self.value = np.asarray(value, dtype=float)
|
|
25
|
+
self.n = len(self.value)
|
|
26
|
+
|
|
27
|
+
# 读取参数
|
|
28
|
+
params = params or {}
|
|
29
|
+
self.variogram = params.get("variogram", "spherical")
|
|
30
|
+
# 经验设定:若未提供,range 取最大样本距离的一半,sill 取样本方差,nugget 给一个极小正数以稳定求逆
|
|
31
|
+
# 计算样本两两距离
|
|
32
|
+
pts = np.column_stack((self.x, self.y))
|
|
33
|
+
dmat = self._pairwise_dist(pts, pts)
|
|
34
|
+
max_d = float(np.max(dmat)) if self.n > 1 else 1.0
|
|
35
|
+
self.range = float(params.get("range", max(1e-8, 0.5 * max_d)))
|
|
36
|
+
var = float(np.var(self.value))
|
|
37
|
+
self.sill = float(params.get("sill", var if var > 0 else 1.0))
|
|
38
|
+
self.nugget = float(params.get("nugget", 1e-10))
|
|
39
|
+
|
|
40
|
+
# 构造普通克里金矩阵 K(n+1, n+1): [Gamma 1; 1^T 0]
|
|
41
|
+
# 其中 Gamma_ij = gamma(|x_i - x_j|)
|
|
42
|
+
Gamma = self._gamma(dmat)
|
|
43
|
+
K = np.zeros((self.n + 1, self.n + 1), dtype=float)
|
|
44
|
+
K[: self.n, : self.n] = Gamma
|
|
45
|
+
K[: self.n, self.n] = 1.0
|
|
46
|
+
K[self.n, : self.n] = 1.0
|
|
47
|
+
# 预计算逆或伪逆,提高多点预测效率
|
|
48
|
+
# 为避免奇异情况,使用伪逆更鲁棒
|
|
49
|
+
self.K_inv = np.linalg.pinv(K)
|
|
50
|
+
|
|
51
|
+
def _pairwise_dist(self, A: np.ndarray, B: np.ndarray) -> np.ndarray:
|
|
52
|
+
# ||A_i - B_j|| 的矩阵
|
|
53
|
+
# 使用 (a-b)^2 = a^2 + b^2 - 2ab 加速计算
|
|
54
|
+
A2 = np.sum(A**2, axis=1, keepdims=True)
|
|
55
|
+
B2 = np.sum(B**2, axis=1, keepdims=True).T
|
|
56
|
+
d2 = A2 + B2 - 2 * (A @ B.T)
|
|
57
|
+
d2 = np.maximum(d2, 0.0)
|
|
58
|
+
return np.sqrt(d2)
|
|
59
|
+
|
|
60
|
+
def _structure(self, h: np.ndarray) -> np.ndarray:
|
|
61
|
+
a = self.range
|
|
62
|
+
if self.variogram == "spherical":
|
|
63
|
+
# spherical: s * (1.5*(h/a) - 0.5*(h/a)^3) for h<=a, else s
|
|
64
|
+
hr = np.clip(h / a, 0.0, None)
|
|
65
|
+
val = 1.5 * hr - 0.5 * (hr**3)
|
|
66
|
+
return np.where(h <= a, self.sill * val, self.sill)
|
|
67
|
+
elif self.variogram == "exponential":
|
|
68
|
+
# exponential: s * (1 - exp(-h/a))
|
|
69
|
+
return self.sill * (1.0 - np.exp(-h / a))
|
|
70
|
+
elif self.variogram == "gaussian":
|
|
71
|
+
# gaussian: s * (1 - exp(-(h/a)^2))
|
|
72
|
+
hr = h / a
|
|
73
|
+
return self.sill * (1.0 - np.exp(-(hr**2)))
|
|
74
|
+
else:
|
|
75
|
+
# 默认使用 exponential
|
|
76
|
+
return self.sill * (1.0 - np.exp(-h / a))
|
|
77
|
+
|
|
78
|
+
def _gamma(self, hmat: np.ndarray) -> np.ndarray:
|
|
79
|
+
# 半变异函数 gamma(h) = nugget + structure(h)
|
|
80
|
+
gamma = self.nugget + self._structure(hmat)
|
|
81
|
+
# 理论上 gamma(0) = nugget;已在式中体现
|
|
82
|
+
return gamma
|
|
83
|
+
|
|
84
|
+
def execute(self, point_x: float, point_y: float):
|
|
85
|
+
# 构造右端向量 k: [gamma(|x_i - x|); 1]
|
|
86
|
+
p = np.array([[point_x, point_y]], dtype=float)
|
|
87
|
+
pts = np.column_stack((self.x, self.y))
|
|
88
|
+
d = self._pairwise_dist(pts, p).ravel() # shape (n,)
|
|
89
|
+
k = np.zeros(self.n + 1, dtype=float)
|
|
90
|
+
k[: self.n] = self.nugget + self._structure(d)
|
|
91
|
+
k[self.n] = 1.0
|
|
92
|
+
|
|
93
|
+
# 求权重
|
|
94
|
+
w_lambda = self.K_inv @ k
|
|
95
|
+
w = w_lambda[: self.n]
|
|
96
|
+
lam = w_lambda[self.n]
|
|
97
|
+
|
|
98
|
+
# 预测值
|
|
99
|
+
z_hat = float(np.dot(w, self.value))
|
|
100
|
+
# 克里金方差(近似公式):sigma^2 = sum_i w_i * gamma(h_i) + lambda
|
|
101
|
+
sigma2 = float(np.dot(w, k[: self.n]) + lam)
|
|
102
|
+
return z_hat, sigma2
|
|
103
|
+
|
|
104
|
+
def fit(self, data: list | tuple):
|
|
105
|
+
x = [row[0] for row in data]
|
|
106
|
+
y = [row[1] for row in data]
|
|
107
|
+
z = [row[2] for row in data]
|
|
108
|
+
self.model = self.OKModel(x, y, z, self.params)
|
|
109
|
+
return self
|
|
110
|
+
|
|
111
|
+
def predict(self, points: list | tuple):
|
|
112
|
+
arr = np.asarray(points)
|
|
113
|
+
if arr.ndim == 1:
|
|
114
|
+
result, _ = self.model.execute(float(arr[0]), float(arr[1]))
|
|
115
|
+
return result
|
|
116
|
+
if arr.ndim == 2 and arr.shape[1] == 2:
|
|
117
|
+
z1 = np.zeros(arr.shape[0], dtype=float)
|
|
118
|
+
for i in range(arr.shape[0]):
|
|
119
|
+
result, _ = self.model.execute(float(arr[i, 0]), float(arr[i, 1]))
|
|
120
|
+
z1[i] = result
|
|
121
|
+
return z1
|
|
122
|
+
raise ValueError("预测点坐标必须是2列:[x, y] 或形状 (M, 2)")
|
|
123
|
+
|
|
124
|
+
def loss(self, data, res):
|
|
125
|
+
return ErrorMetrics.mse(data, res)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class KrigingOpm3D(Predictor):
|
|
129
|
+
"""
|
|
130
|
+
三维普通克里金插值(3D Ordinary Kriging),仿照 IDWOpm3D 的设计模式:
|
|
131
|
+
- 通过 __call__(data) 传入训练样本(list/tuple,每个元素为 [x, y, z, value])
|
|
132
|
+
- 通过 predict(points) 预测多个查询点(list/tuple,每个元素为 [x, y, z])
|
|
133
|
+
- 可使用 add_params(params) 设置变差函数参数:
|
|
134
|
+
{
|
|
135
|
+
"variogram": "spherical" | "exponential" | "gaussian",
|
|
136
|
+
"range": float, # 影响范围 a
|
|
137
|
+
"sill": float, # 基台 s
|
|
138
|
+
"nugget": float # 块金 n(用于数值稳定,默认极小值)
|
|
139
|
+
}
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
class OK3DModel:
|
|
143
|
+
def __init__(
|
|
144
|
+
self, x: list, y: list, z: list, value: list, params: dict | None = None
|
|
145
|
+
):
|
|
146
|
+
self.x = np.asarray(x, dtype=float)
|
|
147
|
+
self.y = np.asarray(y, dtype=float)
|
|
148
|
+
self.z = np.asarray(z, dtype=float)
|
|
149
|
+
self.value = np.asarray(value, dtype=float)
|
|
150
|
+
self.n = len(self.value)
|
|
151
|
+
|
|
152
|
+
# 读取参数
|
|
153
|
+
params = params or {}
|
|
154
|
+
self.variogram = params.get("variogram", "spherical")
|
|
155
|
+
|
|
156
|
+
# 计算三维样本两两距离
|
|
157
|
+
pts = np.column_stack((self.x, self.y, self.z))
|
|
158
|
+
dmat = self._pairwise_dist_3d(pts, pts)
|
|
159
|
+
max_d = float(np.max(dmat)) if self.n > 1 else 1.0
|
|
160
|
+
self.range = float(params.get("range", max(1e-8, 0.5 * max_d)))
|
|
161
|
+
var = float(np.var(self.value))
|
|
162
|
+
self.sill = float(params.get("sill", var if var > 0 else 1.0))
|
|
163
|
+
self.nugget = float(params.get("nugget", 1e-10))
|
|
164
|
+
|
|
165
|
+
# 构造普通克里金矩阵 K(n+1, n+1): [Gamma 1; 1^T 0]
|
|
166
|
+
# 其中 Gamma_ij = gamma(|x_i - x_j|)
|
|
167
|
+
Gamma = self._gamma(dmat)
|
|
168
|
+
K = np.zeros((self.n + 1, self.n + 1), dtype=float)
|
|
169
|
+
K[: self.n, : self.n] = Gamma
|
|
170
|
+
K[: self.n, self.n] = 1.0
|
|
171
|
+
K[self.n, : self.n] = 1.0
|
|
172
|
+
# 预计算逆或伪逆,提高多点预测效率
|
|
173
|
+
# 为避免奇异情况,使用伪逆更鲁棒
|
|
174
|
+
self.K_inv = np.linalg.pinv(K)
|
|
175
|
+
|
|
176
|
+
def _pairwise_dist_3d(self, A: np.ndarray, B: np.ndarray) -> np.ndarray:
|
|
177
|
+
"""计算三维点集A和B之间的欧几里得距离矩阵"""
|
|
178
|
+
# ||A_i - B_j|| 的矩阵
|
|
179
|
+
# 使用 (a-b)^2 = a^2 + b^2 - 2ab 加速计算
|
|
180
|
+
A2 = np.sum(A**2, axis=1, keepdims=True)
|
|
181
|
+
B2 = np.sum(B**2, axis=1, keepdims=True).T
|
|
182
|
+
d2 = A2 + B2 - 2 * (A @ B.T)
|
|
183
|
+
d2 = np.maximum(d2, 0.0)
|
|
184
|
+
return np.sqrt(d2)
|
|
185
|
+
|
|
186
|
+
def _structure(self, h: np.ndarray) -> np.ndarray:
|
|
187
|
+
"""变差函数的结构部分"""
|
|
188
|
+
a = self.range
|
|
189
|
+
if self.variogram == "spherical":
|
|
190
|
+
# spherical: s * (1.5*(h/a) - 0.5*(h/a)^3) for h<=a, else s
|
|
191
|
+
hr = np.clip(h / a, 0.0, None)
|
|
192
|
+
val = 1.5 * hr - 0.5 * (hr**3)
|
|
193
|
+
return np.where(h <= a, self.sill * val, self.sill)
|
|
194
|
+
elif self.variogram == "exponential":
|
|
195
|
+
# exponential: s * (1 - exp(-h/a))
|
|
196
|
+
return self.sill * (1.0 - np.exp(-h / a))
|
|
197
|
+
elif self.variogram == "gaussian":
|
|
198
|
+
# gaussian: s * (1 - exp(-(h/a)^2))
|
|
199
|
+
hr = h / a
|
|
200
|
+
return self.sill * (1.0 - np.exp(-(hr**2)))
|
|
201
|
+
else:
|
|
202
|
+
# 默认使用 exponential
|
|
203
|
+
return self.sill * (1.0 - np.exp(-h / a))
|
|
204
|
+
|
|
205
|
+
def _gamma(self, hmat: np.ndarray) -> np.ndarray:
|
|
206
|
+
"""半变异函数 gamma(h) = nugget + structure(h)"""
|
|
207
|
+
gamma = self.nugget + self._structure(hmat)
|
|
208
|
+
return gamma
|
|
209
|
+
|
|
210
|
+
def execute(self, point_x: float, point_y: float, point_z: float):
|
|
211
|
+
"""执行三维克里金插值预测"""
|
|
212
|
+
# 构造右端向量 k: [gamma(|x_i - x|); 1]
|
|
213
|
+
p = np.array([[point_x, point_y, point_z]], dtype=float)
|
|
214
|
+
pts = np.column_stack((self.x, self.y, self.z))
|
|
215
|
+
d = self._pairwise_dist_3d(pts, p).ravel() # shape (n,)
|
|
216
|
+
k = np.zeros(self.n + 1, dtype=float)
|
|
217
|
+
k[: self.n] = self.nugget + self._structure(d)
|
|
218
|
+
k[self.n] = 1.0
|
|
219
|
+
|
|
220
|
+
# 求权重
|
|
221
|
+
w_lambda = self.K_inv @ k
|
|
222
|
+
w = w_lambda[: self.n]
|
|
223
|
+
lam = w_lambda[self.n]
|
|
224
|
+
|
|
225
|
+
# 预测值
|
|
226
|
+
z_hat = float(np.dot(w, self.value))
|
|
227
|
+
# 克里金方差(近似公式):sigma^2 = sum_i w_i * gamma(h_i) + lambda
|
|
228
|
+
sigma2 = float(np.dot(w, k[: self.n]) + lam)
|
|
229
|
+
return z_hat, sigma2
|
|
230
|
+
|
|
231
|
+
def fit(self, data: list | tuple):
|
|
232
|
+
"""初始化模型,传入训练数据"""
|
|
233
|
+
x = [row[0] for row in data]
|
|
234
|
+
y = [row[1] for row in data]
|
|
235
|
+
z = [row[2] for row in data]
|
|
236
|
+
value = [row[3] for row in data]
|
|
237
|
+
self.model = self.OK3DModel(x, y, z, value, self.params)
|
|
238
|
+
return self
|
|
239
|
+
|
|
240
|
+
def predict(self, points: list | tuple):
|
|
241
|
+
"""预测多个查询点的值"""
|
|
242
|
+
arr = np.asarray(points)
|
|
243
|
+
if arr.ndim == 1:
|
|
244
|
+
result, _ = self.model.execute(float(arr[0]), float(arr[1]), float(arr[2]))
|
|
245
|
+
return result
|
|
246
|
+
if arr.ndim == 2 and arr.shape[1] == 3:
|
|
247
|
+
z1 = np.zeros(arr.shape[0], dtype=float)
|
|
248
|
+
for i in range(arr.shape[0]):
|
|
249
|
+
result, _ = self.model.execute(
|
|
250
|
+
float(arr[i, 0]), float(arr[i, 1]), float(arr[i, 2])
|
|
251
|
+
)
|
|
252
|
+
z1[i] = result
|
|
253
|
+
return z1
|
|
254
|
+
raise ValueError("预测点坐标必须是3列:[x, y, z] 或形状 (M, 3)")
|
|
255
|
+
|
|
256
|
+
def loss(self, data, res):
|
|
257
|
+
"""计算损失函数"""
|
|
258
|
+
return ErrorMetrics.mse(data, res)
|
|
259
|
+
|
|
260
|
+
def add_params(self, params: dict):
|
|
261
|
+
"""添加变差函数参数"""
|
|
262
|
+
self.params = params
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""
|
|
2
|
+
损失函数
|
|
3
|
+
提供常用的损失函数计算方法,如均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)和平均相对误差(RE)。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from typing import Union, List
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ErrorMetrics:
|
|
11
|
+
"""
|
|
12
|
+
常用误差计算工具类(静态方法)
|
|
13
|
+
支持输入类型:列表、NumPy数组等可迭代对象
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
@staticmethod
|
|
17
|
+
def _convert_to_array(data: Union[List, np.ndarray]) -> np.ndarray:
|
|
18
|
+
"""将输入数据统一转换为NumPy数组"""
|
|
19
|
+
if not isinstance(data, np.ndarray):
|
|
20
|
+
data = np.array(data)
|
|
21
|
+
return data.astype(float)
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def _validate_input_length(data: np.ndarray, pred: np.ndarray):
|
|
25
|
+
"""检查输入数据长度一致性"""
|
|
26
|
+
if len(data) != len(pred):
|
|
27
|
+
raise ValueError("输入数据长度不一致")
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def mse(data: Union[List, np.ndarray], pred: Union[List, np.ndarray]) -> float:
|
|
31
|
+
"""
|
|
32
|
+
计算均方误差(Mean Squared Error)
|
|
33
|
+
公式: MSE = 1/n * Σ(y_true - y_pred)^2
|
|
34
|
+
"""
|
|
35
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
36
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
37
|
+
if len(y_true) != len(y_pred):
|
|
38
|
+
raise ValueError("输入数据长度不一致")
|
|
39
|
+
return np.mean((y_true - y_pred) ** 2)
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def rmse(data: Union[List, np.ndarray], pred: Union[List, np.ndarray]) -> float:
|
|
43
|
+
"""
|
|
44
|
+
计算均方根误差(Root Mean Squared Error)
|
|
45
|
+
公式: RMSE = sqrt(MSE)
|
|
46
|
+
"""
|
|
47
|
+
mse = ErrorMetrics.mse(data, pred)
|
|
48
|
+
return np.sqrt(mse)
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def mae(data: Union[List, np.ndarray], pred: Union[List, np.ndarray]) -> float:
|
|
52
|
+
"""
|
|
53
|
+
计算平均绝对误差(Mean Absolute Error)
|
|
54
|
+
公式: MAE = 1/n * Σ|y_true - y_pred|
|
|
55
|
+
"""
|
|
56
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
57
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
58
|
+
if len(y_true) != len(y_pred):
|
|
59
|
+
raise ValueError("输入数据长度不一致")
|
|
60
|
+
return np.mean(np.abs(y_true - y_pred))
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def relative_error(
|
|
64
|
+
data: Union[List, np.ndarray], pred: Union[List, np.ndarray]
|
|
65
|
+
) -> float:
|
|
66
|
+
"""
|
|
67
|
+
计算平均相对误差(Relative Error)
|
|
68
|
+
公式: RE = 1/n * Σ(|y_true - y_pred| / |y_true|)
|
|
69
|
+
"""
|
|
70
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
71
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
72
|
+
if len(y_true) != len(y_pred):
|
|
73
|
+
raise ValueError("输入数据长度不一致")
|
|
74
|
+
if np.any(y_true == 0):
|
|
75
|
+
raise ValueError("真实值包含0,无法计算相对误差")
|
|
76
|
+
return np.mean(np.abs((y_true - y_pred) / y_true))
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def r2_score(data: Union[List, np.ndarray], pred: Union[List, np.ndarray]) -> float:
|
|
80
|
+
"""
|
|
81
|
+
计算R平方决定系数(R-squared)
|
|
82
|
+
公式: R² = 1 - (Σ(y_true - y_pred)^2 / Σ(y_true - y_mean)^2)
|
|
83
|
+
"""
|
|
84
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
85
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
86
|
+
if len(y_true) != len(y_pred):
|
|
87
|
+
raise ValueError("输入数据长度不一致")
|
|
88
|
+
ss_res = np.sum((y_true - y_pred) ** 2)
|
|
89
|
+
ss_tot = np.sum((y_true - np.mean(y_true)) ** 2)
|
|
90
|
+
return 1 - (ss_res / ss_tot)
|
|
91
|
+
|
|
92
|
+
@staticmethod
|
|
93
|
+
def cross_entropy(
|
|
94
|
+
data: Union[List, np.ndarray],
|
|
95
|
+
pred: Union[List, np.ndarray],
|
|
96
|
+
epsilon: float = 1e-12,
|
|
97
|
+
) -> float:
|
|
98
|
+
"""
|
|
99
|
+
计算交叉熵损失(Cross-Entropy Loss)
|
|
100
|
+
适用于分类任务的概率输出
|
|
101
|
+
公式: CE = -Σ[y_true * log(y_pred) + (1-y_true)*log(1-y_pred)]
|
|
102
|
+
"""
|
|
103
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
104
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
105
|
+
if len(y_true) != len(y_pred):
|
|
106
|
+
raise ValueError("输入数据长度不一致")
|
|
107
|
+
y_pred = np.clip(y_pred, epsilon, 1.0 - epsilon)
|
|
108
|
+
return -np.sum(
|
|
109
|
+
y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)
|
|
110
|
+
) / len(y_true)
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def nrmse(
|
|
114
|
+
data: Union[List, np.ndarray],
|
|
115
|
+
pred: Union[List, np.ndarray],
|
|
116
|
+
normalization: str = "range",
|
|
117
|
+
) -> float:
|
|
118
|
+
"""
|
|
119
|
+
归一化均方根误差(Normalized RMSE)
|
|
120
|
+
|
|
121
|
+
参数:
|
|
122
|
+
normalization: 归一化方法,可选 'range'(最大值-最小值)或 'std'(标准差)[2,12](@ref)
|
|
123
|
+
"""
|
|
124
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
125
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
126
|
+
ErrorMetrics._validate_input_length(y_true, y_pred)
|
|
127
|
+
|
|
128
|
+
rmse = ErrorMetrics.rmse(y_true, y_pred)
|
|
129
|
+
|
|
130
|
+
if normalization == "range":
|
|
131
|
+
norm_factor = np.max(y_true) - np.min(y_true)
|
|
132
|
+
if norm_factor == 0:
|
|
133
|
+
raise ValueError("数据范围为零,无法使用range归一化")
|
|
134
|
+
elif normalization == "std":
|
|
135
|
+
norm_factor = np.std(y_true)
|
|
136
|
+
if norm_factor == 0:
|
|
137
|
+
raise ValueError("数据标准差为零,无法使用std归一化")
|
|
138
|
+
else:
|
|
139
|
+
raise ValueError("归一化方法仅支持 'range' 或 'std'")
|
|
140
|
+
|
|
141
|
+
return rmse / norm_factor
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def peak_error(
|
|
145
|
+
data: Union[List, np.ndarray], pred: Union[List, np.ndarray], mode: str = "max"
|
|
146
|
+
) -> float:
|
|
147
|
+
"""
|
|
148
|
+
极值误差(Peak Error)
|
|
149
|
+
|
|
150
|
+
参数:
|
|
151
|
+
mode: 计算模式,可选 'max'(最大绝对误差)或 'min'(最小绝对误差)[11](@ref)
|
|
152
|
+
"""
|
|
153
|
+
y_true = ErrorMetrics._convert_to_array(data)
|
|
154
|
+
y_pred = ErrorMetrics._convert_to_array(pred)
|
|
155
|
+
ErrorMetrics._validate_input_length(y_true, y_pred)
|
|
156
|
+
|
|
157
|
+
abs_errors = np.abs(y_true - y_pred)
|
|
158
|
+
|
|
159
|
+
if mode == "max":
|
|
160
|
+
return np.max(abs_errors)
|
|
161
|
+
elif mode == "min":
|
|
162
|
+
return np.min(abs_errors)
|
|
163
|
+
else:
|
|
164
|
+
raise ValueError("模式仅支持 'max' 或 'min'")
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""
|
|
2
|
+
插值方法
|
|
3
|
+
|
|
4
|
+
- IDW: 反距离加权插值
|
|
5
|
+
- 最近邻插值
|
|
6
|
+
- RBF: 径向基函数插值
|
|
7
|
+
- 三线性插值
|
|
8
|
+
- 普通克里金插值
|
|
9
|
+
- 优化克里金插值
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from .idw import IDW2D, IDW3D, IDW
|
|
13
|
+
|
|
14
|
+
from .nearest_neighbor import (
|
|
15
|
+
NearestNeighbor2D,
|
|
16
|
+
NearestNeighbor3D,
|
|
17
|
+
KNearestNeighbor,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from .rbf import RBF2D, RBF3D
|
|
21
|
+
|
|
22
|
+
from .trilinear import (
|
|
23
|
+
Trilinear3D,
|
|
24
|
+
BilinearInterpolator,
|
|
25
|
+
LinearInterpolator,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
from .Kriging import Kriging2D, Kriging3D, Kriging3DUn
|
|
29
|
+
|
|
30
|
+
from .midw import IDW as MIDW, IDWOpm, IDWOpm3D
|
|
31
|
+
|
|
32
|
+
from .KrigingM import KrigingOpm, KrigingOpm3D
|
|
33
|
+
|
|
34
|
+
INTER_METHODS = [
|
|
35
|
+
{
|
|
36
|
+
"name": "midw",
|
|
37
|
+
"desc": "反距离加权插值",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "idw",
|
|
41
|
+
"desc": "反距离权重插值",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "idw_m",
|
|
45
|
+
"desc": "优化反距离权重插值",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "kriging",
|
|
49
|
+
"desc": "普通克里金插值",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "kriging_m",
|
|
53
|
+
"desc": "优化克里金插值",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "rbf",
|
|
57
|
+
"desc": "径向基函数插值",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "nearest",
|
|
61
|
+
"desc": "最近邻插值",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "knearest",
|
|
65
|
+
"desc": "K最近邻插值",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "linear",
|
|
69
|
+
"desc": "线性插值",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "bilinear",
|
|
73
|
+
"desc": "双线性插值",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "trilinear",
|
|
77
|
+
"desc": "三线性插值",
|
|
78
|
+
},
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
# region 插值器
|
|
82
|
+
def make_interpolator(method: str, dim: int):
|
|
83
|
+
"""工厂:根据方法名和维度返回插值器实例"""
|
|
84
|
+
if method == "midw":
|
|
85
|
+
return IDW3D() if dim == 3 else IDW2D()
|
|
86
|
+
|
|
87
|
+
# IDW (反距离权重插值)
|
|
88
|
+
if method == "idw":
|
|
89
|
+
return IDW3D() if dim == 3 else IDW2D()
|
|
90
|
+
|
|
91
|
+
if method == "idw_m":
|
|
92
|
+
print("IDW-MT")
|
|
93
|
+
return IDWOpm3D() if dim == 3 else IDWOpm()
|
|
94
|
+
|
|
95
|
+
# Kriging (克里金插值)
|
|
96
|
+
if method == "kriging":
|
|
97
|
+
return Kriging3D() if dim == 3 else Kriging2D()
|
|
98
|
+
|
|
99
|
+
if method == "kriging_m":
|
|
100
|
+
return KrigingOpm3D() if dim == 3 else KrigingOpm()
|
|
101
|
+
|
|
102
|
+
# RBF (径向基函数插值)
|
|
103
|
+
if method == "rbf":
|
|
104
|
+
return RBF3D() if dim == 3 else RBF2D()
|
|
105
|
+
|
|
106
|
+
# 最近邻插值
|
|
107
|
+
if method == "nearest":
|
|
108
|
+
return NearestNeighbor3D() if dim == 3 else NearestNeighbor2D()
|
|
109
|
+
|
|
110
|
+
# K最近邻插值
|
|
111
|
+
if method == "knearest":
|
|
112
|
+
return KNearestNeighbor()
|
|
113
|
+
|
|
114
|
+
# 线性插值系列
|
|
115
|
+
if method == "linear":
|
|
116
|
+
if dim == 1:
|
|
117
|
+
return LinearInterpolator()
|
|
118
|
+
elif dim == 2:
|
|
119
|
+
return BilinearInterpolator()
|
|
120
|
+
elif dim == 3:
|
|
121
|
+
return Trilinear3D()
|
|
122
|
+
else:
|
|
123
|
+
raise ValueError(f"线性插值不支持 {dim} 维")
|
|
124
|
+
|
|
125
|
+
# 双线性插值 (2D专用)
|
|
126
|
+
if method == "bilinear":
|
|
127
|
+
if dim != 2:
|
|
128
|
+
raise ValueError("双线性插值只支持2D数据")
|
|
129
|
+
return BilinearInterpolator()
|
|
130
|
+
|
|
131
|
+
# 三线性插值 (3D专用)
|
|
132
|
+
if method == "trilinear":
|
|
133
|
+
if dim != 3:
|
|
134
|
+
raise ValueError("三线性插值只支持3D数据")
|
|
135
|
+
return Trilinear3D()
|
|
136
|
+
|
|
137
|
+
# 可用的方法列表
|
|
138
|
+
available_methods = [
|
|
139
|
+
"idw",
|
|
140
|
+
"idw_m",
|
|
141
|
+
"kriging",
|
|
142
|
+
"kriging_m",
|
|
143
|
+
"rbf",
|
|
144
|
+
"nearest",
|
|
145
|
+
"knearest",
|
|
146
|
+
"linear",
|
|
147
|
+
"bilinear",
|
|
148
|
+
"trilinear",
|
|
149
|
+
]
|
|
150
|
+
|
|
151
|
+
raise ValueError(
|
|
152
|
+
f"不支持的方法: {method}。当前可用的方法: {', '.join(available_methods)}"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
# endregion 插值器
|
|
157
|
+
|
|
158
|
+
__all__ = [
|
|
159
|
+
"IDW2D",
|
|
160
|
+
"IDW3D",
|
|
161
|
+
"IDW",
|
|
162
|
+
"NearestNeighbor2D",
|
|
163
|
+
"NearestNeighbor3D",
|
|
164
|
+
"KNearestNeighbor",
|
|
165
|
+
"RBF2D",
|
|
166
|
+
"RBF3D",
|
|
167
|
+
"Trilinear3D",
|
|
168
|
+
"BilinearInterpolator",
|
|
169
|
+
"LinearInterpolator",
|
|
170
|
+
"Kriging2D",
|
|
171
|
+
"Kriging3D",
|
|
172
|
+
"Kriging3DUn",
|
|
173
|
+
"MIDW",
|
|
174
|
+
"IDWOpm",
|
|
175
|
+
"IDWOpm3D",
|
|
176
|
+
"KrigingOpm",
|
|
177
|
+
"KrigingOpm3D",
|
|
178
|
+
]
|