我希望将我的数据可视化为箱形图,这些图表按照我可怕的图纸中显示的另一个变量分组:
所以我所做的就是使用pandas系列变量告诉pandas我已经对变量进行了分组,这就是我所做的:
import pandas as pd
import seaborn as sns
#example data for reproduciblity
a = pd.DataFrame(
[
[2, 1],
[4, 2],
[5, 1],
[10, 2],
[9, 2],
[3, 1]
])
#converting second column to Series
a.ix[:,1] = pd.Series(a.ix[:,1])
#Plotting by seaborn
sns.boxplot(a, groupby=a.ix[:,1])
这就是我得到的:
然而,我原本期望获得的是两个箱图,每个箱图仅描述第一列,按第二列中的相应列(转换为系列的列)分组,而上图则分别显示每列不是我想要的。
答案 0 :(得分:7)
Dataframe
中的列已经是Series
,因此无需进行转换。此外,如果您只想对两个箱图使用第一列,则只应将其传递给Seaborn。
所以:
#example data for reproduciblity
df = pd.DataFrame(
[
[2, 1],
[4, 2],
[5, 1],
[10, 2],
[9, 2],
[3, 1]
], columns=['a', 'b'])
#Plotting by seaborn
sns.boxplot(df.a, groupby=df.b)
我稍微改变了你的例子,给我一些标签让我觉得它更清晰。
如果您想分别绘制所有列,我(我认为)基本上需要groupby
列和任何其他列中所有值的组合。所以如果你Dataframe
看起来像这样:
a b grouper
0 2 5 1
1 4 9 2
2 5 3 1
3 10 6 2
4 9 7 2
5 3 11 1
您想要列a
和b
的箱图,同时按列grouper
进行分组。您应该展平列并更改groupby列以包含a1
,a2
,b1
等值。
考虑到上面显示的Dataframe,我认为这是一种粗略的方法:
dfpiv = df.pivot(index=df.index, columns='grouper')
cols_flat = [dfpiv.columns.levels[0][i] + str(dfpiv.columns.levels[1][j]) for i, j in zip(dfpiv.columns.labels[0], dfpiv.columns.labels[1])]
dfpiv.columns = cols_flat
dfpiv = dfpiv.stack(0)
sns.boxplot(dfpiv, groupby=dfpiv.index.get_level_values(1))
也许有更多奇特的方法来重组Dataframe
。特别是旋转后层次的扁平化很难读,我不喜欢它。
答案 1 :(得分:1)
这是一个旧问题的新答案,因为在 seaborn
和 pandas
中是通过版本更新进行的一些更改。由于这种变化,Rutger 的答案不再有效。
最重要的变化是从 seaborn==v0.5.x
到 seaborn==v0.6.0
。我引用日志:
对 boxplot()
和 violinplot()
的更改可能是最具破坏性的。这两个函数在它们可以接受的数据类型方面保持向后兼容性,但语法已更改为与其他 seaborn 函数更相似。现在使用 x
和/或 y
参数调用这些函数,这些参数是传递给新数据参数的长格式 DataFrame 中的数据向量或变量名称。
现在让我们来看看例子:
# preamble
import pandas as pd # version 1.1.4
import seaborn as sns # version 0.11.0
sns.set_theme()
示例 1:简单箱线图
df = pd.DataFrame([[2, 1] ,[4, 2],[5, 1],
[10, 2],[9, 2],[3, 1]
], columns=['a', 'b'])
#Plotting by seaborn with x and y as parameter
sns.boxplot(x='b', y='a', data=df)
示例 2:带石斑鱼的箱线图
df = pd.DataFrame([[2, 5, 1], [4, 9, 2],[5, 3, 1],
[10, 6, 2],[9, 7, 2],[3, 11, 1]
], columns=['a', 'b', 'grouper'])
# usinge pandas melt
df_long = pd.melt(df, "grouper", var_name='a', value_name='b')
# join two columns together
df_long['a'] = df_long['a'].astype(str) + df_long['grouper'].astype(str)
sns.boxplot(x='a', y='b', data=df_long)
示例3:重新排列DataFrame传递直接给seaborn
def df_rename_by_group(data:pd.DataFrame, col:str)->pd.DataFrame:
'''This function takes a DataFrame, groups by one column and returns
a new DataFrame where the old columnnames are extended by the group item.
'''
grouper = df.groupby(col)
max_length_of_group = max([len(values) for item, values in grouper.indices.items()])
_df = pd.DataFrame(index=range(max_length_of_group))
for i in grouper.groups.keys():
helper = grouper.get_group(i).drop(col, axis=1).add_suffix(str(i))
helper.reset_index(drop=True, inplace=True)
_df = _df.join(helper)
return _df
df = pd.DataFrame([[2, 5, 1], [4, 9, 2],[5, 3, 1],
[10, 6, 2],[9, 7, 2],[3, 11, 1]
], columns=['a', 'b', 'grouper'])
df_new = df_rename_by_group(data=df, col='grouper')
sns.boxplot(data=df_new)
我真的希望这个答案有助于避免一些混乱。
答案 2 :(得分:0)
sns.boxplot() 不接受 groupby。
也许你会看到
TypeError: boxplot() got an unexpected keyword argument 'groupby'.
对数据进行分组并在箱线图中使用的最佳方法是将数据作为 groupby 数据框值传递。
import seaborn as sns
grouDataFrame = nameDataFrame(['A'])['B'].agg(sum).reset_index()
sns.boxplot(y='B', x='A', data=grouDataFrame)
此处 B 列数据包含数值并在 A 的基础上进行分组。添加所有分组值及其各自的列并绘制箱线图。希望这会有所帮助。