我有一个数据框,其中包含一个感兴趣的变量(分类,此处为Yes
,No
等)和一个分组变量(请参见下文):
import pandas as pd
import numpy as np
df = pd.DataFrame({
'ID': range(100),
'group': np.random.choice(['A', 'B', 'C'], 100),
'Response':np.random.choice(['Yes','No','Other', np.nan], 100)})
由此,我想在条形图中检索并绘制每组的累积数据。
详细信息:对于组A
,Yes
,No
等的百分比,对于组别相同。
命令df['Response'].groupby(df['group']).value_counts()
已经给了我这个输出:
group Response
A Other 14
No 8
Yes 8
nan 8
B Other 11
nan 11
No 5
Yes 4
C No 9
Yes 9
nan 7
Other 6
Name: Response, dtype: int64
这就是我想要的,但是我找不到一种适当地绘制它的方法(在matplotlib或seaborn中),并且不确定这是否是数据转换或可视化的问题。
This的问题是在询问类似问题,但我无法使其与unstack
一起使用:
df = df['group'].unstack(0, fill_value = 0)
给予
AttributeError:“ RangeIndex”对象没有属性“ remove_unused_levels”
和
df = df['group'].unstack(0, fill_value = 0)
df.index.name = None
df.columns.name = None
df.plot.bar(stacked=True)
仅绘制ID
(未分组)。
答案 0 :(得分:2)
您应该在不选择unstack
的情况下执行columns
,groupby
的输出为Series
,并请注意您没有使用Series
groupby
pd.DataFrame.groupby
df['Response'].groupby(df['group']).value_counts().unstack(fill_value=0)
type(df['Response'].groupby(df['group']).value_counts())
Out[207]: pandas.core.series.Series
答案 1 :(得分:1)
我认为更好的方法是使用string
中的按列分组并在groupby
之后获取列进行处理:
df1 = df.groupby('group')['Response'].value_counts().unstack(fill_value=0)
替代方法是使用crosstab
:
df1 = pd.crosstab(df['group'], df['Response'])
要删除索引和列名,请使用您的解决方案或DataFrame.rename_axis
:
#pandas 0.24+
df1.rename_axis(index=None, columns=None).plot.bar(stacked=True)
#pandas bellow
#df1.rename_axis(None).rename_axis(None, axis=1).plot.bar(stacked=True)
您的解决方案is mainly syntactic sugar for the alternative and much more verbose,显然是在需要处理列之前使用的,例如需要列Response
的小写字母:
df1 = df['Response'].str.lower().groupby(df['group']).value_counts().unstack(fill_value=0)
第一个解决方案是可能的,但需要2行:
df['Response'] = df['Response'].str.lower()
df1 = df.groupby('group')['Response'].value_counts().unstack(fill_value=0)
编辑:
要缩放,请使用Series.value_counts
中的normalize=True
:
.value_counts(normalize=True)