资讯详情

基于经济指标的旅游需求预测:从数据探索到滚动验证的完整链路

📅 2026/10/12 12:20:57 | 华诺云谱 👁 阅读
基于经济指标的旅游需求预测:从数据探索到滚动验证的完整链路
简介这份资源面向具备一定机器学习与Python基础的数据分析学习者围绕旅游与经济指标之间的关联展开完整实战。内容以全球旅游经济数据为对象覆盖探索性数据分析、特征标准化、时间序列建模与多模型回归预测等环节帮助读者理解如何从真实数据中挖掘旅游对经济的影响规律。压缩包共9个文件包含7个py源代码、1个csv数据集与1个txt说明文件整体约283KB其中数据集约665.76KB代码约44.34KB结构清晰便于按模块学习。代码手工整理、无语法错误且可直接运行涉及pandas、seaborn、statsmodels、sklearn、xgboost、geopandas等常用库涵盖ARIMA、指数平滑、随机森林、梯度提升、SVR、KMeans聚类及t检验等方法。已有40人学习下载适合希望系统掌握旅游经济数据分析与预测流程的读者参考复用。1. 旅游和经济指标关系数据集分析预测从一张 Excel 到可复现的预测链路手里拿到一份「旅游和经济指标关系数据集分析预测」的压缩包里面躺着 7 个源代码文件和 665.76 KB 的数据集第一反应往往不是兴奋而是犯嘀咕这点数据量能跑出什么名堂我一开始也这么想直到把旅游人次、GDP、居民可支配收入、CPI、汇率这几列摊开才发现它真正值钱的地方不在体量而在结构——它把宏观经济的几个关键指标和旅游这个具体行业绑在了一起天然适合做「指标驱动预测」的实战演练。这类数据集分析预测的活儿核心不是把模型调到多高精度而是搞清楚经济指标怎么影响旅游需求、哪些指标是领先信号、哪些只是噪声。适合已经会写 Python、跑过 sklearn 或 statsmodels但没系统做过「经济指标 行业预测」这条链路的人。下面我按自己复现的顺序把选型、代码、参数和踩过的坑讲清楚。2. 先搞懂数据结构和预测目标别急着上模型2.1 665.76 KB 里到底装了什么拿到数据集先别写模型用 pandas 把结构摸清楚。旅游和经济指标关系这类数据常见形态是「时间 地区 指标列」的宽表665.76 KB 大概对应几千行、十几列的量级。我一般先跑一段探查代码把列类型、缺失、时间跨度一次性看清楚。import pandas as pd # 读取数据集先不指定 dtype让 pandas 自己推断 df pd.read_csv(tourism_economy.csv) # 基础结构行数、列数、每列类型 print(df.shape) print(df.dtypes) # 时间列单独看确认粒度和跨度 df[date] pd.to_datetime(df[date]) print(df[date].min(), df[date].max()) print(df[date].dt.to_period(M).nunique()) # 月度粒度有多少期 # 缺失和描述统计 print(df.isnull().sum()) print(df.describe().T[[mean, std, min, max]])这段代码的逻辑是先确认「有多少行、什么类型、时间跨度多长」再决定后面能不能做时间序列。参数上to_datetime一定要显式调用否则日期列会被当成字符串后面做滞后特征会直接翻车。describe().T转置是为了让指标名在行上方便一眼扫完。如果发现时间跨度不到 3 年、月度数据不足 36 期那季节性分解和 ARIMA 这类方法就要慎用样本太短参数估计不稳。2.2 预测目标怎么定旅游人次还是旅游收入这一步决定了后面所有特征工程的方向。旅游和经济指标关系数据集里通常同时有「旅游人次」和「旅游收入」两列。我的经验是如果数据里有人均消费或客单价优先预测人次因为人次对经济指标的响应更直接、更少受价格波动干扰如果只有收入那就预测收入但要把 CPI 作为解释变量放进去否则通胀会把趋势带偏。选目标时还要看它和候选经济指标的相关系数。我一般先算一个相关矩阵把和目标相关性低于 0.2 的指标先剔掉避免后面特征太多、模型过拟合。import seaborn as sns import matplotlib.pyplot as plt # 只保留数值列算相关 num_cols df.select_dtypes(includenumber).columns corr df[num_cols].corr() # 看和目标列的相关性排序 target tourism_arrivals print(corr[target].sort_values(ascendingFalse)) # 热力图辅助判断共线性 plt.figure(figsize(10, 8)) sns.heatmap(corr, annotFalse, cmapcoolwarm) plt.show()逻辑说明先筛数值列避免把地区名字符串带进相关计算报错。sort_values是为了快速定位哪些经济指标和目标最相关。参数上热力图annotFalse是因为列多时数字会糊成一片看颜色块就够了。如果发现 GDP 和居民收入相关性超过 0.9说明存在严重共线性线性回归里只能留一个或者改用岭回归。2.3 为什么先做平稳性检验再谈模型经济指标和旅游数据大多是时间序列直接丢进回归会得到「伪回归」——R² 很高但残差有趋势预测毫无意义。我一般先做 ADF 检验确认序列平稳性不平稳就差分。from statsmodels.tsa.stattools import adfuller def adf_test(series, name): result adfuller(series.dropna(), autolagAIC) print(f{name}: ADF{result[0]:.3f}, p{result[1]:.3f}) return result[1] # 对目标列和每个经济指标做检验 for col in [tourism_arrivals, gdp, income, cpi]: p adf_test(df[col], col) if p 0.05: print(f - {col} 不平稳需要差分)逻辑上autolagAIC让 statsmodels 自动选滞后阶数比手动指定稳。p 值大于 0.05 就认为不平稳需要做一阶差分再检验。这一步不做后面 ARIMA 的 d 参数就是瞎猜预测结果会系统性偏移。常见做法是差分后再跑一次 ADF直到 p 小于 0.05 为止。3. 特征工程把经济指标变成模型能吃的信号3.1 滞后特征经济指标影响旅游往往有延迟经济指标对旅游的影响很少是当期的。居民收入涨了可能过两三个月才体现在旅游人次上CPI 上升旅游需求可能滞后一个季度才下滑。所以要把经济指标做滞后处理构造 lag 特征。# 对经济指标构造 1-3 期滞后 lag_cols [gdp, income, cpi] for col in lag_cols: for lag in [1, 2, 3]: df[f{col}_lag{lag}] df[col].shift(lag) # 目标列也做滞后用于自回归特征 df[arrivals_lag1] df[tourism_arrivals].shift(1) df[arrivals_lag2] df[tourism_arrivals].shift(2) # 差分后去掉前几行 NaN df_model df.dropna().reset_index(dropTrue) print(df_model.shape)逻辑说明shift(lag)把序列往下移lag1 就是上一期的值。参数上滞后阶数不是越多越好一般先试 1 到 3 期超过 3 期在经济意义上解释力就弱了而且会吃掉样本量。dropna之后要检查还剩多少行如果原本只有 40 期去掉 3 期滞后加 2 期自回归只剩 35 期样本就偏紧了。3.2 滚动统计特征捕捉趋势和波动除了滞后滚动均值和滚动标准差能帮模型捕捉趋势方向和波动大小。旅游数据往往有季节性滚动窗口用 3 或 6 期比较合适。# 滚动均值和标准差窗口 3 期 df[arrivals_roll3_mean] df[tourism_arrivals].rolling(3).mean() df[arrivals_roll3_std] df[tourism_arrivals].rolling(3).std() # 经济指标的滚动均值平滑短期噪声 df[gdp_roll3] df[gdp].rolling(3).mean() df[income_roll3] df[income].rolling(3).mean() df_model df.dropna().reset_index(dropTrue)逻辑上滚动均值相当于低通滤波把短期波动压掉留下趋势。参数上窗口选 3 是因为月度数据里一个季度是 3 期和很多经济指标的发布节奏对得上。窗口太大比如 12会让特征过于平滑失去对近期变化的敏感度。滚动标准差则反映波动性旅游旺季和淡季的波动差异会被它捕捉到。3.3 季节性处理月度数据绕不开的坑旅游数据几乎必然有季节性暑期和节假日是高峰。处理方式有两种一是把月份做成哑变量二是做季节性差分。我一般先看季节图再决定用哪种。# 月份哑变量 df[month] df[date].dt.month month_dummies pd.get_dummies(df[month], prefixmonth, drop_firstTrue) df pd.concat([df, month_dummies], axis1) # 季节性差分12 期 df[arrivals_seasonal_diff] df[tourism_arrivals].diff(12)逻辑说明get_dummies把月份变成 0/1 列drop_firstTrue避免虚拟变量陷阱。季节性差分diff(12)是减去去年同期的值直接消除年度季节模式。参数上如果数据不足 24 期季节性差分会产生大量 NaN这时候只能用月份哑变量。两种方式不要同时用否则会过度差分把真实信号也差掉。4. 模型选型与训练从线性基线到树模型4.1 线性回归基线先跑通再优化不管最后用什么模型我都会先跑一个线性回归当基线。它的好处是可解释性强能直接看系数判断哪个经济指标影响大。from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error, r2_score # 特征列滞后、滚动、月份哑变量 feature_cols [c for c in df_model.columns if c not in [date, tourism_arrivals, tourism_revenue]] X df_model[feature_cols] y df_model[tourism_arrivals] # 时间序列不能随机打乱按时间顺序切 split int(len(X) * 0.8) X_train, X_test X[:split], X[split:] y_train, y_test y[:split], y[split:] lr LinearRegression() lr.fit(X_train, y_train) pred lr.predict(X_test) print(MAE:, mean_absolute_error(y_test, pred)) print(R2:, r2_score(y_test, pred)) # 看系数 coef pd.Series(lr.coef_, indexfeature_cols).sort_values() print(coef)逻辑说明时间序列切分必须按顺序不能train_test_split随机打乱否则用未来数据预测过去指标会虚高。参数上split取 80% 是常见做法但如果样本少于 50 期建议用时间序列交叉验证而不是单次切分。系数排序能直接看出哪个滞后经济指标贡献最大如果 GDP 滞后 2 期的系数绝对值最大说明经济对旅游的影响大约滞后两个月。4.2 树模型处理非线性和交互效应经济指标和旅游的关系往往不是线性的收入到一定水平后边际影响递减。这时候随机森林或梯度提升树更合适。from sklearn.ensemble import RandomForestRegressor rf RandomForestRegressor( n_estimators300, max_depth6, min_samples_leaf3, random_state42 ) rf.fit(X_train, y_train) pred_rf rf.predict(X_test) print(RF MAE:, mean_absolute_error(y_test, pred_rf)) print(RF R2:, r2_score(y_test, pred_rf)) # 特征重要性 imp pd.Series(rf.feature_importances_, indexfeature_cols).sort_values(ascendingFalse) print(imp.head(10))逻辑说明n_estimators300是精度和速度的平衡点再多提升有限。max_depth6控制树深防止过拟合样本少的时候尤其重要。min_samples_leaf3保证叶子节点至少有 3 个样本避免模型记住噪声。特征重要性排序能验证前面的相关性分析——如果滞后 GDP 和滚动均值排在前列说明特征工程方向对了。4.3 时间序列交叉验证别用单次切分下结论单次切分的结果波动很大换个切分点指标就变了。我一般用TimeSeriesSplit做多折验证看指标的稳定性。from sklearn.model_selection import TimeSeriesSplit import numpy as np tscv TimeSeriesSplit(n_splits5) mae_scores [] for train_idx, test_idx in tscv.split(X): X_tr, X_te X.iloc[train_idx], X.iloc[test_idx] y_tr, y_te y.iloc[train_idx], y.iloc[test_idx] rf.fit(X_tr, y_tr) p rf.predict(X_te) mae_scores.append(mean_absolute_error(y_te, p)) print(CV MAE:, np.mean(mae_scores), /-, np.std(mae_scores))逻辑说明TimeSeriesSplit保证每折的训练集都在测试集之前符合时间序列的因果顺序。参数上n_splits5是常用值样本少可以降到 3。看均值和标准差如果标准差很大说明模型在不同时间段表现不稳定可能是某个经济指标在某段时期发生了结构变化需要单独排查。5. 避坑与排查7 个源代码文件背后容易翻车的地方5.1 现象模型 R² 很高但预测图明显偏移原因时间序列做了随机切分测试集里混入了未来信息指标虚高。解决改用按时间顺序切分或TimeSeriesSplit重新评估。这个坑我踩过不止一次R² 0.95 看着漂亮画图一看预测线整体滞后一期就是数据泄漏。5.2 现象ADF 检验 p 值忽高忽低原因滞后阶数选择不当或者序列里有异常值。解决固定autolagAIC先做异常值检测比如 3 倍标准差剔除或平滑后再检验。经济指标偶尔有统计口径调整会造成假的结构突变。5.3 现象树模型特征重要性里月份哑变量排第一原因旅游数据的季节性太强月份哑变量把经济指标的信号盖住了。解决先做季节性差分或去季节化再跑模型或者把月份哑变量单独建模经济指标只解释去季节后的残差。我一般会对比去季节前后的特征重要性确认经济指标是否还有增量贡献。5.4 现象滞后特征一加样本量骤降原因每个滞后吃掉一行多个滞后叠加后样本不够。解决优先保留经济意义最强的 1 到 2 个滞后或者用插值补缺失再构造滞后。样本少于 30 期时建议放弃复杂模型改用简单回归加滚动预测。5.5 现象预测值出现负的旅游人次原因线性模型外推时没有约束经济指标出现极端值时预测越界。解决对目标做对数变换再建模预测后取指数还原或者用clip(lower0)做后处理。对数变换还能缓解异方差一举两得。6. 进阶技巧用滚动预测验证真实场景下的表现前面都是单次预测真实场景里模型是滚动使用的——用历史数据训练预测下一期然后加入新数据再预测。这个验证方式更接近落地也更容易暴露问题。# 滚动预测每次用前 N 期训练预测下一期 def rolling_forecast(df, feature_cols, target, start_ratio0.7): n len(df) start int(n * start_ratio) preds, actuals [], [] for i in range(start, n): train df.iloc[:i] test df.iloc[i:i1] model RandomForestRegressor(n_estimators200, max_depth6, random_state42) model.fit(train[feature_cols], train[target]) preds.append(model.predict(test[feature_cols])[0]) actuals.append(test[target].values[0]) return actuals, preds actuals, preds rolling_forecast(df_model, feature_cols, tourism_arrivals) mae mean_absolute_error(actuals, preds) print(滚动预测 MAE:, mae)逻辑说明每次只用当前时间点之前的数据训练预测下一期模拟真实部署时的信息约束。参数上start_ratio0.7表示前 70% 数据用于初始训练后面逐期滚动。这个方式计算量大但能真实反映模型在「只能看到过去」条件下的表现。如果滚动 MAE 明显高于单次切分的 MAE说明模型对近期变化不够敏感需要检查滞后特征是否够新。验证方式优点缺点适用场景单次时间切分快易实现结果波动大快速基线TimeSeriesSplit多折较稳仍有信息约束模型对比滚动预测最接近真实计算量大上线前验证最后说个我自己的习惯每次跑完模型我都会把预测值和实际值画在同一张图上不看指标先看图。图对了指标才有意义图不对R² 再高也是玄学。这个数据集不大但正好够把「经济指标 → 特征工程 → 模型 → 滚动验证」这条链路完整走一遍走通了再换更大的数据集心里就有底了。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