seaborn distplot / displot 具有多个分布

Posted

技术标签:

【中文标题】seaborn distplot / displot 具有多个分布【英文标题】:seaborn distplot / displot with multiple distributions 【发布时间】:2018-02-13 04:55:33 【问题描述】:

我正在使用 seaborn 绘制分布图。我想用不同的颜色在同一个图上绘制多个分布:

这是我开始分布图的方式:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()
iris = pd.DataFrame(data= np.c_[iris['data'], iris['target']],columns= iris['feature_names'] + ['target'])

   sepal length (cm)  sepal width (cm)  petal length (cm)  petal width (cm)  target
0                5.1               3.5                1.4               0.2     0.0
1                4.9               3.0                1.4               0.2     0.0
2                4.7               3.2                1.3               0.2     0.0
3                4.6               3.1                1.5               0.2     0.0
4                5.0               3.6                1.4               0.2     0.0

sns.distplot(iris[['sepal length (cm)']], hist=False, rug=True);

'target' 列包含 3 个值:0、1、2。

我想查看一个萼片长度分布图,其中target ==0target ==1target ==2,总共有 3 个图。

【问题讨论】:

来自seaborn v0.11.0,使用sns.displot查看更新的答案,它取代了sns.distplot 【参考方案1】:

重要的是按target012 的值对数据帧进行排序。

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
import seaborn as sns

iris = load_iris()
iris = pd.DataFrame(data=np.c_[iris['data'], iris['target']],
                    columns=iris['feature_names'] + ['target'])

# Sort the dataframe by target
target_0 = iris.loc[iris['target'] == 0]
target_1 = iris.loc[iris['target'] == 1]
target_2 = iris.loc[iris['target'] == 2]

sns.distplot(target_0[['sepal length (cm)']], hist=False, rug=True)
sns.distplot(target_1[['sepal length (cm)']], hist=False, rug=True)
sns.distplot(target_2[['sepal length (cm)']], hist=False, rug=True)

plt.show()

输出如下:

如果您不知道target 可能有多少个值,请在target 列中找到唯一值,然后对数据框进行切片并适当地添加到图中。

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
import seaborn as sns

iris = load_iris()
iris = pd.DataFrame(data=np.c_[iris['data'], iris['target']],
                    columns=iris['feature_names'] + ['target'])

unique_vals = iris['target'].unique()  # [0, 1, 2]

# Sort the dataframe by target
# Use a list comprehension to create list of sliced dataframes
targets = [iris.loc[iris['target'] == val] for val in unique_vals]

# Iterate through list and plot the sliced dataframe
for target in targets:
    sns.distplot(target[['sepal length (cm)']], hist=False, rug=True)

【讨论】:

这为我创建了单独的图(在 2021 年),也许它已经改变了【参考方案2】:

解决此类问题的一种更常见的方法是使用 melt 将数据重新转换为长格式,然后让 map 完成剩下的工作。

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
import seaborn as sns

iris = load_iris()
iris = pd.DataFrame(data=np.c_[iris['data'], iris['target']], 
                    columns=iris['feature_names'] + ['target'])

# recast into long format 
df = iris.melt(['target'], var_name='cols',  value_name='vals')

df.head()

   target               cols  vals
0     0.0  sepal length (cm)   5.1
1     0.0  sepal length (cm)   4.9
2     0.0  sepal length (cm)   4.7
3     0.0  sepal length (cm)   4.6
4     0.0  sepal length (cm)   5.0

您现在可以简单地通过创建 FacetGrid 并使用地图进行绘图:

g = sns.FacetGrid(df, col='cols', hue="target", palette="Set1")
g = (g.map(sns.distplot, "vals", hist=False, rug=True))

【讨论】:

【参考方案3】:

citynorman 在https://github.com/mwaskom/seaborn/issues/861 上使用FacetGrid 找到了一个更简单的解决方案:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()
iris = pd.DataFrame(data= np.c_[iris['data'], iris['target']],columns= iris['feature_names'] + ['target'])

g = sns.FacetGrid(iris, hue="target")
g = g.map(sns.distplot, "sepal length (cm)",  hist=False, rug=True)

【讨论】:

【参考方案4】:

一个更新更简单的选项:

sns.displot(data=iris, x='sepal length (cm)', hue='target', kind='kde')

【讨论】:

【参考方案5】:

任何尝试使用新的 0.11.0 版本构建相同绘图的人,Seaborn 已经或正在弃用 distplot 并将其替换为 displot。

所以新版本的代码应该是:

import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
import seaborn as sns

iris = load_iris()
iris = pd.DataFrame(data=np.c_[iris['data'], iris['target']],
                    columns=iris['feature_names'] + ['target'])

sns.displot(data=iris, x='sepal length (cm)', hue='target', kind='kde', fill=True, palette=sns.color_palette('bright')[:3], height=5, aspect=1.5)

编辑

正如 Raghav 在评论部分所问的那样,我们能否在不更改数据框本身的情况下更改图表中的标签。是的,我们绝对可以。因此,我们首先将绘图分配给一个名为 chart 的变量,然后执行以下操作:

chart = sns.displot(data=iris, x='sepal length (cm)', hue='target', kind='kde', fill=True, palette=sns.color_palette('bright')[:3], height=5, aspect=1.5)

## Changing title
new_title = 'This is a NEW title'
chart._legend.set_title(new_title)

# Replacing labels
new_labels = ['label 1', 'label 2', 'label 3']
for t, l in zip(chart._legend.texts, new_labels):
    t.set_text(l)

最终的图表如下所示:

希望这对 Raghav 有所帮助。

【讨论】:

有没有办法将图例的值从 0、1、2 更改为其他值,而无需更改数据框本身的名称 哦,这肯定是可能的,让我在答案中回答。 @RaghavArora 查看编辑后的答案,希望对您有所帮助。 太棒了,谢谢【参考方案6】:

如果有人希望获得 sns.distplot 的 facetgrid,则将其替换为图形级选项 sns.displot 和轴级函数 sns.histplot

这使得使用pandas.DataFrame.melt将数据从宽格式(如OP中所示)转换为长格式变得非常容易

import pandas as pd
import seaborn as sns

iris = sns.load_dataset('iris')

# convert the dataframe from wide to long form
iris_melt = iris.melt(id_vars='species')

iris_melt.head()

  species      variable  value
0  setosa  sepal_length    5.1
1  setosa  sepal_length    4.9
2  setosa  sepal_length    4.7
3  setosa  sepal_length    4.6
4  setosa  sepal_length    5.0

sns.displot(
    data=iris_melt, 
    x='value', 
    hue='species', 
    kind='kde', 
    fill=True,
    col='variable'
)

这里的图片很小,但是如果你右键点击图片并在新的标签页或窗口中打开它,你可以更好地看到细节。

【讨论】:

以上是关于seaborn distplot / displot 具有多个分布的主要内容,如果未能解决你的问题,请参考以下文章

如何规范seaborn distplot?

seaborn distplot / displot 具有多个分布

无法在 seaborn distplot 中显示图例

在 seaborn displot/histplot 函数中绘制高斯拟合直方图(不是 distplot)

Python Seaborn:在 Facetgrid 中绘制多个 distplot

seaborn distplot中的y轴是啥?