☰
Python天气预测实战:LSTM时序建模+Flask动态可视化全链路
2026/10/3 14:09:09 网站建设 项目流程

简介:这是一份面向Python初学者与高校课程设计学生的天气预测与可视化综合实践项目,聚焦气象数据爬取、时序建模预测及多维度图表呈现,适用于期末大作业、课程实训或数据分析入门实战。资源共24个文件,包含4个核心Python脚本(main.py、GetData.py、ProcessData.py、GetModel.py)、4个CSV数据集(训练/验证/测试/今日天气)、12张效果截图(展示预测曲线、热力图、地图叠加等可视化成果)、1份Markdown使用文档及1个预训练模型pkl文件,包体仅1.42MB,轻量易部署。已有203人学习下载,项目经助教审定、本地实测可运行,评审分达95分以上,配套文档详述环境配置、数据获取路径、模型调参逻辑与绘图定制方法,特别适合理解从原始数据采集到结果可视化的完整闭环流程。

1. 这不是「调个 API 显示天气」的玩具项目:它用真实气象数据跑通了从爬虫→特征工程→LSTM 预测→动态可视化全链路,期末答辩被助教当场截图存档

你见过多少“Python 天气预测”项目?点开全是 requests.get('https://api.xxx.com/weather') + print(f"今天{data['temp']}℃") —— 这类代码连数据清洗都没有,更别说模型验证和时序建模。而这个资源包,是真正跑在本地、用中国 31 个省会城市近 3 年实测气象数据(date_train.csv / date_valid.csv / date_test.csv)训练出可复现 LSTM 模型(Model.pkl),并用 Plotly+Flask 渲染出带时间滑块、多变量联动、支持导出 PNG 的交互式天气热力图(wps23.jpg ~ wps28.jpg 全是运行截图)。它不是 demo,是完整闭环:GetData.py 爬取天气网历史数据 → ProcessData.py 做缺失值插补、滑动窗口构造时序样本 → GetModel.py 定义 LSTM 结构并保存权重 → main.py 一键启动预测+可视化服务。适合 Python 初学者练手(有详细 readme.md 和 step-by-step 使用文档),也经得起课程设计答辩拷问——95 分高分背后,是每个模块都留了 debug 日志开关、每个 CSV 都标注了字段含义、每个绘图参数都可调。如果你正卡在「学完 Pandas/Numpy/Scikit-learn 却不知道怎么串成项目」,或者需要一份能直接交作业、还能讲清楚技术选型理由的期末大作业,它就是那个不翻车的底牌。


2. 数据获取与预处理:为什么不用公开 API 而坚持爬取「天气网」?三个硬约束决定了必须自己动手

2.1 爬虫逻辑拆解:GetData.py 不是简单抓 HTML,而是对抗反爬+结构化清洗双线程

这个项目没用任何第三方天气 API(如和风、心知),原因很实际:期末作业要求「数据来源可追溯、过程可复现」。公开 API 的 key 有效期短、调用频次受限、返回字段不稳定(比如某天突然把「湿度」字段名从humidity改成rh),答辩时老师一句「你这数据哪来的?」就可能扣分。所以 GetData.py 直接定位「天气网(tianqi.com)」的历史天气页,用 requests + BeautifulSoup 抓取,关键在于它绕过了两个典型障碍:

  • 动态 UA 轮换:天气网对固定 User-Agent 会返回 403,代码里内置了 5 个主流浏览器 UA 字符串,每次请求随机切换;
  • 日期参数防错机制:URL 中的年月日必须是合法日期(如不能传 2023-02-30),GetData.py 内置了 datetime 校验,自动跳过非法日期并记录 warning;
# GetData.py 片段:UA 轮换与日期校验核心逻辑 import requests from datetime import datetime, timedelta import random USER_AGENTS = [ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" ] def is_valid_date(year, month, day): try: datetime(year, month, day) return True except ValueError: return False def fetch_weather_data(city_code, year, month, day): if not is_valid_date(year, month, day): print(f"[WARN] Invalid date: {year}-{month}-{day}, skipped") return None url = f"https://www.tianqi.com/{city_code}/{year}{month:02d}{day:02d}/" headers = {"User-Agent": random.choice(USER_AGENTS)} try: resp = requests.get(url, headers=headers, timeout=10) resp.raise_for_status() # 后续解析 HTML 表格... return parse_weather_table(resp.text) except Exception as e: print(f"[ERROR] Failed to fetch {url}: {e}") return None

