【问题标题】:How to combine multiple data frames into a single violinplot and add a swarmplot如何将多个数据帧组合成一个 violinplot 并添加一个 swarmplot
【发布时间】:2023-02-17 08:00:48
【问题描述】:

我有两个数据框,具有不同的形状。我想将小提琴图的两个数据框值绘制成彼此相邻而不是重叠。

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

data1 = {
    'DT' : np.random.normal(-1, 1, 100),
    'RF' : np.random.normal(-1, 1, 110),
    'KNN' : np.random.normal(-1, 1, 120)
}
maxsize = max([a.size for a in data1.values()])
data_pad1 = {k:np.pad(v, pad_width=(0,maxsize-v.size,), mode='constant', constant_values=np.nan) for k,v in data1.items()}
df1 = pd.DataFrame(data_pad1) # data frame

data2 = {
    'DT' : np.random.normal(-1, 1, 50),
    'RF' : np.random.normal(-1, 1, 60),
    'KNN' : np.random.normal(-1, 1, 80)
}

maxsize = max([a.size for a in data2.values()])
data_pad2 = {k:np.pad(v, pad_width=(0,maxsize-v.size,), mode='constant', constant_values=np.nan) for k,v in data2.items()}
df2 = pd.DataFrame(data_pad2) # dataframe2 

#plotting 
fig, ax = plt.subplots(figsize=(15, 6))
ax = sns.violinplot(data=df1, color="blue")
ax = sns.violinplot(data=df2, color="red")
plt.show()

这是我的输出图像。

但我想让每个蓝色和红色的小提琴图彼此相邻而不是重叠。我还想通过群图显示数据点。

【问题讨论】:

    标签: python matplotlib seaborn violin-plot


    【解决方案1】:

    Seaborn 最容易处理“长格式”数据。您可以直接从给定的字典创建这样的数据框,而无需填充 NaN。

    import matplotlib.pyplot as plt
    import seaborn as sns
    import pandas as pd
    import numpy as np
    
    data1 = {'DT': np.random.normal(-1, 1, 100),
             'RF': np.random.normal(-1, 1, 110),
             'KNN': np.random.normal(-1, 1, 120)}
    data2 = {'DT': np.random.normal(-1, 1, 50),
             'RF': np.random.normal(-1, 1, 60),
             'KNN': np.random.normal(-1, 1, 80)}
    
    df = pd.DataFrame([[label, val, 'data1'] for label, values in data1.items() for val in values]
                      + [[label, val, 'data2'] for label, values in data2.items() for val in values],
                      columns=['label', 'value', 'source'])
    
    fig, ax = plt.subplots(figsize=(15, 6))
    sns.violinplot(data=df, x='label', y='value', hue='source', palette=['cornflowerblue', 'indianred'], ax=ax)
    ax.set(xlabel='', ylabel='')  # remove labels set by seaborn
    sns.despine()
    plt.show()
    

    PS:要将小提琴情节与群体情节结合起来,您还需要hue=dodge=True,例如sns.swarmplot(data=df, x='label', y='value', hue='source', palette=['black', 'black'], dodge=True, ax=ax)。您可能还想删除 violinplot 的现有 inner

    sns.violinplot(data=df, x='label', y='value', hue='source', palette=['cornflowerblue', 'indianred'], saturation=1, inner=None, ax=ax)
    sns.swarmplot(data=df, x='label', y='value', hue='source', palette=['black', 'black'], dodge=True, legend=False, ax=ax)
    

    或者,您可以创建一个拆分小提琴图:

    sns.violinplot(data=df, x='label', y='value', hue='source', palette=['lightgrey', 'lightyellow'], saturation=0.5,
                   inner=None, split=True, ax=ax)
    sns.swarmplot(data=df, x='label', y='value', hue='source', palette=['cornflowerblue', 'indianred'], ax=ax)
    

    【讨论】:

    • 如果您想要更鲜艳的颜色,可以使用sns.violinplot(..., saturation=1)
    • 谢谢,如果尝试在小提琴图下方显示数据点,则无法正常工作。 sns.swarmplot(数据=df,颜色=“黑色”,ax=ax)。你也可以显示数据点吗?
    • 写作“它不工作”信息量不大。如果你想要用“色调”分隔的点,你需要hue=dodge=True例如sns.swarmplot(data=df, x='label', y='value', hue='source', palette=['black', 'black'], dodge=True, ax=ax)。您可能还想删除 violinplot 的现有 inner,例如 sns.violinplot(data=df, ..., inner=None)。 (inner 的其他选项是 “box”, “quartile”, “point”, “stick”。)
    【解决方案2】:

    我建议重新标记每个数据框中的列以反映数据框编号,例如:

    data2 = {
        'DT2' : np.random.normal(-1, 1, 50),
        'RF2' : np.random.normal(-1, 1, 60),
        'KNN2' : np.random.normal(-1, 1, 80)
    }
    

    然后你可以:

    1. 连接两个数据帧:

      df = pd.concat([df1, df2], 轴=1)

    2. 定义你自己的调色板:

      my_palette = {“DT1”:“蓝色”,“DT2”:“红色”,“KNN1”:“蓝色”,“KNN2”:“红色”,“RF1”:“蓝色”,“RF2”:“红色” }

    3. 然后使用 order 参数强制绘图顺序:

      sns.violinplot(data=df, order = ['DT1', 'DT2', 'KNN1', 'KNN2', 'RF1', 'RF2'], palette=my_palette)

      这会产生以下结果:

      编辑:

      您可以手动设置标签以替换每个标签对(例如DT1、DT2) 带有单个标签 (例如DT):

      locs, labels = plt.xticks()  # Get the current locations and labels.
      plt.xticks(np.arange(0.5, 4.5, step=2))  # Set label locations.
      plt.xticks([0.5, 2.5, 4.5], ['DT', 'KNN', 'RFF'])  # Set text labels.
      

      这产生:

    【讨论】:

    • 我尝试了这个想法。是否有可能获得红色和蓝色小提琴之间的 x-tick 值?
    • 我刚刚编辑了我的答案,并提出了如何改进标签的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多