机器学习数据分析helper

姜智浩 Lv4

数据分析是一个循环迭代的过程,主要步骤如下:

  1. 明确问题 :定义目标和需求。
  2. 数据收集 :获取相关数据。
  3. 数据清洗 :处理缺失值、异常值等问题。
  4. 数据探索 :理解数据特性。
  5. 特征工程 :提取和优化特征。
  6. 模型选择与训练 :构建和训练模型。
  7. 模型评估 :验证模型性能。
  8. 结果解释与可视化 :呈现分析结果。
  9. 部署与监控 :应用到实际场景。
  10. 反馈与迭代 :持续改进。

基本库

最基础的库

1
2
import pandas as pd
import numpy as np

画图库

1
2
3
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline

机器学习库

1
2
3
4
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error,r2_score

sklearn库有很多 需要什么就import什么
不要直接import整个库

浏览数据

阅读数据

1
2
data = pd.read_csv('data.csv')  #打开data.csv文件
data.head #浏览前5行

查看数据信息

1
2
diabetes.describe() #查看数据的统计信息 如最大值 最小值 均值等
diabetes.info() #查看数据信息 如字段名 字段类型

EDA

通用 subplot 模板(可自定义图表类型):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

import matplotlib.pyplot as plt
import seaborn as sns
import math

# 选出要绘图的列(比如数值型列,或你指定的一组列)
plot_cols = [col for col in df.columns if df[col].dtype in ['float64', 'int64']]
# plot_cols = ['col1', 'col2', 'col3'] # 或者你手动指定

# 设置 subplot 的行列数(每行几个图)
n_cols = 2
n_rows = math.ceil(len(plot_cols) / n_cols)

# 创建子图网格
fig, axes = plt.subplots(n_rows, n_cols, figsize=(6 * n_cols, 5 * n_rows))
axes = axes.flatten() # 保证是 1D,方便遍历

# 遍历每个列,绘制你想要的图
for i, col in enumerate(plot_cols):
ax = axes[i]

# 可以自定义图表类型的部分(替换这里)
# 示例:绘制箱线图
sns.boxplot(data=df, x='Country', y=col, ax=ax)

# 示例:绘制散点图(替换上面一行即可)
# sns.scatterplot(data=df, x='Country', y=col, ax=ax)

# 示例:绘制折线图(如果是时间序列)
# sns.lineplot(data=df, x='Date', y=col, ax=ax)

ax.set_title(col)
ax.tick_params(axis='x', rotation=45)

# 删除多余的子图
for j in range(i+1, len(axes)):
fig.delaxes(axes[j])

plt.tight_layout()
plt.show()

散点图

matlab库

1
2
3
4
5
6
7
x = data["x"]
y = data["y"]
plt.scatter(x, y)
plt.xlabel('x')
plt.ylabel('y')
plt.title('title')
plt.show()

相关性分析

相关性矩阵

1
2
3
4
5
6
7
8
9
10
y = data['target']  #填入要进行分析的结果列 通常为最后一列
X = diabetes.drop(['target', 'others'], axis=1) #去除结果列和字符列(如果有)
#通常string类型的列(离散的特性)进行调整成int类型(连续化)即离散特征连续化

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

correlation_matrix = pd.concat([X_train, y_train], axis=1).corr()

sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm')
plt.show()

数据预处理

处理缺失值

删除含有缺失值的行

1
data_cleaned = df.dropna()

使用均值填充缺失值

1
df_filled = df.fillna(df.mean())

使用众数填充缺失值

1
2
3
4
5
6
7
8
9
10
# 示例数据
data = {'A': [1, 2, 2, None, 4, 2], 'B': ['red', 'blue', 'red', None, 'green', 'red']}
df = pd.DataFrame(data)

# 找到每列的众数
mode_A = df['A'].mode()[0] # 数值型列
mode_B = df['B'].mode()[0] # 类别型列

# 使用众数填充缺失值
df_filled_mode = df.fillna({'A': mode_A, 'B': mode_B})
1
2
3
4
5
6
7
8
9
10
11
12
13
# 示例数据
data = {'C': [1, 2, 3, None, 5, 6, None]}
df = pd.DataFrame(data)

# 计算指定分位数
quantile_25 = df['C'].quantile(0.25) # 第一四分位数 (25%)
quantile_50 = df['C'].quantile(0.50) # 中位数 (50%)
quantile_75 = df['C'].quantile(0.75) # 第三四分位数 (75%)

