Python 计算dataframe中多行上的日期时间差异

Python 计算dataframe中多行上的日期时间差异,python,pandas,dataframe,Python,Pandas,Dataframe,我有一个关于数据帧中日期时间的python相关问题。我通过pd.read\u csv() 我想知道标有A、B、C的行之间的时差,如下所示: datetime label d_time 0 2017-01-03 23:52:00 1 2017-01-03 23:53:00 A 0:02 2 2017-01-03 23:54:00 A 3 2017-01-03 23:55:00 A 4 2017

我有一个关于数据帧中日期时间的python相关问题。我通过
pd.read\u csv()

我想知道标有A、B、C的行之间的时差,如下所示:

    datetime             label  d_time
0   2017-01-03 23:52:00            
1   2017-01-03 23:53:00  A      0:02
2   2017-01-03 23:54:00  A   
3   2017-01-03 23:55:00  A   
4   2017-01-04 00:01:00     
5   2017-01-04 00:02:00  B      0:09 
6   2017-01-04 00:06:00  B
7   2017-01-04 00:09:00  B
8   2017-01-04 00:11:00  B
9   2017-01-04 00:12:00  
10  2017-01-04 00:14:00  
11  2017-01-04 00:16:00  
12  2017-01-04 00:18:00  C      0:02 
13  2017-01-04 00:20:00  C 
14  2017-01-04 00:22:00  

因此,
d_time
应该是标记行上的总时间差。大约有100种不同的标签,它们可以从1到x连续变化。必须对+100万行执行此计算,因此循环可能不起作用。有人知道怎么做吗?提前谢谢

如果日期时间是
datetime
对象(或
pandas.TimeStamp
),则可以将其用于循环

a_rows = []
for row in df.itertuples():
    if row.label == 'A':
        a_rows.append(row)
    elif a_rows:
        d_time = a_rows[-1].datetime - a_rows[0].datetime
        df.loc[a_rows[0].Index, 'd_time'] = d_time
        a_rows = []
有了这个结果

    datetime    label   d_time
0   2017-01-03 23:52:00     
1   2017-01-03 23:53:00 A   0 days 00:02:00
2   2017-01-03 23:54:00 A   
3   2017-01-03 23:55:00 A   
4   2017-01-04 00:01:00     
5   2017-01-04 00:02:00 A   0 days 00:07:00
6   2017-01-04 00:06:00 A   
7   2017-01-04 00:09:00 A   
8   2017-01-04 00:11:00     
如果需要,以后可以格式化
timedelta
对象


如果datetime列是
string
s,您可以使用
df['datetime']=pd.轻松地将它们转换为\u datetime(df['datetime'])
如果datetime是
datetime
对象(或
pandas.TimeStamp
),您可以将其用于循环

a_rows = []
for row in df.itertuples():
    if row.label == 'A':
        a_rows.append(row)
    elif a_rows:
        d_time = a_rows[-1].datetime - a_rows[0].datetime
        df.loc[a_rows[0].Index, 'd_time'] = d_time
        a_rows = []
有了这个结果

    datetime    label   d_time
0   2017-01-03 23:52:00     
1   2017-01-03 23:53:00 A   0 days 00:02:00
2   2017-01-03 23:54:00 A   
3   2017-01-03 23:55:00 A   
4   2017-01-04 00:01:00     
5   2017-01-04 00:02:00 A   0 days 00:07:00
6   2017-01-04 00:06:00 A   
7   2017-01-04 00:09:00 A   
8   2017-01-04 00:11:00     
如果需要,以后可以格式化
timedelta
对象


如果datetime列是
字符串
s,您可以使用
df['datetime']=pd.轻松地将它们转换为_datetime(df['datetime'])
假设连续标签都相同,并且由1
nan分隔

你可以这样做

idx = pd.Series(df[pd.isnull(df['label'])].index)

idx_begin = idx.iloc[:-1] + 1
idx_end = idx.iloc[1:] - 1

d_time = df.loc[idx_end, 'datetime'].reset_index(drop=True) - df.loc[idx_begin, 'datetime'].reset_index(drop=True)
d_time.index = idx_begin
df.loc[idx_begin, 'd_time'] = d_time
如果您的数据集看起来不同,您可能会寻找不同的方法来访问
idx\u begin
idx\u end
,但这适用于您发布的数据集

多个连续的
nan
s 如果有多个连续的
nan
-值,可以通过将其添加到末尾来解决此问题

df.loc[df[pd.isnull(df['label'])].index, 'd_time'] = None
连续不同标签 这将不同的标签标记为不同的开始和开始。为了实现这一点,您需要在末尾添加
df.loc[df[pd.isnull(df['label'])]索引'd_time']=None

