MySQL高级讲座篇之:`SQL`中的机器学习:如何利用MySQL的内置函数进行简单的数据预测?

各位观众老爷们,大家好!我是今天的主讲人,一个在代码堆里摸爬滚打多年的老码农。今天咱们来聊点有意思的,把MySQL这个老伙计拉出来,看看它能不能客串一把“机器学习工程师”,用它内置的函数,做点简单的数据预测。

别害怕,不是真的让你用SQL写神经网络,那太为难它了。我们只是利用一些统计函数,加上一点点SQL技巧,实现一些基础的预测功能。记住,是“简单”的预测,别指望它能预测世界杯冠军。

第一部分:数据准备,巧妇难为无米之炊

要想让MySQL做预测,首先得有数据。咱们先来创建一个简单的示例数据表,模拟一下电商平台的销售数据:

CREATE TABLE sales_data (
    sale_date DATE,
    product_id INT,
    quantity INT,
    price DECIMAL(10, 2),
    PRIMARY KEY (sale_date, product_id)
);

INSERT INTO sales_data (sale_date, product_id, quantity, price) VALUES
('2023-01-01', 1, 10, 25.00),
('2023-01-01', 2, 5, 50.00),
('2023-01-02', 1, 12, 25.00),
('2023-01-02', 2, 8, 50.00),
('2023-01-03', 1, 15, 25.00),
('2023-01-03', 2, 6, 50.00),
('2023-01-04', 1, 11, 25.00),
('2023-01-04', 2, 7, 50.00),
('2023-01-05', 1, 13, 25.00),
('2023-01-05', 2, 9, 50.00),
('2023-01-06', 1, 14, 25.00),
('2023-01-06', 2, 10, 50.00),
('2023-01-07', 1, 16, 25.00),
('2023-01-07', 2, 5, 50.00),
('2023-01-08', 1, 12, 25.00),
('2023-01-08', 2, 8, 50.00),
('2023-01-09', 1, 15, 25.00),
('2023-01-09', 2, 6, 50.00),
('2023-01-10', 1, 11, 25.00),
('2023-01-10', 2, 7, 50.00);

这个表包含了销售日期 (sale_date),产品ID (product_id),销售数量 (quantity) 和单价 (price)。有了这些数据,我们才能开始“预测”。

第二部分:利用内置函数,小试牛刀

MySQL内置了一些统计函数,像是AVG(), SUM(), MIN(), MAX(), STDDEV() 等,这些都是我们用来做简单预测的“武器”。

1. 平均值预测法:简单粗暴,但有效

最简单的预测方法就是用平均值。比如,我们想预测接下来几天产品1的销量,可以先计算过去一段时间的平均销量:

SELECT AVG(quantity) AS average_quantity
FROM sales_data
WHERE product_id = 1;

这条SQL会返回产品1的平均销量。然后,我们可以简单地认为,未来的销量也会接近这个平均值。

当然,这种方法很粗糙,没有考虑时间序列的变化。但它简单易懂,适合快速得到一个初步的预测值。

2. 移动平均法:考虑时间因素,更平滑

移动平均法是一种更高级一点的平均值预测方法。它只考虑最近一段时间的数据,并计算这些数据的平均值。这样可以更好地反映数据的趋势变化。

MySQL本身没有直接提供计算移动平均的函数,但我们可以用子查询和窗口函数来模拟:

