前言

各位小伙伴,Day 6 的学习让我兴奋不已!我们终于从幕后的数据“清洗工”,转型到了台前的“数据翻译官”。今天,我们学习了如何使用 Python 中最强大的两个可视化库——matplotlibseaborn——让冰冷的数据以图形的方式,生动地向我们讲述它背后的故事。

数据可视化不仅仅是为了让报告更好看,它的核心价值在于:通过图形直观地发现数据中的模式、趋势、异常值和关系。很多时候,一张图表所能揭示的信息,远比几页密密麻麻的数字表格要多得多。

今天,我将带大家回顾可视化的基本流程,并完成一份有趣的“看图说话”作业,尝试从图表中挖掘出有价值的业务洞察。


一、知识点总结:我的第一张数据图表

1. 可视化双雄:Matplotlib & Seaborn

  • matplotlib: 是 Python 可视化的“奠基者”,功能强大,可定制性极高。可以把它看作是画图的“基础工具箱”,提供了画布、画笔等基本元素。
  • seaborn: 基于 matplotlib 构建的“高级工具箱”,提供了更美观的默认样式和更简洁的绘图函数,尤其擅长统计类图表的绘制。

我们的策略通常是:seaborn 进行快速、美观的统计绘图,用 matplotlib 进行细节调整和定制

2. 跨越第一个障碍:解决中文乱码

这是几乎每个新手都会遇到的问题!当你兴奋地打上中文标题时,却只看到一堆方框 □□□。原因是 matplotlib 默认字体不支持中文。
完美解决方案:在绘图代码前,加入以下两行“魔法咒语”。

import matplotlib.pyplot as plt

# 设置全局字体为支持中文的字体 (例如 'SimHei' 黑体)
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号'-'显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False

这段代码一劳永逸地解决了中文显示和负号显示的问题,是开启可视化之旅的必备配置!

3. 可视化三步曲

老师总结了三种核心的可视化分析角度,我将其理解为“从宏观到微观”的探索过程:

  1. 单特征分布可视化:这个特征自己长什么样?(高矮胖瘦?)

    • 连续变量 (如 Annual Income): 使用箱线图 (boxplot) 查看数据分布的四分位点和异常值;或使用直方图/核密度图 (histplot with kde=True) 查看数据的整体分布形状(是正态分布?还是偏态?)。
    • 离散变量 (如 Years in current job): 使用计数图/条形图 (countplot) 查看每个类别的数量多少。
  2. 特征与标签关系可视化:这个特征和我们的目标(是否违约 Credit Default)有什么关系?

    • 连续特征 vs. 标签:
      • 箱线图/小提琴图 (boxplot/violinplot),将不同标签(01)的数据分布并列比较。例如,比较违约者和非违约者的年收入分布。
      • 分组直方图 (histplot with hue=标签),在同一个直方图上用不同颜色展示不同标签下的数据分布。
    • 离散特征 vs. 标签:
      • 分组计数图 (countplot with hue=标签),查看在每个类别下,违约和不违约的人数分别是多少。
  3. 特征与特征关系可视化 (今天未深入,但也很重要):特征A和特征B之间有什么关系?(例如,收入和信贷历史年限是否相关?)通常使用散点图 (scatterplot)热力图 (heatmap)


二、今日作业:对其他特征进行可视化探索

今天的作业是,对其他特征进行可视化,并尝试解读出有意思的结论。我选择了两个代表性特征进行探索:

  • 连续特征: Credit Score (信用分数)
  • 离散特征: Purpose (贷款目的)

我的探索代码 (初学者逻辑版)

这个版本代码直截了当,一步一步地画图,符合初学者的思考路径。

# 导入所需库
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

# --- 准备工作 ---
# 1. 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 2. 读取数据
data = pd.read_csv(r'data.csv') # 请替换为你的文件路径

# --- 探索 1: 信用分数 (Credit Score) ---
print("正在绘制 'Credit Score' 相关图表...")

# 1.1 单特征可视化:看看信用分数本身的分布
plt.figure(figsize=(10, 6)) # 创建一个大一点的画布
sns.histplot(data['Credit Score'], kde=True, bins=50)
plt.title('信用分数分布直方图')
plt.xlabel('信用分数')
plt.ylabel('客户数量')
plt.show()

# 1.2 特征与标签关系:信用分数和是否违约有关吗?
plt.figure(figsize=(8, 6))
sns.boxplot(x='Credit Default', y='Credit Score', data=data)
plt.title('不同违约状态下的信用分数分布')
plt.xlabel('是否违约 (1=是, 0=否)')
plt.ylabel('信用分数')
plt.show()

# --- 探索 2: 贷款目的 (Purpose) ---
print("\n正在绘制 'Purpose' 相关图表...")

# 2.1 单特征可视化:大家贷款都是为了干嘛?
plt.figure(figsize=(10, 8))
# Pro Tip: 当类别名称很长时,将x和y对调,画水平条形图更美观!
sns.countplot(y='Purpose', data=data, order=data['Purpose'].value_counts().index)
plt.title('贷款目的分布')
plt.xlabel('申请数量')
plt.ylabel('贷款目的')
plt.show()

# 2.2 特征与标签关系:哪种贷款目的更容易导致违约?
plt.figure(figsize=(12, 8))
sns.countplot(y='Purpose', hue='Credit Default', data=data)
plt.title('不同贷款目的下的违约情况')
plt.xlabel('申请数量')
plt.ylabel('贷款目的')
plt.legend(title='是否违约', labels=['否', '是'])
plt.show()

