Python 为组合定义唯一ID

Python 为组合定义唯一ID,python,pandas,Python,Pandas,我有如下表所示的数据 grp dpt cls lvl Grp1 0 Grp1 dpt1 1 Grp1 dpt2 1 Grp1 dpt1 cs1 2 Grp1 dpt1 cs2 2 Grp1 dpt2 cs1 2 Grp1 dpt2 cs2 2 Grp1 dpt2 cs3 2 我有grp、dpt、cls的组合,并根据

我有如下表所示的数据

grp      dpt    cls  lvl
Grp1                  0
Grp1    dpt1          1
Grp1    dpt2          1 
Grp1    dpt1    cs1   2
Grp1    dpt1    cs2   2
Grp1    dpt2    cs1   2
Grp1    dpt2    cs2   2
Grp1    dpt2    cs3   2
我有grp、dpt、cls的组合,并根据职位分配了级别。 此列表可能因用户从前端的选择而异

我要做的是为如下表所示的组合分配一个唯一ID。SNO

grp      dpt     cls  lvl   SNO
Grp1                   0    0
Grp1    dpt1           1    1
Grp1    dpt2           1    2
Grp1    dpt1    cs1    2    11
Grp1    dpt1    cs2    2    12
Grp1    dpt2    cs1    2    21
Grp1    dpt2    cs2    2    22
Grp1    dpt2    cs3    2    23
这里我只有一个grp,所以SNO是0

2个唯一的dpt,因此SNO分别为1和2

根据dpt1,对于1的dpt,相应的cls将具有SNO 11、12

根据dpt2,对于2的dpt,相应的cls将具有子21、22

IF USER SELECT ONE MORE HIERARCHY AFTER CLS THEN THE NEXT LEVEL OF HIERARCHY WILL HAVE SNO's DEPENDING ON THE CLS VALUES. EG (111, 112, 113  or 121, 122, 123)
用户也可以从前端选择GRP、DPT、CLS或任何其他组合,以便数据将相应地更改

我所要做的就是动态地分配SNO。SNO是从第1列到最后第二列的每列末尾的数字的组合。您可以组合所有这些列,并使用正则表达式提取结尾处出现的数字。否则,将需要一个循环遍历所有列。连接以仅确定每个列的值结尾处出现的数字

df['SNO'] = (df.iloc[:, 1:-1] # this will take all the columns after grp and before lvl
             .apply(lambda x: "##".join(x.values.astype(str))+"##", axis=1)
             .str.extractall(r'(?P<SNO>\d+)##') # extract all the numbers before ##
             .groupby(level=0)['SNO'].apply(lambda x: "".join(list(x))))

     grp    dpt     cls  lvl   SNO
0   Grp1                 0     NaN
1   Grp1    dpt1         1     1
2   Grp1    dpt2         1     2
3   Grp1    dpt1    cs1  2     11
4   Grp1    dpt1    cs2  2     12
5   Grp1    dpt2    cs1  2     21
6   Grp1    dpt2    cs2  2     22
7   Grp1    dpt2    cs3  2     23
中间步骤输出: 使用这种方法来实现目标。
使用列表,因为我想根据用户传递的列表将其动态化。

我不确定您想要的SNO列是什么意思,但如果您想将末尾的数字作为类别值,可以使用df.str.split将其拆分,然后将三列合并为整数。结果将是100110120111112121,。。。
df['SNO'] = df['SNO'].fillna((df['grp'].str.extract(r'(\d+)$').astype(int)-1)[0])

     grp    dpt     cls lvl SNO
0   Grp1                0   0
1   Grp1    dpt1        1   1
2   Grp1    dpt2        1   2
3   Grp1    dpt1    cs1 2   11
4   Grp1    dpt1    cs2 2   12
5   Grp1    dpt2    cs1 2   21
6   Grp1    dpt2    cs2 2   22
7   Grp1    dpt2    cs3 2   23
df.iloc[:, 1:-1].apply(lambda x: "##".join(x.values.astype(str))+"##", axis=1)

0    ####       
1    dpt1####   
2    dpt2####   
3    dpt1##cs1##
4    dpt1##cs2##
5    dpt2##cs1##
6    dpt2##cs2##
7    dpt2##cs3##
dtype: object

