知识点:
## NumPy 数组基础笔记
### 1. 理解数组的维度 (Dimensions)
NumPy 数组的**维度 (Dimension)** 或称为 **轴 (Axis)** 的概念,与我们日常理解的维度非常相似。
* **直观判断:** 数组的维度层数通常可以通过打印输出时**中括号 `[]` 的嵌套层数**来初步确定:
* 一层 `[]`: **一维 (1D)** 数组。
* 两层 `[]`: **二维 (2D)** 数组。
* 三层 `[]`: **三维 (3D)** 数组,依此类推。
### 2. NumPy 数组与深度学习 Tensor 的关系
在后续进行频繁的数学运算时,尤其是在深度学习领域,对 NumPy 数组的理解非常有帮助,因为 PyTorch 或 TensorFlow 中的 **Tensor** 张量本质上可以视为**支持 GPU 加速**和**自动微分**的 NumPy 数组。掌握 NumPy 的基本操作,能极大地降低学习 Tensor 的门槛。关于 NumPy 更深入的性质,我们留待后续探讨。
### 3. 一维数组 (1D Array)
一维数组在结构上与 Python 中的列表(List)非常相似。它们的主要区别在于:
* **打印输出格式:** 当使用 `print()` 函数输出时:
* NumPy 一维数组的元素之间默认使用**空格**分隔。
* Python 列表的元素之间使用**逗号**分隔。
* **示例 (一维数组输出):**
```
[7 5 3 9]
```
### 4. 二维数组 (2D Array)
二维数组可以被看作是“数组的数组”或者一个矩阵。其结构由两个主要维度决定:
* **行数:** 代表整个二维数组中**包含多少个一维数组**。
* **列数:** 代表**每个一维数组(也就是每一行)中包含多少个元素**。
值得注意的是,二维数组**不一定**是正方形(即行数等于列数),它可以是任意的 `n * m` 形状,其中 `n` 是行数,`m` 是列数。
### 5. 数组的创建
NumPy 的 `array()` 函数非常灵活,可以接受各种“序列型”对象作为输入参数来创建数组。这意味着你可以将 Python 的**列表 (List)**、**元组 (Tuple)**,甚至其他的 NumPy **数组**等数据结构直接传递给 `np.array()` 来创建新的 NumPy 数组。
简单数组的建立
# 简单创建
arr1 = np.array([1, 2, 3, 4, 5]) # 一维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]]) # 二维数组
arr3 = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) # 三维数组
print("一维数组:")
print(arr1)
print("\n二维数组:")
print(arr2)
print("\n三维数组:")
print(arr3)
random_arr1 = np.random.randint(0, 10, 5) # 生成[0,10)区间的一维随机数组
random_arr2 = np.random.randint(-5, 5, (3, 3)) # 生成[-5,5)区间的3x3二维随机数组
random_arr3 = np.random.randint(10, 20, (2, 2, 2)) # 生成[10,20)区间的2x2x2三维随机数组
print("\n随机一维数组:")
print(random_arr1)
print("\n随机二维数组:")
print(random_arr2)
print("\n随机三维数组:")
print(random_arr3)
print("一维数组遍历:")
for num in arr1:
print(num)
print("\n二维数组遍历:")
for row in arr2:
for num in row:
print(num)
print("\n三维数组遍历:")
for matrix in arr3:
for row in matrix:
for num in row:
print(num)
# 矩阵运算
mat_a = np.array([[1, 2], [3, 4]]) # 2x2矩阵
mat_b = np.array([[5, 6], [7, 8]]) # 2x2矩阵
# 矩阵乘法
mat_mul = np.matmul(mat_a, mat_b) # 或者使用 @ 运算符: mat_a @ mat_b
print("\n矩阵乘法结果:")
print(mat_mul)
# 矩阵点乘 (逐元素相乘)
mat_dot = np.multiply(mat_a, mat_b) # 或者使用 * 运算符: mat_a * mat_b
print("\n矩阵点乘结果:")
print(mat_dot)
# 矩阵转置
mat_transpose = np.transpose(mat_a) # 或者使用 .T 属性: mat_a.T
print("\n矩阵转置结果:")
print(mat_transpose)
# 矩阵求逆 (必须是方阵且可逆)
mat_inv = np.linalg.inv(mat_a)
print("\n矩阵逆矩阵结果:")
print(mat_inv)
# 矩阵行列式 (必须是方阵)
mat_det = np.linalg.det(mat_a)
print("\n矩阵行列式结果:")
print(mat_det)
# 基本运算
sum_arr = arr1 + 10 # 每个元素加10
print("\n数组每个元素加10:")
print(sum_arr)
mul_arr = arr2 * 2 # 每个元素乘2
print("\n数组每个元素乘2:")
print(mul_arr)
dot_product = np.dot(arr1, np.array([2, 2, 2, 2, 2])) # 点积
print("\n数组点积结果:")
print(dot_product)
# 一维
print("\n一维数组索引:")
print(arr1[0]) # 第一个元素
print(arr1[-1]) # 最后一个元素
# 二维
print("\n二维数组索引:")
print(arr2[0, 1]) # 第一行第二列
print(arr2[:, 1]) # 所有行的第二列
# 三维
print("\n三维数组索引:")
print(arr3[0, 1, 0]) # 第一个矩阵的第二行第一列
print(arr3[1, :, 0]) # 第二个矩阵的所有行的第一列
import numpy as np
a = np.array([2,4,6,8,10,12]) # 创建一个一维数组
b = np.array([[2,4,6],[8,10,12]]) # 创建一个二维数组
print(a)
print(b)
SHAP值的深入理解
# 先运行之前预处理好的代码
import pandas as pd
import pandas as pd #用于数据处理和分析,可处理表格数据。
import numpy as np #用于数值计算,提供了高效的数组操作。
import matplotlib.pyplot as plt #用于绘制各种类型的图表
import seaborn as sns #基于matplotlib的高级绘图库,能绘制更美观的统计图形。
import warnings
warnings.filterwarnings("ignore")
# 设置中文字体(解决中文显示问题)
plt.rcParams['font.sans-serif'] = ['SimHei'] # Windows系统常用黑体字体
plt.rcParams['axes.unicode_minus'] = False # 正常显示负号
data = pd.read_csv('data.csv') #读取数据
# 先筛选字符串变量
discrete_features = data.select_dtypes(include=['object']).columns.tolist()
# Home Ownership 标签编码
home_ownership_mapping = {
'Own Home': 1,
'Rent': 2,
'Have Mortgage': 3,
'Home Mortgage': 4
}
data['Home Ownership'] = data['Home Ownership'].map(home_ownership_mapping)
# Years in current job 标签编码
years_in_job_mapping = {
'< 1 year': 1,
'1 year': 2,
'2 years': 3,
'3 years': 4,
'4 years': 5,
'5 years': 6,
'6 years': 7,
'7 years': 8,
'8 years': 9,
'9 years': 10,
'10+ years': 11
}
data['Years in current job'] = data['Years in current job'].map(years_in_job_mapping)
# Purpose 独热编码,记得需要将bool类型转换为数值
data = pd.get_dummies(data, columns=['Purpose'])
data2 = pd.read_csv("data.csv") # 重新读取数据,用来做列名对比
list_final = [] # 新建一个空列表,用于存放独热编码后新增的特征名
for i in data.columns:
if i not in data2.columns:
list_final.append(i) # 这里打印出来的就是独热编码后的特征名
for i in list_final:
data[i] = data[i].astype(int) # 这里的i就是独热编码后的特征名
# Term 0 - 1 映射
term_mapping = {
'Short Term': 0,
'Long Term': 1
}
data['Term'] = data['Term'].map(term_mapping)
data.rename(columns={'Term': 'Long Term'}, inplace=True) # 重命名列
continuous_features = data.select_dtypes(include=['int64', 'float64']).columns.tolist() #把筛选出来的列名转换成列表
# 连续特征用中位数补全
for feature in continuous_features:
mode_value = data[feature].mode()[0] #获取该列的众数。
data[feature].fillna(mode_value, inplace=True) #用众数填充该列的缺失值,inplace=True表示直接在原数据上修改。
# 最开始也说了 很多调参函数自带交叉验证,甚至是必选的参数,你如果想要不交叉反而实现起来会麻烦很多
# 所以这里我们还是只划分一次数据集
from sklearn.model_selection import train_test_split
X = data.drop(['Credit Default'], axis=1) # 特征,axis=1表示按列删除
y = data['Credit Default'] # 标签
# 按照8:2划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 80%训练集,20%测试集
from sklearn.ensemble import RandomForestClassifier #随机森林分类器
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score # 用于评估分类器性能的指标
from sklearn.metrics import classification_report, confusion_matrix #用于生成分类报告和混淆矩阵
import warnings #用于忽略警告信息
warnings.filterwarnings("ignore") # 忽略所有警告信息
# --- 1. 默认参数的随机森林 ---
# 评估基准模型,这里确实不需要验证集
print("--- 1. 默认参数随机森林 (训练集 -> 测试集) ---")
import time # 这里介绍一个新的库,time库,主要用于时间相关的操作,因为调参需要很长时间,记录下会帮助后人知道大概的时长
start_time = time.time() # 记录开始时间
rf_model = RandomForestClassifier(random_state=42)
rf_model.fit(X_train, y_train) # 在训练集上训练
rf_pred = rf_model.predict(X_test) # 在测试集上预测
end_time = time.time() # 记录结束时间
print(f"训练与预测耗时: {end_time - start_time:.4f} 秒")
print("\n默认随机森林 在测试集上的分类报告:")
print(classification_report(y_test, rf_pred))
print("默认随机森林 在测试集上的混淆矩阵:")
print(confusion_matrix(y_test, rf_pred))
此时可以理解为什么shap.summary_plot中第一个参数是所有样本对预测类别的shap值了。
传入的 SHAP 值 (shap_values[:, :, 0]) 和特征数据 (X_test) 在维度上需要高度一致和对应。
- shap_values[:, :, 0] 的每一行代表的是 一个特定样本每个特征对于预测类别的贡献值(SHAP 值)。缺乏特征本身的值
- X_test 的每一行代表的也是同一个特定样本的特征值。
这二者组合后,就可以组合(特征数,特征值,shap值)构成shap图的基本元素
上面这些就是我对于shap图的理解,去年很多同学在这里经常和我说是借助ai没办法对这里debug,实际上是因为没有理解shap