1. 项目目标

本项目基于学校多源业务数据,完成学生单次考试成绩预测。不以学生平均分为预测对象,而是以成绩表中的 每一条考试记录 为一个样本,预测该学生在某次考试、某门学科中的真实成绩 mes_Score

将对比三类回归模型:

  • 线性回归 LinearRegression
  • 决策树回归 DecisionTreeRegressor
  • XGBoost 回归 XGBRegressor

训练结束后为每个模型保存 **.joblib(内含预处理 + 回归器),并自动选择 测试集 RMSE 最低 的模型为 **best_score_model.joblib。

2.数据说明

2.1 七张原始业务表(data/

文件名 说明
1_teacher.csv 近五年各班各学科教师信息
2_student_info.csv 当前在校学生基础信息
3_kaoqin.csv 学生考勤记录
4_kaoqintype.csv 考勤类型字典
5_chengji.csv 学生成绩记录
6_exam_type.csv 考试类型字典
7_consumption.csv 学生消费记录

核心标签来自成绩表字段 mes_Score

2.2 异常成绩编码(业务含义)

含义 处理方式
-1 作弊 过滤(mes_Score >= 0 以外剔除)
-2 缺考 同上
-3 免考 同上

训练时 仅保留 mes_Score >= 0 的有效分数记录。

2.3 读取优先级

程序 优先 读取:

outputs/cleaned/

中的清洗后 CSV;若该目录为空,则读取 data/ 原始文件。

3. 项目目录结构

项目根目录/
├── data/                          # 原始 CSV
├── outputs/
│   ├── cleaned/                   # clean.py 产出
│   └── score_prediction_no_avg/
│       ├── model_dataset.csv      # 全量建模宽表(特征 + target_mes_Score)
│       ├── model_metrics.csv      # 各模型 train/test 指标
│       ├── best_model_predictions.csv
│       ├── model_predictions/     # 各模型测试集预测明细
│       ├── feature_importance/
│       ├── cross_validation/
│       └── figures/
│           ├── global_compare/    # 多模型对比图
│           └── each_model_8plots/ # 各模型单独 8 类图
├── models/
│   ├── LinearRegression_score_model.joblib
│   ├── DecisionTree_score_model.joblib
│   ├── XGBoost_score_model.joblib
│   └── best_score_model.joblib
├── train.py                       # 实际训练与预测入口
└── clean.py                       # 生成 outputs/cleaned/

4. 环境依赖

建议 Python 3.8+。

pip install pandas numpy scikit-learn xgboost joblib matplotlib

5. 工作流程

读取多张 CSV(优先 cleaned)
        ↓
统一字段名和学生 ID(bf_StudentID)
        ↓
过滤异常成绩(mes_Score >= 0)
        ↓
成绩表衍生考试年/月/日/星期
        ↓
按学生聚合考勤特征 → left merge
        ↓
按学生聚合消费特征 → left merge
        ↓
合并学生基础信息
        ↓
合并考试类型维表
        ↓
教师表去重后合并(班级+学科)
        ↓
构造特征矩阵 X,标签 y;剔除泄漏列、姓名、时间戳、ID、常数列
        ↓
保存 model_dataset.csv(可选)
        ↓
train_test_split(test_size=0.2, random_state=42)
        ↓
数值:中位数填补 + 标准化;类别:众数填补 + One-Hot
        ↓
训练 LinearRegression / DecisionTree / XGBoost(Pipeline)
        ↓
评估 MAE、RMSE、R²;保存 joblib 与预测 CSV
        ↓
交叉验证(可选)+ 导出 figures/

6. 特征工程说明

6.1 学生基础信息特征

来自学生信息表,例如:性别、民族、出生年份、班级名、住址、政治面貌、宿舍等(以实际列为准)。年龄:

student_age = 2026 - bf_BornDate

6.2 考勤特征(按 bf_StudentID 聚合)

特征 含义
attendance_event_count 考勤事件总数
late_count 迟到次数
early_leave_count 早退或离校次数
uniform_problem_count 校服相关问题次数
avg_attendance_hour 平均考勤小时
active_attendance_months 有考勤记录的月份数
active_attendance_weekdays 有考勤记录的星期数

规则:controler_name 含「迟到」→ 迟到;含「早退」或「离校」→ 早退/离校;含「校服」→ 校服问题。

6.3 消费特征(按 bf_StudentID 聚合)

特征 含义
total_spend 总消费金额
avg_spend 平均单笔
max_spend / min_spend 最大/最小单笔
std_spend 标准差(单值组填 0)
consumption_count 消费笔数
active_consume_months 有消费的月份数
avg_consume_hour 平均消费小时

金额:MonDeal 为负时取 **abs(MonDeal)** 作为支出(或直接使用 spend_amount)。

6.4 考试信息特征

来自成绩表及考试类型表,例如:exam_numnameexam_termexam_typeEXAM_KIND_NAMEexam_yearexam_monthexam_dayexam_dayofweekmes_sub_name 等。

6.5 教师信息特征

合并键:班级名 cla_Name + 学科名 mes_sub_name(与教师表 cla_Name + sub_Name 对齐)。
必须先按 cla_Name + sub_Name 去重,避免一对多合并导致样本行数膨胀。


7. 数据泄漏处理

训练前从特征中移除:

mes_Score, mes_Z_Score, mes_T_Score, mes_dengdi

并移除姓名、原始日期时间、各类业务 ID 等。

8. 核心实现代码

以下代码均来自项目根目录 `train.py

8.1 读取数据:load_tables

def load_tables():
    tables = {}
    cleaned_files = {
        "teacher": ["clean_teacher.csv"],
        "student": ["clean_student_info.csv", "clean_student_profile.csv", "student_profile.csv"],
        "attendance": ["clean_attendance.csv"],
        "attendance_type": ["clean_attendance_type.csv"],
        "score": ["clean_score.csv"],
        "exam_type": ["clean_exam_type.csv"],
        "consumption": ["clean_consumption.csv"],
    }
    raw_files = {
        "teacher": ["1_teacher.csv"],
        "student": ["2_student_info.csv", "2_studentinfo.csv"],
        "attendance": ["3_kaoqin.csv"],
        "attendance_type": ["4_kaoqintype.csv"],
        "score": ["5_chengji.csv"],
        "exam_type": ["6_exam_type.csv"],
        "consumption": ["7_consumption.csv"],
    }
    use_cleaned = os.path.exists(CLEANED_DIR) and len(os.listdir(CLEANED_DIR)) > 0
    if use_cleaned:
        for key, candidates in cleaned_files.items():
            path = find_existing_file(CLEANED_DIR, candidates)
            if path is None:
                tables[key] = None
                continue
            df = read_csv_smart(path)
            df = clean_column_names(df)
            df = normalize_student_id(df)
            tables[key] = df
    else:
        for key, candidates in raw_files.items():
            path = find_existing_file(DATA_DIR, candidates)
            if path is None:
                tables[key] = None
                continue
            if key == "attendance_type":
                try:
                    df = read_csv_smart(path, sep="\t")
                except Exception:
                    df = read_csv_smart(path, sep=",")
            else:
                df = read_csv_smart(path)
            df = clean_column_names(df)
            df = normalize_student_id(df)
            tables[key] = df
    return tables

8.2 考勤聚合:build_attendance_features

def build_attendance_features(attendance):
    if attendance is None or attendance.empty:
        return pd.DataFrame({"bf_StudentID": []})
    df = attendance.copy()
    df = clean_column_names(df)
    df = normalize_student_id(df)
    if "bf_StudentID" not in df.columns:
        return pd.DataFrame({"bf_StudentID": []})
    if "DataDateTime" in df.columns:
        df["DataDateTime"] = safe_to_datetime(df["DataDateTime"])
        df["attendance_hour"] = df["DataDateTime"].dt.hour
        df["attendance_month"] = df["DataDateTime"].dt.month
        df["attendance_dayofweek"] = df["DataDateTime"].dt.dayofweek
    else:
        df["attendance_hour"] = np.nan
        df["attendance_month"] = np.nan
        df["attendance_dayofweek"] = np.nan
    if "controler_name" not in df.columns:
        df["controler_name"] = ""
    df["controler_name"] = df["controler_name"].astype(str)
    df["is_late"] = df["controler_name"].str.contains("迟到", na=False).astype(int)
    df["is_early_leave"] = (
        df["controler_name"].str.contains("早退", na=False) |
        df["controler_name"].str.contains("离校", na=False)
    ).astype(int)
    df["is_uniform_problem"] = df["controler_name"].str.contains("校服", na=False).astype(int)
    agg = df.groupby("bf_StudentID").agg(
        attendance_event_count=("bf_StudentID", "count"),
        late_count=("is_late", "sum"),
        early_leave_count=("is_early_leave", "sum"),
        uniform_problem_count=("is_uniform_problem", "sum"),
        avg_attendance_hour=("attendance_hour", "mean"),
        active_attendance_months=("attendance_month", "nunique"),
        active_attendance_weekdays=("attendance_dayofweek", "nunique"),
    ).reset_index()
    return agg

8.3 消费聚合:build_consumption_features

def build_consumption_features(consumption):
    if consumption is None or consumption.empty:
        return pd.DataFrame({"bf_StudentID": []})
    df = consumption.copy()
    df = clean_column_names(df)
    df = normalize_student_id(df)
    if "bf_StudentID" not in df.columns:
        return pd.DataFrame({"bf_StudentID": []})
    if "DealTime" in df.columns:
        df["DealTime"] = safe_to_datetime(df["DealTime"])
        df["consume_month"] = df["DealTime"].dt.month
        df["consume_hour"] = df["DealTime"].dt.hour
    else:
        df["consume_month"] = np.nan
        df["consume_hour"] = np.nan
    if "spend_amount" in df.columns:
        df["spend_amount"] = safe_to_numeric(df["spend_amount"])
    elif "MonDeal" in df.columns:
        df["MonDeal"] = safe_to_numeric(df["MonDeal"])
        df["spend_amount"] = df["MonDeal"].apply(
            lambda x: abs(x) if pd.notna(x) and x < 0 else x
        )
    else:
        df["spend_amount"] = np.nan
    agg = df.groupby("bf_StudentID").agg(
        total_spend=("spend_amount", "sum"),
        avg_spend=("spend_amount", "mean"),
        max_spend=("spend_amount", "max"),
        min_spend=("spend_amount", "min"),
        std_spend=("spend_amount", "std"),
        consumption_count=("spend_amount", "count"),
        active_consume_months=("consume_month", "nunique"),
        avg_consume_hour=("consume_hour", "mean"),
    ).reset_index()
    agg["std_spend"] = agg["std_spend"].fillna(0)
    return agg

8.4 教师表去重:prepare_teacher_table

def prepare_teacher_table(teacher):
    """教师表去重,避免 班级+学科 一对多合并导致样本数量膨胀。"""
    if teacher is None or teacher.empty:
        return None
    df = teacher.copy()
    df = clean_column_names(df)
    keep_cols = []
    for col in ["term", "cla_id", "cla_Name", "gra_Name", "sub_id", "sub_Name", "bas_id", "bas_Name"]:
        if col in df.columns:
            keep_cols.append(col)
    if len(keep_cols) == 0:
        return None
    df = df[keep_cols].drop_duplicates()
    if "cla_Name" in df.columns and "sub_Name" in df.columns:
        sort_cols = [c for c in ["term", "cla_Name", "sub_Name"] if c in df.columns]
        if len(sort_cols) > 0:
            df = df.sort_values(by=sort_cols)
        df = df.drop_duplicates(subset=["cla_Name", "sub_Name"], keep="last")
    return df

8.5 宽表构建与删列(节选):build_model_dataset

    score["mes_Score"] = safe_to_numeric(score["mes_Score"])
    score = score[score["mes_Score"] >= 0].copy()

    if "exam_sdate" in score.columns:
        score["exam_sdate"] = safe_to_datetime(score["exam_sdate"])
        score["exam_year"] = score["exam_sdate"].dt.year
        score["exam_month"] = score["exam_sdate"].dt.month
        score["exam_day"] = score["exam_sdate"].dt.day
        score["exam_dayofweek"] = score["exam_sdate"].dt.dayofweek

    data = score.copy()
    # merge student, attendance_features, consumption_features, exam_type, teacher_prepared ...
    y = data["mes_Score"].copy()

    leak_cols = ["mes_Score", "mes_Z_Score", "mes_T_Score", "mes_dengdi"]
    name_cols = ["bf_Name", "bf_Name_stu", "AccName", "bas_Name"]
    raw_time_cols = ["exam_sdate", "DataDateTime", "DealTime"]
    id_cols = [
        "bf_StudentID", "mes_TestID", "exam_number", "mes_sub_id", "cla_id", "cla_id_teacher",
        "sub_id", "bas_id", "EXAM_KIND_ID", "kaoqin_id", "kaoqing_id", "controler_id",
        "ControllerID", "control_task_order_id", "bf_classid",
    ]
    drop_cols = leak_cols + name_cols + raw_time_cols + id_cols
    X = data.drop(columns=[c for c in drop_cols if c in data.columns], errors="ignore")
    X = X.dropna(axis=1, how="all")
    nunique = X.nunique(dropna=True)
    useless_cols = nunique[nunique <= 1].index.tolist()
    X = X.drop(columns=useless_cols, errors="ignore")

    if save_dataset:
        dataset_save = X.copy()
        dataset_save["target_mes_Score"] = y.values
        dataset_save.to_csv(os.path.join(RESULT_DIR, "model_dataset.csv"), index=False, encoding="utf-8-sig")
    return X, y, data

8.6 预处理与构建模型结构:build_preprocessorbuild_models

def build_preprocessor(X):
    numeric_features = X.select_dtypes(
        include=["int64", "int32", "float64", "float32", "bool"]
    ).columns.tolist()
    categorical_features = [c for c in X.columns if c not in numeric_features]

    numeric_transformer = Pipeline(steps=[
        ("imputer", SimpleImputer(strategy="median")),
        ("scaler", StandardScaler()),
    ])
    categorical_transformer = Pipeline(steps=[
        ("imputer", SimpleImputer(strategy="most_frequent")),
        ("onehot", OneHotEncoder(handle_unknown="ignore")),
    ])
    preprocessor = ColumnTransformer(
        transformers=[
            ("num", numeric_transformer, numeric_features),
            ("cat", categorical_transformer, categorical_features),
        ]
    )
    return preprocessor


def build_models(preprocessor):
    models = {}
    models["LinearRegression"] = Pipeline(steps=[
        ("preprocess", preprocessor),
        ("model", LinearRegression()),
    ])
    models["DecisionTree"] = Pipeline(steps=[
        ("preprocess", preprocessor),
        ("model", DecisionTreeRegressor(
            max_depth=8,
            min_samples_split=20,
            min_samples_leaf=10,
            random_state=42,
        )),
    ])
    from xgboost import XGBRegressor
    models["XGBoost"] = Pipeline(steps=[
        ("preprocess", preprocessor),
        ("model", XGBRegressor(
            n_estimators=300,
            max_depth=5,
            learning_rate=0.05,
            subsample=0.8,
            colsample_bytree=0.8,
            objective="reg:squarederror",
            random_state=42,
            n_jobs=-1,
        )),
    ])
    return models

8.7 划分数据集、训练、指标:train_models / evaluate_regression_model(节选)

def evaluate_regression_model(model_name, model, X_train, X_test, y_train, y_test):
    model.fit(X_train, y_train)
    pred_train = model.predict(X_train)
    pred_test = model.predict(X_test)
    train_mae = mean_absolute_error(y_train, pred_train)
    test_mae = mean_absolute_error(y_test, pred_test)
    train_rmse = mean_squared_error(y_train, pred_train, squared=False)
    test_rmse = mean_squared_error(y_test, pred_test, squared=False)
    train_r2 = r2_score(y_train, pred_train)
    test_r2 = r2_score(y_test, pred_test)
    return {
        "model_name": model_name,
        "train_mae": train_mae, "test_mae": test_mae,
        "train_rmse": train_rmse, "test_rmse": test_rmse,
        "train_r2": train_r2, "test_r2": test_r2,
        "model": model,
        "pred_train": pred_train,
        "pred_test": pred_test,
    }


def train_models(X, y, cv_folds=5, cv_sample=50000):
    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=42,
    )
    preprocessor = build_preprocessor(X)
    models = build_models(preprocessor)
    # 循环 evaluate → joblib.dump → 保存 test 预测 → 选最佳 RMSE → model_metrics.csv → 绘图 ...

8.8 在其他 Python 文件中调用模型

# -*- coding: utf-8 -*-
import joblib
import pandas as pd

model_path = r"models/best_score_model.joblib"
x_path = r"outputs/score_prediction_no_avg/model_dataset.csv"

model = joblib.load(model_path)
df = pd.read_csv(x_path, encoding="utf-8-sig")

if "target_mes_Score" in df.columns:
    X = df.drop(columns=["target_mes_Score"])
else:
    X = df.copy()

pred = model.predict(X)
df["predicted_score"] = pred
df.to_csv(r"outputs/score_prediction_no_avg/call_model_result.csv", index=False, encoding="utf-8-sig")

9. 模型训练与命令

python train.py --mode train

训练过程包含:读表、构造 X/y、划分数据集、三套 Pipeline 训练、计算 MAE/RMSE/R²、保存 models/*.joblib、保存 model_metrics.csv 与测试集预测、导出图表。

10.模型评估指标

MAE: 1n∑∣yi−y^i∣\frac{1}{n}\sum |y_i - \hat{y}_i|n1yiy^i,越小越好。

RMSE: 1n∑(yi−y^i)2\sqrt{\frac{1}{n}\sum (y_i - \hat{y}_i)^2}n1(yiy^i)2 ,对大误差更敏感。

R²: 越接近 1,相对均值基线的改进越大。

11.实验结果

11.1线性回归模型

交叉验证箱线图结果表明,该线性回归模型在不同数据划分下的 MAE、RMSE 与 R² 指标分布集中,均值与中位数基本重合,无明显异常波动,说明模型预测误差稳定、泛化能力良好,整体性能具有较强鲁棒性。
在这里插入图片描述

真实值 - 预测值散点图显示,样本点整体沿理想预测线分布,与 R²=0.751 的结果一致,模型对数据的整体解释力较强;但低分段样本存在一定的系统性高估现象,说明模型对低分数据的拟合能力仍有提升空间。
在这里插入图片描述

11.2 决策树模型

交叉验证箱线图结果表明,该决策树模型在不同数据划分下的 MAE、RMSE 与 R² 指标分布集中,均值与中位数基本重合,无明显异常波动,模型预测误差稳定、泛化能力良好;与线性回归模型相比,其误差指标更低、R² 更高,整体预测性能更优。在这里插入图片描述
真实值 - 预测值散点图显示,样本点整体沿理想预测线分布,与 R²=0.778 的结果一致,模型对数据的整体解释力较强;但受决策树离散输出特性影响,预测值存在明显的阶梯状分布,对连续成绩的精细化拟合能力仍有提升空间。
在这里插入图片描述

11.3 XGBoos模型

交叉验证箱线图结果表明,该 XGBoost 模型在不同数据划分下的 MAE、RMSE 与 R² 指标分布集中,均值与中位数基本重合,无明显异常波动,模型预测误差稳定、泛化能力良好;与线性回归和决策树模型相比,其误差指标最低、R² 最高,整体预测性能最优。
在这里插入图片描述

真实值 - 预测值散点图显示,样本点紧密沿理想预测线分布,与 R²=0.822 的结果一致,模型对数据的整体解释力显著提升;同时低分段样本的系统性高估问题得到明显改善,无明显阶梯状分布,对连续成绩的精细化拟合能力在三个模型中表现最佳。
在这里插入图片描述

11.4 多模型对比

在这里插入图片描述

1. 指标量化分析(基于柱状图)

直接通过数据对比,给出结论。

性能排序: 在 MAE(平均绝对误差)和 RMSE(均方根误差)两项指标上,表现优劣排序一致为:XGBoost > 决策树 > 线性回归。

误差降幅: 重点描述最优模型比基准模型提升了多少。

例如:XGBoost 的 MAE 约为 8.51,相比于线性回归的 10.58,误差降低了约 19.6%。

RMSE 的表现同样证明了 XGBoost 对大误差样本的控制力更强。
在这里插入图片描述

2. 拟合能力与数据特性分析(基于散点图)

通过观察散点图的形态,分析模型对真实成绩的还原度。

线性回归(基准): 散点最为弥散,且在低分段和高分段都有明显的偏离。这说明学生成绩与特征之间并非简单的线性关系,单纯的加权求和无法捕捉复杂的表现规律。

决策树(阶梯效应): 散点呈现明显的横向条纹状(阶梯状)。这是由决策树通过阈值划分导致的离散输出特性引起的。虽然 R²有所提升,但对于连续的成绩预测来说,这种“分段式”预测不够精细。

XGBoost(最优): 散点最紧密地围绕在红色对角线(理想预测线)周围,R²达到了 0.825。它不仅解决了线性回归的欠拟合问题,也通过集成学习克服了单棵决策树的粗糙感,拟合曲线更平滑、更精准。

在这里插入图片描述

11.5 最优模型分析

通过对比分析可知,XGBoost模型为本次实验中性能最优模型。
XGBoost 模型的残差分布散点图显示,大部分样本的残差随机分布在零线附近,无明显的异方差现象,模型整体误差分布稳定。但在低分段成绩预测中,残差呈现明显的负向线性趋势,说明模型对低分样本存在系统性高估;同时高分段样本的残差离散度有所增大,预测稳定性略有下降,后续可通过特征优化或针对性数据处理进一步改善。
在这里插入图片描述
模型残差直方图显示,残差整体呈近似正态分布,峰值集中在 0 附近,说明大部分样本的预测误差较小,整体拟合质量较高;结合残差散点图进一步分析,低分段成绩预测存在明显的系统性高估趋势,而高分段样本的残差离散度有所增大,后续可针对性优化模型对极端样本的拟合能力。
在这里插入图片描述
XGBoost 模型特征重要性条形图如下:
从图里能看到,前 4 个特征的重要性占比远超其他所有特征,加起来超过了0.68,是模型预测成绩的核心依据:
TOP1:EXAM_KIND_NAME_平时(总评用)(重要性≈0.198)
TOP2:EXAM_KIND_NAME_平时1(重要性≈0.181)
TOP3:exam_type_4(重要性≈0.158)
TOP4:exam_type_22(重要性≈0.126)
这直接说明:“平时成绩 / 过程性评价” 和 “特定考试类型”,是模型判断学生成绩最关键的信息,远超过单次大型考试(如模拟考、联考)的影响。
在这里插入图片描述

12.关键结论解读

12.1 预测精度:XGBoost 全面领先

XGBoost 在测试集上的 MAE(8.51)、RMSE(11.93)均为三者最低,R²(0.822)最高,相比线性回归,误差降低约 19.6%,R² 提升约 9.5%,说明模型对数据的拟合能力和预测准确性显著优于另外两个模型。

12.2 泛化能力:三个模型均无明显过拟合

三个模型的训练集与测试集指标几乎无差异,例如 XGBoost 的训练 / 测试 R² 仅差 0.002,说明模型未出现过拟合,在 unseen 数据上的表现稳定可靠。

12.3 模型特性差异

线性回归:作为基准模型,性能最弱,说明数据中存在明显的非线性关系,简单线性模型无法充分捕捉。
决策树:性能居中,相比线性回归有提升,但受限于单棵树的表达能力,对复杂模式的捕捉能力弱于集成模型。
XGBoost:通过梯度提升的集成学习方式,有效捕捉了数据中的非线性特征,同时保持了良好的泛化能力,是本次任务的最优模型。

13. 未来优化方向与展望

13.1 特征工程的进一步挖掘

时序特征增强:目前主要使用了静态聚合特征,未来可以引入成绩变化趋势(如前三次考试的斜率)来捕捉学生的进步或退步状态。

细粒度考勤分析:目前的考勤特征较为宏观,未来可以分析特定学科前的考勤表现(例如:英语课前的迟到率是否与英语成绩有更强的关联)。

13.2 模型算法的进阶尝试

深度学习引入:尝试使用 TabNet 或神经网络模型,探索在大规模样本下是否能进一步压低 RMSE。

模型解释性增强:引入 SHAP (SHapley Additive exPlanations) 值分析,为每一位学生的预测分数提供具体的“扣分项”或“加分项”解释,辅助老师进行精准谈话。

13.3 业务场景的落地应用

学业风险预警系统:将模型部署为自动化服务,在每次考试前根据近期的消费和考勤数据,自动推送“潜在成绩下滑风险”名单给班主任。

异常得分检测:利用预测分与真实分的偏差,识别出“发挥超常”或“发挥失常”的学生,帮助学校筛选需要心理疏导或学习方法指导的个案。

13.4 数据质量的闭环优化

解决低分段高估问题:针对目前模型对低分样本预测偏高的问题,计划采集更多关于学生心理状态、家庭背景或课堂表现的维度,以填补这部分信息的空白。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