【问题标题】:How to calculate time difference between specific row values in dataframe using python?如何使用python计算数据框中特定行值之间的时间差?
【发布时间】:2020-01-25 09:52:40
【问题描述】:

df 如下所示:


Time                    A 

2019-05-18 01:15:28     7
2019-05-18 01:28:11     7
2019-05-18 01:36:36     12
2019-05-18 01:39:47     12
2019-05-18 01:53:32     12
2019-05-18 02:05:37     7

我了解如何计算连续行时间差。但我想在 A 中的值为 7 到 12 时计算时间差。

预期输出:


Time                    A   Time_difference

2019-05-18 01:15:28     7   0
2019-05-18 01:28:11     7   0
2019-05-18 01:36:36     12  00:21:08
2019-05-18 01:39:47     12  0
2019-05-18 01:53:32     12  0
2019-05-18 02:05:37     12  0

【问题讨论】:

  • 这是您需要的特定计算,还是有关于减去哪些行的任何规则?一般来说,时间计算都有timedelta对象。
  • 是特定规则,比如A列中出现7到12之间的窗口时间。
  • 712 之间可能有多个 7 或 12 值?
  • 是的。但窗口会在前 7 到前 12 之间。例如:[7,4,7,7,12] 7 到 12 是焦点。
  • 您能否为minimal, complete, and verifiable example 添加更多712 值?我认为如果更多连续的712 或两者兼而有之。

标签: python pandas time


【解决方案1】:

解释

  • (df["A"] == 7).cumsum() 将行分隔为每个 7
  • 对于每组 7 个,如果有 12 个,则从组的第 1 行中减去第 1 行和 12
  • 如果直到找到 12 才将组的第一行的值传递给下一组

import pandas as pd
import numpy as np

np.random.seed(10)
date_range = pd.date_range("25-9-2019", "27-9-2019", freq="3H")
df = pd.DataFrame({'Time':date_range, 'A':np.random.choice([5,7,12], len(date_range))})

df["Seven"] = (df["A"] == 7).cumsum()

# display(df)
pass_to_next_group = {"val": None}
def diff(group):
    group["Diff"]=0
    loc = group.index[group["A"]==12]

    time_a = pass_to_next_group["val"] if pass_to_next_group["val"] else group["Time"].iloc[0]
    pass_to_next_group["val"] = None

    if group.name>0 and len(loc)>0:           
        group.loc[loc[0],"Diff"] =  time_a-group.loc[loc[0],"Time"]
    else:
        pass_to_next_group["val"] = time_a

    return group


df.groupby("Seven").apply(diff)

【讨论】:

    【解决方案2】:

    示例:

    times = [
        '2019-05-18 01:15:28',
        '2019-05-18 01:28:11',
        '2019-05-18 01:36:36',
        '2019-05-18 01:39:47',
        '2019-05-18 01:53:32',
        '2019-05-18 02:05:37'
    ]
    
    a = [7, 7, 12, 7, 12, 7]
    
    df = pd.DataFrame({'times': pd.to_datetime(times), 'A':a})
    print (df)
                    times   A
    0 2019-05-18 01:15:28   7
    1 2019-05-18 01:28:11   7
    2 2019-05-18 01:36:36  12
    3 2019-05-18 01:39:47   7
    4 2019-05-18 01:53:32  12
    5 2019-05-18 02:05:37   7
    

    首先创建默认索引并仅使用712 过滤行:

    df = df.reset_index(drop=True)
    df1 = df[df['A'].isin([7, 12])]
    

    然后通过与移位值进行比较来获取行中的第一个连续值:

    df1 = df1[df1['A'].ne(df1['A'].shift())]
    print (df1)
                    times   A
    0 2019-05-18 01:15:28   7
    2 2019-05-18 01:36:36  12
    3 2019-05-18 01:39:47   7
    4 2019-05-18 01:53:32  12
    5 2019-05-18 02:05:37   7
    

    然后过滤7 与下一个12 行:

    m1 = df1['A'].eq(7) & df1['A'].shift(-1).eq(12)
    m2 = df1['A'].eq(12) & df1['A'].shift().eq(7)
    
    df2 = df1[m1 | m2]
    print (df2)
                    times   A
    0 2019-05-18 01:15:28   7
    2 2019-05-18 01:36:36  12
    3 2019-05-18 01:39:47   7
    4 2019-05-18 01:53:32  12
    

    获取包含配对和取消配对行的日期时间:

    out7 = df2.iloc[::2]
    out12 = df2.iloc[1::2]
    

    最后减去:

    df['Time_difference'] = out12['times'] - out7['times'].to_numpy()
    df['Time_difference'] = df['Time_difference'].fillna(pd.Timedelta(0))
    print (df)
                    times   A Time_difference
    0 2019-05-18 01:15:28   7        00:00:00
    1 2019-05-18 01:28:11   7        00:00:00
    2 2019-05-18 01:36:36  12        00:21:08
    3 2019-05-18 01:39:47   7        00:00:00
    4 2019-05-18 01:53:32  12        00:13:45
    5 2019-05-18 02:05:37   7        00:00:00
    

    【讨论】:

      【解决方案3】:

      您可以使用loc 隔离数据框中的任何值。返回的是一个系列,它可以像列表一样被索引。使用[0] 获取系列中的第一个匹配项。

      times = [
          '2019-05-18 01:15:28',
          '2019-05-18 01:28:11',
          '2019-05-18 01:36:36',
          '2019-05-18 01:39:47',
          '2019-05-18 01:53:32',
          '2019-05-18 02:05:37'
      ]
      
      a = [9, 7, 7, 5, 12, 12]
      
      df = pd.DataFrame({'times':times, 'a':a})
      df.times = pd.to_datetime(df['times'])
      pd.Timedelta(df.loc[df.a == 12, 'times'].values[0] - df.loc[df.a == 7, 'times'].values[0])
      

      Timedelta('0 days 00:25:21')

      或者,为了便于阅读,我们可以将代码分开,并对新变量进行计算:

      times = [
          '2019-05-18 01:15:28',
          '2019-05-18 01:28:11',
          '2019-05-18 01:36:36',
          '2019-05-18 01:39:47',
          '2019-05-18 01:53:32',
          '2019-05-18 02:05:37'
      ]
      
      a = [9, 7, 7, 5, 12, 12]
      
      df = pd.DataFrame({'times':times, 'a':a})
      df.times = pd.to_datetime(df['times'])
      end = df.loc[df.a == 12, 'times'].values[0]
      start = df.loc[df.a == 7, 'times'].values[0]
      pd.Timedelta(end - start)
      

      Timedelta('0 days 00:25:21')

      【讨论】:

      • 谢谢!但它不会遍历数据框以找到另一个 7 到 12 的窗口。就像我输入预期的输出一样,只要数据框中有 7 到 12 的窗口,就应该计算差异。我会稍微调整一下你的逻辑并检查...
      • 我认为这不是您的预期输出所反映的。如果你想让它继续下去,会不会有另一个时差?在一条评论中,您明确表示您希望第一次出现。
      猜你喜欢
      • 2019-11-11
      • 2021-12-25
      • 2019-09-02
      • 1970-01-01
      • 2021-01-14
      • 2022-12-09
      • 1970-01-01
      • 2021-11-28
      • 2017-05-21
      相关资源
      最近更新 更多