简介:这是一份面向计算机、电子信息工程及数学类专业本科生的机器学习综合实践资源,聚焦真实场景下的数据获取与分析闭环:从爬取重庆历史天气与空气质量数据,到完成质量趋势建模与可视化分析。资源包含6个核心文件(3个Python脚本+3个Excel数据表),总大小仅369KB,轻量易部署——其中爬虫脚本(QualitySpider.py、ReadCQWeather.py)支持参数化配置城市与时间范围,预测脚本(Prediction.py)封装基础时序分析逻辑,配套Excel文件涵盖原始爬取数据、清洗合并结果及空气质量指标,结构清晰、用途明确。已有367人下载学习,适合作为课程设计、期末大作业或毕业设计的参考范例。所有代码均经实测运行通过,注释详尽、思路分层,附带完整执行结果截图,便于理解数据流向与算法落地过程;作者为具备十年算法仿真经验的大厂工程师,内容兼顾工程规范性与教学可读性。
1. 项目缘起:从一份作业到一个完整的数据分析项目
最近在整理过往项目时,翻到了一个挺有意思的“老古董”——一个关于重庆天气数据爬取与分析的机器学习作业。说它老,是因为代码和思路现在看来有些稚嫩;说它有意思,是因为这个项目麻雀虽小,五脏俱全,完整地走了一遍从数据获取、清洗、分析到可视化的全流程,非常适合刚接触数据科学或者想找个练手项目的朋友。
这个项目的核心目标很明确:获取重庆地区的历史天气数据,并尝试用一些基础的机器学习方法,对空气质量进行简单的分析和预测。听起来是不是有点像 Kaggle 上的入门竞赛?没错,它的本质就是一个微缩版的、有明确地域指向的数据分析项目。对于学生党来说,这是一个绝佳的课程作业或毕业设计选题;对于职场新人或转行朋友,这也是一个能写在简历里、体现实操能力的完整案例。
为什么是重庆?一方面,山城独特的地理环境和气候特征,让它的天气数据(尤其是空气质量)分析变得有挑战性,也更有趣。另一方面,公开、稳定、结构化的天气数据源相对好找,降低了项目启动的门槛。整个项目会涉及到几个关键环节:Python 网络爬虫负责从公开网站抓取原始数据;Pandas 和 NumPy进行数据清洗与预处理;Matplotlib 和 Seaborn完成探索性数据分析和可视化;最后,Scikit-learn中的一些经典模型会登场,尝试对空气质量等级进行分类或预测。
接下来,我会把这个项目的完整实现过程拆解开,包括当初踩过的坑、做出的取舍,以及事后回看可以优化的地方。无论你是想复现这个项目,还是借鉴其中的思路应用到其他城市或领域,相信都能有所收获。我们不仅会看到代码怎么写,更重要的是理解为什么这么写,以及在实际操作中可能会遇到什么。
2. 数据基石:如何稳定、合规地爬取重庆天气数据
数据是分析的血液。第一步,也是最关键的一步,就是获取可靠、连续、字段丰富的重庆天气历史数据。市面上有很多提供天气数据的平台,有收费的API,也有免费的公开页面。对于学习项目,我们当然优先考虑后者。
2.1 目标网站分析与请求策略
当初我选择的是一个大型气象数据网站的“历史天气”查询页面。这类页面通常通过城市和日期参数来动态加载数据。我们的目标是爬取重庆主城区过去几年的逐日天气数据,包括日期、最高/最低气温、天气状况、风向风力、空气质量指数(AQI)及等级等。
第一步是分析网页请求。打开浏览器的开发者工具(F12),切换到 Network(网络)标签,然后查询某一天重庆的天气。你会发现,数据很可能不是直接嵌在初始HTML里的,而是通过一个额外的XHR(异步)请求获取的。这个请求的URL、请求方法(通常是GET或POST)、以及携带的参数(如城市代码cityCode、日期date)就是我们爬虫需要模拟的关键。
这里有个重要的经验:务必仔细检查请求头(Headers)。除了常见的User-Agent(模拟浏览器),有些网站会校验Referer(来源页)或使用Cookie进行会话管理。直接请求数据接口而不携带这些信息,很可能返回空数据或错误页面。我的做法是,把浏览器中成功请求到的所有Headers信息,有选择地复制到爬虫的请求头字典里。
import requests import pandas as pd from datetime import datetime, timedelta import time 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', 'Referer': 'https://www.目标网站.com/weather/101040100.shtml', # 示例,需替换 # 可能还有其他必要的头信息,如 Accept, Accept-Language 等 } def fetch_single_day(city_code, query_date): """抓取指定城市单日天气数据""" url = "https://api.目标网站.com/数据接口路径" # 示例,需替换为真实接口 params = { 'city': city_code, 'date': query_date.strftime('%Y-%m-%d') } try: response = requests.get(url, headers=headers, params=params, timeout=10) response.raise_for_status() # 检查HTTP错误 # 假设返回的是JSON格式 data = response.json() return parse_weather_data(data) # 解析函数,将JSON转为字典 except requests.exceptions.RequestException as e: print(f"请求{query_date}数据失败: {e}") return None except ValueError as e: print(f"解析{query_date}的JSON数据失败: {e}") return None2.2 循环抓取与友好访问
我们需要爬取多日数据,这就需要一个循环。但切记,不要用for循环无间隔地狂发请求,这会被网站视为攻击,导致IP被暂时封禁。必须设置延迟。
def fetch_date_range(city_code, start_date, end_date): """抓取指定日期范围内的数据""" current_date = start_date all_data = [] while current_date <= end_date: daily_data = fetch_single_day(city_code, current_date) if daily_data: all_data.append(daily_data) print(f"成功获取 {current_date} 数据") else: print(f"跳过 {current_date},数据获取失败") # 关键:设置延迟,模拟人类操作。时间间隔可以随机化,更友好。 time.sleep(2 + random.random()) # 随机延迟2-3秒 current_date += timedelta(days=1) return pd.DataFrame(all_data)延迟时间(如2-3秒)是一个平衡艺术。太短有风险,太长效率低。对于学习项目,数据量不大(比如抓一年365条),慢一点更稳妥。此外,可以考虑使用random.uniform(1.5, 4)来让延迟时间随机化,进一步降低被识别为机器人的概率。
2.3 数据解析与字段提取
接口返回的数据结构需要仔细解析。通常是一个嵌套的JSON。我们需要从中提取出有用的字段,并转换成平坦的、适合表格存储的结构。
def parse_weather_data(raw_json): """解析原始JSON,提取所需字段""" # 这是一个示例解析逻辑,实际结构需根据目标网站调整 try: day_data = raw_json['data'][0] # 假设数据在data列表的第一个元素 parsed = { 'date': day_data.get('date'), 'high_temp': day_data.get('tempHigh'), # 最高温 'low_temp': day_data.get('tempLow'), # 最低温 'weather_day': day_data.get('dayWeather'), # 白天天气 'weather_night': day_data.get('nightWeather'), # 夜间天气 'wind_dir_day': day_data.get('dayWindDir'), # 白天风向 'wind_force_day': day_data.get('dayWindPower'), # 白天风力 'aqi': day_data.get('aqi'), # 空气质量指数 'aqi_level': day_data.get('quality'), # 空气质量等级(如:优、良) 'pm25': day_data.get('pm25') # PM2.5浓度 } # 处理可能的缺失值或异常值,例如‘-’代表无数据 for key, value in parsed.items(): if value == '-' or value == '': parsed[key] = None return parsed except (KeyError, IndexError, TypeError) as e: print(f"解析数据结构时出错: {e}, 原始数据: {raw_json}") return None解析环节最容易出错。网站的数据结构可能微调,字段名可能变化。因此,异常捕获(try-except)和日志打印至关重要。它能让你的爬虫在遇到意外数据格式时不至于崩溃,而是跳过该条记录并告诉你哪里出了问题,便于后续排查。
2.4 数据存储与增量更新
抓取到的DataFrame应及时保存到本地,推荐使用CSV格式,因为它易于用文本编辑器查看,也方便Pandas再次读取。
# 假设 df 是 fetch_date_range 返回的 DataFrame if not df.empty: file_name = f'chongqing_weather_{start_date}_{end_date}.csv' df.to_csv(file_name, index=False, encoding='utf-8-sig') # utf-8-sig 解决Excel打开中文乱码 print(f"数据已保存至 {file_name}") else: print("未获取到有效数据,未保存文件。")对于需要长期维护的数据集,可以考虑实现增量爬虫。即每次运行时,先读取本地已存在的数据文件,找出最新的日期,然后只爬取该日期之后的新数据,再合并保存。这能节省时间和网络资源,也是对目标网站更友好的做法。
3. 数据清洗与预处理:从原始数据到分析就绪
爬虫抓回来的数据通常是“脏”的,直接用于分析会问题百出。数据清洗(Data Cleaning)是数据分析中耗时最长、也最考验耐心的环节。
3.1 缺失值处理:AQI数据的常见坑
天气数据中,缺失值很常见。尤其是AQI和PM2.5数据,可能因为监测站点故障或数据传输问题,在某些日期完全缺失。
首先用Pandas加载数据并查看概况:
import pandas as pd import numpy as np df = pd.read_csv('chongqing_weather_20220101_20231231.csv') print(df.info()) # 查看各字段非空数量、类型 print(df.isnull().sum()) # 统计各字段缺失值数量处理缺失值有多种策略:
- 删除:如果某一行关键字段(如日期、AQI)缺失,且缺失量很少(<5%),可以直接删除该行。
df.dropna(subset=['aqi', 'pm25'], inplace=True) - 填充:对于数值型数据(如温度),可以用前后几天的平均值(移动平均)或中位数来填充。
df['high_temp'].fillna(df['high_temp'].rolling(3, min_periods=1).mean(), inplace=True) - 标记:对于分类数据(如天气状况),可以创建一个新的类别如“未知”来填充。
df['weather_day'].fillna('未知', inplace=True) - 不处理(针对模型):有些机器学习算法(如XGBoost)可以原生处理缺失值。但更多时候,我们需要先处理。
我的经验是,对于AQI这类核心分析目标,如果某天完全缺失,且无法通过可靠方法插补,宁愿删除该条记录,也不要随意填充,以免引入噪音,影响后续分析的结论可靠性。
3.2 异常值检测与修正
异常值可能是真实的极端天气,也可能是数据错误。例如,重庆夏季最高温超过45度?冬季最低温低于-5度?这需要结合常识和重庆的气候特点来判断。
# 通过描述性统计和可视化发现异常 print(df[['high_temp', 'low_temp', 'aqi']].describe()) import matplotlib.pyplot as plt plt.figure(figsize=(12,4)) plt.subplot(131) df['high_temp'].hist(bins=50) plt.title('最高温分布') plt.subplot(132) df['low_temp'].hist(bins=50) plt.title('最低温分布') plt.subplot(133) df['aqi'].hist(bins=50) plt.title('AQI分布') plt.tight_layout() plt.show()发现异常值后,处理方法包括:
- 盖帽法(Capping):将超出合理范围的值替换为边界值。例如,设定最高温上限为42度,下限为-2度。
df['high_temp'] = df['high_temp'].clip(lower=-2, upper=42) - 视为缺失值处理:将明显错误的值(如温度999)替换为
NaN,然后按缺失值方法处理。 - 结合上下文修正:如果某天温度异常,但天气描述是“晴”,可以查看前后几天的温度,用插值法修正。
3.3 特征工程:创造更有价值的输入
原始数据字段有时不能直接用于模型。我们需要通过特征工程(Feature Engineering)创造新的、对预测目标更有帮助的特征。
- 日期特征提取:日期本身是字符串或时间戳,但其中蕴含周期性信息。
df['date'] = pd.to_datetime(df['date']) df['year'] = df['date'].dt.year df['month'] = df['date'].dt.month df['day_of_month'] = df['date'].dt.day df['day_of_week'] = df['date'].dt.dayofweek # 周一=0,周日=6 df['is_weekend'] = df['day_of_week'].apply(lambda x: 1 if x >=5 else 0) df['season'] = df['month'].apply(lambda m: (m%12 + 3)//3) # 1:春,2:夏,3:秋,4:冬 - 温差特征:
df['temp_range'] = df['high_temp'] - df['low_temp']。昼夜温差可能对空气质量有影响。 - 滞后特征(Lag Features):今天的空气质量很可能和昨天、前天有关。
df['aqi_lag1'] = df['aqi'].shift(1) # 前一天的AQI df['aqi_lag2'] = df['aqi'].shift(2) # 前两天的AQI - 分类数据编码:天气状况(晴、多云、雨)、风向(北风、东南风)是文本,需要转为数值。
- 标签编码(Label Encoding):适用于有大小顺序的类别(如空气质量等级:优<良<轻度污染...)。
from sklearn.preprocessing import LabelEncoder - 独热编码(One-Hot Encoding):适用于无序类别(如天气状况)。
pd.get_dummies(df, columns=['weather_day', 'wind_dir_day'])。注意这可能造成特征维度爆炸,对于类别很多的字段要谨慎。
- 标签编码(Label Encoding):适用于有大小顺序的类别(如空气质量等级:优<良<轻度污染...)。
特征工程是提升模型性能的关键,但也最容易导致过拟合。创造的特征一定要有业务或物理意义,并且需要在训练集上完成拟合(如计算平均值、编码映射),再应用到测试集,避免数据泄露。
4. 探索性数据分析:用可视化洞察重庆天气与空气质量
在把数据喂给模型之前,我们必须先“看”懂它。探索性数据分析(EDA)能帮助我们理解数据分布、发现规律、验证假设,并为后续的模型选择提供依据。
4.1 空气质量的时间序列趋势
首先,我们最关心的是AQI随时间的变化。
plt.figure(figsize=(15,5)) plt.plot(df['date'], df['aqi'], linewidth=0.5, alpha=0.7) plt.axhline(y=100, color='r', linestyle='--', alpha=0.5, label='AQI=100 (良/轻度污染边界)') plt.xlabel('日期') plt.ylabel('AQI') plt.title('重庆日度AQI时间序列趋势') plt.legend() plt.grid(True, alpha=0.3) plt.show()从图中,你可以直观地看到:重庆的空气质量是否存在明显的季节性规律?(例如,冬季是否因扩散条件差而AQI更高?)是否有长期改善或恶化的趋势?极端污染事件发生在什么时候?
为了更清晰地观察季节性,我们可以按月份聚合:
monthly_avg = df.groupby('month')['aqi'].mean() plt.figure(figsize=(10,4)) monthly_avg.plot(kind='bar', color='skyblue') plt.axhline(y=100, color='r', linestyle='--', alpha=0.5) plt.xlabel('月份') plt.ylabel('月均AQI') plt.title('重庆月均AQI分布(多年平均)') plt.xticks(rotation=0) plt.grid(axis='y', alpha=0.3) plt.show()4.2 气象要素与空气质量的相关性分析
空气质量受多种气象因素影响。我们可以计算相关系数矩阵,并用热图可视化。
# 选择数值型特征 numeric_features = ['high_temp', 'low_temp', 'temp_range', 'pm25', 'aqi', 'month', 'day_of_week'] corr_matrix = df[numeric_features].corr() import seaborn as sns plt.figure(figsize=(10,8)) sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='coolwarm', center=0, square=True) plt.title('气象要素与AQI相关性热图') plt.tight_layout() plt.show()重点关注AQI这一列。你可能会发现:
pm25与aqi高度正相关(这是显然的,PM2.5是AQI的主要组分)。temp_range(温差)可能与aqi呈负相关?较大的昼夜温差有时意味着大气垂直对流较强,有利于污染物扩散。month与aqi的相关性,印证了之前的季节性观察。
注意:相关性不等于因果关系。热图展示的是线性相关关系。更深层的影响可能需要通过更复杂的统计模型或领域知识来解释。
4.3 不同天气状况下的空气质量对比
天气状况(晴、雨、多云等)对空气质量有直接影响。我们可以用箱型图来观察不同天气下AQI的分布差异。
# 假设我们已经对 `weather_day` 进行了归类,合并了相似类别(如‘小雨’、‘中雨’合并为‘雨’) plt.figure(figsize=(12,6)) order = df.groupby('weather_day')['aqi'].median().sort_values().index # 按中位数排序 sns.boxplot(x='weather_day', y='aqi', data=df, order=order) plt.axhline(y=100, color='r', linestyle='--', alpha=0.5) plt.xlabel('白天天气状况') plt.ylabel('AQI') plt.title('不同天气状况下AQI分布对比') plt.xticks(rotation=45) plt.tight_layout() plt.show()箱型图可以告诉我们:雨天是否普遍对应更低的AQI?多云和晴天的空气质量中位数有何差异?不同天气状况下,AQI的波动范围(箱子的高度)有多大?这些直观的观察能为后续的建模提供特征选择的方向,例如,是否将“天气状况”作为一个重要的分类特征引入模型。
5. 机器学习模型初探:预测空气质量等级
经过充分的EDA,我们对数据有了感性认识。现在,可以尝试构建一个简单的机器学习模型,来预测重庆的空气质量等级(例如,二分类:“良及以下” vs “轻度污染及以上”,或多分类:优、良、轻度污染等)。
5.1 问题定义与数据准备
我们将问题定义为监督学习中的分类问题。
- 目标变量(Label):空气质量等级(
aqi_level),需要从文本(如“优”、“良”)转换为数值标签(如0,1,2...)。 - 特征变量(Features):选择与目标可能相关的特征,如月份、最高温、最低温、温差、前一天AQI、天气状况(编码后)、风向(编码后)等。
首先,准备特征X和标签y,并划分训练集和测试集。务必注意:时间序列数据不能随机划分!如果随机打乱,模型可能会用“未来”的数据来学习预测“过去”,造成数据泄露,得到过于乐观的评估结果。正确的做法是按时间顺序划分,例如用前80%的数据做训练,后20%做测试。
from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler, LabelEncoder # 1. 准备特征和标签 feature_cols = ['month', 'high_temp', 'low_temp', 'temp_range', 'aqi_lag1', 'weather_day_encoded', 'wind_dir_encoded'] # 假设已创建了编码后的特征列 ‘weather_day_encoded’ 和 ‘wind_dir_encoded’ X = df[feature_cols].dropna() # 删除因创建滞后特征而产生的初始行NA y = df.loc[X.index, 'aqi_level_encoded'] # 对应的标签,也已编码 # 2. 按时间顺序划分(假设数据已按日期排序) split_idx = int(len(X) * 0.8) X_train, X_test = X.iloc[:split_idx], X.iloc[split_idx:] y_train, y_test = y.iloc[:split_idx], y.iloc[split_idx:] # 3. 特征标准化(对基于距离的模型如SVM、KNN很重要) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) # 只在训练集上拟合scaler X_test_scaled = scaler.transform(X_test) # 用训练集的参数转换测试集5.2 模型选择与训练
对于入门级的分类问题,我们可以尝试几种经典算法,比较它们的性能。
from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report, confusion_matrix models = { 'Logistic Regression': LogisticRegression(max_iter=1000, random_state=42), 'Decision Tree': DecisionTreeClassifier(random_state=42), 'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42), 'SVM': SVC(kernel='rbf', random_state=42) } results = {} for name, model in models.items(): model.fit(X_train_scaled, y_train) y_pred = model.predict(X_test_scaled) acc = accuracy_score(y_test, y_pred) results[name] = acc print(f"{name} 准确率: {acc:.4f}") # 打印更详细的评估报告 print(classification_report(y_test, y_pred, target_names=['优','良','轻度污染'])) # 假设是三类 print("-"*50)为什么选择这几个模型?
- 逻辑回归:基线模型,简单、可解释性强,适合线性可分问题。
- 决策树:非线性,能捕捉特征交互,但容易过拟合。
- 随机森林:决策树的集成,通过“投票”降低过拟合风险,通常表现稳健,是很好的基准模型。
- 支持向量机(SVM):在高维空间寻找最优分类边界,对特征缩放敏感(所以我们做了标准化)。
5.3 模型评估与特征重要性分析
准确率只是一个宏观指标。对于类别不平衡的数据集(比如“优”和“良”的天数远多于“污染”天数),我们需要看更细化的指标:精确率(Precision)、召回率(Recall)和F1-score。classification_report已经提供了这些。
对于随机森林这类模型,我们还可以查看特征重要性,这能帮助我们理解模型是如何做决策的,并可能指导我们进行特征筛选。
# 以随机森林为例 rf_model = models['Random Forest'] importances = rf_model.feature_importances_ feature_names = X_train.columns importance_df = pd.DataFrame({'feature': feature_names, 'importance': importances}).sort_values('importance', ascending=False) plt.figure(figsize=(10,6)) plt.barh(importance_df['feature'], importance_df['importance']) plt.xlabel('特征重要性') plt.title('随机森林模型特征重要性排序') plt.gca().invert_yaxis() # 最重要的在顶部 plt.tight_layout() plt.show()你可能会发现,aqi_lag1(前一天的AQI)是最重要的特征,这符合空气污染具有连续性的常识。month(月份)和temp_range(温差)也可能排名靠前。如果某些特征重要性几乎为0,可以考虑在后续迭代中移除它们,简化模型。
5.4 常见陷阱与调优思路
- 过拟合(Overfitting):模型在训练集上表现完美,在测试集上却很差。决策树尤其容易过拟合。对策:使用随机森林;对决策树进行剪枝(设置
max_depth,min_samples_split等参数);增加训练数据量。 - 类别不平衡(Class Imbalance):如果“污染”天数很少,模型可能倾向于总是预测“非污染”,导致对污染天的召回率极低。对策:使用
class_weight='balanced'参数(如果模型支持);对少数类进行过采样(如SMOTE算法);或使用更适合的评估指标(如AUC-ROC)。 - 数据泄露(Data Leakage):这是我们反复强调的。除了时间划分错误,另一个常见泄露是在整个数据集上做特征缩放或编码后再划分。务必确保所有预处理步骤(
fit)只使用训练集数据。 - 超参数调优:模型的默认参数不一定最优。可以使用
GridSearchCV或RandomizedSearchCV进行网格搜索或随机搜索,寻找最佳参数组合。但要注意,交叉验证也要按时间序列的方式进行(如TimeSeriesSplit),不能打乱数据。
这个机器学习环节的目的,不在于构建一个预测精度极高的复杂模型,而在于完整地走通一个数据分析流程,理解每个步骤的意义和潜在问题。对于天气预测这种受复杂系统影响的任务,简单的模型往往能提供一个不错的基线,并帮助我们量化不同因素对空气质量的影响程度。
6. 项目总结与扩展思考
回顾这个“重庆天气质量分析”项目,它从一个简单的数据抓取需求开始,逐步深入到数据清洗、探索分析,并最终尝试用机器学习模型去理解和预测空气质量。整个过程,更像是一个标准的数据科学微型工作流的演练。
几个关键的实操心得:
- 爬虫的稳健性高于效率:对于学习或小规模项目,爬虫代码的健壮性(完善的错误处理、日志记录、友好延迟)比极限速度重要得多。一次成功的、完整的数据抓取,胜过多次因被封禁而中断的快速抓取。
- EDA是模型的指路明灯:跳过EDA直接建模是危险的。可视化图表和相关性分析不仅能帮你发现数据问题,更能形成对问题的直觉,指导特征工程和模型选择。例如,通过时间序列图发现季节性,你就会想到加入“月份”特征。
- 理解评估指标背后的意义:准确率90%听起来很高,但如果你的数据中90%都是“良”,一个总是预测“良”的傻瓜模型也能达到90%准确率。因此,必须结合混淆矩阵、精确率、召回率等指标综合判断模型在每一类上的表现。
- 从简单模型开始:逻辑回归或随机森林作为基线模型非常合适。它们训练快,可解释性强。在基线模型表现不佳时,再去尝试更复杂的模型(如梯度提升树、神经网络)才有意义。永远记住“没有免费的午餐”定理,复杂模型不一定更好。
这个项目还可以如何扩展?
- 更丰富的特征:引入更多气象数据,如湿度、气压、降水量、风速等。甚至可以尝试加入节假日信息、前几天的污染累积效应等。
- 更复杂的模型:尝试使用LSTM(长短期记忆网络)等时序模型来捕捉空气质量的长周期依赖关系。
- 预测目标变化:不预测等级,而是回归预测具体的AQI数值。或者预测未来多天的空气质量(多步预测)。
- 部署为简单应用:使用
Flask或Streamlit搭建一个简单的Web应用,输入日期,输出该日空气质量的预测结果和可视化图表。
最后,这个项目所有的源代码、清洗后的数据集、详细的文档说明(包括环境配置、步骤解读、遇到的问题及解决方案),都应该妥善整理和归档。这不仅是为了作业提交,更是为了你日后回顾、复用或向他人展示时,能快速理解当时的思路。一个好的数据项目,其价值一半在分析结果,另一半则在可复现、可理解的工程实现过程中。
本文还有配套的精品资源,点击获取