Python Pandas группирует DataFrame по блокам последовательных значений

У меня есть большой DataFrame pandas, имеющий столбец метки времени, столбец значений, столбец «ключ» и столбец с флагом, указывающим конец блока (и еще несколько на самом деле)

timestamp, value, key, last_in_block
12345, 1.0, 2, False <-- start of block 1
12346, 0.5, 4, False
12347, 1.2, 1, False
12348, 2.2, 6, False
12349, 1.5, 3, False
12350, 1.2, 3, False
12351, 2.3, 3, False
12352, 0.4, 5, True
12371, 1.3, 2, False <-- start of block 2
12372, 0.9, 4, False
12373, 1.7, 1, False
12374, 2.0, 6, False
12375, 1.2, 3, False
12376, 1.4, 3, False
12377, 2.7, 3, False
12378, 0.8, 5, True
...

В столбце «ключ» появляется характерная последовательность значений (в данном примере 2 4 5 6 3 3 3 5), идентифицирующая блок данных. Я хотел бы применить оператор groupBy, чтобы разбить фрейм на группы по блокам. Это/как это возможно?

df = pd.DataFrame(data =
              {"timestamp": list(range(12345,12353)) + list(range(12371,12379)),
                "value": [1.0,0.5,1.2,2.2,1.5,1.2,2.3,0.4,1.3,0.9,1.7,2.0,1.2,1.4,2.7,0.8],
                "key": [2,4,1,6,3,3,3,5]*2,
               "last_in_block" : [False]*7+[True]+[False]*7+[True]})

Обновление, ответы на вопросы:

  • Я заранее знал последовательность
  • Последовательности полны, за очень редкими исключениями.

Знаете ли вы эту последовательность заранее? Его длина? Если нет, то всегда ли оно завершено? Пожалуйста, дайте некоторый контекст, поскольку в настоящее время трудно понять, как это обобщает.

mozway 20.03.2024 14:18

@mozway: я улучшил описание выше в соответствии с вашими вопросами.

WolfiG 20.03.2024 14:30

спасибо за обновление, если у вас есть флаг, это легко, см. ниже ;)

mozway 20.03.2024 15:13
Почему в 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 может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
3
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать last_in_block для обозначения групп, а затем использовать groupby:

df["last_in_block"] = np.where(df["last_in_block"].shift(), 1, 0)
df["last_in_block"] = df["last_in_block"].cumsum()
grouped = df.groupby("last_in_block")

grouped.groups:

{1: [0, 1, 2, 3, 4, 5, 6, 7], 2: [8, 9, 10, 11, 12, 13, 14, 15]}

grouped.mean():

               timestamp   value    key
last_in_block                          
1                12348.5  1.2875  3.375
2                12374.5  1.5000  3.375

Если у вас есть флаг для последнего элемента в блоке, вы можете использовать обратную cumsum для формирования групп:

group = df.loc[::-1, 'last_in_block'].cumsum()
for k, g in df.groupby(group, sort=False):
    print(g)

В качестве альтернативы, если вы не знали периодичность и не имели флага, вы могли оценить периодичность с помощью автокорреляции (autocorr) по ключу, периодичность, соответствующая задержке с максимальной корреляцией:

lag = pd.Series({i: df['key'].autocorr(i)
                 for i in range(1, len(s)//2+1)}
               ).idxmax()
# periodicity: 8

group = np.arange(len(df))//lag

for k, g in df.groupby(group, sort=False):
    print(g)

Выход:

   timestamp  value  key  last_in_block
0      12345    1.0    2          False
1      12346    0.5    4          False
2      12347    1.2    1          False
3      12348    2.2    6          False
4      12349    1.5    3          False
5      12350    1.2    3          False
6      12351    2.3    3          False
7      12352    0.4    5           True
    timestamp  value  key  last_in_block
8       12371    1.3    2          False
9       12372    0.9    4          False
10      12373    1.7    1          False
11      12374    2.0    6          False
12      12375    1.2    3          False
13      12376    1.4    3          False
14      12377    2.7    3          False
15      12378    0.8    5           True

График автокорреляции:

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