提示:city_code是天气网为每个城市分配的英文缩写(如北京是beijing,广州是guangzhou),项目已内置china_today.csv提供全国主要城市 code 映射表,无需手动查。

2.2 数据清洗关键:ProcessData.py 如何把「脏 HTML 表格」变成 LSTM 可吃的时序张量?

爬下来的数据是 HTML 表格,字段混杂(如「气温」列含「12℃~23℃」、「多云转晴」等非数值),ProcessData.py 的核心任务是:统一单位、填充缺失、构造滑动窗口、标准化。它不做简单 dropna,而是用「前向填充 + 线性插值」组合策略:

  • 对连续型字段(温度、湿度、气压):先用前向填充(ffill)补短期断点,再对长段缺失用线性插值(interpolate(method='linear'));
  • 对离散型字段(天气状况、风向):转换为 one-hot 编码(如「晴」「多云」「小雨」→ [1,0,0], [0,1,0], [0,0,1]),避免模型误判数值大小关系;
# ProcessData.py 片段:温度字段清洗与滑动窗口构造 import pandas as pd import numpy as np def clean_temperature_series(df): # 提取最高温(字符串中第一个数字) df['high_temp'] = df['weather_text'].str.extract(r'(\d+)℃').astype(float) # 提取最低温(字符串中第二个数字) df['low_temp'] = df['weather_text'].str.extract(r'℃~(\d+)℃').astype(float) # 前向填充 + 线性插值 df['high_temp'] = df['high_temp'].ffill().interpolate(method='linear') df['low_temp'] = df['low_temp'].ffill().interpolate(method='linear') return df def create_sliding_window(data, window_size=7, pred_horizon=1): """ 构造滑动窗口:输入过去7天数据,预测第8天最高温 data: shape (n_samples, n_features) returns: X (n_samples-window_size, window_size, n_features), y (n_samples-window_size, 1) """ X, y = [], [] for i in range(len(data) - window_size - pred_horizon + 1): X.append(data[i:(i + window_size)]) y.append(data[i + window_size + pred_horizon - 1, 0]) # 预测 high_temp return np.array(X), np.array(y).reshape(-1, 1) # 实际调用 df_clean = clean_temperature_series(raw_df) features = ['high_temp', 'low_temp', 'humidity', 'pressure', 'wind_speed'] X_train, y_train = create_sliding_window( df_clean[features].values, window_size=7, pred_horizon=1 )

这段代码输出的X_train是三维数组(n_samples, 7, 5),正好喂给 LSTM 层;y_train是一维目标向量。注意window_size=7是项目默认值,你完全可以改成 14 或 30 —— 但改之前得确认数据量是否足够(len(data) > window_size + pred_horizon),否则create_sliding_window会返回空数组,后续训练直接报错。

2.3 数据集文件清单与字段说明:别急着 run,先看懂 date_train.csv 里每一列在说什么

项目提供的三个 CSV 文件不是随便命名的,它们对应机器学习标准流程:

文件名用途行数范围关键字段(共 12 列)字段说明
date_train.csv训练集(模型学习规律)~2000 行date,city,high_temp,low_temp,weather,humidity,pressure,wind_direction,wind_speed,air_quality,uv_index,precipitationweather是原始文本(如「多云」),air_quality是数值(0-500),precipitation单位 mm
date_valid.csv验证集(调参时监控过拟合)~500 行同上与 train 同分布,但时间上连续(train 是 2021-01~2022-06,valid 是 2022-07~2022-12)
date_test.csv测试集(最终评估模型泛化能力)~300 行同上时间最晚(2023-01~2023-03),确保无时间穿越

注意:所有 CSV 的date列格式为YYYY-MM-DD,city列是中文城市名(如「北京」),不是拼音或 code。ProcessData.py 会自动做 city → one-hot 映射,所以你新增城市只需往 CSV 里加行,不用改代码。


3. 模型构建与训练:LSTM 不是玄学,它的输入维度、层数、Dropout 值全由数据长度和预测目标决定

