在使用 groupby 时遍历列以生成条形图
Iterate through columns to generate barplots while using groupby
这是我的数据框:
data = {'machine': ['machine_a', 'machine_a', 'machine a', 'machine a', 'machine a', 'machine a', 'machine_b', 'machine_b', 'machine_b', 'machine_b', 'machine_b', 'machine_b', 'machine_c', 'machine_c', 'machine_c', 'machine_c', 'machine_c', 'machine_c'], 'bin': ['(0, 200]', '(200, 400]', '(400, 600]', '(600, 800]', '(800, 1000]', '(1000, 1200]', '(0, 200]', '(200, 400]', '(400, 600]', '(600, 800]', '(800, 1000]', '(1000, 1200]', '(0, 200]', '(200, 400]', '(400, 600]', '(600, 800]', '(800, 1000]', '(1000, 1200]'], 'speed': [10, 0, 20, 0, 20, 10, 5, 0, 40, 10, 20, 10, 5, 25, 0, 10, 5, 10], 'Temp': [0, 0, 0, 20, 20, 0, 35, 0, 0, 20, 0, 70, 30, 0, 0, 5, 0, 25]}
df = pd.DataFrame(data)
machine bin speed Temp
0 machine_a (0, 200] 10 0
1 machine_a (200, 400] 0 0
2 machine a (400, 600] 20 0
3 machine a (600, 800] 0 20
4 machine a (800, 1000] 20 20
5 machine a (1000, 1200] 10 0
6 machine_b (0, 200] 5 35
7 machine_b (200, 400] 0 0
8 machine_b (400, 600] 40 0
9 machine_b (600, 800] 10 20
10 machine_b (800, 1000] 20 0
11 machine_b (1000, 1200] 10 70
12 machine_c (0, 200] 5 30
13 machine_c (200, 400] 25 0
14 machine_c (400, 600] 0 0
15 machine_c (600, 800] 10 5
16 machine_c (800, 1000] 5 0
17 machine_c (1000, 1200] 10 25
我想为列速度和温度创建不同的条形图,其中 x 轴是 bins 列。我想为每台不同的机器执行此操作。
到目前为止,我已经创建了一个 for 循环来遍历最后两列
import seaborn as sns
import matplotlib.pyplot as plt
for column in df.columns[2:]:
sns.set()
fig, ax = plt.subplots()
sns.set(style="ticks")
sns.barplot(x = df.bin, y=column, data=df)
sns.despine(offset=10, trim=True)
fig.set_size_inches(22,14)
这将创建 2 个条形图。 1 表示速度,1 表示温度。我该怎么做才能得到 6 个条形图(每台机器 2 个)?在这种情况下,基本上我该如何使用 groupby?
完整的综合数据
- 50 台机器,每台机器有 109 个 bin
import pandas as pd
import numpy as np
bins = [f'({n*200}, {(n+1)*200}]' for _ in range(50) for n in range(109)]
machines = [f'machine_{n}' for n in range(50) for _ in range(109)]
np.random.seed(365)
speed = np.random.randint(0, 40, size=len(machines))
temp = np.random.choice([0, 30, 70], size=len(machines))
df = pd.DataFrame({'machine': machines, 'bin': bins, 'speed': speed, 'Temp': temp})
df.head()
machine bin speed Temp
0 machine_0 (0, 200] 18 30
1 machine_0 (200, 400] 33 70
2 machine_0 (400, 600] 27 30
3 machine_0 (600, 800] 5 30
4 machine_0 (800, 1000] 34 30
df.tail()
machine bin speed Temp
5445 machine_49 (20800, 21000] 6 0
5446 machine_49 (21000, 21200] 20 30
5447 machine_49 (21200, 21400] 14 0
5448 machine_49 (21400, 21600] 38 30
5449 machine_49 (21600, 21800] 24 70
可以直接使用seaborn.catplot
。您只需要先融化 y 列:
import seaborn as sns
sns.catplot(data=df.melt(id_vars=['machine', 'bin']),
col='machine',
x='bin', y='value', hue='variable',
kind='bar'
)
输出:
或者将变量作为行:
import seaborn as sns
sns.catplot(data=df.melt(id_vars=['machine', 'bin']),
col='machine',
row='variable',
x='bin', y='value',
kind='bar',
color='k',
)
输出:
或者拆分变量:
import seaborn as sns
sns.catplot(data=df.melt(id_vars=['machine', 'bin']),
hue='machine',
x='bin', y='value', col='variable',
kind='bar'
)
这是一个使用 groupby
的版本:
df2 = df.melt(id_vars=['machine', 'bin'])
COLS = df2['machine'].nunique()
ROWS = df2['variable'].nunique()
fig, axes = plt.subplots(ncols=COLS,
nrows=ROWS,
)
i = 0
for group, d in df2.groupby(['machine', 'variable']):
ax = axes[i%ROWS][i//ROWS]
ax.bar(d['bin'], d['value'])
if not i//ROWS:
ax.set_ylabel(group[1])
if i%ROWS == ROWS-1:
ax.set_xlabel(group[0])
i+=1
输出:
- 鉴于评论中描述的现有数据和更新的合成数据集。
- 使用
seaborn.barplot
。 seaborn
是 matplotlib
的高级 API
import matplotlib.pyplot as plt
import seaborn as sns
# melt the dataframe into a long form and group by the machine
dfmg = df.melt(id_vars=['machine', 'bin']).groupby('machine')
选项 1
- 为每台机器创建一个单独的绘图,与机器名称一起保存
- 这节省了 50 个图,每台机器 1 个
for mach, data in dfmg:
plt.figure(figsize=(20, 5))
sns.barplot(data=data, x='bin', y='value', hue='variable')
plt.xticks(rotation=90, ha='center')
plt.title(mach)
plt.legend(loc='upper left')
plt.tight_layout()
plt.savefig(f'{mach}.png')
plt.show()
'Temp'
和 'speed'
的单独图
for mach, data in dfmg:
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(20, 5), sharex=True)
# select data
temp = data[data.variable.eq('Temp')]
speed = data[data.variable.eq('speed')]
# plot data
sns.barplot(data=temp, x='bin', y='value', ax=ax1) # ax1.bar(data=temp, x='bin', y='value') - without seaborn
sns.barplot(data=speed, x='bin', y='value', ax=ax2) # ax2.bar(data=speed, x='bin', y='value') - without seaborn
ax1.set(xlabel=None, ylabel='Temp')
ax1.tick_params(bottom=False)
ax2.set(ylabel='Speed')
ax2.set_xticklabels(ax2.get_xticklabels(), rotation=90, ha='center') # ax2.tick_params('x', rotation=90) - without seaborn
fig.suptitle(mach)
fig.tight_layout()
fig.savefig(f'{mach}.png')
plt.show()
选项 2
- 或者,创建单个图形将图形上的所有图
- 所有 50 台机器都节省了 1 个数字
- 本节图中每台机器的绘图,看起来与之前的绘图相同,具有橙色和蓝色色调。
fig, axes = plt.subplots(nrows=len(df.machine.unique()), ncols=1, figsize=(20, 250))
for i, (mach, data) in enumerate(df.melt(id_vars=['machine', 'bin']).groupby('machine')):
sns.barplot(data=data, x='bin', y='value', hue='variable', ax=axes[i])
axes[i].set_xticklabels(axes[i].get_xticklabels(), rotation=90, ha='center')
axes[i].set(title=mach)
axes[i].legend(loc='upper left')
fig.tight_layout()
fig.savefig('machines_all.png')
plt.show()
seaborn.catplot
可以用一条线创建等效的单图级图
import seaborn as sns
# melt the dataframe into a long form
dfm = df.melt(id_vars=['machine', 'bin'])
# plot
p = sns.catplot(data=dfm, col='machine', x='bin', y='value', hue='variable', kind='bar', col_wrap=1, height=4, aspect=5)
p.set_xticklabels(rotation=90)
p.savefig("facet_plot.png")
这是我的数据框:
data = {'machine': ['machine_a', 'machine_a', 'machine a', 'machine a', 'machine a', 'machine a', 'machine_b', 'machine_b', 'machine_b', 'machine_b', 'machine_b', 'machine_b', 'machine_c', 'machine_c', 'machine_c', 'machine_c', 'machine_c', 'machine_c'], 'bin': ['(0, 200]', '(200, 400]', '(400, 600]', '(600, 800]', '(800, 1000]', '(1000, 1200]', '(0, 200]', '(200, 400]', '(400, 600]', '(600, 800]', '(800, 1000]', '(1000, 1200]', '(0, 200]', '(200, 400]', '(400, 600]', '(600, 800]', '(800, 1000]', '(1000, 1200]'], 'speed': [10, 0, 20, 0, 20, 10, 5, 0, 40, 10, 20, 10, 5, 25, 0, 10, 5, 10], 'Temp': [0, 0, 0, 20, 20, 0, 35, 0, 0, 20, 0, 70, 30, 0, 0, 5, 0, 25]}
df = pd.DataFrame(data)
machine bin speed Temp
0 machine_a (0, 200] 10 0
1 machine_a (200, 400] 0 0
2 machine a (400, 600] 20 0
3 machine a (600, 800] 0 20
4 machine a (800, 1000] 20 20
5 machine a (1000, 1200] 10 0
6 machine_b (0, 200] 5 35
7 machine_b (200, 400] 0 0
8 machine_b (400, 600] 40 0
9 machine_b (600, 800] 10 20
10 machine_b (800, 1000] 20 0
11 machine_b (1000, 1200] 10 70
12 machine_c (0, 200] 5 30
13 machine_c (200, 400] 25 0
14 machine_c (400, 600] 0 0
15 machine_c (600, 800] 10 5
16 machine_c (800, 1000] 5 0
17 machine_c (1000, 1200] 10 25
我想为列速度和温度创建不同的条形图,其中 x 轴是 bins 列。我想为每台不同的机器执行此操作。
到目前为止,我已经创建了一个 for 循环来遍历最后两列
import seaborn as sns
import matplotlib.pyplot as plt
for column in df.columns[2:]:
sns.set()
fig, ax = plt.subplots()
sns.set(style="ticks")
sns.barplot(x = df.bin, y=column, data=df)
sns.despine(offset=10, trim=True)
fig.set_size_inches(22,14)
这将创建 2 个条形图。 1 表示速度,1 表示温度。我该怎么做才能得到 6 个条形图(每台机器 2 个)?在这种情况下,基本上我该如何使用 groupby?
完整的综合数据
- 50 台机器,每台机器有 109 个 bin
import pandas as pd
import numpy as np
bins = [f'({n*200}, {(n+1)*200}]' for _ in range(50) for n in range(109)]
machines = [f'machine_{n}' for n in range(50) for _ in range(109)]
np.random.seed(365)
speed = np.random.randint(0, 40, size=len(machines))
temp = np.random.choice([0, 30, 70], size=len(machines))
df = pd.DataFrame({'machine': machines, 'bin': bins, 'speed': speed, 'Temp': temp})
df.head()
machine bin speed Temp
0 machine_0 (0, 200] 18 30
1 machine_0 (200, 400] 33 70
2 machine_0 (400, 600] 27 30
3 machine_0 (600, 800] 5 30
4 machine_0 (800, 1000] 34 30
df.tail()
machine bin speed Temp
5445 machine_49 (20800, 21000] 6 0
5446 machine_49 (21000, 21200] 20 30
5447 machine_49 (21200, 21400] 14 0
5448 machine_49 (21400, 21600] 38 30
5449 machine_49 (21600, 21800] 24 70
可以直接使用seaborn.catplot
。您只需要先融化 y 列:
import seaborn as sns
sns.catplot(data=df.melt(id_vars=['machine', 'bin']),
col='machine',
x='bin', y='value', hue='variable',
kind='bar'
)
输出:
或者将变量作为行:
import seaborn as sns
sns.catplot(data=df.melt(id_vars=['machine', 'bin']),
col='machine',
row='variable',
x='bin', y='value',
kind='bar',
color='k',
)
输出:
或者拆分变量:
import seaborn as sns
sns.catplot(data=df.melt(id_vars=['machine', 'bin']),
hue='machine',
x='bin', y='value', col='variable',
kind='bar'
)
这是一个使用 groupby
的版本:
df2 = df.melt(id_vars=['machine', 'bin'])
COLS = df2['machine'].nunique()
ROWS = df2['variable'].nunique()
fig, axes = plt.subplots(ncols=COLS,
nrows=ROWS,
)
i = 0
for group, d in df2.groupby(['machine', 'variable']):
ax = axes[i%ROWS][i//ROWS]
ax.bar(d['bin'], d['value'])
if not i//ROWS:
ax.set_ylabel(group[1])
if i%ROWS == ROWS-1:
ax.set_xlabel(group[0])
i+=1
输出:
- 鉴于评论中描述的现有数据和更新的合成数据集。
- 使用
seaborn.barplot
。seaborn
是matplotlib
的高级 API
import matplotlib.pyplot as plt
import seaborn as sns
# melt the dataframe into a long form and group by the machine
dfmg = df.melt(id_vars=['machine', 'bin']).groupby('machine')
选项 1
- 为每台机器创建一个单独的绘图,与机器名称一起保存
- 这节省了 50 个图,每台机器 1 个
for mach, data in dfmg:
plt.figure(figsize=(20, 5))
sns.barplot(data=data, x='bin', y='value', hue='variable')
plt.xticks(rotation=90, ha='center')
plt.title(mach)
plt.legend(loc='upper left')
plt.tight_layout()
plt.savefig(f'{mach}.png')
plt.show()
'Temp'
和'speed'
的单独图
for mach, data in dfmg:
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(20, 5), sharex=True)
# select data
temp = data[data.variable.eq('Temp')]
speed = data[data.variable.eq('speed')]
# plot data
sns.barplot(data=temp, x='bin', y='value', ax=ax1) # ax1.bar(data=temp, x='bin', y='value') - without seaborn
sns.barplot(data=speed, x='bin', y='value', ax=ax2) # ax2.bar(data=speed, x='bin', y='value') - without seaborn
ax1.set(xlabel=None, ylabel='Temp')
ax1.tick_params(bottom=False)
ax2.set(ylabel='Speed')
ax2.set_xticklabels(ax2.get_xticklabels(), rotation=90, ha='center') # ax2.tick_params('x', rotation=90) - without seaborn
fig.suptitle(mach)
fig.tight_layout()
fig.savefig(f'{mach}.png')
plt.show()
选项 2
- 或者,创建单个图形将图形上的所有图
- 所有 50 台机器都节省了 1 个数字
- 本节图中每台机器的绘图,看起来与之前的绘图相同,具有橙色和蓝色色调。
fig, axes = plt.subplots(nrows=len(df.machine.unique()), ncols=1, figsize=(20, 250))
for i, (mach, data) in enumerate(df.melt(id_vars=['machine', 'bin']).groupby('machine')):
sns.barplot(data=data, x='bin', y='value', hue='variable', ax=axes[i])
axes[i].set_xticklabels(axes[i].get_xticklabels(), rotation=90, ha='center')
axes[i].set(title=mach)
axes[i].legend(loc='upper left')
fig.tight_layout()
fig.savefig('machines_all.png')
plt.show()
seaborn.catplot
可以用一条线创建等效的单图级图
import seaborn as sns
# melt the dataframe into a long form
dfm = df.melt(id_vars=['machine', 'bin'])
# plot
p = sns.catplot(data=dfm, col='machine', x='bin', y='value', hue='variable', kind='bar', col_wrap=1, height=4, aspect=5)
p.set_xticklabels(rotation=90)
p.savefig("facet_plot.png")