Pandas+带有多维数据帧的seaborn分面

Pandas+seaborn faceting with multidimensional dataframes

在 Python pandas 中,我需要从多维 DataFrame 做一个小平面网格。 在 ab 列中,我保存标量值,代表实验条件。 在 xy 列中,我有两个 numpy 数组。 x 列是数据的 x 轴,y 列是 f(x) 对应的函数值。 显然 xy 具有相同数量的元素。

我现在想做一个 facet 网格,其中行和列指定条件,并在网格的每个单元格中绘制 D 列与 D 列的值。

这可能是一个最小的工作示例:

import pandas as pd
d = [0]*4 # initialize a list with 4 elements
d[0] = {'x':[1,2,3],'y':[4,5,6],'a':1,'b':2} # then fill these elements
d[1] = {'x':[3,1,5],'y':[6,5,1],'a':0,'b':3}
d[2] = {'x':[3,1,5],'y':[6,5,1],'a':1,'b':3}
d[3] = {'x':[3,1,5],'y':[6,5,1],'a':0,'b':2}
pd.DataFrame(d) # create the pandas dataframe

如何使用现有的分面函数来解决按条件 ab 分组绘制 y vs x 的问题?

由于我需要将此函数应用于具有不同列名的一般数据集,因此我想避免诉诸硬编码解决方案,而是看看是否可以将 seaborn FacetGrid 函数扩展到这种类型问题。

您需要一个长格式的框架才能使用 FacetGrid,因此最好的办法是展开列表,然后重新组合并应用:

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

d = [0]*4
d[0] = {'x':[1,2,3],'y':[4,5,6],'a':1,'b':2} # then fill these elements
d[1] = {'x':[3,1,5],'y':[6,5,1],'a':0,'b':3}
d[2] = {'x':[3,1,5],'y':[6,5,1],'a':1,'b':3}
d[3] = {'x':[3,1,5],'y':[6,5,1],'a':0,'b':2}
df = pd.DataFrame(d)

df.set_index(['a','b'], inplace=True, drop=True)

x_long = pd.melt(df['x'].apply(pd.Series).reset_index(),
                 id_vars=['a', 'b'], value_name='x')

y_long = pd.melt(df['y'].apply(pd.Series).reset_index(),
                 id_vars=['a', 'b'], value_name='y')

long_df = pd.merge(x_long, y_long).drop('variable', axis='columns')

grid = sns.FacetGrid(long_df, row='a', col='b')
grid.map(plt.scatter, 'x', 'y')
plt.show()

这将向您展示以下内容:

我认为最好的方法是先拆分嵌套数组,然后使用 seaborn 创建一个面网格。

感谢这个 post () 我能够在你的数据框中拆分嵌套数组:

unnested_lst = []
for col in df.columns:
    unnested_lst.append(df[col].apply(pd.Series).stack())
result = pd.concat(unnested_lst, axis=1, keys=df.columns).fillna(method='ffill')

然后你可以用这段代码制作小平面网格:

import seaborn as sbn
fg = sbn.FacetGrid(result, row='b', col='a')
fg.map(plt.scatter, "x", "y", color='blue')

我认为最好、最短和最容易理解的解决方案是定义一个适当创建的 lambda 函数。它以 FacetGrid.map 方法指定的映射变量作为输入,并通过 .values[0] 以 numpy 数组的形式获取其值,因为它们是唯一的。

import pandas as pd
d = [0]*4 # initialize a list with 4 elements
d[0] = {'x':[1,2,3],'y':[4,5,6],'a':1,'b':2} # then fill these elements
d[1] = {'x':[3,1,5],'y':[6,5,1],'a':0,'b':3}
d[2] = {'x':[3,1,5],'y':[6,5,1],'a':1,'b':3}
d[3] = {'x':[3,1,5],'y':[6,5,1],'a':0,'b':2}
df = pd.DataFrame(d) # create the pandas dataframe

import seaborn as sns
import matplotlib.pyplot as plt
grid = sns.FacetGrid(df,row='a',col='b')
grid.map(lambda _x,_y,**kwargs : plt.scatter(_x.values[0],_y.values[0]),'x','y')