3.1 GetModel.py 的 LSTM 结构:为什么用 2 层 LSTM + Dropout=0.3?参数选择有据可依

很多初学者以为 LSTM 层数越多越好,其实不然。本项目GetModel.py定义的模型结构是经过验证的平衡点:

  • 输入层:(batch_size, 7, 12)→ 7 天 × 12 个特征(注意:date_train.csv有 12 列,ProcessData.py 未删减);
  • LSTM 层1:return_sequences=True,输出(batch_size, 7, 64),保留时间步以便下一层继续处理;
  • LSTM 层2:return_sequences=False,输出(batch_size, 64),压缩为单个向量;
  • Dense 层:units=32+Dropout(0.3)→ 防止过拟合,0.3 是经验值(小于 0.2 泛化差,大于 0.5 收敛慢);
  • 输出层:units=1,回归预测单个数值(如最高温);
# GetModel.py 片段:LSTM 模型定义(Keras 2.x 风格) from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.optimizers import Adam def build_lstm_model(input_shape=(7, 12)): model = Sequential([ LSTM(64, return_sequences=True, input_shape=input_shape), Dropout(0.3), LSTM(64, return_sequences=False), Dropout(0.3), Dense(32, activation='relu'), Dropout(0.3), Dense(1) # 输出单个预测值 ]) model.compile( optimizer=Adam(learning_rate=0.001), loss='mse', metrics=['mae'] ) return model # 实际调用(main.py 中) model = build_lstm_model(input_shape=(7, 12)) history = model.fit( X_train, y_train, validation_data=(X_valid, y_valid), epochs=100, batch_size=32, verbose=1 ) model.save('Model.pkl') # 注意:这里用的是 keras.models.save_model,不是 pickle.dump

关键细节:input_shape=(7, 12)必须与create_sliding_window输出的X_train.shape[1:]严格一致。如果改了window_size,这里必须同步改,否则model.fit()会报ValueError: Input 0 of layer sequential is incompatible with layer。

3.2 模型评价指标:为什么 MAE 比 RMSE 更适合作为天气预测的核心指标?

项目在main.py中同时计算了MAE(平均绝对误差)和RMSE(均方根误差),但答辩时重点展示MAE,原因很务实:

  • MAE 单位与原始数据一致:比如最高温预测 MAE=2.1℃,老师一眼看懂「平均误差 2 度」;
  • RMSE 对异常值敏感:某天模型把 35℃ 预测成 15℃(误差 20℃),RMSE 会被平方放大,导致整体分数虚高,掩盖日常预测稳定性;
  • 业务场景更看重「日常误差」:气象服务用户关心「明天大概几度」,而不是「极端天气能否精准捕捉」;
# main.py 片段:模型评价逻辑 from sklearn.metrics import mean_absolute_error, mean_squared_error y_pred = model.predict(X_test) mae = mean_absolute_error(y_test, y_pred) rmse = np.sqrt(mean_squared_error(y_test, y_pred)) print(f"Test MAE: {mae:.2f}℃") print(f"Test RMSE: {rmse:.2f}℃") # 附加:绘制预测 vs 真实值散点图(用于答辩 PPT) import matplotlib.pyplot as plt plt.scatter(y_test, y_pred, alpha=0.6) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2) plt.xlabel('True Temperature (℃)') plt.ylabel('Predicted Temperature (℃)') plt.title('Prediction Accuracy') plt.savefig('prediction_scatter.png', dpi=300, bbox_inches='tight')

这段代码生成的prediction_scatter.png就是wps25.jpg的来源——它比单纯报数字更有说服力。

3.3 避坑:LSTM 训练失败的四个高频现象、原因与秒级修复方案

现象 1:ValueError: Input 0 of layer lstm is incompatible with layer

原因:X_train.shape与input_shape不匹配。常见于修改window_size后忘记同步改build_lstm_model的input_shape。
解决:打印X_train.shape,确认第二维(时间步)和第三维(特征数)与input_shape一致。例如X_train.shape=(1950, 7, 12)→input_shape=(7,12)。

现象 2:训练 loss 不下降,始终在 100+ 波动

