【问题标题】:Nearest neighbor distance for k=1 in units of timek=1 的最近邻距离(以时间为单位)
【发布时间】:2019-06-11 01:43:10
【问题描述】:

我有以下数据框

A_key      Date
      A1      2016-05-03
      A1      2016-09-25
      A2      2015-02-25
      A2      2015-02-25
      A3      2015-10-04
      A3      2016-03-15
      A3      2016-04-10
      A4      2015-09-26
      A4      2015-09-26

我想在 n_neighbor(k) = 1 的情况下以天为单位获取每个不同 A_key 的最近邻距离,以便输出如下所示

      A_key      Date       Distance
      A1      2016-05-03     145
      A1      2016-09-25     145
      A2      2015-02-25     0
      A2      2015-02-25     0
      A3      2015-10-04     163
      A3      2016-03-15     26
      A3      2016-04-10     26
      A4      2015-09-26     0
      A4      2015-09-26     0

【问题讨论】:

  • 嗯为什么第二个A3不是163?您对此使用什么标准?

标签: python pandas datediff nearest-neighbor date-difference


【解决方案1】:

这基于 groupby 将您的原始 df 拆分为小的唯一关键数据帧,然后我们使用 numpy 广播来加速整个计算

df.Date=pd.to_datetime(df.Date)
l=[]
for _, x in df.groupby('A_key'):
    s=np.abs((x['Date'].values - x['Date'].values[:,None])).astype('timedelta64[D]').astype(int)
    s[[np.arange(len(s))] * 2]=9999
    l.append(np.min(s,1))

df['New']=np.concatenate(l)
df
Out[501]: 
  A_key       Date  New
0    A1 2016-05-03  145
1    A1 2016-09-25  145
2    A2 2015-02-25    0
3    A2 2015-02-25    0
4    A3 2015-10-04  163
5    A3 2016-03-15   26
6    A3 2016-04-10   26
7    A4 2015-09-26    0
8    A4 2015-09-26    0

【讨论】:

  • 为什么第二个A3是26而不是163?我的意思是它与 OP 输出相同,只是不明白为什么会这样
  • @yatu min 在所有日期之间的差异
  • @yatu,它不像 groupby 和 diff 那样简单。 OP想要组中每个点的最近点
  • 啊,现在知道nearest的想法,明白了。谢谢
  • @abcdaire 这可以解决,将原始索引保存为 idx,然后用 A_Key 排序_values,然后做我上面所做的,然后用 idx 为输出数据帧重新索引
【解决方案2】:

您可以使用以下代码将日期转换为 Epoch:

import time
date_time = '2016-05-03 00:00:00'
pattern = '%Y-%m-`enter code here`%d %H:%M:%S'
epoch = int(time.mktime(time.strptime(date_time, pattern)))

然后,只需从其相邻值中减去该值。请注意,结果将以毫秒为单位,因此您必须除以 (1000*60*60*24) 才能将其转换为天数。

【讨论】:

    【解决方案3】:

    您已经在每个键中按日期排序。 因此,您所需要的只是计算同一个键中到下一个日期和上一个日期的距离。 我试过这个(在 Swift 中)来计算 2 个日期之间的距离,格式为 2015-05-22

    func dist(_ d1: String, _ d2: String) -> Int {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "YYYY-MM-DD"
    
        if let date1 = dateFormatter.date(from: d1), let date2 = dateFormatter.date(from: d2) {
            let distance = date1.timeIntervalSince(date2) / 86400
            return abs(Int(distance))
        } else { return 0 }
    }
    
    print(dist("2015-05-25", "2015-05-22"))
    

    您现在可以遍历一个键中的值来计算给定键的最小距离(当然除了它本身)

    【讨论】:

    • 谢谢,但它不仅仅是连续日期之间的距离,对于给定的 A_key,如果有三个记录,每个记录计算其与其他两个记录的时间距离并选择代表最近邻居的最小值距离
    • 对,除非数组已经排序;然后只需要与前一个和下一个日期(如果存在)进行比较;所有其他人都将比这更进一步;因为 abcdaire 正在寻找最接近的……
    【解决方案4】:

    您好,这是一个仅使用 Pandas 的可能解决方案

    让我们给当前索引一个名字(为了方便并确保我们可以很好地恢复所有内容)

    df['Date'] = df['Date'].astype('datetime64[ns]')
    df.index.name = 'id'
    

    我们首先要按日期排序并对每个组应用一个函数, 需要注意的是,我们将依赖 pandas 保留组内的行顺序这一事实(请参阅文档)

    sorted_df = sorted_df = df.sort_values('Date')
    result_df = sorted_df.groupby('A_key').apply(nearest_date_distance)
    

    现在让我们看看nearest_date_distance 函数里面有什么 该函数依赖于 Date 将被排序这一事实,因此我们计算前一天的时间和后一天的时间,当天和第二天之间的差异是负数,这就是我们添加 .abs() 的原因.最后我们取这两个距离之间的最小值(顺便说一句,min 运算符不会取第一行 time_to_before 和最后一行 time 到 after 的缺失值 (NaT))

    def nearest_date_distance(sub):
        time_to_before = sub['Date'].diff()
        time_to_after = sub['Date'].diff(-1).abs()
        nearest_date_distance = pd.concat([time_to_before, time_to_after],axis=1).min(axis=1)
        nearest_date_distance.name = 'Distance'
        return nearest_date_distance
    

    最后我撒了一点谎 result_df 将是这种形式的 MultiIndex Serie(不是数据帧):

    A_key  id
    A1     0    145 days
           1    145 days
    A2     2      0 days
           3      0 days
    A3     4    163 days
           5     26 days
           6     26 days
    A4     7      0 days
           8      0 days
    

    我们可以轻松地将其转换为 DataFrame,并为我们的原始索引正确命名有助于查看所有内容的索引与原始 df 中的相同。

    result_df =sorted_df.groupby('A_key').apply(nearest_date_distance).reset_index(level=0)
    
        A_key   Distance
    id      
    0   A1  145 days
    1   A1  145 days
    2   A2  0 days
    3   A2  0 days
    4   A3  163 days
    5   A3  26 days
    6   A3  26 days
    7   A4  0 days
    8   A4  0 days
    

    如果您需要生成的 Dataframe 上的日期 result_df['Date'] = df['Date']should do the trick :)

    【讨论】:

      猜你喜欢
      • 2019-05-26
      • 2019-06-05
      • 2015-01-25
      • 2014-07-10
      • 2016-10-31
      • 2020-01-26
      • 2014-06-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多