分享

机器学习中最酷的9幅图

 汉无为 2023-09-18

在数据科学领域,数据可视化作为一个核心工具,为我们提供了深入了解、探索和解释复杂数据集的能力。这不仅帮助我们清晰地呈现数据的特点,而且还允许非专家用户快速理解数据的关键趋势和模式。本文将介绍一系列精选的数据可视化技巧,这些技巧在实践中都被证明是非常有价值的。从KS图到小提琴图,每一种都有其独特的应用场景和优势。

KS 图

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats

# Generate random data and a normal distribution for demonstration purposes
np.random.seed(0)
data = np.random.normal(011000)
theoretical = np.sort(np.random.normal(011000))

# Compute KS statistic
ks_statistic, p_value = stats.ks_2samp(data, theoretical)

# Plot KS Plot
plt.figure(figsize=(106))
plt.plot(np.sort(data), np.linspace(01, len(data), endpoint=False), label='Data CDF')
plt.plot(theoretical, np.linspace(01, len(theoretical), endpoint=False), label='Theoretical CDF', linestyle='--')
plt.title(f'KS Plot (KS Statistic = {ks_statistic:.2f})')
plt.legend()
plt.xlabel('Value')
plt.ylabel('CDF')
plt.grid(True)
plt.show()

图片

这是一个KS图,它表示了数据的累积分布函数(CDF)与理论正态分布的CDF。在这个图中:

蓝色实线代表我们的数据CDF。黄色虚线代表理论的正态分布CDF。KS统计量表示这两个分布之间的最大差异。在这个例子中,KS统计量约为0.03,表示两个CDF之间的最大差异是0.03。

这种图形在检验数据是否符合某种理论分布时非常有用,如正态分布。

SHAP

由于SHAP图需要一个预训练的模型和特定的数据,我会简化这个过程并使用一个标准数据集和XGBoost模型进行演示。

图片

import xgboost
import shap

# train an XGBoost model
X, y = shap.datasets.boston()
model = xgboost.XGBRegressor().fit(X, y)

# explain the model's predictions using SHAP
# (same syntax works for LightGBM, CatBoost, scikit-learn, transformers, Spark, etc.)
explainer = shap.Explainer(model)
shap_values = explainer(X)

# visualize the first prediction's explanation
shap.plots.waterfall(shap_values[0])

图片

上述解释展示了每个特征如何推动模型的输出从基值(我们传递的训练数据集上的平均模型输出)到模型输出。推动预测更高的特征显示为红色,推动预测更低的特征显示为蓝色。

图片

如果我们取很多像上面那样的力量图解释,将它们旋转90度,然后水平堆叠,我们可以看到整个数据集的解释

图片

# 可视化所有的训练集预测
shap.plots.force(shap_values)

为了理解单一特征如何影响模型的输出,我们可以绘制该特征的SHAP值与数据集中所有示例的特征值。由于SHAP值代表特征对模型输出变化的责任,下面的图表示随着RM(一个地区的房屋平均房间数)的变化,预测的房价发生的变化。RM的单一值的垂直分散表示与其他特征的交互效应。为了帮助揭示这些交互作用,我们可以用另一个特征进行着色。如果我们将整个解释张量传递给颜色参数,散点图将选择最佳的颜色特征。在这种情况下,它选择了RAD(到放射状高速公路的可达性指数),因为这突出了对于具有高RAD值的地区,房屋的平均房间数对房价的影响较小。

# 创建一个依赖散点图,显示整个数据集中单一特征的效果
shap.plots.scatter(shap_values[:,'RM'], color=shap_values)

图片

为了获得哪些特征对模型最重要的概览,我们可以绘制每个样本的每个特征的SHAP值。下面的图按照所有样本的SHAP值大小对特征进行排序,并使用SHAP值显示每个特征对模型输出的影响的分布。颜色代表特征值(红色高,蓝色低)。这揭示了例如高LSTAT(%较低的人口状态)降低了预测的房价。

图片

