🧑 博主简介:曾任某智慧城市类企业算法总监,目前在美国市场的物流公司从事高级算法工程师一职,深耕人工智能领域,精通python数据挖掘、可视化、机器学习等,发表过AI相关的专利并多次在AI类比赛中获奖。CSDN人工智能领域的优质创作者,提供AI相关的技术咨询、项目开发和个性化解决方案等服务,如有需要请站内私信或者联系任意文章底部的的VX名片(ID:xf982831907

💬 博主粉丝群介绍:① 群内初中生、高中生、本科生、研究生、博士生遍布,可互相学习,交流困惑。② 热榜top10的常客也在群里,也有数不清的万粉大佬,可以交流写作技巧,上榜经验,涨粉秘籍。③ 群内也有职场精英,大厂大佬,可交流技术、面试、找工作的经验。④ 进群免费赠送写作秘籍一份,助你由写作小白晋升为创作大佬。⑤ 进群赠送CSDN评论防封脚本,送真活跃粉丝,助你提升文章热度。有兴趣的加文末联系方式,备注自己的CSDN昵称,拉你进群,互相学习共同进步。

在这里插入图片描述


引言

在ChatGPT、Gemini、Copilot等人工智能工具迅速普及的当下,教育领域正经历着一场前所未有的变革。人工智能辅助学习工具已经从"锦上添花"变为"日常必备",深刻影响着学生的学习方式和学术表现。然而,一个关键问题日益凸显:AI工具的使用究竟是促进学生学业成功的神奇帮手,还是削弱独立思考能力的"双刃剑"?。
本文基于8000名学生的学业表现与AI使用数据,深入分析了AI依赖度对学生学习成绩的影响,并构建了预测学生是否通过考试的机器学习模型。本博客将完整展示从数据探索、特征工程到模型训练评估的全过程。

1. 数据集概览

1.1 数据基本信息

该数据集包含8000条学生记录,涵盖26个特征,主要分为四个维度:

1.1.1 人口统计学特征

字段名 数据类型 说明 缺失情况
student_id int64 学生唯一标识ID,用于样本区分 无缺失(8000条)
age int64 学生年龄(数值型) 无缺失(8000条)
gender object 学生性别(分类型,如男/女/其他) 无缺失(8000条)
grade_level object 年级/学段(分类型,如初中/高中/大学) 无缺失(8000条)

1.1.2 AI使用行为特征

字段名 数据类型 说明 缺失情况
uses_ai int64 是否使用AI工具(二分类:0=不使用,1=使用) 无缺失(8000条)
ai_usage_time_minutes int64 每日AI使用时长(单位:分钟) 无缺失(8000条)
ai_tools_used object 使用的AI工具类型(多分类/文本型,如ChatGPT/豆包/讯飞星火等) 部分缺失(6638条有效数据)
ai_usage_purpose object AI使用目的(分类型,如知识点学习/作业完成/论文写作等) 部分缺失(6654条有效数据)
ai_dependency_score int64 AI依赖度评分(数值型,分值越高依赖度越强) 无缺失(8000条)
ai_generated_content_percentage int64 AI生成内容占作业/考试的比例(百分比,0-100) 无缺失(8000条)
ai_prompts_per_week int64 每周使用AI的提示词数量(数值型) 无缺失(8000条)
ai_ethics_score int64 AI伦理认知评分(数值型,反映对AI使用规范、学术诚信的认知程度) 无缺失(8000条)

1.1.3 学习过程特征

字段名 数据类型 说明 缺失情况
study_hours_per_day float64 每日自主学习时长(单位:小时,含小数) 无缺失(8000条)
attendance_percentage float64 出勤率(百分比,0-100) 无缺失(8000条)
study_consistency_index float64 学习一致性指数(数值型,反映学习行为的稳定性) 无缺失(8000条)
sleep_hours float64 每日睡眠时间(单位:小时) 无缺失(8000条)
social_media_hours float64 每日社交媒体使用时长(单位:小时) 无缺失(8000条)
tutoring_hours float64 每周辅导时长(单位:小时) 无缺失(8000条)
class_participation_score int64 课堂参与度评分(数值型,反映课堂互动、回答问题等表现) 无缺失(8000条)

1.1.4 学业成果特征

字段名 数据类型 说明 缺失情况
last_exam_score int64 最近一次考试成绩(数值型) 无缺失(8000条)
assignment_scores_avg float64 作业平均成绩(含小数) 无缺失(8000条)
concept_understanding_score int64 概念理解能力评分(核心学业能力指标,反映对知识点的掌握程度) 无缺失(8000条)
improvement_rate float64 成绩提升率(百分比,反映一段时间内的成绩变化趋势) 无缺失(8000条)
final_score float64 最终总成绩(核心因变量) 无缺失(8000条)
passed int64 是否通过考核(二分类:0=未通过,1=通过) 无缺失(8000条)
performance_category object 学业表现分类(分类型,如优秀/良好/及格/不及格) 无缺失(8000条)
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from math import pi
import warnings
warnings.filterwarnings('ignore')

# 设置中文字体和样式
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.figsize'] = (12, 8)
plt.rcParams['font.size'] = 12

# 加载数据
file_path = 'ai_impact_student_performance_dataset.csv'
df = pd.read_csv(file_path)

print("="*60)
print("数据集基本信息")
print("="*60)
print(f"数据形状: {df.shape}")
print(f"特征数量: {len(df.columns)}")
print(f"记录数量: {len(df):,}")
print(f"是否存在缺失值: {df.isnull().sum().sum() > 0}")

print("\n前5行数据预览:")
display(df.head())
print("\n数据列信息:")
print(df.info())

2. 数据预处理与探索性分析

2.1 数据集概况可视化

# 数据概览可视化
def dataset_overview_viz(df):
    """数据集概览可视化"""
    fig, axes = plt.subplots(2, 2, figsize=(16, 12))
    fig.suptitle('数据集概览', fontsize=18, fontweight='bold', y=0.98)
    
    # 1. 特征类型分布
    ax1 = axes[0, 0]
    dtype_counts = df.dtypes.value_counts()
    colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
    wedges, texts, autotexts = ax1.pie(dtype_counts.values, labels=dtype_counts.index, 
                                       autopct='%1.1f%%', colors=colors[:len(dtype_counts)],
                                       startangle=90, explode=(0.05, 0.05, 0.05)[:len(dtype_counts)])
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontweight('bold')
    ax1.set_title('数据类型分布', fontsize=14)
    
    # 2. 缺失值可视化
    ax2 = axes[0, 1]
    missing_data = df.isnull().sum()
    missing_data = missing_data[missing_data > 0]
    if len(missing_data) > 0:
        bars = ax2.bar(missing_data.index, missing_data.values, color='#FFA726')
        ax2.set_title('缺失值分布', fontsize=14)
        ax2.set_ylabel('缺失值数量')
        ax2.tick_params(axis='x', rotation=45)
        # 添加数值标签
        for bar in bars:
            height = bar.get_height()
            ax2.text(bar.get_x() + bar.get_width()/2., height + 5,
                    f'{int(height)}', ha='center', va='bottom', fontweight='bold')
    else:
        ax2.text(0.5, 0.5, '无缺失值', ha='center', va='center', fontsize=16)
        ax2.set_title('缺失值分布', fontsize=14)
    
    # 3. 核心数值特征分布
    ax3 = axes[1, 0]
    core_numerical = ['final_score', 'ai_dependency_score', 'study_hours_per_day']
    for col in core_numerical:
        if col in df.columns:
            sns.kdeplot(df[col], ax=ax3, label=col.replace('_', ' ').title(), linewidth=2)
    ax3.set_title('核心数值特征分布', fontsize=14)
    ax3.set_xlabel('数值')
    ax3.set_ylabel('密度')
    ax3.legend()
    ax3.grid(True, alpha=0.3)
    
    # 4. 分类特征分布(通过率)
    ax4 = axes[1, 1]
    pass_rate = df['passed'].value_counts()
    pass_labels = ['未通过', '通过']
    bars = ax4.bar(pass_labels, pass_rate.values, color=['#FF6B6B', '#4ECDC4'])
    ax4.set_title('考试通过情况分布', fontsize=14)
    ax4.set_ylabel('学生数量')
    # 添加百分比标签
    total = pass_rate.sum()
    for bar, count in zip(bars, pass_rate.values):
        percentage = count / total * 100
        ax4.text(bar.get_x() + bar.get_width()/2., bar.get_height() + 50,
                f'{count:,}\n({percentage:.1f}%)', ha='center', va='bottom', fontweight='bold')
    
    plt.tight_layout()
    plt.subplots_adjust(top=0.93)
    plt.show()

# 执行数据集概览可视化
dataset_overview_viz(df)


通过可视化分析,清晰呈现了数据集的核心特征:

  • 数据类型分布:数值型特征(int64/float64)占主导,确保了机器学习建模的可行性;
  • 缺失值分布:仅ai_tools_used和ai_usage_purpose存在少量缺失,占比极低,不影响整体分析;
  • 核心数值特征分布:期末成绩、AI 依赖度、每日学习时间均呈现合理的分布形态,无极端偏态;
  • 考试通过率:通过与未通过学生数量分布相对均衡,避免了数据偏斜对模型的影响。

2.2 数据清洗

# 数据清洗函数
def clean_data(df):
    """执行数据清洗操作"""
    df_clean = df.copy()
    
    # 1. 处理缺失值
    missing_cols = ['ai_tools_used', 'ai_usage_purpose']
    for col in missing_cols:
        if col in df_clean.columns:
            df_clean[col] = df_clean[col].fillna('None')
    
    # 2. 检查数据类型
    print("数据类型分布:")
    for dtype in ['object', 'int64', 'float64']:
        cols = df_clean.select_dtypes(include=[dtype]).columns
        if len(cols) > 0:
            print(f"{dtype}: {len(cols)}列")
    
    # 3. 检查异常值
    numeric_cols = df_clean.select_dtypes(include=['int64', 'float64']).columns
    outlier_report = {}
    
    for col in numeric_cols:
        if col not in ['student_id', 'passed']:  # 排除ID和标签列
            Q1 = df_clean[col].quantile(0.25)
            Q3 = df_clean[col].quantile(0.75)
            IQR = Q3 - Q1
            lower_bound = Q1 - 1.5 * IQR
            upper_bound = Q3 + 1.5 * IQR
            
            outliers = df_clean[(df_clean[col] < lower_bound) | (df_clean[col] > upper_bound)]
            if len(outliers) > 0:
                outlier_report[col] = {
                    'outlier_count': len(outliers),
                    'percentage': len(outliers)/len(df_clean)*100,
                    'min': df_clean[col].min(),
                    'max': df_clean[col].max()
                }
    
    print(f"\n发现 {len(outlier_report)} 个数值列存在异常值")
    
    return df_clean, outlier_report

# 执行数据清洗
df_clean, outlier_report = clean_data(df)

print("\n清洗后的数据信息:")
print(f"总记录数: {len(df_clean)}")
print(f"缺失值总数: {df_clean.isnull().sum().sum()}")


针对数据集开展了标准化清洗工作:

  • 缺失值处理:对少量缺失的 AI 工具类型、使用目的字段填充为 “None”,保证数据完整性;
  • 数据类型校验:确认各字段数据类型与业务含义匹配,无需额外转换;
  • 异常值检测:通过四分位数法(IQR)识别出部分数值字段的异常值,量化了异常值数量和占比,为后续分析提供了异常值参考依据。
    清洗后数据集无缺失值,记录数保持 8000 条,数据质量满足分析要求。

2.3 基础统计分析

def basic_statistics_analysis(df):
    """执行基础统计分析"""
    
    print("基础统计分析")
    print("="*60)
    
    # 1. 数值型特征统计
    numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns
    numeric_stats = df[numeric_cols].describe().T
    
    # 2. 分类特征统计
    categorical_cols = df.select_dtypes(include=['object']).columns
    print(f"分类特征: {list(categorical_cols)}")
    
    for col in categorical_cols:
        if col in df.columns:
            print(f"\n{col} 的分布:")
            print(df[col].value_counts().head())
    
    # 3. 核心指标分析
    print("\n核心指标分析:")
    core_metrics = ['final_score', 'ai_dependency_score', 'ai_ethics_score', 
                    'concept_understanding_score', 'study_hours_per_day']
    
    for metric in core_metrics:
        if metric in df.columns:
            print(f"{metric}: 均值={df[metric].mean():.2f}, 标准差={df[metric].std():.2f}, "
                  f"范围=[{df[metric].min():.2f}, {df[metric].max():.2f}]")
    
    return numeric_stats

# 执行统计分析
numeric_stats = basic_statistics_analysis(df_clean)


通过统计分析挖掘了数据的核心特征:

  • 数值特征统计:获取了各核心指标的均值、标准差、最值等关键统计量,明确了数据分布范围;
  • 分类特征分布:梳理了性别、年级、学业表现类别等分类特征的分布情况;

3. 数据可视化分析

3.1 分布分析可视化

def distribution_visualization(df):
    """分布可视化分析"""
    
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    fig.suptitle('学生数据分布分析', fontsize=16, fontweight='bold', y=1.02)
    
    # 1. AI使用与最终成绩分布
    ax1 = axes[0, 0]
    ai_users = df[df['uses_ai'] == 1]['final_score']
    non_ai_users = df[df['uses_ai'] == 0]['final_score']
    
    ax1.hist(ai_users, bins=30, alpha=0.5, label='使用AI', color='#FF6B6B', density=True)
    ax1.hist(non_ai_users, bins=30, alpha=0.5, label='不使用AI', color='#4ECDC4', density=True)
    ax1.axvline(df['final_score'].mean(), color='red', linestyle='--', linewidth=2, 
               label=f'总体均值: {df["final_score"].mean():.1f}')
    ax1.set_xlabel('最终成绩')
    ax1.set_ylabel('密度')
    ax1.set_title('AI使用与最终成绩分布')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 2. AI依赖度分布
    ax2 = axes[0, 1]
    dependency_bins = pd.cut(df['ai_dependency_score'], bins=10)
    dependency_dist = df.groupby(dependency_bins).size()
    
    colors = plt.cm.YlOrRd(np.linspace(0.4, 1, len(dependency_dist)))
    bars = ax2.bar(range(len(dependency_dist)), dependency_dist.values, color=colors)
    ax2.set_xlabel('AI依赖度分数区间')
    ax2.set_ylabel('学生数量')
    ax2.set_title('AI依赖度分布')
    ax2.set_xticks(range(len(dependency_dist)))
    ax2.set_xticklabels([str(b)[1:-1] for b in dependency_dist.index], rotation=45, ha='right')
    
    # 添加数值标签
    for bar, count in zip(bars, dependency_dist.values):
        height = bar.get_height()
        ax2.text(bar.get_x() + bar.get_width()/2., height + 20,
                f'{count}', ha='center', va='bottom', fontsize=9)
    
    # 3. 成绩类别分布
    ax3 = axes[0, 2]
    performance_counts = df['performance_category'].value_counts()
    colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
    wedges, texts, autotexts = ax3.pie(performance_counts.values, 
                                      labels=performance_counts.index,
                                      colors=colors, autopct='%1.1f%%',
                                      startangle=90, explode=(0.05, 0.05, 0.05))
    
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontweight('bold')
    
    ax3.set_title('学业表现类别分布')
    
    # 4. AI伦理分数与概念理解关系
    ax4 = axes[1, 0]
    scatter = ax4.scatter(df['ai_ethics_score'], df['concept_understanding_score'],
                         c=df['final_score'], cmap='viridis', alpha=0.6, s=50)
    ax4.set_xlabel('AI伦理分数')
    ax4.set_ylabel('概念理解分数')
    ax4.set_title('AI伦理与概念理解关系')
    plt.colorbar(scatter, ax=ax4, label='最终成绩')
    ax4.grid(True, alpha=0.3)
    
    # 5. 学习时间与成绩关系
    ax5 = axes[1, 1]
    ax5.hexbin(df['study_hours_per_day'], df['final_score'], 
               gridsize=30, cmap='YlOrRd', mincnt=1)
    ax5.set_xlabel('每日学习时间 (小时)')
    ax5.set_ylabel('最终成绩')
    ax5.set_title('学习时间与成绩关系')
    
    # 添加趋势线
    z = np.polyfit(df['study_hours_per_day'], df['final_score'], 1)
    p = np.poly1d(z)
    ax5.plot(sorted(df['study_hours_per_day']), 
             p(sorted(df['study_hours_per_day'])), 
             "r--", alpha=0.8, linewidth=2)
    
    # 6. 多维度箱线图
    ax6 = axes[1, 2]
    boxplot_data = []
    box_labels = []
    
    metrics = ['ai_dependency_score', 'ai_ethics_score', 'study_hours_per_day', 
               'concept_understanding_score']
    
    for metric in metrics:
        boxplot_data.append(df[metric].values)
        box_labels.append(metric.replace('_', ' ').title())
    
    bp = ax6.boxplot(boxplot_data, labels=box_labels, patch_artist=True)
    
    # 设置箱线图颜色
    colors_box = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA726']
    for patch, color in zip(bp['boxes'], colors_box):
        patch.set_facecolor(color)
        patch.set_alpha(0.7)
    
    ax6.set_ylabel('分数')
    ax6.set_title('关键指标分布箱线图')
    ax6.tick_params(axis='x', rotation=45)
    ax6.grid(True, alpha=0.3, axis='y')
    
    plt.tight_layout()
    plt.show()

# 执行可视化
distribution_visualization(df_clean)


从多维度可视化了学生数据的分布特征:

  • AI 使用与成绩关系:使用 AI 的学生与未使用 AI 的学生成绩分布存在差异,但无绝对优劣之分;
  • AI 依赖度分布:学生 AI 依赖度呈现中等集中的特点,过高或过低依赖度的学生占比均较低;
  • AI 伦理与概念理解:AI 伦理分数与概念理解分数呈正相关,且与最终成绩高度关联;
  • 学习时间与成绩:学习时间与成绩呈弱正相关,但并非线性增长,存在最优时长区间;
  • 关键指标箱线图:直观展示了 AI 依赖度、伦理分数、学习时间等指标的离散程度和异常值分布。

3.2 人口统计学特征分析

# 人口统计学特征分析
def demographic_analysis(df):
    """人口统计学特征可视化分析"""
    fig, axes = plt.subplots(2, 2, figsize=(18, 14))
    fig.suptitle('人口统计学特征分析', fontsize=18, fontweight='bold', y=0.98)
    
    # 1. 年龄分布
    ax1 = axes[0, 0]
    age_bins = range(df['age'].min(), df['age'].max() + 2, 2)
    ax1.hist(df['age'], bins=age_bins, color='#4ECDC4', edgecolor='black', alpha=0.7)
    ax1.set_title('学生年龄分布', fontsize=14)
    ax1.set_xlabel('年龄')
    ax1.set_ylabel('学生数量')
    ax1.axvline(df['age'].mean(), color='red', linestyle='--', linewidth=2, 
                label=f'平均年龄: {df["age"].mean():.1f}')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    
    # 2. 性别分布与成绩关系
    ax2 = axes[0, 1]
    gender_score = df.groupby('gender')['final_score'].agg(['mean', 'std', 'count'])
    x = range(len(gender_score))
    width = 0.6
    
    bars = ax2.bar(x, gender_score['mean'], width, yerr=gender_score['std'], 
                   capsize=5, color=['#FF6B6B', '#45B7D1', '#FFA726'][:len(x)])
    ax2.set_title('不同性别学生平均成绩', fontsize=14)
    ax2.set_xlabel('性别')
    ax2.set_ylabel('平均最终成绩')
    ax2.set_xticks(x)
    ax2.set_xticklabels(gender_score.index)
    
    # 添加数值标签
    for i, (bar, count) in enumerate(zip(bars, gender_score['count'])):
        height = bar.get_height()
        ax2.text(bar.get_x() + bar.get_width()/2., height + 1,
                f'{height:.1f}\n(n={count:,})', ha='center', va='bottom', fontweight='bold')
    
    # 3. 年级分布
    ax3 = axes[1, 0]
    grade_counts = df['grade_level'].value_counts()
    colors = plt.cm.Set3(np.linspace(0, 1, len(grade_counts)))
    wedges, texts, autotexts = ax3.pie(grade_counts.values, labels=grade_counts.index,
                                       autopct='%1.1f%%', colors=colors, startangle=90)
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontweight('bold')
    ax3.set_title('年级分布', fontsize=14)
    
    # 4. 年级与AI使用关系
    ax4 = axes[1, 1]
    grade_ai = df.groupby('grade_level')['uses_ai'].mean() * 100
    bars = ax4.bar(grade_ai.index, grade_ai.values, color=plt.cm.viridis(np.linspace(0, 1, len(grade_ai))))
    ax4.set_title('不同年级AI使用率', fontsize=14)
    ax4.set_xlabel('年级')
    ax4.set_ylabel('AI使用率 (%)')
    ax4.tick_params(axis='x', rotation=45)
    
    # 添加数值标签
    for bar in bars:
        height = bar.get_height()
        ax4.text(bar.get_x() + bar.get_width()/2., height + 1,
                f'{height:.1f}%', ha='center', va='bottom', fontweight='bold')
    
    plt.tight_layout()
    plt.subplots_adjust(top=0.93)
    plt.show()

# 执行人口统计学分析
demographic_analysis(df_clean)


聚焦人口统计学维度的核心发现:

  • 年龄分布:学生年龄集中在青少年阶段,平均年龄约 16-18 岁,分布符合学业阶段特征;
  • 性别与成绩:不同性别学生的平均成绩差异较小,无显著性别偏向;
  • 年级分布:各年级学生占比相对均衡,高年级学生 AI 使用率略高于低年级;
  • 年级与 AI 使用:AI 使用率随年级升高呈上升趋势,反映了不同学段学生对 AI 工具的接受度差异。

3.3 AI 使用行为深度分析

# AI使用行为深度分析
def ai_usage_analysis(df):
    """AI使用行为深度可视化分析"""
    # 只分析使用AI的学生
    ai_users_df = df[df['uses_ai'] == 1].copy()
    
    fig, axes = plt.subplots(2, 3, figsize=(20, 14))
    fig.suptitle('AI使用行为深度分析 (仅AI用户)', fontsize=18, fontweight='bold', y=0.98)
    
    # 1. AI使用时长分布
    ax1 = axes[0, 0]
    usage_time_bins = [0, 15, 30, 60, 120, 180, np.inf]
    usage_time_labels = ['0-15', '15-30', '30-60', '60-120', '120-180', '>180']
    ai_users_df['usage_time_bin'] = pd.cut(ai_users_df['ai_usage_time_minutes'], 
                                          bins=usage_time_bins, labels=usage_time_labels)
    time_dist = ai_users_df['usage_time_bin'].value_counts().sort_index()
    
    bars = ax1.bar(time_dist.index, time_dist.values, color=plt.cm.Oranges(np.linspace(0.4, 1, len(time_dist))))
    ax1.set_title('AI每日使用时长分布 (分钟)', fontsize=14)
    ax1.set_xlabel('使用时长区间')
    ax1.set_ylabel('学生数量')
    
    for bar in bars:
        height = bar.get_height()
        ax1.text(bar.get_x() + bar.get_width()/2., height + 10,
                f'{height}', ha='center', va='bottom', fontsize=10)
    
    # 2. AI使用目的分布
    ax2 = axes[0, 1]
    if 'ai_usage_purpose' in ai_users_df.columns:
        purpose_dist = ai_users_df['ai_usage_purpose'].value_counts().head(6)
        bars = ax2.barh(range(len(purpose_dist)), purpose_dist.values, 
                       color=plt.cm.Paired(np.linspace(0, 1, len(purpose_dist))))
        ax2.set_yticks(range(len(purpose_dist)))
        ax2.set_yticklabels(purpose_dist.index)
        ax2.set_title('AI主要使用目的 (Top 6)', fontsize=14)
        ax2.set_xlabel('学生数量')
        
        for i, bar in enumerate(bars):
            width = bar.get_width()
            ax2.text(width + 5, bar.get_y() + bar.get_height()/2,
                    f'{width}', ha='left', va='center', fontsize=10)
    
    # 3. AI生成内容比例分布
    ax3 = axes[0, 2]
    content_bins = [0, 10, 25, 50, 75, 100]
    content_labels = ['0-10%', '10-25%', '25-50%', '50-75%', '75-100%']
    ai_users_df['content_bin'] = pd.cut(ai_users_df['ai_generated_content_percentage'],
                                       bins=content_bins, labels=content_labels)
    content_dist = ai_users_df['content_bin'].value_counts().sort_index()
    
    colors = plt.cm.Reds(np.linspace(0.4, 1, len(content_dist)))
    wedges, texts, autotexts = ax3.pie(content_dist.values, labels=content_dist.index,
                                       autopct='%1.1f%%', colors=colors, startangle=90)
    for autotext in autotexts:
        autotext.set_color('white')
        autotext.set_fontweight('bold')
    ax3.set_title('AI生成内容占比分布', fontsize=14)
    
    # 4. AI依赖度与成绩关系
    ax4 = axes[1, 0]
    dependency_bins = [0, 3, 6, 9, 12]
    ai_users_df['dependency_bin'] = pd.cut(ai_users_df['ai_dependency_score'], bins=dependency_bins)
    dependency_score = ai_users_df.groupby('dependency_bin')['final_score'].agg(['mean', 'std'])
    
    x = range(len(dependency_score))
    bars = ax4.bar(x, dependency_score['mean'], yerr=dependency_score['std'],
                   capsize=5, color=plt.cm.Blues(np.linspace(0.5, 1, len(x))))
    ax4.set_title('不同AI依赖度的平均成绩', fontsize=14)
    ax4.set_xlabel('AI依赖度区间')
    ax4.set_ylabel('平均最终成绩')
    ax4.set_xticks(x)
    ax4.set_xticklabels([str(b)[1:-1] for b in dependency_score.index])
    
    for bar in bars:
        height = bar.get_height()
        ax4.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                f'{height:.1f}', ha='center', va='bottom', fontsize=10)
    
    # 5. AI提示词使用频率
    ax5 = axes[1, 1]
    prompt_bins = [0, 5, 10, 20, 30, np.inf]
    prompt_labels = ['0-5', '5-10', '10-20', '20-30', '>30']
    ai_users_df['prompt_bin'] = pd.cut(ai_users_df['ai_prompts_per_week'],
                                      bins=prompt_bins, labels=prompt_labels)
    prompt_dist = ai_users_df['prompt_bin'].value_counts().sort_index()
    
    bars = ax5.bar(prompt_dist.index, prompt_dist.values,
                   color=plt.cm.Greens(np.linspace(0.4, 1, len(prompt_dist))))
    ax5.set_title('每周AI提示词使用数量', fontsize=14)
    ax5.set_xlabel('提示词数量区间')
    ax5.set_ylabel('学生数量')
    
    for bar in bars:
        height = bar.get_height()
        ax5.text(bar.get_x() + bar.get_width()/2., height + 5,
                f'{height}', ha='center', va='bottom', fontsize=10)
    
    # 6. AI伦理分数与依赖度散点图
    ax6 = axes[1, 2]
    scatter = ax6.scatter(ai_users_df['ai_ethics_score'], 
                         ai_users_df['ai_dependency_score'],
                         c=ai_users_df['final_score'], 
                         cmap='coolwarm', alpha=0.6, s=60)
    ax6.set_title('AI伦理分数 vs AI依赖度', fontsize=14)
    ax6.set_xlabel('AI伦理分数')
    ax6.set_ylabel('AI依赖度分数')
    plt.colorbar(scatter, ax=ax6, label='最终成绩')
    ax6.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.subplots_adjust(top=0.93)
    plt.show()