探索结论与“看图说话”

  1. 关于 Credit Score (信用分数):

    • 单特征图发现:信用分数的分布非常奇怪,并不是一个平滑的正态分布。它在 750 分左右有一个巨大的峰值,而在 5000-6000 分之间也有一段“高原”。这暗示数据可能经过了某些处理,或者信用评分系统本身就有这样的分段特点。特别是高分段,可能代表另一类完全不同的客户群体。
    • 关系图发现: 从箱线图可以非常清晰地看到,违约客户 (Credit Default = 1) 的信用分数中位数远低于非违约客户 (Credit Default = 0)。这完全符合我们的直觉:信用分数越低的人,违约风险越高。这个特征对于预测模型来说,无疑是极其重要的。
  2. 关于 Purpose (贷款目的):

    • 单特征图发现:绝大多数人的贷款目的是 debt consolidation (债务整合),这说明市场上有大量客户希望通过一笔新贷款来偿还多笔旧债,以降低利率或简化还款。其他目的如 other, home improvements (房屋装修) 也占有一定比例。
    • 关系图发现:虽然债务整合的总人数最多,但我们更关心违约率。通过目测比较每个目的下代表违约的橙色条和代表正常的蓝色条的相对比例,我们可以初步发现:small business (小生意), business loan(商业贷款), renewable energy(可再生能源)这些目的的橙色条比例似乎更高。这暗示与商业经营相关的贷款,其违约风险可能显著高于个人消费类贷款(如买车、度假)。这为风险控制提供了非常有价值的方向!

完整注释与便捷写法版

这个版本将绘图逻辑封装成函数,代码复用性更高,结构更清晰。

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

def setup_plot_style():
    """设置图表的全局样式,包括中文支持。"""
    plt.rcParams['font.sans-serif'] = ['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    print("图表样式设置完毕,已支持中文显示。")

def plot_continuous_feature(df, feature, label=None):
    """
    绘制单个连续特征的分布图,以及它和标签的关系图。
    :param df: DataFrame
    :param feature: 要分析的连续特征列名
    :param label: 标签列名 (可选)
    """
    print(f"\n--- 分析连续特征: {feature} ---")
    
    # 创建一个 1x2 的子图布局
    fig, axes = plt.subplots(1, 2, figsize=(16, 6))
    
    # 左图:单特征分布
    sns.histplot(df[feature], kde=True, bins=50, ax=axes[0])
    axes[0].set_title(f'{feature} 的分布')
    axes[0].set_xlabel(feature)
    axes[0].set_ylabel('频数')
    
    # 右图:与标签的关系
    if label and label in df.columns:
        sns.boxplot(x=label, y=feature, data=df, ax=axes[1])
        axes[1].set_title(f'{feature}{label} 的关系')
        axes[1].set_xlabel(label)
        axes[1].set_ylabel(feature)
    else:
        axes[1].set_visible(False) # 如果没有标签,隐藏右图
        
    plt.tight_layout() # 自动调整布局
    plt.show()

def plot_discrete_feature(df, feature, label=None):
    """
    绘制单个离散特征的分布图,以及它和标签的关系图。
    :param df: DataFrame
    :param feature: 要分析的离散特征列名
    :param label: 标签列名 (可选)
    """
    print(f"\n--- 分析离散特征: {feature} ---")

    # 创建一个 2x1 的子图布局
    fig, axes = plt.subplots(2, 1, figsize=(12, 14))

    # 上图:单特征分布
    sns.countplot(y=feature, data=df, order=df[feature].value_counts().index, ax=axes[0])
    axes[0].set_title(f'{feature} 的分布')
    axes[0].set_xlabel('数量')
    axes[0].set_ylabel(feature)

    # 下图:与标签的关系
    if label and label in df.columns:
        sns.countplot(y=feature, hue=label, data=df, ax=axes[1])
        axes[1].set_title(f'{feature}{label} 的关系')
        axes[1].set_xlabel('数量')
        axes[1].set_ylabel(feature)
        axes[1].legend(title=label, labels=['非违约', '违约'])
    else:
        axes[1].set_visible(False) # 如果没有标签,隐藏下图

    plt.tight_layout() # 自动调整布局
    plt.show()

# --- 主程序执行 ---
if __name__ == '__main__':
    setup_plot_style()
    
    try:
        df = pd.read_csv(r'data.csv') # 请替换为你的文件路径
    except FileNotFoundError:
        print("错误:data.csv 文件未找到,请检查路径!")
        exit()
        
    # 对 'Credit Score' 进行可视化
    plot_continuous_feature(df, 'Credit Score', label='Credit Default')
    
    # 对 'Purpose' 进行可视化
    plot_discrete_feature(df, 'Purpose', label='Credit Default')

总结与反思

Day 6 的学习是成果满满的一天!我不仅学会了如何用代码画出漂亮的图表,更重要的是,我开始理解如何通过图表与数据对话

  1. 工具在手,天下我有matplotlibseaborn 是数据科学家的“眼睛”。掌握它们,就等于开启了上帝视角,能洞察数据背后的秘密。
  2. 可视化是思考的催化剂:绘图的过程,本身就是强迫自己去思考“我想看什么?”、“它们之间可能有什么关系?”的过程。它将抽象的数据分析问题,具体化为一个个清晰的图表。
  3. 结论比代码更重要:正如老师所说,很多时候,深刻的洞见并不需要复杂的 AI 模型,仅仅通过扎实的描述性统计和可视化就能得出。今天的分析就是一个很好的例子,我们已经能为银行的风控部门提出初步但有价值的建议了。

从今天起,我不再仅仅满足于让代码跑通,更要努力去理解代码运行结果背后的业务含义。这或许就是从“码农”到“数据分析师”的蜕变之路吧!


最后,再次感谢 @浙大疏锦行 老师的精彩课程,带领我们领略了数据可视化的魅力!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