# 使用分位数填充缺失值
df_filled_quantile_25 = df.fillna({'C': quantile_25})
df_filled_quantile_50 = df.fillna({'C': quantile_50})
df_filled_quantile_75 = df.fillna({'C': quantile_75})

处理异常值

异常值检测

使用 Z-Score 检测

Z-Score 衡量某个值距离均值的标准差数量。通常,绝对 Z-Score 大于 3 的值被认为是异常值。

1
2
3
4
5
6
7
8
9
10
11
12
# 示例数据
data = {'A': [1, 2, 3, 4, 5, 100]}
df = pd.DataFrame(data)

# 计算 Z-Score
mean = df['A'].mean()
std = df['A'].std()
df['Z-Score'] = (df['A'] - mean) / std

# 检测异常值(Z-Score > 3 或 < -3)
outliers = df[abs(df['Z-Score']) > 3]
print("异常值:\n", outliers)

使用 IQR 方法检测

IQR(四分位距)是第三四分位数(Q3)与第一四分位数(Q1)的差值。通常,低于 Q1−1.5×IQR 或高于 Q3+1.5×IQR 的值被认为是异常值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 示例数据
data = {'A': [1, 2, 3, 4, 5, 100]}
df = pd.DataFrame(data)

# 计算 IQR
Q1 = df['A'].quantile(0.25)
Q3 = df['A'].quantile(0.75)
IQR = Q3 - Q1

# 定义上下界
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 检测异常值
outliers = df[(df['A'] < lower_bound) | (df['A'] > upper_bound)]
print("异常值:\n", outliers)

This is Tab 3.

箱线图(Box Plot)是一种直观的异常值检测工具。
箱线图中的点位于箱子外部的上界或下界之外,这些点即为异常值。

1
2
3
4
5
6
import matplotlib.pyplot as plt

# 绘制箱线图
plt.boxplot(df['A'])
plt.title('Box Plot of Data')
plt.show()

异常值处理

删除异常值
直接从数据集中移除异常值。

1
2
3
 # 删除基于 IQR 方法检测到的异常值
filtered_df = df[(df['A'] >= lower_bound) & (df['A'] <= upper_bound)]
print("删除异常值后的数据:\n", filtered_df)

替换异常值

将异常值替换为合理的值,例如均值、中位数或边界值。

1
2
3
4
5
# 将异常值替换为中位数
median = df['A'].median()
df['A'] = np.where((df['A'] < lower_bound) | (df['A'] > upper_bound), median, df['A'])

print("替换异常值后的数据:\n", df)

胜率变换

将异常值限制在一定范围内,而不是完全删除或替换。

1
2
3
4
5
6
from scipy.stats import mstats

# 胜率变换:将异常值限制在 5% 和 95% 分位数之间
df['A_winsorized'] = mstats.winsorize(df['A'], limits=[0.05, 0.05])

print("胜率变换后的数据:\n", df)

数据标准化与归一化

标准化

将数据转换为零均值(Mean = 0)和单位方差(Variance = 1)

  • 适用于数据分布接近正态分布的情况 :标准化假设数据服从正态分布,因此在数据分布大致对称时效果更好。
  • 适用于对距离敏感的算法 :例如 K-Means、KNN、SVM 和神经网络等。这些算法对特征的尺度非常敏感,标准化可以确保每个特征对结果的贡献是均衡的。
  • 适用于梯度下降优化的模型 :如线性回归、逻辑回归等。标准化可以使梯度下降更快收敛。
1
2
3
4
5
6
7
8
9
10
from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 示例数据
data = [[1, 2], [3, 4], [5, 6]]
X = pd.DataFrame(data, columns=['A', 'B'])

# 标准化
scaler = StandardScaler()
X_standardized = scaler.fit_transform(X)
print("标准化后的数据:\n", X_standardized)

归一化

将数据缩放到指定范围(通常是 [0, 1] 或 [-1, 1])

  • 适用于数据分布未知或非正态分布的情况 :归一化不要求数据服从正态分布,因此适用于分布不规则的数据。
  • 适用于最大值和最小值明确的场景 :例如图像像素值通常在 [0, 255] 范围内,归一化可以将其缩放到 [0, 1]。
  • 适用于距离计算或相似性度量的算法 :例如余弦相似度、基于距离的聚类算法等。归一化可以避免大值特征主导结果。
1
2
3
4
5
6
7
8
9
10
from sklearn.preprocessing import StandardScaler, MinMaxScaler

