Рекурсивно переупорядочивать данные по парам

У меня есть фрейм данных, содержащий пару ACQ/REL, как показано ниже:

import pandas as pd

data = [
    ['2023-06-05 16:51:27.561','ACQ','location'],    
    ['2023-06-05 16:51:27.564','ACQ','location'],
    ['2023-06-05 16:51:27.567','ACQ','location'],
    ['2023-06-05 16:51:27.571','REL','location'],
    ['2023-06-05 16:51:27.573','REL','location'],
    ['2023-06-05 16:51:27.587','REL','location'],
    ['2023-06-05 16:51:28.559','ACQ','location'],
    ['2023-06-05 16:51:28.561','ACQ','location'],
    ['2023-06-05 16:51:28.563','ACQ','location'],
    ['2023-06-05 16:51:28.566','REL','location'],
    ['2023-06-05 16:51:28.569','REL','location'],
    ['2023-06-05 16:51:28.575','REL','location']
]

df = pd.DataFrame(data,columns=['ts','action','name'])

Я бы реорганизовал его по парам ACQ/REL, внешние пары ACQ/REL как группу, чтобы выходной фрейм данных выглядел следующим образом:

0   2023-06-05 16:51:27.561    ACQ  location
5   2023-06-05 16:51:27.587    REL  location
1   2023-06-05 16:51:27.564    ACQ  location
4   2023-06-05 16:51:27.573    REL  location
2   2023-06-05 16:51:27.567    ACQ  location
3   2023-06-05 16:51:27.571    REL  location
6   2023-06-05 16:51:28.559    ACQ  location
11  2023-06-05 16:51:28.575    REL  location
7   2023-06-05 16:51:28.561    ACQ  location
10  2023-06-05 16:51:28.569    REL  location
8   2023-06-05 16:51:28.563    ACQ  location
9   2023-06-05 16:51:28.566    REL  location

Текущий пример - 3 пары в группе, но это не всегда одно и то же. Каков правильный способ получить такие результаты?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
65
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Если всегда гарантируется, что существует одинаковое количество ACQ и REL, и что они, соответственно, в правильном порядке (т. исходный список сначала на два, по второму элементу, а затем в цикле для вывода одного из каждого списка.

Код:

import pandas as pd

data = [
    ['2023-06-05 16:51:27.561', 'ACQ', 'location'],
    ['2023-06-05 16:51:27.564', 'ACQ', 'location'],
    ['2023-06-05 16:51:27.567', 'ACQ', 'location'],
    ['2023-06-05 16:51:27.571', 'REL', 'location'],
    ['2023-06-05 16:51:27.573', 'REL', 'location'],
    ['2023-06-05 16:51:27.587', 'REL', 'location'],
    ['2023-06-05 16:51:28.559', 'ACQ', 'location'],
    ['2023-06-05 16:51:28.561', 'ACQ', 'location'],
    ['2023-06-05 16:51:28.563', 'ACQ', 'location'],
    ['2023-06-05 16:51:28.566', 'REL', 'location'],
    ['2023-06-05 16:51:28.569', 'REL', 'location'],
    ['2023-06-05 16:51:28.575', 'REL', 'location']
]

df = pd.DataFrame(data, columns=['ts', 'action', 'name'])
# print(df)

data_acq = []
data_rel = []

for index, row in df.iterrows():
    if row['action'] == 'ACQ':
        data_acq.append(row)
    elif row['action'] == 'REL':
        data_rel.append(row)
assert len(data_acq) == len(data_rel)

df_new = pd.DataFrame([], columns=['ts', 'action', 'name'])

for j in range(len(data_acq)):
    df_new = pd.concat([
        df_new,
        pd.DataFrame([
            data_acq[j], data_rel[j]
        ])
    ])
print(df_new)

Выход:

                         ts action      name
0   2023-06-05 16:51:27.561    ACQ  location
3   2023-06-05 16:51:27.571    REL  location
1   2023-06-05 16:51:27.564    ACQ  location
4   2023-06-05 16:51:27.573    REL  location
2   2023-06-05 16:51:27.567    ACQ  location
5   2023-06-05 16:51:27.587    REL  location
6   2023-06-05 16:51:28.559    ACQ  location
9   2023-06-05 16:51:28.566    REL  location
7   2023-06-05 16:51:28.561    ACQ  location
10  2023-06-05 16:51:28.569    REL  location
8   2023-06-05 16:51:28.563    ACQ  location
11  2023-06-05 16:51:28.575    REL  location

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

df.sort_values('ts').assign(sortkey=df.groupby('action').cumcount()).sort_values(['sortkey','action'])

Выход:

                         ts action      name  sortkey
0   2023-06-05 16:51:27.561    ACQ  location        0
3   2023-06-05 16:51:27.571    REL  location        0
1   2023-06-05 16:51:27.564    ACQ  location        1
4   2023-06-05 16:51:27.573    REL  location        1
2   2023-06-05 16:51:27.567    ACQ  location        2
5   2023-06-05 16:51:27.587    REL  location        2
6   2023-06-05 16:51:28.559    ACQ  location        3
9   2023-06-05 16:51:28.566    REL  location        3
7   2023-06-05 16:51:28.561    ACQ  location        4
10  2023-06-05 16:51:28.569    REL  location        4
8   2023-06-05 16:51:28.563    ACQ  location        5
11  2023-06-05 16:51:28.575    REL  location        5
Ответ принят как подходящий

Используя список в качестве стека, вы можете вычислить смещения для REL, которые указывают, насколько далеко назад расположен соответствующий ACQ (т. е. индекс ACQ). Затем отсортируйте индексы в соответствии с скорректированными позициями (ACQ остается в исходной позиции, а REL смещается обратно к позиции ACQ), чтобы получить индексы в новом порядке:

acq     = list()                                # stack of ACQ positions
iREL    = enumerate(x= = "REL" for _,x,_ in data) # identify REL indices

offsets = (acq.pop() if rel else acq.append(i) or i for i,rel in iREL)
order   = (i for i,_ in sorted(enumerate(offsets),key=lambda x:x[::-1]))

data    = [data[i] for i in order]   # reorder data : df.reindex(order)

print(*data,sep = "\n")

['2023-06-05 16:51:27.561', 'ACQ', 'location']
['2023-06-05 16:51:27.587', 'REL', 'location']
['2023-06-05 16:51:27.564', 'ACQ', 'location']
['2023-06-05 16:51:27.573', 'REL', 'location']
['2023-06-05 16:51:27.567', 'ACQ', 'location']
['2023-06-05 16:51:27.571', 'REL', 'location']
['2023-06-05 16:51:28.559', 'ACQ', 'location']
['2023-06-05 16:51:28.575', 'REL', 'location']
['2023-06-05 16:51:28.561', 'ACQ', 'location']
['2023-06-05 16:51:28.569', 'REL', 'location']
['2023-06-05 16:51:28.563', 'ACQ', 'location']
['2023-06-05 16:51:28.566', 'REL', 'location']

Если данные уже находятся в фрейме данных, список order можно использовать для сортировки фрейма данных с помощью метода reindex().

Другие вопросы по теме