news 2026/9/11 22:48:38

迁徙指数数据获取与分析:从Python抓取到时间序列挖掘

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
迁徙指数数据获取与分析:从Python抓取到时间序列挖掘

简介:迁徙指数数据包源自百度迁徙平台,覆盖2022年1月1日至5月13日,并附带2021年全年及2019、2020年部分历史数据。面向研究人口流动、城市网络与疫情防控政策的科研人员、政府机构及商业分析者,可用来分析城际迁徙强度、迁入迁出峰值与趋势变化,验证城市吸引力及社会经济活动等研究假设。数据包共10个文件,主体为8个开放式XML工作表与2个关系定义文件,压缩包大小3.07MB;工作表内应包含日期、城市、迁入指数、迁出指数等字段,可结合Excel/Pandas/R等工具做清洗、折线图绘制与关联分析,提取不同时段、区域的迁徙特征。这些数据对理解节假日人口迁移规律与区域管控效果尤其有帮助。目前已有238人浏览学习,适合需要获取跨年度人口流动样本的课题或行业应用场景。

1. 迁徙指数数据(截止2022.5.13)真正值钱的是时间边界

这个标题看起来像一份静态表格,实际上背后是一整套人口流动观测体系。移动互联网时代,百度迁徙、腾讯位置大数据、联通智慧足迹这类平台通过位置服务与手机信令,把一座城市每天迁入迁出的规模换算成指数对外发布。这个指数的量纲不是"人次",而是相对于基准日的归一化强度,直接拿两个城市或两个年份的数值比较,必须先确认口径。截止2022.5.13这个时间点,让数据变成冻结快照,之后上游平台无论怎么调整算法,这份切片都不会再变,这对历史回溯和模型回测来说是最理想的性质。下面按"对齐口径、抓取数据、清洗落库、分析调参、质量校核"的顺序展开,适合每天跟迁徙数据打交道的分析师和数据工程师。

2. 迁徙指数数据的字段口径与抓取参数

2.1 迁徙指数是相对强度,不是真实客流

迁徙指数的原始数据来自用户授权的位置上报、基站切换和 Wi-Fi 探针,平台方把一次完整的跨城市移动识别为一次"迁徙事件"。但直接暴露真实人次既涉及隐私,也会因为各平台覆盖用户比例不同而产生口径差异,所以对外发布的统一是归一化指数。常见的做法是选定一个基准日,把该日的迁徙事件数定义为 100,其他日期按比例换算。举例来说,某城市迁入指数为 120,意思是当日迁入事件数比基准日多了两成,而不是有 120 个人进城。

理解了这一点,就能避开两个常见错误。第一,不同平台的指数不能直接混用,因为它们的用户池和基期不同,A 平台的 120 和 B 平台的 120 没有可比性。第二,指数可以在同一个平台内部做时间趋势比较,但不能把一年 365 天的指数直接加总当作年度客流总量,这是量纲问题,不是计算精度问题。拿到"截止2022.5.13"的数据集时,第一步不是看数字,而是确认这份数据的来源平台和基期规则,否则后续所有报表都建立在不可比的基础上。

2.2 cityrank.jsonp 接口的关键参数与最小抓取代码

百度迁徙的cityrank接口是公开可访问的,返回格式为 JSONP。用 Python 抓取时先做一层解包,把回调函数名剥掉,再交给标准库解析。

import json import pandas as pd import requests def fetch_city_rank(date_str: str, city_id: str, move_type: str = "move_in", scope: str = "nationwide") -> pd.DataFrame: """抓取指定日期的城市级迁徙排行。 date_str: 日期字符串,格式为 YYYYMMDD,例如 20220513 city_id: 目标城市行政区划编码,例如 110000 表示北京 move_type: move_in 表示迁入目标城市,move_out 表示迁出 scope: 统计范围,nationwide 表示全国范围内统计 """ url = "https://huiyan.baidu.com/migration/cityrank.jsonp" params = { "dt": "city", "id": city_id, "date": date_str, "scope": scope, "type": move_type, } resp = requests.get(url, params=params, timeout=15) text = resp.text # 返回体形如 b({...}),截取第一个左括号到最后一个右括号之间的 JSON payload = json.loads(text[text.index("(") + 1: text.rindex(")")]) rows = payload["data"]["list"] return pd.DataFrame(rows)

这段代码把参数集中在params字典里,方便后续换成批量参数组合。dt=city表示按城市维度聚合,如果不传这个参数,部分版本会返回全国总量或按省份聚合,字段结构完全不同。type决定方向:move_in返回的是从哪些城市迁入到目标城市,move_out返回的是目标城市的人迁往了哪些城市。接口返回的list中通常包含城市名、城市编码和指数值,城市编码在后续清洗时统一补齐 6 位,避免 10000 和 100000 被当成同一座城市。

