2016-08-06 1 views
2

이메일, 제목 및 타임 스탬프의 세 열에 두 개의 데이터 프레임을 병합하고 싶습니다. 데이터 프레임 간의 타임 스탬프가 다르기 때문에 이메일 그룹 &에 가장 가까운 일치하는 타임 스탬프를 식별해야합니다.가장 가까운 타임 스탬프에 pandas 데이터 프레임 병합

다음은 this 질문에 제안 된 가장 가까운 일치 기능을 사용하는 재현 가능한 예입니다. [email protected]을 위해 가장 가까운 일치 10시 17분 5초 반면 [email protected]을 위해 가장 가까운 일치하는 타임 스탬프, 10시 17분 39초 것을

import numpy as np 
import pandas as pd 
from pandas.io.parsers import StringIO 

def find_closest_date(timepoint, time_series, add_time_delta_column=True): 
    # takes a pd.Timestamp() instance and a pd.Series with dates in it 
    # calcs the delta between `timepoint` and each date in `time_series` 
    # returns the closest date and optionally the number of days in its time delta 
    deltas = np.abs(time_series - timepoint) 
    idx_closest_date = np.argmin(deltas) 
    res = {"closest_date": time_series.ix[idx_closest_date]} 
    idx = ['closest_date'] 
    if add_time_delta_column: 
     res["closest_delta"] = deltas[idx_closest_date] 
     idx.append('closest_delta') 
    return pd.Series(res, index=idx) 


a = """timestamp,email,subject 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 02:01:02,[email protected],welcome 
2016-07-01 14:45:04,[email protected],subject3 
2016-07-01 08:14:02,[email protected],subject2 
2016-07-01 16:26:35,[email protected],subject4 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 02:01:02,[email protected],welcome 
2016-07-01 14:45:04,[email protected],subject3 
2016-07-01 08:14:02,[email protected],subject2 
2016-07-01 16:26:35,[email protected],subject4 
""" 

b = """timestamp,email,subject,clicks,var1 
2016-07-01 02:01:14,[email protected],welcome,1,1 
2016-07-01 08:15:48,[email protected],subject2,2,2 
2016-07-01 10:17:39,[email protected],subject3,1,7 
2016-07-01 14:46:01,[email protected],subject3,1,2 
2016-07-01 16:27:28,[email protected],subject4,1,2 
2016-07-01 10:17:05,[email protected],subject3,0,0 
2016-07-01 02:01:03,[email protected],welcome,0,0 
2016-07-01 14:45:05,[email protected],subject3,0,0 
2016-07-01 08:16:00,[email protected],subject2,0,0 
2016-07-01 17:00:00,[email protected],subject4,0,0 
""" 

알 수 있습니다.

a = """timestamp,email,subject 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 10:17:00,[email protected],subject3 
""" 

b = """timestamp,email,subject,clicks,var1 
2016-07-01 10:17:39,[email protected],subject3,1,7 
2016-07-01 10:17:05,[email protected],subject3,0,0 
""" 
df1 = pd.read_csv(StringIO(a), parse_dates=['timestamp']) 
df2 = pd.read_csv(StringIO(b), parse_dates=['timestamp']) 

df1[['closest', 'time_bt_x_and_y']] = df1.timestamp.apply(find_closest_date, args=[df2.timestamp]) 
df1 

df3 = pd.merge(df1, df2, left_on=['email','subject','closest'], right_on=['email','subject','timestamp'],how='left') 

df3 
timestamp_x  email subject    closest time_bt_x_and_y   timestamp_y clicks var1 
    2016-07-01 10:17:00 [email protected] subject3 2016-07-01 10:17:05   00:00:05     NaT  NaN NaN 
    2016-07-01 02:01:02 [email protected] welcome 2016-07-01 02:01:03   00:00:01     NaT  NaN NaN 
    2016-07-01 14:45:04 [email protected] subject3 2016-07-01 14:45:05   00:00:01     NaT  NaN NaN 
    2016-07-01 08:14:02 [email protected] subject2 2016-07-01 08:15:48   00:01:46 2016-07-01 08:15:48  2.0 2.0 
    2016-07-01 16:26:35 [email protected] subject4 2016-07-01 16:27:28   00:00:53 2016-07-01 16:27:28  1.0 2.0 
    2016-07-01 10:17:00 [email protected] subject3 2016-07-01 10:17:05   00:00:05 2016-07-01 10:17:05  0.0 0.0 
    2016-07-01 02:01:02 [email protected] welcome 2016-07-01 02:01:03   00:00:01 2016-07-01 02:01:03  0.0 0.0 
    2016-07-01 14:45:04 [email protected] subject3 2016-07-01 14:45:05   00:00:01 2016-07-01 14:45:05  0.0 0.0 
    2016-07-01 08:14:02 [email protected] subject2 2016-07-01 08:15:48   00:01:46     NaT  NaN NaN 
    2016-07-01 16:26:35 [email protected] subject4 2016-07-01 16:27:28   00:00:53     NaT  NaN NaN 