# 执行AI使用行为分析
ai_usage_analysis(df_clean)


针对 AI 用户开展了专项分析(仅分析使用 AI 的学生):

  • 使用时长分布:多数学生每日 AI 使用时长集中在 60-180 分钟,过长或过短使用时长的学生占比低;
  • 使用目的:AI 主要用于知识点学习和作业完成,娱乐性使用占比极低;
  • AI 生成内容占比:大部分学生 AI 生成内容占比低于 25%,过度依赖 AI 生成内容的学生占比不足 10%;
  • 依赖度与成绩:中等 AI 依赖度学生平均成绩最高,低依赖和高依赖学生成绩均偏低;
  • 伦理分数与依赖度:AI 伦理分数高的学生,依赖度更趋于合理,且最终成绩更高。

3.4 学习习惯与成绩关系分析

# 学习习惯与成绩关系分析
def study_habits_analysis(df):
    """学习习惯与成绩关系可视化分析"""
    fig, axes = plt.subplots(2, 3, figsize=(20, 14))
    fig.suptitle('学习习惯与学业成绩关系分析', fontsize=18, fontweight='bold', y=0.98)
    
    # 1. 睡眠时间与成绩关系
    ax1 = axes[0, 0]
    sleep_bins = [0, 5, 6, 7, 8, 9, 12]
    df['sleep_bin'] = pd.cut(df['sleep_hours'], bins=sleep_bins)
    sleep_score = df.groupby('sleep_bin')['final_score'].mean()
    
    ax1.plot(range(len(sleep_score)), sleep_score.values, 'o-', linewidth=3, markersize=8, color='#4ECDC4')
    ax1.set_title('睡眠时间与平均成绩关系', fontsize=14)
    ax1.set_xlabel('睡眠时间区间 (小时)')
    ax1.set_ylabel('平均最终成绩')
    ax1.set_xticks(range(len(sleep_score)))
    ax1.set_xticklabels([str(b)[1:-1] for b in sleep_score.index], rotation=45)
    ax1.grid(True, alpha=0.3)
    
    # 2. 社交媒体使用时间vs学习时间
    ax2 = axes[0, 1]
    scatter = ax2.scatter(df['social_media_hours'], df['study_hours_per_day'],
                         c=df['final_score'], cmap='RdYlGn', alpha=0.6, s=50)
    ax2.set_title('社交媒体时间 vs 学习时间', fontsize=14)
    ax2.set_xlabel('每日社交媒体时间 (小时)')
    ax2.set_ylabel('每日学习时间 (小时)')
    plt.colorbar(scatter, ax=ax2, label='最终成绩')
    ax2.grid(True, alpha=0.3)
    
    # 3. 辅导时间效果分析
    ax3 = axes[0, 2]
    tutoring_bins = [0, 1, 2, 4, 8, np.inf]
    tutoring_labels = ['0', '0-1', '1-2', '2-4', '>4']
    df['tutoring_bin'] = pd.cut(df['tutoring_hours'], bins=tutoring_bins, labels=tutoring_labels)
    tutoring_score = df.groupby('tutoring_bin')['final_score'].mean()
    
    bars = ax3.bar(tutoring_score.index, tutoring_score.values, color=plt.cm.Purples(np.linspace(0.4, 1, len(tutoring_score))))
    ax3.set_title('每周辅导时间与平均成绩', fontsize=14)
    ax3.set_xlabel('辅导时间 (小时/周)')
    ax3.set_ylabel('平均最终成绩')
    
    for bar in bars:
        height = bar.get_height()
        ax3.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                f'{height:.1f}', ha='center', va='bottom', fontsize=10)
    
    # 4. 出勤率与成绩关系
    ax4 = axes[1, 0]
    ax4.hexbin(df['attendance_percentage'], df['final_score'],
               gridsize=25, cmap='YlGnBu', mincnt=1)
    ax4.set_title('出勤率与最终成绩关系', fontsize=14)
    ax4.set_xlabel('出勤率 (%)')
    ax4.set_ylabel('最终成绩')
    
    # 添加趋势线
    z = np.polyfit(df['attendance_percentage'], df['final_score'], 1)
    p = np.poly1d(z)
    ax4.plot(sorted(df['attendance_percentage']), 
             p(sorted(df['attendance_percentage'])), 
             "r--", alpha=0.8, linewidth=2)
    
    # 5. 学习一致性与成绩提升率
    ax5 = axes[1, 1]
    ax5.scatter(df['study_consistency_index'], df['improvement_rate'],
               alpha=0.6, c='#FF6B6B', s=50)
    ax5.set_title('学习一致性与成绩提升率', fontsize=14)
    ax5.set_xlabel('学习一致性指数')
    ax5.set_ylabel('成绩提升率 (%)')
    ax5.grid(True, alpha=0.3)
    
    # 添加趋势线
    z = np.polyfit(df['study_consistency_index'], df['improvement_rate'], 1)
    p = np.poly1d(z)
    ax5.plot(sorted(df['study_consistency_index']), 
             p(sorted(df['study_consistency_index'])), 
             "blue", alpha=0.8, linewidth=2)
    
    # 6. 课堂参与度分布
    ax6 = axes[1, 2]
    sns.kdeplot(data=df, x='class_participation_score', hue='passed',
                fill=True, alpha=0.5, linewidth=2, ax=ax6)
    ax6.set_title('课堂参与度分数分布 (按通过状态)', fontsize=14)
    ax6.set_xlabel('课堂参与度分数')
    ax6.set_ylabel('密度')
    ax6.legend(['未通过', '通过'])
    ax6.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.subplots_adjust(top=0.93)
    plt.show()

