【发布时间】:2015-12-31 16:42:39
【问题描述】:
我想绘制箱线图,但我没有原始数据,而是在 Pandas DataFrame 中汇总了结果。
是否仍然可以从汇总结果中绘制箱线图?
如果不是,我能得到的最接近的图是什么,以绘制最小值、最大值、平均值、中位数、标准差等。我知道我可以使用折线图绘制它们,但我需要对箱线图进行分组/集群。
这是我的数据,缺少绘图部分。请帮忙。谢谢
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
df = pd.DataFrame({
'group' : ['Tick Tick Tick', 'Tock Tock Tock', 'Tock Tock Tock', 'Tick Tick Tick']*3, # , ['Tock Tock Tock', 'Tick Tick Tick']*6,
'person':[x*5 for x in list('ABC')]*4,
'Median':np.random.randn(12),
'StdDev':np.random.randn(12)
})
df["Average"]=df["Median"]*1.1
df["Minimum"]=df["Median"]*0.5
df["Maximum"]=df["Median"]*1.6
df["90%"]=df["Maximum"]*0.9
df["95%"]=df["Maximum"]*0.95
df["99%"]=df["Maximum"]*0.99
df
更新,
我现在离我的结果又近了一步——我刚刚发现这个功能是available since matplotlib 1.4,我使用的是matplotlib 1.5,我测试了它和proved that it is working for me。
问题是我不知道它为什么起作用,以及如何调整我上面的代码来使用这样的新功能。我将在下面重新发布我的工作代码,希望有人能理解并将两个和两个放在一起。
我拥有的数据是 Median、Average、Minimum、90%、95%、99%、Maximum 和 StdDev,我希望将它们全部绘制成图表。我查看了以下代码的logstats的数据结构,在for stats, label in zip(logstats, list('ABCD'))之后,发现它的字段是:
[{'cihi': 4.2781254505311281,
'cilo': 1.6164348064249057,
'fliers': array([ 19.69118642, 19.01171604]),
'iqr': 5.1561885723613567,
'label': 'A',
'mean': 4.9486856766955922,
'med': 2.9472801284780168,
'q1': 1.7655440553898782,
'q3': 6.9217326277512345,
'whishi': 12.576334012545718,
'whislo': 0.24252084924003742},
{'cihi': 4.3186289184254107,
'cilo': 1.9963715983778565,
...
所以,从这里
和bxp 文档,我将按如下方式映射我的数据:
- whislo:最低
- q1:中位数
- med:平均
- 平均:90%
- 第三季度:95%
- 威士忌:99%
- 和最大的传单
要映射它们,我只需 SELECT Minimum AS whislo, [90%] AS mean, [95%] as q3, [99%] as whishi...这是最终结果:
raw_data = {'label': ['Label_01 Init', 'Label_02', 'Label_03', 'Label_04', 'Label_05', 'Label_06', 'Label_07', 'Label_08', 'Label_99'], 'whislo': [0.17999999999999999, 2.0299999999999998, 4.0800000000000001, 2.0899999999999999, 2.3300000000000001, 2.3799999999999999, 1.97, 2.6499999999999999, 0.089999999999999997], 'q3': [0.5, 4.9699999999999998, 11.77, 5.71, 12.460000000000001, 11.859999999999999, 13.84, 16.969999999999999, 0.29999999999999999], 'mean': [0.40000000000000002, 4.1299999999999999, 10.619999999999999, 5.0999999999999996, 10.24, 9.0700000000000003, 11.960000000000001, 15.15, 0.26000000000000001], 'whishi': [1.76, 7.6399999999999997, 20.039999999999999, 6.6699999999999999, 22.460000000000001, 21.66, 16.629999999999999, 19.690000000000001, 1.1799999999999999], 'q1': [0.28000000000000003, 2.96, 7.6100000000000003, 3.46, 5.8099999999999996, 5.4400000000000004, 6.6299999999999999, 8.9900000000000002, 0.16], 'fliers': [5.5, 17.129999999999999, 32.890000000000001, 7.9100000000000001, 32.829999999999998, 70.680000000000007, 24.699999999999999, 32.240000000000002, 3.3500000000000001]}
df = pd.DataFrame(raw_data, columns = ['label', 'whislo', 'q1', 'mean', 'q3', 'whishi', 'fliers'])
现在要挑战的是如何在具有多级分组的箱形图中呈现我的上述数据框。如果多级分组太难了,让我们先从 pd 数据帧开始绘图,因为我的pd 数据帧与所需的np 数组具有相同的字段。所以我尝试了,
fig, ax = plt.subplots()
ax.bxp(df.as_matrix(), showmeans=True, showfliers=True, vert=False)
但我得到了
...\Anaconda3\lib\site-packages\matplotlib\axes\_axes.py in bxp(self, bxpstats, positions, widths, vert, patch_artist, shownotches, showmeans, showcaps, showbox, showfliers, boxprops, whiskerprops, flierprops, medianprops, capprops, meanprops, meanline, manage_xticks)
3601 for pos, width, stats in zip(positions, widths, bxpstats):
3602 # try to find a new label
-> 3603 datalabels.append(stats.get('label', pos))
3604 # fliers coords
3605 flier_x = np.ones(len(stats['fliers'])) * pos
AttributeError: 'numpy.ndarray' object has no attribute 'get'
如果我使用ax.bxp(df.to_records(), ...,那么我会得到AttributeError: 'record' object has no attribute 'get'。
好的,我终于搞定了,从 pd 数据帧绘图,但不是多级分组,像这样:
df['fliers']=''
fig, ax = plt.subplots()
ax.bxp(df.to_dict('records'), showmeans=True, meanline=True, showfliers=False, vert=False) # shownotches=True,
plt.show()
请注意,我上面的数据缺少med 字段,您可以添加正确的字段,或使用df['med']=df['q1']*1.2 使其正常工作。
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
def test_bxp_with_ylabels():
np.random.seed(937)
logstats = matplotlib.cbook.boxplot_stats(
np.random.lognormal(mean=1.25, sigma=1., size=(37,4))
)
print(logstats)
for stats, label in zip(logstats, list('ABCD')):
stats['label'] = label
fig, ax = plt.subplots()
ax.set_xscale('log')
ax.bxp(logstats, vert=False)
test_bxp_with_ylabels()
【问题讨论】:
-
我不明白你有什么数据以及你期望多少箱线图。
ax.bxp期望中位数、四分位数和胡须值。你有吗? -
到目前为止,我了解到您只有
p和e,并且您想制作一个箱线图,其中p中的值作为平均值,e中的值作为标准,以某种方式绘制`p±e`,是你想要的吗? -
好的,箱线图的分组是否在我的答案中?同样在您的数据框中,给定对(组;人)的中位数有多个值,我应该使用这些值的平均值吗? (就像你之前对
pivot_table所做的那样?) -
是的,我确实需要将它们分组,即您的答案是正确的。我只是不知道如何实现它,所以我删除了
pivot_table语句,只是为了强调原始数据源。至于数据映射,根据你的新解释,我就做SELECT Minimum AS whislo, [90%] AS q3, [95%] as whishi...。下一个挑战是如何用多层次的分组来呈现它。再次感谢您的帮助。
标签: python pandas matplotlib plot dataframe