(df.iloc[:, 1:-1].apply(lambda x: "##".join(x.values.astype(str))+"##", axis=1)
 .str.extractall(r'(?P<SNO>\d+)##'))

        SNO
  match 
1   0   1
2   0   2
3   0   1
    1   1
4   0   1
    1   2
5   0   2
    1   1
6   0   2
    1   2
7   0   2
    1   3
# create a map for every column's content to unique number
col_map = dict()
col_map['grp'] = {'Grp1':'0'}
for col in ['dpt', 'cls']:
    cond = df[col] != ''
    obj = df.loc[cond, col].sort_values().dropna().unique()
    col_map[col] = dict(zip(obj, map(str,range(1, len(obj)+1))))

col_map
# {'grp': {'Grp1': '0'},
#  'dpt': {'dpt1': '1', 'dpt2': '2'},
#  'cls': {'cs1': '1', 'cs2': '2', 'cs3': '3'}}

# map with col_map content to number
for col in col_map:
    df[col+'_m'] = df[col].map(col_map[col])
df = df.fillna('')

df['tag'] = df[['grp_m','dpt_m','cls_m']].apply(lambda x: ''.join(x), axis=1).map(list)
df['lvl'] = df['lvl'].astype(int)
df['SNO'] = df.apply(lambda x: ''.join(x.tag[-x.lvl:]), axis=1)

print(df)

#     grp   dpt  cls  lvl grp_m dpt_m cls_m        tag SNO
# 0  Grp1               0     0                    [0]   0
# 1  Grp1  dpt1         1     0     1           [0, 1]   1
# 2  Grp1  dpt2         1     0     2           [0, 2]   2
# 3  Grp1  dpt1  cs1    2     0     1     1  [0, 1, 1]  11
# 4  Grp1  dpt1  cs2    2     0     1     2  [0, 1, 2]  12
# 5  Grp1  dpt2  cs1    2     0     2     1  [0, 2, 1]  21
# 6  Grp1  dpt2  cs2    2     0     2     2  [0, 2, 2]  22
# 7  Grp1  dpt2  cs3    2     0     2     3  [0, 2, 3]  23
lists=['GRP','DPT','CLS']


grpNM = pd.DataFrame({lists[0]: df[lists[0]].unique()})

grpNM['SN_lvl'] = grpNM.index+1

df = df.merge(grpNM, how='left', on=lists[0])

df['SN_lvl'] = df['SN_lvl'].fillna(0)

df['SN_lvl'] = df['SN_lvl'].astype(int)

df['SNO'] = df['SN_lvl'].astype(str)

df.drop(['SN_lvl'], inplace=True, axis=1)

#FOR FIRST LEVEL ID ASSIGNMENT DONE MANUALLY 

#1st LEVEL OF ID ASSIGNMENT DONE MANUALLY WITHOUT RUUNING THE LOOP


#NEXT LEVELS ID CREATION HAS BEEN DONE INSIDE LOOP

sn_list = df['SNO'].unique()

tempF = pd.DataFrame()

l1=lists.copy()
l1=l1[1:]
print(l1)

for L in range(len(l1)):
    for i in sn_list:
    
        tempDF = pd.DataFrame({l1[L]: df[df['SNO'] == i][l1[L]].unique()[1:]})
    
        tempDF['SN_lvl'] = tempDF.index+1
        
        tempDF['SN_lvl'].astype(int)
        
        tempDF['SNO'] = i
    
        tempF = tempF.append(tempDF, ignore_index=False) 
        
    df = df.merge(tempF, how='left', on=['SNO',l1[L]])
    
    df['SN_lvl'] = df['SN_lvl'].astype('O')    
    df.loc[df['SN_lvl'].notnull(), 'SN_lvl'] = df.loc[df['SN_lvl'].notnull(), 'SN_lvl'].astype(int)
    
    df['SN_lvl'] = df['SN_lvl'].fillna('')
    
    df['SNO'] = df['SNO'] + df['SN_lvl'].astype(str)
    
    df.drop(['SN_lvl'], inplace=True, axis=1)  
    
    sn_list = df['SNO'].unique()[1:]