# 总结所有特征的影响
shap.plots.beeswarm(shap_values)

Q-Q图

# Generate QQ Plot using the random data for KS plot
plt.figure(figsize=(106))
stats.probplot(np.random.normal(011000), dist='norm', plot=plt)
plt.title('QQ Plot for Randomly Generated Normal Data')
plt.grid(True)
plt.show()

图片

这是一个QQ图,用于比较随机生成的正态分布数据与理论正态分布。在这个图中:

X轴表示理论正态分布的分位数。Y轴表示观察到的数据的分位数。如果数据完全遵循正态分布,那么点会紧密地围绕红色的参考线。从这个图中我们可以看到,数据点大致围绕参考线,这意味着我们的随机数据与正态分布非常接近。

累计方差图

from sklearn.decomposition import PCA

# Use PCA on the Boston dataset
pca = PCA()
X_pca = pca.fit_transform(X)

# Calculate cumulative explained variance
cumulative_variance = np.cumsum(pca.explained_variance_ratio_)

# Plot Cumulative Explained Variance Plot
plt.figure(figsize=(106))
plt.plot(range(1, len(cumulative_variance)+1), cumulative_variance, marker='o', linestyle='--')
plt.title('Cumulative Explained Variance Plot')
plt.xlabel('Number of Components')
plt.ylabel('Cumulative Explained Variance')
plt.grid(True)
plt.show()

图片

这是一个累积解释方差图,它展示了当我们使用主成分分析(PCA)进行降维时,每个主成分解释的方差的累积总和。

在图中:

X轴表示主成分的数量。Y轴表示对应数量的主成分所解释的累积方差的比例。例如,前5个主成分大致解释了近80%的方差。这意味着如果我们只使用前5个主成分来代表数据,我们将能够保留原始数据的大约80%的信息。

这种图形在决定PCA中要保留的主成分数量时非常有用,因为它可以帮助我们平衡降维与保留信息之间的权衡。

Gini不纯度 vs 熵

Gini不纯度 vs. 摘的图通常用于比较决策树分割的不纯度或混乱度。这两种度量方法都可以用 作决策树算法中的分裂标准。在不同的情境下,一个方法可能比另一个方法更优。

Gini不纯度:当一个节点是纯净的 (即,它只包含一个类的样本) 时,Gini不纯度为 0 。其最 大值取决于类的数量,但对于二分类问题,最大值为 0.5 。

桷:当一个节点是纯净的时,摘为 0 。与Gini不纯度一样,其最大值取决于头的数量。对于二 分夹问题,最大值为 1 。

为了可视化这两个度量方法,我们可以为给定的概率值计算Gini不纯度和摘,并将它们绘制在 同一张图上。这将帮助我们理解两者在不同概率值下的行为。让我们来彸制这个图。

# Calculate Gini Impurity and Entropy for a range of probability values
probabilities = np.linspace(01100)
gini = [1 - p**2 - (1-p)**2 for p in probabilities]
entropy = [-p*np.log2(p) - (1-p)*np.log2(1-p) if p != 0 and p != 1 else 0 for p in probabilities]

# Plot Gini vs Entropy
plt.figure(figsize=(106))
plt.plot(probabilities, gini, label='Gini Impurity', color='blue')
plt.plot(probabilities, entropy, label='Entropy', color='red', linestyle='--')
plt.title('Gini Impurity vs. Entropy')
plt.xlabel('Probability')
plt.ylabel('Impurity/Entropy Value')
plt.legend()
plt.grid(True)
plt.show()

图片

这是一个Gini不纯度 vs. 熵的图。在此图中:

X轴表示某一类的概率值。蓝色实线表示Gini不纯度。红色虚线表示熵。从图中可以看出:

当概率为0或1时(也就是说,节点是纯净的),Gini不纯度和熵都为0。对于二分类问题,当概率为0.5时(即,两个类的样本数量相等),Gini不纯度和熵都达到最大值。这两种度量方法都用于度量决策树节点的不纯度或混乱度。选择哪一个作为分裂标准取决于具体的应用和数据。

