在pandas DataFrame中从分组数据绘制直方图。

98

我如何从数据框中的一组数据绘制一个直方图块?例如,给定:

from pandas import DataFrame
import numpy as np
x = ['A']*300 + ['B']*400 + ['C']*300
y = np.random.randn(1000)
df = DataFrame({'Letter': x, 'N': y})

我试过了。
df.groupby('Letter').hist()

...报错信息如下:

类型错误:无法连接 'str' 和 'float' 对象

6个回答

257
我正在进行得很顺利,刚刚发现了使用hist方法中的by关键字来更简单地完成它的方法。
df.hist('N', by='Letter')

这是一个非常方便的小技巧,可以快速扫描您分组的数据!
对于未来的访问者,此调用的产品是以下图表:

output of hist plot command

以下是对下面问题的回答,这里有一个直方图绘制的具体调整示例:
# import libraries
import pandas as pd
import numpy as np

# Create test dataframe
x = ['A']*300 + ['B']*400 + ['C']*300
y = np.random.randn(1000)
z = np.random.randn(1000)
df = pd.DataFrame({'Letter':x, 'N1':y, 'N2':z})

# Plot histograms
axes = df.hist(['N1','N2'], by='Letter',bins=10, layout=(2,2),
               legend=True, yrot=90,sharex=True,sharey=True, 
               log=True, figsize=(6,6))
for ax in axes.flatten():
    ax.set_xlabel('N')
    ax.set_ylabel('Count')
    ax.set_ylim(bottom=1,top=100)

enter image description here


44
能否将它们放在同一张图中呢? - Phani
6
@Phani: 使用Matplotlib同时绘制两个直方图。 - Jonathan Jin
5
为了获得更大的图表;df['N'].hist(by=df['Letter']), figsize=(16,18)) - Nosey
df.groupby('age').survived.value_counts().unstack().plot.bar(width=1, stacked=True)) 这段代码可以将所有内容绘制在同一张图中。 - prof_FL
有没有办法让每个子图使用不同的颜色?我的直方图只有一列,而不是两列,但我希望每个直方图的颜色都不同。 - undefined
显示剩余7条评论

14

一种解决方法是直接在每个分组的数据框上使用 matplotlib 直方图。您可以循环遍历所获得的组。每个组都是一个数据框,您可以为每个数据框创建一个直方图。

from pandas import DataFrame
import numpy as np
x = ['A']*300 + ['B']*400 + ['C']*300
y = np.random.randn(1000)
df = DataFrame({'Letter':x, 'N':y})
grouped = df.groupby('Letter')

for group in grouped:
  figure()
  matplotlib.pyplot.hist(group[1].N)
  show()

感谢Paul。我对'group[1].N'中的'[1]'有点困惑。当我在for循环中添加了一个'print group'语句时,每个'group'似乎只有两列(Letter和N)的DF。在这种情况下,'group.N'不就足够了吗? - dreme
1
啊,撤回之前的评论吧,我刚刚想通了。每个“组”实际上是包含组名和组数据框的二元组。唉,还真是没想到! - dreme
3
建议在for循环中拆分元组: for index, group in grouped,这样就可以省略 [1] - Gigo
matplotlib.pyplot.figure()和matplotlib.pyplot.show()应该放在循环外面。 - Sam

9
你的函数失败是因为你得到了一个具有分层索引和两个列(Letter和N)的groupby数据框,所以当你使用.hist()时,它会尝试制作两个列的直方图,因此出现了str错误。
这是pandas绘图函数的默认行为(每列一个图),因此如果你重塑数据框,使每个字母成为一列,你将得到正好想要的结果。
df.reset_index().pivot('index','Letter','N').hist()
reset_index()的作用是将当前索引放入名为index的列中。然后,pivot会获取您的数据框,收集所有Letter的值N并将它们作为一列。生成的数据帧有400行(使用NaN填充缺失的值)和三列(A, B, C)。hist()然后会对每个列生成一个直方图,并且您可以根据需要格式化绘图。

按照这种方法,我无法通过它们的数组获得图表。这是因为我的方法有误吗?我得到了一个长度为0x246c5fe10个项的matplotlib.axes.AxesSubplot对象数组。有没有办法让它们以每行3或4个的方式显示出来? - Douglas Fils
如果您正在使用IPython笔记本,则运行%pylab或%matplotlib魔术函数以自动显示图形。 - dreme

8

在最近版本的Pandas中,您可以使用df.N.hist(by=df.Letter)

就像上面的解决方案一样,每个子图的坐标轴将是不同的。我还没有解决这个问题。


3
您可以使用sharexsharey关键字为您的绘图获取公共轴,即: df.N.hist(by=df.Letter, sharey=True, sharex=True) - dreme

2
我发现这甚至更容易和更快。

data_df.groupby('Letter').count()['N'].hist(bins=100)


1
我写这篇答案是因为我正在寻找一种将不同组的直方图绘制在一起的方法。以下方法并不十分聪明,但对我来说很有效。我使用Numpy计算直方图,并使用Bokeh进行绘图。我认为它是自解释的,但如果需要澄清,可以随时询问,我很乐意添加细节(并改善文章)。
figures = {
    'Transit': figure(title='Transit', x_axis_label='speed [km/h]', y_axis_label='frequency'),
    'Driving': figure(title='Driving', x_axis_label='speed [km/h]', y_axis_label='frequency')
}

cols = {'Vienna': 'red', 'Turin': 'blue', 'Rome': 'Orange'}
for gr in df_trips.groupby(['locality', 'means']):
    locality = gr[0][0]
    means = gr[0][1]
    fig = figures[means]
    h, b = np.histogram(pd.DataFrame(gr[1]).speed.values)
    fig.vbar(x=b[1:], top=h, width=(b[1]-b[0]), legend_label=locality, fill_color=cols[locality], alpha=0.5)

show(gridplot([
    [figures['Transit']],
    [figures['Driving']],
]))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接