#python #pandas
Вопрос:
У меня есть очень грязный столбец во фрейме данных, который содержит следующие данные.
ID | код |
---|---|
1 | A312B-D |
2 | BAFDA-BAFDC |
3 | BFD3-5 |
4 | B3140-B3142 |
Я хочу проанализировать столбец кода со следующим выводом:
ID | код |
---|---|
1 | A312B A312C A312D |
2 | BAFDA BAFDB BAFDC |
3 | BFD3 BFD4 BFD5 |
4 | B3140 B3141 B3142 |
Таким образом, основное правило состоит в том, что если исходное значение кода содержит 2 или более символов, содержит тире, и либо за тире следует одна буква или число (т. е. «XXXX1-3»), либо строка одинаковой длины до и после тире (т. е. «XXXX1-XXXX3»), то мы разделяем ее на отдельные значения, разделенные пробелом.
Потратил на это несколько часов, но не смог найти решения, надеюсь получить некоторую помощь.
Комментарии:
1. Я ценю, что вы много работали над этим, но пока мы не увидим некоторые примеры вашего кода, трудно понять, с какой частью проблемы у вас возникли проблемы.
Ответ №1:
Вы можете использовать Панд apply
с функцией ( expand
в примере), использующей регулярное выражение, чтобы разделить код на группы захвата, и, используя преимущества уже существующих групп регулярных выражений, используйте группы как для определения того, является ли это буквой или цифрой, так и range
для создания шаблона для этих символов.
import pandas as pd
import re
d = {
'id ': {0: 1, 1: 2, 2: 3, 3: 4},
'code': {0: 'A312B-D', 1: 'BAFDA-BAFDC', 2: 'BFD3-5', 3: 'B3140-B3142'}
}
df = pd.DataFrame(d)
print(df)
regex = re.compile(r'(.*?)(d |[A-Z])-(.*?)(d |[A-Z])
Вывод из df
id code code_ext
0 1 A312B-D A312B A312C A312D
1 2 BAFDA-BAFDC BAFDA BAFDB BAFDC
2 3 BFD3-5 BFD3 BFD4 BFD5
3 4 B3140-B3142 B3140 B3141 B3142
)
def expand(code):
m = regex.findall(code)
if m:
if m[0][1].isdigit():
new_range = [f'{m[0][0]}{num}' for num in range(int(m[0][1]), int(m[0][3]) 1)]
else:
new_range = [f'{m[0][0]}{chr(num)}' for num in range(ord(m[0][1]), ord(m[0][3]) 1)]
return " ".join(new_range)
return code
df['code_ext'] = df['code'].apply(expand)
print(df)
Вывод из df