偏差-方差权衡图

偏差-方差权衡是监督学习中的一个核心概念,它解释了模型的总误差是如何由三个不同的误差类型组成的:

偏差(Bias):描述了模型预测的平均值与真实值之间的差异。高偏差意味着模型可能欠拟合数据。方差(Variance):描述了模型预测对于不同训练集的变化程度。高方差意味着模型可能过拟合数据。不可减少的误差:描述了即使在理想条件下,由于数据中的噪声导致的误差。

在实际应用中,我们通常会看到一个权衡关系:随着模型复杂度的增加,偏差会减少,但方差会增加,反之亦然。因此,我们的目标是找到一个平衡点,使得总误差最小化。

为了直观地展示这个权衡关系,我会绘制一个理论图,显示偏差、方差和总误差随模型复杂度的变化情况。

# Simulating the Bias-Variance Tradeoff

# Model complexity range (for the sake of this example)
complexity = np.linspace(0, 1, 200)

# Simulated bias and variance values (just for visualization)
bias_squared = (1 - complexity)**2.5
variance = complexity**2.5

# Total error is the sum of bias^2, variance, and some irreducible error
total_error = bias_squared + variance + 0.2

# Plotting the Bias-Variance tradeoff
plt.figure(figsize=(10, 6))
plt.plot(complexity, bias_squared, label='Bias^2', color='blue')
plt.plot(complexity, variance, label='Variance', color='red')
plt.plot(complexity, total_error, label='Total Error', color='green')
plt.xlabel('Model Complexity')
plt.ylabel('Error')
plt.title('Bias-Variance Tradeoff')
plt.legend()
plt.grid(True)
plt.show()

这是模拟的偏差-方差权衡图。

图片

在此图中:

X轴表示模型的复杂度。随着模型复杂度的增加,我们期望偏差降低但方差增加。蓝色曲线表示偏差的平方。可以看到,随着模型复杂度的增加,偏差的平方降低。红色曲线表示方差。随着模型复杂度的增加,方差增加。绿色曲线表示总误差,它是偏差的平方、方差和不可避免的误差之和。可以看到,总误差在某个模型复杂度点达到最小值。这是我们希望找到的理想的模型复杂度。通过这种可视化,我们可以更好地理解如何选择合适的模型复杂度,以平衡偏差和方差并最小化总误差。

ROC曲线

ROC曲线 (Receiver Operating Characteristic Curve)是用于评估分类模型性能的图。它显示了真正例率 (True Positive Rate, TPR) 和假正例率 (False Positive Rate, FPR) 之间的权衡关系,随着分类阈值的变化。

from sklearn.datasets import load_iris
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from sklearn.metrics import roc_curve, auc

# Load iris dataset
iris = load_iris()
X_iris = iris.data
y_iris = iris.target

# Binarize the output labels for multi-class ROC curve
y_iris_bin = label_binarize(y_iris, classes=[012])
n_classes = y_iris_bin.shape[1]

# Split the data
X_train_iris, X_test_iris, y_train_iris, y_test_iris = train_test_split(X_iris, y_iris_bin, test_size=0.5, random_state=42)

# Train a One-vs-Rest logistic regression model
clf_iris = OneVsRestClassifier(LogisticRegression(max_iter=10000))
y_score_iris = clf_iris.fit(X_train_iris, y_train_iris).decision_function(X_test_iris)

# Compute ROC curve for each class
fpr_iris = dict()
tpr_iris = dict()
roc_auc_iris = dict()
for i in range(n_classes):
    fpr_iris[i], tpr_iris[i], _ = roc_curve(y_test_iris[:, i], y_score_iris[:, i])
    roc_auc_iris[i] = auc(fpr_iris[i], tpr_iris[i])

# Plot the ROC curve for each class
plt.figure(figsize=(106))
colors = ['blue''red''green']
for i, color in zip(range(n_classes), colors):
    plt.plot(fpr_iris[i], tpr_iris[i], color=color, label=f'ROC curve for class {i} (area = {roc_auc_iris[i]:.2f})')
