利用plot.density的秩相关可视化(小白自学版)

上图为可视化结果,供判断是否是自己想要的可视化方向,对适用情况另作如下说明:

本文章题干来自于2024年APCAM亚太建模大赛Q1【可视化】任务;

该可视化方式只适用于①样本量较大的②二维变量且③其中一维为等级序数,另一维为服从位置分布的随机变量(本题为概率)

绘图应用的思路为:完整的data->确定某一个变量的有什么级别(利用集合)->分别索引每一个级别对应的洪水概率->生成该级别洪水概率的密度函数->把不同级别的密度函数放在一个子图里->返回完整的子图

正文开始👇

Part1:数据及题目说明

题目要求对“季风强度”、“地形排水”、“河流管理”等21个变量和洪水概率之间的相关性进行分析,通过可视化基本判断某一个变量和洪水之间的相关关系。因此,需要我们将所有的变量和洪水概率之间逐一进行可视化,观察不同级别的洪水概率是否有较为显著的差异

大赛给出了如下csv格式数据,其中前20列均为等级序数“洪水概率”服从未知分布

Part2:问题及解决思路

注释:正常可以通过绘制散点图或者使用copula函数分别计算20个变量和洪水之间的相关性,但是前者可视化后的结果不美观也不明晰,没有很好地反映出不同水文等级(例如季风强度为1、2、3……)下洪水概率密度分布的不同;后者则是因为我debug失败所以没捅咕出来哈哈。

首先,我们先确定一张图里只绘制一个变量和洪水之间的关系,绘制一张图的过程生成一个函数。当然,为了便于最后放在一张图中,这里的函数最后返回的最好是子图而非单独的图像;

其中,为了能够较为清晰的看到不同等级之间洪水概率密度的差别,我们希望将每一个级别的洪水发生的概率密度分别绘制,并将所有等级的放在一张子图里便于比较差异;

最后,如果想要绘制多个子图就可以利用for循环对每一个变量进行相同的绘制过程,并绘制在一张图上

总结来说,从数据到图的整体思路就是:完整的data->确定某一个变量的有什么级别(利用集合)->分别索引每一个级别对应的洪水概率->生成该级别洪水概率的密度函数->放在一个子图里->返回完整的子图

Part3:代码实现

这里方便大家复制粘贴就直接放完整的代码了,解释会用#注释

准备工作:

import numpy as np
import pandas as pd
from pandas import DataFrame, Series
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

test = pd.read_csv('test.csv',encoding='gbk')
train = pd.read_csv('train.csv',encoding='gbk')
train.head(3)

如果只对“季风强度”和洪水概率进行可视化分析,不需要定义函数的形式,应用到相同的情况当中只需要修改变量名即可: 

set_jifeng = set(train['季风强度'])
list_jifeng = sorted(set_jifeng)  # 确保顺序一致

plt.figure(figsize=(10, 6))
colors = ["yellow", "red"]
cmap = LinearSegmentedColormap.from_list("yellow_red_gradient", colors, N=len(list_jifeng))
for idx, jifeng in enumerate(list_jifeng):
    data_use = train[train['季风强度'] == jifeng]
    data_use = data_use[['洪水概率']]
    color = cmap(idx / len(list_jifeng))
    data_use['洪水概率'].plot.density(label=f'季风强度 {jifeng}',color=color)

plt.rcParams['font.family'] = 'MingLiU'
plt.legend()
plt.title('洪水概率的密度图')
plt.xlabel('洪水概率')
plt.ylabel('密度')

plt.show()

当然,如果想要遍历所有的变量,将“季风强度”替换为for循环遍历每一个变量即可。

如果对文件当中的所有变量分别和洪水概率进行可视化分析、每一个变量生成一个子图并最后绘制到一张图上的话,则总体分为两步:第一步定义绘图的函数(这里的函数相较于绘制单独的图像略有修改,因为绘制的是子图),第二步识别变量并进行循环:

import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import pandas as pd  # 确保你有导入必要的库

# 假设 train 已经定义好并且包含了需要的列
# 例如: train = pd.read_csv('your_data.csv')

# 生成颜色映射
COLORS = ["yellow", "red"]
CMAP = LinearSegmentedColormap.from_list("yellow_red_gradient", COLORS)

def draw(ax, name, colors=COLORS, cmap=CMAP):
    set_jifeng = set(train[name])
    list_jifeng = sorted(set_jifeng)  # 确保顺序一致

    for idx, jifeng in enumerate(list_jifeng):
        data_use = train[train[name] == jifeng]
        if data_use.empty:
            continue
        data_use = data_use[['洪水概率']]
        color = cmap(idx / len(list_jifeng))
        data_use['洪水概率'].plot.density(ax=ax, label=f'{name} {jifeng}', color=color)
    
    ax.set_title(name)
    ax.set_xlabel('洪水概率')
    ax.set_ylabel('密度')
    ax.legend()

# 创建子图
num_plots = len(train.columns) - 1  # 不包括 'id'
num_rows = (num_plots + 2) // 3  # 每行最多三个子图
fig, axes = plt.subplots(num_rows, 3, figsize=(15, 5 * num_rows))
axes = axes.flatten()  # 将二维数组展平为一维数组,方便索引



# 绘制每个特征的密度图
for i, col in enumerate(train.columns):
    if col == 'id':  # 忽略 'id' 列
        data_use['洪水概率'].plot.density()
        continue
    draw(axes[i], col)

# 处理没有用到的子图
for j in range(i + 1, len(axes)):
    fig.delaxes(axes[j])

plt.tight_layout()
plt.show()

Part4:说明

由于是自己搭建的框架,所用用到的函数都非常基础,最后也是通过循环来完成的,计算速度非常慢,如有改进方式或者任何问题欢迎提出!

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值