Python 使用熊猫中的两列创建层次结构

Python 使用熊猫中的两列创建层次结构,python,pandas,dataframe,hierarchy,Python,Pandas,Dataframe,Hierarchy,我正在处理的数据如下: Name RefSecondary RefMain test 2 3 bet 3 4 get 1 2 set null 1 net 3 5 Result RefMain 0 get/test 3 1 test/bet 4

我正在处理的数据如下:

Name RefSecondary     RefMain
test  2               3   
bet   3               4   
get   1               2   
set   null            1   
net   3               5
   Result          RefMain
0  get/test           3
1  test/bet           4
2  set/get            2
3  set                1
4  test/net           5
我做了一个非常简单的查询,查找dataframe中的值并构建层次结构

sys_role = 'sample.xlsx'
df = pd.read_excel(sys_role,na_filter = False).apply(lambda x: x.astype(str).str.strip())
for i in range(count):
    for j in range(count):
        if df.iloc[i]['RefMain'] == df.iloc[j]['RefSecondary']:
            df.iloc[j, df.columns.get_loc('Name')] = "/".join([df.iloc[i]['Name'],df.iloc[j]['Name']])
    j = j+1
i = i+1
我得到的结果如下:

Name RefSecondary     RefMain
test  2               3   
bet   3               4   
get   1               2   
set   null            1   
net   3               5
   Result          RefMain
0  get/test           3
1  test/bet           4
2  set/get            2
3  set                1
4  test/net           5
这真的很慢,而且逻辑也不能很好地工作。有没有办法让我更快地完成这件事

逻辑需要如下所示:

结果数据帧应如下所示:

   Result            RefMain
0  set/get/test          3
1  set/get/test/bet      4
2  set/get               2
3  set                   1
4  set/get/test/net      5

以下代码查找ref(本例中为1),直到找不到任何行。它输出

def查找(df,ref):
arr_结果=[]
结果=[]
行=df[df.RefMain==ref]
当len(row)>0时:
arr_result.append(row.Name.iloc[0])
result.append((“/”.join(arr_result),row.RefMain.iloc[0]))
row=df[df.RefSecondary==row.RefMain.iloc[0]]
返回pd.DataFrame(结果,列=[“结果”,“参考主”])
查找(df,1)
输出

Result  RefMain
0   set 1
1   set/get 2
2   set/get/test    3
3   set/get/test/bet    4

在上面的问题中,如何获取“set/get/test/net 5”行,我是否遗漏了某个内容或它是一个错误?

此代码与
合并一起工作。它有点扭曲,但它应该运行得很快,因为(可能是因为)没有行迭代

简而言之,它会一直合并,直到所有新的
RefSecondary
值都为空

我想还可以对
merge
操作进行进一步优化

df_ref = df.copy()

df.rename(columns={'Name':'Result'},inplace=True)

while not np.all(pd.isnull(df['RefSecondary'])):
    df = df.merge(df_ref,how='left',
                  left_on='RefSecondary',right_on='RefMain',
                  suffixes=['_old',''])
    mask_=pd.notnull(df['RefMain'])
    df.loc[mask_,'Result'] = df.loc[mask_,'Result']+'/'+df.loc[mask_,'Name']
    df.drop(['RefSecondary_old','RefMain_old','Name'],axis='columns',inplace=True)


df = df[['Result']].join(df_ref['RefMain'])
来源数据:

df = pd.DataFrame(data=[['test',2,3],
                    ['bet',3,4],
                    ['get',1,2],
                    ['set','null',1],
                    ['net',3,5]], 
              columns=['Name','RefSecondary','RefMain'])

顺便说一下,这段代码假设原始数据是一致的。例如,如果链接中有一个循环,它将被困在一个无限循环中。

这听起来像是一个图形问题。您可以按如下方式尝试
networkx

df = df.fillna(-1)

# create a graph
G = nx.DiGraph()

# add reference as edges
G.add_edges_from(zip(df['RefMain'],df['RefSecondary'] ))

# rename the nodes accordingly
G = nx.relabel_nodes(G, mapping=df.set_index('RefMain')['Name'].to_dict())


# merge the path list to the dataframe
df = df.merge(pd.DataFrame(nx.shortest_path(G)).T['null'], 
              left_on='Name', 
              right_index=True)

# new column:
df['Path'] = df['null'].apply(lambda x: '/'.join(x[-2::-1]) )
输出:

   Name RefSecondary RefMain                         null              Path
0  test            2       3       [test, get, set, null]      set/get/test
1   bet            3       4  [bet, test, get, set, null]  set/get/test/bet
2   get            1       2             [get, set, null]           set/get
3   set         null       1                  [set, null]               set
4   net            3       5  [net, test, get, set, null]  set/get/test/net

可以使用方法
reindex()
将列
RefMain
设置为索引并访问字符串:

您将获得以下数组列表
lst

[array(['test', 'bet', 'get', 'set', 'net'], dtype=object),
 array(['get', 'test', 'set', nan, 'test'], dtype=object),
 array(['set', 'get', nan, nan, 'get'], dtype=object),
 array([nan, 'set', nan, nan, 'set'], dtype=object),
 array([nan, nan, nan, nan, nan], dtype=object)]
现在您可以连接字符串并创建新的df

result = ['/'.join(filter(np.nan.__eq__, i)) for i in zip(*lst[::-1])]
result = pd.DataFrame({'Result': result, 'RefMain': df['RefMain'].values})
最终结果:

             Result  RefMain
0      set/get/test        3
1  set/get/test/bet        4
2           set/get        2
3               set        1
4  set/get/test/net        5

缺少问题?已更新以澄清您的逻辑仍然不清楚,您能否尝试解释如何获得第二行RefMain=4RefMain 4,其对应的RefSecondary值为3。现在可以在RefMain列中找到3,其对应的RefSecondary为2。现在可以在RefMain列中找到2,其RefSecondary为1。现在可以在RefMain列中找到1,其RefSecondary为null或不匹配。由于没有匹配,因此流停止,所有值都被加起来。我已经用我到目前为止所做的更新了这个问题。
df=df.merge(pd.DataFrame(nx.shortest_path(G)).T[-1]
这个谎言显示了
关键错误:-1
我做了。为了清楚起见,我也写了关于如何加载数据帧的代码,以防万一。您的原始数据是
nan
而不是第4行的
null
。字符串
是否为null'
int
?数字是
int
,yes null是string
null
在这种情况下,将
[-1]
替换为
['null']
。请参见编辑。
df.loc[mask_u,'Result']=df.loc[mask_u,'Result']+/'+df.loc[mask_u,'index']
此行显示
KeyError:“结果”
没有列
索引
在上面的代码中被重命名。另外
Result
是我在输出数据框中创建的一列。我根据您的评论调整了我的回复。