plt.plot([01], [01], 'k--')
plt.xlim([0.01.0])
plt.ylim([0.01.05])
plt.xlabel('False Positive Rate (FPR)')
plt.ylabel('True Positive Rate (TPR)')
plt.title('Receiver Operating Characteristic (ROC) Curve for Iris Dataset')
plt.legend(loc='lower right')
plt.grid(True)
plt.show()

这是在iris数据集上训练的多类逻辑回归模型的ROC曲线。

图片

在此图中:

X轴表示假正例率 (False Positive Rate, FPR)。Y轴表示真正例率 (True Positive Rate, TPR)。三种颜色(蓝色、红色和绿色)代表iris数据集的三个类别:setosa、versicolor和virginica。黑色虚线表示完全随机分类器的表现。每条曲线下的面积(AUC)表示模型对应类别的性能,值越接近1,表示模型的性能越好。

精确率-召回率曲线

from sklearn.metrics import precision_recall_curve, average_precision_score

# Compute Precision-Recall curve for each class
precision_iris = dict()
recall_iris = dict()
average_precision_iris = dict()

for i in range(n_classes):
    precision_iris[i], recall_iris[i], _ = precision_recall_curve(y_test_iris[:, i], y_score_iris[:, i])
    average_precision_iris[i] = average_precision_score(y_test_iris[:, i], y_score_iris[:, i])

# Plot the Precision-Recall curve for each class
plt.figure(figsize=(106))
colors = ['blue''red''green']
for i, color in zip(range(n_classes), colors):
    plt.plot(recall_iris[i], precision_iris[i], color=color,
             label=f'Precision-Recall curve for class {i} (average precision = {average_precision_iris[i]:.2f})')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.ylim([0.01.05])
plt.xlim([0.01.0])
plt.title('Precision-Recall Curve for Iris Dataset')
plt.legend(loc='upper right')
plt.grid(True)
plt.show()

这是在iris数据集上训练的多类逻辑回归模型的精确率-召回率曲线。

图片

在此图中:

X轴表示召回率 (Recall)。Y轴表示精确率 (Precision)。三种颜色(蓝色、红色和绿色)代表iris数据集的三个类别:setosa、versicolor和virginica。每条曲线的平均精确率(average precision)表示模型对应类别的性能,值越接近1,表示模型的性能越好。与ROC曲线不同,精确率-召回率曲线特别适合处理类别不平衡的数据集。这是因为它专注于正类的预测,而不是整体的表现。

Elbow Curve

from sklearn.cluster import KMeans

# Compute the sum of squared distances for different number of clusters
wcss = []  # within-cluster sum of squares
n_clusters_range = range(111)  # considering from 1 to 10 clusters

for i in n_clusters_range:
    kmeans = KMeans(n_clusters=i, random_state=42)
    kmeans.fit(X_iris)
    wcss.append(kmeans.inertia_)

# Plot the Elbow curve
plt.figure(figsize=(106))
plt.plot(n_clusters_range, wcss, marker='o')
plt.title('Elbow Curve for KMeans Clustering on Iris Dataset')
plt.xlabel('Number of clusters')
plt.ylabel('Within-Cluster Sum of Squares (WCSS)')
plt.grid(True)
plt.show()

这是iris数据集上的Elbow曲线。

图片

在此图中:

X轴表示考虑的簇数(从1到10)。Y轴表示每个簇数对应的within-cluster sum of squares (WCSS)。WCSS是簇内所有点到簇中心的平方距离之和。“肘部”是曲线的一个关键点,表示增加更多的簇不会显著降低WCSS。在这个点,我们可以选择簇的最佳数量。从图中可以看出,肘部大约在2或3的位置,这意味着选择2或3个簇可能是最佳选择。

其他

以下是一些常见和有用的数据可视化技巧和方法:

直方图 (Histograms): 用于显示数值变量的分布。可以帮助识别数据中的模式,如正态性、偏斜等。

