2016-10-17 2 views
2

특정 데이터 프레임을 병합하고 싶습니다. 병합은 특정 범위의 날짜/시간 조건부 조건입니다.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('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 

, 난 Timestampdata되도록 처음 time 값 이후에 발생 special_ID를 병합 할. 즉 myID = 002 함유 열 중 바로 2016-01-01 00:06:00 다음 data 내의 다음 시간 ( special_ID = foo_0time)은 이후 예를 들어, foo_0myID = 002으로 2016-01-01 01:00:00에 대응하는 행 것이다.

참고 : Timestampdata의 인덱스가 아니며 timedata2의 인덱스가 아닙니다. 다른 대부분의 관련 게시물은 datetime 개체를 데이터 프레임의 인덱스로 사용하는 것으로 나타납니다.

답변

8

당신은 대부분의 작업을 할 수 팬더 0.19의 새로운 merge_asof를 사용할 수 있습니다. 그런 다음, 보조 일치를 제거하는 locduplicated을 결합 :

# 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 
+1

을! 나는이 일을하고 있었는데 지금은 할 필요가 없다. :-) – piRSquared

+0

어떤 종류의 버그가 있습니다. 데이터의 타임 스탬프를 변경했습니다. – Oren

+0

@Oren : 아니요, 출력물이 방금 약간 다르게 정렬되었습니다. – root

1

매우 좋지는 않지만 작동한다고 생각합니다.

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