Учитывая тестовый набор данных следующим образом:
city district ... Q3:*your age[open question] Q4:*skill[open question]
0 bj cy ... 45 R
1 bj cy ... 34 Python
Мне нужно переименовать столбцы с помощью регулярного выражения для извлечения содержимого между *
и [
, а также удалить your
, если они существуют. Обратите внимание, что в реальном случае у меня много столбцов вопросов, как показано ниже.
df.columns
Out[112]:
Index(['city', 'district', 'name', 'Q1:*your tel[open question]',
'Q2:*your profession[close question]', 'Q3:*your age[open question]',
'Q4:*skill[open question]'],
dtype='object')
Ожидаемые столбцы будут такими:
['city', 'district', 'name', 'tel', 'profession', 'age', 'skill']
Как я мог сделать это в Pandas и регулярном выражении? Заранее большое спасибо.
df13 = df.filter(regex = '^[^Q]', axis = 1) #Isolate columns without Q
df12 = df.filter(regex = '^Q', axis = 1) #isolate columns with Q
x = df.filter(regex = '^Q', axis = 1).reindex(df.filter(regex = '^Q', axis = 1).\
columns.str.findall('([a-z]+(?=\[))').str.join(','),\
axis = "columns").columns # transform column names with q
df12.columns=list(x) # reset df12 column names
pd.concat([df13, df12], axis = 1)
Пример данных
df=pd.DataFrame({'city':[1], 'district':[1], 'name':[1], 'Q1:*your tel[open question]':[1],
'Q2:*your profession[close question]':[1], 'Q3:*your age[open question]':[1],
'Q4:*skill[open question]':[1]})
печать (дф)
city district name Q1:*your tel[open question] \
0 1 1 1 1
Q2:*your profession[close question] Q3:*your age[open question] \
0 1 1
Q4:*skill[open question]
0 1
Исход
city district name tel profession age skill
0 1 1 1 1 1 1 1
Пытаться:
cols = []
for i in df.columns:
if re.search(r'Q\d:',i) != None:
cols.append(re.match(r'^Q\d:\*(your\s)?([\w]*)',i).group(2))
else:
cols.append(i)
Замена Oneliner выше:
[(re.match(r'^Q\d:\*(your\s)?([\w]*)',i).group(2)) if re.search(r'Q\d:',i) is not None else i for i in df.columns]
Обе печати:
['city', 'district', 'name', 'tel', 'profession', 'age', 'skill']
О, в этом шаблоне регулярного выражения есть две группы захвата: одна для необязательного (your\s)?
и одна для фактической строки, которую вы хотите использовать в качестве имени столбца ([\w]*)
. Поэтому я использую group(2)
для захвата второго значения группы захвата.
только что заметил, что это похоже на то, что @ralubrusto также использовал в своем ответе col: re.search(pattern, col).group(2).strip()
Да, я пробую свои реальные данные с помощью if re.search(r'Q\d:',i) != None: print(cols)
, но он возвращает несколько пустых списков. Я не понял, почему это происходит. Нет этих ошибок для решения @ralubrusto.
Всякий раз, когда вы сталкиваетесь с такими проблемами, вы можете дать себе время подумать, какой шаблон соответствует тому, что вы хотите. Для этого я бы порекомендовал этот сайт, где вы можете вставить целевой текст и попробовать некоторые шаблоны. Это занимает некоторое время, но именно так мы и учимся (регулярные выражения всегда являются хорошей тренировкой для мозга).
В вашем случае желаемый шаблон — это r'\*(your)?(.*)\['
, где вторая совпадающая группа — это слово, которое будет новым именем столбца. Итак, вы можете попробовать что-то вроде:
import re
pattern = r'\*(your)?(.*)\['
print('# Before\n', df.columns)
df = df.rename({
col: re.search(pattern, col).group(2).strip()
if re.search(pattern, col)
else col
for col in df.columns
}, axis=1)
print('# After\n', df.columns)
И вывод будет:
# Before
Index(['city', 'district', 'name', 'Q1:*your tel[open question]',
'Q2:*your profession[close question]', 'Q3:*your age[open question]',
'Q4:*skill[open question]'],
dtype='object')
# After
Index(['city', 'district', 'name', 'tel', 'profession', 'age', 'skill'], dtype='object')
Спасибо, regex101.com тоже весьма полезен.
Я полагаю, вы использовали два шаблона, не могли бы вы опубликовать их в части кода, чтобы я мог проверить?
Извините, есть только один шаблон, но я забыл добавить его в ответ. Я отредактирую это прямо сейчас
Я не понимаю, с этим узором, как получается Q4:*skill[open question]
, у которого нет your
внутри?
Он имеет ?
после (your)
, что означает, что он будет соответствовать 0 или 1 вхождению your
. Попробуйте, и вы увидите, как это работает
Спасибо, что означает
group(2)
в вашем коде?