Полный рабочий код
import pandas as pd
df = pd.DataFrame(
[['A', 'X', 3], ['A', 'X', 5], ['A', 'Y', 7], ['A', 'Y', 1],
['B', 'X', 3], ['B', 'X', 1], ['B', 'X', 3], ['B', 'Y', 1],
['C', 'X', 7], ['C', 'Y', 4], ['C', 'Y', 1], ['C', 'Y', 6]],
columns=['c1', 'c2', 'v1'])
df['seq'] = df.groupby(['c1', 'c2']).cumcount() + 1
print(df)
Выход
c1 c2 v1 seq
0 A X 3 1
1 A X 5 2
2 A Y 7 1
3 A Y 1 2
4 B X 3 1
5 B X 1 2
6 B X 3 3
7 B Y 1 1
8 C X 7 1
9 C Y 4 1
10 C Y 1 2
11 C Y 6 3
Поскольку Google возвращает этот SO-запрос поверх результатов для tempered greedy token
, я чувствую себя обязанным предоставить более полный ответ.
Ссылка rexegg.com tempered greedy token довольно кратка:
В
blockquote>(?:(?!{END}).)*
квантор*
применяется к точке, но теперь это закаленная точка. Отрицательный lookhhead(?!{END})
утверждает, что то, что следует за текущей позицией, не является строкой{END}
. Поэтому точка никогда не сможет сопоставить открывающую фигуру{END}
, гарантируя, что мы не будем перепрыгивать через разделитель{END}
.То есть: умеренный жадный token является своего рода отрицательным символьным классом для последовательности символа (см. отрицательный класс символов для single характер ).
ПРИМЕЧАНИЕ. Разница между умеренным жадным токеном и классом отрицательных символов заключается в том, что первый не соответствует тексту, отличному от самой последовательности, но single character , который не запускает эту последовательность. То есть
(?:(?!abc|xyz).)+
не будет соответствоватьdef
вdefabc
, но будет соответствоватьdef
иbc
, посколькуa
запускает запрещенныйabc
иbc
этого не делает.Он состоит из:
(?:...)*
- количественная группа, не захватывающая захват (это может быть группа захвата, но она не имеет смысла захватывать каждый отдельный символ) (*
может быть+
, это зависит от того, будет ли ожидаться пустая строка)(?!...)
- отрицательный результат, который фактически налагает ограничение на значение справа от текущего местоположения.
- (или любой (обычно одиночный) символ) шаблон потребления.Однако мы всегда можем дополнительно умерить токен, используя чередование в негативном представлении (например,
(?!{(?:END|START|MID)})
) или заменяя точку совпадения символом с отрицательным символьным классом (например,(?:(?!START|END|MID)[^<>])
при попытке сопоставить текст только внутри тегов).Распределение расходной части
Обратите внимание, что не упоминается конструкция, в которой потребляющая часть (точка в ориге inal tempered greedy token) помещается до . Ответ Авинаша ясно объясняет эту часть:
(.(?!</table>))*
сначала сопоставляет любой символ (но новую строку без модификатора DOTALL), а затем проверяет, не следует ли ему</table>
, что приводит к сбоюe
в<table>table</table>
.Когда использовать умеренный жадный токен?
Rexegg.com дает идею:
- Если мы хотим сопоставить блок текста между разделителем 1 и разделителем 2 без промежуточной подстроки 3 (например,
{START}(?:(?!{(?:MID|RESTART)}).)*?{END}
- Если мы хотим сопоставить блок текста, содержащий специфический шаблон внутри без переполнения последующих блоков (например, вместо ленивого совпадения точек, как в
<table>.*?chair.*?</table>
, мы будем использовать что-то вроде<table>(?:(?!chair|</?table>).)*chair(?:(?!<table>).)*</table>
).- Когда мы хотим совместить кратчайшее возможное окно между двумя строками. Лестное совпадение не поможет, когда вам нужно получить
abc 2 xyz
изabc 1 abc 2 xyz
(см.abc.*?xyz
иabc(?:(?!abc).)*?xyz
).Проблема с производительностью
Закаленный жадный токен является ресурсоемким, так как контрольная проверка выполняется после каждого символ, сопоставляемый с шаблоном потребления. Развертывание техники цикла может значительно увеличить умеренную производительность алгоритма.
Скажем, мы хотим сопоставить
abc 2 xyz
в abc 1 abc 2 xyz 3 xyz . Вместо проверки каждого символа междуabc
иxyz
с помощьюabc(?:(?!abc|xyz).)*xyz
мы можем пропустить все символы, которые не являютсяa
илиx
, с[^ax]*
, а затем соответствуют всемa
, за которыми не следуютbc
(сa(?!bc)
) и всеx
, за которыми не следуетyz
(сx(?!yz)
):abc[^ax]*(?:a(?!bc)[^ax]*|x(?!yz)[^ax]*)*xyz
.
((?!</table>).)*
будет проверять, что этот конкретный символ, который будет согласован, не должен быть начальным символом в строке </table>
. Если да, то только он соответствует этому конкретному символу. *
повторяет то же самое ноль или более раз.
(.(?!</table>))*
соответствует любому символу, только если за ним не следует </table>
, ноль или более раз. Таким образом, это будет соответствовать всем символам внутри тега таблицы excpet последнего символа, так как за последним символом следует </table>
. И следующий шаблон </table>
утверждает, что в конце матча должен быть тег закрывающей таблицы. Это приводит к сбою совпадения.
См. здесь
умеренный токен действительно просто означает:
"соответствует, но только до точки"
blockquote>, как вы делаете это:
вы помещаете токен , который вы не хотите сопоставлять как отрицательный lookahead
(?!notAllowedToMatch)
перед точкой.
(соответствует любому одна вещь), то вы повторяете , что вся вещь со звездой*
:blockquote>
((?!notAllowedToMatch).)*
как это работает:
«смотреть и есть один» снова и снова, перемещая по одному символу слева направо через входную строку до тех пор, пока запрещенная последовательность (или конец строки ), в этот момент матч останавливается.
blockquote>Более подробный ответ Wiktor - это хорошо, я просто подумал, что более простое объяснение было в порядке.