Pandas:计算中间时间项的总时间差

2 投票
2 回答
47 浏览
提问于 2025-04-12 17:33

我有一个数据表,内容如下:

日期 姓名 进/出 时间
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)

这是输出的结果:

enter image description here

你只需要创建一个新的数据表,把每个人每天的记录合并成一条,然后对这个新数据表应用这个方法。首先,你需要把日期和时间合并成字符串,然后用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

撰写回答