df.loc[df[pd.isnull(df['label'])].index, 'd_time'] = None
&(pd.notnull(df['label'])|(pd.notnull(df['label'].shift(1))
部分是因为
None!=None

结果 屈服

    datetime    label   d_time
0   2017-01-03 23:52:00     NaN     NaT
1   2017-01-03 23:53:00     A   00:01:00
2   2017-01-03 23:54:00     A   NaT
3   2017-01-03 23:52:00     NaN     NaT
4   2017-01-03 23:53:00     B   00:01:00
5   2017-01-03 23:54:00     B   NaT
6   2017-01-03 23:55:00     NaN     NaT
7   2017-01-03 23:56:00     NaN     NaT
8   2017-01-03 23:57:00     NaN     NaT
9   2017-01-04 00:02:00     A   00:07:00
10  2017-01-04 00:06:00     A   NaT
11  2017-01-04 00:09:00     A   NaT
12  2017-01-04 00:02:00     B   00:07:00
13  2017-01-04 00:06:00     B   NaT
14  2017-01-04 00:09:00     B   NaT
15  2017-01-04 00:11:00     NaN     NaT
最后一系列 如果最后一行与前一行相比没有更改标签,则最后一个系列将不会注册

您可以通过在第一行之后包含此项来防止此问题

if idx[-1] != df.index[-1]:
    idx = idx.append(df.index[[-1]]+1)

假设连续的标签都相同,并且由1
nan

你可以这样做

idx = pd.Series(df[pd.isnull(df['label'])].index)

idx_begin = idx.iloc[:-1] + 1
idx_end = idx.iloc[1:] - 1

d_time = df.loc[idx_end, 'datetime'].reset_index(drop=True) - df.loc[idx_begin, 'datetime'].reset_index(drop=True)
d_time.index = idx_begin
df.loc[idx_begin, 'd_time'] = d_time
如果您的数据集看起来不同,您可能会寻找不同的方法来访问
idx\u begin
idx\u end
,但这适用于您发布的数据集

多个连续的
nan
s 如果有多个连续的
nan
-值,可以通过将其添加到末尾来解决此问题

df.loc[df[pd.isnull(df['label'])].index, 'd_time'] = None
连续不同标签 这会将不同的标签标记为不同的开始和开始。为了实现这一点,需要在末尾添加
df.loc[df[pd.isnull(df['label'])]].index,“d_time']=None

df.loc[df[pd.isnull(df['label'])].index, 'd_time'] = None
&(pd.notnull(df['label'])|(pd.notnull(df['label'].shift(1))
部分是因为
None!=None

结果 屈服

    datetime    label   d_time
0   2017-01-03 23:52:00     NaN     NaT
1   2017-01-03 23:53:00     A   00:01:00
2   2017-01-03 23:54:00     A   NaT
3   2017-01-03 23:52:00     NaN     NaT
4   2017-01-03 23:53:00     B   00:01:00
5   2017-01-03 23:54:00     B   NaT
6   2017-01-03 23:55:00     NaN     NaT
7   2017-01-03 23:56:00     NaN     NaT
8   2017-01-03 23:57:00     NaN     NaT
9   2017-01-04 00:02:00     A   00:07:00
10  2017-01-04 00:06:00     A   NaT
11  2017-01-04 00:09:00     A   NaT
12  2017-01-04 00:02:00     B   00:07:00
13  2017-01-04 00:06:00     B   NaT
14  2017-01-04 00:09:00     B   NaT
15  2017-01-04 00:11:00     NaN     NaT
最后一系列 如果最后一行与前一行相比没有更改标签,则最后一个系列将不会注册

您可以通过在第一行之后包含此项来防止此问题

if idx[-1] != df.index[-1]:
    idx = idx.append(df.index[[-1]]+1)

你的回答总是3行,还是仅仅针对所有连续的AWA?总是3行,还是仅仅针对所有连续的AThanks Maarten。也许我应该更精确一些,因为标签A并不总是A,而是来自另一个列表的一些标签。我必须迭代超过100万行,因此使用df.itertuples()进行for循环行不通……第一个问题不是什么大问题,你只需要调整
行。label==“a”
。while数据帧的标签总是相同的,还是有更多的标签。一行中总是有3个
a
?迭代问题是一个更大的问题,这取决于你需要执行此计算的次数e是多个标签(约100个),并且不总是一行3个,它们可以在一行1到x之间变化。对于每个数据帧,此计算必须进行大约300-400次。也许可以将此澄清添加到您的原始答案中,并添加一个更为复杂的数据集,更像您自己的数据集。感谢Maarten的回复。也许我应该更精确一些,因为标签是a不总是一个,而是另一个列表中的一些标签。而且我必须迭代超过100万行,因此使用df.itertuples()进行for循环行不通……第一个问题不是什么大问题,你只需要调整
行。label==“a”
。while数据帧的标签总是相同的,还是有更多的标签。一行中总是有3个
a
?迭代问题是一个更大的问题,这取决于你需要执行此计算的次数e是多个标签(大约100个),并非总是一行3个,它们可以在一行1到x之间变化。每个数据帧必须进行大约300-400次计算。也许可以将此澄清添加到原始答案中,并添加一个更复杂的数据集,更像您自己的数据集