# 执行学习习惯分析
study_habits_analysis(df_clean)


揭示了学习习惯对学业表现的核心影响:

  • 睡眠时间:5-6 小时睡眠时间的学生平均成绩最高,睡眠不足或过多均会影响成绩;
  • 社交媒体与学习时间:社交媒体使用时间与学习时间呈负相关,且与最终成绩呈弱负相关;
  • 辅导时间效果:适量辅导(0-1 小时 / 周)效果最佳,过度辅导未带来成绩显著提升;
  • 出勤率与成绩:出勤率与最终成绩呈强正相关,是学业表现的重要保障;
  • 学习一致性:学习行为越稳定,成绩提升率越高;
  • 课堂参与度:通过考试的学生课堂参与度显著高于未通过学生。

3.5 相关性分析

def correlation_analysis(df):
    """相关性分析"""
    
    # 选择数值型特征
    numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns
    
    # 移除ID和分类标签列
    exclude_cols = ['student_id', 'passed']
    numeric_cols = [col for col in numeric_cols if col not in exclude_cols]
    
    # 计算相关性矩阵
    corr_matrix = df[numeric_cols].corr()
    
    # 创建可视化
    fig, axes = plt.subplots(1, 2, figsize=(20, 8))
    
    # 1. 相关性热力图
    mask = np.triu(np.ones_like(corr_matrix, dtype=bool))
    sns.heatmap(corr_matrix, mask=mask, cmap='coolwarm', center=0,
                annot=False, linewidths=0.5, cbar_kws={"shrink": 0.8}, ax=axes[0])
    axes[0].set_title('特征相关性热力图', fontsize=14, fontweight='bold')
    axes[0].set_xticklabels(axes[0].get_xticklabels(), rotation=45, ha='right')
    
    # 2. 与最终成绩相关性最高的特征
    if 'final_score' in corr_matrix.columns:
        final_score_corr = corr_matrix['final_score'].sort_values(ascending=False)
        
        # 选择与最终成绩相关性最高的15个特征
        top_n = 15
        top_features = final_score_corr[1:top_n+1]  # 排除自身
        
        colors = plt.cm.RdYlBu(np.linspace(0, 1, len(top_features)))
        bars = axes[1].barh(range(len(top_features)), top_features.values, color=colors)
        axes[1].set_yticks(range(len(top_features)))
        axes[1].set_yticklabels(top_features.index)
        axes[1].invert_yaxis()
        axes[1].set_xlabel('相关系数')
        axes[1].set_title(f'与最终成绩相关性最高的{top_n}个特征', fontsize=14, fontweight='bold')
        axes[1].grid(True, alpha=0.3, axis='x')
        
        # 添加数值标签
        for i, (bar, value) in enumerate(zip(bars, top_features.values)):
            axes[1].text(value + 0.01 * (1 if value >= 0 else -1), 
                        bar.get_y() + bar.get_height()/2,
                        f'{value:.3f}', va='center',
                        color='black' if abs(value) < 0.5 else 'white',
                        fontweight='bold')
    
    plt.suptitle('特征相关性分析', fontsize=16, fontweight='bold', y=1.02)
    plt.tight_layout()
    plt.show()
    
    # 打印关键发现
    if 'final_score' in corr_matrix.columns:
        print("\n关键相关性发现:")
        print("="*50)
        
        positive_corr = final_score_corr[final_score_corr > 0.3].index.tolist()
        negative_corr = final_score_corr[final_score_corr < -0.1].index.tolist()
        
        print(f"1. 与最终成绩正相关较强的特征 (>0.3):")
        for feature in positive_corr:
            if feature != 'final_score':
                corr_value = final_score_corr[feature]
                print(f"   • {feature}: {corr_value:.3f}")
        
        print(f"\n2. 与最终成绩负相关的特征 (< -0.1):")
        for feature in negative_corr:
            corr_value = final_score_corr[feature]
            print(f"   • {feature}: {corr_value:.3f}")
    
    return corr_matrix

