Разделение столбца несколькими пользовательскими разделителями в Python

#python #pandas

Вопрос:

Мне нужно разделить столбец под названием Creative, где каждая ячейка содержит образцы, такие как:

 pn(2021)io(302)ta(Yes)pt(Blue)cn(John)cs(Doe)
 

Где каждый двухбуквенный код, предшествующий каждому пузырьковому разделу (), является заголовком нужного столбца и одинаков в каждой строке. Единственные данные, которые меняются, — это то, что находится внутри пузырьков. Я хочу, чтобы данные выглядели так:

pn io ta Очки cn CS
2021 302 ДА Синий Джон Доу

Я пытался

  df[['Creative', 'Creative Size']] = df['Creative'].str.split('cs(',expand=True)
 

и

 df['Creative Size'] = df['Creative Size'].str.replace(')','')
 

но произошла ошибка, ошибка: missing ), unterminated subpattern at position 2 , предполагая, что это как-то связано с регулярными выражениями.

Есть ли простой способ разделить их ? Спасибо.

Комментарии:

1. попробуйте это df[‘Креативный размер’] = df[‘Креативный размер’].str.замените(‘)’,»)

2. Оба ваших примера связаны с неправильным синтаксисом, например, df [[«Креативный», «Креативный размер»]] = df [«Креативный»]. str.split («cs (» , expand=True) определенно отсутствует апостроф и последняя закрывающая скобка

Ответ №1:

Используйте extract с именованными группами захвата (см. Здесь):

 import pandas as pd

# toy example
df = pd.DataFrame(data=[["pn(2021)io(302)ta(Yes)pt(Blue)cn(John)cs(Doe)"]], columns=["Creative"])

# extract with a named capturing group
res = df["Creative"].str.extract(
    r"pn((?P<pn>d ))io((?P<io>d ))ta((?P<ta>w ))pt((?P<pt>w ))cn((?P<cn>w ))cs((?P<cs>w ))",
    expand=True)

print(res)
 

Выход

      pn   io   ta    pt    cn   cs
0  2021  302  Yes  Blue  John  Doe
 

Ответ №2:

Я бы использовал регулярное выражение для создания списка словарей с помощью понимания. Идея состоит в том, чтобы создать список словарей, каждый из которых представляет строки нужного фрейма данных, а затем построить из него фрейм данных. Я могу построить его в одном вложенном понимании:

 import re
rows = [{r[0]:r[1] for r in re.findall(r'(w{2})((. ))', c)} for c in df['Creative']]
subtable = pd.DataFrame(rows)
for col in subtable.columns:
    df[col] = subtable[col].values
 

В принципе, я регулярно выполняю поиск экземпляров ab(*) и фиксирую двухбуквенный префикс и содержимое круглых скобок и сохраняю их в списке кортежей. Затем я создаю словарь из списка кортежей, каждый из которых по сути является строкой, подобной той, которую вы показываете в своем вопросе. Затем я помещаю их в фрейм данных и вставляю каждый из этих столбцов в исходный фрейм данных. Дайте мне знать, если это вас как-то смущает!

Дэвид

Ответ №3:

Попробуйте с extractall :

 names = df["Creative"].str.extractall("(.*?)(.*?)").loc[0][0].tolist()
output = df["Creative"].str.extractall("((.*?))").unstack()[0].set_axis(names, axis=1)

>>> output
     pn   io   ta    pt    cn   cs
0  2021  302  Yes  Blue  John  Doe
1  2020  301   No   Red  Jane  Doe
 
Вход df:
 df = pd.DataFrame({"Creative": ["pn(2021)io(302)ta(Yes)pt(Blue)cn(John)cs(Doe)", 
                                "pn(2020)io(301)ta(No)pt(Red)cn(Jane)cs(Doe)"]})

 

Ответ №4:

Мы можем использовать str.findall для извлечения совпадающих пар имя-значение столбца

 pd.DataFrame(map(dict, df['Creative'].str.findall(r'(w )((w )')))
 

      pn   io   ta    pt    cn   cs
0  2021  302  Yes  Blue  John  Doe
 

Ответ №5:

Использование регулярных выражений, другой способ упаковки конечного кадра данных:

 import re
import pandas as pd

txt = 'pn(2021)io(302)ta(Yes)pt(Blue)cn(John)cs(Doe)'

data = list(zip(*re.findall('([^(] )(([^)] ))', txt))
df = pd.DataFrame([data[1]], columns=data[0])