在最近的数据清洗工作中,我遇到了一批存在严重缺失值的长序列空间流动数据。尤其是在构建跨度较长的地级市级别数据集时,某些特定年份或特定节点的数据存在大面积空白。
如果直接剔除这些缺失行,会导致样本量骤降;如果使用简单的均值填补,又会完全破坏空间流动数据的拓扑结构和比例关系。经过查阅文献,我决定采用**迭代比例拟合(Iterative Proportional Fitting, 简称 IPF)**方法来进行数据插补。
今天记录一下在使用 Python 实现 IPF 算法时踩过的一些坑,特别是关于输出偏差和零值处理的问题。
1. 什么是 IPF?
IPF 最初是统计学中用于调整二维或多维列联表(Contingency Table)边缘分布的方法。简单来说,当我们已知一个矩阵的内部结构(比如历史基准年份的流动比例),同时又知道当前年份的总流出量(行和)与总流入量(列和)时,IPF 可以通过不断交替调整行比例和列比例,逼近真实的内部流动矩阵。
2. Python 核心实现逻辑
在 Python 中,通常不需要手写死循环,利用 numpy 和 pandas 的矩阵运算可以极大地提升效率。以下是一个简化的核心逻辑:
import numpy as np
import pandas as pd
def apply_ipf(seed_matrix, target_row_margins, target_col_margins, tolerance=1e-5, max_iter=1000):
"""
seed_matrix: 历史基准矩阵 (2D numpy array)
target_row_margins: 目标行和 (1D numpy array)
target_col_margins: 目标列和 (1D numpy array)
"""
matrix = seed_matrix.copy().astype(float)
for iteration in range(max_iter):
# 1. 调整行比例
current_row_margins = matrix.sum(axis=1)
# 避免除以零
current_row_margins[current_row_margins == 0] = 1
row_multipliers = target_row_margins / current_row_margins
matrix = matrix * row_multipliers[:, np.newaxis]
# 2. 调整列比例
current_col_margins = matrix.sum(axis=0)
current_col_margins[current_col_margins == 0] = 1
col_multipliers = target_col_margins / current_col_margins
matrix = matrix * col_multipliers
# 3. 检查收敛性
row_diff = np.abs(matrix.sum(axis=1) - target_row_margins).max()
col_diff = np.abs(matrix.sum(axis=0) - target_col_margins).max()
if row_diff < tolerance and col_diff < tolerance:
print(f"IPF converged in {iteration} iterations.")
return matrix
print("Warning: IPF did not converge reach max iterations.")
return matrix
3. 遇到的坑与解决方案
在将上述基础逻辑应用到真实的省市级数据时,我遇到了两个主要问题:
问题一:结构性零值(Structural Zeros)导致输出偏差
在真实地理数据中,某些城市之间由于物理阻隔或政策原因,流动量本身就是绝对的 0。如果基准矩阵(Seed Matrix)中该位置为 0,无论 IPF 怎么乘,结果永远是 0。 解决办法: 在初始化矩阵时,需要严格区分“真实的 0”和“缺失的 0”。对于可能存在流动的缺失位置,可以赋予一个极小的平滑常数(如 1e-9)作为先验,确保迭代能够进行。
问题二:边缘和不一致导致无法收敛
由于统计口径的问题,有时候从宏观年鉴上获取的“总流出”之和,并不等于“总流入”之和。如果 sum(target_row_margins) != sum(target_col_margins),IPF 算法将永远在两端震荡,无法收敛。 解决办法: 在输入算法前,必须先进行数据对齐(Reconciliation),通常按比例将较小的一方缩放至与较大的一方总量一致。
总结
IPF 是一个非常经典且有效的空间数据推算工具。结合 pandas 的高维分组运算,可以快速完成长序列数据集的清洗工作。接下来我计划对比一下 IPF 与基于重力模型(Gravity Model)推算结果的差异,看看在长尾分布的特征下哪种表现更好。