线性回归实战(一):房价预测数据集入库KingbaseES,表结构设计

线性回归实战(一):房价预测数据集入库 KingbaseES ------ 表结构设计

------别让"脏数据"毁掉你精心调优的模型

大家好,我是那个总在模型上线前夜发现"面积字段有负值"、又在 KES 里追查一条异常样本血缘的老架构。今天不讲算法,也不谈梯度------我们回到 AI 工程最朴素也最关键的起点:

数据怎么存?

很多人以为:"不就是建个表,把 CSV 导进去吗?"

但现实是:90% 的模型失败,源于糟糕的数据建模

特征缺失、单位混乱、版本错乱、标签泄露......这些问题,不是训练时能补救的,必须在入库那一刻就堵住

而真相是:数据库表结构,就是你的第一层特征工程

今天我们就以经典的"房价预测"任务为例,手把手设计一套面向机器学习的 KingbaseES 表结构 ,并用 Java 完成数据入库。全程基于电科金仓 KES,不依赖外部工具,只为构建一个干净、可追溯、可复现的 AI 数据底座。


一、原始数据长什么样?

我们采用 Kaggle 上经典的 California Housing Dataset(简化版),包含以下字段:

字段 含义 示例值
longitude 经度 -122.23
latitude 纬度 37.88
housing_median_age 房屋中位年龄(年) 41
total_rooms 总房间数 880
total_bedrooms 总卧室数 129
population 人口 322
households 家庭数 126
median_income 收入中位数(万美元) 8.3252
median_house_value 房价中位数(万美元) 452600 ← 标签

注意:所有数值都是连续型,无分类变量,非常适合线性回归入门


二、表结构设计原则:为 ML 而生

在传统业务系统中,表设计关注范式、事务、一致性。

但在 AI 场景下,我们要额外考虑:

特征完整性 :不能丢字段

数值精度 :避免 float 舍入误差

空值策略 :明确缺失处理方式

版本隔离 :支持多轮实验

标签安全:防止训练时信息泄露

基于此,我们设计三层表结构:

复制代码
raw/        → 原始数据(只读)
cleaned/    → 清洗后特征(带元数据)
datasets/   → 划分后的训练/测试集(带版本)

三、Step 1:原始数据表(ai_raw.california_housing_raw)

sql 复制代码
CREATE SCHEMA IF NOT EXISTS ai_raw;

CREATE TABLE ai_raw.california_housing_raw (
    id                    SERIAL PRIMARY KEY,
    longitude             REAL        NOT NULL,
    latitude              REAL        NOT NULL,
    housing_median_age    REAL        NOT NULL,
    total_rooms           INTEGER     NOT NULL,
    total_bedrooms        INTEGER,    -- 允许 NULL(真实场景常见)
    population            INTEGER     NOT NULL,
    households            INTEGER     NOT NULL,
    median_income         REAL        NOT NULL,
    median_house_value    REAL        NOT NULL,  -- 标签
    source_file           VARCHAR(64) NOT NULL DEFAULT 'sklearn_v1',
    ingest_time           TIMESTAMP   DEFAULT NOW()
);

💡 设计说明:

  • total_bedrooms 允许 NULL:模拟真实缺失;
  • 所有数值用 REAL(4 字节 float):平衡精度与存储;
  • source_fileingest_time:追踪数据来源;
  • 不做任何清洗:保留原始状态,便于回溯。

四、Step 2:清洗后特征表(ai_features.california_housing_cleaned)

清洗逻辑用 SQL 视图实现(可复用、可审计):

sql 复制代码
CREATE SCHEMA IF NOT EXISTS ai_features;

CREATE OR REPLACE VIEW ai_features.v_california_housing_cleaned AS
SELECT
    id,
    longitude,
    latitude,
    housing_median_age,
    total_rooms,
    COALESCE(total_bedrooms, total_rooms * 0.3) AS total_bedrooms,  -- 缺失填充
    population,
    households,
    median_income,
    median_house_value,
    -- 衍生特征(简单示例)
    (total_rooms::REAL / households) AS rooms_per_household,
    (population::REAL / households)  AS population_per_household,
    -- 标签归一化(可选,也可在 Java 中做)
    median_house_value / 100000.0 AS label_normalized
FROM ai_raw.california_housing_raw
WHERE 
    total_rooms > 0 
    AND households > 0 
    AND median_income BETWEEN 0.5 AND 15.0;  -- 过滤异常值

✅ 优势:

  • 清洗逻辑与代码解耦;
  • 业务人员可直接查视图验证;
  • 未来新增特征,只需改 SQL。

五、Step 3:训练/测试集划分(带版本)