# 示例数据
data = [[1, 2], [3, 4], [5, 6]]
X = pd.DataFrame(data, columns=['A', 'B'])

# 归一化
minmax_scaler = MinMaxScaler()
X_normalized = minmax_scaler.fit_transform(X)
print("归一化后的数据:\n", X_normalized)

特征编码

特征编码(Feature Encoding)是将非数值型特征(如类别型、文本型数据)转换为数值型表示的过程。它是机器学习中数据预处理的重要步骤,因为大多数机器学习算法只能处理数值型数据。

将类别型变量映射为整数(如 “red” → 0, “blue” → 1, “green” → 2)。
适用场景 :类别之间具有顺序关系(如 “low”, “medium”, “high”)。
优点 :简单高效,适用于少量类别的情况。
缺点 :可能导致模型误以为类别之间有数值上的大小关系。

1
2
3
4
5
6
7
from sklearn.preprocessing import LabelEncoder

# 示例数据
data = ['red', 'blue', 'green', 'blue', 'red']
le = LabelEncoder()
encoded_data = le.fit_transform(data)
print("标签编码结果:", encoded_data)

将每个类别值转换为一个二进制向量。
适用场景 :类别之间没有顺序关系(如 “red”, “blue”, “green”)。
优点 :消除了类别间的数值关系,适合无序类别。
缺点 :可能会导致维度爆炸(类别数量过多时生成的特征维度过大)。

1
2
3
4
5
6
7
8
from sklearn.preprocessing import OneHotEncoder
import pandas as pd

# 示例数据
data = ['red', 'blue', 'green', 'blue', 'red']
ohe = OneHotEncoder(sparse=False)
encoded_data = ohe.fit_transform(pd.DataFrame(data))
print("独热编码结果:\n", encoded_data)

使用目标变量的统计信息(如均值)对类别变量进行编码。
适用场景 :类别数量较多且数据量较大时,避免维度爆炸问题。
优点 :保留了类别与目标变量的关系。
缺点 :可能导致过拟合,需注意平滑处理。

1
2
3
4
5
6
7
8
9
10
import pandas as pd

# 示例数据
data = {'category': ['A', 'B', 'A', 'B', 'C'], 'target': [1, 0, 1, 1, 0]}
df = pd.DataFrame(data)

# 计算每个类别的目标均值
target_mean = df.groupby('category')['target'].mean()
df['target_encoded'] = df['category'].map(target_mean)
print("目标编码结果:\n", df)

特征选择与降维

特征选择

特征选择是从原始特征集中选择最重要的子集,从而减少无关或冗余特征对模型的影响。

减少过拟合 :通过去除无关特征,降低模型复杂度。
提高训练效率 :减少特征数量可以加速模型训练。
增强可解释性 :保留关键特征有助于理解模型的工作机制。

根据特征选择的方式,可分为以下三类:

根据统计指标(如相关性、互信息等)独立评估每个特征的重要性。
不依赖于具体模型。
优点 :计算简单,速度快。
缺点 :可能忽略特征之间的交互关系。

示例 :
相关系数(Pearson、Spearman)
卡方检验
互信息

1
2
3
4
5
6
7
8
9
10
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.datasets import load_iris

# 加载数据
X, y = load_iris(return_X_y=True)

# 使用卡方检验选择前 2 个最佳特征
selector = SelectKBest(chi2, k=2)
X_new = selector.fit_transform(X, y)
print("选择后的特征形状:", X_new.shape)

通过反复训练模型来评估特征子集的表现。
常用算法:递归特征消除(RFE)。
优点 :考虑特征之间的交互关系。
缺点 :计算成本高。

示例 :
RFE(Recursive Feature Elimination)

1
2
3
4
5
6
7
8
 from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression

# 创建模型
model = LogisticRegression()
rfe = RFE(model, n_features_to_select=2)
X_new = rfe.fit_transform(X, y)
print("选择后的特征形状:", X_new.shape)

在模型训练过程中自动选择重要特征。
常用算法:Lasso 回归、树模型(如随机森林、XGBoost)。
优点 :结合了模型训练和特征选择。
缺点 :依赖于具体模型。

示例 :
Lasso 回归(基于 L1 正则化)

1
2
3
4
5
6
7
from sklearn.linear_model import Lasso

# 使用 Lasso 回归进行特征选择
lasso = Lasso(alpha=0.1)
lasso.fit(X, y)
selected_features = [i for i, coef in enumerate(lasso.coef_) if coef != 0]
print("选择的特征索引:", selected_features)

