Вырастите панды датафрейма группа за группой

У меня есть многоиндексный Pandas DataFrame. В моем примере есть два уровня: транспортные средства (с атрибутами A и B) и reference_days (с атрибутами 1 и 2). Для каждого транспортного средства для каждого дня есть набор моментов времени (в строковом формате, например, «2330» соответствует 23:30 и «30» - 0:30). Эти моменты времени упорядочены в хронологическом порядке, но за 1 reference_day они могут пересекать линию «полуночи». То есть момент времени в 02:00 утра может быть посчитан до ПРЕДЫДУЩЕГО дня. Я хочу иметь новый столбец, который принимает значение 1, если момент времени этой строки фактически соответствует «новому» дню (то есть была ли пересечена линия полуночи). Этот пример соответствует расписанию движения поездов, в котором поездки между полуночью и (приблизительно) 4 утра регистрируются за предыдущий день.

Пример:

dict = {"vehicle": ["A"]*8 + ["B"]*8,
        "reference_day" : [1, 1, 1, 1, 2, 2, 2, 2]*2,
        "time" : [1830, 2200, 30, 115, 1700, 1800, 2300, 100,
                  1900, 2300, 15, 200, 1500, 2000, 2330, 120]}
df = pd.DataFrame(dict).reset_index(drop=True).set_index(["vehicle", "reference_day"], drop=True)

DataFrame выглядит так:

                       time
vehicle reference_day      
A       1              1830
        1              2200
        1                30
        1               115
        2              1700
        2              1800
        2              2300
        2               100
B       1              1900
        1              2300
        1                15
        1               200
        2              1500
        2              2000
        2              2330
        2               120

Я хочу иметь дополнительный столбец, как это:

                       time   next_day
vehicle reference_day      
A       1              1830   0
        1              2200   0
        1                30   1
        1               115   1
        2              1700   0
        2              1800   0
        2              2300   0
        2               100   1
B       1              1900   0
        1              2300   0
        1                15   1
        1               200   1
        2              1500   0
        2              2000   0
        2              2330   0
        2               120   1

Как мне добиться этого элегантным способом? Надеюсь, кто-нибудь может помочь, спасибо!

Всего 3 ответа


Давай попробуем:

df['next_day'] = df.groupby(level=[0,1])['time']
                   .transform(lambda x: x.diff().lt(0).cumsum())

Выход:

                       time  next_day
vehicle reference_day                
A       1              1830         0
        1              2200         0
        1                30         1
        1               115         1
        2              1700         0
        2              1800         0
        2              2300         0
        2               100         1
B       1              1900         0
        1              2300         0
        1                15         1
        1               200         1
        2              1500         0
        2              2000         0
        2              2330         0
        2               120         1

Мы также могли бы использовать:

df['next_day']= (df.groupby(level = [0,1])[['time']].diff()
                   .lt(0)
                   .groupby(level = [0,1])['time']
                   .cumsum()
                   .astype(int)
                )
print(df)
                       time  next_day
vehicle reference_day                
A       1              1830         0
        1              2200         0
        1                30         1
        1               115         1
        2              1700         0
        2              1800         0
        2              2300         0
        2               100         1
B       1              1900         0
        1              2300         0
        1                15         1
        1               200         1
        2              1500         0
        2              2000         0
        2              2330         0
        2               120         1

имейте в виду, что это на уровне производительности аналогично groupby.transform , хотя здесь мы группируемся дважды, apply или transform лямбда-функцию несколькими методами, как правило, тоже медленно.


Следующее может помочь?

df['next_day']=(df['time']<400).astype(int)

Есть идеи?

10000