замена столбца в фрейме данных с помощью регулярного выражения

#python #pandas

#python #pandas

Вопрос:

У меня есть фрейм данных с 4 столбцами, col4 — это строка, включающая тексты и цифры:

  Col1           Col2              Col3           Col4
Syslog        2016,09,17           1    PD380_003 %LINK-3-UPDOWN
Syslog        2016,09,17           1    NM380_005 %BGP-5-NBR_RESET
Syslog        2016,09,14           1    NM380_005 %BGP-5-NBR_RESET
Syslog        2016,09,08           1    DO NOT TICKET LO380_004 %SYS-5-CONFIG_I Config
  

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

 data.replace({'Col4':{'.*':'([A-Z]{2}[0-9]{3}_[0-9]{3})'}},regex=True)
  

желаемый результат:

  Col1           Col2              Col3           Col4
Syslog        2016,09,17           1           PD380_003
Syslog        2016,09,17           1           NM380_005
Syslog        2016,09,14           1           LO380_004
Syslog        2016,09,08           1           LO380_004
  

но результат, который я получаю, выглядит так:

  Col1           Col2              Col3           Col4
Syslog        2016,09,17           1    ([A-Z]{2}[0-9]{3}_[0-9]{3})
Syslog        2016,09,17           1    ([A-Z]{2}[0-9]{3}_[0-9]{3})
Syslog        2016,09,14           1    ([A-Z]{2}[0-9]{3}_[0-9]{3})
Syslog        2016,09,08           1    ([A-Z]{2}[0-9]{3}_[0-9]{3})
  

что я делаю не так?

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

1. можете ли вы опубликовать свой data DF перед заменой?

2. да, пожалуйста, проверьте это еще раз.

Ответ №1:

Во-первых, у вас неправильные регулярные выражения в неправильных позициях. to_replace Аргумент .replace должен соответствовать тому, что нужно заменить, а что удалить. Итак, в этом случае вам нужно a ^.* перед и a .*$ за вашим регулярным выражением, поскольку вы хотите обрезать строку вне соответствия:

 ^.*([A-Z]{2}[0-9]{3}_[0-9]{3}).*$
  

ДЕМОНСТРАЦИЯ

Во-вторых, replace аргумент, если это регулярное выражение, должен быть группой захвата или фиксированной строкой. В этом случае 1 подойдет.

Наконец, форма серии .replace имеет более простой синтаксис (по крайней мере, для меня) для понимания.

Итак, учитывая:

 >>> df
     Col1        Col2  Col3                                            Col4
0  SysLog  2016,09,17     1                        PD380_003 %LINK-3-UPDOWN
1  SysLog  2016,09,17     1                      NM380_005 %BGP-5-NBR_RESET
2  SysLog  2016,09,17     1                      NM380_005 %BGP-5-NBR_RESET
3  SysLog  2016,09,17     1  DO NOT TICKET LO380_004 %SYS-5-CONFIG_I Config
  

Вы можете сделать:

 >>> df['Col4'].replace(to_replace='^.*([A-Z]{2}[0-9]{3}_[0-9]{3}).*$', value=r'1', regex=True) 
0    PD380_003
1    NM380_005
2    NM380_005
3    LO380_004
Name: Col4, dtype: object
  

Вы также можете использовать версию позиционного аргумента, если проще:

 df['Col4'].replace('^.*([A-Z]{2}[0-9]{3}_[0-9]{3}).*$', r'1', regex=True)
  

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

Наконец, назначьте непосредственно в оригинал:

 >>> df['Col4']=df['Col4'].replace('^.*([A-Z]{2}[0-9]{3}_[0-9]{3}).*$', r'1', regex=True)
>>> df
     Col1        Col2  Col3       Col4
0  SysLog  2016,09,17     1  PD380_003
1  SysLog  2016,09,17     1  NM380_005
2  SysLog  2016,09,17     1  NM380_005
3  SysLog  2016,09,17     1  LO380_004
  

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

1. спасибо за объяснение, я новичок в Panda, это объяснение помогает 🙂

Ответ №2:

Я думаю, вам нужно extract :

 data.Col4 = data.Col4.str.extract('([A-Z]{2}[0-9]{3}_[0-9]{3})', expand=False)

print (data)
     Col1        Col2  Col3       Col4
0  Syslog  2016,09,17     1  PD380_003
1  Syslog  2016,09,17     1  NM380_005
2  Syslog  2016,09,14     1  NM380_005
3  Syslog  2016,09,08     1  LO380_004
  

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

1. да, это работает, но мне просто интересно, почему replace не может прочитать регулярное выражение?

2. Хм, я проверяю документы , и это может сработать.

3. Но я думаю, что это ошибка.

Ответ №3:

Вы неправильно использовали регулярные выражения.

{'Col4':{'.*':'([A-Z]{2}[0-9]{3}_[0-9]{3})'}} — означает замену любой строки в Col4 столбце на '([A-Z]{2}[0-9]{3}_[0-9]{3})'

Попробуйте это:

 In [87]: df.replace({'Col4':{r'.*?([A-Z]{2}[0-9]{3}_[0-9]{3}).*':r'1'}}, regex=True)
Out[87]:
     Col1        Col2  Col3       Col4
0  Syslog  2016,09,17     1  PD380_003
1  Syslog  2016,09,17     1  NM380_005
2  Syslog  2016,09,14     1  NM380_005
3  Syslog  2016,09,08     1  LO380_004