# 执行相关性分析
corr_matrix = correlation_analysis(df_clean)


量化了各特征与学业表现的关联程度:

  • 相关性热力图:直观展示了特征间的关联模式,避免了多重共线性风险;
  • 核心关联特征:概念理解分数、课堂参与度、出勤率与最终成绩正相关性最强;
  • 负相关特征:社交媒体使用时间、AI 生成内容占比与成绩呈弱负相关;
  • AI 相关特征:AI 伦理分数与成绩正相关,而 AI 依赖度与成绩相关性较弱。

4. 特征工程

4.1 特征创建与转换

def feature_engineering(df):
    """特征工程"""
    
    df_engineered = df.copy()
    
    print("特征工程开始...")
    print("="*50)
    
    # 1. 创建交互特征
    print("1. 创建交互特征:")
    
    # AI使用强度 = AI依赖度 * AI使用时间
    if all(col in df_engineered.columns for col in ['ai_dependency_score', 'ai_usage_time_minutes']):
        df_engineered['ai_usage_intensity'] = (
            df_engineered['ai_dependency_score'] * 
            df_engineered['ai_usage_time_minutes'] / 60  # 转换为小时
        )
        print("   • 创建: ai_usage_intensity")
    
    # 学习效率 = 概念理解分数 / 学习时间
    if all(col in df_engineered.columns for col in ['concept_understanding_score', 'study_hours_per_day']):
        df_engineered['learning_efficiency'] = (
            df_engineered['concept_understanding_score'] / 
            (df_engineered['study_hours_per_day'] + 0.1)  # 避免除零
        )
        print("   • 创建: learning_efficiency")
    
    # 平衡得分 = 学习时间 - 社交媒体时间
    if all(col in df_engineered.columns for col in ['study_hours_per_day', 'social_media_hours']):
        df_engineered['study_social_balance'] = (
            df_engineered['study_hours_per_day'] - 
            df_engineered['social_media_hours']
        )
        print("   • 创建: study_social_balance")
    
    # 2. 创建分组特征
    print("\n2. 创建分组特征:")
    
    # AI依赖度分组
    df_engineered['ai_dependency_group'] = pd.cut(
        df_engineered['ai_dependency_score'],
        bins=[-1, 3, 7, 11],
        labels=['低依赖', '中依赖', '高依赖']
    )
    print("   • 创建: ai_dependency_group")
    
    # 成绩分组(更细粒度)
    if 'final_score' in df_engineered.columns:
        df_engineered['score_quartile'] = pd.qcut(
            df_engineered['final_score'],
            q=4,
            labels=['Q1 (低)', 'Q2 (中下)', 'Q3 (中上)', 'Q4 (高)']
        )
        print("   • 创建: score_quartile")
    
    # 3. 多项式特征(二次项)
    print("\n3. 创建多项式特征:")
    
    poly_features = ['study_hours_per_day', 'ai_dependency_score', 'ai_ethics_score']
    for feature in poly_features:
        if feature in df_engineered.columns:
            df_engineered[f'{feature}_squared'] = df_engineered[feature] ** 2
            print(f"   • 创建: {feature}_squared")
    
    # 4. 创建比率特征
    print("\n4. 创建比率特征:")
    
    # AI内容生成比例与伦理分数的比率
    if all(col in df_engineered.columns for col in ['ai_generated_content_percentage', 'ai_ethics_score']):
        df_engineered['ai_content_ethics_ratio'] = (
            df_engineered['ai_generated_content_percentage'] / 
            (df_engineered['ai_ethics_score'] + 1)  # 避免除零
        )
        print("   • 创建: ai_content_ethics_ratio")
    
    # 5. 时间特征组合
    print("\n5. 创建时间组合特征:")
    
    time_features = ['study_hours_per_day', 'sleep_hours', 'social_media_hours']
    if all(col in df_engineered.columns for col in time_features):
        df_engineered['total_daily_hours'] = df_engineered[time_features].sum(axis=1)
        df_engineered['productive_time_ratio'] = (
            df_engineered['study_hours_per_day'] / 
            (df_engineered['total_daily_hours'] + 0.1)
        )
        print("   • 创建: total_daily_hours, productive_time_ratio")
    
    print("\n" + "="*50)
    print(f"特征工程完成!")
    print(f"原始特征数: {len(df.columns)}")
    print(f"新特征数: {len(df_engineered.columns)}")
    print(f"新增特征数: {len(df_engineered.columns) - len(df.columns)}")
    
    return df_engineered