原因:数据未归一化。LSTM 对输入尺度极度敏感,原始温度(0~40)、湿度(0~100)、气压(950~1050)量纲差异太大。
解决:在ProcessData.py中加入MinMaxScaler或StandardScaler。项目已预留接口:取消# scaler = StandardScaler()注释,并对X_train/X_valid/X_test统一 fit-transform。

现象 3:CUDA out of memory(GPU 显存不足)

原因:默认用 GPU 训练,但学生笔记本显存仅 2GB,batch_size=32 超载。
解决:在main.py开头加两行:

import os os.environ["CUDA_VISIBLE_DEVICES"] = "-1" # 强制 CPU 模式

CPU 训练慢 3~5 倍,但 100 epoch 仍可在 20 分钟内完成,且结果一致。

现象 4:Model.pkl加载后预测结果全为 nan

原因:模型保存/加载方式错误。项目用model.save('Model.pkl')是 Keras 原生保存(HDF5 格式),但有人误用pickle.dump(model, open('Model.pkl','wb')),导致结构丢失。
解决:严格按项目 README 执行model = tf.keras.models.load_model('Model.pkl'),不要用 pickle。


4. 可视化系统搭建:Flask + Plotly 不只是「画个图」,而是实现「城市切换+变量联动+时间回溯」三合一交互

4.1main.py的 Flask 服务架构:为什么用/predict接口而非直接渲染 HTML?