参数示例值作用
dtcity聚合粒度,city 为城市级
id110000目标城市区划编码
date20220513查询日期,精确到天
scopenationwide统计范围,固定传 nationwide 即可
typemove_in / move_out迁徙方向,决定返回结果含义

请求频率要控制,连续抓取时每两次请求至少间隔 0.5 秒。接口并没有承诺不限流,短时间内高并发容易触发验证页,返回的内容不再是 JSONP 而是一段 HTML,此时json.loads会直接抛异常。把这一层异常捕获放到批量任务里,单个日期抓取失败只记录日志,不中断整个任务。

2.3 截止 2022.5.13 隐含的时间序列特征

2022 年 5 月 13 日是星期五,往前推两周是五一假期。迁徙指数在假期前后呈现出非常典型的"节前集中迁出、节后集中迁入"形态,而 5 月 13 日已经回到常规通勤节奏,周内周期开始主导:周一至周五迁出大于迁入,周末相反。这个日期切片适合用来研究"静态时段特征",但不适合用来推断全年规律,因为季节性和节假日效应在这份截断数据里只覆盖了冬季到春末这一段。

另一个容易忽略的点是,截止 2022.5.13 意味着数据不是流式追加的。做预测模型时,只能用 5 月 13 日及之前的数据做训练,之后的真实值没有出现在数据集中,这天然规避了数据泄漏。很多时间序列项目所谓的验证集漂移,在这个固定切片上根本不存在,这是它做回测实验的天然优势。

3. 用 Python 把迁徙指数数据落成本地时间序列

3.1 批量抓取时如何对日期循环与异常续跑

单日抓取只是验证接口连通性,真正做分析要连续抓取至少 90 天。把日期列表传给循环函数,每个日期单独调用fetch_city_rank,抓到的数据先暂存内存,全部完成后统一合并。

import time from pathlib import Path def fetch_period(date_list, city_id, move_type, interval: float = 0.5, retry: int = 2) -> pd.DataFrame: frames = [] for day in date_list: for attempt in range(retry + 1): try: df = fetch_city_rank(day, city_id, move_type) df["date"] = day frames.append(df) break except Exception as exc: print(f"{day} 第 {attempt + 1} 次抓取失败: {exc}") time.sleep(interval * (attempt + 1)) time.sleep(interval) return pd.concat(frames, ignore_index=True)

这段代码把失败重试和限速合并在一起。retry控制每个日期的最大尝试次数,第一次失败后等待 0.5 秒,第二次失败等待 1 秒,重试仍失败就跳过该日期。设计上要容忍局部缺失,因为后续清洗阶段会专门处理空窗日期。抓取结束后立刻把原始数据落盘,不要只留在内存里,常见的做法是保存成 parquet 文件并带上抓取时间戳,避免因进程崩溃而重新抓一遍。

3.2 清洗时必须统一日期、城市编码和重复值

线上接口返回的城市名存在同名问题,比如"吉林"既是省名也是市名,"朝阳"在辽宁和北京都存在。清洗时不能只按城市名去重,必须以城市编码为唯一键。下面这段清洗逻辑覆盖了三个高频问题:日期格式转换、城市编码补零、按城市和日期去重。

def normalize_migration(df: pd.DataFrame) -> pd.DataFrame: df = df.copy() # 日期列统一成 datetime 类型 df["date"] = pd.to_datetime(df["date"], format="%Y%m%d") # 城市编码补齐 6 位,避免 1100 和 110000 被当成不同城市 df["city_code"] = df["city_code"].astype(str).str.zfill(6) # 部分接口版本带 province 字段,用它做城市名消歧 if "province" in df.columns: df["city_name"] = df["province"] + "·" + df["city_name"] # 同一城市同一天只保留一条记录 df = df.drop_duplicates(subset=["date", "city_code", "city_name"]) return df.sort_values(["city_code", "date"]).reset_index(drop=True)

清洗的关键不在于代码量,而在于排序和去重的键选择。drop_duplicates如果不指定subset,会因为接口返回的排名列表中城市名重复而误删有效数据。排序用["city_code", "date"],保证后面做groupby时每个城市的时间序列是顺序排列的,否则算环比时前后颠倒,结果没有意义。清洗后要检查每个城市的日期覆盖天数,如果目标城市 90 天数据里只有 60 天记录,说明中间有抓取失败或接口屏蔽,需要补抓。

3.3 以宽表还是长表落库

