【问题标题】:check if timestamp column is in date range from another dataframe检查时间戳列是否在另一个数据框的日期范围内
【发布时间】:2018-05-22 18:10:27
【问题描述】:

我有一个数据框 df_A,它有两列“amin”和“amax”,这是一组时间范围。

我的目标是找出 df_B 中的列是否位于 df_A 'amin' 和 'amax' 列中的任何范围行之间。

df_A[['amin','amax'] ]

                  amin                   amax
          0 2016-07-16 19:37:03   2016-07-17 11:16:32
          1 2016-07-04 21:15:54   2016-07-05 10:57:46
          2 2016-07-24 23:30:41   2016-07-25 15:38:02
          3 2016-07-12 03:02:38   2016-07-12 22:11:01

df_B['created_date']

      created_date
   2016-07-17 01:16:32 
   2016-07-05 10:15:54  
   2016-07-12 12:11:01


df_A['amin'] = pd.to_datetime(df_A['amin'], errors='coerce')
df_A['amax'] = pd.to_datetime(df_A['amax'], errors='coerce')
df_B['created_date'] = pd.to_datetime(df_B['created_date'],errors='coerce')

def dt2epoch(value):
   epoch = (value - pd.to_datetime(datetime(2015,12,31).strftime('%Y-%m-%d %H:%M:%S.%f'))).total_seconds()
   return epoch    

df_A['amax_epoch']=df_A['amax'].apply(dt2epoch)
df_A['amin_epoch']=df_A['amin'].apply(dt2epoch)
df_B['created_date_epoch']=df_B['created_date'].apply(dt2epoch)


def make_tuple(row):
     n= len(row)
     row = [(x,row[n - 1]) for x in row]
     return row

minMaxTuple = minMax.apply(make_tuple, axis =1)

上面是我的代码的一部分,我在下面尝试过(不确定是否有必要):

  1. 将它们转换为纪元值
  2. 将 df_A 转换为元组。

但是,df_A 和 df_B 的行数不同。另外,我没有任何 id 列将它们合并在一起。

label = []

for l in df_B['created_date_epoch']:

    if (m[0] for m in minMaxTuple) <= l <= (m[1] for m in minMaxTuple):
        label.append('1')
    else:
        label.append('0')

但是,当我运行它时,我得到的“标签”结果是一个空列表。

此外,标签应该是与 df_A 具有相同行数的列。

最后,我想在 df_A 中添加一个新的“标签”列:

                              minMaxTuple                      label
            (2016-07-16 19:37:03, 2016-07-17 11:16:32)            1
            (2016-07-04 21:15:54, 2016-07-05 10:57:46)            1 
            (2016-07-24 23:30:41, 2016-07-25 15:38:02)            0
            (2016-07-12 03:02:38, 2016-07-12 22:11:01)            1

【问题讨论】:

  • 您是否曾经有过相互冲突的数据?意味着您有多个 created_dates 可以适合另一个 amin/amax 组合?
  • @MattR hmm 是的,这也可能是问题之一。如果发生这种情况,您认为仅标记 1 和 0 来表示会更好吗?而不是存储原始数据?
  • 这是什么数据?这可能不是pandas 的事情。它可能是一般数据的东西。有没有可以使用的唯一标识符?在我们开始深入研究代码之前,可能会有一个不那么痛苦的解决方案
  • @MattR 你的意思是唯一键吗?因为它们来自不同的表,因此没有。 df_A 是对一系列时间序列数据进行聚类的结果,amin amax 是该特定聚类的最小和最大时间。而 df_B 是事件发生的日期,我想标记 df_A 数据。
  • 唯一键,唯一标识符。我的书中也有同样的事情。那么如果created_date 中有两个可能的值,那么预期的结果是什么?我担心这个问题解决后,你需要问另一个问题,因为我正在谈论的场景会出现

标签: python pandas dataframe timestamp range


【解决方案1】:

