Pandas 数据帧 - 通过两列'Father'和'Son'运行,逐步重建端到端链接



我有一个长的数据帧,需要转换才能得到一个宽的数据帧。长的是:

df = pd.DataFrame({
'key' : ['E', 'E', 'E', 'E', 'J', 'J', 'J', 'J'],
'father' : ['A', 'D', 'C', 'B', 'F', 'H', 'G', 'I'],
'son' : ['B', 'E', 'D', 'C', 'G', 'I', 'H', 'J']
})
df

我认为,首先要做的是按键分组。然后我们必须找到那些键在"儿子"列中的位置,这是我需要重建的链接的末尾(也是最后一个儿子(。

为了重建联系,我需要寻找他的"父亲"。他的"父亲"需要被保留为最后一步的父亲,也需要被发现为"儿子"。

我需要迭代,直到在"son"列中找不到"father",所以它将是链接的father_0。

我认为可以将这些步骤迭代到递归函数中,其中stop case:在"son"中找不到"father"。

这是我想从中获得的数据帧:

df1 = pd.DataFrame({
'key' : ['E', 'J'],
'father_1' : ['A', 'F'],
'son_1' : ['B', 'G'],
'father_2' : ['B', 'G'],
'son_2' : ['C', 'H'],
'father_3' : ['C', 'H'],
'son_3' : ['D', 'I'],
'father_4' : ['D', 'I'],
'son_4' : ['E', 'J'],
})
df1

我在这里用两个相同深度的不同链接简化了问题,但对于许多不同的键,它们可能从深度1到深度10(可能更多,但很少且不可预测(。这里是df的另一个例子,有两个不同大小的链接:

df_ = pd.DataFrame({
'key' : ['E', 'E', 'E', 'E', 'K', 'K', 'K', 'K', 'K'],
'father' : ['A', 'D', 'C', 'B', 'F', 'H', 'G', 'I', 'J'],
'son' : ['B', 'E', 'D', 'C', 'G', 'I', 'H', 'J', 'K']
})
df_
df_1 = pd.DataFrame({
'key' : ['E', 'K'],
'father_1' : ['A', 'F'],
'son_1' : ['B', 'G'],
'father_2' : ['B', 'G'],
'son_2' : ['C', 'H'],
'father_3' : ['C', 'H'],
'son_3' : ['D', 'I'],
'father_4' : ['D', 'I'],
'son_4' : ['E', 'J'],
'father_5' : [np.NaN, 'J'],
'son_5' : [np.NaN, 'K']
})
df_1 

最后一步很简单,就是把"父亲_x"one_answers"儿子_x-1"变成"步骤_x-1":因此,这些示例的结果数据帧将是:

df2 = pd.DataFrame({
'key' : ['E', 'J'],
'step_0' : ['A', 'F'],
'step_1' : ['B', 'G'],
'step_2' : ['C', 'H'],
'step_3' : ['D', 'I'],
'step_4' : ['E', 'J'],
})
df2
df_2 = pd.DataFrame({
'key' : ['E', 'K'],
'step_0' : ['A', 'F'],
'step_1' : ['B', 'G'],
'step_2' : ['C', 'H'],
'step_3' : ['D', 'I'],
'step_4' : ['E', 'J'],
'step_5' : [np.NaN, 'K']
})
df_2

我关心的更多的是如何将数据从宽到长按照之前给定的规则聚合为递归函数。

这就像在groupby.agg中一样,但我不能只向其中传递字典,因为新列是基于递归函数在每个键上的迭代次数。

cumcount分配新密钥,然后我们可以执行pivot

out = df.assign(c = df.groupby('key').cumcount().add(1).astype(str)).pivot('key','c').sort_index(level=1,axis=1)
out.columns = out.columns.map('_'.join)
out
Out[34]: 
father_1 son_1 father_2 son_2 father_3 son_3 father_4 son_4
key                                                            
E          A     B        B     C        C     D        D     E
J          F     G        G     H        H     I        I     J

我为这种特定类型的数据帧找到了一个解决方案:除了根之外,所有值只有一个前置值。它还需要使用NetworkX。我没有找到只使用熊猫的方法。

首先,我们需要从边缘列表构建一个图:

G = nx.from_pandas_edgelist(df, 'father', 'son', create_using=nx.MultiDiGraph, edge_key = 'key')
from networkx.drawing.nx_agraph import write_dot, graphviz_layout
#write_dot(G,'test.dot')
plt.title('draw_networkx')
pos =graphviz_layout(G, prog='dot')
nx.draw(G, pos, with_labels=True, arrows=True)

对于pygraphviz安装,请参阅此问题。然后使用构建端到端链路数据帧

num=0
num_max = len(df.key.drop_duplicates())
m_max = 30
dfy = pd.DataFrame(index=range(num_max),columns=range(m_max))
for n in df.key.drop_duplicates() :
m = 0
dfy.iloc[num, m] = n
while len(list(G.predecessors(dfy.iloc[num,m])))!=0 :
dfy.iloc[num,m+1] = list(G.predecessors(dfy.iloc[num,m]))[0]
m+=1
num+=1
print(dfy)

输出:

0  1  2  3  4    5    6    7    8    9  ...   
0  E  D  C  B  A  NaN  NaN  NaN  NaN  NaN  ...  
1  K  J  I  H  G    F  NaN  NaN  NaN  NaN  ...

最新更新