Дублировать последнюю строку группы/идентификатора в фрейме данных на основе определенного условия

У меня есть следующий фрейм данных:

#Load the required libraries
import pandas as pd

#Create dataset
data = {'id': [1, 1, 1, 1, 1,1, 1, 1, 1, 1, 1,
               2, 2,
               3, 3, 3, 3, 3, 3,
               4, 
               5, 5, 5, 5, 5,5, 5, 5,5],
        'cycle': [1,2, 3, 4, 5,6,7,8,9,10,11,
                  1,2, 
                  1,2, 3, 4, 5,6,
                  1,
                  1,2, 3, 4, 5,6,7,8,9,],
        'Salary': [7, 7, 7,8,9,10,11,12,13,14,15,
                   4, 5,
                   8,9,10,11,12,13,
                   8,
                   7, 7,9,10,11,12,13,14,15,],
        'Children': ['No', 'Yes', 'Yes', 'Yes', 'Yes', 'No','No', 'Yes', 'Yes', 'Yes', 'No',
                     'Yes', 'No', 
                     'No','Yes', 'Yes', 'No','No', 'Yes',
                     'Yes',
                      'No',  'Yes', 'No', 'No', 'Yes', 'Yes', 'Yes', 'Yes', 'No',],
        'Days': [123, 128, 66, 66, 120, 141, 52,96, 120, 141, 52,
                 96, 120,
                 15,123, 128, 66, 120, 141,
                 141,
                 123, 128, 66, 123, 128, 66, 120, 141, 52,],
        }

#Convert to dataframe
df = pd.DataFrame(data)
print("df = \n", df)

Приведенный выше фрейм данных выглядит так:

Здесь каждый идентификатор имеет разные циклы в соответствии со столбцом «цикл». Например,

id-1 имеет максимум 11 циклов.

id-2 имеет максимум 2 цикла.

id-3 имеет максимум 6 циклов.

id-4 имеет максимум 1 цикл.

id-5 имеет максимум 9 циклов.

У меня есть определенный пороговый предел для «циклов». Скажем, цикл_порог = 3

Если максимальное количество циклов для и id <= cycle_threshold, то дублируйте последнюю строку этой группы/идентификатора, пока цикл не достигнет 4.

Например,

Для id-2, поскольку максимальное количество циклов равно 2 (что меньше 3), повторяйте последнюю строку id-2, пока цикл не станет 4.

Для id-4, поскольку максимальное количество циклов равно 1 (что меньше 3), повторяйте последнюю строку id-4, пока цикл не станет 4.

Остальные группы/идентификаторы остаются прежними.

Результат выглядит так:

Может кто-нибудь, пожалуйста, дайте мне знать, как мне выполнить эту задачу в Python?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вы можете определить id, сравнив максимальные значения cycle для групп, а для отфильтрованных групп создайте MultiIndex.from_product и повторите последнее значение с помощью DataFrame.reindex с параметром method='ffill':

cycle_threshold = 3
M = 4

#get maximal cycle per id
s = df.groupby('id')['cycle'].max()

#get id less or equal threshold
ids = s.index[s.le(cycle_threshold)]

#test groups by id match list ids
mask = df['id'].isin(ids)

#create MultiIndex with range(1,M + 1) for filtered groups
df1 = df[mask].set_index(['id','cycle'])
mux = pd.MultiIndex.from_product([ids, range(1, M + 1)], names=['id','cycle'])

#append new groups with sorting by id and cycle
df2 = (pd.concat([df[~mask],
                 df1.reindex(mux, method='ffill').reset_index()])
          .sort_values(['id','cycle'], ignore_index=True))

Другая идея - создать окончательный MultiIndex и переиндексировать все строки:

cycle_threshold = 3
M = 4

s = df.groupby('id')['cycle'].max()
ids = s.index[s.le(cycle_threshold)]

mask = df['id'].isin(ids)

df2 = df.set_index(['id','cycle'])
mux = (pd.MultiIndex.from_product([ids, range(1, 5)], 
                                 names=['id','cycle']).append(df2[~mask.to_numpy()].index)
        .sort_values())
