熊猫:在条形图上同时使用日志和堆栈

时间:2017-01-21 11:47:43

标签: python python-3.x pandas matplotlib

我有一些来自亚马逊的数据,我想参与其中。我想要包括的一个情节是每个品牌的评级分布,我认为这样做的最佳方式是堆积条形图。

然而,有些品牌比其他品牌更受欢迎,所以我必须使用对数刻度,否则情节将是3个峰值,其他品牌将无法正常看待。

有大约300个' 000 entires看起来像这样

reviewID  brand      overall
0         Logitech   5.0
1         Garmin     4.0
2         Logitech   4.0
3         Logitech   5.0

我已使用此代码

brandScore = swissDF.groupby(['brand', 'overall'])['brand']
brandScore = brandScore.count().unstack('overall')
brandScore.plot(kind='bar', stacked=True, log=True, figsize=(8,6))

这是结果

bar plot

现在,如果您不熟悉数据,这可能看起来可以接受,但实际上并非如此。 1.0评级堆栈看起来与其他堆栈相比太大,因为对数不是完全有效的"在那个范围内但是会收获更好的分数。 有没有办法在对数图上线性表示评级分布?

我的意思是,如果60%的评分是5.0,那么60%的标准应该是粉红色,而不是我现在拥有的

3 个答案:

答案 0 :(得分:2)

为了使总条形高度以对数刻度生存,但条形内的类别比例是线性的,可以重新计算堆积数据,使其在对数刻度上呈线性。

作为一个展示示例,让我们选择具有非常不同的总数([5,10,50,100,500,1000])的6个数据集,这样在线性比例上,较低的条形将会很小。在这种情况下,我们将它分成30%,50%和20%(为简单起见,所有不同的数据按相同的比例划分)。

然后我们可以计算每个数据点,这些数据点稍后应该在堆积条上出现需要多大的数据点,这样在对数比例图中保留30%,50%和20%的比率,最后绘制那些新创建的数据。

from __future__ import division 
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

a = np.array([5,10,50,100,500,1000])

p = [0.3,0.5,0.2]
c = np.c_[p[0]*a,p[1]*a, p[2]*a]

d = np.zeros(c.shape)
for j, row in enumerate(c):
    g = np.zeros(len(row)+1)
    G = np.sum(row)
    g[1:] = np.cumsum(row)
    f = 10**(g/G*np.log10(G))
    f[0] = 0
    d[j, :] = np.diff( f )

collabels = ["{:3d}%".format(int(100*i)) for i in p]     
dfo = pd.DataFrame(c, columns=collabels)
df2 = pd.DataFrame(d, columns=collabels)

fig, axes = plt.subplots(ncols=2)

axes[0].set_title("linear stack bar")
dfo.plot.bar(stacked=True, log=False, ax=axes[0])
axes[0].set_xticklabels(a)

axes[1].set_title("log total barheight\nlinear stack distribution")
df2.plot.bar(stacked=True, log=True, ax=axes[1])
axes[1].set_xticklabels(a)
axes[1].set_ylim([1, 1100])
plt.show()

enter image description here

最后一句话:我认为应该小心这样的情节。它可能对检查有用,但我不建议向其他人展示这样的情节,除非人们可以绝对确定他们理解绘制的内容以及如何阅读它。否则这可能会引起很多混乱,因为堆积的类别'高度与简单错误的比例不匹配。并且显示错误数据会导致很多麻烦!

答案 1 :(得分:1)

为了避免对数刻度的问题,您无法在绘图中堆叠条形图。有了这个,您可以比较每个相同比例的栏。但是你需要更长的数字(5倍以上)。只需stacked=False。示例数据示例:

poke_example

答案 2 :(得分:1)

没有数据的两条建议(提供样本数据更好)

选项1
使用value_counts(normalize=True)

brandScore = swissDF.groupby(['brand', 'overall'])['brand']
brandScore = brandScore.value_counts(normalize=True).unstack('overall')
brandScore.plot(kind='bar', stacked=True, figsize=(8,6))

选项2
除以行和

brandScore = swissDF.groupby(['brand', 'overall'])['brand']
brandScore = brandScore.count().unstack('overall')
brandScore.div(brandScore.sum(1), 0).plot(kind='bar', stacked=True, figsize=(8,6))