Pandas(杂):将多列变量值堆叠为一列以便于matplotlib及seaborn制图

在绘图时有时需要将本地的表格转换为目标接口要求的格式 -> reshape。以seaborn绘制多变量箱线图为例,其默认数据接口需要的是一列数值加一列类型,但是本地通常是多列,因此需要转换,此外如果涉及到排序也需要自行调整,以下为案例代码记录以供复用:

DataFrame格式转换

比如我的表格为如下的,n行6列的表格,其中5列代表五个不同的变量,需要将其转换为三列:UID, Typename, Value

1
2
3
4
5
6
7
8
9
df = pd.DataFrame(
{
"UID": range(12),
"x1": np.random.randn(12),
"x2": np.random.randn(12),
"x3": np.random.randn(12),
"x4": np.random.randn(12),
"x5": np.random.randn(12),
})

使用pd.stack()

1
2
3
4
df2 = df.set_index("UID")
df2 = df2.stack().reset_index()
df2.columns = ["UID","typaneme","y"]
df2

不使用函数自行定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def stack_data(datatable, typenames, col_id):
uids = []
names = []
values = []
for col in typenames:
value = list(datatable[col])
names.extend([col]*len(value))
values.extend(value)
uids.extend(datatable[col_id])
df_temp = pd.DataFrame({col_id:uids,"typename":names, "y":values})
return df_temp
# 选定要堆叠的变量
cols = list(df.columns[1:])
typenames = cols
# ['x1', 'x2', 'x3', 'x4', 'x5']
df_temp = stack_data(df,typenames,"UID")
df_temp

如果不需要UID列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def stack_data(datatable, typenames):
names = []
values = []
for col in typenames:
value = list(datatable[col])
names.extend([col]*len(value))
values.extend(value)
df_temp = pd.DataFrame({"typename":names, "y":values})
return df_temp
# 选定要堆叠的变量
cols = list(df.columns[1:])
typenames = cols

df_temp = stack_data(df,typenames)
df_temp

按照统计值排序

如果是直接排序,直接对得到的表格进行排序即可,df.sort_values(by=["y"], scending=False,ignore_index=False)

1
2
3
#直接对堆叠后的值排序如下, 也可多列进行排序,也可以结合set_index();sort_index()函数操作
df_temp.sort_values(by=["y"], ascending=[False],ignore_index=False)

有时候需要先对列进行排序再进行堆叠,比如按照中位数或者均值排列

1
2
3
4
5
6
7
8
9
10
df3 = df[df.columns[1:]]
meds = df3.median()
meds = meds.sort_values(ascending=False)
cols_sort = list(meds.index)
# cols_sort即为按照列的中位数调整顺序后的列名['x2', 'x5', 'x1', 'x4', 'x3']
cols_sort.insert(0,"UID")
df3 = df[cols_sort]

....
# 再进行堆叠即可得到新的按照变量的中值进行排序的结果

Seaborn绘图示意

seaborn.boxplot(data=None, *, x=None, y=None, hue=None, order=None, hue_order=None, orient=None, color=None, palette=None, saturation=0.75, width=0.8, dodge=True, fliersize=5, linewidth=None, whis=1.5, ax=None, **kwargs)

实际上我们可以对该图进行定制,包括颜色,文字,线和箱等等,后续单独记一下boxplot的调参

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import seaborn as sns
import matplotlib.pyplot as plt

sns.set_theme(style="ticks")

# Initialize the figure with a logarithmic x axis
f, ax = plt.subplots(figsize=(7, 6))
ax.set_xscale("log")

# Load the example planets dataset
planets = sns.load_dataset("planets")

# Plot the orbital period with horizontal boxes
sns.boxplot(x="distance", y="method", data=planets,
whis=[0, 100], width=.6, palette="vlag")

# Add in points to show each observation
sns.stripplot(x="distance", y="method", data=planets,
size=4, color=".3", linewidth=0)

# Tweak the visual presentation
ax.xaxis.grid(True)
ax.set(ylabel="")
sns.despine(trim=True, left=True)

参考