결과는 계정 이메일 & 대상으로하지 않기 때문에 가장 가까운 날짜가 잘못 주로하기 때문에 잘못된 것입니다.

예상되는 결과는 도움이 될 것입니다 주어진 이메일과 피사체에 가장 가까운 timesstamps를 제공하는 기능을 개정

enter image description here

입니다.

df1.groupby(['email','subject'])['timestamp'].apply(find_closest_date, args=[df1.timestamp]) 

그러나 그룹 개체에 대해 함수가 정의되지 않았기 때문에 오류가 발생합니다. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

+1

코드 또는 데이터를 PNG로 사용하지 말아주십시오 얻을 수 있습니다. – Merlin

+0

오케이, 대신 어떤 형식을 원하십니까? – TinaW

+0

예상되는 출력은 텍스트입니다. 텍스트가 아닌 이미지로 게시물에 추가하십시오. –

답변

3

공지 사항의 각 그룹에 가장 가까운 타임 스탬프 논리를 적용 할 가능 관련 타임 스탬프 페어링은 :

In [108]: result = pd.merge(df1, df2, how='left', on=['email','subject'], suffixes=['', '_y']); result 
Out[108]: 
      timestamp  email subject   timestamp_y clicks var1 
0 2016-07-01 10:17:00 [email protected] subject3 2016-07-01 10:17:39  1  7 
1 2016-07-01 10:17:00 [email protected] subject3 2016-07-01 14:46:01  1  2 
2 2016-07-01 02:01:02 [email protected] welcome 2016-07-01 02:01:14  1  1 
3 2016-07-01 14:45:04 [email protected] subject3 2016-07-01 10:17:39  1  7 
4 2016-07-01 14:45:04 [email protected] subject3 2016-07-01 14:46:01  1  2 
5 2016-07-01 08:14:02 [email protected] subject2 2016-07-01 08:15:48  2  2 
6 2016-07-01 16:26:35 [email protected] subject4 2016-07-01 16:27:28  1  2 
7 2016-07-01 10:17:00 [email protected] subject3 2016-07-01 10:17:05  0  0 
8 2016-07-01 10:17:00 [email protected] subject3 2016-07-01 14:45:05  0  0 
9 2016-07-01 02:01:02 [email protected] welcome 2016-07-01 02:01:03  0  0 
10 2016-07-01 14:45:04 [email protected] subject3 2016-07-01 10:17:05  0  0 
11 2016-07-01 14:45:04 [email protected] subject3 2016-07-01 14:45:05  0  0 
12 2016-07-01 08:14:02 [email protected] subject2 2016-07-01 08:16:00  0  0 
13 2016-07-01 16:26:35 [email protected] subject4 2016-07-01 17:00:00  0  0 

는 이제 타임 스탬프 (F)의 차이의 절대 값을 취할 수 각 행 : 다음

result['diff'] = (result['timestamp_y'] - result['timestamp']).abs() 

idx = result.groupby(['timestamp','email','subject'])['diff'].idxmin() 
result = result.loc[idx] 

['timestamp','email','subject']에 따라 각 그룹에 대한 최소 차이 로우를 찾아 사용한다.


import numpy as np 
import pandas as pd 
from pandas.io.parsers import StringIO 

a = """timestamp,email,subject 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 02:01:02,[email protected],welcome 
2016-07-01 14:45:04,[email protected],subject3 
2016-07-01 08:14:02,[email protected],subject2 
2016-07-01 16:26:35,[email protected],subject4 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 02:01:02,[email protected],welcome 
2016-07-01 14:45:04,[email protected],subject3 
2016-07-01 08:14:02,[email protected],subject2 
2016-07-01 16:26:35,[email protected],subject4 
""" 

b = """timestamp,email,subject,clicks,var1 
2016-07-01 02:01:14,[email protected],welcome,1,1 
2016-07-01 08:15:48,[email protected],subject2,2,2 
2016-07-01 10:17:39,[email protected],subject3,1,7 
2016-07-01 14:46:01,[email protected],subject3,1,2 
2016-07-01 16:27:28,[email protected],subject4,1,2 
2016-07-01 10:17:05,[email protected],subject3,0,0 
2016-07-01 02:01:03,[email protected],welcome,0,0 
2016-07-01 14:45:05,[email protected],subject3,0,0 
2016-07-01 08:16:00,[email protected],subject2,0,0 
2016-07-01 17:00:00,[email protected],subject4,0,0 
""" 

df1 = pd.read_csv(StringIO(a), parse_dates=['timestamp']) 
df2 = pd.read_csv(StringIO(b), parse_dates=['timestamp']) 