主成分分析(PCA)

将数据投影到方差最大的方向上。
优点 :线性变换,计算高效。
缺点 :仅适用于线性可分的数据。

1
2
3
4
5
6
from sklearn.decomposition import PCA

# 使用 PCA 降维到 2 维
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
print("降维后的数据形状:", X_pca.shape)

数据划分

分离特征和目标变量

1
2
3
# 假设 'target' 是目标变量列名
X = data.drop(columns=['target']) # 特征
y = data['target'] # 目标变量

数据划分

将数据划分为训练集和测试集

1
2
3
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print("训练集大小:", X_train.shape)
print("测试集大小:", X_test.shape)

模型

sklearn 中的常用二分类模型代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.neural_network import MLPClassifier

models = {
"Logistic Regression": LogisticRegression(),
"SVM": SVC(),
"Random Forest": RandomForestClassifier(),
"KNN": KNeighborsClassifier(),
"Naive Bayes": GaussianNB(),
"MLP Neural Net": MLPClassifier()
}

模型标准化+训练+优化模版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler # ✅ 可换成 MinMaxScaler、RobustScaler 等
from sklearn.svm import SVC # ✅ 可换成 LogisticRegression, RandomForestClassifier, etc.
from sklearn.model_selection import GridSearchCV

# ✅ 第1处:构建Pipeline步骤
pipeline = Pipeline([
('scaler', StandardScaler()), # 标准化步骤(可删、可换)
('svm', SVC()) # 模型步骤(可换)
])

# ✅ 第2处:定义参数网格
param_grid = {
'svm__C': [0.1, 1, 10], # 可调SVM的 C 值范围
'svm__kernel': ['linear', 'rbf'], # 可选 kernel 类型
'svm__gamma': ['scale', 'auto'] # 适用于 rbf kernel
# 替换模型时需要换成对应模型参数名,例如:
# 'logreg__penalty': ['l2'],
# 'logreg__C': [0.01, 0.1, 1, 10]
}

# ✅ 第3处:GridSearchCV 封装 Pipeline
grid_search = GridSearchCV(pipeline, param_grid, cv=5) # cv 可改为 3/10 或 StratifiedKFold 等

# ✅ 第4处:训练
grid_search.fit(X_train, y_train) # 训练数据输入(确保已经分好训练集)

# ✅ 第5处:结果查看
print("最优参数:", grid_search.best_params_)
print("最优交叉验证得分:", grid_search.best_score_)

# ✅ 第6处:在测试集上做预测
y_pred = grid_search.predict(X_test)

模型评估

准确率

准确率是指模型预测正确的样本占总样本的比例。

1
2
3
4
5
6
7
8
9
from sklearn.metrics import accuracy_score

# 示例数据
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]

# 计算准确率
accuracy = accuracy_score(y_true, y_pred)
print("准确率:", accuracy)

混淆矩阵

混淆矩阵是一个表格,用于总结分类模型的预测结果。

常见术语:
TP(True Positive):正类正确预测为正类。
TN(True Negative):负类正确预测为负类。
FP(False Positive):负类错误预测为正类。
FN(False Negative):正类错误预测为负类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt

# 示例数据
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]

# 计算混淆矩阵
cm = confusion_matrix(y_true, y_pred)

# 可视化混淆矩阵
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('Predicted Labels')
plt.ylabel('True Labels')
plt.title('Confusion Matrix')
plt.show()

召回率

召回率(也称灵敏度或 True Positive Rate)是指模型正确预测为正类的样本占实际正类的比例。

1
2
3
4
5
6
7
8
9
from sklearn.metrics import recall_score

# 示例数据
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]

# 计算召回率
recall = recall_score(y_true, y_pred)
print("召回率:", recall)

精确率

精确率是指模型预测为正类的样本中实际为正类的比例。

适用场景
关注减少误报时使用(如推荐系统)。

1
2
3
4
5
6
7
8
9
from sklearn.metrics import precision_score

# 示例数据
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]

# 计算精确率
precision = precision_score(y_true, y_pred)
print("精确率:", precision)

F1 分数

F1 分数是精确率和召回率的调和平均值,用于综合衡量模型性能。

适用场景
类别不平衡时使用。

1
2
3
4
5
6
7
8
9
from sklearn.metrics import f1_score

