多索引 DataFrame 的多面图

Faceted plots of a multi-indexed DataFrame

如何使用 pandas 和 seaborn 绘制每个渠道(inapp、电子邮件、推送)的三个时间序列,色调变化 'enabled'?请注意,这些列是多索引的。我希望这些图共享 y 轴并有一个共同的图例来指示 'enabled'.

的值
|---------|---------------|--------------|---------------|
| channel | inapp         | email        | push          |
| enabled | true  | false | false | true | false | true  |
|---------|-------|-------|-------|------|-------|-------|
| 0       | 0     | 80    | 28    | 0    | 5     | 0     |
| 1       | 2     | 80    | 28    | 3    | 5     | 233   |
| 2       | 4     | 80    | 28    | 7    | 5     | 587   |
| 3       | 5     | 80    | 28    | 12   | 5     | 882   |
| 4       | 7     | 86    | 28    | 16   | 5     | 1292  |
|---------|-------|-------|-------|------|-------|-------|

Seaborn 可能不是必需的。
这是构建您指定的数据框的代码:

import pandas as pd

enabled = [True, False]
channel =['inapp','email','push']
values = [0,2,4,5,7,80,80,80,80,86,28,28,28,28,28,
          0,3,7,12,16,5,5,5,5,5,0,233,587,882,1292]
values = np.array(values).reshape((5,6), order='F')

columns = pd.MultiIndex.from_product([channel,enabled], 
                                     names=("channel","enabled"))
df = pd.DataFrame(values, columns=columns)

channel inapp       email        push      
enabled True  False True  False True  False
0           0    80    28     0     5     0
1           2    80    28     3     5   233
2           4    80    28     7     5   587
3           5    80    28    12     5   882
4           7    86    28    16     5  1292  

假设您所指的时间序列由索引值 0-4 组成,并且如果可以使用 pyplot 创建子图,则以下代码将满足您的规范:

from matplotlib import pyplot as plt  

fig, ax = plt.subplots(1, 3, sharey=True)
for i, col in enumerate(channel):
    df.T.xs(col).T.plot(ax=ax[i], xticks=df.index, title=col)

诚然,换位有点费力。可能有 Pandas-fu 方法可以达到相同的效果,使用 groupby(),但我试了一下,找不到解决方案。希望这有帮助。

这是另一种方法,使用 Paul H 的 .stack() 方法(尽管我也无法用 FacetGrid 弄清楚):

import pandas as pd
from matplotlib import pyplot as plt

enabled = [True, False]
channel =['inapp','email','push']
values = [0,2,4,5,7,80,80,80,80,86,28,28,28,28,28,
          0,3,7,12,16,5,5,5,5,5,0,233,587,882,1292]
values = np.array(values).reshape((5,6), order='F')

columns = pd.MultiIndex.from_product([channel,enabled], names=("channel","enabled"))
df = pd.DataFrame(values, columns=columns)

fig, ax = plt.subplots(1,3,sharey=True)

for i, (key, group) in enumerate(df.stack(level='channel').reset_index(level=1).groupby('channel')):
    group.plot(label=key, title=key, ax=ax[i])

更新:
这是一个更紧凑的版本,使用 unstack()factorplot().
rename 线只是为了情节清晰,它可以被删除。

df = (df.unstack('enabled')
        .reset_index()
        .rename(columns={'level_2':'time',0:'value'})
)
sns.factorplot(data=df, x='time', y='value', hue='enabled', col='channel')