Вычислить разницу в минутах на основе 30-минутного интервала? - PullRequest
3 голосов
/ 10 мая 2019

У меня был df, такой как

ID  | Half Hour Bucket | clock in time  | clock out time  | Rate
232 | 4/1/19 8:00 PM   | 4/1/19 7:12 PM | 4/1/19 10:45 PM | 0.54
342 | 4/1/19 8:30 PM   | 4/1/19 7:12 PM | 4/1/19 7:22 PM  | 0.23
232 | 4/1/19 7:00 PM   | 4/1/19 7:12 PM | 4/1/19 10:45 PM | 0.54

Я хочу, чтобы мой вывод был

 ID | Half Hour Bucket | clock in time  | clock out time  | Rate | Mins
232 | 4/1/19 8:00 PM   | 4/1/19 7:12 PM | 4/1/19 10:45 PM | 0.54 |
342 | 4/1/19 8:30 PM   | 4/1/19 7:12 PM | 4/1/19 7:22 PM  | 0.23 |
232 | 4/1/19 7:00 PM   | 4/1/19 7:12 PM | 4/1/19 10:45 PM | 0.54 |

Где минуты представляют собой разницу между временем на выходе и временем на часах.

Но я могу содержать значение минут только для получасового сегмента в той же строке, которой оно соответствует.

Например, для идентификатора 342 это будет десять минут, и 10 минут будут в этом ряду.

Но для идентификатора 232 время на входе составляет 3 часа. Я хотел бы только 30 минут для 8 до 830 в первом ряду и 18 минут в третьем ряду. для минут в полчаса, таких как 830-9 или 9-930, которых нет в первом ряду, я бы хотел создать новую строку в том же самом df, которая содержит nans для всего, кроме полчаса и поля mins для минуты, которых нет в исходной строке.

30 минут с 8-830 останутся в первом ряду, но я бы хотел 5 новых рядов для всех полчасов, которые не являются 4/1/19 8:00 PM как новые ряды только с полчаса и скоростью, переносимой с ряда. Это возможно?

Я благодарю всех за уделенное время!

1 Ответ

1 голос
/ 12 мая 2019

Понял, что мой первый ответ, вероятно, был не тем, что вы хотели.Эта версия, надеюсь, есть.Это было немного сложнее, чем я предполагал вначале!

Создание данных

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

import math
import numpy as np
import pandas as pd

# Create a dataframe to work with from the data provided in the question
columns = ['id', 'half_hour_bucket', 'clock_in_time', 'clock_out_time' , 'rate']

data = [[232, '4/1/19 8:00 PM', '4/1/19 7:12 PM', '4/1/19 10:45 PM', 0.54],
        [342, '4/1/19 8:30 PM', '4/1/19 7:12 PM', '4/1/19 07:22 PM ', 0.23],
        [232, '4/1/19 7:00 PM', '4/1/19 7:12 PM', '4/1/19 10:45 PM', 0.54]]

df = pd.DataFrame(data, columns=columns)

def convert_cols_to_dt(df):
    # Convert relevant columns to datetime format
    for col in df:
        if col not in ['id', 'rate']:
            df[col] = pd.to_datetime(df[col])

    return df

df = convert_cols_to_dt(df)
# Create the mins column
df['mins'] = (df.clock_out_time - df.clock_in_time)

Вывод:

  id  half_hour_bucket    clock_in_time       clock_out_time      rate mins
0 232 2019-04-01 20:00:00 2019-04-01 19:12:00 2019-04-01 22:45:00 0.54 0 days 03:33:00.000000000
1 342 2019-04-01 20:30:00 2019-04-01 19:12:00 2019-04-01 19:22:00 0.23 0 days 00:10:00.000000000
2 232 2019-04-01 19:00:00 2019-04-01 19:12:00 2019-04-01 22:45:00 0.54 0 days 03:33:00.000000000

Решение

