

重庆2022-2024年天气数据分析实验报告
一、实验目的
1.1 技术目标
- 掌握使用Python进行网络爬虫的技术,从指定网站爬取重庆2022-2024年的天气数据。
- 学习数据预处理方法,包括处理缺失值、标准化数值特征和编码分类变量。
- 应用机器学习算法(逻辑回归、随机森林、支持向量机)进行空气质量分类预测。
- 熟悉模型评估方法,生成混淆矩阵、ROC曲线,并分析模型性能。
1.2 实践目标
- 提升数据分析能力,整合爬虫、预处理和机器学习的全流程。
- 通过可视化工具(混淆矩阵、ROC曲线)直观展示模型效果。
- 总结实验中的问题并提出改进方案,培养解决实际问题的能力。
二、实验要求
2.1 数据采集
- 从
tianqi.2345.com爬取重庆2022-2024年的天气数据,包括日期、最高温度、最低温度、天气状况和空气质量。 - 数据保存为CSV文件,使用
utf-8-sig编码,确保中文字符无乱码。
2.2 数据处理
- 处理缺失值,数值型特征用均值填充,分类变量用众数填充。
- 标准化温度特征,编码天气和空气质量为数值。
2.3 模型训练与评估
- 使用逻辑回归、随机森林和支持向量机三种模型进行空气质量预测。
- 计算准确率、精确率、召回率和ROC曲线(若为二分类)。
- 生成并保存混淆矩阵和ROC曲线的可视化图像。
2.4 报告内容
- 提供详细的实验报告,包含代码、结果分析和问题解决。
- 使用Markdown格式,结构清晰,包含多级标题和无序列表。
三、开发环境
3.1 硬件环境
- 操作系统:Windows 10
- CPU:Intel Core i5 或更高
- 内存:8GB 或更高
3.2 软件环境
- 编程语言:Python 3.8+
- 开发工具:PyCharm / Jupyter Notebook
- 主要库:
requests:发送HTTP请求,爬取网页数据BeautifulSoup:解析HTML,提取表格数据pandas:数据处理与CSV保存numpy:数值计算scikit-learn:机器学习模型训练与评估matplotlib&seaborn:数据可视化
- 数据源:
https://tianqi.2345.com/wea_history/57516.htm(假设URL,需验证)
四、实验内容及代码
4.1 实验内容
4.1.1 数据爬取
- 目标:从
tianqi.2345.com获取重庆2022-2024年的天气数据。 - 方法:使用
requests发送HTTP请求,BeautifulSoup解析HTML,提取表格数据。 - 输出:保存为
chongqing_weather_2022_2024.csv。
4.1.2 数据预处理
- 清理:提取温度数字,处理缺失值。
- 编码:将天气和空气质量转换为数值。
- 标准化:对温度特征进行标准化处理。
4.1.3 模型训练
- 模型:逻辑回归、随机森林、支持向量机。
- 特征:最高温度、最低温度、天气(编码后)。
- 目标:空气质量(编码后)。
4.1.4 模型评估
- 指标:准确率、精确率、召回率、ROC AUC(若适用)。
- 可视化:混淆矩阵和ROC曲线,保存为PNG文件。
4.2 代码实现
以下是实验的核心代码,包含详细中文注释:
import requests
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import time
import os
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, roc_curve, auc
import matplotlib.pyplot as plt
import seaborn as sns
import uuid
设置请求头,模拟浏览器访问
# 设置请求头,模拟浏览器访问
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',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Connection': 'keep-alive'
}
生成2022-2024年的每月URL
# 生成2022-2024年的每月URL
def generate_month_urls():
base_url = "https://tianqi.2345.com/wea_history/57516.htm" # 假设的天气数据基础URL
# 注意:实际URL可能需要参数或不同端点,需检查网站结构
start_date = datetime(2022, 1, 1) # 起始日期
end_date = datetime(2024, 12, 31) # 结束日期
urls = []
current_date = start_date
while current_date <= end_date:
# 网站可能使用JavaScript加载数据,需找到实际数据端点
# 暂时尝试主页面并检查数据
urls.append((base_url, current_date.strftime("%Y%m")))
current_date = (current_date + timedelta(days=31)).replace(day=1) # 移到下个月
return urls
爬取单月天气数据
# 爬取单月天气数据
def scrape_month_data(url, year_month):
try:
# 发送HTTP请求
response = requests.get(url, headers=headers)
response.raise_for_status() # 检查请求是否成功
response.encoding = ‘utf-8’ # 设置编码
soup = BeautifulSoup(response.text, ‘html.parser’) # 解析HTML
# 查找数据表格(需根据实际网站调整类名)
table = soup.find(‘table’, class_=’history-table’)
if not table:
print(f”{year_month}未找到数据表格”)
return None
# 提取表格行,跳过表头
rows = table.find_all(‘tr’)[1:]
data = []
for row in rows:
cols = row.find_all(‘td’)
if len(cols) >= 4: # 根据实际列数调整
date = cols[0].text.strip() # 日期
temp_high = cols[1].text.strip() # 最高温度
temp_low = cols[2].text.strip() # 最低温度
weather = cols[3].text.strip() # 天气状况
air_quality = cols[4].text.strip() if len(cols) > 4 else ‘未知’ # 空气质量
data.append({
‘Date’: f”{year_month[:4]}-{year_month[4:]}-{date}”, # 格式化日期
‘Temp_High’: temp_high,
‘Temp_Low’: temp_low,
‘Weather’: weather,
‘Air_Quality’: air_quality
})
return data
except Exception as e:
print(f”爬取{year_month}出错: {e}”)
return None
保存数据到CSV
# 保存数据到CSV文件
def save_to_csv(data, filename='chongqing_weather_2022_2024.csv'):
df = pd.DataFrame(data) # 转换为DataFrame
df.to_csv(filename, index=False, encoding='utf-8-sig') # 使用utf-8-sig编码避免中文乱码
print(f"数据已保存至{filename}")
return df
主爬虫函数
# 主爬虫函数
def crawl_weather_data():
urls = generate_month_urls() # 获取所有月份的URL
all_data = []
for url, year_month in urls:
print(f"正在爬取{year_month}的数据")
month_data = scrape_month_data(url, year_month)
if month_data:
all_data.extend(month_data) # 合并当月数据
time.sleep(1) # 暂停1秒,避免请求过快
if all_data:
df = save_to_csv(all_data)
return df
else:
print("未收集到数据")
return None
数据预处理
# 数据预处理
def preprocess_data(df):
# 检查缺失值
print("预处理前的缺失值:")
print(df.isnull().sum())
# 提取温度中的数字并转换为浮点数
df['Temp_High'] = df['Temp_High'].str.extract(r'(\d+)').astype(float)
df['Temp_Low'] = df['Temp_Low'].str.extract(r'(\d+)').astype(float)
# 用均值填充数值型缺失值
df['Temp_High'].fillna(df['Temp_High'].mean(), inplace=True)
df['Temp_Low'].fillna(df['Temp_Low'].mean(), inplace=True)
# 用众数填充分类变量缺失值
df['Weather'].fillna(df['Weather'].mode()[0], inplace=True)
df['Air_Quality'].fillna(df['Air_Quality'].mode()[0], inplace=True)
# 编码分类变量
le_weather = LabelEncoder()
le_air_quality = LabelEncoder()
df['Weather_Encoded'] = le_weather.fit_transform(df['Weather'])
df['Air_Quality_Encoded'] = le_air_quality.fit_transform(df['Air_Quality'])
# 标准化数值特征
scaler = StandardScaler()
df[['Temp_High', 'Temp_Low']] = scaler.fit_transform(df[['Temp_High', 'Temp_Low']])
# 检查预处理后缺失值
print("预处理后的缺失值:")
print(df.isnull().sum())
return df, le_air_quality
训练和评估模型
# 训练和评估模型
def train_and_evaluate_models(df, le_air_quality):
# 选择特征和目标变量
X = df[['Temp_High', 'Temp_Low', 'Weather_Encoded']]
y = df['Air_Quality_Encoded']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 初始化模型
models = {
'逻辑回归': LogisticRegression(max_iter=1000),
'随机森林': RandomForestClassifier(n_estimators=100, random_state=42),
'支持向量机': SVC(probability=True, random_state=42)
}
# 存储评估结果
results = {}
plt.figure(figsize=(10, 8))
for name, model in models.items():
# 训练模型
model.fit(X_train, y_train)
y_pred = model.predict(X_test) # 预测
y_prob = model.predict_proba(X_test)[:, 1] if hasattr(model, 'predict_proba') else model.decision_function(X_test)
# 计算评估指标
cm = confusion_matrix(y_test, y_pred) # 混淆矩阵
accuracy = accuracy_score(y_test, y_pred) # 准确率
precision = precision_score(y_test, y_pred, average='weighted', zero_division=0) # 精确率
recall = recall_score(y_test, y_pred, average='weighted', zero_division=0) # 召回率
# ROC曲线(仅适用于二分类)
if len(np.unique(y)) == 2:
fpr, tpr, _ = roc_curve(y_test, y_prob, pos_label=1)
roc_auc = auc(fpr, tpr) # 计算AUC
plt.plot(fpr, tpr, label=f'{name} (AUC = {roc_auc:.2f})')
else:
roc_auc = '不适用'
results[name] = {
'混淆矩阵': cm,
'准确率': accuracy,
'精确率': precision,
'召回率': recall,
'ROC AUC': roc_auc
}
# 绘制混淆矩阵
plt.figure(figsize=(6, 4))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title(f'混淆矩阵 - {name}')
plt.ylabel('真实标签')
plt.xlabel('预测标签')
plt.savefig(f'confusion_matrix_{name}.png') # 保存图像
plt.close()
# 完成ROC曲线
if len(np.unique(y)) == 2:
plt.plot([0, 1], [0, 1], 'k--') # 绘制对角线
plt.xlabel('假阳性率')
plt.ylabel('真阳性率')
plt.title('ROC曲线')
plt.legend(loc='lower right')
plt.savefig('roc_curves.png') # 保存ROC曲线
plt.close()
# 打印模型评估结果
for name, metrics in results.items():
print(f"\n模型: {name}")
print(f"准确率: {metrics['准确率']:.4f}")
print(f"精确率: {metrics['精确率']:.4f}")
print(f"召回率: {metrics['召回率']:.4f}")
print(f"ROC AUC: {metrics['ROC AUC']}")
print("混淆矩阵:")
print(metrics['混淆矩阵'])
return results
主程序
# 主程序
if __name__ == "__main__":
# 步骤1:爬取数据
df = crawl_weather_data()
if df is None:
print("爬取失败,请检查网站结构或网络连接。")
exit()
# 步骤2:预处理数据
df, le_air_quality = preprocess_data(df)
# 步骤3:训练和评估模型
results = train_and_evaluate_models(df, le_air_quality)
# 步骤4:实验总结
print("\n实验总结:")
print("1. 成功爬取重庆2022-2024年天气数据。")
print("2. 通过处理缺失值和标准化特征完成数据预处理。")
print("3. 训练了三种分类模型:逻辑回归、随机森林和支持向量机。")
print("4. 使用准确率、精确率、召回率和ROC曲线评估模型。")
print("5. 保存了混淆矩阵和ROC曲线的可视化图像。")