sql 复制代码
-- 创建版本化表
CREATE TABLE ai_datasets.california_housing_v1_train (
    LIKE ai_features.v_california_housing_cleaned INCLUDING ALL
);

CREATE TABLE ai_datasets.california_housing_v1_test (
    LIKE ai_features.v_california_housing_cleaned INCLUDING ALL
);

-- 按 ID 哈希划分(确保可复现)
INSERT INTO ai_datasets.california_housing_v1_train
SELECT * FROM ai_features.v_california_housing_cleaned
WHERE ABS(hashtext(id::TEXT)) % 10 < 8;  -- 80% 训练

INSERT INTO ai_datasets.california_housing_v1_test
SELECT * FROM ai_features.v_california_housing_cleaned
WHERE ABS(hashtext(id::TEXT)) % 10 >= 8; -- 20% 测试

同时记录元数据:

sql 复制代码
CREATE TABLE ai_datasets.dataset_version_meta (
    version       VARCHAR(32) PRIMARY KEY,
    description   TEXT,
    train_count   INT,
    test_count    INT,
    created_at    TIMESTAMP DEFAULT NOW()
);

INSERT INTO ai_datasets.dataset_version_meta 
(version, description, train_count, test_count)
VALUES (
    'california_housing_v1',
    'Baseline for linear regression, with basic imputation',
    (SELECT COUNT(*) FROM ai_datasets.california_housing_v1_train),
    (SELECT COUNT(*) FROM ai_datasets.california_housing_v1_test)
);

六、Java 实现:从 CSV 到 KES 入库

java 复制代码
public void ingestHousingData(String csvPath) throws Exception {
    // 1. 读取 CSV(略去解析细节)
    List<HousingRecord> records = parseCSV(csvPath);

    // 2. 批量插入 raw 表
    String sql = """
        INSERT INTO ai_raw.california_housing_raw (
            longitude, latitude, housing_median_age,
            total_rooms, total_bedrooms, population,
            households, median_income, median_house_value
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """;

    try (Connection conn = KESDataSource.getConnection();
         PreparedStatement ps = conn.prepareStatement(sql)) {

        for (HousingRecord r : records) {
            ps.setDouble(1, r.longitude);
            ps.setDouble(2, r.latitude);
            ps.setDouble(3, r.housingMedianAge);
            ps.setInt(4, r.totalRooms);
            ps.setObject(5, r.totalBedrooms); // null-safe
            ps.setInt(6, r.population);
            ps.setInt(7, r.households);
            ps.setDouble(8, r.medianIncome);
            ps.setDouble(9, r.medianHouseValue);
            ps.addBatch();
        }
        ps.executeBatch();
    }

    System.out.println("Ingested " + records.size() + " records to KES.");
}

🔗 JDBC 驱动请从 电科金仓官网下载,确保支持 setObject 处理 NULL。


七、为什么这套设计值得借鉴?

  1. 可追溯:从 raw → cleaned → dataset,每一步可审计;
  2. 可复现:哈希划分 + 版本表,确保实验一致;
  3. 可扩展:新增特征只需改视图,不影响上游;
  4. 国产友好:完全基于 KES 能力,无需 Python pandas;
  5. 安全隔离:训练集不含未来信息(如未发生交易)。

结语:数据建模,是 AI 工程的"第一道防线"

在国产化 AI 落地中,我们常被要求"快速出效果"。

但真正的专业,体现在愿意花时间把数据底座打牢

当你能在电科金仓的 KES 中,用清晰的 schema、可复现的划分、可解释的清洗,构建一个干净的房价数据集------你就已经赢了 80% 的团队。

因为接下来,无论是最小二乘法、梯度下降,还是 DL4J 的神经网络,它们面对的,将是一个值得信赖的世界

------ 一位相信"好的模型,始于干净的数据"的架构师

相关推荐
CSD资源分享2 小时前
Claude Code 国内API配置完整指南
java·windows·claude·claude code
索荣荣2 小时前
Java关键字终极指南:从入门到精通
java·开发语言
田里的水稻2 小时前
AD_车辆运动无模型横向控制_纯跟踪(PP,Pure Pursuit)
人工智能·自动驾驶
czlczl200209252 小时前
工作流 Flowable 全流程
java·spring boot·后端
李少兄2 小时前
IntelliJ IDEA 全局搜索完全指南:从高效使用到快捷键失效排查
java·intellij-idea·策略模式
沉默-_-2 小时前
掌握Maven:高效Java项目构建与管理
java·开发语言·后端·maven
淬炼之火2 小时前
图文跨模态融合基础 2 :LLM工程总览
人工智能·语言模型·自然语言处理
数据知道2 小时前
PostgreSQL 实战:数组的增删改查与索引优化详解
数据库·postgresql
wangbing11252 小时前
从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
java·开发语言