分析场景不同,表结构完全不同。趋势分析适合长表,一行一个城市一天的数值;聚类和相关性分析适合宽表,每行一个城市、每列一个日期。落库时我一般直接建长表,分析时再透视成宽表,这样保留最大灵活性。

CREATE TABLE migration_index ( date Date, city_code String, city_name String, move_in Float32 COMMENT '迁入指数', move_out Float32 COMMENT '迁出指数', dt String DEFAULT '2022-05-13' COMMENT '数据快照截止时间' ) ENGINE = MergeTree() PARTITION BY toYYYYMM(date) ORDER BY (city_code, date);

表结构里特意加了dt字段记录数据快照截止时间,这是这类固定切片数据集最容易忽略的元数据。同一张表以后可能追加新批次数据,没有dt列就无法区分哪些行属于 2022.5.13 之前的旧切片。ORDER BY(city_code, date),让同一个城市的数据在存储上连续,查询单城市时间序列时只需要扫一个分区段,不需要全表扫描。PARTITION BY toYYYYMM(date)按月分区,删除某个月的数据直接 drop 分区即可。

4. 迁徙指数数据的分析玩法与参数调优

4.1 用净迁入率替代原始指数做城市吸引力对比

原始迁徙指数受城市人口基数影响极大,北京和一座三线城市的迁入指数不在同一量级,直接对比无法体现"相对吸引力"。常见做法是把同一城市同一天的迁入和迁出放在一起计算净迁入率,消除城市规模带来的偏差。

def add_net_ratio(df: pd.DataFrame) -> pd.DataFrame: df = df.copy() total = df["move_in"] + df["move_out"] # 净流入率,范围在 [-1, 1] 之间 df["net_ratio"] = (df["move_in"] - df["move_out"]) / total.replace(0, pd.NA) return df

净迁入率为正说明当天人口净流入,为负说明净流出,接近 0 说明双向流动均衡。分母用迁入加迁出的总和而不是城市常住人口,因为迁徙指数本身是相对值,两个相对值做除法时作为基准的比例效应会被抵消。这个指标对数值的高低不敏感,更适合跨城市横向比较。

4.2 同日同环比参数怎么选才不踩周内周期

迁徙指数有很强的星期周期性:工作日的迁出指数普遍高于周末,高铁和航班时刻表也强化了这种规律。直接拿 5 月 13 日和前一天的 5 月 12 日做环比,两个都是工作日,结果相对平稳;但如果拿 5 月 13 日(周五)和 5 月 12 日(周四)比完,再拿 5 月 14 日(周六)和 5 月 13 日比,数值会出现剧烈波动,这不是突发事件,只是周期性。

# 日环比:反映短期波动,但会受周内周期干扰 df["dod"] = df.sort_values("date")["move_in"].pct_change(1) # 周同比:消除星期效应,适合观察真实趋势变化 df["wow"] = df.sort_values("date")["move_in"].pct_change(7) # 年同比:需要至少 1 年数据,季节效应被完全消除 df["yoy"] = df.sort_values("date")["move_in"].pct_change(365)
对比类型窗口长度适用场景
日环比1 天突发事件检测、政策影响评估
周同比7 天常规趋势分析,推荐首选
年同比365 天长期结构性变化,需要满一年数据

参数选择上,pct_change(7)是处理迁徙数据最稳妥的起点。它把每个周五和上周五相比,两个同类星期几做差,周内周期被剔除。如果拿着截止 2022.5.13 的数据只算日环比,会出现大量虚高的波动峰值,分析结论很容易做反。

4.3 用 KMeans 聚类识别城市流动模式时先做标准化

城市迁徙序列的形态比绝对值更有分析价值。有的城市全年迁出平稳,只在春节前后出现尖峰;有的城市在暑期出现持续两个月的迁出抬升。把这两种城市都丢进聚类算法,如果不做标准化,平稳城市的数值差异会被尖峰城市的极值淹没,聚类结果几乎完全由人口规模决定。

from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler def cluster_cities(df: pd.DataFrame, n_clusters: int = 4): # 透视成宽表:行是城市,列是日期 pivot = df.pivot_table(index="city_code", columns="date", values="move_in") # 每个城市的序列独立标准化,消除规模差异 scaler = StandardScaler() X = scaler.fit_transform(pivot.fillna(pivot.median())) model = KMeans(n_clusters=n_clusters, random_state=42, n_init=10) labels = model.fit_predict(X) return pivot.index, labels

StandardScaler对每一列做标准化,但在宽表里每一列是一个日期,标准化后每个日期的均值变为 0,实际是把所有城市在单日的水平差异抹平。聚类算法由此关注的是城市序列的形态相似性,而不是数值高低。n_init=10是 KMeans 的常规设定,防止单次初始化落入局部最优;如果隐式聚类数量不清楚,用轮廓系数遍历 2 到 6 选一个曲率拐点,比直接拍脑袋定 4 更有说服力。

