我有一个单列数据框,如下所示:
df = pd.DataFrame(np.random.randn(20, 1),
columns=['Time'])
df['EDGE'] = pd.Series(['A', 'A', 'A','B', 'B', 'A', 'B','C','C', 'B','D','A','E','F','F','A','G','H','H','A'])
df
实际数据框有数十万行,唯一的“ EDGE”值列表大约为200
我想以箱图的方式绘制结果,如下所示:
boxplot = df.boxplot(by='EDGE')
现在有太多的值需要打印一点,只需在同一图中首先说出10个首字母即可。 另一方面,我想先打印平均时间更长的值。
预期结果: 每个箱线图包括10条EDGE的箱线图集合。这些框相对于平均“时间”以降序显示。
如何进行?
我尝试了什么?
我试图用loc为sub_df设置每个值,但是每个框图只能得到一个框 我尝试使用groupby毫无用处地按“ EDGE”,因为我不知道如何仅绘制数据帧的前n个组
注意:我假装使用尽可能少的库,也就是说,如果我可以使用pandas而不是使用matplotlib更好地使用它,并且matplotlib可以比使用matplotlib之上的另一个库更好地使用
答案 0 :(得分:1)
IIUC,那么您可以通过重塑数据框来实现
# define the number of edges per plot
nb_edges_per_plot = 4 #to change to your needs
# group by edge
gr = df.groupby('EDGE')['Time']
# get the mean per group and sort them
order_ = gr.mean().sort_values(ascending=False).index
print (order_) #order depends on the random value so probably not same for you
#Index(['D', 'H', 'C', 'B', 'A', 'E', 'G', 'F'], dtype='object', name='EDGE')
# reshape your dataframe to ake each EDGE a column and order the columns
df_ = df.set_index(['EDGE', gr.cumcount()])['Time'].unstack(0)[order_]
print (df_.iloc[:5, :5])
# EDGE D H C B A
# 0 1.729417 0.270593 -0.140786 -0.540270 0.862832
# 1 NaN 0.647830 1.038952 -0.129361 -0.648432
# 2 NaN NaN NaN -1.235637 -0.430890
# 3 NaN NaN NaN 0.631744 -1.622461
# 4 NaN NaN NaN NaN 0.694052
现在您可以将boxplot
与groupby
一起使用。要在子图上绘制每组边缘,请执行以下操作:
df_.groupby(np.arange(len(order_))//nb_edges_per_plot, axis=1).boxplot()
或者如果您想要分开的数字,则可以
for _, dfg_ in df_.groupby(np.arange(len(order_))//nb_edges_per_plot, axis=1):
dfg_.plot(kind='box')
甚至一行都可以得到分开的图形,看到的区别是使用boxplot()
而不是plot.box()
。请注意,如果要更改每个绘图中的参数,则循环版本更为灵活
df_.groupby(np.arange(len(order_))//nb_edges_per_plot, axis=1).plot.box()
答案 1 :(得分:1)
您可以创建一个中间框架groups
,并将EDGE分配给绘图编号(列Order
)和每个绘图内的EDGE位置(列Pos
)。
chunk_size = 3
groups = df.groupby('EDGE')
groups = (groups.ngroups - groups.Time.mean().rank(method='first').astype(int)).to_frame()
groups['Order'] = groups.Time // chunk_size
groups['Pos'] = groups.Time % chunk_size
for i in range(groups.Order.max() + 1):
group = groups[groups.Order==i]
df[df.EDGE.isin(group.index)].boxplot(by='EDGE', positions=group.Pos)
示例:
import pandas as pd
import numpy as np
np.random.seed(0)
df = pd.DataFrame(np.random.randn(20, 1), columns=['Time'])
df['EDGE'] = pd.Series(['A', 'A', 'A','B', 'B', 'A', 'B','C','C', 'B','D','A','E','F','F','A','G','H','H','A'])
# code from above ...
#verification:
print(df.groupby('EDGE').Time.mean().sort_values(ascending=False))
#EDGE
#G 1.494079
#B 1.367285
#E 0.761038
#A 0.442789
#F 0.282769
#D 0.144044
#H 0.053955
#C -0.127288