Я почти новичок с Pandas, поэтому я хотел бы знать, возможна ли определенная операция, прежде чем начинать кодирование вокруг нее.
У меня есть набор данных о рабочем времени сотрудников, например (это слишком упрощенно, реальный материал - тысячи и тысячи записей)
ID Name Date Hour Type
0 123 Bob 01/01/2018 09:00 In
1 123 Bob 01/01/2018 09:30 Out
2 123 Bob 01/01/2018 10:00 In
3 123 Bob 01/01/2018 12:00 Out
4 123 Bob 01/01/2018 13:00 In
5 123 Bob 01/01/2018 17:00 Out
6 456 Max 01/01/2018 09:00 In
7 456 Max 01/01/2018 12:00 Out
8 456 Max 01/01/2018 13:00 In
9 456 Max 01/01/2018 17:00 Out
10 123 Bob 02/01/2018 09:00 In
11 123 Bob 02/01/2018 09:30 Out
12 123 Bob 02/01/2018 10:00 In
13 123 Bob 02/01/2018 17:00 Out
14 456 Max 02/01/2018 10:00 In
15 456 Max 02/01/2018 17:00 Out
Я знаю, как мощный Python и Pandas манипулируют данными, я хотел бы знать, есть ли у вас такой выход, без прохождения итеративного кодирования
ID Name Date HourWorked
0 123 Bob 01/01/2018 06:30
1 456 Max 01/01/2018 07:00
2 123 Bob 02/01/2018 07:30
3 456 Max 02/01/2018 07:00
В конце концов, мне нужно (для каждого идентификатора сотрудника) вычислять часы/минуты, работающие на каждый день
Я смотрел много примеров GroupBy, но нашел что-нибудь полезное.
ТИА
Конвертируйте часы в datetime
, groupby
In и Outs и принимайте разницу. Позже суммируйте разностную группировку по 'ID'
и 'Date'
т.е.
df['Hour'] = pd.to_datetime(df['Hour'])
df['diff'] = df.groupby((df['Type'] == 'In').cumsum())['Hour'].diff()
df_new = df.groupby(['ID','Name','Date'])['diff'].sum().to_frame('Hours Worked')
Hours Worked
ID Name Date
123 Bob 01/01/2018 06:30:00
02/01/2018 07:30:00
456 Max 01/01/2018 07:00:00
02/01/2018 07:00:00
С помощью groupby
+ пользовательская функция. Это предполагает, что ваши "In" и "Out" времена правильно спарены и упорядочены.
# convert series to timedelta
df['Hour'] = pd.to_timedelta(df['Hour']+':00')
# define total time calculation
def total_time(x):
return (x.iloc[1::2].values - x.iloc[::2].values).sum()
# apply groupby and convert to dataframe
res = df.groupby(['ID', 'Name', 'Date'])['Hour'].apply(total_time)\
.to_frame('Hours Worked').reset_index()
print(res)
ID Name Date Hours Worked
0 123 Bob 01/01/2018 06:30:00
1 123 Bob 02/01/2018 07:30:00
2 456 Max 01/01/2018 07:00:00
3 456 Max 02/01/2018 07:00:00
Это решение предполагает, однако, что ваш Type
всегда находится в порядке "In-Out"
df = pd.DataFrame({"ID": [123,123,123,123,456,456, 123,123, 456,456],
"Date": ["01/01/2018","01/01/2018", "01/01/2018", "01/01/2018", "01/01/2018", "01/01/2018",
"02/01/2018", "02/01/2018", "02/01/2018", "02/01/2018"],
"Hour": ["09:00","09:30","10:00","12:00","13:00","17:00", "10:00","12:00","13:00","17:00"],
"Type": ["In","Out","In","Out","In","Out", "In","Out","In","Out"]})
df["DateTime"] = pd.to_datetime(df["Hour"] + " " + df["Date"])
df.groupby(["ID", "Date"])["DateTime"].apply(list).\
apply(lambda x: [x[i+1] - x[i] for i in range(len(x) - 1)]).str[0::2].\
apply(lambda x: np.sum(x))
timedelta
:)