云计算实验2 -重庆天气数据爬取与空气质量预测系统实验报告

重庆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曲线的可视化图像。")

本技术内容仅供学习和交流使用,如有疑问请联系qq2014160588并注明来意。请确保在使用过程中遵守相关法律法规。任何因使用本技术内容而导致的直接或间接损失,作者概不负责。用户需自行承担因使用本技术内容而产生的所有风险和责任。请勿将本技术内容用于任何非法用途。
上一篇
下一篇