简介本资源是一份面向计算机、电子信息工程及数学等专业本科生的机器学习综合实践项目聚焦重庆地区天气与空气质量数据的采集、分析与建模全流程适用于课程设计、期末大作业及毕业设计等教学场景。压缩包共6个文件3个xlsx数据表用于存储爬取的天气、空气质量及合并后的结构化数据3个Python脚本分别实现网页爬虫抓取、数据质量分析与基础预测功能整体大小仅369KB轻量易部署。已有367人下载学习代码采用参数化设计关键变量如城市名、时间范围、API接口均封装为可配置项配合详尽中文注释与完整运行结果截图确保开箱即用所有模块均经实测验证通过逻辑清晰、调试友好特别适合初学机器学习与网络爬虫的学生快速掌握从数据获取到分析建模的闭环能力。1. 项目概述从数据采集到智能分析的完整闭环最近在带学生做机器学习相关的课程设计发现一个非常普遍的现象很多同学拿到“数据分析”或“预测模型”这类题目后第一反应就是去Kaggle或者UCI找现成的数据集。这当然没问题但对于理解一个真实机器学习项目的全生命周期来说缺失了至关重要的一环——数据从哪里来一个只做“数据清洗-建模-评估”的项目就像只学了炒菜却不会买菜和备料总感觉少了点根基。所以当有同学提出想做一个结合重庆本地特色的天气分析项目时我立刻觉得这是个绝佳的机会。这个项目麻雀虽小五脏俱全它要求你从一个具体的、动态的目标重庆天气出发亲自动手解决数据获取爬虫、数据整理、探索性分析并最终运用机器学习方法去发现规律或做出预测。整个过程恰好覆盖了从数据生产到数据消费的完整链条。重庆作为一个典型的山地城市其天气系统复杂多雾、夏季高温高湿、冬季阴冷这些特点都为数据分析提供了丰富的素材。你不仅能练手技术还能对身边的环境有更数据化的认识。这个项目非常适合有一定Python基础正在学习数据分析或机器学习入门的朋友。无论你是学生想完成一份出色的课程作业还是职场新人想构建自己的第一个数据作品集跟着这个思路走一遍你会对“数据驱动”有更实在的体会。接下来我就把这个项目的完整实现路径、技术选型的考量、实操中踩过的坑以及一些进阶思考毫无保留地分享出来。2. 核心需求解析与方案设计2.1 需求拆解我们要的不仅仅是一份数据乍看标题“重庆天气爬虫-质量分析”需求似乎很直白爬点天气数据然后分析一下。但深究下去我们需要明确几个层次的目标数据获取的可持续性与合规性我们需要的是一个能稳定、持续获取重庆地区历史与实时天气数据的方案。数据源必须可靠、公开且爬取行为不能对目标服务器造成压力必须遵守robots.txt协议。这意味着我们不能简单粗暴地无限循环请求。数据字段的完整性与业务贴合度天气数据包含哪些维度除了常规的温度、湿度、风力、天气现象对于重庆这样的城市空气质量AQI、能见度、体感温度、气压等字段可能对后续分析如舒适度研究、雾霾分析至关重要。我们需要根据分析目标反推需要爬取哪些字段。数据质量的评估与清洗爬下来的数据直接就是干净的吗几乎不可能。缺失值、异常值比如湿度超过100%、格式不一致天气现象描述的中英文混杂等问题普遍存在。因此“质量分析”的第一步其实是对数据本身质量进行评估和清洗。从描述到预测的分析进阶基础分析可以包括历史趋势、季节性规律、各气象要素的相关性等。但机器学习作业的要求更高我们需要设定明确的建模目标例如基于前几天的天气数据预测明天的最高温度或者根据气象要素预测空气质量等级。这决定了我们后续特征工程和模型选型的方向。基于以上拆解我设计的方案核心思路是构建一个模块化、可配置的爬虫系统获取结构化、带时间戳的天气数据存入本地数据库或文件然后利用Pandas进行数据质量探查与清洗最后使用Scikit-learn库构建预测模型并完成模型评估与可视化。2.2 技术栈选型与理由为什么选这些工具每个选择背后都有具体的考量爬虫核心Requests BeautifulSoup4 / PyQueryRequestsHTTP库的“事实标准”简单易用功能强大。对于大多数静态天气网站它完全够用。BeautifulSoup4或PyQueryHTML解析库。BeautifulSoup更普及文档丰富PyQuery的语法类似jQuery对于前端熟悉的同学更友好。本项目选择BeautifulSoup4适用性更广。为什么不直接用ScrapyScrapy是强大的框架适合构建大型、复杂的爬虫项目。但对于我们这个目标单一、页面结构相对固定的天气爬虫用RequestsBeautifulSoup组合更轻量、更直接学习曲线平缓更能让初学者聚焦于数据提取逻辑本身。数据存储SQLite / CSVSQLite轻量级数据库无需安装服务器单个文件即可管理非常适合本地项目。它能方便地按日期查询、去重是比纯CSV更规范的选择。CSV作为备份或中间格式便于用Excel快速查看和Pandas读取。最佳实践是爬虫数据先入SQLite保证结构化和可管理分析时导出或连接所需数据到Pandas。数据分析与机器学习Pandas NumPy Scikit-learn Matplotlib/SeabornPandas数据操作的基石数据清洗、转换、聚合离不开它。NumPy底层数值计算支持。Scikit-learn提供了几乎所有经典的机器学习算法回归、分类、聚类和完整的模型工具链训练、评估、调参。MatplotlibSeaborn可视化黄金搭档。Matplotlib定制性强Seaborn统计图表美观默认样式好看。调度与容错进阶Schedule / APScheduler如果想实现每日定时自动爬取可以引入轻量级的定时任务库如schedule。更复杂的可以用APScheduler。关键点必须加入异常处理try...except和日志记录logging模块记录爬取成功、失败的情况便于后期维护和排查。注意伦理与合规红线在编写爬虫前务必仔细查看目标网站的robots.txt文件通常在网站根目录如https://目标网站/robots.txt尊重其中关于爬取频率和禁止爬取目录的规定。在代码中通过设置requests.get()的headers参数模拟真实浏览器访问并在请求间添加随机延时如time.sleep(random.uniform(1, 3))避免高频请求对服务器造成干扰这是每个数据采集者应遵守的基本准则。3. 爬虫核心实现稳定获取重庆天气数据3.1 目标网站分析与字段确定国内有许多天气数据来源例如中国天气网、心知天气API、和风天气API等。考虑到项目的练习性质和可访问性我们选择一个结构清晰的公开天气历史数据查询网站作为示例请注意实际项目中请务必确认该网站允许爬取并遵守其服务条款。假设我们目标页面能按城市和日期查询历史天气。通过浏览器开发者工具F12查看网络请求我们发现数据可能是通过后端接口返回的JSON也可能是直接渲染在HTML中。这里我们以更常见的HTML直接渲染为例进行解析。我们需要爬取的典型字段包括date: 日期 (主键)high_temp: 最高气温 (℃)low_temp: 最低气温 (℃)weather: 天气现象 (如晴、多云、阴、小雨)wind_direction: 风向wind_force: 风力等级aqi: 空气质量指数 (可选如果页面提供)aqi_level: 空气质量等级 (可选)3.2 爬虫代码模块化构建我将爬虫构建为几个函数提高代码可读性和可维护性。import requests from bs4 import BeautifulSoup import pandas as pd import sqlite3 import time import random import logging from datetime import datetime, timedelta # 配置日志方便追踪运行状态和错误 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s: %(message)s) class ChongqingWeatherSpider: def __init__(self, base_url, start_date, end_date): 初始化爬虫 :param base_url: 基础URL通常包含城市和日期占位符 :param start_date: 开始日期字符串格式 YYYY-MM-DD :param end_date: 结束日期字符串格式 YYYY-MM-DD self.base_url base_url self.start_date datetime.strptime(start_date, %Y-%m-%d) self.end_date datetime.strptime(end_date, %Y-%m-%d) self.headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 } self.data_list [] # 临时存储爬取的数据 def _parse_date_range(self): 生成需要爬取的日期列表 date_list [] current_date self.start_date while current_date self.end_date: date_list.append(current_date.strftime(%Y-%m-%d)) current_date timedelta(days1) return date_list def _fetch_html(self, url): 请求网页返回BeautifulSoup对象 try: # 添加随机延时模拟人工操作 time.sleep(random.uniform(1, 2)) resp requests.get(url, headersself.headers, timeout10) resp.raise_for_status() # 如果状态码不是200抛出HTTPError异常 resp.encoding resp.apparent_encoding # 自动识别编码 return BeautifulSoup(resp.text, html.parser) except requests.RequestException as e: logging.error(f请求失败 {url}: {e}) return None def _parse_single_day(self, soup, query_date): 解析单日天气数据这是核心函数需要根据目标网站HTML结构具体调整 这里是一个示例解析逻辑你需要用浏览器开发者工具定位实际元素 day_data {date: query_date} try: # 示例假设数据在一个class为‘weather-info’的div里 # 你需要根据实际网站结构修改这些选择器 weather_div soup.find(div, class_weather-info) if not weather_div: logging.warning(f{query_date} 页面结构可能已变化未找到关键元素) return None # 解析最高温和最低温 (示例文本可能是“高温 32℃ 低温 25℃”) temp_text weather_div.find(p, class_temp).text # 这里需要编写具体的文本提取和清洗逻辑例如用正则表达式 # 假设提取出数字 import re temps re.findall(r\d, temp_text) if len(temps) 2: day_data[high_temp] int(temps[0]) day_data[low_temp] int(temps[1]) # 解析天气现象 weather_span weather_div.find(span, class_weather) if weather_span: day_data[weather] weather_span.text.strip() # 解析风力风向 wind_div weather_div.find(div, class_wind) if wind_div: parts wind_div.text.split() if len(parts) 2: day_data[wind_direction] parts[0] day_data[wind_force] parts[1] # 检查必要字段是否齐全 if all(k in day_data for k in [high_temp, low_temp, weather]): logging.info(f成功解析 {query_date} 数据) return day_data else: logging.warning(f{query_date} 数据解析不完整: {day_data}) return None except Exception as e: logging.error(f解析 {query_date} 数据时发生异常: {e}) return None def run(self): 主运行函数 dates_to_crawl self._parse_date_range() logging.info(f开始爬取 {self.start_date.date()} 至 {self.end_date.date()} 的天气数据共{len(dates_to_crawl)}天) for single_date in dates_to_crawl: # 构造具体日期的URL例如 base_url 可能是 http://example.com/weather/chongqing-{date} target_url self.base_url.format(datesingle_date) logging.info(f正在处理 {single_date}, URL: {target_url}) soup self._fetch_html(target_url) if not soup: continue day_data self._parse_single_day(soup, single_date) if day_data: self.data_list.append(day_data) logging.info(f爬取结束共获取到 {len(self.data_list)} 条有效数据) return self.data_list def save_to_sqlite(self, db_pathweather_data.db): 将数据保存到SQLite数据库 if not self.data_list: logging.warning(没有数据可保存) return conn sqlite3.connect(db_path) df pd.DataFrame(self.data_list) # 如果表不存在则创建如果存在则替换可根据需要改为追加‘append’ df.to_sql(chongqing_weather, conn, if_existsreplace, indexFalse) conn.close() logging.info(f数据已保存至数据库: {db_path}) def save_to_csv(self, csv_pathweather_data.csv): 将数据保存到CSV文件 if not self.data_list: logging.warning(没有数据可保存) return df pd.DataFrame(self.data_list) df.to_csv(csv_path, indexFalse, encodingutf-8-sig) # utf-8-sig 解决Excel打开中文乱码 logging.info(f数据已保存至CSV文件: {csv_path}) # 使用示例 if __name__ __main__: # 请务必替换为真实、合规的目标URL格式 BASE_URL_TEMPLATE https://tianqi.example.com/chongqing/{date}.html spider ChongqingWeatherSpider( base_urlBASE_URL_TEMPLATE, start_date2023-01-01, end_date2023-01-07 # 初始测试时范围小一点 ) data spider.run() spider.save_to_csv(chongqing_weather_2023_sample.csv) spider.save_to_sqlite()关键点解析类封装使用类ChongqingWeatherSpider将数据和方法封装在一起结构清晰便于管理状态如data_list。健壮性设计_fetch_html方法包含了异常处理try...except和状态码检查raise_for_status。_parse_single_day方法内部有try...except防止因某一天页面结构异常导致整个程序崩溃。添加了详细的日志logging运行情况一目了然。遵守爬虫礼仪在_fetch_html中加入了随机延时time.sleep(random.uniform(1, 2))并设置了合理的User-Agent。数据持久化提供了保存到SQLite数据库和CSV文件两种方式SQLite便于后续复杂查询CSV便于交换和快速查看。3.3 反爬策略应对与实战技巧在实际操作中你可能会遇到一些简单的反爬措施请求头Headers缺失像上面代码中设置User-Agent是最基本的。有时还需要添加Referer、Accept-Language等字段。用浏览器开发者工具查看一次正常请求的Headers并复制是最高效的方法。IP限制如果频繁请求可能会被临时封禁IP。对于个人小规模爬取降低请求频率是最有效的方法如将延时增加到3-5秒。本项目数据量不大此方法足够。大规模爬取需要考虑代理IP池但这超出了课程作业范围且涉及更高风险与成本。动态加载数据如果数据是通过JavaScript异步加载的在“网络”选项卡中看到XHR或Fetch请求那么Requests获取的HTML就不包含数据。这时需要分析这些异步请求的接口直接模拟请求接口URL通常返回JSON这往往比解析HTML更简单。可以使用浏览器开发者工具的“网络”面板进行抓包分析。页面结构变更这是爬虫失效最常见的原因。所以核心解析函数_parse_single_day中的选择器如find(‘div’, class_‘weather-info’)非常脆弱。一个好的习惯是将这些选择器用的class或id名定义为类常量一旦网站改版只需修改一处。更好的做法是使用相对更稳定的定位方式比如通过标签层级关系而不是完全依赖易变的class名。实操心得不要试图一次性写出完美的、能应对所有情况的爬虫。应该采用“小步快跑”的策略先针对一个具体的日期页面在Python交互环境如Jupyter Notebook里用Requests和BeautifulSoup手动调试解析代码成功提取出该页面的所有目标字段。确认逻辑无误后再将其封装成函数并加入循环和异常处理。这样能极大降低调试复杂度。4. 数据质量分析与清洗实战拿到原始数据后切忌直接开始建模。脏数据会导致错误的结论。我们需要先用Pandas进行彻底的数据质量探查EDA, Exploratory Data Analysis。4.1 数据加载与初步探查import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 加载数据 df pd.read_csv(chongqing_weather_2023_sample.csv) # 或从SQLite加载 # import sqlite3 # conn sqlite3.connect(weather_data.db) # df pd.read_sql_query(SELECT * FROM chongqing_weather, conn) print(数据形状行列:, df.shape) print(\n前5行数据) print(df.head()) print(\n数据基本信息) print(df.info()) print(\n数值型字段描述性统计) print(df.describe())运行df.info()会立刻告诉我们是否有缺失值Non-Null Count。df.describe()可以查看数值字段的分布均值、标准差、最小值、最大值快速发现异常比如最高温度出现100℃这种明显错误。4.2 数据清洗的具体操作清洗通常是一个迭代的过程以下是一些常见操作# 1. 处理日期字段 df[date] pd.to_datetime(df[date]) # 转换为datetime类型 df[year] df[date].dt.year df[month] df[date].dt.month df[day] df[date].dt.day df[day_of_week] df[date].dt.dayofweek # 周一0周日6 # 2. 处理缺失值 print(缺失值统计) print(df.isnull().sum()) # 根据情况处理例如 # - 对于数值列如温度可以用前后天的平均值填充或该月的历史平均值填充 # - 对于类别列如天气现象可以用众数填充或标记为‘未知’ df[high_temp].fillna(df[high_temp].interpolate(), inplaceTrue) # 线性插值 df[weather].fillna(df[weather].mode()[0], inplaceTrue) # 用出现最多的天气填充 # 3. 处理异常值 # 基于业务逻辑判断例如重庆最高气温通常不会超过45℃最低不会低于-5℃ temp_upper_limit 45 temp_lower_limit -5 # 将超出范围的温度视为异常可以用边界值替换或设为NaN df.loc[df[high_temp] temp_upper_limit, high_temp] temp_upper_limit df.loc[df[low_temp] temp_lower_limit, low_temp] temp_lower_limit # 或者使用统计学方法如3σ原则假设数据近似正态分布 # mean, std df[high_temp].mean(), df[high_temp].std() # df df[(df[high_temp] mean - 3*std) (df[high_temp] mean 3*std)] # 4. 数据格式标准化 # 例如天气现象字段可能有‘晴’‘晴天’‘Sunny’需要统一 weather_mapping {晴天: 晴, Sunny: 晴, 多云: 多云, Cloudy: 多云, 小雨: 小雨} df[weather] df[weather].map(weather_mapping).fillna(df[weather]) # 映射已知的未知的保留原值 # 风力字段可能包含‘3-4级’需要提取数字 df[wind_force_num] df[wind_force].str.extract(r(\d)).astype(float) # 5. 创建衍生特征特征工程初步 df[temp_range] df[high_temp] - df[low_temp] # 日温差 # 将天气现象转换为类别编码或独热编码为建模准备 df[weather_encoded] pd.Categorical(df[weather]).codes # 或者使用独热编码如果类别不多 # weather_dummies pd.get_dummies(df[weather], prefixweather) # df pd.concat([df, weather_dummies], axis1) print(\n清洗后的数据信息) print(df.info()) print(df[[date, high_temp, low_temp, weather, temp_range]].head())4.3 可视化探查数据质量与分布可视化能帮助我们直观发现问题。# 设置绘图风格 sns.set_style(whitegrid) # 1. 检查温度随时间的变化趋势同时查看缺失和异常 plt.figure(figsize(15, 5)) plt.subplot(1, 2, 1) plt.plot(df[date], df[high_temp], labelHigh Temp, markero, markersize2, linewidth0.5) plt.plot(df[date], df[low_temp], labelLow Temp, markers, markersize2, linewidth0.5) plt.xlabel(Date) plt.ylabel(Temperature (°C)) plt.title(Daily Temperature Trend (Raw)) plt.legend() plt.xticks(rotation45) # 2. 查看最高温度的分布直方图 plt.subplot(1, 2, 2) sns.histplot(df[high_temp], kdeTrue, bins20) plt.xlabel(High Temperature (°C)) plt.ylabel(Frequency) plt.title(Distribution of High Temperature) plt.tight_layout() plt.show() # 3. 检查缺失值分布使用热图 plt.figure(figsize(10, 4)) sns.heatmap(df.isnull(), cbarFalse, cmapviridis, yticklabelsFalse) plt.title(Missing Values Heatmap) plt.show() # 4. 查看天气现象的频次 plt.figure(figsize(8, 5)) weather_counts df[weather].value_counts() sns.barplot(xweather_counts.index, yweather_counts.values) plt.xlabel(Weather Phenomenon) plt.ylabel(Count) plt.title(Frequency of Weather Types) plt.xticks(rotation45) plt.show()通过以上步骤我们不仅清洗了数据还对数据的分布、质量和特征有了深入的了解为后续的机器学习建模打下了坚实的基础。5. 基于机器学习的天气分析与预测数据准备就绪后我们就可以进入核心的机器学习环节。这里我们设定一个具体的预测任务利用前N天的天气数据预测未来第M天的最高温度。这是一个经典的时序回归问题。5.1 问题定义与特征工程我们预测的是未来某一天t1天的最高温度。因此特征X可以选取过去几天t, t-1, t-2, ...的各类天气数据标签y就是t1天的最高温度。# 假设我们想用过去3天的数据预测下一天的最高温 look_back 3 forecast_ahead 1 features [] labels [] # 确保数据按日期排序 df_sorted df.sort_values(date).reset_index(dropTrue) for i in range(look_back, len(df_sorted) - forecast_ahead): # 提取过去look_back天的特征 past_features [] for j in range(look_back): idx i - look_back j # 选择你认为有用的特征这里以温度和天气编码为例 row df_sorted.iloc[idx] past_features.extend([ row[high_temp], row[low_temp], row[temp_range], row[weather_encoded], # 使用编码后的天气 row[wind_force_num] if not pd.isna(row[wind_force_num]) else 0 ]) features.append(past_features) # 标签是未来forecast_ahead天的最高温 labels.append(df_sorted.iloc[i forecast_ahead][high_temp]) X np.array(features) y np.array(labels) print(f特征矩阵 X 的形状: {X.shape}) # (样本数, look_back * 每天特征数) print(f标签向量 y 的形状: {y.shape})特征工程思考时序特征我们手动构造了滞后特征lag features这是处理时序预测问题的基本方法。领域特征除了原始数据我们加入了计算出的temp_range日温差这可能是一个重要特征。周期性特征还可以加入monthday_of_week的sin/cos编码以捕捉季节性和周周期性。天气类别处理天气现象是分类变量我们使用了简单的标签编码Categorical().codes。对于线性模型更好的做法是使用独热编码One-Hot Encoding但对于树模型如随机森林标签编码通常也可以。5.2 模型选择、训练与评估我们尝试几种经典的回归模型并比较其性能。from sklearn.model_selection import train_test_split, cross_val_score from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression, Ridge from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score # 1. 划分训练集和测试集注意时序数据不能随机打乱 # 我们按时间顺序划分前80%作为训练后20%作为测试 split_idx int(len(X) * 0.8) X_train, X_test X[:split_idx], X[split_idx:] y_train, y_test y[:split_idx], y[split_idx:] print(f训练集大小: {X_train.shape}, 测试集大小: {X_test.shape}) # 2. 特征标准化对线性模型很重要对树模型非必须但无害 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 3. 初始化模型 models { 线性回归: LinearRegression(), 岭回归 (Ridge): Ridge(alpha1.0), # 加入L2正则化防止过拟合 随机森林: RandomForestRegressor(n_estimators100, random_state42, n_jobs-1) } # 4. 训练、预测并评估 results {} for name, model in models.items(): model.fit(X_train_scaled, y_train) y_pred model.predict(X_test_scaled) mae mean_absolute_error(y_test, y_pred) rmse np.sqrt(mean_squared_error(y_test, y_pred)) r2 r2_score(y_test, y_pred) results[name] {MAE: mae, RMSE: rmse, R2: r2} print(f\n{name}:) print(f 平均绝对误差 (MAE): {mae:.2f}°C) print(f 均方根误差 (RMSE): {rmse:.2f}°C) print(f 决定系数 (R²): {r2:.4f}) # 5. 可视化预测结果 vs 真实值 best_model_name min(results, keylambda x: results[x][MAE]) # 选择MAE最小的模型 best_model models[best_model_name] best_model.fit(X_train_scaled, y_train) y_pred_best best_model.predict(X_test_scaled) plt.figure(figsize(12, 6)) plt.plot(range(len(y_test)), y_test, labelTrue Temperature, markero, linewidth1) plt.plot(range(len(y_test)), y_pred_best, labelfPredicted ({best_model_name}), markerx, linewidth1, alpha0.7) plt.xlabel(Test Sample Index) plt.ylabel(High Temperature (°C)) plt.title(fWeather Temperature Prediction - {best_model_name}) plt.legend() plt.grid(True, linestyle--, alpha0.5) plt.show() # 6. 分析特征重要性对于随机森林 if hasattr(best_model, feature_importances_): importances best_model.feature_importances_ feature_names [fLag{i1}_Feature{j1} for i in range(look_back) for j in range(5)] # 根据实际特征数调整 feat_imp_df pd.DataFrame({feature: feature_names, importance: importances}) feat_imp_df feat_imp_df.sort_values(importance, ascendingFalse) plt.figure(figsize(10, 6)) sns.barplot(ximportance, yfeature, datafeat_imp_df.head(15)) # 看最重要的15个 plt.title(Top 15 Feature Importances (Random Forest)) plt.tight_layout() plt.show()模型选择解读线性回归 / 岭回归作为基线模型简单、可解释性强。如果特征与目标存在近似线性关系它们可能表现不错。岭回归通过正则化能缓解过拟合。随机森林集成学习模型能捕捉非线性关系对异常值不敏感通常能取得比线性模型更好的性能也提供了特征重要性评估。为什么不用更复杂的LSTM对于单变量或多变量时序预测循环神经网络如LSTM确实是强大工具。但对于入门级项目且数据量可能不大的情况下传统机器学习模型更容易训练、调参和解释作为起点更合适。你完全可以在后续进阶中尝试LSTM。5.3 模型优化思路与调参如果对初步结果不满意可以从以下几个方面优化特征工程尝试不同的look_back回顾天数。加入更多衍生特征前几天的平均温度、温度变化率、滑动窗口统计量均值、标准差。更精细地处理天气现象比如将“小雨转多云”拆分为两个特征。加入节假日、季节sin/cos编码等外部特征。模型调参对于随机森林可以调整n_estimators树的数量、max_depth树的最大深度、min_samples_split内部节点再划分所需最小样本数等。使用GridSearchCV或RandomizedSearchCV进行自动化超参数搜索。尝试其他模型梯度提升树如XGBoost, LightGBM通常在表格数据上表现优异。也可以尝试简单的神经网络MLP。交叉验证使用时间序列交叉验证TimeSeriesSplit来更可靠地评估模型性能避免信息泄露。6. 项目总结与扩展思考走完从爬虫到建模的整个流程你会发现一个完整的机器学习项目远不止调包和跑算法。数据获取的艰辛、数据清洗的繁琐往往占据了项目大部分时间但也正是这些工作决定了模型效果的上限。我个人在带学生做这类项目时最深的体会是一定要先明确分析或预测的目标然后根据目标去反推需要什么样的数据再设计爬虫方案。很多同学本末倒置先爬一堆数据再想能做什么结果往往发现数据不符合需求。例如如果你的目标是分析“雾霾与气象条件的关系”那么爬虫时就必须确保包含AQI和PM2.5等关键字段。关于项目扩展这里有几个方向供你参考分析维度深化不局限于温度预测。可以分析重庆的“雾日”与湿度、风速、气压的关系可以研究夏季高温热浪的持续时间和强度变化可以做空气质量AQI的预测。爬虫系统化将爬虫脚本部署到云服务器使用APScheduler或Celery实现每日定时自动爬取、数据入库、异常报警构建一个微型的数据管道。可视化仪表盘使用Plotly Dash或Streamlit快速搭建一个交互式Web仪表盘展示重庆天气的历史趋势、实时状态和模型预测结果让项目成果更直观。模型服务化将训练好的最佳模型用Flask或FastAPI包装成一个简单的REST API提供“根据过去几天天气预测明日高温”的在线服务。最后务必整理好你的源代码、文档说明和数据集。文档说明README.md至少应包括项目简介、环境依赖requirements.txt、如何运行爬虫、如何运行分析脚本、关键结果展示。一个结构清晰、文档齐全的项目仓库是你能力最好的证明。这个“重庆天气分析”项目完全可以成为你简历或作品集中一个亮眼的、体现全栈数据技能的实际案例。本文还有配套的精品资源点击获取