matplotlib 在pandas条形图上同时使用log和stack

qojgxg4l  于 2023-04-06  发布在  其他
关注(0)|答案(3)|浏览(127)

我有一些来自亚马逊的数据,我想做一些工作,其中一个图是每个品牌的评分分布图,我认为最好的方法是一个堆叠的条形图。
然而,有些品牌比其他品牌更多的审查,所以我必须使用日志规模,否则情节将是3峰和其他品牌将是不可能体面地看到。
大约有30万个这样的个体

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))

而这就是结果

现在,如果你不熟悉这些数据,这看起来可能是可以接受的,但事实并非如此。1.0的评分堆栈与其他评分堆栈相比看起来太大了,因为对数在该范围内不是“完全有效”,而是对更好的分数进行了处理。有没有办法在对数图上线性表示评分分布?
我的意思是,如果60%的收视率是5.0,那么60%的酒吧应该是粉红色的,而不是我现在拥有的

esbemjvw

esbemjvw1#

为了使总条高度在对数尺度上存在,但是条内的类别的比例是线性的,可以重新计算堆叠的数据,使得其在对数尺度上呈现线性。
作为一个展示的例子,让我们选择6个数据集,它们的总数非常不同([5,10,50,100,500,1000]),这样在线性尺度上,下面的条会很小。让我们将其分为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()

最后一点:我认为人们应该小心使用这样的图表。它可能对检查有用,但我不建议向其他人展示这样的图表,除非你能绝对确保他们理解图表的内容以及如何阅读它。否则这可能会引起很多混乱,因为堆叠的类别的高度与比例不匹配,这根本就是错误的。显示错误的数据会引起很多麻烦!

htrmnn0y

htrmnn0y2#

为了避免对数标度的问题,您不能将图中的条形图堆叠起来。这样,您可以将每个条形图与相同的标度进行比较。但您需要一个更长的图(5倍以上)。简单地stacked=False。示例数据:

biswetbf

biswetbf3#

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

选项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))

相关问题