Pandas:计算中间时间项的总时间差
我有一个数据表,内容如下:
日期 | 姓名 | 进/出 | 时间 |
---|---|---|---|
2024-01-01 | 霍默 | 进 | 07:10 |
2024-01-01 | 霍默 | 出 | 09:30 |
2024-01-01 | 霍默 | 进 | 10:00 |
2024-01-01 | 霍默 | 出 | 16:00 |
2024-01-01 | 玛吉 | 进 | 07:15 |
2024-01-01 | 玛吉 | 出 | 16:10 |
2024-01-01 | 巴特 | 进 | 07:14 |
2024-01-01 | 巴特 | 出 | 10:00 |
2024-01-01 | 巴特 | 进 | 10:15 |
2024-01-01 | 巴特 | 出 | 12:00 |
2024-01-01 | 巴特 | 进 | 12:30 |
2024-01-01 | 巴特 | 出 | 17:00 |
我的最终目标是计算中间的进出时间的总时长(以秒为单位),如上面高亮的部分所示。期望的输出如下:
日期 | 姓名 | 时间差 |
---|---|---|
2024-01-01 | 霍默 | 1800 |
2024-01-01 | 巴特 | 2700 |
我不知道从哪里开始,也找不到其他地方的例子?
示例数据表:
example_df = pd.DataFrame([
['2024-01-01', 'Homer', 'in', '07:30'],
['2024-01-01', 'Homer', 'out' ,'09:00'],
['2024-01-01', 'Homer', 'in' ,'09:30'],
['2024-01-01', 'Homer', 'out' ,'16:00'],
['2024-01-01', 'Marge', 'in' , '06:20'],
['2024-01-01', 'Marge', 'out' ,'16:00'],
['2024-01-01', 'Bart', 'in' ,'07:10'],
['2024-01-01', 'Bart', 'out' ,'08:00'],
['2024-01-01', 'Bart', 'in' ,'08:20'],
['2024-01-01', 'Bart', 'out' ,'17:00'],
['2024-01-01', 'Barney', 'in' ,'08:10'],
['2024-01-01', 'Lisa', 'in' ,'08:05'],
['2024-01-01', 'Lisa', 'out' ,'14:00'],
['2024-01-01', 'Lisa', 'in' ,'14:15'],
['2024-01-01', 'Lisa', 'out' ,'18:10'],
['2024-01-01', 'Millhouse', 'out' ,'19:10'],
['2024-02-01', 'Homer', 'in', '07:30'],
['2024-02-01', 'Homer', 'out' ,'09:00'],
['2024-02-01', 'Marge', 'in' , '06:30'],
['2024-02-01', 'Marge', 'out' ,'09:10'],
['2024-02-01', 'Marge', 'in' ,'10:10'],
['2024-02-01', 'Marge', 'out' ,'16:10'],
['2024-02-01', 'Bart', 'in' ,'07:10'],
['2024-02-01', 'Bart', 'out' ,'15:00'],
['2024-02-01', 'Barney', 'in' ,'08:10'],
['2024-02-01', 'Lisa', 'in' ,'08:05'],
['2024-02-01', 'Lisa', 'out' ,'16:00'],
['2024-02-01', 'Millhouse', 'in' ,'08:10'],
['2024-02-01', 'Millhouse', 'in' ,'08:10'],
['2024-02-01', 'Millhouse', 'in' ,'16:15']],
columns=['Date', 'Name', 'In/Out', 'Time'])
2 个回答
-1
我会把你的数据表转换成每个人在某一天的记录,包含进场时间和出场时间。这样你就可以直接计算这两个时间之间的差值了。下面是我会怎么做的。
import pandas as pd
import random as rd
names=['John','Jeff']
dates=['01/01/2024','01/02/2024']
intimes=['08:00','09:00']
outtimes=['17:00','17:30']
namelist=[]
datelist=[]
inlist=[]
outlist=[]
for i in names:
for j in dates:
namelist.append(i)
datelist.append(j)
inlist.append(rd.sample(intimes,1)[0])
outlist.append(rd.sample(outtimes,1)[0])
df=pd.DataFrame()
df['Name']=namelist
df['Date']=datelist
df['In']=inlist
df['Out']=outlist
df['InDateandTime']=pd.to_datetime(df['Date']+' '+df['In'])
df['OutDateandTime']=pd.to_datetime(df['Date']+' '+df['Out'])
df['TimeDelta']=df['OutDateandTime']-df['InDateandTime']
display(df)
这是输出的结果:
你只需要创建一个新的数据表,把每个人每天的记录合并成一条,然后对这个新数据表应用这个方法。首先,你需要把日期和时间合并成字符串,然后用pd.DateTime把它们转换成日期时间格式。我在代码中展示了怎么做。你也可以删除原来的'日期'、'进'和'出'这几列,但我保留它们是为了让你更清楚我做了什么。大部分代码只是为了创建一个我可以用作示例的数据集。
1
假设时间在一组数据中是排好序的,且第一条记录总是“进”,而“进”和“出”是交替出现的。
你可以先把时间转换成日期时间格式,接着使用分组的方法来计算时间差,忽略第一条和最后一条记录,然后把所有“进”的时间差加起来,最后再转换成总秒数:
# cleanup IN/OUT format
df['In/Out'] = df['In/Out'].str.upper()
out = (df
.assign(dt=pd.to_datetime(df['Time'], format='%H:%M'))
.groupby(['Date', 'Name'])
.apply(lambda g:
g['dt'].diff().iloc[1:-1]
[g['In/Out'].eq('IN')]
.sum().total_seconds())
.reset_index(name='TimeDelta')
.query('TimeDelta>0') # optional: remove rows with null TimeDelta
)
输出结果:
Date Name TimeDelta
1 2024-01-01 J Bloggs 1800.0
2 2024-01-01 M Simpson 2700.0
注意:如果最开始的假设有误,你只需要先处理一下数据,确保它是排好序的,并去掉无效的行。
举个例子:
# cleanup IN/OUT format
df['In/Out'] = df['In/Out'].str.upper()
m1 = df.sort_values(by='Time').groupby(['Date', 'Name'])['In/Out'].shift(-1).ne(df['In/Out'])
out = (df[m1]
.assign(dt=pd.to_datetime(df.loc[m1, 'Time'], format='%H:%M'))
.groupby(['Date', 'Name'])
.apply(lambda g:
g['dt'].diff().iloc[1:-1]
[g['In/Out'].eq('IN')]
.sum().total_seconds())
.reset_index(name='TimeDelta')
.query('TimeDelta>0') # optional: remove rows with null TimeDelta
)
输出结果:
Date Name TimeDelta
1 2024-01-01 Bart 1200.0
2 2024-01-01 Homer 1800.0
3 2024-01-01 Lisa 900.0
10 2024-02-01 Marge 3600.0