SELECT
    sale_date,
    quantity,
    AVG(quantity) OVER (ORDER BY sale_date ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_average
FROM
    sales_data
WHERE
    product_id = 1
ORDER BY
    sale_date;

这条SQL会计算产品1的3天移动平均销量。AVG(quantity) OVER (ORDER BY sale_date ASC ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) 这部分是关键,它使用了窗口函数,指定了计算平均值的窗口范围:从当前行往前推2行。

你可以调整 ROWS BETWEEN 的参数来控制移动平均的窗口大小。窗口越大,预测结果越平滑,但也可能错过一些短期趋势。

3. 线性回归:寻找趋势线,预测未来

线性回归是一种更复杂的预测方法,它可以找到数据之间的线性关系,并用一条直线来拟合这些数据。然后,我们可以根据这条直线来预测未来的值。

MySQL提供了 STDDEV_POP() (总体标准差), STDDEV_SAMP() (样本标准差), VAR_POP() (总体方差), VAR_SAMP() (样本方差) 这些统计函数,可以帮助我们计算线性回归的参数。

线性回归公式:y = ax + b

其中:

  • y 是预测值
  • x 是自变量 (例如时间)
  • a 是斜率
  • b 是截距

计算公式:

  • a = (n * SUM(xy) - SUM(x) * SUM(y)) / (n * SUM(x^2) - SUM(x)^2)
  • b = (SUM(y) - a * SUM(x)) / n

咱们写个SQL来计算产品1的线性回归参数:

WITH data AS (
    SELECT
        ROW_NUMBER() OVER (ORDER BY sale_date) AS x,  -- 将日期转换为数字序列
        quantity AS y
    FROM
        sales_data
    WHERE
        product_id = 1
),
calculations AS (
    SELECT
        COUNT(*) AS n,
        SUM(x) AS sum_x,
        SUM(y) AS sum_y,
        SUM(x * y) AS sum_xy,
        SUM(x * x) AS sum_x2
    FROM
        data
)
SELECT
    (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x) AS a,  -- 斜率
    (sum_y - ((n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)) * sum_x) / n AS b   -- 截距
FROM
    calculations;

这条SQL有点长,咱们一步步解释:

  • WITH data AS (...): 这是一个公共表表达式 (CTE),用来准备数据。我们把 sale_date 转换成一个数字序列 x,把 quantity 作为 y
  • WITH calculations AS (...): 另一个CTE,用来计算需要的统计值,比如 SUM(x), SUM(y), SUM(x * y) 等。
  • 最后的 SELECT 语句,根据线性回归的公式,计算斜率 a 和截距 b

得到 ab 之后,就可以预测未来的销量了。比如,如果我们想预测第21天的销量,只需要把 x = 21 代入公式 y = ax + b 即可。

第三部分:更高级的技巧,让预测更精准

上面的方法都很基础,只能算是一些简单的尝试。要想让MySQL的预测更精准,还需要一些更高级的技巧。

1. 数据清洗:去除异常值,提高数据质量

数据质量对预测结果至关重要。如果数据中存在异常值,会严重影响预测的准确性。因此,在做预测之前,一定要进行数据清洗,去除异常值。

异常值有很多种定义方式,比如:

  • 超过平均值3个标准差的值
  • 落在某个固定范围之外的值

我们可以用SQL来识别和去除异常值:

-- 识别超过平均值3个标准差的异常值
SELECT
    sale_date,
    product_id,
    quantity
FROM
    sales_data
WHERE
    product_id = 1 AND
    quantity > (SELECT AVG(quantity) + 3 * STDDEV(quantity) FROM sales_data WHERE product_id = 1);

-- 从表中删除异常值(谨慎操作!)
DELETE FROM sales_data
WHERE
    product_id = 1 AND
    quantity > (SELECT AVG(quantity) + 3 * STDDEV(quantity) FROM sales_data WHERE product_id = 1);

注意: 删除数据是很危险的操作,一定要谨慎!最好先备份数据,或者创建一个新的表来存储清洗后的数据。

2. 特征工程:提取更多信息,增强预测能力

除了原始数据之外,我们还可以从原始数据中提取更多的特征,来增强预测能力。比如:

  • 季节性特征: 一年中的不同季节,销量可能会有很大的差异。我们可以创建一个 month 列,表示销售月份,然后把这个列作为特征。
  • 节假日特征: 节假日期间,销量通常会大幅增长。我们可以创建一个 is_holiday 列,表示是否是节假日。
  • 滞后特征: 昨天的销量可能会影响今天的销量。我们可以创建一个 yesterday_quantity 列,表示昨天的销量。

这些特征可以帮助模型更好地理解数据的模式,从而提高预测的准确性。

创建季节性特征的例子:

ALTER TABLE sales_data ADD COLUMN month INT;
UPDATE sales_data SET month = MONTH(sale_date);

3. 模型选择:选择合适的模型,提高预测精度

线性回归只是众多预测模型中的一种。还有很多其他的模型,比如:

  • 多项式回归: 用多项式曲线来拟合数据,可以更好地捕捉非线性关系。
  • 指数平滑: 对过去的数据赋予不同的权重,更重视最近的数据。

MySQL本身没有提供这些模型的实现,但我们可以把数据导出到Python或者R等工具中,用这些工具来训练模型,然后把预测结果导入回MySQL。

第四部分:实战案例,预测未来销量

咱们来一个稍微复杂一点的实战案例,预测未来一周的产品1的销量。

  1. 数据准备和清洗: 假设我们已经完成了数据准备和清洗工作,得到了一个干净的数据表 sales_data

  2. 特征工程: 我们提取了季节性特征 month 和滞后特征 yesterday_quantity

-- 创建滞后特征
ALTER TABLE sales_data ADD COLUMN yesterday_quantity INT;

UPDATE sales_data AS t1
JOIN (
    SELECT
        sale_date,
        product_id,
        quantity,
        LAG(quantity, 1, 0) OVER (PARTITION BY product_id ORDER BY sale_date) AS yesterday_quantity
    FROM
        sales_data
) AS t2 ON t1.sale_date = t2.sale_date AND t1.product_id = t2.product_id
SET t1.yesterday_quantity = t2.yesterday_quantity;
  1. 模型选择和训练: 我们选择线性回归模型,并用Python来训练模型。
import mysql.connector
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# 连接MySQL数据库
mydb = mysql.connector.connect(
    host="localhost",
    user="your_user",
    password="your_password",
    database="your_database"
)

# 读取数据
query = "SELECT sale_date, quantity, month, yesterday_quantity FROM sales_data WHERE product_id = 1"
df = pd.read_sql(query, mydb)

# 准备特征和目标变量
X = df[['month', 'yesterday_quantity']]
y = df['quantity']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 训练线性回归模型
model = LinearRegression()
model.fit(X_train, y_train)

# 打印模型参数
print("斜率 (a):", model.coef_)
print("截距 (b):", model.intercept_)

# 预测未来一周的销量 (假设1月份)
future_dates = pd.to_datetime(['2023-01-11', '2023-01-12', '2023-01-13', '2023-01-14', '2023-01-15', '2023-01-16', '2023-01-17'])
future_month = [d.month for d in future_dates]
# 需要手动模拟昨天的销量,这里简单假设为最近一天的销量
yesterday_quantity = [df['quantity'].iloc[-1]] * len(future_dates) #假设未来每天的昨天销量是当前最后一条记录的销量
future_data = pd.DataFrame({'month': future_month, 'yesterday_quantity': yesterday_quantity})
predictions = model.predict(future_data)

# 打印预测结果
print("未来一周的销量预测:")
for i, date in enumerate(future_dates):
    print(f"{date.strftime('%Y-%m-%d')}: {predictions[i]:.2f}")

# 关闭数据库连接
mydb.close()

这个Python脚本做了以下几件事:

  • 连接MySQL数据库,读取数据。
  • 准备特征和目标变量 (month, yesterday_quantity 作为特征,quantity 作为目标变量)。
  • 划分训练集和测试集。
  • 训练线性回归模型。
  • 预测未来一周的销量。
  • 打印预测结果。
  1. 将预测结果导入回MySQL: 我们可以把Python脚本的预测结果导入回MySQL,存储在一个新的表中。
CREATE TABLE sales_predictions (
    prediction_date DATE,
    product_id INT,
    predicted_quantity DECIMAL(10, 2),
    PRIMARY KEY (prediction_date, product_id)
);

-- 假设你已经把Python脚本的预测结果存储在一个名为 `predictions` 的列表中
-- 循环插入数据
-- INSERT INTO sales_predictions (prediction_date, product_id, predicted_quantity) VALUES
-- ('2023-01-11', 1, predictions[0]),
-- ('2023-01-12', 1, predictions[1]),
-- ...

第五部分:总结与展望

今天我们学习了如何利用MySQL的内置函数进行简单的数据预测。虽然MySQL不是专业的机器学习工具,但它的一些统计函数,加上一些SQL技巧,可以帮助我们快速得到一些初步的预测结果。

当然,这些方法都有局限性。如果需要更精准的预测,还是需要借助专业的机器学习工具。但对于一些简单的预测任务,或者作为初步的探索,MySQL完全可以胜任。

未来的展望:

  • MySQL 8.0的窗口函数: MySQL 8.0引入了更强大的窗口函数,可以更方便地计算移动平均、累计总和等统计指标,从而简化预测代码。
  • MySQL的插件: 未来可能会出现一些MySQL插件,提供更高级的机器学习功能,比如模型训练、模型评估等。
  • 与外部工具的集成: MySQL可以与Python、R等工具无缝集成,利用这些工具的强大机器学习能力,然后把预测结果导入回MySQL。

希望今天的讲座能给大家带来一些启发。记住,不要小看MySQL,它还有很多潜力可以挖掘。

感谢大家的观看!下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注