seaborn distplot / 具有多个分布的 displot

seaborn distplot / displot with multiple distributions

我正在使用 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 个图。

重要的是按 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)

解决此类问题的更常见方法是使用 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))

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

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)

更新更简单的选项:

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

任何试图使用新的 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 有所帮助。

如果有人想要获得 sns.distplot 的 facetgrid,它已被替换为图形级选项 sns.displot, and an axes-level function, sns.histplot

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

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'
)

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