# 执行特征工程
df_engineered = feature_engineering(df_clean)

# 显示新增特征
new_features = [col for col in df_engineered.columns if col not in df_clean.columns]
print(f"\n新增特征列表 ({len(new_features)}个):")
for i, feat in enumerate(new_features, 1):
    print(f"{i:2d}. {feat}")


为提升模型效果,构建了 12 个衍生特征:

  • 交互特征:创建 AI 使用强度(依赖度 × 使用时间)、学习效率(概念理解 / 学习时间)、学习社交平衡(学习时间 - 社交媒体时间)等核心交互特征;
  • 分组特征:将 AI 依赖度划分为低 / 中 / 高三个等级,将成绩分为四个分位数区间;
  • 多项式特征:为学习时间、AI 依赖度、伦理分数创建平方项,捕捉非线性关系;
  • 比率特征:构建 AI 内容 - 伦理比率、有效时间占比等比率特征;
  • 时间组合特征:整合各类时间特征,量化学生每日时间分配的合理性。

4.2 新特征效果可视化

# 新特征效果可视化
def new_features_visualization(df):
    """新创建特征效果可视化分析"""
    fig, axes = plt.subplots(2, 2, figsize=(18, 14))
    fig.suptitle('新创建特征效果分析', fontsize=18, fontweight='bold', y=0.98)
    
    # 1. AI使用强度分布
    ax1 = axes[0, 0]
    if 'ai_usage_intensity' in df.columns:
        sns.histplot(df['ai_usage_intensity'], bins=30, kde=True, ax=ax1, color='#FF6B6B')
        ax1.set_title('AI使用强度分布', fontsize=14)
        ax1.set_xlabel('AI使用强度 (依赖度 × 使用时间)')
        ax1.set_ylabel('学生数量')
        ax1.grid(True, alpha=0.3)
    
    # 2. 学习效率与成绩关系
    ax2 = axes[0, 1]
    if 'learning_efficiency' in df.columns:
        ax2.scatter(df['learning_efficiency'], df['final_score'], alpha=0.6, c='#4ECDC4', s=50)
        ax2.set_title('学习效率与最终成绩关系', fontsize=14)
        ax2.set_xlabel('学习效率 (概念理解/学习时间)')
        ax2.set_ylabel('最终成绩')
        ax2.grid(True, alpha=0.3)
        
        # 添加趋势线
        z = np.polyfit(df['learning_efficiency'], df['final_score'], 1)
        p = np.poly1d(z)
        ax2.plot(sorted(df['learning_efficiency']), 
                 p(sorted(df['learning_efficiency'])), 
                 "red", alpha=0.8, linewidth=2)
    
    # 3. AI依赖度分组与成绩
    ax3 = axes[1, 0]
    if 'ai_dependency_group' in df.columns:
        dependency_score = df.groupby('ai_dependency_group')['final_score'].agg(['mean', 'std'])
        x = range(len(dependency_score))
        
        bars = ax3.bar(x, dependency_score['mean'], yerr=dependency_score['std'],
                       capsize=5, color=['#4ECDC4', '#FFA726', '#FF6B6B'])
        ax3.set_title('不同AI依赖度分组的平均成绩', fontsize=14)
        ax3.set_xlabel('AI依赖度分组')
        ax3.set_ylabel('平均最终成绩')
        ax3.set_xticks(x)
        ax3.set_xticklabels(dependency_score.index)
        
        for bar in bars:
            height = bar.get_height()
            ax3.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                    f'{height:.1f}', ha='center', va='bottom', fontweight='bold')
    
    # 4. 学习社交平衡与成绩
    ax4 = axes[1, 1]
    if 'study_social_balance' in df.columns:
        # 分组
        balance_bins = [-np.inf, -2, 0, 2, 4, np.inf]
        balance_labels = ['<-2', '-2~0', '0~2', '2~4', '>4']
        df['balance_bin'] = pd.cut(df['study_social_balance'], bins=balance_bins, labels=balance_labels)
        balance_score = df.groupby('balance_bin')['final_score'].mean()
        
        bars = ax4.bar(balance_score.index, balance_score.values, 
                       color=plt.cm.coolwarm(np.linspace(0, 1, len(balance_score))))
        ax4.set_title('学习-社交平衡与平均成绩', fontsize=14)
        ax4.set_xlabel('学习时间 - 社交媒体时间 (小时)')
        ax4.set_ylabel('平均最终成绩')
        
        for bar in bars:
            height = bar.get_height()
            ax4.text(bar.get_x() + bar.get_width()/2., height + 0.5,
                    f'{height:.1f}', ha='center', va='bottom', fontweight='bold')
    
    plt.tight_layout()
    plt.subplots_adjust(top=0.93)
    plt.show()

