繁体   English   中英

如何基于最近的日期合并两个数据帧

[英]How to merge two data frames based on nearest date

我想基于两列合并两个数据框:“代码”和“日期”。 可以直接根据“代码”合并数据帧,但是在“日期”的情况下变得棘手 - 在df1和df2中的日期之间没有完全匹配。 所以,我想选择最接近的日期。 我怎样才能做到这一点?

df = df1[column_names1].merge(df2[column_names2], on='Code')

我不认为有一种快速的,单行的方式来做这种事情,但我相信最好的方法是这样做:

  1. 使用df2相应组中最接近的日期向df1添加一列

  2. 在这些上调用标准合并

随着数据大小的增长,除非你做一些复杂的事情,否则这个“最接近日期”的操作会变得相当昂贵。 我喜欢使用scikit-learn的NearestNeighbor代码NearestNeighbor这类事情。

我已经将一种解决方案放在一起,这种解决方案应该相对较好地扩展。 首先我们可以生成一些简单的数据:

import pandas as pd
import numpy as np
dates = pd.date_range('2015', periods=200, freq='D')

rand = np.random.RandomState(42)
i1 = np.sort(rand.permutation(np.arange(len(dates)))[:5])
i2 = np.sort(rand.permutation(np.arange(len(dates)))[:5])

df1 = pd.DataFrame({'Code': rand.randint(0, 2, 5),
                    'Date': dates[i1],
                    'val1':rand.rand(5)})
df2 = pd.DataFrame({'Code': rand.randint(0, 2, 5),
                    'Date': dates[i2],
                    'val2':rand.rand(5)})

我们来看看这些:

>>> df1
   Code       Date      val1
0     0 2015-01-16  0.975852
1     0 2015-01-31  0.516300
2     1 2015-04-06  0.322956
3     1 2015-05-09  0.795186
4     1 2015-06-08  0.270832

>>> df2
   Code       Date      val2
0     1 2015-02-03  0.184334
1     1 2015-04-13  0.080873
2     0 2015-05-02  0.428314
3     1 2015-06-26  0.688500
4     0 2015-06-30  0.058194

现在让我们编写一个apply函数,使用scikit-learn将最近的日期列添加到df1

from sklearn.neighbors import NearestNeighbors

def find_nearest(group, match, groupname):
    match = match[match[groupname] == group.name]
    nbrs = NearestNeighbors(1).fit(match['Date'].values[:, None])
    dist, ind = nbrs.kneighbors(group['Date'].values[:, None])

    group['Date1'] = group['Date']
    group['Date'] = match['Date'].values[ind.ravel()]
    return group

df1_mod = df1.groupby('Code').apply(find_nearest, df2, 'Code')
>>> df1_mod
   Code       Date      val1      Date1
0     0 2015-05-02  0.975852 2015-01-16
1     0 2015-05-02  0.516300 2015-01-31
2     1 2015-04-13  0.322956 2015-04-06
3     1 2015-04-13  0.795186 2015-05-09
4     1 2015-06-26  0.270832 2015-06-08

最后,我们可以通过直接调用pd.merge将它们合并在一起:

>>> pd.merge(df1_mod, df2, on=['Code', 'Date'])
   Code       Date      val1      Date1      val2
0     0 2015-05-02  0.975852 2015-01-16  0.428314
1     0 2015-05-02  0.516300 2015-01-31  0.428314
2     1 2015-04-13  0.322956 2015-04-06  0.080873
3     1 2015-04-13  0.795186 2015-05-09  0.080873
4     1 2015-06-26  0.270832 2015-06-08  0.688500

请注意,第0行和第1行都匹配相同的val2 ; 考虑到您描述所需解决方案的方式,这是预期的。

这是另一种解决方案:

  1. 合并代码。

  2. 根据需要添加日期差异列(我在下面的示例中使用了abs)并使用新列对数据进行排序。

  3. 按第一个数据帧的记录进行分组,并为每个组从第二个数据帧中取最近日期的记录。

码:

df = df1.reset_index()[column_names1].merge(df2[column_names2], on='Code')
df['DateDiff'] = (df['Date1'] - df['Date2']).abs()
df.sort_values('DateDiff').groupby('index').first().reset_index()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM