Pandas + морская грань с многомерными фреймами данных - PullRequest
0 голосов
/ 06 сентября 2018

В Python pandas мне нужно сделать сетку фасетов из многомерного DataFrame. В столбцах a и b я держу скалярные значения, которые представляют условия эксперимента. В столбцах x и y вместо этого у меня есть два массива. Столбец x - это ось X данных, а столбец y - это значение функции, соответствующее f(x). Очевидно, что x и y имеют одинаковое количество элементов.

Теперь я хотел бы создать фазовую сетку со строками и столбцами, задающими условия, и в каждой ячейке сетки выведите значение столбца 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

Как я могу использовать уже существующие функции огранки для решения проблемы построения y vs x, сгруппированных по условиям a и b?

Поскольку мне нужно применить эту функцию к общим наборам данных с разными именами столбцов, я бы хотел не прибегать к жестко-закодированным решениям, а скорее посмотреть, возможно ли расширить функцию seaborn FacetGrid для решения этой проблемы.

Ответы [ 3 ]

0 голосов
/ 06 сентября 2018

Я думаю, что лучший способ - это сначала разделить вложенные массивы, а затем создать сетку фасетов с помощью seaborn.

Благодаря этому сообщению ( Разделить значения вложенного массива из ячейки Pandas Dataframe на несколькостроки ) Мне удалось разделить вложенный массив в вашем фрейме данных:

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')
0 голосов
/ 12 ноября 2018

Я считаю, что лучшее, самое короткое и наиболее понятное решение - это определить подходящую lambda функцию. Он имеет в качестве входных данных переменные отображения, определенные методом FacetGrid.map, и принимает значения в виде числовых массивов .values[0], поскольку они уникальны.

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

seaborn faceting with lambda functions

0 голосов
/ 06 сентября 2018

Вам нужен длинный фрейм, чтобы использовать 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()

Это покажет вам следующее:enter image description here

...