用遞歸計(jì)算股權(quán)層級(jí)

一、問(wèn)題背景:

一個(gè)集團(tuán)公司下設(shè)有多層企業(yè),整體的股權(quán)結(jié)構(gòu)呈垂直特征,即A公司控制B公司、B公司控制C公司,依次向下,現(xiàn)在想獲取每個(gè)公司在這個(gè)垂直結(jié)構(gòu)中的股權(quán)層級(jí),如果是頂層的A公司,就是1級(jí),層級(jí)越低,級(jí)數(shù)越大,這里約定:假如一個(gè)公司G即被母公司A直接持股,也被A公司的子公司B公司直接持股,則G的層級(jí)取2,而非3。案例測(cè)試數(shù)據(jù)為:


一個(gè)簡(jiǎn)單的股權(quán)結(jié)構(gòu)

形象的說(shuō),就是對(duì)于每個(gè)子公司,找到最短的“回A之路”。你可以先不看下面的代碼,想一想應(yīng)該怎么解決這個(gè)問(wèn)題。

二、代碼實(shí)現(xiàn)如下:

a=Ctrsht['子公司'].unique().tolist()#數(shù)組a記錄了去除所有的非重復(fù)機(jī)構(gòu)
b=[]#數(shù)組b用于記錄每個(gè)機(jī)構(gòu)的層級(jí)
def levelsearch(level,name):
    if name=='A':#遞歸函數(shù)必須由明確的退出機(jī)制,否則就是死循環(huán)
        return(level,name)#當(dāng)傳入的機(jī)構(gòu)名稱為A時(shí),表示子公司順著股權(quán)路徑找到了A公司,這時(shí)level就是返回的級(jí)數(shù)
    else:#如果尚未返回A公司,則記錄此時(shí)尋找到的母公司是哪一個(gè)
        for i in range(len(Ctrsht['子公司'])):#遍歷上面的dataframe
            if Ctrsht.iloc[i,1]==name:#定位當(dāng)前傳入的機(jī)構(gòu)名稱的所在行
                if Ctrsht.iloc[i,0]=='A':#如果該行的母公司即為A則返回層數(shù)
                    return(level+1,'A')
                else:
                    return(levelsearch(level+1,Ctrsht.iloc[i,0]))#如果該行的母公司不是A,則調(diào)用函數(shù)本身,下一次傳入的機(jī)構(gòu)名稱即該行的母公司
            else:
                pass
for i in range(len(a)):#遍歷子公司數(shù)組,計(jì)算每個(gè)子公司的層級(jí)
    b.append(levelsearch(1,a[i])[0])
equitylevel=pd.DataFrame(a)
equitylevel['股權(quán)層級(jí)']=b
equitylevel
股權(quán)層級(jí)

三、改進(jìn):

上述程序有個(gè)問(wèn)題:有的子公司出現(xiàn)了多次,比如F公司,程序返回層級(jí)為F第一次出現(xiàn)時(shí)的股權(quán)層級(jí),即為3(A--B--F),而如果源數(shù)據(jù)文件中將第6行E->F放在B->F前面,則程序返回的F層級(jí)就是6(A--B--C--D--E--F)。
因此當(dāng)前的結(jié)果依賴于股權(quán)結(jié)構(gòu)表的排序,需要進(jìn)一步完善。

完善步驟為:
1、找到某公司在“子公司”列中出現(xiàn)的所有行數(shù)(F公司就是第5行和第6行)
2、分別計(jì)算該公司在各行時(shí)返回的股權(quán)層級(jí)(F公司就是3和4)
3、根據(jù)問(wèn)題的初始規(guī)定原則,取過(guò)程2中的最小值

這里有個(gè)一非常繞的情境,就是F的母公司E,在各行也出現(xiàn)了兩次,兩種回A的路徑分別是ABCDE和ABCE,這樣返回的F股權(quán)層級(jí)就是6和5,按照規(guī)定原則,結(jié)果應(yīng)該是5(即選擇ABCE路徑),所以在遞歸函數(shù)的定義中,必須用循環(huán)將最佳回A路徑找出。

首先定義遞歸函數(shù)