箱型图 (Box Plots): 用于显示数据的五数概括:最小值、第一四分位数、中位数、第三四分位数和最大值。可以帮助识别离群值。

散点图 (Scatter Plots): 用于显示两个数值变量之间的关系。可以帮助识别相关性、数据的集群等。

堆积柱状图和堆积面积图: 用于显示多个类别或时间序列数据的部分到整体的关系。

热图 (Heatmaps): 用于显示两个类别变量之间关系的强度或数值变量的密度。

雷达/蜘蛛图 (Radar/Spider Charts): 用于显示多个变量的一个实体或类别的值。常用于性能分析或比较多个实体。

地图可视化: 用于显示地理数据,如国家、城市或地理坐标上的数据点。

时间序列图: 用于显示随时间变化的数据。

小提琴图 (Violin Plots): 结合了箱型图和密度图的特点,显示数据的分布和概率密度。

配对图 (Pair Plots): 用于显示多个数值变量之间的所有可能的散点图。

树状图 (Tree Maps): 用于显示层次数据或部分到整体的关系。

圆环图 (Donut Charts): 一个饼图的变体,用于显示类别数据的比例。

词云 (Word Clouds): 用于显示文本数据中词的频率。最常见的词以较大的字体显示。

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import pandas as pd

# Generating some random data for visualization
np.random.seed(42)
data = np.random.randn(1000)
data2 = np.random.randn(1000) + 5
time_series_data = np.cumsum(np.random.randn(1000))
categories = np.random.choice(['A''B''C'], size=1000)
categories_2 = np.random.choice(['D''E''F'], size=1000)

df = pd.DataFrame({
    'data': data,
    'data2': data2,
    'time': np.arange(1000),
    'categories': categories,
    'categories_2': categories_2
})

# Creating subplots
fig, axs = plt.subplots(33, figsize=(1515))

# Plotting
# Histogram
axs[00].hist(data, bins=30, color='skyblue', edgecolor='black')
axs[00].set_title('直方图 (Histogram)')

# Boxplot
sns.boxplot(data=[data, data2], ax=axs[01])
axs[01].set_title('箱型图 (Box Plot)')

# Scatter Plot
axs[02].scatter(data, data2, alpha=0.6)
axs[02].set_title('散点图 (Scatter Plot)')

# Stacked bar plot
df_group = df.groupby('categories')['data'].mean()
df_group.plot(kind='bar', stacked=True, ax=axs[10])
axs[10].set_title('堆积柱状图')

# Heatmap
sns.heatmap(df.corr(), annot=True, cmap='coolwarm', ax=axs[11])
axs[11].set_title('热图 (Heatmap)')

# Radar/Spider Chart
from math import pi
categories_list = list(df_group.index)
N = len(categories_list)
values = df_group.values.flatten().tolist()
values += values[:1]
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
axs[12].plot(angles, values, linewidth=2, linestyle='solid')
axs[12].fill(angles, values, alpha=0.4)
axs[12].set_xticks(angles[:-1])
axs[12].set_xticklabels(categories_list)
axs[12].set_title('雷达/蜘蛛图 (Radar/Spider Chart)')

# Time Series
axs[20].plot(time_series_data)
axs[20].set_title('时间序列图')

# Violin Plot
sns.violinplot(x='categories', y='data', data=df, ax=axs[21])
axs[21].set_title('小提琴图 (Violin Plot)')

# Removing the last empty subplot
fig.delaxes(axs[22])

plt.tight_layout()
plt.show()

图片

有效的数据可视化是数据科学的基石。它不仅为我们提供了一种直观的方式来理解和解释数据,而且还为我们的分析增添了额外的价值。正如我们在上述各种图形中所看到的,选择合适的可视化方法可以帮助我们更好地解释和传达我们的发现。

参考资料:
[1] Daily Dose of Data Science. (n.d.). 250+ Python & Data Science Posts. DailyDoseofDS.com.
[2] https://github.com/shap/shap


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多