# 执行新特征可视化
new_features_visualization(df_engineered)


验证了衍生特征的有效性:

  • AI 使用强度:分布呈右偏,多数学生 AI 使用强度适中;
  • 学习效率:与最终成绩呈强正相关,是学业表现的核心预测指标;
  • AI 依赖度分组:中等依赖度组平均成绩显著高于低 / 高依赖组;
  • 学习社交平衡:平衡值为正且适中的学生成绩最优,过度学习或过度社交均不利。

4.2 特征编码与标准化

def prepare_features_for_modeling(df):
    """为建模准备特征"""
    
    print("特征准备开始...")
    print("="*50)
    
    # 1. 选择特征和标签
    # 排除不需要的列
    exclude_cols = ['student_id', 'passed', 'performance_category', 
                   'ai_tools_used', 'ai_usage_purpose']
    
    # 识别特征类型
    categorical_cols = df.select_dtypes(include=['object', 'category']).columns
    categorical_cols = [col for col in categorical_cols if col not in exclude_cols]
    
    numeric_cols = df.select_dtypes(include=['int64', 'float64']).columns
    numeric_cols = [col for col in numeric_cols if col not in exclude_cols + ['passed']]
    
    print(f"分类特征: {len(categorical_cols)} 个")
    print(f"数值特征: {len(numeric_cols)} 个")
    
    # 2. 准备特征矩阵
    X = df[numeric_cols].copy()
    
    # 添加编码后的分类特征
    if len(categorical_cols) > 0:
        from sklearn.preprocessing import LabelEncoder
        
        for col in categorical_cols:
            le = LabelEncoder()
            X[col] = le.fit_transform(df[col].astype(str))
    
    # 3. 处理缺失值
    missing_values = X.isnull().sum().sum()
    if missing_values > 0:
        print(f"发现 {missing_values} 个缺失值,使用中位数填充...")
        X = X.fillna(X.median())
    
    # 4. 目标变量
    y = df['passed']
    
    print(f"\n最终特征矩阵形状: {X.shape}")
    print(f"目标变量形状: {y.shape}")
    print(f"正例比例: {y.mean():.2%} (通过)")
    print(f"负例比例: {(1 - y.mean()):.2%} (未通过)")
    
    return X, y, numeric_cols, categorical_cols

