python小项目
项目一:全球气候温度数据可视化与趋势分析工具
项目背景
全球气候变暖是当前重要环境议题,相关温度数据的分析能直观呈现气候变化规律。本项目基于公开的全球气温数据集,开发分析工具,实现温度数据的清洗、统计与可视化,为气候相关学习与研究提供支持,贴合信息与计算科学专业 “数据处理与可视化” 的实践需求。
核心功能要求
1. 数据获取与预处理:从公开数据源(如NASA地球观测站官网https://earthobservatory.nasa.gov/提供的 “全球年均温度异常数据集”、 Kaggle 平台 “Global Temperature Time Series” 数据集)下载 CSV/Excel 格式数据,包含 “年份、全球平均温度、北半球平均温度、南半球平均温度” 等字段。对数据进行清洗,剔除缺失值、修正格式异常数据(如日期格式统一),并提取 “2020-2025 年” 关键时间段数据进行分析。
2. 趋势统计分析:计算 2020-2025 年全球平均温度的年际变化率、每年平均温度均值;对比北半球与南半球的温度变化差异,找出温度上升最显著的年份。
3. 多维度可视化:使用 Matplotlib/Seaborn 绘制 “2020-2025 年全球平均温度变化折线图”(标注温度异常峰值年份)、“南北半球温度对比柱状图(每年)”、“全球温度异常分布热力图(按年份)”;通过可视化直观呈现温度上升趋势。
4. 结果导出与报告:将统计结果(如每年温度均值表、温度变化率表)导出为 Excel 文件,将所有可视化图表保存为高清 PNG 格式;给出生成《全球气候温度趋势分析报告》(Markdown 格式),包含数据来源说明、分析结论(如 “2020-2025 年全球平均温度上升约1.1℃”)及建议。
代码包含以下8个文件:
data_loader.py:负责加载 Excel 格式的数据文件
data_extractor.py:从原始数据中提取指定时间段(默认 2020-2025 年)的数据,处理数据缺失情况
data_analyzer.py:对提取的时间段数据进行基础分析,包括计算温度趋势(上升/下降/平稳)、总变化幅度、极值(最高/最低温度及对应年份)、平均值、标准差,以及检测异常值(基于±2σ范围),并输出分析结果。
data_trend_analyzer.py:进行更深入的趋势统计分析
data_visualizer.py:提供可视化功能
data_visualizer_extend.py:扩展可视化功能
report_generator.py:生成分析结果报告
main.py:主程序入口,串联整个分析流程
以下为每个代码块的具体代码:
data_loader.py
import pandas as pd
import os
from typing import Optional
def load_excel_data(file_path: str) -> Optional[pd.DataFrame]:
"""
加载Excel数据
:param file_path: Excel文件路径
:return: 原始DataFrame或None(文件不存在时)
"""
# 1. 校验文件是否存在
if not os.path.exists(file_path):
print(f"文件 '{file_path}' 不存在")
return None
# 2. 校验文件格式
if not file_path.endswith(('.xlsx', '.xls')):
print(f"文件 '{file_path}' 不是Excel格式")
return None
try:
# 优先使用openpyxl引擎(支持.xlsx),兼容中文
df = pd.read_excel(file_path, engine='openpyxl')
print(f"成功加载数据:{file_path}")
print(f"原始数据规模:{df.shape[0]}行 × {df.shape[1]}列")
return df
except Exception as e:
print(f"读取文件失败:{str(e)}")
return None
data_extractor.py
import pandas as pd
import os
from typing import Optional
def extract_time_period(df: pd.DataFrame, start_year: int = 2020, end_year: int = 2025) -> Optional[pd.DataFrame]:
"""
提取指定时间段数据(默认2020-2025年)
:param df: 清洗后的DataFrame
:param start_year: 起始年份
:param end_year: 结束年份
:return: 时间段内的DataFrame
"""
# 校验年份列是否存在
if '年份' not in df.columns:
print("未找到'年份'列,无法提取时间段数据")
return None
# 2. 筛选目标时间段
df_extracted = df[(df['年份'] >= start_year) & (df['年份'] <= end_year)]
extracted_years = sorted(df_extracted['年份'].unique())
# 3. 处理数据不足的情况
if len(df_extracted) == 0:
print(f"无{start_year}-{end_year}年数据,将提取最近5年数据")
recent_years = sorted(df['年份'].unique())[-5:]
df_extracted = df[df['年份'].isin(recent_years)]
extracted_years = recent_years
return df_extracted
def save_extracted_data(df: pd.DataFrame, output_dir: str = 'output', filename: str = 'extracted_data.xlsx') -> bool:
"""
保存提取的时间段数据
:param df: 提取后的DataFrame
:param output_dir: 输出文件夹
:param filename: 输出文件名
:return: 保存成功返回True,失败返回False
"""
# 创建输出文件夹(不存在则创建)
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, filename)
try:
df.to_excel(output_path, index=False, engine='openpyxl')
return True
except Exception as e:
print(f"保存提取数据失败:{str(e)}")
return False
data_analyzer.py
import pandas as pd
# import numpy as np
from typing import Dict, Optional
def analyze_extracted_data(df: pd.DataFrame) -> Optional[Dict]:
"""
分析提取的时间段数据(2020-2025年)- 修复空值导致的KeyError
:param df: 提取后的DataFrame
:return: 分析结果字典(含趋势、极值、异常值等)
"""
# 基础校验:必要列存在性
required_cols = ['年份', '全年平均']
if not all(col in df.columns for col in required_cols):
print(f"缺失必要列(需包含{required_cols}),无法分析")
return None
# 2. 空值过滤:仅保留核心字段无空值的行
df_valid = df[['年份', '全年平均']].copy().dropna(subset=['年份', '全年平均'])
total_raw_rows = len(df) # 原始总行数
valid_data_rows = len(df_valid) # 有效数据行数
if valid_data_rows == 0:
print(f"有效数据为空:原始{total_raw_rows}行数据均含空值(年份或全年平均为空),无法计算分析指标")
return None # 直接返回,避免后续创建字典失败
# 提取核心数据
years = df_valid['年份'].values
annual_avg = df_valid['全年平均'].values
# 4. 提取季节数据
seasonal_cols = ['冬季平均', '春季平均', '夏季平均', '秋季平均']
if all(col in df.columns for col in seasonal_cols):
df_season_valid = df_valid.join(df[seasonal_cols]).dropna(subset=seasonal_cols)
# 5. 计算关键指标(仅在有效数据足够时执行)
analysis_result = {} # 初始化字典
try:
# 基础时间信息
analysis_result['time_period'] = f"{int(years.min())}-{int(years.max())}年"
analysis_result['total_raw_rows'] = total_raw_rows
analysis_result['valid_data_rows'] = valid_data_rows
# 趋势计算(至少2行有效数据才计算趋势)
if valid_data_rows >= 2:
trend = '上升' if annual_avg[-1] > annual_avg[0] else '下降' if annual_avg[-1] < annual_avg[0] else '平稳'
total_change = round(annual_avg[-1] - annual_avg[0], 1)
analysis_result['annual_trend'] = trend
analysis_result['total_change'] = total_change
else:
analysis_result['annual_trend'] = '无法判断(有效数据仅1行)'
analysis_result['total_change'] = 0.0
# 极值与统计量计算
analysis_result['max_temp'] = {
'year': int(years[annual_avg.argmax()]),
'value': round(annual_avg.max(), 1)
}
analysis_result['min_temp'] = {
'year': int(years[annual_avg.argmin()]),
'value': round(annual_avg.min(), 1)
}
analysis_result['avg_temp'] = round(annual_avg.mean(), 2)
analysis_result['temp_std'] = round(annual_avg.std(), 2) if valid_data_rows >= 2 else 0.0
# 异常值检测(至少3行有效数据才检测)
analysis_result['outliers'] = []
if valid_data_rows >= 3:
mean_val = annual_avg.mean()
std_val = annual_avg.std()
outliers_mask = (annual_avg < mean_val - 2 * std_val) | (annual_avg > mean_val + 2 * std_val)
if outliers_mask.any():
analysis_result['outliers'] = [
{'year': int(years[i]), 'value': round(annual_avg[i], 1)}
for i in range(len(years)) if outliers_mask[i]
]
except Exception as e:
print(f"计算分析指标时出错:{str(e)}")
return None
# 输出分析结果(确保所有字典键存在)
print(f"分析时间段:{analysis_result.get('time_period', '未知')}")
print(f"原始数据行数:{analysis_result.get('total_raw_rows', 0)}行")
print(f"有效数据行数:{analysis_result.get('valid_data_rows', 0)}行")
print(f"\n温度趋势:")
print(f"整体趋势:{analysis_result.get('annual_trend', '无法判断')}")
if analysis_result.get('annual_trend') != '无法判断(有效数据仅1行)':
print(f"变化幅度:{analysis_result.get('total_change', 0.0)}")
print(f"平均温度:{analysis_result.get('avg_temp', 0.0)}")
print(f"温度波动:{analysis_result.get('temp_std', 0.0)}(标准差)")
print(f"\n极值统计:")
max_temp = analysis_result.get('max_temp', {'year': '未知', 'value': 0.0})
min_temp = analysis_result.get('min_temp', {'year': '未知', 'value': 0.0})
print(f"最高温度:{max_temp['year']}年({max_temp['value']})")
print(f"最低温度:{min_temp['year']}年({min_temp['value']})")
outliers = analysis_result.get('outliers', [])
if outliers:
print(f"\n发现{len(outliers)}个异常值(超出±2σ范围)")
for outlier in outliers:
print(f"{outlier['year']}年:{outlier['value']}")
else:
print(f"\n未发现异常值(所有数据在±2σ范围内)")
return analysis_result
data_trend_analyzer.py
import pandas as pd
import numpy as np
from typing import Dict, Tuple
def calculate_annual_change_rate(df: pd.DataFrame) -> Tuple[pd.DataFrame, Dict]:
"""
计算2020-2025年全球平均温度的年际变化率和每年温度均值
年际变化率 = (当年温度 - 前一年温度) / 前一年温度 * 100%
"""
# 筛选有效数据
df_valid = df[['年份', '全年平均']].dropna(subset=['年份', '全年平均']).sort_values('年份')
years = df_valid['年份'].astype(int).values
temps = df_valid['全年平均'].values
# 计算每年温度均值
annual_mean = pd.DataFrame({
'年份': years,
'全球平均温度': temps
})
# 计算年际变化率
annual_change_rates = [np.nan] # 第一年无变化率
for i in range(1, len(temps)):
rate = (temps[i] - temps[i - 1]) / temps[i - 1] * 100
annual_change_rates.append(round(rate, 2))
annual_mean['年际变化率(%)'] = annual_change_rates
# 找出温度上升最显著的年份
valid_rates = [(years[i], annual_change_rates[i]) for i in range(1, len(annual_change_rates)) if
annual_change_rates[i] > 0]
if valid_rates:
max_rise_year, max_rise_rate = max(valid_rates, key=lambda x: x[1])
else:
max_rise_year, max_rise_rate = None, 0
trend_result = {
'annual_mean_df': annual_mean,
'max_rise_year': max_rise_year,
'max_rise_rate': max_rise_rate,
'total_rise': round(temps[-1] - temps[0], 2) if len(temps) >= 2 else 0
}
return annual_mean, trend_result
def compare_hemisphere_temp(df: pd.DataFrame) -> pd.DataFrame:
"""
对比南北半球温度变化差异(模拟划分:冬季平均=北半球,夏季平均=南半球)
计算每年南北半球温度及温差
"""
required_cols = ['年份', '冬季平均', '夏季平均']
df_hemisphere = df[required_cols].dropna(subset=required_cols).sort_values('年份')
df_hemisphere['年份'] = df_hemisphere['年份'].astype(int)
df_hemisphere.columns = ['年份', '北半球平均温度', '南半球平均温度']
# 计算南北半球温差
df_hemisphere['南北半球温差'] = df_hemisphere['北半球平均温度'] - df_hemisphere['南半球平均温度']
df_hemisphere = df_hemisphere.round(2)
return df_hemisphere
def get_temp_anomaly(df: pd.DataFrame) -> pd.DataFrame:
"""
计算每年温度异常值(相对于2020-2025年整体均值),用于热力图绘制
"""
df_valid = df[['年份', '全年平均']].dropna(subset=['年份', '全年平均'])
overall_mean = df_valid['全年平均'].mean()
df_valid['温度异常值'] = df_valid['全年平均'] - overall_mean
df_valid['年份'] = df_valid['年份'].astype(int)
return df_valid[['年份', '温度异常值']].sort_values('年份')
data_visualizer.py
import pandas as pd
import matplotlib
matplotlib.use('TkAgg') # 使用TkAgg后端
import matplotlib.pyplot as plt
import os
import numpy as np
def set_plot_style():
"""设置图表样式(兼容所有Matplotlib版本,仅保留基础稳定参数)"""
# 中文显示配置
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'sans-serif']
plt.rcParams['axes.unicode_minus'] = False
# 基础样式
plt.rcParams['figure.figsize'] = (16, 8) # 月度图加宽画布,减少标签重叠
plt.rcParams['font.size'] = 10
plt.rcParams['axes.linewidth'] = 1.0
plt.rcParams['grid.alpha'] = 0.3
def plot_monthly_temperature_2020_2025(df: pd.DataFrame, output_dir: str = 'output',
filename: str = 'monthly_temperature_202001_202510.png') -> bool:
"""绘制2020年1月-2025年10月月度温度图"""
set_plot_style()
# 数据预处理:年度转月度时间序列
target_years = df[(df['年份'] >= 2020) & (df['年份'] <= 2025)].copy()
if len(target_years) == 0:
print(f"未找到2020-2025年数据")
return False
month_cols = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
monthly_dates = [] # 格式:2020-01
monthly_temps = []
missing_months = []
for _, row in target_years.iterrows():
year = int(row['年份'])
# 2025年只取1-10月,其他年份1-12月
max_month = 10 if year == 2025 else 12
for month in range(1, max_month + 1):
month_col = month_cols[month - 1]
temp = row[month_col]
date_str = f"{year}-{str(month).zfill(2)}"
monthly_dates.append(date_str)
if pd.notna(temp):
monthly_temps.append(float(temp))
else:
monthly_temps.append(np.nan)
missing_months.append(date_str)
# 筛选2020-01至2025-10范围
start_idx = monthly_dates.index('2020-01') if '2020-01' in monthly_dates else 0
end_idx = monthly_dates.index('2025-10') + 1 if '2025-10' in monthly_dates else len(monthly_dates)
final_dates = monthly_dates[start_idx:end_idx]
final_temps = monthly_temps[start_idx:end_idx]
if len(final_dates) == 0:
print(f"未找到2020-01至2025-10的月度数据")
return False
# 2. 绘制图表
fig, ax = plt.subplots(1, 1)
# 绘制月度温度折线
ax.plot(final_dates, final_temps,
color='#2E86AB', linewidth=2.0,
marker='o', markersize=4,
markerfacecolor='#E74C3C', markeredgewidth=0.5,
label='月度平均温度', alpha=0.8)
# 标注缺失数据
if missing_months:
missing_in_range = [d for d in missing_months if d in final_dates]
if missing_in_range:
# 计算y轴位置(避免与有效数据重叠)
valid_temps = [t for t in final_temps if pd.notna(t)]
y_min = min(valid_temps) - 5 if valid_temps else 0
# 绘制缺失值标记
ax.scatter(missing_in_range, [y_min] * len(missing_in_range),
color='#E74C3C', s=50, marker='x', linewidth=2,
label=f'缺失数据({len(missing_in_range)}个月份)', zorder=5)
# 3. X轴标签设置
# 每6个月显示一个标签,减少密度
ax.set_xticks(final_dates[::6])
# 设置标签并旋转
ax.set_xticklabels(final_dates[::6], rotation=45)
ax.tick_params(axis='x', labelsize=9)
# 坐标轴和标题
ax.set_xlabel('年月', fontsize=12, fontweight='bold')
ax.set_ylabel('月度平均温度', fontsize=12, fontweight='bold')
ax.grid(True, axis='y', alpha=0.3) # 仅显示y轴网格,不干扰x轴标签
ax.set_title('2020年1月-2025年10月全球月度平均温度变化图',
fontsize=14, fontweight='bold', pad=20)
# 图例位置优化
ax.legend(loc='upper right', frameon=True, fancybox=True, shadow=True, fontsize=9)
ax.set_facecolor('#F8F9FA')
fig.patch.set_facecolor('white')
# 5. 保存图表
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, filename)
try:
# 旧版Matplotlib tight_layout可能有问题,改用subplots_adjust
plt.subplots_adjust(bottom=0.15) # 预留底部空间,防止x轴标签被截断
plt.savefig(output_path, dpi=300, bbox_inches='tight', facecolor='white')
plt.close()
# 统计信息
valid_count = sum(1 for t in final_temps if pd.notna(t))
print(f"统计:共{len(final_temps)}个月份(2020-01至2025-10),有效数据{valid_count}个,缺失{len(final_temps) - valid_count}个")
return True
except Exception as e:
print(f"保存图表失败:{str(e)}")
return False
def plot_temperature_trend(df: pd.DataFrame, output_dir: str = 'output', filename: str = 'analysis_chart.png') -> bool:
"""绘制年度温度图"""
set_plot_style()
years = df['年份'].values
annual_avg = df['全年平均'].values
# 1. 过滤无效值(解决分析时nan问题)
valid_mask = pd.notna(annual_avg)
valid_years = years[valid_mask]
valid_avg = annual_avg[valid_mask]
if len(valid_years) < 2:
print("有效年度数据不足(需至少2年),无法绘制年度图")
return False
# 2. 计算统计指标
mean_val = valid_avg.mean()
std_val = valid_avg.std()
outliers_mask = (valid_avg < mean_val - 2 * std_val) | (valid_avg > mean_val + 2 * std_val)
outliers = valid_avg[outliers_mask]
outlier_years = valid_years[outliers_mask]
# 3. 绘制年度图(旧版兼容)
fig, ax = plt.subplots(1, 1)
ax.plot(valid_years, valid_avg,
color='#2E86AB', linewidth=3.5,
marker='o', markersize=10,
markerfacecolor='#E74C3C', markeredgecolor='white', markeredgewidth=2,
label='全球平均温度')
# 标注异常值(旧版兼容)
if len(outliers) > 0:
for year, temp in zip(outlier_years, outliers):
ax.scatter(year, temp, color='#F39C12', s=200, zorder=5, edgecolor='#D35400', linewidth=2)
ax.annotate(f'异常值\n{int(year)}年:{temp:.1f}',
xy=(year, temp), xytext=(0, 30), textcoords='offset points',
ha='center', va='bottom', fontweight='bold', fontsize=9,
bbox=dict(boxstyle='round,pad=0.5', facecolor='#FDEBD0', edgecolor='#E67E22'))
# 4. X轴设置(旧版兼容)
ax.set_xticks(valid_years)
ax.set_xticklabels([f'{int(y)}年' for y in valid_years])
ax.tick_params(axis='x', labelsize=10)
# 5. 参考线和配置
ax.axhline(y=mean_val, color='#95A5A6', linestyle='-', linewidth=1.5, alpha=0.8, label=f'平均值:{mean_val:.1f}')
ax.axhline(y=mean_val + 2 * std_val, color='#E74C3C', linestyle='--', linewidth=2, alpha=0.8,
label=f'异常上限:{mean_val + 2 * std_val:.1f}')
ax.set_xlabel('年份', fontsize=13, fontweight='bold')
ax.set_ylabel('全球平均温度', fontsize=13, fontweight='bold')
ax.set_title(f'{int(valid_years.min())}-{int(valid_years.max())}年全球平均温度变化趋势',
fontsize=16, fontweight='bold', pad=20)
ax.grid(True, axis='y')
ax.legend(loc='upper left', frameon=True, fancybox=True, shadow=True)
ax.set_facecolor('#F8F9FA')
fig.patch.set_facecolor('white')
# 6. 保存(旧版兼容)
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, filename)
try:
plt.subplots_adjust(bottom=0.1)
plt.savefig(output_path, dpi=300, bbox_inches='tight', facecolor='white')
plt.close()
return True
except Exception as e:
print(f"保存年度温度图失败:{str(e)}")
return False
data_visualizer_extend.py
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import os
# 基础样式配置
def set_base_style():
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'sans-serif']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.figsize'] = (12, 6)
plt.rcParams['font.size'] = 10
plt.rcParams['grid.alpha'] = 0.3
def plot_temp_change_line(annual_mean_df: pd.DataFrame, output_dir: str = 'output'):
"""绘制2020-2025年全球平均温度变化折线图(标注异常峰值年份)"""
set_base_style()
years = annual_mean_df['年份'].values
temps = annual_mean_df['全球平均温度'].values
# 识别异常峰值(高于均值+1个标准差)
mean_temp = temps.mean()
std_temp = temps.std()
peak_mask = temps > mean_temp + std_temp
peak_years = years[peak_mask]
peak_temps = temps[peak_mask]
fig, ax = plt.subplots(1, 1)
# 绘制主折线
ax.plot(years, temps, color='#2E86AB', linewidth=3, marker='o', markersize=8, label='全球平均温度')
# 标注峰值
if len(peak_years) > 0:
for year, temp in zip(peak_years, peak_temps):
ax.scatter(year, temp, color='#E74C3C', s=150, zorder=5)
ax.annotate(f'峰值\n{year}年:{temp:.1f}', xy=(year, temp), xytext=(0, 10), textcoords='offset points',
ha='center')
ax.set_title('2020-2025年全球平均温度变化折线图', fontsize=14, fontweight='bold', pad=20)
ax.set_xlabel('年份', fontsize=12, fontweight='bold')
ax.set_ylabel('全球平均温度', fontsize=12, fontweight='bold')
ax.grid(True, axis='y')
ax.legend()
ax.set_facecolor('#F8F9FA')
output_path = os.path.join(output_dir, '全球温度变化折线图.png')
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight', facecolor='white')
plt.close()
print(f"折线图已保存至:{output_path}")
def plot_hemisphere_bar(hemisphere_df: pd.DataFrame, output_dir: str = 'output'):
"""绘制南北半球温度对比柱状图(每年)"""
set_base_style()
years = hemisphere_df['年份'].values
north_temps = hemisphere_df['北半球平均温度'].values
south_temps = hemisphere_df['南半球平均温度'].values
x = np.arange(len(years))
width = 0.35
fig, ax = plt.subplots(1, 1)
bars1 = ax.bar(x - width / 2, north_temps, width, label='北半球', color='#3498DB', alpha=0.8)
bars2 = ax.bar(x + width / 2, south_temps, width, label='南半球', color='#E67E22', alpha=0.8)
ax.set_title('2020-2025年南北半球温度对比柱状图', fontsize=14, fontweight='bold', pad=20)
ax.set_xlabel('年份', fontsize=12, fontweight='bold')
ax.set_ylabel('平均温度', fontsize=12, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(years)
ax.legend()
ax.grid(True, axis='y')
ax.set_facecolor('#F8F9FA')
# 添加数值标签
for bar in bars1:
height = bar.get_height()
ax.annotate(f'{height:.1f}', xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3),
textcoords='offset points', ha='center')
for bar in bars2:
height = bar.get_height()
ax.annotate(f'{height:.1f}', xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3),
textcoords='offset points', ha='center')
output_path = os.path.join(output_dir, '南北半球温度对比柱状图.png')
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight', facecolor='white')
plt.close()
print(f"柱状图已保存至:{output_path}")
def plot_temp_anomaly_heatmap(anomaly_df: pd.DataFrame, output_dir: str = 'output'):
"""绘制全球温度异常分布热力图(按年份)"""
set_base_style()
plt.rcParams['figure.figsize'] = (10, 5)
# 转换为热力图所需的矩阵格式
years = anomaly_df['年份'].values.reshape(1, -1)
anomalies = anomaly_df['温度异常值'].values.reshape(1, -1)
fig, ax = plt.subplots(1, 1)
im = ax.imshow(anomalies, cmap='RdBu_r', aspect='auto')
# 设置坐标轴
ax.set_xticks(np.arange(len(years[0])))
ax.set_xticklabels(years[0])
ax.set_yticks([0])
ax.set_yticklabels(['温度异常值'])
# 添加数值标签
for i in range(len(years[0])):
text = ax.text(i, 0, f'{anomalies[0, i]:.1f}', ha='center', va='center', color='black', fontweight='bold')
# 添加颜色条
cbar = plt.colorbar(im, ax=ax, shrink=0.8)
cbar.set_label('温度异常值', rotation=270, labelpad=15)
ax.set_title('2020-2025年全球温度异常分布热力图', fontsize=14, fontweight='bold', pad=20)
ax.set_facecolor('#F8F9FA')
output_path = os.path.join(output_dir, '全球温度异常热力图.png')
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight', facecolor='white')
plt.close()
print(f"热力图已保存至:{output_path}")
report_generator.py
import pandas as pd
import os
from typing import Dict
def export_excel_results(annual_mean: pd.DataFrame, hemisphere_df: pd.DataFrame, anomaly_df: pd.DataFrame,
output_dir: str = 'output'):
"""
导出统计结果到Excel文件,包含3个工作表
"""
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, '全球温度统计结果.xlsx')
with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
annual_mean.to_excel(writer, sheet_name='年度温度与变化率', index=False)
hemisphere_df.to_excel(writer, sheet_name='南北半球温度对比', index=False)
anomaly_df.to_excel(writer, sheet_name='温度异常值', index=False)
print(f"统计结果已导出至:{output_path}")
return output_path
def generate_markdown_report(trend_result: Dict, hemisphere_df: pd.DataFrame, output_dir: str = 'output'):
"""
生成《全球气候温度趋势分析报告》(Markdown格式)
"""
os.makedirs(output_dir, exist_ok=True)
report_path = os.path.join(output_dir, '全球气候温度趋势分析报告.md')
# 提取核心结论
annual_mean_df = trend_result['annual_mean_df']
max_rise_year = trend_result['max_rise_year']
max_rise_rate = trend_result['max_rise_rate']
total_rise = trend_result['total_rise']
overall_mean = annual_mean_df['全球平均温度'].mean()
# 南北半球核心数据
avg_north = hemisphere_df['北半球平均温度'].mean()
avg_south = hemisphere_df['南半球平均温度'].mean()
avg_temp_diff = hemisphere_df['南北半球温差'].mean()
report_content = f"""# 全球气候温度趋势分析报告
## 一、数据来源说明
- 数据文件:全球.xlsx
- 分析时间段:2020-2025年
- 核心指标:全球平均温度、冬季平均温度(北半球模拟)、夏季平均温度(南半球模拟)
- 数据处理:自动过滤缺失值,保留有效数据{len(annual_mean_df)}条
## 二、核心统计结论
### 2.1 全球温度整体趋势
1. 分析期间全球平均温度:{overall_mean:.2f}
2. 2020-2025年全球温度总上升幅度:{total_rise:.2f}
3. 温度上升最显著年份:{max_rise_year}年(年际变化率:{max_rise_rate:.2f}%)
4. 年度平均温度范围:{annual_mean_df['全球平均温度'].min():.2f} - {annual_mean_df['全球平均温度'].max():.2f}
### 2.2 南北半球温度差异
1. 北半球平均温度:{avg_north:.2f}
2. 南半球平均温度:{avg_south:.2f}
3. 南北半球平均温差:{avg_temp_diff:.2f}
4. 南半球温度整体{"高于" if avg_south > avg_north else "低于"}北半球
### 2.3 年际变化特征
- 正增长年份数量:{len([r for r in annual_mean_df['年际变化率(%)'].dropna() if r > 0])}个
- 负增长年份数量:{len([r for r in annual_mean_df['年际变化率(%)'].dropna() if r < 0])}个
- 温度变化率波动范围:{annual_mean_df['年际变化率(%)'].dropna().min():.2f}% - {annual_mean_df['年际变化率(%)'].dropna().max():.2f}%
## 三、可视化结果说明
1. 全球平均温度变化折线图:标注温度异常峰值年份,直观呈现上升趋势
2. 南北半球温度对比柱状图:展示每年南北半球温度差异
3. 全球温度异常分布热力图:突出温度偏离均值的年份
## 四、建议
1. **气候监测**:重点关注{max_rise_year}年类似的快速升温时段,加强气象数据实时监测
2. **区域适配**:针对北半球温度波动更大的特征,制定差异化气候应对策略
3. **长期预警**:基于总上升幅度{total_rise:.2f}的趋势,建立长期温度预警机制
4. **数据完善**:建议补充南北半球直接观测数据,提升差异分析准确性
## 五、数据附录
- 年度温度与变化率表:全球温度统计结果.xlsx(工作表1)
- 南北半球温度对比表:全球温度统计结果.xlsx(工作表2)
- 温度异常值表:全球温度统计结果.xlsx(工作表3)
---
*报告生成时间:自动生成*
*数据版本:原始数据无清洗,保留完整原始信息*
"""
with open(report_path, 'w', encoding='utf-8') as f:
f.write(report_content)
print(f"分析报告已生成至:{report_path}")
return report_path
main.py
import os
from data_loader import load_excel_data
from data_extractor import extract_time_period, save_extracted_data
from data_analyzer import analyze_extracted_data
from data_trend_analyzer import calculate_annual_change_rate, compare_hemisphere_temp, get_temp_anomaly
from data_visualizer_extend import plot_temp_change_line, plot_hemisphere_bar, plot_temp_anomaly_heatmap
from report_generator import export_excel_results, generate_markdown_report
from data_visualizer import plot_monthly_temperature_2020_2025
def main():
"""主程序:完整实现趋势分析、多维度可视化、结果导出"""
# 1. 配置参数
RAW_DATA_PATH = '全球.xlsx'
OUTPUT_DIR = 'output'
TARGET_START_YEAR = 2020
TARGET_END_YEAR = 2025
# 2. 加载原始数据
raw_df = load_excel_data(RAW_DATA_PATH)
if raw_df is None:
print("数据加载失败,程序终止")
return
# 3. 提取目标时间段数据
extracted_df = extract_time_period(raw_df, TARGET_START_YEAR, TARGET_END_YEAR)
if extracted_df is None:
print("数据提取失败,程序终止")
return
save_extracted_data(extracted_df, OUTPUT_DIR, 'extracted_data_2020_2025_raw.xlsx')
# 4. 基础数据分析
analyze_extracted_data(extracted_df)
# 5. 趋势统计分析(新增)
annual_mean_df, trend_result = calculate_annual_change_rate(extracted_df)
hemisphere_df = compare_hemisphere_temp(extracted_df)
anomaly_df = get_temp_anomaly(extracted_df)
print(f"趋势分析完成:2020-2025年温度总上升{trend_result['total_rise']},升温最显著年份{trend_result['max_rise_year']}年")
# 6. 多维度可视化(新增)
plot_temp_change_line(annual_mean_df, OUTPUT_DIR) # 折线图
plot_hemisphere_bar(hemisphere_df, OUTPUT_DIR) # 柱状图
plot_temp_anomaly_heatmap(anomaly_df, OUTPUT_DIR) # 热力图
plot_monthly_temperature_2020_2025(extracted_df, OUTPUT_DIR) # 原有月度图
# 7. 结果导出与报告生成(新增)
export_excel_results(annual_mean_df, hemisphere_df, anomaly_df, OUTPUT_DIR)
generate_markdown_report(trend_result, hemisphere_df, OUTPUT_DIR)
if __name__ == "__main__":
main()





