В моем случае у нас есть временные ряды с разных устройств, но некоторые устройства не могли отправить какое-либо значение в течение некоторого периода времени. Таким образом, мы должны создавать значения NA для каждого устройства и период времени, а затем делать fillna.
df = pd.DataFrame([["device1", 1, 'first val of device1'], ["device2", 2, 'first val of device2'], ["device3", 3, 'first val of device3']])
df.pivot(index=1, columns=0, values=2).fillna(method='ffill').unstack().reset_index(name='value')
Результат:
0 1 value
0 device1 1 first val of device1
1 device1 2 first val of device1
2 device1 3 first val of device1
3 device2 1 None
4 device2 2 first val of device2
5 device2 3 first val of device2
6 device3 1 None
7 device3 2 None
8 device3 3 first val of device3
Один из способов сделать это - использовать findall
с регулярным выражением, которое с жадностью совпадает с вещами, которые могут проходить между разделителями. например:
>>> s = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> r = re.compile(r'(?:[^,(]|\([^)]*\))+')
>>> r.findall(s)
['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']
Повторное выражение выше соответствует одному или нескольким:
. Одна из особенностей этого подхода состоит в том, что соседние разделители рассматриваются как один разделитель. То есть вы не увидите пустую строку. Это может быть ошибка или функция в зависимости от вашего прецедента.
Также обратите внимание, что регулярные выражения not подходят для случаев, когда вложенность является возможностью. Так, например, это будет неправильно разбито:
"Wilbur Smith (son of John (Johnny, son of James), aka Billy), Eddie Murphy (John)"
Если вам нужно иметь дело с вложением, лучшим выбором будет разбиение строки на парсеры, запятые и все остальное (в основном, токенизация - это часть все равно может выполняться с помощью регулярных выражений), а затем пройдите через те маркеры, которые снова собирают поля, отслеживая уровень вашего гнездования, когда вы идете (это отслеживание уровня вложенности - это то, что регулярные выражения не могут делать самостоятельно).
s = re.split(r',\s*(?=[^)]*(?:\(|$))', x)
Представление соответствует всем значениям до следующей открытой или в конце строки, если между ними нет закрывающей скобки. Это гарантирует, что запятая не находится внутри набора круглых скобок.
Этот пост мне очень помог. Я искал разбиение строки запятыми, расположенными вне кавычек. Я использовал это как стартер. Моя последняя строка кода была regEx = re.compile(r'(?:[^,"]|"[^"]*")+')
. Это сделал трюк. Спасибо тонну.
Я, конечно, согласен с @Wogan выше, что использование CSV moudle - хороший подход. Сказав, что если вы все еще хотите попробовать регулярное выражение, попробуйте, но вам придется адаптировать его к диалекту Python
string.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/)
HTH
Вот общий метод, который я использовал в прошлом для таких случаев:
Используйте функцию sub
модуля re
с функцией в качестве аргумента замены. Функция отслеживает открытие и закрытие парсеров, кронштейнов и брекетов, а также одиночные и двойные кавычки и выполняет замену только за пределами таких заключенных в скобки и подкатегорий. Затем вы можете заменить запятые без кавычек на другой символ, который, как вы уверены, не отображается в строке (я использую код ASCII / Unicode group-separator: chr (29)), а затем простую строку. раскол на этот символ. Вот код:
import re
def srchrepl(srch, repl, string):
"""Replace non-bracketed/quoted occurrences of srch with repl in string"""
resrchrepl = re.compile(r"""(?P<lbrkt>[([{])|(?P<quote>['"])|(?P<sep>["""
+ srch + """])|(?P<rbrkt>[)\]}])""")
return resrchrepl.sub(_subfact(repl), string)
def _subfact(repl):
"""Replacement function factory for regex sub method in srchrepl."""
level = 0
qtflags = 0
def subf(mo):
nonlocal level, qtflags
sepfound = mo.group('sep')
if sepfound:
if level == 0 and qtflags == 0:
return repl
else:
return mo.group(0)
elif mo.group('lbrkt'):
level += 1
return mo.group(0)
elif mo.group('quote') == "'":
qtflags ^= 1 # toggle bit 1
return "'"
elif mo.group('quote') == '"':
qtflags ^= 2 # toggle bit 2
return '"'
elif mo.group('rbrkt'):
level -= 1
return mo.group(0)
return subf
Если у вас нет nonlocal
в вашей версии Python, просто измените его на global
и определите level
и qtflags
на уровне модуля.
Вот как он используется:
>>> GRPSEP = chr(29)
>>> string = "Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> lst = srchrepl(',', GRPSEP, string).split(GRPSEP)
>>> lst
['Wilbur Smith (Billy, son of John)', ' Eddie Murphy (John)', ' Elvis Presley', ' Jane Doe (Jane Doe)']
split by ")"
>>> s="Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)"
>>> s.split(")")
['Wilbur Smith (Billy, son of John', ', Eddie Murphy (John', ', Elvis Presley, Jane Doe (Jane Doe', '']
>>> for i in s.split(")"):
... print i.split("(")
...
['Wilbur Smith ', 'Billy, son of John']
[', Eddie Murphy ', 'John']
[', Elvis Presley, Jane Doe ', 'Jane Doe']
['']
вы можете продолжить проверку, чтобы получить те имена, которые не входят с ().
Попытка читаемого пользователем регулярного выражения:
import re
regex = re.compile(r"""
# name starts and ends on word boundary
# no '(' or commas in the name
(?P<name>\b[^(,]+\b)
\s*
# everything inside parentheses is a role
(?:\(
(?P<role>[^)]+)
\))? # role is optional
""", re.VERBOSE)
s = ("Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley,"
"Jane Doe (Jane Doe)")
print re.findall(regex, s)
Выход:
[('Wilbur Smith', 'Billy, son of John'), ('Eddie Murphy', 'John'),
('Elvis Presley', ''), ('Jane Doe', 'Jane Doe')]
Мой ответ не будет использовать регулярное выражение.
Я думаю, что должен работать простой сканер символов с состоянием «in_actor_name
». Помните, что состояние «in_actor_name
» заканчивается либо «)», либо запятой в этом состоянии.
Моя попытка:
s = 'Wilbur Smith (Billy, son of John), Eddie Murphy (John), Elvis Presley, Jane Doe (Jane Doe)'
in_actor_name = 1
role = ''
name = ''
for c in s:
if c == ')' or (c == ',' and in_actor_name):
in_actor_name = 1
name = name.strip()
if name:
print "%s: %s" % (name, role)
name = ''
role = ''
elif c == '(':
in_actor_name = 0
else:
if in_actor_name:
name += c
else:
role += c
if name:
print "%s: %s" % (name, role)
Выход:
Wilbur Smith: Billy, son of John
Eddie Murphy: John
Elvis Presley:
Jane Doe: Jane Doe
Ни один из приведенных выше ответов не является правильным, если в ваших данных есть какие-либо ошибки или шум.
Легко придумать хорошее решение, если вы знаете, что данные правильны каждый раз. Но что произойдет, если есть ошибки форматирования? Что вы хотите добиться?
Предположим, что вложенные круглые скобки? Предположим, что есть несогласованные круглые скобки? Предположим, что строка заканчивается запятой или начинается с запятой или имеет две строки?
Все вышеупомянутые решения будут вызывать больше или меньше мусора и не сообщать об этом вам.
Если бы это зависело от меня, я бы начал с довольно строгим ограничением на то, что «правильные» данные были: никаких скобок вложенности, не совпадающих круглых скобок и без пустых сегментов до, между или после комментариев - подтвердите, когда я пошел, а затем поднимите исключение, если я не смог проверить.
Я думаю, что лучший способ приблизиться к этому - использовать встроенный модуль csv python.
Поскольку только модуль csv позволяет a один символ quotechar
, вам нужно будет сделать замену на ваших входах, чтобы преобразовать ()
в нечто вроде |
или "
. Затем убедитесь, что вы используете соответствующий диалект и не двигаетесь.
r = [re.sub(r'\([^)]*\)', '', s) for s in r]
. Если вам нужен более подробный ответ, вероятно, вы должны задать отдельный вопрос. – Laurence Gonsalves 18 November 2013 в 20:53