# 示例数据
y_true = [0, 1, 1, 0, 1]
y_pred = [0, 1, 0, 0, 1]

# 计算 F1 分数
f1 = f1_score(y_true, y_pred)
print("F1 分数:", f1)

AUC

AUC 是 ROC 曲线下的面积,用于衡量模型区分正负类的能力。
范围:[0, 1],值越大表示模型性能越好。

适用场景
需要评估模型整体性能时使用。

1
2
3
4
5
6
7
8
9
from sklearn.metrics import roc_auc_score

# 示例数据
y_true = [0, 1, 1, 0, 1]
y_scores = [0.1, 0.9, 0.8, 0.2, 0.7] # 模型预测的概率值

# 计算 AUC
auc = roc_auc_score(y_true, y_scores)
print("AUC:", auc)

均方误差 均方根误差 R² 决定系数

均方误差是预测值与真实值之间差值平方的平均值。

均方根误差是均方误差的平方根,用于将误差恢复到原始单位。

R² 决定系数衡量模型对数据的拟合程度,取值范围为 (−∞,1]。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score

# 示例数据
y_true = [3.0, -0.5, 2.0, 7.0] # 真实值
y_pred = [2.5, 0.0, 2.0, 8.0] # 预测值

# 计算 MSE
mse = mean_squared_error(y_true, y_pred)
print("均方误差(MSE):", mse)

# 计算 RMSE
rmse = np.sqrt(mse)
print("均方根误差(RMSE):", rmse)

# 计算 MAE
mae = mean_absolute_error(y_true, y_pred)
print("平均绝对误差(MAE):", mae)

# 计算 R²
r2 = r2_score(y_true, y_pred)
print("R² 决定系数:", r2)

综合案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split, cross_val_score, GridSearchCV
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error, r2_score

# 假设 data 是一个 Pandas DataFrame
# data = pd.read_csv('data.csv')

# 数据预处理
X = data.drop(columns=['target'])
y = data['target']

numeric_features = X.select_dtypes(include=['int64', 'float64']).columns
categorical_features = X.select_dtypes(include=['object', 'category']).columns

preprocessor = ColumnTransformer(
transformers=[
('num', StandardScaler(), numeric_features),
('cat', OneHotEncoder(), categorical_features)
]
)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 可视化
plt.figure(figsize=(8, 5))
sns.histplot(y, kde=True, bins=30, color='blue')
plt.title('Target Variable Distribution')
plt.show()

# 模型选择
models = {
"Linear Regression": Pipeline(steps=[('preprocessor', preprocessor), ('regressor', LinearRegression())]),
"Ridge Regression": Pipeline(steps=[('preprocessor', preprocessor), ('regressor', Ridge())]),
"Lasso Regression": Pipeline(steps=[('preprocessor', preprocessor), ('regressor', Lasso())])
}

param_grid = {'regressor__alpha': [0.01, 0.1, 1, 10, 100]}
for model_name, model in list(models.items())[1:]:
grid_search = GridSearchCV(model, param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
models[model_name] = grid_search.best_estimator_
print(f"{model_name} 最佳参数:", grid_search.best_params_)

# 模型验证
results = {}
for model_name, model in models.items():
scores = cross_val_score(model, X_train, y_train, cv=5, scoring='neg_mean_squared_error')
results[model_name] = -scores.mean()
print(f"{model_name} 的平均 MSE:", results[model_name])

# 测试集评估
best_model_name = min(results, key=results.get)
best_model = models[best_model_name]
print(f"最佳模型:{best_model_name}")

best_model.fit(X_train, y_train)
y_pred = best_model.predict(X_test)

mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f"测试集 MSE:{mse}")
print(f"测试集 R²:{r2}")

# 结果可视化
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, alpha=0.7, color='blue')
plt.plot([y.min(), y.max()], [y.min(), y.max()], 'r--', lw=2)
plt.title('True vs Predicted Values')
plt.show()

residuals = y_test - y_pred
plt.figure(figsize=(8, 6))
sns.histplot(residuals, kde=True, bins=30, color='green')
plt.title('Residuals Distribution')
plt.show()
  • Title: 机器学习数据分析helper
  • Author: 姜智浩
  • Created at : 2025-04-07 11:45:14
  • Updated at : 2025-06-05 21:30:32
  • Link: https://super-213.github.io/zhihaojiang.github.io/2025/04/07/20250407机器学习数据分析helper/
  • License: This work is licensed under CC BY-NC-SA 4.0.