以下是绘制南北半球温度对比柱状图(每年)的代码
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 1. 基础配置
plt.switch_backend('Agg')
plt.rcParams['font.sans-serif'] = ['SimHei', 'WenQuanYi Zen Hei']
plt.rcParams['axes.unicode_minus'] = False
# 2. 加载数据
df_north = pd.read_excel('北半球.xlsx')
df_south = pd.read_excel('南半球.xlsx')
# 3. 数据对齐
df_merged = pd.merge(
df_north[['年份', '全年平均']].rename(columns={'全年平均': '北半球温度'}),
df_south[['年份', '全年平均']].rename(columns={'全年平均': '南半球温度'}),
on='年份',
how='inner'
).sort_values('年份')
# 4. 绘制对比柱状图
x = np.arange(len(df_merged))
width = 0.35
fig, ax = plt.subplots(figsize=(12, 6))
bars1 = ax.bar(x - width/2, df_merged['北半球温度'], width, label='北半球', color='#FF6B6B', alpha=0.8)
bars2 = ax.bar(x + width/2, df_merged['南半球温度'], width, label='南半球', color='#4ECDC4', alpha=0.8)
# 图表样式
ax.set_xlabel('年份', fontsize=11)
ax.set_ylabel('全年平均温度 (℃)', fontsize=11)
ax.set_title('南北半球年度全年平均温度对比', fontsize=13, fontweight='bold')
ax.set_xticks(x)
ax.set_xticklabels(df_merged['年份'], rotation=45)
ax.legend()
# 优化:数值标签显示在柱子内部(避免重叠)
def add_labels_inside(bars, color='white'):
for bar in bars:
height = bar.get_height()
ax.text(bar.get_x() + bar.get_width()/2., height/2, # 标签位置在柱子中间
f'{height:.1f}', ha='center', va='center', fontsize=9, color=color, fontweight='bold')
add_labels_inside(bars1, color='white') # 北半球柱子内白色标签
add_labels_inside(bars2, color='black') # 南半球柱子内黑色标签(对比更清晰)
# 5. 保存图表
plt.tight_layout()
plt.savefig('南北半球年度温度对比图_优化版.png', dpi=300)
plt.close()
建议
1.气候监测:重点关注2023年类似的快速升温时段,加强气象数据实时监测
2.区域适配:针对北半球温度波动更大的特征,制定差异化气候应对策略
3.长期预警:基于总上升幅度28.00的趋势,建立长期温度预警机制
4.数据完善:建议补充南北半球直接观测数据,提升差异分析准确性
项目二:电商平台商品评论情感分析与热销款预测工具
项目背景
电商平台商品评论蕴含用户偏好与产品质量反馈,通过情感分析可挖掘用户满意度,结合销量数据还能预测热销款,为商家运营提供决策支持。本项目基于公开电商评论数据集,开发分析工具,贴合应用统计学专业 “数据分析与预测” 的实践需求。
核心功能要求
1. 数据获取与预处理:从公开数据源(如 Kaggle 平台 “Amazon Product Reviews” 数据集、天池平台 “淘宝商品评论数据集”)下载数据,包含 “商品 ID、商品类别、用户评论内容、评分(1-5 星)、评论时间、商品销量” 等字段。对评论内容进行预处理:去除特殊符号、停用词(如 “的”“了”),使用 jieba 库进行分词;将评分映射为情感标签(5 星 = 正面、3-4 星 = 中性、1-2 星 = 负面)。
2. 情感分析与统计:采用 “评分映射 + 关键词匹配” 结合的方式,统计每类商品的正面评论率(正面评论数 / 总评论数)、负面评论关键词 TOP10(如 “质量差”“物流慢”);对比不同类别商品的情感倾向差异(如 “电子产品正面评论率 82%,服装类 75%”)。
3. 热销款预测与可视化:以 “商品月销量” 为目标变量,“正面评论率、评论数量、商品价格” 为特征变量,使用线性回归模型(sklearn 库)构建热销款预测模型,预测下月可能成为热销款的商品(销量排名前 10%);绘制 “商品正面评论率与销量散点图”(标注预测热销款)、“不同类别商品销量对比饼图”。
4. 结果应用:将情感分析结果(如各商品负面关键词表)、热销款预测名单导出为 Excel 文件;生成《电商商品评论分析与热销款预测报告》,为商家提供建议(如 “针对‘物流慢’负面评论,优化快递合作商”“重点备货预测热销的 3 款电子产品”)。
代码:
import pandas as pd
import jieba
from collections import Counter
df = pd.read_excel('商品销量评论数据.xlsx')
def get_sentiment(score):
if score == 5:
return '正面'
elif 3 <= score <= 4:
return '中性'
else:
return '负面'
df['情感标签'] = df['评分(1-5星)'].apply(get_sentiment)
# 正面评论率统计
category_sentiment = df.groupby('商品类别')['情感标签'].value_counts().unstack(fill_value=0)
category_sentiment['总评论数'] = category_sentiment.sum(axis=1)
category_sentiment['正面评论率'] = (category_sentiment['正面'] / category_sentiment['总评论数']).round(4) * 100
print("\n=== 各类商品正面评论率 ===")
print(category_sentiment[['正面', '总评论数', '正面评论率']].astype({'正面': int, '总评论数': int}))
# 负面评论关键词TOP10
stop_words = {'的', '了', '是', '在', '我', '有', '和', '就', '不', '人', '都', '一', '这个', '很', '也', '还', '但'}
negative_comments = df[df['情感标签'] == '负面']['用户评论内容'].str.cat(sep=' ')
words = [w for w in jieba.lcut(negative_comments) if w not in stop_words and len(w) >= 2]
negative_top10 = Counter(words).most_common(10)
print("\n=== 负面评论关键词TOP10 ===")
for i, (word, count) in enumerate(negative_top10, 1):
print(f"{i}. {word}: {count}次")
# 商品情感倾向对比
print("\n=== 商品情感倾向差异对比 ===")
for category in category_sentiment.index:
rate = category_sentiment.loc[category, '正面评论率']
print(f"{category}正面评论率{rate:.1f}%")

