#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, и уровни были назначены на основе позиции.
Этот список может меняться в зависимости от выбора пользователя из интерфейса.
что я хочу сделать, так это присвоить уникальный идентификатор для комбинаций, подобных приведенной ниже таблице.(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 соответствующие cls будут иметь SNO 11, 12 для dpt 1.
в зависимости от dpt2 соответствующие cls будут иметь SON 21, 22 для dpt 2.
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.
Комментарии:
1. Я не уверен, что вы подразумеваете под нужным столбцом SNO, но если вы хотите, чтобы число в конце было значением категории, вы можете использовать
df.str.split
его для разделения, затем соединить три столбца вместе и сделать его целым числом. Результатом будет 100,110,120,111,112,121,…
Ответ №1:
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:]
Использовал этот подход, чтобы достичь цели.
Использовал список, поскольку я хотел сделать его динамическим на основе списка, переданного пользователем.
Ответ №2:
# 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
Ответ №3:
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
потребуется group no - 1
df['SNO'] = df['SNO'].fillna((df['grp'].str.extract(r'(d )
Промежуточные шаги выводят:
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
).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