5. 用节假日效应快速校核迁徙指数数据质量

拿到外部数据集,先别急着建模,用已知的节假日效应反向验证数据可靠性,成本最低。2022 年 5 月 13 日前最近的大型节假日是五一劳动节,节前最后一个工作日 2022.4.29 的迁出指数应当明显高于前后一周的均值,迁入大省如广东、浙江还应该在节后 5.4 到 5.5 出现迁入反弹。如果数据集里看不到这两个峰,先说数据有问题,别先怀疑业务逻辑。

def check_holiday_signal(s: pd.Series, holiday: str, pre_days: int = 3): """检查指定日期前是否出现迁徙强度尖峰。""" s = s.sort_index() holiday = pd.Timestamp(holiday) pre_window = s.loc[holiday - pd.Timedelta(days=pre_days): holiday] threshold = s.median() * 1.5 if pre_window.max() < threshold: print(f"警告: {holiday.date()} 节前未出现超过中位数 1.5 倍的迁徙尖峰") return False return True

阈值的选取不用太严格,迁徙指数在节假日前通常会上升到日常中位数的 2 倍以上,取 1.5 倍已经能过滤大部分误判。这段校验不需要每一天都看,每天只取迁出指数的最大值,所以速度很快,300 天数据十秒钟内能跑完。

第二个校核手段是双源交叉验证。如果手里只有百度迁徙的 2022.5.13 截止数据,可以抓取同一天的腾讯迁徙指数,虽然两者绝对数值不同,但同方向的变化趋势应当高度相关。把两个来源按城市对齐后计算 Spearman 相关系数,正常城市之间相关系数在 0.8 以上,低于 0.5 的城市要么是数据缺失导致对齐错位,要么是抓取时日期参数串了。相关系数矩阵不需要做完整版,只抽查迁入迁出排名前 20 的城市,半小时就能定位全链路中哪一环出了问题。

最后一个常用校核手段是周期性自洽检查。固定切片下做不了回测,但能验证数据是否满足星期周期:同一个城市任意相邻两周的同一星期几,迁出指数差值的绝对值不应普遍超过 50%。逐城市计算diff的标准差,如果超过这个阈值,大概率是混入了其他日期或城市的数据,回到第 3 章的drop_duplicatessort_values重新核对。这一套校核做完,数据质量就有底了,再往后无论做城市群识别还是节假日客流预测,前提都是同一份可信的时间序列。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 22:45:32

Matlab三维蚁群路径规划实战:从点云到避障航迹

简介&#xff1a;本资源是一套面向本科及硕士阶段教研学习的蚁群算法三维路径规划实践方案&#xff0c;聚焦智能优化算法在三维空间路径规划中的工程实现&#xff0c;特别适用于无人机、水下潜器等移动平台的轨迹优化教学与仿真实验。压缩包共20个文件&#xff0c;含7个核心MAT…

作者头像 李华
网站建设 2026/9/11 22:38:50

YOLOv8玉米叶病害检测与PyQt界面封装:从数据集训练到桌面应用

简介&#xff1a;面向玉米叶病害检测这一实际应用场景&#xff0c;这套资料将YOLOv8模型权重、PyQt图形界面与1500张标注图片整合在一起&#xff0c;既适合刚接触目标检测的初学者完成入门实验&#xff0c;也方便农业智能化方向的开发者、算法研究者直接复用模型与数据。压缩包…

作者头像 李华
网站建设 2026/9/11 22:38:18

谷粒商城本地部署全攻略:从课件到可运行微服务项目的完整实践

简介&#xff1a;面向微服务电商项目学习者的谷粒商城配套课件合集&#xff0c;覆盖从入门到实战的完整知识链路&#xff0c;尤其适合准备面试、做项目复盘或梳理分布式体系的开发者。内容按基础篇、高级篇、运维篇组织&#xff1a;基础篇讲解项目环境搭建、SpringCloud组件、前…

作者头像 李华
网站建设 2026/9/11 22:38:11

手写决策树:从信息增益到预剪枝后剪枝的Python实现

简介&#xff1a;围绕《机器学习》&#xff08;西瓜书&#xff09;第四章决策树&#xff0c;这份资源提供基于信息熵与基尼指数的决策树算法Python实现&#xff0c;适合正在阅读该书并希望动手实践的机器学习初学者、高校学生及研究人员。压缩包共9个文件&#xff0c;含4个Pyth…

作者头像 李华