import pandas as pd
import numpy as np
import matplotlib
matplotlib.use('Agg') # 使用非交互式后端,避免GUI问题
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
from sklearn.preprocessing import StandardScaler
# 中文字体设置
plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei', 'SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(42) # 固定随机种子,结果可复现
df = pd.read_excel('商品销量评论数据.xlsx')
sales_data = df.groupby('商品ID')['商品销量'].mean().reset_index(name='商品销量')
# 特征1:评论数量(每个商品的评论总数)
sales_data['评论数量'] = df.groupby('商品ID').size().values
# 特征2:正面评论率(5星为正面,计算占比)
positive_count = df[df['评分(1-5星)'] == 5].groupby('商品ID').size()
sales_data['正面评论率'] = (positive_count.reindex(sales_data['商品ID'], fill_value=0) / sales_data['评论数量']).round(4)
# 特征3:商品价格(模拟合理价格,可替换为真实数据)
sales_data['商品价格'] = np.random.uniform(30, 1800, len(sales_data)).round(2)
sales_data['正面评论率'] = sales_data['正面评论率'].fillna(0)
sales_data['平均评分'] = df.groupby('商品ID')['评分(1-5星)'].mean().values
sales_data['评分标准差'] = df.groupby('商品ID')['评分(1-5星)'].std().fillna(0).values
sales_data['价格销量比'] = sales_data['商品价格'] / (sales_data['商品销量'] + 1) # +1避免除零
print("数据基本信息:")
print(f"总商品数:{len(sales_data)}")
print(f"特征数:{len(sales_data.columns) - 2}") # 减去商品ID和商品销量
# 2. 线性回归建模与热销款预测
X = sales_data[['正面评论率', '评论数量', '商品价格', '平均评分', '评分标准差', '价格销量比']]
y = sales_data['商品销量']
# 数据标准化(提高模型稳定性)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 检查是否有NaN值
print("\n检查NaN值:")
for col in X.columns:
nan_count = X[col].isna().sum()
if nan_count > 0:
print(f"{col}: {nan_count}个NaN值,使用均值填充")
X[col] = X[col].fillna(X[col].mean())
# 划分训练集/测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
# 训练模型并预测
lr = LinearRegression()
lr.fit(X_train, y_train)
# 全量商品预测销量
X_full_scaled = scaler.transform(X)
sales_data['预测销量'] = lr.predict(X_full_scaled)
# 确保预测销量非负
sales_data['预测销量'] = sales_data['预测销量'].clip(lower=0)
# 筛选热销款(预测销量前10%)
hot_threshold = sales_data['预测销量'].quantile(0.9)
sales_data['是否热销款'] = sales_data['预测销量'] >= hot_threshold
hot_count = sales_data['是否热销款'].sum()
# 模型评估
y_pred_test = lr.predict(X_test)
r2 = r2_score(y_test, y_pred_test)
print(f'\n=== 模型评估结果 ===')
print(f'模型R²评分:{r2:.4f}')
print(f'预测下月热销款数量:{hot_count}(总商品数:{len(sales_data)})')
# 显示模型系数
print(f'\n=== 特征重要性(标准化后)===')
feature_names = ['正面评论率', '评论数量', '商品价格', '平均评分', '评分标准差', '价格销量比']
for feature, coef in zip(feature_names, lr.coef_):
importance = f'正向影响' if coef > 0 else f'负向影响'
print(f'{feature:10s} 系数: {coef:8.4f} ({importance})')
print(f'截距: {lr.intercept_:.4f}')
# 3. 绘制「正面评论率与销量散点图」(单独保存)
plt.figure(figsize=(12, 8))
# 非热销款
plt.scatter(
sales_data[sales_data['是否热销款'] == False]['正面评论率'],
sales_data[sales_data['是否热销款'] == False]['商品销量'],
c='#87CEEB', label=f'非热销款 ({len(sales_data) - hot_count}个)', alpha=0.6, s=50
)
# 预测热销款(突出显示)
plt.scatter(
sales_data[sales_data['是否热销款'] == True]['正面评论率'],
sales_data[sales_data['是否热销款'] == True]['商品销量'],
c='#FF4500', label=f'预测热销款 ({hot_count}个)', alpha=0.9, s=150, marker='*', edgecolors='black', linewidth=1
)
plt.xlabel('正面评论率', fontsize=12)
plt.ylabel('商品销量', fontsize=12)
plt.title(f'商品正面评论率与销量关系\n模型R²评分: {r2:.4f}', fontsize=14, pad=20)
plt.legend(fontsize=10, loc='upper right')
plt.grid(alpha=0.3, linestyle='--')
plt.tight_layout()
plt.savefig('正面评论率与销量散点图.png', dpi=300, bbox_inches='tight')
plt.close()
# 4. 绘制「不同类别商品销量对比饼图」(单独保存)
# 计算各类别总销量
category_total_sales = df.groupby('商品类别')['商品销量'].sum().sort_values(ascending=False)
plt.figure(figsize=(12, 8))
# 饼图样式设置
wedges, texts, autotexts = plt.pie(
category_total_sales.values,
labels=category_total_sales.index,
autopct='%1.1f%%', # 显示百分比
startangle=90,
colors=plt.cm.Set3(np.linspace(0, 1, len(category_total_sales))),
textprops={'fontsize': 10},
explode=[0.05 if i < 3 else 0 for i in range(len(category_total_sales))] # 突出前3名
)
# 优化百分比文字颜色
for autotext in autotexts:
autotext.set_color('black')
autotext.set_fontweight('bold')
autotext.set_fontsize(9)
plt.title('不同类别商品销量占比', fontsize=14, pad=20)
plt.axis('equal') # 保证饼图为正圆形
plt.tight_layout()
plt.savefig('不同类别商品销量饼图.png', dpi=300, bbox_inches='tight')
plt.close()
# 5. 新增:热销款特征分布图
plt.figure(figsize=(14, 10))
features_to_plot = ['正面评论率', '评论数量', '平均评分', '商品价格']
for i, feature in enumerate(features_to_plot, 1):
plt.subplot(2, 2, i)
# 热销款
hot_values = sales_data[sales_data['是否热销款'] == True][feature]
# 非热销款
non_hot_values = sales_data[sales_data['是否热销款'] == False][feature]
plt.hist(non_hot_values, bins=20, alpha=0.6, color='#87CEEB', label='非热销款', density=True)
plt.hist(hot_values, bins=10, alpha=0.8, color='#FF4500', label='热销款', density=True)
plt.xlabel(feature, fontsize=10)
plt.ylabel('密度', fontsize=10)
plt.title(f'{feature}分布对比', fontsize=11)
plt.legend(fontsize=9)
plt.grid(alpha=0.3, linestyle=':')
plt.suptitle('热销款与非热销款特征分布对比', fontsize=14, y=1.02)
plt.tight_layout()
plt.savefig('热销款特征分布图.png', dpi=300, bbox_inches='tight')
plt.close()
print('\n=== 热销款分析 ===')
hot_items = sales_data[sales_data['是否热销款'] == True].sort_values('预测销量', ascending=False)
print(f"热销款平均正面评论率: {hot_items['正面评论率'].mean():.3f}")
print(f"热销款平均评论数量: {hot_items['评论数量'].mean():.1f}")
print(f"热销款平均评分: {hot_items['平均评分'].mean():.2f}")
print(f"热销款平均价格: ¥{hot_items['商品价格'].mean():.2f}")
# 保存预测结果到Excel
sales_data.to_excel('商品热销预测结果.xlsx', index=False)
print('预测结果已保存到:商品热销预测结果.xlsx')

