我想基于两列合并两个数据框:“代码”和“日期”。可以直接根据“代码”合并数据帧,但是在“日期”的情况下变得棘手 - 在df1和df2中的日期之间没有完全匹配。所以,我想选择最接近的日期。我怎么能这样做?
df = df1[column_names1].merge(df2[column_names2], on='Code')
答案 0 :(得分:7)
我不认为有一种快速,单行的方式来做这种事情,但我相信最好的方法是这样做:
在df1
df2
相对应的最近日期的列
在这些
随着数据大小的增长,除非你做一些复杂的事情,否则这个“最接近日期”的操作会变得相当昂贵。我喜欢使用scikit-learn的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 :(得分:0)
这是另一种解决方案:
合并代码。
根据您的需要添加日期差异列(我在下面的示例中使用了abs)并使用新列对数据进行排序。
按第一个数据框的记录分组,每个组从第二个数据框中取最近日期的记录。
代码:
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()