#2020/3/7改進(jìn)
#3/7改進(jìn)2
def levelsearch(level,position,name):#level為初始層級(jí),一般為1,position為子公司所在行數(shù)
    if name=='A':#name記錄當(dāng)前子公司的母公司,如果為A則跳出遞歸程序
        return(level,position,name)
    else:
        if Ctrsht.iloc[position,1]==name:
            if Ctrsht.iloc[position,0]=='A':#如果當(dāng)前子公司的母公司為A,則層級(jí)加1,遞歸結(jié)束
                return(level+1,position,'A')
            else:#如果當(dāng)前子公司的母公司不為A,先記錄母公司在“子公司”列出現(xiàn)的行數(shù),然后調(diào)用程序自身
                temPosition=[]
                for i in range(len(Ctrsht['子公司'])):
                    if Ctrsht.iloc[i,1]==Ctrsht.iloc[position,0]:
                        temPosition.append(i)#母公司在“子公司”列出現(xiàn)的行數(shù)可能為多個(gè),必須用數(shù)組記錄,并遍歷數(shù)組調(diào)用遞歸函數(shù)
                templevel={}#用字典記錄母公司每次返回的股權(quán)層級(jí)
                levelsig=0
                for k in temPosition:
                    templevel[k]=levelsearch(levelsig,k,Ctrsht.iloc[k,1])[0]
                minilevel = min(templevel, key=lambda x:templevel[x])
                return(levelsearch(level+1,minilevel,Ctrsht.iloc[minilevel,1]))
        else:
            pass

然后對(duì)每個(gè)子公司分別計(jì)算出現(xiàn)的行數(shù),并調(diào)用遞歸函數(shù)計(jì)算min{基于各行數(shù)計(jì)算的股權(quán)層級(jí)}

a=Ctrsht['子公司'].unique().tolist()#去除所有的非重復(fù)機(jī)構(gòu)
b=[]#記錄每個(gè)機(jī)構(gòu)的層級(jí)
for i in range(len(a)):
    linenum=[]#獲得每個(gè)機(jī)構(gòu)在持股機(jī)構(gòu)列中出現(xiàn)的行數(shù)
    for k in range(len(Ctrsht['子公司'])):
        if Ctrsht.iloc[k,1]==a[i]:
            linenum.append(k)
    agencylevel=[]#記錄不同出現(xiàn)行數(shù)計(jì)算的股權(quán)層級(jí)
    for j in linenum:
        agencylevel.append(levelsearch(1,j,a[i])[0])
    b.append(min(agencylevel))
equitylevel=pd.DataFrame(a)
equitylevel['改進(jìn)的股權(quán)層級(jí)']=b
equitylevel
image.png

可以看到E的股權(quán)層級(jí)得到了修正。
下面這個(gè)圖可以看到,F(xiàn)的層級(jí)是在比較3和5之后,選擇的最小值,E的層級(jí)是在比較4和5之后,選擇的最小值


E

F

結(jié)語(yǔ):遞歸是目前我寫過(guò)最難的程序了,對(duì)邏輯的要求高,中間的各種計(jì)數(shù)變量、臨時(shí)變量也多,大腦要清醒,但遞歸代碼的簡(jiǎn)潔和高效也使遞歸成為應(yīng)用非常廣泛的算法
算是剛?cè)肓碎T,以后再修煉吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 選擇題部分 1.()部門負(fù)責(zé)日常監(jiān)督檢查工作,安全巡視的同時(shí)進(jìn)行消防檢查,推動(dòng)消防安全制度的貫徹落實(shí)。 A: 消防...
    skystarwuwei閱讀 15,943評(píng)論 0 3
  • 高級(jí)鉗工應(yīng)知鑒定題庫(kù)(858題) ***單選題*** 1. 000003難易程度:較難知識(shí)范圍:相關(guān)4 01答案:...
    開源時(shí)代閱讀 6,306評(píng)論 1 9
  • 選擇題部分 1.(),只有在發(fā)生短路事故時(shí)或者在負(fù)荷電流較大時(shí),變流器中才會(huì)有足夠的二次電流作為繼電保護(hù)跳閘之用。...
    skystarwuwei閱讀 14,379評(píng)論 0 7
  • 說(shuō)到影子,我想到了去年張藝謀拍的電影《影》,講述的是一個(gè)關(guān)于替身也就是影子的故事。電影中影子如同與真身互為一體,令...
    燕敏Lisa閱讀 151評(píng)論 0 0
  • 影響他人最重要的條件是什么? 1.正能量,積極主動(dòng) 2.利他 3.互賴 4. 領(lǐng)導(dǎo)力,牽引力 5.內(nèi)心堅(jiān)...
    森塬閱讀 661評(píng)論 0 1

友情鏈接更多精彩內(nèi)容