不同类别商品销量对比饼图

项目三:城市空气质量数据统计与健康建议系统
项目背景
城市空气质量(如 PM2.5、PM10 浓度)与居民健康密切相关,实时统计与分析空气质量数据,能为居民出行提供健康建议。本项目基于公开的城市空气质量数据集,开发分析系统,贴合基层环境监测与健康管理的实际需求。
核心功能要求
1. 数据获取与预处理:从公开数据源(如中国空气质量在线监测分析平台https://www.aqistudy.cn/提供的 “城市空气质量历史数据”、Kaggle “Beijing Air Quality Data” 数据集)下载 CSV 格式数据,包含 “日期、城市名称、PM2.5 浓度、PM10 浓度、SO₂浓度、AQI 指数、空气质量等级(优 / 良 / 轻度污染等)” 字段。清洗数据:剔除 AQI 指数为 0 的异常值、填充缺失的 PM2.5 数据(用同日期周边城市均值填充),提取 “2023 年某省份 10 个城市” 的数据进行分析。
2. 空气质量统计分析:计算 2023 年各城市的 “PM2.5 年均浓度”“优良天数占比(优良天数 / 全年天数)”“轻度及以上污染天数”;找出空气质量最优(优良天数占比最高)与最差(污染天数最多)的城市;分析季节性差异(如冬季 PM2.5 浓度是否显著高于夏季)。
3. 健康建议与可视化:根据 AQI 指数制定健康建议规则(如 AQI<50:适宜户外活动;AQI 151-200:敏感人群减少外出);绘制 “2023 年各城市 PM2.5 年均浓度柱状图”“某城市四季 AQI 指数变化折线图”“空气质量等级分布饼图(全省)”,图表标注对应健康建议。
4. 结果输出:将各城市空气质量统计数据导出为 Excel,生成《某省份 2023 年空气质量分析与健康建议报告》(Word 格式),包含数据来源、统计结论及分城市健康出行建议。
项目四:电影票房数据统计与类型偏好分析工具
项目背景
电影票房数据反映市场热度与观众偏好,分析票房与电影类型、上映时间的关联性,能为影视行业从业者提供参考。本项目基于公开电影票房数据集,开发分析工具,贴合数据统计与市场分析的实际场景。
核心功能要求
1. 数据获取与预处理:从公开数据源(如猫眼专业版https://piaofang.maoyan.com/提供的 “年度电影票房数据”、Kaggle “Movie Box Office Dataset” 数据集)下载 Excel/CSV 数据,包含 “电影名称、类型(如喜剧 / 动作 / 科幻)、上映日期、总票房、场均人次、评分(豆瓣 / 猫眼)” 等字段。清洗数据:统一电影类型格式(如 “喜剧片”“喜剧” 合并为 “喜剧”)、提取上映月份(用于分析档期影响)、剔除票房为 0 的未上映电影数据。
2. 票房统计与类型分析:计算 2023 年各类型电影的 “总票房占比”“平均票房”“最高票房电影”;分析档期对票房的影响(如春节档、国庆档电影的平均票房是否高于非档期);找出评分与票房的相关性(如评分≥8.0 的电影平均票房是否是评分<6.0 的 2 倍以上)。
3. 可视化与趋势呈现:绘制 “2023 年各类型电影总票房饼图”“春节档 vs 非档期电影平均票房柱状图”“电影评分与总票房散点图”(标注高评分高票房电影);通过可视化直观展示类型偏好与票房规律。
4. 结果导出与建议:将各类型电影统计数据(如平均票房、最高票房)导出为 Excel,生成《2023 年电影票房与类型偏好分析报告》,为影视制作方提供建议(如 “喜剧类型电影市场接受度高,可加大创作投入”“春节档是票房黄金档期,建议重点影片选择该档期上映”)。
在该网站下载数据:
https://www.kaggle.com/code/shivamb/netflix-shows-and-movies-exploratory-analysis
import pandas as pd
import numpy as np
# 1. 加载数据+预处理(同目录下文件)
df = pd.read_csv('shuju_with_aqi.csv')
df['date'] = pd.to_datetime(df[['year', 'month', 'day']])
df_2016 = df[df['year'] == 2016].copy()
# 2. 日级聚合(核心计算)
daily = df_2016.groupby('date').agg({
'PM2.5': 'mean', # PM2.5日均
'AQI': 'mean' # AQI日均
}).reset_index()
# 3. 空气质量等级映射
daily['等级'] = daily['AQI'].apply(
lambda x: '优' if x<=50 else '良' if x<=100 else '轻度污染' if x<=150
else '中度污染' if x<=200 else '重度污染' if x<=300 else '严重污染'
)
# 4. 2016年核心指标
pm25_annual = daily['PM2.5'].mean() # PM2.5年均浓度
excellent_days = daily[daily['等级'].isin(['优', '良'])].shape[0] # 优良天数
pollution_days = daily[~daily['等级'].isin(['优', '良'])].shape[0] # 污染天数
excellent_ratio = (excellent_days / len(daily)) * 100 # 优良天数占比
# 5. 极值日期
best_day = daily[daily['等级'].isin(['优', '良'])].sort_values('AQI').iloc[0] # 最优日
worst_day = daily[~daily['等级'].isin(['优', '良'])].sort_values('AQI', ascending=False).iloc[0] # 最差日
# 6. 季节性差异(按季度分组)
daily['季度'] = daily['date'].dt.month.apply(
lambda x: '春季' if x in [1,2,3] else '夏季' if x in [4,5,6] else '秋季' if x in [7,8,9] else '冬季'
)
seasonal_pm25 = daily.groupby('季度')['PM2.5'].mean().reindex(['春季', '夏季', '秋季', '冬季'])
# 7. 结果输出
print("=== 2016年空气质量核心指标 ===")
print(f"1. PM2.5年均浓度:{pm25_annual:.2f} μg/m³")
print(f"2. 优良天数:{excellent_days} 天,占比:{excellent_ratio:.1f}%")
print(f"3. 轻度及以上污染天数:{pollution_days} 天\n")
print("=== 极值日期 ===")
print(f"最优日:{best_day['date'].strftime('%Y-%m-%d')},PM2.5:{best_day['PM2.5']:.2f} μg/m³,等级:{best_day['等级']}")
print(f"最差日:{worst_day['date'].strftime('%Y-%m-%d')},PM2.5:{worst_day['PM2.5']:.2f} μg/m³,等级:{worst_day['等级']}\n")
print("=== 季节性PM2.5浓度 ===")
for season, pm25 in seasonal_pm25.items():
print(f"{season}:{pm25:.2f} μg/m³")
print(f"\n结论:冬季PM2.5({seasonal_pm25['冬季']:.2f})显著高于夏季({seasonal_pm25['夏季']:.2f}),差值:{seasonal_pm25['冬季']-seasonal_pm25['夏季']:.2f} μg/m³")

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
plt.switch_backend('Agg')
# 1. 基础配置(解决后端+中文问题)
plt.switch_backend('Agg')
plt.rcParams['font.sans-serif'] = ['SimHei', 'WenQuanYi Zen Hei']
plt.rcParams['axes.unicode_minus'] = False
# 2. 加载数据(同目录下的shuju_with_aqi.csv)
df = pd.read_csv('shuju_with_aqi.csv')
df['date'] = pd.to_datetime(df[['year', 'month', 'day']])
df = df[(df['year'] >= 2013) & (df['year'] <= 2017)] # 筛选2013-2017年
# 3. 数据聚合
# 3.1 PM2.5年均浓度(用于图1)
annual_pm25 = df.groupby('year')['PM2.5'].mean().reset_index()
# 3.2 2013-2017年每季AQI(用于图2)
df['季度'] = df['month'].apply(lambda x: ['春季', '夏季', '秋季', '冬季'][(x-1)//3])
df['年季'] = df['year'].astype(str) + '-' + df['季度']
season_order = [f'{y}-{s}' for y in range(2013,2018) for s in ['春季','夏季','秋季','冬季']]
seasonal_aqi = df.groupby('年季')['AQI'].mean()
seasonal_aqi = seasonal_aqi.reindex(season_order) # 按时间排序
# 4. 图1:PM2.5年均浓度柱状图(单独保存)
plt.figure(figsize=(10, 5))
plt.bar(annual_pm25['year'], annual_pm25['PM2.5'], color='#FF6B6B', alpha=0.8)
plt.xlabel('年份', fontsize=11)
plt.ylabel('PM2.5浓度 (μg/m³)', fontsize=11)
plt.title('2013-2017年PM2.5年均浓度', fontsize=12, fontweight='bold')
plt.grid(axis='y', alpha=0.3)
# 添加数值标签
for x, y in zip(annual_pm25['year'], annual_pm25['PM2.5']):
plt.text(x, y+2, f'{y:.1f}', ha='center', fontsize=10)
plt.tight_layout()
plt.savefig('2013-2017_PM25年均浓度图.png', dpi=300)
plt.close()
# 5. 图2:2013-2017年四季AQI折线图(单独保存)
plt.figure(figsize=(12, 5))
plt.plot(seasonal_aqi.index, seasonal_aqi.values, marker='o', linewidth=2,
markersize=5, color='#4ECDC4', markerfacecolor='#FFD700')
plt.xlabel('年份-季度', fontsize=11)
plt.ylabel('AQI均值', fontsize=11)
plt.title('2013-2017年各季度AQI变化', fontsize=12, fontweight='bold')
plt.xticks(rotation=45) # 旋转x轴标签防重叠
plt.grid(alpha=0.3)
# 每年春季标数值(避免拥挤)
for i, (x, y) in enumerate(seasonal_aqi.items()):
if i % 4 == 0:
plt.text(x, y+3, f'{y:.1f}', ha='center', fontsize=9)
plt.tight_layout()
plt.savefig('2013-2017_四季AQI变化图.png', dpi=300)
plt.close()
# 6. 结果提示
print("✅ AQI健康建议规则已生成(见上文表格)")
print("✅ 两张图表已分别保存:")
print(" 1. 2013-2017_PM25年均浓度图.png")
print(" 2. 2013-2017_四季AQI变化图.png")
各类型电影总票房饼图

春节档vs非档期电影平均票房柱状图

电影评分与总票房散点图

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)