# 准备特征
X, y, numeric_cols, categorical_cols = prepare_features_for_modeling(df_engineered)


为建模完成了特征预处理:

  • 特征筛选:排除学生 ID、标签列等非预测特征,保留其余有效特征;
  • 分类特征编码:对性别、年级等分类特征进行标签编码,转换为数值形式;
  • 缺失值填充:使用中位数填充少量缺失值,保证数据完整性;
  • 数据分割:按 7:3 比例划分训练集(5600 条)和测试集(2400 条),并进行分层抽样确保标签分布一致;
  • 标准化处理:对数值特征进行标准化,消除量纲影响,提升模型收敛速度。

5. 模型构建与训练

5.1 数据分割与预处理

from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import (accuracy_score, precision_score, recall_score, 
                           f1_score, roc_auc_score, confusion_matrix, 
                           classification_report)
import time

def split_and_scale_data(X, y, test_size=0.3, random_state=42):
    """分割数据并进行标准化"""
    
    print("数据分割与标准化...")
    print("="*50)
    
    # 分割数据
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=test_size, random_state=random_state, stratify=y
    )
    
    print(f"训练集大小: {X_train.shape[0]:,} 样本")
    print(f"测试集大小: {X_test.shape[0]:,} 样本")
    print(f"特征数量: {X_train.shape[1]}")
    
    # 标准化特征
    scaler = StandardScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_test_scaled = scaler.transform(X_test)
    
    print(f"\n标准化完成!")
    print(f"训练集均值: {X_train_scaled.mean():.4f}")
    print(f"训练集标准差: {X_train_scaled.std():.4f}")
    
    return X_train_scaled, X_test_scaled, y_train, y_test, scaler

# 分割和标准化数据
X_train_scaled, X_test_scaled, y_train, y_test, scaler = split_and_scale_data(X, y)

5.2 随机森林模型训练

def train_random_forest(X_train, y_train, X_test, y_test):
    """训练随机森林分类器"""
    
    print("训练随机森林模型...")
    print("="*50)
    
    start_time = time.time()
    
    # 初始化模型
    rf_model = RandomForestClassifier(
        n_estimators=200,
        max_depth=15,
        min_samples_split=5,
        min_samples_leaf=2,
        max_features='sqrt',
        bootstrap=True,
        random_state=42,
        n_jobs=-1,
        class_weight='balanced'
    )
    
    # 训练模型
    rf_model.fit(X_train, y_train)
    
    training_time = time.time() - start_time
    print(f"模型训练完成,耗时: {training_time:.2f} 秒")
    
    # 预测
    y_train_pred = rf_model.predict(X_train)
    y_test_pred = rf_model.predict(X_test)
    y_test_prob = rf_model.predict_proba(X_test)[:, 1]
    
    return rf_model, y_train_pred, y_test_pred, y_test_prob

# 训练模型
rf_model, y_train_pred, y_test_pred, y_test_prob = train_random_forest(
    X_train_scaled, y_train, X_test_scaled, y_test
)


选择随机森林作为核心预测模型,原因在于其能有效处理非线性关系、抗过拟合能力强且能输出特征重要性:

  • 模型参数:设置 200 棵决策树,最大深度 15,最小分割样本数 5,采用平衡类别权重处理潜在的类别不平衡;
  • 训练效率:模型训练耗时约0.38秒,在普通硬件上即可快速完成;
  • 预测输出:不仅输出分类结果,还输出预测概率,为后续深度分析提供基础。

6. 模型评估与结果分析

6.1 综合性能评估

def evaluate_model_performance(y_true, y_pred, y_prob=None, dataset_name="测试集"):
    """评估模型性能"""
    
    print(f"\n{dataset_name} 性能评估")
    print("="*60)
    
    # 计算各项指标
    accuracy = accuracy_score(y_true, y_pred)
    precision = precision_score(y_true, y_pred)
    recall = recall_score(y_true, y_pred)
    f1 = f1_score(y_true, y_pred)
    
    metrics = {
        '准确率': accuracy,
        '精确率': precision,
        '召回率': recall,
        'F1分数': f1
    }
    
    if y_prob is not None:
        roc_auc = roc_auc_score(y_true, y_prob)
        metrics['ROC AUC'] = roc_auc
    
    # 打印指标
    for metric_name, metric_value in metrics.items():
        print(f"{metric_name:10s}: {metric_value:.4f}")
    
    # 分类报告
    print("\n分类报告:")
    print(classification_report(y_true, y_pred, target_names=['未通过', '通过']))
    
    return metrics

# 评估训练集和测试集
print("模型性能评估")
print("="*60)

train_metrics = evaluate_model_performance(y_train, y_train_pred, dataset_name="训练集")
test_metrics = evaluate_model_performance(y_test, y_test_pred, y_test_prob, dataset_name="测试集")

6.2 可视化评估结果

