Разделить серию pandas строки, разделенной '_', на переменное количество полей, заполнив отсутствующие поля

В следующем кадре данных я хотел бы правильно разделить «ресурс» серии на его различные компоненты, изначально разделенные символом «_»:

ресурс MTUG1_ABO_DPP_1 MTUG1_ABO_DPP_2 MTUG1_ABO_DPP_3 MTUG1_ABO_DPP_4 MTUG1_ABO_DPP_5 MTUG1_ABO_DPU_1 MTUG1_ABO_DPU_2 MTUG1_ABO_DPU_3 MTUG1_ABO_UUB_VDU1_1 МТУГ1_АБО_УУБ_ВДУ1_2 МТУГ1_АБО_УУБ_ВДУ1_3 МТУГ1_АБО_УУБ_ВДУ2_1 МТУГ1_АБО_УУБ_ВДУ2_2
import pandas as pd
Data = {'resource':['MTUG1_ABO_DPP_1','MTUG1_ABO_DPP_2','MTUG1_ABO_DPP_3','MTUG1_ABO_DPP_4','MTUG1_ABO_DPP_5','MTUG1_ABO_DPU_1','MTUG1_ABO_DPU_2','MTUG1_ABO_DPU_3','MTUG1_ABO_UUB_VDU1_1','MTUG1_ABO_UUB_VDU1_2','MTUG1_ABO_UUB_VDU1_3','MTUG1_ABO_UUB_VDU2_1','MTUG1_ABO_UUB_VDU2_2']}
df = pd.DataFrame(Data, columns= ['resource'])

Результат, который я хочу:

Узел Единица unit_num vdu_num вм МТУГ1 ДПП 1 DDP_1 МТУГ1 ДПП 2 ДПП_2 МТУГ1 ДПП 3 ДПП_3 МТУГ1 ДПП 4 ДПП_4 МТУГ1 ДПП 5 ДПП_5 МТУГ1 ДПУ 1 DPU_1 МТУГ1 ДПУ 2 DPU_2 МТУГ1 ДПУ 3 DPU_3 МТУГ1 УУБ ВДУ1 1 ВДУ1_1 МТУГ1 УУБ ВДУ1 2 ВДУ1_2 МТУГ1 УУБ ВДУ1 3 ВДУ1_3 МТУГ1 УУБ ВДУ2 1 ВДУ2_1 МТУГ1 УУБ ВДУ2 2 ВДУ2_2

Итак, MTUG1 -> становится содержимым нового столбца «Узел». DPP DPU UUB--> становится содержимым для нового столбца «Единица». Затем мне нужно создать еще одну новую серию «vm», где я объединяю строку в «Unit» со следующим номером (разделенным добавлением «_»), и если содержимое в «unit_num» является VDUx, мне нужно также объединить его с помощью пятая часть, vdu_num.

Но если я использую:

df['Node']=df['resource'].str.split("_").str.get(0)
df['Unit']=df['resource'].str.split("_").str.get(2)
unit_num=df['resource'].str.split("_").str.get(3)
vdu_num=df['resource'].str.split("_").str.get(4)
df['vm']=df['Unit'].str.cat(vm_num, sep = "_").str.cat(vdu_num, sep = "_")
df['vm'].unique()

Я получаю только компоненты VDU:

array([nan, 'UUB_VDU1_1', 'UUB_VDU1_2', 'UUB_VDU1_3', 'UUB_VDU2_1',
   'UUB_VDU2_2'], dtype=object)

в то время как, чтобы увидеть оставшуюся часть, я должен удалить последнюю конкатенацию. Как бы вы решили это?

Исправьте ошибку в коде: NameError: имя 'vm_num' не определено в строке 6.

smci 12.12.2020 21:43

Кроме того, заголовок «не может правильно разделить строки в серии» вообще ни о чем нам не говорит. «разделить серию строк, разделенных '_', на переменное количество полей, заполнив отсутствующие поля».

smci 12.12.2020 21:55
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
83
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете применить два случая отдельно, используя логическое индексирование, где вы проверяете, является ли vdu_num NaN или нет.

df.loc[~vdu_num.isna(), 'vm']=df['Unit'].str.cat(unit_num, sep = "_").str.cat(vdu_num, sep = "_")
df.loc[vdu_num.isna(), 'vm']=df['Unit'].str.cat(unit_num, sep = "_")

производит

    resource              Node    Unit    unit_num      vdu_num  vm
--  --------------------  ------  ------  ----------  ---------  ----------
 0  MTUG1_ABO_DPP_1       MTUG1   DPP     1                 nan  DPP_1
 1  MTUG1_ABO_DPP_2       MTUG1   DPP     2                 nan  DPP_2
 2  MTUG1_ABO_DPP_3       MTUG1   DPP     3                 nan  DPP_3
 3  MTUG1_ABO_DPP_4       MTUG1   DPP     4                 nan  DPP_4
 4  MTUG1_ABO_DPP_5       MTUG1   DPP     5                 nan  DPP_5
 5  MTUG1_ABO_DPU_1       MTUG1   DPU     1                 nan  DPU_1
 6  MTUG1_ABO_DPU_2       MTUG1   DPU     2                 nan  DPU_2
 7  MTUG1_ABO_DPU_3       MTUG1   DPU     3                 nan  DPU_3
 8  MTUG1_ABO_UUB_VDU1_1  MTUG1   UUB     VDU1                1  UUB_VDU1_1
 9  MTUG1_ABO_UUB_VDU1_2  MTUG1   UUB     VDU1                2  UUB_VDU1_2
10  MTUG1_ABO_UUB_VDU1_3  MTUG1   UUB     VDU1                3  UUB_VDU1_3
11  MTUG1_ABO_UUB_VDU2_1  MTUG1   UUB     VDU2                1  UUB_VDU2_1
12  MTUG1_ABO_UUB_VDU2_2  MTUG1   UUB     VDU2                2  UUB_VDU2_2

Спасибо! Он работает отлично! Что означает этот символ ~?

auato 12.12.2020 22:16

Рад, что это помогло! Символ «~» в логическом индексировании означает «не». Таким образом, первая строка выбирает строки, в которых «vdu_num не равно NaN». Рассмотрите возможность принятия ответа в соответствии с рекомендациями stackoverflow.com/help/someone-answers

piterbarg 12.12.2020 22:25

кажется, не соответствует желаемому результату.

Pierre D 12.12.2020 22:29

@PierreD согласен - использовал код OP для случая, который действительно работал, что несколько не соответствовало предоставленному выводу.

piterbarg 12.12.2020 22:31

Вы можете упростить свое разделение (сделать это один раз), а затем также использовать where, чтобы взять unit_num или vdu_num в зависимости от того, что не равно нулю:

df2 = (
    df['resource']
    .str.split('_', expand=True)[[0, 2, 3, 4]]
    .set_axis('Node Unit unit_num vdu_num'.split(), axis=1)
)
df2['vm'] = df2['Unit'].str.cat(
    df2['unit_num'].where(df2['vdu_num'].isnull(), df2['vdu_num']), sep='_')

Или, если вы предпочитаете перезаписать оригинал df:

df = pd.concat([
    df['resource'],
    df['resource']
    .str.split('_', expand=True)[[0, 2, 3, 4]]
    .set_axis('Node Unit unit_num vdu_num'.split(), axis=1)
], axis=1)
df['vm'] = df['Unit'].str.cat(
    df['unit_num'].where(df['vdu_num'].isnull(), df['vdu_num']), sep='_')

Другие вопросы по теме