Python 熊猫:根据时间范围合并条件

Python 熊猫:根据时间范围合并条件,python,datetime,pandas,Python,Datetime,Pandas,我希望将一个数据帧与另一个数据帧合并,合并的条件是日期/时间在特定范围内 例如,假设我有以下两个数据帧 import pandas as pd import datetime # Create main data frame. data = pd.DataFrame() time_seq1 = pd.DataFrame(pd.date_range('1/1/2016', periods=3, freq='H')) time_seq2 = pd.DataFrame(pd.date_range('

我希望将一个数据帧与另一个数据帧合并,合并的条件是日期/时间在特定范围内

例如,假设我有以下两个数据帧

import pandas as pd
import datetime

# Create main data frame.
data = pd.DataFrame()
time_seq1 = pd.DataFrame(pd.date_range('1/1/2016', periods=3, freq='H'))
time_seq2 = pd.DataFrame(pd.date_range('1/2/2016', periods=3, freq='H'))
data = data.append(time_seq1, ignore_index=True)
data = data.append(time_seq1, ignore_index=True)
data = data.append(time_seq1, ignore_index=True)
data = data.append(time_seq2, ignore_index=True)
data['myID'] = ['001','001','001','002','002','002','003','003','003','004','004','004']
data.columns = ['Timestamp', 'myID']

# Create second data frame.
data2 = pd.DataFrame()
data2['time'] = [pd.to_datetime('1/1/2016 12:06 AM'), pd.to_datetime('1/1/2016 1:34 AM'), pd.to_datetime('1/2/2016 12:25 AM')]
data2['myID'] = ['002', '003', '004']
data2['specialID'] = ['foo_0', 'foo_1', 'foo_2']

# Show data frames.
data
             Timestamp myID
0  2016-01-01 00:00:00  001
1  2016-01-01 01:00:00  001
2  2016-01-01 02:00:00  001
3  2016-01-01 00:00:00  002
4  2016-01-01 01:00:00  002
5  2016-01-01 02:00:00  002
6  2016-01-01 00:00:00  003
7  2016-01-01 01:00:00  003
8  2016-01-01 02:00:00  003
9  2016-01-02 00:00:00  004
10 2016-01-02 01:00:00  004
11 2016-01-02 02:00:00  004

data2
                 time myID specialID
0 2016-01-01 00:06:00  002     foo_0
1 2016-01-01 01:34:00  003     foo_1
2 2016-01-02 00:25:00  004     foo_2
我想构造以下输出

# Desired output.
             Timestamp myID special_ID
0  2016-01-01 00:00:00  001        NaN
1  2016-01-01 01:00:00  001        NaN
2  2016-01-01 02:00:00  001        NaN
3  2016-01-01 00:00:00  002        NaN
4  2016-01-01 01:00:00  002      foo_0
5  2016-01-01 02:00:00  002        NaN
6  2016-01-01 00:00:00  003        NaN
7  2016-01-01 01:00:00  003        NaN
8  2016-01-01 02:00:00  003      foo_1
9  2016-01-02 00:00:00  004        NaN
10 2016-01-02 01:00:00  004      foo_2
11 2016-01-02 02:00:00  004        NaN
特别是,我想将
特殊的_ID
合并到
数据中
,这样
时间戳
是在
时间
的值之后第一次出现。例如,
foo\u 0
将位于
2016-01-01 01:00:00
myID=002
对应的行中,因为这是
2016-01-01 00:06:00
之后的
数据中的下一次时间(包含
myID=002
的行中的
time


注意,
时间戳
不是
数据
的索引,
时间
不是
数据2
的索引。大多数其他相关文章似乎都依赖于使用datetime对象作为数据帧的索引。

不是很漂亮,但我认为它是可行的

data['specialID'] = None
foolist = list(data2['myID'])
for i in data.index:
    if data.myID[i] in foolist:
        if data.Timestamp[i]> list(data2[data2['myID'] == data.myID[i]].time)[0]:
            data['specialID'][i] = list(data2[data2['myID'] == data.myID[i]].specialID)[0]
            foolist.remove(list(data2[data2['myID'] == data.myID[i]].myID)[0])

In [95]: data
Out[95]:
             Timestamp myID specialID
0  2016-01-01 00:00:00  001      None
1  2016-01-01 01:00:00  001      None
2  2016-01-01 02:00:00  001      None
3  2016-01-01 00:00:00  002      None
4  2016-01-01 01:00:00  002     foo_0
5  2016-01-01 02:00:00  002      None
6  2016-01-01 00:00:00  003      None
7  2016-01-01 01:00:00  003      None
8  2016-01-01 02:00:00  003     foo_1
9  2016-01-02 00:00:00  004      None
10 2016-01-02 01:00:00  004     foo_2
11 2016-01-02 02:00:00  004      None
您可以使用Pandas 0.19中的新功能来完成大部分工作。然后,组合
loc
duplicated
以删除次要匹配项:

# Data needs to be sorted for merge_asof.
data = data.sort_values(by='Timestamp')

# Perform the merge_asof.
df = pd.merge_asof(data, data2, left_on='Timestamp', right_on='time', by='myID').drop('time', axis=1)

# Make the additional matches null.
df.loc[df['specialID'].duplicated(), 'specialID'] = np.nan

# Get the original ordering.
df = df.set_index(data.index).sort_index()
结果输出:

             Timestamp myID specialID
0  2016-01-01 00:00:00  001       NaN
1  2016-01-01 01:00:00  001       NaN
2  2016-01-01 02:00:00  001       NaN
3  2016-01-01 00:00:00  002       NaN
4  2016-01-01 01:00:00  002     foo_0
5  2016-01-01 02:00:00  002       NaN
6  2016-01-01 00:00:00  003       NaN
7  2016-01-01 01:00:00  003       NaN
8  2016-01-01 02:00:00  003     foo_1
9  2016-01-02 00:00:00  004       NaN
10 2016-01-02 01:00:00  004     foo_2
11 2016-01-02 02:00:00  004       NaN

完美的我只是在做这个,现在我不必了。:-)你有一个bug,你改变了data@Oren:不,我的输出只是排序稍有不同。@root谢谢!您能否编辑您的回复以保留原始顺序?然后我将此标记为已解决。@Adam:已更新以保持原始顺序。我使用的方法假设您的原始索引只是默认的有序
Int64Index
,就像示例数据中的那样。