Я рисую диаграмму Санки, чтобы сравнить различные классификации наблюдений. Однако у меня возникают некоторые проблемы с более чем двумя классификациями, когда порядок наблюдений в каждой классификации меняется между входами и выходами каждого узла.
Я использую следующий код:
def pl_sankey(df, label_color, categories, value, title='Sankey Diagram', fname=None, width=3000, height=1600, scale=2):
from IPython.display import Image
import plotly.graph_objects as go
import pandas as pd
df = df.copy()
labels = []
colors = []
# associate labels to colors
for k, v in label_color.items():
labels += [k]
colors += [v]
# transform df into a source-target pair
st_df = None
for i in range(len(categories)-1):
_st_df = df[[categories[i],categories[i+1],value]]
_st_df.columns = ['source', 'target', 'count']
st_df = pd.concat([st_df, _st_df])
st_df = st_df.groupby(['source', 'target']).agg({'count': 'sum'}).reset_index()
# add index for source-target pair
st_df['sourceID'] = st_df['source'].apply(lambda x: labels.index(str(x)))
st_df['targetID'] = st_df['target'].apply(lambda x: labels.index(str(x)))
# creating the sankey diagram
data = dict(
type='sankey', node=dict(
pad=15, thickness=20, line = dict(color='black', width=0.5), label=labels, color=colors,
),
link=dict(source=st_df['sourceID'], target=st_df['targetID'], value=st_df['count']),
)
layout = dict(title=title, font=dict(size=16, family='Arial'))
# creating figure
fig = go.Figure(dict(data=[data], layout=layout))
if fname:
fig.write_image(f'{fname}.pdf', format='pdf', width=width, height=height, scale=scale)
return Image(fig.to_image(format='png', width=width, height=height, scale=scale))
Входные параметры:
- a pandas DataFrame
df
с группировками для каждого набора строк, например:
# g1_l1 means group1, label1
g1 g2 g3 counts
0 g1_l1 g2_l1 g3_l1 10
1 g1_l3 g2_l2 g3_l1 1
2 g1_l1 g2_l2 g3_l2 1
3 g1_l2 g2_l2 g3_l1 40
4 g1_l2 g2_l3 g3_l2 20
5 g1_l3 g2_l1 g3_l2 10
label_color
- словарь, где ключи - это метки, а значения - цвета categories
- имена столбцов группировок, в данном случае ['grouping1', 'grouping2', 'grouping3']
values
- имя столбца счетчиков, в данном случае 'counts'
Один из примеров выполнения следующий:
df = pd.DataFrame([
['g1_l1', 'g2_l1', 'g3_l1', 10],
['g1_l3', 'g2_l2', 'g3_l1', 1],
['g1_l1', 'g2_l2', 'g3_l2', 1],
['g1_l2', 'g2_l2', 'g3_l1', 40],
['g1_l2', 'g2_l3', 'g3_l2', 20],
['g1_l3', 'g2_l1', 'g3_l2', 10],
], columns=['g1', 'g2', 'g3', 'counts'])
label_color = {
'g1_l1': '#1f77b4', 'g1_l2': '#ff7f0e', 'g1_l3': '#279e68',
'g2_l1': '#1f77b4', 'g2_l2': '#ff7f0e', 'g2_l3': '#279e68',
'g3_l1': '#1f77b4', 'g3_l2': '#ff7f0e',
}
pl_sankey(df, label_color, categories=df.columns[:-1], value='counts', title='', fname=None)
However, this code guarantees row matching only between two adjacent columns. Consider for example, row 1:
g1 g2 g3 counts
1 g1_l3 g2_l2 g3_l1 1
Such row should start from green cluster (g1_l3
) on first column, land in orange cluster (g2_l2
) in second column and continue to blue cluster (g3_l1
) on third column. However, this is not respected in the previous plot, where input into the second column is not sorted similarly to matching output.
Attached the annotated plot to show the jumping of the observation in second column (such observation is second to last in input, but last in output in the second column):
наблюдательные прыжки
Я хотел бы проследить путь строки от первого до последнего столбца. Возможно ли это и как это сделать с помощью диаграммы Санки?