外观
局部莫兰指数
支持多时期局部 Moran’s I、显著空间集聚象限汇总与按需明细。
核心代码
py
def _fit_local_moran(self, *, decimals: int, title: str) -> None:
prepared = self._prepare_panel(require_x=False)
raw_permutations = self.spatial_options.get('moran_permutations')
permutations = 999 if raw_permutations is None else max(0, min(int(raw_permutations), 999))
seed = int(self.spatial_options.get('moran_seed') or 5282026)
rng = np.random.default_rng(seed)
selected_times = self._resolve_local_moran_times(
self.spatial_options.get('moran_local_times'),
prepared['times'],
)
show_details = bool(self.spatial_options.get('moran_show_details', False))
local_rows: list[dict[str, Any]] = []
summary_rows: list[dict[str, Any]] = []
for time_value in selected_times:
time_index = prepared['times'].index(time_value)
values = prepared['y'][time_index]
if np.nanstd(values) <= 1e-12:
summary_rows.append({
'time': time_value,
'entities': len(values),
'significant': 0,
'hh': 0,
'll': 0,
'hl': 0,
'lh': 0,
'note': _('该时期变量没有横截面变异,已跳过'),
})
continue
period_rows = self._local_moran(
values,
self.weight_matrix,
prepared['entities'],
permutations,
rng,
)
for row in period_rows:
row['time'] = time_value
row['significant'] = bool(np.isfinite(row['p']) and row['p'] < 0.05)
significant_rows = [row for row in period_rows if row['significant']]
summary_rows.append({
'time': time_value,
'entities': len(period_rows),
'significant': len(significant_rows),
'hh': sum(row['quadrant'] == 'HH' for row in significant_rows),
'll': sum(row['quadrant'] == 'LL' for row in significant_rows),
'hl': sum(row['quadrant'] == 'HL' for row in significant_rows),
'lh': sum(row['quadrant'] == 'LH' for row in significant_rows),
'note': '',
})
local_rows.extend(period_rows)
scatter = self._moran_scatter_image(values, time_value)
if scatter:
self.chart_images.append(scatter)
self.model_stats = {
'N': int(prepared['n'] * len(selected_times)),
'Groups': int(prepared['n']),
'Periods': int(len(selected_times)),
}
self.result_payload = {
'local_moran_summary': summary_rows,
'local_moran': local_rows,
'selected_times': selected_times,
'show_details': show_details,
'alignment_report': self.alignment_report,
'seed': seed,
'permutations': permutations,
}
self.custom_html = self._render_local_moran_html(
summary_rows,
local_rows,
show_details,
decimals,
title,
)
self.raw_output = json_like_text(self.result_payload)