result = pd.merge(df1, df2, how='left', on=['email','subject'], suffixes=['', '_y']) 
result['diff'] = (result['timestamp_y'] - result['timestamp']).abs() 
idx = result.groupby(['timestamp','email','subject'])['diff'].idxmin() 
result = result.loc[idx].drop(['timestamp_y','diff'], axis=1) 
result = result.sort_index() 
print(result) 

   timestamp  email subject clicks var1 
0 2016-07-01 10:17:00 [email protected] subject3  1  7 
2 2016-07-01 02:01:02 [email protected] welcome  1  1 
4 2016-07-01 14:45:04 [email protected] subject3  1  2 
5 2016-07-01 08:14:02 [email protected] subject2  2  2 
6 2016-07-01 16:26:35 [email protected] subject4  1  2 
7 2016-07-01 10:17:00 [email protected] subject3  0  0 
9 2016-07-01 02:01:02 [email protected] welcome  0  0 
11 2016-07-01 14:45:04 [email protected] subject3  0  0 
12 2016-07-01 08:14:02 [email protected] subject2  0  0 
13 2016-07-01 16:26:35 [email protected] subject4  0  0 
+0

많은 감사 !!! – TinaW

1

당신은 당신이 emailsubjectdf1df2 병합의 경우, 결과 모두를 가지고 '이메일'과 '대상'

a = """timestamp,email,subject 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 02:01:02,[email protected],welcome 
2016-07-01 14:45:04,[email protected],subject3 
2016-07-01 08:14:02,[email protected],subject2 
2016-07-01 16:26:35,[email protected],subject4 
2016-07-01 10:17:00,[email protected],subject3 
2016-07-01 02:01:02,[email protected],welcome 
2016-07-01 14:45:04,[email protected],subject3 
2016-07-01 08:14:02,[email protected],subject2 
2016-07-01 16:26:35,[email protected],subject4 
""" 

b = """timestamp,email,subject,clicks,var1 
2016-07-01 02:01:14,[email protected],welcome,1,1 
2016-07-01 08:15:48,[email protected],subject2,2,2 
2016-07-01 10:17:39,[email protected],subject3,1,7 
2016-07-01 14:46:01,[email protected],subject3,1,2 
2016-07-01 16:27:28,[email protected],subject4,1,2 
2016-07-01 10:17:05,[email protected],subject3,0,0 
2016-07-01 02:01:03,[email protected],welcome,0,0 
2016-07-01 14:45:05,[email protected],subject3,0,0 
2016-07-01 08:16:00,[email protected],subject2,0,0 
2016-07-01 17:00:00,[email protected],subject4,0,0 
""" 

df1 = pd.read_csv(StringIO(a), parse_dates=['timestamp']) 
df2 = pd.read_csv(StringIO(b), parse_dates=['timestamp']) 
df2 = df2.set_index(['email', 'subject']) 

def find_closest_date(timepoint, time_series, add_time_delta_column=True): 
    # takes a pd.Timestamp() instance and a pd.Series with dates in it 
    # calcs the delta between `timepoint` and each date in `time_series` 
    # returns the closest date and optionally the number of days in its time delta 
    time_series = time_series.values 
    timepoint = np.datetime64(timepoint) 
    deltas = np.abs(np.subtract(time_series, timepoint)) 
    idx_closest_date = np.argmin(deltas) 
    res = {"closest_date": time_series[idx_closest_date]} 
    idx = ['closest_date'] 
    if add_time_delta_column: 
     res["closest_delta"] = deltas[idx_closest_date] 
     idx.append('closest_delta') 
    return pd.Series(res, index=idx) 

# Then group df1 as needed 
grouped = df1.groupby(['email', 'subject']) 

# Finally loop over the group items, finding the closest timestamps 
join_ts = pd.DataFrame() 
for name, group in grouped: 
    try: 
     join_ts = pd.concat([join_ts, group['timestamp']\ 
          .apply(find_closest_date, time_series=df2.loc[name, 'timestamp'])], 
          axis=0) 
    except KeyError: 
     pass 

df3 = pd.merge(pd.concat([df1, join_ts], axis=1), df2, left_on=['closest_date'], right_on=['timestamp']) 
+0

죄송합니다, 그 결과는 기대하지 않습니다. – TinaW

+0

그래서 무엇을 제공합니까? 오류, 다른 뭔가? 조금 더 구체적 일 수 있습니까? 부디. – Kartik

+0

내 게시물의 그림에 예상 된 결과가 표시됩니다. 가장 큰 문제는 가장 가까운 타임 스탬프가 잘못되었다는 것입니다. 전자 메일 및 주제 인 다른 두 가지 차원을 고려하지 않기 때문입니다.내부 조인 결과를 보면 5 개의 전자 메일 만 포함되지만 10을 표시해야합니다 (내 게시물의 그림 참조). – TinaW

관련 문제