df2 = df2.reindex(mux, method='ffill').reset_index()

print (df2)
    id  cycle  Salary Children  Days
0    1      1       7       No   123
1    1      2       7      Yes   128
2    1      3       7      Yes    66
3    1      4       8      Yes    66
4    1      5       9      Yes   120
5    1      6      10       No   141
6    1      7      11       No    52
7    1      8      12      Yes    96
8    1      9      13      Yes   120
9    1     10      14      Yes   141
10   1     11      15       No    52
11   2      1       4      Yes    96
12   2      2       5       No   120
13   2      3       5       No   120
14   2      4       5       No   120
15   3      1       8       No    15
16   3      2       9      Yes   123
17   3      3      10      Yes   128
18   3      4      11       No    66
19   3      5      12       No   120
20   3      6      13      Yes   141
21   4      1       8      Yes   141
22   4      2       8      Yes   141
23   4      3       8      Yes   141
24   4      4       8      Yes   141
25   5      1       7       No   123
26   5      2       7      Yes   128
27   5      3       9       No    66
28   5      4      10       No   123
29   5      5      11      Yes   128
30   5      6      12      Yes    66
31   5      7      13      Yes   120
32   5      8      14      Yes   141
33   5      9      15       No    52

Создайте фрейм данных с повторяющимися строками, затем соедините его с исходным и, наконец, отсортируйте его:

import numpy as np

cycle_threshold = 3

def fix_cycle(df):
    lgt = len(df)
    if lgt < cycle_threshold:
        df1 = df.reindex(df.index[-1].repeat(cycle_threshold - lgt + 1))
        df1['cycle'] += np.arange(len(df1)) + 1
        return df1

df1 = df.groupby('id').apply(fix_cycle).droplevel(0)
out = pd.concat([df, df1]).sort_index(kind='stable', ignore_index=True)

Выход:

>>> out
    id  cycle  Salary Children  Days
0    1      1       7       No   123
1    1      2       7      Yes   128
2    1      3       7      Yes    66
3    1      4       8      Yes    66
4    1      5       9      Yes   120
5    1      6      10       No   141
6    1      7      11       No    52
7    1      8      12      Yes    96
8    1      9      13      Yes   120
9    1     10      14      Yes   141
10   1     11      15       No    52
11   2      1       4      Yes    96
12   2      2       5       No   120
13   2      3       5       No   120  # <- HERE
14   2      4       5       No   120  # <- HERE
15   3      1       8       No    15
16   3      2       9      Yes   123
17   3      3      10      Yes   128
18   3      4      11       No    66
19   3      5      12       No   120
20   3      6      13      Yes   141
21   4      1       8      Yes   141
22   4      2       8      Yes   141  # <- HERE
23   4      3       8      Yes   141  # <- HERE
24   4      4       8      Yes   141  # <- HERE
25   5      1       7       No   123
26   5      2       7      Yes   128
27   5      3       9       No    66
28   5      4      10       No   123
29   5      5      11      Yes   128
30   5      6      12      Yes    66
31   5      7      13      Yes   120
32   5      8      14      Yes   141
33   5      9      15       No    52

Подробности:

>>> df1
    id  cycle  Salary Children  Days
12   2      3       5       No   120
12   2      4       5       No   120
19   4      2       8      Yes   141
19   4      3       8      Yes   141
19   4      4       8      Yes   141

@Corralien... Я получаю сообщение об ошибке в строке "1: = ".... не могли бы вы сообщить мне о проблеме?

NN_Developer 05.04.2023 06:37

Это не 1, а l (нижний L) и := — оператор моржа (python >= 3.8)

Corralien 05.04.2023 07:16

Получил вашу точку зрения. Поскольку у меня python 3.7.6, я получаю сообщение об ошибке.

NN_Developer 05.04.2023 07:30

Я обновил свой ответ для вашей версии Python. Преимущество использования внешнего фрейма данных заключается в том, что вы можете отслеживать, какие строки были добавлены, а какие — из исходного набора данных.

Corralien 05.04.2023 07:36

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