def visualize_model_performance(y_test, y_pred, y_prob, rf_model, X_train):
    """可视化模型性能"""
    
    fig, axes = plt.subplots(2, 3, figsize=(18, 12))
    fig.suptitle('模型性能综合评估', fontsize=16, fontweight='bold', y=1.02)
    
    # 1. 混淆矩阵
    cm = confusion_matrix(y_test, y_pred)
    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', 
                xticklabels=['未通过', '通过'], 
                yticklabels=['未通过', '通过'], ax=axes[0, 0])
    axes[0, 0].set_title('混淆矩阵')
    axes[0, 0].set_xlabel('预测标签')
    axes[0, 0].set_ylabel('真实标签')
    
    # 2. 特征重要性
    importances = rf_model.feature_importances_
    indices = np.argsort(importances)[-15:]  # 取最重要的15个特征
    
    # 获取特征名称
    feature_names = X.columns if hasattr(X, 'columns') else [f'Feature_{i}' for i in range(len(importances))]
    
    axes[0, 1].barh(range(len(indices)), importances[indices], color='#4ECDC4')
    axes[0, 1].set_yticks(range(len(indices)))
    axes[0, 1].set_yticklabels([feature_names[i] for i in indices])
    axes[0, 1].set_xlabel('特征重要性')
    axes[0, 1].set_title('Top 15 特征重要性')
    axes[0, 1].grid(True, alpha=0.3, axis='x')
    
    # 3. ROC曲线
    from sklearn.metrics import roc_curve
    fpr, tpr, _ = roc_curve(y_test, y_prob)
    auc_score = roc_auc_score(y_test, y_prob)
    
    axes[0, 2].plot(fpr, tpr, color='#FF6B6B', lw=2, 
                   label=f'ROC曲线 (AUC = {auc_score:.3f})')
    axes[0, 2].plot([0, 1], [0, 1], color='gray', lw=1, linestyle='--')
    axes[0, 2].set_xlabel('假正率')
    axes[0, 2].set_ylabel('真正率')
    axes[0, 2].set_title('ROC曲线')
    axes[0, 2].legend(loc='lower right')
    axes[0, 2].grid(True, alpha=0.3)
    
    # 4. 预测概率分布
    axes[1, 0].hist(y_prob[y_test == 0], bins=30, alpha=0.5, 
                   label='未通过', color='#FF6B6B', density=True)
    axes[1, 0].hist(y_prob[y_test == 1], bins=30, alpha=0.5, 
                   label='通过', color='#4ECDC4', density=True)
    axes[1, 0].axvline(0.5, color='black', linestyle='--', linewidth=2)
    axes[1, 0].set_xlabel('预测概率')
    axes[1, 0].set_ylabel('密度')
    axes[1, 0].set_title('预测概率分布')
    axes[1, 0].legend()
    axes[1, 0].grid(True, alpha=0.3)
    
    # 5. 性能指标对比
    metrics_names = ['准确率', '精确率', '召回率', 'F1分数']
    train_values = [train_metrics.get(m, 0) for m in metrics_names]
    test_values = [test_metrics.get(m, 0) for m in metrics_names]
    
    x = np.arange(len(metrics_names))
    width = 0.35
    
    axes[1, 1].bar(x - width/2, train_values, width, label='训练集', color='#45B7D1')
    axes[1, 1].bar(x + width/2, test_values, width, label='测试集', color='#FFA726')
    axes[1, 1].set_xlabel('评估指标')
    axes[1, 1].set_ylabel('分数')
    axes[1, 1].set_title('训练集 vs 测试集性能对比')
    axes[1, 1].set_xticks(x)
    axes[1, 1].set_xticklabels(metrics_names)
    axes[1, 1].legend()
    axes[1, 1].grid(True, alpha=0.3, axis='y')
    
    # 添加数值标签
    for i, (train_val, test_val) in enumerate(zip(train_values, test_values)):
        axes[1, 1].text(i - width/2, train_val + 0.01, f'{train_val:.3f}', 
                       ha='center', va='bottom', fontsize=9)
        axes[1, 1].text(i + width/2, test_val + 0.01, f'{test_val:.3f}', 
                       ha='center', va='bottom', fontsize=9)
    
    # 6. 学习曲线(简化版)
    from sklearn.model_selection import learning_curve
    
    train_sizes, train_scores, test_scores = learning_curve(
        rf_model, X_train_scaled, y_train, cv=5, 
        n_jobs=-1, train_sizes=np.linspace(0.1, 1.0, 10)
    )
    
    train_scores_mean = np.mean(train_scores, axis=1)
    test_scores_mean = np.mean(test_scores, axis=1)
    
    axes[1, 2].plot(train_sizes, train_scores_mean, 'o-', color='#45B7D1', 
                   label='训练集分数')
    axes[1, 2].plot(train_sizes, test_scores_mean, 'o-', color='#FFA726', 
                   label='交叉验证分数')
    axes[1, 2].fill_between(train_sizes, train_scores_mean - np.std(train_scores, axis=1),
                           train_scores_mean + np.std(train_scores, axis=1), alpha=0.1, color='#45B7D1')
    axes[1, 2].fill_between(train_sizes, test_scores_mean - np.std(test_scores, axis=1),
                           test_scores_mean + np.std(test_scores, axis=1), alpha=0.1, color='#FFA726')
    axes[1, 2].set_xlabel('训练样本数')
    axes[1, 2].set_ylabel('准确率')
    axes[1, 2].set_title('学习曲线')
    axes[1, 2].legend(loc='best')
    axes[1, 2].grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.show()

# 可视化性能评估
visualize_model_performance(y_test, y_test_pred, y_test_prob, rf_model, X_train_scaled)

7. 关键发现与业务洞察

7.1 主要发现总结

def summarize_key_findings(df, test_metrics, rf_model, X):
    """总结关键发现"""
    
    print("="*70)
    print("关键发现与业务洞察总结")
    print("="*70)
    
    # 1. AI使用影响
    print("\n1. AI使用对学生成绩的影响:")
    print("-"*40)
    
    # AI用户 vs 非AI用户成绩对比
    ai_users_mean = df[df['uses_ai'] == 1]['final_score'].mean()
    non_ai_users_mean = df[df['uses_ai'] == 0]['final_score'].mean()
    print(f"   • AI用户平均成绩: {ai_users_mean:.1f}")
    print(f"   • 非AI用户平均成绩: {non_ai_users_mean:.1f}")
    print(f"   • 差异: {ai_users_mean - non_ai_users_mean:+.1f} 分")
    
    # AI依赖度与成绩关系
    correlation = df['ai_dependency_score'].corr(df['final_score'])
    print(f"   • AI依赖度与成绩相关性: {correlation:.3f}")
    
    # 2. 模型表现
    print("\n2. 预测模型表现:")
    print("-"*40)
    print(f"   • 测试集准确率: {test_metrics.get('准确率', 0):.2%}")
    print(f"   • 模型区分度 (AUC): {test_metrics.get('ROC AUC', 0):.3f}")
    
    # 3. 重要特征
    print("\n3. 影响学业表现的关键因素:")
    print("-"*40)
    
    if hasattr(rf_model, 'feature_importances_'):
        importances = rf_model.feature_importances_
        indices = np.argsort(importances)[::-1]
        
        # 获取特征名称
        feature_names = X.columns if hasattr(X, 'columns') else [f'Feature_{i}' for i in range(len(importances))]
        
        print("   最重要的5个特征:")
        for i in range(min(5, len(indices))):
            feature_name = feature_names[indices[i]]
            importance = importances[indices[i]]
            
            # 解读特征
            interpretation = ""
            if 'concept' in feature_name.lower():
                interpretation = "(概念理解能力)"
            elif 'study' in feature_name.lower():
                interpretation = "(学习时间)"
            elif 'attendance' in feature_name.lower():
                interpretation = "(出勤率)"
            elif 'ai' in feature_name.lower():
                interpretation = "(AI使用相关)"
            
            print(f"   {i+1}. {feature_name:25s} {importance:.4f} {interpretation}")
    
    # 4. 业务建议
    print("\n4. 教育实践建议:")
    print("-"*40)
    print("   • 适度使用AI工具可以提升学习效率,但过度依赖可能影响概念理解")
    print("   • 保持良好学习习惯(规律学习、充足睡眠)对学业成功至关重要")
    print("   • AI伦理教育应纳入课程,确保学生正确使用AI工具")
    print("   • 个性化学习方案应考虑学生的AI使用模式和依赖程度")
    
    # 5. 后续研究方向
    print("\n5. 后续研究方向:")
    print("-"*40)
    print("   • 深入研究AI使用模式与不同学科成绩的关系")
    print("   • 探索AI工具类型对学习效果的影响差异")
    print("   • 开展纵向研究,追踪AI使用行为的长期影响")
    print("   • 开发基于AI的个性化学习推荐系统")
    
    print("\n" + "="*70)

# 总结关键发现
summarize_key_findings(df_clean, test_metrics, rf_model, X)


本次研究的核心结论:

  • AI 使用的双重效应:AI 工具并非简单提升 / 降低成绩,中等 AI 依赖度学生成绩最高;
  • 核心决定因素不变:概念理解能力、课堂出勤率、学习效率是学业表现的 TOP3 关键因素,AI 使用仅为辅助变量;
  • 学习习惯的重要性:5-6 小时睡眠、适度学习时间、低社交媒体沉迷、高课堂参与度构成优秀学业表现的习惯基础;
  • AI 伦理的价值:AI 伦理认知与学业表现正相关,理性的 AI 使用认知能帮助学生更好利用 AI 工具。

结论

本研究表明,AI工具在学生学习中的应用具有双重效应:适度使用可以提升学习效率,但过度依赖可能导致概念理解能力下降。通过构建随机森林分类器,我们实现了对学生是否通过考试的高精度预测,并识别出概念理解分数、学习时间和出勤率等关键影响因素。

核心建议:

  1. 教育政策:应将AI伦理教育纳入课程体系
  2. 教学实践:鼓励学生合理使用AI工具,避免过度依赖
  3. 技术应用:开发智能学习分析系统,实现个性化学习指导
  4. 未来研究:开展纵向追踪研究,深入理解AI使用的长期影响

  注: 博主目前收集了6900+份相关数据集,有想要的可以领取部分数据,关注下方公众号或添加微信:

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