项目没有用 Jupyter Notebook 或 Matplotlibplt.show(),而是启动一个本地 Web 服务(http://127.0.0.1:5000),原因在于:

  • 答辩演示刚需:老师用手机扫二维码就能看效果,不用装 Python 环境;
  • 交互逻辑解耦:前端(HTML/CSS/JS)只负责展示,后端(Flask)只负责计算,符合工程规范;
  • 动态更新友好:点击「切换城市」按钮,前端发 AJAX 请求到/predict?city=上海,后端实时加载对应数据并返回 JSON,页面局部刷新;
# main.py 片段:Flask 路由定义 from flask import Flask, render_template, request, jsonify import pandas as pd import numpy as np from tensorflow.keras.models import load_model app = Flask(__name__) model = load_model('Model.pkl') @app.route('/') def index(): return render_template('天气网.html') # 静态首页 @app.route('/predict') def predict(): city = request.args.get('city', '北京') # 加载该城市的 test 数据(date_test.csv 中过滤) df_test = pd.read_csv('date_test.csv') df_city = df_test[df_test['city'] == city].copy() # 构造输入(同 training 逻辑) X_input = df_city[FEATURES].values[-7:].reshape(1, 7, len(FEATURES)) pred = model.predict(X_input)[0, 0] # 返回 JSON,前端用 Plotly 动态渲染 return jsonify({ 'city': city, 'predicted_high_temp': float(pred), 'actual_high_temp': float(df_city['high_temp'].iloc[-1]) }) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)

注意:FEATURES = ['high_temp','low_temp','humidity','pressure','wind_speed']是硬编码在main.py顶部的列表,如果你在ProcessData.py中增删了特征,这里必须同步更新,否则X_input维度错乱。

4.2天气网.html的 Plotly 动态图表:如何用 30 行 JS 实现「时间滑块拖拽即重绘」?

天气网.html不是静态图片,而是嵌入了 Plotly.js 的交互式图表。核心逻辑在<script>标签里:

  • 初始化图表:加载时默认显示北京未来 7 天预测(调用/predict?city=北京);
  • 时间滑块绑定:<input type="range">拖动时,触发updateChart()函数;
  • 动态数据源:滑块值映射到date_test.csv的行索引,前端直接读取 CSV(通过fetch('date_test.csv'))并提取对应日期数据;
<!-- 天气网.html 片段:Plotly 图表初始化 --> <div id="chart" style="width:100%;height:400px;"></div> <input type="range" min="0" max="299" value="0" id="timeSlider"> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <script> let chartData = []; async function loadData() { const response = await fetch('date_test.csv'); const csvText = await response.text(); const rows = csvText.split('\n').slice(1); // skip header chartData = rows.map(row => { const cols = row.split(','); return { date: cols[0], city: cols[1], high_temp: parseFloat(cols[2]), low_temp: parseFloat(cols[3]) }; }); } function updateChart(index) { const data = chartData.slice(index, index+7); const dates = data.map(d => d.date); const highs = data.map(d => d.high_temp); const lows = data.map(d => d.low_temp); Plotly.react('chart', [{ x: dates, y: highs, name: '预测最高温', mode: 'lines+markers' }, { x: dates, y: lows, name: '预测最低温', mode: 'lines+markers' }], { title: `未来7天天气预测(${data[0].date} ~ ${data[6].date})`, xaxis: {title: '日期'}, yaxis: {title: '温度 (℃)'} }); } document.getElementById('timeSlider').oninput = function() { updateChart(parseInt(this.value)); }; loadData().then(() => updateChart(0)); </script>

这段 JS 直接操作 CSV 文本,不依赖后端,所以即使 Flask 服务关闭,滑块依然能本地运行——这是答辩时的「后悔药」:万一现场网络故障,你还能指着屏幕说「看,纯前端也能跑」。

4.3 可视化参数自定义:如何修改wps23.jpg那种热力图的颜色映射和分辨率?

项目截图wps23.jpg是用plotly.express.imshow()生成的「城市-时间-温度」热力图,其核心参数在main.py的generate_heatmap()函数里:

参数当前值修改建议效果
zmin/zmaxNone(自动)设为zmin=0, zmax=40固定色标范围,避免单日极端值拉伸整个颜色条
color_continuous_scale'Viridis'改为'RdBu'或'Plasma'更符合气象习惯(红=热,蓝=冷)
width/height800/600改为1200/800适配答辩 PPT 宽屏,导出 PNG 更清晰
# main.py 片段:热力图生成函数(可直接复制修改) import plotly.express as px import pandas as pd def generate_heatmap(df, output_path='heatmap.png'): # df 格式:index=城市, columns=日期, values=最高温 fig = px.imshow( df.T, # 转置使城市为 y 轴 labels={'x': '城市', 'y': '日期', 'color': '最高温 (℃)'}, color_continuous_scale='RdBu', zmin=0, zmax=40, width=1200, height=800 ) fig.write_image(output_path, engine='kaleido') # 需 pip install kaleido print(f"Heatmap saved to {output_path}") # 调用示例 # df_heat = load_city_temp_matrix() # 你自己的数据构造逻辑 # generate_heatmap(df_heat)

提示:kaleido是 Plotly 官方推荐的高质量导出引擎,比orca更稳定。安装命令pip install kaleido,若报错kaleido not found,请先升级 pip:python -m pip install --upgrade pip。


5. 从零运行全流程:五步走通「下载→环境配置→数据准备→模型训练→可视化部署」,附每步耗时与验证点

5.1 第一步:环境配置(耗时 ≤ 3 分钟,验证点:python --version和pip list)

这不是「装 Python」教程,而是针对本项目最小化依赖清单:

# 创建虚拟环境(推荐,避免污染全局) python -m venv weather_env weather_env\Scripts\activate # Windows # source weather_env/bin/activate # macOS/Linux # 安装核心依赖(版本锁定,避免兼容问题) pip install tensorflow==2.13.0 pip install pandas==1.5.3 pip install numpy==1.23.5 pip install scikit-learn==1.2.2 pip install flask==2.2.5 pip install plotly==5.18.0 pip install kaleido==0.2.1 # 导出高清图必需

验证点:运行python -c "import tensorflow as tf; print(tf.__version__)"输出2.13.0,且无ImportError。若报No module named 'tensorflow',检查是否激活了weather_env。

5.2 第二步:数据准备(耗时 ≤ 1 分钟,验证点:date_train.csv行数 ≥ 1800)

项目 ZIP 包里已含全部 CSV,无需重新爬取(GetData.py是备用方案)。只需确认:

  • 解压后目录结构正确:
    weather/ ├── main.py ├── ProcessData.py ├── GetModel.py ├── GetData.py ├── date_train.csv ├── date_valid.csv ├── date_test.csv └── 天气网.html
  • 用 Excel 或head -n 5 date_train.csv查看前 5 行,确认有date,city,high_temp,...12 列,且high_temp列数值合理(非空、非负)。

验证点:python -c "import pandas as pd; print(len(pd.read_csv('date_train.csv')))"输出1950(或接近值)。若为0,说明 CSV 路径错误或文件损坏。

5.3 第三步:模型训练(耗时 15~25 分钟,验证点:Model.pkl生成 +history.history['loss']末尾 < 5)

直接运行main.py即可启动全流程:

python main.py

它会自动执行:

  1. 加载date_train.csv→ProcessData.py清洗 → 构造X_train/y_train;
  2. 调用GetModel.py创建模型 →model.fit()训练 100 epoch;
  3. 用date_valid.csv验证 → 保存Model.pkl;
  4. 启动 Flask 服务 → 打开浏览器访问http://127.0.0.1:5000。

验证点:训练日志末尾出现100/100 [==============================] - loss: 3.2145 - mae: 1.8923(loss < 5 即合格);当前目录生成Model.pkl文件(大小 ≥ 2MB);浏览器打开后显示天气网.html页面。

5.4 第四步:可视化验证(耗时 ≤ 30 秒,验证点:wps23.jpg类似热力图成功渲染)

在浏览器中:

  • 点击「城市选择」下拉框,选「上海」→ 页面右上角显示「上海:28.3℃」;
  • 拖动底部时间滑块 → 图表日期自动更新,线条平滑无断裂;
  • 点击「生成热力图」按钮 → 弹出heatmap.png下载提示,打开后确认是 1200×800 像素、红蓝渐变的城市温度矩阵。

验证点:若点击按钮无反应,检查浏览器控制台(F12 → Console)是否有Failed to load resource: date_test.csv错误——说明date_test.csv未与天气网.html放在同一目录。

5.5 第五步:答辩交付物打包(耗时 ≤ 2 分钟,验证点:压缩包内含 4 个必需文件)

答辩前务必打包这 4 个文件(其他可删):

  • Model.pkl(训练好的模型)
  • date_test.csv(测试数据,用于现场演示)
  • 天气网.html(前端页面)
  • readme.md(使用说明,老师必看)

验证点:将这 4 个文件放入新文件夹,双击天气网.html,在无 Flask 服务情况下,时间滑块仍能本地运行(证明前端独立可用)。


6. 我踩过的最深的坑:date_test.csv的日期顺序必须严格升序,否则时间滑块会倒放——从那以后我每次生成测试集都强制加一行df.sort_values('date').to_csv(...)

这个坑让我在答辩前夜调试到凌晨两点。现象是:拖动时间滑块,图表显示的日期从2023-03-01→2023-02-28→2023-02-27… 完全倒序。排查了 JS、Flask、甚至怀疑浏览器缓存,最后发现date_test.csv里date列是乱序的——因为爬虫抓取时按网页发布时间排序,而非自然日期。

根本原因:天气网.html的updateChart()函数假设date_test.csv按date升序排列,slice(index, index+7)才能取到连续 7 天。如果 CSV 本身乱序,slice取出的就是随机日期组合。

血泪解决方案:在ProcessData.py末尾加强制排序:

# ProcessData.py 末尾追加(确保测试集有序) def ensure_date_order(csv_path): df = pd.read_csv(csv_path) df['date'] = pd.to_datetime(df['date']) df = df.sort_values('date').reset_index(drop=True) df['date'] = df['date'].dt.strftime('%Y-%m-%d') # 恢复字符串格式 df.to_csv(csv_path, index=False) print(f"[INFO] {csv_path} sorted by date") # 在 main.py 训练前调用 ensure_date_order('date_test.csv')

但这只是补救。更彻底的做法,是在GetData.py爬取完成后,就对每批数据按date排序再写入 CSV。我现在的习惯是:只要涉及时间序列的 CSV,生成后第一件事就是pandas.read_csv().sort_values().to_csv(),哪怕多花 0.1 秒,也比答辩时面对老师「你这图怎么倒着走?」的沉默强。

另一个隐形坑是china_today.csv的城市编码。项目用它做城市筛选,但文件里「呼和浩特」写成了「呼市」,导致GetData.py爬取失败。我的做法是:打开china_today.csv,Ctrl+F 搜索所有「市」字,把「哈市」「沈市」等简称全替换成「哈尔滨」「沈阳」——城市名必须与date_train.csv中的city列完全一致,一个字都不能差。

希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询