一种解决方案是查看 df_b 中的 created_date 是否介于 aminamax 之间,这是使用布尔逻辑。在df_a 中每一行的逐行计算中,您可以使用以下逻辑:

if sum((row['amin'] > df_b['created_date']) | (row['amax'] < df_b['created_date'])) == len(df_b)

在本文中,我使用逻辑运算符| 来检查amin 是否小于created_dateamax 是否小于created_date。如果语句是True,您可以得出结论,创建日期不在aminamax 创建的时间段之间。如果没有一个created_dates 介于aminamax 创建的时间段之间,那么您可以将0 的值分配给df_a['label']:类似于:

import pandas as pd
from StringIO import StringIO

def myfunc(row, df_b):
    if sum((row['amin'] > df_b['created_date']) | (row['amax'] < df_b['created_date'])) == len(df_b):
        return 0
    else:
        return 1

a_str= """
amin,amax
2016-07-16 19:37:03,2016-07-17 11:16:32
2016-07-04 21:15:54,2016-07-05 10:57:46
2016-07-24 23:30:41,2016-07-25 15:38:02
2016-07-12 03:02:38,2016-07-12 22:11:01"""

b_str = """
created_date
2016-07-17 01:16:32 
2016-07-05 10:15:54  
2016-07-12 12:11:01"""
df_a = pd.read_csv(StringIO(a_str), sep=',')
df_b = pd.read_csv(StringIO(b_str), sep=',')

#Convert to datetime
df_a['amin'] = pd.to_datetime(df_a['amin'])
df_a['amax'] = pd.to_datetime(df_a['amax'])
df_b['created_date'] = pd.to_datetime(df_b['created_date'])

df_a['label'] = df_a.apply(lambda x: myfunc(x,df_b), axis=1)

df_a 中返回一列label,预期输出为:

                 amin                amax  label
0 2016-07-16 19:37:03 2016-07-17 11:16:32      1
1 2016-07-04 21:15:54 2016-07-05 10:57:46      1
2 2016-07-24 23:30:41 2016-07-25 15:38:02      0
3 2016-07-12 03:02:38 2016-07-12 22:11:01      1

【讨论】:

  • 嗨!这完美!但是我能问一下为什么不检查语句的“总和”是否是“len(df_B)”的“==”? @dubbbdan
  • @jayen 我选择了 OR 逻辑 (|),因为只需一个条件为假,created_date 就不会在aminamax 创建的时间段内。总和将True 视为值1。因此,如果所有元素系列都是True(没有日期在时间跨度内),它将等于系列的长度created_date
  • @jayen 如果逻辑语句返回True,则可以断定创建的日期都不在aminamax 创建的时间段内。希望这会有所帮助!
【解决方案2】:

与@dubbbdan 的答案非常相似,但使用anyand 运算符可能更简单:

any_in_range = lambda row, iterable: any(
    [(row[0] < x) & (x < row[1]) for x in iterable])
df_A['label'] = df_A.apply(any_in_range, iterable=df_B['created_date'], axis=1)
print df_A

打印:

                 amin                amax  label
0 2016-07-16 19:37:03 2016-07-17 11:16:32   True
1 2016-07-04 21:15:54 2016-07-05 10:57:46   True
2 2016-07-24 23:30:41 2016-07-25 15:38:02  False
3 2016-07-12 03:02:38 2016-07-12 22:11:01   True

【讨论】:

  • 谢谢!这就是我想要使用and 运算符来做的事情
【解决方案3】:

我从最大和最小日期列创建了一个元组列表,然后在这个元组列表中搜索日期时间戳。

tuple_to_search = list(zip(df_A.amin,df_A.amax))

df_B['is_true']= df_B['created_date'].map(lambda k: any(filter(lambda x : x [0]<= k <=x[1],tuple_to_search ))).astype(int)

【讨论】:

  • 我从最大和最小日期列创建了一个元组列表,然后在这个元组列表中搜索日期时间戳。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 2019-05-20
  • 2019-12-27
  • 1970-01-01
相关资源
最近更新 更多