在自然科学领域研究中,数据预处理往往决定了模型的上限。与商业数据不同,科研数据具有独特的复杂性和挑战性。以气象数据为例,我们经常需要处理来自不同观测站点的多源异构数据,这些数据可能包含仪器误差、传输丢失和人为记录错误等多种问题。
科研数据首先需要明确其测量尺度:
特别注意:不同尺度的数据需要采用不同的统计方法和模型处理。错误地将名义变量当作连续变量处理会导致严重的模型偏差。
时空数据结构在环境科学中尤为常见:
python复制# 典型时空数据表示示例
import xarray as xr
ds = xr.Dataset(
{
"temperature": (["time", "lat", "lon"], temp_data),
"precipitation": (["time", "lat", "lon"], precip_data)
},
coords={
"time": pd.date_range("2020-01-01", periods=365),
"lat": np.arange(-90, 90, 0.5),
"lon": np.arange(-180, 180, 0.5)
}
)
多重插补(Multiple Imputation)是处理科研数据缺失值的黄金标准:
对于气象数据中的异常值检测,我推荐使用基于物理约束的方法:
python复制def physical_constraint_check(temp, humidity):
"""基于气象学原理的异常值检测"""
invalid = (
(temp < -90) | (temp > 60) |
(humidity < 0) | (humidity > 100) |
((temp > 50) & (humidity > 90)) # 不符合实际的气象条件
)
return invalid
在生态学研究中,我经常构造以下特征:
实战经验:对于时间序列数据,滞后特征(lagged features)往往比原始值更具预测力。但在构建滞后特征时,务必注意避免数据泄露。
在科研建模中,单一的准确率指标远远不够。以气候变化预测为例,我们需要关注:
| 评估维度 | 适用指标 | 科学意义 |
|---|---|---|
| 预测精度 | RMSE, MAE | 预测值与实际观测的接近程度 |
| 不确定性 | PICP, MPIW | 预测区间是否覆盖真实值 |
| 物理一致性 | 自定义约束 | 是否符合热力学定律等物理原理 |
| 可解释性 | SHAP值 | 变量贡献是否符合领域知识 |
时空数据的交叉验证需要特殊设计:
python复制from sklearn.model_selection import TimeSeriesSplit
tss = TimeSeriesSplit(
n_splits=5,
gap=30, # 避免相邻折叠间的信息泄露
test_size=90 # 90天的测试窗口
)
贝叶斯方法可以自然地表征参数不确定性:
python复制import pymc3 as pm
with pm.Model() as climate_model:
# 先验分布
alpha = pm.Normal("alpha", mu=0, sigma=10)
beta = pm.Normal("beta", mu=0, sigma=10, shape=3)
# 似然函数
mu = alpha + pm.math.dot(X, beta)
pm.Normal("y", mu=mu, sigma=sigma, observed=y)
# MCMC采样
trace = pm.sample(2000, tune=1000)
注意事项:贝叶斯模型的计算成本较高,对于大规模数据集可考虑变分推断(VI)作为近似方法。
PCA在遥感图像处理中效果显著:
python复制from sklearn.decomposition import PCA
# 多光谱影像降维
pca = PCA(n_components=0.95) # 保留95%方差
X_pca = pca.fit_transform(X)
# 可视化主成分载荷
plt.imshow(pca.components_[0].reshape(64, 64), cmap="viridis")
NMF特别适合环境污染物源解析:
python复制from sklearn.decomposition import NMF
model = NMF(n_components=3, init="nndsvda", max_iter=1000)
W = model.fit_transform(X) # 源成分谱
H = model.components_ # 贡献矩阵
EMD处理非平稳气候信号:
python复制from PyEMD import EMD
emd = EMD()
IMFs = emd(temperature_series)
# 可视化本征模态函数
for i, imf in enumerate(IMFs):
plt.subplot(len(IMFs), 1, i+1)
plt.plot(imf)
python复制import pywt
# 小波变换参数选择
scales = np.arange(1, 128)
wavelet = "morl"
# 连续小波变换
coefficients, frequencies = pywt.cwt(series, scales, wavelet)
# 小波功率谱
power = (abs(coefficients)) ** 2
研究厄尔尼诺与印度洋偶极子的关系:
python复制from mlxtend.plotting import plot_wavelet_coherence
# 计算小波相干性
wcoh = plot_wavelet_coherence(
enso_series, iod_series,
scales=scales,
wavelet="morl"
)
python复制from statsmodels.regression.quantile_regression import QuantReg
model = QuantReg(y, X)
result = model.fit(q=0.95) # 预测95%分位数
python复制from statsmodels.discrete.count_model import ZeroInflatedPoisson
model = ZeroInflatedPoisson(
endog=species_count,
exog=environment_factors,
exog_infl=sampling_effort
)
results = model.fit()
python复制from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor(
n_estimators=500,
max_features="sqrt", # 对于高维数据
min_samples_leaf=5, # 防止过拟合
oob_score=True # 使用袋外样本评估
)
rf.fit(X, y)
# 特征重要性可视化
pd.Series(rf.feature_importances_, index=X.columns).plot.barh()
python复制import xgboost as xgb
from sklearn.model_selection import RandomizedSearchCV
param_dist = {
"learning_rate": [0.01, 0.05, 0.1],
"max_depth": [3, 5, 7],
"subsample": [0.6, 0.8, 1.0],
"colsample_bytree": [0.6, 0.8, 1.0]
}
xgb_model = xgb.XGBRegressor(objective="reg:squarederror")
search = RandomizedSearchCV(xgb_model, param_dist, n_iter=50, cv=5)
search.fit(X, y)
python复制import shap
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)
# 可视化单个预测解释
shap.force_plot(explainer.expected_value, shap_values[0,:], X.iloc[0,:])
python复制from sklearn.inspection import plot_partial_dependence
plot_partial_dependence(
model, X, features=["temperature", "precipitation"],
grid_resolution=20
)
python复制from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import ConvLSTM2D, BatchNormalization
model = Sequential([
ConvLSTM2D(
filters=64, kernel_size=(3, 3),
input_shape=(None, 64, 64, 1),
padding="same", return_sequences=True
),
BatchNormalization(),
# 更多层...
])
python复制from transformers import TimeSeriesTransformerModel
model = TimeSeriesTransformerModel(
input_size=128,
decoder_input_size=128,
output_size=1,
n_head=8,
dim_feedforward=512
)
python复制from pykrige.ok import OrdinaryKriging
OK = OrdinaryKriging(
x_coords, y_coords, values,
variogram_model="spherical"
)
z, ss = OK.execute("grid", gridx, gridy)
python复制class SpatioTemporalAttention(nn.Module):
def __init__(self, channels, reduction=8):
super().__init__()
self.temporal_attention = TemporalAttention(channels, reduction)
self.spatial_attention = SpatialAttention(channels, reduction)
def forward(self, x):
x = self.temporal_attention(x)
x = self.spatial_attention(x)
return x
python复制import tensorflow_model_optimization as tfmot
prune_low_magnitude = tfmot.sparsity.keras.prune_low_magnitude
model_for_pruning = prune_low_magnitude(
original_model,
pruning_schedule=tfmot.sparsity.keras.ConstantSparsity(0.5, 0)
)
python复制from river import ensemble
from river import preprocessing
from river import tree
model = ensemble.AdaptiveRandomForestClassifier(
n_models=10,
drift_detector=preprocessing.HoeffdingTreeClassifier()
)
for x, y in stream:
model.learn_one(x, y)
y_pred = model.predict_one(x)
在长期的气象建模实践中,我发现模型性能的瓶颈往往不在于算法本身,而在于数据质量和特征工程。特别是在处理长期气候数据时,必须特别注意数据的一致性检查和标准化处理。另一个关键点是模型的可解释性——在科研领域,一个能被领域专家理解的简单模型,往往比黑箱的复杂模型更有价值。