Затем определите простую функцию, которая возвращает список длины, равный числу 30-минутных интервалов в столбце min.

def upsample_list(x):
    multiplier = math.ceil(x.total_seconds() / (60 * 30))

    return list(range(multiplier))

И примените это кфрейм данных:

df['samples'] = df.mins.apply(upsample_list)

Далее создайте новую строку для каждого элемента списка в столбце «выборки» (используя ответ, предоставленный Roman Pekar здесь ):

s = df.apply(lambda x: pd.Series(x['samples']),axis=1).stack().reset_index(level=1, drop=True)
s.name = 'sample'

Присоедините s к информационному фрейму и очистите дополнительные столбцы:

df = df.drop('samples', axis=1).join(s, how='inner').drop('sample', axis=1)

Что дает нам это:

   id   half_hour_bucket    clock_in_time        clock_out_time       rate  mins
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
0  232  2019-04-01 20:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
1  342  2019-04-01 20:30:00 2019-04-01 19:12:00  2019-04-01 19:22:00  0.23  00:10:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00
2  232  2019-04-01 19:00:00 2019-04-01 19:12:00  2019-04-01 22:45:00  0.54  03:33:00

Почти там!

Сбросить индекс:

df = df.reset_index(drop=True)

Установить дублирующиеся строки на NaN:

df = df.mask(df.duplicated())

, что дает:

   id    half_hour_bucket    clock_in_time       clock_out_time      rate mins
0  232.0 2019-04-01 20:00:00 2019-04-01 19:12:00 2019-04-01 22:45:00 0.54 03:33:00
1  NaN   NaT                 NaT                 NaT                 NaN  NaT
2  NaN   NaT                 NaT                 NaT                 NaN  NaT
3  NaN   NaT                 NaT                 NaT                 NaN  NaT
4  NaN   NaT                 NaT                 NaT                 NaN  NaT
5  NaN   NaT                 NaT                 NaT                 NaN  NaT
6  NaN   NaT                 NaT                 NaT                 NaN  NaT
7  NaN   NaT                 NaT                 NaT                 NaN  NaT
8  342.0 2019-04-01 20:30:00 2019-04-01 19:12:00 2019-04-01 19:22:00 0.23 00:10:00
9  232.0 2019-04-01 19:00:00 2019-04-01 19:12:00 2019-04-01 22:45:00 0.54 03:33:00
10 NaN   NaT                 NaT                 NaT                 NaN  NaT
11 NaN   NaT                 NaT                 NaT                 NaN  NaT
12 NaN   NaT                 NaT                 NaT                 NaN  NaT
13 NaN   NaT                 NaT                 NaT                 NaN  NaT
14 NaN   NaT                 NaT                 NaT                 NaN  NaT
15 NaN   NaT                 NaT                 NaT                 NaN  NaT
16 NaN   NaT                 NaT                 NaT                 NaN  NaT

Наконец,вперед заполните поля half_hour_bucket и rate.

df[['half_hour_bucket', 'rate']] = df[['half_hour_bucket', 'rate']].ffill()

Окончательный вывод:

     id     half_hour_bucket     clock_in_time        clock_out_time       rate  mins
0    232.0  2019-04-01 20:00:00  2019-04-01_19:12:00  2019-04-01_22:45:00  0.54  03:33:00
1    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
2    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
3    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
4    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
5    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
6    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
7    NaN    2019-04-01 20:00:00  NaT                  NaT                  0.54  NaT
8    342.0  2019-04-01 20:30:00  2019-04-01_19:12:00  2019-04-01_19:22:00  0.23  00:10:00
9    232.0  2019-04-01 19:00:00  2019-04-01_19:12:00  2019-04-01_22:45:00  0.54  03:33:00
10   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
11   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
12   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
13   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
14   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
15   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
16   NaN    2019-04-01 19:00:00  NaT                  NaT                  0.54  NaT
...